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