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.
This commit is contained in:
Flyinghead 2024-01-24 18:35:23 +01:00
parent 88fd2641d9
commit cbd01fba38
9 changed files with 128 additions and 70 deletions

View File

@ -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;
}

View File

@ -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();

View File

@ -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

View File

@ -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<u8> *digest);
Disc* gdi_parse(const char* file, std::vector<u8> *digest);
@ -9,8 +11,9 @@ Disc* cdi_parse(const char* file, std::vector<u8> *digest);
Disc* cue_parse(const char* file, std::vector<u8> *digest);
Disc* ioctl_parse(const char* file, std::vector<u8> *digest);
u32 NullDriveDiscType;
static u32 NullDriveDiscType;
Disc* disc;
static int schedId = -1;
constexpr Disc* (*drivers[])(const char* path, std::vector<u8> *digest)
{
@ -23,7 +26,7 @@ constexpr Disc* (*drivers[])(const char* path, std::vector<u8> *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);
}

View File

@ -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
{

View File

@ -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

View File

@ -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<u32>(); // FLASH_SIZE
deser.skip<u32>(); // 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);

View File

@ -71,7 +71,8 @@ public:
V43,
V44,
V45,
Current = V45,
V46,
Current = V46,
Next = Current + 1,
};

View File

@ -32,7 +32,7 @@ TEST_F(SerializeTest, SizeTest)
std::vector<char> data(30000000);
Serializer ser(data.data(), data.size());
dc_serialize(ser);
ASSERT_EQ(28191425u, ser.size());
ASSERT_EQ(28191437u, ser.size());
}