1 /***************************************************************************
2 * Copyright (C) 2019 Ryan Schultz, PCSX-df Team, PCSX team, gameblabla, *
3 * dmitrysmagin, senquack *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA. *
19 ***************************************************************************/
21 /* Gameblabla 2018-2019 :
22 * Numerous changes to bios calls as well as improvements in order to conform to nocash's findings
23 * for the PSX bios calls. Thanks senquack for helping out with some of the changes
24 * and helping to spot issues and refine my patches.
28 * Internal simulated HLE BIOS.
31 // TODO: implement all system calls, count the exact CPU cycles of system calls.
38 #include "psxinterpreter.h"
39 #include "psxevents.h"
45 //#define PSXBIOS_LOG printf
46 #define PSXBIOS_LOG(...)
48 #ifndef PSXBIOS_EV_LOG
49 //#define PSXBIOS_EV_LOG printf
50 #define PSXBIOS_EV_LOG(...)
53 #define PTR_1 (void *)(size_t)1
55 char *biosA0n[256] = {
57 "open", "lseek", "read", "write",
58 "close", "ioctl", "exit", "sys_a0_07",
59 "getc", "putc", "todigit", "atof",
60 "strtoul", "strtol", "abs", "labs",
62 "atoi", "atol", "atob", "setjmp",
63 "longjmp", "strcat", "strncat", "strcmp",
64 "strncmp", "strcpy", "strncpy", "strlen",
65 "index", "rindex", "strchr", "strrchr",
67 "strpbrk", "strspn", "strcspn", "strtok",
68 "strstr", "toupper", "tolower", "bcopy",
69 "bzero", "bcmp", "memcpy", "memset",
70 "memmove", "memcmp", "memchr", "rand",
72 "srand", "qsort", "strtod", "malloc",
73 "free", "lsearch", "bsearch", "calloc",
74 "realloc", "InitHeap", "_exit", "getchar",
75 "putchar", "gets", "puts", "printf",
77 "SystemErrorUnresolvedException", "LoadTest", "Load", "Exec",
78 "FlushCache", "InstallInterruptHandler", "GPU_dw", "mem2vram",
79 "SendGPUStatus", "GPU_cw", "GPU_cwb", "SendPackets",
80 "sys_a0_4c", "GetGPUStatus", "GPU_sync", "sys_a0_4f",
82 "sys_a0_50", "LoadExec", "GetSysSp", "sys_a0_53",
83 "_96_init()", "_bu_init()", "_96_remove()", "sys_a0_57",
84 "sys_a0_58", "sys_a0_59", "sys_a0_5a", "dev_tty_init",
85 "dev_tty_open", "sys_a0_5d", "dev_tty_ioctl","dev_cd_open",
87 "dev_cd_read", "dev_cd_close", "dev_cd_firstfile", "dev_cd_nextfile",
88 "dev_cd_chdir", "dev_card_open", "dev_card_read", "dev_card_write",
89 "dev_card_close", "dev_card_firstfile", "dev_card_nextfile","dev_card_erase",
90 "dev_card_undelete","dev_card_format", "dev_card_rename", "dev_card_6f",
92 "_bu_init", "CdInit", "CdRemove", "sys_a0_73",
93 "sys_a0_74", "sys_a0_75", "sys_a0_76", "sys_a0_77",
94 "_96_CdSeekL", "sys_a0_79", "sys_a0_7a", "sys_a0_7b",
95 "_96_CdGetStatus", "sys_a0_7d", "_96_CdRead", "sys_a0_7f",
97 "sys_a0_80", "sys_a0_81", "sys_a0_82", "sys_a0_83",
98 "sys_a0_84", "_96_CdStop", "sys_a0_86", "sys_a0_87",
99 "sys_a0_88", "sys_a0_89", "sys_a0_8a", "sys_a0_8b",
100 "sys_a0_8c", "sys_a0_8d", "sys_a0_8e", "sys_a0_8f",
102 "sys_a0_90", "sys_a0_91", "sys_a0_92", "sys_a0_93",
103 "sys_a0_94", "CdReset", "AddCDROMDevice", "AddMemCardDevide",
104 "DisableKernelIORedirection", "EnableKernelIORedirection", "sys_a0_9a", "sys_a0_9b",
105 "SetConf", "GetConf", "sys_a0_9e", "SetMem",
107 "_boot", "SystemError", "EnqueueCdIntr", "DequeueCdIntr",
108 "sys_a0_a4", "ReadSector", "get_cd_status", "bufs_cb_0",
109 "bufs_cb_1", "bufs_cb_2", "bufs_cb_3", "_card_info",
110 "_card_load", "_card_auto", "bufs_cd_4", "sys_a0_af",
112 "sys_a0_b0", "sys_a0_b1", "do_a_long_jmp", "sys_a0_b3",
116 char *biosB0n[256] = {
118 "SysMalloc", "sys_b0_01", "sys_b0_02", "sys_b0_03",
119 "sys_b0_04", "sys_b0_05", "sys_b0_06", "DeliverEvent",
120 "OpenEvent", "CloseEvent", "WaitEvent", "TestEvent",
121 "EnableEvent", "DisableEvent", "OpenTh", "CloseTh",
123 "ChangeTh", "sys_b0_11", "InitPAD", "StartPAD",
124 "StopPAD", "PAD_init", "PAD_dr", "ReturnFromException",
125 "ResetEntryInt", "HookEntryInt", "sys_b0_1a", "sys_b0_1b",
126 "sys_b0_1c", "sys_b0_1d", "sys_b0_1e", "sys_b0_1f",
128 "UnDeliverEvent", "sys_b0_21", "sys_b0_22", "sys_b0_23",
129 "sys_b0_24", "sys_b0_25", "sys_b0_26", "sys_b0_27",
130 "sys_b0_28", "sys_b0_29", "sys_b0_2a", "sys_b0_2b",
131 "sys_b0_2c", "sys_b0_2d", "sys_b0_2e", "sys_b0_2f",
133 "sys_b0_30", "sys_b0_31", "open", "lseek",
134 "read", "write", "close", "ioctl",
135 "exit", "sys_b0_39", "getc", "putc",
136 "getchar", "putchar", "gets", "puts",
138 "cd", "format", "firstfile", "nextfile",
139 "rename", "delete", "undelete", "AddDevice",
140 "RemoteDevice", "PrintInstalledDevices", "InitCARD", "StartCARD",
141 "StopCARD", "sys_b0_4d", "_card_write", "_card_read",
143 "_new_card", "Krom2RawAdd", "sys_b0_52", "sys_b0_53",
144 "_get_errno", "_get_error", "GetC0Table", "GetB0Table",
145 "_card_chan", "sys_b0_59", "sys_b0_5a", "ChangeClearPAD",
146 "_card_status", "_card_wait",
149 char *biosC0n[256] = {
151 "InitRCnt", "InitException", "SysEnqIntRP", "SysDeqIntRP",
152 "get_free_EvCB_slot", "get_free_TCB_slot", "ExceptionHandler", "InstallExeptionHandler",
153 "SysInitMemory", "SysInitKMem", "ChangeClearRCnt", "SystemError",
154 "InitDefInt", "sys_c0_0d", "sys_c0_0e", "sys_c0_0f",
156 "sys_c0_10", "sys_c0_11", "InstallDevices", "FlushStfInOutPut",
157 "sys_c0_14", "_cdevinput", "_cdevscan", "_circgetc",
158 "_circputc", "ioabort", "sys_c0_1a", "KernelRedirect",
162 //#define r0 (psxRegs.GPR.n.r0)
163 #define at (psxRegs.GPR.n.at)
164 #define v0 (psxRegs.GPR.n.v0)
165 #define v1 (psxRegs.GPR.n.v1)
166 #define a0 (psxRegs.GPR.n.a0)
167 #define a1 (psxRegs.GPR.n.a1)
168 #define a2 (psxRegs.GPR.n.a2)
169 #define a3 (psxRegs.GPR.n.a3)
170 #define t0 (psxRegs.GPR.n.t0)
171 #define t1 (psxRegs.GPR.n.t1)
172 #define t2 (psxRegs.GPR.n.t2)
173 #define t3 (psxRegs.GPR.n.t3)
174 #define t4 (psxRegs.GPR.n.t4)
175 #define t5 (psxRegs.GPR.n.t5)
176 #define t6 (psxRegs.GPR.n.t6)
177 #define t7 (psxRegs.GPR.n.t7)
178 #define t8 (psxRegs.GPR.n.t8)
179 #define t9 (psxRegs.GPR.n.t9)
180 #define s0 (psxRegs.GPR.n.s0)
181 #define s1 (psxRegs.GPR.n.s1)
182 #define s2 (psxRegs.GPR.n.s2)
183 #define s3 (psxRegs.GPR.n.s3)
184 #define s4 (psxRegs.GPR.n.s4)
185 #define s5 (psxRegs.GPR.n.s5)
186 #define s6 (psxRegs.GPR.n.s6)
187 #define s7 (psxRegs.GPR.n.s7)
188 #define k0 (psxRegs.GPR.n.k0)
189 #define k1 (psxRegs.GPR.n.k1)
190 #define gp (psxRegs.GPR.n.gp)
191 #define sp (psxRegs.GPR.n.sp)
192 #define fp (psxRegs.GPR.n.fp)
193 #define ra (psxRegs.GPR.n.ra)
194 #define pc0 (psxRegs.pc)
196 #define Ra0 ((char *)PSXM(a0))
197 #define Ra1 ((char *)PSXM(a1))
198 #define Ra2 ((char *)PSXM(a2))
199 #define Ra3 ((char *)PSXM(a3))
200 #define Rv0 ((char *)PSXM(v0))
201 #define Rsp ((char *)PSXM(sp))
212 #define EvStUNUSED 0x0000
213 #define EvStDISABLED 0x1000
214 #define EvStACTIVE 0x2000
215 #define EvStALREADY 0x4000
217 #define EvMdCALL 0x1000
218 #define EvMdMARK 0x2000
241 u32 _sp, _fp, _gp, ret, base;
261 // todo: FileDesc layout is wrong
262 // todo: get rid of these globals
263 static FileDesc FDesc[32];
264 static char ffile[64];
266 static char cdir[8*8+8];
268 static int card_io_delay;
270 // fixed RAM offsets, SCPH1001 compatible
271 #define A_TT_ExCB 0x0100
272 #define A_TT_PCB 0x0108
273 #define A_TT_TCB 0x0110
274 #define A_TT_EvCB 0x0120
275 #define A_A0_TABLE 0x0200
276 #define A_B0_TABLE 0x0874
277 #define A_C0_TABLE 0x0674
278 #define A_SYSCALL 0x0650
279 #define A_EXCEPTION 0x0c80
280 #define A_EXC_SP 0x6cf0
281 #define A_EEXIT_DEF 0x6cf4
282 #define A_CARD_ISLOT 0x7264 // 0 or 1, toggled by card vint handler
283 #define A_KMALLOC_PTR 0x7460
284 #define A_KMALLOC_SIZE 0x7464
285 #define A_KMALLOC_END 0x7468
286 #define A_PADCRD_CHN_E 0x74a8 // pad/card irq chain entry, see hleExcPadCard1()
287 #define A_PAD_IRQR_ENA 0x74b8 // pad read on vint irq (nocash 'pad_enable_flag')
288 #define A_CARD_IRQR_ENA 0x74bc // same for card
289 #define A_PAD_INBUF 0x74c8 // 2x buffers for rx pad data
290 #define A_PAD_OUTBUF 0x74d0 // 2x buffers for tx pad data
291 #define A_PAD_IN_LEN 0x74d8
292 #define A_PAD_OUT_LEN 0x74e0
293 #define A_PAD_DR_DST 0x74c4
294 #define A_CARD_ACHAN 0x7500 // currently active port in 0xPortSlot format
295 #define A_CARD_HANDLER 0x7528 // ptr to irq handler
296 #define A_CARD_STATUS1 0x7568
297 #define A_CARD_STATUS2 0x7569
298 #define A_PAD_DR_BUF1 0x7570
299 #define A_PAD_DR_BUF2 0x7598
300 #define A_EEXIT_PTR 0x75d0
301 #define A_EXC_STACK 0x85d8 // exception stack top
302 #define A_RCNT_VBL_ACK 0x8600
303 #define A_PAD_ACK_VBL 0x8914 // enable vint ack by pad reading code
304 #define A_HEAP_BASE 0x9000
305 #define A_HEAP_SIZE 0x9004
306 #define A_HEAP_END 0x9008
307 #define A_HEAP_INIT_FLG 0x900c
308 #define A_RND_SEED 0x9010
309 #define A_HEAP_FRSTCHNK 0xb060
310 #define A_HEAP_CURCHNK 0xb064
311 #define A_CONF_TCB 0xb940
312 #define A_CONF_EvCB 0xb944
313 #define A_CONF_SP 0xb948
314 #define A_CD_EVENTS 0xb9b8
315 #define A_EXC_GP 0xf450
317 #define A_A0_TRAPS 0x1010
318 #define A_B0_TRAPS 0x2010
319 #define A_C0_TRAPS 0x3010
320 #define A_B0_5B_TRAP 0x43d0
322 #define CARD_HARDLER_WRITE 0x51F4
323 #define CARD_HARDLER_WRITEM 0x51F5 // fake, for psxBios_write()
324 #define CARD_HARDLER_READ 0x5688
325 #define CARD_HARDLER_READM 0x5689 // fake, for psxBios_read()
326 #define CARD_HARDLER_INFO 0x5B64
328 #define HLEOP(n) SWAPu32((0x3bu << 26) | (n));
330 static u8 loadRam8(u32 addr)
332 assert(!(addr & 0x5f800000));
333 return psxM[addr & 0x1fffff];
336 static u32 loadRam32(u32 addr)
338 assert(!(addr & 0x5f800000));
339 return SWAP32(*((u32 *)psxM + ((addr & 0x1fffff) >> 2)));
342 static void *castRam8ptr(u32 addr)
344 assert(!(addr & 0x5f800000));
345 return psxM + (addr & 0x1fffff);
348 static void *castRam32ptr(u32 addr)
350 assert(!(addr & 0x5f800003));
351 return psxM + (addr & 0x1ffffc);
354 static void *loadRam8ptr(u32 addr)
356 return castRam8ptr(loadRam32(addr));
359 static void *loadRam32ptr(u32 addr)
361 return castRam32ptr(loadRam32(addr));
364 static void storeRam8(u32 addr, u8 d)
366 assert(!(addr & 0x5f800000));
367 *((u8 *)psxM + (addr & 0x1fffff)) = d;
370 static void storeRam32(u32 addr, u32 d)
372 assert(!(addr & 0x5f800000));
373 *((u32 *)psxM + ((addr & 0x1fffff) >> 2)) = SWAP32(d);
376 static void mips_return(u32 val)
382 static void mips_return_void(void)
387 static void use_cycles(u32 cycle)
389 psxRegs.cycle += cycle * 2;
392 static void mips_return_c(u32 val, u32 cycle)
398 static void mips_return_void_c(u32 cycle)
404 static int returned_from_exception(void)
406 // 0x80000080 means it took another exception just after return
407 return pc0 == k0 || pc0 == 0x80000080
409 // lightrec doesn't return at 0x80000080, so look
410 // for the next block too
411 || pc0 == A_EXCEPTION
416 int psxBiosSoftcallEnded(void)
418 return pc0 == 0x80001000 || returned_from_exception();
421 // TODO: get rid of this softCall() thing as recursive cpu calls cause
422 // complications with dynarecs
423 static inline void softCall(u32 pc) {
425 u32 ssr = psxRegs.CP0.n.SR;
429 psxRegs.CP0.n.SR &= ~0x404; // disable interrupts
431 assert(psxRegs.cpuInRecursion <= 1);
432 psxRegs.cpuInRecursion++;
433 psxCpu->Notify(R3000ACPU_NOTIFY_AFTER_LOAD, PTR_1);
435 while (!psxBiosSoftcallEnded() && ++lim < 0x100000)
436 psxCpu->ExecuteBlock(&psxRegs, EXEC_CALLER_HLE);
438 psxCpu->Notify(R3000ACPU_NOTIFY_BEFORE_SAVE, PTR_1);
439 psxRegs.cpuInRecursion--;
441 if (pc0 != 0x80001000)
442 log_unhandled("%s @%x did not return (@%x cnt=%d)\n",
443 __func__, pc, pc0, lim);
445 psxRegs.CP0.n.SR |= ssr & 0x404;
448 static inline void softCallInException(u32 pc) {
453 assert(ra != 0x80001000);
454 if (ra == 0x80001000)
458 psxRegs.cpuInRecursion++;
459 psxCpu->Notify(R3000ACPU_NOTIFY_AFTER_LOAD, PTR_1);
461 while (!psxBiosSoftcallEnded() && ++lim < 0x100000)
462 psxCpu->ExecuteBlock(&psxRegs, EXEC_CALLER_HLE);
464 psxCpu->Notify(R3000ACPU_NOTIFY_BEFORE_SAVE, PTR_1);
465 psxRegs.cpuInRecursion--;
467 if (pc0 != 0x80001000 && !psxBiosSoftcallEnded())
468 log_unhandled("%s @%x did not return (@%x cnt=%d)\n",
469 __func__, pc, pc0, lim);
470 if (pc0 == 0x80001000)
474 static u32 OpenEvent(u32 class, u32 spec, u32 mode, u32 func);
475 static void EnableEvent(u32 ev, int do_log);
476 static u32 DeliverEvent(u32 class, u32 spec);
477 static u32 UnDeliverEvent(u32 class, u32 spec);
478 static void CloseEvent(u32 ev);
480 static int card_buf_io(int is_write, int port, void *buf, u32 size)
482 char *mcdptr = port ? Mcd2Data : Mcd1Data;
483 FileDesc *desc = &FDesc[2 + port];
484 u32 offset = 8192 * desc->mcfile + desc->offset;
486 PSXBIOS_LOG("card_%s_buf %d,%d: ofs=%x(%x) sz=%x (%s)\n",
487 is_write ? "write" : "read", port, desc->mcfile,
488 desc->offset, offset, size, mcdptr + 128 * desc->mcfile + 0xa);
489 if (!(loadRam8(A_CARD_STATUS1 + port) & 1)) {
490 PSXBIOS_LOG(" ...busy %x\n", loadRam8(A_CARD_STATUS1 + port));
493 UnDeliverEvent(0xf4000001, 0x0004);
494 UnDeliverEvent(0xf4000001, 0x8000);
495 UnDeliverEvent(0xf4000001, 0x2000);
496 UnDeliverEvent(0xf4000001, 0x0100);
498 if (offset >= 128*1024u) {
499 log_unhandled("card offs %x(%x)\n", desc->offset, offset);
500 DeliverEvent(0xf4000001, 0x8000); // ?
503 if (offset + size >= 128*1024u) {
504 log_unhandled("card offs+size %x+%x\n", offset, size);
505 size = 128*1024 - offset;
508 memcpy(mcdptr + offset, buf, size);
510 SaveMcd(Config.Mcd1, Mcd1Data, offset, size);
512 SaveMcd(Config.Mcd2, Mcd2Data, offset, size);
515 size_t ram_offset = (s8 *)buf - psxM;
516 memcpy(buf, mcdptr + offset, size);
517 if (ram_offset < 0x200000)
518 psxCpu->Clear(ram_offset, (size + 3) / 4);
520 desc->offset += size;
521 if (desc->mode & 0x8000) { // async
522 storeRam8(A_CARD_STATUS1 + port, is_write ? 4 : 2); // busy
523 storeRam32(A_CARD_HANDLER,
524 is_write ? CARD_HARDLER_WRITEM : CARD_HARDLER_READM);
525 card_io_delay = 2 + size / 1024; // hack
534 // System calls A0 */
536 /* Internally redirects to "FileRead(fd,tempbuf,1)".*/
537 /* For some strange reason, the returned character is sign-expanded; */
538 /* So if a return value of FFFFFFFFh could mean either character FFh, or error. */
539 static void psxBios_getc(void) // 0x03, 0x35
544 PSXBIOS_LOG("psxBios_%s %d\n", biosA0n[0x03], a0);
548 else if (a0 == 2 || a0 == 3) {
549 card_buf_io(0, a0 - 2, buf, 1);
553 mips_return_c(ret, 100);
556 /* Copy of psxBios_write, except size is 1. */
557 static void psxBios_putc(void) // 0x09, 0x3B
559 u8 buf[1] = { (u8)a0 };
562 if (a1 != 1) // not stdout
563 PSXBIOS_LOG("psxBios_%s '%c' %d\n", biosA0n[0x09], (char)a0, a1);
565 if (a1 == 1) { // stdout
566 if (Config.PsxOut) printf("%c", (char)a0);
568 else if (a1 == 2 || a1 == 3) {
569 ret = card_buf_io(1, a1 - 2, buf, 1);
572 mips_return_c(ret, 100);
575 static u32 do_todigit(u32 c)
578 if (c >= 0x30 && c < 0x3A) {
581 else if (c > 0x60 && c < 0x7B) {
584 else if (c > 0x40 && c < 0x5B) {
587 else if (c >= 0x80) {
588 log_unhandled("todigit %02x\n", c);
599 static void psxBios_todigit(void) // 0x0a
601 mips_return(do_todigit(a0));
602 PSXBIOS_LOG("psxBios_%s '%c' -> %u\n", biosA0n[0x0a], a0, v0);
605 static void do_strtol(char *p, void *end_, u32 base, int can_neg) {
610 if (p == INVALID_PTR) {
615 for (; (0x09 <= *p && *p <= '\r') || *p == ' '; p++)
618 for (; *p == '-'; f = 1, p++)
621 if (base == 0 || base > 36)
625 case 'b': case 'B': base = 2; break;
626 case 'x': case 'X': base = 16; break;
629 else if (*p == 'o' || *p == 'O') {
634 for (; (t = do_todigit(*p)) < base; p++) {
640 if (end != INVALID_PTR)
641 *end = SWAP32(a0 + (p - Ra0));
642 mips_return_c(n, 100);
645 static void psxBios_strtoul() { // 0x0c
646 do_strtol(a0 ? Ra0 : INVALID_PTR, a1 ? Ra1 : INVALID_PTR, a2, 0);
647 PSXBIOS_LOG("psxBios_%s %s (%x), %x, %x -> 0x%x\n",
648 biosA0n[0x0c], a0 ? Ra0 : NULL, a0, a1, a2, v0);
651 static void psxBios_strtol() { // 0x0d
652 do_strtol(a0 ? Ra0 : INVALID_PTR, a1 ? Ra1 : INVALID_PTR, a2, 1);
653 PSXBIOS_LOG("psxBios_%s %s (%x), %x, %x -> 0x%x\n",
654 biosA0n[0x0d], a0 ? Ra0 : NULL, a0, a1, a2, v0);
657 void psxBios_abs() { // 0x0e
658 if ((s32)a0 < 0) v0 = -(s32)a0;
663 void psxBios_labs() { // 0x0f
667 void psxBios_atoi() { // 0x10
669 char *p = (char *)Ra0;
671 if (p == INVALID_PTR) {
678 case ' ': case '\t': continue;
685 while (*p >= '0' && *p <= '9') {
686 n = n * 10 + *p++ - '0';
691 PSXBIOS_LOG("psxBios_%s %s (%x) -> 0x%x\n", biosA0n[0x10], Ra0, a0, v0);
694 void psxBios_atol() { // 0x11
704 static void psxBios_setjmp() { // 0x13
705 struct jmp_buf_ *jmp_buf = castRam32ptr(a0);
708 PSXBIOS_LOG("psxBios_%s %x\n", biosA0n[0x13], a0);
710 jmp_buf->ra_ = SWAP32(ra);
711 jmp_buf->sp_ = SWAP32(sp);
712 jmp_buf->fp_ = SWAP32(fp);
713 for (i = 0; i < 8; i++) // s0-s7
714 jmp_buf->s[i] = SWAP32(psxRegs.GPR.r[16 + i]);
715 jmp_buf->gp_ = SWAP32(gp);
717 mips_return_c(0, 15);
720 static void longjmp_load(const struct jmp_buf_ *jmp_buf)
724 ra = SWAP32(jmp_buf->ra_);
725 sp = SWAP32(jmp_buf->sp_);
726 fp = SWAP32(jmp_buf->fp_);
727 for (i = 0; i < 8; i++) // s0-s7
728 psxRegs.GPR.r[16 + i] = SWAP32(jmp_buf->s[i]);
729 gp = SWAP32(jmp_buf->gp_);;
732 void psxBios_longjmp() { // 0x14
733 struct jmp_buf_ *jmp_buf = castRam32ptr(a0);
735 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x14]);
736 longjmp_load(jmp_buf);
737 mips_return_c(a1, 15);
740 void psxBios_strcat() { // 0x15
744 PSXBIOS_LOG("psxBios_%s %s (%x), %s (%x)\n", biosA0n[0x15], Ra0, a0, Ra1, a1);
745 if (a0 == 0 || a1 == 0 || p2 == INVALID_PTR)
750 while (loadRam8(p1)) {
754 for (; *p2; p1++, p2++)
758 mips_return_c(a0, 22);
761 void psxBios_strncat() { // 0x16
762 char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
766 PSXBIOS_LOG("psxBios_%s: %s (%x), %s (%x), %d\n", biosA0n[0x16], Ra0, a0, Ra1, a1, a2);
768 if (a0 == 0 || a1 == 0)
776 while ((*p1++ = *p2++) != '\0') {
786 void psxBios_strcmp() { // 0x17
787 char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
789 if (a0 == 0 && a1 == 0)
795 else if (a0 == 0 && a1 != 0)
801 else if (a0 != 0 && a1 == 0)
808 PSXBIOS_LOG("psxBios_%s: %s (%x), %s (%x)\n", biosA0n[0x17], Ra0, a0, Ra1, a1);
811 while (*p1 == *p2++) {
830 void psxBios_strncmp() { // 0x18
831 char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
833 if (a0 == 0 && a1 == 0)
839 else if (a0 == 0 && a1 != 0)
845 else if (a0 != 0 && a1 == 0)
852 PSXBIOS_LOG("psxBios_%s: %s (%x), %s (%x), %d\n", biosA0n[0x18], Ra0, a0, Ra1, a1, a2);
855 while (--n >= 0 && *p1 == *p2++) {
859 v1 = a2 - ((a2-n) - 1);
867 v0 = (n < 0 ? 0 : *p1 - *--p2);
869 v1 = a2 - ((a2-n) - 1);
875 void psxBios_strcpy() { // 0x19
876 char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
877 PSXBIOS_LOG("psxBios_%s %x, %s (%x)\n", biosA0n[0x19], a0, p2, a1);
878 if (a0 == 0 || a1 == 0)
884 while ((*p1++ = *p2++) != '\0');
889 void psxBios_strncpy() { // 0x1a
890 char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
892 if (a0 == 0 || a1 == 0)
898 for (i = 0; i < n; i++) {
899 if ((*p1++ = *p2++) == '\0') {
911 void psxBios_strlen() { // 0x1b
912 char *p = (char *)Ra0;
923 void psxBios_index() { // 0x1c
924 char *p = (char *)Ra0;
934 v0 = a0 + (p - (char *)Ra0);
938 } while (*p++ != '\0');
943 void psxBios_rindex() { // 0x1d
944 char *p = (char *)Ra0;
954 v0 = a0 + (p - (char *)Ra0);
955 } while (*p++ != '\0');
960 void psxBios_strchr() { // 0x1e
964 void psxBios_strrchr() { // 0x1f
968 void psxBios_strpbrk() { // 0x20
969 char *p1 = (char *)Ra0, *p2 = (char *)Ra1, *scanp, c, sc;
971 while ((c = *p1++) != '\0') {
972 for (scanp = p2; (sc = *scanp++) != '\0';) {
974 v0 = a0 + (p1 - 1 - (char *)Ra0);
981 // BUG: return a0 instead of NULL if not found
985 void psxBios_strspn() { // 0x21
988 for (p1 = (char *)Ra0; *p1 != '\0'; p1++) {
989 for (p2 = (char *)Ra1; *p2 != '\0' && *p2 != *p1; p2++);
990 if (*p2 == '\0') break;
993 v0 = p1 - (char *)Ra0; pc0 = ra;
996 void psxBios_strcspn() { // 0x22
999 for (p1 = (char *)Ra0; *p1 != '\0'; p1++) {
1000 for (p2 = (char *)Ra1; *p2 != '\0' && *p2 != *p1; p2++);
1001 if (*p2 != '\0') break;
1004 v0 = p1 - (char *)Ra0; pc0 = ra;
1007 void psxBios_strtok() { // 0x23
1008 char *pcA0 = (char *)Ra0;
1009 char *pcRet = strtok(pcA0, (char *)Ra1);
1011 v0 = a0 + pcRet - pcA0;
1017 void psxBios_strstr() { // 0x24
1018 char *p = (char *)Ra0, *p1, *p2;
1019 PSXBIOS_LOG("psxBios_%s %s (%x), %s (%x)\n", biosA0n[0x24], p, a0, Ra1, a1);
1021 while (*p != '\0') {
1025 while (*p1 != '\0' && *p2 != '\0' && *p1 == *p2) {
1030 v0 = a0 + (p - (char *)Ra0);
1032 PSXBIOS_LOG(" -> %x\n", v0);
1036 // bug: skips the whole matched substring + 1
1043 void psxBios_toupper() { // 0x25
1044 v0 = (s8)(a0 & 0xff);
1045 if (v0 >= 'a' && v0 <= 'z') v0 -= 'a' - 'A';
1049 void psxBios_tolower() { // 0x26
1050 v0 = (s8)(a0 & 0xff);
1051 if (v0 >= 'A' && v0 <= 'Z') v0 += 'a' - 'A';
1055 static void do_memset(u32 dst, u32 v, s32 len)
1061 if (db != INVALID_PTR)
1065 psxCpu->Clear(dst, (len + 3) / 4);
1068 static void do_memcpy(u32 dst, u32 src, s32 len)
1070 u32 d = dst, s = src;
1073 const u8 *sb = PSXM(s);
1075 if (db != INVALID_PTR && sb != INVALID_PTR)
1080 psxCpu->Clear(dst, (len + 3) / 4);
1083 static void psxBios_memcpy();
1085 static void psxBios_bcopy() { // 0x27 - memcpy with args swapped
1086 //PSXBIOS_LOG("psxBios_%s %x %x %x\n", biosA0n[0x27], a0, a1, a2);
1087 u32 ret = a0, cycles = 0;
1088 if (a0 == 0) // ...but it checks src this time
1090 mips_return_c(0, 4);
1095 do_memcpy(a1, a0, a2);
1101 mips_return_c(ret, cycles + 5);
1104 static void psxBios_bzero() { // 0x28
1105 /* Same as memset here (See memset below) */
1106 u32 ret = a0, cycles;
1107 if (a0 == 0 || (s32)a1 <= 0)
1109 mips_return_c(0, 6);
1112 do_memset(a0, 0, a1);
1116 // todo: many more cycles due to uncached bios mem
1117 mips_return_c(ret, cycles + 5);
1120 void psxBios_bcmp() { // 0x29
1121 char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
1123 if (a0 == 0 || a1 == 0) { v0 = 0; pc0 = ra; return; }
1125 while ((s32)a2-- > 0) {
1126 if (*p1++ != *p2++) {
1127 v0 = *p1 - *p2; // BUG: compare the NEXT byte
1136 static void psxBios_memcpy() { // 0x2a
1137 u32 ret = a0, cycles = 0;
1140 mips_return_c(0, 4);
1145 do_memcpy(a0, a1, a2);
1151 mips_return_c(ret, cycles + 5);
1154 static void psxBios_memset() { // 0x2b
1155 u32 ret = a0, cycles;
1156 if (a0 == 0 || (s32)a2 <= 0)
1158 mips_return_c(0, 6);
1161 do_memset(a0, a1, a2);
1165 // todo: many more cycles due to uncached bios mem
1166 mips_return_c(ret, cycles + 5);
1169 void psxBios_memmove() { // 0x2c
1170 u32 ret = a0, cycles = 0;
1173 mips_return_c(0, 4);
1177 if ((s32)a2 > 0 && a0 > a1 && a0 < a1 + a2) {
1178 u32 dst = a0, len = a2 + 1;
1181 while ((s32)a2 >= 0) { // BUG: copies one more byte here
1182 const u8 *sb = PSXM(a1);
1184 if (db != INVALID_PTR && sb != INVALID_PTR)
1190 psxCpu->Clear(dst, (len + 3) / 4);
1191 cycles = 10 + len * 8;
1192 } else if ((s32)a2 > 0) {
1193 do_memcpy(a0, a1, a2);
1199 mips_return_c(ret, cycles + 5);
1202 void psxBios_memcmp() { // 0x2d
1206 void psxBios_memchr() { // 0x2e
1207 char *p = (char *)Ra0;
1209 if (a0 == 0 || a2 > 0x7FFFFFFF)
1215 while ((s32)a2-- > 0) {
1216 if (*p++ != (s8)a1) continue;
1217 v0 = a0 + (p - (char *)Ra0 - 1);
1225 static void psxBios_rand() { // 0x2f
1226 u32 s = loadRam32(A_RND_SEED) * 1103515245 + 12345;
1227 storeRam32(A_RND_SEED, s);
1229 mips_return_c((s >> 16) & 0x7fff, 12+37);
1232 static void psxBios_srand() { // 0x30
1233 storeRam32(A_RND_SEED, a0);
1234 mips_return_void_c(3);
1237 static u32 qscmpfunc, qswidth;
1239 static inline int qscmp(char *a, char *b) {
1242 a0 = sa0 + (a - (char *)PSXM(sa0));
1243 a1 = sa0 + (b - (char *)PSXM(sa0));
1245 softCall(qscmpfunc);
1251 static inline void qexchange(char *i, char *j) {
1262 static inline void q3exchange(char *i, char *j, char *k) {
1274 static void qsort_main(char *a, char *l) {
1275 char *i, *j, *lp, *hp;
1280 if ((n = l - a) <= qswidth)
1282 n = qswidth * (n / (2 * qswidth));
1288 if ((c = qscmp(i, lp)) == 0) {
1289 qexchange(i, lp -= qswidth);
1300 if ((c = qscmp(hp, j)) == 0) {
1301 qexchange(hp += qswidth, j);
1306 q3exchange(i, hp += qswidth, j);
1320 if (lp - a >= l - hp) {
1321 qsort_main(hp + qswidth, l);
1330 q3exchange(j, lp -= qswidth, i);
1335 void psxBios_qsort() { // 0x31
1338 qsort_main((char *)Ra0, (char *)Ra0 + a1 * a2);
1343 static int malloc_heap_grow(u32 size) {
1344 u32 heap_addr, heap_end, heap_addr_new;
1346 heap_addr = loadRam32(A_HEAP_BASE);
1347 heap_end = loadRam32(A_HEAP_END);
1348 heap_addr_new = heap_addr + size + 4;
1349 if (heap_addr_new >= heap_end)
1351 storeRam32(A_HEAP_BASE, heap_addr_new);
1352 storeRam32(heap_addr - 4, size | 1);
1353 storeRam32(heap_addr + size, ~1); // terminator
1357 static void psxBios_malloc() { // 0x33
1358 u32 size = (a0 + 3) & ~3;
1359 u32 limit = 32*1024;
1363 PSXBIOS_LOG("psxBios_%s %d\n", biosA0n[0x33], a0);
1365 if (!loadRam32(A_HEAP_INIT_FLG)) {
1366 u32 heap_addr = loadRam32(A_HEAP_BASE);
1367 storeRam32(heap_addr, ~1);
1368 storeRam32(A_HEAP_FRSTCHNK, heap_addr);
1369 storeRam32(A_HEAP_CURCHNK, heap_addr);
1370 storeRam32(A_HEAP_BASE, heap_addr + 4);
1371 if (malloc_heap_grow(size)) {
1372 PSXBIOS_LOG("malloc: init OOM\n");
1373 mips_return_c(0, 20);
1376 storeRam32(A_HEAP_INIT_FLG, 1);
1379 for (i = 0; tries > 0 && i < limit; i++)
1381 u32 chunk = loadRam32(A_HEAP_CURCHNK);
1382 u32 chunk_hdr = loadRam32(chunk);
1383 u32 next_chunk = chunk + 4 + (chunk_hdr & ~3);
1384 u32 next_chunk_hdr = loadRam32(next_chunk);
1386 //printf(" c %08x %08x\n", chunk, chunk_hdr);
1387 if (chunk_hdr & 1) {
1389 if (chunk_hdr > (size | 1)) {
1391 u32 p2size = (chunk_hdr & ~3) - size - 4;
1392 storeRam32(chunk + 4 + size, p2size | 1);
1393 chunk_hdr = size | 1;
1395 if (chunk_hdr == (size | 1)) {
1396 storeRam32(chunk, size);
1400 if (next_chunk_hdr == ~1) {
1401 // rm useless last free block
1402 storeRam32(A_HEAP_BASE, chunk + 4);
1403 storeRam32(chunk, ~1);
1406 if (next_chunk_hdr & 1) {
1408 u32 msize = (chunk_hdr & ~3) + 4 + (next_chunk_hdr & ~3);
1409 storeRam32(chunk, msize | 1);
1413 if (chunk_hdr == ~1) {
1416 storeRam32(A_HEAP_CURCHNK, loadRam32(A_HEAP_FRSTCHNK));
1420 // go to the next chunk
1421 storeRam32(A_HEAP_CURCHNK, next_chunk);
1426 PSXBIOS_LOG("malloc: limit OOM\n");
1429 else if (tries == 0 && malloc_heap_grow(size)) {
1430 PSXBIOS_LOG("malloc: grow OOM s=%d end=%08x/%08x\n",
1431 size, loadRam32(A_HEAP_BASE), loadRam32(A_HEAP_END));
1435 u32 chunk = loadRam32(A_HEAP_CURCHNK);
1436 storeRam32(chunk, loadRam32(chunk) & ~3);
1440 PSXBIOS_LOG(" -> %08x\n", ret);
1441 mips_return_c(ret, 40);
1444 static void psxBios_free() { // 0x34
1445 PSXBIOS_LOG("psxBios_%s %x (%d bytes)\n", biosA0n[0x34], a0, loadRam32(a0 - 4));
1446 storeRam32(a0 - 4, loadRam32(a0 - 4) | 1); // set chunk to free
1447 mips_return_void_c(5);
1450 static void psxBios_calloc() { // 0x37
1452 PSXBIOS_LOG("psxBios_%s %x %x\n", biosA0n[0x37], a0, a1);
1454 a0 = size = a0 * a1;
1458 a0 = ret; a1 = size;
1461 mips_return_c(ret, 21);
1464 void psxBios_realloc() { // 0x38
1468 PSXBIOS_LOG("psxBios_%s %08x %d\n", biosA0n[0x38], a0, a1);
1471 /* If "old_buf" is zero, executes malloc(new_size), and returns r2=new_buf (or 0=failed). */
1476 /* Else, if "new_size" is zero, executes free(old_buf), and returns r2=garbage. */
1481 /* Else, executes malloc(new_size), bcopy(old_buf,new_buf,new_size), and free(old_buf), and returns r2=new_buf (or 0=failed). */
1482 /* Note that it is not quite implemented this way here. */
1492 /* InitHeap(void *block , int n) */
1493 static void psxBios_InitHeap() { // 0x39
1494 PSXBIOS_LOG("psxBios_%s %x %x\n", biosA0n[0x39], a0, a1);
1496 storeRam32(A_HEAP_BASE, a0);
1497 storeRam32(A_HEAP_SIZE, a1);
1498 storeRam32(A_HEAP_END, a0 + (a1 & ~3) + 4);
1499 storeRam32(A_HEAP_INIT_FLG, 0);
1502 mips_return_void_c(14);
1505 void psxBios_getchar() { //0x3b
1506 v0 = getchar(); pc0 = ra;
1509 static void psxBios_printf_psxout() { // 0x3f
1512 u32 save[4] = { 0, };
1518 if (psp != INVALID_PTR) {
1519 memcpy(save, psp, 4 * 4);
1520 psxMu32ref(sp) = SWAP32((u32)a0);
1521 psxMu32ref(sp + 4) = SWAP32((u32)a1);
1522 psxMu32ref(sp + 8) = SWAP32((u32)a2);
1523 psxMu32ref(sp + 12) = SWAP32((u32)a3);
1535 tmp2[j++] = Ra0[i]; goto _start;
1537 if (Ra0[i] >= '0' && Ra0[i] <= '9') {
1548 ptmp += sprintf(ptmp, tmp2, (float)psxMu32(sp + n * 4)); n++; break;
1552 ptmp += sprintf(ptmp, tmp2, (double)psxMu32(sp + n * 4)); n++; break;
1558 ptmp += sprintf(ptmp, tmp2, (unsigned int)psxMu32(sp + n * 4)); n++; break;
1560 ptmp += sprintf(ptmp, tmp2, (unsigned char)psxMu32(sp + n * 4)); n++; break;
1562 ptmp += sprintf(ptmp, tmp2, (char*)PSXM(psxMu32(sp + n * 4))); n++; break;
1564 *ptmp++ = Ra0[i]; break;
1574 if (psp != INVALID_PTR)
1575 memcpy(psp, save, 4 * 4);
1578 SysPrintf("%s", tmp);
1581 void psxBios_printf() { // 0x3f
1582 psxBios_printf_psxout();
1586 static void psxBios_cd() { // 0x40
1587 const char *p, *dir = Ra0;
1588 PSXBIOS_LOG("psxBios_%s %x(%s)\n", biosB0n[0x40], a0, dir);
1589 if (dir != INVALID_PTR) {
1590 if ((p = strchr(dir, ':')))
1594 snprintf(cdir, sizeof(cdir), "%s", dir);
1596 mips_return_c(1, 100);
1599 static void psxBios_format() { // 0x41
1600 PSXBIOS_LOG("psxBios_%s %x(%s)\n", biosB0n[0x41], a0, Ra0);
1601 if (strcmp(Ra0, "bu00:") == 0 && Config.Mcd1[0] != '\0')
1603 CreateMcd(Config.Mcd1);
1604 LoadMcd(1, Config.Mcd1);
1607 else if (strcmp(Ra0, "bu10:") == 0 && Config.Mcd2[0] != '\0')
1609 CreateMcd(Config.Mcd2);
1610 LoadMcd(2, Config.Mcd2);
1620 static void psxBios_SystemErrorUnresolvedException() {
1621 if (floodchk != 0x12340a40) { // prevent log flood
1622 SysPrintf("psxBios_%s called from %08x\n", biosA0n[0x40], ra);
1623 floodchk = 0x12340a40;
1625 mips_return_void_c(1000);
1628 static void FlushCache() {
1629 psxCpu->Notify(R3000ACPU_NOTIFY_CACHE_ISOLATED, NULL);
1630 psxCpu->Notify(R3000ACPU_NOTIFY_CACHE_UNISOLATED, NULL);
1632 // runs from uncached mem so tons of cycles
1636 // you likely want to mask irqs before calling these
1637 static u8 cdrom_sync(int do_ack)
1640 if (psxRegs.interrupt & (1u << PSXINT_CDR)) {
1641 if ((s32)(psxRegs.cycle - psxRegs.event_cycles[PSXINT_CDR]) < 0)
1642 psxRegs.cycle = psxRegs.event_cycles[PSXINT_CDR] + 1;
1643 irq_test(&psxRegs.CP0);
1647 r = cdrRead3() & 0x1f;
1648 cdrWrite3(0x5f); // ack; clear params
1653 static void cdrom_cmd_and_wait(u8 cmd, int arg_cnt, int resp_cnt, ...)
1659 va_start(ap, resp_cnt);
1660 while (arg_cnt-- > 0)
1661 cdrWrite2(va_arg(ap, u32));
1666 u8 r = cdrom_sync(1);
1667 assert(r == 3); (void)r;
1671 u8 r = cdrom_sync(1);
1672 assert(r == 2); (void)r;
1678 * long Load(char *name, struct EXEC *header);
1681 void psxBios_Load() { // 0x42
1682 u8 time[3] = { 2, 0, 0x16 };
1690 PSXBIOS_LOG("psxBios_%s %x(%s), %x\n", biosA0n[0x42], a0, pa0, a1);
1691 if (pa0 == INVALID_PTR || pa1 == INVALID_PTR) {
1695 if ((p = strchr(pa0, ':')))
1700 snprintf(path, sizeof(path), "%s\\%s", cdir, (char *)pa0);
1702 snprintf(path, sizeof(path), "%s", (char *)pa0);
1704 if (LoadCdromFile(path, &eheader, time) == 0) {
1705 memcpy(pa1, ((char*)&eheader)+16, sizeof(EXEC));
1706 psxCpu->Clear(a1, sizeof(EXEC) / 4);
1710 PSXBIOS_LOG(" -> %d\n", v0);
1714 // set the cdrom to a state of just after exe read
1715 psxRegs.CP0.n.SR &= ~0x404;
1718 cdrWrite2(0x1f); // unmask
1719 cdrom_cmd_and_wait(0x0e, 1, 1, 0x80u); // CdlSetmode
1720 cdrom_cmd_and_wait(0x02, 3, 1, time[0], time[1], time[2]); // CdlSetloc
1721 cdrom_cmd_and_wait(0x15, 0, 2); // CdlSeekL
1722 psxHwWrite16(0x1f801070, ~4);
1723 MTC0(&psxRegs, 12, psxRegs.CP0.n.SR | 0x404);
1727 * int Exec(struct EXEC *header , int argc , char **argv);
1730 void psxBios_Exec() { // 43
1731 EXEC *header = (EXEC *)castRam32ptr(a0);
1735 PSXBIOS_LOG("psxBios_%s: %x, %x, %x\n", biosA0n[0x43], a0, a1, a2);
1737 header->_sp = SWAP32(sp);
1738 header->_fp = SWAP32(fp);
1739 header->_sp = SWAP32(sp);
1740 header->_gp = SWAP32(gp);
1741 header->ret = SWAP32(ra);
1742 header->base = SWAP32(s0);
1744 ptr = SWAP32(header->b_addr);
1745 len = SWAP32(header->b_size);
1751 if (header->S_addr != 0)
1752 sp = fp = SWAP32(header->S_addr) + SWAP32(header->s_size);
1754 gp = SWAP32(header->gp0);
1762 pc0 = SWAP32(header->_pc0);
1765 static void psxBios_FlushCache() { // 44
1766 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x44]);
1771 void psxBios_GPU_dw() { // 0x46
1776 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x46]);
1779 GPU_writeData(0xa0000000);
1780 GPU_writeData((a1<<0x10)|(a0&0xffff));
1781 GPU_writeData((a3<<0x10)|(a2&0xffff));
1783 ptr = (u32*)PSXM(Rsp[4]); //that is correct?
1786 GPU_writeData(SWAPu32(*ptr++));
1792 static void gpu_sync() {
1793 // not implemented...
1794 // might be problematic to do because of Config.GpuListWalking
1795 if (psxRegs.interrupt & (1u << PSXINT_GPUDMA))
1796 log_unhandled("gpu_sync with active dma\n");
1797 mips_return_c(0, 21);
1800 void psxBios_mem2vram() { // 0x47
1802 gpuSyncPluginSR(); // flush
1803 GPU_writeData(0xa0000000);
1804 GPU_writeData((a1<<0x10)|(a0&0xffff));
1805 GPU_writeData((a3<<0x10)|(a2&0xffff));
1806 size = ((((a2 * a3) / 2) >> 4) << 16);
1807 GPU_writeStatus(0x04000002);
1808 psxHwWrite32(0x1f8010f4,0);
1809 psxHwWrite32(0x1f8010f0,psxHwRead32(0x1f8010f0)|0x800);
1810 psxHwWrite32(0x1f8010a0,Rsp[4]);//might have a buggy...
1811 psxHwWrite32(0x1f8010a4, size | 0x10);
1812 psxHwWrite32(0x1f8010a8,0x01000201);
1817 void psxBios_SendGPU() { // 0x48
1818 GPU_writeStatus(a0);
1823 void psxBios_GPU_cw() { // 0x49
1830 void psxBios_GPU_cwb() { // 0x4a
1831 u32 *ptr = (u32*)Ra0;
1836 GPU_writeData(SWAPu32(*ptr++));
1842 void psxBios_GPU_SendPackets() { //4b:
1844 GPU_writeStatus(0x04000002);
1845 psxHwWrite32(0x1f8010f4,0);
1846 psxHwWrite32(0x1f8010f0,psxHwRead32(0x1f8010f0)|0x800);
1847 psxHwWrite32(0x1f8010a0,a0);
1848 psxHwWrite32(0x1f8010a4,0);
1849 psxHwWrite32(0x1f8010a8,0x010000401);
1853 void psxBios_sys_a0_4c() { // 0x4c GPU relate
1854 psxHwWrite32(0x1f8010a8,0x00000401);
1855 GPU_writeData(0x0400000);
1856 GPU_writeData(0x0200000);
1857 GPU_writeData(0x0100000);
1862 void psxBios_GPU_GetGPUStatus() { // 0x4d
1863 v0 = GPU_readStatus();
1869 void psxBios_LoadExec() { // 51
1870 EXEC *header = (EXEC*)PSXM(0xf000);
1874 PSXBIOS_LOG("psxBios_%s: %s: %x,%x\n", biosA0n[0x51], Ra0, a1, a2);
1876 s_addr = a1; s_size = a2;
1881 header->S_addr = s_addr;
1882 header->s_size = s_size;
1884 a0 = 0xf000; a1 = 0; a2 = 0;
1888 static void psxBios__bu_init() { // 70
1889 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x70]);
1891 DeliverEvent(0xf0000011, 0x0004);
1892 DeliverEvent(0xf4000001, 0x0004);
1897 static void write_chain(u32 *d, u32 next, u32 handler1, u32 handler2);
1898 static void psxBios_SysEnqIntRP_(u32 priority, u32 chain_eptr);
1899 static void psxBios_SysDeqIntRP_(u32 priority, u32 chain_rm_eptr);
1901 static void psxBios_EnqueueCdIntr_(void)
1903 u32 *ram32 = (u32 *)psxM;
1905 // traps should already be installed by write_chain()
1906 ram32[0x91d0/4] = 0;
1907 ram32[0x91d4/4] = SWAP32(0xbfc0506c);
1908 ram32[0x91d8/4] = SWAP32(0xbfc04dec);
1909 psxBios_SysEnqIntRP_(0, 0x91d0);
1910 ram32[0x91e0/4] = 0;
1911 ram32[0x91e4/4] = SWAP32(0xbfc050a4);
1912 ram32[0x91e8/4] = SWAP32(0xbfc04fbc);
1913 psxBios_SysEnqIntRP_(0, 0x91e0);
1917 static void setup_cd_irq_and_events(void)
1919 u16 specs[] = { 0x10, 0x20, 0x40, 0x80, 0x8000 };
1922 psxBios_EnqueueCdIntr_();
1924 for (i = 0; i < sizeof(specs) / sizeof(specs[0]); i++) {
1925 u32 h = OpenEvent(0xf0000003, specs[i], EvMdMARK, 0);
1927 storeRam32(A_CD_EVENTS + i * 4, h);
1932 static void psxBios_CdReset_() {
1933 psxRegs.CP0.n.SR &= ~0x404; // disable interrupts
1937 cdrWrite2(0x1f); // unmask
1938 cdrom_cmd_and_wait(0x0a, 0, 2); // CdlReset
1939 cdrom_cmd_and_wait(0x0e, 1, 1, 0x80u); // CdlSetmode
1941 // todo(?): should read something (iso root directory?)
1942 // from { 0, 2, 16 } to somewhere and pause
1945 psxHwWrite16(0x1f801070, ~4);
1946 MTC0(&psxRegs, 12, psxRegs.CP0.n.SR | 0x404);
1947 DeliverEvent(0xf0000003, 0x0020);
1950 static void psxBios_CdInit() { // 54, 71
1951 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x71]);
1952 setup_cd_irq_and_events();
1956 // this function takes pretty much forever
1957 mips_return_c(0, 50000*11);
1960 static void psxBios_DequeueCdIntr_() {
1961 psxBios_SysDeqIntRP_(0, 0x91d0);
1962 psxBios_SysDeqIntRP_(0, 0x91e0);
1966 static void psxBios_CdReset() { // 95
1967 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x95]);
1971 static void psxBios_EnqueueCdIntr() { // a2
1972 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0xa2]);
1973 psxBios_EnqueueCdIntr_();
1974 // return value comes from SysEnqIntRP() insternal call
1977 static void psxBios_DequeueCdIntr() { // a3
1978 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0xa3]);
1979 psxBios_DequeueCdIntr_();
1982 static void psxBios_CdRemove() { // 56, 72
1983 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x72]);
1985 CloseEvent(loadRam32(A_CD_EVENTS + 0x00));
1986 CloseEvent(loadRam32(A_CD_EVENTS + 0x04));
1987 CloseEvent(loadRam32(A_CD_EVENTS + 0x08));
1988 CloseEvent(loadRam32(A_CD_EVENTS + 0x0c));
1989 CloseEvent(loadRam32(A_CD_EVENTS + 0x10));
1990 psxBios_DequeueCdIntr_();
1992 // EnterCriticalSection - should be done at the beginning,
1993 // but this way is much easier to implement
1999 static void setup_tt(u32 tcb_cnt, u32 evcb_cnt, u32 stack);
2001 static void psxBios_SetConf() { // 9c
2002 PSXBIOS_LOG("psxBios_%s %x %x %x\n", biosA0n[0x9c], a0, a1, a2);
2003 setup_tt(a1, a0, a2);
2004 psxRegs.CP0.n.SR |= 0x401;
2005 mips_return_void_c(500);
2008 static void psxBios_GetConf() { // 9d
2009 PSXBIOS_LOG("psxBios_%s %x %x %x\n", biosA0n[0x9d], a0, a1, a2);
2010 storeRam32(a0, loadRam32(A_CONF_EvCB));
2011 storeRam32(a1, loadRam32(A_CONF_TCB));
2012 storeRam32(a2, loadRam32(A_CONF_SP));
2013 mips_return_void_c(10);
2016 void psxBios_SetMem() { // 9f
2017 u32 new = psxHu32(0x1060);
2020 PSXBIOS_LOG("psxBios_%s: %x, %x\n", biosA0n[0x9f], a0, a1);
2025 psxHu32ref(0x1060) = SWAP32(new);
2026 psxMu32ref(0x060) = a0;
2027 PSXBIOS_LOG("Change effective memory : %d MBytes\n",a0);
2031 psxHu32ref(0x1060) = SWAP32(new | 0x300);
2032 psxMu32ref(0x060) = a0;
2033 PSXBIOS_LOG("Change effective memory : %d MBytes\n",a0);
2036 PSXBIOS_LOG("Effective memory must be 2/8 MBytes\n");
2043 /* TODO FIXME : Not compliant. -1 indicates failure but using 1 for now. */
2044 static void psxBios_get_cd_status() // a6
2046 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0xa6]);
2051 static void psxBios_GetSystemInfo() { // b4
2053 //PSXBIOS_LOG("psxBios_%s %x\n", biosA0n[0xb4], a0);
2054 SysPrintf("psxBios_%s %x\n", biosA0n[0xb4], a0);
2057 case 1: ret = SWAP32(((u32 *)psxR)[0x100/4 + a0]); break;
2058 case 2: ret = 0xbfc0012c; break;
2059 case 5: ret = loadRam32(0x60) << 10; break;
2061 mips_return_c(ret, 20);
2064 /* System calls B0 */
2066 static u32 psxBios_SysMalloc_(u32 size);
2068 static void psxBios_SysMalloc() { // B 00
2069 u32 ret = psxBios_SysMalloc_(a0);
2071 PSXBIOS_LOG("psxBios_%s 0x%x -> %x\n", biosB0n[0x00], a0, ret);
2072 mips_return_c(ret, 33);
2075 void psxBios_SetRCnt() { // 02
2077 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x02]);
2084 psxRcntWtarget(a0, a1);
2085 if (a2&0x1000) mode|= 0x050; // Interrupt Mode
2086 if (a2&0x0100) mode|= 0x008; // Count to 0xffff
2087 if (a2&0x0010) mode|= 0x001; // Timer stop mode
2088 if (a0 == 2) { if (a2&0x0001) mode|= 0x200; } // System Clock mode
2089 else { if (a2&0x0001) mode|= 0x100; } // System Clock mode
2091 psxRcntWmode(a0, mode);
2096 void psxBios_GetRCnt() { // 03
2098 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x03]);
2103 case 0: v0 = psxRcntRcount0(); break;
2104 case 1: v0 = psxRcntRcount1(); break;
2105 case 2: v0 = psxRcntRcount2(); break;
2106 case 3: v0 = 0; break;
2111 void psxBios_StartRCnt() { // 04
2113 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x04]);
2117 if (a0 != 3) psxHu32ref(0x1074)|= SWAP32((u32)((1<<(a0+4))));
2118 else psxHu32ref(0x1074)|= SWAPu32(0x1);
2122 void psxBios_StopRCnt() { // 05
2124 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x05]);
2128 if (a0 != 3) psxHu32ref(0x1074)&= SWAP32((u32)(~(1<<(a0+4))));
2129 else psxHu32ref(0x1074)&= SWAPu32(~0x1);
2133 void psxBios_ResetRCnt() { // 06
2135 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x06]);
2140 psxRcntWmode(a0, 0);
2141 psxRcntWtarget(a0, 0);
2142 psxRcntWcount(a0, 0);
2147 static u32 DeliverEvent(u32 class, u32 spec) {
2148 EvCB *ev, *ev_first = (EvCB *)loadRam32ptr(A_TT_EvCB);
2149 u32 evcb_len = loadRam32(A_TT_EvCB + 4);
2150 u32 ret = loadRam32(A_TT_EvCB) + evcb_len;
2151 u32 i, lim = evcb_len / 0x1c;
2153 //printf("%s %08x %x\n", __func__, class, spec);
2154 for (i = 0, ev = ev_first; i < lim; i++, ev++) {
2156 if (SWAP32(ev->status) != EvStACTIVE)
2159 if (SWAP32(ev->class) != class)
2162 if (SWAP32(ev->spec) != spec)
2165 ret = SWAP32(ev->mode);
2166 if (ret == EvMdMARK) {
2167 if (ev->status != SWAP32(EvStALREADY))
2168 PSXBIOS_EV_LOG("DeliverEvent %08x %x (%08zx) set\n",
2169 class, spec, (ev - ev_first) | 0xf1000000u);
2170 ev->status = SWAP32(EvStALREADY);
2174 if (ret == EvMdCALL) {
2175 ret = SWAP32(ev->fhandler);
2176 PSXBIOS_EV_LOG("DeliverEvent %08x %x (%08zx) cb %x\n",
2177 class, spec, (ev - ev_first) | 0xf1000000u, ret);
2190 static u32 UnDeliverEvent(u32 class, u32 spec) {
2191 EvCB *ev = (EvCB *)loadRam32ptr(A_TT_EvCB);
2192 u32 evcb_len = loadRam32(A_TT_EvCB + 4);
2193 u32 ret = loadRam32(A_TT_EvCB) + evcb_len;
2194 u32 i, lim = evcb_len / 0x1c;
2196 for (i = 0; i < lim; i++, ev++) {
2198 if (SWAP32(ev->status) != EvStALREADY)
2201 if (SWAP32(ev->class) != class)
2204 if (SWAP32(ev->spec) != spec)
2207 if (SWAP32(ev->mode) == EvMdMARK)
2208 ev->status = SWAP32(EvStACTIVE);
2214 static void psxBios_DeliverEvent() { // 07
2216 PSXBIOS_LOG("psxBios_%s %x %04x\n", biosB0n[0x07], a0, a1);
2218 ret = DeliverEvent(a0, a1);
2222 static s32 get_free_EvCB_slot() {
2223 EvCB *ev = (EvCB *)loadRam32ptr(A_TT_EvCB);
2224 u32 i, lim = loadRam32(A_TT_EvCB + 4) / 0x1c;
2227 for (i = 0; i < lim; i++, ev++) {
2229 if (ev->status == SWAP32(EvStUNUSED))
2235 static u32 OpenEvent(u32 class, u32 spec, u32 mode, u32 func) {
2236 u32 ret = get_free_EvCB_slot();
2237 if ((s32)ret >= 0) {
2238 EvCB *ev = (EvCB *)loadRam32ptr(A_TT_EvCB) + ret;
2239 ev->class = SWAP32(class);
2240 ev->status = SWAP32(EvStDISABLED);
2241 ev->spec = SWAP32(spec);
2242 ev->mode = SWAP32(mode);
2243 ev->fhandler = SWAP32(func);
2249 static void psxBios_OpenEvent() { // 08
2250 u32 ret = OpenEvent(a0, a1, a2, a3);
2251 PSXBIOS_LOG("psxBios_%s (class:%x, spec:%04x, mode:%04x, func:%x) -> %x\n",
2252 biosB0n[0x08], a0, a1, a2, a3, ret);
2253 mips_return_c(ret, 36);
2256 static void CloseEvent(u32 ev)
2258 u32 base = loadRam32(A_TT_EvCB);
2259 storeRam32(base + (ev & 0xffff) * sizeof(EvCB) + 4, EvStUNUSED);
2262 static void psxBios_CloseEvent() { // 09
2263 PSXBIOS_LOG("psxBios_%s %x (%x)\n", biosB0n[0x09], a0,
2264 loadRam32(loadRam32(A_TT_EvCB) + (a0 & 0xffff) * sizeof(EvCB) + 4));
2266 mips_return_c(1, 10);
2269 static void psxBios_WaitEvent() { // 0a
2270 u32 base = loadRam32(A_TT_EvCB);
2271 u32 status = loadRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4);
2272 PSXBIOS_LOG("psxBios_%s %x (status=%x)\n", biosB0n[0x0a], a0, status);
2275 if (status == EvStALREADY) {
2276 storeRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4, EvStACTIVE);
2280 if (status != EvStACTIVE)
2282 mips_return_c(0, 2);
2286 // retrigger this hlecall after the next emulation event
2288 if ((s32)(psxRegs.next_interupt - psxRegs.cycle) > 0)
2289 psxRegs.cycle = psxRegs.next_interupt;
2293 static void psxBios_TestEvent() { // 0b
2294 u32 base = loadRam32(A_TT_EvCB);
2295 u32 status = loadRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4);
2298 if (psxRegs.cycle - floodchk > 16*1024u) { // prevent log flood
2299 PSXBIOS_LOG("psxBios_%s %x %x\n", biosB0n[0x0b], a0, status);
2300 floodchk = psxRegs.cycle;
2302 if (status == EvStALREADY) {
2303 storeRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4, EvStACTIVE);
2307 mips_return_c(ret, 15);
2310 static void EnableEvent(u32 ev, int do_log) {
2311 u32 base = loadRam32(A_TT_EvCB);
2312 u32 status = loadRam32(base + (ev & 0xffff) * sizeof(EvCB) + 4);
2314 PSXBIOS_LOG("psxBios_%s %x (%x)\n", biosB0n[0x0c], ev, status);
2315 if (status != EvStUNUSED)
2316 storeRam32(base + (ev & 0xffff) * sizeof(EvCB) + 4, EvStACTIVE);
2319 static void psxBios_EnableEvent() { // 0c
2321 mips_return_c(1, 15);
2324 static void psxBios_DisableEvent() { // 0d
2325 u32 base = loadRam32(A_TT_EvCB);
2326 u32 status = loadRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4);
2327 PSXBIOS_LOG("psxBios_%s %x: %x\n", biosB0n[0x0d], a0, status);
2328 if (status != EvStUNUSED)
2329 storeRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4, EvStDISABLED);
2331 mips_return_c(1, 15);
2335 * long OpenTh(long (*func)(), unsigned long sp, unsigned long gp);
2338 void psxBios_OpenTh() { // 0e
2339 TCB *tcb = loadRam32ptr(A_TT_TCB);
2340 u32 limit = loadRam32(A_TT_TCB + 4) / 0xc0u;
2343 for (th = 1; th < limit; th++)
2345 if (tcb[th].status != SWAP32(0x4000)) break;
2349 // Feb 2019 - Added out-of-bounds fix caught by cppcheck:
2350 // When no free TCB is found, return 0xffffffff according to Nocash doc.
2352 PSXBIOS_LOG("\t%s() WARNING! No Free TCBs found!\n", __func__);
2354 mips_return_c(0xffffffff, 20);
2357 PSXBIOS_LOG("psxBios_%s -> %x\n", biosB0n[0x0e], 0xff000000 + th);
2359 tcb[th].status = SWAP32(0x4000);
2360 tcb[th].mode = SWAP32(0x1000);
2361 tcb[th].epc = SWAP32(a0);
2362 tcb[th].reg[30] = SWAP32(a1); // fp
2363 tcb[th].reg[29] = SWAP32(a1); // sp
2364 tcb[th].reg[28] = SWAP32(a2); // gp
2366 mips_return_c(0xff000000 + th, 34);
2370 * int CloseTh(long thread);
2373 static void psxBios_CloseTh() { // 0f
2374 u32 tcb = loadRam32(A_TT_TCB);
2375 u32 th = a0 & 0xffff;
2377 PSXBIOS_LOG("psxBios_%s %x\n", biosB0n[0x0f], a0);
2378 // in the usual bios fashion no checks, just write and return 1
2379 storeRam32(tcb + th * sizeof(TCB), 0x1000);
2381 mips_return_c(1, 11);
2385 * int ChangeTh(long thread);
2388 void psxBios_ChangeTh() { // 10
2389 u32 tcbBase = loadRam32(A_TT_TCB);
2390 u32 th = a0 & 0xffff;
2392 // this is quite spammy
2393 //PSXBIOS_LOG("psxBios_%s %x\n", biosB0n[0x10], th);
2395 // without doing any argument checks, just issue a syscall
2396 // (like the real bios does)
2398 a1 = tcbBase + th * sizeof(TCB);
2403 void psxBios_InitPAD() { // 0x12
2404 u32 i, *ram32 = (u32 *)psxM;
2405 PSXBIOS_LOG("psxBios_%s %x %x %x %x\n", biosB0n[0x12], a0, a1, a2, a3);
2407 // printf("%s", "PS-X Control PAD Driver Ver 3.0");
2408 ram32[A_PAD_DR_DST/4] = 0;
2409 ram32[A_PAD_OUTBUF/4 + 0] = 0;
2410 ram32[A_PAD_OUTBUF/4 + 1] = 0;
2411 ram32[A_PAD_OUT_LEN/4 + 0] = 0;
2412 ram32[A_PAD_OUT_LEN/4 + 1] = 0;
2413 ram32[A_PAD_INBUF/4 + 0] = SWAP32(a0);
2414 ram32[A_PAD_INBUF/4 + 1] = SWAP32(a2);
2415 ram32[A_PAD_IN_LEN/4 + 0] = SWAP32(a1);
2416 ram32[A_PAD_IN_LEN/4 + 1] = SWAP32(a3);
2418 for (i = 0; i < a1; i++) {
2420 storeRam8(a0 + i, 0);
2422 for (i = 0; i < a3; i++) {
2424 storeRam8(a2 + i, 0);
2426 write_chain(ram32 + A_PADCRD_CHN_E/4, 0, 0x49bc, 0x4a4c);
2428 ram32[A_PAD_IRQR_ENA/4] = SWAP32(1);
2430 mips_return_c(1, 200);
2433 void psxBios_StartPAD() { // 13
2434 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x13]);
2436 psxBios_SysDeqIntRP_(2, A_PADCRD_CHN_E);
2437 psxBios_SysEnqIntRP_(2, A_PADCRD_CHN_E);
2438 psxHwWrite16(0x1f801070, ~1);
2439 psxHwWrite16(0x1f801074, psxHu32(0x1074) | 1);
2440 storeRam32(A_PAD_ACK_VBL, 1);
2441 storeRam32(A_RCNT_VBL_ACK + (3 << 2), 0);
2442 psxRegs.CP0.n.SR |= 0x401;
2444 mips_return_c(1, 300);
2447 void psxBios_StopPAD() { // 14
2448 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x14]);
2449 storeRam32(A_RCNT_VBL_ACK + (3 << 2), 1);
2450 psxBios_SysDeqIntRP_(2, A_PADCRD_CHN_E);
2451 psxRegs.CP0.n.SR |= 0x401;
2452 mips_return_void_c(200);
2455 static void psxBios_PAD_init() { // 15
2457 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x15]);
2458 if (a0 == 0x20000000 || a0 == 0x20000001)
2461 a0 = A_PAD_DR_BUF1; a1 = 0x22;
2462 a2 = A_PAD_DR_BUF2; a3 = 0x22;
2465 storeRam32(A_PAD_DR_DST, dst);
2468 mips_return_c(ret, 100);
2471 static u32 psxBios_PAD_dr_() {
2472 u8 *dst = loadRam32ptr(A_PAD_DR_DST);
2473 u8 *buf1 = castRam8ptr(A_PAD_DR_BUF1);
2474 u8 *buf2 = castRam8ptr(A_PAD_DR_BUF2);
2475 dst[0] = dst[1] = dst[2] = dst[3] = ~0;
2476 if (buf1[0] == 0 && (buf1[1] == 0x23 || buf1[1] == 0x41))
2478 dst[0] = buf1[3], dst[1] = buf1[2];
2479 if (buf1[1] == 0x23) {
2480 dst[0] |= 0xc7, dst[1] |= 7;
2481 if (buf1[5] >= 0x10) dst[0] &= ~(1u << 6);
2482 if (buf1[6] >= 0x10) dst[0] &= ~(1u << 7);
2485 if (buf2[0] == 0 && (buf2[1] == 0x23 || buf2[1] == 0x41))
2487 dst[2] = buf2[3], dst[3] = buf2[2];
2488 if (buf2[1] == 0x23) {
2489 dst[2] |= 0xc7, dst[3] |= 7;
2490 if (buf2[5] >= 0x10) dst[2] &= ~(1u << 6);
2491 if (buf2[6] >= 0x10) dst[2] &= ~(1u << 7);
2495 return SWAP32(*(u32 *)dst);
2498 static void psxBios_PAD_dr() { // 16
2499 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x16]);
2500 u32 ret = psxBios_PAD_dr_();
2504 static void psxBios_ReturnFromException() { // 17
2505 u32 tcbPtr = loadRam32(A_TT_PCB);
2506 const TCB *tcb = loadRam32ptr(tcbPtr);
2510 for (i = 1; i < 32; i++)
2511 psxRegs.GPR.r[i] = SWAP32(tcb->reg[i]);
2512 psxRegs.GPR.n.lo = SWAP32(tcb->lo);
2513 psxRegs.GPR.n.hi = SWAP32(tcb->hi);
2514 sr = SWAP32(tcb->sr);
2516 //printf("%s %08x->%08x %u\n", __func__, pc0, tcb->epc, psxRegs.cycle);
2517 pc0 = k0 = SWAP32(tcb->epc);
2519 // the interpreter wants to know about sr changes, so do a MTC0
2520 sr = (sr & ~0x0f) | ((sr & 0x3c) >> 2);
2521 MTC0(&psxRegs, 12, sr);
2527 void psxBios_ResetEntryInt() { // 18
2528 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x18]);
2530 storeRam32(A_EEXIT_PTR, A_EEXIT_DEF);
2531 mips_return_void_c(5);
2534 void psxBios_HookEntryInt() { // 19
2535 PSXBIOS_LOG("psxBios_%s %x\n", biosB0n[0x19], a0);
2537 storeRam32(A_EEXIT_PTR, a0);
2538 mips_return_void_c(3);
2541 static void psxBios_UnDeliverEvent() { // 0x20
2543 PSXBIOS_LOG("psxBios_%s %x %x\n", biosB0n[0x20], a0, a1);
2545 ret = UnDeliverEvent(a0, a1);
2549 static void buopen(int mcd, char *ptr, char *cfg)
2552 char *mcd_data = ptr;
2554 strcpy(FDesc[1 + mcd].name, Ra0+5);
2555 FDesc[1 + mcd].offset = 0;
2556 FDesc[1 + mcd].mode = a1;
2558 for (i=1; i<16; i++) {
2559 const char *fptr = mcd_data + 128 * i;
2560 if ((*fptr & 0xF0) != 0x50) continue;
2561 if (strcmp(FDesc[1 + mcd].name, fptr+0xa)) continue;
2562 FDesc[1 + mcd].mcfile = i;
2564 PSXBIOS_LOG("open %s -> %d\n", fptr+0xa, v0);
2567 if (a1 & 0x200 && v0 == -1) { /* FCREAT */
2568 for (i=1; i<16; i++) {
2569 int j, xor, nblk = a1 >> 16;
2571 char *fptr = mcd_data + 128 * i;
2573 if ((*fptr & 0xF0) != 0xa0) continue;
2575 FDesc[1 + mcd].mcfile = i;
2578 fptr[5] = 0x20 * nblk;
2581 strcpy(fptr+0xa, FDesc[1 + mcd].name);
2582 pptr = fptr2 = fptr;
2583 for(j=2; j<=nblk; j++) {
2585 for(i++; i<16; i++) {
2588 memset(fptr2, 0, 128);
2589 fptr2[0] = j < nblk ? 0x52 : 0x53;
2592 for (k=0, xor=0; k<127; k++) xor^= pptr[k];
2597 /* shouldn't this return ENOSPC if i == 16? */
2599 pptr[8] = pptr[9] = 0xff;
2600 for (j=0, xor=0; j<127; j++) xor^= pptr[j];
2602 PSXBIOS_LOG("openC %s %d\n", ptr, nblk);
2604 /* just go ahead and resave them all */
2605 SaveMcd(cfg, ptr, 128, 128 * 15);
2608 /* shouldn't this return ENOSPC if i == 16? */
2613 * int open(char *name , int mode);
2616 void psxBios_open() { // 0x32
2619 PSXBIOS_LOG("psxBios_%s %s(%x) %x\n", biosB0n[0x32], Ra0, a0, a1);
2623 if (pa0 != INVALID_PTR) {
2624 if (!strncmp(pa0, "bu00", 4)) {
2625 buopen(1, Mcd1Data, Config.Mcd1);
2628 if (!strncmp(pa0, "bu10", 4)) {
2629 buopen(2, Mcd2Data, Config.Mcd2);
2637 * int lseek(int fd , int offset , int whence);
2640 void psxBios_lseek() { // 0x33
2642 PSXBIOS_LOG("psxBios_%s: %x, %x, %x\n", biosB0n[0x33], a0, a1, a2);
2647 FDesc[a0].offset = a1;
2649 // DeliverEvent(0xf0000011, 0x0004);
2650 // DeliverEvent(0xf4000001, 0x0004);
2654 FDesc[a0].offset+= a1;
2655 v0 = FDesc[a0].offset;
2664 * int read(int fd , void *buf , int nbytes);
2667 static void psxBios_read() { // 0x34
2671 PSXBIOS_LOG("psxBios_%s: %x, %x, %x\n", biosB0n[0x34], a0, a1, a2);
2673 if (pa1 == INVALID_PTR)
2675 else if (a0 == 2 || a0 == 3)
2676 ret = card_buf_io(0, a0 - 2, pa1, a2);
2678 mips_return_c(ret, 100);
2682 * int write(int fd , void *buf , int nbytes);
2685 static void psxBios_write() { // 0x35/0x03
2689 if (a0 != 1) // not stdout
2690 PSXBIOS_LOG("psxBios_%s: %x,%x,%x\n", biosB0n[0x35], a0, a1, a2);
2692 if (pa1 == INVALID_PTR)
2694 else if (a0 == 1) { // stdout
2698 if (Config.PsxOut) while (a2 > 0) {
2699 SysPrintf("%c", *ptr++); a2--;
2703 else if (a0 == 2 || a0 == 3)
2704 ret = card_buf_io(1, a0 - 2, pa1, a2);
2706 mips_return_c(ret, 100);
2709 static void psxBios_write_psxout() {
2710 if (a0 == 1) { // stdout
2711 const char *ptr = Ra1;
2714 if (ptr != INVALID_PTR)
2716 SysPrintf("%c", *ptr++);
2720 static void psxBios_putchar_psxout() { // 3d
2721 SysPrintf("%c", (char)a0);
2724 static void psxBios_puts_psxout() { // 3e/3f
2725 SysPrintf("%s", Ra0);
2729 * int close(int fd);
2732 void psxBios_close() { // 0x36
2734 PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x36], a0);
2741 void psxBios_putchar() { // 3d
2742 if (Config.PsxOut) SysPrintf("%c", (char)a0);
2746 void psxBios_puts() { // 3e/3f
2747 if (Config.PsxOut) SysPrintf("%s", Ra0);
2751 static void bufile(const u8 *mcd_data, u32 dir_) {
2752 struct DIRENTRY *dir = (struct DIRENTRY *)PSXM(dir_);
2753 const char *pfile = ffile + 5;
2754 const u8 *data = mcd_data;
2755 int i = 0, match = 0;
2760 if (dir == INVALID_PTR)
2763 for (; nfile <= 15 && !match; nfile++) {
2766 head = nfile * 0x40;
2767 data = mcd_data + 128 * nfile;
2768 name = (const char *)data + 0x0a;
2769 if ((data[0] & 0xF0) != 0x50) continue;
2770 /* Bug link files show up as free block. */
2771 if (!name[0]) continue;
2773 for (i = 0; i < 20; i++) {
2774 if (pfile[i] == name[i] || pfile[i] == '?')
2775 dir->name[i] = name[i];
2776 else if (pfile[i] == '*') {
2777 int len = strlen(name + i);
2780 memcpy(dir->name + i, name + i, len + 1);
2791 PSXBIOS_LOG("%d : %s = %s + %s (match=%d)\n",
2792 nfile, dir->name, pfile, name, match);
2794 for (; nfile <= 15; nfile++, blocks++) {
2795 const u8 *data2 = mcd_data + 128 * nfile;
2796 const char *name = (const char *)data2 + 0x0a;
2797 if ((data2[0] & 0xF0) != 0x50 || name[0])
2801 // nul char of full lenth name seems to overwrite .attr
2802 dir->attr = SWAP32(i < 20 ? data[0] & 0xf0 : 0); // ?
2803 dir->size = 8192 * blocks;
2807 PSXBIOS_LOG(" -> %x '%s' %x %x %x %x\n", v0, v0 ? dir->name : "",
2808 dir->attr, dir->size, dir->next, dir->head);
2812 * struct DIRENTRY* firstfile(char *name,struct DIRENTRY *dir);
2815 static void psxBios_firstfile() { // 42
2818 PSXBIOS_LOG("psxBios_%s %s %x\n", biosB0n[0x42], pa0, a1);
2821 if (pa0 != INVALID_PTR)
2823 snprintf(ffile, sizeof(ffile), "%s", pa0);
2825 strcpy(ffile + 5, "*"); // maybe?
2827 if (!strncmp(pa0, "bu00", 4)) {
2828 // firstfile() calls _card_read() internally, so deliver it's event
2829 DeliverEvent(0xf0000011, 0x0004);
2830 bufile((u8 *)Mcd1Data, a1);
2831 } else if (!strncmp(pa0, "bu10", 4)) {
2832 // firstfile() calls _card_read() internally, so deliver it's event
2833 DeliverEvent(0xf0000011, 0x0004);
2834 bufile((u8 *)Mcd2Data, a1);
2842 * struct DIRENTRY* nextfile(struct DIRENTRY *dir);
2845 void psxBios_nextfile() { // 43
2846 PSXBIOS_LOG("psxBios_%s %x\n", biosB0n[0x43], a0);
2849 if (!strncmp(ffile, "bu00", 4))
2850 bufile((u8 *)Mcd1Data, a0);
2851 else if (!strncmp(ffile, "bu10", 4))
2852 bufile((u8 *)Mcd2Data, a0);
2857 #define burename(mcd) { \
2858 for (i=1; i<16; i++) { \
2859 int namelen, j, xor = 0; \
2860 ptr = Mcd##mcd##Data + 128 * i; \
2861 if ((*ptr & 0xF0) != 0x50) continue; \
2862 if (strcmp(Ra0+5, ptr+0xa)) continue; \
2863 namelen = strlen(Ra1+5); \
2864 memcpy(ptr+0xa, Ra1+5, namelen); \
2865 memset(ptr+0xa+namelen, 0, 0x75-namelen); \
2866 for (j=0; j<127; j++) xor^= ptr[j]; \
2868 SaveMcd(Config.Mcd##mcd, Mcd##mcd##Data, 128 * i + 0xa, 0x76); \
2875 * int rename(char *old, char *new);
2878 void psxBios_rename() { // 44
2885 PSXBIOS_LOG("psxBios_%s: %s,%s\n", biosB0n[0x44], Ra0, Ra1);
2890 if (pa0 != INVALID_PTR && pa1 != INVALID_PTR) {
2891 if (!strncmp(pa0, "bu00", 4) && !strncmp(pa1, "bu00", 4)) {
2895 if (!strncmp(pa0, "bu10", 4) && !strncmp(pa1, "bu10", 4)) {
2904 #define budelete(mcd) { \
2905 for (i=1; i<16; i++) { \
2906 ptr = Mcd##mcd##Data + 128 * i; \
2907 if ((*ptr & 0xF0) != 0x50) continue; \
2908 if (strcmp(Ra0+5, ptr+0xa)) continue; \
2909 *ptr = (*ptr & 0xf) | 0xA0; \
2910 SaveMcd(Config.Mcd##mcd, Mcd##mcd##Data, 128 * i, 1); \
2911 PSXBIOS_LOG("delete %s\n", ptr+0xa); \
2918 * int delete(char *name);
2921 void psxBios_delete() { // 45
2927 PSXBIOS_LOG("psxBios_%s: %s\n", biosB0n[0x45], Ra0);
2932 if (pa0 != INVALID_PTR) {
2933 if (!strncmp(pa0, "bu00", 4)) {
2937 if (!strncmp(pa0, "bu10", 4)) {
2945 void psxBios_InitCARD() { // 4a
2946 u8 *ram8 = (u8 *)psxM;
2947 u32 *ram32 = (u32 *)psxM;
2948 PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x4a], a0);
2949 write_chain(ram32 + A_PADCRD_CHN_E/4, 0, 0x49bc, 0x4a4c);
2951 ram8[A_CARD_ISLOT] = 0;
2952 ram8[A_CARD_STATUS1] = 1;
2953 ram8[A_CARD_STATUS2] = 1;
2954 // (maybe) todo: early_card_irq, etc
2956 ram32[A_PAD_IRQR_ENA/4] = SWAP32(a0);
2958 psxBios_FlushCache();
2959 mips_return_c(0, 34+13+15+6);
2962 void psxBios_StartCARD() { // 4b
2963 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x4b]);
2964 psxBios_SysDeqIntRP_(2, A_PADCRD_CHN_E);
2965 psxBios_SysEnqIntRP_(2, A_PADCRD_CHN_E);
2967 psxHwWrite16(0x1f801074, psxHu32(0x1074) | 1);
2968 storeRam32(A_PAD_ACK_VBL, 1);
2969 storeRam32(A_RCNT_VBL_ACK + (3 << 2), 0);
2970 storeRam32(A_CARD_IRQR_ENA, 1);
2971 psxRegs.CP0.n.SR |= 0x401;
2973 mips_return_c(1, 200);
2976 void psxBios_StopCARD() { // 4c
2977 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x4c]);
2978 storeRam32(A_RCNT_VBL_ACK + (3 << 2), 1);
2979 psxBios_SysDeqIntRP_(2, A_PADCRD_CHN_E);
2980 storeRam32(A_CARD_IRQR_ENA, 0);
2981 psxRegs.CP0.n.SR |= 0x401;
2982 mips_return_void_c(200);
2985 void psxBios__card_write() { // 0x4e
2989 PSXBIOS_LOG("psxBios_%s %02x,%x,%x\n", biosB0n[0x4e], a0, a1, a2);
2990 // function also accepts sector 400h (a bug),
2991 // but what actually happens then?
2994 /* Invalid sectors */
2998 storeRam32(A_CARD_ACHAN, a0);
3001 if (pa2 != INVALID_PTR && a1 < 0x400) {
3003 memcpy(Mcd1Data + a1 * 128, pa2, 128);
3004 SaveMcd(Config.Mcd1, Mcd1Data, a1 * 128, 128);
3006 memcpy(Mcd2Data + a1 * 128, pa2, 128);
3007 SaveMcd(Config.Mcd2, Mcd2Data, a1 * 128, 128);
3011 storeRam8(A_CARD_STATUS1 + port, 4); // busy/write
3012 storeRam32(A_CARD_HANDLER, CARD_HARDLER_WRITE);
3017 static void psxBios__card_read() { // 0x4f
3021 PSXBIOS_LOG("psxBios_%s %x,%x,%x\n", biosB0n[0x4f], a0, a1, a2);
3024 /* Invalid sectors */
3028 storeRam32(A_CARD_ACHAN, a0);
3031 if (pa2 != INVALID_PTR && a1 < 0x400) {
3033 memcpy(pa2, Mcd1Data + a1 * 128, 128);
3035 memcpy(pa2, Mcd2Data + a1 * 128, 128);
3039 storeRam8(A_CARD_STATUS1 + port, 2); // busy/read
3040 storeRam32(A_CARD_HANDLER, CARD_HARDLER_READ);
3045 void psxBios__new_card() { // 0x50
3047 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x50]);
3053 /* According to a user, this allows Final Fantasy Tactics to save/load properly */
3054 void psxBios__get_error(void) // 55
3056 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x55]);
3061 void psxBios_Krom2RawAdd() { // 0x51
3064 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x51]);
3065 const u32 table_8140[][2] = {
3066 {0x8140, 0x0000}, {0x8180, 0x0762}, {0x81ad, 0x0cc6}, {0x81b8, 0x0ca8},
3067 {0x81c0, 0x0f00}, {0x81c8, 0x0d98}, {0x81cf, 0x10c2}, {0x81da, 0x0e6a},
3068 {0x81e9, 0x13ce}, {0x81f0, 0x102c}, {0x81f8, 0x1590}, {0x81fc, 0x111c},
3069 {0x81fd, 0x1626}, {0x824f, 0x113a}, {0x8259, 0x20ee}, {0x8260, 0x1266},
3070 {0x827a, 0x24cc}, {0x8281, 0x1572}, {0x829b, 0x28aa}, {0x829f, 0x187e},
3071 {0x82f2, 0x32dc}, {0x8340, 0x2238}, {0x837f, 0x4362}, {0x8380, 0x299a},
3072 {0x8397, 0x4632}, {0x839f, 0x2c4c}, {0x83b7, 0x49f2}, {0x83bf, 0x2f1c},
3073 {0x83d7, 0x4db2}, {0x8440, 0x31ec}, {0x8461, 0x5dde}, {0x8470, 0x35ca},
3074 {0x847f, 0x6162}, {0x8480, 0x378c}, {0x8492, 0x639c}, {0x849f, 0x39a8},
3078 const u32 table_889f[][2] = {
3079 {0x889f, 0x3d68}, {0x8900, 0x40ec}, {0x897f, 0x4fb0}, {0x8a00, 0x56f4},
3080 {0x8a7f, 0x65b8}, {0x8b00, 0x6cfc}, {0x8b7f, 0x7bc0}, {0x8c00, 0x8304},
3081 {0x8c7f, 0x91c8}, {0x8d00, 0x990c}, {0x8d7f, 0xa7d0}, {0x8e00, 0xaf14},
3082 {0x8e7f, 0xbdd8}, {0x8f00, 0xc51c}, {0x8f7f, 0xd3e0}, {0x9000, 0xdb24},
3083 {0x907f, 0xe9e8}, {0x9100, 0xf12c}, {0x917f, 0xfff0}, {0x9200, 0x10734},
3084 {0x927f, 0x115f8}, {0x9300, 0x11d3c}, {0x937f, 0x12c00}, {0x9400, 0x13344},
3085 {0x947f, 0x14208}, {0x9500, 0x1494c}, {0x957f, 0x15810}, {0x9600, 0x15f54},
3086 {0x967f, 0x16e18}, {0x9700, 0x1755c}, {0x977f, 0x18420}, {0x9800, 0x18b64},
3090 if (a0 >= 0x8140 && a0 <= 0x84be) {
3091 while (table_8140[i][0] <= a0) i++;
3092 a0 -= table_8140[i - 1][0];
3093 v0 = 0xbfc66000 + (a0 * 0x1e + table_8140[i - 1][1]);
3094 } else if (a0 >= 0x889f && a0 <= 0x9872) {
3095 while (table_889f[i][0] <= a0) i++;
3096 a0 -= table_889f[i - 1][0];
3097 v0 = 0xbfc66000 + (a0 * 0x1e + table_889f[i - 1][1]);
3105 void psxBios_GetC0Table() { // 56
3106 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x56]);
3107 log_unhandled("GetC0Table @%08x\n", ra);
3109 mips_return_c(A_C0_TABLE, 3);
3112 void psxBios_GetB0Table() { // 57
3113 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x57]);
3114 log_unhandled("GetB0Table @%08x\n", ra);
3116 mips_return_c(A_B0_TABLE, 3);
3119 static void psxBios__card_chan() { // 0x58
3120 // todo: should return active slot channel
3121 // (active - which was last processed by irq code)
3122 u32 ret = loadRam32(A_CARD_ACHAN);
3123 PSXBIOS_LOG("psxBios_%s -> %02x\n", biosB0n[0x58], ret);
3125 mips_return_c(ret, 8);
3128 static void psxBios_ChangeClearPad() { // 5b
3130 PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x5b], a0);
3131 ret = loadRam32(A_PAD_ACK_VBL);
3132 storeRam32(A_PAD_ACK_VBL, a0);
3134 mips_return_c(ret, 6);
3137 static void psxBios__card_status() { // 5c
3138 u8 s = loadRam8(A_CARD_STATUS1 + a0);
3139 PSXBIOS_LOG("psxBios_%s %x -> %x\n", biosB0n[0x5c], a0, s);
3141 mips_return_c(s, 5);
3144 static void psxBios__card_wait() { // 5d
3145 u8 s = loadRam8(A_CARD_STATUS1 + a0);
3146 PSXBIOS_LOG("psxBios_%s %x -> %x\n", biosB0n[0x5d], a0, s);
3150 log_unhandled("%s %x\n", __func__, s);
3152 mips_return_c(s, 11);
3155 static void psxBios__card_info() { // A ab
3156 PSXBIOS_LOG("psxBios_%s %02x\n", biosA0n[0xab], a0);
3158 storeRam32(A_CARD_ACHAN, a0);
3165 if (McdDisable[port & 1])
3169 PSXBIOS_LOG("psxBios_%s: UNKNOWN PORT 0x%x\n", biosA0n[0xab], a0);
3174 if (McdDisable[0] && McdDisable[1])
3178 // deliver from card_vint_handler()
3179 storeRam8(A_CARD_STATUS1 + port, 8); // busy/info
3180 storeRam32(A_CARD_HANDLER, CARD_HARDLER_INFO);
3182 DeliverEvent(0xf4000001, ret);
3183 DeliverEvent(0xf0000011, 0x0004); // ?
3188 static void psxBios__card_load() { // A ac
3189 PSXBIOS_LOG("psxBios_%s %02x\n", biosA0n[0xac], a0);
3191 storeRam32(A_CARD_ACHAN, a0);
3193 // DeliverEvent(0xf0000011, 0x0004);
3194 DeliverEvent(0xf4000001, 0x0004);
3199 static void card_vint_handler(void) {
3203 if (card_io_delay) {
3207 UnDeliverEvent(0xf0000011, 0x0004);
3208 UnDeliverEvent(0xf0000011, 0x8000);
3209 UnDeliverEvent(0xf0000011, 0x0100);
3210 UnDeliverEvent(0xf0000011, 0x0200);
3211 UnDeliverEvent(0xf0000011, 0x2000);
3214 select = loadRam8(A_CARD_ISLOT);
3215 select = (select ^ 1) & 1;
3216 storeRam8(A_CARD_ISLOT, select);
3218 select = loadRam8(A_CARD_ACHAN) >> 4;
3219 storeRam8(A_CARD_ISLOT, select);
3221 status = loadRam8(A_CARD_STATUS1 + select);
3225 //psxBios_SysDeqIntRP_(0, 0x7540);
3226 //psxBios_SysDeqIntRP_(0, 0x7540);
3227 //card_state_machine = 0;
3228 //card_error_flag = 0;
3229 handler = loadRam32(A_CARD_HANDLER);
3231 case CARD_HARDLER_INFO:
3232 DeliverEvent(0xf4000001, 4);
3233 DeliverEvent(0xf0000011, 4);
3234 storeRam8(A_CARD_STATUS1 + select, 1);
3235 storeRam32(A_CARD_HANDLER, 0);
3237 case CARD_HARDLER_WRITEM:
3238 case CARD_HARDLER_READM:
3239 DeliverEvent(0xf4000001, 4);
3241 case CARD_HARDLER_WRITE:
3242 case CARD_HARDLER_READ:
3243 DeliverEvent(0xf0000011, 4);
3244 storeRam8(A_CARD_STATUS1 + select, 1);
3245 storeRam32(A_CARD_HANDLER, 0);
3250 log_unhandled("%s: unhandled handler %x\n", __func__, handler);
3251 DeliverEvent(0xf0000011, 0x8000);
3252 storeRam8(A_CARD_STATUS1 + select, 1);
3253 storeRam32(A_CARD_HANDLER, 0);
3257 /* System calls C0 */
3259 static void psxBios_InitRCnt() { // 00
3261 PSXBIOS_LOG("psxBios_%s %x\n", biosC0n[0x00], a0);
3262 psxHwWrite16(0x1f801074, psxHu32(0x1074) & ~0x71);
3263 for (i = 0; i < 3; i++) {
3264 psxHwWrite16(0x1f801100 + i*0x10 + 4, 0);
3265 psxHwWrite16(0x1f801100 + i*0x10 + 8, 0);
3266 psxHwWrite16(0x1f801100 + i*0x10 + 0, 0);
3268 for (i = 0; i < 4; i++)
3269 psxBios_SysEnqIntRP_(a0, 0x6d58 + i * 0x10);
3270 mips_return_c(0, 9);
3273 static void psxBios_InitException() { // 01
3274 PSXBIOS_LOG("psxBios_%s %x\n", biosC0n[0x01], a0);
3275 psxBios_SysEnqIntRP_(a0, 0x6da8);
3276 mips_return_c(0, 9);
3280 * int SysEnqIntRP(int index , long *queue);
3283 static void psxBios_SysEnqIntRP_(u32 priority, u32 chain_eptr) {
3284 u32 old, base = loadRam32(A_TT_ExCB);
3286 old = loadRam32(base + (priority << 3));
3287 storeRam32(base + (priority << 3), chain_eptr);
3288 storeRam32(chain_eptr, old);
3289 mips_return_c(0, 9);
3292 static void psxBios_SysEnqIntRP() { // 02
3293 PSXBIOS_LOG("psxBios_%s %x %x\n", biosC0n[0x02], a0, a1);
3294 psxBios_SysEnqIntRP_(a0, a1);
3298 * int SysDeqIntRP(int index , long *queue);
3301 static void psxBios_SysDeqIntRP_(u32 priority, u32 chain_rm_eptr) {
3302 u32 ptr, next, base = loadRam32(A_TT_ExCB);
3303 u32 lim = 0, ret = 0;
3305 // as in original: no arg checks of any kind, bug if a1 == 0
3306 ptr = loadRam32(base + (priority << 3));
3308 next = loadRam32(ptr);
3309 if (ptr == chain_rm_eptr) {
3310 storeRam32(base + (priority << 3), next);
3315 while (next && next != chain_rm_eptr && lim++ < 100) {
3317 next = loadRam32(ptr);
3320 if (next == chain_rm_eptr) {
3321 next = loadRam32(next);
3322 storeRam32(ptr, next);
3329 PSXBIOS_LOG("bad chain %u %x\n", priority, base);
3331 mips_return_c(ret, 12);
3334 static void psxBios_SysDeqIntRP() { // 03
3335 PSXBIOS_LOG("psxBios_%s %x %x\n", biosC0n[0x03], a0, a1);
3336 psxBios_SysDeqIntRP_(a0, a1);
3339 static void psxBios_get_free_EvCB_slot() { // 04
3340 PSXBIOS_LOG("psxBios_%s\n", biosC0n[0x04]);
3341 s32 ret = get_free_EvCB_slot();
3342 mips_return_c(ret, 0);
3345 static void psxBios_SysInitMemory_(u32 base, u32 size) {
3346 storeRam32(base, 0);
3347 storeRam32(A_KMALLOC_PTR, base);
3348 storeRam32(A_KMALLOC_SIZE, size);
3349 storeRam32(A_KMALLOC_END, base + (size & ~3) + 4);
3352 // this should be much more complicated, but maybe that'll be enough
3353 static u32 psxBios_SysMalloc_(u32 size) {
3354 u32 ptr = loadRam32(A_KMALLOC_PTR);
3356 size = (size + 3) & ~3;
3357 storeRam32(A_KMALLOC_PTR, ptr + 4 + size);
3358 storeRam32(ptr, size);
3362 static void psxBios_SysInitMemory() { // 08
3363 PSXBIOS_LOG("psxBios_%s %x %x\n", biosC0n[0x08], a0, a1);
3365 psxBios_SysInitMemory_(a0, a1);
3366 mips_return_void_c(12);
3369 static void psxBios_ChangeClearRCnt() { // 0a
3372 PSXBIOS_LOG("psxBios_%s: %x, %x\n", biosC0n[0x0a], a0, a1);
3374 ret = loadRam32(A_RCNT_VBL_ACK + (a0 << 2));
3375 storeRam32(A_RCNT_VBL_ACK + (a0 << 2), a1);
3376 mips_return_c(ret, 8);
3379 static void psxBios_InitDefInt() { // 0c
3380 PSXBIOS_LOG("psxBios_%s %x\n", biosC0n[0x0c], a0);
3381 // should also clear the autoack table
3382 psxBios_SysEnqIntRP_(a0, 0x6d98);
3383 mips_return_c(0, 20 + 6*2);
3386 void psxBios_dummy() {
3387 u32 pc = (pc0 & 0x1fffff) - 4;
3388 char **ntab = pc == 0xa0 ? biosA0n : pc == 0xb0 ? biosB0n
3389 : pc == 0xc0 ? biosC0n : NULL;
3390 PSXBIOS_LOG("unk %x call: %x ra=%x (%s)\n",
3391 pc, t1, ra, ntab ? ntab[t1 & 0xff] : "???");
3392 (void)pc; (void)ntab;
3393 mips_return_c(0, 100);
3396 void (*biosA0[256])();
3397 // C0 and B0 overlap (end of C0 is start of B0)
3398 void (*biosC0[256+128])();
3399 void (**biosB0)() = biosC0 + 128;
3401 static void setup_mips_code()
3404 ptr = (u32 *)&psxM[A_SYSCALL];
3405 ptr[0x00/4] = SWAPu32(0x0000000c); // syscall 0
3406 ptr[0x04/4] = SWAPu32(0x03e00008); // jr $ra
3407 ptr[0x08/4] = SWAPu32(0x00000000); // nop
3409 ptr = (u32 *)&psxM[A_EXCEPTION];
3410 memset(ptr, 0, 0xc0); // nops (to be patched by games sometimes)
3411 ptr[0x10/4] = SWAPu32(0x8c1a0108); // lw $k0, (0x108) // PCB
3412 ptr[0x14/4] = SWAPu32(0x00000000); // nop
3413 ptr[0x18/4] = SWAPu32(0x8f5a0000); // lw $k0, ($k0) // TCB
3414 ptr[0x1c/4] = SWAPu32(0x00000000); // nop
3415 ptr[0x20/4] = SWAPu32(0x275a0008); // addiu $k0, $k0, 8 // regs
3416 ptr[0x24/4] = SWAPu32(0xaf5f007c); // sw $ra, 0x7c($k0)
3417 ptr[0x28/4] = SWAPu32(0xaf410004); // sw $at, 0x04($k0)
3418 ptr[0x2c/4] = SWAPu32(0xaf420008); // sw $v0, 0x08($k0)
3419 ptr[0x30/4] = SWAPu32(0xaf43000c); // sw $v1, 0x0c($k0)
3421 ptr[0x60/4] = SWAPu32(0x40037000); // mfc0 $v1, EPC
3422 ptr[0x64/4] = SWAPu32(0x40026800); // mfc0 $v0, Cause
3423 ptr[0x6c/4] = SWAPu32(0xaf430080); // sw $v1, 0x80($k0)
3425 ptr[0xb0/4] = HLEOP(hleop_exception);
3428 static const struct {
3432 { 0xbfc050a4, hleop_exc0_0_1 },
3433 { 0xbfc04fbc, hleop_exc0_0_2 },
3434 { 0xbfc0506c, hleop_exc0_1_1 },
3435 { 0xbfc04dec, hleop_exc0_1_2 },
3436 { 0x1a00, hleop_exc0_2_2 },
3437 { 0x19c8, hleop_exc1_0_1 },
3438 { 0x18bc, hleop_exc1_0_2 },
3439 { 0x1990, hleop_exc1_1_1 },
3440 { 0x1858, hleop_exc1_1_2 },
3441 { 0x1958, hleop_exc1_2_1 },
3442 { 0x17f4, hleop_exc1_2_2 },
3443 { 0x1920, hleop_exc1_3_1 },
3444 { 0x1794, hleop_exc1_3_2 },
3445 { 0x2458, hleop_exc3_0_2 },
3446 { 0x49bc, hleop_exc_padcard1 }, // hleExcPadCard1
3447 { 0x4a4c, hleop_exc_padcard2 },
3450 static int chain_hle_op(u32 handler)
3454 for (i = 0; i < sizeof(chainfns) / sizeof(chainfns[0]); i++)
3455 if (chainfns[i].addr == handler)
3456 return chainfns[i].op;
3460 static void write_chain(u32 *d, u32 next, u32 handler1, u32 handler2)
3462 d[0] = SWAPu32(next);
3463 d[1] = SWAPu32(handler1);
3464 d[2] = SWAPu32(handler2);
3466 // install the hle traps
3467 if (handler1) PSXMu32ref(handler1) = HLEOP(chain_hle_op(handler1));
3468 if (handler2) PSXMu32ref(handler2) = HLEOP(chain_hle_op(handler2));
3471 static void setup_tt(u32 tcb_cnt, u32 evcb_cnt, u32 stack)
3473 u32 *ram32 = (u32 *)psxM;
3474 u32 s_excb = 0x20, s_evcb, s_pcb = 4, s_tcb;
3475 u32 p_excb, p_evcb, p_pcb, p_tcb;
3478 PSXBIOS_LOG("setup: tcb %u, evcb %u\n", tcb_cnt, evcb_cnt);
3480 // the real bios doesn't care, but we just don't
3481 // want to crash in case of garbage parameters
3482 if (tcb_cnt > 1024) tcb_cnt = 1024;
3483 if (evcb_cnt > 1024) evcb_cnt = 1024;
3484 s_evcb = 0x1c * evcb_cnt;
3485 s_tcb = 0xc0 * tcb_cnt;
3487 memset(ram32 + 0xe000/4, 0, s_excb + s_evcb + s_pcb + s_tcb + 5*4);
3488 psxBios_SysInitMemory_(0xa000e000, 0x2000);
3489 p_excb = psxBios_SysMalloc_(s_excb);
3490 p_evcb = psxBios_SysMalloc_(s_evcb);
3491 p_pcb = psxBios_SysMalloc_(s_pcb);
3492 p_tcb = psxBios_SysMalloc_(s_tcb);
3494 // "table of tables". Some games modify it
3495 assert(A_TT_ExCB == 0x0100);
3496 ram32[0x0100/4] = SWAPu32(p_excb); // ExCB - exception chains
3497 ram32[0x0104/4] = SWAPu32(s_excb); // ExCB size
3498 ram32[0x0108/4] = SWAPu32(p_pcb); // PCB - process control
3499 ram32[0x010c/4] = SWAPu32(s_pcb); // PCB size
3500 ram32[0x0110/4] = SWAPu32(p_tcb); // TCB - thread control
3501 ram32[0x0114/4] = SWAPu32(s_tcb); // TCB size
3502 ram32[0x0120/4] = SWAPu32(p_evcb); // EvCB - event control
3503 ram32[0x0124/4] = SWAPu32(s_evcb); // EvCB size
3504 ram32[0x0140/4] = SWAPu32(0x8648); // FCB - file control
3505 ram32[0x0144/4] = SWAPu32(0x02c0); // FCB size
3506 ram32[0x0150/4] = SWAPu32(0x6ee0); // DCB - device control
3507 ram32[0x0154/4] = SWAPu32(0x0320); // DCB size
3509 storeRam32(p_excb + 0*4, 0x0000); // chain0
3510 storeRam32(p_excb + 2*4, 0x6d88); // chain1
3511 storeRam32(p_excb + 4*4, 0x0000); // chain2
3512 storeRam32(p_excb + 6*4, 0x6d98); // chain3
3514 storeRam32(p_pcb, p_tcb);
3515 storeRam32(p_tcb, 0x4000); // first TCB
3516 for (i = 1; i < tcb_cnt; i++)
3517 storeRam32(p_tcb + sizeof(TCB) * i, 0x1000);
3519 psxBios_SysEnqIntRP_(0, 0x6da8);
3520 setup_cd_irq_and_events();
3522 storeRam32(A_CONF_EvCB, evcb_cnt);
3523 storeRam32(A_CONF_TCB, tcb_cnt);
3524 storeRam32(A_CONF_SP, stack);
3527 static const u32 gpu_ctl_def[] = {
3528 0x00000000, 0x01000000, 0x03000000, 0x04000000,
3529 0x05000800, 0x06c60260, 0x0703fc10, 0x08000027
3532 static const u32 gpu_data_def[] = {
3533 0xe100360b, 0xe2000000, 0xe3000800, 0xe4077e7f,
3534 0xe5001000, 0xe6000000,
3535 0x02000000, 0x00000000, 0x01ff03ff
3539 static const u16 spu_config[] = {
3540 0x3fff, 0x37ef, 0x5ebc, 0x5ebc, 0x0000, 0x0000, 0x0000, 0x00a0,
3541 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0x00ff, 0x0000, 0x0000,
3542 0x0000, 0xe128, 0x0000, 0x0200, 0xf0f0, 0xc085, 0x0004, 0x0000,
3543 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
3544 0x033d, 0x0231, 0x7e00, 0x5000, 0xb400, 0xb000, 0x4c00, 0xb000,
3545 0x6000, 0x5400, 0x1ed6, 0x1a31, 0x1d14, 0x183b, 0x1bc2, 0x16b2,
3546 0x1a32, 0x15ef, 0x15ee, 0x1055, 0x1334, 0x0f2d, 0x11f6, 0x0c5d,
3547 0x1056, 0x0ae1, 0x0ae0, 0x07a2, 0x0464, 0x0232, 0x8000, 0x8000
3550 void psxBiosSetupBootState(void)
3552 boolean hle = Config.HLE;
3553 u32 *hw = (u32 *)psxH;
3556 // see also SetBootRegs()
3559 a0 = 1; a2 = a3 = 0; a3 = 0x2a;
3560 t2 = 0x2d; t4 = 0x23; t5 = 0x2b; t6 = 0xa0010000;
3562 k0 = 0xbfc0d968; k1 = 0xf1c;
3563 ra = 0xf0001234; // just to easily detect attempts to return
3564 psxRegs.CP0.n.Cause = 0x20;
3565 psxRegs.CP0.n.EPC = 0xbfc0d964; // EnterCriticalSection syscall
3567 hw[0x1000/4] = SWAP32(0x1f000000);
3568 hw[0x1004/4] = SWAP32(0x1f802000);
3569 hw[0x1008/4] = SWAP32(0x0013243f);
3570 hw[0x100c/4] = SWAP32(0x00003022);
3571 hw[0x1010/4] = SWAP32(0x0013243f);
3572 hw[0x1014/4] = SWAP32(0x200931e1);
3573 hw[0x1018/4] = SWAP32(0x00020943);
3574 hw[0x101c/4] = SWAP32(0x00070777);
3575 hw[0x1020/4] = SWAP32(0x0000132c);
3576 hw[0x1060/4] = SWAP32(0x00000b88);
3577 hw[0x1070/4] = SWAP32(0x00000001);
3578 hw[0x1074/4] = SWAP32(0x0000000c);
3579 hw[0x2040/4] = SWAP32(0x00000900);
3582 hw[0x10a0/4] = SWAP32(0x00ffffff);
3583 hw[0x10a8/4] = SWAP32(0x00000401);
3584 hw[0x10b0/4] = SWAP32(0x0008b000);
3585 hw[0x10b4/4] = SWAP32(0x00010200);
3586 hw[0x10e0/4] = SWAP32(0x000eccf4);
3587 hw[0x10e4/4] = SWAP32(0x00000400);
3588 hw[0x10e8/4] = SWAP32(0x00000002);
3589 hw[0x10f0/4] = SWAP32(0x00009099);
3590 hw[0x10f4/4] = SWAP32(0x8c8c0000);
3599 for (i = 0; i < sizeof(gpu_ctl_def) / sizeof(gpu_ctl_def[0]); i++)
3600 GPU_writeStatus(gpu_ctl_def[i]);
3601 for (i = 0; i < sizeof(gpu_data_def) / sizeof(gpu_data_def[0]); i++)
3602 GPU_writeData(gpu_data_def[i]);
3605 for (i = 0x1f801d80; i < sizeof(spu_config) / sizeof(spu_config[0]); i++)
3606 SPU_writeRegister(0x1f801d80 + i*2, spu_config[i], psxRegs.cycle);
3609 static void hleExc0_0_1();
3610 static void hleExc0_0_2();
3611 static void hleExc0_1_1();
3612 static void hleExc0_1_2();
3614 #include "sjisfont.h"
3616 void psxBiosInit() {
3617 u32 *ptr, *ram32, *rom32;
3622 psxRegs.biosBranchCheck = ~0;
3624 memset(psxM, 0, 0x10000);
3625 for(i = 0; i < 256; i++) {
3630 biosA0[0x03] = biosB0[0x35] = psxBios_write_psxout;
3631 biosA0[0x3c] = biosB0[0x3d] = psxBios_putchar_psxout;
3632 biosA0[0x3e] = biosB0[0x3f] = psxBios_puts_psxout;
3633 // calls putchar() internally so no need to override
3634 //biosA0[0x3f] = psxBios_printf_psxout;
3637 char verstr[0x24+1];
3638 rom32 = (u32 *)psxR;
3639 memcpy(verstr, psxR + 0x12c, 0x24);
3641 SysPrintf("BIOS: %08x, '%s', '%c'\n", SWAP32(rom32[0x100/4]),
3642 verstr, psxR[0x7ff52]);
3646 for(i = 0; i < 256; i++) {
3647 if (biosA0[i] == NULL) biosA0[i] = psxBios_dummy;
3648 if (biosB0[i] == NULL) biosB0[i] = psxBios_dummy;
3649 if (biosC0[i] == NULL) biosC0[i] = psxBios_dummy;
3652 biosA0[0x00] = psxBios_open;
3653 biosA0[0x01] = psxBios_lseek;
3654 biosA0[0x02] = psxBios_read;
3655 biosA0[0x03] = psxBios_write;
3656 biosA0[0x04] = psxBios_close;
3657 //biosA0[0x05] = psxBios_ioctl;
3658 //biosA0[0x06] = psxBios_exit;
3659 //biosA0[0x07] = psxBios_sys_a0_07;
3660 biosA0[0x08] = psxBios_getc;
3661 biosA0[0x09] = psxBios_putc;
3662 biosA0[0x0a] = psxBios_todigit;
3663 //biosA0[0x0b] = psxBios_atof;
3664 biosA0[0x0c] = psxBios_strtoul;
3665 biosA0[0x0d] = psxBios_strtol;
3666 biosA0[0x0e] = psxBios_abs;
3667 biosA0[0x0f] = psxBios_labs;
3668 biosA0[0x10] = psxBios_atoi;
3669 biosA0[0x11] = psxBios_atol;
3670 //biosA0[0x12] = psxBios_atob;
3671 biosA0[0x13] = psxBios_setjmp;
3672 biosA0[0x14] = psxBios_longjmp;
3673 biosA0[0x15] = psxBios_strcat;
3674 biosA0[0x16] = psxBios_strncat;
3675 biosA0[0x17] = psxBios_strcmp;
3676 biosA0[0x18] = psxBios_strncmp;
3677 biosA0[0x19] = psxBios_strcpy;
3678 biosA0[0x1a] = psxBios_strncpy;
3679 biosA0[0x1b] = psxBios_strlen;
3680 biosA0[0x1c] = psxBios_index;
3681 biosA0[0x1d] = psxBios_rindex;
3682 biosA0[0x1e] = psxBios_strchr;
3683 biosA0[0x1f] = psxBios_strrchr;
3684 biosA0[0x20] = psxBios_strpbrk;
3685 biosA0[0x21] = psxBios_strspn;
3686 biosA0[0x22] = psxBios_strcspn;
3687 biosA0[0x23] = psxBios_strtok;
3688 biosA0[0x24] = psxBios_strstr;
3689 biosA0[0x25] = psxBios_toupper;
3690 biosA0[0x26] = psxBios_tolower;
3691 biosA0[0x27] = psxBios_bcopy;
3692 biosA0[0x28] = psxBios_bzero;
3693 biosA0[0x29] = psxBios_bcmp;
3694 biosA0[0x2a] = psxBios_memcpy;
3695 biosA0[0x2b] = psxBios_memset;
3696 biosA0[0x2c] = psxBios_memmove;
3697 biosA0[0x2d] = psxBios_memcmp;
3698 biosA0[0x2e] = psxBios_memchr;
3699 biosA0[0x2f] = psxBios_rand;
3700 biosA0[0x30] = psxBios_srand;
3701 biosA0[0x31] = psxBios_qsort;
3702 //biosA0[0x32] = psxBios_strtod;
3703 biosA0[0x33] = psxBios_malloc;
3704 biosA0[0x34] = psxBios_free;
3705 //biosA0[0x35] = psxBios_lsearch;
3706 //biosA0[0x36] = psxBios_bsearch;
3707 biosA0[0x37] = psxBios_calloc;
3708 biosA0[0x38] = psxBios_realloc;
3709 biosA0[0x39] = psxBios_InitHeap;
3710 //biosA0[0x3a] = psxBios__exit;
3711 biosA0[0x3b] = psxBios_getchar;
3712 biosA0[0x3c] = psxBios_putchar;
3713 //biosA0[0x3d] = psxBios_gets;
3714 biosA0[0x3e] = psxBios_puts;
3715 biosA0[0x3f] = psxBios_printf;
3716 biosA0[0x40] = psxBios_SystemErrorUnresolvedException;
3717 //biosA0[0x41] = psxBios_LoadTest;
3718 biosA0[0x42] = psxBios_Load;
3719 biosA0[0x43] = psxBios_Exec;
3720 biosA0[0x44] = psxBios_FlushCache;
3721 //biosA0[0x45] = psxBios_InstallInterruptHandler;
3722 biosA0[0x46] = psxBios_GPU_dw;
3723 biosA0[0x47] = psxBios_mem2vram;
3724 biosA0[0x48] = psxBios_SendGPU;
3725 biosA0[0x49] = psxBios_GPU_cw;
3726 biosA0[0x4a] = psxBios_GPU_cwb;
3727 biosA0[0x4b] = psxBios_GPU_SendPackets;
3728 biosA0[0x4c] = psxBios_sys_a0_4c;
3729 biosA0[0x4d] = psxBios_GPU_GetGPUStatus;
3730 //biosA0[0x4e] = psxBios_GPU_sync;
3731 //biosA0[0x4f] = psxBios_sys_a0_4f;
3732 //biosA0[0x50] = psxBios_sys_a0_50;
3733 biosA0[0x51] = psxBios_LoadExec;
3734 //biosA0[0x52] = psxBios_GetSysSp;
3735 //biosA0[0x53] = psxBios_sys_a0_53;
3736 biosA0[0x54] = psxBios_CdInit;
3737 biosA0[0x55] = psxBios__bu_init;
3738 biosA0[0x56] = psxBios_CdRemove;
3739 //biosA0[0x57] = psxBios_sys_a0_57;
3740 //biosA0[0x58] = psxBios_sys_a0_58;
3741 //biosA0[0x59] = psxBios_sys_a0_59;
3742 //biosA0[0x5a] = psxBios_sys_a0_5a;
3743 //biosA0[0x5b] = psxBios_dev_tty_init;
3744 //biosA0[0x5c] = psxBios_dev_tty_open;
3745 //biosA0[0x5d] = psxBios_sys_a0_5d;
3746 //biosA0[0x5e] = psxBios_dev_tty_ioctl;
3747 //biosA0[0x5f] = psxBios_dev_cd_open;
3748 //biosA0[0x60] = psxBios_dev_cd_read;
3749 //biosA0[0x61] = psxBios_dev_cd_close;
3750 //biosA0[0x62] = psxBios_dev_cd_firstfile;
3751 //biosA0[0x63] = psxBios_dev_cd_nextfile;
3752 //biosA0[0x64] = psxBios_dev_cd_chdir;
3753 //biosA0[0x65] = psxBios_dev_card_open;
3754 //biosA0[0x66] = psxBios_dev_card_read;
3755 //biosA0[0x67] = psxBios_dev_card_write;
3756 //biosA0[0x68] = psxBios_dev_card_close;
3757 //biosA0[0x69] = psxBios_dev_card_firstfile;
3758 //biosA0[0x6a] = psxBios_dev_card_nextfile;
3759 //biosA0[0x6b] = psxBios_dev_card_erase;
3760 //biosA0[0x6c] = psxBios_dev_card_undelete;
3761 //biosA0[0x6d] = psxBios_dev_card_format;
3762 //biosA0[0x6e] = psxBios_dev_card_rename;
3763 //biosA0[0x6f] = psxBios_dev_card_6f;
3764 biosA0[0x70] = psxBios__bu_init;
3765 biosA0[0x71] = psxBios_CdInit;
3766 biosA0[0x72] = psxBios_CdRemove;
3767 //biosA0[0x73] = psxBios_sys_a0_73;
3768 //biosA0[0x74] = psxBios_sys_a0_74;
3769 //biosA0[0x75] = psxBios_sys_a0_75;
3770 //biosA0[0x76] = psxBios_sys_a0_76;
3771 //biosA0[0x77] = psxBios_sys_a0_77;
3772 //biosA0[0x78] = psxBios__96_CdSeekL;
3773 //biosA0[0x79] = psxBios_sys_a0_79;
3774 //biosA0[0x7a] = psxBios_sys_a0_7a;
3775 //biosA0[0x7b] = psxBios_sys_a0_7b;
3776 //biosA0[0x7c] = psxBios__96_CdGetStatus;
3777 //biosA0[0x7d] = psxBios_sys_a0_7d;
3778 //biosA0[0x7e] = psxBios__96_CdRead;
3779 //biosA0[0x7f] = psxBios_sys_a0_7f;
3780 //biosA0[0x80] = psxBios_sys_a0_80;
3781 //biosA0[0x81] = psxBios_sys_a0_81;
3782 //biosA0[0x82] = psxBios_sys_a0_82;
3783 //biosA0[0x83] = psxBios_sys_a0_83;
3784 //biosA0[0x84] = psxBios_sys_a0_84;
3785 //biosA0[0x85] = psxBios__96_CdStop;
3786 //biosA0[0x86] = psxBios_sys_a0_86;
3787 //biosA0[0x87] = psxBios_sys_a0_87;
3788 //biosA0[0x88] = psxBios_sys_a0_88;
3789 //biosA0[0x89] = psxBios_sys_a0_89;
3790 //biosA0[0x8a] = psxBios_sys_a0_8a;
3791 //biosA0[0x8b] = psxBios_sys_a0_8b;
3792 //biosA0[0x8c] = psxBios_sys_a0_8c;
3793 //biosA0[0x8d] = psxBios_sys_a0_8d;
3794 //biosA0[0x8e] = psxBios_sys_a0_8e;
3795 //biosA0[0x8f] = psxBios_sys_a0_8f;
3796 biosA0[0x90] = hleExc0_1_2;
3797 biosA0[0x91] = hleExc0_0_2;
3798 biosA0[0x92] = hleExc0_1_1;
3799 biosA0[0x93] = hleExc0_0_1;
3800 //biosA0[0x94] = psxBios_sys_a0_94;
3801 biosA0[0x95] = psxBios_CdReset;
3802 //biosA0[0x96] = psxBios_AddCDROMDevice;
3803 //biosA0[0x97] = psxBios_AddMemCardDevide;
3804 //biosA0[0x98] = psxBios_DisableKernelIORedirection;
3805 //biosA0[0x99] = psxBios_EnableKernelIORedirection;
3806 //biosA0[0x9a] = psxBios_sys_a0_9a;
3807 //biosA0[0x9b] = psxBios_sys_a0_9b;
3808 biosA0[0x9c] = psxBios_SetConf;
3809 biosA0[0x9d] = psxBios_GetConf;
3810 //biosA0[0x9e] = psxBios_sys_a0_9e;
3811 biosA0[0x9f] = psxBios_SetMem;
3812 //biosA0[0xa0] = psxBios__boot;
3813 //biosA0[0xa1] = psxBios_SystemError;
3814 biosA0[0xa2] = psxBios_EnqueueCdIntr;
3815 biosA0[0xa3] = psxBios_DequeueCdIntr;
3816 //biosA0[0xa4] = psxBios_sys_a0_a4;
3817 //biosA0[0xa5] = psxBios_ReadSector;
3818 biosA0[0xa6] = psxBios_get_cd_status;
3819 //biosA0[0xa7] = psxBios_bufs_cb_0;
3820 //biosA0[0xa8] = psxBios_bufs_cb_1;
3821 //biosA0[0xa9] = psxBios_bufs_cb_2;
3822 //biosA0[0xaa] = psxBios_bufs_cb_3;
3823 biosA0[0xab] = psxBios__card_info;
3824 biosA0[0xac] = psxBios__card_load;
3825 //biosA0[0axd] = psxBios__card_auto;
3826 //biosA0[0xae] = psxBios_bufs_cd_4;
3827 //biosA0[0xaf] = psxBios_sys_a0_af;
3828 //biosA0[0xb0] = psxBios_sys_a0_b0;
3829 //biosA0[0xb1] = psxBios_sys_a0_b1;
3830 //biosA0[0xb2] = psxBios_do_a_long_jmp
3831 //biosA0[0xb3] = psxBios_sys_a0_b3;
3832 biosA0[0xb4] = psxBios_GetSystemInfo;
3833 //*******************B0 CALLS****************************
3834 biosB0[0x00] = psxBios_SysMalloc;
3835 //biosB0[0x01] = psxBios_sys_b0_01;
3836 biosB0[0x02] = psxBios_SetRCnt;
3837 biosB0[0x03] = psxBios_GetRCnt;
3838 biosB0[0x04] = psxBios_StartRCnt;
3839 biosB0[0x05] = psxBios_StopRCnt;
3840 biosB0[0x06] = psxBios_ResetRCnt;
3841 biosB0[0x07] = psxBios_DeliverEvent;
3842 biosB0[0x08] = psxBios_OpenEvent;
3843 biosB0[0x09] = psxBios_CloseEvent;
3844 biosB0[0x0a] = psxBios_WaitEvent;
3845 biosB0[0x0b] = psxBios_TestEvent;
3846 biosB0[0x0c] = psxBios_EnableEvent;
3847 biosB0[0x0d] = psxBios_DisableEvent;
3848 biosB0[0x0e] = psxBios_OpenTh;
3849 biosB0[0x0f] = psxBios_CloseTh;
3850 biosB0[0x10] = psxBios_ChangeTh;
3851 //biosB0[0x11] = psxBios_psxBios_b0_11;
3852 biosB0[0x12] = psxBios_InitPAD;
3853 biosB0[0x13] = psxBios_StartPAD;
3854 biosB0[0x14] = psxBios_StopPAD;
3855 biosB0[0x15] = psxBios_PAD_init;
3856 biosB0[0x16] = psxBios_PAD_dr;
3857 biosB0[0x17] = psxBios_ReturnFromException;
3858 biosB0[0x18] = psxBios_ResetEntryInt;
3859 biosB0[0x19] = psxBios_HookEntryInt;
3860 //biosB0[0x1a] = psxBios_sys_b0_1a;
3861 //biosB0[0x1b] = psxBios_sys_b0_1b;
3862 //biosB0[0x1c] = psxBios_sys_b0_1c;
3863 //biosB0[0x1d] = psxBios_sys_b0_1d;
3864 //biosB0[0x1e] = psxBios_sys_b0_1e;
3865 //biosB0[0x1f] = psxBios_sys_b0_1f;
3866 biosB0[0x20] = psxBios_UnDeliverEvent;
3867 //biosB0[0x21] = psxBios_sys_b0_21;
3868 //biosB0[0x22] = psxBios_sys_b0_22;
3869 //biosB0[0x23] = psxBios_sys_b0_23;
3870 //biosB0[0x24] = psxBios_sys_b0_24;
3871 //biosB0[0x25] = psxBios_sys_b0_25;
3872 //biosB0[0x26] = psxBios_sys_b0_26;
3873 //biosB0[0x27] = psxBios_sys_b0_27;
3874 //biosB0[0x28] = psxBios_sys_b0_28;
3875 //biosB0[0x29] = psxBios_sys_b0_29;
3876 //biosB0[0x2a] = psxBios_sys_b0_2a;
3877 //biosB0[0x2b] = psxBios_sys_b0_2b;
3878 //biosB0[0x2c] = psxBios_sys_b0_2c;
3879 //biosB0[0x2d] = psxBios_sys_b0_2d;
3880 //biosB0[0x2e] = psxBios_sys_b0_2e;
3881 //biosB0[0x2f] = psxBios_sys_b0_2f;
3882 //biosB0[0x30] = psxBios_sys_b0_30;
3883 //biosB0[0x31] = psxBios_sys_b0_31;
3884 biosB0[0x32] = psxBios_open;
3885 biosB0[0x33] = psxBios_lseek;
3886 biosB0[0x34] = psxBios_read;
3887 biosB0[0x35] = psxBios_write;
3888 biosB0[0x36] = psxBios_close;
3889 //biosB0[0x37] = psxBios_ioctl;
3890 //biosB0[0x38] = psxBios_exit;
3891 //biosB0[0x39] = psxBios_sys_b0_39;
3892 biosB0[0x3a] = psxBios_getc;
3893 biosB0[0x3b] = psxBios_putc;
3894 biosB0[0x3c] = psxBios_getchar;
3895 biosB0[0x3d] = psxBios_putchar;
3896 //biosB0[0x3e] = psxBios_gets;
3897 biosB0[0x3f] = psxBios_puts;
3898 biosB0[0x40] = psxBios_cd;
3899 biosB0[0x41] = psxBios_format;
3900 biosB0[0x42] = psxBios_firstfile;
3901 biosB0[0x43] = psxBios_nextfile;
3902 biosB0[0x44] = psxBios_rename;
3903 biosB0[0x45] = psxBios_delete;
3904 //biosB0[0x46] = psxBios_undelete;
3905 //biosB0[0x47] = psxBios_AddDevice;
3906 //biosB0[0x48] = psxBios_RemoteDevice;
3907 //biosB0[0x49] = psxBios_PrintInstalledDevices;
3908 biosB0[0x4a] = psxBios_InitCARD;
3909 biosB0[0x4b] = psxBios_StartCARD;
3910 biosB0[0x4c] = psxBios_StopCARD;
3911 //biosB0[0x4d] = psxBios_sys_b0_4d;
3912 biosB0[0x4e] = psxBios__card_write;
3913 biosB0[0x4f] = psxBios__card_read;
3914 biosB0[0x50] = psxBios__new_card;
3915 biosB0[0x51] = psxBios_Krom2RawAdd;
3916 //biosB0[0x52] = psxBios_sys_b0_52;
3917 //biosB0[0x53] = psxBios_sys_b0_53;
3918 //biosB0[0x54] = psxBios__get_errno;
3919 biosB0[0x55] = psxBios__get_error;
3920 biosB0[0x56] = psxBios_GetC0Table;
3921 biosB0[0x57] = psxBios_GetB0Table;
3922 biosB0[0x58] = psxBios__card_chan;
3923 //biosB0[0x59] = psxBios_sys_b0_59;
3924 //biosB0[0x5a] = psxBios_sys_b0_5a;
3925 biosB0[0x5b] = psxBios_ChangeClearPad;
3926 biosB0[0x5c] = psxBios__card_status;
3927 biosB0[0x5d] = psxBios__card_wait;
3928 //*******************C0 CALLS****************************
3929 biosC0[0x00] = psxBios_InitRCnt;
3930 biosC0[0x01] = psxBios_InitException;
3931 biosC0[0x02] = psxBios_SysEnqIntRP;
3932 biosC0[0x03] = psxBios_SysDeqIntRP;
3933 biosC0[0x04] = psxBios_get_free_EvCB_slot;
3934 //biosC0[0x05] = psxBios_get_free_TCB_slot;
3935 //biosC0[0x06] = psxBios_ExceptionHandler;
3936 //biosC0[0x07] = psxBios_InstallExeptionHandler;
3937 biosC0[0x08] = psxBios_SysInitMemory;
3938 //biosC0[0x09] = psxBios_SysInitKMem;
3939 biosC0[0x0a] = psxBios_ChangeClearRCnt;
3940 //biosC0[0x0b] = psxBios_SystemError;
3941 biosC0[0x0c] = psxBios_InitDefInt;
3942 //biosC0[0x0d] = psxBios_sys_c0_0d;
3943 //biosC0[0x0e] = psxBios_sys_c0_0e;
3944 //biosC0[0x0f] = psxBios_sys_c0_0f;
3945 //biosC0[0x10] = psxBios_sys_c0_10;
3946 //biosC0[0x11] = psxBios_sys_c0_11;
3947 //biosC0[0x12] = psxBios_InstallDevices;
3948 //biosC0[0x13] = psxBios_FlushStfInOutPut;
3949 //biosC0[0x14] = psxBios_sys_c0_14;
3950 //biosC0[0x15] = psxBios__cdevinput;
3951 //biosC0[0x16] = psxBios__cdevscan;
3952 //biosC0[0x17] = psxBios__circgetc;
3953 //biosC0[0x18] = psxBios__circputc;
3954 //biosC0[0x19] = psxBios_ioabort;
3955 //biosC0[0x1a] = psxBios_sys_c0_1a
3956 //biosC0[0x1b] = psxBios_KernelRedirect;
3957 //biosC0[0x1c] = psxBios_PatchAOTable;
3958 //************** THE END ***************************************
3961 memset(FDesc, 0, sizeof(FDesc));
3962 memset(cdir, 0, sizeof(cdir));
3965 // somewhat pretend to be a SCPH1001 BIOS
3966 // some games look for these and take an exception if they're missing
3967 rom32 = (u32 *)psxR;
3968 rom32[0x100/4] = SWAP32(0x19951204);
3969 rom32[0x104/4] = SWAP32(3);
3970 romc = (char *)psxR;
3971 strcpy(romc + 0x108, "PCSX authors");
3972 strcpy(romc + 0x12c, "CEX-3000 PCSX HLE"); // see psxBios_GetSystemInfo
3973 strcpy(romc + 0x7ff32, "System ROM Version 2.2 12/04/95 A");
3974 strcpy(romc + 0x7ff54, "GPL-2.0-or-later");
3977 len = 0x80000 - 0x66000;
3978 uncompress((Bytef *)(psxR + 0x66000), &len, font_8140, sizeof(font_8140));
3979 len = 0x80000 - 0x69d68;
3980 uncompress((Bytef *)(psxR + 0x69d68), &len, font_889f, sizeof(font_889f));
3982 // trap attempts to call bios directly
3983 rom32[0x00000/4] = HLEOP(hleop_dummy);
3984 rom32[0x00180/4] = HLEOP(hleop_dummy);
3985 rom32[0x3fffc/4] = HLEOP(hleop_dummy);
3986 rom32[0x65ffc/4] = HLEOP(hleop_dummy);
3987 rom32[0x7ff2c/4] = HLEOP(hleop_dummy);
3989 /* Some games like R-Types, CTR, Fade to Black read from adress 0x00000000 due to uninitialized pointers.
3990 See Garbage Area at Address 00000000h in Nocash PSX Specfications for more information.
3991 Here are some examples of games not working with this fix in place :
3992 R-type won't get past the Irem logo if not implemented.
3993 Crash Team Racing will softlock after the Sony logo.
3996 ram32 = (u32 *)psxM;
3997 ram32[0x0000/4] = SWAPu32(0x00000003); // lui $k0, 0 (overwritten by 3)
3998 ram32[0x0004/4] = SWAPu32(0x275a0000 + A_EXCEPTION); // addiu $k0, $k0, 0xc80
3999 ram32[0x0008/4] = SWAPu32(0x03400008); // jr $k0
4000 ram32[0x000c/4] = SWAPu32(0x00000000); // nop
4002 ram32[0x0060/4] = SWAPu32(0x00000002); // ram size?
4003 ram32[0x0068/4] = SWAPu32(0x000000ff); // unknown
4005 ram32[0x0080/4] = SWAPu32(0x3c1a0000); // lui $k0, 0 // exception vector
4006 ram32[0x0084/4] = SWAPu32(0x275a0000 + A_EXCEPTION); // addiu $k0, $k0, 0xc80
4007 ram32[0x0088/4] = SWAPu32(0x03400008); // jr $k0
4008 ram32[0x008c/4] = SWAPu32(0x00000000); // nop
4010 ram32[0x00a0/4] = HLEOP(hleop_a0);
4011 ram32[0x00b0/4] = HLEOP(hleop_b0);
4012 ram32[0x00c0/4] = HLEOP(hleop_c0);
4014 setup_tt(4, 16, 0x801fff00);
4015 DeliverEvent(0xf0000003, 0x0010);
4017 ram32[0x6ee0/4] = SWAPu32(0x0000eff0); // DCB
4018 strcpy((char *)&ram32[0xeff0/4], "bu");
4020 // default exception handler chains
4021 // see also setup_cd_irq_and_events()
4022 write_chain(&ram32[0x91e0/4], 0x91d0, 0xbfc050a4, 0xbfc04fbc); // chain0.e0
4023 write_chain(&ram32[0x91d0/4], 0x6da8, 0xbfc0506c, 0xbfc04dec); // chain0.e1
4024 write_chain(&ram32[0x6da8/4], 0, 0, 0x1a00); // chain0.e2
4025 write_chain(&ram32[0x6d88/4], 0x6d78, 0x19c8, 0x18bc); // chain1.e0
4026 write_chain(&ram32[0x6d78/4], 0x6d68, 0x1990, 0x1858); // chain1.e1
4027 write_chain(&ram32[0x6d68/4], 0x6d58, 0x1958, 0x17f4); // chain1.e2
4028 write_chain(&ram32[0x6d58/4], 0, 0x1920, 0x1794); // chain1.e3
4029 write_chain(&ram32[0x6d98/4], 0, 0, 0x2458); // chain3.e0
4033 // fill the api jumptables with fake entries as some games patch them
4034 // (or rather the funcs listed there)
4035 // also trap the destination as some "Cheats Edition" thing overrides the
4036 // dispatcher with a wrapper and then jumps to the table entries directly
4037 ptr = (u32 *)&psxM[A_A0_TABLE];
4038 for (i = 0; i < 256; i++) {
4039 ptr[i] = SWAP32(A_A0_TRAPS + i*4);
4040 ram32[A_A0_TRAPS/4 + i] = HLEOP(hleop_a0t);
4042 ptr = (u32 *)&psxM[A_B0_TABLE];
4043 for (i = 0; i < 256; i++) {
4044 ptr[i] = SWAP32(A_B0_TRAPS + i*4);
4045 ram32[A_B0_TRAPS/4 + i] = HLEOP(hleop_b0t);
4047 // B(5b) is special because games patch (sometimes even jump to)
4048 // code at fixed offsets from it, nocash lists offsets:
4049 // patch: +3d8, +4dc, +594, +62c, +9c8, +1988
4050 // call: +7a0=4b70, +884=4c54, +894=4c64
4051 ptr[0x5b] = SWAP32(A_B0_5B_TRAP); // 0x43d0
4052 ram32[A_B0_5B_TRAP/4] = HLEOP(hleop_b0t);
4054 ram32[0x4b70/4] = SWAP32(0x03e00008); // jr $ra // setPadOutputBuf
4056 ram32[0x4c54/4] = SWAP32(0x240e0001); // mov $t6, 1
4057 ram32[0x4c58/4] = SWAP32(0x03e00008); // jr $ra
4058 ram32[0x4c5c/4] = SWAP32(0xac0e0000 + A_PAD_IRQR_ENA); // sw $t6, ...
4060 ram32[0x4c64/4] = SWAP32(0x03e00008); // jr $ra
4061 ram32[0x4c68/4] = SWAP32(0xac000000 + A_PAD_IRQR_ENA); // sw $0, ...
4063 ptr = (u32 *)&psxM[A_C0_TABLE];
4064 for (i = 0; i < 256/2; i++) {
4065 ptr[i] = SWAP32(A_C0_TRAPS + i*4);
4066 ram32[A_C0_TRAPS/4 + i] = HLEOP(hleop_c0t);
4068 ptr[6] = SWAP32(A_EXCEPTION);
4071 ram32[A_A0_TRAPS/4 - 1] = HLEOP(hleop_dummy);
4072 ram32[A_B0_TRAPS/4 - 1] = HLEOP(hleop_dummy);
4073 ram32[A_C0_TRAPS/4 - 1] = HLEOP(hleop_dummy);
4074 ram32[0x7ffc/4] = HLEOP(hleop_dummy);
4075 ram32[0x8000/4] = HLEOP(hleop_execret);
4077 ram32[A_EEXIT_PTR/4] = SWAP32(A_EEXIT_DEF);
4078 ram32[A_EXC_SP/4] = SWAP32(A_EXC_STACK);
4079 ram32[A_RCNT_VBL_ACK/4 + 0] = SWAP32(1);
4080 ram32[A_RCNT_VBL_ACK/4 + 1] = SWAP32(1);
4081 ram32[A_RCNT_VBL_ACK/4 + 2] = SWAP32(1);
4082 ram32[A_RCNT_VBL_ACK/4 + 3] = SWAP32(1);
4083 ram32[A_RND_SEED/4] = SWAPu32(0x24040001); // was 0xac20cc00
4086 void psxBiosShutdown() {
4089 void psxBiosCnfLoaded(u32 tcb_cnt, u32 evcb_cnt, u32 stack) {
4092 if (tcb_cnt != 4 || evcb_cnt != 16) {
4093 setup_tt(tcb_cnt, evcb_cnt, stack);
4094 DeliverEvent(0xf0000003, 0x0010);
4096 storeRam32(A_CONF_SP, stack);
4099 #define psxBios_PADpoll(pad) { \
4100 int i, more_data = 0; \
4101 PAD##pad##_startPoll(pad); \
4102 pad_buf##pad[1] = PAD##pad##_poll(0x42, &more_data); \
4103 pad_buf##pad[0] = more_data ? 0 : 0xff; \
4104 PAD##pad##_poll(0, &more_data); \
4106 while (more_data) { \
4107 pad_buf##pad[i++] = PAD##pad##_poll(0, &more_data); \
4111 static void handle_chain_x_x_1(u32 enable, u32 irqbit)
4115 psxHwWrite16(0x1f801070, ~(1u << irqbit));
4116 psxBios_ReturnFromException();
4122 // hleExc0_{0,1}* are usually removed by A(56)/A(72) on the game's startup,
4123 // so this is only partially implemented
4124 static void hleExc0_0_1() // A(93h) - CdromDmaIrqFunc2
4126 u32 cdrom_dma_ack_enable = 1; // a000b93c
4127 handle_chain_x_x_1(cdrom_dma_ack_enable, 3); // IRQ3 DMA
4130 static void hleExc0_0_2() // A(91h) - CdromDmaIrqFunc1
4133 //PSXBIOS_LOG("%s\n", __func__);
4135 if (psxHu32(0x1074) & psxHu32(0x1070) & 8) { // IRQ3 DMA
4136 psxHwWrite32(0x1f8010f4, (psxHu32(0x10f4) & 0xffffff) | 0x88000000);
4137 //if (--cdrom_irq_counter == 0) // 0xa0009180
4138 // DeliverEvent(0xf0000003, 0x10);
4142 mips_return_c(ret, 20);
4145 static void hleExc0_1_1() // A(92h) - CdromIoIrqFunc2
4147 u32 cdrom_irq_ack_enable = 1; // a000b938
4148 handle_chain_x_x_1(cdrom_irq_ack_enable, 2); // IRQ2 cdrom
4151 static void hleExc0_1_2() // A(90h) - CdromIoIrqFunc1
4154 if (psxHu32(0x1074) & psxHu32(0x1070) & 4) { // IRQ2 cdrom
4155 PSXBIOS_LOG("%s TODO\n", __func__);
4158 mips_return_c(ret, 20);
4161 static void hleExc0_2_2_syscall() // not in any A/B/C table
4163 u32 tcbPtr = loadRam32(A_TT_PCB);
4164 TCB *tcb = loadRam32ptr(tcbPtr);
4165 u32 code = (SWAP32(tcb->cause) & 0x3c) >> 2;
4167 if (code != R3000E_Syscall) {
4169 DeliverEvent(0xf0000010, 0x1000);
4170 //psxBios_SystemErrorUnresolvedException();
4172 mips_return_c(0, 17);
4176 //printf("%s c=%d a0=%d\n", __func__, code, SWAP32(tcb->reg[4]));
4177 tcb->epc += SWAP32(4);
4178 switch (SWAP32(tcb->reg[4])) { // a0
4182 case 1: { // EnterCritical - disable irqs
4183 u32 was_enabled = ((SWAP32(tcb->sr) & 0x404) == 0x404);
4184 tcb->reg[2] = SWAP32(was_enabled);
4185 tcb->sr &= SWAP32(~0x404);
4188 case 2: // ExitCritical - enable irqs
4189 tcb->sr |= SWAP32(0x404);
4192 case 3: { // ChangeThreadSubFunction
4193 u32 tcbPtr = loadRam32(A_TT_PCB);
4194 storeRam32(tcbPtr, SWAP32(tcb->reg[5])); // a1
4198 DeliverEvent(0xf0000010, 0x4000);
4202 psxBios_ReturnFromException();
4205 static void hleExc1_0_1(void)
4207 u32 vbl_irq_ack_enable = loadRam32(A_RCNT_VBL_ACK + 0x0c); // 860c
4208 handle_chain_x_x_1(vbl_irq_ack_enable, 0); // IRQ0 vblank
4211 static void handle_chain_1_x_2(u32 ev_index, u32 irqbit)
4214 if (psxHu32(0x1074) & psxHu32(0x1070) & (1u << irqbit)) {
4215 DeliverEvent(0xf2000000 + ev_index, 0x0002);
4218 mips_return_c(ret, 22);
4221 static void hleExc1_0_2(void)
4223 handle_chain_1_x_2(3, 0); // IRQ0 vblank
4226 static void hleExc1_1_1(void)
4228 u32 rcnt_irq_ack_enable = loadRam32(A_RCNT_VBL_ACK + 0x08); // 8608
4229 handle_chain_x_x_1(rcnt_irq_ack_enable, 6); // IRQ6 rcnt2
4232 static void hleExc1_1_2(void)
4234 handle_chain_1_x_2(2, 6); // IRQ6 rcnt2
4237 static void hleExc1_2_1(void)
4239 u32 rcnt_irq_ack_enable = loadRam32(A_RCNT_VBL_ACK + 0x04); // 8604
4240 handle_chain_x_x_1(rcnt_irq_ack_enable, 5); // IRQ5 rcnt1
4243 static void hleExc1_2_2(void)
4245 handle_chain_1_x_2(1, 5); // IRQ5 rcnt1
4248 static void hleExc1_3_1(void)
4250 u32 rcnt_irq_ack_enable = loadRam32(A_RCNT_VBL_ACK + 0x00); // 8600
4251 handle_chain_x_x_1(rcnt_irq_ack_enable, 4); // IRQ4 rcnt0
4254 static void hleExc1_3_2(void)
4256 handle_chain_1_x_2(0, 4); // IRQ4 rcnt0
4259 static void hleExc3_0_2_defint(void)
4261 static const struct {
4272 { 6, 6 }, // rcnt2 (bug)
4277 for (i = 0; i < sizeof(tab) / sizeof(tab[0]); i++) {
4278 if (psxHu32(0x1074) & psxHu32(0x1070) & (1u << tab[i].irqbit)) {
4279 DeliverEvent(0xf0000000 + tab[i].ev, 0x1000);
4284 mips_return_c(0, 11 + 7*11 + 7*11 + 12);
4287 static void hleExcPadCard1(void)
4289 if (loadRam32(A_PAD_IRQR_ENA)) {
4290 u8 *pad_buf1 = loadRam8ptr(A_PAD_INBUF + 0);
4291 u8 *pad_buf2 = loadRam8ptr(A_PAD_INBUF + 4);
4296 if (loadRam32(A_PAD_DR_DST))
4299 if (loadRam32(A_PAD_ACK_VBL))
4300 psxHwWrite16(0x1f801070, ~1);
4301 if (loadRam32(A_CARD_IRQR_ENA))
4302 card_vint_handler();
4304 mips_return_c(0, 18);
4307 static void hleExcPadCard2(void)
4309 u32 ret = psxHu32(0x1074) & psxHu32(0x1070) & 1;
4310 mips_return_c(ret, 15);
4313 void psxBiosException() {
4314 u32 tcbPtr = loadRam32(A_TT_PCB);
4315 u32 *chains = loadRam32ptr(A_TT_ExCB);
4316 TCB *tcb = loadRam32ptr(tcbPtr);
4322 // $at, $v0, $v1, $ra already saved by the mips code at A_EXCEPTION
4323 for (i = 4; i < 31; i++) {
4326 tcb->reg[i] = SWAP32(psxRegs.GPR.r[i]);
4328 tcb->lo = SWAP32(psxRegs.GPR.n.lo);
4329 tcb->hi = SWAP32(psxRegs.GPR.n.hi);
4330 //tcb->epc = SWAP32(psxRegs.CP0.n.EPC); // done by asm
4331 tcb->sr = SWAP32(psxRegs.CP0.n.SR);
4332 tcb->cause = SWAP32(psxRegs.CP0.n.Cause);
4333 sp = fp = loadRam32(A_EXC_SP);
4336 assert(!psxRegs.cpuInRecursion);
4338 // do the chains (always 4)
4339 for (c = lim = 0; c < 4; c++) {
4340 if (chains[c * 2] == 0)
4342 ptr = SWAP32(chains[c * 2]);
4343 for (; ptr && lim < 100; ptr = SWAP32(chain[0])) {
4344 chain = castRam32ptr(ptr);
4349 softCallInException(SWAP32(chain[2]));
4350 if (returned_from_exception())
4353 if (v0 == 0 || chain[1] == 0)
4355 softCallInException(SWAP32(chain[1]));
4356 if (returned_from_exception())
4362 // return from exception (custom or default)
4364 ptr = loadRam32(A_EEXIT_PTR);
4365 if (ptr != A_EEXIT_DEF) {
4366 const struct jmp_buf_ *jmp_buf = castRam32ptr(ptr);
4367 longjmp_load(jmp_buf);
4372 psxBios_ReturnFromException();
4376 static void hleDummy() {
4377 log_unhandled("hleDummy called @%08x ra=%08x\n", psxRegs.pc - 4, ra);
4379 psxRegs.cycle += 1000;
4384 static void hleA0() {
4385 u32 call = t1 & 0xff;
4386 u32 entry = loadRam32(A_A0_TABLE + call * 4);
4389 if (call < 192 && entry != A_A0_TRAPS + call * 4) {
4390 PSXBIOS_LOG("custom A%02x %s(0x%x, ) addr=%08x ra=%08x\n",
4391 call, biosA0n[call], a0, entry, ra);
4394 PSXBIOS_LOG(" -> %08x\n", v0);
4396 else if (biosA0[call])
4399 //printf("A(%02x) -> %x\n", call, v0);
4403 static void hleB0() {
4404 u32 call = t1 & 0xff;
4405 u32 entry = loadRam32(A_B0_TABLE + call * 4);
4410 is_custom = entry != A_B0_5B_TRAP;
4412 is_custom = entry != A_B0_TRAPS + call * 4;
4414 PSXBIOS_LOG("custom B%02x %s(0x%x, ) addr=%08x ra=%08x\n",
4415 call, biosB0n[call], a0, entry, ra);
4418 PSXBIOS_LOG(" -> %08x\n", v0);
4420 else if (biosB0[call])
4423 //printf("B(%02x) -> %x\n", call, v0);
4427 static void hleC0() {
4428 u32 call = t1 & 0xff;
4429 u32 entry = loadRam32(A_C0_TABLE + call * 4);
4432 if (call < 128 && entry != A_C0_TRAPS + call * 4) {
4433 PSXBIOS_LOG("custom C%02x %s(0x%x, ) addr=%08x ra=%08x\n",
4434 call, biosC0n[call], a0, entry, ra);
4437 PSXBIOS_LOG(" -> %08x\n", v0);
4439 else if (biosC0[call])
4442 //printf("C(%02x) -> %x\n", call, v0);
4446 static void hleA0t() {
4447 u32 call = (pc0 - A_A0_TRAPS) / 4 - 1;
4448 if (call >= 256u || !biosA0[call]) {
4449 log_unhandled("unexpected A trap @%08x ra=%08x\n", pc0 - 4, ra);
4450 mips_return_void_c(1000);
4455 //printf("A(%02x) -> %x\n", call, v0);
4459 static void hleB0t() {
4460 u32 call = (pc0 - A_B0_TRAPS) / 4 - 1;
4461 if (pc0 - 4 == A_B0_5B_TRAP)
4463 if (call >= 256u || !biosB0[call]) {
4464 log_unhandled("unexpected B trap @%08x ra=%08x\n", pc0 - 4, ra);
4465 mips_return_void_c(1000);
4470 //printf("B(%02x) -> %x\n", call, v0);
4474 static void hleC0t() {
4475 u32 call = (pc0 - A_C0_TRAPS) / 4 - 1;
4476 if (call >= 128u || !biosC0[call]) {
4477 log_unhandled("unexpected C trap @%08x ra=%08x\n", pc0 - 4, ra);
4478 mips_return_void_c(1000);
4483 //printf("C(%02x) -> %x\n", call, v0);
4487 // currently not used
4488 static void hleBootstrap() {
4493 static void hleExecRet() {
4494 const EXEC *header = (EXEC *)PSXM(s0);
4496 PSXBIOS_LOG("ExecRet %x: %x\n", s0, header->ret);
4498 ra = SWAP32(header->ret);
4499 sp = SWAP32(header->_sp);
4500 fp = SWAP32(header->_fp);
4501 gp = SWAP32(header->_gp);
4502 s0 = SWAP32(header->base);
4508 void (* const psxHLEt[hleop_count_])() = {
4509 hleDummy, hleA0, hleB0, hleC0,
4510 hleBootstrap, hleExecRet, psxBiosException, hleDummy,
4511 hleExc0_0_1, hleExc0_0_2,
4512 hleExc0_1_1, hleExc0_1_2, hleExc0_2_2_syscall,
4513 hleExc1_0_1, hleExc1_0_2,
4514 hleExc1_1_1, hleExc1_1_2,
4515 hleExc1_2_1, hleExc1_2_2,
4516 hleExc1_3_1, hleExc1_3_2,
4518 hleExcPadCard1, hleExcPadCard2,
4519 hleA0t, hleB0t, hleC0t,
4522 void psxBiosCheckExe(u32 t_addr, u32 t_size, int loading_state)
4524 // lw $v0, 0x10($sp)
4527 // sw $v0, 0x10($sp)
4528 // lw $v0, 0x10($sp)
4530 // bne $v0, $v1, not_timeout
4533 static const u8 pattern[] = {
4534 0x10, 0x00, 0xA2, 0x8F, 0x00, 0x00, 0x00, 0x00,
4535 0xFF, 0xFF, 0x42, 0x24, 0x10, 0x00, 0xA2, 0xAF,
4536 0x10, 0x00, 0xA2, 0x8F, 0x00, 0x00, 0x00, 0x00,
4537 0x0C, 0x00, 0x43, 0x14, 0x00, 0x00, 0x00, 0x00,
4539 u32 start = t_addr & 0x1ffffc;
4540 u32 end = (start + t_size) & 0x1ffffc;
4541 u32 buf[sizeof(pattern) / sizeof(u32)];
4542 const u32 *r32 = (u32 *)(psxM + start);
4550 memcpy(buf, pattern, sizeof(buf));
4551 for (i = 0; i < t_size / 4; i += j + 1) {
4552 for (j = 0; j < sizeof(buf) / sizeof(buf[0]); j++)
4553 if (r32[i + j] != buf[j])
4555 if (j != sizeof(buf) / sizeof(buf[0]))
4558 if ((SWAP32(r32[i + j]) >> 16) != 0x3c04) // lui
4561 SysPrintf("HLE vsync @%08x\n", start + i * 4);
4562 psxRegs.biosBranchCheck = (t_addr & 0xa01ffffc) + i * 4;
4566 void psxBiosCheckBranch(void)
4570 static u32 cycles_prev, v0_prev;
4571 u32 cycles_passed, waste_cycles;
4572 u32 loops, v0_expect = v0_prev - 1;
4576 cycles_passed = psxRegs.cycle - cycles_prev;
4577 cycles_prev = psxRegs.cycle;
4579 if (cycles_passed < 10 || cycles_passed > 50 || v0 != v0_expect)
4582 waste_cycles = schedule_timeslice(&psxRegs) - psxRegs.cycle;
4583 loops = waste_cycles / cycles_passed;
4587 psxRegs.cycle += loops * cycles_passed;
4588 //printf("c %4u %d\n", loops, cycles_passed);
4592 #define bfreeze(ptr, size) { \
4593 if (Mode == 1) memcpy(&psxR[base], ptr, size); \
4594 if (Mode == 0) memcpy(ptr, &psxR[base], size); \
4598 #define bfreezes(ptr) bfreeze(ptr, sizeof(ptr))
4599 #define bfreezel(ptr) bfreeze(ptr, sizeof(*(ptr)))
4601 void psxBiosFreeze(int Mode) {
4608 bfreezel(&card_io_delay);