/***************************************************************************
* Copyright (C) 2019 Ryan Schultz, PCSX-df Team, PCSX team, gameblabla, *
- * dmitrysmagin, senquack *
+ * dmitrysmagin, senquack *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
#define PSXBIOS_LOG(...)
#endif
+#define PTR_1 (void *)(size_t)1
+
char *biosA0n[256] = {
// 0x00
"open", "lseek", "read", "write",
static FileDesc FDesc[32];
static char ffile[64];
static int nfile;
+static char cdir[8*8+8];
+static u32 floodchk;
// fixed RAM offsets, SCPH1001 compatible
#define A_TT_ExCB 0x0100
#define A_HEAP_END 0x9008
#define A_HEAP_FLAG 0x900c
#define A_RND_SEED 0x9010
+#define A_CONF_TCB 0xb940
+#define A_CONF_EvCB 0xb944
+#define A_CONF_SP 0xb948
#define A_CD_EVENTS 0xb9b8
#define A_EXC_GP 0xf450
ra = 0x80001000;
psxRegs.CP0.n.SR &= ~0x404; // disable interrupts
+ psxCpu->Notify(R3000ACPU_NOTIFY_AFTER_LOAD, PTR_1);
+
while (pc0 != 0x80001000 && ++lim < 1000000)
psxCpu->ExecuteBlock(EXEC_CALLER_HLE);
+ psxCpu->Notify(R3000ACPU_NOTIFY_BEFORE_SAVE, PTR_1);
+
if (lim == 1000000)
PSXBIOS_LOG("softCall @%x hit lim\n", pc);
ra = sra;
return;
ra = 0x80001000;
+ psxCpu->Notify(R3000ACPU_NOTIFY_AFTER_LOAD, PTR_1);
+
while (!returned_from_exception() && pc0 != 0x80001000 && ++lim < 1000000)
psxCpu->ExecuteBlock(EXEC_CALLER_HLE);
+ psxCpu->Notify(R3000ACPU_NOTIFY_BEFORE_SAVE, PTR_1);
+
if (lim == 1000000)
PSXBIOS_LOG("softCallInException @%x hit lim\n", pc);
if (pc0 == 0x80001000)
pc0 = ra;
}
-void psxBios_format() { // 0x41
+static void psxBios_cd() { // 0x40
+ const char *p, *dir = castRam8ptr(a0);
+ PSXBIOS_LOG("psxBios_%s %x(%s)\n", biosB0n[0x40], a0, dir);
+ if ((p = strchr(dir, ':')))
+ dir = ++p;
+ if (*dir == '\\')
+ dir++;
+ snprintf(cdir, sizeof(cdir), "%s", dir);
+ mips_return_c(1, 100);
+}
+
+static void psxBios_format() { // 0x41
+ PSXBIOS_LOG("psxBios_%s %x(%s)\n", biosB0n[0x41], a0, Ra0);
if (strcmp(Ra0, "bu00:") == 0 && Config.Mcd1[0] != '\0')
{
CreateMcd(Config.Mcd1);
}
static void psxBios_SystemErrorUnresolvedException() {
- if (loadRam32(0xfffc) != 0x12345678) { // prevent log flood
+ if (floodchk != 0x12340a40) { // prevent log flood
SysPrintf("psxBios_%s called from %08x\n", biosA0n[0x40], ra);
- storeRam32(0xfffc, 0x12345678);
+ floodchk = 0x12340a40;
}
mips_return_void_c(1000);
}
void psxBios_Load() { // 0x42
EXE_HEADER eheader;
+ char path[256];
+ char *pa0, *p;
void *pa1;
+ pa0 = Ra0;
pa1 = Ra1;
- if (pa1 != INVALID_PTR && LoadCdromFile(Ra0, &eheader) == 0) {
+ PSXBIOS_LOG("psxBios_%s %x(%s), %x\n", biosA0n[0x42], a0, pa0, a1);
+ if (pa0 == INVALID_PTR || pa1 == INVALID_PTR) {
+ mips_return(0);
+ return;
+ }
+ if ((p = strchr(pa0, ':')))
+ pa0 = ++p;
+ if (*pa0 == '\\')
+ pa0++;
+ if (cdir[0])
+ snprintf(path, sizeof(path), "%s\\%s", cdir, (char *)pa0);
+ else
+ snprintf(path, sizeof(path), "%s", (char *)pa0);
+
+ if (LoadCdromFile(path, &eheader) == 0) {
memcpy(pa1, ((char*)&eheader)+16, sizeof(EXEC));
psxCpu->Clear(a1, sizeof(EXEC) / 4);
FlushCache();
v0 = 1;
} else v0 = 0;
- PSXBIOS_LOG("psxBios_%s: %s, %d -> %d\n", biosA0n[0x42], Ra0, a1, v0);
+ PSXBIOS_LOG(" -> %d\n", v0);
pc0 = ra;
}
use_cycles(30);
}
+static void setup_tt(u32 tcb_cnt, u32 evcb_cnt, u32 stack);
+
+static void psxBios_SetConf() { // 9c
+ PSXBIOS_LOG("psxBios_%s %x %x %x\n", biosA0n[0x9c], a0, a1, a2);
+ setup_tt(a1, a0, a2);
+ psxRegs.CP0.n.SR |= 0x401;
+ mips_return_void_c(500);
+}
+
+static void psxBios_GetConf() { // 9d
+ PSXBIOS_LOG("psxBios_%s %x %x %x\n", biosA0n[0x9d], a0, a1, a2);
+ storeRam32(a0, loadRam32(A_CONF_EvCB));
+ storeRam32(a1, loadRam32(A_CONF_TCB));
+ storeRam32(a2, loadRam32(A_CONF_SP));
+ mips_return_void_c(10);
+}
+
void psxBios_SetMem() { // 9f
u32 new = psxHu32(0x1060);
PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x03]);
#endif
- a0&= 0x3;
- if (a0 != 3) v0 = psxRcntRcount(a0);
- else v0 = 0;
+ switch (a0 & 0x3)
+ {
+ case 0: v0 = psxRcntRcount0(); break;
+ case 1: v0 = psxRcntRcount1(); break;
+ case 2: v0 = psxRcntRcount2(); break;
+ case 3: v0 = 0; break;
+ }
pc0 = ra;
}
}
}
}
+ floodchk = 0;
use_cycles(29);
return ret;
}
u32 base = loadRam32(A_TT_EvCB);
u32 status = loadRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4);
u32 ret = 0;
- PSXBIOS_LOG("psxBios_%s %x %x\n", biosB0n[0x0b], a0, status);
+
+ if (psxRegs.cycle - floodchk > 16*1024u) { // prevent log flood
+ PSXBIOS_LOG("psxBios_%s %x %x\n", biosB0n[0x0b], a0, status);
+ floodchk = psxRegs.cycle;
+ }
if (status == EvStALREADY) {
storeRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4, EvStACTIVE);
ret = 1;
mips_return_c(0xffffffff, 20);
return;
}
- PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x0e], th);
+ PSXBIOS_LOG("psxBios_%s -> %x\n", biosB0n[0x0e], 0xff000000 + th);
tcb[th].status = SWAP32(0x4000);
tcb[th].mode = SWAP32(0x1000);
* int CloseTh(long thread);
*/
-void psxBios_CloseTh() { // 0f
- TCB *tcb = loadRam32ptr(A_TT_TCB);
- u32 limit = loadRam32(A_TT_TCB + 4) / 0xc0u;
- u32 th = a0 & 0xff;
+static void psxBios_CloseTh() { // 0f
+ u32 tcb = loadRam32(A_TT_TCB);
+ u32 th = a0 & 0xffff;
-#ifdef PSXBIOS_LOG
- PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x0f], th);
-#endif
- /* The return value is always 1 (even if the handle was already closed). */
- v0 = 1;
- if (th < limit && tcb[th].status == SWAP32(0x4000)) {
- tcb[th].status = SWAP32(0x1000);
- }
+ PSXBIOS_LOG("psxBios_%s %x\n", biosB0n[0x0f], a0);
+ // in the usual bios fashion no checks, just write and return 1
+ storeRam32(tcb + th * sizeof(TCB), 0x1000);
- pc0 = ra;
+ mips_return_c(1, 11);
}
/*
pc0 = ra;
}
+static void bufile(const u8 *mcd_data, u32 dir_) {
+ struct DIRENTRY *dir = (struct DIRENTRY *)castRam8ptr(dir_);
+ const char *pfile = ffile + 5;
+ const u8 *data = mcd_data;
+ int i = 0, match = 0;
+ int blocks = 1;
+ u32 head = 0;
-/* To avoid any issues with different behaviour when using the libc's own strlen instead.
- * We want to mimic the PSX's behaviour in this case for bufile. */
-static size_t strlen_internal(char* p)
-{
- size_t size_of_array = 0;
- while (*p++) size_of_array++;
- return size_of_array;
-}
-
-#define bufile(mcd) { \
- size_t size_of_name = strlen_internal(dir->name); \
- v0 = 0; \
- while (nfile < 16) { \
- char *pfile = ffile+5; \
- int match=1; \
- \
- ptr = Mcd##mcd##Data + 128 * (nfile + 1); \
- nfile++; \
- if ((*ptr & 0xF0) != 0x50) continue; \
- /* Bug link files show up as free block. */ \
- if (!ptr[0xa]) continue; \
- ptr+= 0xa; \
- if (pfile[0] == 0) { \
- strncpy(dir->name, ptr, sizeof(dir->name) - 1); \
- if (size_of_name < sizeof(dir->name)) dir->name[size_of_name] = '\0'; \
- } else for (i=0; i<20; i++) { \
- if (pfile[i] == ptr[i]) { \
- dir->name[i] = ptr[i]; continue; } \
- if (pfile[i] == '?') { \
- dir->name[i] = ptr[i]; continue; } \
- if (pfile[i] == '*') { \
- strcpy(dir->name+i, ptr+i); break; } \
- match = 0; break; \
- } \
- PSXBIOS_LOG("%d : %s = %s + %s (match=%d)\n", nfile, dir->name, pfile, ptr, match); \
- if (match == 0) { continue; } \
- dir->size = 8192; \
- v0 = _dir; \
- break; \
- } \
+ v0 = 0;
+ for (; nfile <= 15 && !match; nfile++) {
+ const char *name;
+
+ head = nfile * 0x40;
+ data = mcd_data + 128 * nfile;
+ name = (const char *)data + 0x0a;
+ if ((data[0] & 0xF0) != 0x50) continue;
+ /* Bug link files show up as free block. */
+ if (!name[0]) continue;
+ match = 1;
+ for (i = 0; i < 20; i++) {
+ if (pfile[i] == name[i] || pfile[i] == '?')
+ dir->name[i] = name[i];
+ else if (pfile[i] == '*') {
+ int len = strlen(name + i);
+ if (i + len > 20)
+ len = 20 - i;
+ memcpy(dir->name + i, name + i, len + 1);
+ i += len;
+ break;
+ }
+ else {
+ match = 0;
+ break;
+ }
+ if (!name[i])
+ break;
+ }
+ PSXBIOS_LOG("%d : %s = %s + %s (match=%d)\n",
+ nfile, dir->name, pfile, name, match);
+ }
+ for (; nfile <= 15; nfile++, blocks++) {
+ const u8 *data2 = mcd_data + 128 * nfile;
+ const char *name = data2 + 0x0a;
+ if ((data2[0] & 0xF0) != 0x50 || name[0])
+ break;
+ }
+ if (match) {
+ // nul char of full lenth name seems to overwrite .attr
+ dir->attr = SWAP32(i < 20 ? data[0] & 0xf0 : 0); // ?
+ dir->size = 8192 * blocks;
+ dir->head = head;
+ v0 = dir_;
+ }
+ PSXBIOS_LOG(" -> %x '%s' %x %x %x %x\n", v0, v0 ? dir->name : "",
+ dir->attr, dir->size, dir->next, dir->head);
}
/*
*/
static void psxBios_firstfile() { // 42
- struct DIRENTRY *dir = (struct DIRENTRY *)castRam8ptr(a1);
char *pa0 = castRam8ptr(a0);
- u32 _dir = a1;
- char *ptr;
- int i;
+ PSXBIOS_LOG("psxBios_%s %s %x\n", biosB0n[0x42], pa0, a1);
v0 = 0;
{
snprintf(ffile, sizeof(ffile), "%s", pa0);
- nfile = 0;
+ if (ffile[5] == 0)
+ strcpy(ffile + 5, "*"); // maybe?
+ nfile = 1;
if (!strncmp(pa0, "bu00", 4)) {
// firstfile() calls _card_read() internally, so deliver it's event
DeliverEvent(0xf0000011, 0x0004);
- bufile(1);
+ bufile(Mcd1Data, a1);
} else if (!strncmp(pa0, "bu10", 4)) {
// firstfile() calls _card_read() internally, so deliver it's event
DeliverEvent(0xf0000011, 0x0004);
- bufile(2);
+ bufile(Mcd2Data, a1);
}
}
- PSXBIOS_LOG("psxBios_%s %s %x -> %x\n", biosB0n[0x42], pa0, a1, v0);
pc0 = ra;
}
*/
void psxBios_nextfile() { // 43
- struct DIRENTRY *dir = (struct DIRENTRY *)Ra0;
- u32 _dir = a0;
- char *ptr;
- int i;
+ PSXBIOS_LOG("psxBios_%s %x\n", biosB0n[0x43], a0);
v0 = 0;
-
- if (!strncmp(ffile, "bu00", 4)) {
- bufile(1);
- }
- else if (!strncmp(ffile, "bu10", 4)) {
- bufile(2);
- }
- PSXBIOS_LOG("psxBios_%s %s -> %x\n", biosB0n[0x43], dir->name, v0);
+ if (!strncmp(ffile, "bu00", 4))
+ bufile(Mcd1Data, a0);
+ else if (!strncmp(ffile, "bu10", 4))
+ bufile(Mcd2Data, a0);
pc0 = ra;
}
if (handler2) PSXMu32ref(handler2) = HLEOP(chain_hle_op(handler2));
}
-static void setup_tt(u32 tcb_cnt, u32 evcb_cnt)
+static void setup_tt(u32 tcb_cnt, u32 evcb_cnt, u32 stack)
{
u32 *ram32 = (u32 *)psxM;
- u32 s_excb = 0x20, s_evcb = 0x1c * evcb_cnt;
- u32 s_pcb = 4, s_tcb = 0xc0 * tcb_cnt;
+ u32 s_excb = 0x20, s_evcb, s_pcb = 4, s_tcb;
u32 p_excb, p_evcb, p_pcb, p_tcb;
+ u32 i;
+
+ PSXBIOS_LOG("setup: tcb %u, evcb %u\n", tcb_cnt, evcb_cnt);
+
+ // the real bios doesn't care, but we just don't
+ // want to crash in case of garbage parameters
+ if (tcb_cnt > 1024) tcb_cnt = 1024;
+ if (evcb_cnt > 1024) evcb_cnt = 1024;
+ s_evcb = 0x1c * evcb_cnt;
+ s_tcb = 0xc0 * tcb_cnt;
memset(ram32 + 0xe000/4, 0, s_excb + s_evcb + s_pcb + s_tcb + 5*4);
psxBios_SysInitMemory_(0xa000e000, 0x2000);
storeRam32(p_pcb, p_tcb);
storeRam32(p_tcb, 0x4000); // first TCB
+ for (i = 1; i < tcb_cnt; i++)
+ storeRam32(p_tcb + sizeof(TCB) * i, 0x1000);
// default events
storeRam32(A_CD_EVENTS + 0x00, OpenEvent(0xf0000003, 0x0010, EvMdMARK, 0));
storeRam32(A_CD_EVENTS + 0x08, OpenEvent(0xf0000003, 0x0040, EvMdMARK, 0));
storeRam32(A_CD_EVENTS + 0x0c, OpenEvent(0xf0000003, 0x0080, EvMdMARK, 0));
storeRam32(A_CD_EVENTS + 0x10, OpenEvent(0xf0000003, 0x8000, EvMdMARK, 0));
- DeliverEvent(0xf0000003, 0x0010);
+
+ storeRam32(A_CONF_EvCB, evcb_cnt);
+ storeRam32(A_CONF_TCB, tcb_cnt);
+ storeRam32(A_CONF_SP, stack);
}
static const u32 gpu_ctl_def[] = {
//biosA0[0x99] = psxBios_EnableKernelIORedirection;
//biosA0[0x9a] = psxBios_sys_a0_9a;
//biosA0[0x9b] = psxBios_sys_a0_9b;
- //biosA0[0x9c] = psxBios_SetConf;
- //biosA0[0x9d] = psxBios_GetConf;
+ biosA0[0x9c] = psxBios_SetConf;
+ biosA0[0x9d] = psxBios_GetConf;
//biosA0[0x9e] = psxBios_sys_a0_9e;
biosA0[0x9f] = psxBios_SetMem;
//biosA0[0xa0] = psxBios__boot;
biosB0[0x3d] = psxBios_putchar;
//biosB0[0x3e] = psxBios_gets;
biosB0[0x3f] = psxBios_puts;
- //biosB0[0x40] = psxBios_cd;
+ biosB0[0x40] = psxBios_cd;
biosB0[0x41] = psxBios_format;
biosB0[0x42] = psxBios_firstfile;
biosB0[0x43] = psxBios_nextfile;
/**/
memset(FDesc, 0, sizeof(FDesc));
+ memset(cdir, 0, sizeof(cdir));
+ floodchk = 0;
// somewhat pretend to be a SCPH1001 BIOS
// some games look for these and take an exception if they're missing
ram32[0x00b0/4] = HLEOP(hleop_b0);
ram32[0x00c0/4] = HLEOP(hleop_c0);
- setup_tt(4, 16);
+ setup_tt(4, 16, 0x801fff00);
+ DeliverEvent(0xf0000003, 0x0010);
ram32[0x6ee0/4] = SWAPu32(0x0000eff0); // DCB
strcpy((char *)&ram32[0xeff0/4], "bu");
void psxBiosShutdown() {
}
-void psxBiosCnfLoaded(u32 tcb_cnt, u32 evcb_cnt) {
- if (tcb_cnt != 4 || evcb_cnt != 16)
- setup_tt(tcb_cnt, evcb_cnt);
+void psxBiosCnfLoaded(u32 tcb_cnt, u32 evcb_cnt, u32 stack) {
+ if (stack == 0)
+ stack = 0x801FFF00;
+ if (tcb_cnt != 4 || evcb_cnt != 16) {
+ setup_tt(tcb_cnt, evcb_cnt, stack);
+ DeliverEvent(0xf0000003, 0x0010);
+ }
+ storeRam32(A_CONF_SP, stack);
}
#define psxBios_PADpoll(pad) { \
- PAD##pad##_startPoll(pad); \
- pad_buf##pad[0] = 0; \
- pad_buf##pad[1] = PAD##pad##_poll(0x42); \
- if (!(pad_buf##pad[1] & 0x0f)) { \
- bufcount = 32; \
- } else { \
- bufcount = (pad_buf##pad[1] & 0x0f) * 2; \
- } \
- PAD##pad##_poll(0); \
+ int i, more_data = 0; \
+ pad_buf##pad[0] = PAD##pad##_startPoll(pad); \
+ pad_buf##pad[1] = PAD##pad##_poll(0x42, &more_data); \
i = 2; \
- while (bufcount--) { \
- pad_buf##pad[i++] = PAD##pad##_poll(0); \
+ while (more_data) { \
+ pad_buf##pad[i++] = PAD##pad##_poll(0, &more_data); \
} \
}
if (loadRam32(A_PAD_IRQR_ENA)) {
u8 *pad_buf1 = loadRam8ptr(A_PAD_INBUF + 0);
u8 *pad_buf2 = loadRam8ptr(A_PAD_INBUF + 4);
- int i, bufcount;
psxBios_PADpoll(1);
psxBios_PADpoll(2);
int i;
// save the regs
- // $at, $v0, $v1 already saved by the mips code at A_EXCEPTION
- for (i = 4; i < 32; i++) {
+ // $at, $v0, $v1, $ra already saved by the mips code at A_EXCEPTION
+ for (i = 4; i < 31; i++) {
if (i == 26) // $k0
continue;
tcb->reg[i] = SWAP32(psxRegs.GPR.r[i]);
bfreezes(FDesc);
bfreezes(ffile);
bfreezel(&nfile);
+ bfreezes(cdir);
}