testing
This commit is contained in:
parent
571a773b29
commit
c883779595
|
@ -704,9 +704,6 @@ void CDROM::DeliverAsyncInterrupt()
|
||||||
Assert(m_pending_async_interrupt != 0 && !HasPendingInterrupt());
|
Assert(m_pending_async_interrupt != 0 && !HasPendingInterrupt());
|
||||||
Log_DebugPrintf("Delivering async interrupt %u", m_pending_async_interrupt);
|
Log_DebugPrintf("Delivering async interrupt %u", m_pending_async_interrupt);
|
||||||
|
|
||||||
if (m_pending_async_interrupt == static_cast<u8>(Interrupt::DataReady))
|
|
||||||
m_current_read_sector_buffer = m_current_write_sector_buffer;
|
|
||||||
|
|
||||||
m_response_fifo.Clear();
|
m_response_fifo.Clear();
|
||||||
m_response_fifo.PushFromQueue(&m_async_response_fifo);
|
m_response_fifo.PushFromQueue(&m_async_response_fifo);
|
||||||
m_interrupt_flag_register = m_pending_async_interrupt;
|
m_interrupt_flag_register = m_pending_async_interrupt;
|
||||||
|
@ -1812,8 +1809,11 @@ void CDROM::BeginReading(TickCount ticks_late /* = 0 */, bool after_seek /* = fa
|
||||||
m_drive_state = DriveState::Reading;
|
m_drive_state = DriveState::Reading;
|
||||||
m_drive_event->SetInterval(ticks);
|
m_drive_event->SetInterval(ticks);
|
||||||
m_drive_event->Schedule(first_sector_ticks);
|
m_drive_event->Schedule(first_sector_ticks);
|
||||||
m_current_read_sector_buffer = 0;
|
m_current_read_sector_buffer = NUM_SECTOR_BUFFERS - 1;
|
||||||
m_current_write_sector_buffer = 0;
|
m_current_write_sector_buffer = 0;
|
||||||
|
m_deliver_sector_buffer = 0;
|
||||||
|
m_buffered_sector_count = 0;
|
||||||
|
m_buffered_sectors_remaining = NUM_SECTORS_TO_BUFFER;
|
||||||
|
|
||||||
m_requested_lba = m_current_lba;
|
m_requested_lba = m_current_lba;
|
||||||
m_reader.QueueReadSector(m_requested_lba);
|
m_reader.QueueReadSector(m_requested_lba);
|
||||||
|
@ -1855,8 +1855,11 @@ void CDROM::BeginPlaying(u8 track, TickCount ticks_late /* = 0 */, bool after_se
|
||||||
m_drive_state = DriveState::Playing;
|
m_drive_state = DriveState::Playing;
|
||||||
m_drive_event->SetInterval(ticks);
|
m_drive_event->SetInterval(ticks);
|
||||||
m_drive_event->Schedule(first_sector_ticks);
|
m_drive_event->Schedule(first_sector_ticks);
|
||||||
m_current_read_sector_buffer = 0;
|
m_current_read_sector_buffer = NUM_SECTOR_BUFFERS - 1;
|
||||||
m_current_write_sector_buffer = 0;
|
m_current_write_sector_buffer = 0;
|
||||||
|
m_deliver_sector_buffer = 0;
|
||||||
|
m_buffered_sector_count = 0;
|
||||||
|
m_buffered_sectors_remaining = NUM_SECTORS_TO_BUFFER;
|
||||||
|
|
||||||
m_requested_lba = m_current_lba;
|
m_requested_lba = m_current_lba;
|
||||||
m_reader.QueueReadSector(m_requested_lba);
|
m_reader.QueueReadSector(m_requested_lba);
|
||||||
|
@ -2066,9 +2069,9 @@ bool CDROM::CompleteSeek()
|
||||||
{
|
{
|
||||||
if (logical)
|
if (logical)
|
||||||
{
|
{
|
||||||
ProcessDataSectorHeader(m_reader.GetSectorBuffer().data());
|
const CDImage::SectorHeader* header =
|
||||||
seek_okay = (m_last_sector_header.minute == seek_mm && m_last_sector_header.second == seek_ss &&
|
reinterpret_cast<const CDImage::SectorHeader*>(m_reader.GetSectorBuffer().data() + SECTOR_SYNC_SIZE);
|
||||||
m_last_sector_header.frame == seek_ff);
|
seek_okay = (header->minute == seek_mm && header->second == seek_ss && header->frame == seek_ff);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -2320,15 +2323,11 @@ void CDROM::DoSectorRead()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
ProcessDataSectorHeader(m_reader.GetSectorBuffer().data());
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 next_sector = m_current_lba + 1u;
|
u32 next_sector = m_current_lba + 1u;
|
||||||
if (is_data_sector && m_drive_state == DriveState::Reading)
|
if (is_data_sector && m_drive_state == DriveState::Reading)
|
||||||
{
|
{
|
||||||
ProcessDataSector(m_reader.GetSectorBuffer().data(), subq);
|
EnqueueDataSector(m_reader.GetSectorBuffer().data());
|
||||||
}
|
}
|
||||||
else if (!is_data_sector &&
|
else if (!is_data_sector &&
|
||||||
(m_drive_state == DriveState::Playing || (m_drive_state == DriveState::Reading && m_mode.cdda)))
|
(m_drive_state == DriveState::Playing || (m_drive_state == DriveState::Reading && m_mode.cdda)))
|
||||||
|
@ -2348,6 +2347,8 @@ void CDROM::DoSectorRead()
|
||||||
is_data_sector ? "data" : "audio", is_data_sector ? "reading" : "playing");
|
is_data_sector ? "data" : "audio", is_data_sector ? "reading" : "playing");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ProcessDataSector();
|
||||||
|
|
||||||
m_requested_lba = next_sector;
|
m_requested_lba = next_sector;
|
||||||
m_reader.QueueReadSector(m_requested_lba);
|
m_reader.QueueReadSector(m_requested_lba);
|
||||||
}
|
}
|
||||||
|
@ -2355,59 +2356,87 @@ void CDROM::DoSectorRead()
|
||||||
void CDROM::ProcessDataSectorHeader(const u8* raw_sector)
|
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_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)],
|
std::memcpy(&m_last_sector_subheader, &raw_sector[SECTOR_SYNC_SIZE + sizeof(m_last_sector_header)], sizeof(m_last_sector_subheader));
|
||||||
sizeof(m_last_sector_subheader));
|
|
||||||
m_last_sector_header_valid = true;
|
m_last_sector_header_valid = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDROM::ProcessDataSector(const u8* raw_sector, const CDImage::SubChannelQ& subq)
|
void CDROM::EnqueueDataSector(const u8* raw_sector)
|
||||||
{
|
{
|
||||||
const u32 sb_num = (m_current_write_sector_buffer + 1) % NUM_SECTOR_BUFFERS;
|
const CDImage::SectorHeader* header =
|
||||||
Log_DevPrintf("Read sector %u: mode %u submode 0x%02X into buffer %u", m_current_lba,
|
reinterpret_cast<const CDImage::SectorHeader*>(m_reader.GetSectorBuffer().data() + SECTOR_SYNC_SIZE);
|
||||||
ZeroExtend32(m_last_sector_header.sector_mode), ZeroExtend32(m_last_sector_subheader.submode.bits),
|
const CDXA::XASubHeader* subheader = reinterpret_cast<const CDXA::XASubHeader*>(
|
||||||
sb_num);
|
m_reader.GetSectorBuffer().data() + SECTOR_SYNC_SIZE + sizeof(CDImage::SectorHeader));
|
||||||
|
if (header->sector_mode != 2)
|
||||||
if (m_mode.xa_enable && m_last_sector_header.sector_mode == 2)
|
|
||||||
{
|
|
||||||
if (m_last_sector_subheader.submode.realtime && m_last_sector_subheader.submode.audio)
|
|
||||||
{
|
|
||||||
ProcessXAADPCMSector(raw_sector, subq);
|
|
||||||
|
|
||||||
// Audio+realtime sectors aren't delivered to the CPU.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: How does XA relate to this buffering?
|
|
||||||
SectorBuffer* sb = &m_sector_buffers[sb_num];
|
|
||||||
if (sb->size > 0)
|
|
||||||
{
|
|
||||||
Log_DevPrintf("Sector buffer %u was not read, previous sector dropped",
|
|
||||||
(m_current_write_sector_buffer - 1) % NUM_SECTOR_BUFFERS);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_mode.ignore_bit)
|
|
||||||
Log_WarningPrintf("SetMode.4 bit set on read of sector %u", m_current_lba);
|
|
||||||
|
|
||||||
if (m_mode.read_raw_sector)
|
|
||||||
{
|
|
||||||
std::memcpy(sb->data.data(), raw_sector + SECTOR_SYNC_SIZE, RAW_SECTOR_OUTPUT_SIZE);
|
|
||||||
sb->size = RAW_SECTOR_OUTPUT_SIZE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// TODO: This should actually depend on the mode...
|
|
||||||
if (m_last_sector_header.sector_mode != 2)
|
|
||||||
{
|
{
|
||||||
Log_WarningPrintf("Ignoring non-mode2 sector at %u", m_current_lba);
|
Log_WarningPrintf("Ignoring non-mode2 sector at %u", m_current_lba);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::memcpy(sb->data.data(), raw_sector + CDImage::SECTOR_SYNC_SIZE + 12, DATA_SECTOR_OUTPUT_SIZE);
|
if (m_mode.ignore_bit)
|
||||||
sb->size = DATA_SECTOR_OUTPUT_SIZE;
|
Log_WarningPrintf("SetMode.4 bit set on read of sector %u", m_current_lba);
|
||||||
|
|
||||||
|
const u32 sb_num = m_current_write_sector_buffer;
|
||||||
|
m_current_write_sector_buffer = (m_current_write_sector_buffer + 1) % NUM_SECTOR_BUFFERS;
|
||||||
|
|
||||||
|
Log_DevPrintf("Enqueue data sector %u: %02X:%02X:%02X mode %u submode 0x%02X into buffer %u", m_current_lba,
|
||||||
|
ZeroExtend32(header->minute), ZeroExtend32(header->second), ZeroExtend32(header->frame),
|
||||||
|
ZeroExtend32(header->sector_mode), ZeroExtend32(subheader->submode.bits), sb_num);
|
||||||
|
|
||||||
|
SectorBuffer* sb = &m_sector_buffers[sb_num];
|
||||||
|
if (sb->size > 0)
|
||||||
|
Log_DevPrintf("Sector buffer %u was not read, previous sector dropped", m_current_write_sector_buffer);
|
||||||
|
|
||||||
|
std::memcpy(sb->data.data(), raw_sector, CDImage::RAW_SECTOR_SIZE);
|
||||||
|
sb->size = CDImage::RAW_SECTOR_SIZE;
|
||||||
|
|
||||||
|
m_buffered_sector_count++;
|
||||||
|
Log_DevPrintf("[%u] %u sectors buffered...", m_current_lba, m_buffered_sector_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_current_write_sector_buffer = sb_num;
|
void CDROM::ProcessDataSector()
|
||||||
|
{
|
||||||
|
// Wait until we have at least two sectors buffered before we process any.
|
||||||
|
// This simulates the delay between subq and data present on the hardware, where it's doing ECC and other processing.
|
||||||
|
if (m_buffered_sectors_remaining > 0 && (m_buffered_sectors_remaining--) > 0)
|
||||||
|
{
|
||||||
|
Log_DebugPrintf("Only %u sectors buffered, waiting...", m_buffered_sector_count);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Anything to process?
|
||||||
|
if (m_buffered_sector_count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Add a delay for the next sector if we're not full
|
||||||
|
m_buffered_sector_count--;
|
||||||
|
if (m_buffered_sector_count < NUM_SECTORS_TO_BUFFER)
|
||||||
|
m_buffered_sectors_remaining++;
|
||||||
|
|
||||||
|
m_current_read_sector_buffer = (m_current_read_sector_buffer + 1) % NUM_SECTOR_BUFFERS;
|
||||||
|
const u32 sb_num = m_current_read_sector_buffer;
|
||||||
|
|
||||||
|
SectorBuffer* sb = &m_sector_buffers[sb_num];
|
||||||
|
if (sb->size == 0)
|
||||||
|
{
|
||||||
|
Log_WarningPrintf("Empty sector buffer %u?!", sb_num);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read out and store header (for GetLocL).
|
||||||
|
ProcessDataSectorHeader(sb->data.data());
|
||||||
|
|
||||||
|
// Non-mode 2 sectors aren't buffered.
|
||||||
|
if (m_mode.xa_enable /*&& m_last_sector_header.sector_mode == 2*/)
|
||||||
|
{
|
||||||
|
if (m_last_sector_subheader.submode.realtime && m_last_sector_subheader.submode.audio)
|
||||||
|
{
|
||||||
|
ProcessXAADPCMSector(sb->data.data());
|
||||||
|
|
||||||
|
// Audio+realtime sectors aren't delivered to the CPU.
|
||||||
|
sb->size = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Deliver to CPU
|
// Deliver to CPU
|
||||||
if (HasPendingAsyncInterrupt())
|
if (HasPendingAsyncInterrupt())
|
||||||
|
@ -2418,14 +2447,21 @@ void CDROM::ProcessDataSector(const u8* raw_sector, const CDImage::SubChannelQ&
|
||||||
|
|
||||||
if (HasPendingInterrupt())
|
if (HasPendingInterrupt())
|
||||||
{
|
{
|
||||||
const u32 sectors_missed = (m_current_write_sector_buffer - m_current_read_sector_buffer) % NUM_SECTOR_BUFFERS;
|
const u32 sectors_missed = (sb_num - m_deliver_sector_buffer) % NUM_SECTOR_BUFFERS;
|
||||||
if (sectors_missed > 1)
|
if (sectors_missed > 1)
|
||||||
Log_WarningPrintf("Interrupt not processed in time, missed %u sectors", sectors_missed - 1);
|
Log_WarningPrintf("Interrupt not processed in time, missed %u sectors", sectors_missed - 1);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// This sector is now ready for delivery.
|
||||||
|
Log_DevPrintf("Deliver sector %02X:%02X:%02X to CPU", ZeroExtend32(m_last_sector_header.minute),
|
||||||
|
ZeroExtend32(m_last_sector_header.second), ZeroExtend32(m_last_sector_header.frame));
|
||||||
|
m_deliver_sector_buffer = sb_num;
|
||||||
|
|
||||||
m_async_response_fifo.Push(m_secondary_status.bits);
|
m_async_response_fifo.Push(m_secondary_status.bits);
|
||||||
SetAsyncInterrupt(Interrupt::DataReady);
|
SetAsyncInterrupt(Interrupt::DataReady);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static std::array<std::array<s16, 29>, 7> s_zigzag_table = {
|
static std::array<std::array<s16, 29>, 7> s_zigzag_table = {
|
||||||
{{0, 0x0, 0x0, 0x0, 0x0, -0x0002, 0x000A, -0x0022, 0x0041, -0x0054,
|
{{0, 0x0, 0x0, 0x0, 0x0, -0x0002, 0x000A, -0x0022, 0x0041, -0x0054,
|
||||||
|
@ -2531,7 +2567,7 @@ void CDROM::ResetAudioDecoder()
|
||||||
m_audio_fifo.Clear();
|
m_audio_fifo.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDROM::ProcessXAADPCMSector(const u8* raw_sector, const CDImage::SubChannelQ& subq)
|
void CDROM::ProcessXAADPCMSector(const u8* raw_sector)
|
||||||
{
|
{
|
||||||
// Check for automatic ADPCM filter.
|
// Check for automatic ADPCM filter.
|
||||||
if (m_mode.xa_filter && (m_last_sector_subheader.file_number != m_xa_filter_file_number ||
|
if (m_mode.xa_filter && (m_last_sector_subheader.file_number != m_xa_filter_file_number ||
|
||||||
|
@ -2719,24 +2755,31 @@ void CDROM::LoadDataFIFO()
|
||||||
}
|
}
|
||||||
|
|
||||||
// any data to load?
|
// any data to load?
|
||||||
SectorBuffer& sb = m_sector_buffers[m_current_read_sector_buffer];
|
SectorBuffer& sb = m_sector_buffers[m_deliver_sector_buffer];
|
||||||
if (sb.size == 0)
|
if (sb.size == 0)
|
||||||
{
|
{
|
||||||
Log_WarningPrintf("Attempting to load empty sector buffer");
|
Log_WarningPrintf("Attempting to load empty sector buffer");
|
||||||
m_data_fifo.PushRange(sb.data.data(), RAW_SECTOR_OUTPUT_SIZE);
|
m_data_fifo.PushRange(sb.data.data() + SECTOR_SYNC_SIZE, RAW_SECTOR_OUTPUT_SIZE);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_data_fifo.PushRange(sb.data.data(), sb.size);
|
if (m_mode.read_raw_sector)
|
||||||
|
m_data_fifo.PushRange(sb.data.data() + SECTOR_SYNC_SIZE, RAW_SECTOR_OUTPUT_SIZE);
|
||||||
|
else
|
||||||
|
m_data_fifo.PushRange(sb.data.data() + SECTOR_SYNC_SIZE + 12, DATA_SECTOR_OUTPUT_SIZE);
|
||||||
sb.size = 0;
|
sb.size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Log_DebugPrintf("Loaded %u bytes to data FIFO from buffer %u", m_data_fifo.GetSize(), m_current_read_sector_buffer);
|
const CDImage::SectorHeader* header = reinterpret_cast<const CDImage::SectorHeader*>(sb.data.data() + SECTOR_SYNC_SIZE);
|
||||||
|
Log_DevPrintf("Loaded %u bytes to data FIFO from buffer %u [%02X:%02X:%02X]", m_data_fifo.GetSize(),
|
||||||
|
m_deliver_sector_buffer, header->minute, header->second, header->frame);
|
||||||
|
|
||||||
SectorBuffer& next_sb = m_sector_buffers[m_current_write_sector_buffer];
|
// FIXME
|
||||||
|
SectorBuffer& next_sb = m_sector_buffers[m_current_read_sector_buffer];
|
||||||
if (next_sb.size > 0)
|
if (next_sb.size > 0)
|
||||||
{
|
{
|
||||||
Log_DevPrintf("Sending additional INT1 for missed sector in buffer %u", m_current_write_sector_buffer);
|
Log_DevPrintf("Sending additional INT1 for missed sector in buffer %u", m_current_read_sector_buffer);
|
||||||
|
m_deliver_sector_buffer = m_current_read_sector_buffer;
|
||||||
m_async_response_fifo.Push(m_secondary_status.bits);
|
m_async_response_fifo.Push(m_secondary_status.bits);
|
||||||
SetAsyncInterrupt(Interrupt::DataReady);
|
SetAsyncInterrupt(Interrupt::DataReady);
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,7 +87,9 @@ private:
|
||||||
MOTOR_ON_RESPONSE_TICKS = 400000,
|
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,
|
||||||
|
|
||||||
|
NUM_SECTORS_TO_BUFFER = 2
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr u8 INTERRUPT_REGISTER_MASK = 0x1F;
|
static constexpr u8 INTERRUPT_REGISTER_MASK = 0x1F;
|
||||||
|
@ -314,9 +316,10 @@ private:
|
||||||
void DoSpeedChangeOrImplicitTOCReadComplete();
|
void DoSpeedChangeOrImplicitTOCReadComplete();
|
||||||
void DoIDRead();
|
void DoIDRead();
|
||||||
void DoSectorRead();
|
void DoSectorRead();
|
||||||
|
void EnqueueDataSector(const u8* raw_sector);
|
||||||
|
void ProcessDataSector();
|
||||||
void ProcessDataSectorHeader(const u8* raw_sector);
|
void ProcessDataSectorHeader(const u8* raw_sector);
|
||||||
void ProcessDataSector(const u8* raw_sector, const CDImage::SubChannelQ& subq);
|
void ProcessXAADPCMSector(const u8* raw_sector);
|
||||||
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 StartMotor();
|
||||||
|
@ -395,12 +398,15 @@ private:
|
||||||
|
|
||||||
struct SectorBuffer
|
struct SectorBuffer
|
||||||
{
|
{
|
||||||
HeapArray<u8, RAW_SECTOR_OUTPUT_SIZE> data;
|
HeapArray<u8, CDImage::RAW_SECTOR_SIZE> data;
|
||||||
u32 size;
|
u32 size;
|
||||||
};
|
};
|
||||||
|
|
||||||
u32 m_current_read_sector_buffer = 0;
|
u32 m_current_read_sector_buffer = 0;
|
||||||
u32 m_current_write_sector_buffer = 0;
|
u32 m_current_write_sector_buffer = 0;
|
||||||
|
u32 m_deliver_sector_buffer = 0;
|
||||||
|
u32 m_buffered_sector_count = 0;
|
||||||
|
u32 m_buffered_sectors_remaining = 0;
|
||||||
std::array<SectorBuffer, NUM_SECTOR_BUFFERS> m_sector_buffers;
|
std::array<SectorBuffer, NUM_SECTOR_BUFFERS> m_sector_buffers;
|
||||||
|
|
||||||
CDROMAsyncReader m_reader;
|
CDROMAsyncReader m_reader;
|
||||||
|
|
Loading…
Reference in New Issue