CDROM: Implement GetlocP/GetlocL commands

This commit is contained in:
Connor McLaughlin 2019-10-04 19:05:19 +10:00
parent bbe1fc062f
commit 0b46a8cfc4
3 changed files with 98 additions and 62 deletions

View file

@ -1,4 +1,5 @@
#pragma once #pragma once
#include "bitfield.h"
#include "types.h" #include "types.h"
class ByteStream; class ByteStream;
@ -14,6 +15,8 @@ public:
RAW_SECTOR_SIZE = 2352, RAW_SECTOR_SIZE = 2352,
DATA_SECTOR_SIZE = 2048, DATA_SECTOR_SIZE = 2048,
SECTOR_SYNC_SIZE = 12, SECTOR_SYNC_SIZE = 12,
SECTOR_HEADER_SIZE = 4,
SECTOR_XA_SUBHEADER_SIZE = 4,
FRAMES_PER_SECOND = 75, // "sectors" FRAMES_PER_SECOND = 75, // "sectors"
SECONDS_PER_MINUTE = 60, SECONDS_PER_MINUTE = 60,
FRAMES_PER_MINUTE = FRAMES_PER_SECOND * SECONDS_PER_MINUTE, FRAMES_PER_MINUTE = FRAMES_PER_SECOND * SECONDS_PER_MINUTE,
@ -21,9 +24,44 @@ public:
enum class ReadMode : u32 enum class ReadMode : u32
{ {
DataOnly, // 2048 bytes per sector. DataOnly, // 2048 bytes per sector.
RawSector, // 2352 bytes per sector. RawSector, // 2352 bytes per sector.
RawNoSync, // 2340 bytes per sector. RawNoSync, // 2340 bytes per sector.
};
struct SectorHeader
{
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;
}; };
// Conversion helpers. // Conversion helpers.

View file

@ -683,6 +683,33 @@ void CDROM::ExecuteCommand()
} }
break; break;
case Command::GetlocL:
{
Log_DebugPrintf("CDROM GetlocL command");
m_response_fifo.PushRange(reinterpret_cast<const u8*>(&m_last_sector_header), sizeof(m_last_sector_header));
m_response_fifo.PushRange(reinterpret_cast<const u8*>(&m_last_sector_subheader), sizeof(m_last_sector_subheader));
SetInterrupt(Interrupt::ACK);
EndCommand();
}
break;
case Command::GetlocP:
{
// TODO: Subchannel Q support..
Log_DebugPrintf("CDROM GetlocP command");
m_response_fifo.Push(1); // track number
m_response_fifo.Push(1); // index
m_response_fifo.Push(DecimalToBCD(m_last_sector_header.minute)); // minute within track
m_response_fifo.Push(DecimalToBCD(m_last_sector_header.second)); // second within track
m_response_fifo.Push(DecimalToBCD(m_last_sector_header.frame)); // frame within track
m_response_fifo.Push(DecimalToBCD(m_last_sector_header.minute)); // minute on entire disc
m_response_fifo.Push(DecimalToBCD(m_last_sector_header.second)); // second on entire disc
m_response_fifo.Push(DecimalToBCD(m_last_sector_header.frame)); // frame on entire disc
SetInterrupt(Interrupt::ACK);
EndCommand();
}
break;
default: default:
Panic("Unknown command"); Panic("Unknown command");
break; break;
@ -749,32 +776,28 @@ void CDROM::DoSectorRead()
// TODO: Error handling // TODO: Error handling
// TODO: Sector buffer should be two sectors? // TODO: Sector buffer should be two sectors?
Assert(!m_mode.ignore_bit); Assert(!m_mode.ignore_bit);
m_sector_buffer.resize(CDImage::RAW_SECTOR_SIZE); m_sector_buffer.resize(RAW_SECTOR_SIZE);
m_media->Read(CDImage::ReadMode::RawSector, 1, m_sector_buffer.data()); 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]), std::memcpy(&m_last_sector_header, &m_sector_buffer[SECTOR_SYNC_SIZE], sizeof(m_last_sector_header));
ZeroExtend32(m_sector_buffer[18])); std::memcpy(&m_last_sector_subheader, &m_sector_buffer[SECTOR_SYNC_SIZE + sizeof(m_last_sector_header)],
sizeof(m_last_sector_subheader));
Log_DevPrintf("Read sector %llu: mode %u submode 0x%02X", m_media->GetCurrentLBA(),
ZeroExtend32(m_last_sector_header.sector_mode), ZeroExtend32(m_last_sector_subheader.submode.bits));
bool pass_to_cpu = true; bool pass_to_cpu = true;
if (m_mode.xa_enable) if (m_mode.xa_enable && m_last_sector_header.sector_mode == 2)
{ {
const CDSectorHeader* sh = if (m_last_sector_subheader.submode.realtime && m_last_sector_subheader.submode.audio)
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 + // TODO: Decode audio sector. Do we still transfer this to the CPU?
sizeof(CDSectorHeader)); Log_WarningPrintf("Decode CD-XA audio sector");
if (xsh->submode.realtime && xsh->submode.audio) m_sector_buffer.clear();
{ pass_to_cpu = false;
// 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) if (m_last_sector_subheader.submode.eof)
{ {
Log_WarningPrintf("End of CD-XA file"); Log_WarningPrintf("End of CD-XA file");
}
} }
} }

View file

@ -1,11 +1,11 @@
#pragma once #pragma once
#include "common/bitfield.h" #include "common/bitfield.h"
#include "common/fifo_queue.h" #include "common/fifo_queue.h"
#include "common/cd_image.h"
#include "types.h" #include "types.h"
#include <string> #include <string>
#include <vector> #include <vector>
class CDImage;
class StateWrapper; class StateWrapper;
class System; class System;
@ -34,6 +34,14 @@ public:
void Execute(TickCount ticks); void Execute(TickCount ticks);
private: private:
enum : u32
{
RAW_SECTOR_SIZE = CDImage::RAW_SECTOR_SIZE,
SECTOR_SYNC_SIZE = CDImage::SECTOR_SYNC_SIZE,
SECTOR_HEADER_SIZE = CDImage::SECTOR_HEADER_SIZE,
SECTOR_XA_SUBHEADER_SIZE = CDImage::SECTOR_XA_SUBHEADER_SIZE,
};
static constexpr u32 PARAM_FIFO_SIZE = 16; static constexpr u32 PARAM_FIFO_SIZE = 16;
static constexpr u32 RESPONSE_FIFO_SIZE = 16; static constexpr u32 RESPONSE_FIFO_SIZE = 16;
static constexpr u32 DATA_FIFO_SIZE = 4096; static constexpr u32 DATA_FIFO_SIZE = 4096;
@ -146,41 +154,6 @@ private:
BitField<u8, bool, 7, 1> BFRD; 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; } bool HasPendingInterrupt() const { return m_interrupt_flag_register != 0; }
void SetInterrupt(Interrupt interrupt); void SetInterrupt(Interrupt interrupt);
void PushStatResponse(Interrupt interrupt = Interrupt::ACK); void PushStatResponse(Interrupt interrupt = Interrupt::ACK);
@ -213,13 +186,15 @@ private:
bool m_reading = false; bool m_reading = false;
bool m_muted = false; bool m_muted = false;
Loc m_setloc = {};
bool m_setloc_dirty = false;
StatusRegister m_status = {}; StatusRegister m_status = {};
SecondaryStatusRegister m_secondary_status = {}; SecondaryStatusRegister m_secondary_status = {};
ModeRegister m_mode = {}; ModeRegister m_mode = {};
Loc m_setloc = {};
bool m_setloc_dirty = false;
CDImage::SectorHeader m_last_sector_header = {};
CDImage::XASubHeader m_last_sector_subheader = {};
u8 m_interrupt_enable_register = INTERRUPT_REGISTER_MASK; u8 m_interrupt_enable_register = INTERRUPT_REGISTER_MASK;
u8 m_interrupt_flag_register = 0; u8 m_interrupt_flag_register = 0;