mirror of
https://github.com/libretro/Play-.git
synced 2025-02-04 16:06:05 +00:00
git-svn-id: http://svn.purei.org/purei/trunk@174 b36208d7-6611-0410-8bec-b1987f11c4a2
This commit is contained in:
parent
d75bac07a3
commit
8a1f6fe2f5
@ -5,6 +5,11 @@
|
||||
#include "PtrMacro.h"
|
||||
#include "CacheBlock.h"
|
||||
#include "MIPS.h"
|
||||
#include "COP_SCU.h"
|
||||
#include "X86Assembler.h"
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
using namespace boost;
|
||||
|
||||
#ifdef AMD64
|
||||
|
||||
@ -124,6 +129,12 @@ void CCacheBlock::InsertProlog(CMIPS* pCtx)
|
||||
|
||||
void CCacheBlock::InsertEpilog(CMIPS* pCtx, bool nDelayJump)
|
||||
{
|
||||
CX86Assembler assembler(
|
||||
bind(&CCacheBlock::StreamWriteByte, this, _1),
|
||||
bind(&CCacheBlock::StreamWriteAt, this, _1, _2),
|
||||
bind(&CCacheBlock::StreamGetSize, this)
|
||||
);
|
||||
|
||||
//Check delay slot (we truly need to do something better about this...)
|
||||
if(nDelayJump)
|
||||
{
|
||||
@ -208,6 +219,17 @@ void CCacheBlock::InsertEpilog(CMIPS* pCtx, bool nDelayJump)
|
||||
StreamWrite(1, 0xC3);
|
||||
}
|
||||
|
||||
{
|
||||
CX86Assembler::LABEL label = assembler.CreateLabel();
|
||||
assembler.CmpId(
|
||||
CX86Assembler::MakeIndRegOffAddress(CX86Assembler::rBP, offsetof(CMIPS, m_State.nCOP0[CCOP_SCU::EPC])), 0);
|
||||
assembler.JeJb(label);
|
||||
assembler.MovId(CX86Assembler::rAX, RET_CODE_EXCEPTION);
|
||||
assembler.Ret();
|
||||
assembler.MarkLabel(label);
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
//Decrement quota
|
||||
|
||||
@ -235,6 +257,7 @@ void CCacheBlock::InsertEpilog(CMIPS* pCtx, bool nDelayJump)
|
||||
SynchornizePC(pCtx);
|
||||
}
|
||||
|
||||
assembler.ResolveLabelReferences();
|
||||
}
|
||||
|
||||
void CCacheBlock::SynchornizePC(CMIPS* pCtx)
|
||||
|
@ -23,6 +23,7 @@ enum RET_CODE
|
||||
RET_CODE_QUOTADONE,
|
||||
RET_CODE_BREAKPOINT,
|
||||
RET_CODE_INTERBLOCKJUMP,
|
||||
RET_CODE_EXCEPTION,
|
||||
};
|
||||
|
||||
class CCacheBlock
|
||||
|
@ -15,7 +15,12 @@ CArrayStack<uint32> CCodeGen::m_Shadow;
|
||||
CArrayStack<uint32, 2> CCodeGen::m_PullReg64Stack;
|
||||
#endif
|
||||
CArrayStack<uint32> CCodeGen::m_IfStack;
|
||||
CX86Assembler CCodeGen::m_Assembler(&CCodeGen::WriteByte);
|
||||
CX86Assembler CCodeGen::m_Assembler
|
||||
(
|
||||
&CCodeGen::StreamWriteByte,
|
||||
&CCodeGen::StreamWriteAt,
|
||||
&CCodeGen::StreamTell
|
||||
);
|
||||
|
||||
bool CCodeGen::m_nRegisterAllocated[MAX_REGISTER];
|
||||
|
||||
@ -2377,6 +2382,25 @@ void CCodeGen::Sub()
|
||||
m_Shadow.Push(nRegister);
|
||||
m_Shadow.Push(REGISTER);
|
||||
}
|
||||
else if((m_Shadow.GetAt(0) == CONSTANT) && (m_Shadow.GetAt(2) == RELATIVE))
|
||||
{
|
||||
uint32 nRelative, nConstant, nRegister;
|
||||
|
||||
m_Shadow.Pull();
|
||||
nConstant = m_Shadow.Pull();
|
||||
m_Shadow.Pull();
|
||||
nRelative = m_Shadow.Pull();
|
||||
|
||||
nRegister = AllocateRegister();
|
||||
LoadRelativeInRegister(nRegister, nRelative);
|
||||
|
||||
m_Assembler.SubId(
|
||||
CX86Assembler::MakeRegisterAddress(m_nRegisterLookupEx[nRegister]),
|
||||
nConstant);
|
||||
|
||||
m_Shadow.Push(nRegister);
|
||||
m_Shadow.Push(REGISTER);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(0);
|
||||
@ -2845,11 +2869,21 @@ bool CCodeGen::IsTopContRelCstPair64()
|
||||
}
|
||||
}
|
||||
|
||||
void CCodeGen::WriteByte(uint8 nByte)
|
||||
void CCodeGen::StreamWriteByte(uint8 nByte)
|
||||
{
|
||||
m_pBlock->StreamWriteByte(nByte);
|
||||
}
|
||||
|
||||
void CCodeGen::StreamWriteAt(unsigned int position, uint8 value)
|
||||
{
|
||||
m_pBlock->StreamWriteAt(position, value);
|
||||
}
|
||||
|
||||
size_t CCodeGen::StreamTell()
|
||||
{
|
||||
return m_pBlock->StreamGetSize();
|
||||
}
|
||||
|
||||
void CCodeGen::X86_RegImmOp(unsigned int nRegister, uint32 nConstant, unsigned int nOp)
|
||||
{
|
||||
assert(nOp < 8);
|
||||
|
@ -182,7 +182,9 @@ private:
|
||||
static void Cmp64Cont(CONDITION);
|
||||
|
||||
static void X86_RegImmOp(unsigned int, uint32, unsigned int);
|
||||
static void WriteByte(uint8);
|
||||
static void StreamWriteByte(uint8);
|
||||
static void StreamWriteAt(unsigned int, uint8);
|
||||
static size_t StreamTell();
|
||||
|
||||
static bool m_nBlockStarted;
|
||||
|
||||
|
@ -72,6 +72,7 @@ public:
|
||||
|
||||
enum MIPS_RELOCATION_TYPE
|
||||
{
|
||||
R_MIPS_32 = 2,
|
||||
R_MIPS_26 = 4,
|
||||
R_MIPS_HI16 = 5,
|
||||
R_MIPS_LO16 = 6,
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include "MA_MIPSIV.h"
|
||||
#include "MIPS.h"
|
||||
#include "CodeGen.h"
|
||||
#include "COP_SCU.h"
|
||||
|
||||
#undef offsetof
|
||||
#define offsetof(a, b) (reinterpret_cast<uint8*>(&reinterpret_cast<a*>(0x10)->b) - reinterpret_cast<uint8*>(0x10))
|
||||
@ -406,21 +407,25 @@ void CMA_MIPSIV::ADDI()
|
||||
//09
|
||||
void CMA_MIPSIV::ADDIU()
|
||||
{
|
||||
if(m_nRT == 0)
|
||||
{
|
||||
//Hack: PS2 IOP uses ADDIU R0, R0, $x for dynamic linking
|
||||
SYSCALL();
|
||||
return;
|
||||
}
|
||||
|
||||
CCodeGen::Begin(m_pB);
|
||||
{
|
||||
CCodeGen::PushRel(offsetof(CMIPS, m_State.nGPR[m_nRS].nV[0]));
|
||||
CCodeGen::PushCst((int16)m_nImmediate);
|
||||
CCodeGen::Add();
|
||||
CCodeGen::SeX();
|
||||
CCodeGen::PullRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[1]));
|
||||
CCodeGen::PullRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[0]));
|
||||
if(m_nRT == 0)
|
||||
{
|
||||
//Hack: PS2 IOP uses ADDIU R0, R0, $x for dynamic linking
|
||||
CCodeGen::PushRel(offsetof(CMIPS, m_State.nPC));
|
||||
CCodeGen::PushCst(4);
|
||||
CCodeGen::Sub();
|
||||
CCodeGen::PullRel(offsetof(CMIPS, m_State.nCOP0[CCOP_SCU::EPC]));
|
||||
}
|
||||
else
|
||||
{
|
||||
CCodeGen::PushRel(offsetof(CMIPS, m_State.nGPR[m_nRS].nV[0]));
|
||||
CCodeGen::PushCst((int16)m_nImmediate);
|
||||
CCodeGen::Add();
|
||||
CCodeGen::SeX();
|
||||
CCodeGen::PullRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[1]));
|
||||
CCodeGen::PullRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[0]));
|
||||
}
|
||||
}
|
||||
CCodeGen::End();
|
||||
}
|
||||
@ -1686,9 +1691,13 @@ void CMA_MIPSIV::SYSCALL()
|
||||
{
|
||||
CCodeGen::Begin(m_pB);
|
||||
{
|
||||
CCodeGen::PushRef(m_pCtx);
|
||||
CCodeGen::Call(reinterpret_cast<void*>(m_pCtx->m_pSysCallHandler), 1, false);
|
||||
m_pB->SetProgramCounterChanged();
|
||||
CCodeGen::PushRel(offsetof(CMIPS, m_State.nPC));
|
||||
CCodeGen::PushCst(4);
|
||||
CCodeGen::Sub();
|
||||
CCodeGen::PullRel(offsetof(CMIPS, m_State.nCOP0[CCOP_SCU::EPC]));
|
||||
// CCodeGen::PushRef(m_pCtx);
|
||||
// CCodeGen::Call(reinterpret_cast<void*>(m_pCtx->m_pSysCallHandler), 1, false);
|
||||
// m_pB->SetProgramCounterChanged();
|
||||
}
|
||||
CCodeGen::End();
|
||||
|
||||
|
@ -53,6 +53,7 @@ void CMIPSAnalysis::Analyse(uint32 nStart, uint32 nEnd)
|
||||
|
||||
nFound = 0;
|
||||
nCandidate = nStart;
|
||||
nReturnAddr = 0;
|
||||
|
||||
while(nCandidate != nEnd)
|
||||
{
|
||||
|
@ -1,7 +1,16 @@
|
||||
#include "X86Assembler.h"
|
||||
|
||||
CX86Assembler::CX86Assembler(const WriteFunctionType& WriteFunction) :
|
||||
m_WriteFunction(WriteFunction)
|
||||
using namespace std;
|
||||
|
||||
CX86Assembler::CX86Assembler(
|
||||
const WriteFunctionType& WriteFunction,
|
||||
const WriteAtFunctionType& WriteAtFunction,
|
||||
const TellFunctionType& TellFunction
|
||||
) :
|
||||
m_WriteFunction(WriteFunction),
|
||||
m_WriteAtFunction(WriteAtFunction),
|
||||
m_TellFunction(TellFunction),
|
||||
m_nextLabelId(1)
|
||||
{
|
||||
|
||||
}
|
||||
@ -55,6 +64,42 @@ CX86Assembler::CAddress CX86Assembler::MakeIndRegOffAddress(REGISTER nRegister,
|
||||
return Address;
|
||||
}
|
||||
|
||||
CX86Assembler::LABEL CX86Assembler::CreateLabel()
|
||||
{
|
||||
return m_nextLabelId++;
|
||||
}
|
||||
|
||||
void CX86Assembler::MarkLabel(LABEL label)
|
||||
{
|
||||
m_labels[label] = m_TellFunction();
|
||||
}
|
||||
|
||||
void CX86Assembler::ResolveLabelReferences()
|
||||
{
|
||||
for(LabelReferenceMapType::iterator labelRef(m_labelReferences.begin());
|
||||
m_labelReferences.end() != labelRef; labelRef++)
|
||||
{
|
||||
LabelMapType::iterator label(m_labels.find(labelRef->first));
|
||||
if(label == m_labels.end())
|
||||
{
|
||||
throw runtime_error("Invalid label.");
|
||||
}
|
||||
size_t referencePos = labelRef->second.address;
|
||||
size_t labelPos = label->second;
|
||||
unsigned int referenceSize = labelRef->second.offsetSize;
|
||||
int offset = static_cast<int>(labelPos - referencePos - referenceSize);
|
||||
if(referenceSize == 1)
|
||||
{
|
||||
if(offset > 127 || offset < -128)
|
||||
{
|
||||
throw runtime_error("Label reference too small.");
|
||||
}
|
||||
m_WriteAtFunction(referencePos, static_cast<uint8>(offset));
|
||||
}
|
||||
}
|
||||
m_labelReferences.clear();
|
||||
}
|
||||
|
||||
void CX86Assembler::AddId(const CAddress& Address, uint32 nConstant)
|
||||
{
|
||||
WriteEvId(0x00, Address, nConstant);
|
||||
@ -75,6 +120,20 @@ void CX86Assembler::CmpIq(const CAddress& Address, uint64 nConstant)
|
||||
WriteEvIq(0x07, Address, nConstant);
|
||||
}
|
||||
|
||||
void CX86Assembler::JeJb(LABEL label)
|
||||
{
|
||||
WriteByte(0x74);
|
||||
CreateLabelReference(label, 1);
|
||||
WriteByte(0x00);
|
||||
}
|
||||
|
||||
void CX86Assembler::JneJb(LABEL label)
|
||||
{
|
||||
WriteByte(0x75);
|
||||
CreateLabelReference(label, 1);
|
||||
WriteByte(0x00);
|
||||
}
|
||||
|
||||
void CX86Assembler::Nop()
|
||||
{
|
||||
WriteByte(0x90);
|
||||
@ -103,6 +162,11 @@ void CX86Assembler::MovId(REGISTER nRegister, uint32 nConstant)
|
||||
WriteDWord(nConstant);
|
||||
}
|
||||
|
||||
void CX86Assembler::Ret()
|
||||
{
|
||||
WriteByte(0xC3);
|
||||
}
|
||||
|
||||
void CX86Assembler::SubEd(REGISTER nRegister, const CAddress& Address)
|
||||
{
|
||||
WriteEvGvOp(0x2B, false, Address, nRegister);
|
||||
@ -199,6 +263,14 @@ void CX86Assembler::WriteEvIq(uint8 nOp, const CAddress& Address, uint64 nConsta
|
||||
}
|
||||
}
|
||||
|
||||
void CX86Assembler::CreateLabelReference(LABEL label, unsigned int size)
|
||||
{
|
||||
LABELREF reference;
|
||||
reference.address = m_TellFunction();
|
||||
reference.offsetSize = size;
|
||||
m_labelReferences.insert(LabelReferenceMapType::value_type(label, reference));
|
||||
}
|
||||
|
||||
unsigned int CX86Assembler::GetMinimumConstantSize(uint32 nConstant)
|
||||
{
|
||||
if((static_cast<int32>(nConstant) >= -128) && (static_cast<int32>(nConstant) <= 127))
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include "Types.h"
|
||||
#include <boost/function.hpp>
|
||||
#include <map>
|
||||
|
||||
class CX86Assembler
|
||||
{
|
||||
@ -27,7 +28,10 @@ public:
|
||||
r15,
|
||||
};
|
||||
|
||||
typedef boost::function<void (uint8)> WriteFunctionType;
|
||||
typedef boost::function<void (uint8)> WriteFunctionType;
|
||||
typedef boost::function<void (unsigned int, uint8)> WriteAtFunctionType;
|
||||
typedef boost::function<size_t ()> TellFunctionType;
|
||||
typedef unsigned int LABEL;
|
||||
|
||||
class CAddress
|
||||
{
|
||||
@ -53,39 +57,65 @@ public:
|
||||
void Write(const WriteFunctionType&);
|
||||
};
|
||||
|
||||
CX86Assembler(const WriteFunctionType&);
|
||||
CX86Assembler(
|
||||
const WriteFunctionType&,
|
||||
const WriteAtFunctionType&,
|
||||
const TellFunctionType&);
|
||||
virtual ~CX86Assembler();
|
||||
|
||||
static CAddress MakeRegisterAddress(REGISTER);
|
||||
static CAddress MakeIndRegOffAddress(REGISTER, uint32);
|
||||
|
||||
LABEL CreateLabel();
|
||||
void MarkLabel(LABEL);
|
||||
void ResolveLabelReferences();
|
||||
|
||||
void AddId(const CAddress&, uint32);
|
||||
void CmpEq(REGISTER, const CAddress&);
|
||||
void CmpId(const CAddress&, uint32);
|
||||
void CmpIq(const CAddress&, uint64);
|
||||
void JeJb(LABEL);
|
||||
void JneJb(LABEL);
|
||||
void Nop();
|
||||
void MovEd(REGISTER, const CAddress&);
|
||||
void MovEq(REGISTER, const CAddress&);
|
||||
void MovGd(const CAddress&, REGISTER);
|
||||
void MovId(REGISTER, uint32);
|
||||
void Ret();
|
||||
void SubEd(REGISTER, const CAddress&);
|
||||
void SubId(const CAddress&, uint32);
|
||||
void XorGd(const CAddress&, REGISTER);
|
||||
void XorGq(const CAddress&, REGISTER);
|
||||
|
||||
private:
|
||||
struct LABELREF
|
||||
{
|
||||
size_t address;
|
||||
unsigned int offsetSize;
|
||||
};
|
||||
|
||||
typedef std::map<LABEL, size_t> LabelMapType;
|
||||
typedef std::multimap<LABEL, LABELREF> LabelReferenceMapType;
|
||||
|
||||
void WriteRexByte(bool, const CAddress&);
|
||||
void WriteRexByte(bool, const CAddress&, REGISTER&);
|
||||
void WriteEvGvOp(uint8, bool, const CAddress&, REGISTER);
|
||||
void WriteEvId(uint8, const CAddress&, uint32);
|
||||
void WriteEvIq(uint8, const CAddress&, uint64);
|
||||
|
||||
void CreateLabelReference(LABEL, unsigned int);
|
||||
|
||||
static unsigned int GetMinimumConstantSize(uint32);
|
||||
static unsigned int GetMinimumConstantSize64(uint64);
|
||||
|
||||
void WriteByte(uint8);
|
||||
void WriteDWord(uint32);
|
||||
WriteFunctionType m_WriteFunction;
|
||||
WriteAtFunctionType m_WriteAtFunction;
|
||||
TellFunctionType m_TellFunction;
|
||||
LabelMapType m_labels;
|
||||
LabelReferenceMapType m_labelReferences;
|
||||
LABEL m_nextLabelId;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -188,18 +188,38 @@
|
||||
RelativePath=".\Source\Ioman_Psf.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Source\Iop_Dynamic.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Source\Iop_Ioman.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Source\Iop_Loadcore.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Source\Iop_Modload.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Source\Iop_Stdio.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Source\Iop_Sysclib.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Source\Iop_Sysmem.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Source\IopBios.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Source\win32\MiniDebugger.cpp"
|
||||
>
|
||||
@ -254,10 +274,22 @@
|
||||
RelativePath=".\Source\Ioman_Psf.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Source\Iop_Dynamic.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Source\Iop_Ioman.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Source\Iop_Loadcore.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Source\Iop_Modload.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Source\Iop_Module.h"
|
||||
>
|
||||
@ -266,10 +298,18 @@
|
||||
RelativePath=".\Source\Iop_Stdio.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Source\Iop_Sysclib.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Source\Iop_Sysmem.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Source\IopBios.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Source\win32\MiniDebugger.h"
|
||||
>
|
||||
|
358
tools/PsfPlayer/Source/IopBios.cpp
Normal file
358
tools/PsfPlayer/Source/IopBios.cpp
Normal file
@ -0,0 +1,358 @@
|
||||
#include "IopBios.h"
|
||||
#include "COP_SCU.h"
|
||||
#include "Iop_Sysclib.h"
|
||||
#include "Iop_Loadcore.h"
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
using namespace Framework;
|
||||
|
||||
CIopBios::CIopBios(uint32 baseAddress, CMIPS& cpu, uint8* ram, uint32 ramSize) :
|
||||
m_baseAddress(baseAddress),
|
||||
m_cpu(cpu),
|
||||
m_ram(ram),
|
||||
m_nextThreadId(1),
|
||||
m_stdio(NULL),
|
||||
m_sysmem(NULL),
|
||||
m_ioman(NULL),
|
||||
m_modload(NULL),
|
||||
m_currentThreadId(-1)
|
||||
{
|
||||
CMIPSAssembler assembler(reinterpret_cast<uint32*>(&m_ram[m_baseAddress]));
|
||||
m_threadFinishAddress = AssembleThreadFinish(assembler);
|
||||
|
||||
//Register built-in modules
|
||||
{
|
||||
m_stdio = new Iop::CStdio(m_ram);
|
||||
RegisterModule(m_stdio);
|
||||
}
|
||||
{
|
||||
m_ioman = new Iop::CIoman(m_ram);
|
||||
RegisterModule(m_ioman);
|
||||
}
|
||||
{
|
||||
m_sysmem = new Iop::CSysmem(0x1000, ramSize);
|
||||
RegisterModule(m_sysmem);
|
||||
}
|
||||
{
|
||||
m_modload = new Iop::CModload(*this, m_ram);
|
||||
RegisterModule(m_modload);
|
||||
}
|
||||
{
|
||||
RegisterModule(new Iop::CSysclib(m_ram));
|
||||
}
|
||||
{
|
||||
RegisterModule(new Iop::CLoadcore(*this, m_ram));
|
||||
}
|
||||
}
|
||||
|
||||
CIopBios::~CIopBios()
|
||||
{
|
||||
while(m_modules.size() != 0)
|
||||
{
|
||||
delete m_modules.begin()->second;
|
||||
m_modules.erase(m_modules.begin());
|
||||
}
|
||||
}
|
||||
|
||||
void CIopBios::LoadAndStartModule(const char* path, const char* args, unsigned int argsLength)
|
||||
{
|
||||
uint32 entryPoint = LoadExecutable(path);
|
||||
uint32 threadId = CreateThread(entryPoint);
|
||||
THREAD& thread = GetThread(threadId);
|
||||
|
||||
typedef vector<uint32> ParamListType;
|
||||
ParamListType paramList;
|
||||
|
||||
paramList.push_back(Push(
|
||||
thread.context.gpr[CMIPS::SP],
|
||||
reinterpret_cast<const uint8*>(path),
|
||||
static_cast<uint32>(strlen(path)) + 1));
|
||||
if(argsLength != 0 && args != NULL)
|
||||
{
|
||||
paramList.push_back(Push(
|
||||
thread.context.gpr[CMIPS::SP],
|
||||
reinterpret_cast<const uint8*>(args),
|
||||
static_cast<uint32>(strlen(args)) + 1));
|
||||
}
|
||||
thread.context.gpr[CMIPS::A0] = paramList.size();
|
||||
for(ParamListType::reverse_iterator param(paramList.rbegin());
|
||||
paramList.rend() != param; param++)
|
||||
{
|
||||
thread.context.gpr[CMIPS::A1] = Push(
|
||||
thread.context.gpr[CMIPS::SP],
|
||||
reinterpret_cast<const uint8*>(&(*param)),
|
||||
4);
|
||||
}
|
||||
|
||||
Reschedule();
|
||||
}
|
||||
|
||||
CIopBios::THREAD& CIopBios::GetThread(uint32 threadId)
|
||||
{
|
||||
return GetThreadPosition(threadId)->second;
|
||||
}
|
||||
|
||||
CIopBios::ThreadMapType::iterator CIopBios::GetThreadPosition(uint32 threadId)
|
||||
{
|
||||
for(ThreadMapType::iterator thread(m_threads.begin());
|
||||
thread != m_threads.end(); thread++)
|
||||
{
|
||||
if(thread->second.id == threadId)
|
||||
{
|
||||
return thread;
|
||||
}
|
||||
}
|
||||
throw runtime_error("Unexisting thread id.");
|
||||
}
|
||||
|
||||
uint32 CIopBios::CreateThread(uint32 threadProc)
|
||||
{
|
||||
THREAD thread;
|
||||
memset(&thread, 0, sizeof(thread));
|
||||
thread.context.delayJump = 1;
|
||||
uint32 stackBaseAddress = m_sysmem->AllocateMemory(DEFAULT_STACKSIZE, 0);
|
||||
thread.id = m_nextThreadId++;
|
||||
thread.priority = 7;
|
||||
thread.context.epc = threadProc;
|
||||
thread.context.gpr[CMIPS::RA] = m_threadFinishAddress;
|
||||
thread.context.gpr[CMIPS::SP] = stackBaseAddress;
|
||||
m_threads.insert(ThreadMapType::value_type(thread.priority, thread));
|
||||
return thread.id;
|
||||
}
|
||||
|
||||
void CIopBios::ExitCurrentThread()
|
||||
{
|
||||
ThreadMapType::iterator thread = GetThreadPosition(m_currentThreadId);
|
||||
m_threads.erase(thread);
|
||||
m_currentThreadId = -1;
|
||||
Reschedule();
|
||||
}
|
||||
|
||||
void CIopBios::LoadThreadContext(uint32 threadId)
|
||||
{
|
||||
THREAD& thread = GetThread(threadId);
|
||||
for(unsigned int i = 0; i < 32; i++)
|
||||
{
|
||||
if(i == CMIPS::R0) continue;
|
||||
if(i == CMIPS::K0) continue;
|
||||
if(i == CMIPS::K1) continue;
|
||||
m_cpu.m_State.nGPR[i].nD0 = static_cast<int32>(thread.context.gpr[i]);
|
||||
}
|
||||
m_cpu.m_State.nPC = thread.context.epc;
|
||||
m_cpu.m_State.nDelayedJumpAddr = thread.context.delayJump;
|
||||
}
|
||||
|
||||
void CIopBios::SaveThreadContext(uint32 threadId)
|
||||
{
|
||||
THREAD& thread = GetThread(threadId);
|
||||
for(unsigned int i = 0; i < 32; i++)
|
||||
{
|
||||
if(i == CMIPS::R0) continue;
|
||||
if(i == CMIPS::K0) continue;
|
||||
if(i == CMIPS::K1) continue;
|
||||
thread.context.gpr[i] = m_cpu.m_State.nGPR[i].nV0;
|
||||
}
|
||||
thread.context.epc = m_cpu.m_State.nPC;
|
||||
thread.context.delayJump = m_cpu.m_State.nDelayedJumpAddr;
|
||||
}
|
||||
|
||||
void CIopBios::Reschedule()
|
||||
{
|
||||
if(m_currentThreadId != -1)
|
||||
{
|
||||
SaveThreadContext(m_currentThreadId);
|
||||
//Reinsert the thread into the map
|
||||
ThreadMapType::iterator threadPosition = GetThreadPosition(m_currentThreadId);
|
||||
THREAD thread(threadPosition->second);
|
||||
m_threads.erase(threadPosition);
|
||||
m_threads.insert(ThreadMapType::value_type(thread.priority, thread));
|
||||
}
|
||||
|
||||
THREAD& nextThread = m_threads.begin()->second;
|
||||
LoadThreadContext(nextThread.id);
|
||||
m_currentThreadId = nextThread.id;
|
||||
m_cpu.m_nQuota = 1;
|
||||
}
|
||||
|
||||
Iop::CIoman* CIopBios::GetIoman()
|
||||
{
|
||||
return m_ioman;
|
||||
}
|
||||
|
||||
uint32 CIopBios::AssembleThreadFinish(CMIPSAssembler& assembler)
|
||||
{
|
||||
uint32 address = m_baseAddress + assembler.GetProgramSize();
|
||||
assembler.ADDIU(CMIPS::V0, CMIPS::R0, 0x0666);
|
||||
assembler.SYSCALL();
|
||||
return address;
|
||||
}
|
||||
|
||||
void CIopBios::SysCallHandler()
|
||||
{
|
||||
uint32 searchAddress = m_cpu.m_State.nCOP0[CCOP_SCU::EPC];
|
||||
uint32 callInstruction = m_cpu.m_pMemoryMap->GetWord(searchAddress);
|
||||
if(callInstruction == 0x0000000C)
|
||||
{
|
||||
if(m_cpu.m_State.nGPR[CMIPS::V0].nV0 == 0x666)
|
||||
{
|
||||
ExitCurrentThread();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Search for the import record
|
||||
uint32 instruction = callInstruction;
|
||||
while(instruction != 0x41E00000)
|
||||
{
|
||||
searchAddress -= 4;
|
||||
instruction = m_cpu.m_pMemoryMap->GetWord(searchAddress);
|
||||
}
|
||||
uint32 functionId = callInstruction & 0xFFFF;
|
||||
uint32 version = m_cpu.m_pMemoryMap->GetWord(searchAddress + 8);
|
||||
string moduleName = ReadModuleName(searchAddress + 0x0C);
|
||||
|
||||
IopModuleMapType::iterator module(m_modules.find(moduleName));
|
||||
if(module != m_modules.end())
|
||||
{
|
||||
module->second->Invoke(m_cpu, functionId);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("IOP(%0.8X): Trying to call a function from non-existing module (%s, %d).\r\n",
|
||||
m_cpu.m_State.nPC, moduleName.c_str(), functionId);
|
||||
}
|
||||
}
|
||||
|
||||
m_cpu.m_State.nCOP0[CCOP_SCU::EPC] = 0;
|
||||
}
|
||||
|
||||
string CIopBios::ReadModuleName(uint32 address)
|
||||
{
|
||||
string moduleName;
|
||||
while(1)
|
||||
{
|
||||
uint8 character = m_cpu.m_pMemoryMap->GetByte(address++);
|
||||
if(character == 0) break;
|
||||
if(character < 0x10) continue;
|
||||
moduleName += character;
|
||||
}
|
||||
return moduleName;
|
||||
}
|
||||
|
||||
void CIopBios::RegisterModule(Iop::CModule* module)
|
||||
{
|
||||
m_modules[module->GetId()] = module;
|
||||
}
|
||||
|
||||
uint32 CIopBios::Push(uint32& address, const uint8* data, uint32 size)
|
||||
{
|
||||
uint32 fixedSize = ((size + 0x3) / 0x4) * 0x4;
|
||||
address -= fixedSize;
|
||||
memcpy(&m_ram[address], data, size);
|
||||
return address;
|
||||
}
|
||||
|
||||
uint32 CIopBios::LoadExecutable(const char* path)
|
||||
{
|
||||
uint32 handle = m_ioman->Open(Iop::Ioman::CDevice::O_RDONLY, path);
|
||||
if(handle & 0x80000000)
|
||||
{
|
||||
throw runtime_error("Couldn't open executable for reading.");
|
||||
}
|
||||
Iop::CIoman::CFile file(handle, *m_ioman);
|
||||
CStream* stream = m_ioman->GetFileStream(file);
|
||||
CELF elf(stream);
|
||||
|
||||
uint32 baseAddress = m_sysmem->AllocateMemory(elf.m_nLenght, 0);
|
||||
RelocateElf(elf, baseAddress);
|
||||
|
||||
for(unsigned int i = 0; i < elf.m_Header.nProgHeaderCount; i++)
|
||||
{
|
||||
ELFPROGRAMHEADER* programHeader = elf.GetProgram(i);
|
||||
if(programHeader != NULL && programHeader->nType == 1)
|
||||
{
|
||||
memcpy(
|
||||
m_ram + baseAddress,
|
||||
elf.m_pData + programHeader->nOffset,
|
||||
programHeader->nFileSize);
|
||||
}
|
||||
}
|
||||
|
||||
return baseAddress + elf.m_Header.nEntryPoint;
|
||||
}
|
||||
|
||||
void CIopBios::RelocateElf(CELF& elf, uint32 baseAddress)
|
||||
{
|
||||
//Process relocation
|
||||
for(unsigned int i = 0; i < elf.m_Header.nSectHeaderCount; i++)
|
||||
{
|
||||
ELFSECTIONHEADER* sectionHeader = elf.GetSection(i);
|
||||
if(sectionHeader != NULL && sectionHeader->nType == CELF::SHT_REL)
|
||||
{
|
||||
uint32 lastHi16 = -1;
|
||||
uint32 instructionHi16 = -1;
|
||||
unsigned int linkedSection = sectionHeader->nInfo;
|
||||
unsigned int recordCount = sectionHeader->nSize / 8;
|
||||
ELFSECTIONHEADER* relocatedSection = elf.GetSection(linkedSection);
|
||||
const uint32* relocationRecord = reinterpret_cast<const uint32*>(elf.GetSectionData(i));
|
||||
uint8* relocatedSectionData = reinterpret_cast<uint8*>(const_cast<void*>(elf.GetSectionData(linkedSection)));
|
||||
if(relocatedSection == NULL || relocationRecord == NULL || relocatedSection == NULL) continue;
|
||||
for(unsigned int record = 0; record < recordCount; record++)
|
||||
{
|
||||
uint32 relocationAddress = relocationRecord[0];
|
||||
uint32 relocationType = relocationRecord[1];
|
||||
if(relocationAddress < relocatedSection->nSize)
|
||||
{
|
||||
uint32& instruction = *reinterpret_cast<uint32*>(&relocatedSectionData[relocationAddress]);
|
||||
switch(relocationType)
|
||||
{
|
||||
case CELF::R_MIPS_32:
|
||||
{
|
||||
instruction += baseAddress;
|
||||
}
|
||||
break;
|
||||
case CELF::R_MIPS_26:
|
||||
{
|
||||
uint32 offset = (instruction & 0x03FFFFFF) + (baseAddress >> 2);
|
||||
instruction &= ~0x03FFFFFF;
|
||||
instruction |= offset;
|
||||
}
|
||||
break;
|
||||
case CELF::R_MIPS_HI16:
|
||||
{
|
||||
lastHi16 = relocationAddress;
|
||||
instructionHi16 = instruction;
|
||||
}
|
||||
break;
|
||||
case CELF::R_MIPS_LO16:
|
||||
{
|
||||
if(lastHi16 != -1)
|
||||
{
|
||||
uint32 offset = static_cast<int16>(instruction) + (instructionHi16 << 16);
|
||||
offset += baseAddress;
|
||||
instruction &= ~0xFFFF;
|
||||
instruction |= offset & 0xFFFF;
|
||||
|
||||
uint32& prevInstruction = *reinterpret_cast<uint32*>(&relocatedSectionData[lastHi16]);
|
||||
prevInstruction &= ~0xFFFF;
|
||||
if(offset & 0x8000) offset += 0x10000;
|
||||
prevInstruction |= offset >> 16;
|
||||
lastHi16 = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("%s: No HI16 relocation record found for corresponding LO16.\r\n", __FUNCTION__);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw runtime_error("Unknown relocation type.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
relocationRecord += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
76
tools/PsfPlayer/Source/IopBios.h
Normal file
76
tools/PsfPlayer/Source/IopBios.h
Normal file
@ -0,0 +1,76 @@
|
||||
#ifndef _IOPBIOS_H_
|
||||
#define _IOPBIOS_H_
|
||||
|
||||
#include "MIPSAssembler.h"
|
||||
#include "MIPS.h"
|
||||
#include "ELF.h"
|
||||
#include "Iop_Ioman.h"
|
||||
#include "Iop_Stdio.h"
|
||||
#include "Iop_Sysmem.h"
|
||||
#include "Iop_Modload.h"
|
||||
|
||||
class CIopBios
|
||||
{
|
||||
public:
|
||||
CIopBios(uint32, CMIPS&, uint8*, uint32);
|
||||
virtual ~CIopBios();
|
||||
|
||||
void LoadAndStartModule(const char*, const char*, unsigned int);
|
||||
void SysCallHandler();
|
||||
|
||||
Iop::CIoman* GetIoman();
|
||||
void RegisterModule(Iop::CModule*);
|
||||
|
||||
private:
|
||||
enum DEFAULT_STACKSIZE
|
||||
{
|
||||
DEFAULT_STACKSIZE = 0x8000,
|
||||
};
|
||||
|
||||
struct THREADCONTEXT
|
||||
{
|
||||
uint32 gpr[0x20];
|
||||
uint32 epc;
|
||||
uint32 delayJump;
|
||||
};
|
||||
|
||||
struct THREAD
|
||||
{
|
||||
uint32 id;
|
||||
uint32 priority;
|
||||
THREADCONTEXT context;
|
||||
};
|
||||
|
||||
typedef std::multimap<uint32, THREAD> ThreadMapType;
|
||||
typedef std::map<std::string, Iop::CModule*> IopModuleMapType;
|
||||
|
||||
THREAD& GetThread(uint32);
|
||||
ThreadMapType::iterator GetThreadPosition(uint32);
|
||||
uint32 CreateThread(uint32);
|
||||
void ExitCurrentThread();
|
||||
void LoadThreadContext(uint32);
|
||||
void SaveThreadContext(uint32);
|
||||
void Reschedule();
|
||||
|
||||
uint32 LoadExecutable(const char*);
|
||||
void RelocateElf(CELF&, uint32);
|
||||
std::string ReadModuleName(uint32);
|
||||
uint32 Push(uint32&, const uint8*, uint32);
|
||||
|
||||
uint32 AssembleThreadFinish(CMIPSAssembler&);
|
||||
|
||||
CMIPS& m_cpu;
|
||||
uint8* m_ram;
|
||||
uint32 m_baseAddress;
|
||||
uint32 m_threadFinishAddress;
|
||||
uint32 m_nextThreadId;
|
||||
uint32 m_currentThreadId;
|
||||
ThreadMapType m_threads;
|
||||
IopModuleMapType m_modules;
|
||||
Iop::CStdio* m_stdio;
|
||||
Iop::CIoman* m_ioman;
|
||||
Iop::CSysmem* m_sysmem;
|
||||
Iop::CModload* m_modload;
|
||||
};
|
||||
|
||||
#endif
|
28
tools/PsfPlayer/Source/Iop_Dynamic.cpp
Normal file
28
tools/PsfPlayer/Source/Iop_Dynamic.cpp
Normal file
@ -0,0 +1,28 @@
|
||||
#include "Iop_Dynamic.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace Iop;
|
||||
|
||||
CDynamic::CDynamic(uint32* exportTable) :
|
||||
m_exportTable(exportTable),
|
||||
m_name(reinterpret_cast<char*>(m_exportTable) + 12)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CDynamic::~CDynamic()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
string CDynamic::GetId() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
void CDynamic::Invoke(CMIPS& context, unsigned int functionId)
|
||||
{
|
||||
uint32 functionAddress = m_exportTable[5 + functionId];
|
||||
context.m_State.nGPR[CMIPS::RA].nD0 = context.m_State.nPC;
|
||||
context.m_State.nPC = functionAddress;
|
||||
}
|
23
tools/PsfPlayer/Source/Iop_Dynamic.h
Normal file
23
tools/PsfPlayer/Source/Iop_Dynamic.h
Normal file
@ -0,0 +1,23 @@
|
||||
#ifndef _IOP_DYNAMIC_H_
|
||||
#define _IOP_DYNAMIC_H_
|
||||
|
||||
#include "Iop_Module.h"
|
||||
|
||||
namespace Iop
|
||||
{
|
||||
class CDynamic : public CModule
|
||||
{
|
||||
public:
|
||||
CDynamic(uint32*);
|
||||
virtual ~CDynamic();
|
||||
|
||||
std::string GetId() const;
|
||||
void Invoke(CMIPS&, unsigned int);
|
||||
|
||||
private:
|
||||
uint32* m_exportTable;
|
||||
std::string m_name;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -86,12 +86,8 @@ uint32 CIoman::Read(uint32 handle, uint32 size, void* buffer)
|
||||
uint32 result = 0xFFFFFFFF;
|
||||
try
|
||||
{
|
||||
FileMapType::iterator file(m_files.find(handle));
|
||||
if(file == m_files.end())
|
||||
{
|
||||
throw runtime_error("Invalid file handle.");
|
||||
}
|
||||
result = static_cast<uint32>(file->second->Read(buffer, size));
|
||||
CStream* stream = GetFileStream(handle);
|
||||
result = static_cast<uint32>(stream->Read(buffer, size));
|
||||
}
|
||||
catch(const exception& except)
|
||||
{
|
||||
@ -105,11 +101,7 @@ uint32 CIoman::Seek(uint32 handle, uint32 position, uint32 whence)
|
||||
uint32 result = 0xFFFFFFFF;
|
||||
try
|
||||
{
|
||||
FileMapType::iterator file(m_files.find(handle));
|
||||
if(file == m_files.end())
|
||||
{
|
||||
throw runtime_error("Invalid file handle.");
|
||||
}
|
||||
CStream* stream = GetFileStream(handle);
|
||||
switch(whence)
|
||||
{
|
||||
case 0:
|
||||
@ -123,8 +115,8 @@ uint32 CIoman::Seek(uint32 handle, uint32 position, uint32 whence)
|
||||
break;
|
||||
}
|
||||
|
||||
file->second->Seek(position, static_cast<STREAM_SEEK_DIRECTION>(whence));
|
||||
result = static_cast<uint32>(file->second->Tell());
|
||||
stream->Seek(position, static_cast<STREAM_SEEK_DIRECTION>(whence));
|
||||
result = static_cast<uint32>(stream->Tell());
|
||||
}
|
||||
catch(const exception& except)
|
||||
{
|
||||
@ -133,6 +125,16 @@ uint32 CIoman::Seek(uint32 handle, uint32 position, uint32 whence)
|
||||
return result;
|
||||
}
|
||||
|
||||
CStream* CIoman::GetFileStream(uint32 handle)
|
||||
{
|
||||
FileMapType::iterator file(m_files.find(handle));
|
||||
if(file == m_files.end())
|
||||
{
|
||||
throw runtime_error("Invalid file handle.");
|
||||
}
|
||||
return file->second;
|
||||
}
|
||||
|
||||
void CIoman::Invoke(CMIPS& context, unsigned int functionId)
|
||||
{
|
||||
switch(functionId)
|
||||
@ -166,3 +168,23 @@ void CIoman::Invoke(CMIPS& context, unsigned int functionId)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
//--------------------------------------------------
|
||||
|
||||
CIoman::CFile::CFile(uint32 handle, CIoman& ioman) :
|
||||
m_handle(handle),
|
||||
m_ioman(ioman)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CIoman::CFile::~CFile()
|
||||
{
|
||||
m_ioman.Close(m_handle);
|
||||
}
|
||||
|
||||
CIoman::CFile::operator uint32()
|
||||
{
|
||||
return m_handle;
|
||||
}
|
||||
|
@ -11,6 +11,18 @@ namespace Iop
|
||||
class CIoman : public CModule
|
||||
{
|
||||
public:
|
||||
class CFile
|
||||
{
|
||||
public:
|
||||
CFile(uint32, CIoman&);
|
||||
virtual ~CFile();
|
||||
|
||||
operator uint32();
|
||||
private:
|
||||
uint32 m_handle;
|
||||
CIoman& m_ioman;
|
||||
};
|
||||
|
||||
CIoman(uint8*);
|
||||
virtual ~CIoman();
|
||||
|
||||
@ -24,7 +36,10 @@ namespace Iop
|
||||
uint32 Read(uint32, uint32, void*);
|
||||
uint32 Seek(uint32, uint32, uint32);
|
||||
|
||||
Framework::CStream* GetFileStream(uint32);
|
||||
|
||||
private:
|
||||
|
||||
typedef std::map<uint32, Framework::CStream*> FileMapType;
|
||||
typedef std::map<std::string, Ioman::CDevice*> DeviceMapType;
|
||||
|
||||
|
44
tools/PsfPlayer/Source/Iop_Loadcore.cpp
Normal file
44
tools/PsfPlayer/Source/Iop_Loadcore.cpp
Normal file
@ -0,0 +1,44 @@
|
||||
#include "Iop_Loadcore.h"
|
||||
#include "Iop_Dynamic.h"
|
||||
#include "IopBios.h"
|
||||
|
||||
using namespace Iop;
|
||||
using namespace std;
|
||||
|
||||
CLoadcore::CLoadcore(CIopBios& bios, uint8* ram) :
|
||||
m_bios(bios),
|
||||
m_ram(ram)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CLoadcore::~CLoadcore()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
string CLoadcore::GetId() const
|
||||
{
|
||||
return "loadcore";
|
||||
}
|
||||
|
||||
void CLoadcore::Invoke(CMIPS& context, unsigned int functionId)
|
||||
{
|
||||
switch(functionId)
|
||||
{
|
||||
case 6:
|
||||
context.m_State.nGPR[CMIPS::V0].nD0 = static_cast<int32>(RegisterLibraryEntries(
|
||||
reinterpret_cast<uint32*>(&m_ram[context.m_State.nGPR[CMIPS::A0].nV0])
|
||||
));
|
||||
break;
|
||||
default:
|
||||
printf("%s(%0.8X): Unknown function (%d) called.\r\n", __FUNCTION__, context.m_State.nPC, functionId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 CLoadcore::RegisterLibraryEntries(uint32* exportTable)
|
||||
{
|
||||
m_bios.RegisterModule(new CDynamic(exportTable));
|
||||
return 1;
|
||||
}
|
27
tools/PsfPlayer/Source/Iop_Loadcore.h
Normal file
27
tools/PsfPlayer/Source/Iop_Loadcore.h
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef _IOP_LOADCORE_H_
|
||||
#define _IOP_LOADCORE_H_
|
||||
|
||||
#include "Iop_Module.h"
|
||||
|
||||
class CIopBios;
|
||||
|
||||
namespace Iop
|
||||
{
|
||||
class CLoadcore : public CModule
|
||||
{
|
||||
public:
|
||||
CLoadcore(CIopBios&, uint8*);
|
||||
virtual ~CLoadcore();
|
||||
|
||||
std::string GetId() const;
|
||||
void Invoke(CMIPS&, unsigned int);
|
||||
|
||||
private:
|
||||
uint32 RegisterLibraryEntries(uint32*);
|
||||
|
||||
CIopBios& m_bios;
|
||||
uint8* m_ram;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
54
tools/PsfPlayer/Source/Iop_Modload.cpp
Normal file
54
tools/PsfPlayer/Source/Iop_Modload.cpp
Normal file
@ -0,0 +1,54 @@
|
||||
#include "Iop_Modload.h"
|
||||
#include "IopBios.h"
|
||||
|
||||
using namespace Iop;
|
||||
using namespace std;
|
||||
using namespace Framework;
|
||||
|
||||
CModload::CModload(CIopBios& bios, uint8* ram) :
|
||||
m_bios(bios),
|
||||
m_ram(ram)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CModload::~CModload()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
string CModload::GetId() const
|
||||
{
|
||||
return "modload";
|
||||
}
|
||||
|
||||
void CModload::Invoke(CMIPS& context, unsigned int functionId)
|
||||
{
|
||||
switch(functionId)
|
||||
{
|
||||
case 7:
|
||||
context.m_State.nGPR[CMIPS::V0].nD0 = static_cast<int32>(LoadStartModule(
|
||||
reinterpret_cast<const char*>(&m_ram[context.m_State.nGPR[CMIPS::A0].nV0]),
|
||||
context.m_State.nGPR[CMIPS::A1].nV0,
|
||||
reinterpret_cast<const char*>(&m_ram[context.m_State.nGPR[CMIPS::A2].nV0]),
|
||||
reinterpret_cast<uint32*>(&m_ram[context.m_State.nGPR[CMIPS::A3].nV0])
|
||||
));
|
||||
break;
|
||||
default:
|
||||
printf("%s(%0.8X): Unknown function (%d) called.\r\n", __FUNCTION__, context.m_State.nPC, functionId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 CModload::LoadStartModule(const char* path, uint32 argsLength, const char* args, uint32* result)
|
||||
{
|
||||
try
|
||||
{
|
||||
m_bios.LoadAndStartModule(path, args, argsLength);
|
||||
}
|
||||
catch(const exception& except)
|
||||
{
|
||||
printf("%s: Error occured while trying to load module '%s' : %s\r\n", __FUNCTION__, path, except.what());
|
||||
}
|
||||
return 0;
|
||||
}
|
26
tools/PsfPlayer/Source/Iop_Modload.h
Normal file
26
tools/PsfPlayer/Source/Iop_Modload.h
Normal file
@ -0,0 +1,26 @@
|
||||
#ifndef _IOP_MODLOAD_H_
|
||||
#define _IOP_MODLOAD_H_
|
||||
|
||||
#include "Iop_Module.h"
|
||||
|
||||
class CIopBios;
|
||||
|
||||
namespace Iop
|
||||
{
|
||||
class CModload : public CModule
|
||||
{
|
||||
public:
|
||||
CModload(CIopBios&, uint8*);
|
||||
virtual ~CModload();
|
||||
|
||||
std::string GetId() const;
|
||||
void Invoke(CMIPS&, unsigned int);
|
||||
|
||||
private:
|
||||
uint32 LoadStartModule(const char*, uint32, const char*, uint32*);
|
||||
CIopBios& m_bios;
|
||||
uint8* m_ram;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
76
tools/PsfPlayer/Source/Iop_Sysclib.cpp
Normal file
76
tools/PsfPlayer/Source/Iop_Sysclib.cpp
Normal file
@ -0,0 +1,76 @@
|
||||
#include "Iop_Sysclib.h"
|
||||
|
||||
using namespace Iop;
|
||||
using namespace std;
|
||||
|
||||
CSysclib::CSysclib(uint8* ram) :
|
||||
m_ram(ram)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CSysclib::~CSysclib()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
string CSysclib::GetId() const
|
||||
{
|
||||
return "sysclib";
|
||||
}
|
||||
|
||||
void CSysclib::Invoke(CMIPS& context, unsigned int functionId)
|
||||
{
|
||||
switch(functionId)
|
||||
{
|
||||
case 14:
|
||||
context.m_State.nGPR[CMIPS::V0].nD0 = context.m_State.nGPR[CMIPS::A0].nD0;
|
||||
__memset(
|
||||
&m_ram[context.m_State.nGPR[CMIPS::A0].nV0],
|
||||
context.m_State.nGPR[CMIPS::A1].nV0,
|
||||
context.m_State.nGPR[CMIPS::A2].nV0);
|
||||
break;
|
||||
case 27:
|
||||
context.m_State.nGPR[CMIPS::V0].nD0 = static_cast<int32>(__strlen(
|
||||
reinterpret_cast<char*>(&m_ram[context.m_State.nGPR[CMIPS::A0].nV0])
|
||||
));
|
||||
break;
|
||||
case 30:
|
||||
context.m_State.nGPR[CMIPS::V0].nD0 = context.m_State.nGPR[CMIPS::A0].nD0;
|
||||
__strncpy(
|
||||
reinterpret_cast<char*>(&m_ram[context.m_State.nGPR[CMIPS::A0].nV0]),
|
||||
reinterpret_cast<char*>(&m_ram[context.m_State.nGPR[CMIPS::A1].nV0]),
|
||||
context.m_State.nGPR[CMIPS::A2].nV0);
|
||||
break;
|
||||
case 36:
|
||||
assert(context.m_State.nGPR[CMIPS::A1].nV0 == 0);
|
||||
context.m_State.nGPR[CMIPS::V0].nD0 = static_cast<int32>(__strtol(
|
||||
reinterpret_cast<char*>(&m_ram[context.m_State.nGPR[CMIPS::A0].nV0]),
|
||||
context.m_State.nGPR[CMIPS::A2].nV0
|
||||
));
|
||||
break;
|
||||
default:
|
||||
printf("%s(%0.8X): Unknown function (%d) called.\r\n", __FUNCTION__, context.m_State.nPC, functionId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CSysclib::__memset(void* dest, int character, unsigned int length)
|
||||
{
|
||||
memset(dest, character, length);
|
||||
}
|
||||
|
||||
uint32 CSysclib::__strlen(const char* string)
|
||||
{
|
||||
return static_cast<uint32>(strlen(string));
|
||||
}
|
||||
|
||||
void CSysclib::__strncpy(char* dst, const char* src, unsigned int count)
|
||||
{
|
||||
strncpy(dst, src, count);
|
||||
}
|
||||
|
||||
uint32 CSysclib::__strtol(const char* string, unsigned int radix)
|
||||
{
|
||||
return strtol(string, NULL, radix);
|
||||
}
|
26
tools/PsfPlayer/Source/Iop_Sysclib.h
Normal file
26
tools/PsfPlayer/Source/Iop_Sysclib.h
Normal file
@ -0,0 +1,26 @@
|
||||
#ifndef _IOP_SYSCLIB_H_
|
||||
#define _IOP_SYSCLIB_H_
|
||||
|
||||
#include "IOP_Module.h"
|
||||
|
||||
namespace Iop
|
||||
{
|
||||
class CSysclib : public CModule
|
||||
{
|
||||
public:
|
||||
CSysclib(uint8*);
|
||||
virtual ~CSysclib();
|
||||
|
||||
std::string GetId() const;
|
||||
void Invoke(CMIPS&, unsigned int);
|
||||
|
||||
private:
|
||||
void __memset(void*, int, unsigned int);
|
||||
uint32 __strlen(const char*);
|
||||
void __strncpy(char*, const char*, unsigned int);
|
||||
uint32 __strtol(const char*, unsigned int);
|
||||
uint8* m_ram;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -32,6 +32,11 @@ void CSysmem::Invoke(CMIPS& context, unsigned int functionId)
|
||||
context.m_State.nGPR[CMIPS::A0].nV[0]
|
||||
));
|
||||
break;
|
||||
case 5:
|
||||
context.m_State.nGPR[CMIPS::V0].nD0 = static_cast<int32>(FreeMemory(
|
||||
context.m_State.nGPR[CMIPS::A0].nV[0]
|
||||
));
|
||||
break;
|
||||
default:
|
||||
printf("%s(%0.8X): Unknown function (%d) called.\r\n", __FUNCTION__, context.m_State.nPC, functionId);
|
||||
break;
|
||||
@ -61,7 +66,7 @@ uint32 CSysmem::AllocateMemory(uint32 size, uint32 flags)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void CSysmem::FreeMemory(uint32 address)
|
||||
uint32 CSysmem::FreeMemory(uint32 address)
|
||||
{
|
||||
address -= m_memoryBegin;
|
||||
BlockMapType::iterator block(m_blockMap.find(address));
|
||||
@ -73,4 +78,5 @@ void CSysmem::FreeMemory(uint32 address)
|
||||
{
|
||||
printf("%s: Trying to unallocate an unexisting memory block (0x%0.8X).\r\n", __FUNCTION__, address);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -15,7 +15,8 @@ namespace Iop
|
||||
void Invoke(CMIPS&, unsigned int);
|
||||
|
||||
uint32 AllocateMemory(uint32, uint32);
|
||||
void FreeMemory(uint32);
|
||||
uint32 FreeMemory(uint32);
|
||||
|
||||
private:
|
||||
typedef std::map<uint32, uint32> BlockMapType;
|
||||
|
||||
|
@ -41,7 +41,7 @@ CPsfFs::CPsfFs(const char* loadPath)
|
||||
stream.Seek(tagBeginPosition, STREAM_SEEK_SET);
|
||||
|
||||
{
|
||||
char* tagBuffer = reinterpret_cast<char*>(alloca(tagSize + 1));
|
||||
char* tagBuffer = reinterpret_cast<char*>(alloca(static_cast<size_t>(tagSize) + 1));
|
||||
stream.Read(tagBuffer, tagSize);
|
||||
tagBuffer[tagSize] = 0;
|
||||
m_tag = tagBuffer;
|
||||
@ -148,7 +148,7 @@ const CPsfFs::FILE* CPsfFs::GetFileDetail(const DIRECTORY& directory, const char
|
||||
nodeIterator != directory.fileList.end(); nodeIterator++)
|
||||
{
|
||||
const NODE* node(*nodeIterator);
|
||||
if(!strcmp(node->name, path))
|
||||
if(!_stricmp(node->name, path))
|
||||
{
|
||||
return dynamic_cast<const FILE*>(node);
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
#include "PsfVm.h"
|
||||
#include "MA_MIPSIV.h"
|
||||
#include "COP_SCU.h"
|
||||
#include "PtrStream.h"
|
||||
#include "Ioman_Psf.h"
|
||||
#include "ELF.h"
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
@ -9,13 +11,16 @@ using namespace Framework;
|
||||
using namespace std;
|
||||
using namespace boost;
|
||||
|
||||
#define PSF_DEVICENAME "psf"
|
||||
|
||||
CPsfVm::CPsfVm(const char* psfPath) :
|
||||
m_fileSystem(psfPath),
|
||||
m_cpu(MEMORYMAP_ENDIAN_LSBF, 0x00000000, RAMSIZE),
|
||||
m_status(PAUSED),
|
||||
m_pauseAck(false),
|
||||
m_emuThread(NULL),
|
||||
m_iopStdio(NULL)
|
||||
m_bios(NULL),
|
||||
m_singleStep(false)
|
||||
{
|
||||
memset(&m_cpu.m_State, 0, sizeof(m_cpu.m_State));
|
||||
m_ram = new uint8[RAMSIZE];
|
||||
@ -33,36 +38,12 @@ m_iopStdio(NULL)
|
||||
m_cpu.m_Comments.Unserialize("comments.bin");
|
||||
#endif
|
||||
|
||||
//Register built-in modules
|
||||
{
|
||||
m_iopStdio = new Iop::CStdio(m_ram);
|
||||
RegisterModule(m_iopStdio);
|
||||
}
|
||||
{
|
||||
m_iopIoman = new Iop::CIoman(m_ram);
|
||||
RegisterModule(m_iopIoman);
|
||||
m_iopIoman->RegisterDevice("host", new Iop::Ioman::CPsf(m_fileSystem));
|
||||
}
|
||||
{
|
||||
m_iopSysmem = new Iop::CSysmem(0x1000, RAMSIZE);
|
||||
RegisterModule(m_iopSysmem);
|
||||
}
|
||||
m_bios = new CIopBios(0x100, m_cpu, m_ram, RAMSIZE);
|
||||
|
||||
uint32 stackBegin = m_iopSysmem->AllocateMemory(DEFAULT_STACKSIZE, 0);
|
||||
uint32 entryPoint = LoadIopModule("psf2.irx", 0x000100000);
|
||||
string execPath = "host:/psf2.irx";
|
||||
m_cpu.m_State.nGPR[CMIPS::SP].nV0 = stackBegin + DEFAULT_STACKSIZE;
|
||||
m_cpu.m_State.nGPR[CMIPS::A0].nV0 = 1;
|
||||
uint32 firstParam = Push(
|
||||
m_cpu.m_State.nGPR[CMIPS::SP].nV0,
|
||||
reinterpret_cast<const uint8*>(execPath.c_str()),
|
||||
execPath.length() + 1);
|
||||
m_cpu.m_State.nGPR[CMIPS::A1].nV0 = Push(
|
||||
m_cpu.m_State.nGPR[CMIPS::SP].nV0,
|
||||
reinterpret_cast<const uint8*>(&firstParam),
|
||||
4);
|
||||
m_cpu.m_State.nPC = entryPoint;
|
||||
string execPath = string(PSF_DEVICENAME) + ":/psf2.irx";
|
||||
|
||||
m_bios->GetIoman()->RegisterDevice(PSF_DEVICENAME, new Iop::Ioman::CPsf(m_fileSystem));
|
||||
m_bios->LoadAndStartModule(execPath.c_str(), NULL, 0);
|
||||
|
||||
m_emuThread = new thread(bind(&CPsfVm::EmulationProc, this));
|
||||
}
|
||||
@ -73,12 +54,7 @@ CPsfVm::~CPsfVm()
|
||||
m_cpu.m_Functions.Serialize("functions.bin");
|
||||
m_cpu.m_Comments.Serialize("comments.bin");
|
||||
#endif
|
||||
|
||||
while(m_iopModules.size() != 0)
|
||||
{
|
||||
delete m_iopModules.begin()->second;
|
||||
m_iopModules.erase(m_iopModules.begin());
|
||||
}
|
||||
delete m_bios;
|
||||
delete [] m_ram;
|
||||
}
|
||||
|
||||
@ -96,6 +72,13 @@ void CPsfVm::Pause()
|
||||
m_OnRunningStateChange();
|
||||
}
|
||||
|
||||
void CPsfVm::Step()
|
||||
{
|
||||
if(GetStatus() == RUNNING) return;
|
||||
m_singleStep = true;
|
||||
m_status = RUNNING;
|
||||
}
|
||||
|
||||
void CPsfVm::Resume()
|
||||
{
|
||||
if(GetStatus() == RUNNING) return;
|
||||
@ -113,96 +96,6 @@ CVirtualMachine::STATUS CPsfVm::GetStatus() const
|
||||
return m_status;
|
||||
}
|
||||
|
||||
uint32 CPsfVm::LoadIopModule(const char* modulePath, uint32 baseAddress)
|
||||
{
|
||||
const CPsfFs::FILE* file = m_fileSystem.GetFile(modulePath);
|
||||
CPtrStream stream(file->data, file->size);
|
||||
CELF elf(&stream);
|
||||
|
||||
baseAddress = m_iopSysmem->AllocateMemory(elf.m_nLenght, 0);
|
||||
|
||||
//Process relocation
|
||||
for(unsigned int i = 0; i < elf.m_Header.nSectHeaderCount; i++)
|
||||
{
|
||||
ELFSECTIONHEADER* sectionHeader = elf.GetSection(i);
|
||||
if(sectionHeader != NULL && sectionHeader->nType == CELF::SHT_REL)
|
||||
{
|
||||
uint32 lastHi16 = -1;
|
||||
uint32 instructionHi16 = -1;
|
||||
unsigned int linkedSection = sectionHeader->nInfo;
|
||||
unsigned int recordCount = sectionHeader->nSize / 8;
|
||||
ELFSECTIONHEADER* relocatedSection = elf.GetSection(linkedSection);
|
||||
const uint32* relocationRecord = reinterpret_cast<const uint32*>(elf.GetSectionData(i));
|
||||
uint8* relocatedSectionData = reinterpret_cast<uint8*>(const_cast<void*>(elf.GetSectionData(linkedSection)));
|
||||
if(relocatedSection == NULL || relocationRecord == NULL || relocatedSection == NULL) continue;
|
||||
for(unsigned int record = 0; record < recordCount; record++)
|
||||
{
|
||||
uint32 relocationAddress = relocationRecord[0];
|
||||
uint32 relocationType = relocationRecord[1];
|
||||
if(relocationAddress < relocatedSection->nSize)
|
||||
{
|
||||
uint32& instruction = *reinterpret_cast<uint32*>(&relocatedSectionData[relocationAddress]);
|
||||
switch(relocationType)
|
||||
{
|
||||
case CELF::R_MIPS_26:
|
||||
{
|
||||
uint32 offset = (instruction & 0x03FFFFFF) + (baseAddress >> 2);
|
||||
instruction &= ~0x03FFFFFF;
|
||||
instruction |= offset;
|
||||
}
|
||||
break;
|
||||
case CELF::R_MIPS_HI16:
|
||||
{
|
||||
lastHi16 = relocationAddress;
|
||||
instructionHi16 = instruction;
|
||||
}
|
||||
break;
|
||||
case CELF::R_MIPS_LO16:
|
||||
{
|
||||
if(lastHi16 != -1)
|
||||
{
|
||||
uint32 offset = static_cast<int16>(instruction) + (instructionHi16 << 16);
|
||||
offset += baseAddress;
|
||||
instruction &= ~0xFFFF;
|
||||
instruction |= offset & 0xFFFF;
|
||||
|
||||
uint32& prevInstruction = *reinterpret_cast<uint32*>(&relocatedSectionData[lastHi16]);
|
||||
prevInstruction &= ~0xFFFF;
|
||||
if(offset & 0x8000) offset += 0x10000;
|
||||
prevInstruction |= offset >> 16;
|
||||
lastHi16 = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("%s: No HI16 relocation record found for corresponding LO16.\r\n", __FUNCTION__);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw exception();
|
||||
break;
|
||||
}
|
||||
}
|
||||
relocationRecord += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(unsigned int i = 0; i < elf.m_Header.nProgHeaderCount; i++)
|
||||
{
|
||||
ELFPROGRAMHEADER* programHeader = elf.GetProgram(i);
|
||||
if(programHeader != NULL && programHeader->nType == 1)
|
||||
{
|
||||
memcpy(
|
||||
m_ram + baseAddress,
|
||||
elf.m_pData + programHeader->nOffset,
|
||||
programHeader->nFileSize);
|
||||
}
|
||||
}
|
||||
|
||||
return baseAddress + elf.m_Header.nEntryPoint;
|
||||
}
|
||||
|
||||
unsigned int CPsfVm::TickFunctionStub(unsigned int ticks, CMIPS* context)
|
||||
{
|
||||
return reinterpret_cast<CPsfVm*>(context->m_handlerParam)->TickFunction(ticks);
|
||||
@ -217,62 +110,9 @@ unsigned int CPsfVm::TickFunction(unsigned int ticks)
|
||||
return 0;
|
||||
}
|
||||
|
||||
string CPsfVm::ReadModuleName(uint32 address)
|
||||
{
|
||||
string moduleName;
|
||||
while(1)
|
||||
{
|
||||
uint8 character = m_cpu.m_pMemoryMap->GetByte(address);
|
||||
if(character == 0) break;
|
||||
moduleName += character;
|
||||
address++;
|
||||
}
|
||||
return moduleName;
|
||||
}
|
||||
|
||||
void CPsfVm::RegisterModule(Iop::CModule* module)
|
||||
{
|
||||
m_iopModules[module->GetId()] = module;
|
||||
}
|
||||
|
||||
void CPsfVm::SysCallHandlerStub(CMIPS* state)
|
||||
{
|
||||
reinterpret_cast<CPsfVm*>(state->m_handlerParam)->SysCallHandler();
|
||||
}
|
||||
|
||||
void CPsfVm::SysCallHandler()
|
||||
{
|
||||
uint32 searchAddress = m_cpu.m_State.nPC - 4;
|
||||
uint32 callInstruction = m_cpu.m_pMemoryMap->GetWord(searchAddress);
|
||||
//Search for the import record
|
||||
uint32 instruction = callInstruction;
|
||||
while(instruction != 0x41E00000)
|
||||
{
|
||||
searchAddress -= 4;
|
||||
instruction = m_cpu.m_pMemoryMap->GetWord(searchAddress);
|
||||
}
|
||||
uint32 functionId = callInstruction & 0xFFFF;
|
||||
uint32 version = m_cpu.m_pMemoryMap->GetWord(searchAddress + 8);
|
||||
string moduleName = ReadModuleName(searchAddress + 0x0C);
|
||||
|
||||
IopModuleMapType::iterator module(m_iopModules.find(moduleName));
|
||||
if(module != m_iopModules.end())
|
||||
{
|
||||
module->second->Invoke(m_cpu, functionId);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("IOP(%0.8X): Trying to call a function from non-existing module (%s, %d).\r\n",
|
||||
m_cpu.m_State.nPC, moduleName.c_str(), functionId);
|
||||
}
|
||||
}
|
||||
|
||||
uint32 CPsfVm::Push(uint32& address, const uint8* data, uint32 size)
|
||||
{
|
||||
uint32 fixedSize = ((size + 0xF) / 0x10) * 0x10;
|
||||
address -= fixedSize;
|
||||
memcpy(&m_ram[address], data, size);
|
||||
return address;
|
||||
reinterpret_cast<CPsfVm*>(state->m_handlerParam)->m_bios->SysCallHandler();
|
||||
}
|
||||
|
||||
void CPsfVm::EmulationProc()
|
||||
@ -281,10 +121,16 @@ void CPsfVm::EmulationProc()
|
||||
{
|
||||
if(m_status == RUNNING)
|
||||
{
|
||||
RET_CODE returnCode = m_cpu.Execute(1000);
|
||||
if(returnCode == RET_CODE_BREAKPOINT)
|
||||
RET_CODE returnCode = m_cpu.Execute(m_singleStep ? 1 : 1000);
|
||||
if(m_cpu.m_State.nCOP0[CCOP_SCU::EPC] != 0)
|
||||
{
|
||||
m_bios->SysCallHandler();
|
||||
assert(m_cpu.m_State.nCOP0[CCOP_SCU::EPC] == 0);
|
||||
}
|
||||
if(returnCode == RET_CODE_BREAKPOINT || m_singleStep)
|
||||
{
|
||||
m_status = PAUSED;
|
||||
m_singleStep = false;
|
||||
m_OnRunningStateChange();
|
||||
m_OnMachineStateChange();
|
||||
}
|
||||
@ -294,7 +140,7 @@ void CPsfVm::EmulationProc()
|
||||
m_pauseAck = true;
|
||||
xtime xt;
|
||||
xtime_get(&xt, boost::TIME_UTC);
|
||||
xt.nsec += 100000000;
|
||||
xt.nsec += 10000000;
|
||||
thread::sleep(xt);
|
||||
}
|
||||
}
|
||||
|
@ -6,10 +6,7 @@
|
||||
#include "VirtualMachine.h"
|
||||
#include <string>
|
||||
#include <boost/thread.hpp>
|
||||
#include "Iop_Stdio.h"
|
||||
#include "Iop_Ioman.h"
|
||||
#include "Iop_Sysmem.h"
|
||||
#include "Ioman_Psf.h"
|
||||
#include "IopBios.h"
|
||||
|
||||
class CPsfVm : public CVirtualMachine
|
||||
{
|
||||
@ -19,45 +16,30 @@ public:
|
||||
|
||||
CMIPS& GetCpu();
|
||||
STATUS GetStatus() const;
|
||||
void Step();
|
||||
void Pause();
|
||||
void Resume();
|
||||
|
||||
private:
|
||||
typedef std::map<std::string, Iop::CModule*> IopModuleMapType;
|
||||
|
||||
enum RAMSIZE
|
||||
{
|
||||
RAMSIZE = 0x00400000,
|
||||
};
|
||||
|
||||
enum DEFAULT_STACKSIZE
|
||||
{
|
||||
DEFAULT_STACKSIZE = 0x8000,
|
||||
};
|
||||
|
||||
uint32 LoadIopModule(const char*, uint32);
|
||||
uint32 Push(uint32&, const uint8*, uint32);
|
||||
static unsigned int TickFunctionStub(unsigned int, CMIPS*);
|
||||
static void SysCallHandlerStub(CMIPS*);
|
||||
unsigned int TickFunction(unsigned int);
|
||||
void SysCallHandler();
|
||||
|
||||
std::string ReadModuleName(uint32);
|
||||
void RegisterModule(Iop::CModule*);
|
||||
static void SysCallHandlerStub(CMIPS*);
|
||||
|
||||
void EmulationProc();
|
||||
|
||||
CMIPS m_cpu;
|
||||
CPsfFs m_fileSystem;
|
||||
CIopBios* m_bios;
|
||||
uint8* m_ram;
|
||||
STATUS m_status;
|
||||
bool m_pauseAck;
|
||||
boost::thread* m_emuThread;
|
||||
|
||||
IopModuleMapType m_iopModules;
|
||||
Iop::CStdio* m_iopStdio;
|
||||
Iop::CIoman* m_iopIoman;
|
||||
Iop::CSysmem* m_iopSysmem;
|
||||
bool m_singleStep;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -1,12 +1,14 @@
|
||||
#include "MiniDebugger.h"
|
||||
#include "win32/Rect.h"
|
||||
#include "win32ui/resource.h"
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
#define CLSNAME _T("MiniDebugger")
|
||||
#define WNDSTYLE (WS_CAPTION | WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_SYSMENU)
|
||||
#define WNDSTYLEEX (0)
|
||||
|
||||
using namespace Framework;
|
||||
using namespace boost;
|
||||
|
||||
CMiniDebugger::CMiniDebugger(CPsfVm& virtualMachine) :
|
||||
m_virtualMachine(virtualMachine),
|
||||
@ -40,6 +42,7 @@ m_registerView(NULL)
|
||||
m_registerView->Show(SW_SHOW);
|
||||
|
||||
m_functionsView = new CFunctionsView(NULL, &m_virtualMachine.GetCpu());
|
||||
m_functionsView->m_OnFunctionDblClick.connect(bind(&CMiniDebugger::OnFunctionDblClick, this, _1));
|
||||
m_functionsView->Refresh();
|
||||
|
||||
m_splitter->SetChild(0, *m_disAsmView);
|
||||
@ -101,8 +104,12 @@ void CMiniDebugger::StepCPU()
|
||||
}
|
||||
|
||||
m_disAsmView->SetFocus();
|
||||
m_virtualMachine.GetCpu().Step();
|
||||
m_virtualMachine.m_OnMachineStateChange();
|
||||
m_virtualMachine.Step();
|
||||
}
|
||||
|
||||
void CMiniDebugger::OnFunctionDblClick(uint32 address)
|
||||
{
|
||||
m_disAsmView->SetAddress(address);
|
||||
}
|
||||
|
||||
void CMiniDebugger::CreateAccelerators()
|
||||
|
@ -21,6 +21,7 @@ protected:
|
||||
private:
|
||||
void CreateAccelerators();
|
||||
void StepCPU();
|
||||
void OnFunctionDblClick(uint32);
|
||||
|
||||
CPsfVm& m_virtualMachine;
|
||||
Framework::Win32::CHorizontalSplitter* m_splitter;
|
||||
|
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user