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(...)
49 #define PTR_1 (void *)(size_t)1
51 char *biosA0n[256] = {
53 "open", "lseek", "read", "write",
54 "close", "ioctl", "exit", "sys_a0_07",
55 "getc", "putc", "todigit", "atof",
56 "strtoul", "strtol", "abs", "labs",
58 "atoi", "atol", "atob", "setjmp",
59 "longjmp", "strcat", "strncat", "strcmp",
60 "strncmp", "strcpy", "strncpy", "strlen",
61 "index", "rindex", "strchr", "strrchr",
63 "strpbrk", "strspn", "strcspn", "strtok",
64 "strstr", "toupper", "tolower", "bcopy",
65 "bzero", "bcmp", "memcpy", "memset",
66 "memmove", "memcmp", "memchr", "rand",
68 "srand", "qsort", "strtod", "malloc",
69 "free", "lsearch", "bsearch", "calloc",
70 "realloc", "InitHeap", "_exit", "getchar",
71 "putchar", "gets", "puts", "printf",
73 "SystemErrorUnresolvedException", "LoadTest", "Load", "Exec",
74 "FlushCache", "InstallInterruptHandler", "GPU_dw", "mem2vram",
75 "SendGPUStatus", "GPU_cw", "GPU_cwb", "SendPackets",
76 "sys_a0_4c", "GetGPUStatus", "GPU_sync", "sys_a0_4f",
78 "sys_a0_50", "LoadExec", "GetSysSp", "sys_a0_53",
79 "_96_init()", "_bu_init()", "_96_remove()", "sys_a0_57",
80 "sys_a0_58", "sys_a0_59", "sys_a0_5a", "dev_tty_init",
81 "dev_tty_open", "sys_a0_5d", "dev_tty_ioctl","dev_cd_open",
83 "dev_cd_read", "dev_cd_close", "dev_cd_firstfile", "dev_cd_nextfile",
84 "dev_cd_chdir", "dev_card_open", "dev_card_read", "dev_card_write",
85 "dev_card_close", "dev_card_firstfile", "dev_card_nextfile","dev_card_erase",
86 "dev_card_undelete","dev_card_format", "dev_card_rename", "dev_card_6f",
88 "_bu_init", "CdInit", "CdRemove", "sys_a0_73",
89 "sys_a0_74", "sys_a0_75", "sys_a0_76", "sys_a0_77",
90 "_96_CdSeekL", "sys_a0_79", "sys_a0_7a", "sys_a0_7b",
91 "_96_CdGetStatus", "sys_a0_7d", "_96_CdRead", "sys_a0_7f",
93 "sys_a0_80", "sys_a0_81", "sys_a0_82", "sys_a0_83",
94 "sys_a0_84", "_96_CdStop", "sys_a0_86", "sys_a0_87",
95 "sys_a0_88", "sys_a0_89", "sys_a0_8a", "sys_a0_8b",
96 "sys_a0_8c", "sys_a0_8d", "sys_a0_8e", "sys_a0_8f",
98 "sys_a0_90", "sys_a0_91", "sys_a0_92", "sys_a0_93",
99 "sys_a0_94", "CdReset", "AddCDROMDevice", "AddMemCardDevide",
100 "DisableKernelIORedirection", "EnableKernelIORedirection", "sys_a0_9a", "sys_a0_9b",
101 "SetConf", "GetConf", "sys_a0_9e", "SetMem",
103 "_boot", "SystemError", "EnqueueCdIntr", "DequeueCdIntr",
104 "sys_a0_a4", "ReadSector", "get_cd_status", "bufs_cb_0",
105 "bufs_cb_1", "bufs_cb_2", "bufs_cb_3", "_card_info",
106 "_card_load", "_card_auto", "bufs_cd_4", "sys_a0_af",
108 "sys_a0_b0", "sys_a0_b1", "do_a_long_jmp", "sys_a0_b3",
112 char *biosB0n[256] = {
114 "SysMalloc", "sys_b0_01", "sys_b0_02", "sys_b0_03",
115 "sys_b0_04", "sys_b0_05", "sys_b0_06", "DeliverEvent",
116 "OpenEvent", "CloseEvent", "WaitEvent", "TestEvent",
117 "EnableEvent", "DisableEvent", "OpenTh", "CloseTh",
119 "ChangeTh", "sys_b0_11", "InitPAD", "StartPAD",
120 "StopPAD", "PAD_init", "PAD_dr", "ReturnFromExecption",
121 "ResetEntryInt", "HookEntryInt", "sys_b0_1a", "sys_b0_1b",
122 "sys_b0_1c", "sys_b0_1d", "sys_b0_1e", "sys_b0_1f",
124 "UnDeliverEvent", "sys_b0_21", "sys_b0_22", "sys_b0_23",
125 "sys_b0_24", "sys_b0_25", "sys_b0_26", "sys_b0_27",
126 "sys_b0_28", "sys_b0_29", "sys_b0_2a", "sys_b0_2b",
127 "sys_b0_2c", "sys_b0_2d", "sys_b0_2e", "sys_b0_2f",
129 "sys_b0_30", "sys_b0_31", "open", "lseek",
130 "read", "write", "close", "ioctl",
131 "exit", "sys_b0_39", "getc", "putc",
132 "getchar", "putchar", "gets", "puts",
134 "cd", "format", "firstfile", "nextfile",
135 "rename", "delete", "undelete", "AddDevice",
136 "RemoteDevice", "PrintInstalledDevices", "InitCARD", "StartCARD",
137 "StopCARD", "sys_b0_4d", "_card_write", "_card_read",
139 "_new_card", "Krom2RawAdd", "sys_b0_52", "sys_b0_53",
140 "_get_errno", "_get_error", "GetC0Table", "GetB0Table",
141 "_card_chan", "sys_b0_59", "sys_b0_5a", "ChangeClearPAD",
142 "_card_status", "_card_wait",
145 char *biosC0n[256] = {
147 "InitRCnt", "InitException", "SysEnqIntRP", "SysDeqIntRP",
148 "get_free_EvCB_slot", "get_free_TCB_slot", "ExceptionHandler", "InstallExeptionHandler",
149 "SysInitMemory", "SysInitKMem", "ChangeClearRCnt", "SystemError",
150 "InitDefInt", "sys_c0_0d", "sys_c0_0e", "sys_c0_0f",
152 "sys_c0_10", "sys_c0_11", "InstallDevices", "FlushStfInOutPut",
153 "sys_c0_14", "_cdevinput", "_cdevscan", "_circgetc",
154 "_circputc", "ioabort", "sys_c0_1a", "KernelRedirect",
158 //#define r0 (psxRegs.GPR.n.r0)
159 #define at (psxRegs.GPR.n.at)
160 #define v0 (psxRegs.GPR.n.v0)
161 #define v1 (psxRegs.GPR.n.v1)
162 #define a0 (psxRegs.GPR.n.a0)
163 #define a1 (psxRegs.GPR.n.a1)
164 #define a2 (psxRegs.GPR.n.a2)
165 #define a3 (psxRegs.GPR.n.a3)
166 #define t0 (psxRegs.GPR.n.t0)
167 #define t1 (psxRegs.GPR.n.t1)
168 #define t2 (psxRegs.GPR.n.t2)
169 #define t3 (psxRegs.GPR.n.t3)
170 #define t4 (psxRegs.GPR.n.t4)
171 #define t5 (psxRegs.GPR.n.t5)
172 #define t6 (psxRegs.GPR.n.t6)
173 #define t7 (psxRegs.GPR.n.t7)
174 #define t8 (psxRegs.GPR.n.t8)
175 #define t9 (psxRegs.GPR.n.t9)
176 #define s0 (psxRegs.GPR.n.s0)
177 #define s1 (psxRegs.GPR.n.s1)
178 #define s2 (psxRegs.GPR.n.s2)
179 #define s3 (psxRegs.GPR.n.s3)
180 #define s4 (psxRegs.GPR.n.s4)
181 #define s5 (psxRegs.GPR.n.s5)
182 #define s6 (psxRegs.GPR.n.s6)
183 #define s7 (psxRegs.GPR.n.s7)
184 #define k0 (psxRegs.GPR.n.k0)
185 #define k1 (psxRegs.GPR.n.k1)
186 #define gp (psxRegs.GPR.n.gp)
187 #define sp (psxRegs.GPR.n.sp)
188 #define fp (psxRegs.GPR.n.fp)
189 #define ra (psxRegs.GPR.n.ra)
190 #define pc0 (psxRegs.pc)
192 #define Ra0 ((char *)PSXM(a0))
193 #define Ra1 ((char *)PSXM(a1))
194 #define Ra2 ((char *)PSXM(a2))
195 #define Ra3 ((char *)PSXM(a3))
196 #define Rv0 ((char *)PSXM(v0))
197 #define Rsp ((char *)PSXM(sp))
208 #define EvStUNUSED 0x0000
209 #define EvStDISABLED 0x1000
210 #define EvStACTIVE 0x2000
211 #define EvStALREADY 0x4000
213 #define EvMdCALL 0x1000
214 #define EvMdMARK 0x2000
237 u32 _sp, _fp, _gp, ret, base;
257 // todo: FileDesc layout is wrong
258 // todo: get rid of these globals
259 static FileDesc FDesc[32];
260 static char ffile[64];
262 static char cdir[8*8+8];
265 // fixed RAM offsets, SCPH1001 compatible
266 #define A_TT_ExCB 0x0100
267 #define A_TT_PCB 0x0108
268 #define A_TT_TCB 0x0110
269 #define A_TT_EvCB 0x0120
270 #define A_A0_TABLE 0x0200
271 #define A_B0_TABLE 0x0874
272 #define A_C0_TABLE 0x0674
273 #define A_SYSCALL 0x0650
274 #define A_EXCEPTION 0x0c80
275 #define A_EXC_SP 0x6cf0
276 #define A_EEXIT_DEF 0x6cf4
277 #define A_KMALLOC_PTR 0x7460
278 #define A_KMALLOC_SIZE 0x7464
279 #define A_KMALLOC_END 0x7468
280 #define A_PADCRD_CHN_E 0x74a8 // pad/card irq chain entry, see hleExcPadCard1()
281 #define A_PAD_IRQR_ENA 0x74b8 // pad read on vint irq (nocash 'pad_enable_flag')
282 #define A_CARD_IRQR_ENA 0x74bc // same for card
283 #define A_PAD_INBUF 0x74c8 // 2x buffers for rx pad data
284 #define A_PAD_OUTBUF 0x74d0 // 2x buffers for tx pad data
285 #define A_PAD_IN_LEN 0x74d8
286 #define A_PAD_OUT_LEN 0x74e0
287 #define A_PAD_DR_DST 0x74c4
288 #define A_CARD_CHAN1 0x7500
289 #define A_PAD_DR_BUF1 0x7570
290 #define A_PAD_DR_BUF2 0x7598
291 #define A_EEXIT_PTR 0x75d0
292 #define A_EXC_STACK 0x85d8 // exception stack top
293 #define A_RCNT_VBL_ACK 0x8600
294 #define A_PAD_ACK_VBL 0x8914 // enable vint ack by pad reading code
295 #define A_HEAP_BASE 0x9000
296 #define A_HEAP_SIZE 0x9004
297 #define A_HEAP_END 0x9008
298 #define A_HEAP_INIT_FLG 0x900c
299 #define A_RND_SEED 0x9010
300 #define A_HEAP_FRSTCHNK 0xb060
301 #define A_HEAP_CURCHNK 0xb064
302 #define A_CONF_TCB 0xb940
303 #define A_CONF_EvCB 0xb944
304 #define A_CONF_SP 0xb948
305 #define A_CD_EVENTS 0xb9b8
306 #define A_EXC_GP 0xf450
308 #define A_A0_TRAPS 0x1010
309 #define A_B0_TRAPS 0x2010
310 #define A_C0_TRAPS 0x3010
311 #define A_B0_5B_TRAP 0x43d0
313 #define HLEOP(n) SWAPu32((0x3b << 26) | (n));
315 static u8 loadRam8(u32 addr)
317 assert(!(addr & 0x5f800000));
318 return psxM[addr & 0x1fffff];
321 static u32 loadRam32(u32 addr)
323 assert(!(addr & 0x5f800000));
324 return SWAP32(*((u32 *)psxM + ((addr & 0x1fffff) >> 2)));
327 static void *castRam8ptr(u32 addr)
329 assert(!(addr & 0x5f800000));
330 return psxM + (addr & 0x1fffff);
333 static void *castRam32ptr(u32 addr)
335 assert(!(addr & 0x5f800003));
336 return psxM + (addr & 0x1ffffc);
339 static void *loadRam8ptr(u32 addr)
341 return castRam8ptr(loadRam32(addr));
344 static void *loadRam32ptr(u32 addr)
346 return castRam32ptr(loadRam32(addr));
349 static void storeRam8(u32 addr, u8 d)
351 assert(!(addr & 0x5f800000));
352 *((u8 *)psxM + (addr & 0x1fffff)) = d;
355 static void storeRam32(u32 addr, u32 d)
357 assert(!(addr & 0x5f800000));
358 *((u32 *)psxM + ((addr & 0x1fffff) >> 2)) = SWAP32(d);
361 static void mips_return(u32 val)
367 static void mips_return_void(void)
372 static void use_cycles(u32 cycle)
374 psxRegs.cycle += cycle * 2;
377 static void mips_return_c(u32 val, u32 cycle)
383 static void mips_return_void_c(u32 cycle)
389 static int returned_from_exception(void)
391 // 0x80000080 means it took another exception just after return
392 return pc0 == k0 || pc0 == 0x80000080;
395 static inline void softCall(u32 pc) {
397 u32 ssr = psxRegs.CP0.n.SR;
401 psxRegs.CP0.n.SR &= ~0x404; // disable interrupts
403 assert(psxRegs.cpuInRecursion <= 1);
404 psxRegs.cpuInRecursion++;
405 psxCpu->Notify(R3000ACPU_NOTIFY_AFTER_LOAD, PTR_1);
407 while (pc0 != 0x80001000 && ++lim < 0x100000)
408 psxCpu->ExecuteBlock(EXEC_CALLER_HLE);
410 psxCpu->Notify(R3000ACPU_NOTIFY_BEFORE_SAVE, PTR_1);
411 psxRegs.cpuInRecursion--;
414 PSXBIOS_LOG("softCall @%x hit lim\n", pc);
416 psxRegs.CP0.n.SR |= ssr & 0x404;
419 static inline void softCallInException(u32 pc) {
424 assert(ra != 0x80001000);
425 if (ra == 0x80001000)
429 psxRegs.cpuInRecursion++;
430 psxCpu->Notify(R3000ACPU_NOTIFY_AFTER_LOAD, PTR_1);
432 while (!returned_from_exception() && pc0 != 0x80001000 && ++lim < 0x100000)
433 psxCpu->ExecuteBlock(EXEC_CALLER_HLE);
435 psxCpu->Notify(R3000ACPU_NOTIFY_BEFORE_SAVE, PTR_1);
436 psxRegs.cpuInRecursion--;
439 PSXBIOS_LOG("softCallInException @%x hit lim\n", pc);
440 if (pc0 == 0x80001000)
444 static u32 OpenEvent(u32 class, u32 spec, u32 mode, u32 func);
445 static void EnableEvent(u32 ev, int do_log);
446 static u32 DeliverEvent(u32 class, u32 spec);
447 static u32 UnDeliverEvent(u32 class, u32 spec);
448 static void CloseEvent(u32 ev);
453 // System calls A0 */
456 #define buread(Ra1, mcd, length) { \
457 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); \
458 ptr = Mcd##mcd##Data + 8192 * FDesc[1 + mcd].mcfile + FDesc[1 + mcd].offset; \
459 memcpy(Ra1, ptr, length); \
460 psxCpu->Clear(a1, (length + 3) / 4); \
461 if (FDesc[1 + mcd].mode & 0x8000) { \
462 DeliverEvent(0xf0000011, 0x0004); \
463 DeliverEvent(0xf4000001, 0x0004); \
466 FDesc[1 + mcd].offset += v0; \
469 #define buwrite(Ra1, mcd, length) { \
470 u32 offset = + 8192 * FDesc[1 + mcd].mcfile + FDesc[1 + mcd].offset; \
471 PSXBIOS_LOG("write %d: %x,%x\n", FDesc[1 + mcd].mcfile, FDesc[1 + mcd].offset, a2); \
472 ptr = Mcd##mcd##Data + offset; \
473 memcpy(ptr, Ra1, length); \
474 FDesc[1 + mcd].offset += length; \
475 SaveMcd(Config.Mcd##mcd, Mcd##mcd##Data, offset, length); \
476 if (FDesc[1 + mcd].mode & 0x8000) { \
477 DeliverEvent(0xf0000011, 0x0004); \
478 DeliverEvent(0xf4000001, 0x0004); \
483 /* Internally redirects to "FileRead(fd,tempbuf,1)".*/
484 /* For some strange reason, the returned character is sign-expanded; */
485 /* So if a return value of FFFFFFFFh could mean either character FFh, or error. */
486 /* TODO FIX ME : Properly implement this behaviour */
487 void psxBios_getc(void) // 0x03, 0x35
492 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x03]);
496 if (pa1 != INVALID_PTR) {
498 case 2: buread(pa1, 1, 1); break;
499 case 3: buread(pa1, 2, 1); break;
506 /* Copy of psxBios_write, except size is 1. */
507 void psxBios_putc(void) // 0x09, 0x3B
512 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x09]);
515 if (pa1 == INVALID_PTR) {
520 if (a0 == 1) { // stdout
521 char *ptr = (char *)pa1;
525 printf("%c", *ptr++); a2--;
531 case 2: buwrite(pa1, 1, 1); break;
532 case 3: buwrite(pa1, 2, 1); break;
538 static u32 do_todigit(u32 c)
541 if (c >= 0x30 && c < 0x3A) {
544 else if (c > 0x60 && c < 0x7B) {
547 else if (c > 0x40 && c < 0x5B) {
550 else if (c >= 0x80) {
551 log_unhandled("todigit %02x\n", c);
562 static void psxBios_todigit(void) // 0x0a
564 mips_return(do_todigit(a0));
565 PSXBIOS_LOG("psxBios_%s '%c' -> %u\n", biosA0n[0x0a], a0, v0);
568 static void do_strtol(char *p, void *end_, u32 base, int can_neg) {
573 if (p == INVALID_PTR) {
578 for (; (0x09 <= *p && *p <= '\r') || *p == ' '; p++)
581 for (; *p == '-'; f = 1, p++)
584 if (base == 0 || base > 36)
588 case 'b': case 'B': base = 2; break;
589 case 'x': case 'X': base = 16; break;
592 else if (*p == 'o' || *p == 'O') {
597 for (; (t = do_todigit(*p)) < base; p++) {
603 if (end != INVALID_PTR)
604 *end = SWAP32(a0 + (p - Ra0));
605 mips_return_c(n, 100);
608 static void psxBios_strtoul() { // 0x0c
609 do_strtol(a0 ? Ra0 : INVALID_PTR, a1 ? Ra1 : INVALID_PTR, a2, 0);
610 PSXBIOS_LOG("psxBios_%s %s (%x), %x, %x -> 0x%x\n",
611 biosA0n[0x0c], a0 ? Ra0 : NULL, a0, a1, a2, v0);
614 static void psxBios_strtol() { // 0x0d
615 do_strtol(a0 ? Ra0 : INVALID_PTR, a1 ? Ra1 : INVALID_PTR, a2, 1);
616 PSXBIOS_LOG("psxBios_%s %s (%x), %x, %x -> 0x%x\n",
617 biosA0n[0x0d], a0 ? Ra0 : NULL, a0, a1, a2, v0);
620 void psxBios_abs() { // 0x0e
621 if ((s32)a0 < 0) v0 = -(s32)a0;
626 void psxBios_labs() { // 0x0f
630 void psxBios_atoi() { // 0x10
632 char *p = (char *)Ra0;
634 if (p == INVALID_PTR) {
641 case ' ': case '\t': continue;
648 while (*p >= '0' && *p <= '9') {
649 n = n * 10 + *p++ - '0';
654 PSXBIOS_LOG("psxBios_%s %s (%x) -> 0x%x\n", biosA0n[0x10], Ra0, a0, v0);
657 void psxBios_atol() { // 0x11
667 static void psxBios_setjmp() { // 0x13
668 struct jmp_buf_ *jmp_buf = castRam32ptr(a0);
671 PSXBIOS_LOG("psxBios_%s %x\n", biosA0n[0x13], a0);
673 jmp_buf->ra_ = SWAP32(ra);
674 jmp_buf->sp_ = SWAP32(sp);
675 jmp_buf->fp_ = SWAP32(fp);
676 for (i = 0; i < 8; i++) // s0-s7
677 jmp_buf->s[i] = SWAP32(psxRegs.GPR.r[16 + i]);
678 jmp_buf->gp_ = SWAP32(gp);
680 mips_return_c(0, 15);
683 static void longjmp_load(const struct jmp_buf_ *jmp_buf)
687 ra = SWAP32(jmp_buf->ra_);
688 sp = SWAP32(jmp_buf->sp_);
689 fp = SWAP32(jmp_buf->fp_);
690 for (i = 0; i < 8; i++) // s0-s7
691 psxRegs.GPR.r[16 + i] = SWAP32(jmp_buf->s[i]);
692 gp = SWAP32(jmp_buf->gp_);;
695 void psxBios_longjmp() { // 0x14
696 struct jmp_buf_ *jmp_buf = castRam32ptr(a0);
698 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x14]);
699 longjmp_load(jmp_buf);
700 mips_return_c(a1, 15);
703 void psxBios_strcat() { // 0x15
707 PSXBIOS_LOG("psxBios_%s %s (%x), %s (%x)\n", biosA0n[0x15], Ra0, a0, Ra1, a1);
708 if (a0 == 0 || a1 == 0 || p2 == INVALID_PTR)
713 while (loadRam8(p1)) {
717 for (; *p2; p1++, p2++)
721 mips_return_c(a0, 22);
724 void psxBios_strncat() { // 0x16
725 char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
729 PSXBIOS_LOG("psxBios_%s: %s (%x), %s (%x), %d\n", biosA0n[0x16], Ra0, a0, Ra1, a1, a2);
731 if (a0 == 0 || a1 == 0)
739 while ((*p1++ = *p2++) != '\0') {
749 void psxBios_strcmp() { // 0x17
750 char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
752 if (a0 == 0 && a1 == 0)
758 else if (a0 == 0 && a1 != 0)
764 else if (a0 != 0 && a1 == 0)
771 PSXBIOS_LOG("psxBios_%s: %s (%x), %s (%x)\n", biosA0n[0x17], Ra0, a0, Ra1, a1);
774 while (*p1 == *p2++) {
793 void psxBios_strncmp() { // 0x18
794 char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
796 if (a0 == 0 && a1 == 0)
802 else if (a0 == 0 && a1 != 0)
808 else if (a0 != 0 && a1 == 0)
815 PSXBIOS_LOG("psxBios_%s: %s (%x), %s (%x), %d\n", biosA0n[0x18], Ra0, a0, Ra1, a1, a2);
818 while (--n >= 0 && *p1 == *p2++) {
822 v1 = a2 - ((a2-n) - 1);
830 v0 = (n < 0 ? 0 : *p1 - *--p2);
832 v1 = a2 - ((a2-n) - 1);
838 void psxBios_strcpy() { // 0x19
839 char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
840 PSXBIOS_LOG("psxBios_%s %x, %s (%x)\n", biosA0n[0x19], a0, p2, a1);
841 if (a0 == 0 || a1 == 0)
847 while ((*p1++ = *p2++) != '\0');
852 void psxBios_strncpy() { // 0x1a
853 char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
855 if (a0 == 0 || a1 == 0)
861 for (i = 0; i < n; i++) {
862 if ((*p1++ = *p2++) == '\0') {
874 void psxBios_strlen() { // 0x1b
875 char *p = (char *)Ra0;
886 void psxBios_index() { // 0x1c
887 char *p = (char *)Ra0;
897 v0 = a0 + (p - (char *)Ra0);
901 } while (*p++ != '\0');
906 void psxBios_rindex() { // 0x1d
907 char *p = (char *)Ra0;
917 v0 = a0 + (p - (char *)Ra0);
918 } while (*p++ != '\0');
923 void psxBios_strchr() { // 0x1e
927 void psxBios_strrchr() { // 0x1f
931 void psxBios_strpbrk() { // 0x20
932 char *p1 = (char *)Ra0, *p2 = (char *)Ra1, *scanp, c, sc;
934 while ((c = *p1++) != '\0') {
935 for (scanp = p2; (sc = *scanp++) != '\0';) {
937 v0 = a0 + (p1 - 1 - (char *)Ra0);
944 // BUG: return a0 instead of NULL if not found
948 void psxBios_strspn() { // 0x21
951 for (p1 = (char *)Ra0; *p1 != '\0'; p1++) {
952 for (p2 = (char *)Ra1; *p2 != '\0' && *p2 != *p1; p2++);
953 if (*p2 == '\0') break;
956 v0 = p1 - (char *)Ra0; pc0 = ra;
959 void psxBios_strcspn() { // 0x22
962 for (p1 = (char *)Ra0; *p1 != '\0'; p1++) {
963 for (p2 = (char *)Ra1; *p2 != '\0' && *p2 != *p1; p2++);
964 if (*p2 != '\0') break;
967 v0 = p1 - (char *)Ra0; pc0 = ra;
970 void psxBios_strtok() { // 0x23
971 char *pcA0 = (char *)Ra0;
972 char *pcRet = strtok(pcA0, (char *)Ra1);
974 v0 = a0 + pcRet - pcA0;
980 void psxBios_strstr() { // 0x24
981 char *p = (char *)Ra0, *p1, *p2;
982 PSXBIOS_LOG("psxBios_%s %s (%x), %s (%x)\n", biosA0n[0x24], p, a0, Ra1, a1);
988 while (*p1 != '\0' && *p2 != '\0' && *p1 == *p2) {
993 v0 = a0 + (p - (char *)Ra0);
995 PSXBIOS_LOG(" -> %x\n", v0);
999 // bug: skips the whole matched substring + 1
1006 void psxBios_toupper() { // 0x25
1007 v0 = (s8)(a0 & 0xff);
1008 if (v0 >= 'a' && v0 <= 'z') v0 -= 'a' - 'A';
1012 void psxBios_tolower() { // 0x26
1013 v0 = (s8)(a0 & 0xff);
1014 if (v0 >= 'A' && v0 <= 'Z') v0 += 'a' - 'A';
1018 static void do_memset(u32 dst, u32 v, s32 len)
1024 if (db != INVALID_PTR)
1028 psxCpu->Clear(dst, (len + 3) / 4);
1031 static void do_memcpy(u32 dst, u32 src, s32 len)
1033 u32 d = dst, s = src;
1036 const u8 *sb = PSXM(s);
1038 if (db != INVALID_PTR && sb != INVALID_PTR)
1043 psxCpu->Clear(dst, (len + 3) / 4);
1046 static void psxBios_memcpy();
1048 static void psxBios_bcopy() { // 0x27 - memcpy with args swapped
1049 //PSXBIOS_LOG("psxBios_%s %x %x %x\n", biosA0n[0x27], a0, a1, a2);
1050 u32 ret = a0, cycles = 0;
1051 if (a0 == 0) // ...but it checks src this time
1053 mips_return_c(0, 4);
1058 do_memcpy(a1, a0, a2);
1064 mips_return_c(ret, cycles + 5);
1067 static void psxBios_bzero() { // 0x28
1068 /* Same as memset here (See memset below) */
1069 u32 ret = a0, cycles;
1070 if (a0 == 0 || (s32)a1 <= 0)
1072 mips_return_c(0, 6);
1075 do_memset(a0, 0, a1);
1079 // todo: many more cycles due to uncached bios mem
1080 mips_return_c(ret, cycles + 5);
1083 void psxBios_bcmp() { // 0x29
1084 char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
1086 if (a0 == 0 || a1 == 0) { v0 = 0; pc0 = ra; return; }
1088 while ((s32)a2-- > 0) {
1089 if (*p1++ != *p2++) {
1090 v0 = *p1 - *p2; // BUG: compare the NEXT byte
1099 static void psxBios_memcpy() { // 0x2a
1100 u32 ret = a0, cycles = 0;
1103 mips_return_c(0, 4);
1108 do_memcpy(a0, a1, a2);
1114 mips_return_c(ret, cycles + 5);
1117 static void psxBios_memset() { // 0x2b
1118 u32 ret = a0, cycles;
1119 if (a0 == 0 || (s32)a2 <= 0)
1121 mips_return_c(0, 6);
1124 do_memset(a0, a1, a2);
1128 // todo: many more cycles due to uncached bios mem
1129 mips_return_c(ret, cycles + 5);
1132 void psxBios_memmove() { // 0x2c
1133 u32 ret = a0, cycles = 0;
1136 mips_return_c(0, 4);
1140 if ((s32)a2 > 0 && a0 > a1 && a0 < a1 + a2) {
1141 u32 dst = a0, len = a2 + 1;
1144 while ((s32)a2 >= 0) { // BUG: copies one more byte here
1145 const u8 *sb = PSXM(a1);
1147 if (db != INVALID_PTR && sb != INVALID_PTR)
1153 psxCpu->Clear(dst, (len + 3) / 4);
1154 cycles = 10 + len * 8;
1155 } else if ((s32)a2 > 0) {
1156 do_memcpy(a0, a1, a2);
1162 mips_return_c(ret, cycles + 5);
1165 void psxBios_memcmp() { // 0x2d
1169 void psxBios_memchr() { // 0x2e
1170 char *p = (char *)Ra0;
1172 if (a0 == 0 || a2 > 0x7FFFFFFF)
1178 while ((s32)a2-- > 0) {
1179 if (*p++ != (s8)a1) continue;
1180 v0 = a0 + (p - (char *)Ra0 - 1);
1188 static void psxBios_rand() { // 0x2f
1189 u32 s = loadRam32(A_RND_SEED) * 1103515245 + 12345;
1190 storeRam32(A_RND_SEED, s);
1192 mips_return_c((s >> 16) & 0x7fff, 12+37);
1195 static void psxBios_srand() { // 0x30
1196 storeRam32(A_RND_SEED, a0);
1197 mips_return_void_c(3);
1200 static u32 qscmpfunc, qswidth;
1202 static inline int qscmp(char *a, char *b) {
1205 a0 = sa0 + (a - (char *)PSXM(sa0));
1206 a1 = sa0 + (b - (char *)PSXM(sa0));
1208 softCall(qscmpfunc);
1214 static inline void qexchange(char *i, char *j) {
1225 static inline void q3exchange(char *i, char *j, char *k) {
1237 static void qsort_main(char *a, char *l) {
1238 char *i, *j, *lp, *hp;
1243 if ((n = l - a) <= qswidth)
1245 n = qswidth * (n / (2 * qswidth));
1251 if ((c = qscmp(i, lp)) == 0) {
1252 qexchange(i, lp -= qswidth);
1263 if ((c = qscmp(hp, j)) == 0) {
1264 qexchange(hp += qswidth, j);
1269 q3exchange(i, hp += qswidth, j);
1283 if (lp - a >= l - hp) {
1284 qsort_main(hp + qswidth, l);
1293 q3exchange(j, lp -= qswidth, i);
1298 void psxBios_qsort() { // 0x31
1301 qsort_main((char *)Ra0, (char *)Ra0 + a1 * a2);
1306 static int malloc_heap_grow(u32 size) {
1307 u32 heap_addr, heap_end, heap_addr_new;
1309 heap_addr = loadRam32(A_HEAP_BASE);
1310 heap_end = loadRam32(A_HEAP_END);
1311 heap_addr_new = heap_addr + 4 + size;
1312 if (heap_addr_new >= heap_end)
1314 storeRam32(A_HEAP_BASE, heap_addr_new);
1315 storeRam32(heap_addr - 4, size | 1);
1316 storeRam32(heap_addr + size, ~1); // terminator
1320 static void psxBios_malloc() { // 0x33
1321 u32 size = (a0 + 3) & ~3;
1322 u32 limit = 32*1024;
1326 PSXBIOS_LOG("psxBios_%s %d\n", biosA0n[0x33], a0);
1328 if (!loadRam32(A_HEAP_INIT_FLG)) {
1329 u32 heap_addr = loadRam32(A_HEAP_BASE);
1330 storeRam32(heap_addr, ~1);
1331 storeRam32(A_HEAP_FRSTCHNK, heap_addr);
1332 storeRam32(A_HEAP_CURCHNK, heap_addr);
1333 storeRam32(A_HEAP_BASE, heap_addr + 4);
1334 if (malloc_heap_grow(size)) {
1335 PSXBIOS_LOG("malloc: init OOM\n");
1336 mips_return_c(0, 20);
1339 storeRam32(A_HEAP_INIT_FLG, 1);
1342 for (i = 0; tries > 0 && i < limit; i++)
1344 u32 chunk = loadRam32(A_HEAP_CURCHNK);
1345 u32 chunk_hdr = loadRam32(chunk);
1346 u32 next_chunk = chunk + 4 + (chunk_hdr & ~3);
1347 u32 next_chunk_hdr = loadRam32(next_chunk);
1349 //printf(" c %08x %08x\n", chunk, chunk_hdr);
1350 if (chunk_hdr & 1) {
1352 if (chunk_hdr > (size | 1)) {
1354 u32 p2size = (chunk_hdr & ~3) - size - 4;
1355 storeRam32(chunk + 4 + size, p2size | 1);
1356 chunk_hdr = size | 1;
1358 if (chunk_hdr == (size | 1)) {
1359 storeRam32(chunk, size);
1363 if (next_chunk_hdr & 1) {
1365 u32 msize = (chunk_hdr & ~3) + 4 + (next_chunk_hdr & ~3);
1366 storeRam32(chunk, msize | 1);
1370 if (chunk_hdr == ~1) {
1373 storeRam32(A_HEAP_CURCHNK, loadRam32(A_HEAP_FRSTCHNK));
1377 // go to the next chunk
1378 storeRam32(A_HEAP_CURCHNK, next_chunk);
1384 else if (tries == 0 && malloc_heap_grow(size))
1387 u32 chunk = loadRam32(A_HEAP_CURCHNK);
1388 storeRam32(chunk, loadRam32(chunk) & ~3);
1392 PSXBIOS_LOG(" -> %08x\n", ret);
1393 mips_return_c(ret, 40);
1396 static void psxBios_free() { // 0x34
1397 PSXBIOS_LOG("psxBios_%s %x (%d bytes)\n", biosA0n[0x34], a0, loadRam32(a0 - 4));
1398 storeRam32(a0 - 4, loadRam32(a0 - 4) | 1); // set chunk to free
1399 mips_return_void_c(5);
1402 static void psxBios_calloc() { // 0x37
1404 PSXBIOS_LOG("psxBios_%s %x %x\n", biosA0n[0x37], a0, a1);
1406 a0 = size = a0 * a1;
1410 a0 = ret; a1 = size;
1413 mips_return_c(ret, 21);
1416 void psxBios_realloc() { // 0x38
1420 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x38]);
1424 /* If "old_buf" is zero, executes malloc(new_size), and returns r2=new_buf (or 0=failed). */
1429 /* Else, if "new_size" is zero, executes free(old_buf), and returns r2=garbage. */
1434 /* Else, executes malloc(new_size), bcopy(old_buf,new_buf,new_size), and free(old_buf), and returns r2=new_buf (or 0=failed). */
1435 /* Note that it is not quite implemented this way here. */
1445 /* InitHeap(void *block , int n) */
1446 static void psxBios_InitHeap() { // 0x39
1447 PSXBIOS_LOG("psxBios_%s %x %x\n", biosA0n[0x39], a0, a1);
1449 storeRam32(A_HEAP_BASE, a0);
1450 storeRam32(A_HEAP_SIZE, a1);
1451 storeRam32(A_HEAP_END, a0 + (a1 & ~3) + 4);
1452 storeRam32(A_HEAP_INIT_FLG, 0);
1455 mips_return_void_c(14);
1458 void psxBios_getchar() { //0x3b
1459 v0 = getchar(); pc0 = ra;
1462 static void psxBios_printf_psxout() { // 0x3f
1465 u32 save[4] = { 0, };
1471 if (psp != INVALID_PTR) {
1472 memcpy(save, psp, 4 * 4);
1473 psxMu32ref(sp) = SWAP32((u32)a0);
1474 psxMu32ref(sp + 4) = SWAP32((u32)a1);
1475 psxMu32ref(sp + 8) = SWAP32((u32)a2);
1476 psxMu32ref(sp + 12) = SWAP32((u32)a3);
1488 tmp2[j++] = Ra0[i]; goto _start;
1490 if (Ra0[i] >= '0' && Ra0[i] <= '9') {
1501 ptmp += sprintf(ptmp, tmp2, (float)psxMu32(sp + n * 4)); n++; break;
1505 ptmp += sprintf(ptmp, tmp2, (double)psxMu32(sp + n * 4)); n++; break;
1511 ptmp += sprintf(ptmp, tmp2, (unsigned int)psxMu32(sp + n * 4)); n++; break;
1513 ptmp += sprintf(ptmp, tmp2, (unsigned char)psxMu32(sp + n * 4)); n++; break;
1515 ptmp += sprintf(ptmp, tmp2, (char*)PSXM(psxMu32(sp + n * 4))); n++; break;
1517 *ptmp++ = Ra0[i]; break;
1527 if (psp != INVALID_PTR)
1528 memcpy(psp, save, 4 * 4);
1531 SysPrintf("%s", tmp);
1534 void psxBios_printf() { // 0x3f
1535 psxBios_printf_psxout();
1539 static void psxBios_cd() { // 0x40
1540 const char *p, *dir = Ra0;
1541 PSXBIOS_LOG("psxBios_%s %x(%s)\n", biosB0n[0x40], a0, dir);
1542 if (dir != INVALID_PTR) {
1543 if ((p = strchr(dir, ':')))
1547 snprintf(cdir, sizeof(cdir), "%s", dir);
1549 mips_return_c(1, 100);
1552 static void psxBios_format() { // 0x41
1553 PSXBIOS_LOG("psxBios_%s %x(%s)\n", biosB0n[0x41], a0, Ra0);
1554 if (strcmp(Ra0, "bu00:") == 0 && Config.Mcd1[0] != '\0')
1556 CreateMcd(Config.Mcd1);
1557 LoadMcd(1, Config.Mcd1);
1560 else if (strcmp(Ra0, "bu10:") == 0 && Config.Mcd2[0] != '\0')
1562 CreateMcd(Config.Mcd2);
1563 LoadMcd(2, Config.Mcd2);
1573 static void psxBios_SystemErrorUnresolvedException() {
1574 if (floodchk != 0x12340a40) { // prevent log flood
1575 SysPrintf("psxBios_%s called from %08x\n", biosA0n[0x40], ra);
1576 floodchk = 0x12340a40;
1578 mips_return_void_c(1000);
1581 static void FlushCache() {
1582 psxCpu->Notify(R3000ACPU_NOTIFY_CACHE_ISOLATED, NULL);
1583 psxCpu->Notify(R3000ACPU_NOTIFY_CACHE_UNISOLATED, NULL);
1585 // runs from uncached mem so tons of cycles
1589 // you likely want to mask irqs before calling these
1590 static u8 cdrom_sync(int do_ack)
1593 if (psxRegs.interrupt & (1u << PSXINT_CDR)) {
1594 if ((s32)(psxRegs.cycle - event_cycles[PSXINT_CDR]) < 0)
1595 psxRegs.cycle = event_cycles[PSXINT_CDR] + 1;
1596 irq_test(&psxRegs.CP0);
1600 r = cdrRead3() & 0x1f;
1601 cdrWrite3(0x5f); // ack; clear params
1606 static void cdrom_cmd_and_wait(u8 cmd, int arg_cnt, int resp_cnt, ...)
1612 va_start(ap, resp_cnt);
1613 while (arg_cnt-- > 0)
1614 cdrWrite2(va_arg(ap, u32));
1619 u8 r = cdrom_sync(1);
1620 assert(r == 3); (void)r;
1624 u8 r = cdrom_sync(1);
1625 assert(r == 2); (void)r;
1631 * long Load(char *name, struct EXEC *header);
1634 void psxBios_Load() { // 0x42
1635 u8 time[3] = { 2, 0, 0x16 };
1643 PSXBIOS_LOG("psxBios_%s %x(%s), %x\n", biosA0n[0x42], a0, pa0, a1);
1644 if (pa0 == INVALID_PTR || pa1 == INVALID_PTR) {
1648 if ((p = strchr(pa0, ':')))
1653 snprintf(path, sizeof(path), "%s\\%s", cdir, (char *)pa0);
1655 snprintf(path, sizeof(path), "%s", (char *)pa0);
1657 if (LoadCdromFile(path, &eheader, time) == 0) {
1658 memcpy(pa1, ((char*)&eheader)+16, sizeof(EXEC));
1659 psxCpu->Clear(a1, sizeof(EXEC) / 4);
1663 PSXBIOS_LOG(" -> %d\n", v0);
1667 // set the cdrom to a state of just after exe read
1668 psxRegs.CP0.n.SR &= ~0x404;
1671 cdrWrite2(0x1f); // unmask
1672 cdrom_cmd_and_wait(0x0e, 1, 1, 0x80u); // CdlSetmode
1673 cdrom_cmd_and_wait(0x02, 3, 1, time[0], time[1], time[2]); // CdlSetloc
1674 cdrom_cmd_and_wait(0x15, 0, 2); // CdlSeekL
1675 psxHwWrite16(0x1f801070, ~4);
1676 MTC0(&psxRegs, 12, psxRegs.CP0.n.SR | 0x404);
1680 * int Exec(struct EXEC *header , int argc , char **argv);
1683 void psxBios_Exec() { // 43
1684 EXEC *header = (EXEC *)castRam32ptr(a0);
1688 PSXBIOS_LOG("psxBios_%s: %x, %x, %x\n", biosA0n[0x43], a0, a1, a2);
1690 header->_sp = SWAP32(sp);
1691 header->_fp = SWAP32(fp);
1692 header->_sp = SWAP32(sp);
1693 header->_gp = SWAP32(gp);
1694 header->ret = SWAP32(ra);
1695 header->base = SWAP32(s0);
1697 ptr = SWAP32(header->b_addr);
1698 len = SWAP32(header->b_size);
1704 if (header->S_addr != 0)
1705 sp = fp = SWAP32(header->S_addr) + SWAP32(header->s_size);
1707 gp = SWAP32(header->gp0);
1715 pc0 = SWAP32(header->_pc0);
1718 static void psxBios_FlushCache() { // 44
1719 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x44]);
1724 void psxBios_GPU_dw() { // 0x46
1729 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x46]);
1732 GPU_writeData(0xa0000000);
1733 GPU_writeData((a1<<0x10)|(a0&0xffff));
1734 GPU_writeData((a3<<0x10)|(a2&0xffff));
1736 ptr = (u32*)PSXM(Rsp[4]); //that is correct?
1739 GPU_writeData(SWAPu32(*ptr++));
1745 static void gpu_sync() {
1746 // not implemented...
1747 // might be problematic to do because of Config.GpuListWalking
1748 if (psxRegs.interrupt & (1u << PSXINT_GPUDMA))
1749 log_unhandled("gpu_sync with active dma\n");
1750 mips_return_c(0, 21);
1753 void psxBios_mem2vram() { // 0x47
1755 gpuSyncPluginSR(); // flush
1756 GPU_writeData(0xa0000000);
1757 GPU_writeData((a1<<0x10)|(a0&0xffff));
1758 GPU_writeData((a3<<0x10)|(a2&0xffff));
1759 size = ((((a2 * a3) / 2) >> 4) << 16);
1760 GPU_writeStatus(0x04000002);
1761 psxHwWrite32(0x1f8010f4,0);
1762 psxHwWrite32(0x1f8010f0,psxHwRead32(0x1f8010f0)|0x800);
1763 psxHwWrite32(0x1f8010a0,Rsp[4]);//might have a buggy...
1764 psxHwWrite32(0x1f8010a4, size | 0x10);
1765 psxHwWrite32(0x1f8010a8,0x01000201);
1770 void psxBios_SendGPU() { // 0x48
1771 GPU_writeStatus(a0);
1776 void psxBios_GPU_cw() { // 0x49
1783 void psxBios_GPU_cwb() { // 0x4a
1784 u32 *ptr = (u32*)Ra0;
1789 GPU_writeData(SWAPu32(*ptr++));
1795 void psxBios_GPU_SendPackets() { //4b:
1797 GPU_writeStatus(0x04000002);
1798 psxHwWrite32(0x1f8010f4,0);
1799 psxHwWrite32(0x1f8010f0,psxHwRead32(0x1f8010f0)|0x800);
1800 psxHwWrite32(0x1f8010a0,a0);
1801 psxHwWrite32(0x1f8010a4,0);
1802 psxHwWrite32(0x1f8010a8,0x010000401);
1806 void psxBios_sys_a0_4c() { // 0x4c GPU relate
1807 psxHwWrite32(0x1f8010a8,0x00000401);
1808 GPU_writeData(0x0400000);
1809 GPU_writeData(0x0200000);
1810 GPU_writeData(0x0100000);
1815 void psxBios_GPU_GetGPUStatus() { // 0x4d
1816 v0 = GPU_readStatus();
1822 void psxBios_LoadExec() { // 51
1823 EXEC *header = (EXEC*)PSXM(0xf000);
1827 PSXBIOS_LOG("psxBios_%s: %s: %x,%x\n", biosA0n[0x51], Ra0, a1, a2);
1829 s_addr = a1; s_size = a2;
1834 header->S_addr = s_addr;
1835 header->s_size = s_size;
1837 a0 = 0xf000; a1 = 0; a2 = 0;
1841 void psxBios__bu_init() { // 70
1843 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x70]);
1846 DeliverEvent(0xf0000011, 0x0004);
1847 DeliverEvent(0xf4000001, 0x0004);
1852 static void write_chain(u32 *d, u32 next, u32 handler1, u32 handler2);
1853 static void psxBios_SysEnqIntRP_(u32 priority, u32 chain_eptr);
1854 static void psxBios_SysDeqIntRP_(u32 priority, u32 chain_rm_eptr);
1856 static void psxBios_EnqueueCdIntr_(void)
1858 u32 *ram32 = (u32 *)psxM;
1860 // traps should already be installed by write_chain()
1861 ram32[0x91d0/4] = 0;
1862 ram32[0x91d4/4] = SWAP32(0xbfc0506c);
1863 ram32[0x91d8/4] = SWAP32(0xbfc04dec);
1864 psxBios_SysEnqIntRP_(0, 0x91d0);
1865 ram32[0x91e0/4] = 0;
1866 ram32[0x91e4/4] = SWAP32(0xbfc050a4);
1867 ram32[0x91e8/4] = SWAP32(0xbfc04fbc);
1868 psxBios_SysEnqIntRP_(0, 0x91e0);
1872 static void setup_cd_irq_and_events(void)
1874 u16 specs[] = { 0x10, 0x20, 0x40, 0x80, 0x8000 };
1877 psxBios_EnqueueCdIntr_();
1879 for (i = 0; i < sizeof(specs) / sizeof(specs[0]); i++) {
1880 u32 h = OpenEvent(0xf0000003, specs[i], EvMdMARK, 0);
1882 storeRam32(A_CD_EVENTS + i * 4, h);
1887 static void psxBios_CdReset_() {
1888 psxRegs.CP0.n.SR &= ~0x404; // disable interrupts
1892 cdrWrite2(0x1f); // unmask
1893 cdrom_cmd_and_wait(0x0a, 0, 2); // CdlReset
1894 cdrom_cmd_and_wait(0x0e, 1, 1, 0x80u); // CdlSetmode
1896 // todo(?): should read something (iso root directory?)
1897 // from { 0, 2, 16 } to somewhere and pause
1900 psxHwWrite16(0x1f801070, ~4);
1901 MTC0(&psxRegs, 12, psxRegs.CP0.n.SR | 0x404);
1902 DeliverEvent(0xf0000003, 0x0020);
1905 static void psxBios_CdInit() { // 54, 71
1906 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x71]);
1907 setup_cd_irq_and_events();
1911 // this function takes pretty much forever
1912 mips_return_c(0, 50000*11);
1915 static void psxBios_DequeueCdIntr_() {
1916 psxBios_SysDeqIntRP_(0, 0x91d0);
1917 psxBios_SysDeqIntRP_(0, 0x91e0);
1921 static void psxBios_CdReset() { // 95
1922 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x95]);
1926 static void psxBios_EnqueueCdIntr() { // a2
1927 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0xa2]);
1928 psxBios_EnqueueCdIntr_();
1929 // return value comes from SysEnqIntRP() insternal call
1932 static void psxBios_DequeueCdIntr() { // a3
1933 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0xa3]);
1934 psxBios_DequeueCdIntr_();
1937 static void psxBios_CdRemove() { // 56, 72
1938 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x72]);
1940 CloseEvent(loadRam32(A_CD_EVENTS + 0x00));
1941 CloseEvent(loadRam32(A_CD_EVENTS + 0x04));
1942 CloseEvent(loadRam32(A_CD_EVENTS + 0x08));
1943 CloseEvent(loadRam32(A_CD_EVENTS + 0x0c));
1944 CloseEvent(loadRam32(A_CD_EVENTS + 0x10));
1945 psxBios_DequeueCdIntr_();
1947 // EnterCriticalSection - should be done at the beginning,
1948 // but this way is much easier to implement
1954 static void setup_tt(u32 tcb_cnt, u32 evcb_cnt, u32 stack);
1956 static void psxBios_SetConf() { // 9c
1957 PSXBIOS_LOG("psxBios_%s %x %x %x\n", biosA0n[0x9c], a0, a1, a2);
1958 setup_tt(a1, a0, a2);
1959 psxRegs.CP0.n.SR |= 0x401;
1960 mips_return_void_c(500);
1963 static void psxBios_GetConf() { // 9d
1964 PSXBIOS_LOG("psxBios_%s %x %x %x\n", biosA0n[0x9d], a0, a1, a2);
1965 storeRam32(a0, loadRam32(A_CONF_EvCB));
1966 storeRam32(a1, loadRam32(A_CONF_TCB));
1967 storeRam32(a2, loadRam32(A_CONF_SP));
1968 mips_return_void_c(10);
1971 void psxBios_SetMem() { // 9f
1972 u32 new = psxHu32(0x1060);
1975 PSXBIOS_LOG("psxBios_%s: %x, %x\n", biosA0n[0x9f], a0, a1);
1980 psxHu32ref(0x1060) = SWAP32(new);
1981 psxMu32ref(0x060) = a0;
1982 PSXBIOS_LOG("Change effective memory : %d MBytes\n",a0);
1986 psxHu32ref(0x1060) = SWAP32(new | 0x300);
1987 psxMu32ref(0x060) = a0;
1988 PSXBIOS_LOG("Change effective memory : %d MBytes\n",a0);
1991 PSXBIOS_LOG("Effective memory must be 2/8 MBytes\n");
1998 /* TODO FIXME : Not compliant. -1 indicates failure but using 1 for now. */
1999 static void psxBios_get_cd_status() // a6
2001 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0xa6]);
2006 static void psxBios__card_info() { // ab
2007 PSXBIOS_LOG("psxBios_%s: %x\n", biosA0n[0xab], a0);
2009 storeRam32(A_CARD_CHAN1, a0);
2016 if (McdDisable[port & 1])
2020 PSXBIOS_LOG("psxBios_%s: UNKNOWN PORT 0x%x\n", biosA0n[0xab], a0);
2025 if (McdDisable[0] && McdDisable[1])
2028 DeliverEvent(0xf0000011, 0x0004);
2029 // DeliverEvent(0xf4000001, 0x0004);
2030 DeliverEvent(0xf4000001, ret);
2034 void psxBios__card_load() { // ac
2036 PSXBIOS_LOG("psxBios_%s: %x\n", biosA0n[0xac], a0);
2039 storeRam32(A_CARD_CHAN1, a0);
2041 // DeliverEvent(0xf0000011, 0x0004);
2042 DeliverEvent(0xf4000001, 0x0004);
2047 static void psxBios_GetSystemInfo() { // b4
2049 //PSXBIOS_LOG("psxBios_%s %x\n", biosA0n[0xb4], a0);
2050 SysPrintf("psxBios_%s %x\n", biosA0n[0xb4], a0);
2053 case 1: ret = SWAP32(((u32 *)psxR)[0x100/4 + a0]); break;
2054 case 2: ret = 0xbfc0012c; break;
2055 case 5: ret = loadRam32(0x60) << 10; break;
2057 mips_return_c(ret, 20);
2060 /* System calls B0 */
2062 static u32 psxBios_SysMalloc_(u32 size);
2064 static void psxBios_SysMalloc() { // B 00
2065 u32 ret = psxBios_SysMalloc_(a0);
2067 PSXBIOS_LOG("psxBios_%s 0x%x -> %x\n", biosB0n[0x00], a0, ret);
2068 mips_return_c(ret, 33);
2071 void psxBios_SetRCnt() { // 02
2073 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x02]);
2080 psxRcntWtarget(a0, a1);
2081 if (a2&0x1000) mode|= 0x050; // Interrupt Mode
2082 if (a2&0x0100) mode|= 0x008; // Count to 0xffff
2083 if (a2&0x0010) mode|= 0x001; // Timer stop mode
2084 if (a0 == 2) { if (a2&0x0001) mode|= 0x200; } // System Clock mode
2085 else { if (a2&0x0001) mode|= 0x100; } // System Clock mode
2087 psxRcntWmode(a0, mode);
2092 void psxBios_GetRCnt() { // 03
2094 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x03]);
2099 case 0: v0 = psxRcntRcount0(); break;
2100 case 1: v0 = psxRcntRcount1(); break;
2101 case 2: v0 = psxRcntRcount2(); break;
2102 case 3: v0 = 0; break;
2107 void psxBios_StartRCnt() { // 04
2109 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x04]);
2113 if (a0 != 3) psxHu32ref(0x1074)|= SWAP32((u32)((1<<(a0+4))));
2114 else psxHu32ref(0x1074)|= SWAPu32(0x1);
2118 void psxBios_StopRCnt() { // 05
2120 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x05]);
2124 if (a0 != 3) psxHu32ref(0x1074)&= SWAP32((u32)(~(1<<(a0+4))));
2125 else psxHu32ref(0x1074)&= SWAPu32(~0x1);
2129 void psxBios_ResetRCnt() { // 06
2131 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x06]);
2136 psxRcntWmode(a0, 0);
2137 psxRcntWtarget(a0, 0);
2138 psxRcntWcount(a0, 0);
2143 static u32 DeliverEvent(u32 class, u32 spec) {
2144 EvCB *ev = (EvCB *)loadRam32ptr(A_TT_EvCB);
2145 u32 evcb_len = loadRam32(A_TT_EvCB + 4);
2146 u32 ret = loadRam32(A_TT_EvCB) + evcb_len;
2147 u32 i, lim = evcb_len / 0x1c;
2149 //printf("%s %08x %x\n", __func__, class, spec);
2150 for (i = 0; i < lim; i++, ev++) {
2152 if (SWAP32(ev->status) != EvStACTIVE)
2155 if (SWAP32(ev->class) != class)
2158 if (SWAP32(ev->spec) != spec)
2161 ret = SWAP32(ev->mode);
2162 if (ret == EvMdMARK) {
2163 ev->status = SWAP32(EvStALREADY);
2167 if (ret == EvMdCALL) {
2168 ret = SWAP32(ev->fhandler);
2181 static u32 UnDeliverEvent(u32 class, u32 spec) {
2182 EvCB *ev = (EvCB *)loadRam32ptr(A_TT_EvCB);
2183 u32 evcb_len = loadRam32(A_TT_EvCB + 4);
2184 u32 ret = loadRam32(A_TT_EvCB) + evcb_len;
2185 u32 i, lim = evcb_len / 0x1c;
2187 for (i = 0; i < lim; i++, ev++) {
2189 if (SWAP32(ev->status) != EvStALREADY)
2192 if (SWAP32(ev->class) != class)
2195 if (SWAP32(ev->spec) != spec)
2198 if (SWAP32(ev->mode) == EvMdMARK)
2199 ev->status = SWAP32(EvStACTIVE);
2205 static void psxBios_DeliverEvent() { // 07
2207 PSXBIOS_LOG("psxBios_%s %x %04x\n", biosB0n[0x07], a0, a1);
2209 ret = DeliverEvent(a0, a1);
2213 static s32 get_free_EvCB_slot() {
2214 EvCB *ev = (EvCB *)loadRam32ptr(A_TT_EvCB);
2215 u32 i, lim = loadRam32(A_TT_EvCB + 4) / 0x1c;
2218 for (i = 0; i < lim; i++, ev++) {
2220 if (ev->status == SWAP32(EvStUNUSED))
2226 static u32 OpenEvent(u32 class, u32 spec, u32 mode, u32 func) {
2227 u32 ret = get_free_EvCB_slot();
2228 if ((s32)ret >= 0) {
2229 EvCB *ev = (EvCB *)loadRam32ptr(A_TT_EvCB) + ret;
2230 ev->class = SWAP32(class);
2231 ev->status = SWAP32(EvStDISABLED);
2232 ev->spec = SWAP32(spec);
2233 ev->mode = SWAP32(mode);
2234 ev->fhandler = SWAP32(func);
2240 static void psxBios_OpenEvent() { // 08
2241 u32 ret = OpenEvent(a0, a1, a2, a3);
2242 PSXBIOS_LOG("psxBios_%s (class:%x, spec:%04x, mode:%04x, func:%x) -> %x\n",
2243 biosB0n[0x08], a0, a1, a2, a3, ret);
2244 mips_return_c(ret, 36);
2247 static void CloseEvent(u32 ev)
2249 u32 base = loadRam32(A_TT_EvCB);
2250 storeRam32(base + (ev & 0xffff) * sizeof(EvCB) + 4, EvStUNUSED);
2253 static void psxBios_CloseEvent() { // 09
2254 PSXBIOS_LOG("psxBios_%s %x (%x)\n", biosB0n[0x09], a0,
2255 loadRam32(loadRam32(A_TT_EvCB) + (a0 & 0xffff) * sizeof(EvCB) + 4));
2257 mips_return_c(1, 10);
2260 static void psxBios_WaitEvent() { // 0a
2261 u32 base = loadRam32(A_TT_EvCB);
2262 u32 status = loadRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4);
2263 PSXBIOS_LOG("psxBios_%s %x (status=%x)\n", biosB0n[0x0a], a0, status);
2266 if (status == EvStALREADY) {
2267 storeRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4, EvStACTIVE);
2271 if (status != EvStACTIVE)
2273 mips_return_c(0, 2);
2277 // retrigger this hlecall after the next emulation event
2279 if ((s32)(next_interupt - psxRegs.cycle) > 0)
2280 psxRegs.cycle = next_interupt;
2284 static void psxBios_TestEvent() { // 0b
2285 u32 base = loadRam32(A_TT_EvCB);
2286 u32 status = loadRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4);
2289 if (psxRegs.cycle - floodchk > 16*1024u) { // prevent log flood
2290 PSXBIOS_LOG("psxBios_%s %x %x\n", biosB0n[0x0b], a0, status);
2291 floodchk = psxRegs.cycle;
2293 if (status == EvStALREADY) {
2294 storeRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4, EvStACTIVE);
2298 mips_return_c(ret, 15);
2301 static void EnableEvent(u32 ev, int do_log) {
2302 u32 base = loadRam32(A_TT_EvCB);
2303 u32 status = loadRam32(base + (ev & 0xffff) * sizeof(EvCB) + 4);
2305 PSXBIOS_LOG("psxBios_%s %x (%x)\n", biosB0n[0x0c], ev, status);
2306 if (status != EvStUNUSED)
2307 storeRam32(base + (ev & 0xffff) * sizeof(EvCB) + 4, EvStACTIVE);
2310 static void psxBios_EnableEvent() { // 0c
2312 mips_return_c(1, 15);
2315 static void psxBios_DisableEvent() { // 0d
2316 u32 base = loadRam32(A_TT_EvCB);
2317 u32 status = loadRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4);
2318 PSXBIOS_LOG("psxBios_%s %x: %x\n", biosB0n[0x0d], a0, status);
2319 if (status != EvStUNUSED)
2320 storeRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4, EvStDISABLED);
2322 mips_return_c(1, 15);
2326 * long OpenTh(long (*func)(), unsigned long sp, unsigned long gp);
2329 void psxBios_OpenTh() { // 0e
2330 TCB *tcb = loadRam32ptr(A_TT_TCB);
2331 u32 limit = loadRam32(A_TT_TCB + 4) / 0xc0u;
2334 for (th = 1; th < limit; th++)
2336 if (tcb[th].status != SWAP32(0x4000)) break;
2340 // Feb 2019 - Added out-of-bounds fix caught by cppcheck:
2341 // When no free TCB is found, return 0xffffffff according to Nocash doc.
2343 PSXBIOS_LOG("\t%s() WARNING! No Free TCBs found!\n", __func__);
2345 mips_return_c(0xffffffff, 20);
2348 PSXBIOS_LOG("psxBios_%s -> %x\n", biosB0n[0x0e], 0xff000000 + th);
2350 tcb[th].status = SWAP32(0x4000);
2351 tcb[th].mode = SWAP32(0x1000);
2352 tcb[th].epc = SWAP32(a0);
2353 tcb[th].reg[30] = SWAP32(a1); // fp
2354 tcb[th].reg[29] = SWAP32(a1); // sp
2355 tcb[th].reg[28] = SWAP32(a2); // gp
2357 mips_return_c(0xff000000 + th, 34);
2361 * int CloseTh(long thread);
2364 static void psxBios_CloseTh() { // 0f
2365 u32 tcb = loadRam32(A_TT_TCB);
2366 u32 th = a0 & 0xffff;
2368 PSXBIOS_LOG("psxBios_%s %x\n", biosB0n[0x0f], a0);
2369 // in the usual bios fashion no checks, just write and return 1
2370 storeRam32(tcb + th * sizeof(TCB), 0x1000);
2372 mips_return_c(1, 11);
2376 * int ChangeTh(long thread);
2379 void psxBios_ChangeTh() { // 10
2380 u32 tcbBase = loadRam32(A_TT_TCB);
2381 u32 th = a0 & 0xffff;
2383 // this is quite spammy
2384 //PSXBIOS_LOG("psxBios_%s %x\n", biosB0n[0x10], th);
2386 // without doing any argument checks, just issue a syscall
2387 // (like the real bios does)
2389 a1 = tcbBase + th * sizeof(TCB);
2394 void psxBios_InitPAD() { // 0x12
2395 u32 i, *ram32 = (u32 *)psxM;
2396 PSXBIOS_LOG("psxBios_%s %x %x %x %x\n", biosB0n[0x12], a0, a1, a2, a3);
2398 // printf("%s", "PS-X Control PAD Driver Ver 3.0");
2399 ram32[A_PAD_DR_DST/4] = 0;
2400 ram32[A_PAD_OUTBUF/4 + 0] = 0;
2401 ram32[A_PAD_OUTBUF/4 + 1] = 0;
2402 ram32[A_PAD_OUT_LEN/4 + 0] = 0;
2403 ram32[A_PAD_OUT_LEN/4 + 1] = 0;
2404 ram32[A_PAD_INBUF/4 + 0] = SWAP32(a0);
2405 ram32[A_PAD_INBUF/4 + 1] = SWAP32(a2);
2406 ram32[A_PAD_IN_LEN/4 + 0] = SWAP32(a1);
2407 ram32[A_PAD_IN_LEN/4 + 1] = SWAP32(a3);
2409 for (i = 0; i < a1; i++) {
2411 storeRam8(a0 + i, 0);
2413 for (i = 0; i < a3; i++) {
2415 storeRam8(a2 + i, 0);
2417 write_chain(ram32 + A_PADCRD_CHN_E/4, 0, 0x49bc, 0x4a4c);
2419 ram32[A_PAD_IRQR_ENA/4] = SWAP32(1);
2421 mips_return_c(1, 200);
2424 void psxBios_StartPAD() { // 13
2425 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x13]);
2427 psxBios_SysDeqIntRP_(2, A_PADCRD_CHN_E);
2428 psxBios_SysEnqIntRP_(2, A_PADCRD_CHN_E);
2429 psxHwWrite16(0x1f801070, ~1);
2430 psxHwWrite16(0x1f801074, psxHu32(0x1074) | 1);
2431 storeRam32(A_PAD_ACK_VBL, 1);
2432 storeRam32(A_RCNT_VBL_ACK + (3 << 2), 0);
2433 psxRegs.CP0.n.SR |= 0x401;
2435 mips_return_c(1, 300);
2438 void psxBios_StopPAD() { // 14
2439 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x14]);
2440 storeRam32(A_RCNT_VBL_ACK + (3 << 2), 1);
2441 psxBios_SysDeqIntRP_(2, A_PADCRD_CHN_E);
2442 psxRegs.CP0.n.SR |= 0x401;
2443 mips_return_void_c(200);
2446 static void psxBios_PAD_init() { // 15
2448 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x15]);
2449 if (a0 == 0x20000000 || a0 == 0x20000001)
2452 a0 = A_PAD_DR_BUF1; a1 = 0x22;
2453 a2 = A_PAD_DR_BUF2; a3 = 0x22;
2456 storeRam32(A_PAD_DR_DST, dst);
2459 mips_return_c(ret, 100);
2462 static u32 psxBios_PAD_dr_() {
2463 u8 *dst = loadRam32ptr(A_PAD_DR_DST);
2464 u8 *buf1 = castRam8ptr(A_PAD_DR_BUF1);
2465 u8 *buf2 = castRam8ptr(A_PAD_DR_BUF2);
2466 dst[0] = dst[1] = dst[2] = dst[3] = ~0;
2467 if (buf1[0] == 0 && (buf1[1] == 0x23 || buf1[1] == 0x41))
2469 dst[0] = buf1[3], dst[1] = buf1[2];
2470 if (buf1[1] == 0x23) {
2471 dst[0] |= 0xc7, dst[1] |= 7;
2472 if (buf1[5] >= 0x10) dst[0] &= ~(1u << 6);
2473 if (buf1[6] >= 0x10) dst[0] &= ~(1u << 7);
2476 if (buf2[0] == 0 && (buf2[1] == 0x23 || buf2[1] == 0x41))
2478 dst[2] = buf2[3], dst[3] = buf2[2];
2479 if (buf2[1] == 0x23) {
2480 dst[2] |= 0xc7, dst[3] |= 7;
2481 if (buf2[5] >= 0x10) dst[2] &= ~(1u << 6);
2482 if (buf2[6] >= 0x10) dst[2] &= ~(1u << 7);
2486 return SWAP32(*(u32 *)dst);
2489 static void psxBios_PAD_dr() { // 16
2490 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x16]);
2491 u32 ret = psxBios_PAD_dr_();
2495 static void psxBios_ReturnFromException() { // 17
2496 u32 tcbPtr = loadRam32(A_TT_PCB);
2497 const TCB *tcb = loadRam32ptr(tcbPtr);
2501 for (i = 1; i < 32; i++)
2502 psxRegs.GPR.r[i] = SWAP32(tcb->reg[i]);
2503 psxRegs.GPR.n.lo = SWAP32(tcb->lo);
2504 psxRegs.GPR.n.hi = SWAP32(tcb->hi);
2505 sr = SWAP32(tcb->sr);
2507 //printf("%s %08x->%08x %u\n", __func__, pc0, tcb->epc, psxRegs.cycle);
2508 pc0 = k0 = SWAP32(tcb->epc);
2510 // the interpreter wants to know about sr changes, so do a MTC0
2511 sr = (sr & ~0x0f) | ((sr & 0x3c) >> 2);
2512 MTC0(&psxRegs, 12, sr);
2518 void psxBios_ResetEntryInt() { // 18
2519 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x18]);
2521 storeRam32(A_EEXIT_PTR, A_EEXIT_DEF);
2522 mips_return_void_c(5);
2525 void psxBios_HookEntryInt() { // 19
2526 PSXBIOS_LOG("psxBios_%s %x\n", biosB0n[0x19], a0);
2528 storeRam32(A_EEXIT_PTR, a0);
2529 mips_return_void_c(3);
2532 static void psxBios_UnDeliverEvent() { // 0x20
2534 PSXBIOS_LOG("psxBios_%s %x %x\n", biosB0n[0x20], a0, a1);
2536 ret = UnDeliverEvent(a0, a1);
2540 static void buopen(int mcd, char *ptr, char *cfg)
2543 char *mcd_data = ptr;
2545 strcpy(FDesc[1 + mcd].name, Ra0+5);
2546 FDesc[1 + mcd].offset = 0;
2547 FDesc[1 + mcd].mode = a1;
2549 for (i=1; i<16; i++) {
2550 const char *fptr = mcd_data + 128 * i;
2551 if ((*fptr & 0xF0) != 0x50) continue;
2552 if (strcmp(FDesc[1 + mcd].name, fptr+0xa)) continue;
2553 FDesc[1 + mcd].mcfile = i;
2554 PSXBIOS_LOG("open %s\n", fptr+0xa);
2558 if (a1 & 0x200 && v0 == -1) { /* FCREAT */
2559 for (i=1; i<16; i++) {
2560 int j, xor, nblk = a1 >> 16;
2562 char *fptr = mcd_data + 128 * i;
2564 if ((*fptr & 0xF0) != 0xa0) continue;
2566 FDesc[1 + mcd].mcfile = i;
2569 fptr[5] = 0x20 * nblk;
2572 strcpy(fptr+0xa, FDesc[1 + mcd].name);
2573 pptr = fptr2 = fptr;
2574 for(j=2; j<=nblk; j++) {
2576 for(i++; i<16; i++) {
2579 memset(fptr2, 0, 128);
2580 fptr2[0] = j < nblk ? 0x52 : 0x53;
2583 for (k=0, xor=0; k<127; k++) xor^= pptr[k];
2588 /* shouldn't this return ENOSPC if i == 16? */
2590 pptr[8] = pptr[9] = 0xff;
2591 for (j=0, xor=0; j<127; j++) xor^= pptr[j];
2593 PSXBIOS_LOG("openC %s %d\n", ptr, nblk);
2595 /* just go ahead and resave them all */
2596 SaveMcd(cfg, ptr, 128, 128 * 15);
2599 /* shouldn't this return ENOSPC if i == 16? */
2604 * int open(char *name , int mode);
2607 void psxBios_open() { // 0x32
2610 PSXBIOS_LOG("psxBios_%s %s %x\n", biosB0n[0x32], Ra0, a1);
2614 if (pa0 != INVALID_PTR) {
2615 if (!strncmp(pa0, "bu00", 4)) {
2616 buopen(1, Mcd1Data, Config.Mcd1);
2619 if (!strncmp(pa0, "bu10", 4)) {
2620 buopen(2, Mcd2Data, Config.Mcd2);
2628 * int lseek(int fd , int offset , int whence);
2631 void psxBios_lseek() { // 0x33
2633 PSXBIOS_LOG("psxBios_%s: %x, %x, %x\n", biosB0n[0x33], a0, a1, a2);
2638 FDesc[a0].offset = a1;
2640 // DeliverEvent(0xf0000011, 0x0004);
2641 // DeliverEvent(0xf4000001, 0x0004);
2645 FDesc[a0].offset+= a1;
2646 v0 = FDesc[a0].offset;
2655 * int read(int fd , void *buf , int nbytes);
2658 void psxBios_read() { // 0x34
2663 PSXBIOS_LOG("psxBios_%s: %x, %x, %x\n", biosB0n[0x34], a0, a1, a2);
2668 if (pa1 != INVALID_PTR) {
2670 case 2: buread(pa1, 1, a2); break;
2671 case 3: buread(pa1, 2, a2); break;
2679 * int write(int fd , void *buf , int nbytes);
2682 void psxBios_write() { // 0x35/0x03
2686 if (a0 != 1) // stdout
2687 PSXBIOS_LOG("psxBios_%s: %x,%x,%x\n", biosB0n[0x35], a0, a1, a2);
2690 if (pa1 == INVALID_PTR) {
2695 if (a0 == 1) { // stdout
2699 if (Config.PsxOut) while (a2 > 0) {
2700 SysPrintf("%c", *ptr++); a2--;
2706 case 2: buwrite(pa1, 1, a2); break;
2707 case 3: buwrite(pa1, 2, a2); break;
2713 static void psxBios_write_psxout() {
2714 if (a0 == 1) { // stdout
2715 const char *ptr = Ra1;
2718 if (ptr != INVALID_PTR)
2720 SysPrintf("%c", *ptr++);
2724 static void psxBios_putchar_psxout() { // 3d
2725 SysPrintf("%c", (char)a0);
2728 static void psxBios_puts_psxout() { // 3e/3f
2729 SysPrintf("%s", Ra0);
2733 * int close(int fd);
2736 void psxBios_close() { // 0x36
2738 PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x36], a0);
2745 void psxBios_putchar() { // 3d
2746 if (Config.PsxOut) SysPrintf("%c", (char)a0);
2750 void psxBios_puts() { // 3e/3f
2751 if (Config.PsxOut) SysPrintf("%s", Ra0);
2755 static void bufile(const u8 *mcd_data, u32 dir_) {
2756 struct DIRENTRY *dir = (struct DIRENTRY *)PSXM(dir_);
2757 const char *pfile = ffile + 5;
2758 const u8 *data = mcd_data;
2759 int i = 0, match = 0;
2764 if (dir == INVALID_PTR)
2767 for (; nfile <= 15 && !match; nfile++) {
2770 head = nfile * 0x40;
2771 data = mcd_data + 128 * nfile;
2772 name = (const char *)data + 0x0a;
2773 if ((data[0] & 0xF0) != 0x50) continue;
2774 /* Bug link files show up as free block. */
2775 if (!name[0]) continue;
2777 for (i = 0; i < 20; i++) {
2778 if (pfile[i] == name[i] || pfile[i] == '?')
2779 dir->name[i] = name[i];
2780 else if (pfile[i] == '*') {
2781 int len = strlen(name + i);
2784 memcpy(dir->name + i, name + i, len + 1);
2795 PSXBIOS_LOG("%d : %s = %s + %s (match=%d)\n",
2796 nfile, dir->name, pfile, name, match);
2798 for (; nfile <= 15; nfile++, blocks++) {
2799 const u8 *data2 = mcd_data + 128 * nfile;
2800 const char *name = (const char *)data2 + 0x0a;
2801 if ((data2[0] & 0xF0) != 0x50 || name[0])
2805 // nul char of full lenth name seems to overwrite .attr
2806 dir->attr = SWAP32(i < 20 ? data[0] & 0xf0 : 0); // ?
2807 dir->size = 8192 * blocks;
2811 PSXBIOS_LOG(" -> %x '%s' %x %x %x %x\n", v0, v0 ? dir->name : "",
2812 dir->attr, dir->size, dir->next, dir->head);
2816 * struct DIRENTRY* firstfile(char *name,struct DIRENTRY *dir);
2819 static void psxBios_firstfile() { // 42
2822 PSXBIOS_LOG("psxBios_%s %s %x\n", biosB0n[0x42], pa0, a1);
2825 if (pa0 != INVALID_PTR)
2827 snprintf(ffile, sizeof(ffile), "%s", pa0);
2829 strcpy(ffile + 5, "*"); // maybe?
2831 if (!strncmp(pa0, "bu00", 4)) {
2832 // firstfile() calls _card_read() internally, so deliver it's event
2833 DeliverEvent(0xf0000011, 0x0004);
2834 bufile((u8 *)Mcd1Data, a1);
2835 } else if (!strncmp(pa0, "bu10", 4)) {
2836 // firstfile() calls _card_read() internally, so deliver it's event
2837 DeliverEvent(0xf0000011, 0x0004);
2838 bufile((u8 *)Mcd2Data, a1);
2846 * struct DIRENTRY* nextfile(struct DIRENTRY *dir);
2849 void psxBios_nextfile() { // 43
2850 PSXBIOS_LOG("psxBios_%s %x\n", biosB0n[0x43], a0);
2853 if (!strncmp(ffile, "bu00", 4))
2854 bufile((u8 *)Mcd1Data, a0);
2855 else if (!strncmp(ffile, "bu10", 4))
2856 bufile((u8 *)Mcd2Data, a0);
2861 #define burename(mcd) { \
2862 for (i=1; i<16; i++) { \
2863 int namelen, j, xor = 0; \
2864 ptr = Mcd##mcd##Data + 128 * i; \
2865 if ((*ptr & 0xF0) != 0x50) continue; \
2866 if (strcmp(Ra0+5, ptr+0xa)) continue; \
2867 namelen = strlen(Ra1+5); \
2868 memcpy(ptr+0xa, Ra1+5, namelen); \
2869 memset(ptr+0xa+namelen, 0, 0x75-namelen); \
2870 for (j=0; j<127; j++) xor^= ptr[j]; \
2872 SaveMcd(Config.Mcd##mcd, Mcd##mcd##Data, 128 * i + 0xa, 0x76); \
2879 * int rename(char *old, char *new);
2882 void psxBios_rename() { // 44
2889 PSXBIOS_LOG("psxBios_%s: %s,%s\n", biosB0n[0x44], Ra0, Ra1);
2894 if (pa0 != INVALID_PTR && pa1 != INVALID_PTR) {
2895 if (!strncmp(pa0, "bu00", 4) && !strncmp(pa1, "bu00", 4)) {
2899 if (!strncmp(pa0, "bu10", 4) && !strncmp(pa1, "bu10", 4)) {
2908 #define budelete(mcd) { \
2909 for (i=1; i<16; i++) { \
2910 ptr = Mcd##mcd##Data + 128 * i; \
2911 if ((*ptr & 0xF0) != 0x50) continue; \
2912 if (strcmp(Ra0+5, ptr+0xa)) continue; \
2913 *ptr = (*ptr & 0xf) | 0xA0; \
2914 SaveMcd(Config.Mcd##mcd, Mcd##mcd##Data, 128 * i, 1); \
2915 PSXBIOS_LOG("delete %s\n", ptr+0xa); \
2922 * int delete(char *name);
2925 void psxBios_delete() { // 45
2931 PSXBIOS_LOG("psxBios_%s: %s\n", biosB0n[0x45], Ra0);
2936 if (pa0 != INVALID_PTR) {
2937 if (!strncmp(pa0, "bu00", 4)) {
2941 if (!strncmp(pa0, "bu10", 4)) {
2949 void psxBios_InitCARD() { // 4a
2950 u32 *ram32 = (u32 *)psxM;
2951 PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x4a], a0);
2952 write_chain(ram32 + A_PADCRD_CHN_E/4, 0, 0x49bc, 0x4a4c);
2953 // (maybe) todo: early_card_irq, etc
2955 ram32[A_PAD_IRQR_ENA/4] = SWAP32(a0);
2957 psxBios_FlushCache();
2958 mips_return_c(0, 34+13+15+6);
2961 void psxBios_StartCARD() { // 4b
2962 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x4b]);
2963 psxBios_SysDeqIntRP_(2, A_PADCRD_CHN_E);
2964 psxBios_SysEnqIntRP_(2, A_PADCRD_CHN_E);
2966 psxHwWrite16(0x1f801074, psxHu32(0x1074) | 1);
2967 storeRam32(A_PAD_ACK_VBL, 1);
2968 storeRam32(A_RCNT_VBL_ACK + (3 << 2), 0);
2969 storeRam32(A_CARD_IRQR_ENA, 1);
2970 psxRegs.CP0.n.SR |= 0x401;
2972 mips_return_c(1, 200);
2975 void psxBios_StopCARD() { // 4c
2976 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x4c]);
2977 storeRam32(A_RCNT_VBL_ACK + (3 << 2), 1);
2978 psxBios_SysDeqIntRP_(2, A_PADCRD_CHN_E);
2979 storeRam32(A_CARD_IRQR_ENA, 0);
2980 psxRegs.CP0.n.SR |= 0x401;
2981 mips_return_void_c(200);
2984 void psxBios__card_write() { // 0x4e
2989 PSXBIOS_LOG("psxBios_%s: %x,%x,%x\n", biosB0n[0x4e], a0, a1, a2);
2992 Function also accepts sector 400h (a bug).
2993 But notaz said we shouldn't allow sector 400h because it can corrupt the emulator.
2997 /* Invalid sectors */
3001 storeRam32(A_CARD_CHAN1, a0);
3004 if (pa2 != INVALID_PTR) {
3006 memcpy(Mcd1Data + a1 * 128, pa2, 128);
3007 SaveMcd(Config.Mcd1, Mcd1Data, a1 * 128, 128);
3009 memcpy(Mcd2Data + a1 * 128, pa2, 128);
3010 SaveMcd(Config.Mcd2, Mcd2Data, a1 * 128, 128);
3014 DeliverEvent(0xf0000011, 0x0004);
3015 // DeliverEvent(0xf4000001, 0x0004);
3020 void psxBios__card_read() { // 0x4f
3025 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x4f]);
3028 Function also accepts sector 400h (a bug).
3029 But notaz said we shouldn't allow sector 400h because it can corrupt the emulator.
3033 /* Invalid sectors */
3037 storeRam32(A_CARD_CHAN1, a0);
3040 if (pa2 != INVALID_PTR) {
3042 memcpy(pa2, Mcd1Data + a1 * 128, 128);
3044 memcpy(pa2, Mcd2Data + a1 * 128, 128);
3048 DeliverEvent(0xf0000011, 0x0004);
3049 // DeliverEvent(0xf4000001, 0x0004);
3054 void psxBios__new_card() { // 0x50
3056 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x50]);
3062 /* According to a user, this allows Final Fantasy Tactics to save/load properly */
3063 void psxBios__get_error(void) // 55
3065 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x55]);
3070 void psxBios_Krom2RawAdd() { // 0x51
3073 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x51]);
3074 const u32 table_8140[][2] = {
3075 {0x8140, 0x0000}, {0x8180, 0x0762}, {0x81ad, 0x0cc6}, {0x81b8, 0x0ca8},
3076 {0x81c0, 0x0f00}, {0x81c8, 0x0d98}, {0x81cf, 0x10c2}, {0x81da, 0x0e6a},
3077 {0x81e9, 0x13ce}, {0x81f0, 0x102c}, {0x81f8, 0x1590}, {0x81fc, 0x111c},
3078 {0x81fd, 0x1626}, {0x824f, 0x113a}, {0x8259, 0x20ee}, {0x8260, 0x1266},
3079 {0x827a, 0x24cc}, {0x8281, 0x1572}, {0x829b, 0x28aa}, {0x829f, 0x187e},
3080 {0x82f2, 0x32dc}, {0x8340, 0x2238}, {0x837f, 0x4362}, {0x8380, 0x299a},
3081 {0x8397, 0x4632}, {0x839f, 0x2c4c}, {0x83b7, 0x49f2}, {0x83bf, 0x2f1c},
3082 {0x83d7, 0x4db2}, {0x8440, 0x31ec}, {0x8461, 0x5dde}, {0x8470, 0x35ca},
3083 {0x847f, 0x6162}, {0x8480, 0x378c}, {0x8492, 0x639c}, {0x849f, 0x39a8},
3087 const u32 table_889f[][2] = {
3088 {0x889f, 0x3d68}, {0x8900, 0x40ec}, {0x897f, 0x4fb0}, {0x8a00, 0x56f4},
3089 {0x8a7f, 0x65b8}, {0x8b00, 0x6cfc}, {0x8b7f, 0x7bc0}, {0x8c00, 0x8304},
3090 {0x8c7f, 0x91c8}, {0x8d00, 0x990c}, {0x8d7f, 0xa7d0}, {0x8e00, 0xaf14},
3091 {0x8e7f, 0xbdd8}, {0x8f00, 0xc51c}, {0x8f7f, 0xd3e0}, {0x9000, 0xdb24},
3092 {0x907f, 0xe9e8}, {0x9100, 0xf12c}, {0x917f, 0xfff0}, {0x9200, 0x10734},
3093 {0x927f, 0x115f8}, {0x9300, 0x11d3c}, {0x937f, 0x12c00}, {0x9400, 0x13344},
3094 {0x947f, 0x14208}, {0x9500, 0x1494c}, {0x957f, 0x15810}, {0x9600, 0x15f54},
3095 {0x967f, 0x16e18}, {0x9700, 0x1755c}, {0x977f, 0x18420}, {0x9800, 0x18b64},
3099 if (a0 >= 0x8140 && a0 <= 0x84be) {
3100 while (table_8140[i][0] <= a0) i++;
3101 a0 -= table_8140[i - 1][0];
3102 v0 = 0xbfc66000 + (a0 * 0x1e + table_8140[i - 1][1]);
3103 } else if (a0 >= 0x889f && a0 <= 0x9872) {
3104 while (table_889f[i][0] <= a0) i++;
3105 a0 -= table_889f[i - 1][0];
3106 v0 = 0xbfc66000 + (a0 * 0x1e + table_889f[i - 1][1]);
3114 void psxBios_GetC0Table() { // 56
3115 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x56]);
3116 log_unhandled("GetC0Table @%08x\n", ra);
3118 mips_return_c(A_C0_TABLE, 3);
3121 void psxBios_GetB0Table() { // 57
3122 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x57]);
3123 log_unhandled("GetB0Table @%08x\n", ra);
3125 mips_return_c(A_B0_TABLE, 3);
3128 static void psxBios__card_chan() { // 0x58
3130 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x58]);
3132 // todo: should return active slot chan
3133 // (active - which was last processed by irq code)
3134 ret = loadRam32(A_CARD_CHAN1);
3135 mips_return_c(ret, 8);
3138 static void psxBios_ChangeClearPad() { // 5b
3140 PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x5b], a0);
3141 ret = loadRam32(A_PAD_ACK_VBL);
3142 storeRam32(A_PAD_ACK_VBL, a0);
3144 mips_return_c(ret, 6);
3147 static void psxBios__card_status() { // 5c
3148 PSXBIOS_LOG("psxBios_%s %x\n", biosB0n[0x5c], a0);
3154 static void psxBios__card_wait() { // 5d
3155 PSXBIOS_LOG("psxBios_%s %x\n", biosB0n[0x5d], a0);
3161 /* System calls C0 */
3163 static void psxBios_InitRCnt() { // 00
3165 PSXBIOS_LOG("psxBios_%s %x\n", biosC0n[0x00], a0);
3166 psxHwWrite16(0x1f801074, psxHu32(0x1074) & ~0x71);
3167 for (i = 0; i < 3; i++) {
3168 psxHwWrite16(0x1f801100 + i*0x10 + 4, 0);
3169 psxHwWrite16(0x1f801100 + i*0x10 + 8, 0);
3170 psxHwWrite16(0x1f801100 + i*0x10 + 0, 0);
3172 for (i = 0; i < 4; i++)
3173 psxBios_SysEnqIntRP_(a0, 0x6d58 + i * 0x10);
3174 mips_return_c(0, 9);
3177 static void psxBios_InitException() { // 01
3178 PSXBIOS_LOG("psxBios_%s %x\n", biosC0n[0x01], a0);
3179 psxBios_SysEnqIntRP_(a0, 0x6da8);
3180 mips_return_c(0, 9);
3184 * int SysEnqIntRP(int index , long *queue);
3187 static void psxBios_SysEnqIntRP_(u32 priority, u32 chain_eptr) {
3188 u32 old, base = loadRam32(A_TT_ExCB);
3190 old = loadRam32(base + (priority << 3));
3191 storeRam32(base + (priority << 3), chain_eptr);
3192 storeRam32(chain_eptr, old);
3193 mips_return_c(0, 9);
3196 static void psxBios_SysEnqIntRP() { // 02
3197 PSXBIOS_LOG("psxBios_%s %x %x\n", biosC0n[0x02], a0, a1);
3198 psxBios_SysEnqIntRP_(a0, a1);
3202 * int SysDeqIntRP(int index , long *queue);
3205 static void psxBios_SysDeqIntRP_(u32 priority, u32 chain_rm_eptr) {
3206 u32 ptr, next, base = loadRam32(A_TT_ExCB);
3207 u32 lim = 0, ret = 0;
3209 // as in original: no arg checks of any kind, bug if a1 == 0
3210 ptr = loadRam32(base + (priority << 3));
3212 next = loadRam32(ptr);
3213 if (ptr == chain_rm_eptr) {
3214 storeRam32(base + (priority << 3), next);
3219 while (next && next != chain_rm_eptr && lim++ < 100) {
3221 next = loadRam32(ptr);
3224 if (next == chain_rm_eptr) {
3225 next = loadRam32(next);
3226 storeRam32(ptr, next);
3233 PSXBIOS_LOG("bad chain %u %x\n", priority, base);
3235 mips_return_c(ret, 12);
3238 static void psxBios_SysDeqIntRP() { // 03
3239 PSXBIOS_LOG("psxBios_%s %x %x\n", biosC0n[0x03], a0, a1);
3240 psxBios_SysDeqIntRP_(a0, a1);
3243 static void psxBios_get_free_EvCB_slot() { // 04
3244 PSXBIOS_LOG("psxBios_%s\n", biosC0n[0x04]);
3245 s32 ret = get_free_EvCB_slot();
3246 mips_return_c(ret, 0);
3249 static void psxBios_SysInitMemory_(u32 base, u32 size) {
3250 storeRam32(base, 0);
3251 storeRam32(A_KMALLOC_PTR, base);
3252 storeRam32(A_KMALLOC_SIZE, size);
3253 storeRam32(A_KMALLOC_END, base + (size & ~3) + 4);
3256 // this should be much more complicated, but maybe that'll be enough
3257 static u32 psxBios_SysMalloc_(u32 size) {
3258 u32 ptr = loadRam32(A_KMALLOC_PTR);
3260 size = (size + 3) & ~3;
3261 storeRam32(A_KMALLOC_PTR, ptr + 4 + size);
3262 storeRam32(ptr, size);
3266 static void psxBios_SysInitMemory() { // 08
3267 PSXBIOS_LOG("psxBios_%s %x %x\n", biosC0n[0x08], a0, a1);
3269 psxBios_SysInitMemory_(a0, a1);
3270 mips_return_void_c(12);
3273 static void psxBios_ChangeClearRCnt() { // 0a
3276 PSXBIOS_LOG("psxBios_%s: %x, %x\n", biosC0n[0x0a], a0, a1);
3278 ret = loadRam32(A_RCNT_VBL_ACK + (a0 << 2));
3279 storeRam32(A_RCNT_VBL_ACK + (a0 << 2), a1);
3280 mips_return_c(ret, 8);
3283 static void psxBios_InitDefInt() { // 0c
3284 PSXBIOS_LOG("psxBios_%s %x\n", biosC0n[0x0c], a0);
3285 // should also clear the autoack table
3286 psxBios_SysEnqIntRP_(a0, 0x6d98);
3287 mips_return_c(0, 20 + 6*2);
3290 void psxBios_dummy() {
3291 u32 pc = (pc0 & 0x1fffff) - 4;
3292 char **ntab = pc == 0xa0 ? biosA0n : pc == 0xb0 ? biosB0n
3293 : pc == 0xc0 ? biosC0n : NULL;
3294 PSXBIOS_LOG("unk %x call: %x ra=%x (%s)\n",
3295 pc, t1, ra, ntab ? ntab[t1 & 0xff] : "???");
3296 (void)pc; (void)ntab;
3297 mips_return_c(0, 100);
3300 void (*biosA0[256])();
3301 // C0 and B0 overlap (end of C0 is start of B0)
3302 void (*biosC0[256+128])();
3303 void (**biosB0)() = biosC0 + 128;
3305 static void setup_mips_code()
3308 ptr = (u32 *)&psxM[A_SYSCALL];
3309 ptr[0x00/4] = SWAPu32(0x0000000c); // syscall 0
3310 ptr[0x04/4] = SWAPu32(0x03e00008); // jr $ra
3311 ptr[0x08/4] = SWAPu32(0x00000000); // nop
3313 ptr = (u32 *)&psxM[A_EXCEPTION];
3314 memset(ptr, 0, 0xc0); // nops (to be patched by games sometimes)
3315 ptr[0x10/4] = SWAPu32(0x8c1a0108); // lw $k0, (0x108) // PCB
3316 ptr[0x14/4] = SWAPu32(0x00000000); // nop
3317 ptr[0x18/4] = SWAPu32(0x8f5a0000); // lw $k0, ($k0) // TCB
3318 ptr[0x1c/4] = SWAPu32(0x00000000); // nop
3319 ptr[0x20/4] = SWAPu32(0x275a0008); // addiu $k0, $k0, 8 // regs
3320 ptr[0x24/4] = SWAPu32(0xaf5f007c); // sw $ra, 0x7c($k0)
3321 ptr[0x28/4] = SWAPu32(0xaf410004); // sw $at, 0x04($k0)
3322 ptr[0x2c/4] = SWAPu32(0xaf420008); // sw $v0, 0x08($k0)
3323 ptr[0x30/4] = SWAPu32(0xaf43000c); // sw $v1, 0x0c($k0)
3325 ptr[0x60/4] = SWAPu32(0x40037000); // mfc0 $v1, EPC
3326 ptr[0x64/4] = SWAPu32(0x40026800); // mfc0 $v0, Cause
3327 ptr[0x6c/4] = SWAPu32(0xaf430080); // sw $v1, 0x80($k0)
3329 ptr[0xb0/4] = HLEOP(hleop_exception);
3332 static const struct {
3336 { 0xbfc050a4, hleop_exc0_0_1 },
3337 { 0xbfc04fbc, hleop_exc0_0_2 },
3338 { 0xbfc0506c, hleop_exc0_1_1 },
3339 { 0xbfc04dec, hleop_exc0_1_2 },
3340 { 0x1a00, hleop_exc0_2_2 },
3341 { 0x19c8, hleop_exc1_0_1 },
3342 { 0x18bc, hleop_exc1_0_2 },
3343 { 0x1990, hleop_exc1_1_1 },
3344 { 0x1858, hleop_exc1_1_2 },
3345 { 0x1958, hleop_exc1_2_1 },
3346 { 0x17f4, hleop_exc1_2_2 },
3347 { 0x1920, hleop_exc1_3_1 },
3348 { 0x1794, hleop_exc1_3_2 },
3349 { 0x2458, hleop_exc3_0_2 },
3350 { 0x49bc, hleop_exc_padcard1 },
3351 { 0x4a4c, hleop_exc_padcard2 },
3354 static int chain_hle_op(u32 handler)
3358 for (i = 0; i < sizeof(chainfns) / sizeof(chainfns[0]); i++)
3359 if (chainfns[i].addr == handler)
3360 return chainfns[i].op;
3364 static void write_chain(u32 *d, u32 next, u32 handler1, u32 handler2)
3366 d[0] = SWAPu32(next);
3367 d[1] = SWAPu32(handler1);
3368 d[2] = SWAPu32(handler2);
3370 // install the hle traps
3371 if (handler1) PSXMu32ref(handler1) = HLEOP(chain_hle_op(handler1));
3372 if (handler2) PSXMu32ref(handler2) = HLEOP(chain_hle_op(handler2));
3375 static void setup_tt(u32 tcb_cnt, u32 evcb_cnt, u32 stack)
3377 u32 *ram32 = (u32 *)psxM;
3378 u32 s_excb = 0x20, s_evcb, s_pcb = 4, s_tcb;
3379 u32 p_excb, p_evcb, p_pcb, p_tcb;
3382 PSXBIOS_LOG("setup: tcb %u, evcb %u\n", tcb_cnt, evcb_cnt);
3384 // the real bios doesn't care, but we just don't
3385 // want to crash in case of garbage parameters
3386 if (tcb_cnt > 1024) tcb_cnt = 1024;
3387 if (evcb_cnt > 1024) evcb_cnt = 1024;
3388 s_evcb = 0x1c * evcb_cnt;
3389 s_tcb = 0xc0 * tcb_cnt;
3391 memset(ram32 + 0xe000/4, 0, s_excb + s_evcb + s_pcb + s_tcb + 5*4);
3392 psxBios_SysInitMemory_(0xa000e000, 0x2000);
3393 p_excb = psxBios_SysMalloc_(s_excb);
3394 p_evcb = psxBios_SysMalloc_(s_evcb);
3395 p_pcb = psxBios_SysMalloc_(s_pcb);
3396 p_tcb = psxBios_SysMalloc_(s_tcb);
3398 // "table of tables". Some games modify it
3399 assert(A_TT_ExCB == 0x0100);
3400 ram32[0x0100/4] = SWAPu32(p_excb); // ExCB - exception chains
3401 ram32[0x0104/4] = SWAPu32(s_excb); // ExCB size
3402 ram32[0x0108/4] = SWAPu32(p_pcb); // PCB - process control
3403 ram32[0x010c/4] = SWAPu32(s_pcb); // PCB size
3404 ram32[0x0110/4] = SWAPu32(p_tcb); // TCB - thread control
3405 ram32[0x0114/4] = SWAPu32(s_tcb); // TCB size
3406 ram32[0x0120/4] = SWAPu32(p_evcb); // EvCB - event control
3407 ram32[0x0124/4] = SWAPu32(s_evcb); // EvCB size
3408 ram32[0x0140/4] = SWAPu32(0x8648); // FCB - file control
3409 ram32[0x0144/4] = SWAPu32(0x02c0); // FCB size
3410 ram32[0x0150/4] = SWAPu32(0x6ee0); // DCB - device control
3411 ram32[0x0154/4] = SWAPu32(0x0320); // DCB size
3413 storeRam32(p_excb + 0*4, 0x0000); // chain0
3414 storeRam32(p_excb + 2*4, 0x6d88); // chain1
3415 storeRam32(p_excb + 4*4, 0x0000); // chain2
3416 storeRam32(p_excb + 6*4, 0x6d98); // chain3
3418 storeRam32(p_pcb, p_tcb);
3419 storeRam32(p_tcb, 0x4000); // first TCB
3420 for (i = 1; i < tcb_cnt; i++)
3421 storeRam32(p_tcb + sizeof(TCB) * i, 0x1000);
3423 psxBios_SysEnqIntRP_(0, 0x6da8);
3424 setup_cd_irq_and_events();
3426 storeRam32(A_CONF_EvCB, evcb_cnt);
3427 storeRam32(A_CONF_TCB, tcb_cnt);
3428 storeRam32(A_CONF_SP, stack);
3431 static const u32 gpu_ctl_def[] = {
3432 0x00000000, 0x01000000, 0x03000000, 0x04000000,
3433 0x05000800, 0x06c60260, 0x0703fc10, 0x08000027
3436 static const u32 gpu_data_def[] = {
3437 0xe100360b, 0xe2000000, 0xe3000800, 0xe4077e7f,
3438 0xe5001000, 0xe6000000,
3439 0x02000000, 0x00000000, 0x01ff03ff
3443 static const u16 spu_config[] = {
3444 0x3fff, 0x37ef, 0x5ebc, 0x5ebc, 0x0000, 0x0000, 0x0000, 0x00a0,
3445 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0x00ff, 0x0000, 0x0000,
3446 0x0000, 0xe128, 0x0000, 0x0200, 0xf0f0, 0xc085, 0x0004, 0x0000,
3447 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
3448 0x033d, 0x0231, 0x7e00, 0x5000, 0xb400, 0xb000, 0x4c00, 0xb000,
3449 0x6000, 0x5400, 0x1ed6, 0x1a31, 0x1d14, 0x183b, 0x1bc2, 0x16b2,
3450 0x1a32, 0x15ef, 0x15ee, 0x1055, 0x1334, 0x0f2d, 0x11f6, 0x0c5d,
3451 0x1056, 0x0ae1, 0x0ae0, 0x07a2, 0x0464, 0x0232, 0x8000, 0x8000
3454 void psxBiosSetupBootState(void)
3456 boolean hle = Config.HLE;
3457 u32 *hw = (u32 *)psxH;
3460 // see also SetBootRegs()
3463 a0 = 1; a2 = a3 = 0; a3 = 0x2a;
3464 t2 = 0x2d; t4 = 0x23; t5 = 0x2b; t6 = 0xa0010000;
3466 k0 = 0xbfc0d968; k1 = 0xf1c;
3467 ra = 0xf0001234; // just to easily detect attempts to return
3468 psxRegs.CP0.n.Cause = 0x20;
3469 psxRegs.CP0.n.EPC = 0xbfc0d964; // EnterCriticalSection syscall
3471 hw[0x1000/4] = SWAP32(0x1f000000);
3472 hw[0x1004/4] = SWAP32(0x1f802000);
3473 hw[0x1008/4] = SWAP32(0x0013243f);
3474 hw[0x100c/4] = SWAP32(0x00003022);
3475 hw[0x1010/4] = SWAP32(0x0013243f);
3476 hw[0x1014/4] = SWAP32(0x200931e1);
3477 hw[0x1018/4] = SWAP32(0x00020943);
3478 hw[0x101c/4] = SWAP32(0x00070777);
3479 hw[0x1020/4] = SWAP32(0x0000132c);
3480 hw[0x1060/4] = SWAP32(0x00000b88);
3481 hw[0x1070/4] = SWAP32(0x00000001);
3482 hw[0x1074/4] = SWAP32(0x0000000c);
3483 hw[0x2040/4] = SWAP32(0x00000900);
3486 hw[0x10a0/4] = SWAP32(0x00ffffff);
3487 hw[0x10a8/4] = SWAP32(0x00000401);
3488 hw[0x10b0/4] = SWAP32(0x0008b000);
3489 hw[0x10b4/4] = SWAP32(0x00010200);
3490 hw[0x10e0/4] = SWAP32(0x000eccf4);
3491 hw[0x10e4/4] = SWAP32(0x00000400);
3492 hw[0x10e8/4] = SWAP32(0x00000002);
3493 hw[0x10f0/4] = SWAP32(0x00009099);
3494 hw[0x10f4/4] = SWAP32(0x8c8c0000);
3503 for (i = 0; i < sizeof(gpu_ctl_def) / sizeof(gpu_ctl_def[0]); i++)
3504 GPU_writeStatus(gpu_ctl_def[i]);
3505 for (i = 0; i < sizeof(gpu_data_def) / sizeof(gpu_data_def[0]); i++)
3506 GPU_writeData(gpu_data_def[i]);
3509 for (i = 0x1f801d80; i < sizeof(spu_config) / sizeof(spu_config[0]); i++)
3510 SPU_writeRegister(0x1f801d80 + i*2, spu_config[i], psxRegs.cycle);
3513 static void hleExc0_0_1();
3514 static void hleExc0_0_2();
3515 static void hleExc0_1_1();
3516 static void hleExc0_1_2();
3518 #include "sjisfont.h"
3520 void psxBiosInit() {
3521 u32 *ptr, *ram32, *rom32;
3526 psxRegs.biosBranchCheck = ~0;
3528 memset(psxM, 0, 0x10000);
3529 for(i = 0; i < 256; i++) {
3534 biosA0[0x03] = biosB0[0x35] = psxBios_write_psxout;
3535 biosA0[0x3c] = biosB0[0x3d] = psxBios_putchar_psxout;
3536 biosA0[0x3e] = biosB0[0x3f] = psxBios_puts_psxout;
3537 biosA0[0x3f] = psxBios_printf_psxout;
3540 char verstr[0x24+1];
3541 rom32 = (u32 *)psxR;
3542 memcpy(verstr, psxR + 0x12c, 0x24);
3544 SysPrintf("BIOS: %08x, '%s', '%c'\n", SWAP32(rom32[0x100/4]),
3545 verstr, psxR[0x7ff52]);
3549 for(i = 0; i < 256; i++) {
3550 if (biosA0[i] == NULL) biosA0[i] = psxBios_dummy;
3551 if (biosB0[i] == NULL) biosB0[i] = psxBios_dummy;
3552 if (biosC0[i] == NULL) biosC0[i] = psxBios_dummy;
3555 biosA0[0x00] = psxBios_open;
3556 biosA0[0x01] = psxBios_lseek;
3557 biosA0[0x02] = psxBios_read;
3558 biosA0[0x03] = psxBios_write;
3559 biosA0[0x04] = psxBios_close;
3560 //biosA0[0x05] = psxBios_ioctl;
3561 //biosA0[0x06] = psxBios_exit;
3562 //biosA0[0x07] = psxBios_sys_a0_07;
3563 biosA0[0x08] = psxBios_getc;
3564 biosA0[0x09] = psxBios_putc;
3565 biosA0[0x0a] = psxBios_todigit;
3566 //biosA0[0x0b] = psxBios_atof;
3567 biosA0[0x0c] = psxBios_strtoul;
3568 biosA0[0x0d] = psxBios_strtol;
3569 biosA0[0x0e] = psxBios_abs;
3570 biosA0[0x0f] = psxBios_labs;
3571 biosA0[0x10] = psxBios_atoi;
3572 biosA0[0x11] = psxBios_atol;
3573 //biosA0[0x12] = psxBios_atob;
3574 biosA0[0x13] = psxBios_setjmp;
3575 biosA0[0x14] = psxBios_longjmp;
3576 biosA0[0x15] = psxBios_strcat;
3577 biosA0[0x16] = psxBios_strncat;
3578 biosA0[0x17] = psxBios_strcmp;
3579 biosA0[0x18] = psxBios_strncmp;
3580 biosA0[0x19] = psxBios_strcpy;
3581 biosA0[0x1a] = psxBios_strncpy;
3582 biosA0[0x1b] = psxBios_strlen;
3583 biosA0[0x1c] = psxBios_index;
3584 biosA0[0x1d] = psxBios_rindex;
3585 biosA0[0x1e] = psxBios_strchr;
3586 biosA0[0x1f] = psxBios_strrchr;
3587 biosA0[0x20] = psxBios_strpbrk;
3588 biosA0[0x21] = psxBios_strspn;
3589 biosA0[0x22] = psxBios_strcspn;
3590 biosA0[0x23] = psxBios_strtok;
3591 biosA0[0x24] = psxBios_strstr;
3592 biosA0[0x25] = psxBios_toupper;
3593 biosA0[0x26] = psxBios_tolower;
3594 biosA0[0x27] = psxBios_bcopy;
3595 biosA0[0x28] = psxBios_bzero;
3596 biosA0[0x29] = psxBios_bcmp;
3597 biosA0[0x2a] = psxBios_memcpy;
3598 biosA0[0x2b] = psxBios_memset;
3599 biosA0[0x2c] = psxBios_memmove;
3600 biosA0[0x2d] = psxBios_memcmp;
3601 biosA0[0x2e] = psxBios_memchr;
3602 biosA0[0x2f] = psxBios_rand;
3603 biosA0[0x30] = psxBios_srand;
3604 biosA0[0x31] = psxBios_qsort;
3605 //biosA0[0x32] = psxBios_strtod;
3606 biosA0[0x33] = psxBios_malloc;
3607 biosA0[0x34] = psxBios_free;
3608 //biosA0[0x35] = psxBios_lsearch;
3609 //biosA0[0x36] = psxBios_bsearch;
3610 biosA0[0x37] = psxBios_calloc;
3611 biosA0[0x38] = psxBios_realloc;
3612 biosA0[0x39] = psxBios_InitHeap;
3613 //biosA0[0x3a] = psxBios__exit;
3614 biosA0[0x3b] = psxBios_getchar;
3615 biosA0[0x3c] = psxBios_putchar;
3616 //biosA0[0x3d] = psxBios_gets;
3617 biosA0[0x3e] = psxBios_puts;
3618 biosA0[0x3f] = psxBios_printf;
3619 biosA0[0x40] = psxBios_SystemErrorUnresolvedException;
3620 //biosA0[0x41] = psxBios_LoadTest;
3621 biosA0[0x42] = psxBios_Load;
3622 biosA0[0x43] = psxBios_Exec;
3623 biosA0[0x44] = psxBios_FlushCache;
3624 //biosA0[0x45] = psxBios_InstallInterruptHandler;
3625 biosA0[0x46] = psxBios_GPU_dw;
3626 biosA0[0x47] = psxBios_mem2vram;
3627 biosA0[0x48] = psxBios_SendGPU;
3628 biosA0[0x49] = psxBios_GPU_cw;
3629 biosA0[0x4a] = psxBios_GPU_cwb;
3630 biosA0[0x4b] = psxBios_GPU_SendPackets;
3631 biosA0[0x4c] = psxBios_sys_a0_4c;
3632 biosA0[0x4d] = psxBios_GPU_GetGPUStatus;
3633 //biosA0[0x4e] = psxBios_GPU_sync;
3634 //biosA0[0x4f] = psxBios_sys_a0_4f;
3635 //biosA0[0x50] = psxBios_sys_a0_50;
3636 biosA0[0x51] = psxBios_LoadExec;
3637 //biosA0[0x52] = psxBios_GetSysSp;
3638 //biosA0[0x53] = psxBios_sys_a0_53;
3639 biosA0[0x54] = psxBios_CdInit;
3640 //biosA0[0x55] = psxBios__bu_init_a55;
3641 biosA0[0x56] = psxBios_CdRemove;
3642 //biosA0[0x57] = psxBios_sys_a0_57;
3643 //biosA0[0x58] = psxBios_sys_a0_58;
3644 //biosA0[0x59] = psxBios_sys_a0_59;
3645 //biosA0[0x5a] = psxBios_sys_a0_5a;
3646 //biosA0[0x5b] = psxBios_dev_tty_init;
3647 //biosA0[0x5c] = psxBios_dev_tty_open;
3648 //biosA0[0x5d] = psxBios_sys_a0_5d;
3649 //biosA0[0x5e] = psxBios_dev_tty_ioctl;
3650 //biosA0[0x5f] = psxBios_dev_cd_open;
3651 //biosA0[0x60] = psxBios_dev_cd_read;
3652 //biosA0[0x61] = psxBios_dev_cd_close;
3653 //biosA0[0x62] = psxBios_dev_cd_firstfile;
3654 //biosA0[0x63] = psxBios_dev_cd_nextfile;
3655 //biosA0[0x64] = psxBios_dev_cd_chdir;
3656 //biosA0[0x65] = psxBios_dev_card_open;
3657 //biosA0[0x66] = psxBios_dev_card_read;
3658 //biosA0[0x67] = psxBios_dev_card_write;
3659 //biosA0[0x68] = psxBios_dev_card_close;
3660 //biosA0[0x69] = psxBios_dev_card_firstfile;
3661 //biosA0[0x6a] = psxBios_dev_card_nextfile;
3662 //biosA0[0x6b] = psxBios_dev_card_erase;
3663 //biosA0[0x6c] = psxBios_dev_card_undelete;
3664 //biosA0[0x6d] = psxBios_dev_card_format;
3665 //biosA0[0x6e] = psxBios_dev_card_rename;
3666 //biosA0[0x6f] = psxBios_dev_card_6f;
3667 biosA0[0x70] = psxBios__bu_init;
3668 biosA0[0x71] = psxBios_CdInit;
3669 biosA0[0x72] = psxBios_CdRemove;
3670 //biosA0[0x73] = psxBios_sys_a0_73;
3671 //biosA0[0x74] = psxBios_sys_a0_74;
3672 //biosA0[0x75] = psxBios_sys_a0_75;
3673 //biosA0[0x76] = psxBios_sys_a0_76;
3674 //biosA0[0x77] = psxBios_sys_a0_77;
3675 //biosA0[0x78] = psxBios__96_CdSeekL;
3676 //biosA0[0x79] = psxBios_sys_a0_79;
3677 //biosA0[0x7a] = psxBios_sys_a0_7a;
3678 //biosA0[0x7b] = psxBios_sys_a0_7b;
3679 //biosA0[0x7c] = psxBios__96_CdGetStatus;
3680 //biosA0[0x7d] = psxBios_sys_a0_7d;
3681 //biosA0[0x7e] = psxBios__96_CdRead;
3682 //biosA0[0x7f] = psxBios_sys_a0_7f;
3683 //biosA0[0x80] = psxBios_sys_a0_80;
3684 //biosA0[0x81] = psxBios_sys_a0_81;
3685 //biosA0[0x82] = psxBios_sys_a0_82;
3686 //biosA0[0x83] = psxBios_sys_a0_83;
3687 //biosA0[0x84] = psxBios_sys_a0_84;
3688 //biosA0[0x85] = psxBios__96_CdStop;
3689 //biosA0[0x86] = psxBios_sys_a0_86;
3690 //biosA0[0x87] = psxBios_sys_a0_87;
3691 //biosA0[0x88] = psxBios_sys_a0_88;
3692 //biosA0[0x89] = psxBios_sys_a0_89;
3693 //biosA0[0x8a] = psxBios_sys_a0_8a;
3694 //biosA0[0x8b] = psxBios_sys_a0_8b;
3695 //biosA0[0x8c] = psxBios_sys_a0_8c;
3696 //biosA0[0x8d] = psxBios_sys_a0_8d;
3697 //biosA0[0x8e] = psxBios_sys_a0_8e;
3698 //biosA0[0x8f] = psxBios_sys_a0_8f;
3699 biosA0[0x90] = hleExc0_1_2;
3700 biosA0[0x91] = hleExc0_0_2;
3701 biosA0[0x92] = hleExc0_1_1;
3702 biosA0[0x93] = hleExc0_0_1;
3703 //biosA0[0x94] = psxBios_sys_a0_94;
3704 biosA0[0x95] = psxBios_CdReset;
3705 //biosA0[0x96] = psxBios_AddCDROMDevice;
3706 //biosA0[0x97] = psxBios_AddMemCardDevide;
3707 //biosA0[0x98] = psxBios_DisableKernelIORedirection;
3708 //biosA0[0x99] = psxBios_EnableKernelIORedirection;
3709 //biosA0[0x9a] = psxBios_sys_a0_9a;
3710 //biosA0[0x9b] = psxBios_sys_a0_9b;
3711 biosA0[0x9c] = psxBios_SetConf;
3712 biosA0[0x9d] = psxBios_GetConf;
3713 //biosA0[0x9e] = psxBios_sys_a0_9e;
3714 biosA0[0x9f] = psxBios_SetMem;
3715 //biosA0[0xa0] = psxBios__boot;
3716 //biosA0[0xa1] = psxBios_SystemError;
3717 biosA0[0xa2] = psxBios_EnqueueCdIntr;
3718 biosA0[0xa3] = psxBios_DequeueCdIntr;
3719 //biosA0[0xa4] = psxBios_sys_a0_a4;
3720 //biosA0[0xa5] = psxBios_ReadSector;
3721 biosA0[0xa6] = psxBios_get_cd_status;
3722 //biosA0[0xa7] = psxBios_bufs_cb_0;
3723 //biosA0[0xa8] = psxBios_bufs_cb_1;
3724 //biosA0[0xa9] = psxBios_bufs_cb_2;
3725 //biosA0[0xaa] = psxBios_bufs_cb_3;
3726 biosA0[0xab] = psxBios__card_info;
3727 biosA0[0xac] = psxBios__card_load;
3728 //biosA0[0axd] = psxBios__card_auto;
3729 //biosA0[0xae] = psxBios_bufs_cd_4;
3730 //biosA0[0xaf] = psxBios_sys_a0_af;
3731 //biosA0[0xb0] = psxBios_sys_a0_b0;
3732 //biosA0[0xb1] = psxBios_sys_a0_b1;
3733 //biosA0[0xb2] = psxBios_do_a_long_jmp
3734 //biosA0[0xb3] = psxBios_sys_a0_b3;
3735 biosA0[0xb4] = psxBios_GetSystemInfo;
3736 //*******************B0 CALLS****************************
3737 biosB0[0x00] = psxBios_SysMalloc;
3738 //biosB0[0x01] = psxBios_sys_b0_01;
3739 biosB0[0x02] = psxBios_SetRCnt;
3740 biosB0[0x03] = psxBios_GetRCnt;
3741 biosB0[0x04] = psxBios_StartRCnt;
3742 biosB0[0x05] = psxBios_StopRCnt;
3743 biosB0[0x06] = psxBios_ResetRCnt;
3744 biosB0[0x07] = psxBios_DeliverEvent;
3745 biosB0[0x08] = psxBios_OpenEvent;
3746 biosB0[0x09] = psxBios_CloseEvent;
3747 biosB0[0x0a] = psxBios_WaitEvent;
3748 biosB0[0x0b] = psxBios_TestEvent;
3749 biosB0[0x0c] = psxBios_EnableEvent;
3750 biosB0[0x0d] = psxBios_DisableEvent;
3751 biosB0[0x0e] = psxBios_OpenTh;
3752 biosB0[0x0f] = psxBios_CloseTh;
3753 biosB0[0x10] = psxBios_ChangeTh;
3754 //biosB0[0x11] = psxBios_psxBios_b0_11;
3755 biosB0[0x12] = psxBios_InitPAD;
3756 biosB0[0x13] = psxBios_StartPAD;
3757 biosB0[0x14] = psxBios_StopPAD;
3758 biosB0[0x15] = psxBios_PAD_init;
3759 biosB0[0x16] = psxBios_PAD_dr;
3760 biosB0[0x17] = psxBios_ReturnFromException;
3761 biosB0[0x18] = psxBios_ResetEntryInt;
3762 biosB0[0x19] = psxBios_HookEntryInt;
3763 //biosB0[0x1a] = psxBios_sys_b0_1a;
3764 //biosB0[0x1b] = psxBios_sys_b0_1b;
3765 //biosB0[0x1c] = psxBios_sys_b0_1c;
3766 //biosB0[0x1d] = psxBios_sys_b0_1d;
3767 //biosB0[0x1e] = psxBios_sys_b0_1e;
3768 //biosB0[0x1f] = psxBios_sys_b0_1f;
3769 biosB0[0x20] = psxBios_UnDeliverEvent;
3770 //biosB0[0x21] = psxBios_sys_b0_21;
3771 //biosB0[0x22] = psxBios_sys_b0_22;
3772 //biosB0[0x23] = psxBios_sys_b0_23;
3773 //biosB0[0x24] = psxBios_sys_b0_24;
3774 //biosB0[0x25] = psxBios_sys_b0_25;
3775 //biosB0[0x26] = psxBios_sys_b0_26;
3776 //biosB0[0x27] = psxBios_sys_b0_27;
3777 //biosB0[0x28] = psxBios_sys_b0_28;
3778 //biosB0[0x29] = psxBios_sys_b0_29;
3779 //biosB0[0x2a] = psxBios_sys_b0_2a;
3780 //biosB0[0x2b] = psxBios_sys_b0_2b;
3781 //biosB0[0x2c] = psxBios_sys_b0_2c;
3782 //biosB0[0x2d] = psxBios_sys_b0_2d;
3783 //biosB0[0x2e] = psxBios_sys_b0_2e;
3784 //biosB0[0x2f] = psxBios_sys_b0_2f;
3785 //biosB0[0x30] = psxBios_sys_b0_30;
3786 //biosB0[0x31] = psxBios_sys_b0_31;
3787 biosB0[0x32] = psxBios_open;
3788 biosB0[0x33] = psxBios_lseek;
3789 biosB0[0x34] = psxBios_read;
3790 biosB0[0x35] = psxBios_write;
3791 biosB0[0x36] = psxBios_close;
3792 //biosB0[0x37] = psxBios_ioctl;
3793 //biosB0[0x38] = psxBios_exit;
3794 //biosB0[0x39] = psxBios_sys_b0_39;
3795 //biosB0[0x3a] = psxBios_getc;
3796 //biosB0[0x3b] = psxBios_putc;
3797 biosB0[0x3c] = psxBios_getchar;
3798 biosB0[0x3d] = psxBios_putchar;
3799 //biosB0[0x3e] = psxBios_gets;
3800 biosB0[0x3f] = psxBios_puts;
3801 biosB0[0x40] = psxBios_cd;
3802 biosB0[0x41] = psxBios_format;
3803 biosB0[0x42] = psxBios_firstfile;
3804 biosB0[0x43] = psxBios_nextfile;
3805 biosB0[0x44] = psxBios_rename;
3806 biosB0[0x45] = psxBios_delete;
3807 //biosB0[0x46] = psxBios_undelete;
3808 //biosB0[0x47] = psxBios_AddDevice;
3809 //biosB0[0x48] = psxBios_RemoteDevice;
3810 //biosB0[0x49] = psxBios_PrintInstalledDevices;
3811 biosB0[0x4a] = psxBios_InitCARD;
3812 biosB0[0x4b] = psxBios_StartCARD;
3813 biosB0[0x4c] = psxBios_StopCARD;
3814 //biosB0[0x4d] = psxBios_sys_b0_4d;
3815 biosB0[0x4e] = psxBios__card_write;
3816 biosB0[0x4f] = psxBios__card_read;
3817 biosB0[0x50] = psxBios__new_card;
3818 biosB0[0x51] = psxBios_Krom2RawAdd;
3819 //biosB0[0x52] = psxBios_sys_b0_52;
3820 //biosB0[0x53] = psxBios_sys_b0_53;
3821 //biosB0[0x54] = psxBios__get_errno;
3822 biosB0[0x55] = psxBios__get_error;
3823 biosB0[0x56] = psxBios_GetC0Table;
3824 biosB0[0x57] = psxBios_GetB0Table;
3825 biosB0[0x58] = psxBios__card_chan;
3826 //biosB0[0x59] = psxBios_sys_b0_59;
3827 //biosB0[0x5a] = psxBios_sys_b0_5a;
3828 biosB0[0x5b] = psxBios_ChangeClearPad;
3829 biosB0[0x5c] = psxBios__card_status;
3830 biosB0[0x5d] = psxBios__card_wait;
3831 //*******************C0 CALLS****************************
3832 biosC0[0x00] = psxBios_InitRCnt;
3833 biosC0[0x01] = psxBios_InitException;
3834 biosC0[0x02] = psxBios_SysEnqIntRP;
3835 biosC0[0x03] = psxBios_SysDeqIntRP;
3836 biosC0[0x04] = psxBios_get_free_EvCB_slot;
3837 //biosC0[0x05] = psxBios_get_free_TCB_slot;
3838 //biosC0[0x06] = psxBios_ExceptionHandler;
3839 //biosC0[0x07] = psxBios_InstallExeptionHandler;
3840 biosC0[0x08] = psxBios_SysInitMemory;
3841 //biosC0[0x09] = psxBios_SysInitKMem;
3842 biosC0[0x0a] = psxBios_ChangeClearRCnt;
3843 //biosC0[0x0b] = psxBios_SystemError;
3844 biosC0[0x0c] = psxBios_InitDefInt;
3845 //biosC0[0x0d] = psxBios_sys_c0_0d;
3846 //biosC0[0x0e] = psxBios_sys_c0_0e;
3847 //biosC0[0x0f] = psxBios_sys_c0_0f;
3848 //biosC0[0x10] = psxBios_sys_c0_10;
3849 //biosC0[0x11] = psxBios_sys_c0_11;
3850 //biosC0[0x12] = psxBios_InstallDevices;
3851 //biosC0[0x13] = psxBios_FlushStfInOutPut;
3852 //biosC0[0x14] = psxBios_sys_c0_14;
3853 //biosC0[0x15] = psxBios__cdevinput;
3854 //biosC0[0x16] = psxBios__cdevscan;
3855 //biosC0[0x17] = psxBios__circgetc;
3856 //biosC0[0x18] = psxBios__circputc;
3857 //biosC0[0x19] = psxBios_ioabort;
3858 //biosC0[0x1a] = psxBios_sys_c0_1a
3859 //biosC0[0x1b] = psxBios_KernelRedirect;
3860 //biosC0[0x1c] = psxBios_PatchAOTable;
3861 //************** THE END ***************************************
3864 memset(FDesc, 0, sizeof(FDesc));
3865 memset(cdir, 0, sizeof(cdir));
3868 // somewhat pretend to be a SCPH1001 BIOS
3869 // some games look for these and take an exception if they're missing
3870 rom32 = (u32 *)psxR;
3871 rom32[0x100/4] = SWAP32(0x19951204);
3872 rom32[0x104/4] = SWAP32(3);
3873 romc = (char *)psxR;
3874 strcpy(romc + 0x108, "PCSX authors");
3875 strcpy(romc + 0x12c, "CEX-3000 PCSX HLE"); // see psxBios_GetSystemInfo
3876 strcpy(romc + 0x7ff32, "System ROM Version 2.2 12/04/95 A");
3877 strcpy(romc + 0x7ff54, "GPL-2.0-or-later");
3880 len = 0x80000 - 0x66000;
3881 uncompress((Bytef *)(psxR + 0x66000), &len, font_8140, sizeof(font_8140));
3882 len = 0x80000 - 0x69d68;
3883 uncompress((Bytef *)(psxR + 0x69d68), &len, font_889f, sizeof(font_889f));
3885 // trap attempts to call bios directly
3886 rom32[0x00000/4] = HLEOP(hleop_dummy);
3887 rom32[0x00180/4] = HLEOP(hleop_dummy);
3888 rom32[0x3fffc/4] = HLEOP(hleop_dummy);
3889 rom32[0x65ffc/4] = HLEOP(hleop_dummy);
3890 rom32[0x7ff2c/4] = HLEOP(hleop_dummy);
3892 /* Some games like R-Types, CTR, Fade to Black read from adress 0x00000000 due to uninitialized pointers.
3893 See Garbage Area at Address 00000000h in Nocash PSX Specfications for more information.
3894 Here are some examples of games not working with this fix in place :
3895 R-type won't get past the Irem logo if not implemented.
3896 Crash Team Racing will softlock after the Sony logo.
3899 ram32 = (u32 *)psxM;
3900 ram32[0x0000/4] = SWAPu32(0x00000003); // lui $k0, 0 (overwritten by 3)
3901 ram32[0x0004/4] = SWAPu32(0x275a0000 + A_EXCEPTION); // addiu $k0, $k0, 0xc80
3902 ram32[0x0008/4] = SWAPu32(0x03400008); // jr $k0
3903 ram32[0x000c/4] = SWAPu32(0x00000000); // nop
3905 ram32[0x0060/4] = SWAPu32(0x00000002); // ram size?
3906 ram32[0x0068/4] = SWAPu32(0x000000ff); // unknown
3908 ram32[0x0080/4] = SWAPu32(0x3c1a0000); // lui $k0, 0 // exception vector
3909 ram32[0x0084/4] = SWAPu32(0x275a0000 + A_EXCEPTION); // addiu $k0, $k0, 0xc80
3910 ram32[0x0088/4] = SWAPu32(0x03400008); // jr $k0
3911 ram32[0x008c/4] = SWAPu32(0x00000000); // nop
3913 ram32[0x00a0/4] = HLEOP(hleop_a0);
3914 ram32[0x00b0/4] = HLEOP(hleop_b0);
3915 ram32[0x00c0/4] = HLEOP(hleop_c0);
3917 setup_tt(4, 16, 0x801fff00);
3918 DeliverEvent(0xf0000003, 0x0010);
3920 ram32[0x6ee0/4] = SWAPu32(0x0000eff0); // DCB
3921 strcpy((char *)&ram32[0xeff0/4], "bu");
3923 // default exception handler chains
3924 // see also setup_cd_irq_and_events()
3925 write_chain(&ram32[0x91e0/4], 0x91d0, 0xbfc050a4, 0xbfc04fbc); // chain0.e0
3926 write_chain(&ram32[0x91d0/4], 0x6da8, 0xbfc0506c, 0xbfc04dec); // chain0.e1
3927 write_chain(&ram32[0x6da8/4], 0, 0, 0x1a00); // chain0.e2
3928 write_chain(&ram32[0x6d88/4], 0x6d78, 0x19c8, 0x18bc); // chain1.e0
3929 write_chain(&ram32[0x6d78/4], 0x6d68, 0x1990, 0x1858); // chain1.e1
3930 write_chain(&ram32[0x6d68/4], 0x6d58, 0x1958, 0x17f4); // chain1.e2
3931 write_chain(&ram32[0x6d58/4], 0, 0x1920, 0x1794); // chain1.e3
3932 write_chain(&ram32[0x6d98/4], 0, 0, 0x2458); // chain3.e0
3936 // fill the api jumptables with fake entries as some games patch them
3937 // (or rather the funcs listed there)
3938 // also trap the destination as some "Cheats Edition" thing overrides the
3939 // dispatcher with a wrapper and then jumps to the table entries directly
3940 ptr = (u32 *)&psxM[A_A0_TABLE];
3941 for (i = 0; i < 256; i++) {
3942 ptr[i] = SWAP32(A_A0_TRAPS + i*4);
3943 ram32[A_A0_TRAPS/4 + i] = HLEOP(hleop_a0t);
3945 ptr = (u32 *)&psxM[A_B0_TABLE];
3946 for (i = 0; i < 256; i++) {
3947 ptr[i] = SWAP32(A_B0_TRAPS + i*4);
3948 ram32[A_B0_TRAPS/4 + i] = HLEOP(hleop_b0t);
3950 // B(5b) is special because games patch (sometimes even jump to)
3951 // code at fixed offsets from it, nocash lists offsets:
3952 // patch: +3d8, +4dc, +594, +62c, +9c8, +1988
3953 // call: +7a0=4b70, +884=4c54, +894=4c64
3954 ptr[0x5b] = SWAP32(A_B0_5B_TRAP); // 0x43d0
3955 ram32[A_B0_5B_TRAP/4] = HLEOP(hleop_b0t);
3957 ram32[0x4b70/4] = SWAP32(0x03e00008); // jr $ra // setPadOutputBuf
3959 ram32[0x4c54/4] = SWAP32(0x240e0001); // mov $t6, 1
3960 ram32[0x4c58/4] = SWAP32(0x03e00008); // jr $ra
3961 ram32[0x4c5c/4] = SWAP32(0xac0e0000 + A_PAD_IRQR_ENA); // sw $t6, ...
3963 ram32[0x4c64/4] = SWAP32(0x03e00008); // jr $ra
3964 ram32[0x4c68/4] = SWAP32(0xac000000 + A_PAD_IRQR_ENA); // sw $0, ...
3966 ptr = (u32 *)&psxM[A_C0_TABLE];
3967 for (i = 0; i < 256/2; i++) {
3968 ptr[i] = SWAP32(A_C0_TRAPS + i*4);
3969 ram32[A_C0_TRAPS/4 + i] = HLEOP(hleop_c0t);
3971 ptr[6] = SWAP32(A_EXCEPTION);
3974 ram32[A_A0_TRAPS/4 - 1] = HLEOP(hleop_dummy);
3975 ram32[A_B0_TRAPS/4 - 1] = HLEOP(hleop_dummy);
3976 ram32[A_C0_TRAPS/4 - 1] = HLEOP(hleop_dummy);
3977 ram32[0x7ffc/4] = HLEOP(hleop_dummy);
3978 ram32[0x8000/4] = HLEOP(hleop_execret);
3980 ram32[A_EEXIT_PTR/4] = SWAP32(A_EEXIT_DEF);
3981 ram32[A_EXC_SP/4] = SWAP32(A_EXC_STACK);
3982 ram32[A_RCNT_VBL_ACK/4 + 0] = SWAP32(1);
3983 ram32[A_RCNT_VBL_ACK/4 + 1] = SWAP32(1);
3984 ram32[A_RCNT_VBL_ACK/4 + 2] = SWAP32(1);
3985 ram32[A_RCNT_VBL_ACK/4 + 3] = SWAP32(1);
3986 ram32[A_RND_SEED/4] = SWAPu32(0x24040001); // was 0xac20cc00
3989 void psxBiosShutdown() {
3992 void psxBiosCnfLoaded(u32 tcb_cnt, u32 evcb_cnt, u32 stack) {
3995 if (tcb_cnt != 4 || evcb_cnt != 16) {
3996 setup_tt(tcb_cnt, evcb_cnt, stack);
3997 DeliverEvent(0xf0000003, 0x0010);
3999 storeRam32(A_CONF_SP, stack);
4002 #define psxBios_PADpoll(pad) { \
4003 int i, more_data = 0; \
4004 PAD##pad##_startPoll(pad); \
4005 pad_buf##pad[1] = PAD##pad##_poll(0x42, &more_data); \
4006 pad_buf##pad[0] = more_data ? 0 : 0xff; \
4007 PAD##pad##_poll(0, &more_data); \
4009 while (more_data) { \
4010 pad_buf##pad[i++] = PAD##pad##_poll(0, &more_data); \
4014 static void handle_chain_x_x_1(u32 enable, u32 irqbit)
4018 psxHwWrite16(0x1f801070, ~(1u << irqbit));
4019 psxBios_ReturnFromException();
4025 // hleExc0_{0,1}* are usually removed by A(56)/A(72) on the game's startup,
4026 // so this is only partially implemented
4027 static void hleExc0_0_1() // A(93h) - CdromDmaIrqFunc2
4029 u32 cdrom_dma_ack_enable = 1; // a000b93c
4030 handle_chain_x_x_1(cdrom_dma_ack_enable, 3); // IRQ3 DMA
4033 static void hleExc0_0_2() // A(91h) - CdromDmaIrqFunc1
4036 //PSXBIOS_LOG("%s\n", __func__);
4038 if (psxHu32(0x1074) & psxHu32(0x1070) & 8) { // IRQ3 DMA
4039 psxHwWrite32(0x1f8010f4, (psxHu32(0x10f4) & 0xffffff) | 0x88000000);
4040 //if (--cdrom_irq_counter == 0) // 0xa0009180
4041 // DeliverEvent(0xf0000003, 0x10);
4045 mips_return_c(ret, 20);
4048 static void hleExc0_1_1() // A(92h) - CdromIoIrqFunc2
4050 u32 cdrom_irq_ack_enable = 1; // a000b938
4051 handle_chain_x_x_1(cdrom_irq_ack_enable, 2); // IRQ2 cdrom
4054 static void hleExc0_1_2() // A(90h) - CdromIoIrqFunc1
4057 if (psxHu32(0x1074) & psxHu32(0x1070) & 4) { // IRQ2 cdrom
4058 PSXBIOS_LOG("%s TODO\n", __func__);
4061 mips_return_c(ret, 20);
4064 static void hleExc0_2_2_syscall() // not in any A/B/C table
4066 u32 tcbPtr = loadRam32(A_TT_PCB);
4067 TCB *tcb = loadRam32ptr(tcbPtr);
4068 u32 code = (SWAP32(tcb->cause) & 0x3c) >> 2;
4070 if (code != R3000E_Syscall) {
4072 DeliverEvent(0xf0000010, 0x1000);
4073 //psxBios_SystemErrorUnresolvedException();
4075 mips_return_c(0, 17);
4079 //printf("%s c=%d a0=%d\n", __func__, code, SWAP32(tcb->reg[4]));
4080 tcb->epc += SWAP32(4);
4081 switch (SWAP32(tcb->reg[4])) { // a0
4085 case 1: { // EnterCritical - disable irqs
4086 u32 was_enabled = ((SWAP32(tcb->sr) & 0x404) == 0x404);
4087 tcb->reg[2] = SWAP32(was_enabled);
4088 tcb->sr &= SWAP32(~0x404);
4091 case 2: // ExitCritical - enable irqs
4092 tcb->sr |= SWAP32(0x404);
4095 case 3: { // ChangeThreadSubFunction
4096 u32 tcbPtr = loadRam32(A_TT_PCB);
4097 storeRam32(tcbPtr, SWAP32(tcb->reg[5])); // a1
4101 DeliverEvent(0xf0000010, 0x4000);
4105 psxBios_ReturnFromException();
4108 static void hleExc1_0_1(void)
4110 u32 vbl_irq_ack_enable = loadRam32(A_RCNT_VBL_ACK + 0x0c); // 860c
4111 handle_chain_x_x_1(vbl_irq_ack_enable, 0); // IRQ0 vblank
4114 static void handle_chain_1_x_2(u32 ev_index, u32 irqbit)
4117 if (psxHu32(0x1074) & psxHu32(0x1070) & (1u << irqbit)) {
4118 DeliverEvent(0xf2000000 + ev_index, 0x0002);
4121 mips_return_c(ret, 22);
4124 static void hleExc1_0_2(void)
4126 handle_chain_1_x_2(3, 0); // IRQ0 vblank
4129 static void hleExc1_1_1(void)
4131 u32 rcnt_irq_ack_enable = loadRam32(A_RCNT_VBL_ACK + 0x08); // 8608
4132 handle_chain_x_x_1(rcnt_irq_ack_enable, 6); // IRQ6 rcnt2
4135 static void hleExc1_1_2(void)
4137 handle_chain_1_x_2(2, 6); // IRQ6 rcnt2
4140 static void hleExc1_2_1(void)
4142 u32 rcnt_irq_ack_enable = loadRam32(A_RCNT_VBL_ACK + 0x04); // 8604
4143 handle_chain_x_x_1(rcnt_irq_ack_enable, 5); // IRQ5 rcnt1
4146 static void hleExc1_2_2(void)
4148 handle_chain_1_x_2(1, 5); // IRQ5 rcnt1
4151 static void hleExc1_3_1(void)
4153 u32 rcnt_irq_ack_enable = loadRam32(A_RCNT_VBL_ACK + 0x00); // 8600
4154 handle_chain_x_x_1(rcnt_irq_ack_enable, 4); // IRQ4 rcnt0
4157 static void hleExc1_3_2(void)
4159 handle_chain_1_x_2(0, 4); // IRQ4 rcnt0
4162 static void hleExc3_0_2_defint(void)
4164 static const struct {
4175 { 6, 6 }, // rcnt2 (bug)
4180 for (i = 0; i < sizeof(tab) / sizeof(tab[0]); i++) {
4181 if (psxHu32(0x1074) & psxHu32(0x1070) & (1u << tab[i].irqbit)) {
4182 DeliverEvent(0xf0000000 + tab[i].ev, 0x1000);
4187 mips_return_c(0, 11 + 7*11 + 7*11 + 12);
4190 static void hleExcPadCard1(void)
4192 if (loadRam32(A_PAD_IRQR_ENA)) {
4193 u8 *pad_buf1 = loadRam8ptr(A_PAD_INBUF + 0);
4194 u8 *pad_buf2 = loadRam8ptr(A_PAD_INBUF + 4);
4199 if (loadRam32(A_PAD_DR_DST))
4202 if (loadRam32(A_PAD_ACK_VBL))
4203 psxHwWrite16(0x1f801070, ~1);
4204 if (loadRam32(A_CARD_IRQR_ENA)) {
4208 mips_return_c(0, 18);
4211 static void hleExcPadCard2(void)
4213 u32 ret = psxHu32(0x1074) & psxHu32(0x1070) & 1;
4214 mips_return_c(ret, 15);
4217 void psxBiosException() {
4218 u32 tcbPtr = loadRam32(A_TT_PCB);
4219 u32 *chains = loadRam32ptr(A_TT_ExCB);
4220 TCB *tcb = loadRam32ptr(tcbPtr);
4226 // $at, $v0, $v1, $ra already saved by the mips code at A_EXCEPTION
4227 for (i = 4; i < 31; i++) {
4230 tcb->reg[i] = SWAP32(psxRegs.GPR.r[i]);
4232 tcb->lo = SWAP32(psxRegs.GPR.n.lo);
4233 tcb->hi = SWAP32(psxRegs.GPR.n.hi);
4234 //tcb->epc = SWAP32(psxRegs.CP0.n.EPC); // done by asm
4235 tcb->sr = SWAP32(psxRegs.CP0.n.SR);
4236 tcb->cause = SWAP32(psxRegs.CP0.n.Cause);
4237 sp = fp = loadRam32(A_EXC_SP);
4240 assert(!psxRegs.cpuInRecursion);
4242 // do the chains (always 4)
4243 for (c = lim = 0; c < 4; c++) {
4244 if (chains[c * 2] == 0)
4246 ptr = SWAP32(chains[c * 2]);
4247 for (; ptr && lim < 100; ptr = SWAP32(chain[0])) {
4248 chain = castRam32ptr(ptr);
4253 softCallInException(SWAP32(chain[2]));
4254 if (returned_from_exception())
4257 if (v0 == 0 || chain[1] == 0)
4259 softCallInException(SWAP32(chain[1]));
4260 if (returned_from_exception())
4266 // return from exception (custom or default)
4268 ptr = loadRam32(A_EEXIT_PTR);
4269 if (ptr != A_EEXIT_DEF) {
4270 const struct jmp_buf_ *jmp_buf = castRam32ptr(ptr);
4271 longjmp_load(jmp_buf);
4276 psxBios_ReturnFromException();
4280 static void hleDummy() {
4281 log_unhandled("hleDummy called @%08x ra=%08x\n", psxRegs.pc - 4, ra);
4283 psxRegs.cycle += 1000;
4288 static void hleA0() {
4289 u32 call = t1 & 0xff;
4290 u32 entry = loadRam32(A_A0_TABLE + call * 4);
4293 if (call < 192 && entry != A_A0_TRAPS + call * 4) {
4294 PSXBIOS_LOG("custom A%02x %s(0x%x, ) addr=%08x ra=%08x\n",
4295 call, biosA0n[call], a0, entry, ra);
4298 PSXBIOS_LOG(" -> %08x\n", v0);
4300 else if (biosA0[call])
4303 //printf("A(%02x) -> %x\n", call, v0);
4307 static void hleB0() {
4308 u32 call = t1 & 0xff;
4309 u32 entry = loadRam32(A_B0_TABLE + call * 4);
4314 is_custom = entry != A_B0_5B_TRAP;
4316 is_custom = entry != A_B0_TRAPS + call * 4;
4318 PSXBIOS_LOG("custom B%02x %s(0x%x, ) addr=%08x ra=%08x\n",
4319 call, biosB0n[call], a0, entry, ra);
4322 PSXBIOS_LOG(" -> %08x\n", v0);
4324 else if (biosB0[call])
4327 //printf("B(%02x) -> %x\n", call, v0);
4331 static void hleC0() {
4332 u32 call = t1 & 0xff;
4333 u32 entry = loadRam32(A_C0_TABLE + call * 4);
4336 if (call < 128 && entry != A_C0_TRAPS + call * 4) {
4337 PSXBIOS_LOG("custom C%02x %s(0x%x, ) addr=%08x ra=%08x\n",
4338 call, biosC0n[call], a0, entry, ra);
4341 PSXBIOS_LOG(" -> %08x\n", v0);
4343 else if (biosC0[call])
4346 //printf("C(%02x) -> %x\n", call, v0);
4350 static void hleA0t() {
4351 u32 call = (pc0 - A_A0_TRAPS) / 4 - 1;
4352 if (call >= 256u || !biosA0[call]) {
4353 log_unhandled("unexpected A trap @%08x ra=%08x\n", pc0 - 4, ra);
4354 mips_return_void_c(1000);
4359 //printf("A(%02x) -> %x\n", call, v0);
4363 static void hleB0t() {
4364 u32 call = (pc0 - A_B0_TRAPS) / 4 - 1;
4365 if (pc0 - 4 == A_B0_5B_TRAP)
4367 if (call >= 256u || !biosB0[call]) {
4368 log_unhandled("unexpected B trap @%08x ra=%08x\n", pc0 - 4, ra);
4369 mips_return_void_c(1000);
4374 //printf("B(%02x) -> %x\n", call, v0);
4378 static void hleC0t() {
4379 u32 call = (pc0 - A_C0_TRAPS) / 4 - 1;
4380 if (call >= 128u || !biosC0[call]) {
4381 log_unhandled("unexpected C trap @%08x ra=%08x\n", pc0 - 4, ra);
4382 mips_return_void_c(1000);
4387 //printf("C(%02x) -> %x\n", call, v0);
4391 // currently not used
4392 static void hleBootstrap() {
4397 static void hleExecRet() {
4398 const EXEC *header = (EXEC *)PSXM(s0);
4400 PSXBIOS_LOG("ExecRet %x: %x\n", s0, header->ret);
4402 ra = SWAP32(header->ret);
4403 sp = SWAP32(header->_sp);
4404 fp = SWAP32(header->_fp);
4405 gp = SWAP32(header->_gp);
4406 s0 = SWAP32(header->base);
4412 void (* const psxHLEt[hleop_count_])() = {
4413 hleDummy, hleA0, hleB0, hleC0,
4414 hleBootstrap, hleExecRet, psxBiosException, hleDummy,
4415 hleExc0_0_1, hleExc0_0_2,
4416 hleExc0_1_1, hleExc0_1_2, hleExc0_2_2_syscall,
4417 hleExc1_0_1, hleExc1_0_2,
4418 hleExc1_1_1, hleExc1_1_2,
4419 hleExc1_2_1, hleExc1_2_2,
4420 hleExc1_3_1, hleExc1_3_2,
4422 hleExcPadCard1, hleExcPadCard2,
4423 hleA0t, hleB0t, hleC0t,
4426 void psxBiosCheckExe(u32 t_addr, u32 t_size, int loading_state)
4428 // lw $v0, 0x10($sp)
4431 // sw $v0, 0x10($sp)
4432 // lw $v0, 0x10($sp)
4434 // bne $v0, $v1, not_timeout
4437 static const u8 pattern[] = {
4438 0x10, 0x00, 0xA2, 0x8F, 0x00, 0x00, 0x00, 0x00,
4439 0xFF, 0xFF, 0x42, 0x24, 0x10, 0x00, 0xA2, 0xAF,
4440 0x10, 0x00, 0xA2, 0x8F, 0x00, 0x00, 0x00, 0x00,
4441 0x0C, 0x00, 0x43, 0x14, 0x00, 0x00, 0x00, 0x00,
4443 u32 start = t_addr & 0x1ffffc;
4444 u32 end = (start + t_size) & 0x1ffffc;
4445 u32 buf[sizeof(pattern) / sizeof(u32)];
4446 const u32 *r32 = (u32 *)(psxM + start);
4454 memcpy(buf, pattern, sizeof(buf));
4455 for (i = 0; i < t_size / 4; i += j + 1) {
4456 for (j = 0; j < sizeof(buf) / sizeof(buf[0]); j++)
4457 if (r32[i + j] != buf[j])
4459 if (j != sizeof(buf) / sizeof(buf[0]))
4462 if ((SWAP32(r32[i + j]) >> 16) != 0x3c04) // lui
4465 SysPrintf("HLE vsync @%08x\n", start + i * 4);
4466 psxRegs.biosBranchCheck = (t_addr & 0xa01ffffc) + i * 4;
4470 void psxBiosCheckBranch(void)
4474 static u32 cycles_prev, v0_prev;
4475 u32 cycles_passed, waste_cycles;
4476 u32 loops, v0_expect = v0_prev - 1;
4480 cycles_passed = psxRegs.cycle - cycles_prev;
4481 cycles_prev = psxRegs.cycle;
4483 if (cycles_passed < 10 || cycles_passed > 50 || v0 != v0_expect)
4486 waste_cycles = schedule_timeslice() - psxRegs.cycle;
4487 loops = waste_cycles / cycles_passed;
4491 psxRegs.cycle += loops * cycles_passed;
4492 //printf("c %4u %d\n", loops, cycles_passed);
4496 #define bfreeze(ptr, size) { \
4497 if (Mode == 1) memcpy(&psxR[base], ptr, size); \
4498 if (Mode == 0) memcpy(ptr, &psxR[base], size); \
4502 #define bfreezes(ptr) bfreeze(ptr, sizeof(ptr))
4503 #define bfreezel(ptr) bfreeze(ptr, sizeof(*(ptr)))
4505 void psxBiosFreeze(int Mode) {