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