140 lines
3.7 KiB
C++
140 lines
3.7 KiB
C++
#include <Core.hpp>
|
|
#include <ParallelRDPWrapper.hpp>
|
|
#include <Scheduler.hpp>
|
|
#include <Options.hpp>
|
|
|
|
namespace n64 {
|
|
Core::Core() :
|
|
interpreter(*mem, regs)
|
|
#ifdef KAIZEN_JIT_ENABLED
|
|
,
|
|
jit(*mem, regs)
|
|
#endif
|
|
{
|
|
const auto selectedCpu = Options::GetInstance().GetValue<std::string>("cpu", "type");
|
|
if (selectedCpu == "interpreter") {
|
|
cpuType = Interpreted;
|
|
} else if (selectedCpu == "jit") {
|
|
cpuType = DynamicRecompiler;
|
|
} else if (selectedCpu == "cached_interpreter") {
|
|
cpuType = CachedInterpreter;
|
|
} else {
|
|
panic("Unimplemented CPU type");
|
|
}
|
|
}
|
|
|
|
void Core::Stop() {
|
|
pause = true;
|
|
romLoaded = false;
|
|
Reset();
|
|
}
|
|
|
|
void Core::Reset() {
|
|
regs.Reset();
|
|
mem->Reset();
|
|
interpreter.Reset();
|
|
if (romLoaded)
|
|
mem->mmio.si.pif.Execute();
|
|
}
|
|
|
|
void Core::LoadTAS(const fs::path &path) const { mem->mmio.si.pif.movie.Load(path); }
|
|
|
|
void Core::LoadROM(const std::string &rom_) {
|
|
Stop();
|
|
rom = rom_;
|
|
|
|
std::string archive_types[] = {".zip", ".7z", ".rar", ".tar"};
|
|
|
|
auto extension = fs::path(rom).extension().string();
|
|
const bool isArchive = std::ranges::any_of(archive_types, [&extension](const auto &e) { return e == extension; });
|
|
|
|
mem->LoadROM(isArchive, rom);
|
|
GameDB::match();
|
|
if (mem->rom.gameNameDB.empty()) {
|
|
mem->rom.gameNameDB = fs::path(rom).stem().string();
|
|
}
|
|
mem->mmio.vi.isPal = mem->IsROMPAL();
|
|
mem->mmio.si.pif.InitDevices(mem->saveType);
|
|
mem->mmio.si.pif.mempakPath = rom;
|
|
mem->mmio.si.pif.LoadEeprom(mem->saveType, rom);
|
|
mem->flash.Load(mem->saveType, rom);
|
|
mem->LoadSRAM(mem->saveType, rom);
|
|
mem->mmio.si.pif.Execute();
|
|
pause = false;
|
|
romLoaded = true;
|
|
}
|
|
|
|
u32 Core::StepCPU() {
|
|
if (cpuType == Interpreted) {
|
|
auto taken = interpreter.Step() + regs.PopStalledCycles();
|
|
StepRSP(taken);
|
|
return taken;
|
|
}
|
|
|
|
if (cpuType == CachedInterpreter)
|
|
return interpreter.ExecuteCached() + regs.PopStalledCycles();
|
|
|
|
#ifdef KAIZEN_JIT_ENABLED
|
|
if (cpuType == DynamicRecompiler)
|
|
return jit.Step() + regs.PopStalledCycles();
|
|
#endif
|
|
|
|
panic("Invalid CPU type?");
|
|
}
|
|
|
|
void Core::StepRSP(const u32 cpuCycles) {
|
|
MMIO &mmio = mem->mmio;
|
|
|
|
if (mmio.rsp.spStatus.halt) {
|
|
regs.steps = 0;
|
|
mmio.rsp.steps = 0;
|
|
return;
|
|
}
|
|
|
|
static constexpr u32 cpuRatio = 3, rspRatio = 2;
|
|
|
|
regs.steps += cpuCycles;
|
|
const auto sets = regs.steps / cpuRatio;
|
|
mmio.rsp.steps += sets * rspRatio;
|
|
regs.steps -= sets * cpuRatio;
|
|
|
|
while (mmio.rsp.steps > 0) {
|
|
mmio.rsp.steps--;
|
|
mmio.rsp.Step();
|
|
}
|
|
}
|
|
|
|
void Core::Run(const float volumeL, const float volumeR) {
|
|
MMIO &mmio = mem->mmio;
|
|
|
|
bool broken = false;
|
|
for (int field = 0; field < mmio.vi.numFields; field++) {
|
|
Scheduler::GetInstance().HandleEvents();
|
|
u32 frameCycles = 0;
|
|
for (int halfline = 0; halfline < mmio.vi.numHalflines; halfline++) {
|
|
mmio.vi.current = (halfline << 1) + field;
|
|
|
|
if ((mmio.vi.current & 0x3FE) == mmio.vi.intr) {
|
|
mmio.mi.InterruptRaise(MI::Interrupt::VI);
|
|
}
|
|
|
|
for (int cycles = 0; cycles < mem->mmio.vi.cyclesPerHalfline;) {
|
|
Scheduler::GetInstance().HandleEvents();
|
|
|
|
const u32 taken = StepCPU();
|
|
cycles += taken;
|
|
frameCycles += taken;
|
|
Scheduler::GetInstance().Tick(taken);
|
|
}
|
|
}
|
|
|
|
if ((mmio.vi.current & 0x3FE) == mmio.vi.intr) {
|
|
mmio.mi.InterruptRaise(MI::Interrupt::VI);
|
|
}
|
|
|
|
mmio.ai.Step(frameCycles, volumeL, volumeR);
|
|
Scheduler::GetInstance().Tick(frameCycles);
|
|
}
|
|
}
|
|
} // namespace n64
|