get rid of JIT and other things
This commit is contained in:
@@ -49,7 +49,6 @@ add_subdirectory(frontend)
|
||||
add_subdirectory(frontend/imgui)
|
||||
add_subdirectory(backend)
|
||||
add_subdirectory(backend/core)
|
||||
add_subdirectory(backend/core/jit)
|
||||
add_subdirectory(backend/core/interpreter)
|
||||
add_subdirectory(backend/core/mmio)
|
||||
add_subdirectory(backend/core/registers)
|
||||
@@ -68,7 +67,7 @@ file(REMOVE
|
||||
${PROJECT_BINARY_DIR}/resources/shader.vert)
|
||||
|
||||
target_link_libraries(kaizen PUBLIC frontend frontend-imgui
|
||||
discord-rpc imgui nfd parallel-rdp backend fmt::fmt nlohmann_json::nlohmann_json core jit registers interpreter mmio rsp SDL2::SDL2main SDL2::SDL2)
|
||||
discord-rpc imgui nfd parallel-rdp backend fmt::fmt nlohmann_json::nlohmann_json core registers interpreter mmio rsp SDL2::SDL2main SDL2::SDL2)
|
||||
|
||||
if(WIN32)
|
||||
target_compile_definitions(kaizen PUBLIC NOMINMAX _CRT_SECURE_NO_WARNINGS)
|
||||
|
||||
@@ -11,59 +11,75 @@ Core::Core() {
|
||||
}
|
||||
|
||||
void Core::Stop() {
|
||||
cpu->Reset();
|
||||
cpu->mem.Reset();
|
||||
cpu.Reset();
|
||||
cpu.mem.Reset();
|
||||
pause = true;
|
||||
romLoaded = false;
|
||||
}
|
||||
|
||||
void Core::LoadROM(const std::string& rom_) {
|
||||
rom = rom_;
|
||||
cpu->Reset();
|
||||
cpu->mem.Reset();
|
||||
cpu.Reset();
|
||||
cpu.mem.Reset();
|
||||
pause = false;
|
||||
romLoaded = true;
|
||||
|
||||
cpu->mem.LoadROM(rom);
|
||||
GameDB::match(cpu->mem);
|
||||
cpu->mem.mmio.si.pif.InitDevices(cpu->mem.saveType);
|
||||
cpu->mem.mmio.si.pif.LoadMempak(rom_);
|
||||
cpu->mem.mmio.si.pif.LoadEeprom(cpu->mem.saveType, rom_);
|
||||
isPAL = cpu->mem.IsROMPAL();
|
||||
cpu->mem.mmio.si.pif.ExecutePIF(cpu->mem, cpu->regs);
|
||||
cpu.mem.LoadROM(rom);
|
||||
GameDB::match(cpu.mem);
|
||||
cpu.mem.mmio.si.pif.InitDevices(cpu.mem.saveType);
|
||||
cpu.mem.mmio.si.pif.LoadMempak(rom_);
|
||||
cpu.mem.mmio.si.pif.LoadEeprom(cpu.mem.saveType, rom_);
|
||||
isPAL = cpu.mem.IsROMPAL();
|
||||
cpu.mem.mmio.vi.isPal = isPAL;
|
||||
cpu.mem.mmio.si.pif.ExecutePIF(cpu.mem, cpu.regs);
|
||||
}
|
||||
|
||||
void Core::Run(Window& window, float volumeL, float volumeR) {
|
||||
MMIO& mmio = cpu->mem.mmio;
|
||||
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++) {
|
||||
if (!pause && romLoaded) {
|
||||
int 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, cpu->regs, Interrupt::VI);
|
||||
}
|
||||
|
||||
int cpuCount = cpu->Run();
|
||||
cpu->RunRSP(cpuCount);
|
||||
frameCycles += cpuCount;
|
||||
}
|
||||
int 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, cpu->regs, Interrupt::VI);
|
||||
InterruptRaise(mmio.mi, regs, Interrupt::VI);
|
||||
}
|
||||
|
||||
UpdateScreenParallelRdp(*this, window, GetVI());
|
||||
for(; cycles < mem.mmio.vi.cyclesPerHalfline; cycles++, frameCycles++) {
|
||||
int taken = cpu.Step();
|
||||
static int 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;
|
||||
}
|
||||
|
||||
mmio.ai.Step(cpu->mem, cpu->regs, frameCycles, volumeL, volumeR);
|
||||
scheduler.tick(frameCycles, cpu->mem, cpu->regs);
|
||||
} else if (pause && romLoaded) {
|
||||
UpdateScreenParallelRdp(*this, window, GetVI());
|
||||
} else if (pause && !romLoaded) {
|
||||
UpdateScreenParallelRdpNoGame(*this, window);
|
||||
while(mmio.rsp.steps > 0) {
|
||||
mmio.rsp.steps--;
|
||||
mmio.rsp.Step(regs, mem);
|
||||
}
|
||||
}
|
||||
|
||||
cycles += taken;
|
||||
frameCycles += taken;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,36 +3,29 @@
|
||||
#include <backend/core/Interpreter.hpp>
|
||||
#include <backend/core/Mem.hpp>
|
||||
#include <string>
|
||||
#include <backend/core/JIT.hpp>
|
||||
#include <backend/core/registers/Registers.hpp>
|
||||
#include <Debugger.hpp>
|
||||
#include <SDL2/SDL_timer.h>
|
||||
|
||||
struct Window;
|
||||
|
||||
namespace n64 {
|
||||
enum class CpuType {
|
||||
Interpreter, JIT, COUNT
|
||||
};
|
||||
|
||||
struct Core {
|
||||
~Core() { Stop(); }
|
||||
Core();
|
||||
void Stop();
|
||||
void LoadROM(const std::string&);
|
||||
void Run(Window&, float volumeL, float volumeR);
|
||||
void Run(float volumeL, float volumeR);
|
||||
void TogglePause() { pause = !pause; }
|
||||
VI& GetVI() { return cpu->mem.mmio.vi; }
|
||||
VI& GetVI() { return cpu.mem.mmio.vi; }
|
||||
|
||||
u32 breakpoint = 0;
|
||||
|
||||
bool pause = true;
|
||||
int cycles = 0;
|
||||
bool isPAL = false;
|
||||
bool romLoaded = false;
|
||||
bool done = false;
|
||||
std::string rom;
|
||||
CpuType cpuType = CpuType::COUNT;
|
||||
std::unique_ptr<BaseCPU> cpu;
|
||||
Debugger debugger{*this};
|
||||
Interpreter cpu;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
#include <Debugger.hpp>
|
||||
@@ -1,32 +0,0 @@
|
||||
#pragma once
|
||||
#include <common.hpp>
|
||||
|
||||
struct Breakpoint {
|
||||
u32 address = 0;
|
||||
Breakpoint* next = nullptr;
|
||||
};
|
||||
|
||||
namespace n64 { struct Core; }
|
||||
|
||||
struct Debugger {
|
||||
Debugger(n64::Core& core) :core(core) {}
|
||||
~Debugger() = default;
|
||||
|
||||
bool broken = false, enabled = true;
|
||||
Breakpoint* breakpoints = nullptr;
|
||||
n64::Core& core;
|
||||
|
||||
[[nodiscard]] inline bool checkBreakpoint(u32 address) const {
|
||||
auto* cur = breakpoints;
|
||||
while (cur != nullptr) {
|
||||
if (cur->address == address) {
|
||||
return true;
|
||||
}
|
||||
cur = cur->next;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void tick() const {}
|
||||
void breakpointHit() {}
|
||||
};
|
||||
@@ -1,15 +0,0 @@
|
||||
#pragma once
|
||||
#include <Registers.hpp>
|
||||
|
||||
namespace n64 {
|
||||
struct BaseCPU {
|
||||
virtual ~BaseCPU() {}
|
||||
virtual void Reset() {}
|
||||
virtual int Run() {}
|
||||
void RunRSP(int cpuCount) {
|
||||
mem.mmio.rsp.Run(cpuCount, regs, mem);
|
||||
}
|
||||
Registers regs;
|
||||
Mem mem;
|
||||
};
|
||||
}
|
||||
@@ -1,59 +1,7 @@
|
||||
#include <Core.hpp>
|
||||
#include <log.hpp>
|
||||
|
||||
namespace n64 {
|
||||
inline bool ShouldServiceInterrupt(Registers& regs) {
|
||||
bool interrupts_pending = (regs.cop0.status.im & regs.cop0.cause.interruptPending) != 0;
|
||||
bool interrupts_enabled = regs.cop0.status.ie == 1;
|
||||
bool currently_handling_exception = regs.cop0.status.exl == 1;
|
||||
bool currently_handling_error = regs.cop0.status.erl == 1;
|
||||
|
||||
return interrupts_pending && interrupts_enabled &&
|
||||
!currently_handling_exception && !currently_handling_error;
|
||||
}
|
||||
|
||||
inline void CheckCompareInterrupt(MI& mi, Registers& regs) {
|
||||
regs.cop0.count++;
|
||||
regs.cop0.count &= 0x1FFFFFFFF;
|
||||
if(regs.cop0.count == (u64)regs.cop0.compare << 1) {
|
||||
regs.cop0.cause.ip7 = 1;
|
||||
UpdateInterrupt(mi, regs);
|
||||
}
|
||||
}
|
||||
|
||||
void Interpreter::Reset() {
|
||||
regs.Reset();
|
||||
}
|
||||
|
||||
int Interpreter::Run() {
|
||||
int cycles = 1;
|
||||
for(; cycles < mem.mmio.vi.cyclesPerHalfline; cycles++) {
|
||||
CheckCompareInterrupt(mem.mmio.mi, regs);
|
||||
|
||||
regs.prevDelaySlot = regs.delaySlot;
|
||||
regs.delaySlot = false;
|
||||
|
||||
u32 paddr = 0;
|
||||
if(!MapVAddr(regs, LOAD, regs.pc, paddr)) {
|
||||
HandleTLBException(regs, regs.pc);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, false);
|
||||
return cycles;
|
||||
}
|
||||
|
||||
u32 instruction = mem.Read32(regs, paddr);
|
||||
|
||||
if(ShouldServiceInterrupt(regs)) {
|
||||
FireException(regs, ExceptionCode::Interrupt, 0, false);
|
||||
return cycles;
|
||||
}
|
||||
|
||||
regs.oldPC = regs.pc;
|
||||
regs.pc = regs.nextPC;
|
||||
regs.nextPC += 4;
|
||||
|
||||
Exec(instruction);
|
||||
}
|
||||
|
||||
return cycles;
|
||||
}
|
||||
}
|
||||
@@ -2,19 +2,66 @@
|
||||
#include <core/registers/Registers.hpp>
|
||||
#include <Mem.hpp>
|
||||
#include <vector>
|
||||
#include <BaseCPU.hpp>
|
||||
|
||||
namespace n64 {
|
||||
struct Core;
|
||||
struct Interpreter : BaseCPU {
|
||||
struct Interpreter {
|
||||
Interpreter() = default;
|
||||
~Interpreter() = default;
|
||||
int Run() override;
|
||||
void Reset() override;
|
||||
FORCE_INLINE int Step() {
|
||||
CheckCompareInterrupt();
|
||||
|
||||
regs.prevDelaySlot = regs.delaySlot;
|
||||
regs.delaySlot = false;
|
||||
|
||||
u32 paddr = 0;
|
||||
if(!MapVAddr(regs, LOAD, regs.pc, paddr)) {
|
||||
HandleTLBException(regs, regs.pc);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 instruction = mem.Read32(regs, paddr);
|
||||
|
||||
if(ShouldServiceInterrupt()) {
|
||||
FireException(regs, ExceptionCode::Interrupt, 0, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
regs.oldPC = regs.pc;
|
||||
regs.pc = regs.nextPC;
|
||||
regs.nextPC += 4;
|
||||
|
||||
Exec(instruction);
|
||||
|
||||
return 1;
|
||||
}
|
||||
void Reset();
|
||||
Registers regs;
|
||||
Mem mem;
|
||||
private:
|
||||
u64 cop2Latch{};
|
||||
friend struct Cop1;
|
||||
|
||||
[[nodiscard]] FORCE_INLINE bool ShouldServiceInterrupt() const {
|
||||
bool interrupts_pending = (regs.cop0.status.im & regs.cop0.cause.interruptPending) != 0;
|
||||
bool interrupts_enabled = regs.cop0.status.ie == 1;
|
||||
bool currently_handling_exception = regs.cop0.status.exl == 1;
|
||||
bool currently_handling_error = regs.cop0.status.erl == 1;
|
||||
|
||||
return interrupts_pending && interrupts_enabled &&
|
||||
!currently_handling_exception && !currently_handling_error;
|
||||
}
|
||||
|
||||
FORCE_INLINE void CheckCompareInterrupt() {
|
||||
regs.cop0.count++;
|
||||
regs.cop0.count &= 0x1FFFFFFFF;
|
||||
if(regs.cop0.count == (u64)regs.cop0.compare << 1) {
|
||||
regs.cop0.cause.ip7 = 1;
|
||||
UpdateInterrupt(mem.mmio.mi, regs);
|
||||
}
|
||||
}
|
||||
|
||||
void cop2Decode(u32);
|
||||
void special(u32);
|
||||
void regimm(u32);
|
||||
|
||||
@@ -1,133 +0,0 @@
|
||||
#include <Registers.hpp>
|
||||
#include <filesystem>
|
||||
#include <JIT.hpp>
|
||||
|
||||
namespace n64 {
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
JIT::~JIT() {
|
||||
Util::aligned_free(codeCache);
|
||||
dump.close();
|
||||
}
|
||||
|
||||
JIT::JIT() : code(CODECACHE_SIZE, codeCache) {
|
||||
codeCache = (u8*)Util::aligned_alloc(4096, CODECACHE_SIZE);
|
||||
CodeArray::protect(
|
||||
codeCache,
|
||||
CODECACHE_SIZE,
|
||||
CodeArray::PROTECT_RWE
|
||||
);
|
||||
|
||||
if(fs::exists("jit.dump")) {
|
||||
fs::remove("jit.dump");
|
||||
}
|
||||
|
||||
dump.open("jit.dump", std::ios::ate | std::ios::binary);
|
||||
dump.unsetf(std::ios::skipws);
|
||||
regs.Reset();
|
||||
}
|
||||
|
||||
inline bool ShouldServiceInterrupt(Registers& regs) {
|
||||
bool interrupts_pending = (regs.cop0.status.im & regs.cop0.cause.interruptPending) != 0;
|
||||
bool interrupts_enabled = regs.cop0.status.ie == 1;
|
||||
bool currently_handling_exception = regs.cop0.status.exl == 1;
|
||||
bool currently_handling_error = regs.cop0.status.erl == 1;
|
||||
|
||||
return interrupts_pending && interrupts_enabled &&
|
||||
!currently_handling_exception && !currently_handling_error;
|
||||
}
|
||||
|
||||
inline void CheckCompareInterrupt(MI& mi, Registers& regs) {
|
||||
regs.cop0.count++;
|
||||
regs.cop0.count &= 0x1FFFFFFFF;
|
||||
if(regs.cop0.count == (u64)regs.cop0.compare << 1) {
|
||||
regs.cop0.cause.ip7 = 1;
|
||||
UpdateInterrupt(mi, regs);
|
||||
}
|
||||
}
|
||||
|
||||
void JIT::Recompile(Mem& mem, u32 pc) {
|
||||
bool branch = false, prevBranch = false;
|
||||
u32 startPC = pc;
|
||||
u32 loopPC = pc;
|
||||
Fn block = code.getCurr<Fn>();
|
||||
|
||||
if(code.getSize() >= CODECACHE_OVERHEAD) {
|
||||
Util::debug("Code cache overflow!\n");
|
||||
code.setSize(0);
|
||||
InvalidateCache();
|
||||
}
|
||||
|
||||
code.sub(rsp, 8);
|
||||
|
||||
while(!prevBranch) {
|
||||
instrInBlock++;
|
||||
prevBranch = branch;
|
||||
u32 instr = mem.Read32(regs, loopPC);
|
||||
loopPC += 4;
|
||||
|
||||
code.mov(rdi, (uintptr_t)this);
|
||||
code.mov(qword[rdi + GPR_OFFSET(0, this)], 0);
|
||||
code.mov(r8, qword[rdi + REG_OFFSET(oldPC, this)]);
|
||||
code.mov(r9, qword[rdi + REG_OFFSET(pc, this)]);
|
||||
code.mov(r10, qword[rdi + REG_OFFSET(nextPC, this)]);
|
||||
code.mov(r8, r9);
|
||||
code.mov(r9, r10);
|
||||
code.add(r10, 4);
|
||||
code.mov(qword[rdi + REG_OFFSET(oldPC, this)], r8);
|
||||
code.mov(qword[rdi + REG_OFFSET(pc, this)], r9);
|
||||
code.mov( qword[rdi + REG_OFFSET(nextPC, this)], r10);
|
||||
|
||||
code.mov(esi, instr);
|
||||
branch = Exec(mem, instr);
|
||||
}
|
||||
|
||||
code.add(rsp, 8);
|
||||
code.ret();
|
||||
dump.write(code.getCode<char*>(), code.getSize());
|
||||
|
||||
blockCache[startPC >> 20][startPC & 0xFFF] = block;
|
||||
}
|
||||
|
||||
void JIT::AllocateOuter(u32 pc) {
|
||||
blockCache[pc >> 20] = (Fn*)bumpAlloc(0x1000 * sizeof(Fn));
|
||||
}
|
||||
|
||||
int JIT::Run() {
|
||||
instrInBlock = 0;
|
||||
regs.prevDelaySlot = regs.delaySlot;
|
||||
regs.delaySlot = false;
|
||||
|
||||
u32 pc{};
|
||||
|
||||
if(!MapVAddr(regs, LOAD, regs.pc, pc)) {
|
||||
HandleTLBException(regs, regs.pc);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!blockCache[pc >> 20]) {
|
||||
AllocateOuter(pc);
|
||||
}
|
||||
|
||||
if(!blockCache[pc >> 20][pc & 0xfff]) {
|
||||
Recompile(mem, pc);
|
||||
}
|
||||
|
||||
CheckCompareInterrupt(mem.mmio.mi, regs);
|
||||
if(ShouldServiceInterrupt(regs)) {
|
||||
FireException(regs, ExceptionCode::Interrupt, 0, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
blockCache[pc >> 20][pc & 0xfff]();
|
||||
|
||||
return instrInBlock;
|
||||
}
|
||||
|
||||
void JIT::Reset() {
|
||||
code.reset();
|
||||
regs.Reset();
|
||||
InvalidateCache();
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
#pragma once
|
||||
#include <xbyak/xbyak.h>
|
||||
#include <backend/core/Mem.hpp>
|
||||
#include <fstream>
|
||||
#include <BaseCPU.hpp>
|
||||
|
||||
namespace n64 {
|
||||
using namespace Xbyak;
|
||||
using namespace Xbyak::util;
|
||||
using Fn = void (*)();
|
||||
|
||||
#define GPR_OFFSET(x, jit) ((uintptr_t)®s.gpr[(x)] - (uintptr_t)jit)
|
||||
#define REG_OFFSET(kind, jit) ((uintptr_t)®s.kind - (uintptr_t)jit)
|
||||
#define CODECACHE_SIZE (2 << 25)
|
||||
#define CODECACHE_OVERHEAD (CODECACHE_SIZE - 1_kb)
|
||||
|
||||
struct JIT : BaseCPU {
|
||||
JIT();
|
||||
~JIT() override;
|
||||
int Run() override;
|
||||
void Reset() override;
|
||||
u64 cop2Latch{};
|
||||
CodeGenerator code;
|
||||
void InvalidatePage(u32);
|
||||
void InvalidateCache();
|
||||
private:
|
||||
friend struct n64::Cop1;
|
||||
Fn* blockCache[0x80000]{};
|
||||
u8* codeCache;
|
||||
int instrInBlock = 0;
|
||||
u64 sizeUsed = 0;
|
||||
std::ofstream dump;
|
||||
|
||||
void* bumpAlloc(u64 size, u8 val = 0);
|
||||
void Recompile(Mem&, u32 pc);
|
||||
void AllocateOuter(u32 pc);
|
||||
void cop2Decode(u32);
|
||||
bool special(u32);
|
||||
bool regimm(u32);
|
||||
bool Exec(Mem&, u32);
|
||||
};
|
||||
}
|
||||
@@ -3,7 +3,6 @@
|
||||
#include <core/registers/Registers.hpp>
|
||||
#include <core/registers/Cop0.hpp>
|
||||
#include <core/Interpreter.hpp>
|
||||
#include <core/JIT.hpp>
|
||||
#include <File.hpp>
|
||||
|
||||
namespace n64 {
|
||||
@@ -254,26 +253,6 @@ u64 Mem::Read64(n64::Registers ®s, u32 paddr) {
|
||||
}
|
||||
}
|
||||
|
||||
void Mem::Write8(Registers& regs, JIT& dyn, u32 paddr, u32 val) {
|
||||
dyn.InvalidatePage(BYTE_ADDRESS(paddr));
|
||||
return Write8(regs, paddr, val);
|
||||
}
|
||||
|
||||
void Mem::Write16(Registers& regs, JIT& dyn, u32 paddr, u32 val) {
|
||||
dyn.InvalidatePage(HALF_ADDRESS(paddr));
|
||||
return Write16(regs, paddr, val);
|
||||
}
|
||||
|
||||
void Mem::Write32(Registers& regs, JIT& dyn, u32 paddr, u32 val) {
|
||||
dyn.InvalidatePage(paddr);
|
||||
return Write32(regs, paddr, val);
|
||||
}
|
||||
|
||||
void Mem::Write64(Registers& regs, JIT& dyn, u32 paddr, u64 val) {
|
||||
dyn.InvalidatePage(paddr);
|
||||
return Write64(regs, paddr, val);
|
||||
}
|
||||
|
||||
void Mem::Write8(Registers& regs, u32 paddr, u32 val) {
|
||||
const auto page = paddr >> 12;
|
||||
auto offset = paddr & 0xFFF;
|
||||
|
||||
@@ -16,8 +16,6 @@ struct CartInfo {
|
||||
u32 crc;
|
||||
};
|
||||
|
||||
struct JIT;
|
||||
|
||||
struct ROMHeader {
|
||||
u8 initialValues[4];
|
||||
u32 clockRate;
|
||||
@@ -61,10 +59,6 @@ struct Mem {
|
||||
u16 Read16(Registers&, u32);
|
||||
u32 Read32(Registers&, u32);
|
||||
u64 Read64(Registers&, u32);
|
||||
void Write8(Registers&, JIT&, u32, u32);
|
||||
void Write16(Registers&, JIT&, u32, u32);
|
||||
void Write32(Registers&, JIT&, u32, u32);
|
||||
void Write64(Registers&, JIT&, u32, u64);
|
||||
void Write8(Registers&, u32, u32);
|
||||
void Write16(Registers&, u32, u32);
|
||||
void Write32(Registers&, u32, u32);
|
||||
@@ -116,7 +110,7 @@ private:
|
||||
bool IsROMPAL() {
|
||||
static const char pal_codes[] = {'D', 'F', 'I', 'P', 'S', 'U', 'X', 'Y'};
|
||||
return std::any_of(std::begin(pal_codes), std::end(pal_codes), [this](char a) {
|
||||
return rom.cart[0x3e] == a;
|
||||
return rom.cart[0x3d] == a;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -66,30 +66,6 @@ inline void logRSP(const RSP& rsp, const u32 instr) {
|
||||
}
|
||||
*/
|
||||
|
||||
void RSP::Run(int cpuCount, Registers& regs, Mem& mem) {
|
||||
while(cpuCount--) {
|
||||
if (!spStatus.halt) {
|
||||
regs.steps++;
|
||||
if (regs.steps > 2) {
|
||||
steps += 2;
|
||||
regs.steps -= 3;
|
||||
}
|
||||
|
||||
while (steps > 0) {
|
||||
steps--;
|
||||
gpr[0] = 0;
|
||||
u32 instr = Util::ReadAccess<u32>(imem, pc & IMEM_DSIZE);
|
||||
oldPC = pc & 0xFFC;
|
||||
pc = nextPC & 0xFFC;
|
||||
nextPC += 4;
|
||||
|
||||
Exec(regs, mem, instr);
|
||||
//logRSP(*this, instr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto RSP::Read(u32 addr) -> u32{
|
||||
switch (addr) {
|
||||
case 0x04040000: return lastSuccessfulSPAddr.raw & 0x1FF8;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include <core/mmio/MI.hpp>
|
||||
#include <core/RDP.hpp>
|
||||
#include <MemoryRegions.hpp>
|
||||
#include <MemoryHelpers.hpp>
|
||||
#include <Interrupt.hpp>
|
||||
|
||||
#define RSP_BYTE(addr) (dmem[BYTE_ADDRESS(addr) & 0xFFF])
|
||||
@@ -113,7 +114,16 @@ struct Registers;
|
||||
struct RSP {
|
||||
RSP();
|
||||
void Reset();
|
||||
void Run(int, Registers& regs, Mem& mem);
|
||||
|
||||
FORCE_INLINE void Step(Registers& regs, Mem& mem) {
|
||||
gpr[0] = 0;
|
||||
u32 instr = Util::ReadAccess<u32>(imem, pc & IMEM_DSIZE);
|
||||
oldPC = pc & 0xFFC;
|
||||
pc = nextPC & 0xFFC;
|
||||
nextPC += 4;
|
||||
|
||||
Exec(regs, mem, instr);
|
||||
}
|
||||
auto Read(u32 addr) -> u32;
|
||||
void Write(Mem& mem, Registers& regs, u32 addr, u32 value);
|
||||
void Exec(Registers& regs, Mem& mem, u32 instr);
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
file(GLOB_RECURSE SOURCES *.cpp)
|
||||
file(GLOB_RECURSE HEADERS *.hpp)
|
||||
|
||||
add_library(jit ${SOURCES} ${HEADERS})
|
||||
@@ -1,27 +0,0 @@
|
||||
#include <core/JIT.hpp>
|
||||
|
||||
namespace n64 {
|
||||
void JIT::InvalidatePage(u32 paddr) {
|
||||
blockCache[paddr >> 20] = nullptr;
|
||||
}
|
||||
|
||||
void JIT::InvalidateCache() {
|
||||
sizeUsed = 0;
|
||||
for(auto &i : blockCache) {
|
||||
i = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void* JIT::bumpAlloc(u64 size, u8 val) {
|
||||
if(sizeUsed + size >= CODECACHE_SIZE) {
|
||||
InvalidateCache();
|
||||
}
|
||||
|
||||
void* ptr = &codeCache[sizeUsed];
|
||||
sizeUsed += size;
|
||||
|
||||
memset(ptr, val, size);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
#include <jit/cop/cop0decode.hpp>
|
||||
#include <jit/cop/cop0instructions.hpp>
|
||||
#include <Registers.hpp>
|
||||
|
||||
namespace n64 {
|
||||
void cop0Decode(JIT& cpu, u32 instr) {
|
||||
u8 mask_cop = (instr >> 21) & 0x1F;
|
||||
u8 mask_cop2 = instr & 0x3F;
|
||||
Xbyak::CodeGenerator& code = cpu.code;
|
||||
Registers& regs = cpu.regs;
|
||||
|
||||
switch(mask_cop) {
|
||||
case 0x00:
|
||||
code.mov(code.rax, (u64)mfc0);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x01:
|
||||
code.mov(code.rax, (u64)dmfc0);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x04:
|
||||
code.mov(code.rax, (uintptr_t)mtc0);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x05:
|
||||
code.mov(code.rax, (u64)dmtc0);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x10 ... 0x1F:
|
||||
switch(mask_cop2) {
|
||||
case 0x01:
|
||||
code.mov(code.rax, (u64)tlbr);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x02:
|
||||
code.mov(code.rcx, code.dword[code.rdi + REG_OFFSET(cop0.index, &cpu)]);
|
||||
code.and_(code.rcx, 0x3F);
|
||||
code.mov(code.rsi, code.rcx);
|
||||
code.mov(code.rax, (u64)tlbw);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x06:
|
||||
code.mov(code.rsi, (u64)regs.cop0.GetRandom());
|
||||
code.mov(code.rax, (u64)tlbw);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x08:
|
||||
code.mov(code.rax, (u64)tlbp);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x18:
|
||||
code.mov(code.rax, (u64)eret);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
default: Util::panic("Unimplemented COP0 function {} {} ({:08X}) ({:016lX})", mask_cop2 >> 3, mask_cop2 & 7, instr, regs.oldPC);
|
||||
}
|
||||
break;
|
||||
default: Util::panic("Unimplemented COP0 instruction {} {}", mask_cop >> 4, mask_cop & 7);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
#pragma once
|
||||
#include <JIT.hpp>
|
||||
|
||||
namespace n64 {
|
||||
struct Registers;
|
||||
void cop0Decode(JIT& cpu, u32 instr);
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
#include <jit/cop/cop0instructions.hpp>
|
||||
#include <log.hpp>
|
||||
#include <Registers.hpp>
|
||||
|
||||
namespace n64 {
|
||||
void mtc0(JIT& cpu, u32 instr) {
|
||||
Registers& regs = cpu.regs;
|
||||
regs.cop0.SetReg32(RD(instr), regs.gpr[RT(instr)]);
|
||||
}
|
||||
|
||||
void dmtc0(JIT& cpu, u32 instr) {
|
||||
Registers& regs = cpu.regs;
|
||||
regs.cop0.SetReg64(RD(instr), regs.gpr[RT(instr)]);
|
||||
}
|
||||
|
||||
void mfc0(JIT& cpu, u32 instr) {
|
||||
Registers& regs = cpu.regs;
|
||||
regs.gpr[RT(instr)] = s32(regs.cop0.GetReg32(RD(instr)));
|
||||
}
|
||||
|
||||
void dmfc0(JIT& cpu, u32 instr) {
|
||||
Registers& regs = cpu.regs;
|
||||
regs.gpr[RT(instr)] = s64(regs.cop0.GetReg64(RD(instr)));
|
||||
}
|
||||
|
||||
void eret(JIT& cpu) {
|
||||
Registers& regs = cpu.regs;
|
||||
if(regs.cop0.status.erl) {
|
||||
regs.SetPC64(regs.cop0.ErrorEPC);
|
||||
regs.cop0.status.erl = false;
|
||||
} else {
|
||||
regs.SetPC64(regs.cop0.EPC);
|
||||
regs.cop0.status.exl = false;
|
||||
}
|
||||
regs.cop0.llbit = false;
|
||||
}
|
||||
|
||||
|
||||
void tlbr(JIT& cpu) {
|
||||
Registers& regs = cpu.regs;
|
||||
u8 Index = regs.cop0.index & 0b111111;
|
||||
if (Index >= 32) {
|
||||
Util::panic("TLBR with TLB index {}", Index);
|
||||
}
|
||||
|
||||
TLBEntry entry = regs.cop0.tlb[Index];
|
||||
|
||||
regs.cop0.entryHi.raw = entry.entryHi.raw;
|
||||
regs.cop0.entryLo0.raw = entry.entryLo0.raw & 0x3FFFFFFF;
|
||||
regs.cop0.entryLo1.raw = entry.entryLo1.raw & 0x3FFFFFFF;
|
||||
|
||||
regs.cop0.entryLo0.g = entry.global;
|
||||
regs.cop0.entryLo1.g = entry.global;
|
||||
regs.cop0.pageMask.raw = entry.pageMask.raw;
|
||||
}
|
||||
|
||||
void tlbw(JIT& cpu, int index_) {
|
||||
Registers& regs = cpu.regs;
|
||||
PageMask page_mask = regs.cop0.pageMask;
|
||||
u32 top = page_mask.mask & 0xAAA;
|
||||
page_mask.mask = top | (top >> 1);
|
||||
|
||||
if(index_ >= 32) {
|
||||
Util::panic("TLBWI with TLB index {}", index_);
|
||||
}
|
||||
|
||||
regs.cop0.tlb[index_].entryHi.raw = regs.cop0.entryHi.raw;
|
||||
regs.cop0.tlb[index_].entryHi.vpn2 &= ~page_mask.mask;
|
||||
|
||||
regs.cop0.tlb[index_].entryLo0.raw = regs.cop0.entryLo0.raw & 0x03FFFFFE;
|
||||
regs.cop0.tlb[index_].entryLo1.raw = regs.cop0.entryLo1.raw & 0x03FFFFFE;
|
||||
regs.cop0.tlb[index_].pageMask.raw = page_mask.raw;
|
||||
|
||||
regs.cop0.tlb[index_].global = regs.cop0.entryLo0.g && regs.cop0.entryLo1.g;
|
||||
regs.cop0.tlb[index_].initialized = true;
|
||||
}
|
||||
|
||||
void tlbp(JIT& cpu) {
|
||||
Registers& regs = cpu.regs;
|
||||
int match = -1;
|
||||
TLBEntry* entry = TLBTryMatch(regs, regs.cop0.entryHi.raw, &match);
|
||||
if(entry && match >= 0) {
|
||||
regs.cop0.index = match;
|
||||
} else {
|
||||
regs.cop0.index = 0x80000000;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
#pragma once
|
||||
#include <JIT.hpp>
|
||||
|
||||
namespace n64 {
|
||||
void mtc0(JIT&, u32);
|
||||
void dmtc0(JIT&, u32);
|
||||
void mfc0(JIT&, u32);
|
||||
void dmfc0(JIT&, u32);
|
||||
void eret(JIT&);
|
||||
void tlbr(JIT&);
|
||||
void tlbw(JIT&, int);
|
||||
void tlbp(JIT&);
|
||||
}
|
||||
@@ -1,464 +0,0 @@
|
||||
#include <jit/cop/cop1decode.hpp>
|
||||
#include <jit/instructions.hpp>
|
||||
#include <Registers.hpp>
|
||||
|
||||
namespace n64 {
|
||||
bool cop1Decode(JIT& cpu, u32 instr) {
|
||||
Xbyak::CodeGenerator& code = cpu.code;
|
||||
Registers& regs = cpu.regs;
|
||||
|
||||
u8 mask_sub = (instr >> 21) & 0x1F;
|
||||
u8 mask_fun = instr & 0x3F;
|
||||
u8 mask_branch = (instr >> 16) & 0x1F;
|
||||
|
||||
switch(mask_sub) {
|
||||
// 000r_rccc
|
||||
case 0x00:
|
||||
code.mov(code.rax, (u64)mfc1);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x01:
|
||||
code.mov(code.rax, (u64)dmfc1);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x02:
|
||||
code.mov(code.rax, (u64)cfc1);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x03:
|
||||
Util::panic("[RECOMPILER] FPU Reserved instruction exception! {:08X}\n", instr);
|
||||
case 0x04:
|
||||
code.mov(code.rax, (u64)mtc1);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x05:
|
||||
code.mov(code.rax, (u64)dmtc1);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x06:
|
||||
code.mov(code.rax, (u64)ctc1);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x07:
|
||||
Util::panic("[RECOMPILER] FPU Reserved instruction exception! {:08X}\n", instr);
|
||||
case 0x08:
|
||||
switch(mask_branch) {
|
||||
case 0:
|
||||
code.mov(code.rdx, !regs.cop1.fcr31.compare);
|
||||
code.mov(code.rax, (u64)b);
|
||||
code.call(code.rax);
|
||||
return true;
|
||||
case 1:
|
||||
code.mov(code.rdx, regs.cop1.fcr31.compare);
|
||||
code.mov(code.rax, (u64)b);
|
||||
code.call(code.rax);
|
||||
return true;
|
||||
case 2:
|
||||
code.mov(code.rdx, !regs.cop1.fcr31.compare);
|
||||
code.mov(code.rax, (u64)bl);
|
||||
code.call(code.rax);
|
||||
return true;
|
||||
case 3:
|
||||
code.mov(code.rdx, regs.cop1.fcr31.compare);
|
||||
code.mov(code.rax, (u64)bl);
|
||||
code.call(code.rax);
|
||||
return true;
|
||||
default: Util::panic("Undefined BC COP1 {:02X}\n", mask_branch);
|
||||
}
|
||||
break;
|
||||
case 0x10: // s
|
||||
switch(mask_fun) {
|
||||
case 0x00:
|
||||
code.mov(code.rax, (u64)adds);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x01:
|
||||
code.mov(code.rax, (u64)subs);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x02:
|
||||
code.mov(code.rax, (u64)muls);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x03:
|
||||
code.mov(code.rax, (u64)divs);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x04:
|
||||
code.mov(code.rax, (u64)sqrts);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x05:
|
||||
code.mov(code.rax, (u64)abss);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x06:
|
||||
code.mov(code.rax, (u64)movs);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x07:
|
||||
code.mov(code.rax, (u64)negs);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x08:
|
||||
code.mov(code.rax, (u64)roundls);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x09:
|
||||
code.mov(code.rax, (u64)truncls);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x0A:
|
||||
code.mov(code.rax, (u64)ceills);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x0B:
|
||||
code.mov(code.rax, (u64)floorls);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x0C:
|
||||
code.mov(code.rax, (u64)roundws);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x0D:
|
||||
code.mov(code.rax, (u64)truncws);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x0E:
|
||||
code.mov(code.rax, (u64)ceilws);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x0F:
|
||||
code.mov(code.rax, (u64)floorws);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x20:
|
||||
Util::panic("[RECOMPILER] FPU Reserved instruction exception! {:08X}\n", instr);
|
||||
case 0x21:
|
||||
code.mov(code.rax, (u64)cvtds);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x24:
|
||||
code.mov(code.rax, (u64)cvtws);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x25:
|
||||
code.mov(code.rax, (u64)cvtls);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x30:
|
||||
code.mov(code.rax, (u64)ccond<float>);
|
||||
code.mov(code.rdx, F);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x31:
|
||||
code.mov(code.rax, (u64)ccond<float>);
|
||||
code.mov(code.rdx, UN);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x32:
|
||||
code.mov(code.rax, (u64)ccond<float>);
|
||||
code.mov(code.rdx, EQ);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x33:
|
||||
code.mov(code.rax, (u64)ccond<float>);
|
||||
code.mov(code.rdx, UEQ);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x34:
|
||||
code.mov(code.rax, (u64)ccond<float>);
|
||||
code.mov(code.rdx, OLT);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x35:
|
||||
code.mov(code.rax, (u64)ccond<float>);
|
||||
code.mov(code.rdx, ULT);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x36:
|
||||
code.mov(code.rax, (u64)ccond<float>);
|
||||
code.mov(code.rdx, OLE);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x37:
|
||||
code.mov(code.rax, (u64)ccond<float>);
|
||||
code.mov(code.rdx, ULE);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x38:
|
||||
code.mov(code.rax, (u64)ccond<float>);
|
||||
code.mov(code.rdx, SF);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x39:
|
||||
code.mov(code.rax, (u64)ccond<float>);
|
||||
code.mov(code.rdx, NGLE);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x3A:
|
||||
code.mov(code.rax, (u64)ccond<float>);
|
||||
code.mov(code.rdx, SEQ);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x3B:
|
||||
code.mov(code.rax, (u64)ccond<float>);
|
||||
code.mov(code.rdx, NGL);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x3C:
|
||||
code.mov(code.rax, (u64)ccond<float>);
|
||||
code.mov(code.rdx, LT);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x3D:
|
||||
code.mov(code.rax, (u64)ccond<float>);
|
||||
code.mov(code.rdx, NGE);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x3E:
|
||||
code.mov(code.rax, (u64)ccond<float>);
|
||||
code.mov(code.rdx, LE);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x3F:
|
||||
code.mov(code.rax, (u64)ccond<float>);
|
||||
code.mov(code.rdx, NGT);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
default: Util::panic("Unimplemented COP1 function S[{} {}] ({:08X}) ({:016X})", mask_fun >> 3, mask_fun & 7, instr, (u64)regs.oldPC);
|
||||
}
|
||||
break;
|
||||
case 0x11: // d
|
||||
switch(mask_fun) {
|
||||
case 0x00:
|
||||
code.mov(code.rax, (u64)addd);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x01:
|
||||
code.mov(code.rax, (u64)subd);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x02:
|
||||
code.mov(code.rax, (u64)muld);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x03:
|
||||
code.mov(code.rax, (u64)divd);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x04:
|
||||
code.mov(code.rax, (u64)sqrtd);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x05:
|
||||
code.mov(code.rax, (u64)absd);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x06:
|
||||
code.mov(code.rax, (u64)movd);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x07:
|
||||
code.mov(code.rax, (u64)negd);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x08:
|
||||
code.mov(code.rax, (u64)roundld);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x09:
|
||||
code.mov(code.rax, (u64)truncld);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x0A:
|
||||
code.mov(code.rax, (u64)ceilld);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x0B:
|
||||
code.mov(code.rax, (u64)floorld);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x0C:
|
||||
code.mov(code.rax, (u64)roundwd);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x0D:
|
||||
code.mov(code.rax, (u64)truncwd);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x0E:
|
||||
code.mov(code.rax, (u64)ceilwd);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x0F:
|
||||
code.mov(code.rax, (u64)floorwd);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x20:
|
||||
code.mov(code.rax, (u64)cvtsd);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x21:
|
||||
Util::panic("[RECOMPILER] FPU Reserved instruction exception! {:08X}\n", instr);
|
||||
case 0x24:
|
||||
code.mov(code.rax, (u64)cvtwd);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x25:
|
||||
code.mov(code.rax, (u64)cvtld);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x30:
|
||||
code.mov(code.rax, (u64)ccond<double>);
|
||||
code.mov(code.rdx, F);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x31:
|
||||
code.mov(code.rax, (u64)ccond<double>);
|
||||
code.mov(code.rdx, UN);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x32:
|
||||
code.mov(code.rax, (u64)ccond<double>);
|
||||
code.mov(code.rdx, EQ);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x33:
|
||||
code.mov(code.rax, (u64)ccond<double>);
|
||||
code.mov(code.rdx, UEQ);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x34:
|
||||
code.mov(code.rax, (u64)ccond<double>);
|
||||
code.mov(code.rdx, OLT);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x35:
|
||||
code.mov(code.rax, (u64)ccond<double>);
|
||||
code.mov(code.rdx, ULT);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x36:
|
||||
code.mov(code.rax, (u64)ccond<double>);
|
||||
code.mov(code.rdx, OLE);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x37:
|
||||
code.mov(code.rax, (u64)ccond<double>);
|
||||
code.mov(code.rdx, ULE);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x38:
|
||||
code.mov(code.rax, (u64)ccond<double>);
|
||||
code.mov(code.rdx, SF);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x39:
|
||||
code.mov(code.rax, (u64)ccond<double>);
|
||||
code.mov(code.rdx, NGLE);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x3A:
|
||||
code.mov(code.rax, (u64)ccond<double>);
|
||||
code.mov(code.rdx, SEQ);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x3B:
|
||||
code.mov(code.rax, (u64)ccond<double>);
|
||||
code.mov(code.rdx, NGL);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x3C:
|
||||
code.mov(code.rax, (u64)ccond<double>);
|
||||
code.mov(code.rdx, LT);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x3D:
|
||||
code.mov(code.rax, (u64)ccond<double>);
|
||||
code.mov(code.rdx, NGE);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x3E:
|
||||
code.mov(code.rax, (u64)ccond<double>);
|
||||
code.mov(code.rdx, LE);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x3F:
|
||||
code.mov(code.rax, (u64)ccond<double>);
|
||||
code.mov(code.rdx, NGT);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
default: Util::panic("Unimplemented COP1 function D[{} {}] ({:08X}) ({:016X})", mask_fun >> 3, mask_fun & 7, instr, (u64)regs.oldPC);
|
||||
}
|
||||
break;
|
||||
case 0x14: // w
|
||||
switch(mask_fun) {
|
||||
case 0x01:
|
||||
code.mov(code.rax, (u64)subw);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x05:
|
||||
code.mov(code.rax, (u64)absw);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x02:
|
||||
code.mov(code.rax, (u64)mulw);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x06:
|
||||
code.mov(code.rax, (u64)movw);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x20:
|
||||
code.mov(code.rax, (u64)cvtsw);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x21:
|
||||
code.mov(code.rax, (u64)cvtdw);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x24:
|
||||
Util::panic("[RECOMPILER] FPU Reserved instruction exception! {:08X}\n", instr);
|
||||
default: Util::panic("Unimplemented COP1 function W[{} {}] ({:08X}) ({:016X})", mask_fun >> 3, mask_fun & 7, instr, (u64)regs.oldPC);
|
||||
}
|
||||
break;
|
||||
case 0x15: // l
|
||||
switch(mask_fun) {
|
||||
case 0x01:
|
||||
code.mov(code.rax, (u64)subl);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x05:
|
||||
code.mov(code.rax, (u64)absl);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x02:
|
||||
code.mov(code.rax, (u64)mull);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x06:
|
||||
code.mov(code.rax, (u64)movl);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x20:
|
||||
code.mov(code.rax, (u64)cvtsl);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x21:
|
||||
code.mov(code.rax, (u64)cvtdl);
|
||||
code.call(code.rax);
|
||||
break;
|
||||
case 0x24:
|
||||
Util::panic("[RECOMPILER] FPU Reserved instruction exception! {:08X}\n", instr);
|
||||
case 0x25:
|
||||
Util::panic("[RECOMPILER] FPU Reserved instruction exception! {:08X}\n", instr);
|
||||
default: Util::panic("Unimplemented COP1 function L[{} {}] ({:08X}) ({:016X})", mask_fun >> 3, mask_fun & 7, instr, (u64)regs.oldPC);
|
||||
}
|
||||
break;
|
||||
default: Util::panic("Unimplemented COP1 instruction {} {}", mask_sub >> 3, mask_sub & 7);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
#pragma once
|
||||
#include <jit/cop/cop1instructions.hpp>
|
||||
|
||||
namespace n64 {
|
||||
bool cop1Decode(JIT& cpu, u32 instr);
|
||||
}
|
||||
@@ -1,617 +0,0 @@
|
||||
#include <jit/cop/cop1instructions.hpp>
|
||||
#include <cfenv>
|
||||
#include <cmath>
|
||||
#include <Cop1.hpp>
|
||||
#include <Registers.hpp>
|
||||
|
||||
namespace n64 {
|
||||
inline int PushRoundingMode(const FCR31& fcr31) {
|
||||
int og = fegetround();
|
||||
switch(fcr31.rounding_mode) {
|
||||
case 0: fesetround(FE_TONEAREST); break;
|
||||
case 1: fesetround(FE_TOWARDZERO); break;
|
||||
case 2: fesetround(FE_UPWARD); break;
|
||||
case 3: fesetround(FE_DOWNWARD); break;
|
||||
}
|
||||
|
||||
return og;
|
||||
}
|
||||
|
||||
#define PUSHROUNDINGMODE int og = PushRoundingMode(regs.cop1.fcr31)
|
||||
#define POPROUNDINGMODE fesetround(og)
|
||||
|
||||
#define checknanregs(fs, ft) do { \
|
||||
if(std::isnan(fs) || std::isnan(ft)) { \
|
||||
regs.cop1.fcr31.flag_invalid_operation = true; \
|
||||
regs.cop1.fcr31.cause_invalid_operation = true; \
|
||||
FireException(regs, ExceptionCode::FloatingPointError, 1, true); \
|
||||
return; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
void absd(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
|
||||
regs.cop1.SetCop1Reg<double>(regs.cop0, FD(instr), std::abs(fs));
|
||||
}
|
||||
|
||||
void abss(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
|
||||
regs.cop1.SetCop1Reg<float>(regs.cop0, FD(instr), std::abs(fs));
|
||||
}
|
||||
|
||||
void absw(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
s32 fs = regs.cop1.GetReg<s32>(regs.cop0, FS(instr));
|
||||
regs.cop1.SetReg<u32>(regs.cop0, FD(instr), std::abs(fs));
|
||||
}
|
||||
|
||||
void absl(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
s64 fs = regs.cop1.GetReg<s64>(regs.cop0, FS(instr));
|
||||
regs.cop1.SetReg(regs.cop0, FD(instr), std::abs(fs));
|
||||
}
|
||||
|
||||
void adds(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
|
||||
float ft = regs.cop1.GetCop1Reg<float>(regs.cop0, FT(instr));
|
||||
checknanregs(fs, ft);
|
||||
float result = fs + ft;
|
||||
regs.cop1.SetCop1Reg<float>(regs.cop0, FD(instr), result);
|
||||
}
|
||||
|
||||
void addd(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
|
||||
double ft = regs.cop1.GetCop1Reg<double>(regs.cop0, FT(instr));
|
||||
checknanregs(fs, ft);
|
||||
double result = fs + ft;
|
||||
regs.cop1.SetCop1Reg<double>(regs.cop0, FD(instr), result);
|
||||
}
|
||||
|
||||
void ceills(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
|
||||
s64 result = std::ceil(fs);
|
||||
regs.cop1.SetReg<u64>(regs.cop0, FD(instr), result);
|
||||
}
|
||||
|
||||
void ceilws(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
|
||||
s32 result = std::ceil(fs);
|
||||
regs.cop1.SetReg<u32>(regs.cop0, FD(instr), result);
|
||||
}
|
||||
|
||||
void ceilld(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
|
||||
s64 result = std::ceil(fs);
|
||||
regs.cop1.SetReg<u64>(regs.cop0, FD(instr), result);
|
||||
}
|
||||
|
||||
void ceilwd(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
|
||||
s32 result = std::ceil(fs);
|
||||
regs.cop1.SetReg<u32>(regs.cop0, FD(instr), result);
|
||||
}
|
||||
|
||||
void cfc1(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
u8 fd = RD(instr);
|
||||
s32 val = 0;
|
||||
switch(fd) {
|
||||
case 0: val = regs.cop1.fcr0; break;
|
||||
case 31:
|
||||
val = regs.cop1.fcr31.raw;
|
||||
break;
|
||||
default: Util::panic("Undefined CFC1 with rd != 0 or 31\n");
|
||||
}
|
||||
regs.gpr[RT(instr)] = val;
|
||||
}
|
||||
|
||||
void ctc1(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
u8 fs = RD(instr);
|
||||
u32 val = regs.gpr[RT(instr)];
|
||||
switch(fs) {
|
||||
case 0: break;
|
||||
case 31: {
|
||||
val &= 0x183ffff;
|
||||
regs.cop1.fcr31.raw = val;
|
||||
} break;
|
||||
default: Util::panic("Undefined CTC1 with rd != 0 or 31\n");
|
||||
}
|
||||
}
|
||||
|
||||
void cvtds(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
regs.cop1.SetCop1Reg<double>(
|
||||
regs.cop0,
|
||||
FD(instr),
|
||||
regs.cop1.GetCop1Reg<float>(
|
||||
regs.cop0,
|
||||
FS(instr)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void cvtsd(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
regs.cop1.SetCop1Reg<float>(
|
||||
regs.cop0,
|
||||
FD(instr),
|
||||
regs.cop1.GetCop1Reg<double>(
|
||||
regs.cop0,
|
||||
FS(instr)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void cvtwd(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
regs.cop1.SetReg<u32>(
|
||||
regs.cop0,
|
||||
FD(instr),
|
||||
regs.cop1.GetCop1Reg<double>(
|
||||
regs.cop0,
|
||||
FS(instr)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void cvtws(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
regs.cop1.SetReg<u32>(
|
||||
regs.cop0,
|
||||
FD(instr),
|
||||
regs.cop1.GetCop1Reg<float>(
|
||||
regs.cop0,
|
||||
FS(instr)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void cvtls(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
regs.cop1.SetReg<u64>(
|
||||
regs.cop0,
|
||||
FD(instr),
|
||||
regs.cop1.GetCop1Reg<float>(
|
||||
regs.cop0,
|
||||
FS(instr)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void cvtsl(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
regs.cop1.SetCop1Reg<float>(
|
||||
regs.cop0,
|
||||
FD(instr),
|
||||
(s64)regs.cop1.GetReg<u64>(
|
||||
regs.cop0,
|
||||
FS(instr)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void cvtdw(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
regs.cop1.SetCop1Reg<double>(
|
||||
regs.cop0,
|
||||
FD(instr),
|
||||
(s32)regs.cop1.GetReg<u32>(
|
||||
regs.cop0,
|
||||
FS(instr)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void cvtsw(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
regs.cop1.SetCop1Reg<float>(
|
||||
regs.cop0,
|
||||
FD(instr),
|
||||
(s32)regs.cop1.GetReg<u32>(
|
||||
regs.cop0,
|
||||
FS(instr)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void cvtdl(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
regs.cop1.SetCop1Reg<double>(
|
||||
regs.cop0,
|
||||
FD(instr),
|
||||
(s64)regs.cop1.GetReg<u64>(
|
||||
regs.cop0,
|
||||
FS(instr)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void cvtld(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
regs.cop1.SetReg<u64>(
|
||||
regs.cop0,
|
||||
FD(instr),
|
||||
regs.cop1.GetCop1Reg<double>(
|
||||
regs.cop0,
|
||||
FS(instr)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool CalculateCondition(Registers& regs, T fs, T ft, CompConds cond) {
|
||||
switch(cond) {
|
||||
case F: return false;
|
||||
case UN: return std::isnan(fs) || std::isnan(ft);
|
||||
case EQ: return fs == ft;
|
||||
case UEQ: return (std::isnan(fs) || std::isnan(ft)) || (fs == ft);
|
||||
case OLT: return (!std::isnan(fs) && !std::isnan(ft)) && (fs < ft);
|
||||
case ULT: return (std::isnan(fs) || std::isnan(ft)) || (fs < ft);
|
||||
case OLE: return (!std::isnan(fs) && !std::isnan(ft)) && (fs <= ft);
|
||||
case ULE: return (std::isnan(fs) || std::isnan(ft)) || (fs <= ft);
|
||||
default:
|
||||
if(std::isnan(fs) || std::isnan(ft)) {
|
||||
regs.cop1.fcr31.flag_invalid_operation = true;
|
||||
regs.cop1.fcr31.cause_invalid_operation = true;
|
||||
FireException(regs, ExceptionCode::FloatingPointError, 1, true);
|
||||
return false;
|
||||
}
|
||||
|
||||
return CalculateCondition(regs, fs, ft, static_cast<CompConds>(cond - 8));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ccond(JIT& dyn, u32 instr, CompConds cond) {
|
||||
Registers& regs = dyn.regs;
|
||||
T fs = regs.cop1.GetCop1Reg<T>(regs.cop0, FS(instr));
|
||||
T ft = regs.cop1.GetCop1Reg<T>(regs.cop0, FT(instr));
|
||||
|
||||
regs.cop1.fcr31.compare = CalculateCondition(regs, fs, ft, cond);
|
||||
}
|
||||
|
||||
template void ccond<float>(JIT& dyn, u32 instr, CompConds cond);
|
||||
template void ccond<double>(JIT& dyn, u32 instr, CompConds cond);
|
||||
|
||||
void divs(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
|
||||
float ft = regs.cop1.GetCop1Reg<float>(regs.cop0, FT(instr));
|
||||
regs.cop1.SetCop1Reg<float>(regs.cop0, FD(instr), fs / ft);
|
||||
}
|
||||
|
||||
void divd(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
|
||||
double ft = regs.cop1.GetCop1Reg<double>(regs.cop0, FT(instr));
|
||||
regs.cop1.SetCop1Reg<double>(regs.cop0, FD(instr), fs / ft);
|
||||
}
|
||||
|
||||
void muls(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
|
||||
float ft = regs.cop1.GetCop1Reg<float>(regs.cop0, FT(instr));
|
||||
regs.cop1.SetCop1Reg<float>(regs.cop0, FD(instr), fs * ft);
|
||||
}
|
||||
|
||||
void muld(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
|
||||
double ft = regs.cop1.GetCop1Reg<double>(regs.cop0, FT(instr));
|
||||
regs.cop1.SetCop1Reg<double>(regs.cop0, FD(instr), fs * ft);
|
||||
}
|
||||
|
||||
void mulw(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
u32 fs = regs.cop1.GetReg<u32>(regs.cop0, FS(instr));
|
||||
u32 ft = regs.cop1.GetReg<u32>(regs.cop0, FT(instr));
|
||||
regs.cop1.SetReg<u32>(regs.cop0, FD(instr), fs * ft);
|
||||
}
|
||||
|
||||
void mull(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
u64 fs = regs.cop1.GetReg<u64>(regs.cop0, FS(instr));
|
||||
u64 ft = regs.cop1.GetReg<u64>(regs.cop0, FT(instr));
|
||||
regs.cop1.SetReg<u64>(regs.cop0, FD(instr), fs * ft);
|
||||
}
|
||||
|
||||
void subs(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
|
||||
float ft = regs.cop1.GetCop1Reg<float>(regs.cop0, FT(instr));
|
||||
regs.cop1.SetCop1Reg<float>(regs.cop0, FD(instr), fs - ft);
|
||||
}
|
||||
|
||||
void subd(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
|
||||
double ft = regs.cop1.GetCop1Reg<double>(regs.cop0, FT(instr));
|
||||
regs.cop1.SetCop1Reg<double>(regs.cop0, FD(instr), fs - ft);
|
||||
}
|
||||
|
||||
void subw(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
u32 fs = regs.cop1.GetReg<u32>(regs.cop0, FS(instr));
|
||||
u32 ft = regs.cop1.GetReg<u32>(regs.cop0, FT(instr));
|
||||
regs.cop1.SetReg<u32>(regs.cop0, FD(instr), fs - ft);
|
||||
}
|
||||
|
||||
void subl(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
u64 fs = regs.cop1.GetReg<u64>(regs.cop0, FS(instr));
|
||||
u64 ft = regs.cop1.GetReg<u64>(regs.cop0, FT(instr));
|
||||
regs.cop1.SetReg<u64>(regs.cop0, FD(instr), fs - ft);
|
||||
}
|
||||
|
||||
void movs(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
regs.cop1.SetCop1Reg<float>(
|
||||
regs.cop0,
|
||||
FD(instr),
|
||||
regs.cop1.GetCop1Reg<float>(
|
||||
regs.cop0,
|
||||
FS(instr)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void movd(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
regs.cop1.SetCop1Reg<double>(
|
||||
regs.cop0,
|
||||
FD(instr),
|
||||
regs.cop1.GetCop1Reg<double>(
|
||||
regs.cop0,
|
||||
FS(instr)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void movw(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
regs.cop1.SetReg<u32>(
|
||||
regs.cop0,
|
||||
FD(instr),
|
||||
regs.cop1.GetReg<u32>(
|
||||
regs.cop0,
|
||||
FS(instr)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void movl(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
regs.cop1.SetReg<u64>(
|
||||
regs.cop0,
|
||||
FD(instr),
|
||||
regs.cop1.GetReg<u64>(
|
||||
regs.cop0,
|
||||
FS(instr)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void negs(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
regs.cop1.SetCop1Reg<float>(
|
||||
regs.cop0,
|
||||
FD(instr),
|
||||
-regs.cop1.GetCop1Reg<float>(
|
||||
regs.cop0,
|
||||
FS(instr)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void negd(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
regs.cop1.SetCop1Reg<double>(
|
||||
regs.cop0,
|
||||
FD(instr),
|
||||
-regs.cop1.GetCop1Reg<double>(
|
||||
regs.cop0,
|
||||
FS(instr)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void sqrts(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
|
||||
regs.cop1.SetCop1Reg<float>(regs.cop0, FD(instr), std::sqrt(fs));
|
||||
}
|
||||
|
||||
void sqrtd(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
|
||||
regs.cop1.SetCop1Reg<double>(regs.cop0, FD(instr), std::sqrt(fs));
|
||||
}
|
||||
|
||||
void roundls(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
|
||||
PUSHROUNDINGMODE;
|
||||
regs.cop1.SetReg<u64>(regs.cop0, FD(instr), (s32)std::nearbyint(fs));
|
||||
POPROUNDINGMODE;
|
||||
}
|
||||
|
||||
void roundld(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
|
||||
PUSHROUNDINGMODE;
|
||||
regs.cop1.SetReg<u64>(regs.cop0, FD(instr), (s64)std::nearbyint(fs));
|
||||
POPROUNDINGMODE;
|
||||
}
|
||||
|
||||
void roundws(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
|
||||
PUSHROUNDINGMODE;
|
||||
regs.cop1.SetReg<u32>(regs.cop0, FD(instr), (s32)std::nearbyint(fs));
|
||||
POPROUNDINGMODE;
|
||||
}
|
||||
|
||||
void roundwd(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
|
||||
PUSHROUNDINGMODE;
|
||||
regs.cop1.SetReg<u32>(regs.cop0, FD(instr), (s32)std::nearbyint(fs));
|
||||
POPROUNDINGMODE;
|
||||
}
|
||||
|
||||
void floorls(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
|
||||
regs.cop1.SetReg<u64>(regs.cop0, FD(instr), (s64)std::floor(fs));
|
||||
}
|
||||
|
||||
void floorld(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
|
||||
regs.cop1.SetReg<u64>(regs.cop0, FD(instr), (s64)std::floor(fs));
|
||||
}
|
||||
|
||||
void floorws(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
|
||||
regs.cop1.SetReg<u32>(regs.cop0, FD(instr), (s64)std::floor(fs));
|
||||
}
|
||||
|
||||
void floorwd(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
|
||||
regs.cop1.SetReg<u32>(regs.cop0, FD(instr), (s64)std::floor(fs));
|
||||
}
|
||||
|
||||
void lwc1(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
if(!regs.cop0.status.cu1) {
|
||||
FireException(regs, ExceptionCode::CoprocessorUnusable, 1, true);
|
||||
return;
|
||||
}
|
||||
|
||||
u64 addr = (s64)(s16)instr + regs.gpr[BASE(instr)];
|
||||
|
||||
u32 physical;
|
||||
if(!MapVAddr(regs, LOAD, addr, physical)) {
|
||||
HandleTLBException(regs, addr);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
|
||||
} else {
|
||||
u32 data = dyn.mem.Read32(regs, physical);
|
||||
regs.cop1.SetReg<u32>(regs.cop0, FT(instr), data);
|
||||
}
|
||||
}
|
||||
|
||||
void swc1(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
if(!regs.cop0.status.cu1) {
|
||||
FireException(regs, ExceptionCode::CoprocessorUnusable, 1, true);
|
||||
return;
|
||||
}
|
||||
|
||||
u64 addr = (s64)(s16)instr + regs.gpr[BASE(instr)];
|
||||
|
||||
u32 physical;
|
||||
if(!MapVAddr(regs, STORE, addr, physical)) {
|
||||
HandleTLBException(regs, addr);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
|
||||
} else {
|
||||
dyn.mem.Write32(regs, physical, regs.cop1.GetReg<u32>(regs.cop0, FT(instr)));
|
||||
}
|
||||
}
|
||||
|
||||
void ldc1(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
if(!regs.cop0.status.cu1) {
|
||||
FireException(regs, ExceptionCode::CoprocessorUnusable, 1, true);
|
||||
return;
|
||||
}
|
||||
|
||||
u64 addr = (s64)(s16)instr + regs.gpr[BASE(instr)];
|
||||
|
||||
u32 physical;
|
||||
if(!MapVAddr(regs, LOAD, addr, physical)) {
|
||||
HandleTLBException(regs, addr);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
|
||||
} else {
|
||||
u64 data = dyn.mem.Read64(regs, physical);
|
||||
regs.cop1.SetReg<u64>(regs.cop0, FT(instr), data);
|
||||
}
|
||||
}
|
||||
|
||||
void sdc1(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
if(!regs.cop0.status.cu1) {
|
||||
FireException(regs, ExceptionCode::CoprocessorUnusable, 1, true);
|
||||
return;
|
||||
}
|
||||
|
||||
u64 addr = (s64)(s16)instr + regs.gpr[BASE(instr)];
|
||||
|
||||
u32 physical;
|
||||
if(!MapVAddr(regs, STORE, addr, physical)) {
|
||||
HandleTLBException(regs, addr);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
|
||||
} else {
|
||||
dyn.mem.Write64(regs, physical, regs.cop1.GetReg<u64>(regs.cop0, FT(instr)));
|
||||
}
|
||||
}
|
||||
|
||||
void truncws(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
|
||||
s32 result = (s32)std::trunc(fs);
|
||||
regs.cop1.SetReg<u32>(regs.cop0, FD(instr), result);
|
||||
}
|
||||
|
||||
void truncwd(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
|
||||
s32 result = (s32)std::trunc(fs);
|
||||
regs.cop1.SetReg<u32>(regs.cop0, FD(instr), result);
|
||||
}
|
||||
|
||||
void truncls(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
|
||||
s64 result = (s64)std::trunc(fs);
|
||||
regs.cop1.SetReg<u64>(regs.cop0, FD(instr), result);
|
||||
}
|
||||
|
||||
void truncld(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
|
||||
s64 result = (s64)std::trunc(fs);
|
||||
regs.cop1.SetReg<u64>(regs.cop0, FD(instr), result);
|
||||
}
|
||||
|
||||
void mfc1(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
regs.gpr[RT(instr)] = (s32)regs.cop1.GetReg<u32>(regs.cop0, FS(instr));
|
||||
}
|
||||
|
||||
void dmfc1(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
regs.gpr[RT(instr)] = (s64)regs.cop1.GetReg<u64>(regs.cop0, FS(instr));
|
||||
}
|
||||
|
||||
void mtc1(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
regs.cop1.SetReg<u32>(regs.cop0, FS(instr), regs.gpr[RT(instr)]);
|
||||
}
|
||||
|
||||
void dmtc1(JIT& dyn, u32 instr) {
|
||||
Registers& regs = dyn.regs;
|
||||
regs.cop1.SetReg<u64>(regs.cop0, FS(instr), regs.gpr[RT(instr)]);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
#pragma once
|
||||
#include <JIT.hpp>
|
||||
#include <Cop1.hpp>
|
||||
|
||||
namespace n64 {
|
||||
void absd(JIT&, u32 instr);
|
||||
void abss(JIT&, u32 instr);
|
||||
void absw(JIT&, u32 instr);
|
||||
void absl(JIT&, u32 instr);
|
||||
void adds(JIT&, u32 instr);
|
||||
void addd(JIT&, u32 instr);
|
||||
void subs(JIT&, u32 instr);
|
||||
void subd(JIT&, u32 instr);
|
||||
void subw(JIT&, u32 instr);
|
||||
void subl(JIT&, u32 instr);
|
||||
void ceills(JIT&, u32 instr);
|
||||
void ceilws(JIT&, u32 instr);
|
||||
void ceilld(JIT&, u32 instr);
|
||||
void ceilwd(JIT&, u32 instr);
|
||||
void cfc1(JIT&, u32 instr);
|
||||
void ctc1(JIT&, u32 instr);
|
||||
void roundls(JIT&, u32 instr);
|
||||
void roundld(JIT&, u32 instr);
|
||||
void roundws(JIT&, u32 instr);
|
||||
void roundwd(JIT&, u32 instr);
|
||||
void floorls(JIT&, u32 instr);
|
||||
void floorld(JIT&, u32 instr);
|
||||
void floorws(JIT&, u32 instr);
|
||||
void floorwd(JIT&, u32 instr);
|
||||
void cvtls(JIT&, u32 instr);
|
||||
void cvtws(JIT&, u32 instr);
|
||||
void cvtds(JIT&, u32 instr);
|
||||
void cvtsw(JIT&, u32 instr);
|
||||
void cvtdw(JIT&, u32 instr);
|
||||
void cvtsd(JIT&, u32 instr);
|
||||
void cvtwd(JIT&, u32 instr);
|
||||
void cvtld(JIT&, u32 instr);
|
||||
void cvtdl(JIT&, u32 instr);
|
||||
void cvtsl(JIT&, u32 instr);
|
||||
template <typename T>
|
||||
void ccond(JIT&, u32 instr, CompConds);
|
||||
void divs(JIT&, u32 instr);
|
||||
void divd(JIT&, u32 instr);
|
||||
void muls(JIT&, u32 instr);
|
||||
void muld(JIT&, u32 instr);
|
||||
void mulw(JIT&, u32 instr);
|
||||
void mull(JIT&, u32 instr);
|
||||
void movs(JIT&, u32 instr);
|
||||
void movd(JIT&, u32 instr);
|
||||
void movw(JIT&, u32 instr);
|
||||
void movl(JIT&, u32 instr);
|
||||
void negs(JIT&, u32 instr);
|
||||
void negd(JIT&, u32 instr);
|
||||
void sqrts(JIT&, u32 instr);
|
||||
void sqrtd(JIT&, u32 instr);
|
||||
void lwc1(JIT&, u32 instr);
|
||||
void swc1(JIT&, u32 instr);
|
||||
void ldc1(JIT&, u32 instr);
|
||||
void mfc1(JIT&, u32 instr);
|
||||
void dmfc1(JIT&, u32 instr);
|
||||
void mtc1(JIT&, u32 instr);
|
||||
void dmtc1(JIT&, u32 instr);
|
||||
void sdc1(JIT&, u32 instr);
|
||||
void truncws(JIT&, u32 instr);
|
||||
void truncwd(JIT&, u32 instr);
|
||||
void truncls(JIT&, u32 instr);
|
||||
void truncld(JIT&, u32 instr);
|
||||
}
|
||||
@@ -1,655 +0,0 @@
|
||||
#include <jit/instructions.hpp>
|
||||
#include <jit/cop/cop1decode.hpp>
|
||||
#include <jit/cop/cop0decode.hpp>
|
||||
#include <Registers.hpp>
|
||||
|
||||
namespace n64 {
|
||||
void JIT::cop2Decode(u32 instr) {
|
||||
switch(RS(instr)) {
|
||||
case 0x00:
|
||||
code.mov(rax, (u64)mfc2);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x01:
|
||||
code.mov(rax, (u64)dmfc2);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x02: case 0x06: break;
|
||||
case 0x04:
|
||||
code.mov(rax, (u64)mtc2);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x05:
|
||||
code.mov(rax, (u64)dmtc2);
|
||||
code.call(rax);
|
||||
break;
|
||||
default:
|
||||
Util::panic("[RECOMPILER] Unhandled reserved instruction exception {:016X}\n", (u64)regs.pc);
|
||||
}
|
||||
}
|
||||
|
||||
bool JIT::special(u32 instr) {
|
||||
u8 mask = (instr & 0x3F);
|
||||
bool res = false;
|
||||
|
||||
// 00rr_rccc
|
||||
switch (mask) { // TODO: named constants for clearer code
|
||||
case 0:
|
||||
if (instr != 0) {
|
||||
code.mov(rax, (u64)sll);
|
||||
code.call(rax);
|
||||
}
|
||||
break;
|
||||
case 0x02:
|
||||
code.mov(rax, (u64)srl);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x03:
|
||||
code.mov(rax, (u64)sra);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x04:
|
||||
code.mov(rax, (u64)sllv);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x06:
|
||||
code.mov(rax, (u64)srlv);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x07:
|
||||
code.mov(rax, (u64)srav);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x08:
|
||||
code.mov(rax, (u64)jr);
|
||||
code.call(rax);
|
||||
res = true;
|
||||
break;
|
||||
case 0x09:
|
||||
code.mov(rax, (u64)jalr);
|
||||
code.call(rax);
|
||||
res = true;
|
||||
break;
|
||||
case 0x0C: Util::panic("[RECOMPILER] Unhandled syscall instruction {:016X}\n", (u64)regs.pc);
|
||||
case 0x0D: Util::panic("[RECOMPILER] Unhandled break instruction {:016X}\n", (u64)regs.pc);
|
||||
case 0x0F: break; // SYNC
|
||||
case 0x10:
|
||||
code.mov(rax, (u64)mfhi);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x11:
|
||||
code.mov(rax, (u64)mthi);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x12:
|
||||
code.mov(rax, (u64)mflo);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x13:
|
||||
code.mov(rax, (u64)mtlo);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x14:
|
||||
code.mov(rax, (u64)dsllv);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x16:
|
||||
code.mov(rax, (u64)dsrlv);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x17:
|
||||
code.mov(rax, (u64)dsrav);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x18:
|
||||
code.mov(rax, (u64)mult);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x19:
|
||||
code.mov(rax, (u64)multu);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x1A:
|
||||
code.mov(rax, (u64)div);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x1B:
|
||||
code.mov(rax, (u64)divu);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x1C:
|
||||
code.mov(rax, (u64)dmult);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x1D:
|
||||
code.mov(rax, (u64)dmultu);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x1E:
|
||||
code.mov(rax, (u64)ddiv);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x1F:
|
||||
code.mov(rax, (u64)ddivu);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x20:
|
||||
code.mov(rax, (u64)add);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x21:
|
||||
code.mov(rax, (u64)addu);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x22:
|
||||
code.mov(rax, (u64)sub);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x23:
|
||||
code.mov(rax, (u64)subu);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x24:
|
||||
code.mov(rax, (u64)and_);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x25:
|
||||
code.mov(rax, (u64)or_);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x26:
|
||||
code.mov(rax, (u64)xor_);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x27:
|
||||
code.mov(rax, (u64)nor);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x2A:
|
||||
code.mov(rax, (u64)slt);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x2B:
|
||||
code.mov(rax, (u64)sltu);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x2C:
|
||||
code.mov(rax, (u64)dadd);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x2D:
|
||||
code.mov(rax, (u64)daddu);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x2E:
|
||||
code.mov(rax, (u64)dsub);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x2F:
|
||||
code.mov(rax, (u64)dsubu);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x30:
|
||||
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
|
||||
code.mov(rcx, qword[rdi + GPR_OFFSET(RT(instr), this)]);
|
||||
code.xor_(rsi, rsi);
|
||||
code.cmp(r8, rcx);
|
||||
code.setge(sil);
|
||||
code.mov(rax, (u64)trap);
|
||||
code.call(rax);
|
||||
res = true;
|
||||
break;
|
||||
case 0x31:
|
||||
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
|
||||
code.mov(rcx, qword[rdi + GPR_OFFSET(RT(instr), this)]);
|
||||
code.xor_(rsi, rsi);
|
||||
code.cmp(r8, rcx);
|
||||
code.setae(sil);
|
||||
code.mov(rax, (u64)trap);
|
||||
code.call(rax);
|
||||
res = true;
|
||||
break;
|
||||
case 0x32:
|
||||
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
|
||||
code.mov(rcx, qword[rdi + GPR_OFFSET(RT(instr), this)]);
|
||||
code.xor_(rsi, rsi);
|
||||
code.cmp(r8, rcx);
|
||||
code.setl(sil);
|
||||
code.mov(rax, (u64)trap);
|
||||
code.call(rax);
|
||||
res = true;
|
||||
break;
|
||||
case 0x33:
|
||||
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
|
||||
code.mov(rcx, qword[rdi + GPR_OFFSET(RT(instr), this)]);
|
||||
code.xor_(rsi, rsi);
|
||||
code.cmp(r8, rcx);
|
||||
code.setb(sil);
|
||||
code.mov(rax, (u64)trap);
|
||||
code.call(rax);
|
||||
res = true;
|
||||
break;
|
||||
case 0x34:
|
||||
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
|
||||
code.mov(rcx, qword[rdi + GPR_OFFSET(RT(instr), this)]);
|
||||
code.xor_(rsi, rsi);
|
||||
code.cmp(r8, rcx);
|
||||
code.sete(sil);
|
||||
code.mov(rax, (u64)trap);
|
||||
code.call(rax);
|
||||
res = true;
|
||||
break;
|
||||
case 0x36:
|
||||
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
|
||||
code.mov(rcx, qword[rdi + GPR_OFFSET(RT(instr), this)]);
|
||||
code.xor_(rsi, rsi);
|
||||
code.cmp(r8, rcx);
|
||||
code.setne(sil);
|
||||
code.mov(rax, (u64)trap);
|
||||
code.call(rax);
|
||||
res = true;
|
||||
break;
|
||||
case 0x38:
|
||||
code.mov(rax, (u64)dsll);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x3A:
|
||||
code.mov(rax, (u64)dsrl);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x3B:
|
||||
code.mov(rax, (u64)dsra);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x3C:
|
||||
code.mov(rax, (u64)dsll32);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x3E:
|
||||
code.mov(rax, (u64)dsrl32);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x3F:
|
||||
code.mov(rax, (u64)dsra32);
|
||||
code.call(rax);
|
||||
break;
|
||||
default:
|
||||
Util::panic("Unimplemented special {} {} ({:08X}) (pc: {:016X})\n", (mask >> 3) & 7, mask & 7, instr, (u64)regs.oldPC);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool JIT::regimm(u32 instr) {
|
||||
u8 mask = ((instr >> 16) & 0x1F);
|
||||
// 000r_rccc
|
||||
switch (mask) { // TODO: named constants for clearer code
|
||||
case 0x00:
|
||||
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
|
||||
code.xor_(rdx, rdx);
|
||||
code.cmp(r8, 0);
|
||||
code.setl(dl);
|
||||
code.mov(rax, (u64)b);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x01:
|
||||
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
|
||||
code.xor_(rdx, rdx);
|
||||
code.cmp(r8, 0);
|
||||
code.setge(dl);
|
||||
code.mov(rax, (u64)b);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x02:
|
||||
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
|
||||
code.xor_(rdx, rdx);
|
||||
code.cmp(r8, 0);
|
||||
code.setl(dl);
|
||||
code.mov(rax, (u64)bl);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x03:
|
||||
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
|
||||
code.xor_(rdx, rdx);
|
||||
code.cmp(r8, 0);
|
||||
code.setge(dl);
|
||||
code.mov(rax, (u64)bl);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x08:
|
||||
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
|
||||
code.xor_(rsi, rsi);
|
||||
code.cmp(r8, s64(s16(instr)));
|
||||
code.setge(sil);
|
||||
code.mov(rax, (u64)trap);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x09:
|
||||
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
|
||||
code.xor_(rsi, rsi);
|
||||
code.cmp(r8, u64(s64(s16(instr))));
|
||||
code.setae(sil);
|
||||
code.mov(rax, (u64)trap);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x0A:
|
||||
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
|
||||
code.xor_(rsi, rsi);
|
||||
code.cmp(r8, s64(s16(instr)));
|
||||
code.setl(sil);
|
||||
code.mov(rax, (u64)trap);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x0B:
|
||||
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
|
||||
code.xor_(rsi, rsi);
|
||||
code.cmp(r8, u64(s64(s16(instr))));
|
||||
code.setb(sil);
|
||||
code.mov(rax, (u64)trap);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x0C:
|
||||
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
|
||||
code.xor_(rsi, rsi);
|
||||
code.cmp(r8, s64(s16(instr)));
|
||||
code.sete(sil);
|
||||
code.mov(rax, (u64)trap);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x0E:
|
||||
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
|
||||
code.xor_(rsi, rsi);
|
||||
code.cmp(r8, s64(s16(instr)));
|
||||
code.setne(sil);
|
||||
code.mov(rax, (u64)trap);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x10:
|
||||
code.mov(rcx, qword[rdi + GPR_OFFSET(RS(instr), this)]);
|
||||
code.xor_(rdx, rdx);
|
||||
code.cmp(rcx, 0);
|
||||
code.setl(dl);
|
||||
code.mov(rax, (u64)blink);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x11:
|
||||
code.mov(rcx, qword[rdi + GPR_OFFSET(RS(instr), this)]);
|
||||
code.xor_(rdx, rdx);
|
||||
code.cmp(rcx, 0);
|
||||
code.setge(dl);
|
||||
code.mov(rax, (u64)blink);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x12:
|
||||
code.mov(rcx, qword[rdi + GPR_OFFSET(RS(instr), this)]);
|
||||
code.xor_(rdx, rdx);
|
||||
code.cmp(rcx, 0);
|
||||
code.setl(dl);
|
||||
code.mov(rax, (u64)bllink);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x13:
|
||||
code.mov(rcx, qword[rdi + GPR_OFFSET(RS(instr), this)]);
|
||||
code.xor_(rdx, rdx);
|
||||
code.cmp(rcx, 0);
|
||||
code.setge(dl);
|
||||
code.mov(rax, (u64)bllink);
|
||||
code.call(rax);
|
||||
break;
|
||||
default:
|
||||
Util::panic("Unimplemented regimm {} {} ({:08X}) (pc: {:016X})\n", (mask >> 3) & 3, mask & 7, instr, (u64)regs.oldPC);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JIT::Exec(Mem& mem, u32 instr) {
|
||||
u8 mask = (instr >> 26) & 0x3f;
|
||||
bool res = false;
|
||||
|
||||
// 00rr_rccc
|
||||
switch(mask) { // TODO: named constants for clearer code
|
||||
case 0x00: res = special(instr); break;
|
||||
case 0x01: res = regimm(instr); break;
|
||||
case 0x02:
|
||||
code.mov(rax, (u64)j);
|
||||
code.call(rax);
|
||||
res = true;
|
||||
break;
|
||||
case 0x03:
|
||||
code.mov(rax, (u64)jal);
|
||||
code.call(rax);
|
||||
res = true;
|
||||
break;
|
||||
case 0x04:
|
||||
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
|
||||
code.mov(r9, qword[rdi + GPR_OFFSET(RT(instr), this)]);
|
||||
code.xor_(rdx, rdx);
|
||||
code.cmp(r8, r9);
|
||||
code.sete(dl);
|
||||
code.mov(rax, (u64)b);
|
||||
code.call(rax);
|
||||
res = true;
|
||||
break;
|
||||
case 0x05:
|
||||
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
|
||||
code.mov(r9, qword[rdi + GPR_OFFSET(RT(instr), this)]);
|
||||
code.xor_(rdx, rdx);
|
||||
code.cmp(r8, r9);
|
||||
code.setne(dl);
|
||||
code.mov(rax, (u64)b);
|
||||
code.call(rax);
|
||||
res = true;
|
||||
break;
|
||||
case 0x06:
|
||||
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
|
||||
code.xor_(rdx, rdx);
|
||||
code.test(r8, r8);
|
||||
code.setnz(dl);
|
||||
code.mov(rax, (u64)b);
|
||||
code.call(rax);
|
||||
res = true;
|
||||
break;
|
||||
case 0x07:
|
||||
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
|
||||
code.xor_(rdx, rdx);
|
||||
code.test(r8, r8);
|
||||
code.setg(dl);
|
||||
code.mov(rax, (u64)b);
|
||||
code.call(rax);
|
||||
res = true;
|
||||
break;
|
||||
case 0x08:
|
||||
code.mov(rax, (u64)addi);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x09:
|
||||
code.mov(rax, (u64)addiu);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x0A:
|
||||
code.mov(rax, (u64)slti);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x0B:
|
||||
code.mov(rax, (u64)sltiu);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x0C:
|
||||
code.mov(rax, (u64)andi);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x0D:
|
||||
code.mov(rax, (u64)ori);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x0E:
|
||||
code.mov(rax, (u64)xori);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x0F:
|
||||
code.mov(rax, (u64)lui);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x10: cop0Decode(*this, instr); break;
|
||||
case 0x11: res = cop1Decode(*this, instr); break;
|
||||
case 0x12: cop2Decode(instr); break;
|
||||
case 0x14:
|
||||
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
|
||||
code.mov(rcx, qword[rdi + GPR_OFFSET(RT(instr), this)]);
|
||||
code.xor_(rdx, rdx);
|
||||
code.cmp(r8, rcx);
|
||||
code.sete(dl);
|
||||
code.mov(rax, (u64)bl);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x15:
|
||||
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
|
||||
code.mov(rcx, qword[rdi + GPR_OFFSET(RT(instr), this)]);
|
||||
code.xor_(rdx, rdx);
|
||||
code.cmp(r8, rcx);
|
||||
code.setne(dl);
|
||||
code.mov(rax, (u64)bl);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x16:
|
||||
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
|
||||
code.xor_(rdx, rdx);
|
||||
code.cmp(r8, 0);
|
||||
code.setle(dl);
|
||||
code.mov(rax, (u64)bl);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x17:
|
||||
code.mov(r8, qword[rdi + GPR_OFFSET(RS(instr), this)]);
|
||||
code.xor_(rdx, rdx);
|
||||
code.cmp(r8, 0);
|
||||
code.setg(dl);
|
||||
code.mov(rax, (u64)b);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x18:
|
||||
code.mov(rax, (u64)daddi);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x19:
|
||||
code.mov(rax, (u64)daddiu);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x1A:
|
||||
code.mov(rax, (u64)ldl);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x1B:
|
||||
code.mov(rax, (u64)ldr);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x1F: Util::panic("[RECOMPILER] Unhandled reserved instruction exception {:016X}\n", regs.oldPC); break;
|
||||
case 0x20:
|
||||
code.mov(rax, (u64)lb);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x21:
|
||||
code.mov(rax, (u64)lh);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x22:
|
||||
code.mov(rax, (u64)lwl);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x23:
|
||||
code.mov(rax, (u64)lw);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x24:
|
||||
code.mov(rax, (u64)lbu);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x25:
|
||||
code.mov(rax, (u64)lhu);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x26:
|
||||
code.mov(rax, (u64)lwr);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x27:
|
||||
code.mov(rax, (u64)lwu);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x28:
|
||||
code.mov(rax, (u64)sb);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x29:
|
||||
code.mov(rax, (u64)sh);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x2A:
|
||||
code.mov(rax, (u64)swl);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x2B:
|
||||
code.mov(rax, (u64)sw);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x2C:
|
||||
code.mov(rax, (u64)sdl);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x2D:
|
||||
code.mov(rax, (u64)sdr);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x2E:
|
||||
code.mov(rax, (u64)swr);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x2F: break; // CACHE
|
||||
case 0x30:
|
||||
code.mov(rax, (u64)ll);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x31:
|
||||
code.mov(rax, (u64)lwc1);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x34:
|
||||
code.mov(rax, (u64)lld);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x35:
|
||||
code.mov(rax, (u64)ldc1);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x37:
|
||||
code.mov(rax, (u64)ld);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x38:
|
||||
code.mov(rax, (u64)sc);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x39:
|
||||
code.mov(rax, (u64)swc1);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x3C:
|
||||
code.mov(rax, (u64)scd);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x3D:
|
||||
code.mov(rax, (u64)sdc1);
|
||||
code.call(rax);
|
||||
break;
|
||||
case 0x3F:
|
||||
code.mov(rax, (u64)sd);
|
||||
code.call(rax);
|
||||
break;
|
||||
default:
|
||||
Util::panic("Unimplemented instruction {:02X} ({:08X}) (pc: {:016X})\n", mask, instr, (u64)regs.oldPC);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,94 +0,0 @@
|
||||
#pragma once
|
||||
#include <JIT.hpp>
|
||||
|
||||
namespace n64 {
|
||||
void add(JIT&, u32);
|
||||
void addu(JIT&, u32);
|
||||
void addi(JIT&, u32);
|
||||
void addiu(JIT&, u32);
|
||||
void andi(JIT&, u32);
|
||||
void and_(JIT&, u32);
|
||||
void branch(JIT&, bool, s64);
|
||||
void branch_likely(JIT&, bool, s64);
|
||||
void b(JIT&, u32, bool);
|
||||
void blink(JIT&, u32, bool);
|
||||
void bl(JIT&, u32, bool);
|
||||
void bllink(JIT&, u32, bool);
|
||||
void dadd(JIT&, u32);
|
||||
void daddu(JIT&, u32);
|
||||
void daddi(JIT&, u32);
|
||||
void daddiu(JIT&, u32);
|
||||
void ddiv(JIT&, u32);
|
||||
void ddivu(JIT&, u32);
|
||||
void div(JIT&, u32);
|
||||
void divu(JIT&, u32);
|
||||
void dmult(JIT&, u32);
|
||||
void dmultu(JIT&, u32);
|
||||
void dsll(JIT&, u32);
|
||||
void dsllv(JIT&, u32);
|
||||
void dsll32(JIT&, u32);
|
||||
void dsra(JIT&, u32);
|
||||
void dsrav(JIT&, u32);
|
||||
void dsra32(JIT&, u32);
|
||||
void dsrl(JIT&, u32);
|
||||
void dsrlv(JIT&, u32);
|
||||
void dsrl32(JIT&, u32);
|
||||
void dsub(JIT&, u32);
|
||||
void dsubu(JIT&, u32);
|
||||
void j(JIT&, u32);
|
||||
void jr(JIT&, u32);
|
||||
void jal(JIT&, u32);
|
||||
void jalr(JIT&, u32);
|
||||
void lui(JIT&, u32);
|
||||
void lbu(JIT&, u32);
|
||||
void lb(JIT&, u32);
|
||||
void ld(JIT&, u32);
|
||||
void ldl(JIT&, u32);
|
||||
void ldr(JIT&, u32);
|
||||
void lh(JIT&, u32);
|
||||
void lhu(JIT&, u32);
|
||||
void ll(JIT&, u32);
|
||||
void lld(JIT&, u32);
|
||||
void lw(JIT&, u32);
|
||||
void lwl(JIT&, u32);
|
||||
void lwu(JIT&, u32);
|
||||
void lwr(JIT&, u32);
|
||||
void mfhi(JIT&, u32);
|
||||
void mflo(JIT&, u32);
|
||||
void mult(JIT&, u32);
|
||||
void multu(JIT&, u32);
|
||||
void mthi(JIT&, u32);
|
||||
void mtlo(JIT&, u32);
|
||||
void nor(JIT&, u32);
|
||||
void sb(JIT&, u32);
|
||||
void sc(JIT&, u32);
|
||||
void scd(JIT&, u32);
|
||||
void sd(JIT&, u32);
|
||||
void sdl(JIT&, u32);
|
||||
void sdr(JIT&, u32);
|
||||
void sh(JIT&, u32);
|
||||
void sw(JIT&, u32);
|
||||
void swl(JIT&, u32);
|
||||
void swr(JIT&, u32);
|
||||
void slti(JIT&, u32);
|
||||
void sltiu(JIT&, u32);
|
||||
void slt(JIT&, u32);
|
||||
void sltu(JIT&, u32);
|
||||
void sll(JIT&, u32);
|
||||
void sllv(JIT&, u32);
|
||||
void sub(JIT&, u32);
|
||||
void subu(JIT&, u32);
|
||||
void sra(JIT&, u32);
|
||||
void srav(JIT&, u32);
|
||||
void srl(JIT&, u32);
|
||||
void srlv(JIT&, u32);
|
||||
void trap(JIT&, bool);
|
||||
void or_(JIT&, u32);
|
||||
void ori(JIT&, u32);
|
||||
void xor_(JIT&, u32);
|
||||
void xori(JIT&, u32);
|
||||
void mtc2(JIT&, u32);
|
||||
void mfc2(JIT&, u32);
|
||||
void dmtc2(JIT&, u32);
|
||||
void dmfc2(JIT&, u32);
|
||||
}
|
||||
@@ -349,6 +349,7 @@ void PIF::UpdateController() {
|
||||
} else {
|
||||
yclamped /= SDL_JOYSTICK_AXIS_MAX;
|
||||
}
|
||||
|
||||
yclamped *= 86;
|
||||
|
||||
joybusDevices[channel].controller.joy_x = xclamped;
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
|
||||
namespace n64 {
|
||||
void PIF::InitDevices(SaveType saveType) {
|
||||
for (int i = 0; i < 4; i++) { //TODO: make this configurable
|
||||
joybusDevices[0].type = JOYBUS_CONTROLLER;
|
||||
joybusDevices[0].accessoryType = ACCESSORY_MEMPACK;
|
||||
for (int i = 1; i < 4; i++) { //TODO: make this configurable
|
||||
joybusDevices[i].type = JOYBUS_NONE;
|
||||
joybusDevices[i].accessoryType = ACCESSORY_NONE;
|
||||
}
|
||||
joybusDevices[0].type = JOYBUS_CONTROLLER;
|
||||
joybusDevices[0].accessoryType = ACCESSORY_MEMPACK;
|
||||
|
||||
if (saveType == SAVE_EEPROM_4k) {
|
||||
joybusDevices[4].type = JOYBUS_4KB_EEPROM;
|
||||
|
||||
@@ -69,7 +69,7 @@ void VI::Write(MI& mi, Registers& regs, u32 paddr, u32 val) {
|
||||
case 0x04400018: {
|
||||
vsync = val & 0x3FF;
|
||||
numHalflines = vsync >> 1;
|
||||
cyclesPerHalfline = N64_CYCLES_PER_FRAME(false) / numHalflines;
|
||||
cyclesPerHalfline = N64_CYCLES_PER_FRAME(isPal) / numHalflines;
|
||||
} break;
|
||||
case 0x0440001C: {
|
||||
hsync = val & 0x3FF;
|
||||
|
||||
@@ -88,6 +88,7 @@ struct VI {
|
||||
u32 origin, width, current;
|
||||
u32 vsync, hsync, intr;
|
||||
AxisStart hstart{}, vstart{};
|
||||
bool isPal = false;
|
||||
int swaps{};
|
||||
int numHalflines;
|
||||
int numFields;
|
||||
|
||||
@@ -37,4 +37,4 @@ using m128i = __m128i;
|
||||
|
||||
#define unlikely(exp) __builtin_expect(exp, 0)
|
||||
#define likely(exp) __builtin_expect(exp, 1)
|
||||
#define INLINE static inline __attribute__((always_inline))
|
||||
#define FORCE_INLINE inline __attribute__((always_inline))
|
||||
@@ -9,10 +9,17 @@ App::App() : window(core) {
|
||||
|
||||
void App::Run() {
|
||||
SDL_EventState(SDL_DROPFILE, SDL_ENABLE);
|
||||
n64::SI& si = core.cpu->mem.mmio.si;
|
||||
n64::SI& si = core.cpu.mem.mmio.si;
|
||||
|
||||
while (!core.done) {
|
||||
core.Run(window, window.settings.GetVolumeL(), window.settings.GetVolumeL());
|
||||
if(core.romLoaded) {
|
||||
if(!core.pause) {
|
||||
core.Run(window.settings.GetVolumeL(), window.settings.GetVolumeR());
|
||||
}
|
||||
UpdateScreenParallelRdp(core, window, core.GetVI());
|
||||
} else {
|
||||
UpdateScreenParallelRdpNoGame(core, window);
|
||||
}
|
||||
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event)) {
|
||||
|
||||
@@ -27,34 +27,16 @@ Settings::Settings(n64::Core& core) {
|
||||
if(fileExists) {
|
||||
settingsFile = std::fstream("resources/settings.json", std::fstream::in | std::fstream::out);
|
||||
settings = json::parse(settingsFile);
|
||||
auto entryCpuType = settings["cpu"]["type"];
|
||||
if(!entryCpuType.empty()) {
|
||||
cpuType = entryCpuType.get<std::string>();
|
||||
if(cpuType == "jit") {
|
||||
core.cpuType = n64::CpuType::JIT;
|
||||
} else if(cpuType == "interpreter") {
|
||||
core.cpuType = n64::CpuType::Interpreter;
|
||||
} else {
|
||||
Util::panic("Unrecognized cpu type: {}\n", cpuType);
|
||||
}
|
||||
} else {
|
||||
settingsFile.clear();
|
||||
settings["cpu"]["type"] = "interpreter";
|
||||
settingsFile << settings;
|
||||
core.cpuType = n64::CpuType::Interpreter;
|
||||
}
|
||||
|
||||
checkjsonentry(volumeR, float, "audio", "volumeR", 0.5);
|
||||
checkjsonentry(volumeL, float, "audio", "volumeL", 0.5);
|
||||
checkjsonentry(lockChannels, bool, "audio", "lockChannels", true);
|
||||
} else {
|
||||
settingsFile = std::fstream("resources/settings.json", std::fstream::trunc | std::fstream::in | std::fstream::out);
|
||||
settings["cpu"]["type"] = "interpreter";
|
||||
settings["audio"]["volumeR"] = 0.5;
|
||||
settings["audio"]["volumeL"] = 0.5;
|
||||
settings["audio"]["lockChannels"] = true;
|
||||
|
||||
core.cpuType = n64::CpuType::Interpreter;
|
||||
volumeR = 0.5;
|
||||
volumeL = 0.5;
|
||||
lockChannels = true;
|
||||
@@ -62,17 +44,6 @@ Settings::Settings(n64::Core& core) {
|
||||
settingsFile << settings;
|
||||
}
|
||||
settingsFile.close();
|
||||
|
||||
switch(core.cpuType) {
|
||||
case n64::CpuType::Interpreter:
|
||||
core.cpu = std::make_unique<n64::Interpreter>();
|
||||
break;
|
||||
case n64::CpuType::JIT:
|
||||
core.cpu = std::make_unique<n64::JIT>();
|
||||
break;
|
||||
case n64::CpuType::COUNT:
|
||||
Util::panic("BRUH\n");
|
||||
}
|
||||
}
|
||||
|
||||
Settings::~Settings() {
|
||||
@@ -81,7 +52,6 @@ Settings::~Settings() {
|
||||
if(fileExists) {
|
||||
settingsFile = std::fstream("resources/settings.json", std::fstream::trunc | std::fstream::out);
|
||||
|
||||
settings["cpu"]["type"] = cpuType;
|
||||
settings["audio"]["volumeR"] = volumeR;
|
||||
settings["audio"]["volumeL"] = volumeL;
|
||||
settings["audio"]["lockChannels"] = lockChannels;
|
||||
@@ -89,7 +59,6 @@ Settings::~Settings() {
|
||||
} else {
|
||||
settingsFile = std::fstream("resources/settings.json", std::fstream::out);
|
||||
|
||||
settings["cpu"]["type"] = cpuType;
|
||||
settings["audio"]["volumeR"] = volumeR;
|
||||
settings["audio"]["volumeL"] = volumeL;
|
||||
settings["audio"]["lockChannels"] = lockChannels;
|
||||
@@ -103,30 +72,12 @@ void Settings::RenderWidget(bool& show) {
|
||||
if(show) {
|
||||
ImGui::OpenPopup("Settings");
|
||||
if(ImGui::BeginPopupModal("Settings", &show)) {
|
||||
enum class SelectedSetting { CPU, Audio, COUNT };
|
||||
enum class SelectedSetting { Audio, COUNT };
|
||||
static SelectedSetting selectedSetting = SelectedSetting::Audio;
|
||||
const char *categories[(int)SelectedSetting::COUNT] = { "CPU", "Audio" };
|
||||
const char *categories[(int)SelectedSetting::COUNT] = { "Audio" };
|
||||
CreateComboList("##", (int*)&selectedSetting, categories, (int)SelectedSetting::COUNT);
|
||||
ImGui::Separator();
|
||||
switch (selectedSetting) {
|
||||
case SelectedSetting::CPU: {
|
||||
const char* cpuTypes[(int)n64::CpuType::COUNT] = { "Interpreter", "JIT" };
|
||||
static n64::CpuType currentType = n64::CpuType::Interpreter;
|
||||
if (cpuType == "jit") currentType = n64::CpuType::JIT;
|
||||
|
||||
if (CreateComboList("Core type", (int*)¤tType, cpuTypes, (int)n64::CpuType::COUNT)) {
|
||||
switch (currentType) {
|
||||
case n64::CpuType::Interpreter:
|
||||
cpuType = "interpreter";
|
||||
break;
|
||||
case n64::CpuType::JIT:
|
||||
cpuType = "jit";
|
||||
break;
|
||||
case n64::CpuType::COUNT:
|
||||
Util::panic("BRUH\n");
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case SelectedSetting::Audio:
|
||||
ImGui::Checkbox("Lock channels", &lockChannels);
|
||||
ImGui::SliderFloat("Volume L", &volumeL, 0, 1, "%.2f", ImGuiSliderFlags_NoInput);
|
||||
|
||||
@@ -11,11 +11,9 @@ struct Settings {
|
||||
inline float GetVolumeL() const { return volumeL; };
|
||||
inline float GetVolumeR() const { return volumeR; };
|
||||
inline bool GetLockChannels() const { return lockChannels; }
|
||||
inline std::string GetCpuType() const { return cpuType; }
|
||||
|
||||
void RenderWidget(bool& show);
|
||||
private:
|
||||
std::string cpuType = "interpreter";
|
||||
float volumeL = 0.0, volumeR = 0.0;
|
||||
bool lockChannels = true;
|
||||
json settings;
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace fs = std::filesystem;
|
||||
|
||||
Window::Window(n64::Core& core) : settings(core) {
|
||||
InitSDL();
|
||||
InitParallelRDP(core.cpu->mem.GetRDRAM(), window);
|
||||
InitParallelRDP(core.cpu.mem.GetRDRAM(), window);
|
||||
InitImgui();
|
||||
NFD::Init();
|
||||
}
|
||||
@@ -152,7 +152,7 @@ ImDrawData* Window::Present(n64::Core& core) {
|
||||
void Window::LoadROM(n64::Core& core, const std::string &path) {
|
||||
if(!path.empty()) {
|
||||
core.LoadROM(path);
|
||||
gameName = core.cpu->mem.rom.gameNameDB;
|
||||
gameName = core.cpu.mem.rom.gameNameDB;
|
||||
|
||||
if(gameName.empty()) {
|
||||
gameName = fs::path(path).stem().string();
|
||||
@@ -181,13 +181,13 @@ void Window::RenderMainMenuBar(n64::Core &core) {
|
||||
}
|
||||
}
|
||||
if (ImGui::MenuItem("Dump RDRAM")) {
|
||||
core.cpu->mem.DumpRDRAM();
|
||||
core.cpu.mem.DumpRDRAM();
|
||||
}
|
||||
if (ImGui::MenuItem("Dump IMEM")) {
|
||||
core.cpu->mem.DumpIMEM();
|
||||
core.cpu.mem.DumpIMEM();
|
||||
}
|
||||
if (ImGui::MenuItem("Dump DMEM")) {
|
||||
core.cpu->mem.DumpDMEM();
|
||||
core.cpu.mem.DumpDMEM();
|
||||
}
|
||||
if (ImGui::MenuItem("Exit")) {
|
||||
core.done = true;
|
||||
@@ -232,8 +232,8 @@ void Window::Render(n64::Core& core) {
|
||||
static u32 lastFrame = 0;
|
||||
if(!core.pause && lastFrame < ticks - 1000) {
|
||||
lastFrame = ticks;
|
||||
windowTitle += fmt::format(" | {:02d} VI/s", core.cpu->mem.mmio.vi.swaps);
|
||||
core.cpu->mem.mmio.vi.swaps = 0;
|
||||
windowTitle += fmt::format(" | {:02d} VI/s", core.cpu.mem.mmio.vi.swaps);
|
||||
core.cpu.mem.mmio.vi.swaps = 0;
|
||||
SDL_SetWindowTitle(window, windowTitle.c_str());
|
||||
windowTitle = shadowWindowTitle;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user