CDROM: Detection of XA audio sectors

This commit is contained in:
Connor McLaughlin 2019-09-30 20:01:41 +10:00
parent 8b4ec87055
commit 40dceacc7c
4 changed files with 118 additions and 38 deletions

View file

@ -123,7 +123,7 @@ u8 CDROM::ReadRegister(u32 offset)
switch (offset)
{
case 0: // status register
Log_DebugPrintf("CDROM read status register <- 0x%08X", m_status.bits);
Log_TracePrintf("CDROM read status register <- 0x%08X", m_status.bits);
return m_status.bits;
case 1: // always response FIFO
@ -184,7 +184,7 @@ void CDROM::WriteRegister(u32 offset, u8 value)
{
case 0:
{
Log_DebugPrintf("CDROM status register <- 0x%02X", ZeroExtend32(value));
Log_TracePrintf("CDROM status register <- 0x%02X", ZeroExtend32(value));
m_status.bits = (m_status.bits & static_cast<u8>(~3)) | (value & u8(3));
return;
}
@ -277,16 +277,7 @@ void CDROM::WriteRegister(u32 offset, u8 value)
Assert(!rr.SMEN);
if (rr.BFRD)
{
// any data to load?
if (m_sector_buffer.empty())
{
Log_DevPrintf("Attempting to load empty sector buffer");
return;
}
Log_DebugPrintf("Loading data FIFO");
m_data_fifo.PushRange(m_sector_buffer.data(), static_cast<u32>(m_sector_buffer.size()));
m_sector_buffer.clear();
LoadDataFIFO();
}
else
{
@ -361,7 +352,7 @@ u32 CDROM::DMARead()
m_data_fifo.Clear();
}
// Log_DebugPrintf("DMA Read -> 0x%08X", data);
// Log_DebugPrintf("DMA Read -> 0x%08X (%u remaining)", data, m_data_fifo.GetSize());
return data;
}
@ -755,19 +746,44 @@ void CDROM::DoSectorRead()
// return;
}
Log_DevPrintf("Reading sector %llu", m_media->GetCurrentLBA());
// TODO: Error handling
// TODO: Sector buffer should be two sectors?
Assert(!m_mode.ignore_bit);
const u32 size =
m_mode.read_raw_sector ? (CDImage::RAW_SECTOR_SIZE - CDImage::SECTOR_SYNC_SIZE) : CDImage::DATA_SECTOR_SIZE;
m_sector_buffer.resize(size);
m_media->Read(m_mode.read_raw_sector ? CDImage::ReadMode::RawNoSync : CDImage::ReadMode::DataOnly, 1,
m_sector_buffer.data());
m_response_fifo.Push(m_secondary_status.bits);
SetInterrupt(Interrupt::INT1);
UpdateStatusRegister();
m_sector_buffer.resize(CDImage::RAW_SECTOR_SIZE);
m_media->Read(CDImage::ReadMode::RawSector, 1, m_sector_buffer.data());
Log_DevPrintf("Read sector %llu: mode %u submode 0x%02X", m_media->GetCurrentLBA(), ZeroExtend32(m_sector_buffer[15]),
ZeroExtend32(m_sector_buffer[18]));
bool pass_to_cpu = true;
if (m_mode.xa_enable)
{
const CDSectorHeader* sh =
reinterpret_cast<const CDSectorHeader*>(m_sector_buffer.data() + CDImage::SECTOR_SYNC_SIZE);
if (sh->sector_mode == 2)
{
const XASubHeader* xsh = reinterpret_cast<const XASubHeader*>(m_sector_buffer.data() + CDImage::SECTOR_SYNC_SIZE +
sizeof(CDSectorHeader));
if (xsh->submode.realtime && xsh->submode.audio)
{
// TODO: Decode audio sector. Do we still transfer this to the CPU?
Log_WarningPrintf("Decode CD-XA audio sector");
m_sector_buffer.clear();
pass_to_cpu = false;
}
if (xsh->submode.eof)
{
Log_WarningPrintf("End of CD-XA file");
}
}
}
if (pass_to_cpu)
{
m_response_fifo.Push(m_secondary_status.bits);
SetInterrupt(Interrupt::INT1);
UpdateStatusRegister();
}
m_sector_read_remaining_ticks += GetTicksForRead();
m_system->SetDowncount(m_sector_read_remaining_ticks);
@ -782,3 +798,26 @@ void CDROM::StopReading()
m_secondary_status.reading = false;
m_reading = false;
}
void CDROM::LoadDataFIFO()
{
// any data to load?
if (m_sector_buffer.empty())
{
Log_DevPrintf("Attempting to load empty sector buffer");
return;
}
if (m_mode.read_raw_sector)
{
m_data_fifo.PushRange(m_sector_buffer.data() + CDImage::SECTOR_SYNC_SIZE,
CDImage::RAW_SECTOR_SIZE - CDImage::SECTOR_SYNC_SIZE);
}
else
{
m_data_fifo.PushRange(m_sector_buffer.data() + CDImage::SECTOR_SYNC_SIZE + 12, CDImage::DATA_SECTOR_SIZE);
}
Log_DebugPrintf("Loaded %u bytes to data FIFO", m_data_fifo.GetSize());
m_sector_buffer.clear();
}

View file

@ -134,7 +134,7 @@ private:
BitField<u8, bool, 3, 1> xa_filter;
BitField<u8, bool, 4, 1> ignore_bit;
BitField<u8, bool, 5, 1> read_raw_sector;
BitField<u8, bool, 6, 1> xa_adpcm;
BitField<u8, bool, 6, 1> xa_enable;
BitField<u8, bool, 7, 1> double_speed;
};
@ -146,6 +146,41 @@ private:
BitField<u8, bool, 7, 1> BFRD;
};
struct CDSectorHeader
{
u8 minute;
u8 second;
u8 frame;
u8 sector_mode;
};
struct XASubHeader
{
u8 file_number;
u8 channel_number;
union Submode
{
u8 bits;
BitField<u8, bool, 0, 1> eor;
BitField<u8, bool, 1, 1> video;
BitField<u8, bool, 2, 1> audio;
BitField<u8, bool, 3, 1> data;
BitField<u8, bool, 4, 1> trigger;
BitField<u8, bool, 5, 1> form2;
BitField<u8, bool, 6, 1> realtime;
BitField<u8, bool, 7, 1> eof;
} submode;
union Codinginfo
{
u8 bits;
BitField<u8, u8, 0, 2> mono_stereo;
BitField<u8, u8, 2, 2> sample_rate;
BitField<u8, u8, 4, 2> bits_per_sample;
BitField<u8, bool, 6, 1> emphasis;
} codinginfo;
};
bool HasPendingInterrupt() const { return m_interrupt_flag_register != 0; }
void SetInterrupt(Interrupt interrupt);
void PushStatResponse(Interrupt interrupt = Interrupt::ACK);
@ -161,6 +196,7 @@ private:
void BeginReading();
void DoSectorRead();
void StopReading();
void LoadDataFIFO();
System* m_system = nullptr;
DMA* m_dma = nullptr;

View file

@ -92,12 +92,12 @@ void DMA::WriteRegister(u32 offset, u32 value)
case 0x00:
{
state.base_address = value & ADDRESS_MASK;
Log_DebugPrintf("DMA channel %u base address <- 0x%08X", channel_index, state.base_address);
Log_TracePrintf("DMA channel %u base address <- 0x%08X", channel_index, state.base_address);
return;
}
case 0x04:
{
Log_DebugPrintf("DMA channel %u block control <- 0x%08X", channel_index, value);
Log_TracePrintf("DMA channel %u block control <- 0x%08X", channel_index, value);
state.block_control.bits = value;
return;
}
@ -106,7 +106,7 @@ void DMA::WriteRegister(u32 offset, u32 value)
{
state.channel_control.bits = (state.channel_control.bits & ~ChannelState::ChannelControl::WRITE_MASK) |
(value & ChannelState::ChannelControl::WRITE_MASK);
Log_DebugPrintf("DMA channel %u channel control <- 0x%08X", channel_index, state.channel_control.bits);
Log_TracePrintf("DMA channel %u channel control <- 0x%08X", channel_index, state.channel_control.bits);
if (CanRunChannel(static_cast<Channel>(channel_index)))
UpdateTransferPending();
@ -123,14 +123,14 @@ void DMA::WriteRegister(u32 offset, u32 value)
{
case 0x70:
{
Log_DebugPrintf("DPCR <- 0x%08X", value);
Log_TracePrintf("DPCR <- 0x%08X", value);
m_DPCR.bits = value;
return;
}
case 0x74:
{
Log_DebugPrintf("DCIR <- 0x%08X", value);
Log_TracePrintf("DCIR <- 0x%08X", value);
m_DICR.bits = (m_DICR.bits & ~DICR_WRITE_MASK) | (value & DICR_WRITE_MASK);
m_DICR.bits = (m_DICR.bits & ~DICR_RESET_MASK) & (value ^ DICR_RESET_MASK);
m_DICR.UpdateMasterFlag();
@ -214,7 +214,6 @@ void DMA::RunDMA(Channel channel)
{
ChannelState& cs = m_state[static_cast<u32>(channel)];
const bool copy_to_device = cs.channel_control.copy_to_device;
Log_DebugPrintf("Running DMA for channel %u", static_cast<u32>(channel));
// start/trigger bit is cleared on beginning of transfer
cs.channel_control.start_trigger = false;
@ -226,7 +225,8 @@ void DMA::RunDMA(Channel channel)
case SyncMode::Manual:
{
const u32 word_count = cs.block_control.manual.GetWordCount();
Log_DebugPrintf(" ... copying %u words %s 0x%08X", word_count, copy_to_device ? "from" : "to", current_address);
Log_DebugPrintf("DMA%u: Copying %u words %s 0x%08X", static_cast<u32>(channel), word_count,
copy_to_device ? "from" : "to", current_address);
if (copy_to_device)
{
u32 words_remaining = word_count;
@ -265,6 +265,9 @@ void DMA::RunDMA(Channel channel)
}
else
{
Log_DebugPrintf("DMA%u: Copying linked list starting at 0x%08X to device", static_cast<u32>(channel),
current_address);
for (;;)
{
u32 header;
@ -303,8 +306,8 @@ void DMA::RunDMA(Channel channel)
{
const u32 block_size = cs.block_control.request.GetBlockSize();
const u32 block_count = cs.block_control.request.GetBlockCount();
Log_DebugPrintf(" ... copying %u blocks of size %u %s 0x%08X", block_count, block_size,
copy_to_device ? "from" : "to", current_address);
Log_DebugPrintf("DMA%u: Copying %u blocks of size %u %s 0x%08X", static_cast<u32>(channel), block_count,
block_size, copy_to_device ? "from" : "to", current_address);
if (copy_to_device)
{
u32 words_remaining = block_size * block_count;
@ -344,12 +347,12 @@ void DMA::RunDMA(Channel channel)
cs.channel_control.enable_busy = false;
if (m_DICR.IsIRQEnabled(channel))
{
Log_DebugPrintf("Set DMA interrupt for channel %u", static_cast<u32>(channel));
Log_TracePrintf("Set DMA interrupt for channel %u", static_cast<u32>(channel));
m_DICR.SetIRQFlag(channel);
m_DICR.UpdateMasterFlag();
if (m_DICR.master_flag)
{
Log_DebugPrintf("Firing DMA interrupt");
Log_TracePrintf("Firing DMA interrupt");
m_interrupt_controller->InterruptRequest(InterruptController::IRQ::DMA);
}
}

View file

@ -229,8 +229,9 @@ void MDEC::HandleDecodeMacroblockCommand()
{
while (src != src_end)
{
u32 old_offs = static_cast<u32>(src - temp.data());
src = DecodeColoredMacroblock(src, src_end);
Log_InfoPrint("Decoded colour macroblock");
Log_InfoPrintf("Decoded colour macroblock, ptr was %u, now %u", old_offs, static_cast<u32>(src - temp.data()));
}
}
}
@ -464,7 +465,8 @@ void MDEC::IDCT(s16* blk)
for (u32 u = 0; u < 8; u++)
sum += s64(temp_buffer[u + y * 8]) * s32(m_scale_table[u * 8 + x]);
blk[x + y * 8] = static_cast<s16>(std::clamp<s32>(SignExtendN<9, s32>((sum >> 32) + ((sum >> 31) & 1)), -128, 127));
blk[x + y * 8] =
static_cast<s16>(std::clamp<s32>(SignExtendN<9, s32>((sum >> 32) + ((sum >> 31) & 1)), -128, 127));
}
}
}
@ -494,7 +496,7 @@ void MDEC::yuv_to_rgb(u32 xx, u32 yy, const std::array<s16, 64>& Crblk, const st
rgb_out[(x + xx) + ((y + yy) * 16)] = ZeroExtend32(static_cast<u16>(R)) |
(ZeroExtend32(static_cast<u16>(G)) << 8) |
(ZeroExtend32(static_cast<u16>(B)) << 16);
(ZeroExtend32(static_cast<u16>(B)) << 16) | UINT32_C(0xFF000000);
}
}
}