* 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.
#include "psxbios.h"
#include "psxhw.h"
#include "gpu.h"
+#include "sio.h"
#include <zlib.h>
#if (defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)
u32 func;
} TCB;
-typedef struct {
+typedef struct {
u32 _pc0;
u32 gp0;
u32 t_addr;
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
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;
}
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;
#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;
PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x09]);
#endif
v0 = -1;
- if (!pa1) {
+ if (pa1 == INVALID_PTR) {
pc0 = ra;
return;
}
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;
}
void psxBios_malloc() { // 0x33
- unsigned int *chunk, *newchunk = NULL;
+ u32 *chunk, *newchunk = NULL;
unsigned int dsize = 0, csize, cstat;
int colflag;
#ifdef PSXBIOS_LOG
v0 = getchar(); pc0 = ra;
}
-void psxBios_printf() { // 0x3f
+static void psxBios_printf_psxout() { // 0x3f
char tmp[1024];
char tmp2[1024];
u32 save[4];
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);
}
*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;
}
#ifdef PSXBIOS_LOG
PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x44]);
#endif
-#ifdef ICACHE_EMULATION
psxCpu->Notify(R3000ACPU_NOTIFY_CACHE_ISOLATED, NULL);
psxCpu->Notify(R3000ACPU_NOTIFY_CACHE_UNISOLATED, NULL);
-#endif
pc0 = ra;
}
}
pc0 = ra;
-}
+}
void psxBios_mem2vram() { // 0x47
int size;
void psxBios_GPU_cw() { // 0x49
gpuSyncPluginSR();
GPU_writeData(a0);
- pc0 = ra;
v0 = HW_GPU_STATUS;
+ pc0 = ra;
}
void psxBios_GPU_cwb() { // 0x4a
#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(0x81, 0x2); // 0xf4000001, 0x0004
DeliverEvent(0x81, ret); // 0xf4000001, 0x0004
v0 = 1; pc0 = ra;
}
}
-/* 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) { \
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;
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;
}
#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;
ev = a0 & 0xff;
spec = (a0 >> 8) & 0xff;
- if (Event[ev][spec].status == EvStALREADY)
+ if (EventCB[ev][spec].status == EvStALREADY)
{
- if (!(Event[ev][spec].mode == EvMdINTR)) Event[ev][spec].status = EvStACTIVE;
+ if (!(EventCB[ev][spec].mode == EvMdINTR)) EventCB[ev][spec].status = EvStACTIVE;
v0 = 1;
- }
- else
+ }
+ else
{
v0 = 0;
}
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;
}
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;
}
for (th=1; th<8; th++)
{
- if (Thread[th].status == 0) break;
+ if (ThreadCB[th].status == 0) break;
}
if (th == 8) {
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;
}
#endif
/* The return value is always 1 (even if the handle was already closed). */
v0 = 1;
- if (Thread[th].status != 0) {
- Thread[th].status = 0;
+ if (ThreadCB[th].status != 0) {
+ ThreadCB[th].status = 0;
}
pc0 = ra;
#endif
/* The return value is always 1. */
v0 = 1;
- if (Thread[th].status == 0 || CurThread == th) {
+ if (ThreadCB[th].status == 0 || CurThread == th) {
pc0 = ra;
} else {
- 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;
}
}
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, char *ptr, char *cfg)
{
int i;
- char *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;
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;
fptr[6] = 0x00;
fptr[7] = 0x00;
strcpy(fptr+0xa, FDesc[1 + mcd].name);
- pptr = fptr2 = (u8 *)fptr;
+ 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;
v0 = -1;
- if (pa0) {
+ if (pa0 != INVALID_PTR) {
if (!strncmp(pa0, "bu00", 4)) {
buopen(1, Mcd1Data, Config.Mcd1);
}
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;
}
#endif
v0 = -1;
- if (!pa1) {
+ if (pa1 == INVALID_PTR) {
pc0 = ra;
return;
}
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);
*/
/* 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++;
/*
* struct DIRENTRY* firstfile(char *name,struct DIRENTRY *dir);
*/
-
+
void psxBios_firstfile() { // 42
struct DIRENTRY *dir = (struct DIRENTRY *)Ra1;
void *pa0 = Ra0;
v0 = 0;
- if (pa0) {
+ if (pa0 != INVALID_PTR) {
strcpy(ffile, pa0);
pfile = ffile+5;
nfile = 0;
v0 = 0;
- if (pa0 && pa1) {
+ if (pa0 != INVALID_PTR && pa1 != INVALID_PTR) {
if (!strncmp(pa0, "bu00", 4) && !strncmp(pa1, "bu00", 4)) {
burename(1);
}
v0 = 0;
- if (pa0) {
+ if (pa0 != INVALID_PTR) {
if (!strncmp(pa0, "bu00", 4)) {
budelete(1);
}
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);
card_active_chan = a0;
port = a0 >> 4;
- if (pa2) {
+ if (pa2 != INVALID_PTR) {
if (port == 0) {
memcpy(pa2, Mcd1Data + a1 * 128, 128);
} else {
/* 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_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;
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;
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;
/**/
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);
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;
*/
// opcode HLE
psxRu32ref(0x0000) = SWAPu32((0x3b << 26) | 4);
- /* 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);
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.
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:
bfreezes(regs);
bfreezes(SysIntRP);
bfreezel(&CardState);
- bfreezes(Thread);
+ bfreezes(ThreadCB);
bfreezel(&CurThread);
bfreezes(FDesc);
bfreezel(&card_active_chan);