CDROM: Trigger INT5 on shell open

This behaviour has been verified on console.

Fixes disc swap detection in "Arc the Lad III"
This commit is contained in:
Connor McLaughlin 2020-03-29 01:15:04 +10:00
parent 2292292956
commit 0e0bd2852f
2 changed files with 41 additions and 19 deletions

View File

@ -43,6 +43,7 @@ void CDROM::SoftReset()
m_drive_event->Deactivate();
m_status.bits = 0;
m_secondary_status.bits = 0;
m_secondary_status.motor_on = HasMedia();
m_mode.bits = 0;
m_interrupt_enable_register = INTERRUPT_REGISTER_MASK;
m_interrupt_flag_register = 0;
@ -170,6 +171,9 @@ void CDROM::InsertMedia(std::unique_ptr<CDImage> media)
Log_InfoPrintf("Inserting new media, disc region: %s, console region: %s", Settings::GetDiscRegionName(m_disc_region),
Settings::GetConsoleRegionName(m_system->GetRegion()));
// motor automatically spins up
m_secondary_status.motor_on = true;
m_reader.SetMedia(std::move(media));
}
@ -181,17 +185,19 @@ void CDROM::RemoveMedia()
Log_InfoPrintf("Removing CD...");
m_reader.RemoveMedia();
m_secondary_status.motor_on = false;
m_secondary_status.shell_open = true;
m_secondary_status.ClearActiveBits();
m_disc_region = DiscRegion::Other;
// If the drive was doing anything, we need to abort the command.
if (m_drive_state != DriveState::Idle)
{
// TODO: Verify this.
Log_WarningPrintf("Aborting drive operation");
SendAsyncErrorResponse(0x08);
m_drive_state = DriveState::Idle;
}
m_command = Command::None;
m_command_event->Deactivate();
m_drive_event->Deactivate();
// The console sends an interrupt when the shell is opened regardless of whether a command was executing.
SendAsyncErrorResponse(STAT_ERROR, 0x08);
}
void CDROM::SetUseReadThread(bool enabled)
@ -761,12 +767,12 @@ void CDROM::ExecuteCommand()
return;
}
case Command::Init:
case Command::Reset:
{
Log_DebugPrintf("CDROM init command");
Log_DebugPrintf("CDROM reset command");
SendACKAndStat();
m_drive_state = DriveState::SpinningUp;
m_drive_state = DriveState::Resetting;
m_drive_event->Schedule(80000);
EndCommand();
@ -785,7 +791,7 @@ void CDROM::ExecuteCommand()
{
SendACKAndStat();
m_drive_state = DriveState::SpinningUp;
m_drive_state = DriveState::Resetting;
m_drive_event->Schedule(80000);
}
@ -1033,8 +1039,8 @@ void CDROM::ExecuteDrive(TickCount ticks_late)
{
switch (m_drive_state)
{
case DriveState::SpinningUp:
DoSpinUpComplete();
case DriveState::Resetting:
DoResetComplete(ticks_late);
break;
case DriveState::SeekingPhysical:
@ -1164,7 +1170,7 @@ void CDROM::BeginSeeking(bool logical, bool read_after_seek, bool play_after_see
m_reader.QueueReadSector(m_last_requested_sector);
}
void CDROM::DoSpinUpComplete()
void CDROM::DoResetComplete(TickCount ticks_late)
{
m_drive_state = DriveState::Idle;
m_drive_event->Deactivate();
@ -1174,9 +1180,24 @@ void CDROM::DoSpinUpComplete()
m_mode.bits = 0;
m_mode.read_raw_sector = true;
if (!HasMedia())
{
Log_DevPrintf("CDROM reset - no disc");
m_secondary_status.shell_open = true;
m_secondary_status.motor_on = false;
SendAsyncErrorResponse(STAT_ERROR, 0x08);
return;
}
m_async_response_fifo.Clear();
m_async_response_fifo.Push(m_secondary_status.bits);
SetAsyncInterrupt(Interrupt::Complete);
if (!HasMedia())
{
m_secondary_status.motor_on = false;
m_secondary_status.shell_open = true;
}
}
void CDROM::DoSeekComplete(TickCount ticks_late)
@ -1329,6 +1350,7 @@ void CDROM::DoTOCRead()
Log_DebugPrintf("TOC read complete");
m_drive_state = DriveState::Idle;
m_drive_event->Deactivate();
m_async_response_fifo.Clear();
m_async_response_fifo.Push(m_secondary_status.bits);
SetAsyncInterrupt(Interrupt::Complete);
@ -1754,7 +1776,7 @@ void CDROM::DrawDebugWindow()
if (ImGui::CollapsingHeader("Status/Mode", ImGuiTreeNodeFlags_DefaultOpen))
{
static constexpr std::array<const char*, 11> drive_state_names = {
{"Idle", "Spinning Up", "Seeking (Physical)", "Seeking (Logical)", "Reading ID", "Reading TOC", "Reading",
{"Idle", "Resetting", "Seeking (Physical)", "Seeking (Logical)", "Reading ID", "Reading TOC", "Reading",
"Playing", "Pausing", "Stopping", "Changing Session"}};
ImGui::Columns(3);

View File

@ -83,7 +83,7 @@ private:
MotorOn = 0x07,
Stop = 0x08,
Pause = 0x09,
Init = 0x0A,
Reset = 0x0A,
Mute = 0x0B,
Demute = 0x0C,
Setfilter = 0x0D,
@ -101,7 +101,7 @@ private:
Test = 0x19,
GetID = 0x1A,
ReadS = 0x1B,
Reset = 0x1C,
Init = 0x1C,
GetQ = 0x1D,
ReadTOC = 0x1E,
VideoCD = 0x1F,
@ -112,7 +112,7 @@ private:
enum class DriveState : u8
{
Idle,
SpinningUp,
Resetting,
SeekingPhysical,
SeekingLogical,
ReadingID,
@ -215,7 +215,7 @@ private:
void ExecuteDrive(TickCount ticks_late);
void BeginReading(TickCount ticks_late = 0);
void BeginPlaying(u8 track_bcd, TickCount ticks_late = 0);
void DoSpinUpComplete();
void DoResetComplete(TickCount ticks_late);
void DoSeekComplete(TickCount ticks_late);
void DoPauseComplete();
void DoStopComplete();