/***************************************************************************
- * Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team *
+ * 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 *
* 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA. *
***************************************************************************/
-/* Gameblabla 2018-2019 :
++/* Gameblabla 2018-2019 :
+ * Numerous changes to bios calls as well as improvements in order to conform to nocash's findings
+ * for the PSX bios calls. Thanks senquack for helping out with some of the changes
+ * and helping to spot issues and refine my patches.
+ * */
+
/*
* Internal simulated HLE BIOS.
*/
u32 func;
} TCB;
--typedef struct {
++typedef struct {
u32 _pc0;
u32 gp0;
u32 t_addr;
void psxBios_index() { // 0x1c
char *p = (char *)Ra0;
-
+ if (a0 == 0)
+ {
+ v0 = 0;
+ pc0 = ra;
+ return;
+ }
+
do {
if (*p == a1) {
v0 = a0 + (p - (char *)Ra0);
void psxBios_memchr() { // 0x2e
char *p = (char *)Ra0;
-
+
+ if (a0 == 0 || a2 > 0x7FFFFFFF)
+ {
+ pc0 = ra;
+ return;
+ }
+
while ((s32)a2-- > 0) {
if (*p++ != (s8)a1) continue;
v0 = a0 + (p - (char *)Ra0 - 1);
} while(--size);
pc0 = ra;
--}
++}
void psxBios_mem2vram() { // 0x47
int size;
pc0 = ra;
}
--
--void psxBios_GPU_SendPackets() { //4b:
++
++void psxBios_GPU_SendPackets() { //4b:
GPU_writeStatus(0x04000002);
psxHwWrite32(0x1f8010f4,0);
psxHwWrite32(0x1f8010f0,psxHwRead32(0x1f8010f0)|0x800);
#endif
s_addr = a1; s_size = a2;
-- a1 = 0xf000;
++ a1 = 0xf000;
psxBios_Load();
header->S_addr = s_addr;
psxHu32ref(0x1060) = SWAP32(new | 0x300);
psxMu32ref(0x060) = a0;
SysPrintf("Change effective memory : %d MBytes\n",a0);
--
++
default:
SysPrintf("Effective memory must be 2/8 MBytes\n");
break;
#ifdef PSXBIOS_LOG
PSXBIOS_LOG("psxBios_%s: %x\n", biosA0n[0xab], a0);
#endif
-
- u32 ret;
++ u32 ret, port;
card_active_chan = a0;
-
- switch (card_active_chan)
- {
- case 0x00: case 0x01: case 0x02: case 0x03:
- ret = Config.Mcd1[0] ? 0x2 : 0x8;
- break;
- case 0x10: case 0x11: case 0x12: case 0x13:
- ret = Config.Mcd2[0] ? 0x2 : 0x8;
+ port = card_active_chan >> 4;
+
+ switch (port) {
+ case 0x0:
+ case 0x1:
+ ret = 0x2;
+ if (McdDisable[port & 1])
+ ret = 0x8;
break;
default:
#ifdef PSXBIOS_LOG
ret = 0x11;
break;
}
-
- DeliverEvent(0x11, 0x2); // 0xf4000001, 0x0004
+
+ if (McdDisable[0] && McdDisable[1])
+ ret = 0x8;
+
- // DeliverEvent(0x11, 0x2); // 0xf0000011, 0x0004
++ DeliverEvent(0x11, 0x2); // 0xf0000011, 0x0004
+// DeliverEvent(0x81, 0x2); // 0xf4000001, 0x0004
DeliverEvent(0x81, ret); // 0xf4000001, 0x0004
-
v0 = 1; pc0 = ra;
}
#ifdef PSXBIOS_LOG
PSXBIOS_LOG("psxBios_%s %x,%x\n", biosB0n[0x0a], ev, spec);
#endif
- pc0 = ra;
+ if (Event[ev][spec].status == EvStUNUSED)
+ {
+ v0 = 0;
++ pc0 = ra;
+ return;
+ }
- Event[ev][spec].status = EvStACTIVE;
- if (Event[ev][spec].status == EvStALREADY)
++ if (Event[ev][spec].status == EvStALREADY)
+ {
+ /* Callback events (mode=EvMdINTR) do never set the ready flag (and thus WaitEvent would hang forever). */
+ if (!(Event[ev][spec].mode == EvMdINTR)) Event[ev][spec].status = EvStACTIVE;
+ v0 = 1;
+ pc0 = ra;
+ return;
+ }
- v0 = 1; pc0 = ra;
+ v0 = 0;
+ pc0 = ra;
}
void psxBios_TestEvent() { // 0b
ev = a0 & 0xff;
spec = (a0 >> 8) & 0xff;
- if (Event[ev][spec].status == EvStALREADY) {
- Event[ev][spec].status = EvStACTIVE; v0 = 1;
- } else v0 = 0;
- if (Event[ev][spec].status == EvStALREADY)
++ if (Event[ev][spec].status == EvStALREADY)
+ {
+ if (!(Event[ev][spec].mode == EvMdINTR)) Event[ev][spec].status = EvStACTIVE;
+ v0 = 1;
- }
- else
++ }
++ else
+ {
+ v0 = 0;
+ }
#ifdef PSXBIOS_LOG
PSXBIOS_LOG("psxBios_%s %x,%x: %x\n", biosB0n[0x0b], ev, spec, v0);
pc0 = ra;
}
- #define buopen(mcd) { \
- strcpy(FDesc[1 + mcd].name, Ra0+5); \
- FDesc[1 + mcd].offset = 0; \
- FDesc[1 + mcd].mode = a1; \
- \
- for (i=1; i<16; i++) { \
- ptr = Mcd##mcd##Data + 128 * i; \
- if ((*ptr & 0xF0) != 0x50) continue; \
- if (strcmp(FDesc[1 + mcd].name, ptr+0xa)) continue; \
- FDesc[1 + mcd].mcfile = i; \
- SysPrintf("open %s\n", ptr+0xa); \
- v0 = 1 + mcd; \
- break; \
- } \
- if (a1 & 0x200 && v0 == -1) { /* FCREAT */ \
- for (i=1; i<16; i++) { \
- int j, xor = 0; \
- \
- ptr = Mcd##mcd##Data + 128 * i; \
- if ((*ptr & 0xF0) == 0x50) continue; \
- ptr[0] = 0x50 | (u8)(a1 >> 16); \
- ptr[4] = 0x00; \
- ptr[5] = 0x20; \
- ptr[6] = 0x00; \
- ptr[7] = 0x00; \
- ptr[8] = 'B'; \
- ptr[9] = 'I'; \
- strcpy(ptr+0xa, FDesc[1 + mcd].name); \
- for (j=0; j<127; j++) xor^= ptr[j]; \
- ptr[127] = xor; \
- FDesc[1 + mcd].mcfile = i; \
- SysPrintf("openC %s\n", ptr); \
- v0 = 1 + mcd; \
- SaveMcd(Config.Mcd##mcd, Mcd##mcd##Data, 128 * i, 128); \
- break; \
- } \
- } \
+ char ffile[64], *pfile;
+ int nfile;
+ static void buopen(int mcd, u8 *ptr, u8 *cfg)
+ {
+ int i;
+ u8 *fptr = ptr;
+
+ strcpy(FDesc[1 + mcd].name, Ra0+5);
+ FDesc[1 + mcd].offset = 0;
+ FDesc[1 + mcd].mode = a1;
+
+ for (i=1; i<16; i++) {
+ fptr += 128;
+ 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);
+ v0 = 1 + mcd;
+ break;
+ }
+ if (a1 & 0x200 && v0 == -1) { /* FCREAT */
+ fptr = ptr;
+ for (i=1; i<16; i++) {
+ int j, xor, nblk = a1 >> 16;
+ u8 *pptr, *fptr2;
+
+ fptr += 128;
+ if ((*fptr & 0xF0) != 0xa0) continue;
+
+ FDesc[1 + mcd].mcfile = i;
+ fptr[0] = 0x51;
+ fptr[4] = 0x00;
+ fptr[5] = 0x20 * nblk;
+ fptr[6] = 0x00;
+ fptr[7] = 0x00;
+ strcpy(fptr+0xa, FDesc[1 + mcd].name);
+ pptr = fptr2 = fptr;
+ for(j=2; j<=nblk; j++) {
+ int k;
+ for(i++; i<16; i++) {
+ fptr2 += 128;
-
++
+ memset(fptr2, 0, 128);
+ fptr2[0] = j < nblk ? 0x52 : 0x53;
+ pptr[8] = i - 1;
+ pptr[9] = 0;
+ for (k=0, xor=0; k<127; k++) xor^= pptr[k];
+ pptr[127] = xor;
+ pptr = fptr2;
+ break;
+ }
+ /* shouldn't this return ENOSPC if i == 16? */
+ }
+ 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);
+ v0 = 1 + mcd;
+ /* just go ahead and resave them all */
+ SaveMcd(cfg, ptr, 128, 128 * 15);
+ break;
+ }
+ /* shouldn't this return ENOSPC if i == 16? */
+ }
}
/*
if (pa1) {
switch (a0) {
- case 2: buread(pa1, 1); break;
- case 3: buread(pa1, 2); break;
+ case 2: buread(pa1, 1, a2); break;
+ case 3: buread(pa1, 2, a2); break;
}
}
--
- pc0 = ra;
- }
+
- #define buwrite(Ra1, mcd) { \
- 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); \
- ptr = Mcd##mcd##Data + offset; \
- memcpy(ptr, Ra1, a2); \
- FDesc[1 + mcd].offset += a2; \
- SaveMcd(Config.Mcd##mcd, Mcd##mcd##Data, offset, a2); \
- if (FDesc[1 + mcd].mode & 0x8000) v0 = 0; \
- else v0 = a2; \
- DeliverEvent(0x11, 0x2); /* 0xf0000011, 0x0004 */ \
- DeliverEvent(0x81, 0x2); /* 0xf4000001, 0x0004 */ \
+ pc0 = ra;
}
/*
pc0 = ra;
}
- char ffile[64], *pfile;
- int nfile;
+
+ /* 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)
++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); \
while (nfile < 16) { \
int match=1; \
\
/*
* struct DIRENTRY* firstfile(char *name,struct DIRENTRY *dir);
*/
--
++
void psxBios_firstfile() { // 42
struct DIRENTRY *dir = (struct DIRENTRY *)Ra1;
void *pa0 = Ra0;
pc0 = ra;
}
-{
+ /* According to a user, this allows Final Fantasy Tactics to save/load properly */
+ void psxBios__get_error(void) // 55
++{
+ v0 = 0;
+ pc0 = ra;
+ }
+
void psxBios_Krom2RawAdd() { // 0x51
int i = 0;
void psxBios_ChangeClearPad() { // 5b
#ifdef PSXBIOS_LOG
PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x5b], a0);
--#endif
++#endif
pc0 = ra;
}
pc0 = ra;
}
--void psxBios_dummy() {
++void psxBios_dummy() {
#ifdef PSXBIOS_LOG
PSXBIOS_LOG("unk %x call: %x\n", pc0 & 0x1fffff, t1);
#endif
-- pc0 = ra;
++ pc0 = ra;
}
void (*biosA0[256])();
void psxBiosInit() {
u32 base, size;
-- u32 *ptr;
++ u32 *ptr;
int i;
uLongf len;
biosA0[0x39] = psxBios_InitHeap;
//biosA0[0x3a] = psxBios__exit;
biosA0[0x3b] = psxBios_getchar;
-- biosA0[0x3c] = psxBios_putchar;
++ biosA0[0x3c] = psxBios_putchar;
//biosA0[0x3d] = psxBios_gets;
//biosA0[0x40] = psxBios_sys_a0_40;
//biosA0[0x41] = psxBios_LoadTest;
biosA0[0x4b] = psxBios_GPU_SendPackets;
biosA0[0x4c] = psxBios_sys_a0_4c;
biosA0[0x4d] = psxBios_GPU_GetGPUStatus;
-- //biosA0[0x4e] = psxBios_GPU_sync;
++ //biosA0[0x4e] = psxBios_GPU_sync;
//biosA0[0x4f] = psxBios_sys_a0_4f;
//biosA0[0x50] = psxBios_sys_a0_50;
biosA0[0x51] = psxBios_LoadExec;
//biosA0[0x7f] = psxBios_sys_a0_7f;
//biosA0[0x80] = psxBios_sys_a0_80;
//biosA0[0x81] = psxBios_sys_a0_81;
-- //biosA0[0x82] = psxBios_sys_a0_82;
++ //biosA0[0x82] = psxBios_sys_a0_82;
//biosA0[0x83] = psxBios_sys_a0_83;
//biosA0[0x84] = psxBios_sys_a0_84;
-- //biosA0[0x85] = psxBios__96_CdStop;
++ //biosA0[0x85] = psxBios__96_CdStop;
//biosA0[0x86] = psxBios_sys_a0_86;
//biosA0[0x87] = psxBios_sys_a0_87;
//biosA0[0x88] = psxBios_sys_a0_88;
//biosC0[0x07] = psxBios_InstallExeptionHandler;
//biosC0[0x08] = psxBios_SysInitMemory;
//biosC0[0x09] = psxBios_SysInitKMem;
-- biosC0[0x0a] = psxBios_ChangeClearRCnt;
++ biosC0[0x0a] = psxBios_ChangeClearRCnt;
//biosC0[0x0b] = psxBios_SystemError;
//biosC0[0x0c] = psxBios_InitDefInt;
//biosC0[0x0d] = psxBios_sys_c0_0d;
*/
// opcode HLE
psxRu32ref(0x0000) = SWAPu32((0x3b << 26) | 4);
- psxMu32ref(0x0000) = SWAPu32((0x3b << 26) | 0);
- /* Whatever this does, it actually breaks CTR, even without the uninitiliazed memory patch.
++ /* Whatever this does, it actually breaks CTR, even without the uninitiliazed memory patch.
+ Normally games shouldn't read from address 0 yet they do. See explanation below in details. */
+ //psxMu32ref(0x0000) = SWAPu32((0x3b << 26) | 0);
psxMu32ref(0x00a0) = SWAPu32((0x3b << 26) | 1);
psxMu32ref(0x00b0) = SWAPu32((0x3b << 26) | 2);
psxMu32ref(0x00c0) = SWAPu32((0x3b << 26) | 3);
psxHu32ref(0x1060) = SWAPu32(0x00000b88);
hleSoftCall = FALSE;
-
++
+ /* 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 :
+ R-type won't get past the Irem logo if not implemented.
+ Crash Team Racing will softlock after the Sony logo.
+ */
-
++
+ psxMu32ref(0x0000) = SWAPu32(0x00000003);
+ /*
+ But overwritten by 00000003h after soon.
+ psxMu32ref(0x0000) = SWAPu32(0x00001A3C);
+ */
+ psxMu32ref(0x0004) = SWAPu32(0x800C5A27);
+ psxMu32ref(0x0008) = SWAPu32(0x08000403);
+ psxMu32ref(0x000C) = SWAPu32(0x00000000);
}
void psxBiosShutdown() {
break;
case 2: // ExitCritical - enable irq's
-- psxRegs.CP0.n.Status |= 0x404;
++ psxRegs.CP0.n.Status |= 0x404;
+ break;
+ /* Normally this should cover SYS(00h, SYS(04h but they don't do anything relevant so... */
+ default:
break;
}
pc0 = psxRegs.CP0.n.EPC + 4;