CDROM: Properly handle audio sectors in SeekL

This commit is contained in:
Connor McLaughlin 2019-11-16 12:54:41 +10:00
parent f12b97e98b
commit d6209937fb
2 changed files with 57 additions and 23 deletions

View file

@ -549,7 +549,8 @@ void CDROM::Execute(TickCount ticks)
DoSpinUpComplete();
break;
case DriveState::Seeking:
case DriveState::SeekingPhysical:
case DriveState::SeekingLogical:
DoSeekComplete();
break;
@ -717,8 +718,8 @@ void CDROM::ExecuteCommand()
case Command::SeekL:
case Command::SeekP:
{
// TODO: Data vs audio mode
Log_DebugPrintf("CDROM seek command");
const bool logical = (m_command == Command::SeekL);
Log_DebugPrintf("CDROM %s command", logical ? "SeekL" : "SeekP");
if (!m_media)
{
SendErrorResponse(0x80);
@ -726,7 +727,7 @@ void CDROM::ExecuteCommand()
else
{
SendACKAndStat();
BeginSeeking(false, false);
BeginSeeking(logical, false, false);
}
EndCommand();
@ -1022,7 +1023,7 @@ void CDROM::BeginReading()
Log_DebugPrintf("Starting reading");
if (m_setloc_pending)
{
BeginSeeking(true, false);
BeginSeeking(true, true, false);
return;
}
@ -1059,7 +1060,7 @@ void CDROM::BeginPlaying(u8 track_bcd)
if (m_setloc_pending)
{
BeginSeeking(false, true);
BeginSeeking(false, false, true);
return;
}
@ -1074,7 +1075,7 @@ void CDROM::BeginPlaying(u8 track_bcd)
m_system->SetDowncount(m_drive_remaining_ticks);
}
void CDROM::BeginSeeking(bool read_after_seek, bool play_after_seek)
void CDROM::BeginSeeking(bool logical, bool read_after_seek, bool play_after_seek)
{
if (!m_setloc_pending)
Log_WarningPrintf("Seeking without setloc set");
@ -1084,7 +1085,8 @@ void CDROM::BeginSeeking(bool read_after_seek, bool play_after_seek)
m_play_after_seek = play_after_seek;
m_setloc_pending = false;
Log_DebugPrintf("Seeking to [%02u:%02u:%02u]", m_seek_position.minute, m_seek_position.second, m_seek_position.frame);
Log_DebugPrintf("Seeking to [%02u:%02u:%02u] (%s)", m_seek_position.minute, m_seek_position.second,
m_seek_position.frame, logical ? "logical" : "physical");
const TickCount seek_time = GetTicksForSeek();
@ -1092,7 +1094,7 @@ void CDROM::BeginSeeking(bool read_after_seek, bool play_after_seek)
m_secondary_status.motor_on = true;
m_sector_buffer.clear();
m_drive_state = DriveState::Seeking;
m_drive_state = logical ? DriveState::SeekingLogical : DriveState::SeekingPhysical;
m_drive_remaining_ticks = seek_time;
m_system->SetDowncount(m_drive_remaining_ticks);
}
@ -1110,12 +1112,38 @@ void CDROM::DoSpinUpComplete()
void CDROM::DoSeekComplete()
{
const bool logical = (m_drive_state == DriveState::SeekingLogical);
m_drive_state = DriveState::Idle;
m_secondary_status.ClearActiveBits();
m_sector_buffer.clear();
// seek and update sub-q for ReadP command
if (m_media && m_media->Seek(m_seek_position) && m_media->ReadSubChannelQ(&m_last_subq))
// TODO: Check SubQ checksum
CDImage::SubChannelQ subq;
bool seek_okay = (m_media && m_media->Seek(m_seek_position) && m_media->ReadSubChannelQ(&subq));
if (seek_okay)
{
m_last_subq = subq;
// check for data header for logical seeks
if (logical)
{
u8 raw_sector[CDImage::RAW_SECTOR_SIZE];
seek_okay &= m_media->ReadRawSector(raw_sector);
seek_okay &= m_media->Seek(m_media->GetPositionOnDisc() - 1);
if (seek_okay)
{
ProcessDataSectorHeader(raw_sector);
// ensure the location matches up (it should)
const auto [seek_mm, seek_ss, seek_ff] = m_seek_position.ToBCD();
seek_okay = (m_last_sector_header.minute == seek_mm && m_last_sector_header.second == seek_ss &&
m_last_sector_header.frame == seek_ff);
}
}
}
if (seek_okay)
{
// seek complete, transition to play/read if requested
// INT2 is not sent on play/read
@ -1135,8 +1163,8 @@ void CDROM::DoSeekComplete()
}
else
{
Log_WarningPrintf("Seek to [%02u:%02u:%02u] failed", m_seek_position.minute, m_seek_position.second,
m_seek_position.frame);
Log_WarningPrintf("%s seek to [%02u:%02u:%02u] failed", logical ? "Logical" : "Physical", m_seek_position.minute,
m_seek_position.second, m_seek_position.frame);
m_secondary_status.seek_error = true;
SendAsyncErrorResponse(0x80);
}
@ -1201,6 +1229,7 @@ void CDROM::DoTOCRead()
void CDROM::DoSectorRead()
{
// TODO: Error handling
// TODO: Check SubQ checksum.
CDImage::SubChannelQ subq;
if (!m_media->ReadSubChannelQ(&subq))
Panic("SubChannel Q read failed");
@ -1235,6 +1264,8 @@ void CDROM::DoSectorRead()
if (!m_media->ReadRawSector(raw_sector))
Panic("Sector read failed");
m_last_subq = subq;
if (is_data_sector && m_drive_state == DriveState::Reading)
{
ProcessDataSector(raw_sector, subq);
@ -1257,16 +1288,18 @@ void CDROM::DoSectorRead()
m_system->SetDowncount(m_drive_remaining_ticks);
}
void CDROM::ProcessDataSector(const u8* raw_sector, const CDImage::SubChannelQ& subq)
void CDROM::ProcessDataSectorHeader(const u8* raw_sector)
{
std::memcpy(&m_last_sector_header, &raw_sector[SECTOR_SYNC_SIZE], sizeof(m_last_sector_header));
std::memcpy(&m_last_sector_subheader, &raw_sector[SECTOR_SYNC_SIZE + sizeof(m_last_sector_header)],
sizeof(m_last_sector_subheader));
// TODO: Check SubQ checksum.
m_last_subq = subq;
m_secondary_status.header_valid = true;
}
void CDROM::ProcessDataSector(const u8* raw_sector, const CDImage::SubChannelQ& subq)
{
ProcessDataSectorHeader(raw_sector);
Log_DevPrintf("Read sector %u: mode %u submode 0x%02X", m_media->GetPositionOnDisc() - 1,
ZeroExtend32(m_last_sector_header.sector_mode), ZeroExtend32(m_last_sector_subheader.submode.bits));
@ -1493,8 +1526,6 @@ void CDROM::ProcessCDDASector(const u8* raw_sector, const CDImage::SubChannelQ&
}
}
m_last_subq = subq;
// Apply volume when pushing sectors to SPU.
if (m_muted)
return;
@ -1571,8 +1602,9 @@ void CDROM::DrawDebugWindow()
if (ImGui::CollapsingHeader("Status/Mode", ImGuiTreeNodeFlags_DefaultOpen))
{
static constexpr std::array<const char*, 9> drive_state_names = {
{"Idle", "Spinning Up", "Seeking", "Reading ID", "Reading TOC", "Reading", "Playing", "Pausing", "Stopping"}};
static constexpr std::array<const char*, 10> drive_state_names = {{"Idle", "Spinning Up", "Seeking (Physical)",
"Seeking (Logical)", "Reading ID", "Reading TOC",
"Reading", "Playing", "Pausing", "Stopping"}};
ImGui::Columns(3);
@ -1634,7 +1666,7 @@ void CDROM::DrawDebugWindow()
ImGui::TextColored(m_status.BUSYSTS ? active_color : inactive_color, "BUSYSTS: %s",
m_status.BUSYSTS ? "Yes" : "No");
ImGui::NextColumn();
ImGui::TextColored(m_secondary_status.header_valid ? active_color : inactive_color, "Reading: %s",
ImGui::TextColored(m_secondary_status.header_valid ? active_color : inactive_color, "Header Valid: %s",
m_secondary_status.header_valid ? "Yes" : "No");
ImGui::NextColumn();
ImGui::TextColored(m_mode.read_raw_sector ? active_color : inactive_color, "Read Raw Sectors: %s",

View file

@ -110,7 +110,8 @@ private:
{
Idle,
SpinningUp,
Seeking,
SeekingPhysical,
SeekingLogical,
ReadingID,
ReadingTOC,
Reading,
@ -205,10 +206,11 @@ private:
void DoIDRead();
void DoTOCRead();
void DoSectorRead();
void ProcessDataSectorHeader(const u8* raw_sector);
void ProcessDataSector(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 BeginSeeking(bool read_after_seek, bool play_after_seek);
void BeginSeeking(bool logical, bool read_after_seek, bool play_after_seek);
void LoadDataFIFO();
System* m_system = nullptr;