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@168 b36208d7-6611-0410-8bec-b1987f11c4a2
This commit is contained in:
parent
175f74312a
commit
8c6158075f
30
Purei.sln
30
Purei.sln
@ -3,11 +3,11 @@ Microsoft Visual Studio Solution File, Format Version 9.00
|
||||
# Visual Studio 2005
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Purei", "Purei.vcproj", "{DF7BEC15-DC00-4C86-94AF-72CA742590CC}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{9B46B4A7-0FBD-44FD-8E9C-BC2CBA64643A} = {9B46B4A7-0FBD-44FD-8E9C-BC2CBA64643A}
|
||||
{CF8E8640-24C8-49F1-B510-CF5BB945F99C} = {CF8E8640-24C8-49F1-B510-CF5BB945F99C}
|
||||
{9B46B4A7-0FBD-44FD-8E9C-BC2CBA64643A} = {9B46B4A7-0FBD-44FD-8E9C-BC2CBA64643A}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib-1.2.3", "..\zlib-1.2.3\zlib-1.2.3.vcproj", "{8AD44184-94A7-461B-8076-CE4455B7559A}"
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib-1.2.3", "..\zlib-1.2.3\zlib-1.2.3.vcproj", "{FCF8C365-733E-4E64-B0ED-41C0BE66ED0C}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Framework", "..\Framework\Framework.vcproj", "{CF8E8640-24C8-49F1-B510-CF5BB945F99C}"
|
||||
EndProject
|
||||
@ -20,7 +20,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ElfView", "tools\ElfView\El
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PsfPlayer", "tools\PsfPlayer\PsfPlayer.vcproj", "{EDA20432-A4C3-481C-B0EA-24AA8ABD7621}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{8AD44184-94A7-461B-8076-CE4455B7559A} = {8AD44184-94A7-461B-8076-CE4455B7559A}
|
||||
{FCF8C365-733E-4E64-B0ED-41C0BE66ED0C} = {FCF8C365-733E-4E64-B0ED-41C0BE66ED0C}
|
||||
{CF8E8640-24C8-49F1-B510-CF5BB945F99C} = {CF8E8640-24C8-49F1-B510-CF5BB945F99C}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
@ -46,18 +46,18 @@ Global
|
||||
{DF7BEC15-DC00-4C86-94AF-72CA742590CC}.Release|Win32.Build.0 = Release|Win32
|
||||
{DF7BEC15-DC00-4C86-94AF-72CA742590CC}.Release|x64.ActiveCfg = Release|x64
|
||||
{DF7BEC15-DC00-4C86-94AF-72CA742590CC}.Release|x64.Build.0 = Release|x64
|
||||
{8AD44184-94A7-461B-8076-CE4455B7559A}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{8AD44184-94A7-461B-8076-CE4455B7559A}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{8AD44184-94A7-461B-8076-CE4455B7559A}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{8AD44184-94A7-461B-8076-CE4455B7559A}.Debug|x64.Build.0 = Debug|x64
|
||||
{8AD44184-94A7-461B-8076-CE4455B7559A}.Debug+|Win32.ActiveCfg = Debug|Win32
|
||||
{8AD44184-94A7-461B-8076-CE4455B7559A}.Debug+|Win32.Build.0 = Debug|Win32
|
||||
{8AD44184-94A7-461B-8076-CE4455B7559A}.Debug+|x64.ActiveCfg = Release|x64
|
||||
{8AD44184-94A7-461B-8076-CE4455B7559A}.Debug+|x64.Build.0 = Release|x64
|
||||
{8AD44184-94A7-461B-8076-CE4455B7559A}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{8AD44184-94A7-461B-8076-CE4455B7559A}.Release|Win32.Build.0 = Release|Win32
|
||||
{8AD44184-94A7-461B-8076-CE4455B7559A}.Release|x64.ActiveCfg = Release|x64
|
||||
{8AD44184-94A7-461B-8076-CE4455B7559A}.Release|x64.Build.0 = Release|x64
|
||||
{FCF8C365-733E-4E64-B0ED-41C0BE66ED0C}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{FCF8C365-733E-4E64-B0ED-41C0BE66ED0C}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{FCF8C365-733E-4E64-B0ED-41C0BE66ED0C}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{FCF8C365-733E-4E64-B0ED-41C0BE66ED0C}.Debug|x64.Build.0 = Debug|x64
|
||||
{FCF8C365-733E-4E64-B0ED-41C0BE66ED0C}.Debug+|Win32.ActiveCfg = Debug|Win32
|
||||
{FCF8C365-733E-4E64-B0ED-41C0BE66ED0C}.Debug+|Win32.Build.0 = Debug|Win32
|
||||
{FCF8C365-733E-4E64-B0ED-41C0BE66ED0C}.Debug+|x64.ActiveCfg = Release|x64
|
||||
{FCF8C365-733E-4E64-B0ED-41C0BE66ED0C}.Debug+|x64.Build.0 = Release|x64
|
||||
{FCF8C365-733E-4E64-B0ED-41C0BE66ED0C}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{FCF8C365-733E-4E64-B0ED-41C0BE66ED0C}.Release|Win32.Build.0 = Release|Win32
|
||||
{FCF8C365-733E-4E64-B0ED-41C0BE66ED0C}.Release|x64.ActiveCfg = Release|x64
|
||||
{FCF8C365-733E-4E64-B0ED-41C0BE66ED0C}.Release|x64.Build.0 = Release|x64
|
||||
{CF8E8640-24C8-49F1-B510-CF5BB945F99C}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{CF8E8640-24C8-49F1-B510-CF5BB945F99C}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{CF8E8640-24C8-49F1-B510-CF5BB945F99C}.Debug|x64.ActiveCfg = Debug|x64
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8,00"
|
||||
Version="8.00"
|
||||
Name="PsfPlayer"
|
||||
ProjectGUID="{EDA20432-A4C3-481C-B0EA-24AA8ABD7621}"
|
||||
RootNamespace="PsfPlayer"
|
||||
@ -179,6 +179,10 @@
|
||||
RelativePath="..\..\Source\win32ui\DisAsm.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Source\Iop_Stdio.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Source\win32\MiniDebugger.cpp"
|
||||
>
|
||||
@ -221,6 +225,14 @@
|
||||
RelativePath="..\..\Source\win32ui\DisAsm.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Source\Iop_Module.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Source\Iop_Stdio.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Source\win32\MiniDebugger.h"
|
||||
>
|
||||
|
21
tools/PsfPlayer/Source/Iop_Module.h
Normal file
21
tools/PsfPlayer/Source/Iop_Module.h
Normal file
@ -0,0 +1,21 @@
|
||||
#ifndef _IOP_MODULE_H_
|
||||
#define _IOP_MODULE_H_
|
||||
|
||||
#include <string>
|
||||
#include "MIPS.h"
|
||||
|
||||
namespace Iop
|
||||
{
|
||||
class CModule
|
||||
{
|
||||
public:
|
||||
virtual ~CModule() {}
|
||||
virtual std::string GetId() const = 0;
|
||||
virtual void Invoke(CMIPS&, unsigned int) = 0;
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
60
tools/PsfPlayer/Source/Iop_Stdio.cpp
Normal file
60
tools/PsfPlayer/Source/Iop_Stdio.cpp
Normal file
@ -0,0 +1,60 @@
|
||||
#include "Iop_Stdio.h"
|
||||
|
||||
using namespace Iop;
|
||||
using namespace std;
|
||||
|
||||
CStdio::CStdio()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CStdio::~CStdio()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
string CStdio::GetId() const
|
||||
{
|
||||
return "stdio";
|
||||
}
|
||||
|
||||
void CStdio::Invoke(CMIPS& context, unsigned int functionId)
|
||||
{
|
||||
switch(functionId)
|
||||
{
|
||||
case 4:
|
||||
Printf(context);
|
||||
break;
|
||||
default:
|
||||
printf("%s: Unknown function (%d) called.", __FUNCTION__, functionId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CStdio::Printf(CMIPS& context)
|
||||
{
|
||||
const char* format = reinterpret_cast<const char*>(&m_ram[context.m_State.nGPR[CMIPS::A0].nV[0]]);
|
||||
unsigned int param = CMIPS::A1;
|
||||
while(*format != 0)
|
||||
{
|
||||
char character = *(format++);
|
||||
if(character == '%')
|
||||
{
|
||||
char type = *(format++);
|
||||
if(type == 's')
|
||||
{
|
||||
const char* text = reinterpret_cast<const char*>(&m_ram[context.m_State.nGPR[param++].nV[0]]);
|
||||
printf("%s", text);
|
||||
}
|
||||
else if(type == 'd')
|
||||
{
|
||||
int number = context.m_State.nGPR[param++].nV[0];
|
||||
printf("%d", number);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
putc(character, stdout);
|
||||
}
|
||||
}
|
||||
}
|
22
tools/PsfPlayer/Source/Iop_Stdio.h
Normal file
22
tools/PsfPlayer/Source/Iop_Stdio.h
Normal file
@ -0,0 +1,22 @@
|
||||
#ifndef _IOP_STDIO_H_
|
||||
#define _IOP_STDIO_H_
|
||||
|
||||
#include "Iop_Module.h"
|
||||
|
||||
namespace Iop
|
||||
{
|
||||
class CStdio : public CModule
|
||||
{
|
||||
public:
|
||||
CStdio();
|
||||
virtual ~CStdio();
|
||||
|
||||
std::string GetId() const;
|
||||
void Invoke(CMIPS&, unsigned int);
|
||||
|
||||
private:
|
||||
void Printf(CMIPS&);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -1,331 +1,303 @@
|
||||
#include "PsfVm.h"
|
||||
#include "MA_MIPSIV.h"
|
||||
#include "PtrStream.h"
|
||||
#include "ELF.h"
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
using namespace Framework;
|
||||
using namespace std;
|
||||
using namespace boost;
|
||||
|
||||
CPsfVm::CPsfVm(const char* psfPath) :
|
||||
m_fileSystem(psfPath),
|
||||
m_cpu(MEMORYMAP_ENDIAN_LSBF, 0x00000000, RAMSIZE),
|
||||
m_status(PAUSED),
|
||||
m_pauseAck(false),
|
||||
m_emuThread(NULL)
|
||||
{
|
||||
//Initialize block map
|
||||
m_blockMap[RAMSIZE] = 0;
|
||||
|
||||
memset(&m_cpu.m_State, 0, sizeof(m_cpu.m_State));
|
||||
m_ram = new uint8[RAMSIZE];
|
||||
m_cpu.m_pMemoryMap->InsertReadMap(0x00000000, RAMSIZE - 1, m_ram, MEMORYMAP_TYPE_MEMORY, 0x00);
|
||||
m_cpu.m_pMemoryMap->InsertWriteMap(0x00000000, RAMSIZE - 1, m_ram, MEMORYMAP_TYPE_MEMORY, 0x00);
|
||||
|
||||
m_cpu.m_pArch = &g_MAMIPSIV;
|
||||
m_cpu.m_pAddrTranslator = m_cpu.TranslateAddress64;
|
||||
m_cpu.m_pTickFunction = reinterpret_cast<TickFunctionType>(TickFunctionStub);
|
||||
m_cpu.m_pSysCallHandler = reinterpret_cast<SysCallHandlerType>(SysCallHandlerStub);
|
||||
m_cpu.m_handlerParam = this;
|
||||
|
||||
uint32 stackBegin = AllocateMemory(DEFAULT_STACKSIZE);
|
||||
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;
|
||||
|
||||
m_emuThread = new thread(bind(&CPsfVm::EmulationProc, this));
|
||||
}
|
||||
|
||||
CPsfVm::~CPsfVm()
|
||||
{
|
||||
delete [] m_ram;
|
||||
}
|
||||
|
||||
void CPsfVm::Pause()
|
||||
{
|
||||
if(GetStatus() == PAUSED) return;
|
||||
m_pauseAck = false;
|
||||
m_status = PAUSED;
|
||||
while(!m_pauseAck)
|
||||
{
|
||||
#include "PsfVm.h"
|
||||
#include "MA_MIPSIV.h"
|
||||
#include "PtrStream.h"
|
||||
#include "ELF.h"
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
using namespace Framework;
|
||||
using namespace std;
|
||||
using namespace boost;
|
||||
|
||||
CPsfVm::CPsfVm(const char* psfPath) :
|
||||
m_fileSystem(psfPath),
|
||||
m_cpu(MEMORYMAP_ENDIAN_LSBF, 0x00000000, RAMSIZE),
|
||||
m_status(PAUSED),
|
||||
m_pauseAck(false),
|
||||
m_emuThread(NULL)
|
||||
{
|
||||
//Initialize block map
|
||||
m_blockMap[RAMSIZE] = 0;
|
||||
|
||||
memset(&m_cpu.m_State, 0, sizeof(m_cpu.m_State));
|
||||
m_ram = new uint8[RAMSIZE];
|
||||
m_cpu.m_pMemoryMap->InsertReadMap(0x00000000, RAMSIZE - 1, m_ram, MEMORYMAP_TYPE_MEMORY, 0x00);
|
||||
m_cpu.m_pMemoryMap->InsertWriteMap(0x00000000, RAMSIZE - 1, m_ram, MEMORYMAP_TYPE_MEMORY, 0x00);
|
||||
|
||||
m_cpu.m_pArch = &g_MAMIPSIV;
|
||||
m_cpu.m_pAddrTranslator = m_cpu.TranslateAddress64;
|
||||
m_cpu.m_pTickFunction = reinterpret_cast<TickFunctionType>(TickFunctionStub);
|
||||
m_cpu.m_pSysCallHandler = reinterpret_cast<SysCallHandlerType>(SysCallHandlerStub);
|
||||
m_cpu.m_handlerParam = this;
|
||||
|
||||
uint32 stackBegin = AllocateMemory(DEFAULT_STACKSIZE);
|
||||
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;
|
||||
|
||||
m_emuThread = new thread(bind(&CPsfVm::EmulationProc, this));
|
||||
}
|
||||
|
||||
CPsfVm::~CPsfVm()
|
||||
{
|
||||
delete [] m_ram;
|
||||
}
|
||||
|
||||
void CPsfVm::Pause()
|
||||
{
|
||||
if(GetStatus() == PAUSED) return;
|
||||
m_pauseAck = false;
|
||||
m_status = PAUSED;
|
||||
while(!m_pauseAck)
|
||||
{
|
||||
xtime xt;
|
||||
xtime_get(&xt, boost::TIME_UTC);
|
||||
xt.nsec += 100000000;
|
||||
}
|
||||
m_OnRunningStateChange();
|
||||
}
|
||||
|
||||
void CPsfVm::Resume()
|
||||
{
|
||||
if(GetStatus() == RUNNING) return;
|
||||
m_status = RUNNING;
|
||||
m_OnRunningStateChange();
|
||||
}
|
||||
|
||||
CMIPS& CPsfVm::GetCpu()
|
||||
{
|
||||
return m_cpu;
|
||||
}
|
||||
|
||||
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 = AllocateMemory(elf.m_nLenght);
|
||||
|
||||
//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);
|
||||
}
|
||||
|
||||
unsigned int CPsfVm::TickFunction(unsigned int ticks)
|
||||
{
|
||||
if(m_cpu.MustBreak())
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
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::stdio_printf()
|
||||
{
|
||||
const char* format = reinterpret_cast<const char*>(&m_ram[m_cpu.m_State.nGPR[CMIPS::A0].nV[0]]);
|
||||
unsigned int param = CMIPS::A1;
|
||||
while(*format != 0)
|
||||
{
|
||||
char character = *(format++);
|
||||
if(character == '%')
|
||||
{
|
||||
char type = *(format++);
|
||||
if(type == 's')
|
||||
{
|
||||
const char* text = reinterpret_cast<const char*>(&m_ram[m_cpu.m_State.nGPR[param++].nV[0]]);
|
||||
printf("%s", text);
|
||||
}
|
||||
else if(type == 'd')
|
||||
{
|
||||
int number = m_cpu.m_State.nGPR[param++].nV[0];
|
||||
printf("%d", number);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
putc(character, stdout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
printf("IOP: Calling function %d of module '%s'.\r\n", functionId, moduleName.c_str());
|
||||
|
||||
if(!moduleName.compare("stdio"))
|
||||
{
|
||||
switch(functionId)
|
||||
{
|
||||
case 4:
|
||||
stdio_printf();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32 CPsfVm::AllocateMemory(uint32 size)
|
||||
{
|
||||
uint32 begin = 0x1000;
|
||||
const uint32 blockSize = 0x400;
|
||||
size = ((size + (blockSize - 1)) / blockSize) * blockSize;
|
||||
for(BlockMapType::iterator blockIterator(m_blockMap.begin());
|
||||
blockIterator != m_blockMap.end(); blockIterator++)
|
||||
{
|
||||
uint32 end = blockIterator->first;
|
||||
if((end - begin) >= size)
|
||||
{
|
||||
break;
|
||||
}
|
||||
begin = blockIterator->first + blockIterator->second;
|
||||
}
|
||||
if(begin != RAMSIZE)
|
||||
{
|
||||
m_blockMap[begin] = size;
|
||||
return begin;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void CPsfVm::FreeMemory(uint32 address)
|
||||
{
|
||||
BlockMapType::iterator block(m_blockMap.find(address));
|
||||
if(block != m_blockMap.end())
|
||||
{
|
||||
m_blockMap.erase(block);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("%s: Trying to unallocate an unexisting memory block (0x%0.8X).\r\n", __FUNCTION__, address);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void CPsfVm::EmulationProc()
|
||||
{
|
||||
while(1)
|
||||
{
|
||||
if(m_status == RUNNING)
|
||||
{
|
||||
RET_CODE returnCode = m_cpu.Execute(1000);
|
||||
if(returnCode == RET_CODE_BREAKPOINT)
|
||||
{
|
||||
m_status = PAUSED;
|
||||
m_OnRunningStateChange();
|
||||
m_OnMachineStateChange();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
m_OnRunningStateChange();
|
||||
}
|
||||
|
||||
void CPsfVm::Resume()
|
||||
{
|
||||
if(GetStatus() == RUNNING) return;
|
||||
m_status = RUNNING;
|
||||
m_OnRunningStateChange();
|
||||
}
|
||||
|
||||
CMIPS& CPsfVm::GetCpu()
|
||||
{
|
||||
return m_cpu;
|
||||
}
|
||||
|
||||
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 = AllocateMemory(elf.m_nLenght);
|
||||
|
||||
//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);
|
||||
}
|
||||
|
||||
unsigned int CPsfVm::TickFunction(unsigned int ticks)
|
||||
{
|
||||
if(m_cpu.MustBreak())
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
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::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);
|
||||
|
||||
printf("IOP: Calling function %d of module '%s'.\r\n", functionId, moduleName.c_str());
|
||||
|
||||
if(!moduleName.compare("stdio"))
|
||||
{
|
||||
switch(functionId)
|
||||
{
|
||||
case 4:
|
||||
stdio_printf();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32 CPsfVm::AllocateMemory(uint32 size)
|
||||
{
|
||||
uint32 begin = 0x1000;
|
||||
const uint32 blockSize = 0x400;
|
||||
size = ((size + (blockSize - 1)) / blockSize) * blockSize;
|
||||
for(BlockMapType::iterator blockIterator(m_blockMap.begin());
|
||||
blockIterator != m_blockMap.end(); blockIterator++)
|
||||
{
|
||||
uint32 end = blockIterator->first;
|
||||
if((end - begin) >= size)
|
||||
{
|
||||
break;
|
||||
}
|
||||
begin = blockIterator->first + blockIterator->second;
|
||||
}
|
||||
if(begin != RAMSIZE)
|
||||
{
|
||||
m_blockMap[begin] = size;
|
||||
return begin;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void CPsfVm::FreeMemory(uint32 address)
|
||||
{
|
||||
BlockMapType::iterator block(m_blockMap.find(address));
|
||||
if(block != m_blockMap.end())
|
||||
{
|
||||
m_blockMap.erase(block);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("%s: Trying to unallocate an unexisting memory block (0x%0.8X).\r\n", __FUNCTION__, address);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void CPsfVm::EmulationProc()
|
||||
{
|
||||
while(1)
|
||||
{
|
||||
if(m_status == RUNNING)
|
||||
{
|
||||
RET_CODE returnCode = m_cpu.Execute(1000);
|
||||
if(returnCode == RET_CODE_BREAKPOINT)
|
||||
{
|
||||
m_status = PAUSED;
|
||||
m_OnRunningStateChange();
|
||||
m_OnMachineStateChange();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pauseAck = true;
|
||||
xtime xt;
|
||||
xtime_get(&xt, boost::TIME_UTC);
|
||||
xt.nsec += 100000000;
|
||||
thread::sleep(xt);
|
||||
}
|
||||
}
|
||||
}
|
||||
thread::sleep(xt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include "PsfFs.h"
|
||||
#include "VirtualMachine.h"
|
||||
#include <string>
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
class CPsfVm : public CVirtualMachine
|
||||
{
|
||||
|
@ -1,11 +1,11 @@
|
||||
#include <windows.h>
|
||||
#include "..\PsfVm.h"
|
||||
#include "MiniDebugger.h"
|
||||
#include <windows.h>
|
||||
#include "..\PsfVm.h"
|
||||
#include "MiniDebugger.h"
|
||||
#include <io.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
using namespace std;
|
||||
|
||||
void InitializeConsole()
|
||||
{
|
||||
AllocConsole();
|
||||
@ -23,17 +23,17 @@ void InitializeConsole()
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
ios::sync_with_stdio();
|
||||
}
|
||||
|
||||
int WINAPI WinMain(HINSTANCE instance, HINSTANCE, char*, int)
|
||||
{
|
||||
// string filename = "C:\\nsf\\kh\\Kingdom Hearts (Sequences Only)\\101 - Dearly Beloved.psf2";
|
||||
// string filename = "C:\\nsf\\FF10\\111 Game Over.minipsf2";
|
||||
string filename = "C:\\Projects\\Purei\\tools\\PsfPlayer\\226 Castle Zvahl.psf2";
|
||||
InitializeConsole();
|
||||
CPsfVm virtualMachine(filename.c_str());
|
||||
|
||||
CMiniDebugger debugger(virtualMachine);
|
||||
debugger.Show(SW_SHOW);
|
||||
debugger.Run();
|
||||
return 1;
|
||||
}
|
||||
|
||||
int WINAPI WinMain(HINSTANCE instance, HINSTANCE, char*, int)
|
||||
{
|
||||
string filename = "C:\\nsf\\kh\\Kingdom Hearts (Sequences Only)\\101 - Dearly Beloved.psf2";
|
||||
// string filename = "C:\\nsf\\FF10\\111 Game Over.minipsf2";
|
||||
// string filename = "C:\\Projects\\Purei\\tools\\PsfPlayer\\226 Castle Zvahl.psf2";
|
||||
InitializeConsole();
|
||||
CPsfVm virtualMachine(filename.c_str());
|
||||
|
||||
CMiniDebugger debugger(virtualMachine);
|
||||
debugger.Show(SW_SHOW);
|
||||
debugger.Run();
|
||||
return 1;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user