Skip to content

Commit

Permalink
Fix Formula One 2001 and improve compat modes
Browse files Browse the repository at this point in the history
  • Loading branch information
rickgaiser committed Nov 28, 2024
1 parent 1175727 commit b3cdec7
Show file tree
Hide file tree
Showing 12 changed files with 119 additions and 92 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,8 @@ Options:
Defaults to cd for size<=650MiB, and dvd for size>650MiB
-gc=<compat> Game compatibility modes, supported are:
- 0: Disable builtin compat flags
- 1: IOP: Accurate reads (sceCdRead)
- 0: IOP: Fast reads (sceCdRead)
- 1: dummy
- 2: IOP: Sync reads (sceCdRead)
- 3: EE : Unhook syscalls
- 5: IOP: Emulate DVD-DL
Expand Down
8 changes: 1 addition & 7 deletions ee/ee_core/include/ee_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,7 @@ extern int iop_reboot_count;

extern u32 g_compat_mask;

#define COMPAT_MODE_1 0x01 // Accurate reads (sceCdRead)
#define COMPAT_MODE_2 0x02 // Sync reads (sceCdRead)
#define COMPAT_MODE_3 0x04 // Unhook syscalls
//#define COMPAT_MODE_4 0x08 // Skip videos - not supported!
#define COMPAT_MODE_5 0x10 // Emulate DVD-DL
//#define COMPAT_MODE_6 0x20 // Disable IGR - not supported!
#define COMPAT_MODE_7 0x40 // Patch IOP buffer overrun (game bug)
#define EECORE_COMPAT_UNHOOK (1<<0) // Unhook syscalls

extern char GameID[16];
extern int GameMode;
Expand Down
2 changes: 1 addition & 1 deletion ee/loader/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ all: $(EE_BIN_PACKED)
#GAME = 'DVD/Inuyasha - Feudal Combat (U).iso' # neutrino github issue 8: UDPBD: sfx missing or random freezes when starting match
#GAME = 'DVD/Scooby-Doo! Mystery Mayhem (U).iso' # neutrino github issue 19: When starting a new game, the cutscene freezes
#GAME = 'DVD/Silent Hill 3 (U).iso' # neutrino github issue 30: USB: freezes on startup logo, only on real ps2, works in pcsx2
#GAME = 'DVD/Formula One 2001 (E).iso'

# Games that use the HDD in one way or another
#GAME = 'DVD/The Sims 2 (U).iso'
Expand Down Expand Up @@ -123,6 +122,7 @@ GAME = 'DVD/Ratchet Clank - Up Your Arsenal (U).iso'
#GAME = 'DVD/Auto Modellista (E).iso'
#GAME = 'DVD/Disney's Treasure Planet (E).iso' # buffer overrun issue
#GAME = 'DVD/Donkey Xote (E).iso' # buffer overrun issue
#GAME = 'DVD/Formula One 2001 (E).iso' # cdvdman break command

# Example arguments
#-bsd=udpbd -dvd=mass:$(GAME)
Expand Down
91 changes: 63 additions & 28 deletions ee/loader/src/compat.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,53 +3,88 @@

// Other
#include "compat.h"
#include "ee_core.h"
#include "ee_core.h" // EECORE compat flags
#include "../../../iop/common/cdvd_config.h" // CDVDMAN compat flags


/****************************************************************************
* Compatibility options:
* #define COMPAT_MODE_1 0x01 // Accurate reads (sceCdRead)
* #define COMPAT_MODE_2 0x02 // Sync reads (sceCdRead)
* #define COMPAT_MODE_3 0x04 // Unhook syscalls
* #define COMPAT_MODE_4 0x08 // Skip videos - not supported!
* #define COMPAT_MODE_5 0x10 // Emulate DVD-DL
* #define COMPAT_MODE_6 0x20 // Disable IGR - not supported!
* #define COMPAT_MODE_7 0x40 // Patch IOP buffer overrun (bug in the game)
*/
typedef struct
{
uint32_t flag;
uint32_t eecore_flags;
uint32_t cdvdman_flags;
const char *ioppatch;
} flagcompat_t;

static const flagcompat_t flag_compat[] = {
{1<<0, 0, CDVDMAN_COMPAT_FAST_READS, NULL }, // MODE 0
{1<<2, 0, CDVDMAN_COMPAT_ALT_READ, NULL }, // MODE 2
{1<<3, EECORE_COMPAT_UNHOOK, 0, NULL }, // MODE 3
{1<<5, 0, CDVDMAN_COMPAT_EMU_DVDDL, NULL }, // MODE 5
{1<<7, 0, 0, "patch_membo.irx" }, // MODE 7
{0<<0, 0, 0, NULL},
};

void get_compat_flag(uint32_t flags, uint32_t *eecore, uint32_t *cdvdman, const char **ioppatch)
{
// Game specific compatibility mode
const flagcompat_t *p = &flag_compat[0];
while (p->flag != 0) {
if ((p->flag & flags) != 0) {
*eecore |= p->eecore_flags; // multiple flags possible
*cdvdman |= p->cdvdman_flags; // multiple flags possible
*ioppatch = p->ioppatch; // only 1 patch possible
}
p++;
}
}

typedef struct
{
char *game;
uint32_t flags;
uint32_t eecore_flags;
uint32_t cdvdman_flags;
const char *ioppatch;
} gamecompat_t;

static const gamecompat_t default_game_compat[] = {
{"SCES_524.12", COMPAT_MODE_2 }, // Jackie Chan Adventures # only needed for USB ?
{"SCUS_971.24", COMPAT_MODE_3 }, // Jak and Daxter - The Precursor Legacy # game writes to 0x84000 region !
{"SCUS_973.30", COMPAT_MODE_3 }, // Jak 3 # game writes to 0x84000 region !
{"SCES_524.60", COMPAT_MODE_3 }, // Jak 3 # game writes to 0x84000 region !
{"SLES_548.38", COMPAT_MODE_7 }, // Donkey Xote # game has IOP buffer overrun issues
{"SCES_511.76", COMPAT_MODE_7 }, // Disney's Treasure Planet # game has IOP buffer overrun issues
{NULL, 0},
static const gamecompat_t game_compat[] = {
{"SCES_524.12", 0, CDVDMAN_COMPAT_ALT_READ, NULL }, // Jackie Chan Adventures # only needed for USB ?

// These games write to the EE 0x84000 region, where our EECORE is loaded
{"SCUS_971.24", EECORE_COMPAT_UNHOOK, 0, NULL }, // Jak and Daxter - The Precursor Legacy
{"SCUS_973.30", EECORE_COMPAT_UNHOOK, 0, NULL }, // Jak 3
{"SCES_524.60", EECORE_COMPAT_UNHOOK, 0, NULL }, // Jak 3

// These games have IOP memory buffer overrun issues
{"SLES_548.38", 0, 0, "patch_membo.irx" }, // Donkey Xote
{"SCES_511.76", 0, 0, "patch_membo.irx" }, // Disney's Treasure Planet

// These games send a cdvd break command from EE directly into IOP memory map
// This causes an interrupt by cdvd, plus a callback that the game needs.
// In PCSX2 you can see the PCSX2 message "Read Abort" every time this happens.
//
// Emulation has so far not been able to reproduce this behaviour,
// as a workaround extra cdvd callbacks are fired.
{"SCUS_971.50", 0, CDVDMAN_COMPAT_F1_2001, NULL }, // Formula One 2001 <- not checked
{"SCES_500.04", 0, CDVDMAN_COMPAT_F1_2001, NULL }, // Formula One 2001 <- checked and working
{"SCED_502.54", 0, CDVDMAN_COMPAT_F1_2001, NULL }, // Formula One 2001 <- not checked
{"SCED_503.13", 0, CDVDMAN_COMPAT_F1_2001, NULL }, // Formula One 2001 <- not checked
{"SCPS_150.19", 0, CDVDMAN_COMPAT_F1_2001, NULL }, // Formula One 2001 <- not checked
{NULL, 0, 0, NULL},
};

uint32_t get_compat(const char *id)
void get_compat_game(const char *id, uint32_t *eecore, uint32_t *cdvdman, const char **ioppatch)
{
// Default compatibility mode
uint32_t compat = COMPAT_MODE_1;

// Game specific compatibility mode
const gamecompat_t *p = &default_game_compat[0];
const gamecompat_t *p = &game_compat[0];
while (p->game != NULL) {
if (strcmp(id, p->game) == 0) {
compat |= p->flags;
*eecore |= p->eecore_flags; // multiple flags possible
*cdvdman |= p->cdvdman_flags; // multiple flags possible
*ioppatch = p->ioppatch; // only 1 patch possible
break;
}
p++;
}

return compat;
}


Expand Down
3 changes: 2 additions & 1 deletion ee/loader/src/compat.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
#include <stdint.h>


uint32_t get_compat(const char *id);
void get_compat_flag(uint32_t flags, uint32_t *eecore, uint32_t *cdvdman, const char **ioppatch);
void get_compat_game(const char *id, uint32_t *eecore, uint32_t *cdvdman, const char **ioppatch);
void *get_modstorage(const char *id);


Expand Down
44 changes: 21 additions & 23 deletions ee/loader/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,8 @@ void print_usage()
printf(" Defaults to cd for size<=650MiB, and dvd for size>650MiB\n");
printf("\n");
printf(" -gc=<compat> Game compatibility modes, supported are:\n");
printf(" - 0: Disable builtin compat flags\n");
printf(" - 1: IOP: Accurate reads (sceCdRead)\n");
printf(" - 0: IOP: Fast reads (sceCdRead)\n");
printf(" - 1: dummy\n");
printf(" - 2: IOP: Sync reads (sceCdRead)\n");
printf(" - 3: EE : Unhook syscalls\n");
printf(" - 5: IOP: Emulate DVD-DL\n");
Expand Down Expand Up @@ -1049,14 +1049,12 @@ int main(int argc, char *argv[])
char c = *sys.sGC;
switch (c) {
case '0':
iCompat |= 1U << 31; // Set dummy flag
break;
case '1':
case '1': // dummy
case '2':
case '3':
case '5':
case '7':
iCompat |= 1U << (c - '1');
iCompat |= 1U << (c - '0');
break;
default:
printf("ERROR: compat flag %c not supported\n", c);
Expand All @@ -1067,6 +1065,14 @@ int main(int argc, char *argv[])
}
}

/*
* Process user requested compatibility flags
*/
uint32_t eecore_compat = 0;
uint32_t cdvdman_compat = 0;
const char * patch_compat = NULL;
get_compat_flag(iCompat, &eecore_compat, &cdvdman_compat, &patch_compat);

/*
* Load backing store driver settings
*/
Expand Down Expand Up @@ -1118,11 +1124,11 @@ int main(int argc, char *argv[])
/*
* Load IOP game compatibility modules
*/
if (iCompat & COMPAT_MODE_7) {
if (patch_compat != NULL) {
struct SModule * m = &drv.mod.mod[drv.mod.count];
drv.mod.count++;

m->sFileName = "patch_membo.irx";
m->sFileName = (char *)patch_compat;
m->env = MOD_ENV_EE;
}

Expand Down Expand Up @@ -1304,7 +1310,7 @@ int main(int argc, char *argv[])
}
}
else {
if (iCompat != 0)
if (cdvdman_compat != 0)
printf("WARNING: compatibility cannot be changed without emulating the DVD\n");
if (eMediaType != SCECdNODISC)
printf("WARNING: media type cannot be changed without emulating the DVD\n");
Expand Down Expand Up @@ -1366,23 +1372,15 @@ int main(int argc, char *argv[])
/*
* Get ELF/game compatibility flags
*/
if (iCompat == 0)
iCompat = get_compat(sGameID);
iCompat &= ~(1U << 31); // Clear dummy flag
get_compat_game(sGameID, &eecore_compat, &cdvdman_compat, &patch_compat);
printf("EECORE compat flags: 0x%lX\n", eecore_compat);
printf("CDVDMAN compat flags: 0x%lX\n", cdvdman_compat);

/*
* Set CDVDMAN compatibility
*/
if (sDVDFile != NULL) {
if (iCompat & COMPAT_MODE_1)
set_cdvdman->flags |= IOPCORE_COMPAT_ACCU_READS;
if (iCompat & COMPAT_MODE_2)
set_cdvdman->flags |= IOPCORE_COMPAT_ALT_READ;
if (iCompat & COMPAT_MODE_5)
set_cdvdman->flags |= IOPCORE_COMPAT_EMU_DVDDL;

printf("Compat flags: 0x%X, IOP=0x%X\n", (unsigned int)iCompat, set_cdvdman->flags);
}
if (sDVDFile != NULL)
set_cdvdman->flags = cdvdman_compat;

/*
* Set deckard compatibility
Expand Down Expand Up @@ -1607,7 +1605,7 @@ int main(int argc, char *argv[])
eecc_setELFArgs(&eeconf, argc-iELFArgcStart, (const char **)&argv[iELFArgcStart]);
eecc_setKernelConfig(&eeconf, eeloadCopy, initUserMemory);
eecc_setModStorageConfig(&eeconf, irxtable, irxptr);
eecc_setCompatFlags(&eeconf, iCompat);
eecc_setCompatFlags(&eeconf, eecore_compat);
eecc_setDebugColors(&eeconf, sys.bDebugColors);
eecc_setPS2Logo(&eeconf, sys.bLogo);
printf("Starting ee_core with following arguments:\n");
Expand Down
16 changes: 8 additions & 8 deletions iop/cdvdman_emu/src/cdvdman.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ static int cdvdman_read_sectors(u32 lsn, unsigned int sectors, void *buf)

//M_DEBUG("cdvdman_read_sectors lsn=%lu sectors=%u buf=%p\n", lsn, sectors, buf);

if (cdvdman_settings.flags & IOPCORE_COMPAT_ACCU_READS) {
if ((cdvdman_settings.flags & CDVDMAN_COMPAT_FAST_READS) == 0) {
/*
* Limit transfer speed to match the physical drive in the ps2
*
Expand Down Expand Up @@ -184,7 +184,7 @@ static int cdvdman_read_sectors(u32 lsn, unsigned int sectors, void *buf)
for (ptr = buf, remaining = sectors; remaining > 0;) {
unsigned int SectorsToRead = remaining;

if (cdvdman_settings.flags & IOPCORE_COMPAT_ACCU_READS) {
if ((cdvdman_settings.flags & CDVDMAN_COMPAT_FAST_READS) == 0) {
// Limit transfers to a maximum length of 8, with a restricted transfer rate.
iop_sys_clock_t TargetTime;

Expand All @@ -198,7 +198,7 @@ static int cdvdman_read_sectors(u32 lsn, unsigned int sectors, void *buf)

cdvdman_stat.err = DeviceReadSectors(lsn, ptr, SectorsToRead);
if (cdvdman_stat.err != SCECdErNO) {
if (cdvdman_settings.flags & IOPCORE_COMPAT_ACCU_READS)
if ((cdvdman_settings.flags & CDVDMAN_COMPAT_FAST_READS) == 0)
CancelAlarm(&cdvdemu_read_end_cb, NULL);
break;
}
Expand Down Expand Up @@ -227,7 +227,7 @@ static int cdvdman_read_sectors(u32 lsn, unsigned int sectors, void *buf)
lsn += SectorsToRead;
ReadPos += SectorsToRead * 2048;

if (cdvdman_settings.flags & IOPCORE_COMPAT_ACCU_READS) {
if ((cdvdman_settings.flags & CDVDMAN_COMPAT_FAST_READS) == 0) {
// Sleep until the required amount of time has been spent.
WaitEventFlag(cdvdman_stat.intr_ef, CDVDEF_READ_END, WEF_AND, NULL);
}
Expand Down Expand Up @@ -623,9 +623,9 @@ static void cdvdman_cdread_Thread(void *args)
if (Stm0Callback != NULL)
Stm0Callback();

// Notify external irx that sceCdRead has finished
// 'Formula One 2001' seems to need this for background music
cdvdman_cb_event(SCECdFuncRead);
if (cdvdman_settings.flags & CDVDMAN_COMPAT_F1_2001)
cdvdman_cb_event(SCECdFuncRead);

break;
}

Expand Down Expand Up @@ -699,7 +699,7 @@ int _start(int argc, char **argv)
RegisterLibraryEntries(&_exp_cdvdstm);

// Setup the callback timer.
USec2SysClock((cdvdman_settings.flags & IOPCORE_COMPAT_ACCU_READS) ? 5000 : 0, &gCallbackSysClock);
USec2SysClock((cdvdman_settings.flags & CDVDMAN_COMPAT_FAST_READS) ? 0 : 5000, &gCallbackSysClock);

// Limit min/max sectors
if (cdvdman_settings.fs_sectors < 2)
Expand Down
4 changes: 2 additions & 2 deletions iop/cdvdman_emu/src/ncmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ int sceCdRead(u32 lsn, u32 sectors, void *buf, sceCdRMode *mode)

result = sceCdRead_internal(lsn, sectors, buf, mode, ECS_EXTERNAL);

if ((result == 1) && (cdvdman_settings.flags & IOPCORE_COMPAT_ALT_READ) && !QueryIntrContext())
if ((result == 1) && (cdvdman_settings.flags & CDVDMAN_COMPAT_ALT_READ) && !QueryIntrContext())
WaitEventFlag(cdvdman_stat.intr_ef, CDVDEF_MAN_UNLOCKED, WEF_AND, NULL);

return result;
Expand Down Expand Up @@ -140,7 +140,7 @@ static int cdvdman_fill_toc(u8 *tocBuff)
memset(tocBuff, 0, 2048);

u8 dual = 0;
if ((!(cdvdman_settings.flags & IOPCORE_COMPAT_EMU_DVDDL)) || (cdvdman_settings.layer1_start > 0))
if ((!(cdvdman_settings.flags & CDVDMAN_COMPAT_EMU_DVDDL)) || (cdvdman_settings.layer1_start > 0))
dual = 1;

// Write only what we need, memset has cleared the above buffers.
Expand Down
2 changes: 1 addition & 1 deletion iop/cdvdman_emu/src/scmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ int sceCdReadDvdDualInfo(int *on_dual, unsigned int *layer1_start)
{
M_DEBUG("%s(-, -)\n", __FUNCTION__);

if (cdvdman_settings.flags & IOPCORE_COMPAT_EMU_DVDDL) {
if (cdvdman_settings.flags & CDVDMAN_COMPAT_EMU_DVDDL) {
// Make layer 1 point to layer 0.
*layer1_start = 0;
*on_dual = 1;
Expand Down
6 changes: 3 additions & 3 deletions iop/cdvdman_emu/src/searchfile.c
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ static struct dirTocEntry *cdvdman_locatefile(char *name, u32 tocLBA, int tocLen
tocLength = tocEntryPointer->fileSize;
p = &slash[1];

if (!(cdvdman_settings.flags & IOPCORE_COMPAT_EMU_DVDDL)) {
if (!(cdvdman_settings.flags & CDVDMAN_COMPAT_EMU_DVDDL)) {
int on_dual;
unsigned int layer1_start;
sceCdReadDvdDualInfo(&on_dual, &layer1_start);
Expand Down Expand Up @@ -160,7 +160,7 @@ static int cdvdman_findfile(sceCdlFILE *pcdfile, const char *name, int layer)

cdvdman_init();

if (cdvdman_settings.flags & IOPCORE_COMPAT_EMU_DVDDL)
if (cdvdman_settings.flags & CDVDMAN_COMPAT_EMU_DVDDL)
layer = 0;
pLayerInfo = (layer != 0) ? &layer_info[1] : &layer_info[0]; // SCE CDVDMAN simply treats a non-zero value as a signal for the 2nd layer.

Expand Down Expand Up @@ -235,7 +235,7 @@ void cdvdman_searchfile_init(void)
//M_DEBUG("cdvdman_searchfile_init mediaLsnCount=%d\n", mediaLsnCount);

// DVD DL support
if (!(cdvdman_settings.flags & IOPCORE_COMPAT_EMU_DVDDL)) {
if (!(cdvdman_settings.flags & CDVDMAN_COMPAT_EMU_DVDDL)) {
int on_dual;
unsigned int layer1_start;
sceCdReadDvdDualInfo(&on_dual, &layer1_start);
Expand Down
Loading

0 comments on commit b3cdec7

Please sign in to comment.