rework gpu busy timing
[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"
9a0a61d2 39#include "psxevents.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
9ece32be 1482 const char *p, *dir = Ra0;
0a50313e 1483 PSXBIOS_LOG("psxBios_%s %x(%s)\n", biosB0n[0x40], a0, dir);
9ece32be 1484 if (dir != INVALID_PTR) {
1485 if ((p = strchr(dir, ':')))
1486 dir = ++p;
1487 if (*dir == '\\')
1488 dir++;
1489 snprintf(cdir, sizeof(cdir), "%s", dir);
1490 }
0a50313e 1491 mips_return_c(1, 100);
1492}
1493
1494static void psxBios_format() { // 0x41
1495 PSXBIOS_LOG("psxBios_%s %x(%s)\n", biosB0n[0x41], a0, Ra0);
e7e1f572 1496 if (strcmp(Ra0, "bu00:") == 0 && Config.Mcd1[0] != '\0')
1497 {
1498 CreateMcd(Config.Mcd1);
1499 LoadMcd(1, Config.Mcd1);
1500 v0 = 1;
1501 }
1502 else if (strcmp(Ra0, "bu10:") == 0 && Config.Mcd2[0] != '\0')
1503 {
1504 CreateMcd(Config.Mcd2);
1505 LoadMcd(2, Config.Mcd2);
1506 v0 = 1;
1507 }
1508 else
1509 {
1510 v0 = 0;
1511 }
1512 pc0 = ra;
1513}
1514
dc4fa8bc 1515static void psxBios_SystemErrorUnresolvedException() {
0a50313e 1516 if (floodchk != 0x12340a40) { // prevent log flood
31cd6032 1517 SysPrintf("psxBios_%s called from %08x\n", biosA0n[0x40], ra);
0a50313e 1518 floodchk = 0x12340a40;
dc4fa8bc 1519 }
1520 mips_return_void_c(1000);
1521}
1522
fed9fd6f 1523static void FlushCache() {
1524 psxCpu->Notify(R3000ACPU_NOTIFY_CACHE_ISOLATED, NULL);
1525 psxCpu->Notify(R3000ACPU_NOTIFY_CACHE_UNISOLATED, NULL);
1526 k0 = 0xbfc0193c;
1527 // runs from uncached mem so tons of cycles
1528 use_cycles(500);
1529}
1530
ef79bbde
P
1531/*
1532 * long Load(char *name, struct EXEC *header);
1533 */
1534
1535void psxBios_Load() { // 0x42
1536 EXE_HEADER eheader;
0a50313e 1537 char path[256];
1538 char *pa0, *p;
02949f79 1539 void *pa1;
ef79bbde 1540
0a50313e 1541 pa0 = Ra0;
02949f79 1542 pa1 = Ra1;
0a50313e 1543 PSXBIOS_LOG("psxBios_%s %x(%s), %x\n", biosA0n[0x42], a0, pa0, a1);
1544 if (pa0 == INVALID_PTR || pa1 == INVALID_PTR) {
1545 mips_return(0);
1546 return;
1547 }
1548 if ((p = strchr(pa0, ':')))
1549 pa0 = ++p;
1550 if (*pa0 == '\\')
1551 pa0++;
1552 if (cdir[0])
1553 snprintf(path, sizeof(path), "%s\\%s", cdir, (char *)pa0);
1554 else
1555 snprintf(path, sizeof(path), "%s", (char *)pa0);
1556
1557 if (LoadCdromFile(path, &eheader) == 0) {
02949f79 1558 memcpy(pa1, ((char*)&eheader)+16, sizeof(EXEC));
86c70511 1559 psxCpu->Clear(a1, sizeof(EXEC) / 4);
fed9fd6f 1560 FlushCache();
ef79bbde
P
1561 v0 = 1;
1562 } else v0 = 0;
0a50313e 1563 PSXBIOS_LOG(" -> %d\n", v0);
ef79bbde
P
1564
1565 pc0 = ra;
1566}
1567
1568/*
1569 * int Exec(struct EXEC *header , int argc , char **argv);
1570 */
1571
1572void psxBios_Exec() { // 43
31cd6032 1573 EXEC *header = (EXEC *)castRam32ptr(a0);
1574 u32 ptr;
1575 s32 len;
ef79bbde 1576
ef79bbde 1577 PSXBIOS_LOG("psxBios_%s: %x, %x, %x\n", biosA0n[0x43], a0, a1, a2);
ef79bbde 1578
31cd6032 1579 header->_sp = SWAP32(sp);
1580 header->_fp = SWAP32(fp);
1581 header->_sp = SWAP32(sp);
1582 header->_gp = SWAP32(gp);
1583 header->ret = SWAP32(ra);
1584 header->base = SWAP32(s0);
ef79bbde 1585
31cd6032 1586 ptr = SWAP32(header->b_addr);
1587 len = SWAP32(header->b_size);
1588 if (len != 0) do {
1589 storeRam32(ptr, 0);
1590 len -= 4; ptr += 4;
1591 } while (len > 0);
1592
1593 if (header->S_addr != 0)
1594 sp = fp = SWAP32(header->S_addr) + SWAP32(header->s_size);
ef79bbde 1595
31cd6032 1596 gp = SWAP32(header->gp0);
ef79bbde
P
1597
1598 s0 = a0;
1599
1600 a0 = a1;
1601 a1 = a2;
1602
1603 ra = 0x8000;
31cd6032 1604 pc0 = SWAP32(header->_pc0);
ef79bbde
P
1605}
1606
fed9fd6f 1607static void psxBios_FlushCache() { // 44
ef79bbde 1608 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x44]);
fed9fd6f 1609 FlushCache();
1610 mips_return_void();
ef79bbde
P
1611}
1612
1613void psxBios_GPU_dw() { // 0x46
1614 int size;
3a284665 1615 u32 *ptr;
ef79bbde
P
1616
1617#ifdef PSXBIOS_LOG
1618 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x46]);
1619#endif
1620
1621 GPU_writeData(0xa0000000);
3a284665 1622 GPU_writeData((a1<<0x10)|(a0&0xffff));
1623 GPU_writeData((a3<<0x10)|(a2&0xffff));
1624 size = (a2*a3)/2;
1625 ptr = (u32*)PSXM(Rsp[4]); //that is correct?
1626 while(size--)
1627 {
1628 GPU_writeData(SWAPu32(*ptr++));
1629 }
ef79bbde
P
1630
1631 pc0 = ra;
7a8d521f 1632}
ef79bbde
P
1633
1634void psxBios_mem2vram() { // 0x47
1635 int size;
7c3332fb 1636 gpuSyncPluginSR(); // flush
ef79bbde 1637 GPU_writeData(0xa0000000);
3a284665 1638 GPU_writeData((a1<<0x10)|(a0&0xffff));
1639 GPU_writeData((a3<<0x10)|(a2&0xffff));
1640 size = ((((a2 * a3) / 2) >> 4) << 16);
ef79bbde
P
1641 GPU_writeStatus(0x04000002);
1642 psxHwWrite32(0x1f8010f4,0);
1643 psxHwWrite32(0x1f8010f0,psxHwRead32(0x1f8010f0)|0x800);
1644 psxHwWrite32(0x1f8010a0,Rsp[4]);//might have a buggy...
3a284665 1645 psxHwWrite32(0x1f8010a4, size | 0x10);
ef79bbde
P
1646 psxHwWrite32(0x1f8010a8,0x01000201);
1647
1648 pc0 = ra;
1649}
1650
1651void psxBios_SendGPU() { // 0x48
1652 GPU_writeStatus(a0);
ddbaf678 1653 gpuSyncPluginSR();
ef79bbde
P
1654 pc0 = ra;
1655}
1656
1657void psxBios_GPU_cw() { // 0x49
1658 GPU_writeData(a0);
7c3332fb 1659 gpuSyncPluginSR();
3a284665 1660 v0 = HW_GPU_STATUS;
7a8d521f 1661 pc0 = ra;
ef79bbde
P
1662}
1663
1664void psxBios_GPU_cwb() { // 0x4a
3a284665 1665 u32 *ptr = (u32*)Ra0;
ef79bbde 1666 int size = a1;
3a284665 1667 gpuSyncPluginSR();
1668 while(size--)
1669 {
1670 GPU_writeData(SWAPu32(*ptr++));
ef79bbde
P
1671 }
1672
1673 pc0 = ra;
1674}
1675
1676void psxBios_GPU_SendPackets() { //4b:
3a284665 1677 gpuSyncPluginSR();
ef79bbde
P
1678 GPU_writeStatus(0x04000002);
1679 psxHwWrite32(0x1f8010f4,0);
1680 psxHwWrite32(0x1f8010f0,psxHwRead32(0x1f8010f0)|0x800);
1681 psxHwWrite32(0x1f8010a0,a0);
1682 psxHwWrite32(0x1f8010a4,0);
1683 psxHwWrite32(0x1f8010a8,0x010000401);
1684 pc0 = ra;
1685}
1686
1687void psxBios_sys_a0_4c() { // 0x4c GPU relate
1688 psxHwWrite32(0x1f8010a8,0x00000401);
1689 GPU_writeData(0x0400000);
1690 GPU_writeData(0x0200000);
1691 GPU_writeData(0x0100000);
cd1ea245 1692 v0 = 0x1f801814;
ef79bbde
P
1693 pc0 = ra;
1694}
1695
1696void psxBios_GPU_GetGPUStatus() { // 0x4d
1697 v0 = GPU_readStatus();
1698 pc0 = ra;
1699}
1700
1701#undef s_addr
1702
1703void psxBios_LoadExec() { // 51
1704 EXEC *header = (EXEC*)PSXM(0xf000);
1705 u32 s_addr, s_size;
1706
1707#ifdef PSXBIOS_LOG
1708 PSXBIOS_LOG("psxBios_%s: %s: %x,%x\n", biosA0n[0x51], Ra0, a1, a2);
1709#endif
1710 s_addr = a1; s_size = a2;
1711
7a8d521f 1712 a1 = 0xf000;
ef79bbde
P
1713 psxBios_Load();
1714
1715 header->S_addr = s_addr;
1716 header->s_size = s_size;
1717
1718 a0 = 0xf000; a1 = 0; a2 = 0;
1719 psxBios_Exec();
1720}
1721
1722void psxBios__bu_init() { // 70
1723#ifdef PSXBIOS_LOG
1724 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x70]);
1725#endif
1726
4d2f73bb 1727 DeliverEvent(0xf0000011, 0x0004);
1728 DeliverEvent(0xf4000001, 0x0004);
ef79bbde
P
1729
1730 pc0 = ra;
1731}
1732
1733void psxBios__96_init() { // 71
1734#ifdef PSXBIOS_LOG
1735 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x71]);
1736#endif
1737
1738 pc0 = ra;
1739}
1740
ea72f34a 1741static void write_chain(u32 *d, u32 next, u32 handler1, u32 handler2);
1742static void psxBios_SysEnqIntRP_(u32 priority, u32 chain_eptr);
1743static void psxBios_SysDeqIntRP_(u32 priority, u32 chain_rm_eptr);
dc4fa8bc 1744
1745static void psxBios_DequeueCdIntr_() {
ea72f34a 1746 psxBios_SysDeqIntRP_(0, 0x91d0);
1747 psxBios_SysDeqIntRP_(0, 0x91e0);
dc4fa8bc 1748 use_cycles(16);
1749}
1750
1751static void psxBios_DequeueCdIntr() { // a3
1752 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0xa3]);
1753 psxBios_DequeueCdIntr_();
1754}
1755
1756static void psxBios_CdRemove() { // 56, 72
ef79bbde 1757 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x72]);
ef79bbde 1758
4d2f73bb 1759 CloseEvent(loadRam32(A_CD_EVENTS + 0x00));
1760 CloseEvent(loadRam32(A_CD_EVENTS + 0x04));
1761 CloseEvent(loadRam32(A_CD_EVENTS + 0x08));
1762 CloseEvent(loadRam32(A_CD_EVENTS + 0x0c));
1763 CloseEvent(loadRam32(A_CD_EVENTS + 0x10));
dc4fa8bc 1764 psxBios_DequeueCdIntr_();
1765
1766 // EnterCriticalSection - should be done at the beginning,
1767 // but this way is much easier to implement
1768 a0 = 1;
1769 pc0 = A_SYSCALL;
1770 use_cycles(30);
ef79bbde
P
1771}
1772
5c8119b8 1773static void setup_tt(u32 tcb_cnt, u32 evcb_cnt, u32 stack);
1774
1775static void psxBios_SetConf() { // 9c
1776 PSXBIOS_LOG("psxBios_%s %x %x %x\n", biosA0n[0x9c], a0, a1, a2);
1777 setup_tt(a1, a0, a2);
1778 psxRegs.CP0.n.SR |= 0x401;
1779 mips_return_void_c(500);
1780}
1781
1782static void psxBios_GetConf() { // 9d
1783 PSXBIOS_LOG("psxBios_%s %x %x %x\n", biosA0n[0x9d], a0, a1, a2);
1784 storeRam32(a0, loadRam32(A_CONF_EvCB));
1785 storeRam32(a1, loadRam32(A_CONF_TCB));
1786 storeRam32(a2, loadRam32(A_CONF_SP));
1787 mips_return_void_c(10);
1788}
1789
ef79bbde
P
1790void psxBios_SetMem() { // 9f
1791 u32 new = psxHu32(0x1060);
1792
1793#ifdef PSXBIOS_LOG
1794 PSXBIOS_LOG("psxBios_%s: %x, %x\n", biosA0n[0x9f], a0, a1);
1795#endif
1796
1797 switch(a0) {
1798 case 2:
1799 psxHu32ref(0x1060) = SWAP32(new);
1800 psxMu32ref(0x060) = a0;
31cd6032 1801 PSXBIOS_LOG("Change effective memory : %d MBytes\n",a0);
ef79bbde
P
1802 break;
1803
1804 case 8:
1805 psxHu32ref(0x1060) = SWAP32(new | 0x300);
1806 psxMu32ref(0x060) = a0;
31cd6032 1807 PSXBIOS_LOG("Change effective memory : %d MBytes\n",a0);
7a8d521f 1808
ef79bbde 1809 default:
31cd6032 1810 PSXBIOS_LOG("Effective memory must be 2/8 MBytes\n");
ef79bbde
P
1811 break;
1812 }
1813
1814 pc0 = ra;
1815}
1816
18dd7e9e 1817/* TODO FIXME : Not compliant. -1 indicates failure but using 1 for now. */
1e50f05b 1818static void psxBios_get_cd_status() // a6
18dd7e9e 1819{
1e50f05b 1820 PSXBIOS_LOG("psxBios_%s\n", biosA0n[0xa6]);
18dd7e9e 1821 v0 = 1;
1822 pc0 = ra;
1823}
1824
1e50f05b 1825static void psxBios__card_info() { // ab
ef79bbde 1826 PSXBIOS_LOG("psxBios_%s: %x\n", biosA0n[0xab], a0);
7a8d521f 1827 u32 ret, port;
1e50f05b 1828 storeRam32(A_CARD_CHAN1, a0);
1829 port = a0 >> 4;
7a8d521f 1830
1831 switch (port) {
1832 case 0x0:
1833 case 0x1:
4d2f73bb 1834 ret = 0x0004;
7a8d521f 1835 if (McdDisable[port & 1])
4d2f73bb 1836 ret = 0x0100;
76b81516 1837 break;
1838 default:
1e50f05b 1839 PSXBIOS_LOG("psxBios_%s: UNKNOWN PORT 0x%x\n", biosA0n[0xab], a0);
4d2f73bb 1840 ret = 0x0302;
76b81516 1841 break;
1842 }
7a8d521f 1843
1844 if (McdDisable[0] && McdDisable[1])
4d2f73bb 1845 ret = 0x0100;
7a8d521f 1846
4d2f73bb 1847 DeliverEvent(0xf0000011, 0x0004);
1848// DeliverEvent(0xf4000001, 0x0004);
1849 DeliverEvent(0xf4000001, ret);
ef79bbde
P
1850 v0 = 1; pc0 = ra;
1851}
1852
1853void psxBios__card_load() { // ac
1854#ifdef PSXBIOS_LOG
1855 PSXBIOS_LOG("psxBios_%s: %x\n", biosA0n[0xac], a0);
1856#endif
1857
1e50f05b 1858 storeRam32(A_CARD_CHAN1, a0);
e9fda093 1859
4d2f73bb 1860// DeliverEvent(0xf0000011, 0x0004);
1861 DeliverEvent(0xf4000001, 0x0004);
ef79bbde
P
1862
1863 v0 = 1; pc0 = ra;
1864}
1865
31cd6032 1866static void psxBios_GetSystemInfo() { // b4
1867 u32 ret = 0;
1868 //PSXBIOS_LOG("psxBios_%s %x\n", biosA0n[0xb4], a0);
1869 SysPrintf("psxBios_%s %x\n", biosA0n[0xb4], a0);
1870 switch (a0) {
1871 case 0:
1872 case 1: ret = SWAP32(((u32 *)psxR)[0x100/4 + a0]); break;
1873 case 2: ret = 0xbfc0012c; break;
1874 case 5: ret = loadRam32(0x60) << 10; break;
1875 }
1876 mips_return_c(ret, 20);
1877}
1878
ef79bbde
P
1879/* System calls B0 */
1880
7650b754 1881static u32 psxBios_SysMalloc_(u32 size);
1882
1883static void psxBios_SysMalloc() { // B 00
1884 u32 ret = psxBios_SysMalloc_(a0);
1885
1886 PSXBIOS_LOG("psxBios_%s 0x%x -> %x\n", biosB0n[0x00], a0, ret);
1887 mips_return_c(ret, 33);
1888}
1889
ef79bbde
P
1890void psxBios_SetRCnt() { // 02
1891#ifdef PSXBIOS_LOG
1892 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x02]);
1893#endif
1894
1895 a0&= 0x3;
1896 if (a0 != 3) {
1897 u32 mode=0;
1898
1899 psxRcntWtarget(a0, a1);
1900 if (a2&0x1000) mode|= 0x050; // Interrupt Mode
1901 if (a2&0x0100) mode|= 0x008; // Count to 0xffff
1902 if (a2&0x0010) mode|= 0x001; // Timer stop mode
1903 if (a0 == 2) { if (a2&0x0001) mode|= 0x200; } // System Clock mode
1904 else { if (a2&0x0001) mode|= 0x100; } // System Clock mode
1905
1906 psxRcntWmode(a0, mode);
1907 }
1908 pc0 = ra;
1909}
1910
1911void psxBios_GetRCnt() { // 03
1912#ifdef PSXBIOS_LOG
1913 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x03]);
1914#endif
1915
11d23573 1916 switch (a0 & 0x3)
1917 {
1918 case 0: v0 = psxRcntRcount0(); break;
1919 case 1: v0 = psxRcntRcount1(); break;
1920 case 2: v0 = psxRcntRcount2(); break;
1921 case 3: v0 = 0; break;
1922 }
ef79bbde
P
1923 pc0 = ra;
1924}
1925
1926void psxBios_StartRCnt() { // 04
1927#ifdef PSXBIOS_LOG
1928 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x04]);
1929#endif
1930
1931 a0&= 0x3;
1932 if (a0 != 3) psxHu32ref(0x1074)|= SWAP32((u32)((1<<(a0+4))));
1933 else psxHu32ref(0x1074)|= SWAPu32(0x1);
1934 v0 = 1; pc0 = ra;
1935}
1936
1937void psxBios_StopRCnt() { // 05
1938#ifdef PSXBIOS_LOG
1939 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x05]);
1940#endif
1941
1942 a0&= 0x3;
1943 if (a0 != 3) psxHu32ref(0x1074)&= SWAP32((u32)(~(1<<(a0+4))));
1944 else psxHu32ref(0x1074)&= SWAPu32(~0x1);
1945 pc0 = ra;
1946}
1947
1948void psxBios_ResetRCnt() { // 06
1949#ifdef PSXBIOS_LOG
1950 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x06]);
1951#endif
1952
1953 a0&= 0x3;
1954 if (a0 != 3) {
1955 psxRcntWmode(a0, 0);
1956 psxRcntWtarget(a0, 0);
1957 psxRcntWcount(a0, 0);
1958 }
1959 pc0 = ra;
1960}
1961
4d2f73bb 1962static u32 DeliverEvent(u32 class, u32 spec) {
1963 EvCB *ev = (EvCB *)loadRam32ptr(A_TT_EvCB);
1964 u32 evcb_len = loadRam32(A_TT_EvCB + 4);
1965 u32 ret = loadRam32(A_TT_EvCB) + evcb_len;
1966 u32 i, lim = evcb_len / 0x1c;
ef79bbde 1967
7c3332fb 1968 //printf("%s %08x %x\n", __func__, class, spec);
4d2f73bb 1969 for (i = 0; i < lim; i++, ev++) {
1970 use_cycles(8);
1971 if (SWAP32(ev->status) != EvStACTIVE)
1972 continue;
1973 use_cycles(4);
1974 if (SWAP32(ev->class) != class)
1975 continue;
1976 use_cycles(4);
1977 if (SWAP32(ev->spec) != spec)
1978 continue;
1979 use_cycles(6);
1980 ret = SWAP32(ev->mode);
1981 if (ret == EvMdMARK) {
1982 ev->status = SWAP32(EvStALREADY);
1983 continue;
1984 }
1985 use_cycles(8);
1986 if (ret == EvMdCALL) {
1987 ret = SWAP32(ev->fhandler);
1988 if (ret) {
1989 v0 = ret;
1990 softCall(ret);
1991 ret = v0;
1992 }
1993 }
ef79bbde 1994 }
0a50313e 1995 floodchk = 0;
4d2f73bb 1996 use_cycles(29);
1997 return ret;
1998}
ef79bbde 1999
4d2f73bb 2000static u32 UnDeliverEvent(u32 class, u32 spec) {
2001 EvCB *ev = (EvCB *)loadRam32ptr(A_TT_EvCB);
2002 u32 evcb_len = loadRam32(A_TT_EvCB + 4);
2003 u32 ret = loadRam32(A_TT_EvCB) + evcb_len;
2004 u32 i, lim = evcb_len / 0x1c;
ef79bbde 2005
4d2f73bb 2006 for (i = 0; i < lim; i++, ev++) {
2007 use_cycles(8);
2008 if (SWAP32(ev->status) != EvStALREADY)
2009 continue;
2010 use_cycles(4);
2011 if (SWAP32(ev->class) != class)
2012 continue;
2013 use_cycles(4);
2014 if (SWAP32(ev->spec) != spec)
2015 continue;
2016 use_cycles(6);
2017 if (SWAP32(ev->mode) == EvMdMARK)
2018 ev->status = SWAP32(EvStACTIVE);
2019 }
2020 use_cycles(28);
2021 return ret;
ef79bbde
P
2022}
2023
4d2f73bb 2024static void psxBios_DeliverEvent() { // 07
2025 u32 ret;
2026 PSXBIOS_LOG("psxBios_%s %x %04x\n", biosB0n[0x07], a0, a1);
ef79bbde 2027
4d2f73bb 2028 ret = DeliverEvent(a0, a1);
2029 mips_return(ret);
2030}
ef79bbde 2031
4d2f73bb 2032static s32 get_free_EvCB_slot() {
2033 EvCB *ev = (EvCB *)loadRam32ptr(A_TT_EvCB);
2034 u32 i, lim = loadRam32(A_TT_EvCB + 4) / 0x1c;
ef79bbde 2035
4d2f73bb 2036 use_cycles(19);
2037 for (i = 0; i < lim; i++, ev++) {
2038 use_cycles(8);
2039 if (ev->status == SWAP32(EvStUNUSED))
2040 return i;
2041 }
2042 return -1;
ef79bbde
P
2043}
2044
4d2f73bb 2045static u32 OpenEvent(u32 class, u32 spec, u32 mode, u32 func) {
2046 u32 ret = get_free_EvCB_slot();
2047 if ((s32)ret >= 0) {
2048 EvCB *ev = (EvCB *)loadRam32ptr(A_TT_EvCB) + ret;
2049 ev->class = SWAP32(class);
2050 ev->status = SWAP32(EvStDISABLED);
2051 ev->spec = SWAP32(spec);
2052 ev->mode = SWAP32(mode);
2053 ev->fhandler = SWAP32(func);
2054 ret |= 0xf1000000u;
2055 }
2056 return ret;
2057}
ef79bbde 2058
4d2f73bb 2059static void psxBios_OpenEvent() { // 08
2060 u32 ret = OpenEvent(a0, a1, a2, a3);
2061 PSXBIOS_LOG("psxBios_%s (class:%x, spec:%04x, mode:%04x, func:%x) -> %x\n",
2062 biosB0n[0x08], a0, a1, a2, a3, ret);
2063 mips_return_c(ret, 36);
2064}
ef79bbde 2065
4d2f73bb 2066static void CloseEvent(u32 ev)
2067{
2068 u32 base = loadRam32(A_TT_EvCB);
2069 storeRam32(base + (ev & 0xffff) * sizeof(EvCB) + 4, EvStUNUSED);
2070}
ef79bbde 2071
4d2f73bb 2072static void psxBios_CloseEvent() { // 09
2073 PSXBIOS_LOG("psxBios_%s %x (%x)\n", biosB0n[0x09], a0,
2074 loadRam32(loadRam32(A_TT_EvCB) + (a0 & 0xffff) * sizeof(EvCB) + 4));
2075 CloseEvent(a0);
2076 mips_return_c(1, 10);
ef79bbde
P
2077}
2078
4d2f73bb 2079static void psxBios_WaitEvent() { // 0a
2080 u32 base = loadRam32(A_TT_EvCB);
2081 u32 status = loadRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4);
2082 PSXBIOS_LOG("psxBios_%s %x (status=%x)\n", biosB0n[0x0a], a0, status);
ef79bbde 2083
4d2f73bb 2084 use_cycles(15);
2085 if (status == EvStALREADY) {
2086 storeRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4, EvStACTIVE);
2087 mips_return(1);
d95c9dcb 2088 return;
2089 }
4d2f73bb 2090 if (status != EvStACTIVE)
d95c9dcb 2091 {
4d2f73bb 2092 mips_return_c(0, 2);
d95c9dcb 2093 return;
2094 }
ef79bbde 2095
4d2f73bb 2096 // retrigger this hlecall after the next emulation event
2097 pc0 -= 4;
2098 if ((s32)(next_interupt - psxRegs.cycle) > 0)
2099 psxRegs.cycle = next_interupt;
2100 psxBranchTest();
ef79bbde
P
2101}
2102
4d2f73bb 2103static void psxBios_TestEvent() { // 0b
2104 u32 base = loadRam32(A_TT_EvCB);
2105 u32 status = loadRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4);
2106 u32 ret = 0;
0a50313e 2107
2108 if (psxRegs.cycle - floodchk > 16*1024u) { // prevent log flood
2109 PSXBIOS_LOG("psxBios_%s %x %x\n", biosB0n[0x0b], a0, status);
2110 floodchk = psxRegs.cycle;
2111 }
4d2f73bb 2112 if (status == EvStALREADY) {
2113 storeRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4, EvStACTIVE);
2114 ret = 1;
b4ae2532 2115 }
ef79bbde 2116
4d2f73bb 2117 mips_return_c(ret, 15);
ef79bbde
P
2118}
2119
4d2f73bb 2120static void psxBios_EnableEvent() { // 0c
2121 u32 base = loadRam32(A_TT_EvCB);
2122 u32 status = loadRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4);
2123 PSXBIOS_LOG("psxBios_%s %x (%x)\n", biosB0n[0x0c], a0, status);
2124 if (status != EvStUNUSED)
2125 storeRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4, EvStACTIVE);
ef79bbde 2126
4d2f73bb 2127 mips_return_c(1, 15);
ef79bbde
P
2128}
2129
4d2f73bb 2130static void psxBios_DisableEvent() { // 0d
2131 u32 base = loadRam32(A_TT_EvCB);
2132 u32 status = loadRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4);
2133 PSXBIOS_LOG("psxBios_%s %x: %x\n", biosB0n[0x0d], a0, status);
2134 if (status != EvStUNUSED)
2135 storeRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4, EvStDISABLED);
ef79bbde 2136
4d2f73bb 2137 mips_return_c(1, 15);
ef79bbde
P
2138}
2139
2140/*
2141 * long OpenTh(long (*func)(), unsigned long sp, unsigned long gp);
2142 */
2143
2144void psxBios_OpenTh() { // 0e
dc4fa8bc 2145 TCB *tcb = loadRam32ptr(A_TT_TCB);
2146 u32 limit = loadRam32(A_TT_TCB + 4) / 0xc0u;
ef79bbde
P
2147 int th;
2148
dc4fa8bc 2149 for (th = 1; th < limit; th++)
a66d3058 2150 {
dc4fa8bc 2151 if (tcb[th].status != SWAP32(0x4000)) break;
ef79bbde 2152
a66d3058 2153 }
dc4fa8bc 2154 if (th == limit) {
a66d3058 2155 // Feb 2019 - Added out-of-bounds fix caught by cppcheck:
2156 // When no free TCB is found, return 0xffffffff according to Nocash doc.
2157#ifdef PSXBIOS_LOG
2158 PSXBIOS_LOG("\t%s() WARNING! No Free TCBs found!\n", __func__);
2159#endif
dc4fa8bc 2160 mips_return_c(0xffffffff, 20);
a66d3058 2161 return;
2162 }
5c8119b8 2163 PSXBIOS_LOG("psxBios_%s -> %x\n", biosB0n[0x0e], 0xff000000 + th);
ef79bbde 2164
dc4fa8bc 2165 tcb[th].status = SWAP32(0x4000);
2166 tcb[th].mode = SWAP32(0x1000);
2167 tcb[th].epc = SWAP32(a0);
2168 tcb[th].reg[30] = SWAP32(a1); // fp
2169 tcb[th].reg[29] = SWAP32(a1); // sp
2170 tcb[th].reg[28] = SWAP32(a2); // gp
ef79bbde 2171
dc4fa8bc 2172 mips_return_c(0xff000000 + th, 34);
ef79bbde
P
2173}
2174
2175/*
2176 * int CloseTh(long thread);
2177 */
2178
5c8119b8 2179static void psxBios_CloseTh() { // 0f
2180 u32 tcb = loadRam32(A_TT_TCB);
2181 u32 th = a0 & 0xffff;
ef79bbde 2182
5c8119b8 2183 PSXBIOS_LOG("psxBios_%s %x\n", biosB0n[0x0f], a0);
2184 // in the usual bios fashion no checks, just write and return 1
2185 storeRam32(tcb + th * sizeof(TCB), 0x1000);
ef79bbde 2186
5c8119b8 2187 mips_return_c(1, 11);
ef79bbde
P
2188}
2189
2190/*
2191 * int ChangeTh(long thread);
2192 */
2193
2194void psxBios_ChangeTh() { // 10
dc4fa8bc 2195 u32 tcbBase = loadRam32(A_TT_TCB);
2196 u32 th = a0 & 0xffff;
ef79bbde 2197
31cd6032 2198 // this is quite spammy
2199 //PSXBIOS_LOG("psxBios_%s %x\n", biosB0n[0x10], th);
2200
dc4fa8bc 2201 // without doing any argument checks, just issue a syscall
2202 // (like the real bios does)
2203 a0 = 3;
2204 a1 = tcbBase + th * sizeof(TCB);
2205 pc0 = A_SYSCALL;
2206 use_cycles(15);
ef79bbde
P
2207}
2208
2209void psxBios_InitPAD() { // 0x12
ea72f34a 2210 u32 i, *ram32 = (u32 *)psxM;
2211 PSXBIOS_LOG("psxBios_%s %x %x %x %x\n", biosB0n[0x12], a0, a1, a2, a3);
2212
2213 // printf("%s", "PS-X Control PAD Driver Ver 3.0");
2bce5171 2214 ram32[A_PAD_DR_DST/4] = 0;
ea72f34a 2215 ram32[A_PAD_OUTBUF/4 + 0] = 0;
2216 ram32[A_PAD_OUTBUF/4 + 1] = 0;
2217 ram32[A_PAD_OUT_LEN/4 + 0] = 0;
2218 ram32[A_PAD_OUT_LEN/4 + 1] = 0;
2219 ram32[A_PAD_INBUF/4 + 0] = SWAP32(a0);
2220 ram32[A_PAD_INBUF/4 + 1] = SWAP32(a2);
2221 ram32[A_PAD_IN_LEN/4 + 0] = SWAP32(a1);
2222 ram32[A_PAD_IN_LEN/4 + 1] = SWAP32(a3);
2223
2224 for (i = 0; i < a1; i++) {
2225 use_cycles(4);
2226 storeRam8(a0 + i, 0);
2227 }
2228 for (i = 0; i < a3; i++) {
2229 use_cycles(4);
2230 storeRam8(a2 + i, 0);
2231 }
2232 write_chain(ram32 + A_PADCRD_CHN_E/4, 0, 0x49bc, 0x4a4c);
ef79bbde 2233
ea72f34a 2234 ram32[A_PAD_IRQR_ENA/4] = SWAP32(1);
ef79bbde 2235
ea72f34a 2236 mips_return_c(1, 200);
ef79bbde
P
2237}
2238
2239void psxBios_StartPAD() { // 13
ef79bbde 2240 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x13]);
ea72f34a 2241
2242 psxBios_SysDeqIntRP_(2, A_PADCRD_CHN_E);
2243 psxBios_SysEnqIntRP_(2, A_PADCRD_CHN_E);
2244 psxHwWrite16(0x1f801070, ~1);
2245 psxHwWrite16(0x1f801074, psxHu32(0x1074) | 1);
2246 storeRam32(A_PAD_ACK_VBL, 1);
2247 storeRam32(A_RCNT_VBL_ACK + (3 << 2), 0);
bc7c5acb 2248 psxRegs.CP0.n.SR |= 0x401;
ea72f34a 2249
2250 mips_return_c(1, 300);
ef79bbde
P
2251}
2252
2253void psxBios_StopPAD() { // 14
ef79bbde 2254 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x14]);
ea72f34a 2255 storeRam32(A_RCNT_VBL_ACK + (3 << 2), 1);
2256 psxBios_SysDeqIntRP_(2, A_PADCRD_CHN_E);
2257 psxRegs.CP0.n.SR |= 0x401;
2258 mips_return_void_c(200);
ef79bbde
P
2259}
2260
2bce5171 2261static void psxBios_PAD_init() { // 15
2262 u32 ret = 0;
ef79bbde 2263 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x15]);
2bce5171 2264 if (a0 == 0x20000000 || a0 == 0x20000001)
a824e83d 2265 {
2bce5171 2266 u32 dst = a1;
2267 a0 = A_PAD_DR_BUF1; a1 = 0x22;
2268 a2 = A_PAD_DR_BUF2; a3 = 0x22;
2269 psxBios_InitPAD();
2270 psxBios_StartPAD();
2271 storeRam32(A_PAD_DR_DST, dst);
2272 ret = 2;
2273 }
2274 mips_return_c(ret, 100);
2275}
2276
2277static u32 psxBios_PAD_dr_() {
2278 u8 *dst = loadRam32ptr(A_PAD_DR_DST);
2279 u8 *buf1 = castRam8ptr(A_PAD_DR_BUF1);
2280 u8 *buf2 = castRam8ptr(A_PAD_DR_BUF2);
2281 dst[0] = dst[1] = dst[2] = dst[3] = ~0;
2282 if (buf1[0] == 0 && (buf1[1] == 0x23 || buf1[1] == 0x41))
2283 {
2284 dst[0] = buf1[3], dst[1] = buf1[2];
2285 if (buf1[1] == 0x23) {
2286 dst[0] |= 0xc7, dst[1] |= 7;
2287 if (buf1[5] >= 0x10) dst[0] &= ~(1u << 6);
2288 if (buf1[6] >= 0x10) dst[0] &= ~(1u << 7);
2289 }
a824e83d 2290 }
2bce5171 2291 if (buf2[0] == 0 && (buf2[1] == 0x23 || buf2[1] == 0x41))
2292 {
2293 dst[2] = buf2[3], dst[3] = buf2[2];
2294 if (buf2[1] == 0x23) {
2295 dst[2] |= 0xc7, dst[3] |= 7;
2296 if (buf2[5] >= 0x10) dst[2] &= ~(1u << 6);
2297 if (buf2[6] >= 0x10) dst[2] &= ~(1u << 7);
2298 }
2299 }
2300 use_cycles(55);
2301 return SWAP32(*(u32 *)dst);
ef79bbde
P
2302}
2303
2bce5171 2304static void psxBios_PAD_dr() { // 16
ef79bbde 2305 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x16]);
2bce5171 2306 u32 ret = psxBios_PAD_dr_();
2307 mips_return(ret);
ef79bbde
P
2308}
2309
dc4fa8bc 2310static void psxBios_ReturnFromException() { // 17
2311 u32 tcbPtr = loadRam32(A_TT_PCB);
2312 const TCB *tcb = loadRam32ptr(tcbPtr);
31cd6032 2313 u32 sr;
dc4fa8bc 2314 int i;
2315
2316 for (i = 1; i < 32; i++)
2317 psxRegs.GPR.r[i] = SWAP32(tcb->reg[i]);
2318 psxRegs.GPR.n.lo = SWAP32(tcb->lo);
2319 psxRegs.GPR.n.hi = SWAP32(tcb->hi);
31cd6032 2320 sr = SWAP32(tcb->sr);
ef79bbde 2321
dc4fa8bc 2322 //printf("%s %08x->%08x %u\n", __func__, pc0, tcb->epc, psxRegs.cycle);
2323 pc0 = k0 = SWAP32(tcb->epc);
ef79bbde 2324
31cd6032 2325 // the interpreter wants to know about sr changes, so do a MTC0
2326 sr = (sr & ~0x0f) | ((sr & 0x3c) >> 2);
2327 MTC0(&psxRegs, 12, sr);
2328
dc4fa8bc 2329 use_cycles(53);
2330 psxBranchTest();
ef79bbde
P
2331}
2332
2333void psxBios_ResetEntryInt() { // 18
ef79bbde 2334 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x18]);
ef79bbde 2335
dc4fa8bc 2336 storeRam32(A_EEXIT_PTR, A_EEXIT_DEF);
2337 mips_return_void_c(5);
ef79bbde
P
2338}
2339
2340void psxBios_HookEntryInt() { // 19
dc4fa8bc 2341 PSXBIOS_LOG("psxBios_%s %x\n", biosB0n[0x19], a0);
ef79bbde 2342
dc4fa8bc 2343 storeRam32(A_EEXIT_PTR, a0);
2344 mips_return_void_c(3);
ef79bbde
P
2345}
2346
4d2f73bb 2347static void psxBios_UnDeliverEvent() { // 0x20
2348 u32 ret;
2349 PSXBIOS_LOG("psxBios_%s %x %x\n", biosB0n[0x20], a0, a1);
ef79bbde 2350
4d2f73bb 2351 ret = UnDeliverEvent(a0, a1);
2352 mips_return(ret);
ef79bbde
P
2353}
2354
857275a9 2355static void buopen(int mcd, char *ptr, char *cfg)
595a136b 2356{
2357 int i;
7a8d521f 2358 char *mcd_data = ptr;
595a136b 2359
2360 strcpy(FDesc[1 + mcd].name, Ra0+5);
2361 FDesc[1 + mcd].offset = 0;
2362 FDesc[1 + mcd].mode = a1;
2363
2364 for (i=1; i<16; i++) {
7a8d521f 2365 const char *fptr = mcd_data + 128 * i;
595a136b 2366 if ((*fptr & 0xF0) != 0x50) continue;
2367 if (strcmp(FDesc[1 + mcd].name, fptr+0xa)) continue;
2368 FDesc[1 + mcd].mcfile = i;
31cd6032 2369 PSXBIOS_LOG("open %s\n", fptr+0xa);
595a136b 2370 v0 = 1 + mcd;
2371 break;
2372 }
2373 if (a1 & 0x200 && v0 == -1) { /* FCREAT */
595a136b 2374 for (i=1; i<16; i++) {
2375 int j, xor, nblk = a1 >> 16;
7a8d521f 2376 char *pptr, *fptr2;
2377 char *fptr = mcd_data + 128 * i;
595a136b 2378
595a136b 2379 if ((*fptr & 0xF0) != 0xa0) continue;
2380
2381 FDesc[1 + mcd].mcfile = i;
2382 fptr[0] = 0x51;
2383 fptr[4] = 0x00;
2384 fptr[5] = 0x20 * nblk;
2385 fptr[6] = 0x00;
2386 fptr[7] = 0x00;
2387 strcpy(fptr+0xa, FDesc[1 + mcd].name);
7a8d521f 2388 pptr = fptr2 = fptr;
595a136b 2389 for(j=2; j<=nblk; j++) {
2390 int k;
2391 for(i++; i<16; i++) {
2392 fptr2 += 128;
7a8d521f 2393
595a136b 2394 memset(fptr2, 0, 128);
2395 fptr2[0] = j < nblk ? 0x52 : 0x53;
2396 pptr[8] = i - 1;
2397 pptr[9] = 0;
2398 for (k=0, xor=0; k<127; k++) xor^= pptr[k];
2399 pptr[127] = xor;
2400 pptr = fptr2;
2401 break;
2402 }
2403 /* shouldn't this return ENOSPC if i == 16? */
2404 }
2405 pptr[8] = pptr[9] = 0xff;
2406 for (j=0, xor=0; j<127; j++) xor^= pptr[j];
2407 pptr[127] = xor;
31cd6032 2408 PSXBIOS_LOG("openC %s %d\n", ptr, nblk);
595a136b 2409 v0 = 1 + mcd;
2410 /* just go ahead and resave them all */
2411 SaveMcd(cfg, ptr, 128, 128 * 15);
2412 break;
2413 }
2414 /* shouldn't this return ENOSPC if i == 16? */
2415 }
ef79bbde
P
2416}
2417
2418/*
2419 * int open(char *name , int mode);
2420 */
2421
2422void psxBios_open() { // 0x32
02949f79 2423 void *pa0 = Ra0;
ef79bbde 2424
7c3332fb 2425 PSXBIOS_LOG("psxBios_%s %s %x\n", biosB0n[0x32], Ra0, a1);
ef79bbde
P
2426
2427 v0 = -1;
2428
7a8d521f 2429 if (pa0 != INVALID_PTR) {
02949f79 2430 if (!strncmp(pa0, "bu00", 4)) {
595a136b 2431 buopen(1, Mcd1Data, Config.Mcd1);
02949f79 2432 }
ef79bbde 2433
02949f79 2434 if (!strncmp(pa0, "bu10", 4)) {
595a136b 2435 buopen(2, Mcd2Data, Config.Mcd2);
02949f79 2436 }
ef79bbde
P
2437 }
2438
2439 pc0 = ra;
2440}
2441
2442/*
2443 * int lseek(int fd , int offset , int whence);
2444 */
2445
2446void psxBios_lseek() { // 0x33
2447#ifdef PSXBIOS_LOG
2448 PSXBIOS_LOG("psxBios_%s: %x, %x, %x\n", biosB0n[0x33], a0, a1, a2);
2449#endif
2450
2451 switch (a2) {
2452 case 0: // SEEK_SET
2453 FDesc[a0].offset = a1;
2454 v0 = a1;
4d2f73bb 2455// DeliverEvent(0xf0000011, 0x0004);
2456// DeliverEvent(0xf4000001, 0x0004);
ef79bbde
P
2457 break;
2458
2459 case 1: // SEEK_CUR
2460 FDesc[a0].offset+= a1;
2461 v0 = FDesc[a0].offset;
2462 break;
2463 }
2464
2465 pc0 = ra;
2466}
2467
595a136b 2468
ef79bbde
P
2469/*
2470 * int read(int fd , void *buf , int nbytes);
2471 */
2472
2473void psxBios_read() { // 0x34
2474 char *ptr;
02949f79 2475 void *pa1 = Ra1;
ef79bbde
P
2476
2477#ifdef PSXBIOS_LOG
2478 PSXBIOS_LOG("psxBios_%s: %x, %x, %x\n", biosB0n[0x34], a0, a1, a2);
2479#endif
2480
2481 v0 = -1;
2482
7a8d521f 2483 if (pa1 != INVALID_PTR) {
02949f79 2484 switch (a0) {
595a136b 2485 case 2: buread(pa1, 1, a2); break;
2486 case 3: buread(pa1, 2, a2); break;
02949f79 2487 }
ef79bbde 2488 }
7a8d521f 2489
ef79bbde
P
2490 pc0 = ra;
2491}
2492
ef79bbde
P
2493/*
2494 * int write(int fd , void *buf , int nbytes);
2495 */
2496
2497void psxBios_write() { // 0x35/0x03
2498 char *ptr;
02949f79 2499 void *pa1 = Ra1;
2500
31cd6032 2501 if (a0 != 1) // stdout
2502 PSXBIOS_LOG("psxBios_%s: %x,%x,%x\n", biosB0n[0x35], a0, a1, a2);
02949f79 2503
2504 v0 = -1;
7a8d521f 2505 if (pa1 == INVALID_PTR) {
02949f79 2506 pc0 = ra;
2507 return;
2508 }
ef79bbde
P
2509
2510 if (a0 == 1) { // stdout
02949f79 2511 char *ptr = pa1;
ef79bbde 2512
02949f79 2513 v0 = a2;
31cd6032 2514 if (Config.PsxOut) while (a2 > 0) {
ef79bbde
P
2515 SysPrintf("%c", *ptr++); a2--;
2516 }
2517 pc0 = ra; return;
2518 }
ef79bbde
P
2519
2520 switch (a0) {
595a136b 2521 case 2: buwrite(pa1, 1, a2); break;
2522 case 3: buwrite(pa1, 2, a2); break;
ef79bbde
P
2523 }
2524
2525 pc0 = ra;
2526}
2527
a94ccc7f 2528static void psxBios_write_psxout() {
2529 if (a0 == 1) { // stdout
2530 const char *ptr = Ra1;
2531 int len = a2;
2532
2533 if (ptr != INVALID_PTR)
2534 while (len-- > 0)
2535 SysPrintf("%c", *ptr++);
2536 }
2537}
2538
2539static void psxBios_putchar_psxout() { // 3d
2540 SysPrintf("%c", (char)a0);
2541}
2542
2543static void psxBios_puts_psxout() { // 3e/3f
2544 SysPrintf("%s", Ra0);
2545}
2546
ef79bbde
P
2547/*
2548 * int close(int fd);
2549 */
2550
2551void psxBios_close() { // 0x36
2552#ifdef PSXBIOS_LOG
2553 PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x36], a0);
2554#endif
2555
2556 v0 = a0;
2557 pc0 = ra;
2558}
2559
2560void psxBios_putchar() { // 3d
31cd6032 2561 if (Config.PsxOut) SysPrintf("%c", (char)a0);
ef79bbde
P
2562 pc0 = ra;
2563}
2564
2565void psxBios_puts() { // 3e/3f
31cd6032 2566 if (Config.PsxOut) SysPrintf("%s", Ra0);
ef79bbde
P
2567 pc0 = ra;
2568}
2569
f7cfdeaf 2570static void bufile(const u8 *mcd_data, u32 dir_) {
9ece32be 2571 struct DIRENTRY *dir = (struct DIRENTRY *)PSXM(dir_);
f7cfdeaf 2572 const char *pfile = ffile + 5;
2573 const u8 *data = mcd_data;
2574 int i = 0, match = 0;
2575 int blocks = 1;
2576 u32 head = 0;
f1514614 2577
f7cfdeaf 2578 v0 = 0;
9ece32be 2579 if (dir == INVALID_PTR)
2580 return;
2581
f7cfdeaf 2582 for (; nfile <= 15 && !match; nfile++) {
2583 const char *name;
2584
2585 head = nfile * 0x40;
2586 data = mcd_data + 128 * nfile;
2587 name = (const char *)data + 0x0a;
2588 if ((data[0] & 0xF0) != 0x50) continue;
2589 /* Bug link files show up as free block. */
2590 if (!name[0]) continue;
2591 match = 1;
2592 for (i = 0; i < 20; i++) {
2593 if (pfile[i] == name[i] || pfile[i] == '?')
2594 dir->name[i] = name[i];
2595 else if (pfile[i] == '*') {
2596 int len = strlen(name + i);
2597 if (i + len > 20)
2598 len = 20 - i;
2599 memcpy(dir->name + i, name + i, len + 1);
2600 i += len;
2601 break;
2602 }
2603 else {
2604 match = 0;
2605 break;
2606 }
2607 if (!name[i])
2608 break;
2609 }
2610 PSXBIOS_LOG("%d : %s = %s + %s (match=%d)\n",
2611 nfile, dir->name, pfile, name, match);
2612 }
2613 for (; nfile <= 15; nfile++, blocks++) {
2614 const u8 *data2 = mcd_data + 128 * nfile;
27f734f9 2615 const char *name = (const char *)data2 + 0x0a;
f7cfdeaf 2616 if ((data2[0] & 0xF0) != 0x50 || name[0])
2617 break;
2618 }
2619 if (match) {
2620 // nul char of full lenth name seems to overwrite .attr
2621 dir->attr = SWAP32(i < 20 ? data[0] & 0xf0 : 0); // ?
2622 dir->size = 8192 * blocks;
2623 dir->head = head;
2624 v0 = dir_;
2625 }
2626 PSXBIOS_LOG(" -> %x '%s' %x %x %x %x\n", v0, v0 ? dir->name : "",
2627 dir->attr, dir->size, dir->next, dir->head);
ef79bbde
P
2628}
2629
2630/*
2631 * struct DIRENTRY* firstfile(char *name,struct DIRENTRY *dir);
2632 */
7a8d521f 2633
7c3332fb 2634static void psxBios_firstfile() { // 42
9ece32be 2635 char *pa0 = Ra0;
ef79bbde 2636
f7cfdeaf 2637 PSXBIOS_LOG("psxBios_%s %s %x\n", biosB0n[0x42], pa0, a1);
ef79bbde
P
2638 v0 = 0;
2639
9ece32be 2640 if (pa0 != INVALID_PTR)
7c3332fb 2641 {
2642 snprintf(ffile, sizeof(ffile), "%s", pa0);
f7cfdeaf 2643 if (ffile[5] == 0)
2644 strcpy(ffile + 5, "*"); // maybe?
2645 nfile = 1;
02949f79 2646 if (!strncmp(pa0, "bu00", 4)) {
857fabea 2647 // firstfile() calls _card_read() internally, so deliver it's event
4d2f73bb 2648 DeliverEvent(0xf0000011, 0x0004);
27f734f9 2649 bufile((u8 *)Mcd1Data, a1);
02949f79 2650 } else if (!strncmp(pa0, "bu10", 4)) {
857fabea 2651 // firstfile() calls _card_read() internally, so deliver it's event
4d2f73bb 2652 DeliverEvent(0xf0000011, 0x0004);
27f734f9 2653 bufile((u8 *)Mcd2Data, a1);
02949f79 2654 }
ef79bbde
P
2655 }
2656
2657 pc0 = ra;
2658}
2659
2660/*
2661 * struct DIRENTRY* nextfile(struct DIRENTRY *dir);
2662 */
2663
2664void psxBios_nextfile() { // 43
f7cfdeaf 2665 PSXBIOS_LOG("psxBios_%s %x\n", biosB0n[0x43], a0);
ef79bbde 2666
ef79bbde 2667 v0 = 0;
f7cfdeaf 2668 if (!strncmp(ffile, "bu00", 4))
27f734f9 2669 bufile((u8 *)Mcd1Data, a0);
f7cfdeaf 2670 else if (!strncmp(ffile, "bu10", 4))
27f734f9 2671 bufile((u8 *)Mcd2Data, a0);
ef79bbde
P
2672
2673 pc0 = ra;
2674}
2675
2676#define burename(mcd) { \
2677 for (i=1; i<16; i++) { \
2678 int namelen, j, xor = 0; \
2679 ptr = Mcd##mcd##Data + 128 * i; \
2680 if ((*ptr & 0xF0) != 0x50) continue; \
2681 if (strcmp(Ra0+5, ptr+0xa)) continue; \
2682 namelen = strlen(Ra1+5); \
2683 memcpy(ptr+0xa, Ra1+5, namelen); \
2684 memset(ptr+0xa+namelen, 0, 0x75-namelen); \
2685 for (j=0; j<127; j++) xor^= ptr[j]; \
2686 ptr[127] = xor; \
2687 SaveMcd(Config.Mcd##mcd, Mcd##mcd##Data, 128 * i + 0xa, 0x76); \
2688 v0 = 1; \
2689 break; \
2690 } \
2691}
2692
2693/*
2694 * int rename(char *old, char *new);
2695 */
2696
2697void psxBios_rename() { // 44
02949f79 2698 void *pa0 = Ra0;
2699 void *pa1 = Ra1;
ef79bbde
P
2700 char *ptr;
2701 int i;
2702
2703#ifdef PSXBIOS_LOG
2704 PSXBIOS_LOG("psxBios_%s: %s,%s\n", biosB0n[0x44], Ra0, Ra1);
2705#endif
2706
2707 v0 = 0;
2708
7a8d521f 2709 if (pa0 != INVALID_PTR && pa1 != INVALID_PTR) {
02949f79 2710 if (!strncmp(pa0, "bu00", 4) && !strncmp(pa1, "bu00", 4)) {
2711 burename(1);
2712 }
ef79bbde 2713
02949f79 2714 if (!strncmp(pa0, "bu10", 4) && !strncmp(pa1, "bu10", 4)) {
2715 burename(2);
2716 }
ef79bbde
P
2717 }
2718
2719 pc0 = ra;
2720}
2721
2722
2723#define budelete(mcd) { \
2724 for (i=1; i<16; i++) { \
2725 ptr = Mcd##mcd##Data + 128 * i; \
2726 if ((*ptr & 0xF0) != 0x50) continue; \
2727 if (strcmp(Ra0+5, ptr+0xa)) continue; \
2728 *ptr = (*ptr & 0xf) | 0xA0; \
2729 SaveMcd(Config.Mcd##mcd, Mcd##mcd##Data, 128 * i, 1); \
31cd6032 2730 PSXBIOS_LOG("delete %s\n", ptr+0xa); \
ef79bbde
P
2731 v0 = 1; \
2732 break; \
2733 } \
2734}
2735
2736/*
2737 * int delete(char *name);
2738 */
2739
2740void psxBios_delete() { // 45
02949f79 2741 void *pa0 = Ra0;
ef79bbde
P
2742 char *ptr;
2743 int i;
2744
2745#ifdef PSXBIOS_LOG
2746 PSXBIOS_LOG("psxBios_%s: %s\n", biosB0n[0x45], Ra0);
2747#endif
2748
2749 v0 = 0;
2750
7a8d521f 2751 if (pa0 != INVALID_PTR) {
02949f79 2752 if (!strncmp(pa0, "bu00", 4)) {
2753 budelete(1);
2754 }
ef79bbde 2755
02949f79 2756 if (!strncmp(pa0, "bu10", 4)) {
2757 budelete(2);
2758 }
ef79bbde
P
2759 }
2760
2761 pc0 = ra;
2762}
2763
2764void psxBios_InitCARD() { // 4a
ea72f34a 2765 u32 *ram32 = (u32 *)psxM;
ef79bbde 2766 PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x4a], a0);
ea72f34a 2767 write_chain(ram32 + A_PADCRD_CHN_E/4, 0, 0x49bc, 0x4a4c);
fed9fd6f 2768 // (maybe) todo: early_card_irq, etc
ef79bbde 2769
ea72f34a 2770 ram32[A_PAD_IRQR_ENA/4] = SWAP32(a0);
2771
fed9fd6f 2772 psxBios_FlushCache();
2773 mips_return_c(0, 34+13+15+6);
ef79bbde
P
2774}
2775
2776void psxBios_StartCARD() { // 4b
ef79bbde 2777 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x4b]);
ea72f34a 2778 psxBios_SysDeqIntRP_(2, A_PADCRD_CHN_E);
2779 psxBios_SysEnqIntRP_(2, A_PADCRD_CHN_E);
ef79bbde 2780
ea72f34a 2781 psxHwWrite16(0x1f801074, psxHu32(0x1074) | 1);
2782 storeRam32(A_PAD_ACK_VBL, 1);
2783 storeRam32(A_RCNT_VBL_ACK + (3 << 2), 0);
2784 storeRam32(A_CARD_IRQR_ENA, 1);
2785 psxRegs.CP0.n.SR |= 0x401;
2786
2787 mips_return_c(1, 200);
ef79bbde
P
2788}
2789
2790void psxBios_StopCARD() { // 4c
ef79bbde 2791 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x4c]);
ea72f34a 2792 storeRam32(A_RCNT_VBL_ACK + (3 << 2), 1);
2793 psxBios_SysDeqIntRP_(2, A_PADCRD_CHN_E);
2794 storeRam32(A_CARD_IRQR_ENA, 0);
2795 psxRegs.CP0.n.SR |= 0x401;
2796 mips_return_void_c(200);
ef79bbde
P
2797}
2798
2799void psxBios__card_write() { // 0x4e
02949f79 2800 void *pa2 = Ra2;
ef79bbde
P
2801 int port;
2802
2803#ifdef PSXBIOS_LOG
2804 PSXBIOS_LOG("psxBios_%s: %x,%x,%x\n", biosB0n[0x4e], a0, a1, a2);
2805#endif
1059caaf 2806 /*
2807 Function also accepts sector 400h (a bug).
2808 But notaz said we shouldn't allow sector 400h because it can corrupt the emulator.
2809 */
2810 if (!(a1 <= 0x3FF))
bd48ba5e 2811 {
2812 /* Invalid sectors */
2813 v0 = 0; pc0 = ra;
2814 return;
2815 }
1e50f05b 2816 storeRam32(A_CARD_CHAN1, a0);
ef79bbde
P
2817 port = a0 >> 4;
2818
7a8d521f 2819 if (pa2 != INVALID_PTR) {
02949f79 2820 if (port == 0) {
2821 memcpy(Mcd1Data + a1 * 128, pa2, 128);
2822 SaveMcd(Config.Mcd1, Mcd1Data, a1 * 128, 128);
2823 } else {
2824 memcpy(Mcd2Data + a1 * 128, pa2, 128);
2825 SaveMcd(Config.Mcd2, Mcd2Data, a1 * 128, 128);
2826 }
ef79bbde
P
2827 }
2828
4d2f73bb 2829 DeliverEvent(0xf0000011, 0x0004);
2830// DeliverEvent(0xf4000001, 0x0004);
ef79bbde
P
2831
2832 v0 = 1; pc0 = ra;
2833}
2834
2835void psxBios__card_read() { // 0x4f
02949f79 2836 void *pa2 = Ra2;
ef79bbde
P
2837 int port;
2838
2839#ifdef PSXBIOS_LOG
2840 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x4f]);
2841#endif
1059caaf 2842 /*
2843 Function also accepts sector 400h (a bug).
2844 But notaz said we shouldn't allow sector 400h because it can corrupt the emulator.
2845 */
2846 if (!(a1 <= 0x3FF))
bd48ba5e 2847 {
2848 /* Invalid sectors */
2849 v0 = 0; pc0 = ra;
2850 return;
2851 }
1e50f05b 2852 storeRam32(A_CARD_CHAN1, a0);
ef79bbde
P
2853 port = a0 >> 4;
2854
7a8d521f 2855 if (pa2 != INVALID_PTR) {
02949f79 2856 if (port == 0) {
2857 memcpy(pa2, Mcd1Data + a1 * 128, 128);
2858 } else {
2859 memcpy(pa2, Mcd2Data + a1 * 128, 128);
2860 }
ef79bbde
P
2861 }
2862
4d2f73bb 2863 DeliverEvent(0xf0000011, 0x0004);
2864// DeliverEvent(0xf4000001, 0x0004);
ef79bbde
P
2865
2866 v0 = 1; pc0 = ra;
2867}
2868
2869void psxBios__new_card() { // 0x50
2870#ifdef PSXBIOS_LOG
2871 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x50]);
2872#endif
2873
2874 pc0 = ra;
2875}
2876
002b2f7d 2877/* According to a user, this allows Final Fantasy Tactics to save/load properly */
2878void psxBios__get_error(void) // 55
7a8d521f 2879{
dc4fa8bc 2880 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x55]);
002b2f7d 2881 v0 = 0;
2882 pc0 = ra;
2883}
2884
ef79bbde
P
2885void psxBios_Krom2RawAdd() { // 0x51
2886 int i = 0;
2887
dc4fa8bc 2888 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x51]);
ef79bbde
P
2889 const u32 table_8140[][2] = {
2890 {0x8140, 0x0000}, {0x8180, 0x0762}, {0x81ad, 0x0cc6}, {0x81b8, 0x0ca8},
2891 {0x81c0, 0x0f00}, {0x81c8, 0x0d98}, {0x81cf, 0x10c2}, {0x81da, 0x0e6a},
2892 {0x81e9, 0x13ce}, {0x81f0, 0x102c}, {0x81f8, 0x1590}, {0x81fc, 0x111c},
2893 {0x81fd, 0x1626}, {0x824f, 0x113a}, {0x8259, 0x20ee}, {0x8260, 0x1266},
2894 {0x827a, 0x24cc}, {0x8281, 0x1572}, {0x829b, 0x28aa}, {0x829f, 0x187e},
2895 {0x82f2, 0x32dc}, {0x8340, 0x2238}, {0x837f, 0x4362}, {0x8380, 0x299a},
2896 {0x8397, 0x4632}, {0x839f, 0x2c4c}, {0x83b7, 0x49f2}, {0x83bf, 0x2f1c},
2897 {0x83d7, 0x4db2}, {0x8440, 0x31ec}, {0x8461, 0x5dde}, {0x8470, 0x35ca},
2898 {0x847f, 0x6162}, {0x8480, 0x378c}, {0x8492, 0x639c}, {0x849f, 0x39a8},
2899 {0xffff, 0}
2900 };
2901
2902 const u32 table_889f[][2] = {
2903 {0x889f, 0x3d68}, {0x8900, 0x40ec}, {0x897f, 0x4fb0}, {0x8a00, 0x56f4},
2904 {0x8a7f, 0x65b8}, {0x8b00, 0x6cfc}, {0x8b7f, 0x7bc0}, {0x8c00, 0x8304},
2905 {0x8c7f, 0x91c8}, {0x8d00, 0x990c}, {0x8d7f, 0xa7d0}, {0x8e00, 0xaf14},
2906 {0x8e7f, 0xbdd8}, {0x8f00, 0xc51c}, {0x8f7f, 0xd3e0}, {0x9000, 0xdb24},
2907 {0x907f, 0xe9e8}, {0x9100, 0xf12c}, {0x917f, 0xfff0}, {0x9200, 0x10734},
2908 {0x927f, 0x115f8}, {0x9300, 0x11d3c}, {0x937f, 0x12c00}, {0x9400, 0x13344},
2909 {0x947f, 0x14208}, {0x9500, 0x1494c}, {0x957f, 0x15810}, {0x9600, 0x15f54},
2910 {0x967f, 0x16e18}, {0x9700, 0x1755c}, {0x977f, 0x18420}, {0x9800, 0x18b64},
2911 {0xffff, 0}
2912 };
2913
2914 if (a0 >= 0x8140 && a0 <= 0x84be) {
2915 while (table_8140[i][0] <= a0) i++;
2916 a0 -= table_8140[i - 1][0];
2917 v0 = 0xbfc66000 + (a0 * 0x1e + table_8140[i - 1][1]);
2918 } else if (a0 >= 0x889f && a0 <= 0x9872) {
2919 while (table_889f[i][0] <= a0) i++;
2920 a0 -= table_889f[i - 1][0];
2921 v0 = 0xbfc66000 + (a0 * 0x1e + table_889f[i - 1][1]);
2922 } else {
2923 v0 = 0xffffffff;
2924 }
2925
2926 pc0 = ra;
2927}
2928
2929void psxBios_GetC0Table() { // 56
ef79bbde 2930 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x56]);
dc4fa8bc 2931 log_unhandled("GetC0Table @%08x\n", ra);
ef79bbde 2932
dc4fa8bc 2933 mips_return_c(A_C0_TABLE, 3);
ef79bbde
P
2934}
2935
2936void psxBios_GetB0Table() { // 57
ef79bbde 2937 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x57]);
dc4fa8bc 2938 log_unhandled("GetB0Table @%08x\n", ra);
ef79bbde 2939
dc4fa8bc 2940 mips_return_c(A_B0_TABLE, 3);
ef79bbde
P
2941}
2942
1e50f05b 2943static void psxBios__card_chan() { // 0x58
2944 u32 ret;
e9fda093 2945 PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x58]);
e9fda093 2946
1e50f05b 2947 // todo: should return active slot chan
2948 // (active - which was last processed by irq code)
2949 ret = loadRam32(A_CARD_CHAN1);
2950 mips_return_c(ret, 8);
e9fda093 2951}
2952
ea72f34a 2953static void psxBios_ChangeClearPad() { // 5b
2954 u32 ret;
ef79bbde 2955 PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x5b], a0);
ea72f34a 2956 ret = loadRam32(A_PAD_ACK_VBL);
2957 storeRam32(A_PAD_ACK_VBL, a0);
ef79bbde 2958
ea72f34a 2959 mips_return_c(ret, 6);
ef79bbde
P
2960}
2961
1e50f05b 2962static void psxBios__card_status() { // 5c
2963 PSXBIOS_LOG("psxBios_%s %x\n", biosB0n[0x5c], a0);
21af3ff6 2964
1e50f05b 2965 v0 = 1; // ready
21af3ff6 2966 pc0 = ra;
2967}
2968
1e50f05b 2969static void psxBios__card_wait() { // 5d
2970 PSXBIOS_LOG("psxBios_%s %x\n", biosB0n[0x5d], a0);
5f652aa9 2971
1e50f05b 2972 v0 = 1; // ready
5f652aa9 2973 pc0 = ra;
2974}
2975
ef79bbde
P
2976/* System calls C0 */
2977
7650b754 2978static void psxBios_InitRCnt() { // 00
2979 int i;
2980 PSXBIOS_LOG("psxBios_%s %x\n", biosC0n[0x00], a0);
2981 psxHwWrite16(0x1f801074, psxHu32(0x1074) & ~0x71);
2982 for (i = 0; i < 3; i++) {
2983 psxHwWrite16(0x1f801100 + i*0x10 + 4, 0);
2984 psxHwWrite16(0x1f801100 + i*0x10 + 8, 0);
2985 psxHwWrite16(0x1f801100 + i*0x10 + 0, 0);
2986 }
ea72f34a 2987 psxBios_SysEnqIntRP_(a0, 0x6d88);
7650b754 2988 mips_return_c(0, 9);
2989}
2990
2991static void psxBios_InitException() { // 01
2992 PSXBIOS_LOG("psxBios_%s %x\n", biosC0n[0x01], a0);
ea72f34a 2993 psxBios_SysEnqIntRP_(a0, 0x6da8);
7650b754 2994 mips_return_c(0, 9);
2995}
2996
ef79bbde
P
2997/*
2998 * int SysEnqIntRP(int index , long *queue);
2999 */
3000
ea72f34a 3001static void psxBios_SysEnqIntRP_(u32 priority, u32 chain_eptr) {
dc4fa8bc 3002 u32 old, base = loadRam32(A_TT_ExCB);
ef79bbde 3003
ea72f34a 3004 old = loadRam32(base + (priority << 3));
3005 storeRam32(base + (priority << 3), chain_eptr);
3006 storeRam32(chain_eptr, old);
dc4fa8bc 3007 mips_return_c(0, 9);
ef79bbde
P
3008}
3009
ea72f34a 3010static void psxBios_SysEnqIntRP() { // 02
3011 PSXBIOS_LOG("psxBios_%s %x %x\n", biosC0n[0x02], a0, a1);
3012 psxBios_SysEnqIntRP_(a0, a1);
3013}
3014
ef79bbde
P
3015/*
3016 * int SysDeqIntRP(int index , long *queue);
3017 */
3018
ea72f34a 3019static void psxBios_SysDeqIntRP_(u32 priority, u32 chain_rm_eptr) {
dc4fa8bc 3020 u32 ptr, next, base = loadRam32(A_TT_ExCB);
3021 u32 lim = 0, ret = 0;
3022
3023 // as in original: no arg checks of any kind, bug if a1 == 0
ea72f34a 3024 ptr = loadRam32(base + (priority << 3));
dc4fa8bc 3025 while (ptr) {
3026 next = loadRam32(ptr);
ea72f34a 3027 if (ptr == chain_rm_eptr) {
3028 storeRam32(base + (priority << 3), next);
dc4fa8bc 3029 ret = ptr;
3030 use_cycles(6);
3031 break;
3032 }
ea72f34a 3033 while (next && next != chain_rm_eptr && lim++ < 100) {
dc4fa8bc 3034 ptr = next;
3035 next = loadRam32(ptr);
3036 use_cycles(8);
3037 }
ea72f34a 3038 if (next == chain_rm_eptr) {
dc4fa8bc 3039 next = loadRam32(next);
3040 storeRam32(ptr, next);
3041 ret = ptr;
3042 use_cycles(6);
3043 }
3044 break;
3045 }
3046 if (lim == 100)
ea72f34a 3047 PSXBIOS_LOG("bad chain %u %x\n", priority, base);
ef79bbde 3048
dc4fa8bc 3049 mips_return_c(ret, 12);
3050}
ef79bbde 3051
dc4fa8bc 3052static void psxBios_SysDeqIntRP() { // 03
3053 PSXBIOS_LOG("psxBios_%s %x %x\n", biosC0n[0x03], a0, a1);
ea72f34a 3054 psxBios_SysDeqIntRP_(a0, a1);
ef79bbde
P
3055}
3056
4d2f73bb 3057static void psxBios_get_free_EvCB_slot() { // 04
3058 PSXBIOS_LOG("psxBios_%s\n", biosC0n[0x04]);
3059 s32 ret = get_free_EvCB_slot();
3060 mips_return_c(ret, 0);
3061}
3062
7650b754 3063static void psxBios_SysInitMemory_(u32 base, u32 size) {
3064 storeRam32(base, 0);
3065 storeRam32(A_KMALLOC_PTR, base);
3066 storeRam32(A_KMALLOC_SIZE, size);
3067 storeRam32(A_KMALLOC_END, base + (size & ~3) + 4);
3068}
3069
3070// this should be much more complicated, but maybe that'll be enough
3071static u32 psxBios_SysMalloc_(u32 size) {
3072 u32 ptr = loadRam32(A_KMALLOC_PTR);
3073
3074 size = (size + 3) & ~3;
3075 storeRam32(A_KMALLOC_PTR, ptr + 4 + size);
3076 storeRam32(ptr, size);
3077 return ptr + 4;
3078}
3079
3080static void psxBios_SysInitMemory() { // 08
3081 PSXBIOS_LOG("psxBios_%s %x %x\n", biosC0n[0x08], a0, a1);
3082
3083 psxBios_SysInitMemory_(a0, a1);
3084 mips_return_void_c(12);
3085}
3086
3087static void psxBios_ChangeClearRCnt() { // 0a
dc4fa8bc 3088 u32 ret;
ef79bbde 3089
ef79bbde 3090 PSXBIOS_LOG("psxBios_%s: %x, %x\n", biosC0n[0x0a], a0, a1);
ef79bbde 3091
dc4fa8bc 3092 ret = loadRam32(A_RCNT_VBL_ACK + (a0 << 2));
3093 storeRam32(A_RCNT_VBL_ACK + (a0 << 2), a1);
3094 mips_return_c(ret, 8);
ef79bbde
P
3095}
3096
7650b754 3097static void psxBios_InitDefInt() { // 0c
3098 PSXBIOS_LOG("psxBios_%s %x\n", biosC0n[0x0c], a0);
3099 // should also clear the autoack table
ea72f34a 3100 psxBios_SysEnqIntRP_(a0, 0x6d98);
7650b754 3101 mips_return_c(0, 20 + 6*2);
3102}
3103
7a8d521f 3104void psxBios_dummy() {
dc4fa8bc 3105 u32 pc = (pc0 & 0x1fffff) - 4;
3106 char **ntab = pc == 0xa0 ? biosA0n : pc == 0xb0 ? biosB0n
3107 : pc == 0xc0 ? biosC0n : NULL;
3108 PSXBIOS_LOG("unk %x call: %x ra=%x (%s)\n",
3109 pc, t1, ra, ntab ? ntab[t1 & 0xff] : "???");
3110 (void)pc; (void)ntab;
3111 mips_return_c(0, 100);
ef79bbde
P
3112}
3113
3114void (*biosA0[256])();
dc4fa8bc 3115// C0 and B0 overlap (end of C0 is start of B0)
3116void (*biosC0[256+128])();
3117void (**biosB0)() = biosC0 + 128;
ef79bbde 3118
14b3bd95 3119static void setup_mips_code()
dc4fa8bc 3120{
3121 u32 *ptr;
3122 ptr = (u32 *)&psxM[A_SYSCALL];
3123 ptr[0x00/4] = SWAPu32(0x0000000c); // syscall 0
3124 ptr[0x04/4] = SWAPu32(0x03e00008); // jr $ra
3125 ptr[0x08/4] = SWAPu32(0x00000000); // nop
3126
3127 ptr = (u32 *)&psxM[A_EXCEPTION];
3128 memset(ptr, 0, 0xc0); // nops (to be patched by games sometimes)
3129 ptr[0x10/4] = SWAPu32(0x8c1a0108); // lw $k0, (0x108) // PCB
3130 ptr[0x14/4] = SWAPu32(0x00000000); // nop
3131 ptr[0x18/4] = SWAPu32(0x8f5a0000); // lw $k0, ($k0) // TCB
3132 ptr[0x1c/4] = SWAPu32(0x00000000); // nop
3133 ptr[0x20/4] = SWAPu32(0x275a0008); // addiu $k0, $k0, 8 // regs
3134 ptr[0x24/4] = SWAPu32(0xaf5f007c); // sw $ra, 0x7c($k0)
3135 ptr[0x28/4] = SWAPu32(0xaf410004); // sw $at, 0x04($k0)
3136 ptr[0x2c/4] = SWAPu32(0xaf420008); // sw $v0, 0x08($k0)
3137 ptr[0x30/4] = SWAPu32(0xaf43000c); // sw $v1, 0x0c($k0)
3138
3139 ptr[0x60/4] = SWAPu32(0x40037000); // mfc0 $v1, EPC
3140 ptr[0x64/4] = SWAPu32(0x40026800); // mfc0 $v0, Cause
dc4fa8bc 3141 ptr[0x6c/4] = SWAPu32(0xaf430080); // sw $v1, 0x80($k0)
3142
3143 ptr[0xb0/4] = HLEOP(hleop_exception);
3144}
3145
3146static const struct {
3147 u32 addr;
3148 enum hle_op op;
3149} chainfns[] = {
3150 { 0xbfc050a4, hleop_exc0_0_1 },
3151 { 0xbfc04fbc, hleop_exc0_0_2 },
3152 { 0xbfc0506c, hleop_exc0_1_1 },
3153 { 0xbfc04dec, hleop_exc0_1_2 },
3154 { 0x1a00, hleop_exc0_2_2 },
3155 { 0x19c8, hleop_exc1_0_1 },
3156 { 0x18bc, hleop_exc1_0_2 },
3157 { 0x1990, hleop_exc1_1_1 },
3158 { 0x1858, hleop_exc1_1_2 },
3159 { 0x1958, hleop_exc1_2_1 },
3160 { 0x17f4, hleop_exc1_2_2 },
3161 { 0x1920, hleop_exc1_3_1 },
3162 { 0x1794, hleop_exc1_3_2 },
3163 { 0x2458, hleop_exc3_0_2 },
ea72f34a 3164 { 0x49bc, hleop_exc_padcard1 },
3165 { 0x4a4c, hleop_exc_padcard2 },
dc4fa8bc 3166};
3167
3168static int chain_hle_op(u32 handler)
3169{
3170 size_t i;
3171
3172 for (i = 0; i < sizeof(chainfns) / sizeof(chainfns[0]); i++)
3173 if (chainfns[i].addr == handler)
3174 return chainfns[i].op;
3175 return hleop_dummy;
3176}
3177
3178static void write_chain(u32 *d, u32 next, u32 handler1, u32 handler2)
3179{
3180 d[0] = SWAPu32(next);
3181 d[1] = SWAPu32(handler1);
3182 d[2] = SWAPu32(handler2);
3183
ea72f34a 3184 // install the hle traps
fed9fd6f 3185 if (handler1) PSXMu32ref(handler1) = HLEOP(chain_hle_op(handler1));
3186 if (handler2) PSXMu32ref(handler2) = HLEOP(chain_hle_op(handler2));
dc4fa8bc 3187}
3188
5c8119b8 3189static void setup_tt(u32 tcb_cnt, u32 evcb_cnt, u32 stack)
7650b754 3190{
3191 u32 *ram32 = (u32 *)psxM;
5c8119b8 3192 u32 s_excb = 0x20, s_evcb, s_pcb = 4, s_tcb;
7650b754 3193 u32 p_excb, p_evcb, p_pcb, p_tcb;
5c8119b8 3194 u32 i;
3195
3196 PSXBIOS_LOG("setup: tcb %u, evcb %u\n", tcb_cnt, evcb_cnt);
3197
3198 // the real bios doesn't care, but we just don't
3199 // want to crash in case of garbage parameters
3200 if (tcb_cnt > 1024) tcb_cnt = 1024;
3201 if (evcb_cnt > 1024) evcb_cnt = 1024;
3202 s_evcb = 0x1c * evcb_cnt;
3203 s_tcb = 0xc0 * tcb_cnt;
7650b754 3204
3205 memset(ram32 + 0xe000/4, 0, s_excb + s_evcb + s_pcb + s_tcb + 5*4);
3206 psxBios_SysInitMemory_(0xa000e000, 0x2000);
3207 p_excb = psxBios_SysMalloc_(s_excb);
3208 p_evcb = psxBios_SysMalloc_(s_evcb);
3209 p_pcb = psxBios_SysMalloc_(s_pcb);
3210 p_tcb = psxBios_SysMalloc_(s_tcb);
3211
3212 // "table of tables". Some games modify it
3213 assert(A_TT_ExCB == 0x0100);
3214 ram32[0x0100/4] = SWAPu32(p_excb); // ExCB - exception chains
3215 ram32[0x0104/4] = SWAPu32(s_excb); // ExCB size
3216 ram32[0x0108/4] = SWAPu32(p_pcb); // PCB - process control
3217 ram32[0x010c/4] = SWAPu32(s_pcb); // PCB size
3218 ram32[0x0110/4] = SWAPu32(p_tcb); // TCB - thread control
3219 ram32[0x0114/4] = SWAPu32(s_tcb); // TCB size
3220 ram32[0x0120/4] = SWAPu32(p_evcb); // EvCB - event control
3221 ram32[0x0124/4] = SWAPu32(s_evcb); // EvCB size
3222 ram32[0x0140/4] = SWAPu32(0x8648); // FCB - file control
3223 ram32[0x0144/4] = SWAPu32(0x02c0); // FCB size
3224 ram32[0x0150/4] = SWAPu32(0x6ee0); // DCB - device control
3225 ram32[0x0154/4] = SWAPu32(0x0320); // DCB size
3226
3227 storeRam32(p_excb + 0*4, 0x91e0); // chain0
3228 storeRam32(p_excb + 2*4, 0x6d88); // chain1
3229 storeRam32(p_excb + 4*4, 0x0000); // chain2
3230 storeRam32(p_excb + 6*4, 0x6d98); // chain3
3231
3232 storeRam32(p_pcb, p_tcb);
3233 storeRam32(p_tcb, 0x4000); // first TCB
5c8119b8 3234 for (i = 1; i < tcb_cnt; i++)
3235 storeRam32(p_tcb + sizeof(TCB) * i, 0x1000);
4d2f73bb 3236
3237 // default events
3238 storeRam32(A_CD_EVENTS + 0x00, OpenEvent(0xf0000003, 0x0010, EvMdMARK, 0));
3239 storeRam32(A_CD_EVENTS + 0x04, OpenEvent(0xf0000003, 0x0020, EvMdMARK, 0));
3240 storeRam32(A_CD_EVENTS + 0x08, OpenEvent(0xf0000003, 0x0040, EvMdMARK, 0));
3241 storeRam32(A_CD_EVENTS + 0x0c, OpenEvent(0xf0000003, 0x0080, EvMdMARK, 0));
3242 storeRam32(A_CD_EVENTS + 0x10, OpenEvent(0xf0000003, 0x8000, EvMdMARK, 0));
5c8119b8 3243
3244 storeRam32(A_CONF_EvCB, evcb_cnt);
3245 storeRam32(A_CONF_TCB, tcb_cnt);
3246 storeRam32(A_CONF_SP, stack);
7650b754 3247}
3248
14b3bd95 3249static const u32 gpu_ctl_def[] = {
3250 0x00000000, 0x01000000, 0x03000000, 0x04000000,
3251 0x05000800, 0x06c60260, 0x0703fc10, 0x08000027
3252};
3253
3254static const u32 gpu_data_def[] = {
3255 0xe100360b, 0xe2000000, 0xe3000800, 0xe4077e7f,
3256 0xe5001000, 0xe6000000,
3257 0x02000000, 0x00000000, 0x01ff03ff
3258};
3259
3260// from 1f801d80
3261static const u16 spu_config[] = {
3262 0x3fff, 0x37ef, 0x5ebc, 0x5ebc, 0x0000, 0x0000, 0x0000, 0x00a0,
3263 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0x00ff, 0x0000, 0x0000,
3264 0x0000, 0xe128, 0x0000, 0x0200, 0xf0f0, 0xc085, 0x0004, 0x0000,
3265 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
3266 0x033d, 0x0231, 0x7e00, 0x5000, 0xb400, 0xb000, 0x4c00, 0xb000,
3267 0x6000, 0x5400, 0x1ed6, 0x1a31, 0x1d14, 0x183b, 0x1bc2, 0x16b2,
3268 0x1a32, 0x15ef, 0x15ee, 0x1055, 0x1334, 0x0f2d, 0x11f6, 0x0c5d,
3269 0x1056, 0x0ae1, 0x0ae0, 0x07a2, 0x0464, 0x0232, 0x8000, 0x8000
3270};
3271
3272void psxBiosSetupBootState(void)
3273{
3274 boolean hle = Config.HLE;
3275 u32 *hw = (u32 *)psxH;
3276 int i;
3277
3278 // see also SetBootRegs()
3279 if (hle) {
3280 v0 = 1; v1 = 4;
3281 a0 = 1; a2 = a3 = 0; a3 = 0x2a;
3282 t2 = 0x2d; t4 = 0x23; t5 = 0x2b; t6 = 0xa0010000;
3283 s0 = 0xa000b870;
3284 k0 = 0xbfc0d968; k1 = 0xf1c;
3285 ra = 0xf0001234; // just to easily detect attempts to return
3286 psxRegs.CP0.n.Cause = 0x20;
3287 psxRegs.CP0.n.EPC = 0xbfc0d964; // EnterCriticalSection syscall
3288
3289 hw[0x1000/4] = SWAP32(0x1f000000);
3290 hw[0x1004/4] = SWAP32(0x1f802000);
3291 hw[0x1008/4] = SWAP32(0x0013243f);
3292 hw[0x100c/4] = SWAP32(0x00003022);
3293 hw[0x1010/4] = SWAP32(0x0013243f);
3294 hw[0x1014/4] = SWAP32(0x200931e1);
3295 hw[0x1018/4] = SWAP32(0x00020943);
3296 hw[0x101c/4] = SWAP32(0x00070777);
3297 hw[0x1020/4] = SWAP32(0x0000132c);
3298 hw[0x1060/4] = SWAP32(0x00000b88);
3299 hw[0x1070/4] = SWAP32(0x00000001);
3300 hw[0x1074/4] = SWAP32(0x0000000c);
3301 hw[0x2040/4] = SWAP32(0x00000900);
3302 }
3303
3304 hw[0x10a0/4] = SWAP32(0x00ffffff);
3305 hw[0x10a8/4] = SWAP32(0x00000401);
3306 hw[0x10b0/4] = SWAP32(0x0008b000);
3307 hw[0x10b4/4] = SWAP32(0x00010200);
3308 hw[0x10e0/4] = SWAP32(0x000eccf4);
3309 hw[0x10e4/4] = SWAP32(0x00000400);
3310 hw[0x10e8/4] = SWAP32(0x00000002);
3311 hw[0x10f0/4] = SWAP32(0x00009099);
3312 hw[0x10f4/4] = SWAP32(0x8c8c0000);
3313
3314 if (hle) {
3315 psxRcntWmode(0, 0);
3316 psxRcntWmode(1, 0);
3317 psxRcntWmode(2, 0);
3318 }
3319
3320 // gpu
3321 for (i = 0; i < sizeof(gpu_ctl_def) / sizeof(gpu_ctl_def[0]); i++)
3322 GPU_writeStatus(gpu_ctl_def[i]);
3323 for (i = 0; i < sizeof(gpu_data_def) / sizeof(gpu_data_def[0]); i++)
3324 GPU_writeData(gpu_data_def[i]);
14b3bd95 3325
3326 // spu
3327 for (i = 0x1f801d80; i < sizeof(spu_config) / sizeof(spu_config[0]); i++)
3328 SPU_writeRegister(0x1f801d80 + i*2, spu_config[i], psxRegs.cycle);
3329}
3330
0890ae15 3331static void hleExc0_0_1();
3332static void hleExc0_0_2();
3333static void hleExc0_1_1();
3334static void hleExc0_1_2();
3335
14b3bd95 3336#include "sjisfont.h"
3337
ef79bbde 3338void psxBiosInit() {
4d2f73bb 3339 u32 *ptr, *ram32, *rom32;
27f734f9 3340 char *romc;
ef79bbde
P
3341 int i;
3342 uLongf len;
3343
de74f599 3344 psxRegs.biosBranchCheck = ~0;
3345
dc4fa8bc 3346 memset(psxM, 0, 0x10000);
ef79bbde
P
3347 for(i = 0; i < 256; i++) {
3348 biosA0[i] = NULL;
3349 biosB0[i] = NULL;
3350 biosC0[i] = NULL;
3351 }
a94ccc7f 3352 biosA0[0x03] = biosB0[0x35] = psxBios_write_psxout;
3353 biosA0[0x3c] = biosB0[0x3d] = psxBios_putchar_psxout;
3354 biosA0[0x3e] = biosB0[0x3f] = psxBios_puts_psxout;
3355 biosA0[0x3f] = psxBios_printf_psxout;
ef79bbde 3356
42eb665e 3357 if (!Config.HLE) {
3358 char verstr[0x24+1];
3359 rom32 = (u32 *)psxR;
3360 memcpy(verstr, psxR + 0x12c, 0x24);
3361 verstr[0x24] = 0;
3362 SysPrintf("BIOS: %08x, '%s', '%c'\n", SWAP32(rom32[0x100/4]),
3363 verstr, psxR[0x7ff52]);
3364 return;
3365 }
ef79bbde
P
3366
3367 for(i = 0; i < 256; i++) {
3368 if (biosA0[i] == NULL) biosA0[i] = psxBios_dummy;
3369 if (biosB0[i] == NULL) biosB0[i] = psxBios_dummy;
3370 if (biosC0[i] == NULL) biosC0[i] = psxBios_dummy;
3371 }
3372
3373 biosA0[0x00] = psxBios_open;
3374 biosA0[0x01] = psxBios_lseek;
3375 biosA0[0x02] = psxBios_read;
3376 biosA0[0x03] = psxBios_write;
3377 biosA0[0x04] = psxBios_close;
3378 //biosA0[0x05] = psxBios_ioctl;
3379 //biosA0[0x06] = psxBios_exit;
3380 //biosA0[0x07] = psxBios_sys_a0_07;
324cec89 3381 biosA0[0x08] = psxBios_getc;
3382 biosA0[0x09] = psxBios_putc;
ba11675c 3383 biosA0[0x0a] = psxBios_todigit;
ef79bbde
P
3384 //biosA0[0x0b] = psxBios_atof;
3385 //biosA0[0x0c] = psxBios_strtoul;
3386 //biosA0[0x0d] = psxBios_strtol;
3387 biosA0[0x0e] = psxBios_abs;
3388 biosA0[0x0f] = psxBios_labs;
3389 biosA0[0x10] = psxBios_atoi;
3390 biosA0[0x11] = psxBios_atol;
3391 //biosA0[0x12] = psxBios_atob;
3392 biosA0[0x13] = psxBios_setjmp;
3393 biosA0[0x14] = psxBios_longjmp;
3394 biosA0[0x15] = psxBios_strcat;
3395 biosA0[0x16] = psxBios_strncat;
3396 biosA0[0x17] = psxBios_strcmp;
3397 biosA0[0x18] = psxBios_strncmp;
3398 biosA0[0x19] = psxBios_strcpy;
3399 biosA0[0x1a] = psxBios_strncpy;
3400 biosA0[0x1b] = psxBios_strlen;
3401 biosA0[0x1c] = psxBios_index;
3402 biosA0[0x1d] = psxBios_rindex;
3403 biosA0[0x1e] = psxBios_strchr;
3404 biosA0[0x1f] = psxBios_strrchr;
3405 biosA0[0x20] = psxBios_strpbrk;
3406 biosA0[0x21] = psxBios_strspn;
3407 biosA0[0x22] = psxBios_strcspn;
3408 biosA0[0x23] = psxBios_strtok;
3409 biosA0[0x24] = psxBios_strstr;
3410 biosA0[0x25] = psxBios_toupper;
3411 biosA0[0x26] = psxBios_tolower;
3412 biosA0[0x27] = psxBios_bcopy;
3413 biosA0[0x28] = psxBios_bzero;
3414 biosA0[0x29] = psxBios_bcmp;
3415 biosA0[0x2a] = psxBios_memcpy;
3416 biosA0[0x2b] = psxBios_memset;
3417 biosA0[0x2c] = psxBios_memmove;
3418 biosA0[0x2d] = psxBios_memcmp;
3419 biosA0[0x2e] = psxBios_memchr;
3420 biosA0[0x2f] = psxBios_rand;
3421 biosA0[0x30] = psxBios_srand;
3422 biosA0[0x31] = psxBios_qsort;
3423 //biosA0[0x32] = psxBios_strtod;
3424 biosA0[0x33] = psxBios_malloc;
3425 biosA0[0x34] = psxBios_free;
3426 //biosA0[0x35] = psxBios_lsearch;
3427 //biosA0[0x36] = psxBios_bsearch;
3428 biosA0[0x37] = psxBios_calloc;
3429 biosA0[0x38] = psxBios_realloc;
3430 biosA0[0x39] = psxBios_InitHeap;
3431 //biosA0[0x3a] = psxBios__exit;
3432 biosA0[0x3b] = psxBios_getchar;
7a8d521f 3433 biosA0[0x3c] = psxBios_putchar;
ef79bbde 3434 //biosA0[0x3d] = psxBios_gets;
31cd6032 3435 biosA0[0x3e] = psxBios_puts;
3436 biosA0[0x3f] = psxBios_printf;
dc4fa8bc 3437 biosA0[0x40] = psxBios_SystemErrorUnresolvedException;
ef79bbde
P
3438 //biosA0[0x41] = psxBios_LoadTest;
3439 biosA0[0x42] = psxBios_Load;
3440 biosA0[0x43] = psxBios_Exec;
3441 biosA0[0x44] = psxBios_FlushCache;
3442 //biosA0[0x45] = psxBios_InstallInterruptHandler;
3443 biosA0[0x46] = psxBios_GPU_dw;
3444 biosA0[0x47] = psxBios_mem2vram;
3445 biosA0[0x48] = psxBios_SendGPU;
3446 biosA0[0x49] = psxBios_GPU_cw;
3447 biosA0[0x4a] = psxBios_GPU_cwb;
3448 biosA0[0x4b] = psxBios_GPU_SendPackets;
3449 biosA0[0x4c] = psxBios_sys_a0_4c;
3450 biosA0[0x4d] = psxBios_GPU_GetGPUStatus;
7a8d521f 3451 //biosA0[0x4e] = psxBios_GPU_sync;
ef79bbde
P
3452 //biosA0[0x4f] = psxBios_sys_a0_4f;
3453 //biosA0[0x50] = psxBios_sys_a0_50;
3454 biosA0[0x51] = psxBios_LoadExec;
3455 //biosA0[0x52] = psxBios_GetSysSp;
3456 //biosA0[0x53] = psxBios_sys_a0_53;
3457 //biosA0[0x54] = psxBios__96_init_a54;
3458 //biosA0[0x55] = psxBios__bu_init_a55;
dc4fa8bc 3459 biosA0[0x56] = psxBios_CdRemove;
ef79bbde
P
3460 //biosA0[0x57] = psxBios_sys_a0_57;
3461 //biosA0[0x58] = psxBios_sys_a0_58;
3462 //biosA0[0x59] = psxBios_sys_a0_59;
3463 //biosA0[0x5a] = psxBios_sys_a0_5a;
3464 //biosA0[0x5b] = psxBios_dev_tty_init;
3465 //biosA0[0x5c] = psxBios_dev_tty_open;
3466 //biosA0[0x5d] = psxBios_sys_a0_5d;
3467 //biosA0[0x5e] = psxBios_dev_tty_ioctl;
3468 //biosA0[0x5f] = psxBios_dev_cd_open;
3469 //biosA0[0x60] = psxBios_dev_cd_read;
3470 //biosA0[0x61] = psxBios_dev_cd_close;
3471 //biosA0[0x62] = psxBios_dev_cd_firstfile;
3472 //biosA0[0x63] = psxBios_dev_cd_nextfile;
3473 //biosA0[0x64] = psxBios_dev_cd_chdir;
3474 //biosA0[0x65] = psxBios_dev_card_open;
3475 //biosA0[0x66] = psxBios_dev_card_read;
3476 //biosA0[0x67] = psxBios_dev_card_write;
3477 //biosA0[0x68] = psxBios_dev_card_close;
3478 //biosA0[0x69] = psxBios_dev_card_firstfile;
3479 //biosA0[0x6a] = psxBios_dev_card_nextfile;
3480 //biosA0[0x6b] = psxBios_dev_card_erase;
3481 //biosA0[0x6c] = psxBios_dev_card_undelete;
3482 //biosA0[0x6d] = psxBios_dev_card_format;
3483 //biosA0[0x6e] = psxBios_dev_card_rename;
3484 //biosA0[0x6f] = psxBios_dev_card_6f;
3485 biosA0[0x70] = psxBios__bu_init;
3486 biosA0[0x71] = psxBios__96_init;
dc4fa8bc 3487 biosA0[0x72] = psxBios_CdRemove;
ef79bbde
P
3488 //biosA0[0x73] = psxBios_sys_a0_73;
3489 //biosA0[0x74] = psxBios_sys_a0_74;
3490 //biosA0[0x75] = psxBios_sys_a0_75;
3491 //biosA0[0x76] = psxBios_sys_a0_76;
3492 //biosA0[0x77] = psxBios_sys_a0_77;
3493 //biosA0[0x78] = psxBios__96_CdSeekL;
3494 //biosA0[0x79] = psxBios_sys_a0_79;
3495 //biosA0[0x7a] = psxBios_sys_a0_7a;
3496 //biosA0[0x7b] = psxBios_sys_a0_7b;
3497 //biosA0[0x7c] = psxBios__96_CdGetStatus;
3498 //biosA0[0x7d] = psxBios_sys_a0_7d;
3499 //biosA0[0x7e] = psxBios__96_CdRead;
3500 //biosA0[0x7f] = psxBios_sys_a0_7f;
3501 //biosA0[0x80] = psxBios_sys_a0_80;
3502 //biosA0[0x81] = psxBios_sys_a0_81;
7a8d521f 3503 //biosA0[0x82] = psxBios_sys_a0_82;
ef79bbde
P
3504 //biosA0[0x83] = psxBios_sys_a0_83;
3505 //biosA0[0x84] = psxBios_sys_a0_84;
7a8d521f 3506 //biosA0[0x85] = psxBios__96_CdStop;
ef79bbde
P
3507 //biosA0[0x86] = psxBios_sys_a0_86;
3508 //biosA0[0x87] = psxBios_sys_a0_87;
3509 //biosA0[0x88] = psxBios_sys_a0_88;
3510 //biosA0[0x89] = psxBios_sys_a0_89;
3511 //biosA0[0x8a] = psxBios_sys_a0_8a;
3512 //biosA0[0x8b] = psxBios_sys_a0_8b;
3513 //biosA0[0x8c] = psxBios_sys_a0_8c;
3514 //biosA0[0x8d] = psxBios_sys_a0_8d;
3515 //biosA0[0x8e] = psxBios_sys_a0_8e;
3516 //biosA0[0x8f] = psxBios_sys_a0_8f;
dc4fa8bc 3517 biosA0[0x90] = hleExc0_1_2;
3518 biosA0[0x91] = hleExc0_0_2;
3519 biosA0[0x92] = hleExc0_1_1;
3520 biosA0[0x93] = hleExc0_0_1;
ef79bbde
P
3521 //biosA0[0x94] = psxBios_sys_a0_94;
3522 //biosA0[0x95] = psxBios_sys_a0_95;
3523 //biosA0[0x96] = psxBios_AddCDROMDevice;
3524 //biosA0[0x97] = psxBios_AddMemCardDevide;
3525 //biosA0[0x98] = psxBios_DisableKernelIORedirection;
3526 //biosA0[0x99] = psxBios_EnableKernelIORedirection;
3527 //biosA0[0x9a] = psxBios_sys_a0_9a;
3528 //biosA0[0x9b] = psxBios_sys_a0_9b;
5c8119b8 3529 biosA0[0x9c] = psxBios_SetConf;
3530 biosA0[0x9d] = psxBios_GetConf;
ef79bbde
P
3531 //biosA0[0x9e] = psxBios_sys_a0_9e;
3532 biosA0[0x9f] = psxBios_SetMem;
3533 //biosA0[0xa0] = psxBios__boot;
3534 //biosA0[0xa1] = psxBios_SystemError;
3535 //biosA0[0xa2] = psxBios_EnqueueCdIntr;
dc4fa8bc 3536 biosA0[0xa3] = psxBios_DequeueCdIntr;
ef79bbde
P
3537 //biosA0[0xa4] = psxBios_sys_a0_a4;
3538 //biosA0[0xa5] = psxBios_ReadSector;
18dd7e9e 3539 biosA0[0xa6] = psxBios_get_cd_status;
ef79bbde
P
3540 //biosA0[0xa7] = psxBios_bufs_cb_0;
3541 //biosA0[0xa8] = psxBios_bufs_cb_1;
3542 //biosA0[0xa9] = psxBios_bufs_cb_2;
3543 //biosA0[0xaa] = psxBios_bufs_cb_3;
3544 biosA0[0xab] = psxBios__card_info;
3545 biosA0[0xac] = psxBios__card_load;
3546 //biosA0[0axd] = psxBios__card_auto;
3547 //biosA0[0xae] = psxBios_bufs_cd_4;
3548 //biosA0[0xaf] = psxBios_sys_a0_af;
3549 //biosA0[0xb0] = psxBios_sys_a0_b0;
3550 //biosA0[0xb1] = psxBios_sys_a0_b1;
3551 //biosA0[0xb2] = psxBios_do_a_long_jmp
3552 //biosA0[0xb3] = psxBios_sys_a0_b3;
31cd6032 3553 biosA0[0xb4] = psxBios_GetSystemInfo;
ef79bbde 3554//*******************B0 CALLS****************************
7650b754 3555 biosB0[0x00] = psxBios_SysMalloc;
ef79bbde
P
3556 //biosB0[0x01] = psxBios_sys_b0_01;
3557 biosB0[0x02] = psxBios_SetRCnt;
3558 biosB0[0x03] = psxBios_GetRCnt;
3559 biosB0[0x04] = psxBios_StartRCnt;
3560 biosB0[0x05] = psxBios_StopRCnt;
3561 biosB0[0x06] = psxBios_ResetRCnt;
3562 biosB0[0x07] = psxBios_DeliverEvent;
3563 biosB0[0x08] = psxBios_OpenEvent;
3564 biosB0[0x09] = psxBios_CloseEvent;
3565 biosB0[0x0a] = psxBios_WaitEvent;
3566 biosB0[0x0b] = psxBios_TestEvent;
3567 biosB0[0x0c] = psxBios_EnableEvent;
3568 biosB0[0x0d] = psxBios_DisableEvent;
3569 biosB0[0x0e] = psxBios_OpenTh;
3570 biosB0[0x0f] = psxBios_CloseTh;
3571 biosB0[0x10] = psxBios_ChangeTh;
3572 //biosB0[0x11] = psxBios_psxBios_b0_11;
3573 biosB0[0x12] = psxBios_InitPAD;
3574 biosB0[0x13] = psxBios_StartPAD;
3575 biosB0[0x14] = psxBios_StopPAD;
3576 biosB0[0x15] = psxBios_PAD_init;
3577 biosB0[0x16] = psxBios_PAD_dr;
3578 biosB0[0x17] = psxBios_ReturnFromException;
3579 biosB0[0x18] = psxBios_ResetEntryInt;
3580 biosB0[0x19] = psxBios_HookEntryInt;
3581 //biosB0[0x1a] = psxBios_sys_b0_1a;
3582 //biosB0[0x1b] = psxBios_sys_b0_1b;
3583 //biosB0[0x1c] = psxBios_sys_b0_1c;
3584 //biosB0[0x1d] = psxBios_sys_b0_1d;
3585 //biosB0[0x1e] = psxBios_sys_b0_1e;
3586 //biosB0[0x1f] = psxBios_sys_b0_1f;
3587 biosB0[0x20] = psxBios_UnDeliverEvent;
3588 //biosB0[0x21] = psxBios_sys_b0_21;
3589 //biosB0[0x22] = psxBios_sys_b0_22;
3590 //biosB0[0x23] = psxBios_sys_b0_23;
3591 //biosB0[0x24] = psxBios_sys_b0_24;
3592 //biosB0[0x25] = psxBios_sys_b0_25;
3593 //biosB0[0x26] = psxBios_sys_b0_26;
3594 //biosB0[0x27] = psxBios_sys_b0_27;
3595 //biosB0[0x28] = psxBios_sys_b0_28;
3596 //biosB0[0x29] = psxBios_sys_b0_29;
3597 //biosB0[0x2a] = psxBios_sys_b0_2a;
3598 //biosB0[0x2b] = psxBios_sys_b0_2b;
3599 //biosB0[0x2c] = psxBios_sys_b0_2c;
3600 //biosB0[0x2d] = psxBios_sys_b0_2d;
3601 //biosB0[0x2e] = psxBios_sys_b0_2e;
3602 //biosB0[0x2f] = psxBios_sys_b0_2f;
3603 //biosB0[0x30] = psxBios_sys_b0_30;
3604 //biosB0[0x31] = psxBios_sys_b0_31;
3605 biosB0[0x32] = psxBios_open;
3606 biosB0[0x33] = psxBios_lseek;
3607 biosB0[0x34] = psxBios_read;
3608 biosB0[0x35] = psxBios_write;
3609 biosB0[0x36] = psxBios_close;
3610 //biosB0[0x37] = psxBios_ioctl;
3611 //biosB0[0x38] = psxBios_exit;
3612 //biosB0[0x39] = psxBios_sys_b0_39;
3613 //biosB0[0x3a] = psxBios_getc;
3614 //biosB0[0x3b] = psxBios_putc;
3615 biosB0[0x3c] = psxBios_getchar;
31cd6032 3616 biosB0[0x3d] = psxBios_putchar;
ef79bbde 3617 //biosB0[0x3e] = psxBios_gets;
31cd6032 3618 biosB0[0x3f] = psxBios_puts;
0a50313e 3619 biosB0[0x40] = psxBios_cd;
e7e1f572 3620 biosB0[0x41] = psxBios_format;
ef79bbde
P
3621 biosB0[0x42] = psxBios_firstfile;
3622 biosB0[0x43] = psxBios_nextfile;
3623 biosB0[0x44] = psxBios_rename;
3624 biosB0[0x45] = psxBios_delete;
3625 //biosB0[0x46] = psxBios_undelete;
3626 //biosB0[0x47] = psxBios_AddDevice;
3627 //biosB0[0x48] = psxBios_RemoteDevice;
3628 //biosB0[0x49] = psxBios_PrintInstalledDevices;
3629 biosB0[0x4a] = psxBios_InitCARD;
3630 biosB0[0x4b] = psxBios_StartCARD;
3631 biosB0[0x4c] = psxBios_StopCARD;
3632 //biosB0[0x4d] = psxBios_sys_b0_4d;
3633 biosB0[0x4e] = psxBios__card_write;
3634 biosB0[0x4f] = psxBios__card_read;
3635 biosB0[0x50] = psxBios__new_card;
3636 biosB0[0x51] = psxBios_Krom2RawAdd;
3637 //biosB0[0x52] = psxBios_sys_b0_52;
3638 //biosB0[0x53] = psxBios_sys_b0_53;
3639 //biosB0[0x54] = psxBios__get_errno;
002b2f7d 3640 biosB0[0x55] = psxBios__get_error;
ef79bbde
P
3641 biosB0[0x56] = psxBios_GetC0Table;
3642 biosB0[0x57] = psxBios_GetB0Table;
e9fda093 3643 biosB0[0x58] = psxBios__card_chan;
ef79bbde
P
3644 //biosB0[0x59] = psxBios_sys_b0_59;
3645 //biosB0[0x5a] = psxBios_sys_b0_5a;
3646 biosB0[0x5b] = psxBios_ChangeClearPad;
21af3ff6 3647 biosB0[0x5c] = psxBios__card_status;
5f652aa9 3648 biosB0[0x5d] = psxBios__card_wait;
ef79bbde 3649//*******************C0 CALLS****************************
7650b754 3650 biosC0[0x00] = psxBios_InitRCnt;
3651 biosC0[0x01] = psxBios_InitException;
ef79bbde
P
3652 biosC0[0x02] = psxBios_SysEnqIntRP;
3653 biosC0[0x03] = psxBios_SysDeqIntRP;
4d2f73bb 3654 biosC0[0x04] = psxBios_get_free_EvCB_slot;
ef79bbde
P
3655 //biosC0[0x05] = psxBios_get_free_TCB_slot;
3656 //biosC0[0x06] = psxBios_ExceptionHandler;
3657 //biosC0[0x07] = psxBios_InstallExeptionHandler;
7650b754 3658 biosC0[0x08] = psxBios_SysInitMemory;
ef79bbde 3659 //biosC0[0x09] = psxBios_SysInitKMem;
7a8d521f 3660 biosC0[0x0a] = psxBios_ChangeClearRCnt;
ef79bbde 3661 //biosC0[0x0b] = psxBios_SystemError;
7650b754 3662 biosC0[0x0c] = psxBios_InitDefInt;
ef79bbde
P
3663 //biosC0[0x0d] = psxBios_sys_c0_0d;
3664 //biosC0[0x0e] = psxBios_sys_c0_0e;
3665 //biosC0[0x0f] = psxBios_sys_c0_0f;
3666 //biosC0[0x10] = psxBios_sys_c0_10;
3667 //biosC0[0x11] = psxBios_sys_c0_11;
3668 //biosC0[0x12] = psxBios_InstallDevices;
3669 //biosC0[0x13] = psxBios_FlushStfInOutPut;
3670 //biosC0[0x14] = psxBios_sys_c0_14;
3671 //biosC0[0x15] = psxBios__cdevinput;
3672 //biosC0[0x16] = psxBios__cdevscan;
3673 //biosC0[0x17] = psxBios__circgetc;
3674 //biosC0[0x18] = psxBios__circputc;
3675 //biosC0[0x19] = psxBios_ioabort;
3676 //biosC0[0x1a] = psxBios_sys_c0_1a
3677 //biosC0[0x1b] = psxBios_KernelRedirect;
3678 //biosC0[0x1c] = psxBios_PatchAOTable;
3679//************** THE END ***************************************
3680/**/
ef79bbde 3681
c62b43c9 3682 memset(FDesc, 0, sizeof(FDesc));
0a50313e 3683 memset(cdir, 0, sizeof(cdir));
3684 floodchk = 0;
c62b43c9 3685
31cd6032 3686 // somewhat pretend to be a SCPH1001 BIOS
3687 // some games look for these and take an exception if they're missing
4d2f73bb 3688 rom32 = (u32 *)psxR;
3689 rom32[0x100/4] = SWAP32(0x19951204);
3690 rom32[0x104/4] = SWAP32(3);
27f734f9 3691 romc = (char *)psxR;
3692 strcpy(romc + 0x108, "PCSX authors");
3693 strcpy(romc + 0x12c, "CEX-3000 PCSX HLE"); // see psxBios_GetSystemInfo
3694 strcpy(romc + 0x7ff32, "System ROM Version 2.2 12/04/95 A");
3695 strcpy(romc + 0x7ff54, "GPL-2.0-or-later");
4d2f73bb 3696
ef79bbde
P
3697 // fonts
3698 len = 0x80000 - 0x66000;
3699 uncompress((Bytef *)(psxR + 0x66000), &len, font_8140, sizeof(font_8140));
3700 len = 0x80000 - 0x69d68;
3701 uncompress((Bytef *)(psxR + 0x69d68), &len, font_889f, sizeof(font_889f));
3702
fed9fd6f 3703 // trap attempts to call bios directly
3704 rom32[0x00000/4] = HLEOP(hleop_dummy);
3705 rom32[0x00180/4] = HLEOP(hleop_dummy);
3706 rom32[0x3fffc/4] = HLEOP(hleop_dummy);
3707 rom32[0x65ffc/4] = HLEOP(hleop_dummy);
3708 rom32[0x7ff2c/4] = HLEOP(hleop_dummy);
3709
bf643fd9 3710 /* Some games like R-Types, CTR, Fade to Black read from adress 0x00000000 due to uninitialized pointers.
3711 See Garbage Area at Address 00000000h in Nocash PSX Specfications for more information.
339cc5b6 3712 Here are some examples of games not working with this fix in place :
3713 R-type won't get past the Irem logo if not implemented.
3714 Crash Team Racing will softlock after the Sony logo.
bf643fd9 3715 */
7a8d521f 3716
dc4fa8bc 3717 ram32 = (u32 *)psxM;
3718 ram32[0x0000/4] = SWAPu32(0x00000003); // lui $k0, 0 (overwritten by 3)
3719 ram32[0x0004/4] = SWAPu32(0x275a0000 + A_EXCEPTION); // addiu $k0, $k0, 0xc80
3720 ram32[0x0008/4] = SWAPu32(0x03400008); // jr $k0
3721 ram32[0x000c/4] = SWAPu32(0x00000000); // nop
3722
3723 ram32[0x0060/4] = SWAPu32(0x00000002); // ram size?
3724 ram32[0x0068/4] = SWAPu32(0x000000ff); // unknown
3725
3726 ram32[0x0080/4] = SWAPu32(0x3c1a0000); // lui $k0, 0 // exception vector
3727 ram32[0x0084/4] = SWAPu32(0x275a0000 + A_EXCEPTION); // addiu $k0, $k0, 0xc80
3728 ram32[0x0088/4] = SWAPu32(0x03400008); // jr $k0
3729 ram32[0x008c/4] = SWAPu32(0x00000000); // nop
3730
3731 ram32[0x00a0/4] = HLEOP(hleop_a0);
3732 ram32[0x00b0/4] = HLEOP(hleop_b0);
3733 ram32[0x00c0/4] = HLEOP(hleop_c0);
3734
5c8119b8 3735 setup_tt(4, 16, 0x801fff00);
3736 DeliverEvent(0xf0000003, 0x0010);
dc4fa8bc 3737
3738 ram32[0x6ee0/4] = SWAPu32(0x0000eff0); // DCB
3739 strcpy((char *)&ram32[0xeff0/4], "bu");
3740
3741 // default exception handler chains
3742 write_chain(&ram32[0x91e0/4], 0x91d0, 0xbfc050a4, 0xbfc04fbc); // chain0.e0
3743 write_chain(&ram32[0x91d0/4], 0x6da8, 0xbfc0506c, 0xbfc04dec); // chain0.e1
3744 write_chain(&ram32[0x6da8/4], 0, 0, 0x1a00); // chain0.e2
3745 write_chain(&ram32[0x6d88/4], 0x6d78, 0x19c8, 0x18bc); // chain1.e0
3746 write_chain(&ram32[0x6d78/4], 0x6d68, 0x1990, 0x1858); // chain1.e1
3747 write_chain(&ram32[0x6d68/4], 0x6d58, 0x1958, 0x17f4); // chain1.e2
3748 write_chain(&ram32[0x6d58/4], 0, 0x1920, 0x1794); // chain1.e3
3749 write_chain(&ram32[0x6d98/4], 0, 0, 0x2458); // chain3.e0
3750
3751 setup_mips_code();
3752
3753 // fill the api jumptables with fake entries as some games patch them
3754 // (or rather the funcs listed there)
3755 ptr = (u32 *)&psxM[A_A0_TABLE];
3756 for (i = 0; i < 256; i++)
0890ae15 3757 ptr[i] = SWAP32(A_A0_DUMMY);
dc4fa8bc 3758
3759 ptr = (u32 *)&psxM[A_B0_TABLE];
3760 for (i = 0; i < 256; i++)
0890ae15 3761 ptr[i] = SWAP32(A_B0_DUMMY);
dc4fa8bc 3762 // B(5b) is special because games patch (sometimes even jump to)
3763 // code at fixed offsets from it, nocash lists offsets:
3764 // patch: +3d8, +4dc, +594, +62c, +9c8, +1988
3765 // call: +7a0=4b70, +884=4c54, +894=4c64
0890ae15 3766 ptr[0x5b] = SWAP32(A_B0_5B_DUMMY); // 0x43d0
ea72f34a 3767 ram32[0x4b70/4] = SWAP32(0x03e00008); // jr $ra // setPadOutputBuf
3768
3769 ram32[0x4c54/4] = SWAP32(0x240e0001); // mov $t6, 1
3770 ram32[0x4c58/4] = SWAP32(0x03e00008); // jr $ra
3771 ram32[0x4c5c/4] = SWAP32(0xac0e0000 + A_PAD_IRQR_ENA); // sw $t6, ...
3772
dc4fa8bc 3773 ram32[0x4c64/4] = SWAP32(0x03e00008); // jr $ra
ea72f34a 3774 ram32[0x4c68/4] = SWAP32(0xac000000 + A_PAD_IRQR_ENA); // sw $0, ...
dc4fa8bc 3775
3776 ptr = (u32 *)&psxM[A_C0_TABLE];
3777 for (i = 0; i < 256/2; i++)
0890ae15 3778 ptr[i] = SWAP32(A_C0_DUMMY);
dc4fa8bc 3779 ptr[6] = SWAP32(A_EXCEPTION);
3780
3781 // more HLE traps
0890ae15 3782 ram32[A_A0_DUMMY/4] = HLEOP(hleop_dummy);
3783 ram32[A_B0_DUMMY/4] = HLEOP(hleop_dummy);
3784 ram32[A_C0_DUMMY/4] = HLEOP(hleop_dummy);
3785 ram32[A_B0_5B_DUMMY/4] = HLEOP(hleop_dummy);
dc4fa8bc 3786 ram32[0x8000/4] = HLEOP(hleop_execret);
3787
3788 ram32[A_EEXIT_PTR/4] = SWAP32(A_EEXIT_DEF);
3789 ram32[A_EXC_SP/4] = SWAP32(A_EXC_STACK);
3790 ram32[A_RCNT_VBL_ACK/4 + 0] = SWAP32(1);
3791 ram32[A_RCNT_VBL_ACK/4 + 1] = SWAP32(1);
3792 ram32[A_RCNT_VBL_ACK/4 + 2] = SWAP32(1);
3793 ram32[A_RCNT_VBL_ACK/4 + 3] = SWAP32(1);
7c3332fb 3794 ram32[A_RND_SEED/4] = SWAPu32(0x24040001); // was 0xac20cc00
ef79bbde
P
3795}
3796
3797void psxBiosShutdown() {
3798}
3799
5c8119b8 3800void psxBiosCnfLoaded(u32 tcb_cnt, u32 evcb_cnt, u32 stack) {
3801 if (stack == 0)
3802 stack = 0x801FFF00;
3803 if (tcb_cnt != 4 || evcb_cnt != 16) {
3804 setup_tt(tcb_cnt, evcb_cnt, stack);
3805 DeliverEvent(0xf0000003, 0x0010);
3806 }
3807 storeRam32(A_CONF_SP, stack);
dc4fa8bc 3808}
3809
ef79bbde 3810#define psxBios_PADpoll(pad) { \
2db412ad 3811 int i, more_data = 0; \
8aecce15 3812 PAD##pad##_startPoll(pad); \
2db412ad 3813 pad_buf##pad[1] = PAD##pad##_poll(0x42, &more_data); \
8aecce15 3814 pad_buf##pad[0] = more_data ? 0 : 0xff; \
3815 PAD##pad##_poll(0, &more_data); \
ef79bbde 3816 i = 2; \
2db412ad 3817 while (more_data) { \
3818 pad_buf##pad[i++] = PAD##pad##_poll(0, &more_data); \
ef79bbde
P
3819 } \
3820}
3821
dc4fa8bc 3822static void handle_chain_x_x_1(u32 enable, u32 irqbit)
3823{
3824 use_cycles(10);
3825 if (enable) {
3826 psxHwWrite16(0x1f801070, ~(1u << irqbit));
3827 psxBios_ReturnFromException();
3828 }
3829 else
3830 pc0 = ra;
3831}
ef79bbde 3832
dc4fa8bc 3833// hleExc0_{0,1}* are usually removed by A(56)/A(72) on the game's startup,
3834// so this is only partially implemented
0890ae15 3835static void hleExc0_0_1() // A(93h) - CdromDmaIrqFunc2
dc4fa8bc 3836{
3837 u32 cdrom_dma_ack_enable = 1; // a000b93c
3838 handle_chain_x_x_1(cdrom_dma_ack_enable, 3); // IRQ3 DMA
3839}
ef79bbde 3840
0890ae15 3841static void hleExc0_0_2() // A(91h) - CdromDmaIrqFunc1
dc4fa8bc 3842{
3843 u32 ret = 0;
3844 //PSXBIOS_LOG("%s\n", __func__);
ef79bbde 3845
dc4fa8bc 3846 if (psxHu32(0x1074) & psxHu32(0x1070) & 8) { // IRQ3 DMA
3847 psxHwWrite32(0x1f8010f4, (psxHu32(0x10f4) & 0xffffff) | 0x88000000);
3848 //if (--cdrom_irq_counter == 0) // 0xa0009180
4d2f73bb 3849 // DeliverEvent(0xf0000003, 0x10);
dc4fa8bc 3850 use_cycles(22);
3851 ret = 1;
3852 }
3853 mips_return_c(ret, 20);
3854}
ef79bbde 3855
0890ae15 3856static void hleExc0_1_1() // A(92h) - CdromIoIrqFunc2
dc4fa8bc 3857{
3858 u32 cdrom_irq_ack_enable = 1; // a000b938
3859 handle_chain_x_x_1(cdrom_irq_ack_enable, 2); // IRQ2 cdrom
3860}
ef79bbde 3861
0890ae15 3862static void hleExc0_1_2() // A(90h) - CdromIoIrqFunc1
dc4fa8bc 3863{
3864 u32 ret = 0;
3865 if (psxHu32(0x1074) & psxHu32(0x1070) & 4) { // IRQ2 cdrom
3866 PSXBIOS_LOG("%s TODO\n", __func__);
3867 ret = 1;
3868 }
3869 mips_return_c(ret, 20);
3870}
ef79bbde 3871
0890ae15 3872static void hleExc0_2_2_syscall() // not in any A/B/C table
dc4fa8bc 3873{
dc4fa8bc 3874 u32 tcbPtr = loadRam32(A_TT_PCB);
3875 TCB *tcb = loadRam32ptr(tcbPtr);
7c3332fb 3876 u32 code = (SWAP32(tcb->cause) & 0x3c) >> 2;
dc4fa8bc 3877
3878 if (code != R3000E_Syscall) {
3879 if (code != 0) {
4d2f73bb 3880 DeliverEvent(0xf0000010, 0x1000);
31cd6032 3881 //psxBios_SystemErrorUnresolvedException();
ef79bbde 3882 }
dc4fa8bc 3883 mips_return_c(0, 17);
3884 return;
ef79bbde
P
3885 }
3886
4d4e34c6 3887 //printf("%s c=%d a0=%d\n", __func__, code, SWAP32(tcb->reg[4]));
dc4fa8bc 3888 tcb->epc += SWAP32(4);
4d4e34c6 3889 switch (SWAP32(tcb->reg[4])) { // a0
dc4fa8bc 3890 case 0: // noop
3891 break;
ef79bbde 3892
dc4fa8bc 3893 case 1: { // EnterCritical - disable irqs
3894 u32 was_enabled = ((SWAP32(tcb->sr) & 0x404) == 0x404);
3895 tcb->reg[2] = SWAP32(was_enabled);
3896 tcb->sr &= SWAP32(~0x404);
3897 break;
3898 }
3899 case 2: // ExitCritical - enable irqs
3900 tcb->sr |= SWAP32(0x404);
3901 break;
3902
3903 case 3: { // ChangeThreadSubFunction
3904 u32 tcbPtr = loadRam32(A_TT_PCB);
4d4e34c6 3905 storeRam32(tcbPtr, SWAP32(tcb->reg[5])); // a1
dc4fa8bc 3906 break;
ef79bbde 3907 }
dc4fa8bc 3908 default:
4d2f73bb 3909 DeliverEvent(0xf0000010, 0x4000);
dc4fa8bc 3910 break;
ef79bbde 3911 }
dc4fa8bc 3912 use_cycles(30);
3913 psxBios_ReturnFromException();
ef79bbde
P
3914}
3915
0890ae15 3916static void hleExc1_0_1(void)
dc4fa8bc 3917{
3918 u32 vbl_irq_ack_enable = loadRam32(A_RCNT_VBL_ACK + 0x0c); // 860c
3919 handle_chain_x_x_1(vbl_irq_ack_enable, 0); // IRQ0 vblank
3920}
ef79bbde 3921
dc4fa8bc 3922static void handle_chain_1_x_2(u32 ev_index, u32 irqbit)
3923{
3924 u32 ret = 0;
3925 if (psxHu32(0x1074) & psxHu32(0x1070) & (1u << irqbit)) {
4d2f73bb 3926 DeliverEvent(0xf2000000 + ev_index, 0x0002);
dc4fa8bc 3927 ret = 1;
3928 }
3929 mips_return_c(ret, 22);
3930}
ef79bbde 3931
0890ae15 3932static void hleExc1_0_2(void)
dc4fa8bc 3933{
3934 handle_chain_1_x_2(3, 0); // IRQ0 vblank
3935}
ef79bbde 3936
0890ae15 3937static void hleExc1_1_1(void)
dc4fa8bc 3938{
3939 u32 rcnt_irq_ack_enable = loadRam32(A_RCNT_VBL_ACK + 0x08); // 8608
3940 handle_chain_x_x_1(rcnt_irq_ack_enable, 6); // IRQ6 rcnt2
3941}
ef79bbde 3942
0890ae15 3943static void hleExc1_1_2(void)
dc4fa8bc 3944{
3945 handle_chain_1_x_2(2, 6); // IRQ6 rcnt2
3946}
ef79bbde 3947
0890ae15 3948static void hleExc1_2_1(void)
dc4fa8bc 3949{
3950 u32 rcnt_irq_ack_enable = loadRam32(A_RCNT_VBL_ACK + 0x04); // 8604
3951 handle_chain_x_x_1(rcnt_irq_ack_enable, 5); // IRQ5 rcnt1
3952}
ef79bbde 3953
0890ae15 3954static void hleExc1_2_2(void)
dc4fa8bc 3955{
3956 handle_chain_1_x_2(1, 5); // IRQ5 rcnt1
3957}
ef79bbde 3958
0890ae15 3959static void hleExc1_3_1(void)
dc4fa8bc 3960{
3961 u32 rcnt_irq_ack_enable = loadRam32(A_RCNT_VBL_ACK + 0x00); // 8600
3962 handle_chain_x_x_1(rcnt_irq_ack_enable, 4); // IRQ4 rcnt0
3963}
ef79bbde 3964
0890ae15 3965static void hleExc1_3_2(void)
dc4fa8bc 3966{
3967 handle_chain_1_x_2(0, 4); // IRQ4 rcnt0
3968}
ef79bbde 3969
0890ae15 3970static void hleExc3_0_2_defint(void)
dc4fa8bc 3971{
3972 static const struct {
3973 u8 ev, irqbit;
3974 } tab[] = {
3975 { 3, 2 }, // cdrom
3976 { 9, 9 }, // spu
3977 { 2, 1 }, // gpu
3978 { 10, 10 }, // io
3979 { 11, 8 }, // sio
3980 { 1, 0 }, // vbl
3981 { 5, 4 }, // rcnt0
3982 { 6, 5 }, // rcnt1
3983 { 6, 6 }, // rcnt2 (bug)
3984 { 8, 7 }, // sio rx
3985 { 4, 3 }, // sio
3986 };
3987 size_t i;
3988 for (i = 0; i < sizeof(tab) / sizeof(tab[0]); i++) {
3989 if (psxHu32(0x1074) & psxHu32(0x1070) & (1u << tab[i].irqbit)) {
4d2f73bb 3990 DeliverEvent(0xf0000000 + tab[i].ev, 0x1000);
dc4fa8bc 3991 use_cycles(7);
3992 }
ef79bbde 3993
dc4fa8bc 3994 }
3995 mips_return_c(0, 11 + 7*11 + 7*11 + 12);
3996}
ef79bbde 3997
0890ae15 3998static void hleExcPadCard1(void)
ea72f34a 3999{
4000 if (loadRam32(A_PAD_IRQR_ENA)) {
4001 u8 *pad_buf1 = loadRam8ptr(A_PAD_INBUF + 0);
4002 u8 *pad_buf2 = loadRam8ptr(A_PAD_INBUF + 4);
ea72f34a 4003
4004 psxBios_PADpoll(1);
4005 psxBios_PADpoll(2);
ea72f34a 4006 use_cycles(100);
2bce5171 4007 if (loadRam32(A_PAD_DR_DST))
4008 psxBios_PAD_dr_();
ea72f34a 4009 }
4010 if (loadRam32(A_PAD_ACK_VBL))
4011 psxHwWrite16(0x1f801070, ~1);
4012 if (loadRam32(A_CARD_IRQR_ENA)) {
4013 // todo, maybe
4014 }
4015
4016 mips_return_c(0, 18);
4017}
4018
0890ae15 4019static void hleExcPadCard2(void)
ea72f34a 4020{
4021 u32 ret = psxHu32(0x1074) & psxHu32(0x1070) & 1;
4022 mips_return_c(ret, 15);
4023}
4024
dc4fa8bc 4025void psxBiosException() {
4026 u32 tcbPtr = loadRam32(A_TT_PCB);
4027 u32 *chains = loadRam32ptr(A_TT_ExCB);
4028 TCB *tcb = loadRam32ptr(tcbPtr);
4029 u32 ptr, *chain;
4030 int c, lim;
4031 int i;
ef79bbde 4032
dc4fa8bc 4033 // save the regs
82575753 4034 // $at, $v0, $v1, $ra already saved by the mips code at A_EXCEPTION
4035 for (i = 4; i < 31; i++) {
dc4fa8bc 4036 if (i == 26) // $k0
4037 continue;
4038 tcb->reg[i] = SWAP32(psxRegs.GPR.r[i]);
4039 }
4040 tcb->lo = SWAP32(psxRegs.GPR.n.lo);
4041 tcb->hi = SWAP32(psxRegs.GPR.n.hi);
14b3bd95 4042 //tcb->epc = SWAP32(psxRegs.CP0.n.EPC); // done by asm
dc4fa8bc 4043 tcb->sr = SWAP32(psxRegs.CP0.n.SR);
4044 tcb->cause = SWAP32(psxRegs.CP0.n.Cause);
4045 sp = fp = loadRam32(A_EXC_SP);
4046 gp = A_EXC_GP;
4047 use_cycles(46);
65722e04 4048 assert(!psxRegs.cpuInRecursion);
dc4fa8bc 4049
4050 // do the chains (always 4)
4051 for (c = lim = 0; c < 4; c++) {
4052 if (chains[c * 2] == 0)
4053 continue;
4054 ptr = SWAP32(chains[c * 2]);
4055 for (; ptr && lim < 100; ptr = SWAP32(chain[0])) {
4056 chain = castRam32ptr(ptr);
4057 use_cycles(14);
4058 lim++;
4059 if (chain[2] == 0)
4060 continue;
4061 softCallInException(SWAP32(chain[2]));
4062 if (returned_from_exception())
4063 return;
ef79bbde 4064
dc4fa8bc 4065 if (v0 == 0 || chain[1] == 0)
4066 continue;
4067 softCallInException(SWAP32(chain[1]));
4068 if (returned_from_exception())
4069 return;
4070 }
ef79bbde 4071 }
dc4fa8bc 4072 assert(lim < 100);
ef79bbde 4073
dc4fa8bc 4074 // return from exception (custom or default)
4075 use_cycles(23);
4076 ptr = loadRam32(A_EEXIT_PTR);
4077 if (ptr != A_EEXIT_DEF) {
4078 const struct jmp_buf_ *jmp_buf = castRam32ptr(ptr);
4079 longjmp_load(jmp_buf);
4080 v0 = 1;
4081 pc0 = ra;
4082 return;
4083 }
4084 psxBios_ReturnFromException();
ef79bbde
P
4085}
4086
0890ae15 4087/* HLE */
4088static void hleDummy() {
4089 log_unhandled("hleDummy called @%08x ra=%08x\n", psxRegs.pc - 4, ra);
4090 psxRegs.pc = ra;
4091 psxRegs.cycle += 1000;
4092
4093 psxBranchTest();
4094}
4095
4096static void hleA0() {
4097 u32 call = t1 & 0xff;
4098 u32 entry = loadRam32(A_A0_TABLE + call * 4);
4099
4100 if (call < 192 && entry != A_A0_DUMMY) {
4101 PSXBIOS_LOG("custom A%02x %s(0x%x, ) addr=%08x ra=%08x\n",
4102 call, biosA0n[call], a0, entry, ra);
4103 softCall(entry);
4104 pc0 = ra;
4105 PSXBIOS_LOG(" -> %08x\n", v0);
4106 }
4107 else if (biosA0[call])
4108 biosA0[call]();
4109
3b988ef2 4110 //printf("A(%02x) -> %x\n", call, v0);
0890ae15 4111 psxBranchTest();
4112}
4113
4114static void hleB0() {
4115 u32 call = t1 & 0xff;
4116 u32 entry = loadRam32(A_B0_TABLE + call * 4);
4117 int is_custom = 0;
4118
4119 if (call == 0x5b)
4120 is_custom = entry != A_B0_5B_DUMMY;
4121 else
4122 is_custom = entry != A_B0_DUMMY;
4123 if (is_custom) {
4124 PSXBIOS_LOG("custom B%02x %s(0x%x, ) addr=%08x ra=%08x\n",
4125 call, biosB0n[call], a0, entry, ra);
4126 softCall(entry);
4127 pc0 = ra;
4128 PSXBIOS_LOG(" -> %08x\n", v0);
4129 }
4130 else if (biosB0[call])
4131 biosB0[call]();
4132
3b988ef2 4133 //printf("B(%02x) -> %x\n", call, v0);
0890ae15 4134 psxBranchTest();
4135}
4136
4137static void hleC0() {
4138 u32 call = t1 & 0xff;
4139 u32 entry = loadRam32(A_C0_TABLE + call * 4);
4140
4141 if (call < 128 && entry != A_C0_DUMMY) {
4142 PSXBIOS_LOG("custom C%02x %s(0x%x, ) addr=%08x ra=%08x\n",
4143 call, biosC0n[call], a0, entry, ra);
4144 softCall(entry);
4145 pc0 = ra;
4146 PSXBIOS_LOG(" -> %08x\n", v0);
4147 }
4148 else if (biosC0[call])
4149 biosC0[call]();
4150
3b988ef2 4151 //printf("C(%02x) -> %x\n", call, v0);
0890ae15 4152 psxBranchTest();
4153}
4154
4155// currently not used
4156static void hleBootstrap() {
4157 CheckCdrom();
4158 LoadCdrom();
4159}
4160
4161static void hleExecRet() {
4162 const EXEC *header = (EXEC *)PSXM(s0);
4163
4164 PSXBIOS_LOG("ExecRet %x: %x\n", s0, header->ret);
4165
4166 ra = SWAP32(header->ret);
4167 sp = SWAP32(header->_sp);
4168 fp = SWAP32(header->_fp);
4169 gp = SWAP32(header->_gp);
4170 s0 = SWAP32(header->base);
4171
4172 v0 = 1;
4173 psxRegs.pc = ra;
4174}
4175
4176void (* const psxHLEt[24])() = {
4177 hleDummy, hleA0, hleB0, hleC0,
4178 hleBootstrap, hleExecRet, psxBiosException, hleDummy,
4179 hleExc0_0_1, hleExc0_0_2,
4180 hleExc0_1_1, hleExc0_1_2, hleExc0_2_2_syscall,
4181 hleExc1_0_1, hleExc1_0_2,
4182 hleExc1_1_1, hleExc1_1_2,
4183 hleExc1_2_1, hleExc1_2_2,
4184 hleExc1_3_1, hleExc1_3_2,
4185 hleExc3_0_2_defint,
4186 hleExcPadCard1, hleExcPadCard2,
4187};
4188
b34d6a80 4189void psxBiosCheckExe(u32 t_addr, u32 t_size, int loading_state)
de74f599 4190{
4191 // lw $v0, 0x10($sp)
4192 // nop
4193 // addiu $v0, -1
4194 // sw $v0, 0x10($sp)
4195 // lw $v0, 0x10($sp)
4196 // nop
4197 // bne $v0, $v1, not_timeout
4198 // nop
4199 // lui $a0, ...
4200 static const u8 pattern[] = {
4201 0x10, 0x00, 0xA2, 0x8F, 0x00, 0x00, 0x00, 0x00,
4202 0xFF, 0xFF, 0x42, 0x24, 0x10, 0x00, 0xA2, 0xAF,
4203 0x10, 0x00, 0xA2, 0x8F, 0x00, 0x00, 0x00, 0x00,
4204 0x0C, 0x00, 0x43, 0x14, 0x00, 0x00, 0x00, 0x00,
4205 };
4206 u32 start = t_addr & 0x1ffffc;
4207 u32 end = (start + t_size) & 0x1ffffc;
4208 u32 buf[sizeof(pattern) / sizeof(u32)];
4209 const u32 *r32 = (u32 *)(psxM + start);
4210 u32 i, j;
4211
4212 if (end <= start)
4213 return;
4214 if (!Config.HLE)
4215 return;
4216
4217 memcpy(buf, pattern, sizeof(buf));
4218 for (i = 0; i < t_size / 4; i += j + 1) {
4219 for (j = 0; j < sizeof(buf) / sizeof(buf[0]); j++)
4220 if (r32[i + j] != buf[j])
4221 break;
4222 if (j != sizeof(buf) / sizeof(buf[0]))
4223 continue;
4224
4225 if ((SWAP32(r32[i + j]) >> 16) != 0x3c04) // lui
4226 continue;
b34d6a80 4227 if (!loading_state)
4228 SysPrintf("HLE vsync @%08x\n", start + i * 4);
de74f599 4229 psxRegs.biosBranchCheck = (t_addr & 0xa01ffffc) + i * 4;
4230 }
4231}
4232
4233void psxBiosCheckBranch(void)
4234{
4235#if 1
4236 // vsync HLE hack
4237 static u32 cycles_prev, v0_prev;
4238 u32 cycles_passed, waste_cycles;
4239 u32 loops, v0_expect = v0_prev - 1;
4240 if (v0 != 1)
4241 return;
4242 execI(&psxRegs);
4243 cycles_passed = psxRegs.cycle - cycles_prev;
4244 cycles_prev = psxRegs.cycle;
4245 v0_prev = v0;
4246 if (cycles_passed < 10 || cycles_passed > 50 || v0 != v0_expect)
4247 return;
4248
4249 waste_cycles = schedule_timeslice() - psxRegs.cycle;
4250 loops = waste_cycles / cycles_passed;
4251 if (loops > v0)
4252 loops = v0;
4253 v0 -= loops;
4254 psxRegs.cycle += loops * cycles_passed;
4255 //printf("c %4u %d\n", loops, cycles_passed);
4256#endif
4257}
0890ae15 4258
ef79bbde
P
4259#define bfreeze(ptr, size) { \
4260 if (Mode == 1) memcpy(&psxR[base], ptr, size); \
4261 if (Mode == 0) memcpy(ptr, &psxR[base], size); \
4262 base += size; \
4263}
4264
4265#define bfreezes(ptr) bfreeze(ptr, sizeof(ptr))
7c3332fb 4266#define bfreezel(ptr) bfreeze(ptr, sizeof(*(ptr)))
ef79bbde
P
4267
4268void psxBiosFreeze(int Mode) {
4269 u32 base = 0x40000;
4270
ef79bbde 4271 bfreezes(FDesc);
7c3332fb 4272 bfreezes(ffile);
4273 bfreezel(&nfile);
0a50313e 4274 bfreezes(cdir);
ef79bbde 4275}