From 04b9d3fbc56ef03d2cf6e225f19b0f339e0e069d Mon Sep 17 00:00:00 2001 From: kuba-j Date: Sun, 18 Jan 2026 18:32:23 +0100 Subject: [PATCH 1/9] Add optional Backward Seek Hack (OSD toggle) - fix Dave Mirra/Thrasher games Fix for Dave Mirra/Thrasher is generally safe for most titles (tested over 200+ games ), but known to cause issues in some Army Men games. It must be some edge case that cannot tolerate this change. Anyway, the problem with Dave Mirra is also like that :) Kept as an unsafe optional setting until a proper fix is available. This is the best solution for now, and it would be a shame to lose the opportunity to comfortably play Dave Mirra and Trasher games --- rtl/cd_top.vhd | 12 +++++++++--- rtl/psx_mister.vhd | 2 ++ rtl/psx_top.vhd | 3 +++ 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/rtl/cd_top.vhd b/rtl/cd_top.vhd index f7bd5c3..06358ab 100644 --- a/rtl/cd_top.vhd +++ b/rtl/cd_top.vhd @@ -22,6 +22,8 @@ entity cd_top is pauseOnCDSlow : in std_logic; region : in std_logic_vector(1 downto 0); region_out : out std_logic_vector(1 downto 0); + + backwardSeekHack : in std_logic; pauseCD : out std_logic := '0'; Pause_idle_cd : out std_logic := '0'; @@ -1915,9 +1917,13 @@ begin ackDriveEnd <= '1'; else skipreading := '0'; - if (setLocActive = '1' and (currentLBA - seekLBA) >= 2) then - skipreading := '1'; - end if; + -- optional fix for Dave Mirra / Trasher + if (backwardSeekHack = '1') then + if (setLocActive = '1' and (currentLBA - seekLBA) >= 2) then + skipreading := '1'; + end if; + end if; + if (isAudio = '1') then if (currentTrackBCD = x"00") then -- auto find track number from subheader currentTrackBCD <= nextSubdata(1); diff --git a/rtl/psx_mister.vhd b/rtl/psx_mister.vhd index a7ce2e3..14e2c07 100644 --- a/rtl/psx_mister.vhd +++ b/rtl/psx_mister.vhd @@ -66,6 +66,7 @@ entity psx_mister is REPRODUCIBLESPUDMA : in std_logic; WIDESCREEN : in std_logic_vector(1 downto 0); oldGPU : in std_logic; + backwardSeekHack : in std_logic; -- RAM/BIOS interface biosregion : in std_logic_vector(1 downto 0); ram_refresh : out std_logic; @@ -359,6 +360,7 @@ begin REPRODUCIBLESPUDMA => REPRODUCIBLESPUDMA, WIDESCREEN => WIDESCREEN, oldGPU => oldGPU, + backwardSeekHack => backwardSeekHack, -- RAM/BIOS interface biosregion => biosregion, ram_refresh => ram_refresh, diff --git a/rtl/psx_top.vhd b/rtl/psx_top.vhd index 928b8f9..22245df 100644 --- a/rtl/psx_top.vhd +++ b/rtl/psx_top.vhd @@ -70,6 +70,7 @@ entity psx_top is REPRODUCIBLESPUDMA : in std_logic; WIDESCREEN : in std_logic_vector(1 downto 0); oldGPU : in std_logic; + backwardSeekHack : in std_logic; -- RAM/BIOS interface biosregion : in std_logic_vector(1 downto 0); ram_refresh : out std_logic; @@ -1404,6 +1405,8 @@ begin LIDopen => LIDopen, region => region, region_out => region_out, + + backwardSeekHack => backwardSeekHack, pauseCD => pauseCD, Pause_idle_cd => Pause_idle_cd, From 02570ea086e4f1344e3582781df58fc17230422d Mon Sep 17 00:00:00 2001 From: kuba-j Date: Sun, 18 Jan 2026 18:33:00 +0100 Subject: [PATCH 2/9] Add optional Backward Seek Hack (OSD toggle) - fix Dave Mirra/Thrasher games Fix for Dave Mirra/Thrasher is generally safe for most titles (tested over 200+ games ), but known to cause issues in some Army Men games. It must be some edge case that cannot tolerate this change. Anyway, the problem with Dave Mirra is also like that :) Kept as an unsafe optional setting until a proper fix is available. This is the best solution for now, and it would be a shame to lose the opportunity to comfortably play Dave Mirra and Trasher games --- PSX.sv | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/PSX.sv b/PSX.sv index 3f845a0..67981e6 100644 --- a/PSX.sv +++ b/PSX.sv @@ -345,7 +345,7 @@ wire reset_or = RESET | buttons[1] | status[0] | bios_download | exe_download | // 0 1 2 3 4 5 6 7 8 9 // 01234567890123456789012345678901 23456789012345678901234567890123 45678901234567890123456789012345 // 0123456789ABCDEFGHIJKLMNOPQRSTUV 0123456789ABCDEFGHIJKLMNOPQRSTUV -// XXXX XXXXXX XXXXXX XXXXX XX XX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXX +// XXXX XXXXXX XXXXXX XXXXX XX XX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX `include "build_id.v" parameter CONF_STR = { @@ -423,6 +423,7 @@ parameter CONF_STR = { "P2O[21],CD Fast Seek,Off,On(U);", "P2O[77:75],CD Speed,Original,Forced 1X(U),Forced 2X(U),Hack 4X(U),Hack 6X(U),Hack 8X(U);", "P2O[78],Limit Max CD Speed,Off,On(U);", + "P2O[93],Backward Seek Hack,Off,On(U);", "P2O[85],RAM(Homebrew),2 MByte,8 MByte(U);", "P2O[90],GPU Slowdown,Off,On(U);", "P2O[92],Old GPU,Off,On;", @@ -941,7 +942,7 @@ always @(posedge clk_1x) begin if (!padMode[1]) psx_info <= 8'd18; end else if (cdinfo_download_1 && ~cdinfo_download) begin // warning for every unsafe option - if (status[89] || status[80:79] > 0 || status[72] || status[15] || status[21] || status[77:75] > 0 || status[78] || status[85]) begin + if (status[89] || status[80:79] > 0 || status[72] || status[15] || status[21] || status[77:75] > 0 || status[78] || status[85] || status[93]) begin psx_info_req <= 1; psx_info <= 8'd24; end else if (status[40:39] == 2'b00) begin @@ -1109,6 +1110,7 @@ psx .REPRODUCIBLESPUDMA(status[43]), .WIDESCREEN(status[54:53]), .oldGPU(status[92]), + .backwardSeekHack(status[93]), // RAM/BIOS interface .biosregion(biosregion), From cdb33cd56d30172bdca59ffaa773945e738de2d9 Mon Sep 17 00:00:00 2001 From: kuba-j Date: Sun, 18 Jan 2026 18:37:04 +0100 Subject: [PATCH 3/9] Update README.md --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 369ea5a..71d5b3c 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ SDRAM of any size is required. * 8 Mbyte mode(from dev units, mostly for homebrew) * Inputs: DualShock, Digital, Analog, Mouse, NeGcon, Wheel, Justifier and Guncon support. * Native Input support through SNAC +* Old GPU (CXD8514Q) ## Bios Rename your playstation bios file (e.g. `scph-1001.bin`/`ps-22a.bin` ) and place it in the `./games/PSX/` folder. @@ -107,6 +108,11 @@ The higher speed rates are more unstable and require proper storage to be usable Will hold back any new CD data until the game has processed the last data. Mostly useful to prevent CD data overrun when using higher speed modes, leading to overall faster loading times due to less read retries. +- Backward Seek Hack: +Fixes long stutters in Dave Mirra and Thrasher games related to backward CD seeks. +The drive continues reading normally, while sectors ahead of the seek target are temporarily hidden from the CPU until the correct position is reached. +Generally safe, but may affect a small number of sensitive titles (e.g. some Army Men games). + - RAM: 8 Mbyte option from development consoles. Only use for homebrew that requires it, otherwise there is a high chance of crashing games. From 50ed47e25f88df0c747a35ca9a68d1a6a2d84a45 Mon Sep 17 00:00:00 2001 From: kuba-j Date: Sun, 18 Jan 2026 18:40:25 +0100 Subject: [PATCH 4/9] Update PSX.sv --- PSX.sv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PSX.sv b/PSX.sv index 67981e6..8a8ffdd 100644 --- a/PSX.sv +++ b/PSX.sv @@ -426,7 +426,7 @@ parameter CONF_STR = { "P2O[93],Backward Seek Hack,Off,On(U);", "P2O[85],RAM(Homebrew),2 MByte,8 MByte(U);", "P2O[90],GPU Slowdown,Off,On(U);", - "P2O[92],Old GPU,Off,On;", + "P2O[92],Old GPU (CXD8514Q),Off,On;", "P2-;", "P2O[28],FPS Overlay,Off,On;", "P2O[74],Error Overlay,Off,On;", From bce86f034ccf22d688d62393562764c92bb87448 Mon Sep 17 00:00:00 2001 From: kuba-j Date: Sun, 18 Jan 2026 18:42:49 +0100 Subject: [PATCH 5/9] CD: Fix INT1 handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CD: Fix INT1 vs INT3 interrupt ordering Some games rely on very strict CDROM interrupt ordering and timing: Gokujou Parodius Da! Deluxe Pack and Crime Crackers require INT1 to be visible immediately after a sector becomes readable. Jikkyō Powerful Pro Yakyū ’95 relies on INT3 responses being fully processed before INT1, otherwise FIFO responses are read in the wrong order, causing music stutter. This change refines INT1 delivery logic. INT1 is forced immediately when no conflicting INT3 is active (required by Parodius / Crime Crackers). INT1 is deferred (queued) when INT3 is currently active, preventing response/FIFO ordering issues (required by Jikkyō ’95). Any active non-INT1 IRQ is preserved using the existing pendingDriveIRQ mechanism. --- rtl/cd_top.vhd | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/rtl/cd_top.vhd b/rtl/cd_top.vhd index 06358ab..810937f 100644 --- a/rtl/cd_top.vhd +++ b/rtl/cd_top.vhd @@ -716,19 +716,24 @@ begin end if; end if; - if (ackRead = '1' or ackRead_data = '1') then - if (CDROM_IRQFLAG = "00001") then -- irq for sector still pending, sector missed - -- will be handled when next sector is fetched from cpu interface - elsif (CDROM_IRQFLAG /= "00000") then -- store sector done if current irq is something else, so CPU will be notified later - pendingDriveIRQ <= "00001"; - pendingDriveResponse <= internalStatus; + if (ackRead = '1' or ackRead_data = '1') then + if (CDROM_IRQFLAG = "00011") then + -- INT3 active: do not overwrite it with INT1 + -- queue INT1 for later delivery + if (pendingDriveIRQ = "00000") then + pendingDriveIRQ <= "00001"; + pendingDriveResponse <= internalStatus; + end if; else + if (CDROM_IRQFLAG /= "00000" and CDROM_IRQFLAG /= "00001") then + pendingDriveIRQ <= CDROM_IRQFLAG; + end if; CDROM_IRQFLAG <= "00001"; if (CDROM_IRQENA(0) = '1') then irqOut <= '1'; end if; ackRead_valid <= '1'; - end if; + end if; end if; if (ackPendingIRQNext = '1') then From 02f8a8852b0b8f8105b202020d633431c9ba8303 Mon Sep 17 00:00:00 2001 From: kuba-j Date: Sun, 18 Jan 2026 19:34:57 +0100 Subject: [PATCH 6/9] Update PSX.sv --- PSX.sv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PSX.sv b/PSX.sv index 8a8ffdd..e7f0d5e 100644 --- a/PSX.sv +++ b/PSX.sv @@ -426,7 +426,7 @@ parameter CONF_STR = { "P2O[93],Backward Seek Hack,Off,On(U);", "P2O[85],RAM(Homebrew),2 MByte,8 MByte(U);", "P2O[90],GPU Slowdown,Off,On(U);", - "P2O[92],Old GPU (CXD8514Q),Off,On;", + "P2O[92],Old GPU(CXD8514Q),Off,On;", "P2-;", "P2O[28],FPS Overlay,Off,On;", "P2O[74],Error Overlay,Off,On;", From 6df0b564f579e188b5d530987f42ddf4cf9ef1af Mon Sep 17 00:00:00 2001 From: kuba-j Date: Sun, 18 Jan 2026 22:04:04 +0100 Subject: [PATCH 7/9] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 71d5b3c..f03d430 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ You need to save them either manually in the OSD or turn on autosave. Saving or ## Multiple Disc Games -To swap discs while the game is running, you will need have all of the disc files for the game placed in the same folder. Then when loading a new disc for most games you will need to toggle the Lid Open/Close option to tell the game you have opened the lid and closed it. Example folder structure of a multi disc game: +To swap discs while the game is running, all disc files for the game must be placed in the same folder. When a disc change is required, the core will automatically simulate opening and closing the disc lid. Example folder structure of a multi-disc game: ``` /media/fat/games/PSX/Final Fantasy VII (USA)/Final Fantasy VII (USA) (Disc 1).chd From 2046176beb547b3a1559b2a1f11007f132188f67 Mon Sep 17 00:00:00 2001 From: kuba-j Date: Sat, 24 Jan 2026 22:08:32 +0100 Subject: [PATCH 8/9] CD: fix DMA read from empty sector buffer - The previous code could start a CD-ROM DMA transfer even when sectorBufferSizes(readPtr) was zero, and it cleared the buffer size flag before copySize was latched, leading to reads from empty buffers and propagation of invalid data. - The new logic only starts DMA when a valid sector is present and latches the sector size before clearing the ready flag, eliminating the race condition. --- rtl/cd_top.vhd | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/rtl/cd_top.vhd b/rtl/cd_top.vhd index 810937f..02c975c 100644 --- a/rtl/cd_top.vhd +++ b/rtl/cd_top.vhd @@ -2828,19 +2828,23 @@ begin case (copyState) is when COPY_IDLE => - if (copyData = '1' and ce = '1') then + if (copyData = '1' and ce = '1' and + sectorBufferSizes(to_integer(readSectorPointer)) /= 0) then + copyState <= COPY_FIRST; copyCount <= 0; copyReadAddr <= 0; copyByteCnt <= 0; copySectorPointer <= readSectorPointer; - sectorBufferSizes(to_integer(readSectorPointer)) <= 0; - if (sectorBufferSizes(to_integer(readSectorPointer)) = 0) then - copySize <= RAW_SECTOR_OUTPUT_SIZE / 4; - else - copySize <= sectorBufferSizes(to_integer(readSectorPointer)); - end if; + -- read size before clearing buffer size + if (sectorBufferSizes(to_integer(readSectorPointer)) = 0) then + copySize <= RAW_SECTOR_OUTPUT_SIZE / 4; + else + copySize <= sectorBufferSizes(to_integer(readSectorPointer)); end if; + -- clear buffer size after size was latched + sectorBufferSizes(to_integer(readSectorPointer)) <= 0; + end if; when COPY_FIRST => copyState <= COPY_DATA; From 0077e4922516c1e952c0e090e61a3ebd21ad623e Mon Sep 17 00:00:00 2001 From: kuba-j Date: Mon, 26 Jan 2026 08:40:04 +0100 Subject: [PATCH 9/9] CD: Fix PAUSE timing to match psx-spx and DuckStation --- rtl/cd_top.vhd | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rtl/cd_top.vhd b/rtl/cd_top.vhd index 02c975c..132027c 100644 --- a/rtl/cd_top.vhd +++ b/rtl/cd_top.vhd @@ -1112,11 +1112,11 @@ begin workCommand <= nextCmd; cmdResetXa <= '1'; if (driveState = DRIVE_READING or driveState = DRIVE_PLAYING) then - -- todo: should this be swapped between single speed and double speed? DuckStation has double speed longer and psx spx doc has single speed being longer + -- Matches psx spx doc and DuckStation if (modeReg(7) = '1') then - workDelay <= 2157295 + driveDelay; -- value from psx spx doc - else workDelay <= 1066874 + driveDelay; -- value from psx spx doc + else + workDelay <= 2157295 + driveDelay; -- value from psx spx doc end if; end if; if (driveState = DRIVE_SEEKLOGICAL or driveState = DRIVE_SEEKPHYSICAL or driveState = DRIVE_SEEKIMPLICIT) then