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.
40 #if (defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)
41 #pragma GCC diagnostic ignored "-Wpointer-sign"
45 #define SysPrintf if (Config.PsxOut) printf
47 char *biosA0n[256] = {
49 "open", "lseek", "read", "write",
50 "close", "ioctl", "exit", "sys_a0_07",
51 "getc", "putc", "todigit", "atof",
52 "strtoul", "strtol", "abs", "labs",
54 "atoi", "atol", "atob", "setjmp",
55 "longjmp", "strcat", "strncat", "strcmp",
56 "strncmp", "strcpy", "strncpy", "strlen",
57 "index", "rindex", "strchr", "strrchr",
59 "strpbrk", "strspn", "strcspn", "strtok",
60 "strstr", "toupper", "tolower", "bcopy",
61 "bzero", "bcmp", "memcpy", "memset",
62 "memmove", "memcmp", "memchr", "rand",
64 "srand", "qsort", "strtod", "malloc",
65 "free", "lsearch", "bsearch", "calloc",
66 "realloc", "InitHeap", "_exit", "getchar",
67 "putchar", "gets", "puts", "printf",
69 "sys_a0_40", "LoadTest", "Load", "Exec",
70 "FlushCache", "InstallInterruptHandler", "GPU_dw", "mem2vram",
71 "SendGPUStatus", "GPU_cw", "GPU_cwb", "SendPackets",
72 "sys_a0_4c", "GetGPUStatus", "GPU_sync", "sys_a0_4f",
74 "sys_a0_50", "LoadExec", "GetSysSp", "sys_a0_53",
75 "_96_init()", "_bu_init()", "_96_remove()", "sys_a0_57",
76 "sys_a0_58", "sys_a0_59", "sys_a0_5a", "dev_tty_init",
77 "dev_tty_open", "sys_a0_5d", "dev_tty_ioctl","dev_cd_open",
79 "dev_cd_read", "dev_cd_close", "dev_cd_firstfile", "dev_cd_nextfile",
80 "dev_cd_chdir", "dev_card_open", "dev_card_read", "dev_card_write",
81 "dev_card_close", "dev_card_firstfile", "dev_card_nextfile","dev_card_erase",
82 "dev_card_undelete","dev_card_format", "dev_card_rename", "dev_card_6f",
84 "_bu_init", "_96_init", "CdRemove", "sys_a0_73",
85 "sys_a0_74", "sys_a0_75", "sys_a0_76", "sys_a0_77",
86 "_96_CdSeekL", "sys_a0_79", "sys_a0_7a", "sys_a0_7b",
87 "_96_CdGetStatus", "sys_a0_7d", "_96_CdRead", "sys_a0_7f",
89 "sys_a0_80", "sys_a0_81", "sys_a0_82", "sys_a0_83",
90 "sys_a0_84", "_96_CdStop", "sys_a0_86", "sys_a0_87",
91 "sys_a0_88", "sys_a0_89", "sys_a0_8a", "sys_a0_8b",
92 "sys_a0_8c", "sys_a0_8d", "sys_a0_8e", "sys_a0_8f",
94 "sys_a0_90", "sys_a0_91", "sys_a0_92", "sys_a0_93",
95 "sys_a0_94", "sys_a0_95", "AddCDROMDevice", "AddMemCardDevide",
96 "DisableKernelIORedirection", "EnableKernelIORedirection", "sys_a0_9a", "sys_a0_9b",
97 "SetConf", "GetConf", "sys_a0_9e", "SetMem",
99 "_boot", "SystemError", "EnqueueCdIntr", "DequeueCdIntr",
100 "sys_a0_a4", "ReadSector", "get_cd_status", "bufs_cb_0",
101 "bufs_cb_1", "bufs_cb_2", "bufs_cb_3", "_card_info",
102 "_card_load", "_card_auto", "bufs_cd_4", "sys_a0_af",
104 "sys_a0_b0", "sys_a0_b1", "do_a_long_jmp", "sys_a0_b3",
108 char *biosB0n[256] = {
110 "SysMalloc", "sys_b0_01", "sys_b0_02", "sys_b0_03",
111 "sys_b0_04", "sys_b0_05", "sys_b0_06", "DeliverEvent",
112 "OpenEvent", "CloseEvent", "WaitEvent", "TestEvent",
113 "EnableEvent", "DisableEvent", "OpenTh", "CloseTh",
115 "ChangeTh", "sys_b0_11", "InitPAD", "StartPAD",
116 "StopPAD", "PAD_init", "PAD_dr", "ReturnFromExecption",
117 "ResetEntryInt", "HookEntryInt", "sys_b0_1a", "sys_b0_1b",
118 "sys_b0_1c", "sys_b0_1d", "sys_b0_1e", "sys_b0_1f",
120 "UnDeliverEvent", "sys_b0_21", "sys_b0_22", "sys_b0_23",
121 "sys_b0_24", "sys_b0_25", "sys_b0_26", "sys_b0_27",
122 "sys_b0_28", "sys_b0_29", "sys_b0_2a", "sys_b0_2b",
123 "sys_b0_2c", "sys_b0_2d", "sys_b0_2e", "sys_b0_2f",
125 "sys_b0_30", "sys_b0_31", "open", "lseek",
126 "read", "write", "close", "ioctl",
127 "exit", "sys_b0_39", "getc", "putc",
128 "getchar", "putchar", "gets", "puts",
130 "cd", "format", "firstfile", "nextfile",
131 "rename", "delete", "undelete", "AddDevice",
132 "RemoteDevice", "PrintInstalledDevices", "InitCARD", "StartCARD",
133 "StopCARD", "sys_b0_4d", "_card_write", "_card_read",
135 "_new_card", "Krom2RawAdd", "sys_b0_52", "sys_b0_53",
136 "_get_errno", "_get_error", "GetC0Table", "GetB0Table",
137 "_card_chan", "sys_b0_59", "sys_b0_5a", "ChangeClearPAD",
138 "_card_status", "_card_wait",
141 char *biosC0n[256] = {
143 "InitRCnt", "InitException", "SysEnqIntRP", "SysDeqIntRP",
144 "get_free_EvCB_slot", "get_free_TCB_slot", "ExceptionHandler", "InstallExeptionHandler",
145 "SysInitMemory", "SysInitKMem", "ChangeClearRCnt", "SystemError",
146 "InitDefInt", "sys_c0_0d", "sys_c0_0e", "sys_c0_0f",
148 "sys_c0_10", "sys_c0_11", "InstallDevices", "FlushStfInOutPut",
149 "sys_c0_14", "_cdevinput", "_cdevscan", "_circgetc",
150 "_circputc", "ioabort", "sys_c0_1a", "KernelRedirect",
154 //#define r0 (psxRegs.GPR.n.r0)
155 #define at (psxRegs.GPR.n.at)
156 #define v0 (psxRegs.GPR.n.v0)
157 #define v1 (psxRegs.GPR.n.v1)
158 #define a0 (psxRegs.GPR.n.a0)
159 #define a1 (psxRegs.GPR.n.a1)
160 #define a2 (psxRegs.GPR.n.a2)
161 #define a3 (psxRegs.GPR.n.a3)
162 #define t0 (psxRegs.GPR.n.t0)
163 #define t1 (psxRegs.GPR.n.t1)
164 #define t2 (psxRegs.GPR.n.t2)
165 #define t3 (psxRegs.GPR.n.t3)
166 #define t4 (psxRegs.GPR.n.t4)
167 #define t5 (psxRegs.GPR.n.t5)
168 #define t6 (psxRegs.GPR.n.t6)
169 #define t7 (psxRegs.GPR.n.t7)
170 #define t8 (psxRegs.GPR.n.t8)
171 #define t9 (psxRegs.GPR.n.t9)
172 #define s0 (psxRegs.GPR.n.s0)
173 #define s1 (psxRegs.GPR.n.s1)
174 #define s2 (psxRegs.GPR.n.s2)
175 #define s3 (psxRegs.GPR.n.s3)
176 #define s4 (psxRegs.GPR.n.s4)
177 #define s5 (psxRegs.GPR.n.s5)
178 #define s6 (psxRegs.GPR.n.s6)
179 #define s7 (psxRegs.GPR.n.s7)
180 #define k0 (psxRegs.GPR.n.k0)
181 #define k1 (psxRegs.GPR.n.k1)
182 #define gp (psxRegs.GPR.n.gp)
183 #define sp (psxRegs.GPR.n.sp)
184 #define fp (psxRegs.GPR.n.s8)
185 #define ra (psxRegs.GPR.n.ra)
186 #define pc0 (psxRegs.pc)
188 #define Ra0 ((char *)PSXM(a0))
189 #define Ra1 ((char *)PSXM(a1))
190 #define Ra2 ((char *)PSXM(a2))
191 #define Ra3 ((char *)PSXM(a3))
192 #define Rv0 ((char *)PSXM(v0))
193 #define Rsp ((char *)PSXM(sp))
204 #define EvStUNUSED 0x0000
205 #define EvStDISABLED 0x1000
206 #define EvStACTIVE 0x2000
207 #define EvStALREADY 0x4000
209 #define EvMdCALL 0x1000
210 #define EvMdMARK 0x2000
233 u32 _sp, _fp, _gp, ret, base;
253 static int *pad_buf = NULL;
254 static u32 heap_size = 0;
255 static u32 *heap_addr = NULL;
256 static u32 *heap_end = NULL;
257 static FileDesc FDesc[32];
258 static u32 card_active_chan = 0;
260 // fixed RAM offsets, SCPH1001 compatible
261 #define A_TT_ExCB 0x0100
262 #define A_TT_PCB 0x0108
263 #define A_TT_TCB 0x0110
264 #define A_TT_EvCB 0x0120
265 #define A_A0_TABLE 0x0200
266 #define A_B0_TABLE 0x0874
267 #define A_C0_TABLE 0x0674
268 #define A_SYSCALL 0x0650
269 #define A_EXCEPTION 0x0c80
270 #define A_EXC_SP 0x6cf0
271 #define A_EEXIT_DEF 0x6cf4
272 #define A_KMALLOC_PTR 0x7460
273 #define A_KMALLOC_SIZE 0x7464
274 #define A_KMALLOC_END 0x7468
275 #define A_PADCRD_CHN_E 0x74a8 // pad/card irq chain entry
276 #define A_PAD_IRQR_ENA 0x74b8 // pad read on vint irq (nocash 'pad_enable_flag')
277 #define A_CARD_IRQR_ENA 0x74bc // same for card
278 #define A_PAD_INBUF 0x74c8 // 2x buffers for rx pad data
279 #define A_PAD_OUTBUF 0x74d0 // 2x buffers for tx pad data
280 #define A_PAD_IN_LEN 0x74d8
281 #define A_PAD_OUT_LEN 0x74e0
282 #define A_EEXIT_PTR 0x75d0
283 #define A_EXC_STACK 0x85d8 // exception stack top
284 #define A_RCNT_VBL_ACK 0x8600
285 #define A_PAD_ACK_VBL 0x8914 // enable vint ack by pad reading code
286 #define A_CD_EVENTS 0xb9b8
287 #define A_EXC_GP 0xf450
289 #define HLEOP(n) SWAPu32((0x3b << 26) | (n));
291 static u32 loadRam32(u32 addr)
293 assert(!(addr & 0x5f800000));
294 return SWAP32(*((u32 *)psxM + ((addr & 0x1fffff) >> 2)));
297 static void *castRam8ptr(u32 addr)
299 assert(!(addr & 0x5f800000));
300 return psxM + (addr & 0x1fffff);
303 static void *castRam32ptr(u32 addr)
305 assert(!(addr & 0x5f800003));
306 return psxM + (addr & 0x1ffffc);
309 static void *loadRam8ptr(u32 addr)
311 return castRam8ptr(loadRam32(addr));
314 static void *loadRam32ptr(u32 addr)
316 return castRam32ptr(loadRam32(addr));
319 static void storeRam8(u32 addr, u8 d)
321 assert(!(addr & 0x5f800000));
322 *((u8 *)psxM + (addr & 0x1fffff)) = d;
325 static void storeRam32(u32 addr, u32 d)
327 assert(!(addr & 0x5f800000));
328 *((u32 *)psxM + ((addr & 0x1fffff) >> 2)) = SWAP32(d);
331 static void mips_return(u32 val)
337 static void use_cycles(u32 cycle)
339 psxRegs.cycle += cycle * 2;
342 static void mips_return_c(u32 val, u32 cycle)
348 static void mips_return_void_c(u32 cycle)
354 static int returned_from_exception(void)
356 // 0x80000080 means it took another exception just after return
357 return pc0 == k0 || pc0 == 0x80000080;
360 static inline void softCall(u32 pc) {
362 u32 ssr = psxRegs.CP0.n.SR;
365 psxRegs.CP0.n.SR &= ~0x404; // disable interrupts
367 while (pc0 != 0x80001000)
368 psxCpu->ExecuteBlock(EXEC_CALLER_HLE);
371 psxRegs.CP0.n.SR = ssr;
374 static inline void softCallInException(u32 pc) {
379 while (!returned_from_exception() && pc0 != 0x80001000)
380 psxCpu->ExecuteBlock(EXEC_CALLER_HLE);
382 if (pc0 == 0x80001000)
386 static u32 OpenEvent(u32 class, u32 spec, u32 mode, u32 func);
387 static u32 DeliverEvent(u32 class, u32 spec);
388 static u32 UnDeliverEvent(u32 class, u32 spec);
389 static void CloseEvent(u32 ev);
394 // System calls A0 */
397 #define buread(Ra1, mcd, length) { \
398 SysPrintf("read %d: %x,%x (%s)\n", FDesc[1 + mcd].mcfile, FDesc[1 + mcd].offset, a2, Mcd##mcd##Data + 128 * FDesc[1 + mcd].mcfile + 0xa); \
399 ptr = Mcd##mcd##Data + 8192 * FDesc[1 + mcd].mcfile + FDesc[1 + mcd].offset; \
400 memcpy(Ra1, ptr, length); \
401 if (FDesc[1 + mcd].mode & 0x8000) { \
402 DeliverEvent(0xf0000011, 0x0004); \
403 DeliverEvent(0xf4000001, 0x0004); \
406 FDesc[1 + mcd].offset += v0; \
409 #define buwrite(Ra1, mcd, length) { \
410 u32 offset = + 8192 * FDesc[1 + mcd].mcfile + FDesc[1 + mcd].offset; \
411 SysPrintf("write %d: %x,%x\n", FDesc[1 + mcd].mcfile, FDesc[1 + mcd].offset, a2); \
412 ptr = Mcd##mcd##Data + offset; \
413 memcpy(ptr, Ra1, length); \
414 FDesc[1 + mcd].offset += length; \
415 SaveMcd(Config.Mcd##mcd, Mcd##mcd##Data, offset, length); \
416 if (FDesc[1 + mcd].mode & 0x8000) { \
417 DeliverEvent(0xf0000011, 0x0004); \
418 DeliverEvent(0xf4000001, 0x0004); \
424 //#define PSXBIOS_LOG printf
425 #define PSXBIOS_LOG(...)
428 /* Internally redirects to "FileRead(fd,tempbuf,1)".*/
429 /* For some strange reason, the returned character is sign-expanded; */
430 /* So if a return value of FFFFFFFFh could mean either character FFh, or error. */
431 /* TODO FIX ME : Properly implement this behaviour */
432 void psxBios_getc(void) // 0x03, 0x35
437 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x03]);
441 if (pa1 != INVALID_PTR) {
443 case 2: buread(pa1, 1, 1); break;
444 case 3: buread(pa1, 2, 1); break;
451 /* Copy of psxBios_write, except size is 1. */
452 void psxBios_putc(void) // 0x09, 0x3B
457 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x09]);
460 if (pa1 == INVALID_PTR) {
465 if (a0 == 1) { // stdout
466 char *ptr = (char *)pa1;
470 printf("%c", *ptr++); a2--;
476 case 2: buwrite(pa1, 1, 1); break;
477 case 3: buwrite(pa1, 2, 1); break;
483 void psxBios_todigit(void) // 0x0a
487 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x0a]);
490 if (c >= 0x30 && c < 0x3A) {
493 else if (c > 0x60 && c < 0x7B) {
496 else if (c > 0x40 && c < 0x5B) {
499 else if (c >= 0x80) {
510 void psxBios_abs() { // 0x0e
511 if ((s32)a0 < 0) v0 = -(s32)a0;
516 void psxBios_labs() { // 0x0f
520 void psxBios_atoi() { // 0x10
522 char *p = (char *)Ra0;
526 case ' ': case '\t': continue;
533 while (*p >= '0' && *p <= '9') {
534 n = n * 10 + *p++ - '0';
541 void psxBios_atol() { // 0x11
551 static void psxBios_setjmp() { // 0x13
552 struct jmp_buf_ *jmp_buf = castRam32ptr(a0);
555 PSXBIOS_LOG("psxBios_%s %x\n", biosA0n[0x13], a0);
557 jmp_buf->ra_ = SWAP32(ra);
558 jmp_buf->sp_ = SWAP32(sp);
559 jmp_buf->fp_ = SWAP32(fp);
560 for (i = 0; i < 8; i++) // s0-s7
561 jmp_buf->s[i] = SWAP32(psxRegs.GPR.r[16 + i]);
562 jmp_buf->gp_ = SWAP32(gp);
564 mips_return_c(0, 15);
567 static void longjmp_load(const struct jmp_buf_ *jmp_buf)
571 ra = SWAP32(jmp_buf->ra_);
572 sp = SWAP32(jmp_buf->sp_);
573 fp = SWAP32(jmp_buf->fp_);
574 for (i = 0; i < 8; i++) // s0-s7
575 psxRegs.GPR.r[16 + i] = SWAP32(jmp_buf->s[i]);
576 gp = SWAP32(jmp_buf->gp_);;
579 void psxBios_longjmp() { // 0x14
580 struct jmp_buf_ *jmp_buf = castRam32ptr(a0);
582 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x14]);
583 longjmp_load(jmp_buf);
584 mips_return_c(a1, 15);
587 void psxBios_strcat() { // 0x15
588 char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
591 PSXBIOS_LOG("psxBios_%s: %s, %s\n", biosA0n[0x15], Ra0, Ra1);
593 if (a0 == 0 || a1 == 0)
601 while ((*p1++ = *p2++) != '\0');
606 void psxBios_strncat() { // 0x16
607 char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
611 PSXBIOS_LOG("psxBios_%s: %s (%x), %s (%x), %d\n", biosA0n[0x16], Ra0, a0, Ra1, a1, a2);
613 if (a0 == 0 || a1 == 0)
621 while ((*p1++ = *p2++) != '\0') {
631 void psxBios_strcmp() { // 0x17
632 char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
634 if (a0 == 0 && a1 == 0)
640 else if (a0 == 0 && a1 != 0)
646 else if (a0 != 0 && a1 == 0)
653 PSXBIOS_LOG("psxBios_%s: %s (%x), %s (%x)\n", biosA0n[0x17], Ra0, a0, Ra1, a1);
656 while (*p1 == *p2++) {
675 void psxBios_strncmp() { // 0x18
676 char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
678 if (a0 == 0 && a1 == 0)
684 else if (a0 == 0 && a1 != 0)
690 else if (a0 != 0 && a1 == 0)
697 PSXBIOS_LOG("psxBios_%s: %s (%x), %s (%x), %d\n", biosA0n[0x18], Ra0, a0, Ra1, a1, a2);
700 while (--n >= 0 && *p1 == *p2++) {
704 v1 = a2 - ((a2-n) - 1);
712 v0 = (n < 0 ? 0 : *p1 - *--p2);
714 v1 = a2 - ((a2-n) - 1);
720 void psxBios_strcpy() { // 0x19
721 char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
722 if (a0 == 0 || a1 == 0)
728 while ((*p1++ = *p2++) != '\0');
733 void psxBios_strncpy() { // 0x1a
734 char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
736 if (a0 == 0 || a1 == 0)
742 for (i = 0; i < n; i++) {
743 if ((*p1++ = *p2++) == '\0') {
755 void psxBios_strlen() { // 0x1b
756 char *p = (char *)Ra0;
767 void psxBios_index() { // 0x1c
768 char *p = (char *)Ra0;
778 v0 = a0 + (p - (char *)Ra0);
782 } while (*p++ != '\0');
787 void psxBios_rindex() { // 0x1d
788 char *p = (char *)Ra0;
798 v0 = a0 + (p - (char *)Ra0);
799 } while (*p++ != '\0');
804 void psxBios_strchr() { // 0x1e
808 void psxBios_strrchr() { // 0x1f
812 void psxBios_strpbrk() { // 0x20
813 char *p1 = (char *)Ra0, *p2 = (char *)Ra1, *scanp, c, sc;
815 while ((c = *p1++) != '\0') {
816 for (scanp = p2; (sc = *scanp++) != '\0';) {
818 v0 = a0 + (p1 - 1 - (char *)Ra0);
825 // BUG: return a0 instead of NULL if not found
829 void psxBios_strspn() { // 0x21
832 for (p1 = (char *)Ra0; *p1 != '\0'; p1++) {
833 for (p2 = (char *)Ra1; *p2 != '\0' && *p2 != *p1; p2++);
834 if (*p2 == '\0') break;
837 v0 = p1 - (char *)Ra0; pc0 = ra;
840 void psxBios_strcspn() { // 0x22
843 for (p1 = (char *)Ra0; *p1 != '\0'; p1++) {
844 for (p2 = (char *)Ra1; *p2 != '\0' && *p2 != *p1; p2++);
845 if (*p2 != '\0') break;
848 v0 = p1 - (char *)Ra0; pc0 = ra;
851 void psxBios_strtok() { // 0x23
852 char *pcA0 = (char *)Ra0;
853 char *pcRet = strtok(pcA0, (char *)Ra1);
855 v0 = a0 + pcRet - pcA0;
861 void psxBios_strstr() { // 0x24
862 char *p = (char *)Ra0, *p1, *p2;
868 while (*p1 != '\0' && *p2 != '\0' && *p1 == *p2) {
873 v0 = a0 + (p - (char *)Ra0);
884 void psxBios_toupper() { // 0x25
885 v0 = (s8)(a0 & 0xff);
886 if (v0 >= 'a' && v0 <= 'z') v0 -= 'a' - 'A';
890 void psxBios_tolower() { // 0x26
891 v0 = (s8)(a0 & 0xff);
892 if (v0 >= 'A' && v0 <= 'Z') v0 += 'a' - 'A';
896 void psxBios_bcopy() { // 0x27
897 char *p1 = (char *)Ra1, *p2 = (char *)Ra0;
899 if (a0 == 0 || a2 > 0x7FFFFFFF)
904 while ((s32)a2-- > 0) *p1++ = *p2++;
909 void psxBios_bzero() { // 0x28
910 char *p = (char *)Ra0;
912 /* Same as memset here (See memset below) */
913 if (a1 > 0x7FFFFFFF || a1 == 0)
924 while ((s32)a1-- > 0) *p++ = '\0';
929 void psxBios_bcmp() { // 0x29
930 char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
932 if (a0 == 0 || a1 == 0) { v0 = 0; pc0 = ra; return; }
934 while ((s32)a2-- > 0) {
935 if (*p1++ != *p2++) {
936 v0 = *p1 - *p2; // BUG: compare the NEXT byte
945 void psxBios_memcpy() { // 0x2a
946 char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
948 if (a0 == 0 || a2 > 0x7FFFFFFF)
953 while ((s32)a2-- > 0) {
960 void psxBios_memset() { // 0x2b
961 char *p = (char *)Ra0;
963 if (a2 > 0x7FFFFFFF || a2 == 0)
974 while ((s32)a2-- > 0) *p++ = (char)a1;
979 void psxBios_memmove() { // 0x2c
980 char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
982 if (a0 == 0 || a2 > 0x7FFFFFFF)
987 if (p2 <= p1 && p2 + a2 > p1) {
988 a2++; // BUG: copy one more byte here
991 while ((s32)a2-- > 0) *--p1 = *--p2;
993 while ((s32)a2-- > 0) *p1++ = *p2++;
998 void psxBios_memcmp() { // 0x2d
1002 void psxBios_memchr() { // 0x2e
1003 char *p = (char *)Ra0;
1005 if (a0 == 0 || a2 > 0x7FFFFFFF)
1011 while ((s32)a2-- > 0) {
1012 if (*p++ != (s8)a1) continue;
1013 v0 = a0 + (p - (char *)Ra0 - 1);
1021 void psxBios_rand() { // 0x2f
1022 u32 s = psxMu32(0x9010) * 1103515245 + 12345;
1023 v0 = (s >> 16) & 0x7fff;
1024 psxMu32ref(0x9010) = SWAPu32(s);
1028 void psxBios_srand() { // 0x30
1029 psxMu32ref(0x9010) = SWAPu32(a0);
1033 static u32 qscmpfunc, qswidth;
1035 static inline int qscmp(char *a, char *b) {
1038 a0 = sa0 + (a - (char *)PSXM(sa0));
1039 a1 = sa0 + (b - (char *)PSXM(sa0));
1041 softCall(qscmpfunc);
1047 static inline void qexchange(char *i, char *j) {
1058 static inline void q3exchange(char *i, char *j, char *k) {
1070 static void qsort_main(char *a, char *l) {
1071 char *i, *j, *lp, *hp;
1076 if ((n = l - a) <= qswidth)
1078 n = qswidth * (n / (2 * qswidth));
1084 if ((c = qscmp(i, lp)) == 0) {
1085 qexchange(i, lp -= qswidth);
1096 if ((c = qscmp(hp, j)) == 0) {
1097 qexchange(hp += qswidth, j);
1102 q3exchange(i, hp += qswidth, j);
1116 if (lp - a >= l - hp) {
1117 qsort_main(hp + qswidth, l);
1126 q3exchange(j, lp -= qswidth, i);
1131 void psxBios_qsort() { // 0x31
1134 qsort_main((char *)Ra0, (char *)Ra0 + a1 * a2);
1139 void psxBios_malloc() { // 0x33
1140 u32 *chunk, *newchunk = NULL;
1141 unsigned int dsize = 0, csize, cstat;
1144 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x33]);
1146 if (!a0 || (!heap_size || !heap_addr)) {
1152 // scan through heap and combine free chunks of space
1155 while(chunk < heap_end) {
1156 // get size and status of actual chunk
1157 csize = ((u32)*chunk) & 0xfffffffc;
1158 cstat = ((u32)*chunk) & 1;
1160 // most probably broken heap descriptor
1161 // this fixes Burning Road
1164 dsize = ((uptr)heap_end - (uptr)chunk) - 4;
1169 // it's a free chunk
1174 colflag = 1; // let's begin a new collection of free memory
1176 else dsize += (csize+4); // add the new size including header
1178 // not a free chunk: did we start a collection ?
1180 if(colflag == 1) { // collection is over
1182 *newchunk = SWAP32(dsize | 1);
1187 chunk = (u32*)((uptr)chunk + csize + 4);
1189 // if neccessary free memory on end of heap
1191 *newchunk = SWAP32(dsize | 1);
1194 csize = ((u32)*chunk) & 0xfffffffc;
1195 cstat = ((u32)*chunk) & 1;
1196 dsize = (a0 + 3) & 0xfffffffc;
1198 // exit on uninitialized heap
1199 if (chunk == NULL) {
1200 printf("malloc %x,%x: Uninitialized Heap!\n", v0, a0);
1206 // search an unused chunk that is big enough until the end of the heap
1207 while ((dsize > csize || cstat==0) && chunk < heap_end ) {
1208 chunk = (u32*)((uptr)chunk + csize + 4);
1210 // catch out of memory
1211 if(chunk >= heap_end) {
1212 printf("malloc %x,%x: Out of memory error!\n",
1218 csize = ((u32)*chunk) & 0xfffffffc;
1219 cstat = ((u32)*chunk) & 1;
1223 if(dsize == csize) {
1224 // chunk has same size
1225 *chunk &= 0xfffffffc;
1226 } else if (dsize > csize) {
1231 *chunk = SWAP32(dsize);
1232 newchunk = (u32*)((uptr)chunk + dsize + 4);
1233 *newchunk = SWAP32(((csize - dsize - 4) & 0xfffffffc) | 1);
1236 // return pointer to allocated memory
1237 v0 = ((uptr)chunk - (uptr)psxM) + 4;
1239 //printf ("malloc %x,%x\n", v0, a0);
1243 void psxBios_free() { // 0x34
1246 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x34]);
1249 SysPrintf("free %x: %x bytes\n", a0, *(u32*)(Ra0-4));
1252 *(u32*)(Ra0-4) |= 1; // set chunk to free
1256 void psxBios_calloc() { // 0x37
1259 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x37]);
1269 void psxBios_realloc() { // 0x38
1273 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x38]);
1277 /* If "old_buf" is zero, executes malloc(new_size), and returns r2=new_buf (or 0=failed). */
1282 /* Else, if "new_size" is zero, executes free(old_buf), and returns r2=garbage. */
1287 /* Else, executes malloc(new_size), bcopy(old_buf,new_buf,new_size), and free(old_buf), and returns r2=new_buf (or 0=failed). */
1288 /* Note that it is not quite implemented this way here. */
1298 /* InitHeap(void *block , int n) */
1299 void psxBios_InitHeap() { // 0x39
1303 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x39]);
1306 if (((a0 & 0x1fffff) + a1)>= 0x200000) size = 0x1ffffc - (a0 & 0x1fffff);
1311 heap_addr = (u32 *)Ra0;
1313 heap_end = (u32 *)((u8 *)heap_addr + heap_size);
1314 /* HACKFIX: Commenting out this line fixes GTA2 crash */
1315 //*heap_addr = SWAP32(size | 1);
1317 SysPrintf("InitHeap %x,%x : %x %x\n",a0,a1, (int)((uptr)heap_addr-(uptr)psxM), size);
1322 void psxBios_getchar() { //0x3b
1323 v0 = getchar(); pc0 = ra;
1326 static void psxBios_printf_psxout() { // 0x3f
1335 if (psp != INVALID_PTR) {
1336 memcpy(save, psp, 4 * 4);
1337 psxMu32ref(sp) = SWAP32((u32)a0);
1338 psxMu32ref(sp + 4) = SWAP32((u32)a1);
1339 psxMu32ref(sp + 8) = SWAP32((u32)a2);
1340 psxMu32ref(sp + 12) = SWAP32((u32)a3);
1352 tmp2[j++] = Ra0[i]; goto _start;
1354 if (Ra0[i] >= '0' && Ra0[i] <= '9') {
1365 ptmp += sprintf(ptmp, tmp2, (float)psxMu32(sp + n * 4)); n++; break;
1369 ptmp += sprintf(ptmp, tmp2, (double)psxMu32(sp + n * 4)); n++; break;
1375 ptmp += sprintf(ptmp, tmp2, (unsigned int)psxMu32(sp + n * 4)); n++; break;
1377 ptmp += sprintf(ptmp, tmp2, (unsigned char)psxMu32(sp + n * 4)); n++; break;
1379 ptmp += sprintf(ptmp, tmp2, (char*)PSXM(psxMu32(sp + n * 4))); n++; break;
1381 *ptmp++ = Ra0[i]; break;
1391 if (psp != INVALID_PTR)
1392 memcpy(psp, save, 4 * 4);
1394 SysPrintf("%s", tmp);
1397 void psxBios_printf() { // 0x3f
1398 psxBios_printf_psxout();
1402 void psxBios_format() { // 0x41
1403 if (strcmp(Ra0, "bu00:") == 0 && Config.Mcd1[0] != '\0')
1405 CreateMcd(Config.Mcd1);
1406 LoadMcd(1, Config.Mcd1);
1409 else if (strcmp(Ra0, "bu10:") == 0 && Config.Mcd2[0] != '\0')
1411 CreateMcd(Config.Mcd2);
1412 LoadMcd(2, Config.Mcd2);
1422 static void psxBios_SystemErrorUnresolvedException() {
1423 if (loadRam32(0xfffc) != 0x12345678) { // prevent log flood
1424 SysPrintf("psxBios_%s\n", biosA0n[0x40]);
1425 storeRam32(0xfffc, 0x12345678);
1427 mips_return_void_c(1000);
1431 * long Load(char *name, struct EXEC *header);
1434 void psxBios_Load() { // 0x42
1439 if (pa1 && LoadCdromFile(Ra0, &eheader) == 0) {
1440 memcpy(pa1, ((char*)&eheader)+16, sizeof(EXEC));
1443 PSXBIOS_LOG("psxBios_%s: %s, %d -> %d\n", biosA0n[0x42], Ra0, a1, v0);
1449 * int Exec(struct EXEC *header , int argc , char **argv);
1452 void psxBios_Exec() { // 43
1453 EXEC *header = (EXEC*)Ra0;
1457 PSXBIOS_LOG("psxBios_%s: %x, %x, %x\n", biosA0n[0x43], a0, a1, a2);
1467 if (header->S_addr != 0) {
1468 tmp = header->S_addr + header->s_size;
1484 void psxBios_FlushCache() { // 44
1486 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x44]);
1488 psxCpu->Notify(R3000ACPU_NOTIFY_CACHE_ISOLATED, NULL);
1489 psxCpu->Notify(R3000ACPU_NOTIFY_CACHE_UNISOLATED, NULL);
1493 void psxBios_GPU_dw() { // 0x46
1498 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x46]);
1501 GPU_writeData(0xa0000000);
1502 GPU_writeData((a1<<0x10)|(a0&0xffff));
1503 GPU_writeData((a3<<0x10)|(a2&0xffff));
1505 ptr = (u32*)PSXM(Rsp[4]); //that is correct?
1508 GPU_writeData(SWAPu32(*ptr++));
1514 void psxBios_mem2vram() { // 0x47
1517 GPU_writeData(0xa0000000);
1518 GPU_writeData((a1<<0x10)|(a0&0xffff));
1519 GPU_writeData((a3<<0x10)|(a2&0xffff));
1520 size = ((((a2 * a3) / 2) >> 4) << 16);
1521 GPU_writeStatus(0x04000002);
1522 psxHwWrite32(0x1f8010f4,0);
1523 psxHwWrite32(0x1f8010f0,psxHwRead32(0x1f8010f0)|0x800);
1524 psxHwWrite32(0x1f8010a0,Rsp[4]);//might have a buggy...
1525 psxHwWrite32(0x1f8010a4, size | 0x10);
1526 psxHwWrite32(0x1f8010a8,0x01000201);
1531 void psxBios_SendGPU() { // 0x48
1532 GPU_writeStatus(a0);
1537 void psxBios_GPU_cw() { // 0x49
1544 void psxBios_GPU_cwb() { // 0x4a
1545 u32 *ptr = (u32*)Ra0;
1550 GPU_writeData(SWAPu32(*ptr++));
1556 void psxBios_GPU_SendPackets() { //4b:
1558 GPU_writeStatus(0x04000002);
1559 psxHwWrite32(0x1f8010f4,0);
1560 psxHwWrite32(0x1f8010f0,psxHwRead32(0x1f8010f0)|0x800);
1561 psxHwWrite32(0x1f8010a0,a0);
1562 psxHwWrite32(0x1f8010a4,0);
1563 psxHwWrite32(0x1f8010a8,0x010000401);
1567 void psxBios_sys_a0_4c() { // 0x4c GPU relate
1568 psxHwWrite32(0x1f8010a8,0x00000401);
1569 GPU_writeData(0x0400000);
1570 GPU_writeData(0x0200000);
1571 GPU_writeData(0x0100000);
1576 void psxBios_GPU_GetGPUStatus() { // 0x4d
1577 v0 = GPU_readStatus();
1583 void psxBios_LoadExec() { // 51
1584 EXEC *header = (EXEC*)PSXM(0xf000);
1588 PSXBIOS_LOG("psxBios_%s: %s: %x,%x\n", biosA0n[0x51], Ra0, a1, a2);
1590 s_addr = a1; s_size = a2;
1595 header->S_addr = s_addr;
1596 header->s_size = s_size;
1598 a0 = 0xf000; a1 = 0; a2 = 0;
1602 void psxBios__bu_init() { // 70
1604 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x70]);
1607 DeliverEvent(0xf0000011, 0x0004);
1608 DeliverEvent(0xf4000001, 0x0004);
1613 void psxBios__96_init() { // 71
1615 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x71]);
1621 static void write_chain(u32 *d, u32 next, u32 handler1, u32 handler2);
1622 static void psxBios_SysEnqIntRP_(u32 priority, u32 chain_eptr);
1623 static void psxBios_SysDeqIntRP_(u32 priority, u32 chain_rm_eptr);
1625 static void psxBios_DequeueCdIntr_() {
1626 psxBios_SysDeqIntRP_(0, 0x91d0);
1627 psxBios_SysDeqIntRP_(0, 0x91e0);
1631 static void psxBios_DequeueCdIntr() { // a3
1632 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0xa3]);
1633 psxBios_DequeueCdIntr_();
1636 static void psxBios_CdRemove() { // 56, 72
1637 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x72]);
1639 CloseEvent(loadRam32(A_CD_EVENTS + 0x00));
1640 CloseEvent(loadRam32(A_CD_EVENTS + 0x04));
1641 CloseEvent(loadRam32(A_CD_EVENTS + 0x08));
1642 CloseEvent(loadRam32(A_CD_EVENTS + 0x0c));
1643 CloseEvent(loadRam32(A_CD_EVENTS + 0x10));
1644 psxBios_DequeueCdIntr_();
1646 // EnterCriticalSection - should be done at the beginning,
1647 // but this way is much easier to implement
1653 void psxBios_SetMem() { // 9f
1654 u32 new = psxHu32(0x1060);
1657 PSXBIOS_LOG("psxBios_%s: %x, %x\n", biosA0n[0x9f], a0, a1);
1662 psxHu32ref(0x1060) = SWAP32(new);
1663 psxMu32ref(0x060) = a0;
1664 SysPrintf("Change effective memory : %d MBytes\n",a0);
1668 psxHu32ref(0x1060) = SWAP32(new | 0x300);
1669 psxMu32ref(0x060) = a0;
1670 SysPrintf("Change effective memory : %d MBytes\n",a0);
1673 SysPrintf("Effective memory must be 2/8 MBytes\n");
1680 /* TODO FIXME : Not compliant. -1 indicates failure but using 1 for now. */
1681 void psxBios_get_cd_status(void) //a6
1687 void psxBios__card_info() { // ab
1689 PSXBIOS_LOG("psxBios_%s: %x\n", biosA0n[0xab], a0);
1692 card_active_chan = a0;
1693 port = card_active_chan >> 4;
1699 if (McdDisable[port & 1])
1704 PSXBIOS_LOG("psxBios_%s: UNKNOWN PORT 0x%x\n", biosA0n[0xab], card_active_chan);
1710 if (McdDisable[0] && McdDisable[1])
1713 DeliverEvent(0xf0000011, 0x0004);
1714 // DeliverEvent(0xf4000001, 0x0004);
1715 DeliverEvent(0xf4000001, ret);
1719 void psxBios__card_load() { // ac
1721 PSXBIOS_LOG("psxBios_%s: %x\n", biosA0n[0xac], a0);
1724 card_active_chan = a0;
1726 // DeliverEvent(0xf0000011, 0x0004);
1727 DeliverEvent(0xf4000001, 0x0004);
1732 /* System calls B0 */
1734 static u32 psxBios_SysMalloc_(u32 size);
1736 static void psxBios_SysMalloc() { // B 00
1737 u32 ret = psxBios_SysMalloc_(a0);
1739 PSXBIOS_LOG("psxBios_%s 0x%x -> %x\n", biosB0n[0x00], a0, ret);
1740 mips_return_c(ret, 33);
1743 void psxBios_SetRCnt() { // 02
1745 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x02]);
1752 psxRcntWtarget(a0, a1);
1753 if (a2&0x1000) mode|= 0x050; // Interrupt Mode
1754 if (a2&0x0100) mode|= 0x008; // Count to 0xffff
1755 if (a2&0x0010) mode|= 0x001; // Timer stop mode
1756 if (a0 == 2) { if (a2&0x0001) mode|= 0x200; } // System Clock mode
1757 else { if (a2&0x0001) mode|= 0x100; } // System Clock mode
1759 psxRcntWmode(a0, mode);
1764 void psxBios_GetRCnt() { // 03
1766 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x03]);
1770 if (a0 != 3) v0 = psxRcntRcount(a0);
1775 void psxBios_StartRCnt() { // 04
1777 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x04]);
1781 if (a0 != 3) psxHu32ref(0x1074)|= SWAP32((u32)((1<<(a0+4))));
1782 else psxHu32ref(0x1074)|= SWAPu32(0x1);
1786 void psxBios_StopRCnt() { // 05
1788 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x05]);
1792 if (a0 != 3) psxHu32ref(0x1074)&= SWAP32((u32)(~(1<<(a0+4))));
1793 else psxHu32ref(0x1074)&= SWAPu32(~0x1);
1797 void psxBios_ResetRCnt() { // 06
1799 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x06]);
1804 psxRcntWmode(a0, 0);
1805 psxRcntWtarget(a0, 0);
1806 psxRcntWcount(a0, 0);
1811 static u32 DeliverEvent(u32 class, u32 spec) {
1812 EvCB *ev = (EvCB *)loadRam32ptr(A_TT_EvCB);
1813 u32 evcb_len = loadRam32(A_TT_EvCB + 4);
1814 u32 ret = loadRam32(A_TT_EvCB) + evcb_len;
1815 u32 i, lim = evcb_len / 0x1c;
1817 for (i = 0; i < lim; i++, ev++) {
1819 if (SWAP32(ev->status) != EvStACTIVE)
1822 if (SWAP32(ev->class) != class)
1825 if (SWAP32(ev->spec) != spec)
1828 ret = SWAP32(ev->mode);
1829 if (ret == EvMdMARK) {
1830 ev->status = SWAP32(EvStALREADY);
1834 if (ret == EvMdCALL) {
1835 ret = SWAP32(ev->fhandler);
1847 static u32 UnDeliverEvent(u32 class, u32 spec) {
1848 EvCB *ev = (EvCB *)loadRam32ptr(A_TT_EvCB);
1849 u32 evcb_len = loadRam32(A_TT_EvCB + 4);
1850 u32 ret = loadRam32(A_TT_EvCB) + evcb_len;
1851 u32 i, lim = evcb_len / 0x1c;
1853 for (i = 0; i < lim; i++, ev++) {
1855 if (SWAP32(ev->status) != EvStALREADY)
1858 if (SWAP32(ev->class) != class)
1861 if (SWAP32(ev->spec) != spec)
1864 if (SWAP32(ev->mode) == EvMdMARK)
1865 ev->status = SWAP32(EvStACTIVE);
1871 static void psxBios_DeliverEvent() { // 07
1873 PSXBIOS_LOG("psxBios_%s %x %04x\n", biosB0n[0x07], a0, a1);
1875 ret = DeliverEvent(a0, a1);
1879 static s32 get_free_EvCB_slot() {
1880 EvCB *ev = (EvCB *)loadRam32ptr(A_TT_EvCB);
1881 u32 i, lim = loadRam32(A_TT_EvCB + 4) / 0x1c;
1884 for (i = 0; i < lim; i++, ev++) {
1886 if (ev->status == SWAP32(EvStUNUSED))
1892 static u32 OpenEvent(u32 class, u32 spec, u32 mode, u32 func) {
1893 u32 ret = get_free_EvCB_slot();
1894 if ((s32)ret >= 0) {
1895 EvCB *ev = (EvCB *)loadRam32ptr(A_TT_EvCB) + ret;
1896 ev->class = SWAP32(class);
1897 ev->status = SWAP32(EvStDISABLED);
1898 ev->spec = SWAP32(spec);
1899 ev->mode = SWAP32(mode);
1900 ev->fhandler = SWAP32(func);
1906 static void psxBios_OpenEvent() { // 08
1907 u32 ret = OpenEvent(a0, a1, a2, a3);
1908 PSXBIOS_LOG("psxBios_%s (class:%x, spec:%04x, mode:%04x, func:%x) -> %x\n",
1909 biosB0n[0x08], a0, a1, a2, a3, ret);
1910 mips_return_c(ret, 36);
1913 static void CloseEvent(u32 ev)
1915 u32 base = loadRam32(A_TT_EvCB);
1916 storeRam32(base + (ev & 0xffff) * sizeof(EvCB) + 4, EvStUNUSED);
1919 static void psxBios_CloseEvent() { // 09
1920 PSXBIOS_LOG("psxBios_%s %x (%x)\n", biosB0n[0x09], a0,
1921 loadRam32(loadRam32(A_TT_EvCB) + (a0 & 0xffff) * sizeof(EvCB) + 4));
1923 mips_return_c(1, 10);
1926 static void psxBios_WaitEvent() { // 0a
1927 u32 base = loadRam32(A_TT_EvCB);
1928 u32 status = loadRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4);
1929 PSXBIOS_LOG("psxBios_%s %x (status=%x)\n", biosB0n[0x0a], a0, status);
1932 if (status == EvStALREADY) {
1933 storeRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4, EvStACTIVE);
1937 if (status != EvStACTIVE)
1939 mips_return_c(0, 2);
1943 // retrigger this hlecall after the next emulation event
1945 if ((s32)(next_interupt - psxRegs.cycle) > 0)
1946 psxRegs.cycle = next_interupt;
1950 static void psxBios_TestEvent() { // 0b
1951 u32 base = loadRam32(A_TT_EvCB);
1952 u32 status = loadRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4);
1954 PSXBIOS_LOG("psxBios_%s %x %x\n", biosB0n[0x0b], a0, status);
1955 if (status == EvStALREADY) {
1956 storeRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4, EvStACTIVE);
1960 mips_return_c(ret, 15);
1963 static void psxBios_EnableEvent() { // 0c
1964 u32 base = loadRam32(A_TT_EvCB);
1965 u32 status = loadRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4);
1966 PSXBIOS_LOG("psxBios_%s %x (%x)\n", biosB0n[0x0c], a0, status);
1967 if (status != EvStUNUSED)
1968 storeRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4, EvStACTIVE);
1970 mips_return_c(1, 15);
1973 static void psxBios_DisableEvent() { // 0d
1974 u32 base = loadRam32(A_TT_EvCB);
1975 u32 status = loadRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4);
1976 PSXBIOS_LOG("psxBios_%s %x: %x\n", biosB0n[0x0d], a0, status);
1977 if (status != EvStUNUSED)
1978 storeRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4, EvStDISABLED);
1980 mips_return_c(1, 15);
1984 * long OpenTh(long (*func)(), unsigned long sp, unsigned long gp);
1987 void psxBios_OpenTh() { // 0e
1988 TCB *tcb = loadRam32ptr(A_TT_TCB);
1989 u32 limit = loadRam32(A_TT_TCB + 4) / 0xc0u;
1992 for (th = 1; th < limit; th++)
1994 if (tcb[th].status != SWAP32(0x4000)) break;
1998 // Feb 2019 - Added out-of-bounds fix caught by cppcheck:
1999 // When no free TCB is found, return 0xffffffff according to Nocash doc.
2001 PSXBIOS_LOG("\t%s() WARNING! No Free TCBs found!\n", __func__);
2003 mips_return_c(0xffffffff, 20);
2006 PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x0e], th);
2008 tcb[th].status = SWAP32(0x4000);
2009 tcb[th].mode = SWAP32(0x1000);
2010 tcb[th].epc = SWAP32(a0);
2011 tcb[th].reg[30] = SWAP32(a1); // fp
2012 tcb[th].reg[29] = SWAP32(a1); // sp
2013 tcb[th].reg[28] = SWAP32(a2); // gp
2015 mips_return_c(0xff000000 + th, 34);
2019 * int CloseTh(long thread);
2022 void psxBios_CloseTh() { // 0f
2023 TCB *tcb = loadRam32ptr(A_TT_TCB);
2024 u32 limit = loadRam32(A_TT_TCB + 4) / 0xc0u;
2028 PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x0f], th);
2030 /* The return value is always 1 (even if the handle was already closed). */
2032 if (th < limit && tcb[th].status == SWAP32(0x4000)) {
2033 tcb[th].status = SWAP32(0x1000);
2040 * int ChangeTh(long thread);
2043 void psxBios_ChangeTh() { // 10
2044 u32 tcbBase = loadRam32(A_TT_TCB);
2045 u32 th = a0 & 0xffff;
2048 // PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x10], th);
2050 // without doing any argument checks, just issue a syscall
2051 // (like the real bios does)
2053 a1 = tcbBase + th * sizeof(TCB);
2058 void psxBios_InitPAD() { // 0x12
2059 u32 i, *ram32 = (u32 *)psxM;
2060 PSXBIOS_LOG("psxBios_%s %x %x %x %x\n", biosB0n[0x12], a0, a1, a2, a3);
2062 // printf("%s", "PS-X Control PAD Driver Ver 3.0");
2063 // PAD_dr_enable = 0;
2064 ram32[A_PAD_OUTBUF/4 + 0] = 0;
2065 ram32[A_PAD_OUTBUF/4 + 1] = 0;
2066 ram32[A_PAD_OUT_LEN/4 + 0] = 0;
2067 ram32[A_PAD_OUT_LEN/4 + 1] = 0;
2068 ram32[A_PAD_INBUF/4 + 0] = SWAP32(a0);
2069 ram32[A_PAD_INBUF/4 + 1] = SWAP32(a2);
2070 ram32[A_PAD_IN_LEN/4 + 0] = SWAP32(a1);
2071 ram32[A_PAD_IN_LEN/4 + 1] = SWAP32(a3);
2073 for (i = 0; i < a1; i++) {
2075 storeRam8(a0 + i, 0);
2077 for (i = 0; i < a3; i++) {
2079 storeRam8(a2 + i, 0);
2081 write_chain(ram32 + A_PADCRD_CHN_E/4, 0, 0x49bc, 0x4a4c);
2083 ram32[A_PAD_IRQR_ENA/4] = SWAP32(1);
2085 mips_return_c(1, 200);
2088 void psxBios_StartPAD() { // 13
2089 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x13]);
2091 psxBios_SysDeqIntRP_(2, A_PADCRD_CHN_E);
2092 psxBios_SysEnqIntRP_(2, A_PADCRD_CHN_E);
2093 psxHwWrite16(0x1f801070, ~1);
2094 psxHwWrite16(0x1f801074, psxHu32(0x1074) | 1);
2095 storeRam32(A_PAD_ACK_VBL, 1);
2096 storeRam32(A_RCNT_VBL_ACK + (3 << 2), 0);
2097 psxRegs.CP0.n.SR |= 0x401;
2099 mips_return_c(1, 300);
2102 void psxBios_StopPAD() { // 14
2103 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x14]);
2104 storeRam32(A_RCNT_VBL_ACK + (3 << 2), 1);
2105 psxBios_SysDeqIntRP_(2, A_PADCRD_CHN_E);
2106 psxRegs.CP0.n.SR |= 0x401;
2107 mips_return_void_c(200);
2110 void psxBios_PAD_init() { // 15
2112 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x15]);
2114 if (!(a0 == 0x20000000 || a0 == 0x20000001))
2120 psxHwWrite16(0x1f801074, (u16)(psxHwRead16(0x1f801074) | 0x1));
2121 pad_buf = (int *)Ra1;
2123 psxRegs.CP0.n.SR |= 0x401;
2128 void psxBios_PAD_dr() { // 16
2130 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x16]);
2136 static void psxBios_ReturnFromException() { // 17
2137 u32 tcbPtr = loadRam32(A_TT_PCB);
2138 const TCB *tcb = loadRam32ptr(tcbPtr);
2141 for (i = 1; i < 32; i++)
2142 psxRegs.GPR.r[i] = SWAP32(tcb->reg[i]);
2143 psxRegs.GPR.n.lo = SWAP32(tcb->lo);
2144 psxRegs.GPR.n.hi = SWAP32(tcb->hi);
2145 psxRegs.CP0.n.SR = SWAP32(tcb->sr);
2147 //printf("%s %08x->%08x %u\n", __func__, pc0, tcb->epc, psxRegs.cycle);
2148 pc0 = k0 = SWAP32(tcb->epc);
2150 psxRegs.CP0.n.SR = (psxRegs.CP0.n.SR & ~0x0f) | ((psxRegs.CP0.n.SR & 0x3c) >> 2);
2155 void psxBios_ResetEntryInt() { // 18
2156 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x18]);
2158 storeRam32(A_EEXIT_PTR, A_EEXIT_DEF);
2159 mips_return_void_c(5);
2162 void psxBios_HookEntryInt() { // 19
2163 PSXBIOS_LOG("psxBios_%s %x\n", biosB0n[0x19], a0);
2165 storeRam32(A_EEXIT_PTR, a0);
2166 mips_return_void_c(3);
2169 static void psxBios_UnDeliverEvent() { // 0x20
2171 PSXBIOS_LOG("psxBios_%s %x %x\n", biosB0n[0x20], a0, a1);
2173 ret = UnDeliverEvent(a0, a1);
2177 char ffile[64], *pfile;
2180 static void buopen(int mcd, char *ptr, char *cfg)
2183 char *mcd_data = ptr;
2185 strcpy(FDesc[1 + mcd].name, Ra0+5);
2186 FDesc[1 + mcd].offset = 0;
2187 FDesc[1 + mcd].mode = a1;
2189 for (i=1; i<16; i++) {
2190 const char *fptr = mcd_data + 128 * i;
2191 if ((*fptr & 0xF0) != 0x50) continue;
2192 if (strcmp(FDesc[1 + mcd].name, fptr+0xa)) continue;
2193 FDesc[1 + mcd].mcfile = i;
2194 SysPrintf("open %s\n", fptr+0xa);
2198 if (a1 & 0x200 && v0 == -1) { /* FCREAT */
2199 for (i=1; i<16; i++) {
2200 int j, xor, nblk = a1 >> 16;
2202 char *fptr = mcd_data + 128 * i;
2204 if ((*fptr & 0xF0) != 0xa0) continue;
2206 FDesc[1 + mcd].mcfile = i;
2209 fptr[5] = 0x20 * nblk;
2212 strcpy(fptr+0xa, FDesc[1 + mcd].name);
2213 pptr = fptr2 = fptr;
2214 for(j=2; j<=nblk; j++) {
2216 for(i++; i<16; i++) {
2219 memset(fptr2, 0, 128);
2220 fptr2[0] = j < nblk ? 0x52 : 0x53;
2223 for (k=0, xor=0; k<127; k++) xor^= pptr[k];
2228 /* shouldn't this return ENOSPC if i == 16? */
2230 pptr[8] = pptr[9] = 0xff;
2231 for (j=0, xor=0; j<127; j++) xor^= pptr[j];
2233 SysPrintf("openC %s %d\n", ptr, nblk);
2235 /* just go ahead and resave them all */
2236 SaveMcd(cfg, ptr, 128, 128 * 15);
2239 /* shouldn't this return ENOSPC if i == 16? */
2244 * int open(char *name , int mode);
2247 void psxBios_open() { // 0x32
2251 PSXBIOS_LOG("psxBios_%s: %s,%x\n", biosB0n[0x32], Ra0, a1);
2256 if (pa0 != INVALID_PTR) {
2257 if (!strncmp(pa0, "bu00", 4)) {
2258 buopen(1, Mcd1Data, Config.Mcd1);
2261 if (!strncmp(pa0, "bu10", 4)) {
2262 buopen(2, Mcd2Data, Config.Mcd2);
2270 * int lseek(int fd , int offset , int whence);
2273 void psxBios_lseek() { // 0x33
2275 PSXBIOS_LOG("psxBios_%s: %x, %x, %x\n", biosB0n[0x33], a0, a1, a2);
2280 FDesc[a0].offset = a1;
2282 // DeliverEvent(0xf0000011, 0x0004);
2283 // DeliverEvent(0xf4000001, 0x0004);
2287 FDesc[a0].offset+= a1;
2288 v0 = FDesc[a0].offset;
2297 * int read(int fd , void *buf , int nbytes);
2300 void psxBios_read() { // 0x34
2305 PSXBIOS_LOG("psxBios_%s: %x, %x, %x\n", biosB0n[0x34], a0, a1, a2);
2310 if (pa1 != INVALID_PTR) {
2312 case 2: buread(pa1, 1, a2); break;
2313 case 3: buread(pa1, 2, a2); break;
2321 * int write(int fd , void *buf , int nbytes);
2324 void psxBios_write() { // 0x35/0x03
2329 PSXBIOS_LOG("psxBios_%s: %x,%x,%x\n", biosB0n[0x35], a0, a1, a2);
2333 if (pa1 == INVALID_PTR) {
2338 if (a0 == 1) { // stdout
2343 SysPrintf("%c", *ptr++); a2--;
2349 case 2: buwrite(pa1, 1, a2); break;
2350 case 3: buwrite(pa1, 2, a2); break;
2356 static void psxBios_write_psxout() {
2357 if (a0 == 1) { // stdout
2358 const char *ptr = Ra1;
2361 if (ptr != INVALID_PTR)
2363 SysPrintf("%c", *ptr++);
2367 static void psxBios_putchar_psxout() { // 3d
2368 SysPrintf("%c", (char)a0);
2371 static void psxBios_puts_psxout() { // 3e/3f
2372 SysPrintf("%s", Ra0);
2376 * int close(int fd);
2379 void psxBios_close() { // 0x36
2381 PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x36], a0);
2388 void psxBios_putchar() { // 3d
2389 SysPrintf("%c", (char)a0);
2393 void psxBios_puts() { // 3e/3f
2394 SysPrintf("%s", Ra0);
2399 /* To avoid any issues with different behaviour when using the libc's own strlen instead.
2400 * We want to mimic the PSX's behaviour in this case for bufile. */
2401 static size_t strlen_internal(char* p)
2403 size_t size_of_array = 0;
2404 while (*p++) size_of_array++;
2405 return size_of_array;
2408 #define bufile(mcd) { \
2409 size_t size_of_name = strlen_internal(dir->name); \
2410 while (nfile < 16) { \
2413 ptr = Mcd##mcd##Data + 128 * (nfile + 1); \
2415 if ((*ptr & 0xF0) != 0x50) continue; \
2416 /* Bug link files show up as free block. */ \
2417 if (!ptr[0xa]) continue; \
2419 if (pfile[0] == 0) { \
2420 strncpy(dir->name, ptr, sizeof(dir->name) - 1); \
2421 if (size_of_name < sizeof(dir->name)) dir->name[size_of_name] = '\0'; \
2422 } else for (i=0; i<20; i++) { \
2423 if (pfile[i] == ptr[i]) { \
2424 dir->name[i] = ptr[i]; continue; } \
2425 if (pfile[i] == '?') { \
2426 dir->name[i] = ptr[i]; continue; } \
2427 if (pfile[i] == '*') { \
2428 strcpy(dir->name+i, ptr+i); break; } \
2431 SysPrintf("%d : %s = %s + %s (match=%d)\n", nfile, dir->name, pfile, ptr, match); \
2432 if (match == 0) { continue; } \
2440 * struct DIRENTRY* firstfile(char *name,struct DIRENTRY *dir);
2443 void psxBios_firstfile() { // 42
2444 struct DIRENTRY *dir = (struct DIRENTRY *)Ra1;
2451 PSXBIOS_LOG("psxBios_%s: %s\n", biosB0n[0x42], Ra0);
2456 if (pa0 != INVALID_PTR) {
2460 if (!strncmp(pa0, "bu00", 4)) {
2461 // firstfile() calls _card_read() internally, so deliver it's event
2462 DeliverEvent(0xf0000011, 0x0004);
2464 } else if (!strncmp(pa0, "bu10", 4)) {
2465 // firstfile() calls _card_read() internally, so deliver it's event
2466 DeliverEvent(0xf0000011, 0x0004);
2475 * struct DIRENTRY* nextfile(struct DIRENTRY *dir);
2478 void psxBios_nextfile() { // 43
2479 struct DIRENTRY *dir = (struct DIRENTRY *)Ra0;
2485 PSXBIOS_LOG("psxBios_%s: %s\n", biosB0n[0x43], dir->name);
2490 if (!strncmp(ffile, "bu00", 4)) {
2494 if (!strncmp(ffile, "bu10", 4)) {
2501 #define burename(mcd) { \
2502 for (i=1; i<16; i++) { \
2503 int namelen, j, xor = 0; \
2504 ptr = Mcd##mcd##Data + 128 * i; \
2505 if ((*ptr & 0xF0) != 0x50) continue; \
2506 if (strcmp(Ra0+5, ptr+0xa)) continue; \
2507 namelen = strlen(Ra1+5); \
2508 memcpy(ptr+0xa, Ra1+5, namelen); \
2509 memset(ptr+0xa+namelen, 0, 0x75-namelen); \
2510 for (j=0; j<127; j++) xor^= ptr[j]; \
2512 SaveMcd(Config.Mcd##mcd, Mcd##mcd##Data, 128 * i + 0xa, 0x76); \
2519 * int rename(char *old, char *new);
2522 void psxBios_rename() { // 44
2529 PSXBIOS_LOG("psxBios_%s: %s,%s\n", biosB0n[0x44], Ra0, Ra1);
2534 if (pa0 != INVALID_PTR && pa1 != INVALID_PTR) {
2535 if (!strncmp(pa0, "bu00", 4) && !strncmp(pa1, "bu00", 4)) {
2539 if (!strncmp(pa0, "bu10", 4) && !strncmp(pa1, "bu10", 4)) {
2548 #define budelete(mcd) { \
2549 for (i=1; i<16; i++) { \
2550 ptr = Mcd##mcd##Data + 128 * i; \
2551 if ((*ptr & 0xF0) != 0x50) continue; \
2552 if (strcmp(Ra0+5, ptr+0xa)) continue; \
2553 *ptr = (*ptr & 0xf) | 0xA0; \
2554 SaveMcd(Config.Mcd##mcd, Mcd##mcd##Data, 128 * i, 1); \
2555 SysPrintf("delete %s\n", ptr+0xa); \
2562 * int delete(char *name);
2565 void psxBios_delete() { // 45
2571 PSXBIOS_LOG("psxBios_%s: %s\n", biosB0n[0x45], Ra0);
2576 if (pa0 != INVALID_PTR) {
2577 if (!strncmp(pa0, "bu00", 4)) {
2581 if (!strncmp(pa0, "bu10", 4)) {
2589 void psxBios_InitCARD() { // 4a
2590 u32 *ram32 = (u32 *)psxM;
2591 PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x4a], a0);
2592 write_chain(ram32 + A_PADCRD_CHN_E/4, 0, 0x49bc, 0x4a4c);
2593 // (maybe) todo: early_card_irq, FlushCache etc
2595 ram32[A_PAD_IRQR_ENA/4] = SWAP32(a0);
2597 mips_return_c(0, 300);
2600 void psxBios_StartCARD() { // 4b
2601 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x4b]);
2602 psxBios_SysDeqIntRP_(2, A_PADCRD_CHN_E);
2603 psxBios_SysEnqIntRP_(2, A_PADCRD_CHN_E);
2605 psxHwWrite16(0x1f801074, psxHu32(0x1074) | 1);
2606 storeRam32(A_PAD_ACK_VBL, 1);
2607 storeRam32(A_RCNT_VBL_ACK + (3 << 2), 0);
2608 storeRam32(A_CARD_IRQR_ENA, 1);
2609 psxRegs.CP0.n.SR |= 0x401;
2611 mips_return_c(1, 200);
2614 void psxBios_StopCARD() { // 4c
2615 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x4c]);
2616 storeRam32(A_RCNT_VBL_ACK + (3 << 2), 1);
2617 psxBios_SysDeqIntRP_(2, A_PADCRD_CHN_E);
2618 storeRam32(A_CARD_IRQR_ENA, 0);
2619 psxRegs.CP0.n.SR |= 0x401;
2620 mips_return_void_c(200);
2623 void psxBios__card_write() { // 0x4e
2628 PSXBIOS_LOG("psxBios_%s: %x,%x,%x\n", biosB0n[0x4e], a0, a1, a2);
2631 Function also accepts sector 400h (a bug).
2632 But notaz said we shouldn't allow sector 400h because it can corrupt the emulator.
2636 /* Invalid sectors */
2640 card_active_chan = a0;
2643 if (pa2 != INVALID_PTR) {
2645 memcpy(Mcd1Data + a1 * 128, pa2, 128);
2646 SaveMcd(Config.Mcd1, Mcd1Data, a1 * 128, 128);
2648 memcpy(Mcd2Data + a1 * 128, pa2, 128);
2649 SaveMcd(Config.Mcd2, Mcd2Data, a1 * 128, 128);
2653 DeliverEvent(0xf0000011, 0x0004);
2654 // DeliverEvent(0xf4000001, 0x0004);
2659 void psxBios__card_read() { // 0x4f
2664 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x4f]);
2667 Function also accepts sector 400h (a bug).
2668 But notaz said we shouldn't allow sector 400h because it can corrupt the emulator.
2672 /* Invalid sectors */
2676 card_active_chan = a0;
2679 if (pa2 != INVALID_PTR) {
2681 memcpy(pa2, Mcd1Data + a1 * 128, 128);
2683 memcpy(pa2, Mcd2Data + a1 * 128, 128);
2687 DeliverEvent(0xf0000011, 0x0004);
2688 // DeliverEvent(0xf4000001, 0x0004);
2693 void psxBios__new_card() { // 0x50
2695 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x50]);
2701 /* According to a user, this allows Final Fantasy Tactics to save/load properly */
2702 void psxBios__get_error(void) // 55
2704 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x55]);
2709 void psxBios_Krom2RawAdd() { // 0x51
2712 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x51]);
2713 const u32 table_8140[][2] = {
2714 {0x8140, 0x0000}, {0x8180, 0x0762}, {0x81ad, 0x0cc6}, {0x81b8, 0x0ca8},
2715 {0x81c0, 0x0f00}, {0x81c8, 0x0d98}, {0x81cf, 0x10c2}, {0x81da, 0x0e6a},
2716 {0x81e9, 0x13ce}, {0x81f0, 0x102c}, {0x81f8, 0x1590}, {0x81fc, 0x111c},
2717 {0x81fd, 0x1626}, {0x824f, 0x113a}, {0x8259, 0x20ee}, {0x8260, 0x1266},
2718 {0x827a, 0x24cc}, {0x8281, 0x1572}, {0x829b, 0x28aa}, {0x829f, 0x187e},
2719 {0x82f2, 0x32dc}, {0x8340, 0x2238}, {0x837f, 0x4362}, {0x8380, 0x299a},
2720 {0x8397, 0x4632}, {0x839f, 0x2c4c}, {0x83b7, 0x49f2}, {0x83bf, 0x2f1c},
2721 {0x83d7, 0x4db2}, {0x8440, 0x31ec}, {0x8461, 0x5dde}, {0x8470, 0x35ca},
2722 {0x847f, 0x6162}, {0x8480, 0x378c}, {0x8492, 0x639c}, {0x849f, 0x39a8},
2726 const u32 table_889f[][2] = {
2727 {0x889f, 0x3d68}, {0x8900, 0x40ec}, {0x897f, 0x4fb0}, {0x8a00, 0x56f4},
2728 {0x8a7f, 0x65b8}, {0x8b00, 0x6cfc}, {0x8b7f, 0x7bc0}, {0x8c00, 0x8304},
2729 {0x8c7f, 0x91c8}, {0x8d00, 0x990c}, {0x8d7f, 0xa7d0}, {0x8e00, 0xaf14},
2730 {0x8e7f, 0xbdd8}, {0x8f00, 0xc51c}, {0x8f7f, 0xd3e0}, {0x9000, 0xdb24},
2731 {0x907f, 0xe9e8}, {0x9100, 0xf12c}, {0x917f, 0xfff0}, {0x9200, 0x10734},
2732 {0x927f, 0x115f8}, {0x9300, 0x11d3c}, {0x937f, 0x12c00}, {0x9400, 0x13344},
2733 {0x947f, 0x14208}, {0x9500, 0x1494c}, {0x957f, 0x15810}, {0x9600, 0x15f54},
2734 {0x967f, 0x16e18}, {0x9700, 0x1755c}, {0x977f, 0x18420}, {0x9800, 0x18b64},
2738 if (a0 >= 0x8140 && a0 <= 0x84be) {
2739 while (table_8140[i][0] <= a0) i++;
2740 a0 -= table_8140[i - 1][0];
2741 v0 = 0xbfc66000 + (a0 * 0x1e + table_8140[i - 1][1]);
2742 } else if (a0 >= 0x889f && a0 <= 0x9872) {
2743 while (table_889f[i][0] <= a0) i++;
2744 a0 -= table_889f[i - 1][0];
2745 v0 = 0xbfc66000 + (a0 * 0x1e + table_889f[i - 1][1]);
2753 void psxBios_GetC0Table() { // 56
2754 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x56]);
2755 log_unhandled("GetC0Table @%08x\n", ra);
2757 mips_return_c(A_C0_TABLE, 3);
2760 void psxBios_GetB0Table() { // 57
2761 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x57]);
2762 log_unhandled("GetB0Table @%08x\n", ra);
2764 mips_return_c(A_B0_TABLE, 3);
2767 void psxBios__card_chan() { // 0x58
2769 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x58]);
2772 v0 = card_active_chan;
2776 static void psxBios_ChangeClearPad() { // 5b
2778 PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x5b], a0);
2779 ret = loadRam32(A_PAD_ACK_VBL);
2780 storeRam32(A_PAD_ACK_VBL, a0);
2782 mips_return_c(ret, 6);
2785 void psxBios__card_status() { // 5c
2787 PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x5c], a0);
2790 v0 = card_active_chan;
2794 void psxBios__card_wait() { // 5d
2796 PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x5d], a0);
2803 /* System calls C0 */
2805 static void psxBios_InitRCnt() { // 00
2807 PSXBIOS_LOG("psxBios_%s %x\n", biosC0n[0x00], a0);
2808 psxHwWrite16(0x1f801074, psxHu32(0x1074) & ~0x71);
2809 for (i = 0; i < 3; i++) {
2810 psxHwWrite16(0x1f801100 + i*0x10 + 4, 0);
2811 psxHwWrite16(0x1f801100 + i*0x10 + 8, 0);
2812 psxHwWrite16(0x1f801100 + i*0x10 + 0, 0);
2814 psxBios_SysEnqIntRP_(a0, 0x6d88);
2815 mips_return_c(0, 9);
2818 static void psxBios_InitException() { // 01
2819 PSXBIOS_LOG("psxBios_%s %x\n", biosC0n[0x01], a0);
2820 psxBios_SysEnqIntRP_(a0, 0x6da8);
2821 mips_return_c(0, 9);
2825 * int SysEnqIntRP(int index , long *queue);
2828 static void psxBios_SysEnqIntRP_(u32 priority, u32 chain_eptr) {
2829 u32 old, base = loadRam32(A_TT_ExCB);
2831 old = loadRam32(base + (priority << 3));
2832 storeRam32(base + (priority << 3), chain_eptr);
2833 storeRam32(chain_eptr, old);
2834 mips_return_c(0, 9);
2837 static void psxBios_SysEnqIntRP() { // 02
2838 PSXBIOS_LOG("psxBios_%s %x %x\n", biosC0n[0x02], a0, a1);
2839 psxBios_SysEnqIntRP_(a0, a1);
2843 * int SysDeqIntRP(int index , long *queue);
2846 static void psxBios_SysDeqIntRP_(u32 priority, u32 chain_rm_eptr) {
2847 u32 ptr, next, base = loadRam32(A_TT_ExCB);
2848 u32 lim = 0, ret = 0;
2850 // as in original: no arg checks of any kind, bug if a1 == 0
2851 ptr = loadRam32(base + (priority << 3));
2853 next = loadRam32(ptr);
2854 if (ptr == chain_rm_eptr) {
2855 storeRam32(base + (priority << 3), next);
2860 while (next && next != chain_rm_eptr && lim++ < 100) {
2862 next = loadRam32(ptr);
2865 if (next == chain_rm_eptr) {
2866 next = loadRam32(next);
2867 storeRam32(ptr, next);
2874 PSXBIOS_LOG("bad chain %u %x\n", priority, base);
2876 mips_return_c(ret, 12);
2879 static void psxBios_SysDeqIntRP() { // 03
2880 PSXBIOS_LOG("psxBios_%s %x %x\n", biosC0n[0x03], a0, a1);
2881 psxBios_SysDeqIntRP_(a0, a1);
2884 static void psxBios_get_free_EvCB_slot() { // 04
2885 PSXBIOS_LOG("psxBios_%s\n", biosC0n[0x04]);
2886 s32 ret = get_free_EvCB_slot();
2887 mips_return_c(ret, 0);
2890 static void psxBios_SysInitMemory_(u32 base, u32 size) {
2891 storeRam32(base, 0);
2892 storeRam32(A_KMALLOC_PTR, base);
2893 storeRam32(A_KMALLOC_SIZE, size);
2894 storeRam32(A_KMALLOC_END, base + (size & ~3) + 4);
2897 // this should be much more complicated, but maybe that'll be enough
2898 static u32 psxBios_SysMalloc_(u32 size) {
2899 u32 ptr = loadRam32(A_KMALLOC_PTR);
2901 size = (size + 3) & ~3;
2902 storeRam32(A_KMALLOC_PTR, ptr + 4 + size);
2903 storeRam32(ptr, size);
2907 static void psxBios_SysInitMemory() { // 08
2908 PSXBIOS_LOG("psxBios_%s %x %x\n", biosC0n[0x08], a0, a1);
2910 psxBios_SysInitMemory_(a0, a1);
2911 mips_return_void_c(12);
2914 static void psxBios_ChangeClearRCnt() { // 0a
2917 PSXBIOS_LOG("psxBios_%s: %x, %x\n", biosC0n[0x0a], a0, a1);
2919 ret = loadRam32(A_RCNT_VBL_ACK + (a0 << 2));
2920 storeRam32(A_RCNT_VBL_ACK + (a0 << 2), a1);
2921 mips_return_c(ret, 8);
2924 static void psxBios_InitDefInt() { // 0c
2925 PSXBIOS_LOG("psxBios_%s %x\n", biosC0n[0x0c], a0);
2926 // should also clear the autoack table
2927 psxBios_SysEnqIntRP_(a0, 0x6d98);
2928 mips_return_c(0, 20 + 6*2);
2931 void psxBios_dummy() {
2932 u32 pc = (pc0 & 0x1fffff) - 4;
2933 char **ntab = pc == 0xa0 ? biosA0n : pc == 0xb0 ? biosB0n
2934 : pc == 0xc0 ? biosC0n : NULL;
2935 PSXBIOS_LOG("unk %x call: %x ra=%x (%s)\n",
2936 pc, t1, ra, ntab ? ntab[t1 & 0xff] : "???");
2937 (void)pc; (void)ntab;
2938 mips_return_c(0, 100);
2941 void (*biosA0[256])();
2942 // C0 and B0 overlap (end of C0 is start of B0)
2943 void (*biosC0[256+128])();
2944 void (**biosB0)() = biosC0 + 128;
2946 #include "sjisfont.h"
2948 void setup_mips_code()
2951 ptr = (u32 *)&psxM[A_SYSCALL];
2952 ptr[0x00/4] = SWAPu32(0x0000000c); // syscall 0
2953 ptr[0x04/4] = SWAPu32(0x03e00008); // jr $ra
2954 ptr[0x08/4] = SWAPu32(0x00000000); // nop
2956 ptr = (u32 *)&psxM[A_EXCEPTION];
2957 memset(ptr, 0, 0xc0); // nops (to be patched by games sometimes)
2958 ptr[0x10/4] = SWAPu32(0x8c1a0108); // lw $k0, (0x108) // PCB
2959 ptr[0x14/4] = SWAPu32(0x00000000); // nop
2960 ptr[0x18/4] = SWAPu32(0x8f5a0000); // lw $k0, ($k0) // TCB
2961 ptr[0x1c/4] = SWAPu32(0x00000000); // nop
2962 ptr[0x20/4] = SWAPu32(0x275a0008); // addiu $k0, $k0, 8 // regs
2963 ptr[0x24/4] = SWAPu32(0xaf5f007c); // sw $ra, 0x7c($k0)
2964 ptr[0x28/4] = SWAPu32(0xaf410004); // sw $at, 0x04($k0)
2965 ptr[0x2c/4] = SWAPu32(0xaf420008); // sw $v0, 0x08($k0)
2966 ptr[0x30/4] = SWAPu32(0xaf43000c); // sw $v1, 0x0c($k0)
2968 ptr[0x60/4] = SWAPu32(0x40037000); // mfc0 $v1, EPC
2969 ptr[0x64/4] = SWAPu32(0x40026800); // mfc0 $v0, Cause
2970 ptr[0x68/4] = SWAPu32(0x24630004); // addiu $v1, $v1, 4
2971 ptr[0x6c/4] = SWAPu32(0xaf430080); // sw $v1, 0x80($k0)
2973 ptr[0xb0/4] = HLEOP(hleop_exception);
2976 static const struct {
2980 { 0xbfc050a4, hleop_exc0_0_1 },
2981 { 0xbfc04fbc, hleop_exc0_0_2 },
2982 { 0xbfc0506c, hleop_exc0_1_1 },
2983 { 0xbfc04dec, hleop_exc0_1_2 },
2984 { 0x1a00, hleop_exc0_2_2 },
2985 { 0x19c8, hleop_exc1_0_1 },
2986 { 0x18bc, hleop_exc1_0_2 },
2987 { 0x1990, hleop_exc1_1_1 },
2988 { 0x1858, hleop_exc1_1_2 },
2989 { 0x1958, hleop_exc1_2_1 },
2990 { 0x17f4, hleop_exc1_2_2 },
2991 { 0x1920, hleop_exc1_3_1 },
2992 { 0x1794, hleop_exc1_3_2 },
2993 { 0x2458, hleop_exc3_0_2 },
2994 { 0x49bc, hleop_exc_padcard1 },
2995 { 0x4a4c, hleop_exc_padcard2 },
2998 static int chain_hle_op(u32 handler)
3002 for (i = 0; i < sizeof(chainfns) / sizeof(chainfns[0]); i++)
3003 if (chainfns[i].addr == handler)
3004 return chainfns[i].op;
3008 static void write_chain(u32 *d, u32 next, u32 handler1, u32 handler2)
3010 d[0] = SWAPu32(next);
3011 d[1] = SWAPu32(handler1);
3012 d[2] = SWAPu32(handler2);
3014 // install the hle traps
3015 PSXMu32ref(handler1) = HLEOP(chain_hle_op(handler1));
3016 PSXMu32ref(handler2) = HLEOP(chain_hle_op(handler2));
3019 static void setup_tt(u32 tcb_cnt, u32 evcb_cnt)
3021 u32 *ram32 = (u32 *)psxM;
3022 u32 s_excb = 0x20, s_evcb = 0x1c * evcb_cnt;
3023 u32 s_pcb = 4, s_tcb = 0xc0 * tcb_cnt;
3024 u32 p_excb, p_evcb, p_pcb, p_tcb;
3026 memset(ram32 + 0xe000/4, 0, s_excb + s_evcb + s_pcb + s_tcb + 5*4);
3027 psxBios_SysInitMemory_(0xa000e000, 0x2000);
3028 p_excb = psxBios_SysMalloc_(s_excb);
3029 p_evcb = psxBios_SysMalloc_(s_evcb);
3030 p_pcb = psxBios_SysMalloc_(s_pcb);
3031 p_tcb = psxBios_SysMalloc_(s_tcb);
3033 // "table of tables". Some games modify it
3034 assert(A_TT_ExCB == 0x0100);
3035 ram32[0x0100/4] = SWAPu32(p_excb); // ExCB - exception chains
3036 ram32[0x0104/4] = SWAPu32(s_excb); // ExCB size
3037 ram32[0x0108/4] = SWAPu32(p_pcb); // PCB - process control
3038 ram32[0x010c/4] = SWAPu32(s_pcb); // PCB size
3039 ram32[0x0110/4] = SWAPu32(p_tcb); // TCB - thread control
3040 ram32[0x0114/4] = SWAPu32(s_tcb); // TCB size
3041 ram32[0x0120/4] = SWAPu32(p_evcb); // EvCB - event control
3042 ram32[0x0124/4] = SWAPu32(s_evcb); // EvCB size
3043 ram32[0x0140/4] = SWAPu32(0x8648); // FCB - file control
3044 ram32[0x0144/4] = SWAPu32(0x02c0); // FCB size
3045 ram32[0x0150/4] = SWAPu32(0x6ee0); // DCB - device control
3046 ram32[0x0154/4] = SWAPu32(0x0320); // DCB size
3048 storeRam32(p_excb + 0*4, 0x91e0); // chain0
3049 storeRam32(p_excb + 2*4, 0x6d88); // chain1
3050 storeRam32(p_excb + 4*4, 0x0000); // chain2
3051 storeRam32(p_excb + 6*4, 0x6d98); // chain3
3053 storeRam32(p_pcb, p_tcb);
3054 storeRam32(p_tcb, 0x4000); // first TCB
3057 storeRam32(A_CD_EVENTS + 0x00, OpenEvent(0xf0000003, 0x0010, EvMdMARK, 0));
3058 storeRam32(A_CD_EVENTS + 0x04, OpenEvent(0xf0000003, 0x0020, EvMdMARK, 0));
3059 storeRam32(A_CD_EVENTS + 0x08, OpenEvent(0xf0000003, 0x0040, EvMdMARK, 0));
3060 storeRam32(A_CD_EVENTS + 0x0c, OpenEvent(0xf0000003, 0x0080, EvMdMARK, 0));
3061 storeRam32(A_CD_EVENTS + 0x10, OpenEvent(0xf0000003, 0x8000, EvMdMARK, 0));
3062 DeliverEvent(0xf0000003, 0x0010);
3065 void psxBiosInit() {
3066 u32 *ptr, *ram32, *rom32;
3070 memset(psxM, 0, 0x10000);
3071 for(i = 0; i < 256; i++) {
3076 biosA0[0x03] = biosB0[0x35] = psxBios_write_psxout;
3077 biosA0[0x3c] = biosB0[0x3d] = psxBios_putchar_psxout;
3078 biosA0[0x3e] = biosB0[0x3f] = psxBios_puts_psxout;
3079 biosA0[0x3f] = psxBios_printf_psxout;
3081 if (!Config.HLE) return;
3083 for(i = 0; i < 256; i++) {
3084 if (biosA0[i] == NULL) biosA0[i] = psxBios_dummy;
3085 if (biosB0[i] == NULL) biosB0[i] = psxBios_dummy;
3086 if (biosC0[i] == NULL) biosC0[i] = psxBios_dummy;
3089 biosA0[0x00] = psxBios_open;
3090 biosA0[0x01] = psxBios_lseek;
3091 biosA0[0x02] = psxBios_read;
3092 biosA0[0x03] = psxBios_write;
3093 biosA0[0x04] = psxBios_close;
3094 //biosA0[0x05] = psxBios_ioctl;
3095 //biosA0[0x06] = psxBios_exit;
3096 //biosA0[0x07] = psxBios_sys_a0_07;
3097 biosA0[0x08] = psxBios_getc;
3098 biosA0[0x09] = psxBios_putc;
3099 biosA0[0x0a] = psxBios_todigit;
3100 //biosA0[0x0b] = psxBios_atof;
3101 //biosA0[0x0c] = psxBios_strtoul;
3102 //biosA0[0x0d] = psxBios_strtol;
3103 biosA0[0x0e] = psxBios_abs;
3104 biosA0[0x0f] = psxBios_labs;
3105 biosA0[0x10] = psxBios_atoi;
3106 biosA0[0x11] = psxBios_atol;
3107 //biosA0[0x12] = psxBios_atob;
3108 biosA0[0x13] = psxBios_setjmp;
3109 biosA0[0x14] = psxBios_longjmp;
3110 biosA0[0x15] = psxBios_strcat;
3111 biosA0[0x16] = psxBios_strncat;
3112 biosA0[0x17] = psxBios_strcmp;
3113 biosA0[0x18] = psxBios_strncmp;
3114 biosA0[0x19] = psxBios_strcpy;
3115 biosA0[0x1a] = psxBios_strncpy;
3116 biosA0[0x1b] = psxBios_strlen;
3117 biosA0[0x1c] = psxBios_index;
3118 biosA0[0x1d] = psxBios_rindex;
3119 biosA0[0x1e] = psxBios_strchr;
3120 biosA0[0x1f] = psxBios_strrchr;
3121 biosA0[0x20] = psxBios_strpbrk;
3122 biosA0[0x21] = psxBios_strspn;
3123 biosA0[0x22] = psxBios_strcspn;
3124 biosA0[0x23] = psxBios_strtok;
3125 biosA0[0x24] = psxBios_strstr;
3126 biosA0[0x25] = psxBios_toupper;
3127 biosA0[0x26] = psxBios_tolower;
3128 biosA0[0x27] = psxBios_bcopy;
3129 biosA0[0x28] = psxBios_bzero;
3130 biosA0[0x29] = psxBios_bcmp;
3131 biosA0[0x2a] = psxBios_memcpy;
3132 biosA0[0x2b] = psxBios_memset;
3133 biosA0[0x2c] = psxBios_memmove;
3134 biosA0[0x2d] = psxBios_memcmp;
3135 biosA0[0x2e] = psxBios_memchr;
3136 biosA0[0x2f] = psxBios_rand;
3137 biosA0[0x30] = psxBios_srand;
3138 biosA0[0x31] = psxBios_qsort;
3139 //biosA0[0x32] = psxBios_strtod;
3140 biosA0[0x33] = psxBios_malloc;
3141 biosA0[0x34] = psxBios_free;
3142 //biosA0[0x35] = psxBios_lsearch;
3143 //biosA0[0x36] = psxBios_bsearch;
3144 biosA0[0x37] = psxBios_calloc;
3145 biosA0[0x38] = psxBios_realloc;
3146 biosA0[0x39] = psxBios_InitHeap;
3147 //biosA0[0x3a] = psxBios__exit;
3148 biosA0[0x3b] = psxBios_getchar;
3149 biosA0[0x3c] = psxBios_putchar;
3150 //biosA0[0x3d] = psxBios_gets;
3151 biosA0[0x40] = psxBios_SystemErrorUnresolvedException;
3152 //biosA0[0x41] = psxBios_LoadTest;
3153 biosA0[0x42] = psxBios_Load;
3154 biosA0[0x43] = psxBios_Exec;
3155 biosA0[0x44] = psxBios_FlushCache;
3156 //biosA0[0x45] = psxBios_InstallInterruptHandler;
3157 biosA0[0x46] = psxBios_GPU_dw;
3158 biosA0[0x47] = psxBios_mem2vram;
3159 biosA0[0x48] = psxBios_SendGPU;
3160 biosA0[0x49] = psxBios_GPU_cw;
3161 biosA0[0x4a] = psxBios_GPU_cwb;
3162 biosA0[0x4b] = psxBios_GPU_SendPackets;
3163 biosA0[0x4c] = psxBios_sys_a0_4c;
3164 biosA0[0x4d] = psxBios_GPU_GetGPUStatus;
3165 //biosA0[0x4e] = psxBios_GPU_sync;
3166 //biosA0[0x4f] = psxBios_sys_a0_4f;
3167 //biosA0[0x50] = psxBios_sys_a0_50;
3168 biosA0[0x51] = psxBios_LoadExec;
3169 //biosA0[0x52] = psxBios_GetSysSp;
3170 //biosA0[0x53] = psxBios_sys_a0_53;
3171 //biosA0[0x54] = psxBios__96_init_a54;
3172 //biosA0[0x55] = psxBios__bu_init_a55;
3173 biosA0[0x56] = psxBios_CdRemove;
3174 //biosA0[0x57] = psxBios_sys_a0_57;
3175 //biosA0[0x58] = psxBios_sys_a0_58;
3176 //biosA0[0x59] = psxBios_sys_a0_59;
3177 //biosA0[0x5a] = psxBios_sys_a0_5a;
3178 //biosA0[0x5b] = psxBios_dev_tty_init;
3179 //biosA0[0x5c] = psxBios_dev_tty_open;
3180 //biosA0[0x5d] = psxBios_sys_a0_5d;
3181 //biosA0[0x5e] = psxBios_dev_tty_ioctl;
3182 //biosA0[0x5f] = psxBios_dev_cd_open;
3183 //biosA0[0x60] = psxBios_dev_cd_read;
3184 //biosA0[0x61] = psxBios_dev_cd_close;
3185 //biosA0[0x62] = psxBios_dev_cd_firstfile;
3186 //biosA0[0x63] = psxBios_dev_cd_nextfile;
3187 //biosA0[0x64] = psxBios_dev_cd_chdir;
3188 //biosA0[0x65] = psxBios_dev_card_open;
3189 //biosA0[0x66] = psxBios_dev_card_read;
3190 //biosA0[0x67] = psxBios_dev_card_write;
3191 //biosA0[0x68] = psxBios_dev_card_close;
3192 //biosA0[0x69] = psxBios_dev_card_firstfile;
3193 //biosA0[0x6a] = psxBios_dev_card_nextfile;
3194 //biosA0[0x6b] = psxBios_dev_card_erase;
3195 //biosA0[0x6c] = psxBios_dev_card_undelete;
3196 //biosA0[0x6d] = psxBios_dev_card_format;
3197 //biosA0[0x6e] = psxBios_dev_card_rename;
3198 //biosA0[0x6f] = psxBios_dev_card_6f;
3199 biosA0[0x70] = psxBios__bu_init;
3200 biosA0[0x71] = psxBios__96_init;
3201 biosA0[0x72] = psxBios_CdRemove;
3202 //biosA0[0x73] = psxBios_sys_a0_73;
3203 //biosA0[0x74] = psxBios_sys_a0_74;
3204 //biosA0[0x75] = psxBios_sys_a0_75;
3205 //biosA0[0x76] = psxBios_sys_a0_76;
3206 //biosA0[0x77] = psxBios_sys_a0_77;
3207 //biosA0[0x78] = psxBios__96_CdSeekL;
3208 //biosA0[0x79] = psxBios_sys_a0_79;
3209 //biosA0[0x7a] = psxBios_sys_a0_7a;
3210 //biosA0[0x7b] = psxBios_sys_a0_7b;
3211 //biosA0[0x7c] = psxBios__96_CdGetStatus;
3212 //biosA0[0x7d] = psxBios_sys_a0_7d;
3213 //biosA0[0x7e] = psxBios__96_CdRead;
3214 //biosA0[0x7f] = psxBios_sys_a0_7f;
3215 //biosA0[0x80] = psxBios_sys_a0_80;
3216 //biosA0[0x81] = psxBios_sys_a0_81;
3217 //biosA0[0x82] = psxBios_sys_a0_82;
3218 //biosA0[0x83] = psxBios_sys_a0_83;
3219 //biosA0[0x84] = psxBios_sys_a0_84;
3220 //biosA0[0x85] = psxBios__96_CdStop;
3221 //biosA0[0x86] = psxBios_sys_a0_86;
3222 //biosA0[0x87] = psxBios_sys_a0_87;
3223 //biosA0[0x88] = psxBios_sys_a0_88;
3224 //biosA0[0x89] = psxBios_sys_a0_89;
3225 //biosA0[0x8a] = psxBios_sys_a0_8a;
3226 //biosA0[0x8b] = psxBios_sys_a0_8b;
3227 //biosA0[0x8c] = psxBios_sys_a0_8c;
3228 //biosA0[0x8d] = psxBios_sys_a0_8d;
3229 //biosA0[0x8e] = psxBios_sys_a0_8e;
3230 //biosA0[0x8f] = psxBios_sys_a0_8f;
3231 biosA0[0x90] = hleExc0_1_2;
3232 biosA0[0x91] = hleExc0_0_2;
3233 biosA0[0x92] = hleExc0_1_1;
3234 biosA0[0x93] = hleExc0_0_1;
3235 //biosA0[0x94] = psxBios_sys_a0_94;
3236 //biosA0[0x95] = psxBios_sys_a0_95;
3237 //biosA0[0x96] = psxBios_AddCDROMDevice;
3238 //biosA0[0x97] = psxBios_AddMemCardDevide;
3239 //biosA0[0x98] = psxBios_DisableKernelIORedirection;
3240 //biosA0[0x99] = psxBios_EnableKernelIORedirection;
3241 //biosA0[0x9a] = psxBios_sys_a0_9a;
3242 //biosA0[0x9b] = psxBios_sys_a0_9b;
3243 //biosA0[0x9c] = psxBios_SetConf;
3244 //biosA0[0x9d] = psxBios_GetConf;
3245 //biosA0[0x9e] = psxBios_sys_a0_9e;
3246 biosA0[0x9f] = psxBios_SetMem;
3247 //biosA0[0xa0] = psxBios__boot;
3248 //biosA0[0xa1] = psxBios_SystemError;
3249 //biosA0[0xa2] = psxBios_EnqueueCdIntr;
3250 biosA0[0xa3] = psxBios_DequeueCdIntr;
3251 //biosA0[0xa4] = psxBios_sys_a0_a4;
3252 //biosA0[0xa5] = psxBios_ReadSector;
3253 biosA0[0xa6] = psxBios_get_cd_status;
3254 //biosA0[0xa7] = psxBios_bufs_cb_0;
3255 //biosA0[0xa8] = psxBios_bufs_cb_1;
3256 //biosA0[0xa9] = psxBios_bufs_cb_2;
3257 //biosA0[0xaa] = psxBios_bufs_cb_3;
3258 biosA0[0xab] = psxBios__card_info;
3259 biosA0[0xac] = psxBios__card_load;
3260 //biosA0[0axd] = psxBios__card_auto;
3261 //biosA0[0xae] = psxBios_bufs_cd_4;
3262 //biosA0[0xaf] = psxBios_sys_a0_af;
3263 //biosA0[0xb0] = psxBios_sys_a0_b0;
3264 //biosA0[0xb1] = psxBios_sys_a0_b1;
3265 //biosA0[0xb2] = psxBios_do_a_long_jmp
3266 //biosA0[0xb3] = psxBios_sys_a0_b3;
3267 //biosA0[0xb4] = psxBios_sub_function;
3268 //*******************B0 CALLS****************************
3269 biosB0[0x00] = psxBios_SysMalloc;
3270 //biosB0[0x01] = psxBios_sys_b0_01;
3271 biosB0[0x02] = psxBios_SetRCnt;
3272 biosB0[0x03] = psxBios_GetRCnt;
3273 biosB0[0x04] = psxBios_StartRCnt;
3274 biosB0[0x05] = psxBios_StopRCnt;
3275 biosB0[0x06] = psxBios_ResetRCnt;
3276 biosB0[0x07] = psxBios_DeliverEvent;
3277 biosB0[0x08] = psxBios_OpenEvent;
3278 biosB0[0x09] = psxBios_CloseEvent;
3279 biosB0[0x0a] = psxBios_WaitEvent;
3280 biosB0[0x0b] = psxBios_TestEvent;
3281 biosB0[0x0c] = psxBios_EnableEvent;
3282 biosB0[0x0d] = psxBios_DisableEvent;
3283 biosB0[0x0e] = psxBios_OpenTh;
3284 biosB0[0x0f] = psxBios_CloseTh;
3285 biosB0[0x10] = psxBios_ChangeTh;
3286 //biosB0[0x11] = psxBios_psxBios_b0_11;
3287 biosB0[0x12] = psxBios_InitPAD;
3288 biosB0[0x13] = psxBios_StartPAD;
3289 biosB0[0x14] = psxBios_StopPAD;
3290 biosB0[0x15] = psxBios_PAD_init;
3291 biosB0[0x16] = psxBios_PAD_dr;
3292 biosB0[0x17] = psxBios_ReturnFromException;
3293 biosB0[0x18] = psxBios_ResetEntryInt;
3294 biosB0[0x19] = psxBios_HookEntryInt;
3295 //biosB0[0x1a] = psxBios_sys_b0_1a;
3296 //biosB0[0x1b] = psxBios_sys_b0_1b;
3297 //biosB0[0x1c] = psxBios_sys_b0_1c;
3298 //biosB0[0x1d] = psxBios_sys_b0_1d;
3299 //biosB0[0x1e] = psxBios_sys_b0_1e;
3300 //biosB0[0x1f] = psxBios_sys_b0_1f;
3301 biosB0[0x20] = psxBios_UnDeliverEvent;
3302 //biosB0[0x21] = psxBios_sys_b0_21;
3303 //biosB0[0x22] = psxBios_sys_b0_22;
3304 //biosB0[0x23] = psxBios_sys_b0_23;
3305 //biosB0[0x24] = psxBios_sys_b0_24;
3306 //biosB0[0x25] = psxBios_sys_b0_25;
3307 //biosB0[0x26] = psxBios_sys_b0_26;
3308 //biosB0[0x27] = psxBios_sys_b0_27;
3309 //biosB0[0x28] = psxBios_sys_b0_28;
3310 //biosB0[0x29] = psxBios_sys_b0_29;
3311 //biosB0[0x2a] = psxBios_sys_b0_2a;
3312 //biosB0[0x2b] = psxBios_sys_b0_2b;
3313 //biosB0[0x2c] = psxBios_sys_b0_2c;
3314 //biosB0[0x2d] = psxBios_sys_b0_2d;
3315 //biosB0[0x2e] = psxBios_sys_b0_2e;
3316 //biosB0[0x2f] = psxBios_sys_b0_2f;
3317 //biosB0[0x30] = psxBios_sys_b0_30;
3318 //biosB0[0x31] = psxBios_sys_b0_31;
3319 biosB0[0x32] = psxBios_open;
3320 biosB0[0x33] = psxBios_lseek;
3321 biosB0[0x34] = psxBios_read;
3322 biosB0[0x35] = psxBios_write;
3323 biosB0[0x36] = psxBios_close;
3324 //biosB0[0x37] = psxBios_ioctl;
3325 //biosB0[0x38] = psxBios_exit;
3326 //biosB0[0x39] = psxBios_sys_b0_39;
3327 //biosB0[0x3a] = psxBios_getc;
3328 //biosB0[0x3b] = psxBios_putc;
3329 biosB0[0x3c] = psxBios_getchar;
3330 //biosB0[0x3e] = psxBios_gets;
3331 //biosB0[0x40] = psxBios_cd;
3332 biosB0[0x41] = psxBios_format;
3333 biosB0[0x42] = psxBios_firstfile;
3334 biosB0[0x43] = psxBios_nextfile;
3335 biosB0[0x44] = psxBios_rename;
3336 biosB0[0x45] = psxBios_delete;
3337 //biosB0[0x46] = psxBios_undelete;
3338 //biosB0[0x47] = psxBios_AddDevice;
3339 //biosB0[0x48] = psxBios_RemoteDevice;
3340 //biosB0[0x49] = psxBios_PrintInstalledDevices;
3341 biosB0[0x4a] = psxBios_InitCARD;
3342 biosB0[0x4b] = psxBios_StartCARD;
3343 biosB0[0x4c] = psxBios_StopCARD;
3344 //biosB0[0x4d] = psxBios_sys_b0_4d;
3345 biosB0[0x4e] = psxBios__card_write;
3346 biosB0[0x4f] = psxBios__card_read;
3347 biosB0[0x50] = psxBios__new_card;
3348 biosB0[0x51] = psxBios_Krom2RawAdd;
3349 //biosB0[0x52] = psxBios_sys_b0_52;
3350 //biosB0[0x53] = psxBios_sys_b0_53;
3351 //biosB0[0x54] = psxBios__get_errno;
3352 biosB0[0x55] = psxBios__get_error;
3353 biosB0[0x56] = psxBios_GetC0Table;
3354 biosB0[0x57] = psxBios_GetB0Table;
3355 biosB0[0x58] = psxBios__card_chan;
3356 //biosB0[0x59] = psxBios_sys_b0_59;
3357 //biosB0[0x5a] = psxBios_sys_b0_5a;
3358 biosB0[0x5b] = psxBios_ChangeClearPad;
3359 biosB0[0x5c] = psxBios__card_status;
3360 biosB0[0x5d] = psxBios__card_wait;
3361 //*******************C0 CALLS****************************
3362 biosC0[0x00] = psxBios_InitRCnt;
3363 biosC0[0x01] = psxBios_InitException;
3364 biosC0[0x02] = psxBios_SysEnqIntRP;
3365 biosC0[0x03] = psxBios_SysDeqIntRP;
3366 biosC0[0x04] = psxBios_get_free_EvCB_slot;
3367 //biosC0[0x05] = psxBios_get_free_TCB_slot;
3368 //biosC0[0x06] = psxBios_ExceptionHandler;
3369 //biosC0[0x07] = psxBios_InstallExeptionHandler;
3370 biosC0[0x08] = psxBios_SysInitMemory;
3371 //biosC0[0x09] = psxBios_SysInitKMem;
3372 biosC0[0x0a] = psxBios_ChangeClearRCnt;
3373 //biosC0[0x0b] = psxBios_SystemError;
3374 biosC0[0x0c] = psxBios_InitDefInt;
3375 //biosC0[0x0d] = psxBios_sys_c0_0d;
3376 //biosC0[0x0e] = psxBios_sys_c0_0e;
3377 //biosC0[0x0f] = psxBios_sys_c0_0f;
3378 //biosC0[0x10] = psxBios_sys_c0_10;
3379 //biosC0[0x11] = psxBios_sys_c0_11;
3380 //biosC0[0x12] = psxBios_InstallDevices;
3381 //biosC0[0x13] = psxBios_FlushStfInOutPut;
3382 //biosC0[0x14] = psxBios_sys_c0_14;
3383 //biosC0[0x15] = psxBios__cdevinput;
3384 //biosC0[0x16] = psxBios__cdevscan;
3385 //biosC0[0x17] = psxBios__circgetc;
3386 //biosC0[0x18] = psxBios__circputc;
3387 //biosC0[0x19] = psxBios_ioabort;
3388 //biosC0[0x1a] = psxBios_sys_c0_1a
3389 //biosC0[0x1b] = psxBios_KernelRedirect;
3390 //biosC0[0x1c] = psxBios_PatchAOTable;
3391 //************** THE END ***************************************
3398 memset(FDesc, 0, sizeof(FDesc));
3399 card_active_chan = 0;
3402 psxMu32ref(0x9010) = SWAPu32(0xac20cc00);
3404 rom32 = (u32 *)psxR;
3405 rom32[0x100/4] = SWAP32(0x19951204);
3406 rom32[0x104/4] = SWAP32(3);
3407 strcpy(psxR + 0x108, "PCSX authors");
3408 strcpy(psxR + 0x12c, "PCSX HLE");
3411 len = 0x80000 - 0x66000;
3412 uncompress((Bytef *)(psxR + 0x66000), &len, font_8140, sizeof(font_8140));
3413 len = 0x80000 - 0x69d68;
3414 uncompress((Bytef *)(psxR + 0x69d68), &len, font_889f, sizeof(font_889f));
3417 psxHu32ref(0x1060) = SWAPu32(0x00000b88);
3419 /* Some games like R-Types, CTR, Fade to Black read from adress 0x00000000 due to uninitialized pointers.
3420 See Garbage Area at Address 00000000h in Nocash PSX Specfications for more information.
3421 Here are some examples of games not working with this fix in place :
3422 R-type won't get past the Irem logo if not implemented.
3423 Crash Team Racing will softlock after the Sony logo.
3426 ram32 = (u32 *)psxM;
3427 ram32[0x0000/4] = SWAPu32(0x00000003); // lui $k0, 0 (overwritten by 3)
3428 ram32[0x0004/4] = SWAPu32(0x275a0000 + A_EXCEPTION); // addiu $k0, $k0, 0xc80
3429 ram32[0x0008/4] = SWAPu32(0x03400008); // jr $k0
3430 ram32[0x000c/4] = SWAPu32(0x00000000); // nop
3432 ram32[0x0060/4] = SWAPu32(0x00000002); // ram size?
3433 ram32[0x0068/4] = SWAPu32(0x000000ff); // unknown
3435 ram32[0x0080/4] = SWAPu32(0x3c1a0000); // lui $k0, 0 // exception vector
3436 ram32[0x0084/4] = SWAPu32(0x275a0000 + A_EXCEPTION); // addiu $k0, $k0, 0xc80
3437 ram32[0x0088/4] = SWAPu32(0x03400008); // jr $k0
3438 ram32[0x008c/4] = SWAPu32(0x00000000); // nop
3440 ram32[0x00a0/4] = HLEOP(hleop_a0);
3441 ram32[0x00b0/4] = HLEOP(hleop_b0);
3442 ram32[0x00c0/4] = HLEOP(hleop_c0);
3446 ram32[0x6ee0/4] = SWAPu32(0x0000eff0); // DCB
3447 strcpy((char *)&ram32[0xeff0/4], "bu");
3449 // default exception handler chains
3450 write_chain(&ram32[0x91e0/4], 0x91d0, 0xbfc050a4, 0xbfc04fbc); // chain0.e0
3451 write_chain(&ram32[0x91d0/4], 0x6da8, 0xbfc0506c, 0xbfc04dec); // chain0.e1
3452 write_chain(&ram32[0x6da8/4], 0, 0, 0x1a00); // chain0.e2
3453 write_chain(&ram32[0x6d88/4], 0x6d78, 0x19c8, 0x18bc); // chain1.e0
3454 write_chain(&ram32[0x6d78/4], 0x6d68, 0x1990, 0x1858); // chain1.e1
3455 write_chain(&ram32[0x6d68/4], 0x6d58, 0x1958, 0x17f4); // chain1.e2
3456 write_chain(&ram32[0x6d58/4], 0, 0x1920, 0x1794); // chain1.e3
3457 write_chain(&ram32[0x6d98/4], 0, 0, 0x2458); // chain3.e0
3461 // fill the api jumptables with fake entries as some games patch them
3462 // (or rather the funcs listed there)
3463 ptr = (u32 *)&psxM[A_A0_TABLE];
3464 for (i = 0; i < 256; i++)
3465 ptr[i] = SWAP32(0x1000);
3467 ptr = (u32 *)&psxM[A_B0_TABLE];
3468 for (i = 0; i < 256; i++)
3469 ptr[i] = SWAP32(0x2000);
3470 // B(5b) is special because games patch (sometimes even jump to)
3471 // code at fixed offsets from it, nocash lists offsets:
3472 // patch: +3d8, +4dc, +594, +62c, +9c8, +1988
3473 // call: +7a0=4b70, +884=4c54, +894=4c64
3474 ptr[0x5b] = SWAP32(0x43d0);
3475 ram32[0x4b70/4] = SWAP32(0x03e00008); // jr $ra // setPadOutputBuf
3477 ram32[0x4c54/4] = SWAP32(0x240e0001); // mov $t6, 1
3478 ram32[0x4c58/4] = SWAP32(0x03e00008); // jr $ra
3479 ram32[0x4c5c/4] = SWAP32(0xac0e0000 + A_PAD_IRQR_ENA); // sw $t6, ...
3481 ram32[0x4c64/4] = SWAP32(0x03e00008); // jr $ra
3482 ram32[0x4c68/4] = SWAP32(0xac000000 + A_PAD_IRQR_ENA); // sw $0, ...
3484 ptr = (u32 *)&psxM[A_C0_TABLE];
3485 for (i = 0; i < 256/2; i++)
3486 ptr[i] = SWAP32(0x3000);
3487 ptr[6] = SWAP32(A_EXCEPTION);
3490 ram32[0x1000/4] = HLEOP(hleop_dummy);
3491 ram32[0x2000/4] = HLEOP(hleop_dummy);
3492 ram32[0x3000/4] = HLEOP(hleop_dummy);
3493 ram32[0x4c54/4] = HLEOP(hleop_dummy); // for B12_InitPad?
3494 ram32[0x8000/4] = HLEOP(hleop_execret);
3496 ram32[A_EEXIT_PTR/4] = SWAP32(A_EEXIT_DEF);
3497 ram32[A_EXC_SP/4] = SWAP32(A_EXC_STACK);
3498 ram32[A_RCNT_VBL_ACK/4 + 0] = SWAP32(1);
3499 ram32[A_RCNT_VBL_ACK/4 + 1] = SWAP32(1);
3500 ram32[A_RCNT_VBL_ACK/4 + 2] = SWAP32(1);
3501 ram32[A_RCNT_VBL_ACK/4 + 3] = SWAP32(1);
3504 void psxBiosShutdown() {
3507 void psxBiosCnfLoaded(u32 tcb_cnt, u32 evcb_cnt) {
3508 if (tcb_cnt != 4 || evcb_cnt != 16)
3509 setup_tt(tcb_cnt, evcb_cnt);
3512 #define psxBios_PADpoll(pad) { \
3513 PAD##pad##_startPoll(pad); \
3514 pad_buf##pad[0] = 0; \
3515 pad_buf##pad[1] = PAD##pad##_poll(0x42); \
3516 if (!(pad_buf##pad[1] & 0x0f)) { \
3519 bufcount = (pad_buf##pad[1] & 0x0f) * 2; \
3521 PAD##pad##_poll(0); \
3523 while (bufcount--) { \
3524 pad_buf##pad[i++] = PAD##pad##_poll(0); \
3528 static void biosPadHLE() {
3529 if (pad_buf != NULL) {
3530 u32 *buf = (u32*)pad_buf;
3533 if (PAD1_poll(0x42) == 0x23) {
3535 *buf = PAD1_poll(0) << 8;
3536 *buf |= PAD1_poll(0);
3538 *buf &= ~((PAD1_poll(0) > 0x20) ? 1 << 6 : 0);
3539 *buf &= ~((PAD1_poll(0) > 0x20) ? 1 << 7 : 0);
3542 *buf = PAD1_poll(0) << 8;
3543 *buf|= PAD1_poll(0);
3547 if (PAD2_poll(0x42) == 0x23) {
3549 *buf |= PAD2_poll(0) << 24;
3550 *buf |= PAD2_poll(0) << 16;
3552 *buf &= ~((PAD2_poll(0) > 0x20) ? 1 << 22 : 0);
3553 *buf &= ~((PAD2_poll(0) > 0x20) ? 1 << 23 : 0);
3556 *buf |= PAD2_poll(0) << 24;
3557 *buf |= PAD2_poll(0) << 16;
3562 static void handle_chain_x_x_1(u32 enable, u32 irqbit)
3566 psxHwWrite16(0x1f801070, ~(1u << irqbit));
3567 psxBios_ReturnFromException();
3573 // hleExc0_{0,1}* are usually removed by A(56)/A(72) on the game's startup,
3574 // so this is only partially implemented
3575 void hleExc0_0_1() // A(93h) - CdromDmaIrqFunc2
3577 u32 cdrom_dma_ack_enable = 1; // a000b93c
3578 handle_chain_x_x_1(cdrom_dma_ack_enable, 3); // IRQ3 DMA
3581 void hleExc0_0_2() // A(91h) - CdromDmaIrqFunc1
3584 //PSXBIOS_LOG("%s\n", __func__);
3586 if (psxHu32(0x1074) & psxHu32(0x1070) & 8) { // IRQ3 DMA
3587 psxHwWrite32(0x1f8010f4, (psxHu32(0x10f4) & 0xffffff) | 0x88000000);
3588 //if (--cdrom_irq_counter == 0) // 0xa0009180
3589 // DeliverEvent(0xf0000003, 0x10);
3593 mips_return_c(ret, 20);
3596 void hleExc0_1_1() // A(92h) - CdromIoIrqFunc2
3598 u32 cdrom_irq_ack_enable = 1; // a000b938
3599 handle_chain_x_x_1(cdrom_irq_ack_enable, 2); // IRQ2 cdrom
3602 void hleExc0_1_2() // A(90h) - CdromIoIrqFunc1
3605 if (psxHu32(0x1074) & psxHu32(0x1070) & 4) { // IRQ2 cdrom
3606 PSXBIOS_LOG("%s TODO\n", __func__);
3609 mips_return_c(ret, 20);
3612 void hleExc0_2_2_syscall() // not in any A/B/C table
3614 u32 code = (psxRegs.CP0.n.Cause & 0x3c) >> 2;
3615 u32 tcbPtr = loadRam32(A_TT_PCB);
3616 TCB *tcb = loadRam32ptr(tcbPtr);
3618 if (code != R3000E_Syscall) {
3620 DeliverEvent(0xf0000010, 0x1000);
3621 psxBios_SystemErrorUnresolvedException();
3623 mips_return_c(0, 17);
3627 //printf("%s c=%d a0=%d\n", __func__, code, a0);
3628 tcb->epc += SWAP32(4);
3633 case 1: { // EnterCritical - disable irqs
3634 u32 was_enabled = ((SWAP32(tcb->sr) & 0x404) == 0x404);
3635 tcb->reg[2] = SWAP32(was_enabled);
3636 tcb->sr &= SWAP32(~0x404);
3639 case 2: // ExitCritical - enable irqs
3640 tcb->sr |= SWAP32(0x404);
3643 case 3: { // ChangeThreadSubFunction
3644 u32 tcbPtr = loadRam32(A_TT_PCB);
3645 storeRam32(tcbPtr, a1);
3649 DeliverEvent(0xf0000010, 0x4000);
3653 psxBios_ReturnFromException();
3656 void hleExc1_0_1(void)
3658 u32 vbl_irq_ack_enable = loadRam32(A_RCNT_VBL_ACK + 0x0c); // 860c
3659 handle_chain_x_x_1(vbl_irq_ack_enable, 0); // IRQ0 vblank
3662 static void handle_chain_1_x_2(u32 ev_index, u32 irqbit)
3665 if (psxHu32(0x1074) & psxHu32(0x1070) & (1u << irqbit)) {
3666 DeliverEvent(0xf2000000 + ev_index, 0x0002);
3669 mips_return_c(ret, 22);
3672 void hleExc1_0_2(void)
3674 handle_chain_1_x_2(3, 0); // IRQ0 vblank
3677 void hleExc1_1_1(void)
3679 u32 rcnt_irq_ack_enable = loadRam32(A_RCNT_VBL_ACK + 0x08); // 8608
3680 handle_chain_x_x_1(rcnt_irq_ack_enable, 6); // IRQ6 rcnt2
3683 void hleExc1_1_2(void)
3685 handle_chain_1_x_2(2, 6); // IRQ6 rcnt2
3688 void hleExc1_2_1(void)
3690 u32 rcnt_irq_ack_enable = loadRam32(A_RCNT_VBL_ACK + 0x04); // 8604
3691 handle_chain_x_x_1(rcnt_irq_ack_enable, 5); // IRQ5 rcnt1
3694 void hleExc1_2_2(void)
3696 handle_chain_1_x_2(1, 5); // IRQ5 rcnt1
3699 void hleExc1_3_1(void)
3701 u32 rcnt_irq_ack_enable = loadRam32(A_RCNT_VBL_ACK + 0x00); // 8600
3702 handle_chain_x_x_1(rcnt_irq_ack_enable, 4); // IRQ4 rcnt0
3705 void hleExc1_3_2(void)
3707 handle_chain_1_x_2(0, 4); // IRQ4 rcnt0
3710 void hleExc3_0_2_defint(void)
3712 static const struct {
3723 { 6, 6 }, // rcnt2 (bug)
3728 for (i = 0; i < sizeof(tab) / sizeof(tab[0]); i++) {
3729 if (psxHu32(0x1074) & psxHu32(0x1070) & (1u << tab[i].irqbit)) {
3730 DeliverEvent(0xf0000000 + tab[i].ev, 0x1000);
3735 mips_return_c(0, 11 + 7*11 + 7*11 + 12);
3738 void hleExcPadCard1(void)
3740 if (loadRam32(A_PAD_IRQR_ENA)) {
3741 u8 *pad_buf1 = loadRam8ptr(A_PAD_INBUF + 0);
3742 u8 *pad_buf2 = loadRam8ptr(A_PAD_INBUF + 4);
3750 if (loadRam32(A_PAD_ACK_VBL))
3751 psxHwWrite16(0x1f801070, ~1);
3752 if (loadRam32(A_CARD_IRQR_ENA)) {
3756 mips_return_c(0, 18);
3759 void hleExcPadCard2(void)
3761 u32 ret = psxHu32(0x1074) & psxHu32(0x1070) & 1;
3762 mips_return_c(ret, 15);
3765 void psxBiosException() {
3766 u32 tcbPtr = loadRam32(A_TT_PCB);
3767 u32 *chains = loadRam32ptr(A_TT_ExCB);
3768 TCB *tcb = loadRam32ptr(tcbPtr);
3774 // $at, $v0, $v1 already saved by the mips code at A_EXCEPTION
3775 for (i = 4; i < 32; i++) {
3778 tcb->reg[i] = SWAP32(psxRegs.GPR.r[i]);
3780 tcb->lo = SWAP32(psxRegs.GPR.n.lo);
3781 tcb->hi = SWAP32(psxRegs.GPR.n.hi);
3782 tcb->epc = SWAP32(psxRegs.CP0.n.EPC);
3783 tcb->sr = SWAP32(psxRegs.CP0.n.SR);
3784 tcb->cause = SWAP32(psxRegs.CP0.n.Cause);
3785 sp = fp = loadRam32(A_EXC_SP);
3789 // do the chains (always 4)
3790 for (c = lim = 0; c < 4; c++) {
3791 if (chains[c * 2] == 0)
3793 ptr = SWAP32(chains[c * 2]);
3794 for (; ptr && lim < 100; ptr = SWAP32(chain[0])) {
3795 chain = castRam32ptr(ptr);
3800 softCallInException(SWAP32(chain[2]));
3801 if (returned_from_exception())
3804 if (v0 == 0 || chain[1] == 0)
3806 softCallInException(SWAP32(chain[1]));
3807 if (returned_from_exception())
3813 // return from exception (custom or default)
3815 ptr = loadRam32(A_EEXIT_PTR);
3816 if (ptr != A_EEXIT_DEF) {
3817 const struct jmp_buf_ *jmp_buf = castRam32ptr(ptr);
3818 longjmp_load(jmp_buf);
3823 psxBios_ReturnFromException();
3826 #define bfreeze(ptr, size) { \
3827 if (Mode == 1) memcpy(&psxR[base], ptr, size); \
3828 if (Mode == 0) memcpy(ptr, &psxR[base], size); \
3832 #define bfreezes(ptr) bfreeze(ptr, sizeof(ptr))
3833 #define bfreezel(ptr) bfreeze(ptr, sizeof(*ptr))
3835 #define bfreezepsxMptr(ptr, type) { \
3837 if (ptr) psxRu32ref(base) = SWAPu32((s8 *)(ptr) - psxM); \
3838 else psxRu32ref(base) = 0; \
3840 if (psxRu32(base) != 0) ptr = (type *)(psxM + psxRu32(base)); \
3841 else (ptr) = NULL; \
3843 base += sizeof(u32); \
3846 void psxBiosFreeze(int Mode) {
3849 bfreezepsxMptr(pad_buf, int);
3850 bfreezepsxMptr(heap_addr, u32);
3852 bfreezel(&card_active_chan);
3853 bfreezel(&heap_size);