2008-11-10 01:46:02 +00:00
|
|
|
#include <stddef.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <exception>
|
|
|
|
#include <boost/filesystem/path.hpp>
|
2014-05-23 00:39:22 -04:00
|
|
|
#include <boost/algorithm/string.hpp>
|
2008-11-10 01:46:02 +00:00
|
|
|
#include "PS2OS.h"
|
|
|
|
#include "Ps2Const.h"
|
|
|
|
#include "StdStream.h"
|
|
|
|
#include "PtrMacro.h"
|
|
|
|
#include "Utils.h"
|
|
|
|
#include "DMAC.h"
|
|
|
|
#include "INTC.h"
|
|
|
|
#include "SIF.h"
|
|
|
|
#include "ElfFile.h"
|
|
|
|
#include "COP_SCU.h"
|
|
|
|
#include "uint128.h"
|
2014-09-28 23:57:02 -04:00
|
|
|
#include "EEAssembler.h"
|
2012-08-23 01:49:03 +00:00
|
|
|
#include "PathUtils.h"
|
2008-11-10 01:46:02 +00:00
|
|
|
#include "xml/Node.h"
|
|
|
|
#include "xml/Parser.h"
|
|
|
|
#include "xml/FilteringNodeIterator.h"
|
|
|
|
#include "Log.h"
|
|
|
|
#include "iop/IopBios.h"
|
2012-08-23 11:27:27 +00:00
|
|
|
#include "StdStreamUtils.h"
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
// PS2OS Memory Allocation
|
2012-04-14 21:08:33 +00:00
|
|
|
// Start End Description
|
2014-10-12 20:55:28 -04:00
|
|
|
// 0x80000010 0x80000014 Current Thread ID
|
2008-11-10 01:46:02 +00:00
|
|
|
// 0x80008000 0x8000A000 DECI2 Handlers
|
|
|
|
// 0x8000A000 0x8000C000 INTC Handlers
|
|
|
|
// 0x8000C000 0x8000E000 DMAC Handlers
|
|
|
|
// 0x8000E000 0x80010000 Semaphores
|
2012-04-14 21:08:33 +00:00
|
|
|
// 0x80010000 0x80010800 Custom System Call addresses (0x200 entries)
|
2015-01-28 03:32:18 -05:00
|
|
|
// 0x80010800 0x80011000 Alarms
|
2008-11-10 01:46:02 +00:00
|
|
|
// 0x80011000 0x80020000 Threads
|
|
|
|
// 0x80020000 0x80030000 Kernel Stack
|
|
|
|
// 0x80030000 0x80032000 Thread Linked List
|
|
|
|
|
|
|
|
// BIOS area
|
2012-04-14 21:08:33 +00:00
|
|
|
// Start End Description
|
2008-11-10 01:46:02 +00:00
|
|
|
// 0x1FC00100 0x1FC00200 Custom System Call handling code
|
|
|
|
// 0x1FC00200 0x1FC01000 Interrupt Handler
|
2015-01-28 03:10:09 -05:00
|
|
|
// 0x1FC01000 0x1FC02000 DMAC Handler
|
|
|
|
// 0x1FC02000 0x1FC03000 INTC Handler
|
2008-11-10 01:46:02 +00:00
|
|
|
// 0x1FC03000 0x1FC03100 Thread epilogue
|
|
|
|
// 0x1FC03100 0x1FC03200 Wait Thread Proc
|
2015-01-28 03:32:18 -05:00
|
|
|
// 0x1FC03200 0x1FC03300 Alarm Handler
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-06-01 23:21:33 -04:00
|
|
|
#define BIOS_ADDRESS_KERNELSTACK_TOP 0x00030000
|
2014-10-12 20:55:28 -04:00
|
|
|
#define BIOS_ADDRESS_CURRENT_THREAD_ID 0x00000010
|
2015-01-29 01:36:29 -05:00
|
|
|
#define BIOS_ADDRESS_DMACHANDLER_BASE 0x0000C000
|
2015-01-31 01:40:42 -05:00
|
|
|
#define BIOS_ADDRESS_SEMAPHORE_BASE 0x0000E000
|
2015-01-28 03:32:18 -05:00
|
|
|
#define BIOS_ADDRESS_ALARM_BASE 0x00010800
|
2014-06-01 23:21:33 -04:00
|
|
|
|
|
|
|
#define BIOS_ADDRESS_BASE 0x1FC00000
|
2015-01-29 01:36:29 -05:00
|
|
|
#define BIOS_ADDRESS_INTERRUPTHANDLER 0x1FC00200
|
|
|
|
#define BIOS_ADDRESS_DMACHANDLER 0x1FC01000
|
2014-08-30 14:35:52 +09:00
|
|
|
#define BIOS_ADDRESS_THREADEPILOG 0x1FC03000
|
2014-06-01 23:21:33 -04:00
|
|
|
#define BIOS_ADDRESS_WAITTHREADPROC 0x1FC03100
|
2015-01-28 03:32:18 -05:00
|
|
|
#define BIOS_ADDRESS_ALARMHANDLER 0x1FC03200
|
|
|
|
|
|
|
|
#define BIOS_ID_BASE 1
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-10-05 01:41:06 -04:00
|
|
|
#define CONFIGPATH "./config/"
|
|
|
|
#define PATCHESFILENAME "patches.xml"
|
|
|
|
#define LOG_NAME ("ps2os")
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
#define THREAD_INIT_QUOTA (15)
|
|
|
|
|
2012-04-14 21:08:33 +00:00
|
|
|
#define SYSCALL_NAME_LOADEXECPS2 "osLoadExecPS2"
|
2011-07-04 03:12:07 +00:00
|
|
|
#define SYSCALL_NAME_ADDINTCHANDLER "osAddIntcHandler"
|
2014-12-14 01:55:22 -05:00
|
|
|
#define SYSCALL_NAME_REMOVEINTCHANDLER "osRemoveIntcHandler"
|
|
|
|
#define SYSCALL_NAME_ADDDMACHANDLER "osAddDmacHandler"
|
|
|
|
#define SYSCALL_NAME_REMOVEDMACHANDLER "osRemoveDmacHandler"
|
2011-07-16 04:39:52 +00:00
|
|
|
#define SYSCALL_NAME_ENABLEINTC "osEnableIntc"
|
2013-03-03 10:02:58 +00:00
|
|
|
#define SYSCALL_NAME_DISABLEINTC "osDisableIntc"
|
|
|
|
#define SYSCALL_NAME_ENABLEDMAC "osEnableDmac"
|
|
|
|
#define SYSCALL_NAME_DISABLEDMAC "osDisableDmac"
|
2015-01-28 03:32:18 -05:00
|
|
|
#define SYSCALL_NAME_SETALARM "osSetAlarm"
|
|
|
|
#define SYSCALL_NAME_IRELEASEALARM "osiReleaseAlarm"
|
2011-07-04 03:12:07 +00:00
|
|
|
#define SYSCALL_NAME_CREATETHREAD "osCreateThread"
|
2014-12-14 01:55:22 -05:00
|
|
|
#define SYSCALL_NAME_DELETETHREAD "osDeleteThread"
|
2011-07-04 03:12:07 +00:00
|
|
|
#define SYSCALL_NAME_STARTTHREAD "osStartThread"
|
2014-08-13 03:31:02 -04:00
|
|
|
#define SYSCALL_NAME_EXITDELETETHREAD "osExitDeleteThread"
|
2014-12-14 01:55:22 -05:00
|
|
|
#define SYSCALL_NAME_TERMINATETHREAD "osTerminateThread"
|
2014-08-10 20:39:17 -04:00
|
|
|
#define SYSCALL_NAME_CHANGETHREADPRIORITY "osChangeThreadPriority"
|
2011-07-04 03:12:07 +00:00
|
|
|
#define SYSCALL_NAME_ICHANGETHREADPRIORITY "osiChangeThreadPriority"
|
2011-12-25 04:06:43 +00:00
|
|
|
#define SYSCALL_NAME_ROTATETHREADREADYQUEUE "osRotateThreadReadyQueue"
|
2011-07-04 03:12:07 +00:00
|
|
|
#define SYSCALL_NAME_GETTHREADID "osGetThreadId"
|
|
|
|
#define SYSCALL_NAME_REFERTHREADSTATUS "osReferThreadStatus"
|
|
|
|
#define SYSCALL_NAME_IREFERTHREADSTATUS "osiReferThreadStatus"
|
2011-07-16 04:39:52 +00:00
|
|
|
#define SYSCALL_NAME_SLEEPTHREAD "osSleepThread"
|
|
|
|
#define SYSCALL_NAME_WAKEUPTHREAD "osWakeupThread"
|
|
|
|
#define SYSCALL_NAME_IWAKEUPTHREAD "osiWakeupThread"
|
2014-09-29 01:27:13 -04:00
|
|
|
#define SYSCALL_NAME_CANCELWAKEUPTHREAD "osCancelWakeupThread"
|
|
|
|
#define SYSCALL_NAME_ICANCELWAKEUPTHREAD "osiCancelWakeupThread"
|
2012-06-28 06:03:14 +00:00
|
|
|
#define SYSCALL_NAME_SUSPENDTHREAD "osSuspendThread"
|
|
|
|
#define SYSCALL_NAME_RESUMETHREAD "osResumeThread"
|
2011-12-25 04:06:43 +00:00
|
|
|
#define SYSCALL_NAME_ENDOFHEAP "osEndOfHeap"
|
2011-07-04 03:12:07 +00:00
|
|
|
#define SYSCALL_NAME_CREATESEMA "osCreateSema"
|
|
|
|
#define SYSCALL_NAME_DELETESEMA "osDeleteSema"
|
|
|
|
#define SYSCALL_NAME_SIGNALSEMA "osSignalSema"
|
|
|
|
#define SYSCALL_NAME_ISIGNALSEMA "osiSignalSema"
|
|
|
|
#define SYSCALL_NAME_WAITSEMA "osWaitSema"
|
|
|
|
#define SYSCALL_NAME_POLLSEMA "osPollSema"
|
2014-06-28 23:35:15 -04:00
|
|
|
#define SYSCALL_NAME_REFERSEMASTATUS "osReferSemaStatus"
|
|
|
|
#define SYSCALL_NAME_IREFERSEMASTATUS "osiReferSemaStatus"
|
2011-07-04 03:12:07 +00:00
|
|
|
#define SYSCALL_NAME_FLUSHCACHE "osFlushCache"
|
2014-08-02 21:34:38 -04:00
|
|
|
#define SYSCALL_NAME_SIFSTOPDMA "osSifStopDma"
|
2012-05-29 04:18:40 +00:00
|
|
|
#define SYSCALL_NAME_GSGETIMR "osGsGetIMR"
|
|
|
|
#define SYSCALL_NAME_GSPUTIMR "osGsPutIMR"
|
2013-03-03 10:02:58 +00:00
|
|
|
#define SYSCALL_NAME_SETVSYNCFLAG "osSetVSyncFlag"
|
2011-07-04 03:12:07 +00:00
|
|
|
#define SYSCALL_NAME_SIFDMASTAT "osSifDmaStat"
|
|
|
|
#define SYSCALL_NAME_SIFSETDMA "osSifSetDma"
|
2011-12-25 04:06:43 +00:00
|
|
|
#define SYSCALL_NAME_SIFSETDCHAIN "osSifSetDChain"
|
2015-03-05 12:08:07 -08:00
|
|
|
#define SYSCALL_NAME_DECI2CALL "osDeci2Call"
|
2011-07-04 03:12:07 +00:00
|
|
|
|
|
|
|
#ifdef DEBUGGER_INCLUDED
|
|
|
|
|
|
|
|
const CPS2OS::SYSCALL_NAME CPS2OS::g_syscallNames[] =
|
|
|
|
{
|
2012-04-14 21:08:33 +00:00
|
|
|
{ 0x0006, SYSCALL_NAME_LOADEXECPS2 },
|
2011-07-04 03:12:07 +00:00
|
|
|
{ 0x0010, SYSCALL_NAME_ADDINTCHANDLER },
|
2014-12-14 01:55:22 -05:00
|
|
|
{ 0x0011, SYSCALL_NAME_REMOVEINTCHANDLER },
|
|
|
|
{ 0x0012, SYSCALL_NAME_ADDDMACHANDLER },
|
|
|
|
{ 0x0013, SYSCALL_NAME_REMOVEDMACHANDLER },
|
2011-07-16 04:39:52 +00:00
|
|
|
{ 0x0014, SYSCALL_NAME_ENABLEINTC },
|
2013-03-03 10:02:58 +00:00
|
|
|
{ 0x0015, SYSCALL_NAME_DISABLEINTC },
|
|
|
|
{ 0x0016, SYSCALL_NAME_ENABLEDMAC },
|
|
|
|
{ 0x0017, SYSCALL_NAME_DISABLEDMAC },
|
2015-01-28 03:32:18 -05:00
|
|
|
{ 0x0018, SYSCALL_NAME_SETALARM },
|
|
|
|
{ 0x001F, SYSCALL_NAME_IRELEASEALARM },
|
2011-07-04 03:12:07 +00:00
|
|
|
{ 0x0020, SYSCALL_NAME_CREATETHREAD },
|
2014-12-14 01:55:22 -05:00
|
|
|
{ 0x0021, SYSCALL_NAME_DELETETHREAD },
|
2011-07-04 03:12:07 +00:00
|
|
|
{ 0x0022, SYSCALL_NAME_STARTTHREAD },
|
2014-08-13 03:31:02 -04:00
|
|
|
{ 0x0024, SYSCALL_NAME_EXITDELETETHREAD },
|
2014-12-14 01:55:22 -05:00
|
|
|
{ 0x0025, SYSCALL_NAME_TERMINATETHREAD },
|
2014-08-10 20:39:17 -04:00
|
|
|
{ 0x0029, SYSCALL_NAME_CHANGETHREADPRIORITY },
|
2011-07-04 03:12:07 +00:00
|
|
|
{ 0x002A, SYSCALL_NAME_ICHANGETHREADPRIORITY },
|
2011-12-25 04:06:43 +00:00
|
|
|
{ 0x002B, SYSCALL_NAME_ROTATETHREADREADYQUEUE },
|
2011-07-04 03:12:07 +00:00
|
|
|
{ 0x002F, SYSCALL_NAME_GETTHREADID },
|
|
|
|
{ 0x0030, SYSCALL_NAME_REFERTHREADSTATUS },
|
|
|
|
{ 0x0031, SYSCALL_NAME_IREFERTHREADSTATUS },
|
2011-07-16 04:39:52 +00:00
|
|
|
{ 0x0032, SYSCALL_NAME_SLEEPTHREAD },
|
|
|
|
{ 0x0033, SYSCALL_NAME_WAKEUPTHREAD },
|
|
|
|
{ 0x0034, SYSCALL_NAME_IWAKEUPTHREAD },
|
2014-09-29 01:27:13 -04:00
|
|
|
{ 0x0035, SYSCALL_NAME_CANCELWAKEUPTHREAD },
|
|
|
|
{ 0x0036, SYSCALL_NAME_ICANCELWAKEUPTHREAD },
|
2012-06-28 06:03:14 +00:00
|
|
|
{ 0x0037, SYSCALL_NAME_SUSPENDTHREAD },
|
|
|
|
{ 0x0039, SYSCALL_NAME_RESUMETHREAD },
|
2011-12-25 04:06:43 +00:00
|
|
|
{ 0x003E, SYSCALL_NAME_ENDOFHEAP },
|
2011-07-04 03:12:07 +00:00
|
|
|
{ 0x0040, SYSCALL_NAME_CREATESEMA },
|
|
|
|
{ 0x0041, SYSCALL_NAME_DELETESEMA },
|
|
|
|
{ 0x0042, SYSCALL_NAME_SIGNALSEMA },
|
|
|
|
{ 0x0043, SYSCALL_NAME_ISIGNALSEMA },
|
|
|
|
{ 0x0044, SYSCALL_NAME_WAITSEMA },
|
|
|
|
{ 0x0045, SYSCALL_NAME_POLLSEMA },
|
2014-06-28 23:35:15 -04:00
|
|
|
{ 0x0047, SYSCALL_NAME_REFERSEMASTATUS },
|
|
|
|
{ 0x0048, SYSCALL_NAME_IREFERSEMASTATUS },
|
2011-07-04 03:12:07 +00:00
|
|
|
{ 0x0064, SYSCALL_NAME_FLUSHCACHE },
|
2014-08-02 21:34:38 -04:00
|
|
|
{ 0x006B, SYSCALL_NAME_SIFSTOPDMA },
|
2012-05-29 04:18:40 +00:00
|
|
|
{ 0x0070, SYSCALL_NAME_GSGETIMR },
|
|
|
|
{ 0x0071, SYSCALL_NAME_GSPUTIMR },
|
2013-03-03 10:02:58 +00:00
|
|
|
{ 0x0073, SYSCALL_NAME_SETVSYNCFLAG },
|
2011-07-04 03:12:07 +00:00
|
|
|
{ 0x0076, SYSCALL_NAME_SIFDMASTAT },
|
|
|
|
{ 0x0077, SYSCALL_NAME_SIFSETDMA },
|
2011-12-25 04:06:43 +00:00
|
|
|
{ 0x0078, SYSCALL_NAME_SIFSETDCHAIN },
|
2015-03-05 12:08:07 -08:00
|
|
|
{ 0x007C, SYSCALL_NAME_DECI2CALL },
|
2011-07-04 03:12:07 +00:00
|
|
|
{ 0x0000, NULL }
|
|
|
|
};
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2008-12-15 02:57:21 +00:00
|
|
|
namespace filesystem = boost::filesystem;
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2015-01-31 23:05:56 -05:00
|
|
|
CPS2OS::CPS2OS(CMIPS& ee, uint8* ram, uint8* bios, uint8* spr, CGSHandler*& gs, CSIF& sif, CIopBios& iopBios)
|
2011-05-08 21:58:55 +00:00
|
|
|
: m_ee(ee)
|
|
|
|
, m_gs(gs)
|
2014-10-12 20:07:03 -04:00
|
|
|
, m_elf(nullptr)
|
2011-05-08 21:58:55 +00:00
|
|
|
, m_ram(ram)
|
|
|
|
, m_bios(bios)
|
2015-01-31 23:05:56 -05:00
|
|
|
, m_spr(spr)
|
2014-08-27 01:07:09 -04:00
|
|
|
, m_threadSchedule(nullptr)
|
2011-05-08 21:58:55 +00:00
|
|
|
, m_sif(sif)
|
|
|
|
, m_iopBios(iopBios)
|
2015-01-31 01:40:42 -05:00
|
|
|
, m_semaphores(reinterpret_cast<SEMAPHORE*>(m_ram + BIOS_ADDRESS_SEMAPHORE_BASE), BIOS_ID_BASE, MAX_SEMAPHORE)
|
2015-01-29 01:36:29 -05:00
|
|
|
, m_dmacHandlers(reinterpret_cast<DMACHANDLER*>(m_ram + BIOS_ADDRESS_DMACHANDLER_BASE), BIOS_ID_BASE, MAX_DMACHANDLER)
|
|
|
|
, m_alarms(reinterpret_cast<ALARM*>(m_ram + BIOS_ADDRESS_ALARM_BASE), BIOS_ID_BASE, MAX_ALARM)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
|
|
|
Initialize();
|
|
|
|
}
|
|
|
|
|
|
|
|
CPS2OS::~CPS2OS()
|
|
|
|
{
|
|
|
|
Release();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CPS2OS::Initialize()
|
|
|
|
{
|
2014-10-12 20:07:03 -04:00
|
|
|
m_elf = nullptr;
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
m_threadSchedule = new CRoundRibbon(m_ram + 0x30000, 0x2000);
|
2011-05-08 21:58:55 +00:00
|
|
|
|
|
|
|
m_semaWaitId = -1;
|
|
|
|
m_semaWaitCount = 0;
|
|
|
|
m_semaWaitCaller = 0;
|
2011-05-16 00:04:02 +00:00
|
|
|
m_semaWaitThreadId = -1;
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CPS2OS::Release()
|
|
|
|
{
|
|
|
|
UnloadExecutable();
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
DELETEPTR(m_threadSchedule);
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
2011-05-08 21:58:55 +00:00
|
|
|
bool CPS2OS::IsIdle() const
|
|
|
|
{
|
2011-05-16 00:04:02 +00:00
|
|
|
return (GetCurrentThreadId() == m_semaWaitThreadId);
|
2011-05-08 21:58:55 +00:00
|
|
|
}
|
|
|
|
|
2008-11-10 01:46:02 +00:00
|
|
|
void CPS2OS::DumpIntcHandlers()
|
|
|
|
{
|
|
|
|
printf("INTC Handlers Information\r\n");
|
|
|
|
printf("-------------------------\r\n");
|
|
|
|
|
|
|
|
for(unsigned int i = 0; i < MAX_INTCHANDLER; i++)
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
INTCHANDLER* handler = GetIntcHandler(i + 1);
|
|
|
|
if(handler->valid == 0) continue;
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
printf("ID: %0.2i, Line: %i, Address: 0x%0.8X.\r\n", \
|
|
|
|
i + 1,
|
2014-08-27 01:07:09 -04:00
|
|
|
handler->cause,
|
|
|
|
handler->address);
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CPS2OS::DumpDmacHandlers()
|
|
|
|
{
|
|
|
|
printf("DMAC Handlers Information\r\n");
|
|
|
|
printf("-------------------------\r\n");
|
|
|
|
|
|
|
|
for(unsigned int i = 0; i < MAX_DMACHANDLER; i++)
|
|
|
|
{
|
2015-01-29 01:36:29 -05:00
|
|
|
auto handler = m_dmacHandlers[i + 1];
|
|
|
|
if(handler == nullptr) continue;
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
printf("ID: %0.2i, Channel: %i, Address: 0x%0.8X.\r\n", \
|
|
|
|
i + 1,
|
2014-08-27 01:07:09 -04:00
|
|
|
handler->channel,
|
|
|
|
handler->address);
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CPS2OS::BootFromFile(const char* sPath)
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
filesystem::path execPath(sPath);
|
|
|
|
Framework::CStdStream stream(fopen(execPath.string().c_str(), "rb"));
|
|
|
|
LoadELF(stream, execPath.filename().string().c_str(), ArgumentList());
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
2012-04-14 21:08:33 +00:00
|
|
|
void CPS2OS::BootFromCDROM(const ArgumentList& arguments)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2011-07-04 03:12:07 +00:00
|
|
|
std::string executablePath;
|
2012-03-11 20:06:14 +00:00
|
|
|
Iop::CIoman* ioman = m_iopBios.GetIoman();
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2012-03-11 20:06:14 +00:00
|
|
|
{
|
2012-09-05 20:40:23 +00:00
|
|
|
uint32 handle = ioman->Open(Iop::Ioman::CDevice::OPEN_FLAG_RDONLY, "cdrom0:SYSTEM.CNF");
|
2012-03-11 20:06:14 +00:00
|
|
|
if(static_cast<int32>(handle) < 0)
|
|
|
|
{
|
2011-07-04 03:12:07 +00:00
|
|
|
throw std::runtime_error("No 'SYSTEM.CNF' file found on the cdrom0 device.");
|
2012-03-11 20:06:14 +00:00
|
|
|
}
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2012-03-11 20:06:14 +00:00
|
|
|
{
|
2011-07-04 03:12:07 +00:00
|
|
|
Framework::CStream* file(ioman->GetFileStream(handle));
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-05-23 00:39:22 -04:00
|
|
|
auto line = Utils::GetLine(file);
|
2012-03-11 20:06:14 +00:00
|
|
|
while(!file->IsEOF())
|
|
|
|
{
|
2014-05-23 00:39:22 -04:00
|
|
|
auto trimmedEnd = std::remove_if(line.begin(), line.end(), isspace);
|
|
|
|
auto trimmedLine = std::string(line.begin(), trimmedEnd);
|
|
|
|
std::vector<std::string> components;
|
|
|
|
boost::split(components, trimmedLine, boost::is_any_of("="), boost::algorithm::token_compress_on);
|
|
|
|
if(components.size() >= 2)
|
2012-03-11 20:06:14 +00:00
|
|
|
{
|
2014-05-23 00:39:22 -04:00
|
|
|
if(components[0] == "BOOT2")
|
2012-03-11 20:06:14 +00:00
|
|
|
{
|
2014-05-23 00:39:22 -04:00
|
|
|
executablePath = components[1];
|
2012-03-11 20:06:14 +00:00
|
|
|
}
|
|
|
|
}
|
2014-05-23 00:39:22 -04:00
|
|
|
line = Utils::GetLine(file);
|
2012-03-11 20:06:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ioman->Close(handle);
|
|
|
|
}
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
if(executablePath.length() == 0)
|
|
|
|
{
|
2011-07-04 03:12:07 +00:00
|
|
|
throw std::runtime_error("Error parsing 'SYSTEM.CNF' for a BOOT2 value.");
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
2012-03-11 20:06:14 +00:00
|
|
|
{
|
2012-09-05 20:40:23 +00:00
|
|
|
uint32 handle = ioman->Open(Iop::Ioman::CDevice::OPEN_FLAG_RDONLY, executablePath.c_str());
|
2012-03-11 20:06:14 +00:00
|
|
|
if(static_cast<int32>(handle) < 0)
|
|
|
|
{
|
2011-07-04 03:12:07 +00:00
|
|
|
throw std::runtime_error("Couldn't open executable specified in SYSTEM.CNF.");
|
2012-03-11 20:06:14 +00:00
|
|
|
}
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2012-03-11 20:06:14 +00:00
|
|
|
try
|
|
|
|
{
|
|
|
|
const char* executableName = strchr(executablePath.c_str(), ':') + 1;
|
|
|
|
if(executableName[0] == '/' || executableName[0] == '\\') executableName++;
|
2011-07-04 03:12:07 +00:00
|
|
|
Framework::CStream* file(ioman->GetFileStream(handle));
|
2012-04-14 21:08:33 +00:00
|
|
|
LoadELF(*file, executableName, arguments);
|
2012-03-11 20:06:14 +00:00
|
|
|
}
|
|
|
|
catch(...)
|
|
|
|
{
|
2014-07-12 20:27:48 -04:00
|
|
|
throw std::runtime_error("Error occured while reading ELF executable from disk.");
|
2012-03-11 20:06:14 +00:00
|
|
|
}
|
|
|
|
ioman->Close(handle);
|
|
|
|
}
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CELF* CPS2OS::GetELF()
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
return m_elf;
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
2011-10-21 19:01:59 +00:00
|
|
|
const char* CPS2OS::GetExecutableName() const
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2012-04-14 21:08:33 +00:00
|
|
|
return m_executableName.c_str();
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
2011-10-21 19:01:59 +00:00
|
|
|
std::pair<uint32, uint32> CPS2OS::GetExecutableRange() const
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
uint32 minAddr = 0xFFFFFFF0;
|
|
|
|
uint32 maxAddr = 0x00000000;
|
|
|
|
const ELFHEADER& header = m_elf->GetHeader();
|
2011-10-21 19:01:59 +00:00
|
|
|
|
|
|
|
for(unsigned int i = 0; i < header.nProgHeaderCount; i++)
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
ELFPROGRAMHEADER* p = m_elf->GetProgram(i);
|
2011-10-21 19:01:59 +00:00
|
|
|
if(p != NULL)
|
|
|
|
{
|
2012-12-30 22:34:28 +00:00
|
|
|
//Wild Arms: Alter Code F has zero sized program headers
|
|
|
|
if(p->nFileSize == 0) continue;
|
2011-10-21 19:01:59 +00:00
|
|
|
uint32 end = p->nVAddress + p->nFileSize;
|
2012-09-12 01:03:53 +00:00
|
|
|
if(end >= PS2::EE_RAM_SIZE) continue;
|
2014-08-27 01:07:09 -04:00
|
|
|
minAddr = std::min<uint32>(minAddr, p->nVAddress);
|
|
|
|
maxAddr = std::max<uint32>(maxAddr, end);
|
2011-10-21 19:01:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
return std::pair<uint32, uint32>(minAddr, maxAddr);
|
2011-10-21 19:01:59 +00:00
|
|
|
}
|
|
|
|
|
2012-04-14 21:08:33 +00:00
|
|
|
void CPS2OS::LoadELF(Framework::CStream& stream, const char* sExecName, const ArgumentList& arguments)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
CELF* elf(new CElfFile(stream));
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
const ELFHEADER& header = elf->GetHeader();
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
//Check for MIPS CPU
|
|
|
|
if(header.nCPU != 8)
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
DELETEPTR(elf);
|
2011-07-04 03:12:07 +00:00
|
|
|
throw std::runtime_error("Invalid target CPU. Must be MIPS.");
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if(header.nType != 2)
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
DELETEPTR(elf);
|
2011-07-04 03:12:07 +00:00
|
|
|
throw std::runtime_error("Not an executable ELF file.");
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
UnloadExecutable();
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
m_elf = elf;
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2012-04-14 21:08:33 +00:00
|
|
|
m_executableName = sExecName;
|
|
|
|
m_currentArguments = arguments;
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2012-12-23 14:59:38 +00:00
|
|
|
LoadExecutableInternal();
|
2008-11-10 01:46:02 +00:00
|
|
|
ApplyPatches();
|
|
|
|
|
2012-03-11 20:06:14 +00:00
|
|
|
OnExecutableChange();
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
printf("PS2OS: Loaded '%s' executable file.\r\n", sExecName);
|
|
|
|
}
|
|
|
|
|
2012-12-23 14:59:38 +00:00
|
|
|
void CPS2OS::LoadExecutableInternal()
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2011-10-21 19:01:59 +00:00
|
|
|
//Copy program in main RAM
|
2014-08-27 01:07:09 -04:00
|
|
|
const ELFHEADER& header = m_elf->GetHeader();
|
2008-11-10 01:46:02 +00:00
|
|
|
for(unsigned int i = 0; i < header.nProgHeaderCount; i++)
|
|
|
|
{
|
2015-01-01 18:14:21 -05:00
|
|
|
auto p = m_elf->GetProgram(i);
|
|
|
|
if(p != nullptr)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2015-01-01 18:14:21 -05:00
|
|
|
if(p->nVAddress >= PS2::EE_RAM_SIZE)
|
|
|
|
{
|
|
|
|
assert(false);
|
|
|
|
continue;
|
|
|
|
}
|
2014-08-27 01:07:09 -04:00
|
|
|
memcpy(m_ram + p->nVAddress, m_elf->GetContent() + p->nOffset, p->nFileSize);
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
m_ee.m_State.nPC = header.nEntryPoint;
|
|
|
|
|
|
|
|
AssembleCustomSyscallHandler();
|
|
|
|
AssembleInterruptHandler();
|
|
|
|
AssembleDmacHandler();
|
|
|
|
AssembleIntcHandler();
|
|
|
|
AssembleThreadEpilog();
|
|
|
|
AssembleWaitThreadProc();
|
2015-01-28 03:32:18 -05:00
|
|
|
AssembleAlarmHandler();
|
2008-11-10 01:46:02 +00:00
|
|
|
CreateWaitThread();
|
|
|
|
|
|
|
|
#ifdef DEBUGGER_INCLUDED
|
2011-10-21 19:01:59 +00:00
|
|
|
std::pair<uint32, uint32> executableRange = GetExecutableRange();
|
2014-08-27 01:07:09 -04:00
|
|
|
uint32 minAddr = executableRange.first;
|
|
|
|
uint32 maxAddr = executableRange.second & ~0x03;
|
2011-10-21 19:01:59 +00:00
|
|
|
|
2014-08-16 21:42:19 -04:00
|
|
|
m_ee.m_analysis->Clear();
|
2014-08-27 01:07:09 -04:00
|
|
|
m_ee.m_analysis->Analyse(minAddr, maxAddr, header.nEntryPoint);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2011-07-04 03:12:07 +00:00
|
|
|
//Tag system calls
|
2014-08-27 01:07:09 -04:00
|
|
|
for(uint32 address = minAddr; address < maxAddr; address += 4)
|
2011-07-04 03:12:07 +00:00
|
|
|
{
|
|
|
|
//Check for SYSCALL opcode
|
|
|
|
uint32 opcode = *reinterpret_cast<uint32*>(m_ram + address);
|
|
|
|
if(opcode == 0x0000000C)
|
|
|
|
{
|
|
|
|
//Check the opcode before and after it
|
|
|
|
uint32 addiu = *reinterpret_cast<uint32*>(m_ram + address - 4);
|
|
|
|
uint32 jr = *reinterpret_cast<uint32*>(m_ram + address + 4);
|
|
|
|
if(
|
|
|
|
(jr == 0x03E00008) &&
|
|
|
|
(addiu & 0xFFFF0000) == 0x24030000
|
|
|
|
)
|
|
|
|
{
|
|
|
|
//We have it!
|
|
|
|
int16 syscallId = static_cast<int16>(addiu);
|
|
|
|
if(syscallId & 0x8000)
|
|
|
|
{
|
|
|
|
syscallId = 0 - syscallId;
|
|
|
|
}
|
|
|
|
char syscallName[256];
|
|
|
|
int syscallNameIndex = -1;
|
|
|
|
for(int i = 0; g_syscallNames[i].name != NULL; i++)
|
|
|
|
{
|
|
|
|
if(g_syscallNames[i].id == syscallId)
|
|
|
|
{
|
|
|
|
syscallNameIndex = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(syscallNameIndex != -1)
|
|
|
|
{
|
|
|
|
strncpy(syscallName, g_syscallNames[syscallNameIndex].name, 256);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sprintf(syscallName, "syscall_%0.4X", syscallId);
|
|
|
|
}
|
|
|
|
m_ee.m_Functions.InsertTag(address - 4, syscallName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CPS2OS::UnloadExecutable()
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
if(m_elf == NULL) return;
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2012-03-11 20:06:14 +00:00
|
|
|
OnExecutableUnloading();
|
2008-11-25 02:00:42 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
DELETEPTR(m_elf);
|
2011-07-04 03:12:07 +00:00
|
|
|
}
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2012-10-24 06:39:29 +00:00
|
|
|
uint32 CPS2OS::LoadExecutable(const char* path, const char* section)
|
|
|
|
{
|
|
|
|
auto ioman = m_iopBios.GetIoman();
|
|
|
|
|
|
|
|
uint32 handle = ioman->Open(Iop::Ioman::CDevice::OPEN_FLAG_RDONLY, path);
|
|
|
|
if(static_cast<int32>(handle) < 0)
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32 result = 0;
|
|
|
|
|
|
|
|
//We don't support loading anything else than all sections
|
|
|
|
assert(strcmp(section, "all") == 0);
|
|
|
|
|
|
|
|
auto fileStream(ioman->GetFileStream(handle));
|
|
|
|
|
|
|
|
//Load all program sections
|
|
|
|
{
|
|
|
|
CElfFile executable(*fileStream);
|
|
|
|
const auto& header = executable.GetHeader();
|
|
|
|
for(unsigned int i = 0; i < header.nProgHeaderCount; i++)
|
|
|
|
{
|
|
|
|
auto p = executable.GetProgram(i);
|
|
|
|
if(p)
|
|
|
|
{
|
|
|
|
memcpy(m_ram + p->nVAddress, executable.GetContent() + p->nOffset, p->nFileSize);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
result = executable.GetHeader().nEntryPoint;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Flush all instruction cache
|
|
|
|
OnRequestInstructionCacheFlush();
|
|
|
|
|
|
|
|
ioman->Close(handle);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2008-11-10 01:46:02 +00:00
|
|
|
void CPS2OS::ApplyPatches()
|
|
|
|
{
|
2012-08-23 01:49:03 +00:00
|
|
|
auto patchesPath = Framework::PathUtils::GetAppResourcesPath() / PATCHESFILENAME;
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2012-08-23 01:49:03 +00:00
|
|
|
std::unique_ptr<Framework::Xml::CNode> document;
|
2008-11-10 01:46:02 +00:00
|
|
|
try
|
|
|
|
{
|
2012-09-04 23:53:34 +00:00
|
|
|
Framework::CStdStream patchesStream(Framework::CreateInputStdStream(patchesPath.native()));
|
|
|
|
document = std::unique_ptr<Framework::Xml::CNode>(Framework::Xml::CParser::ParseDocument(patchesStream));
|
2012-08-23 01:49:03 +00:00
|
|
|
if(!document) return;
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
2012-08-23 01:49:03 +00:00
|
|
|
catch(const std::exception& exception)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2012-08-23 01:49:03 +00:00
|
|
|
printf("Failed to open patch definition file: %s.\r\n", exception.what());
|
2008-11-10 01:46:02 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-08-23 01:49:03 +00:00
|
|
|
auto patchesNode = document->Select("Patches");
|
|
|
|
if(patchesNode == NULL)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-08-23 01:49:03 +00:00
|
|
|
for(Framework::Xml::CFilteringNodeIterator itNode(patchesNode, "Executable"); !itNode.IsEnd(); itNode++)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2012-08-23 01:49:03 +00:00
|
|
|
auto executableNode = (*itNode);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
const char* name = executableNode->GetAttribute("Name");
|
|
|
|
if(name == NULL) continue;
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
if(!strcmp(name, GetExecutableName()))
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
|
|
|
//Found the right executable
|
2014-08-27 01:07:09 -04:00
|
|
|
unsigned int patchCount = 0;
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2012-08-23 01:49:03 +00:00
|
|
|
for(Framework::Xml::CFilteringNodeIterator itNode(executableNode, "Patch"); !itNode.IsEnd(); itNode++)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
auto patch = (*itNode);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
const char* addressString = patch->GetAttribute("Address");
|
|
|
|
const char* valueString = patch->GetAttribute("Value");
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
if(addressString == nullptr) continue;
|
|
|
|
if(valueString == nullptr) continue;
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
uint32 value = 0, address = 0;
|
|
|
|
if(sscanf(addressString, "%x", &address) == 0) continue;
|
|
|
|
if(sscanf(valueString, "%x", &value) == 0) continue;
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
*(uint32*)&m_ram[address] = value;
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
patchCount++;
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
printf("PS2OS: Applied %i patch(es).\r\n", patchCount);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CPS2OS::AssembleCustomSyscallHandler()
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
CMIPSAssembler assembler((uint32*)&m_bios[0x100]);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
//Epilogue
|
2014-08-27 01:07:09 -04:00
|
|
|
assembler.ADDIU(CMIPS::SP, CMIPS::SP, 0xFFF0);
|
|
|
|
assembler.SD(CMIPS::RA, 0x0000, CMIPS::SP);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
//Load the function address off the table at 0x80010000
|
2014-08-27 01:07:09 -04:00
|
|
|
assembler.SLL(CMIPS::T0, CMIPS::V1, 2);
|
|
|
|
assembler.LUI(CMIPS::T1, 0x8001);
|
|
|
|
assembler.ADDU(CMIPS::T0, CMIPS::T0, CMIPS::T1);
|
|
|
|
assembler.LW(CMIPS::T0, 0x0000, CMIPS::T0);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
//And the address with 0x1FFFFFFF
|
2014-08-27 01:07:09 -04:00
|
|
|
assembler.LUI(CMIPS::T1, 0x1FFF);
|
|
|
|
assembler.ORI(CMIPS::T1, CMIPS::T1, 0xFFFF);
|
|
|
|
assembler.AND(CMIPS::T0, CMIPS::T0, CMIPS::T1);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
//Jump to the system call address
|
2014-08-27 01:07:09 -04:00
|
|
|
assembler.JALR(CMIPS::T0);
|
|
|
|
assembler.NOP();
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
//Prologue
|
2014-08-27 01:07:09 -04:00
|
|
|
assembler.LD(CMIPS::RA, 0x0000, CMIPS::SP);
|
|
|
|
assembler.ADDIU(CMIPS::SP, CMIPS::SP, 0x0010);
|
|
|
|
assembler.ERET();
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CPS2OS::AssembleInterruptHandler()
|
|
|
|
{
|
2015-01-29 01:36:29 -05:00
|
|
|
CEEAssembler assembler(reinterpret_cast<uint32*>(&m_bios[BIOS_ADDRESS_INTERRUPTHANDLER - BIOS_ADDRESS_BASE]));
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-07-10 23:56:50 -04:00
|
|
|
const uint32 stackFrameSize = 0x230;
|
2011-07-04 03:12:07 +00:00
|
|
|
|
|
|
|
//Epilogue (allocate stackFrameSize bytes)
|
2014-08-27 01:07:09 -04:00
|
|
|
assembler.LI(CMIPS::K0, BIOS_ADDRESS_KERNELSTACK_TOP);
|
|
|
|
assembler.ADDIU(CMIPS::K0, CMIPS::K0, 0x10000 - stackFrameSize);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
//Save context
|
2010-10-13 01:53:26 +00:00
|
|
|
for(unsigned int i = 0; i < 32; i++)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
assembler.SQ(i, (i * 0x10), CMIPS::K0);
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
2014-07-10 23:56:50 -04:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
assembler.MFLO(CMIPS::V0);
|
|
|
|
assembler.MFLO1(CMIPS::V1);
|
|
|
|
assembler.SD(CMIPS::V0, 0x0200, CMIPS::K0);
|
|
|
|
assembler.SD(CMIPS::V1, 0x0208, CMIPS::K0);
|
2014-07-10 23:56:50 -04:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
assembler.MFHI(CMIPS::V0);
|
|
|
|
assembler.MFHI1(CMIPS::V1);
|
|
|
|
assembler.SD(CMIPS::V0, 0x0210, CMIPS::K0);
|
|
|
|
assembler.SD(CMIPS::V1, 0x0218, CMIPS::K0);
|
2014-07-10 23:56:50 -04:00
|
|
|
|
2008-11-10 01:46:02 +00:00
|
|
|
//Save EPC
|
2014-08-27 01:07:09 -04:00
|
|
|
assembler.MFC0(CMIPS::T0, CCOP_SCU::EPC);
|
|
|
|
assembler.SW(CMIPS::T0, 0x0220, CMIPS::K0);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
//Set SP
|
2014-08-27 01:07:09 -04:00
|
|
|
assembler.ADDU(CMIPS::SP, CMIPS::K0, CMIPS::R0);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
//Get INTC status
|
2014-08-27 01:07:09 -04:00
|
|
|
assembler.LUI(CMIPS::T0, 0x1000);
|
|
|
|
assembler.ORI(CMIPS::T0, CMIPS::T0, 0xF000);
|
|
|
|
assembler.LW(CMIPS::S0, 0x0000, CMIPS::T0);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
//Get INTC mask
|
2014-08-27 01:07:09 -04:00
|
|
|
assembler.LUI(CMIPS::T1, 0x1000);
|
|
|
|
assembler.ORI(CMIPS::T1, CMIPS::T1, 0xF010);
|
|
|
|
assembler.LW(CMIPS::S1, 0x0000, CMIPS::T1);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
//Get cause
|
2014-08-27 01:07:09 -04:00
|
|
|
assembler.AND(CMIPS::S0, CMIPS::S0, CMIPS::S1);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
//Clear cause
|
2014-08-27 01:07:09 -04:00
|
|
|
//assembler.SW(CMIPS::S0, 0x0000, CMIPS::T0);
|
|
|
|
assembler.NOP();
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-04-17 02:38:25 -04:00
|
|
|
static const auto generateIntHandler =
|
|
|
|
[](CMIPSAssembler& assembler, uint32 line)
|
|
|
|
{
|
|
|
|
auto skipIntHandlerLabel = assembler.CreateLabel();
|
2014-03-27 13:44:44 +00:00
|
|
|
|
2014-04-17 02:38:25 -04:00
|
|
|
//Check cause
|
|
|
|
assembler.ANDI(CMIPS::T0, CMIPS::S0, (1 << line));
|
|
|
|
assembler.BEQ(CMIPS::R0, CMIPS::T0, skipIntHandlerLabel);
|
|
|
|
assembler.NOP();
|
2014-03-27 13:44:44 +00:00
|
|
|
|
2014-04-17 02:38:25 -04:00
|
|
|
//Process handlers
|
|
|
|
assembler.LUI(CMIPS::T0, 0x1FC0);
|
|
|
|
assembler.ORI(CMIPS::T0, CMIPS::T0, 0x2000);
|
|
|
|
assembler.ADDIU(CMIPS::A0, CMIPS::R0, line);
|
|
|
|
assembler.JALR(CMIPS::T0);
|
|
|
|
assembler.NOP();
|
2010-10-13 01:53:26 +00:00
|
|
|
|
2014-04-17 02:38:25 -04:00
|
|
|
assembler.MarkLabel(skipIntHandlerLabel);
|
|
|
|
};
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
generateIntHandler(assembler, CINTC::INTC_LINE_GS);
|
2014-04-17 02:38:25 -04:00
|
|
|
|
2010-10-13 01:53:26 +00:00
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
auto skipIntHandlerLabel = assembler.CreateLabel();
|
2010-10-13 01:53:26 +00:00
|
|
|
|
2014-04-17 02:38:25 -04:00
|
|
|
//Check if INT1 (DMAC)
|
2014-08-27 01:07:09 -04:00
|
|
|
assembler.ANDI(CMIPS::T0, CMIPS::S0, (1 << CINTC::INTC_LINE_DMAC));
|
|
|
|
assembler.BEQ(CMIPS::R0, CMIPS::T0, skipIntHandlerLabel);
|
|
|
|
assembler.NOP();
|
2010-10-13 01:53:26 +00:00
|
|
|
|
2014-04-17 02:38:25 -04:00
|
|
|
//Go to DMAC interrupt handler
|
2015-01-29 01:36:29 -05:00
|
|
|
assembler.JAL(BIOS_ADDRESS_DMACHANDLER);
|
2014-08-27 01:07:09 -04:00
|
|
|
assembler.NOP();
|
2010-10-13 01:53:26 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
assembler.MarkLabel(skipIntHandlerLabel);
|
2010-10-13 01:53:26 +00:00
|
|
|
}
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
generateIntHandler(assembler, CINTC::INTC_LINE_VBLANK_START);
|
|
|
|
generateIntHandler(assembler, CINTC::INTC_LINE_VBLANK_END);
|
|
|
|
generateIntHandler(assembler, CINTC::INTC_LINE_TIMER0);
|
|
|
|
generateIntHandler(assembler, CINTC::INTC_LINE_TIMER1);
|
|
|
|
generateIntHandler(assembler, CINTC::INTC_LINE_TIMER2);
|
|
|
|
generateIntHandler(assembler, CINTC::INTC_LINE_TIMER3);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2015-01-28 03:32:18 -05:00
|
|
|
assembler.JAL(BIOS_ADDRESS_ALARMHANDLER);
|
|
|
|
assembler.NOP();
|
|
|
|
|
2014-06-01 23:21:33 -04:00
|
|
|
//Move back SP into K0 before restoring state
|
2014-08-27 01:07:09 -04:00
|
|
|
assembler.ADDIU(CMIPS::K0, CMIPS::SP, CMIPS::R0);
|
2014-06-01 23:21:33 -04:00
|
|
|
|
2008-11-10 01:46:02 +00:00
|
|
|
//Restore EPC
|
2014-08-27 01:07:09 -04:00
|
|
|
assembler.LW(CMIPS::T0, 0x0220, CMIPS::K0);
|
|
|
|
assembler.MTC0(CMIPS::T0, CCOP_SCU::EPC);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
//Restore Context
|
2014-08-27 01:07:09 -04:00
|
|
|
assembler.LD(CMIPS::V0, 0x0210, CMIPS::K0);
|
|
|
|
assembler.LD(CMIPS::V1, 0x0218, CMIPS::K0);
|
|
|
|
assembler.MTHI(CMIPS::V0);
|
|
|
|
assembler.MTHI1(CMIPS::V1);
|
2014-07-10 23:56:50 -04:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
assembler.LD(CMIPS::V0, 0x0200, CMIPS::K0);
|
|
|
|
assembler.LD(CMIPS::V1, 0x0208, CMIPS::K0);
|
|
|
|
assembler.MTLO(CMIPS::V0);
|
|
|
|
assembler.MTLO1(CMIPS::V1);
|
2014-07-10 23:56:50 -04:00
|
|
|
|
2010-10-13 01:53:26 +00:00
|
|
|
for(unsigned int i = 0; i < 32; i++)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
assembler.LQ(i, (i * 0x10), CMIPS::K0);
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//Prologue
|
2014-08-27 01:07:09 -04:00
|
|
|
assembler.ERET();
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CPS2OS::AssembleDmacHandler()
|
|
|
|
{
|
2015-01-29 01:36:29 -05:00
|
|
|
CMIPSAssembler assembler(reinterpret_cast<uint32*>(&m_bios[BIOS_ADDRESS_DMACHANDLER - BIOS_ADDRESS_BASE]));
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
auto testHandlerLabel = assembler.CreateLabel();
|
|
|
|
auto testChannelLabel = assembler.CreateLabel();
|
|
|
|
auto skipHandlerLabel = assembler.CreateLabel();
|
|
|
|
auto skipChannelLabel = assembler.CreateLabel();
|
2014-04-27 20:26:05 -04:00
|
|
|
|
2008-11-10 01:46:02 +00:00
|
|
|
//Prologue
|
|
|
|
//S0 -> Channel Counter
|
|
|
|
//S1 -> DMA Interrupt Status
|
|
|
|
//S2 -> Handler Counter
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
assembler.ADDIU(CMIPS::SP, CMIPS::SP, 0xFFE0);
|
|
|
|
assembler.SD(CMIPS::RA, 0x0000, CMIPS::SP);
|
|
|
|
assembler.SD(CMIPS::S0, 0x0008, CMIPS::SP);
|
|
|
|
assembler.SD(CMIPS::S1, 0x0010, CMIPS::SP);
|
|
|
|
assembler.SD(CMIPS::S2, 0x0018, CMIPS::SP);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2012-03-11 20:06:14 +00:00
|
|
|
//Clear INTC cause
|
2014-08-27 01:07:09 -04:00
|
|
|
assembler.LI(CMIPS::T1, CINTC::INTC_STAT);
|
|
|
|
assembler.ADDIU(CMIPS::T0, CMIPS::R0, (1 << CINTC::INTC_LINE_DMAC));
|
|
|
|
assembler.SW(CMIPS::T0, 0x0000, CMIPS::T1);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
//Load the DMA interrupt status
|
2014-08-27 01:07:09 -04:00
|
|
|
assembler.LI(CMIPS::T0, CDMAC::D_STAT);
|
|
|
|
assembler.LW(CMIPS::T0, 0x0000, CMIPS::T0);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
assembler.SRL(CMIPS::T1, CMIPS::T0, 16);
|
|
|
|
assembler.AND(CMIPS::S1, CMIPS::T0, CMIPS::T1);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
//Initialize channel counter
|
2014-08-27 01:07:09 -04:00
|
|
|
assembler.ADDIU(CMIPS::S0, CMIPS::R0, 0x0009);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
assembler.MarkLabel(testChannelLabel);
|
2014-04-27 20:26:05 -04:00
|
|
|
|
2008-11-10 01:46:02 +00:00
|
|
|
//Check if that specific DMA channel interrupt is the cause
|
2014-08-27 01:07:09 -04:00
|
|
|
assembler.ORI(CMIPS::T0, CMIPS::R0, 0x0001);
|
|
|
|
assembler.SLLV(CMIPS::T0, CMIPS::T0, CMIPS::S0);
|
|
|
|
assembler.AND(CMIPS::T0, CMIPS::T0, CMIPS::S1);
|
|
|
|
assembler.BEQ(CMIPS::T0, CMIPS::R0, skipChannelLabel);
|
|
|
|
assembler.NOP();
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
//Clear interrupt
|
2014-08-27 01:07:09 -04:00
|
|
|
assembler.LI(CMIPS::T1, CDMAC::D_STAT);
|
|
|
|
assembler.SW(CMIPS::T0, 0x0000, CMIPS::T1);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
//Initialize DMAC handler loop
|
2014-08-27 01:07:09 -04:00
|
|
|
assembler.ADDU(CMIPS::S2, CMIPS::R0, CMIPS::R0);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
assembler.MarkLabel(testHandlerLabel);
|
2014-04-27 20:26:05 -04:00
|
|
|
|
2008-11-10 01:46:02 +00:00
|
|
|
//Get the address to the current DMACHANDLER structure
|
2014-08-27 01:07:09 -04:00
|
|
|
assembler.ADDIU(CMIPS::T0, CMIPS::R0, sizeof(DMACHANDLER));
|
|
|
|
assembler.MULTU(CMIPS::T0, CMIPS::S2, CMIPS::T0);
|
2015-01-29 01:36:29 -05:00
|
|
|
assembler.LI(CMIPS::T1, BIOS_ADDRESS_DMACHANDLER_BASE);
|
2014-08-27 01:07:09 -04:00
|
|
|
assembler.ADDU(CMIPS::T0, CMIPS::T0, CMIPS::T1);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
//Check validity
|
2015-01-29 01:36:29 -05:00
|
|
|
assembler.LW(CMIPS::T1, offsetof(DMACHANDLER, isValid), CMIPS::T0);
|
2014-08-27 01:07:09 -04:00
|
|
|
assembler.BEQ(CMIPS::T1, CMIPS::R0, skipHandlerLabel);
|
|
|
|
assembler.NOP();
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
//Check if the channel is good one
|
2015-01-29 01:36:29 -05:00
|
|
|
assembler.LW(CMIPS::T1, offsetof(DMACHANDLER, channel), CMIPS::T0);
|
2014-08-27 01:07:09 -04:00
|
|
|
assembler.BNE(CMIPS::S0, CMIPS::T1, skipHandlerLabel);
|
|
|
|
assembler.NOP();
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
//Load the necessary stuff
|
2015-01-29 01:36:29 -05:00
|
|
|
assembler.LW(CMIPS::T1, offsetof(DMACHANDLER, address), CMIPS::T0);
|
2014-08-27 01:07:09 -04:00
|
|
|
assembler.ADDU(CMIPS::A0, CMIPS::S0, CMIPS::R0);
|
2015-01-29 01:36:29 -05:00
|
|
|
assembler.LW(CMIPS::A1, offsetof(DMACHANDLER, arg), CMIPS::T0);
|
|
|
|
assembler.LW(CMIPS::GP, offsetof(DMACHANDLER, gp), CMIPS::T0);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
//Jump
|
2014-08-27 01:07:09 -04:00
|
|
|
assembler.JALR(CMIPS::T1);
|
|
|
|
assembler.NOP();
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
assembler.MarkLabel(skipHandlerLabel);
|
2014-04-27 20:26:05 -04:00
|
|
|
|
2008-11-10 01:46:02 +00:00
|
|
|
//Increment handler counter and test
|
2014-08-27 01:07:09 -04:00
|
|
|
assembler.ADDIU(CMIPS::S2, CMIPS::S2, 0x0001);
|
|
|
|
assembler.ADDIU(CMIPS::T0, CMIPS::R0, MAX_DMACHANDLER - 1);
|
|
|
|
assembler.BNE(CMIPS::S2, CMIPS::T0, testHandlerLabel);
|
|
|
|
assembler.NOP();
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
assembler.MarkLabel(skipChannelLabel);
|
2014-04-27 20:26:05 -04:00
|
|
|
|
2008-11-10 01:46:02 +00:00
|
|
|
//Decrement channel counter and test
|
2014-08-27 01:07:09 -04:00
|
|
|
assembler.ADDIU(CMIPS::S0, CMIPS::S0, 0xFFFF);
|
|
|
|
assembler.BGEZ(CMIPS::S0, testChannelLabel);
|
|
|
|
assembler.NOP();
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
//Epilogue
|
2014-08-27 01:07:09 -04:00
|
|
|
assembler.LD(CMIPS::RA, 0x0000, CMIPS::SP);
|
|
|
|
assembler.LD(CMIPS::S0, 0x0008, CMIPS::SP);
|
|
|
|
assembler.LD(CMIPS::S1, 0x0010, CMIPS::SP);
|
|
|
|
assembler.LD(CMIPS::S2, 0x0018, CMIPS::SP);
|
|
|
|
assembler.ADDIU(CMIPS::SP, CMIPS::SP, 0x20);
|
|
|
|
assembler.JR(CMIPS::RA);
|
|
|
|
assembler.NOP();
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CPS2OS::AssembleIntcHandler()
|
|
|
|
{
|
2012-04-23 06:07:13 +00:00
|
|
|
CMIPSAssembler assembler(reinterpret_cast<uint32*>(&m_bios[0x2000]));
|
|
|
|
|
|
|
|
CMIPSAssembler::LABEL checkHandlerLabel = assembler.CreateLabel();
|
|
|
|
CMIPSAssembler::LABEL moveToNextHandler = assembler.CreateLabel();
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
//Prologue
|
|
|
|
//S0 -> Handler Counter
|
|
|
|
|
2012-04-23 06:07:13 +00:00
|
|
|
assembler.ADDIU(CMIPS::SP, CMIPS::SP, 0xFFE0);
|
|
|
|
assembler.SD(CMIPS::RA, 0x0000, CMIPS::SP);
|
|
|
|
assembler.SD(CMIPS::S0, 0x0008, CMIPS::SP);
|
|
|
|
assembler.SD(CMIPS::S1, 0x0010, CMIPS::SP);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2012-03-11 20:06:14 +00:00
|
|
|
//Clear INTC cause
|
2012-04-23 06:07:13 +00:00
|
|
|
assembler.LUI(CMIPS::T1, 0x1000);
|
|
|
|
assembler.ORI(CMIPS::T1, CMIPS::T1, 0xF000);
|
|
|
|
assembler.ADDIU(CMIPS::T0, CMIPS::R0, 0x0001);
|
|
|
|
assembler.SLLV(CMIPS::T0, CMIPS::T0, CMIPS::A0);
|
|
|
|
assembler.SW(CMIPS::T0, 0x0000, CMIPS::T1);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2012-03-11 20:06:14 +00:00
|
|
|
//Initialize INTC handler loop
|
2012-04-23 06:07:13 +00:00
|
|
|
assembler.ADDU(CMIPS::S0, CMIPS::R0, CMIPS::R0);
|
|
|
|
assembler.ADDU(CMIPS::S1, CMIPS::A0, CMIPS::R0);
|
|
|
|
|
|
|
|
assembler.MarkLabel(checkHandlerLabel);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
//Get the address to the current INTCHANDLER structure
|
2012-04-23 06:07:13 +00:00
|
|
|
assembler.ADDIU(CMIPS::T0, CMIPS::R0, sizeof(INTCHANDLER));
|
|
|
|
assembler.MULTU(CMIPS::T0, CMIPS::S0, CMIPS::T0);
|
|
|
|
assembler.LUI(CMIPS::T1, 0x8000);
|
|
|
|
assembler.ORI(CMIPS::T1, CMIPS::T1, 0xA000);
|
|
|
|
assembler.ADDU(CMIPS::T0, CMIPS::T0, CMIPS::T1);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
//Check validity
|
2012-04-23 06:07:13 +00:00
|
|
|
assembler.LW(CMIPS::T1, 0x0000, CMIPS::T0);
|
|
|
|
assembler.BEQ(CMIPS::T1, CMIPS::R0, moveToNextHandler);
|
|
|
|
assembler.NOP();
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
//Check if the cause is good one
|
2012-04-23 06:07:13 +00:00
|
|
|
assembler.LW(CMIPS::T1, 0x0004, CMIPS::T0);
|
|
|
|
assembler.BNE(CMIPS::S1, CMIPS::T1, moveToNextHandler);
|
|
|
|
assembler.NOP();
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
//Load the necessary stuff
|
2012-04-23 06:07:13 +00:00
|
|
|
assembler.LW(CMIPS::T1, 0x0008, CMIPS::T0);
|
|
|
|
assembler.ADDU(CMIPS::A0, CMIPS::S1, CMIPS::R0);
|
|
|
|
assembler.LW(CMIPS::A1, 0x000C, CMIPS::T0);
|
|
|
|
assembler.LW(CMIPS::GP, 0x0010, CMIPS::T0);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
//Jump
|
2012-04-23 06:07:13 +00:00
|
|
|
assembler.JALR(CMIPS::T1);
|
|
|
|
assembler.NOP();
|
|
|
|
|
|
|
|
assembler.MarkLabel(moveToNextHandler);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
//Increment handler counter and test
|
2012-04-23 06:07:13 +00:00
|
|
|
assembler.ADDIU(CMIPS::S0, CMIPS::S0, 0x0001);
|
|
|
|
assembler.ADDIU(CMIPS::T0, CMIPS::R0, MAX_INTCHANDLER - 1);
|
|
|
|
assembler.BNE(CMIPS::S0, CMIPS::T0, checkHandlerLabel);
|
|
|
|
assembler.NOP();
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
//Epilogue
|
2012-04-23 06:07:13 +00:00
|
|
|
assembler.LD(CMIPS::RA, 0x0000, CMIPS::SP);
|
|
|
|
assembler.LD(CMIPS::S0, 0x0008, CMIPS::SP);
|
|
|
|
assembler.LD(CMIPS::S1, 0x0010, CMIPS::SP);
|
|
|
|
assembler.ADDIU(CMIPS::SP, CMIPS::SP, 0x20);
|
|
|
|
assembler.JR(CMIPS::RA);
|
|
|
|
assembler.NOP();
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CPS2OS::AssembleThreadEpilog()
|
|
|
|
{
|
2014-08-30 14:35:52 +09:00
|
|
|
CMIPSAssembler assembler((uint32*)&m_bios[BIOS_ADDRESS_THREADEPILOG - BIOS_ADDRESS_BASE]);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
assembler.ADDIU(CMIPS::V1, CMIPS::R0, 0x23);
|
|
|
|
assembler.SYSCALL();
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CPS2OS::AssembleWaitThreadProc()
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
CMIPSAssembler assembler((uint32*)&m_bios[BIOS_ADDRESS_WAITTHREADPROC - BIOS_ADDRESS_BASE]);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
assembler.ADDIU(CMIPS::V1, CMIPS::R0, 0x666);
|
|
|
|
assembler.SYSCALL();
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
assembler.BEQ(CMIPS::R0, CMIPS::R0, 0xFFFD);
|
|
|
|
assembler.NOP();
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
2015-01-28 03:32:18 -05:00
|
|
|
void CPS2OS::AssembleAlarmHandler()
|
|
|
|
{
|
|
|
|
CMIPSAssembler assembler(reinterpret_cast<uint32*>(&m_bios[BIOS_ADDRESS_ALARMHANDLER - BIOS_ADDRESS_BASE]));
|
|
|
|
|
|
|
|
auto checkHandlerLabel = assembler.CreateLabel();
|
|
|
|
auto moveToNextHandler = assembler.CreateLabel();
|
|
|
|
|
|
|
|
//Prologue
|
|
|
|
//S0 -> Handler Counter
|
|
|
|
|
|
|
|
assembler.ADDIU(CMIPS::SP, CMIPS::SP, 0xFFF0);
|
|
|
|
assembler.SD(CMIPS::RA, 0x0000, CMIPS::SP);
|
|
|
|
assembler.SD(CMIPS::S0, 0x0008, CMIPS::SP);
|
|
|
|
|
|
|
|
//Initialize handler loop
|
|
|
|
assembler.ADDU(CMIPS::S0, CMIPS::R0, CMIPS::R0);
|
|
|
|
|
|
|
|
assembler.MarkLabel(checkHandlerLabel);
|
|
|
|
|
|
|
|
//Get the address to the current INTCHANDLER structure
|
|
|
|
assembler.ADDIU(CMIPS::T0, CMIPS::R0, sizeof(ALARM));
|
|
|
|
assembler.MULTU(CMIPS::T0, CMIPS::S0, CMIPS::T0);
|
|
|
|
assembler.LI(CMIPS::T1, BIOS_ADDRESS_ALARM_BASE);
|
|
|
|
assembler.ADDU(CMIPS::T0, CMIPS::T0, CMIPS::T1);
|
|
|
|
|
|
|
|
//Check validity
|
|
|
|
assembler.LW(CMIPS::T1, offsetof(ALARM, isValid), CMIPS::T0);
|
|
|
|
assembler.BEQ(CMIPS::T1, CMIPS::R0, moveToNextHandler);
|
|
|
|
assembler.NOP();
|
|
|
|
|
|
|
|
//Load the necessary stuff
|
|
|
|
assembler.LW(CMIPS::T1, offsetof(ALARM, callback), CMIPS::T0);
|
|
|
|
assembler.ADDIU(CMIPS::A0, CMIPS::S0, BIOS_ID_BASE);
|
|
|
|
assembler.LW(CMIPS::A1, offsetof(ALARM, delay), CMIPS::T0);
|
|
|
|
assembler.LW(CMIPS::A2, offsetof(ALARM, callbackParam), CMIPS::T0);
|
|
|
|
assembler.LW(CMIPS::GP, offsetof(ALARM, gp), CMIPS::T0);
|
|
|
|
|
|
|
|
//Jump
|
|
|
|
assembler.JALR(CMIPS::T1);
|
|
|
|
assembler.NOP();
|
|
|
|
|
|
|
|
//Delete handler (call iReleaseAlarm)
|
|
|
|
assembler.ADDIU(CMIPS::A0, CMIPS::S0, BIOS_ID_BASE);
|
|
|
|
assembler.ADDIU(CMIPS::V1, CMIPS::R0, -0x1F);
|
|
|
|
assembler.SYSCALL();
|
|
|
|
|
|
|
|
assembler.MarkLabel(moveToNextHandler);
|
|
|
|
|
|
|
|
//Increment handler counter and test
|
|
|
|
assembler.ADDIU(CMIPS::S0, CMIPS::S0, 0x0001);
|
|
|
|
assembler.ADDIU(CMIPS::T0, CMIPS::R0, MAX_ALARM - 1);
|
|
|
|
assembler.BNE(CMIPS::S0, CMIPS::T0, checkHandlerLabel);
|
|
|
|
assembler.NOP();
|
|
|
|
|
|
|
|
//Epilogue
|
|
|
|
assembler.LD(CMIPS::RA, 0x0000, CMIPS::SP);
|
|
|
|
assembler.LD(CMIPS::S0, 0x0008, CMIPS::SP);
|
|
|
|
assembler.ADDIU(CMIPS::SP, CMIPS::SP, 0x10);
|
|
|
|
assembler.JR(CMIPS::RA);
|
|
|
|
assembler.NOP();
|
|
|
|
}
|
|
|
|
|
2008-11-10 01:46:02 +00:00
|
|
|
uint32* CPS2OS::GetCustomSyscallTable()
|
|
|
|
{
|
|
|
|
return (uint32*)&m_ram[0x00010000];
|
|
|
|
}
|
|
|
|
|
2011-05-16 00:04:02 +00:00
|
|
|
uint32 CPS2OS::GetCurrentThreadId() const
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2014-10-12 20:55:28 -04:00
|
|
|
return *reinterpret_cast<uint32*>(m_ram + BIOS_ADDRESS_CURRENT_THREAD_ID);
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
2014-10-12 20:55:28 -04:00
|
|
|
void CPS2OS::SetCurrentThreadId(uint32 threadId)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2014-10-12 20:55:28 -04:00
|
|
|
*reinterpret_cast<uint32*>(m_ram + BIOS_ADDRESS_CURRENT_THREAD_ID) = threadId;
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
uint32 CPS2OS::GetNextAvailableThreadId()
|
|
|
|
{
|
2012-04-14 21:08:33 +00:00
|
|
|
for(uint32 i = 0; i < MAX_THREAD; i++)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2014-08-27 00:10:31 -04:00
|
|
|
THREAD* thread = GetThread(i);
|
2014-08-27 01:07:09 -04:00
|
|
|
if(thread->valid != 1)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0xFFFFFFFF;
|
|
|
|
}
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
CPS2OS::THREAD* CPS2OS::GetThread(uint32 id) const
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
return &((THREAD*)&m_ram[0x00011000])[id];
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CPS2OS::ThreadShakeAndBake()
|
|
|
|
{
|
|
|
|
//Don't play with fire (don't switch if we're in exception mode)
|
2011-11-08 07:59:11 +00:00
|
|
|
if(m_ee.m_State.nCOP0[CCOP_SCU::STATUS] & CMIPS::STATUS_EXL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Don't switch if interrupts are disabled
|
|
|
|
if(!(m_ee.m_State.nCOP0[CCOP_SCU::STATUS] & CMIPS::STATUS_INT))
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
//First of all, revoke the current's thread right to execute itself
|
2012-03-11 20:06:14 +00:00
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
unsigned int id = GetCurrentThreadId();
|
|
|
|
if(id != 0)
|
2012-03-11 20:06:14 +00:00
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
THREAD* thread = GetThread(id);
|
|
|
|
thread->quota--;
|
2012-03-11 20:06:14 +00:00
|
|
|
}
|
|
|
|
}
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
//Check if all quotas expired
|
|
|
|
if(ThreadHasAllQuotasExpired())
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
CRoundRibbon::ITERATOR threadIterator(m_threadSchedule);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2012-03-11 20:06:14 +00:00
|
|
|
//If so, regive a quota to everyone
|
2014-08-27 01:07:09 -04:00
|
|
|
for(threadIterator = m_threadSchedule->Begin(); !threadIterator.IsEnd(); threadIterator++)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
unsigned int id = threadIterator.GetValue();
|
|
|
|
THREAD* thread = GetThread(id);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
thread->quota = THREAD_INIT_QUOTA;
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-11 20:06:14 +00:00
|
|
|
//Select thread to execute
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
unsigned int id = 0;
|
|
|
|
THREAD* thread = nullptr;
|
|
|
|
CRoundRibbon::ITERATOR threadIterator(m_threadSchedule);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2012-03-11 20:06:14 +00:00
|
|
|
//Next, find the next suitable thread to execute
|
2014-08-27 01:07:09 -04:00
|
|
|
for(threadIterator = m_threadSchedule->Begin(); !threadIterator.IsEnd(); threadIterator++)
|
2012-03-11 20:06:14 +00:00
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
id = threadIterator.GetValue();
|
|
|
|
thread = GetThread(id);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
if(thread->status != THREAD_RUNNING) continue;
|
|
|
|
//if(thread->quota == 0) continue;
|
2012-03-11 20:06:14 +00:00
|
|
|
break;
|
|
|
|
}
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
if(threadIterator.IsEnd())
|
2012-03-11 20:06:14 +00:00
|
|
|
{
|
|
|
|
//Deadlock or something here
|
2012-04-23 02:55:30 +00:00
|
|
|
//printf("%s: Warning, no thread to execute.\r\n", LOG_NAME);
|
2014-08-27 01:07:09 -04:00
|
|
|
id = 0;
|
2012-03-11 20:06:14 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//Remove and readd the thread into the queue
|
2014-08-27 01:07:09 -04:00
|
|
|
m_threadSchedule->Remove(thread->scheduleID);
|
|
|
|
thread->scheduleID = m_threadSchedule->Insert(id, thread->priority);
|
2012-03-11 20:06:14 +00:00
|
|
|
}
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
ThreadSwitchContext(id);
|
2012-03-11 20:06:14 +00:00
|
|
|
}
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool CPS2OS::ThreadHasAllQuotasExpired()
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
CRoundRibbon::ITERATOR threadIterator(m_threadSchedule);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
for(threadIterator = m_threadSchedule->Begin(); !threadIterator.IsEnd(); threadIterator++)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
unsigned int id = threadIterator.GetValue();
|
|
|
|
THREAD* thread = GetThread(id);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
if(thread->status != THREAD_RUNNING) continue;
|
|
|
|
if(thread->quota == 0) continue;
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
void CPS2OS::ThreadSwitchContext(unsigned int id)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
if(id == GetCurrentThreadId()) return;
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2012-04-23 02:55:30 +00:00
|
|
|
//Save the context of the current thread
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2015-01-31 23:05:56 -05:00
|
|
|
auto thread = GetThread(GetCurrentThreadId());
|
|
|
|
auto context = reinterpret_cast<THREADCONTEXT*>(GetStructPtr(thread->contextPtr));
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2012-04-23 02:55:30 +00:00
|
|
|
//Save the context
|
|
|
|
for(uint32 i = 0; i < 0x20; i++)
|
|
|
|
{
|
|
|
|
if(i == CMIPS::R0) continue;
|
|
|
|
if(i == CMIPS::K0) continue;
|
|
|
|
if(i == CMIPS::K1) continue;
|
2014-08-27 00:10:31 -04:00
|
|
|
context->gpr[i] = m_ee.m_State.nGPR[i];
|
2012-04-23 02:55:30 +00:00
|
|
|
}
|
2014-08-27 00:10:31 -04:00
|
|
|
context->lo.nV[0] = m_ee.m_State.nLO[0]; context->lo.nV[1] = m_ee.m_State.nLO[1];
|
|
|
|
context->hi.nV[0] = m_ee.m_State.nHI[0]; context->hi.nV[1] = m_ee.m_State.nHI[1];
|
|
|
|
context->lo.nV[2] = m_ee.m_State.nLO1[0]; context->lo.nV[3] = m_ee.m_State.nLO1[1];
|
|
|
|
context->hi.nV[2] = m_ee.m_State.nHI1[0]; context->hi.nV[3] = m_ee.m_State.nHI1[1];
|
2014-08-27 03:37:57 -04:00
|
|
|
context->sa = m_ee.m_State.nSA;
|
|
|
|
for(uint32 i = 0; i < THREADCONTEXT::COP1_REG_COUNT; i++)
|
|
|
|
{
|
2014-09-28 03:09:17 -04:00
|
|
|
context->cop1[i] = m_ee.m_State.nCOP1[i];
|
2014-08-27 03:37:57 -04:00
|
|
|
}
|
|
|
|
for(uint32 i = 0; i < 4; i++)
|
|
|
|
{
|
2014-09-28 03:09:17 -04:00
|
|
|
context->gpr[CMIPS::K0].nV[i] = m_ee.m_State.nCOP1[i + THREADCONTEXT::COP1_REG_COUNT];
|
2014-08-27 03:37:57 -04:00
|
|
|
}
|
|
|
|
context->cop1a = m_ee.m_State.nCOP1A;
|
2014-08-29 22:16:13 +09:00
|
|
|
context->fcsr = m_ee.m_State.nFCSR;
|
2012-04-23 02:55:30 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
thread->epc = m_ee.m_State.nPC;
|
2012-04-23 02:55:30 +00:00
|
|
|
}
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
SetCurrentThreadId(id);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2012-04-23 02:55:30 +00:00
|
|
|
//Load the new context
|
|
|
|
{
|
2015-01-31 23:05:56 -05:00
|
|
|
auto thread = GetThread(GetCurrentThreadId());
|
|
|
|
auto context = reinterpret_cast<THREADCONTEXT*>(GetStructPtr(thread->contextPtr));
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
m_ee.m_State.nPC = thread->epc;
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2012-04-23 02:55:30 +00:00
|
|
|
for(uint32 i = 0; i < 0x20; i++)
|
|
|
|
{
|
|
|
|
if(i == CMIPS::R0) continue;
|
|
|
|
if(i == CMIPS::K0) continue;
|
|
|
|
if(i == CMIPS::K1) continue;
|
2014-08-27 00:10:31 -04:00
|
|
|
m_ee.m_State.nGPR[i] = context->gpr[i];
|
2012-04-23 02:55:30 +00:00
|
|
|
}
|
2014-08-27 00:10:31 -04:00
|
|
|
m_ee.m_State.nLO[0] = context->lo.nV[0]; m_ee.m_State.nLO[1] = context->lo.nV[1];
|
|
|
|
m_ee.m_State.nHI[0] = context->hi.nV[0]; m_ee.m_State.nHI[1] = context->hi.nV[1];
|
|
|
|
m_ee.m_State.nLO1[0] = context->lo.nV[2]; m_ee.m_State.nLO1[1] = context->lo.nV[3];
|
|
|
|
m_ee.m_State.nHI1[0] = context->hi.nV[2]; m_ee.m_State.nHI1[1] = context->hi.nV[3];
|
2014-08-27 03:37:57 -04:00
|
|
|
m_ee.m_State.nSA = context->sa;
|
|
|
|
for(uint32 i = 0; i < THREADCONTEXT::COP1_REG_COUNT; i++)
|
|
|
|
{
|
2014-09-28 03:09:17 -04:00
|
|
|
m_ee.m_State.nCOP1[i] = context->cop1[i];
|
2014-08-27 03:37:57 -04:00
|
|
|
}
|
|
|
|
for(uint32 i = 0; i < 4; i++)
|
|
|
|
{
|
2014-09-28 03:09:17 -04:00
|
|
|
m_ee.m_State.nCOP1[i + THREADCONTEXT::COP1_REG_COUNT] = context->gpr[CMIPS::K0].nV[i];
|
2014-08-27 03:37:57 -04:00
|
|
|
}
|
|
|
|
m_ee.m_State.nCOP1A = context->cop1a;
|
2014-08-29 22:16:13 +09:00
|
|
|
m_ee.m_State.nFCSR = context->fcsr;
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
CLog::GetInstance().Print(LOG_NAME, "New thread elected (id = %i).\r\n", id);
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CPS2OS::CreateWaitThread()
|
|
|
|
{
|
2014-08-27 00:10:31 -04:00
|
|
|
THREAD* thread = GetThread(0);
|
2014-08-27 01:07:09 -04:00
|
|
|
thread->valid = 1;
|
|
|
|
thread->epc = BIOS_ADDRESS_WAITTHREADPROC;
|
|
|
|
thread->status = THREAD_ZOMBIE;
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
2015-01-31 23:05:56 -05:00
|
|
|
uint8* CPS2OS::GetStructPtr(uint32 address) const
|
|
|
|
{
|
|
|
|
uint8* memory = nullptr;
|
|
|
|
if(address >= 0x70000000)
|
|
|
|
{
|
|
|
|
address &= (PS2::EE_SPR_SIZE - 1);
|
|
|
|
memory = m_spr;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
address &= (PS2::EE_RAM_SIZE - 1);
|
|
|
|
memory = m_ram;
|
|
|
|
}
|
|
|
|
return memory + address;
|
|
|
|
}
|
|
|
|
|
2008-11-10 01:46:02 +00:00
|
|
|
uint32 CPS2OS::GetNextAvailableIntcHandlerId()
|
|
|
|
{
|
2012-04-23 02:55:30 +00:00
|
|
|
for(uint32 i = 1; i < MAX_INTCHANDLER; i++)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
INTCHANDLER* handler = GetIntcHandler(i);
|
|
|
|
if(handler->valid != 1)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0xFFFFFFFF;
|
|
|
|
}
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
CPS2OS::INTCHANDLER* CPS2OS::GetIntcHandler(uint32 id)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
id--;
|
|
|
|
return &((INTCHANDLER*)&m_ram[0x0000A000])[id];
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
uint32 CPS2OS::GetNextAvailableDeci2HandlerId()
|
|
|
|
{
|
2012-04-23 02:55:30 +00:00
|
|
|
for(uint32 i = 1; i < MAX_DECI2HANDLER; i++)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
DECI2HANDLER* handler = GetDeci2Handler(i);
|
|
|
|
if(handler->valid != 1)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0xFFFFFFFF;
|
|
|
|
}
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
CPS2OS::DECI2HANDLER* CPS2OS::GetDeci2Handler(uint32 id)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
id--;
|
|
|
|
return &((DECI2HANDLER*)&m_ram[0x00008000])[id];
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
2014-06-04 23:37:40 -04:00
|
|
|
void CPS2OS::HandleInterrupt()
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2011-05-08 21:58:55 +00:00
|
|
|
m_semaWaitCount = 0;
|
2008-11-10 01:46:02 +00:00
|
|
|
m_ee.GenerateInterrupt(0x1FC00200);
|
|
|
|
}
|
|
|
|
|
2014-06-04 23:37:40 -04:00
|
|
|
void CPS2OS::HandleReturnFromException()
|
|
|
|
{
|
|
|
|
ThreadShakeAndBake();
|
|
|
|
}
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
uint32 CPS2OS::TranslateAddress(CMIPS*, uint32 vaddrLo)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
if(vaddrLo >= 0x70000000 && vaddrLo <= 0x70003FFF)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
return (vaddrLo - 0x6E000000);
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
2014-08-27 01:07:09 -04:00
|
|
|
if(vaddrLo >= 0x30100000 && vaddrLo <= 0x31FFFFFF)
|
2012-03-11 20:06:14 +00:00
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
return (vaddrLo - 0x30000000);
|
2012-03-11 20:06:14 +00:00
|
|
|
}
|
2014-08-27 01:07:09 -04:00
|
|
|
return vaddrLo & 0x1FFFFFFF;
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////
|
|
|
|
//System Calls
|
|
|
|
//////////////////////////////////////////////////
|
|
|
|
|
|
|
|
void CPS2OS::sc_Unhandled()
|
|
|
|
{
|
2015-01-20 01:02:04 -05:00
|
|
|
CLog::GetInstance().Print(LOG_NAME, "Unknown system call (0x%X) called from 0x%0.8X.\r\n", m_ee.m_State.nGPR[3].nV[0], m_ee.m_State.nPC);
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//02
|
|
|
|
void CPS2OS::sc_GsSetCrt()
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
bool isInterlaced = (m_ee.m_State.nGPR[SC_PARAM0].nV[0] != 0);
|
|
|
|
unsigned int mode = m_ee.m_State.nGPR[SC_PARAM1].nV[0];
|
|
|
|
bool isFrameMode = (m_ee.m_State.nGPR[SC_PARAM2].nV[0] != 0);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
if(m_gs != NULL)
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
m_gs->SetCrt(isInterlaced, mode, isFrameMode);
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-04-14 21:08:33 +00:00
|
|
|
//06
|
|
|
|
void CPS2OS::sc_LoadExecPS2()
|
|
|
|
{
|
|
|
|
uint32 fileNamePtr = m_ee.m_State.nGPR[SC_PARAM0].nV[0];
|
|
|
|
uint32 argCount = m_ee.m_State.nGPR[SC_PARAM1].nV[0];
|
|
|
|
uint32 argValuesPtr = m_ee.m_State.nGPR[SC_PARAM2].nV[0];
|
|
|
|
|
|
|
|
ArgumentList arguments;
|
|
|
|
for(uint32 i = 0; i < argCount; i++)
|
|
|
|
{
|
|
|
|
uint32 argValuePtr = *reinterpret_cast<uint32*>(m_ram + argValuesPtr + i * 4);
|
|
|
|
arguments.push_back(reinterpret_cast<const char*>(m_ram + argValuePtr));
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string fileName = reinterpret_cast<const char*>(m_ram + fileNamePtr);
|
|
|
|
OnRequestLoadExecutable(fileName.c_str(), arguments);
|
|
|
|
}
|
|
|
|
|
2008-11-10 01:46:02 +00:00
|
|
|
//10
|
|
|
|
void CPS2OS::sc_AddIntcHandler()
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
uint32 cause = m_ee.m_State.nGPR[SC_PARAM0].nV[0];
|
|
|
|
uint32 address = m_ee.m_State.nGPR[SC_PARAM1].nV[0];
|
|
|
|
uint32 next = m_ee.m_State.nGPR[SC_PARAM2].nV[0];
|
|
|
|
uint32 arg = m_ee.m_State.nGPR[SC_PARAM3].nV[0];
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
/*
|
2014-08-27 01:07:09 -04:00
|
|
|
if(next != 0)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
|
|
|
assert(0);
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
uint32 id = GetNextAvailableIntcHandlerId();
|
|
|
|
if(id == 0xFFFFFFFF)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[0] = 0xFFFFFFFF;
|
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[1] = 0xFFFFFFFF;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
INTCHANDLER* handler = GetIntcHandler(id);
|
|
|
|
handler->valid = 1;
|
|
|
|
handler->address = address;
|
|
|
|
handler->cause = cause;
|
|
|
|
handler->arg = arg;
|
|
|
|
handler->gp = m_ee.m_State.nGPR[CMIPS::GP].nV[0];
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[0] = id;
|
2008-11-10 01:46:02 +00:00
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[1] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//11
|
|
|
|
void CPS2OS::sc_RemoveIntcHandler()
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
uint32 cause = m_ee.m_State.nGPR[SC_PARAM0].nV[0];
|
|
|
|
uint32 id = m_ee.m_State.nGPR[SC_PARAM1].nV[0];
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
INTCHANDLER* handler = GetIntcHandler(id);
|
|
|
|
if(handler->valid != 1)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[0] = 0xFFFFFFFF;
|
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[1] = 0xFFFFFFFF;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
handler->valid = 0;
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[0] = 0;
|
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[1] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//12
|
|
|
|
void CPS2OS::sc_AddDmacHandler()
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
uint32 channel = m_ee.m_State.nGPR[SC_PARAM0].nV[0];
|
|
|
|
uint32 address = m_ee.m_State.nGPR[SC_PARAM1].nV[0];
|
|
|
|
uint32 next = m_ee.m_State.nGPR[SC_PARAM2].nV[0];
|
|
|
|
uint32 arg = m_ee.m_State.nGPR[SC_PARAM3].nV[0];
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
//The Next parameter indicates at which moment we'd want our DMAC handler to be called.
|
|
|
|
//-1 -> At the end
|
|
|
|
//0 -> At the start
|
|
|
|
//n -> After handler 'n'
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
if(next != 0)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
|
|
|
assert(0);
|
|
|
|
}
|
|
|
|
|
2015-01-29 01:36:29 -05:00
|
|
|
uint32 id = m_dmacHandlers.Allocate();
|
2014-08-27 01:07:09 -04:00
|
|
|
if(id == 0xFFFFFFFF)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2015-01-29 01:36:29 -05:00
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nD0 = -1;
|
2008-11-10 01:46:02 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-01-29 01:36:29 -05:00
|
|
|
auto handler = m_dmacHandlers[id];
|
2014-08-27 01:07:09 -04:00
|
|
|
handler->address = address;
|
|
|
|
handler->channel = channel;
|
|
|
|
handler->arg = arg;
|
|
|
|
handler->gp = m_ee.m_State.nGPR[CMIPS::GP].nV[0];
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2015-01-29 01:36:29 -05:00
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nD0 = id;
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//13
|
|
|
|
void CPS2OS::sc_RemoveDmacHandler()
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
uint32 channel = m_ee.m_State.nGPR[SC_PARAM0].nV[0];
|
|
|
|
uint32 id = m_ee.m_State.nGPR[SC_PARAM1].nV[0];
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2015-01-29 01:36:29 -05:00
|
|
|
auto handler = m_dmacHandlers[id];
|
|
|
|
if(handler == nullptr)
|
|
|
|
{
|
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nD0 = -1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_dmacHandlers.Free(id);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2015-01-29 01:36:29 -05:00
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nD0 = 0;
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//14
|
|
|
|
void CPS2OS::sc_EnableIntc()
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
uint32 cause = m_ee.m_State.nGPR[SC_PARAM0].nV[0];
|
|
|
|
uint32 mask = 1 << cause;
|
2015-02-07 21:50:27 -05:00
|
|
|
bool changed = false;
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
if(!(m_ee.m_pMemoryMap->GetWord(CINTC::INTC_MASK) & mask))
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
m_ee.m_pMemoryMap->SetWord(CINTC::INTC_MASK, mask);
|
2015-02-07 21:50:27 -05:00
|
|
|
changed = true;
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
2015-02-07 21:50:27 -05:00
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nD0 = changed ? 1 : 0;
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//15
|
|
|
|
void CPS2OS::sc_DisableIntc()
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
uint32 cause = m_ee.m_State.nGPR[SC_PARAM0].nV[0];
|
|
|
|
uint32 mask = 1 << cause;
|
2015-02-07 21:50:27 -05:00
|
|
|
bool changed = false;
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
if(m_ee.m_pMemoryMap->GetWord(CINTC::INTC_MASK) & mask)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
m_ee.m_pMemoryMap->SetWord(CINTC::INTC_MASK, mask);
|
2015-02-07 21:50:27 -05:00
|
|
|
changed = true;
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
2015-02-07 21:50:27 -05:00
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nD0 = changed ? 1 : 0;
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//16
|
|
|
|
void CPS2OS::sc_EnableDmac()
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
uint32 channel = m_ee.m_State.nGPR[SC_PARAM0].nV[0];
|
|
|
|
uint32 registerId = 0x10000 << channel;
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
if(!(m_ee.m_pMemoryMap->GetWord(CDMAC::D_STAT) & registerId))
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
m_ee.m_pMemoryMap->SetWord(CDMAC::D_STAT, registerId);
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//Enable INT1
|
|
|
|
if(!(m_ee.m_pMemoryMap->GetWord(CINTC::INTC_MASK) & 0x02))
|
|
|
|
{
|
|
|
|
m_ee.m_pMemoryMap->SetWord(CINTC::INTC_MASK, 0x02);
|
|
|
|
}
|
|
|
|
|
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[0] = 1;
|
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[1] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//17
|
|
|
|
void CPS2OS::sc_DisableDmac()
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
uint32 channel = m_ee.m_State.nGPR[SC_PARAM0].nV[0];
|
|
|
|
uint32 registerId = 0x10000 << channel;
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
if(m_ee.m_pMemoryMap->GetWord(CDMAC::D_STAT) & registerId)
|
2012-03-11 20:06:14 +00:00
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
m_ee.m_pMemoryMap->SetWord(CDMAC::D_STAT, registerId);
|
2012-06-28 06:03:14 +00:00
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nD0 = 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nD0 = 0;
|
2012-03-11 20:06:14 +00:00
|
|
|
}
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
2015-01-28 03:32:18 -05:00
|
|
|
//18
|
|
|
|
void CPS2OS::sc_SetAlarm()
|
|
|
|
{
|
|
|
|
uint32 delay = m_ee.m_State.nGPR[SC_PARAM0].nV[0];
|
|
|
|
uint32 callback = m_ee.m_State.nGPR[SC_PARAM1].nV[0];
|
|
|
|
uint32 callbackParam = m_ee.m_State.nGPR[SC_PARAM2].nV[0];
|
|
|
|
|
|
|
|
auto alarmId = m_alarms.Allocate();
|
|
|
|
assert(alarmId != -1);
|
|
|
|
if(alarmId == -1)
|
|
|
|
{
|
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nD0 = -1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto alarm = m_alarms[alarmId];
|
|
|
|
alarm->delay = delay;
|
|
|
|
alarm->callback = callback;
|
|
|
|
alarm->callbackParam = callbackParam;
|
|
|
|
alarm->gp = m_ee.m_State.nGPR[CMIPS::GP].nV0;
|
|
|
|
|
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nD0 = alarmId;
|
|
|
|
}
|
|
|
|
|
|
|
|
//1F
|
|
|
|
void CPS2OS::sc_ReleaseAlarm()
|
|
|
|
{
|
|
|
|
uint32 alarmId = m_ee.m_State.nGPR[SC_PARAM0].nV[0];
|
|
|
|
|
|
|
|
auto alarm = m_alarms[alarmId];
|
|
|
|
if(alarm == nullptr)
|
|
|
|
{
|
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nD0 = -1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_alarms.Free(alarmId);
|
|
|
|
}
|
|
|
|
|
2008-11-10 01:46:02 +00:00
|
|
|
//20
|
|
|
|
void CPS2OS::sc_CreateThread()
|
|
|
|
{
|
2015-01-31 23:05:56 -05:00
|
|
|
auto threadParam = reinterpret_cast<THREADPARAM*>(GetStructPtr(m_ee.m_State.nGPR[SC_PARAM0].nV0));
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
uint32 id = GetNextAvailableThreadId();
|
|
|
|
if(id == 0xFFFFFFFF)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[0] = id;
|
2008-11-10 01:46:02 +00:00
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[1] = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-08-30 13:47:38 +09:00
|
|
|
auto thread = GetThread(GetCurrentThreadId());
|
2014-08-27 01:07:09 -04:00
|
|
|
uint32 heapBase = thread->heapBase;
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
assert(threadParam->priority < 128);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
thread = GetThread(id);
|
|
|
|
thread->valid = 1;
|
|
|
|
thread->status = THREAD_ZOMBIE;
|
|
|
|
thread->stackBase = threadParam->stackBase;
|
|
|
|
thread->epc = threadParam->threadProc;
|
2014-08-30 14:51:35 +09:00
|
|
|
thread->threadProc = threadParam->threadProc;
|
2014-08-27 01:07:09 -04:00
|
|
|
thread->priority = threadParam->priority;
|
|
|
|
thread->heapBase = heapBase;
|
|
|
|
thread->wakeUpCount = 0;
|
|
|
|
thread->quota = THREAD_INIT_QUOTA;
|
|
|
|
thread->scheduleID = m_threadSchedule->Insert(id, threadParam->priority);
|
|
|
|
thread->stackSize = threadParam->stackSize;
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
uint32 stackAddr = threadParam->stackBase + threadParam->stackSize - STACKRES;
|
|
|
|
thread->contextPtr = stackAddr;
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
assert(sizeof(THREADCONTEXT) == STACKRES);
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
THREADCONTEXT* context = reinterpret_cast<THREADCONTEXT*>(&m_ram[thread->contextPtr]);
|
2014-08-27 00:10:31 -04:00
|
|
|
memset(context, 0, sizeof(THREADCONTEXT));
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
context->gpr[CMIPS::SP].nV0 = stackAddr;
|
|
|
|
context->gpr[CMIPS::FP].nV0 = stackAddr;
|
|
|
|
context->gpr[CMIPS::GP].nV0 = threadParam->gp;
|
2014-08-30 14:35:52 +09:00
|
|
|
context->gpr[CMIPS::RA].nV0 = BIOS_ADDRESS_THREADEPILOG;
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[0] = id;
|
2008-11-10 01:46:02 +00:00
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[1] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//21
|
|
|
|
void CPS2OS::sc_DeleteThread()
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
uint32 id = m_ee.m_State.nGPR[SC_PARAM0].nV[0];
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
THREAD* thread = GetThread(id);
|
|
|
|
if(!thread->valid)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[0] = 0xFFFFFFFF;
|
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[1] = 0xFFFFFFFF;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
m_threadSchedule->Remove(thread->scheduleID);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
thread->valid = 0;
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[0] = 0;
|
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[1] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//22
|
|
|
|
void CPS2OS::sc_StartThread()
|
|
|
|
{
|
2014-08-27 00:10:31 -04:00
|
|
|
uint32 id = m_ee.m_State.nGPR[SC_PARAM0].nV[0];
|
|
|
|
uint32 arg = m_ee.m_State.nGPR[SC_PARAM1].nV[0];
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 00:10:31 -04:00
|
|
|
THREAD* thread = GetThread(id);
|
2014-08-27 01:07:09 -04:00
|
|
|
if(!thread->valid)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[0] = 0xFFFFFFFF;
|
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[1] = 0xFFFFFFFF;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
assert(thread->status == THREAD_ZOMBIE);
|
|
|
|
thread->status = THREAD_RUNNING;
|
2014-08-30 14:51:35 +09:00
|
|
|
thread->epc = thread->threadProc;
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
THREADCONTEXT* context = reinterpret_cast<THREADCONTEXT*>(&m_ram[thread->contextPtr]);
|
2014-08-27 00:10:31 -04:00
|
|
|
context->gpr[CMIPS::A0].nV0 = arg;
|
2014-08-30 14:51:35 +09:00
|
|
|
context->gpr[CMIPS::RA].nV0 = BIOS_ADDRESS_THREADEPILOG;
|
|
|
|
context->gpr[CMIPS::SP].nV0 = thread->contextPtr;
|
|
|
|
context->gpr[CMIPS::FP].nV0 = thread->contextPtr;
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 00:10:31 -04:00
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[0] = id;
|
2008-11-10 01:46:02 +00:00
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[1] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//23
|
|
|
|
void CPS2OS::sc_ExitThread()
|
|
|
|
{
|
2014-08-27 00:10:31 -04:00
|
|
|
THREAD* thread = GetThread(GetCurrentThreadId());
|
2014-08-27 01:07:09 -04:00
|
|
|
thread->status = THREAD_ZOMBIE;
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
ThreadShakeAndBake();
|
|
|
|
}
|
|
|
|
|
|
|
|
//25
|
|
|
|
void CPS2OS::sc_TerminateThread()
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
uint32 id = m_ee.m_State.nGPR[SC_PARAM0].nV[0];
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
THREAD* thread = GetThread(id);
|
|
|
|
if(!thread->valid)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[0] = 0xFFFFFFFF;
|
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[1] = 0xFFFFFFFF;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
thread->status = THREAD_ZOMBIE;
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[0] = 0;
|
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[1] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//29
|
2011-11-08 07:59:11 +00:00
|
|
|
//2A
|
2008-11-10 01:46:02 +00:00
|
|
|
void CPS2OS::sc_ChangeThreadPriority()
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
bool isInt = m_ee.m_State.nGPR[3].nV[0] == 0x2A;
|
|
|
|
uint32 id = m_ee.m_State.nGPR[SC_PARAM0].nV[0];
|
|
|
|
uint32 prio = m_ee.m_State.nGPR[SC_PARAM1].nV[0];
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
THREAD* thread = GetThread(id);
|
|
|
|
if(!thread->valid)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[0] = 0xFFFFFFFF;
|
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[1] = 0xFFFFFFFF;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
uint32 prevPrio = thread->priority;
|
|
|
|
thread->priority = prio;
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[0] = prevPrio;
|
2008-11-10 01:46:02 +00:00
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[1] = 0;
|
|
|
|
|
|
|
|
//Reschedule?
|
2014-08-27 01:07:09 -04:00
|
|
|
m_threadSchedule->Remove(thread->scheduleID);
|
|
|
|
thread->scheduleID = m_threadSchedule->Insert(id, thread->priority);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
if(!isInt)
|
2011-11-08 07:59:11 +00:00
|
|
|
{
|
|
|
|
ThreadShakeAndBake();
|
|
|
|
}
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//2B
|
|
|
|
void CPS2OS::sc_RotateThreadReadyQueue()
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
CRoundRibbon::ITERATOR threadIterator(m_threadSchedule);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
uint32 prio = m_ee.m_State.nGPR[SC_PARAM0].nV[0];
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
//TODO: Rescheduling isn't always necessary and will cause the current thread's priority queue to be
|
|
|
|
//rotated too since each time a thread is picked to be executed it's placed at the end of the queue...
|
|
|
|
|
|
|
|
//Find first of this priority and reinsert if it's the same as the current thread
|
|
|
|
//If it's not the same, the schedule will be rotated when another thread is choosen
|
2014-08-27 01:07:09 -04:00
|
|
|
for(threadIterator = m_threadSchedule->Begin(); !threadIterator.IsEnd(); threadIterator++)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
if(threadIterator.GetWeight() == prio)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
uint32 id = threadIterator.GetValue();
|
|
|
|
if(id == GetCurrentThreadId())
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2011-07-04 03:12:07 +00:00
|
|
|
throw std::runtime_error("Need to reverify that.");
|
2014-08-27 01:07:09 -04:00
|
|
|
THREAD* thread(GetThread(id));
|
|
|
|
m_threadSchedule->Remove(threadIterator.GetIndex());
|
|
|
|
thread->scheduleID = m_threadSchedule->Insert(id, prio);
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[0] = prio;
|
2008-11-10 01:46:02 +00:00
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[1] = 0;
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
if(!threadIterator.IsEnd())
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
|
|
|
//Change has been made
|
|
|
|
ThreadShakeAndBake();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//2F
|
|
|
|
void CPS2OS::sc_GetThreadId()
|
|
|
|
{
|
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[0] = GetCurrentThreadId();
|
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[1] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//30
|
|
|
|
void CPS2OS::sc_ReferThreadStatus()
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
uint32 id = m_ee.m_State.nGPR[SC_PARAM0].nV[0];
|
|
|
|
uint32 statusPtr = m_ee.m_State.nGPR[SC_PARAM1].nV[0];
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
THREAD* thread = GetThread(id);
|
|
|
|
if(!thread->valid)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[0] = 0xFFFFFFFF;
|
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[1] = 0xFFFFFFFF;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-07-04 03:12:07 +00:00
|
|
|
//THS_RUN = 0x01, THS_READY = 0x02, THS_WAIT = 0x04, THS_SUSPEND = 0x08, THS_DORMANT = 0x10
|
2014-08-27 01:07:09 -04:00
|
|
|
uint32 ret = 0;
|
|
|
|
switch(thread->status)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
|
|
|
case THREAD_RUNNING:
|
2014-08-27 01:07:09 -04:00
|
|
|
ret = 0x01;
|
2008-11-10 01:46:02 +00:00
|
|
|
break;
|
|
|
|
case THREAD_WAITING:
|
2012-06-28 06:03:14 +00:00
|
|
|
case THREAD_SLEEPING:
|
2014-08-27 01:07:09 -04:00
|
|
|
ret = 0x04;
|
2008-11-10 01:46:02 +00:00
|
|
|
break;
|
|
|
|
case THREAD_SUSPENDED:
|
2014-08-27 01:07:09 -04:00
|
|
|
ret = 0x08;
|
2011-07-16 04:39:52 +00:00
|
|
|
break;
|
2012-06-28 06:03:14 +00:00
|
|
|
case THREAD_SUSPENDED_WAITING:
|
|
|
|
case THREAD_SUSPENDED_SLEEPING:
|
2014-08-27 01:07:09 -04:00
|
|
|
ret = 0x0C;
|
2012-06-28 06:03:14 +00:00
|
|
|
break;
|
2011-07-16 04:39:52 +00:00
|
|
|
case THREAD_ZOMBIE:
|
2014-08-27 01:07:09 -04:00
|
|
|
ret = 0x10;
|
2008-11-10 01:46:02 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
if(statusPtr != 0)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2015-01-31 23:05:56 -05:00
|
|
|
auto threadParam = reinterpret_cast<THREADPARAM*>(GetStructPtr(statusPtr));
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
threadParam->status = ret;
|
|
|
|
threadParam->priority = thread->priority;
|
|
|
|
threadParam->currentPriority = thread->priority;
|
|
|
|
threadParam->stackBase = thread->stackBase;
|
|
|
|
threadParam->stackSize = thread->stackSize;
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[0] = ret;
|
2008-11-10 01:46:02 +00:00
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[1] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//32
|
|
|
|
void CPS2OS::sc_SleepThread()
|
|
|
|
{
|
2014-08-27 00:10:31 -04:00
|
|
|
THREAD* thread = GetThread(GetCurrentThreadId());
|
2014-08-27 01:07:09 -04:00
|
|
|
if(thread->wakeUpCount == 0)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
assert(thread->status == THREAD_RUNNING);
|
|
|
|
thread->status = THREAD_SLEEPING;
|
2008-11-10 01:46:02 +00:00
|
|
|
ThreadShakeAndBake();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
thread->wakeUpCount--;
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//33
|
|
|
|
//34
|
|
|
|
void CPS2OS::sc_WakeupThread()
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
uint32 id = m_ee.m_State.nGPR[SC_PARAM0].nV[0];
|
|
|
|
bool isInt = m_ee.m_State.nGPR[3].nV[0] == 0x34;
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
THREAD* thread = GetThread(id);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2012-06-28 06:03:14 +00:00
|
|
|
if(
|
2014-08-27 01:07:09 -04:00
|
|
|
(thread->status == THREAD_SLEEPING) ||
|
|
|
|
(thread->status == THREAD_SUSPENDED_SLEEPING))
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
switch(thread->status)
|
2012-06-28 06:03:14 +00:00
|
|
|
{
|
|
|
|
case THREAD_SLEEPING:
|
2014-08-27 01:07:09 -04:00
|
|
|
thread->status = THREAD_RUNNING;
|
2012-06-28 06:03:14 +00:00
|
|
|
break;
|
|
|
|
case THREAD_SUSPENDED_SLEEPING:
|
2014-08-27 01:07:09 -04:00
|
|
|
thread->status = THREAD_SUSPENDED;
|
2012-06-28 06:03:14 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
assert(0);
|
|
|
|
break;
|
|
|
|
}
|
2014-10-12 20:06:30 -04:00
|
|
|
if(!isInt)
|
|
|
|
{
|
|
|
|
ThreadShakeAndBake();
|
|
|
|
}
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
thread->wakeUpCount++;
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-29 01:27:13 -04:00
|
|
|
//35
|
|
|
|
//36
|
|
|
|
void CPS2OS::sc_CancelWakeupThread()
|
|
|
|
{
|
|
|
|
uint32 id = m_ee.m_State.nGPR[SC_PARAM0].nV[0];
|
|
|
|
bool isInt = m_ee.m_State.nGPR[3].nV[0] == 0x36;
|
|
|
|
|
|
|
|
auto thread = GetThread(id);
|
|
|
|
if(!thread->valid)
|
|
|
|
{
|
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nD0 = ~0ULL;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32 wakeUpCount = thread->wakeUpCount;
|
|
|
|
thread->wakeUpCount = 0;
|
|
|
|
|
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nD0 = wakeUpCount;
|
|
|
|
}
|
|
|
|
|
2012-06-28 06:03:14 +00:00
|
|
|
//37
|
|
|
|
void CPS2OS::sc_SuspendThread()
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
uint32 id = m_ee.m_State.nGPR[SC_PARAM0].nV[0];
|
2012-06-28 06:03:14 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
THREAD* thread = GetThread(id);
|
|
|
|
if(!thread->valid)
|
2012-06-28 06:03:14 +00:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
switch(thread->status)
|
2012-06-28 06:03:14 +00:00
|
|
|
{
|
|
|
|
case THREAD_RUNNING:
|
2014-08-27 01:07:09 -04:00
|
|
|
thread->status = THREAD_SUSPENDED;
|
2012-06-28 06:03:14 +00:00
|
|
|
break;
|
|
|
|
case THREAD_WAITING:
|
2014-08-27 01:07:09 -04:00
|
|
|
thread->status = THREAD_SUSPENDED_WAITING;
|
2012-06-28 06:03:14 +00:00
|
|
|
break;
|
|
|
|
case THREAD_SLEEPING:
|
2014-08-27 01:07:09 -04:00
|
|
|
thread->status = THREAD_SUSPENDED_SLEEPING;
|
2012-06-28 06:03:14 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
assert(0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
ThreadShakeAndBake();
|
|
|
|
}
|
|
|
|
|
|
|
|
//39
|
|
|
|
void CPS2OS::sc_ResumeThread()
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
uint32 id = m_ee.m_State.nGPR[SC_PARAM0].nV[0];
|
2012-06-28 06:03:14 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
THREAD* thread = GetThread(id);
|
|
|
|
if(!thread->valid)
|
2012-06-28 06:03:14 +00:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
switch(thread->status)
|
2012-06-28 06:03:14 +00:00
|
|
|
{
|
|
|
|
case THREAD_SUSPENDED:
|
2014-08-27 01:07:09 -04:00
|
|
|
thread->status = THREAD_RUNNING;
|
2012-06-28 06:03:14 +00:00
|
|
|
break;
|
|
|
|
case THREAD_SUSPENDED_WAITING:
|
2014-08-27 01:07:09 -04:00
|
|
|
thread->status = THREAD_WAITING;
|
2012-06-28 06:03:14 +00:00
|
|
|
break;
|
|
|
|
case THREAD_SUSPENDED_SLEEPING:
|
2014-08-27 01:07:09 -04:00
|
|
|
thread->status = THREAD_SLEEPING;
|
2012-06-28 06:03:14 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
assert(0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
ThreadShakeAndBake();
|
|
|
|
}
|
|
|
|
|
2008-11-10 01:46:02 +00:00
|
|
|
//3C
|
2012-04-14 21:08:33 +00:00
|
|
|
void CPS2OS::sc_SetupThread()
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
uint32 stackBase = m_ee.m_State.nGPR[SC_PARAM1].nV[0];
|
|
|
|
uint32 stackSize = m_ee.m_State.nGPR[SC_PARAM2].nV[0];
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
uint32 stackAddr = 0;
|
|
|
|
if(stackBase == 0xFFFFFFFF)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
stackAddr = 0x02000000;
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
stackAddr = stackBase + stackSize;
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
2012-04-14 21:08:33 +00:00
|
|
|
uint32 argsBase = m_ee.m_State.nGPR[SC_PARAM3].nV[0];
|
|
|
|
//Copy arguments
|
|
|
|
{
|
|
|
|
ArgumentList completeArgList;
|
|
|
|
completeArgList.push_back(m_executableName);
|
|
|
|
completeArgList.insert(completeArgList.end(), m_currentArguments.begin(), m_currentArguments.end());
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2012-04-23 02:55:30 +00:00
|
|
|
uint32 argsCount = static_cast<uint32>(completeArgList.size());
|
2012-04-14 21:08:33 +00:00
|
|
|
|
|
|
|
*reinterpret_cast<uint32*>(m_ram + argsBase) = argsCount;
|
|
|
|
uint32 argsPtrs = argsBase + 4;
|
2014-10-02 02:43:38 -04:00
|
|
|
//We add 1 to argsCount because argv[argc] must be equal to 0
|
|
|
|
uint32 argsPayload = argsPtrs + ((argsCount + 1) * 4);
|
2012-04-14 21:08:33 +00:00
|
|
|
for(uint32 i = 0; i < argsCount; i++)
|
|
|
|
{
|
|
|
|
const auto& currentArg = completeArgList[i];
|
|
|
|
*reinterpret_cast<uint32*>(m_ram + argsPtrs + (i * 4)) = argsPayload;
|
2012-04-23 02:55:30 +00:00
|
|
|
uint32 argSize = static_cast<uint32>(currentArg.size()) + 1;
|
2012-04-14 21:08:33 +00:00
|
|
|
memcpy(m_ram + argsPayload, currentArg.c_str(), argSize);
|
|
|
|
argsPayload += argSize;
|
|
|
|
}
|
2014-10-02 02:43:38 -04:00
|
|
|
//Set argv[argc] to 0
|
|
|
|
*reinterpret_cast<uint32*>(m_ram + argsPtrs + (argsCount * 4)) = 0;
|
2012-04-14 21:08:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//Set up the main thread
|
2014-08-27 00:10:31 -04:00
|
|
|
THREAD* thread = GetThread(1);
|
2014-08-27 01:07:09 -04:00
|
|
|
thread->valid = 0x01;
|
|
|
|
thread->status = THREAD_RUNNING;
|
|
|
|
thread->stackBase = stackAddr - stackSize;
|
|
|
|
thread->priority = 0;
|
|
|
|
thread->quota = THREAD_INIT_QUOTA;
|
|
|
|
thread->scheduleID = m_threadSchedule->Insert(1, thread->priority);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
stackAddr -= STACKRES;
|
|
|
|
thread->contextPtr = stackAddr;
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
SetCurrentThreadId(1);
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[0] = stackAddr;
|
2008-11-10 01:46:02 +00:00
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[1] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//3D
|
2012-04-14 21:08:33 +00:00
|
|
|
void CPS2OS::sc_SetupHeap()
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2014-08-27 00:10:31 -04:00
|
|
|
THREAD* thread = GetThread(GetCurrentThreadId());
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
uint32 heapBase = m_ee.m_State.nGPR[SC_PARAM0].nV[0];
|
|
|
|
uint32 heapSize = m_ee.m_State.nGPR[SC_PARAM1].nV[0];
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
if(heapSize == 0xFFFFFFFF)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
thread->heapBase = thread->stackBase;
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
thread->heapBase = heapBase + heapSize;
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[0] = thread->heapBase;
|
2008-11-10 01:46:02 +00:00
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[1] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//3E
|
|
|
|
void CPS2OS::sc_EndOfHeap()
|
|
|
|
{
|
2014-08-27 00:10:31 -04:00
|
|
|
THREAD* thread = GetThread(GetCurrentThreadId());
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[0] = thread->heapBase;
|
2008-11-10 01:46:02 +00:00
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[1] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//40
|
|
|
|
void CPS2OS::sc_CreateSema()
|
|
|
|
{
|
2015-01-31 23:05:56 -05:00
|
|
|
auto semaParam = reinterpret_cast<SEMAPHOREPARAM*>(GetStructPtr(m_ee.m_State.nGPR[SC_PARAM0].nV0));
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2015-01-31 01:40:42 -05:00
|
|
|
uint32 id = m_semaphores.Allocate();
|
2014-08-27 01:07:09 -04:00
|
|
|
if(id == 0xFFFFFFFF)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2015-01-31 01:40:42 -05:00
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nD0 = -1;
|
2008-11-10 01:46:02 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-01-31 01:40:42 -05:00
|
|
|
auto sema = m_semaphores[id];
|
2014-08-27 01:07:09 -04:00
|
|
|
sema->count = semaParam->initCount;
|
|
|
|
sema->maxCount = semaParam->maxCount;
|
|
|
|
sema->waitCount = 0;
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
assert(sema->count <= sema->maxCount);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2015-01-31 01:40:42 -05:00
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nD0 = id;
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//41
|
|
|
|
void CPS2OS::sc_DeleteSema()
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
uint32 id = m_ee.m_State.nGPR[SC_PARAM0].nV[0];
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2015-01-31 01:40:42 -05:00
|
|
|
auto sema = m_semaphores[id];
|
|
|
|
if(sema == nullptr)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2015-01-31 01:40:42 -05:00
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nD0 = -1;
|
2008-11-10 01:46:02 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Check if any threads are waiting for this?
|
2014-08-27 01:07:09 -04:00
|
|
|
if(sema->waitCount != 0)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
|
|
|
assert(0);
|
|
|
|
}
|
|
|
|
|
2015-01-31 01:40:42 -05:00
|
|
|
m_semaphores.Free(id);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2015-01-31 01:40:42 -05:00
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nD0 = id;
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//42
|
|
|
|
//43
|
|
|
|
void CPS2OS::sc_SignalSema()
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
bool isInt = m_ee.m_State.nGPR[3].nV[0] == 0x43;
|
|
|
|
uint32 id = m_ee.m_State.nGPR[SC_PARAM0].nV[0];
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2015-01-31 01:40:42 -05:00
|
|
|
auto sema = m_semaphores[id];
|
|
|
|
if(sema == nullptr)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2015-01-31 01:40:42 -05:00
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nD0 = -1;
|
2008-11-10 01:46:02 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
if(sema->waitCount != 0)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
|
|
|
//Unsleep all threads if they were waiting
|
|
|
|
for(uint32 i = 0; i < MAX_THREAD; i++)
|
|
|
|
{
|
2014-08-27 00:10:31 -04:00
|
|
|
THREAD* thread = GetThread(i);
|
2014-08-27 01:07:09 -04:00
|
|
|
if(!thread->valid) continue;
|
|
|
|
if((thread->status != THREAD_WAITING) && (thread->status != THREAD_SUSPENDED_WAITING)) continue;
|
|
|
|
if(thread->semaWait != id) continue;
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
switch(thread->status)
|
2012-06-28 06:03:14 +00:00
|
|
|
{
|
|
|
|
case THREAD_WAITING:
|
2014-08-27 01:07:09 -04:00
|
|
|
thread->status = THREAD_RUNNING;
|
2012-06-28 06:03:14 +00:00
|
|
|
break;
|
|
|
|
case THREAD_SUSPENDED_WAITING:
|
2014-08-27 01:07:09 -04:00
|
|
|
thread->status = THREAD_SUSPENDED;
|
2012-06-28 06:03:14 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
assert(0);
|
|
|
|
break;
|
|
|
|
}
|
2014-08-27 01:07:09 -04:00
|
|
|
thread->quota = THREAD_INIT_QUOTA;
|
|
|
|
sema->waitCount--;
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
if(sema->waitCount == 0)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[0] = id;
|
2008-11-10 01:46:02 +00:00
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[1] = 0;
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
if(!isInt)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
|
|
|
ThreadShakeAndBake();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
sema->count++;
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
2015-01-31 01:40:42 -05:00
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nD0 = id;
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//44
|
|
|
|
void CPS2OS::sc_WaitSema()
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
uint32 id = m_ee.m_State.nGPR[SC_PARAM0].nV[0];
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2015-01-31 01:40:42 -05:00
|
|
|
auto sema = m_semaphores[id];
|
|
|
|
if(sema == nullptr)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2015-01-31 01:40:42 -05:00
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nD0 = -1;
|
2008-11-10 01:46:02 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
if((m_semaWaitId == id) && (m_semaWaitCaller == m_ee.m_State.nGPR[CMIPS::RA].nV0))
|
2011-05-08 21:58:55 +00:00
|
|
|
{
|
|
|
|
m_semaWaitCount++;
|
2011-05-16 00:04:02 +00:00
|
|
|
if(m_semaWaitCount > 100)
|
|
|
|
{
|
|
|
|
m_semaWaitThreadId = GetCurrentThreadId();
|
|
|
|
}
|
2011-05-08 21:58:55 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
m_semaWaitId = id;
|
2011-05-08 21:58:55 +00:00
|
|
|
m_semaWaitCaller = m_ee.m_State.nGPR[CMIPS::RA].nV0;
|
|
|
|
m_semaWaitCount = 0;
|
|
|
|
}
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
if(sema->count == 0)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
|
|
|
//Put this thread in sleep mode and reschedule...
|
2014-08-27 01:07:09 -04:00
|
|
|
sema->waitCount++;
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 00:10:31 -04:00
|
|
|
THREAD* thread = GetThread(GetCurrentThreadId());
|
2014-08-27 01:07:09 -04:00
|
|
|
assert(thread->status == THREAD_RUNNING);
|
|
|
|
thread->status = THREAD_WAITING;
|
|
|
|
thread->semaWait = id;
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
ThreadShakeAndBake();
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
if(sema->count != 0)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
sema->count--;
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
2015-01-31 01:40:42 -05:00
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nD0 = id;
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//45
|
|
|
|
void CPS2OS::sc_PollSema()
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
uint32 id = m_ee.m_State.nGPR[SC_PARAM0].nV[0];
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2015-01-31 01:40:42 -05:00
|
|
|
auto sema = m_semaphores[id];
|
|
|
|
if(sema == nullptr)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2015-01-31 01:40:42 -05:00
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nD0 = -1;
|
2008-11-10 01:46:02 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
if(sema->count == 0)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2015-01-31 01:40:42 -05:00
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nD0 = -1;
|
2008-11-10 01:46:02 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
sema->count--;
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2015-01-31 01:40:42 -05:00
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nD0 = id;
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
2009-08-16 21:03:03 +00:00
|
|
|
//47
|
2008-11-10 01:46:02 +00:00
|
|
|
//48
|
|
|
|
void CPS2OS::sc_ReferSemaStatus()
|
|
|
|
{
|
2012-03-11 20:06:14 +00:00
|
|
|
bool isInt = m_ee.m_State.nGPR[3].nV[0] != 0x47;
|
2014-08-27 01:07:09 -04:00
|
|
|
uint32 id = m_ee.m_State.nGPR[SC_PARAM0].nV[0];
|
|
|
|
SEMAPHOREPARAM* semaParam = (SEMAPHOREPARAM*)(m_ram + (m_ee.m_State.nGPR[SC_PARAM1].nV[0] & 0x1FFFFFFF));
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2015-01-31 01:40:42 -05:00
|
|
|
auto sema = m_semaphores[id];
|
|
|
|
if(sema == nullptr)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2015-01-31 01:40:42 -05:00
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nD0 = -1;
|
2008-11-10 01:46:02 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
semaParam->count = sema->count;
|
|
|
|
semaParam->maxCount = sema->maxCount;
|
|
|
|
semaParam->waitThreads = sema->waitCount;
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2015-01-31 01:40:42 -05:00
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nD0 = id;
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//64
|
|
|
|
void CPS2OS::sc_FlushCache()
|
|
|
|
{
|
2011-12-25 04:06:43 +00:00
|
|
|
uint32 operationType = m_ee.m_State.nGPR[SC_PARAM0].nV[0];
|
|
|
|
if(operationType == 2)
|
|
|
|
{
|
|
|
|
//Flush instruction cache
|
2012-03-11 20:06:14 +00:00
|
|
|
OnRequestInstructionCacheFlush();
|
2011-12-25 04:06:43 +00:00
|
|
|
}
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
2012-05-29 04:18:40 +00:00
|
|
|
//70
|
|
|
|
void CPS2OS::sc_GsGetIMR()
|
|
|
|
{
|
|
|
|
uint32 result = 0;
|
|
|
|
|
|
|
|
if(m_gs != NULL)
|
|
|
|
{
|
|
|
|
result = m_gs->ReadPrivRegister(CGSHandler::GS_IMR);
|
|
|
|
}
|
|
|
|
|
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nD0 = static_cast<int32>(result);
|
|
|
|
}
|
|
|
|
|
2008-11-10 01:46:02 +00:00
|
|
|
//71
|
|
|
|
void CPS2OS::sc_GsPutIMR()
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
uint32 imr = m_ee.m_State.nGPR[SC_PARAM0].nV[0];
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
if(m_gs != NULL)
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
m_gs->WritePrivRegister(CGSHandler::GS_IMR, imr);
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//73
|
|
|
|
void CPS2OS::sc_SetVSyncFlag()
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
uint32 ptr1 = m_ee.m_State.nGPR[SC_PARAM0].nV[0];
|
|
|
|
uint32 ptr2 = m_ee.m_State.nGPR[SC_PARAM1].nV[0];
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
*(uint32*)&m_ram[ptr1] = 0x01;
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
if(m_gs != NULL)
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
//*(uint32*)&m_ram[ptr2] = 0x2000;
|
|
|
|
*(uint32*)&m_ram[ptr2] = m_gs->ReadPrivRegister(CGSHandler::GS_CSR) & 0x2000;
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//Humm...
|
2014-08-27 01:07:09 -04:00
|
|
|
*(uint32*)&m_ram[ptr2] = 0;
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[0] = 0;
|
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[1] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//74
|
|
|
|
void CPS2OS::sc_SetSyscall()
|
|
|
|
{
|
2014-06-01 23:15:36 -04:00
|
|
|
uint32 number = m_ee.m_State.nGPR[SC_PARAM0].nV[0];
|
|
|
|
uint32 address = m_ee.m_State.nGPR[SC_PARAM1].nV[0];
|
|
|
|
|
|
|
|
if(number < 0x100)
|
|
|
|
{
|
|
|
|
GetCustomSyscallTable()[number] = address;
|
|
|
|
}
|
|
|
|
else if(number == 0x12C)
|
|
|
|
{
|
|
|
|
//This syscall doesn't do any bounds checking and it's possible to
|
|
|
|
//set INTC handler for timer 3 through this system call (a particular version of libcdvd does this)
|
|
|
|
//My guess is that the BIOS doesn't process custom INTC handlers for INT12 (timer 3) and the
|
|
|
|
//only way to have an handler placed on that interrupt line is to do that trick.
|
|
|
|
|
|
|
|
unsigned int line = 12;
|
|
|
|
|
|
|
|
uint32 handlerId = GetNextAvailableIntcHandlerId();
|
|
|
|
if(handlerId == 0xFFFFFFFF)
|
|
|
|
{
|
|
|
|
CLog::GetInstance().Print(LOG_NAME, "Couldn't set INTC handler through SetSyscall");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
INTCHANDLER* handler = GetIntcHandler(handlerId);
|
|
|
|
handler->valid = 1;
|
|
|
|
handler->address = address & 0x1FFFFFFF;
|
|
|
|
handler->cause = line;
|
|
|
|
handler->arg = 0;
|
|
|
|
handler->gp = 0;
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-06-01 23:15:36 -04:00
|
|
|
if(!(m_ee.m_pMemoryMap->GetWord(CINTC::INTC_MASK) & (1 << line)))
|
|
|
|
{
|
|
|
|
m_ee.m_pMemoryMap->SetWord(CINTC::INTC_MASK, (1 << line));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
CLog::GetInstance().Print(LOG_NAME, "Unknown syscall set.", number);
|
|
|
|
}
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[0] = 0;
|
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[1] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//76
|
|
|
|
void CPS2OS::sc_SifDmaStat()
|
|
|
|
{
|
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[0] = 0xFFFFFFFF;
|
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[1] = 0xFFFFFFFF;
|
|
|
|
}
|
|
|
|
|
|
|
|
//77
|
|
|
|
void CPS2OS::sc_SifSetDma()
|
|
|
|
{
|
2015-01-31 23:05:56 -05:00
|
|
|
auto xfer = reinterpret_cast<SIFDMAREG*>(GetStructPtr(m_ee.m_State.nGPR[SC_PARAM0].nV0));
|
2014-08-27 01:07:09 -04:00
|
|
|
uint32 count = m_ee.m_State.nGPR[SC_PARAM1].nV[0];
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
//Returns count
|
|
|
|
//DMA might call an interrupt handler
|
2014-08-27 01:07:09 -04:00
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nD0 = static_cast<int32>(count);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
for(unsigned int i = 0; i < count; i++)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
uint32 size = (xfer[i].size + 0x0F) / 0x10;
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
m_ee.m_pMemoryMap->SetWord(CDMAC::D6_MADR, xfer[i].srcAddr);
|
|
|
|
m_ee.m_pMemoryMap->SetWord(CDMAC::D6_TADR, xfer[i].dstAddr);
|
|
|
|
m_ee.m_pMemoryMap->SetWord(CDMAC::D6_QWC, size);
|
2008-11-10 01:46:02 +00:00
|
|
|
m_ee.m_pMemoryMap->SetWord(CDMAC::D6_CHCR, 0x00000100);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//78
|
|
|
|
void CPS2OS::sc_SifSetDChain()
|
|
|
|
{
|
|
|
|
//Humm, set the SIF0 DMA channel in destination chain mode?
|
2014-07-12 02:13:35 -04:00
|
|
|
|
|
|
|
//This syscall is invoked by the SIF dma interrupt handler (when a packet has been received)
|
|
|
|
//To make sure every packet generates an interrupt, the SIF will hold into any packet
|
|
|
|
//that it might have in its queue while a packet is being processed.
|
|
|
|
//The MarkPacketProcess function will tell the SIF that the packet has been processed
|
|
|
|
//and that it can continue sending packets over. (Needed for Guilty Gear XX Accent Core Plus)
|
|
|
|
bool isInt = m_ee.m_State.nGPR[3].nV[1] == ~0;
|
|
|
|
if(isInt)
|
|
|
|
{
|
|
|
|
m_sif.MarkPacketProcessed();
|
|
|
|
}
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//79
|
|
|
|
void CPS2OS::sc_SifSetReg()
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
uint32 registerId = m_ee.m_State.nGPR[SC_PARAM0].nV[0];
|
|
|
|
uint32 value = m_ee.m_State.nGPR[SC_PARAM1].nV[0];
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
m_sif.SetRegister(registerId, value);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nD0 = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//7A
|
|
|
|
void CPS2OS::sc_SifGetReg()
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
uint32 registerId = m_ee.m_State.nGPR[SC_PARAM0].nV[0];
|
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nD0 = static_cast<int32>(m_sif.GetRegister(registerId));
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//7C
|
|
|
|
void CPS2OS::sc_Deci2Call()
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
uint32 function = m_ee.m_State.nGPR[SC_PARAM0].nV[0];
|
|
|
|
uint32 param = m_ee.m_State.nGPR[SC_PARAM1].nV[0];
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
switch(function)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
|
|
|
case 0x01:
|
|
|
|
//Deci2Open
|
2012-04-23 02:55:30 +00:00
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
uint32 id = GetNextAvailableDeci2HandlerId();
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
DECI2HANDLER* handler = GetDeci2Handler(id);
|
|
|
|
handler->valid = 1;
|
|
|
|
handler->device = *(uint32*)&m_ram[param + 0x00];
|
|
|
|
handler->bufferAddr = *(uint32*)&m_ram[param + 0x04];
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[0] = id;
|
2012-04-23 02:55:30 +00:00
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[1] = 0;
|
|
|
|
}
|
2008-11-10 01:46:02 +00:00
|
|
|
break;
|
|
|
|
case 0x03:
|
|
|
|
//Deci2Send
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
uint32 id = *reinterpret_cast<uint32*>(&m_ram[param + 0x00]);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
DECI2HANDLER* handler = GetDeci2Handler(id);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
if(handler->valid != 0)
|
2012-04-23 02:55:30 +00:00
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
uint32 stringAddr = *reinterpret_cast<uint32*>(&m_ram[handler->bufferAddr + 0x10]);
|
2012-09-12 01:03:53 +00:00
|
|
|
stringAddr &= (PS2::EE_RAM_SIZE - 1);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
uint32 length = m_ram[stringAddr + 0x00] - 0x0C;
|
|
|
|
uint8* string = &m_ram[stringAddr + 0x0C];
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
m_iopBios.GetIoman()->Write(1, length, string);
|
2012-04-23 02:55:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[0] = 1;
|
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[1] = 0;
|
|
|
|
}
|
2008-11-10 01:46:02 +00:00
|
|
|
break;
|
|
|
|
case 0x04:
|
|
|
|
//Deci2Poll
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
uint32 id = *reinterpret_cast<uint32*>(&m_ram[param + 0x00]);
|
2012-04-23 02:55:30 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
DECI2HANDLER* handler = GetDeci2Handler(id);
|
|
|
|
if(handler->valid != 0)
|
2012-04-23 02:55:30 +00:00
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
*(uint32*)&m_ram[handler->bufferAddr + 0x0C] = 0;
|
2012-04-23 02:55:30 +00:00
|
|
|
}
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2012-04-23 02:55:30 +00:00
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[0] = 1;
|
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[1] = 0;
|
|
|
|
}
|
2008-11-10 01:46:02 +00:00
|
|
|
break;
|
|
|
|
case 0x10:
|
|
|
|
//kPuts
|
2012-04-23 02:55:30 +00:00
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
uint32 stringAddr = *reinterpret_cast<uint32*>(&m_ram[param]);
|
|
|
|
uint8* string = &m_ram[stringAddr];
|
|
|
|
m_iopBios.GetIoman()->Write(1, static_cast<uint32>(strlen(reinterpret_cast<char*>(string))), string);
|
2012-04-23 02:55:30 +00:00
|
|
|
}
|
2008-11-10 01:46:02 +00:00
|
|
|
break;
|
|
|
|
default:
|
2014-08-27 01:07:09 -04:00
|
|
|
CLog::GetInstance().Print(LOG_NAME, "Unknown Deci2Call function (0x%0.8X) called. PC: 0x%0.8X.\r\n", function, m_ee.m_State.nPC);
|
2008-11-10 01:46:02 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
//7F
|
|
|
|
void CPS2OS::sc_GetMemorySize()
|
|
|
|
{
|
2012-09-12 01:03:53 +00:00
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[0] = PS2::EE_RAM_SIZE;
|
2008-11-10 01:46:02 +00:00
|
|
|
m_ee.m_State.nGPR[SC_RETURN].nV[1] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////
|
|
|
|
//System Call Handler
|
|
|
|
//////////////////////////////////////////////////
|
|
|
|
|
2014-06-04 23:37:40 -04:00
|
|
|
void CPS2OS::HandleSyscall()
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2012-03-11 20:06:14 +00:00
|
|
|
uint32 searchAddress = m_ee.m_State.nCOP0[CCOP_SCU::EPC];
|
|
|
|
uint32 callInstruction = m_ee.m_pMemoryMap->GetInstruction(searchAddress);
|
|
|
|
if(callInstruction != 0x0000000C)
|
|
|
|
{
|
|
|
|
throw std::runtime_error("Not a SYSCALL.");
|
|
|
|
}
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
uint32 func = m_ee.m_State.nGPR[3].nV[0];
|
2012-03-11 20:06:14 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
if(func == 0x666)
|
2012-03-11 20:06:14 +00:00
|
|
|
{
|
|
|
|
//Reschedule
|
|
|
|
ThreadShakeAndBake();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
if(func & 0x80000000)
|
2012-03-11 20:06:14 +00:00
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
func = 0 - func;
|
2012-03-11 20:06:14 +00:00
|
|
|
}
|
|
|
|
//Save for custom handler
|
2014-08-27 01:07:09 -04:00
|
|
|
m_ee.m_State.nGPR[3].nV[0] = func;
|
2012-03-11 20:06:14 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
if(GetCustomSyscallTable()[func] == NULL)
|
2012-03-11 20:06:14 +00:00
|
|
|
{
|
|
|
|
#ifdef _DEBUG
|
2014-08-27 01:07:09 -04:00
|
|
|
DisassembleSysCall(static_cast<uint8>(func & 0xFF));
|
2012-03-11 20:06:14 +00:00
|
|
|
#endif
|
2014-08-27 01:07:09 -04:00
|
|
|
if(func < 0x80)
|
2012-03-11 20:06:14 +00:00
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
((this)->*(m_sysCall[func & 0xFF]))();
|
2012-03-11 20:06:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_ee.GenerateException(0x1FC00100);
|
|
|
|
}
|
|
|
|
}
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2012-03-11 20:06:14 +00:00
|
|
|
m_ee.m_State.nHasException = 0;
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
void CPS2OS::DisassembleSysCall(uint8 func)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
|
|
|
#ifdef _DEBUG
|
2014-08-27 01:07:09 -04:00
|
|
|
std::string description(GetSysCallDescription(func));
|
|
|
|
if(description.length() != 0)
|
2012-03-11 20:06:14 +00:00
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
CLog::GetInstance().Print(LOG_NAME, "%d: %s\r\n", GetCurrentThreadId(), description.c_str());
|
2012-03-11 20:06:14 +00:00
|
|
|
}
|
2008-11-10 01:46:02 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
std::string CPS2OS::GetSysCallDescription(uint8 function)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
char description[256];
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
strcpy(description, "");
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
switch(function)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
|
|
|
case 0x02:
|
2014-08-27 01:07:09 -04:00
|
|
|
sprintf(description, "GsSetCrt(interlace = %i, mode = %i, field = %i);", \
|
2008-11-10 01:46:02 +00:00
|
|
|
m_ee.m_State.nGPR[SC_PARAM0].nV[0], \
|
|
|
|
m_ee.m_State.nGPR[SC_PARAM1].nV[0], \
|
|
|
|
m_ee.m_State.nGPR[SC_PARAM2].nV[0]);
|
|
|
|
break;
|
2012-04-14 21:08:33 +00:00
|
|
|
case 0x06:
|
2014-08-27 01:07:09 -04:00
|
|
|
sprintf(description, SYSCALL_NAME_LOADEXECPS2 "(exec = 0x%0.8X, argc = %d, argv = 0x%0.8X);",
|
2012-04-14 21:08:33 +00:00
|
|
|
m_ee.m_State.nGPR[SC_PARAM0].nV[0],
|
|
|
|
m_ee.m_State.nGPR[SC_PARAM1].nV[0],
|
|
|
|
m_ee.m_State.nGPR[SC_PARAM2].nV[0]);
|
|
|
|
break;
|
2012-03-11 20:06:14 +00:00
|
|
|
case 0x10:
|
2014-08-27 01:07:09 -04:00
|
|
|
sprintf(description, SYSCALL_NAME_ADDINTCHANDLER "(cause = %i, address = 0x%0.8X, next = 0x%0.8X, arg = 0x%0.8X);",
|
2009-04-29 02:58:23 +00:00
|
|
|
m_ee.m_State.nGPR[SC_PARAM0].nV[0],
|
2012-03-11 20:06:14 +00:00
|
|
|
m_ee.m_State.nGPR[SC_PARAM1].nV[0],
|
|
|
|
m_ee.m_State.nGPR[SC_PARAM2].nV[0],
|
|
|
|
m_ee.m_State.nGPR[SC_PARAM3].nV[0]);
|
|
|
|
break;
|
2008-11-10 01:46:02 +00:00
|
|
|
case 0x11:
|
2014-12-14 01:55:22 -05:00
|
|
|
sprintf(description, SYSCALL_NAME_REMOVEINTCHANDLER "(cause = %i, id = %i);", \
|
2008-11-10 01:46:02 +00:00
|
|
|
m_ee.m_State.nGPR[SC_PARAM0].nV[0], \
|
|
|
|
m_ee.m_State.nGPR[SC_PARAM1].nV[0]);
|
|
|
|
break;
|
|
|
|
case 0x12:
|
2014-12-14 01:55:22 -05:00
|
|
|
sprintf(description, SYSCALL_NAME_ADDDMACHANDLER "(channel = %i, address = 0x%0.8X, next = %i, arg = %i);", \
|
2008-11-10 01:46:02 +00:00
|
|
|
m_ee.m_State.nGPR[SC_PARAM0].nV[0], \
|
|
|
|
m_ee.m_State.nGPR[SC_PARAM1].nV[0], \
|
|
|
|
m_ee.m_State.nGPR[SC_PARAM2].nV[0], \
|
|
|
|
m_ee.m_State.nGPR[SC_PARAM3].nV[0]);
|
|
|
|
break;
|
|
|
|
case 0x13:
|
2014-12-14 01:55:22 -05:00
|
|
|
sprintf(description, SYSCALL_NAME_REMOVEDMACHANDLER "(channel = %i, handler = %i);", \
|
2008-11-10 01:46:02 +00:00
|
|
|
m_ee.m_State.nGPR[SC_PARAM0].nV[0], \
|
|
|
|
m_ee.m_State.nGPR[SC_PARAM1].nV[0]);
|
|
|
|
break;
|
|
|
|
case 0x14:
|
2014-08-27 01:07:09 -04:00
|
|
|
sprintf(description, SYSCALL_NAME_ENABLEINTC "(cause = %i);", \
|
2008-11-10 01:46:02 +00:00
|
|
|
m_ee.m_State.nGPR[SC_PARAM0].nV[0]);
|
|
|
|
break;
|
|
|
|
case 0x15:
|
2014-08-27 01:07:09 -04:00
|
|
|
sprintf(description, SYSCALL_NAME_DISABLEINTC "(cause = %i);", \
|
2008-11-10 01:46:02 +00:00
|
|
|
m_ee.m_State.nGPR[SC_PARAM0].nV[0]);
|
|
|
|
break;
|
|
|
|
case 0x16:
|
2014-08-27 01:07:09 -04:00
|
|
|
sprintf(description, SYSCALL_NAME_ENABLEDMAC "(channel = %i);", \
|
2008-11-10 01:46:02 +00:00
|
|
|
m_ee.m_State.nGPR[SC_PARAM0].nV[0]);
|
|
|
|
break;
|
|
|
|
case 0x17:
|
2014-08-27 01:07:09 -04:00
|
|
|
sprintf(description, SYSCALL_NAME_DISABLEDMAC "(channel = %i);", \
|
2008-11-10 01:46:02 +00:00
|
|
|
m_ee.m_State.nGPR[SC_PARAM0].nV[0]);
|
|
|
|
break;
|
2015-01-28 03:32:18 -05:00
|
|
|
case 0x18:
|
|
|
|
sprintf(description, SYSCALL_NAME_SETALARM "(time = %d, proc = 0x%0.8X, arg = 0x%0.8X);",
|
|
|
|
m_ee.m_State.nGPR[SC_PARAM0].nV[0],
|
|
|
|
m_ee.m_State.nGPR[SC_PARAM1].nV[0],
|
|
|
|
m_ee.m_State.nGPR[SC_PARAM2].nV[0]);
|
|
|
|
break;
|
|
|
|
case 0x1F:
|
|
|
|
sprintf(description, SYSCALL_NAME_IRELEASEALARM "(id = %d);",
|
|
|
|
m_ee.m_State.nGPR[SC_PARAM0].nV[0]);
|
|
|
|
break;
|
2008-11-10 01:46:02 +00:00
|
|
|
case 0x20:
|
2014-08-27 01:07:09 -04:00
|
|
|
sprintf(description, SYSCALL_NAME_CREATETHREAD "(thread = 0x%0.8X);", \
|
2008-11-10 01:46:02 +00:00
|
|
|
m_ee.m_State.nGPR[SC_PARAM0].nV[0]);
|
|
|
|
break;
|
|
|
|
case 0x21:
|
2014-12-14 01:55:22 -05:00
|
|
|
sprintf(description, SYSCALL_NAME_DELETETHREAD "(id = 0x%0.8X);", \
|
2008-11-10 01:46:02 +00:00
|
|
|
m_ee.m_State.nGPR[SC_PARAM0].nV[0]);
|
|
|
|
break;
|
|
|
|
case 0x22:
|
2014-08-27 01:07:09 -04:00
|
|
|
sprintf(description, SYSCALL_NAME_STARTTHREAD "(id = 0x%0.8X, a0 = 0x%0.8X);", \
|
2008-11-10 01:46:02 +00:00
|
|
|
m_ee.m_State.nGPR[SC_PARAM0].nV[0], \
|
|
|
|
m_ee.m_State.nGPR[SC_PARAM1].nV[0]);
|
|
|
|
break;
|
|
|
|
case 0x23:
|
2014-08-27 01:07:09 -04:00
|
|
|
sprintf(description, "ExitThread();");
|
2008-11-10 01:46:02 +00:00
|
|
|
break;
|
|
|
|
case 0x25:
|
2014-12-14 01:55:22 -05:00
|
|
|
sprintf(description, SYSCALL_NAME_TERMINATETHREAD "(id = 0x%0.8X);", \
|
2008-11-10 01:46:02 +00:00
|
|
|
m_ee.m_State.nGPR[SC_PARAM0].nV[0]);
|
|
|
|
break;
|
|
|
|
case 0x29:
|
2014-08-27 01:07:09 -04:00
|
|
|
sprintf(description, SYSCALL_NAME_CHANGETHREADPRIORITY "(id = 0x%0.8X, priority = %i);", \
|
2008-11-10 01:46:02 +00:00
|
|
|
m_ee.m_State.nGPR[SC_PARAM0].nV[0], \
|
|
|
|
m_ee.m_State.nGPR[SC_PARAM1].nV[0]);
|
|
|
|
break;
|
2011-11-08 07:59:11 +00:00
|
|
|
case 0x2A:
|
2014-08-27 01:07:09 -04:00
|
|
|
sprintf(description, SYSCALL_NAME_ICHANGETHREADPRIORITY "(id = 0x%0.8X, priority = %i);", \
|
2011-11-08 07:59:11 +00:00
|
|
|
m_ee.m_State.nGPR[SC_PARAM0].nV[0], \
|
|
|
|
m_ee.m_State.nGPR[SC_PARAM1].nV[0]);
|
|
|
|
break;
|
2008-11-10 01:46:02 +00:00
|
|
|
case 0x2B:
|
2014-08-27 01:07:09 -04:00
|
|
|
sprintf(description, SYSCALL_NAME_ROTATETHREADREADYQUEUE "(prio = %i);", \
|
2008-11-10 01:46:02 +00:00
|
|
|
m_ee.m_State.nGPR[SC_PARAM0].nV[0]);
|
|
|
|
break;
|
|
|
|
case 0x2F:
|
2014-08-27 01:07:09 -04:00
|
|
|
sprintf(description, SYSCALL_NAME_GETTHREADID "();");
|
2008-11-10 01:46:02 +00:00
|
|
|
break;
|
2012-06-28 06:03:14 +00:00
|
|
|
case 0x30:
|
2014-08-27 01:07:09 -04:00
|
|
|
sprintf(description, SYSCALL_NAME_REFERTHREADSTATUS "(threadId = %d, infoPtr = 0x%0.8X);",
|
2012-06-28 06:03:14 +00:00
|
|
|
m_ee.m_State.nGPR[SC_PARAM0].nV[0],
|
|
|
|
m_ee.m_State.nGPR[SC_PARAM1].nV[0]);
|
|
|
|
break;
|
|
|
|
case 0x31:
|
2014-08-27 01:07:09 -04:00
|
|
|
sprintf(description, SYSCALL_NAME_IREFERTHREADSTATUS "(threadId = %d, infoPtr = 0x%0.8X);",
|
2012-06-28 06:03:14 +00:00
|
|
|
m_ee.m_State.nGPR[SC_PARAM0].nV[0],
|
|
|
|
m_ee.m_State.nGPR[SC_PARAM1].nV[0]);
|
|
|
|
break;
|
2008-11-10 01:46:02 +00:00
|
|
|
case 0x32:
|
2014-08-27 01:07:09 -04:00
|
|
|
sprintf(description, SYSCALL_NAME_SLEEPTHREAD "();");
|
2008-11-10 01:46:02 +00:00
|
|
|
break;
|
|
|
|
case 0x33:
|
2014-08-27 01:07:09 -04:00
|
|
|
sprintf(description, SYSCALL_NAME_WAKEUPTHREAD "(id = %i);", \
|
2008-11-10 01:46:02 +00:00
|
|
|
m_ee.m_State.nGPR[SC_PARAM0].nV[0]);
|
|
|
|
break;
|
|
|
|
case 0x34:
|
2014-08-27 01:07:09 -04:00
|
|
|
sprintf(description, SYSCALL_NAME_IWAKEUPTHREAD "(id = %i);", \
|
2008-11-10 01:46:02 +00:00
|
|
|
m_ee.m_State.nGPR[SC_PARAM0].nV[0]);
|
|
|
|
break;
|
2014-09-29 01:27:13 -04:00
|
|
|
case 0x35:
|
|
|
|
sprintf(description, SYSCALL_NAME_CANCELWAKEUPTHREAD "(id = %d);",
|
|
|
|
m_ee.m_State.nGPR[SC_PARAM0].nV[0]);
|
|
|
|
break;
|
|
|
|
case 0x36:
|
|
|
|
sprintf(description, SYSCALL_NAME_ICANCELWAKEUPTHREAD "(id = %d);",
|
|
|
|
m_ee.m_State.nGPR[SC_PARAM0].nV[0]);
|
|
|
|
break;
|
2012-06-28 06:03:14 +00:00
|
|
|
case 0x37:
|
2014-08-27 01:07:09 -04:00
|
|
|
sprintf(description, SYSCALL_NAME_SUSPENDTHREAD "(id = %i);", \
|
2012-06-28 06:03:14 +00:00
|
|
|
m_ee.m_State.nGPR[SC_PARAM0].nV[0]);
|
|
|
|
break;
|
|
|
|
case 0x39:
|
2014-08-27 01:07:09 -04:00
|
|
|
sprintf(description, SYSCALL_NAME_RESUMETHREAD "(id = %i);", \
|
2012-06-28 06:03:14 +00:00
|
|
|
m_ee.m_State.nGPR[SC_PARAM0].nV[0]);
|
|
|
|
break;
|
2008-11-10 01:46:02 +00:00
|
|
|
case 0x3C:
|
2014-08-27 01:07:09 -04:00
|
|
|
sprintf(description, "SetupThread(gp = 0x%0.8X, stack = 0x%0.8X, stack_size = 0x%0.8X, args = 0x%0.8X, root_func = 0x%0.8X);", \
|
2008-11-10 01:46:02 +00:00
|
|
|
m_ee.m_State.nGPR[SC_PARAM0].nV[0], \
|
|
|
|
m_ee.m_State.nGPR[SC_PARAM1].nV[0], \
|
|
|
|
m_ee.m_State.nGPR[SC_PARAM2].nV[0], \
|
|
|
|
m_ee.m_State.nGPR[SC_PARAM3].nV[0], \
|
|
|
|
m_ee.m_State.nGPR[SC_PARAM4].nV[0]);
|
|
|
|
break;
|
|
|
|
case 0x3D:
|
2014-08-27 01:07:09 -04:00
|
|
|
sprintf(description, "SetupHeap(heap_start = 0x%0.8X, heap_size = 0x%0.8X);", \
|
2008-11-10 01:46:02 +00:00
|
|
|
m_ee.m_State.nGPR[SC_PARAM0].nV[0], \
|
|
|
|
m_ee.m_State.nGPR[SC_PARAM1].nV[0]);
|
|
|
|
break;
|
|
|
|
case 0x3E:
|
2014-08-27 01:07:09 -04:00
|
|
|
sprintf(description, SYSCALL_NAME_ENDOFHEAP "();");
|
2008-11-10 01:46:02 +00:00
|
|
|
break;
|
|
|
|
case 0x40:
|
2014-08-27 01:07:09 -04:00
|
|
|
sprintf(description, SYSCALL_NAME_CREATESEMA "(sema = 0x%0.8X);", \
|
2008-11-10 01:46:02 +00:00
|
|
|
m_ee.m_State.nGPR[SC_PARAM0].nV[0]);
|
|
|
|
break;
|
|
|
|
case 0x41:
|
2014-08-27 01:07:09 -04:00
|
|
|
sprintf(description, SYSCALL_NAME_DELETESEMA "(semaid = %i);", \
|
2008-11-10 01:46:02 +00:00
|
|
|
m_ee.m_State.nGPR[SC_PARAM0].nV[0]);
|
|
|
|
break;
|
|
|
|
case 0x42:
|
2014-08-27 01:07:09 -04:00
|
|
|
sprintf(description, SYSCALL_NAME_SIGNALSEMA "(semaid = %i);", \
|
2008-11-10 01:46:02 +00:00
|
|
|
m_ee.m_State.nGPR[SC_PARAM0].nV[0]);
|
|
|
|
break;
|
|
|
|
case 0x43:
|
2014-08-27 01:07:09 -04:00
|
|
|
sprintf(description, SYSCALL_NAME_ISIGNALSEMA "(semaid = %i);", \
|
2008-11-10 01:46:02 +00:00
|
|
|
m_ee.m_State.nGPR[SC_PARAM0].nV[0]);
|
|
|
|
break;
|
|
|
|
case 0x44:
|
2014-08-27 01:07:09 -04:00
|
|
|
sprintf(description, SYSCALL_NAME_WAITSEMA "(semaid = %i);", \
|
2008-11-10 01:46:02 +00:00
|
|
|
m_ee.m_State.nGPR[SC_PARAM0].nV[0]);
|
|
|
|
break;
|
|
|
|
case 0x45:
|
2014-08-27 01:07:09 -04:00
|
|
|
sprintf(description, SYSCALL_NAME_POLLSEMA "(semaid = %i);", \
|
2008-11-10 01:46:02 +00:00
|
|
|
m_ee.m_State.nGPR[SC_PARAM0].nV[0]);
|
|
|
|
break;
|
|
|
|
case 0x46:
|
2014-08-27 01:07:09 -04:00
|
|
|
sprintf(description, "iPollSema(semaid = %i);", \
|
2008-11-10 01:46:02 +00:00
|
|
|
m_ee.m_State.nGPR[SC_PARAM0].nV[0]);
|
|
|
|
break;
|
2012-03-11 20:06:14 +00:00
|
|
|
case 0x47:
|
2014-08-27 01:07:09 -04:00
|
|
|
sprintf(description, SYSCALL_NAME_REFERSEMASTATUS "(semaid = %i, status = 0x%0.8X);",
|
2014-06-28 23:35:15 -04:00
|
|
|
m_ee.m_State.nGPR[SC_PARAM0].nV[0],
|
|
|
|
m_ee.m_State.nGPR[SC_PARAM1].nV[0]);
|
|
|
|
break;
|
2008-11-10 01:46:02 +00:00
|
|
|
case 0x48:
|
2014-08-27 01:07:09 -04:00
|
|
|
sprintf(description, SYSCALL_NAME_IREFERSEMASTATUS "(semaid = %i, status = 0x%0.8X);",
|
2008-11-10 01:46:02 +00:00
|
|
|
m_ee.m_State.nGPR[SC_PARAM0].nV[0],
|
|
|
|
m_ee.m_State.nGPR[SC_PARAM1].nV[0]);
|
|
|
|
break;
|
|
|
|
case 0x64:
|
|
|
|
case 0x68:
|
|
|
|
#ifdef _DEBUG
|
2014-08-27 01:07:09 -04:00
|
|
|
// sprintf(description, SYSCALL_NAME_FLUSHCACHE "();");
|
2008-11-10 01:46:02 +00:00
|
|
|
#endif
|
|
|
|
break;
|
2012-05-29 04:18:40 +00:00
|
|
|
case 0x70:
|
2014-08-27 01:07:09 -04:00
|
|
|
sprintf(description, SYSCALL_NAME_GSGETIMR "();");
|
2012-05-29 04:18:40 +00:00
|
|
|
break;
|
2008-11-10 01:46:02 +00:00
|
|
|
case 0x71:
|
2014-08-27 01:07:09 -04:00
|
|
|
sprintf(description, SYSCALL_NAME_GSPUTIMR "(GS_IMR = 0x%0.8X);", \
|
2008-11-10 01:46:02 +00:00
|
|
|
m_ee.m_State.nGPR[SC_PARAM0].nV[0]);
|
|
|
|
break;
|
|
|
|
case 0x73:
|
2014-08-27 01:07:09 -04:00
|
|
|
sprintf(description, SYSCALL_NAME_SETVSYNCFLAG "(ptr1 = 0x%0.8X, ptr2 = 0x%0.8X);", \
|
2008-11-10 01:46:02 +00:00
|
|
|
m_ee.m_State.nGPR[SC_PARAM0].nV[0], \
|
|
|
|
m_ee.m_State.nGPR[SC_PARAM1].nV[0]);
|
|
|
|
break;
|
|
|
|
case 0x74:
|
2014-08-27 01:07:09 -04:00
|
|
|
sprintf(description, "SetSyscall(num = 0x%0.2X, address = 0x%0.8X);", \
|
2008-11-10 01:46:02 +00:00
|
|
|
m_ee.m_State.nGPR[SC_PARAM0].nV[0], \
|
|
|
|
m_ee.m_State.nGPR[SC_PARAM1].nV[0]);
|
|
|
|
break;
|
|
|
|
case 0x76:
|
2014-08-27 01:07:09 -04:00
|
|
|
sprintf(description, SYSCALL_NAME_SIFDMASTAT "();");
|
2008-11-10 01:46:02 +00:00
|
|
|
break;
|
|
|
|
case 0x77:
|
2014-08-27 01:07:09 -04:00
|
|
|
sprintf(description, SYSCALL_NAME_SIFSETDMA "(list = 0x%0.8X, count = %i);", \
|
2008-11-10 01:46:02 +00:00
|
|
|
m_ee.m_State.nGPR[SC_PARAM0].nV[0], \
|
|
|
|
m_ee.m_State.nGPR[SC_PARAM1].nV[0]);
|
|
|
|
break;
|
|
|
|
case 0x78:
|
2014-08-27 01:07:09 -04:00
|
|
|
sprintf(description, SYSCALL_NAME_SIFSETDCHAIN "();");
|
2008-11-10 01:46:02 +00:00
|
|
|
break;
|
|
|
|
case 0x79:
|
2014-08-27 01:07:09 -04:00
|
|
|
sprintf(description, "SifSetReg(register = 0x%0.8X, value = 0x%0.8X);", \
|
2008-11-10 01:46:02 +00:00
|
|
|
m_ee.m_State.nGPR[SC_PARAM0].nV[0], \
|
|
|
|
m_ee.m_State.nGPR[SC_PARAM1].nV[0]);
|
|
|
|
break;
|
|
|
|
case 0x7A:
|
2014-08-27 01:07:09 -04:00
|
|
|
sprintf(description, "SifGetReg(register = 0x%0.8X);", \
|
2008-11-10 01:46:02 +00:00
|
|
|
m_ee.m_State.nGPR[SC_PARAM0].nV[0]);
|
|
|
|
break;
|
|
|
|
case 0x7C:
|
2015-03-05 12:08:07 -08:00
|
|
|
sprintf(description, SYSCALL_NAME_DECI2CALL "(func = 0x%0.8X, param = 0x%0.8X);",
|
|
|
|
m_ee.m_State.nGPR[SC_PARAM0].nV[0],
|
2008-11-10 01:46:02 +00:00
|
|
|
m_ee.m_State.nGPR[SC_PARAM1].nV[0]);
|
|
|
|
break;
|
|
|
|
case 0x7F:
|
2014-08-27 01:07:09 -04:00
|
|
|
sprintf(description, "GetMemorySize();");
|
2008-11-10 01:46:02 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
return std::string(description);
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////
|
|
|
|
//System Call Handlers Table
|
|
|
|
//////////////////////////////////////////////////
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
CPS2OS::SystemCallHandler CPS2OS::m_sysCall[0x80] =
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
|
|
|
//0x00
|
2014-09-29 01:27:13 -04:00
|
|
|
&CPS2OS::sc_Unhandled, &CPS2OS::sc_Unhandled, &CPS2OS::sc_GsSetCrt, &CPS2OS::sc_Unhandled, &CPS2OS::sc_Unhandled, &CPS2OS::sc_Unhandled, &CPS2OS::sc_LoadExecPS2, &CPS2OS::sc_Unhandled,
|
2008-11-10 01:46:02 +00:00
|
|
|
//0x08
|
2014-09-29 01:27:13 -04:00
|
|
|
&CPS2OS::sc_Unhandled, &CPS2OS::sc_Unhandled, &CPS2OS::sc_Unhandled, &CPS2OS::sc_Unhandled, &CPS2OS::sc_Unhandled, &CPS2OS::sc_Unhandled, &CPS2OS::sc_Unhandled, &CPS2OS::sc_Unhandled,
|
2008-11-10 01:46:02 +00:00
|
|
|
//0x10
|
2014-09-29 01:27:13 -04:00
|
|
|
&CPS2OS::sc_AddIntcHandler, &CPS2OS::sc_RemoveIntcHandler, &CPS2OS::sc_AddDmacHandler, &CPS2OS::sc_RemoveDmacHandler, &CPS2OS::sc_EnableIntc, &CPS2OS::sc_DisableIntc, &CPS2OS::sc_EnableDmac, &CPS2OS::sc_DisableDmac,
|
2008-11-10 01:46:02 +00:00
|
|
|
//0x18
|
2015-01-28 03:32:18 -05:00
|
|
|
&CPS2OS::sc_SetAlarm, &CPS2OS::sc_Unhandled, &CPS2OS::sc_Unhandled, &CPS2OS::sc_Unhandled, &CPS2OS::sc_Unhandled, &CPS2OS::sc_Unhandled, &CPS2OS::sc_Unhandled, &CPS2OS::sc_ReleaseAlarm,
|
2008-11-10 01:46:02 +00:00
|
|
|
//0x20
|
2014-09-29 01:27:13 -04:00
|
|
|
&CPS2OS::sc_CreateThread, &CPS2OS::sc_DeleteThread, &CPS2OS::sc_StartThread, &CPS2OS::sc_ExitThread, &CPS2OS::sc_Unhandled, &CPS2OS::sc_TerminateThread, &CPS2OS::sc_Unhandled, &CPS2OS::sc_Unhandled,
|
2008-11-10 01:46:02 +00:00
|
|
|
//0x28
|
2014-09-29 01:27:13 -04:00
|
|
|
&CPS2OS::sc_Unhandled, &CPS2OS::sc_ChangeThreadPriority, &CPS2OS::sc_ChangeThreadPriority, &CPS2OS::sc_RotateThreadReadyQueue, &CPS2OS::sc_Unhandled, &CPS2OS::sc_Unhandled, &CPS2OS::sc_Unhandled, &CPS2OS::sc_GetThreadId,
|
2008-11-10 01:46:02 +00:00
|
|
|
//0x30
|
2014-09-29 01:27:13 -04:00
|
|
|
&CPS2OS::sc_ReferThreadStatus, &CPS2OS::sc_ReferThreadStatus, &CPS2OS::sc_SleepThread, &CPS2OS::sc_WakeupThread, &CPS2OS::sc_WakeupThread, &CPS2OS::sc_CancelWakeupThread, &CPS2OS::sc_CancelWakeupThread, &CPS2OS::sc_SuspendThread,
|
2008-11-10 01:46:02 +00:00
|
|
|
//0x38
|
2014-09-29 01:27:13 -04:00
|
|
|
&CPS2OS::sc_Unhandled, &CPS2OS::sc_ResumeThread, &CPS2OS::sc_Unhandled, &CPS2OS::sc_Unhandled, &CPS2OS::sc_SetupThread, &CPS2OS::sc_SetupHeap, &CPS2OS::sc_EndOfHeap, &CPS2OS::sc_Unhandled,
|
2008-11-10 01:46:02 +00:00
|
|
|
//0x40
|
2014-09-29 01:27:13 -04:00
|
|
|
&CPS2OS::sc_CreateSema, &CPS2OS::sc_DeleteSema, &CPS2OS::sc_SignalSema, &CPS2OS::sc_SignalSema, &CPS2OS::sc_WaitSema, &CPS2OS::sc_PollSema, &CPS2OS::sc_PollSema, &CPS2OS::sc_ReferSemaStatus,
|
2008-11-10 01:46:02 +00:00
|
|
|
//0x48
|
2014-09-29 01:27:13 -04:00
|
|
|
&CPS2OS::sc_ReferSemaStatus, &CPS2OS::sc_Unhandled, &CPS2OS::sc_Unhandled, &CPS2OS::sc_Unhandled, &CPS2OS::sc_Unhandled, &CPS2OS::sc_Unhandled, &CPS2OS::sc_Unhandled, &CPS2OS::sc_Unhandled,
|
2008-11-10 01:46:02 +00:00
|
|
|
//0x50
|
2014-09-29 01:27:13 -04:00
|
|
|
&CPS2OS::sc_Unhandled, &CPS2OS::sc_Unhandled, &CPS2OS::sc_Unhandled, &CPS2OS::sc_Unhandled, &CPS2OS::sc_Unhandled, &CPS2OS::sc_Unhandled, &CPS2OS::sc_Unhandled, &CPS2OS::sc_Unhandled,
|
2008-11-10 01:46:02 +00:00
|
|
|
//0x58
|
2014-09-29 01:27:13 -04:00
|
|
|
&CPS2OS::sc_Unhandled, &CPS2OS::sc_Unhandled, &CPS2OS::sc_Unhandled, &CPS2OS::sc_Unhandled, &CPS2OS::sc_Unhandled, &CPS2OS::sc_Unhandled, &CPS2OS::sc_Unhandled, &CPS2OS::sc_Unhandled,
|
2008-11-10 01:46:02 +00:00
|
|
|
//0x60
|
2014-09-29 01:27:13 -04:00
|
|
|
&CPS2OS::sc_Unhandled, &CPS2OS::sc_Unhandled, &CPS2OS::sc_Unhandled, &CPS2OS::sc_Unhandled, &CPS2OS::sc_FlushCache, &CPS2OS::sc_Unhandled, &CPS2OS::sc_Unhandled, &CPS2OS::sc_Unhandled,
|
2008-11-10 01:46:02 +00:00
|
|
|
//0x68
|
2014-09-29 01:27:13 -04:00
|
|
|
&CPS2OS::sc_FlushCache, &CPS2OS::sc_Unhandled, &CPS2OS::sc_Unhandled, &CPS2OS::sc_Unhandled, &CPS2OS::sc_Unhandled, &CPS2OS::sc_Unhandled, &CPS2OS::sc_Unhandled, &CPS2OS::sc_Unhandled,
|
2008-11-10 01:46:02 +00:00
|
|
|
//0x70
|
2014-09-29 01:27:13 -04:00
|
|
|
&CPS2OS::sc_GsGetIMR, &CPS2OS::sc_GsPutIMR, &CPS2OS::sc_Unhandled, &CPS2OS::sc_SetVSyncFlag, &CPS2OS::sc_SetSyscall, &CPS2OS::sc_Unhandled, &CPS2OS::sc_SifDmaStat, &CPS2OS::sc_SifSetDma,
|
2008-11-10 01:46:02 +00:00
|
|
|
//0x78
|
2014-09-29 01:27:13 -04:00
|
|
|
&CPS2OS::sc_SifSetDChain, &CPS2OS::sc_SifSetReg, &CPS2OS::sc_SifGetReg, &CPS2OS::sc_Unhandled, &CPS2OS::sc_Deci2Call, &CPS2OS::sc_Unhandled, &CPS2OS::sc_Unhandled, &CPS2OS::sc_GetMemorySize,
|
2008-11-10 01:46:02 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////
|
|
|
|
//Round Ribbon Implementation
|
|
|
|
//////////////////////////////////////////////////
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
CPS2OS::CRoundRibbon::CRoundRibbon(void* memory, uint32 size)
|
|
|
|
: m_node(reinterpret_cast<NODE*>(memory))
|
|
|
|
, m_maxNode(size / sizeof(NODE))
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
memset(memory, 0, size);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
NODE* head = GetNode(0);
|
|
|
|
head->indexNext = -1;
|
|
|
|
head->weight = -1;
|
|
|
|
head->valid = 1;
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CPS2OS::CRoundRibbon::~CRoundRibbon()
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
unsigned int CPS2OS::CRoundRibbon::Insert(uint32 value, uint32 weight)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
|
|
|
//Initialize the new node
|
2014-08-27 01:07:09 -04:00
|
|
|
NODE* node = AllocateNode();
|
|
|
|
if(node == NULL) return -1;
|
|
|
|
node->weight = weight;
|
|
|
|
node->value = value;
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
//Insert node in list
|
2014-08-27 01:07:09 -04:00
|
|
|
NODE* next = GetNode(0);
|
|
|
|
NODE* prev = NULL;
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
while(1)
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
if(next == NULL)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
|
|
|
//We must insert there...
|
2014-08-27 01:07:09 -04:00
|
|
|
node->indexNext = prev->indexNext;
|
|
|
|
prev->indexNext = GetNodeIndex(node);
|
2008-11-10 01:46:02 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
if(next->weight == -1)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
prev = next;
|
|
|
|
next = GetNode(next->indexNext);
|
2008-11-10 01:46:02 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
if(node->weight < next->weight)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
next = NULL;
|
2008-11-10 01:46:02 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
prev = next;
|
|
|
|
next = GetNode(next->indexNext);
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
return GetNodeIndex(node);
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
void CPS2OS::CRoundRibbon::Remove(unsigned int index)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
if(index == 0) return;
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
NODE* curr = GetNode(index);
|
|
|
|
if(curr == NULL) return;
|
|
|
|
if(curr->valid != 1) return;
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
NODE* node = GetNode(0);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
|
|
|
while(1)
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
if(node == NULL) break;
|
|
|
|
assert(node->valid);
|
2008-11-10 01:46:02 +00:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
if(node->indexNext == index)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
node->indexNext = curr->indexNext;
|
2008-11-10 01:46:02 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
node = GetNode(node->indexNext);
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
FreeNode(curr);
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int CPS2OS::CRoundRibbon::Begin()
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
return GetNode(0)->indexNext;
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
CPS2OS::CRoundRibbon::NODE* CPS2OS::CRoundRibbon::GetNode(unsigned int index)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
if(index >= m_maxNode) return NULL;
|
|
|
|
return m_node + index;
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
unsigned int CPS2OS::CRoundRibbon::GetNodeIndex(NODE* node)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
return (unsigned int)(node - m_node);
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CPS2OS::CRoundRibbon::NODE* CPS2OS::CRoundRibbon::AllocateNode()
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
for(unsigned int i = 1; i < m_maxNode; i++)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
NODE* node = GetNode(i);
|
|
|
|
if(node->valid == 1) continue;
|
|
|
|
node->valid = 1;
|
|
|
|
return node;
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
void CPS2OS::CRoundRibbon::FreeNode(NODE* node)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
node->valid = 0;
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CPS2OS::CRoundRibbon::ITERATOR::ITERATOR(CRoundRibbon* pRibbon)
|
2014-08-27 01:07:09 -04:00
|
|
|
: m_ribbon(pRibbon)
|
|
|
|
, m_index(0)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2012-04-23 02:55:30 +00:00
|
|
|
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
CPS2OS::CRoundRibbon::ITERATOR& CPS2OS::CRoundRibbon::ITERATOR::operator =(unsigned int index)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
m_index = index;
|
2008-11-10 01:46:02 +00:00
|
|
|
return (*this);
|
|
|
|
}
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
CPS2OS::CRoundRibbon::ITERATOR& CPS2OS::CRoundRibbon::ITERATOR::operator ++(int)
|
2008-11-10 01:46:02 +00:00
|
|
|
{
|
|
|
|
if(!IsEnd())
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
NODE* node = m_ribbon->GetNode(m_index);
|
|
|
|
m_index = node->indexNext;
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return (*this);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32 CPS2OS::CRoundRibbon::ITERATOR::GetValue()
|
|
|
|
{
|
|
|
|
if(!IsEnd())
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
return m_ribbon->GetNode(m_index)->value;
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32 CPS2OS::CRoundRibbon::ITERATOR::GetWeight()
|
|
|
|
{
|
|
|
|
if(!IsEnd())
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
return m_ribbon->GetNode(m_index)->weight;
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int CPS2OS::CRoundRibbon::ITERATOR::GetIndex()
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
return m_index;
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool CPS2OS::CRoundRibbon::ITERATOR::IsEnd()
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
if(m_ribbon == NULL) return true;
|
|
|
|
return m_ribbon->GetNode(m_index) == NULL;
|
2008-11-10 01:46:02 +00:00
|
|
|
}
|
2014-07-04 01:55:09 -04:00
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//Debug Stuff
|
|
|
|
|
|
|
|
#ifdef DEBUGGER_INCLUDED
|
|
|
|
|
2014-07-04 02:18:14 -04:00
|
|
|
BiosDebugModuleInfoArray CPS2OS::GetModulesDebugInfo() const
|
2014-07-04 01:55:09 -04:00
|
|
|
{
|
|
|
|
BiosDebugModuleInfoArray result;
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
if(m_elf)
|
2014-07-04 01:55:09 -04:00
|
|
|
{
|
|
|
|
auto executableRange = GetExecutableRange();
|
|
|
|
|
|
|
|
BIOS_DEBUG_MODULE_INFO module;
|
|
|
|
module.name = m_executableName;
|
|
|
|
module.begin = executableRange.first;
|
|
|
|
module.end = executableRange.second;
|
2014-08-27 01:07:09 -04:00
|
|
|
module.param = m_elf;
|
2014-07-04 01:55:09 -04:00
|
|
|
result.push_back(module);
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2014-07-04 02:18:14 -04:00
|
|
|
BiosDebugThreadInfoArray CPS2OS::GetThreadsDebugInfo() const
|
2014-07-04 01:55:09 -04:00
|
|
|
{
|
|
|
|
BiosDebugThreadInfoArray threadInfos;
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
CRoundRibbon::ITERATOR threadIterator(m_threadSchedule);
|
2014-07-04 01:55:09 -04:00
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
for(threadIterator = m_threadSchedule->Begin();
|
2014-07-04 01:55:09 -04:00
|
|
|
!threadIterator.IsEnd(); threadIterator++)
|
|
|
|
{
|
|
|
|
auto thread = GetThread(threadIterator.GetValue());
|
2015-01-31 23:05:56 -05:00
|
|
|
auto threadContext = reinterpret_cast<THREADCONTEXT*>(GetStructPtr(thread->contextPtr));
|
2014-07-04 01:55:09 -04:00
|
|
|
|
|
|
|
BIOS_DEBUG_THREAD_INFO threadInfo;
|
|
|
|
threadInfo.id = threadIterator.GetValue();
|
2014-08-27 01:07:09 -04:00
|
|
|
threadInfo.priority = thread->priority;
|
2014-07-04 01:55:09 -04:00
|
|
|
if(GetCurrentThreadId() == threadIterator.GetValue())
|
|
|
|
{
|
|
|
|
threadInfo.pc = m_ee.m_State.nPC;
|
|
|
|
threadInfo.ra = m_ee.m_State.nGPR[CMIPS::RA].nV0;
|
|
|
|
threadInfo.sp = m_ee.m_State.nGPR[CMIPS::SP].nV0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-08-27 01:07:09 -04:00
|
|
|
threadInfo.pc = thread->epc;
|
2014-08-27 00:10:31 -04:00
|
|
|
threadInfo.ra = threadContext->gpr[CMIPS::RA].nV0;
|
|
|
|
threadInfo.sp = threadContext->gpr[CMIPS::SP].nV0;
|
2014-07-04 01:55:09 -04:00
|
|
|
}
|
|
|
|
|
2014-08-27 01:07:09 -04:00
|
|
|
switch(thread->status)
|
2014-07-04 01:55:09 -04:00
|
|
|
{
|
|
|
|
case THREAD_RUNNING:
|
|
|
|
threadInfo.stateDescription = "Running";
|
|
|
|
break;
|
|
|
|
case THREAD_SLEEPING:
|
|
|
|
threadInfo.stateDescription = "Sleeping";
|
|
|
|
break;
|
|
|
|
case THREAD_WAITING:
|
2014-08-27 01:07:09 -04:00
|
|
|
threadInfo.stateDescription = "Waiting (Semaphore: " + boost::lexical_cast<std::string>(thread->semaWait) + ")";
|
2014-07-04 01:55:09 -04:00
|
|
|
break;
|
|
|
|
case THREAD_SUSPENDED:
|
|
|
|
threadInfo.stateDescription = "Suspended";
|
|
|
|
break;
|
|
|
|
case THREAD_SUSPENDED_SLEEPING:
|
|
|
|
threadInfo.stateDescription = "Suspended+Sleeping";
|
|
|
|
break;
|
|
|
|
case THREAD_SUSPENDED_WAITING:
|
2014-08-27 01:07:09 -04:00
|
|
|
threadInfo.stateDescription = "Suspended+Waiting (Semaphore: " + boost::lexical_cast<std::string>(thread->semaWait) + ")";
|
2014-07-04 01:55:09 -04:00
|
|
|
break;
|
|
|
|
case THREAD_ZOMBIE:
|
|
|
|
threadInfo.stateDescription = "Zombie";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
threadInfo.stateDescription = "Unknown";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
threadInfos.push_back(threadInfo);
|
|
|
|
}
|
|
|
|
|
|
|
|
return threadInfos;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|