BizHawk/waterbox/bsnescore/bsnes/sfc/cpu/cpu.cpp

137 lines
3.5 KiB
C++

#include <sfc/sfc.hpp>
namespace SuperFamicom {
CPU cpu;
#include "dma.cpp"
#include "memory.cpp"
#include "io.cpp"
#include "timing.cpp"
#include "irq.cpp"
#include "serialization.cpp"
auto CPU::synchronizeSMP() -> void {
if(smp.clock < 0) scheduler.resume(smp.thread);
}
auto CPU::synchronizePPU() -> void {
if(ppu.clock < 0) scheduler.resume(ppu.thread);
}
auto CPU::synchronizeCoprocessors() -> void {
for(auto coprocessor : coprocessors) {
if(coprocessor->clock < 0) scheduler.resume(coprocessor->thread);
}
}
auto CPU::Enter() -> void {
while(true) {
scheduler.synchronize();
cpu.main();
if (scheduler.StepOnce) {
scheduler.StepOnce = false;
scheduler.leave(Scheduler::Event::Desynchronized);
}
}
}
auto CPU::main() -> void {
if(r.wai) return instructionWait();
if(r.stp) return instructionStop();
if(!status.interruptPending) {
if (__builtin_expect(platform->executeHookEnabled, 0))
platform->execHook(cpu.r.pc.d);
if (platform->traceEnabled) {
vector<string> disassembly = disassemble();
disassembly[1].append(" V:", hex(cpu.vcounter(), 3), " H:", hex(cpu.hdot(), 3));
platform->cpuTrace(disassembly);
}
return instruction();
}
if(status.nmiPending) {
status.nmiPending = 0;
r.vector = r.e ? 0xfffa : 0xffea;
return interrupt();
}
if(status.irqPending) {
status.irqPending = 0;
r.vector = r.e ? 0xfffe : 0xffee;
return interrupt();
}
if(status.resetPending) {
status.resetPending = 0;
for(uint repeat : range(22)) step<6,0>(); //step(132);
r.vector = 0xfffc;
return interrupt();
}
status.interruptPending = 0;
}
auto CPU::load() -> bool {
version = configuration.system.cpu.version;
if(version < 1) version = 1;
if(version > 2) version = 2;
return true;
}
auto CPU::power(bool reset) -> void {
WDC65816::power();
Thread::create(Enter, system.cpuFrequency());
coprocessors.reset();
PPUcounter::reset();
PPUcounter::scanline = {&CPU::scanline, this};
function<uint8 (uint, uint8)> reader;
function<void (uint, uint8)> writer;
reader = {&CPU::readRAM, this};
writer = {&CPU::writeRAM, this};
bus.map(reader, writer, "00-3f,80-bf:0000-1fff", true, 0x2000);
bus.map(reader, writer, "7e-7f:0000-ffff", true, 0x20000);
reader = {&CPU::readAPU, this};
writer = {&CPU::writeAPU, this};
bus.map(reader, writer, "00-3f,80-bf:2140-217f", false);
reader = {&CPU::readCPU, this};
writer = {&CPU::writeCPU, this};
bus.map(reader, writer, "00-3f,80-bf:2180-2183,4016-4017,4200-421f", false);
reader = {&CPU::readDMA, this};
writer = {&CPU::writeDMA, this};
bus.map(reader, writer, "00-3f,80-bf:4300-437f", true);
if(!reset) random.array(wram, sizeof(wram));
if(configuration.hacks.hotfixes) {
//Dirt Racer (Europe) relies on uninitialized memory containing certain values to boot without freezing.
//the game itself is broken and will fail to run sometimes on real hardware, but for the sake of expedience,
//WRAM is initialized to a constant value that will allow this game to always boot in successfully.
if(cartridge.headerTitle() == "DIRT RACER") {
for(auto& byte : wram) byte = 0xff;
}
}
for(uint n : range(8)) {
channels[n] = {};
if(n != 7) channels[n].next = channels[n + 1];
}
counter = {};
io = {};
alu = {};
status = {};
status.dramRefreshPosition = (version == 1 ? 530 : 538);
status.hdmaSetupPosition = (version == 1 ? 12 + 8 - dmaCounter() : 12 + dmaCounter());
status.hdmaPosition = 1104;
status.resetPending = 1;
status.interruptPending = 1;
}
}