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