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