git-svn-id: http://svn.purei.org/purei/trunk@174 b36208d7-6611-0410-8bec-b1987f11c4a2

This commit is contained in:
jpd002 2007-11-12 03:59:42 +00:00
parent d75bac07a3
commit 8a1f6fe2f5
30 changed files with 1078 additions and 247 deletions

View File

@ -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)

View File

@ -23,6 +23,7 @@ enum RET_CODE
RET_CODE_QUOTADONE,
RET_CODE_BREAKPOINT,
RET_CODE_INTERBLOCKJUMP,
RET_CODE_EXCEPTION,
};
class CCacheBlock

View File

@ -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);

View File

@ -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;

View File

@ -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,

View File

@ -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();

View File

@ -53,6 +53,7 @@ void CMIPSAnalysis::Analyse(uint32 nStart, uint32 nEnd)
nFound = 0;
nCandidate = nStart;
nReturnAddr = 0;
while(nCandidate != nEnd)
{

View File

@ -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))

View File

@ -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

View File

@ -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"
>

View 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;
}
}
}
}

View 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

View 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;
}

View 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

View File

@ -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;
}

View File

@ -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;

View 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;
}

View 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

View 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;
}

View 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

View 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);
}

View 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

View File

@ -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;
}

View File

@ -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;

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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

View File

@ -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()

View File

@ -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.