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"
41 #if (defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)
42 #pragma GCC diagnostic ignored "-Wpointer-sign"
46 //#define PSXBIOS_LOG printf
47 #define PSXBIOS_LOG(...)
50 char *biosA0n[256] = {
52 "open", "lseek", "read", "write",
53 "close", "ioctl", "exit", "sys_a0_07",
54 "getc", "putc", "todigit", "atof",
55 "strtoul", "strtol", "abs", "labs",
57 "atoi", "atol", "atob", "setjmp",
58 "longjmp", "strcat", "strncat", "strcmp",
59 "strncmp", "strcpy", "strncpy", "strlen",
60 "index", "rindex", "strchr", "strrchr",
62 "strpbrk", "strspn", "strcspn", "strtok",
63 "strstr", "toupper", "tolower", "bcopy",
64 "bzero", "bcmp", "memcpy", "memset",
65 "memmove", "memcmp", "memchr", "rand",
67 "srand", "qsort", "strtod", "malloc",
68 "free", "lsearch", "bsearch", "calloc",
69 "realloc", "InitHeap", "_exit", "getchar",
70 "putchar", "gets", "puts", "printf",
72 "SystemErrorUnresolvedException", "LoadTest", "Load", "Exec",
73 "FlushCache", "InstallInterruptHandler", "GPU_dw", "mem2vram",
74 "SendGPUStatus", "GPU_cw", "GPU_cwb", "SendPackets",
75 "sys_a0_4c", "GetGPUStatus", "GPU_sync", "sys_a0_4f",
77 "sys_a0_50", "LoadExec", "GetSysSp", "sys_a0_53",
78 "_96_init()", "_bu_init()", "_96_remove()", "sys_a0_57",
79 "sys_a0_58", "sys_a0_59", "sys_a0_5a", "dev_tty_init",
80 "dev_tty_open", "sys_a0_5d", "dev_tty_ioctl","dev_cd_open",
82 "dev_cd_read", "dev_cd_close", "dev_cd_firstfile", "dev_cd_nextfile",
83 "dev_cd_chdir", "dev_card_open", "dev_card_read", "dev_card_write",
84 "dev_card_close", "dev_card_firstfile", "dev_card_nextfile","dev_card_erase",
85 "dev_card_undelete","dev_card_format", "dev_card_rename", "dev_card_6f",
87 "_bu_init", "_96_init", "CdRemove", "sys_a0_73",
88 "sys_a0_74", "sys_a0_75", "sys_a0_76", "sys_a0_77",
89 "_96_CdSeekL", "sys_a0_79", "sys_a0_7a", "sys_a0_7b",
90 "_96_CdGetStatus", "sys_a0_7d", "_96_CdRead", "sys_a0_7f",
92 "sys_a0_80", "sys_a0_81", "sys_a0_82", "sys_a0_83",
93 "sys_a0_84", "_96_CdStop", "sys_a0_86", "sys_a0_87",
94 "sys_a0_88", "sys_a0_89", "sys_a0_8a", "sys_a0_8b",
95 "sys_a0_8c", "sys_a0_8d", "sys_a0_8e", "sys_a0_8f",
97 "sys_a0_90", "sys_a0_91", "sys_a0_92", "sys_a0_93",
98 "sys_a0_94", "sys_a0_95", "AddCDROMDevice", "AddMemCardDevide",
99 "DisableKernelIORedirection", "EnableKernelIORedirection", "sys_a0_9a", "sys_a0_9b",
100 "SetConf", "GetConf", "sys_a0_9e", "SetMem",
102 "_boot", "SystemError", "EnqueueCdIntr", "DequeueCdIntr",
103 "sys_a0_a4", "ReadSector", "get_cd_status", "bufs_cb_0",
104 "bufs_cb_1", "bufs_cb_2", "bufs_cb_3", "_card_info",
105 "_card_load", "_card_auto", "bufs_cd_4", "sys_a0_af",
107 "sys_a0_b0", "sys_a0_b1", "do_a_long_jmp", "sys_a0_b3",
111 char *biosB0n[256] = {
113 "SysMalloc", "sys_b0_01", "sys_b0_02", "sys_b0_03",
114 "sys_b0_04", "sys_b0_05", "sys_b0_06", "DeliverEvent",
115 "OpenEvent", "CloseEvent", "WaitEvent", "TestEvent",
116 "EnableEvent", "DisableEvent", "OpenTh", "CloseTh",
118 "ChangeTh", "sys_b0_11", "InitPAD", "StartPAD",
119 "StopPAD", "PAD_init", "PAD_dr", "ReturnFromExecption",
120 "ResetEntryInt", "HookEntryInt", "sys_b0_1a", "sys_b0_1b",
121 "sys_b0_1c", "sys_b0_1d", "sys_b0_1e", "sys_b0_1f",
123 "UnDeliverEvent", "sys_b0_21", "sys_b0_22", "sys_b0_23",
124 "sys_b0_24", "sys_b0_25", "sys_b0_26", "sys_b0_27",
125 "sys_b0_28", "sys_b0_29", "sys_b0_2a", "sys_b0_2b",
126 "sys_b0_2c", "sys_b0_2d", "sys_b0_2e", "sys_b0_2f",
128 "sys_b0_30", "sys_b0_31", "open", "lseek",
129 "read", "write", "close", "ioctl",
130 "exit", "sys_b0_39", "getc", "putc",
131 "getchar", "putchar", "gets", "puts",
133 "cd", "format", "firstfile", "nextfile",
134 "rename", "delete", "undelete", "AddDevice",
135 "RemoteDevice", "PrintInstalledDevices", "InitCARD", "StartCARD",
136 "StopCARD", "sys_b0_4d", "_card_write", "_card_read",
138 "_new_card", "Krom2RawAdd", "sys_b0_52", "sys_b0_53",
139 "_get_errno", "_get_error", "GetC0Table", "GetB0Table",
140 "_card_chan", "sys_b0_59", "sys_b0_5a", "ChangeClearPAD",
141 "_card_status", "_card_wait",
144 char *biosC0n[256] = {
146 "InitRCnt", "InitException", "SysEnqIntRP", "SysDeqIntRP",
147 "get_free_EvCB_slot", "get_free_TCB_slot", "ExceptionHandler", "InstallExeptionHandler",
148 "SysInitMemory", "SysInitKMem", "ChangeClearRCnt", "SystemError",
149 "InitDefInt", "sys_c0_0d", "sys_c0_0e", "sys_c0_0f",
151 "sys_c0_10", "sys_c0_11", "InstallDevices", "FlushStfInOutPut",
152 "sys_c0_14", "_cdevinput", "_cdevscan", "_circgetc",
153 "_circputc", "ioabort", "sys_c0_1a", "KernelRedirect",
157 //#define r0 (psxRegs.GPR.n.r0)
158 #define at (psxRegs.GPR.n.at)
159 #define v0 (psxRegs.GPR.n.v0)
160 #define v1 (psxRegs.GPR.n.v1)
161 #define a0 (psxRegs.GPR.n.a0)
162 #define a1 (psxRegs.GPR.n.a1)
163 #define a2 (psxRegs.GPR.n.a2)
164 #define a3 (psxRegs.GPR.n.a3)
165 #define t0 (psxRegs.GPR.n.t0)
166 #define t1 (psxRegs.GPR.n.t1)
167 #define t2 (psxRegs.GPR.n.t2)
168 #define t3 (psxRegs.GPR.n.t3)
169 #define t4 (psxRegs.GPR.n.t4)
170 #define t5 (psxRegs.GPR.n.t5)
171 #define t6 (psxRegs.GPR.n.t6)
172 #define t7 (psxRegs.GPR.n.t7)
173 #define t8 (psxRegs.GPR.n.t8)
174 #define t9 (psxRegs.GPR.n.t9)
175 #define s0 (psxRegs.GPR.n.s0)
176 #define s1 (psxRegs.GPR.n.s1)
177 #define s2 (psxRegs.GPR.n.s2)
178 #define s3 (psxRegs.GPR.n.s3)
179 #define s4 (psxRegs.GPR.n.s4)
180 #define s5 (psxRegs.GPR.n.s5)
181 #define s6 (psxRegs.GPR.n.s6)
182 #define s7 (psxRegs.GPR.n.s7)
183 #define k0 (psxRegs.GPR.n.k0)
184 #define k1 (psxRegs.GPR.n.k1)
185 #define gp (psxRegs.GPR.n.gp)
186 #define sp (psxRegs.GPR.n.sp)
187 #define fp (psxRegs.GPR.n.fp)
188 #define ra (psxRegs.GPR.n.ra)
189 #define pc0 (psxRegs.pc)
191 #define Ra0 ((char *)PSXM(a0))
192 #define Ra1 ((char *)PSXM(a1))
193 #define Ra2 ((char *)PSXM(a2))
194 #define Ra3 ((char *)PSXM(a3))
195 #define Rv0 ((char *)PSXM(v0))
196 #define Rsp ((char *)PSXM(sp))
207 #define EvStUNUSED 0x0000
208 #define EvStDISABLED 0x1000
209 #define EvStACTIVE 0x2000
210 #define EvStALREADY 0x4000
212 #define EvMdCALL 0x1000
213 #define EvMdMARK 0x2000
236 u32 _sp, _fp, _gp, ret, base;
256 // todo: FileDesc layout is wrong
257 // todo: get rid of these globals
258 static FileDesc FDesc[32];
259 static char ffile[64], *pfile;
262 // fixed RAM offsets, SCPH1001 compatible
263 #define A_TT_ExCB 0x0100
264 #define A_TT_PCB 0x0108
265 #define A_TT_TCB 0x0110
266 #define A_TT_EvCB 0x0120
267 #define A_A0_TABLE 0x0200
268 #define A_B0_TABLE 0x0874
269 #define A_C0_TABLE 0x0674
270 #define A_SYSCALL 0x0650
271 #define A_EXCEPTION 0x0c80
272 #define A_EXC_SP 0x6cf0
273 #define A_EEXIT_DEF 0x6cf4
274 #define A_KMALLOC_PTR 0x7460
275 #define A_KMALLOC_SIZE 0x7464
276 #define A_KMALLOC_END 0x7468
277 #define A_PADCRD_CHN_E 0x74a8 // pad/card irq chain entry, see hleExcPadCard1()
278 #define A_PAD_IRQR_ENA 0x74b8 // pad read on vint irq (nocash 'pad_enable_flag')
279 #define A_CARD_IRQR_ENA 0x74bc // same for card
280 #define A_PAD_INBUF 0x74c8 // 2x buffers for rx pad data
281 #define A_PAD_OUTBUF 0x74d0 // 2x buffers for tx pad data
282 #define A_PAD_IN_LEN 0x74d8
283 #define A_PAD_OUT_LEN 0x74e0
284 #define A_PAD_DR_DST 0x74c4
285 #define A_CARD_CHAN1 0x7500
286 #define A_PAD_DR_BUF1 0x7570
287 #define A_PAD_DR_BUF2 0x7598
288 #define A_EEXIT_PTR 0x75d0
289 #define A_EXC_STACK 0x85d8 // exception stack top
290 #define A_RCNT_VBL_ACK 0x8600
291 #define A_PAD_ACK_VBL 0x8914 // enable vint ack by pad reading code
292 #define A_HEAP_BASE 0x9000
293 #define A_HEAP_SIZE 0x9004
294 #define A_HEAP_END 0x9008
295 #define A_HEAP_FLAG 0x900c
296 #define A_CD_EVENTS 0xb9b8
297 #define A_EXC_GP 0xf450
299 #define HLEOP(n) SWAPu32((0x3b << 26) | (n));
301 static u32 loadRam32(u32 addr)
303 assert(!(addr & 0x5f800000));
304 return SWAP32(*((u32 *)psxM + ((addr & 0x1fffff) >> 2)));
307 static void *castRam8ptr(u32 addr)
309 assert(!(addr & 0x5f800000));
310 return psxM + (addr & 0x1fffff);
313 static void *castRam32ptr(u32 addr)
315 assert(!(addr & 0x5f800003));
316 return psxM + (addr & 0x1ffffc);
319 static void *loadRam8ptr(u32 addr)
321 return castRam8ptr(loadRam32(addr));
324 static void *loadRam32ptr(u32 addr)
326 return castRam32ptr(loadRam32(addr));
329 static void storeRam8(u32 addr, u8 d)
331 assert(!(addr & 0x5f800000));
332 *((u8 *)psxM + (addr & 0x1fffff)) = d;
335 static void storeRam32(u32 addr, u32 d)
337 assert(!(addr & 0x5f800000));
338 *((u32 *)psxM + ((addr & 0x1fffff) >> 2)) = SWAP32(d);
341 static void mips_return(u32 val)
347 static void use_cycles(u32 cycle)
349 psxRegs.cycle += cycle * 2;
352 static void mips_return_c(u32 val, u32 cycle)
358 static void mips_return_void_c(u32 cycle)
364 static int returned_from_exception(void)
366 // 0x80000080 means it took another exception just after return
367 return pc0 == k0 || pc0 == 0x80000080;
370 static inline void softCall(u32 pc) {
372 u32 ssr = psxRegs.CP0.n.SR;
376 psxRegs.CP0.n.SR &= ~0x404; // disable interrupts
378 while (pc0 != 0x80001000 && ++lim < 1000000)
379 psxCpu->ExecuteBlock(EXEC_CALLER_HLE);
382 PSXBIOS_LOG("softCall @%x hit lim\n", pc);
384 psxRegs.CP0.n.SR |= ssr & 0x404;
387 static inline void softCallInException(u32 pc) {
393 while (!returned_from_exception() && pc0 != 0x80001000 && ++lim < 1000000)
394 psxCpu->ExecuteBlock(EXEC_CALLER_HLE);
397 PSXBIOS_LOG("softCallInException @%x hit lim\n", pc);
398 if (pc0 == 0x80001000)
402 static u32 OpenEvent(u32 class, u32 spec, u32 mode, u32 func);
403 static u32 DeliverEvent(u32 class, u32 spec);
404 static u32 UnDeliverEvent(u32 class, u32 spec);
405 static void CloseEvent(u32 ev);
410 // System calls A0 */
413 #define buread(Ra1, mcd, length) { \
414 PSXBIOS_LOG("read %d: %x,%x (%s)\n", FDesc[1 + mcd].mcfile, FDesc[1 + mcd].offset, a2, Mcd##mcd##Data + 128 * FDesc[1 + mcd].mcfile + 0xa); \
415 ptr = Mcd##mcd##Data + 8192 * FDesc[1 + mcd].mcfile + FDesc[1 + mcd].offset; \
416 memcpy(Ra1, ptr, length); \
417 psxCpu->Clear(a1, (length + 3) / 4); \
418 if (FDesc[1 + mcd].mode & 0x8000) { \
419 DeliverEvent(0xf0000011, 0x0004); \
420 DeliverEvent(0xf4000001, 0x0004); \
423 FDesc[1 + mcd].offset += v0; \
426 #define buwrite(Ra1, mcd, length) { \
427 u32 offset = + 8192 * FDesc[1 + mcd].mcfile + FDesc[1 + mcd].offset; \
428 PSXBIOS_LOG("write %d: %x,%x\n", FDesc[1 + mcd].mcfile, FDesc[1 + mcd].offset, a2); \
429 ptr = Mcd##mcd##Data + offset; \
430 memcpy(ptr, Ra1, length); \
431 FDesc[1 + mcd].offset += length; \
432 SaveMcd(Config.Mcd##mcd, Mcd##mcd##Data, offset, length); \
433 if (FDesc[1 + mcd].mode & 0x8000) { \
434 DeliverEvent(0xf0000011, 0x0004); \
435 DeliverEvent(0xf4000001, 0x0004); \
440 /* Internally redirects to "FileRead(fd,tempbuf,1)".*/
441 /* For some strange reason, the returned character is sign-expanded; */
442 /* So if a return value of FFFFFFFFh could mean either character FFh, or error. */
443 /* TODO FIX ME : Properly implement this behaviour */
444 void psxBios_getc(void) // 0x03, 0x35
449 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x03]);
453 if (pa1 != INVALID_PTR) {
455 case 2: buread(pa1, 1, 1); break;
456 case 3: buread(pa1, 2, 1); break;
463 /* Copy of psxBios_write, except size is 1. */
464 void psxBios_putc(void) // 0x09, 0x3B
469 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x09]);
472 if (pa1 == INVALID_PTR) {
477 if (a0 == 1) { // stdout
478 char *ptr = (char *)pa1;
482 printf("%c", *ptr++); a2--;
488 case 2: buwrite(pa1, 1, 1); break;
489 case 3: buwrite(pa1, 2, 1); break;
495 void psxBios_todigit(void) // 0x0a
499 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x0a]);
502 if (c >= 0x30 && c < 0x3A) {
505 else if (c > 0x60 && c < 0x7B) {
508 else if (c > 0x40 && c < 0x5B) {
511 else if (c >= 0x80) {
522 void psxBios_abs() { // 0x0e
523 if ((s32)a0 < 0) v0 = -(s32)a0;
528 void psxBios_labs() { // 0x0f
532 void psxBios_atoi() { // 0x10
534 char *p = (char *)Ra0;
538 case ' ': case '\t': continue;
545 while (*p >= '0' && *p <= '9') {
546 n = n * 10 + *p++ - '0';
553 void psxBios_atol() { // 0x11
563 static void psxBios_setjmp() { // 0x13
564 struct jmp_buf_ *jmp_buf = castRam32ptr(a0);
567 PSXBIOS_LOG("psxBios_%s %x\n", biosA0n[0x13], a0);
569 jmp_buf->ra_ = SWAP32(ra);
570 jmp_buf->sp_ = SWAP32(sp);
571 jmp_buf->fp_ = SWAP32(fp);
572 for (i = 0; i < 8; i++) // s0-s7
573 jmp_buf->s[i] = SWAP32(psxRegs.GPR.r[16 + i]);
574 jmp_buf->gp_ = SWAP32(gp);
576 mips_return_c(0, 15);
579 static void longjmp_load(const struct jmp_buf_ *jmp_buf)
583 ra = SWAP32(jmp_buf->ra_);
584 sp = SWAP32(jmp_buf->sp_);
585 fp = SWAP32(jmp_buf->fp_);
586 for (i = 0; i < 8; i++) // s0-s7
587 psxRegs.GPR.r[16 + i] = SWAP32(jmp_buf->s[i]);
588 gp = SWAP32(jmp_buf->gp_);;
591 void psxBios_longjmp() { // 0x14
592 struct jmp_buf_ *jmp_buf = castRam32ptr(a0);
594 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x14]);
595 longjmp_load(jmp_buf);
596 mips_return_c(a1, 15);
599 void psxBios_strcat() { // 0x15
600 char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
603 PSXBIOS_LOG("psxBios_%s: %s, %s\n", biosA0n[0x15], Ra0, Ra1);
605 if (a0 == 0 || a1 == 0)
613 while ((*p1++ = *p2++) != '\0');
618 void psxBios_strncat() { // 0x16
619 char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
623 PSXBIOS_LOG("psxBios_%s: %s (%x), %s (%x), %d\n", biosA0n[0x16], Ra0, a0, Ra1, a1, a2);
625 if (a0 == 0 || a1 == 0)
633 while ((*p1++ = *p2++) != '\0') {
643 void psxBios_strcmp() { // 0x17
644 char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
646 if (a0 == 0 && a1 == 0)
652 else if (a0 == 0 && a1 != 0)
658 else if (a0 != 0 && a1 == 0)
665 PSXBIOS_LOG("psxBios_%s: %s (%x), %s (%x)\n", biosA0n[0x17], Ra0, a0, Ra1, a1);
668 while (*p1 == *p2++) {
687 void psxBios_strncmp() { // 0x18
688 char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
690 if (a0 == 0 && a1 == 0)
696 else if (a0 == 0 && a1 != 0)
702 else if (a0 != 0 && a1 == 0)
709 PSXBIOS_LOG("psxBios_%s: %s (%x), %s (%x), %d\n", biosA0n[0x18], Ra0, a0, Ra1, a1, a2);
712 while (--n >= 0 && *p1 == *p2++) {
716 v1 = a2 - ((a2-n) - 1);
724 v0 = (n < 0 ? 0 : *p1 - *--p2);
726 v1 = a2 - ((a2-n) - 1);
732 void psxBios_strcpy() { // 0x19
733 char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
734 if (a0 == 0 || a1 == 0)
740 while ((*p1++ = *p2++) != '\0');
745 void psxBios_strncpy() { // 0x1a
746 char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
748 if (a0 == 0 || a1 == 0)
754 for (i = 0; i < n; i++) {
755 if ((*p1++ = *p2++) == '\0') {
767 void psxBios_strlen() { // 0x1b
768 char *p = (char *)Ra0;
779 void psxBios_index() { // 0x1c
780 char *p = (char *)Ra0;
790 v0 = a0 + (p - (char *)Ra0);
794 } while (*p++ != '\0');
799 void psxBios_rindex() { // 0x1d
800 char *p = (char *)Ra0;
810 v0 = a0 + (p - (char *)Ra0);
811 } while (*p++ != '\0');
816 void psxBios_strchr() { // 0x1e
820 void psxBios_strrchr() { // 0x1f
824 void psxBios_strpbrk() { // 0x20
825 char *p1 = (char *)Ra0, *p2 = (char *)Ra1, *scanp, c, sc;
827 while ((c = *p1++) != '\0') {
828 for (scanp = p2; (sc = *scanp++) != '\0';) {
830 v0 = a0 + (p1 - 1 - (char *)Ra0);
837 // BUG: return a0 instead of NULL if not found
841 void psxBios_strspn() { // 0x21
844 for (p1 = (char *)Ra0; *p1 != '\0'; p1++) {
845 for (p2 = (char *)Ra1; *p2 != '\0' && *p2 != *p1; p2++);
846 if (*p2 == '\0') break;
849 v0 = p1 - (char *)Ra0; pc0 = ra;
852 void psxBios_strcspn() { // 0x22
855 for (p1 = (char *)Ra0; *p1 != '\0'; p1++) {
856 for (p2 = (char *)Ra1; *p2 != '\0' && *p2 != *p1; p2++);
857 if (*p2 != '\0') break;
860 v0 = p1 - (char *)Ra0; pc0 = ra;
863 void psxBios_strtok() { // 0x23
864 char *pcA0 = (char *)Ra0;
865 char *pcRet = strtok(pcA0, (char *)Ra1);
867 v0 = a0 + pcRet - pcA0;
873 void psxBios_strstr() { // 0x24
874 char *p = (char *)Ra0, *p1, *p2;
880 while (*p1 != '\0' && *p2 != '\0' && *p1 == *p2) {
885 v0 = a0 + (p - (char *)Ra0);
896 void psxBios_toupper() { // 0x25
897 v0 = (s8)(a0 & 0xff);
898 if (v0 >= 'a' && v0 <= 'z') v0 -= 'a' - 'A';
902 void psxBios_tolower() { // 0x26
903 v0 = (s8)(a0 & 0xff);
904 if (v0 >= 'A' && v0 <= 'Z') v0 += 'a' - 'A';
908 static void do_memset(u32 dst, u32 v, s32 len)
914 if (db != INVALID_PTR)
918 psxCpu->Clear(dst, (len + 3) / 4);
921 static void do_memcpy(u32 dst, u32 src, s32 len)
923 u32 d = dst, s = src;
926 const u8 *sb = PSXM(s);
928 if (db != INVALID_PTR && sb != INVALID_PTR)
933 psxCpu->Clear(dst, (len + 3) / 4);
936 static void psxBios_memcpy();
938 static void psxBios_bcopy() { // 0x27
939 psxBios_memcpy(); // identical
942 static void psxBios_bzero() { // 0x28
943 /* Same as memset here (See memset below) */
944 u32 ret = a0, cycles;
945 if (a0 == 0 || (s32)a1 <= 0)
950 do_memset(a0, 0, a1);
954 // todo: many more cycles due to uncached bios mem
955 mips_return_c(ret, cycles + 5);
958 void psxBios_bcmp() { // 0x29
959 char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
961 if (a0 == 0 || a1 == 0) { v0 = 0; pc0 = ra; return; }
963 while ((s32)a2-- > 0) {
964 if (*p1++ != *p2++) {
965 v0 = *p1 - *p2; // BUG: compare the NEXT byte
974 static void psxBios_memcpy() { // 0x2a
975 u32 ret = a0, cycles = 0;
982 do_memcpy(a0, a1, a2);
989 mips_return_c(ret, cycles + 5);
992 static void psxBios_memset() { // 0x2b
993 u32 ret = a0, cycles;
994 if (a0 == 0 || (s32)a2 <= 0)
999 do_memset(a0, a1, a2);
1003 // todo: many more cycles due to uncached bios mem
1004 mips_return_c(ret, cycles + 5);
1007 void psxBios_memmove() { // 0x2c
1008 u32 ret = a0, cycles = 0;
1011 mips_return_c(0, 4);
1015 if ((s32)a2 > 0 && a0 > a1 && a0 < a1 + a2) {
1016 u32 dst = a0, len = a2 + 1;
1019 while ((s32)a2 >= 0) { // BUG: copies one more byte here
1020 const u8 *sb = PSXM(a1);
1022 if (db != INVALID_PTR && sb != INVALID_PTR)
1028 psxCpu->Clear(dst, (len + 3) / 4);
1029 cycles = 10 + len * 8;
1030 } else if ((s32)a2 > 0) {
1031 do_memcpy(a0, a1, a2);
1037 mips_return_c(ret, cycles + 5);
1040 void psxBios_memcmp() { // 0x2d
1044 void psxBios_memchr() { // 0x2e
1045 char *p = (char *)Ra0;
1047 if (a0 == 0 || a2 > 0x7FFFFFFF)
1053 while ((s32)a2-- > 0) {
1054 if (*p++ != (s8)a1) continue;
1055 v0 = a0 + (p - (char *)Ra0 - 1);
1063 void psxBios_rand() { // 0x2f
1064 u32 s = psxMu32(0x9010) * 1103515245 + 12345;
1065 v0 = (s >> 16) & 0x7fff;
1066 psxMu32ref(0x9010) = SWAPu32(s);
1070 void psxBios_srand() { // 0x30
1071 psxMu32ref(0x9010) = SWAPu32(a0);
1075 static u32 qscmpfunc, qswidth;
1077 static inline int qscmp(char *a, char *b) {
1080 a0 = sa0 + (a - (char *)PSXM(sa0));
1081 a1 = sa0 + (b - (char *)PSXM(sa0));
1083 softCall(qscmpfunc);
1089 static inline void qexchange(char *i, char *j) {
1100 static inline void q3exchange(char *i, char *j, char *k) {
1112 static void qsort_main(char *a, char *l) {
1113 char *i, *j, *lp, *hp;
1118 if ((n = l - a) <= qswidth)
1120 n = qswidth * (n / (2 * qswidth));
1126 if ((c = qscmp(i, lp)) == 0) {
1127 qexchange(i, lp -= qswidth);
1138 if ((c = qscmp(hp, j)) == 0) {
1139 qexchange(hp += qswidth, j);
1144 q3exchange(i, hp += qswidth, j);
1158 if (lp - a >= l - hp) {
1159 qsort_main(hp + qswidth, l);
1168 q3exchange(j, lp -= qswidth, i);
1173 void psxBios_qsort() { // 0x31
1176 qsort_main((char *)Ra0, (char *)Ra0 + a1 * a2);
1181 // this isn't how the real bios works, but maybe good enough
1182 static void psxBios_malloc() { // 0x33
1183 u32 *heap_addr, *heap_end;
1184 u32 *chunk, *newchunk = NULL;
1185 unsigned int dsize = 0, csize, cstat;
1187 PSXBIOS_LOG("psxBios_%s %x\n", biosA0n[0x33], a0);
1188 heap_addr = loadRam32ptr(A_HEAP_BASE);
1189 heap_end = loadRam32ptr(A_HEAP_END);
1190 if (heap_addr >= heap_end) {
1196 // scan through heap and combine free chunks of space
1199 while(chunk < heap_end) {
1200 // get size and status of actual chunk
1201 csize = ((u32)*chunk) & 0xfffffffc;
1202 cstat = ((u32)*chunk) & 1;
1204 // most probably broken heap descriptor
1205 // this fixes Burning Road
1208 dsize = ((uptr)heap_end - (uptr)chunk) - 4;
1213 // it's a free chunk
1218 colflag = 1; // let's begin a new collection of free memory
1220 else dsize += (csize+4); // add the new size including header
1222 // not a free chunk: did we start a collection ?
1224 if(colflag == 1) { // collection is over
1226 *newchunk = SWAP32(dsize | 1);
1231 chunk = (u32*)((uptr)chunk + csize + 4);
1233 // if neccessary free memory on end of heap
1235 *newchunk = SWAP32(dsize | 1);
1238 csize = ((u32)*chunk) & 0xfffffffc;
1239 cstat = ((u32)*chunk) & 1;
1240 dsize = (a0 + 3) & 0xfffffffc;
1242 // exit on uninitialized heap
1243 if (chunk == NULL) {
1244 printf("malloc %x,%x: Uninitialized Heap!\n", v0, a0);
1250 // search an unused chunk that is big enough until the end of the heap
1251 while ((dsize > csize || cstat==0) && chunk < heap_end ) {
1252 chunk = (u32*)((uptr)chunk + csize + 4);
1254 // catch out of memory
1255 if(chunk >= heap_end) {
1256 printf("malloc %x,%x: Out of memory error!\n",
1262 csize = ((u32)*chunk) & 0xfffffffc;
1263 cstat = ((u32)*chunk) & 1;
1267 if(dsize == csize) {
1268 // chunk has same size
1269 *chunk &= 0xfffffffc;
1270 } else if (dsize > csize) {
1275 *chunk = SWAP32(dsize);
1276 newchunk = (u32*)((uptr)chunk + dsize + 4);
1277 *newchunk = SWAP32(((csize - dsize - 4) & 0xfffffffc) | 1);
1280 // return pointer to allocated memory
1281 v0 = ((uptr)chunk - (uptr)psxM) + 4;
1283 //printf ("malloc %x,%x\n", v0, a0);
1287 static void psxBios_free() { // 0x34
1288 PSXBIOS_LOG("psxBios_%s %x (%x bytes)\n", biosA0n[0x34], a0, loadRam32(a0 - 4));
1289 storeRam32(a0 - 4, loadRam32(a0 - 4) | 1); // set chunk to free
1290 mips_return_void_c(5);
1293 static void psxBios_calloc() { // 0x37
1295 PSXBIOS_LOG("psxBios_%s %x %x\n", biosA0n[0x37], a0, a1);
1297 a0 = size = a0 * a1;
1301 a0 = ret; a1 = size;
1304 mips_return_c(ret, 21);
1307 void psxBios_realloc() { // 0x38
1311 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x38]);
1315 /* If "old_buf" is zero, executes malloc(new_size), and returns r2=new_buf (or 0=failed). */
1320 /* Else, if "new_size" is zero, executes free(old_buf), and returns r2=garbage. */
1325 /* Else, executes malloc(new_size), bcopy(old_buf,new_buf,new_size), and free(old_buf), and returns r2=new_buf (or 0=failed). */
1326 /* Note that it is not quite implemented this way here. */
1336 /* InitHeap(void *block , int n) */
1337 static void psxBios_InitHeap() { // 0x39
1338 PSXBIOS_LOG("psxBios_%s %x %x\n", biosA0n[0x39], a0, a1);
1340 storeRam32(A_HEAP_BASE, a0);
1341 storeRam32(A_HEAP_SIZE, a1);
1342 storeRam32(A_HEAP_END, a0 + (a1 & ~3) + 4);
1343 storeRam32(A_HEAP_FLAG, 0);
1346 mips_return_void_c(14);
1349 void psxBios_getchar() { //0x3b
1350 v0 = getchar(); pc0 = ra;
1353 static void psxBios_printf_psxout() { // 0x3f
1362 if (psp != INVALID_PTR) {
1363 memcpy(save, psp, 4 * 4);
1364 psxMu32ref(sp) = SWAP32((u32)a0);
1365 psxMu32ref(sp + 4) = SWAP32((u32)a1);
1366 psxMu32ref(sp + 8) = SWAP32((u32)a2);
1367 psxMu32ref(sp + 12) = SWAP32((u32)a3);
1379 tmp2[j++] = Ra0[i]; goto _start;
1381 if (Ra0[i] >= '0' && Ra0[i] <= '9') {
1392 ptmp += sprintf(ptmp, tmp2, (float)psxMu32(sp + n * 4)); n++; break;
1396 ptmp += sprintf(ptmp, tmp2, (double)psxMu32(sp + n * 4)); n++; break;
1402 ptmp += sprintf(ptmp, tmp2, (unsigned int)psxMu32(sp + n * 4)); n++; break;
1404 ptmp += sprintf(ptmp, tmp2, (unsigned char)psxMu32(sp + n * 4)); n++; break;
1406 ptmp += sprintf(ptmp, tmp2, (char*)PSXM(psxMu32(sp + n * 4))); n++; break;
1408 *ptmp++ = Ra0[i]; break;
1418 if (psp != INVALID_PTR)
1419 memcpy(psp, save, 4 * 4);
1422 SysPrintf("%s", tmp);
1425 void psxBios_printf() { // 0x3f
1426 psxBios_printf_psxout();
1430 void psxBios_format() { // 0x41
1431 if (strcmp(Ra0, "bu00:") == 0 && Config.Mcd1[0] != '\0')
1433 CreateMcd(Config.Mcd1);
1434 LoadMcd(1, Config.Mcd1);
1437 else if (strcmp(Ra0, "bu10:") == 0 && Config.Mcd2[0] != '\0')
1439 CreateMcd(Config.Mcd2);
1440 LoadMcd(2, Config.Mcd2);
1450 static void psxBios_SystemErrorUnresolvedException() {
1451 if (loadRam32(0xfffc) != 0x12345678) { // prevent log flood
1452 SysPrintf("psxBios_%s called from %08x\n", biosA0n[0x40], ra);
1453 storeRam32(0xfffc, 0x12345678);
1455 mips_return_void_c(1000);
1459 * long Load(char *name, struct EXEC *header);
1462 void psxBios_Load() { // 0x42
1467 if (pa1 != INVALID_PTR && LoadCdromFile(Ra0, &eheader) == 0) {
1468 memcpy(pa1, ((char*)&eheader)+16, sizeof(EXEC));
1469 psxCpu->Clear(a1, sizeof(EXEC) / 4);
1472 PSXBIOS_LOG("psxBios_%s: %s, %d -> %d\n", biosA0n[0x42], Ra0, a1, v0);
1478 * int Exec(struct EXEC *header , int argc , char **argv);
1481 void psxBios_Exec() { // 43
1482 EXEC *header = (EXEC *)castRam32ptr(a0);
1486 PSXBIOS_LOG("psxBios_%s: %x, %x, %x\n", biosA0n[0x43], a0, a1, a2);
1488 header->_sp = SWAP32(sp);
1489 header->_fp = SWAP32(fp);
1490 header->_sp = SWAP32(sp);
1491 header->_gp = SWAP32(gp);
1492 header->ret = SWAP32(ra);
1493 header->base = SWAP32(s0);
1495 ptr = SWAP32(header->b_addr);
1496 len = SWAP32(header->b_size);
1502 if (header->S_addr != 0)
1503 sp = fp = SWAP32(header->S_addr) + SWAP32(header->s_size);
1505 gp = SWAP32(header->gp0);
1513 pc0 = SWAP32(header->_pc0);
1516 void psxBios_FlushCache() { // 44
1518 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x44]);
1520 psxCpu->Notify(R3000ACPU_NOTIFY_CACHE_ISOLATED, NULL);
1521 psxCpu->Notify(R3000ACPU_NOTIFY_CACHE_UNISOLATED, NULL);
1525 void psxBios_GPU_dw() { // 0x46
1530 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x46]);
1533 GPU_writeData(0xa0000000);
1534 GPU_writeData((a1<<0x10)|(a0&0xffff));
1535 GPU_writeData((a3<<0x10)|(a2&0xffff));
1537 ptr = (u32*)PSXM(Rsp[4]); //that is correct?
1540 GPU_writeData(SWAPu32(*ptr++));
1546 void psxBios_mem2vram() { // 0x47
1549 GPU_writeData(0xa0000000);
1550 GPU_writeData((a1<<0x10)|(a0&0xffff));
1551 GPU_writeData((a3<<0x10)|(a2&0xffff));
1552 size = ((((a2 * a3) / 2) >> 4) << 16);
1553 GPU_writeStatus(0x04000002);
1554 psxHwWrite32(0x1f8010f4,0);
1555 psxHwWrite32(0x1f8010f0,psxHwRead32(0x1f8010f0)|0x800);
1556 psxHwWrite32(0x1f8010a0,Rsp[4]);//might have a buggy...
1557 psxHwWrite32(0x1f8010a4, size | 0x10);
1558 psxHwWrite32(0x1f8010a8,0x01000201);
1563 void psxBios_SendGPU() { // 0x48
1564 GPU_writeStatus(a0);
1569 void psxBios_GPU_cw() { // 0x49
1576 void psxBios_GPU_cwb() { // 0x4a
1577 u32 *ptr = (u32*)Ra0;
1582 GPU_writeData(SWAPu32(*ptr++));
1588 void psxBios_GPU_SendPackets() { //4b:
1590 GPU_writeStatus(0x04000002);
1591 psxHwWrite32(0x1f8010f4,0);
1592 psxHwWrite32(0x1f8010f0,psxHwRead32(0x1f8010f0)|0x800);
1593 psxHwWrite32(0x1f8010a0,a0);
1594 psxHwWrite32(0x1f8010a4,0);
1595 psxHwWrite32(0x1f8010a8,0x010000401);
1599 void psxBios_sys_a0_4c() { // 0x4c GPU relate
1600 psxHwWrite32(0x1f8010a8,0x00000401);
1601 GPU_writeData(0x0400000);
1602 GPU_writeData(0x0200000);
1603 GPU_writeData(0x0100000);
1608 void psxBios_GPU_GetGPUStatus() { // 0x4d
1609 v0 = GPU_readStatus();
1615 void psxBios_LoadExec() { // 51
1616 EXEC *header = (EXEC*)PSXM(0xf000);
1620 PSXBIOS_LOG("psxBios_%s: %s: %x,%x\n", biosA0n[0x51], Ra0, a1, a2);
1622 s_addr = a1; s_size = a2;
1627 header->S_addr = s_addr;
1628 header->s_size = s_size;
1630 a0 = 0xf000; a1 = 0; a2 = 0;
1634 void psxBios__bu_init() { // 70
1636 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x70]);
1639 DeliverEvent(0xf0000011, 0x0004);
1640 DeliverEvent(0xf4000001, 0x0004);
1645 void psxBios__96_init() { // 71
1647 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x71]);
1653 static void write_chain(u32 *d, u32 next, u32 handler1, u32 handler2);
1654 static void psxBios_SysEnqIntRP_(u32 priority, u32 chain_eptr);
1655 static void psxBios_SysDeqIntRP_(u32 priority, u32 chain_rm_eptr);
1657 static void psxBios_DequeueCdIntr_() {
1658 psxBios_SysDeqIntRP_(0, 0x91d0);
1659 psxBios_SysDeqIntRP_(0, 0x91e0);
1663 static void psxBios_DequeueCdIntr() { // a3
1664 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0xa3]);
1665 psxBios_DequeueCdIntr_();
1668 static void psxBios_CdRemove() { // 56, 72
1669 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x72]);
1671 CloseEvent(loadRam32(A_CD_EVENTS + 0x00));
1672 CloseEvent(loadRam32(A_CD_EVENTS + 0x04));
1673 CloseEvent(loadRam32(A_CD_EVENTS + 0x08));
1674 CloseEvent(loadRam32(A_CD_EVENTS + 0x0c));
1675 CloseEvent(loadRam32(A_CD_EVENTS + 0x10));
1676 psxBios_DequeueCdIntr_();
1678 // EnterCriticalSection - should be done at the beginning,
1679 // but this way is much easier to implement
1685 void psxBios_SetMem() { // 9f
1686 u32 new = psxHu32(0x1060);
1689 PSXBIOS_LOG("psxBios_%s: %x, %x\n", biosA0n[0x9f], a0, a1);
1694 psxHu32ref(0x1060) = SWAP32(new);
1695 psxMu32ref(0x060) = a0;
1696 PSXBIOS_LOG("Change effective memory : %d MBytes\n",a0);
1700 psxHu32ref(0x1060) = SWAP32(new | 0x300);
1701 psxMu32ref(0x060) = a0;
1702 PSXBIOS_LOG("Change effective memory : %d MBytes\n",a0);
1705 PSXBIOS_LOG("Effective memory must be 2/8 MBytes\n");
1712 /* TODO FIXME : Not compliant. -1 indicates failure but using 1 for now. */
1713 static void psxBios_get_cd_status() // a6
1715 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0xa6]);
1720 static void psxBios__card_info() { // ab
1721 PSXBIOS_LOG("psxBios_%s: %x\n", biosA0n[0xab], a0);
1723 storeRam32(A_CARD_CHAN1, a0);
1730 if (McdDisable[port & 1])
1734 PSXBIOS_LOG("psxBios_%s: UNKNOWN PORT 0x%x\n", biosA0n[0xab], a0);
1739 if (McdDisable[0] && McdDisable[1])
1742 DeliverEvent(0xf0000011, 0x0004);
1743 // DeliverEvent(0xf4000001, 0x0004);
1744 DeliverEvent(0xf4000001, ret);
1748 void psxBios__card_load() { // ac
1750 PSXBIOS_LOG("psxBios_%s: %x\n", biosA0n[0xac], a0);
1753 storeRam32(A_CARD_CHAN1, a0);
1755 // DeliverEvent(0xf0000011, 0x0004);
1756 DeliverEvent(0xf4000001, 0x0004);
1761 static void psxBios_GetSystemInfo() { // b4
1763 //PSXBIOS_LOG("psxBios_%s %x\n", biosA0n[0xb4], a0);
1764 SysPrintf("psxBios_%s %x\n", biosA0n[0xb4], a0);
1767 case 1: ret = SWAP32(((u32 *)psxR)[0x100/4 + a0]); break;
1768 case 2: ret = 0xbfc0012c; break;
1769 case 5: ret = loadRam32(0x60) << 10; break;
1771 mips_return_c(ret, 20);
1774 /* System calls B0 */
1776 static u32 psxBios_SysMalloc_(u32 size);
1778 static void psxBios_SysMalloc() { // B 00
1779 u32 ret = psxBios_SysMalloc_(a0);
1781 PSXBIOS_LOG("psxBios_%s 0x%x -> %x\n", biosB0n[0x00], a0, ret);
1782 mips_return_c(ret, 33);
1785 void psxBios_SetRCnt() { // 02
1787 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x02]);
1794 psxRcntWtarget(a0, a1);
1795 if (a2&0x1000) mode|= 0x050; // Interrupt Mode
1796 if (a2&0x0100) mode|= 0x008; // Count to 0xffff
1797 if (a2&0x0010) mode|= 0x001; // Timer stop mode
1798 if (a0 == 2) { if (a2&0x0001) mode|= 0x200; } // System Clock mode
1799 else { if (a2&0x0001) mode|= 0x100; } // System Clock mode
1801 psxRcntWmode(a0, mode);
1806 void psxBios_GetRCnt() { // 03
1808 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x03]);
1812 if (a0 != 3) v0 = psxRcntRcount(a0);
1817 void psxBios_StartRCnt() { // 04
1819 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x04]);
1823 if (a0 != 3) psxHu32ref(0x1074)|= SWAP32((u32)((1<<(a0+4))));
1824 else psxHu32ref(0x1074)|= SWAPu32(0x1);
1828 void psxBios_StopRCnt() { // 05
1830 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x05]);
1834 if (a0 != 3) psxHu32ref(0x1074)&= SWAP32((u32)(~(1<<(a0+4))));
1835 else psxHu32ref(0x1074)&= SWAPu32(~0x1);
1839 void psxBios_ResetRCnt() { // 06
1841 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x06]);
1846 psxRcntWmode(a0, 0);
1847 psxRcntWtarget(a0, 0);
1848 psxRcntWcount(a0, 0);
1853 static u32 DeliverEvent(u32 class, u32 spec) {
1854 EvCB *ev = (EvCB *)loadRam32ptr(A_TT_EvCB);
1855 u32 evcb_len = loadRam32(A_TT_EvCB + 4);
1856 u32 ret = loadRam32(A_TT_EvCB) + evcb_len;
1857 u32 i, lim = evcb_len / 0x1c;
1859 for (i = 0; i < lim; i++, ev++) {
1861 if (SWAP32(ev->status) != EvStACTIVE)
1864 if (SWAP32(ev->class) != class)
1867 if (SWAP32(ev->spec) != spec)
1870 ret = SWAP32(ev->mode);
1871 if (ret == EvMdMARK) {
1872 ev->status = SWAP32(EvStALREADY);
1876 if (ret == EvMdCALL) {
1877 ret = SWAP32(ev->fhandler);
1889 static u32 UnDeliverEvent(u32 class, u32 spec) {
1890 EvCB *ev = (EvCB *)loadRam32ptr(A_TT_EvCB);
1891 u32 evcb_len = loadRam32(A_TT_EvCB + 4);
1892 u32 ret = loadRam32(A_TT_EvCB) + evcb_len;
1893 u32 i, lim = evcb_len / 0x1c;
1895 for (i = 0; i < lim; i++, ev++) {
1897 if (SWAP32(ev->status) != EvStALREADY)
1900 if (SWAP32(ev->class) != class)
1903 if (SWAP32(ev->spec) != spec)
1906 if (SWAP32(ev->mode) == EvMdMARK)
1907 ev->status = SWAP32(EvStACTIVE);
1913 static void psxBios_DeliverEvent() { // 07
1915 PSXBIOS_LOG("psxBios_%s %x %04x\n", biosB0n[0x07], a0, a1);
1917 ret = DeliverEvent(a0, a1);
1921 static s32 get_free_EvCB_slot() {
1922 EvCB *ev = (EvCB *)loadRam32ptr(A_TT_EvCB);
1923 u32 i, lim = loadRam32(A_TT_EvCB + 4) / 0x1c;
1926 for (i = 0; i < lim; i++, ev++) {
1928 if (ev->status == SWAP32(EvStUNUSED))
1934 static u32 OpenEvent(u32 class, u32 spec, u32 mode, u32 func) {
1935 u32 ret = get_free_EvCB_slot();
1936 if ((s32)ret >= 0) {
1937 EvCB *ev = (EvCB *)loadRam32ptr(A_TT_EvCB) + ret;
1938 ev->class = SWAP32(class);
1939 ev->status = SWAP32(EvStDISABLED);
1940 ev->spec = SWAP32(spec);
1941 ev->mode = SWAP32(mode);
1942 ev->fhandler = SWAP32(func);
1948 static void psxBios_OpenEvent() { // 08
1949 u32 ret = OpenEvent(a0, a1, a2, a3);
1950 PSXBIOS_LOG("psxBios_%s (class:%x, spec:%04x, mode:%04x, func:%x) -> %x\n",
1951 biosB0n[0x08], a0, a1, a2, a3, ret);
1952 mips_return_c(ret, 36);
1955 static void CloseEvent(u32 ev)
1957 u32 base = loadRam32(A_TT_EvCB);
1958 storeRam32(base + (ev & 0xffff) * sizeof(EvCB) + 4, EvStUNUSED);
1961 static void psxBios_CloseEvent() { // 09
1962 PSXBIOS_LOG("psxBios_%s %x (%x)\n", biosB0n[0x09], a0,
1963 loadRam32(loadRam32(A_TT_EvCB) + (a0 & 0xffff) * sizeof(EvCB) + 4));
1965 mips_return_c(1, 10);
1968 static void psxBios_WaitEvent() { // 0a
1969 u32 base = loadRam32(A_TT_EvCB);
1970 u32 status = loadRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4);
1971 PSXBIOS_LOG("psxBios_%s %x (status=%x)\n", biosB0n[0x0a], a0, status);
1974 if (status == EvStALREADY) {
1975 storeRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4, EvStACTIVE);
1979 if (status != EvStACTIVE)
1981 mips_return_c(0, 2);
1985 // retrigger this hlecall after the next emulation event
1987 if ((s32)(next_interupt - psxRegs.cycle) > 0)
1988 psxRegs.cycle = next_interupt;
1992 static void psxBios_TestEvent() { // 0b
1993 u32 base = loadRam32(A_TT_EvCB);
1994 u32 status = loadRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4);
1996 PSXBIOS_LOG("psxBios_%s %x %x\n", biosB0n[0x0b], a0, status);
1997 if (status == EvStALREADY) {
1998 storeRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4, EvStACTIVE);
2002 mips_return_c(ret, 15);
2005 static void psxBios_EnableEvent() { // 0c
2006 u32 base = loadRam32(A_TT_EvCB);
2007 u32 status = loadRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4);
2008 PSXBIOS_LOG("psxBios_%s %x (%x)\n", biosB0n[0x0c], a0, status);
2009 if (status != EvStUNUSED)
2010 storeRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4, EvStACTIVE);
2012 mips_return_c(1, 15);
2015 static void psxBios_DisableEvent() { // 0d
2016 u32 base = loadRam32(A_TT_EvCB);
2017 u32 status = loadRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4);
2018 PSXBIOS_LOG("psxBios_%s %x: %x\n", biosB0n[0x0d], a0, status);
2019 if (status != EvStUNUSED)
2020 storeRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4, EvStDISABLED);
2022 mips_return_c(1, 15);
2026 * long OpenTh(long (*func)(), unsigned long sp, unsigned long gp);
2029 void psxBios_OpenTh() { // 0e
2030 TCB *tcb = loadRam32ptr(A_TT_TCB);
2031 u32 limit = loadRam32(A_TT_TCB + 4) / 0xc0u;
2034 for (th = 1; th < limit; th++)
2036 if (tcb[th].status != SWAP32(0x4000)) break;
2040 // Feb 2019 - Added out-of-bounds fix caught by cppcheck:
2041 // When no free TCB is found, return 0xffffffff according to Nocash doc.
2043 PSXBIOS_LOG("\t%s() WARNING! No Free TCBs found!\n", __func__);
2045 mips_return_c(0xffffffff, 20);
2048 PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x0e], th);
2050 tcb[th].status = SWAP32(0x4000);
2051 tcb[th].mode = SWAP32(0x1000);
2052 tcb[th].epc = SWAP32(a0);
2053 tcb[th].reg[30] = SWAP32(a1); // fp
2054 tcb[th].reg[29] = SWAP32(a1); // sp
2055 tcb[th].reg[28] = SWAP32(a2); // gp
2057 mips_return_c(0xff000000 + th, 34);
2061 * int CloseTh(long thread);
2064 void psxBios_CloseTh() { // 0f
2065 TCB *tcb = loadRam32ptr(A_TT_TCB);
2066 u32 limit = loadRam32(A_TT_TCB + 4) / 0xc0u;
2070 PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x0f], th);
2072 /* The return value is always 1 (even if the handle was already closed). */
2074 if (th < limit && tcb[th].status == SWAP32(0x4000)) {
2075 tcb[th].status = SWAP32(0x1000);
2082 * int ChangeTh(long thread);
2085 void psxBios_ChangeTh() { // 10
2086 u32 tcbBase = loadRam32(A_TT_TCB);
2087 u32 th = a0 & 0xffff;
2089 // this is quite spammy
2090 //PSXBIOS_LOG("psxBios_%s %x\n", biosB0n[0x10], th);
2092 // without doing any argument checks, just issue a syscall
2093 // (like the real bios does)
2095 a1 = tcbBase + th * sizeof(TCB);
2100 void psxBios_InitPAD() { // 0x12
2101 u32 i, *ram32 = (u32 *)psxM;
2102 PSXBIOS_LOG("psxBios_%s %x %x %x %x\n", biosB0n[0x12], a0, a1, a2, a3);
2104 // printf("%s", "PS-X Control PAD Driver Ver 3.0");
2105 ram32[A_PAD_DR_DST/4] = 0;
2106 ram32[A_PAD_OUTBUF/4 + 0] = 0;
2107 ram32[A_PAD_OUTBUF/4 + 1] = 0;
2108 ram32[A_PAD_OUT_LEN/4 + 0] = 0;
2109 ram32[A_PAD_OUT_LEN/4 + 1] = 0;
2110 ram32[A_PAD_INBUF/4 + 0] = SWAP32(a0);
2111 ram32[A_PAD_INBUF/4 + 1] = SWAP32(a2);
2112 ram32[A_PAD_IN_LEN/4 + 0] = SWAP32(a1);
2113 ram32[A_PAD_IN_LEN/4 + 1] = SWAP32(a3);
2115 for (i = 0; i < a1; i++) {
2117 storeRam8(a0 + i, 0);
2119 for (i = 0; i < a3; i++) {
2121 storeRam8(a2 + i, 0);
2123 write_chain(ram32 + A_PADCRD_CHN_E/4, 0, 0x49bc, 0x4a4c);
2125 ram32[A_PAD_IRQR_ENA/4] = SWAP32(1);
2127 mips_return_c(1, 200);
2130 void psxBios_StartPAD() { // 13
2131 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x13]);
2133 psxBios_SysDeqIntRP_(2, A_PADCRD_CHN_E);
2134 psxBios_SysEnqIntRP_(2, A_PADCRD_CHN_E);
2135 psxHwWrite16(0x1f801070, ~1);
2136 psxHwWrite16(0x1f801074, psxHu32(0x1074) | 1);
2137 storeRam32(A_PAD_ACK_VBL, 1);
2138 storeRam32(A_RCNT_VBL_ACK + (3 << 2), 0);
2139 psxRegs.CP0.n.SR |= 0x401;
2141 mips_return_c(1, 300);
2144 void psxBios_StopPAD() { // 14
2145 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x14]);
2146 storeRam32(A_RCNT_VBL_ACK + (3 << 2), 1);
2147 psxBios_SysDeqIntRP_(2, A_PADCRD_CHN_E);
2148 psxRegs.CP0.n.SR |= 0x401;
2149 mips_return_void_c(200);
2152 static void psxBios_PAD_init() { // 15
2154 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x15]);
2155 if (a0 == 0x20000000 || a0 == 0x20000001)
2158 a0 = A_PAD_DR_BUF1; a1 = 0x22;
2159 a2 = A_PAD_DR_BUF2; a3 = 0x22;
2162 storeRam32(A_PAD_DR_DST, dst);
2165 mips_return_c(ret, 100);
2168 static u32 psxBios_PAD_dr_() {
2169 u8 *dst = loadRam32ptr(A_PAD_DR_DST);
2170 u8 *buf1 = castRam8ptr(A_PAD_DR_BUF1);
2171 u8 *buf2 = castRam8ptr(A_PAD_DR_BUF2);
2172 dst[0] = dst[1] = dst[2] = dst[3] = ~0;
2173 if (buf1[0] == 0 && (buf1[1] == 0x23 || buf1[1] == 0x41))
2175 dst[0] = buf1[3], dst[1] = buf1[2];
2176 if (buf1[1] == 0x23) {
2177 dst[0] |= 0xc7, dst[1] |= 7;
2178 if (buf1[5] >= 0x10) dst[0] &= ~(1u << 6);
2179 if (buf1[6] >= 0x10) dst[0] &= ~(1u << 7);
2182 if (buf2[0] == 0 && (buf2[1] == 0x23 || buf2[1] == 0x41))
2184 dst[2] = buf2[3], dst[3] = buf2[2];
2185 if (buf2[1] == 0x23) {
2186 dst[2] |= 0xc7, dst[3] |= 7;
2187 if (buf2[5] >= 0x10) dst[2] &= ~(1u << 6);
2188 if (buf2[6] >= 0x10) dst[2] &= ~(1u << 7);
2192 return SWAP32(*(u32 *)dst);
2195 static void psxBios_PAD_dr() { // 16
2196 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x16]);
2197 u32 ret = psxBios_PAD_dr_();
2201 static void psxBios_ReturnFromException() { // 17
2202 u32 tcbPtr = loadRam32(A_TT_PCB);
2203 const TCB *tcb = loadRam32ptr(tcbPtr);
2207 for (i = 1; i < 32; i++)
2208 psxRegs.GPR.r[i] = SWAP32(tcb->reg[i]);
2209 psxRegs.GPR.n.lo = SWAP32(tcb->lo);
2210 psxRegs.GPR.n.hi = SWAP32(tcb->hi);
2211 sr = SWAP32(tcb->sr);
2213 //printf("%s %08x->%08x %u\n", __func__, pc0, tcb->epc, psxRegs.cycle);
2214 pc0 = k0 = SWAP32(tcb->epc);
2216 // the interpreter wants to know about sr changes, so do a MTC0
2217 sr = (sr & ~0x0f) | ((sr & 0x3c) >> 2);
2218 MTC0(&psxRegs, 12, sr);
2224 void psxBios_ResetEntryInt() { // 18
2225 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x18]);
2227 storeRam32(A_EEXIT_PTR, A_EEXIT_DEF);
2228 mips_return_void_c(5);
2231 void psxBios_HookEntryInt() { // 19
2232 PSXBIOS_LOG("psxBios_%s %x\n", biosB0n[0x19], a0);
2234 storeRam32(A_EEXIT_PTR, a0);
2235 mips_return_void_c(3);
2238 static void psxBios_UnDeliverEvent() { // 0x20
2240 PSXBIOS_LOG("psxBios_%s %x %x\n", biosB0n[0x20], a0, a1);
2242 ret = UnDeliverEvent(a0, a1);
2246 static void buopen(int mcd, char *ptr, char *cfg)
2249 char *mcd_data = ptr;
2251 strcpy(FDesc[1 + mcd].name, Ra0+5);
2252 FDesc[1 + mcd].offset = 0;
2253 FDesc[1 + mcd].mode = a1;
2255 for (i=1; i<16; i++) {
2256 const char *fptr = mcd_data + 128 * i;
2257 if ((*fptr & 0xF0) != 0x50) continue;
2258 if (strcmp(FDesc[1 + mcd].name, fptr+0xa)) continue;
2259 FDesc[1 + mcd].mcfile = i;
2260 PSXBIOS_LOG("open %s\n", fptr+0xa);
2264 if (a1 & 0x200 && v0 == -1) { /* FCREAT */
2265 for (i=1; i<16; i++) {
2266 int j, xor, nblk = a1 >> 16;
2268 char *fptr = mcd_data + 128 * i;
2270 if ((*fptr & 0xF0) != 0xa0) continue;
2272 FDesc[1 + mcd].mcfile = i;
2275 fptr[5] = 0x20 * nblk;
2278 strcpy(fptr+0xa, FDesc[1 + mcd].name);
2279 pptr = fptr2 = fptr;
2280 for(j=2; j<=nblk; j++) {
2282 for(i++; i<16; i++) {
2285 memset(fptr2, 0, 128);
2286 fptr2[0] = j < nblk ? 0x52 : 0x53;
2289 for (k=0, xor=0; k<127; k++) xor^= pptr[k];
2294 /* shouldn't this return ENOSPC if i == 16? */
2296 pptr[8] = pptr[9] = 0xff;
2297 for (j=0, xor=0; j<127; j++) xor^= pptr[j];
2299 PSXBIOS_LOG("openC %s %d\n", ptr, nblk);
2301 /* just go ahead and resave them all */
2302 SaveMcd(cfg, ptr, 128, 128 * 15);
2305 /* shouldn't this return ENOSPC if i == 16? */
2310 * int open(char *name , int mode);
2313 void psxBios_open() { // 0x32
2317 PSXBIOS_LOG("psxBios_%s: %s,%x\n", biosB0n[0x32], Ra0, a1);
2322 if (pa0 != INVALID_PTR) {
2323 if (!strncmp(pa0, "bu00", 4)) {
2324 buopen(1, Mcd1Data, Config.Mcd1);
2327 if (!strncmp(pa0, "bu10", 4)) {
2328 buopen(2, Mcd2Data, Config.Mcd2);
2336 * int lseek(int fd , int offset , int whence);
2339 void psxBios_lseek() { // 0x33
2341 PSXBIOS_LOG("psxBios_%s: %x, %x, %x\n", biosB0n[0x33], a0, a1, a2);
2346 FDesc[a0].offset = a1;
2348 // DeliverEvent(0xf0000011, 0x0004);
2349 // DeliverEvent(0xf4000001, 0x0004);
2353 FDesc[a0].offset+= a1;
2354 v0 = FDesc[a0].offset;
2363 * int read(int fd , void *buf , int nbytes);
2366 void psxBios_read() { // 0x34
2371 PSXBIOS_LOG("psxBios_%s: %x, %x, %x\n", biosB0n[0x34], a0, a1, a2);
2376 if (pa1 != INVALID_PTR) {
2378 case 2: buread(pa1, 1, a2); break;
2379 case 3: buread(pa1, 2, a2); break;
2387 * int write(int fd , void *buf , int nbytes);
2390 void psxBios_write() { // 0x35/0x03
2394 if (a0 != 1) // stdout
2395 PSXBIOS_LOG("psxBios_%s: %x,%x,%x\n", biosB0n[0x35], a0, a1, a2);
2398 if (pa1 == INVALID_PTR) {
2403 if (a0 == 1) { // stdout
2407 if (Config.PsxOut) while (a2 > 0) {
2408 SysPrintf("%c", *ptr++); a2--;
2414 case 2: buwrite(pa1, 1, a2); break;
2415 case 3: buwrite(pa1, 2, a2); break;
2421 static void psxBios_write_psxout() {
2422 if (a0 == 1) { // stdout
2423 const char *ptr = Ra1;
2426 if (ptr != INVALID_PTR)
2428 SysPrintf("%c", *ptr++);
2432 static void psxBios_putchar_psxout() { // 3d
2433 SysPrintf("%c", (char)a0);
2436 static void psxBios_puts_psxout() { // 3e/3f
2437 SysPrintf("%s", Ra0);
2441 * int close(int fd);
2444 void psxBios_close() { // 0x36
2446 PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x36], a0);
2453 void psxBios_putchar() { // 3d
2454 if (Config.PsxOut) SysPrintf("%c", (char)a0);
2458 void psxBios_puts() { // 3e/3f
2459 if (Config.PsxOut) SysPrintf("%s", Ra0);
2464 /* To avoid any issues with different behaviour when using the libc's own strlen instead.
2465 * We want to mimic the PSX's behaviour in this case for bufile. */
2466 static size_t strlen_internal(char* p)
2468 size_t size_of_array = 0;
2469 while (*p++) size_of_array++;
2470 return size_of_array;
2473 #define bufile(mcd) { \
2474 size_t size_of_name = strlen_internal(dir->name); \
2475 while (nfile < 16) { \
2478 ptr = Mcd##mcd##Data + 128 * (nfile + 1); \
2480 if ((*ptr & 0xF0) != 0x50) continue; \
2481 /* Bug link files show up as free block. */ \
2482 if (!ptr[0xa]) continue; \
2484 if (pfile[0] == 0) { \
2485 strncpy(dir->name, ptr, sizeof(dir->name) - 1); \
2486 if (size_of_name < sizeof(dir->name)) dir->name[size_of_name] = '\0'; \
2487 } else for (i=0; i<20; i++) { \
2488 if (pfile[i] == ptr[i]) { \
2489 dir->name[i] = ptr[i]; continue; } \
2490 if (pfile[i] == '?') { \
2491 dir->name[i] = ptr[i]; continue; } \
2492 if (pfile[i] == '*') { \
2493 strcpy(dir->name+i, ptr+i); break; } \
2496 PSXBIOS_LOG("%d : %s = %s + %s (match=%d)\n", nfile, dir->name, pfile, ptr, match); \
2497 if (match == 0) { continue; } \
2505 * struct DIRENTRY* firstfile(char *name,struct DIRENTRY *dir);
2508 void psxBios_firstfile() { // 42
2509 struct DIRENTRY *dir = (struct DIRENTRY *)Ra1;
2516 PSXBIOS_LOG("psxBios_%s: %s\n", biosB0n[0x42], Ra0);
2521 if (pa0 != INVALID_PTR) {
2525 if (!strncmp(pa0, "bu00", 4)) {
2526 // firstfile() calls _card_read() internally, so deliver it's event
2527 DeliverEvent(0xf0000011, 0x0004);
2529 } else if (!strncmp(pa0, "bu10", 4)) {
2530 // firstfile() calls _card_read() internally, so deliver it's event
2531 DeliverEvent(0xf0000011, 0x0004);
2540 * struct DIRENTRY* nextfile(struct DIRENTRY *dir);
2543 void psxBios_nextfile() { // 43
2544 struct DIRENTRY *dir = (struct DIRENTRY *)Ra0;
2550 PSXBIOS_LOG("psxBios_%s: %s\n", biosB0n[0x43], dir->name);
2555 if (!strncmp(ffile, "bu00", 4)) {
2559 if (!strncmp(ffile, "bu10", 4)) {
2566 #define burename(mcd) { \
2567 for (i=1; i<16; i++) { \
2568 int namelen, j, xor = 0; \
2569 ptr = Mcd##mcd##Data + 128 * i; \
2570 if ((*ptr & 0xF0) != 0x50) continue; \
2571 if (strcmp(Ra0+5, ptr+0xa)) continue; \
2572 namelen = strlen(Ra1+5); \
2573 memcpy(ptr+0xa, Ra1+5, namelen); \
2574 memset(ptr+0xa+namelen, 0, 0x75-namelen); \
2575 for (j=0; j<127; j++) xor^= ptr[j]; \
2577 SaveMcd(Config.Mcd##mcd, Mcd##mcd##Data, 128 * i + 0xa, 0x76); \
2584 * int rename(char *old, char *new);
2587 void psxBios_rename() { // 44
2594 PSXBIOS_LOG("psxBios_%s: %s,%s\n", biosB0n[0x44], Ra0, Ra1);
2599 if (pa0 != INVALID_PTR && pa1 != INVALID_PTR) {
2600 if (!strncmp(pa0, "bu00", 4) && !strncmp(pa1, "bu00", 4)) {
2604 if (!strncmp(pa0, "bu10", 4) && !strncmp(pa1, "bu10", 4)) {
2613 #define budelete(mcd) { \
2614 for (i=1; i<16; i++) { \
2615 ptr = Mcd##mcd##Data + 128 * i; \
2616 if ((*ptr & 0xF0) != 0x50) continue; \
2617 if (strcmp(Ra0+5, ptr+0xa)) continue; \
2618 *ptr = (*ptr & 0xf) | 0xA0; \
2619 SaveMcd(Config.Mcd##mcd, Mcd##mcd##Data, 128 * i, 1); \
2620 PSXBIOS_LOG("delete %s\n", ptr+0xa); \
2627 * int delete(char *name);
2630 void psxBios_delete() { // 45
2636 PSXBIOS_LOG("psxBios_%s: %s\n", biosB0n[0x45], Ra0);
2641 if (pa0 != INVALID_PTR) {
2642 if (!strncmp(pa0, "bu00", 4)) {
2646 if (!strncmp(pa0, "bu10", 4)) {
2654 void psxBios_InitCARD() { // 4a
2655 u32 *ram32 = (u32 *)psxM;
2656 PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x4a], a0);
2657 write_chain(ram32 + A_PADCRD_CHN_E/4, 0, 0x49bc, 0x4a4c);
2658 // (maybe) todo: early_card_irq, FlushCache etc
2660 ram32[A_PAD_IRQR_ENA/4] = SWAP32(a0);
2662 mips_return_c(0, 300);
2665 void psxBios_StartCARD() { // 4b
2666 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x4b]);
2667 psxBios_SysDeqIntRP_(2, A_PADCRD_CHN_E);
2668 psxBios_SysEnqIntRP_(2, A_PADCRD_CHN_E);
2670 psxHwWrite16(0x1f801074, psxHu32(0x1074) | 1);
2671 storeRam32(A_PAD_ACK_VBL, 1);
2672 storeRam32(A_RCNT_VBL_ACK + (3 << 2), 0);
2673 storeRam32(A_CARD_IRQR_ENA, 1);
2674 psxRegs.CP0.n.SR |= 0x401;
2676 mips_return_c(1, 200);
2679 void psxBios_StopCARD() { // 4c
2680 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x4c]);
2681 storeRam32(A_RCNT_VBL_ACK + (3 << 2), 1);
2682 psxBios_SysDeqIntRP_(2, A_PADCRD_CHN_E);
2683 storeRam32(A_CARD_IRQR_ENA, 0);
2684 psxRegs.CP0.n.SR |= 0x401;
2685 mips_return_void_c(200);
2688 void psxBios__card_write() { // 0x4e
2693 PSXBIOS_LOG("psxBios_%s: %x,%x,%x\n", biosB0n[0x4e], a0, a1, a2);
2696 Function also accepts sector 400h (a bug).
2697 But notaz said we shouldn't allow sector 400h because it can corrupt the emulator.
2701 /* Invalid sectors */
2705 storeRam32(A_CARD_CHAN1, a0);
2708 if (pa2 != INVALID_PTR) {
2710 memcpy(Mcd1Data + a1 * 128, pa2, 128);
2711 SaveMcd(Config.Mcd1, Mcd1Data, a1 * 128, 128);
2713 memcpy(Mcd2Data + a1 * 128, pa2, 128);
2714 SaveMcd(Config.Mcd2, Mcd2Data, a1 * 128, 128);
2718 DeliverEvent(0xf0000011, 0x0004);
2719 // DeliverEvent(0xf4000001, 0x0004);
2724 void psxBios__card_read() { // 0x4f
2729 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x4f]);
2732 Function also accepts sector 400h (a bug).
2733 But notaz said we shouldn't allow sector 400h because it can corrupt the emulator.
2737 /* Invalid sectors */
2741 storeRam32(A_CARD_CHAN1, a0);
2744 if (pa2 != INVALID_PTR) {
2746 memcpy(pa2, Mcd1Data + a1 * 128, 128);
2748 memcpy(pa2, Mcd2Data + a1 * 128, 128);
2752 DeliverEvent(0xf0000011, 0x0004);
2753 // DeliverEvent(0xf4000001, 0x0004);
2758 void psxBios__new_card() { // 0x50
2760 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x50]);
2766 /* According to a user, this allows Final Fantasy Tactics to save/load properly */
2767 void psxBios__get_error(void) // 55
2769 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x55]);
2774 void psxBios_Krom2RawAdd() { // 0x51
2777 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x51]);
2778 const u32 table_8140[][2] = {
2779 {0x8140, 0x0000}, {0x8180, 0x0762}, {0x81ad, 0x0cc6}, {0x81b8, 0x0ca8},
2780 {0x81c0, 0x0f00}, {0x81c8, 0x0d98}, {0x81cf, 0x10c2}, {0x81da, 0x0e6a},
2781 {0x81e9, 0x13ce}, {0x81f0, 0x102c}, {0x81f8, 0x1590}, {0x81fc, 0x111c},
2782 {0x81fd, 0x1626}, {0x824f, 0x113a}, {0x8259, 0x20ee}, {0x8260, 0x1266},
2783 {0x827a, 0x24cc}, {0x8281, 0x1572}, {0x829b, 0x28aa}, {0x829f, 0x187e},
2784 {0x82f2, 0x32dc}, {0x8340, 0x2238}, {0x837f, 0x4362}, {0x8380, 0x299a},
2785 {0x8397, 0x4632}, {0x839f, 0x2c4c}, {0x83b7, 0x49f2}, {0x83bf, 0x2f1c},
2786 {0x83d7, 0x4db2}, {0x8440, 0x31ec}, {0x8461, 0x5dde}, {0x8470, 0x35ca},
2787 {0x847f, 0x6162}, {0x8480, 0x378c}, {0x8492, 0x639c}, {0x849f, 0x39a8},
2791 const u32 table_889f[][2] = {
2792 {0x889f, 0x3d68}, {0x8900, 0x40ec}, {0x897f, 0x4fb0}, {0x8a00, 0x56f4},
2793 {0x8a7f, 0x65b8}, {0x8b00, 0x6cfc}, {0x8b7f, 0x7bc0}, {0x8c00, 0x8304},
2794 {0x8c7f, 0x91c8}, {0x8d00, 0x990c}, {0x8d7f, 0xa7d0}, {0x8e00, 0xaf14},
2795 {0x8e7f, 0xbdd8}, {0x8f00, 0xc51c}, {0x8f7f, 0xd3e0}, {0x9000, 0xdb24},
2796 {0x907f, 0xe9e8}, {0x9100, 0xf12c}, {0x917f, 0xfff0}, {0x9200, 0x10734},
2797 {0x927f, 0x115f8}, {0x9300, 0x11d3c}, {0x937f, 0x12c00}, {0x9400, 0x13344},
2798 {0x947f, 0x14208}, {0x9500, 0x1494c}, {0x957f, 0x15810}, {0x9600, 0x15f54},
2799 {0x967f, 0x16e18}, {0x9700, 0x1755c}, {0x977f, 0x18420}, {0x9800, 0x18b64},
2803 if (a0 >= 0x8140 && a0 <= 0x84be) {
2804 while (table_8140[i][0] <= a0) i++;
2805 a0 -= table_8140[i - 1][0];
2806 v0 = 0xbfc66000 + (a0 * 0x1e + table_8140[i - 1][1]);
2807 } else if (a0 >= 0x889f && a0 <= 0x9872) {
2808 while (table_889f[i][0] <= a0) i++;
2809 a0 -= table_889f[i - 1][0];
2810 v0 = 0xbfc66000 + (a0 * 0x1e + table_889f[i - 1][1]);
2818 void psxBios_GetC0Table() { // 56
2819 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x56]);
2820 log_unhandled("GetC0Table @%08x\n", ra);
2822 mips_return_c(A_C0_TABLE, 3);
2825 void psxBios_GetB0Table() { // 57
2826 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x57]);
2827 log_unhandled("GetB0Table @%08x\n", ra);
2829 mips_return_c(A_B0_TABLE, 3);
2832 static void psxBios__card_chan() { // 0x58
2834 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x58]);
2836 // todo: should return active slot chan
2837 // (active - which was last processed by irq code)
2838 ret = loadRam32(A_CARD_CHAN1);
2839 mips_return_c(ret, 8);
2842 static void psxBios_ChangeClearPad() { // 5b
2844 PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x5b], a0);
2845 ret = loadRam32(A_PAD_ACK_VBL);
2846 storeRam32(A_PAD_ACK_VBL, a0);
2848 mips_return_c(ret, 6);
2851 static void psxBios__card_status() { // 5c
2852 PSXBIOS_LOG("psxBios_%s %x\n", biosB0n[0x5c], a0);
2858 static void psxBios__card_wait() { // 5d
2859 PSXBIOS_LOG("psxBios_%s %x\n", biosB0n[0x5d], a0);
2865 /* System calls C0 */
2867 static void psxBios_InitRCnt() { // 00
2869 PSXBIOS_LOG("psxBios_%s %x\n", biosC0n[0x00], a0);
2870 psxHwWrite16(0x1f801074, psxHu32(0x1074) & ~0x71);
2871 for (i = 0; i < 3; i++) {
2872 psxHwWrite16(0x1f801100 + i*0x10 + 4, 0);
2873 psxHwWrite16(0x1f801100 + i*0x10 + 8, 0);
2874 psxHwWrite16(0x1f801100 + i*0x10 + 0, 0);
2876 psxBios_SysEnqIntRP_(a0, 0x6d88);
2877 mips_return_c(0, 9);
2880 static void psxBios_InitException() { // 01
2881 PSXBIOS_LOG("psxBios_%s %x\n", biosC0n[0x01], a0);
2882 psxBios_SysEnqIntRP_(a0, 0x6da8);
2883 mips_return_c(0, 9);
2887 * int SysEnqIntRP(int index , long *queue);
2890 static void psxBios_SysEnqIntRP_(u32 priority, u32 chain_eptr) {
2891 u32 old, base = loadRam32(A_TT_ExCB);
2893 old = loadRam32(base + (priority << 3));
2894 storeRam32(base + (priority << 3), chain_eptr);
2895 storeRam32(chain_eptr, old);
2896 mips_return_c(0, 9);
2899 static void psxBios_SysEnqIntRP() { // 02
2900 PSXBIOS_LOG("psxBios_%s %x %x\n", biosC0n[0x02], a0, a1);
2901 psxBios_SysEnqIntRP_(a0, a1);
2905 * int SysDeqIntRP(int index , long *queue);
2908 static void psxBios_SysDeqIntRP_(u32 priority, u32 chain_rm_eptr) {
2909 u32 ptr, next, base = loadRam32(A_TT_ExCB);
2910 u32 lim = 0, ret = 0;
2912 // as in original: no arg checks of any kind, bug if a1 == 0
2913 ptr = loadRam32(base + (priority << 3));
2915 next = loadRam32(ptr);
2916 if (ptr == chain_rm_eptr) {
2917 storeRam32(base + (priority << 3), next);
2922 while (next && next != chain_rm_eptr && lim++ < 100) {
2924 next = loadRam32(ptr);
2927 if (next == chain_rm_eptr) {
2928 next = loadRam32(next);
2929 storeRam32(ptr, next);
2936 PSXBIOS_LOG("bad chain %u %x\n", priority, base);
2938 mips_return_c(ret, 12);
2941 static void psxBios_SysDeqIntRP() { // 03
2942 PSXBIOS_LOG("psxBios_%s %x %x\n", biosC0n[0x03], a0, a1);
2943 psxBios_SysDeqIntRP_(a0, a1);
2946 static void psxBios_get_free_EvCB_slot() { // 04
2947 PSXBIOS_LOG("psxBios_%s\n", biosC0n[0x04]);
2948 s32 ret = get_free_EvCB_slot();
2949 mips_return_c(ret, 0);
2952 static void psxBios_SysInitMemory_(u32 base, u32 size) {
2953 storeRam32(base, 0);
2954 storeRam32(A_KMALLOC_PTR, base);
2955 storeRam32(A_KMALLOC_SIZE, size);
2956 storeRam32(A_KMALLOC_END, base + (size & ~3) + 4);
2959 // this should be much more complicated, but maybe that'll be enough
2960 static u32 psxBios_SysMalloc_(u32 size) {
2961 u32 ptr = loadRam32(A_KMALLOC_PTR);
2963 size = (size + 3) & ~3;
2964 storeRam32(A_KMALLOC_PTR, ptr + 4 + size);
2965 storeRam32(ptr, size);
2969 static void psxBios_SysInitMemory() { // 08
2970 PSXBIOS_LOG("psxBios_%s %x %x\n", biosC0n[0x08], a0, a1);
2972 psxBios_SysInitMemory_(a0, a1);
2973 mips_return_void_c(12);
2976 static void psxBios_ChangeClearRCnt() { // 0a
2979 PSXBIOS_LOG("psxBios_%s: %x, %x\n", biosC0n[0x0a], a0, a1);
2981 ret = loadRam32(A_RCNT_VBL_ACK + (a0 << 2));
2982 storeRam32(A_RCNT_VBL_ACK + (a0 << 2), a1);
2983 mips_return_c(ret, 8);
2986 static void psxBios_InitDefInt() { // 0c
2987 PSXBIOS_LOG("psxBios_%s %x\n", biosC0n[0x0c], a0);
2988 // should also clear the autoack table
2989 psxBios_SysEnqIntRP_(a0, 0x6d98);
2990 mips_return_c(0, 20 + 6*2);
2993 void psxBios_dummy() {
2994 u32 pc = (pc0 & 0x1fffff) - 4;
2995 char **ntab = pc == 0xa0 ? biosA0n : pc == 0xb0 ? biosB0n
2996 : pc == 0xc0 ? biosC0n : NULL;
2997 PSXBIOS_LOG("unk %x call: %x ra=%x (%s)\n",
2998 pc, t1, ra, ntab ? ntab[t1 & 0xff] : "???");
2999 (void)pc; (void)ntab;
3000 mips_return_c(0, 100);
3003 void (*biosA0[256])();
3004 // C0 and B0 overlap (end of C0 is start of B0)
3005 void (*biosC0[256+128])();
3006 void (**biosB0)() = biosC0 + 128;
3008 static void setup_mips_code()
3011 ptr = (u32 *)&psxM[A_SYSCALL];
3012 ptr[0x00/4] = SWAPu32(0x0000000c); // syscall 0
3013 ptr[0x04/4] = SWAPu32(0x03e00008); // jr $ra
3014 ptr[0x08/4] = SWAPu32(0x00000000); // nop
3016 ptr = (u32 *)&psxM[A_EXCEPTION];
3017 memset(ptr, 0, 0xc0); // nops (to be patched by games sometimes)
3018 ptr[0x10/4] = SWAPu32(0x8c1a0108); // lw $k0, (0x108) // PCB
3019 ptr[0x14/4] = SWAPu32(0x00000000); // nop
3020 ptr[0x18/4] = SWAPu32(0x8f5a0000); // lw $k0, ($k0) // TCB
3021 ptr[0x1c/4] = SWAPu32(0x00000000); // nop
3022 ptr[0x20/4] = SWAPu32(0x275a0008); // addiu $k0, $k0, 8 // regs
3023 ptr[0x24/4] = SWAPu32(0xaf5f007c); // sw $ra, 0x7c($k0)
3024 ptr[0x28/4] = SWAPu32(0xaf410004); // sw $at, 0x04($k0)
3025 ptr[0x2c/4] = SWAPu32(0xaf420008); // sw $v0, 0x08($k0)
3026 ptr[0x30/4] = SWAPu32(0xaf43000c); // sw $v1, 0x0c($k0)
3028 ptr[0x60/4] = SWAPu32(0x40037000); // mfc0 $v1, EPC
3029 ptr[0x64/4] = SWAPu32(0x40026800); // mfc0 $v0, Cause
3030 ptr[0x6c/4] = SWAPu32(0xaf430080); // sw $v1, 0x80($k0)
3032 ptr[0xb0/4] = HLEOP(hleop_exception);
3035 static const struct {
3039 { 0xbfc050a4, hleop_exc0_0_1 },
3040 { 0xbfc04fbc, hleop_exc0_0_2 },
3041 { 0xbfc0506c, hleop_exc0_1_1 },
3042 { 0xbfc04dec, hleop_exc0_1_2 },
3043 { 0x1a00, hleop_exc0_2_2 },
3044 { 0x19c8, hleop_exc1_0_1 },
3045 { 0x18bc, hleop_exc1_0_2 },
3046 { 0x1990, hleop_exc1_1_1 },
3047 { 0x1858, hleop_exc1_1_2 },
3048 { 0x1958, hleop_exc1_2_1 },
3049 { 0x17f4, hleop_exc1_2_2 },
3050 { 0x1920, hleop_exc1_3_1 },
3051 { 0x1794, hleop_exc1_3_2 },
3052 { 0x2458, hleop_exc3_0_2 },
3053 { 0x49bc, hleop_exc_padcard1 },
3054 { 0x4a4c, hleop_exc_padcard2 },
3057 static int chain_hle_op(u32 handler)
3061 for (i = 0; i < sizeof(chainfns) / sizeof(chainfns[0]); i++)
3062 if (chainfns[i].addr == handler)
3063 return chainfns[i].op;
3067 static void write_chain(u32 *d, u32 next, u32 handler1, u32 handler2)
3069 d[0] = SWAPu32(next);
3070 d[1] = SWAPu32(handler1);
3071 d[2] = SWAPu32(handler2);
3073 // install the hle traps
3074 PSXMu32ref(handler1) = HLEOP(chain_hle_op(handler1));
3075 PSXMu32ref(handler2) = HLEOP(chain_hle_op(handler2));
3078 static void setup_tt(u32 tcb_cnt, u32 evcb_cnt)
3080 u32 *ram32 = (u32 *)psxM;
3081 u32 s_excb = 0x20, s_evcb = 0x1c * evcb_cnt;
3082 u32 s_pcb = 4, s_tcb = 0xc0 * tcb_cnt;
3083 u32 p_excb, p_evcb, p_pcb, p_tcb;
3085 memset(ram32 + 0xe000/4, 0, s_excb + s_evcb + s_pcb + s_tcb + 5*4);
3086 psxBios_SysInitMemory_(0xa000e000, 0x2000);
3087 p_excb = psxBios_SysMalloc_(s_excb);
3088 p_evcb = psxBios_SysMalloc_(s_evcb);
3089 p_pcb = psxBios_SysMalloc_(s_pcb);
3090 p_tcb = psxBios_SysMalloc_(s_tcb);
3092 // "table of tables". Some games modify it
3093 assert(A_TT_ExCB == 0x0100);
3094 ram32[0x0100/4] = SWAPu32(p_excb); // ExCB - exception chains
3095 ram32[0x0104/4] = SWAPu32(s_excb); // ExCB size
3096 ram32[0x0108/4] = SWAPu32(p_pcb); // PCB - process control
3097 ram32[0x010c/4] = SWAPu32(s_pcb); // PCB size
3098 ram32[0x0110/4] = SWAPu32(p_tcb); // TCB - thread control
3099 ram32[0x0114/4] = SWAPu32(s_tcb); // TCB size
3100 ram32[0x0120/4] = SWAPu32(p_evcb); // EvCB - event control
3101 ram32[0x0124/4] = SWAPu32(s_evcb); // EvCB size
3102 ram32[0x0140/4] = SWAPu32(0x8648); // FCB - file control
3103 ram32[0x0144/4] = SWAPu32(0x02c0); // FCB size
3104 ram32[0x0150/4] = SWAPu32(0x6ee0); // DCB - device control
3105 ram32[0x0154/4] = SWAPu32(0x0320); // DCB size
3107 storeRam32(p_excb + 0*4, 0x91e0); // chain0
3108 storeRam32(p_excb + 2*4, 0x6d88); // chain1
3109 storeRam32(p_excb + 4*4, 0x0000); // chain2
3110 storeRam32(p_excb + 6*4, 0x6d98); // chain3
3112 storeRam32(p_pcb, p_tcb);
3113 storeRam32(p_tcb, 0x4000); // first TCB
3116 storeRam32(A_CD_EVENTS + 0x00, OpenEvent(0xf0000003, 0x0010, EvMdMARK, 0));
3117 storeRam32(A_CD_EVENTS + 0x04, OpenEvent(0xf0000003, 0x0020, EvMdMARK, 0));
3118 storeRam32(A_CD_EVENTS + 0x08, OpenEvent(0xf0000003, 0x0040, EvMdMARK, 0));
3119 storeRam32(A_CD_EVENTS + 0x0c, OpenEvent(0xf0000003, 0x0080, EvMdMARK, 0));
3120 storeRam32(A_CD_EVENTS + 0x10, OpenEvent(0xf0000003, 0x8000, EvMdMARK, 0));
3121 DeliverEvent(0xf0000003, 0x0010);
3124 static const u32 gpu_ctl_def[] = {
3125 0x00000000, 0x01000000, 0x03000000, 0x04000000,
3126 0x05000800, 0x06c60260, 0x0703fc10, 0x08000027
3129 static const u32 gpu_data_def[] = {
3130 0xe100360b, 0xe2000000, 0xe3000800, 0xe4077e7f,
3131 0xe5001000, 0xe6000000,
3132 0x02000000, 0x00000000, 0x01ff03ff
3136 static const u16 spu_config[] = {
3137 0x3fff, 0x37ef, 0x5ebc, 0x5ebc, 0x0000, 0x0000, 0x0000, 0x00a0,
3138 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0x00ff, 0x0000, 0x0000,
3139 0x0000, 0xe128, 0x0000, 0x0200, 0xf0f0, 0xc085, 0x0004, 0x0000,
3140 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
3141 0x033d, 0x0231, 0x7e00, 0x5000, 0xb400, 0xb000, 0x4c00, 0xb000,
3142 0x6000, 0x5400, 0x1ed6, 0x1a31, 0x1d14, 0x183b, 0x1bc2, 0x16b2,
3143 0x1a32, 0x15ef, 0x15ee, 0x1055, 0x1334, 0x0f2d, 0x11f6, 0x0c5d,
3144 0x1056, 0x0ae1, 0x0ae0, 0x07a2, 0x0464, 0x0232, 0x8000, 0x8000
3147 void psxBiosSetupBootState(void)
3149 boolean hle = Config.HLE;
3150 u32 *hw = (u32 *)psxH;
3153 // see also SetBootRegs()
3156 a0 = 1; a2 = a3 = 0; a3 = 0x2a;
3157 t2 = 0x2d; t4 = 0x23; t5 = 0x2b; t6 = 0xa0010000;
3159 k0 = 0xbfc0d968; k1 = 0xf1c;
3160 ra = 0xf0001234; // just to easily detect attempts to return
3161 psxRegs.CP0.n.Cause = 0x20;
3162 psxRegs.CP0.n.EPC = 0xbfc0d964; // EnterCriticalSection syscall
3164 hw[0x1000/4] = SWAP32(0x1f000000);
3165 hw[0x1004/4] = SWAP32(0x1f802000);
3166 hw[0x1008/4] = SWAP32(0x0013243f);
3167 hw[0x100c/4] = SWAP32(0x00003022);
3168 hw[0x1010/4] = SWAP32(0x0013243f);
3169 hw[0x1014/4] = SWAP32(0x200931e1);
3170 hw[0x1018/4] = SWAP32(0x00020943);
3171 hw[0x101c/4] = SWAP32(0x00070777);
3172 hw[0x1020/4] = SWAP32(0x0000132c);
3173 hw[0x1060/4] = SWAP32(0x00000b88);
3174 hw[0x1070/4] = SWAP32(0x00000001);
3175 hw[0x1074/4] = SWAP32(0x0000000c);
3176 hw[0x2040/4] = SWAP32(0x00000900);
3179 hw[0x10a0/4] = SWAP32(0x00ffffff);
3180 hw[0x10a8/4] = SWAP32(0x00000401);
3181 hw[0x10b0/4] = SWAP32(0x0008b000);
3182 hw[0x10b4/4] = SWAP32(0x00010200);
3183 hw[0x10e0/4] = SWAP32(0x000eccf4);
3184 hw[0x10e4/4] = SWAP32(0x00000400);
3185 hw[0x10e8/4] = SWAP32(0x00000002);
3186 hw[0x10f0/4] = SWAP32(0x00009099);
3187 hw[0x10f4/4] = SWAP32(0x8c8c0000);
3196 for (i = 0; i < sizeof(gpu_ctl_def) / sizeof(gpu_ctl_def[0]); i++)
3197 GPU_writeStatus(gpu_ctl_def[i]);
3198 for (i = 0; i < sizeof(gpu_data_def) / sizeof(gpu_data_def[0]); i++)
3199 GPU_writeData(gpu_data_def[i]);
3200 HW_GPU_STATUS |= SWAP32(PSXGPU_nBUSY);
3203 for (i = 0x1f801d80; i < sizeof(spu_config) / sizeof(spu_config[0]); i++)
3204 SPU_writeRegister(0x1f801d80 + i*2, spu_config[i], psxRegs.cycle);
3207 #include "sjisfont.h"
3209 void psxBiosInit() {
3210 u32 *ptr, *ram32, *rom32;
3214 memset(psxM, 0, 0x10000);
3215 for(i = 0; i < 256; i++) {
3220 biosA0[0x03] = biosB0[0x35] = psxBios_write_psxout;
3221 biosA0[0x3c] = biosB0[0x3d] = psxBios_putchar_psxout;
3222 biosA0[0x3e] = biosB0[0x3f] = psxBios_puts_psxout;
3223 biosA0[0x3f] = psxBios_printf_psxout;
3225 if (!Config.HLE) return;
3227 for(i = 0; i < 256; i++) {
3228 if (biosA0[i] == NULL) biosA0[i] = psxBios_dummy;
3229 if (biosB0[i] == NULL) biosB0[i] = psxBios_dummy;
3230 if (biosC0[i] == NULL) biosC0[i] = psxBios_dummy;
3233 biosA0[0x00] = psxBios_open;
3234 biosA0[0x01] = psxBios_lseek;
3235 biosA0[0x02] = psxBios_read;
3236 biosA0[0x03] = psxBios_write;
3237 biosA0[0x04] = psxBios_close;
3238 //biosA0[0x05] = psxBios_ioctl;
3239 //biosA0[0x06] = psxBios_exit;
3240 //biosA0[0x07] = psxBios_sys_a0_07;
3241 biosA0[0x08] = psxBios_getc;
3242 biosA0[0x09] = psxBios_putc;
3243 biosA0[0x0a] = psxBios_todigit;
3244 //biosA0[0x0b] = psxBios_atof;
3245 //biosA0[0x0c] = psxBios_strtoul;
3246 //biosA0[0x0d] = psxBios_strtol;
3247 biosA0[0x0e] = psxBios_abs;
3248 biosA0[0x0f] = psxBios_labs;
3249 biosA0[0x10] = psxBios_atoi;
3250 biosA0[0x11] = psxBios_atol;
3251 //biosA0[0x12] = psxBios_atob;
3252 biosA0[0x13] = psxBios_setjmp;
3253 biosA0[0x14] = psxBios_longjmp;
3254 biosA0[0x15] = psxBios_strcat;
3255 biosA0[0x16] = psxBios_strncat;
3256 biosA0[0x17] = psxBios_strcmp;
3257 biosA0[0x18] = psxBios_strncmp;
3258 biosA0[0x19] = psxBios_strcpy;
3259 biosA0[0x1a] = psxBios_strncpy;
3260 biosA0[0x1b] = psxBios_strlen;
3261 biosA0[0x1c] = psxBios_index;
3262 biosA0[0x1d] = psxBios_rindex;
3263 biosA0[0x1e] = psxBios_strchr;
3264 biosA0[0x1f] = psxBios_strrchr;
3265 biosA0[0x20] = psxBios_strpbrk;
3266 biosA0[0x21] = psxBios_strspn;
3267 biosA0[0x22] = psxBios_strcspn;
3268 biosA0[0x23] = psxBios_strtok;
3269 biosA0[0x24] = psxBios_strstr;
3270 biosA0[0x25] = psxBios_toupper;
3271 biosA0[0x26] = psxBios_tolower;
3272 biosA0[0x27] = psxBios_bcopy;
3273 biosA0[0x28] = psxBios_bzero;
3274 biosA0[0x29] = psxBios_bcmp;
3275 biosA0[0x2a] = psxBios_memcpy;
3276 biosA0[0x2b] = psxBios_memset;
3277 biosA0[0x2c] = psxBios_memmove;
3278 biosA0[0x2d] = psxBios_memcmp;
3279 biosA0[0x2e] = psxBios_memchr;
3280 biosA0[0x2f] = psxBios_rand;
3281 biosA0[0x30] = psxBios_srand;
3282 biosA0[0x31] = psxBios_qsort;
3283 //biosA0[0x32] = psxBios_strtod;
3284 biosA0[0x33] = psxBios_malloc;
3285 biosA0[0x34] = psxBios_free;
3286 //biosA0[0x35] = psxBios_lsearch;
3287 //biosA0[0x36] = psxBios_bsearch;
3288 biosA0[0x37] = psxBios_calloc;
3289 biosA0[0x38] = psxBios_realloc;
3290 biosA0[0x39] = psxBios_InitHeap;
3291 //biosA0[0x3a] = psxBios__exit;
3292 biosA0[0x3b] = psxBios_getchar;
3293 biosA0[0x3c] = psxBios_putchar;
3294 //biosA0[0x3d] = psxBios_gets;
3295 biosA0[0x3e] = psxBios_puts;
3296 biosA0[0x3f] = psxBios_printf;
3297 biosA0[0x40] = psxBios_SystemErrorUnresolvedException;
3298 //biosA0[0x41] = psxBios_LoadTest;
3299 biosA0[0x42] = psxBios_Load;
3300 biosA0[0x43] = psxBios_Exec;
3301 biosA0[0x44] = psxBios_FlushCache;
3302 //biosA0[0x45] = psxBios_InstallInterruptHandler;
3303 biosA0[0x46] = psxBios_GPU_dw;
3304 biosA0[0x47] = psxBios_mem2vram;
3305 biosA0[0x48] = psxBios_SendGPU;
3306 biosA0[0x49] = psxBios_GPU_cw;
3307 biosA0[0x4a] = psxBios_GPU_cwb;
3308 biosA0[0x4b] = psxBios_GPU_SendPackets;
3309 biosA0[0x4c] = psxBios_sys_a0_4c;
3310 biosA0[0x4d] = psxBios_GPU_GetGPUStatus;
3311 //biosA0[0x4e] = psxBios_GPU_sync;
3312 //biosA0[0x4f] = psxBios_sys_a0_4f;
3313 //biosA0[0x50] = psxBios_sys_a0_50;
3314 biosA0[0x51] = psxBios_LoadExec;
3315 //biosA0[0x52] = psxBios_GetSysSp;
3316 //biosA0[0x53] = psxBios_sys_a0_53;
3317 //biosA0[0x54] = psxBios__96_init_a54;
3318 //biosA0[0x55] = psxBios__bu_init_a55;
3319 biosA0[0x56] = psxBios_CdRemove;
3320 //biosA0[0x57] = psxBios_sys_a0_57;
3321 //biosA0[0x58] = psxBios_sys_a0_58;
3322 //biosA0[0x59] = psxBios_sys_a0_59;
3323 //biosA0[0x5a] = psxBios_sys_a0_5a;
3324 //biosA0[0x5b] = psxBios_dev_tty_init;
3325 //biosA0[0x5c] = psxBios_dev_tty_open;
3326 //biosA0[0x5d] = psxBios_sys_a0_5d;
3327 //biosA0[0x5e] = psxBios_dev_tty_ioctl;
3328 //biosA0[0x5f] = psxBios_dev_cd_open;
3329 //biosA0[0x60] = psxBios_dev_cd_read;
3330 //biosA0[0x61] = psxBios_dev_cd_close;
3331 //biosA0[0x62] = psxBios_dev_cd_firstfile;
3332 //biosA0[0x63] = psxBios_dev_cd_nextfile;
3333 //biosA0[0x64] = psxBios_dev_cd_chdir;
3334 //biosA0[0x65] = psxBios_dev_card_open;
3335 //biosA0[0x66] = psxBios_dev_card_read;
3336 //biosA0[0x67] = psxBios_dev_card_write;
3337 //biosA0[0x68] = psxBios_dev_card_close;
3338 //biosA0[0x69] = psxBios_dev_card_firstfile;
3339 //biosA0[0x6a] = psxBios_dev_card_nextfile;
3340 //biosA0[0x6b] = psxBios_dev_card_erase;
3341 //biosA0[0x6c] = psxBios_dev_card_undelete;
3342 //biosA0[0x6d] = psxBios_dev_card_format;
3343 //biosA0[0x6e] = psxBios_dev_card_rename;
3344 //biosA0[0x6f] = psxBios_dev_card_6f;
3345 biosA0[0x70] = psxBios__bu_init;
3346 biosA0[0x71] = psxBios__96_init;
3347 biosA0[0x72] = psxBios_CdRemove;
3348 //biosA0[0x73] = psxBios_sys_a0_73;
3349 //biosA0[0x74] = psxBios_sys_a0_74;
3350 //biosA0[0x75] = psxBios_sys_a0_75;
3351 //biosA0[0x76] = psxBios_sys_a0_76;
3352 //biosA0[0x77] = psxBios_sys_a0_77;
3353 //biosA0[0x78] = psxBios__96_CdSeekL;
3354 //biosA0[0x79] = psxBios_sys_a0_79;
3355 //biosA0[0x7a] = psxBios_sys_a0_7a;
3356 //biosA0[0x7b] = psxBios_sys_a0_7b;
3357 //biosA0[0x7c] = psxBios__96_CdGetStatus;
3358 //biosA0[0x7d] = psxBios_sys_a0_7d;
3359 //biosA0[0x7e] = psxBios__96_CdRead;
3360 //biosA0[0x7f] = psxBios_sys_a0_7f;
3361 //biosA0[0x80] = psxBios_sys_a0_80;
3362 //biosA0[0x81] = psxBios_sys_a0_81;
3363 //biosA0[0x82] = psxBios_sys_a0_82;
3364 //biosA0[0x83] = psxBios_sys_a0_83;
3365 //biosA0[0x84] = psxBios_sys_a0_84;
3366 //biosA0[0x85] = psxBios__96_CdStop;
3367 //biosA0[0x86] = psxBios_sys_a0_86;
3368 //biosA0[0x87] = psxBios_sys_a0_87;
3369 //biosA0[0x88] = psxBios_sys_a0_88;
3370 //biosA0[0x89] = psxBios_sys_a0_89;
3371 //biosA0[0x8a] = psxBios_sys_a0_8a;
3372 //biosA0[0x8b] = psxBios_sys_a0_8b;
3373 //biosA0[0x8c] = psxBios_sys_a0_8c;
3374 //biosA0[0x8d] = psxBios_sys_a0_8d;
3375 //biosA0[0x8e] = psxBios_sys_a0_8e;
3376 //biosA0[0x8f] = psxBios_sys_a0_8f;
3377 biosA0[0x90] = hleExc0_1_2;
3378 biosA0[0x91] = hleExc0_0_2;
3379 biosA0[0x92] = hleExc0_1_1;
3380 biosA0[0x93] = hleExc0_0_1;
3381 //biosA0[0x94] = psxBios_sys_a0_94;
3382 //biosA0[0x95] = psxBios_sys_a0_95;
3383 //biosA0[0x96] = psxBios_AddCDROMDevice;
3384 //biosA0[0x97] = psxBios_AddMemCardDevide;
3385 //biosA0[0x98] = psxBios_DisableKernelIORedirection;
3386 //biosA0[0x99] = psxBios_EnableKernelIORedirection;
3387 //biosA0[0x9a] = psxBios_sys_a0_9a;
3388 //biosA0[0x9b] = psxBios_sys_a0_9b;
3389 //biosA0[0x9c] = psxBios_SetConf;
3390 //biosA0[0x9d] = psxBios_GetConf;
3391 //biosA0[0x9e] = psxBios_sys_a0_9e;
3392 biosA0[0x9f] = psxBios_SetMem;
3393 //biosA0[0xa0] = psxBios__boot;
3394 //biosA0[0xa1] = psxBios_SystemError;
3395 //biosA0[0xa2] = psxBios_EnqueueCdIntr;
3396 biosA0[0xa3] = psxBios_DequeueCdIntr;
3397 //biosA0[0xa4] = psxBios_sys_a0_a4;
3398 //biosA0[0xa5] = psxBios_ReadSector;
3399 biosA0[0xa6] = psxBios_get_cd_status;
3400 //biosA0[0xa7] = psxBios_bufs_cb_0;
3401 //biosA0[0xa8] = psxBios_bufs_cb_1;
3402 //biosA0[0xa9] = psxBios_bufs_cb_2;
3403 //biosA0[0xaa] = psxBios_bufs_cb_3;
3404 biosA0[0xab] = psxBios__card_info;
3405 biosA0[0xac] = psxBios__card_load;
3406 //biosA0[0axd] = psxBios__card_auto;
3407 //biosA0[0xae] = psxBios_bufs_cd_4;
3408 //biosA0[0xaf] = psxBios_sys_a0_af;
3409 //biosA0[0xb0] = psxBios_sys_a0_b0;
3410 //biosA0[0xb1] = psxBios_sys_a0_b1;
3411 //biosA0[0xb2] = psxBios_do_a_long_jmp
3412 //biosA0[0xb3] = psxBios_sys_a0_b3;
3413 biosA0[0xb4] = psxBios_GetSystemInfo;
3414 //*******************B0 CALLS****************************
3415 biosB0[0x00] = psxBios_SysMalloc;
3416 //biosB0[0x01] = psxBios_sys_b0_01;
3417 biosB0[0x02] = psxBios_SetRCnt;
3418 biosB0[0x03] = psxBios_GetRCnt;
3419 biosB0[0x04] = psxBios_StartRCnt;
3420 biosB0[0x05] = psxBios_StopRCnt;
3421 biosB0[0x06] = psxBios_ResetRCnt;
3422 biosB0[0x07] = psxBios_DeliverEvent;
3423 biosB0[0x08] = psxBios_OpenEvent;
3424 biosB0[0x09] = psxBios_CloseEvent;
3425 biosB0[0x0a] = psxBios_WaitEvent;
3426 biosB0[0x0b] = psxBios_TestEvent;
3427 biosB0[0x0c] = psxBios_EnableEvent;
3428 biosB0[0x0d] = psxBios_DisableEvent;
3429 biosB0[0x0e] = psxBios_OpenTh;
3430 biosB0[0x0f] = psxBios_CloseTh;
3431 biosB0[0x10] = psxBios_ChangeTh;
3432 //biosB0[0x11] = psxBios_psxBios_b0_11;
3433 biosB0[0x12] = psxBios_InitPAD;
3434 biosB0[0x13] = psxBios_StartPAD;
3435 biosB0[0x14] = psxBios_StopPAD;
3436 biosB0[0x15] = psxBios_PAD_init;
3437 biosB0[0x16] = psxBios_PAD_dr;
3438 biosB0[0x17] = psxBios_ReturnFromException;
3439 biosB0[0x18] = psxBios_ResetEntryInt;
3440 biosB0[0x19] = psxBios_HookEntryInt;
3441 //biosB0[0x1a] = psxBios_sys_b0_1a;
3442 //biosB0[0x1b] = psxBios_sys_b0_1b;
3443 //biosB0[0x1c] = psxBios_sys_b0_1c;
3444 //biosB0[0x1d] = psxBios_sys_b0_1d;
3445 //biosB0[0x1e] = psxBios_sys_b0_1e;
3446 //biosB0[0x1f] = psxBios_sys_b0_1f;
3447 biosB0[0x20] = psxBios_UnDeliverEvent;
3448 //biosB0[0x21] = psxBios_sys_b0_21;
3449 //biosB0[0x22] = psxBios_sys_b0_22;
3450 //biosB0[0x23] = psxBios_sys_b0_23;
3451 //biosB0[0x24] = psxBios_sys_b0_24;
3452 //biosB0[0x25] = psxBios_sys_b0_25;
3453 //biosB0[0x26] = psxBios_sys_b0_26;
3454 //biosB0[0x27] = psxBios_sys_b0_27;
3455 //biosB0[0x28] = psxBios_sys_b0_28;
3456 //biosB0[0x29] = psxBios_sys_b0_29;
3457 //biosB0[0x2a] = psxBios_sys_b0_2a;
3458 //biosB0[0x2b] = psxBios_sys_b0_2b;
3459 //biosB0[0x2c] = psxBios_sys_b0_2c;
3460 //biosB0[0x2d] = psxBios_sys_b0_2d;
3461 //biosB0[0x2e] = psxBios_sys_b0_2e;
3462 //biosB0[0x2f] = psxBios_sys_b0_2f;
3463 //biosB0[0x30] = psxBios_sys_b0_30;
3464 //biosB0[0x31] = psxBios_sys_b0_31;
3465 biosB0[0x32] = psxBios_open;
3466 biosB0[0x33] = psxBios_lseek;
3467 biosB0[0x34] = psxBios_read;
3468 biosB0[0x35] = psxBios_write;
3469 biosB0[0x36] = psxBios_close;
3470 //biosB0[0x37] = psxBios_ioctl;
3471 //biosB0[0x38] = psxBios_exit;
3472 //biosB0[0x39] = psxBios_sys_b0_39;
3473 //biosB0[0x3a] = psxBios_getc;
3474 //biosB0[0x3b] = psxBios_putc;
3475 biosB0[0x3c] = psxBios_getchar;
3476 biosB0[0x3d] = psxBios_putchar;
3477 //biosB0[0x3e] = psxBios_gets;
3478 biosB0[0x3f] = psxBios_puts;
3479 //biosB0[0x40] = psxBios_cd;
3480 biosB0[0x41] = psxBios_format;
3481 biosB0[0x42] = psxBios_firstfile;
3482 biosB0[0x43] = psxBios_nextfile;
3483 biosB0[0x44] = psxBios_rename;
3484 biosB0[0x45] = psxBios_delete;
3485 //biosB0[0x46] = psxBios_undelete;
3486 //biosB0[0x47] = psxBios_AddDevice;
3487 //biosB0[0x48] = psxBios_RemoteDevice;
3488 //biosB0[0x49] = psxBios_PrintInstalledDevices;
3489 biosB0[0x4a] = psxBios_InitCARD;
3490 biosB0[0x4b] = psxBios_StartCARD;
3491 biosB0[0x4c] = psxBios_StopCARD;
3492 //biosB0[0x4d] = psxBios_sys_b0_4d;
3493 biosB0[0x4e] = psxBios__card_write;
3494 biosB0[0x4f] = psxBios__card_read;
3495 biosB0[0x50] = psxBios__new_card;
3496 biosB0[0x51] = psxBios_Krom2RawAdd;
3497 //biosB0[0x52] = psxBios_sys_b0_52;
3498 //biosB0[0x53] = psxBios_sys_b0_53;
3499 //biosB0[0x54] = psxBios__get_errno;
3500 biosB0[0x55] = psxBios__get_error;
3501 biosB0[0x56] = psxBios_GetC0Table;
3502 biosB0[0x57] = psxBios_GetB0Table;
3503 biosB0[0x58] = psxBios__card_chan;
3504 //biosB0[0x59] = psxBios_sys_b0_59;
3505 //biosB0[0x5a] = psxBios_sys_b0_5a;
3506 biosB0[0x5b] = psxBios_ChangeClearPad;
3507 biosB0[0x5c] = psxBios__card_status;
3508 biosB0[0x5d] = psxBios__card_wait;
3509 //*******************C0 CALLS****************************
3510 biosC0[0x00] = psxBios_InitRCnt;
3511 biosC0[0x01] = psxBios_InitException;
3512 biosC0[0x02] = psxBios_SysEnqIntRP;
3513 biosC0[0x03] = psxBios_SysDeqIntRP;
3514 biosC0[0x04] = psxBios_get_free_EvCB_slot;
3515 //biosC0[0x05] = psxBios_get_free_TCB_slot;
3516 //biosC0[0x06] = psxBios_ExceptionHandler;
3517 //biosC0[0x07] = psxBios_InstallExeptionHandler;
3518 biosC0[0x08] = psxBios_SysInitMemory;
3519 //biosC0[0x09] = psxBios_SysInitKMem;
3520 biosC0[0x0a] = psxBios_ChangeClearRCnt;
3521 //biosC0[0x0b] = psxBios_SystemError;
3522 biosC0[0x0c] = psxBios_InitDefInt;
3523 //biosC0[0x0d] = psxBios_sys_c0_0d;
3524 //biosC0[0x0e] = psxBios_sys_c0_0e;
3525 //biosC0[0x0f] = psxBios_sys_c0_0f;
3526 //biosC0[0x10] = psxBios_sys_c0_10;
3527 //biosC0[0x11] = psxBios_sys_c0_11;
3528 //biosC0[0x12] = psxBios_InstallDevices;
3529 //biosC0[0x13] = psxBios_FlushStfInOutPut;
3530 //biosC0[0x14] = psxBios_sys_c0_14;
3531 //biosC0[0x15] = psxBios__cdevinput;
3532 //biosC0[0x16] = psxBios__cdevscan;
3533 //biosC0[0x17] = psxBios__circgetc;
3534 //biosC0[0x18] = psxBios__circputc;
3535 //biosC0[0x19] = psxBios_ioabort;
3536 //biosC0[0x1a] = psxBios_sys_c0_1a
3537 //biosC0[0x1b] = psxBios_KernelRedirect;
3538 //biosC0[0x1c] = psxBios_PatchAOTable;
3539 //************** THE END ***************************************
3542 memset(FDesc, 0, sizeof(FDesc));
3545 psxMu32ref(0x9010) = SWAPu32(0xac20cc00);
3547 // somewhat pretend to be a SCPH1001 BIOS
3548 // some games look for these and take an exception if they're missing
3549 rom32 = (u32 *)psxR;
3550 rom32[0x100/4] = SWAP32(0x19951204);
3551 rom32[0x104/4] = SWAP32(3);
3552 strcpy(psxR + 0x108, "PCSX authors");
3553 strcpy(psxR + 0x12c, "CEX-3000 PCSX HLE"); // see psxBios_GetSystemInfo
3554 strcpy(psxR + 0x7ff32, "System ROM Version 2.2 12/04/95 A");
3555 strcpy(psxR + 0x7ff54, "GPL-2.0-or-later");
3558 len = 0x80000 - 0x66000;
3559 uncompress((Bytef *)(psxR + 0x66000), &len, font_8140, sizeof(font_8140));
3560 len = 0x80000 - 0x69d68;
3561 uncompress((Bytef *)(psxR + 0x69d68), &len, font_889f, sizeof(font_889f));
3563 /* Some games like R-Types, CTR, Fade to Black read from adress 0x00000000 due to uninitialized pointers.
3564 See Garbage Area at Address 00000000h in Nocash PSX Specfications for more information.
3565 Here are some examples of games not working with this fix in place :
3566 R-type won't get past the Irem logo if not implemented.
3567 Crash Team Racing will softlock after the Sony logo.
3570 ram32 = (u32 *)psxM;
3571 ram32[0x0000/4] = SWAPu32(0x00000003); // lui $k0, 0 (overwritten by 3)
3572 ram32[0x0004/4] = SWAPu32(0x275a0000 + A_EXCEPTION); // addiu $k0, $k0, 0xc80
3573 ram32[0x0008/4] = SWAPu32(0x03400008); // jr $k0
3574 ram32[0x000c/4] = SWAPu32(0x00000000); // nop
3576 ram32[0x0060/4] = SWAPu32(0x00000002); // ram size?
3577 ram32[0x0068/4] = SWAPu32(0x000000ff); // unknown
3579 ram32[0x0080/4] = SWAPu32(0x3c1a0000); // lui $k0, 0 // exception vector
3580 ram32[0x0084/4] = SWAPu32(0x275a0000 + A_EXCEPTION); // addiu $k0, $k0, 0xc80
3581 ram32[0x0088/4] = SWAPu32(0x03400008); // jr $k0
3582 ram32[0x008c/4] = SWAPu32(0x00000000); // nop
3584 ram32[0x00a0/4] = HLEOP(hleop_a0);
3585 ram32[0x00b0/4] = HLEOP(hleop_b0);
3586 ram32[0x00c0/4] = HLEOP(hleop_c0);
3590 ram32[0x6ee0/4] = SWAPu32(0x0000eff0); // DCB
3591 strcpy((char *)&ram32[0xeff0/4], "bu");
3593 // default exception handler chains
3594 write_chain(&ram32[0x91e0/4], 0x91d0, 0xbfc050a4, 0xbfc04fbc); // chain0.e0
3595 write_chain(&ram32[0x91d0/4], 0x6da8, 0xbfc0506c, 0xbfc04dec); // chain0.e1
3596 write_chain(&ram32[0x6da8/4], 0, 0, 0x1a00); // chain0.e2
3597 write_chain(&ram32[0x6d88/4], 0x6d78, 0x19c8, 0x18bc); // chain1.e0
3598 write_chain(&ram32[0x6d78/4], 0x6d68, 0x1990, 0x1858); // chain1.e1
3599 write_chain(&ram32[0x6d68/4], 0x6d58, 0x1958, 0x17f4); // chain1.e2
3600 write_chain(&ram32[0x6d58/4], 0, 0x1920, 0x1794); // chain1.e3
3601 write_chain(&ram32[0x6d98/4], 0, 0, 0x2458); // chain3.e0
3605 // fill the api jumptables with fake entries as some games patch them
3606 // (or rather the funcs listed there)
3607 ptr = (u32 *)&psxM[A_A0_TABLE];
3608 for (i = 0; i < 256; i++)
3609 ptr[i] = SWAP32(0x1000);
3611 ptr = (u32 *)&psxM[A_B0_TABLE];
3612 for (i = 0; i < 256; i++)
3613 ptr[i] = SWAP32(0x2000);
3614 // B(5b) is special because games patch (sometimes even jump to)
3615 // code at fixed offsets from it, nocash lists offsets:
3616 // patch: +3d8, +4dc, +594, +62c, +9c8, +1988
3617 // call: +7a0=4b70, +884=4c54, +894=4c64
3618 ptr[0x5b] = SWAP32(0x43d0);
3619 ram32[0x4b70/4] = SWAP32(0x03e00008); // jr $ra // setPadOutputBuf
3621 ram32[0x4c54/4] = SWAP32(0x240e0001); // mov $t6, 1
3622 ram32[0x4c58/4] = SWAP32(0x03e00008); // jr $ra
3623 ram32[0x4c5c/4] = SWAP32(0xac0e0000 + A_PAD_IRQR_ENA); // sw $t6, ...
3625 ram32[0x4c64/4] = SWAP32(0x03e00008); // jr $ra
3626 ram32[0x4c68/4] = SWAP32(0xac000000 + A_PAD_IRQR_ENA); // sw $0, ...
3628 ptr = (u32 *)&psxM[A_C0_TABLE];
3629 for (i = 0; i < 256/2; i++)
3630 ptr[i] = SWAP32(0x3000);
3631 ptr[6] = SWAP32(A_EXCEPTION);
3634 ram32[0x1000/4] = HLEOP(hleop_dummy);
3635 ram32[0x2000/4] = HLEOP(hleop_dummy);
3636 ram32[0x3000/4] = HLEOP(hleop_dummy);
3637 ram32[0x4c54/4] = HLEOP(hleop_dummy); // for B12_InitPad?
3638 ram32[0x8000/4] = HLEOP(hleop_execret);
3640 ram32[A_EEXIT_PTR/4] = SWAP32(A_EEXIT_DEF);
3641 ram32[A_EXC_SP/4] = SWAP32(A_EXC_STACK);
3642 ram32[A_RCNT_VBL_ACK/4 + 0] = SWAP32(1);
3643 ram32[A_RCNT_VBL_ACK/4 + 1] = SWAP32(1);
3644 ram32[A_RCNT_VBL_ACK/4 + 2] = SWAP32(1);
3645 ram32[A_RCNT_VBL_ACK/4 + 3] = SWAP32(1);
3648 void psxBiosShutdown() {
3651 void psxBiosCnfLoaded(u32 tcb_cnt, u32 evcb_cnt) {
3652 if (tcb_cnt != 4 || evcb_cnt != 16)
3653 setup_tt(tcb_cnt, evcb_cnt);
3656 #define psxBios_PADpoll(pad) { \
3657 PAD##pad##_startPoll(pad); \
3658 pad_buf##pad[0] = 0; \
3659 pad_buf##pad[1] = PAD##pad##_poll(0x42); \
3660 if (!(pad_buf##pad[1] & 0x0f)) { \
3663 bufcount = (pad_buf##pad[1] & 0x0f) * 2; \
3665 PAD##pad##_poll(0); \
3667 while (bufcount--) { \
3668 pad_buf##pad[i++] = PAD##pad##_poll(0); \
3672 static void handle_chain_x_x_1(u32 enable, u32 irqbit)
3676 psxHwWrite16(0x1f801070, ~(1u << irqbit));
3677 psxBios_ReturnFromException();
3683 // hleExc0_{0,1}* are usually removed by A(56)/A(72) on the game's startup,
3684 // so this is only partially implemented
3685 void hleExc0_0_1() // A(93h) - CdromDmaIrqFunc2
3687 u32 cdrom_dma_ack_enable = 1; // a000b93c
3688 handle_chain_x_x_1(cdrom_dma_ack_enable, 3); // IRQ3 DMA
3691 void hleExc0_0_2() // A(91h) - CdromDmaIrqFunc1
3694 //PSXBIOS_LOG("%s\n", __func__);
3696 if (psxHu32(0x1074) & psxHu32(0x1070) & 8) { // IRQ3 DMA
3697 psxHwWrite32(0x1f8010f4, (psxHu32(0x10f4) & 0xffffff) | 0x88000000);
3698 //if (--cdrom_irq_counter == 0) // 0xa0009180
3699 // DeliverEvent(0xf0000003, 0x10);
3703 mips_return_c(ret, 20);
3706 void hleExc0_1_1() // A(92h) - CdromIoIrqFunc2
3708 u32 cdrom_irq_ack_enable = 1; // a000b938
3709 handle_chain_x_x_1(cdrom_irq_ack_enable, 2); // IRQ2 cdrom
3712 void hleExc0_1_2() // A(90h) - CdromIoIrqFunc1
3715 if (psxHu32(0x1074) & psxHu32(0x1070) & 4) { // IRQ2 cdrom
3716 PSXBIOS_LOG("%s TODO\n", __func__);
3719 mips_return_c(ret, 20);
3722 void hleExc0_2_2_syscall() // not in any A/B/C table
3724 u32 code = (psxRegs.CP0.n.Cause & 0x3c) >> 2;
3725 u32 tcbPtr = loadRam32(A_TT_PCB);
3726 TCB *tcb = loadRam32ptr(tcbPtr);
3728 if (code != R3000E_Syscall) {
3730 DeliverEvent(0xf0000010, 0x1000);
3731 //psxBios_SystemErrorUnresolvedException();
3733 mips_return_c(0, 17);
3737 //printf("%s c=%d a0=%d\n", __func__, code, a0);
3738 tcb->epc += SWAP32(4);
3743 case 1: { // EnterCritical - disable irqs
3744 u32 was_enabled = ((SWAP32(tcb->sr) & 0x404) == 0x404);
3745 tcb->reg[2] = SWAP32(was_enabled);
3746 tcb->sr &= SWAP32(~0x404);
3749 case 2: // ExitCritical - enable irqs
3750 tcb->sr |= SWAP32(0x404);
3753 case 3: { // ChangeThreadSubFunction
3754 u32 tcbPtr = loadRam32(A_TT_PCB);
3755 storeRam32(tcbPtr, a1);
3759 DeliverEvent(0xf0000010, 0x4000);
3763 psxBios_ReturnFromException();
3766 void hleExc1_0_1(void)
3768 u32 vbl_irq_ack_enable = loadRam32(A_RCNT_VBL_ACK + 0x0c); // 860c
3769 handle_chain_x_x_1(vbl_irq_ack_enable, 0); // IRQ0 vblank
3772 static void handle_chain_1_x_2(u32 ev_index, u32 irqbit)
3775 if (psxHu32(0x1074) & psxHu32(0x1070) & (1u << irqbit)) {
3776 DeliverEvent(0xf2000000 + ev_index, 0x0002);
3779 mips_return_c(ret, 22);
3782 void hleExc1_0_2(void)
3784 handle_chain_1_x_2(3, 0); // IRQ0 vblank
3787 void hleExc1_1_1(void)
3789 u32 rcnt_irq_ack_enable = loadRam32(A_RCNT_VBL_ACK + 0x08); // 8608
3790 handle_chain_x_x_1(rcnt_irq_ack_enable, 6); // IRQ6 rcnt2
3793 void hleExc1_1_2(void)
3795 handle_chain_1_x_2(2, 6); // IRQ6 rcnt2
3798 void hleExc1_2_1(void)
3800 u32 rcnt_irq_ack_enable = loadRam32(A_RCNT_VBL_ACK + 0x04); // 8604
3801 handle_chain_x_x_1(rcnt_irq_ack_enable, 5); // IRQ5 rcnt1
3804 void hleExc1_2_2(void)
3806 handle_chain_1_x_2(1, 5); // IRQ5 rcnt1
3809 void hleExc1_3_1(void)
3811 u32 rcnt_irq_ack_enable = loadRam32(A_RCNT_VBL_ACK + 0x00); // 8600
3812 handle_chain_x_x_1(rcnt_irq_ack_enable, 4); // IRQ4 rcnt0
3815 void hleExc1_3_2(void)
3817 handle_chain_1_x_2(0, 4); // IRQ4 rcnt0
3820 void hleExc3_0_2_defint(void)
3822 static const struct {
3833 { 6, 6 }, // rcnt2 (bug)
3838 for (i = 0; i < sizeof(tab) / sizeof(tab[0]); i++) {
3839 if (psxHu32(0x1074) & psxHu32(0x1070) & (1u << tab[i].irqbit)) {
3840 DeliverEvent(0xf0000000 + tab[i].ev, 0x1000);
3845 mips_return_c(0, 11 + 7*11 + 7*11 + 12);
3848 void hleExcPadCard1(void)
3850 if (loadRam32(A_PAD_IRQR_ENA)) {
3851 u8 *pad_buf1 = loadRam8ptr(A_PAD_INBUF + 0);
3852 u8 *pad_buf2 = loadRam8ptr(A_PAD_INBUF + 4);
3858 if (loadRam32(A_PAD_DR_DST))
3861 if (loadRam32(A_PAD_ACK_VBL))
3862 psxHwWrite16(0x1f801070, ~1);
3863 if (loadRam32(A_CARD_IRQR_ENA)) {
3867 mips_return_c(0, 18);
3870 void hleExcPadCard2(void)
3872 u32 ret = psxHu32(0x1074) & psxHu32(0x1070) & 1;
3873 mips_return_c(ret, 15);
3876 void psxBiosException() {
3877 u32 tcbPtr = loadRam32(A_TT_PCB);
3878 u32 *chains = loadRam32ptr(A_TT_ExCB);
3879 TCB *tcb = loadRam32ptr(tcbPtr);
3885 // $at, $v0, $v1 already saved by the mips code at A_EXCEPTION
3886 for (i = 4; i < 32; i++) {
3889 tcb->reg[i] = SWAP32(psxRegs.GPR.r[i]);
3891 tcb->lo = SWAP32(psxRegs.GPR.n.lo);
3892 tcb->hi = SWAP32(psxRegs.GPR.n.hi);
3893 //tcb->epc = SWAP32(psxRegs.CP0.n.EPC); // done by asm
3894 tcb->sr = SWAP32(psxRegs.CP0.n.SR);
3895 tcb->cause = SWAP32(psxRegs.CP0.n.Cause);
3896 sp = fp = loadRam32(A_EXC_SP);
3900 // do the chains (always 4)
3901 for (c = lim = 0; c < 4; c++) {
3902 if (chains[c * 2] == 0)
3904 ptr = SWAP32(chains[c * 2]);
3905 for (; ptr && lim < 100; ptr = SWAP32(chain[0])) {
3906 chain = castRam32ptr(ptr);
3911 softCallInException(SWAP32(chain[2]));
3912 if (returned_from_exception())
3915 if (v0 == 0 || chain[1] == 0)
3917 softCallInException(SWAP32(chain[1]));
3918 if (returned_from_exception())
3924 // return from exception (custom or default)
3926 ptr = loadRam32(A_EEXIT_PTR);
3927 if (ptr != A_EEXIT_DEF) {
3928 const struct jmp_buf_ *jmp_buf = castRam32ptr(ptr);
3929 longjmp_load(jmp_buf);
3934 psxBios_ReturnFromException();
3937 #define bfreeze(ptr, size) { \
3938 if (Mode == 1) memcpy(&psxR[base], ptr, size); \
3939 if (Mode == 0) memcpy(ptr, &psxR[base], size); \
3943 #define bfreezes(ptr) bfreeze(ptr, sizeof(ptr))
3944 #define bfreezel(ptr) bfreeze(ptr, sizeof(*ptr))
3946 #define bfreezepsxMptr(ptr, type) { \
3948 if (ptr) psxRu32ref(base) = SWAPu32((s8 *)(ptr) - psxM); \
3949 else psxRu32ref(base) = 0; \
3951 if (psxRu32(base) != 0) ptr = (type *)(psxM + psxRu32(base)); \
3952 else (ptr) = NULL; \
3954 base += sizeof(u32); \
3957 void psxBiosFreeze(int Mode) {