X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?p=pcsx_rearmed.git;a=blobdiff_plain;f=libpcsxcore%2Fpsxbios.c;h=ecd4264d5db5fe1d24e7f84ee8c9b69fb1103ea1;hp=288e33b3060284c2cb421652e6fe091b979aaed4;hb=e49ac7a53e2fb04e24c6e75b7d38bf357210b96c;hpb=a946d159bfc8e85d5ff2bcb08fc940830d5acbf4 diff --git a/libpcsxcore/psxbios.c b/libpcsxcore/psxbios.c index 288e33b3..ecd4264d 100644 --- a/libpcsxcore/psxbios.c +++ b/libpcsxcore/psxbios.c @@ -1,5 +1,6 @@ /*************************************************************************** - * Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team * + * Copyright (C) 2019 Ryan Schultz, PCSX-df Team, PCSX team, gameblabla, * + * 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 * @@ -17,6 +18,12 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA. * ***************************************************************************/ +/* 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. */ @@ -245,6 +252,7 @@ static u32 *jmp_int = NULL; static int *pad_buf = NULL; static char *pad_buf1 = NULL, *pad_buf2 = NULL; static int pad_buf1len, pad_buf2len; +static int pad_stopped = 0; static u32 regs[35]; static EvCB *Event; @@ -299,6 +307,8 @@ static inline void DeliverEvent(u32 ev, u32 spec) { } else Event[ev][spec].status = EvStALREADY; } +static unsigned interrupt_r26=0x8004E8B0; + static inline void SaveRegs() { memcpy(regs, psxRegs.GPR.r, 32*4); regs[32] = psxRegs.GPR.n.lo; @@ -322,9 +332,10 @@ static inline void LoadRegs() { 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); \ ptr = Mcd##mcd##Data + 8192 * FDesc[1 + mcd].mcfile + FDesc[1 + mcd].offset; \ memcpy(Ra1, ptr, length); \ + if (FDesc[1 + mcd].mode & 0x8000) { \ DeliverEvent(0x11, 0x2); /* 0xf0000011, 0x0004 */ \ DeliverEvent(0x81, 0x2); /* 0xf4000001, 0x0004 */ \ - if (FDesc[1 + mcd].mode & 0x8000) v0 = 0; \ + v0 = 0; } \ else v0 = length; \ FDesc[1 + mcd].offset += v0; \ } @@ -334,10 +345,12 @@ static inline void LoadRegs() { SysPrintf("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; \ + SaveMcd(Config.Mcd##mcd, Mcd##mcd##Data, offset, length); \ + if (FDesc[1 + mcd].mode & 0x8000) { \ DeliverEvent(0x11, 0x2); /* 0xf0000011, 0x0004 */ \ DeliverEvent(0x81, 0x2); /* 0xf4000001, 0x0004 */ \ - FDesc[1 + mcd].offset += length; \ - if (FDesc[1 + mcd].mode & 0x8000) v0 = 0; \ + v0 = 0; } \ else v0 = length; \ } @@ -855,7 +868,6 @@ void psxBios_bcmp() { // 0x29 void psxBios_memcpy() { // 0x2a char *p1 = (char *)Ra0, *p2 = (char *)Ra1; - s32 n=0; v0 = a0; if (a0 == 0 || a2 > 0x7FFFFFFF) { @@ -863,7 +875,6 @@ void psxBios_memcpy() { // 0x2a return; } while ((s32)a2-- > 0) { - n++; *p1++ = *p2++; } a2 = 0; @@ -914,6 +925,12 @@ void psxBios_memcmp() { // 0x2d 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; @@ -1216,8 +1233,10 @@ void psxBios_InitHeap() { // 0x39 size &= 0xfffffffc; heap_addr = (u32 *)Ra0; - heap_end = (u32 *)((u8 *)heap_addr + size); - *heap_addr = SWAP32(size | 1); + heap_size = size; + heap_end = (u32 *)((u8 *)heap_addr + heap_size); + /* 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); @@ -1545,6 +1564,13 @@ void psxBios_SetMem() { // 9f pc0 = ra; } +/* TODO FIXME : Not compliant. -1 indicates failure but using 1 for now. */ +void psxBios_get_cd_status(void) //a6 +{ + v0 = 1; + pc0 = ra; +} + void psxBios__card_info() { // ab #ifdef PSXBIOS_LOG PSXBIOS_LOG("psxBios_%s: %x\n", biosA0n[0xab], a0); @@ -1568,11 +1594,8 @@ void psxBios__card_info() { // ab break; } -// DeliverEvent(0x11, 0x2); // 0xf0000011, 0x0004 -// DeliverEvent(0x11, 0x2); // 0xf0000011, 0x0004 - DeliverEvent(0x81, 0x2); // 0xf4000001, 0x0004 + DeliverEvent(0x11, 0x2); // 0xf4000001, 0x0004 DeliverEvent(0x81, ret); // 0xf4000001, 0x0004 - v0 = 1; pc0 = ra; } @@ -1762,9 +1785,15 @@ 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].mode == EvMdINTR)) Event[ev][spec].status = EvStACTIVE; + v0 = 1; + } + else + { + v0 = 0; + } #ifdef PSXBIOS_LOG PSXBIOS_LOG("psxBios_%s %x,%x: %x\n", biosB0n[0x0b], ev, spec, v0); @@ -1847,12 +1876,10 @@ void psxBios_CloseTh() { // 0f #ifdef PSXBIOS_LOG PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x0f], th); #endif - - if (Thread[th].status == 0) { - v0 = 0; - } else { + /* The return value is always 1 (even if the handle was already closed). */ + v0 = 1; + if (Thread[th].status != 0) { Thread[th].status = 0; - v0 = 1; } pc0 = ra; @@ -1868,14 +1895,11 @@ void psxBios_ChangeTh() { // 10 #ifdef PSXBIOS_LOG // PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x10], th); #endif - + /* The return value is always 1. */ + v0 = 1; if (Thread[th].status == 0 || CurThread == th) { - v0 = 0; - pc0 = ra; } else { - v0 = 1; - if (Thread[CurThread].status == 2) { Thread[CurThread].status = 1; Thread[CurThread].func = ra; @@ -1906,7 +1930,7 @@ void psxBios_StartPAD() { // 13 #ifdef PSXBIOS_LOG PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x13]); #endif - + pad_stopped = 0; psxHwWrite16(0x1f801074, (unsigned short)(psxHwRead16(0x1f801074) | 0x1)); psxRegs.CP0.n.Status |= 0x401; pc0 = ra; @@ -1916,10 +1940,9 @@ void psxBios_StopPAD() { // 14 #ifdef PSXBIOS_LOG PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x14]); #endif - if (pad_buf == 0){ + pad_stopped = 1; pad_buf1 = NULL; pad_buf2 = NULL; - } pc0 = ra; } @@ -1953,6 +1976,7 @@ void psxBios_ReturnFromException() { // 17 LoadRegs(); pc0 = psxRegs.CP0.n.EPC; + k0 = interrupt_r26; if (psxRegs.CP0.n.Cause & 0x80000000) pc0 += 4; psxRegs.CP0.n.Status = (psxRegs.CP0.n.Status & 0xfffffff0) | @@ -2199,10 +2223,18 @@ void psxBios_puts() { // 3e/3f 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) +{ + 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; \ \ @@ -2213,8 +2245,8 @@ int nfile; if (!ptr[0xa]) continue; \ ptr+= 0xa; \ if (pfile[0] == 0) { \ - strncpy(dir->name, ptr, sizeof(dir->name)); \ - dir->name[sizeof(dir->name) - 1] = '\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; } \ @@ -2252,7 +2284,7 @@ void psxBios_firstfile() { // 42 if (pa0) { strcpy(ffile, pa0); pfile = ffile+5; - nfile = 1; + nfile = 0; if (!strncmp(pa0, "bu00", 4)) { // firstfile() calls _card_read() internally, so deliver it's event DeliverEvent(0x11, 0x2); @@ -2419,8 +2451,11 @@ void psxBios__card_write() { // 0x4e #ifdef PSXBIOS_LOG PSXBIOS_LOG("psxBios_%s: %x,%x,%x\n", biosB0n[0x4e], a0, a1, a2); #endif - /* Function also accepts sector 400h (a bug) */ - if (!(a1 <= 0x400)) + /* + Function also accepts sector 400h (a bug). + But notaz said we shouldn't allow sector 400h because it can corrupt the emulator. + */ + if (!(a1 <= 0x3FF)) { /* Invalid sectors */ v0 = 0; pc0 = ra; @@ -2452,8 +2487,11 @@ void psxBios__card_read() { // 0x4f #ifdef PSXBIOS_LOG PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x4f]); #endif - /* Function also accepts sector 400h (a bug) */ - if (!(a1 <= 0x400)) + /* + Function also accepts sector 400h (a bug). + But notaz said we shouldn't allow sector 400h because it can corrupt the emulator. + */ + if (!(a1 <= 0x3FF)) { /* Invalid sectors */ v0 = 0; pc0 = ra; @@ -2567,6 +2605,24 @@ void psxBios_ChangeClearPad() { // 5b pc0 = ra; } +void psxBios__card_status() { // 5c +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x5c], a0); +#endif + + v0 = card_active_chan; + pc0 = ra; +} + +void psxBios__card_wait() { // 5d +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x5d], a0); +#endif + + v0 = 1; + pc0 = ra; +} + /* System calls C0 */ /* @@ -2814,7 +2870,7 @@ void psxBiosInit() { //biosA0[0xa3] = psxBios_DequeueCdIntr; //biosA0[0xa4] = psxBios_sys_a0_a4; //biosA0[0xa5] = psxBios_ReadSector; - //biosA0[0xa6] = psxBios_get_cd_status; + biosA0[0xa6] = psxBios_get_cd_status; //biosA0[0xa7] = psxBios_bufs_cb_0; //biosA0[0xa8] = psxBios_bufs_cb_1; //biosA0[0xa9] = psxBios_bufs_cb_2; @@ -2920,8 +2976,8 @@ void psxBiosInit() { //biosB0[0x59] = psxBios_sys_b0_59; //biosB0[0x5a] = psxBios_sys_b0_5a; biosB0[0x5b] = psxBios_ChangeClearPad; - //biosB0[0x5c] = psxBios__card_status; - //biosB0[0x5d] = psxBios__card_wait; + biosB0[0x5c] = psxBios__card_status; + biosB0[0x5d] = psxBios__card_wait; //*******************C0 CALLS**************************** //biosC0[0x00] = psxBios_InitRCnt; //biosC0[0x01] = psxBios_InitException; @@ -2975,6 +3031,7 @@ void psxBiosInit() { memset(Thread, 0, sizeof(Thread)); Thread[0].status = 2; // main thread + pad_stopped = 1; jmp_int = NULL; pad_buf = NULL; pad_buf1 = NULL; @@ -2986,6 +3043,7 @@ void psxBiosInit() { CardState = -1; CurThread = 0; memset(FDesc, 0, sizeof(FDesc)); + card_active_chan = 0; psxMu32ref(0x0150) = SWAPu32(0x160); psxMu32ref(0x0154) = SWAPu32(0x320); @@ -2999,7 +3057,9 @@ void psxBiosInit() { */ // 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. + 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); @@ -3025,6 +3085,22 @@ void psxBiosInit() { 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() { @@ -3110,12 +3186,14 @@ void biosInterrupt() { if (NET_recvPadData(pad_buf2, 2) == -1) netError(); } else { - if (pad_buf1) { - psxBios_PADpoll(1); - } + if (!pad_stopped) { + if (pad_buf1) { + psxBios_PADpoll(1); + } - if (pad_buf2) { - psxBios_PADpoll(2); + if (pad_buf2) { + psxBios_PADpoll(2); + } } } @@ -3145,6 +3223,7 @@ void psxBiosException() { switch (psxRegs.CP0.n.Cause & 0x3c) { case 0x00: // Interrupt + interrupt_r26=psxRegs.CP0.n.EPC; #ifdef PSXCPU_LOG // PSXCPU_LOG("interrupt\n"); #endif @@ -3257,4 +3336,6 @@ void psxBiosFreeze(int Mode) { bfreezel(&CurThread); bfreezes(FDesc); bfreezel(&card_active_chan); + bfreezel(&pad_stopped); + bfreezel(&heap_size); }