X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=libpcsxcore%2Fpsxbios.c;h=a41cf54ec6b211b9d0b8c1b8382c5e47c1403d56;hb=46fe949677745250de387994657de2004fe3b29b;hp=19e0fe415a078f7dbc464f93b414fe7ff87bed65;hpb=11d23573173ec4b5074eb35665c6012a46034d5c;p=pcsx_rearmed.git diff --git a/libpcsxcore/psxbios.c b/libpcsxcore/psxbios.c index 19e0fe41..a41cf54e 100644 --- a/libpcsxcore/psxbios.c +++ b/libpcsxcore/psxbios.c @@ -1,6 +1,6 @@ /*************************************************************************** * 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 * @@ -38,10 +38,6 @@ #include "psxinterpreter.h" #include -#if (defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__) -#pragma GCC diagnostic ignored "-Wpointer-sign" -#endif - #ifndef PSXBIOS_LOG //#define PSXBIOS_LOG printf #define PSXBIOS_LOG(...) @@ -260,6 +256,8 @@ typedef struct { static FileDesc FDesc[32]; static char ffile[64]; static int nfile; +static char cdir[8*8+8]; +static u32 floodchk; // fixed RAM offsets, SCPH1001 compatible #define A_TT_ExCB 0x0100 @@ -294,8 +292,10 @@ static int nfile; #define A_HEAP_BASE 0x9000 #define A_HEAP_SIZE 0x9004 #define A_HEAP_END 0x9008 -#define A_HEAP_FLAG 0x900c +#define A_HEAP_INIT_FLG 0x900c #define A_RND_SEED 0x9010 +#define A_HEAP_FRSTCHNK 0xb060 +#define A_HEAP_CURCHNK 0xb064 #define A_CONF_TCB 0xb940 #define A_CONF_EvCB 0xb944 #define A_CONF_SP 0xb948 @@ -1216,114 +1216,98 @@ void psxBios_qsort() { // 0x31 pc0 = ra; } -// this isn't how the real bios works, but maybe good enough +static int malloc_heap_grow(u32 size) { + u32 heap_addr, heap_end, heap_addr_new; + + heap_addr = loadRam32(A_HEAP_BASE); + heap_end = loadRam32(A_HEAP_END); + heap_addr_new = heap_addr + 4 + size; + if (heap_addr_new >= heap_end) + return -1; + storeRam32(A_HEAP_BASE, heap_addr_new); + storeRam32(heap_addr - 4, size | 1); + storeRam32(heap_addr + size, ~1); // terminator + return 0; +} + static void psxBios_malloc() { // 0x33 - u32 *heap_addr, *heap_end; - u32 *chunk, *newchunk = NULL; - unsigned int dsize = 0, csize, cstat; - int colflag; - PSXBIOS_LOG("psxBios_%s %x\n", biosA0n[0x33], a0); - heap_addr = loadRam32ptr(A_HEAP_BASE); - heap_end = loadRam32ptr(A_HEAP_END); - if (heap_addr >= heap_end) { - v0 = 0; - pc0 = ra; - return; - } + u32 size = (a0 + 3) & ~3; + u32 limit = 32*1024; + u32 tries = 2, i; + u32 ret; - // scan through heap and combine free chunks of space - chunk = heap_addr; - colflag = 0; - while(chunk < heap_end) { - // get size and status of actual chunk - 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; + PSXBIOS_LOG("psxBios_%s %d\n", biosA0n[0x33], a0); + + if (!loadRam32(A_HEAP_INIT_FLG)) { + u32 heap_addr = loadRam32(A_HEAP_BASE); + storeRam32(heap_addr, ~1); + storeRam32(A_HEAP_FRSTCHNK, heap_addr); + storeRam32(A_HEAP_CURCHNK, heap_addr); + storeRam32(A_HEAP_BASE, heap_addr + 4); + if (malloc_heap_grow(size)) { + PSXBIOS_LOG("malloc: init OOM\n"); + mips_return_c(0, 20); + return; } + storeRam32(A_HEAP_INIT_FLG, 1); + } - // it's a free chunk - if(cstat == 1) { - if(colflag == 0) { - newchunk = chunk; - dsize = csize; - colflag = 1; // let's begin a new collection of free memory + for (i = 0; tries > 0 && i < limit; i++) + { + u32 chunk = loadRam32(A_HEAP_CURCHNK); + u32 chunk_hdr = loadRam32(chunk); + u32 next_chunk = chunk + 4 + (chunk_hdr & ~3); + u32 next_chunk_hdr = loadRam32(next_chunk); + use_cycles(20); + //printf(" c %08x %08x\n", chunk, chunk_hdr); + if (chunk_hdr & 1) { + // free chunk + if (chunk_hdr > (size | 1)) { + // split + u32 p2size = (chunk_hdr & ~3) - size - 4; + storeRam32(chunk + 4 + size, p2size | 1); + chunk_hdr = size | 1; + } + if (chunk_hdr == (size | 1)) { + storeRam32(chunk, size); + break; + } + // chunk too small + if (next_chunk_hdr & 1) { + // merge + u32 msize = (chunk_hdr & ~3) + 4 + (next_chunk_hdr & ~3); + storeRam32(chunk, msize | 1); + continue; } - else dsize += (csize+4); // add the new size including header } - // not a free chunk: did we start a collection ? + if (chunk_hdr == ~1) { + // last chunk + if (tries == 2) + storeRam32(A_HEAP_CURCHNK, loadRam32(A_HEAP_FRSTCHNK)); + tries--; + } else { - if(colflag == 1) { // collection is over - colflag = 0; - *newchunk = SWAP32(dsize | 1); - } + // go to the next chunk + storeRam32(A_HEAP_CURCHNK, next_chunk); } - - // next chunk - chunk = (u32*)((uptr)chunk + csize + 4); - } - // if neccessary free memory on end of heap - if (colflag == 1) - *newchunk = SWAP32(dsize | 1); - - chunk = heap_addr; - csize = ((u32)*chunk) & 0xfffffffc; - cstat = ((u32)*chunk) & 1; - dsize = (a0 + 3) & 0xfffffffc; - - // exit on uninitialized heap - if (chunk == NULL) { - 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 ) { - 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; + if (i == limit) + ret = 0; + else if (tries == 0 && malloc_heap_grow(size)) + ret = 0; + else { + u32 chunk = loadRam32(A_HEAP_CURCHNK); + storeRam32(chunk, loadRam32(chunk) & ~3); + ret = chunk + 4; } - // allocate memory - if(dsize == csize) { - // chunk has same size - *chunk &= 0xfffffffc; - } else if (dsize > csize) { - v0 = 0; pc0 = ra; - return; - } else { - // split free chunk - *chunk = SWAP32(dsize); - newchunk = (u32*)((uptr)chunk + dsize + 4); - *newchunk = SWAP32(((csize - dsize - 4) & 0xfffffffc) | 1); - } - - // return pointer to allocated memory - v0 = ((uptr)chunk - (uptr)psxM) + 4; - v0|= 0x80000000; - //printf ("malloc %x,%x\n", v0, a0); - pc0 = ra; + PSXBIOS_LOG(" -> %08x\n", ret); + mips_return_c(ret, 40); } static void psxBios_free() { // 0x34 - PSXBIOS_LOG("psxBios_%s %x (%x bytes)\n", biosA0n[0x34], a0, loadRam32(a0 - 4)); + PSXBIOS_LOG("psxBios_%s %x (%d bytes)\n", biosA0n[0x34], a0, loadRam32(a0 - 4)); storeRam32(a0 - 4, loadRam32(a0 - 4) | 1); // set chunk to free mips_return_void_c(5); } @@ -1378,7 +1362,7 @@ static void psxBios_InitHeap() { // 0x39 storeRam32(A_HEAP_BASE, a0); storeRam32(A_HEAP_SIZE, a1); storeRam32(A_HEAP_END, a0 + (a1 & ~3) + 4); - storeRam32(A_HEAP_FLAG, 0); + storeRam32(A_HEAP_INIT_FLG, 0); storeRam32(a0, 0); mips_return_void_c(14); @@ -1465,7 +1449,19 @@ void psxBios_printf() { // 0x3f pc0 = ra; } -void psxBios_format() { // 0x41 +static void psxBios_cd() { // 0x40 + const char *p, *dir = castRam8ptr(a0); + PSXBIOS_LOG("psxBios_%s %x(%s)\n", biosB0n[0x40], a0, dir); + if ((p = strchr(dir, ':'))) + dir = ++p; + if (*dir == '\\') + dir++; + snprintf(cdir, sizeof(cdir), "%s", dir); + mips_return_c(1, 100); +} + +static void psxBios_format() { // 0x41 + PSXBIOS_LOG("psxBios_%s %x(%s)\n", biosB0n[0x41], a0, Ra0); if (strcmp(Ra0, "bu00:") == 0 && Config.Mcd1[0] != '\0') { CreateMcd(Config.Mcd1); @@ -1486,9 +1482,9 @@ void psxBios_format() { // 0x41 } static void psxBios_SystemErrorUnresolvedException() { - if (loadRam32(0xfffc) != 0x12345678) { // prevent log flood + if (floodchk != 0x12340a40) { // prevent log flood SysPrintf("psxBios_%s called from %08x\n", biosA0n[0x40], ra); - storeRam32(0xfffc, 0x12345678); + floodchk = 0x12340a40; } mips_return_void_c(1000); } @@ -1507,16 +1503,33 @@ static void FlushCache() { void psxBios_Load() { // 0x42 EXE_HEADER eheader; + char path[256]; + char *pa0, *p; void *pa1; + pa0 = Ra0; pa1 = Ra1; - if (pa1 != INVALID_PTR && LoadCdromFile(Ra0, &eheader) == 0) { + PSXBIOS_LOG("psxBios_%s %x(%s), %x\n", biosA0n[0x42], a0, pa0, a1); + if (pa0 == INVALID_PTR || pa1 == INVALID_PTR) { + mips_return(0); + return; + } + if ((p = strchr(pa0, ':'))) + pa0 = ++p; + if (*pa0 == '\\') + pa0++; + if (cdir[0]) + snprintf(path, sizeof(path), "%s\\%s", cdir, (char *)pa0); + else + snprintf(path, sizeof(path), "%s", (char *)pa0); + + if (LoadCdromFile(path, &eheader) == 0) { memcpy(pa1, ((char*)&eheader)+16, sizeof(EXEC)); psxCpu->Clear(a1, sizeof(EXEC) / 4); FlushCache(); v0 = 1; } else v0 = 0; - PSXBIOS_LOG("psxBios_%s: %s, %d -> %d\n", biosA0n[0x42], Ra0, a1, v0); + PSXBIOS_LOG(" -> %d\n", v0); pc0 = ra; } @@ -1948,6 +1961,7 @@ static u32 DeliverEvent(u32 class, u32 spec) { } } } + floodchk = 0; use_cycles(29); return ret; } @@ -2059,7 +2073,11 @@ static void psxBios_TestEvent() { // 0b u32 base = loadRam32(A_TT_EvCB); u32 status = loadRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4); u32 ret = 0; - PSXBIOS_LOG("psxBios_%s %x %x\n", biosB0n[0x0b], a0, status); + + if (psxRegs.cycle - floodchk > 16*1024u) { // prevent log flood + PSXBIOS_LOG("psxBios_%s %x %x\n", biosB0n[0x0b], a0, status); + floodchk = psxRegs.cycle; + } if (status == EvStALREADY) { storeRam32(base + (a0 & 0xffff) * sizeof(EvCB) + 4, EvStACTIVE); ret = 1; @@ -2560,7 +2578,7 @@ static void bufile(const u8 *mcd_data, u32 dir_) { } for (; nfile <= 15; nfile++, blocks++) { const u8 *data2 = mcd_data + 128 * nfile; - const char *name = data2 + 0x0a; + const char *name = (const char *)data2 + 0x0a; if ((data2[0] & 0xF0) != 0x50 || name[0]) break; } @@ -2593,11 +2611,11 @@ static void psxBios_firstfile() { // 42 if (!strncmp(pa0, "bu00", 4)) { // firstfile() calls _card_read() internally, so deliver it's event DeliverEvent(0xf0000011, 0x0004); - bufile(Mcd1Data, a1); + bufile((u8 *)Mcd1Data, a1); } else if (!strncmp(pa0, "bu10", 4)) { // firstfile() calls _card_read() internally, so deliver it's event DeliverEvent(0xf0000011, 0x0004); - bufile(Mcd2Data, a1); + bufile((u8 *)Mcd2Data, a1); } } @@ -2613,9 +2631,9 @@ void psxBios_nextfile() { // 43 v0 = 0; if (!strncmp(ffile, "bu00", 4)) - bufile(Mcd1Data, a0); + bufile((u8 *)Mcd1Data, a0); else if (!strncmp(ffile, "bu10", 4)) - bufile(Mcd2Data, a0); + bufile((u8 *)Mcd2Data, a0); pc0 = ra; } @@ -3280,6 +3298,7 @@ void psxBiosSetupBootState(void) void psxBiosInit() { u32 *ptr, *ram32, *rom32; + char *romc; int i; uLongf len; @@ -3548,7 +3567,7 @@ void psxBiosInit() { biosB0[0x3d] = psxBios_putchar; //biosB0[0x3e] = psxBios_gets; biosB0[0x3f] = psxBios_puts; - //biosB0[0x40] = psxBios_cd; + biosB0[0x40] = psxBios_cd; biosB0[0x41] = psxBios_format; biosB0[0x42] = psxBios_firstfile; biosB0[0x43] = psxBios_nextfile; @@ -3612,16 +3631,19 @@ void psxBiosInit() { /**/ memset(FDesc, 0, sizeof(FDesc)); + memset(cdir, 0, sizeof(cdir)); + floodchk = 0; // 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, "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"); + romc = (char *)psxR; + strcpy(romc + 0x108, "PCSX authors"); + strcpy(romc + 0x12c, "CEX-3000 PCSX HLE"); // see psxBios_GetSystemInfo + strcpy(romc + 0x7ff32, "System ROM Version 2.2 12/04/95 A"); + strcpy(romc + 0x7ff54, "GPL-2.0-or-later"); // fonts len = 0x80000 - 0x66000; @@ -3736,18 +3758,14 @@ void psxBiosCnfLoaded(u32 tcb_cnt, u32 evcb_cnt, u32 stack) { } #define psxBios_PADpoll(pad) { \ + int i, more_data = 0; \ PAD##pad##_startPoll(pad); \ - pad_buf##pad[0] = 0; \ - pad_buf##pad[1] = PAD##pad##_poll(0x42); \ - if (!(pad_buf##pad[1] & 0x0f)) { \ - bufcount = 32; \ - } else { \ - bufcount = (pad_buf##pad[1] & 0x0f) * 2; \ - } \ - PAD##pad##_poll(0); \ + pad_buf##pad[1] = PAD##pad##_poll(0x42, &more_data); \ + pad_buf##pad[0] = more_data ? 0 : 0xff; \ + PAD##pad##_poll(0, &more_data); \ i = 2; \ - while (bufcount--) { \ - pad_buf##pad[i++] = PAD##pad##_poll(0); \ + while (more_data) { \ + pad_buf##pad[i++] = PAD##pad##_poll(0, &more_data); \ } \ } @@ -3932,7 +3950,6 @@ void hleExcPadCard1(void) if (loadRam32(A_PAD_IRQR_ENA)) { u8 *pad_buf1 = loadRam8ptr(A_PAD_INBUF + 0); u8 *pad_buf2 = loadRam8ptr(A_PAD_INBUF + 4); - int i, bufcount; psxBios_PADpoll(1); psxBios_PADpoll(2); @@ -3964,8 +3981,8 @@ void psxBiosException() { int i; // save the regs - // $at, $v0, $v1 already saved by the mips code at A_EXCEPTION - for (i = 4; i < 32; i++) { + // $at, $v0, $v1, $ra already saved by the mips code at A_EXCEPTION + for (i = 4; i < 31; i++) { if (i == 26) // $k0 continue; tcb->reg[i] = SWAP32(psxRegs.GPR.r[i]); @@ -4031,4 +4048,5 @@ void psxBiosFreeze(int Mode) { bfreezes(FDesc); bfreezes(ffile); bfreezel(&nfile); + bfreezes(cdir); }