[CDROM] Add test command

This commit is contained in:
liuk7071 2023-09-09 19:08:31 +02:00
parent e79b771a61
commit 1ff9d8ca6c
4 changed files with 120 additions and 9 deletions

View file

@ -1,19 +1,53 @@
#include <cdrom.hpp>
CDROM::CDROM() {
CDROM::CDROM(Scheduler* scheduler) : scheduler(scheduler) {
status.prmempt = 1; // Parameter fifo empty
status.prmwrdy = 1; // Parameter fifo not full
}
void CDROM::executeCommand(u8 data) {
Helpers::panic("[FATAL] Unimplemented CDROM command 0x%02x\n", data);
switch (data) {
case CDROMCommands::Test: {
u8 subFunc = getParamByte();
switch (subFunc) {
case 0x20: {
response.push(0x94);
response.push(0x09);
response.push(0x19);
response.push(0xC0);
break;
}
default:
Helpers::panic("[FATAL] Unimplemented CDROM test subfunc 0x%02x\n", subFunc);
}
scheduler->push(&int3, scheduler->time + int3Delay, this);
break;
}
default:
Helpers::panic("[FATAL] Unimplemented CDROM command 0x%02x\n", data);
}
Helpers::debugAssert(params.size() == 0, "[FATAL] CDROM command did not use all parameters");
status.rslrrdy = 1; // Response fifo not empty
status.prmempt = 1; // Parameter fifo empty
status.prmwrdy = 1; // Parameter fifo not full
}
bool CDROM::shouldFireIRQ() {
return intFlag & intEnable;
}
void CDROM::int3(void* classptr) {
CDROM* cdrom = (CDROM*)classptr;
Helpers::debugAssert((cdrom->intFlag & 7) == 0, "[FATAL] CDROM INT3 was fired before previous INT was acknowledged in interrupt flag (INT%d)\n", cdrom->intFlag & 3);
cdrom->intFlag |= 3;
}
void CDROM::pushParam(u8 data) {
Helpers::debugAssert(params.size() <= 16, "[FATAL] Wrote more than 16 bytes to CDROM parameter fifo");
params.push(data);
@ -31,13 +65,45 @@ void CDROM::writeStatus(u8 data) {
}
void CDROM::writeIE(u8 data) {
// TODO: stubbed
intEnable = data;
}
u8 CDROM::readIF() {
return intFlag | (7 << 5); // bits 5-7 are always 1
}
void CDROM::writeIF(u8 data) {
// TODO: stubbed
intEnable &= ~(data & 0x1f);
if (data & (1 << 6)) { // "CLRPRM" clear parameter fifo
while (params.size()) params.pop();
status.prmempt = 1; // Parameter fifo empty
status.prmwrdy = 1; // Parameter fifo not full
}
// Upon acknowledge, the response fifo is cleared
while (response.size()) response.pop();
}
u8 CDROM::getIndex() {
return status.index;
}
u8 CDROM::getParamByte() {
u8 byte = params.front();
params.pop();
return byte;
}
u8 CDROM::getResponseByte() {
if (!response.size()) {
return 0;
}
u8 byte = response.front();
response.pop();
if (!response.size()) {
status.rslrrdy = 0; // Response fifo empty
}
return byte;
}

View file

@ -3,24 +3,46 @@
#include <helpers.hpp>
#include <BitField.hpp>
#include <queue>
#include <scheduler.hpp>
constexpr u64 cpuSpeed = 33868800;
constexpr u64 readDelay = cpuSpeed / 75;
constexpr u64 readDelayDoubleSpeed = readDelay / 2;
constexpr u64 int3Delay = cpuSpeed / 1000; // I don't know if this is ok???
class CDROM {
public:
CDROM();
CDROM(Scheduler* scheduler);
Scheduler* scheduler;
void executeCommand(u8 data);
// INTs
bool shouldFireIRQ();
static void int3(void* classptr);
void pushParam(u8 data);
u8 readStatus();
void writeStatus(u8 data);
void writeIE(u8 data);
u8 readIF();
void writeIF(u8 data);
u8 getIndex();
u8 getResponseByte(); // This one is public so it can be called from the memory read handlers
private:
u8 intEnable = 0;
u8 intFlag = 0;
std::queue<u8> params;
u8 getParamByte();
std::queue<u8> response;
union {
u8 raw = 0;
@ -32,4 +54,10 @@ private:
BitField<6, 1, u8> drqsts;
BitField<7, 1, u8> busysts;
} status;
};
};
namespace CDROMCommands {
enum {
Test = 0x19
};
} // End namespace CDROMCommands

View file

@ -66,6 +66,20 @@ u8 Memory::read(u32 vaddr) {
// CDROM
if (paddr == 0x1f801800) return cdrom->readStatus();
else if (paddr == 0x1f801801) {
switch (cdrom->getIndex()) {
case 1: return cdrom->getResponseByte();
default:
Helpers::panic("[FATAL] Unhandled CDROM read8 0x1f801801.%d", cdrom->getIndex());
}
}
else if (paddr == 0x1f801803) {
switch (cdrom->getIndex()) {
case 1: return cdrom->readIF();
default:
Helpers::panic("[FATAL] Unhandled CDROM read8 0x1f801803.%d", cdrom->getIndex());
}
}
else if (Helpers::inRangeSized<u32>(paddr, 0x1f000000, 0x400)) return 0xff;
else
Helpers::panic("[FATAL] Unhandled read8 0x%08x (virtual 0x%08x)\n", paddr, vaddr);
@ -169,7 +183,6 @@ void Memory::write(u32 vaddr, u8 data) {
default:
Helpers::panic("[FATAL] Unhandled CDROM write8 0x1f801802.%d <- 0x%02x\n", cdrom->getIndex(), data);
}
return;
}
else if (paddr == 0x1f801803) {
switch (cdrom->getIndex()) {
@ -180,7 +193,6 @@ void Memory::write(u32 vaddr, u8 data) {
default:
Helpers::panic("[FATAL] Unhandled CDROM write8 0x1f801803.%d <- 0x%02x\n", cdrom->getIndex(), data);
}
return;
}
else if (paddr == 0x1f802041) return; // POST - External 7-segment Display (W)
else

View file

@ -12,7 +12,7 @@
class PlayStation {
public:
PlayStation(const fs::path& biosPath) : cdrom(), interrupt(), gpu(&scheduler), dma(), mem(&interrupt, &dma, &gpu, &cdrom), cpu(&mem) {
PlayStation(const fs::path& biosPath) : cdrom(&scheduler), interrupt(), gpu(&scheduler), dma(), mem(&interrupt, &dma, &gpu, &cdrom), cpu(&mem) {
mem.loadBios(biosPath);
cpu.switchBackend(Cpu::Backend::Interpreter);
@ -27,6 +27,11 @@ public:
auto cyclesToAdd = isInBIOS() ? 20 : 2;
scheduler.tick(cyclesToAdd);
cycles += cyclesToAdd;
// CDROM IRQ
if (cdrom.shouldFireIRQ()) {
interrupt.raiseInterrupt(Interrupt::InterruptType::CDROM);
}
}
u32 getPC() { return cpu.core.pc; }