mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-26 07:35:41 +00:00
CDROM: Implement GetlocP/GetlocL commands
This commit is contained in:
parent
bbe1fc062f
commit
0b46a8cfc4
|
@ -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,
|
||||||
|
@ -26,6 +29,41 @@ public:
|
||||||
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.
|
||||||
static constexpr u64 MSFToLBA(u32 pregap_seconds, u32 minute, u32 second, u32 frame);
|
static constexpr u64 MSFToLBA(u32 pregap_seconds, u32 minute, u32 second, u32 frame);
|
||||||
static constexpr void LBAToMSF(u32 pregap_seconds, u64 lba, u32* minute, u32* second, u32* frame);
|
static constexpr void LBAToMSF(u32 pregap_seconds, u64 lba, u32* minute, u32* second, u32* frame);
|
||||||
|
|
|
@ -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,21 +776,18 @@ 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 +
|
|
||||||
sizeof(CDSectorHeader));
|
|
||||||
if (xsh->submode.realtime && xsh->submode.audio)
|
|
||||||
{
|
{
|
||||||
// TODO: Decode audio sector. Do we still transfer this to the CPU?
|
// TODO: Decode audio sector. Do we still transfer this to the CPU?
|
||||||
Log_WarningPrintf("Decode CD-XA audio sector");
|
Log_WarningPrintf("Decode CD-XA audio sector");
|
||||||
|
@ -771,12 +795,11 @@ void CDROM::DoSectorRead()
|
||||||
pass_to_cpu = false;
|
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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (pass_to_cpu)
|
if (pass_to_cpu)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue