CDROM: Implement get version and getstat commands
This commit is contained in:
parent
b951f27381
commit
e3c6035152
|
@ -88,7 +88,7 @@ struct BitField
|
|||
|
||||
BitField& operator|=(DataType rhs)
|
||||
{
|
||||
SetValue(GetValue() & rhs);
|
||||
SetValue(GetValue() | rhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ public:
|
|||
T* GetFrontPointer() { return m_ptr[m_head]; }
|
||||
constexpr u32 GetCapacity() const { return CAPACITY; }
|
||||
u32 GetSize() const { return m_size; }
|
||||
bool IsEmpty() const { return m_size > 0; }
|
||||
bool IsEmpty() const { return m_size == 0; }
|
||||
bool IsFull() const { return m_size == CAPACITY; }
|
||||
|
||||
void Clear()
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "cdrom.h"
|
||||
#include "YBaseLib/Log.h"
|
||||
#include "common/state_wrapper.h"
|
||||
#include "interrupt_controller.h"
|
||||
Log_SetChannel(CDROM);
|
||||
|
||||
CDROM::CDROM() = default;
|
||||
|
@ -16,9 +17,17 @@ bool CDROM::Initialize(DMA* dma, InterruptController* interrupt_controller)
|
|||
|
||||
void CDROM::Reset()
|
||||
{
|
||||
m_state = State::Idle;
|
||||
m_status.bits = 0;
|
||||
m_secondary_status.bits = 0;
|
||||
m_interrupt_enable_register = INTERRUPT_REGISTER_MASK;
|
||||
m_interrupt_flag_register = 0;
|
||||
m_param_fifo.Clear();
|
||||
m_response_fifo.Clear();
|
||||
m_data_fifo.Clear();
|
||||
UpdateStatusRegister();
|
||||
|
||||
m_secondary_status.shell_open = true;
|
||||
}
|
||||
|
||||
bool CDROM::DoState(StateWrapper& sw)
|
||||
|
@ -39,10 +48,18 @@ u8 CDROM::ReadRegister(u32 offset)
|
|||
return m_status.bits;
|
||||
|
||||
case 1: // always response FIFO
|
||||
return m_response_fifo.Pop();
|
||||
{
|
||||
const u8 value = m_response_fifo.Pop();
|
||||
UpdateStatusRegister();
|
||||
return value;
|
||||
}
|
||||
|
||||
case 2: // always data FIFO
|
||||
return m_data_fifo.Pop();
|
||||
{
|
||||
const u8 value = m_data_fifo.Pop();
|
||||
UpdateStatusRegister();
|
||||
return value;
|
||||
}
|
||||
|
||||
case 3:
|
||||
{
|
||||
|
@ -88,7 +105,7 @@ void CDROM::WriteRegister(u32 offset, u8 value)
|
|||
if (m_state != State::Idle)
|
||||
Log_ErrorPrintf("Ignoring write (0x%02X) to command register in non-idle state", ZeroExtend32(value));
|
||||
else
|
||||
WriteCommand(value);
|
||||
ExecuteCommand(static_cast<Command>(value));
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -127,6 +144,7 @@ void CDROM::WriteRegister(u32 offset, u8 value)
|
|||
}
|
||||
|
||||
m_param_fifo.Push(value);
|
||||
UpdateStatusRegister();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -190,9 +208,74 @@ void CDROM::WriteRegister(u32 offset, u8 value)
|
|||
ZeroExtend32(m_status.index.GetValue()), ZeroExtend32(value));
|
||||
}
|
||||
|
||||
void CDROM::SetInterrupt(Interrupt interrupt)
|
||||
{
|
||||
m_interrupt_flag_register = static_cast<u8>(interrupt);
|
||||
if (HasPendingInterrupt())
|
||||
m_interrupt_controller->InterruptRequest(InterruptController::IRQ::CDROM);
|
||||
}
|
||||
|
||||
void CDROM::UpdateStatusRegister()
|
||||
{
|
||||
m_status.ADPBUSY = false;
|
||||
m_status.PRMEMPTY = m_param_fifo.IsEmpty();
|
||||
m_status.PRMWRDY = m_param_fifo.IsFull();
|
||||
m_status.RSLRRDY = !m_response_fifo.IsEmpty();
|
||||
m_status.DRQSTS = !m_data_fifo.IsEmpty();
|
||||
m_status.BUSYSTS = m_state != State::Idle;
|
||||
}
|
||||
|
||||
void CDROM::Execute() {}
|
||||
|
||||
void CDROM::WriteCommand(u8 command)
|
||||
void CDROM::ExecuteCommand(Command command)
|
||||
{
|
||||
Log_ErrorPrintf("CDROM write command 0x%02X", ZeroExtend32(command));
|
||||
Log_ErrorPrintf("CDROM write command 0x%02X", ZeroExtend32(static_cast<u8>(command)));
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case Command::Getstat:
|
||||
{
|
||||
Log_DebugPrintf("CDROM Getstat command");
|
||||
|
||||
// if bit 0 or 2 is set, send an additional byte
|
||||
m_response_fifo.Push(m_secondary_status.bits);
|
||||
SetInterrupt(Interrupt::INT3);
|
||||
UpdateStatusRegister();
|
||||
}
|
||||
break;
|
||||
|
||||
case Command::Test:
|
||||
{
|
||||
const u8 subcommand = m_param_fifo.Pop();
|
||||
ExecuteTestCommand(subcommand);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
Panic("Unknown command");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CDROM::ExecuteTestCommand(u8 subcommand)
|
||||
{
|
||||
switch (subcommand)
|
||||
{
|
||||
case 0x20: // Get CDROM BIOS Date/Version
|
||||
{
|
||||
Log_DebugPrintf("Get CDROM BIOS Date/Version");
|
||||
static constexpr u8 response[] = {0x94, 0x09, 0x19, 0xC0};
|
||||
m_response_fifo.PushRange(response, countof(response));
|
||||
m_param_fifo.Clear();
|
||||
SetInterrupt(Interrupt::INT3);
|
||||
UpdateStatusRegister();
|
||||
return;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
Log_ErrorPrintf("Unknown test command 0x%02X", subcommand);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,8 +31,56 @@ private:
|
|||
static constexpr u32 NUM_INTERRUPTS = 32;
|
||||
static constexpr u8 INTERRUPT_REGISTER_MASK = 0x1F;
|
||||
|
||||
enum class Interrupt : u8
|
||||
{
|
||||
INT1 = 0x01,
|
||||
INT2 = 0x02,
|
||||
INT3 = 0x03,
|
||||
INT4 = 0x04,
|
||||
INT5 = 0x05
|
||||
};
|
||||
|
||||
enum class Command : u8
|
||||
{
|
||||
Sync = 0x00,
|
||||
Getstat = 0x01,
|
||||
Setloc = 0x02,
|
||||
Play = 0x03,
|
||||
Forward = 0x04,
|
||||
Backward = 0x05,
|
||||
ReadN = 0x06,
|
||||
MotorOn = 0x07,
|
||||
Stop = 0x08,
|
||||
Pause = 0x09,
|
||||
Init = 0x0A,
|
||||
Mute = 0x0B,
|
||||
Demute = 0x0C,
|
||||
Setfilter = 0x0D,
|
||||
Setmode = 0x0E,
|
||||
Getparam = 0x0F,
|
||||
GetlocL = 0x10,
|
||||
GetlocP = 0x11,
|
||||
SetSession = 0x12,
|
||||
GetTN = 0x13,
|
||||
GetTD = 0x14,
|
||||
SeekL = 0x15,
|
||||
SeekP = 0x16,
|
||||
SetClock = 0x17,
|
||||
GetClock = 0x18,
|
||||
Test = 0x19,
|
||||
GetID = 0x1A,
|
||||
ReadS = 0x1B,
|
||||
Reset = 0x1C,
|
||||
GetQ = 0x1D,
|
||||
ReadTOC = 0x1E,
|
||||
VideoCD = 0x1F,
|
||||
};
|
||||
|
||||
bool HasPendingInterrupt() const { return m_interrupt_flag_register != 0; }
|
||||
void WriteCommand(u8 command);
|
||||
void SetInterrupt(Interrupt interrupt);
|
||||
void UpdateStatusRegister();
|
||||
void ExecuteCommand(Command command);
|
||||
void ExecuteTestCommand(u8 subcommand);
|
||||
|
||||
DMA* m_dma;
|
||||
InterruptController* m_interrupt_controller;
|
||||
|
@ -56,6 +104,19 @@ private:
|
|||
BitField<u8, bool, 7, 1> BUSYSTS;
|
||||
} m_status = {};
|
||||
|
||||
union
|
||||
{
|
||||
u8 bits;
|
||||
BitField<u8, bool, 0, 1> error;
|
||||
BitField<u8, bool, 1, 1> motor_on;
|
||||
BitField<u8, bool, 2, 1> seek_error;
|
||||
BitField<u8, bool, 3, 1> id_error;
|
||||
BitField<u8, bool, 4, 1> shell_open;
|
||||
BitField<u8, bool, 5, 1> reading;
|
||||
BitField<u8, bool, 6, 1> seeking;
|
||||
BitField<u8, bool, 7, 1> playing_cdda;
|
||||
} m_secondary_status = {};
|
||||
|
||||
u8 m_interrupt_enable_register = INTERRUPT_REGISTER_MASK;
|
||||
u8 m_interrupt_flag_register = 0;
|
||||
|
||||
|
|
|
@ -606,6 +606,7 @@ void Core::ExecuteInstruction(Instruction inst)
|
|||
|
||||
case InstructionFunct::syscall:
|
||||
{
|
||||
Log_DebugPrintf("Syscall 0x%X(0x%X)", m_regs.s0, m_regs.a0);
|
||||
RaiseException(Exception::Syscall);
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -289,7 +289,7 @@ struct Cop0Registers
|
|||
BitField<u32, u8, 0, 6> mode_bits;
|
||||
BitField<u32, u8, 28, 2> coprocessor_enable_mask;
|
||||
|
||||
static constexpr u32 WRITE_MASK = 0b1111'0010'0111'1111'1111'0011'0011'1111;
|
||||
static constexpr u32 WRITE_MASK = 0b1111'0010'0111'1111'1111'1111'0011'1111;
|
||||
} sr;
|
||||
|
||||
union CAUSE
|
||||
|
|
|
@ -292,6 +292,8 @@ void GPU::Execute(TickCount ticks)
|
|||
// start the new frame
|
||||
m_system->IncrementFrameNumber();
|
||||
m_crtc_state.current_scanline = 0;
|
||||
m_crtc_state.in_hblank = false;
|
||||
m_crtc_state.in_vblank = false;
|
||||
|
||||
if (m_GPUSTAT.vertical_resolution)
|
||||
m_GPUSTAT.drawing_even_line ^= true;
|
||||
|
|
|
@ -58,7 +58,7 @@ void InterruptController::WriteRegister(u32 offset, u32 value)
|
|||
case 0x00: // I_STATUS
|
||||
{
|
||||
Log_DebugPrintf("Clearing bits 0x%08X", value);
|
||||
m_interrupt_status_register = m_interrupt_status_register & (~(value & REGISTER_WRITE_MASK));
|
||||
m_interrupt_status_register = m_interrupt_status_register & (value & REGISTER_WRITE_MASK);
|
||||
UpdateCPUInterruptRequest();
|
||||
}
|
||||
break;
|
||||
|
@ -80,7 +80,7 @@ void InterruptController::UpdateCPUInterruptRequest()
|
|||
{
|
||||
// external interrupts set bit 10 only?
|
||||
if (m_interrupt_status_register != 0)
|
||||
m_cpu->SetExternalInterrupt(3);
|
||||
m_cpu->SetExternalInterrupt(2);
|
||||
else
|
||||
m_cpu->ClearExternalInterrupt(3);
|
||||
m_cpu->ClearExternalInterrupt(2);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue