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