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