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=b13874ea7476ef1ef3d8b9bc7f850ab86eccc156;hb=e49ac7a53e2fb04e24c6e75b7d38bf357210b96c;hpb=324cec89343c216ad232fbcaf50faed6e528beef diff --git a/libpcsxcore/psxbios.c b/libpcsxcore/psxbios.c index b13874ea..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; @@ -254,6 +262,7 @@ static EvCB *RcEV; // 0xf2 static EvCB *UeEV; // 0xf3 static EvCB *SwEV; // 0xf4 static EvCB *ThEV; // 0xff +static u32 heap_size = 0; static u32 *heap_addr = NULL; static u32 *heap_end = NULL; static u32 SysIntRP[8]; @@ -298,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; @@ -316,12 +327,41 @@ static inline void LoadRegs() { // * // System calls A0 */ + +#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); \ + 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 */ \ + v0 = 0; } \ + else v0 = length; \ + FDesc[1 + mcd].offset += v0; \ +} + +#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); \ + 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 */ \ + v0 = 0; } \ + else v0 = length; \ +} + + /* 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. */ /* TODO FIX ME : Properly implement this behaviour */ void psxBios_getc(void) // 0x03, 0x35 { + char *ptr; void *pa1 = Ra1; #ifdef PSXBIOS_LOG PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x03]); @@ -341,6 +381,7 @@ void psxBios_getc(void) // 0x03, 0x35 /* Copy of psxBios_write, except size is 1. */ void psxBios_putc(void) // 0x09, 0x3B { + char *ptr; void *pa1 = Ra1; #ifdef PSXBIOS_LOG PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x09]); @@ -369,6 +410,33 @@ void psxBios_putc(void) // 0x09, 0x3B pc0 = ra; } +void psxBios_todigit(void) // 0x0a +{ + int c = a0; +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x0a]); +#endif + c &= 0xFF; + if (c >= 0x30 && c < 0x3A) { + c -= 0x30; + } + else if (c > 0x60 && c < 0x7B) { + c -= 0x20; + } + else if (c > 0x40 && c < 0x5B) { + c = c - 0x41 + 10; + } + else if (c >= 0x80) { + c = -1; + } + else + { + c = 0x0098967F; + } + v0 = c; + pc0 = ra; +} + void psxBios_abs() { // 0x0e if ((s32)a0 < 0) v0 = -(s32)a0; else v0 = a0; @@ -466,7 +534,12 @@ void psxBios_strncat() { // 0x16 #ifdef PSXBIOS_LOG PSXBIOS_LOG("psxBios_%s: %s (%x), %s (%x), %d\n", biosA0n[0x16], Ra0, a0, Ra1, a1, a2); #endif - + if (a0 == 0 || a1 == 0) + { + v0 = 0; + pc0 = ra; + return; + } while (*p1++); --p1; while ((*p1++ = *p2++) != '\0') { @@ -481,13 +554,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; @@ -495,13 +590,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 @@ -510,16 +625,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; @@ -528,7 +657,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) { @@ -545,13 +679,24 @@ 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; } 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); @@ -567,7 +712,11 @@ void psxBios_rindex() { // 0x1d char *p = (char *)Ra0; v0 = 0; - + if (a0 == 0) + { + pc0 = ra; + return; + } do { if (*p == a1) v0 = a0 + (p - (char *)Ra0); @@ -670,15 +819,34 @@ void psxBios_tolower() { // 0x26 void psxBios_bcopy() { // 0x27 char *p1 = (char *)Ra1, *p2 = (char *)Ra0; + v0 = a0; + if (a0 == 0 || a2 > 0x7FFFFFFF) + { + pc0 = ra; + return; + } while ((s32)a2-- > 0) *p1++ = *p2++; - + a2 = 0; pc0 = ra; } void psxBios_bzero() { // 0x28 char *p = (char *)Ra0; + v0 = a0; + /* Same as memset here (See memset below) */ + if (a1 > 0x7FFFFFFF || a1 == 0) + { + v0 = 0; + pc0 = ra; + return; + } + else if (a0 == 0) + { + pc0 = ra; + return; + } while ((s32)a1-- > 0) *p++ = '\0'; - + a1 = 0; pc0 = ra; } @@ -700,22 +868,46 @@ void psxBios_bcmp() { // 0x29 void psxBios_memcpy() { // 0x2a char *p1 = (char *)Ra0, *p2 = (char *)Ra1; - while ((s32)a2-- > 0) *p1++ = *p2++; - - v0 = a0; pc0 = ra; + v0 = a0; + if (a0 == 0 || a2 > 0x7FFFFFFF) + { + pc0 = ra; + return; + } + while ((s32)a2-- > 0) { + *p1++ = *p2++; + } + a2 = 0; + pc0 = ra; } void psxBios_memset() { // 0x2b char *p = (char *)Ra0; + v0 = a0; + if (a2 > 0x7FFFFFFF || a2 == 0) + { + v0 = 0; + pc0 = ra; + return; + } + if (a0 == 0) + { + pc0 = ra; + return; + } while ((s32)a2-- > 0) *p++ = (char)a1; - a2 = 0; v0 = a0; pc0 = ra; } void psxBios_memmove() { // 0x2c char *p1 = (char *)Ra0, *p2 = (char *)Ra1; - + v0 = a0; + if (a0 == 0 || a2 > 0x7FFFFFFF) + { + pc0 = ra; + return; + } if (p2 <= p1 && p2 + a2 > p1) { a2++; // BUG: copy one more byte here p1 += a2; @@ -724,8 +916,7 @@ void psxBios_memmove() { // 0x2c } else { while ((s32)a2-- > 0) *p1++ = *p2++; } - - v0 = a0; pc0 = ra; + pc0 = ra; } void psxBios_memcmp() { // 0x2d @@ -734,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; @@ -870,6 +1067,11 @@ void psxBios_malloc() { // 0x33 #ifdef PSXBIOS_LOG PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x33]); #endif + if (!a0 || (!heap_size || !heap_addr)) { + v0 = 0; + pc0 = ra; + return; + } // scan through heap and combine free chunks of space chunk = heap_addr; @@ -879,6 +1081,15 @@ void psxBios_malloc() { // 0x33 csize = ((u32)*chunk) & 0xfffffffc; cstat = ((u32)*chunk) & 1; + // most probably broken heap descriptor + // this fixes Burning Road + if (*chunk == 0) { + newchunk = chunk; + dsize = ((uptr)heap_end - (uptr)chunk) - 4; + colflag = 1; + break; + } + // it's a free chunk if(cstat == 1) { if(colflag == 0) { @@ -910,28 +1121,36 @@ void psxBios_malloc() { // 0x33 // exit on uninitialized heap if (chunk == NULL) { - SysPrintf("malloc %x,%x: Uninitialized Heap!\n", v0, a0); + printf("malloc %x,%x: Uninitialized Heap!\n", v0, a0); v0 = 0; pc0 = ra; return; } // search an unused chunk that is big enough until the end of the heap - while ((dsize > csize || cstat == 0) && chunk < heap_end ) { + while ((dsize > csize || cstat==0) && chunk < heap_end ) { chunk = (u32*)((uptr)chunk + csize + 4); + + // catch out of memory + if(chunk >= heap_end) { + printf("malloc %x,%x: Out of memory error!\n", + v0, a0); + v0 = 0; pc0 = ra; + return; + } + csize = ((u32)*chunk) & 0xfffffffc; cstat = ((u32)*chunk) & 1; } - // catch out of memory - if(chunk >= heap_end) { SysPrintf("malloc %x,%x: Out of memory error!\n", v0, a0); v0 = 0; pc0 = ra; return; } - // allocate memory if(dsize == csize) { // chunk has same size *chunk &= 0xfffffffc; - } - else { + } else if (dsize > csize) { + v0 = 0; pc0 = ra; + return; + } else { // split free chunk *chunk = SWAP32(dsize); newchunk = (u32*)((uptr)chunk + dsize + 4); @@ -939,9 +1158,9 @@ void psxBios_malloc() { // 0x33 } // return pointer to allocated memory - v0 = ((unsigned long)chunk - (unsigned long)psxM) + 4; + v0 = ((uptr)chunk - (uptr)psxM) + 4; v0|= 0x80000000; - SysPrintf ("malloc %x,%x\n", v0, a0); + //printf ("malloc %x,%x\n", v0, a0); pc0 = ra; } @@ -953,7 +1172,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; } @@ -978,9 +1198,24 @@ void psxBios_realloc() { // 0x38 #endif a0 = block; - psxBios_free(); - a0 = size; - psxBios_malloc(); + /* If "old_buf" is zero, executes malloc(new_size), and returns r2=new_buf (or 0=failed). */ + if (block == 0) + { + psxBios_malloc(); + } + /* Else, if "new_size" is zero, executes free(old_buf), and returns r2=garbage. */ + else if (size == 0) + { + psxBios_free(); + } + /* Else, executes malloc(new_size), bcopy(old_buf,new_buf,new_size), and free(old_buf), and returns r2=new_buf (or 0=failed). */ + /* Note that it is not quite implemented this way here. */ + else + { + psxBios_free(); + a0 = size; + psxBios_malloc(); + } } @@ -998,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); @@ -1327,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); @@ -1350,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; } @@ -1515,14 +1756,27 @@ void psxBios_WaitEvent() { // 0a ev = a0 & 0xff; spec = (a0 >> 8) & 0xff; - #ifdef PSXBIOS_LOG PSXBIOS_LOG("psxBios_%s %x,%x\n", biosB0n[0x0a], ev, spec); #endif + if (Event[ev][spec].status == EvStUNUSED) + { + v0 = 0; + pc0 = ra; + return; + } - Event[ev][spec].status = EvStACTIVE; + 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 @@ -1531,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); @@ -1580,8 +1840,20 @@ void psxBios_OpenTh() { // 0e int th; for (th=1; th<8; th++) + { if (Thread[th].status == 0) break; + } + if (th == 8) { + // Feb 2019 - Added out-of-bounds fix caught by cppcheck: + // When no free TCB is found, return 0xffffffff according to Nocash doc. +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("\t%s() WARNING! No Free TCBs found!\n", __func__); +#endif + v0 = 0xffffffff; + pc0 = ra; + return; + } #ifdef PSXBIOS_LOG PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x0e], th); #endif @@ -1604,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; @@ -1625,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; @@ -1663,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; @@ -1673,7 +1940,7 @@ void psxBios_StopPAD() { // 14 #ifdef PSXBIOS_LOG PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x14]); #endif - + pad_stopped = 1; pad_buf1 = NULL; pad_buf2 = NULL; pc0 = ra; @@ -1709,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) | @@ -1871,18 +2139,6 @@ void psxBios_lseek() { // 0x33 pc0 = ra; } -#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); \ - ptr = Mcd##mcd##Data + 8192 * FDesc[1 + mcd].mcfile + FDesc[1 + mcd].offset; \ - memcpy(Ra1, ptr, length); \ - DeliverEvent(0x11, 0x2); /* 0xf0000011, 0x0004 */ \ - DeliverEvent(0x81, 0x2); /* 0xf4000001, 0x0004 */ \ - if (FDesc[1 + mcd].mode & 0x8000) v0 = 0; \ - else v0 = length; \ - FDesc[1 + mcd].offset += v0; \ -} - - /* * int read(int fd , void *buf , int nbytes); @@ -1908,18 +2164,6 @@ void psxBios_read() { // 0x34 pc0 = ra; } -#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); \ - ptr = Mcd##mcd##Data + offset; \ - memcpy(ptr, Ra1, length); \ - DeliverEvent(0x11, 0x2); /* 0xf0000011, 0x0004 */ \ - DeliverEvent(0x81, 0x2); /* 0xf4000001, 0x0004 */ \ - FDesc[1 + mcd].offset += length; \ - if (FDesc[1 + mcd].mode & 0x8000) v0 = 0; \ - else v0 = length; \ -} - /* * int write(int fd , void *buf , int nbytes); */ @@ -1979,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; \ \ @@ -1993,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; } \ @@ -2032,17 +2284,18 @@ 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); bufile(1); } else if (!strncmp(pa0, "bu10", 4)) { + // firstfile() calls _card_read() internally, so deliver it's event + DeliverEvent(0x11, 0x2); bufile(2); } } - // firstfile() calls _card_read() internally, so deliver it's event - DeliverEvent(0x11, 0x2); - pc0 = ra; } @@ -2198,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; @@ -2231,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; @@ -2263,6 +2522,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; @@ -2339,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 */ /* @@ -2432,7 +2716,7 @@ void psxBiosInit() { //biosA0[0x07] = psxBios_sys_a0_07; biosA0[0x08] = psxBios_getc; biosA0[0x09] = psxBios_putc; - //biosA0[0x0a] = psxBios_todigit; + biosA0[0x0a] = psxBios_todigit; //biosA0[0x0b] = psxBios_atof; //biosA0[0x0c] = psxBios_strtoul; //biosA0[0x0d] = psxBios_strtol; @@ -2586,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; @@ -2685,15 +2969,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; @@ -2747,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; @@ -2754,9 +3039,11 @@ void psxBiosInit() { pad_buf1len = pad_buf2len = 0; heap_addr = NULL; heap_end = NULL; + heap_size = 0; CardState = -1; CurThread = 0; memset(FDesc, 0, sizeof(FDesc)); + card_active_chan = 0; psxMu32ref(0x0150) = SWAPu32(0x160); psxMu32ref(0x0154) = SWAPu32(0x320); @@ -2770,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); @@ -2796,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() { @@ -2881,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); + } } } @@ -2916,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 @@ -2967,6 +3275,9 @@ void psxBiosException() { case 2: // ExitCritical - enable irq's 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; @@ -3025,4 +3336,6 @@ void psxBiosFreeze(int Mode) { bfreezel(&CurThread); bfreezes(FDesc); bfreezel(&card_active_chan); + bfreezel(&pad_stopped); + bfreezel(&heap_size); }