1 /***************************************************************************
2 * Copyright (C) 2019 Ryan Schultz, PCSX-df Team, PCSX team, gameblabla, *
3 * dmitrysmagin, senquack *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA. *
19 ***************************************************************************/
21 /* Gameblabla 2018-2019 :
22 * Numerous changes to bios calls as well as improvements in order to conform to nocash's findings
23 * for the PSX bios calls. Thanks senquack for helping out with some of the changes
24 * and helping to spot issues and refine my patches.
28 * Internal simulated HLE BIOS.
31 // TODO: implement all system calls, count the exact CPU cycles of system calls.
38 #include "psxinterpreter.h"
39 #include "psxevents.h"
45 //#define PSXBIOS_LOG printf
46 #define PSXBIOS_LOG(...)
48 #ifndef PSXBIOS_EV_LOG
49 //#define PSXBIOS_EV_LOG printf
50 #define PSXBIOS_EV_LOG(...)
53 #define PTR_1 (void *)(size_t)1
55 char *biosA0n[256] = {
57 "open", "lseek", "read", "write",
58 "close", "ioctl", "exit", "sys_a0_07",
59 "getc", "putc", "todigit", "atof",
60 "strtoul", "strtol", "abs", "labs",
62 "atoi", "atol", "atob", "setjmp",
63 "longjmp", "strcat", "strncat", "strcmp",
64 "strncmp", "strcpy", "strncpy", "strlen",
65 "index", "rindex", "strchr", "strrchr",
67 "strpbrk", "strspn", "strcspn", "strtok",
68 "strstr", "toupper", "tolower", "bcopy",
69 "bzero", "bcmp", "memcpy", "memset",
70 "memmove", "memcmp", "memchr", "rand",
72 "srand", "qsort", "strtod", "malloc",
73 "free", "lsearch", "bsearch", "calloc",
74 "realloc", "InitHeap", "_exit", "getchar",
75 "putchar", "gets", "puts", "printf",
77 "SystemErrorUnresolvedException", "LoadTest", "Load", "Exec",
78 "FlushCache", "InstallInterruptHandler", "GPU_dw", "mem2vram",
79 "SendGPUStatus", "GPU_cw", "GPU_cwb", "SendPackets",
80 "sys_a0_4c", "GetGPUStatus", "GPU_sync", "sys_a0_4f",
82 "sys_a0_50", "LoadExec", "GetSysSp", "sys_a0_53",
83 "_96_init()", "_bu_init()", "_96_remove()", "sys_a0_57",
84 "sys_a0_58", "sys_a0_59", "sys_a0_5a", "dev_tty_init",
85 "dev_tty_open", "sys_a0_5d", "dev_tty_ioctl","dev_cd_open",
87 "dev_cd_read", "dev_cd_close", "dev_cd_firstfile", "dev_cd_nextfile",
88 "dev_cd_chdir", "dev_card_open", "dev_card_read", "dev_card_write",
89 "dev_card_close", "dev_card_firstfile", "dev_card_nextfile","dev_card_erase",
90 "dev_card_undelete","dev_card_format", "dev_card_rename", "dev_card_6f",
92 "_bu_init", "CdInit", "CdRemove", "sys_a0_73",
93 "sys_a0_74", "sys_a0_75", "sys_a0_76", "sys_a0_77",
94 "_96_CdSeekL", "sys_a0_79", "sys_a0_7a", "sys_a0_7b",
95 "_96_CdGetStatus", "sys_a0_7d", "_96_CdRead", "sys_a0_7f",
97 "sys_a0_80", "sys_a0_81", "sys_a0_82", "sys_a0_83",
98 "sys_a0_84", "_96_CdStop", "sys_a0_86", "sys_a0_87",
99 "sys_a0_88", "sys_a0_89", "sys_a0_8a", "sys_a0_8b",
100 "sys_a0_8c", "sys_a0_8d", "sys_a0_8e", "sys_a0_8f",
102 "sys_a0_90", "sys_a0_91", "sys_a0_92", "sys_a0_93",
103 "sys_a0_94", "CdReset", "AddCDROMDevice", "AddMemCardDevide",
104 "DisableKernelIORedirection", "EnableKernelIORedirection", "sys_a0_9a", "sys_a0_9b",
105 "SetConf", "GetConf", "sys_a0_9e", "SetMem",
107 "_boot", "SystemError", "EnqueueCdIntr", "DequeueCdIntr",
108 "sys_a0_a4", "ReadSector", "get_cd_status", "bufs_cb_0",
109 "bufs_cb_1", "bufs_cb_2", "bufs_cb_3", "_card_info",
110 "_card_load", "_card_auto", "bufs_cd_4", "sys_a0_af",
112 "sys_a0_b0", "sys_a0_b1", "do_a_long_jmp", "sys_a0_b3",
116 char *biosB0n[256] = {
118 "SysMalloc", "sys_b0_01", "sys_b0_02", "sys_b0_03",
119 "sys_b0_04", "sys_b0_05", "sys_b0_06", "DeliverEvent",
120 "OpenEvent", "CloseEvent", "WaitEvent", "TestEvent",
121 "EnableEvent", "DisableEvent", "OpenTh", "CloseTh",
123 "ChangeTh", "sys_b0_11", "InitPAD", "StartPAD",
124 "StopPAD", "PAD_init", "PAD_dr", "ReturnFromException",
125 "ResetEntryInt", "HookEntryInt", "sys_b0_1a", "sys_b0_1b",
126 "sys_b0_1c", "sys_b0_1d", "sys_b0_1e", "sys_b0_1f",
128 "UnDeliverEvent", "sys_b0_21", "sys_b0_22", "sys_b0_23",
129 "sys_b0_24", "sys_b0_25", "sys_b0_26", "sys_b0_27",
130 "sys_b0_28", "sys_b0_29", "sys_b0_2a", "sys_b0_2b",
131 "sys_b0_2c", "sys_b0_2d", "sys_b0_2e", "sys_b0_2f",
133 "sys_b0_30", "sys_b0_31", "open", "lseek",
134 "read", "write", "close", "ioctl",
135 "exit", "sys_b0_39", "getc", "putc",
136 "getchar", "putchar", "gets", "puts",
138 "cd", "format", "firstfile", "nextfile",
139 "rename", "delete", "undelete", "AddDevice",
140 "RemoteDevice", "PrintInstalledDevices", "InitCARD", "StartCARD",
141 "StopCARD", "sys_b0_4d", "_card_write", "_card_read",
143 "_new_card", "Krom2RawAdd", "sys_b0_52", "sys_b0_53",
144 "_get_errno", "_get_error", "GetC0Table", "GetB0Table",
145 "_card_chan", "sys_b0_59", "sys_b0_5a", "ChangeClearPAD",
146 "_card_status", "_card_wait",
149 char *biosC0n[256] = {
151 "InitRCnt", "InitException", "SysEnqIntRP", "SysDeqIntRP",
152 "get_free_EvCB_slot", "get_free_TCB_slot", "ExceptionHandler", "InstallExeptionHandler",
153 "SysInitMemory", "SysInitKMem", "ChangeClearRCnt", "SystemError",
154 "InitDefInt", "sys_c0_0d", "sys_c0_0e", "sys_c0_0f",
156 "sys_c0_10", "sys_c0_11", "InstallDevices", "FlushStfInOutPut",
157 "sys_c0_14", "_cdevinput", "_cdevscan", "_circgetc",
158 "_circputc", "ioabort", "sys_c0_1a", "KernelRedirect",
162 //#define r0 (psxRegs.GPR.n.r0)
163 #define at (psxRegs.GPR.n.at)
164 #define v0 (psxRegs.GPR.n.v0)
165 #define v1 (psxRegs.GPR.n.v1)
166 #define a0 (psxRegs.GPR.n.a0)
167 #define a1 (psxRegs.GPR.n.a1)
168 #define a2 (psxRegs.GPR.n.a2)
169 #define a3 (psxRegs.GPR.n.a3)
170 #define t0 (psxRegs.GPR.n.t0)
171 #define t1 (psxRegs.GPR.n.t1)
172 #define t2 (psxRegs.GPR.n.t2)
173 #define t3 (psxRegs.GPR.n.t3)
174 #define t4 (psxRegs.GPR.n.t4)
175 #define t5 (psxRegs.GPR.n.t5)
176 #define t6 (psxRegs.GPR.n.t6)
177 #define t7 (psxRegs.GPR.n.t7)
178 #define t8 (psxRegs.GPR.n.t8)
179 #define t9 (psxRegs.GPR.n.t9)
180 #define s0 (psxRegs.GPR.n.s0)
181 #define s1 (psxRegs.GPR.n.s1)
182 #define s2 (psxRegs.GPR.n.s2)
183 #define s3 (psxRegs.GPR.n.s3)
184 #define s4 (psxRegs.GPR.n.s4)
185 #define s5 (psxRegs.GPR.n.s5)
186 #define s6 (psxRegs.GPR.n.s6)
187 #define s7 (psxRegs.GPR.n.s7)
188 #define k0 (psxRegs.GPR.n.k0)
189 #define k1 (psxRegs.GPR.n.k1)
190 #define gp (psxRegs.GPR.n.gp)
191 #define sp (psxRegs.GPR.n.sp)
192 #define fp (psxRegs.GPR.n.fp)
193 #define ra (psxRegs.GPR.n.ra)
194 #define pc0 (psxRegs.pc)
196 #define Ra0 ((char *)PSXM(a0))
197 #define Ra1 ((char *)PSXM(a1))
198 #define Ra2 ((char *)PSXM(a2))
199 #define Ra3 ((char *)PSXM(a3))
200 #define Rv0 ((char *)PSXM(v0))
201 #define Rsp ((char *)PSXM(sp))
212 #define EvStUNUSED 0x0000
213 #define EvStDISABLED 0x1000
214 #define EvStACTIVE 0x2000
215 #define EvStALREADY 0x4000
217 #define EvMdCALL 0x1000
218 #define EvMdMARK 0x2000
241 u32 _sp, _fp, _gp, ret, base;
261 // todo: FileDesc layout is wrong
262 // todo: get rid of these globals
263 static FileDesc FDesc[32];
264 static char ffile[64];
266 static char cdir[8*8+8];
269 // fixed RAM offsets, SCPH1001 compatible
270 #define A_TT_ExCB 0x0100
271 #define A_TT_PCB 0x0108
272 #define A_TT_TCB 0x0110
273 #define A_TT_EvCB 0x0120
274 #define A_A0_TABLE 0x0200
275 #define A_B0_TABLE 0x0874
276 #define A_C0_TABLE 0x0674
277 #define A_SYSCALL 0x0650
278 #define A_EXCEPTION 0x0c80
279 #define A_EXC_SP 0x6cf0
280 #define A_EEXIT_DEF 0x6cf4
281 #define A_CARD_ISLOT 0x7264 // 0 or 1, toggled by card vint handler
282 #define A_KMALLOC_PTR 0x7460
283 #define A_KMALLOC_SIZE 0x7464
284 #define A_KMALLOC_END 0x7468
285 #define A_PADCRD_CHN_E 0x74a8 // pad/card irq chain entry, see hleExcPadCard1()
286 #define A_PAD_IRQR_ENA 0x74b8 // pad read on vint irq (nocash 'pad_enable_flag')
287 #define A_CARD_IRQR_ENA 0x74bc // same for card
288 #define A_PAD_INBUF 0x74c8 // 2x buffers for rx pad data
289 #define A_PAD_OUTBUF 0x74d0 // 2x buffers for tx pad data
290 #define A_PAD_IN_LEN 0x74d8
291 #define A_PAD_OUT_LEN 0x74e0
292 #define A_PAD_DR_DST 0x74c4
293 #define A_CARD_ACHAN 0x7500 // currently active port in 0xPortSlot format
294 #define A_CARD_HANDLER 0x7528 // ptr to irq handler
295 #define A_CARD_STATUS1 0x7568
296 #define A_CARD_STATUS2 0x7569
297 #define A_PAD_DR_BUF1 0x7570
298 #define A_PAD_DR_BUF2 0x7598
299 #define A_EEXIT_PTR 0x75d0
300 #define A_EXC_STACK 0x85d8 // exception stack top
301 #define A_RCNT_VBL_ACK 0x8600
302 #define A_PAD_ACK_VBL 0x8914 // enable vint ack by pad reading code
303 #define A_HEAP_BASE 0x9000
304 #define A_HEAP_SIZE 0x9004
305 #define A_HEAP_END 0x9008
306 #define A_HEAP_INIT_FLG 0x900c
307 #define A_RND_SEED 0x9010
308 #define A_HEAP_FRSTCHNK 0xb060
309 #define A_HEAP_CURCHNK 0xb064
310 #define A_CONF_TCB 0xb940
311 #define A_CONF_EvCB 0xb944
312 #define A_CONF_SP 0xb948
313 #define A_CD_EVENTS 0xb9b8
314 #define A_EXC_GP 0xf450
316 #define A_A0_TRAPS 0x1010
317 #define A_B0_TRAPS 0x2010
318 #define A_C0_TRAPS 0x3010
319 #define A_B0_5B_TRAP 0x43d0
321 #define CARD_HARDLER_WRITE 0x51F4
322 #define CARD_HARDLER_READ 0x5688
323 #define CARD_HARDLER_INFO 0x5B64
325 #define HLEOP(n) SWAPu32((0x3b << 26) | (n));
327 static u8 loadRam8(u32 addr)
329 assert(!(addr & 0x5f800000));
330 return psxM[addr & 0x1fffff];
333 static u32 loadRam32(u32 addr)
335 assert(!(addr & 0x5f800000));
336 return SWAP32(*((u32 *)psxM + ((addr & 0x1fffff) >> 2)));
339 static void *castRam8ptr(u32 addr)
341 assert(!(addr & 0x5f800000));
342 return psxM + (addr & 0x1fffff);
345 static void *castRam32ptr(u32 addr)
347 assert(!(addr & 0x5f800003));
348 return psxM + (addr & 0x1ffffc);
351 static void *loadRam8ptr(u32 addr)
353 return castRam8ptr(loadRam32(addr));
356 static void *loadRam32ptr(u32 addr)
358 return castRam32ptr(loadRam32(addr));
361 static void storeRam8(u32 addr, u8 d)
363 assert(!(addr & 0x5f800000));
364 *((u8 *)psxM + (addr & 0x1fffff)) = d;
367 static void storeRam32(u32 addr, u32 d)
369 assert(!(addr & 0x5f800000));
370 *((u32 *)psxM + ((addr & 0x1fffff) >> 2)) = SWAP32(d);
373 static void mips_return(u32 val)
379 static void mips_return_void(void)
384 static void use_cycles(u32 cycle)
386 psxRegs.cycle += cycle * 2;
389 static void mips_return_c(u32 val, u32 cycle)
395 static void mips_return_void_c(u32 cycle)
401 static int returned_from_exception(void)
403 // 0x80000080 means it took another exception just after return
404 return pc0 == k0 || pc0 == 0x80000080;
407 static inline void softCall(u32 pc) {
409 u32 ssr = psxRegs.CP0.n.SR;
413 psxRegs.CP0.n.SR &= ~0x404; // disable interrupts
415 assert(psxRegs.cpuInRecursion <= 1);
416 psxRegs.cpuInRecursion++;
417 psxCpu->Notify(R3000ACPU_NOTIFY_AFTER_LOAD, PTR_1);
419 while (pc0 != 0x80001000 && ++lim < 0x100000)
420 psxCpu->ExecuteBlock(EXEC_CALLER_HLE);
422 psxCpu->Notify(R3000ACPU_NOTIFY_BEFORE_SAVE, PTR_1);
423 psxRegs.cpuInRecursion--;
426 PSXBIOS_LOG("softCall @%x hit lim\n", pc);
428 psxRegs.CP0.n.SR |= ssr & 0x404;
431 static inline void softCallInException(u32 pc) {
436 assert(ra != 0x80001000);
437 if (ra == 0x80001000)
441 psxRegs.cpuInRecursion++;
442 psxCpu->Notify(R3000ACPU_NOTIFY_AFTER_LOAD, PTR_1);
444 while (!returned_from_exception() && pc0 != 0x80001000 && ++lim < 0x100000)
445 psxCpu->ExecuteBlock(EXEC_CALLER_HLE);
447 psxCpu->Notify(R3000ACPU_NOTIFY_BEFORE_SAVE, PTR_1);
448 psxRegs.cpuInRecursion--;
451 PSXBIOS_LOG("softCallInException @%x hit lim\n", pc);
452 if (pc0 == 0x80001000)
456 static u32 OpenEvent(u32 class, u32 spec, u32 mode, u32 func);
457 static void EnableEvent(u32 ev, int do_log);
458 static u32 DeliverEvent(u32 class, u32 spec);
459 static u32 UnDeliverEvent(u32 class, u32 spec);
460 static void CloseEvent(u32 ev);
465 // System calls A0 */
468 #define buread(Ra1, mcd, length) { \
469 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); \
470 ptr = Mcd##mcd##Data + 8192 * FDesc[1 + mcd].mcfile + FDesc[1 + mcd].offset; \
471 memcpy(Ra1, ptr, length); \
472 psxCpu->Clear(a1, (length + 3) / 4); \
473 if (FDesc[1 + mcd].mode & 0x8000) { \
474 DeliverEvent(0xf0000011, 0x0004); \
475 DeliverEvent(0xf4000001, 0x0004); \
478 FDesc[1 + mcd].offset += v0; \
481 #define buwrite(Ra1, mcd, length) { \
482 u32 offset = + 8192 * FDesc[1 + mcd].mcfile + FDesc[1 + mcd].offset; \
483 PSXBIOS_LOG("write %d: %x,%x\n", FDesc[1 + mcd].mcfile, FDesc[1 + mcd].offset, a2); \
484 ptr = Mcd##mcd##Data + offset; \
485 memcpy(ptr, Ra1, length); \
486 FDesc[1 + mcd].offset += length; \
487 SaveMcd(Config.Mcd##mcd, Mcd##mcd##Data, offset, length); \
488 if (FDesc[1 + mcd].mode & 0x8000) { \
489 DeliverEvent(0xf0000011, 0x0004); \
490 DeliverEvent(0xf4000001, 0x0004); \
495 /* Internally redirects to "FileRead(fd,tempbuf,1)".*/
496 /* For some strange reason, the returned character is sign-expanded; */
497 /* So if a return value of FFFFFFFFh could mean either character FFh, or error. */
498 /* TODO FIX ME : Properly implement this behaviour */
499 void psxBios_getc(void) // 0x03, 0x35
504 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x03]);
508 if (pa1 != INVALID_PTR) {
510 case 2: buread(pa1, 1, 1); break;
511 case 3: buread(pa1, 2, 1); break;
518 /* Copy of psxBios_write, except size is 1. */
519 void psxBios_putc(void) // 0x09, 0x3B
524 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x09]);
527 if (pa1 == INVALID_PTR) {
532 if (a0 == 1) { // stdout
533 char *ptr = (char *)pa1;
537 printf("%c", *ptr++); a2--;
543 case 2: buwrite(pa1, 1, 1); break;
544 case 3: buwrite(pa1, 2, 1); break;
550 static u32 do_todigit(u32 c)
553 if (c >= 0x30 && c < 0x3A) {
556 else if (c > 0x60 && c < 0x7B) {
559 else if (c > 0x40 && c < 0x5B) {
562 else if (c >= 0x80) {
563 log_unhandled("todigit %02x\n", c);
574 static void psxBios_todigit(void) // 0x0a
576 mips_return(do_todigit(a0));
577 PSXBIOS_LOG("psxBios_%s '%c' -> %u\n", biosA0n[0x0a], a0, v0);
580 static void do_strtol(char *p, void *end_, u32 base, int can_neg) {
585 if (p == INVALID_PTR) {
590 for (; (0x09 <= *p && *p <= '\r') || *p == ' '; p++)
593 for (; *p == '-'; f = 1, p++)
596 if (base == 0 || base > 36)
600 case 'b': case 'B': base = 2; break;
601 case 'x': case 'X': base = 16; break;
604 else if (*p == 'o' || *p == 'O') {
609 for (; (t = do_todigit(*p)) < base; p++) {
615 if (end != INVALID_PTR)
616 *end = SWAP32(a0 + (p - Ra0));
617 mips_return_c(n, 100);
620 static void psxBios_strtoul() { // 0x0c
621 do_strtol(a0 ? Ra0 : INVALID_PTR, a1 ? Ra1 : INVALID_PTR, a2, 0);
622 PSXBIOS_LOG("psxBios_%s %s (%x), %x, %x -> 0x%x\n",
623 biosA0n[0x0c], a0 ? Ra0 : NULL, a0, a1, a2, v0);
626 static void psxBios_strtol() { // 0x0d
627 do_strtol(a0 ? Ra0 : INVALID_PTR, a1 ? Ra1 : INVALID_PTR, a2, 1);
628 PSXBIOS_LOG("psxBios_%s %s (%x), %x, %x -> 0x%x\n",
629 biosA0n[0x0d], a0 ? Ra0 : NULL, a0, a1, a2, v0);
632 void psxBios_abs() { // 0x0e
633 if ((s32)a0 < 0) v0 = -(s32)a0;
638 void psxBios_labs() { // 0x0f
642 void psxBios_atoi() { // 0x10
644 char *p = (char *)Ra0;
646 if (p == INVALID_PTR) {
653 case ' ': case '\t': continue;
660 while (*p >= '0' && *p <= '9') {
661 n = n * 10 + *p++ - '0';
666 PSXBIOS_LOG("psxBios_%s %s (%x) -> 0x%x\n", biosA0n[0x10], Ra0, a0, v0);
669 void psxBios_atol() { // 0x11
679 static void psxBios_setjmp() { // 0x13
680 struct jmp_buf_ *jmp_buf = castRam32ptr(a0);
683 PSXBIOS_LOG("psxBios_%s %x\n", biosA0n[0x13], a0);
685 jmp_buf->ra_ = SWAP32(ra);
686 jmp_buf->sp_ = SWAP32(sp);
687 jmp_buf->fp_ = SWAP32(fp);
688 for (i = 0; i < 8; i++) // s0-s7
689 jmp_buf->s[i] = SWAP32(psxRegs.GPR.r[16 + i]);
690 jmp_buf->gp_ = SWAP32(gp);
692 mips_return_c(0, 15);
695 static void longjmp_load(const struct jmp_buf_ *jmp_buf)
699 ra = SWAP32(jmp_buf->ra_);
700 sp = SWAP32(jmp_buf->sp_);
701 fp = SWAP32(jmp_buf->fp_);
702 for (i = 0; i < 8; i++) // s0-s7
703 psxRegs.GPR.r[16 + i] = SWAP32(jmp_buf->s[i]);
704 gp = SWAP32(jmp_buf->gp_);;
707 void psxBios_longjmp() { // 0x14
708 struct jmp_buf_ *jmp_buf = castRam32ptr(a0);
710 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x14]);
711 longjmp_load(jmp_buf);
712 mips_return_c(a1, 15);
715 void psxBios_strcat() { // 0x15
719 PSXBIOS_LOG("psxBios_%s %s (%x), %s (%x)\n", biosA0n[0x15], Ra0, a0, Ra1, a1);
720 if (a0 == 0 || a1 == 0 || p2 == INVALID_PTR)
725 while (loadRam8(p1)) {
729 for (; *p2; p1++, p2++)
733 mips_return_c(a0, 22);
736 void psxBios_strncat() { // 0x16
737 char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
741 PSXBIOS_LOG("psxBios_%s: %s (%x), %s (%x), %d\n", biosA0n[0x16], Ra0, a0, Ra1, a1, a2);
743 if (a0 == 0 || a1 == 0)
751 while ((*p1++ = *p2++) != '\0') {
761 void psxBios_strcmp() { // 0x17
762 char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
764 if (a0 == 0 && a1 == 0)
770 else if (a0 == 0 && a1 != 0)
776 else if (a0 != 0 && a1 == 0)
783 PSXBIOS_LOG("psxBios_%s: %s (%x), %s (%x)\n", biosA0n[0x17], Ra0, a0, Ra1, a1);
786 while (*p1 == *p2++) {
805 void psxBios_strncmp() { // 0x18
806 char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
808 if (a0 == 0 && a1 == 0)
814 else if (a0 == 0 && a1 != 0)
820 else if (a0 != 0 && a1 == 0)
827 PSXBIOS_LOG("psxBios_%s: %s (%x), %s (%x), %d\n", biosA0n[0x18], Ra0, a0, Ra1, a1, a2);
830 while (--n >= 0 && *p1 == *p2++) {
834 v1 = a2 - ((a2-n) - 1);
842 v0 = (n < 0 ? 0 : *p1 - *--p2);
844 v1 = a2 - ((a2-n) - 1);
850 void psxBios_strcpy() { // 0x19
851 char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
852 PSXBIOS_LOG("psxBios_%s %x, %s (%x)\n", biosA0n[0x19], a0, p2, a1);
853 if (a0 == 0 || a1 == 0)
859 while ((*p1++ = *p2++) != '\0');
864 void psxBios_strncpy() { // 0x1a
865 char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
867 if (a0 == 0 || a1 == 0)
873 for (i = 0; i < n; i++) {
874 if ((*p1++ = *p2++) == '\0') {
886 void psxBios_strlen() { // 0x1b
887 char *p = (char *)Ra0;
898 void psxBios_index() { // 0x1c
899 char *p = (char *)Ra0;
909 v0 = a0 + (p - (char *)Ra0);
913 } while (*p++ != '\0');
918 void psxBios_rindex() { // 0x1d
919 char *p = (char *)Ra0;
929 v0 = a0 + (p - (char *)Ra0);
930 } while (*p++ != '\0');
935 void psxBios_strchr() { // 0x1e
939 void psxBios_strrchr() { // 0x1f
943 void psxBios_strpbrk() { // 0x20
944 char *p1 = (char *)Ra0, *p2 = (char *)Ra1, *scanp, c, sc;
946 while ((c = *p1++) != '\0') {
947 for (scanp = p2; (sc = *scanp++) != '\0';) {
949 v0 = a0 + (p1 - 1 - (char *)Ra0);
956 // BUG: return a0 instead of NULL if not found
960 void psxBios_strspn() { // 0x21
963 for (p1 = (char *)Ra0; *p1 != '\0'; p1++) {
964 for (p2 = (char *)Ra1; *p2 != '\0' && *p2 != *p1; p2++);
965 if (*p2 == '\0') break;
968 v0 = p1 - (char *)Ra0; pc0 = ra;
971 void psxBios_strcspn() { // 0x22
974 for (p1 = (char *)Ra0; *p1 != '\0'; p1++) {
975 for (p2 = (char *)Ra1; *p2 != '\0' && *p2 != *p1; p2++);
976 if (*p2 != '\0') break;
979 v0 = p1 - (char *)Ra0; pc0 = ra;
982 void psxBios_strtok() { // 0x23
983 char *pcA0 = (char *)Ra0;
984 char *pcRet = strtok(pcA0, (char *)Ra1);
986 v0 = a0 + pcRet - pcA0;
992 void psxBios_strstr() { // 0x24
993 char *p = (char *)Ra0, *p1, *p2;
994 PSXBIOS_LOG("psxBios_%s %s (%x), %s (%x)\n", biosA0n[0x24], p, a0, Ra1, a1);
1000 while (*p1 != '\0' && *p2 != '\0' && *p1 == *p2) {
1005 v0 = a0 + (p - (char *)Ra0);
1007 PSXBIOS_LOG(" -> %x\n", v0);
1011 // bug: skips the whole matched substring + 1
1018 void psxBios_toupper() { // 0x25
1019 v0 = (s8)(a0 & 0xff);
1020 if (v0 >= 'a' && v0 <= 'z') v0 -= 'a' - 'A';
1024 void psxBios_tolower() { // 0x26
1025 v0 = (s8)(a0 & 0xff);
1026 if (v0 >= 'A' && v0 <= 'Z') v0 += 'a' - 'A';
1030 static void do_memset(u32 dst, u32 v, s32 len)
1036 if (db != INVALID_PTR)
1040 psxCpu->Clear(dst, (len + 3) / 4);
1043 static void do_memcpy(u32 dst, u32 src, s32 len)
1045 u32 d = dst, s = src;
1048 const u8 *sb = PSXM(s);
1050 if (db != INVALID_PTR && sb != INVALID_PTR)
1055 psxCpu->Clear(dst, (len + 3) / 4);
1058 static void psxBios_memcpy();
1060 static void psxBios_bcopy() { // 0x27 - memcpy with args swapped
1061 //PSXBIOS_LOG("psxBios_%s %x %x %x\n", biosA0n[0x27], a0, a1, a2);
1062 u32 ret = a0, cycles = 0;
1063 if (a0 == 0) // ...but it checks src this time
1065 mips_return_c(0, 4);
1070 do_memcpy(a1, a0, a2);
1076 mips_return_c(ret, cycles + 5);
1079 static void psxBios_bzero() { // 0x28
1080 /* Same as memset here (See memset below) */
1081 u32 ret = a0, cycles;
1082 if (a0 == 0 || (s32)a1 <= 0)
1084 mips_return_c(0, 6);
1087 do_memset(a0, 0, a1);
1091 // todo: many more cycles due to uncached bios mem
1092 mips_return_c(ret, cycles + 5);
1095 void psxBios_bcmp() { // 0x29
1096 char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
1098 if (a0 == 0 || a1 == 0) { v0 = 0; pc0 = ra; return; }
1100 while ((s32)a2-- > 0) {
1101 if (*p1++ != *p2++) {
1102 v0 = *p1 - *p2; // BUG: compare the NEXT byte
1111 static void psxBios_memcpy() { // 0x2a
1112 u32 ret = a0, cycles = 0;
1115 mips_return_c(0, 4);
1120 do_memcpy(a0, a1, a2);
1126 mips_return_c(ret, cycles + 5);
1129 static void psxBios_memset() { // 0x2b
1130 u32 ret = a0, cycles;
1131 if (a0 == 0 || (s32)a2 <= 0)
1133 mips_return_c(0, 6);
1136 do_memset(a0, a1, a2);
1140 // todo: many more cycles due to uncached bios mem
1141 mips_return_c(ret, cycles + 5);
1144 void psxBios_memmove() { // 0x2c
1145 u32 ret = a0, cycles = 0;
1148 mips_return_c(0, 4);
1152 if ((s32)a2 > 0 && a0 > a1 && a0 < a1 + a2) {
1153 u32 dst = a0, len = a2 + 1;
1156 while ((s32)a2 >= 0) { // BUG: copies one more byte here
1157 const u8 *sb = PSXM(a1);
1159 if (db != INVALID_PTR && sb != INVALID_PTR)
1165 psxCpu->Clear(dst, (len + 3) / 4);
1166 cycles = 10 + len * 8;
1167 } else if ((s32)a2 > 0) {
1168 do_memcpy(a0, a1, a2);
1174 mips_return_c(ret, cycles + 5);
1177 void psxBios_memcmp() { // 0x2d
1181 void psxBios_memchr() { // 0x2e
1182 char *p = (char *)Ra0;
1184 if (a0 == 0 || a2 > 0x7FFFFFFF)
1190 while ((s32)a2-- > 0) {
1191 if (*p++ != (s8)a1) continue;
1192 v0 = a0 + (p - (char *)Ra0 - 1);
1200 static void psxBios_rand() { // 0x2f
1201 u32 s = loadRam32(A_RND_SEED) * 1103515245 + 12345;
1202 storeRam32(A_RND_SEED, s);
1204 mips_return_c((s >> 16) & 0x7fff, 12+37);
1207 static void psxBios_srand() { // 0x30
1208 storeRam32(A_RND_SEED, a0);
1209 mips_return_void_c(3);
1212 static u32 qscmpfunc, qswidth;
1214 static inline int qscmp(char *a, char *b) {
1217 a0 = sa0 + (a - (char *)PSXM(sa0));
1218 a1 = sa0 + (b - (char *)PSXM(sa0));
1220 softCall(qscmpfunc);
1226 static inline void qexchange(char *i, char *j) {
1237 static inline void q3exchange(char *i, char *j, char *k) {
1249 static void qsort_main(char *a, char *l) {
1250 char *i, *j, *lp, *hp;
1255 if ((n = l - a) <= qswidth)
1257 n = qswidth * (n / (2 * qswidth));
1263 if ((c = qscmp(i, lp)) == 0) {
1264 qexchange(i, lp -= qswidth);
1275 if ((c = qscmp(hp, j)) == 0) {
1276 qexchange(hp += qswidth, j);
1281 q3exchange(i, hp += qswidth, j);
1295 if (lp - a >= l - hp) {
1296 qsort_main(hp + qswidth, l);
1305 q3exchange(j, lp -= qswidth, i);
1310 void psxBios_qsort() { // 0x31
1313 qsort_main((char *)Ra0, (char *)Ra0 + a1 * a2);
1318 static int malloc_heap_grow(u32 size) {
1319 u32 heap_addr, heap_end, heap_addr_new;
1321 heap_addr = loadRam32(A_HEAP_BASE);
1322 heap_end = loadRam32(A_HEAP_END);
1323 heap_addr_new = heap_addr + size + 4;
1324 if (heap_addr_new >= heap_end)
1326 storeRam32(A_HEAP_BASE, heap_addr_new);
1327 storeRam32(heap_addr - 4, size | 1);
1328 storeRam32(heap_addr + size, ~1); // terminator
1332 static void psxBios_malloc() { // 0x33
1333 u32 size = (a0 + 3) & ~3;
1334 u32 limit = 32*1024;
1338 PSXBIOS_LOG("psxBios_%s %d\n", biosA0n[0x33], a0);
1340 if (!loadRam32(A_HEAP_INIT_FLG)) {
1341 u32 heap_addr = loadRam32(A_HEAP_BASE);
1342 storeRam32(heap_addr, ~1);
1343 storeRam32(A_HEAP_FRSTCHNK, heap_addr);
1344 storeRam32(A_HEAP_CURCHNK, heap_addr);
1345 storeRam32(A_HEAP_BASE, heap_addr + 4);
1346 if (malloc_heap_grow(size)) {
1347 PSXBIOS_LOG("malloc: init OOM\n");
1348 mips_return_c(0, 20);
1351 storeRam32(A_HEAP_INIT_FLG, 1);
1354 for (i = 0; tries > 0 && i < limit; i++)
1356 u32 chunk = loadRam32(A_HEAP_CURCHNK);
1357 u32 chunk_hdr = loadRam32(chunk);
1358 u32 next_chunk = chunk + 4 + (chunk_hdr & ~3);
1359 u32 next_chunk_hdr = loadRam32(next_chunk);
1361 //printf(" c %08x %08x\n", chunk, chunk_hdr);
1362 if (chunk_hdr & 1) {
1364 if (chunk_hdr > (size | 1)) {
1366 u32 p2size = (chunk_hdr & ~3) - size - 4;
1367 storeRam32(chunk + 4 + size, p2size | 1);
1368 chunk_hdr = size | 1;
1370 if (chunk_hdr == (size | 1)) {
1371 storeRam32(chunk, size);
1375 if (next_chunk_hdr == ~1) {
1376 // rm useless last free block
1377 storeRam32(A_HEAP_BASE, chunk + 4);
1378 storeRam32(chunk, ~1);
1381 if (next_chunk_hdr & 1) {
1383 u32 msize = (chunk_hdr & ~3) + 4 + (next_chunk_hdr & ~3);
1384 storeRam32(chunk, msize | 1);
1388 if (chunk_hdr == ~1) {
1391 storeRam32(A_HEAP_CURCHNK, loadRam32(A_HEAP_FRSTCHNK));
1395 // go to the next chunk
1396 storeRam32(A_HEAP_CURCHNK, next_chunk);
1401 PSXBIOS_LOG("malloc: limit OOM\n");
1404 else if (tries == 0 && malloc_heap_grow(size)) {
1405 PSXBIOS_LOG("malloc: grow OOM s=%d end=%08x/%08x\n",
1406 size, loadRam32(A_HEAP_BASE), loadRam32(A_HEAP_END));
1410 u32 chunk = loadRam32(A_HEAP_CURCHNK);
1411 storeRam32(chunk, loadRam32(chunk) & ~3);
1415 PSXBIOS_LOG(" -> %08x\n", ret);
1416 mips_return_c(ret, 40);
1419 static void psxBios_free() { // 0x34
1420 PSXBIOS_LOG("psxBios_%s %x (%d bytes)\n", biosA0n[0x34], a0, loadRam32(a0 - 4));
1421 storeRam32(a0 - 4, loadRam32(a0 - 4) | 1); // set chunk to free
1422 mips_return_void_c(5);
1425 static void psxBios_calloc() { // 0x37
1427 PSXBIOS_LOG("psxBios_%s %x %x\n", biosA0n[0x37], a0, a1);
1429 a0 = size = a0 * a1;
1433 a0 = ret; a1 = size;
1436 mips_return_c(ret, 21);
1439 void psxBios_realloc() { // 0x38
1443 PSXBIOS_LOG("psxBios_%s %08x %d\n", biosA0n[0x38], a0, a1);
1446 /* If "old_buf" is zero, executes malloc(new_size), and returns r2=new_buf (or 0=failed). */
1451 /* Else, if "new_size" is zero, executes free(old_buf), and returns r2=garbage. */
1456 /* Else, executes malloc(new_size), bcopy(old_buf,new_buf,new_size), and free(old_buf), and returns r2=new_buf (or 0=failed). */
1457 /* Note that it is not quite implemented this way here. */
1467 /* InitHeap(void *block , int n) */
1468 static void psxBios_InitHeap() { // 0x39
1469 PSXBIOS_LOG("psxBios_%s %x %x\n", biosA0n[0x39], a0, a1);
1471 storeRam32(A_HEAP_BASE, a0);
1472 storeRam32(A_HEAP_SIZE, a1);
1473 storeRam32(A_HEAP_END, a0 + (a1 & ~3) + 4);
1474 storeRam32(A_HEAP_INIT_FLG, 0);
1477 mips_return_void_c(14);
1480 void psxBios_getchar() { //0x3b
1481 v0 = getchar(); pc0 = ra;
1484 static void psxBios_printf_psxout() { // 0x3f
1487 u32 save[4] = { 0, };
1493 if (psp != INVALID_PTR) {
1494 memcpy(save, psp, 4 * 4);
1495 psxMu32ref(sp) = SWAP32((u32)a0);
1496 psxMu32ref(sp + 4) = SWAP32((u32)a1);
1497 psxMu32ref(sp + 8) = SWAP32((u32)a2);
1498 psxMu32ref(sp + 12) = SWAP32((u32)a3);
1510 tmp2[j++] = Ra0[i]; goto _start;
1512 if (Ra0[i] >= '0' && Ra0[i] <= '9') {
1523 ptmp += sprintf(ptmp, tmp2, (float)psxMu32(sp + n * 4)); n++; break;
1527 ptmp += sprintf(ptmp, tmp2, (double)psxMu32(sp + n * 4)); n++; break;
1533 ptmp += sprintf(ptmp, tmp2, (unsigned int)psxMu32(sp + n * 4)); n++; break;
1535 ptmp += sprintf(ptmp, tmp2, (unsigned char)psxMu32(sp + n * 4)); n++; break;
1537 ptmp += sprintf(ptmp, tmp2, (char*)PSXM(psxMu32(sp + n * 4))); n++; break;
1539 *ptmp++ = Ra0[i]; break;
1549 if (psp != INVALID_PTR)
1550 memcpy(psp, save, 4 * 4);
1553 SysPrintf("%s", tmp);
1556 void psxBios_printf() { // 0x3f
1557 psxBios_printf_psxout();
1561 static void psxBios_cd() { // 0x40
1562 const char *p, *dir = Ra0;
1563 PSXBIOS_LOG("psxBios_%s %x(%s)\n", biosB0n[0x40], a0, dir);
1564 if (dir != INVALID_PTR) {
1565 if ((p = strchr(dir, ':')))
1569 snprintf(cdir, sizeof(cdir), "%s", dir);
1571 mips_return_c(1, 100);
1574 static void psxBios_format() { // 0x41
1575 PSXBIOS_LOG("psxBios_%s %x(%s)\n", biosB0n[0x41], a0, Ra0);
1576 if (strcmp(Ra0, "bu00:") == 0 && Config.Mcd1[0] != '\0')
1578 CreateMcd(Config.Mcd1);
1579 LoadMcd(1, Config.Mcd1);
1582 else if (strcmp(Ra0, "bu10:") == 0 && Config.Mcd2[0] != '\0')
1584 CreateMcd(Config.Mcd2);
1585 LoadMcd(2, Config.Mcd2);
1595 static void psxBios_SystemErrorUnresolvedException() {
1596 if (floodchk != 0x12340a40) { // prevent log flood
1597 SysPrintf("psxBios_%s called from %08x\n", biosA0n[0x40], ra);
1598 floodchk = 0x12340a40;
1600 mips_return_void_c(1000);
1603 static void FlushCache() {
1604 psxCpu->Notify(R3000ACPU_NOTIFY_CACHE_ISOLATED, NULL);
1605 psxCpu->Notify(R3000ACPU_NOTIFY_CACHE_UNISOLATED, NULL);
1607 // runs from uncached mem so tons of cycles
1611 // you likely want to mask irqs before calling these
1612 static u8 cdrom_sync(int do_ack)
1615 if (psxRegs.interrupt & (1u << PSXINT_CDR)) {
1616 if ((s32)(psxRegs.cycle - event_cycles[PSXINT_CDR]) < 0)
1617 psxRegs.cycle = event_cycles[PSXINT_CDR] + 1;
1618 irq_test(&psxRegs.CP0);
1622 r = cdrRead3() & 0x1f;
1623 cdrWrite3(0x5f); // ack; clear params
1628 static void cdrom_cmd_and_wait(u8 cmd, int arg_cnt, int resp_cnt, ...)
1634 va_start(ap, resp_cnt);
1635 while (arg_cnt-- > 0)
1636 cdrWrite2(va_arg(ap, u32));
1641 u8 r = cdrom_sync(1);
1642 assert(r == 3); (void)r;
1646 u8 r = cdrom_sync(1);
1647 assert(r == 2); (void)r;
1653 * long Load(char *name, struct EXEC *header);
1656 void psxBios_Load() { // 0x42
1657 u8 time[3] = { 2, 0, 0x16 };
1665 PSXBIOS_LOG("psxBios_%s %x(%s), %x\n", biosA0n[0x42], a0, pa0, a1);
1666 if (pa0 == INVALID_PTR || pa1 == INVALID_PTR) {
1670 if ((p = strchr(pa0, ':')))
1675 snprintf(path, sizeof(path), "%s\\%s", cdir, (char *)pa0);
1677 snprintf(path, sizeof(path), "%s", (char *)pa0);
1679 if (LoadCdromFile(path, &eheader, time) == 0) {
1680 memcpy(pa1, ((char*)&eheader)+16, sizeof(EXEC));
1681 psxCpu->Clear(a1, sizeof(EXEC) / 4);
1685 PSXBIOS_LOG(" -> %d\n", v0);
1689 // set the cdrom to a state of just after exe read
1690 psxRegs.CP0.n.SR &= ~0x404;
1693 cdrWrite2(0x1f); // unmask
1694 cdrom_cmd_and_wait(0x0e, 1, 1, 0x80u); // CdlSetmode
1695 cdrom_cmd_and_wait(0x02, 3, 1, time[0], time[1], time[2]); // CdlSetloc
1696 cdrom_cmd_and_wait(0x15, 0, 2); // CdlSeekL
1697 psxHwWrite16(0x1f801070, ~4);
1698 MTC0(&psxRegs, 12, psxRegs.CP0.n.SR | 0x404);
1702 * int Exec(struct EXEC *header , int argc , char **argv);
1705 void psxBios_Exec() { // 43
1706 EXEC *header = (EXEC *)castRam32ptr(a0);
1710 PSXBIOS_LOG("psxBios_%s: %x, %x, %x\n", biosA0n[0x43], a0, a1, a2);
1712 header->_sp = SWAP32(sp);
1713 header->_fp = SWAP32(fp);
1714 header->_sp = SWAP32(sp);
1715 header->_gp = SWAP32(gp);
1716 header->ret = SWAP32(ra);
1717 header->base = SWAP32(s0);
1719 ptr = SWAP32(header->b_addr);
1720 len = SWAP32(header->b_size);
1726 if (header->S_addr != 0)
1727 sp = fp = SWAP32(header->S_addr) + SWAP32(header->s_size);
1729 gp = SWAP32(header->gp0);
1737 pc0 = SWAP32(header->_pc0);
1740 static void psxBios_FlushCache() { // 44
1741 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x44]);
1746 void psxBios_GPU_dw() { // 0x46
1751 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x46]);
1754 GPU_writeData(0xa0000000);
1755 GPU_writeData((a1<<0x10)|(a0&0xffff));
1756 GPU_writeData((a3<<0x10)|(a2&0xffff));
1758 ptr = (u32*)PSXM(Rsp[4]); //that is correct?
1761 GPU_writeData(SWAPu32(*ptr++));
1767 static void gpu_sync() {
1768 // not implemented...
1769 // might be problematic to do because of Config.GpuListWalking
1770 if (psxRegs.interrupt & (1u << PSXINT_GPUDMA))
1771 log_unhandled("gpu_sync with active dma\n");
1772 mips_return_c(0, 21);
1775 void psxBios_mem2vram() { // 0x47
1777 gpuSyncPluginSR(); // flush
1778 GPU_writeData(0xa0000000);
1779 GPU_writeData((a1<<0x10)|(a0&0xffff));
1780 GPU_writeData((a3<<0x10)|(a2&0xffff));
1781 size = ((((a2 * a3) / 2) >> 4) << 16);
1782 GPU_writeStatus(0x04000002);
1783 psxHwWrite32(0x1f8010f4,0);
1784 psxHwWrite32(0x1f8010f0,psxHwRead32(0x1f8010f0)|0x800);
1785 psxHwWrite32(0x1f8010a0,Rsp[4]);//might have a buggy...
1786 psxHwWrite32(0x1f8010a4, size | 0x10);
1787 psxHwWrite32(0x1f8010a8,0x01000201);
1792 void psxBios_SendGPU() { // 0x48
1793 GPU_writeStatus(a0);
1798 void psxBios_GPU_cw() { // 0x49
1805 void psxBios_GPU_cwb() { // 0x4a
1806 u32 *ptr = (u32*)Ra0;
1811 GPU_writeData(SWAPu32(*ptr++));
1817 void psxBios_GPU_SendPackets() { //4b:
1819 GPU_writeStatus(0x04000002);
1820 psxHwWrite32(0x1f8010f4,0);
1821 psxHwWrite32(0x1f8010f0,psxHwRead32(0x1f8010f0)|0x800);
1822 psxHwWrite32(0x1f8010a0,a0);
1823 psxHwWrite32(0x1f8010a4,0);
1824 psxHwWrite32(0x1f8010a8,0x010000401);
1828 void psxBios_sys_a0_4c() { // 0x4c GPU relate
1829 psxHwWrite32(0x1f8010a8,0x00000401);
1830 GPU_writeData(0x0400000);
1831 GPU_writeData(0x0200000);
1832 GPU_writeData(0x0100000);
1837 void psxBios_GPU_GetGPUStatus() { // 0x4d
1838 v0 = GPU_readStatus();
1844 void psxBios_LoadExec() { // 51
1845 EXEC *header = (EXEC*)PSXM(0xf000);
1849 PSXBIOS_LOG("psxBios_%s: %s: %x,%x\n", biosA0n[0x51], Ra0, a1, a2);
1851 s_addr = a1; s_size = a2;
1856 header->S_addr = s_addr;
1857 header->s_size = s_size;
1859 a0 = 0xf000; a1 = 0; a2 = 0;
1863 static void psxBios__bu_init() { // 70
1864 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x70]);
1866 DeliverEvent(0xf0000011, 0x0004);
1867 DeliverEvent(0xf4000001, 0x0004);
1872 static void write_chain(u32 *d, u32 next, u32 handler1, u32 handler2);
1873 static void psxBios_SysEnqIntRP_(u32 priority, u32 chain_eptr);
1874 static void psxBios_SysDeqIntRP_(u32 priority, u32 chain_rm_eptr);
1876 static void psxBios_EnqueueCdIntr_(void)
1878 u32 *ram32 = (u32 *)psxM;
1880 // traps should already be installed by write_chain()
1881 ram32[0x91d0/4] = 0;
1882 ram32[0x91d4/4] = SWAP32(0xbfc0506c);
1883 ram32[0x91d8/4] = SWAP32(0xbfc04dec);
1884 psxBios_SysEnqIntRP_(0, 0x91d0);
1885 ram32[0x91e0/4] = 0;
1886 ram32[0x91e4/4] = SWAP32(0xbfc050a4);
1887 ram32[0x91e8/4] = SWAP32(0xbfc04fbc);
1888 psxBios_SysEnqIntRP_(0, 0x91e0);
1892 static void setup_cd_irq_and_events(void)
1894 u16 specs[] = { 0x10, 0x20, 0x40, 0x80, 0x8000 };
1897 psxBios_EnqueueCdIntr_();
1899 for (i = 0; i < sizeof(specs) / sizeof(specs[0]); i++) {
1900 u32 h = OpenEvent(0xf0000003, specs[i], EvMdMARK, 0);
1902 storeRam32(A_CD_EVENTS + i * 4, h);
1907 static void psxBios_CdReset_() {
1908 psxRegs.CP0.n.SR &= ~0x404; // disable interrupts
1912 cdrWrite2(0x1f); // unmask
1913 cdrom_cmd_and_wait(0x0a, 0, 2); // CdlReset
1914 cdrom_cmd_and_wait(0x0e, 1, 1, 0x80u); // CdlSetmode
1916 // todo(?): should read something (iso root directory?)
1917 // from { 0, 2, 16 } to somewhere and pause
1920 psxHwWrite16(0x1f801070, ~4);
1921 MTC0(&psxRegs, 12, psxRegs.CP0.n.SR | 0x404);
1922 DeliverEvent(0xf0000003, 0x0020);
1925 static void psxBios_CdInit() { // 54, 71
1926 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x71]);
1927 setup_cd_irq_and_events();
1931 // this function takes pretty much forever
1932 mips_return_c(0, 50000*11);
1935 static void psxBios_DequeueCdIntr_() {
1936 psxBios_SysDeqIntRP_(0, 0x91d0);
1937 psxBios_SysDeqIntRP_(0, 0x91e0);
1941 static void psxBios_CdReset() { // 95
1942 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x95]);
1946 static void psxBios_EnqueueCdIntr() { // a2
1947 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0xa2]);
1948 psxBios_EnqueueCdIntr_();
1949 // return value comes from SysEnqIntRP() insternal call
1952 static void psxBios_DequeueCdIntr() { // a3
1953 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0xa3]);
1954 psxBios_DequeueCdIntr_();
1957 static void psxBios_CdRemove() { // 56, 72
1958 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x72]);
1960 CloseEvent(loadRam32(A_CD_EVENTS + 0x00));
1961 CloseEvent(loadRam32(A_CD_EVENTS + 0x04));
1962 CloseEvent(loadRam32(A_CD_EVENTS + 0x08));
1963 CloseEvent(loadRam32(A_CD_EVENTS + 0x0c));
1964 CloseEvent(loadRam32(A_CD_EVENTS + 0x10));
1965 psxBios_DequeueCdIntr_();
1967 // EnterCriticalSection - should be done at the beginning,
1968 // but this way is much easier to implement
1974 static void setup_tt(u32 tcb_cnt, u32 evcb_cnt, u32 stack);
1976 static void psxBios_SetConf() { // 9c
1977 PSXBIOS_LOG("psxBios_%s %x %x %x\n", biosA0n[0x9c], a0, a1, a2);
1978 setup_tt(a1, a0, a2);
1979 psxRegs.CP0.n.SR |= 0x401;
1980 mips_return_void_c(500);
1983 static void psxBios_GetConf() { // 9d
1984 PSXBIOS_LOG("psxBios_%s %x %x %x\n", biosA0n[0x9d], a0, a1, a2);
1985 storeRam32(a0, loadRam32(A_CONF_EvCB));
1986 storeRam32(a1, loadRam32(A_CONF_TCB));
1987 storeRam32(a2, loadRam32(A_CONF_SP));
1988 mips_return_void_c(10);
1991 void psxBios_SetMem() { // 9f
1992 u32 new = psxHu32(0x1060);
1995 PSXBIOS_LOG("psxBios_%s: %x, %x\n", biosA0n[0x9f], a0, a1);
2000 psxHu32ref(0x1060) = SWAP32(new);
2001 psxMu32ref(0x060) = a0;
2002 PSXBIOS_LOG("Change effective memory : %d MBytes\n",a0);
2006 psxHu32ref(0x1060) = SWAP32(new | 0x300);
2007 psxMu32ref(0x060) = a0;
2008 PSXBIOS_LOG("Change effective memory : %d MBytes\n",a0);
2011 PSXBIOS_LOG("Effective memory must be 2/8 MBytes\n");
2018 /* TODO FIXME : Not compliant. -1 indicates failure but using 1 for now. */
2019 static void psxBios_get_cd_status() // a6
2021 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0xa6]);
2026 static void psxBios_GetSystemInfo() { // b4
2028 //PSXBIOS_LOG("psxBios_%s %x\n", biosA0n[0xb4], a0);
2029 SysPrintf("psxBios_%s %x\n", biosA0n[0xb4], a0);
2032 case 1: ret = SWAP32(((u32 *)psxR)[0x100/4 + a0]); break;
2033 case 2: ret = 0xbfc0012c; break;
2034 case 5: ret = loadRam32(0x60) << 10; break;
2036 mips_return_c(ret, 20);
2039 /* System calls B0 */
2041 static u32 psxBios_SysMalloc_(u32 size);
2043 static void psxBios_SysMalloc() { // B 00
2044 u32 ret = psxBios_SysMalloc_(a0);
2046 PSXBIOS_LOG("psxBios_%s 0x%x -> %x\n", biosB0n[0x00], a0, ret);
2047 mips_return_c(ret, 33);
2050 void psxBios_SetRCnt() { // 02
2052 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x02]);
2059 psxRcntWtarget(a0, a1);
2060 if (a2&0x1000) mode|= 0x050; // Interrupt Mode
2061 if (a2&0x0100) mode|= 0x008; // Count to 0xffff
2062 if (a2&0x0010) mode|= 0x001; // Timer stop mode
2063 if (a0 == 2) { if (a2&0x0001) mode|= 0x200; } // System Clock mode
2064 else { if (a2&0x0001) mode|= 0x100; } // System Clock mode
2066 psxRcntWmode(a0, mode);
2071 void psxBios_GetRCnt() { // 03
2073 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x03]);
2078 case 0: v0 = psxRcntRcount0(); break;
2079 case 1: v0 = psxRcntRcount1(); break;
2080 case 2: v0 = psxRcntRcount2(); break;
2081 case 3: v0 = 0; break;
2086 void psxBios_StartRCnt() { // 04
2088 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x04]);
2092 if (a0 != 3) psxHu32ref(0x1074)|= SWAP32((u32)((1<<(a0+4))));
2093 else psxHu32ref(0x1074)|= SWAPu32(0x1);
2097 void psxBios_StopRCnt() { // 05
2099 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x05]);
2103 if (a0 != 3) psxHu32ref(0x1074)&= SWAP32((u32)(~(1<<(a0+4))));
2104 else psxHu32ref(0x1074)&= SWAPu32(~0x1);
2108 void psxBios_ResetRCnt() { // 06
2110 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x06]);
2115 psxRcntWmode(a0, 0);
2116 psxRcntWtarget(a0, 0);
2117 psxRcntWcount(a0, 0);
2122 static u32 DeliverEvent(u32 class, u32 spec) {
2123 EvCB *ev, *ev_first = (EvCB *)loadRam32ptr(A_TT_EvCB);
2124 u32 evcb_len = loadRam32(A_TT_EvCB + 4);
2125 u32 ret = loadRam32(A_TT_EvCB) + evcb_len;
2126 u32 i, lim = evcb_len / 0x1c;
2128 //printf("%s %08x %x\n", __func__, class, spec);
2129 for (i = 0, ev = ev_first; i < lim; i++, ev++) {
2131 if (SWAP32(ev->status) != EvStACTIVE)
2134 if (SWAP32(ev->class) != class)
2137 if (SWAP32(ev->spec) != spec)
2140 ret = SWAP32(ev->mode);
2141 if (ret == EvMdMARK) {
2142 if (ev->status != SWAP32(EvStALREADY))
2143 PSXBIOS_EV_LOG("DeliverEvent %08x %x (%08zx) set\n",
2144 class, spec, (ev - ev_first) | 0xf1000000u);
2145 ev->status = SWAP32(EvStALREADY);
2149 if (ret == EvMdCALL) {
2150 ret = SWAP32(ev->fhandler);
2151 PSXBIOS_EV_LOG("DeliverEvent %08x %x (%08zx) cb %x\n",
2152 class, spec, (ev - ev_first) | 0xf1000000u, ret);
2165 static u32 UnDeliverEvent(u32 class, u32 spec) {
2166 EvCB *ev = (EvCB *)loadRam32ptr(A_TT_EvCB);
2167 u32 evcb_len = loadRam32(A_TT_EvCB + 4);
2168 u32 ret = loadRam32(A_TT_EvCB) + evcb_len;
2169 u32 i, lim = evcb_len / 0x1c;
2171 for (i = 0; i < lim; i++, ev++) {
2173 if (SWAP32(ev->status) != EvStALREADY)
2176 if (SWAP32(ev->class) != class)
2179 if (SWAP32(ev->spec) != spec)
2182 if (SWAP32(ev->mode) == EvMdMARK)
2183 ev->status = SWAP32(EvStACTIVE);
2189 static void psxBios_DeliverEvent() { // 07
2191 PSXBIOS_LOG("psxBios_%s %x %04x\n", biosB0n[0x07], a0, a1);
2193 ret = DeliverEvent(a0, a1);
2197 static s32 get_free_EvCB_slot() {
2198 EvCB *ev = (EvCB *)loadRam32ptr(A_TT_EvCB);
2199 u32 i, lim = loadRam32(A_TT_EvCB + 4) / 0x1c;
2202 for (i = 0; i < lim; i++, ev++) {
2204 if (ev->status == SWAP32(EvStUNUSED))
2210 static u32 OpenEvent(u32 class, u32 spec, u32 mode, u32 func) {
2211 u32 ret = get_free_EvCB_slot();
2212 if ((s32)ret >= 0) {
2213 EvCB *ev = (EvCB *)loadRam32ptr(A_TT_EvCB) + ret;
2214 ev->class = SWAP32(class);
2215 ev->status = SWAP32(EvStDISABLED);
2216 ev->spec = SWAP32(spec);
2217 ev->mode = SWAP32(mode);
2218 ev->fhandler = SWAP32(func);
2224 static void psxBios_OpenEvent() { // 08
2225 u32 ret = OpenEvent(a0, a1, a2, a3);
2226 PSXBIOS_LOG("psxBios_%s (class:%x, spec:%04x, mode:%04x, func:%x) -> %x\n",
2227 biosB0n[0x08], a0, a1, a2, a3, ret);
2228 mips_return_c(ret, 36);
2231 static void CloseEvent(u32 ev)
2233 u32 base = loadRam32(A_TT_EvCB);
2234 storeRam32(base + (ev & 0xffff) * sizeof(EvCB) + 4, EvStUNUSED);
2237 static void psxBios_CloseEvent() { // 09
2238 PSXBIOS_LOG("psxBios_%s %x (%x)\n", biosB0n[0x09], a0,
2239 loadRam32(loadRam32(A_TT_EvCB) + (a0 & 0xffff) * sizeof(EvCB) + 4));
2241 mips_return_c(1, 10);
2244 static void psxBios_WaitEvent() { // 0a
2245 u32 base = loadRam32(A_TT_EvCB);
2246 u32 status = loadRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4);
2247 PSXBIOS_LOG("psxBios_%s %x (status=%x)\n", biosB0n[0x0a], a0, status);
2250 if (status == EvStALREADY) {
2251 storeRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4, EvStACTIVE);
2255 if (status != EvStACTIVE)
2257 mips_return_c(0, 2);
2261 // retrigger this hlecall after the next emulation event
2263 if ((s32)(next_interupt - psxRegs.cycle) > 0)
2264 psxRegs.cycle = next_interupt;
2268 static void psxBios_TestEvent() { // 0b
2269 u32 base = loadRam32(A_TT_EvCB);
2270 u32 status = loadRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4);
2273 if (psxRegs.cycle - floodchk > 16*1024u) { // prevent log flood
2274 PSXBIOS_LOG("psxBios_%s %x %x\n", biosB0n[0x0b], a0, status);
2275 floodchk = psxRegs.cycle;
2277 if (status == EvStALREADY) {
2278 storeRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4, EvStACTIVE);
2282 mips_return_c(ret, 15);
2285 static void EnableEvent(u32 ev, int do_log) {
2286 u32 base = loadRam32(A_TT_EvCB);
2287 u32 status = loadRam32(base + (ev & 0xffff) * sizeof(EvCB) + 4);
2289 PSXBIOS_LOG("psxBios_%s %x (%x)\n", biosB0n[0x0c], ev, status);
2290 if (status != EvStUNUSED)
2291 storeRam32(base + (ev & 0xffff) * sizeof(EvCB) + 4, EvStACTIVE);
2294 static void psxBios_EnableEvent() { // 0c
2296 mips_return_c(1, 15);
2299 static void psxBios_DisableEvent() { // 0d
2300 u32 base = loadRam32(A_TT_EvCB);
2301 u32 status = loadRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4);
2302 PSXBIOS_LOG("psxBios_%s %x: %x\n", biosB0n[0x0d], a0, status);
2303 if (status != EvStUNUSED)
2304 storeRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4, EvStDISABLED);
2306 mips_return_c(1, 15);
2310 * long OpenTh(long (*func)(), unsigned long sp, unsigned long gp);
2313 void psxBios_OpenTh() { // 0e
2314 TCB *tcb = loadRam32ptr(A_TT_TCB);
2315 u32 limit = loadRam32(A_TT_TCB + 4) / 0xc0u;
2318 for (th = 1; th < limit; th++)
2320 if (tcb[th].status != SWAP32(0x4000)) break;
2324 // Feb 2019 - Added out-of-bounds fix caught by cppcheck:
2325 // When no free TCB is found, return 0xffffffff according to Nocash doc.
2327 PSXBIOS_LOG("\t%s() WARNING! No Free TCBs found!\n", __func__);
2329 mips_return_c(0xffffffff, 20);
2332 PSXBIOS_LOG("psxBios_%s -> %x\n", biosB0n[0x0e], 0xff000000 + th);
2334 tcb[th].status = SWAP32(0x4000);
2335 tcb[th].mode = SWAP32(0x1000);
2336 tcb[th].epc = SWAP32(a0);
2337 tcb[th].reg[30] = SWAP32(a1); // fp
2338 tcb[th].reg[29] = SWAP32(a1); // sp
2339 tcb[th].reg[28] = SWAP32(a2); // gp
2341 mips_return_c(0xff000000 + th, 34);
2345 * int CloseTh(long thread);
2348 static void psxBios_CloseTh() { // 0f
2349 u32 tcb = loadRam32(A_TT_TCB);
2350 u32 th = a0 & 0xffff;
2352 PSXBIOS_LOG("psxBios_%s %x\n", biosB0n[0x0f], a0);
2353 // in the usual bios fashion no checks, just write and return 1
2354 storeRam32(tcb + th * sizeof(TCB), 0x1000);
2356 mips_return_c(1, 11);
2360 * int ChangeTh(long thread);
2363 void psxBios_ChangeTh() { // 10
2364 u32 tcbBase = loadRam32(A_TT_TCB);
2365 u32 th = a0 & 0xffff;
2367 // this is quite spammy
2368 //PSXBIOS_LOG("psxBios_%s %x\n", biosB0n[0x10], th);
2370 // without doing any argument checks, just issue a syscall
2371 // (like the real bios does)
2373 a1 = tcbBase + th * sizeof(TCB);
2378 void psxBios_InitPAD() { // 0x12
2379 u32 i, *ram32 = (u32 *)psxM;
2380 PSXBIOS_LOG("psxBios_%s %x %x %x %x\n", biosB0n[0x12], a0, a1, a2, a3);
2382 // printf("%s", "PS-X Control PAD Driver Ver 3.0");
2383 ram32[A_PAD_DR_DST/4] = 0;
2384 ram32[A_PAD_OUTBUF/4 + 0] = 0;
2385 ram32[A_PAD_OUTBUF/4 + 1] = 0;
2386 ram32[A_PAD_OUT_LEN/4 + 0] = 0;
2387 ram32[A_PAD_OUT_LEN/4 + 1] = 0;
2388 ram32[A_PAD_INBUF/4 + 0] = SWAP32(a0);
2389 ram32[A_PAD_INBUF/4 + 1] = SWAP32(a2);
2390 ram32[A_PAD_IN_LEN/4 + 0] = SWAP32(a1);
2391 ram32[A_PAD_IN_LEN/4 + 1] = SWAP32(a3);
2393 for (i = 0; i < a1; i++) {
2395 storeRam8(a0 + i, 0);
2397 for (i = 0; i < a3; i++) {
2399 storeRam8(a2 + i, 0);
2401 write_chain(ram32 + A_PADCRD_CHN_E/4, 0, 0x49bc, 0x4a4c);
2403 ram32[A_PAD_IRQR_ENA/4] = SWAP32(1);
2405 mips_return_c(1, 200);
2408 void psxBios_StartPAD() { // 13
2409 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x13]);
2411 psxBios_SysDeqIntRP_(2, A_PADCRD_CHN_E);
2412 psxBios_SysEnqIntRP_(2, A_PADCRD_CHN_E);
2413 psxHwWrite16(0x1f801070, ~1);
2414 psxHwWrite16(0x1f801074, psxHu32(0x1074) | 1);
2415 storeRam32(A_PAD_ACK_VBL, 1);
2416 storeRam32(A_RCNT_VBL_ACK + (3 << 2), 0);
2417 psxRegs.CP0.n.SR |= 0x401;
2419 mips_return_c(1, 300);
2422 void psxBios_StopPAD() { // 14
2423 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x14]);
2424 storeRam32(A_RCNT_VBL_ACK + (3 << 2), 1);
2425 psxBios_SysDeqIntRP_(2, A_PADCRD_CHN_E);
2426 psxRegs.CP0.n.SR |= 0x401;
2427 mips_return_void_c(200);
2430 static void psxBios_PAD_init() { // 15
2432 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x15]);
2433 if (a0 == 0x20000000 || a0 == 0x20000001)
2436 a0 = A_PAD_DR_BUF1; a1 = 0x22;
2437 a2 = A_PAD_DR_BUF2; a3 = 0x22;
2440 storeRam32(A_PAD_DR_DST, dst);
2443 mips_return_c(ret, 100);
2446 static u32 psxBios_PAD_dr_() {
2447 u8 *dst = loadRam32ptr(A_PAD_DR_DST);
2448 u8 *buf1 = castRam8ptr(A_PAD_DR_BUF1);
2449 u8 *buf2 = castRam8ptr(A_PAD_DR_BUF2);
2450 dst[0] = dst[1] = dst[2] = dst[3] = ~0;
2451 if (buf1[0] == 0 && (buf1[1] == 0x23 || buf1[1] == 0x41))
2453 dst[0] = buf1[3], dst[1] = buf1[2];
2454 if (buf1[1] == 0x23) {
2455 dst[0] |= 0xc7, dst[1] |= 7;
2456 if (buf1[5] >= 0x10) dst[0] &= ~(1u << 6);
2457 if (buf1[6] >= 0x10) dst[0] &= ~(1u << 7);
2460 if (buf2[0] == 0 && (buf2[1] == 0x23 || buf2[1] == 0x41))
2462 dst[2] = buf2[3], dst[3] = buf2[2];
2463 if (buf2[1] == 0x23) {
2464 dst[2] |= 0xc7, dst[3] |= 7;
2465 if (buf2[5] >= 0x10) dst[2] &= ~(1u << 6);
2466 if (buf2[6] >= 0x10) dst[2] &= ~(1u << 7);
2470 return SWAP32(*(u32 *)dst);
2473 static void psxBios_PAD_dr() { // 16
2474 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x16]);
2475 u32 ret = psxBios_PAD_dr_();
2479 static void psxBios_ReturnFromException() { // 17
2480 u32 tcbPtr = loadRam32(A_TT_PCB);
2481 const TCB *tcb = loadRam32ptr(tcbPtr);
2485 for (i = 1; i < 32; i++)
2486 psxRegs.GPR.r[i] = SWAP32(tcb->reg[i]);
2487 psxRegs.GPR.n.lo = SWAP32(tcb->lo);
2488 psxRegs.GPR.n.hi = SWAP32(tcb->hi);
2489 sr = SWAP32(tcb->sr);
2491 //printf("%s %08x->%08x %u\n", __func__, pc0, tcb->epc, psxRegs.cycle);
2492 pc0 = k0 = SWAP32(tcb->epc);
2494 // the interpreter wants to know about sr changes, so do a MTC0
2495 sr = (sr & ~0x0f) | ((sr & 0x3c) >> 2);
2496 MTC0(&psxRegs, 12, sr);
2502 void psxBios_ResetEntryInt() { // 18
2503 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x18]);
2505 storeRam32(A_EEXIT_PTR, A_EEXIT_DEF);
2506 mips_return_void_c(5);
2509 void psxBios_HookEntryInt() { // 19
2510 PSXBIOS_LOG("psxBios_%s %x\n", biosB0n[0x19], a0);
2512 storeRam32(A_EEXIT_PTR, a0);
2513 mips_return_void_c(3);
2516 static void psxBios_UnDeliverEvent() { // 0x20
2518 PSXBIOS_LOG("psxBios_%s %x %x\n", biosB0n[0x20], a0, a1);
2520 ret = UnDeliverEvent(a0, a1);
2524 static void buopen(int mcd, char *ptr, char *cfg)
2527 char *mcd_data = ptr;
2529 strcpy(FDesc[1 + mcd].name, Ra0+5);
2530 FDesc[1 + mcd].offset = 0;
2531 FDesc[1 + mcd].mode = a1;
2533 for (i=1; i<16; i++) {
2534 const char *fptr = mcd_data + 128 * i;
2535 if ((*fptr & 0xF0) != 0x50) continue;
2536 if (strcmp(FDesc[1 + mcd].name, fptr+0xa)) continue;
2537 FDesc[1 + mcd].mcfile = i;
2538 PSXBIOS_LOG("open %s\n", fptr+0xa);
2542 if (a1 & 0x200 && v0 == -1) { /* FCREAT */
2543 for (i=1; i<16; i++) {
2544 int j, xor, nblk = a1 >> 16;
2546 char *fptr = mcd_data + 128 * i;
2548 if ((*fptr & 0xF0) != 0xa0) continue;
2550 FDesc[1 + mcd].mcfile = i;
2553 fptr[5] = 0x20 * nblk;
2556 strcpy(fptr+0xa, FDesc[1 + mcd].name);
2557 pptr = fptr2 = fptr;
2558 for(j=2; j<=nblk; j++) {
2560 for(i++; i<16; i++) {
2563 memset(fptr2, 0, 128);
2564 fptr2[0] = j < nblk ? 0x52 : 0x53;
2567 for (k=0, xor=0; k<127; k++) xor^= pptr[k];
2572 /* shouldn't this return ENOSPC if i == 16? */
2574 pptr[8] = pptr[9] = 0xff;
2575 for (j=0, xor=0; j<127; j++) xor^= pptr[j];
2577 PSXBIOS_LOG("openC %s %d\n", ptr, nblk);
2579 /* just go ahead and resave them all */
2580 SaveMcd(cfg, ptr, 128, 128 * 15);
2583 /* shouldn't this return ENOSPC if i == 16? */
2588 * int open(char *name , int mode);
2591 void psxBios_open() { // 0x32
2594 PSXBIOS_LOG("psxBios_%s %s %x\n", biosB0n[0x32], Ra0, a1);
2598 if (pa0 != INVALID_PTR) {
2599 if (!strncmp(pa0, "bu00", 4)) {
2600 buopen(1, Mcd1Data, Config.Mcd1);
2603 if (!strncmp(pa0, "bu10", 4)) {
2604 buopen(2, Mcd2Data, Config.Mcd2);
2612 * int lseek(int fd , int offset , int whence);
2615 void psxBios_lseek() { // 0x33
2617 PSXBIOS_LOG("psxBios_%s: %x, %x, %x\n", biosB0n[0x33], a0, a1, a2);
2622 FDesc[a0].offset = a1;
2624 // DeliverEvent(0xf0000011, 0x0004);
2625 // DeliverEvent(0xf4000001, 0x0004);
2629 FDesc[a0].offset+= a1;
2630 v0 = FDesc[a0].offset;
2639 * int read(int fd , void *buf , int nbytes);
2642 void psxBios_read() { // 0x34
2647 PSXBIOS_LOG("psxBios_%s: %x, %x, %x\n", biosB0n[0x34], a0, a1, a2);
2652 if (pa1 != INVALID_PTR) {
2654 case 2: buread(pa1, 1, a2); break;
2655 case 3: buread(pa1, 2, a2); break;
2663 * int write(int fd , void *buf , int nbytes);
2666 void psxBios_write() { // 0x35/0x03
2670 if (a0 != 1) // stdout
2671 PSXBIOS_LOG("psxBios_%s: %x,%x,%x\n", biosB0n[0x35], a0, a1, a2);
2674 if (pa1 == INVALID_PTR) {
2679 if (a0 == 1) { // stdout
2683 if (Config.PsxOut) while (a2 > 0) {
2684 SysPrintf("%c", *ptr++); a2--;
2690 case 2: buwrite(pa1, 1, a2); break;
2691 case 3: buwrite(pa1, 2, a2); break;
2697 static void psxBios_write_psxout() {
2698 if (a0 == 1) { // stdout
2699 const char *ptr = Ra1;
2702 if (ptr != INVALID_PTR)
2704 SysPrintf("%c", *ptr++);
2708 static void psxBios_putchar_psxout() { // 3d
2709 SysPrintf("%c", (char)a0);
2712 static void psxBios_puts_psxout() { // 3e/3f
2713 SysPrintf("%s", Ra0);
2717 * int close(int fd);
2720 void psxBios_close() { // 0x36
2722 PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x36], a0);
2729 void psxBios_putchar() { // 3d
2730 if (Config.PsxOut) SysPrintf("%c", (char)a0);
2734 void psxBios_puts() { // 3e/3f
2735 if (Config.PsxOut) SysPrintf("%s", Ra0);
2739 static void bufile(const u8 *mcd_data, u32 dir_) {
2740 struct DIRENTRY *dir = (struct DIRENTRY *)PSXM(dir_);
2741 const char *pfile = ffile + 5;
2742 const u8 *data = mcd_data;
2743 int i = 0, match = 0;
2748 if (dir == INVALID_PTR)
2751 for (; nfile <= 15 && !match; nfile++) {
2754 head = nfile * 0x40;
2755 data = mcd_data + 128 * nfile;
2756 name = (const char *)data + 0x0a;
2757 if ((data[0] & 0xF0) != 0x50) continue;
2758 /* Bug link files show up as free block. */
2759 if (!name[0]) continue;
2761 for (i = 0; i < 20; i++) {
2762 if (pfile[i] == name[i] || pfile[i] == '?')
2763 dir->name[i] = name[i];
2764 else if (pfile[i] == '*') {
2765 int len = strlen(name + i);
2768 memcpy(dir->name + i, name + i, len + 1);
2779 PSXBIOS_LOG("%d : %s = %s + %s (match=%d)\n",
2780 nfile, dir->name, pfile, name, match);
2782 for (; nfile <= 15; nfile++, blocks++) {
2783 const u8 *data2 = mcd_data + 128 * nfile;
2784 const char *name = (const char *)data2 + 0x0a;
2785 if ((data2[0] & 0xF0) != 0x50 || name[0])
2789 // nul char of full lenth name seems to overwrite .attr
2790 dir->attr = SWAP32(i < 20 ? data[0] & 0xf0 : 0); // ?
2791 dir->size = 8192 * blocks;
2795 PSXBIOS_LOG(" -> %x '%s' %x %x %x %x\n", v0, v0 ? dir->name : "",
2796 dir->attr, dir->size, dir->next, dir->head);
2800 * struct DIRENTRY* firstfile(char *name,struct DIRENTRY *dir);
2803 static void psxBios_firstfile() { // 42
2806 PSXBIOS_LOG("psxBios_%s %s %x\n", biosB0n[0x42], pa0, a1);
2809 if (pa0 != INVALID_PTR)
2811 snprintf(ffile, sizeof(ffile), "%s", pa0);
2813 strcpy(ffile + 5, "*"); // maybe?
2815 if (!strncmp(pa0, "bu00", 4)) {
2816 // firstfile() calls _card_read() internally, so deliver it's event
2817 DeliverEvent(0xf0000011, 0x0004);
2818 bufile((u8 *)Mcd1Data, a1);
2819 } else if (!strncmp(pa0, "bu10", 4)) {
2820 // firstfile() calls _card_read() internally, so deliver it's event
2821 DeliverEvent(0xf0000011, 0x0004);
2822 bufile((u8 *)Mcd2Data, a1);
2830 * struct DIRENTRY* nextfile(struct DIRENTRY *dir);
2833 void psxBios_nextfile() { // 43
2834 PSXBIOS_LOG("psxBios_%s %x\n", biosB0n[0x43], a0);
2837 if (!strncmp(ffile, "bu00", 4))
2838 bufile((u8 *)Mcd1Data, a0);
2839 else if (!strncmp(ffile, "bu10", 4))
2840 bufile((u8 *)Mcd2Data, a0);
2845 #define burename(mcd) { \
2846 for (i=1; i<16; i++) { \
2847 int namelen, j, xor = 0; \
2848 ptr = Mcd##mcd##Data + 128 * i; \
2849 if ((*ptr & 0xF0) != 0x50) continue; \
2850 if (strcmp(Ra0+5, ptr+0xa)) continue; \
2851 namelen = strlen(Ra1+5); \
2852 memcpy(ptr+0xa, Ra1+5, namelen); \
2853 memset(ptr+0xa+namelen, 0, 0x75-namelen); \
2854 for (j=0; j<127; j++) xor^= ptr[j]; \
2856 SaveMcd(Config.Mcd##mcd, Mcd##mcd##Data, 128 * i + 0xa, 0x76); \
2863 * int rename(char *old, char *new);
2866 void psxBios_rename() { // 44
2873 PSXBIOS_LOG("psxBios_%s: %s,%s\n", biosB0n[0x44], Ra0, Ra1);
2878 if (pa0 != INVALID_PTR && pa1 != INVALID_PTR) {
2879 if (!strncmp(pa0, "bu00", 4) && !strncmp(pa1, "bu00", 4)) {
2883 if (!strncmp(pa0, "bu10", 4) && !strncmp(pa1, "bu10", 4)) {
2892 #define budelete(mcd) { \
2893 for (i=1; i<16; i++) { \
2894 ptr = Mcd##mcd##Data + 128 * i; \
2895 if ((*ptr & 0xF0) != 0x50) continue; \
2896 if (strcmp(Ra0+5, ptr+0xa)) continue; \
2897 *ptr = (*ptr & 0xf) | 0xA0; \
2898 SaveMcd(Config.Mcd##mcd, Mcd##mcd##Data, 128 * i, 1); \
2899 PSXBIOS_LOG("delete %s\n", ptr+0xa); \
2906 * int delete(char *name);
2909 void psxBios_delete() { // 45
2915 PSXBIOS_LOG("psxBios_%s: %s\n", biosB0n[0x45], Ra0);
2920 if (pa0 != INVALID_PTR) {
2921 if (!strncmp(pa0, "bu00", 4)) {
2925 if (!strncmp(pa0, "bu10", 4)) {
2933 void psxBios_InitCARD() { // 4a
2934 u8 *ram8 = (u8 *)psxM;
2935 u32 *ram32 = (u32 *)psxM;
2936 PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x4a], a0);
2937 write_chain(ram32 + A_PADCRD_CHN_E/4, 0, 0x49bc, 0x4a4c);
2939 ram8[A_CARD_ISLOT] = 0;
2940 ram8[A_CARD_STATUS1] = 1;
2941 ram8[A_CARD_STATUS2] = 1;
2942 // (maybe) todo: early_card_irq, etc
2944 ram32[A_PAD_IRQR_ENA/4] = SWAP32(a0);
2946 psxBios_FlushCache();
2947 mips_return_c(0, 34+13+15+6);
2950 void psxBios_StartCARD() { // 4b
2951 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x4b]);
2952 psxBios_SysDeqIntRP_(2, A_PADCRD_CHN_E);
2953 psxBios_SysEnqIntRP_(2, A_PADCRD_CHN_E);
2955 psxHwWrite16(0x1f801074, psxHu32(0x1074) | 1);
2956 storeRam32(A_PAD_ACK_VBL, 1);
2957 storeRam32(A_RCNT_VBL_ACK + (3 << 2), 0);
2958 storeRam32(A_CARD_IRQR_ENA, 1);
2959 psxRegs.CP0.n.SR |= 0x401;
2961 mips_return_c(1, 200);
2964 void psxBios_StopCARD() { // 4c
2965 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x4c]);
2966 storeRam32(A_RCNT_VBL_ACK + (3 << 2), 1);
2967 psxBios_SysDeqIntRP_(2, A_PADCRD_CHN_E);
2968 storeRam32(A_CARD_IRQR_ENA, 0);
2969 psxRegs.CP0.n.SR |= 0x401;
2970 mips_return_void_c(200);
2973 void psxBios__card_write() { // 0x4e
2977 PSXBIOS_LOG("psxBios_%s %02x,%x,%x\n", biosB0n[0x4e], a0, a1, a2);
2978 // function also accepts sector 400h (a bug),
2979 // but what actually happens then?
2982 /* Invalid sectors */
2986 storeRam32(A_CARD_ACHAN, a0);
2989 if (pa2 != INVALID_PTR && a1 < 0x400) {
2991 memcpy(Mcd1Data + a1 * 128, pa2, 128);
2992 SaveMcd(Config.Mcd1, Mcd1Data, a1 * 128, 128);
2994 memcpy(Mcd2Data + a1 * 128, pa2, 128);
2995 SaveMcd(Config.Mcd2, Mcd2Data, a1 * 128, 128);
2999 storeRam8(A_CARD_STATUS1 + port, 4); // busy/write
3000 storeRam32(A_CARD_HANDLER, CARD_HARDLER_READ);
3005 static void psxBios__card_read() { // 0x4f
3009 PSXBIOS_LOG("psxBios_%s %x,%x,%x\n", biosB0n[0x4f], a0, a1, a2);
3012 /* Invalid sectors */
3016 storeRam32(A_CARD_ACHAN, a0);
3019 if (pa2 != INVALID_PTR && a1 < 0x400) {
3021 memcpy(pa2, Mcd1Data + a1 * 128, 128);
3023 memcpy(pa2, Mcd2Data + a1 * 128, 128);
3027 storeRam8(A_CARD_STATUS1 + port, 2); // busy/read
3028 storeRam32(A_CARD_HANDLER, CARD_HARDLER_READ);
3033 void psxBios__new_card() { // 0x50
3035 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x50]);
3041 /* According to a user, this allows Final Fantasy Tactics to save/load properly */
3042 void psxBios__get_error(void) // 55
3044 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x55]);
3049 void psxBios_Krom2RawAdd() { // 0x51
3052 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x51]);
3053 const u32 table_8140[][2] = {
3054 {0x8140, 0x0000}, {0x8180, 0x0762}, {0x81ad, 0x0cc6}, {0x81b8, 0x0ca8},
3055 {0x81c0, 0x0f00}, {0x81c8, 0x0d98}, {0x81cf, 0x10c2}, {0x81da, 0x0e6a},
3056 {0x81e9, 0x13ce}, {0x81f0, 0x102c}, {0x81f8, 0x1590}, {0x81fc, 0x111c},
3057 {0x81fd, 0x1626}, {0x824f, 0x113a}, {0x8259, 0x20ee}, {0x8260, 0x1266},
3058 {0x827a, 0x24cc}, {0x8281, 0x1572}, {0x829b, 0x28aa}, {0x829f, 0x187e},
3059 {0x82f2, 0x32dc}, {0x8340, 0x2238}, {0x837f, 0x4362}, {0x8380, 0x299a},
3060 {0x8397, 0x4632}, {0x839f, 0x2c4c}, {0x83b7, 0x49f2}, {0x83bf, 0x2f1c},
3061 {0x83d7, 0x4db2}, {0x8440, 0x31ec}, {0x8461, 0x5dde}, {0x8470, 0x35ca},
3062 {0x847f, 0x6162}, {0x8480, 0x378c}, {0x8492, 0x639c}, {0x849f, 0x39a8},
3066 const u32 table_889f[][2] = {
3067 {0x889f, 0x3d68}, {0x8900, 0x40ec}, {0x897f, 0x4fb0}, {0x8a00, 0x56f4},
3068 {0x8a7f, 0x65b8}, {0x8b00, 0x6cfc}, {0x8b7f, 0x7bc0}, {0x8c00, 0x8304},
3069 {0x8c7f, 0x91c8}, {0x8d00, 0x990c}, {0x8d7f, 0xa7d0}, {0x8e00, 0xaf14},
3070 {0x8e7f, 0xbdd8}, {0x8f00, 0xc51c}, {0x8f7f, 0xd3e0}, {0x9000, 0xdb24},
3071 {0x907f, 0xe9e8}, {0x9100, 0xf12c}, {0x917f, 0xfff0}, {0x9200, 0x10734},
3072 {0x927f, 0x115f8}, {0x9300, 0x11d3c}, {0x937f, 0x12c00}, {0x9400, 0x13344},
3073 {0x947f, 0x14208}, {0x9500, 0x1494c}, {0x957f, 0x15810}, {0x9600, 0x15f54},
3074 {0x967f, 0x16e18}, {0x9700, 0x1755c}, {0x977f, 0x18420}, {0x9800, 0x18b64},
3078 if (a0 >= 0x8140 && a0 <= 0x84be) {
3079 while (table_8140[i][0] <= a0) i++;
3080 a0 -= table_8140[i - 1][0];
3081 v0 = 0xbfc66000 + (a0 * 0x1e + table_8140[i - 1][1]);
3082 } else if (a0 >= 0x889f && a0 <= 0x9872) {
3083 while (table_889f[i][0] <= a0) i++;
3084 a0 -= table_889f[i - 1][0];
3085 v0 = 0xbfc66000 + (a0 * 0x1e + table_889f[i - 1][1]);
3093 void psxBios_GetC0Table() { // 56
3094 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x56]);
3095 log_unhandled("GetC0Table @%08x\n", ra);
3097 mips_return_c(A_C0_TABLE, 3);
3100 void psxBios_GetB0Table() { // 57
3101 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x57]);
3102 log_unhandled("GetB0Table @%08x\n", ra);
3104 mips_return_c(A_B0_TABLE, 3);
3107 static void psxBios__card_chan() { // 0x58
3108 // todo: should return active slot channel
3109 // (active - which was last processed by irq code)
3110 u32 ret = loadRam32(A_CARD_ACHAN);
3111 PSXBIOS_LOG("psxBios_%s -> %02x\n", biosB0n[0x58], ret);
3113 mips_return_c(ret, 8);
3116 static void psxBios_ChangeClearPad() { // 5b
3118 PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x5b], a0);
3119 ret = loadRam32(A_PAD_ACK_VBL);
3120 storeRam32(A_PAD_ACK_VBL, a0);
3122 mips_return_c(ret, 6);
3125 static void psxBios__card_status() { // 5c
3126 u8 s = loadRam8(A_CARD_STATUS1 + a0);
3127 PSXBIOS_LOG("psxBios_%s %x -> %x\n", biosB0n[0x5c], a0, s);
3129 mips_return_c(s, 5);
3132 static void psxBios__card_wait() { // 5d
3133 u8 s = loadRam8(A_CARD_STATUS1 + a0);
3134 PSXBIOS_LOG("psxBios_%s %x -> %x\n", biosB0n[0x5d], a0, s);
3138 log_unhandled("%s %x\n", __func__, s);
3140 mips_return_c(s, 11);
3143 static void psxBios__card_info() { // A ab
3144 PSXBIOS_LOG("psxBios_%s %02x\n", biosA0n[0xab], a0);
3146 storeRam32(A_CARD_ACHAN, a0);
3153 if (McdDisable[port & 1])
3157 PSXBIOS_LOG("psxBios_%s: UNKNOWN PORT 0x%x\n", biosA0n[0xab], a0);
3162 if (McdDisable[0] && McdDisable[1])
3166 // deliver from card_vint_handler()
3167 storeRam8(A_CARD_STATUS1 + port, 8); // busy/info
3168 storeRam32(A_CARD_HANDLER, CARD_HARDLER_INFO);
3170 DeliverEvent(0xf4000001, ret);
3171 DeliverEvent(0xf0000011, 0x0004); // ?
3176 static void psxBios__card_load() { // A ac
3177 PSXBIOS_LOG("psxBios_%s %02x\n", biosA0n[0xac], a0);
3179 storeRam32(A_CARD_ACHAN, a0);
3181 // DeliverEvent(0xf0000011, 0x0004);
3182 DeliverEvent(0xf4000001, 0x0004);
3187 static void card_vint_handler(void) {
3190 UnDeliverEvent(0xf0000011, 0x0004);
3191 UnDeliverEvent(0xf0000011, 0x8000);
3192 UnDeliverEvent(0xf0000011, 0x0100);
3193 UnDeliverEvent(0xf0000011, 0x0200);
3194 UnDeliverEvent(0xf0000011, 0x2000);
3197 select = loadRam8(A_CARD_ISLOT);
3198 select = (select ^ 1) & 1;
3199 storeRam8(A_CARD_ISLOT, select);
3201 select = loadRam8(A_CARD_ACHAN) >> 4;
3202 storeRam8(A_CARD_ISLOT, select);
3204 status = loadRam8(A_CARD_STATUS1 + select);
3208 //psxBios_SysDeqIntRP_(0, 0x7540);
3209 //psxBios_SysDeqIntRP_(0, 0x7540);
3210 //card_state_machine = 0;
3211 //card_error_flag = 0;
3212 handler = loadRam32(A_CARD_HANDLER);
3214 case CARD_HARDLER_INFO:
3215 DeliverEvent(0xf4000001, 4);
3216 DeliverEvent(0xf0000011, 4);
3217 storeRam8(A_CARD_STATUS1 + select, 1);
3218 storeRam32(A_CARD_HANDLER, 0);
3220 case CARD_HARDLER_WRITE:
3221 case CARD_HARDLER_READ:
3222 DeliverEvent(0xf0000011, 4);
3223 storeRam8(A_CARD_STATUS1 + select, 1);
3224 storeRam32(A_CARD_HANDLER, 0);
3229 log_unhandled("%s: unhandled handler %x\n", __func__, handler);
3233 /* System calls C0 */
3235 static void psxBios_InitRCnt() { // 00
3237 PSXBIOS_LOG("psxBios_%s %x\n", biosC0n[0x00], a0);
3238 psxHwWrite16(0x1f801074, psxHu32(0x1074) & ~0x71);
3239 for (i = 0; i < 3; i++) {
3240 psxHwWrite16(0x1f801100 + i*0x10 + 4, 0);
3241 psxHwWrite16(0x1f801100 + i*0x10 + 8, 0);
3242 psxHwWrite16(0x1f801100 + i*0x10 + 0, 0);
3244 for (i = 0; i < 4; i++)
3245 psxBios_SysEnqIntRP_(a0, 0x6d58 + i * 0x10);
3246 mips_return_c(0, 9);
3249 static void psxBios_InitException() { // 01
3250 PSXBIOS_LOG("psxBios_%s %x\n", biosC0n[0x01], a0);
3251 psxBios_SysEnqIntRP_(a0, 0x6da8);
3252 mips_return_c(0, 9);
3256 * int SysEnqIntRP(int index , long *queue);
3259 static void psxBios_SysEnqIntRP_(u32 priority, u32 chain_eptr) {
3260 u32 old, base = loadRam32(A_TT_ExCB);
3262 old = loadRam32(base + (priority << 3));
3263 storeRam32(base + (priority << 3), chain_eptr);
3264 storeRam32(chain_eptr, old);
3265 mips_return_c(0, 9);
3268 static void psxBios_SysEnqIntRP() { // 02
3269 PSXBIOS_LOG("psxBios_%s %x %x\n", biosC0n[0x02], a0, a1);
3270 psxBios_SysEnqIntRP_(a0, a1);
3274 * int SysDeqIntRP(int index , long *queue);
3277 static void psxBios_SysDeqIntRP_(u32 priority, u32 chain_rm_eptr) {
3278 u32 ptr, next, base = loadRam32(A_TT_ExCB);
3279 u32 lim = 0, ret = 0;
3281 // as in original: no arg checks of any kind, bug if a1 == 0
3282 ptr = loadRam32(base + (priority << 3));
3284 next = loadRam32(ptr);
3285 if (ptr == chain_rm_eptr) {
3286 storeRam32(base + (priority << 3), next);
3291 while (next && next != chain_rm_eptr && lim++ < 100) {
3293 next = loadRam32(ptr);
3296 if (next == chain_rm_eptr) {
3297 next = loadRam32(next);
3298 storeRam32(ptr, next);
3305 PSXBIOS_LOG("bad chain %u %x\n", priority, base);
3307 mips_return_c(ret, 12);
3310 static void psxBios_SysDeqIntRP() { // 03
3311 PSXBIOS_LOG("psxBios_%s %x %x\n", biosC0n[0x03], a0, a1);
3312 psxBios_SysDeqIntRP_(a0, a1);
3315 static void psxBios_get_free_EvCB_slot() { // 04
3316 PSXBIOS_LOG("psxBios_%s\n", biosC0n[0x04]);
3317 s32 ret = get_free_EvCB_slot();
3318 mips_return_c(ret, 0);
3321 static void psxBios_SysInitMemory_(u32 base, u32 size) {
3322 storeRam32(base, 0);
3323 storeRam32(A_KMALLOC_PTR, base);
3324 storeRam32(A_KMALLOC_SIZE, size);
3325 storeRam32(A_KMALLOC_END, base + (size & ~3) + 4);
3328 // this should be much more complicated, but maybe that'll be enough
3329 static u32 psxBios_SysMalloc_(u32 size) {
3330 u32 ptr = loadRam32(A_KMALLOC_PTR);
3332 size = (size + 3) & ~3;
3333 storeRam32(A_KMALLOC_PTR, ptr + 4 + size);
3334 storeRam32(ptr, size);
3338 static void psxBios_SysInitMemory() { // 08
3339 PSXBIOS_LOG("psxBios_%s %x %x\n", biosC0n[0x08], a0, a1);
3341 psxBios_SysInitMemory_(a0, a1);
3342 mips_return_void_c(12);
3345 static void psxBios_ChangeClearRCnt() { // 0a
3348 PSXBIOS_LOG("psxBios_%s: %x, %x\n", biosC0n[0x0a], a0, a1);
3350 ret = loadRam32(A_RCNT_VBL_ACK + (a0 << 2));
3351 storeRam32(A_RCNT_VBL_ACK + (a0 << 2), a1);
3352 mips_return_c(ret, 8);
3355 static void psxBios_InitDefInt() { // 0c
3356 PSXBIOS_LOG("psxBios_%s %x\n", biosC0n[0x0c], a0);
3357 // should also clear the autoack table
3358 psxBios_SysEnqIntRP_(a0, 0x6d98);
3359 mips_return_c(0, 20 + 6*2);
3362 void psxBios_dummy() {
3363 u32 pc = (pc0 & 0x1fffff) - 4;
3364 char **ntab = pc == 0xa0 ? biosA0n : pc == 0xb0 ? biosB0n
3365 : pc == 0xc0 ? biosC0n : NULL;
3366 PSXBIOS_LOG("unk %x call: %x ra=%x (%s)\n",
3367 pc, t1, ra, ntab ? ntab[t1 & 0xff] : "???");
3368 (void)pc; (void)ntab;
3369 mips_return_c(0, 100);
3372 void (*biosA0[256])();
3373 // C0 and B0 overlap (end of C0 is start of B0)
3374 void (*biosC0[256+128])();
3375 void (**biosB0)() = biosC0 + 128;
3377 static void setup_mips_code()
3380 ptr = (u32 *)&psxM[A_SYSCALL];
3381 ptr[0x00/4] = SWAPu32(0x0000000c); // syscall 0
3382 ptr[0x04/4] = SWAPu32(0x03e00008); // jr $ra
3383 ptr[0x08/4] = SWAPu32(0x00000000); // nop
3385 ptr = (u32 *)&psxM[A_EXCEPTION];
3386 memset(ptr, 0, 0xc0); // nops (to be patched by games sometimes)
3387 ptr[0x10/4] = SWAPu32(0x8c1a0108); // lw $k0, (0x108) // PCB
3388 ptr[0x14/4] = SWAPu32(0x00000000); // nop
3389 ptr[0x18/4] = SWAPu32(0x8f5a0000); // lw $k0, ($k0) // TCB
3390 ptr[0x1c/4] = SWAPu32(0x00000000); // nop
3391 ptr[0x20/4] = SWAPu32(0x275a0008); // addiu $k0, $k0, 8 // regs
3392 ptr[0x24/4] = SWAPu32(0xaf5f007c); // sw $ra, 0x7c($k0)
3393 ptr[0x28/4] = SWAPu32(0xaf410004); // sw $at, 0x04($k0)
3394 ptr[0x2c/4] = SWAPu32(0xaf420008); // sw $v0, 0x08($k0)
3395 ptr[0x30/4] = SWAPu32(0xaf43000c); // sw $v1, 0x0c($k0)
3397 ptr[0x60/4] = SWAPu32(0x40037000); // mfc0 $v1, EPC
3398 ptr[0x64/4] = SWAPu32(0x40026800); // mfc0 $v0, Cause
3399 ptr[0x6c/4] = SWAPu32(0xaf430080); // sw $v1, 0x80($k0)
3401 ptr[0xb0/4] = HLEOP(hleop_exception);
3404 static const struct {
3408 { 0xbfc050a4, hleop_exc0_0_1 },
3409 { 0xbfc04fbc, hleop_exc0_0_2 },
3410 { 0xbfc0506c, hleop_exc0_1_1 },
3411 { 0xbfc04dec, hleop_exc0_1_2 },
3412 { 0x1a00, hleop_exc0_2_2 },
3413 { 0x19c8, hleop_exc1_0_1 },
3414 { 0x18bc, hleop_exc1_0_2 },
3415 { 0x1990, hleop_exc1_1_1 },
3416 { 0x1858, hleop_exc1_1_2 },
3417 { 0x1958, hleop_exc1_2_1 },
3418 { 0x17f4, hleop_exc1_2_2 },
3419 { 0x1920, hleop_exc1_3_1 },
3420 { 0x1794, hleop_exc1_3_2 },
3421 { 0x2458, hleop_exc3_0_2 },
3422 { 0x49bc, hleop_exc_padcard1 }, // hleExcPadCard1
3423 { 0x4a4c, hleop_exc_padcard2 },
3426 static int chain_hle_op(u32 handler)
3430 for (i = 0; i < sizeof(chainfns) / sizeof(chainfns[0]); i++)
3431 if (chainfns[i].addr == handler)
3432 return chainfns[i].op;
3436 static void write_chain(u32 *d, u32 next, u32 handler1, u32 handler2)
3438 d[0] = SWAPu32(next);
3439 d[1] = SWAPu32(handler1);
3440 d[2] = SWAPu32(handler2);
3442 // install the hle traps
3443 if (handler1) PSXMu32ref(handler1) = HLEOP(chain_hle_op(handler1));
3444 if (handler2) PSXMu32ref(handler2) = HLEOP(chain_hle_op(handler2));
3447 static void setup_tt(u32 tcb_cnt, u32 evcb_cnt, u32 stack)
3449 u32 *ram32 = (u32 *)psxM;
3450 u32 s_excb = 0x20, s_evcb, s_pcb = 4, s_tcb;
3451 u32 p_excb, p_evcb, p_pcb, p_tcb;
3454 PSXBIOS_LOG("setup: tcb %u, evcb %u\n", tcb_cnt, evcb_cnt);
3456 // the real bios doesn't care, but we just don't
3457 // want to crash in case of garbage parameters
3458 if (tcb_cnt > 1024) tcb_cnt = 1024;
3459 if (evcb_cnt > 1024) evcb_cnt = 1024;
3460 s_evcb = 0x1c * evcb_cnt;
3461 s_tcb = 0xc0 * tcb_cnt;
3463 memset(ram32 + 0xe000/4, 0, s_excb + s_evcb + s_pcb + s_tcb + 5*4);
3464 psxBios_SysInitMemory_(0xa000e000, 0x2000);
3465 p_excb = psxBios_SysMalloc_(s_excb);
3466 p_evcb = psxBios_SysMalloc_(s_evcb);
3467 p_pcb = psxBios_SysMalloc_(s_pcb);
3468 p_tcb = psxBios_SysMalloc_(s_tcb);
3470 // "table of tables". Some games modify it
3471 assert(A_TT_ExCB == 0x0100);
3472 ram32[0x0100/4] = SWAPu32(p_excb); // ExCB - exception chains
3473 ram32[0x0104/4] = SWAPu32(s_excb); // ExCB size
3474 ram32[0x0108/4] = SWAPu32(p_pcb); // PCB - process control
3475 ram32[0x010c/4] = SWAPu32(s_pcb); // PCB size
3476 ram32[0x0110/4] = SWAPu32(p_tcb); // TCB - thread control
3477 ram32[0x0114/4] = SWAPu32(s_tcb); // TCB size
3478 ram32[0x0120/4] = SWAPu32(p_evcb); // EvCB - event control
3479 ram32[0x0124/4] = SWAPu32(s_evcb); // EvCB size
3480 ram32[0x0140/4] = SWAPu32(0x8648); // FCB - file control
3481 ram32[0x0144/4] = SWAPu32(0x02c0); // FCB size
3482 ram32[0x0150/4] = SWAPu32(0x6ee0); // DCB - device control
3483 ram32[0x0154/4] = SWAPu32(0x0320); // DCB size
3485 storeRam32(p_excb + 0*4, 0x0000); // chain0
3486 storeRam32(p_excb + 2*4, 0x6d88); // chain1
3487 storeRam32(p_excb + 4*4, 0x0000); // chain2
3488 storeRam32(p_excb + 6*4, 0x6d98); // chain3
3490 storeRam32(p_pcb, p_tcb);
3491 storeRam32(p_tcb, 0x4000); // first TCB
3492 for (i = 1; i < tcb_cnt; i++)
3493 storeRam32(p_tcb + sizeof(TCB) * i, 0x1000);
3495 psxBios_SysEnqIntRP_(0, 0x6da8);
3496 setup_cd_irq_and_events();
3498 storeRam32(A_CONF_EvCB, evcb_cnt);
3499 storeRam32(A_CONF_TCB, tcb_cnt);
3500 storeRam32(A_CONF_SP, stack);
3503 static const u32 gpu_ctl_def[] = {
3504 0x00000000, 0x01000000, 0x03000000, 0x04000000,
3505 0x05000800, 0x06c60260, 0x0703fc10, 0x08000027
3508 static const u32 gpu_data_def[] = {
3509 0xe100360b, 0xe2000000, 0xe3000800, 0xe4077e7f,
3510 0xe5001000, 0xe6000000,
3511 0x02000000, 0x00000000, 0x01ff03ff
3515 static const u16 spu_config[] = {
3516 0x3fff, 0x37ef, 0x5ebc, 0x5ebc, 0x0000, 0x0000, 0x0000, 0x00a0,
3517 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0x00ff, 0x0000, 0x0000,
3518 0x0000, 0xe128, 0x0000, 0x0200, 0xf0f0, 0xc085, 0x0004, 0x0000,
3519 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
3520 0x033d, 0x0231, 0x7e00, 0x5000, 0xb400, 0xb000, 0x4c00, 0xb000,
3521 0x6000, 0x5400, 0x1ed6, 0x1a31, 0x1d14, 0x183b, 0x1bc2, 0x16b2,
3522 0x1a32, 0x15ef, 0x15ee, 0x1055, 0x1334, 0x0f2d, 0x11f6, 0x0c5d,
3523 0x1056, 0x0ae1, 0x0ae0, 0x07a2, 0x0464, 0x0232, 0x8000, 0x8000
3526 void psxBiosSetupBootState(void)
3528 boolean hle = Config.HLE;
3529 u32 *hw = (u32 *)psxH;
3532 // see also SetBootRegs()
3535 a0 = 1; a2 = a3 = 0; a3 = 0x2a;
3536 t2 = 0x2d; t4 = 0x23; t5 = 0x2b; t6 = 0xa0010000;
3538 k0 = 0xbfc0d968; k1 = 0xf1c;
3539 ra = 0xf0001234; // just to easily detect attempts to return
3540 psxRegs.CP0.n.Cause = 0x20;
3541 psxRegs.CP0.n.EPC = 0xbfc0d964; // EnterCriticalSection syscall
3543 hw[0x1000/4] = SWAP32(0x1f000000);
3544 hw[0x1004/4] = SWAP32(0x1f802000);
3545 hw[0x1008/4] = SWAP32(0x0013243f);
3546 hw[0x100c/4] = SWAP32(0x00003022);
3547 hw[0x1010/4] = SWAP32(0x0013243f);
3548 hw[0x1014/4] = SWAP32(0x200931e1);
3549 hw[0x1018/4] = SWAP32(0x00020943);
3550 hw[0x101c/4] = SWAP32(0x00070777);
3551 hw[0x1020/4] = SWAP32(0x0000132c);
3552 hw[0x1060/4] = SWAP32(0x00000b88);
3553 hw[0x1070/4] = SWAP32(0x00000001);
3554 hw[0x1074/4] = SWAP32(0x0000000c);
3555 hw[0x2040/4] = SWAP32(0x00000900);
3558 hw[0x10a0/4] = SWAP32(0x00ffffff);
3559 hw[0x10a8/4] = SWAP32(0x00000401);
3560 hw[0x10b0/4] = SWAP32(0x0008b000);
3561 hw[0x10b4/4] = SWAP32(0x00010200);
3562 hw[0x10e0/4] = SWAP32(0x000eccf4);
3563 hw[0x10e4/4] = SWAP32(0x00000400);
3564 hw[0x10e8/4] = SWAP32(0x00000002);
3565 hw[0x10f0/4] = SWAP32(0x00009099);
3566 hw[0x10f4/4] = SWAP32(0x8c8c0000);
3575 for (i = 0; i < sizeof(gpu_ctl_def) / sizeof(gpu_ctl_def[0]); i++)
3576 GPU_writeStatus(gpu_ctl_def[i]);
3577 for (i = 0; i < sizeof(gpu_data_def) / sizeof(gpu_data_def[0]); i++)
3578 GPU_writeData(gpu_data_def[i]);
3581 for (i = 0x1f801d80; i < sizeof(spu_config) / sizeof(spu_config[0]); i++)
3582 SPU_writeRegister(0x1f801d80 + i*2, spu_config[i], psxRegs.cycle);
3585 static void hleExc0_0_1();
3586 static void hleExc0_0_2();
3587 static void hleExc0_1_1();
3588 static void hleExc0_1_2();
3590 #include "sjisfont.h"
3592 void psxBiosInit() {
3593 u32 *ptr, *ram32, *rom32;
3598 psxRegs.biosBranchCheck = ~0;
3600 memset(psxM, 0, 0x10000);
3601 for(i = 0; i < 256; i++) {
3606 biosA0[0x03] = biosB0[0x35] = psxBios_write_psxout;
3607 biosA0[0x3c] = biosB0[0x3d] = psxBios_putchar_psxout;
3608 biosA0[0x3e] = biosB0[0x3f] = psxBios_puts_psxout;
3609 biosA0[0x3f] = psxBios_printf_psxout;
3612 char verstr[0x24+1];
3613 rom32 = (u32 *)psxR;
3614 memcpy(verstr, psxR + 0x12c, 0x24);
3616 SysPrintf("BIOS: %08x, '%s', '%c'\n", SWAP32(rom32[0x100/4]),
3617 verstr, psxR[0x7ff52]);
3621 for(i = 0; i < 256; i++) {
3622 if (biosA0[i] == NULL) biosA0[i] = psxBios_dummy;
3623 if (biosB0[i] == NULL) biosB0[i] = psxBios_dummy;
3624 if (biosC0[i] == NULL) biosC0[i] = psxBios_dummy;
3627 biosA0[0x00] = psxBios_open;
3628 biosA0[0x01] = psxBios_lseek;
3629 biosA0[0x02] = psxBios_read;
3630 biosA0[0x03] = psxBios_write;
3631 biosA0[0x04] = psxBios_close;
3632 //biosA0[0x05] = psxBios_ioctl;
3633 //biosA0[0x06] = psxBios_exit;
3634 //biosA0[0x07] = psxBios_sys_a0_07;
3635 biosA0[0x08] = psxBios_getc;
3636 biosA0[0x09] = psxBios_putc;
3637 biosA0[0x0a] = psxBios_todigit;
3638 //biosA0[0x0b] = psxBios_atof;
3639 biosA0[0x0c] = psxBios_strtoul;
3640 biosA0[0x0d] = psxBios_strtol;
3641 biosA0[0x0e] = psxBios_abs;
3642 biosA0[0x0f] = psxBios_labs;
3643 biosA0[0x10] = psxBios_atoi;
3644 biosA0[0x11] = psxBios_atol;
3645 //biosA0[0x12] = psxBios_atob;
3646 biosA0[0x13] = psxBios_setjmp;
3647 biosA0[0x14] = psxBios_longjmp;
3648 biosA0[0x15] = psxBios_strcat;
3649 biosA0[0x16] = psxBios_strncat;
3650 biosA0[0x17] = psxBios_strcmp;
3651 biosA0[0x18] = psxBios_strncmp;
3652 biosA0[0x19] = psxBios_strcpy;
3653 biosA0[0x1a] = psxBios_strncpy;
3654 biosA0[0x1b] = psxBios_strlen;
3655 biosA0[0x1c] = psxBios_index;
3656 biosA0[0x1d] = psxBios_rindex;
3657 biosA0[0x1e] = psxBios_strchr;
3658 biosA0[0x1f] = psxBios_strrchr;
3659 biosA0[0x20] = psxBios_strpbrk;
3660 biosA0[0x21] = psxBios_strspn;
3661 biosA0[0x22] = psxBios_strcspn;
3662 biosA0[0x23] = psxBios_strtok;
3663 biosA0[0x24] = psxBios_strstr;
3664 biosA0[0x25] = psxBios_toupper;
3665 biosA0[0x26] = psxBios_tolower;
3666 biosA0[0x27] = psxBios_bcopy;
3667 biosA0[0x28] = psxBios_bzero;
3668 biosA0[0x29] = psxBios_bcmp;
3669 biosA0[0x2a] = psxBios_memcpy;
3670 biosA0[0x2b] = psxBios_memset;
3671 biosA0[0x2c] = psxBios_memmove;
3672 biosA0[0x2d] = psxBios_memcmp;
3673 biosA0[0x2e] = psxBios_memchr;
3674 biosA0[0x2f] = psxBios_rand;
3675 biosA0[0x30] = psxBios_srand;
3676 biosA0[0x31] = psxBios_qsort;
3677 //biosA0[0x32] = psxBios_strtod;
3678 biosA0[0x33] = psxBios_malloc;
3679 biosA0[0x34] = psxBios_free;
3680 //biosA0[0x35] = psxBios_lsearch;
3681 //biosA0[0x36] = psxBios_bsearch;
3682 biosA0[0x37] = psxBios_calloc;
3683 biosA0[0x38] = psxBios_realloc;
3684 biosA0[0x39] = psxBios_InitHeap;
3685 //biosA0[0x3a] = psxBios__exit;
3686 biosA0[0x3b] = psxBios_getchar;
3687 biosA0[0x3c] = psxBios_putchar;
3688 //biosA0[0x3d] = psxBios_gets;
3689 biosA0[0x3e] = psxBios_puts;
3690 biosA0[0x3f] = psxBios_printf;
3691 biosA0[0x40] = psxBios_SystemErrorUnresolvedException;
3692 //biosA0[0x41] = psxBios_LoadTest;
3693 biosA0[0x42] = psxBios_Load;
3694 biosA0[0x43] = psxBios_Exec;
3695 biosA0[0x44] = psxBios_FlushCache;
3696 //biosA0[0x45] = psxBios_InstallInterruptHandler;
3697 biosA0[0x46] = psxBios_GPU_dw;
3698 biosA0[0x47] = psxBios_mem2vram;
3699 biosA0[0x48] = psxBios_SendGPU;
3700 biosA0[0x49] = psxBios_GPU_cw;
3701 biosA0[0x4a] = psxBios_GPU_cwb;
3702 biosA0[0x4b] = psxBios_GPU_SendPackets;
3703 biosA0[0x4c] = psxBios_sys_a0_4c;
3704 biosA0[0x4d] = psxBios_GPU_GetGPUStatus;
3705 //biosA0[0x4e] = psxBios_GPU_sync;
3706 //biosA0[0x4f] = psxBios_sys_a0_4f;
3707 //biosA0[0x50] = psxBios_sys_a0_50;
3708 biosA0[0x51] = psxBios_LoadExec;
3709 //biosA0[0x52] = psxBios_GetSysSp;
3710 //biosA0[0x53] = psxBios_sys_a0_53;
3711 biosA0[0x54] = psxBios_CdInit;
3712 biosA0[0x55] = psxBios__bu_init;
3713 biosA0[0x56] = psxBios_CdRemove;
3714 //biosA0[0x57] = psxBios_sys_a0_57;
3715 //biosA0[0x58] = psxBios_sys_a0_58;
3716 //biosA0[0x59] = psxBios_sys_a0_59;
3717 //biosA0[0x5a] = psxBios_sys_a0_5a;
3718 //biosA0[0x5b] = psxBios_dev_tty_init;
3719 //biosA0[0x5c] = psxBios_dev_tty_open;
3720 //biosA0[0x5d] = psxBios_sys_a0_5d;
3721 //biosA0[0x5e] = psxBios_dev_tty_ioctl;
3722 //biosA0[0x5f] = psxBios_dev_cd_open;
3723 //biosA0[0x60] = psxBios_dev_cd_read;
3724 //biosA0[0x61] = psxBios_dev_cd_close;
3725 //biosA0[0x62] = psxBios_dev_cd_firstfile;
3726 //biosA0[0x63] = psxBios_dev_cd_nextfile;
3727 //biosA0[0x64] = psxBios_dev_cd_chdir;
3728 //biosA0[0x65] = psxBios_dev_card_open;
3729 //biosA0[0x66] = psxBios_dev_card_read;
3730 //biosA0[0x67] = psxBios_dev_card_write;
3731 //biosA0[0x68] = psxBios_dev_card_close;
3732 //biosA0[0x69] = psxBios_dev_card_firstfile;
3733 //biosA0[0x6a] = psxBios_dev_card_nextfile;
3734 //biosA0[0x6b] = psxBios_dev_card_erase;
3735 //biosA0[0x6c] = psxBios_dev_card_undelete;
3736 //biosA0[0x6d] = psxBios_dev_card_format;
3737 //biosA0[0x6e] = psxBios_dev_card_rename;
3738 //biosA0[0x6f] = psxBios_dev_card_6f;
3739 biosA0[0x70] = psxBios__bu_init;
3740 biosA0[0x71] = psxBios_CdInit;
3741 biosA0[0x72] = psxBios_CdRemove;
3742 //biosA0[0x73] = psxBios_sys_a0_73;
3743 //biosA0[0x74] = psxBios_sys_a0_74;
3744 //biosA0[0x75] = psxBios_sys_a0_75;
3745 //biosA0[0x76] = psxBios_sys_a0_76;
3746 //biosA0[0x77] = psxBios_sys_a0_77;
3747 //biosA0[0x78] = psxBios__96_CdSeekL;
3748 //biosA0[0x79] = psxBios_sys_a0_79;
3749 //biosA0[0x7a] = psxBios_sys_a0_7a;
3750 //biosA0[0x7b] = psxBios_sys_a0_7b;
3751 //biosA0[0x7c] = psxBios__96_CdGetStatus;
3752 //biosA0[0x7d] = psxBios_sys_a0_7d;
3753 //biosA0[0x7e] = psxBios__96_CdRead;
3754 //biosA0[0x7f] = psxBios_sys_a0_7f;
3755 //biosA0[0x80] = psxBios_sys_a0_80;
3756 //biosA0[0x81] = psxBios_sys_a0_81;
3757 //biosA0[0x82] = psxBios_sys_a0_82;
3758 //biosA0[0x83] = psxBios_sys_a0_83;
3759 //biosA0[0x84] = psxBios_sys_a0_84;
3760 //biosA0[0x85] = psxBios__96_CdStop;
3761 //biosA0[0x86] = psxBios_sys_a0_86;
3762 //biosA0[0x87] = psxBios_sys_a0_87;
3763 //biosA0[0x88] = psxBios_sys_a0_88;
3764 //biosA0[0x89] = psxBios_sys_a0_89;
3765 //biosA0[0x8a] = psxBios_sys_a0_8a;
3766 //biosA0[0x8b] = psxBios_sys_a0_8b;
3767 //biosA0[0x8c] = psxBios_sys_a0_8c;
3768 //biosA0[0x8d] = psxBios_sys_a0_8d;
3769 //biosA0[0x8e] = psxBios_sys_a0_8e;
3770 //biosA0[0x8f] = psxBios_sys_a0_8f;
3771 biosA0[0x90] = hleExc0_1_2;
3772 biosA0[0x91] = hleExc0_0_2;
3773 biosA0[0x92] = hleExc0_1_1;
3774 biosA0[0x93] = hleExc0_0_1;
3775 //biosA0[0x94] = psxBios_sys_a0_94;
3776 biosA0[0x95] = psxBios_CdReset;
3777 //biosA0[0x96] = psxBios_AddCDROMDevice;
3778 //biosA0[0x97] = psxBios_AddMemCardDevide;
3779 //biosA0[0x98] = psxBios_DisableKernelIORedirection;
3780 //biosA0[0x99] = psxBios_EnableKernelIORedirection;
3781 //biosA0[0x9a] = psxBios_sys_a0_9a;
3782 //biosA0[0x9b] = psxBios_sys_a0_9b;
3783 biosA0[0x9c] = psxBios_SetConf;
3784 biosA0[0x9d] = psxBios_GetConf;
3785 //biosA0[0x9e] = psxBios_sys_a0_9e;
3786 biosA0[0x9f] = psxBios_SetMem;
3787 //biosA0[0xa0] = psxBios__boot;
3788 //biosA0[0xa1] = psxBios_SystemError;
3789 biosA0[0xa2] = psxBios_EnqueueCdIntr;
3790 biosA0[0xa3] = psxBios_DequeueCdIntr;
3791 //biosA0[0xa4] = psxBios_sys_a0_a4;
3792 //biosA0[0xa5] = psxBios_ReadSector;
3793 biosA0[0xa6] = psxBios_get_cd_status;
3794 //biosA0[0xa7] = psxBios_bufs_cb_0;
3795 //biosA0[0xa8] = psxBios_bufs_cb_1;
3796 //biosA0[0xa9] = psxBios_bufs_cb_2;
3797 //biosA0[0xaa] = psxBios_bufs_cb_3;
3798 biosA0[0xab] = psxBios__card_info;
3799 biosA0[0xac] = psxBios__card_load;
3800 //biosA0[0axd] = psxBios__card_auto;
3801 //biosA0[0xae] = psxBios_bufs_cd_4;
3802 //biosA0[0xaf] = psxBios_sys_a0_af;
3803 //biosA0[0xb0] = psxBios_sys_a0_b0;
3804 //biosA0[0xb1] = psxBios_sys_a0_b1;
3805 //biosA0[0xb2] = psxBios_do_a_long_jmp
3806 //biosA0[0xb3] = psxBios_sys_a0_b3;
3807 biosA0[0xb4] = psxBios_GetSystemInfo;
3808 //*******************B0 CALLS****************************
3809 biosB0[0x00] = psxBios_SysMalloc;
3810 //biosB0[0x01] = psxBios_sys_b0_01;
3811 biosB0[0x02] = psxBios_SetRCnt;
3812 biosB0[0x03] = psxBios_GetRCnt;
3813 biosB0[0x04] = psxBios_StartRCnt;
3814 biosB0[0x05] = psxBios_StopRCnt;
3815 biosB0[0x06] = psxBios_ResetRCnt;
3816 biosB0[0x07] = psxBios_DeliverEvent;
3817 biosB0[0x08] = psxBios_OpenEvent;
3818 biosB0[0x09] = psxBios_CloseEvent;
3819 biosB0[0x0a] = psxBios_WaitEvent;
3820 biosB0[0x0b] = psxBios_TestEvent;
3821 biosB0[0x0c] = psxBios_EnableEvent;
3822 biosB0[0x0d] = psxBios_DisableEvent;
3823 biosB0[0x0e] = psxBios_OpenTh;
3824 biosB0[0x0f] = psxBios_CloseTh;
3825 biosB0[0x10] = psxBios_ChangeTh;
3826 //biosB0[0x11] = psxBios_psxBios_b0_11;
3827 biosB0[0x12] = psxBios_InitPAD;
3828 biosB0[0x13] = psxBios_StartPAD;
3829 biosB0[0x14] = psxBios_StopPAD;
3830 biosB0[0x15] = psxBios_PAD_init;
3831 biosB0[0x16] = psxBios_PAD_dr;
3832 biosB0[0x17] = psxBios_ReturnFromException;
3833 biosB0[0x18] = psxBios_ResetEntryInt;
3834 biosB0[0x19] = psxBios_HookEntryInt;
3835 //biosB0[0x1a] = psxBios_sys_b0_1a;
3836 //biosB0[0x1b] = psxBios_sys_b0_1b;
3837 //biosB0[0x1c] = psxBios_sys_b0_1c;
3838 //biosB0[0x1d] = psxBios_sys_b0_1d;
3839 //biosB0[0x1e] = psxBios_sys_b0_1e;
3840 //biosB0[0x1f] = psxBios_sys_b0_1f;
3841 biosB0[0x20] = psxBios_UnDeliverEvent;
3842 //biosB0[0x21] = psxBios_sys_b0_21;
3843 //biosB0[0x22] = psxBios_sys_b0_22;
3844 //biosB0[0x23] = psxBios_sys_b0_23;
3845 //biosB0[0x24] = psxBios_sys_b0_24;
3846 //biosB0[0x25] = psxBios_sys_b0_25;
3847 //biosB0[0x26] = psxBios_sys_b0_26;
3848 //biosB0[0x27] = psxBios_sys_b0_27;
3849 //biosB0[0x28] = psxBios_sys_b0_28;
3850 //biosB0[0x29] = psxBios_sys_b0_29;
3851 //biosB0[0x2a] = psxBios_sys_b0_2a;
3852 //biosB0[0x2b] = psxBios_sys_b0_2b;
3853 //biosB0[0x2c] = psxBios_sys_b0_2c;
3854 //biosB0[0x2d] = psxBios_sys_b0_2d;
3855 //biosB0[0x2e] = psxBios_sys_b0_2e;
3856 //biosB0[0x2f] = psxBios_sys_b0_2f;
3857 //biosB0[0x30] = psxBios_sys_b0_30;
3858 //biosB0[0x31] = psxBios_sys_b0_31;
3859 biosB0[0x32] = psxBios_open;
3860 biosB0[0x33] = psxBios_lseek;
3861 biosB0[0x34] = psxBios_read;
3862 biosB0[0x35] = psxBios_write;
3863 biosB0[0x36] = psxBios_close;
3864 //biosB0[0x37] = psxBios_ioctl;
3865 //biosB0[0x38] = psxBios_exit;
3866 //biosB0[0x39] = psxBios_sys_b0_39;
3867 //biosB0[0x3a] = psxBios_getc;
3868 //biosB0[0x3b] = psxBios_putc;
3869 biosB0[0x3c] = psxBios_getchar;
3870 biosB0[0x3d] = psxBios_putchar;
3871 //biosB0[0x3e] = psxBios_gets;
3872 biosB0[0x3f] = psxBios_puts;
3873 biosB0[0x40] = psxBios_cd;
3874 biosB0[0x41] = psxBios_format;
3875 biosB0[0x42] = psxBios_firstfile;
3876 biosB0[0x43] = psxBios_nextfile;
3877 biosB0[0x44] = psxBios_rename;
3878 biosB0[0x45] = psxBios_delete;
3879 //biosB0[0x46] = psxBios_undelete;
3880 //biosB0[0x47] = psxBios_AddDevice;
3881 //biosB0[0x48] = psxBios_RemoteDevice;
3882 //biosB0[0x49] = psxBios_PrintInstalledDevices;
3883 biosB0[0x4a] = psxBios_InitCARD;
3884 biosB0[0x4b] = psxBios_StartCARD;
3885 biosB0[0x4c] = psxBios_StopCARD;
3886 //biosB0[0x4d] = psxBios_sys_b0_4d;
3887 biosB0[0x4e] = psxBios__card_write;
3888 biosB0[0x4f] = psxBios__card_read;
3889 biosB0[0x50] = psxBios__new_card;
3890 biosB0[0x51] = psxBios_Krom2RawAdd;
3891 //biosB0[0x52] = psxBios_sys_b0_52;
3892 //biosB0[0x53] = psxBios_sys_b0_53;
3893 //biosB0[0x54] = psxBios__get_errno;
3894 biosB0[0x55] = psxBios__get_error;
3895 biosB0[0x56] = psxBios_GetC0Table;
3896 biosB0[0x57] = psxBios_GetB0Table;
3897 biosB0[0x58] = psxBios__card_chan;
3898 //biosB0[0x59] = psxBios_sys_b0_59;
3899 //biosB0[0x5a] = psxBios_sys_b0_5a;
3900 biosB0[0x5b] = psxBios_ChangeClearPad;
3901 biosB0[0x5c] = psxBios__card_status;
3902 biosB0[0x5d] = psxBios__card_wait;
3903 //*******************C0 CALLS****************************
3904 biosC0[0x00] = psxBios_InitRCnt;
3905 biosC0[0x01] = psxBios_InitException;
3906 biosC0[0x02] = psxBios_SysEnqIntRP;
3907 biosC0[0x03] = psxBios_SysDeqIntRP;
3908 biosC0[0x04] = psxBios_get_free_EvCB_slot;
3909 //biosC0[0x05] = psxBios_get_free_TCB_slot;
3910 //biosC0[0x06] = psxBios_ExceptionHandler;
3911 //biosC0[0x07] = psxBios_InstallExeptionHandler;
3912 biosC0[0x08] = psxBios_SysInitMemory;
3913 //biosC0[0x09] = psxBios_SysInitKMem;
3914 biosC0[0x0a] = psxBios_ChangeClearRCnt;
3915 //biosC0[0x0b] = psxBios_SystemError;
3916 biosC0[0x0c] = psxBios_InitDefInt;
3917 //biosC0[0x0d] = psxBios_sys_c0_0d;
3918 //biosC0[0x0e] = psxBios_sys_c0_0e;
3919 //biosC0[0x0f] = psxBios_sys_c0_0f;
3920 //biosC0[0x10] = psxBios_sys_c0_10;
3921 //biosC0[0x11] = psxBios_sys_c0_11;
3922 //biosC0[0x12] = psxBios_InstallDevices;
3923 //biosC0[0x13] = psxBios_FlushStfInOutPut;
3924 //biosC0[0x14] = psxBios_sys_c0_14;
3925 //biosC0[0x15] = psxBios__cdevinput;
3926 //biosC0[0x16] = psxBios__cdevscan;
3927 //biosC0[0x17] = psxBios__circgetc;
3928 //biosC0[0x18] = psxBios__circputc;
3929 //biosC0[0x19] = psxBios_ioabort;
3930 //biosC0[0x1a] = psxBios_sys_c0_1a
3931 //biosC0[0x1b] = psxBios_KernelRedirect;
3932 //biosC0[0x1c] = psxBios_PatchAOTable;
3933 //************** THE END ***************************************
3936 memset(FDesc, 0, sizeof(FDesc));
3937 memset(cdir, 0, sizeof(cdir));
3940 // somewhat pretend to be a SCPH1001 BIOS
3941 // some games look for these and take an exception if they're missing
3942 rom32 = (u32 *)psxR;
3943 rom32[0x100/4] = SWAP32(0x19951204);
3944 rom32[0x104/4] = SWAP32(3);
3945 romc = (char *)psxR;
3946 strcpy(romc + 0x108, "PCSX authors");
3947 strcpy(romc + 0x12c, "CEX-3000 PCSX HLE"); // see psxBios_GetSystemInfo
3948 strcpy(romc + 0x7ff32, "System ROM Version 2.2 12/04/95 A");
3949 strcpy(romc + 0x7ff54, "GPL-2.0-or-later");
3952 len = 0x80000 - 0x66000;
3953 uncompress((Bytef *)(psxR + 0x66000), &len, font_8140, sizeof(font_8140));
3954 len = 0x80000 - 0x69d68;
3955 uncompress((Bytef *)(psxR + 0x69d68), &len, font_889f, sizeof(font_889f));
3957 // trap attempts to call bios directly
3958 rom32[0x00000/4] = HLEOP(hleop_dummy);
3959 rom32[0x00180/4] = HLEOP(hleop_dummy);
3960 rom32[0x3fffc/4] = HLEOP(hleop_dummy);
3961 rom32[0x65ffc/4] = HLEOP(hleop_dummy);
3962 rom32[0x7ff2c/4] = HLEOP(hleop_dummy);
3964 /* Some games like R-Types, CTR, Fade to Black read from adress 0x00000000 due to uninitialized pointers.
3965 See Garbage Area at Address 00000000h in Nocash PSX Specfications for more information.
3966 Here are some examples of games not working with this fix in place :
3967 R-type won't get past the Irem logo if not implemented.
3968 Crash Team Racing will softlock after the Sony logo.
3971 ram32 = (u32 *)psxM;
3972 ram32[0x0000/4] = SWAPu32(0x00000003); // lui $k0, 0 (overwritten by 3)
3973 ram32[0x0004/4] = SWAPu32(0x275a0000 + A_EXCEPTION); // addiu $k0, $k0, 0xc80
3974 ram32[0x0008/4] = SWAPu32(0x03400008); // jr $k0
3975 ram32[0x000c/4] = SWAPu32(0x00000000); // nop
3977 ram32[0x0060/4] = SWAPu32(0x00000002); // ram size?
3978 ram32[0x0068/4] = SWAPu32(0x000000ff); // unknown
3980 ram32[0x0080/4] = SWAPu32(0x3c1a0000); // lui $k0, 0 // exception vector
3981 ram32[0x0084/4] = SWAPu32(0x275a0000 + A_EXCEPTION); // addiu $k0, $k0, 0xc80
3982 ram32[0x0088/4] = SWAPu32(0x03400008); // jr $k0
3983 ram32[0x008c/4] = SWAPu32(0x00000000); // nop
3985 ram32[0x00a0/4] = HLEOP(hleop_a0);
3986 ram32[0x00b0/4] = HLEOP(hleop_b0);
3987 ram32[0x00c0/4] = HLEOP(hleop_c0);
3989 setup_tt(4, 16, 0x801fff00);
3990 DeliverEvent(0xf0000003, 0x0010);
3992 ram32[0x6ee0/4] = SWAPu32(0x0000eff0); // DCB
3993 strcpy((char *)&ram32[0xeff0/4], "bu");
3995 // default exception handler chains
3996 // see also setup_cd_irq_and_events()
3997 write_chain(&ram32[0x91e0/4], 0x91d0, 0xbfc050a4, 0xbfc04fbc); // chain0.e0
3998 write_chain(&ram32[0x91d0/4], 0x6da8, 0xbfc0506c, 0xbfc04dec); // chain0.e1
3999 write_chain(&ram32[0x6da8/4], 0, 0, 0x1a00); // chain0.e2
4000 write_chain(&ram32[0x6d88/4], 0x6d78, 0x19c8, 0x18bc); // chain1.e0
4001 write_chain(&ram32[0x6d78/4], 0x6d68, 0x1990, 0x1858); // chain1.e1
4002 write_chain(&ram32[0x6d68/4], 0x6d58, 0x1958, 0x17f4); // chain1.e2
4003 write_chain(&ram32[0x6d58/4], 0, 0x1920, 0x1794); // chain1.e3
4004 write_chain(&ram32[0x6d98/4], 0, 0, 0x2458); // chain3.e0
4008 // fill the api jumptables with fake entries as some games patch them
4009 // (or rather the funcs listed there)
4010 // also trap the destination as some "Cheats Edition" thing overrides the
4011 // dispatcher with a wrapper and then jumps to the table entries directly
4012 ptr = (u32 *)&psxM[A_A0_TABLE];
4013 for (i = 0; i < 256; i++) {
4014 ptr[i] = SWAP32(A_A0_TRAPS + i*4);
4015 ram32[A_A0_TRAPS/4 + i] = HLEOP(hleop_a0t);
4017 ptr = (u32 *)&psxM[A_B0_TABLE];
4018 for (i = 0; i < 256; i++) {
4019 ptr[i] = SWAP32(A_B0_TRAPS + i*4);
4020 ram32[A_B0_TRAPS/4 + i] = HLEOP(hleop_b0t);
4022 // B(5b) is special because games patch (sometimes even jump to)
4023 // code at fixed offsets from it, nocash lists offsets:
4024 // patch: +3d8, +4dc, +594, +62c, +9c8, +1988
4025 // call: +7a0=4b70, +884=4c54, +894=4c64
4026 ptr[0x5b] = SWAP32(A_B0_5B_TRAP); // 0x43d0
4027 ram32[A_B0_5B_TRAP/4] = HLEOP(hleop_b0t);
4029 ram32[0x4b70/4] = SWAP32(0x03e00008); // jr $ra // setPadOutputBuf
4031 ram32[0x4c54/4] = SWAP32(0x240e0001); // mov $t6, 1
4032 ram32[0x4c58/4] = SWAP32(0x03e00008); // jr $ra
4033 ram32[0x4c5c/4] = SWAP32(0xac0e0000 + A_PAD_IRQR_ENA); // sw $t6, ...
4035 ram32[0x4c64/4] = SWAP32(0x03e00008); // jr $ra
4036 ram32[0x4c68/4] = SWAP32(0xac000000 + A_PAD_IRQR_ENA); // sw $0, ...
4038 ptr = (u32 *)&psxM[A_C0_TABLE];
4039 for (i = 0; i < 256/2; i++) {
4040 ptr[i] = SWAP32(A_C0_TRAPS + i*4);
4041 ram32[A_C0_TRAPS/4 + i] = HLEOP(hleop_c0t);
4043 ptr[6] = SWAP32(A_EXCEPTION);
4046 ram32[A_A0_TRAPS/4 - 1] = HLEOP(hleop_dummy);
4047 ram32[A_B0_TRAPS/4 - 1] = HLEOP(hleop_dummy);
4048 ram32[A_C0_TRAPS/4 - 1] = HLEOP(hleop_dummy);
4049 ram32[0x7ffc/4] = HLEOP(hleop_dummy);
4050 ram32[0x8000/4] = HLEOP(hleop_execret);
4052 ram32[A_EEXIT_PTR/4] = SWAP32(A_EEXIT_DEF);
4053 ram32[A_EXC_SP/4] = SWAP32(A_EXC_STACK);
4054 ram32[A_RCNT_VBL_ACK/4 + 0] = SWAP32(1);
4055 ram32[A_RCNT_VBL_ACK/4 + 1] = SWAP32(1);
4056 ram32[A_RCNT_VBL_ACK/4 + 2] = SWAP32(1);
4057 ram32[A_RCNT_VBL_ACK/4 + 3] = SWAP32(1);
4058 ram32[A_RND_SEED/4] = SWAPu32(0x24040001); // was 0xac20cc00
4061 void psxBiosShutdown() {
4064 void psxBiosCnfLoaded(u32 tcb_cnt, u32 evcb_cnt, u32 stack) {
4067 if (tcb_cnt != 4 || evcb_cnt != 16) {
4068 setup_tt(tcb_cnt, evcb_cnt, stack);
4069 DeliverEvent(0xf0000003, 0x0010);
4071 storeRam32(A_CONF_SP, stack);
4074 #define psxBios_PADpoll(pad) { \
4075 int i, more_data = 0; \
4076 PAD##pad##_startPoll(pad); \
4077 pad_buf##pad[1] = PAD##pad##_poll(0x42, &more_data); \
4078 pad_buf##pad[0] = more_data ? 0 : 0xff; \
4079 PAD##pad##_poll(0, &more_data); \
4081 while (more_data) { \
4082 pad_buf##pad[i++] = PAD##pad##_poll(0, &more_data); \
4086 static void handle_chain_x_x_1(u32 enable, u32 irqbit)
4090 psxHwWrite16(0x1f801070, ~(1u << irqbit));
4091 psxBios_ReturnFromException();
4097 // hleExc0_{0,1}* are usually removed by A(56)/A(72) on the game's startup,
4098 // so this is only partially implemented
4099 static void hleExc0_0_1() // A(93h) - CdromDmaIrqFunc2
4101 u32 cdrom_dma_ack_enable = 1; // a000b93c
4102 handle_chain_x_x_1(cdrom_dma_ack_enable, 3); // IRQ3 DMA
4105 static void hleExc0_0_2() // A(91h) - CdromDmaIrqFunc1
4108 //PSXBIOS_LOG("%s\n", __func__);
4110 if (psxHu32(0x1074) & psxHu32(0x1070) & 8) { // IRQ3 DMA
4111 psxHwWrite32(0x1f8010f4, (psxHu32(0x10f4) & 0xffffff) | 0x88000000);
4112 //if (--cdrom_irq_counter == 0) // 0xa0009180
4113 // DeliverEvent(0xf0000003, 0x10);
4117 mips_return_c(ret, 20);
4120 static void hleExc0_1_1() // A(92h) - CdromIoIrqFunc2
4122 u32 cdrom_irq_ack_enable = 1; // a000b938
4123 handle_chain_x_x_1(cdrom_irq_ack_enable, 2); // IRQ2 cdrom
4126 static void hleExc0_1_2() // A(90h) - CdromIoIrqFunc1
4129 if (psxHu32(0x1074) & psxHu32(0x1070) & 4) { // IRQ2 cdrom
4130 PSXBIOS_LOG("%s TODO\n", __func__);
4133 mips_return_c(ret, 20);
4136 static void hleExc0_2_2_syscall() // not in any A/B/C table
4138 u32 tcbPtr = loadRam32(A_TT_PCB);
4139 TCB *tcb = loadRam32ptr(tcbPtr);
4140 u32 code = (SWAP32(tcb->cause) & 0x3c) >> 2;
4142 if (code != R3000E_Syscall) {
4144 DeliverEvent(0xf0000010, 0x1000);
4145 //psxBios_SystemErrorUnresolvedException();
4147 mips_return_c(0, 17);
4151 //printf("%s c=%d a0=%d\n", __func__, code, SWAP32(tcb->reg[4]));
4152 tcb->epc += SWAP32(4);
4153 switch (SWAP32(tcb->reg[4])) { // a0
4157 case 1: { // EnterCritical - disable irqs
4158 u32 was_enabled = ((SWAP32(tcb->sr) & 0x404) == 0x404);
4159 tcb->reg[2] = SWAP32(was_enabled);
4160 tcb->sr &= SWAP32(~0x404);
4163 case 2: // ExitCritical - enable irqs
4164 tcb->sr |= SWAP32(0x404);
4167 case 3: { // ChangeThreadSubFunction
4168 u32 tcbPtr = loadRam32(A_TT_PCB);
4169 storeRam32(tcbPtr, SWAP32(tcb->reg[5])); // a1
4173 DeliverEvent(0xf0000010, 0x4000);
4177 psxBios_ReturnFromException();
4180 static void hleExc1_0_1(void)
4182 u32 vbl_irq_ack_enable = loadRam32(A_RCNT_VBL_ACK + 0x0c); // 860c
4183 handle_chain_x_x_1(vbl_irq_ack_enable, 0); // IRQ0 vblank
4186 static void handle_chain_1_x_2(u32 ev_index, u32 irqbit)
4189 if (psxHu32(0x1074) & psxHu32(0x1070) & (1u << irqbit)) {
4190 DeliverEvent(0xf2000000 + ev_index, 0x0002);
4193 mips_return_c(ret, 22);
4196 static void hleExc1_0_2(void)
4198 handle_chain_1_x_2(3, 0); // IRQ0 vblank
4201 static void hleExc1_1_1(void)
4203 u32 rcnt_irq_ack_enable = loadRam32(A_RCNT_VBL_ACK + 0x08); // 8608
4204 handle_chain_x_x_1(rcnt_irq_ack_enable, 6); // IRQ6 rcnt2
4207 static void hleExc1_1_2(void)
4209 handle_chain_1_x_2(2, 6); // IRQ6 rcnt2
4212 static void hleExc1_2_1(void)
4214 u32 rcnt_irq_ack_enable = loadRam32(A_RCNT_VBL_ACK + 0x04); // 8604
4215 handle_chain_x_x_1(rcnt_irq_ack_enable, 5); // IRQ5 rcnt1
4218 static void hleExc1_2_2(void)
4220 handle_chain_1_x_2(1, 5); // IRQ5 rcnt1
4223 static void hleExc1_3_1(void)
4225 u32 rcnt_irq_ack_enable = loadRam32(A_RCNT_VBL_ACK + 0x00); // 8600
4226 handle_chain_x_x_1(rcnt_irq_ack_enable, 4); // IRQ4 rcnt0
4229 static void hleExc1_3_2(void)
4231 handle_chain_1_x_2(0, 4); // IRQ4 rcnt0
4234 static void hleExc3_0_2_defint(void)
4236 static const struct {
4247 { 6, 6 }, // rcnt2 (bug)
4252 for (i = 0; i < sizeof(tab) / sizeof(tab[0]); i++) {
4253 if (psxHu32(0x1074) & psxHu32(0x1070) & (1u << tab[i].irqbit)) {
4254 DeliverEvent(0xf0000000 + tab[i].ev, 0x1000);
4259 mips_return_c(0, 11 + 7*11 + 7*11 + 12);
4262 static void hleExcPadCard1(void)
4264 if (loadRam32(A_PAD_IRQR_ENA)) {
4265 u8 *pad_buf1 = loadRam8ptr(A_PAD_INBUF + 0);
4266 u8 *pad_buf2 = loadRam8ptr(A_PAD_INBUF + 4);
4271 if (loadRam32(A_PAD_DR_DST))
4274 if (loadRam32(A_PAD_ACK_VBL))
4275 psxHwWrite16(0x1f801070, ~1);
4276 if (loadRam32(A_CARD_IRQR_ENA))
4277 card_vint_handler();
4279 mips_return_c(0, 18);
4282 static void hleExcPadCard2(void)
4284 u32 ret = psxHu32(0x1074) & psxHu32(0x1070) & 1;
4285 mips_return_c(ret, 15);
4288 void psxBiosException() {
4289 u32 tcbPtr = loadRam32(A_TT_PCB);
4290 u32 *chains = loadRam32ptr(A_TT_ExCB);
4291 TCB *tcb = loadRam32ptr(tcbPtr);
4297 // $at, $v0, $v1, $ra already saved by the mips code at A_EXCEPTION
4298 for (i = 4; i < 31; i++) {
4301 tcb->reg[i] = SWAP32(psxRegs.GPR.r[i]);
4303 tcb->lo = SWAP32(psxRegs.GPR.n.lo);
4304 tcb->hi = SWAP32(psxRegs.GPR.n.hi);
4305 //tcb->epc = SWAP32(psxRegs.CP0.n.EPC); // done by asm
4306 tcb->sr = SWAP32(psxRegs.CP0.n.SR);
4307 tcb->cause = SWAP32(psxRegs.CP0.n.Cause);
4308 sp = fp = loadRam32(A_EXC_SP);
4311 assert(!psxRegs.cpuInRecursion);
4313 // do the chains (always 4)
4314 for (c = lim = 0; c < 4; c++) {
4315 if (chains[c * 2] == 0)
4317 ptr = SWAP32(chains[c * 2]);
4318 for (; ptr && lim < 100; ptr = SWAP32(chain[0])) {
4319 chain = castRam32ptr(ptr);
4324 softCallInException(SWAP32(chain[2]));
4325 if (returned_from_exception())
4328 if (v0 == 0 || chain[1] == 0)
4330 softCallInException(SWAP32(chain[1]));
4331 if (returned_from_exception())
4337 // return from exception (custom or default)
4339 ptr = loadRam32(A_EEXIT_PTR);
4340 if (ptr != A_EEXIT_DEF) {
4341 const struct jmp_buf_ *jmp_buf = castRam32ptr(ptr);
4342 longjmp_load(jmp_buf);
4347 psxBios_ReturnFromException();
4351 static void hleDummy() {
4352 log_unhandled("hleDummy called @%08x ra=%08x\n", psxRegs.pc - 4, ra);
4354 psxRegs.cycle += 1000;
4359 static void hleA0() {
4360 u32 call = t1 & 0xff;
4361 u32 entry = loadRam32(A_A0_TABLE + call * 4);
4364 if (call < 192 && entry != A_A0_TRAPS + call * 4) {
4365 PSXBIOS_LOG("custom A%02x %s(0x%x, ) addr=%08x ra=%08x\n",
4366 call, biosA0n[call], a0, entry, ra);
4369 PSXBIOS_LOG(" -> %08x\n", v0);
4371 else if (biosA0[call])
4374 //printf("A(%02x) -> %x\n", call, v0);
4378 static void hleB0() {
4379 u32 call = t1 & 0xff;
4380 u32 entry = loadRam32(A_B0_TABLE + call * 4);
4385 is_custom = entry != A_B0_5B_TRAP;
4387 is_custom = entry != A_B0_TRAPS + call * 4;
4389 PSXBIOS_LOG("custom B%02x %s(0x%x, ) addr=%08x ra=%08x\n",
4390 call, biosB0n[call], a0, entry, ra);
4393 PSXBIOS_LOG(" -> %08x\n", v0);
4395 else if (biosB0[call])
4398 //printf("B(%02x) -> %x\n", call, v0);
4402 static void hleC0() {
4403 u32 call = t1 & 0xff;
4404 u32 entry = loadRam32(A_C0_TABLE + call * 4);
4407 if (call < 128 && entry != A_C0_TRAPS + call * 4) {
4408 PSXBIOS_LOG("custom C%02x %s(0x%x, ) addr=%08x ra=%08x\n",
4409 call, biosC0n[call], a0, entry, ra);
4412 PSXBIOS_LOG(" -> %08x\n", v0);
4414 else if (biosC0[call])
4417 //printf("C(%02x) -> %x\n", call, v0);
4421 static void hleA0t() {
4422 u32 call = (pc0 - A_A0_TRAPS) / 4 - 1;
4423 if (call >= 256u || !biosA0[call]) {
4424 log_unhandled("unexpected A trap @%08x ra=%08x\n", pc0 - 4, ra);
4425 mips_return_void_c(1000);
4430 //printf("A(%02x) -> %x\n", call, v0);
4434 static void hleB0t() {
4435 u32 call = (pc0 - A_B0_TRAPS) / 4 - 1;
4436 if (pc0 - 4 == A_B0_5B_TRAP)
4438 if (call >= 256u || !biosB0[call]) {
4439 log_unhandled("unexpected B trap @%08x ra=%08x\n", pc0 - 4, ra);
4440 mips_return_void_c(1000);
4445 //printf("B(%02x) -> %x\n", call, v0);
4449 static void hleC0t() {
4450 u32 call = (pc0 - A_C0_TRAPS) / 4 - 1;
4451 if (call >= 128u || !biosC0[call]) {
4452 log_unhandled("unexpected C trap @%08x ra=%08x\n", pc0 - 4, ra);
4453 mips_return_void_c(1000);
4458 //printf("C(%02x) -> %x\n", call, v0);
4462 // currently not used
4463 static void hleBootstrap() {
4468 static void hleExecRet() {
4469 const EXEC *header = (EXEC *)PSXM(s0);
4471 PSXBIOS_LOG("ExecRet %x: %x\n", s0, header->ret);
4473 ra = SWAP32(header->ret);
4474 sp = SWAP32(header->_sp);
4475 fp = SWAP32(header->_fp);
4476 gp = SWAP32(header->_gp);
4477 s0 = SWAP32(header->base);
4483 void (* const psxHLEt[hleop_count_])() = {
4484 hleDummy, hleA0, hleB0, hleC0,
4485 hleBootstrap, hleExecRet, psxBiosException, hleDummy,
4486 hleExc0_0_1, hleExc0_0_2,
4487 hleExc0_1_1, hleExc0_1_2, hleExc0_2_2_syscall,
4488 hleExc1_0_1, hleExc1_0_2,
4489 hleExc1_1_1, hleExc1_1_2,
4490 hleExc1_2_1, hleExc1_2_2,
4491 hleExc1_3_1, hleExc1_3_2,
4493 hleExcPadCard1, hleExcPadCard2,
4494 hleA0t, hleB0t, hleC0t,
4497 void psxBiosCheckExe(u32 t_addr, u32 t_size, int loading_state)
4499 // lw $v0, 0x10($sp)
4502 // sw $v0, 0x10($sp)
4503 // lw $v0, 0x10($sp)
4505 // bne $v0, $v1, not_timeout
4508 static const u8 pattern[] = {
4509 0x10, 0x00, 0xA2, 0x8F, 0x00, 0x00, 0x00, 0x00,
4510 0xFF, 0xFF, 0x42, 0x24, 0x10, 0x00, 0xA2, 0xAF,
4511 0x10, 0x00, 0xA2, 0x8F, 0x00, 0x00, 0x00, 0x00,
4512 0x0C, 0x00, 0x43, 0x14, 0x00, 0x00, 0x00, 0x00,
4514 u32 start = t_addr & 0x1ffffc;
4515 u32 end = (start + t_size) & 0x1ffffc;
4516 u32 buf[sizeof(pattern) / sizeof(u32)];
4517 const u32 *r32 = (u32 *)(psxM + start);
4525 memcpy(buf, pattern, sizeof(buf));
4526 for (i = 0; i < t_size / 4; i += j + 1) {
4527 for (j = 0; j < sizeof(buf) / sizeof(buf[0]); j++)
4528 if (r32[i + j] != buf[j])
4530 if (j != sizeof(buf) / sizeof(buf[0]))
4533 if ((SWAP32(r32[i + j]) >> 16) != 0x3c04) // lui
4536 SysPrintf("HLE vsync @%08x\n", start + i * 4);
4537 psxRegs.biosBranchCheck = (t_addr & 0xa01ffffc) + i * 4;
4541 void psxBiosCheckBranch(void)
4545 static u32 cycles_prev, v0_prev;
4546 u32 cycles_passed, waste_cycles;
4547 u32 loops, v0_expect = v0_prev - 1;
4551 cycles_passed = psxRegs.cycle - cycles_prev;
4552 cycles_prev = psxRegs.cycle;
4554 if (cycles_passed < 10 || cycles_passed > 50 || v0 != v0_expect)
4557 waste_cycles = schedule_timeslice() - psxRegs.cycle;
4558 loops = waste_cycles / cycles_passed;
4562 psxRegs.cycle += loops * cycles_passed;
4563 //printf("c %4u %d\n", loops, cycles_passed);
4567 #define bfreeze(ptr, size) { \
4568 if (Mode == 1) memcpy(&psxR[base], ptr, size); \
4569 if (Mode == 0) memcpy(ptr, &psxR[base], size); \
4573 #define bfreezes(ptr) bfreeze(ptr, sizeof(ptr))
4574 #define bfreezel(ptr) bfreeze(ptr, sizeof(*(ptr)))
4576 void psxBiosFreeze(int Mode) {