mirror of
https://github.com/liuk7071/ChonkyStation.git
synced 2024-05-20 12:57:52 -04:00
[CDROM] Reads and other stuff
This commit is contained in:
parent
76f8db38a1
commit
a95f467e11
|
@ -3,7 +3,10 @@
|
||||||
|
|
||||||
MAKE_LOG_FUNCTION(log, cdromLogger)
|
MAKE_LOG_FUNCTION(log, cdromLogger)
|
||||||
|
|
||||||
CDROM::CDROM(Scheduler* scheduler) : scheduler(scheduler) {
|
CDROM::CDROM(const fs::path& cdPath, Scheduler* scheduler) : scheduler(scheduler) {
|
||||||
|
std::string pathStr = cdPath.string();
|
||||||
|
cd = std::fopen(pathStr.c_str(), "rb");
|
||||||
|
|
||||||
statusReg.prmempt = 1; // Parameter fifo empty
|
statusReg.prmempt = 1; // Parameter fifo empty
|
||||||
statusReg.prmwrdy = 1; // Parameter fifo not full
|
statusReg.prmwrdy = 1; // Parameter fifo not full
|
||||||
|
|
||||||
|
@ -34,6 +37,68 @@ void CDROM::executeCommand(u8 data) {
|
||||||
log("SetLoc (loc: %d)\n", seekLoc);
|
log("SetLoc (loc: %d)\n", seekLoc);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case CDROMCommands::ReadN: {
|
||||||
|
response.push(statusCode.raw);
|
||||||
|
scheduler->push(&int3, scheduler->time + int3Delay, this);
|
||||||
|
|
||||||
|
log("ReadN\n");
|
||||||
|
|
||||||
|
beginReading();
|
||||||
|
scheduler->push(&cdRead, scheduler->time + (!mode.doubleSpeed ? readTime : readTimeDoubleSpeed), this, "cdRead");
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case CDROMCommands::Pause: {
|
||||||
|
response.push(statusCode.raw);
|
||||||
|
scheduler->push(&int3, scheduler->time + int3Delay, this);
|
||||||
|
|
||||||
|
scheduler->push(&int2, scheduler->time + int3Delay + int2Delay, this);
|
||||||
|
stopReading();
|
||||||
|
secondResponse.push(statusCode.raw);
|
||||||
|
|
||||||
|
log("Pause\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case CDROMCommands::Init: {
|
||||||
|
response.push(statusCode.raw);
|
||||||
|
secondResponse.push(statusCode.raw);
|
||||||
|
|
||||||
|
scheduler->push(&int3, scheduler->time + int3Delay, this);
|
||||||
|
scheduler->push(&int2, scheduler->time + int3Delay + int2Delay, this);
|
||||||
|
|
||||||
|
log("Init\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case CDROMCommands::Setmode: {
|
||||||
|
mode.raw = getParamByte();
|
||||||
|
|
||||||
|
Helpers::debugAssert(!mode.autoPause, "Enabled CDROM auto pause\n");
|
||||||
|
Helpers::debugAssert(!mode.report, "Enabled CDROM report\n");
|
||||||
|
Helpers::debugAssert(!mode.xaFilter, "Enabled CDROM xa-filter\n");
|
||||||
|
Helpers::debugAssert(!mode.ignoreBit, "Enabled CDROM ignore bit\n");
|
||||||
|
Helpers::debugAssert(!mode.sectorSize, "Enabled CDROM 0x924 byte sectors\n");
|
||||||
|
Helpers::debugAssert(!mode.xaAdpcm, "Enabled CDROM xa-adpcm\n");
|
||||||
|
|
||||||
|
response.push(statusCode.raw);
|
||||||
|
scheduler->push(&int3, scheduler->time + int3Delay, this);
|
||||||
|
|
||||||
|
log("Setmode\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case CDROMCommands::Demute: {
|
||||||
|
response.push(statusCode.raw);
|
||||||
|
secondResponse.push(statusCode.raw);
|
||||||
|
|
||||||
|
scheduler->push(&int3, scheduler->time + int3Delay, this);
|
||||||
|
|
||||||
|
log("Demute\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case CDROMCommands::SeekL: {
|
case CDROMCommands::SeekL: {
|
||||||
// TODO: SeekL/P should stop ongoing reads
|
// TODO: SeekL/P should stop ongoing reads
|
||||||
|
@ -171,6 +236,51 @@ void CDROM::stopSeeking(void* classptr) {
|
||||||
log("Seek ended\n");
|
log("Seek ended\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CDROM::beginReading() {
|
||||||
|
statusCode.reading = true;
|
||||||
|
log("Begin reading\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDROM::stopReading() {
|
||||||
|
statusCode.reading = false;
|
||||||
|
log("Stop reading\n");
|
||||||
|
scheduler->deleteAllEventsOfName("cdRead");
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDROM::cdRead(void* classptr) {
|
||||||
|
CDROM* cdrom = (CDROM*)classptr;
|
||||||
|
Helpers::debugAssert((cdrom->intFlag & 7) == 0, "[ FATAL ] CDROM INT1 was fired before previous INT%d was acknowledged in interrupt flag\n", cdrom->intFlag & 3);
|
||||||
|
cdrom->intFlag |= 1;
|
||||||
|
|
||||||
|
cdrom->sector.clear();
|
||||||
|
cdrom->sector.resize(sectorSize);
|
||||||
|
std::fseek(cdrom->cd, (cdrom->seekLoc - 150) * sectorSize, SEEK_SET);
|
||||||
|
std::fread(cdrom->sector.data(), 1, sectorSize, cdrom->cd);
|
||||||
|
cdrom->statusReg.drqsts = 1;
|
||||||
|
|
||||||
|
log("Read sector %d\n", cdrom->seekLoc);
|
||||||
|
cdrom->seekLoc++;
|
||||||
|
|
||||||
|
if (cdrom->mode.sectorSize)
|
||||||
|
cdrom->sectorCur = 0x0C;
|
||||||
|
else
|
||||||
|
cdrom->sectorCur = 0x18;
|
||||||
|
|
||||||
|
cdrom->scheduler->push(&cdrom->cdRead, cdrom->scheduler->time + (!cdrom->mode.doubleSpeed ? readTime : readTimeDoubleSpeed), classptr, "cdRead");
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 CDROM::readSectorWord() {
|
||||||
|
if ((sectorCur + 3) >= sector.size()) Helpers::panic("[ FATAL ] CDROM sector read out of bounds\n");
|
||||||
|
|
||||||
|
u32 word;
|
||||||
|
std::memcpy(&word, §or[sectorCur], sizeof(u32));
|
||||||
|
sectorCur += sizeof(u32);
|
||||||
|
|
||||||
|
if (sectorCur == sectorSize) statusReg.drqsts = 0;
|
||||||
|
|
||||||
|
return word;
|
||||||
|
}
|
||||||
|
|
||||||
void CDROM::pushParam(u8 data) {
|
void CDROM::pushParam(u8 data) {
|
||||||
params.push(data);
|
params.push(data);
|
||||||
Helpers::debugAssert(params.size() <= 16, "[ FATAL ] Wrote more than 16 bytes to CDROM parameter fifo");
|
Helpers::debugAssert(params.size() <= 16, "[ FATAL ] Wrote more than 16 bytes to CDROM parameter fifo");
|
||||||
|
@ -187,6 +297,10 @@ void CDROM::writeStatus(u8 data) {
|
||||||
statusReg.index = data & 3;
|
statusReg.index = data & 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u8 CDROM::readIE() {
|
||||||
|
return intEnable;
|
||||||
|
}
|
||||||
|
|
||||||
void CDROM::writeIE(u8 data) {
|
void CDROM::writeIE(u8 data) {
|
||||||
intEnable = data;
|
intEnable = data;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,21 +8,25 @@
|
||||||
|
|
||||||
|
|
||||||
constexpr u64 cpuSpeed = 33868800;
|
constexpr u64 cpuSpeed = 33868800;
|
||||||
constexpr u64 readDelay = cpuSpeed / 75;
|
constexpr u64 readTime = cpuSpeed / 75;
|
||||||
constexpr u64 readDelayDoubleSpeed = readDelay / 2;
|
constexpr u64 readTimeDoubleSpeed = readTime / 2;
|
||||||
|
|
||||||
// I don't know if these are ok?????
|
// I don't know if these are ok?????
|
||||||
constexpr u64 int3Delay = cpuSpeed / 1000;
|
constexpr u64 int3Delay = cpuSpeed / 15000;
|
||||||
constexpr u64 int2Delay = int3Delay * 2;
|
constexpr u64 int2Delay = int3Delay * 2;
|
||||||
constexpr u64 getIDDelay = 33868;
|
constexpr u64 getIDDelay = 33868;
|
||||||
|
|
||||||
constexpr u64 seekTime = 150000; // Currently stubbed seeking time to this for all seeks
|
constexpr u64 seekTime = 75000; // Currently stubbed seeking time to this for all seeks
|
||||||
|
|
||||||
|
constexpr u64 sectorSize = 0x930;
|
||||||
|
|
||||||
class CDROM {
|
class CDROM {
|
||||||
public:
|
public:
|
||||||
CDROM(Scheduler* scheduler);
|
CDROM(const fs::path& cdPath, Scheduler* scheduler);
|
||||||
Scheduler* scheduler;
|
Scheduler* scheduler;
|
||||||
|
|
||||||
|
FILE* cd;
|
||||||
|
|
||||||
void executeCommand(u8 data);
|
void executeCommand(u8 data);
|
||||||
|
|
||||||
// INTs
|
// INTs
|
||||||
|
@ -34,11 +38,16 @@ public:
|
||||||
|
|
||||||
static void stopSeeking(void* classptr);
|
static void stopSeeking(void* classptr);
|
||||||
|
|
||||||
|
void beginReading();
|
||||||
|
void stopReading();
|
||||||
|
static void cdRead(void* classptr);
|
||||||
|
|
||||||
void pushParam(u8 data);
|
void pushParam(u8 data);
|
||||||
|
|
||||||
u8 readStatus();
|
u8 readStatus();
|
||||||
void writeStatus(u8 data);
|
void writeStatus(u8 data);
|
||||||
|
|
||||||
|
u8 readIE();
|
||||||
void writeIE(u8 data);
|
void writeIE(u8 data);
|
||||||
u8 readIF();
|
u8 readIF();
|
||||||
void writeIF(u8 data);
|
void writeIF(u8 data);
|
||||||
|
@ -46,7 +55,11 @@ public:
|
||||||
u8 getIndex();
|
u8 getIndex();
|
||||||
|
|
||||||
u8 getResponseByte(); // This one is public so it can be called from the memory read handlers
|
u8 getResponseByte(); // This one is public so it can be called from the memory read handlers
|
||||||
|
u32 readSectorWord();
|
||||||
private:
|
private:
|
||||||
|
std::vector<u8> sector;
|
||||||
|
u64 sectorCur = 0;
|
||||||
|
|
||||||
u8 intEnable = 0;
|
u8 intEnable = 0;
|
||||||
u8 intFlag = 0;
|
u8 intFlag = 0;
|
||||||
|
|
||||||
|
@ -56,6 +69,18 @@ private:
|
||||||
u32 seekLoc = 0;
|
u32 seekLoc = 0;
|
||||||
u8 bcdToDec(u8 n) { return n - 6 * (n >> 4); }
|
u8 bcdToDec(u8 n) { return n - 6 * (n >> 4); }
|
||||||
|
|
||||||
|
union {
|
||||||
|
u8 raw = 0;
|
||||||
|
BitField<0, 1, u8> cdda;
|
||||||
|
BitField<1, 1, u8> autoPause;
|
||||||
|
BitField<2, 1, u8> report;
|
||||||
|
BitField<3, 1, u8> xaFilter;
|
||||||
|
BitField<4, 1, u8> ignoreBit;
|
||||||
|
BitField<5, 1, u8> sectorSize;
|
||||||
|
BitField<6, 1, u8> xaAdpcm;
|
||||||
|
BitField<7, 1, u8> doubleSpeed;
|
||||||
|
} mode;
|
||||||
|
|
||||||
std::queue<u8> response;
|
std::queue<u8> response;
|
||||||
std::queue<u8> secondResponse;
|
std::queue<u8> secondResponse;
|
||||||
|
|
||||||
|
@ -87,6 +112,11 @@ namespace CDROMCommands {
|
||||||
enum {
|
enum {
|
||||||
GetStat = 0x01,
|
GetStat = 0x01,
|
||||||
SetLoc = 0x02,
|
SetLoc = 0x02,
|
||||||
|
ReadN = 0x06,
|
||||||
|
Pause = 0x09,
|
||||||
|
Init = 0x0A,
|
||||||
|
Setmode = 0x0E,
|
||||||
|
Demute = 0x0C,
|
||||||
SeekL = 0x15,
|
SeekL = 0x15,
|
||||||
Test = 0x19,
|
Test = 0x19,
|
||||||
GetID = 0x1A
|
GetID = 0x1A
|
||||||
|
|
|
@ -6,6 +6,7 @@ MAKE_LOG_FUNCTION(log, dmaLogger)
|
||||||
|
|
||||||
DMA::DMA() {
|
DMA::DMA() {
|
||||||
channels[2].doDMA = &gpuDMA;
|
channels[2].doDMA = &gpuDMA;
|
||||||
|
channels[3].doDMA = &cdromDMA;
|
||||||
channels[6].doDMA = &otcDMA;
|
channels[6].doDMA = &otcDMA;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,6 +99,35 @@ void DMA::gpuDMA(Memory* memory) {
|
||||||
log("GPU DMA done\n");
|
log("GPU DMA done\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DMA::cdromDMA(Memory* memory) {
|
||||||
|
const auto& dma = memory->dma;
|
||||||
|
auto& ch = dma->channels[3];
|
||||||
|
log("Start CDROM DMA\n");
|
||||||
|
|
||||||
|
switch (ch.chcr.syncMode) {
|
||||||
|
case (u32)SyncMode::Block: {
|
||||||
|
u32 addr = ch.madr & 0x1ffffc;
|
||||||
|
u32 bc = ch.bcr.bc;
|
||||||
|
if (!bc) bc = 0x10000;
|
||||||
|
while (bc-- > 1) {
|
||||||
|
memory->write<u32>(addr, memory->cdrom->readSectorWord());
|
||||||
|
if (ch.chcr.step == (u32)Step::Forward)
|
||||||
|
addr += 4;
|
||||||
|
else
|
||||||
|
addr -= 4;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
Helpers::panic("[DMA] Unimplemented CDROM DMA sync mode %d\n", ch.chcr.syncMode.Value());
|
||||||
|
}
|
||||||
|
|
||||||
|
ch.chcr.enable = 0;
|
||||||
|
ch.chcr.trigger = 0;
|
||||||
|
// TODO: Update DICR
|
||||||
|
log("CDROM DMA done\n");
|
||||||
|
}
|
||||||
|
|
||||||
void DMA::otcDMA(Memory* memory) {
|
void DMA::otcDMA(Memory* memory) {
|
||||||
const auto& dma = memory->dma;
|
const auto& dma = memory->dma;
|
||||||
auto& ch = dma->channels[6];
|
auto& ch = dma->channels[6];
|
||||||
|
|
|
@ -35,7 +35,7 @@ public:
|
||||||
} chcr;
|
} chcr;
|
||||||
|
|
||||||
bool shouldStartDMA();
|
bool shouldStartDMA();
|
||||||
void (*doDMA)(Memory*);
|
void (*doDMA)(Memory*) = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
DMAChannel channels[7];
|
DMAChannel channels[7];
|
||||||
|
@ -59,5 +59,6 @@ public:
|
||||||
|
|
||||||
void doDMA(int channel, Memory* memory);
|
void doDMA(int channel, Memory* memory);
|
||||||
static void gpuDMA(Memory* memory);
|
static void gpuDMA(Memory* memory);
|
||||||
|
static void cdromDMA(Memory* memory);
|
||||||
static void otcDMA(Memory* memory);
|
static void otcDMA(Memory* memory);
|
||||||
};
|
};
|
|
@ -10,10 +10,10 @@ int main(int argc, char** argv) {
|
||||||
|
|
||||||
printf("ChonkyStation\n");
|
printf("ChonkyStation\n");
|
||||||
|
|
||||||
PlayStation playstation = PlayStation(argv[1]);
|
PlayStation playstation = PlayStation(argv[1], argv[2]);
|
||||||
|
|
||||||
if (argc >= 3) {
|
if (argc >= 4) {
|
||||||
playstation.sideloadExecutable(argv[2]);
|
playstation.sideloadExecutable(argv[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Testing
|
// Testing
|
||||||
|
|
|
@ -76,6 +76,7 @@ u8 Memory::read(u32 vaddr) {
|
||||||
}
|
}
|
||||||
else if (paddr == 0x1f801803) {
|
else if (paddr == 0x1f801803) {
|
||||||
switch (cdrom->getIndex()) {
|
switch (cdrom->getIndex()) {
|
||||||
|
case 0: return cdrom->readIE();
|
||||||
case 1: return cdrom->readIF();
|
case 1: return cdrom->readIF();
|
||||||
default:
|
default:
|
||||||
Helpers::panic("[ FATAL ] Unhandled CDROM read8 0x1f801803.%d", cdrom->getIndex());
|
Helpers::panic("[ FATAL ] Unhandled CDROM read8 0x1f801803.%d", cdrom->getIndex());
|
||||||
|
@ -113,6 +114,8 @@ u16 Memory::read(u32 vaddr) {
|
||||||
else if (Helpers::inRangeSized<u32>(paddr, (u32)MemoryBase::SIO, (u32)MemorySize::SIO)) return 0;
|
else if (Helpers::inRangeSized<u32>(paddr, (u32)MemoryBase::SIO, (u32)MemorySize::SIO)) return 0;
|
||||||
// SPU
|
// SPU
|
||||||
else if (Helpers::inRangeSized<u32>(paddr, (u32)MemoryBase::SPU, (u32)MemorySize::SPU)) return 0;
|
else if (Helpers::inRangeSized<u32>(paddr, (u32)MemoryBase::SPU, (u32)MemorySize::SPU)) return 0;
|
||||||
|
// Timers
|
||||||
|
else if (Helpers::inRangeSized<u32>(paddr, (u32)MemoryBase::Timer, (u32)MemorySize::Timer)) return 0;
|
||||||
else
|
else
|
||||||
Helpers::panic("[ FATAL ] Unhandled read16 0x%08x (virtual 0x%08x)\n", paddr, vaddr);
|
Helpers::panic("[ FATAL ] Unhandled read16 0x%08x (virtual 0x%08x)\n", paddr, vaddr);
|
||||||
}
|
}
|
||||||
|
@ -158,7 +161,10 @@ u32 Memory::read(u32 vaddr) {
|
||||||
// Timers
|
// Timers
|
||||||
else if (Helpers::inRangeSized<u32>(paddr, (u32)MemoryBase::Timer, (u32)MemorySize::Timer)) return 0;
|
else if (Helpers::inRangeSized<u32>(paddr, (u32)MemoryBase::Timer, (u32)MemorySize::Timer)) return 0;
|
||||||
|
|
||||||
|
else if (paddr == 0x1f802080) return 0; // 1F802080h 4 Redux-Expansion ID "PCSX" (R)
|
||||||
|
|
||||||
else if (paddr == 0x1f80101C) return 0x00070777; // Expansion 2 Delay/Size (usually 00070777h) (128 bytes, 8bit bus)
|
else if (paddr == 0x1f80101C) return 0x00070777; // Expansion 2 Delay/Size (usually 00070777h) (128 bytes, 8bit bus)
|
||||||
|
else if (paddr == 0x1f801060) return 0x00000b88; // RAM_SIZE (R/W) (usually 00000B88h) (or 00000888h)
|
||||||
|
|
||||||
else
|
else
|
||||||
Helpers::dump("ramdump.bin", ram, 2_MB);
|
Helpers::dump("ramdump.bin", ram, 2_MB);
|
||||||
|
@ -188,6 +194,9 @@ void Memory::write(u32 vaddr, u8 data) {
|
||||||
cdrom->executeCommand(data);
|
cdrom->executeCommand(data);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 1: break;
|
||||||
|
case 2: break;
|
||||||
|
case 3: break;
|
||||||
default:
|
default:
|
||||||
Helpers::panic("[ FATAL ] Unhandled CDROM write8 0x1f801801.%d <- 0x%02x\n", cdrom->getIndex(), data);
|
Helpers::panic("[ FATAL ] Unhandled CDROM write8 0x1f801801.%d <- 0x%02x\n", cdrom->getIndex(), data);
|
||||||
}
|
}
|
||||||
|
@ -202,20 +211,35 @@ void Memory::write(u32 vaddr, u8 data) {
|
||||||
cdrom->writeIE(data);
|
cdrom->writeIE(data);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 2: break;
|
||||||
|
case 3: break;
|
||||||
default:
|
default:
|
||||||
Helpers::panic("[ FATAL ] Unhandled CDROM write8 0x1f801802.%d <- 0x%02x\n", cdrom->getIndex(), data);
|
Helpers::panic("[ FATAL ] Unhandled CDROM write8 0x1f801802.%d <- 0x%02x\n", cdrom->getIndex(), data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (paddr == 0x1f801803) {
|
else if (paddr == 0x1f801803) {
|
||||||
switch (cdrom->getIndex()) {
|
switch (cdrom->getIndex()) {
|
||||||
|
case 0: {
|
||||||
|
Helpers::debugAssert(((data >> 5) & 1) == 0, "[ FATAL ] Unhandled CDROM Request Register SMEN bit\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
case 1: {
|
case 1: {
|
||||||
cdrom->writeIF(data);
|
cdrom->writeIF(data);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 2: break;
|
||||||
|
case 3: break;
|
||||||
default:
|
default:
|
||||||
Helpers::panic("[ FATAL ] Unhandled CDROM write8 0x1f801803.%d <- 0x%02x\n", cdrom->getIndex(), data);
|
Helpers::panic("[ FATAL ] Unhandled CDROM write8 0x1f801803.%d <- 0x%02x\n", cdrom->getIndex(), data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 1F802080h 1 Redux-Expansion Console putchar (W)
|
||||||
|
else if (paddr == 0x1f802080) {
|
||||||
|
std::putc(data, stdout);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
else if (paddr == 0x1f802041) return; // POST - External 7-segment Display (W)
|
else if (paddr == 0x1f802041) return; // POST - External 7-segment Display (W)
|
||||||
else
|
else
|
||||||
Helpers::panic("[ FATAL ] Unhandled write8 0x%08x (virtual 0x%08x) <- 0x%02x\n", paddr, vaddr, data);
|
Helpers::panic("[ FATAL ] Unhandled write8 0x%08x (virtual 0x%08x) <- 0x%02x\n", paddr, vaddr, data);
|
||||||
|
|
|
@ -12,11 +12,11 @@
|
||||||
|
|
||||||
class PlayStation {
|
class PlayStation {
|
||||||
public:
|
public:
|
||||||
PlayStation(const fs::path& biosPath) : cdrom(&scheduler), interrupt(), gpu(&scheduler), dma(), mem(&interrupt, &dma, &gpu, &cdrom), cpu(&mem) {
|
PlayStation(const fs::path& biosPath, const fs::path& cdPath) : cdrom(cdPath, &scheduler), interrupt(), gpu(&scheduler), dma(), mem(&interrupt, &dma, &gpu, &cdrom), cpu(&mem) {
|
||||||
mem.core = &cpu.core;
|
mem.core = &cpu.core;
|
||||||
|
|
||||||
mem.loadBios(biosPath);
|
mem.loadBios(biosPath);
|
||||||
cpu.switchBackend(Cpu::Backend::OldInterpreter);
|
cpu.switchBackend(Cpu::Backend::Interpreter);
|
||||||
|
|
||||||
// Setup GPU scheduler events
|
// Setup GPU scheduler events
|
||||||
scheduler.push(&gpu.scanlineEvent, scheduler.time + GPUConstants::cyclesPerScanline, &gpu);
|
scheduler.push(&gpu.scanlineEvent, scheduler.time + GPUConstants::cyclesPerScanline, &gpu);
|
||||||
|
|
|
@ -13,8 +13,18 @@ void Scheduler::tick(u64 cycles) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scheduler::push(void (*functionPtr)(void*), u64 time, void* data) {
|
void Scheduler::push(void (*functionPtr)(void*), u64 time, void* data, std::string name) {
|
||||||
Helpers::debugAssert(events.size() < schedulerMaxEntries, "[ FATAL ] Queued more than %d scheduler events\n", schedulerMaxEntries);
|
Helpers::debugAssert(events.size() < schedulerMaxEntries, "[ FATAL ] Queued more than %d scheduler events\n", schedulerMaxEntries);
|
||||||
|
|
||||||
events.push({ .functionPtr = functionPtr, .data = data, .time = time });
|
events.push({ .functionPtr = functionPtr, .data = data, .time = time, .name = name });
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scheduler::deleteAllEventsOfName(std::string name) {
|
||||||
|
auto eventList = events.get_container();
|
||||||
|
|
||||||
|
for (int i = 0; i < events.size(); i++) {
|
||||||
|
for (auto& i : eventList) {
|
||||||
|
if (i.name == name) events.remove(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -2,25 +2,61 @@
|
||||||
|
|
||||||
#include <helpers.hpp>
|
#include <helpers.hpp>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
|
||||||
constexpr auto schedulerMaxEntries = 64;
|
constexpr auto schedulerMaxEntries = 64;
|
||||||
|
|
||||||
|
// https://stackoverflow.com/questions/19467485/how-to-remove-element-not-at-top-from-priority-queue
|
||||||
|
template<typename T>
|
||||||
|
class pqueue : public std::priority_queue<T, std::vector<T>, std::greater<T>> {
|
||||||
|
public:
|
||||||
|
std::vector<T>& get_container() {
|
||||||
|
return this->c;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool remove(const T& value) {
|
||||||
|
auto it = std::find(this->c.begin(), this->c.end(), value);
|
||||||
|
|
||||||
|
if (it == this->c.end()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (it == this->c.begin()) {
|
||||||
|
// Deque the top element
|
||||||
|
this->pop();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Remove element and re-heap
|
||||||
|
this->c.erase(it);
|
||||||
|
std::make_heap(this->c.begin(), this->c.end(), this->comp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class Scheduler {
|
class Scheduler {
|
||||||
public:
|
public:
|
||||||
u64 time = 0;
|
u64 time = 0;
|
||||||
void tick(u64 cycles);
|
void tick(u64 cycles);
|
||||||
|
|
||||||
struct Event {
|
struct Event {
|
||||||
void (*functionPtr)(void*);
|
void (*functionPtr)(void*) = nullptr;
|
||||||
void* data;
|
void* data = nullptr;
|
||||||
u64 time;
|
u64 time = 0;
|
||||||
|
std::string name = "Default";
|
||||||
|
|
||||||
|
bool operator==(const Event& other) const {
|
||||||
|
return (functionPtr == other.functionPtr) && (data == other.data) && (time == other.time) && (name == other.name);
|
||||||
|
}
|
||||||
|
|
||||||
bool operator>(const Event& other) const {
|
bool operator>(const Event& other) const {
|
||||||
return time > other.time;
|
return time > other.time;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::priority_queue<Event, std::vector<Event>, std::greater<Event>> events;
|
pqueue<Event> events;
|
||||||
void push(void (*functionPtr)(void*), u64 time, void* data);
|
void push(void (*functionPtr)(void*), u64 time, void* data, std::string name = "Default");
|
||||||
|
void deleteAllEventsOfName(std::string name);
|
||||||
};
|
};
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
using namespace Test;
|
using namespace Test;
|
||||||
|
|
||||||
Diff::Diff(const fs::path& biosPath) : p1(biosPath), p2(biosPath) {
|
Diff::Diff(const fs::path& biosPath, const fs::path& cdPath) : p1(biosPath, cdPath), p2(biosPath, cdPath) {
|
||||||
p1.switchCpuBackend(Cpu::Backend::Interpreter);
|
p1.switchCpuBackend(Cpu::Backend::Interpreter);
|
||||||
p2.switchCpuBackend(Cpu::Backend::OldInterpreter);
|
p2.switchCpuBackend(Cpu::Backend::OldInterpreter);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
namespace Test {
|
namespace Test {
|
||||||
class Diff {
|
class Diff {
|
||||||
public:
|
public:
|
||||||
Diff(const fs::path& biosPath);
|
Diff(const fs::path& biosPath, const fs::path& cdPath);
|
||||||
void doTest();
|
void doTest();
|
||||||
private:
|
private:
|
||||||
PlayStation p1;
|
PlayStation p1;
|
||||||
|
|
Loading…
Reference in a new issue