Skip to content

Commit

Permalink
CDROM: Add randomness to repeated seek times
Browse files Browse the repository at this point in the history
I hate it, but it fixes lockups in Dino Crisis 2, and probably
other games with dodgy code too.

Also Simple 1500 Series Vol. 57 - The Meiro.
  • Loading branch information
stenzek committed Feb 17, 2025
1 parent 2f5c4d8 commit 6f25cf3
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 1 deletion.
16 changes: 16 additions & 0 deletions src/core/cdrom.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "common/gsvector.h"
#include "common/heap_array.h"
#include "common/log.h"
#include "common/xorshift_prng.h"

#include "fmt/format.h"
#include "imgui.h"
Expand Down Expand Up @@ -52,6 +53,7 @@ enum : u32
XA_RESAMPLE_RING_BUFFER_SIZE = 32,
XA_RESAMPLE_ZIGZAG_TABLE_SIZE = 29,
XA_RESAMPLE_NUM_ZIGZAG_TABLES = 7,
PRNG_SEED = 0x4B435544u,

PARAM_FIFO_SIZE = 16,
RESPONSE_FIFO_SIZE = 16,
Expand Down Expand Up @@ -460,6 +462,8 @@ struct CDROMState
InlineFIFOQueue<u8, RESPONSE_FIFO_SIZE> response_fifo;
InlineFIFOQueue<u8, RESPONSE_FIFO_SIZE> async_response_fifo;

XorShift128PlusPlus prng;

std::array<SectorBuffer, NUM_SECTOR_BUFFERS> sector_buffers;
u32 current_read_sector_buffer = 0;
u32 current_write_sector_buffer = 0;
Expand Down Expand Up @@ -608,6 +612,7 @@ void CDROM::Reset()
s_state.param_fifo.Clear();
s_state.response_fifo.Clear();
s_state.async_response_fifo.Clear();
s_state.prng.Reset(PRNG_SEED);

UpdateStatusRegister();

Expand Down Expand Up @@ -758,6 +763,11 @@ bool CDROM::DoState(StateWrapper& sw)
sw.Do(&s_state.response_fifo);
sw.Do(&s_state.async_response_fifo);

if (sw.GetVersion() >= 79)
sw.DoPOD(s_state.prng.GetMutableStatePtr());
else
s_state.prng.Reset(PRNG_SEED);

if (sw.GetVersion() < 65)
{
// Skip over the "copied out data", we don't care about it.
Expand Down Expand Up @@ -1637,6 +1647,12 @@ TickCount CDROM::GetTicksForSeek(CDImage::LBA new_lba, bool ignore_speed_change)
seek_type = (new_lba > current_lba) ? "sled forward" : "sled backward";
}

// I hate this so much. There's some games that are extremely timing sensitive in their disc code, and if we return
// the same seek times repeatedly, end up locking up in an infinite loop. e.g. Resident Evil, Dino Crisis, etc.
// Add some randomness to timing if we detect them repeatedly seeking, otherwise don't. This somewhat simulates how
// the real hardware behaves, by adding an additional 0.5-1ms to every seek.
ticks += s_state.prng.NextRange<u32>(System::MASTER_CLOCK / 2000, System::MASTER_CLOCK / 1000);

if (g_settings.cdrom_seek_speedup > 1)
ticks = std::max<u32>(ticks / g_settings.cdrom_seek_speedup, MIN_SEEK_TICKS);

Expand Down
2 changes: 1 addition & 1 deletion src/core/save_state_version.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
#include "common/types.h"

static constexpr u32 SAVE_STATE_MAGIC = 0x43435544;
static constexpr u32 SAVE_STATE_VERSION = 78;
static constexpr u32 SAVE_STATE_VERSION = 79;
static constexpr u32 SAVE_STATE_MINIMUM_VERSION = 42;

static_assert(SAVE_STATE_VERSION >= SAVE_STATE_MINIMUM_VERSION);
Expand Down

0 comments on commit 6f25cf3

Please sign in to comment.