psxbios: handle dynamic CB alloc
[pcsx_rearmed.git] / libpcsxcore / psxbios.c
1 /***************************************************************************
2  *   Copyright (C) 2019 Ryan Schultz, PCSX-df Team, PCSX team, gameblabla, *
3  *       dmitrysmagin, senquack                                                                                            *
4  *                                                                         *
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.                                   *
9  *                                                                         *
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.                          *
14  *                                                                         *
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  ***************************************************************************/
20
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.
25  * */
26
27 /*
28  * Internal simulated HLE BIOS.
29  */
30
31 // TODO: implement all system calls, count the exact CPU cycles of system calls.
32
33 #include "psxbios.h"
34 #include "psxhw.h"
35 #include "gpu.h"
36 #include "sio.h"
37 #include "psxhle.h"
38 #include <zlib.h>
39
40 #if (defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)
41 #pragma GCC diagnostic ignored "-Wpointer-sign"
42 #endif
43
44 #undef SysPrintf
45 #define SysPrintf if (Config.PsxOut) printf
46
47 char *biosA0n[256] = {
48 // 0x00
49         "open",         "lseek",        "read",         "write",
50         "close",        "ioctl",        "exit",         "sys_a0_07",
51         "getc",         "putc",         "todigit",      "atof",
52         "strtoul",      "strtol",       "abs",          "labs",
53 // 0x10
54         "atoi",         "atol",         "atob",         "setjmp",
55         "longjmp",      "strcat",       "strncat",      "strcmp",
56         "strncmp",      "strcpy",       "strncpy",      "strlen",
57         "index",        "rindex",       "strchr",       "strrchr",
58 // 0x20
59         "strpbrk",      "strspn",       "strcspn",      "strtok",
60         "strstr",       "toupper",      "tolower",      "bcopy",
61         "bzero",        "bcmp",         "memcpy",       "memset",
62         "memmove",      "memcmp",       "memchr",       "rand",
63 // 0x30
64         "srand",        "qsort",        "strtod",       "malloc",
65         "free",         "lsearch",      "bsearch",      "calloc",
66         "realloc",      "InitHeap",     "_exit",        "getchar",
67         "putchar",      "gets",         "puts",         "printf",
68 // 0x40
69         "sys_a0_40",            "LoadTest",                                     "Load",         "Exec",
70         "FlushCache",           "InstallInterruptHandler",      "GPU_dw",       "mem2vram",
71         "SendGPUStatus",        "GPU_cw",                                       "GPU_cwb",      "SendPackets",
72         "sys_a0_4c",            "GetGPUStatus",                         "GPU_sync",     "sys_a0_4f",
73 // 0x50
74         "sys_a0_50",            "LoadExec",                             "GetSysSp",             "sys_a0_53",
75         "_96_init()",           "_bu_init()",                   "_96_remove()", "sys_a0_57",
76         "sys_a0_58",            "sys_a0_59",                    "sys_a0_5a",    "dev_tty_init",
77         "dev_tty_open",         "sys_a0_5d",                    "dev_tty_ioctl","dev_cd_open",
78 // 0x60
79         "dev_cd_read",          "dev_cd_close",                 "dev_cd_firstfile",     "dev_cd_nextfile",
80         "dev_cd_chdir",         "dev_card_open",                "dev_card_read",        "dev_card_write",
81         "dev_card_close",       "dev_card_firstfile",   "dev_card_nextfile","dev_card_erase",
82         "dev_card_undelete","dev_card_format",          "dev_card_rename",      "dev_card_6f",
83 // 0x70
84         "_bu_init",                     "_96_init",             "CdRemove",             "sys_a0_73",
85         "sys_a0_74",            "sys_a0_75",    "sys_a0_76",            "sys_a0_77",
86         "_96_CdSeekL",          "sys_a0_79",    "sys_a0_7a",            "sys_a0_7b",
87         "_96_CdGetStatus",      "sys_a0_7d",    "_96_CdRead",           "sys_a0_7f",
88 // 0x80
89         "sys_a0_80",            "sys_a0_81",    "sys_a0_82",            "sys_a0_83",
90         "sys_a0_84",            "_96_CdStop",   "sys_a0_86",            "sys_a0_87",
91         "sys_a0_88",            "sys_a0_89",    "sys_a0_8a",            "sys_a0_8b",
92         "sys_a0_8c",            "sys_a0_8d",    "sys_a0_8e",            "sys_a0_8f",
93 // 0x90
94         "sys_a0_90",            "sys_a0_91",    "sys_a0_92",            "sys_a0_93",
95         "sys_a0_94",            "sys_a0_95",    "AddCDROMDevice",       "AddMemCardDevide",
96         "DisableKernelIORedirection",           "EnableKernelIORedirection", "sys_a0_9a", "sys_a0_9b",
97         "SetConf",                      "GetConf",              "sys_a0_9e",            "SetMem",
98 // 0xa0
99         "_boot",                        "SystemError",  "EnqueueCdIntr",        "DequeueCdIntr",
100         "sys_a0_a4",            "ReadSector",   "get_cd_status",        "bufs_cb_0",
101         "bufs_cb_1",            "bufs_cb_2",    "bufs_cb_3",            "_card_info",
102         "_card_load",           "_card_auto",   "bufs_cd_4",            "sys_a0_af",
103 // 0xb0
104         "sys_a0_b0",            "sys_a0_b1",    "do_a_long_jmp",        "sys_a0_b3",
105         "?? sub_function",
106 };
107
108 char *biosB0n[256] = {
109 // 0x00
110         "SysMalloc",            "sys_b0_01",    "sys_b0_02",    "sys_b0_03",
111         "sys_b0_04",            "sys_b0_05",    "sys_b0_06",    "DeliverEvent",
112         "OpenEvent",            "CloseEvent",   "WaitEvent",    "TestEvent",
113         "EnableEvent",          "DisableEvent", "OpenTh",               "CloseTh",
114 // 0x10
115         "ChangeTh",                     "sys_b0_11",    "InitPAD",              "StartPAD",
116         "StopPAD",                      "PAD_init",             "PAD_dr",               "ReturnFromExecption",
117         "ResetEntryInt",        "HookEntryInt", "sys_b0_1a",    "sys_b0_1b",
118         "sys_b0_1c",            "sys_b0_1d",    "sys_b0_1e",    "sys_b0_1f",
119 // 0x20
120         "UnDeliverEvent",       "sys_b0_21",    "sys_b0_22",    "sys_b0_23",
121         "sys_b0_24",            "sys_b0_25",    "sys_b0_26",    "sys_b0_27",
122         "sys_b0_28",            "sys_b0_29",    "sys_b0_2a",    "sys_b0_2b",
123         "sys_b0_2c",            "sys_b0_2d",    "sys_b0_2e",    "sys_b0_2f",
124 // 0x30
125         "sys_b0_30",            "sys_b0_31",    "open",                 "lseek",
126         "read",                         "write",                "close",                "ioctl",
127         "exit",                         "sys_b0_39",    "getc",                 "putc",
128         "getchar",                      "putchar",              "gets",                 "puts",
129 // 0x40
130         "cd",                           "format",               "firstfile",    "nextfile",
131         "rename",                       "delete",               "undelete",             "AddDevice",
132         "RemoteDevice",         "PrintInstalledDevices", "InitCARD", "StartCARD",
133         "StopCARD",                     "sys_b0_4d",    "_card_write",  "_card_read",
134 // 0x50
135         "_new_card",            "Krom2RawAdd",  "sys_b0_52",    "sys_b0_53",
136         "_get_errno",           "_get_error",   "GetC0Table",   "GetB0Table",
137         "_card_chan",           "sys_b0_59",    "sys_b0_5a",    "ChangeClearPAD",
138         "_card_status",         "_card_wait",
139 };
140
141 char *biosC0n[256] = {
142 // 0x00
143         "InitRCnt",                       "InitException",              "SysEnqIntRP",          "SysDeqIntRP",
144         "get_free_EvCB_slot", "get_free_TCB_slot",      "ExceptionHandler",     "InstallExeptionHandler",
145         "SysInitMemory",          "SysInitKMem",                "ChangeClearRCnt",      "SystemError",
146         "InitDefInt",             "sys_c0_0d",                  "sys_c0_0e",            "sys_c0_0f",
147 // 0x10
148         "sys_c0_10",              "sys_c0_11",                  "InstallDevices",       "FlushStfInOutPut",
149         "sys_c0_14",              "_cdevinput",                 "_cdevscan",            "_circgetc",
150         "_circputc",              "ioabort",                    "sys_c0_1a",            "KernelRedirect",
151         "PatchAOTable",
152 };
153
154 //#define r0 (psxRegs.GPR.n.r0)
155 #define at (psxRegs.GPR.n.at)
156 #define v0 (psxRegs.GPR.n.v0)
157 #define v1 (psxRegs.GPR.n.v1)
158 #define a0 (psxRegs.GPR.n.a0)
159 #define a1 (psxRegs.GPR.n.a1)
160 #define a2 (psxRegs.GPR.n.a2)
161 #define a3 (psxRegs.GPR.n.a3)
162 #define t0 (psxRegs.GPR.n.t0)
163 #define t1 (psxRegs.GPR.n.t1)
164 #define t2 (psxRegs.GPR.n.t2)
165 #define t3 (psxRegs.GPR.n.t3)
166 #define t4 (psxRegs.GPR.n.t4)
167 #define t5 (psxRegs.GPR.n.t5)
168 #define t6 (psxRegs.GPR.n.t6)
169 #define t7 (psxRegs.GPR.n.t7)
170 #define t8 (psxRegs.GPR.n.t8)
171 #define t9 (psxRegs.GPR.n.t9)
172 #define s0 (psxRegs.GPR.n.s0)
173 #define s1 (psxRegs.GPR.n.s1)
174 #define s2 (psxRegs.GPR.n.s2)
175 #define s3 (psxRegs.GPR.n.s3)
176 #define s4 (psxRegs.GPR.n.s4)
177 #define s5 (psxRegs.GPR.n.s5)
178 #define s6 (psxRegs.GPR.n.s6)
179 #define s7 (psxRegs.GPR.n.s7)
180 #define k0 (psxRegs.GPR.n.k0)
181 #define k1 (psxRegs.GPR.n.k1)
182 #define gp (psxRegs.GPR.n.gp)
183 #define sp (psxRegs.GPR.n.sp)
184 #define fp (psxRegs.GPR.n.s8)
185 #define ra (psxRegs.GPR.n.ra)
186 #define pc0 (psxRegs.pc)
187
188 #define Ra0 ((char *)PSXM(a0))
189 #define Ra1 ((char *)PSXM(a1))
190 #define Ra2 ((char *)PSXM(a2))
191 #define Ra3 ((char *)PSXM(a3))
192 #define Rv0 ((char *)PSXM(v0))
193 #define Rsp ((char *)PSXM(sp))
194
195 typedef struct {
196         u32 desc;
197         s32 status;
198         s32 mode;
199         u32 fhandler;
200 } EvCB[32];
201
202 #define EvStUNUSED      0x0000
203 #define EvStWAIT        0x1000
204 #define EvStACTIVE      0x2000
205 #define EvStALREADY 0x4000
206
207 #define EvMdINTR        0x1000
208 #define EvMdNOINTR      0x2000
209
210 /*
211 typedef struct {
212         s32 next;
213         s32 func1;
214         s32 func2;
215         s32 pad;
216 } SysRPst;
217 */
218
219 typedef struct {
220         u32 status;
221         u32 mode;
222         u32 reg[32];
223         u32 epc;
224         u32 hi, lo;
225         u32 sr, cause;
226         u32 unused[9];
227 } TCB;
228
229 typedef struct {
230         u32 _pc0;
231         u32 gp0;
232         u32 t_addr;
233         u32 t_size;
234         u32 d_addr;
235         u32 d_size;
236         u32 b_addr;
237         u32 b_size;
238         u32 S_addr;
239         u32 s_size;
240         u32 _sp, _fp, _gp, ret, base;
241 } EXEC;
242
243 struct DIRENTRY {
244         char name[20];
245         s32 attr;
246         s32 size;
247         u32 next;
248         s32 head;
249         char system[4];
250 };
251
252 typedef struct {
253         char name[32];
254         u32  mode;
255         u32  offset;
256         u32  size;
257         u32  mcfile;
258 } FileDesc;
259
260 static int *pad_buf = NULL;
261 static char *pad_buf1 = NULL, *pad_buf2 = NULL;
262 static int pad_buf1len, pad_buf2len;
263 static int pad_stopped = 0;
264
265 static u32 regs[35];
266 static EvCB *EventCB;
267 static EvCB *HwEV; // 0xf0
268 static EvCB *EvEV; // 0xf1
269 static EvCB *RcEV; // 0xf2
270 static EvCB *UeEV; // 0xf3
271 static EvCB *SwEV; // 0xf4
272 static EvCB *ThEV; // 0xff
273 static u32 heap_size = 0;
274 static u32 *heap_addr = NULL;
275 static u32 *heap_end = NULL;
276 static int CardState = -1;
277 static int CurThread = 0;
278 static FileDesc FDesc[32];
279 static u32 card_active_chan = 0;
280
281 // fixed RAM offsets, SCPH1001 compatible
282 #define A_TT_ExCB       0x0100
283 #define A_TT_PCB        0x0108
284 #define A_TT_TCB        0x0110
285 #define A_A0_TABLE      0x0200
286 #define A_B0_TABLE      0x0874
287 #define A_C0_TABLE      0x0674
288 #define A_SYSCALL       0x0650
289 #define A_EXCEPTION     0x0c80
290 #define A_EXC_SP        0x6cf0
291 #define A_EEXIT_DEF     0x6cf4
292 #define A_KMALLOC_PTR   0x7460
293 #define A_KMALLOC_SIZE  0x7464
294 #define A_KMALLOC_END   0x7468
295 #define A_EEXIT_PTR     0x75d0
296 #define A_EXC_STACK     0x85d8  // exception stack top
297 #define A_RCNT_VBL_ACK  0x8600
298 #define A_EXC_GP        0xf450
299
300 #define HLEOP(n) SWAPu32((0x3b << 26) | (n));
301
302 static u32 loadRam32(u32 addr)
303 {
304         assert(!(addr & 0x5f800000));
305         return SWAP32(*((u32 *)psxM + ((addr & 0x1fffff) >> 2)));
306 }
307
308 static void *castRam32ptr(u32 addr)
309 {
310         assert(!(addr & 0x5f800003));
311         return psxM + (addr & 0x1ffffc);
312 }
313
314 static void *loadRam32ptr(u32 addr)
315 {
316         return castRam32ptr(loadRam32(addr));
317 }
318
319 static void storeRam32(u32 addr, u32 d)
320 {
321         assert(!(addr & 0x5f800000));
322         *((u32 *)psxM + ((addr & 0x1fffff) >> 2)) = SWAP32(d);
323 }
324
325 static void mips_return(u32 val)
326 {
327         v0 = val;
328         pc0 = ra;
329 }
330
331 static void use_cycles(u32 cycle)
332 {
333         psxRegs.cycle += cycle * 2;
334 }
335
336 static void mips_return_c(u32 val, u32 cycle)
337 {
338         use_cycles(cycle);
339         mips_return(val);
340 }
341
342 static void mips_return_void_c(u32 cycle)
343 {
344         use_cycles(cycle);
345         pc0 = ra;
346 }
347
348 static int returned_from_exception(void)
349 {
350         // 0x80000080 means it took another exception just after return
351         return pc0 == k0 || pc0 == 0x80000080;
352 }
353
354 static inline void softCall(u32 pc) {
355         u32 sra = ra;
356         u32 ssr = psxRegs.CP0.n.SR;
357         pc0 = pc;
358         ra = 0x80001000;
359         psxRegs.CP0.n.SR &= ~0x404; // disable interrupts
360
361         while (pc0 != 0x80001000)
362                 psxCpu->ExecuteBlock(EXEC_CALLER_HLE);
363
364         ra = sra;
365         psxRegs.CP0.n.SR = ssr;
366 }
367
368 static inline void softCallInException(u32 pc) {
369         u32 sra = ra;
370         pc0 = pc;
371         ra = 0x80001000;
372
373         while (!returned_from_exception() && pc0 != 0x80001000)
374                 psxCpu->ExecuteBlock(EXEC_CALLER_HLE);
375
376         if (pc0 == 0x80001000)
377                 ra = sra;
378 }
379
380 static inline void DeliverEvent(u32 ev, u32 spec) {
381         if (EventCB[ev][spec].status != EvStACTIVE) return;
382
383 //      EventCB[ev][spec].status = EvStALREADY;
384         if (EventCB[ev][spec].mode == EvMdINTR) {
385                 softCall(EventCB[ev][spec].fhandler);
386         } else EventCB[ev][spec].status = EvStALREADY;
387 }
388
389 /*                                           *
390 //                                           *
391 //                                           *
392 //               System calls A0             */
393
394
395 #define buread(Ra1, mcd, length) { \
396         SysPrintf("read %d: %x,%x (%s)\n", FDesc[1 + mcd].mcfile, FDesc[1 + mcd].offset, a2, Mcd##mcd##Data + 128 * FDesc[1 + mcd].mcfile + 0xa); \
397         ptr = Mcd##mcd##Data + 8192 * FDesc[1 + mcd].mcfile + FDesc[1 + mcd].offset; \
398         memcpy(Ra1, ptr, length); \
399         if (FDesc[1 + mcd].mode & 0x8000) { \
400         DeliverEvent(0x11, 0x2); /* 0xf0000011, 0x0004 */ \
401         DeliverEvent(0x81, 0x2); /* 0xf4000001, 0x0004 */ \
402         v0 = 0; } \
403         else v0 = length; \
404         FDesc[1 + mcd].offset += v0; \
405 }
406
407 #define buwrite(Ra1, mcd, length) { \
408         u32 offset =  + 8192 * FDesc[1 + mcd].mcfile + FDesc[1 + mcd].offset; \
409         SysPrintf("write %d: %x,%x\n", FDesc[1 + mcd].mcfile, FDesc[1 + mcd].offset, a2); \
410         ptr = Mcd##mcd##Data + offset; \
411         memcpy(ptr, Ra1, length); \
412         FDesc[1 + mcd].offset += length; \
413         SaveMcd(Config.Mcd##mcd, Mcd##mcd##Data, offset, length); \
414         if (FDesc[1 + mcd].mode & 0x8000) { \
415         DeliverEvent(0x11, 0x2); /* 0xf0000011, 0x0004 */ \
416         DeliverEvent(0x81, 0x2); /* 0xf4000001, 0x0004 */ \
417         v0 = 0; } \
418         else v0 = length; \
419 }
420
421 #ifndef PSXBIOS_LOG
422 //#define PSXBIOS_LOG printf
423 #define PSXBIOS_LOG(...)
424 #endif
425
426 /* Internally redirects to "FileRead(fd,tempbuf,1)".*/
427 /* For some strange reason, the returned character is sign-expanded; */
428 /* So if a return value of FFFFFFFFh could mean either character FFh, or error. */
429 /* TODO FIX ME : Properly implement this behaviour */
430 void psxBios_getc(void) // 0x03, 0x35
431 {
432         char *ptr;
433         void *pa1 = Ra1;
434 #ifdef PSXBIOS_LOG
435         PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x03]);
436 #endif
437         v0 = -1;
438
439         if (pa1 != INVALID_PTR) {
440                 switch (a0) {
441                         case 2: buread(pa1, 1, 1); break;
442                         case 3: buread(pa1, 2, 1); break;
443                 }
444         }
445
446         pc0 = ra;
447 }
448
449 /* Copy of psxBios_write, except size is 1. */
450 void psxBios_putc(void) // 0x09, 0x3B
451 {
452         char *ptr;
453         void *pa1 = Ra1;
454 #ifdef PSXBIOS_LOG
455         PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x09]);
456 #endif
457         v0 = -1;
458         if (pa1 == INVALID_PTR) {
459                 pc0 = ra;
460                 return;
461         }
462
463         if (a0 == 1) { // stdout
464                 char *ptr = (char *)pa1;
465
466                 v0 = a2;
467                 while (a2 > 0) {
468                         printf("%c", *ptr++); a2--;
469                 }
470                 pc0 = ra; return;
471         }
472
473         switch (a0) {
474                 case 2: buwrite(pa1, 1, 1); break;
475                 case 3: buwrite(pa1, 2, 1); break;
476         }
477
478         pc0 = ra;
479 }
480
481 void psxBios_todigit(void) // 0x0a
482 {
483         int c = a0;
484 #ifdef PSXBIOS_LOG
485         PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x0a]);
486 #endif
487         c &= 0xFF;
488         if (c >= 0x30 && c < 0x3A) {
489                 c -= 0x30;
490         }
491         else if (c > 0x60 && c < 0x7B) {
492                 c -= 0x20;
493         }
494         else if (c > 0x40 && c < 0x5B) {
495                 c = c - 0x41 + 10;
496         }
497         else if (c >= 0x80) {
498                 c = -1;
499         }
500         else
501         {
502                 c = 0x0098967F;
503         }
504         v0 = c;
505         pc0 = ra;
506 }
507
508 void psxBios_abs() { // 0x0e
509         if ((s32)a0 < 0) v0 = -(s32)a0;
510         else v0 = a0;
511         pc0 = ra;
512 }
513
514 void psxBios_labs() { // 0x0f
515         psxBios_abs();
516 }
517
518 void psxBios_atoi() { // 0x10
519         s32 n = 0, f = 0;
520         char *p = (char *)Ra0;
521
522         for (;;p++) {
523                 switch (*p) {
524                         case ' ': case '\t': continue;
525                         case '-': f++;
526                         case '+': p++;
527                 }
528                 break;
529         }
530
531         while (*p >= '0' && *p <= '9') {
532                 n = n * 10 + *p++ - '0';
533         }
534
535         v0 = (f ? -n : n);
536         pc0 = ra;
537 }
538
539 void psxBios_atol() { // 0x11
540         psxBios_atoi();
541 }
542
543 struct jmp_buf_ {
544         u32 ra_, sp_, fp_;
545         u32 s[8];
546         u32 gp_;
547 };
548
549 static void psxBios_setjmp() { // 0x13
550         struct jmp_buf_ *jmp_buf = castRam32ptr(a0);
551         int i;
552
553         PSXBIOS_LOG("psxBios_%s %x\n", biosA0n[0x13], a0);
554
555         jmp_buf->ra_ = SWAP32(ra);
556         jmp_buf->sp_ = SWAP32(sp);
557         jmp_buf->fp_ = SWAP32(fp);
558         for (i = 0; i < 8; i++) // s0-s7
559                 jmp_buf->s[i] = SWAP32(psxRegs.GPR.r[16 + i]);
560         jmp_buf->gp_ = SWAP32(gp);
561
562         mips_return_c(0, 15);
563 }
564
565 static void longjmp_load(const struct jmp_buf_ *jmp_buf)
566 {
567         int i;
568
569         ra = SWAP32(jmp_buf->ra_);
570         sp = SWAP32(jmp_buf->sp_);
571         fp = SWAP32(jmp_buf->fp_);
572         for (i = 0; i < 8; i++) // s0-s7
573                 psxRegs.GPR.r[16 + i] = SWAP32(jmp_buf->s[i]);
574         gp = SWAP32(jmp_buf->gp_);;
575 }
576
577 void psxBios_longjmp() { // 0x14
578         struct jmp_buf_ *jmp_buf = castRam32ptr(a0);
579
580         PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x14]);
581         longjmp_load(jmp_buf);
582         mips_return_c(a1, 15);
583 }
584
585 void psxBios_strcat() { // 0x15
586         char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
587
588 #ifdef PSXBIOS_LOG
589         PSXBIOS_LOG("psxBios_%s: %s, %s\n", biosA0n[0x15], Ra0, Ra1);
590 #endif
591         if (a0 == 0 || a1 == 0)
592         {
593                 v0 = 0;
594                 pc0 = ra;
595                 return;
596         }
597         while (*p1++);
598         --p1;
599         while ((*p1++ = *p2++) != '\0');
600
601         v0 = a0; pc0 = ra;
602 }
603
604 void psxBios_strncat() { // 0x16
605         char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
606         s32 n = a2;
607
608 #ifdef PSXBIOS_LOG
609         PSXBIOS_LOG("psxBios_%s: %s (%x), %s (%x), %d\n", biosA0n[0x16], Ra0, a0, Ra1, a1, a2);
610 #endif
611         if (a0 == 0 || a1 == 0)
612         {
613                 v0 = 0;
614                 pc0 = ra;
615                 return;
616         }
617         while (*p1++);
618         --p1;
619         while ((*p1++ = *p2++) != '\0') {
620                 if (--n < 0) {
621                         *--p1 = '\0';
622                         break;
623                 }
624         }
625
626         v0 = a0; pc0 = ra;
627 }
628
629 void psxBios_strcmp() { // 0x17
630         char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
631         s32 n=0;
632         if (a0 == 0 && a1 == 0)
633         {
634                 v0 = 0;
635                 pc0 = ra;
636                 return;
637         }
638         else if (a0 == 0 && a1 != 0)
639         {
640                 v0 = -1;
641                 pc0 = ra;
642                 return;
643         }
644         else if (a0 != 0 && a1 == 0)
645         {
646                 v0 = 1;
647                 pc0 = ra;
648                 return;
649         }
650 #ifdef PSXBIOS_LOG
651         PSXBIOS_LOG("psxBios_%s: %s (%x), %s (%x)\n", biosA0n[0x17], Ra0, a0, Ra1, a1);
652 #endif
653
654         while (*p1 == *p2++) {
655                 n++;
656                 if (*p1++ == '\0') {
657                         v1=n-1;
658                         a0+=n;
659                         a1+=n;
660                         v0 = 0;
661                         pc0 = ra;
662                         return;
663                 }
664         }
665
666         v0 = (*p1 - *--p2);
667         v1 = n;
668         a0+=n;
669         a1+=n;
670         pc0 = ra;
671 }
672
673 void psxBios_strncmp() { // 0x18
674         char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
675         s32 n = a2;
676         if (a0 == 0 && a1 == 0)
677         {
678                 v0 = 0;
679                 pc0 = ra;
680                 return;
681         }
682         else if (a0 == 0 && a1 != 0)
683         {
684                 v0 = -1;
685                 pc0 = ra;
686                 return;
687         }
688         else if (a0 != 0 && a1 == 0)
689         {
690                 v0 = 1;
691                 pc0 = ra;
692                 return;
693         }
694 #ifdef PSXBIOS_LOG
695         PSXBIOS_LOG("psxBios_%s: %s (%x), %s (%x), %d\n", biosA0n[0x18], Ra0, a0, Ra1, a1, a2);
696 #endif
697
698         while (--n >= 0 && *p1 == *p2++) {
699                 if (*p1++ == '\0') {
700                         v0 = 0;
701                         pc0 = ra;
702                         v1 = a2 - ((a2-n) - 1);
703                         a0 += (a2-n) - 1;
704                         a1 += (a2-n) - 1;
705                         a2 = n;
706                         return;
707                 }
708         }
709
710         v0 = (n < 0 ? 0 : *p1 - *--p2);
711         pc0 = ra;
712         v1 = a2 - ((a2-n) - 1);
713         a0 += (a2-n) - 1;
714         a1 += (a2-n) - 1;
715         a2 = n;
716 }
717
718 void psxBios_strcpy() { // 0x19
719         char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
720         if (a0 == 0 || a1 == 0)
721         {
722                 v0 = 0;
723                 pc0 = ra;
724                 return;
725         }
726         while ((*p1++ = *p2++) != '\0');
727
728         v0 = a0; pc0 = ra;
729 }
730
731 void psxBios_strncpy() { // 0x1a
732         char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
733         s32 n = a2, i;
734         if (a0 == 0 || a1 == 0)
735         {
736                 v0 = 0;
737                 pc0 = ra;
738                 return;
739         }
740         for (i = 0; i < n; i++) {
741                 if ((*p1++ = *p2++) == '\0') {
742                         while (++i < n) {
743                                 *p1++ = '\0';
744                         }
745                         v0 = a0; pc0 = ra;
746                         return;
747                 }
748         }
749
750         v0 = a0; pc0 = ra;
751 }
752
753 void psxBios_strlen() { // 0x1b
754         char *p = (char *)Ra0;
755         v0 = 0;
756         if (a0 == 0)
757         {
758                 pc0 = ra;
759                 return;
760         }
761         while (*p++) v0++;
762         pc0 = ra;
763 }
764
765 void psxBios_index() { // 0x1c
766         char *p = (char *)Ra0;
767         if (a0 == 0)
768         {
769                 v0 = 0;
770                 pc0 = ra;
771                 return;
772         }
773
774         do {
775                 if (*p == a1) {
776                         v0 = a0 + (p - (char *)Ra0);
777                         pc0 = ra;
778                         return;
779                 }
780         } while (*p++ != '\0');
781
782         v0 = 0; pc0 = ra;
783 }
784
785 void psxBios_rindex() { // 0x1d
786         char *p = (char *)Ra0;
787
788         v0 = 0;
789         if (a0 == 0)
790         {
791                 pc0 = ra;
792                 return;
793         }
794         do {
795                 if (*p == a1)
796                         v0 = a0 + (p - (char *)Ra0);
797         } while (*p++ != '\0');
798
799         pc0 = ra;
800 }
801
802 void psxBios_strchr() { // 0x1e
803         psxBios_index();
804 }
805
806 void psxBios_strrchr() { // 0x1f
807         psxBios_rindex();
808 }
809
810 void psxBios_strpbrk() { // 0x20
811         char *p1 = (char *)Ra0, *p2 = (char *)Ra1, *scanp, c, sc;
812
813         while ((c = *p1++) != '\0') {
814                 for (scanp = p2; (sc = *scanp++) != '\0';) {
815                         if (sc == c) {
816                                 v0 = a0 + (p1 - 1 - (char *)Ra0);
817                                 pc0 = ra;
818                                 return;
819                         }
820                 }
821         }
822
823         // BUG: return a0 instead of NULL if not found
824         v0 = a0; pc0 = ra;
825 }
826
827 void psxBios_strspn() { // 0x21
828         char *p1, *p2;
829
830         for (p1 = (char *)Ra0; *p1 != '\0'; p1++) {
831                 for (p2 = (char *)Ra1; *p2 != '\0' && *p2 != *p1; p2++);
832                 if (*p2 == '\0') break;
833         }
834
835         v0 = p1 - (char *)Ra0; pc0 = ra;
836 }
837
838 void psxBios_strcspn() { // 0x22
839         char *p1, *p2;
840
841         for (p1 = (char *)Ra0; *p1 != '\0'; p1++) {
842                 for (p2 = (char *)Ra1; *p2 != '\0' && *p2 != *p1; p2++);
843                 if (*p2 != '\0') break;
844         }
845
846         v0 = p1 - (char *)Ra0; pc0 = ra;
847 }
848
849 void psxBios_strtok() { // 0x23
850         char *pcA0 = (char *)Ra0;
851         char *pcRet = strtok(pcA0, (char *)Ra1);
852         if (pcRet)
853                 v0 = a0 + pcRet - pcA0;
854         else
855                 v0 = 0;
856         pc0 = ra;
857 }
858
859 void psxBios_strstr() { // 0x24
860         char *p = (char *)Ra0, *p1, *p2;
861
862         while (*p != '\0') {
863                 p1 = p;
864                 p2 = (char *)Ra1;
865
866                 while (*p1 != '\0' && *p2 != '\0' && *p1 == *p2) {
867                         p1++; p2++;
868                 }
869
870                 if (*p2 == '\0') {
871                         v0 = a0 + (p - (char *)Ra0);
872                         pc0 = ra;
873                         return;
874                 }
875
876                 p++;
877         }
878
879         v0 = 0; pc0 = ra;
880 }
881
882 void psxBios_toupper() { // 0x25
883         v0 = (s8)(a0 & 0xff);
884         if (v0 >= 'a' && v0 <= 'z') v0 -= 'a' - 'A';
885         pc0 = ra;
886 }
887
888 void psxBios_tolower() { // 0x26
889         v0 = (s8)(a0 & 0xff);
890         if (v0 >= 'A' && v0 <= 'Z') v0 += 'a' - 'A';
891         pc0 = ra;
892 }
893
894 void psxBios_bcopy() { // 0x27
895         char *p1 = (char *)Ra1, *p2 = (char *)Ra0;
896         v0 = a0;
897         if (a0 == 0 || a2 > 0x7FFFFFFF)
898         {
899                 pc0 = ra;
900                 return;
901         }
902         while ((s32)a2-- > 0) *p1++ = *p2++;
903         a2 = 0;
904         pc0 = ra;
905 }
906
907 void psxBios_bzero() { // 0x28
908         char *p = (char *)Ra0;
909         v0 = a0;
910         /* Same as memset here (See memset below) */
911         if (a1 > 0x7FFFFFFF || a1 == 0)
912         {
913                 v0 = 0;
914                 pc0 = ra;
915                 return;
916         }
917         else if (a0 == 0)
918         {
919                 pc0 = ra;
920                 return;
921         }
922         while ((s32)a1-- > 0) *p++ = '\0';
923         a1 = 0;
924         pc0 = ra;
925 }
926
927 void psxBios_bcmp() { // 0x29
928         char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
929
930         if (a0 == 0 || a1 == 0) { v0 = 0; pc0 = ra; return; }
931
932         while ((s32)a2-- > 0) {
933                 if (*p1++ != *p2++) {
934                         v0 = *p1 - *p2; // BUG: compare the NEXT byte
935                         pc0 = ra;
936                         return;
937                 }
938         }
939
940         v0 = 0; pc0 = ra;
941 }
942
943 void psxBios_memcpy() { // 0x2a
944         char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
945         v0 = a0;
946         if (a0 == 0 || a2 > 0x7FFFFFFF)
947         {
948                 pc0 = ra;
949                 return;
950         }
951         while ((s32)a2-- > 0) {
952                 *p1++ = *p2++;
953         }
954         a2 = 0;
955         pc0 = ra;
956 }
957
958 void psxBios_memset() { // 0x2b
959         char *p = (char *)Ra0;
960         v0 = a0;
961         if (a2 > 0x7FFFFFFF || a2 == 0)
962         {
963                 v0 = 0;
964                 pc0 = ra;
965                 return;
966         }
967         if (a0 == 0)
968         {
969                 pc0 = ra;
970                 return;
971         }
972         while ((s32)a2-- > 0) *p++ = (char)a1;
973         a2 = 0;
974         v0 = a0; pc0 = ra;
975 }
976
977 void psxBios_memmove() { // 0x2c
978         char *p1 = (char *)Ra0, *p2 = (char *)Ra1;
979         v0 = a0;
980         if (a0 == 0 || a2 > 0x7FFFFFFF)
981         {
982                 pc0 = ra;
983                 return;
984         }
985         if (p2 <= p1 && p2 + a2 > p1) {
986                 a2++; // BUG: copy one more byte here
987                 p1 += a2;
988                 p2 += a2;
989                 while ((s32)a2-- > 0) *--p1 = *--p2;
990         } else {
991                 while ((s32)a2-- > 0) *p1++ = *p2++;
992         }
993         pc0 = ra;
994 }
995
996 void psxBios_memcmp() { // 0x2d
997         psxBios_bcmp();
998 }
999
1000 void psxBios_memchr() { // 0x2e
1001         char *p = (char *)Ra0;
1002
1003         if (a0 == 0 || a2 > 0x7FFFFFFF)
1004         {
1005                 pc0 = ra;
1006                 return;
1007         }
1008
1009         while ((s32)a2-- > 0) {
1010                 if (*p++ != (s8)a1) continue;
1011                 v0 = a0 + (p - (char *)Ra0 - 1);
1012                 pc0 = ra;
1013                 return;
1014         }
1015
1016         v0 = 0; pc0 = ra;
1017 }
1018
1019 void psxBios_rand() { // 0x2f
1020         u32 s = psxMu32(0x9010) * 1103515245 + 12345;
1021         v0 = (s >> 16) & 0x7fff;
1022         psxMu32ref(0x9010) = SWAPu32(s);
1023         pc0 = ra;
1024 }
1025
1026 void psxBios_srand() { // 0x30
1027         psxMu32ref(0x9010) = SWAPu32(a0);
1028         pc0 = ra;
1029 }
1030
1031 static u32 qscmpfunc, qswidth;
1032
1033 static inline int qscmp(char *a, char *b) {
1034         u32 sa0 = a0;
1035
1036         a0 = sa0 + (a - (char *)PSXM(sa0));
1037         a1 = sa0 + (b - (char *)PSXM(sa0));
1038
1039         softCall(qscmpfunc);
1040
1041         a0 = sa0;
1042         return (s32)v0;
1043 }
1044
1045 static inline void qexchange(char *i, char *j) {
1046         char t;
1047         int n = qswidth;
1048
1049         do {
1050                 t = *i;
1051                 *i++ = *j;
1052                 *j++ = t;
1053         } while (--n);
1054 }
1055
1056 static inline void q3exchange(char *i, char *j, char *k) {
1057         char t;
1058         int n = qswidth;
1059
1060         do {
1061                 t = *i;
1062                 *i++ = *k;
1063                 *k++ = *j;
1064                 *j++ = t;
1065         } while (--n);
1066 }
1067
1068 static void qsort_main(char *a, char *l) {
1069         char *i, *j, *lp, *hp;
1070         int c;
1071         unsigned int n;
1072
1073 start:
1074         if ((n = l - a) <= qswidth)
1075                 return;
1076         n = qswidth * (n / (2 * qswidth));
1077         hp = lp = a + n;
1078         i = a;
1079         j = l - qswidth;
1080         while (TRUE) {
1081                 if (i < lp) {
1082                         if ((c = qscmp(i, lp)) == 0) {
1083                                 qexchange(i, lp -= qswidth);
1084                                 continue;
1085                         }
1086                         if (c < 0) {
1087                                 i += qswidth;
1088                                 continue;
1089                         }
1090                 }
1091
1092 loop:
1093                 if (j > hp) {
1094                         if ((c = qscmp(hp, j)) == 0) {
1095                                 qexchange(hp += qswidth, j);
1096                                 goto loop;
1097                         }
1098                         if (c > 0) {
1099                                 if (i == lp) {
1100                                         q3exchange(i, hp += qswidth, j);
1101                                         i = lp += qswidth;
1102                                         goto loop;
1103                                 }
1104                                 qexchange(i, j);
1105                                 j -= qswidth;
1106                                 i += qswidth;
1107                                 continue;
1108                         }
1109                         j -= qswidth;
1110                         goto loop;
1111                 }
1112
1113                 if (i == lp) {
1114                         if (lp - a >= l - hp) {
1115                                 qsort_main(hp + qswidth, l);
1116                                 l = lp;
1117                         } else {
1118                                 qsort_main(a, lp);
1119                                 a = hp + qswidth;
1120                         }
1121                         goto start;
1122                 }
1123
1124                 q3exchange(j, lp -= qswidth, i);
1125                 j = hp -= qswidth;
1126         }
1127 }
1128
1129 void psxBios_qsort() { // 0x31
1130         qswidth = a2;
1131         qscmpfunc = a3;
1132         qsort_main((char *)Ra0, (char *)Ra0 + a1 * a2);
1133
1134         pc0 = ra;
1135 }
1136
1137 void psxBios_malloc() { // 0x33
1138         u32 *chunk, *newchunk = NULL;
1139         unsigned int dsize = 0, csize, cstat;
1140         int colflag;
1141 #ifdef PSXBIOS_LOG
1142         PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x33]);
1143 #endif
1144         if (!a0 || (!heap_size || !heap_addr)) {
1145                 v0 = 0;
1146                 pc0 = ra;
1147                 return;
1148         }
1149
1150         // scan through heap and combine free chunks of space
1151         chunk = heap_addr;
1152         colflag = 0;
1153         while(chunk < heap_end) {
1154                 // get size and status of actual chunk
1155                 csize = ((u32)*chunk) & 0xfffffffc;
1156                 cstat = ((u32)*chunk) & 1;
1157
1158                 // most probably broken heap descriptor
1159                 // this fixes Burning Road
1160                 if (*chunk == 0) {
1161                         newchunk = chunk;
1162                         dsize = ((uptr)heap_end - (uptr)chunk) - 4;
1163                         colflag = 1;
1164                         break;
1165                 }
1166
1167                 // it's a free chunk
1168                 if(cstat == 1) {
1169                         if(colflag == 0) {
1170                                 newchunk = chunk;
1171                                 dsize = csize;
1172                                 colflag = 1;                    // let's begin a new collection of free memory
1173                         }
1174                         else dsize += (csize+4);        // add the new size including header
1175                 }
1176                 // not a free chunk: did we start a collection ?
1177                 else {
1178                         if(colflag == 1) {                      // collection is over
1179                                 colflag = 0;
1180                                 *newchunk = SWAP32(dsize | 1);
1181                         }
1182                 }
1183
1184                 // next chunk
1185                 chunk = (u32*)((uptr)chunk + csize + 4);
1186         }
1187         // if neccessary free memory on end of heap
1188         if (colflag == 1)
1189                 *newchunk = SWAP32(dsize | 1);
1190
1191         chunk = heap_addr;
1192         csize = ((u32)*chunk) & 0xfffffffc;
1193         cstat = ((u32)*chunk) & 1;
1194         dsize = (a0 + 3) & 0xfffffffc;
1195
1196         // exit on uninitialized heap
1197         if (chunk == NULL) {
1198                 printf("malloc %x,%x: Uninitialized Heap!\n", v0, a0);
1199                 v0 = 0;
1200                 pc0 = ra;
1201                 return;
1202         }
1203
1204         // search an unused chunk that is big enough until the end of the heap
1205         while ((dsize > csize || cstat==0) && chunk < heap_end ) {
1206                 chunk = (u32*)((uptr)chunk + csize + 4);
1207
1208                         // catch out of memory
1209                         if(chunk >= heap_end) {
1210                                 printf("malloc %x,%x: Out of memory error!\n",
1211                                         v0, a0);
1212                                 v0 = 0; pc0 = ra;
1213                                 return;
1214                         }
1215
1216                 csize = ((u32)*chunk) & 0xfffffffc;
1217                 cstat = ((u32)*chunk) & 1;
1218         }
1219
1220         // allocate memory
1221         if(dsize == csize) {
1222                 // chunk has same size
1223                 *chunk &= 0xfffffffc;
1224         } else if (dsize > csize) {
1225                 v0 = 0; pc0 = ra;
1226                 return;
1227         } else {
1228                 // split free chunk
1229                 *chunk = SWAP32(dsize);
1230                 newchunk = (u32*)((uptr)chunk + dsize + 4);
1231                 *newchunk = SWAP32(((csize - dsize - 4) & 0xfffffffc) | 1);
1232         }
1233
1234         // return pointer to allocated memory
1235         v0 = ((uptr)chunk - (uptr)psxM) + 4;
1236         v0|= 0x80000000;
1237         //printf ("malloc %x,%x\n", v0, a0);
1238         pc0 = ra;
1239 }
1240
1241 void psxBios_free() { // 0x34
1242
1243 #ifdef PSXBIOS_LOG
1244         PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x34]);
1245 #endif
1246
1247         SysPrintf("free %x: %x bytes\n", a0, *(u32*)(Ra0-4));
1248
1249         if (a0)
1250                 *(u32*)(Ra0-4) |= 1;    // set chunk to free
1251         pc0 = ra;
1252 }
1253
1254 void psxBios_calloc() { // 0x37
1255         void *pv0;
1256 #ifdef PSXBIOS_LOG
1257         PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x37]);
1258 #endif
1259
1260         a0 = a0 * a1;
1261         psxBios_malloc();
1262         pv0 = Rv0;
1263         if (pv0)
1264                 memset(pv0, 0, a0);
1265 }
1266
1267 void psxBios_realloc() { // 0x38
1268         u32 block = a0;
1269         u32 size = a1;
1270 #ifdef PSXBIOS_LOG
1271         PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x38]);
1272 #endif
1273
1274         a0 = block;
1275         /* If "old_buf" is zero, executes malloc(new_size), and returns r2=new_buf (or 0=failed). */
1276         if (block == 0)
1277         {
1278                 psxBios_malloc();
1279         }
1280         /* Else, if "new_size" is zero, executes free(old_buf), and returns r2=garbage. */
1281         else if (size == 0)
1282         {
1283                 psxBios_free();
1284         }
1285         /* Else, executes malloc(new_size), bcopy(old_buf,new_buf,new_size), and free(old_buf), and returns r2=new_buf (or 0=failed). */
1286         /* Note that it is not quite implemented this way here. */
1287         else
1288         {
1289                 psxBios_free();
1290                 a0 = size;
1291                 psxBios_malloc();
1292         }
1293 }
1294
1295
1296 /* InitHeap(void *block , int n) */
1297 void psxBios_InitHeap() { // 0x39
1298         unsigned int size;
1299
1300 #ifdef PSXBIOS_LOG
1301         PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x39]);
1302 #endif
1303
1304         if (((a0 & 0x1fffff) + a1)>= 0x200000) size = 0x1ffffc - (a0 & 0x1fffff);
1305         else size = a1;
1306
1307         size &= 0xfffffffc;
1308
1309         heap_addr = (u32 *)Ra0;
1310         heap_size = size;
1311         heap_end = (u32 *)((u8 *)heap_addr + heap_size);
1312         /* HACKFIX: Commenting out this line fixes GTA2 crash */
1313         //*heap_addr = SWAP32(size | 1);
1314
1315         SysPrintf("InitHeap %x,%x : %x %x\n",a0,a1, (int)((uptr)heap_addr-(uptr)psxM), size);
1316
1317         pc0 = ra;
1318 }
1319
1320 void psxBios_getchar() { //0x3b
1321         v0 = getchar(); pc0 = ra;
1322 }
1323
1324 static void psxBios_printf_psxout() { // 0x3f
1325         char tmp[1024];
1326         char tmp2[1024];
1327         u32 save[4];
1328         char *ptmp = tmp;
1329         int n=1, i=0, j;
1330         void *psp;
1331
1332         psp = PSXM(sp);
1333         if (psp != INVALID_PTR) {
1334                 memcpy(save, psp, 4 * 4);
1335                 psxMu32ref(sp) = SWAP32((u32)a0);
1336                 psxMu32ref(sp + 4) = SWAP32((u32)a1);
1337                 psxMu32ref(sp + 8) = SWAP32((u32)a2);
1338                 psxMu32ref(sp + 12) = SWAP32((u32)a3);
1339         }
1340
1341         while (Ra0[i]) {
1342                 switch (Ra0[i]) {
1343                         case '%':
1344                                 j = 0;
1345                                 tmp2[j++] = '%';
1346 _start:
1347                                 switch (Ra0[++i]) {
1348                                         case '.':
1349                                         case 'l':
1350                                                 tmp2[j++] = Ra0[i]; goto _start;
1351                                         default:
1352                                                 if (Ra0[i] >= '0' && Ra0[i] <= '9') {
1353                                                         tmp2[j++] = Ra0[i];
1354                                                         goto _start;
1355                                                 }
1356                                                 break;
1357                                 }
1358                                 tmp2[j++] = Ra0[i];
1359                                 tmp2[j] = 0;
1360
1361                                 switch (Ra0[i]) {
1362                                         case 'f': case 'F':
1363                                                 ptmp += sprintf(ptmp, tmp2, (float)psxMu32(sp + n * 4)); n++; break;
1364                                         case 'a': case 'A':
1365                                         case 'e': case 'E':
1366                                         case 'g': case 'G':
1367                                                 ptmp += sprintf(ptmp, tmp2, (double)psxMu32(sp + n * 4)); n++; break;
1368                                         case 'p':
1369                                         case 'i': case 'u':
1370                                         case 'd': case 'D':
1371                                         case 'o': case 'O':
1372                                         case 'x': case 'X':
1373                                                 ptmp += sprintf(ptmp, tmp2, (unsigned int)psxMu32(sp + n * 4)); n++; break;
1374                                         case 'c':
1375                                                 ptmp += sprintf(ptmp, tmp2, (unsigned char)psxMu32(sp + n * 4)); n++; break;
1376                                         case 's':
1377                                                 ptmp += sprintf(ptmp, tmp2, (char*)PSXM(psxMu32(sp + n * 4))); n++; break;
1378                                         case '%':
1379                                                 *ptmp++ = Ra0[i]; break;
1380                                 }
1381                                 i++;
1382                                 break;
1383                         default:
1384                                 *ptmp++ = Ra0[i++];
1385                 }
1386         }
1387         *ptmp = 0;
1388
1389         if (psp != INVALID_PTR)
1390                 memcpy(psp, save, 4 * 4);
1391
1392         SysPrintf("%s", tmp);
1393 }
1394
1395 void psxBios_printf() { // 0x3f
1396         psxBios_printf_psxout();
1397         pc0 = ra;
1398 }
1399
1400 void psxBios_format() { // 0x41
1401         if (strcmp(Ra0, "bu00:") == 0 && Config.Mcd1[0] != '\0')
1402         {
1403                 CreateMcd(Config.Mcd1);
1404                 LoadMcd(1, Config.Mcd1);
1405                 v0 = 1;
1406         }
1407         else if (strcmp(Ra0, "bu10:") == 0 && Config.Mcd2[0] != '\0')
1408         {
1409                 CreateMcd(Config.Mcd2);
1410                 LoadMcd(2, Config.Mcd2);
1411                 v0 = 1;
1412         }
1413         else
1414         {
1415                 v0 = 0;
1416         }
1417         pc0 = ra;
1418 }
1419
1420 static void psxBios_SystemErrorUnresolvedException() {
1421         if (loadRam32(0xfffc) != 0x12345678) { // prevent log flood
1422                 SysPrintf("psxBios_%s\n", biosA0n[0x40]);
1423                 storeRam32(0xfffc, 0x12345678);
1424         }
1425         mips_return_void_c(1000);
1426 }
1427
1428 /*
1429  *      long Load(char *name, struct EXEC *header);
1430  */
1431
1432 void psxBios_Load() { // 0x42
1433         EXE_HEADER eheader;
1434         void *pa1;
1435
1436         pa1 = Ra1;
1437         if (pa1 && LoadCdromFile(Ra0, &eheader) == 0) {
1438                 memcpy(pa1, ((char*)&eheader)+16, sizeof(EXEC));
1439                 v0 = 1;
1440         } else v0 = 0;
1441         PSXBIOS_LOG("psxBios_%s: %s, %d -> %d\n", biosA0n[0x42], Ra0, a1, v0);
1442
1443         pc0 = ra;
1444 }
1445
1446 /*
1447  *      int Exec(struct EXEC *header , int argc , char **argv);
1448  */
1449
1450 void psxBios_Exec() { // 43
1451         EXEC *header = (EXEC*)Ra0;
1452         u32 tmp;
1453
1454 #ifdef PSXBIOS_LOG
1455         PSXBIOS_LOG("psxBios_%s: %x, %x, %x\n", biosA0n[0x43], a0, a1, a2);
1456 #endif
1457
1458         header->_sp = sp;
1459         header->_fp = fp;
1460         header->_sp = sp;
1461         header->_gp = gp;
1462         header->ret = ra;
1463         header->base = s0;
1464
1465         if (header->S_addr != 0) {
1466                 tmp = header->S_addr + header->s_size;
1467                 sp = tmp;
1468                 fp = sp;
1469         }
1470
1471         gp = header->gp0;
1472
1473         s0 = a0;
1474
1475         a0 = a1;
1476         a1 = a2;
1477
1478         ra = 0x8000;
1479         pc0 = header->_pc0;
1480 }
1481
1482 void psxBios_FlushCache() { // 44
1483 #ifdef PSXBIOS_LOG
1484         PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x44]);
1485 #endif
1486         psxCpu->Notify(R3000ACPU_NOTIFY_CACHE_ISOLATED, NULL);
1487         psxCpu->Notify(R3000ACPU_NOTIFY_CACHE_UNISOLATED, NULL);
1488         pc0 = ra;
1489 }
1490
1491 void psxBios_GPU_dw() { // 0x46
1492         int size;
1493         u32 *ptr;
1494
1495 #ifdef PSXBIOS_LOG
1496         PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x46]);
1497 #endif
1498
1499         GPU_writeData(0xa0000000);
1500         GPU_writeData((a1<<0x10)|(a0&0xffff));
1501         GPU_writeData((a3<<0x10)|(a2&0xffff));
1502         size = (a2*a3)/2;
1503         ptr = (u32*)PSXM(Rsp[4]);  //that is correct?
1504         while(size--)
1505         {
1506                 GPU_writeData(SWAPu32(*ptr++));
1507         } 
1508
1509         pc0 = ra;
1510 }
1511
1512 void psxBios_mem2vram() { // 0x47
1513         int size;
1514         gpuSyncPluginSR();
1515         GPU_writeData(0xa0000000);
1516         GPU_writeData((a1<<0x10)|(a0&0xffff));
1517         GPU_writeData((a3<<0x10)|(a2&0xffff));
1518         size = ((((a2 * a3) / 2) >> 4) << 16);
1519         GPU_writeStatus(0x04000002);
1520         psxHwWrite32(0x1f8010f4,0);
1521         psxHwWrite32(0x1f8010f0,psxHwRead32(0x1f8010f0)|0x800);
1522         psxHwWrite32(0x1f8010a0,Rsp[4]);//might have a buggy...
1523         psxHwWrite32(0x1f8010a4, size | 0x10);
1524         psxHwWrite32(0x1f8010a8,0x01000201);
1525
1526         pc0 = ra;
1527 }
1528
1529 void psxBios_SendGPU() { // 0x48
1530         GPU_writeStatus(a0);
1531         gpuSyncPluginSR();
1532         pc0 = ra;
1533 }
1534
1535 void psxBios_GPU_cw() { // 0x49
1536         gpuSyncPluginSR();
1537         GPU_writeData(a0);
1538         v0 = HW_GPU_STATUS;
1539         pc0 = ra;
1540 }
1541
1542 void psxBios_GPU_cwb() { // 0x4a
1543         u32 *ptr = (u32*)Ra0;
1544         int size = a1;
1545         gpuSyncPluginSR();
1546         while(size--)
1547         {
1548                 GPU_writeData(SWAPu32(*ptr++));
1549         }
1550
1551         pc0 = ra;
1552 }
1553    
1554 void psxBios_GPU_SendPackets() { //4b:  
1555         gpuSyncPluginSR();
1556         GPU_writeStatus(0x04000002);
1557         psxHwWrite32(0x1f8010f4,0);
1558         psxHwWrite32(0x1f8010f0,psxHwRead32(0x1f8010f0)|0x800);
1559         psxHwWrite32(0x1f8010a0,a0);
1560         psxHwWrite32(0x1f8010a4,0);
1561         psxHwWrite32(0x1f8010a8,0x010000401);
1562         pc0 = ra;
1563 }
1564
1565 void psxBios_sys_a0_4c() { // 0x4c GPU relate
1566         psxHwWrite32(0x1f8010a8,0x00000401);
1567         GPU_writeData(0x0400000);
1568         GPU_writeData(0x0200000);
1569         GPU_writeData(0x0100000);
1570         v0 = 0x1f801814;
1571         pc0 = ra;
1572 }
1573
1574 void psxBios_GPU_GetGPUStatus() { // 0x4d
1575         v0 = GPU_readStatus();
1576         pc0 = ra;
1577 }
1578
1579 #undef s_addr
1580
1581 void psxBios_LoadExec() { // 51
1582         EXEC *header = (EXEC*)PSXM(0xf000);
1583         u32 s_addr, s_size;
1584
1585 #ifdef PSXBIOS_LOG
1586         PSXBIOS_LOG("psxBios_%s: %s: %x,%x\n", biosA0n[0x51], Ra0, a1, a2);
1587 #endif
1588         s_addr = a1; s_size = a2;
1589
1590         a1 = 0xf000;
1591         psxBios_Load();
1592
1593         header->S_addr = s_addr;
1594         header->s_size = s_size;
1595
1596         a0 = 0xf000; a1 = 0; a2 = 0;
1597         psxBios_Exec();
1598 }
1599
1600 void psxBios__bu_init() { // 70
1601 #ifdef PSXBIOS_LOG
1602         PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x70]);
1603 #endif
1604
1605         DeliverEvent(0x11, 0x2); // 0xf0000011, 0x0004
1606         DeliverEvent(0x81, 0x2); // 0xf4000001, 0x0004
1607
1608         pc0 = ra;
1609 }
1610
1611 void psxBios__96_init() { // 71
1612 #ifdef PSXBIOS_LOG
1613         PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x71]);
1614 #endif
1615
1616         pc0 = ra;
1617 }
1618
1619 static void psxBios_SysDeqIntRP_();
1620
1621 static void psxBios_DequeueCdIntr_() {
1622         a0 = 0; a1 = 0x91d0;
1623         psxBios_SysDeqIntRP_();
1624         a0 = 0; a1 = 0x91e0;
1625         psxBios_SysDeqIntRP_();
1626         use_cycles(16);
1627 }
1628
1629 static void psxBios_DequeueCdIntr() { // a3
1630         PSXBIOS_LOG("psxBios_%s\n", biosA0n[0xa3]);
1631         psxBios_DequeueCdIntr_();
1632 }
1633
1634 static void psxBios_CdRemove() { // 56, 72
1635         PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x72]);
1636
1637         // CloseEvent 0xf1000000
1638         // CloseEvent 0xf1000001
1639         // CloseEvent 0xf1000002
1640         // CloseEvent 0xf1000003
1641         // CloseEvent 0xf1000004
1642         psxBios_DequeueCdIntr_();
1643
1644         // EnterCriticalSection - should be done at the beginning,
1645         // but this way is much easier to implement
1646         a0 = 1;
1647         pc0 = A_SYSCALL;
1648         use_cycles(30);
1649 }
1650
1651 void psxBios_SetMem() { // 9f
1652         u32 new = psxHu32(0x1060);
1653
1654 #ifdef PSXBIOS_LOG
1655         PSXBIOS_LOG("psxBios_%s: %x, %x\n", biosA0n[0x9f], a0, a1);
1656 #endif
1657
1658         switch(a0) {
1659                 case 2:
1660                         psxHu32ref(0x1060) = SWAP32(new);
1661                         psxMu32ref(0x060) = a0;
1662                         SysPrintf("Change effective memory : %d MBytes\n",a0);
1663                         break;
1664
1665                 case 8:
1666                         psxHu32ref(0x1060) = SWAP32(new | 0x300);
1667                         psxMu32ref(0x060) = a0;
1668                         SysPrintf("Change effective memory : %d MBytes\n",a0);
1669
1670                 default:
1671                         SysPrintf("Effective memory must be 2/8 MBytes\n");
1672                 break;
1673         }
1674
1675         pc0 = ra;
1676 }
1677
1678 /* TODO FIXME : Not compliant. -1 indicates failure but using 1 for now. */
1679 void psxBios_get_cd_status(void) //a6
1680 {
1681         v0 = 1;
1682         pc0 = ra;
1683 }
1684
1685 void psxBios__card_info() { // ab
1686 #ifdef PSXBIOS_LOG
1687         PSXBIOS_LOG("psxBios_%s: %x\n", biosA0n[0xab], a0);
1688 #endif
1689         u32 ret, port;
1690         card_active_chan = a0;
1691         port = card_active_chan >> 4;
1692
1693         switch (port) {
1694         case 0x0:
1695         case 0x1:
1696                 ret = 0x2;
1697                 if (McdDisable[port & 1])
1698                         ret = 0x8;
1699                 break;
1700         default:
1701 #ifdef PSXBIOS_LOG
1702                 PSXBIOS_LOG("psxBios_%s: UNKNOWN PORT 0x%x\n", biosA0n[0xab], card_active_chan);
1703 #endif
1704                 ret = 0x11;
1705                 break;
1706         }
1707
1708         if (McdDisable[0] && McdDisable[1])
1709                 ret = 0x8;
1710
1711         DeliverEvent(0x11, 0x2); // 0xf0000011, 0x0004
1712 //      DeliverEvent(0x81, 0x2); // 0xf4000001, 0x0004
1713         DeliverEvent(0x81, ret); // 0xf4000001, 0x0004
1714         v0 = 1; pc0 = ra;
1715 }
1716
1717 void psxBios__card_load() { // ac
1718 #ifdef PSXBIOS_LOG
1719         PSXBIOS_LOG("psxBios_%s: %x\n", biosA0n[0xac], a0);
1720 #endif
1721
1722         card_active_chan = a0;
1723
1724 //      DeliverEvent(0x11, 0x2); // 0xf0000011, 0x0004
1725         DeliverEvent(0x81, 0x2); // 0xf4000001, 0x0004
1726
1727         v0 = 1; pc0 = ra;
1728 }
1729
1730 /* System calls B0 */
1731
1732 static u32 psxBios_SysMalloc_(u32 size);
1733
1734 static void psxBios_SysMalloc() { // B 00
1735         u32 ret = psxBios_SysMalloc_(a0);
1736
1737         PSXBIOS_LOG("psxBios_%s 0x%x -> %x\n", biosB0n[0x00], a0, ret);
1738         mips_return_c(ret, 33);
1739 }
1740
1741 void psxBios_SetRCnt() { // 02
1742 #ifdef PSXBIOS_LOG
1743         PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x02]);
1744 #endif
1745
1746         a0&= 0x3;
1747         if (a0 != 3) {
1748                 u32 mode=0;
1749
1750                 psxRcntWtarget(a0, a1);
1751                 if (a2&0x1000) mode|= 0x050; // Interrupt Mode
1752                 if (a2&0x0100) mode|= 0x008; // Count to 0xffff
1753                 if (a2&0x0010) mode|= 0x001; // Timer stop mode
1754                 if (a0 == 2) { if (a2&0x0001) mode|= 0x200; } // System Clock mode
1755                 else         { if (a2&0x0001) mode|= 0x100; } // System Clock mode
1756
1757                 psxRcntWmode(a0, mode);
1758         }
1759         pc0 = ra;
1760 }
1761
1762 void psxBios_GetRCnt() { // 03
1763 #ifdef PSXBIOS_LOG
1764         PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x03]);
1765 #endif
1766
1767         a0&= 0x3;
1768         if (a0 != 3) v0 = psxRcntRcount(a0);
1769         else v0 = 0;
1770         pc0 = ra;
1771 }
1772
1773 void psxBios_StartRCnt() { // 04
1774 #ifdef PSXBIOS_LOG
1775         PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x04]);
1776 #endif
1777
1778         a0&= 0x3;
1779         if (a0 != 3) psxHu32ref(0x1074)|= SWAP32((u32)((1<<(a0+4))));
1780         else psxHu32ref(0x1074)|= SWAPu32(0x1);
1781         v0 = 1; pc0 = ra;
1782 }
1783
1784 void psxBios_StopRCnt() { // 05
1785 #ifdef PSXBIOS_LOG
1786         PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x05]);
1787 #endif
1788
1789         a0&= 0x3;
1790         if (a0 != 3) psxHu32ref(0x1074)&= SWAP32((u32)(~(1<<(a0+4))));
1791         else psxHu32ref(0x1074)&= SWAPu32(~0x1);
1792         pc0 = ra;
1793 }
1794
1795 void psxBios_ResetRCnt() { // 06
1796 #ifdef PSXBIOS_LOG
1797         PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x06]);
1798 #endif
1799
1800         a0&= 0x3;
1801         if (a0 != 3) {
1802                 psxRcntWmode(a0, 0);
1803                 psxRcntWtarget(a0, 0);
1804                 psxRcntWcount(a0, 0);
1805         }
1806         pc0 = ra;
1807 }
1808
1809
1810 /* gets ev for use with EventCB */
1811 #define GetEv() \
1812         ev = (a0 >> 24) & 0xf; \
1813         if (ev == 0xf) ev = 0x5; \
1814         ev*= 32; \
1815         ev+= a0&0x1f;
1816
1817 /* gets spec for use with EventCB */
1818 #define GetSpec() \
1819         spec = 0; \
1820         switch (a1) { \
1821                 case 0x0301: spec = 16; break; \
1822                 case 0x0302: spec = 17; break; \
1823                 default: \
1824                         for (i=0; i<16; i++) if (a1 & (1 << i)) { spec = i; break; } \
1825                         break; \
1826         }
1827
1828 void psxBios_DeliverEvent() { // 07
1829         int ev, spec;
1830         int i;
1831
1832         GetEv();
1833         GetSpec();
1834
1835 #ifdef PSXBIOS_LOG
1836         PSXBIOS_LOG("psxBios_%s %x,%x\n", biosB0n[0x07], ev, spec);
1837 #endif
1838
1839         DeliverEvent(ev, spec);
1840
1841         pc0 = ra;
1842 }
1843
1844 void psxBios_OpenEvent() { // 08
1845         int ev, spec;
1846         int i;
1847
1848         GetEv();
1849         GetSpec();
1850
1851 #ifdef PSXBIOS_LOG
1852         PSXBIOS_LOG("psxBios_%s %x,%x (class:%x, spec:%x, mode:%x, func:%x)\n", biosB0n[0x08], ev, spec, a0, a1, a2, a3);
1853 #endif
1854
1855         EventCB[ev][spec].status = EvStWAIT;
1856         EventCB[ev][spec].mode = a2;
1857         EventCB[ev][spec].fhandler = a3;
1858
1859         v0 = ev | (spec << 8);
1860         pc0 = ra;
1861 }
1862
1863 void psxBios_CloseEvent() { // 09
1864         int ev, spec;
1865
1866         ev   = a0 & 0xff;
1867         spec = (a0 >> 8) & 0xff;
1868
1869 #ifdef PSXBIOS_LOG
1870         PSXBIOS_LOG("psxBios_%s %x,%x\n", biosB0n[0x09], ev, spec);
1871 #endif
1872
1873         EventCB[ev][spec].status = EvStUNUSED;
1874
1875         v0 = 1; pc0 = ra;
1876 }
1877
1878 void psxBios_WaitEvent() { // 0a
1879         int ev, spec;
1880
1881         ev   = a0 & 0xff;
1882         spec = (a0 >> 8) & 0xff;
1883 #ifdef PSXBIOS_LOG
1884         PSXBIOS_LOG("psxBios_%s %x,%x\n", biosB0n[0x0a], ev, spec);
1885 #endif
1886         if (EventCB[ev][spec].status == EvStUNUSED)
1887         {
1888                 v0 = 0;
1889                 pc0 = ra;
1890                 return;
1891         }
1892
1893         if (EventCB[ev][spec].status == EvStALREADY)
1894         {
1895                 /* Callback events (mode=EvMdINTR) do never set the ready flag (and thus WaitEvent would hang forever). */
1896                 if (!(EventCB[ev][spec].mode == EvMdINTR)) EventCB[ev][spec].status = EvStACTIVE;
1897                 v0 = 1;
1898                 pc0 = ra;
1899                 return;
1900         }
1901
1902         v0 = 0;
1903         pc0 = ra;
1904 }
1905
1906 void psxBios_TestEvent() { // 0b
1907         int ev, spec;
1908
1909         ev   = a0 & 0xff;
1910         spec = (a0 >> 8) & 0xff;
1911
1912         if (EventCB[ev][spec].status == EvStALREADY)
1913         {
1914                 if (!(EventCB[ev][spec].mode == EvMdINTR)) EventCB[ev][spec].status = EvStACTIVE;
1915                 v0 = 1;
1916         }
1917         else
1918         {
1919                 v0 = 0;
1920         }
1921
1922 #ifdef PSXBIOS_LOG
1923         PSXBIOS_LOG("psxBios_%s %x,%x: %x\n", biosB0n[0x0b], ev, spec, v0);
1924 #endif
1925
1926         pc0 = ra;
1927 }
1928
1929 void psxBios_EnableEvent() { // 0c
1930         int ev, spec;
1931
1932         ev   = a0 & 0xff;
1933         spec = (a0 >> 8) & 0xff;
1934
1935 #ifdef PSXBIOS_LOG
1936         PSXBIOS_LOG("psxBios_%s %x,%x\n", biosB0n[0x0c], ev, spec);
1937 #endif
1938
1939         EventCB[ev][spec].status = EvStACTIVE;
1940
1941         v0 = 1; pc0 = ra;
1942 }
1943
1944 void psxBios_DisableEvent() { // 0d
1945         int ev, spec;
1946
1947         ev   = a0 & 0xff;
1948         spec = (a0 >> 8) & 0xff;
1949
1950 #ifdef PSXBIOS_LOG
1951         PSXBIOS_LOG("psxBios_%s %x,%x\n", biosB0n[0x0d], ev, spec);
1952 #endif
1953
1954         EventCB[ev][spec].status = EvStWAIT;
1955
1956         v0 = 1; pc0 = ra;
1957 }
1958
1959 /*
1960  *      long OpenTh(long (*func)(), unsigned long sp, unsigned long gp);
1961  */
1962
1963 void psxBios_OpenTh() { // 0e
1964         TCB *tcb = loadRam32ptr(A_TT_TCB);
1965         u32 limit = loadRam32(A_TT_TCB + 4) / 0xc0u;
1966         int th;
1967
1968         for (th = 1; th < limit; th++)
1969         {
1970                 if (tcb[th].status != SWAP32(0x4000)) break;
1971
1972         }
1973         if (th == limit) {
1974                 // Feb 2019 - Added out-of-bounds fix caught by cppcheck:
1975                 // When no free TCB is found, return 0xffffffff according to Nocash doc.
1976 #ifdef PSXBIOS_LOG
1977                 PSXBIOS_LOG("\t%s() WARNING! No Free TCBs found!\n", __func__);
1978 #endif
1979                 mips_return_c(0xffffffff, 20);
1980                 return;
1981         }
1982         PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x0e], th);
1983
1984         tcb[th].status  = SWAP32(0x4000);
1985         tcb[th].mode    = SWAP32(0x1000);
1986         tcb[th].epc     = SWAP32(a0);
1987         tcb[th].reg[30] = SWAP32(a1); // fp
1988         tcb[th].reg[29] = SWAP32(a1); // sp
1989         tcb[th].reg[28] = SWAP32(a2); // gp
1990
1991         mips_return_c(0xff000000 + th, 34);
1992 }
1993
1994 /*
1995  *      int CloseTh(long thread);
1996  */
1997
1998 void psxBios_CloseTh() { // 0f
1999         TCB *tcb = loadRam32ptr(A_TT_TCB);
2000         u32 limit = loadRam32(A_TT_TCB + 4) / 0xc0u;
2001         u32 th = a0 & 0xff;
2002
2003 #ifdef PSXBIOS_LOG
2004         PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x0f], th);
2005 #endif
2006         /* The return value is always 1 (even if the handle was already closed). */
2007         v0 = 1;
2008         if (th < limit && tcb[th].status == SWAP32(0x4000)) {
2009                 tcb[th].status = SWAP32(0x1000);
2010         }
2011
2012         pc0 = ra;
2013 }
2014
2015 /*
2016  *      int ChangeTh(long thread);
2017  */
2018
2019 void psxBios_ChangeTh() { // 10
2020         u32 tcbBase = loadRam32(A_TT_TCB);
2021         u32 th = a0 & 0xffff;
2022
2023 #ifdef PSXBIOS_LOG
2024 //      PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x10], th);
2025 #endif
2026         // without doing any argument checks, just issue a syscall
2027         // (like the real bios does)
2028         a0 = 3;
2029         a1 = tcbBase + th * sizeof(TCB);
2030         pc0 = A_SYSCALL;
2031         use_cycles(15);
2032 }
2033
2034 void psxBios_InitPAD() { // 0x12
2035 #ifdef PSXBIOS_LOG
2036         PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x12]);
2037 #endif
2038
2039         pad_buf1 = (char*)Ra0;
2040         pad_buf1len = a1;
2041         pad_buf2 = (char*)Ra2;
2042         pad_buf2len = a3;
2043
2044         v0 = 1; pc0 = ra;
2045 }
2046
2047 void psxBios_StartPAD() { // 13
2048 #ifdef PSXBIOS_LOG
2049         PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x13]);
2050 #endif
2051         pad_stopped = 0;
2052         psxHwWrite16(0x1f801074, (unsigned short)(psxHwRead16(0x1f801074) | 0x1));
2053         psxRegs.CP0.n.SR |= 0x401;
2054         pc0 = ra;
2055 }
2056
2057 void psxBios_StopPAD() { // 14
2058 #ifdef PSXBIOS_LOG
2059         PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x14]);
2060 #endif
2061         pad_stopped = 1;
2062         pad_buf1 = NULL;
2063         pad_buf2 = NULL;
2064         pc0 = ra;
2065 }
2066
2067 void psxBios_PAD_init() { // 15
2068 #ifdef PSXBIOS_LOG
2069         PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x15]);
2070 #endif
2071         if (!(a0 == 0x20000000 || a0 == 0x20000001))
2072         {
2073                 v0 = 0;
2074                 pc0 = ra;
2075                 return;
2076         }
2077         psxHwWrite16(0x1f801074, (u16)(psxHwRead16(0x1f801074) | 0x1));
2078         pad_buf = (int *)Ra1;
2079         *pad_buf = -1;
2080         psxRegs.CP0.n.SR |= 0x401;
2081         v0 = 2;
2082         pc0 = ra;
2083 }
2084
2085 void psxBios_PAD_dr() { // 16
2086 #ifdef PSXBIOS_LOG
2087         PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x16]);
2088 #endif
2089
2090         v0 = -1; pc0 = ra;
2091 }
2092
2093 static void psxBios_ReturnFromException() { // 17
2094         u32 tcbPtr = loadRam32(A_TT_PCB);
2095         const TCB *tcb = loadRam32ptr(tcbPtr);
2096         int i;
2097
2098         for (i = 1; i < 32; i++)
2099                 psxRegs.GPR.r[i] = SWAP32(tcb->reg[i]);
2100         psxRegs.GPR.n.lo = SWAP32(tcb->lo);
2101         psxRegs.GPR.n.hi = SWAP32(tcb->hi);
2102         psxRegs.CP0.n.SR = SWAP32(tcb->sr);
2103
2104         //printf("%s %08x->%08x %u\n", __func__, pc0, tcb->epc, psxRegs.cycle);
2105         pc0 = k0 = SWAP32(tcb->epc);
2106
2107         psxRegs.CP0.n.SR = (psxRegs.CP0.n.SR & ~0x0f) | ((psxRegs.CP0.n.SR & 0x3c) >> 2);
2108         use_cycles(53);
2109         psxBranchTest();
2110 }
2111
2112 void psxBios_ResetEntryInt() { // 18
2113         PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x18]);
2114
2115         storeRam32(A_EEXIT_PTR, A_EEXIT_DEF);
2116         mips_return_void_c(5);
2117 }
2118
2119 void psxBios_HookEntryInt() { // 19
2120         PSXBIOS_LOG("psxBios_%s %x\n", biosB0n[0x19], a0);
2121
2122         storeRam32(A_EEXIT_PTR, a0);
2123         mips_return_void_c(3);
2124 }
2125
2126 void psxBios_UnDeliverEvent() { // 0x20
2127         int ev, spec;
2128         int i;
2129
2130         GetEv();
2131         GetSpec();
2132
2133 #ifdef PSXBIOS_LOG
2134         PSXBIOS_LOG("psxBios_%s %x,%x\n", biosB0n[0x20], ev, spec);
2135 #endif
2136
2137         if (EventCB[ev][spec].status == EvStALREADY &&
2138                 EventCB[ev][spec].mode == EvMdNOINTR)
2139                 EventCB[ev][spec].status = EvStACTIVE;
2140
2141         pc0 = ra;
2142 }
2143
2144 char ffile[64], *pfile;
2145 int nfile;
2146
2147 static void buopen(int mcd, char *ptr, char *cfg)
2148 {
2149         int i;
2150         char *mcd_data = ptr;
2151
2152         strcpy(FDesc[1 + mcd].name, Ra0+5);
2153         FDesc[1 + mcd].offset = 0;
2154         FDesc[1 + mcd].mode   = a1;
2155
2156         for (i=1; i<16; i++) {
2157                 const char *fptr = mcd_data + 128 * i;
2158                 if ((*fptr & 0xF0) != 0x50) continue;
2159                 if (strcmp(FDesc[1 + mcd].name, fptr+0xa)) continue;
2160                 FDesc[1 + mcd].mcfile = i;
2161                 SysPrintf("open %s\n", fptr+0xa);
2162                 v0 = 1 + mcd;
2163                 break;
2164         }
2165         if (a1 & 0x200 && v0 == -1) { /* FCREAT */
2166                 for (i=1; i<16; i++) {
2167                         int j, xor, nblk = a1 >> 16;
2168                         char *pptr, *fptr2;
2169                         char *fptr = mcd_data + 128 * i;
2170
2171                         if ((*fptr & 0xF0) != 0xa0) continue;
2172
2173                         FDesc[1 + mcd].mcfile = i;
2174                         fptr[0] = 0x51;
2175                         fptr[4] = 0x00;
2176                         fptr[5] = 0x20 * nblk;
2177                         fptr[6] = 0x00;
2178                         fptr[7] = 0x00;
2179                         strcpy(fptr+0xa, FDesc[1 + mcd].name);
2180                         pptr = fptr2 = fptr;
2181                         for(j=2; j<=nblk; j++) {
2182                                 int k;
2183                                 for(i++; i<16; i++) {
2184                                         fptr2 += 128;
2185
2186                                         memset(fptr2, 0, 128);
2187                                         fptr2[0] = j < nblk ? 0x52 : 0x53;
2188                                         pptr[8] = i - 1;
2189                                         pptr[9] = 0;
2190                                         for (k=0, xor=0; k<127; k++) xor^= pptr[k];
2191                                         pptr[127] = xor;
2192                                         pptr = fptr2;
2193                                         break;
2194                                 }
2195                                 /* shouldn't this return ENOSPC if i == 16? */
2196                         }
2197                         pptr[8] = pptr[9] = 0xff;
2198                         for (j=0, xor=0; j<127; j++) xor^= pptr[j];
2199                         pptr[127] = xor;
2200                         SysPrintf("openC %s %d\n", ptr, nblk);
2201                         v0 = 1 + mcd;
2202                         /* just go ahead and resave them all */
2203                         SaveMcd(cfg, ptr, 128, 128 * 15);
2204                         break;
2205                 }
2206                 /* shouldn't this return ENOSPC if i == 16? */
2207         }
2208 }
2209
2210 /*
2211  *      int open(char *name , int mode);
2212  */
2213
2214 void psxBios_open() { // 0x32
2215         void *pa0 = Ra0;
2216
2217 #ifdef PSXBIOS_LOG
2218         PSXBIOS_LOG("psxBios_%s: %s,%x\n", biosB0n[0x32], Ra0, a1);
2219 #endif
2220
2221         v0 = -1;
2222
2223         if (pa0 != INVALID_PTR) {
2224                 if (!strncmp(pa0, "bu00", 4)) {
2225                         buopen(1, Mcd1Data, Config.Mcd1);
2226                 }
2227
2228                 if (!strncmp(pa0, "bu10", 4)) {
2229                         buopen(2, Mcd2Data, Config.Mcd2);
2230                 }
2231         }
2232
2233         pc0 = ra;
2234 }
2235
2236 /*
2237  *      int lseek(int fd , int offset , int whence);
2238  */
2239
2240 void psxBios_lseek() { // 0x33
2241 #ifdef PSXBIOS_LOG
2242         PSXBIOS_LOG("psxBios_%s: %x, %x, %x\n", biosB0n[0x33], a0, a1, a2);
2243 #endif
2244
2245         switch (a2) {
2246                 case 0: // SEEK_SET
2247                         FDesc[a0].offset = a1;
2248                         v0 = a1;
2249 //                      DeliverEvent(0x11, 0x2); // 0xf0000011, 0x0004
2250 //                      DeliverEvent(0x81, 0x2); // 0xf4000001, 0x0004
2251                         break;
2252
2253                 case 1: // SEEK_CUR
2254                         FDesc[a0].offset+= a1;
2255                         v0 = FDesc[a0].offset;
2256                         break;
2257         }
2258
2259         pc0 = ra;
2260 }
2261
2262
2263 /*
2264  *      int read(int fd , void *buf , int nbytes);
2265  */
2266
2267 void psxBios_read() { // 0x34
2268         char *ptr;
2269         void *pa1 = Ra1;
2270
2271 #ifdef PSXBIOS_LOG
2272         PSXBIOS_LOG("psxBios_%s: %x, %x, %x\n", biosB0n[0x34], a0, a1, a2);
2273 #endif
2274
2275         v0 = -1;
2276
2277         if (pa1 != INVALID_PTR) {
2278                 switch (a0) {
2279                         case 2: buread(pa1, 1, a2); break;
2280                         case 3: buread(pa1, 2, a2); break;
2281                 }
2282         }
2283
2284         pc0 = ra;
2285 }
2286
2287 /*
2288  *      int write(int fd , void *buf , int nbytes);
2289  */
2290
2291 void psxBios_write() { // 0x35/0x03
2292         char *ptr;
2293         void *pa1 = Ra1;
2294
2295 #ifdef PSXBIOS_LOG
2296         PSXBIOS_LOG("psxBios_%s: %x,%x,%x\n", biosB0n[0x35], a0, a1, a2);
2297 #endif
2298
2299         v0 = -1;
2300         if (pa1 == INVALID_PTR) {
2301                 pc0 = ra;
2302                 return;
2303         }
2304
2305         if (a0 == 1) { // stdout
2306                 char *ptr = pa1;
2307
2308                 v0 = a2;
2309                 while (a2 > 0) {
2310                         SysPrintf("%c", *ptr++); a2--;
2311                 }
2312                 pc0 = ra; return;
2313         }
2314
2315         switch (a0) {
2316                 case 2: buwrite(pa1, 1, a2); break;
2317                 case 3: buwrite(pa1, 2, a2); break;
2318         }
2319
2320         pc0 = ra;
2321 }
2322
2323 static void psxBios_write_psxout() {
2324         if (a0 == 1) { // stdout
2325                 const char *ptr = Ra1;
2326                 int len = a2;
2327
2328                 if (ptr != INVALID_PTR)
2329                         while (len-- > 0)
2330                                 SysPrintf("%c", *ptr++);
2331         }
2332 }
2333
2334 static void psxBios_putchar_psxout() { // 3d
2335         SysPrintf("%c", (char)a0);
2336 }
2337
2338 static void psxBios_puts_psxout() { // 3e/3f
2339         SysPrintf("%s", Ra0);
2340 }
2341
2342 /*
2343  *      int close(int fd);
2344  */
2345
2346 void psxBios_close() { // 0x36
2347 #ifdef PSXBIOS_LOG
2348         PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x36], a0);
2349 #endif
2350
2351         v0 = a0;
2352         pc0 = ra;
2353 }
2354
2355 void psxBios_putchar() { // 3d
2356         SysPrintf("%c", (char)a0);
2357         pc0 = ra;
2358 }
2359
2360 void psxBios_puts() { // 3e/3f
2361         SysPrintf("%s", Ra0);
2362         pc0 = ra;
2363 }
2364
2365
2366 /* To avoid any issues with different behaviour when using the libc's own strlen instead.
2367  * We want to mimic the PSX's behaviour in this case for bufile. */
2368 static size_t strlen_internal(char* p)
2369 {
2370         size_t size_of_array = 0;
2371         while (*p++) size_of_array++;
2372         return size_of_array;
2373 }
2374
2375 #define bufile(mcd) { \
2376         size_t size_of_name = strlen_internal(dir->name); \
2377         while (nfile < 16) { \
2378                 int match=1; \
2379  \
2380                 ptr = Mcd##mcd##Data + 128 * (nfile + 1); \
2381                 nfile++; \
2382                 if ((*ptr & 0xF0) != 0x50) continue; \
2383                 /* Bug link files show up as free block. */ \
2384                 if (!ptr[0xa]) continue; \
2385                 ptr+= 0xa; \
2386                 if (pfile[0] == 0) { \
2387                         strncpy(dir->name, ptr, sizeof(dir->name) - 1); \
2388                         if (size_of_name < sizeof(dir->name)) dir->name[size_of_name] = '\0'; \
2389                 } else for (i=0; i<20; i++) { \
2390                         if (pfile[i] == ptr[i]) { \
2391                                                                 dir->name[i] = ptr[i]; continue; } \
2392                         if (pfile[i] == '?') { \
2393                                 dir->name[i] = ptr[i]; continue; } \
2394                         if (pfile[i] == '*') { \
2395                                 strcpy(dir->name+i, ptr+i); break; } \
2396                         match = 0; break; \
2397                 } \
2398                 SysPrintf("%d : %s = %s + %s (match=%d)\n", nfile, dir->name, pfile, ptr, match); \
2399                 if (match == 0) { continue; } \
2400                 dir->size = 8192; \
2401                 v0 = _dir; \
2402                 break; \
2403         } \
2404 }
2405
2406 /*
2407  *      struct DIRENTRY* firstfile(char *name,struct DIRENTRY *dir);
2408  */
2409
2410 void psxBios_firstfile() { // 42
2411         struct DIRENTRY *dir = (struct DIRENTRY *)Ra1;
2412         void *pa0 = Ra0;
2413         u32 _dir = a1;
2414         char *ptr;
2415         int i;
2416
2417 #ifdef PSXBIOS_LOG
2418         PSXBIOS_LOG("psxBios_%s: %s\n", biosB0n[0x42], Ra0);
2419 #endif
2420
2421         v0 = 0;
2422
2423         if (pa0 != INVALID_PTR) {
2424                 strcpy(ffile, pa0);
2425                 pfile = ffile+5;
2426                 nfile = 0;
2427                 if (!strncmp(pa0, "bu00", 4)) {
2428                         // firstfile() calls _card_read() internally, so deliver it's event
2429                         DeliverEvent(0x11, 0x2);
2430                         bufile(1);
2431                 } else if (!strncmp(pa0, "bu10", 4)) {
2432                         // firstfile() calls _card_read() internally, so deliver it's event
2433                         DeliverEvent(0x11, 0x2);
2434                         bufile(2);
2435                 }
2436         }
2437
2438         pc0 = ra;
2439 }
2440
2441 /*
2442  *      struct DIRENTRY* nextfile(struct DIRENTRY *dir);
2443  */
2444
2445 void psxBios_nextfile() { // 43
2446         struct DIRENTRY *dir = (struct DIRENTRY *)Ra0;
2447         u32 _dir = a0;
2448         char *ptr;
2449         int i;
2450
2451 #ifdef PSXBIOS_LOG
2452         PSXBIOS_LOG("psxBios_%s: %s\n", biosB0n[0x43], dir->name);
2453 #endif
2454
2455         v0 = 0;
2456
2457         if (!strncmp(ffile, "bu00", 4)) {
2458                 bufile(1);
2459         }
2460
2461         if (!strncmp(ffile, "bu10", 4)) {
2462                 bufile(2);
2463         }
2464
2465         pc0 = ra;
2466 }
2467
2468 #define burename(mcd) { \
2469         for (i=1; i<16; i++) { \
2470                 int namelen, j, xor = 0; \
2471                 ptr = Mcd##mcd##Data + 128 * i; \
2472                 if ((*ptr & 0xF0) != 0x50) continue; \
2473                 if (strcmp(Ra0+5, ptr+0xa)) continue; \
2474                 namelen = strlen(Ra1+5); \
2475                 memcpy(ptr+0xa, Ra1+5, namelen); \
2476                 memset(ptr+0xa+namelen, 0, 0x75-namelen); \
2477                 for (j=0; j<127; j++) xor^= ptr[j]; \
2478                 ptr[127] = xor; \
2479                 SaveMcd(Config.Mcd##mcd, Mcd##mcd##Data, 128 * i + 0xa, 0x76); \
2480                 v0 = 1; \
2481                 break; \
2482         } \
2483 }
2484
2485 /*
2486  *      int rename(char *old, char *new);
2487  */
2488
2489 void psxBios_rename() { // 44
2490         void *pa0 = Ra0;
2491         void *pa1 = Ra1;
2492         char *ptr;
2493         int i;
2494
2495 #ifdef PSXBIOS_LOG
2496         PSXBIOS_LOG("psxBios_%s: %s,%s\n", biosB0n[0x44], Ra0, Ra1);
2497 #endif
2498
2499         v0 = 0;
2500
2501         if (pa0 != INVALID_PTR && pa1 != INVALID_PTR) {
2502                 if (!strncmp(pa0, "bu00", 4) && !strncmp(pa1, "bu00", 4)) {
2503                         burename(1);
2504                 }
2505
2506                 if (!strncmp(pa0, "bu10", 4) && !strncmp(pa1, "bu10", 4)) {
2507                         burename(2);
2508                 }
2509         }
2510
2511         pc0 = ra;
2512 }
2513
2514
2515 #define budelete(mcd) { \
2516         for (i=1; i<16; i++) { \
2517                 ptr = Mcd##mcd##Data + 128 * i; \
2518                 if ((*ptr & 0xF0) != 0x50) continue; \
2519                 if (strcmp(Ra0+5, ptr+0xa)) continue; \
2520                 *ptr = (*ptr & 0xf) | 0xA0; \
2521                 SaveMcd(Config.Mcd##mcd, Mcd##mcd##Data, 128 * i, 1); \
2522                 SysPrintf("delete %s\n", ptr+0xa); \
2523                 v0 = 1; \
2524                 break; \
2525         } \
2526 }
2527
2528 /*
2529  *      int delete(char *name);
2530  */
2531
2532 void psxBios_delete() { // 45
2533         void *pa0 = Ra0;
2534         char *ptr;
2535         int i;
2536
2537 #ifdef PSXBIOS_LOG
2538         PSXBIOS_LOG("psxBios_%s: %s\n", biosB0n[0x45], Ra0);
2539 #endif
2540
2541         v0 = 0;
2542
2543         if (pa0 != INVALID_PTR) {
2544                 if (!strncmp(pa0, "bu00", 4)) {
2545                         budelete(1);
2546                 }
2547
2548                 if (!strncmp(pa0, "bu10", 4)) {
2549                         budelete(2);
2550                 }
2551         }
2552
2553         pc0 = ra;
2554 }
2555
2556 void psxBios_InitCARD() { // 4a
2557 #ifdef PSXBIOS_LOG
2558         PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x4a], a0);
2559 #endif
2560
2561         CardState = 0;
2562
2563         pc0 = ra;
2564 }
2565
2566 void psxBios_StartCARD() { // 4b
2567 #ifdef PSXBIOS_LOG
2568         PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x4b]);
2569 #endif
2570
2571         if (CardState == 0) CardState = 1;
2572
2573         pc0 = ra;
2574 }
2575
2576 void psxBios_StopCARD() { // 4c
2577 #ifdef PSXBIOS_LOG
2578         PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x4c]);
2579 #endif
2580
2581         if (CardState == 1) CardState = 0;
2582
2583         pc0 = ra;
2584 }
2585
2586 void psxBios__card_write() { // 0x4e
2587         void *pa2 = Ra2;
2588         int port;
2589
2590 #ifdef PSXBIOS_LOG
2591         PSXBIOS_LOG("psxBios_%s: %x,%x,%x\n", biosB0n[0x4e], a0, a1, a2);
2592 #endif
2593         /*
2594         Function also accepts sector 400h (a bug).
2595         But notaz said we shouldn't allow sector 400h because it can corrupt the emulator.
2596         */
2597         if (!(a1 <= 0x3FF))
2598         {
2599                 /* Invalid sectors */
2600                 v0 = 0; pc0 = ra;
2601                 return;
2602         }
2603         card_active_chan = a0;
2604         port = a0 >> 4;
2605
2606         if (pa2 != INVALID_PTR) {
2607                 if (port == 0) {
2608                         memcpy(Mcd1Data + a1 * 128, pa2, 128);
2609                         SaveMcd(Config.Mcd1, Mcd1Data, a1 * 128, 128);
2610                 } else {
2611                         memcpy(Mcd2Data + a1 * 128, pa2, 128);
2612                         SaveMcd(Config.Mcd2, Mcd2Data, a1 * 128, 128);
2613                 }
2614         }
2615
2616         DeliverEvent(0x11, 0x2); // 0xf0000011, 0x0004
2617 //      DeliverEvent(0x81, 0x2); // 0xf4000001, 0x0004
2618
2619         v0 = 1; pc0 = ra;
2620 }
2621
2622 void psxBios__card_read() { // 0x4f
2623         void *pa2 = Ra2;
2624         int port;
2625
2626 #ifdef PSXBIOS_LOG
2627         PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x4f]);
2628 #endif
2629         /*
2630         Function also accepts sector 400h (a bug).
2631         But notaz said we shouldn't allow sector 400h because it can corrupt the emulator.
2632         */
2633         if (!(a1 <= 0x3FF))
2634         {
2635                 /* Invalid sectors */
2636                 v0 = 0; pc0 = ra;
2637                 return;
2638         }
2639         card_active_chan = a0;
2640         port = a0 >> 4;
2641
2642         if (pa2 != INVALID_PTR) {
2643                 if (port == 0) {
2644                         memcpy(pa2, Mcd1Data + a1 * 128, 128);
2645                 } else {
2646                         memcpy(pa2, Mcd2Data + a1 * 128, 128);
2647                 }
2648         }
2649
2650         DeliverEvent(0x11, 0x2); // 0xf0000011, 0x0004
2651 //      DeliverEvent(0x81, 0x2); // 0xf4000001, 0x0004
2652
2653         v0 = 1; pc0 = ra;
2654 }
2655
2656 void psxBios__new_card() { // 0x50
2657 #ifdef PSXBIOS_LOG
2658         PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x50]);
2659 #endif
2660
2661         pc0 = ra;
2662 }
2663
2664 /* According to a user, this allows Final Fantasy Tactics to save/load properly */
2665 void psxBios__get_error(void) // 55
2666 {
2667         PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x55]);
2668         v0 = 0;
2669         pc0 = ra;
2670 }
2671
2672 void psxBios_Krom2RawAdd() { // 0x51
2673         int i = 0;
2674
2675         PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x51]);
2676         const u32 table_8140[][2] = {
2677                 {0x8140, 0x0000}, {0x8180, 0x0762}, {0x81ad, 0x0cc6}, {0x81b8, 0x0ca8},
2678                 {0x81c0, 0x0f00}, {0x81c8, 0x0d98}, {0x81cf, 0x10c2}, {0x81da, 0x0e6a},
2679                 {0x81e9, 0x13ce}, {0x81f0, 0x102c}, {0x81f8, 0x1590}, {0x81fc, 0x111c},
2680                 {0x81fd, 0x1626}, {0x824f, 0x113a}, {0x8259, 0x20ee}, {0x8260, 0x1266},
2681                 {0x827a, 0x24cc}, {0x8281, 0x1572}, {0x829b, 0x28aa}, {0x829f, 0x187e},
2682                 {0x82f2, 0x32dc}, {0x8340, 0x2238}, {0x837f, 0x4362}, {0x8380, 0x299a},
2683                 {0x8397, 0x4632}, {0x839f, 0x2c4c}, {0x83b7, 0x49f2}, {0x83bf, 0x2f1c},
2684                 {0x83d7, 0x4db2}, {0x8440, 0x31ec}, {0x8461, 0x5dde}, {0x8470, 0x35ca},
2685                 {0x847f, 0x6162}, {0x8480, 0x378c}, {0x8492, 0x639c}, {0x849f, 0x39a8},
2686                 {0xffff, 0}
2687         };
2688
2689         const u32 table_889f[][2] = {
2690                 {0x889f, 0x3d68},  {0x8900, 0x40ec},  {0x897f, 0x4fb0},  {0x8a00, 0x56f4},
2691                 {0x8a7f, 0x65b8},  {0x8b00, 0x6cfc},  {0x8b7f, 0x7bc0},  {0x8c00, 0x8304},
2692                 {0x8c7f, 0x91c8},  {0x8d00, 0x990c},  {0x8d7f, 0xa7d0},  {0x8e00, 0xaf14},
2693                 {0x8e7f, 0xbdd8},  {0x8f00, 0xc51c},  {0x8f7f, 0xd3e0},  {0x9000, 0xdb24},
2694                 {0x907f, 0xe9e8},  {0x9100, 0xf12c},  {0x917f, 0xfff0},  {0x9200, 0x10734},
2695                 {0x927f, 0x115f8}, {0x9300, 0x11d3c}, {0x937f, 0x12c00}, {0x9400, 0x13344},
2696                 {0x947f, 0x14208}, {0x9500, 0x1494c}, {0x957f, 0x15810}, {0x9600, 0x15f54},
2697                 {0x967f, 0x16e18}, {0x9700, 0x1755c}, {0x977f, 0x18420}, {0x9800, 0x18b64},
2698                 {0xffff, 0}
2699         };
2700
2701         if (a0 >= 0x8140 && a0 <= 0x84be) {
2702                 while (table_8140[i][0] <= a0) i++;
2703                 a0 -= table_8140[i - 1][0];
2704                 v0 = 0xbfc66000 + (a0 * 0x1e + table_8140[i - 1][1]);
2705         } else if (a0 >= 0x889f && a0 <= 0x9872) {
2706                 while (table_889f[i][0] <= a0) i++;
2707                 a0 -= table_889f[i - 1][0];
2708                 v0 = 0xbfc66000 + (a0 * 0x1e + table_889f[i - 1][1]);
2709         } else {
2710                 v0 = 0xffffffff;
2711         }
2712
2713         pc0 = ra;
2714 }
2715
2716 void psxBios_GetC0Table() { // 56
2717         PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x56]);
2718         log_unhandled("GetC0Table @%08x\n", ra);
2719
2720         mips_return_c(A_C0_TABLE, 3);
2721 }
2722
2723 void psxBios_GetB0Table() { // 57
2724         PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x57]);
2725         log_unhandled("GetB0Table @%08x\n", ra);
2726
2727         mips_return_c(A_B0_TABLE, 3);
2728 }
2729
2730 void psxBios__card_chan() { // 0x58
2731 #ifdef PSXBIOS_LOG
2732         PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x58]);
2733 #endif
2734
2735         v0 = card_active_chan;
2736         pc0 = ra;
2737 }
2738
2739 void psxBios_ChangeClearPad() { // 5b
2740 #ifdef PSXBIOS_LOG
2741         PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x5b], a0);
2742 #endif
2743
2744         pc0 = ra;
2745 }
2746
2747 void psxBios__card_status() { // 5c
2748 #ifdef PSXBIOS_LOG
2749         PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x5c], a0);
2750 #endif
2751
2752         v0 = card_active_chan;
2753         pc0 = ra;
2754 }
2755
2756 void psxBios__card_wait() { // 5d
2757 #ifdef PSXBIOS_LOG
2758         PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x5d], a0);
2759 #endif
2760
2761         v0 = 1;
2762         pc0 = ra;
2763 }
2764
2765 /* System calls C0 */
2766
2767 static void psxBios_SysEnqIntRP();
2768
2769 static void psxBios_InitRCnt() { // 00
2770         int i;
2771         PSXBIOS_LOG("psxBios_%s %x\n", biosC0n[0x00], a0);
2772         psxHwWrite16(0x1f801074, psxHu32(0x1074) & ~0x71);
2773         for (i = 0; i < 3; i++) {
2774                 psxHwWrite16(0x1f801100 + i*0x10 + 4, 0);
2775                 psxHwWrite16(0x1f801100 + i*0x10 + 8, 0);
2776                 psxHwWrite16(0x1f801100 + i*0x10 + 0, 0);
2777         }
2778         a1 = 0x6d88;
2779         psxBios_SysEnqIntRP();
2780         mips_return_c(0, 9);
2781 }
2782
2783 static void psxBios_InitException() { // 01
2784         PSXBIOS_LOG("psxBios_%s %x\n", biosC0n[0x01], a0);
2785         a1 = 0x6da8;
2786         psxBios_SysEnqIntRP();
2787         mips_return_c(0, 9);
2788 }
2789
2790 /*
2791  * int SysEnqIntRP(int index , long *queue);
2792  */
2793
2794 static void psxBios_SysEnqIntRP() { // 02
2795         u32 old, base = loadRam32(A_TT_ExCB);
2796         PSXBIOS_LOG("psxBios_%s %x %x\n", biosC0n[0x02], a0, a1);
2797
2798         old = loadRam32(base + (a0 << 3));
2799         storeRam32(base + (a0 << 3), a1);
2800         storeRam32(a1, old);
2801         mips_return_c(0, 9);
2802 }
2803
2804 /*
2805  * int SysDeqIntRP(int index , long *queue);
2806  */
2807
2808 static void psxBios_SysDeqIntRP_() { // 03
2809         u32 ptr, next, base = loadRam32(A_TT_ExCB);
2810         u32 lim = 0, ret = 0;
2811
2812         // as in original: no arg checks of any kind, bug if a1 == 0
2813         ptr = loadRam32(base + (a0 << 3));
2814         while (ptr) {
2815                 next = loadRam32(ptr);
2816                 if (ptr == a1) {
2817                         storeRam32(base + (a0 << 3), next);
2818                         ret = ptr;
2819                         use_cycles(6);
2820                         break;
2821                 }
2822                 while (next && next != a1 && lim++ < 100) {
2823                         ptr = next;
2824                         next = loadRam32(ptr);
2825                         use_cycles(8);
2826                 }
2827                 if (next == a1) {
2828                         next = loadRam32(next);
2829                         storeRam32(ptr, next);
2830                         ret = ptr;
2831                         use_cycles(6);
2832                 }
2833                 break;
2834         }
2835         if (lim == 100)
2836                 PSXBIOS_LOG("bad chain %u %x\n", a0, base);
2837
2838         mips_return_c(ret, 12);
2839 }
2840
2841 static void psxBios_SysDeqIntRP() { // 03
2842         PSXBIOS_LOG("psxBios_%s %x %x\n", biosC0n[0x03], a0, a1);
2843         psxBios_SysDeqIntRP_();
2844 }
2845
2846 static void psxBios_SysInitMemory_(u32 base, u32 size) {
2847         storeRam32(base, 0);
2848         storeRam32(A_KMALLOC_PTR, base);
2849         storeRam32(A_KMALLOC_SIZE, size);
2850         storeRam32(A_KMALLOC_END, base + (size & ~3) + 4);
2851 }
2852
2853 // this should be much more complicated, but maybe that'll be enough
2854 static u32 psxBios_SysMalloc_(u32 size) {
2855         u32 ptr = loadRam32(A_KMALLOC_PTR);
2856
2857         size = (size + 3) & ~3;
2858         storeRam32(A_KMALLOC_PTR, ptr + 4 + size);
2859         storeRam32(ptr, size);
2860         return ptr + 4;
2861 }
2862
2863 static void psxBios_SysInitMemory() { // 08
2864         PSXBIOS_LOG("psxBios_%s %x %x\n", biosC0n[0x08], a0, a1);
2865
2866         psxBios_SysInitMemory_(a0, a1);
2867         mips_return_void_c(12);
2868 }
2869
2870 static void psxBios_ChangeClearRCnt() { // 0a
2871         u32 ret;
2872
2873         PSXBIOS_LOG("psxBios_%s: %x, %x\n", biosC0n[0x0a], a0, a1);
2874
2875         ret = loadRam32(A_RCNT_VBL_ACK + (a0 << 2));
2876         storeRam32(A_RCNT_VBL_ACK + (a0 << 2), a1);
2877         mips_return_c(ret, 8);
2878 }
2879
2880 static void psxBios_InitDefInt() { // 0c
2881         PSXBIOS_LOG("psxBios_%s %x\n", biosC0n[0x0c], a0);
2882         // should also clear the autoack table
2883         a1 = 0x6d98;
2884         psxBios_SysEnqIntRP();
2885         mips_return_c(0, 20 + 6*2);
2886 }
2887
2888 void psxBios_dummy() {
2889         u32 pc = (pc0 & 0x1fffff) - 4;
2890         char **ntab = pc == 0xa0 ? biosA0n : pc == 0xb0 ? biosB0n
2891                 : pc == 0xc0 ? biosC0n : NULL;
2892         PSXBIOS_LOG("unk %x call: %x ra=%x (%s)\n",
2893                 pc, t1, ra, ntab ? ntab[t1 & 0xff] : "???");
2894         (void)pc; (void)ntab;
2895         mips_return_c(0, 100);
2896 }
2897
2898 void (*biosA0[256])();
2899 // C0 and B0 overlap (end of C0 is start of B0)
2900 void (*biosC0[256+128])();
2901 void (**biosB0)() = biosC0 + 128;
2902
2903 #include "sjisfont.h"
2904
2905 void setup_mips_code()
2906 {
2907         u32 *ptr;
2908         ptr = (u32 *)&psxM[A_SYSCALL];
2909         ptr[0x00/4] = SWAPu32(0x0000000c); // syscall 0
2910         ptr[0x04/4] = SWAPu32(0x03e00008); // jr    $ra
2911         ptr[0x08/4] = SWAPu32(0x00000000); // nop
2912
2913         ptr = (u32 *)&psxM[A_EXCEPTION];
2914         memset(ptr, 0, 0xc0);              // nops (to be patched by games sometimes)
2915         ptr[0x10/4] = SWAPu32(0x8c1a0108); // lw    $k0, (0x108)   // PCB
2916         ptr[0x14/4] = SWAPu32(0x00000000); // nop
2917         ptr[0x18/4] = SWAPu32(0x8f5a0000); // lw    $k0, ($k0)     // TCB
2918         ptr[0x1c/4] = SWAPu32(0x00000000); // nop
2919         ptr[0x20/4] = SWAPu32(0x275a0008); // addiu $k0, $k0, 8    // regs
2920         ptr[0x24/4] = SWAPu32(0xaf5f007c); // sw    $ra, 0x7c($k0)
2921         ptr[0x28/4] = SWAPu32(0xaf410004); // sw    $at, 0x04($k0)
2922         ptr[0x2c/4] = SWAPu32(0xaf420008); // sw    $v0, 0x08($k0)
2923         ptr[0x30/4] = SWAPu32(0xaf43000c); // sw    $v1, 0x0c($k0)
2924
2925         ptr[0x60/4] = SWAPu32(0x40037000); // mfc0  $v1, EPC
2926         ptr[0x64/4] = SWAPu32(0x40026800); // mfc0  $v0, Cause
2927         ptr[0x68/4] = SWAPu32(0x24630004); // addiu $v1, $v1, 4
2928         ptr[0x6c/4] = SWAPu32(0xaf430080); // sw    $v1, 0x80($k0)
2929
2930         ptr[0xb0/4] = HLEOP(hleop_exception);
2931 }
2932
2933 static const struct {
2934         u32 addr;
2935         enum hle_op op;
2936 } chainfns[] = {
2937         { 0xbfc050a4, hleop_exc0_0_1 },
2938         { 0xbfc04fbc, hleop_exc0_0_2 },
2939         { 0xbfc0506c, hleop_exc0_1_1 },
2940         { 0xbfc04dec, hleop_exc0_1_2 },
2941         {     0x1a00, hleop_exc0_2_2 },
2942         {     0x19c8, hleop_exc1_0_1 },
2943         {     0x18bc, hleop_exc1_0_2 },
2944         {     0x1990, hleop_exc1_1_1 },
2945         {     0x1858, hleop_exc1_1_2 },
2946         {     0x1958, hleop_exc1_2_1 },
2947         {     0x17f4, hleop_exc1_2_2 },
2948         {     0x1920, hleop_exc1_3_1 },
2949         {     0x1794, hleop_exc1_3_2 },
2950         {     0x2458, hleop_exc3_0_2 },
2951 };
2952
2953 static int chain_hle_op(u32 handler)
2954 {
2955         size_t i;
2956
2957         for (i = 0; i < sizeof(chainfns) / sizeof(chainfns[0]); i++)
2958                 if (chainfns[i].addr == handler)
2959                         return chainfns[i].op;
2960         return hleop_dummy;
2961 }
2962
2963 static void write_chain(u32 *d, u32 next, u32 handler1, u32 handler2)
2964 {
2965         d[0] = SWAPu32(next);
2966         d[1] = SWAPu32(handler1);
2967         d[2] = SWAPu32(handler2);
2968
2969         // install hle traps
2970         PSXMu32ref(handler1) = HLEOP(chain_hle_op(handler1));
2971         PSXMu32ref(handler2) = HLEOP(chain_hle_op(handler2));
2972 }
2973
2974 static void setup_tt(u32 tcb_cnt, u32 evcb_cnt)
2975 {
2976         u32 *ram32 = (u32 *)psxM;
2977         u32 s_excb = 0x20, s_evcb = 0x1c * evcb_cnt;
2978         u32 s_pcb = 4, s_tcb = 0xc0 * tcb_cnt;
2979         u32 p_excb, p_evcb, p_pcb, p_tcb;
2980
2981         memset(ram32 + 0xe000/4, 0, s_excb + s_evcb + s_pcb + s_tcb + 5*4);
2982         psxBios_SysInitMemory_(0xa000e000, 0x2000);
2983         p_excb = psxBios_SysMalloc_(s_excb);
2984         p_evcb = psxBios_SysMalloc_(s_evcb);
2985         p_pcb  = psxBios_SysMalloc_(s_pcb);
2986         p_tcb  = psxBios_SysMalloc_(s_tcb);
2987
2988         // "table of tables". Some games modify it
2989         assert(A_TT_ExCB == 0x0100);
2990         ram32[0x0100/4] = SWAPu32(p_excb);  // ExCB - exception chains
2991         ram32[0x0104/4] = SWAPu32(s_excb);  // ExCB size
2992         ram32[0x0108/4] = SWAPu32(p_pcb);   // PCB - process control
2993         ram32[0x010c/4] = SWAPu32(s_pcb);   // PCB size
2994         ram32[0x0110/4] = SWAPu32(p_tcb);   // TCB - thread control
2995         ram32[0x0114/4] = SWAPu32(s_tcb);   // TCB size
2996         ram32[0x0120/4] = SWAPu32(p_evcb);  // EvCB - event control
2997         ram32[0x0124/4] = SWAPu32(s_evcb);  // EvCB size
2998         ram32[0x0140/4] = SWAPu32(0x8648);  // FCB - file control
2999         ram32[0x0144/4] = SWAPu32(0x02c0);  // FCB size
3000         ram32[0x0150/4] = SWAPu32(0x6ee0);  // DCB - device control
3001         ram32[0x0154/4] = SWAPu32(0x0320);  // DCB size
3002
3003         storeRam32(p_excb + 0*4, 0x91e0);   // chain0
3004         storeRam32(p_excb + 2*4, 0x6d88);   // chain1
3005         storeRam32(p_excb + 4*4, 0x0000);   // chain2
3006         storeRam32(p_excb + 6*4, 0x6d98);   // chain3
3007
3008         storeRam32(p_pcb, p_tcb);
3009         storeRam32(p_tcb, 0x4000);          // first TCB
3010 }
3011
3012 void psxBiosInit() {
3013         u32 base, size;
3014         u32 *ptr, *ram32;
3015         int i;
3016         uLongf len;
3017
3018         memset(psxM, 0, 0x10000);
3019         for(i = 0; i < 256; i++) {
3020                 biosA0[i] = NULL;
3021                 biosB0[i] = NULL;
3022                 biosC0[i] = NULL;
3023         }
3024         biosA0[0x03] = biosB0[0x35] = psxBios_write_psxout;
3025         biosA0[0x3c] = biosB0[0x3d] = psxBios_putchar_psxout;
3026         biosA0[0x3e] = biosB0[0x3f] = psxBios_puts_psxout;
3027         biosA0[0x3f] = psxBios_printf_psxout;
3028
3029         if (!Config.HLE) return;
3030
3031         for(i = 0; i < 256; i++) {
3032                 if (biosA0[i] == NULL) biosA0[i] = psxBios_dummy;
3033                 if (biosB0[i] == NULL) biosB0[i] = psxBios_dummy;
3034                 if (biosC0[i] == NULL) biosC0[i] = psxBios_dummy;
3035         }
3036
3037         biosA0[0x00] = psxBios_open;
3038         biosA0[0x01] = psxBios_lseek;
3039         biosA0[0x02] = psxBios_read;
3040         biosA0[0x03] = psxBios_write;
3041         biosA0[0x04] = psxBios_close;
3042         //biosA0[0x05] = psxBios_ioctl;
3043         //biosA0[0x06] = psxBios_exit;
3044         //biosA0[0x07] = psxBios_sys_a0_07;
3045         biosA0[0x08] = psxBios_getc;
3046         biosA0[0x09] = psxBios_putc;
3047         biosA0[0x0a] = psxBios_todigit;
3048         //biosA0[0x0b] = psxBios_atof;
3049         //biosA0[0x0c] = psxBios_strtoul;
3050         //biosA0[0x0d] = psxBios_strtol;
3051         biosA0[0x0e] = psxBios_abs;
3052         biosA0[0x0f] = psxBios_labs;
3053         biosA0[0x10] = psxBios_atoi;
3054         biosA0[0x11] = psxBios_atol;
3055         //biosA0[0x12] = psxBios_atob;
3056         biosA0[0x13] = psxBios_setjmp;
3057         biosA0[0x14] = psxBios_longjmp;
3058         biosA0[0x15] = psxBios_strcat;
3059         biosA0[0x16] = psxBios_strncat;
3060         biosA0[0x17] = psxBios_strcmp;
3061         biosA0[0x18] = psxBios_strncmp;
3062         biosA0[0x19] = psxBios_strcpy;
3063         biosA0[0x1a] = psxBios_strncpy;
3064         biosA0[0x1b] = psxBios_strlen;
3065         biosA0[0x1c] = psxBios_index;
3066         biosA0[0x1d] = psxBios_rindex;
3067         biosA0[0x1e] = psxBios_strchr;
3068         biosA0[0x1f] = psxBios_strrchr;
3069         biosA0[0x20] = psxBios_strpbrk;
3070         biosA0[0x21] = psxBios_strspn;
3071         biosA0[0x22] = psxBios_strcspn;
3072         biosA0[0x23] = psxBios_strtok;
3073         biosA0[0x24] = psxBios_strstr;
3074         biosA0[0x25] = psxBios_toupper;
3075         biosA0[0x26] = psxBios_tolower;
3076         biosA0[0x27] = psxBios_bcopy;
3077         biosA0[0x28] = psxBios_bzero;
3078         biosA0[0x29] = psxBios_bcmp;
3079         biosA0[0x2a] = psxBios_memcpy;
3080         biosA0[0x2b] = psxBios_memset;
3081         biosA0[0x2c] = psxBios_memmove;
3082         biosA0[0x2d] = psxBios_memcmp;
3083         biosA0[0x2e] = psxBios_memchr;
3084         biosA0[0x2f] = psxBios_rand;
3085         biosA0[0x30] = psxBios_srand;
3086         biosA0[0x31] = psxBios_qsort;
3087         //biosA0[0x32] = psxBios_strtod;
3088         biosA0[0x33] = psxBios_malloc;
3089         biosA0[0x34] = psxBios_free;
3090         //biosA0[0x35] = psxBios_lsearch;
3091         //biosA0[0x36] = psxBios_bsearch;
3092         biosA0[0x37] = psxBios_calloc;
3093         biosA0[0x38] = psxBios_realloc;
3094         biosA0[0x39] = psxBios_InitHeap;
3095         //biosA0[0x3a] = psxBios__exit;
3096         biosA0[0x3b] = psxBios_getchar;
3097         biosA0[0x3c] = psxBios_putchar;
3098         //biosA0[0x3d] = psxBios_gets;
3099         biosA0[0x40] = psxBios_SystemErrorUnresolvedException;
3100         //biosA0[0x41] = psxBios_LoadTest;
3101         biosA0[0x42] = psxBios_Load;
3102         biosA0[0x43] = psxBios_Exec;
3103         biosA0[0x44] = psxBios_FlushCache;
3104         //biosA0[0x45] = psxBios_InstallInterruptHandler;
3105         biosA0[0x46] = psxBios_GPU_dw;
3106         biosA0[0x47] = psxBios_mem2vram;
3107         biosA0[0x48] = psxBios_SendGPU;
3108         biosA0[0x49] = psxBios_GPU_cw;
3109         biosA0[0x4a] = psxBios_GPU_cwb;
3110         biosA0[0x4b] = psxBios_GPU_SendPackets;
3111         biosA0[0x4c] = psxBios_sys_a0_4c;
3112         biosA0[0x4d] = psxBios_GPU_GetGPUStatus;
3113         //biosA0[0x4e] = psxBios_GPU_sync;
3114         //biosA0[0x4f] = psxBios_sys_a0_4f;
3115         //biosA0[0x50] = psxBios_sys_a0_50;
3116         biosA0[0x51] = psxBios_LoadExec;
3117         //biosA0[0x52] = psxBios_GetSysSp;
3118         //biosA0[0x53] = psxBios_sys_a0_53;
3119         //biosA0[0x54] = psxBios__96_init_a54;
3120         //biosA0[0x55] = psxBios__bu_init_a55;
3121         biosA0[0x56] = psxBios_CdRemove;
3122         //biosA0[0x57] = psxBios_sys_a0_57;
3123         //biosA0[0x58] = psxBios_sys_a0_58;
3124         //biosA0[0x59] = psxBios_sys_a0_59;
3125         //biosA0[0x5a] = psxBios_sys_a0_5a;
3126         //biosA0[0x5b] = psxBios_dev_tty_init;
3127         //biosA0[0x5c] = psxBios_dev_tty_open;
3128         //biosA0[0x5d] = psxBios_sys_a0_5d;
3129         //biosA0[0x5e] = psxBios_dev_tty_ioctl;
3130         //biosA0[0x5f] = psxBios_dev_cd_open;
3131         //biosA0[0x60] = psxBios_dev_cd_read;
3132         //biosA0[0x61] = psxBios_dev_cd_close;
3133         //biosA0[0x62] = psxBios_dev_cd_firstfile;
3134         //biosA0[0x63] = psxBios_dev_cd_nextfile;
3135         //biosA0[0x64] = psxBios_dev_cd_chdir;
3136         //biosA0[0x65] = psxBios_dev_card_open;
3137         //biosA0[0x66] = psxBios_dev_card_read;
3138         //biosA0[0x67] = psxBios_dev_card_write;
3139         //biosA0[0x68] = psxBios_dev_card_close;
3140         //biosA0[0x69] = psxBios_dev_card_firstfile;
3141         //biosA0[0x6a] = psxBios_dev_card_nextfile;
3142         //biosA0[0x6b] = psxBios_dev_card_erase;
3143         //biosA0[0x6c] = psxBios_dev_card_undelete;
3144         //biosA0[0x6d] = psxBios_dev_card_format;
3145         //biosA0[0x6e] = psxBios_dev_card_rename;
3146         //biosA0[0x6f] = psxBios_dev_card_6f;
3147         biosA0[0x70] = psxBios__bu_init;
3148         biosA0[0x71] = psxBios__96_init;
3149         biosA0[0x72] = psxBios_CdRemove;
3150         //biosA0[0x73] = psxBios_sys_a0_73;
3151         //biosA0[0x74] = psxBios_sys_a0_74;
3152         //biosA0[0x75] = psxBios_sys_a0_75;
3153         //biosA0[0x76] = psxBios_sys_a0_76;
3154         //biosA0[0x77] = psxBios_sys_a0_77;
3155         //biosA0[0x78] = psxBios__96_CdSeekL;
3156         //biosA0[0x79] = psxBios_sys_a0_79;
3157         //biosA0[0x7a] = psxBios_sys_a0_7a;
3158         //biosA0[0x7b] = psxBios_sys_a0_7b;
3159         //biosA0[0x7c] = psxBios__96_CdGetStatus;
3160         //biosA0[0x7d] = psxBios_sys_a0_7d;
3161         //biosA0[0x7e] = psxBios__96_CdRead;
3162         //biosA0[0x7f] = psxBios_sys_a0_7f;
3163         //biosA0[0x80] = psxBios_sys_a0_80;
3164         //biosA0[0x81] = psxBios_sys_a0_81;
3165         //biosA0[0x82] = psxBios_sys_a0_82;
3166         //biosA0[0x83] = psxBios_sys_a0_83;
3167         //biosA0[0x84] = psxBios_sys_a0_84;
3168         //biosA0[0x85] = psxBios__96_CdStop;
3169         //biosA0[0x86] = psxBios_sys_a0_86;
3170         //biosA0[0x87] = psxBios_sys_a0_87;
3171         //biosA0[0x88] = psxBios_sys_a0_88;
3172         //biosA0[0x89] = psxBios_sys_a0_89;
3173         //biosA0[0x8a] = psxBios_sys_a0_8a;
3174         //biosA0[0x8b] = psxBios_sys_a0_8b;
3175         //biosA0[0x8c] = psxBios_sys_a0_8c;
3176         //biosA0[0x8d] = psxBios_sys_a0_8d;
3177         //biosA0[0x8e] = psxBios_sys_a0_8e;
3178         //biosA0[0x8f] = psxBios_sys_a0_8f;
3179         biosA0[0x90] = hleExc0_1_2;
3180         biosA0[0x91] = hleExc0_0_2;
3181         biosA0[0x92] = hleExc0_1_1;
3182         biosA0[0x93] = hleExc0_0_1;
3183         //biosA0[0x94] = psxBios_sys_a0_94;
3184         //biosA0[0x95] = psxBios_sys_a0_95;
3185         //biosA0[0x96] = psxBios_AddCDROMDevice;
3186         //biosA0[0x97] = psxBios_AddMemCardDevide;
3187         //biosA0[0x98] = psxBios_DisableKernelIORedirection;
3188         //biosA0[0x99] = psxBios_EnableKernelIORedirection;
3189         //biosA0[0x9a] = psxBios_sys_a0_9a;
3190         //biosA0[0x9b] = psxBios_sys_a0_9b;
3191         //biosA0[0x9c] = psxBios_SetConf;
3192         //biosA0[0x9d] = psxBios_GetConf;
3193         //biosA0[0x9e] = psxBios_sys_a0_9e;
3194         biosA0[0x9f] = psxBios_SetMem;
3195         //biosA0[0xa0] = psxBios__boot;
3196         //biosA0[0xa1] = psxBios_SystemError;
3197         //biosA0[0xa2] = psxBios_EnqueueCdIntr;
3198         biosA0[0xa3] = psxBios_DequeueCdIntr;
3199         //biosA0[0xa4] = psxBios_sys_a0_a4;
3200         //biosA0[0xa5] = psxBios_ReadSector;
3201         biosA0[0xa6] = psxBios_get_cd_status;
3202         //biosA0[0xa7] = psxBios_bufs_cb_0;
3203         //biosA0[0xa8] = psxBios_bufs_cb_1;
3204         //biosA0[0xa9] = psxBios_bufs_cb_2;
3205         //biosA0[0xaa] = psxBios_bufs_cb_3;
3206         biosA0[0xab] = psxBios__card_info;
3207         biosA0[0xac] = psxBios__card_load;
3208         //biosA0[0axd] = psxBios__card_auto;
3209         //biosA0[0xae] = psxBios_bufs_cd_4;
3210         //biosA0[0xaf] = psxBios_sys_a0_af;
3211         //biosA0[0xb0] = psxBios_sys_a0_b0;
3212         //biosA0[0xb1] = psxBios_sys_a0_b1;
3213         //biosA0[0xb2] = psxBios_do_a_long_jmp
3214         //biosA0[0xb3] = psxBios_sys_a0_b3;
3215         //biosA0[0xb4] = psxBios_sub_function;
3216 //*******************B0 CALLS****************************
3217         biosB0[0x00] = psxBios_SysMalloc;
3218         //biosB0[0x01] = psxBios_sys_b0_01;
3219         biosB0[0x02] = psxBios_SetRCnt;
3220         biosB0[0x03] = psxBios_GetRCnt;
3221         biosB0[0x04] = psxBios_StartRCnt;
3222         biosB0[0x05] = psxBios_StopRCnt;
3223         biosB0[0x06] = psxBios_ResetRCnt;
3224         biosB0[0x07] = psxBios_DeliverEvent;
3225         biosB0[0x08] = psxBios_OpenEvent;
3226         biosB0[0x09] = psxBios_CloseEvent;
3227         biosB0[0x0a] = psxBios_WaitEvent;
3228         biosB0[0x0b] = psxBios_TestEvent;
3229         biosB0[0x0c] = psxBios_EnableEvent;
3230         biosB0[0x0d] = psxBios_DisableEvent;
3231         biosB0[0x0e] = psxBios_OpenTh;
3232         biosB0[0x0f] = psxBios_CloseTh;
3233         biosB0[0x10] = psxBios_ChangeTh;
3234         //biosB0[0x11] = psxBios_psxBios_b0_11;
3235         biosB0[0x12] = psxBios_InitPAD;
3236         biosB0[0x13] = psxBios_StartPAD;
3237         biosB0[0x14] = psxBios_StopPAD;
3238         biosB0[0x15] = psxBios_PAD_init;
3239         biosB0[0x16] = psxBios_PAD_dr;
3240         biosB0[0x17] = psxBios_ReturnFromException;
3241         biosB0[0x18] = psxBios_ResetEntryInt;
3242         biosB0[0x19] = psxBios_HookEntryInt;
3243         //biosB0[0x1a] = psxBios_sys_b0_1a;
3244         //biosB0[0x1b] = psxBios_sys_b0_1b;
3245         //biosB0[0x1c] = psxBios_sys_b0_1c;
3246         //biosB0[0x1d] = psxBios_sys_b0_1d;
3247         //biosB0[0x1e] = psxBios_sys_b0_1e;
3248         //biosB0[0x1f] = psxBios_sys_b0_1f;
3249         biosB0[0x20] = psxBios_UnDeliverEvent;
3250         //biosB0[0x21] = psxBios_sys_b0_21;
3251         //biosB0[0x22] = psxBios_sys_b0_22;
3252         //biosB0[0x23] = psxBios_sys_b0_23;
3253         //biosB0[0x24] = psxBios_sys_b0_24;
3254         //biosB0[0x25] = psxBios_sys_b0_25;
3255         //biosB0[0x26] = psxBios_sys_b0_26;
3256         //biosB0[0x27] = psxBios_sys_b0_27;
3257         //biosB0[0x28] = psxBios_sys_b0_28;
3258         //biosB0[0x29] = psxBios_sys_b0_29;
3259         //biosB0[0x2a] = psxBios_sys_b0_2a;
3260         //biosB0[0x2b] = psxBios_sys_b0_2b;
3261         //biosB0[0x2c] = psxBios_sys_b0_2c;
3262         //biosB0[0x2d] = psxBios_sys_b0_2d;
3263         //biosB0[0x2e] = psxBios_sys_b0_2e;
3264         //biosB0[0x2f] = psxBios_sys_b0_2f;
3265         //biosB0[0x30] = psxBios_sys_b0_30;
3266         //biosB0[0x31] = psxBios_sys_b0_31;
3267         biosB0[0x32] = psxBios_open;
3268         biosB0[0x33] = psxBios_lseek;
3269         biosB0[0x34] = psxBios_read;
3270         biosB0[0x35] = psxBios_write;
3271         biosB0[0x36] = psxBios_close;
3272         //biosB0[0x37] = psxBios_ioctl;
3273         //biosB0[0x38] = psxBios_exit;
3274         //biosB0[0x39] = psxBios_sys_b0_39;
3275         //biosB0[0x3a] = psxBios_getc;
3276         //biosB0[0x3b] = psxBios_putc;
3277         biosB0[0x3c] = psxBios_getchar;
3278         //biosB0[0x3e] = psxBios_gets;
3279         //biosB0[0x40] = psxBios_cd;
3280         biosB0[0x41] = psxBios_format;
3281         biosB0[0x42] = psxBios_firstfile;
3282         biosB0[0x43] = psxBios_nextfile;
3283         biosB0[0x44] = psxBios_rename;
3284         biosB0[0x45] = psxBios_delete;
3285         //biosB0[0x46] = psxBios_undelete;
3286         //biosB0[0x47] = psxBios_AddDevice;
3287         //biosB0[0x48] = psxBios_RemoteDevice;
3288         //biosB0[0x49] = psxBios_PrintInstalledDevices;
3289         biosB0[0x4a] = psxBios_InitCARD;
3290         biosB0[0x4b] = psxBios_StartCARD;
3291         biosB0[0x4c] = psxBios_StopCARD;
3292         //biosB0[0x4d] = psxBios_sys_b0_4d;
3293         biosB0[0x4e] = psxBios__card_write;
3294         biosB0[0x4f] = psxBios__card_read;
3295         biosB0[0x50] = psxBios__new_card;
3296         biosB0[0x51] = psxBios_Krom2RawAdd;
3297         //biosB0[0x52] = psxBios_sys_b0_52;
3298         //biosB0[0x53] = psxBios_sys_b0_53;
3299         //biosB0[0x54] = psxBios__get_errno;
3300         biosB0[0x55] = psxBios__get_error;
3301         biosB0[0x56] = psxBios_GetC0Table;
3302         biosB0[0x57] = psxBios_GetB0Table;
3303         biosB0[0x58] = psxBios__card_chan;
3304         //biosB0[0x59] = psxBios_sys_b0_59;
3305         //biosB0[0x5a] = psxBios_sys_b0_5a;
3306         biosB0[0x5b] = psxBios_ChangeClearPad;
3307         biosB0[0x5c] = psxBios__card_status;
3308         biosB0[0x5d] = psxBios__card_wait;
3309 //*******************C0 CALLS****************************
3310         biosC0[0x00] = psxBios_InitRCnt;
3311         biosC0[0x01] = psxBios_InitException;
3312         biosC0[0x02] = psxBios_SysEnqIntRP;
3313         biosC0[0x03] = psxBios_SysDeqIntRP;
3314         //biosC0[0x04] = psxBios_get_free_EvCB_slot;
3315         //biosC0[0x05] = psxBios_get_free_TCB_slot;
3316         //biosC0[0x06] = psxBios_ExceptionHandler;
3317         //biosC0[0x07] = psxBios_InstallExeptionHandler;
3318         biosC0[0x08] = psxBios_SysInitMemory;
3319         //biosC0[0x09] = psxBios_SysInitKMem;
3320         biosC0[0x0a] = psxBios_ChangeClearRCnt;
3321         //biosC0[0x0b] = psxBios_SystemError;
3322         biosC0[0x0c] = psxBios_InitDefInt;
3323         //biosC0[0x0d] = psxBios_sys_c0_0d;
3324         //biosC0[0x0e] = psxBios_sys_c0_0e;
3325         //biosC0[0x0f] = psxBios_sys_c0_0f;
3326         //biosC0[0x10] = psxBios_sys_c0_10;
3327         //biosC0[0x11] = psxBios_sys_c0_11;
3328         //biosC0[0x12] = psxBios_InstallDevices;
3329         //biosC0[0x13] = psxBios_FlushStfInOutPut;
3330         //biosC0[0x14] = psxBios_sys_c0_14;
3331         //biosC0[0x15] = psxBios__cdevinput;
3332         //biosC0[0x16] = psxBios__cdevscan;
3333         //biosC0[0x17] = psxBios__circgetc;
3334         //biosC0[0x18] = psxBios__circputc;
3335         //biosC0[0x19] = psxBios_ioabort;
3336         //biosC0[0x1a] = psxBios_sys_c0_1a
3337         //biosC0[0x1b] = psxBios_KernelRedirect;
3338         //biosC0[0x1c] = psxBios_PatchAOTable;
3339 //************** THE END ***************************************
3340 /**/
3341         base = 0x1000;
3342         size = sizeof(EvCB) * 32;
3343         EventCB = (void *)&psxR[base]; base += size * 6;
3344         memset(EventCB, 0, size * 6);
3345         HwEV = EventCB;
3346         EvEV = EventCB + 32;
3347         RcEV = EventCB + 32 * 2;
3348         UeEV = EventCB + 32 * 3;
3349         SwEV = EventCB + 32 * 4;
3350         ThEV = EventCB + 32 * 5;
3351
3352         pad_stopped = 1;
3353         pad_buf = NULL;
3354         pad_buf1 = NULL;
3355         pad_buf2 = NULL;
3356         pad_buf1len = pad_buf2len = 0;
3357         heap_addr = NULL;
3358         heap_end = NULL;
3359         heap_size = 0;
3360         CardState = -1;
3361         CurThread = 0;
3362         memset(FDesc, 0, sizeof(FDesc));
3363         card_active_chan = 0;
3364
3365         // initial RNG seed
3366         psxMu32ref(0x9010) = SWAPu32(0xac20cc00);
3367
3368         // fonts
3369         len = 0x80000 - 0x66000;
3370         uncompress((Bytef *)(psxR + 0x66000), &len, font_8140, sizeof(font_8140));
3371         len = 0x80000 - 0x69d68;
3372         uncompress((Bytef *)(psxR + 0x69d68), &len, font_889f, sizeof(font_889f));
3373
3374         // memory size 2 MB
3375         psxHu32ref(0x1060) = SWAPu32(0x00000b88);
3376
3377         /*      Some games like R-Types, CTR, Fade to Black read from adress 0x00000000 due to uninitialized pointers.
3378                 See Garbage Area at Address 00000000h in Nocash PSX Specfications for more information.
3379                 Here are some examples of games not working with this fix in place :
3380                 R-type won't get past the Irem logo if not implemented.
3381                 Crash Team Racing will softlock after the Sony logo.
3382         */
3383
3384         ram32 = (u32 *)psxM;
3385         ram32[0x0000/4] = SWAPu32(0x00000003); // lui   $k0, 0  (overwritten by 3)
3386         ram32[0x0004/4] = SWAPu32(0x275a0000 + A_EXCEPTION); // addiu $k0, $k0, 0xc80
3387         ram32[0x0008/4] = SWAPu32(0x03400008); // jr    $k0
3388         ram32[0x000c/4] = SWAPu32(0x00000000); // nop
3389
3390         ram32[0x0060/4] = SWAPu32(0x00000002); // ram size?
3391         ram32[0x0068/4] = SWAPu32(0x000000ff); // unknown
3392
3393         ram32[0x0080/4] = SWAPu32(0x3c1a0000); // lui   $k0, 0  // exception vector
3394         ram32[0x0084/4] = SWAPu32(0x275a0000 + A_EXCEPTION); // addiu $k0, $k0, 0xc80
3395         ram32[0x0088/4] = SWAPu32(0x03400008); // jr    $k0
3396         ram32[0x008c/4] = SWAPu32(0x00000000); // nop
3397
3398         ram32[0x00a0/4] = HLEOP(hleop_a0);
3399         ram32[0x00b0/4] = HLEOP(hleop_b0);
3400         ram32[0x00c0/4] = HLEOP(hleop_c0);
3401
3402         setup_tt(4, 16);
3403
3404         ram32[0x6ee0/4] = SWAPu32(0x0000eff0); // DCB
3405         strcpy((char *)&ram32[0xeff0/4], "bu");
3406
3407         // default exception handler chains
3408         write_chain(&ram32[0x91e0/4], 0x91d0, 0xbfc050a4, 0xbfc04fbc); // chain0.e0
3409         write_chain(&ram32[0x91d0/4], 0x6da8, 0xbfc0506c, 0xbfc04dec); // chain0.e1
3410         write_chain(&ram32[0x6da8/4],      0,          0,     0x1a00); // chain0.e2
3411         write_chain(&ram32[0x6d88/4], 0x6d78,     0x19c8,     0x18bc); // chain1.e0
3412         write_chain(&ram32[0x6d78/4], 0x6d68,     0x1990,     0x1858); // chain1.e1
3413         write_chain(&ram32[0x6d68/4], 0x6d58,     0x1958,     0x17f4); // chain1.e2
3414         write_chain(&ram32[0x6d58/4],      0,     0x1920,     0x1794); // chain1.e3
3415         write_chain(&ram32[0x6d98/4],      0,          0,     0x2458); // chain3.e0
3416
3417         setup_mips_code();
3418
3419         // fill the api jumptables with fake entries as some games patch them
3420         // (or rather the funcs listed there)
3421         ptr = (u32 *)&psxM[A_A0_TABLE];
3422         for (i = 0; i < 256; i++)
3423                 ptr[i] = SWAP32(0x1000);
3424
3425         ptr = (u32 *)&psxM[A_B0_TABLE];
3426         for (i = 0; i < 256; i++)
3427                 ptr[i] = SWAP32(0x2000);
3428         // B(5b) is special because games patch (sometimes even jump to)
3429         // code at fixed offsets from it, nocash lists offsets:
3430         //  patch: +3d8, +4dc, +594, +62c, +9c8, +1988
3431         //  call:  +7a0=4b70, +884=4c54, +894=4c64
3432         ptr[0x5b] = SWAP32(0x43d0);
3433         ram32[0x4b70/4] = SWAP32(0x03e00008); // jr $ra
3434         ram32[0x4c54/4] = SWAP32(0x03e00008); // jr $ra
3435         ram32[0x4c64/4] = SWAP32(0x03e00008); // jr $ra
3436
3437         ptr = (u32 *)&psxM[A_C0_TABLE];
3438         for (i = 0; i < 256/2; i++)
3439                 ptr[i] = SWAP32(0x3000);
3440         ptr[6] = SWAP32(A_EXCEPTION);
3441
3442         // more HLE traps
3443         ram32[0x1000/4] = HLEOP(hleop_dummy);
3444         ram32[0x2000/4] = HLEOP(hleop_dummy);
3445         ram32[0x3000/4] = HLEOP(hleop_dummy);
3446         ram32[0x4c54/4] = HLEOP(hleop_dummy);   // for B12_InitPad?
3447         ram32[0x8000/4] = HLEOP(hleop_execret);
3448
3449         ram32[A_EEXIT_PTR/4] = SWAP32(A_EEXIT_DEF);
3450         ram32[A_EXC_SP/4] = SWAP32(A_EXC_STACK);
3451         ram32[A_RCNT_VBL_ACK/4 + 0] = SWAP32(1);
3452         ram32[A_RCNT_VBL_ACK/4 + 1] = SWAP32(1);
3453         ram32[A_RCNT_VBL_ACK/4 + 2] = SWAP32(1);
3454         ram32[A_RCNT_VBL_ACK/4 + 3] = SWAP32(1);
3455 }
3456
3457 void psxBiosShutdown() {
3458 }
3459
3460 void psxBiosCnfLoaded(u32 tcb_cnt, u32 evcb_cnt) {
3461         if (tcb_cnt != 4 || evcb_cnt != 16)
3462                 setup_tt(tcb_cnt, evcb_cnt);
3463 }
3464
3465 #define psxBios_PADpoll(pad) { \
3466         PAD##pad##_startPoll(pad); \
3467         pad_buf##pad[0] = 0; \
3468         pad_buf##pad[1] = PAD##pad##_poll(0x42); \
3469         if (!(pad_buf##pad[1] & 0x0f)) { \
3470                 bufcount = 32; \
3471         } else { \
3472                 bufcount = (pad_buf##pad[1] & 0x0f) * 2; \
3473         } \
3474         PAD##pad##_poll(0); \
3475         i = 2; \
3476         while (bufcount--) { \
3477                 pad_buf##pad[i++] = PAD##pad##_poll(0); \
3478         } \
3479 }
3480
3481 static void biosPadHLE() {
3482         int i, bufcount;
3483
3484         if (pad_buf != NULL) {
3485                 u32 *buf = (u32*)pad_buf;
3486
3487                 PAD1_startPoll(1);
3488                 if (PAD1_poll(0x42) == 0x23) {
3489                         PAD1_poll(0);
3490                         *buf = PAD1_poll(0) << 8;
3491                         *buf |= PAD1_poll(0);
3492                         PAD1_poll(0);
3493                         *buf &= ~((PAD1_poll(0) > 0x20) ? 1 << 6 : 0);
3494                         *buf &= ~((PAD1_poll(0) > 0x20) ? 1 << 7 : 0);
3495                 } else {
3496                         PAD1_poll(0);
3497                         *buf = PAD1_poll(0) << 8;
3498                         *buf|= PAD1_poll(0);
3499                 }
3500
3501                 PAD2_startPoll(2);
3502                 if (PAD2_poll(0x42) == 0x23) {
3503                         PAD2_poll(0);
3504                         *buf |= PAD2_poll(0) << 24;
3505                         *buf |= PAD2_poll(0) << 16;
3506                         PAD2_poll(0);
3507                         *buf &= ~((PAD2_poll(0) > 0x20) ? 1 << 22 : 0);
3508                         *buf &= ~((PAD2_poll(0) > 0x20) ? 1 << 23 : 0);
3509                 } else {
3510                         PAD2_poll(0);
3511                         *buf |= PAD2_poll(0) << 24;
3512                         *buf |= PAD2_poll(0) << 16;
3513                 }
3514         }
3515         if (!pad_stopped)  {
3516                 if (pad_buf1) {
3517                         psxBios_PADpoll(1);
3518                 }
3519
3520                 if (pad_buf2) {
3521                         psxBios_PADpoll(2);
3522                 }
3523         }
3524 }
3525
3526 static void handle_chain_x_x_1(u32 enable, u32 irqbit)
3527 {
3528         use_cycles(10);
3529         if (enable) {
3530                 psxHwWrite16(0x1f801070, ~(1u << irqbit));
3531                 psxBios_ReturnFromException();
3532         }
3533         else
3534                 pc0 = ra;
3535 }
3536
3537 // hleExc0_{0,1}* are usually removed by A(56)/A(72) on the game's startup,
3538 // so this is only partially implemented
3539 void hleExc0_0_1() // A(93h) - CdromDmaIrqFunc2
3540 {
3541         u32 cdrom_dma_ack_enable = 1; // a000b93c
3542         handle_chain_x_x_1(cdrom_dma_ack_enable, 3); // IRQ3 DMA
3543 }
3544
3545 void hleExc0_0_2() // A(91h) - CdromDmaIrqFunc1
3546 {
3547         u32 ret = 0;
3548         //PSXBIOS_LOG("%s\n", __func__);
3549
3550         if (psxHu32(0x1074) & psxHu32(0x1070) & 8) { // IRQ3 DMA
3551                 psxHwWrite32(0x1f8010f4, (psxHu32(0x10f4) & 0xffffff) | 0x88000000);
3552                 //if (--cdrom_irq_counter == 0) // 0xa0009180
3553                 //      DeliverEvent();         // 0xf0000003, 0x10
3554                 use_cycles(22);
3555                 ret = 1;
3556         }
3557         mips_return_c(ret, 20);
3558 }
3559
3560 void hleExc0_1_1() // A(92h) - CdromIoIrqFunc2
3561 {
3562         u32 cdrom_irq_ack_enable = 1; // a000b938
3563         handle_chain_x_x_1(cdrom_irq_ack_enable, 2); // IRQ2 cdrom
3564 }
3565
3566 void hleExc0_1_2() // A(90h) - CdromIoIrqFunc1
3567 {
3568         u32 ret = 0;
3569         if (psxHu32(0x1074) & psxHu32(0x1070) & 4) { // IRQ2 cdrom
3570                 PSXBIOS_LOG("%s TODO\n", __func__);
3571                 ret = 1;
3572         }
3573         mips_return_c(ret, 20);
3574 }
3575
3576 void hleExc0_2_2_syscall() // not in any A/B/C table
3577 {
3578         u32 code = (psxRegs.CP0.n.Cause & 0x3c) >> 2;
3579         u32 tcbPtr = loadRam32(A_TT_PCB);
3580         TCB *tcb = loadRam32ptr(tcbPtr);
3581
3582         if (code != R3000E_Syscall) {
3583                 if (code != 0) {
3584                         // DeliverEvent(); // 0xf0000010, 0x1000
3585                         psxBios_SystemErrorUnresolvedException();
3586                 }
3587                 mips_return_c(0, 17);
3588                 return;
3589         }
3590
3591         //printf("%s c=%d a0=%d\n", __func__, code, a0);
3592         tcb->epc += SWAP32(4);
3593         switch (a0) {
3594                 case 0: // noop
3595                         break;
3596
3597                 case 1: { // EnterCritical - disable irqs
3598                         u32 was_enabled = ((SWAP32(tcb->sr) & 0x404) == 0x404);
3599                         tcb->reg[2] = SWAP32(was_enabled);
3600                         tcb->sr &= SWAP32(~0x404);
3601                         break;
3602                 }
3603                 case 2: // ExitCritical - enable irqs
3604                         tcb->sr |= SWAP32(0x404);
3605                         break;
3606
3607                 case 3: { // ChangeThreadSubFunction
3608                         u32 tcbPtr = loadRam32(A_TT_PCB);
3609                         storeRam32(tcbPtr, a1);
3610                         break;
3611                 }
3612                 default:
3613                         // DeliverEvent(); // 0xf0000010, 0x4000
3614                         break;
3615         }
3616         use_cycles(30);
3617         psxBios_ReturnFromException();
3618 }
3619
3620 void hleExc1_0_1(void)
3621 {
3622         u32 vbl_irq_ack_enable = loadRam32(A_RCNT_VBL_ACK + 0x0c); // 860c
3623         handle_chain_x_x_1(vbl_irq_ack_enable, 0); // IRQ0 vblank
3624 }
3625
3626 static void handle_chain_1_x_2(u32 ev_index, u32 irqbit)
3627 {
3628         u32 ret = 0;
3629         if (psxHu32(0x1074) & psxHu32(0x1070) & (1u << irqbit)) {
3630                 // DeliverEvent 0xf2000000 + ev_index, 2
3631                 if (RcEV[ev_index][1].status == EvStACTIVE) {
3632                         softCall(RcEV[ev_index][1].fhandler);
3633                 }
3634                 ret = 1;
3635         }
3636         mips_return_c(ret, 22);
3637 }
3638
3639 void hleExc1_0_2(void)
3640 {
3641         handle_chain_1_x_2(3, 0); // IRQ0 vblank
3642 }
3643
3644 void hleExc1_1_1(void)
3645 {
3646         u32 rcnt_irq_ack_enable = loadRam32(A_RCNT_VBL_ACK + 0x08); // 8608
3647         handle_chain_x_x_1(rcnt_irq_ack_enable, 6); // IRQ6 rcnt2
3648 }
3649
3650 void hleExc1_1_2(void)
3651 {
3652         handle_chain_1_x_2(2, 6); // IRQ6 rcnt2
3653 }
3654
3655 void hleExc1_2_1(void)
3656 {
3657         u32 rcnt_irq_ack_enable = loadRam32(A_RCNT_VBL_ACK + 0x04); // 8604
3658         handle_chain_x_x_1(rcnt_irq_ack_enable, 5); // IRQ5 rcnt1
3659 }
3660
3661 void hleExc1_2_2(void)
3662 {
3663         handle_chain_1_x_2(1, 5); // IRQ5 rcnt1
3664 }
3665
3666 void hleExc1_3_1(void)
3667 {
3668         u32 rcnt_irq_ack_enable = loadRam32(A_RCNT_VBL_ACK + 0x00); // 8600
3669         handle_chain_x_x_1(rcnt_irq_ack_enable, 4); // IRQ4 rcnt0
3670 }
3671
3672 void hleExc1_3_2(void)
3673 {
3674         handle_chain_1_x_2(0, 4); // IRQ4 rcnt0
3675 }
3676
3677 void hleExc3_0_2_defint(void)
3678 {
3679         static const struct {
3680                 u8 ev, irqbit;
3681         } tab[] = {
3682                 {  3,  2 }, // cdrom
3683                 {  9,  9 }, // spu
3684                 {  2,  1 }, // gpu
3685                 { 10, 10 }, // io
3686                 { 11,  8 }, // sio
3687                 {  1,  0 }, // vbl
3688                 {  5,  4 }, // rcnt0
3689                 {  6,  5 }, // rcnt1
3690                 {  6,  6 }, // rcnt2 (bug)
3691                 {  8,  7 }, // sio rx
3692                 {  4,  3 }, // sio
3693         };
3694         size_t i;
3695         for (i = 0; i < sizeof(tab) / sizeof(tab[0]); i++) {
3696                 if (psxHu32(0x1074) & psxHu32(0x1070) & (1u << tab[i].irqbit)) {
3697                         // DeliverEvent 0xf0000000 + ev, 0x1000
3698                         use_cycles(7);
3699                 }
3700
3701         }
3702         mips_return_c(0, 11 + 7*11 + 7*11 + 12);
3703 }
3704
3705 void psxBiosException() {
3706         u32 tcbPtr = loadRam32(A_TT_PCB);
3707         u32 *chains = loadRam32ptr(A_TT_ExCB);
3708         TCB *tcb = loadRam32ptr(tcbPtr);
3709         u32 ptr, *chain;
3710         int c, lim;
3711         int i;
3712
3713         // save the regs
3714         // $at, $v0, $v1 already saved by the mips code at A_EXCEPTION
3715         for (i = 4; i < 32; i++) {
3716                 if (i == 26) // $k0
3717                         continue;
3718                 tcb->reg[i] = SWAP32(psxRegs.GPR.r[i]);
3719         }
3720         tcb->lo = SWAP32(psxRegs.GPR.n.lo);
3721         tcb->hi = SWAP32(psxRegs.GPR.n.hi);
3722         tcb->epc = SWAP32(psxRegs.CP0.n.EPC);
3723         tcb->sr = SWAP32(psxRegs.CP0.n.SR);
3724         tcb->cause = SWAP32(psxRegs.CP0.n.Cause);
3725         sp = fp = loadRam32(A_EXC_SP);
3726         gp = A_EXC_GP;
3727         use_cycles(46);
3728
3729         // do the chains (always 4)
3730         for (c = lim = 0; c < 4; c++) {
3731                 if (chains[c * 2] == 0)
3732                         continue;
3733                 ptr = SWAP32(chains[c * 2]);
3734                 for (; ptr && lim < 100; ptr = SWAP32(chain[0])) {
3735                         chain = castRam32ptr(ptr);
3736                         use_cycles(14);
3737                         lim++;
3738                         if (chain[2] == 0)
3739                                 continue;
3740                         softCallInException(SWAP32(chain[2]));
3741                         if (returned_from_exception())
3742                                 return;
3743
3744                         if (v0 == 0 || chain[1] == 0)
3745                                 continue;
3746                         softCallInException(SWAP32(chain[1]));
3747                         if (returned_from_exception())
3748                                 return;
3749                 }
3750         }
3751         assert(lim < 100);
3752
3753         // TODO make this a chain entry
3754         if (psxHu32(0x1070) & 1)
3755                 biosPadHLE();
3756
3757         // return from exception (custom or default)
3758         use_cycles(23);
3759         ptr = loadRam32(A_EEXIT_PTR);
3760         if (ptr != A_EEXIT_DEF) {
3761                 const struct jmp_buf_ *jmp_buf = castRam32ptr(ptr);
3762                 longjmp_load(jmp_buf);
3763                 v0 = 1;
3764                 pc0 = ra;
3765                 return;
3766         }
3767         psxBios_ReturnFromException();
3768 }
3769
3770 #define bfreeze(ptr, size) { \
3771         if (Mode == 1) memcpy(&psxR[base], ptr, size); \
3772         if (Mode == 0) memcpy(ptr, &psxR[base], size); \
3773         base += size; \
3774 }
3775
3776 #define bfreezes(ptr) bfreeze(ptr, sizeof(ptr))
3777 #define bfreezel(ptr) bfreeze(ptr, sizeof(*ptr))
3778
3779 #define bfreezepsxMptr(ptr, type) { \
3780         if (Mode == 1) { \
3781                 if (ptr) psxRu32ref(base) = SWAPu32((s8 *)(ptr) - psxM); \
3782                 else psxRu32ref(base) = 0; \
3783         } else { \
3784                 if (psxRu32(base) != 0) ptr = (type *)(psxM + psxRu32(base)); \
3785                 else (ptr) = NULL; \
3786         } \
3787         base += sizeof(u32); \
3788 }
3789
3790 void psxBiosFreeze(int Mode) {
3791         u32 base = 0x40000;
3792
3793         bfreezepsxMptr(pad_buf, int);
3794         bfreezepsxMptr(pad_buf1, char);
3795         bfreezepsxMptr(pad_buf2, char);
3796         bfreezepsxMptr(heap_addr, u32);
3797         bfreezel(&pad_buf1len);
3798         bfreezel(&pad_buf2len);
3799         bfreezes(regs);
3800         bfreezel(&CardState);
3801         bfreezel(&CurThread);
3802         bfreezes(FDesc);
3803         bfreezel(&card_active_chan);
3804         bfreezel(&pad_stopped);
3805         bfreezel(&heap_size);
3806 }