prep cache impl
This commit is contained in:
@@ -0,0 +1,4 @@
|
|||||||
|
CompileFlags:
|
||||||
|
CompilationDatabase: build/
|
||||||
|
Completion:
|
||||||
|
HeaderInsertion: Never
|
||||||
+91
-93
@@ -5,132 +5,130 @@
|
|||||||
|
|
||||||
namespace n64 {
|
namespace n64 {
|
||||||
Core::Core() {
|
Core::Core() {
|
||||||
const auto selectedCpu = Options::GetInstance().GetValue<std::string>("cpu", "type");
|
const auto selectedCpu = Options::GetInstance().GetValue<std::string>("cpu", "type");
|
||||||
if (selectedCpu == "interpreter") {
|
if (selectedCpu == "interpreter") {
|
||||||
cpuType = Interpreted;
|
cpuType = Interpreted;
|
||||||
cpu = std::make_unique<Interpreter>(*mem, regs);
|
cpu = std::make_unique<Interpreter>(*mem, regs);
|
||||||
} else if(selectedCpu == "jit") {
|
} else if (selectedCpu == "jit") {
|
||||||
#ifndef __aarch64__
|
#ifndef __aarch64__
|
||||||
cpuType = DynamicRecompiler;
|
cpuType = DynamicRecompiler;
|
||||||
cpu = std::make_unique<JIT>(*mem, regs);
|
cpu = std::make_unique<JIT>(*mem, regs);
|
||||||
#else
|
#else
|
||||||
panic("JIT currently unsupported on aarch64");
|
panic("JIT currently unsupported on aarch64");
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
panic("Unimplemented CPU type");
|
panic("Unimplemented CPU type");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Stop() {
|
void Core::Stop() {
|
||||||
pause = true;
|
pause = true;
|
||||||
romLoaded = false;
|
romLoaded = false;
|
||||||
Reset();
|
Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Reset() {
|
void Core::Reset() {
|
||||||
regs.Reset();
|
regs.Reset();
|
||||||
mem->Reset();
|
mem->Reset();
|
||||||
cpu->Reset();
|
cpu->Reset();
|
||||||
if(romLoaded)
|
if (romLoaded)
|
||||||
mem->mmio.si.pif.Execute();
|
mem->mmio.si.pif.Execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::LoadTAS(const fs::path &path) const { mem->mmio.si.pif.movie.Load(path); }
|
void Core::LoadTAS(const fs::path &path) const { mem->mmio.si.pif.movie.Load(path); }
|
||||||
|
|
||||||
void Core::LoadROM(const std::string &rom_) {
|
void Core::LoadROM(const std::string &rom_) {
|
||||||
Stop();
|
Stop();
|
||||||
rom = rom_;
|
rom = rom_;
|
||||||
|
|
||||||
std::string archive_types[] = {".zip", ".7z", ".rar", ".tar"};
|
std::string archive_types[] = {".zip", ".7z", ".rar", ".tar"};
|
||||||
|
|
||||||
auto extension = fs::path(rom).extension().string();
|
auto extension = fs::path(rom).extension().string();
|
||||||
const bool isArchive = std::ranges::any_of(archive_types, [&extension](const auto &e) { return e == extension; });
|
const bool isArchive = std::ranges::any_of(archive_types, [&extension](const auto &e) { return e == extension; });
|
||||||
|
|
||||||
mem->LoadROM(isArchive, rom);
|
mem->LoadROM(isArchive, rom);
|
||||||
GameDB::match();
|
GameDB::match();
|
||||||
if (mem->rom.gameNameDB.empty()) {
|
if (mem->rom.gameNameDB.empty()) {
|
||||||
mem->rom.gameNameDB = fs::path(rom).stem().string();
|
mem->rom.gameNameDB = fs::path(rom).stem().string();
|
||||||
}
|
}
|
||||||
mem->mmio.vi.isPal = mem->IsROMPAL();
|
mem->mmio.vi.isPal = mem->IsROMPAL();
|
||||||
mem->mmio.si.pif.InitDevices(mem->saveType);
|
mem->mmio.si.pif.InitDevices(mem->saveType);
|
||||||
mem->mmio.si.pif.mempakPath = rom;
|
mem->mmio.si.pif.mempakPath = rom;
|
||||||
mem->mmio.si.pif.LoadEeprom(mem->saveType, rom);
|
mem->mmio.si.pif.LoadEeprom(mem->saveType, rom);
|
||||||
mem->flash.Load(mem->saveType, rom);
|
mem->flash.Load(mem->saveType, rom);
|
||||||
mem->LoadSRAM(mem->saveType, rom);
|
mem->LoadSRAM(mem->saveType, rom);
|
||||||
mem->mmio.si.pif.Execute();
|
mem->mmio.si.pif.Execute();
|
||||||
pause = false;
|
pause = false;
|
||||||
romLoaded = true;
|
romLoaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 Core::StepCPU() {
|
u32 Core::StepCPU() { return cpu->Step() + regs.PopStalledCycles(); }
|
||||||
return cpu->Step() + regs.PopStalledCycles();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Core::StepRSP(const u32 cpuCycles) {
|
void Core::StepRSP(const u32 cpuCycles) {
|
||||||
MMIO &mmio = mem->mmio;
|
MMIO &mmio = mem->mmio;
|
||||||
|
|
||||||
if (mmio.rsp.spStatus.halt) {
|
if (mmio.rsp.spStatus.halt) {
|
||||||
regs.steps = 0;
|
regs.steps = 0;
|
||||||
mmio.rsp.steps = 0;
|
mmio.rsp.steps = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr u32 cpuRatio = 3, rspRatio = 2;
|
static constexpr u32 cpuRatio = 3, rspRatio = 2;
|
||||||
|
|
||||||
regs.steps += cpuCycles;
|
regs.steps += cpuCycles;
|
||||||
const auto sets = regs.steps / cpuRatio;
|
const auto sets = regs.steps / cpuRatio;
|
||||||
mmio.rsp.steps += sets * rspRatio;
|
mmio.rsp.steps += sets * rspRatio;
|
||||||
regs.steps -= sets * cpuRatio;
|
regs.steps -= sets * cpuRatio;
|
||||||
|
|
||||||
while (mmio.rsp.steps > 0) {
|
while (mmio.rsp.steps > 0) {
|
||||||
mmio.rsp.steps--;
|
mmio.rsp.steps--;
|
||||||
mmio.rsp.Step();
|
mmio.rsp.Step();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Run(const float volumeL, const float volumeR) {
|
void Core::Run(const float volumeL, const float volumeR) {
|
||||||
MMIO &mmio = mem->mmio;
|
MMIO &mmio = mem->mmio;
|
||||||
|
|
||||||
bool broken = false;
|
bool broken = false;
|
||||||
for (int field = 0; field < mmio.vi.numFields; field++) {
|
for (int field = 0; field < mmio.vi.numFields; field++) {
|
||||||
u32 frameCycles = 0;
|
u32 frameCycles = 0;
|
||||||
for (int i = 0; i < mmio.vi.numHalflines; i++) {
|
for (int i = 0; i < mmio.vi.numHalflines; i++) {
|
||||||
mmio.vi.current = (i << 1) + field;
|
mmio.vi.current = (i << 1) + field;
|
||||||
|
|
||||||
if ((mmio.vi.current & 0x3FE) == mmio.vi.intr) {
|
if ((mmio.vi.current & 0x3FE) == mmio.vi.intr) {
|
||||||
mmio.mi.InterruptRaise(MI::Interrupt::VI);
|
mmio.mi.InterruptRaise(MI::Interrupt::VI);
|
||||||
}
|
}
|
||||||
|
|
||||||
while(cycles < mem->mmio.vi.cyclesPerHalfline) {
|
while (cycles < mem->mmio.vi.cyclesPerHalfline) {
|
||||||
const u32 taken = StepCPU();
|
const u32 taken = StepCPU();
|
||||||
cycles += taken;
|
cycles += taken;
|
||||||
|
|
||||||
if((broken = breakpoints.contains(regs.nextPC)))
|
if ((broken = breakpoints.contains(regs.nextPC)))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
StepRSP(taken);
|
StepRSP(taken);
|
||||||
frameCycles += taken;
|
frameCycles += taken;
|
||||||
Scheduler::GetInstance().Tick(taken);
|
Scheduler::GetInstance().Tick(taken);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(broken)
|
if (broken)
|
||||||
break;
|
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)
|
if (broken)
|
||||||
break;
|
pause = true;
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
} // namespace n64
|
} // namespace n64
|
||||||
|
|||||||
@@ -4,9 +4,30 @@
|
|||||||
#include <Disassembler.hpp>
|
#include <Disassembler.hpp>
|
||||||
|
|
||||||
namespace n64 {
|
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 {
|
struct BaseCPU {
|
||||||
virtual ~BaseCPU() = default;
|
virtual ~BaseCPU() = default;
|
||||||
virtual u32 Step() = 0;
|
virtual u32 Step() = 0;
|
||||||
virtual void Reset() = 0;
|
virtual void Reset() = 0;
|
||||||
};
|
};
|
||||||
} // namespace n64
|
} // namespace n64
|
||||||
|
|||||||
+10
-10
@@ -17,19 +17,19 @@ constexpr u32 N64_CPU_FREQ = 93750000;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
static FORCE_INLINE constexpr u32 GetCyclesPerFrame(bool pal) {
|
static FORCE_INLINE constexpr u32 GetCyclesPerFrame(bool pal) {
|
||||||
if (pal) {
|
if (pal) {
|
||||||
return N64_CPU_FREQ / 50;
|
return N64_CPU_FREQ / 50;
|
||||||
} else {
|
} else {
|
||||||
return N64_CPU_FREQ / 60;
|
return N64_CPU_FREQ / 60;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static FORCE_INLINE constexpr u32 GetVideoFrequency(bool pal) {
|
static FORCE_INLINE constexpr u32 GetVideoFrequency(bool pal) {
|
||||||
if (pal) {
|
if (pal) {
|
||||||
return 49'656'530;
|
return 49'656'530;
|
||||||
} else {
|
} else {
|
||||||
return 48'681'812;
|
return 48'681'812;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define HALF_ADDRESS(addr) ((addr) ^ 2)
|
#define HALF_ADDRESS(addr) ((addr) ^ 2)
|
||||||
|
|||||||
Reference in New Issue
Block a user