From cbd01fba38f1b6b67e0648095fb3307b79c0008f Mon Sep 17 00:00:00 2001 From: Flyinghead Date: Wed, 24 Jan 2024 18:35:23 +0100 Subject: [PATCH] gdrom: fix disk swapping for some games Add a 1 s delay when inserting a disk before the drive is ready. Fixes disk swapping for Skies of Arcadia, Shenmue II (except HLE), Alone in the Dark, Dancing Blade, First Kiss Story II and Kaen Seibo. Issue #1046 Issue #189 Fixes BIOS menu disk swapping. --- core/emulator.cpp | 2 + core/hw/gdrom/gdrom_if.h | 1 - core/hw/gdrom/gdromv3.cpp | 70 ++++++++++++++-------------- core/imgread/common.cpp | 88 ++++++++++++++++++++++++++++-------- core/imgread/common.h | 4 ++ core/reios/reios.cpp | 14 ++++-- core/serialize.cpp | 14 ++---- core/serialize.h | 3 +- tests/src/serialize_test.cpp | 2 +- 9 files changed, 128 insertions(+), 70 deletions(-) diff --git a/core/emulator.cpp b/core/emulator.cpp index 3c97615d4..fe1d3a2de 100644 --- a/core/emulator.cpp +++ b/core/emulator.cpp @@ -412,6 +412,7 @@ void Emulator::init() // Default platform setPlatform(DC_PLATFORM_DREAMCAST); + libGDR_init(); pvr::init(); aica::init(); mem_Init(); @@ -654,6 +655,7 @@ void Emulator::term() aica::term(); pvr::term(); mem_Term(); + libGDR_term(); state = Terminated; } diff --git a/core/hw/gdrom/gdrom_if.h b/core/hw/gdrom/gdrom_if.h index b71180429..213084c77 100644 --- a/core/hw/gdrom/gdrom_if.h +++ b/core/hw/gdrom/gdrom_if.h @@ -8,7 +8,6 @@ void gdrom_reg_Reset(bool hard); u32 ReadMem_gdrom(u32 Addr, u32 sz); void WriteMem_gdrom(u32 Addr, u32 data, u32 sz); void libCore_CDDA_Sector(s16* sector); -void libCore_gdrom_disc_change(); u32 gd_get_subcode(u32 format, u32 fad, u8 *subc_info); void gd_setdisc(); diff --git a/core/hw/gdrom/gdromv3.cpp b/core/hw/gdrom/gdromv3.cpp index 4cc1cc88f..86758ee37 100644 --- a/core/hw/gdrom/gdromv3.cpp +++ b/core/hw/gdrom/gdromv3.cpp @@ -23,16 +23,16 @@ int sns_asc; int sns_ascq; int sns_key; -u32 set_mode_offset; -read_params_t read_params ; -packet_cmd_t packet_cmd ; -read_buff_t read_buff ; -pio_buff_t pio_buff ; -ata_cmd_t ata_cmd ; -cdda_t cdda ; +static u32 set_mode_offset; +static read_params_t read_params; +static packet_cmd_t packet_cmd; +static read_buff_t read_buff; +static pio_buff_t pio_buff; +static ata_cmd_t ata_cmd; +cdda_t cdda; -gd_states gd_state; -DiscType gd_disk_type; +static gd_states gd_state; +static DiscType gd_disk_type; /* GD rom reset -> GDS_WAITCMD @@ -41,19 +41,19 @@ DiscType gd_disk_type; GDS_SPI_READSECTOR -> Depending on features , it can do quite a few things */ -u32 data_write_mode=0; +static u32 data_write_mode=0; //Registers - u32 DriveSel; - GD_ErrRegT Error; - GD_InterruptReasonT IntReason; - GD_FeaturesT Features; - GD_SecCountT SecCount; - GD_SecNumbT SecNumber; +static u32 DriveSel; +static GD_ErrRegT Error; +static GD_InterruptReasonT IntReason; +static GD_FeaturesT Features; +static GD_SecCountT SecCount; +GD_SecNumbT SecNumber; - GD_StatusT GDStatus; +static GD_StatusT GDStatus; - ByteCount_t ByteCount; +static ByteCount_t ByteCount; //end GD_HardwareInfo_t GD_HardwareInfo; @@ -94,9 +94,10 @@ void libCore_CDDA_Sector(s16* sector) memset(sector,0,2352); } } -void gd_spi_pio_end(const u8* buffer, u32 len, gd_states next_state = gds_pio_end); -void gd_process_spi_cmd(); -void gd_process_ata_cmd(); + +static void gd_spi_pio_end(const u8* buffer, u32 len, gd_states next_state = gds_pio_end); +static void gd_process_spi_cmd(); +static void gd_process_ata_cmd(); static void FillReadBuffer() { @@ -114,7 +115,7 @@ static void FillReadBuffer() } -void gd_set_state(gd_states state) +static void gd_set_state(gd_states state) { gd_states prev=gd_state; gd_state=state; @@ -282,7 +283,7 @@ void gd_setdisc() SecNumber.DiscFormat = gd_disk_type >> 4; } -void gd_reset() +static void gd_reset() { //Reset the drive gd_setdisc(); @@ -298,7 +299,7 @@ static u32 GetFAD(u8* data, bool msf) } //disk changes etc -void libCore_gdrom_disc_change() +static void gd_disc_change() { gd_setdisc(); read_params = { 0 }; @@ -311,7 +312,7 @@ void libCore_gdrom_disc_change() } //This handles the work of setting up the pio regs/state :) -void gd_spi_pio_end(const u8* buffer, u32 len, gd_states next_state) +static void gd_spi_pio_end(const u8* buffer, u32 len, gd_states next_state) { verify(len<0xFFFF); pio_buff.index=0; @@ -326,7 +327,7 @@ void gd_spi_pio_end(const u8* buffer, u32 len, gd_states next_state) else gd_set_state(gds_pio_send_data); } -void gd_spi_pio_read_end(u32 len, gd_states next_state) +static void gd_spi_pio_read_end(u32 len, gd_states next_state) { verify(len<0xFFFF); pio_buff.index=0; @@ -338,7 +339,7 @@ void gd_spi_pio_read_end(u32 len, gd_states next_state) else gd_set_state(gds_pio_get_data); } -void gd_process_ata_cmd() +static void gd_process_ata_cmd() { //Any ATA command clears these bits, unless aborted/error :p Error.ABRT=0; @@ -644,7 +645,7 @@ u32 gd_get_subcode(u32 format, u32 fad, u8 *subc_info) return subc_info[3]; } -void gd_process_spi_cmd() +static void gd_process_spi_cmd() { printf_spi("Sense: %02x %02x %02x", sns_asc, sns_ascq, sns_key); @@ -664,9 +665,7 @@ void gd_process_spi_cmd() { case SPI_TEST_UNIT: printf_spicmd("SPI_TEST_UNIT"); - - GDStatus.CHECK=SecNumber.Status==GD_BUSY; // Drive is ready ;) - + // This device does not report the check condition status. gd_set_state(gds_procpacketdone); break; @@ -776,8 +775,8 @@ void gd_process_spi_cmd() case SPI_REQ_STAT: { - printf_spicmd("SPI_REQ_STAT"); u32 curFad = cdda.status == cdda_t::Playing || cdda.status == cdda_t::Paused ? cdda.CurrAddr.FAD : read_params.start_sector - 1; + printf_spicmd("SPI_REQ_STAT: status %d fmt %d fad %d", SecNumber.Status, SecNumber.DiscFormat, curFad); u32 elapsed; u32 tracknum = libGDR_GetTrackNumber(curFad, elapsed); u8 stat[10]; @@ -833,7 +832,7 @@ void gd_process_spi_cmd() case SPI_REQ_SES: { - printf_spicmd("SPI_REQ_SES"); + printf_spicmd("SPI_REQ_SES: status %d", SecNumber.Status); u8 ses_inf[6]; libGDR_GetSessionInfo(ses_inf,packet_cmd.data_8[2]); @@ -1301,7 +1300,7 @@ static void GDROM_DmaEnable(u32 addr, u32 data) void gdrom_reg_Init() { gdrom_schid = sh4_sched_register(0, &GDRomschd); - libCore_gdrom_disc_change(); + gd_disc_change(); } void gdrom_reg_Term() @@ -1327,6 +1326,7 @@ void gdrom_reg_Reset(bool hard) memcpy(GD_HardwareInfo.drive_info, "SE ", sizeof(GD_HardwareInfo.drive_info)); memcpy(GD_HardwareInfo.system_version, "Rev 6.43", sizeof(GD_HardwareInfo.system_version)); memcpy(GD_HardwareInfo.system_date, "990408", sizeof(GD_HardwareInfo.system_date)); + TermDrive(); } SB_GDST = 0; SB_GDEN = 0; @@ -1354,7 +1354,7 @@ void gdrom_reg_Reset(bool hard) GDStatus = {}; ByteCount = {}; - libCore_gdrom_disc_change(); + gd_disc_change(); } namespace gdrom diff --git a/core/imgread/common.cpp b/core/imgread/common.cpp index 611bff5d1..bdbb8a72b 100644 --- a/core/imgread/common.cpp +++ b/core/imgread/common.cpp @@ -2,6 +2,8 @@ #include "hw/gdrom/gdromv3.h" #include "cfg/option.h" #include "stdclass.h" +#include "hw/sh4/sh4_sched.h" +#include "serialize.h" Disc* chd_parse(const char* file, std::vector *digest); Disc* gdi_parse(const char* file, std::vector *digest); @@ -9,8 +11,9 @@ Disc* cdi_parse(const char* file, std::vector *digest); Disc* cue_parse(const char* file, std::vector *digest); Disc* ioctl_parse(const char* file, std::vector *digest); -u32 NullDriveDiscType; +static u32 NullDriveDiscType; Disc* disc; +static int schedId = -1; constexpr Disc* (*drivers[])(const char* path, std::vector *digest) { @@ -23,7 +26,7 @@ constexpr Disc* (*drivers[])(const char* path, std::vector *digest) #endif }; -u8 q_subchannel[96]; +static u8 q_subchannel[96]; static bool convertSector(u8* in_buff , u8* out_buff , int from , int to,int sector) { @@ -113,18 +116,16 @@ static bool loadDisk(const std::string& path) INFO_LOG(GDROM, "gdrom: Failed to open image \"%s\"", path.c_str()); NullDriveDiscType = NoDisk; } - libCore_gdrom_disc_change(); return disc != NULL; } +static bool doDiscSwap(const std::string& path); + bool InitDrive(const std::string& path) { - bool rc = DiscSwap(path); - // not needed at startup and confuses some games - sns_asc = 0; - sns_ascq = 0; - sns_key = 0; + bool rc = doDiscSwap(path); + gd_setdisc(); return rc; } @@ -139,18 +140,12 @@ void DiscOpenLid() sns_key = 0x6; } -bool DiscSwap(const std::string& path) +static bool doDiscSwap(const std::string& path) { - // These Additional Sense Codes mean "The lid was closed" - sns_asc = 0x28; - sns_ascq = 0x00; - sns_key = 0x6; - if (path.empty()) { TermDrive(); NullDriveDiscType = NoDisk; - gd_setdisc(); return true; } @@ -158,15 +153,14 @@ bool DiscSwap(const std::string& path) return true; NullDriveDiscType = NoDisk; - gd_setdisc(); - return false; } void TermDrive() { + sh4_sched_request(schedId, -1); delete disc; - disc = NULL; + disc = nullptr; } @@ -311,8 +305,64 @@ void libGDR_ReadSubChannel(u8 * buff, u32 len) u32 libGDR_GetDiscType() { - if (disc) + if (SecNumber.Status != GD_BUSY && disc != nullptr) return disc->type; else return NullDriveDiscType; } + +static int discSwapCallback(int tag, int sch_cycl, int jitter, void *arg) +{ + if (disc != nullptr) + // The lid was closed + sns_asc = 0x28; + else + // No disc inserted at the time of power-on, reset or hard reset, or TOC cannot be read. + sns_asc = 0x29; + sns_ascq = 0x00; + sns_key = 0x6; + gd_setdisc(); + + return 0; +} + +bool DiscSwap(const std::string& path) +{ + if (!doDiscSwap(path)) + throw FlycastException("This media cannot be loaded"); + // Drive is busy after the lid was closed + sns_asc = 4; + sns_ascq = 1; + sns_key = 2; + SecNumber.Status = GD_BUSY; + sh4_sched_request(schedId, SH4_MAIN_CLOCK); // 1 s + + return true; +} + +void libGDR_init() +{ + schedId = sh4_sched_register(0, discSwapCallback); +} +void libGDR_term() +{ + TermDrive(); + sh4_sched_unregister(schedId); + schedId = -1; +} + +void libGDR_serialize(Serializer& ser) +{ + ser << NullDriveDiscType; + ser << q_subchannel; + sh4_sched_serialize(ser, schedId); +} +void libGDR_deserialize(Deserializer& deser) +{ + deser >> NullDriveDiscType; + deser >> q_subchannel; + if (deser.version() >= Deserializer::V46) + sh4_sched_deserialize(deser, schedId); + else + sh4_sched_request(schedId, -1); +} diff --git a/core/imgread/common.h b/core/imgread/common.h index 0e1ab86d5..8da24bf51 100644 --- a/core/imgread/common.h +++ b/core/imgread/common.h @@ -273,6 +273,10 @@ bool libGDR_GetTrack(u32 track_num, u32& start_fad, u32& end_fad); std::string libGDR_GetDiskCatalog(); std::string libGDR_GetTrackIsrc(u32 trackNum); void libGDR_GetTrackAdrAndControl(u32 trackNum, u8& adr, u8& ctrl); +void libGDR_init(); +void libGDR_term(); +void libGDR_serialize(Serializer& ser); +void libGDR_deserialize(Deserializer& deser); namespace flycast { diff --git a/core/reios/reios.cpp b/core/reios/reios.cpp index 7389b32c7..42c2127b3 100644 --- a/core/reios/reios.cpp +++ b/core/reios/reios.cpp @@ -357,9 +357,17 @@ static void reios_sys_misc() break; case 2: // check disk - p_sh4rcb->cntx.r[0] = 0; - // Reload part of IP.BIN bootstrap - libGDR_ReadSector(GetMemPtr(0x8c008100, 0), base_fad, 7, 2048); + { + u32 diskType = libGDR_GetDiscType(); + if (diskType == NoDisk || diskType == Open) { + p_sh4rcb->cntx.r[0] = -1; + } + else { + p_sh4rcb->cntx.r[0] = 0; + // Reload part of IP.BIN bootstrap + libGDR_ReadSector(GetMemPtr(0x8c008100, 0), base_fad, 7, 2048); + } + } break; case 3: // Exit to CD menu diff --git a/core/serialize.cpp b/core/serialize.cpp index 610dd5f32..4c6b5735d 100644 --- a/core/serialize.cpp +++ b/core/serialize.cpp @@ -15,10 +15,7 @@ #include "hw/naomi/naomi_cart.h" #include "hw/bba/bba.h" #include "cfg/option.h" - -//./core/imgread/common.o -extern u32 NullDriveDiscType; -extern u8 q_subchannel[96]; +#include "imgread/common.h" void dc_serialize(Serializer& ser) { @@ -43,8 +40,7 @@ void dc_serialize(Serializer& ser) sh4::serialize2(ser); - ser << NullDriveDiscType; - ser << q_subchannel; + libGDR_serialize(ser); naomi_Serialize(ser); @@ -82,8 +78,7 @@ static void dc_deserialize_libretro(Deserializer& deser) sh4::deserialize2(deser); - deser >> NullDriveDiscType; - deser >> q_subchannel; + libGDR_deserialize(deser); deser.skip(); // FLASH_SIZE deser.skip(); // BBSRAM_SIZE @@ -141,8 +136,7 @@ void dc_deserialize(Deserializer& deser) sh4::deserialize2(deser); - deser >> NullDriveDiscType; - deser >> q_subchannel; + libGDR_deserialize(deser); naomi_Deserialize(deser); diff --git a/core/serialize.h b/core/serialize.h index 9295f36d1..81405cfef 100644 --- a/core/serialize.h +++ b/core/serialize.h @@ -71,7 +71,8 @@ public: V43, V44, V45, - Current = V45, + V46, + Current = V46, Next = Current + 1, }; diff --git a/tests/src/serialize_test.cpp b/tests/src/serialize_test.cpp index 1415b19eb..0e197a516 100644 --- a/tests/src/serialize_test.cpp +++ b/tests/src/serialize_test.cpp @@ -32,7 +32,7 @@ TEST_F(SerializeTest, SizeTest) std::vector data(30000000); Serializer ser(data.data(), data.size()); dc_serialize(ser); - ASSERT_EQ(28191425u, ser.size()); + ASSERT_EQ(28191437u, ser.size()); }