diff --git a/.clangd b/.clangd new file mode 100644 index 0000000..ab1a655 --- /dev/null +++ b/.clangd @@ -0,0 +1,4 @@ +CompileFlags: + CompilationDatabase: build/ +Completion: + HeaderInsertion: Never diff --git a/src/backend/Core.cpp b/src/backend/Core.cpp index e3edd5e..de5e4e2 100644 --- a/src/backend/Core.cpp +++ b/src/backend/Core.cpp @@ -5,132 +5,130 @@ namespace n64 { Core::Core() { - const auto selectedCpu = Options::GetInstance().GetValue("cpu", "type"); - if (selectedCpu == "interpreter") { - cpuType = Interpreted; - cpu = std::make_unique(*mem, regs); - } else if(selectedCpu == "jit") { - #ifndef __aarch64__ - cpuType = DynamicRecompiler; - cpu = std::make_unique(*mem, regs); - #else - panic("JIT currently unsupported on aarch64"); - #endif - } else { - panic("Unimplemented CPU type"); - } + const auto selectedCpu = Options::GetInstance().GetValue("cpu", "type"); + if (selectedCpu == "interpreter") { + cpuType = Interpreted; + cpu = std::make_unique(*mem, regs); + } else if (selectedCpu == "jit") { +#ifndef __aarch64__ + cpuType = DynamicRecompiler; + cpu = std::make_unique(*mem, regs); +#else + panic("JIT currently unsupported on aarch64"); +#endif + } else { + panic("Unimplemented CPU type"); + } } void Core::Stop() { - pause = true; - romLoaded = false; - Reset(); + pause = true; + romLoaded = false; + Reset(); } void Core::Reset() { - regs.Reset(); - mem->Reset(); - cpu->Reset(); - if(romLoaded) - mem->mmio.si.pif.Execute(); + regs.Reset(); + mem->Reset(); + cpu->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; + 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() { - return cpu->Step() + regs.PopStalledCycles(); -} +u32 Core::StepCPU() { return cpu->Step() + regs.PopStalledCycles(); } void Core::StepRSP(const u32 cpuCycles) { - MMIO &mmio = mem->mmio; + MMIO &mmio = mem->mmio; - if (mmio.rsp.spStatus.halt) { - regs.steps = 0; - mmio.rsp.steps = 0; - return; - } + 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; + static constexpr u32 cpuRatio = 3, rspRatio = 2; - while (mmio.rsp.steps > 0) { - mmio.rsp.steps--; - mmio.rsp.Step(); - } + 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; + MMIO &mmio = mem->mmio; - bool broken = false; - 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; + bool broken = false; + 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) { - mmio.mi.InterruptRaise(MI::Interrupt::VI); - } + if ((mmio.vi.current & 0x3FE) == mmio.vi.intr) { + mmio.mi.InterruptRaise(MI::Interrupt::VI); + } - while(cycles < mem->mmio.vi.cyclesPerHalfline) { - const u32 taken = StepCPU(); - cycles += taken; + while (cycles < mem->mmio.vi.cyclesPerHalfline) { + const u32 taken = StepCPU(); + cycles += taken; - if((broken = breakpoints.contains(regs.nextPC))) - break; + if ((broken = breakpoints.contains(regs.nextPC))) + break; - StepRSP(taken); - frameCycles += taken; - Scheduler::GetInstance().Tick(taken); - } + StepRSP(taken); + frameCycles += taken; + Scheduler::GetInstance().Tick(taken); + } - if(broken) - break; + if (broken) + break; - cycles -= mmio.vi.cyclesPerHalfline; + cycles -= mmio.vi.cyclesPerHalfline; + } + + if (broken) + break; + + if ((mmio.vi.current & 0x3FE) == mmio.vi.intr) { + mmio.mi.InterruptRaise(MI::Interrupt::VI); + } + + mmio.ai.Step(frameCycles, volumeL, volumeR); + Scheduler::GetInstance().Tick(frameCycles); } - if(broken) - break; - - if ((mmio.vi.current & 0x3FE) == mmio.vi.intr) { - mmio.mi.InterruptRaise(MI::Interrupt::VI); - } - - mmio.ai.Step(frameCycles, volumeL, volumeR); - Scheduler::GetInstance().Tick(frameCycles); - } - - if(broken) - pause = true; + if (broken) + pause = true; } } // namespace n64 diff --git a/src/backend/core/BaseCPU.hpp b/src/backend/core/BaseCPU.hpp index 0b4d01c..c69448f 100644 --- a/src/backend/core/BaseCPU.hpp +++ b/src/backend/core/BaseCPU.hpp @@ -4,9 +4,30 @@ #include namespace n64 { +struct alignas(32) InstructionCache { + bool valid; + u32 data[8]; + u32 ptag; + + private: + int GetLineIndex(u64 vaddr) { return (vaddr >> 5) & 0x1FF; } + u32 GetLineStart(u64 paddr) { return paddr & ~0x1F; } +}; + +struct alignas(32) DataCache { + bool valid, dirty; + u8 data[16]; + u32 ptag; + int index; + + private: + int GetLineIndex(u64 vaddr) { return (vaddr >> 4) & 0x1FF; } + u32 GetLineStart(u64 paddr) { return paddr & ~0xF; } +}; + struct BaseCPU { - virtual ~BaseCPU() = default; - virtual u32 Step() = 0; - virtual void Reset() = 0; + virtual ~BaseCPU() = default; + virtual u32 Step() = 0; + virtual void Reset() = 0; }; } // namespace n64 diff --git a/src/common.hpp b/src/common.hpp index b1813c5..8286d5a 100644 --- a/src/common.hpp +++ b/src/common.hpp @@ -17,19 +17,19 @@ constexpr u32 N64_CPU_FREQ = 93750000; #endif static FORCE_INLINE constexpr u32 GetCyclesPerFrame(bool pal) { - if (pal) { - return N64_CPU_FREQ / 50; - } else { - return N64_CPU_FREQ / 60; - } + if (pal) { + return N64_CPU_FREQ / 50; + } else { + return N64_CPU_FREQ / 60; + } } static FORCE_INLINE constexpr u32 GetVideoFrequency(bool pal) { - if (pal) { - return 49'656'530; - } else { - return 48'681'812; - } + if (pal) { + return 49'656'530; + } else { + return 48'681'812; + } } #define HALF_ADDRESS(addr) ((addr) ^ 2)