Dynarec + CMake restructure
This commit is contained in:
9
external/imgui/CMakeLists.txt
vendored
9
external/imgui/CMakeLists.txt
vendored
@@ -1,8 +1,3 @@
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
project(imgui)
|
||||
|
||||
find_package(SDL2 CONFIG REQUIRED)
|
||||
|
||||
add_library(imgui
|
||||
imgui/imgui_demo.cpp
|
||||
imgui/imgui_draw.cpp
|
||||
@@ -23,5 +18,5 @@ if(WIN32)
|
||||
add_compile_options(/EHa)
|
||||
endif()
|
||||
|
||||
target_include_directories(imgui PUBLIC ${SDL2_INCLUDE_DIR} ../parallel-rdp/parallel-rdp-standalone/vulkan-headers/include imgui imgui/backends)
|
||||
target_link_libraries(imgui PUBLIC SDL2::SDL2main SDL2::SDL2)
|
||||
target_include_directories(imgui PUBLIC ../parallel-rdp/parallel-rdp-standalone/volk
|
||||
../parallel-rdp/parallel-rdp-standalone/vulkan-headers/include)
|
||||
29
external/parallel-rdp/CMakeLists.txt
vendored
29
external/parallel-rdp/CMakeLists.txt
vendored
@@ -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)
|
||||
|
||||
find_package(SDL2 CONFIG REQUIRED)
|
||||
|
||||
add_library(parallel-rdp
|
||||
${parallel-rdp-cpp}
|
||||
ParallelRDPWrapper.cpp
|
||||
@@ -52,32 +47,12 @@ add_library(parallel-rdp
|
||||
target_compile_definitions(parallel-rdp PUBLIC GRANITE_VULKAN_MT)
|
||||
|
||||
target_include_directories(parallel-rdp PUBLIC
|
||||
${SDL2_INCLUDE_DIR}
|
||||
${Vulkan_INCLUDE_DIR}
|
||||
parallel-rdp-standalone/parallel-rdp
|
||||
parallel-rdp-standalone/volk
|
||||
parallel-rdp-standalone/spirv-cross
|
||||
parallel-rdp-standalone/vulkan
|
||||
parallel-rdp-standalone/vulkan-headers/include
|
||||
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)
|
||||
@@ -85,10 +60,8 @@ if(WIN32)
|
||||
add_compile_options(/EHa)
|
||||
endif()
|
||||
|
||||
target_link_libraries(parallel-rdp SDL2::SDL2main SDL2::SDL2)
|
||||
|
||||
if(WIN32)
|
||||
target_compile_definitions(parallel-rdp PUBLIC VK_USE_PLATFORM_WIN32_KHR)
|
||||
else()
|
||||
target_link_libraries(parallel-rdp dl)
|
||||
target_link_libraries(parallel-rdp PUBLIC dl)
|
||||
endif()
|
||||
2
external/parallel-rdp/ParallelRDPWrapper.cpp
vendored
2
external/parallel-rdp/ParallelRDPWrapper.cpp
vendored
@@ -5,7 +5,7 @@
|
||||
#include <log.hpp>
|
||||
#include <File.hpp>
|
||||
#include <SDL2/SDL_vulkan.h>
|
||||
#include <imgui/backends/imgui_impl_vulkan.h>
|
||||
#include <imgui_impl_vulkan.h>
|
||||
#include <imgui/Window.hpp>
|
||||
|
||||
using namespace Vulkan;
|
||||
|
||||
@@ -4,54 +4,56 @@ project(gadolinium)
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
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(fmt REQUIRED)
|
||||
find_package(nlohmann_json REQUIRED)
|
||||
|
||||
option(RAPIDJSON_BUILD_DOC "Build rapidjson documentation." OFF)
|
||||
option(RAPIDJSON_BUILD_EXAMPLES "Build rapidjson examples." OFF)
|
||||
option(RAPIDJSON_BUILD_TESTS "Build rapidjson perftests and unittests." OFF)
|
||||
|
||||
add_subdirectory(../external/parallel-rdp prdp)
|
||||
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
|
||||
include_directories(
|
||||
.
|
||||
backend
|
||||
backend/core
|
||||
backend/core/interpreter/
|
||||
backend/core/registers
|
||||
backend/core/mmio
|
||||
backend/core/rsp
|
||||
utils
|
||||
frontend
|
||||
frontend/imgui
|
||||
utils
|
||||
backend
|
||||
backend/core
|
||||
backend/core/mmio
|
||||
backend/core/registers
|
||||
backend/core/rsp
|
||||
../external
|
||||
../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/imgui/imgui
|
||||
../external/imgui/imgui/backends
|
||||
../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(REMOVE
|
||||
${PROJECT_BINARY_DIR}/resources/mario.png
|
||||
@@ -80,4 +82,5 @@ else()
|
||||
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)
|
||||
4
src/backend/CMakeLists.txt
Normal file
4
src/backend/CMakeLists.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
file(GLOB SOURCES *.cpp)
|
||||
file(GLOB HEADERS *.hpp)
|
||||
|
||||
add_library(backend ${SOURCES} ${HEADERS})
|
||||
@@ -45,7 +45,8 @@ void Core::Run(Window& window, float volumeL, float volumeR) {
|
||||
}
|
||||
|
||||
for(;cycles <= mmio.vi.cyclesPerHalfline; cycles++, frameCycles++) {
|
||||
CpuStep();
|
||||
int cpuCount = CpuStep();
|
||||
while(cpuCount--) {
|
||||
if (!mmio.rsp.spStatus.halt) {
|
||||
regs.steps++;
|
||||
if (regs.steps > 2) {
|
||||
@@ -58,6 +59,7 @@ void Core::Run(Window& window, float volumeL, float volumeR) {
|
||||
mmio.rsp.Step(regs, mem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mmio.ai.Step(mem, regs, 1, volumeL, volumeR);
|
||||
scheduler.tick(1, mem, regs);
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
#pragma once
|
||||
#include <SDL_events.h>
|
||||
#include <Interpreter.hpp>
|
||||
#include <Mem.hpp>
|
||||
#include <SDL2/SDL_events.h>
|
||||
#include <backend/core/Interpreter.hpp>
|
||||
#include <backend/core/Mem.hpp>
|
||||
#include <string>
|
||||
#include <Dynarec.hpp>
|
||||
#include <backend/core/Dynarec.hpp>
|
||||
#include <backend/core/registers/Registers.hpp>
|
||||
|
||||
struct Window;
|
||||
|
||||
@@ -29,10 +30,10 @@ struct Core {
|
||||
}
|
||||
}
|
||||
|
||||
void CpuStep() {
|
||||
int CpuStep() {
|
||||
switch(cpuType) {
|
||||
case CpuType::Dynarec: cpuDynarec.Step(mem, regs); break;
|
||||
case CpuType::Interpreter: cpuInterp.Step(mem, regs); break;
|
||||
case CpuType::Dynarec: return cpuDynarec.Step(mem, regs);
|
||||
case CpuType::Interpreter: cpuInterp.Step(mem, regs); return 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +49,7 @@ struct Core {
|
||||
Mem mem;
|
||||
CpuType cpuType = CpuType::Dynarec;
|
||||
Interpreter cpuInterp;
|
||||
Dynarec cpuDynarec;
|
||||
JIT::Dynarec cpuDynarec;
|
||||
Registers regs;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#pragma once
|
||||
#include <PIF.hpp>
|
||||
#include <backend/core/mmio/PIF.hpp>
|
||||
|
||||
void LoadTAS(const char* filename);
|
||||
void UnloadTAS();
|
||||
|
||||
4
src/backend/core/CMakeLists.txt
Normal file
4
src/backend/core/CMakeLists.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
file(GLOB SOURCES *.cpp)
|
||||
file(GLOB HEADERS *.hpp)
|
||||
|
||||
add_library(core ${SOURCES} ${HEADERS})
|
||||
@@ -1,11 +1,52 @@
|
||||
#include <Dynarec.hpp>
|
||||
#include <Registers.hpp>
|
||||
|
||||
namespace n64 {
|
||||
void Dynarec::Reset() {
|
||||
namespace n64::JIT {
|
||||
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);
|
||||
}
|
||||
|
||||
void Dynarec::Step(Mem &mem, Registers& regs) {
|
||||
code.ret();
|
||||
codeCache[start_addr >> 12][start_addr & 15] = block;
|
||||
block();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,114 +1,28 @@
|
||||
#pragma once
|
||||
#include <xbyak/xbyak.h>
|
||||
#include <Mem.hpp>
|
||||
#include <Registers.hpp>
|
||||
#include <backend/core/Mem.hpp>
|
||||
|
||||
namespace n64 {
|
||||
using Block = void (*)(Mem&, Registers&);
|
||||
namespace n64::JIT {
|
||||
using Fn = void (*)();
|
||||
|
||||
struct Dynarec {
|
||||
void Step(Mem&, Registers&);
|
||||
void Reset();
|
||||
private:
|
||||
Dynarec();
|
||||
int Step(Mem&, n64::Registers&);
|
||||
void Reset() {
|
||||
code.reset();
|
||||
}
|
||||
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;
|
||||
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);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ void Interpreter::Step(Mem& mem, Registers& regs) {
|
||||
regs.delaySlot = false;
|
||||
|
||||
if(ShouldServiceInterrupt(regs)) {
|
||||
FireException(regs, ExceptionCode::Interrupt, 0, regs.pc);
|
||||
FireException(regs, ExceptionCode::Interrupt, 0, false);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ private:
|
||||
friend struct Cop1;
|
||||
|
||||
void cop2Decode(Registers&, u32);
|
||||
void special(Registers&, Mem&, u32);
|
||||
void special(Registers&, u32);
|
||||
void regimm(Registers&, u32);
|
||||
void Exec(Registers&, Mem&, u32);
|
||||
void add(Registers&, u32);
|
||||
|
||||
@@ -93,7 +93,7 @@ u8 Mem::Read8(n64::Registers ®s, u64 vaddr, s64 pc) {
|
||||
u32 paddr = vaddr;
|
||||
if (!MapVAddr<tlb>(regs, LOAD, vaddr, paddr)) {
|
||||
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;
|
||||
@@ -144,7 +144,7 @@ u16 Mem::Read16(n64::Registers ®s, u64 vaddr, s64 pc) {
|
||||
u32 paddr = vaddr;
|
||||
if (!MapVAddr<tlb>(regs, LOAD, vaddr, paddr)) {
|
||||
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;
|
||||
@@ -190,7 +190,7 @@ u32 Mem::Read32(n64::Registers ®s, u64 vaddr, s64 pc) {
|
||||
u32 paddr = vaddr;
|
||||
if (!MapVAddr<tlb>(regs, LOAD, vaddr, paddr)) {
|
||||
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;
|
||||
@@ -230,7 +230,7 @@ u64 Mem::Read64(n64::Registers ®s, u64 vaddr, s64 pc) {
|
||||
u32 paddr = vaddr;
|
||||
if (!MapVAddr<tlb>(regs, LOAD, vaddr, paddr)) {
|
||||
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;
|
||||
@@ -284,7 +284,7 @@ void Mem::Write8(Registers& regs, u64 vaddr, u32 val, s64 pc) {
|
||||
u32 paddr = vaddr;
|
||||
if (!MapVAddr<tlb>(regs, LOAD, vaddr, paddr)) {
|
||||
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;
|
||||
@@ -343,7 +343,7 @@ void Mem::Write16(Registers& regs, u64 vaddr, u32 val, s64 pc) {
|
||||
u32 paddr = vaddr;
|
||||
if (!MapVAddr<tlb>(regs, STORE, vaddr, paddr)) {
|
||||
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;
|
||||
@@ -402,7 +402,7 @@ void Mem::Write32(Registers& regs, u64 vaddr, u32 val, s64 pc) {
|
||||
u32 paddr = vaddr;
|
||||
if(!MapVAddr<tlb>(regs, STORE, vaddr, paddr)) {
|
||||
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;
|
||||
@@ -453,7 +453,7 @@ void Mem::Write64(Registers& regs, u64 vaddr, u64 val, s64 pc) {
|
||||
u32 paddr = vaddr;
|
||||
if(!MapVAddr<tlb>(regs, STORE, vaddr, paddr)) {
|
||||
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;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#pragma once
|
||||
#include <common.hpp>
|
||||
#include <MemoryRegions.hpp>
|
||||
#include <core/MMIO.hpp>
|
||||
#include <backend/MemoryRegions.hpp>
|
||||
#include <backend/core/MMIO.hpp>
|
||||
#include <vector>
|
||||
#include <RomHelpers.hpp>
|
||||
#include <backend/RomHelpers.hpp>
|
||||
#include <log.hpp>
|
||||
|
||||
namespace n64 {
|
||||
|
||||
4
src/backend/core/dynarec/CMakeLists.txt
Normal file
4
src/backend/core/dynarec/CMakeLists.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
file(GLOB_RECURSE SOURCES *.cpp)
|
||||
file(GLOB_RECURSE HEADERS *.hpp)
|
||||
|
||||
add_library(dynarec ${SOURCES} ${HEADERS})
|
||||
27
src/backend/core/dynarec/cop/cop0decode.cpp
Normal file
27
src/backend/core/dynarec/cop/cop0decode.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
10
src/backend/core/dynarec/cop/cop0decode.hpp
Normal file
10
src/backend/core/dynarec/cop/cop0decode.hpp
Normal file
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
#include <common.hpp>
|
||||
|
||||
namespace n64 {
|
||||
struct Registers;
|
||||
}
|
||||
|
||||
namespace n64::JIT {
|
||||
void cop0Decode(n64::Registers& regs, u32 instr);
|
||||
}
|
||||
81
src/backend/core/dynarec/cop/cop0instructions.cpp
Normal file
81
src/backend/core/dynarec/cop/cop0instructions.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
13
src/backend/core/dynarec/cop/cop0instructions.hpp
Normal file
13
src/backend/core/dynarec/cop/cop0instructions.hpp
Normal 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&);
|
||||
}
|
||||
484
src/backend/core/dynarec/cop/cop1decode.cpp
Normal file
484
src/backend/core/dynarec/cop/cop1decode.cpp
Normal 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)®s.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)®s);
|
||||
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)®s);
|
||||
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;
|
||||
}
|
||||
}
|
||||
6
src/backend/core/dynarec/cop/cop1decode.hpp
Normal file
6
src/backend/core/dynarec/cop/cop1decode.hpp
Normal file
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
#include <dynarec/cop/cop1instructions.hpp>
|
||||
|
||||
namespace n64::JIT {
|
||||
bool cop1Decode(n64::Registers& regs, Dynarec& cpu, u32 instr);
|
||||
}
|
||||
590
src/backend/core/dynarec/cop/cop1instructions.cpp
Normal file
590
src/backend/core/dynarec/cop/cop1instructions.cpp
Normal 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 ®s, 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 ®s, 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 ®s, 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 ®s, 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 ®s, 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 ®s, 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 ®s, 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 ®s, 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 ®s, 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 ®s, u32 instr) {
|
||||
regs.cop1.SetCop1Reg<float>(
|
||||
regs.cop0,
|
||||
FD(instr),
|
||||
-regs.cop1.GetCop1Reg<float>(
|
||||
regs.cop0,
|
||||
FS(instr)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void negd(Registers ®s, u32 instr) {
|
||||
regs.cop1.SetCop1Reg<double>(
|
||||
regs.cop0,
|
||||
FD(instr),
|
||||
-regs.cop1.GetCop1Reg<double>(
|
||||
regs.cop0,
|
||||
FS(instr)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
void sqrts(Registers ®s, 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 ®s, 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)]);
|
||||
}
|
||||
}
|
||||
68
src/backend/core/dynarec/cop/cop1instructions.hpp
Normal file
68
src/backend/core/dynarec/cop/cop1instructions.hpp
Normal 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);
|
||||
}
|
||||
254
src/backend/core/dynarec/decode.cpp
Normal file
254
src/backend/core/dynarec/decode.cpp
Normal 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)®s.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)®s);
|
||||
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)®s);
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,82 +1,83 @@
|
||||
#include <core/Dynarec.hpp>
|
||||
#include <dynarec/instructions.hpp>
|
||||
#include <Registers.hpp>
|
||||
|
||||
#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_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)
|
||||
|
||||
namespace n64 {
|
||||
void Dynarec::add(Registers& regs, u32 instr) {
|
||||
namespace n64::JIT {
|
||||
void add(Registers& regs, u32 instr) {
|
||||
u32 rs = (s32)regs.gpr[RS(instr)];
|
||||
u32 rt = (s32)regs.gpr[RT(instr)];
|
||||
u32 result = rs + rt;
|
||||
if(check_signed_overflow(rs, rt, result)) {
|
||||
FireException(regs, ExceptionCode::Overflow, 0, regs.oldPC);
|
||||
FireException(regs, ExceptionCode::Overflow, 0, true);
|
||||
} else {
|
||||
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 rt = (s32)regs.gpr[RT(instr)];
|
||||
s32 result = rs + rt;
|
||||
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 imm = s32(s16(instr));
|
||||
u32 result = rs + imm;
|
||||
if(check_signed_overflow(rs, imm, result)) {
|
||||
FireException(regs, ExceptionCode::Overflow, 0, regs.oldPC);
|
||||
FireException(regs, ExceptionCode::Overflow, 0, true);
|
||||
} else {
|
||||
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)];
|
||||
s16 imm = (s16)(instr);
|
||||
s32 result = rs + imm;
|
||||
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 rt = regs.gpr[RT(instr)];
|
||||
u64 result = rt + rs;
|
||||
if(check_signed_overflow(rs, rt, result)) {
|
||||
FireException(regs, ExceptionCode::Overflow, 0, regs.oldPC);
|
||||
FireException(regs, ExceptionCode::Overflow, 0, true);
|
||||
} else {
|
||||
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 rt = regs.gpr[RT(instr)];
|
||||
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 rs = regs.gpr[RS(instr)];
|
||||
u64 result = imm + rs;
|
||||
if(check_signed_overflow(rs, imm, result)) {
|
||||
FireException(regs, ExceptionCode::Overflow, 0, regs.oldPC);
|
||||
FireException(regs, ExceptionCode::Overflow, 0, true);
|
||||
} else {
|
||||
regs.gpr[RT(instr)] = result;
|
||||
}
|
||||
}
|
||||
|
||||
void Dynarec::daddiu(Registers& regs, u32 instr) {
|
||||
void daddiu(Registers& regs, u32 instr) {
|
||||
s16 imm = (s16)(instr);
|
||||
s64 rs = regs.gpr[RS(instr)];
|
||||
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 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 divisor = regs.gpr[RT(instr)];
|
||||
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 divisor = regs.gpr[RT(instr)];
|
||||
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 divisor = regs.gpr[RT(instr)];
|
||||
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;
|
||||
if (cond) {
|
||||
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;
|
||||
if (cond) {
|
||||
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 address = regs.pc + offset;
|
||||
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;
|
||||
s64 offset = (s64)se_imm(instr) << 2;
|
||||
s64 address = regs.pc + offset;
|
||||
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 address = regs.pc + offset;
|
||||
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;
|
||||
s64 offset = (s64)se_imm(instr) << 2;
|
||||
s64 address = regs.pc + offset;
|
||||
branch_likely(regs, cond, address);
|
||||
}
|
||||
|
||||
void Dynarec::lui(Registers& regs, u32 instr) {
|
||||
void lui(Registers& regs, u32 instr) {
|
||||
s64 val = (s16)instr;
|
||||
val <<= 16;
|
||||
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;
|
||||
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;
|
||||
if (check_address_error(address, 0b1)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||
FireException(regs, ExceptionCode::AddressErrorLoad, 0, true);
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
u64 address = regs.gpr[RS(instr)] + offset;
|
||||
if (check_address_error(address, 0b11)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||
FireException(regs, ExceptionCode::AddressErrorLoad, 0, true);
|
||||
return;
|
||||
}
|
||||
|
||||
u32 physical;
|
||||
if (!MapVAddr(regs, LOAD, address, physical)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
|
||||
} else {
|
||||
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;
|
||||
u32 physical;
|
||||
if (!MapVAddr(regs, LOAD, address, physical)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
u32 paddr = 0;
|
||||
if(!MapVAddr(regs, LOAD, address, paddr)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
|
||||
} else {
|
||||
u32 shift = 8 * ((address ^ 0) & 3);
|
||||
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;
|
||||
u32 paddr = 0;
|
||||
if(!MapVAddr(regs, LOAD, address, paddr)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
|
||||
} else {
|
||||
u32 shift = 8 * ((address ^ 3) & 3);
|
||||
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;
|
||||
if (check_address_error(address, 0b111)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||
FireException(regs, ExceptionCode::AddressErrorLoad, 0, true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -282,12 +283,12 @@ void Dynarec::ld(Registers& regs, Mem& mem, u32 instr) {
|
||||
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;
|
||||
u32 paddr;
|
||||
if (!MapVAddr(regs, LOAD, address, paddr)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
u32 paddr = 0;
|
||||
if (!MapVAddr(regs, LOAD, address, paddr)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
|
||||
} else {
|
||||
s32 shift = 8 * ((address ^ 0) & 7);
|
||||
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;
|
||||
u32 paddr;
|
||||
if (!MapVAddr(regs, LOAD, address, paddr)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
|
||||
} else {
|
||||
s32 shift = 8 * ((address ^ 7) & 7);
|
||||
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;
|
||||
u8 value = mem.Read8(regs, address, regs.oldPC);
|
||||
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;
|
||||
if (check_address_error(address, 0b1)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||
FireException(regs, ExceptionCode::AddressErrorLoad, 0, true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -344,11 +345,11 @@ void Dynarec::lhu(Registers& regs, Mem& mem, u32 instr) {
|
||||
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;
|
||||
if (check_address_error(address, 0b11)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||
FireException(regs, ExceptionCode::AddressErrorLoad, 0, true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -356,16 +357,16 @@ void Dynarec::lwu(Registers& regs, Mem& mem, u32 instr) {
|
||||
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;
|
||||
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;
|
||||
if (check_address_error(address, 0b11)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
||||
FireException(regs, ExceptionCode::AddressErrorStore, 0, true);
|
||||
}
|
||||
|
||||
if(regs.cop0.llbit) {
|
||||
@@ -376,11 +377,11 @@ void Dynarec::sc(Registers& regs, Mem& mem, u32 instr) {
|
||||
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;
|
||||
if (check_address_error(address, 0b111)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
||||
FireException(regs, ExceptionCode::AddressErrorStore, 0, true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -392,65 +393,65 @@ void Dynarec::scd(Registers& regs, Mem& mem, u32 instr) {
|
||||
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;
|
||||
if (check_address_error(address, 0b1)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
||||
FireException(regs, ExceptionCode::AddressErrorStore, 0, true);
|
||||
return;
|
||||
}
|
||||
|
||||
u32 physical;
|
||||
if(!MapVAddr(regs, STORE, address, physical)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
|
||||
} else {
|
||||
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;
|
||||
u64 address = regs.gpr[RS(instr)] + offset;
|
||||
if (check_address_error(address, 0b11)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
||||
FireException(regs, ExceptionCode::AddressErrorStore, 0, true);
|
||||
return;
|
||||
}
|
||||
|
||||
u32 physical;
|
||||
if(!MapVAddr(regs, STORE, address, physical)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
|
||||
} else {
|
||||
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;
|
||||
if (check_address_error(address, 0b11)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
||||
FireException(regs, ExceptionCode::AddressErrorStore, 0, true);
|
||||
return;
|
||||
}
|
||||
|
||||
u32 physical;
|
||||
if(!MapVAddr(regs, STORE, address, physical)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
|
||||
} else {
|
||||
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;
|
||||
u32 paddr;
|
||||
if (!MapVAddr(regs, STORE, address, paddr)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
|
||||
} else {
|
||||
s32 shift = 8 * ((address ^ 0) & 7);
|
||||
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;
|
||||
u32 paddr;
|
||||
if (!MapVAddr(regs, STORE, address, paddr)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
|
||||
} else {
|
||||
s32 shift = 8 * ((address ^ 7) & 7);
|
||||
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;
|
||||
u32 paddr;
|
||||
if (!MapVAddr(regs, STORE, address, paddr)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
|
||||
} else {
|
||||
u32 shift = 8 * ((address ^ 0) & 3);
|
||||
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;
|
||||
u32 paddr;
|
||||
if (!MapVAddr(regs, STORE, address, paddr)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
|
||||
} else {
|
||||
u32 shift = 8 * ((address ^ 3) & 3);
|
||||
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 result = imm | regs.gpr[RS(instr)];
|
||||
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)];
|
||||
}
|
||||
|
||||
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)]);
|
||||
}
|
||||
|
||||
void Dynarec::j(Registers& regs, u32 instr) {
|
||||
void j(Registers& regs, u32 instr) {
|
||||
s32 target = (instr & 0x3ffffff) << 2;
|
||||
s64 address = (regs.oldPC & ~0xfffffff) | target;
|
||||
if (check_address_error(address, 0b11)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, ExceptionCode::DataBusError, 0, regs.oldPC);
|
||||
FireException(regs, ExceptionCode::DataBusError, 0, true);
|
||||
}
|
||||
|
||||
branch(regs, true, address);
|
||||
}
|
||||
|
||||
void Dynarec::jal(Registers& regs, u32 instr) {
|
||||
void jal(Registers& regs, u32 instr) {
|
||||
regs.gpr[31] = regs.nextPC;
|
||||
j(regs, instr);
|
||||
}
|
||||
|
||||
void Dynarec::jalr(Registers& regs, u32 instr) {
|
||||
void jalr(Registers& regs, u32 instr) {
|
||||
branch(regs, true, regs.gpr[RS(instr)]);
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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)];
|
||||
}
|
||||
|
||||
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)];
|
||||
}
|
||||
|
||||
void Dynarec::xori(Registers& regs, u32 instr) {
|
||||
void xori(Registers& regs, u32 instr) {
|
||||
s64 imm = (u16)instr;
|
||||
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)];
|
||||
}
|
||||
|
||||
void Dynarec::andi(Registers& regs, u32 instr) {
|
||||
void andi(Registers& regs, u32 instr) {
|
||||
s64 imm = (u16)instr;
|
||||
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)];
|
||||
}
|
||||
|
||||
void Dynarec::sll(Registers& regs, u32 instr) {
|
||||
void sll(Registers& regs, u32 instr) {
|
||||
u8 sa = ((instr >> 6) & 0x1f);
|
||||
s32 result = regs.gpr[RT(instr)] << sa;
|
||||
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;
|
||||
u32 rt = regs.gpr[RT(instr)];
|
||||
s32 result = rt << sa;
|
||||
regs.gpr[RD(instr)] = (s64)result;
|
||||
}
|
||||
|
||||
void Dynarec::dsll32(Registers& regs, u32 instr) {
|
||||
void dsll32(Registers& regs, u32 instr) {
|
||||
u8 sa = ((instr >> 6) & 0x1f);
|
||||
s64 result = regs.gpr[RT(instr)] << (sa + 32);
|
||||
regs.gpr[RD(instr)] = result;
|
||||
}
|
||||
|
||||
void Dynarec::dsll(Registers& regs, u32 instr) {
|
||||
void dsll(Registers& regs, u32 instr) {
|
||||
u8 sa = ((instr >> 6) & 0x1f);
|
||||
s64 result = regs.gpr[RT(instr)] << sa;
|
||||
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 result = regs.gpr[RT(instr)] << sa;
|
||||
regs.gpr[RD(instr)] = result;
|
||||
}
|
||||
|
||||
void Dynarec::srl(Registers& regs, u32 instr) {
|
||||
void srl(Registers& regs, u32 instr) {
|
||||
u32 rt = regs.gpr[RT(instr)];
|
||||
u8 sa = ((instr >> 6) & 0x1f);
|
||||
u32 result = rt >> sa;
|
||||
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);
|
||||
u32 rt = regs.gpr[RT(instr)];
|
||||
s32 result = rt >> sa;
|
||||
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)];
|
||||
u8 sa = ((instr >> 6) & 0x1f);
|
||||
u64 result = rt >> sa;
|
||||
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);
|
||||
u64 rt = regs.gpr[RT(instr)];
|
||||
u64 result = rt >> amount;
|
||||
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)];
|
||||
u8 sa = ((instr >> 6) & 0x1f);
|
||||
u64 result = rt >> (sa + 32);
|
||||
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)];
|
||||
u8 sa = ((instr >> 6) & 0x1f);
|
||||
s32 result = rt >> sa;
|
||||
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 rs = regs.gpr[RS(instr)];
|
||||
u8 sa = rs & 0x1f;
|
||||
@@ -655,14 +656,14 @@ void Dynarec::srav(Registers& regs, u32 instr) {
|
||||
regs.gpr[RD(instr)] = result;
|
||||
}
|
||||
|
||||
void Dynarec::dsra(Registers& regs, u32 instr) {
|
||||
void dsra(Registers& regs, u32 instr) {
|
||||
s64 rt = regs.gpr[RT(instr)];
|
||||
u8 sa = ((instr >> 6) & 0x1f);
|
||||
s64 result = rt >> sa;
|
||||
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 rs = regs.gpr[RS(instr)];
|
||||
s64 sa = rs & 63;
|
||||
@@ -670,14 +671,14 @@ void Dynarec::dsrav(Registers& regs, u32 instr) {
|
||||
regs.gpr[RD(instr)] = result;
|
||||
}
|
||||
|
||||
void Dynarec::dsra32(Registers& regs, u32 instr) {
|
||||
void dsra32(Registers& regs, u32 instr) {
|
||||
s64 rt = regs.gpr[RT(instr)];
|
||||
u8 sa = ((instr >> 6) & 0x1f);
|
||||
s64 result = rt >> (sa + 32);
|
||||
regs.gpr[RD(instr)] = result;
|
||||
}
|
||||
|
||||
void Dynarec::jr(Registers& regs, u32 instr) {
|
||||
void jr(Registers& regs, u32 instr) {
|
||||
s64 address = regs.gpr[RS(instr)];
|
||||
if (check_address_error(address, 0b11)) {
|
||||
HandleTLBException(regs, address);
|
||||
@@ -687,7 +688,7 @@ void Dynarec::jr(Registers& regs, u32 instr) {
|
||||
branch(regs, true, address);
|
||||
}
|
||||
|
||||
void Dynarec::dsub(Registers& regs, u32 instr) {
|
||||
void dsub(Registers& regs, u32 instr) {
|
||||
s64 rt = regs.gpr[RT(instr)];
|
||||
s64 rs = regs.gpr[RS(instr)];
|
||||
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 rs = regs.gpr[RS(instr)];
|
||||
u64 result = rs - rt;
|
||||
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 rs = regs.gpr[RS(instr)];
|
||||
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 rs = regs.gpr[RS(instr)];
|
||||
u32 result = rs - rt;
|
||||
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 rs = regs.gpr[RS(instr)];
|
||||
u128 result = (u128)rt * (u128)rs;
|
||||
@@ -731,7 +732,7 @@ void Dynarec::dmultu(Registers& regs, u32 instr) {
|
||||
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 rs = regs.gpr[RS(instr)];
|
||||
s128 result = (s128)rt * (s128)rs;
|
||||
@@ -739,7 +740,7 @@ void Dynarec::dmult(Registers& regs, u32 instr) {
|
||||
regs.hi = result >> 64;
|
||||
}
|
||||
|
||||
void Dynarec::multu(Registers& regs, u32 instr) {
|
||||
void multu(Registers& regs, u32 instr) {
|
||||
u32 rt = regs.gpr[RT(instr)];
|
||||
u32 rs = regs.gpr[RS(instr)];
|
||||
u64 result = (u64)rt * (u64)rs;
|
||||
@@ -747,7 +748,7 @@ void Dynarec::multu(Registers& regs, u32 instr) {
|
||||
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 rs = regs.gpr[RS(instr)];
|
||||
s64 result = (s64)rt * (s64)rs;
|
||||
@@ -755,51 +756,42 @@ void Dynarec::mult(Registers& regs, u32 instr) {
|
||||
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;
|
||||
}
|
||||
|
||||
void Dynarec::mfhi(Registers& regs, u32 instr) {
|
||||
void mfhi(Registers& regs, u32 instr) {
|
||||
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)];
|
||||
}
|
||||
|
||||
void Dynarec::mthi(Registers& regs, u32 instr) {
|
||||
void mthi(Registers& regs, u32 instr) {
|
||||
regs.hi = regs.gpr[RS(instr)];
|
||||
}
|
||||
|
||||
void Dynarec::trap(Registers& regs, bool cond) {
|
||||
void trap(Registers& regs, bool cond) {
|
||||
if(cond) {
|
||||
FireException(regs, ExceptionCode::Trap, 0, regs.oldPC);
|
||||
}
|
||||
}
|
||||
|
||||
void Dynarec::mtc2(Registers& regs, u32 instr) {
|
||||
cop2Latch = regs.gpr[RT(instr)];
|
||||
void mtc2(Dynarec& dyn, Registers& regs, u32 instr) {
|
||||
dyn.cop2Latch = regs.gpr[RT(instr)];
|
||||
}
|
||||
|
||||
void Dynarec::mfc2(Registers& regs, u32 instr) {
|
||||
s32 value = cop2Latch;
|
||||
void mfc2(Dynarec& dyn, Registers& regs, u32 instr) {
|
||||
s32 value = dyn.cop2Latch;
|
||||
regs.gpr[RT(instr)] = value;
|
||||
}
|
||||
|
||||
void Dynarec::dmtc2(Registers& regs, u32 instr) {
|
||||
cop2Latch = regs.gpr[RT(instr)];
|
||||
void dmtc2(Dynarec& dyn, Registers& regs, u32 instr) {
|
||||
dyn.cop2Latch = regs.gpr[RT(instr)];
|
||||
}
|
||||
|
||||
void Dynarec::dmfc2(Registers& regs, u32 instr) {
|
||||
regs.gpr[RT(instr)] = cop2Latch;
|
||||
void dmfc2(Dynarec& dyn, Registers& regs, u32 instr) {
|
||||
regs.gpr[RT(instr)] = dyn.cop2Latch;
|
||||
}
|
||||
|
||||
void Dynarec::ctc2(Registers& regs, u32) {
|
||||
|
||||
}
|
||||
|
||||
void Dynarec::cfc2(Registers& regs, u32) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
94
src/backend/core/dynarec/instructions.hpp
Normal file
94
src/backend/core/dynarec/instructions.hpp
Normal 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);
|
||||
}
|
||||
4
src/backend/core/interpreter/CMakeLists.txt
Normal file
4
src/backend/core/interpreter/CMakeLists.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
file(GLOB_RECURSE SOURCES *.cpp)
|
||||
file(GLOB_RECURSE HEADERS *.hpp)
|
||||
|
||||
add_library(interpreter ${SOURCES} ${HEADERS})
|
||||
@@ -26,7 +26,7 @@ inline int PushRoundingMode(const FCR31& fcr31) {
|
||||
if(isnanf(fs) || isnanf(ft)) { \
|
||||
regs.cop1.fcr31.flag_invalid_operation = true; \
|
||||
regs.cop1.fcr31.cause_invalid_operation = true; \
|
||||
FireException(regs, ExceptionCode::FloatingPointError, 1, regs.oldPC); \
|
||||
FireException(regs, ExceptionCode::FloatingPointError, 1, true); \
|
||||
return; \
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ inline int PushRoundingMode(const FCR31& fcr31) {
|
||||
if(isnan(fs) || isnan(ft)) { \
|
||||
regs.cop1.fcr31.flag_invalid_operation = true; \
|
||||
regs.cop1.fcr31.cause_invalid_operation = true; \
|
||||
FireException(regs, ExceptionCode::FloatingPointError, 1, regs.oldPC); \
|
||||
FireException(regs, ExceptionCode::FloatingPointError, 1, true); \
|
||||
return; \
|
||||
}
|
||||
#else
|
||||
@@ -42,7 +42,7 @@ inline int PushRoundingMode(const FCR31& fcr31) {
|
||||
if(isnanf(fs) || isnanf(ft)) { \
|
||||
regs.cop1.fcr31.flag_invalid_operation = true; \
|
||||
regs.cop1.fcr31.cause_invalid_operation = true; \
|
||||
FireException(regs, ExceptionCode::FloatingPointError, 1, regs.oldPC); \
|
||||
FireException(regs, ExceptionCode::FloatingPointError, 1, true); \
|
||||
return; \
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ inline int PushRoundingMode(const FCR31& fcr31) {
|
||||
if(isnan(fs) || isnan(ft)) { \
|
||||
regs.cop1.fcr31.flag_invalid_operation = true; \
|
||||
regs.cop1.fcr31.cause_invalid_operation = true; \
|
||||
FireException(regs, ExceptionCode::FloatingPointError, 1, regs.oldPC); \
|
||||
FireException(regs, ExceptionCode::FloatingPointError, 1, true); \
|
||||
return; \
|
||||
}
|
||||
#endif
|
||||
@@ -264,7 +264,7 @@ inline bool CalculateCondition(Registers& regs, T fs, T ft, CompConds cond) {
|
||||
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, regs.oldPC);
|
||||
FireException(regs, ExceptionCode::FloatingPointError, 1, true);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -469,19 +469,19 @@ void Cop1::floorwd(Registers& regs, u32 instr) {
|
||||
|
||||
void Cop1::lwc1(Registers& regs, Mem& mem, u32 instr) {
|
||||
if(!regs.cop0.status.cu1) {
|
||||
FireException(regs, ExceptionCode::CoprocessorUnusable, 1, regs.oldPC);
|
||||
FireException(regs, ExceptionCode::CoprocessorUnusable, 1, true);
|
||||
return;
|
||||
}
|
||||
|
||||
u64 addr = (s64)(s16)instr + regs.gpr[BASE(instr)];
|
||||
if(addr & 3) {
|
||||
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||
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, regs.oldPC);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
|
||||
} else {
|
||||
u32 data = mem.Read32<false>(regs, physical, regs.oldPC);
|
||||
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) {
|
||||
if(!regs.cop0.status.cu1) {
|
||||
FireException(regs, ExceptionCode::CoprocessorUnusable, 1, regs.oldPC);
|
||||
FireException(regs, ExceptionCode::CoprocessorUnusable, 1, true);
|
||||
return;
|
||||
}
|
||||
|
||||
u64 addr = (s64)(s16)instr + regs.gpr[BASE(instr)];
|
||||
if(addr & 3) {
|
||||
FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
||||
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);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
|
||||
} else {
|
||||
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) {
|
||||
if(!regs.cop0.status.cu1) {
|
||||
FireException(regs, ExceptionCode::CoprocessorUnusable, 1, regs.oldPC);
|
||||
FireException(regs, ExceptionCode::CoprocessorUnusable, 1, true);
|
||||
return;
|
||||
}
|
||||
|
||||
u64 addr = (s64)(s16)instr + regs.gpr[BASE(instr)];
|
||||
if(addr & 7) {
|
||||
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||
FireException(regs, ExceptionCode::AddressErrorLoad, 0, true);
|
||||
}
|
||||
|
||||
u32 physical;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#include <log.hpp>
|
||||
|
||||
namespace n64 {
|
||||
void Interpreter::special(Registers& regs, Mem& mem, u32 instr) {
|
||||
void Interpreter::special(Registers& regs, u32 instr) {
|
||||
u8 mask = (instr & 0x3F);
|
||||
// 00rr_rccc
|
||||
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 0x08: jr(regs, instr); break;
|
||||
case 0x09: jalr(regs, instr); break;
|
||||
case 0x0C: FireException(regs, ExceptionCode::Syscall, 0, regs.oldPC); break;
|
||||
case 0x0D: FireException(regs, ExceptionCode::Breakpoint, 0, regs.oldPC); break;
|
||||
case 0x0C: FireException(regs, ExceptionCode::Syscall, 0, true); break;
|
||||
case 0x0D: FireException(regs, ExceptionCode::Breakpoint, 0, true); break;
|
||||
case 0x0F: break; // SYNC
|
||||
case 0x10: mfhi(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) {
|
||||
if(!regs.cop0.status.cu2) {
|
||||
FireException(regs, ExceptionCode::CoprocessorUnusable, 2, regs.oldPC);
|
||||
FireException(regs, ExceptionCode::CoprocessorUnusable, 2, true);
|
||||
return;
|
||||
}
|
||||
switch(RS(instr)) {
|
||||
@@ -103,7 +103,7 @@ void Interpreter::cop2Decode(Registers& regs, u32 instr) {
|
||||
case 0x05: dmtc2(regs, instr); break;
|
||||
case 0x06: ctc2(regs, instr); break;
|
||||
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;
|
||||
// 00rr_rccc
|
||||
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 0x02: j(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 0x1A: ldl(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 0x21: lh(regs, mem, instr); break;
|
||||
case 0x22: lwl(regs, mem, instr); break;
|
||||
|
||||
@@ -11,7 +11,7 @@ void Interpreter::add(Registers& regs, u32 instr) {
|
||||
u32 rt = (s32)regs.gpr[RT(instr)];
|
||||
u32 result = rs + rt;
|
||||
if(check_signed_overflow(rs, rt, result)) {
|
||||
FireException(regs, ExceptionCode::Overflow, 0, regs.oldPC);
|
||||
FireException(regs, ExceptionCode::Overflow, 0, true);
|
||||
} else {
|
||||
regs.gpr[RD(instr)] = s32(result);
|
||||
}
|
||||
@@ -29,7 +29,7 @@ void Interpreter::addi(Registers& regs, u32 instr) {
|
||||
u32 imm = s32(s16(instr));
|
||||
u32 result = rs + imm;
|
||||
if(check_signed_overflow(rs, imm, result)) {
|
||||
FireException(regs, ExceptionCode::Overflow, 0, regs.oldPC);
|
||||
FireException(regs, ExceptionCode::Overflow, 0, true);
|
||||
} else {
|
||||
regs.gpr[RT(instr)] = s32(result);
|
||||
}
|
||||
@@ -47,7 +47,7 @@ void Interpreter::dadd(Registers& regs, u32 instr) {
|
||||
u64 rt = regs.gpr[RT(instr)];
|
||||
u64 result = rt + rs;
|
||||
if(check_signed_overflow(rs, rt, result)) {
|
||||
FireException(regs, ExceptionCode::Overflow, 0, regs.oldPC);
|
||||
FireException(regs, ExceptionCode::Overflow, 0, true);
|
||||
} else {
|
||||
regs.gpr[RD(instr)] = result;
|
||||
}
|
||||
@@ -64,7 +64,7 @@ void Interpreter::daddi(Registers& regs, u32 instr) {
|
||||
u64 rs = regs.gpr[RS(instr)];
|
||||
u64 result = imm + rs;
|
||||
if(check_signed_overflow(rs, imm, result)) {
|
||||
FireException(regs, ExceptionCode::Overflow, 0, regs.oldPC);
|
||||
FireException(regs, ExceptionCode::Overflow, 0, true);
|
||||
} else {
|
||||
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;
|
||||
if (check_address_error(address, 0b1)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||
FireException(regs, ExceptionCode::AddressErrorLoad, 0, true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -213,14 +213,14 @@ void Interpreter::lw(Registers& regs, Mem& mem, u32 instr) {
|
||||
u64 address = regs.gpr[RS(instr)] + offset;
|
||||
if (check_address_error(address, 0b11)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||
FireException(regs, ExceptionCode::AddressErrorLoad, 0, true);
|
||||
return;
|
||||
}
|
||||
|
||||
u32 physical;
|
||||
if (!MapVAddr(regs, LOAD, address, physical)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
|
||||
} else {
|
||||
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;
|
||||
if (!MapVAddr(regs, LOAD, address, physical)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
|
||||
} else {
|
||||
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;
|
||||
if(!MapVAddr(regs, LOAD, address, paddr)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
|
||||
} else {
|
||||
u32 shift = 8 * ((address ^ 0) & 3);
|
||||
u32 mask = 0xFFFFFFFF << shift;
|
||||
@@ -260,7 +260,7 @@ void Interpreter::lwr(Registers& regs, Mem& mem, u32 instr) {
|
||||
u32 paddr = 0;
|
||||
if(!MapVAddr(regs, LOAD, address, paddr)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
|
||||
} else {
|
||||
u32 shift = 8 * ((address ^ 3) & 3);
|
||||
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;
|
||||
if (check_address_error(address, 0b111)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||
FireException(regs, ExceptionCode::AddressErrorLoad, 0, true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -287,7 +287,7 @@ void Interpreter::lld(Registers& regs, Mem& mem, u32 instr) {
|
||||
u32 paddr;
|
||||
if (!MapVAddr(regs, LOAD, address, paddr)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
|
||||
} else {
|
||||
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;
|
||||
if (!MapVAddr(regs, LOAD, address, paddr)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
|
||||
} else {
|
||||
s32 shift = 8 * ((address ^ 0) & 7);
|
||||
u64 mask = 0xFFFFFFFFFFFFFFFF << shift;
|
||||
@@ -316,7 +316,7 @@ void Interpreter::ldr(Registers& regs, Mem& mem, u32 instr) {
|
||||
u32 paddr;
|
||||
if (!MapVAddr(regs, LOAD, address, paddr)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true);
|
||||
} else {
|
||||
s32 shift = 8 * ((address ^ 7) & 7);
|
||||
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;
|
||||
if (check_address_error(address, 0b1)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||
FireException(regs, ExceptionCode::AddressErrorLoad, 0, true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -348,7 +348,7 @@ void Interpreter::lwu(Registers& regs, Mem& mem, u32 instr) {
|
||||
s64 address = regs.gpr[RS(instr)] + (s16)instr;
|
||||
if (check_address_error(address, 0b11)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||
FireException(regs, ExceptionCode::AddressErrorLoad, 0, true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -365,7 +365,7 @@ void Interpreter::sc(Registers& regs, Mem& mem, u32 instr) {
|
||||
s64 address = regs.gpr[RS(instr)] + (s16)instr;
|
||||
if (check_address_error(address, 0b11)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
||||
FireException(regs, ExceptionCode::AddressErrorStore, 0, true);
|
||||
}
|
||||
|
||||
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;
|
||||
if (check_address_error(address, 0b111)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
||||
FireException(regs, ExceptionCode::AddressErrorStore, 0, true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -396,14 +396,14 @@ void Interpreter::sh(Registers& regs, Mem& mem, u32 instr) {
|
||||
s64 address = regs.gpr[RS(instr)] + (s16)instr;
|
||||
if (check_address_error(address, 0b1)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
||||
FireException(regs, ExceptionCode::AddressErrorStore, 0, true);
|
||||
return;
|
||||
}
|
||||
|
||||
u32 physical;
|
||||
if(!MapVAddr(regs, STORE, address, physical)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
|
||||
} else {
|
||||
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;
|
||||
if (check_address_error(address, 0b11)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
||||
FireException(regs, ExceptionCode::AddressErrorStore, 0, true);
|
||||
return;
|
||||
}
|
||||
|
||||
u32 physical;
|
||||
if(!MapVAddr(regs, STORE, address, physical)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
|
||||
} else {
|
||||
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;
|
||||
if (check_address_error(address, 0b11)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
||||
FireException(regs, ExceptionCode::AddressErrorStore, 0, true);
|
||||
return;
|
||||
}
|
||||
|
||||
u32 physical;
|
||||
if(!MapVAddr(regs, STORE, address, physical)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
|
||||
} else {
|
||||
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;
|
||||
if (!MapVAddr(regs, STORE, address, paddr)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
|
||||
} else {
|
||||
s32 shift = 8 * ((address ^ 0) & 7);
|
||||
u64 mask = 0xFFFFFFFFFFFFFFFF >> shift;
|
||||
@@ -465,7 +465,7 @@ void Interpreter::sdr(Registers& regs, Mem& mem, u32 instr) {
|
||||
u32 paddr;
|
||||
if (!MapVAddr(regs, STORE, address, paddr)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
|
||||
} else {
|
||||
s32 shift = 8 * ((address ^ 7) & 7);
|
||||
u64 mask = 0xFFFFFFFFFFFFFFFF << shift;
|
||||
@@ -480,7 +480,7 @@ void Interpreter::swl(Registers& regs, Mem& mem, u32 instr) {
|
||||
u32 paddr;
|
||||
if (!MapVAddr(regs, STORE, address, paddr)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
|
||||
} else {
|
||||
u32 shift = 8 * ((address ^ 0) & 3);
|
||||
u32 mask = 0xFFFFFFFF >> shift;
|
||||
@@ -495,7 +495,7 @@ void Interpreter::swr(Registers& regs, Mem& mem, u32 instr) {
|
||||
u32 paddr;
|
||||
if (!MapVAddr(regs, STORE, address, paddr)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true);
|
||||
} else {
|
||||
u32 shift = 8 * ((address ^ 3) & 3);
|
||||
u32 mask = 0xFFFFFFFF << shift;
|
||||
@@ -524,7 +524,7 @@ void Interpreter::j(Registers& regs, u32 instr) {
|
||||
s64 address = (regs.oldPC & ~0xfffffff) | target;
|
||||
if (check_address_error(address, 0b11)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, ExceptionCode::DataBusError, 0, regs.oldPC);
|
||||
FireException(regs, ExceptionCode::DataBusError, 0, true);
|
||||
}
|
||||
|
||||
branch(regs, true, address);
|
||||
|
||||
4
src/backend/core/mmio/CMakeLists.txt
Normal file
4
src/backend/core/mmio/CMakeLists.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
file(GLOB SOURCES *.cpp)
|
||||
file(GLOB HEADERS *.hpp)
|
||||
|
||||
add_library(mmio ${SOURCES} ${HEADERS})
|
||||
4
src/backend/core/registers/CMakeLists.txt
Normal file
4
src/backend/core/registers/CMakeLists.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
file(GLOB SOURCES *.cpp)
|
||||
file(GLOB HEADERS *.cpp)
|
||||
|
||||
add_library(registers ${SOURCES} ${HEADERS})
|
||||
@@ -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;
|
||||
s64 pc = useOldPC ? regs.oldPC : regs.pc;
|
||||
|
||||
if(!regs.cop0.status.exl) {
|
||||
if(regs.prevDelaySlot) {
|
||||
|
||||
@@ -177,7 +177,7 @@ enum class ExceptionCode : u8 {
|
||||
Watch = 23
|
||||
};
|
||||
|
||||
void FireException(Registers& regs, ExceptionCode code, int cop, s64 pc);
|
||||
void FireException(Registers& regs, ExceptionCode code, int cop, bool useOldPC);
|
||||
|
||||
union Cop0Context {
|
||||
u64 raw;
|
||||
@@ -235,9 +235,6 @@ struct Cop0 {
|
||||
TLBError tlbError = NONE;
|
||||
s64 openbus{};
|
||||
void decode(Registers&, Mem&, u32);
|
||||
private:
|
||||
inline u32 GetWired() { return wired & 0x3F; }
|
||||
inline u32 GetCount() { return u32(u64(count >> 1)); }
|
||||
inline u32 GetRandom() {
|
||||
int val = rand();
|
||||
int wired = GetWired();
|
||||
@@ -253,16 +250,19 @@ private:
|
||||
val = (val % upper) + lower;
|
||||
return val;
|
||||
}
|
||||
private:
|
||||
inline u32 GetWired() { return wired & 0x3F; }
|
||||
inline u32 GetCount() { return u32(u64(count >> 1)); }
|
||||
|
||||
void mtc0(Registers&, u32);
|
||||
void dmtc0(Registers&, u32);
|
||||
void mfc0(Registers&, u32);
|
||||
void dmfc0(Registers&, u32);
|
||||
void eret(Registers&);
|
||||
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(Registers&);
|
||||
void tlbw(int, Registers&);
|
||||
void tlbp(Registers&);
|
||||
void tlbr(n64::Registers&);
|
||||
void tlbw(int, n64::Registers&);
|
||||
void tlbp(n64::Registers&);
|
||||
};
|
||||
|
||||
struct Registers;
|
||||
|
||||
@@ -16,7 +16,7 @@ void Cop1::Reset() {
|
||||
|
||||
void Cop1::decode(Registers& regs, Interpreter& cpu, u32 instr) {
|
||||
if(!regs.cop0.status.cu1) {
|
||||
FireException(regs, ExceptionCode::CoprocessorUnusable, 1, regs.oldPC);
|
||||
FireException(regs, ExceptionCode::CoprocessorUnusable, 1, true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -28,11 +28,11 @@ void Cop1::decode(Registers& regs, Interpreter& cpu, u32 instr) {
|
||||
case 0x00: mfc1(regs, instr); break;
|
||||
case 0x01: dmfc1(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 0x05: dmtc1(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:
|
||||
switch(mask_branch) {
|
||||
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 0x0F: floorws(regs, instr); break;
|
||||
case 0x20:
|
||||
FireException(regs, ExceptionCode::ReservedInstruction, 1, regs.oldPC);
|
||||
FireException(regs, ExceptionCode::ReservedInstruction, 1, true);
|
||||
break;
|
||||
case 0x21: cvtds(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 0x20: cvtsd(regs, instr); break;
|
||||
case 0x21:
|
||||
FireException(regs, ExceptionCode::ReservedInstruction, 1, regs.oldPC);
|
||||
FireException(regs, ExceptionCode::ReservedInstruction, 1, true);
|
||||
break;
|
||||
case 0x24: cvtwd(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 0x21: cvtdw(regs, instr); break;
|
||||
case 0x24:
|
||||
FireException(regs, ExceptionCode::ReservedInstruction, 1, regs.oldPC);
|
||||
FireException(regs, ExceptionCode::ReservedInstruction, 1, true);
|
||||
break;
|
||||
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 0x21: cvtdl(regs, instr); break;
|
||||
case 0x24:
|
||||
FireException(regs, ExceptionCode::ReservedInstruction, 1, regs.oldPC);
|
||||
FireException(regs, ExceptionCode::ReservedInstruction, 1, true);
|
||||
break;
|
||||
case 0x25:
|
||||
FireException(regs, ExceptionCode::ReservedInstruction, 1, regs.oldPC);
|
||||
FireException(regs, ExceptionCode::ReservedInstruction, 1, true);
|
||||
break;
|
||||
default: util::panic("Unimplemented COP1 function L[{} {}] ({:08X}) ({:016X})", mask_fun >> 3, mask_fun & 7, instr, (u64)regs.oldPC);
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ struct Cop1 {
|
||||
void Reset();
|
||||
void decode(Registers&, Interpreter&, u32);
|
||||
friend struct Interpreter;
|
||||
private:
|
||||
|
||||
template <typename T>
|
||||
inline void SetReg(Cop0& cop0, u8 index, T value) {
|
||||
if constexpr(sizeof(T) == 4) {
|
||||
@@ -134,7 +134,7 @@ private:
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private:
|
||||
void absd(Registers&, u32 instr);
|
||||
void abss(Registers&, u32 instr);
|
||||
void absw(Registers&, u32 instr);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
#include <core/registers/Cop0.hpp>
|
||||
#include <core/registers/Cop1.hpp>
|
||||
#include <backend/core/registers/Cop0.hpp>
|
||||
#include <backend/core/registers/Cop1.hpp>
|
||||
|
||||
namespace n64 {
|
||||
struct Registers {
|
||||
|
||||
1
src/backend/core/rsp/CMakeLists.txt
Normal file
1
src/backend/core/rsp/CMakeLists.txt
Normal file
@@ -0,0 +1 @@
|
||||
add_library(rsp decode.cpp instructions.cpp)
|
||||
4
src/frontend/CMakeLists.txt
Normal file
4
src/frontend/CMakeLists.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
file(GLOB SOURCES *.cpp)
|
||||
file(GLOB HEADERS *.hpp)
|
||||
|
||||
add_library(frontend ${SOURCES} ${HEADERS})
|
||||
4
src/frontend/imgui/CMakeLists.txt
Normal file
4
src/frontend/imgui/CMakeLists.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
file(GLOB SOURCES *.cpp)
|
||||
file(GLOB HEADERS *.hpp)
|
||||
|
||||
add_library(frontend-imgui ${SOURCES} ${HEADERS})
|
||||
@@ -1,13 +1,13 @@
|
||||
#pragma once
|
||||
#include <parallel-rdp/ParallelRDPWrapper.hpp>
|
||||
#include <ParallelRDPWrapper.hpp>
|
||||
#include <imgui.h>
|
||||
#include <imgui_impl_sdl.h>
|
||||
#include <imgui_impl_vulkan.h>
|
||||
#include <SDL.h>
|
||||
#include <Core.hpp>
|
||||
#include <SDL2/SDL.h>
|
||||
#include <backend/Core.hpp>
|
||||
#include <vector>
|
||||
#include <Settings.hpp>
|
||||
#include <GameList.hpp>
|
||||
#include <frontend/imgui/Settings.hpp>
|
||||
#include <frontend/imgui/GameList.hpp>
|
||||
|
||||
struct DrawData {
|
||||
ImDrawData* first;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include <frontend/App.hpp>
|
||||
#include <MupenMovie.hpp>
|
||||
#include <backend/MupenMovie.hpp>
|
||||
|
||||
#ifdef _WIN32
|
||||
#define main SDL_main
|
||||
|
||||
Reference in New Issue
Block a user