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