X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=libpcsxcore%2Fpsxbios.c;h=f57f5129c989d582978470ec6c0d93127e8b4fe0;hb=8c84ba5f4478dd4e7cc48e86f1b023bc6b99ea9c;hp=e9a13f990bbcbd4676f4ec59c5243259e9d84ffa;hpb=26b964b587007caace43f0dda8db1ac4a8c97e3d;p=pcsx_rearmed.git diff --git a/libpcsxcore/psxbios.c b/libpcsxcore/psxbios.c index e9a13f99..f57f5129 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. */ @@ -26,8 +33,13 @@ #include "psxbios.h" #include "psxhw.h" #include "gpu.h" +#include "sio.h" #include +#if (defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__) +#pragma GCC diagnostic ignored "-Wpointer-sign" +#endif + #undef SysPrintf #define SysPrintf if (Config.PsxOut) printf @@ -210,7 +222,7 @@ typedef struct { u32 func; } TCB; -typedef struct { +typedef struct { u32 _pc0; u32 gp0; u32 t_addr; @@ -245,9 +257,10 @@ 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; +static EvCB *EventCB; static EvCB *HwEV; // 0xf0 static EvCB *EvEV; // 0xf1 static EvCB *RcEV; // 0xf2 @@ -259,10 +272,10 @@ static u32 *heap_addr = NULL; static u32 *heap_end = NULL; static u32 SysIntRP[8]; static int CardState = -1; -static TCB Thread[8]; +static TCB ThreadCB[8]; static int CurThread = 0; static FileDesc FDesc[32]; -static u32 card_active_chan; +static u32 card_active_chan = 0; boolean hleSoftCall = FALSE; @@ -291,14 +304,16 @@ static inline void softCall2(u32 pc) { } static inline void DeliverEvent(u32 ev, u32 spec) { - if (Event[ev][spec].status != EvStACTIVE) return; + if (EventCB[ev][spec].status != EvStACTIVE) return; -// Event[ev][spec].status = EvStALREADY; - if (Event[ev][spec].mode == EvMdINTR) { - softCall2(Event[ev][spec].fhandler); - } else Event[ev][spec].status = EvStALREADY; +// EventCB[ev][spec].status = EvStALREADY; + if (EventCB[ev][spec].mode == EvMdINTR) { + softCall2(EventCB[ev][spec].fhandler); + } else EventCB[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 +337,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 +350,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; \ } @@ -355,7 +373,7 @@ void psxBios_getc(void) // 0x03, 0x35 #endif v0 = -1; - if (pa1) { + if (pa1 != INVALID_PTR) { switch (a0) { case 2: buread(pa1, 1, 1); break; case 3: buread(pa1, 2, 1); break; @@ -374,7 +392,7 @@ void psxBios_putc(void) // 0x09, 0x3B PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x09]); #endif v0 = -1; - if (!pa1) { + if (pa1 == INVALID_PTR) { pc0 = ra; return; } @@ -541,13 +559,35 @@ void psxBios_strncat() { // 0x16 void psxBios_strcmp() { // 0x17 char *p1 = (char *)Ra0, *p2 = (char *)Ra1; - + s32 n=0; + if (a0 == 0 && a1 == 0) + { + v0 = 0; + pc0 = ra; + return; + } + else if (a0 == 0 && a1 != 0) + { + v0 = -1; + pc0 = ra; + return; + } + else if (a0 != 0 && a1 == 0) + { + v0 = 1; + pc0 = ra; + return; + } #ifdef PSXBIOS_LOG PSXBIOS_LOG("psxBios_%s: %s (%x), %s (%x)\n", biosA0n[0x17], Ra0, a0, Ra1, a1); #endif while (*p1 == *p2++) { + n++; if (*p1++ == '\0') { + v1=n-1; + a0+=n; + a1+=n; v0 = 0; pc0 = ra; return; @@ -555,13 +595,33 @@ void psxBios_strcmp() { // 0x17 } v0 = (*p1 - *--p2); + v1 = n; + a0+=n; + a1+=n; pc0 = ra; } void psxBios_strncmp() { // 0x18 char *p1 = (char *)Ra0, *p2 = (char *)Ra1; s32 n = a2; - + if (a0 == 0 && a1 == 0) + { + v0 = 0; + pc0 = ra; + return; + } + else if (a0 == 0 && a1 != 0) + { + v0 = -1; + pc0 = ra; + return; + } + else if (a0 != 0 && a1 == 0) + { + v0 = 1; + pc0 = ra; + return; + } #ifdef PSXBIOS_LOG PSXBIOS_LOG("psxBios_%s: %s (%x), %s (%x), %d\n", biosA0n[0x18], Ra0, a0, Ra1, a1, a2); #endif @@ -570,16 +630,30 @@ void psxBios_strncmp() { // 0x18 if (*p1++ == '\0') { v0 = 0; pc0 = ra; + v1 = a2 - ((a2-n) - 1); + a0 += (a2-n) - 1; + a1 += (a2-n) - 1; + a2 = n; return; } } v0 = (n < 0 ? 0 : *p1 - *--p2); pc0 = ra; + v1 = a2 - ((a2-n) - 1); + a0 += (a2-n) - 1; + a1 += (a2-n) - 1; + a2 = n; } void psxBios_strcpy() { // 0x19 char *p1 = (char *)Ra0, *p2 = (char *)Ra1; + if (a0 == 0 || a1 == 0) + { + v0 = 0; + pc0 = ra; + return; + } while ((*p1++ = *p2++) != '\0'); v0 = a0; pc0 = ra; @@ -588,7 +662,12 @@ void psxBios_strcpy() { // 0x19 void psxBios_strncpy() { // 0x1a char *p1 = (char *)Ra0, *p2 = (char *)Ra1; s32 n = a2, i; - + if (a0 == 0 || a1 == 0) + { + v0 = 0; + pc0 = ra; + return; + } for (i = 0; i < n; i++) { if ((*p1++ = *p2++) == '\0') { while (++i < n) { @@ -605,6 +684,11 @@ void psxBios_strncpy() { // 0x1a void psxBios_strlen() { // 0x1b char *p = (char *)Ra0; v0 = 0; + if (a0 == 0) + { + pc0 = ra; + return; + } while (*p++) v0++; pc0 = ra; } @@ -617,7 +701,7 @@ void psxBios_index() { // 0x1c pc0 = ra; return; } - + do { if (*p == a1) { v0 = a0 + (p - (char *)Ra0); @@ -789,7 +873,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) { @@ -797,7 +880,6 @@ void psxBios_memcpy() { // 0x2a return; } while ((s32)a2-- > 0) { - n++; *p1++ = *p2++; } a2 = 0; @@ -849,6 +931,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; v0 = a0 + (p - (char *)Ra0 - 1); @@ -978,7 +1066,7 @@ void psxBios_qsort() { // 0x31 } void psxBios_malloc() { // 0x33 - unsigned int *chunk, *newchunk = NULL; + u32 *chunk, *newchunk = NULL; unsigned int dsize = 0, csize, cstat; int colflag; #ifdef PSXBIOS_LOG @@ -1089,7 +1177,8 @@ void psxBios_free() { // 0x34 SysPrintf("free %x: %x bytes\n", a0, *(u32*)(Ra0-4)); - *(u32*)(Ra0-4) |= 1; // set chunk to free + if (a0) + *(u32*)(Ra0-4) |= 1; // set chunk to free pc0 = ra; } @@ -1149,8 +1238,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); @@ -1161,7 +1252,7 @@ void psxBios_getchar() { //0x3b v0 = getchar(); pc0 = ra; } -void psxBios_printf() { // 0x3f +static void psxBios_printf_psxout() { // 0x3f char tmp[1024]; char tmp2[1024]; u32 save[4]; @@ -1170,7 +1261,7 @@ void psxBios_printf() { // 0x3f void *psp; psp = PSXM(sp); - if (psp) { + if (psp != INVALID_PTR) { memcpy(save, psp, 4 * 4); psxMu32ref(sp) = SWAP32((u32)a0); psxMu32ref(sp + 4) = SWAP32((u32)a1); @@ -1226,11 +1317,14 @@ _start: } *ptmp = 0; - if (psp) + if (psp != INVALID_PTR) memcpy(psp, save, 4 * 4); SysPrintf("%s", tmp); +} +void psxBios_printf() { // 0x3f + psxBios_printf_psxout(); pc0 = ra; } @@ -1315,43 +1409,44 @@ void psxBios_FlushCache() { // 44 #ifdef PSXBIOS_LOG PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x44]); #endif - + psxCpu->Notify(R3000ACPU_NOTIFY_CACHE_ISOLATED, NULL); + psxCpu->Notify(R3000ACPU_NOTIFY_CACHE_UNISOLATED, NULL); pc0 = ra; } void psxBios_GPU_dw() { // 0x46 int size; - s32 *ptr; + u32 *ptr; #ifdef PSXBIOS_LOG PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x46]); #endif GPU_writeData(0xa0000000); - GPU_writeData((a1<<16)|(a0&0xffff)); - GPU_writeData((a3<<16)|(a2&0xffff)); - size = (a2*a3+1)/2; - ptr = (s32*)PSXM(Rsp[4]); //that is correct? - do { - GPU_writeData(SWAP32(*ptr)); - ptr++; - } while(--size); + GPU_writeData((a1<<0x10)|(a0&0xffff)); + GPU_writeData((a3<<0x10)|(a2&0xffff)); + size = (a2*a3)/2; + ptr = (u32*)PSXM(Rsp[4]); //that is correct? + while(size--) + { + GPU_writeData(SWAPu32(*ptr++)); + } pc0 = ra; -} +} void psxBios_mem2vram() { // 0x47 int size; - + gpuSyncPluginSR(); GPU_writeData(0xa0000000); - GPU_writeData((a1<<16)|(a0&0xffff)); - GPU_writeData((a3<<16)|(a2&0xffff)); - size = (a2*a3+1)/2; + GPU_writeData((a1<<0x10)|(a0&0xffff)); + GPU_writeData((a3<<0x10)|(a2&0xffff)); + size = ((((a2 * a3) / 2) >> 4) << 16); GPU_writeStatus(0x04000002); psxHwWrite32(0x1f8010f4,0); psxHwWrite32(0x1f8010f0,psxHwRead32(0x1f8010f0)|0x800); psxHwWrite32(0x1f8010a0,Rsp[4]);//might have a buggy... - psxHwWrite32(0x1f8010a4,((size/16)<<16)|16); + psxHwWrite32(0x1f8010a4, size | 0x10); psxHwWrite32(0x1f8010a8,0x01000201); pc0 = ra; @@ -1364,22 +1459,26 @@ void psxBios_SendGPU() { // 0x48 } void psxBios_GPU_cw() { // 0x49 + gpuSyncPluginSR(); GPU_writeData(a0); + v0 = HW_GPU_STATUS; pc0 = ra; } void psxBios_GPU_cwb() { // 0x4a - s32 *ptr = (s32*)Ra0; + u32 *ptr = (u32*)Ra0; int size = a1; - while(size--) { - GPU_writeData(SWAP32(*ptr)); - ptr++; + gpuSyncPluginSR(); + while(size--) + { + GPU_writeData(SWAPu32(*ptr++)); } pc0 = ra; } void psxBios_GPU_SendPackets() { //4b: + gpuSyncPluginSR(); GPU_writeStatus(0x04000002); psxHwWrite32(0x1f8010f4,0); psxHwWrite32(0x1f8010f0,psxHwRead32(0x1f8010f0)|0x800); @@ -1414,7 +1513,7 @@ void psxBios_LoadExec() { // 51 #endif s_addr = a1; s_size = a2; - a1 = 0xf000; + a1 = 0xf000; psxBios_Load(); header->S_addr = s_addr; @@ -1469,7 +1568,7 @@ void psxBios_SetMem() { // 9f 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; @@ -1478,20 +1577,27 @@ 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); #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 @@ -1500,12 +1606,13 @@ void psxBios__card_info() { // ab ret = 0x11; break; } - -// DeliverEvent(0x11, 0x2); // 0xf0000011, 0x0004 -// DeliverEvent(0x11, 0x2); // 0xf0000011, 0x0004 - DeliverEvent(0x81, 0x2); // 0xf4000001, 0x0004 - DeliverEvent(0x81, ret); // 0xf4000001, 0x0004 + if (McdDisable[0] && McdDisable[1]) + ret = 0x8; + + DeliverEvent(0x11, 0x2); // 0xf0000011, 0x0004 +// DeliverEvent(0x81, 0x2); // 0xf4000001, 0x0004 + DeliverEvent(0x81, ret); // 0xf4000001, 0x0004 v0 = 1; pc0 = ra; } @@ -1593,14 +1700,14 @@ void psxBios_ResetRCnt() { // 06 } -/* gets ev for use with Event */ +/* gets ev for use with EventCB */ #define GetEv() \ ev = (a0 >> 24) & 0xf; \ if (ev == 0xf) ev = 0x5; \ ev*= 32; \ ev+= a0&0x1f; -/* gets spec for use with Event */ +/* gets spec for use with EventCB */ #define GetSpec() \ spec = 0; \ switch (a1) { \ @@ -1638,9 +1745,9 @@ void psxBios_OpenEvent() { // 08 PSXBIOS_LOG("psxBios_%s %x,%x (class:%x, spec:%x, mode:%x, func:%x)\n", biosB0n[0x08], ev, spec, a0, a1, a2, a3); #endif - Event[ev][spec].status = EvStWAIT; - Event[ev][spec].mode = a2; - Event[ev][spec].fhandler = a3; + EventCB[ev][spec].status = EvStWAIT; + EventCB[ev][spec].mode = a2; + EventCB[ev][spec].fhandler = a3; v0 = ev | (spec << 8); pc0 = ra; @@ -1656,7 +1763,7 @@ void psxBios_CloseEvent() { // 09 PSXBIOS_LOG("psxBios_%s %x,%x\n", biosB0n[0x09], ev, spec); #endif - Event[ev][spec].status = EvStUNUSED; + EventCB[ev][spec].status = EvStUNUSED; v0 = 1; pc0 = ra; } @@ -1669,17 +1776,17 @@ void psxBios_WaitEvent() { // 0a #ifdef PSXBIOS_LOG PSXBIOS_LOG("psxBios_%s %x,%x\n", biosB0n[0x0a], ev, spec); #endif - if (Event[ev][spec].status == EvStUNUSED) + if (EventCB[ev][spec].status == EvStUNUSED) { v0 = 0; - pc0 = ra; + pc0 = ra; return; } - if (Event[ev][spec].status == EvStALREADY) + if (EventCB[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; + if (!(EventCB[ev][spec].mode == EvMdINTR)) EventCB[ev][spec].status = EvStACTIVE; v0 = 1; pc0 = ra; return; @@ -1695,9 +1802,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 (EventCB[ev][spec].status == EvStALREADY) + { + if (!(EventCB[ev][spec].mode == EvMdINTR)) EventCB[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); @@ -1716,7 +1829,7 @@ void psxBios_EnableEvent() { // 0c PSXBIOS_LOG("psxBios_%s %x,%x\n", biosB0n[0x0c], ev, spec); #endif - Event[ev][spec].status = EvStACTIVE; + EventCB[ev][spec].status = EvStACTIVE; v0 = 1; pc0 = ra; } @@ -1731,7 +1844,7 @@ void psxBios_DisableEvent() { // 0d PSXBIOS_LOG("psxBios_%s %x,%x\n", biosB0n[0x0d], ev, spec); #endif - Event[ev][spec].status = EvStWAIT; + EventCB[ev][spec].status = EvStWAIT; v0 = 1; pc0 = ra; } @@ -1745,7 +1858,7 @@ void psxBios_OpenTh() { // 0e for (th=1; th<8; th++) { - if (Thread[th].status == 0) break; + if (ThreadCB[th].status == 0) break; } if (th == 8) { @@ -1762,10 +1875,10 @@ void psxBios_OpenTh() { // 0e PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x0e], th); #endif - Thread[th].status = 1; - Thread[th].func = a0; - Thread[th].reg[29] = a1; - Thread[th].reg[28] = a2; + ThreadCB[th].status = 1; + ThreadCB[th].func = a0; + ThreadCB[th].reg[29] = a1; + ThreadCB[th].reg[28] = a2; v0 = th; pc0 = ra; } @@ -1780,12 +1893,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 { - Thread[th].status = 0; - v0 = 1; + /* The return value is always 1 (even if the handle was already closed). */ + v0 = 1; + if (ThreadCB[th].status != 0) { + ThreadCB[th].status = 0; } pc0 = ra; @@ -1801,23 +1912,20 @@ void psxBios_ChangeTh() { // 10 #ifdef PSXBIOS_LOG // PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x10], th); #endif - - if (Thread[th].status == 0 || CurThread == th) { - v0 = 0; - + /* The return value is always 1. */ + v0 = 1; + if (ThreadCB[th].status == 0 || CurThread == th) { pc0 = ra; } else { - v0 = 1; - - if (Thread[CurThread].status == 2) { - Thread[CurThread].status = 1; - Thread[CurThread].func = ra; - memcpy(Thread[CurThread].reg, psxRegs.GPR.r, 32*4); + if (ThreadCB[CurThread].status == 2) { + ThreadCB[CurThread].status = 1; + ThreadCB[CurThread].func = ra; + memcpy(ThreadCB[CurThread].reg, psxRegs.GPR.r, 32*4); } - memcpy(psxRegs.GPR.r, Thread[th].reg, 32*4); - pc0 = Thread[th].func; - Thread[th].status = 2; + memcpy(psxRegs.GPR.r, ThreadCB[th].reg, 32*4); + pc0 = ThreadCB[th].func; + ThreadCB[th].status = 2; CurThread = th; } } @@ -1839,7 +1947,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; @@ -1849,10 +1957,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; } @@ -1886,6 +1993,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) | @@ -1921,26 +2029,27 @@ void psxBios_UnDeliverEvent() { // 0x20 PSXBIOS_LOG("psxBios_%s %x,%x\n", biosB0n[0x20], ev, spec); #endif - if (Event[ev][spec].status == EvStALREADY && - Event[ev][spec].mode == EvMdNOINTR) - Event[ev][spec].status = EvStACTIVE; + if (EventCB[ev][spec].status == EvStALREADY && + EventCB[ev][spec].mode == EvMdNOINTR) + EventCB[ev][spec].status = EvStACTIVE; pc0 = ra; } char ffile[64], *pfile; int nfile; -static void buopen(int mcd, u8 *ptr, u8 *cfg) + +static void buopen(int mcd, char *ptr, char *cfg) { int i; - u8 *fptr = ptr; + char *mcd_data = 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; + const char *fptr = mcd_data + 128 * i; if ((*fptr & 0xF0) != 0x50) continue; if (strcmp(FDesc[1 + mcd].name, fptr+0xa)) continue; FDesc[1 + mcd].mcfile = i; @@ -1949,12 +2058,11 @@ static void buopen(int mcd, u8 *ptr, u8 *cfg) break; } if (a1 & 0x200 && v0 == -1) { /* FCREAT */ - fptr = ptr; for (i=1; i<16; i++) { int j, xor, nblk = a1 >> 16; - u8 *pptr, *fptr2; + char *pptr, *fptr2; + char *fptr = mcd_data + 128 * i; - fptr += 128; if ((*fptr & 0xF0) != 0xa0) continue; FDesc[1 + mcd].mcfile = i; @@ -1969,7 +2077,7 @@ static void buopen(int mcd, u8 *ptr, u8 *cfg) int k; for(i++; i<16; i++) { fptr2 += 128; - + memset(fptr2, 0, 128); fptr2[0] = j < nblk ? 0x52 : 0x53; pptr[8] = i - 1; @@ -1999,8 +2107,6 @@ static void buopen(int mcd, u8 *ptr, u8 *cfg) */ void psxBios_open() { // 0x32 - int i; - char *ptr; void *pa0 = Ra0; #ifdef PSXBIOS_LOG @@ -2009,7 +2115,7 @@ void psxBios_open() { // 0x32 v0 = -1; - if (pa0) { + if (pa0 != INVALID_PTR) { if (!strncmp(pa0, "bu00", 4)) { buopen(1, Mcd1Data, Config.Mcd1); } @@ -2063,13 +2169,13 @@ void psxBios_read() { // 0x34 v0 = -1; - if (pa1) { + if (pa1 != INVALID_PTR) { switch (a0) { case 2: buread(pa1, 1, a2); break; case 3: buread(pa1, 2, a2); break; } } - + pc0 = ra; } @@ -2086,7 +2192,7 @@ void psxBios_write() { // 0x35/0x03 #endif v0 = -1; - if (!pa1) { + if (pa1 == INVALID_PTR) { pc0 = ra; return; } @@ -2109,6 +2215,25 @@ void psxBios_write() { // 0x35/0x03 pc0 = ra; } +static void psxBios_write_psxout() { + if (a0 == 1) { // stdout + const char *ptr = Ra1; + int len = a2; + + if (ptr != INVALID_PTR) + while (len-- > 0) + SysPrintf("%c", *ptr++); + } +} + +static void psxBios_putchar_psxout() { // 3d + SysPrintf("%c", (char)a0); +} + +static void psxBios_puts_psxout() { // 3e/3f + SysPrintf("%s", Ra0); +} + /* * int close(int fd); */ @@ -2132,10 +2257,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; \ \ @@ -2146,8 +2279,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; } \ @@ -2168,7 +2301,7 @@ int nfile; /* * struct DIRENTRY* firstfile(char *name,struct DIRENTRY *dir); */ - + void psxBios_firstfile() { // 42 struct DIRENTRY *dir = (struct DIRENTRY *)Ra1; void *pa0 = Ra0; @@ -2182,10 +2315,10 @@ void psxBios_firstfile() { // 42 v0 = 0; - if (pa0) { + if (pa0 != INVALID_PTR) { 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); @@ -2260,7 +2393,7 @@ void psxBios_rename() { // 44 v0 = 0; - if (pa0 && pa1) { + if (pa0 != INVALID_PTR && pa1 != INVALID_PTR) { if (!strncmp(pa0, "bu00", 4) && !strncmp(pa1, "bu00", 4)) { burename(1); } @@ -2302,7 +2435,7 @@ void psxBios_delete() { // 45 v0 = 0; - if (pa0) { + if (pa0 != INVALID_PTR) { if (!strncmp(pa0, "bu00", 4)) { budelete(1); } @@ -2352,8 +2485,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; @@ -2362,7 +2498,7 @@ void psxBios__card_write() { // 0x4e card_active_chan = a0; port = a0 >> 4; - if (pa2) { + if (pa2 != INVALID_PTR) { if (port == 0) { memcpy(Mcd1Data + a1 * 128, pa2, 128); SaveMcd(Config.Mcd1, Mcd1Data, a1 * 128, 128); @@ -2385,8 +2521,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; @@ -2395,7 +2534,7 @@ void psxBios__card_read() { // 0x4f card_active_chan = a0; port = a0 >> 4; - if (pa2) { + if (pa2 != INVALID_PTR) { if (port == 0) { memcpy(pa2, Mcd1Data + a1 * 128, 128); } else { @@ -2417,6 +2556,13 @@ void psxBios__new_card() { // 0x50 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; @@ -2488,11 +2634,29 @@ void psxBios__card_chan() { // 0x58 void psxBios_ChangeClearPad() { // 5b #ifdef PSXBIOS_LOG PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x5b], a0); -#endif +#endif 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 */ /* @@ -2538,11 +2702,11 @@ void psxBios_ChangeClearRCnt() { // 0a 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])(); @@ -2553,7 +2717,7 @@ void (*biosC0[256])(); void psxBiosInit() { u32 base, size; - u32 *ptr; + u32 *ptr; int i; uLongf len; @@ -2562,11 +2726,10 @@ void psxBiosInit() { biosB0[i] = NULL; biosC0[i] = NULL; } - biosA0[0x3e] = psxBios_puts; - biosA0[0x3f] = psxBios_printf; - - biosB0[0x3d] = psxBios_putchar; - biosB0[0x3f] = psxBios_puts; + biosA0[0x03] = biosB0[0x35] = psxBios_write_psxout; + biosA0[0x3c] = biosB0[0x3d] = psxBios_putchar_psxout; + biosA0[0x3e] = biosB0[0x3f] = psxBios_puts_psxout; + biosA0[0x3f] = psxBios_printf_psxout; if (!Config.HLE) return; @@ -2636,7 +2799,7 @@ void psxBiosInit() { 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; @@ -2652,7 +2815,7 @@ void psxBiosInit() { 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; @@ -2704,10 +2867,10 @@ void psxBiosInit() { //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; @@ -2740,7 +2903,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; @@ -2839,15 +3002,15 @@ void psxBiosInit() { //biosB0[0x52] = psxBios_sys_b0_52; //biosB0[0x53] = psxBios_sys_b0_53; //biosB0[0x54] = psxBios__get_errno; - //biosB0[0x55] = psxBios__get_error; + biosB0[0x55] = psxBios__get_error; biosB0[0x56] = psxBios_GetC0Table; biosB0[0x57] = psxBios_GetB0Table; biosB0[0x58] = psxBios__card_chan; //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; @@ -2859,7 +3022,7 @@ void psxBiosInit() { //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; @@ -2882,14 +3045,14 @@ void psxBiosInit() { /**/ base = 0x1000; size = sizeof(EvCB) * 32; - Event = (void *)&psxR[base]; base += size * 6; - memset(Event, 0, size * 6); - HwEV = Event; - EvEV = Event + 32; - RcEV = Event + 32 * 2; - UeEV = Event + 32 * 3; - SwEV = Event + 32 * 4; - ThEV = Event + 32 * 5; + EventCB = (void *)&psxR[base]; base += size * 6; + memset(EventCB, 0, size * 6); + HwEV = EventCB; + EvEV = EventCB + 32; + RcEV = EventCB + 32 * 2; + UeEV = EventCB + 32 * 3; + SwEV = EventCB + 32 * 4; + ThEV = EventCB + 32 * 5; ptr = (u32 *)&psxM[0x0874]; // b0 table ptr[0] = SWAPu32(0x4c54 - 0x884); @@ -2898,9 +3061,10 @@ void psxBiosInit() { ptr[6] = SWAPu32(0xc80); memset(SysIntRP, 0, sizeof(SysIntRP)); - memset(Thread, 0, sizeof(Thread)); - Thread[0].status = 2; // main thread + memset(ThreadCB, 0, sizeof(ThreadCB)); + ThreadCB[0].status = 2; // main thread + pad_stopped = 1; jmp_int = NULL; pad_buf = NULL; pad_buf1 = NULL; @@ -2912,6 +3076,7 @@ void psxBiosInit() { CardState = -1; CurThread = 0; memset(FDesc, 0, sizeof(FDesc)); + card_active_chan = 0; psxMu32ref(0x0150) = SWAPu32(0x160); psxMu32ref(0x0154) = SWAPu32(0x320); @@ -2925,7 +3090,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); @@ -2951,6 +3118,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() { @@ -3036,12 +3219,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); + } } } @@ -3071,6 +3256,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 @@ -3120,7 +3306,10 @@ void psxBiosException() { 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; @@ -3176,8 +3365,10 @@ void psxBiosFreeze(int Mode) { bfreezes(regs); bfreezes(SysIntRP); bfreezel(&CardState); - bfreezes(Thread); + bfreezes(ThreadCB); bfreezel(&CurThread); bfreezes(FDesc); bfreezel(&card_active_chan); + bfreezel(&pad_stopped); + bfreezel(&heap_size); }