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