#include "gpu.h"
#include "sio.h"
#include "psxhle.h"
+#include "psxinterpreter.h"
#include <zlib.h>
#if (defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)
#pragma GCC diagnostic ignored "-Wpointer-sign"
#endif
-#undef SysPrintf
-#define SysPrintf if (Config.PsxOut) printf
+#ifndef PSXBIOS_LOG
+//#define PSXBIOS_LOG printf
+#define PSXBIOS_LOG(...)
+#endif
char *biosA0n[256] = {
// 0x00
"realloc", "InitHeap", "_exit", "getchar",
"putchar", "gets", "puts", "printf",
// 0x40
- "sys_a0_40", "LoadTest", "Load", "Exec",
+ "SystemErrorUnresolvedException", "LoadTest", "Load", "Exec",
"FlushCache", "InstallInterruptHandler", "GPU_dw", "mem2vram",
- "SendGPUStatus", "GPU_cw", "GPU_cwb", "SendPackets",
+ "SendGPUStatus", "GPU_cw", "GPU_cwb", "SendPackets",
"sys_a0_4c", "GetGPUStatus", "GPU_sync", "sys_a0_4f",
// 0x50
"sys_a0_50", "LoadExec", "GetSysSp", "sys_a0_53",
"_card_load", "_card_auto", "bufs_cd_4", "sys_a0_af",
// 0xb0
"sys_a0_b0", "sys_a0_b1", "do_a_long_jmp", "sys_a0_b3",
- "?? sub_function",
+ "GetSystemInfo",
};
char *biosB0n[256] = {
#define k1 (psxRegs.GPR.n.k1)
#define gp (psxRegs.GPR.n.gp)
#define sp (psxRegs.GPR.n.sp)
-#define fp (psxRegs.GPR.n.s8)
+#define fp (psxRegs.GPR.n.fp)
#define ra (psxRegs.GPR.n.ra)
#define pc0 (psxRegs.pc)
u32 gp0;
u32 t_addr;
u32 t_size;
- u32 d_addr;
+ u32 d_addr; // 10
u32 d_size;
u32 b_addr;
- u32 b_size;
+ u32 b_size; // 1c
u32 S_addr;
u32 s_size;
u32 _sp, _fp, _gp, ret, base;
static inline void softCall(u32 pc) {
u32 sra = ra;
u32 ssr = psxRegs.CP0.n.SR;
+ u32 lim = 0;
pc0 = pc;
ra = 0x80001000;
psxRegs.CP0.n.SR &= ~0x404; // disable interrupts
- while (pc0 != 0x80001000)
+ while (pc0 != 0x80001000 && ++lim < 1000000)
psxCpu->ExecuteBlock(EXEC_CALLER_HLE);
+ if (lim == 1000000)
+ PSXBIOS_LOG("softCall @%x hit lim\n", pc);
ra = sra;
- psxRegs.CP0.n.SR = ssr;
+ psxRegs.CP0.n.SR |= ssr & 0x404;
}
static inline void softCallInException(u32 pc) {
u32 sra = ra;
+ u32 lim = 0;
pc0 = pc;
ra = 0x80001000;
- while (!returned_from_exception() && pc0 != 0x80001000)
+ while (!returned_from_exception() && pc0 != 0x80001000 && ++lim < 1000000)
psxCpu->ExecuteBlock(EXEC_CALLER_HLE);
+ if (lim == 1000000)
+ PSXBIOS_LOG("softCallInException @%x hit lim\n", pc);
if (pc0 == 0x80001000)
ra = sra;
}
#define buread(Ra1, mcd, length) { \
- SysPrintf("read %d: %x,%x (%s)\n", FDesc[1 + mcd].mcfile, FDesc[1 + mcd].offset, a2, Mcd##mcd##Data + 128 * FDesc[1 + mcd].mcfile + 0xa); \
+ 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); \
ptr = Mcd##mcd##Data + 8192 * FDesc[1 + mcd].mcfile + FDesc[1 + mcd].offset; \
memcpy(Ra1, ptr, length); \
if (FDesc[1 + mcd].mode & 0x8000) { \
#define buwrite(Ra1, mcd, length) { \
u32 offset = + 8192 * FDesc[1 + mcd].mcfile + FDesc[1 + mcd].offset; \
- SysPrintf("write %d: %x,%x\n", FDesc[1 + mcd].mcfile, FDesc[1 + mcd].offset, a2); \
+ PSXBIOS_LOG("write %d: %x,%x\n", FDesc[1 + mcd].mcfile, FDesc[1 + mcd].offset, a2); \
ptr = Mcd##mcd##Data + offset; \
memcpy(ptr, Ra1, length); \
FDesc[1 + mcd].offset += length; \
else v0 = length; \
}
-#ifndef PSXBIOS_LOG
-//#define PSXBIOS_LOG printf
-#define PSXBIOS_LOG(...)
-#endif
-
/* Internally redirects to "FileRead(fd,tempbuf,1)".*/
/* For some strange reason, the returned character is sign-expanded; */
/* So if a return value of FFFFFFFFh could mean either character FFh, or error. */
void psxBios_free() { // 0x34
-#ifdef PSXBIOS_LOG
PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x34]);
-#endif
-
- SysPrintf("free %x: %x bytes\n", a0, *(u32*)(Ra0-4));
+ PSXBIOS_LOG("free %x: %x bytes\n", a0, *(u32*)(Ra0-4));
if (a0)
*(u32*)(Ra0-4) |= 1; // set chunk to free
/* HACKFIX: Commenting out this line fixes GTA2 crash */
//*heap_addr = SWAP32(size | 1);
- SysPrintf("InitHeap %x,%x : %x %x\n",a0,a1, (int)((uptr)heap_addr-(uptr)psxM), size);
+ PSXBIOS_LOG("InitHeap %x,%x : %x %x\n",a0,a1, (int)((uptr)heap_addr-(uptr)psxM), size);
pc0 = ra;
}
if (psp != INVALID_PTR)
memcpy(psp, save, 4 * 4);
- SysPrintf("%s", tmp);
+ if (Config.PsxOut)
+ SysPrintf("%s", tmp);
}
void psxBios_printf() { // 0x3f
static void psxBios_SystemErrorUnresolvedException() {
if (loadRam32(0xfffc) != 0x12345678) { // prevent log flood
- SysPrintf("psxBios_%s\n", biosA0n[0x40]);
+ SysPrintf("psxBios_%s called from %08x\n", biosA0n[0x40], ra);
storeRam32(0xfffc, 0x12345678);
}
mips_return_void_c(1000);
*/
void psxBios_Exec() { // 43
- EXEC *header = (EXEC*)Ra0;
- u32 tmp;
+ EXEC *header = (EXEC *)castRam32ptr(a0);
+ u32 ptr;
+ s32 len;
-#ifdef PSXBIOS_LOG
PSXBIOS_LOG("psxBios_%s: %x, %x, %x\n", biosA0n[0x43], a0, a1, a2);
-#endif
- header->_sp = sp;
- header->_fp = fp;
- header->_sp = sp;
- header->_gp = gp;
- header->ret = ra;
- header->base = s0;
+ header->_sp = SWAP32(sp);
+ header->_fp = SWAP32(fp);
+ header->_sp = SWAP32(sp);
+ header->_gp = SWAP32(gp);
+ header->ret = SWAP32(ra);
+ header->base = SWAP32(s0);
- if (header->S_addr != 0) {
- tmp = header->S_addr + header->s_size;
- sp = tmp;
- fp = sp;
- }
+ ptr = SWAP32(header->b_addr);
+ len = SWAP32(header->b_size);
+ if (len != 0) do {
+ storeRam32(ptr, 0);
+ len -= 4; ptr += 4;
+ } while (len > 0);
- gp = header->gp0;
+ if (header->S_addr != 0)
+ sp = fp = SWAP32(header->S_addr) + SWAP32(header->s_size);
+
+ gp = SWAP32(header->gp0);
s0 = a0;
a1 = a2;
ra = 0x8000;
- pc0 = header->_pc0;
+ pc0 = SWAP32(header->_pc0);
}
void psxBios_FlushCache() { // 44
case 2:
psxHu32ref(0x1060) = SWAP32(new);
psxMu32ref(0x060) = a0;
- SysPrintf("Change effective memory : %d MBytes\n",a0);
+ PSXBIOS_LOG("Change effective memory : %d MBytes\n",a0);
break;
case 8:
psxHu32ref(0x1060) = SWAP32(new | 0x300);
psxMu32ref(0x060) = a0;
- SysPrintf("Change effective memory : %d MBytes\n",a0);
+ PSXBIOS_LOG("Change effective memory : %d MBytes\n",a0);
default:
- SysPrintf("Effective memory must be 2/8 MBytes\n");
+ PSXBIOS_LOG("Effective memory must be 2/8 MBytes\n");
break;
}
v0 = 1; pc0 = ra;
}
+static void psxBios_GetSystemInfo() { // b4
+ u32 ret = 0;
+ //PSXBIOS_LOG("psxBios_%s %x\n", biosA0n[0xb4], a0);
+ SysPrintf("psxBios_%s %x\n", biosA0n[0xb4], a0);
+ switch (a0) {
+ case 0:
+ case 1: ret = SWAP32(((u32 *)psxR)[0x100/4 + a0]); break;
+ case 2: ret = 0xbfc0012c; break;
+ case 5: ret = loadRam32(0x60) << 10; break;
+ }
+ mips_return_c(ret, 20);
+}
+
/* System calls B0 */
static u32 psxBios_SysMalloc_(u32 size);
u32 tcbBase = loadRam32(A_TT_TCB);
u32 th = a0 & 0xffff;
-#ifdef PSXBIOS_LOG
-// PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x10], th);
-#endif
+ // this is quite spammy
+ //PSXBIOS_LOG("psxBios_%s %x\n", biosB0n[0x10], th);
+
// without doing any argument checks, just issue a syscall
// (like the real bios does)
a0 = 3;
static void psxBios_ReturnFromException() { // 17
u32 tcbPtr = loadRam32(A_TT_PCB);
const TCB *tcb = loadRam32ptr(tcbPtr);
+ u32 sr;
int i;
for (i = 1; i < 32; i++)
psxRegs.GPR.r[i] = SWAP32(tcb->reg[i]);
psxRegs.GPR.n.lo = SWAP32(tcb->lo);
psxRegs.GPR.n.hi = SWAP32(tcb->hi);
- psxRegs.CP0.n.SR = SWAP32(tcb->sr);
+ sr = SWAP32(tcb->sr);
//printf("%s %08x->%08x %u\n", __func__, pc0, tcb->epc, psxRegs.cycle);
pc0 = k0 = SWAP32(tcb->epc);
- psxRegs.CP0.n.SR = (psxRegs.CP0.n.SR & ~0x0f) | ((psxRegs.CP0.n.SR & 0x3c) >> 2);
+ // the interpreter wants to know about sr changes, so do a MTC0
+ sr = (sr & ~0x0f) | ((sr & 0x3c) >> 2);
+ MTC0(&psxRegs, 12, sr);
+
use_cycles(53);
psxBranchTest();
}
if ((*fptr & 0xF0) != 0x50) continue;
if (strcmp(FDesc[1 + mcd].name, fptr+0xa)) continue;
FDesc[1 + mcd].mcfile = i;
- SysPrintf("open %s\n", fptr+0xa);
+ PSXBIOS_LOG("open %s\n", fptr+0xa);
v0 = 1 + mcd;
break;
}
pptr[8] = pptr[9] = 0xff;
for (j=0, xor=0; j<127; j++) xor^= pptr[j];
pptr[127] = xor;
- SysPrintf("openC %s %d\n", ptr, nblk);
+ PSXBIOS_LOG("openC %s %d\n", ptr, nblk);
v0 = 1 + mcd;
/* just go ahead and resave them all */
SaveMcd(cfg, ptr, 128, 128 * 15);
char *ptr;
void *pa1 = Ra1;
-#ifdef PSXBIOS_LOG
- PSXBIOS_LOG("psxBios_%s: %x,%x,%x\n", biosB0n[0x35], a0, a1, a2);
-#endif
+ if (a0 != 1) // stdout
+ PSXBIOS_LOG("psxBios_%s: %x,%x,%x\n", biosB0n[0x35], a0, a1, a2);
v0 = -1;
if (pa1 == INVALID_PTR) {
char *ptr = pa1;
v0 = a2;
- while (a2 > 0) {
+ if (Config.PsxOut) while (a2 > 0) {
SysPrintf("%c", *ptr++); a2--;
}
pc0 = ra; return;
}
void psxBios_putchar() { // 3d
- SysPrintf("%c", (char)a0);
+ if (Config.PsxOut) SysPrintf("%c", (char)a0);
pc0 = ra;
}
void psxBios_puts() { // 3e/3f
- SysPrintf("%s", Ra0);
+ if (Config.PsxOut) SysPrintf("%s", Ra0);
pc0 = ra;
}
strcpy(dir->name+i, ptr+i); break; } \
match = 0; break; \
} \
- SysPrintf("%d : %s = %s + %s (match=%d)\n", nfile, dir->name, pfile, ptr, match); \
+ PSXBIOS_LOG("%d : %s = %s + %s (match=%d)\n", nfile, dir->name, pfile, ptr, match); \
if (match == 0) { continue; } \
dir->size = 8192; \
v0 = _dir; \
if (strcmp(Ra0+5, ptr+0xa)) continue; \
*ptr = (*ptr & 0xf) | 0xA0; \
SaveMcd(Config.Mcd##mcd, Mcd##mcd##Data, 128 * i, 1); \
- SysPrintf("delete %s\n", ptr+0xa); \
+ PSXBIOS_LOG("delete %s\n", ptr+0xa); \
v0 = 1; \
break; \
} \
void (*biosC0[256+128])();
void (**biosB0)() = biosC0 + 128;
-#include "sjisfont.h"
-
-void setup_mips_code()
+static void setup_mips_code()
{
u32 *ptr;
ptr = (u32 *)&psxM[A_SYSCALL];
ptr[0x60/4] = SWAPu32(0x40037000); // mfc0 $v1, EPC
ptr[0x64/4] = SWAPu32(0x40026800); // mfc0 $v0, Cause
- ptr[0x68/4] = SWAPu32(0x24630004); // addiu $v1, $v1, 4
ptr[0x6c/4] = SWAPu32(0xaf430080); // sw $v1, 0x80($k0)
ptr[0xb0/4] = HLEOP(hleop_exception);
DeliverEvent(0xf0000003, 0x0010);
}
+static const u32 gpu_ctl_def[] = {
+ 0x00000000, 0x01000000, 0x03000000, 0x04000000,
+ 0x05000800, 0x06c60260, 0x0703fc10, 0x08000027
+};
+
+static const u32 gpu_data_def[] = {
+ 0xe100360b, 0xe2000000, 0xe3000800, 0xe4077e7f,
+ 0xe5001000, 0xe6000000,
+ 0x02000000, 0x00000000, 0x01ff03ff
+};
+
+// from 1f801d80
+static const u16 spu_config[] = {
+ 0x3fff, 0x37ef, 0x5ebc, 0x5ebc, 0x0000, 0x0000, 0x0000, 0x00a0,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0x00ff, 0x0000, 0x0000,
+ 0x0000, 0xe128, 0x0000, 0x0200, 0xf0f0, 0xc085, 0x0004, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x033d, 0x0231, 0x7e00, 0x5000, 0xb400, 0xb000, 0x4c00, 0xb000,
+ 0x6000, 0x5400, 0x1ed6, 0x1a31, 0x1d14, 0x183b, 0x1bc2, 0x16b2,
+ 0x1a32, 0x15ef, 0x15ee, 0x1055, 0x1334, 0x0f2d, 0x11f6, 0x0c5d,
+ 0x1056, 0x0ae1, 0x0ae0, 0x07a2, 0x0464, 0x0232, 0x8000, 0x8000
+};
+
+void psxBiosSetupBootState(void)
+{
+ boolean hle = Config.HLE;
+ u32 *hw = (u32 *)psxH;
+ int i;
+
+ // see also SetBootRegs()
+ if (hle) {
+ v0 = 1; v1 = 4;
+ a0 = 1; a2 = a3 = 0; a3 = 0x2a;
+ t2 = 0x2d; t4 = 0x23; t5 = 0x2b; t6 = 0xa0010000;
+ s0 = 0xa000b870;
+ k0 = 0xbfc0d968; k1 = 0xf1c;
+ ra = 0xf0001234; // just to easily detect attempts to return
+ psxRegs.CP0.n.Cause = 0x20;
+ psxRegs.CP0.n.EPC = 0xbfc0d964; // EnterCriticalSection syscall
+
+ hw[0x1000/4] = SWAP32(0x1f000000);
+ hw[0x1004/4] = SWAP32(0x1f802000);
+ hw[0x1008/4] = SWAP32(0x0013243f);
+ hw[0x100c/4] = SWAP32(0x00003022);
+ hw[0x1010/4] = SWAP32(0x0013243f);
+ hw[0x1014/4] = SWAP32(0x200931e1);
+ hw[0x1018/4] = SWAP32(0x00020943);
+ hw[0x101c/4] = SWAP32(0x00070777);
+ hw[0x1020/4] = SWAP32(0x0000132c);
+ hw[0x1060/4] = SWAP32(0x00000b88);
+ hw[0x1070/4] = SWAP32(0x00000001);
+ hw[0x1074/4] = SWAP32(0x0000000c);
+ hw[0x2040/4] = SWAP32(0x00000900);
+ }
+
+ hw[0x10a0/4] = SWAP32(0x00ffffff);
+ hw[0x10a8/4] = SWAP32(0x00000401);
+ hw[0x10b0/4] = SWAP32(0x0008b000);
+ hw[0x10b4/4] = SWAP32(0x00010200);
+ hw[0x10e0/4] = SWAP32(0x000eccf4);
+ hw[0x10e4/4] = SWAP32(0x00000400);
+ hw[0x10e8/4] = SWAP32(0x00000002);
+ hw[0x10f0/4] = SWAP32(0x00009099);
+ hw[0x10f4/4] = SWAP32(0x8c8c0000);
+
+ if (hle) {
+ psxRcntWmode(0, 0);
+ psxRcntWmode(1, 0);
+ psxRcntWmode(2, 0);
+ }
+
+ // gpu
+ for (i = 0; i < sizeof(gpu_ctl_def) / sizeof(gpu_ctl_def[0]); i++)
+ GPU_writeStatus(gpu_ctl_def[i]);
+ for (i = 0; i < sizeof(gpu_data_def) / sizeof(gpu_data_def[0]); i++)
+ GPU_writeData(gpu_data_def[i]);
+ HW_GPU_STATUS |= SWAP32(PSXGPU_nBUSY);
+
+ // spu
+ for (i = 0x1f801d80; i < sizeof(spu_config) / sizeof(spu_config[0]); i++)
+ SPU_writeRegister(0x1f801d80 + i*2, spu_config[i], psxRegs.cycle);
+}
+
+#include "sjisfont.h"
+
void psxBiosInit() {
u32 *ptr, *ram32, *rom32;
int i;
biosA0[0x3b] = psxBios_getchar;
biosA0[0x3c] = psxBios_putchar;
//biosA0[0x3d] = psxBios_gets;
+ biosA0[0x3e] = psxBios_puts;
+ biosA0[0x3f] = psxBios_printf;
biosA0[0x40] = psxBios_SystemErrorUnresolvedException;
//biosA0[0x41] = psxBios_LoadTest;
biosA0[0x42] = psxBios_Load;
//biosA0[0xb1] = psxBios_sys_a0_b1;
//biosA0[0xb2] = psxBios_do_a_long_jmp
//biosA0[0xb3] = psxBios_sys_a0_b3;
- //biosA0[0xb4] = psxBios_sub_function;
+ biosA0[0xb4] = psxBios_GetSystemInfo;
//*******************B0 CALLS****************************
biosB0[0x00] = psxBios_SysMalloc;
//biosB0[0x01] = psxBios_sys_b0_01;
//biosB0[0x3a] = psxBios_getc;
//biosB0[0x3b] = psxBios_putc;
biosB0[0x3c] = psxBios_getchar;
+ biosB0[0x3d] = psxBios_putchar;
//biosB0[0x3e] = psxBios_gets;
+ biosB0[0x3f] = psxBios_puts;
//biosB0[0x40] = psxBios_cd;
biosB0[0x41] = psxBios_format;
biosB0[0x42] = psxBios_firstfile;
// initial RNG seed
psxMu32ref(0x9010) = SWAPu32(0xac20cc00);
+ // somewhat pretend to be a SCPH1001 BIOS
+ // some games look for these and take an exception if they're missing
rom32 = (u32 *)psxR;
rom32[0x100/4] = SWAP32(0x19951204);
rom32[0x104/4] = SWAP32(3);
strcpy(psxR + 0x108, "PCSX authors");
- strcpy(psxR + 0x12c, "PCSX HLE");
+ strcpy(psxR + 0x12c, "CEX-3000 PCSX HLE"); // see psxBios_GetSystemInfo
+ strcpy(psxR + 0x7ff32, "System ROM Version 2.2 12/04/95 A");
+ strcpy(psxR + 0x7ff54, "GPL-2.0-or-later");
// fonts
len = 0x80000 - 0x66000;
len = 0x80000 - 0x69d68;
uncompress((Bytef *)(psxR + 0x69d68), &len, font_889f, sizeof(font_889f));
- // memory size 2 MB
- psxHu32ref(0x1060) = SWAPu32(0x00000b88);
-
/* Some games like R-Types, CTR, Fade to Black read from adress 0x00000000 due to uninitialized pointers.
See Garbage Area at Address 00000000h in Nocash PSX Specfications for more information.
Here are some examples of games not working with this fix in place :
if (code != R3000E_Syscall) {
if (code != 0) {
DeliverEvent(0xf0000010, 0x1000);
- psxBios_SystemErrorUnresolvedException();
+ //psxBios_SystemErrorUnresolvedException();
}
mips_return_c(0, 17);
return;
}
tcb->lo = SWAP32(psxRegs.GPR.n.lo);
tcb->hi = SWAP32(psxRegs.GPR.n.hi);
- tcb->epc = SWAP32(psxRegs.CP0.n.EPC);
+ //tcb->epc = SWAP32(psxRegs.CP0.n.EPC); // done by asm
tcb->sr = SWAP32(psxRegs.CP0.n.SR);
tcb->cause = SWAP32(psxRegs.CP0.n.Cause);
sp = fp = loadRam32(A_EXC_SP);