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 static u32 heap_size = 0;
257 static u32 *heap_addr = NULL;
258 static u32 *heap_end = NULL;
259 static FileDesc FDesc[32];
260 static u32 card_active_chan = 0;
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_PAD_DR_BUF1 0x7570
286 #define A_PAD_DR_BUF2 0x7598
287 #define A_EEXIT_PTR 0x75d0
288 #define A_EXC_STACK 0x85d8 // exception stack top
289 #define A_RCNT_VBL_ACK 0x8600
290 #define A_PAD_ACK_VBL 0x8914 // enable vint ack by pad reading code
291 #define A_CD_EVENTS 0xb9b8
292 #define A_EXC_GP 0xf450
294 #define HLEOP(n) SWAPu32((0x3b << 26) | (n));
296 static u32 loadRam32(u32 addr)
298 assert(!(addr & 0x5f800000));
299 return SWAP32(*((u32 *)psxM + ((addr & 0x1fffff) >> 2)));
302 static void *castRam8ptr(u32 addr)
304 assert(!(addr & 0x5f800000));
305 return psxM + (addr & 0x1fffff);
308 static void *castRam32ptr(u32 addr)
310 assert(!(addr & 0x5f800003));
311 return psxM + (addr & 0x1ffffc);
314 static void *loadRam8ptr(u32 addr)
316 return castRam8ptr(loadRam32(addr));
319 static void *loadRam32ptr(u32 addr)
321 return castRam32ptr(loadRam32(addr));
324 static void storeRam8(u32 addr, u8 d)
326 assert(!(addr & 0x5f800000));
327 *((u8 *)psxM + (addr & 0x1fffff)) = d;
330 static void storeRam32(u32 addr, u32 d)
332 assert(!(addr & 0x5f800000));
333 *((u32 *)psxM + ((addr & 0x1fffff) >> 2)) = SWAP32(d);
336 static void mips_return(u32 val)
342 static void use_cycles(u32 cycle)
344 psxRegs.cycle += cycle * 2;
347 static void mips_return_c(u32 val, u32 cycle)
353 static void mips_return_void_c(u32 cycle)
359 static int returned_from_exception(void)
361 // 0x80000080 means it took another exception just after return
362 return pc0 == k0 || pc0 == 0x80000080;
365 static inline void softCall(u32 pc) {
367 u32 ssr = psxRegs.CP0.n.SR;
371 psxRegs.CP0.n.SR &= ~0x404; // disable interrupts
373 while (pc0 != 0x80001000 && ++lim < 1000000)
374 psxCpu->ExecuteBlock(EXEC_CALLER_HLE);
377 PSXBIOS_LOG("softCall @%x hit lim\n", pc);
379 psxRegs.CP0.n.SR |= ssr & 0x404;
382 static inline void softCallInException(u32 pc) {
388 while (!returned_from_exception() && pc0 != 0x80001000 && ++lim < 1000000)
389 psxCpu->ExecuteBlock(EXEC_CALLER_HLE);
392 PSXBIOS_LOG("softCallInException @%x hit lim\n", pc);
393 if (pc0 == 0x80001000)
397 static u32 OpenEvent(u32 class, u32 spec, u32 mode, u32 func);
398 static u32 DeliverEvent(u32 class, u32 spec);
399 static u32 UnDeliverEvent(u32 class, u32 spec);
400 static void CloseEvent(u32 ev);
405 // System calls A0 */
408 #define buread(Ra1, mcd, length) { \
409 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); \
410 ptr = Mcd##mcd##Data + 8192 * FDesc[1 + mcd].mcfile + FDesc[1 + mcd].offset; \
411 memcpy(Ra1, ptr, length); \
412 if (FDesc[1 + mcd].mode & 0x8000) { \
413 DeliverEvent(0xf0000011, 0x0004); \
414 DeliverEvent(0xf4000001, 0x0004); \
417 FDesc[1 + mcd].offset += v0; \
420 #define buwrite(Ra1, mcd, length) { \
421 u32 offset = + 8192 * FDesc[1 + mcd].mcfile + FDesc[1 + mcd].offset; \
422 PSXBIOS_LOG("write %d: %x,%x\n", FDesc[1 + mcd].mcfile, FDesc[1 + mcd].offset, a2); \
423 ptr = Mcd##mcd##Data + offset; \
424 memcpy(ptr, Ra1, length); \
425 FDesc[1 + mcd].offset += length; \
426 SaveMcd(Config.Mcd##mcd, Mcd##mcd##Data, offset, length); \
427 if (FDesc[1 + mcd].mode & 0x8000) { \
428 DeliverEvent(0xf0000011, 0x0004); \
429 DeliverEvent(0xf4000001, 0x0004); \
434 /* Internally redirects to "FileRead(fd,tempbuf,1)".*/
435 /* For some strange reason, the returned character is sign-expanded; */
436 /* So if a return value of FFFFFFFFh could mean either character FFh, or error. */
437 /* TODO FIX ME : Properly implement this behaviour */
438 void psxBios_getc(void) // 0x03, 0x35
443 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x03]);
447 if (pa1 != INVALID_PTR) {
449 case 2: buread(pa1, 1, 1); break;
450 case 3: buread(pa1, 2, 1); break;
457 /* Copy of psxBios_write, except size is 1. */
458 void psxBios_putc(void) // 0x09, 0x3B
463 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x09]);
466 if (pa1 == INVALID_PTR) {
471 if (a0 == 1) { // stdout
472 char *ptr = (char *)pa1;
476 printf("%c", *ptr++); a2--;
482 case 2: buwrite(pa1, 1, 1); break;
483 case 3: buwrite(pa1, 2, 1); break;
489 void psxBios_todigit(void) // 0x0a
493 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x0a]);
496 if (c >= 0x30 && c < 0x3A) {
499 else if (c > 0x60 && c < 0x7B) {
502 else if (c > 0x40 && c < 0x5B) {
505 else if (c >= 0x80) {
516 void psxBios_abs() { // 0x0e
517 if ((s32)a0 < 0) v0 = -(s32)a0;
522 void psxBios_labs() { // 0x0f
526 void psxBios_atoi() { // 0x10
528 char *p = (char *)Ra0;
532 case ' ': case '\t': continue;
539 while (*p >= '0' && *p <= '9') {
540 n = n * 10 + *p++ - '0';
547 void psxBios_atol() { // 0x11
557 static void psxBios_setjmp() { // 0x13
558 struct jmp_buf_ *jmp_buf = castRam32ptr(a0);
561 PSXBIOS_LOG("psxBios_%s %x\n", biosA0n[0x13], a0);
563 jmp_buf->ra_ = SWAP32(ra);
564 jmp_buf->sp_ = SWAP32(sp);
565 jmp_buf->fp_ = SWAP32(fp);
566 for (i = 0; i < 8; i++) // s0-s7
567 jmp_buf->s[i] = SWAP32(psxRegs.GPR.r[16 + i]);
568 jmp_buf->gp_ = SWAP32(gp);
570 mips_return_c(0, 15);
573 static void longjmp_load(const struct jmp_buf_ *jmp_buf)
577 ra = SWAP32(jmp_buf->ra_);
578 sp = SWAP32(jmp_buf->sp_);
579 fp = SWAP32(jmp_buf->fp_);
580 for (i = 0; i < 8; i++) // s0-s7
581 psxRegs.GPR.r[16 + i] = SWAP32(jmp_buf->s[i]);
582 gp = SWAP32(jmp_buf->gp_);;
585 void psxBios_longjmp() { // 0x14
586 struct jmp_buf_ *jmp_buf = castRam32ptr(a0);
588 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x14]);
589 longjmp_load(jmp_buf);
590 mips_return_c(a1, 15);
593 void psxBios_strcat() { // 0x15
594 char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
597 PSXBIOS_LOG("psxBios_%s: %s, %s\n", biosA0n[0x15], Ra0, Ra1);
599 if (a0 == 0 || a1 == 0)
607 while ((*p1++ = *p2++) != '\0');
612 void psxBios_strncat() { // 0x16
613 char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
617 PSXBIOS_LOG("psxBios_%s: %s (%x), %s (%x), %d\n", biosA0n[0x16], Ra0, a0, Ra1, a1, a2);
619 if (a0 == 0 || a1 == 0)
627 while ((*p1++ = *p2++) != '\0') {
637 void psxBios_strcmp() { // 0x17
638 char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
640 if (a0 == 0 && a1 == 0)
646 else if (a0 == 0 && a1 != 0)
652 else if (a0 != 0 && a1 == 0)
659 PSXBIOS_LOG("psxBios_%s: %s (%x), %s (%x)\n", biosA0n[0x17], Ra0, a0, Ra1, a1);
662 while (*p1 == *p2++) {
681 void psxBios_strncmp() { // 0x18
682 char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
684 if (a0 == 0 && a1 == 0)
690 else if (a0 == 0 && a1 != 0)
696 else if (a0 != 0 && a1 == 0)
703 PSXBIOS_LOG("psxBios_%s: %s (%x), %s (%x), %d\n", biosA0n[0x18], Ra0, a0, Ra1, a1, a2);
706 while (--n >= 0 && *p1 == *p2++) {
710 v1 = a2 - ((a2-n) - 1);
718 v0 = (n < 0 ? 0 : *p1 - *--p2);
720 v1 = a2 - ((a2-n) - 1);
726 void psxBios_strcpy() { // 0x19
727 char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
728 if (a0 == 0 || a1 == 0)
734 while ((*p1++ = *p2++) != '\0');
739 void psxBios_strncpy() { // 0x1a
740 char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
742 if (a0 == 0 || a1 == 0)
748 for (i = 0; i < n; i++) {
749 if ((*p1++ = *p2++) == '\0') {
761 void psxBios_strlen() { // 0x1b
762 char *p = (char *)Ra0;
773 void psxBios_index() { // 0x1c
774 char *p = (char *)Ra0;
784 v0 = a0 + (p - (char *)Ra0);
788 } while (*p++ != '\0');
793 void psxBios_rindex() { // 0x1d
794 char *p = (char *)Ra0;
804 v0 = a0 + (p - (char *)Ra0);
805 } while (*p++ != '\0');
810 void psxBios_strchr() { // 0x1e
814 void psxBios_strrchr() { // 0x1f
818 void psxBios_strpbrk() { // 0x20
819 char *p1 = (char *)Ra0, *p2 = (char *)Ra1, *scanp, c, sc;
821 while ((c = *p1++) != '\0') {
822 for (scanp = p2; (sc = *scanp++) != '\0';) {
824 v0 = a0 + (p1 - 1 - (char *)Ra0);
831 // BUG: return a0 instead of NULL if not found
835 void psxBios_strspn() { // 0x21
838 for (p1 = (char *)Ra0; *p1 != '\0'; p1++) {
839 for (p2 = (char *)Ra1; *p2 != '\0' && *p2 != *p1; p2++);
840 if (*p2 == '\0') break;
843 v0 = p1 - (char *)Ra0; pc0 = ra;
846 void psxBios_strcspn() { // 0x22
849 for (p1 = (char *)Ra0; *p1 != '\0'; p1++) {
850 for (p2 = (char *)Ra1; *p2 != '\0' && *p2 != *p1; p2++);
851 if (*p2 != '\0') break;
854 v0 = p1 - (char *)Ra0; pc0 = ra;
857 void psxBios_strtok() { // 0x23
858 char *pcA0 = (char *)Ra0;
859 char *pcRet = strtok(pcA0, (char *)Ra1);
861 v0 = a0 + pcRet - pcA0;
867 void psxBios_strstr() { // 0x24
868 char *p = (char *)Ra0, *p1, *p2;
874 while (*p1 != '\0' && *p2 != '\0' && *p1 == *p2) {
879 v0 = a0 + (p - (char *)Ra0);
890 void psxBios_toupper() { // 0x25
891 v0 = (s8)(a0 & 0xff);
892 if (v0 >= 'a' && v0 <= 'z') v0 -= 'a' - 'A';
896 void psxBios_tolower() { // 0x26
897 v0 = (s8)(a0 & 0xff);
898 if (v0 >= 'A' && v0 <= 'Z') v0 += 'a' - 'A';
902 void psxBios_bcopy() { // 0x27
903 char *p1 = (char *)Ra1, *p2 = (char *)Ra0;
905 if (a0 == 0 || a2 > 0x7FFFFFFF)
910 while ((s32)a2-- > 0) *p1++ = *p2++;
915 void psxBios_bzero() { // 0x28
916 char *p = (char *)Ra0;
918 /* Same as memset here (See memset below) */
919 if (a1 > 0x7FFFFFFF || a1 == 0)
930 while ((s32)a1-- > 0) *p++ = '\0';
935 void psxBios_bcmp() { // 0x29
936 char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
938 if (a0 == 0 || a1 == 0) { v0 = 0; pc0 = ra; return; }
940 while ((s32)a2-- > 0) {
941 if (*p1++ != *p2++) {
942 v0 = *p1 - *p2; // BUG: compare the NEXT byte
951 void psxBios_memcpy() { // 0x2a
952 char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
954 if (a0 == 0 || a2 > 0x7FFFFFFF)
959 while ((s32)a2-- > 0) {
966 void psxBios_memset() { // 0x2b
967 char *p = (char *)Ra0;
969 if (a2 > 0x7FFFFFFF || a2 == 0)
980 while ((s32)a2-- > 0) *p++ = (char)a1;
985 void psxBios_memmove() { // 0x2c
986 char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
988 if (a0 == 0 || a2 > 0x7FFFFFFF)
993 if (p2 <= p1 && p2 + a2 > p1) {
994 a2++; // BUG: copy one more byte here
997 while ((s32)a2-- > 0) *--p1 = *--p2;
999 while ((s32)a2-- > 0) *p1++ = *p2++;
1004 void psxBios_memcmp() { // 0x2d
1008 void psxBios_memchr() { // 0x2e
1009 char *p = (char *)Ra0;
1011 if (a0 == 0 || a2 > 0x7FFFFFFF)
1017 while ((s32)a2-- > 0) {
1018 if (*p++ != (s8)a1) continue;
1019 v0 = a0 + (p - (char *)Ra0 - 1);
1027 void psxBios_rand() { // 0x2f
1028 u32 s = psxMu32(0x9010) * 1103515245 + 12345;
1029 v0 = (s >> 16) & 0x7fff;
1030 psxMu32ref(0x9010) = SWAPu32(s);
1034 void psxBios_srand() { // 0x30
1035 psxMu32ref(0x9010) = SWAPu32(a0);
1039 static u32 qscmpfunc, qswidth;
1041 static inline int qscmp(char *a, char *b) {
1044 a0 = sa0 + (a - (char *)PSXM(sa0));
1045 a1 = sa0 + (b - (char *)PSXM(sa0));
1047 softCall(qscmpfunc);
1053 static inline void qexchange(char *i, char *j) {
1064 static inline void q3exchange(char *i, char *j, char *k) {
1076 static void qsort_main(char *a, char *l) {
1077 char *i, *j, *lp, *hp;
1082 if ((n = l - a) <= qswidth)
1084 n = qswidth * (n / (2 * qswidth));
1090 if ((c = qscmp(i, lp)) == 0) {
1091 qexchange(i, lp -= qswidth);
1102 if ((c = qscmp(hp, j)) == 0) {
1103 qexchange(hp += qswidth, j);
1108 q3exchange(i, hp += qswidth, j);
1122 if (lp - a >= l - hp) {
1123 qsort_main(hp + qswidth, l);
1132 q3exchange(j, lp -= qswidth, i);
1137 void psxBios_qsort() { // 0x31
1140 qsort_main((char *)Ra0, (char *)Ra0 + a1 * a2);
1145 void psxBios_malloc() { // 0x33
1146 u32 *chunk, *newchunk = NULL;
1147 unsigned int dsize = 0, csize, cstat;
1150 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x33]);
1152 if (!a0 || (!heap_size || !heap_addr)) {
1158 // scan through heap and combine free chunks of space
1161 while(chunk < heap_end) {
1162 // get size and status of actual chunk
1163 csize = ((u32)*chunk) & 0xfffffffc;
1164 cstat = ((u32)*chunk) & 1;
1166 // most probably broken heap descriptor
1167 // this fixes Burning Road
1170 dsize = ((uptr)heap_end - (uptr)chunk) - 4;
1175 // it's a free chunk
1180 colflag = 1; // let's begin a new collection of free memory
1182 else dsize += (csize+4); // add the new size including header
1184 // not a free chunk: did we start a collection ?
1186 if(colflag == 1) { // collection is over
1188 *newchunk = SWAP32(dsize | 1);
1193 chunk = (u32*)((uptr)chunk + csize + 4);
1195 // if neccessary free memory on end of heap
1197 *newchunk = SWAP32(dsize | 1);
1200 csize = ((u32)*chunk) & 0xfffffffc;
1201 cstat = ((u32)*chunk) & 1;
1202 dsize = (a0 + 3) & 0xfffffffc;
1204 // exit on uninitialized heap
1205 if (chunk == NULL) {
1206 printf("malloc %x,%x: Uninitialized Heap!\n", v0, a0);
1212 // search an unused chunk that is big enough until the end of the heap
1213 while ((dsize > csize || cstat==0) && chunk < heap_end ) {
1214 chunk = (u32*)((uptr)chunk + csize + 4);
1216 // catch out of memory
1217 if(chunk >= heap_end) {
1218 printf("malloc %x,%x: Out of memory error!\n",
1224 csize = ((u32)*chunk) & 0xfffffffc;
1225 cstat = ((u32)*chunk) & 1;
1229 if(dsize == csize) {
1230 // chunk has same size
1231 *chunk &= 0xfffffffc;
1232 } else if (dsize > csize) {
1237 *chunk = SWAP32(dsize);
1238 newchunk = (u32*)((uptr)chunk + dsize + 4);
1239 *newchunk = SWAP32(((csize - dsize - 4) & 0xfffffffc) | 1);
1242 // return pointer to allocated memory
1243 v0 = ((uptr)chunk - (uptr)psxM) + 4;
1245 //printf ("malloc %x,%x\n", v0, a0);
1249 void psxBios_free() { // 0x34
1251 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x34]);
1252 PSXBIOS_LOG("free %x: %x bytes\n", a0, *(u32*)(Ra0-4));
1255 *(u32*)(Ra0-4) |= 1; // set chunk to free
1259 void psxBios_calloc() { // 0x37
1262 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x37]);
1272 void psxBios_realloc() { // 0x38
1276 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x38]);
1280 /* If "old_buf" is zero, executes malloc(new_size), and returns r2=new_buf (or 0=failed). */
1285 /* Else, if "new_size" is zero, executes free(old_buf), and returns r2=garbage. */
1290 /* Else, executes malloc(new_size), bcopy(old_buf,new_buf,new_size), and free(old_buf), and returns r2=new_buf (or 0=failed). */
1291 /* Note that it is not quite implemented this way here. */
1301 /* InitHeap(void *block , int n) */
1302 void psxBios_InitHeap() { // 0x39
1306 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x39]);
1309 if (((a0 & 0x1fffff) + a1)>= 0x200000) size = 0x1ffffc - (a0 & 0x1fffff);
1314 heap_addr = (u32 *)Ra0;
1316 heap_end = (u32 *)((u8 *)heap_addr + heap_size);
1317 /* HACKFIX: Commenting out this line fixes GTA2 crash */
1318 //*heap_addr = SWAP32(size | 1);
1320 PSXBIOS_LOG("InitHeap %x,%x : %x %x\n",a0,a1, (int)((uptr)heap_addr-(uptr)psxM), size);
1325 void psxBios_getchar() { //0x3b
1326 v0 = getchar(); pc0 = ra;
1329 static void psxBios_printf_psxout() { // 0x3f
1338 if (psp != INVALID_PTR) {
1339 memcpy(save, psp, 4 * 4);
1340 psxMu32ref(sp) = SWAP32((u32)a0);
1341 psxMu32ref(sp + 4) = SWAP32((u32)a1);
1342 psxMu32ref(sp + 8) = SWAP32((u32)a2);
1343 psxMu32ref(sp + 12) = SWAP32((u32)a3);
1355 tmp2[j++] = Ra0[i]; goto _start;
1357 if (Ra0[i] >= '0' && Ra0[i] <= '9') {
1368 ptmp += sprintf(ptmp, tmp2, (float)psxMu32(sp + n * 4)); n++; break;
1372 ptmp += sprintf(ptmp, tmp2, (double)psxMu32(sp + n * 4)); n++; break;
1378 ptmp += sprintf(ptmp, tmp2, (unsigned int)psxMu32(sp + n * 4)); n++; break;
1380 ptmp += sprintf(ptmp, tmp2, (unsigned char)psxMu32(sp + n * 4)); n++; break;
1382 ptmp += sprintf(ptmp, tmp2, (char*)PSXM(psxMu32(sp + n * 4))); n++; break;
1384 *ptmp++ = Ra0[i]; break;
1394 if (psp != INVALID_PTR)
1395 memcpy(psp, save, 4 * 4);
1398 SysPrintf("%s", tmp);
1401 void psxBios_printf() { // 0x3f
1402 psxBios_printf_psxout();
1406 void psxBios_format() { // 0x41
1407 if (strcmp(Ra0, "bu00:") == 0 && Config.Mcd1[0] != '\0')
1409 CreateMcd(Config.Mcd1);
1410 LoadMcd(1, Config.Mcd1);
1413 else if (strcmp(Ra0, "bu10:") == 0 && Config.Mcd2[0] != '\0')
1415 CreateMcd(Config.Mcd2);
1416 LoadMcd(2, Config.Mcd2);
1426 static void psxBios_SystemErrorUnresolvedException() {
1427 if (loadRam32(0xfffc) != 0x12345678) { // prevent log flood
1428 SysPrintf("psxBios_%s called from %08x\n", biosA0n[0x40], ra);
1429 storeRam32(0xfffc, 0x12345678);
1431 mips_return_void_c(1000);
1435 * long Load(char *name, struct EXEC *header);
1438 void psxBios_Load() { // 0x42
1443 if (pa1 && LoadCdromFile(Ra0, &eheader) == 0) {
1444 memcpy(pa1, ((char*)&eheader)+16, sizeof(EXEC));
1447 PSXBIOS_LOG("psxBios_%s: %s, %d -> %d\n", biosA0n[0x42], Ra0, a1, v0);
1453 * int Exec(struct EXEC *header , int argc , char **argv);
1456 void psxBios_Exec() { // 43
1457 EXEC *header = (EXEC *)castRam32ptr(a0);
1461 PSXBIOS_LOG("psxBios_%s: %x, %x, %x\n", biosA0n[0x43], a0, a1, a2);
1463 header->_sp = SWAP32(sp);
1464 header->_fp = SWAP32(fp);
1465 header->_sp = SWAP32(sp);
1466 header->_gp = SWAP32(gp);
1467 header->ret = SWAP32(ra);
1468 header->base = SWAP32(s0);
1470 ptr = SWAP32(header->b_addr);
1471 len = SWAP32(header->b_size);
1477 if (header->S_addr != 0)
1478 sp = fp = SWAP32(header->S_addr) + SWAP32(header->s_size);
1480 gp = SWAP32(header->gp0);
1488 pc0 = SWAP32(header->_pc0);
1491 void psxBios_FlushCache() { // 44
1493 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x44]);
1495 psxCpu->Notify(R3000ACPU_NOTIFY_CACHE_ISOLATED, NULL);
1496 psxCpu->Notify(R3000ACPU_NOTIFY_CACHE_UNISOLATED, NULL);
1500 void psxBios_GPU_dw() { // 0x46
1505 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x46]);
1508 GPU_writeData(0xa0000000);
1509 GPU_writeData((a1<<0x10)|(a0&0xffff));
1510 GPU_writeData((a3<<0x10)|(a2&0xffff));
1512 ptr = (u32*)PSXM(Rsp[4]); //that is correct?
1515 GPU_writeData(SWAPu32(*ptr++));
1521 void psxBios_mem2vram() { // 0x47
1524 GPU_writeData(0xa0000000);
1525 GPU_writeData((a1<<0x10)|(a0&0xffff));
1526 GPU_writeData((a3<<0x10)|(a2&0xffff));
1527 size = ((((a2 * a3) / 2) >> 4) << 16);
1528 GPU_writeStatus(0x04000002);
1529 psxHwWrite32(0x1f8010f4,0);
1530 psxHwWrite32(0x1f8010f0,psxHwRead32(0x1f8010f0)|0x800);
1531 psxHwWrite32(0x1f8010a0,Rsp[4]);//might have a buggy...
1532 psxHwWrite32(0x1f8010a4, size | 0x10);
1533 psxHwWrite32(0x1f8010a8,0x01000201);
1538 void psxBios_SendGPU() { // 0x48
1539 GPU_writeStatus(a0);
1544 void psxBios_GPU_cw() { // 0x49
1551 void psxBios_GPU_cwb() { // 0x4a
1552 u32 *ptr = (u32*)Ra0;
1557 GPU_writeData(SWAPu32(*ptr++));
1563 void psxBios_GPU_SendPackets() { //4b:
1565 GPU_writeStatus(0x04000002);
1566 psxHwWrite32(0x1f8010f4,0);
1567 psxHwWrite32(0x1f8010f0,psxHwRead32(0x1f8010f0)|0x800);
1568 psxHwWrite32(0x1f8010a0,a0);
1569 psxHwWrite32(0x1f8010a4,0);
1570 psxHwWrite32(0x1f8010a8,0x010000401);
1574 void psxBios_sys_a0_4c() { // 0x4c GPU relate
1575 psxHwWrite32(0x1f8010a8,0x00000401);
1576 GPU_writeData(0x0400000);
1577 GPU_writeData(0x0200000);
1578 GPU_writeData(0x0100000);
1583 void psxBios_GPU_GetGPUStatus() { // 0x4d
1584 v0 = GPU_readStatus();
1590 void psxBios_LoadExec() { // 51
1591 EXEC *header = (EXEC*)PSXM(0xf000);
1595 PSXBIOS_LOG("psxBios_%s: %s: %x,%x\n", biosA0n[0x51], Ra0, a1, a2);
1597 s_addr = a1; s_size = a2;
1602 header->S_addr = s_addr;
1603 header->s_size = s_size;
1605 a0 = 0xf000; a1 = 0; a2 = 0;
1609 void psxBios__bu_init() { // 70
1611 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x70]);
1614 DeliverEvent(0xf0000011, 0x0004);
1615 DeliverEvent(0xf4000001, 0x0004);
1620 void psxBios__96_init() { // 71
1622 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x71]);
1628 static void write_chain(u32 *d, u32 next, u32 handler1, u32 handler2);
1629 static void psxBios_SysEnqIntRP_(u32 priority, u32 chain_eptr);
1630 static void psxBios_SysDeqIntRP_(u32 priority, u32 chain_rm_eptr);
1632 static void psxBios_DequeueCdIntr_() {
1633 psxBios_SysDeqIntRP_(0, 0x91d0);
1634 psxBios_SysDeqIntRP_(0, 0x91e0);
1638 static void psxBios_DequeueCdIntr() { // a3
1639 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0xa3]);
1640 psxBios_DequeueCdIntr_();
1643 static void psxBios_CdRemove() { // 56, 72
1644 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x72]);
1646 CloseEvent(loadRam32(A_CD_EVENTS + 0x00));
1647 CloseEvent(loadRam32(A_CD_EVENTS + 0x04));
1648 CloseEvent(loadRam32(A_CD_EVENTS + 0x08));
1649 CloseEvent(loadRam32(A_CD_EVENTS + 0x0c));
1650 CloseEvent(loadRam32(A_CD_EVENTS + 0x10));
1651 psxBios_DequeueCdIntr_();
1653 // EnterCriticalSection - should be done at the beginning,
1654 // but this way is much easier to implement
1660 void psxBios_SetMem() { // 9f
1661 u32 new = psxHu32(0x1060);
1664 PSXBIOS_LOG("psxBios_%s: %x, %x\n", biosA0n[0x9f], a0, a1);
1669 psxHu32ref(0x1060) = SWAP32(new);
1670 psxMu32ref(0x060) = a0;
1671 PSXBIOS_LOG("Change effective memory : %d MBytes\n",a0);
1675 psxHu32ref(0x1060) = SWAP32(new | 0x300);
1676 psxMu32ref(0x060) = a0;
1677 PSXBIOS_LOG("Change effective memory : %d MBytes\n",a0);
1680 PSXBIOS_LOG("Effective memory must be 2/8 MBytes\n");
1687 /* TODO FIXME : Not compliant. -1 indicates failure but using 1 for now. */
1688 void psxBios_get_cd_status(void) //a6
1694 void psxBios__card_info() { // ab
1696 PSXBIOS_LOG("psxBios_%s: %x\n", biosA0n[0xab], a0);
1699 card_active_chan = a0;
1700 port = card_active_chan >> 4;
1706 if (McdDisable[port & 1])
1711 PSXBIOS_LOG("psxBios_%s: UNKNOWN PORT 0x%x\n", biosA0n[0xab], card_active_chan);
1717 if (McdDisable[0] && McdDisable[1])
1720 DeliverEvent(0xf0000011, 0x0004);
1721 // DeliverEvent(0xf4000001, 0x0004);
1722 DeliverEvent(0xf4000001, ret);
1726 void psxBios__card_load() { // ac
1728 PSXBIOS_LOG("psxBios_%s: %x\n", biosA0n[0xac], a0);
1731 card_active_chan = a0;
1733 // DeliverEvent(0xf0000011, 0x0004);
1734 DeliverEvent(0xf4000001, 0x0004);
1739 static void psxBios_GetSystemInfo() { // b4
1741 //PSXBIOS_LOG("psxBios_%s %x\n", biosA0n[0xb4], a0);
1742 SysPrintf("psxBios_%s %x\n", biosA0n[0xb4], a0);
1745 case 1: ret = SWAP32(((u32 *)psxR)[0x100/4 + a0]); break;
1746 case 2: ret = 0xbfc0012c; break;
1747 case 5: ret = loadRam32(0x60) << 10; break;
1749 mips_return_c(ret, 20);
1752 /* System calls B0 */
1754 static u32 psxBios_SysMalloc_(u32 size);
1756 static void psxBios_SysMalloc() { // B 00
1757 u32 ret = psxBios_SysMalloc_(a0);
1759 PSXBIOS_LOG("psxBios_%s 0x%x -> %x\n", biosB0n[0x00], a0, ret);
1760 mips_return_c(ret, 33);
1763 void psxBios_SetRCnt() { // 02
1765 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x02]);
1772 psxRcntWtarget(a0, a1);
1773 if (a2&0x1000) mode|= 0x050; // Interrupt Mode
1774 if (a2&0x0100) mode|= 0x008; // Count to 0xffff
1775 if (a2&0x0010) mode|= 0x001; // Timer stop mode
1776 if (a0 == 2) { if (a2&0x0001) mode|= 0x200; } // System Clock mode
1777 else { if (a2&0x0001) mode|= 0x100; } // System Clock mode
1779 psxRcntWmode(a0, mode);
1784 void psxBios_GetRCnt() { // 03
1786 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x03]);
1790 if (a0 != 3) v0 = psxRcntRcount(a0);
1795 void psxBios_StartRCnt() { // 04
1797 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x04]);
1801 if (a0 != 3) psxHu32ref(0x1074)|= SWAP32((u32)((1<<(a0+4))));
1802 else psxHu32ref(0x1074)|= SWAPu32(0x1);
1806 void psxBios_StopRCnt() { // 05
1808 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x05]);
1812 if (a0 != 3) psxHu32ref(0x1074)&= SWAP32((u32)(~(1<<(a0+4))));
1813 else psxHu32ref(0x1074)&= SWAPu32(~0x1);
1817 void psxBios_ResetRCnt() { // 06
1819 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x06]);
1824 psxRcntWmode(a0, 0);
1825 psxRcntWtarget(a0, 0);
1826 psxRcntWcount(a0, 0);
1831 static u32 DeliverEvent(u32 class, u32 spec) {
1832 EvCB *ev = (EvCB *)loadRam32ptr(A_TT_EvCB);
1833 u32 evcb_len = loadRam32(A_TT_EvCB + 4);
1834 u32 ret = loadRam32(A_TT_EvCB) + evcb_len;
1835 u32 i, lim = evcb_len / 0x1c;
1837 for (i = 0; i < lim; i++, ev++) {
1839 if (SWAP32(ev->status) != EvStACTIVE)
1842 if (SWAP32(ev->class) != class)
1845 if (SWAP32(ev->spec) != spec)
1848 ret = SWAP32(ev->mode);
1849 if (ret == EvMdMARK) {
1850 ev->status = SWAP32(EvStALREADY);
1854 if (ret == EvMdCALL) {
1855 ret = SWAP32(ev->fhandler);
1867 static u32 UnDeliverEvent(u32 class, u32 spec) {
1868 EvCB *ev = (EvCB *)loadRam32ptr(A_TT_EvCB);
1869 u32 evcb_len = loadRam32(A_TT_EvCB + 4);
1870 u32 ret = loadRam32(A_TT_EvCB) + evcb_len;
1871 u32 i, lim = evcb_len / 0x1c;
1873 for (i = 0; i < lim; i++, ev++) {
1875 if (SWAP32(ev->status) != EvStALREADY)
1878 if (SWAP32(ev->class) != class)
1881 if (SWAP32(ev->spec) != spec)
1884 if (SWAP32(ev->mode) == EvMdMARK)
1885 ev->status = SWAP32(EvStACTIVE);
1891 static void psxBios_DeliverEvent() { // 07
1893 PSXBIOS_LOG("psxBios_%s %x %04x\n", biosB0n[0x07], a0, a1);
1895 ret = DeliverEvent(a0, a1);
1899 static s32 get_free_EvCB_slot() {
1900 EvCB *ev = (EvCB *)loadRam32ptr(A_TT_EvCB);
1901 u32 i, lim = loadRam32(A_TT_EvCB + 4) / 0x1c;
1904 for (i = 0; i < lim; i++, ev++) {
1906 if (ev->status == SWAP32(EvStUNUSED))
1912 static u32 OpenEvent(u32 class, u32 spec, u32 mode, u32 func) {
1913 u32 ret = get_free_EvCB_slot();
1914 if ((s32)ret >= 0) {
1915 EvCB *ev = (EvCB *)loadRam32ptr(A_TT_EvCB) + ret;
1916 ev->class = SWAP32(class);
1917 ev->status = SWAP32(EvStDISABLED);
1918 ev->spec = SWAP32(spec);
1919 ev->mode = SWAP32(mode);
1920 ev->fhandler = SWAP32(func);
1926 static void psxBios_OpenEvent() { // 08
1927 u32 ret = OpenEvent(a0, a1, a2, a3);
1928 PSXBIOS_LOG("psxBios_%s (class:%x, spec:%04x, mode:%04x, func:%x) -> %x\n",
1929 biosB0n[0x08], a0, a1, a2, a3, ret);
1930 mips_return_c(ret, 36);
1933 static void CloseEvent(u32 ev)
1935 u32 base = loadRam32(A_TT_EvCB);
1936 storeRam32(base + (ev & 0xffff) * sizeof(EvCB) + 4, EvStUNUSED);
1939 static void psxBios_CloseEvent() { // 09
1940 PSXBIOS_LOG("psxBios_%s %x (%x)\n", biosB0n[0x09], a0,
1941 loadRam32(loadRam32(A_TT_EvCB) + (a0 & 0xffff) * sizeof(EvCB) + 4));
1943 mips_return_c(1, 10);
1946 static void psxBios_WaitEvent() { // 0a
1947 u32 base = loadRam32(A_TT_EvCB);
1948 u32 status = loadRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4);
1949 PSXBIOS_LOG("psxBios_%s %x (status=%x)\n", biosB0n[0x0a], a0, status);
1952 if (status == EvStALREADY) {
1953 storeRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4, EvStACTIVE);
1957 if (status != EvStACTIVE)
1959 mips_return_c(0, 2);
1963 // retrigger this hlecall after the next emulation event
1965 if ((s32)(next_interupt - psxRegs.cycle) > 0)
1966 psxRegs.cycle = next_interupt;
1970 static void psxBios_TestEvent() { // 0b
1971 u32 base = loadRam32(A_TT_EvCB);
1972 u32 status = loadRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4);
1974 PSXBIOS_LOG("psxBios_%s %x %x\n", biosB0n[0x0b], a0, status);
1975 if (status == EvStALREADY) {
1976 storeRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4, EvStACTIVE);
1980 mips_return_c(ret, 15);
1983 static void psxBios_EnableEvent() { // 0c
1984 u32 base = loadRam32(A_TT_EvCB);
1985 u32 status = loadRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4);
1986 PSXBIOS_LOG("psxBios_%s %x (%x)\n", biosB0n[0x0c], a0, status);
1987 if (status != EvStUNUSED)
1988 storeRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4, EvStACTIVE);
1990 mips_return_c(1, 15);
1993 static void psxBios_DisableEvent() { // 0d
1994 u32 base = loadRam32(A_TT_EvCB);
1995 u32 status = loadRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4);
1996 PSXBIOS_LOG("psxBios_%s %x: %x\n", biosB0n[0x0d], a0, status);
1997 if (status != EvStUNUSED)
1998 storeRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4, EvStDISABLED);
2000 mips_return_c(1, 15);
2004 * long OpenTh(long (*func)(), unsigned long sp, unsigned long gp);
2007 void psxBios_OpenTh() { // 0e
2008 TCB *tcb = loadRam32ptr(A_TT_TCB);
2009 u32 limit = loadRam32(A_TT_TCB + 4) / 0xc0u;
2012 for (th = 1; th < limit; th++)
2014 if (tcb[th].status != SWAP32(0x4000)) break;
2018 // Feb 2019 - Added out-of-bounds fix caught by cppcheck:
2019 // When no free TCB is found, return 0xffffffff according to Nocash doc.
2021 PSXBIOS_LOG("\t%s() WARNING! No Free TCBs found!\n", __func__);
2023 mips_return_c(0xffffffff, 20);
2026 PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x0e], th);
2028 tcb[th].status = SWAP32(0x4000);
2029 tcb[th].mode = SWAP32(0x1000);
2030 tcb[th].epc = SWAP32(a0);
2031 tcb[th].reg[30] = SWAP32(a1); // fp
2032 tcb[th].reg[29] = SWAP32(a1); // sp
2033 tcb[th].reg[28] = SWAP32(a2); // gp
2035 mips_return_c(0xff000000 + th, 34);
2039 * int CloseTh(long thread);
2042 void psxBios_CloseTh() { // 0f
2043 TCB *tcb = loadRam32ptr(A_TT_TCB);
2044 u32 limit = loadRam32(A_TT_TCB + 4) / 0xc0u;
2048 PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x0f], th);
2050 /* The return value is always 1 (even if the handle was already closed). */
2052 if (th < limit && tcb[th].status == SWAP32(0x4000)) {
2053 tcb[th].status = SWAP32(0x1000);
2060 * int ChangeTh(long thread);
2063 void psxBios_ChangeTh() { // 10
2064 u32 tcbBase = loadRam32(A_TT_TCB);
2065 u32 th = a0 & 0xffff;
2067 // this is quite spammy
2068 //PSXBIOS_LOG("psxBios_%s %x\n", biosB0n[0x10], th);
2070 // without doing any argument checks, just issue a syscall
2071 // (like the real bios does)
2073 a1 = tcbBase + th * sizeof(TCB);
2078 void psxBios_InitPAD() { // 0x12
2079 u32 i, *ram32 = (u32 *)psxM;
2080 PSXBIOS_LOG("psxBios_%s %x %x %x %x\n", biosB0n[0x12], a0, a1, a2, a3);
2082 // printf("%s", "PS-X Control PAD Driver Ver 3.0");
2083 ram32[A_PAD_DR_DST/4] = 0;
2084 ram32[A_PAD_OUTBUF/4 + 0] = 0;
2085 ram32[A_PAD_OUTBUF/4 + 1] = 0;
2086 ram32[A_PAD_OUT_LEN/4 + 0] = 0;
2087 ram32[A_PAD_OUT_LEN/4 + 1] = 0;
2088 ram32[A_PAD_INBUF/4 + 0] = SWAP32(a0);
2089 ram32[A_PAD_INBUF/4 + 1] = SWAP32(a2);
2090 ram32[A_PAD_IN_LEN/4 + 0] = SWAP32(a1);
2091 ram32[A_PAD_IN_LEN/4 + 1] = SWAP32(a3);
2093 for (i = 0; i < a1; i++) {
2095 storeRam8(a0 + i, 0);
2097 for (i = 0; i < a3; i++) {
2099 storeRam8(a2 + i, 0);
2101 write_chain(ram32 + A_PADCRD_CHN_E/4, 0, 0x49bc, 0x4a4c);
2103 ram32[A_PAD_IRQR_ENA/4] = SWAP32(1);
2105 mips_return_c(1, 200);
2108 void psxBios_StartPAD() { // 13
2109 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x13]);
2111 psxBios_SysDeqIntRP_(2, A_PADCRD_CHN_E);
2112 psxBios_SysEnqIntRP_(2, A_PADCRD_CHN_E);
2113 psxHwWrite16(0x1f801070, ~1);
2114 psxHwWrite16(0x1f801074, psxHu32(0x1074) | 1);
2115 storeRam32(A_PAD_ACK_VBL, 1);
2116 storeRam32(A_RCNT_VBL_ACK + (3 << 2), 0);
2117 psxRegs.CP0.n.SR |= 0x401;
2119 mips_return_c(1, 300);
2122 void psxBios_StopPAD() { // 14
2123 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x14]);
2124 storeRam32(A_RCNT_VBL_ACK + (3 << 2), 1);
2125 psxBios_SysDeqIntRP_(2, A_PADCRD_CHN_E);
2126 psxRegs.CP0.n.SR |= 0x401;
2127 mips_return_void_c(200);
2130 static void psxBios_PAD_init() { // 15
2132 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x15]);
2133 if (a0 == 0x20000000 || a0 == 0x20000001)
2136 a0 = A_PAD_DR_BUF1; a1 = 0x22;
2137 a2 = A_PAD_DR_BUF2; a3 = 0x22;
2140 storeRam32(A_PAD_DR_DST, dst);
2143 mips_return_c(ret, 100);
2146 static u32 psxBios_PAD_dr_() {
2147 u8 *dst = loadRam32ptr(A_PAD_DR_DST);
2148 u8 *buf1 = castRam8ptr(A_PAD_DR_BUF1);
2149 u8 *buf2 = castRam8ptr(A_PAD_DR_BUF2);
2150 dst[0] = dst[1] = dst[2] = dst[3] = ~0;
2151 if (buf1[0] == 0 && (buf1[1] == 0x23 || buf1[1] == 0x41))
2153 dst[0] = buf1[3], dst[1] = buf1[2];
2154 if (buf1[1] == 0x23) {
2155 dst[0] |= 0xc7, dst[1] |= 7;
2156 if (buf1[5] >= 0x10) dst[0] &= ~(1u << 6);
2157 if (buf1[6] >= 0x10) dst[0] &= ~(1u << 7);
2160 if (buf2[0] == 0 && (buf2[1] == 0x23 || buf2[1] == 0x41))
2162 dst[2] = buf2[3], dst[3] = buf2[2];
2163 if (buf2[1] == 0x23) {
2164 dst[2] |= 0xc7, dst[3] |= 7;
2165 if (buf2[5] >= 0x10) dst[2] &= ~(1u << 6);
2166 if (buf2[6] >= 0x10) dst[2] &= ~(1u << 7);
2170 return SWAP32(*(u32 *)dst);
2173 static void psxBios_PAD_dr() { // 16
2174 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x16]);
2175 u32 ret = psxBios_PAD_dr_();
2179 static void psxBios_ReturnFromException() { // 17
2180 u32 tcbPtr = loadRam32(A_TT_PCB);
2181 const TCB *tcb = loadRam32ptr(tcbPtr);
2185 for (i = 1; i < 32; i++)
2186 psxRegs.GPR.r[i] = SWAP32(tcb->reg[i]);
2187 psxRegs.GPR.n.lo = SWAP32(tcb->lo);
2188 psxRegs.GPR.n.hi = SWAP32(tcb->hi);
2189 sr = SWAP32(tcb->sr);
2191 //printf("%s %08x->%08x %u\n", __func__, pc0, tcb->epc, psxRegs.cycle);
2192 pc0 = k0 = SWAP32(tcb->epc);
2194 // the interpreter wants to know about sr changes, so do a MTC0
2195 sr = (sr & ~0x0f) | ((sr & 0x3c) >> 2);
2196 MTC0(&psxRegs, 12, sr);
2202 void psxBios_ResetEntryInt() { // 18
2203 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x18]);
2205 storeRam32(A_EEXIT_PTR, A_EEXIT_DEF);
2206 mips_return_void_c(5);
2209 void psxBios_HookEntryInt() { // 19
2210 PSXBIOS_LOG("psxBios_%s %x\n", biosB0n[0x19], a0);
2212 storeRam32(A_EEXIT_PTR, a0);
2213 mips_return_void_c(3);
2216 static void psxBios_UnDeliverEvent() { // 0x20
2218 PSXBIOS_LOG("psxBios_%s %x %x\n", biosB0n[0x20], a0, a1);
2220 ret = UnDeliverEvent(a0, a1);
2224 char ffile[64], *pfile;
2227 static void buopen(int mcd, char *ptr, char *cfg)
2230 char *mcd_data = ptr;
2232 strcpy(FDesc[1 + mcd].name, Ra0+5);
2233 FDesc[1 + mcd].offset = 0;
2234 FDesc[1 + mcd].mode = a1;
2236 for (i=1; i<16; i++) {
2237 const char *fptr = mcd_data + 128 * i;
2238 if ((*fptr & 0xF0) != 0x50) continue;
2239 if (strcmp(FDesc[1 + mcd].name, fptr+0xa)) continue;
2240 FDesc[1 + mcd].mcfile = i;
2241 PSXBIOS_LOG("open %s\n", fptr+0xa);
2245 if (a1 & 0x200 && v0 == -1) { /* FCREAT */
2246 for (i=1; i<16; i++) {
2247 int j, xor, nblk = a1 >> 16;
2249 char *fptr = mcd_data + 128 * i;
2251 if ((*fptr & 0xF0) != 0xa0) continue;
2253 FDesc[1 + mcd].mcfile = i;
2256 fptr[5] = 0x20 * nblk;
2259 strcpy(fptr+0xa, FDesc[1 + mcd].name);
2260 pptr = fptr2 = fptr;
2261 for(j=2; j<=nblk; j++) {
2263 for(i++; i<16; i++) {
2266 memset(fptr2, 0, 128);
2267 fptr2[0] = j < nblk ? 0x52 : 0x53;
2270 for (k=0, xor=0; k<127; k++) xor^= pptr[k];
2275 /* shouldn't this return ENOSPC if i == 16? */
2277 pptr[8] = pptr[9] = 0xff;
2278 for (j=0, xor=0; j<127; j++) xor^= pptr[j];
2280 PSXBIOS_LOG("openC %s %d\n", ptr, nblk);
2282 /* just go ahead and resave them all */
2283 SaveMcd(cfg, ptr, 128, 128 * 15);
2286 /* shouldn't this return ENOSPC if i == 16? */
2291 * int open(char *name , int mode);
2294 void psxBios_open() { // 0x32
2298 PSXBIOS_LOG("psxBios_%s: %s,%x\n", biosB0n[0x32], Ra0, a1);
2303 if (pa0 != INVALID_PTR) {
2304 if (!strncmp(pa0, "bu00", 4)) {
2305 buopen(1, Mcd1Data, Config.Mcd1);
2308 if (!strncmp(pa0, "bu10", 4)) {
2309 buopen(2, Mcd2Data, Config.Mcd2);
2317 * int lseek(int fd , int offset , int whence);
2320 void psxBios_lseek() { // 0x33
2322 PSXBIOS_LOG("psxBios_%s: %x, %x, %x\n", biosB0n[0x33], a0, a1, a2);
2327 FDesc[a0].offset = a1;
2329 // DeliverEvent(0xf0000011, 0x0004);
2330 // DeliverEvent(0xf4000001, 0x0004);
2334 FDesc[a0].offset+= a1;
2335 v0 = FDesc[a0].offset;
2344 * int read(int fd , void *buf , int nbytes);
2347 void psxBios_read() { // 0x34
2352 PSXBIOS_LOG("psxBios_%s: %x, %x, %x\n", biosB0n[0x34], a0, a1, a2);
2357 if (pa1 != INVALID_PTR) {
2359 case 2: buread(pa1, 1, a2); break;
2360 case 3: buread(pa1, 2, a2); break;
2368 * int write(int fd , void *buf , int nbytes);
2371 void psxBios_write() { // 0x35/0x03
2375 if (a0 != 1) // stdout
2376 PSXBIOS_LOG("psxBios_%s: %x,%x,%x\n", biosB0n[0x35], a0, a1, a2);
2379 if (pa1 == INVALID_PTR) {
2384 if (a0 == 1) { // stdout
2388 if (Config.PsxOut) while (a2 > 0) {
2389 SysPrintf("%c", *ptr++); a2--;
2395 case 2: buwrite(pa1, 1, a2); break;
2396 case 3: buwrite(pa1, 2, a2); break;
2402 static void psxBios_write_psxout() {
2403 if (a0 == 1) { // stdout
2404 const char *ptr = Ra1;
2407 if (ptr != INVALID_PTR)
2409 SysPrintf("%c", *ptr++);
2413 static void psxBios_putchar_psxout() { // 3d
2414 SysPrintf("%c", (char)a0);
2417 static void psxBios_puts_psxout() { // 3e/3f
2418 SysPrintf("%s", Ra0);
2422 * int close(int fd);
2425 void psxBios_close() { // 0x36
2427 PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x36], a0);
2434 void psxBios_putchar() { // 3d
2435 if (Config.PsxOut) SysPrintf("%c", (char)a0);
2439 void psxBios_puts() { // 3e/3f
2440 if (Config.PsxOut) SysPrintf("%s", Ra0);
2445 /* To avoid any issues with different behaviour when using the libc's own strlen instead.
2446 * We want to mimic the PSX's behaviour in this case for bufile. */
2447 static size_t strlen_internal(char* p)
2449 size_t size_of_array = 0;
2450 while (*p++) size_of_array++;
2451 return size_of_array;
2454 #define bufile(mcd) { \
2455 size_t size_of_name = strlen_internal(dir->name); \
2456 while (nfile < 16) { \
2459 ptr = Mcd##mcd##Data + 128 * (nfile + 1); \
2461 if ((*ptr & 0xF0) != 0x50) continue; \
2462 /* Bug link files show up as free block. */ \
2463 if (!ptr[0xa]) continue; \
2465 if (pfile[0] == 0) { \
2466 strncpy(dir->name, ptr, sizeof(dir->name) - 1); \
2467 if (size_of_name < sizeof(dir->name)) dir->name[size_of_name] = '\0'; \
2468 } else for (i=0; i<20; i++) { \
2469 if (pfile[i] == ptr[i]) { \
2470 dir->name[i] = ptr[i]; continue; } \
2471 if (pfile[i] == '?') { \
2472 dir->name[i] = ptr[i]; continue; } \
2473 if (pfile[i] == '*') { \
2474 strcpy(dir->name+i, ptr+i); break; } \
2477 PSXBIOS_LOG("%d : %s = %s + %s (match=%d)\n", nfile, dir->name, pfile, ptr, match); \
2478 if (match == 0) { continue; } \
2486 * struct DIRENTRY* firstfile(char *name,struct DIRENTRY *dir);
2489 void psxBios_firstfile() { // 42
2490 struct DIRENTRY *dir = (struct DIRENTRY *)Ra1;
2497 PSXBIOS_LOG("psxBios_%s: %s\n", biosB0n[0x42], Ra0);
2502 if (pa0 != INVALID_PTR) {
2506 if (!strncmp(pa0, "bu00", 4)) {
2507 // firstfile() calls _card_read() internally, so deliver it's event
2508 DeliverEvent(0xf0000011, 0x0004);
2510 } else if (!strncmp(pa0, "bu10", 4)) {
2511 // firstfile() calls _card_read() internally, so deliver it's event
2512 DeliverEvent(0xf0000011, 0x0004);
2521 * struct DIRENTRY* nextfile(struct DIRENTRY *dir);
2524 void psxBios_nextfile() { // 43
2525 struct DIRENTRY *dir = (struct DIRENTRY *)Ra0;
2531 PSXBIOS_LOG("psxBios_%s: %s\n", biosB0n[0x43], dir->name);
2536 if (!strncmp(ffile, "bu00", 4)) {
2540 if (!strncmp(ffile, "bu10", 4)) {
2547 #define burename(mcd) { \
2548 for (i=1; i<16; i++) { \
2549 int namelen, j, xor = 0; \
2550 ptr = Mcd##mcd##Data + 128 * i; \
2551 if ((*ptr & 0xF0) != 0x50) continue; \
2552 if (strcmp(Ra0+5, ptr+0xa)) continue; \
2553 namelen = strlen(Ra1+5); \
2554 memcpy(ptr+0xa, Ra1+5, namelen); \
2555 memset(ptr+0xa+namelen, 0, 0x75-namelen); \
2556 for (j=0; j<127; j++) xor^= ptr[j]; \
2558 SaveMcd(Config.Mcd##mcd, Mcd##mcd##Data, 128 * i + 0xa, 0x76); \
2565 * int rename(char *old, char *new);
2568 void psxBios_rename() { // 44
2575 PSXBIOS_LOG("psxBios_%s: %s,%s\n", biosB0n[0x44], Ra0, Ra1);
2580 if (pa0 != INVALID_PTR && pa1 != INVALID_PTR) {
2581 if (!strncmp(pa0, "bu00", 4) && !strncmp(pa1, "bu00", 4)) {
2585 if (!strncmp(pa0, "bu10", 4) && !strncmp(pa1, "bu10", 4)) {
2594 #define budelete(mcd) { \
2595 for (i=1; i<16; i++) { \
2596 ptr = Mcd##mcd##Data + 128 * i; \
2597 if ((*ptr & 0xF0) != 0x50) continue; \
2598 if (strcmp(Ra0+5, ptr+0xa)) continue; \
2599 *ptr = (*ptr & 0xf) | 0xA0; \
2600 SaveMcd(Config.Mcd##mcd, Mcd##mcd##Data, 128 * i, 1); \
2601 PSXBIOS_LOG("delete %s\n", ptr+0xa); \
2608 * int delete(char *name);
2611 void psxBios_delete() { // 45
2617 PSXBIOS_LOG("psxBios_%s: %s\n", biosB0n[0x45], Ra0);
2622 if (pa0 != INVALID_PTR) {
2623 if (!strncmp(pa0, "bu00", 4)) {
2627 if (!strncmp(pa0, "bu10", 4)) {
2635 void psxBios_InitCARD() { // 4a
2636 u32 *ram32 = (u32 *)psxM;
2637 PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x4a], a0);
2638 write_chain(ram32 + A_PADCRD_CHN_E/4, 0, 0x49bc, 0x4a4c);
2639 // (maybe) todo: early_card_irq, FlushCache etc
2641 ram32[A_PAD_IRQR_ENA/4] = SWAP32(a0);
2643 mips_return_c(0, 300);
2646 void psxBios_StartCARD() { // 4b
2647 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x4b]);
2648 psxBios_SysDeqIntRP_(2, A_PADCRD_CHN_E);
2649 psxBios_SysEnqIntRP_(2, A_PADCRD_CHN_E);
2651 psxHwWrite16(0x1f801074, psxHu32(0x1074) | 1);
2652 storeRam32(A_PAD_ACK_VBL, 1);
2653 storeRam32(A_RCNT_VBL_ACK + (3 << 2), 0);
2654 storeRam32(A_CARD_IRQR_ENA, 1);
2655 psxRegs.CP0.n.SR |= 0x401;
2657 mips_return_c(1, 200);
2660 void psxBios_StopCARD() { // 4c
2661 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x4c]);
2662 storeRam32(A_RCNT_VBL_ACK + (3 << 2), 1);
2663 psxBios_SysDeqIntRP_(2, A_PADCRD_CHN_E);
2664 storeRam32(A_CARD_IRQR_ENA, 0);
2665 psxRegs.CP0.n.SR |= 0x401;
2666 mips_return_void_c(200);
2669 void psxBios__card_write() { // 0x4e
2674 PSXBIOS_LOG("psxBios_%s: %x,%x,%x\n", biosB0n[0x4e], a0, a1, a2);
2677 Function also accepts sector 400h (a bug).
2678 But notaz said we shouldn't allow sector 400h because it can corrupt the emulator.
2682 /* Invalid sectors */
2686 card_active_chan = a0;
2689 if (pa2 != INVALID_PTR) {
2691 memcpy(Mcd1Data + a1 * 128, pa2, 128);
2692 SaveMcd(Config.Mcd1, Mcd1Data, a1 * 128, 128);
2694 memcpy(Mcd2Data + a1 * 128, pa2, 128);
2695 SaveMcd(Config.Mcd2, Mcd2Data, a1 * 128, 128);
2699 DeliverEvent(0xf0000011, 0x0004);
2700 // DeliverEvent(0xf4000001, 0x0004);
2705 void psxBios__card_read() { // 0x4f
2710 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x4f]);
2713 Function also accepts sector 400h (a bug).
2714 But notaz said we shouldn't allow sector 400h because it can corrupt the emulator.
2718 /* Invalid sectors */
2722 card_active_chan = a0;
2725 if (pa2 != INVALID_PTR) {
2727 memcpy(pa2, Mcd1Data + a1 * 128, 128);
2729 memcpy(pa2, Mcd2Data + a1 * 128, 128);
2733 DeliverEvent(0xf0000011, 0x0004);
2734 // DeliverEvent(0xf4000001, 0x0004);
2739 void psxBios__new_card() { // 0x50
2741 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x50]);
2747 /* According to a user, this allows Final Fantasy Tactics to save/load properly */
2748 void psxBios__get_error(void) // 55
2750 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x55]);
2755 void psxBios_Krom2RawAdd() { // 0x51
2758 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x51]);
2759 const u32 table_8140[][2] = {
2760 {0x8140, 0x0000}, {0x8180, 0x0762}, {0x81ad, 0x0cc6}, {0x81b8, 0x0ca8},
2761 {0x81c0, 0x0f00}, {0x81c8, 0x0d98}, {0x81cf, 0x10c2}, {0x81da, 0x0e6a},
2762 {0x81e9, 0x13ce}, {0x81f0, 0x102c}, {0x81f8, 0x1590}, {0x81fc, 0x111c},
2763 {0x81fd, 0x1626}, {0x824f, 0x113a}, {0x8259, 0x20ee}, {0x8260, 0x1266},
2764 {0x827a, 0x24cc}, {0x8281, 0x1572}, {0x829b, 0x28aa}, {0x829f, 0x187e},
2765 {0x82f2, 0x32dc}, {0x8340, 0x2238}, {0x837f, 0x4362}, {0x8380, 0x299a},
2766 {0x8397, 0x4632}, {0x839f, 0x2c4c}, {0x83b7, 0x49f2}, {0x83bf, 0x2f1c},
2767 {0x83d7, 0x4db2}, {0x8440, 0x31ec}, {0x8461, 0x5dde}, {0x8470, 0x35ca},
2768 {0x847f, 0x6162}, {0x8480, 0x378c}, {0x8492, 0x639c}, {0x849f, 0x39a8},
2772 const u32 table_889f[][2] = {
2773 {0x889f, 0x3d68}, {0x8900, 0x40ec}, {0x897f, 0x4fb0}, {0x8a00, 0x56f4},
2774 {0x8a7f, 0x65b8}, {0x8b00, 0x6cfc}, {0x8b7f, 0x7bc0}, {0x8c00, 0x8304},
2775 {0x8c7f, 0x91c8}, {0x8d00, 0x990c}, {0x8d7f, 0xa7d0}, {0x8e00, 0xaf14},
2776 {0x8e7f, 0xbdd8}, {0x8f00, 0xc51c}, {0x8f7f, 0xd3e0}, {0x9000, 0xdb24},
2777 {0x907f, 0xe9e8}, {0x9100, 0xf12c}, {0x917f, 0xfff0}, {0x9200, 0x10734},
2778 {0x927f, 0x115f8}, {0x9300, 0x11d3c}, {0x937f, 0x12c00}, {0x9400, 0x13344},
2779 {0x947f, 0x14208}, {0x9500, 0x1494c}, {0x957f, 0x15810}, {0x9600, 0x15f54},
2780 {0x967f, 0x16e18}, {0x9700, 0x1755c}, {0x977f, 0x18420}, {0x9800, 0x18b64},
2784 if (a0 >= 0x8140 && a0 <= 0x84be) {
2785 while (table_8140[i][0] <= a0) i++;
2786 a0 -= table_8140[i - 1][0];
2787 v0 = 0xbfc66000 + (a0 * 0x1e + table_8140[i - 1][1]);
2788 } else if (a0 >= 0x889f && a0 <= 0x9872) {
2789 while (table_889f[i][0] <= a0) i++;
2790 a0 -= table_889f[i - 1][0];
2791 v0 = 0xbfc66000 + (a0 * 0x1e + table_889f[i - 1][1]);
2799 void psxBios_GetC0Table() { // 56
2800 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x56]);
2801 log_unhandled("GetC0Table @%08x\n", ra);
2803 mips_return_c(A_C0_TABLE, 3);
2806 void psxBios_GetB0Table() { // 57
2807 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x57]);
2808 log_unhandled("GetB0Table @%08x\n", ra);
2810 mips_return_c(A_B0_TABLE, 3);
2813 void psxBios__card_chan() { // 0x58
2815 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x58]);
2818 v0 = card_active_chan;
2822 static void psxBios_ChangeClearPad() { // 5b
2824 PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x5b], a0);
2825 ret = loadRam32(A_PAD_ACK_VBL);
2826 storeRam32(A_PAD_ACK_VBL, a0);
2828 mips_return_c(ret, 6);
2831 void psxBios__card_status() { // 5c
2833 PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x5c], a0);
2836 v0 = card_active_chan;
2840 void psxBios__card_wait() { // 5d
2842 PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x5d], a0);
2849 /* System calls C0 */
2851 static void psxBios_InitRCnt() { // 00
2853 PSXBIOS_LOG("psxBios_%s %x\n", biosC0n[0x00], a0);
2854 psxHwWrite16(0x1f801074, psxHu32(0x1074) & ~0x71);
2855 for (i = 0; i < 3; i++) {
2856 psxHwWrite16(0x1f801100 + i*0x10 + 4, 0);
2857 psxHwWrite16(0x1f801100 + i*0x10 + 8, 0);
2858 psxHwWrite16(0x1f801100 + i*0x10 + 0, 0);
2860 psxBios_SysEnqIntRP_(a0, 0x6d88);
2861 mips_return_c(0, 9);
2864 static void psxBios_InitException() { // 01
2865 PSXBIOS_LOG("psxBios_%s %x\n", biosC0n[0x01], a0);
2866 psxBios_SysEnqIntRP_(a0, 0x6da8);
2867 mips_return_c(0, 9);
2871 * int SysEnqIntRP(int index , long *queue);
2874 static void psxBios_SysEnqIntRP_(u32 priority, u32 chain_eptr) {
2875 u32 old, base = loadRam32(A_TT_ExCB);
2877 old = loadRam32(base + (priority << 3));
2878 storeRam32(base + (priority << 3), chain_eptr);
2879 storeRam32(chain_eptr, old);
2880 mips_return_c(0, 9);
2883 static void psxBios_SysEnqIntRP() { // 02
2884 PSXBIOS_LOG("psxBios_%s %x %x\n", biosC0n[0x02], a0, a1);
2885 psxBios_SysEnqIntRP_(a0, a1);
2889 * int SysDeqIntRP(int index , long *queue);
2892 static void psxBios_SysDeqIntRP_(u32 priority, u32 chain_rm_eptr) {
2893 u32 ptr, next, base = loadRam32(A_TT_ExCB);
2894 u32 lim = 0, ret = 0;
2896 // as in original: no arg checks of any kind, bug if a1 == 0
2897 ptr = loadRam32(base + (priority << 3));
2899 next = loadRam32(ptr);
2900 if (ptr == chain_rm_eptr) {
2901 storeRam32(base + (priority << 3), next);
2906 while (next && next != chain_rm_eptr && lim++ < 100) {
2908 next = loadRam32(ptr);
2911 if (next == chain_rm_eptr) {
2912 next = loadRam32(next);
2913 storeRam32(ptr, next);
2920 PSXBIOS_LOG("bad chain %u %x\n", priority, base);
2922 mips_return_c(ret, 12);
2925 static void psxBios_SysDeqIntRP() { // 03
2926 PSXBIOS_LOG("psxBios_%s %x %x\n", biosC0n[0x03], a0, a1);
2927 psxBios_SysDeqIntRP_(a0, a1);
2930 static void psxBios_get_free_EvCB_slot() { // 04
2931 PSXBIOS_LOG("psxBios_%s\n", biosC0n[0x04]);
2932 s32 ret = get_free_EvCB_slot();
2933 mips_return_c(ret, 0);
2936 static void psxBios_SysInitMemory_(u32 base, u32 size) {
2937 storeRam32(base, 0);
2938 storeRam32(A_KMALLOC_PTR, base);
2939 storeRam32(A_KMALLOC_SIZE, size);
2940 storeRam32(A_KMALLOC_END, base + (size & ~3) + 4);
2943 // this should be much more complicated, but maybe that'll be enough
2944 static u32 psxBios_SysMalloc_(u32 size) {
2945 u32 ptr = loadRam32(A_KMALLOC_PTR);
2947 size = (size + 3) & ~3;
2948 storeRam32(A_KMALLOC_PTR, ptr + 4 + size);
2949 storeRam32(ptr, size);
2953 static void psxBios_SysInitMemory() { // 08
2954 PSXBIOS_LOG("psxBios_%s %x %x\n", biosC0n[0x08], a0, a1);
2956 psxBios_SysInitMemory_(a0, a1);
2957 mips_return_void_c(12);
2960 static void psxBios_ChangeClearRCnt() { // 0a
2963 PSXBIOS_LOG("psxBios_%s: %x, %x\n", biosC0n[0x0a], a0, a1);
2965 ret = loadRam32(A_RCNT_VBL_ACK + (a0 << 2));
2966 storeRam32(A_RCNT_VBL_ACK + (a0 << 2), a1);
2967 mips_return_c(ret, 8);
2970 static void psxBios_InitDefInt() { // 0c
2971 PSXBIOS_LOG("psxBios_%s %x\n", biosC0n[0x0c], a0);
2972 // should also clear the autoack table
2973 psxBios_SysEnqIntRP_(a0, 0x6d98);
2974 mips_return_c(0, 20 + 6*2);
2977 void psxBios_dummy() {
2978 u32 pc = (pc0 & 0x1fffff) - 4;
2979 char **ntab = pc == 0xa0 ? biosA0n : pc == 0xb0 ? biosB0n
2980 : pc == 0xc0 ? biosC0n : NULL;
2981 PSXBIOS_LOG("unk %x call: %x ra=%x (%s)\n",
2982 pc, t1, ra, ntab ? ntab[t1 & 0xff] : "???");
2983 (void)pc; (void)ntab;
2984 mips_return_c(0, 100);
2987 void (*biosA0[256])();
2988 // C0 and B0 overlap (end of C0 is start of B0)
2989 void (*biosC0[256+128])();
2990 void (**biosB0)() = biosC0 + 128;
2992 static void setup_mips_code()
2995 ptr = (u32 *)&psxM[A_SYSCALL];
2996 ptr[0x00/4] = SWAPu32(0x0000000c); // syscall 0
2997 ptr[0x04/4] = SWAPu32(0x03e00008); // jr $ra
2998 ptr[0x08/4] = SWAPu32(0x00000000); // nop
3000 ptr = (u32 *)&psxM[A_EXCEPTION];
3001 memset(ptr, 0, 0xc0); // nops (to be patched by games sometimes)
3002 ptr[0x10/4] = SWAPu32(0x8c1a0108); // lw $k0, (0x108) // PCB
3003 ptr[0x14/4] = SWAPu32(0x00000000); // nop
3004 ptr[0x18/4] = SWAPu32(0x8f5a0000); // lw $k0, ($k0) // TCB
3005 ptr[0x1c/4] = SWAPu32(0x00000000); // nop
3006 ptr[0x20/4] = SWAPu32(0x275a0008); // addiu $k0, $k0, 8 // regs
3007 ptr[0x24/4] = SWAPu32(0xaf5f007c); // sw $ra, 0x7c($k0)
3008 ptr[0x28/4] = SWAPu32(0xaf410004); // sw $at, 0x04($k0)
3009 ptr[0x2c/4] = SWAPu32(0xaf420008); // sw $v0, 0x08($k0)
3010 ptr[0x30/4] = SWAPu32(0xaf43000c); // sw $v1, 0x0c($k0)
3012 ptr[0x60/4] = SWAPu32(0x40037000); // mfc0 $v1, EPC
3013 ptr[0x64/4] = SWAPu32(0x40026800); // mfc0 $v0, Cause
3014 ptr[0x6c/4] = SWAPu32(0xaf430080); // sw $v1, 0x80($k0)
3016 ptr[0xb0/4] = HLEOP(hleop_exception);
3019 static const struct {
3023 { 0xbfc050a4, hleop_exc0_0_1 },
3024 { 0xbfc04fbc, hleop_exc0_0_2 },
3025 { 0xbfc0506c, hleop_exc0_1_1 },
3026 { 0xbfc04dec, hleop_exc0_1_2 },
3027 { 0x1a00, hleop_exc0_2_2 },
3028 { 0x19c8, hleop_exc1_0_1 },
3029 { 0x18bc, hleop_exc1_0_2 },
3030 { 0x1990, hleop_exc1_1_1 },
3031 { 0x1858, hleop_exc1_1_2 },
3032 { 0x1958, hleop_exc1_2_1 },
3033 { 0x17f4, hleop_exc1_2_2 },
3034 { 0x1920, hleop_exc1_3_1 },
3035 { 0x1794, hleop_exc1_3_2 },
3036 { 0x2458, hleop_exc3_0_2 },
3037 { 0x49bc, hleop_exc_padcard1 },
3038 { 0x4a4c, hleop_exc_padcard2 },
3041 static int chain_hle_op(u32 handler)
3045 for (i = 0; i < sizeof(chainfns) / sizeof(chainfns[0]); i++)
3046 if (chainfns[i].addr == handler)
3047 return chainfns[i].op;
3051 static void write_chain(u32 *d, u32 next, u32 handler1, u32 handler2)
3053 d[0] = SWAPu32(next);
3054 d[1] = SWAPu32(handler1);
3055 d[2] = SWAPu32(handler2);
3057 // install the hle traps
3058 PSXMu32ref(handler1) = HLEOP(chain_hle_op(handler1));
3059 PSXMu32ref(handler2) = HLEOP(chain_hle_op(handler2));
3062 static void setup_tt(u32 tcb_cnt, u32 evcb_cnt)
3064 u32 *ram32 = (u32 *)psxM;
3065 u32 s_excb = 0x20, s_evcb = 0x1c * evcb_cnt;
3066 u32 s_pcb = 4, s_tcb = 0xc0 * tcb_cnt;
3067 u32 p_excb, p_evcb, p_pcb, p_tcb;
3069 memset(ram32 + 0xe000/4, 0, s_excb + s_evcb + s_pcb + s_tcb + 5*4);
3070 psxBios_SysInitMemory_(0xa000e000, 0x2000);
3071 p_excb = psxBios_SysMalloc_(s_excb);
3072 p_evcb = psxBios_SysMalloc_(s_evcb);
3073 p_pcb = psxBios_SysMalloc_(s_pcb);
3074 p_tcb = psxBios_SysMalloc_(s_tcb);
3076 // "table of tables". Some games modify it
3077 assert(A_TT_ExCB == 0x0100);
3078 ram32[0x0100/4] = SWAPu32(p_excb); // ExCB - exception chains
3079 ram32[0x0104/4] = SWAPu32(s_excb); // ExCB size
3080 ram32[0x0108/4] = SWAPu32(p_pcb); // PCB - process control
3081 ram32[0x010c/4] = SWAPu32(s_pcb); // PCB size
3082 ram32[0x0110/4] = SWAPu32(p_tcb); // TCB - thread control
3083 ram32[0x0114/4] = SWAPu32(s_tcb); // TCB size
3084 ram32[0x0120/4] = SWAPu32(p_evcb); // EvCB - event control
3085 ram32[0x0124/4] = SWAPu32(s_evcb); // EvCB size
3086 ram32[0x0140/4] = SWAPu32(0x8648); // FCB - file control
3087 ram32[0x0144/4] = SWAPu32(0x02c0); // FCB size
3088 ram32[0x0150/4] = SWAPu32(0x6ee0); // DCB - device control
3089 ram32[0x0154/4] = SWAPu32(0x0320); // DCB size
3091 storeRam32(p_excb + 0*4, 0x91e0); // chain0
3092 storeRam32(p_excb + 2*4, 0x6d88); // chain1
3093 storeRam32(p_excb + 4*4, 0x0000); // chain2
3094 storeRam32(p_excb + 6*4, 0x6d98); // chain3
3096 storeRam32(p_pcb, p_tcb);
3097 storeRam32(p_tcb, 0x4000); // first TCB
3100 storeRam32(A_CD_EVENTS + 0x00, OpenEvent(0xf0000003, 0x0010, EvMdMARK, 0));
3101 storeRam32(A_CD_EVENTS + 0x04, OpenEvent(0xf0000003, 0x0020, EvMdMARK, 0));
3102 storeRam32(A_CD_EVENTS + 0x08, OpenEvent(0xf0000003, 0x0040, EvMdMARK, 0));
3103 storeRam32(A_CD_EVENTS + 0x0c, OpenEvent(0xf0000003, 0x0080, EvMdMARK, 0));
3104 storeRam32(A_CD_EVENTS + 0x10, OpenEvent(0xf0000003, 0x8000, EvMdMARK, 0));
3105 DeliverEvent(0xf0000003, 0x0010);
3108 static const u32 gpu_ctl_def[] = {
3109 0x00000000, 0x01000000, 0x03000000, 0x04000000,
3110 0x05000800, 0x06c60260, 0x0703fc10, 0x08000027
3113 static const u32 gpu_data_def[] = {
3114 0xe100360b, 0xe2000000, 0xe3000800, 0xe4077e7f,
3115 0xe5001000, 0xe6000000,
3116 0x02000000, 0x00000000, 0x01ff03ff
3120 static const u16 spu_config[] = {
3121 0x3fff, 0x37ef, 0x5ebc, 0x5ebc, 0x0000, 0x0000, 0x0000, 0x00a0,
3122 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0x00ff, 0x0000, 0x0000,
3123 0x0000, 0xe128, 0x0000, 0x0200, 0xf0f0, 0xc085, 0x0004, 0x0000,
3124 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
3125 0x033d, 0x0231, 0x7e00, 0x5000, 0xb400, 0xb000, 0x4c00, 0xb000,
3126 0x6000, 0x5400, 0x1ed6, 0x1a31, 0x1d14, 0x183b, 0x1bc2, 0x16b2,
3127 0x1a32, 0x15ef, 0x15ee, 0x1055, 0x1334, 0x0f2d, 0x11f6, 0x0c5d,
3128 0x1056, 0x0ae1, 0x0ae0, 0x07a2, 0x0464, 0x0232, 0x8000, 0x8000
3131 void psxBiosSetupBootState(void)
3133 boolean hle = Config.HLE;
3134 u32 *hw = (u32 *)psxH;
3137 // see also SetBootRegs()
3140 a0 = 1; a2 = a3 = 0; a3 = 0x2a;
3141 t2 = 0x2d; t4 = 0x23; t5 = 0x2b; t6 = 0xa0010000;
3143 k0 = 0xbfc0d968; k1 = 0xf1c;
3144 ra = 0xf0001234; // just to easily detect attempts to return
3145 psxRegs.CP0.n.Cause = 0x20;
3146 psxRegs.CP0.n.EPC = 0xbfc0d964; // EnterCriticalSection syscall
3148 hw[0x1000/4] = SWAP32(0x1f000000);
3149 hw[0x1004/4] = SWAP32(0x1f802000);
3150 hw[0x1008/4] = SWAP32(0x0013243f);
3151 hw[0x100c/4] = SWAP32(0x00003022);
3152 hw[0x1010/4] = SWAP32(0x0013243f);
3153 hw[0x1014/4] = SWAP32(0x200931e1);
3154 hw[0x1018/4] = SWAP32(0x00020943);
3155 hw[0x101c/4] = SWAP32(0x00070777);
3156 hw[0x1020/4] = SWAP32(0x0000132c);
3157 hw[0x1060/4] = SWAP32(0x00000b88);
3158 hw[0x1070/4] = SWAP32(0x00000001);
3159 hw[0x1074/4] = SWAP32(0x0000000c);
3160 hw[0x2040/4] = SWAP32(0x00000900);
3163 hw[0x10a0/4] = SWAP32(0x00ffffff);
3164 hw[0x10a8/4] = SWAP32(0x00000401);
3165 hw[0x10b0/4] = SWAP32(0x0008b000);
3166 hw[0x10b4/4] = SWAP32(0x00010200);
3167 hw[0x10e0/4] = SWAP32(0x000eccf4);
3168 hw[0x10e4/4] = SWAP32(0x00000400);
3169 hw[0x10e8/4] = SWAP32(0x00000002);
3170 hw[0x10f0/4] = SWAP32(0x00009099);
3171 hw[0x10f4/4] = SWAP32(0x8c8c0000);
3180 for (i = 0; i < sizeof(gpu_ctl_def) / sizeof(gpu_ctl_def[0]); i++)
3181 GPU_writeStatus(gpu_ctl_def[i]);
3182 for (i = 0; i < sizeof(gpu_data_def) / sizeof(gpu_data_def[0]); i++)
3183 GPU_writeData(gpu_data_def[i]);
3184 HW_GPU_STATUS |= SWAP32(PSXGPU_nBUSY);
3187 for (i = 0x1f801d80; i < sizeof(spu_config) / sizeof(spu_config[0]); i++)
3188 SPU_writeRegister(0x1f801d80 + i*2, spu_config[i], psxRegs.cycle);
3191 #include "sjisfont.h"
3193 void psxBiosInit() {
3194 u32 *ptr, *ram32, *rom32;
3198 memset(psxM, 0, 0x10000);
3199 for(i = 0; i < 256; i++) {
3204 biosA0[0x03] = biosB0[0x35] = psxBios_write_psxout;
3205 biosA0[0x3c] = biosB0[0x3d] = psxBios_putchar_psxout;
3206 biosA0[0x3e] = biosB0[0x3f] = psxBios_puts_psxout;
3207 biosA0[0x3f] = psxBios_printf_psxout;
3209 if (!Config.HLE) return;
3211 for(i = 0; i < 256; i++) {
3212 if (biosA0[i] == NULL) biosA0[i] = psxBios_dummy;
3213 if (biosB0[i] == NULL) biosB0[i] = psxBios_dummy;
3214 if (biosC0[i] == NULL) biosC0[i] = psxBios_dummy;
3217 biosA0[0x00] = psxBios_open;
3218 biosA0[0x01] = psxBios_lseek;
3219 biosA0[0x02] = psxBios_read;
3220 biosA0[0x03] = psxBios_write;
3221 biosA0[0x04] = psxBios_close;
3222 //biosA0[0x05] = psxBios_ioctl;
3223 //biosA0[0x06] = psxBios_exit;
3224 //biosA0[0x07] = psxBios_sys_a0_07;
3225 biosA0[0x08] = psxBios_getc;
3226 biosA0[0x09] = psxBios_putc;
3227 biosA0[0x0a] = psxBios_todigit;
3228 //biosA0[0x0b] = psxBios_atof;
3229 //biosA0[0x0c] = psxBios_strtoul;
3230 //biosA0[0x0d] = psxBios_strtol;
3231 biosA0[0x0e] = psxBios_abs;
3232 biosA0[0x0f] = psxBios_labs;
3233 biosA0[0x10] = psxBios_atoi;
3234 biosA0[0x11] = psxBios_atol;
3235 //biosA0[0x12] = psxBios_atob;
3236 biosA0[0x13] = psxBios_setjmp;
3237 biosA0[0x14] = psxBios_longjmp;
3238 biosA0[0x15] = psxBios_strcat;
3239 biosA0[0x16] = psxBios_strncat;
3240 biosA0[0x17] = psxBios_strcmp;
3241 biosA0[0x18] = psxBios_strncmp;
3242 biosA0[0x19] = psxBios_strcpy;
3243 biosA0[0x1a] = psxBios_strncpy;
3244 biosA0[0x1b] = psxBios_strlen;
3245 biosA0[0x1c] = psxBios_index;
3246 biosA0[0x1d] = psxBios_rindex;
3247 biosA0[0x1e] = psxBios_strchr;
3248 biosA0[0x1f] = psxBios_strrchr;
3249 biosA0[0x20] = psxBios_strpbrk;
3250 biosA0[0x21] = psxBios_strspn;
3251 biosA0[0x22] = psxBios_strcspn;
3252 biosA0[0x23] = psxBios_strtok;
3253 biosA0[0x24] = psxBios_strstr;
3254 biosA0[0x25] = psxBios_toupper;
3255 biosA0[0x26] = psxBios_tolower;
3256 biosA0[0x27] = psxBios_bcopy;
3257 biosA0[0x28] = psxBios_bzero;
3258 biosA0[0x29] = psxBios_bcmp;
3259 biosA0[0x2a] = psxBios_memcpy;
3260 biosA0[0x2b] = psxBios_memset;
3261 biosA0[0x2c] = psxBios_memmove;
3262 biosA0[0x2d] = psxBios_memcmp;
3263 biosA0[0x2e] = psxBios_memchr;
3264 biosA0[0x2f] = psxBios_rand;
3265 biosA0[0x30] = psxBios_srand;
3266 biosA0[0x31] = psxBios_qsort;
3267 //biosA0[0x32] = psxBios_strtod;
3268 biosA0[0x33] = psxBios_malloc;
3269 biosA0[0x34] = psxBios_free;
3270 //biosA0[0x35] = psxBios_lsearch;
3271 //biosA0[0x36] = psxBios_bsearch;
3272 biosA0[0x37] = psxBios_calloc;
3273 biosA0[0x38] = psxBios_realloc;
3274 biosA0[0x39] = psxBios_InitHeap;
3275 //biosA0[0x3a] = psxBios__exit;
3276 biosA0[0x3b] = psxBios_getchar;
3277 biosA0[0x3c] = psxBios_putchar;
3278 //biosA0[0x3d] = psxBios_gets;
3279 biosA0[0x3e] = psxBios_puts;
3280 biosA0[0x3f] = psxBios_printf;
3281 biosA0[0x40] = psxBios_SystemErrorUnresolvedException;
3282 //biosA0[0x41] = psxBios_LoadTest;
3283 biosA0[0x42] = psxBios_Load;
3284 biosA0[0x43] = psxBios_Exec;
3285 biosA0[0x44] = psxBios_FlushCache;
3286 //biosA0[0x45] = psxBios_InstallInterruptHandler;
3287 biosA0[0x46] = psxBios_GPU_dw;
3288 biosA0[0x47] = psxBios_mem2vram;
3289 biosA0[0x48] = psxBios_SendGPU;
3290 biosA0[0x49] = psxBios_GPU_cw;
3291 biosA0[0x4a] = psxBios_GPU_cwb;
3292 biosA0[0x4b] = psxBios_GPU_SendPackets;
3293 biosA0[0x4c] = psxBios_sys_a0_4c;
3294 biosA0[0x4d] = psxBios_GPU_GetGPUStatus;
3295 //biosA0[0x4e] = psxBios_GPU_sync;
3296 //biosA0[0x4f] = psxBios_sys_a0_4f;
3297 //biosA0[0x50] = psxBios_sys_a0_50;
3298 biosA0[0x51] = psxBios_LoadExec;
3299 //biosA0[0x52] = psxBios_GetSysSp;
3300 //biosA0[0x53] = psxBios_sys_a0_53;
3301 //biosA0[0x54] = psxBios__96_init_a54;
3302 //biosA0[0x55] = psxBios__bu_init_a55;
3303 biosA0[0x56] = psxBios_CdRemove;
3304 //biosA0[0x57] = psxBios_sys_a0_57;
3305 //biosA0[0x58] = psxBios_sys_a0_58;
3306 //biosA0[0x59] = psxBios_sys_a0_59;
3307 //biosA0[0x5a] = psxBios_sys_a0_5a;
3308 //biosA0[0x5b] = psxBios_dev_tty_init;
3309 //biosA0[0x5c] = psxBios_dev_tty_open;
3310 //biosA0[0x5d] = psxBios_sys_a0_5d;
3311 //biosA0[0x5e] = psxBios_dev_tty_ioctl;
3312 //biosA0[0x5f] = psxBios_dev_cd_open;
3313 //biosA0[0x60] = psxBios_dev_cd_read;
3314 //biosA0[0x61] = psxBios_dev_cd_close;
3315 //biosA0[0x62] = psxBios_dev_cd_firstfile;
3316 //biosA0[0x63] = psxBios_dev_cd_nextfile;
3317 //biosA0[0x64] = psxBios_dev_cd_chdir;
3318 //biosA0[0x65] = psxBios_dev_card_open;
3319 //biosA0[0x66] = psxBios_dev_card_read;
3320 //biosA0[0x67] = psxBios_dev_card_write;
3321 //biosA0[0x68] = psxBios_dev_card_close;
3322 //biosA0[0x69] = psxBios_dev_card_firstfile;
3323 //biosA0[0x6a] = psxBios_dev_card_nextfile;
3324 //biosA0[0x6b] = psxBios_dev_card_erase;
3325 //biosA0[0x6c] = psxBios_dev_card_undelete;
3326 //biosA0[0x6d] = psxBios_dev_card_format;
3327 //biosA0[0x6e] = psxBios_dev_card_rename;
3328 //biosA0[0x6f] = psxBios_dev_card_6f;
3329 biosA0[0x70] = psxBios__bu_init;
3330 biosA0[0x71] = psxBios__96_init;
3331 biosA0[0x72] = psxBios_CdRemove;
3332 //biosA0[0x73] = psxBios_sys_a0_73;
3333 //biosA0[0x74] = psxBios_sys_a0_74;
3334 //biosA0[0x75] = psxBios_sys_a0_75;
3335 //biosA0[0x76] = psxBios_sys_a0_76;
3336 //biosA0[0x77] = psxBios_sys_a0_77;
3337 //biosA0[0x78] = psxBios__96_CdSeekL;
3338 //biosA0[0x79] = psxBios_sys_a0_79;
3339 //biosA0[0x7a] = psxBios_sys_a0_7a;
3340 //biosA0[0x7b] = psxBios_sys_a0_7b;
3341 //biosA0[0x7c] = psxBios__96_CdGetStatus;
3342 //biosA0[0x7d] = psxBios_sys_a0_7d;
3343 //biosA0[0x7e] = psxBios__96_CdRead;
3344 //biosA0[0x7f] = psxBios_sys_a0_7f;
3345 //biosA0[0x80] = psxBios_sys_a0_80;
3346 //biosA0[0x81] = psxBios_sys_a0_81;
3347 //biosA0[0x82] = psxBios_sys_a0_82;
3348 //biosA0[0x83] = psxBios_sys_a0_83;
3349 //biosA0[0x84] = psxBios_sys_a0_84;
3350 //biosA0[0x85] = psxBios__96_CdStop;
3351 //biosA0[0x86] = psxBios_sys_a0_86;
3352 //biosA0[0x87] = psxBios_sys_a0_87;
3353 //biosA0[0x88] = psxBios_sys_a0_88;
3354 //biosA0[0x89] = psxBios_sys_a0_89;
3355 //biosA0[0x8a] = psxBios_sys_a0_8a;
3356 //biosA0[0x8b] = psxBios_sys_a0_8b;
3357 //biosA0[0x8c] = psxBios_sys_a0_8c;
3358 //biosA0[0x8d] = psxBios_sys_a0_8d;
3359 //biosA0[0x8e] = psxBios_sys_a0_8e;
3360 //biosA0[0x8f] = psxBios_sys_a0_8f;
3361 biosA0[0x90] = hleExc0_1_2;
3362 biosA0[0x91] = hleExc0_0_2;
3363 biosA0[0x92] = hleExc0_1_1;
3364 biosA0[0x93] = hleExc0_0_1;
3365 //biosA0[0x94] = psxBios_sys_a0_94;
3366 //biosA0[0x95] = psxBios_sys_a0_95;
3367 //biosA0[0x96] = psxBios_AddCDROMDevice;
3368 //biosA0[0x97] = psxBios_AddMemCardDevide;
3369 //biosA0[0x98] = psxBios_DisableKernelIORedirection;
3370 //biosA0[0x99] = psxBios_EnableKernelIORedirection;
3371 //biosA0[0x9a] = psxBios_sys_a0_9a;
3372 //biosA0[0x9b] = psxBios_sys_a0_9b;
3373 //biosA0[0x9c] = psxBios_SetConf;
3374 //biosA0[0x9d] = psxBios_GetConf;
3375 //biosA0[0x9e] = psxBios_sys_a0_9e;
3376 biosA0[0x9f] = psxBios_SetMem;
3377 //biosA0[0xa0] = psxBios__boot;
3378 //biosA0[0xa1] = psxBios_SystemError;
3379 //biosA0[0xa2] = psxBios_EnqueueCdIntr;
3380 biosA0[0xa3] = psxBios_DequeueCdIntr;
3381 //biosA0[0xa4] = psxBios_sys_a0_a4;
3382 //biosA0[0xa5] = psxBios_ReadSector;
3383 biosA0[0xa6] = psxBios_get_cd_status;
3384 //biosA0[0xa7] = psxBios_bufs_cb_0;
3385 //biosA0[0xa8] = psxBios_bufs_cb_1;
3386 //biosA0[0xa9] = psxBios_bufs_cb_2;
3387 //biosA0[0xaa] = psxBios_bufs_cb_3;
3388 biosA0[0xab] = psxBios__card_info;
3389 biosA0[0xac] = psxBios__card_load;
3390 //biosA0[0axd] = psxBios__card_auto;
3391 //biosA0[0xae] = psxBios_bufs_cd_4;
3392 //biosA0[0xaf] = psxBios_sys_a0_af;
3393 //biosA0[0xb0] = psxBios_sys_a0_b0;
3394 //biosA0[0xb1] = psxBios_sys_a0_b1;
3395 //biosA0[0xb2] = psxBios_do_a_long_jmp
3396 //biosA0[0xb3] = psxBios_sys_a0_b3;
3397 biosA0[0xb4] = psxBios_GetSystemInfo;
3398 //*******************B0 CALLS****************************
3399 biosB0[0x00] = psxBios_SysMalloc;
3400 //biosB0[0x01] = psxBios_sys_b0_01;
3401 biosB0[0x02] = psxBios_SetRCnt;
3402 biosB0[0x03] = psxBios_GetRCnt;
3403 biosB0[0x04] = psxBios_StartRCnt;
3404 biosB0[0x05] = psxBios_StopRCnt;
3405 biosB0[0x06] = psxBios_ResetRCnt;
3406 biosB0[0x07] = psxBios_DeliverEvent;
3407 biosB0[0x08] = psxBios_OpenEvent;
3408 biosB0[0x09] = psxBios_CloseEvent;
3409 biosB0[0x0a] = psxBios_WaitEvent;
3410 biosB0[0x0b] = psxBios_TestEvent;
3411 biosB0[0x0c] = psxBios_EnableEvent;
3412 biosB0[0x0d] = psxBios_DisableEvent;
3413 biosB0[0x0e] = psxBios_OpenTh;
3414 biosB0[0x0f] = psxBios_CloseTh;
3415 biosB0[0x10] = psxBios_ChangeTh;
3416 //biosB0[0x11] = psxBios_psxBios_b0_11;
3417 biosB0[0x12] = psxBios_InitPAD;
3418 biosB0[0x13] = psxBios_StartPAD;
3419 biosB0[0x14] = psxBios_StopPAD;
3420 biosB0[0x15] = psxBios_PAD_init;
3421 biosB0[0x16] = psxBios_PAD_dr;
3422 biosB0[0x17] = psxBios_ReturnFromException;
3423 biosB0[0x18] = psxBios_ResetEntryInt;
3424 biosB0[0x19] = psxBios_HookEntryInt;
3425 //biosB0[0x1a] = psxBios_sys_b0_1a;
3426 //biosB0[0x1b] = psxBios_sys_b0_1b;
3427 //biosB0[0x1c] = psxBios_sys_b0_1c;
3428 //biosB0[0x1d] = psxBios_sys_b0_1d;
3429 //biosB0[0x1e] = psxBios_sys_b0_1e;
3430 //biosB0[0x1f] = psxBios_sys_b0_1f;
3431 biosB0[0x20] = psxBios_UnDeliverEvent;
3432 //biosB0[0x21] = psxBios_sys_b0_21;
3433 //biosB0[0x22] = psxBios_sys_b0_22;
3434 //biosB0[0x23] = psxBios_sys_b0_23;
3435 //biosB0[0x24] = psxBios_sys_b0_24;
3436 //biosB0[0x25] = psxBios_sys_b0_25;
3437 //biosB0[0x26] = psxBios_sys_b0_26;
3438 //biosB0[0x27] = psxBios_sys_b0_27;
3439 //biosB0[0x28] = psxBios_sys_b0_28;
3440 //biosB0[0x29] = psxBios_sys_b0_29;
3441 //biosB0[0x2a] = psxBios_sys_b0_2a;
3442 //biosB0[0x2b] = psxBios_sys_b0_2b;
3443 //biosB0[0x2c] = psxBios_sys_b0_2c;
3444 //biosB0[0x2d] = psxBios_sys_b0_2d;
3445 //biosB0[0x2e] = psxBios_sys_b0_2e;
3446 //biosB0[0x2f] = psxBios_sys_b0_2f;
3447 //biosB0[0x30] = psxBios_sys_b0_30;
3448 //biosB0[0x31] = psxBios_sys_b0_31;
3449 biosB0[0x32] = psxBios_open;
3450 biosB0[0x33] = psxBios_lseek;
3451 biosB0[0x34] = psxBios_read;
3452 biosB0[0x35] = psxBios_write;
3453 biosB0[0x36] = psxBios_close;
3454 //biosB0[0x37] = psxBios_ioctl;
3455 //biosB0[0x38] = psxBios_exit;
3456 //biosB0[0x39] = psxBios_sys_b0_39;
3457 //biosB0[0x3a] = psxBios_getc;
3458 //biosB0[0x3b] = psxBios_putc;
3459 biosB0[0x3c] = psxBios_getchar;
3460 biosB0[0x3d] = psxBios_putchar;
3461 //biosB0[0x3e] = psxBios_gets;
3462 biosB0[0x3f] = psxBios_puts;
3463 //biosB0[0x40] = psxBios_cd;
3464 biosB0[0x41] = psxBios_format;
3465 biosB0[0x42] = psxBios_firstfile;
3466 biosB0[0x43] = psxBios_nextfile;
3467 biosB0[0x44] = psxBios_rename;
3468 biosB0[0x45] = psxBios_delete;
3469 //biosB0[0x46] = psxBios_undelete;
3470 //biosB0[0x47] = psxBios_AddDevice;
3471 //biosB0[0x48] = psxBios_RemoteDevice;
3472 //biosB0[0x49] = psxBios_PrintInstalledDevices;
3473 biosB0[0x4a] = psxBios_InitCARD;
3474 biosB0[0x4b] = psxBios_StartCARD;
3475 biosB0[0x4c] = psxBios_StopCARD;
3476 //biosB0[0x4d] = psxBios_sys_b0_4d;
3477 biosB0[0x4e] = psxBios__card_write;
3478 biosB0[0x4f] = psxBios__card_read;
3479 biosB0[0x50] = psxBios__new_card;
3480 biosB0[0x51] = psxBios_Krom2RawAdd;
3481 //biosB0[0x52] = psxBios_sys_b0_52;
3482 //biosB0[0x53] = psxBios_sys_b0_53;
3483 //biosB0[0x54] = psxBios__get_errno;
3484 biosB0[0x55] = psxBios__get_error;
3485 biosB0[0x56] = psxBios_GetC0Table;
3486 biosB0[0x57] = psxBios_GetB0Table;
3487 biosB0[0x58] = psxBios__card_chan;
3488 //biosB0[0x59] = psxBios_sys_b0_59;
3489 //biosB0[0x5a] = psxBios_sys_b0_5a;
3490 biosB0[0x5b] = psxBios_ChangeClearPad;
3491 biosB0[0x5c] = psxBios__card_status;
3492 biosB0[0x5d] = psxBios__card_wait;
3493 //*******************C0 CALLS****************************
3494 biosC0[0x00] = psxBios_InitRCnt;
3495 biosC0[0x01] = psxBios_InitException;
3496 biosC0[0x02] = psxBios_SysEnqIntRP;
3497 biosC0[0x03] = psxBios_SysDeqIntRP;
3498 biosC0[0x04] = psxBios_get_free_EvCB_slot;
3499 //biosC0[0x05] = psxBios_get_free_TCB_slot;
3500 //biosC0[0x06] = psxBios_ExceptionHandler;
3501 //biosC0[0x07] = psxBios_InstallExeptionHandler;
3502 biosC0[0x08] = psxBios_SysInitMemory;
3503 //biosC0[0x09] = psxBios_SysInitKMem;
3504 biosC0[0x0a] = psxBios_ChangeClearRCnt;
3505 //biosC0[0x0b] = psxBios_SystemError;
3506 biosC0[0x0c] = psxBios_InitDefInt;
3507 //biosC0[0x0d] = psxBios_sys_c0_0d;
3508 //biosC0[0x0e] = psxBios_sys_c0_0e;
3509 //biosC0[0x0f] = psxBios_sys_c0_0f;
3510 //biosC0[0x10] = psxBios_sys_c0_10;
3511 //biosC0[0x11] = psxBios_sys_c0_11;
3512 //biosC0[0x12] = psxBios_InstallDevices;
3513 //biosC0[0x13] = psxBios_FlushStfInOutPut;
3514 //biosC0[0x14] = psxBios_sys_c0_14;
3515 //biosC0[0x15] = psxBios__cdevinput;
3516 //biosC0[0x16] = psxBios__cdevscan;
3517 //biosC0[0x17] = psxBios__circgetc;
3518 //biosC0[0x18] = psxBios__circputc;
3519 //biosC0[0x19] = psxBios_ioabort;
3520 //biosC0[0x1a] = psxBios_sys_c0_1a
3521 //biosC0[0x1b] = psxBios_KernelRedirect;
3522 //biosC0[0x1c] = psxBios_PatchAOTable;
3523 //************** THE END ***************************************
3529 memset(FDesc, 0, sizeof(FDesc));
3530 card_active_chan = 0;
3533 psxMu32ref(0x9010) = SWAPu32(0xac20cc00);
3535 // somewhat pretend to be a SCPH1001 BIOS
3536 // some games look for these and take an exception if they're missing
3537 rom32 = (u32 *)psxR;
3538 rom32[0x100/4] = SWAP32(0x19951204);
3539 rom32[0x104/4] = SWAP32(3);
3540 strcpy(psxR + 0x108, "PCSX authors");
3541 strcpy(psxR + 0x12c, "CEX-3000 PCSX HLE"); // see psxBios_GetSystemInfo
3542 strcpy(psxR + 0x7ff32, "System ROM Version 2.2 12/04/95 A");
3543 strcpy(psxR + 0x7ff54, "GPL-2.0-or-later");
3546 len = 0x80000 - 0x66000;
3547 uncompress((Bytef *)(psxR + 0x66000), &len, font_8140, sizeof(font_8140));
3548 len = 0x80000 - 0x69d68;
3549 uncompress((Bytef *)(psxR + 0x69d68), &len, font_889f, sizeof(font_889f));
3551 /* Some games like R-Types, CTR, Fade to Black read from adress 0x00000000 due to uninitialized pointers.
3552 See Garbage Area at Address 00000000h in Nocash PSX Specfications for more information.
3553 Here are some examples of games not working with this fix in place :
3554 R-type won't get past the Irem logo if not implemented.
3555 Crash Team Racing will softlock after the Sony logo.
3558 ram32 = (u32 *)psxM;
3559 ram32[0x0000/4] = SWAPu32(0x00000003); // lui $k0, 0 (overwritten by 3)
3560 ram32[0x0004/4] = SWAPu32(0x275a0000 + A_EXCEPTION); // addiu $k0, $k0, 0xc80
3561 ram32[0x0008/4] = SWAPu32(0x03400008); // jr $k0
3562 ram32[0x000c/4] = SWAPu32(0x00000000); // nop
3564 ram32[0x0060/4] = SWAPu32(0x00000002); // ram size?
3565 ram32[0x0068/4] = SWAPu32(0x000000ff); // unknown
3567 ram32[0x0080/4] = SWAPu32(0x3c1a0000); // lui $k0, 0 // exception vector
3568 ram32[0x0084/4] = SWAPu32(0x275a0000 + A_EXCEPTION); // addiu $k0, $k0, 0xc80
3569 ram32[0x0088/4] = SWAPu32(0x03400008); // jr $k0
3570 ram32[0x008c/4] = SWAPu32(0x00000000); // nop
3572 ram32[0x00a0/4] = HLEOP(hleop_a0);
3573 ram32[0x00b0/4] = HLEOP(hleop_b0);
3574 ram32[0x00c0/4] = HLEOP(hleop_c0);
3578 ram32[0x6ee0/4] = SWAPu32(0x0000eff0); // DCB
3579 strcpy((char *)&ram32[0xeff0/4], "bu");
3581 // default exception handler chains
3582 write_chain(&ram32[0x91e0/4], 0x91d0, 0xbfc050a4, 0xbfc04fbc); // chain0.e0
3583 write_chain(&ram32[0x91d0/4], 0x6da8, 0xbfc0506c, 0xbfc04dec); // chain0.e1
3584 write_chain(&ram32[0x6da8/4], 0, 0, 0x1a00); // chain0.e2
3585 write_chain(&ram32[0x6d88/4], 0x6d78, 0x19c8, 0x18bc); // chain1.e0
3586 write_chain(&ram32[0x6d78/4], 0x6d68, 0x1990, 0x1858); // chain1.e1
3587 write_chain(&ram32[0x6d68/4], 0x6d58, 0x1958, 0x17f4); // chain1.e2
3588 write_chain(&ram32[0x6d58/4], 0, 0x1920, 0x1794); // chain1.e3
3589 write_chain(&ram32[0x6d98/4], 0, 0, 0x2458); // chain3.e0
3593 // fill the api jumptables with fake entries as some games patch them
3594 // (or rather the funcs listed there)
3595 ptr = (u32 *)&psxM[A_A0_TABLE];
3596 for (i = 0; i < 256; i++)
3597 ptr[i] = SWAP32(0x1000);
3599 ptr = (u32 *)&psxM[A_B0_TABLE];
3600 for (i = 0; i < 256; i++)
3601 ptr[i] = SWAP32(0x2000);
3602 // B(5b) is special because games patch (sometimes even jump to)
3603 // code at fixed offsets from it, nocash lists offsets:
3604 // patch: +3d8, +4dc, +594, +62c, +9c8, +1988
3605 // call: +7a0=4b70, +884=4c54, +894=4c64
3606 ptr[0x5b] = SWAP32(0x43d0);
3607 ram32[0x4b70/4] = SWAP32(0x03e00008); // jr $ra // setPadOutputBuf
3609 ram32[0x4c54/4] = SWAP32(0x240e0001); // mov $t6, 1
3610 ram32[0x4c58/4] = SWAP32(0x03e00008); // jr $ra
3611 ram32[0x4c5c/4] = SWAP32(0xac0e0000 + A_PAD_IRQR_ENA); // sw $t6, ...
3613 ram32[0x4c64/4] = SWAP32(0x03e00008); // jr $ra
3614 ram32[0x4c68/4] = SWAP32(0xac000000 + A_PAD_IRQR_ENA); // sw $0, ...
3616 ptr = (u32 *)&psxM[A_C0_TABLE];
3617 for (i = 0; i < 256/2; i++)
3618 ptr[i] = SWAP32(0x3000);
3619 ptr[6] = SWAP32(A_EXCEPTION);
3622 ram32[0x1000/4] = HLEOP(hleop_dummy);
3623 ram32[0x2000/4] = HLEOP(hleop_dummy);
3624 ram32[0x3000/4] = HLEOP(hleop_dummy);
3625 ram32[0x4c54/4] = HLEOP(hleop_dummy); // for B12_InitPad?
3626 ram32[0x8000/4] = HLEOP(hleop_execret);
3628 ram32[A_EEXIT_PTR/4] = SWAP32(A_EEXIT_DEF);
3629 ram32[A_EXC_SP/4] = SWAP32(A_EXC_STACK);
3630 ram32[A_RCNT_VBL_ACK/4 + 0] = SWAP32(1);
3631 ram32[A_RCNT_VBL_ACK/4 + 1] = SWAP32(1);
3632 ram32[A_RCNT_VBL_ACK/4 + 2] = SWAP32(1);
3633 ram32[A_RCNT_VBL_ACK/4 + 3] = SWAP32(1);
3636 void psxBiosShutdown() {
3639 void psxBiosCnfLoaded(u32 tcb_cnt, u32 evcb_cnt) {
3640 if (tcb_cnt != 4 || evcb_cnt != 16)
3641 setup_tt(tcb_cnt, evcb_cnt);
3644 #define psxBios_PADpoll(pad) { \
3645 PAD##pad##_startPoll(pad); \
3646 pad_buf##pad[0] = 0; \
3647 pad_buf##pad[1] = PAD##pad##_poll(0x42); \
3648 if (!(pad_buf##pad[1] & 0x0f)) { \
3651 bufcount = (pad_buf##pad[1] & 0x0f) * 2; \
3653 PAD##pad##_poll(0); \
3655 while (bufcount--) { \
3656 pad_buf##pad[i++] = PAD##pad##_poll(0); \
3660 static void handle_chain_x_x_1(u32 enable, u32 irqbit)
3664 psxHwWrite16(0x1f801070, ~(1u << irqbit));
3665 psxBios_ReturnFromException();
3671 // hleExc0_{0,1}* are usually removed by A(56)/A(72) on the game's startup,
3672 // so this is only partially implemented
3673 void hleExc0_0_1() // A(93h) - CdromDmaIrqFunc2
3675 u32 cdrom_dma_ack_enable = 1; // a000b93c
3676 handle_chain_x_x_1(cdrom_dma_ack_enable, 3); // IRQ3 DMA
3679 void hleExc0_0_2() // A(91h) - CdromDmaIrqFunc1
3682 //PSXBIOS_LOG("%s\n", __func__);
3684 if (psxHu32(0x1074) & psxHu32(0x1070) & 8) { // IRQ3 DMA
3685 psxHwWrite32(0x1f8010f4, (psxHu32(0x10f4) & 0xffffff) | 0x88000000);
3686 //if (--cdrom_irq_counter == 0) // 0xa0009180
3687 // DeliverEvent(0xf0000003, 0x10);
3691 mips_return_c(ret, 20);
3694 void hleExc0_1_1() // A(92h) - CdromIoIrqFunc2
3696 u32 cdrom_irq_ack_enable = 1; // a000b938
3697 handle_chain_x_x_1(cdrom_irq_ack_enable, 2); // IRQ2 cdrom
3700 void hleExc0_1_2() // A(90h) - CdromIoIrqFunc1
3703 if (psxHu32(0x1074) & psxHu32(0x1070) & 4) { // IRQ2 cdrom
3704 PSXBIOS_LOG("%s TODO\n", __func__);
3707 mips_return_c(ret, 20);
3710 void hleExc0_2_2_syscall() // not in any A/B/C table
3712 u32 code = (psxRegs.CP0.n.Cause & 0x3c) >> 2;
3713 u32 tcbPtr = loadRam32(A_TT_PCB);
3714 TCB *tcb = loadRam32ptr(tcbPtr);
3716 if (code != R3000E_Syscall) {
3718 DeliverEvent(0xf0000010, 0x1000);
3719 //psxBios_SystemErrorUnresolvedException();
3721 mips_return_c(0, 17);
3725 //printf("%s c=%d a0=%d\n", __func__, code, a0);
3726 tcb->epc += SWAP32(4);
3731 case 1: { // EnterCritical - disable irqs
3732 u32 was_enabled = ((SWAP32(tcb->sr) & 0x404) == 0x404);
3733 tcb->reg[2] = SWAP32(was_enabled);
3734 tcb->sr &= SWAP32(~0x404);
3737 case 2: // ExitCritical - enable irqs
3738 tcb->sr |= SWAP32(0x404);
3741 case 3: { // ChangeThreadSubFunction
3742 u32 tcbPtr = loadRam32(A_TT_PCB);
3743 storeRam32(tcbPtr, a1);
3747 DeliverEvent(0xf0000010, 0x4000);
3751 psxBios_ReturnFromException();
3754 void hleExc1_0_1(void)
3756 u32 vbl_irq_ack_enable = loadRam32(A_RCNT_VBL_ACK + 0x0c); // 860c
3757 handle_chain_x_x_1(vbl_irq_ack_enable, 0); // IRQ0 vblank
3760 static void handle_chain_1_x_2(u32 ev_index, u32 irqbit)
3763 if (psxHu32(0x1074) & psxHu32(0x1070) & (1u << irqbit)) {
3764 DeliverEvent(0xf2000000 + ev_index, 0x0002);
3767 mips_return_c(ret, 22);
3770 void hleExc1_0_2(void)
3772 handle_chain_1_x_2(3, 0); // IRQ0 vblank
3775 void hleExc1_1_1(void)
3777 u32 rcnt_irq_ack_enable = loadRam32(A_RCNT_VBL_ACK + 0x08); // 8608
3778 handle_chain_x_x_1(rcnt_irq_ack_enable, 6); // IRQ6 rcnt2
3781 void hleExc1_1_2(void)
3783 handle_chain_1_x_2(2, 6); // IRQ6 rcnt2
3786 void hleExc1_2_1(void)
3788 u32 rcnt_irq_ack_enable = loadRam32(A_RCNT_VBL_ACK + 0x04); // 8604
3789 handle_chain_x_x_1(rcnt_irq_ack_enable, 5); // IRQ5 rcnt1
3792 void hleExc1_2_2(void)
3794 handle_chain_1_x_2(1, 5); // IRQ5 rcnt1
3797 void hleExc1_3_1(void)
3799 u32 rcnt_irq_ack_enable = loadRam32(A_RCNT_VBL_ACK + 0x00); // 8600
3800 handle_chain_x_x_1(rcnt_irq_ack_enable, 4); // IRQ4 rcnt0
3803 void hleExc1_3_2(void)
3805 handle_chain_1_x_2(0, 4); // IRQ4 rcnt0
3808 void hleExc3_0_2_defint(void)
3810 static const struct {
3821 { 6, 6 }, // rcnt2 (bug)
3826 for (i = 0; i < sizeof(tab) / sizeof(tab[0]); i++) {
3827 if (psxHu32(0x1074) & psxHu32(0x1070) & (1u << tab[i].irqbit)) {
3828 DeliverEvent(0xf0000000 + tab[i].ev, 0x1000);
3833 mips_return_c(0, 11 + 7*11 + 7*11 + 12);
3836 void hleExcPadCard1(void)
3838 if (loadRam32(A_PAD_IRQR_ENA)) {
3839 u8 *pad_buf1 = loadRam8ptr(A_PAD_INBUF + 0);
3840 u8 *pad_buf2 = loadRam8ptr(A_PAD_INBUF + 4);
3846 if (loadRam32(A_PAD_DR_DST))
3849 if (loadRam32(A_PAD_ACK_VBL))
3850 psxHwWrite16(0x1f801070, ~1);
3851 if (loadRam32(A_CARD_IRQR_ENA)) {
3855 mips_return_c(0, 18);
3858 void hleExcPadCard2(void)
3860 u32 ret = psxHu32(0x1074) & psxHu32(0x1070) & 1;
3861 mips_return_c(ret, 15);
3864 void psxBiosException() {
3865 u32 tcbPtr = loadRam32(A_TT_PCB);
3866 u32 *chains = loadRam32ptr(A_TT_ExCB);
3867 TCB *tcb = loadRam32ptr(tcbPtr);
3873 // $at, $v0, $v1 already saved by the mips code at A_EXCEPTION
3874 for (i = 4; i < 32; i++) {
3877 tcb->reg[i] = SWAP32(psxRegs.GPR.r[i]);
3879 tcb->lo = SWAP32(psxRegs.GPR.n.lo);
3880 tcb->hi = SWAP32(psxRegs.GPR.n.hi);
3881 //tcb->epc = SWAP32(psxRegs.CP0.n.EPC); // done by asm
3882 tcb->sr = SWAP32(psxRegs.CP0.n.SR);
3883 tcb->cause = SWAP32(psxRegs.CP0.n.Cause);
3884 sp = fp = loadRam32(A_EXC_SP);
3888 // do the chains (always 4)
3889 for (c = lim = 0; c < 4; c++) {
3890 if (chains[c * 2] == 0)
3892 ptr = SWAP32(chains[c * 2]);
3893 for (; ptr && lim < 100; ptr = SWAP32(chain[0])) {
3894 chain = castRam32ptr(ptr);
3899 softCallInException(SWAP32(chain[2]));
3900 if (returned_from_exception())
3903 if (v0 == 0 || chain[1] == 0)
3905 softCallInException(SWAP32(chain[1]));
3906 if (returned_from_exception())
3912 // return from exception (custom or default)
3914 ptr = loadRam32(A_EEXIT_PTR);
3915 if (ptr != A_EEXIT_DEF) {
3916 const struct jmp_buf_ *jmp_buf = castRam32ptr(ptr);
3917 longjmp_load(jmp_buf);
3922 psxBios_ReturnFromException();
3925 #define bfreeze(ptr, size) { \
3926 if (Mode == 1) memcpy(&psxR[base], ptr, size); \
3927 if (Mode == 0) memcpy(ptr, &psxR[base], size); \
3931 #define bfreezes(ptr) bfreeze(ptr, sizeof(ptr))
3932 #define bfreezel(ptr) bfreeze(ptr, sizeof(*ptr))
3934 #define bfreezepsxMptr(ptr, type) { \
3936 if (ptr) psxRu32ref(base) = SWAPu32((s8 *)(ptr) - psxM); \
3937 else psxRu32ref(base) = 0; \
3939 if (psxRu32(base) != 0) ptr = (type *)(psxM + psxRu32(base)); \
3940 else (ptr) = NULL; \
3942 base += sizeof(u32); \
3945 void psxBiosFreeze(int Mode) {
3948 bfreezepsxMptr(heap_addr, u32);
3950 bfreezel(&card_active_chan);
3951 bfreezel(&heap_size);