1 #include <cstring>
2 #include "PsxBios.h"
3 #include "COP_SCU.h"
4 #include "Log.h"
5 #include "iop/Iop_Intc.h"
6 #include "MIPSAssembler.h"
7 #include "xml/Node.h"
8 #include "xml/Writer.h"
9
10 #define LOG_NAME ("psxbios")
11 #define SC_PARAM0 (CMIPS::A0)
12 #define SC_PARAM1 (CMIPS::A1)
13 #define SC_PARAM2 (CMIPS::A2)
14 #define SC_PARAM3 (CMIPS::A3)
15 #define SC_RETURN (CMIPS::V0)
16
17 using namespace Iop;
18
19 #define PCB_TABLE_ADDRESS (0x0108)
20 #define TCB_TABLE_ADDRESS (0x0110)
21 #define EXITFROMEXCEPTION_STATE_ADDR (0x0200)
22 #define SYSHEAP_POINTER_ADDR (0x0204)
23 #define INTR_HANDLER (0x1000)
24 #define EVENT_CHECKER (0x1200)
25 #define EVENTS_BEGIN (0x3000)
26 #define EVENTS_SIZE (sizeof(CPsxBios::EVENT) * CPsxBios::MAX_EVENT)
27 #define B0TABLE_BEGIN (EVENTS_BEGIN + EVENTS_SIZE)
28 #define B0TABLE_SIZE (0x5D * 4)
29 #define C0TABLE_BEGIN (B0TABLE_BEGIN + B0TABLE_SIZE)
30 #define C0TABLE_SIZE (0x1C * 4)
31 #define C0_EXCEPTIONHANDLER_BEGIN (C0TABLE_BEGIN + C0TABLE_SIZE)
32 #define C0_EXCEPTIONHANDLER_SIZE (0x1000)
33 #define HEAP_START (C0_EXCEPTIONHANDLER_BEGIN + C0_EXCEPTIONHANDLER_SIZE)
34 #define HEAP_SIZE (0x2000)
35 #define BIOS_MEMORY_END (HEAP_START + HEAP_SIZE)
36
CPsxBios(CMIPS & cpu,uint8 * ram,uint32 ramSize)37 CPsxBios::CPsxBios(CMIPS& cpu, uint8* ram, uint32 ramSize)
38 : m_cpu(cpu)
39 , m_ram(ram)
40 , m_ramSize(ramSize)
41 , m_exitFromExceptionStateAddr(reinterpret_cast<uint32*>(m_ram + EXITFROMEXCEPTION_STATE_ADDR))
42 , m_sysHeapPointerAddr(reinterpret_cast<uint32*>(m_ram + SYSHEAP_POINTER_ADDR))
43 , m_events(reinterpret_cast<EVENT*>(&m_ram[EVENTS_BEGIN]), 1, MAX_EVENT)
44 {
45 static_assert(BIOS_MEMORY_END <= 0x10000, "BIOS memory size must not exceed 64k");
46 Reset();
47 }
48
Reset()49 void CPsxBios::Reset()
50 {
51 uint32 syscallAddress[3] = {0xA0, 0xB0, 0xC0};
52
53 for(unsigned int i = 0; i < 3; i++)
54 {
55 CMIPSAssembler assembler(reinterpret_cast<uint32*>(m_ram + syscallAddress[i]));
56 assembler.SYSCALL();
57 assembler.JR(CMIPS::RA);
58 assembler.NOP();
59 }
60
61 //Assembly a dummy JR RA at 0 because Vagrant Story jumps at 0
62 {
63 CMIPSAssembler assembler(reinterpret_cast<uint32*>(m_ram + 0x0));
64 assembler.LUI(CMIPS::K0, 0x0000); //This is required by Xenogears' SFX PSFs
65 assembler.JR(CMIPS::RA);
66 assembler.NOP();
67 }
68
69 m_cpu.m_State.nCOP0[CCOP_SCU::STATUS] |= CMIPS::STATUS_IE;
70
71 AssembleEventChecker();
72 AssembleInterruptHandler();
73
74 //Setup B0 table
75 {
76 uint32* table = reinterpret_cast<uint32*>(&m_ram[B0TABLE_BEGIN]);
77 table[0x5B] = C0_EXCEPTIONHANDLER_BEGIN;
78 }
79
80 //Setup C0 table
81 {
82 uint32* table = reinterpret_cast<uint32*>(&m_ram[C0TABLE_BEGIN]);
83 table[0x06] = C0_EXCEPTIONHANDLER_BEGIN;
84 }
85
86 //Assemble dummy exception handler
87 {
88 //0x70 = LUI
89 //0x74 = ADDIU
90 //Chrono Cross will overwrite the stuff present at the address that would be computed
91 //by these two instructions and use something else
92 CMIPSAssembler assembler(reinterpret_cast<uint32*>(m_ram + C0_EXCEPTIONHANDLER_BEGIN + 0x70));
93 assembler.LI(CMIPS::T0, C0_EXCEPTIONHANDLER_BEGIN);
94 }
95
96 m_exitFromExceptionStateAddr = 0;
97 m_sysHeapPointerAddr = HEAP_START;
98
99 memset(m_events.GetBase(), 0, EVENTS_SIZE);
100
101 //Allocate process control block
102 {
103 auto cbTable = reinterpret_cast<CB_TABLE*>(m_ram + PCB_TABLE_ADDRESS);
104 cbTable->address = AllocateSysMemory(sizeof(PROCESS));
105 cbTable->size = sizeof(PROCESS);
106 }
107
108 //Allocate thread control block
109 {
110 static const uint32 maxTcb = 4;
111 auto cbTable = reinterpret_cast<CB_TABLE*>(m_ram + TCB_TABLE_ADDRESS);
112 cbTable->address = AllocateSysMemory(sizeof(THREAD) * maxTcb);
113 cbTable->size = sizeof(THREAD) * maxTcb;
114 }
115
116 //Setup main thread
117 {
118 auto process = GetProcess();
119 auto threadCbAddr =
120 [&]() {
121 auto cbTable = reinterpret_cast<CB_TABLE*>(m_ram + TCB_TABLE_ADDRESS);
122 auto threadCb = reinterpret_cast<THREAD*>(m_ram + cbTable->address);
123 threadCb->status = THREAD_STATUS_ALLOCATED;
124 return cbTable->address;
125 }();
126 process->currentThreadControlBlockAddr = threadCbAddr;
127 }
128 }
129
LoadExe(const uint8 * exe)130 void CPsxBios::LoadExe(const uint8* exe)
131 {
132 auto exeHeader = reinterpret_cast<const EXEHEADER*>(exe);
133 if(strncmp(reinterpret_cast<const char*>(exeHeader->id), "PS-X EXE", 8))
134 {
135 throw std::runtime_error("Invalid PSX executable.");
136 }
137
138 m_cpu.m_State.nPC = exeHeader->pc0 & 0x1FFFFFFF;
139 m_cpu.m_State.nGPR[CMIPS::GP].nD0 = exeHeader->gp0;
140 m_cpu.m_State.nGPR[CMIPS::SP].nD0 = exeHeader->stackAddr;
141
142 exe += 0x800;
143 if(exeHeader->textAddr != 0)
144 {
145 uint32 realAddr = exeHeader->textAddr & 0x1FFFFFFF;
146 assert(realAddr + exeHeader->textSize <= m_ramSize);
147 memcpy(m_ram + realAddr, exe, exeHeader->textSize);
148 exe += exeHeader->textSize;
149
150 #ifdef DEBUGGER_INCLUDED
151 m_cpu.m_analysis->Analyse(realAddr, realAddr + exeHeader->textSize, m_cpu.m_State.nPC);
152 #endif
153 }
154 }
155
SaveState(Framework::CZipArchiveWriter & archive)156 void CPsxBios::SaveState(Framework::CZipArchiveWriter& archive)
157 {
158 }
159
LoadState(Framework::CZipArchiveReader & archive)160 void CPsxBios::LoadState(Framework::CZipArchiveReader& archive)
161 {
162 }
163
NotifyVBlankStart()164 void CPsxBios::NotifyVBlankStart()
165 {
166 }
167
NotifyVBlankEnd()168 void CPsxBios::NotifyVBlankEnd()
169 {
170 }
171
IsIdle()172 bool CPsxBios::IsIdle()
173 {
174 return false;
175 }
176
177 #ifdef DEBUGGER_INCLUDED
178
LoadDebugTags(Framework::Xml::CNode * root)179 void CPsxBios::LoadDebugTags(Framework::Xml::CNode* root)
180 {
181 }
182
SaveDebugTags(Framework::Xml::CNode * root)183 void CPsxBios::SaveDebugTags(Framework::Xml::CNode* root)
184 {
185 }
186
GetModulesDebugInfo() const187 BiosDebugModuleInfoArray CPsxBios::GetModulesDebugInfo() const
188 {
189 return BiosDebugModuleInfoArray();
190 }
191
GetThreadsDebugInfo() const192 BiosDebugThreadInfoArray CPsxBios::GetThreadsDebugInfo() const
193 {
194 return BiosDebugThreadInfoArray();
195 }
196
197 #endif
198
CountTicks(uint32 ticks)199 void CPsxBios::CountTicks(uint32 ticks)
200 {
201 }
202
AssembleEventChecker()203 void CPsxBios::AssembleEventChecker()
204 {
205 CMIPSAssembler assembler(reinterpret_cast<uint32*>(m_ram + EVENT_CHECKER));
206 CMIPSAssembler::LABEL checkEventLabel = assembler.CreateLabel();
207 CMIPSAssembler::LABEL doneEventLabel = assembler.CreateLabel();
208
209 unsigned int currentEvent = CMIPS::S0;
210 unsigned int eventMax = CMIPS::S1;
211 unsigned int eventToCheck = CMIPS::S2;
212 unsigned int needClearInt = CMIPS::S3;
213 int stackAlloc = 5 * 4;
214
215 //prolog
216 assembler.ADDIU(CMIPS::SP, CMIPS::SP, -stackAlloc);
217 assembler.SW(CMIPS::RA, 0x00, CMIPS::SP);
218 assembler.SW(CMIPS::S0, 0x04, CMIPS::SP);
219 assembler.SW(CMIPS::S1, 0x08, CMIPS::SP);
220 assembler.SW(CMIPS::S2, 0x0C, CMIPS::SP);
221 assembler.SW(CMIPS::S3, 0x10, CMIPS::SP);
222
223 assembler.LI(currentEvent, EVENTS_BEGIN);
224 assembler.LI(eventMax, EVENTS_BEGIN + EVENTS_SIZE);
225 assembler.MOV(eventToCheck, CMIPS::A0);
226 assembler.ADDU(needClearInt, CMIPS::R0, CMIPS::R0);
227
228 //checkEvent
229 {
230 assembler.MarkLabel(checkEventLabel);
231
232 //check if valid
233 assembler.LW(CMIPS::T0, offsetof(EVENT, isValid), currentEvent);
234 assembler.BEQ(CMIPS::T0, CMIPS::R0, doneEventLabel);
235 assembler.NOP();
236
237 //check if good event class
238 assembler.LW(CMIPS::T0, offsetof(EVENT, classId), currentEvent);
239 assembler.BNE(CMIPS::T0, eventToCheck, doneEventLabel);
240 assembler.NOP();
241
242 //Tell that we need to clear interrupt later (experimental)
243 assembler.ADDIU(needClearInt, CMIPS::R0, 1);
244
245 //check if enabled
246 assembler.LW(CMIPS::T0, offsetof(EVENT, enabled), currentEvent);
247 assembler.BEQ(CMIPS::T0, CMIPS::R0, doneEventLabel);
248 assembler.NOP();
249
250 //Start handler if present
251 assembler.LW(CMIPS::T0, offsetof(EVENT, func), currentEvent);
252 assembler.BEQ(CMIPS::T0, CMIPS::R0, doneEventLabel);
253 assembler.NOP();
254
255 assembler.JALR(CMIPS::T0);
256 assembler.NOP();
257 }
258
259 //doneEvent
260 assembler.MarkLabel(doneEventLabel);
261 assembler.ADDIU(currentEvent, currentEvent, sizeof(EVENT));
262 assembler.BNE(currentEvent, eventMax, checkEventLabel);
263 assembler.NOP();
264
265 //Result
266 assembler.ADDU(CMIPS::V0, needClearInt, CMIPS::R0);
267
268 //epilog
269 assembler.LW(CMIPS::RA, 0x00, CMIPS::SP);
270 assembler.LW(CMIPS::S0, 0x04, CMIPS::SP);
271 assembler.LW(CMIPS::S1, 0x08, CMIPS::SP);
272 assembler.LW(CMIPS::S2, 0x0C, CMIPS::SP);
273 assembler.LW(CMIPS::S3, 0x10, CMIPS::SP);
274 assembler.ADDIU(CMIPS::SP, CMIPS::SP, stackAlloc);
275
276 assembler.JR(CMIPS::RA);
277 assembler.NOP();
278 }
279
AssembleInterruptHandler()280 void CPsxBios::AssembleInterruptHandler()
281 {
282 //Assemble interrupt handler
283 CMIPSAssembler assembler(reinterpret_cast<uint32*>(m_ram + INTR_HANDLER));
284 CMIPSAssembler::LABEL skipRootCounter2EventLabel = assembler.CreateLabel();
285 CMIPSAssembler::LABEL returnExceptionLabel = assembler.CreateLabel();
286 CMIPSAssembler::LABEL clearIntcCause = assembler.CreateLabel();
287
288 //Get cause
289 unsigned int cause = CMIPS::S3;
290 assembler.LI(CMIPS::T0, CIntc::STATUS0);
291 assembler.LW(CMIPS::T0, 0, CMIPS::T0);
292 assembler.LI(CMIPS::T1, CIntc::MASK0);
293 assembler.LW(CMIPS::T1, 0, CMIPS::T1);
294 assembler.AND(cause, CMIPS::T0, CMIPS::T1);
295
296 //Check if cause is root counter 2
297 assembler.ANDI(CMIPS::T0, cause, 0x40);
298 assembler.BEQ(CMIPS::T0, CMIPS::R0, skipRootCounter2EventLabel);
299 assembler.NOP();
300
301 assembler.LI(CMIPS::A0, EVENT_ID_RCNT2);
302 assembler.JAL(EVENT_CHECKER);
303 assembler.NOP();
304
305 assembler.BEQ(CMIPS::V0, CMIPS::R0, skipRootCounter2EventLabel);
306 assembler.NOP();
307
308 //Clear root counter 2 cause
309 assembler.LI(CMIPS::T0, CIntc::STATUS0);
310 assembler.LI(CMIPS::T1, ~0x40);
311 assembler.SW(CMIPS::T1, 0, CMIPS::T0);
312
313 assembler.MarkLabel(skipRootCounter2EventLabel);
314
315 //checkIntHook
316 assembler.LI(CMIPS::T0, EXITFROMEXCEPTION_STATE_ADDR);
317 assembler.LW(CMIPS::T0, 0, CMIPS::T0);
318 assembler.BEQ(CMIPS::T0, CMIPS::R0, clearIntcCause);
319 assembler.NOP();
320
321 //callIntHook
322 assembler.ADDIU(CMIPS::A0, CMIPS::T0, CMIPS::R0);
323 assembler.ADDIU(CMIPS::A1, CMIPS::R0, CMIPS::R0);
324 assembler.ADDIU(CMIPS::T0, CMIPS::R0, 0xA0);
325 assembler.ADDIU(CMIPS::T1, CMIPS::R0, 0x14);
326 assembler.JR(CMIPS::T0);
327 assembler.NOP();
328
329 assembler.BEQ(CMIPS::R0, CMIPS::R0, returnExceptionLabel);
330 assembler.NOP();
331
332 //Clear any interrupt that might have triggered this exception handler (to prevent infinite loop)
333 assembler.MarkLabel(clearIntcCause);
334 assembler.LI(CMIPS::T0, CIntc::STATUS0);
335 assembler.NOR(CMIPS::T1, CMIPS::R0, cause);
336 assembler.SW(CMIPS::T1, 0, CMIPS::T0);
337
338 //ReturnFromException
339 assembler.MarkLabel(returnExceptionLabel);
340 assembler.ADDIU(CMIPS::T0, CMIPS::R0, 0xB0);
341 assembler.ADDIU(CMIPS::T1, CMIPS::R0, 0x17);
342 assembler.JR(CMIPS::T0);
343 assembler.NOP();
344 }
345
LongJump(uint32 bufferAddress,uint32 value)346 void CPsxBios::LongJump(uint32 bufferAddress, uint32 value)
347 {
348 bufferAddress = m_cpu.m_pAddrTranslator(&m_cpu, bufferAddress);
349 m_cpu.m_State.nGPR[CMIPS::RA].nD0 = static_cast<int32>(m_cpu.m_pMemoryMap->GetWord(bufferAddress + 0x00));
350 m_cpu.m_State.nGPR[CMIPS::SP].nD0 = static_cast<int32>(m_cpu.m_pMemoryMap->GetWord(bufferAddress + 0x04));
351 m_cpu.m_State.nGPR[CMIPS::FP].nD0 = static_cast<int32>(m_cpu.m_pMemoryMap->GetWord(bufferAddress + 0x08));
352 m_cpu.m_State.nGPR[CMIPS::S0].nD0 = static_cast<int32>(m_cpu.m_pMemoryMap->GetWord(bufferAddress + 0x0C));
353 m_cpu.m_State.nGPR[CMIPS::S1].nD0 = static_cast<int32>(m_cpu.m_pMemoryMap->GetWord(bufferAddress + 0x10));
354 m_cpu.m_State.nGPR[CMIPS::S2].nD0 = static_cast<int32>(m_cpu.m_pMemoryMap->GetWord(bufferAddress + 0x14));
355 m_cpu.m_State.nGPR[CMIPS::S3].nD0 = static_cast<int32>(m_cpu.m_pMemoryMap->GetWord(bufferAddress + 0x18));
356 m_cpu.m_State.nGPR[CMIPS::S4].nD0 = static_cast<int32>(m_cpu.m_pMemoryMap->GetWord(bufferAddress + 0x1C));
357 m_cpu.m_State.nGPR[CMIPS::S5].nD0 = static_cast<int32>(m_cpu.m_pMemoryMap->GetWord(bufferAddress + 0x20));
358 m_cpu.m_State.nGPR[CMIPS::S6].nD0 = static_cast<int32>(m_cpu.m_pMemoryMap->GetWord(bufferAddress + 0x24));
359 m_cpu.m_State.nGPR[CMIPS::S7].nD0 = static_cast<int32>(m_cpu.m_pMemoryMap->GetWord(bufferAddress + 0x28));
360 m_cpu.m_State.nGPR[CMIPS::GP].nD0 = static_cast<int32>(m_cpu.m_pMemoryMap->GetWord(bufferAddress + 0x2C));
361 m_cpu.m_State.nGPR[CMIPS::V0].nD0 = value == 0 ? 1 : value;
362 }
363
GetProcess()364 CPsxBios::PROCESS* CPsxBios::GetProcess()
365 {
366 auto processCbTable = reinterpret_cast<CB_TABLE*>(m_ram + PCB_TABLE_ADDRESS);
367 assert(processCbTable->address != 0);
368 assert(processCbTable->size != 0);
369
370 return reinterpret_cast<PROCESS*>(m_ram + processCbTable->address);
371 }
372
SaveCpuState()373 void CPsxBios::SaveCpuState()
374 {
375 auto process = GetProcess();
376 assert(process->currentThreadControlBlockAddr != 0);
377
378 auto thread = reinterpret_cast<THREAD*>(m_ram + process->currentThreadControlBlockAddr);
379 assert(thread->status == THREAD_STATUS_ALLOCATED);
380 thread->pc = m_cpu.m_State.nPC;
381 for(uint32 i = 0; i < 32; i++)
382 {
383 if(i == CMIPS::R0) continue;
384 if(i == CMIPS::K0) continue;
385 if(i == CMIPS::K1) continue;
386 thread->gpr[i] = m_cpu.m_State.nGPR[i].nV0;
387 }
388 thread->sr = m_cpu.m_State.nCOP0[CCOP_SCU::STATUS];
389 thread->sr &= ~(CMIPS::STATUS_EXL | CMIPS::STATUS_ERL);
390 }
391
LoadCpuState()392 void CPsxBios::LoadCpuState()
393 {
394 auto process = GetProcess();
395 assert(process->currentThreadControlBlockAddr != 0);
396
397 auto thread = reinterpret_cast<THREAD*>(m_ram + process->currentThreadControlBlockAddr);
398 assert(thread->status == THREAD_STATUS_ALLOCATED);
399 m_cpu.m_State.nPC = thread->pc;
400 for(uint32 i = 0; i < 32; i++)
401 {
402 if(i == CMIPS::R0) continue;
403 if(i == CMIPS::K0) continue;
404 if(i == CMIPS::K1) continue;
405 m_cpu.m_State.nGPR[i].nV0 = thread->gpr[i];
406 }
407 m_cpu.m_State.nCOP0[CCOP_SCU::STATUS] = thread->sr;
408 }
409
AllocateSysMemory(uint32 size)410 uint32 CPsxBios::AllocateSysMemory(uint32 size)
411 {
412 assert((m_sysHeapPointerAddr + size) <= (HEAP_START + HEAP_SIZE));
413 uint32 result = m_sysHeapPointerAddr;
414 m_sysHeapPointerAddr += size;
415 return result;
416 }
417
HandleInterrupt()418 void CPsxBios::HandleInterrupt()
419 {
420 if(m_cpu.GenerateInterrupt(m_cpu.m_State.nPC))
421 {
422 SaveCpuState();
423 uint32 status = m_cpu.m_pMemoryMap->GetWord(CIntc::STATUS0);
424 uint32 mask = m_cpu.m_pMemoryMap->GetWord(CIntc::MASK0);
425 uint32 cause = status & mask;
426 for(unsigned int i = 1; i <= MAX_EVENT; i++)
427 {
428 EVENT* eventPtr = m_events[i];
429 if(eventPtr == NULL) continue;
430 if((cause & (1 << CIntc::LINE_DMAC)) && eventPtr->classId == 0xF0000009)
431 {
432 eventPtr->fired = 1;
433 }
434 }
435 m_cpu.m_State.nPC = INTR_HANDLER;
436 }
437 }
438
HandleException()439 void CPsxBios::HandleException()
440 {
441 assert(m_cpu.m_State.nHasException);
442 uint32 searchAddress = m_cpu.m_State.nCOP0[CCOP_SCU::EPC];
443 uint32 callInstruction = m_cpu.m_pMemoryMap->GetWord(searchAddress);
444 if(callInstruction != 0x0000000C)
445 {
446 throw std::runtime_error("Not a SYSCALL.");
447 }
448 #ifdef _DEBUG
449 DisassembleSyscall(searchAddress);
450 #endif
451 if(searchAddress == 0xA0)
452 {
453 ProcessSubFunction(m_handlerA0, MAX_HANDLER_A0);
454 }
455 else if(searchAddress == 0xB0)
456 {
457 ProcessSubFunction(m_handlerB0, MAX_HANDLER_B0);
458 }
459 else if(searchAddress == 0xC0)
460 {
461 ProcessSubFunction(m_handlerC0, MAX_HANDLER_C0);
462 }
463 else
464 {
465 uint32 functionId = m_cpu.m_State.nGPR[CMIPS::A0].nV0;
466 switch(functionId)
467 {
468 case 0x01:
469 sc_EnterCriticalSection();
470 break;
471 case 0x02:
472 sc_ExitCriticalSection();
473 break;
474 default:
475 sc_Illegal();
476 break;
477 }
478 }
479 m_cpu.m_State.nHasException = 0;
480 }
481
ProcessSubFunction(SyscallHandler * handlerTable,unsigned int handlerTableLength)482 void CPsxBios::ProcessSubFunction(SyscallHandler* handlerTable, unsigned int handlerTableLength)
483 {
484 uint32 functionId = m_cpu.m_State.nGPR[CMIPS::T1].nV0;
485 if(functionId >= handlerTableLength)
486 {
487 sc_Illegal();
488 }
489 functionId %= handlerTableLength;
490 ((this)->*(handlerTable[functionId]))();
491 }
492
DisassembleSyscall(uint32 searchAddress)493 void CPsxBios::DisassembleSyscall(uint32 searchAddress)
494 {
495 if(searchAddress == 0x00A0)
496 {
497 uint32 functionId = m_cpu.m_State.nGPR[CMIPS::T1].nV0;
498 switch(functionId)
499 {
500 case 0x13:
501 CLog::GetInstance().Print(LOG_NAME, "setjmp(buffer = 0x%0.8X);\r\n",
502 m_cpu.m_State.nGPR[SC_PARAM0].nV0);
503 break;
504 case 0x14:
505 CLog::GetInstance().Print(LOG_NAME, "longjmp(buffer = 0x%0.8X, value = %i);\r\n",
506 m_cpu.m_State.nGPR[SC_PARAM0].nV0,
507 m_cpu.m_State.nGPR[SC_PARAM1].nV0);
508 break;
509 case 0x19:
510 CLog::GetInstance().Print(LOG_NAME, "strcpy(dst = 0x%0.8X, src = 0x%0.8X);\r\n",
511 m_cpu.m_State.nGPR[SC_PARAM0].nV0,
512 m_cpu.m_State.nGPR[SC_PARAM1].nV0);
513 break;
514 case 0x28:
515 CLog::GetInstance().Print(LOG_NAME, "bzero(address = 0x%0.8X, length = 0x%x);\r\n",
516 m_cpu.m_State.nGPR[SC_PARAM0].nV0,
517 m_cpu.m_State.nGPR[SC_PARAM1].nV0);
518 break;
519 case 0x2A:
520 CLog::GetInstance().Print(LOG_NAME, "memcpy(dst = 0x%0.8X, src = 0x%0.8X, length = 0x%x);\r\n",
521 m_cpu.m_State.nGPR[SC_PARAM0].nV0,
522 m_cpu.m_State.nGPR[SC_PARAM1].nV0,
523 m_cpu.m_State.nGPR[SC_PARAM2].nV0);
524 break;
525 case 0x2B:
526 CLog::GetInstance().Print(LOG_NAME, "memset(address = 0x%0.8X, value = 0x%x, length = 0x%x);\r\n",
527 m_cpu.m_State.nGPR[SC_PARAM0].nV0,
528 m_cpu.m_State.nGPR[SC_PARAM1].nV0,
529 m_cpu.m_State.nGPR[SC_PARAM2].nV0);
530 break;
531 case 0x2F:
532 CLog::GetInstance().Print(LOG_NAME, "rand();\r\n");
533 break;
534 case 0x30:
535 CLog::GetInstance().Print(LOG_NAME, "srand(seed = %d);\r\n",
536 m_cpu.m_State.nGPR[SC_PARAM0].nV0);
537 break;
538 case 0x39:
539 CLog::GetInstance().Print(LOG_NAME, "InitHeap(block = 0x%0.8X, n = 0x%0.8X);\r\n",
540 m_cpu.m_State.nGPR[SC_PARAM0].nV0,
541 m_cpu.m_State.nGPR[SC_PARAM1].nV0);
542 break;
543 case 0x3F:
544 CLog::GetInstance().Print(LOG_NAME, "printf(fmt = 0x%0.8X);\r\n",
545 m_cpu.m_State.nGPR[SC_PARAM0].nV0);
546 break;
547 case 0x44:
548 CLog::GetInstance().Print(LOG_NAME, "FlushCache();\r\n");
549 break;
550 case 0x70:
551 CLog::GetInstance().Print(LOG_NAME, "_bu_init();\r\n");
552 break;
553 case 0x72:
554 CLog::GetInstance().Print(LOG_NAME, "_96_remove();\r\n");
555 break;
556 case 0x9F:
557 CLog::GetInstance().Print(LOG_NAME, "SetMem(size = %i);\r\n",
558 m_cpu.m_State.nGPR[SC_PARAM0].nV0);
559 break;
560 default:
561 CLog::GetInstance().Print(LOG_NAME, "Unknown system call encountered (0xA0, 0x%X).\r\n", functionId);
562 break;
563 }
564 }
565 else if(searchAddress == 0x00B0)
566 {
567 uint32 functionId = m_cpu.m_State.nGPR[CMIPS::T1].nV0;
568 switch(functionId)
569 {
570 case 0x00:
571 CLog::GetInstance().Print(LOG_NAME, "SysMalloc(size = 0x%X);\r\n",
572 m_cpu.m_State.nGPR[SC_PARAM0].nV0);
573 break;
574 case 0x07:
575 CLog::GetInstance().Print(LOG_NAME, "DeliverEvent(class = 0x%X, event = 0x%X);\r\n",
576 m_cpu.m_State.nGPR[SC_PARAM0].nV0,
577 m_cpu.m_State.nGPR[SC_PARAM1].nV0);
578 break;
579 case 0x08:
580 CLog::GetInstance().Print(LOG_NAME, "OpenEvent(class = 0x%X, spec = 0x%X, mode = 0x%X, func = 0x%X);\r\n",
581 m_cpu.m_State.nGPR[SC_PARAM0].nV0,
582 m_cpu.m_State.nGPR[SC_PARAM1].nV0,
583 m_cpu.m_State.nGPR[SC_PARAM2].nV0,
584 m_cpu.m_State.nGPR[SC_PARAM3].nV0);
585 break;
586 case 0x09:
587 CLog::GetInstance().Print(LOG_NAME, "CloseEvent(event = 0x%X);\r\n",
588 m_cpu.m_State.nGPR[SC_PARAM0].nV0);
589 break;
590 case 0x0A:
591 CLog::GetInstance().Print(LOG_NAME, "WaitEvent(event = 0x%X);\r\n",
592 m_cpu.m_State.nGPR[SC_PARAM0].nV0);
593 break;
594 case 0x0B:
595 CLog::GetInstance().Print(LOG_NAME, "TestEvent(event = 0x%X);\r\n",
596 m_cpu.m_State.nGPR[SC_PARAM0].nV0);
597 break;
598 case 0x0C:
599 CLog::GetInstance().Print(LOG_NAME, "EnableEvent(event = 0x%X);\r\n",
600 m_cpu.m_State.nGPR[SC_PARAM0].nV0);
601 break;
602 case 0x0D:
603 CLog::GetInstance().Print(LOG_NAME, "DisableEvent(event = 0x%X);\r\n",
604 m_cpu.m_State.nGPR[SC_PARAM0].nV0);
605 break;
606 case 0x0E:
607 CLog::GetInstance().Print(LOG_NAME, "OpenThread(pc = 0x%08X, sp = 0x%08X, gp = 0x%08X);\r\n",
608 m_cpu.m_State.nGPR[SC_PARAM0].nV0,
609 m_cpu.m_State.nGPR[SC_PARAM1].nV0,
610 m_cpu.m_State.nGPR[SC_PARAM2].nV0);
611 break;
612 case 0x10:
613 CLog::GetInstance().Print(LOG_NAME, "ChangeThread(threadId = 0x%X);\r\n",
614 m_cpu.m_State.nGPR[SC_PARAM0].nV0);
615 break;
616 case 0x14:
617 CLog::GetInstance().Print(LOG_NAME, "StopPAD();\r\n");
618 break;
619 case 0x16:
620 CLog::GetInstance().Print(LOG_NAME, "PAD_dr();\r\n");
621 break;
622 case 0x17:
623 CLog::GetInstance().Print(LOG_NAME, "ReturnFromException();\r\n");
624 break;
625 case 0x18:
626 CLog::GetInstance().Print(LOG_NAME, "SetDefaultExitFromException();\r\n");
627 break;
628 case 0x19:
629 CLog::GetInstance().Print(LOG_NAME, "SetCustomExitFromException(stateAddress = 0x%0.8X);\r\n",
630 m_cpu.m_State.nGPR[SC_PARAM0].nV0);
631 break;
632 case 0x3F:
633 CLog::GetInstance().Print(LOG_NAME, "puts(s = 0x%0.8X);\r\n",
634 m_cpu.m_State.nGPR[SC_PARAM0].nV0);
635 break;
636 case 0x4A:
637 CLog::GetInstance().Print(LOG_NAME, "InitCARD();\r\n");
638 break;
639 case 0x4B:
640 CLog::GetInstance().Print(LOG_NAME, "StartCARD();\r\n");
641 break;
642 case 0x56:
643 CLog::GetInstance().Print(LOG_NAME, "GetC0Table();\r\n");
644 break;
645 case 0x57:
646 CLog::GetInstance().Print(LOG_NAME, "GetB0Table();\r\n");
647 break;
648 case 0x5B:
649 CLog::GetInstance().Print(LOG_NAME, "ChangeClearPad(param = %i);\r\n",
650 m_cpu.m_State.nGPR[SC_PARAM0].nV0);
651 break;
652 default:
653 CLog::GetInstance().Print(LOG_NAME, "Unknown system call encountered (0xB0, 0x%X).\r\n", functionId);
654 break;
655 }
656 }
657 else if(searchAddress == 0x00C0)
658 {
659 uint32 functionId = m_cpu.m_State.nGPR[CMIPS::T1].nV0;
660 switch(functionId)
661 {
662 case 0x00:
663 CLog::GetInstance().Print(LOG_NAME, "EnqueueTimerAndVblankIrqs(priority = %d);\r\n",
664 m_cpu.m_State.nGPR[SC_PARAM0].nV0);
665 break;
666 case 0x01:
667 CLog::GetInstance().Print(LOG_NAME, "EnqueueSyscallHandler(priority = %d);\r\n",
668 m_cpu.m_State.nGPR[SC_PARAM0].nV0);
669 break;
670 case 0x03:
671 CLog::GetInstance().Print(LOG_NAME, "SysDeqIntRP(index = %i, queue = 0x%X);\r\n",
672 m_cpu.m_State.nGPR[SC_PARAM0].nV0,
673 m_cpu.m_State.nGPR[SC_PARAM1].nV0);
674 break;
675 case 0x08:
676 CLog::GetInstance().Print(LOG_NAME, "SysInitMemory(address = 0x%08X, size = 0x%X);\r\n",
677 m_cpu.m_State.nGPR[SC_PARAM0].nV0,
678 m_cpu.m_State.nGPR[SC_PARAM1].nV0);
679 break;
680 case 0x0A:
681 CLog::GetInstance().Print(LOG_NAME, "ChangeClearRCnt(param0 = %i, param1 = %i);\r\n",
682 m_cpu.m_State.nGPR[SC_PARAM0].nV0,
683 m_cpu.m_State.nGPR[SC_PARAM1].nV0);
684 break;
685 case 0x0C:
686 CLog::GetInstance().Print(LOG_NAME, "InitDefInt(priority = %d);\r\n",
687 m_cpu.m_State.nGPR[SC_PARAM0].nV0);
688 break;
689 default:
690 CLog::GetInstance().Print(LOG_NAME, "Unknown system call encountered (0xC0, 0x%X).\r\n", functionId);
691 break;
692 }
693 }
694 else
695 {
696 uint32 functionId = m_cpu.m_State.nGPR[CMIPS::A0].nV0;
697 switch(functionId)
698 {
699 case 0x01:
700 CLog::GetInstance().Print(LOG_NAME, "EnterCriticalSection();\r\n");
701 break;
702 case 0x02:
703 CLog::GetInstance().Print(LOG_NAME, "ExitCriticalSection();\r\n");
704 break;
705 default:
706 CLog::GetInstance().Print(LOG_NAME, "Unknown system call encountered.\r\n");
707 break;
708 }
709 }
710 }
711
712 //A0 - 13
sc_setjmp()713 void CPsxBios::sc_setjmp()
714 {
715 uint32 bufferAddress = m_cpu.m_pAddrTranslator(&m_cpu, m_cpu.m_State.nGPR[SC_PARAM0].nV0);
716 m_cpu.m_pMemoryMap->SetWord(bufferAddress + 0x00, m_cpu.m_State.nGPR[CMIPS::RA].nV0);
717 m_cpu.m_pMemoryMap->SetWord(bufferAddress + 0x04, m_cpu.m_State.nGPR[CMIPS::SP].nV0);
718 m_cpu.m_pMemoryMap->SetWord(bufferAddress + 0x08, m_cpu.m_State.nGPR[CMIPS::FP].nV0);
719 m_cpu.m_pMemoryMap->SetWord(bufferAddress + 0x0C, m_cpu.m_State.nGPR[CMIPS::S0].nV0);
720 m_cpu.m_pMemoryMap->SetWord(bufferAddress + 0x10, m_cpu.m_State.nGPR[CMIPS::S1].nV0);
721 m_cpu.m_pMemoryMap->SetWord(bufferAddress + 0x14, m_cpu.m_State.nGPR[CMIPS::S2].nV0);
722 m_cpu.m_pMemoryMap->SetWord(bufferAddress + 0x18, m_cpu.m_State.nGPR[CMIPS::S3].nV0);
723 m_cpu.m_pMemoryMap->SetWord(bufferAddress + 0x1C, m_cpu.m_State.nGPR[CMIPS::S4].nV0);
724 m_cpu.m_pMemoryMap->SetWord(bufferAddress + 0x20, m_cpu.m_State.nGPR[CMIPS::S5].nV0);
725 m_cpu.m_pMemoryMap->SetWord(bufferAddress + 0x24, m_cpu.m_State.nGPR[CMIPS::S6].nV0);
726 m_cpu.m_pMemoryMap->SetWord(bufferAddress + 0x28, m_cpu.m_State.nGPR[CMIPS::S7].nV0);
727 m_cpu.m_pMemoryMap->SetWord(bufferAddress + 0x2C, m_cpu.m_State.nGPR[CMIPS::GP].nV0);
728 m_cpu.m_State.nGPR[CMIPS::V0].nD0 = 0;
729 }
730
731 //A0 - 14
sc_longjmp()732 void CPsxBios::sc_longjmp()
733 {
734 uint32 buffer = m_cpu.m_State.nGPR[SC_PARAM0].nV0;
735 uint32 value = m_cpu.m_State.nGPR[SC_PARAM1].nV0;
736 LongJump(buffer, value);
737 }
738
739 //A0 - 19
sc_strcpy()740 void CPsxBios::sc_strcpy()
741 {
742 uint32 dst = m_cpu.m_pAddrTranslator(&m_cpu, m_cpu.m_State.nGPR[SC_PARAM0].nV0);
743 uint32 src = m_cpu.m_pAddrTranslator(&m_cpu, m_cpu.m_State.nGPR[SC_PARAM1].nV0);
744
745 strcpy(
746 reinterpret_cast<char*>(m_ram + dst),
747 reinterpret_cast<char*>(m_ram + src));
748
749 m_cpu.m_State.nGPR[SC_RETURN].nV0 = dst;
750 }
751
752 //A0 - 28
sc_bzero()753 void CPsxBios::sc_bzero()
754 {
755 uint32 address = m_cpu.m_pAddrTranslator(&m_cpu, m_cpu.m_State.nGPR[SC_PARAM0].nV0);
756 uint32 length = m_cpu.m_State.nGPR[SC_PARAM1].nV0;
757 if((address + length) > m_ramSize)
758 {
759 throw std::exception();
760 }
761 memset(m_ram + address, 0, length);
762 }
763
764 //A0 - 2A
sc_memcpy()765 void CPsxBios::sc_memcpy()
766 {
767 uint32 dst = m_cpu.m_pAddrTranslator(&m_cpu, m_cpu.m_State.nGPR[SC_PARAM0].nV0);
768 uint32 src = m_cpu.m_pAddrTranslator(&m_cpu, m_cpu.m_State.nGPR[SC_PARAM1].nV0);
769 uint32 length = m_cpu.m_State.nGPR[SC_PARAM2].nV0;
770
771 memcpy(m_ram + dst, m_ram + src, length);
772
773 m_cpu.m_State.nGPR[SC_RETURN].nV0 = m_cpu.m_State.nGPR[SC_PARAM0].nV0;
774 }
775
776 //A0 - 2B
sc_memset()777 void CPsxBios::sc_memset()
778 {
779 uint32 address = m_cpu.m_pAddrTranslator(&m_cpu, m_cpu.m_State.nGPR[SC_PARAM0].nV0);
780 uint8 value = static_cast<uint8>(m_cpu.m_State.nGPR[SC_PARAM1].nV0);
781 uint32 length = m_cpu.m_State.nGPR[SC_PARAM2].nV0;
782 if((address + length) > m_ramSize)
783 {
784 throw std::exception();
785 }
786 memset(m_ram + address, value, length);
787
788 m_cpu.m_State.nGPR[SC_RETURN].nV0 = address;
789 }
790
791 //A0 - 2F
sc_rand()792 void CPsxBios::sc_rand()
793 {
794 m_cpu.m_State.nGPR[SC_RETURN].nV0 = rand();
795 }
796
797 //A0 - 30
sc_srand()798 void CPsxBios::sc_srand()
799 {
800 uint32 seed = m_cpu.m_State.nGPR[SC_PARAM0].nV0;
801 srand(seed);
802 }
803
804 //A0 - 39
sc_InitHeap()805 void CPsxBios::sc_InitHeap()
806 {
807 uint32 block = m_cpu.m_State.nGPR[SC_PARAM0].nV0;
808 uint32 n = m_cpu.m_State.nGPR[SC_PARAM1].nV0;
809 }
810
811 //A0 - 3F
sc_printf()812 void CPsxBios::sc_printf()
813 {
814 uint32 formatAddress = m_cpu.m_State.nGPR[SC_PARAM0].nV0;
815 }
816
817 //A0 - 44
sc_FlushCache()818 void CPsxBios::sc_FlushCache()
819 {
820 }
821
822 //A0 - 70
sc_bu_init()823 void CPsxBios::sc_bu_init()
824 {
825 }
826
827 //A0 - 72
sc_96_remove()828 void CPsxBios::sc_96_remove()
829 {
830 }
831
832 //A0 - 9F
sc_SetMem()833 void CPsxBios::sc_SetMem()
834 {
835 uint32 n = m_cpu.m_State.nGPR[SC_PARAM0].nV0;
836 }
837
838 //B0 - 00
sc_SysMalloc()839 void CPsxBios::sc_SysMalloc()
840 {
841 uint32 size = m_cpu.m_State.nGPR[SC_PARAM0].nV0;
842 uint32 result = AllocateSysMemory(size);
843 m_cpu.m_State.nGPR[SC_RETURN].nV0 = result;
844 }
845
846 //B0 - 07
sc_DeliverEvent()847 void CPsxBios::sc_DeliverEvent()
848 {
849 uint32 classId = m_cpu.m_State.nGPR[SC_PARAM0].nV0;
850 uint32 eventId = m_cpu.m_State.nGPR[SC_PARAM1].nV0;
851 }
852
853 //B0 - 08
sc_OpenEvent()854 void CPsxBios::sc_OpenEvent()
855 {
856 uint32 classId = m_cpu.m_State.nGPR[SC_PARAM0].nV0;
857 uint32 spec = m_cpu.m_State.nGPR[SC_PARAM1].nV0;
858 uint32 mode = m_cpu.m_State.nGPR[SC_PARAM2].nV0;
859 uint32 func = m_cpu.m_State.nGPR[SC_PARAM3].nV0;
860
861 uint32 eventId = m_events.Allocate();
862 if(eventId == -1)
863 {
864 throw std::exception();
865 }
866 EVENT* eventPtr = m_events[eventId];
867 eventPtr->classId = classId;
868 eventPtr->spec = spec;
869 eventPtr->mode = mode;
870 eventPtr->func = func;
871 eventPtr->fired = 0;
872
873 m_cpu.m_State.nGPR[SC_RETURN].nD0 = static_cast<int32>(eventId);
874 }
875
876 //B0 - 09
sc_CloseEvent()877 void CPsxBios::sc_CloseEvent()
878 {
879 uint32 eventId = m_cpu.m_State.nGPR[SC_PARAM0].nV0;
880 EVENT* eventPtr = m_events[eventId];
881 if(eventPtr != NULL)
882 {
883 m_events.Free(eventId);
884 }
885
886 m_cpu.m_State.nGPR[SC_RETURN].nD0 = 0;
887 }
888
889 //B0 - 0A
sc_WaitEvent()890 void CPsxBios::sc_WaitEvent()
891 {
892 uint32 eventId = m_cpu.m_State.nGPR[SC_PARAM0].nV0;
893 auto event = m_events[eventId];
894 if(!event)
895 {
896 m_cpu.m_State.nGPR[SC_RETURN].nD0 = -1;
897 return;
898 }
899 assert(event->fired);
900 }
901
902 //B0 - 0B
sc_TestEvent()903 void CPsxBios::sc_TestEvent()
904 {
905 uint32 eventId = m_cpu.m_State.nGPR[SC_PARAM0].nV0;
906 auto eventPtr = m_events[eventId];
907
908 assert(eventPtr);
909 if(!eventPtr)
910 {
911 m_cpu.m_State.nGPR[SC_RETURN].nD0 = 0;
912 return;
913 }
914
915 m_cpu.m_State.nGPR[SC_RETURN].nD0 = eventPtr->fired;
916 eventPtr->fired = 0;
917 }
918
919 //B0 - 0C
sc_EnableEvent()920 void CPsxBios::sc_EnableEvent()
921 {
922 try
923 {
924 uint32 eventId = m_cpu.m_State.nGPR[SC_PARAM0].nV0;
925 EVENT* eventPtr = m_events[eventId];
926 if(eventPtr != NULL)
927 {
928 eventPtr->enabled = true;
929 eventPtr->fired = 0;
930 }
931 }
932 catch(...)
933 {
934 m_cpu.m_State.nGPR[SC_RETURN].nD0 = -1;
935 }
936 }
937
938 //B0 - 0D
sc_DisableEvent()939 void CPsxBios::sc_DisableEvent()
940 {
941 try
942 {
943 uint32 eventId = m_cpu.m_State.nGPR[SC_PARAM0].nV0;
944 EVENT* eventPtr = m_events[eventId];
945 if(eventPtr != NULL)
946 {
947 eventPtr->enabled = false;
948 }
949 }
950 catch(...)
951 {
952 m_cpu.m_State.nGPR[SC_RETURN].nD0 = -1;
953 }
954 }
955
956 //B0 - 0E
sc_OpenThread()957 void CPsxBios::sc_OpenThread()
958 {
959 uint32 threadPc = m_cpu.m_State.nGPR[SC_PARAM0].nV0;
960 uint32 threadSp = m_cpu.m_State.nGPR[SC_PARAM1].nV0;
961 uint32 threadGp = m_cpu.m_State.nGPR[SC_PARAM2].nV0;
962
963 auto threadCbTable = reinterpret_cast<CB_TABLE*>(m_ram + TCB_TABLE_ADDRESS);
964 assert(threadCbTable->address != 0);
965 assert(threadCbTable->size != 0);
966 assert((threadCbTable->size % sizeof(THREAD)) == 0);
967
968 auto threads = reinterpret_cast<THREAD*>(m_ram + threadCbTable->address);
969 auto threadCount = threadCbTable->size / sizeof(THREAD);
970
971 uint32 threadId = -1;
972 for(uint32 i = 0; i < threadCount; i++)
973 {
974 auto thread = &threads[i];
975 if(thread->status == THREAD_STATUS_ALLOCATED) continue;
976 assert(thread->status == THREAD_STATUS_FREE);
977 threadId = i;
978 break;
979 }
980
981 if(threadId == -1)
982 {
983 m_cpu.m_State.nGPR[SC_RETURN].nD0 = -1;
984 return;
985 }
986
987 auto thread = &threads[threadId];
988 thread->status = THREAD_STATUS_ALLOCATED;
989 thread->pc = threadPc;
990 thread->gpr[CMIPS::SP] = threadSp;
991 thread->gpr[CMIPS::FP] = threadSp;
992 thread->gpr[CMIPS::GP] = threadGp;
993
994 m_cpu.m_State.nGPR[SC_RETURN].nD0 = threadId;
995 }
996
997 //B0 - 10
sc_ChangeThread()998 void CPsxBios::sc_ChangeThread()
999 {
1000 uint32 threadId = m_cpu.m_State.nGPR[SC_PARAM0].nV0;
1001 m_cpu.m_State.nGPR[SC_RETURN].nD0 = 1;
1002
1003 SaveCpuState();
1004
1005 //Update current thread id
1006 {
1007 auto process = GetProcess();
1008
1009 auto threadCbTable = reinterpret_cast<CB_TABLE*>(m_ram + TCB_TABLE_ADDRESS);
1010 assert(threadCbTable->address != 0);
1011 assert(threadCbTable->size != 0);
1012 assert((threadCbTable->size % sizeof(THREAD)) == 0);
1013
1014 auto threadCount = threadCbTable->size / sizeof(THREAD);
1015 assert(threadId < threadCount);
1016
1017 process->currentThreadControlBlockAddr = threadCbTable->address + threadId * sizeof(THREAD);
1018 }
1019
1020 LoadCpuState();
1021 }
1022
1023 //B0 - 14
sc_StopPAD()1024 void CPsxBios::sc_StopPAD()
1025 {
1026 }
1027
1028 //B0 - 16
sc_PAD_dr()1029 void CPsxBios::sc_PAD_dr()
1030 {
1031 }
1032
1033 //B0 - 17
sc_ReturnFromException()1034 void CPsxBios::sc_ReturnFromException()
1035 {
1036 uint32& status = m_cpu.m_State.nCOP0[CCOP_SCU::STATUS];
1037 assert(status & (CMIPS::STATUS_ERL | CMIPS::STATUS_EXL));
1038 if(status & CMIPS::STATUS_ERL)
1039 {
1040 status &= ~CMIPS::STATUS_ERL;
1041 }
1042 else if(status & CMIPS::STATUS_EXL)
1043 {
1044 status &= ~CMIPS::STATUS_EXL;
1045 }
1046 LoadCpuState();
1047 }
1048
1049 //B0 - 18
sc_SetDefaultExitFromException()1050 void CPsxBios::sc_SetDefaultExitFromException()
1051 {
1052 m_exitFromExceptionStateAddr = 0;
1053 m_cpu.m_State.nGPR[SC_RETURN].nD0 = 0;
1054 }
1055
1056 //B0 - 19
sc_SetCustomExitFromException()1057 void CPsxBios::sc_SetCustomExitFromException()
1058 {
1059 uint32 stateAddr = m_cpu.m_State.nGPR[SC_PARAM0].nV0;
1060 m_exitFromExceptionStateAddr = stateAddr;
1061 }
1062
1063 //B0 - 3F
sc_puts()1064 void CPsxBios::sc_puts()
1065 {
1066 uint32 stringAddress = m_cpu.m_State.nGPR[SC_PARAM0].nV0;
1067 }
1068
1069 //B0 - 4A
sc_InitCARD()1070 void CPsxBios::sc_InitCARD()
1071 {
1072 }
1073
1074 //B0 - 4B
sc_StartCARD()1075 void CPsxBios::sc_StartCARD()
1076 {
1077 }
1078
1079 //B0 - 56
sc_GetC0Table()1080 void CPsxBios::sc_GetC0Table()
1081 {
1082 m_cpu.m_State.nGPR[SC_RETURN].nD0 = static_cast<int32>(C0TABLE_BEGIN);
1083 }
1084
1085 //B0 - 57
sc_GetB0Table()1086 void CPsxBios::sc_GetB0Table()
1087 {
1088 m_cpu.m_State.nGPR[SC_RETURN].nD0 = static_cast<int32>(B0TABLE_BEGIN);
1089 }
1090
1091 //B0 - 5B
sc_ChangeClearPad()1092 void CPsxBios::sc_ChangeClearPad()
1093 {
1094 uint32 param = m_cpu.m_State.nGPR[SC_PARAM0].nV0;
1095 }
1096
1097 //C0 - 00
sc_EnqueueTimerAndVblankIrqs()1098 void CPsxBios::sc_EnqueueTimerAndVblankIrqs()
1099 {
1100 }
1101
1102 //C0 - 01
sc_EnqueueSyscallHandler()1103 void CPsxBios::sc_EnqueueSyscallHandler()
1104 {
1105 }
1106
1107 //C0 - 03
sc_SysDeqIntRP()1108 void CPsxBios::sc_SysDeqIntRP()
1109 {
1110 uint32 index = m_cpu.m_State.nGPR[SC_PARAM0].nV0;
1111 uint32 queue = m_cpu.m_State.nGPR[SC_PARAM1].nV0;
1112 }
1113
1114 //C0 - 08
sc_SysInitMemory()1115 void CPsxBios::sc_SysInitMemory()
1116 {
1117 //Two parameters are passed, but don't seem to be used somehow?
1118 //TODO: Reset PCB and TCB addresses
1119 m_sysHeapPointerAddr = HEAP_START;
1120 memset(m_ram + HEAP_START, 0, HEAP_SIZE);
1121 }
1122
1123 //C0 - 0A
sc_ChangeClearRCnt()1124 void CPsxBios::sc_ChangeClearRCnt()
1125 {
1126 uint32 param0 = m_cpu.m_State.nGPR[SC_PARAM0].nV0;
1127 uint32 param1 = m_cpu.m_State.nGPR[SC_PARAM1].nV0;
1128 }
1129
1130 //C0 - 0C
sc_InitDefInt()1131 void CPsxBios::sc_InitDefInt()
1132 {
1133 }
1134
sc_EnterCriticalSection()1135 void CPsxBios::sc_EnterCriticalSection()
1136 {
1137 bool isIntEnabled = (m_cpu.m_State.nCOP0[CCOP_SCU::STATUS] & CMIPS::STATUS_IE) != 0;
1138 m_cpu.m_State.nCOP0[CCOP_SCU::STATUS] &= ~CMIPS::STATUS_IE;
1139
1140 m_cpu.m_State.nGPR[SC_RETURN].nD0 = static_cast<int32>(isIntEnabled ? 1 : 0);
1141 }
1142
sc_ExitCriticalSection()1143 void CPsxBios::sc_ExitCriticalSection()
1144 {
1145 m_cpu.m_State.nCOP0[CCOP_SCU::STATUS] |= CMIPS::STATUS_IE;
1146 }
1147
sc_Illegal()1148 void CPsxBios::sc_Illegal()
1149 {
1150 #ifdef _DEBUG
1151 throw std::runtime_error("Illegal system call.");
1152 #endif
1153 }
1154
1155 // clang-format off
1156 CPsxBios::SyscallHandler CPsxBios::m_handlerA0[MAX_HANDLER_A0] =
1157 {
1158 //0x00
1159 &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal,
1160 //0x08
1161 &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal,
1162 //0x10
1163 &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_setjmp, &CPsxBios::sc_longjmp, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal,
1164 //0x18
1165 &CPsxBios::sc_Illegal, &CPsxBios::sc_strcpy, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal,
1166 //0x20
1167 &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal,
1168 //0x28
1169 &CPsxBios::sc_bzero, &CPsxBios::sc_Illegal, &CPsxBios::sc_memcpy, &CPsxBios::sc_memset, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_rand,
1170 //0x30
1171 &CPsxBios::sc_srand, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal,
1172 //0x38
1173 &CPsxBios::sc_Illegal, &CPsxBios::sc_InitHeap, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_printf,
1174 //0x40
1175 &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_FlushCache, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal,
1176 //0x48
1177 &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal,
1178 //0x50
1179 &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal,
1180 //0x58
1181 &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal,
1182 //0x60
1183 &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal,
1184 //0x68
1185 &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal,
1186 //0x70
1187 &CPsxBios::sc_bu_init, &CPsxBios::sc_Illegal, &CPsxBios::sc_96_remove, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal,
1188 //0x78
1189 &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal,
1190 //0x80
1191 &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal,
1192 //0x88
1193 &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal,
1194 //0x90
1195 &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal,
1196 //0x98
1197 &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_SetMem,
1198 //0xA0
1199 &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal,
1200 //0xA8
1201 &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal,
1202 //0xB0
1203 &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal,
1204 //0xB8
1205 &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal,
1206 //0xC0
1207 &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal,
1208 //0xC8
1209 &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal,
1210 //0xD0
1211 &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal,
1212 //0xD8
1213 &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal,
1214 //0xE0
1215 &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal,
1216 //0xE8
1217 &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal,
1218 //0xF0
1219 &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal,
1220 //0xF8
1221 &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal
1222 };
1223
1224 CPsxBios::SyscallHandler CPsxBios::m_handlerB0[MAX_HANDLER_B0] =
1225 {
1226 //0x00
1227 &CPsxBios::sc_SysMalloc, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_DeliverEvent,
1228 //0x08
1229 &CPsxBios::sc_OpenEvent, &CPsxBios::sc_CloseEvent, &CPsxBios::sc_WaitEvent, &CPsxBios::sc_TestEvent, &CPsxBios::sc_EnableEvent, &CPsxBios::sc_DisableEvent, &CPsxBios::sc_OpenThread, &CPsxBios::sc_Illegal,
1230 //0x10
1231 &CPsxBios::sc_ChangeThread, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_StopPAD, &CPsxBios::sc_Illegal, &CPsxBios::sc_PAD_dr, &CPsxBios::sc_ReturnFromException,
1232 //0x18
1233 &CPsxBios::sc_SetDefaultExitFromException, &CPsxBios::sc_SetCustomExitFromException, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal,
1234 //0x20
1235 &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal,
1236 //0x28
1237 &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal,
1238 //0x30
1239 &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal,
1240 //0x38
1241 &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_puts,
1242 //0x40
1243 &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal,
1244 //0x48
1245 &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_InitCARD, &CPsxBios::sc_StartCARD, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal,
1246 //0x50
1247 &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_GetC0Table, &CPsxBios::sc_GetB0Table,
1248 //0x58
1249 &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_ChangeClearPad, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal,
1250 //0x60
1251 &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal,
1252 //0x68
1253 &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal,
1254 //0x70
1255 &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal,
1256 //0x78
1257 &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal
1258 };
1259
1260 CPsxBios::SyscallHandler CPsxBios::m_handlerC0[MAX_HANDLER_C0] =
1261 {
1262 //0x00
1263 &CPsxBios::sc_EnqueueTimerAndVblankIrqs, &CPsxBios::sc_EnqueueSyscallHandler, &CPsxBios::sc_Illegal, &CPsxBios::sc_SysDeqIntRP, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal,
1264 //0x08
1265 &CPsxBios::sc_SysInitMemory, &CPsxBios::sc_Illegal, &CPsxBios::sc_ChangeClearRCnt, &CPsxBios::sc_Illegal, &CPsxBios::sc_InitDefInt, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal,
1266 //0x10
1267 &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal,
1268 //0x18
1269 &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal, &CPsxBios::sc_Illegal
1270 };
1271 // clang-format on
1272