Start implementing some instructions

This commit is contained in:
SimoneN64
2024-05-21 22:46:08 +02:00
parent 89aa79fa2a
commit a35fac4a4e
9 changed files with 368 additions and 36 deletions

View File

@@ -3,7 +3,7 @@
#include <ParallelRDPWrapper.hpp> #include <ParallelRDPWrapper.hpp>
namespace n64 { 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() { void Core::Stop() {
render = false; render = false;

View File

@@ -1,5 +1,6 @@
#pragma once #pragma once
#include <backend/core/Interpreter.hpp> #include <backend/core/Interpreter.hpp>
#include <backend/core/JIT.hpp>
#include <string> #include <string>
struct Window; struct Window;

View File

@@ -2,10 +2,11 @@ file(GLOB SOURCES *.cpp)
file(GLOB HEADERS *.hpp) file(GLOB HEADERS *.hpp)
add_subdirectory(interpreter) add_subdirectory(interpreter)
add_subdirectory(jit)
add_subdirectory(mem) add_subdirectory(mem)
add_subdirectory(mmio) add_subdirectory(mmio)
add_subdirectory(registers) add_subdirectory(registers)
add_subdirectory(rsp) add_subdirectory(rsp)
add_library(core ${SOURCES} ${HEADERS}) 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)

View File

@@ -2,7 +2,10 @@
#include <jit/helpers.hpp> #include <jit/helpers.hpp>
namespace n64 { 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 JIT::ShouldServiceInterrupt() {
bool interrupts_pending = (regs.cop0.status.im & regs.cop0.cause.interruptPending) != 0; bool interrupts_pending = (regs.cop0.status.im & regs.cop0.cause.interruptPending) != 0;
@@ -24,46 +27,40 @@ void JIT::CheckCompareInterrupt() {
} }
int JIT::Step() { int JIT::Step() {
CheckCompareInterrupt(); u32 instruction;
s64 pc = regs.pc;
regs.prevDelaySlot = regs.delaySlot; do {
regs.delaySlot = false; //CheckCompareInterrupt();
if (check_address_error(0b11, u64(regs.pc))) [[unlikely]] { //regs.prevDelaySlot = regs.delaySlot;
regs.cop0.HandleTLBException(regs.pc); //regs.delaySlot = false;
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.pc);
/*if (check_address_error(0b11, u64(pc))) [[unlikely]] {
regs.cop0.HandleTLBException(pc);
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, pc);
return 1; return 1;
} }*/
u32 paddr = 0; u32 paddr = 0;
if (!regs.cop0.MapVAddr(Cop0::LOAD, regs.pc, paddr)) { if (!regs.cop0.MapVAddr(Cop0::LOAD, pc, paddr)) {
regs.cop0.HandleTLBException(regs.pc); /*regs.cop0.HandleTLBException(pc);
regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.pc); regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, pc);
return 1; return 1;*/
} Util::panic("[JIT]: Unhandled exception TLB exception {} when retrieving PC physical address!", regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD));
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;
} }
instruction = mem.Read<u32>(regs, paddr); instruction = mem.Read<u32>(regs, paddr);
}
if(ShouldServiceInterrupt()) { /*if(ShouldServiceInterrupt()) {
regs.cop0.FireException(ExceptionCode::Interrupt, 0, regs.pc); regs.cop0.FireException(ExceptionCode::Interrupt, 0, regs.pc);
return 1; return 1;
} }*/
regs.oldPC = regs.pc; pc += 4;
regs.pc = regs.nextPC;
regs.nextPC += 4;
Exec(instruction); //Exec(instruction);
} while (!InstrEndsBlock(instruction));
return 1; return 1;
} }

View File

@@ -32,10 +32,10 @@ private:
std::vector<u8> Serialize() override; std::vector<u8> Serialize() override;
void Deserialize(const std::vector<u8>&) override; void Deserialize(const std::vector<u8>&) override;
void Emit(u32);
void cop2Decode(u32); void cop2Decode(u32);
void special(u32); void special(u32);
void regimm(u32); void regimm(u32);
void Exec(u32);
void add(u32); void add(u32);
void addu(u32); void addu(u32);
void addi(u32); void addi(u32);

View File

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

View File

@@ -17,7 +17,8 @@ static inline bool InstrEndsBlock(u32 instr) {
case SPECIAL: return SpecialEndsBlock(instr); case SPECIAL: return SpecialEndsBlock(instr);
case REGIMM: case J: case JAL: case BEQ: case REGIMM: case J: case JAL: case BEQ:
case BNE: case BLEZ: case BGTZ: case BEQL: 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;
} }
} }
} }

View 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) {
}
}

View File

@@ -8,8 +8,19 @@ struct Registers {
void SetPC64(s64); void SetPC64(s64);
void SetPC32(s32); 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]{}; s64 gpr[32]{};
bool gprIsConstant[32]{}; bool gprIsConstant[32]{};
bool loIsConstant = false, hiIsConstant = false;
Cop0 cop0; Cop0 cop0;
Cop1 cop1; Cop1 cop1;
s64 oldPC{}, pc{}, nextPC{}; s64 oldPC{}, pc{}, nextPC{};