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