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