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