mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
Expose PSPThread in the same manner
This commit is contained in:
parent
644f5e4e6c
commit
2bfe327dbd
13 changed files with 360 additions and 345 deletions
|
@ -2170,6 +2170,7 @@ add_library(${CoreLibName} ${CoreLinkType}
|
|||
Core/HLE/HLETables.cpp
|
||||
Core/HLE/HLETables.h
|
||||
Core/HLE/KernelWaitHelpers.h
|
||||
Core/HLE/PSPThreadContext.h
|
||||
Core/HLE/KUBridge.h
|
||||
Core/HLE/KUBridge.cpp
|
||||
Core/HLE/Plugins.h
|
||||
|
|
|
@ -1,21 +1,18 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
typedef std::pair<uint32_t, uint32_t> ExpressionPair;
|
||||
typedef std::vector<ExpressionPair> PostfixExpression;
|
||||
|
||||
enum ExpressionType
|
||||
{
|
||||
enum ExpressionType {
|
||||
EXPR_TYPE_UINT = 0,
|
||||
EXPR_TYPE_FLOAT = 2,
|
||||
};
|
||||
|
||||
class IExpressionFunctions
|
||||
{
|
||||
class IExpressionFunctions {
|
||||
public:
|
||||
virtual ~IExpressionFunctions() {}
|
||||
virtual bool parseReference(char* str, uint32_t& referenceIndex) = 0;
|
||||
|
|
|
@ -1195,6 +1195,7 @@
|
|||
<ClInclude Include="HLE\KUBridge.h" />
|
||||
<ClInclude Include="HLE\NetInetConstants.h" />
|
||||
<ClInclude Include="HLE\Plugins.h" />
|
||||
<ClInclude Include="HLE\PSPThreadContext.h" />
|
||||
<ClInclude Include="HLE\sceAac.h" />
|
||||
<ClInclude Include="HLE\sceKernelHeap.h" />
|
||||
<ClInclude Include="HLE\sceNetApctl.h" />
|
||||
|
|
|
@ -2178,6 +2178,9 @@
|
|||
<ClInclude Include="LuaContext.h">
|
||||
<Filter>Core</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HLE\PSPThreadContext.h">
|
||||
<Filter>HLE\Kernel</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\LICENSE.TXT" />
|
||||
|
@ -2206,4 +2209,4 @@
|
|||
<Filter>Ext</Filter>
|
||||
</Text>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
|
@ -22,6 +22,7 @@
|
|||
#include <mutex>
|
||||
|
||||
#include "Core/MIPS/MIPSDebugInterface.h"
|
||||
#include "Common/Math/expression_parser.h"
|
||||
|
||||
enum BreakAction : u32 {
|
||||
BREAK_ACTION_IGNORE = 0x00,
|
||||
|
|
|
@ -18,9 +18,11 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdio>
|
||||
#include "Core/HLE/sceKernelThread.h"
|
||||
#include "Core/HLE/PSPThreadContext.h"
|
||||
#include "Core/MIPS/MIPSDebugInterface.h"
|
||||
|
||||
struct PSPThreadContext;
|
||||
|
||||
class KernelThreadDebugInterface : public DebugInterface {
|
||||
public:
|
||||
KernelThreadDebugInterface(PSPThreadContext &t) : ctx(t) {}
|
||||
|
|
35
Core/HLE/PSPThreadContext.h
Normal file
35
Core/HLE/PSPThreadContext.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
#pragma once
|
||||
|
||||
// Had to break this out into its own header to solve a circular include issue.
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
struct PSPThreadContext {
|
||||
void reset();
|
||||
|
||||
// r must be followed by f.
|
||||
u32 r[32];
|
||||
union {
|
||||
float f[32];
|
||||
u32 fi[32];
|
||||
int fs[32];
|
||||
};
|
||||
union {
|
||||
float v[128];
|
||||
u32 vi[128];
|
||||
};
|
||||
u32 vfpuCtrl[16];
|
||||
|
||||
union {
|
||||
struct {
|
||||
u32 pc;
|
||||
|
||||
u32 lo;
|
||||
u32 hi;
|
||||
|
||||
u32 fcr31;
|
||||
u32 fpcond;
|
||||
};
|
||||
u32 other[6];
|
||||
};
|
||||
};
|
|
@ -74,11 +74,6 @@
|
|||
#include "GPU/GPUCommon.h"
|
||||
#include "GPU/GPUState.h"
|
||||
|
||||
enum {
|
||||
PSP_THREAD_ATTR_KERNEL = 0x00001000,
|
||||
PSP_THREAD_ATTR_USER = 0x80000000,
|
||||
};
|
||||
|
||||
enum : u32 {
|
||||
// Function exports.
|
||||
NID_MODULE_START = 0xD632ACDB,
|
||||
|
|
|
@ -105,23 +105,6 @@ enum ThreadEventType {
|
|||
|
||||
bool __KernelThreadTriggerEvent(bool isKernel, SceUID threadID, ThreadEventType type);
|
||||
|
||||
enum {
|
||||
PSP_THREAD_ATTR_KERNEL = 0x00001000,
|
||||
PSP_THREAD_ATTR_VFPU = 0x00004000,
|
||||
PSP_THREAD_ATTR_SCRATCH_SRAM = 0x00008000, // Save/restore scratch as part of context???
|
||||
PSP_THREAD_ATTR_NO_FILLSTACK = 0x00100000, // No filling of 0xff.
|
||||
PSP_THREAD_ATTR_CLEAR_STACK = 0x00200000, // Clear thread stack when deleted.
|
||||
PSP_THREAD_ATTR_LOW_STACK = 0x00400000, // Allocate stack from bottom not top.
|
||||
PSP_THREAD_ATTR_USER = 0x80000000,
|
||||
PSP_THREAD_ATTR_USBWLAN = 0xa0000000,
|
||||
PSP_THREAD_ATTR_VSH = 0xc0000000,
|
||||
|
||||
// TODO: Support more, not even sure what all of these mean.
|
||||
PSP_THREAD_ATTR_USER_MASK = 0xf8f060ff,
|
||||
PSP_THREAD_ATTR_USER_ERASE = 0x78800000,
|
||||
PSP_THREAD_ATTR_SUPPORTED = (PSP_THREAD_ATTR_KERNEL | PSP_THREAD_ATTR_VFPU | PSP_THREAD_ATTR_NO_FILLSTACK | PSP_THREAD_ATTR_CLEAR_STACK | PSP_THREAD_ATTR_LOW_STACK | PSP_THREAD_ATTR_USER)
|
||||
};
|
||||
|
||||
struct NativeCallback
|
||||
{
|
||||
SceUInt_le size;
|
||||
|
@ -173,58 +156,6 @@ public:
|
|||
NativeCallback nc;
|
||||
};
|
||||
|
||||
#if COMMON_LITTLE_ENDIAN
|
||||
typedef WaitType WaitType_le;
|
||||
#else
|
||||
typedef swap_struct_t<WaitType, swap_32_t<WaitType> > WaitType_le;
|
||||
#endif
|
||||
|
||||
// Real PSP struct, don't change the fields.
|
||||
struct SceKernelThreadRunStatus
|
||||
{
|
||||
SceSize_le size;
|
||||
u32_le status;
|
||||
s32_le currentPriority;
|
||||
WaitType_le waitType;
|
||||
SceUID_le waitID;
|
||||
s32_le wakeupCount;
|
||||
SceKernelSysClock runForClocks;
|
||||
s32_le numInterruptPreempts;
|
||||
s32_le numThreadPreempts;
|
||||
s32_le numReleases;
|
||||
};
|
||||
|
||||
// Real PSP struct, don't change the fields.
|
||||
struct NativeThread
|
||||
{
|
||||
u32_le nativeSize;
|
||||
char name[KERNELOBJECT_MAX_NAME_LENGTH+1];
|
||||
|
||||
// Threading stuff
|
||||
u32_le attr;
|
||||
u32_le status;
|
||||
u32_le entrypoint;
|
||||
u32_le initialStack;
|
||||
u32_le stackSize;
|
||||
u32_le gpreg;
|
||||
|
||||
s32_le initialPriority;
|
||||
s32_le currentPriority;
|
||||
WaitType_le waitType;
|
||||
SceUID_le waitID;
|
||||
s32_le wakeupCount;
|
||||
s32_le exitStatus;
|
||||
SceKernelSysClock runForClocks;
|
||||
s32_le numInterruptPreempts;
|
||||
s32_le numThreadPreempts;
|
||||
s32_le numReleases;
|
||||
};
|
||||
|
||||
struct ThreadWaitInfo {
|
||||
u32 waitValue;
|
||||
u32 timeoutPtr;
|
||||
};
|
||||
|
||||
// Owns outstanding MIPS calls and provides a way to get them by ID.
|
||||
class MipsCallManager {
|
||||
public:
|
||||
|
@ -344,8 +275,7 @@ public:
|
|||
PSPAction *chainedAction;
|
||||
};
|
||||
|
||||
class ActionAfterCallback : public PSPAction
|
||||
{
|
||||
class ActionAfterCallback : public PSPAction {
|
||||
public:
|
||||
ActionAfterCallback() {}
|
||||
void run(MipsCall &call) override;
|
||||
|
@ -354,13 +284,11 @@ public:
|
|||
return new ActionAfterCallback;
|
||||
}
|
||||
|
||||
void setCallback(SceUID cbId_)
|
||||
{
|
||||
void setCallback(SceUID cbId_) {
|
||||
cbId = cbId_;
|
||||
}
|
||||
|
||||
void DoState(PointerWrap &p) override
|
||||
{
|
||||
void DoState(PointerWrap &p) override {
|
||||
auto s = p.Section("ActionAfterCallback", 1);
|
||||
if (!s)
|
||||
return;
|
||||
|
@ -371,233 +299,172 @@ public:
|
|||
SceUID cbId;
|
||||
};
|
||||
|
||||
class PSPThread : public KernelObject {
|
||||
public:
|
||||
PSPThread() : debug(context) {}
|
||||
u32 PSPThread::GetMissingErrorCode() {
|
||||
return SCE_KERNEL_ERROR_UNKNOWN_THID;
|
||||
}
|
||||
|
||||
const char *GetName() override { return nt.name; }
|
||||
const char *GetTypeName() override { return GetStaticTypeName(); }
|
||||
static const char *GetStaticTypeName() { return "Thread"; }
|
||||
void GetQuickInfo(char *ptr, int size) override {
|
||||
snprintf(ptr, size, "pc= %08x sp= %08x %s %s %s %s %s %s (wt=%i wid=%i wv= %08x )",
|
||||
context.pc, context.r[MIPS_REG_SP],
|
||||
(nt.status & THREADSTATUS_RUNNING) ? "RUN" : "",
|
||||
(nt.status & THREADSTATUS_READY) ? "READY" : "",
|
||||
(nt.status & THREADSTATUS_WAIT) ? "WAIT" : "",
|
||||
(nt.status & THREADSTATUS_SUSPEND) ? "SUSPEND" : "",
|
||||
(nt.status & THREADSTATUS_DORMANT) ? "DORMANT" : "",
|
||||
(nt.status & THREADSTATUS_DEAD) ? "DEAD" : "",
|
||||
(int)nt.waitType,
|
||||
nt.waitID,
|
||||
waitInfo.waitValue);
|
||||
void PSPThread::GetQuickInfo(char *ptr, int size) {
|
||||
snprintf(ptr, size, "pc= %08x sp= %08x %s %s %s %s %s %s (wt=%i wid=%i wv= %08x )",
|
||||
context.pc, context.r[MIPS_REG_SP],
|
||||
(nt.status & THREADSTATUS_RUNNING) ? "RUN" : "",
|
||||
(nt.status & THREADSTATUS_READY) ? "READY" : "",
|
||||
(nt.status & THREADSTATUS_WAIT) ? "WAIT" : "",
|
||||
(nt.status & THREADSTATUS_SUSPEND) ? "SUSPEND" : "",
|
||||
(nt.status & THREADSTATUS_DORMANT) ? "DORMANT" : "",
|
||||
(nt.status & THREADSTATUS_DEAD) ? "DEAD" : "",
|
||||
(int)nt.waitType,
|
||||
nt.waitID,
|
||||
waitInfo.waitValue);
|
||||
}
|
||||
|
||||
BlockAllocator &PSPThread::StackAllocator() {
|
||||
if (nt.attr & PSP_THREAD_ATTR_KERNEL) {
|
||||
return kernelMemory;
|
||||
}
|
||||
return userMemory;
|
||||
}
|
||||
|
||||
static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_THID; }
|
||||
static int GetStaticIDType() { return SCE_KERNEL_TMID_Thread; }
|
||||
int GetIDType() const override { return SCE_KERNEL_TMID_Thread; }
|
||||
bool PSPThread::AllocateStack(u32 &stackSize) {
|
||||
_assert_msg_(stackSize >= 0x200, "thread stack should be 256 bytes or larger");
|
||||
|
||||
bool AllocateStack(u32 &stackSize) {
|
||||
_assert_msg_(stackSize >= 0x200, "thread stack should be 256 bytes or larger");
|
||||
FreeStack();
|
||||
|
||||
FreeStack();
|
||||
|
||||
bool fromTop = (nt.attr & PSP_THREAD_ATTR_LOW_STACK) == 0;
|
||||
currentStack.start = StackAllocator().Alloc(stackSize, fromTop, StringFromFormat("stack/%s", nt.name).c_str());
|
||||
if (currentStack.start == (u32)-1)
|
||||
{
|
||||
currentStack.start = 0;
|
||||
nt.initialStack = 0;
|
||||
ERROR_LOG(Log::sceKernel, "Failed to allocate stack for thread");
|
||||
return false;
|
||||
}
|
||||
|
||||
nt.initialStack = currentStack.start;
|
||||
nt.stackSize = stackSize;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FillStack() {
|
||||
// Fill the stack.
|
||||
if ((nt.attr & PSP_THREAD_ATTR_NO_FILLSTACK) == 0) {
|
||||
Memory::Memset(currentStack.start, 0xFF, nt.stackSize, "ThreadFillStack");
|
||||
}
|
||||
context.r[MIPS_REG_SP] = currentStack.start + nt.stackSize;
|
||||
currentStack.end = context.r[MIPS_REG_SP];
|
||||
// The k0 section is 256 bytes at the top of the stack.
|
||||
context.r[MIPS_REG_SP] -= 256;
|
||||
context.r[MIPS_REG_K0] = context.r[MIPS_REG_SP];
|
||||
u32 k0 = context.r[MIPS_REG_K0];
|
||||
Memory::Memset(k0, 0, 0x100, "ThreadK0");
|
||||
Memory::Write_U32(GetUID(), k0 + 0xc0);
|
||||
Memory::Write_U32(nt.initialStack, k0 + 0xc8);
|
||||
Memory::Write_U32(0xffffffff, k0 + 0xf8);
|
||||
Memory::Write_U32(0xffffffff, k0 + 0xfc);
|
||||
// After k0 comes the arguments, which is done by sceKernelStartThread().
|
||||
|
||||
Memory::Write_U32(GetUID(), nt.initialStack);
|
||||
return true;
|
||||
}
|
||||
|
||||
void FreeStack() {
|
||||
if (currentStack.start != 0) {
|
||||
DEBUG_LOG(Log::sceKernel, "Freeing thread stack %s", nt.name);
|
||||
|
||||
if ((nt.attr & PSP_THREAD_ATTR_CLEAR_STACK) != 0 && nt.initialStack != 0) {
|
||||
Memory::Memset(nt.initialStack, 0, nt.stackSize, "ThreadFreeStack");
|
||||
}
|
||||
|
||||
StackAllocator().Free(currentStack.start);
|
||||
currentStack.start = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool PushExtendedStack(u32 size)
|
||||
bool fromTop = (nt.attr & PSP_THREAD_ATTR_LOW_STACK) == 0;
|
||||
currentStack.start = StackAllocator().Alloc(stackSize, fromTop, StringFromFormat("stack/%s", nt.name).c_str());
|
||||
if (currentStack.start == (u32)-1)
|
||||
{
|
||||
u32 stack = userMemory.Alloc(size, true, StringFromFormat("extended/%s", nt.name).c_str());
|
||||
if (stack == (u32)-1)
|
||||
return false;
|
||||
|
||||
pushedStacks.push_back(currentStack);
|
||||
currentStack.start = stack;
|
||||
currentStack.end = stack + size;
|
||||
nt.initialStack = currentStack.start;
|
||||
nt.stackSize = currentStack.end - currentStack.start;
|
||||
|
||||
// We still drop the threadID at the bottom and fill it, but there's no k0.
|
||||
Memory::Memset(currentStack.start, 0xFF, nt.stackSize, "ThreadExtendStack");
|
||||
Memory::Write_U32(GetUID(), nt.initialStack);
|
||||
return true;
|
||||
currentStack.start = 0;
|
||||
nt.initialStack = 0;
|
||||
ERROR_LOG(Log::sceKernel, "Failed to allocate stack for thread");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PopExtendedStack()
|
||||
{
|
||||
if (pushedStacks.size() == 0)
|
||||
return false;
|
||||
nt.initialStack = currentStack.start;
|
||||
nt.stackSize = stackSize;
|
||||
return true;
|
||||
}
|
||||
|
||||
userMemory.Free(currentStack.start);
|
||||
currentStack = pushedStacks.back();
|
||||
pushedStacks.pop_back();
|
||||
nt.initialStack = currentStack.start;
|
||||
nt.stackSize = currentStack.end - currentStack.start;
|
||||
return true;
|
||||
bool PSPThread::FillStack() {
|
||||
// Fill the stack.
|
||||
if ((nt.attr & PSP_THREAD_ATTR_NO_FILLSTACK) == 0) {
|
||||
Memory::Memset(currentStack.start, 0xFF, nt.stackSize, "ThreadFillStack");
|
||||
}
|
||||
context.r[MIPS_REG_SP] = currentStack.start + nt.stackSize;
|
||||
currentStack.end = context.r[MIPS_REG_SP];
|
||||
// The k0 section is 256 bytes at the top of the stack.
|
||||
context.r[MIPS_REG_SP] -= 256;
|
||||
context.r[MIPS_REG_K0] = context.r[MIPS_REG_SP];
|
||||
u32 k0 = context.r[MIPS_REG_K0];
|
||||
Memory::Memset(k0, 0, 0x100, "ThreadK0");
|
||||
Memory::Write_U32(GetUID(), k0 + 0xc0);
|
||||
Memory::Write_U32(nt.initialStack, k0 + 0xc8);
|
||||
Memory::Write_U32(0xffffffff, k0 + 0xf8);
|
||||
Memory::Write_U32(0xffffffff, k0 + 0xfc);
|
||||
// After k0 comes the arguments, which is done by sceKernelStartThread().
|
||||
|
||||
// Can't use a destructor since savestates will call that too.
|
||||
void Cleanup()
|
||||
{
|
||||
// Callbacks are automatically deleted when their owning thread is deleted.
|
||||
for (auto it = callbacks.begin(), end = callbacks.end(); it != end; ++it)
|
||||
kernelObjects.Destroy<PSPCallback>(*it);
|
||||
Memory::Write_U32(GetUID(), nt.initialStack);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (pushedStacks.size() != 0)
|
||||
{
|
||||
WARN_LOG_REPORT(Log::sceKernel, "Thread ended within an extended stack");
|
||||
for (size_t i = 0; i < pushedStacks.size(); ++i)
|
||||
userMemory.Free(pushedStacks[i].start);
|
||||
void PSPThread::FreeStack() {
|
||||
if (currentStack.start != 0) {
|
||||
DEBUG_LOG(Log::sceKernel, "Freeing thread stack %s", nt.name);
|
||||
|
||||
if ((nt.attr & PSP_THREAD_ATTR_CLEAR_STACK) != 0 && nt.initialStack != 0) {
|
||||
Memory::Memset(nt.initialStack, 0, nt.stackSize, "ThreadFreeStack");
|
||||
}
|
||||
FreeStack();
|
||||
|
||||
StackAllocator().Free(currentStack.start);
|
||||
currentStack.start = 0;
|
||||
}
|
||||
}
|
||||
|
||||
BlockAllocator &StackAllocator() {
|
||||
if (nt.attr & PSP_THREAD_ATTR_KERNEL) {
|
||||
return kernelMemory;
|
||||
}
|
||||
return userMemory;
|
||||
bool PSPThread::PushExtendedStack(u32 size) {
|
||||
u32 stack = userMemory.Alloc(size, true, StringFromFormat("extended/%s", nt.name).c_str());
|
||||
if (stack == (u32)-1)
|
||||
return false;
|
||||
|
||||
pushedStacks.push_back(currentStack);
|
||||
currentStack.start = stack;
|
||||
currentStack.end = stack + size;
|
||||
nt.initialStack = currentStack.start;
|
||||
nt.stackSize = currentStack.end - currentStack.start;
|
||||
|
||||
// We still drop the threadID at the bottom and fill it, but there's no k0.
|
||||
Memory::Memset(currentStack.start, 0xFF, nt.stackSize, "ThreadExtendStack");
|
||||
Memory::Write_U32(GetUID(), nt.initialStack);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PSPThread::PopExtendedStack() {
|
||||
if (pushedStacks.size() == 0)
|
||||
return false;
|
||||
|
||||
userMemory.Free(currentStack.start);
|
||||
currentStack = pushedStacks.back();
|
||||
pushedStacks.pop_back();
|
||||
nt.initialStack = currentStack.start;
|
||||
nt.stackSize = currentStack.end - currentStack.start;
|
||||
return true;
|
||||
}
|
||||
|
||||
void PSPThread::Cleanup() {
|
||||
// Callbacks are automatically deleted when their owning thread is deleted.
|
||||
for (auto it = callbacks.begin(), end = callbacks.end(); it != end; ++it)
|
||||
kernelObjects.Destroy<PSPCallback>(*it);
|
||||
|
||||
if (pushedStacks.size() != 0) {
|
||||
WARN_LOG_REPORT(Log::sceKernel, "Thread ended within an extended stack");
|
||||
for (size_t i = 0; i < pushedStacks.size(); ++i)
|
||||
userMemory.Free(pushedStacks[i].start);
|
||||
}
|
||||
FreeStack();
|
||||
}
|
||||
|
||||
void setReturnValue(u32 retval);
|
||||
void setReturnValue(u64 retval);
|
||||
void resumeFromWait();
|
||||
bool isWaitingFor(WaitType type, int id) const;
|
||||
int getWaitID(WaitType type) const;
|
||||
ThreadWaitInfo getWaitInfo() const;
|
||||
void PSPThread::DoState(PointerWrap &p) {
|
||||
auto s = p.Section("Thread", 1, 5);
|
||||
if (!s)
|
||||
return;
|
||||
|
||||
// Utils
|
||||
inline bool isRunning() const { return (nt.status & THREADSTATUS_RUNNING) != 0; }
|
||||
inline bool isStopped() const { return (nt.status & THREADSTATUS_DORMANT) != 0; }
|
||||
inline bool isReady() const { return (nt.status & THREADSTATUS_READY) != 0; }
|
||||
inline bool isWaiting() const { return (nt.status & THREADSTATUS_WAIT) != 0; }
|
||||
inline bool isSuspended() const { return (nt.status & THREADSTATUS_SUSPEND) != 0; }
|
||||
Do(p, nt);
|
||||
Do(p, waitInfo);
|
||||
Do(p, moduleId);
|
||||
Do(p, isProcessingCallbacks);
|
||||
Do(p, currentMipscallId);
|
||||
Do(p, currentCallbackId);
|
||||
|
||||
void DoState(PointerWrap &p) override
|
||||
{
|
||||
auto s = p.Section("Thread", 1, 5);
|
||||
if (!s)
|
||||
return;
|
||||
// TODO: If we want to "version" a DoState method here, we can just use minVer = 0.
|
||||
Do(p, context);
|
||||
|
||||
Do(p, nt);
|
||||
Do(p, waitInfo);
|
||||
Do(p, moduleId);
|
||||
Do(p, isProcessingCallbacks);
|
||||
Do(p, currentMipscallId);
|
||||
Do(p, currentCallbackId);
|
||||
|
||||
// TODO: If we want to "version" a DoState method here, we can just use minVer = 0.
|
||||
Do(p, context);
|
||||
|
||||
if (s <= 3)
|
||||
{
|
||||
// We must have been loading an old state if we're here.
|
||||
// Reorder VFPU data to new order.
|
||||
float temp[128];
|
||||
memcpy(temp, context.v, 128 * sizeof(float));
|
||||
for (int i = 0; i < 128; i++) {
|
||||
context.v[voffset[i]] = temp[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (s <= 2)
|
||||
{
|
||||
context.other[4] = context.other[5];
|
||||
context.other[3] = context.other[4];
|
||||
}
|
||||
if (s <= 4)
|
||||
std::swap(context.hi, context.lo);
|
||||
|
||||
Do(p, callbacks);
|
||||
|
||||
Do(p, pendingMipsCalls);
|
||||
Do(p, pushedStacks);
|
||||
Do(p, currentStack);
|
||||
|
||||
if (s >= 2)
|
||||
{
|
||||
Do(p, waitingThreads);
|
||||
Do(p, pausedWaits);
|
||||
if (s <= 3) {
|
||||
// We must have been loading an old state if we're here.
|
||||
// Reorder VFPU data to new order.
|
||||
float temp[128];
|
||||
memcpy(temp, context.v, 128 * sizeof(float));
|
||||
for (int i = 0; i < 128; i++) {
|
||||
context.v[voffset[i]] = temp[i];
|
||||
}
|
||||
}
|
||||
|
||||
NativeThread nt{};
|
||||
if (s <= 2) {
|
||||
context.other[4] = context.other[5];
|
||||
context.other[3] = context.other[4];
|
||||
}
|
||||
if (s <= 4)
|
||||
std::swap(context.hi, context.lo);
|
||||
|
||||
ThreadWaitInfo waitInfo{};
|
||||
SceUID moduleId = -1;
|
||||
Do(p, callbacks);
|
||||
|
||||
bool isProcessingCallbacks = false;
|
||||
u32 currentMipscallId = -1;
|
||||
SceUID currentCallbackId = -1;
|
||||
Do(p, pendingMipsCalls);
|
||||
Do(p, pushedStacks);
|
||||
Do(p, currentStack);
|
||||
|
||||
PSPThreadContext context{};
|
||||
KernelThreadDebugInterface debug;
|
||||
if (s >= 2) {
|
||||
Do(p, waitingThreads);
|
||||
Do(p, pausedWaits);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<SceUID> callbacks;
|
||||
|
||||
std::list<u32> pendingMipsCalls;
|
||||
|
||||
struct StackInfo {
|
||||
u32 start;
|
||||
u32 end;
|
||||
};
|
||||
// This is a stack of... stacks, since sceKernelExtendThreadStack() can recurse.
|
||||
// These are stacks that aren't "active" right now, but will pop off once the func returns.
|
||||
std::vector<StackInfo> pushedStacks;
|
||||
|
||||
StackInfo currentStack{};
|
||||
|
||||
// For thread end.
|
||||
std::vector<SceUID> waitingThreads;
|
||||
// Key is the callback id it was for, or if no callback, the thread id.
|
||||
std::map<SceUID, u64> pausedWaits;
|
||||
};
|
||||
|
||||
struct WaitTypeFuncs
|
||||
{
|
||||
|
@ -3104,7 +2971,20 @@ void __KernelChangeThreadState(PSPThread *thread, ThreadStatus newStatus) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
const char *ThreadStatusToString(ThreadStatus status) {
|
||||
switch (status) {
|
||||
case THREADSTATUS_RUNNING: return "Running";
|
||||
case THREADSTATUS_READY: return "Ready";
|
||||
case THREADSTATUS_WAIT: return "Wait";
|
||||
case THREADSTATUS_SUSPEND: return "Suspended";
|
||||
case THREADSTATUS_DORMANT: return "Dormant";
|
||||
case THREADSTATUS_DEAD: return "Dead";
|
||||
case THREADSTATUS_WAITSUSPEND: return "WaitSuspended";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return "(unk)";
|
||||
}
|
||||
|
||||
static bool __CanExecuteCallbackNow(PSPThread *thread) {
|
||||
return currentCallbackThreadID == 0 && g_inCbCount == 0;
|
||||
|
@ -3540,7 +3420,7 @@ std::vector<DebugThreadInfo> GetThreadsInfo() {
|
|||
info.id = uid;
|
||||
strncpy(info.name,t->GetName(),KERNELOBJECT_MAX_NAME_LENGTH);
|
||||
info.name[KERNELOBJECT_MAX_NAME_LENGTH] = 0;
|
||||
info.status = t->nt.status;
|
||||
info.status = (ThreadStatus)t->nt.status;
|
||||
info.entrypoint = t->nt.entrypoint;
|
||||
info.initialStack = t->nt.initialStack;
|
||||
info.stackSize = (u32)t->nt.stackSize;
|
||||
|
|
|
@ -19,15 +19,20 @@
|
|||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <list>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Core/HLE/sceKernel.h"
|
||||
#include "Core/HLE/PSPThreadContext.h"
|
||||
#include "Core/HLE/KernelThreadDebugInterface.h"
|
||||
|
||||
// There's a good description of the thread scheduling rules in:
|
||||
// http://code.google.com/p/jpcsp/source/browse/trunk/src/jpcsp/HLE/modules150/ThreadManForUser.java
|
||||
|
||||
class PSPThread;
|
||||
class DebugInterface;
|
||||
class BlockAllocator;
|
||||
|
||||
int sceKernelChangeThreadPriority(SceUID threadID, int priority);
|
||||
SceUID __KernelCreateThreadInternal(const char *threadName, SceUID moduleID, u32 entry, u32 prio, int stacksize, u32 attr);
|
||||
|
@ -82,8 +87,7 @@ struct SceKernelSysClock {
|
|||
|
||||
// TODO: Map these to PSP wait types. Most of these are wrong.
|
||||
// remember to update the waitTypeNames array in sceKernelThread.cpp when changing these
|
||||
enum WaitType : int
|
||||
{
|
||||
enum WaitType : int {
|
||||
WAITTYPE_NONE = 0,
|
||||
WAITTYPE_SLEEP = 1,
|
||||
WAITTYPE_DELAY = 2,
|
||||
|
@ -124,34 +128,156 @@ typedef void (* WaitEndCallbackFunc)(SceUID threadID, SceUID prevCallbackId);
|
|||
|
||||
void __KernelRegisterWaitTypeFuncs(WaitType type, WaitBeginCallbackFunc beginFunc, WaitEndCallbackFunc endFunc);
|
||||
|
||||
struct PSPThreadContext {
|
||||
void reset();
|
||||
#if COMMON_LITTLE_ENDIAN
|
||||
typedef WaitType WaitType_le;
|
||||
#else
|
||||
typedef swap_struct_t<WaitType, swap_32_t<WaitType> > WaitType_le;
|
||||
#endif
|
||||
|
||||
// r must be followed by f.
|
||||
u32 r[32];
|
||||
union {
|
||||
float f[32];
|
||||
u32 fi[32];
|
||||
int fs[32];
|
||||
// Real PSP struct, don't change the fields.
|
||||
struct SceKernelThreadRunStatus {
|
||||
SceSize_le size;
|
||||
u32_le status;
|
||||
s32_le currentPriority;
|
||||
WaitType_le waitType;
|
||||
SceUID_le waitID;
|
||||
s32_le wakeupCount;
|
||||
SceKernelSysClock runForClocks;
|
||||
s32_le numInterruptPreempts;
|
||||
s32_le numThreadPreempts;
|
||||
s32_le numReleases;
|
||||
};
|
||||
|
||||
// Real PSP struct, don't change the fields.
|
||||
struct NativeThread {
|
||||
u32_le nativeSize;
|
||||
char name[KERNELOBJECT_MAX_NAME_LENGTH + 1];
|
||||
|
||||
// Threading stuff
|
||||
u32_le attr;
|
||||
u32_le status;
|
||||
u32_le entrypoint;
|
||||
u32_le initialStack;
|
||||
u32_le stackSize;
|
||||
u32_le gpreg;
|
||||
|
||||
s32_le initialPriority;
|
||||
s32_le currentPriority;
|
||||
WaitType_le waitType;
|
||||
SceUID_le waitID;
|
||||
s32_le wakeupCount;
|
||||
s32_le exitStatus;
|
||||
SceKernelSysClock runForClocks;
|
||||
s32_le numInterruptPreempts;
|
||||
s32_le numThreadPreempts;
|
||||
s32_le numReleases;
|
||||
};
|
||||
|
||||
struct ThreadWaitInfo {
|
||||
u32 waitValue;
|
||||
u32 timeoutPtr;
|
||||
};
|
||||
|
||||
enum {
|
||||
PSP_THREAD_ATTR_KERNEL = 0x00001000,
|
||||
PSP_THREAD_ATTR_VFPU = 0x00004000,
|
||||
PSP_THREAD_ATTR_SCRATCH_SRAM = 0x00008000, // Save/restore scratch as part of context???
|
||||
PSP_THREAD_ATTR_NO_FILLSTACK = 0x00100000, // No filling of 0xff.
|
||||
PSP_THREAD_ATTR_CLEAR_STACK = 0x00200000, // Clear thread stack when deleted.
|
||||
PSP_THREAD_ATTR_LOW_STACK = 0x00400000, // Allocate stack from bottom not top.
|
||||
PSP_THREAD_ATTR_USER = 0x80000000,
|
||||
PSP_THREAD_ATTR_USBWLAN = 0xa0000000,
|
||||
PSP_THREAD_ATTR_VSH = 0xc0000000,
|
||||
|
||||
// TODO: Support more, not even sure what all of these mean.
|
||||
PSP_THREAD_ATTR_USER_MASK = 0xf8f060ff,
|
||||
PSP_THREAD_ATTR_USER_ERASE = 0x78800000,
|
||||
PSP_THREAD_ATTR_SUPPORTED = (PSP_THREAD_ATTR_KERNEL | PSP_THREAD_ATTR_VFPU | PSP_THREAD_ATTR_NO_FILLSTACK | PSP_THREAD_ATTR_CLEAR_STACK | PSP_THREAD_ATTR_LOW_STACK | PSP_THREAD_ATTR_USER)
|
||||
};
|
||||
|
||||
enum ThreadStatus : u32 {
|
||||
THREADSTATUS_RUNNING = 1,
|
||||
THREADSTATUS_READY = 2,
|
||||
THREADSTATUS_WAIT = 4,
|
||||
THREADSTATUS_SUSPEND = 8,
|
||||
THREADSTATUS_DORMANT = 16,
|
||||
THREADSTATUS_DEAD = 32,
|
||||
|
||||
THREADSTATUS_WAITSUSPEND = THREADSTATUS_WAIT | THREADSTATUS_SUSPEND
|
||||
};
|
||||
const char *ThreadStatusToString(ThreadStatus status);
|
||||
|
||||
class PSPThread : public KernelObject {
|
||||
public:
|
||||
PSPThread() : debug(context) {}
|
||||
const char *GetName() override { return nt.name; }
|
||||
const char *GetTypeName() override { return GetStaticTypeName(); }
|
||||
static const char *GetStaticTypeName() { return "Thread"; }
|
||||
void GetQuickInfo(char *ptr, int size) override;
|
||||
|
||||
static u32 GetMissingErrorCode();
|
||||
static int GetStaticIDType() { return SCE_KERNEL_TMID_Thread; }
|
||||
int GetIDType() const override { return SCE_KERNEL_TMID_Thread; }
|
||||
|
||||
bool AllocateStack(u32 &stackSize);
|
||||
bool FillStack();
|
||||
void FreeStack();
|
||||
|
||||
bool PushExtendedStack(u32 size);
|
||||
bool PopExtendedStack();
|
||||
|
||||
// Can't use a destructor since savestates will call that too.
|
||||
void Cleanup();
|
||||
|
||||
BlockAllocator &StackAllocator();
|
||||
|
||||
void setReturnValue(u32 retval);
|
||||
void setReturnValue(u64 retval);
|
||||
void resumeFromWait();
|
||||
bool isWaitingFor(WaitType type, int id) const;
|
||||
int getWaitID(WaitType type) const;
|
||||
ThreadWaitInfo getWaitInfo() const;
|
||||
|
||||
// Utils
|
||||
inline bool isRunning() const { return (nt.status & THREADSTATUS_RUNNING) != 0; }
|
||||
inline bool isStopped() const { return (nt.status & THREADSTATUS_DORMANT) != 0; }
|
||||
inline bool isReady() const { return (nt.status & THREADSTATUS_READY) != 0; }
|
||||
inline bool isWaiting() const { return (nt.status & THREADSTATUS_WAIT) != 0; }
|
||||
inline bool isSuspended() const { return (nt.status & THREADSTATUS_SUSPEND) != 0; }
|
||||
|
||||
void DoState(PointerWrap &p) override;
|
||||
|
||||
NativeThread nt{};
|
||||
|
||||
ThreadWaitInfo waitInfo{};
|
||||
SceUID moduleId = -1;
|
||||
KernelThreadDebugInterface debug;
|
||||
|
||||
bool isProcessingCallbacks = false;
|
||||
u32 currentMipscallId = -1;
|
||||
SceUID currentCallbackId = -1;
|
||||
|
||||
PSPThreadContext context{};
|
||||
|
||||
std::vector<SceUID> callbacks;
|
||||
|
||||
// TODO: Should probably just be a vector.
|
||||
std::list<u32> pendingMipsCalls;
|
||||
|
||||
struct StackInfo {
|
||||
u32 start;
|
||||
u32 end;
|
||||
};
|
||||
union {
|
||||
float v[128];
|
||||
u32 vi[128];
|
||||
};
|
||||
u32 vfpuCtrl[16];
|
||||
// This is a stack of... stacks, since sceKernelExtendThreadStack() can recurse.
|
||||
// These are stacks that aren't "active" right now, but will pop off once the func returns.
|
||||
std::vector<StackInfo> pushedStacks;
|
||||
|
||||
union {
|
||||
struct {
|
||||
u32 pc;
|
||||
StackInfo currentStack{};
|
||||
|
||||
u32 lo;
|
||||
u32 hi;
|
||||
|
||||
u32 fcr31;
|
||||
u32 fpcond;
|
||||
};
|
||||
u32 other[6];
|
||||
};
|
||||
// For thread end.
|
||||
std::vector<SceUID> waitingThreads;
|
||||
// Key is the callback id it was for, or if no callback, the thread id.
|
||||
std::map<SceUID, u64> pausedWaits;
|
||||
};
|
||||
|
||||
// Internal API, used by implementations of kernel functions
|
||||
|
@ -296,18 +422,6 @@ public:
|
|||
int actionTypeID;
|
||||
};
|
||||
|
||||
enum ThreadStatus
|
||||
{
|
||||
THREADSTATUS_RUNNING = 1,
|
||||
THREADSTATUS_READY = 2,
|
||||
THREADSTATUS_WAIT = 4,
|
||||
THREADSTATUS_SUSPEND = 8,
|
||||
THREADSTATUS_DORMANT = 16,
|
||||
THREADSTATUS_DEAD = 32,
|
||||
|
||||
THREADSTATUS_WAITSUSPEND = THREADSTATUS_WAIT | THREADSTATUS_SUSPEND
|
||||
};
|
||||
|
||||
void __KernelChangeThreadState(PSPThread *thread, ThreadStatus newStatus);
|
||||
|
||||
typedef void (*ThreadCallback)(SceUID threadID);
|
||||
|
@ -317,7 +431,7 @@ struct DebugThreadInfo
|
|||
{
|
||||
SceUID id;
|
||||
char name[KERNELOBJECT_MAX_NAME_LENGTH+1];
|
||||
u32 status;
|
||||
ThreadStatus status;
|
||||
u32 curPC;
|
||||
u32 entrypoint;
|
||||
u32 initialStack;
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <cstdio>
|
||||
|
||||
#include "Common/Math/expression_parser.h"
|
||||
#include "Core/MIPS/MIPS.h"
|
||||
#include "Core/Debugger/DebugInterface.h"
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
#include "Core/HLE/ErrorCodes.h"
|
||||
#include "Core/HLE/sceKernelMemory.h"
|
||||
#include "Core/HLE/sceKernelInterrupt.h"
|
||||
#include "Core/HLE/sceKernelThread.h"
|
||||
#include "Core/HLE/sceGe.h"
|
||||
#include "Core/Util/PPGeDraw.h"
|
||||
#include "Core/MemMapHelpers.h"
|
||||
|
@ -37,6 +36,8 @@
|
|||
#include "GPU/Debugger/Record.h"
|
||||
#include "GPU/Debugger/Stepping.h"
|
||||
|
||||
bool __KernelIsDispatchEnabled();
|
||||
|
||||
void GPUCommon::Flush() {
|
||||
drawEngineCommon_->Flush();
|
||||
}
|
||||
|
|
|
@ -306,21 +306,6 @@ static void DrawVFPU(ImConfig &config, ImControl &control, const MIPSDebugInterf
|
|||
ImGui::End();
|
||||
}
|
||||
|
||||
static const char *ThreadStatusToString(u32 status) {
|
||||
switch (status) {
|
||||
case THREADSTATUS_RUNNING: return "Running";
|
||||
case THREADSTATUS_READY: return "Ready";
|
||||
case THREADSTATUS_WAIT: return "Wait";
|
||||
case THREADSTATUS_SUSPEND: return "Suspended";
|
||||
case THREADSTATUS_DORMANT: return "Dormant";
|
||||
case THREADSTATUS_DEAD: return "Dead";
|
||||
case THREADSTATUS_WAITSUSPEND: return "WaitSuspended";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return "(unk)";
|
||||
}
|
||||
|
||||
void WaitIDToString(WaitType waitType, SceUID waitID, char *buffer, size_t bufSize) {
|
||||
switch (waitType) {
|
||||
case WAITTYPE_AUDIOCHANNEL:
|
||||
|
|
Loading…
Add table
Reference in a new issue