mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-27 08:05:41 +00:00
CDROM: Refactor start/stop/second response
This commit is contained in:
parent
9d36ce757d
commit
36bfc461f9
|
@ -80,8 +80,14 @@ void CDROM::Initialize()
|
||||||
{
|
{
|
||||||
m_command_event = TimingEvents::CreateTimingEvent(
|
m_command_event = TimingEvents::CreateTimingEvent(
|
||||||
"CDROM Command Event", 1, 1,
|
"CDROM Command Event", 1, 1,
|
||||||
[](void* param, TickCount ticks, TickCount ticks_late) { static_cast<CDROM*>(param)->ExecuteCommand(); }, this,
|
[](void* param, TickCount ticks, TickCount ticks_late) { static_cast<CDROM*>(param)->ExecuteCommand(ticks_late); },
|
||||||
false);
|
this, false);
|
||||||
|
m_command_second_response_event = TimingEvents::CreateTimingEvent(
|
||||||
|
"CDROM Command Second Response Event", 1, 1,
|
||||||
|
[](void* param, TickCount ticks, TickCount ticks_late) {
|
||||||
|
static_cast<CDROM*>(param)->ExecuteCommandSecondResponse(ticks_late);
|
||||||
|
},
|
||||||
|
this, false);
|
||||||
m_drive_event = TimingEvents::CreateTimingEvent(
|
m_drive_event = TimingEvents::CreateTimingEvent(
|
||||||
"CDROM Drive Event", 1, 1,
|
"CDROM Drive Event", 1, 1,
|
||||||
[](void* param, TickCount ticks, TickCount ticks_late) { static_cast<CDROM*>(param)->ExecuteDrive(ticks_late); },
|
[](void* param, TickCount ticks, TickCount ticks_late) { static_cast<CDROM*>(param)->ExecuteDrive(ticks_late); },
|
||||||
|
@ -105,32 +111,26 @@ void CDROM::Reset()
|
||||||
{
|
{
|
||||||
SoftReset();
|
SoftReset();
|
||||||
|
|
||||||
// this should be reading sector 0
|
SetHoldPosition(0, true);
|
||||||
m_reader.WaitForReadToComplete();
|
|
||||||
if (m_reader.GetSectorSubQ().IsCRCValid())
|
|
||||||
m_last_subq = m_reader.GetSectorSubQ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDROM::SoftReset()
|
void CDROM::SoftReset()
|
||||||
{
|
{
|
||||||
m_command = Command::None;
|
m_command = Command::None;
|
||||||
m_command_event->Deactivate();
|
m_command_event->Deactivate();
|
||||||
m_drive_state = DriveState::Idle;
|
ClearCommandSecondResponse();
|
||||||
m_drive_event->Deactivate();
|
ClearDriveState();
|
||||||
m_status.bits = 0;
|
m_status.bits = 0;
|
||||||
m_secondary_status.bits = 0;
|
m_secondary_status.bits = 0;
|
||||||
m_secondary_status.motor_on = CanReadMedia();
|
m_secondary_status.motor_on = CanReadMedia();
|
||||||
m_secondary_status.shell_open = !CanReadMedia();
|
m_secondary_status.shell_open = !CanReadMedia();
|
||||||
m_mode.bits = 0;
|
m_mode.bits = 0;
|
||||||
|
m_mode.read_raw_sector = true;
|
||||||
m_current_double_speed = false;
|
m_current_double_speed = false;
|
||||||
m_interrupt_enable_register = INTERRUPT_REGISTER_MASK;
|
m_interrupt_enable_register = INTERRUPT_REGISTER_MASK;
|
||||||
m_interrupt_flag_register = 0;
|
m_interrupt_flag_register = 0;
|
||||||
m_pending_async_interrupt = 0;
|
m_pending_async_interrupt = 0;
|
||||||
m_setloc_position = {};
|
m_setloc_position = {};
|
||||||
m_current_lba = 0;
|
|
||||||
ResetPhysicalPosition();
|
|
||||||
if (m_reader.HasMedia())
|
|
||||||
m_reader.QueueReadSector(m_current_lba);
|
|
||||||
m_seek_start_lba = 0;
|
m_seek_start_lba = 0;
|
||||||
m_seek_end_lba = 0;
|
m_seek_end_lba = 0;
|
||||||
m_setloc_pending = false;
|
m_setloc_pending = false;
|
||||||
|
@ -175,6 +175,7 @@ void CDROM::SoftReset()
|
||||||
bool CDROM::DoState(StateWrapper& sw)
|
bool CDROM::DoState(StateWrapper& sw)
|
||||||
{
|
{
|
||||||
sw.Do(&m_command);
|
sw.Do(&m_command);
|
||||||
|
sw.DoEx(&m_command_second_response, 53, Command::None);
|
||||||
sw.Do(&m_drive_state);
|
sw.Do(&m_drive_state);
|
||||||
sw.Do(&m_status.bits);
|
sw.Do(&m_status.bits);
|
||||||
sw.Do(&m_secondary_status.bits);
|
sw.Do(&m_secondary_status.bits);
|
||||||
|
@ -276,19 +277,10 @@ void CDROM::InsertMedia(std::unique_ptr<CDImage> media)
|
||||||
|
|
||||||
// motor automatically spins up
|
// motor automatically spins up
|
||||||
if (m_drive_state != DriveState::ShellOpening)
|
if (m_drive_state != DriveState::ShellOpening)
|
||||||
{
|
StartMotor();
|
||||||
m_drive_state = DriveState::SpinningUp;
|
|
||||||
m_drive_event->Schedule(System::GetTicksPerSecond());
|
|
||||||
}
|
|
||||||
|
|
||||||
// reading TOC? interestingly this doesn't work for GetlocL though...
|
|
||||||
CDImage::SubChannelQ subq;
|
|
||||||
if (media->Seek(0) && media->ReadRawSector(nullptr, &subq) && subq.IsCRCValid())
|
|
||||||
m_last_subq = subq;
|
|
||||||
|
|
||||||
m_reader.SetMedia(std::move(media));
|
m_reader.SetMedia(std::move(media));
|
||||||
m_current_lba = 0;
|
SetHoldPosition(0, true);
|
||||||
ResetPhysicalPosition();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<CDImage> CDROM::RemoveMedia(bool force /* = false */)
|
std::unique_ptr<CDImage> CDROM::RemoveMedia(bool force /* = false */)
|
||||||
|
@ -309,10 +301,10 @@ std::unique_ptr<CDImage> CDROM::RemoveMedia(bool force /* = false */)
|
||||||
m_disc_region = DiscRegion::Other;
|
m_disc_region = DiscRegion::Other;
|
||||||
|
|
||||||
// If the drive was doing anything, we need to abort the command.
|
// If the drive was doing anything, we need to abort the command.
|
||||||
m_drive_state = DriveState::Idle;
|
ClearDriveState();
|
||||||
|
ClearCommandSecondResponse();
|
||||||
m_command = Command::None;
|
m_command = Command::None;
|
||||||
m_command_event->Deactivate();
|
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.
|
// The console sends an interrupt when the shell is opened regardless of whether a command was executing.
|
||||||
if (HasPendingAsyncInterrupt())
|
if (HasPendingAsyncInterrupt())
|
||||||
|
@ -675,6 +667,21 @@ TickCount CDROM::GetAckDelayForCommand(Command command)
|
||||||
return CanReadMedia() ? default_ack_delay_with_disc : default_ack_delay_no_disc;
|
return CanReadMedia() ? default_ack_delay_with_disc : default_ack_delay_no_disc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TickCount CDROM::GetTicksForSpinUp()
|
||||||
|
{
|
||||||
|
// 1 second
|
||||||
|
return System::GetTicksPerSecond();
|
||||||
|
}
|
||||||
|
|
||||||
|
TickCount CDROM::GetTicksForIDRead()
|
||||||
|
{
|
||||||
|
TickCount ticks = ID_READ_TICKS;
|
||||||
|
if (m_drive_state == DriveState::SpinningUp)
|
||||||
|
ticks += m_drive_event->GetTicksUntilNextExecution();
|
||||||
|
|
||||||
|
return ticks;
|
||||||
|
}
|
||||||
|
|
||||||
TickCount CDROM::GetTicksForRead()
|
TickCount CDROM::GetTicksForRead()
|
||||||
{
|
{
|
||||||
const TickCount tps = System::GetTicksPerSecond();
|
const TickCount tps = System::GetTicksPerSecond();
|
||||||
|
@ -705,12 +712,10 @@ TickCount CDROM::GetTicksForSeek(CDImage::LBA new_lba)
|
||||||
// Motor spin-up time.
|
// Motor spin-up time.
|
||||||
if (!m_secondary_status.motor_on)
|
if (!m_secondary_status.motor_on)
|
||||||
{
|
{
|
||||||
ticks += (m_drive_state == DriveState::SpinningUp) ? m_drive_event->GetTicksUntilNextExecution() : tps;
|
ticks +=
|
||||||
|
(m_drive_state == DriveState::SpinningUp) ? m_drive_event->GetTicksUntilNextExecution() : GetTicksForSpinUp();
|
||||||
if (m_drive_state == DriveState::ShellOpening || m_drive_state == DriveState::SpinningUp)
|
if (m_drive_state == DriveState::ShellOpening || m_drive_state == DriveState::SpinningUp)
|
||||||
{
|
ClearDriveState();
|
||||||
m_drive_state = DriveState::Idle;
|
|
||||||
m_drive_event->Deactivate();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lba_diff >= 2550)
|
if (lba_diff >= 2550)
|
||||||
|
@ -810,10 +815,11 @@ void CDROM::AbortCommand()
|
||||||
UpdateStatusRegister();
|
UpdateStatusRegister();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDROM::ExecuteCommand()
|
void CDROM::ExecuteCommand(TickCount ticks_late)
|
||||||
{
|
{
|
||||||
const CommandInfo& ci = s_command_info[static_cast<u8>(m_command)];
|
const CommandInfo& ci = s_command_info[static_cast<u8>(m_command)];
|
||||||
Log_DevPrintf("CDROM executing command 0x%02X (%s)", static_cast<u8>(m_command), ci.name);
|
Log_DevPrintf("CDROM executing command 0x%02X (%s), stat = 0x%02X", static_cast<u8>(m_command), ci.name,
|
||||||
|
m_secondary_status.bits);
|
||||||
if (m_param_fifo.GetSize() < ci.expected_parameters)
|
if (m_param_fifo.GetSize() < ci.expected_parameters)
|
||||||
{
|
{
|
||||||
Log_WarningPrintf("Too few parameters for command 0x%02X (%s), expecting %u got %u", static_cast<u8>(m_command),
|
Log_WarningPrintf("Too few parameters for command 0x%02X (%s), expecting %u got %u", static_cast<u8>(m_command),
|
||||||
|
@ -864,9 +870,7 @@ void CDROM::ExecuteCommand()
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SendACKAndStat();
|
SendACKAndStat();
|
||||||
|
QueueCommandSecondResponse(Command::GetID, GetTicksForIDRead());
|
||||||
m_drive_state = DriveState::ReadingID;
|
|
||||||
m_drive_event->Schedule(GetTicksForSeek(0) + GetTicksForRead());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EndCommand();
|
EndCommand();
|
||||||
|
@ -883,9 +887,8 @@ void CDROM::ExecuteCommand()
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SendACKAndStat();
|
SendACKAndStat();
|
||||||
|
SetHoldPosition(0, true);
|
||||||
m_drive_state = DriveState::ReadingTOC;
|
QueueCommandSecondResponse(Command::ReadTOC, System::GetTicksPerSecond() / 2); // half a second
|
||||||
m_drive_event->Schedule(System::GetTicksPerSecond() / 2); // half a second
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EndCommand();
|
EndCommand();
|
||||||
|
@ -1090,6 +1093,8 @@ void CDROM::ExecuteCommand()
|
||||||
|
|
||||||
case Command::Pause:
|
case Command::Pause:
|
||||||
{
|
{
|
||||||
|
SendACKAndStat();
|
||||||
|
|
||||||
const bool was_reading = (m_drive_state == DriveState::Reading || m_drive_state == DriveState::Playing);
|
const bool was_reading = (m_drive_state == DriveState::Reading || m_drive_state == DriveState::Playing);
|
||||||
const TickCount pause_time = was_reading ? (m_mode.double_speed ? 2000000 : 1000000) : 7000;
|
const TickCount pause_time = was_reading ? (m_mode.double_speed ? 2000000 : 1000000) : 7000;
|
||||||
|
|
||||||
|
@ -1099,20 +1104,22 @@ void CDROM::ExecuteCommand()
|
||||||
// hardware tests.
|
// hardware tests.
|
||||||
Log_WarningPrintf("CDROM Pause command while seeking from %u to %u - jumping to seek target", m_seek_start_lba,
|
Log_WarningPrintf("CDROM Pause command while seeking from %u to %u - jumping to seek target", m_seek_start_lba,
|
||||||
m_seek_end_lba);
|
m_seek_end_lba);
|
||||||
m_drive_event->Deactivate();
|
|
||||||
m_read_after_seek = false;
|
m_read_after_seek = false;
|
||||||
m_play_after_seek = false;
|
m_play_after_seek = false;
|
||||||
CompleteSeek();
|
CompleteSeek();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
Log_DebugPrintf("CDROM pause command");
|
{
|
||||||
SendACKAndStat();
|
// Stop reading.
|
||||||
|
m_drive_state = DriveState::Idle;
|
||||||
|
m_drive_event->Deactivate();
|
||||||
|
m_secondary_status.ClearActiveBits();
|
||||||
|
}
|
||||||
|
|
||||||
// Reset audio buffer here - control room cutscene audio repeats in Dino Crisis otherwise.
|
// Reset audio buffer here - control room cutscene audio repeats in Dino Crisis otherwise.
|
||||||
ResetAudioDecoder();
|
ResetAudioDecoder();
|
||||||
|
|
||||||
m_drive_state = DriveState::Pausing;
|
QueueCommandSecondResponse(Command::Pause, pause_time);
|
||||||
m_drive_event->Schedule(pause_time);
|
|
||||||
|
|
||||||
EndCommand();
|
EndCommand();
|
||||||
return;
|
return;
|
||||||
|
@ -1121,11 +1128,10 @@ void CDROM::ExecuteCommand()
|
||||||
case Command::Stop:
|
case Command::Stop:
|
||||||
{
|
{
|
||||||
const TickCount stop_time = GetTicksForStop(m_secondary_status.motor_on);
|
const TickCount stop_time = GetTicksForStop(m_secondary_status.motor_on);
|
||||||
Log_DebugPrintf("CDROM stop command");
|
|
||||||
SendACKAndStat();
|
SendACKAndStat();
|
||||||
|
|
||||||
m_drive_state = DriveState::Stopping;
|
StopMotor();
|
||||||
m_drive_event->Schedule(stop_time);
|
QueueCommandSecondResponse(Command::Stop, stop_time);
|
||||||
|
|
||||||
EndCommand();
|
EndCommand();
|
||||||
return;
|
return;
|
||||||
|
@ -1136,15 +1142,27 @@ void CDROM::ExecuteCommand()
|
||||||
Log_DebugPrintf("CDROM reset command");
|
Log_DebugPrintf("CDROM reset command");
|
||||||
SendACKAndStat();
|
SendACKAndStat();
|
||||||
|
|
||||||
|
if (m_command_second_response == Command::Reset)
|
||||||
|
{
|
||||||
|
// still pending
|
||||||
|
EndCommand();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (IsSeeking())
|
if (IsSeeking())
|
||||||
UpdatePositionWhileSeeking();
|
UpdatePositionWhileSeeking();
|
||||||
|
|
||||||
m_drive_state = DriveState::Resetting;
|
SoftReset();
|
||||||
m_drive_event->SetIntervalAndSchedule(BASE_RESET_TICKS + ((m_current_lba != 0) ? GetTicksForSeek(0) : 0));
|
|
||||||
m_seek_start_lba = m_current_lba;
|
|
||||||
m_seek_end_lba = 0;
|
|
||||||
|
|
||||||
EndCommand();
|
if (m_current_lba != 0)
|
||||||
|
{
|
||||||
|
m_drive_state = DriveState::SeekingImplicit;
|
||||||
|
m_drive_event->SetIntervalAndSchedule(((m_current_lba != 0) ? GetTicksForSeek(0) : 0));
|
||||||
|
m_seek_start_lba = m_current_lba;
|
||||||
|
m_seek_end_lba = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
QueueCommandSecondResponse(Command::Reset, RESET_TICKS);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1160,8 +1178,14 @@ void CDROM::ExecuteCommand()
|
||||||
{
|
{
|
||||||
SendACKAndStat();
|
SendACKAndStat();
|
||||||
|
|
||||||
m_drive_state = DriveState::Resetting;
|
// still pending?
|
||||||
m_drive_event->Schedule(System::GetTicksPerSecond());
|
if (m_command_second_response != Command::MotorOn)
|
||||||
|
{
|
||||||
|
if (CanReadMedia())
|
||||||
|
StartMotor();
|
||||||
|
|
||||||
|
QueueCommandSecondResponse(Command::MotorOn, MOTOR_ON_RESPONSE_TICKS);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EndCommand();
|
EndCommand();
|
||||||
|
@ -1427,6 +1451,40 @@ void CDROM::ExecuteTestCommand(u8 subcommand)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CDROM::ExecuteCommandSecondResponse(TickCount ticks_late)
|
||||||
|
{
|
||||||
|
switch (m_command_second_response)
|
||||||
|
{
|
||||||
|
case Command::GetID:
|
||||||
|
DoIDRead();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Command::ReadTOC:
|
||||||
|
case Command::Pause:
|
||||||
|
case Command::Reset:
|
||||||
|
case Command::MotorOn:
|
||||||
|
case Command::Stop:
|
||||||
|
DoStatSecondResponse();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_command_second_response = Command::None;
|
||||||
|
m_command_second_response_event->Deactivate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDROM::QueueCommandSecondResponse(Command command, TickCount ticks)
|
||||||
|
{
|
||||||
|
ClearCommandSecondResponse();
|
||||||
|
m_command_second_response = command;
|
||||||
|
m_command_second_response_event->Schedule(ticks);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDROM::ClearCommandSecondResponse()
|
||||||
|
{
|
||||||
|
m_command_second_response_event->Deactivate();
|
||||||
|
m_command_second_response = Command::None;
|
||||||
|
}
|
||||||
|
|
||||||
void CDROM::UpdateCommandEvent()
|
void CDROM::UpdateCommandEvent()
|
||||||
{
|
{
|
||||||
// if there's a pending interrupt, we can't execute the command yet
|
// if there's a pending interrupt, we can't execute the command yet
|
||||||
|
@ -1446,10 +1504,6 @@ void CDROM::ExecuteDrive(TickCount ticks_late)
|
||||||
{
|
{
|
||||||
switch (m_drive_state)
|
switch (m_drive_state)
|
||||||
{
|
{
|
||||||
case DriveState::Resetting:
|
|
||||||
DoResetComplete(ticks_late);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DriveState::ShellOpening:
|
case DriveState::ShellOpening:
|
||||||
DoShellOpenComplete(ticks_late);
|
DoShellOpenComplete(ticks_late);
|
||||||
break;
|
break;
|
||||||
|
@ -1459,20 +1513,8 @@ void CDROM::ExecuteDrive(TickCount ticks_late)
|
||||||
DoSeekComplete(ticks_late);
|
DoSeekComplete(ticks_late);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DriveState::Pausing:
|
case DriveState::SeekingImplicit:
|
||||||
DoPauseComplete();
|
CompleteSeek();
|
||||||
break;
|
|
||||||
|
|
||||||
case DriveState::Stopping:
|
|
||||||
DoStopComplete();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DriveState::ReadingID:
|
|
||||||
DoIDRead();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DriveState::ReadingTOC:
|
|
||||||
DoTOCRead();
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DriveState::Reading:
|
case DriveState::Reading:
|
||||||
|
@ -1488,12 +1530,50 @@ void CDROM::ExecuteDrive(TickCount ticks_late)
|
||||||
DoSpinUpComplete();
|
DoSpinUpComplete();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// old states, no longer used, but kept for save state compatibility
|
||||||
|
case DriveState::UNUSED_ReadingID:
|
||||||
|
{
|
||||||
|
ClearDriveState();
|
||||||
|
DoIDRead();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DriveState::UNUSED_Resetting:
|
||||||
|
case DriveState::UNUSED_ReadingTOC:
|
||||||
|
{
|
||||||
|
ClearDriveState();
|
||||||
|
DoStatSecondResponse();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DriveState::UNUSED_Pausing:
|
||||||
|
{
|
||||||
|
ClearDriveState();
|
||||||
|
m_secondary_status.ClearActiveBits();
|
||||||
|
DoStatSecondResponse();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DriveState::UNUSED_Stopping:
|
||||||
|
{
|
||||||
|
ClearDriveState();
|
||||||
|
StopMotor();
|
||||||
|
DoStatSecondResponse();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case DriveState::Idle:
|
case DriveState::Idle:
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CDROM::ClearDriveState()
|
||||||
|
{
|
||||||
|
m_drive_state = DriveState::Idle;
|
||||||
|
m_drive_event->Deactivate();
|
||||||
|
}
|
||||||
|
|
||||||
void CDROM::BeginReading(TickCount ticks_late /* = 0 */, bool after_seek /* = false */)
|
void CDROM::BeginReading(TickCount ticks_late /* = 0 */, bool after_seek /* = false */)
|
||||||
{
|
{
|
||||||
ClearSectorBuffers();
|
ClearSectorBuffers();
|
||||||
|
@ -1642,19 +1722,14 @@ void CDROM::UpdatePositionWhileSeeking()
|
||||||
|
|
||||||
// access the image directly since we want to preserve the cached data for the seek complete
|
// access the image directly since we want to preserve the cached data for the seek complete
|
||||||
CDImage::SubChannelQ subq;
|
CDImage::SubChannelQ subq;
|
||||||
if (m_reader.ReadSectorUncached(current_lba, &subq, nullptr) && subq.IsCRCValid())
|
if (!m_reader.ReadSectorUncached(current_lba, &subq, nullptr))
|
||||||
{
|
Log_ErrorPrintf("Failed to read subq for sector %u for physical position", current_lba);
|
||||||
|
else if (subq.IsCRCValid())
|
||||||
m_last_subq = subq;
|
m_last_subq = subq;
|
||||||
m_current_lba = current_lba;
|
|
||||||
ResetPhysicalPosition();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CDROM::ResetPhysicalPosition()
|
m_current_lba = current_lba;
|
||||||
{
|
m_physical_lba = current_lba;
|
||||||
const u32 ticks = TimingEvents::GetGlobalTickCounter();
|
m_physical_lba_update_tick = TimingEvents::GetGlobalTickCounter();
|
||||||
m_physical_lba = m_current_lba;
|
|
||||||
m_physical_lba_update_tick = ticks;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDROM::UpdatePhysicalPosition()
|
void CDROM::UpdatePhysicalPosition()
|
||||||
|
@ -1701,58 +1776,35 @@ void CDROM::UpdatePhysicalPosition()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CDROM::SetHoldPosition(CDImage::LBA lba, bool update_subq)
|
||||||
|
{
|
||||||
|
if (update_subq && m_physical_lba != lba && CanReadMedia())
|
||||||
|
{
|
||||||
|
CDImage::SubChannelQ subq;
|
||||||
|
if (!m_reader.ReadSectorUncached(lba, &subq, nullptr))
|
||||||
|
Log_ErrorPrintf("Failed to read subq for sector %u for physical position", lba);
|
||||||
|
else if (subq.IsCRCValid())
|
||||||
|
m_last_subq = subq;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_current_lba = lba;
|
||||||
|
m_physical_lba = lba;
|
||||||
|
m_physical_lba_update_tick = TimingEvents::GetGlobalTickCounter();
|
||||||
|
}
|
||||||
|
|
||||||
void CDROM::DoShellOpenComplete(TickCount ticks_late)
|
void CDROM::DoShellOpenComplete(TickCount ticks_late)
|
||||||
{
|
{
|
||||||
// media is now readable (if any)
|
// media is now readable (if any)
|
||||||
m_drive_state = DriveState::Idle;
|
ClearDriveState();
|
||||||
m_drive_event->Deactivate();
|
|
||||||
|
|
||||||
if (m_reader.HasMedia())
|
if (CanReadMedia())
|
||||||
{
|
StartMotor();
|
||||||
m_drive_state = DriveState::SpinningUp;
|
|
||||||
m_drive_event->Schedule(System::GetTicksPerSecond());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CDROM::DoResetComplete(TickCount ticks_late)
|
|
||||||
{
|
|
||||||
m_drive_state = DriveState::Idle;
|
|
||||||
m_drive_event->Deactivate();
|
|
||||||
|
|
||||||
m_secondary_status.bits = 0;
|
|
||||||
m_secondary_status.motor_on = CanReadMedia();
|
|
||||||
m_mode.bits = 0;
|
|
||||||
m_mode.read_raw_sector = true;
|
|
||||||
m_data_fifo.Clear();
|
|
||||||
|
|
||||||
if (!CanReadMedia())
|
|
||||||
{
|
|
||||||
Log_DevPrintf("CDROM reset - no disc");
|
|
||||||
m_secondary_status.shell_open = true;
|
|
||||||
SendAsyncErrorResponse(STAT_ERROR, 0x08);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_current_lba = 0;
|
|
||||||
ResetPhysicalPosition();
|
|
||||||
m_reader.QueueReadSector(0);
|
|
||||||
|
|
||||||
m_async_response_fifo.Clear();
|
|
||||||
m_async_response_fifo.Push(m_secondary_status.bits);
|
|
||||||
SetAsyncInterrupt(Interrupt::Complete);
|
|
||||||
|
|
||||||
if (!CanReadMedia())
|
|
||||||
{
|
|
||||||
m_secondary_status.motor_on = false;
|
|
||||||
m_secondary_status.shell_open = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CDROM::CompleteSeek()
|
bool CDROM::CompleteSeek()
|
||||||
{
|
{
|
||||||
const bool logical = (m_drive_state == DriveState::SeekingLogical);
|
const bool logical = (m_drive_state == DriveState::SeekingLogical);
|
||||||
m_drive_state = DriveState::Idle;
|
ClearDriveState();
|
||||||
m_drive_event->Deactivate();
|
|
||||||
m_secondary_status.ClearActiveBits();
|
m_secondary_status.ClearActiveBits();
|
||||||
|
|
||||||
bool seek_okay = m_reader.WaitForReadToComplete();
|
bool seek_okay = m_reader.WaitForReadToComplete();
|
||||||
|
@ -1803,7 +1855,8 @@ bool CDROM::CompleteSeek()
|
||||||
}
|
}
|
||||||
|
|
||||||
m_current_lba = m_reader.GetLastReadSector();
|
m_current_lba = m_reader.GetLastReadSector();
|
||||||
ResetPhysicalPosition();
|
m_physical_lba = m_current_lba;
|
||||||
|
m_physical_lba_update_tick = TimingEvents::GetGlobalTickCounter();
|
||||||
return seek_okay;
|
return seek_okay;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1844,25 +1897,14 @@ void CDROM::DoSeekComplete(TickCount ticks_late)
|
||||||
UpdateStatusRegister();
|
UpdateStatusRegister();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDROM::DoPauseComplete()
|
void CDROM::DoStatSecondResponse()
|
||||||
{
|
{
|
||||||
Log_DebugPrintf("Pause complete");
|
// Mainly for Reset/MotorOn.
|
||||||
m_drive_state = DriveState::Idle;
|
if (!CanReadMedia())
|
||||||
m_drive_event->Deactivate();
|
{
|
||||||
m_secondary_status.ClearActiveBits();
|
SendAsyncErrorResponse(STAT_ERROR, 0x08);
|
||||||
|
return;
|
||||||
m_async_response_fifo.Clear();
|
}
|
||||||
m_async_response_fifo.Push(m_secondary_status.bits);
|
|
||||||
SetAsyncInterrupt(Interrupt::Complete);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CDROM::DoStopComplete()
|
|
||||||
{
|
|
||||||
Log_DebugPrintf("Stop complete");
|
|
||||||
m_drive_state = DriveState::Idle;
|
|
||||||
m_drive_event->Deactivate();
|
|
||||||
m_secondary_status.ClearActiveBits();
|
|
||||||
m_secondary_status.motor_on = false;
|
|
||||||
|
|
||||||
m_async_response_fifo.Clear();
|
m_async_response_fifo.Clear();
|
||||||
m_async_response_fifo.Push(m_secondary_status.bits);
|
m_async_response_fifo.Push(m_secondary_status.bits);
|
||||||
|
@ -1872,8 +1914,7 @@ void CDROM::DoStopComplete()
|
||||||
void CDROM::DoChangeSessionComplete()
|
void CDROM::DoChangeSessionComplete()
|
||||||
{
|
{
|
||||||
Log_DebugPrintf("Changing session complete");
|
Log_DebugPrintf("Changing session complete");
|
||||||
m_drive_state = DriveState::Idle;
|
ClearDriveState();
|
||||||
m_drive_event->Deactivate();
|
|
||||||
m_secondary_status.ClearActiveBits();
|
m_secondary_status.ClearActiveBits();
|
||||||
m_secondary_status.motor_on = true;
|
m_secondary_status.motor_on = true;
|
||||||
|
|
||||||
|
@ -1902,8 +1943,6 @@ void CDROM::DoSpinUpComplete()
|
||||||
void CDROM::DoIDRead()
|
void CDROM::DoIDRead()
|
||||||
{
|
{
|
||||||
Log_DebugPrintf("ID read complete");
|
Log_DebugPrintf("ID read complete");
|
||||||
m_drive_state = DriveState::Idle;
|
|
||||||
m_drive_event->Deactivate();
|
|
||||||
m_secondary_status.ClearActiveBits();
|
m_secondary_status.ClearActiveBits();
|
||||||
m_secondary_status.motor_on = CanReadMedia();
|
m_secondary_status.motor_on = CanReadMedia();
|
||||||
|
|
||||||
|
@ -1917,11 +1956,6 @@ void CDROM::DoIDRead()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// this is where it would get read from the start of the disc?
|
|
||||||
m_current_lba = 0;
|
|
||||||
ResetPhysicalPosition();
|
|
||||||
m_reader.QueueReadSector(0);
|
|
||||||
|
|
||||||
if (!IsMediaPS1Disc())
|
if (!IsMediaPS1Disc())
|
||||||
{
|
{
|
||||||
stat_byte |= STAT_ID_ERROR;
|
stat_byte |= STAT_ID_ERROR;
|
||||||
|
@ -1948,17 +1982,6 @@ void CDROM::DoIDRead()
|
||||||
SetAsyncInterrupt((flags_byte != 0) ? Interrupt::Error : Interrupt::Complete);
|
SetAsyncInterrupt((flags_byte != 0) ? Interrupt::Error : Interrupt::Complete);
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CDROM::StopReadingWithDataEnd()
|
void CDROM::StopReadingWithDataEnd()
|
||||||
{
|
{
|
||||||
ClearAsyncInterrupt();
|
ClearAsyncInterrupt();
|
||||||
|
@ -1966,8 +1989,29 @@ void CDROM::StopReadingWithDataEnd()
|
||||||
SetAsyncInterrupt(Interrupt::DataEnd);
|
SetAsyncInterrupt(Interrupt::DataEnd);
|
||||||
|
|
||||||
m_secondary_status.ClearActiveBits();
|
m_secondary_status.ClearActiveBits();
|
||||||
m_drive_state = DriveState::Idle;
|
ClearDriveState();
|
||||||
m_drive_event->Deactivate();
|
}
|
||||||
|
|
||||||
|
void CDROM::StartMotor()
|
||||||
|
{
|
||||||
|
if (m_drive_state == DriveState::SpinningUp)
|
||||||
|
{
|
||||||
|
Log_DevPrintf("Starting motor - already spinning up");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log_DevPrintf("Starting motor");
|
||||||
|
m_drive_state = DriveState::SpinningUp;
|
||||||
|
m_drive_event->Schedule(GetTicksForSpinUp());
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDROM::StopMotor()
|
||||||
|
{
|
||||||
|
m_secondary_status.ClearActiveBits();
|
||||||
|
m_secondary_status.motor_on = false;
|
||||||
|
ClearDriveState();
|
||||||
|
SetHoldPosition(0, false);
|
||||||
|
m_last_sector_header_valid = false; // TODO: correct?
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDROM::DoSectorRead()
|
void CDROM::DoSectorRead()
|
||||||
|
@ -1978,7 +2022,8 @@ void CDROM::DoSectorRead()
|
||||||
Panic("Sector read failed");
|
Panic("Sector read failed");
|
||||||
|
|
||||||
m_current_lba = m_reader.GetLastReadSector();
|
m_current_lba = m_reader.GetLastReadSector();
|
||||||
ResetPhysicalPosition();
|
m_physical_lba = m_current_lba;
|
||||||
|
m_physical_lba_update_tick = TimingEvents::GetGlobalTickCounter();
|
||||||
|
|
||||||
const CDImage::SubChannelQ& subq = m_reader.GetSectorSubQ();
|
const CDImage::SubChannelQ& subq = m_reader.GetSectorSubQ();
|
||||||
const bool subq_valid = subq.IsCRCValid();
|
const bool subq_valid = subq.IsCRCValid();
|
||||||
|
@ -1997,7 +2042,7 @@ void CDROM::DoSectorRead()
|
||||||
{
|
{
|
||||||
Log_DevPrintf("Read reached lead-out area of disc at LBA %u, stopping", m_reader.GetLastReadSector());
|
Log_DevPrintf("Read reached lead-out area of disc at LBA %u, stopping", m_reader.GetLastReadSector());
|
||||||
StopReadingWithDataEnd();
|
StopReadingWithDataEnd();
|
||||||
m_secondary_status.motor_on = false;
|
StopMotor();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2013,7 +2058,7 @@ void CDROM::DoSectorRead()
|
||||||
else if (m_mode.auto_pause && subq.track_number_bcd != m_play_track_number_bcd)
|
else if (m_mode.auto_pause && subq.track_number_bcd != m_play_track_number_bcd)
|
||||||
{
|
{
|
||||||
// we don't want to update the position if the track changes, so we check it before reading the actual sector.
|
// we don't want to update the position if the track changes, so we check it before reading the actual sector.
|
||||||
Log_DevPrintf("Auto pause at the end of track %02x (LBA %u)", m_last_subq.track_number_bcd, m_current_lba);
|
Log_DevPrintf("Auto pause at the start of track %02x (LBA %u)", m_last_subq.track_number_bcd, m_current_lba);
|
||||||
StopReadingWithDataEnd();
|
StopReadingWithDataEnd();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2506,9 +2551,9 @@ void CDROM::DrawDebugWindow()
|
||||||
|
|
||||||
if (ImGui::CollapsingHeader("Status/Mode", ImGuiTreeNodeFlags_DefaultOpen))
|
if (ImGui::CollapsingHeader("Status/Mode", ImGuiTreeNodeFlags_DefaultOpen))
|
||||||
{
|
{
|
||||||
static constexpr std::array<const char*, 13> drive_state_names = {
|
static constexpr std::array<const char*, 14> drive_state_names = {
|
||||||
{"Idle", "Opening Shell", "Resetting", "Seeking (Physical)", "Seeking (Logical)", "Reading ID", "Reading TOC",
|
{"Idle", "Opening Shell", "Resetting", "Seeking (Physical)", "Seeking (Logical)", "Reading ID", "Reading TOC",
|
||||||
"Reading", "Playing", "Pausing", "Stopping", "Changing Session", "Spinning Up"}};
|
"Reading", "Playing", "Pausing", "Stopping", "Changing Session", "Spinning Up", "Seeking (Implicit)"}};
|
||||||
|
|
||||||
ImGui::Columns(3);
|
ImGui::Columns(3);
|
||||||
|
|
||||||
|
@ -2598,7 +2643,8 @@ void CDROM::DrawDebugWindow()
|
||||||
|
|
||||||
if (HasPendingCommand())
|
if (HasPendingCommand())
|
||||||
{
|
{
|
||||||
ImGui::TextColored(active_color, "Command: 0x%02X (%d ticks remaining)", static_cast<u8>(m_command),
|
ImGui::TextColored(active_color, "Command: %s (0x%02X) (%d ticks remaining)",
|
||||||
|
s_command_info[static_cast<u8>(m_command)].name, static_cast<u8>(m_command),
|
||||||
m_command_event->IsActive() ? m_command_event->GetTicksUntilNextExecution() : 0);
|
m_command_event->IsActive() ? m_command_event->GetTicksUntilNextExecution() : 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -78,7 +78,9 @@ private:
|
||||||
AUDIO_FIFO_SIZE = 44100 * 2,
|
AUDIO_FIFO_SIZE = 44100 * 2,
|
||||||
AUDIO_FIFO_LOW_WATERMARK = 10,
|
AUDIO_FIFO_LOW_WATERMARK = 10,
|
||||||
|
|
||||||
BASE_RESET_TICKS = 400000,
|
RESET_TICKS = 400000,
|
||||||
|
ID_READ_TICKS = 33868,
|
||||||
|
MOTOR_ON_RESPONSE_TICKS = 400000,
|
||||||
|
|
||||||
MAX_FAST_FORWARD_RATE = 12,
|
MAX_FAST_FORWARD_RATE = 12,
|
||||||
FAST_FORWARD_RATE_STEP = 4
|
FAST_FORWARD_RATE_STEP = 4
|
||||||
|
@ -137,17 +139,18 @@ private:
|
||||||
{
|
{
|
||||||
Idle,
|
Idle,
|
||||||
ShellOpening,
|
ShellOpening,
|
||||||
Resetting,
|
UNUSED_Resetting,
|
||||||
SeekingPhysical,
|
SeekingPhysical,
|
||||||
SeekingLogical,
|
SeekingLogical,
|
||||||
ReadingID,
|
UNUSED_ReadingID,
|
||||||
ReadingTOC,
|
UNUSED_ReadingTOC,
|
||||||
Reading,
|
Reading,
|
||||||
Playing,
|
Playing,
|
||||||
Pausing,
|
UNUSED_Pausing,
|
||||||
Stopping,
|
UNUSED_Stopping,
|
||||||
ChangingSession,
|
ChangingSession,
|
||||||
SpinningUp
|
SpinningUp,
|
||||||
|
SeekingImplicit
|
||||||
};
|
};
|
||||||
|
|
||||||
union StatusRegister
|
union StatusRegister
|
||||||
|
@ -222,10 +225,11 @@ private:
|
||||||
void SoftReset();
|
void SoftReset();
|
||||||
|
|
||||||
ALWAYS_INLINE bool IsDriveIdle() const { return m_drive_state == DriveState::Idle; }
|
ALWAYS_INLINE bool IsDriveIdle() const { return m_drive_state == DriveState::Idle; }
|
||||||
|
ALWAYS_INLINE bool IsMotorOn() const { return m_secondary_status.motor_on; }
|
||||||
ALWAYS_INLINE bool IsSeeking() const
|
ALWAYS_INLINE bool IsSeeking() const
|
||||||
{
|
{
|
||||||
return (m_drive_state == DriveState::SeekingLogical || m_drive_state == DriveState::SeekingPhysical ||
|
return (m_drive_state == DriveState::SeekingLogical || m_drive_state == DriveState::SeekingPhysical ||
|
||||||
m_drive_state == DriveState::Resetting);
|
m_drive_state == DriveState::SeekingImplicit);
|
||||||
}
|
}
|
||||||
ALWAYS_INLINE bool IsReadingOrPlaying() const
|
ALWAYS_INLINE bool IsReadingOrPlaying() const
|
||||||
{
|
{
|
||||||
|
@ -261,6 +265,8 @@ private:
|
||||||
bool HasPendingDiscEvent() const;
|
bool HasPendingDiscEvent() const;
|
||||||
|
|
||||||
TickCount GetAckDelayForCommand(Command command);
|
TickCount GetAckDelayForCommand(Command command);
|
||||||
|
TickCount GetTicksForSpinUp();
|
||||||
|
TickCount GetTicksForIDRead();
|
||||||
TickCount GetTicksForRead();
|
TickCount GetTicksForRead();
|
||||||
TickCount GetTicksForSeek(CDImage::LBA new_lba);
|
TickCount GetTicksForSeek(CDImage::LBA new_lba);
|
||||||
TickCount GetTicksForStop(bool motor_was_on);
|
TickCount GetTicksForStop(bool motor_was_on);
|
||||||
|
@ -270,31 +276,34 @@ private:
|
||||||
void BeginCommand(Command command); // also update status register
|
void BeginCommand(Command command); // also update status register
|
||||||
void EndCommand(); // also updates status register
|
void EndCommand(); // also updates status register
|
||||||
void AbortCommand();
|
void AbortCommand();
|
||||||
void ExecuteCommand();
|
void ExecuteCommand(TickCount ticks_late);
|
||||||
void ExecuteTestCommand(u8 subcommand);
|
void ExecuteTestCommand(u8 subcommand);
|
||||||
|
void ExecuteCommandSecondResponse(TickCount ticks_late);
|
||||||
|
void QueueCommandSecondResponse(Command command, TickCount ticks);
|
||||||
|
void ClearCommandSecondResponse();
|
||||||
void UpdateCommandEvent();
|
void UpdateCommandEvent();
|
||||||
void ExecuteDrive(TickCount ticks_late);
|
void ExecuteDrive(TickCount ticks_late);
|
||||||
|
void ClearDriveState();
|
||||||
void BeginReading(TickCount ticks_late = 0, bool after_seek = false);
|
void BeginReading(TickCount ticks_late = 0, bool after_seek = false);
|
||||||
void BeginPlaying(u8 track, TickCount ticks_late = 0, bool after_seek = false);
|
void BeginPlaying(u8 track, TickCount ticks_late = 0, bool after_seek = false);
|
||||||
void DoShellOpenComplete(TickCount ticks_late);
|
void DoShellOpenComplete(TickCount ticks_late);
|
||||||
void DoResetComplete(TickCount ticks_late);
|
|
||||||
void DoSeekComplete(TickCount ticks_late);
|
void DoSeekComplete(TickCount ticks_late);
|
||||||
void DoPauseComplete();
|
void DoStatSecondResponse();
|
||||||
void DoStopComplete();
|
|
||||||
void DoChangeSessionComplete();
|
void DoChangeSessionComplete();
|
||||||
void DoSpinUpComplete();
|
void DoSpinUpComplete();
|
||||||
void DoIDRead();
|
void DoIDRead();
|
||||||
void DoTOCRead();
|
|
||||||
void DoSectorRead();
|
void DoSectorRead();
|
||||||
void ProcessDataSectorHeader(const u8* raw_sector);
|
void ProcessDataSectorHeader(const u8* raw_sector);
|
||||||
void ProcessDataSector(const u8* raw_sector, const CDImage::SubChannelQ& subq);
|
void ProcessDataSector(const u8* raw_sector, const CDImage::SubChannelQ& subq);
|
||||||
void ProcessXAADPCMSector(const u8* raw_sector, const CDImage::SubChannelQ& subq);
|
void ProcessXAADPCMSector(const u8* raw_sector, const CDImage::SubChannelQ& subq);
|
||||||
void ProcessCDDASector(const u8* raw_sector, const CDImage::SubChannelQ& subq);
|
void ProcessCDDASector(const u8* raw_sector, const CDImage::SubChannelQ& subq);
|
||||||
void StopReadingWithDataEnd();
|
void StopReadingWithDataEnd();
|
||||||
|
void StartMotor();
|
||||||
|
void StopMotor();
|
||||||
void BeginSeeking(bool logical, bool read_after_seek, bool play_after_seek);
|
void BeginSeeking(bool logical, bool read_after_seek, bool play_after_seek);
|
||||||
void UpdatePositionWhileSeeking();
|
void UpdatePositionWhileSeeking();
|
||||||
void ResetPhysicalPosition();
|
|
||||||
void UpdatePhysicalPosition();
|
void UpdatePhysicalPosition();
|
||||||
|
void SetHoldPosition(CDImage::LBA lba, bool update_subq);
|
||||||
void ResetCurrentXAFile();
|
void ResetCurrentXAFile();
|
||||||
void ResetAudioDecoder();
|
void ResetAudioDecoder();
|
||||||
void LoadDataFIFO();
|
void LoadDataFIFO();
|
||||||
|
@ -304,9 +313,11 @@ private:
|
||||||
void ResampleXAADPCM(const s16* frames_in, u32 num_frames_in);
|
void ResampleXAADPCM(const s16* frames_in, u32 num_frames_in);
|
||||||
|
|
||||||
std::unique_ptr<TimingEvent> m_command_event;
|
std::unique_ptr<TimingEvent> m_command_event;
|
||||||
|
std::unique_ptr<TimingEvent> m_command_second_response_event;
|
||||||
std::unique_ptr<TimingEvent> m_drive_event;
|
std::unique_ptr<TimingEvent> m_drive_event;
|
||||||
|
|
||||||
Command m_command = Command::None;
|
Command m_command = Command::None;
|
||||||
|
Command m_command_second_response = Command::None;
|
||||||
DriveState m_drive_state = DriveState::Idle;
|
DriveState m_drive_state = DriveState::Idle;
|
||||||
DiscRegion m_disc_region = DiscRegion::Other;
|
DiscRegion m_disc_region = DiscRegion::Other;
|
||||||
|
|
||||||
|
@ -320,10 +331,10 @@ private:
|
||||||
u8 m_pending_async_interrupt = 0;
|
u8 m_pending_async_interrupt = 0;
|
||||||
|
|
||||||
CDImage::Position m_setloc_position = {};
|
CDImage::Position m_setloc_position = {};
|
||||||
CDImage::LBA m_current_lba{};
|
CDImage::LBA m_current_lba{}; // this is the hold position
|
||||||
CDImage::LBA m_seek_start_lba{};
|
CDImage::LBA m_seek_start_lba{};
|
||||||
CDImage::LBA m_seek_end_lba{};
|
CDImage::LBA m_seek_end_lba{};
|
||||||
CDImage::LBA m_physical_lba{};
|
CDImage::LBA m_physical_lba{}; // current position of the disc with respect to time
|
||||||
u32 m_physical_lba_update_tick = 0;
|
u32 m_physical_lba_update_tick = 0;
|
||||||
bool m_setloc_pending = false;
|
bool m_setloc_pending = false;
|
||||||
bool m_read_after_seek = false;
|
bool m_read_after_seek = false;
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
static constexpr u32 SAVE_STATE_MAGIC = 0x43435544;
|
static constexpr u32 SAVE_STATE_MAGIC = 0x43435544;
|
||||||
static constexpr u32 SAVE_STATE_VERSION = 52;
|
static constexpr u32 SAVE_STATE_VERSION = 53;
|
||||||
static constexpr u32 SAVE_STATE_MINIMUM_VERSION = 42;
|
static constexpr u32 SAVE_STATE_MINIMUM_VERSION = 42;
|
||||||
|
|
||||||
static_assert(SAVE_STATE_VERSION >= SAVE_STATE_MINIMUM_VERSION);
|
static_assert(SAVE_STATE_VERSION >= SAVE_STATE_MINIMUM_VERSION);
|
||||||
|
|
Loading…
Reference in a new issue