#include #include namespace n64 { u32 extraCycles = 0; void CpuStall(u32 cycles) { extraCycles += cycles; } u32 PopStalledCycles() { u32 ret = extraCycles; extraCycles = 0; return ret; } Core::Core() { if(SDL_GameControllerAddMappingsFromFile("resources/gamecontrollerdb.txt") < 0) { Util::warn("Failed to load game controller DB"); } cpu = std::make_unique(); } void Core::Stop() { pause = true; romLoaded = false; cpu->Reset(); cpu->mem.Reset(); } void Core::LoadROM(const std::string& rom_) { pause = true; rom = rom_; cpu->Reset(); romLoaded = true; std::string archive_types[] = {".zip",".7z",".rar",".tar"}; auto extension = fs::path(rom).extension().string(); bool isArchive = std::any_of(std::begin(archive_types), std::end(archive_types), [&extension](const auto& e) { return e == extension; }); cpu->mem.LoadROM(isArchive, rom); GameDB::match(cpu->mem); cpu->mem.mmio.vi.isPal = cpu->mem.IsROMPAL(); cpu->mem.mmio.si.pif.InitDevices(cpu->mem.saveType); cpu->mem.mmio.si.pif.mempakPath = rom; cpu->mem.mmio.si.pif.LoadEeprom(cpu->mem.saveType, rom); cpu->mem.flash.Load(cpu->mem.saveType, rom); cpu->mem.LoadSRAM(cpu->mem.saveType, rom); PIF::ExecutePIF(cpu->mem, cpu->regs); pause = false; } void Core::Run(float volumeL, float volumeR) { Mem& mem = cpu->mem; MMIO& mmio = mem.mmio; Registers& regs = cpu->regs; for (int field = 0; field < mmio.vi.numFields; field++) { u32 frameCycles = 0; for (int i = 0; i < mmio.vi.numHalflines; i++) { mmio.vi.current = (i << 1) + field; if ((mmio.vi.current & 0x3FE) == mmio.vi.intr) { InterruptRaise(mmio.mi, regs, Interrupt::VI); } for(; cycles < mem.mmio.vi.cyclesPerHalfline; cycles++, frameCycles++) { u32 taken = cpu->Step(); taken += PopStalledCycles(); static u32 cpuSteps = 0; cpuSteps += taken; if(mmio.rsp.spStatus.halt) { cpuSteps = 0; mmio.rsp.steps = 0; } else { while(cpuSteps > 2) { mmio.rsp.steps += 2; cpuSteps -= 3; } while(mmio.rsp.steps > 0) { mmio.rsp.steps--; mmio.rsp.Step(regs, mem); } } cycles += taken; frameCycles += taken; scheduler.tick(taken, mem, regs); } cycles -= mmio.vi.cyclesPerHalfline; } if ((mmio.vi.current & 0x3FE) == mmio.vi.intr) { InterruptRaise(mmio.mi, regs, Interrupt::VI); } mmio.ai.Step(cpu->mem, regs, frameCycles, volumeL, volumeR); scheduler.tick(frameCycles, mem, regs); } } void Core::Serialize() { auto sMEM = cpu->mem.Serialize(); auto sCPU = cpu->Serialize(); auto sVER = std::vector{KAIZEN_VERSION >> 8, KAIZEN_VERSION >> 4, KAIZEN_VERSION & 0xFF}; memSize = sMEM.size(); cpuSize = sCPU.size(); verSize = sVER.size(); serialized[slot].insert(serialized[slot].begin(), sVER.begin(), sVER.end()); serialized[slot].insert(serialized[slot].end(), sMEM.begin(), sMEM.end()); serialized[slot].insert(serialized[slot].end(), sCPU.begin(), sCPU.end()); } void Core::Deserialize() { std::vector dVER(serialized[slot].begin(), serialized[slot].begin() + verSize); if(dVER[0] != (KAIZEN_VERSION >> 8) || dVER[1] != (KAIZEN_VERSION >> 4) || dVER[2] != (KAIZEN_VERSION & 0xFF)) { Util::panic("PROBLEMI!"); } cpu->mem.Deserialize(std::vector(serialized[slot].begin() + verSize, serialized[slot].begin() + verSize + memSize)); cpu->Deserialize(std::vector(serialized[slot].begin() + verSize + memSize, serialized[slot].begin() + verSize + memSize + cpuSize)); serialized[slot].erase(serialized[slot].begin(), serialized[slot].end()); } }