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