Dynarec + CMake restructure

This commit is contained in:
CocoSimone
2023-01-02 21:44:24 +01:00
parent 91dc3eabba
commit c915ebc11d
43 changed files with 2004 additions and 422 deletions

View File

@@ -1,8 +1,3 @@
cmake_minimum_required(VERSION 3.20)
project(imgui)
find_package(SDL2 CONFIG REQUIRED)
add_library(imgui add_library(imgui
imgui/imgui_demo.cpp imgui/imgui_demo.cpp
imgui/imgui_draw.cpp imgui/imgui_draw.cpp
@@ -23,5 +18,5 @@ if(WIN32)
add_compile_options(/EHa) add_compile_options(/EHa)
endif() endif()
target_include_directories(imgui PUBLIC ${SDL2_INCLUDE_DIR} ../parallel-rdp/parallel-rdp-standalone/vulkan-headers/include imgui imgui/backends) target_include_directories(imgui PUBLIC ../parallel-rdp/parallel-rdp-standalone/volk
target_link_libraries(imgui PUBLIC SDL2::SDL2main SDL2::SDL2) ../parallel-rdp/parallel-rdp-standalone/vulkan-headers/include)

View File

@@ -1,10 +1,5 @@
cmake_minimum_required(VERSION 3.20)
project(parallel-rdp)
file(GLOB_RECURSE parallel-rdp-cpp parallel-rdp-standalone/parallel-rdp/*.cpp) file(GLOB_RECURSE parallel-rdp-cpp parallel-rdp-standalone/parallel-rdp/*.cpp)
find_package(SDL2 CONFIG REQUIRED)
add_library(parallel-rdp add_library(parallel-rdp
${parallel-rdp-cpp} ${parallel-rdp-cpp}
ParallelRDPWrapper.cpp ParallelRDPWrapper.cpp
@@ -52,32 +47,12 @@ add_library(parallel-rdp
target_compile_definitions(parallel-rdp PUBLIC GRANITE_VULKAN_MT) target_compile_definitions(parallel-rdp PUBLIC GRANITE_VULKAN_MT)
target_include_directories(parallel-rdp PUBLIC target_include_directories(parallel-rdp PUBLIC
${SDL2_INCLUDE_DIR}
${Vulkan_INCLUDE_DIR}
parallel-rdp-standalone/parallel-rdp parallel-rdp-standalone/parallel-rdp
parallel-rdp-standalone/volk parallel-rdp-standalone/volk
parallel-rdp-standalone/spirv-cross parallel-rdp-standalone/spirv-cross
parallel-rdp-standalone/vulkan parallel-rdp-standalone/vulkan
parallel-rdp-standalone/vulkan-headers/include parallel-rdp-standalone/vulkan-headers/include
parallel-rdp-standalone/util parallel-rdp-standalone/util
../../src/backend
../../src/utils
../../src/backend/core/
../../src/backend/core/mmio
../../src/backend/core/interpreter/
../../src/backend/core/registers
parallel-rdp-standalone
..
../../src/frontend
../../src/frontend/imgui
../../src/frontend/imgui/debugger
../../src
../imgui
../imgui/imgui
../imgui/imgui/backends
../fmt/include
../discord-rpc/include
.
) )
if(WIN32) if(WIN32)
@@ -85,10 +60,8 @@ if(WIN32)
add_compile_options(/EHa) add_compile_options(/EHa)
endif() endif()
target_link_libraries(parallel-rdp SDL2::SDL2main SDL2::SDL2)
if(WIN32) if(WIN32)
target_compile_definitions(parallel-rdp PUBLIC VK_USE_PLATFORM_WIN32_KHR) target_compile_definitions(parallel-rdp PUBLIC VK_USE_PLATFORM_WIN32_KHR)
else() else()
target_link_libraries(parallel-rdp dl) target_link_libraries(parallel-rdp PUBLIC dl)
endif() endif()

View File

@@ -5,7 +5,7 @@
#include <log.hpp> #include <log.hpp>
#include <File.hpp> #include <File.hpp>
#include <SDL2/SDL_vulkan.h> #include <SDL2/SDL_vulkan.h>
#include <imgui/backends/imgui_impl_vulkan.h> #include <imgui_impl_vulkan.h>
#include <imgui/Window.hpp> #include <imgui/Window.hpp>
using namespace Vulkan; using namespace Vulkan;

View File

@@ -4,54 +4,56 @@ project(gadolinium)
set(BUILD_SHARED_LIBS OFF) set(BUILD_SHARED_LIBS OFF)
set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD 17)
file(GLOB_RECURSE CORE_SOURCES backend/*.cpp)
file(GLOB_RECURSE CORE_HEADERS backend/*.hpp)
file(GLOB_RECURSE FRONTEND_SOURCES frontend/*.cpp)
file(GLOB_RECURSE FRONTEND_HEADERS frontend/*.hpp)
find_package(fmt REQUIRED)
find_package(SDL2 REQUIRED) find_package(SDL2 REQUIRED)
find_package(fmt REQUIRED)
find_package(nlohmann_json REQUIRED) find_package(nlohmann_json REQUIRED)
option(RAPIDJSON_BUILD_DOC "Build rapidjson documentation." OFF) option(RAPIDJSON_BUILD_DOC "Build rapidjson documentation." OFF)
option(RAPIDJSON_BUILD_EXAMPLES "Build rapidjson examples." OFF) option(RAPIDJSON_BUILD_EXAMPLES "Build rapidjson examples." OFF)
option(RAPIDJSON_BUILD_TESTS "Build rapidjson perftests and unittests." OFF) option(RAPIDJSON_BUILD_TESTS "Build rapidjson perftests and unittests." OFF)
add_subdirectory(../external/parallel-rdp prdp) include_directories(
add_subdirectory(../external/imgui imgui)
add_subdirectory(../external/nativefiledialog-extended nfd)
add_subdirectory(../external/discord-rpc discord-rpc)
add_executable(gadolinium
${CORE_SOURCES}
${CORE_HEADERS}
${FRONTEND_SOURCES}
${FRONTEND_HEADERS}
main.cpp
common.hpp
backend/Scheduler.cpp
backend/Scheduler.hpp)
target_include_directories(gadolinium PRIVATE
. .
backend utils
backend/core
backend/core/interpreter/
backend/core/registers
backend/core/mmio
backend/core/rsp
frontend frontend
frontend/imgui frontend/imgui
utils backend
backend/core
backend/core/mmio
backend/core/registers
backend/core/rsp
../external ../external
../external/xbyak ../external/xbyak
../external/imgui/imgui ../external/parallel-rdp
../external/parallel-rdp/ ../external/parallel-rdp/parallel-rdp-standalone/parallel-rdp
../external/parallel-rdp/parallel-rdp-standalone/volk
../external/parallel-rdp/parallel-rdp-standalone/spirv-cross
../external/parallel-rdp/parallel-rdp-standalone/vulkan
../external/parallel-rdp/parallel-rdp-standalone/vulkan-headers/include
../external/parallel-rdp/parallel-rdp-standalone/util
../external/nativefiledialog-extended/src/include ../external/nativefiledialog-extended/src/include
../external/imgui/imgui
../external/imgui/imgui/backends
../external/discord-rpc/include ../external/discord-rpc/include
${SDL2_INCLUDE_DIR} ${SDL2_INCLUDE_DIRS}
) )
add_subdirectory(frontend)
add_subdirectory(frontend/imgui)
add_subdirectory(backend)
add_subdirectory(backend/core)
add_subdirectory(backend/core/dynarec)
add_subdirectory(backend/core/interpreter)
add_subdirectory(backend/core/mmio)
add_subdirectory(backend/core/registers)
add_subdirectory(backend/core/rsp)
add_subdirectory(../external/discord-rpc discord-rpc)
add_subdirectory(../external/imgui imgui)
add_subdirectory(../external/nativefiledialog-extended nfd)
add_subdirectory(../external/parallel-rdp parallel-rdp)
add_executable(gadolinium main.cpp)
file(COPY ${PROJECT_SOURCE_DIR}/../resources/ DESTINATION ${PROJECT_BINARY_DIR}/resources/) file(COPY ${PROJECT_SOURCE_DIR}/../resources/ DESTINATION ${PROJECT_BINARY_DIR}/resources/)
file(REMOVE file(REMOVE
${PROJECT_BINARY_DIR}/resources/mario.png ${PROJECT_BINARY_DIR}/resources/mario.png
@@ -80,4 +82,5 @@ else()
endif() endif()
endif() endif()
target_link_libraries(gadolinium PRIVATE discord-rpc SDL2::SDL2main SDL2::SDL2 nfd parallel-rdp fmt::fmt imgui nlohmann_json::nlohmann_json) target_link_libraries(gadolinium PUBLIC SDL2::SDL2main SDL2::SDL2 frontend frontend-imgui
discord-rpc imgui nfd parallel-rdp backend fmt::fmt nlohmann_json::nlohmann_json core dynarec registers interpreter mmio rsp)

View File

@@ -0,0 +1,4 @@
file(GLOB SOURCES *.cpp)
file(GLOB HEADERS *.hpp)
add_library(backend ${SOURCES} ${HEADERS})

View File

@@ -45,19 +45,21 @@ void Core::Run(Window& window, float volumeL, float volumeR) {
} }
for(;cycles <= mmio.vi.cyclesPerHalfline; cycles++, frameCycles++) { for(;cycles <= mmio.vi.cyclesPerHalfline; cycles++, frameCycles++) {
CpuStep(); int cpuCount = CpuStep();
if(!mmio.rsp.spStatus.halt) { while(cpuCount--) {
if (!mmio.rsp.spStatus.halt) {
regs.steps++; regs.steps++;
if(regs.steps > 2) { if (regs.steps > 2) {
mmio.rsp.steps += 2; mmio.rsp.steps += 2;
regs.steps -= 3; regs.steps -= 3;
} }
while(mmio.rsp.steps > 0) { while (mmio.rsp.steps > 0) {
mmio.rsp.steps--; mmio.rsp.steps--;
mmio.rsp.Step(regs, mem); mmio.rsp.Step(regs, mem);
} }
} }
}
mmio.ai.Step(mem, regs, 1, volumeL, volumeR); mmio.ai.Step(mem, regs, 1, volumeL, volumeR);
scheduler.tick(1, mem, regs); scheduler.tick(1, mem, regs);

View File

@@ -1,9 +1,10 @@
#pragma once #pragma once
#include <SDL_events.h> #include <SDL2/SDL_events.h>
#include <Interpreter.hpp> #include <backend/core/Interpreter.hpp>
#include <Mem.hpp> #include <backend/core/Mem.hpp>
#include <string> #include <string>
#include <Dynarec.hpp> #include <backend/core/Dynarec.hpp>
#include <backend/core/registers/Registers.hpp>
struct Window; struct Window;
@@ -29,10 +30,10 @@ struct Core {
} }
} }
void CpuStep() { int CpuStep() {
switch(cpuType) { switch(cpuType) {
case CpuType::Dynarec: cpuDynarec.Step(mem, regs); break; case CpuType::Dynarec: return cpuDynarec.Step(mem, regs);
case CpuType::Interpreter: cpuInterp.Step(mem, regs); break; case CpuType::Interpreter: cpuInterp.Step(mem, regs); return 1;
} }
} }
@@ -48,7 +49,7 @@ struct Core {
Mem mem; Mem mem;
CpuType cpuType = CpuType::Dynarec; CpuType cpuType = CpuType::Dynarec;
Interpreter cpuInterp; Interpreter cpuInterp;
Dynarec cpuDynarec; JIT::Dynarec cpuDynarec;
Registers regs; Registers regs;
}; };
} }

View File

@@ -1,5 +1,5 @@
#pragma once #pragma once
#include <PIF.hpp> #include <backend/core/mmio/PIF.hpp>
void LoadTAS(const char* filename); void LoadTAS(const char* filename);
void UnloadTAS(); void UnloadTAS();

View File

@@ -0,0 +1,4 @@
file(GLOB SOURCES *.cpp)
file(GLOB HEADERS *.hpp)
add_library(core ${SOURCES} ${HEADERS})

View File

@@ -1,11 +1,52 @@
#include <Dynarec.hpp> #include <Dynarec.hpp>
#include <Registers.hpp>
namespace n64 { namespace n64::JIT {
void Dynarec::Reset() { Dynarec::Dynarec() : code(Xbyak::DEFAULT_MAX_CODE_SIZE, Xbyak::AutoGrow) {}
void Dynarec::Recompile(Registers& regs, Mem& mem) {
bool branch = false, prevBranch = false;
u16 start_addr = regs.pc;
Fn block = code.getCurr<Fn>();
while(!prevBranch) {
instrInBlock++;
prevBranch = branch;
u32 instr = mem.Read32(regs, regs.pc, regs.pc);
regs.oldPC = regs.pc;
regs.pc = regs.nextPC;
regs.nextPC += 4;
branch = Exec(regs, mem, instr);
}
code.ret();
codeCache[start_addr >> 12][start_addr & 15] = block;
block();
} }
void Dynarec::Step(Mem &mem, Registers& regs) { void Dynarec::AllocateOuter(Registers& regs) {
codeCache[regs.pc >> 20] = (Fn*)calloc(0xFFF, sizeof(Fn));
}
int Dynarec::Step(Mem &mem, Registers& regs) {
instrInBlock = 0;
regs.gpr[0] = 0;
regs.prevDelaySlot = regs.delaySlot;
regs.delaySlot = false;
if(codeCache[regs.pc >> 20]) {
if(codeCache[regs.pc >> 20][regs.pc & 0xfff]) {
codeCache[regs.pc >> 20][regs.pc & 0xfff]();
} else {
Recompile(regs, mem);
}
} else {
AllocateOuter(regs);
Recompile(regs, mem);
}
return instrInBlock;
} }
} }

View File

@@ -1,114 +1,28 @@
#pragma once #pragma once
#include <xbyak/xbyak.h> #include <xbyak/xbyak.h>
#include <Mem.hpp> #include <backend/core/Mem.hpp>
#include <Registers.hpp>
namespace n64 { namespace n64::JIT {
using Block = void (*)(Mem&, Registers&); using Fn = void (*)();
struct Dynarec { struct Dynarec {
void Step(Mem&, Registers&); Dynarec();
void Reset(); int Step(Mem&, n64::Registers&);
private: void Reset() {
code.reset();
}
u64 cop2Latch{}; u64 cop2Latch{};
friend struct Cop1;
void cop2Decode(Registers&, u32);
void special(Registers&, Mem&, u32);
void regimm(Registers&, u32);
void Exec(Registers&, Mem&, u32);
void add(Registers&, u32);
void addu(Registers&, u32);
void addi(Registers&, u32);
void addiu(Registers&, u32);
void andi(Registers&, u32);
void and_(Registers&, u32);
void branch(Registers&, bool, s64);
void branch_likely(Registers&, bool, s64);
void b(Registers&, u32, bool);
void blink(Registers&, u32, bool);
void bl(Registers&, u32, bool);
void bllink(Registers&, u32, bool);
void dadd(Registers&, u32);
void daddu(Registers&, u32);
void daddi(Registers&, u32);
void daddiu(Registers&, u32);
void ddiv(Registers&, u32);
void ddivu(Registers&, u32);
void div(Registers&, u32);
void divu(Registers&, u32);
void dmult(Registers&, u32);
void dmultu(Registers&, u32);
void dsll(Registers&, u32);
void dsllv(Registers&, u32);
void dsll32(Registers&, u32);
void dsra(Registers&, u32);
void dsrav(Registers&, u32);
void dsra32(Registers&, u32);
void dsrl(Registers&, u32);
void dsrlv(Registers&, u32);
void dsrl32(Registers&, u32);
void dsub(Registers&, u32);
void dsubu(Registers&, u32);
void j(Registers&, u32);
void jr(Registers&, u32);
void jal(Registers&, u32);
void jalr(Registers&, u32);
void lui(Registers&, u32);
void lbu(Registers&, Mem&, u32);
void lb(Registers&, Mem&, u32);
void ld(Registers&, Mem&, u32);
void ldl(Registers&, Mem&, u32);
void ldr(Registers&, Mem&, u32);
void lh(Registers&, Mem&, u32);
void lhu(Registers&, Mem&, u32);
void ll(Registers&, Mem&, u32);
void lld(Registers&, Mem&, u32);
void lw(Registers&, Mem&, u32);
void lwl(Registers&, Mem&, u32);
void lwu(Registers&, Mem&, u32);
void lwr(Registers&, Mem&, u32);
void mfhi(Registers&, u32);
void mflo(Registers&, u32);
void mult(Registers&, u32);
void multu(Registers&, u32);
void mthi(Registers&, u32);
void mtlo(Registers&, u32);
void nor(Registers&, u32);
void sb(Registers&, Mem&, u32);
void sc(Registers&, Mem&, u32);
void scd(Registers&, Mem&, u32);
void sd(Registers&, Mem&, u32);
void sdl(Registers&, Mem&, u32);
void sdr(Registers&, Mem&, u32);
void sh(Registers&, Mem&, u32);
void sw(Registers&, Mem&, u32);
void swl(Registers&, Mem&, u32);
void swr(Registers&, Mem&, u32);
void slti(Registers&, u32);
void sltiu(Registers&, u32);
void slt(Registers&, u32);
void sltu(Registers&, u32);
void sll(Registers&, u32);
void sllv(Registers&, u32);
void sub(Registers&, u32);
void subu(Registers&, u32);
void sra(Registers&, u32);
void srav(Registers&, u32);
void srl(Registers&, u32);
void srlv(Registers&, u32);
void trap(Registers&, bool);
void or_(Registers&, u32);
void ori(Registers&, u32);
void xor_(Registers&, u32);
void xori(Registers&, u32);
void mtc2(Registers&, u32);
void mfc2(Registers&, u32);
void dmtc2(Registers&, u32);
void dmfc2(Registers&, u32);
void ctc2(Registers&, u32);
void cfc2(Registers&, u32);
Xbyak::CodeGenerator code; Xbyak::CodeGenerator code;
private:
friend struct Cop1;
Fn* codeCache[0x80000]{};
int instrInBlock = 0;
void Recompile(n64::Registers&, Mem&);
void AllocateOuter(n64::Registers&);
void cop2Decode(n64::Registers&, u32);
bool special(n64::Registers&, u32);
bool regimm(n64::Registers&, u32);
bool Exec(n64::Registers&, Mem&, u32);
}; };
} }

View File

@@ -30,7 +30,7 @@ void Interpreter::Step(Mem& mem, Registers& regs) {
regs.delaySlot = false; regs.delaySlot = false;
if(ShouldServiceInterrupt(regs)) { if(ShouldServiceInterrupt(regs)) {
FireException(regs, ExceptionCode::Interrupt, 0, regs.pc); FireException(regs, ExceptionCode::Interrupt, 0, false);
return; return;
} }

View File

@@ -13,7 +13,7 @@ private:
friend struct Cop1; friend struct Cop1;
void cop2Decode(Registers&, u32); void cop2Decode(Registers&, u32);
void special(Registers&, Mem&, u32); void special(Registers&, u32);
void regimm(Registers&, u32); void regimm(Registers&, u32);
void Exec(Registers&, Mem&, u32); void Exec(Registers&, Mem&, u32);
void add(Registers&, u32); void add(Registers&, u32);

View File

@@ -93,7 +93,7 @@ u8 Mem::Read8(n64::Registers &regs, u64 vaddr, s64 pc) {
u32 paddr = vaddr; u32 paddr = vaddr;
if (!MapVAddr<tlb>(regs, LOAD, vaddr, paddr)) { if (!MapVAddr<tlb>(regs, LOAD, vaddr, paddr)) {
HandleTLBException(regs, vaddr); HandleTLBException(regs, vaddr);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, pc); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, false);
} }
const auto page = paddr >> 12; const auto page = paddr >> 12;
@@ -144,7 +144,7 @@ u16 Mem::Read16(n64::Registers &regs, u64 vaddr, s64 pc) {
u32 paddr = vaddr; u32 paddr = vaddr;
if (!MapVAddr<tlb>(regs, LOAD, vaddr, paddr)) { if (!MapVAddr<tlb>(regs, LOAD, vaddr, paddr)) {
HandleTLBException(regs, vaddr); HandleTLBException(regs, vaddr);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, pc); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, false);
} }
const auto page = paddr >> 12; const auto page = paddr >> 12;
@@ -190,7 +190,7 @@ u32 Mem::Read32(n64::Registers &regs, u64 vaddr, s64 pc) {
u32 paddr = vaddr; u32 paddr = vaddr;
if (!MapVAddr<tlb>(regs, LOAD, vaddr, paddr)) { if (!MapVAddr<tlb>(regs, LOAD, vaddr, paddr)) {
HandleTLBException(regs, vaddr); HandleTLBException(regs, vaddr);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, pc); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, false);
} }
const auto page = paddr >> 12; const auto page = paddr >> 12;
@@ -230,7 +230,7 @@ u64 Mem::Read64(n64::Registers &regs, u64 vaddr, s64 pc) {
u32 paddr = vaddr; u32 paddr = vaddr;
if (!MapVAddr<tlb>(regs, LOAD, vaddr, paddr)) { if (!MapVAddr<tlb>(regs, LOAD, vaddr, paddr)) {
HandleTLBException(regs, vaddr); HandleTLBException(regs, vaddr);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, pc); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, false);
} }
const auto page = paddr >> 12; const auto page = paddr >> 12;
@@ -284,7 +284,7 @@ void Mem::Write8(Registers& regs, u64 vaddr, u32 val, s64 pc) {
u32 paddr = vaddr; u32 paddr = vaddr;
if (!MapVAddr<tlb>(regs, LOAD, vaddr, paddr)) { if (!MapVAddr<tlb>(regs, LOAD, vaddr, paddr)) {
HandleTLBException(regs, vaddr); HandleTLBException(regs, vaddr);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, pc); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, false);
} }
const auto page = paddr >> 12; const auto page = paddr >> 12;
@@ -343,7 +343,7 @@ void Mem::Write16(Registers& regs, u64 vaddr, u32 val, s64 pc) {
u32 paddr = vaddr; u32 paddr = vaddr;
if (!MapVAddr<tlb>(regs, STORE, vaddr, paddr)) { if (!MapVAddr<tlb>(regs, STORE, vaddr, paddr)) {
HandleTLBException(regs, vaddr); HandleTLBException(regs, vaddr);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, pc); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, false);
} }
const auto page = paddr >> 12; const auto page = paddr >> 12;
@@ -402,7 +402,7 @@ void Mem::Write32(Registers& regs, u64 vaddr, u32 val, s64 pc) {
u32 paddr = vaddr; u32 paddr = vaddr;
if(!MapVAddr<tlb>(regs, STORE, vaddr, paddr)) { if(!MapVAddr<tlb>(regs, STORE, vaddr, paddr)) {
HandleTLBException(regs, vaddr); HandleTLBException(regs, vaddr);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, pc); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, false);
} }
const auto page = paddr >> 12; const auto page = paddr >> 12;
@@ -453,7 +453,7 @@ void Mem::Write64(Registers& regs, u64 vaddr, u64 val, s64 pc) {
u32 paddr = vaddr; u32 paddr = vaddr;
if(!MapVAddr<tlb>(regs, STORE, vaddr, paddr)) { if(!MapVAddr<tlb>(regs, STORE, vaddr, paddr)) {
HandleTLBException(regs, vaddr); HandleTLBException(regs, vaddr);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, pc); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, false);
} }
const auto page = paddr >> 12; const auto page = paddr >> 12;

View File

@@ -1,9 +1,9 @@
#pragma once #pragma once
#include <common.hpp> #include <common.hpp>
#include <MemoryRegions.hpp> #include <backend/MemoryRegions.hpp>
#include <core/MMIO.hpp> #include <backend/core/MMIO.hpp>
#include <vector> #include <vector>
#include <RomHelpers.hpp> #include <backend/RomHelpers.hpp>
#include <log.hpp> #include <log.hpp>
namespace n64 { namespace n64 {

View File

@@ -0,0 +1,4 @@
file(GLOB_RECURSE SOURCES *.cpp)
file(GLOB_RECURSE HEADERS *.hpp)
add_library(dynarec ${SOURCES} ${HEADERS})

View File

@@ -0,0 +1,27 @@
#include <dynarec/cop/cop0decode.hpp>
#include <Registers.hpp>
#include <dynarec/cop/cop0instructions.hpp>
namespace n64::JIT {
void cop0Decode(n64::Registers& regs, u32 instr) {
u8 mask_cop = (instr >> 21) & 0x1F;
u8 mask_cop2 = instr & 0x3F;
switch(mask_cop) {
case 0x00: mfc0(regs, instr); break;
case 0x01: dmfc0(regs, instr); break;
case 0x04: mtc0(regs, instr); break;
case 0x05: dmtc0(regs, instr); break;
case 0x10 ... 0x1F:
switch(mask_cop2) {
case 0x01: tlbr(regs); break;
case 0x02: tlbw(regs.cop0.index & 0x3F, regs); break;
case 0x06: tlbw(regs.cop0.GetRandom(), regs); break;
case 0x08: tlbp(regs); break;
case 0x18: eret(regs); 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);
}
}
}

View File

@@ -0,0 +1,10 @@
#pragma once
#include <common.hpp>
namespace n64 {
struct Registers;
}
namespace n64::JIT {
void cop0Decode(n64::Registers& regs, u32 instr);
}

View File

@@ -0,0 +1,81 @@
#include <dynarec/cop/cop0instructions.hpp>
#include <log.hpp>
#include <Registers.hpp>
namespace n64::JIT {
void mtc0(n64::Registers& regs, u32 instr) {
regs.cop0.SetReg32(RD(instr), regs.gpr[RT(instr)]);
}
void dmtc0(n64::Registers& regs, u32 instr) {
regs.cop0.SetReg64(RD(instr), regs.gpr[RT(instr)]);
}
void mfc0(n64::Registers& regs, u32 instr) {
regs.gpr[RT(instr)] = s32(regs.cop0.GetReg32(RD(instr)));
}
void dmfc0(n64::Registers& regs, u32 instr) {
regs.gpr[RT(instr)] = s64(regs.cop0.GetReg64(RD(instr)));
}
void eret(n64::Registers& regs) {
if(regs.cop0.status.erl) {
regs.SetPC(regs.cop0.ErrorEPC);
regs.cop0.status.erl = false;
} else {
regs.SetPC(regs.cop0.EPC);
regs.cop0.status.exl = false;
}
regs.cop0.llbit = false;
}
void tlbr(n64::Registers& 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(int index_, n64::Registers& 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(n64::Registers& 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;
}
}
}

View File

@@ -0,0 +1,13 @@
#pragma once
#include <Dynarec.hpp>
namespace n64::JIT {
void mtc0(n64::Registers&, u32);
void dmtc0(n64::Registers&, u32);
void mfc0(n64::Registers&, u32);
void dmfc0(n64::Registers&, u32);
void eret(n64::Registers&);
void tlbr(n64::Registers&);
void tlbw(int, n64::Registers&);
void tlbp(n64::Registers&);
}

View File

@@ -0,0 +1,484 @@
#include <dynarec/cop/cop1decode.hpp>
#include <dynarec/instructions.hpp>
#include <Registers.hpp>
namespace n64::JIT {
bool cop1Decode(n64::Registers& regs, Dynarec& cpu, u32 instr) {
Xbyak::CodeGenerator& code = cpu.code;
code.push(code.rbp);
code.mov(code.rbp, (u64)&regs.cop0.status.raw);
code.mov(code.eax, code.dword[code.rbp]);
code.pop(code.rbp);
code.and_(code.eax, 0x20000000);
code.cmp(code.eax, 1);
code.je("NoException1");
code.mov(code.rdi, (u64)&regs);
code.mov(code.rsi, (u64)ExceptionCode::CoprocessorUnusable);
code.mov(code.rdx, 1);
code.mov(code.rcx, 1);
code.mov(code.rax, (u64) FireException);
code.call(code.rax);
code.xor_(code.rax, code.rax);
code.ret();
code.L("NoException1");
u8 mask_sub = (instr >> 21) & 0x1F;
u8 mask_fun = instr & 0x3F;
u8 mask_branch = (instr >> 16) & 0x1F;
code.mov(code.rdi, (u64)&regs);
code.mov(code.esi, instr);
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!\n");
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!\n");
case 0x08:
switch(mask_branch) {
case 0:
code.mov(code.rdi, !regs.cop1.fcr31.compare);
code.mov(code.rax, (u64)b);
code.call(code.rax);
return true;
case 1:
code.mov(code.rdi, regs.cop1.fcr31.compare);
code.mov(code.rax, (u64)b);
code.call(code.rax);
return true;
case 2:
code.mov(code.rdi, !regs.cop1.fcr31.compare);
code.mov(code.rax, (u64)bl);
code.call(code.rax);
return true;
case 3:
code.mov(code.rdi, 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!\n");
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!\n");
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!\n");
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!\n");
case 0x25:
util::panic("[RECOMPILER] FPU reserved instruction exception!\n");
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;
}
}

View File

@@ -0,0 +1,6 @@
#pragma once
#include <dynarec/cop/cop1instructions.hpp>
namespace n64::JIT {
bool cop1Decode(n64::Registers& regs, Dynarec& cpu, u32 instr);
}

View File

@@ -0,0 +1,590 @@
#include <dynarec/cop/cop1instructions.hpp>
#include <cfenv>
#include <Cop1.hpp>
#include <Registers.hpp>
namespace n64::JIT {
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)
#ifdef _WIN32
#define isnanf isnan
#define checknanregsf(fs, ft) \
if(isnanf(fs) || isnanf(ft)) { \
regs.cop1.fcr31.flag_invalid_operation = true; \
regs.cop1.fcr31.cause_invalid_operation = true; \
FireException(regs, ExceptionCode::FloatingPointError, 1, true); \
return; \
}
#define checknanregsd(fs, ft) \
if(isnan(fs) || isnan(ft)) { \
regs.cop1.fcr31.flag_invalid_operation = true; \
regs.cop1.fcr31.cause_invalid_operation = true; \
FireException(regs, ExceptionCode::FloatingPointError, 1, true); \
return; \
}
#else
#define checknanregsf(fs, ft) \
if(isnanf(fs) || isnanf(ft)) { \
regs.cop1.fcr31.flag_invalid_operation = true; \
regs.cop1.fcr31.cause_invalid_operation = true; \
FireException(regs, ExceptionCode::FloatingPointError, 1, true); \
return; \
}
#define checknanregsd(fs, ft) \
if(isnan(fs) || isnan(ft)) { \
regs.cop1.fcr31.flag_invalid_operation = true; \
regs.cop1.fcr31.cause_invalid_operation = true; \
FireException(regs, ExceptionCode::FloatingPointError, 1, true); \
return; \
}
#endif
void absd(n64::Registers& regs, u32 instr) {
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
regs.cop1.SetCop1Reg<double>(regs.cop0, FD(instr), fabs(fs));
}
void abss(n64::Registers& regs, u32 instr) {
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
regs.cop1.SetCop1Reg<float>(regs.cop0, FD(instr), fabsf(fs));
}
void absw(n64::Registers& regs, u32 instr) {
s32 fs = regs.cop1.GetReg<s32>(regs.cop0, FS(instr));
regs.cop1.SetReg<u32>(regs.cop0, FD(instr), abs(fs));
}
void absl(n64::Registers& regs, u32 instr) {
s64 fs = regs.cop1.GetReg<s64>(regs.cop0, FS(instr));
regs.cop1.SetReg(regs.cop0, FD(instr), labs(fs));
}
void adds(n64::Registers& regs, u32 instr) {
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
float ft = regs.cop1.GetCop1Reg<float>(regs.cop0, FT(instr));
checknanregsf(fs, ft)
float result = fs + ft;
regs.cop1.SetCop1Reg<float>(regs.cop0, FD(instr), result);
}
void addd(n64::Registers& regs, u32 instr) {
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
double ft = regs.cop1.GetCop1Reg<double>(regs.cop0, FT(instr));
checknanregsf(fs, ft)
double result = fs + ft;
regs.cop1.SetCop1Reg<double>(regs.cop0, FD(instr), result);
}
void ceills(n64::Registers& regs, u32 instr) {
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
s64 result = ceilf(fs);
regs.cop1.SetReg<u64>(regs.cop0, FD(instr), result);
}
void ceilws(n64::Registers& regs, u32 instr) {
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
s32 result = ceilf(fs);
regs.cop1.SetReg<u32>(regs.cop0, FD(instr), result);
}
void ceilld(n64::Registers& regs, u32 instr) {
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
s64 result = ceil(fs);
regs.cop1.SetReg<u64>(regs.cop0, FD(instr), result);
}
void ceilwd(n64::Registers& regs, u32 instr) {
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
s32 result = ceil(fs);
regs.cop1.SetReg<u32>(regs.cop0, FD(instr), result);
}
void cfc1(n64::Registers& regs, u32 instr) {
u8 fd = FD(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(n64::Registers& regs, u32 instr) {
u8 fs = FS(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(n64::Registers& regs, u32 instr) {
regs.cop1.SetCop1Reg<double>(
regs.cop0,
FD(instr),
regs.cop1.GetCop1Reg<float>(
regs.cop0,
FS(instr)
)
);
}
void cvtsd(n64::Registers& regs, u32 instr) {
regs.cop1.SetCop1Reg<float>(
regs.cop0,
FD(instr),
regs.cop1.GetCop1Reg<double>(
regs.cop0,
FS(instr)
)
);
}
void cvtwd(n64::Registers& regs, u32 instr) {
regs.cop1.SetReg<u32>(
regs.cop0,
FD(instr),
regs.cop1.GetCop1Reg<double>(
regs.cop0,
FS(instr)
)
);
}
void cvtws(n64::Registers& regs, u32 instr) {
regs.cop1.SetReg<u32>(
regs.cop0,
FD(instr),
regs.cop1.GetCop1Reg<float>(
regs.cop0,
FS(instr)
)
);
}
void cvtls(n64::Registers& regs, u32 instr) {
regs.cop1.SetReg<u64>(
regs.cop0,
FD(instr),
regs.cop1.GetCop1Reg<float>(
regs.cop0,
FS(instr)
)
);
}
void cvtsl(n64::Registers& regs, u32 instr) {
regs.cop1.SetCop1Reg<float>(
regs.cop0,
FD(instr),
(s64)regs.cop1.GetReg<u64>(
regs.cop0,
FS(instr)
)
);
}
void cvtdw(n64::Registers& regs, u32 instr) {
regs.cop1.SetCop1Reg<double>(
regs.cop0,
FD(instr),
(s32)regs.cop1.GetReg<u32>(
regs.cop0,
FS(instr)
)
);
}
void cvtsw(n64::Registers& regs, u32 instr) {
regs.cop1.SetCop1Reg<float>(
regs.cop0,
FD(instr),
(s32)regs.cop1.GetReg<u32>(
regs.cop0,
FS(instr)
)
);
}
void cvtdl(n64::Registers& regs, u32 instr) {
regs.cop1.SetCop1Reg<double>(
regs.cop0,
FD(instr),
(s64)regs.cop1.GetReg<u64>(
regs.cop0,
FS(instr)
)
);
}
void cvtld(n64::Registers& regs, u32 instr) {
regs.cop1.SetReg<u64>(
regs.cop0,
FD(instr),
regs.cop1.GetCop1Reg<double>(
regs.cop0,
FS(instr)
)
);
}
template <typename T>
inline bool CalculateCondition(n64::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(n64::Registers& regs, u32 instr, CompConds cond) {
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>(n64::Registers& regs, u32 instr, CompConds cond);
template void ccond<double>(n64::Registers& regs, u32 instr, CompConds cond);
void divs(Registers &regs, u32 instr) {
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(Registers &regs, u32 instr) {
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(Registers &regs, u32 instr) {
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(n64::Registers& regs, u32 instr) {
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(Registers &regs, u32 instr) {
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(Registers &regs, u32 instr) {
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(Registers &regs, u32 instr) {
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(Registers &regs, u32 instr) {
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(Registers &regs, u32 instr) {
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(Registers &regs, u32 instr) {
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(n64::Registers& regs, u32 instr) {
regs.cop1.SetCop1Reg<float>(
regs.cop0,
FD(instr),
regs.cop1.GetCop1Reg<float>(
regs.cop0,
FS(instr)
)
);
}
void movd(n64::Registers& regs, u32 instr) {
regs.cop1.SetCop1Reg<double>(
regs.cop0,
FD(instr),
regs.cop1.GetCop1Reg<double>(
regs.cop0,
FS(instr)
)
);
}
void movw(n64::Registers& regs, u32 instr) {
regs.cop1.SetReg<u32>(
regs.cop0,
FD(instr),
regs.cop1.GetReg<u32>(
regs.cop0,
FS(instr)
)
);
}
void movl(n64::Registers& regs, u32 instr) {
regs.cop1.SetReg<u64>(
regs.cop0,
FD(instr),
regs.cop1.GetReg<u64>(
regs.cop0,
FS(instr)
)
);
}
void negs(Registers &regs, u32 instr) {
regs.cop1.SetCop1Reg<float>(
regs.cop0,
FD(instr),
-regs.cop1.GetCop1Reg<float>(
regs.cop0,
FS(instr)
)
);
}
void negd(Registers &regs, u32 instr) {
regs.cop1.SetCop1Reg<double>(
regs.cop0,
FD(instr),
-regs.cop1.GetCop1Reg<double>(
regs.cop0,
FS(instr)
)
);
}
void sqrts(Registers &regs, u32 instr) {
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
regs.cop1.SetCop1Reg<float>(regs.cop0, FD(instr), sqrtf(fs));
}
void sqrtd(Registers &regs, u32 instr) {
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
regs.cop1.SetCop1Reg<double>(regs.cop0, FD(instr), sqrt(fs));
}
void roundls(n64::Registers& regs, u32 instr) {
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
PUSHROUNDINGMODE;
regs.cop1.SetReg<u64>(regs.cop0, FD(instr), (s32)nearbyintf(fs));
POPROUNDINGMODE;
}
void roundld(n64::Registers& regs, u32 instr) {
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
PUSHROUNDINGMODE;
regs.cop1.SetReg<u64>(regs.cop0, FD(instr), (s64)nearbyint(fs));
POPROUNDINGMODE;
}
void roundws(n64::Registers& regs, u32 instr) {
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
PUSHROUNDINGMODE;
regs.cop1.SetReg<u32>(regs.cop0, FD(instr), (s32)nearbyintf(fs));
POPROUNDINGMODE;
}
void roundwd(n64::Registers& regs, u32 instr) {
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
PUSHROUNDINGMODE;
regs.cop1.SetReg<u32>(regs.cop0, FD(instr), (s32)nearbyint(fs));
POPROUNDINGMODE;
}
void floorls(n64::Registers& regs, u32 instr) {
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
regs.cop1.SetReg<u64>(regs.cop0, FD(instr), (s64)floorf(fs));
}
void floorld(n64::Registers& regs, u32 instr) {
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
regs.cop1.SetReg<u64>(regs.cop0, FD(instr), (s64)floor(fs));
}
void floorws(n64::Registers& regs, u32 instr) {
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
regs.cop1.SetReg<u32>(regs.cop0, FD(instr), (s64)floorf(fs));
}
void floorwd(n64::Registers& regs, u32 instr) {
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
regs.cop1.SetReg<u32>(regs.cop0, FD(instr), (s64)floor(fs));
}
void lwc1(n64::Registers& regs, Mem& mem, u32 instr) {
if(!regs.cop0.status.cu1) {
FireException(regs, ExceptionCode::CoprocessorUnusable, 1, true);
return;
}
u64 addr = (s64)(s16)instr + regs.gpr[BASE(instr)];
if(addr & 3) {
FireException(regs, ExceptionCode::AddressErrorLoad, 0, true);
}
u32 physical;
if(!MapVAddr(regs, LOAD, addr, physical)) {
HandleTLBException(regs, addr);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
} else {
u32 data = mem.Read32<false>(regs, physical, regs.oldPC);
regs.cop1.SetReg<u32>(regs.cop0, FT(instr), data);
}
}
void swc1(n64::Registers& regs, Mem& mem, u32 instr) {
if(!regs.cop0.status.cu1) {
FireException(regs, ExceptionCode::CoprocessorUnusable, 1, true);
return;
}
u64 addr = (s64)(s16)instr + regs.gpr[BASE(instr)];
if(addr & 3) {
FireException(regs, ExceptionCode::AddressErrorStore, 0, true);
}
u32 physical;
if(!MapVAddr(regs, STORE, addr, physical)) {
HandleTLBException(regs, addr);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC);
} else {
mem.Write32<false>(regs, physical, regs.cop1.GetReg<u32>(regs.cop0, FT(instr)), regs.oldPC);
}
}
void ldc1(n64::Registers& regs, Mem& mem, u32 instr) {
if(!regs.cop0.status.cu1) {
FireException(regs, ExceptionCode::CoprocessorUnusable, 1, regs.oldPC);
return;
}
u64 addr = (s64)(s16)instr + regs.gpr[BASE(instr)];
if(addr & 7) {
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
}
u32 physical;
if(!MapVAddr(regs, LOAD, addr, physical)) {
HandleTLBException(regs, addr);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC);
} else {
u64 data = mem.Read64<false>(regs, physical, regs.oldPC);
regs.cop1.SetReg<u64>(regs.cop0, FT(instr), data);
}
}
void sdc1(n64::Registers& regs, Mem& mem, u32 instr) {
if(!regs.cop0.status.cu1) {
FireException(regs, ExceptionCode::CoprocessorUnusable, 1, regs.oldPC);
return;
}
u64 addr = (s64)(s16)instr + regs.gpr[BASE(instr)];
if(addr & 7) {
FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC);
}
u32 physical;
if(!MapVAddr(regs, STORE, addr, physical)) {
HandleTLBException(regs, addr);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC);
} else {
mem.Write64<false>(regs, physical, regs.cop1.GetReg<u64>(regs.cop0, FT(instr)), regs.oldPC);
}
}
void truncws(n64::Registers& regs, u32 instr) {
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
s32 result = (s32)truncf(fs);
regs.cop1.SetReg<u32>(regs.cop0, FD(instr), result);
}
void truncwd(n64::Registers& regs, u32 instr) {
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
s32 result = (s32)trunc(fs);
regs.cop1.SetReg<u32>(regs.cop0, FD(instr), result);
}
void truncls(n64::Registers& regs, u32 instr) {
float fs = regs.cop1.GetCop1Reg<float>(regs.cop0, FS(instr));
s64 result = (s64)truncf(fs);
regs.cop1.SetReg<u64>(regs.cop0, FD(instr), result);
}
void truncld(n64::Registers& regs, u32 instr) {
double fs = regs.cop1.GetCop1Reg<double>(regs.cop0, FS(instr));
s64 result = (s64)trunc(fs);
regs.cop1.SetReg<u64>(regs.cop0, FD(instr), result);
}
void mfc1(n64::Registers& regs, u32 instr) {
regs.gpr[RT(instr)] = (s32)regs.cop1.GetReg<u32>(regs.cop0, FS(instr));
}
void dmfc1(n64::Registers& regs, u32 instr) {
regs.gpr[RT(instr)] = (s64)regs.cop1.GetReg<u64>(regs.cop0, FS(instr));
}
void mtc1(n64::Registers& regs, u32 instr) {
regs.cop1.SetReg<u32>(regs.cop0, FS(instr), regs.gpr[RT(instr)]);
}
void dmtc1(n64::Registers& regs, u32 instr) {
regs.cop1.SetReg<u64>(regs.cop0, FS(instr), regs.gpr[RT(instr)]);
}
}

View File

@@ -0,0 +1,68 @@
#pragma once
#include <Dynarec.hpp>
#include <Cop1.hpp>
namespace n64::JIT {
void absd(n64::Registers&, u32 instr);
void abss(n64::Registers&, u32 instr);
void absw(n64::Registers&, u32 instr);
void absl(n64::Registers&, u32 instr);
void adds(n64::Registers&, u32 instr);
void addd(n64::Registers&, u32 instr);
void subs(n64::Registers&, u32 instr);
void subd(n64::Registers&, u32 instr);
void subw(n64::Registers&, u32 instr);
void subl(n64::Registers&, u32 instr);
void ceills(n64::Registers&, u32 instr);
void ceilws(n64::Registers&, u32 instr);
void ceilld(n64::Registers&, u32 instr);
void ceilwd(n64::Registers&, u32 instr);
void cfc1(n64::Registers&, u32 instr);
void ctc1(n64::Registers&, u32 instr);
void roundls(n64::Registers&, u32 instr);
void roundld(n64::Registers&, u32 instr);
void roundws(n64::Registers&, u32 instr);
void roundwd(n64::Registers&, u32 instr);
void floorls(n64::Registers&, u32 instr);
void floorld(n64::Registers&, u32 instr);
void floorws(n64::Registers&, u32 instr);
void floorwd(n64::Registers&, u32 instr);
void cvtls(n64::Registers&, u32 instr);
void cvtws(n64::Registers&, u32 instr);
void cvtds(n64::Registers&, u32 instr);
void cvtsw(n64::Registers&, u32 instr);
void cvtdw(n64::Registers&, u32 instr);
void cvtsd(n64::Registers&, u32 instr);
void cvtwd(n64::Registers&, u32 instr);
void cvtld(n64::Registers&, u32 instr);
void cvtdl(n64::Registers&, u32 instr);
void cvtsl(n64::Registers&, u32 instr);
template <typename T>
void ccond(n64::Registers&, u32 instr, CompConds);
void divs(n64::Registers&, u32 instr);
void divd(n64::Registers&, u32 instr);
void muls(n64::Registers&, u32 instr);
void muld(n64::Registers&, u32 instr);
void mulw(n64::Registers&, u32 instr);
void mull(n64::Registers&, u32 instr);
void movs(n64::Registers&, u32 instr);
void movd(n64::Registers&, u32 instr);
void movw(n64::Registers&, u32 instr);
void movl(n64::Registers&, u32 instr);
void negs(n64::Registers&, u32 instr);
void negd(n64::Registers&, u32 instr);
void sqrts(n64::Registers&, u32 instr);
void sqrtd(n64::Registers&, u32 instr);
void lwc1(n64::Registers&, Mem&, u32 instr);
void swc1(n64::Registers&, Mem&, u32 instr);
void ldc1(n64::Registers&, Mem&, u32 instr);
void mfc1(n64::Registers&, u32 instr);
void dmfc1(n64::Registers&, u32 instr);
void mtc1(n64::Registers&, u32 instr);
void dmtc1(n64::Registers&, u32 instr);
void sdc1(n64::Registers&, Mem&, u32 instr);
void truncws(n64::Registers&, u32 instr);
void truncwd(n64::Registers&, u32 instr);
void truncls(n64::Registers&, u32 instr);
void truncld(n64::Registers&, u32 instr);
}

View File

@@ -0,0 +1,254 @@
#include <dynarec/instructions.hpp>
#include <dynarec/cop/cop1decode.hpp>
#include <dynarec/cop/cop0decode.hpp>
#include <Registers.hpp>
namespace n64::JIT {
void Dynarec::cop2Decode(n64::Registers& regs, u32 instr) {
code.push(code.rbp);
code.mov(code.rbp, (u64)&regs.cop0.status.raw);
code.mov(code.eax, code.dword[code.rbp]);
code.pop(code.rbp);
code.and_(code.eax, 0x40000000);
code.cmp(code.eax, 1);
code.je("NoException2");
code.mov(code.rdi, (u64)&regs);
code.mov(code.rsi, (u64)ExceptionCode::CoprocessorUnusable);
code.mov(code.rdx, 2);
code.mov(code.rcx, 1);
code.mov(code.rax, (u64) FireException);
code.call(code.rax);
code.xor_(code.eax, code.eax);
code.ret();
code.L("NoException2");
code.mov(code.rdi, (u64)this);
code.mov(code.rsi, (u64)&regs);
code.mov(code.rdx, (u64)instr);
switch(RS(instr)) {
case 0x00:
code.mov(code.rax, (u64)mfc2);
code.call(code.rax);
break;
case 0x01:
code.mov(code.rax, (u64)dmfc2);
code.call(code.rax);
break;
case 0x02: case 0x06: code.nop(); break;
case 0x04:
code.mov(code.rax, (u64)mtc2);
code.call(code.rax);
break;
case 0x05:
code.mov(code.rax, (u64)dmtc2);
code.call(code.rax);
break;
default:
util::panic("[RECOMPILER] Unhandled reserved instruction exception {:016X}\n", (u64)regs.pc);
}
}
bool Dynarec::special(n64::Registers& regs, u32 instr) {
u8 mask = (instr & 0x3F);
bool res = false;
// 00rr_rccc
switch (mask) { // TODO: named constants for clearer code
case 0:
if (instr != 0) {
sll(regs, instr);
}
break;
case 0x02: srl(regs, instr); break;
case 0x03: sra(regs, instr); break;
case 0x04: sllv(regs, instr); break;
case 0x06: srlv(regs, instr); break;
case 0x07: srav(regs, instr); break;
case 0x08:
jr(regs, instr);
res = true;
break;
case 0x09:
jalr(regs, instr);
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: code.nop(); break; // SYNC
case 0x10: mfhi(regs, instr); break;
case 0x11: mthi(regs, instr); break;
case 0x12: mflo(regs, instr); break;
case 0x13: mtlo(regs, instr); break;
case 0x14: dsllv(regs, instr); break;
case 0x16: dsrlv(regs, instr); break;
case 0x17: dsrav(regs, instr); break;
case 0x18: mult(regs, instr); break;
case 0x19: multu(regs, instr); break;
case 0x1A: div(regs, instr); break;
case 0x1B: divu(regs, instr); break;
case 0x1C: dmult(regs, instr); break;
case 0x1D: dmultu(regs, instr); break;
case 0x1E: ddiv(regs, instr); break;
case 0x1F: ddivu(regs, instr); break;
case 0x20: add(regs, instr); break;
case 0x21: addu(regs, instr); break;
case 0x22: sub(regs, instr); break;
case 0x23: subu(regs, instr); break;
case 0x24: and_(regs, instr); break;
case 0x25: or_(regs, instr); break;
case 0x26: xor_(regs, instr); break;
case 0x27: nor(regs, instr); break;
case 0x2A: slt(regs, instr); break;
case 0x2B: sltu(regs, instr); break;
case 0x2C: dadd(regs, instr); break;
case 0x2D: daddu(regs, instr); break;
case 0x2E: dsub(regs, instr); break;
case 0x2F: dsubu(regs, instr); break;
case 0x30:
trap(regs, regs.gpr[RS(instr)] >= regs.gpr[RT(instr)]);
res = true;
break;
case 0x31:
trap(regs, (u64)regs.gpr[RS(instr)] >= (u64)regs.gpr[RT(instr)]);
res = true;
break;
case 0x32:
trap(regs, regs.gpr[RS(instr)] < regs.gpr[RT(instr)]);
res = true;
break;
case 0x33:
trap(regs, (u64)regs.gpr[RS(instr)] < (u64)regs.gpr[RT(instr)]);
res = true;
break;
case 0x34:
trap(regs, regs.gpr[RS(instr)] == regs.gpr[RT(instr)]);
res = true;
break;
case 0x36:
trap(regs, regs.gpr[RS(instr)] != regs.gpr[RT(instr)]);
res = true;
break;
case 0x38: dsll(regs, instr); break;
case 0x3A: dsrl(regs, instr); break;
case 0x3B: dsra(regs, instr); break;
case 0x3C: dsll32(regs, instr); break;
case 0x3E: dsrl32(regs, instr); break;
case 0x3F: dsra32(regs, instr); break;
default:
util::panic("Unimplemented special {} {} ({:08X}) (pc: {:016X})\n", (mask >> 3) & 7, mask & 7, instr, (u64)regs.oldPC);
}
return res;
}
bool Dynarec::regimm(n64::Registers& regs, u32 instr) {
u8 mask = ((instr >> 16) & 0x1F);
// 000r_rccc
switch (mask) { // TODO: named constants for clearer code
case 0x00: b(regs, instr, regs.gpr[RS(instr)] < 0); break;
case 0x01: b(regs, instr, regs.gpr[RS(instr)] >= 0); break;
case 0x02: bl(regs, instr, regs.gpr[RS(instr)] < 0); break;
case 0x03: bl(regs, instr, regs.gpr[RS(instr)] >= 0); break;
case 0x08: trap(regs, regs.gpr[RS(instr)] >= s64(s16(instr))); break;
case 0x09: trap(regs, u64(regs.gpr[RS(instr)]) >= u64(s64(s16(instr)))); break;
case 0x0A: trap(regs, regs.gpr[RS(instr)] < s64(s16(instr))); break;
case 0x0B: trap(regs, u64(regs.gpr[RS(instr)]) < u64(s64(s16(instr)))); break;
case 0x0C: trap(regs, regs.gpr[RS(instr)] == s64(s16(instr))); break;
case 0x0E: trap(regs, regs.gpr[RS(instr)] != s64(s16(instr))); break;
case 0x10: blink(regs, instr, regs.gpr[RS(instr)] < 0); break;
case 0x11: blink(regs, instr, regs.gpr[RS(instr)] >= 0); break;
case 0x12: bllink(regs, instr, regs.gpr[RS(instr)] < 0); break;
case 0x13: bllink(regs, instr, regs.gpr[RS(instr)] >= 0); break;
default:
util::panic("Unimplemented regimm {} {} ({:08X}) (pc: {:016X})\n", (mask >> 3) & 3, mask & 7, instr, (u64)regs.oldPC);
}
return true;
}
bool Dynarec::Exec(n64::Registers& regs, 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(regs, instr); break;
case 0x01: res = regimm(regs, instr); break;
case 0x02:
j(regs, instr);
res = true;
break;
case 0x03:
jal(regs, instr);
res = true;
break;
case 0x04:
b(regs, instr, regs.gpr[RS(instr)] == regs.gpr[RT(instr)]);
res = true;
break;
case 0x05:
b(regs, instr, regs.gpr[RS(instr)] != regs.gpr[RT(instr)]);
res = true;
break;
case 0x06:
b(regs, instr, regs.gpr[RS(instr)] <= 0);
res = true;
break;
case 0x07:
b(regs, instr, regs.gpr[RS(instr)] > 0);
res = true;
break;
case 0x08: addi(regs, instr); break;
case 0x09: addiu(regs, instr); break;
case 0x0A: slti(regs, instr); break;
case 0x0B: sltiu(regs, instr); break;
case 0x0C: andi(regs, instr); break;
case 0x0D: ori(regs, instr); break;
case 0x0E: xori(regs, instr); break;
case 0x0F: lui(regs, instr); break;
case 0x10: cop0Decode(regs, instr); break;
case 0x11: res = cop1Decode(regs, *this, instr); break;
case 0x12: cop2Decode(regs, instr); break;
case 0x14: bl(regs, instr, regs.gpr[RS(instr)] == regs.gpr[RT(instr)]); break;
case 0x15: bl(regs, instr, regs.gpr[RS(instr)] != regs.gpr[RT(instr)]); break;
case 0x16: bl(regs, instr, regs.gpr[RS(instr)] <= 0); break;
case 0x17: bl(regs, instr, regs.gpr[RS(instr)] > 0); break;
case 0x18: daddi(regs, instr); break;
case 0x19: daddiu(regs, instr); break;
case 0x1A: ldl(regs, mem, instr); break;
case 0x1B: ldr(regs, mem, instr); break;
case 0x1F: FireException(regs, ExceptionCode::ReservedInstruction, 0, true); break;
case 0x20: lb(regs, mem, instr); break;
case 0x21: lh(regs, mem, instr); break;
case 0x22: lwl(regs, mem, instr); break;
case 0x23: lw(regs, mem, instr); break;
case 0x24: lbu(regs, mem, instr); break;
case 0x25: lhu(regs, mem, instr); break;
case 0x26: lwr(regs, mem, instr); break;
case 0x27: lwu(regs, mem, instr); break;
case 0x28: sb(regs, mem, instr); break;
case 0x29: sh(regs, mem, instr); break;
case 0x2A: swl(regs, mem, instr); break;
case 0x2B: sw(regs, mem, instr); break;
case 0x2C: sdl(regs, mem, instr); break;
case 0x2D: sdr(regs, mem, instr); break;
case 0x2E: swr(regs, mem, instr); break;
case 0x2F: break; // CACHE
case 0x30: ll(regs, mem, instr); break;
case 0x31: lwc1(regs, mem, instr); break;
case 0x34: lld(regs, mem, instr); break;
case 0x35: ldc1(regs, mem, instr); break;
case 0x37: ld(regs, mem, instr); break;
case 0x38: sc(regs, mem, instr); break;
case 0x39: swc1(regs, mem, instr); break;
case 0x3C: scd(regs, mem, instr); break;
case 0x3D: sdc1(regs, mem, instr); break;
case 0x3F: sd(regs, mem, instr); break;
default:
util::panic("Unimplemented instruction {:02X} ({:08X}) (pc: {:016X})\n", mask, instr, (u64)regs.oldPC);
}
return res;
}
}

View File

@@ -1,82 +1,83 @@
#include <core/Dynarec.hpp> #include <dynarec/instructions.hpp>
#include <Registers.hpp>
#define se_imm(x) ((s16)((x) & 0xFFFF)) #define se_imm(x) ((s16)((x) & 0xFFFF))
#define check_address_error(mask, addr) (((!regs.cop0.is_64bit_addressing) && (s32)(addr) != (addr)) || (((addr) & (mask)) != 0)) #define check_address_error(mask, addr) (((!regs.cop0.is_64bit_addressing) && (s32)(addr) != (addr)) || (((addr) & (mask)) != 0))
#define check_signed_overflow(op1, op2, res) (((~((op1) ^ (op2)) & ((op1) ^ (res))) >> ((sizeof(res) * 8) - 1)) & 1) #define check_signed_overflow(op1, op2, res) (((~((op1) ^ (op2)) & ((op1) ^ (res))) >> ((sizeof(res) * 8) - 1)) & 1)
#define check_signed_underflow(op1, op2, res) (((((op1) ^ (op2)) & ((op1) ^ (res))) >> ((sizeof(res) * 8) - 1)) & 1) #define check_signed_underflow(op1, op2, res) (((((op1) ^ (op2)) & ((op1) ^ (res))) >> ((sizeof(res) * 8) - 1)) & 1)
namespace n64 { namespace n64::JIT {
void Dynarec::add(Registers& regs, u32 instr) { void add(Registers& regs, u32 instr) {
u32 rs = (s32)regs.gpr[RS(instr)]; u32 rs = (s32)regs.gpr[RS(instr)];
u32 rt = (s32)regs.gpr[RT(instr)]; u32 rt = (s32)regs.gpr[RT(instr)];
u32 result = rs + rt; u32 result = rs + rt;
if(check_signed_overflow(rs, rt, result)) { if(check_signed_overflow(rs, rt, result)) {
FireException(regs, ExceptionCode::Overflow, 0, regs.oldPC); FireException(regs, ExceptionCode::Overflow, 0, true);
} else { } else {
regs.gpr[RD(instr)] = s32(result); regs.gpr[RD(instr)] = s32(result);
} }
} }
void Dynarec::addu(Registers& regs, u32 instr) { void addu(Registers& regs, u32 instr) {
s32 rs = (s32)regs.gpr[RS(instr)]; s32 rs = (s32)regs.gpr[RS(instr)];
s32 rt = (s32)regs.gpr[RT(instr)]; s32 rt = (s32)regs.gpr[RT(instr)];
s32 result = rs + rt; s32 result = rs + rt;
regs.gpr[RD(instr)] = result; regs.gpr[RD(instr)] = result;
} }
void Dynarec::addi(Registers& regs, u32 instr) { void addi(Registers& regs, u32 instr) {
u32 rs = regs.gpr[RS(instr)]; u32 rs = regs.gpr[RS(instr)];
u32 imm = s32(s16(instr)); u32 imm = s32(s16(instr));
u32 result = rs + imm; u32 result = rs + imm;
if(check_signed_overflow(rs, imm, result)) { if(check_signed_overflow(rs, imm, result)) {
FireException(regs, ExceptionCode::Overflow, 0, regs.oldPC); FireException(regs, ExceptionCode::Overflow, 0, true);
} else { } else {
regs.gpr[RT(instr)] = s32(result); regs.gpr[RT(instr)] = s32(result);
} }
} }
void Dynarec::addiu(Registers& regs, u32 instr) { void addiu(Registers& regs, u32 instr) {
s32 rs = (s32)regs.gpr[RS(instr)]; s32 rs = (s32)regs.gpr[RS(instr)];
s16 imm = (s16)(instr); s16 imm = (s16)(instr);
s32 result = rs + imm; s32 result = rs + imm;
regs.gpr[RT(instr)] = result; regs.gpr[RT(instr)] = result;
} }
void Dynarec::dadd(Registers& regs, u32 instr) { void dadd(Registers& regs, u32 instr) {
u64 rs = regs.gpr[RS(instr)]; u64 rs = regs.gpr[RS(instr)];
u64 rt = regs.gpr[RT(instr)]; u64 rt = regs.gpr[RT(instr)];
u64 result = rt + rs; u64 result = rt + rs;
if(check_signed_overflow(rs, rt, result)) { if(check_signed_overflow(rs, rt, result)) {
FireException(regs, ExceptionCode::Overflow, 0, regs.oldPC); FireException(regs, ExceptionCode::Overflow, 0, true);
} else { } else {
regs.gpr[RD(instr)] = result; regs.gpr[RD(instr)] = result;
} }
} }
void Dynarec::daddu(Registers& regs, u32 instr) { void daddu(Registers& regs, u32 instr) {
s64 rs = regs.gpr[RS(instr)]; s64 rs = regs.gpr[RS(instr)];
s64 rt = regs.gpr[RT(instr)]; s64 rt = regs.gpr[RT(instr)];
regs.gpr[RD(instr)] = rs + rt; regs.gpr[RD(instr)] = rs + rt;
} }
void Dynarec::daddi(Registers& regs, u32 instr) { void daddi(Registers& regs, u32 instr) {
u64 imm = s64(s16(instr)); u64 imm = s64(s16(instr));
u64 rs = regs.gpr[RS(instr)]; u64 rs = regs.gpr[RS(instr)];
u64 result = imm + rs; u64 result = imm + rs;
if(check_signed_overflow(rs, imm, result)) { if(check_signed_overflow(rs, imm, result)) {
FireException(regs, ExceptionCode::Overflow, 0, regs.oldPC); FireException(regs, ExceptionCode::Overflow, 0, true);
} else { } else {
regs.gpr[RT(instr)] = result; regs.gpr[RT(instr)] = result;
} }
} }
void Dynarec::daddiu(Registers& regs, u32 instr) { void daddiu(Registers& regs, u32 instr) {
s16 imm = (s16)(instr); s16 imm = (s16)(instr);
s64 rs = regs.gpr[RS(instr)]; s64 rs = regs.gpr[RS(instr)];
regs.gpr[RT(instr)] = rs + imm; regs.gpr[RT(instr)] = rs + imm;
} }
void Dynarec::div(Registers& regs, u32 instr) { void div(Registers& regs, u32 instr) {
s64 dividend = (s32)regs.gpr[RS(instr)]; s64 dividend = (s32)regs.gpr[RS(instr)];
s64 divisor = (s32)regs.gpr[RT(instr)]; s64 divisor = (s32)regs.gpr[RT(instr)];
@@ -95,7 +96,7 @@ void Dynarec::div(Registers& regs, u32 instr) {
} }
} }
void Dynarec::divu(Registers& regs, u32 instr) { void divu(Registers& regs, u32 instr) {
u32 dividend = regs.gpr[RS(instr)]; u32 dividend = regs.gpr[RS(instr)];
u32 divisor = regs.gpr[RT(instr)]; u32 divisor = regs.gpr[RT(instr)];
if(divisor == 0) { if(divisor == 0) {
@@ -109,7 +110,7 @@ void Dynarec::divu(Registers& regs, u32 instr) {
} }
} }
void Dynarec::ddiv(Registers& regs, u32 instr) { void ddiv(Registers& regs, u32 instr) {
s64 dividend = regs.gpr[RS(instr)]; s64 dividend = regs.gpr[RS(instr)];
s64 divisor = regs.gpr[RT(instr)]; s64 divisor = regs.gpr[RT(instr)];
if (dividend == 0x8000000000000000 && divisor == 0xFFFFFFFFFFFFFFFF) { if (dividend == 0x8000000000000000 && divisor == 0xFFFFFFFFFFFFFFFF) {
@@ -130,7 +131,7 @@ void Dynarec::ddiv(Registers& regs, u32 instr) {
} }
} }
void Dynarec::ddivu(Registers& regs, u32 instr) { void ddivu(Registers& regs, u32 instr) {
u64 dividend = regs.gpr[RS(instr)]; u64 dividend = regs.gpr[RS(instr)];
u64 divisor = regs.gpr[RT(instr)]; u64 divisor = regs.gpr[RT(instr)];
if(divisor == 0) { if(divisor == 0) {
@@ -144,14 +145,14 @@ void Dynarec::ddivu(Registers& regs, u32 instr) {
} }
} }
void Dynarec::branch(Registers& regs, bool cond, s64 address) { void branch(Registers& regs, bool cond, s64 address) {
regs.delaySlot = true; regs.delaySlot = true;
if (cond) { if (cond) {
regs.nextPC = address; regs.nextPC = address;
} }
} }
void Dynarec::branch_likely(Registers& regs, bool cond, s64 address) { void branch_likely(Registers& regs, bool cond, s64 address) {
regs.delaySlot = true; regs.delaySlot = true;
if (cond) { if (cond) {
regs.nextPC = address; regs.nextPC = address;
@@ -160,78 +161,78 @@ void Dynarec::branch_likely(Registers& regs, bool cond, s64 address) {
} }
} }
void Dynarec::b(Registers& regs, u32 instr, bool cond) { void b(Registers& regs, u32 instr, bool cond) {
s64 offset = (s64)se_imm(instr) << 2; s64 offset = (s64)se_imm(instr) << 2;
s64 address = regs.pc + offset; s64 address = regs.pc + offset;
branch(regs, cond, address); branch(regs, cond, address);
} }
void Dynarec::blink(Registers& regs, u32 instr, bool cond) { void blink(Registers& regs, u32 instr, bool cond) {
regs.gpr[31] = regs.nextPC; regs.gpr[31] = regs.nextPC;
s64 offset = (s64)se_imm(instr) << 2; s64 offset = (s64)se_imm(instr) << 2;
s64 address = regs.pc + offset; s64 address = regs.pc + offset;
branch(regs, cond, address); branch(regs, cond, address);
} }
void Dynarec::bl(Registers& regs, u32 instr, bool cond) { void bl(Registers& regs, u32 instr, bool cond) {
s64 offset = (s64)se_imm(instr) << 2; s64 offset = (s64)se_imm(instr) << 2;
s64 address = regs.pc + offset; s64 address = regs.pc + offset;
branch_likely(regs, cond, address); branch_likely(regs, cond, address);
} }
void Dynarec::bllink(Registers& regs, u32 instr, bool cond) { void bllink(Registers& regs, u32 instr, bool cond) {
regs.gpr[31] = regs.nextPC; regs.gpr[31] = regs.nextPC;
s64 offset = (s64)se_imm(instr) << 2; s64 offset = (s64)se_imm(instr) << 2;
s64 address = regs.pc + offset; s64 address = regs.pc + offset;
branch_likely(regs, cond, address); branch_likely(regs, cond, address);
} }
void Dynarec::lui(Registers& regs, u32 instr) { void lui(Registers& regs, u32 instr) {
s64 val = (s16)instr; s64 val = (s16)instr;
val <<= 16; val <<= 16;
regs.gpr[RT(instr)] = val; regs.gpr[RT(instr)] = val;
} }
void Dynarec::lb(Registers& regs, Mem& mem, u32 instr) { void lb(Registers& regs, Mem& mem, u32 instr) {
u64 address = regs.gpr[RS(instr)] + (s16)instr; u64 address = regs.gpr[RS(instr)] + (s16)instr;
regs.gpr[RT(instr)] = (s8)mem.Read8(regs, address, regs.oldPC); regs.gpr[RT(instr)] = (s8)mem.Read8(regs, address, regs.oldPC);
} }
void Dynarec::lh(Registers& regs, Mem& mem, u32 instr) { void lh(Registers& regs, Mem& mem, u32 instr) {
u64 address = regs.gpr[RS(instr)] + (s16)instr; u64 address = regs.gpr[RS(instr)] + (s16)instr;
if (check_address_error(address, 0b1)) { if (check_address_error(address, 0b1)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); FireException(regs, ExceptionCode::AddressErrorLoad, 0, true);
return; return;
} }
regs.gpr[RT(instr)] = (s16)mem.Read16(regs, address, regs.oldPC); regs.gpr[RT(instr)] = (s16)mem.Read16(regs, address, regs.oldPC);
} }
void Dynarec::lw(Registers& regs, Mem& mem, u32 instr) { void lw(Registers& regs, Mem& mem, u32 instr) {
s16 offset = instr; s16 offset = instr;
u64 address = regs.gpr[RS(instr)] + offset; u64 address = regs.gpr[RS(instr)] + offset;
if (check_address_error(address, 0b11)) { if (check_address_error(address, 0b11)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); FireException(regs, ExceptionCode::AddressErrorLoad, 0, true);
return; return;
} }
u32 physical; u32 physical;
if (!MapVAddr(regs, LOAD, address, physical)) { if (!MapVAddr(regs, LOAD, address, physical)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
} else { } else {
regs.gpr[RT(instr)] = (s32)mem.Read32<false>(regs, physical, regs.oldPC); regs.gpr[RT(instr)] = (s32)mem.Read32<false>(regs, physical, regs.oldPC);
} }
} }
void Dynarec::ll(Registers& regs, Mem& mem, u32 instr) { void ll(Registers& regs, Mem& mem, u32 instr) {
s64 address = regs.gpr[RS(instr)] + (s16)instr; s64 address = regs.gpr[RS(instr)] + (s16)instr;
u32 physical; u32 physical;
if (!MapVAddr(regs, LOAD, address, physical)) { if (!MapVAddr(regs, LOAD, address, physical)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
} else { } else {
regs.gpr[RT(instr)] = (s32)mem.Read32<false>(regs, physical, regs.oldPC); regs.gpr[RT(instr)] = (s32)mem.Read32<false>(regs, physical, regs.oldPC);
} }
@@ -240,12 +241,12 @@ void Dynarec::ll(Registers& regs, Mem& mem, u32 instr) {
regs.cop0.LLAddr = physical >> 4; regs.cop0.LLAddr = physical >> 4;
} }
void Dynarec::lwl(Registers& regs, Mem& mem, u32 instr) { void lwl(Registers& regs, Mem& mem, u32 instr) {
u64 address = regs.gpr[RS(instr)] + (s16)instr; u64 address = regs.gpr[RS(instr)] + (s16)instr;
u32 paddr = 0; u32 paddr = 0;
if(!MapVAddr(regs, LOAD, address, paddr)) { if(!MapVAddr(regs, LOAD, address, paddr)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
} else { } else {
u32 shift = 8 * ((address ^ 0) & 3); u32 shift = 8 * ((address ^ 0) & 3);
u32 mask = 0xFFFFFFFF << shift; u32 mask = 0xFFFFFFFF << shift;
@@ -255,12 +256,12 @@ void Dynarec::lwl(Registers& regs, Mem& mem, u32 instr) {
} }
} }
void Dynarec::lwr(Registers& regs, Mem& mem, u32 instr) { void lwr(Registers& regs, Mem& mem, u32 instr) {
u64 address = regs.gpr[RS(instr)] + (s16)instr; u64 address = regs.gpr[RS(instr)] + (s16)instr;
u32 paddr = 0; u32 paddr = 0;
if(!MapVAddr(regs, LOAD, address, paddr)) { if(!MapVAddr(regs, LOAD, address, paddr)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
} else { } else {
u32 shift = 8 * ((address ^ 3) & 3); u32 shift = 8 * ((address ^ 3) & 3);
u32 mask = 0xFFFFFFFF >> shift; u32 mask = 0xFFFFFFFF >> shift;
@@ -270,11 +271,11 @@ void Dynarec::lwr(Registers& regs, Mem& mem, u32 instr) {
} }
} }
void Dynarec::ld(Registers& regs, Mem& mem, u32 instr) { void ld(Registers& regs, Mem& mem, u32 instr) {
s64 address = regs.gpr[RS(instr)] + (s16)instr; s64 address = regs.gpr[RS(instr)] + (s16)instr;
if (check_address_error(address, 0b111)) { if (check_address_error(address, 0b111)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); FireException(regs, ExceptionCode::AddressErrorLoad, 0, true);
return; return;
} }
@@ -282,12 +283,12 @@ void Dynarec::ld(Registers& regs, Mem& mem, u32 instr) {
regs.gpr[RT(instr)] = value; regs.gpr[RT(instr)] = value;
} }
void Dynarec::lld(Registers& regs, Mem& mem, u32 instr) { void lld(Registers& regs, Mem& mem, u32 instr) {
s64 address = regs.gpr[RS(instr)] + (s16)instr; s64 address = regs.gpr[RS(instr)] + (s16)instr;
u32 paddr; u32 paddr;
if (!MapVAddr(regs, LOAD, address, paddr)) { if (!MapVAddr(regs, LOAD, address, paddr)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
} else { } else {
regs.gpr[RT(instr)] = mem.Read64<false>(regs, paddr, regs.oldPC); regs.gpr[RT(instr)] = mem.Read64<false>(regs, paddr, regs.oldPC);
} }
@@ -296,12 +297,12 @@ void Dynarec::lld(Registers& regs, Mem& mem, u32 instr) {
regs.cop0.LLAddr = paddr >> 4; regs.cop0.LLAddr = paddr >> 4;
} }
void Dynarec::ldl(Registers& regs, Mem& mem, u32 instr) { void ldl(Registers& regs, Mem& mem, u32 instr) {
u64 address = regs.gpr[RS(instr)] + (s16)instr; u64 address = regs.gpr[RS(instr)] + (s16)instr;
u32 paddr = 0; u32 paddr = 0;
if (!MapVAddr(regs, LOAD, address, paddr)) { if (!MapVAddr(regs, LOAD, address, paddr)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
} else { } else {
s32 shift = 8 * ((address ^ 0) & 7); s32 shift = 8 * ((address ^ 0) & 7);
u64 mask = 0xFFFFFFFFFFFFFFFF << shift; u64 mask = 0xFFFFFFFFFFFFFFFF << shift;
@@ -311,12 +312,12 @@ void Dynarec::ldl(Registers& regs, Mem& mem, u32 instr) {
} }
} }
void Dynarec::ldr(Registers& regs, Mem& mem, u32 instr) { void ldr(Registers& regs, Mem& mem, u32 instr) {
u64 address = regs.gpr[RS(instr)] + (s16)instr; u64 address = regs.gpr[RS(instr)] + (s16)instr;
u32 paddr; u32 paddr;
if (!MapVAddr(regs, LOAD, address, paddr)) { if (!MapVAddr(regs, LOAD, address, paddr)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
} else { } else {
s32 shift = 8 * ((address ^ 7) & 7); s32 shift = 8 * ((address ^ 7) & 7);
u64 mask = 0xFFFFFFFFFFFFFFFF >> shift; u64 mask = 0xFFFFFFFFFFFFFFFF >> shift;
@@ -326,17 +327,17 @@ void Dynarec::ldr(Registers& regs, Mem& mem, u32 instr) {
} }
} }
void Dynarec::lbu(Registers& regs, Mem& mem, u32 instr) { void lbu(Registers& regs, Mem& mem, u32 instr) {
u64 address = regs.gpr[RS(instr)] + (s16)instr; u64 address = regs.gpr[RS(instr)] + (s16)instr;
u8 value = mem.Read8(regs, address, regs.oldPC); u8 value = mem.Read8(regs, address, regs.oldPC);
regs.gpr[RT(instr)] = value; regs.gpr[RT(instr)] = value;
} }
void Dynarec::lhu(Registers& regs, Mem& mem, u32 instr) { void lhu(Registers& regs, Mem& mem, u32 instr) {
s64 address = regs.gpr[RS(instr)] + (s16)instr; s64 address = regs.gpr[RS(instr)] + (s16)instr;
if (check_address_error(address, 0b1)) { if (check_address_error(address, 0b1)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); FireException(regs, ExceptionCode::AddressErrorLoad, 0, true);
return; return;
} }
@@ -344,11 +345,11 @@ void Dynarec::lhu(Registers& regs, Mem& mem, u32 instr) {
regs.gpr[RT(instr)] = value; regs.gpr[RT(instr)] = value;
} }
void Dynarec::lwu(Registers& regs, Mem& mem, u32 instr) { void lwu(Registers& regs, Mem& mem, u32 instr) {
s64 address = regs.gpr[RS(instr)] + (s16)instr; s64 address = regs.gpr[RS(instr)] + (s16)instr;
if (check_address_error(address, 0b11)) { if (check_address_error(address, 0b11)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); FireException(regs, ExceptionCode::AddressErrorLoad, 0, true);
return; return;
} }
@@ -356,16 +357,16 @@ void Dynarec::lwu(Registers& regs, Mem& mem, u32 instr) {
regs.gpr[RT(instr)] = value; regs.gpr[RT(instr)] = value;
} }
void Dynarec::sb(Registers& regs, Mem& mem, u32 instr) { void sb(Registers& regs, Mem& mem, u32 instr) {
u32 address = regs.gpr[RS(instr)] + (s16)instr; u32 address = regs.gpr[RS(instr)] + (s16)instr;
mem.Write8(regs, address, regs.gpr[RT(instr)], regs.oldPC); mem.Write8(regs, address, regs.gpr[RT(instr)], regs.oldPC);
} }
void Dynarec::sc(Registers& regs, Mem& mem, u32 instr) { void sc(Registers& regs, Mem& mem, u32 instr) {
s64 address = regs.gpr[RS(instr)] + (s16)instr; s64 address = regs.gpr[RS(instr)] + (s16)instr;
if (check_address_error(address, 0b11)) { if (check_address_error(address, 0b11)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC); FireException(regs, ExceptionCode::AddressErrorStore, 0, true);
} }
if(regs.cop0.llbit) { if(regs.cop0.llbit) {
@@ -376,11 +377,11 @@ void Dynarec::sc(Registers& regs, Mem& mem, u32 instr) {
regs.cop0.llbit = false; regs.cop0.llbit = false;
} }
void Dynarec::scd(Registers& regs, Mem& mem, u32 instr) { void scd(Registers& regs, Mem& mem, u32 instr) {
s64 address = regs.gpr[RS(instr)] + (s16)instr; s64 address = regs.gpr[RS(instr)] + (s16)instr;
if (check_address_error(address, 0b111)) { if (check_address_error(address, 0b111)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC); FireException(regs, ExceptionCode::AddressErrorStore, 0, true);
return; return;
} }
@@ -392,65 +393,65 @@ void Dynarec::scd(Registers& regs, Mem& mem, u32 instr) {
regs.cop0.llbit = false; regs.cop0.llbit = false;
} }
void Dynarec::sh(Registers& regs, Mem& mem, u32 instr) { void sh(Registers& regs, Mem& mem, u32 instr) {
s64 address = regs.gpr[RS(instr)] + (s16)instr; s64 address = regs.gpr[RS(instr)] + (s16)instr;
if (check_address_error(address, 0b1)) { if (check_address_error(address, 0b1)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC); FireException(regs, ExceptionCode::AddressErrorStore, 0, true);
return; return;
} }
u32 physical; u32 physical;
if(!MapVAddr(regs, STORE, address, physical)) { if(!MapVAddr(regs, STORE, address, physical)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
} else { } else {
mem.Write16<false>(regs, physical, regs.gpr[RT(instr)], regs.oldPC); mem.Write16<false>(regs, physical, regs.gpr[RT(instr)], regs.oldPC);
} }
} }
void Dynarec::sw(Registers& regs, Mem& mem, u32 instr) { void sw(Registers& regs, Mem& mem, u32 instr) {
s16 offset = instr; s16 offset = instr;
u64 address = regs.gpr[RS(instr)] + offset; u64 address = regs.gpr[RS(instr)] + offset;
if (check_address_error(address, 0b11)) { if (check_address_error(address, 0b11)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC); FireException(regs, ExceptionCode::AddressErrorStore, 0, true);
return; return;
} }
u32 physical; u32 physical;
if(!MapVAddr(regs, STORE, address, physical)) { if(!MapVAddr(regs, STORE, address, physical)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
} else { } else {
mem.Write32<false>(regs, physical, regs.gpr[RT(instr)], regs.oldPC); mem.Write32<false>(regs, physical, regs.gpr[RT(instr)], regs.oldPC);
} }
} }
void Dynarec::sd(Registers& regs, Mem& mem, u32 instr) { void sd(Registers& regs, Mem& mem, u32 instr) {
s64 address = regs.gpr[RS(instr)] + (s16)instr; s64 address = regs.gpr[RS(instr)] + (s16)instr;
if (check_address_error(address, 0b11)) { if (check_address_error(address, 0b11)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC); FireException(regs, ExceptionCode::AddressErrorStore, 0, true);
return; return;
} }
u32 physical; u32 physical;
if(!MapVAddr(regs, STORE, address, physical)) { if(!MapVAddr(regs, STORE, address, physical)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
} else { } else {
mem.Write64<false>(regs, physical, regs.gpr[RT(instr)], regs.oldPC); mem.Write64<false>(regs, physical, regs.gpr[RT(instr)], regs.oldPC);
} }
} }
void Dynarec::sdl(Registers& regs, Mem& mem, u32 instr) { void sdl(Registers& regs, Mem& mem, u32 instr) {
u64 address = regs.gpr[RS(instr)] + (s16)instr; u64 address = regs.gpr[RS(instr)] + (s16)instr;
u32 paddr; u32 paddr;
if (!MapVAddr(regs, STORE, address, paddr)) { if (!MapVAddr(regs, STORE, address, paddr)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
} else { } else {
s32 shift = 8 * ((address ^ 0) & 7); s32 shift = 8 * ((address ^ 0) & 7);
u64 mask = 0xFFFFFFFFFFFFFFFF >> shift; u64 mask = 0xFFFFFFFFFFFFFFFF >> shift;
@@ -460,12 +461,12 @@ void Dynarec::sdl(Registers& regs, Mem& mem, u32 instr) {
} }
} }
void Dynarec::sdr(Registers& regs, Mem& mem, u32 instr) { void sdr(Registers& regs, Mem& mem, u32 instr) {
u64 address = regs.gpr[RS(instr)] + (s16)instr; u64 address = regs.gpr[RS(instr)] + (s16)instr;
u32 paddr; u32 paddr;
if (!MapVAddr(regs, STORE, address, paddr)) { if (!MapVAddr(regs, STORE, address, paddr)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
} else { } else {
s32 shift = 8 * ((address ^ 7) & 7); s32 shift = 8 * ((address ^ 7) & 7);
u64 mask = 0xFFFFFFFFFFFFFFFF << shift; u64 mask = 0xFFFFFFFFFFFFFFFF << shift;
@@ -475,12 +476,12 @@ void Dynarec::sdr(Registers& regs, Mem& mem, u32 instr) {
} }
} }
void Dynarec::swl(Registers& regs, Mem& mem, u32 instr) { void swl(Registers& regs, Mem& mem, u32 instr) {
u64 address = regs.gpr[RS(instr)] + (s16)instr; u64 address = regs.gpr[RS(instr)] + (s16)instr;
u32 paddr; u32 paddr;
if (!MapVAddr(regs, STORE, address, paddr)) { if (!MapVAddr(regs, STORE, address, paddr)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
} else { } else {
u32 shift = 8 * ((address ^ 0) & 3); u32 shift = 8 * ((address ^ 0) & 3);
u32 mask = 0xFFFFFFFF >> shift; u32 mask = 0xFFFFFFFF >> shift;
@@ -490,12 +491,12 @@ void Dynarec::swl(Registers& regs, Mem& mem, u32 instr) {
} }
} }
void Dynarec::swr(Registers& regs, Mem& mem, u32 instr) { void swr(Registers& regs, Mem& mem, u32 instr) {
u64 address = regs.gpr[RS(instr)] + (s16)instr; u64 address = regs.gpr[RS(instr)] + (s16)instr;
u32 paddr; u32 paddr;
if (!MapVAddr(regs, STORE, address, paddr)) { if (!MapVAddr(regs, STORE, address, paddr)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
} else { } else {
u32 shift = 8 * ((address ^ 3) & 3); u32 shift = 8 * ((address ^ 3) & 3);
u32 mask = 0xFFFFFFFF << shift; u32 mask = 0xFFFFFFFF << shift;
@@ -505,149 +506,149 @@ void Dynarec::swr(Registers& regs, Mem& mem, u32 instr) {
} }
} }
void Dynarec::ori(Registers& regs, u32 instr) { void ori(Registers& regs, u32 instr) {
s64 imm = (u16)instr; s64 imm = (u16)instr;
s64 result = imm | regs.gpr[RS(instr)]; s64 result = imm | regs.gpr[RS(instr)];
regs.gpr[RT(instr)] = result; regs.gpr[RT(instr)] = result;
} }
void Dynarec::or_(Registers& regs, u32 instr) { void or_(Registers& regs, u32 instr) {
regs.gpr[RD(instr)] = regs.gpr[RS(instr)] | regs.gpr[RT(instr)]; regs.gpr[RD(instr)] = regs.gpr[RS(instr)] | regs.gpr[RT(instr)];
} }
void Dynarec::nor(Registers& regs, u32 instr) { void nor(Registers& regs, u32 instr) {
regs.gpr[RD(instr)] = ~(regs.gpr[RS(instr)] | regs.gpr[RT(instr)]); regs.gpr[RD(instr)] = ~(regs.gpr[RS(instr)] | regs.gpr[RT(instr)]);
} }
void Dynarec::j(Registers& regs, u32 instr) { void j(Registers& regs, u32 instr) {
s32 target = (instr & 0x3ffffff) << 2; s32 target = (instr & 0x3ffffff) << 2;
s64 address = (regs.oldPC & ~0xfffffff) | target; s64 address = (regs.oldPC & ~0xfffffff) | target;
if (check_address_error(address, 0b11)) { if (check_address_error(address, 0b11)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, ExceptionCode::DataBusError, 0, regs.oldPC); FireException(regs, ExceptionCode::DataBusError, 0, true);
} }
branch(regs, true, address); branch(regs, true, address);
} }
void Dynarec::jal(Registers& regs, u32 instr) { void jal(Registers& regs, u32 instr) {
regs.gpr[31] = regs.nextPC; regs.gpr[31] = regs.nextPC;
j(regs, instr); j(regs, instr);
} }
void Dynarec::jalr(Registers& regs, u32 instr) { void jalr(Registers& regs, u32 instr) {
branch(regs, true, regs.gpr[RS(instr)]); branch(regs, true, regs.gpr[RS(instr)]);
regs.gpr[RD(instr)] = regs.pc + 4; regs.gpr[RD(instr)] = regs.pc + 4;
} }
void Dynarec::slti(Registers& regs, u32 instr) { void slti(Registers& regs, u32 instr) {
regs.gpr[RT(instr)] = regs.gpr[RS(instr)] < se_imm(instr); regs.gpr[RT(instr)] = regs.gpr[RS(instr)] < se_imm(instr);
} }
void Dynarec::sltiu(Registers& regs, u32 instr) { void sltiu(Registers& regs, u32 instr) {
regs.gpr[RT(instr)] = (u64)regs.gpr[RS(instr)] < se_imm(instr); regs.gpr[RT(instr)] = (u64)regs.gpr[RS(instr)] < se_imm(instr);
} }
void Dynarec::slt(Registers& regs, u32 instr) { void slt(Registers& regs, u32 instr) {
regs.gpr[RD(instr)] = regs.gpr[RS(instr)] < regs.gpr[RT(instr)]; regs.gpr[RD(instr)] = regs.gpr[RS(instr)] < regs.gpr[RT(instr)];
} }
void Dynarec::sltu(Registers& regs, u32 instr) { void sltu(Registers& regs, u32 instr) {
regs.gpr[RD(instr)] = (u64)regs.gpr[RS(instr)] < (u64)regs.gpr[RT(instr)]; regs.gpr[RD(instr)] = (u64)regs.gpr[RS(instr)] < (u64)regs.gpr[RT(instr)];
} }
void Dynarec::xori(Registers& regs, u32 instr) { void xori(Registers& regs, u32 instr) {
s64 imm = (u16)instr; s64 imm = (u16)instr;
regs.gpr[RT(instr)] = regs.gpr[RS(instr)] ^ imm; regs.gpr[RT(instr)] = regs.gpr[RS(instr)] ^ imm;
} }
void Dynarec::xor_(Registers& regs, u32 instr) { void xor_(Registers& regs, u32 instr) {
regs.gpr[RD(instr)] = regs.gpr[RT(instr)] ^ regs.gpr[RS(instr)]; regs.gpr[RD(instr)] = regs.gpr[RT(instr)] ^ regs.gpr[RS(instr)];
} }
void Dynarec::andi(Registers& regs, u32 instr) { void andi(Registers& regs, u32 instr) {
s64 imm = (u16)instr; s64 imm = (u16)instr;
regs.gpr[RT(instr)] = regs.gpr[RS(instr)] & imm; regs.gpr[RT(instr)] = regs.gpr[RS(instr)] & imm;
} }
void Dynarec::and_(Registers& regs, u32 instr) { void and_(Registers& regs, u32 instr) {
regs.gpr[RD(instr)] = regs.gpr[RS(instr)] & regs.gpr[RT(instr)]; regs.gpr[RD(instr)] = regs.gpr[RS(instr)] & regs.gpr[RT(instr)];
} }
void Dynarec::sll(Registers& regs, u32 instr) { void sll(Registers& regs, u32 instr) {
u8 sa = ((instr >> 6) & 0x1f); u8 sa = ((instr >> 6) & 0x1f);
s32 result = regs.gpr[RT(instr)] << sa; s32 result = regs.gpr[RT(instr)] << sa;
regs.gpr[RD(instr)] = (s64)result; regs.gpr[RD(instr)] = (s64)result;
} }
void Dynarec::sllv(Registers& regs, u32 instr) { void sllv(Registers& regs, u32 instr) {
u8 sa = (regs.gpr[RS(instr)]) & 0x1F; u8 sa = (regs.gpr[RS(instr)]) & 0x1F;
u32 rt = regs.gpr[RT(instr)]; u32 rt = regs.gpr[RT(instr)];
s32 result = rt << sa; s32 result = rt << sa;
regs.gpr[RD(instr)] = (s64)result; regs.gpr[RD(instr)] = (s64)result;
} }
void Dynarec::dsll32(Registers& regs, u32 instr) { void dsll32(Registers& regs, u32 instr) {
u8 sa = ((instr >> 6) & 0x1f); u8 sa = ((instr >> 6) & 0x1f);
s64 result = regs.gpr[RT(instr)] << (sa + 32); s64 result = regs.gpr[RT(instr)] << (sa + 32);
regs.gpr[RD(instr)] = result; regs.gpr[RD(instr)] = result;
} }
void Dynarec::dsll(Registers& regs, u32 instr) { void dsll(Registers& regs, u32 instr) {
u8 sa = ((instr >> 6) & 0x1f); u8 sa = ((instr >> 6) & 0x1f);
s64 result = regs.gpr[RT(instr)] << sa; s64 result = regs.gpr[RT(instr)] << sa;
regs.gpr[RD(instr)] = result; regs.gpr[RD(instr)] = result;
} }
void Dynarec::dsllv(Registers& regs, u32 instr) { void dsllv(Registers& regs, u32 instr) {
s64 sa = regs.gpr[RS(instr)] & 63; s64 sa = regs.gpr[RS(instr)] & 63;
s64 result = regs.gpr[RT(instr)] << sa; s64 result = regs.gpr[RT(instr)] << sa;
regs.gpr[RD(instr)] = result; regs.gpr[RD(instr)] = result;
} }
void Dynarec::srl(Registers& regs, u32 instr) { void srl(Registers& regs, u32 instr) {
u32 rt = regs.gpr[RT(instr)]; u32 rt = regs.gpr[RT(instr)];
u8 sa = ((instr >> 6) & 0x1f); u8 sa = ((instr >> 6) & 0x1f);
u32 result = rt >> sa; u32 result = rt >> sa;
regs.gpr[RD(instr)] = (s32)result; regs.gpr[RD(instr)] = (s32)result;
} }
void Dynarec::srlv(Registers& regs, u32 instr) { void srlv(Registers& regs, u32 instr) {
u8 sa = (regs.gpr[RS(instr)] & 0x1F); u8 sa = (regs.gpr[RS(instr)] & 0x1F);
u32 rt = regs.gpr[RT(instr)]; u32 rt = regs.gpr[RT(instr)];
s32 result = rt >> sa; s32 result = rt >> sa;
regs.gpr[RD(instr)] = (s64)result; regs.gpr[RD(instr)] = (s64)result;
} }
void Dynarec::dsrl(Registers& regs, u32 instr) { void dsrl(Registers& regs, u32 instr) {
u64 rt = regs.gpr[RT(instr)]; u64 rt = regs.gpr[RT(instr)];
u8 sa = ((instr >> 6) & 0x1f); u8 sa = ((instr >> 6) & 0x1f);
u64 result = rt >> sa; u64 result = rt >> sa;
regs.gpr[RD(instr)] = s64(result); regs.gpr[RD(instr)] = s64(result);
} }
void Dynarec::dsrlv(Registers& regs, u32 instr) { void dsrlv(Registers& regs, u32 instr) {
u8 amount = (regs.gpr[RS(instr)] & 63); u8 amount = (regs.gpr[RS(instr)] & 63);
u64 rt = regs.gpr[RT(instr)]; u64 rt = regs.gpr[RT(instr)];
u64 result = rt >> amount; u64 result = rt >> amount;
regs.gpr[RD(instr)] = s64(result); regs.gpr[RD(instr)] = s64(result);
} }
void Dynarec::dsrl32(Registers& regs, u32 instr) { void dsrl32(Registers& regs, u32 instr) {
u64 rt = regs.gpr[RT(instr)]; u64 rt = regs.gpr[RT(instr)];
u8 sa = ((instr >> 6) & 0x1f); u8 sa = ((instr >> 6) & 0x1f);
u64 result = rt >> (sa + 32); u64 result = rt >> (sa + 32);
regs.gpr[RD(instr)] = s64(result); regs.gpr[RD(instr)] = s64(result);
} }
void Dynarec::sra(Registers& regs, u32 instr) { void sra(Registers& regs, u32 instr) {
s64 rt = regs.gpr[RT(instr)]; s64 rt = regs.gpr[RT(instr)];
u8 sa = ((instr >> 6) & 0x1f); u8 sa = ((instr >> 6) & 0x1f);
s32 result = rt >> sa; s32 result = rt >> sa;
regs.gpr[RD(instr)] = result; regs.gpr[RD(instr)] = result;
} }
void Dynarec::srav(Registers& regs, u32 instr) { void srav(Registers& regs, u32 instr) {
s64 rt = regs.gpr[RT(instr)]; s64 rt = regs.gpr[RT(instr)];
s64 rs = regs.gpr[RS(instr)]; s64 rs = regs.gpr[RS(instr)];
u8 sa = rs & 0x1f; u8 sa = rs & 0x1f;
@@ -655,14 +656,14 @@ void Dynarec::srav(Registers& regs, u32 instr) {
regs.gpr[RD(instr)] = result; regs.gpr[RD(instr)] = result;
} }
void Dynarec::dsra(Registers& regs, u32 instr) { void dsra(Registers& regs, u32 instr) {
s64 rt = regs.gpr[RT(instr)]; s64 rt = regs.gpr[RT(instr)];
u8 sa = ((instr >> 6) & 0x1f); u8 sa = ((instr >> 6) & 0x1f);
s64 result = rt >> sa; s64 result = rt >> sa;
regs.gpr[RD(instr)] = result; regs.gpr[RD(instr)] = result;
} }
void Dynarec::dsrav(Registers& regs, u32 instr) { void dsrav(Registers& regs, u32 instr) {
s64 rt = regs.gpr[RT(instr)]; s64 rt = regs.gpr[RT(instr)];
s64 rs = regs.gpr[RS(instr)]; s64 rs = regs.gpr[RS(instr)];
s64 sa = rs & 63; s64 sa = rs & 63;
@@ -670,14 +671,14 @@ void Dynarec::dsrav(Registers& regs, u32 instr) {
regs.gpr[RD(instr)] = result; regs.gpr[RD(instr)] = result;
} }
void Dynarec::dsra32(Registers& regs, u32 instr) { void dsra32(Registers& regs, u32 instr) {
s64 rt = regs.gpr[RT(instr)]; s64 rt = regs.gpr[RT(instr)];
u8 sa = ((instr >> 6) & 0x1f); u8 sa = ((instr >> 6) & 0x1f);
s64 result = rt >> (sa + 32); s64 result = rt >> (sa + 32);
regs.gpr[RD(instr)] = result; regs.gpr[RD(instr)] = result;
} }
void Dynarec::jr(Registers& regs, u32 instr) { void jr(Registers& regs, u32 instr) {
s64 address = regs.gpr[RS(instr)]; s64 address = regs.gpr[RS(instr)];
if (check_address_error(address, 0b11)) { if (check_address_error(address, 0b11)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
@@ -687,7 +688,7 @@ void Dynarec::jr(Registers& regs, u32 instr) {
branch(regs, true, address); branch(regs, true, address);
} }
void Dynarec::dsub(Registers& regs, u32 instr) { void dsub(Registers& regs, u32 instr) {
s64 rt = regs.gpr[RT(instr)]; s64 rt = regs.gpr[RT(instr)];
s64 rs = regs.gpr[RS(instr)]; s64 rs = regs.gpr[RS(instr)];
s64 result = rs - rt; s64 result = rs - rt;
@@ -698,14 +699,14 @@ void Dynarec::dsub(Registers& regs, u32 instr) {
} }
} }
void Dynarec::dsubu(Registers& regs, u32 instr) { void dsubu(Registers& regs, u32 instr) {
u64 rt = regs.gpr[RT(instr)]; u64 rt = regs.gpr[RT(instr)];
u64 rs = regs.gpr[RS(instr)]; u64 rs = regs.gpr[RS(instr)];
u64 result = rs - rt; u64 result = rs - rt;
regs.gpr[RD(instr)] = s64(result); regs.gpr[RD(instr)] = s64(result);
} }
void Dynarec::sub(Registers& regs, u32 instr) { void sub(Registers& regs, u32 instr) {
s32 rt = regs.gpr[RT(instr)]; s32 rt = regs.gpr[RT(instr)];
s32 rs = regs.gpr[RS(instr)]; s32 rs = regs.gpr[RS(instr)];
s32 result = rs - rt; s32 result = rs - rt;
@@ -716,14 +717,14 @@ void Dynarec::sub(Registers& regs, u32 instr) {
} }
} }
void Dynarec::subu(Registers& regs, u32 instr) { void subu(Registers& regs, u32 instr) {
u32 rt = regs.gpr[RT(instr)]; u32 rt = regs.gpr[RT(instr)];
u32 rs = regs.gpr[RS(instr)]; u32 rs = regs.gpr[RS(instr)];
u32 result = rs - rt; u32 result = rs - rt;
regs.gpr[RD(instr)] = (s64)((s32)result); regs.gpr[RD(instr)] = (s64)((s32)result);
} }
void Dynarec::dmultu(Registers& regs, u32 instr) { void dmultu(Registers& regs, u32 instr) {
u64 rt = regs.gpr[RT(instr)]; u64 rt = regs.gpr[RT(instr)];
u64 rs = regs.gpr[RS(instr)]; u64 rs = regs.gpr[RS(instr)];
u128 result = (u128)rt * (u128)rs; u128 result = (u128)rt * (u128)rs;
@@ -731,7 +732,7 @@ void Dynarec::dmultu(Registers& regs, u32 instr) {
regs.hi = (s64)(result >> 64); regs.hi = (s64)(result >> 64);
} }
void Dynarec::dmult(Registers& regs, u32 instr) { void dmult(Registers& regs, u32 instr) {
s64 rt = regs.gpr[RT(instr)]; s64 rt = regs.gpr[RT(instr)];
s64 rs = regs.gpr[RS(instr)]; s64 rs = regs.gpr[RS(instr)];
s128 result = (s128)rt * (s128)rs; s128 result = (s128)rt * (s128)rs;
@@ -739,7 +740,7 @@ void Dynarec::dmult(Registers& regs, u32 instr) {
regs.hi = result >> 64; regs.hi = result >> 64;
} }
void Dynarec::multu(Registers& regs, u32 instr) { void multu(Registers& regs, u32 instr) {
u32 rt = regs.gpr[RT(instr)]; u32 rt = regs.gpr[RT(instr)];
u32 rs = regs.gpr[RS(instr)]; u32 rs = regs.gpr[RS(instr)];
u64 result = (u64)rt * (u64)rs; u64 result = (u64)rt * (u64)rs;
@@ -747,7 +748,7 @@ void Dynarec::multu(Registers& regs, u32 instr) {
regs.hi = (s64)((s32)(result >> 32)); regs.hi = (s64)((s32)(result >> 32));
} }
void Dynarec::mult(Registers& regs, u32 instr) { void mult(Registers& regs, u32 instr) {
s32 rt = regs.gpr[RT(instr)]; s32 rt = regs.gpr[RT(instr)];
s32 rs = regs.gpr[RS(instr)]; s32 rs = regs.gpr[RS(instr)];
s64 result = (s64)rt * (s64)rs; s64 result = (s64)rt * (s64)rs;
@@ -755,51 +756,42 @@ void Dynarec::mult(Registers& regs, u32 instr) {
regs.hi = (s64)((s32)(result >> 32)); regs.hi = (s64)((s32)(result >> 32));
} }
void Dynarec::mflo(Registers& regs, u32 instr) { void mflo(Registers& regs, u32 instr) {
regs.gpr[RD(instr)] = regs.lo; regs.gpr[RD(instr)] = regs.lo;
} }
void Dynarec::mfhi(Registers& regs, u32 instr) { void mfhi(Registers& regs, u32 instr) {
regs.gpr[RD(instr)] = regs.hi; regs.gpr[RD(instr)] = regs.hi;
} }
void Dynarec::mtlo(Registers& regs, u32 instr) { void mtlo(Registers& regs, u32 instr) {
regs.lo = regs.gpr[RS(instr)]; regs.lo = regs.gpr[RS(instr)];
} }
void Dynarec::mthi(Registers& regs, u32 instr) { void mthi(Registers& regs, u32 instr) {
regs.hi = regs.gpr[RS(instr)]; regs.hi = regs.gpr[RS(instr)];
} }
void Dynarec::trap(Registers& regs, bool cond) { void trap(Registers& regs, bool cond) {
if(cond) { if(cond) {
FireException(regs, ExceptionCode::Trap, 0, regs.oldPC); FireException(regs, ExceptionCode::Trap, 0, regs.oldPC);
} }
} }
void Dynarec::mtc2(Registers& regs, u32 instr) { void mtc2(Dynarec& dyn, Registers& regs, u32 instr) {
cop2Latch = regs.gpr[RT(instr)]; dyn.cop2Latch = regs.gpr[RT(instr)];
} }
void Dynarec::mfc2(Registers& regs, u32 instr) { void mfc2(Dynarec& dyn, Registers& regs, u32 instr) {
s32 value = cop2Latch; s32 value = dyn.cop2Latch;
regs.gpr[RT(instr)] = value; regs.gpr[RT(instr)] = value;
} }
void Dynarec::dmtc2(Registers& regs, u32 instr) { void dmtc2(Dynarec& dyn, Registers& regs, u32 instr) {
cop2Latch = regs.gpr[RT(instr)]; dyn.cop2Latch = regs.gpr[RT(instr)];
} }
void Dynarec::dmfc2(Registers& regs, u32 instr) { void dmfc2(Dynarec& dyn, Registers& regs, u32 instr) {
regs.gpr[RT(instr)] = cop2Latch; regs.gpr[RT(instr)] = dyn.cop2Latch;
} }
void Dynarec::ctc2(Registers& regs, u32) {
}
void Dynarec::cfc2(Registers& regs, u32) {
}
} }

View File

@@ -0,0 +1,94 @@
#pragma once
#include <Dynarec.hpp>
namespace n64::JIT {
void add(Registers&, u32);
void addu(Registers&, u32);
void addi(Registers&, u32);
void addiu(Registers&, u32);
void andi(Registers&, u32);
void and_(Registers&, u32);
void branch(Registers&, bool, s64);
void branch_likely(Registers&, bool, s64);
void b(Registers&, u32, bool);
void blink(Registers&, u32, bool);
void bl(Registers&, u32, bool);
void bllink(Registers&, u32, bool);
void dadd(Registers&, u32);
void daddu(Registers&, u32);
void daddi(Registers&, u32);
void daddiu(Registers&, u32);
void ddiv(Registers&, u32);
void ddivu(Registers&, u32);
void div(Registers&, u32);
void divu(Registers&, u32);
void dmult(Registers&, u32);
void dmultu(Registers&, u32);
void dsll(Registers&, u32);
void dsllv(Registers&, u32);
void dsll32(Registers&, u32);
void dsra(Registers&, u32);
void dsrav(Registers&, u32);
void dsra32(Registers&, u32);
void dsrl(Registers&, u32);
void dsrlv(Registers&, u32);
void dsrl32(Registers&, u32);
void dsub(Registers&, u32);
void dsubu(Registers&, u32);
void j(Registers&, u32);
void jr(Registers&, u32);
void jal(Registers&, u32);
void jalr(Registers&, u32);
void lui(Registers&, u32);
void lbu(Registers&, Mem&, u32);
void lb(Registers&, Mem&, u32);
void ld(Registers&, Mem&, u32);
void ldl(Registers&, Mem&, u32);
void ldr(Registers&, Mem&, u32);
void lh(Registers&, Mem&, u32);
void lhu(Registers&, Mem&, u32);
void ll(Registers&, Mem&, u32);
void lld(Registers&, Mem&, u32);
void lw(Registers&, Mem&, u32);
void lwl(Registers&, Mem&, u32);
void lwu(Registers&, Mem&, u32);
void lwr(Registers&, Mem&, u32);
void mfhi(Registers&, u32);
void mflo(Registers&, u32);
void mult(Registers&, u32);
void multu(Registers&, u32);
void mthi(Registers&, u32);
void mtlo(Registers&, u32);
void nor(Registers&, u32);
void sb(Registers&, Mem&, u32);
void sc(Registers&, Mem&, u32);
void scd(Registers&, Mem&, u32);
void sd(Registers&, Mem&, u32);
void sdl(Registers&, Mem&, u32);
void sdr(Registers&, Mem&, u32);
void sh(Registers&, Mem&, u32);
void sw(Registers&, Mem&, u32);
void swl(Registers&, Mem&, u32);
void swr(Registers&, Mem&, u32);
void slti(Registers&, u32);
void sltiu(Registers&, u32);
void slt(Registers&, u32);
void sltu(Registers&, u32);
void sll(Registers&, u32);
void sllv(Registers&, u32);
void sub(Registers&, u32);
void subu(Registers&, u32);
void sra(Registers&, u32);
void srav(Registers&, u32);
void srl(Registers&, u32);
void srlv(Registers&, u32);
void trap(Registers&, bool);
void or_(Registers&, u32);
void ori(Registers&, u32);
void xor_(Registers&, u32);
void xori(Registers&, u32);
void mtc2(Dynarec& dyn, Registers&, u32);
void mfc2(Dynarec& dyn, Registers&, u32);
void dmtc2(Dynarec& dyn, Registers&, u32);
void dmfc2(Dynarec& dyn, Registers&, u32);
}

View File

@@ -0,0 +1,4 @@
file(GLOB_RECURSE SOURCES *.cpp)
file(GLOB_RECURSE HEADERS *.hpp)
add_library(interpreter ${SOURCES} ${HEADERS})

View File

@@ -26,7 +26,7 @@ inline int PushRoundingMode(const FCR31& fcr31) {
if(isnanf(fs) || isnanf(ft)) { \ if(isnanf(fs) || isnanf(ft)) { \
regs.cop1.fcr31.flag_invalid_operation = true; \ regs.cop1.fcr31.flag_invalid_operation = true; \
regs.cop1.fcr31.cause_invalid_operation = true; \ regs.cop1.fcr31.cause_invalid_operation = true; \
FireException(regs, ExceptionCode::FloatingPointError, 1, regs.oldPC); \ FireException(regs, ExceptionCode::FloatingPointError, 1, true); \
return; \ return; \
} }
@@ -34,7 +34,7 @@ inline int PushRoundingMode(const FCR31& fcr31) {
if(isnan(fs) || isnan(ft)) { \ if(isnan(fs) || isnan(ft)) { \
regs.cop1.fcr31.flag_invalid_operation = true; \ regs.cop1.fcr31.flag_invalid_operation = true; \
regs.cop1.fcr31.cause_invalid_operation = true; \ regs.cop1.fcr31.cause_invalid_operation = true; \
FireException(regs, ExceptionCode::FloatingPointError, 1, regs.oldPC); \ FireException(regs, ExceptionCode::FloatingPointError, 1, true); \
return; \ return; \
} }
#else #else
@@ -42,7 +42,7 @@ inline int PushRoundingMode(const FCR31& fcr31) {
if(isnanf(fs) || isnanf(ft)) { \ if(isnanf(fs) || isnanf(ft)) { \
regs.cop1.fcr31.flag_invalid_operation = true; \ regs.cop1.fcr31.flag_invalid_operation = true; \
regs.cop1.fcr31.cause_invalid_operation = true; \ regs.cop1.fcr31.cause_invalid_operation = true; \
FireException(regs, ExceptionCode::FloatingPointError, 1, regs.oldPC); \ FireException(regs, ExceptionCode::FloatingPointError, 1, true); \
return; \ return; \
} }
@@ -50,7 +50,7 @@ inline int PushRoundingMode(const FCR31& fcr31) {
if(isnan(fs) || isnan(ft)) { \ if(isnan(fs) || isnan(ft)) { \
regs.cop1.fcr31.flag_invalid_operation = true; \ regs.cop1.fcr31.flag_invalid_operation = true; \
regs.cop1.fcr31.cause_invalid_operation = true; \ regs.cop1.fcr31.cause_invalid_operation = true; \
FireException(regs, ExceptionCode::FloatingPointError, 1, regs.oldPC); \ FireException(regs, ExceptionCode::FloatingPointError, 1, true); \
return; \ return; \
} }
#endif #endif
@@ -264,7 +264,7 @@ inline bool CalculateCondition(Registers& regs, T fs, T ft, CompConds cond) {
if(std::isnan(fs) || std::isnan(ft)) { if(std::isnan(fs) || std::isnan(ft)) {
regs.cop1.fcr31.flag_invalid_operation = true; regs.cop1.fcr31.flag_invalid_operation = true;
regs.cop1.fcr31.cause_invalid_operation = true; regs.cop1.fcr31.cause_invalid_operation = true;
FireException(regs, ExceptionCode::FloatingPointError, 1, regs.oldPC); FireException(regs, ExceptionCode::FloatingPointError, 1, true);
return false; return false;
} }
@@ -469,19 +469,19 @@ void Cop1::floorwd(Registers& regs, u32 instr) {
void Cop1::lwc1(Registers& regs, Mem& mem, u32 instr) { void Cop1::lwc1(Registers& regs, Mem& mem, u32 instr) {
if(!regs.cop0.status.cu1) { if(!regs.cop0.status.cu1) {
FireException(regs, ExceptionCode::CoprocessorUnusable, 1, regs.oldPC); FireException(regs, ExceptionCode::CoprocessorUnusable, 1, true);
return; return;
} }
u64 addr = (s64)(s16)instr + regs.gpr[BASE(instr)]; u64 addr = (s64)(s16)instr + regs.gpr[BASE(instr)];
if(addr & 3) { if(addr & 3) {
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); FireException(regs, ExceptionCode::AddressErrorLoad, 0, true);
} }
u32 physical; u32 physical;
if(!MapVAddr(regs, LOAD, addr, physical)) { if(!MapVAddr(regs, LOAD, addr, physical)) {
HandleTLBException(regs, addr); HandleTLBException(regs, addr);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
} else { } else {
u32 data = mem.Read32<false>(regs, physical, regs.oldPC); u32 data = mem.Read32<false>(regs, physical, regs.oldPC);
SetReg<u32>(regs.cop0, FT(instr), data); SetReg<u32>(regs.cop0, FT(instr), data);
@@ -490,19 +490,19 @@ void Cop1::lwc1(Registers& regs, Mem& mem, u32 instr) {
void Cop1::swc1(Registers& regs, Mem& mem, u32 instr) { void Cop1::swc1(Registers& regs, Mem& mem, u32 instr) {
if(!regs.cop0.status.cu1) { if(!regs.cop0.status.cu1) {
FireException(regs, ExceptionCode::CoprocessorUnusable, 1, regs.oldPC); FireException(regs, ExceptionCode::CoprocessorUnusable, 1, true);
return; return;
} }
u64 addr = (s64)(s16)instr + regs.gpr[BASE(instr)]; u64 addr = (s64)(s16)instr + regs.gpr[BASE(instr)];
if(addr & 3) { if(addr & 3) {
FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC); FireException(regs, ExceptionCode::AddressErrorStore, 0, true);
} }
u32 physical; u32 physical;
if(!MapVAddr(regs, STORE, addr, physical)) { if(!MapVAddr(regs, STORE, addr, physical)) {
HandleTLBException(regs, addr); HandleTLBException(regs, addr);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
} else { } else {
mem.Write32<false>(regs, physical, GetReg<u32>(regs.cop0, FT(instr)), regs.oldPC); mem.Write32<false>(regs, physical, GetReg<u32>(regs.cop0, FT(instr)), regs.oldPC);
} }
@@ -510,13 +510,13 @@ void Cop1::swc1(Registers& regs, Mem& mem, u32 instr) {
void Cop1::ldc1(Registers& regs, Mem& mem, u32 instr) { void Cop1::ldc1(Registers& regs, Mem& mem, u32 instr) {
if(!regs.cop0.status.cu1) { if(!regs.cop0.status.cu1) {
FireException(regs, ExceptionCode::CoprocessorUnusable, 1, regs.oldPC); FireException(regs, ExceptionCode::CoprocessorUnusable, 1, true);
return; return;
} }
u64 addr = (s64)(s16)instr + regs.gpr[BASE(instr)]; u64 addr = (s64)(s16)instr + regs.gpr[BASE(instr)];
if(addr & 7) { if(addr & 7) {
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); FireException(regs, ExceptionCode::AddressErrorLoad, 0, true);
} }
u32 physical; u32 physical;

View File

@@ -2,7 +2,7 @@
#include <log.hpp> #include <log.hpp>
namespace n64 { namespace n64 {
void Interpreter::special(Registers& regs, Mem& mem, u32 instr) { void Interpreter::special(Registers& regs, u32 instr) {
u8 mask = (instr & 0x3F); u8 mask = (instr & 0x3F);
// 00rr_rccc // 00rr_rccc
switch (mask) { // TODO: named constants for clearer code switch (mask) { // TODO: named constants for clearer code
@@ -18,8 +18,8 @@ void Interpreter::special(Registers& regs, Mem& mem, u32 instr) {
case 0x07: srav(regs, instr); break; case 0x07: srav(regs, instr); break;
case 0x08: jr(regs, instr); break; case 0x08: jr(regs, instr); break;
case 0x09: jalr(regs, instr); break; case 0x09: jalr(regs, instr); break;
case 0x0C: FireException(regs, ExceptionCode::Syscall, 0, regs.oldPC); break; case 0x0C: FireException(regs, ExceptionCode::Syscall, 0, true); break;
case 0x0D: FireException(regs, ExceptionCode::Breakpoint, 0, regs.oldPC); break; case 0x0D: FireException(regs, ExceptionCode::Breakpoint, 0, true); break;
case 0x0F: break; // SYNC case 0x0F: break; // SYNC
case 0x10: mfhi(regs, instr); break; case 0x10: mfhi(regs, instr); break;
case 0x11: mthi(regs, instr); break; case 0x11: mthi(regs, instr); break;
@@ -92,7 +92,7 @@ void Interpreter::regimm(Registers& regs, u32 instr) {
void Interpreter::cop2Decode(Registers& regs, u32 instr) { void Interpreter::cop2Decode(Registers& regs, u32 instr) {
if(!regs.cop0.status.cu2) { if(!regs.cop0.status.cu2) {
FireException(regs, ExceptionCode::CoprocessorUnusable, 2, regs.oldPC); FireException(regs, ExceptionCode::CoprocessorUnusable, 2, true);
return; return;
} }
switch(RS(instr)) { switch(RS(instr)) {
@@ -103,7 +103,7 @@ void Interpreter::cop2Decode(Registers& regs, u32 instr) {
case 0x05: dmtc2(regs, instr); break; case 0x05: dmtc2(regs, instr); break;
case 0x06: ctc2(regs, instr); break; case 0x06: ctc2(regs, instr); break;
default: default:
FireException(regs, ExceptionCode::ReservedInstruction, 2, regs.oldPC); FireException(regs, ExceptionCode::ReservedInstruction, 2, true);
} }
} }
@@ -111,7 +111,7 @@ void Interpreter::Exec(Registers& regs, Mem& mem, u32 instr) {
u8 mask = (instr >> 26) & 0x3f; u8 mask = (instr >> 26) & 0x3f;
// 00rr_rccc // 00rr_rccc
switch(mask) { // TODO: named constants for clearer code switch(mask) { // TODO: named constants for clearer code
case 0x00: special(regs, mem, instr); break; case 0x00: special(regs, instr); break;
case 0x01: regimm(regs, instr); break; case 0x01: regimm(regs, instr); break;
case 0x02: j(regs, instr); break; case 0x02: j(regs, instr); break;
case 0x03: jal(regs, instr); break; case 0x03: jal(regs, instr); break;
@@ -141,7 +141,7 @@ void Interpreter::Exec(Registers& regs, Mem& mem, u32 instr) {
case 0x19: daddiu(regs, instr); break; case 0x19: daddiu(regs, instr); break;
case 0x1A: ldl(regs, mem, instr); break; case 0x1A: ldl(regs, mem, instr); break;
case 0x1B: ldr(regs, mem, instr); break; case 0x1B: ldr(regs, mem, instr); break;
case 0x1F: FireException(regs, ExceptionCode::ReservedInstruction, 0, regs.oldPC); break; case 0x1F: FireException(regs, ExceptionCode::ReservedInstruction, 0, true); break;
case 0x20: lb(regs, mem, instr); break; case 0x20: lb(regs, mem, instr); break;
case 0x21: lh(regs, mem, instr); break; case 0x21: lh(regs, mem, instr); break;
case 0x22: lwl(regs, mem, instr); break; case 0x22: lwl(regs, mem, instr); break;

View File

@@ -11,7 +11,7 @@ void Interpreter::add(Registers& regs, u32 instr) {
u32 rt = (s32)regs.gpr[RT(instr)]; u32 rt = (s32)regs.gpr[RT(instr)];
u32 result = rs + rt; u32 result = rs + rt;
if(check_signed_overflow(rs, rt, result)) { if(check_signed_overflow(rs, rt, result)) {
FireException(regs, ExceptionCode::Overflow, 0, regs.oldPC); FireException(regs, ExceptionCode::Overflow, 0, true);
} else { } else {
regs.gpr[RD(instr)] = s32(result); regs.gpr[RD(instr)] = s32(result);
} }
@@ -29,7 +29,7 @@ void Interpreter::addi(Registers& regs, u32 instr) {
u32 imm = s32(s16(instr)); u32 imm = s32(s16(instr));
u32 result = rs + imm; u32 result = rs + imm;
if(check_signed_overflow(rs, imm, result)) { if(check_signed_overflow(rs, imm, result)) {
FireException(regs, ExceptionCode::Overflow, 0, regs.oldPC); FireException(regs, ExceptionCode::Overflow, 0, true);
} else { } else {
regs.gpr[RT(instr)] = s32(result); regs.gpr[RT(instr)] = s32(result);
} }
@@ -47,7 +47,7 @@ void Interpreter::dadd(Registers& regs, u32 instr) {
u64 rt = regs.gpr[RT(instr)]; u64 rt = regs.gpr[RT(instr)];
u64 result = rt + rs; u64 result = rt + rs;
if(check_signed_overflow(rs, rt, result)) { if(check_signed_overflow(rs, rt, result)) {
FireException(regs, ExceptionCode::Overflow, 0, regs.oldPC); FireException(regs, ExceptionCode::Overflow, 0, true);
} else { } else {
regs.gpr[RD(instr)] = result; regs.gpr[RD(instr)] = result;
} }
@@ -64,7 +64,7 @@ void Interpreter::daddi(Registers& regs, u32 instr) {
u64 rs = regs.gpr[RS(instr)]; u64 rs = regs.gpr[RS(instr)];
u64 result = imm + rs; u64 result = imm + rs;
if(check_signed_overflow(rs, imm, result)) { if(check_signed_overflow(rs, imm, result)) {
FireException(regs, ExceptionCode::Overflow, 0, regs.oldPC); FireException(regs, ExceptionCode::Overflow, 0, true);
} else { } else {
regs.gpr[RT(instr)] = result; regs.gpr[RT(instr)] = result;
} }
@@ -201,7 +201,7 @@ void Interpreter::lh(Registers& regs, Mem& mem, u32 instr) {
u64 address = regs.gpr[RS(instr)] + (s16)instr; u64 address = regs.gpr[RS(instr)] + (s16)instr;
if (check_address_error(address, 0b1)) { if (check_address_error(address, 0b1)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); FireException(regs, ExceptionCode::AddressErrorLoad, 0, true);
return; return;
} }
@@ -213,14 +213,14 @@ void Interpreter::lw(Registers& regs, Mem& mem, u32 instr) {
u64 address = regs.gpr[RS(instr)] + offset; u64 address = regs.gpr[RS(instr)] + offset;
if (check_address_error(address, 0b11)) { if (check_address_error(address, 0b11)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); FireException(regs, ExceptionCode::AddressErrorLoad, 0, true);
return; return;
} }
u32 physical; u32 physical;
if (!MapVAddr(regs, LOAD, address, physical)) { if (!MapVAddr(regs, LOAD, address, physical)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
} else { } else {
regs.gpr[RT(instr)] = (s32)mem.Read32<false>(regs, physical, regs.oldPC); regs.gpr[RT(instr)] = (s32)mem.Read32<false>(regs, physical, regs.oldPC);
} }
@@ -231,7 +231,7 @@ void Interpreter::ll(Registers& regs, Mem& mem, u32 instr) {
u32 physical; u32 physical;
if (!MapVAddr(regs, LOAD, address, physical)) { if (!MapVAddr(regs, LOAD, address, physical)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
} else { } else {
regs.gpr[RT(instr)] = (s32)mem.Read32<false>(regs, physical, regs.oldPC); regs.gpr[RT(instr)] = (s32)mem.Read32<false>(regs, physical, regs.oldPC);
} }
@@ -245,7 +245,7 @@ void Interpreter::lwl(Registers& regs, Mem& mem, u32 instr) {
u32 paddr = 0; u32 paddr = 0;
if(!MapVAddr(regs, LOAD, address, paddr)) { if(!MapVAddr(regs, LOAD, address, paddr)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
} else { } else {
u32 shift = 8 * ((address ^ 0) & 3); u32 shift = 8 * ((address ^ 0) & 3);
u32 mask = 0xFFFFFFFF << shift; u32 mask = 0xFFFFFFFF << shift;
@@ -260,7 +260,7 @@ void Interpreter::lwr(Registers& regs, Mem& mem, u32 instr) {
u32 paddr = 0; u32 paddr = 0;
if(!MapVAddr(regs, LOAD, address, paddr)) { if(!MapVAddr(regs, LOAD, address, paddr)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
} else { } else {
u32 shift = 8 * ((address ^ 3) & 3); u32 shift = 8 * ((address ^ 3) & 3);
u32 mask = 0xFFFFFFFF >> shift; u32 mask = 0xFFFFFFFF >> shift;
@@ -274,7 +274,7 @@ void Interpreter::ld(Registers& regs, Mem& mem, u32 instr) {
s64 address = regs.gpr[RS(instr)] + (s16)instr; s64 address = regs.gpr[RS(instr)] + (s16)instr;
if (check_address_error(address, 0b111)) { if (check_address_error(address, 0b111)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); FireException(regs, ExceptionCode::AddressErrorLoad, 0, true);
return; return;
} }
@@ -287,7 +287,7 @@ void Interpreter::lld(Registers& regs, Mem& mem, u32 instr) {
u32 paddr; u32 paddr;
if (!MapVAddr(regs, LOAD, address, paddr)) { if (!MapVAddr(regs, LOAD, address, paddr)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
} else { } else {
regs.gpr[RT(instr)] = mem.Read64<false>(regs, paddr, regs.oldPC); regs.gpr[RT(instr)] = mem.Read64<false>(regs, paddr, regs.oldPC);
} }
@@ -301,7 +301,7 @@ void Interpreter::ldl(Registers& regs, Mem& mem, u32 instr) {
u32 paddr = 0; u32 paddr = 0;
if (!MapVAddr(regs, LOAD, address, paddr)) { if (!MapVAddr(regs, LOAD, address, paddr)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
} else { } else {
s32 shift = 8 * ((address ^ 0) & 7); s32 shift = 8 * ((address ^ 0) & 7);
u64 mask = 0xFFFFFFFFFFFFFFFF << shift; u64 mask = 0xFFFFFFFFFFFFFFFF << shift;
@@ -316,7 +316,7 @@ void Interpreter::ldr(Registers& regs, Mem& mem, u32 instr) {
u32 paddr; u32 paddr;
if (!MapVAddr(regs, LOAD, address, paddr)) { if (!MapVAddr(regs, LOAD, address, paddr)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
} else { } else {
s32 shift = 8 * ((address ^ 7) & 7); s32 shift = 8 * ((address ^ 7) & 7);
u64 mask = 0xFFFFFFFFFFFFFFFF >> shift; u64 mask = 0xFFFFFFFFFFFFFFFF >> shift;
@@ -336,7 +336,7 @@ void Interpreter::lhu(Registers& regs, Mem& mem, u32 instr) {
s64 address = regs.gpr[RS(instr)] + (s16)instr; s64 address = regs.gpr[RS(instr)] + (s16)instr;
if (check_address_error(address, 0b1)) { if (check_address_error(address, 0b1)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); FireException(regs, ExceptionCode::AddressErrorLoad, 0, true);
return; return;
} }
@@ -348,7 +348,7 @@ void Interpreter::lwu(Registers& regs, Mem& mem, u32 instr) {
s64 address = regs.gpr[RS(instr)] + (s16)instr; s64 address = regs.gpr[RS(instr)] + (s16)instr;
if (check_address_error(address, 0b11)) { if (check_address_error(address, 0b11)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); FireException(regs, ExceptionCode::AddressErrorLoad, 0, true);
return; return;
} }
@@ -365,7 +365,7 @@ void Interpreter::sc(Registers& regs, Mem& mem, u32 instr) {
s64 address = regs.gpr[RS(instr)] + (s16)instr; s64 address = regs.gpr[RS(instr)] + (s16)instr;
if (check_address_error(address, 0b11)) { if (check_address_error(address, 0b11)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC); FireException(regs, ExceptionCode::AddressErrorStore, 0, true);
} }
if(regs.cop0.llbit) { if(regs.cop0.llbit) {
@@ -380,7 +380,7 @@ void Interpreter::scd(Registers& regs, Mem& mem, u32 instr) {
s64 address = regs.gpr[RS(instr)] + (s16)instr; s64 address = regs.gpr[RS(instr)] + (s16)instr;
if (check_address_error(address, 0b111)) { if (check_address_error(address, 0b111)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC); FireException(regs, ExceptionCode::AddressErrorStore, 0, true);
return; return;
} }
@@ -396,14 +396,14 @@ void Interpreter::sh(Registers& regs, Mem& mem, u32 instr) {
s64 address = regs.gpr[RS(instr)] + (s16)instr; s64 address = regs.gpr[RS(instr)] + (s16)instr;
if (check_address_error(address, 0b1)) { if (check_address_error(address, 0b1)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC); FireException(regs, ExceptionCode::AddressErrorStore, 0, true);
return; return;
} }
u32 physical; u32 physical;
if(!MapVAddr(regs, STORE, address, physical)) { if(!MapVAddr(regs, STORE, address, physical)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
} else { } else {
mem.Write16<false>(regs, physical, regs.gpr[RT(instr)], regs.oldPC); mem.Write16<false>(regs, physical, regs.gpr[RT(instr)], regs.oldPC);
} }
@@ -414,14 +414,14 @@ void Interpreter::sw(Registers& regs, Mem& mem, u32 instr) {
u64 address = regs.gpr[RS(instr)] + offset; u64 address = regs.gpr[RS(instr)] + offset;
if (check_address_error(address, 0b11)) { if (check_address_error(address, 0b11)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC); FireException(regs, ExceptionCode::AddressErrorStore, 0, true);
return; return;
} }
u32 physical; u32 physical;
if(!MapVAddr(regs, STORE, address, physical)) { if(!MapVAddr(regs, STORE, address, physical)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
} else { } else {
mem.Write32<false>(regs, physical, regs.gpr[RT(instr)], regs.oldPC); mem.Write32<false>(regs, physical, regs.gpr[RT(instr)], regs.oldPC);
} }
@@ -431,14 +431,14 @@ void Interpreter::sd(Registers& regs, Mem& mem, u32 instr) {
s64 address = regs.gpr[RS(instr)] + (s16)instr; s64 address = regs.gpr[RS(instr)] + (s16)instr;
if (check_address_error(address, 0b11)) { if (check_address_error(address, 0b11)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC); FireException(regs, ExceptionCode::AddressErrorStore, 0, true);
return; return;
} }
u32 physical; u32 physical;
if(!MapVAddr(regs, STORE, address, physical)) { if(!MapVAddr(regs, STORE, address, physical)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
} else { } else {
mem.Write64<false>(regs, physical, regs.gpr[RT(instr)], regs.oldPC); mem.Write64<false>(regs, physical, regs.gpr[RT(instr)], regs.oldPC);
} }
@@ -450,7 +450,7 @@ void Interpreter::sdl(Registers& regs, Mem& mem, u32 instr) {
u32 paddr; u32 paddr;
if (!MapVAddr(regs, STORE, address, paddr)) { if (!MapVAddr(regs, STORE, address, paddr)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
} else { } else {
s32 shift = 8 * ((address ^ 0) & 7); s32 shift = 8 * ((address ^ 0) & 7);
u64 mask = 0xFFFFFFFFFFFFFFFF >> shift; u64 mask = 0xFFFFFFFFFFFFFFFF >> shift;
@@ -465,7 +465,7 @@ void Interpreter::sdr(Registers& regs, Mem& mem, u32 instr) {
u32 paddr; u32 paddr;
if (!MapVAddr(regs, STORE, address, paddr)) { if (!MapVAddr(regs, STORE, address, paddr)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
} else { } else {
s32 shift = 8 * ((address ^ 7) & 7); s32 shift = 8 * ((address ^ 7) & 7);
u64 mask = 0xFFFFFFFFFFFFFFFF << shift; u64 mask = 0xFFFFFFFFFFFFFFFF << shift;
@@ -480,7 +480,7 @@ void Interpreter::swl(Registers& regs, Mem& mem, u32 instr) {
u32 paddr; u32 paddr;
if (!MapVAddr(regs, STORE, address, paddr)) { if (!MapVAddr(regs, STORE, address, paddr)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
} else { } else {
u32 shift = 8 * ((address ^ 0) & 3); u32 shift = 8 * ((address ^ 0) & 3);
u32 mask = 0xFFFFFFFF >> shift; u32 mask = 0xFFFFFFFF >> shift;
@@ -495,7 +495,7 @@ void Interpreter::swr(Registers& regs, Mem& mem, u32 instr) {
u32 paddr; u32 paddr;
if (!MapVAddr(regs, STORE, address, paddr)) { if (!MapVAddr(regs, STORE, address, paddr)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
} else { } else {
u32 shift = 8 * ((address ^ 3) & 3); u32 shift = 8 * ((address ^ 3) & 3);
u32 mask = 0xFFFFFFFF << shift; u32 mask = 0xFFFFFFFF << shift;
@@ -524,7 +524,7 @@ void Interpreter::j(Registers& regs, u32 instr) {
s64 address = (regs.oldPC & ~0xfffffff) | target; s64 address = (regs.oldPC & ~0xfffffff) | target;
if (check_address_error(address, 0b11)) { if (check_address_error(address, 0b11)) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, ExceptionCode::DataBusError, 0, regs.oldPC); FireException(regs, ExceptionCode::DataBusError, 0, true);
} }
branch(regs, true, address); branch(regs, true, address);

View File

@@ -0,0 +1,4 @@
file(GLOB SOURCES *.cpp)
file(GLOB HEADERS *.hpp)
add_library(mmio ${SOURCES} ${HEADERS})

View File

@@ -0,0 +1,4 @@
file(GLOB SOURCES *.cpp)
file(GLOB HEADERS *.cpp)
add_library(registers ${SOURCES} ${HEADERS})

View File

@@ -244,8 +244,9 @@ inline bool Is64BitAddressing(Cop0& cp0, u64 addr) {
} }
} }
void FireException(Registers& regs, ExceptionCode code, int cop, s64 pc) { void FireException(Registers& regs, ExceptionCode code, int cop, bool useOldPC) {
bool old_exl = regs.cop0.status.exl; bool old_exl = regs.cop0.status.exl;
s64 pc = useOldPC ? regs.oldPC : regs.pc;
if(!regs.cop0.status.exl) { if(!regs.cop0.status.exl) {
if(regs.prevDelaySlot) { if(regs.prevDelaySlot) {

View File

@@ -177,7 +177,7 @@ enum class ExceptionCode : u8 {
Watch = 23 Watch = 23
}; };
void FireException(Registers& regs, ExceptionCode code, int cop, s64 pc); void FireException(Registers& regs, ExceptionCode code, int cop, bool useOldPC);
union Cop0Context { union Cop0Context {
u64 raw; u64 raw;
@@ -235,9 +235,6 @@ struct Cop0 {
TLBError tlbError = NONE; TLBError tlbError = NONE;
s64 openbus{}; s64 openbus{};
void decode(Registers&, Mem&, u32); void decode(Registers&, Mem&, u32);
private:
inline u32 GetWired() { return wired & 0x3F; }
inline u32 GetCount() { return u32(u64(count >> 1)); }
inline u32 GetRandom() { inline u32 GetRandom() {
int val = rand(); int val = rand();
int wired = GetWired(); int wired = GetWired();
@@ -253,16 +250,19 @@ private:
val = (val % upper) + lower; val = (val % upper) + lower;
return val; return val;
} }
private:
inline u32 GetWired() { return wired & 0x3F; }
inline u32 GetCount() { return u32(u64(count >> 1)); }
void mtc0(Registers&, u32); void mtc0(n64::Registers&, u32);
void dmtc0(Registers&, u32); void dmtc0(n64::Registers&, u32);
void mfc0(Registers&, u32); void mfc0(n64::Registers&, u32);
void dmfc0(Registers&, u32); void dmfc0(n64::Registers&, u32);
void eret(Registers&); void eret(n64::Registers&);
void tlbr(Registers&); void tlbr(n64::Registers&);
void tlbw(int, Registers&); void tlbw(int, n64::Registers&);
void tlbp(Registers&); void tlbp(n64::Registers&);
}; };
struct Registers; struct Registers;

View File

@@ -16,7 +16,7 @@ void Cop1::Reset() {
void Cop1::decode(Registers& regs, Interpreter& cpu, u32 instr) { void Cop1::decode(Registers& regs, Interpreter& cpu, u32 instr) {
if(!regs.cop0.status.cu1) { if(!regs.cop0.status.cu1) {
FireException(regs, ExceptionCode::CoprocessorUnusable, 1, regs.oldPC); FireException(regs, ExceptionCode::CoprocessorUnusable, 1, true);
return; return;
} }
@@ -28,11 +28,11 @@ void Cop1::decode(Registers& regs, Interpreter& cpu, u32 instr) {
case 0x00: mfc1(regs, instr); break; case 0x00: mfc1(regs, instr); break;
case 0x01: dmfc1(regs, instr); break; case 0x01: dmfc1(regs, instr); break;
case 0x02: cfc1(regs, instr); break; case 0x02: cfc1(regs, instr); break;
case 0x03: FireException(regs, ExceptionCode::ReservedInstruction, 1, regs.oldPC); break; case 0x03: FireException(regs, ExceptionCode::ReservedInstruction, 1, true); break;
case 0x04: mtc1(regs, instr); break; case 0x04: mtc1(regs, instr); break;
case 0x05: dmtc1(regs, instr); break; case 0x05: dmtc1(regs, instr); break;
case 0x06: ctc1(regs, instr); break; case 0x06: ctc1(regs, instr); break;
case 0x07: FireException(regs, ExceptionCode::ReservedInstruction, 1, regs.oldPC); break; case 0x07: FireException(regs, ExceptionCode::ReservedInstruction, 1, true); break;
case 0x08: case 0x08:
switch(mask_branch) { switch(mask_branch) {
case 0: cpu.b(regs, instr, !regs.cop1.fcr31.compare); break; case 0: cpu.b(regs, instr, !regs.cop1.fcr31.compare); break;
@@ -61,7 +61,7 @@ void Cop1::decode(Registers& regs, Interpreter& cpu, u32 instr) {
case 0x0E: ceilws(regs, instr); break; case 0x0E: ceilws(regs, instr); break;
case 0x0F: floorws(regs, instr); break; case 0x0F: floorws(regs, instr); break;
case 0x20: case 0x20:
FireException(regs, ExceptionCode::ReservedInstruction, 1, regs.oldPC); FireException(regs, ExceptionCode::ReservedInstruction, 1, true);
break; break;
case 0x21: cvtds(regs, instr); break; case 0x21: cvtds(regs, instr); break;
case 0x24: cvtws(regs, instr); break; case 0x24: cvtws(regs, instr); break;
@@ -105,7 +105,7 @@ void Cop1::decode(Registers& regs, Interpreter& cpu, u32 instr) {
case 0x0F: floorwd(regs, instr); break; case 0x0F: floorwd(regs, instr); break;
case 0x20: cvtsd(regs, instr); break; case 0x20: cvtsd(regs, instr); break;
case 0x21: case 0x21:
FireException(regs, ExceptionCode::ReservedInstruction, 1, regs.oldPC); FireException(regs, ExceptionCode::ReservedInstruction, 1, true);
break; break;
case 0x24: cvtwd(regs, instr); break; case 0x24: cvtwd(regs, instr); break;
case 0x25: cvtld(regs, instr); break; case 0x25: cvtld(regs, instr); break;
@@ -137,7 +137,7 @@ void Cop1::decode(Registers& regs, Interpreter& cpu, u32 instr) {
case 0x20: cvtsw(regs, instr); break; case 0x20: cvtsw(regs, instr); break;
case 0x21: cvtdw(regs, instr); break; case 0x21: cvtdw(regs, instr); break;
case 0x24: case 0x24:
FireException(regs, ExceptionCode::ReservedInstruction, 1, regs.oldPC); FireException(regs, ExceptionCode::ReservedInstruction, 1, true);
break; break;
default: util::panic("Unimplemented COP1 function W[{} {}] ({:08X}) ({:016X})", mask_fun >> 3, mask_fun & 7, instr, (u64)regs.oldPC); default: util::panic("Unimplemented COP1 function W[{} {}] ({:08X}) ({:016X})", mask_fun >> 3, mask_fun & 7, instr, (u64)regs.oldPC);
} }
@@ -151,10 +151,10 @@ void Cop1::decode(Registers& regs, Interpreter& cpu, u32 instr) {
case 0x20: cvtsl(regs, instr); break; case 0x20: cvtsl(regs, instr); break;
case 0x21: cvtdl(regs, instr); break; case 0x21: cvtdl(regs, instr); break;
case 0x24: case 0x24:
FireException(regs, ExceptionCode::ReservedInstruction, 1, regs.oldPC); FireException(regs, ExceptionCode::ReservedInstruction, 1, true);
break; break;
case 0x25: case 0x25:
FireException(regs, ExceptionCode::ReservedInstruction, 1, regs.oldPC); FireException(regs, ExceptionCode::ReservedInstruction, 1, true);
break; break;
default: util::panic("Unimplemented COP1 function L[{} {}] ({:08X}) ({:016X})", mask_fun >> 3, mask_fun & 7, instr, (u64)regs.oldPC); default: util::panic("Unimplemented COP1 function L[{} {}] ({:08X}) ({:016X})", mask_fun >> 3, mask_fun & 7, instr, (u64)regs.oldPC);
} }

View File

@@ -66,7 +66,7 @@ struct Cop1 {
void Reset(); void Reset();
void decode(Registers&, Interpreter&, u32); void decode(Registers&, Interpreter&, u32);
friend struct Interpreter; friend struct Interpreter;
private:
template <typename T> template <typename T>
inline void SetReg(Cop0& cop0, u8 index, T value) { inline void SetReg(Cop0& cop0, u8 index, T value) {
if constexpr(sizeof(T) == 4) { if constexpr(sizeof(T) == 4) {
@@ -134,7 +134,7 @@ private:
} }
return value; return value;
} }
private:
void absd(Registers&, u32 instr); void absd(Registers&, u32 instr);
void abss(Registers&, u32 instr); void abss(Registers&, u32 instr);
void absw(Registers&, u32 instr); void absw(Registers&, u32 instr);

View File

@@ -1,6 +1,6 @@
#pragma once #pragma once
#include <core/registers/Cop0.hpp> #include <backend/core/registers/Cop0.hpp>
#include <core/registers/Cop1.hpp> #include <backend/core/registers/Cop1.hpp>
namespace n64 { namespace n64 {
struct Registers { struct Registers {

View File

@@ -0,0 +1 @@
add_library(rsp decode.cpp instructions.cpp)

View File

@@ -0,0 +1,4 @@
file(GLOB SOURCES *.cpp)
file(GLOB HEADERS *.hpp)
add_library(frontend ${SOURCES} ${HEADERS})

View File

@@ -0,0 +1,4 @@
file(GLOB SOURCES *.cpp)
file(GLOB HEADERS *.hpp)
add_library(frontend-imgui ${SOURCES} ${HEADERS})

View File

@@ -1,13 +1,13 @@
#pragma once #pragma once
#include <parallel-rdp/ParallelRDPWrapper.hpp> #include <ParallelRDPWrapper.hpp>
#include <imgui.h> #include <imgui.h>
#include <imgui_impl_sdl.h> #include <imgui_impl_sdl.h>
#include <imgui_impl_vulkan.h> #include <imgui_impl_vulkan.h>
#include <SDL.h> #include <SDL2/SDL.h>
#include <Core.hpp> #include <backend/Core.hpp>
#include <vector> #include <vector>
#include <Settings.hpp> #include <frontend/imgui/Settings.hpp>
#include <GameList.hpp> #include <frontend/imgui/GameList.hpp>
struct DrawData { struct DrawData {
ImDrawData* first; ImDrawData* first;

View File

@@ -1,5 +1,5 @@
#include <frontend/App.hpp> #include <frontend/App.hpp>
#include <MupenMovie.hpp> #include <backend/MupenMovie.hpp>
#ifdef _WIN32 #ifdef _WIN32
#define main SDL_main #define main SDL_main