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