* Miscellaneous functions, including savestates and CD-ROM loading.
*/
+#include <stddef.h>
+#include <assert.h>
#include "misc.h"
#include "cdrom.h"
#include "mdec.h"
#include "gpu.h"
#include "ppf.h"
+#include "database.h"
#include <zlib.h>
char CdromId[10] = "";
char name [1];
};
-void mmssdd( char *b, char *p )
+static void mmssdd( char *b, char *p )
{
int m, s, d;
-#if defined(__arm__)
- unsigned char *u = (void *)b;
- int block = (u[3] << 24) | (u[2] << 16) | (u[1] << 8) | u[0];
-#elif defined(__BIGENDIAN__)
- int block = (b[0] & 0xff) | ((b[1] & 0xff) << 8) | ((b[2] & 0xff) << 16) | (b[3] << 24);
-#else
- int block = *((int*)b);
-#endif
+ unsigned char *ub = (void *)b;
+ int block = (ub[3] << 24) | (ub[2] << 16) | (ub[1] << 8) | ub[0];
block += 150;
m = block / 4500; // minutes
m = ((m / 10) << 4) | m % 10;
s = ((s / 10) << 4) | s % 10;
- d = ((d / 10) << 4) | d % 10;
+ d = ((d / 10) << 4) | d % 10;
p[0] = m;
p[1] = s;
time[0] = itob(time[0]); time[1] = itob(time[1]); time[2] = itob(time[2]);
#define READTRACK() \
- if (CDR_readTrack(time) == -1) return -1; \
+ if (!CDR_readTrack(time)) return -1; \
buf = (void *)CDR_getBuffer(); \
if (buf == NULL) return -1; \
else CheckPPFCache((u8 *)buf, time[0], time[1], time[2]);
0x02000000, 0x00000000, 0x01ff03ff,
};
-static void fake_bios_gpu_setup(void)
+void BiosLikeGPUSetup()
{
int i;
for (i = 0; i < sizeof(gpu_data_def) / sizeof(gpu_data_def[0]); i++)
GPU_writeData(gpu_data_def[i]);
+
+ HW_GPU_STATUS |= SWAP32(PSXGPU_nBUSY);
+}
+
+static void SetBootRegs(u32 pc, u32 gp, u32 sp)
+{
+ //printf("%s %08x %08x %08x\n", __func__, pc, gp, sp);
+ psxCpu->Notify(R3000ACPU_NOTIFY_BEFORE_SAVE, NULL);
+
+ psxRegs.pc = pc;
+ psxRegs.GPR.n.gp = gp;
+ psxRegs.GPR.n.sp = sp ? sp : 0x801fff00;
+
+ psxCpu->Notify(R3000ACPU_NOTIFY_AFTER_LOAD, NULL);
+}
+
+void BiosBootBypass() {
+ assert(psxRegs.pc == 0x80030000);
+
+ // skip BIOS logos and region check
+ psxCpu->Notify(R3000ACPU_NOTIFY_BEFORE_SAVE, NULL);
+ psxRegs.pc = psxRegs.GPR.n.ra;
+}
+
+static void getFromCnf(char *buf, const char *key, u32 *val)
+{
+ buf = strstr(buf, key);
+ if (buf)
+ buf = strchr(buf, '=');
+ if (buf)
+ *val = strtol(buf + 1, NULL, 16);
}
int LoadCdrom() {
u8 time[4], *buf;
u8 mdir[4096];
char exename[256];
-
- // not the best place to do it, but since BIOS boot logo killer
- // is just below, do it here
- fake_bios_gpu_setup();
+ u32 cnf_tcb = 4;
+ u32 cnf_event = 16;
+ u32 cnf_stack = 0;
+ u32 sp = 0;
+ int ret;
if (!Config.HLE) {
- // skip BIOS logos
- psxRegs.pc = psxRegs.GPR.n.ra;
- return 0;
+ if (psxRegs.pc != 0x80030000) // BiosBootBypass'ed or custom BIOS?
+ return 0;
+ if (Config.SlowBoot)
+ return 0;
}
time[0] = itob(0); time[1] = itob(2); time[2] = itob(0x10);
READTRACK();
// skip head and sub, and go to the root directory record
- dir = (struct iso_directory_record*) &buf[12+156];
+ dir = (struct iso_directory_record*) &buf[12+156];
mmssdd(dir->extent, (char*)time);
if (GetCdromFile(mdir, time, "SYSTEM.CNF;1") == -1) {
// if SYSTEM.CNF is missing, start an existing PSX.EXE
if (GetCdromFile(mdir, time, "PSX.EXE;1") == -1) return -1;
+ strcpy(exename, "PSX.EXE;1");
READTRACK();
}
else {
// read the SYSTEM.CNF
READTRACK();
+ buf[1023] = 0;
- sscanf((char *)buf + 12, "BOOT = cdrom:\\%255s", exename);
- if (GetCdromFile(mdir, time, exename) == -1) {
- sscanf((char *)buf + 12, "BOOT = cdrom:%255s", exename);
- if (GetCdromFile(mdir, time, exename) == -1) {
+ ret = sscanf((char *)buf + 12, "BOOT = cdrom:\\%255s", exename);
+ if (ret < 1 || GetCdromFile(mdir, time, exename) == -1) {
+ ret = sscanf((char *)buf + 12, "BOOT = cdrom:%255s", exename);
+ if (ret < 1 || GetCdromFile(mdir, time, exename) == -1) {
char *ptr = strstr((char *)buf + 12, "cdrom:");
if (ptr != NULL) {
ptr += 6;
return -1;
}
}
+ getFromCnf((char *)buf + 12, "TCB", &cnf_tcb);
+ getFromCnf((char *)buf + 12, "EVENT", &cnf_event);
+ getFromCnf((char *)buf + 12, "STACK", &cnf_stack);
+ if (Config.HLE)
+ psxBiosCnfLoaded(cnf_tcb, cnf_event);
// Read the EXE-Header
READTRACK();
memcpy(&tmpHead, buf + 12, sizeof(EXE_HEADER));
- psxRegs.pc = SWAP32(tmpHead.pc0);
- psxRegs.GPR.n.gp = SWAP32(tmpHead.gp0);
- psxRegs.GPR.n.sp = SWAP32(tmpHead.s_addr);
- if (psxRegs.GPR.n.sp == 0) psxRegs.GPR.n.sp = 0x801fff00;
+ SysPrintf("manual booting '%s'\n", exename);
+ sp = SWAP32(tmpHead.s_addr);
+ if (cnf_stack)
+ sp = cnf_stack;
+ SetBootRegs(SWAP32(tmpHead.pc0), SWAP32(tmpHead.gp0), sp);
tmpHead.t_size = SWAP32(tmpHead.t_size);
tmpHead.t_addr = SWAP32(tmpHead.t_addr);
psxCpu->Clear(tmpHead.t_addr, tmpHead.t_size / 4);
+ psxCpu->Reset();
// Read the rest of the main executable
while (tmpHead.t_size & ~2047) {
incTime();
READTRACK();
- if (ptr != NULL) memcpy(ptr, buf+12, 2048);
+ if (ptr != INVALID_PTR) memcpy(ptr, buf+12, 2048);
tmpHead.t_size -= 2048;
tmpHead.t_addr += 2048;
u8 time[4],*buf;
u8 mdir[4096];
char exename[256];
+ const char *p1, *p2;
u32 size, addr;
void *mem;
- sscanf(filename, "cdrom:\\%255s", exename);
+ p1 = filename;
+ if ((p2 = strchr(p1, ':')))
+ p1 = p2 + 1;
+ while (*p1 == '\\')
+ p1++;
+ snprintf(exename, sizeof(exename), "%s", p1);
time[0] = itob(0); time[1] = itob(2); time[2] = itob(0x10);
READTRACK();
// skip head and sub, and go to the root directory record
- dir = (struct iso_directory_record *)&buf[12 + 156];
+ dir = (struct iso_directory_record *)&buf[12 + 156];
mmssdd(dir->extent, (char*)time);
addr = head->t_addr;
psxCpu->Clear(addr, size / 4);
+ psxCpu->Reset();
while (size & ~2047) {
incTime();
READTRACK();
mem = PSXM(addr);
- if (mem)
+ if (mem != INVALID_PTR)
memcpy(mem, buf + 12, 2048);
size -= 2048;
strncpy(CdromLabel, buf + 52, 32);
// skip head and sub, and go to the root directory record
- dir = (struct iso_directory_record *)&buf[12 + 156];
+ dir = (struct iso_directory_record *)&buf[12 + 156];
mmssdd(dir->extent, (char *)time);
return -1;
}
}
+ /* Workaround for Wild Arms EU/US which has non-standard string causing incorrect region detection */
+ if (exename[0] == 'E' && exename[1] == 'X' && exename[2] == 'E' && exename[3] == '\\') {
+ size_t offset = 4;
+ size_t i, len = strlen(exename) - offset;
+ for (i = 0; i < len; i++)
+ exename[i] = exename[i + offset];
+ exename[i] = '\0';
+ }
} else if (GetCdromFile(mdir, time, "PSX.EXE;1") != -1) {
strcpy(exename, "PSX.EXE;1");
strcpy(CdromId, "SLUS99999");
strcpy(CdromId, "SLUS99999");
if (Config.PsxAuto) { // autodetect system (pal or ntsc)
- if (CdromId[2] == 'e' || CdromId[2] == 'E')
+ if (
+ /* Make sure Wild Arms SCUS-94608 is not detected as a PAL game. */
+ ((CdromId[0] == 's' || CdromId[0] == 'S') && (CdromId[2] == 'e' || CdromId[2] == 'E')) ||
+ !strncmp(CdromId, "DTLS3035", 8) ||
+ !strncmp(CdromId, "PBPX95001", 9) || // according to redump.org, these PAL
+ !strncmp(CdromId, "PBPX95007", 9) || // discs have a non-standard ID;
+ !strncmp(CdromId, "PBPX95008", 9)) // add more serials if they are discovered.
Config.PsxType = PSX_TYPE_PAL; // pal
else Config.PsxType = PSX_TYPE_NTSC; // ntsc
}
SysPrintf(_("CD-ROM Label: %.32s\n"), CdromLabel);
SysPrintf(_("CD-ROM ID: %.9s\n"), CdromId);
SysPrintf(_("CD-ROM EXE Name: %.255s\n"), exename);
+
+ Apply_Hacks_Cdrom();
BuildPPFCache();
current = ftell(f);
fseek(f, 0L, SEEK_SET);
- fread(mybuf, 2048, 1, f);
+ if (fread(&mybuf, 1, sizeof(mybuf), f) != sizeof(mybuf))
+ goto io_fail;
+
fseek(f, current, SEEK_SET);
exe_hdr = (EXE_HEADER *)mybuf;
return COFF_EXE;
return INVALID_EXE;
+
+io_fail:
+#ifndef NDEBUG
+ SysPrintf(_("File IO error in <%s:%s>.\n"), __FILE__, __func__);
+#endif
+ return INVALID_EXE;
}
// temporary pandora workaround..
{
void *tmp;
size_t ret = 0;
-
+
tmp = malloc(size * nmemb);
if (tmp) {
ret = fread(tmp, size, nmemb, stream);
u32 section_address, section_size;
void *mem;
- strncpy(CdromId, "SLUS99999", 9);
- strncpy(CdromLabel, "SLUS_999.99", 11);
+ strcpy(CdromId, "SLUS99999");
+ strcpy(CdromLabel, "SLUS_999.99");
tmpFile = fopen(ExePath, "rb");
if (tmpFile == NULL) {
type = PSXGetFileType(tmpFile);
switch (type) {
case PSX_EXE:
- fread(&tmpHead,sizeof(EXE_HEADER),1,tmpFile);
+ if (fread(&tmpHead, 1, sizeof(EXE_HEADER), tmpFile) != sizeof(EXE_HEADER))
+ goto fail_io;
section_address = SWAP32(tmpHead.t_addr);
section_size = SWAP32(tmpHead.t_size);
mem = PSXM(section_address);
- if (mem != NULL) {
- fseek(tmpFile, 0x800, SEEK_SET);
+ if (mem != INVALID_PTR) {
+ fseek(tmpFile, 0x800, SEEK_SET);
fread_to_ram(mem, section_size, 1, tmpFile);
psxCpu->Clear(section_address, section_size / 4);
}
- fclose(tmpFile);
- psxRegs.pc = SWAP32(tmpHead.pc0);
- psxRegs.GPR.n.gp = SWAP32(tmpHead.gp0);
- psxRegs.GPR.n.sp = SWAP32(tmpHead.s_addr);
- if (psxRegs.GPR.n.sp == 0)
- psxRegs.GPR.n.sp = 0x801fff00;
+ SetBootRegs(SWAP32(tmpHead.pc0), SWAP32(tmpHead.gp0),
+ SWAP32(tmpHead.s_addr));
retval = 0;
break;
case CPE_EXE:
fseek(tmpFile, 6, SEEK_SET); /* Something tells me we should go to 4 and read the "08 00" here... */
do {
- fread(&opcode, 1, 1, tmpFile);
+ if (fread(&opcode, 1, sizeof(opcode), tmpFile) != sizeof(opcode))
+ goto fail_io;
switch (opcode) {
case 1: /* Section loading */
- fread(§ion_address, 4, 1, tmpFile);
- fread(§ion_size, 4, 1, tmpFile);
+ if (fread(§ion_address, 1, sizeof(section_address), tmpFile) != sizeof(section_address))
+ goto fail_io;
+ if (fread(§ion_size, 1, sizeof(section_size), tmpFile) != sizeof(section_size))
+ goto fail_io;
section_address = SWAPu32(section_address);
section_size = SWAPu32(section_size);
#ifdef EMU_LOG
EMU_LOG("Loading %08X bytes from %08X to %08X\n", section_size, ftell(tmpFile), section_address);
#endif
mem = PSXM(section_address);
- if (mem != NULL) {
+ if (mem != INVALID_PTR) {
fread_to_ram(mem, section_size, 1, tmpFile);
psxCpu->Clear(section_address, section_size / 4);
}
break;
case 3: /* register loading (PC only?) */
fseek(tmpFile, 2, SEEK_CUR); /* unknown field */
- fread(&psxRegs.pc, 4, 1, tmpFile);
+ if (fread(&psxRegs.pc, 1, sizeof(psxRegs.pc), tmpFile) != sizeof(psxRegs.pc))
+ goto fail_io;
psxRegs.pc = SWAPu32(psxRegs.pc);
break;
case 0: /* End of file */
CdromLabel[0] = '\0';
}
+ if (tmpFile)
+ fclose(tmpFile);
return retval;
+
+fail_io:
+#ifndef NDEBUG
+ SysPrintf(_("File IO error in <%s:%s>.\n"), __FILE__, __func__);
+#endif
+ fclose(tmpFile);
+ return -1;
}
// STATES
zlib_open, zlib_read, zlib_write, zlib_seek, zlib_close
};
-static const char PcsxHeader[32] = "STv4 PCSX v" PACKAGE_VERSION;
+static const char PcsxHeader[32] = "STv4 PCSX v" PCSX_VERSION;
// Savestate Versioning!
// If you make changes to the savestate version, please increment the value below.
int SaveState(const char *file) {
void *f;
GPUFreeze_t *gpufP;
+ SPUFreezeHdr_t *spufH;
SPUFreeze_t *spufP;
int Size;
unsigned char *pMem;
f = SaveFuncs.open(file, "wb");
if (f == NULL) return -1;
- new_dyna_before_save();
+ psxCpu->Notify(R3000ACPU_NOTIFY_BEFORE_SAVE, NULL);
SaveFuncs.write(f, (void *)PcsxHeader, 32);
SaveFuncs.write(f, (void *)&SaveVersion, sizeof(u32));
SaveFuncs.write(f, psxM, 0x00200000);
SaveFuncs.write(f, psxR, 0x00080000);
SaveFuncs.write(f, psxH, 0x00010000);
- SaveFuncs.write(f, (void *)&psxRegs, sizeof(psxRegs));
+ // only partial save of psxRegisters to maintain savestate compat
+ SaveFuncs.write(f, &psxRegs, offsetof(psxRegisters, gteBusyCycle));
// gpu
gpufP = (GPUFreeze_t *)malloc(sizeof(GPUFreeze_t));
free(gpufP);
// spu
- spufP = (SPUFreeze_t *) malloc(16);
- SPU_freeze(2, spufP, psxRegs.cycle);
- Size = spufP->Size; SaveFuncs.write(f, &Size, 4);
- free(spufP);
+ spufH = malloc(sizeof(*spufH));
+ SPU_freeze(2, (SPUFreeze_t *)spufH, psxRegs.cycle);
+ Size = spufH->Size; SaveFuncs.write(f, &Size, 4);
+ free(spufH);
spufP = (SPUFreeze_t *) malloc(Size);
SPU_freeze(1, spufP, psxRegs.cycle);
SaveFuncs.write(f, spufP, Size);
SaveFuncs.close(f);
- new_dyna_after_save();
-
return 0;
}
if (Config.HLE)
psxBiosInit();
- psxCpu->Reset();
SaveFuncs.seek(f, 128 * 96 * 3, SEEK_CUR);
-
SaveFuncs.read(f, psxM, 0x00200000);
SaveFuncs.read(f, psxR, 0x00080000);
SaveFuncs.read(f, psxH, 0x00010000);
- SaveFuncs.read(f, (void *)&psxRegs, sizeof(psxRegs));
+ SaveFuncs.read(f, &psxRegs, offsetof(psxRegisters, gteBusyCycle));
+ psxRegs.gteBusyCycle = psxRegs.cycle;
+
+ psxCpu->Notify(R3000ACPU_NOTIFY_AFTER_LOAD, NULL);
if (Config.HLE)
psxBiosFreeze(0);
GPU_freeze(0, gpufP);
free(gpufP);
if (HW_GPU_STATUS == 0)
- HW_GPU_STATUS = GPU_readStatus();
+ HW_GPU_STATUS = SWAP32(GPU_readStatus());
// spu
SaveFuncs.read(f, &Size, 4);
if (NET_recvData == NULL || NET_sendData == NULL)
return 0;
+ boolean Sio_old = 0;
+ boolean SpuIrq_old = 0;
+ boolean RCntFix_old = 0;
NET_sendData(&Config.Xa, sizeof(Config.Xa), PSE_NET_BLOCKING);
- NET_sendData(&Config.Sio, sizeof(Config.Sio), PSE_NET_BLOCKING);
- NET_sendData(&Config.SpuIrq, sizeof(Config.SpuIrq), PSE_NET_BLOCKING);
- NET_sendData(&Config.RCntFix, sizeof(Config.RCntFix), PSE_NET_BLOCKING);
+ NET_sendData(&Sio_old, sizeof(Sio_old), PSE_NET_BLOCKING);
+ NET_sendData(&SpuIrq_old, sizeof(SpuIrq_old), PSE_NET_BLOCKING);
+ NET_sendData(&RCntFix_old, sizeof(RCntFix_old), PSE_NET_BLOCKING);
NET_sendData(&Config.PsxType, sizeof(Config.PsxType), PSE_NET_BLOCKING);
NET_sendData(&Config.Cpu, sizeof(Config.Cpu), PSE_NET_BLOCKING);
if (NET_recvData == NULL || NET_sendData == NULL)
return 0;
+ boolean Sio_old = 0;
+ boolean SpuIrq_old = 0;
+ boolean RCntFix_old = 0;
NET_recvData(&Config.Xa, sizeof(Config.Xa), PSE_NET_BLOCKING);
- NET_recvData(&Config.Sio, sizeof(Config.Sio), PSE_NET_BLOCKING);
- NET_recvData(&Config.SpuIrq, sizeof(Config.SpuIrq), PSE_NET_BLOCKING);
- NET_recvData(&Config.RCntFix, sizeof(Config.RCntFix), PSE_NET_BLOCKING);
+ NET_recvData(&Sio_old, sizeof(Sio_old), PSE_NET_BLOCKING);
+ NET_recvData(&SpuIrq_old, sizeof(SpuIrq_old), PSE_NET_BLOCKING);
+ NET_recvData(&RCntFix_old, sizeof(RCntFix_old), PSE_NET_BLOCKING);
NET_recvData(&Config.PsxType, sizeof(Config.PsxType), PSE_NET_BLOCKING);
- SysUpdate();
-
tmp = Config.Cpu;
NET_recvData(&Config.Cpu, sizeof(Config.Cpu), PSE_NET_BLOCKING);
if (tmp != Config.Cpu) {
psxCpu->Shutdown();
-#ifdef PSXREC
+#ifndef DRC_DISABLE
if (Config.Cpu == CPU_INTERPRETER) psxCpu = &psxInt;
else psxCpu = &psxRec;
#else
SysClose(); return -1;
}
psxCpu->Reset();
+ psxCpu->Notify(R3000ACPU_NOTIFY_AFTER_LOAD, NULL);
}
return 0;