Start implementing some instructions
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
#include <ParallelRDPWrapper.hpp>
|
||||
|
||||
namespace n64 {
|
||||
Core::Core(ParallelRDP& parallel) : cpu(std::make_unique<Interpreter>(parallel)) {}
|
||||
Core::Core(ParallelRDP& parallel) : cpu(std::make_unique<JIT>(parallel)) {}
|
||||
|
||||
void Core::Stop() {
|
||||
render = false;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include <backend/core/Interpreter.hpp>
|
||||
#include <backend/core/JIT.hpp>
|
||||
#include <string>
|
||||
|
||||
struct Window;
|
||||
|
||||
@@ -2,10 +2,11 @@ file(GLOB SOURCES *.cpp)
|
||||
file(GLOB HEADERS *.hpp)
|
||||
|
||||
add_subdirectory(interpreter)
|
||||
add_subdirectory(jit)
|
||||
add_subdirectory(mem)
|
||||
add_subdirectory(mmio)
|
||||
add_subdirectory(registers)
|
||||
add_subdirectory(rsp)
|
||||
|
||||
add_library(core ${SOURCES} ${HEADERS})
|
||||
target_link_libraries(core PRIVATE interpreter mem mmio unarr registers rsp)
|
||||
target_link_libraries(core PRIVATE jit interpreter mem mmio unarr registers rsp)
|
||||
@@ -2,7 +2,10 @@
|
||||
#include <jit/helpers.hpp>
|
||||
|
||||
namespace n64 {
|
||||
JIT::JIT(ParallelRDP& parallel) : mem(regs, parallel) { }
|
||||
JIT::JIT(ParallelRDP& parallel) : mem(regs, parallel) {
|
||||
regs.gpr[0] = 0;
|
||||
regs.gprIsConstant[0] = true;
|
||||
}
|
||||
|
||||
bool JIT::ShouldServiceInterrupt() {
|
||||
bool interrupts_pending = (regs.cop0.status.im & regs.cop0.cause.interruptPending) != 0;
|
||||
@@ -24,46 +27,40 @@ void JIT::CheckCompareInterrupt() {
|
||||
}
|
||||
|
||||
int JIT::Step() {
|
||||
CheckCompareInterrupt();
|
||||
u32 instruction;
|
||||
s64 pc = regs.pc;
|
||||
|
||||
regs.prevDelaySlot = regs.delaySlot;
|
||||
regs.delaySlot = false;
|
||||
do {
|
||||
//CheckCompareInterrupt();
|
||||
|
||||
if (check_address_error(0b11, u64(regs.pc))) [[unlikely]] {
|
||||
regs.cop0.HandleTLBException(regs.pc);
|
||||
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.pc);
|
||||
//regs.prevDelaySlot = regs.delaySlot;
|
||||
//regs.delaySlot = false;
|
||||
|
||||
/*if (check_address_error(0b11, u64(pc))) [[unlikely]] {
|
||||
regs.cop0.HandleTLBException(pc);
|
||||
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, pc);
|
||||
return 1;
|
||||
}
|
||||
}*/
|
||||
|
||||
u32 paddr = 0;
|
||||
if (!regs.cop0.MapVAddr(Cop0::LOAD, regs.pc, paddr)) {
|
||||
regs.cop0.HandleTLBException(regs.pc);
|
||||
regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.pc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
u32 instruction = mem.Read<u32>(regs, paddr);
|
||||
while (!InstrEndsBlock(instr)) {
|
||||
|
||||
if (!regs.cop0.MapVAddr(Cop0::LOAD, regs.pc, paddr)) {
|
||||
regs.cop0.HandleTLBException(regs.pc);
|
||||
regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.pc);
|
||||
return 1;
|
||||
if (!regs.cop0.MapVAddr(Cop0::LOAD, pc, paddr)) {
|
||||
/*regs.cop0.HandleTLBException(pc);
|
||||
regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, pc);
|
||||
return 1;*/
|
||||
Util::panic("[JIT]: Unhandled exception TLB exception {} when retrieving PC physical address!", regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD));
|
||||
}
|
||||
|
||||
instruction = mem.Read<u32>(regs, paddr);
|
||||
}
|
||||
|
||||
if(ShouldServiceInterrupt()) {
|
||||
/*if(ShouldServiceInterrupt()) {
|
||||
regs.cop0.FireException(ExceptionCode::Interrupt, 0, regs.pc);
|
||||
return 1;
|
||||
}
|
||||
}*/
|
||||
|
||||
regs.oldPC = regs.pc;
|
||||
regs.pc = regs.nextPC;
|
||||
regs.nextPC += 4;
|
||||
pc += 4;
|
||||
|
||||
Exec(instruction);
|
||||
//Exec(instruction);
|
||||
} while (!InstrEndsBlock(instruction));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -32,10 +32,10 @@ private:
|
||||
std::vector<u8> Serialize() override;
|
||||
void Deserialize(const std::vector<u8>&) override;
|
||||
|
||||
void Emit(u32);
|
||||
void cop2Decode(u32);
|
||||
void special(u32);
|
||||
void regimm(u32);
|
||||
void Exec(u32);
|
||||
void add(u32);
|
||||
void addu(u32);
|
||||
void addi(u32);
|
||||
|
||||
4
src/backend/core/jit/CMakeLists.txt
Normal file
4
src/backend/core/jit/CMakeLists.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
file(GLOB_RECURSE SOURCES *.cpp)
|
||||
file(GLOB_RECURSE HEADERS *.hpp)
|
||||
|
||||
add_library(jit ${SOURCES} ${HEADERS})
|
||||
@@ -17,7 +17,8 @@ static inline bool InstrEndsBlock(u32 instr) {
|
||||
case SPECIAL: return SpecialEndsBlock(instr);
|
||||
case REGIMM: case J: case JAL: case BEQ:
|
||||
case BNE: case BLEZ: case BGTZ: case BEQL:
|
||||
case BNEL: case BLEZL: case BGTZL: return true:
|
||||
case BNEL: case BLEZL: case BGTZL: return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
317
src/backend/core/jit/instructions.cpp
Normal file
317
src/backend/core/jit/instructions.cpp
Normal file
@@ -0,0 +1,317 @@
|
||||
#include <JIT.hpp>
|
||||
|
||||
#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 JIT::lui(u32 instr) {
|
||||
u64 val = s64((s16)instr);
|
||||
val <<= 16;
|
||||
if (RT(instr) != 0) [[likely]] {
|
||||
regs.gpr[RT(instr)] = val;
|
||||
regs.gprIsConstant[RT(instr)] = true;
|
||||
}
|
||||
}
|
||||
|
||||
void JIT::add(u32 instr) {
|
||||
if(regs.IsRegConstant(RS(instr), RT(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)) {
|
||||
//regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
|
||||
Util::panic("[JIT]: Unhandled Overflow exception in ADD!");
|
||||
}
|
||||
|
||||
if (RD(instr) != 0) [[likely]] {
|
||||
regs.gpr[RD(instr)] = s32(result);
|
||||
regs.gprIsConstant[RD(instr)] = true;
|
||||
}
|
||||
} else {
|
||||
Util::panic("[JIT]: Implement non constant ADD");
|
||||
}
|
||||
}
|
||||
|
||||
void JIT::addu(u32 instr) {
|
||||
if(regs.IsRegConstant(RS(instr), RT(instr))) {
|
||||
s32 rs = (s32) regs.gpr[RS(instr)];
|
||||
s32 rt = (s32) regs.gpr[RT(instr)];
|
||||
s32 result = rs + rt;
|
||||
|
||||
if (RD(instr) != 0) [[likely]] {
|
||||
regs.gpr[RD(instr)] = result;
|
||||
regs.gprIsConstant[RD(instr)] = true;
|
||||
}
|
||||
} else {
|
||||
Util::panic("[JIT]: Implement non constant ADDI");
|
||||
}
|
||||
}
|
||||
|
||||
void JIT::addi(u32 instr) {
|
||||
if(regs.IsRegConstant(RS(instr))) {
|
||||
u32 rs = regs.gpr[RS(instr)];
|
||||
u32 imm = s32(s16(instr));
|
||||
u32 result = rs + imm;
|
||||
if(check_signed_overflow(rs, imm, result)) {
|
||||
Util::panic("[JIT]: Unhandled Overflow exception in ADDI!");
|
||||
} else {
|
||||
if (RT(instr) != 0) [[likely]] {
|
||||
regs.gpr[RT(instr)] = s32(result);
|
||||
regs.gprIsConstant[RT(instr)] = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Util::panic("[JIT]: Implement non constant ADDI!");
|
||||
}
|
||||
}
|
||||
|
||||
void JIT::addiu(u32 instr) {
|
||||
if(regs.IsRegConstant(RS(instr))) {
|
||||
u32 rs = regs.gpr[RS(instr)];
|
||||
u32 imm = s32(s16(instr));
|
||||
u32 result = rs + imm;
|
||||
|
||||
if (RT(instr) != 0) [[likely]] {
|
||||
regs.gpr[RT(instr)] = s32(result);
|
||||
regs.gprIsConstant[RT(instr)] = true;
|
||||
}
|
||||
} else {
|
||||
Util::panic("[JIT]: Implement non constant ADDIU!");
|
||||
}
|
||||
}
|
||||
|
||||
void JIT::andi(u32 instr) {
|
||||
s64 imm = (u16)instr;
|
||||
if(regs.IsRegConstant(RS(instr))) {
|
||||
if (RT(instr) != 0) [[likely]] {
|
||||
regs.gpr[RT(instr)] = regs.gpr[RS(instr)] & imm;
|
||||
regs.gprIsConstant[RT(instr)] = true;
|
||||
}
|
||||
} else {
|
||||
Util::panic("[JIT]: Implement non constant ANDI!");
|
||||
}
|
||||
}
|
||||
|
||||
void JIT::and_(u32 instr) {
|
||||
if(regs.IsRegConstant(RS(instr), RT(instr))) {
|
||||
if (RD(instr) != 0) [[likely]] {
|
||||
regs.gpr[RD(instr)] = regs.gpr[RS(instr)] & regs.gpr[RT(instr)];
|
||||
regs.gprIsConstant[RD(instr)] = true;
|
||||
}
|
||||
} else {
|
||||
Util::panic("[JIT]: Implement non constant AND!");
|
||||
}
|
||||
}
|
||||
|
||||
void JIT::dadd(u32 instr) {
|
||||
if(regs.IsRegConstant(RS(instr), RT(instr))) {
|
||||
u64 rs = regs.gpr[RS(instr)];
|
||||
u64 rt = regs.gpr[RT(instr)];
|
||||
u64 result = rt + rs;
|
||||
if (check_signed_overflow(rs, rt, result)) {
|
||||
//regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
|
||||
Util::panic("[JIT]: Unhandled Overflow exception in DADD!");
|
||||
}
|
||||
|
||||
if (RD(instr) != 0) [[likely]] {
|
||||
regs.gpr[RD(instr)] = result;
|
||||
regs.gprIsConstant[RD(instr)] = true;
|
||||
}
|
||||
} else {
|
||||
Util::panic("[JIT]: Implement non constant DADD!");
|
||||
}
|
||||
}
|
||||
|
||||
void JIT::daddu(u32 instr) {
|
||||
if(regs.IsRegConstant(RS(instr), RT(instr))) {
|
||||
if (RD(instr) != 0) [[likely]] {
|
||||
s64 rs = regs.gpr[RS(instr)];
|
||||
s64 rt = regs.gpr[RT(instr)];
|
||||
regs.gpr[RD(instr)] = rt + rs;
|
||||
regs.gprIsConstant[RD(instr)] = true;
|
||||
}
|
||||
} else {
|
||||
Util::panic("[JIT]: Implement non constant DADD!");
|
||||
}
|
||||
}
|
||||
|
||||
void JIT::daddi(u32 instr) {
|
||||
if(regs.IsRegConstant(RS(instr))) {
|
||||
u64 imm = s64(s16(instr));
|
||||
u64 rs = regs.gpr[RS(instr)];
|
||||
u64 result = imm + rs;
|
||||
if (check_signed_overflow(rs, imm, result)) {
|
||||
//regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
|
||||
Util::panic("[JIT]: Unhandled Overflow exception in DADDI!");
|
||||
}
|
||||
|
||||
if (RT(instr) != 0) [[likely]] {
|
||||
regs.gpr[RT(instr)] = result;
|
||||
regs.gprIsConstant[RT(instr)] = true;
|
||||
}
|
||||
} else {
|
||||
Util::panic("[JIT]: Implement non constant DADDI!");
|
||||
}
|
||||
}
|
||||
|
||||
void JIT::daddiu(u32 instr) {
|
||||
if(regs.IsRegConstant(RS(instr))) {
|
||||
if (RT(instr) != 0) [[likely]] {
|
||||
s16 imm = s16(instr);
|
||||
s64 rs = regs.gpr[RS(instr)];
|
||||
regs.gpr[RT(instr)] = imm + rs;
|
||||
regs.gprIsConstant[RT(instr)] = true;
|
||||
}
|
||||
} else {
|
||||
Util::panic("[JIT]: Implement non constant DADDI!");
|
||||
}
|
||||
}
|
||||
|
||||
void JIT::ddiv(u32 instr) {
|
||||
if(regs.IsRegConstant(RS(instr), RT(instr))) {
|
||||
s64 dividend = regs.gpr[RS(instr)];
|
||||
s64 divisor = regs.gpr[RT(instr)];
|
||||
if (dividend == 0x8000000000000000 && divisor == 0xFFFFFFFFFFFFFFFF) {
|
||||
regs.lo = dividend;
|
||||
regs.hi = 0;
|
||||
} else if(divisor == 0) {
|
||||
regs.hi = dividend;
|
||||
if(dividend >= 0) {
|
||||
regs.lo = -1;
|
||||
} else {
|
||||
regs.lo = 1;
|
||||
}
|
||||
} else {
|
||||
s64 quotient = dividend / divisor;
|
||||
s64 remainder = dividend % divisor;
|
||||
regs.lo = quotient;
|
||||
regs.hi = remainder;
|
||||
}
|
||||
|
||||
regs.loIsConstant = true;
|
||||
regs.hiIsConstant = true;
|
||||
} else {
|
||||
Util::panic("[JIT]: Implement non constant DDIV!");
|
||||
}
|
||||
}
|
||||
|
||||
void JIT::ddivu(u32 instr) {
|
||||
if(regs.IsRegConstant(RS(instr), RT(instr))) {
|
||||
u64 dividend = regs.gpr[RS(instr)];
|
||||
u64 divisor = regs.gpr[RT(instr)];
|
||||
if (divisor == 0) {
|
||||
regs.lo = -1;
|
||||
regs.hi = (s64) dividend;
|
||||
} else {
|
||||
u64 quotient = dividend / divisor;
|
||||
u64 remainder = dividend % divisor;
|
||||
regs.lo = (s64) quotient;
|
||||
regs.hi = (s64) remainder;
|
||||
}
|
||||
|
||||
regs.loIsConstant = true;
|
||||
regs.hiIsConstant = true;
|
||||
} else {
|
||||
Util::panic("[JIT]: Implement non constant DDIVU!");
|
||||
}
|
||||
}
|
||||
|
||||
void JIT::div(u32 instr) {
|
||||
if(regs.IsRegConstant(RS(instr), RT(instr))) {
|
||||
s64 dividend = (s32) regs.gpr[RS(instr)];
|
||||
s64 divisor = (s32) regs.gpr[RT(instr)];
|
||||
|
||||
if (divisor == 0) {
|
||||
regs.hi = dividend;
|
||||
if (dividend >= 0) {
|
||||
regs.lo = s64(-1);
|
||||
} else {
|
||||
regs.lo = s64(1);
|
||||
}
|
||||
} else {
|
||||
s32 quotient = dividend / divisor;
|
||||
s32 remainder = dividend % divisor;
|
||||
regs.lo = quotient;
|
||||
regs.hi = remainder;
|
||||
}
|
||||
|
||||
regs.loIsConstant = true;
|
||||
regs.hiIsConstant = true;
|
||||
} else {
|
||||
Util::panic("[JIT]: Implement non constant DIV!");
|
||||
}
|
||||
}
|
||||
|
||||
void JIT::divu(u32 instr) {
|
||||
if(regs.IsRegConstant(RS(instr), RT(instr))) {
|
||||
u32 dividend = regs.gpr[RS(instr)];
|
||||
u32 divisor = regs.gpr[RT(instr)];
|
||||
if (divisor == 0) {
|
||||
regs.lo = -1;
|
||||
regs.hi = (s32) dividend;
|
||||
} else {
|
||||
s32 quotient = (s32) (dividend / divisor);
|
||||
s32 remainder = (s32) (dividend % divisor);
|
||||
regs.lo = quotient;
|
||||
regs.hi = remainder;
|
||||
}
|
||||
|
||||
regs.loIsConstant = true;
|
||||
regs.hiIsConstant = true;
|
||||
} else {
|
||||
Util::panic("[JIT]: Implement non constant DIVU!");
|
||||
}
|
||||
}
|
||||
|
||||
void JIT::dmult(u32 instr) {
|
||||
|
||||
}
|
||||
|
||||
void JIT::dmultu(u32 instr) {
|
||||
|
||||
}
|
||||
|
||||
void JIT::dsll(u32 instr) {
|
||||
|
||||
}
|
||||
|
||||
void JIT::dsllv(u32 instr) {
|
||||
|
||||
}
|
||||
|
||||
void JIT::dsll32(u32 instr) {
|
||||
|
||||
}
|
||||
|
||||
void JIT::dsra(u32 instr) {
|
||||
|
||||
}
|
||||
|
||||
void JIT::dsrav(u32 instr) {
|
||||
|
||||
}
|
||||
|
||||
void JIT::dsra32(u32 instr) {
|
||||
|
||||
}
|
||||
|
||||
void JIT::dsrl(u32 instr) {
|
||||
|
||||
}
|
||||
|
||||
void JIT::dsrlv(u32 instr) {
|
||||
|
||||
}
|
||||
|
||||
void JIT::dsrl32(u32 instr) {
|
||||
|
||||
}
|
||||
|
||||
void JIT::dsub(u32 instr) {
|
||||
|
||||
}
|
||||
|
||||
void JIT::dsubu(u32 instr) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -8,8 +8,19 @@ struct Registers {
|
||||
void SetPC64(s64);
|
||||
void SetPC32(s32);
|
||||
|
||||
bool IsRegConstant(u32 index) {
|
||||
if(index == 0) return true;
|
||||
return gprIsConstant[index];
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
bool IsRegConstant(Args... indices) {
|
||||
return IsRegConstant(indices...);
|
||||
}
|
||||
|
||||
s64 gpr[32]{};
|
||||
bool gprIsConstant[32]{};
|
||||
bool loIsConstant = false, hiIsConstant = false;
|
||||
Cop0 cop0;
|
||||
Cop1 cop1;
|
||||
s64 oldPC{}, pc{}, nextPC{};
|
||||
|
||||
Reference in New Issue
Block a user