2019-08-17 13:51:31 -04:00
# include <cstring>
2015-05-06 00:54:15 -04:00
# include <stddef.h>
# include <stdlib.h>
# include <exception>
2017-02-26 23:14:17 +00:00
# include "string_format.h"
2015-05-06 00:54:15 -04:00
# include "PS2OS.h"
# include "StdStream.h"
2016-05-23 13:30:46 -04:00
# ifdef __ANDROID__
# include "android/AssetStream.h"
# endif
2015-05-06 00:54:15 -04:00
# include "../Ps2Const.h"
2015-07-22 00:30:06 -04:00
# include "../DiskUtils.h"
2015-05-06 00:54:15 -04:00
# include "../ElfFile.h"
# include "../COP_SCU.h"
# include "../uint128.h"
# include "../Log.h"
# include "../iop/IopBios.h"
# include "DMAC.h"
# include "INTC.h"
2019-01-02 21:34:29 -05:00
# include "Timer.h"
2015-05-06 00:54:15 -04:00
# include "SIF.h"
# include "EEAssembler.h"
# include "PathUtils.h"
# include "xml/Node.h"
# include "xml/Parser.h"
# include "xml/FilteringNodeIterator.h"
# include "StdStreamUtils.h"
2020-09-09 17:13:17 -04:00
# include "AppConfig.h"
# include "PS2VM_Preferences.h"
2015-05-06 00:54:15 -04:00
// PS2OS Memory Allocation
// Start End Description
// 0x80000010 0x80000014 Current Thread ID
// 0x80008000 0x8000A000 DECI2 Handlers
// 0x8000A000 0x8000C000 INTC Handlers
// 0x8000C000 0x8000E000 DMAC Handlers
// 0x8000E000 0x80010000 Semaphores
// 0x80010000 0x80010800 Custom System Call addresses (0x200 entries)
// 0x80010800 0x80011000 Alarms
// 0x80011000 0x80020000 Threads
// 0x80020000 0x80030000 Kernel Stack
// 0x80030000 0x80032000 Thread Linked List
// BIOS area
// Start End Description
// 0x1FC00100 0x1FC00200 Custom System Call handling code
// 0x1FC00200 0x1FC01000 Interrupt Handler
// 0x1FC01000 0x1FC02000 DMAC Handler
// 0x1FC02000 0x1FC03000 INTC Handler
// 0x1FC03000 0x1FC03100 Thread epilogue
// 0x1FC03100 0x1FC03200 Wait Thread Proc
// 0x1FC03200 0x1FC03300 Alarm Handler
2019-01-15 10:11:36 +08:00
# define BIOS_SIFDMA_COUNT 0x20
2018-04-30 21:01:23 +01:00
# define BIOS_ADDRESS_KERNELSTACK_TOP 0x00030000
# define BIOS_ADDRESS_IDLE_THREAD_ID 0x00000010
# define BIOS_ADDRESS_CURRENT_THREAD_ID 0x00000014
# define BIOS_ADDRESS_VSYNCFLAG_VALUE1PTR 0x00000018
# define BIOS_ADDRESS_VSYNCFLAG_VALUE2PTR 0x0000001C
# define BIOS_ADDRESS_THREADSCHEDULE_BASE 0x00000020
# define BIOS_ADDRESS_INTCHANDLERQUEUE_BASE 0x00000024
# define BIOS_ADDRESS_DMACHANDLERQUEUE_BASE 0x00000028
2019-02-21 18:51:00 -05:00
# define BIOS_ADDRESS_TLB_READEXCEPTION_HANDLER 0x0000002C
# define BIOS_ADDRESS_TLB_WRITEEXCEPTION_HANDLER 0x00000030
# define BIOS_ADDRESS_SIFDMA_NEXT_INDEX 0x00000034
# define BIOS_ADDRESS_SIFDMA_TIMES_BASE 0x00000038
2019-02-09 11:16:59 -05:00
# define BIOS_ADDRESS_SIFDMA_TIMES_END (BIOS_ADDRESS_SIFDMA_TIMES_BASE + (4 * BIOS_SIFDMA_COUNT))
2019-02-09 11:26:48 -05:00
# define BIOS_ADDRESS_INTERRUPT_THREAD_CONTEXT BIOS_ADDRESS_SIFDMA_TIMES_END
2018-04-30 21:01:23 +01:00
# define BIOS_ADDRESS_INTCHANDLER_BASE 0x0000A000
# define BIOS_ADDRESS_DMACHANDLER_BASE 0x0000C000
# define BIOS_ADDRESS_SEMAPHORE_BASE 0x0000E000
2019-05-23 21:13:37 -04:00
# define BIOS_ADDRESS_CUSTOMSYSCALL_BASE 0x00010000
2018-04-30 21:01:23 +01:00
# define BIOS_ADDRESS_ALARM_BASE 0x00010800
# define BIOS_ADDRESS_THREAD_BASE 0x00011000
# define BIOS_ADDRESS_BASE 0x1FC00000
# define BIOS_ADDRESS_INTERRUPTHANDLER 0x1FC00200
# define BIOS_ADDRESS_DMACHANDLER 0x1FC01000
# define BIOS_ADDRESS_INTCHANDLER 0x1FC02000
# define BIOS_ADDRESS_THREADEPILOG 0x1FC03000
# define BIOS_ADDRESS_IDLETHREADPROC 0x1FC03100
# define BIOS_ADDRESS_ALARMHANDLER 0x1FC03200
# define BIOS_ID_BASE 1
2021-04-22 16:23:27 -04:00
//Some notes about SEMA_ID_BASE:
// 2K games (ex.: NBA 2K12) seem to have a bug where they wait for a semaphore they don't own.
// The semaphore id is never set and the game will use the id in WaitSema and SignalSema.
2021-04-22 17:16:12 -04:00
// On a real PS2, this seem to work because ids start at 0. The first semaphore created in the
2021-04-22 16:23:27 -04:00
// game's lifetime doesn't seem to be used, so this bug probably doesn't have any side effect.
# define SEMA_ID_BASE 0
2018-04-30 21:01:23 +01:00
# define PATCHESFILENAME "patches.xml"
# define LOG_NAME ("ps2os")
2019-02-09 11:16:59 -05:00
# define SYSCALL_CUSTOM_RESCHEDULE 0x666
2019-02-09 11:26:48 -05:00
# define SYSCALL_CUSTOM_EXITINTERRUPT 0x667
2019-02-09 11:16:59 -05:00
2018-04-30 21:01:23 +01:00
# define SYSCALL_NAME_EXIT "osExit"
# define SYSCALL_NAME_LOADEXECPS2 "osLoadExecPS2"
# define SYSCALL_NAME_EXECPS2 "osExecPS2"
2018-08-27 07:31:18 -04:00
# define SYSCALL_NAME_SETVTLBREFILLHANDLER "osSetVTLBRefillHandler"
# define SYSCALL_NAME_SETVCOMMONHANDLER "osSetVCommonHandler"
2018-04-30 21:01:23 +01:00
# define SYSCALL_NAME_ADDINTCHANDLER "osAddIntcHandler"
# define SYSCALL_NAME_REMOVEINTCHANDLER "osRemoveIntcHandler"
# define SYSCALL_NAME_ADDDMACHANDLER "osAddDmacHandler"
# define SYSCALL_NAME_REMOVEDMACHANDLER "osRemoveDmacHandler"
# define SYSCALL_NAME_ENABLEINTC "osEnableIntc"
# define SYSCALL_NAME_DISABLEINTC "osDisableIntc"
# define SYSCALL_NAME_ENABLEDMAC "osEnableDmac"
# define SYSCALL_NAME_DISABLEDMAC "osDisableDmac"
# define SYSCALL_NAME_SETALARM "osSetAlarm"
# define SYSCALL_NAME_IENABLEINTC "osiEnableIntc"
# define SYSCALL_NAME_IDISABLEINTC "osiDisableIntc"
# define SYSCALL_NAME_IENABLEDMAC "osiEnableDmac"
# define SYSCALL_NAME_IDISABLEDMAC "osiDisableDmac"
2019-08-16 07:49:13 -04:00
# define SYSCALL_NAME_ISETALARM "osiSetAlarm"
2018-04-30 21:01:23 +01:00
# define SYSCALL_NAME_IRELEASEALARM "osiReleaseAlarm"
# define SYSCALL_NAME_CREATETHREAD "osCreateThread"
# define SYSCALL_NAME_DELETETHREAD "osDeleteThread"
# define SYSCALL_NAME_STARTTHREAD "osStartThread"
# define SYSCALL_NAME_EXITTHREAD "osExitThread"
# define SYSCALL_NAME_EXITDELETETHREAD "osExitDeleteThread"
# define SYSCALL_NAME_TERMINATETHREAD "osTerminateThread"
# define SYSCALL_NAME_CHANGETHREADPRIORITY "osChangeThreadPriority"
# define SYSCALL_NAME_ICHANGETHREADPRIORITY "osiChangeThreadPriority"
# define SYSCALL_NAME_ROTATETHREADREADYQUEUE "osRotateThreadReadyQueue"
2018-06-19 19:12:34 -04:00
# define SYSCALL_NAME_RELEASEWAITTHREAD "osReleaseWaitThread"
# define SYSCALL_NAME_IRELEASEWAITTHREAD "osiReleaseWaitThread"
2018-04-30 21:01:23 +01:00
# define SYSCALL_NAME_GETTHREADID "osGetThreadId"
# define SYSCALL_NAME_REFERTHREADSTATUS "osReferThreadStatus"
# define SYSCALL_NAME_IREFERTHREADSTATUS "osiReferThreadStatus"
2018-05-15 12:44:16 -04:00
# define SYSCALL_NAME_GETOSDCONFIGPARAM "osGetOsdConfigParam"
2018-04-30 21:01:23 +01:00
# define SYSCALL_NAME_SLEEPTHREAD "osSleepThread"
# define SYSCALL_NAME_WAKEUPTHREAD "osWakeupThread"
# define SYSCALL_NAME_IWAKEUPTHREAD "osiWakeupThread"
# define SYSCALL_NAME_CANCELWAKEUPTHREAD "osCancelWakeupThread"
# define SYSCALL_NAME_ICANCELWAKEUPTHREAD "osiCancelWakeupThread"
# define SYSCALL_NAME_SUSPENDTHREAD "osSuspendThread"
# define SYSCALL_NAME_ISUSPENDTHREAD "osiSuspendThread"
# define SYSCALL_NAME_RESUMETHREAD "osResumeThread"
# define SYSCALL_NAME_ENDOFHEAP "osEndOfHeap"
# 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"
# define SYSCALL_NAME_IPOLLSEMA "osiPollSema"
# define SYSCALL_NAME_REFERSEMASTATUS "osReferSemaStatus"
# define SYSCALL_NAME_IREFERSEMASTATUS "osiReferSemaStatus"
# define SYSCALL_NAME_FLUSHCACHE "osFlushCache"
# define SYSCALL_NAME_SIFSTOPDMA "osSifStopDma"
# define SYSCALL_NAME_GSGETIMR "osGsGetIMR"
# define SYSCALL_NAME_GSPUTIMR "osGsPutIMR"
# define SYSCALL_NAME_SETVSYNCFLAG "osSetVSyncFlag"
# define SYSCALL_NAME_SETSYSCALL "osSetSyscall"
# define SYSCALL_NAME_SIFDMASTAT "osSifDmaStat"
# define SYSCALL_NAME_SIFSETDMA "osSifSetDma"
# define SYSCALL_NAME_SIFSETDCHAIN "osSifSetDChain"
# define SYSCALL_NAME_DECI2CALL "osDeci2Call"
# define SYSCALL_NAME_MACHINETYPE "osMachineType"
2015-05-06 00:54:15 -04:00
# ifdef DEBUGGER_INCLUDED
2018-04-30 21:01:23 +01:00
const CPS2OS : : SYSCALL_NAME CPS2OS : : g_syscallNames [ ] =
{
{ 0x0004 , SYSCALL_NAME_EXIT } ,
{ 0x0006 , SYSCALL_NAME_LOADEXECPS2 } ,
{ 0x0007 , SYSCALL_NAME_EXECPS2 } ,
2018-08-27 07:31:18 -04:00
{ 0x000D , SYSCALL_NAME_SETVTLBREFILLHANDLER } ,
{ 0x000E , SYSCALL_NAME_SETVCOMMONHANDLER } ,
2018-04-30 21:01:23 +01:00
{ 0x0010 , SYSCALL_NAME_ADDINTCHANDLER } ,
{ 0x0011 , SYSCALL_NAME_REMOVEINTCHANDLER } ,
{ 0x0012 , SYSCALL_NAME_ADDDMACHANDLER } ,
{ 0x0013 , SYSCALL_NAME_REMOVEDMACHANDLER } ,
{ 0x0014 , SYSCALL_NAME_ENABLEINTC } ,
{ 0x0015 , SYSCALL_NAME_DISABLEINTC } ,
{ 0x0016 , SYSCALL_NAME_ENABLEDMAC } ,
{ 0x0017 , SYSCALL_NAME_DISABLEDMAC } ,
{ 0x0018 , SYSCALL_NAME_SETALARM } ,
{ 0x001A , SYSCALL_NAME_IENABLEINTC } ,
{ 0x001B , SYSCALL_NAME_IDISABLEINTC } ,
{ 0x001C , SYSCALL_NAME_IENABLEDMAC } ,
{ 0x001D , SYSCALL_NAME_IDISABLEDMAC } ,
2019-08-16 07:49:13 -04:00
{ 0x001E , SYSCALL_NAME_ISETALARM } ,
2018-04-30 21:01:23 +01:00
{ 0x001F , SYSCALL_NAME_IRELEASEALARM } ,
{ 0x0020 , SYSCALL_NAME_CREATETHREAD } ,
{ 0x0021 , SYSCALL_NAME_DELETETHREAD } ,
{ 0x0022 , SYSCALL_NAME_STARTTHREAD } ,
{ 0x0023 , SYSCALL_NAME_EXITTHREAD } ,
{ 0x0024 , SYSCALL_NAME_EXITDELETETHREAD } ,
{ 0x0025 , SYSCALL_NAME_TERMINATETHREAD } ,
{ 0x0029 , SYSCALL_NAME_CHANGETHREADPRIORITY } ,
{ 0x002A , SYSCALL_NAME_ICHANGETHREADPRIORITY } ,
{ 0x002B , SYSCALL_NAME_ROTATETHREADREADYQUEUE } ,
2018-06-19 19:12:34 -04:00
{ 0x002D , SYSCALL_NAME_RELEASEWAITTHREAD } ,
{ 0x002E , SYSCALL_NAME_IRELEASEWAITTHREAD } ,
2018-04-30 21:01:23 +01:00
{ 0x002F , SYSCALL_NAME_GETTHREADID } ,
{ 0x0030 , SYSCALL_NAME_REFERTHREADSTATUS } ,
{ 0x0031 , SYSCALL_NAME_IREFERTHREADSTATUS } ,
{ 0x0032 , SYSCALL_NAME_SLEEPTHREAD } ,
{ 0x0033 , SYSCALL_NAME_WAKEUPTHREAD } ,
{ 0x0034 , SYSCALL_NAME_IWAKEUPTHREAD } ,
{ 0x0035 , SYSCALL_NAME_CANCELWAKEUPTHREAD } ,
{ 0x0036 , SYSCALL_NAME_ICANCELWAKEUPTHREAD } ,
{ 0x0037 , SYSCALL_NAME_SUSPENDTHREAD } ,
{ 0x0038 , SYSCALL_NAME_ISUSPENDTHREAD } ,
{ 0x0039 , SYSCALL_NAME_RESUMETHREAD } ,
{ 0x003E , SYSCALL_NAME_ENDOFHEAP } ,
{ 0x0040 , SYSCALL_NAME_CREATESEMA } ,
{ 0x0041 , SYSCALL_NAME_DELETESEMA } ,
{ 0x0042 , SYSCALL_NAME_SIGNALSEMA } ,
{ 0x0043 , SYSCALL_NAME_ISIGNALSEMA } ,
{ 0x0044 , SYSCALL_NAME_WAITSEMA } ,
{ 0x0045 , SYSCALL_NAME_POLLSEMA } ,
{ 0x0046 , SYSCALL_NAME_IPOLLSEMA } ,
{ 0x0047 , SYSCALL_NAME_REFERSEMASTATUS } ,
{ 0x0048 , SYSCALL_NAME_IREFERSEMASTATUS } ,
2018-05-15 12:44:16 -04:00
{ 0x004B , SYSCALL_NAME_GETOSDCONFIGPARAM } ,
2018-04-30 21:01:23 +01:00
{ 0x0064 , SYSCALL_NAME_FLUSHCACHE } ,
{ 0x006B , SYSCALL_NAME_SIFSTOPDMA } ,
{ 0x0070 , SYSCALL_NAME_GSGETIMR } ,
{ 0x0071 , SYSCALL_NAME_GSPUTIMR } ,
{ 0x0073 , SYSCALL_NAME_SETVSYNCFLAG } ,
{ 0x0074 , SYSCALL_NAME_SETSYSCALL } ,
{ 0x0076 , SYSCALL_NAME_SIFDMASTAT } ,
{ 0x0077 , SYSCALL_NAME_SIFSETDMA } ,
{ 0x0078 , SYSCALL_NAME_SIFSETDCHAIN } ,
{ 0x007C , SYSCALL_NAME_DECI2CALL } ,
{ 0x007E , SYSCALL_NAME_MACHINETYPE } ,
{ 0x0000 , NULL } } ;
2015-05-06 00:54:15 -04:00
# endif
2018-04-30 21:01:23 +01:00
CPS2OS : : CPS2OS ( CMIPS & ee , uint8 * ram , uint8 * bios , uint8 * spr , CGSHandler * & gs , CSIF & sif , CIopBios & iopBios )
: m_ee ( ee )
, m_gs ( gs )
, m_ram ( ram )
, m_bios ( bios )
, m_spr ( spr )
, m_sif ( sif )
2020-03-25 08:02:59 -04:00
, m_libMc2 ( ram , iopBios )
2018-04-30 21:01:23 +01:00
, m_iopBios ( iopBios )
, m_threads ( reinterpret_cast < THREAD * > ( m_ram + BIOS_ADDRESS_THREAD_BASE ) , BIOS_ID_BASE , MAX_THREAD )
2021-04-22 16:23:27 -04:00
, m_semaphores ( reinterpret_cast < SEMAPHORE * > ( m_ram + BIOS_ADDRESS_SEMAPHORE_BASE ) , SEMA_ID_BASE , MAX_SEMAPHORE )
2018-04-30 21:01:23 +01:00
, m_intcHandlers ( reinterpret_cast < INTCHANDLER * > ( m_ram + BIOS_ADDRESS_INTCHANDLER_BASE ) , BIOS_ID_BASE , MAX_INTCHANDLER )
, 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 )
, m_currentThreadId ( reinterpret_cast < uint32 * > ( m_ram + BIOS_ADDRESS_CURRENT_THREAD_ID ) )
, m_idleThreadId ( reinterpret_cast < uint32 * > ( m_ram + BIOS_ADDRESS_IDLE_THREAD_ID ) )
2019-02-22 12:43:00 -05:00
, m_tlblExceptionHandler ( reinterpret_cast < uint32 * > ( m_ram + BIOS_ADDRESS_TLB_READEXCEPTION_HANDLER ) )
, m_tlbsExceptionHandler ( reinterpret_cast < uint32 * > ( m_ram + BIOS_ADDRESS_TLB_WRITEEXCEPTION_HANDLER ) )
2019-01-15 10:11:36 +08:00
, m_sifDmaNextIdx ( reinterpret_cast < uint32 * > ( m_ram + BIOS_ADDRESS_SIFDMA_NEXT_INDEX ) )
, m_sifDmaTimes ( reinterpret_cast < uint32 * > ( m_ram + BIOS_ADDRESS_SIFDMA_TIMES_BASE ) )
2018-04-30 21:01:23 +01:00
, m_threadSchedule ( m_threads , reinterpret_cast < uint32 * > ( m_ram + BIOS_ADDRESS_THREADSCHEDULE_BASE ) )
, m_intcHandlerQueue ( m_intcHandlers , reinterpret_cast < uint32 * > ( m_ram + BIOS_ADDRESS_INTCHANDLERQUEUE_BASE ) )
, m_dmacHandlerQueue ( m_dmacHandlers , reinterpret_cast < uint32 * > ( m_ram + BIOS_ADDRESS_DMACHANDLERQUEUE_BASE ) )
2015-05-06 00:54:15 -04:00
{
2019-05-23 21:14:00 -04:00
static_assert ( ( BIOS_ADDRESS_SEMAPHORE_BASE + ( sizeof ( SEMAPHORE ) * MAX_SEMAPHORE ) ) < = BIOS_ADDRESS_CUSTOMSYSCALL_BASE , " Semaphore overflow " ) ;
2020-09-09 17:13:17 -04:00
CAppConfig : : GetInstance ( ) . RegisterPreferenceInteger ( PREF_SYSTEM_LANGUAGE , static_cast < uint32 > ( OSD_LANGUAGE : : JAPANESE ) ) ;
2015-05-06 00:54:15 -04:00
}
CPS2OS : : ~ CPS2OS ( )
{
Release ( ) ;
}
void CPS2OS : : Initialize ( )
{
m_elf = nullptr ;
2015-05-15 19:14:03 -04:00
SetVsyncFlagPtrs ( 0 , 0 ) ;
2020-08-05 17:43:36 -04:00
UpdateTLBEnabledState ( ) ;
2015-07-03 21:02:25 -04:00
AssembleCustomSyscallHandler ( ) ;
AssembleInterruptHandler ( ) ;
AssembleDmacHandler ( ) ;
AssembleIntcHandler ( ) ;
AssembleThreadEpilog ( ) ;
2015-08-06 01:20:04 -04:00
AssembleIdleThreadProc ( ) ;
2015-07-03 21:02:25 -04:00
AssembleAlarmHandler ( ) ;
2015-08-06 01:20:04 -04:00
CreateIdleThread ( ) ;
2015-07-03 21:02:25 -04:00
2015-08-06 01:20:04 -04:00
m_ee . m_State . nPC = BIOS_ADDRESS_IDLETHREADPROC ;
2017-08-25 14:12:58 -04:00
m_ee . m_State . nCOP0 [ CCOP_SCU : : STATUS ] | = ( CMIPS : : STATUS_IE | CMIPS : : STATUS_EIE ) ;
2019-01-02 21:34:29 -05:00
//The BIOS enables TIMER3 for alarm purposes, some games (ex.: SoulCalibur 3) assume timer is counting.
m_ee . m_pMemoryMap - > SetWord ( CTimer : : T3_MODE , CTimer : : MODE_CLOCK_SELECT_EXTERNAL | CTimer : : MODE_COUNT_ENABLE | CTimer : : MODE_EQUAL_FLAG | CTimer : : MODE_OVERFLOW_FLAG ) ;
2015-05-06 00:54:15 -04:00
}
void CPS2OS : : Release ( )
{
UnloadExecutable ( ) ;
}
bool CPS2OS : : IsIdle ( ) const
{
2017-08-27 18:43:17 -04:00
return m_ee . CanGenerateInterrupt ( ) & &
2018-04-30 21:01:23 +01:00
( m_currentThreadId = = m_idleThreadId ) ;
2015-05-06 00:54:15 -04:00
}
void CPS2OS : : DumpIntcHandlers ( )
{
printf ( " INTC Handlers Information \r \n " ) ;
printf ( " ------------------------- \r \n " ) ;
for ( unsigned int i = 0 ; i < MAX_INTCHANDLER ; i + + )
{
2015-07-25 20:13:59 -04:00
auto handler = m_intcHandlers [ i + 1 ] ;
if ( handler = = nullptr ) continue ;
2015-05-06 00:54:15 -04:00
2018-04-30 21:01:23 +01:00
printf ( " ID: %02i, Line: %i, Address: 0x%08X. \r \n " ,
i + 1 ,
handler - > cause ,
handler - > address ) ;
2015-05-06 00:54:15 -04:00
}
}
void CPS2OS : : DumpDmacHandlers ( )
{
printf ( " DMAC Handlers Information \r \n " ) ;
printf ( " ------------------------- \r \n " ) ;
for ( unsigned int i = 0 ; i < MAX_DMACHANDLER ; i + + )
{
auto handler = m_dmacHandlers [ i + 1 ] ;
if ( handler = = nullptr ) continue ;
2018-04-30 21:01:23 +01:00
printf ( " ID: %02i, Channel: %i, Address: 0x%08X. \r \n " ,
i + 1 ,
handler - > channel ,
handler - > address ) ;
2015-05-06 00:54:15 -04:00
}
}
2019-10-16 20:51:11 -04:00
void CPS2OS : : BootFromFile ( const fs : : path & execPath )
2015-05-06 00:54:15 -04:00
{
2017-11-01 07:53:21 -04:00
auto stream = Framework : : CreateInputStdStream ( execPath . native ( ) ) ;
2018-02-06 19:05:02 -05:00
auto virtualExecutablePath = " host: " + execPath . filename ( ) . string ( ) ;
LoadELF ( stream , virtualExecutablePath . c_str ( ) , ArgumentList ( ) ) ;
2015-05-06 00:54:15 -04:00
}
2015-12-02 22:40:54 -05:00
void CPS2OS : : BootFromVirtualPath ( const char * executablePath , const ArgumentList & arguments )
{
auto ioman = m_iopBios . GetIoman ( ) ;
uint32 handle = ioman - > Open ( Iop : : Ioman : : CDevice : : OPEN_FLAG_RDONLY , executablePath ) ;
if ( static_cast < int32 > ( handle ) < 0 )
{
throw std : : runtime_error ( " Couldn't open executable specified by virtual path. " ) ;
}
try
{
Framework : : CStream * file ( ioman - > GetFileStream ( handle ) ) ;
2017-08-26 18:01:48 -04:00
LoadELF ( * file , executablePath , arguments ) ;
2015-12-02 22:40:54 -05:00
}
catch ( . . . )
{
throw std : : runtime_error ( " Error occured while reading ELF executable from virtual path. " ) ;
}
ioman - > Close ( handle ) ;
}
void CPS2OS : : BootFromCDROM ( )
2015-05-06 00:54:15 -04:00
{
std : : string executablePath ;
2015-12-02 22:40:54 -05:00
auto ioman = m_iopBios . GetIoman ( ) ;
2015-05-06 00:54:15 -04:00
{
uint32 handle = ioman - > Open ( Iop : : Ioman : : CDevice : : OPEN_FLAG_RDONLY , " cdrom0:SYSTEM.CNF " ) ;
if ( static_cast < int32 > ( handle ) < 0 )
{
throw std : : runtime_error ( " No 'SYSTEM.CNF' file found on the cdrom0 device. " ) ;
}
{
Framework : : CStream * file ( ioman - > GetFileStream ( handle ) ) ;
2015-07-22 00:30:06 -04:00
auto systemConfig = DiskUtils : : ParseSystemConfigFile ( file ) ;
auto bootItemIterator = systemConfig . find ( " BOOT2 " ) ;
if ( bootItemIterator ! = std : : end ( systemConfig ) )
2015-05-06 00:54:15 -04:00
{
2015-07-22 00:30:06 -04:00
executablePath = bootItemIterator - > second ;
2015-05-06 00:54:15 -04:00
}
}
ioman - > Close ( handle ) ;
}
if ( executablePath . length ( ) = = 0 )
{
throw std : : runtime_error ( " Error parsing 'SYSTEM.CNF' for a BOOT2 value. " ) ;
}
2015-12-02 22:40:54 -05:00
BootFromVirtualPath ( executablePath . c_str ( ) , ArgumentList ( ) ) ;
2015-05-06 00:54:15 -04:00
}
CELF * CPS2OS : : GetELF ( )
{
2020-09-09 10:58:50 -04:00
return m_elf . get ( ) ;
2015-05-06 00:54:15 -04:00
}
const char * CPS2OS : : GetExecutableName ( ) const
{
return m_executableName . c_str ( ) ;
}
std : : pair < uint32 , uint32 > CPS2OS : : GetExecutableRange ( ) const
{
uint32 minAddr = 0xFFFFFFF0 ;
uint32 maxAddr = 0x00000000 ;
const ELFHEADER & header = m_elf - > GetHeader ( ) ;
for ( unsigned int i = 0 ; i < header . nProgHeaderCount ; i + + )
{
ELFPROGRAMHEADER * p = m_elf - > GetProgram ( i ) ;
if ( p ! = NULL )
{
//Wild Arms: Alter Code F has zero sized program headers
if ( p - > nFileSize = = 0 ) continue ;
2015-05-15 01:01:24 -04:00
if ( ! ( p - > nFlags & CELF : : PF_X ) ) continue ;
2015-05-06 00:54:15 -04:00
uint32 end = p - > nVAddress + p - > nFileSize ;
if ( end > = PS2 : : EE_RAM_SIZE ) continue ;
minAddr = std : : min < uint32 > ( minAddr , p - > nVAddress ) ;
maxAddr = std : : max < uint32 > ( maxAddr , end ) ;
}
}
return std : : pair < uint32 , uint32 > ( minAddr , maxAddr ) ;
}
2017-08-26 18:01:48 -04:00
void CPS2OS : : LoadELF ( Framework : : CStream & stream , const char * executablePath , const ArgumentList & arguments )
2015-05-06 00:54:15 -04:00
{
2020-09-09 10:58:50 -04:00
auto elf = std : : make_unique < CElfFile > ( stream ) ;
2015-07-03 04:58:53 -04:00
const auto & header = elf - > GetHeader ( ) ;
2015-05-06 00:54:15 -04:00
//Check for MIPS CPU
2015-07-03 04:58:53 -04:00
if ( header . nCPU ! = CELF : : EM_MIPS )
2015-05-06 00:54:15 -04:00
{
throw std : : runtime_error ( " Invalid target CPU. Must be MIPS. " ) ;
}
2015-07-03 04:58:53 -04:00
if ( header . nType ! = CELF : : ET_EXEC )
2015-05-06 00:54:15 -04:00
{
throw std : : runtime_error ( " Not an executable ELF file. " ) ;
}
2018-04-30 21:01:23 +01:00
2015-05-06 00:54:15 -04:00
UnloadExecutable ( ) ;
2020-09-09 10:58:50 -04:00
m_elf = std : : move ( elf ) ;
2015-05-06 00:54:15 -04:00
2018-10-11 12:41:37 -04:00
m_currentArguments . clear ( ) ;
m_currentArguments . push_back ( executablePath ) ;
m_currentArguments . insert ( m_currentArguments . end ( ) , arguments . begin ( ) , arguments . end ( ) ) ;
2015-05-06 00:54:15 -04:00
2018-04-30 21:01:23 +01:00
m_executableName =
[ & ] ( ) {
auto executableName = reinterpret_cast < const char * > ( strchr ( executablePath , ' : ' ) ) ;
if ( ! executableName ) return executablePath ;
executableName + + ;
if ( executableName [ 0 ] = = ' / ' | | executableName [ 0 ] = = ' \\ ' ) executableName + + ;
return executableName ;
} ( ) ;
2017-08-26 18:01:48 -04:00
2015-05-06 00:54:15 -04:00
LoadExecutableInternal ( ) ;
ApplyPatches ( ) ;
OnExecutableChange ( ) ;
2017-08-26 18:01:48 -04:00
CLog : : GetInstance ( ) . Print ( LOG_NAME , " Loaded '%s' executable file. \r \n " , executablePath ) ;
2015-05-06 00:54:15 -04:00
}
void CPS2OS : : LoadExecutableInternal ( )
{
//Copy program in main RAM
const ELFHEADER & header = m_elf - > GetHeader ( ) ;
for ( unsigned int i = 0 ; i < header . nProgHeaderCount ; i + + )
{
auto p = m_elf - > GetProgram ( i ) ;
if ( p ! = nullptr )
{
if ( p - > nVAddress > = PS2 : : EE_RAM_SIZE )
{
assert ( false ) ;
continue ;
}
memcpy ( m_ram + p - > nVAddress , m_elf - > GetContent ( ) + p - > nOffset , p - > nFileSize ) ;
}
}
m_ee . m_State . nPC = header . nEntryPoint ;
2021-06-17 23:05:04 +02:00
m_ee . m_State . nGPR [ CMIPS : : A0 ] . nV [ 0 ] = header . nEntryPoint ;
2018-04-30 21:01:23 +01:00
2015-05-06 00:54:15 -04:00
# ifdef DEBUGGER_INCLUDED
std : : pair < uint32 , uint32 > executableRange = GetExecutableRange ( ) ;
uint32 minAddr = executableRange . first ;
uint32 maxAddr = executableRange . second & ~ 0x03 ;
m_ee . m_analysis - > Clear ( ) ;
m_ee . m_analysis - > Analyse ( minAddr , maxAddr , header . nEntryPoint ) ;
//Tag system calls
for ( uint32 address = minAddr ; address < maxAddr ; address + = 4 )
{
//Check for SYSCALL opcode
uint32 opcode = * reinterpret_cast < uint32 * > ( m_ram + address ) ;
if ( opcode = = 0x0000000C )
{
//Check the opcode before and after it
2018-04-30 21:01:23 +01:00
uint32 addiu = * reinterpret_cast < uint32 * > ( m_ram + address - 4 ) ;
uint32 jr = * reinterpret_cast < uint32 * > ( m_ram + address + 4 ) ;
2015-05-06 00:54:15 -04:00
if (
2018-04-30 21:01:23 +01:00
( jr = = 0x03E00008 ) & &
( addiu & 0xFFFF0000 ) = = 0x24030000 )
2015-05-06 00:54:15 -04:00
{
//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
{
2017-05-29 06:01:32 +01:00
sprintf ( syscallName , " syscall_%04X " , syscallId ) ;
2015-05-06 00:54:15 -04:00
}
m_ee . m_Functions . InsertTag ( address - 4 , syscallName ) ;
}
}
}
# endif
}
void CPS2OS : : UnloadExecutable ( )
{
2020-09-09 10:58:50 -04:00
if ( ! m_elf ) return ;
2015-05-06 00:54:15 -04:00
OnExecutableUnloading ( ) ;
2020-09-09 10:58:50 -04:00
m_elf . reset ( ) ;
2015-05-06 00:54:15 -04: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 ) ) ;
2018-04-30 21:01:23 +01:00
2015-05-06 00:54:15 -04:00
//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 ;
}
void CPS2OS : : ApplyPatches ( )
{
std : : unique_ptr < Framework : : Xml : : CNode > document ;
try
{
2016-05-23 13:30:46 -04:00
# ifdef __ANDROID__
Framework : : Android : : CAssetStream patchesStream ( PATCHESFILENAME ) ;
# else
auto patchesPath = Framework : : PathUtils : : GetAppResourcesPath ( ) / PATCHESFILENAME ;
2015-05-06 00:54:15 -04:00
Framework : : CStdStream patchesStream ( Framework : : CreateInputStdStream ( patchesPath . native ( ) ) ) ;
2016-05-23 13:30:46 -04:00
# endif
2015-05-06 00:54:15 -04:00
document = std : : unique_ptr < Framework : : Xml : : CNode > ( Framework : : Xml : : CParser : : ParseDocument ( patchesStream ) ) ;
if ( ! document ) return ;
}
catch ( const std : : exception & exception )
{
CLog : : GetInstance ( ) . Print ( LOG_NAME , " Failed to open patch definition file: %s. \r \n " , exception . what ( ) ) ;
return ;
}
auto patchesNode = document - > Select ( " Patches " ) ;
if ( patchesNode = = NULL )
{
return ;
}
for ( Framework : : Xml : : CFilteringNodeIterator itNode ( patchesNode , " Executable " ) ; ! itNode . IsEnd ( ) ; itNode + + )
{
auto executableNode = ( * itNode ) ;
const char * name = executableNode - > GetAttribute ( " Name " ) ;
if ( name = = NULL ) continue ;
if ( ! strcmp ( name , GetExecutableName ( ) ) )
{
//Found the right executable
unsigned int patchCount = 0 ;
for ( Framework : : Xml : : CFilteringNodeIterator itNode ( executableNode , " Patch " ) ; ! itNode . IsEnd ( ) ; itNode + + )
{
auto patch = ( * itNode ) ;
2018-04-30 21:01:23 +01:00
const char * addressString = patch - > GetAttribute ( " Address " ) ;
const char * valueString = patch - > GetAttribute ( " Value " ) ;
2015-05-06 00:54:15 -04:00
if ( addressString = = nullptr ) continue ;
if ( valueString = = nullptr ) continue ;
uint32 value = 0 , address = 0 ;
if ( sscanf ( addressString , " %x " , & address ) = = 0 ) continue ;
if ( sscanf ( valueString , " %x " , & value ) = = 0 ) continue ;
* ( uint32 * ) & m_ram [ address ] = value ;
patchCount + + ;
}
CLog : : GetInstance ( ) . Print ( LOG_NAME , " Applied %i patch(es). \r \n " , patchCount ) ;
break ;
}
}
}
void CPS2OS : : AssembleCustomSyscallHandler ( )
{
CMIPSAssembler assembler ( ( uint32 * ) & m_bios [ 0x100 ] ) ;
//Epilogue
assembler . ADDIU ( CMIPS : : SP , CMIPS : : SP , 0xFFF0 ) ;
assembler . SD ( CMIPS : : RA , 0x0000 , CMIPS : : SP ) ;
2018-04-30 21:01:23 +01:00
2015-05-06 00:54:15 -04:00
//Load the function address off the table at 0x80010000
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 ) ;
2018-04-30 21:01:23 +01:00
2015-05-06 00:54:15 -04:00
//And the address with 0x1FFFFFFF
assembler . LUI ( CMIPS : : T1 , 0x1FFF ) ;
assembler . ORI ( CMIPS : : T1 , CMIPS : : T1 , 0xFFFF ) ;
assembler . AND ( CMIPS : : T0 , CMIPS : : T0 , CMIPS : : T1 ) ;
//Jump to the system call address
assembler . JALR ( CMIPS : : T0 ) ;
assembler . NOP ( ) ;
//Prologue
assembler . LD ( CMIPS : : RA , 0x0000 , CMIPS : : SP ) ;
assembler . ADDIU ( CMIPS : : SP , CMIPS : : SP , 0x0010 ) ;
assembler . ERET ( ) ;
}
void CPS2OS : : AssembleInterruptHandler ( )
{
CEEAssembler assembler ( reinterpret_cast < uint32 * > ( & m_bios [ BIOS_ADDRESS_INTERRUPTHANDLER - BIOS_ADDRESS_BASE ] ) ) ;
const uint32 stackFrameSize = 0x230 ;
2017-06-15 10:51:08 -04:00
//Invariant - Current thread is idle thread
//This means we don't need to save/load its context because
//it doesn't have any
2015-05-06 00:54:15 -04:00
//Epilogue (allocate stackFrameSize bytes)
assembler . LI ( CMIPS : : K0 , BIOS_ADDRESS_KERNELSTACK_TOP ) ;
assembler . ADDIU ( CMIPS : : K0 , CMIPS : : K0 , 0x10000 - stackFrameSize ) ;
2018-04-30 21:01:23 +01:00
2015-05-06 00:54:15 -04:00
//Save EPC
assembler . MFC0 ( CMIPS : : T0 , CCOP_SCU : : EPC ) ;
assembler . SW ( CMIPS : : T0 , 0x0220 , CMIPS : : K0 ) ;
//Set SP
assembler . ADDU ( CMIPS : : SP , CMIPS : : K0 , CMIPS : : R0 ) ;
2015-11-01 23:55:20 -05:00
//Disable interrupts. Used by some games (ie.: RE4) to check interrupt context.
assembler . MFC0 ( CMIPS : : T0 , CCOP_SCU : : STATUS ) ;
assembler . LI ( CMIPS : : T1 , ~ CMIPS : : STATUS_IE ) ;
assembler . AND ( CMIPS : : T0 , CMIPS : : T0 , CMIPS : : T1 ) ;
assembler . MTC0 ( CMIPS : : T0 , CCOP_SCU : : STATUS ) ;
2015-05-06 00:54:15 -04:00
//Get INTC status
2015-11-01 01:02:28 -05:00
assembler . LI ( CMIPS : : T0 , CINTC : : INTC_STAT ) ;
2015-05-06 00:54:15 -04:00
assembler . LW ( CMIPS : : S0 , 0x0000 , CMIPS : : T0 ) ;
//Get INTC mask
2015-11-01 01:02:28 -05:00
assembler . LI ( CMIPS : : T1 , CINTC : : INTC_MASK ) ;
2015-05-06 00:54:15 -04:00
assembler . LW ( CMIPS : : S1 , 0x0000 , CMIPS : : T1 ) ;
//Get cause
assembler . AND ( CMIPS : : S0 , CMIPS : : S0 , CMIPS : : S1 ) ;
//Clear cause
//assembler.SW(CMIPS::S0, 0x0000, CMIPS::T0);
assembler . NOP ( ) ;
2018-04-30 21:01:23 +01:00
static const auto generateIntHandler =
[ ] ( CMIPSAssembler & assembler , uint32 line ) {
auto skipIntHandlerLabel = assembler . CreateLabel ( ) ;
2015-05-06 00:54:15 -04:00
2018-04-30 21:01:23 +01:00
//Check cause
assembler . ANDI ( CMIPS : : T0 , CMIPS : : S0 , ( 1 < < line ) ) ;
assembler . BEQ ( CMIPS : : R0 , CMIPS : : T0 , skipIntHandlerLabel ) ;
assembler . NOP ( ) ;
2015-05-06 00:54:15 -04:00
2018-04-30 21:01:23 +01:00
//Process handlers
assembler . ADDIU ( CMIPS : : A0 , CMIPS : : R0 , line ) ;
assembler . JAL ( BIOS_ADDRESS_INTCHANDLER ) ;
assembler . NOP ( ) ;
2015-05-06 00:54:15 -04:00
2018-04-30 21:01:23 +01:00
assembler . MarkLabel ( skipIntHandlerLabel ) ;
} ;
2015-05-06 00:54:15 -04:00
generateIntHandler ( assembler , CINTC : : INTC_LINE_GS ) ;
2018-04-30 21:01:23 +01:00
2015-05-06 00:54:15 -04:00
{
auto skipIntHandlerLabel = assembler . CreateLabel ( ) ;
//Check if INT1 (DMAC)
assembler . ANDI ( CMIPS : : T0 , CMIPS : : S0 , ( 1 < < CINTC : : INTC_LINE_DMAC ) ) ;
assembler . BEQ ( CMIPS : : R0 , CMIPS : : T0 , skipIntHandlerLabel ) ;
assembler . NOP ( ) ;
//Go to DMAC interrupt handler
assembler . JAL ( BIOS_ADDRESS_DMACHANDLER ) ;
assembler . NOP ( ) ;
assembler . MarkLabel ( skipIntHandlerLabel ) ;
}
generateIntHandler ( assembler , CINTC : : INTC_LINE_VBLANK_START ) ;
generateIntHandler ( assembler , CINTC : : INTC_LINE_VBLANK_END ) ;
2015-05-07 23:09:36 -04:00
generateIntHandler ( assembler , CINTC : : INTC_LINE_VIF1 ) ;
2017-01-01 19:22:43 -05:00
generateIntHandler ( assembler , CINTC : : INTC_LINE_IPU ) ;
2015-05-06 00:54:15 -04:00
generateIntHandler ( assembler , CINTC : : INTC_LINE_TIMER0 ) ;
generateIntHandler ( assembler , CINTC : : INTC_LINE_TIMER1 ) ;
generateIntHandler ( assembler , CINTC : : INTC_LINE_TIMER2 ) ;
generateIntHandler ( assembler , CINTC : : INTC_LINE_TIMER3 ) ;
assembler . JAL ( BIOS_ADDRESS_ALARMHANDLER ) ;
assembler . NOP ( ) ;
//Make sure interrupts are enabled (This is needed by some games that play
//with the status register in interrupt handlers and is done by the EE BIOS)
assembler . MFC0 ( CMIPS : : T0 , CCOP_SCU : : STATUS ) ;
assembler . ORI ( CMIPS : : T0 , CMIPS : : T0 , CMIPS : : STATUS_IE ) ;
assembler . MTC0 ( CMIPS : : T0 , CCOP_SCU : : STATUS ) ;
2019-02-09 11:26:48 -05:00
//Prologue
2015-05-06 00:54:15 -04:00
//Move back SP into K0 before restoring state
assembler . ADDIU ( CMIPS : : K0 , CMIPS : : SP , CMIPS : : R0 ) ;
2019-02-09 11:26:48 -05:00
//Read EPC from 0x220
assembler . LW ( CMIPS : : A0 , 0x0220 , CMIPS : : K0 ) ;
2015-05-06 00:54:15 -04:00
2019-02-09 11:26:48 -05:00
assembler . ADDIU ( CMIPS : : V1 , CMIPS : : R0 , SYSCALL_CUSTOM_EXITINTERRUPT ) ;
assembler . SYSCALL ( ) ;
2015-05-06 00:54:15 -04:00
}
void CPS2OS : : AssembleDmacHandler ( )
{
CMIPSAssembler assembler ( reinterpret_cast < uint32 * > ( & m_bios [ BIOS_ADDRESS_DMACHANDLER - BIOS_ADDRESS_BASE ] ) ) ;
2015-07-26 01:11:43 -04:00
auto checkHandlerLabel = assembler . CreateLabel ( ) ;
2015-05-06 00:54:15 -04:00
auto testChannelLabel = assembler . CreateLabel ( ) ;
auto skipChannelLabel = assembler . CreateLabel ( ) ;
2015-07-26 01:11:43 -04:00
auto channelCounterRegister = CMIPS : : S0 ;
auto interruptStatusRegister = CMIPS : : S1 ;
auto nextIdPtrRegister = CMIPS : : S2 ;
auto nextIdRegister = CMIPS : : T2 ;
2015-05-06 00:54:15 -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 ) ;
//Clear INTC cause
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 ) ;
//Load the DMA interrupt status
assembler . LI ( CMIPS : : T0 , CDMAC : : D_STAT ) ;
assembler . LW ( CMIPS : : T0 , 0x0000 , CMIPS : : T0 ) ;
assembler . SRL ( CMIPS : : T1 , CMIPS : : T0 , 16 ) ;
2015-07-26 01:11:43 -04:00
assembler . AND ( interruptStatusRegister , CMIPS : : T0 , CMIPS : : T1 ) ;
2015-05-06 00:54:15 -04:00
//Initialize channel counter
2015-07-26 01:11:43 -04:00
assembler . ADDIU ( channelCounterRegister , CMIPS : : R0 , 0x0009 ) ;
2015-05-06 00:54:15 -04:00
assembler . MarkLabel ( testChannelLabel ) ;
//Check if that specific DMA channel interrupt is the cause
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 ( ) ;
//Clear interrupt
assembler . LI ( CMIPS : : T1 , CDMAC : : D_STAT ) ;
assembler . SW ( CMIPS : : T0 , 0x0000 , CMIPS : : T1 ) ;
//Initialize DMAC handler loop
2015-07-26 01:11:43 -04:00
assembler . LI ( nextIdPtrRegister , BIOS_ADDRESS_DMACHANDLERQUEUE_BASE ) ;
2015-05-06 00:54:15 -04:00
2015-07-26 01:11:43 -04:00
assembler . MarkLabel ( checkHandlerLabel ) ;
//Check
assembler . LW ( nextIdRegister , 0 , nextIdPtrRegister ) ;
assembler . BEQ ( nextIdRegister , CMIPS : : R0 , skipChannelLabel ) ;
assembler . ADDIU ( nextIdRegister , nextIdRegister , static_cast < uint16 > ( - 1 ) ) ;
2015-05-06 00:54:15 -04:00
//Get the address to the current DMACHANDLER structure
assembler . ADDIU ( CMIPS : : T0 , CMIPS : : R0 , sizeof ( DMACHANDLER ) ) ;
2015-07-26 01:11:43 -04:00
assembler . MULTU ( CMIPS : : T0 , nextIdRegister , CMIPS : : T0 ) ;
2015-05-06 00:54:15 -04:00
assembler . LI ( CMIPS : : T1 , BIOS_ADDRESS_DMACHANDLER_BASE ) ;
assembler . ADDU ( CMIPS : : T0 , CMIPS : : T0 , CMIPS : : T1 ) ;
2015-07-26 01:11:43 -04:00
//Adjust nextIdPtr
assembler . ADDIU ( nextIdPtrRegister , CMIPS : : T0 , offsetof ( INTCHANDLER , nextId ) ) ;
2015-05-06 00:54:15 -04:00
//Check if the channel is good one
assembler . LW ( CMIPS : : T1 , offsetof ( DMACHANDLER , channel ) , CMIPS : : T0 ) ;
2015-07-26 01:11:43 -04:00
assembler . BNE ( channelCounterRegister , CMIPS : : T1 , checkHandlerLabel ) ;
2015-05-06 00:54:15 -04:00
assembler . NOP ( ) ;
//Load the necessary stuff
assembler . LW ( CMIPS : : T1 , offsetof ( DMACHANDLER , address ) , CMIPS : : T0 ) ;
2015-07-26 01:11:43 -04:00
assembler . ADDU ( CMIPS : : A0 , channelCounterRegister , CMIPS : : R0 ) ;
2015-05-06 00:54:15 -04:00
assembler . LW ( CMIPS : : A1 , offsetof ( DMACHANDLER , arg ) , CMIPS : : T0 ) ;
assembler . LW ( CMIPS : : GP , offsetof ( DMACHANDLER , gp ) , CMIPS : : T0 ) ;
2018-04-30 21:01:23 +01:00
2015-05-06 00:54:15 -04:00
//Jump
assembler . JALR ( CMIPS : : T1 ) ;
assembler . NOP ( ) ;
2015-07-26 01:11:43 -04:00
assembler . BGEZ ( CMIPS : : V0 , checkHandlerLabel ) ;
2015-05-06 00:54:15 -04:00
assembler . NOP ( ) ;
assembler . MarkLabel ( skipChannelLabel ) ;
//Decrement channel counter and test
2015-07-26 01:11:43 -04:00
assembler . ADDIU ( channelCounterRegister , channelCounterRegister , 0xFFFF ) ;
assembler . BGEZ ( channelCounterRegister , testChannelLabel ) ;
2015-05-06 00:54:15 -04:00
assembler . NOP ( ) ;
//Epilogue
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 ( ) ;
}
void CPS2OS : : AssembleIntcHandler ( )
{
2015-07-25 20:13:59 -04:00
CMIPSAssembler assembler ( reinterpret_cast < uint32 * > ( & m_bios [ BIOS_ADDRESS_INTCHANDLER - BIOS_ADDRESS_BASE ] ) ) ;
2015-05-06 00:54:15 -04:00
2015-07-25 20:13:59 -04:00
auto checkHandlerLabel = assembler . CreateLabel ( ) ;
auto finishLoop = assembler . CreateLabel ( ) ;
2015-05-06 00:54:15 -04:00
2015-07-25 20:13:59 -04:00
auto nextIdPtrRegister = CMIPS : : S0 ;
auto causeRegister = CMIPS : : S1 ;
2015-05-06 00:54:15 -04:00
2015-07-25 20:13:59 -04:00
auto nextIdRegister = CMIPS : : T2 ;
//Prologue
2015-05-06 00:54:15 -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 ) ;
//Clear INTC cause
2015-07-25 20:13:59 -04:00
assembler . LI ( CMIPS : : T1 , CINTC : : INTC_STAT ) ;
2015-05-06 00:54:15 -04:00
assembler . ADDIU ( CMIPS : : T0 , CMIPS : : R0 , 0x0001 ) ;
assembler . SLLV ( CMIPS : : T0 , CMIPS : : T0 , CMIPS : : A0 ) ;
assembler . SW ( CMIPS : : T0 , 0x0000 , CMIPS : : T1 ) ;
//Initialize INTC handler loop
2015-07-25 20:13:59 -04:00
assembler . LI ( nextIdPtrRegister , BIOS_ADDRESS_INTCHANDLERQUEUE_BASE ) ;
assembler . ADDU ( causeRegister , CMIPS : : A0 , CMIPS : : R0 ) ;
2015-05-06 00:54:15 -04:00
assembler . MarkLabel ( checkHandlerLabel ) ;
2015-07-25 20:13:59 -04:00
//Check
assembler . LW ( nextIdRegister , 0 , nextIdPtrRegister ) ;
assembler . BEQ ( nextIdRegister , CMIPS : : R0 , finishLoop ) ;
assembler . ADDIU ( nextIdRegister , nextIdRegister , static_cast < uint16 > ( - 1 ) ) ;
2015-05-06 00:54:15 -04:00
//Get the address to the current INTCHANDLER structure
assembler . ADDIU ( CMIPS : : T0 , CMIPS : : R0 , sizeof ( INTCHANDLER ) ) ;
2015-07-25 20:13:59 -04:00
assembler . MULTU ( CMIPS : : T0 , nextIdRegister , CMIPS : : T0 ) ;
assembler . LI ( CMIPS : : T1 , BIOS_ADDRESS_INTCHANDLER_BASE ) ;
2015-05-06 00:54:15 -04:00
assembler . ADDU ( CMIPS : : T0 , CMIPS : : T0 , CMIPS : : T1 ) ;
2015-07-25 20:13:59 -04:00
//Adjust nextIdPtr
assembler . ADDIU ( nextIdPtrRegister , CMIPS : : T0 , offsetof ( INTCHANDLER , nextId ) ) ;
2015-05-06 00:54:15 -04:00
//Check if the cause is good one
2015-07-25 20:13:59 -04:00
assembler . LW ( CMIPS : : T1 , offsetof ( INTCHANDLER , cause ) , CMIPS : : T0 ) ;
assembler . BNE ( causeRegister , CMIPS : : T1 , checkHandlerLabel ) ;
2015-05-06 00:54:15 -04:00
assembler . NOP ( ) ;
//Load the necessary stuff
2015-07-25 20:13:59 -04:00
assembler . LW ( CMIPS : : T1 , offsetof ( INTCHANDLER , address ) , CMIPS : : T0 ) ;
assembler . ADDU ( CMIPS : : A0 , causeRegister , CMIPS : : R0 ) ;
assembler . LW ( CMIPS : : A1 , offsetof ( INTCHANDLER , arg ) , CMIPS : : T0 ) ;
assembler . LW ( CMIPS : : GP , offsetof ( INTCHANDLER , gp ) , CMIPS : : T0 ) ;
2018-04-30 21:01:23 +01:00
2015-05-06 00:54:15 -04:00
//Jump
assembler . JALR ( CMIPS : : T1 ) ;
assembler . NOP ( ) ;
2015-07-25 20:13:59 -04:00
assembler . BGEZ ( CMIPS : : V0 , checkHandlerLabel ) ;
2015-05-06 00:54:15 -04:00
assembler . NOP ( ) ;
2015-07-25 20:13:59 -04:00
assembler . MarkLabel ( finishLoop ) ;
2015-05-06 00:54:15 -04:00
//Epilogue
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 ( ) ;
}
void CPS2OS : : AssembleThreadEpilog ( )
{
CMIPSAssembler assembler ( ( uint32 * ) & m_bios [ BIOS_ADDRESS_THREADEPILOG - BIOS_ADDRESS_BASE ] ) ;
2018-04-30 21:01:23 +01:00
2015-05-06 00:54:15 -04:00
assembler . ADDIU ( CMIPS : : V1 , CMIPS : : R0 , 0x23 ) ;
assembler . SYSCALL ( ) ;
}
2015-08-06 01:20:04 -04:00
void CPS2OS : : AssembleIdleThreadProc ( )
2015-05-06 00:54:15 -04:00
{
2015-08-06 01:20:04 -04:00
CMIPSAssembler assembler ( ( uint32 * ) & m_bios [ BIOS_ADDRESS_IDLETHREADPROC - BIOS_ADDRESS_BASE ] ) ;
2015-05-06 00:54:15 -04:00
2019-02-09 11:16:59 -05:00
assembler . ADDIU ( CMIPS : : V1 , CMIPS : : R0 , SYSCALL_CUSTOM_RESCHEDULE ) ;
2015-05-06 00:54:15 -04:00
assembler . SYSCALL ( ) ;
assembler . BEQ ( CMIPS : : R0 , CMIPS : : R0 , 0xFFFD ) ;
assembler . NOP ( ) ;
}
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 ) ;
2018-04-30 21:01:23 +01:00
2015-05-06 00:54:15 -04:00
//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 ( ) ;
}
uint32 * CPS2OS : : GetCustomSyscallTable ( )
{
2019-05-23 21:13:37 -04:00
return ( uint32 * ) & m_ram [ BIOS_ADDRESS_CUSTOMSYSCALL_BASE ] ;
2015-05-06 00:54:15 -04:00
}
2015-08-09 00:03:42 -04:00
void CPS2OS : : LinkThread ( uint32 threadId )
{
auto thread = m_threads [ threadId ] ;
for ( auto threadSchedulePair : m_threadSchedule )
{
auto scheduledThread = threadSchedulePair . second ;
if ( scheduledThread - > currPriority > thread - > currPriority )
{
m_threadSchedule . AddBefore ( threadSchedulePair . first , threadId ) ;
return ;
}
}
m_threadSchedule . PushBack ( threadId ) ;
}
void CPS2OS : : UnlinkThread ( uint32 threadId )
{
m_threadSchedule . Unlink ( threadId ) ;
}
2015-05-06 00:54:15 -04:00
void CPS2OS : : ThreadShakeAndBake ( )
{
//Don't play with fire (don't switch if we're in exception mode)
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 ] & INTERRUPTS_ENABLED_MASK ) ! = INTERRUPTS_ENABLED_MASK )
{
return ;
}
2017-09-04 17:49:21 -04:00
//SetupThread has not been called, not ready to switch threads yet
if ( m_currentThreadId = = 0 )
{
return ;
}
2015-05-06 00:54:15 -04:00
//Select thread to execute
{
2015-08-09 00:03:42 -04:00
uint32 nextThreadId = 0 ;
if ( m_threadSchedule . IsEmpty ( ) )
2015-05-06 00:54:15 -04:00
{
2015-08-04 01:16:43 -04:00
//No thread ready to be executed
2015-08-09 00:03:42 -04:00
nextThreadId = m_idleThreadId ;
2015-05-06 00:54:15 -04:00
}
else
{
2015-08-09 00:03:42 -04:00
auto nextThreadPair = * m_threadSchedule . begin ( ) ;
nextThreadId = nextThreadPair . first ;
assert ( nextThreadPair . second - > status = = THREAD_RUNNING ) ;
2015-05-06 00:54:15 -04:00
}
2015-08-09 00:03:42 -04:00
ThreadSwitchContext ( nextThreadId ) ;
2015-05-06 00:54:15 -04:00
}
}
2016-11-20 15:36:48 -05:00
void CPS2OS : : ThreadSwitchContext ( uint32 id )
2015-05-06 00:54:15 -04:00
{
2015-08-08 23:36:00 -04:00
if ( id = = m_currentThreadId ) return ;
2015-05-06 00:54:15 -04:00
//Save the context of the current thread
{
2015-08-08 23:36:00 -04:00
auto thread = m_threads [ m_currentThreadId ] ;
2015-08-06 01:20:04 -04:00
assert ( thread ) ;
2017-06-15 10:24:17 -04:00
thread - > epc = m_ee . m_State . nPC ;
2015-05-06 00:54:15 -04:00
2017-06-15 10:24:17 -04:00
//Idle thread doesn't have a context
if ( m_currentThreadId ! = m_idleThreadId )
2015-05-06 00:54:15 -04:00
{
2019-02-09 11:26:48 -05:00
ThreadSaveContext ( thread , false ) ;
2017-06-15 10:24:17 -04:00
}
2015-05-06 00:54:15 -04:00
}
2015-08-08 23:36:00 -04:00
m_currentThreadId = id ;
2015-05-06 00:54:15 -04:00
//Load the new context
{
2015-08-08 23:36:00 -04:00
auto thread = m_threads [ m_currentThreadId ] ;
2015-08-06 01:20:04 -04:00
assert ( thread ) ;
2015-05-06 00:54:15 -04:00
m_ee . m_State . nPC = thread - > epc ;
2015-08-06 01:20:04 -04:00
//Idle thread doesn't have a context
if ( id ! = m_idleThreadId )
2015-05-06 00:54:15 -04:00
{
2019-02-09 11:26:48 -05:00
ThreadLoadContext ( thread , false ) ;
2015-05-06 00:54:15 -04:00
}
}
CLog : : GetInstance ( ) . Print ( LOG_NAME , " New thread elected (id = %i). \r \n " , id ) ;
}
2019-02-09 11:26:48 -05:00
void CPS2OS : : ThreadSaveContext ( THREAD * thread , bool interrupt )
{
if ( interrupt )
{
thread - > contextPtr = BIOS_ADDRESS_INTERRUPT_THREAD_CONTEXT ;
}
else
{
thread - > contextPtr = m_ee . m_State . nGPR [ CMIPS : : SP ] . nV0 - STACKRES ;
assert ( thread - > contextPtr > = thread - > stackBase ) ;
}
auto context = reinterpret_cast < THREADCONTEXT * > ( GetStructPtr ( thread - > contextPtr ) ) ;
//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 ;
context - > gpr [ i ] = m_ee . m_State . nGPR [ i ] ;
}
for ( uint32 i = 0 ; i < 0x20 ; i + + )
{
context - > cop1 [ i ] = m_ee . m_State . nCOP1 [ i ] ;
}
auto & sa = context - > gpr [ CMIPS : : R0 ] . nV0 ;
auto & hi = context - > gpr [ CMIPS : : K0 ] ;
auto & lo = context - > gpr [ CMIPS : : K1 ] ;
sa = m_ee . m_State . nSA > > 3 ; //Act as if MFSA was used
hi . nV [ 0 ] = m_ee . m_State . nHI [ 0 ] ;
hi . nV [ 1 ] = m_ee . m_State . nHI [ 1 ] ;
hi . nV [ 2 ] = m_ee . m_State . nHI1 [ 0 ] ;
hi . nV [ 3 ] = m_ee . m_State . nHI1 [ 1 ] ;
lo . nV [ 0 ] = m_ee . m_State . nLO [ 0 ] ;
lo . nV [ 1 ] = m_ee . m_State . nLO [ 1 ] ;
lo . nV [ 2 ] = m_ee . m_State . nLO1 [ 0 ] ;
lo . nV [ 3 ] = m_ee . m_State . nLO1 [ 1 ] ;
context - > cop1a = m_ee . m_State . nCOP1A ;
context - > fcsr = m_ee . m_State . nFCSR ;
}
void CPS2OS : : ThreadLoadContext ( THREAD * thread , bool interrupt )
{
assert ( thread - > contextPtr ! = 0 ) ;
2019-02-21 09:14:03 -05:00
assert ( ! interrupt | | ( thread - > contextPtr = = BIOS_ADDRESS_INTERRUPT_THREAD_CONTEXT ) ) ;
2019-02-09 11:26:48 -05:00
auto context = reinterpret_cast < const THREADCONTEXT * > ( GetStructPtr ( thread - > contextPtr ) ) ;
for ( uint32 i = 0 ; i < 0x20 ; i + + )
{
if ( i = = CMIPS : : R0 ) continue ;
if ( i = = CMIPS : : K0 ) continue ;
if ( i = = CMIPS : : K1 ) continue ;
m_ee . m_State . nGPR [ i ] = context - > gpr [ i ] ;
}
for ( uint32 i = 0 ; i < 0x20 ; i + + )
{
m_ee . m_State . nCOP1 [ i ] = context - > cop1 [ i ] ;
}
auto & sa = context - > gpr [ CMIPS : : R0 ] . nV0 ;
auto & hi = context - > gpr [ CMIPS : : K0 ] ;
auto & lo = context - > gpr [ CMIPS : : K1 ] ;
m_ee . m_State . nSA = ( sa & 0x0F ) < < 3 ; //Act as if MTSA was used
m_ee . m_State . nHI [ 0 ] = hi . nV [ 0 ] ;
m_ee . m_State . nHI [ 1 ] = hi . nV [ 1 ] ;
m_ee . m_State . nHI1 [ 0 ] = hi . nV [ 2 ] ;
m_ee . m_State . nHI1 [ 1 ] = hi . nV [ 3 ] ;
m_ee . m_State . nLO [ 0 ] = lo . nV [ 0 ] ;
m_ee . m_State . nLO [ 1 ] = lo . nV [ 1 ] ;
m_ee . m_State . nLO1 [ 0 ] = lo . nV [ 2 ] ;
m_ee . m_State . nLO1 [ 1 ] = lo . nV [ 3 ] ;
m_ee . m_State . nCOP1A = context - > cop1a ;
m_ee . m_State . nFCSR = context - > fcsr ;
}
2016-11-20 17:09:58 -05:00
void CPS2OS : : ThreadReset ( uint32 id )
{
assert ( m_currentThreadId ! = id ) ;
auto thread = m_threads [ id ] ;
assert ( thread - > status = = THREAD_ZOMBIE ) ;
uint32 stackTop = thread - > stackBase + thread - > stackSize ;
thread - > contextPtr = stackTop - STACKRES ;
thread - > currPriority = thread - > initPriority ;
//Reset wakeup count?
auto context = reinterpret_cast < THREADCONTEXT * > ( GetStructPtr ( thread - > contextPtr ) ) ;
context - > gpr [ CMIPS : : SP ] . nV0 = stackTop - STACK_FRAME_RESERVE_SIZE ;
context - > gpr [ CMIPS : : FP ] . nV0 = stackTop - STACK_FRAME_RESERVE_SIZE ;
context - > gpr [ CMIPS : : GP ] . nV0 = thread - > gp ;
context - > gpr [ CMIPS : : RA ] . nV0 = BIOS_ADDRESS_THREADEPILOG ;
}
2015-10-27 00:22:51 -04:00
void CPS2OS : : CheckLivingThreads ( )
{
//Check if we have a living thread (this is needed for autotests to work properly)
bool hasLiveThread = false ;
for ( auto thread : m_threads )
{
if ( ! thread ) continue ;
if ( thread - > status ! = THREAD_ZOMBIE )
{
hasLiveThread = true ;
break ;
}
}
if ( ! hasLiveThread )
{
OnRequestExit ( ) ;
}
}
2017-01-21 17:44:19 -05:00
bool CPS2OS : : SemaReleaseSingleThread ( uint32 semaId , bool cancelled )
2017-01-01 18:29:32 -05:00
{
//Releases a single thread from a semaphore's queue
//TODO: Implement an actual queue
auto sema = m_semaphores [ semaId ] ;
assert ( sema ) ;
assert ( sema - > waitCount ! = 0 ) ;
uint32 returnValue = cancelled ? - 1 : semaId ;
bool changed = false ;
for ( auto threadIterator = std : : begin ( m_threads ) ; threadIterator ! = std : : end ( m_threads ) ; threadIterator + + )
{
auto thread = * threadIterator ;
if ( ! thread ) continue ;
if ( ( thread - > status ! = THREAD_WAITING ) & & ( thread - > status ! = THREAD_SUSPENDED_WAITING ) ) continue ;
if ( thread - > semaWait ! = semaId ) continue ;
switch ( thread - > status )
{
case THREAD_WAITING :
thread - > status = THREAD_RUNNING ;
LinkThread ( threadIterator ) ;
break ;
case THREAD_SUSPENDED_WAITING :
thread - > status = THREAD_SUSPENDED ;
break ;
default :
assert ( 0 ) ;
break ;
}
auto context = reinterpret_cast < THREADCONTEXT * > ( GetStructPtr ( thread - > contextPtr ) ) ;
context - > gpr [ SC_RETURN ] . nD0 = static_cast < int32 > ( returnValue ) ;
sema - > waitCount - - ;
changed = true ;
break ;
}
//Something went wrong if nothing changed
2021-03-04 19:44:59 -05:00
if ( ! changed )
{
CLog : : GetInstance ( ) . Warn ( LOG_NAME , " SemaReleaseSingleThread: Had to release a single thread but it was not possible. Something could be in a wrong state. \r \n " ) ;
}
2017-01-21 17:44:19 -05:00
return changed ;
2017-01-01 18:29:32 -05:00
}
2015-08-06 01:20:04 -04:00
void CPS2OS : : CreateIdleThread ( )
2015-05-06 00:54:15 -04:00
{
2015-08-06 01:20:04 -04:00
m_idleThreadId = m_threads . Allocate ( ) ;
auto thread = m_threads [ m_idleThreadId ] ;
2018-04-30 21:01:23 +01:00
thread - > epc = BIOS_ADDRESS_IDLETHREADPROC ;
thread - > status = THREAD_ZOMBIE ;
2015-05-06 00:54:15 -04:00
}
2015-05-15 19:14:03 -04:00
std : : pair < uint32 , uint32 > CPS2OS : : GetVsyncFlagPtrs ( ) const
{
uint32 value1Ptr = * reinterpret_cast < uint32 * > ( m_ram + BIOS_ADDRESS_VSYNCFLAG_VALUE1PTR ) ;
uint32 value2Ptr = * reinterpret_cast < uint32 * > ( m_ram + BIOS_ADDRESS_VSYNCFLAG_VALUE2PTR ) ;
return std : : make_pair ( value1Ptr , value2Ptr ) ;
}
void CPS2OS : : SetVsyncFlagPtrs ( uint32 value1Ptr , uint32 value2Ptr )
{
* reinterpret_cast < uint32 * > ( m_ram + BIOS_ADDRESS_VSYNCFLAG_VALUE1PTR ) = value1Ptr ;
* reinterpret_cast < uint32 * > ( m_ram + BIOS_ADDRESS_VSYNCFLAG_VALUE2PTR ) = value2Ptr ;
}
2015-05-06 00:54:15 -04:00
uint8 * CPS2OS : : GetStructPtr ( uint32 address ) const
{
2015-12-02 22:22:30 -05:00
address = TranslateAddress ( nullptr , address ) ;
2015-05-06 00:54:15 -04:00
uint8 * memory = nullptr ;
2015-12-02 22:22:30 -05:00
if ( ( address > = PS2 : : EE_SPR_ADDR ) & & ( address < ( PS2 : : EE_SPR_ADDR + PS2 : : EE_SPR_SIZE ) ) )
2015-05-06 00:54:15 -04:00
{
address & = ( PS2 : : EE_SPR_SIZE - 1 ) ;
memory = m_spr ;
}
else
{
address & = ( PS2 : : EE_RAM_SIZE - 1 ) ;
memory = m_ram ;
}
return memory + address ;
}
uint32 CPS2OS : : GetNextAvailableDeci2HandlerId ( )
{
for ( uint32 i = 1 ; i < MAX_DECI2HANDLER ; i + + )
{
DECI2HANDLER * handler = GetDeci2Handler ( i ) ;
if ( handler - > valid ! = 1 )
{
return i ;
}
}
return 0xFFFFFFFF ;
}
CPS2OS : : DECI2HANDLER * CPS2OS : : GetDeci2Handler ( uint32 id )
{
id - - ;
return & ( ( DECI2HANDLER * ) & m_ram [ 0x00008000 ] ) [ id ] ;
}
void CPS2OS : : HandleInterrupt ( )
{
//Check if interrupts are enabled here because EIE bit isn't checked by CMIPS
if ( ( m_ee . m_State . nCOP0 [ CCOP_SCU : : STATUS ] & INTERRUPTS_ENABLED_MASK ) ! = INTERRUPTS_ENABLED_MASK )
{
return ;
}
2017-06-15 10:43:42 -04:00
if ( ! m_ee . CanGenerateInterrupt ( ) )
{
return ;
}
2019-02-09 11:26:48 -05:00
if ( m_currentThreadId ! = m_idleThreadId )
{
auto thread = m_threads [ m_currentThreadId ] ;
ThreadSaveContext ( thread , true ) ;
}
2017-06-15 10:43:42 -04:00
bool interrupted = m_ee . GenerateInterrupt ( BIOS_ADDRESS_INTERRUPTHANDLER ) ;
assert ( interrupted ) ;
2015-05-06 00:54:15 -04:00
}
void CPS2OS : : HandleReturnFromException ( )
{
ThreadShakeAndBake ( ) ;
}
2015-05-17 18:58:19 -04:00
bool CPS2OS : : CheckVBlankFlag ( )
2015-05-15 19:14:03 -04:00
{
2015-05-17 18:58:19 -04:00
bool changed = false ;
2015-05-15 19:14:03 -04:00
auto vsyncFlagPtrs = GetVsyncFlagPtrs ( ) ;
if ( vsyncFlagPtrs . first ! = 0 )
{
2020-04-16 09:04:13 -04:00
auto vsyncFlagFirst = GetStructPtr ( vsyncFlagPtrs . first ) ;
* reinterpret_cast < uint32 * > ( vsyncFlagFirst ) = 1 ;
2015-05-17 18:58:19 -04:00
changed = true ;
2015-05-15 19:14:03 -04:00
}
if ( vsyncFlagPtrs . second ! = 0 )
{
2020-04-16 09:04:13 -04:00
auto vsyncFlagSecond = GetStructPtr ( vsyncFlagPtrs . second ) ;
* reinterpret_cast < uint64 * > ( vsyncFlagSecond ) = m_gs - > ReadPrivRegister ( CGSHandler : : GS_CSR ) ;
2015-05-17 18:58:19 -04:00
changed = true ;
2015-05-15 19:14:03 -04:00
}
SetVsyncFlagPtrs ( 0 , 0 ) ;
2015-05-17 18:58:19 -04:00
return changed ;
2015-05-15 19:14:03 -04:00
}
2020-08-04 13:29:59 -04:00
void CPS2OS : : UpdateTLBEnabledState ( )
{
bool TLBenabled = ( m_tlblExceptionHandler ! = 0 ) | | ( m_tlbsExceptionHandler ! = 0 ) ;
if ( TLBenabled )
{
m_ee . m_pAddrTranslator = & TranslateAddressTLB ;
m_ee . m_TLBExceptionChecker = & CheckTLBExceptions ;
}
else
{
m_ee . m_pAddrTranslator = & TranslateAddress ;
m_ee . m_TLBExceptionChecker = nullptr ;
}
}
//The EE kernel defines some default TLB entries
//These defines seek to allow simple translation without scanning the TLB
//Direct access to physical addresses
# define TLB_IS_DIRECT_VADDRESS(a) ((a) <= 0x1FFFFFFF)
# define TLB_TRANSLATE_DIRECT_VADDRESS(a) ((a)&0x1FFFFFFF)
//RAM access, "uncached" as per TLB entry
# define TLB_IS_UNCACHED_RAM_VADDRESS(a) (((a) >= 0x20100000) && ((a) <= 0x21FFFFFF))
# define TLB_TRANSLATE_UNCACHED_RAM_VADDRESS(a) ((a)-0x20000000)
//RAM access, "uncached & accelerated" as per TLB entry
# define TLB_IS_UNCACHED_FAST_RAM_VADDRESS(a) (((a) >= 0x30100000) && ((a) <= 0x31FFFFFF))
# define TLB_TRANSLATE_UNCACHED_FAST_RAM_VADDRESS(a) ((a)-0x30000000)
//SPR memory access, the TLB entry for this should have the SPR bit set
# define TLB_IS_SPR_VADDRESS(a) (((a) >= 0x70000000) && ((a) <= 0x70003FFF))
# define TLB_TRANSLATE_SPR_VADDRESS(a) ((a) - (0x70000000 - PS2::EE_SPR_ADDR))
2015-05-06 00:54:15 -04:00
uint32 CPS2OS : : TranslateAddress ( CMIPS * , uint32 vaddrLo )
{
2020-08-04 13:29:59 -04:00
if ( TLB_IS_SPR_VADDRESS ( vaddrLo ) )
{
return TLB_TRANSLATE_SPR_VADDRESS ( vaddrLo ) ;
}
if ( TLB_IS_UNCACHED_FAST_RAM_VADDRESS ( vaddrLo ) )
{
return TLB_TRANSLATE_UNCACHED_FAST_RAM_VADDRESS ( vaddrLo ) ;
}
//No need to check "uncached" RAM access here, will be translated correctly by the macro below
return TLB_TRANSLATE_DIRECT_VADDRESS ( vaddrLo ) ;
}
uint32 CPS2OS : : TranslateAddressTLB ( CMIPS * context , uint32 vaddrLo )
{
if ( TLB_IS_DIRECT_VADDRESS ( vaddrLo ) )
{
return TLB_TRANSLATE_DIRECT_VADDRESS ( vaddrLo ) ;
}
if ( TLB_IS_UNCACHED_RAM_VADDRESS ( vaddrLo ) )
{
return TLB_TRANSLATE_UNCACHED_RAM_VADDRESS ( vaddrLo ) ;
}
if ( TLB_IS_UNCACHED_FAST_RAM_VADDRESS ( vaddrLo ) )
2015-05-06 00:54:15 -04:00
{
2020-08-04 13:29:59 -04:00
return TLB_TRANSLATE_UNCACHED_FAST_RAM_VADDRESS ( vaddrLo ) ;
2015-05-06 00:54:15 -04:00
}
2020-08-04 13:29:59 -04:00
if ( TLB_IS_SPR_VADDRESS ( vaddrLo ) )
2015-05-06 00:54:15 -04:00
{
2020-08-04 13:29:59 -04:00
return TLB_TRANSLATE_SPR_VADDRESS ( vaddrLo ) ;
2015-05-06 00:54:15 -04:00
}
2020-08-04 13:29:59 -04:00
for ( uint32 i = 0 ; i < MIPSSTATE : : TLB_ENTRY_MAX ; i + + )
{
const auto & entry = context - > m_State . tlbEntries [ i ] ;
if ( entry . entryHi = = 0 ) continue ;
uint32 pageSize = ( ( entry . pageMask > > 13 ) + 1 ) * 0x1000 ;
uint32 vpnMask = ( pageSize * 2 ) - 1 ;
uint32 vpn = vaddrLo & ~ vpnMask ;
uint32 tlbVpn = entry . entryHi & ~ vpnMask ;
if ( vpn = = tlbVpn )
{
uint32 mask = ( pageSize - 1 ) ;
uint32 entryLo = ( vaddrLo & pageSize ) ? entry . entryLo1 : entry . entryLo0 ;
assert ( entryLo & CCOP_SCU : : ENTRYLO_GLOBAL ) ;
assert ( entryLo & CCOP_SCU : : ENTRYLO_VALID ) ;
uint32 pfn = ( ( entryLo > > 6 ) < < 12 ) ;
uint32 paddr = pfn + ( vaddrLo & mask ) ;
return paddr ;
}
}
//Shouldn't come here
//assert(false);
2015-05-06 00:54:15 -04:00
return vaddrLo & 0x1FFFFFFF ;
}
2020-08-04 13:29:59 -04:00
uint32 CPS2OS : : CheckTLBExceptions ( CMIPS * context , uint32 vaddrLo , uint32 isWrite )
{
if ( TLB_IS_DIRECT_VADDRESS ( vaddrLo ) )
{
return MIPS_EXCEPTION_NONE ;
}
if ( TLB_IS_UNCACHED_RAM_VADDRESS ( vaddrLo ) )
{
return MIPS_EXCEPTION_NONE ;
}
if ( TLB_IS_UNCACHED_FAST_RAM_VADDRESS ( vaddrLo ) )
{
return MIPS_EXCEPTION_NONE ;
}
if ( TLB_IS_SPR_VADDRESS ( vaddrLo ) )
{
return MIPS_EXCEPTION_NONE ;
}
for ( uint32 i = 0 ; i < MIPSSTATE : : TLB_ENTRY_MAX ; i + + )
{
const auto & entry = context - > m_State . tlbEntries [ i ] ;
if ( entry . entryHi = = 0 ) continue ;
uint32 pageSize = ( ( entry . pageMask > > 13 ) + 1 ) * 0x1000 ;
uint32 vpnMask = ( pageSize * 2 ) - 1 ;
uint32 vpn = vaddrLo & ~ vpnMask ;
uint32 tlbVpn = entry . entryHi & ~ vpnMask ;
if ( vpn = = tlbVpn )
{
uint32 entryLo = ( vaddrLo & pageSize ) ? entry . entryLo1 : entry . entryLo0 ;
assert ( entryLo & CCOP_SCU : : ENTRYLO_GLOBAL ) ;
if ( ( entryLo & CCOP_SCU : : ENTRYLO_VALID ) = = 0 )
{
//This causes a TLBL or TLBS exception, but should use the common vector
context - > m_State . nCOP0 [ CCOP_SCU : : CAUSE ] & = ~ CCOP_SCU : : CAUSE_EXCCODE_MASK ;
context - > m_State . nCOP0 [ CCOP_SCU : : CAUSE ] | = isWrite ? CCOP_SCU : : CAUSE_EXCCODE_TLBS : CCOP_SCU : : CAUSE_EXCCODE_TLBL ;
context - > m_State . nCOP0 [ CCOP_SCU : : BADVADDR ] = vaddrLo ;
context - > m_State . nHasException = MIPS_EXCEPTION_TLB ;
return context - > m_State . nHasException ;
}
assert ( ! isWrite | | ( ( entryLo & CCOP_SCU : : ENTRYLO_DIRTY ) ! = 0 ) ) ;
return MIPS_EXCEPTION_NONE ;
}
}
//assert(false);
//We should probably raise some kind of exception here since we didn't match anything
return MIPS_EXCEPTION_NONE ;
}
2015-05-06 00:54:15 -04:00
//////////////////////////////////////////////////
//System Calls
//////////////////////////////////////////////////
void CPS2OS : : sc_Unhandled ( )
{
2018-05-25 12:38:59 -04:00
CLog : : GetInstance ( ) . Warn ( LOG_NAME , " Unknown system call (0x%X) called from 0x%08X. \r \n " , m_ee . m_State . nGPR [ 3 ] . nV [ 0 ] , m_ee . m_State . nPC ) ;
2015-05-06 00:54:15 -04:00
}
//02
void CPS2OS : : sc_GsSetCrt ( )
{
2018-04-30 21:01:23 +01: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 ) ;
2015-05-06 00:54:15 -04:00
if ( m_gs ! = NULL )
{
m_gs - > SetCrt ( isInterlaced , mode , isFrameMode ) ;
}
2021-02-24 16:04:10 -05:00
OnCrtModeChange ( ) ;
2015-05-06 00:54:15 -04:00
}
//04
void CPS2OS : : sc_Exit ( )
{
OnRequestExit ( ) ;
}
//06
void CPS2OS : : sc_LoadExecPS2 ( )
{
2018-04-30 21:01:23 +01:00
uint32 filePathPtr = 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 ] ;
2015-05-06 00:54:15 -04:00
ArgumentList arguments ;
for ( uint32 i = 0 ; i < argCount ; i + + )
{
2015-12-02 22:40:54 -05:00
uint32 argValuePtr = * reinterpret_cast < uint32 * > ( GetStructPtr ( argValuesPtr + i * 4 ) ) ;
arguments . push_back ( reinterpret_cast < const char * > ( GetStructPtr ( argValuePtr ) ) ) ;
2015-05-06 00:54:15 -04:00
}
2015-12-02 22:40:54 -05:00
std : : string filePath = reinterpret_cast < const char * > ( GetStructPtr ( filePathPtr ) ) ;
if ( filePath . find ( ' : ' ) = = std : : string : : npos )
{
//Unreal Tournament doesn't provide drive info in path
filePath = " cdrom0: " + filePath ;
}
OnRequestLoadExecutable ( filePath . c_str ( ) , arguments ) ;
2015-05-06 00:54:15 -04:00
}
2015-06-20 02:15:55 -04:00
//07
void CPS2OS : : sc_ExecPS2 ( )
{
2018-04-30 21:01:23 +01:00
uint32 pc = m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ;
uint32 gp = m_ee . m_State . nGPR [ SC_PARAM1 ] . nV [ 0 ] ;
uint32 argCount = m_ee . m_State . nGPR [ SC_PARAM2 ] . nV [ 0 ] ;
uint32 argValuesPtr = m_ee . m_State . nGPR [ SC_PARAM3 ] . nV [ 0 ] ;
2015-06-20 02:15:55 -04:00
2016-05-08 17:43:02 -04:00
//This is used by Gran Turismo 4. The game clears the program
//loaded initially, so, we need to make sure there's no stale
//threads or handlers
sc_ExitDeleteThread ( ) ;
assert ( m_currentThreadId = = m_idleThreadId ) ;
//Clear all remaining INTC handlers
std : : vector < uint32 > intcHandlerIds ;
for ( const auto & intcHandlerPair : m_intcHandlerQueue )
{
intcHandlerIds . push_back ( intcHandlerPair . first ) ;
}
for ( const auto & intcHandlerId : intcHandlerIds )
{
m_intcHandlerQueue . Unlink ( intcHandlerId ) ;
m_intcHandlers . Free ( intcHandlerId ) ;
}
2018-09-14 13:28:23 -04:00
//Also make sure all interrupts are masked
{
uint32 intcMask = m_ee . m_pMemoryMap - > GetWord ( CINTC : : INTC_MASK ) ;
m_ee . m_pMemoryMap - > SetWord ( CINTC : : INTC_MASK , intcMask ) ;
}
2016-05-08 17:43:02 -04:00
2015-06-20 02:15:55 -04:00
m_ee . m_State . nPC = pc ;
m_ee . m_State . nGPR [ CMIPS : : GP ] . nD0 = static_cast < int32 > ( gp ) ;
2018-10-11 12:41:37 -04:00
ArgumentList arguments ;
for ( uint32 i = 0 ; i < argCount ; i + + )
{
uint32 argValuePtr = * reinterpret_cast < uint32 * > ( GetStructPtr ( argValuesPtr + i * 4 ) ) ;
arguments . push_back ( reinterpret_cast < const char * > ( GetStructPtr ( argValuePtr ) ) ) ;
}
m_currentArguments = arguments ;
2015-06-20 02:15:55 -04:00
}
2018-08-27 07:31:18 -04:00
//0D
void CPS2OS : : sc_SetVTLBRefillHandler ( )
{
2019-02-21 18:51:00 -05:00
uint32 cause = m_ee . m_State . nGPR [ SC_PARAM0 ] . nV0 ;
uint32 handler = m_ee . m_State . nGPR [ SC_PARAM1 ] . nV0 ;
2020-08-04 13:29:59 -04:00
switch ( cause < < 2 )
2019-02-21 18:51:00 -05:00
{
2020-08-04 13:29:59 -04:00
case CCOP_SCU : : CAUSE_EXCCODE_TLBL :
2019-02-21 18:51:00 -05:00
m_tlblExceptionHandler = handler ;
break ;
2020-08-04 13:29:59 -04:00
case CCOP_SCU : : CAUSE_EXCCODE_TLBS :
2019-02-21 18:51:00 -05:00
m_tlbsExceptionHandler = handler ;
break ;
}
2020-08-04 13:29:59 -04:00
UpdateTLBEnabledState ( ) ;
2018-08-27 07:31:18 -04:00
}
//0E
void CPS2OS : : sc_SetVCommonHandler ( )
{
//TODO: Enable TLB processing
}
2015-05-06 00:54:15 -04:00
//10
void CPS2OS : : sc_AddIntcHandler ( )
{
2018-04-30 21:01:23 +01: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 ] ;
2015-05-06 00:54:15 -04:00
2015-07-25 20:13:59 -04:00
uint32 id = m_intcHandlers . Allocate ( ) ;
if ( static_cast < int32 > ( id ) = = - 1 )
2015-05-06 00:54:15 -04:00
{
2015-07-25 20:13:59 -04:00
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = static_cast < int32 > ( - 1 ) ;
2015-05-06 00:54:15 -04:00
return ;
}
2015-07-25 20:13:59 -04:00
auto handler = m_intcHandlers [ id ] ;
2018-04-30 21:01:23 +01:00
handler - > address = address ;
handler - > cause = cause ;
handler - > arg = arg ;
handler - > gp = m_ee . m_State . nGPR [ CMIPS : : GP ] . nV [ 0 ] ;
2015-05-06 00:54:15 -04:00
2015-07-25 20:13:59 -04:00
if ( next = = 0 )
{
m_intcHandlerQueue . PushFront ( id ) ;
}
else if ( static_cast < int32 > ( next ) = = - 1 )
{
m_intcHandlerQueue . PushBack ( id ) ;
}
else
{
m_intcHandlerQueue . AddBefore ( next , id ) ;
}
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = static_cast < int32 > ( id ) ;
2015-05-06 00:54:15 -04:00
}
//11
void CPS2OS : : sc_RemoveIntcHandler ( )
{
2017-10-04 07:20:42 -04:00
uint32 cause = m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ;
2018-04-30 21:01:23 +01:00
uint32 id = m_ee . m_State . nGPR [ SC_PARAM1 ] . nV [ 0 ] ;
2015-05-06 00:54:15 -04:00
2015-07-25 20:13:59 -04:00
auto handler = m_intcHandlers [ id ] ;
if ( ! handler )
2015-05-06 00:54:15 -04:00
{
2015-07-25 20:13:59 -04:00
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = static_cast < int32 > ( - 1 ) ;
2015-05-06 00:54:15 -04:00
return ;
}
2017-09-28 09:43:06 -04:00
assert ( handler - > cause = = cause ) ;
2015-05-06 00:54:15 -04:00
2015-07-25 20:13:59 -04:00
m_intcHandlerQueue . Unlink ( id ) ;
m_intcHandlers . Free ( id ) ;
2015-05-06 00:54:15 -04:00
2017-10-04 07:25:13 -04:00
int32 handlerCount = 0 ;
for ( const auto & handler : m_intcHandlers )
{
if ( ! handler ) continue ;
if ( handler - > cause ! = cause ) continue ;
handlerCount + + ;
}
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = handlerCount ;
2015-05-06 00:54:15 -04:00
}
//12
void CPS2OS : : sc_AddDmacHandler ( )
{
2018-04-30 21:01:23 +01: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 ] ;
2015-05-06 00:54:15 -04:00
uint32 id = m_dmacHandlers . Allocate ( ) ;
2015-07-26 01:11:43 -04:00
if ( static_cast < int32 > ( id ) = = - 1 )
2015-05-06 00:54:15 -04:00
{
2015-07-26 01:11:43 -04:00
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = static_cast < int32 > ( - 1 ) ;
2015-05-06 00:54:15 -04:00
return ;
}
auto handler = m_dmacHandlers [ id ] ;
2018-04-30 21:01:23 +01:00
handler - > address = address ;
handler - > channel = channel ;
handler - > arg = arg ;
handler - > gp = m_ee . m_State . nGPR [ CMIPS : : GP ] . nV [ 0 ] ;
2015-05-06 00:54:15 -04:00
2015-07-26 01:11:43 -04:00
if ( next = = 0 )
{
m_dmacHandlerQueue . PushFront ( id ) ;
}
else if ( static_cast < int32 > ( next ) = = - 1 )
{
m_dmacHandlerQueue . PushBack ( id ) ;
}
else
{
m_dmacHandlerQueue . AddBefore ( next , id ) ;
}
2015-05-06 00:54:15 -04:00
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = id ;
}
//13
void CPS2OS : : sc_RemoveDmacHandler ( )
{
2017-10-04 07:20:42 -04:00
uint32 channel = m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ;
2018-04-30 21:01:23 +01:00
uint32 id = m_ee . m_State . nGPR [ SC_PARAM1 ] . nV [ 0 ] ;
2015-05-06 00:54:15 -04:00
auto handler = m_dmacHandlers [ id ] ;
2015-07-26 01:11:43 -04:00
if ( ! handler )
2015-05-06 00:54:15 -04:00
{
2015-07-26 01:11:43 -04:00
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = static_cast < int32 > ( - 1 ) ;
2015-05-06 00:54:15 -04:00
return ;
}
2017-09-28 09:43:06 -04:00
assert ( handler - > channel = = channel ) ;
2015-05-06 00:54:15 -04:00
2015-07-26 01:11:43 -04:00
m_dmacHandlerQueue . Unlink ( id ) ;
2015-05-06 00:54:15 -04:00
m_dmacHandlers . Free ( id ) ;
2017-10-04 07:25:13 -04:00
int32 handlerCount = 0 ;
for ( const auto & handler : m_dmacHandlers )
{
if ( ! handler ) continue ;
if ( handler - > channel ! = channel ) continue ;
handlerCount + + ;
}
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = handlerCount ;
2015-05-06 00:54:15 -04:00
}
//14
2016-09-25 14:53:30 -04:00
//1A
2015-05-06 00:54:15 -04:00
void CPS2OS : : sc_EnableIntc ( )
{
uint32 cause = m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ;
uint32 mask = 1 < < cause ;
bool changed = false ;
if ( ! ( m_ee . m_pMemoryMap - > GetWord ( CINTC : : INTC_MASK ) & mask ) )
{
m_ee . m_pMemoryMap - > SetWord ( CINTC : : INTC_MASK , mask ) ;
changed = true ;
}
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = changed ? 1 : 0 ;
}
//15
2016-09-25 14:53:30 -04:00
//1B
2015-05-06 00:54:15 -04:00
void CPS2OS : : sc_DisableIntc ( )
{
uint32 cause = m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ;
uint32 mask = 1 < < cause ;
bool changed = false ;
if ( m_ee . m_pMemoryMap - > GetWord ( CINTC : : INTC_MASK ) & mask )
{
m_ee . m_pMemoryMap - > SetWord ( CINTC : : INTC_MASK , mask ) ;
changed = true ;
}
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = changed ? 1 : 0 ;
}
//16
2016-08-29 22:15:29 +09:00
//1C
2015-05-06 00:54:15 -04:00
void CPS2OS : : sc_EnableDmac ( )
{
uint32 channel = m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ;
uint32 registerId = 0x10000 < < channel ;
if ( ! ( m_ee . m_pMemoryMap - > GetWord ( CDMAC : : D_STAT ) & registerId ) )
{
m_ee . m_pMemoryMap - > SetWord ( CDMAC : : D_STAT , registerId ) ;
}
//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
2016-08-29 22:15:29 +09:00
//1D
2015-05-06 00:54:15 -04:00
void CPS2OS : : sc_DisableDmac ( )
{
uint32 channel = m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ;
uint32 registerId = 0x10000 < < channel ;
if ( m_ee . m_pMemoryMap - > GetWord ( CDMAC : : D_STAT ) & registerId )
{
m_ee . m_pMemoryMap - > SetWord ( CDMAC : : D_STAT , registerId ) ;
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = 1 ;
}
else
{
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = 0 ;
}
}
2019-08-16 07:49:13 -04:00
//18/1E
2015-05-06 00:54:15 -04:00
void CPS2OS : : sc_SetAlarm ( )
{
2018-04-30 21:01:23 +01:00
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 ] ;
2015-05-06 00:54:15 -04:00
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 ] ;
2018-04-30 21:01:23 +01:00
alarm - > delay = delay ;
alarm - > callback = callback ;
alarm - > callbackParam = callbackParam ;
alarm - > gp = m_ee . m_State . nGPR [ CMIPS : : GP ] . nV0 ;
2015-05-06 00:54:15 -04:00
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 ) ;
}
//20
void CPS2OS : : sc_CreateThread ( )
{
auto threadParam = reinterpret_cast < THREADPARAM * > ( GetStructPtr ( m_ee . m_State . nGPR [ SC_PARAM0 ] . nV0 ) ) ;
2015-08-06 01:20:04 -04:00
uint32 id = m_threads . Allocate ( ) ;
if ( static_cast < int32 > ( id ) = = - 1 )
2015-05-06 00:54:15 -04:00
{
2015-08-06 01:20:04 -04:00
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = static_cast < int32 > ( id ) ;
2015-05-06 00:54:15 -04:00
return ;
}
2015-08-08 23:36:00 -04:00
auto parentThread = m_threads [ m_currentThreadId ] ;
2015-08-06 01:20:04 -04:00
assert ( parentThread ) ;
2015-05-06 00:54:15 -04:00
uint32 heapBase = parentThread - > heapBase ;
2015-07-12 00:00:35 -04:00
assert ( threadParam - > initPriority < 128 ) ;
2015-05-06 00:54:15 -04:00
2015-08-06 01:20:04 -04:00
auto thread = m_threads [ id ] ;
2018-04-30 21:01:23 +01:00
thread - > status = THREAD_ZOMBIE ;
thread - > stackBase = threadParam - > stackBase ;
thread - > epc = threadParam - > threadProc ;
thread - > threadProc = threadParam - > threadProc ;
thread - > initPriority = threadParam - > initPriority ;
thread - > heapBase = heapBase ;
thread - > wakeUpCount = 0 ;
thread - > gp = threadParam - > gp ;
thread - > stackSize = threadParam - > stackSize ;
2015-05-06 00:54:15 -04:00
2016-11-20 17:09:58 -05:00
ThreadReset ( id ) ;
2015-05-06 00:54:15 -04:00
2016-11-20 15:36:48 -05:00
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = static_cast < int32 > ( id ) ;
2015-05-06 00:54:15 -04:00
}
//21
void CPS2OS : : sc_DeleteThread ( )
{
uint32 id = m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ;
2015-08-08 23:36:00 -04:00
if ( id = = m_currentThreadId )
2015-05-06 00:54:15 -04:00
{
2015-05-28 00:54:05 -04:00
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = static_cast < int32 > ( - 1 ) ;
return ;
}
if ( id > = MAX_THREAD )
{
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = static_cast < int32 > ( - 1 ) ;
2015-05-06 00:54:15 -04:00
return ;
}
2015-08-06 01:20:04 -04:00
auto thread = m_threads [ id ] ;
if ( ! thread )
2015-05-06 00:54:15 -04:00
{
2015-05-28 00:54:05 -04:00
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = static_cast < int32 > ( - 1 ) ;
return ;
}
if ( thread - > status ! = THREAD_ZOMBIE )
{
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = static_cast < int32 > ( - 1 ) ;
2015-05-06 00:54:15 -04:00
return ;
}
2015-08-06 01:20:04 -04:00
m_threads . Free ( id ) ;
2015-05-06 00:54:15 -04:00
2015-05-28 00:54:05 -04:00
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = static_cast < int32 > ( id ) ;
2015-05-06 00:54:15 -04:00
}
//22
void CPS2OS : : sc_StartThread ( )
{
2018-04-30 21:01:23 +01:00
uint32 id = m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ;
uint32 arg = m_ee . m_State . nGPR [ SC_PARAM1 ] . nV [ 0 ] ;
2015-05-06 00:54:15 -04:00
2015-08-06 01:20:04 -04:00
auto thread = m_threads [ id ] ;
if ( ! thread )
2015-05-06 00:54:15 -04:00
{
2015-08-06 01:20:04 -04:00
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = static_cast < int32 > ( - 1 ) ;
2015-05-06 00:54:15 -04:00
return ;
}
assert ( thread - > status = = THREAD_ZOMBIE ) ;
thread - > status = THREAD_RUNNING ;
2018-04-30 21:01:23 +01:00
thread - > epc = thread - > threadProc ;
2015-05-06 00:54:15 -04:00
2016-12-24 18:25:56 -05:00
auto context = reinterpret_cast < THREADCONTEXT * > ( GetStructPtr ( thread - > contextPtr ) ) ;
2015-05-06 00:54:15 -04:00
context - > gpr [ CMIPS : : A0 ] . nV0 = arg ;
2015-08-06 01:20:04 -04:00
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = static_cast < int32 > ( id ) ;
2015-05-24 23:02:55 -04:00
2015-08-09 00:03:42 -04:00
LinkThread ( id ) ;
2015-05-24 23:02:55 -04:00
ThreadShakeAndBake ( ) ;
2015-05-06 00:54:15 -04:00
}
//23
void CPS2OS : : sc_ExitThread ( )
{
2015-08-08 23:36:00 -04:00
uint32 threadId = m_currentThreadId ;
2015-07-12 00:01:51 -04:00
2015-08-06 01:20:04 -04:00
auto thread = m_threads [ threadId ] ;
2015-05-06 00:54:15 -04:00
thread - > status = THREAD_ZOMBIE ;
2015-08-09 00:03:42 -04:00
UnlinkThread ( threadId ) ;
2015-07-12 00:01:51 -04:00
2015-05-06 00:54:15 -04:00
ThreadShakeAndBake ( ) ;
2016-11-20 17:09:58 -05:00
ThreadReset ( threadId ) ;
2015-10-27 00:22:51 -04:00
CheckLivingThreads ( ) ;
2015-05-06 00:54:15 -04:00
}
2015-06-03 04:05:59 -04:00
//24
void CPS2OS : : sc_ExitDeleteThread ( )
{
2015-08-08 23:36:00 -04:00
uint32 threadId = m_currentThreadId ;
2015-08-06 01:20:04 -04:00
auto thread = m_threads [ threadId ] ;
2015-06-03 04:05:59 -04:00
thread - > status = THREAD_ZOMBIE ;
2015-08-09 00:03:42 -04:00
UnlinkThread ( threadId ) ;
2015-06-03 04:05:59 -04:00
ThreadShakeAndBake ( ) ;
2015-08-06 01:20:04 -04:00
m_threads . Free ( threadId ) ;
2015-10-27 00:22:51 -04:00
CheckLivingThreads ( ) ;
2015-06-03 04:05:59 -04:00
}
2015-05-06 00:54:15 -04:00
//25
void CPS2OS : : sc_TerminateThread ( )
{
uint32 id = m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ;
2015-08-08 23:36:00 -04:00
if ( id = = m_currentThreadId )
2015-05-06 00:54:15 -04:00
{
2015-07-04 22:35:53 -04:00
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = static_cast < int32 > ( - 1 ) ;
return ;
}
2015-08-06 01:20:04 -04:00
auto thread = m_threads [ id ] ;
if ( ! thread )
2015-05-06 00:54:15 -04:00
{
2015-07-04 22:35:53 -04:00
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = static_cast < int32 > ( - 1 ) ;
return ;
}
if ( thread - > status = = THREAD_ZOMBIE )
{
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = static_cast < int32 > ( - 1 ) ;
2015-05-06 00:54:15 -04:00
return ;
}
thread - > status = THREAD_ZOMBIE ;
2015-08-09 00:03:42 -04:00
UnlinkThread ( id ) ;
2016-11-20 17:09:58 -05:00
ThreadReset ( id ) ;
2015-07-12 00:01:51 -04:00
2015-07-04 22:35:53 -04:00
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = static_cast < int32 > ( id ) ;
2015-05-06 00:54:15 -04:00
}
//29
//2A
void CPS2OS : : sc_ChangeThreadPriority ( )
{
2018-04-30 21:01:23 +01: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 ] ;
2015-05-06 00:54:15 -04:00
2015-08-06 01:20:04 -04:00
auto thread = m_threads [ id ] ;
if ( ! thread )
2015-05-06 00:54:15 -04:00
{
2015-08-06 01:20:04 -04:00
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = static_cast < int32 > ( - 1 ) ;
2015-05-06 00:54:15 -04:00
return ;
}
2015-07-12 00:00:35 -04:00
uint32 prevPrio = thread - > currPriority ;
thread - > currPriority = prio ;
2015-05-06 00:54:15 -04:00
2015-08-06 01:20:04 -04:00
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = static_cast < int32 > ( prevPrio ) ;
2015-05-06 00:54:15 -04:00
2015-08-09 00:03:42 -04:00
//Reschedule if thread is already running
if ( thread - > status = = THREAD_RUNNING )
{
UnlinkThread ( id ) ;
LinkThread ( id ) ;
}
2015-05-06 00:54:15 -04:00
if ( ! isInt )
{
ThreadShakeAndBake ( ) ;
}
}
//2B
void CPS2OS : : sc_RotateThreadReadyQueue ( )
{
uint32 prio = m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ;
//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
2015-08-09 00:03:42 -04:00
for ( auto threadSchedulePair : m_threadSchedule )
2015-05-06 00:54:15 -04:00
{
2015-08-09 00:03:42 -04:00
auto scheduledThread = threadSchedulePair . second ;
if ( scheduledThread - > currPriority = = prio )
2015-05-06 00:54:15 -04:00
{
2015-08-09 00:03:42 -04:00
UnlinkThread ( threadSchedulePair . first ) ;
LinkThread ( threadSchedulePair . first ) ;
2015-05-06 00:54:15 -04:00
break ;
}
}
2015-08-09 00:03:42 -04:00
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = static_cast < int32 > ( prio ) ;
2015-05-06 00:54:15 -04:00
2015-08-09 00:03:42 -04:00
ThreadShakeAndBake ( ) ;
2015-05-06 00:54:15 -04:00
}
2018-06-19 19:12:34 -04:00
//2D/2E
void CPS2OS : : sc_ReleaseWaitThread ( )
{
2018-06-24 22:27:58 -04:00
uint32 id = m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ;
2018-06-19 19:12:34 -04:00
bool isInt = m_ee . m_State . nGPR [ 3 ] . nV [ 0 ] = = 0x2E ;
auto thread = m_threads [ id ] ;
if ( ! thread )
{
2018-06-22 13:27:21 -04:00
CLog : : GetInstance ( ) . Warn ( LOG_NAME , SYSCALL_NAME_RELEASEWAITTHREAD " : Used on thread that doesn't exist (%d). " ,
2018-06-24 22:27:58 -04:00
id ) ;
2018-06-19 19:12:34 -04:00
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = static_cast < int32 > ( - 1 ) ;
return ;
}
//Must also work with THREAD_WAITING
assert ( thread - > status ! = THREAD_WAITING ) ;
if ( thread - > status ! = THREAD_SLEEPING )
{
2018-06-22 13:27:21 -04:00
CLog : : GetInstance ( ) . Warn ( LOG_NAME , SYSCALL_NAME_RELEASEWAITTHREAD " : Used on non sleeping thread (%d). " ,
2018-06-24 22:27:58 -04:00
id ) ;
2018-06-19 19:12:34 -04:00
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = static_cast < int32 > ( - 1 ) ;
return ;
}
//TODO: Check what happens to wakeUpCount
thread - > wakeUpCount = 0 ;
thread - > status = THREAD_RUNNING ;
LinkThread ( id ) ;
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = static_cast < int32 > ( id ) ;
if ( ! isInt )
{
ThreadShakeAndBake ( ) ;
}
}
2015-05-06 00:54:15 -04:00
//2F
void CPS2OS : : sc_GetThreadId ( )
{
2015-08-08 23:36:00 -04:00
m_ee . m_State . nGPR [ SC_RETURN ] . nV [ 0 ] = m_currentThreadId ;
2015-05-06 00:54:15 -04:00
m_ee . m_State . nGPR [ SC_RETURN ] . nV [ 1 ] = 0 ;
}
//30
void CPS2OS : : sc_ReferThreadStatus ( )
{
2018-04-30 21:01:23 +01:00
uint32 id = m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ;
uint32 statusPtr = m_ee . m_State . nGPR [ SC_PARAM1 ] . nV [ 0 ] ;
2015-05-06 00:54:15 -04:00
2015-05-19 03:18:31 -04:00
if ( id > = MAX_THREAD )
{
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = static_cast < int32 > ( - 1 ) ;
return ;
}
if ( id = = 0 )
{
2015-08-08 23:36:00 -04:00
id = m_currentThreadId ;
2015-05-19 03:18:31 -04:00
}
2015-08-06 01:20:04 -04:00
auto thread = m_threads [ id ] ;
if ( ! thread )
2015-05-06 00:54:15 -04:00
{
2021-03-17 13:59:59 -04:00
//Returns 0 if thread has been deleted (needed by MGS2)
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = static_cast < int32 > ( 0 ) ;
2015-05-06 00:54:15 -04:00
return ;
}
uint32 ret = 0 ;
switch ( thread - > status )
{
case THREAD_RUNNING :
2015-08-08 23:36:00 -04:00
if ( id = = m_currentThreadId )
2015-05-22 01:26:38 -04:00
{
ret = THS_RUN ;
}
else
{
ret = THS_READY ;
}
2015-05-06 00:54:15 -04:00
break ;
case THREAD_WAITING :
case THREAD_SLEEPING :
2015-05-22 01:26:38 -04:00
ret = THS_WAIT ;
2015-05-06 00:54:15 -04:00
break ;
case THREAD_SUSPENDED :
2015-05-22 01:26:38 -04:00
ret = THS_SUSPEND ;
2015-05-06 00:54:15 -04:00
break ;
case THREAD_SUSPENDED_WAITING :
case THREAD_SUSPENDED_SLEEPING :
2015-05-22 01:26:38 -04:00
ret = ( THS_WAIT | THS_SUSPEND ) ;
2015-05-06 00:54:15 -04:00
break ;
case THREAD_ZOMBIE :
2015-05-22 01:26:38 -04:00
ret = THS_DORMANT ;
2015-05-06 00:54:15 -04:00
break ;
}
2016-01-10 22:00:18 -05:00
uint32 waitType = 0 ;
switch ( thread - > status )
{
case THREAD_SLEEPING :
case THREAD_SUSPENDED_SLEEPING :
waitType = 1 ;
break ;
case THREAD_WAITING :
case THREAD_SUSPENDED_WAITING :
waitType = 2 ;
break ;
default :
waitType = 0 ;
break ;
}
2015-05-06 00:54:15 -04:00
if ( statusPtr ! = 0 )
{
2016-01-10 22:00:18 -05:00
auto status = reinterpret_cast < THREADSTATUS * > ( GetStructPtr ( statusPtr ) ) ;
2015-05-06 00:54:15 -04:00
2018-04-30 21:01:23 +01:00
status - > status = ret ;
status - > initPriority = thread - > initPriority ;
status - > currPriority = thread - > currPriority ;
status - > stackBase = thread - > stackBase ;
status - > stackSize = thread - > stackSize ;
status - > waitType = waitType ;
status - > wakeupCount = thread - > wakeUpCount ;
2015-05-06 00:54:15 -04:00
}
2015-05-19 03:17:31 -04:00
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = ret ;
2015-05-06 00:54:15 -04:00
}
//32
void CPS2OS : : sc_SleepThread ( )
{
2016-01-21 22:53:08 -05:00
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = static_cast < int32 > ( m_currentThreadId ) ;
2015-08-08 23:36:00 -04:00
auto thread = m_threads [ m_currentThreadId ] ;
2015-05-06 00:54:15 -04:00
if ( thread - > wakeUpCount = = 0 )
{
assert ( thread - > status = = THREAD_RUNNING ) ;
thread - > status = THREAD_SLEEPING ;
2015-08-09 00:03:42 -04:00
UnlinkThread ( m_currentThreadId ) ;
2015-05-06 00:54:15 -04:00
ThreadShakeAndBake ( ) ;
return ;
}
thread - > wakeUpCount - - ;
}
//33
//34
void CPS2OS : : sc_WakeupThread ( )
{
2018-04-30 21:01:23 +01:00
uint32 id = m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ;
bool isInt = m_ee . m_State . nGPR [ 3 ] . nV [ 0 ] = = 0x34 ;
2015-05-06 00:54:15 -04:00
2016-01-10 22:03:16 -05:00
if ( ( id = = 0 ) | | ( id = = m_currentThreadId ) )
{
//Can't wakeup a thread that's already running
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = static_cast < int32 > ( - 1 ) ;
return ;
}
2015-08-06 01:20:04 -04:00
auto thread = m_threads [ id ] ;
2015-08-09 00:03:42 -04:00
if ( ! thread )
{
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = static_cast < int32 > ( - 1 ) ;
return ;
}
2015-05-06 00:54:15 -04:00
2016-01-10 22:03:16 -05:00
if ( thread - > status = = THREAD_ZOMBIE )
{
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = static_cast < int32 > ( - 1 ) ;
return ;
}
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = static_cast < int32 > ( id ) ;
2015-05-06 00:54:15 -04:00
if (
2018-04-30 21:01:23 +01:00
( thread - > status = = THREAD_SLEEPING ) | |
( thread - > status = = THREAD_SUSPENDED_SLEEPING ) )
2015-05-06 00:54:15 -04:00
{
switch ( thread - > status )
{
case THREAD_SLEEPING :
thread - > status = THREAD_RUNNING ;
2015-08-09 00:03:42 -04:00
LinkThread ( id ) ;
2015-05-06 00:54:15 -04:00
break ;
case THREAD_SUSPENDED_SLEEPING :
thread - > status = THREAD_SUSPENDED ;
break ;
default :
assert ( 0 ) ;
break ;
}
if ( ! isInt )
{
ThreadShakeAndBake ( ) ;
}
}
else
{
thread - > wakeUpCount + + ;
}
}
//35
//36
void CPS2OS : : sc_CancelWakeupThread ( )
{
2018-04-30 21:01:23 +01:00
uint32 id = m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ;
bool isInt = m_ee . m_State . nGPR [ 3 ] . nV [ 0 ] = = 0x36 ;
2015-05-06 00:54:15 -04:00
2015-08-06 01:20:04 -04:00
auto thread = m_threads [ id ] ;
if ( ! thread )
2015-05-06 00:54:15 -04:00
{
2015-08-06 01:20:04 -04:00
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = static_cast < int32 > ( - 1 ) ;
2015-05-06 00:54:15 -04:00
return ;
}
uint32 wakeUpCount = thread - > wakeUpCount ;
thread - > wakeUpCount = 0 ;
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = wakeUpCount ;
}
//37
2016-10-02 16:32:43 -04:00
//38
2015-05-06 00:54:15 -04:00
void CPS2OS : : sc_SuspendThread ( )
{
uint32 id = m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ;
2016-10-02 16:32:43 -04:00
bool isInt = m_ee . m_State . nGPR [ 3 ] . nV [ 0 ] = = 0x38 ;
2015-08-19 21:59:46 -04:00
if ( id = = m_currentThreadId )
{
//This actually works on a real PS2
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = static_cast < int32 > ( - 1 ) ;
return ;
}
2015-08-06 01:20:04 -04:00
auto thread = m_threads [ id ] ;
if ( ! thread )
2015-05-06 00:54:15 -04:00
{
2015-08-16 01:06:38 -04:00
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = static_cast < int32 > ( - 1 ) ;
2015-05-06 00:54:15 -04:00
return ;
}
2015-08-19 21:59:46 -04:00
if (
2018-04-30 21:01:23 +01:00
( thread - > status = = THREAD_ZOMBIE ) | |
( thread - > status = = THREAD_SUSPENDED ) | |
( thread - > status = = THREAD_SUSPENDED_WAITING ) | |
( thread - > status = = THREAD_SUSPENDED_SLEEPING ) )
2015-08-19 21:59:46 -04:00
{
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = static_cast < int32 > ( - 1 ) ;
return ;
}
2015-05-06 00:54:15 -04:00
switch ( thread - > status )
{
case THREAD_RUNNING :
thread - > status = THREAD_SUSPENDED ;
2015-08-09 00:03:42 -04:00
UnlinkThread ( id ) ;
2015-05-06 00:54:15 -04:00
break ;
case THREAD_WAITING :
thread - > status = THREAD_SUSPENDED_WAITING ;
break ;
case THREAD_SLEEPING :
thread - > status = THREAD_SUSPENDED_SLEEPING ;
break ;
default :
assert ( 0 ) ;
break ;
}
2015-08-16 01:06:38 -04:00
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = static_cast < int32 > ( id ) ;
2016-10-02 16:32:43 -04:00
if ( ! isInt )
{
ThreadShakeAndBake ( ) ;
}
2015-05-06 00:54:15 -04:00
}
//39
void CPS2OS : : sc_ResumeThread ( )
{
uint32 id = m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ;
2015-08-19 21:59:46 -04:00
if ( id = = m_currentThreadId )
{
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = static_cast < int32 > ( - 1 ) ;
return ;
}
2015-08-06 01:20:04 -04:00
auto thread = m_threads [ id ] ;
if ( ! thread )
2015-05-06 00:54:15 -04:00
{
2015-08-16 01:06:38 -04:00
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = static_cast < int32 > ( - 1 ) ;
2015-05-06 00:54:15 -04:00
return ;
}
2015-08-19 21:59:46 -04:00
if (
2018-04-30 21:01:23 +01:00
( thread - > status = = THREAD_ZOMBIE ) | |
( thread - > status = = THREAD_RUNNING ) | |
( thread - > status = = THREAD_WAITING ) | |
( thread - > status = = THREAD_SLEEPING ) )
2015-08-19 21:59:46 -04:00
{
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = static_cast < int32 > ( - 1 ) ;
return ;
}
2015-05-06 00:54:15 -04:00
switch ( thread - > status )
{
case THREAD_SUSPENDED :
thread - > status = THREAD_RUNNING ;
2015-08-09 00:03:42 -04:00
LinkThread ( id ) ;
2015-05-06 00:54:15 -04:00
break ;
case THREAD_SUSPENDED_WAITING :
thread - > status = THREAD_WAITING ;
break ;
case THREAD_SUSPENDED_SLEEPING :
thread - > status = THREAD_SLEEPING ;
break ;
default :
assert ( 0 ) ;
break ;
}
2015-08-16 01:06:38 -04:00
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = static_cast < int32 > ( id ) ;
2015-05-06 00:54:15 -04:00
ThreadShakeAndBake ( ) ;
}
//3C
void CPS2OS : : sc_SetupThread ( )
{
uint32 stackBase = m_ee . m_State . nGPR [ SC_PARAM1 ] . nV [ 0 ] ;
uint32 stackSize = m_ee . m_State . nGPR [ SC_PARAM2 ] . nV [ 0 ] ;
uint32 stackAddr = 0 ;
if ( stackBase = = 0xFFFFFFFF )
{
2018-08-06 21:33:27 -04:00
//We need to substract 4k from RAM size because some games (Espgaluda) rely on the
//stack and heap being a very precise size. EE kernel seems to substract that amount too.
stackAddr = PS2 : : EE_RAM_SIZE - ( 4 * 1024 ) ;
2015-05-06 00:54:15 -04:00
}
else
{
stackAddr = stackBase + stackSize ;
}
uint32 argsBase = m_ee . m_State . nGPR [ SC_PARAM3 ] . nV [ 0 ] ;
//Copy arguments
{
2018-10-11 12:41:37 -04:00
uint32 argsCount = static_cast < uint32 > ( m_currentArguments . size ( ) ) ;
2015-05-06 00:54:15 -04:00
* reinterpret_cast < uint32 * > ( m_ram + argsBase ) = argsCount ;
uint32 argsPtrs = argsBase + 4 ;
//We add 1 to argsCount because argv[argc] must be equal to 0
uint32 argsPayload = argsPtrs + ( ( argsCount + 1 ) * 4 ) ;
for ( uint32 i = 0 ; i < argsCount ; i + + )
{
2018-10-11 12:41:37 -04:00
const auto & currentArg = m_currentArguments [ i ] ;
2015-05-06 00:54:15 -04:00
* reinterpret_cast < uint32 * > ( m_ram + argsPtrs + ( i * 4 ) ) = argsPayload ;
uint32 argSize = static_cast < uint32 > ( currentArg . size ( ) ) + 1 ;
memcpy ( m_ram + argsPayload , currentArg . c_str ( ) , argSize ) ;
argsPayload + = argSize ;
}
//Set argv[argc] to 0
* reinterpret_cast < uint32 * > ( m_ram + argsPtrs + ( argsCount * 4 ) ) = 0 ;
}
2018-10-01 13:05:56 -04:00
uint32 threadId = - 1 ;
if (
2018-10-04 17:07:48 -04:00
( m_currentThreadId = = 0 ) | |
( m_currentThreadId = = m_idleThreadId ) )
2018-10-01 13:05:56 -04:00
{
//No thread has been started, spawn a new thread
threadId = m_threads . Allocate ( ) ;
}
else
{
//Re-use the calling thread (needed by 007: Nightfire)
threadId = m_currentThreadId ;
UnlinkThread ( threadId ) ;
}
2015-08-06 01:20:04 -04:00
assert ( static_cast < int32 > ( threadId ) ! = - 1 ) ;
2015-05-06 00:54:15 -04:00
//Set up the main thread
2015-08-16 02:42:47 -04:00
//Priority needs to be 0 because some games rely on this
//by calling RotateThreadReadyQueue(0) (Dynasty Warriors 2)
2015-08-06 01:20:04 -04:00
auto thread = m_threads [ threadId ] ;
2018-04-30 21:01:23 +01:00
thread - > status = THREAD_RUNNING ;
thread - > stackBase = stackAddr - stackSize ;
2019-01-15 17:24:06 +08:00
thread - > stackSize = stackSize ;
2018-04-30 21:01:23 +01:00
thread - > initPriority = 0 ;
thread - > currPriority = 0 ;
thread - > contextPtr = 0 ;
2015-05-06 00:54:15 -04:00
2015-08-09 00:03:42 -04:00
LinkThread ( threadId ) ;
2015-08-08 23:36:00 -04:00
m_currentThreadId = threadId ;
2015-05-06 00:54:15 -04:00
m_ee . m_State . nGPR [ SC_RETURN ] . nV [ 0 ] = stackAddr ;
m_ee . m_State . nGPR [ SC_RETURN ] . nV [ 1 ] = 0 ;
}
//3D
void CPS2OS : : sc_SetupHeap ( )
{
2015-08-08 23:36:00 -04:00
auto thread = m_threads [ m_currentThreadId ] ;
2015-05-06 00:54:15 -04:00
uint32 heapBase = m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ;
uint32 heapSize = m_ee . m_State . nGPR [ SC_PARAM1 ] . nV [ 0 ] ;
if ( heapSize = = 0xFFFFFFFF )
{
thread - > heapBase = thread - > stackBase ;
}
else
{
thread - > heapBase = heapBase + heapSize ;
}
m_ee . m_State . nGPR [ SC_RETURN ] . nV [ 0 ] = thread - > heapBase ;
m_ee . m_State . nGPR [ SC_RETURN ] . nV [ 1 ] = 0 ;
}
//3E
void CPS2OS : : sc_EndOfHeap ( )
{
2015-08-08 23:36:00 -04:00
auto thread = m_threads [ m_currentThreadId ] ;
2015-05-06 00:54:15 -04:00
m_ee . m_State . nGPR [ SC_RETURN ] . nV [ 0 ] = thread - > heapBase ;
m_ee . m_State . nGPR [ SC_RETURN ] . nV [ 1 ] = 0 ;
}
//40
void CPS2OS : : sc_CreateSema ( )
{
auto semaParam = reinterpret_cast < SEMAPHOREPARAM * > ( GetStructPtr ( m_ee . m_State . nGPR [ SC_PARAM0 ] . nV0 ) ) ;
uint32 id = m_semaphores . Allocate ( ) ;
if ( id = = 0xFFFFFFFF )
{
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = - 1 ;
return ;
}
auto sema = m_semaphores [ id ] ;
2018-04-30 21:01:23 +01:00
sema - > count = semaParam - > initCount ;
sema - > maxCount = semaParam - > maxCount ;
2019-05-23 21:14:35 -04:00
sema - > option = semaParam - > option ;
2018-04-30 21:01:23 +01:00
sema - > waitCount = 0 ;
2015-05-06 00:54:15 -04:00
assert ( sema - > count < = sema - > maxCount ) ;
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = id ;
}
//41
void CPS2OS : : sc_DeleteSema ( )
{
uint32 id = m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ;
auto sema = m_semaphores [ id ] ;
if ( sema = = nullptr )
{
2017-01-01 18:27:51 -05:00
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = static_cast < int32 > ( - 1 ) ;
2015-05-06 00:54:15 -04:00
return ;
}
2017-01-01 18:30:19 -05:00
//Set return value now because we might reschedule
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = static_cast < int32 > ( id ) ;
//Release all threads waiting for this semaphore
2015-05-06 00:54:15 -04:00
if ( sema - > waitCount ! = 0 )
{
2017-01-01 18:30:19 -05:00
while ( sema - > waitCount ! = 0 )
{
2017-01-21 17:44:19 -05:00
bool succeeded = SemaReleaseSingleThread ( id , true ) ;
if ( ! succeeded ) break ;
2017-01-01 18:30:19 -05:00
}
ThreadShakeAndBake ( ) ;
2015-05-06 00:54:15 -04:00
}
m_semaphores . Free ( id ) ;
}
//42
//43
void CPS2OS : : sc_SignalSema ( )
{
2018-04-30 21:01:23 +01:00
bool isInt = m_ee . m_State . nGPR [ 3 ] . nV [ 0 ] = = 0x43 ;
uint32 id = m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ;
2015-05-06 00:54:15 -04:00
auto sema = m_semaphores [ id ] ;
if ( sema = = nullptr )
{
2021-04-22 15:27:33 -04:00
CLog : : GetInstance ( ) . Warn ( LOG_NAME , " Trying to signal an invalid semaphore (%d). \r \n " , id ) ;
2017-01-01 18:27:51 -05:00
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = static_cast < int32 > ( - 1 ) ;
2015-05-06 00:54:15 -04:00
return ;
}
2018-04-30 21:01:23 +01:00
2017-01-01 18:29:32 -05:00
//TODO: Check maximum value
2015-05-06 00:54:15 -04:00
2017-01-01 18:29:32 -05:00
//Set return value here because we might reschedule
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = static_cast < int32 > ( id ) ;
2015-05-06 00:54:15 -04:00
2017-01-01 18:29:32 -05:00
if ( sema - > waitCount ! = 0 )
{
SemaReleaseSingleThread ( id , false ) ;
2015-05-06 00:54:15 -04:00
if ( ! isInt )
{
ThreadShakeAndBake ( ) ;
}
}
else
{
sema - > count + + ;
}
}
//44
void CPS2OS : : sc_WaitSema ( )
{
uint32 id = m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ;
auto sema = m_semaphores [ id ] ;
if ( sema = = nullptr )
{
2021-04-22 15:27:33 -04:00
CLog : : GetInstance ( ) . Warn ( LOG_NAME , " Trying to wait an invalid semaphore (%d). \r \n " , id ) ;
2015-05-06 00:54:15 -04:00
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = - 1 ;
return ;
}
if ( sema - > count = = 0 )
{
//Put this thread in sleep mode and reschedule...
sema - > waitCount + + ;
2015-08-08 23:36:00 -04:00
auto thread = m_threads [ m_currentThreadId ] ;
2015-05-06 00:54:15 -04:00
assert ( thread - > status = = THREAD_RUNNING ) ;
2018-04-30 21:01:23 +01:00
thread - > status = THREAD_WAITING ;
2017-01-01 18:27:51 -05:00
thread - > semaWait = id ;
2015-05-06 00:54:15 -04:00
2015-08-09 00:03:42 -04:00
UnlinkThread ( m_currentThreadId ) ;
2015-05-06 00:54:15 -04:00
ThreadShakeAndBake ( ) ;
return ;
}
if ( sema - > count ! = 0 )
{
sema - > count - - ;
}
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = id ;
}
//45
2015-10-31 23:58:56 -04:00
//46
2015-05-06 00:54:15 -04:00
void CPS2OS : : sc_PollSema ( )
{
uint32 id = m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ;
auto sema = m_semaphores [ id ] ;
if ( sema = = nullptr )
{
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = - 1 ;
return ;
}
if ( sema - > count = = 0 )
{
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = - 1 ;
return ;
}
sema - > count - - ;
2018-04-30 21:01:23 +01:00
2015-05-06 00:54:15 -04:00
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = id ;
}
//47
//48
void CPS2OS : : sc_ReferSemaStatus ( )
{
bool isInt = m_ee . m_State . nGPR [ 3 ] . nV [ 0 ] ! = 0x47 ;
uint32 id = m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ;
2016-06-02 22:00:41 -04:00
auto semaParam = reinterpret_cast < SEMAPHOREPARAM * > ( GetStructPtr ( m_ee . m_State . nGPR [ SC_PARAM1 ] . nV0 ) ) ;
2015-05-06 00:54:15 -04:00
auto sema = m_semaphores [ id ] ;
if ( sema = = nullptr )
{
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = - 1 ;
return ;
}
2018-04-30 21:01:23 +01:00
semaParam - > count = sema - > count ;
semaParam - > maxCount = sema - > maxCount ;
semaParam - > waitThreads = sema - > waitCount ;
2019-05-23 21:14:35 -04:00
semaParam - > option = sema - > option ;
2015-05-06 00:54:15 -04:00
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = id ;
}
2018-05-15 12:44:16 -04:00
//4B
void CPS2OS : : sc_GetOsdConfigParam ( )
{
2020-09-09 17:13:17 -04:00
auto language = static_cast < OSD_LANGUAGE > ( CAppConfig : : GetInstance ( ) . GetPreferenceInteger ( PREF_SYSTEM_LANGUAGE ) ) ;
2020-12-17 17:46:02 -05:00
auto widescreenOutput = CAppConfig : : GetInstance ( ) . GetPreferenceBoolean ( PREF_CGSHANDLER_WIDESCREEN ) ;
2020-09-09 17:13:17 -04:00
auto configParam = make_convertible < OSDCONFIGPARAM > ( 0 ) ;
configParam . version = static_cast < uint32 > ( OSD_VERSION : : V2_EXT ) ;
configParam . jpLanguage = ( language = = OSD_LANGUAGE : : JAPANESE ) ? 0 : 1 ;
configParam . language = static_cast < uint32 > ( language ) ;
2020-12-17 17:46:02 -05:00
configParam . screenType = static_cast < uint32 > ( widescreenOutput ? OSD_SCREENTYPE : : RATIO_16_9 : OSD_SCREENTYPE : : RATIO_4_3 ) ;
2020-09-09 17:13:17 -04:00
auto configParamPtr = reinterpret_cast < uint32 * > ( GetStructPtr ( m_ee . m_State . nGPR [ SC_PARAM0 ] . nV0 ) ) ;
( * configParamPtr ) = configParam ;
2018-05-15 12:44:16 -04:00
}
2015-05-06 00:54:15 -04:00
//64
void CPS2OS : : sc_FlushCache ( )
{
uint32 operationType = m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ;
}
//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 ) ;
}
//71
void CPS2OS : : sc_GsPutIMR ( )
{
uint32 imr = m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ;
if ( m_gs ! = NULL )
{
2018-10-24 20:18:13 -04:00
m_gs - > WritePrivRegister ( CGSHandler : : GS_IMR + 0 , imr ) ;
m_gs - > WritePrivRegister ( CGSHandler : : GS_IMR + 4 , 0 ) ;
2015-05-06 00:54:15 -04:00
}
}
//73
void CPS2OS : : sc_SetVSyncFlag ( )
{
2015-05-15 19:14:03 -04:00
uint32 ptr1 = m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ;
uint32 ptr2 = m_ee . m_State . nGPR [ SC_PARAM1 ] . nV [ 0 ] ;
2015-05-06 00:54:15 -04:00
2015-05-15 19:14:03 -04:00
SetVsyncFlagPtrs ( ptr1 , ptr2 ) ;
2015-05-06 00:54:15 -04: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 ( )
{
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 ;
2015-07-25 20:13:59 -04:00
uint32 handlerId = m_intcHandlers . Allocate ( ) ;
if ( static_cast < int32 > ( handlerId ) = = - 1 )
2015-05-06 00:54:15 -04:00
{
2018-05-31 21:45:42 -04:00
CLog : : GetInstance ( ) . Warn ( LOG_NAME , " Couldn't set INTC handler through SetSyscall " ) ;
2015-05-06 00:54:15 -04:00
return ;
}
2015-07-25 20:13:59 -04:00
auto handler = m_intcHandlers [ handlerId ] ;
2018-04-30 21:01:23 +01:00
handler - > address = address & 0x1FFFFFFF ;
handler - > cause = line ;
handler - > arg = 0 ;
handler - > gp = 0 ;
2015-05-06 00:54:15 -04:00
if ( ! ( m_ee . m_pMemoryMap - > GetWord ( CINTC : : INTC_MASK ) & ( 1 < < line ) ) )
{
m_ee . m_pMemoryMap - > SetWord ( CINTC : : INTC_MASK , ( 1 < < line ) ) ;
}
2015-07-25 20:13:59 -04:00
m_intcHandlerQueue . PushFront ( handlerId ) ;
2015-05-06 00:54:15 -04:00
}
else
{
2018-05-31 21:45:42 -04:00
CLog : : GetInstance ( ) . Warn ( LOG_NAME , " Unknown syscall set (%d). \r \n " , number ) ;
2015-05-06 00:54:15 -04: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 ( )
{
2019-01-15 10:11:36 +08:00
uint32 queueId = m_ee . m_State . nGPR [ SC_PARAM0 ] . nV0 ;
uint32 queueIdx = queueId - BIOS_ID_BASE ;
if ( queueIdx > = BIOS_SIFDMA_COUNT )
{
//Act as if it was completed
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = static_cast < int32 > ( - 1 ) ;
return ;
}
2016-05-28 21:07:00 -04:00
//If SIF dma has just been set (100 cycle delay), return 'queued' status.
//This is required for Okami
2019-01-15 10:11:36 +08:00
int64 timerDiff = static_cast < uint64 > ( m_ee . m_State . nCOP0 [ CCOP_SCU : : COUNT ] ) - static_cast < uint64 > ( m_sifDmaTimes [ queueIdx ] ) ;
2016-05-28 21:07:00 -04:00
if ( ( timerDiff < 0 ) | | ( timerDiff > 100 ) )
{
//Completed
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = static_cast < int32 > ( - 1 ) ;
}
else
{
//Queued
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = static_cast < int32 > ( 1 ) ;
}
2015-05-06 00:54:15 -04:00
}
//77
void CPS2OS : : sc_SifSetDma ( )
{
2019-01-15 10:11:36 +08:00
uint32 queueIdx = m_sifDmaNextIdx ;
m_sifDmaTimes [ queueIdx ] = m_ee . m_State . nCOP0 [ CCOP_SCU : : COUNT ] ;
m_sifDmaNextIdx = ( m_sifDmaNextIdx + 1 ) % BIOS_SIFDMA_COUNT ;
2016-05-28 21:07:00 -04:00
2017-01-26 23:31:31 -05:00
auto xfers = reinterpret_cast < const SIFDMAREG * > ( GetStructPtr ( m_ee . m_State . nGPR [ SC_PARAM0 ] . nV0 ) ) ;
2015-05-06 00:54:15 -04:00
uint32 count = m_ee . m_State . nGPR [ SC_PARAM1 ] . nV [ 0 ] ;
2019-01-15 10:11:36 +08:00
//DMA might call an interrupt handler, set return value now
uint32 queueId = queueIdx + BIOS_ID_BASE ;
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = static_cast < int32 > ( queueId ) ;
2015-05-06 00:54:15 -04:00
for ( unsigned int i = 0 ; i < count ; i + + )
{
2017-01-26 23:31:31 -05:00
const auto & xfer = xfers [ i ] ;
2015-05-06 00:54:15 -04:00
2017-01-26 23:31:31 -05:00
uint32 size = ( xfer . size + 0x0F ) / 0x10 ;
assert ( ( xfer . srcAddr & 0x0F ) = = 0 ) ;
assert ( ( xfer . dstAddr & 0x03 ) = = 0 ) ;
m_ee . m_pMemoryMap - > SetWord ( CDMAC : : D6_MADR , xfer . srcAddr ) ;
m_ee . m_pMemoryMap - > SetWord ( CDMAC : : D6_TADR , xfer . dstAddr ) ;
2018-04-30 21:01:23 +01:00
m_ee . m_pMemoryMap - > SetWord ( CDMAC : : D6_QWC , size ) ;
2017-01-26 23:31:31 -05:00
m_ee . m_pMemoryMap - > SetWord ( CDMAC : : D6_CHCR , CDMAC : : CHCR_BIT : : CHCR_STR ) ;
2015-05-06 00:54:15 -04:00
}
}
//78
void CPS2OS : : sc_SifSetDChain ( )
{
//Humm, set the SIF0 DMA channel in destination chain mode?
//This syscall is invoked by the SIF dma interrupt handler (when a packet has been received)
2018-04-30 21:01:23 +01:00
//To make sure every packet generates an interrupt, the SIF will hold into any packet
2015-05-06 00:54:15 -04:00
//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 ( ) ;
}
}
//79
void CPS2OS : : sc_SifSetReg ( )
{
2018-04-30 21:01:23 +01:00
uint32 registerId = m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ;
uint32 value = m_ee . m_State . nGPR [ SC_PARAM1 ] . nV [ 0 ] ;
2015-05-06 00:54:15 -04:00
m_sif . SetRegister ( registerId , value ) ;
m_ee . m_State . nGPR [ SC_RETURN ] . nD0 = 0 ;
}
//7A
void CPS2OS : : sc_SifGetReg ( )
{
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 ) ) ;
}
//7C
void CPS2OS : : sc_Deci2Call ( )
{
2018-04-30 21:01:23 +01:00
uint32 function = m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ;
uint32 param = m_ee . m_State . nGPR [ SC_PARAM1 ] . nV [ 0 ] ;
2015-05-06 00:54:15 -04:00
switch ( function )
{
case 0x01 :
//Deci2Open
{
uint32 id = GetNextAvailableDeci2HandlerId ( ) ;
DECI2HANDLER * handler = GetDeci2Handler ( id ) ;
2018-04-30 21:01:23 +01:00
handler - > valid = 1 ;
2020-04-27 12:45:54 -04:00
handler - > device = * reinterpret_cast < uint32 * > ( GetStructPtr ( param + 0x00 ) ) ;
handler - > bufferAddr = * reinterpret_cast < uint32 * > ( GetStructPtr ( param + 0x04 ) ) ;
2015-05-06 00:54:15 -04:00
m_ee . m_State . nGPR [ SC_RETURN ] . nV [ 0 ] = id ;
m_ee . m_State . nGPR [ SC_RETURN ] . nV [ 1 ] = 0 ;
}
break ;
case 0x03 :
//Deci2Send
{
2016-06-27 20:16:32 -04:00
uint32 id = * reinterpret_cast < uint32 * > ( GetStructPtr ( param + 0x00 ) ) ;
2015-05-06 00:54:15 -04:00
DECI2HANDLER * handler = GetDeci2Handler ( id ) ;
if ( handler - > valid ! = 0 )
{
uint32 stringAddr = * reinterpret_cast < uint32 * > ( & m_ram [ handler - > bufferAddr + 0x10 ] ) ;
stringAddr & = ( PS2 : : EE_RAM_SIZE - 1 ) ;
uint32 length = m_ram [ stringAddr + 0x00 ] - 0x0C ;
uint8 * string = & m_ram [ stringAddr + 0x0C ] ;
2015-06-20 02:31:09 -04:00
m_iopBios . GetIoman ( ) - > Write ( Iop : : CIoman : : FID_STDOUT , length , string ) ;
2015-05-06 00:54:15 -04:00
}
m_ee . m_State . nGPR [ SC_RETURN ] . nV [ 0 ] = 1 ;
m_ee . m_State . nGPR [ SC_RETURN ] . nV [ 1 ] = 0 ;
}
break ;
case 0x04 :
//Deci2Poll
{
2016-06-27 20:16:32 -04:00
uint32 id = * reinterpret_cast < uint32 * > ( GetStructPtr ( param + 0x00 ) ) ;
2018-04-30 21:01:23 +01:00
2015-05-06 00:54:15 -04:00
DECI2HANDLER * handler = GetDeci2Handler ( id ) ;
if ( handler - > valid ! = 0 )
{
* ( uint32 * ) & m_ram [ handler - > bufferAddr + 0x0C ] = 0 ;
}
m_ee . m_State . nGPR [ SC_RETURN ] . nV [ 0 ] = 1 ;
m_ee . m_State . nGPR [ SC_RETURN ] . nV [ 1 ] = 0 ;
}
break ;
case 0x10 :
//kPuts
{
2017-01-28 19:49:50 -05:00
uint32 stringAddr = * reinterpret_cast < uint32 * > ( GetStructPtr ( param ) ) ;
2015-05-06 00:54:15 -04:00
uint8 * string = & m_ram [ stringAddr ] ;
m_iopBios . GetIoman ( ) - > Write ( 1 , static_cast < uint32 > ( strlen ( reinterpret_cast < char * > ( string ) ) ) , string ) ;
}
break ;
default :
2018-05-31 21:45:42 -04:00
CLog : : GetInstance ( ) . Warn ( LOG_NAME , " Unknown Deci2Call function (0x%08X) called. PC: 0x%08X. \r \n " , function , m_ee . m_State . nPC ) ;
2015-05-06 00:54:15 -04:00
break ;
}
}
//7E
void CPS2OS : : sc_MachineType ( )
{
//Return 0x100 for liberx (is this ok?)
m_ee . m_State . nGPR [ SC_RETURN ] . nV [ 0 ] = 0x100 ;
m_ee . m_State . nGPR [ SC_RETURN ] . nV [ 1 ] = 0 ;
}
//7F
void CPS2OS : : sc_GetMemorySize ( )
{
m_ee . m_State . nGPR [ SC_RETURN ] . nV [ 0 ] = PS2 : : EE_RAM_SIZE ;
m_ee . m_State . nGPR [ SC_RETURN ] . nV [ 1 ] = 0 ;
}
//////////////////////////////////////////////////
//System Call Handler
//////////////////////////////////////////////////
void CPS2OS : : HandleSyscall ( )
{
uint32 searchAddress = m_ee . m_State . nCOP0 [ CCOP_SCU : : EPC ] ;
uint32 callInstruction = m_ee . m_pMemoryMap - > GetInstruction ( searchAddress ) ;
if ( callInstruction ! = 0x0000000C )
{
//This will happen if an ADDIU R0, R0, $x instruction is encountered. Not sure if there's a use for that on the EE
2018-05-31 21:45:42 -04:00
CLog : : GetInstance ( ) . Warn ( LOG_NAME , " System call exception occured but no SYSCALL instruction found (addr = 0x%08X, opcode = 0x%08X). \r \n " ,
searchAddress , callInstruction ) ;
2015-05-06 00:54:15 -04:00
m_ee . m_State . nHasException = 0 ;
return ;
}
uint32 func = m_ee . m_State . nGPR [ 3 ] . nV [ 0 ] ;
2018-04-30 21:01:23 +01:00
2019-02-09 11:16:59 -05:00
if ( func = = SYSCALL_CUSTOM_RESCHEDULE )
2015-05-06 00:54:15 -04:00
{
//Reschedule
ThreadShakeAndBake ( ) ;
}
2019-02-09 11:26:48 -05:00
else if ( func = = SYSCALL_CUSTOM_EXITINTERRUPT )
{
//Execute ERET
m_ee . m_State . nCOP0 [ CCOP_SCU : : STATUS ] & = ~ ( CMIPS : : STATUS_EXL ) ;
m_ee . m_State . nPC = m_ee . m_State . nGPR [ CMIPS : : A0 ] . nV0 ;
if ( m_currentThreadId ! = m_idleThreadId )
{
auto thread = m_threads [ m_currentThreadId ] ;
ThreadLoadContext ( thread , true ) ;
}
ThreadShakeAndBake ( ) ;
}
2020-03-25 08:02:59 -04:00
else if ( ( func > = Ee : : CLibMc2 : : SYSCALL_RANGE_START ) & & ( func < Ee : : CLibMc2 : : SYSCALL_RANGE_END ) )
{
m_libMc2 . HandleSyscall ( m_ee ) ;
}
2015-05-06 00:54:15 -04:00
else
{
if ( func & 0x80000000 )
{
func = 0 - func ;
}
//Save for custom handler
m_ee . m_State . nGPR [ 3 ] . nV [ 0 ] = func ;
2015-10-23 23:18:32 -04:00
if ( GetCustomSyscallTable ( ) [ func ] = = 0 )
2015-05-06 00:54:15 -04:00
{
2018-04-30 21:01:23 +01:00
# ifdef _DEBUG
2015-05-06 00:54:15 -04:00
DisassembleSysCall ( static_cast < uint8 > ( func & 0xFF ) ) ;
2018-04-30 21:01:23 +01:00
# endif
2015-05-06 00:54:15 -04:00
if ( func < 0x80 )
{
( ( this ) - > * ( m_sysCall [ func & 0xFF ] ) ) ( ) ;
}
}
else
{
m_ee . GenerateException ( 0x1FC00100 ) ;
}
}
2018-09-17 17:39:49 -04:00
m_ee . m_State . nHasException = MIPS_EXCEPTION_NONE ;
2015-05-06 00:54:15 -04:00
}
2020-08-04 13:29:59 -04:00
void CPS2OS : : HandleTLBException ( )
{
assert ( m_ee . CanGenerateInterrupt ( ) ) ;
m_ee . m_State . nCOP0 [ CCOP_SCU : : STATUS ] | = CMIPS : : STATUS_EXL ;
assert ( m_ee . m_State . nDelayedJumpAddr = = MIPS_INVALID_PC ) ;
uint32 excCode = m_ee . m_State . nCOP0 [ CCOP_SCU : : CAUSE ] & CCOP_SCU : : CAUSE_EXCCODE_MASK ;
switch ( excCode )
{
case CCOP_SCU : : CAUSE_EXCCODE_TLBL :
m_ee . m_State . nPC = m_tlblExceptionHandler ;
break ;
case CCOP_SCU : : CAUSE_EXCCODE_TLBS :
m_ee . m_State . nPC = m_tlbsExceptionHandler ;
break ;
default :
//Can't handle other types of exceptions here
assert ( false ) ;
break ;
}
m_ee . m_State . nHasException = MIPS_EXCEPTION_NONE ;
}
2015-05-06 00:54:15 -04:00
void CPS2OS : : DisassembleSysCall ( uint8 func )
{
# ifdef _DEBUG
std : : string description ( GetSysCallDescription ( func ) ) ;
if ( description . length ( ) ! = 0 )
{
2015-08-08 23:36:00 -04:00
CLog : : GetInstance ( ) . Print ( LOG_NAME , " %d: %s \r \n " , m_currentThreadId . Get ( ) , description . c_str ( ) ) ;
2015-05-06 00:54:15 -04:00
}
# endif
}
std : : string CPS2OS : : GetSysCallDescription ( uint8 function )
{
char description [ 256 ] ;
strcpy ( description , " " ) ;
switch ( function )
{
case 0x02 :
2018-04-30 21:01:23 +01:00
sprintf ( description , " GsSetCrt(interlace = %i, mode = %i, field = %i); " ,
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 ] ) ;
2015-05-06 00:54:15 -04:00
break ;
case 0x04 :
sprintf ( description , SYSCALL_NAME_EXIT " (); " ) ;
break ;
case 0x06 :
2017-05-29 06:01:32 +01:00
sprintf ( description , SYSCALL_NAME_LOADEXECPS2 " (exec = 0x%08X, argc = %d, argv = 0x%08X); " ,
2018-04-30 21:01:23 +01: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 ] ) ;
2015-05-06 00:54:15 -04:00
break ;
2015-06-20 02:15:55 -04:00
case 0x07 :
2017-05-29 06:01:32 +01:00
sprintf ( description , SYSCALL_NAME_EXECPS2 " (pc = 0x%08X, gp = 0x%08X, argc = %d, argv = 0x%08X); " ,
2018-04-30 21:01:23 +01:00
m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ,
2018-08-27 07:22:53 -04: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 ] ) ;
2015-06-20 02:15:55 -04:00
break ;
2018-08-27 07:31:18 -04:00
case 0x0D :
sprintf ( description , SYSCALL_NAME_SETVTLBREFILLHANDLER " (cause = %d, handler = 0x%08x); " ,
m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ,
m_ee . m_State . nGPR [ SC_PARAM1 ] . nV [ 0 ] ) ;
break ;
case 0x0E :
sprintf ( description , SYSCALL_NAME_SETVCOMMONHANDLER " (cause = %d, handler = 0x%08x); " ,
m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ,
m_ee . m_State . nGPR [ SC_PARAM1 ] . nV [ 0 ] ) ;
break ;
2015-05-06 00:54:15 -04:00
case 0x10 :
2017-05-29 06:01:32 +01:00
sprintf ( description , SYSCALL_NAME_ADDINTCHANDLER " (cause = %i, address = 0x%08X, next = 0x%08X, arg = 0x%08X); " ,
2018-04-30 21:01:23 +01: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 ] ) ;
2015-05-06 00:54:15 -04:00
break ;
case 0x11 :
2018-04-30 21:01:23 +01:00
sprintf ( description , SYSCALL_NAME_REMOVEINTCHANDLER " (cause = %i, id = %i); " ,
m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ,
m_ee . m_State . nGPR [ SC_PARAM1 ] . nV [ 0 ] ) ;
2015-05-06 00:54:15 -04:00
break ;
case 0x12 :
2018-04-30 21:01:23 +01:00
sprintf ( description , SYSCALL_NAME_ADDDMACHANDLER " (channel = %i, address = 0x%08X, next = %i, arg = %i); " ,
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 ] ) ;
2015-05-06 00:54:15 -04:00
break ;
case 0x13 :
2018-04-30 21:01:23 +01:00
sprintf ( description , SYSCALL_NAME_REMOVEDMACHANDLER " (channel = %i, handler = %i); " ,
m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ,
m_ee . m_State . nGPR [ SC_PARAM1 ] . nV [ 0 ] ) ;
2015-05-06 00:54:15 -04:00
break ;
case 0x14 :
2018-04-30 21:01:23 +01:00
sprintf ( description , SYSCALL_NAME_ENABLEINTC " (cause = %i); " ,
m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ) ;
2015-05-06 00:54:15 -04:00
break ;
case 0x15 :
2018-04-30 21:01:23 +01:00
sprintf ( description , SYSCALL_NAME_DISABLEINTC " (cause = %i); " ,
m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ) ;
2015-05-06 00:54:15 -04:00
break ;
case 0x16 :
2018-04-30 21:01:23 +01:00
sprintf ( description , SYSCALL_NAME_ENABLEDMAC " (channel = %i); " ,
m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ) ;
2015-05-06 00:54:15 -04:00
break ;
case 0x17 :
2018-04-30 21:01:23 +01:00
sprintf ( description , SYSCALL_NAME_DISABLEDMAC " (channel = %i); " ,
m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ) ;
2015-05-06 00:54:15 -04:00
break ;
case 0x18 :
2017-05-29 06:01:32 +01:00
sprintf ( description , SYSCALL_NAME_SETALARM " (time = %d, proc = 0x%08X, arg = 0x%08X); " ,
2018-04-30 21:01:23 +01: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 ] ) ;
2015-05-06 00:54:15 -04:00
break ;
2016-09-25 14:53:30 -04:00
case 0x1A :
sprintf ( description , SYSCALL_NAME_IENABLEINTC " (cause = %d); " ,
2018-04-30 21:01:23 +01:00
m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ) ;
2016-09-25 14:53:30 -04:00
break ;
case 0x1B :
sprintf ( description , SYSCALL_NAME_IDISABLEINTC " (cause = %d); " ,
2018-04-30 21:01:23 +01:00
m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ) ;
2016-09-25 14:53:30 -04:00
break ;
2016-08-29 22:15:29 +09:00
case 0x1C :
sprintf ( description , SYSCALL_NAME_IENABLEDMAC " (channel = %d); " ,
2018-04-30 21:01:23 +01:00
m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ) ;
2016-08-29 22:15:29 +09:00
break ;
case 0x1D :
sprintf ( description , SYSCALL_NAME_IDISABLEDMAC " (channel = %d); " ,
2018-04-30 21:01:23 +01:00
m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ) ;
2016-08-29 22:15:29 +09:00
break ;
2019-08-16 07:49:13 -04:00
case 0x1E :
sprintf ( description , SYSCALL_NAME_ISETALARM " (time = %d, proc = 0x%08X, arg = 0x%08X); " ,
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 ;
2015-05-06 00:54:15 -04:00
case 0x1F :
sprintf ( description , SYSCALL_NAME_IRELEASEALARM " (id = %d); " ,
2018-04-30 21:01:23 +01:00
m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ) ;
2015-05-06 00:54:15 -04:00
break ;
case 0x20 :
2018-04-30 21:01:23 +01:00
sprintf ( description , SYSCALL_NAME_CREATETHREAD " (thread = 0x%08X); " ,
m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ) ;
2015-05-06 00:54:15 -04:00
break ;
case 0x21 :
2018-04-30 21:01:23 +01:00
sprintf ( description , SYSCALL_NAME_DELETETHREAD " (id = 0x%08X); " ,
m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ) ;
2015-05-06 00:54:15 -04:00
break ;
case 0x22 :
2018-04-30 21:01:23 +01:00
sprintf ( description , SYSCALL_NAME_STARTTHREAD " (id = 0x%08X, a0 = 0x%08X); " ,
m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ,
m_ee . m_State . nGPR [ SC_PARAM1 ] . nV [ 0 ] ) ;
2015-05-06 00:54:15 -04:00
break ;
case 0x23 :
2015-06-03 03:43:48 -04:00
sprintf ( description , SYSCALL_NAME_EXITTHREAD " (); " ) ;
2015-05-06 00:54:15 -04:00
break ;
2015-06-03 04:05:59 -04:00
case 0x24 :
sprintf ( description , SYSCALL_NAME_EXITDELETETHREAD " (); " ) ;
break ;
2015-05-06 00:54:15 -04:00
case 0x25 :
2018-04-30 21:01:23 +01:00
sprintf ( description , SYSCALL_NAME_TERMINATETHREAD " (id = 0x%08X); " ,
m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ) ;
2015-05-06 00:54:15 -04:00
break ;
case 0x29 :
2018-04-30 21:01:23 +01:00
sprintf ( description , SYSCALL_NAME_CHANGETHREADPRIORITY " (id = 0x%08X, priority = %i); " ,
m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ,
m_ee . m_State . nGPR [ SC_PARAM1 ] . nV [ 0 ] ) ;
2015-05-06 00:54:15 -04:00
break ;
case 0x2A :
2018-04-30 21:01:23 +01:00
sprintf ( description , SYSCALL_NAME_ICHANGETHREADPRIORITY " (id = 0x%08X, priority = %i); " ,
m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ,
m_ee . m_State . nGPR [ SC_PARAM1 ] . nV [ 0 ] ) ;
2015-05-06 00:54:15 -04:00
break ;
case 0x2B :
2018-04-30 21:01:23 +01:00
sprintf ( description , SYSCALL_NAME_ROTATETHREADREADYQUEUE " (prio = %i); " ,
m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ) ;
2015-05-06 00:54:15 -04:00
break ;
2018-06-19 19:12:34 -04:00
case 0x2D :
sprintf ( description , SYSCALL_NAME_RELEASEWAITTHREAD " (id = %d); " ,
2018-06-24 22:27:58 -04:00
m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ) ;
2018-06-19 19:12:34 -04:00
break ;
case 0x2E :
sprintf ( description , SYSCALL_NAME_IRELEASEWAITTHREAD " (id = %d); " ,
2018-06-24 22:27:58 -04:00
m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ) ;
2018-06-19 19:12:34 -04:00
break ;
2015-05-06 00:54:15 -04:00
case 0x2F :
sprintf ( description , SYSCALL_NAME_GETTHREADID " (); " ) ;
break ;
case 0x30 :
2017-05-29 06:01:32 +01:00
sprintf ( description , SYSCALL_NAME_REFERTHREADSTATUS " (threadId = %d, infoPtr = 0x%08X); " ,
2018-04-30 21:01:23 +01:00
m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ,
m_ee . m_State . nGPR [ SC_PARAM1 ] . nV [ 0 ] ) ;
2015-05-06 00:54:15 -04:00
break ;
case 0x31 :
2017-05-29 06:01:32 +01:00
sprintf ( description , SYSCALL_NAME_IREFERTHREADSTATUS " (threadId = %d, infoPtr = 0x%08X); " ,
2018-04-30 21:01:23 +01:00
m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ,
m_ee . m_State . nGPR [ SC_PARAM1 ] . nV [ 0 ] ) ;
2015-05-06 00:54:15 -04:00
break ;
case 0x32 :
sprintf ( description , SYSCALL_NAME_SLEEPTHREAD " (); " ) ;
break ;
case 0x33 :
2018-04-30 21:01:23 +01:00
sprintf ( description , SYSCALL_NAME_WAKEUPTHREAD " (id = %i); " ,
m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ) ;
2015-05-06 00:54:15 -04:00
break ;
case 0x34 :
2018-04-30 21:01:23 +01:00
sprintf ( description , SYSCALL_NAME_IWAKEUPTHREAD " (id = %i); " ,
m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ) ;
2015-05-06 00:54:15 -04:00
break ;
case 0x35 :
2018-04-30 21:01:23 +01:00
sprintf ( description , SYSCALL_NAME_CANCELWAKEUPTHREAD " (id = %d); " ,
m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ) ;
2015-05-06 00:54:15 -04:00
break ;
case 0x36 :
2018-04-30 21:01:23 +01:00
sprintf ( description , SYSCALL_NAME_ICANCELWAKEUPTHREAD " (id = %d); " ,
m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ) ;
2015-05-06 00:54:15 -04:00
break ;
case 0x37 :
2018-04-30 21:01:23 +01:00
sprintf ( description , SYSCALL_NAME_SUSPENDTHREAD " (id = %i); " ,
m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ) ;
2015-05-06 00:54:15 -04:00
break ;
2016-10-02 16:32:43 -04:00
case 0x38 :
sprintf ( description , SYSCALL_NAME_ISUSPENDTHREAD " (id = %d); " ,
2018-04-30 21:01:23 +01:00
m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ) ;
2016-10-02 16:32:43 -04:00
break ;
2015-05-06 00:54:15 -04:00
case 0x39 :
2018-04-30 21:01:23 +01:00
sprintf ( description , SYSCALL_NAME_RESUMETHREAD " (id = %i); " ,
m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ) ;
2015-05-06 00:54:15 -04:00
break ;
case 0x3C :
2018-04-30 21:01:23 +01:00
sprintf ( description , " SetupThread(gp = 0x%08X, stack = 0x%08X, stack_size = 0x%08X, args = 0x%08X, root_func = 0x%08X); " ,
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 ] ) ;
2015-05-06 00:54:15 -04:00
break ;
case 0x3D :
2018-04-30 21:01:23 +01:00
sprintf ( description , " SetupHeap(heap_start = 0x%08X, heap_size = 0x%08X); " ,
m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ,
m_ee . m_State . nGPR [ SC_PARAM1 ] . nV [ 0 ] ) ;
2015-05-06 00:54:15 -04:00
break ;
case 0x3E :
sprintf ( description , SYSCALL_NAME_ENDOFHEAP " (); " ) ;
break ;
case 0x40 :
2018-04-30 21:01:23 +01:00
sprintf ( description , SYSCALL_NAME_CREATESEMA " (sema = 0x%08X); " ,
m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ) ;
2015-05-06 00:54:15 -04:00
break ;
case 0x41 :
2018-04-30 21:01:23 +01:00
sprintf ( description , SYSCALL_NAME_DELETESEMA " (semaid = %i); " ,
m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ) ;
2015-05-06 00:54:15 -04:00
break ;
case 0x42 :
2018-04-30 21:01:23 +01:00
sprintf ( description , SYSCALL_NAME_SIGNALSEMA " (semaid = %i); " ,
m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ) ;
2015-05-06 00:54:15 -04:00
break ;
case 0x43 :
2018-04-30 21:01:23 +01:00
sprintf ( description , SYSCALL_NAME_ISIGNALSEMA " (semaid = %i); " ,
m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ) ;
2015-05-06 00:54:15 -04:00
break ;
case 0x44 :
2018-04-30 21:01:23 +01:00
sprintf ( description , SYSCALL_NAME_WAITSEMA " (semaid = %i); " ,
m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ) ;
2015-05-06 00:54:15 -04:00
break ;
case 0x45 :
2018-04-30 21:01:23 +01:00
sprintf ( description , SYSCALL_NAME_POLLSEMA " (semaid = %i); " ,
m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ) ;
2015-05-06 00:54:15 -04:00
break ;
case 0x46 :
2018-04-30 21:01:23 +01:00
sprintf ( description , SYSCALL_NAME_IPOLLSEMA " (semaid = %i); " ,
m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ) ;
2015-05-06 00:54:15 -04:00
break ;
case 0x47 :
2017-05-29 06:01:32 +01:00
sprintf ( description , SYSCALL_NAME_REFERSEMASTATUS " (semaid = %i, status = 0x%08X); " ,
2018-04-30 21:01:23 +01:00
m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ,
m_ee . m_State . nGPR [ SC_PARAM1 ] . nV [ 0 ] ) ;
2015-05-06 00:54:15 -04:00
break ;
case 0x48 :
2017-05-29 06:01:32 +01:00
sprintf ( description , SYSCALL_NAME_IREFERSEMASTATUS " (semaid = %i, status = 0x%08X); " ,
2018-04-30 21:01:23 +01:00
m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ,
m_ee . m_State . nGPR [ SC_PARAM1 ] . nV [ 0 ] ) ;
2015-05-06 00:54:15 -04:00
break ;
2018-05-15 12:44:16 -04:00
case 0x4B :
sprintf ( description , SYSCALL_NAME_GETOSDCONFIGPARAM " (configPtr = 0x%08X); " ,
m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ) ;
break ;
2015-05-06 00:54:15 -04:00
case 0x64 :
case 0x68 :
# ifdef _DEBUG
// sprintf(description, SYSCALL_NAME_FLUSHCACHE "();");
# endif
break ;
case 0x70 :
sprintf ( description , SYSCALL_NAME_GSGETIMR " (); " ) ;
break ;
case 0x71 :
2018-04-30 21:01:23 +01:00
sprintf ( description , SYSCALL_NAME_GSPUTIMR " (GS_IMR = 0x%08X); " ,
m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ) ;
2015-05-06 00:54:15 -04:00
break ;
case 0x73 :
2018-04-30 21:01:23 +01:00
sprintf ( description , SYSCALL_NAME_SETVSYNCFLAG " (ptr1 = 0x%08X, ptr2 = 0x%08X); " ,
m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ,
m_ee . m_State . nGPR [ SC_PARAM1 ] . nV [ 0 ] ) ;
2015-05-06 00:54:15 -04:00
break ;
case 0x74 :
2018-04-30 21:01:23 +01:00
sprintf ( description , SYSCALL_NAME_SETSYSCALL " (num = 0x%02X, address = 0x%08X); " ,
m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ,
m_ee . m_State . nGPR [ SC_PARAM1 ] . nV [ 0 ] ) ;
2015-05-06 00:54:15 -04:00
break ;
case 0x76 :
sprintf ( description , SYSCALL_NAME_SIFDMASTAT " (); " ) ;
break ;
case 0x77 :
2018-04-30 21:01:23 +01:00
sprintf ( description , SYSCALL_NAME_SIFSETDMA " (list = 0x%08X, count = %i); " ,
m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ,
m_ee . m_State . nGPR [ SC_PARAM1 ] . nV [ 0 ] ) ;
2015-05-06 00:54:15 -04:00
break ;
case 0x78 :
sprintf ( description , SYSCALL_NAME_SIFSETDCHAIN " (); " ) ;
break ;
case 0x79 :
2018-04-30 21:01:23 +01:00
sprintf ( description , " SifSetReg(register = 0x%08X, value = 0x%08X); " ,
m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ,
m_ee . m_State . nGPR [ SC_PARAM1 ] . nV [ 0 ] ) ;
2015-05-06 00:54:15 -04:00
break ;
case 0x7A :
2018-04-30 21:01:23 +01:00
sprintf ( description , " SifGetReg(register = 0x%08X); " ,
m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ) ;
2015-05-06 00:54:15 -04:00
break ;
case 0x7C :
2017-05-29 06:01:32 +01:00
sprintf ( description , SYSCALL_NAME_DECI2CALL " (func = 0x%08X, param = 0x%08X); " ,
2018-04-30 21:01:23 +01:00
m_ee . m_State . nGPR [ SC_PARAM0 ] . nV [ 0 ] ,
m_ee . m_State . nGPR [ SC_PARAM1 ] . nV [ 0 ] ) ;
2015-05-06 00:54:15 -04:00
break ;
case 0x7E :
sprintf ( description , SYSCALL_NAME_MACHINETYPE " (); " ) ;
break ;
case 0x7F :
sprintf ( description , " GetMemorySize(); " ) ;
break ;
}
return std : : string ( description ) ;
}
//////////////////////////////////////////////////
//System Call Handlers Table
//////////////////////////////////////////////////
2018-04-30 11:19:06 -04:00
// clang-format off
2015-05-06 00:54:15 -04:00
CPS2OS : : SystemCallHandler CPS2OS : : m_sysCall [ 0x80 ] =
{
//0x00
2018-08-27 07:31:18 -04:00
& CPS2OS : : sc_Unhandled , & CPS2OS : : sc_Unhandled , & CPS2OS : : sc_GsSetCrt , & CPS2OS : : sc_Unhandled , & CPS2OS : : sc_Exit , & CPS2OS : : sc_Unhandled , & CPS2OS : : sc_LoadExecPS2 , & CPS2OS : : sc_ExecPS2 ,
2015-05-06 00:54:15 -04:00
//0x08
2018-08-27 07:31:18 -04:00
& CPS2OS : : sc_Unhandled , & CPS2OS : : sc_Unhandled , & CPS2OS : : sc_Unhandled , & CPS2OS : : sc_Unhandled , & CPS2OS : : sc_Unhandled , & CPS2OS : : sc_SetVTLBRefillHandler , & CPS2OS : : sc_SetVCommonHandler , & CPS2OS : : sc_Unhandled ,
2015-05-06 00:54:15 -04:00
//0x10
2018-08-27 07:31:18 -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 ,
2015-05-06 00:54:15 -04:00
//0x18
2019-08-16 07:49:13 -04:00
& CPS2OS : : sc_SetAlarm , & CPS2OS : : sc_Unhandled , & CPS2OS : : sc_EnableIntc , & CPS2OS : : sc_DisableIntc , & CPS2OS : : sc_EnableDmac , & CPS2OS : : sc_DisableDmac , & CPS2OS : : sc_SetAlarm , & CPS2OS : : sc_ReleaseAlarm ,
2015-05-06 00:54:15 -04:00
//0x20
2018-08-27 07:31:18 -04:00
& CPS2OS : : sc_CreateThread , & CPS2OS : : sc_DeleteThread , & CPS2OS : : sc_StartThread , & CPS2OS : : sc_ExitThread , & CPS2OS : : sc_ExitDeleteThread , & CPS2OS : : sc_TerminateThread , & CPS2OS : : sc_Unhandled , & CPS2OS : : sc_Unhandled ,
2015-05-06 00:54:15 -04:00
//0x28
2018-08-27 07:31:18 -04:00
& CPS2OS : : sc_Unhandled , & CPS2OS : : sc_ChangeThreadPriority , & CPS2OS : : sc_ChangeThreadPriority , & CPS2OS : : sc_RotateThreadReadyQueue , & CPS2OS : : sc_Unhandled , & CPS2OS : : sc_ReleaseWaitThread , & CPS2OS : : sc_ReleaseWaitThread , & CPS2OS : : sc_GetThreadId ,
2015-05-06 00:54:15 -04:00
//0x30
2018-08-27 07:31:18 -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 ,
2015-05-06 00:54:15 -04:00
//0x38
2018-08-27 07:31:18 -04:00
& CPS2OS : : sc_SuspendThread , & CPS2OS : : sc_ResumeThread , & CPS2OS : : sc_Unhandled , & CPS2OS : : sc_Unhandled , & CPS2OS : : sc_SetupThread , & CPS2OS : : sc_SetupHeap , & CPS2OS : : sc_EndOfHeap , & CPS2OS : : sc_Unhandled ,
2015-05-06 00:54:15 -04:00
//0x40
2018-08-27 07:31:18 -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 ,
2015-05-06 00:54:15 -04:00
//0x48
2018-08-27 07:31:18 -04:00
& CPS2OS : : sc_ReferSemaStatus , & CPS2OS : : sc_Unhandled , & CPS2OS : : sc_Unhandled , & CPS2OS : : sc_GetOsdConfigParam , & CPS2OS : : sc_Unhandled , & CPS2OS : : sc_Unhandled , & CPS2OS : : sc_Unhandled , & CPS2OS : : sc_Unhandled ,
2015-05-06 00:54:15 -04:00
//0x50
2018-08-27 07:31:18 -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 ,
2015-05-06 00:54:15 -04:00
//0x58
2018-08-27 07:31:18 -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 ,
2015-05-06 00:54:15 -04:00
//0x60
2018-08-27 07:31:18 -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 ,
2015-05-06 00:54:15 -04:00
//0x68
2018-08-27 07:31:18 -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 ,
2015-05-06 00:54:15 -04:00
//0x70
2018-08-27 07:31:18 -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 ,
2015-05-06 00:54:15 -04:00
//0x78
2018-08-27 07:31:18 -04:00
& CPS2OS : : sc_SifSetDChain , & CPS2OS : : sc_SifSetReg , & CPS2OS : : sc_SifGetReg , & CPS2OS : : sc_Unhandled , & CPS2OS : : sc_Deci2Call , & CPS2OS : : sc_Unhandled , & CPS2OS : : sc_MachineType , & CPS2OS : : sc_GetMemorySize ,
2015-05-06 00:54:15 -04:00
} ;
2018-04-30 11:19:06 -04:00
// clang-format on
2015-05-06 00:54:15 -04:00
//////////////////////////////////////////////////////////////////////////////////////////////////////////
//Debug Stuff
# ifdef DEBUGGER_INCLUDED
BiosDebugModuleInfoArray CPS2OS : : GetModulesDebugInfo ( ) const
{
BiosDebugModuleInfoArray result ;
if ( m_elf )
{
auto executableRange = GetExecutableRange ( ) ;
BIOS_DEBUG_MODULE_INFO module ;
2018-04-30 21:01:23 +01:00
module . name = m_executableName ;
module . begin = executableRange . first ;
module . end = executableRange . second ;
2020-09-09 10:58:50 -04:00
module . param = m_elf . get ( ) ;
2015-05-06 00:54:15 -04:00
result . push_back ( module ) ;
}
return result ;
}
BiosDebugThreadInfoArray CPS2OS : : GetThreadsDebugInfo ( ) const
{
BiosDebugThreadInfoArray threadInfos ;
2015-08-09 00:03:42 -04:00
for ( auto threadIterator = std : : begin ( m_threads ) ; threadIterator ! = std : : end ( m_threads ) ; threadIterator + + )
2015-05-06 00:54:15 -04:00
{
2015-08-09 00:03:42 -04:00
auto thread = * threadIterator ;
if ( ! thread ) continue ;
2015-05-06 00:54:15 -04:00
auto threadContext = reinterpret_cast < THREADCONTEXT * > ( GetStructPtr ( thread - > contextPtr ) ) ;
BIOS_DEBUG_THREAD_INFO threadInfo ;
2018-04-30 21:01:23 +01:00
threadInfo . id = threadIterator ;
threadInfo . priority = thread - > currPriority ;
2015-08-09 00:03:42 -04:00
if ( m_currentThreadId = = threadIterator )
2015-05-06 00:54:15 -04:00
{
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
{
threadInfo . pc = thread - > epc ;
threadInfo . ra = threadContext - > gpr [ CMIPS : : RA ] . nV0 ;
threadInfo . sp = threadContext - > gpr [ CMIPS : : SP ] . nV0 ;
}
switch ( thread - > status )
{
case THREAD_RUNNING :
threadInfo . stateDescription = " Running " ;
break ;
case THREAD_SLEEPING :
threadInfo . stateDescription = " Sleeping " ;
break ;
case THREAD_WAITING :
2017-02-26 23:14:17 +00:00
threadInfo . stateDescription = string_format ( " Waiting (Semaphore: %d) " , thread - > semaWait ) ;
2015-05-06 00:54:15 -04:00
break ;
case THREAD_SUSPENDED :
threadInfo . stateDescription = " Suspended " ;
break ;
case THREAD_SUSPENDED_SLEEPING :
threadInfo . stateDescription = " Suspended+Sleeping " ;
break ;
case THREAD_SUSPENDED_WAITING :
2017-04-16 20:03:04 -04:00
threadInfo . stateDescription = string_format ( " Suspended+Waiting (Semaphore: %d) " , thread - > semaWait ) ;
2015-05-06 00:54:15 -04:00
break ;
case THREAD_ZOMBIE :
threadInfo . stateDescription = " Zombie " ;
break ;
default :
threadInfo . stateDescription = " Unknown " ;
break ;
}
threadInfos . push_back ( threadInfo ) ;
}
return threadInfos ;
}
# endif