CDROM: Implement SetSession command
This commit is contained in:
parent
d0f420de10
commit
c700913322
|
@ -112,6 +112,7 @@ bool CDROM::DoState(StateWrapper& sw)
|
|||
sw.DoBytes(&m_last_subq, sizeof(m_last_subq));
|
||||
sw.Do(&m_last_cdda_report_frame_nibble);
|
||||
sw.Do(&m_play_track_number_bcd);
|
||||
sw.Do(&m_async_command_parameter);
|
||||
sw.Do(&m_cd_audio_volume_matrix);
|
||||
sw.Do(&m_next_cd_audio_volume_matrix);
|
||||
sw.Do(&m_xa_last_samples);
|
||||
|
@ -464,14 +465,14 @@ void CDROM::SendErrorResponse(u8 reason /*= 0x80*/)
|
|||
{
|
||||
m_response_fifo.Push(m_secondary_status.bits | 0x01);
|
||||
m_response_fifo.Push(reason);
|
||||
SetInterrupt(Interrupt::INT5);
|
||||
SetInterrupt(Interrupt::Error);
|
||||
}
|
||||
|
||||
void CDROM::SendAsyncErrorResponse(u8 reason /*= 0x80*/)
|
||||
{
|
||||
m_async_response_fifo.Push(m_secondary_status.bits | 0x01);
|
||||
m_async_response_fifo.Push(reason);
|
||||
SetAsyncInterrupt(Interrupt::INT5);
|
||||
SetAsyncInterrupt(Interrupt::Error);
|
||||
}
|
||||
|
||||
void CDROM::UpdateStatusRegister()
|
||||
|
@ -674,6 +675,32 @@ void CDROM::ExecuteCommand()
|
|||
return;
|
||||
}
|
||||
|
||||
case Command::SetSession:
|
||||
{
|
||||
const u8 session = m_param_fifo.IsEmpty() ? 0 : m_param_fifo.Peek(0);
|
||||
Log_DebugPrintf("CDROM SetSession command, session=%u", session);
|
||||
|
||||
if (!HasMedia() || m_drive_state == DriveState::Reading || m_drive_state == DriveState::Playing)
|
||||
{
|
||||
SendErrorResponse(0x80);
|
||||
}
|
||||
else if (session == 0)
|
||||
{
|
||||
SendErrorResponse(0x10);
|
||||
}
|
||||
else
|
||||
{
|
||||
SendACKAndStat();
|
||||
|
||||
m_async_command_parameter = session;
|
||||
m_drive_state = DriveState::ChangingSession;
|
||||
m_drive_event->Schedule(MASTER_CLOCK / 2); // half a second
|
||||
}
|
||||
|
||||
EndCommand();
|
||||
return;
|
||||
}
|
||||
|
||||
case Command::ReadN:
|
||||
case Command::ReadS:
|
||||
{
|
||||
|
@ -1011,6 +1038,10 @@ void CDROM::ExecuteDrive(TickCount ticks_late)
|
|||
DoSectorRead();
|
||||
break;
|
||||
|
||||
case DriveState::ChangingSession:
|
||||
DoChangeSessionComplete();
|
||||
break;
|
||||
|
||||
case DriveState::Idle:
|
||||
default:
|
||||
break;
|
||||
|
@ -1114,7 +1145,7 @@ void CDROM::DoSpinUpComplete()
|
|||
|
||||
m_async_response_fifo.Clear();
|
||||
m_async_response_fifo.Push(m_secondary_status.bits);
|
||||
SetAsyncInterrupt(Interrupt::INT2);
|
||||
SetAsyncInterrupt(Interrupt::Complete);
|
||||
}
|
||||
|
||||
void CDROM::DoSeekComplete(TickCount ticks_late)
|
||||
|
@ -1164,7 +1195,7 @@ void CDROM::DoSeekComplete(TickCount ticks_late)
|
|||
else
|
||||
{
|
||||
m_async_response_fifo.Push(m_secondary_status.bits);
|
||||
SetAsyncInterrupt(Interrupt::INT2);
|
||||
SetAsyncInterrupt(Interrupt::Complete);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -1192,7 +1223,7 @@ void CDROM::DoPauseComplete()
|
|||
|
||||
m_async_response_fifo.Clear();
|
||||
m_async_response_fifo.Push(m_secondary_status.bits);
|
||||
SetAsyncInterrupt(Interrupt::INT2);
|
||||
SetAsyncInterrupt(Interrupt::Complete);
|
||||
}
|
||||
|
||||
void CDROM::DoStopComplete()
|
||||
|
@ -1208,7 +1239,29 @@ void CDROM::DoStopComplete()
|
|||
|
||||
m_async_response_fifo.Clear();
|
||||
m_async_response_fifo.Push(m_secondary_status.bits);
|
||||
SetAsyncInterrupt(Interrupt::INT2);
|
||||
SetAsyncInterrupt(Interrupt::Complete);
|
||||
}
|
||||
|
||||
void CDROM::DoChangeSessionComplete()
|
||||
{
|
||||
Log_DebugPrintf("Changing session complete");
|
||||
m_drive_state = DriveState::Idle;
|
||||
m_drive_event->Deactivate();
|
||||
m_secondary_status.ClearActiveBits();
|
||||
m_secondary_status.motor_on = true;
|
||||
|
||||
m_async_response_fifo.Clear();
|
||||
if (m_async_command_parameter == 0x01)
|
||||
{
|
||||
m_async_response_fifo.Push(m_secondary_status.bits);
|
||||
SetAsyncInterrupt(Interrupt::Complete);
|
||||
}
|
||||
else
|
||||
{
|
||||
// we don't emulate multisession discs.. for now
|
||||
m_secondary_status.seek_error = true;
|
||||
SendAsyncErrorResponse(0x40);
|
||||
}
|
||||
}
|
||||
|
||||
void CDROM::DoIDRead()
|
||||
|
@ -1226,7 +1279,7 @@ void CDROM::DoIDRead()
|
|||
m_async_response_fifo.Clear();
|
||||
m_async_response_fifo.Push(m_secondary_status.bits);
|
||||
m_async_response_fifo.PushRange(response2, countof(response2));
|
||||
SetAsyncInterrupt(Interrupt::INT2);
|
||||
SetAsyncInterrupt(Interrupt::Complete);
|
||||
}
|
||||
|
||||
void CDROM::DoTOCRead()
|
||||
|
@ -1236,7 +1289,7 @@ void CDROM::DoTOCRead()
|
|||
m_drive_event->Deactivate();
|
||||
m_async_response_fifo.Clear();
|
||||
m_async_response_fifo.Push(m_secondary_status.bits);
|
||||
SetAsyncInterrupt(Interrupt::INT2);
|
||||
SetAsyncInterrupt(Interrupt::Complete);
|
||||
}
|
||||
|
||||
void CDROM::DoSectorRead()
|
||||
|
@ -1265,7 +1318,7 @@ void CDROM::DoSectorRead()
|
|||
|
||||
ClearAsyncInterrupt();
|
||||
m_async_response_fifo.Push(m_secondary_status.bits);
|
||||
SetAsyncInterrupt(Interrupt::INT4);
|
||||
SetAsyncInterrupt(Interrupt::DataEnd);
|
||||
|
||||
m_secondary_status.ClearActiveBits();
|
||||
m_drive_state = DriveState::Idle;
|
||||
|
@ -1375,7 +1428,7 @@ void CDROM::ProcessDataSector(const u8* raw_sector, const CDImage::SubChannelQ&
|
|||
}
|
||||
|
||||
m_async_response_fifo.Push(m_secondary_status.bits);
|
||||
SetAsyncInterrupt(Interrupt::INT1);
|
||||
SetAsyncInterrupt(Interrupt::DataReady);
|
||||
}
|
||||
|
||||
static std::array<std::array<s16, 29>, 7> s_zigzag_table = {
|
||||
|
@ -1550,7 +1603,7 @@ void CDROM::ProcessCDDASector(const u8* raw_sector, const CDImage::SubChannelQ&
|
|||
|
||||
m_async_response_fifo.Push(0); // peak low
|
||||
m_async_response_fifo.Push(0); // peak high
|
||||
SetAsyncInterrupt(Interrupt::INT1);
|
||||
SetAsyncInterrupt(Interrupt::DataReady);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1632,9 +1685,9 @@ void CDROM::DrawDebugWindow()
|
|||
|
||||
if (ImGui::CollapsingHeader("Status/Mode", ImGuiTreeNodeFlags_DefaultOpen))
|
||||
{
|
||||
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"}};
|
||||
static constexpr std::array<const char*, 11> drive_state_names = {
|
||||
{"Idle", "Spinning Up", "Seeking (Physical)", "Seeking (Logical)", "Reading ID", "Reading TOC", "Reading",
|
||||
"Playing", "Pausing", "Stopping", "Changing Session"}};
|
||||
|
||||
ImGui::Columns(3);
|
||||
|
||||
|
|
|
@ -64,11 +64,11 @@ private:
|
|||
|
||||
enum class Interrupt : u8
|
||||
{
|
||||
INT1 = 0x01,
|
||||
INT2 = 0x02,
|
||||
DataReady = 0x01,
|
||||
Complete = 0x02,
|
||||
ACK = 0x03,
|
||||
INT4 = 0x04,
|
||||
INT5 = 0x05
|
||||
DataEnd = 0x04,
|
||||
Error = 0x05
|
||||
};
|
||||
|
||||
enum class Command : u16
|
||||
|
@ -120,7 +120,8 @@ private:
|
|||
Reading,
|
||||
Playing,
|
||||
Pausing,
|
||||
Stopping
|
||||
Stopping,
|
||||
ChangingSession
|
||||
};
|
||||
|
||||
union StatusRegister
|
||||
|
@ -208,6 +209,7 @@ private:
|
|||
void DoSeekComplete(TickCount ticks_late);
|
||||
void DoPauseComplete();
|
||||
void DoStopComplete();
|
||||
void DoChangeSessionComplete();
|
||||
void DoIDRead();
|
||||
void DoTOCRead();
|
||||
void DoSectorRead();
|
||||
|
@ -253,6 +255,7 @@ private:
|
|||
CDImage::SubChannelQ m_last_subq{};
|
||||
u8 m_last_cdda_report_frame_nibble = 0xFF;
|
||||
u8 m_play_track_number_bcd = 0xFF;
|
||||
u8 m_async_command_parameter = 0x00;
|
||||
|
||||
std::array<std::array<u8, 2>, 2> m_cd_audio_volume_matrix{};
|
||||
std::array<std::array<u8, 2>, 2> m_next_cd_audio_volume_matrix{};
|
||||
|
|
|
@ -2,4 +2,4 @@
|
|||
#include "types.h"
|
||||
|
||||
static constexpr u32 SAVE_STATE_MAGIC = 0x43435544;
|
||||
static constexpr u32 SAVE_STATE_VERSION = 3;
|
||||
static constexpr u32 SAVE_STATE_VERSION = 4;
|
||||
|
|
Loading…
Reference in New Issue