This rewrite is working (tested with Super Mario 64)

This commit is contained in:
irisz64
2025-08-29 10:57:01 +02:00
parent dd98e19c95
commit b8d691efb8
15 changed files with 1240 additions and 1255 deletions

View File

@@ -4,76 +4,76 @@
#define check_signed_underflow(op1, op2, res) (((((op1) ^ (op2)) & ((op1) ^ (res))) >> ((sizeof(res) * 8) - 1)) & 1)
namespace n64 {
void Interpreter::add(const u32 instr) {
const u32 rs = regs.Read<s32>(RS(instr));
const u32 rt = regs.Read<s32>(RT(instr));
void Interpreter::add(const Instruction instr) {
const u32 rs = regs.Read<s32>(instr.rs());
const u32 rt = regs.Read<s32>(instr.rt());
if (const u32 result = rs + rt; check_signed_overflow(rs, rt, result)) {
regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
} else {
regs.Write(RD(instr), static_cast<s32>(result));
regs.Write(instr.rd(), static_cast<s32>(result));
}
}
void Interpreter::addu(const u32 instr) {
const s32 rs = regs.Read<s32>(RS(instr));
const s32 rt = regs.Read<s32>(RT(instr));
void Interpreter::addu(const Instruction instr) {
const s32 rs = regs.Read<s32>(instr.rs());
const s32 rt = regs.Read<s32>(instr.rt());
const s32 result = rs + rt;
regs.Write(RD(instr), result);
regs.Write(instr.rd(), result);
}
void Interpreter::addi(const u32 instr) {
const u32 rs = regs.Read<s64>(RS(instr));
void Interpreter::addi(const Instruction instr) {
const u32 rs = regs.Read<s64>(instr.rs());
const u32 imm = static_cast<s32>(static_cast<s16>(instr));
if (const u32 result = rs + imm; check_signed_overflow(rs, imm, result)) {
regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
} else {
regs.Write(RT(instr), static_cast<s32>(result));
regs.Write(instr.rt(), static_cast<s32>(result));
}
}
void Interpreter::addiu(const u32 instr) {
const s32 rs = regs.Read<s32>(RS(instr));
void Interpreter::addiu(const Instruction instr) {
const s32 rs = regs.Read<s32>(instr.rs());
const s16 imm = static_cast<s16>(instr);
const s32 result = rs + imm;
regs.Write(RT(instr), result);
regs.Write(instr.rt(), result);
}
void Interpreter::dadd(const u32 instr) {
const u64 rs = regs.Read<s64>(RS(instr));
const u64 rt = regs.Read<s64>(RT(instr));
void Interpreter::dadd(const Instruction instr) {
const u64 rs = regs.Read<s64>(instr.rs());
const u64 rt = regs.Read<s64>(instr.rt());
if (const u64 result = rt + rs; check_signed_overflow(rs, rt, result)) {
regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
} else {
regs.Write(RD(instr), result);
regs.Write(instr.rd(), result);
}
}
void Interpreter::daddu(const u32 instr) {
const s64 rs = regs.Read<s64>(RS(instr));
const s64 rt = regs.Read<s64>(RT(instr));
regs.Write(RD(instr), rs + rt);
void Interpreter::daddu(const Instruction instr) {
const s64 rs = regs.Read<s64>(instr.rs());
const s64 rt = regs.Read<s64>(instr.rt());
regs.Write(instr.rd(), rs + rt);
}
void Interpreter::daddi(const u32 instr) {
void Interpreter::daddi(const Instruction instr) {
const u64 imm = s64(s16(instr));
const u64 rs = regs.Read<s64>(RS(instr));
const u64 rs = regs.Read<s64>(instr.rs());
if (const u64 result = imm + rs; check_signed_overflow(rs, imm, result)) {
regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
} else {
regs.Write(RT(instr), result);
regs.Write(instr.rt(), result);
}
}
void Interpreter::daddiu(const u32 instr) {
void Interpreter::daddiu(const Instruction instr) {
const s16 imm = static_cast<s16>(instr);
const s64 rs = regs.Read<s64>(RS(instr));
regs.Write(RT(instr), rs + imm);
const s64 rs = regs.Read<s64>(instr.rs());
regs.Write(instr.rt(), rs + imm);
}
void Interpreter::div(const u32 instr) {
const s64 dividend = regs.Read<s32>(RS(instr));
void Interpreter::div(const Instruction instr) {
const s64 dividend = regs.Read<s32>(instr.rs());
if (const s64 divisor = regs.Read<s32>(RT(instr)); divisor == 0) {
if (const s64 divisor = regs.Read<s32>(instr.rt()); divisor == 0) {
regs.hi = dividend;
if (dividend >= 0) {
regs.lo = static_cast<s64>(-1);
@@ -88,9 +88,9 @@ void Interpreter::div(const u32 instr) {
}
}
void Interpreter::divu(const u32 instr) {
const u32 dividend = regs.Read<s64>(RS(instr));
if (const u32 divisor = regs.Read<s64>(RT(instr)); divisor == 0) {
void Interpreter::divu(const Instruction instr) {
const u32 dividend = regs.Read<s64>(instr.rs());
if (const u32 divisor = regs.Read<s64>(instr.rt()); divisor == 0) {
regs.lo = -1;
regs.hi = (s32)dividend;
} else {
@@ -101,9 +101,9 @@ void Interpreter::divu(const u32 instr) {
}
}
void Interpreter::ddiv(const u32 instr) {
const s64 dividend = regs.Read<s64>(RS(instr));
const s64 divisor = regs.Read<s64>(RT(instr));
void Interpreter::ddiv(const Instruction instr) {
const s64 dividend = regs.Read<s64>(instr.rs());
const s64 divisor = regs.Read<s64>(instr.rt());
if (dividend == 0x8000000000000000 && divisor == 0xFFFFFFFFFFFFFFFF) {
regs.lo = dividend;
regs.hi = 0;
@@ -122,9 +122,9 @@ void Interpreter::ddiv(const u32 instr) {
}
}
void Interpreter::ddivu(const u32 instr) {
const u64 dividend = regs.Read<s64>(RS(instr));
const u64 divisor = regs.Read<s64>(RT(instr));
void Interpreter::ddivu(const Instruction instr) {
const u64 dividend = regs.Read<s64>(instr.rs());
const u64 divisor = regs.Read<s64>(instr.rt());
if (divisor == 0) {
regs.lo = -1;
regs.hi = (s64)dividend;
@@ -152,14 +152,14 @@ void Interpreter::branch_likely(const bool cond, const s64 address) {
}
}
void Interpreter::b(const u32 instr, const bool cond) {
void Interpreter::b(const Instruction instr, const bool cond) {
const s16 imm = instr;
const s64 offset = u64((s64)imm) << 2;
const s64 address = regs.pc + offset;
branch(cond, address);
}
void Interpreter::blink(const u32 instr, const bool cond) {
void Interpreter::blink(const Instruction instr, const bool cond) {
regs.Write(31, regs.nextPC);
const s16 imm = instr;
const s64 offset = u64((s64)imm) << 2;
@@ -167,14 +167,14 @@ void Interpreter::blink(const u32 instr, const bool cond) {
branch(cond, address);
}
void Interpreter::bl(const u32 instr, const bool cond) {
void Interpreter::bl(const Instruction instr, const bool cond) {
const s16 imm = instr;
const s64 offset = u64((s64)imm) << 2;
const s64 address = regs.pc + offset;
branch_likely(cond, address);
}
void Interpreter::bllink(const u32 instr, const bool cond) {
void Interpreter::bllink(const Instruction instr, const bool cond) {
regs.Write(31, regs.nextPC);
const s16 imm = instr;
const s64 offset = u64((s64)imm) << 2;
@@ -182,24 +182,24 @@ void Interpreter::bllink(const u32 instr, const bool cond) {
branch_likely(cond, address);
}
void Interpreter::lui(const u32 instr) {
void Interpreter::lui(const Instruction instr) {
u64 val = s64((s16)instr);
val <<= 16;
regs.Write(RT(instr), val);
regs.Write(instr.rt(), val);
}
void Interpreter::lb(const u32 instr) {
const u64 address = regs.Read<s64>(RS(instr)) + (s16)instr;
void Interpreter::lb(const Instruction instr) {
const u64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
if (u32 paddr = 0; !regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) {
regs.cop0.HandleTLBException(address);
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
} else {
regs.Write(RT(instr), (s8)mem.Read<u8>(paddr));
regs.Write(instr.rt(), (s8)mem.Read<u8>(paddr));
}
}
void Interpreter::lh(const u32 instr) {
const u64 address = regs.Read<s64>(RS(instr)) + (s16)instr;
void Interpreter::lh(const Instruction instr) {
const u64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
if (check_address_error(0b1, address)) {
regs.cop0.HandleTLBException(address);
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
@@ -211,13 +211,13 @@ void Interpreter::lh(const u32 instr) {
regs.cop0.HandleTLBException(address);
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
} else {
regs.Write(RT(instr), (s16)mem.Read<u16>(paddr));
regs.Write(instr.rt(), (s16)mem.Read<u16>(paddr));
}
}
void Interpreter::lw(const u32 instr) {
void Interpreter::lw(const Instruction instr) {
const s16 offset = instr;
const u64 address = regs.Read<s64>(RS(instr)) + offset;
const u64 address = regs.Read<s64>(instr.rs()) + offset;
if (check_address_error(0b11, address)) {
regs.cop0.HandleTLBException(address);
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
@@ -229,12 +229,12 @@ void Interpreter::lw(const u32 instr) {
regs.cop0.HandleTLBException(address);
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
} else {
regs.Write(RT(instr), (s32)mem.Read<u32>(physical));
regs.Write(instr.rt(), (s32)mem.Read<u32>(physical));
}
}
void Interpreter::ll(const u32 instr) {
const u64 address = regs.Read<s64>(RS(instr)) + (s16)instr;
void Interpreter::ll(const Instruction instr) {
const u64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
u32 physical;
if (!regs.cop0.MapVAddr(Cop0::LOAD, address, physical)) {
regs.cop0.HandleTLBException(address);
@@ -246,15 +246,15 @@ void Interpreter::ll(const u32 instr) {
return;
}
regs.Write(RT(instr), result);
regs.Write(instr.rt(), result);
regs.cop0.llbit = true;
regs.cop0.LLAddr = physical >> 4;
}
}
void Interpreter::lwl(const u32 instr) {
const u64 address = regs.Read<s64>(RS(instr)) + (s16)instr;
void Interpreter::lwl(const Instruction instr) {
const u64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
u32 paddr = 0;
if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) {
regs.cop0.HandleTLBException(address);
@@ -263,13 +263,13 @@ void Interpreter::lwl(const u32 instr) {
const u32 shift = 8 * ((address ^ 0) & 3);
const u32 mask = 0xFFFFFFFF << shift;
const u32 data = mem.Read<u32>(paddr & ~3);
const s32 result = s32((regs.Read<s64>(RT(instr)) & ~mask) | (data << shift));
regs.Write(RT(instr), result);
const s32 result = s32((regs.Read<s64>(instr.rt()) & ~mask) | (data << shift));
regs.Write(instr.rt(), result);
}
}
void Interpreter::lwr(const u32 instr) {
const u64 address = regs.Read<s64>(RS(instr)) + (s16)instr;
void Interpreter::lwr(const Instruction instr) {
const u64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
u32 paddr = 0;
if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) {
regs.cop0.HandleTLBException(address);
@@ -278,13 +278,13 @@ void Interpreter::lwr(const u32 instr) {
const u32 shift = 8 * ((address ^ 3) & 3);
const u32 mask = 0xFFFFFFFF >> shift;
const u32 data = mem.Read<u32>(paddr & ~3);
const s32 result = s32((regs.Read<s64>(RT(instr)) & ~mask) | (data >> shift));
regs.Write(RT(instr), result);
const s32 result = s32((regs.Read<s64>(instr.rt()) & ~mask) | (data >> shift));
regs.Write(instr.rt(), result);
}
}
void Interpreter::ld(const u32 instr) {
const s64 address = regs.Read<s64>(RS(instr)) + (s16)instr;
void Interpreter::ld(const Instruction instr) {
const s64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
if (check_address_error(0b111, address)) {
regs.cop0.HandleTLBException(address);
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
@@ -297,17 +297,17 @@ void Interpreter::ld(const u32 instr) {
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
} else {
const s64 value = mem.Read<u64>(paddr);
regs.Write(RT(instr), value);
regs.Write(instr.rt(), value);
}
}
void Interpreter::lld(const u32 instr) {
void Interpreter::lld(const Instruction instr) {
if (!regs.cop0.is64BitAddressing && !regs.cop0.kernelMode) {
regs.cop0.FireException(ExceptionCode::ReservedInstruction, 0, regs.oldPC);
return;
}
const u64 address = regs.Read<s64>(RS(instr)) + (s16)instr;
const u64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
u32 paddr;
if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) {
regs.cop0.HandleTLBException(address);
@@ -316,15 +316,15 @@ void Interpreter::lld(const u32 instr) {
if (check_address_error(0b111, address)) {
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
} else {
regs.Write(RT(instr), mem.Read<u64>(paddr));
regs.Write(instr.rt(), mem.Read<u64>(paddr));
regs.cop0.llbit = true;
regs.cop0.LLAddr = paddr >> 4;
}
}
}
void Interpreter::ldl(const u32 instr) {
const u64 address = regs.Read<s64>(RS(instr)) + (s16)instr;
void Interpreter::ldl(const Instruction instr) {
const u64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
u32 paddr = 0;
if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) {
regs.cop0.HandleTLBException(address);
@@ -333,13 +333,13 @@ void Interpreter::ldl(const u32 instr) {
const s32 shift = 8 * ((address ^ 0) & 7);
const u64 mask = 0xFFFFFFFFFFFFFFFF << shift;
const u64 data = mem.Read<u64>(paddr & ~7);
const s64 result = (s64)((regs.Read<s64>(RT(instr)) & ~mask) | (data << shift));
regs.Write(RT(instr), result);
const s64 result = (s64)((regs.Read<s64>(instr.rt()) & ~mask) | (data << shift));
regs.Write(instr.rt(), result);
}
}
void Interpreter::ldr(const u32 instr) {
const u64 address = regs.Read<s64>(RS(instr)) + (s16)instr;
void Interpreter::ldr(const Instruction instr) {
const u64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
u32 paddr;
if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) {
regs.cop0.HandleTLBException(address);
@@ -348,25 +348,25 @@ void Interpreter::ldr(const u32 instr) {
const s32 shift = 8 * ((address ^ 7) & 7);
const u64 mask = 0xFFFFFFFFFFFFFFFF >> shift;
const u64 data = mem.Read<u64>(paddr & ~7);
const s64 result = (s64)((regs.Read<s64>(RT(instr)) & ~mask) | (data >> shift));
regs.Write(RT(instr), result);
const s64 result = (s64)((regs.Read<s64>(instr.rt()) & ~mask) | (data >> shift));
regs.Write(instr.rt(), result);
}
}
void Interpreter::lbu(const u32 instr) {
const u64 address = regs.Read<s64>(RS(instr)) + (s16)instr;
void Interpreter::lbu(const Instruction instr) {
const u64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
u32 paddr;
if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) {
regs.cop0.HandleTLBException(address);
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
} else {
const u8 value = mem.Read<u8>(paddr);
regs.Write(RT(instr), value);
regs.Write(instr.rt(), value);
}
}
void Interpreter::lhu(const u32 instr) {
const s64 address = regs.Read<s64>(RS(instr)) + (s16)instr;
void Interpreter::lhu(const Instruction instr) {
const s64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
if (check_address_error(0b1, address)) {
regs.cop0.HandleTLBException(address);
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
@@ -378,12 +378,12 @@ void Interpreter::lhu(const u32 instr) {
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
} else {
const u16 value = mem.Read<u16>(paddr);
regs.Write(RT(instr), value);
regs.Write(instr.rt(), value);
}
}
void Interpreter::lwu(const u32 instr) {
const s64 address = regs.Read<s64>(RS(instr)) + (s16)instr;
void Interpreter::lwu(const Instruction instr) {
const s64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
if (check_address_error(0b11, address)) {
regs.cop0.HandleTLBException(address);
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
@@ -396,29 +396,29 @@ void Interpreter::lwu(const u32 instr) {
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
} else {
const u32 value = mem.Read<u32>(paddr);
regs.Write(RT(instr), value);
regs.Write(instr.rt(), value);
}
}
void Interpreter::sb(const u32 instr) {
const u64 address = regs.Read<s64>(RS(instr)) + (s16)instr;
void Interpreter::sb(const Instruction instr) {
const u64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
u32 paddr;
if (!regs.cop0.MapVAddr(Cop0::STORE, address, paddr)) {
regs.cop0.HandleTLBException(address);
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
} else {
mem.Write<u8>(paddr, regs.Read<s64>(RT(instr)));
mem.Write<u8>(paddr, regs.Read<s64>(instr.rt()));
}
}
void Interpreter::sc(const u32 instr) {
const u64 address = regs.Read<s64>(RS(instr)) + (s16)instr;
void Interpreter::sc(const Instruction instr) {
const u64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
if (regs.cop0.llbit) {
regs.cop0.llbit = false;
if (check_address_error(0b11, address)) {
regs.Write(RT(instr), 0);
regs.Write(instr.rt(), 0);
regs.cop0.HandleTLBException(address);
regs.cop0.FireException(ExceptionCode::AddressErrorStore, 0, regs.oldPC);
return;
@@ -426,31 +426,31 @@ void Interpreter::sc(const u32 instr) {
u32 paddr = 0;
if (!regs.cop0.MapVAddr(Cop0::STORE, address, paddr)) {
regs.Write(RT(instr), 0);
regs.Write(instr.rt(), 0);
regs.cop0.HandleTLBException(address);
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
} else {
mem.Write<u32>(paddr, regs.Read<s64>(RT(instr)));
regs.Write(RT(instr), 1);
mem.Write<u32>(paddr, regs.Read<s64>(instr.rt()));
regs.Write(instr.rt(), 1);
}
} else {
regs.Write(RT(instr), 0);
regs.Write(instr.rt(), 0);
}
}
void Interpreter::scd(const u32 instr) {
void Interpreter::scd(const Instruction instr) {
if (!regs.cop0.is64BitAddressing && !regs.cop0.kernelMode) {
regs.cop0.FireException(ExceptionCode::ReservedInstruction, 0, regs.oldPC);
return;
}
const s64 address = regs.Read<s64>(RS(instr)) + (s16)instr;
const s64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
if (regs.cop0.llbit) {
regs.cop0.llbit = false;
if (check_address_error(0b111, address)) {
regs.Write(RT(instr), 0);
regs.Write(instr.rt(), 0);
regs.cop0.HandleTLBException(address);
regs.cop0.FireException(ExceptionCode::AddressErrorStore, 0, regs.oldPC);
return;
@@ -458,33 +458,33 @@ void Interpreter::scd(const u32 instr) {
u32 paddr = 0;
if (!regs.cop0.MapVAddr(Cop0::STORE, address, paddr)) {
regs.Write(RT(instr), 0);
regs.Write(instr.rt(), 0);
regs.cop0.HandleTLBException(address);
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
} else {
mem.Write<u32>(paddr, regs.Read<s64>(RT(instr)));
regs.Write(RT(instr), 1);
mem.Write<u32>(paddr, regs.Read<s64>(instr.rt()));
regs.Write(instr.rt(), 1);
}
} else {
regs.Write(RT(instr), 0);
regs.Write(instr.rt(), 0);
}
}
void Interpreter::sh(const u32 instr) {
const s64 address = regs.Read<s64>(RS(instr)) + (s16)instr;
void Interpreter::sh(const Instruction instr) {
const s64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
u32 physical;
if (!regs.cop0.MapVAddr(Cop0::STORE, address, physical)) {
regs.cop0.HandleTLBException(address);
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
} else {
mem.Write<u16>(physical, regs.Read<s64>(RT(instr)));
mem.Write<u16>(physical, regs.Read<s64>(instr.rt()));
}
}
void Interpreter::sw(const u32 instr) {
void Interpreter::sw(const Instruction instr) {
const s16 offset = instr;
const u64 address = regs.Read<s64>(RS(instr)) + offset;
const u64 address = regs.Read<s64>(instr.rs()) + offset;
if (check_address_error(0b11, address)) {
regs.cop0.HandleTLBException(address);
regs.cop0.FireException(ExceptionCode::AddressErrorStore, 0, regs.oldPC);
@@ -496,12 +496,12 @@ void Interpreter::sw(const u32 instr) {
regs.cop0.HandleTLBException(address);
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
} else {
mem.Write<u32>(physical, regs.Read<s64>(RT(instr)));
mem.Write<u32>(physical, regs.Read<s64>(instr.rt()));
}
}
void Interpreter::sd(const u32 instr) {
const s64 address = regs.Read<s64>(RS(instr)) + (s16)instr;
void Interpreter::sd(const Instruction instr) {
const s64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
if (check_address_error(0b111, address)) {
regs.cop0.HandleTLBException(address);
regs.cop0.FireException(ExceptionCode::AddressErrorStore, 0, regs.oldPC);
@@ -513,12 +513,12 @@ void Interpreter::sd(const u32 instr) {
regs.cop0.HandleTLBException(address);
regs.cop0.FireException(Cop0::GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
} else {
mem.Write(physical, regs.Read<s64>(RT(instr)));
mem.Write(physical, regs.Read<s64>(instr.rt()));
}
}
void Interpreter::sdl(const u32 instr) {
const u64 address = regs.Read<s64>(RS(instr)) + (s16)instr;
void Interpreter::sdl(const Instruction instr) {
const u64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
u32 paddr;
if (!regs.cop0.MapVAddr(Cop0::STORE, address, paddr)) {
regs.cop0.HandleTLBException(address);
@@ -527,13 +527,13 @@ void Interpreter::sdl(const u32 instr) {
const s32 shift = 8 * ((address ^ 0) & 7);
const u64 mask = 0xFFFFFFFFFFFFFFFF >> shift;
const u64 data = mem.Read<u64>(paddr & ~7);
const u64 rt = regs.Read<s64>(RT(instr));
const u64 rt = regs.Read<s64>(instr.rt());
mem.Write(paddr & ~7, (data & ~mask) | (rt >> shift));
}
}
void Interpreter::sdr(const u32 instr) {
const u64 address = regs.Read<s64>(RS(instr)) + (s16)instr;
void Interpreter::sdr(const Instruction instr) {
const u64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
u32 paddr;
if (!regs.cop0.MapVAddr(Cop0::STORE, address, paddr)) {
regs.cop0.HandleTLBException(address);
@@ -542,13 +542,13 @@ void Interpreter::sdr(const u32 instr) {
const s32 shift = 8 * ((address ^ 7) & 7);
const u64 mask = 0xFFFFFFFFFFFFFFFF << shift;
const u64 data = mem.Read<u64>(paddr & ~7);
const u64 rt = regs.Read<s64>(RT(instr));
const u64 rt = regs.Read<s64>(instr.rt());
mem.Write(paddr & ~7, (data & ~mask) | (rt << shift));
}
}
void Interpreter::swl(const u32 instr) {
const u64 address = regs.Read<s64>(RS(instr)) + (s16)instr;
void Interpreter::swl(const Instruction instr) {
const u64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
u32 paddr;
if (!regs.cop0.MapVAddr(Cop0::STORE, address, paddr)) {
regs.cop0.HandleTLBException(address);
@@ -557,13 +557,13 @@ void Interpreter::swl(const u32 instr) {
const u32 shift = 8 * ((address ^ 0) & 3);
const u32 mask = 0xFFFFFFFF >> shift;
const u32 data = mem.Read<u32>(paddr & ~3);
const u32 rt = regs.Read<s64>(RT(instr));
const u32 rt = regs.Read<s64>(instr.rt());
mem.Write<u32>(paddr & ~3, (data & ~mask) | (rt >> shift));
}
}
void Interpreter::swr(const u32 instr) {
const u64 address = regs.Read<s64>(RS(instr)) + (s16)instr;
void Interpreter::swr(const Instruction instr) {
const u64 address = regs.Read<s64>(instr.rs()) + (s16)instr;
u32 paddr;
if (!regs.cop0.MapVAddr(Cop0::STORE, address, paddr)) {
regs.cop0.HandleTLBException(address);
@@ -572,256 +572,256 @@ void Interpreter::swr(const u32 instr) {
const u32 shift = 8 * ((address ^ 3) & 3);
const u32 mask = 0xFFFFFFFF << shift;
const u32 data = mem.Read<u32>(paddr & ~3);
const u32 rt = regs.Read<s64>(RT(instr));
const u32 rt = regs.Read<s64>(instr.rt());
mem.Write<u32>(paddr & ~3, (data & ~mask) | (rt << shift));
}
}
void Interpreter::ori(const u32 instr) {
void Interpreter::ori(const Instruction instr) {
const s64 imm = (u16)instr;
const s64 result = imm | regs.Read<s64>(RS(instr));
regs.Write(RT(instr), result);
const s64 result = imm | regs.Read<s64>(instr.rs());
regs.Write(instr.rt(), result);
}
void Interpreter::or_(const u32 instr) { regs.Write(RD(instr), regs.Read<s64>(RS(instr)) | regs.Read<s64>(RT(instr))); }
void Interpreter::or_(const Instruction instr) { regs.Write(instr.rd(), regs.Read<s64>(instr.rs()) | regs.Read<s64>(instr.rt())); }
void Interpreter::nor(const u32 instr) {
regs.Write(RD(instr), ~(regs.Read<s64>(RS(instr)) | regs.Read<s64>(RT(instr))));
void Interpreter::nor(const Instruction instr) {
regs.Write(instr.rd(), ~(regs.Read<s64>(instr.rs()) | regs.Read<s64>(instr.rt())));
}
void Interpreter::j(const u32 instr) {
void Interpreter::j(const Instruction instr) {
const s32 target = (instr & 0x3ffffff) << 2;
const s64 address = (regs.oldPC & ~0xfffffff) | target;
branch(true, address);
}
void Interpreter::jal(const u32 instr) {
void Interpreter::jal(const Instruction instr) {
regs.Write(31, regs.nextPC);
j(instr);
}
void Interpreter::jalr(const u32 instr) {
regs.Write(RD(instr), regs.nextPC);
void Interpreter::jalr(const Instruction instr) {
regs.Write(instr.rd(), regs.nextPC);
jr(instr);
}
void Interpreter::jr(const u32 instr) {
const u64 address = regs.Read<s64>(RS(instr));
void Interpreter::jr(const Instruction instr) {
const u64 address = regs.Read<s64>(instr.rs());
branch(true, address);
}
void Interpreter::slti(const u32 instr) {
void Interpreter::slti(const Instruction instr) {
const s16 imm = instr;
regs.Write(RT(instr), regs.Read<s64>(RS(instr)) < imm);
regs.Write(instr.rt(), regs.Read<s64>(instr.rs()) < imm);
}
void Interpreter::sltiu(const u32 instr) {
void Interpreter::sltiu(const Instruction instr) {
const s16 imm = instr;
regs.Write(RT(instr), regs.Read<u64>(RS(instr)) < imm);
regs.Write(instr.rt(), regs.Read<u64>(instr.rs()) < imm);
}
void Interpreter::slt(const u32 instr) { regs.Write(RD(instr), regs.Read<s64>(RS(instr)) < regs.Read<s64>(RT(instr))); }
void Interpreter::slt(const Instruction instr) { regs.Write(instr.rd(), regs.Read<s64>(instr.rs()) < regs.Read<s64>(instr.rt())); }
void Interpreter::sltu(const u32 instr) {
regs.Write(RD(instr), regs.Read<u64>(RS(instr)) < regs.Read<u64>(RT(instr)));
void Interpreter::sltu(const Instruction instr) {
regs.Write(instr.rd(), regs.Read<u64>(instr.rs()) < regs.Read<u64>(instr.rt()));
}
void Interpreter::xori(const u32 instr) {
void Interpreter::xori(const Instruction instr) {
const s64 imm = (u16)instr;
regs.Write(RT(instr), regs.Read<s64>(RS(instr)) ^ imm);
regs.Write(instr.rt(), regs.Read<s64>(instr.rs()) ^ imm);
}
void Interpreter::xor_(const u32 instr) {
regs.Write(RD(instr), regs.Read<s64>(RT(instr)) ^ regs.Read<s64>(RS(instr)));
void Interpreter::xor_(const Instruction instr) {
regs.Write(instr.rd(), regs.Read<s64>(instr.rt()) ^ regs.Read<s64>(instr.rs()));
}
void Interpreter::andi(const u32 instr) {
void Interpreter::andi(const Instruction instr) {
const s64 imm = (u16)instr;
regs.Write(RT(instr), regs.Read<s64>(RS(instr)) & imm);
regs.Write(instr.rt(), regs.Read<s64>(instr.rs()) & imm);
}
void Interpreter::and_(const u32 instr) {
regs.Write(RD(instr), regs.Read<s64>(RS(instr)) & regs.Read<s64>(RT(instr)));
void Interpreter::and_(const Instruction instr) {
regs.Write(instr.rd(), regs.Read<s64>(instr.rs()) & regs.Read<s64>(instr.rt()));
}
void Interpreter::sll(const u32 instr) {
void Interpreter::sll(const Instruction instr) {
const u8 sa = ((instr >> 6) & 0x1f);
const s32 result = regs.Read<s64>(RT(instr)) << sa;
regs.Write(RD(instr), (s64)result);
const s32 result = regs.Read<s64>(instr.rt()) << sa;
regs.Write(instr.rd(), (s64)result);
}
void Interpreter::sllv(const u32 instr) {
const u8 sa = (regs.Read<s64>(RS(instr))) & 0x1F;
const u32 rt = regs.Read<s64>(RT(instr));
void Interpreter::sllv(const Instruction instr) {
const u8 sa = (regs.Read<s64>(instr.rs())) & 0x1F;
const u32 rt = regs.Read<s64>(instr.rt());
const s32 result = rt << sa;
regs.Write(RD(instr), (s64)result);
regs.Write(instr.rd(), (s64)result);
}
void Interpreter::dsll32(const u32 instr) {
void Interpreter::dsll32(const Instruction instr) {
const u8 sa = ((instr >> 6) & 0x1f);
const s64 result = regs.Read<s64>(RT(instr)) << (sa + 32);
regs.Write(RD(instr), result);
const s64 result = regs.Read<s64>(instr.rt()) << (sa + 32);
regs.Write(instr.rd(), result);
}
void Interpreter::dsll(const u32 instr) {
void Interpreter::dsll(const Instruction instr) {
const u8 sa = ((instr >> 6) & 0x1f);
const s64 result = regs.Read<s64>(RT(instr)) << sa;
regs.Write(RD(instr), result);
const s64 result = regs.Read<s64>(instr.rt()) << sa;
regs.Write(instr.rd(), result);
}
void Interpreter::dsllv(const u32 instr) {
const s64 sa = regs.Read<s64>(RS(instr)) & 63;
const s64 result = regs.Read<s64>(RT(instr)) << sa;
regs.Write(RD(instr), result);
void Interpreter::dsllv(const Instruction instr) {
const s64 sa = regs.Read<s64>(instr.rs()) & 63;
const s64 result = regs.Read<s64>(instr.rt()) << sa;
regs.Write(instr.rd(), result);
}
void Interpreter::srl(const u32 instr) {
const u32 rt = regs.Read<s64>(RT(instr));
void Interpreter::srl(const Instruction instr) {
const u32 rt = regs.Read<s64>(instr.rt());
const u8 sa = ((instr >> 6) & 0x1f);
const u32 result = rt >> sa;
regs.Write(RD(instr), (s32)result);
regs.Write(instr.rd(), (s32)result);
}
void Interpreter::srlv(const u32 instr) {
const u8 sa = (regs.Read<s64>(RS(instr)) & 0x1F);
const u32 rt = regs.Read<s64>(RT(instr));
void Interpreter::srlv(const Instruction instr) {
const u8 sa = (regs.Read<s64>(instr.rs()) & 0x1F);
const u32 rt = regs.Read<s64>(instr.rt());
const s32 result = rt >> sa;
regs.Write(RD(instr), (s64)result);
regs.Write(instr.rd(), (s64)result);
}
void Interpreter::dsrl(const u32 instr) {
const u64 rt = regs.Read<s64>(RT(instr));
void Interpreter::dsrl(const Instruction instr) {
const u64 rt = regs.Read<s64>(instr.rt());
const u8 sa = ((instr >> 6) & 0x1f);
const u64 result = rt >> sa;
regs.Write(RD(instr), s64(result));
regs.Write(instr.rd(), s64(result));
}
void Interpreter::dsrlv(const u32 instr) {
const u8 amount = (regs.Read<s64>(RS(instr)) & 63);
const u64 rt = regs.Read<s64>(RT(instr));
void Interpreter::dsrlv(const Instruction instr) {
const u8 amount = (regs.Read<s64>(instr.rs()) & 63);
const u64 rt = regs.Read<s64>(instr.rt());
const u64 result = rt >> amount;
regs.Write(RD(instr), s64(result));
regs.Write(instr.rd(), s64(result));
}
void Interpreter::dsrl32(const u32 instr) {
const u64 rt = regs.Read<s64>(RT(instr));
void Interpreter::dsrl32(const Instruction instr) {
const u64 rt = regs.Read<s64>(instr.rt());
const u8 sa = ((instr >> 6) & 0x1f);
const u64 result = rt >> (sa + 32);
regs.Write(RD(instr), s64(result));
regs.Write(instr.rd(), s64(result));
}
void Interpreter::sra(const u32 instr) {
const s64 rt = regs.Read<s64>(RT(instr));
void Interpreter::sra(const Instruction instr) {
const s64 rt = regs.Read<s64>(instr.rt());
const u8 sa = ((instr >> 6) & 0x1f);
const s32 result = rt >> sa;
regs.Write(RD(instr), result);
regs.Write(instr.rd(), result);
}
void Interpreter::srav(const u32 instr) {
const s64 rs = regs.Read<s64>(RS(instr));
const s64 rt = regs.Read<s64>(RT(instr));
void Interpreter::srav(const Instruction instr) {
const s64 rs = regs.Read<s64>(instr.rs());
const s64 rt = regs.Read<s64>(instr.rt());
const u8 sa = rs & 0x1f;
const s32 result = rt >> sa;
regs.Write(RD(instr), result);
regs.Write(instr.rd(), result);
}
void Interpreter::dsra(const u32 instr) {
const s64 rt = regs.Read<s64>(RT(instr));
void Interpreter::dsra(const Instruction instr) {
const s64 rt = regs.Read<s64>(instr.rt());
const u8 sa = ((instr >> 6) & 0x1f);
const s64 result = rt >> sa;
regs.Write(RD(instr), result);
regs.Write(instr.rd(), result);
}
void Interpreter::dsrav(const u32 instr) {
const s64 rt = regs.Read<s64>(RT(instr));
const s64 rs = regs.Read<s64>(RS(instr));
void Interpreter::dsrav(const Instruction instr) {
const s64 rt = regs.Read<s64>(instr.rt());
const s64 rs = regs.Read<s64>(instr.rs());
const s64 sa = rs & 63;
const s64 result = rt >> sa;
regs.Write(RD(instr), result);
regs.Write(instr.rd(), result);
}
void Interpreter::dsra32(const u32 instr) {
const s64 rt = regs.Read<s64>(RT(instr));
void Interpreter::dsra32(const Instruction instr) {
const s64 rt = regs.Read<s64>(instr.rt());
const u8 sa = ((instr >> 6) & 0x1f);
const s64 result = rt >> (sa + 32);
regs.Write(RD(instr), result);
regs.Write(instr.rd(), result);
}
void Interpreter::dsub(const u32 instr) {
const s64 rt = regs.Read<s64>(RT(instr));
const s64 rs = regs.Read<s64>(RS(instr));
void Interpreter::dsub(const Instruction instr) {
const s64 rt = regs.Read<s64>(instr.rt());
const s64 rs = regs.Read<s64>(instr.rs());
if (const s64 result = rs - rt; check_signed_underflow(rs, rt, result)) {
regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
} else {
regs.Write(RD(instr), result);
regs.Write(instr.rd(), result);
}
}
void Interpreter::dsubu(const u32 instr) {
const u64 rt = regs.Read<s64>(RT(instr));
const u64 rs = regs.Read<s64>(RS(instr));
void Interpreter::dsubu(const Instruction instr) {
const u64 rt = regs.Read<s64>(instr.rt());
const u64 rs = regs.Read<s64>(instr.rs());
const u64 result = rs - rt;
regs.Write(RD(instr), s64(result));
regs.Write(instr.rd(), s64(result));
}
void Interpreter::sub(const u32 instr) {
const s32 rt = regs.Read<s64>(RT(instr));
const s32 rs = regs.Read<s64>(RS(instr));
void Interpreter::sub(const Instruction instr) {
const s32 rt = regs.Read<s64>(instr.rt());
const s32 rs = regs.Read<s64>(instr.rs());
const s32 result = rs - rt;
if (check_signed_underflow(rs, rt, result)) {
regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
} else {
regs.Write(RD(instr), result);
regs.Write(instr.rd(), result);
}
}
void Interpreter::subu(const u32 instr) {
const u32 rt = regs.Read<s64>(RT(instr));
const u32 rs = regs.Read<s64>(RS(instr));
void Interpreter::subu(const Instruction instr) {
const u32 rt = regs.Read<s64>(instr.rt());
const u32 rs = regs.Read<s64>(instr.rs());
const u32 result = rs - rt;
regs.Write(RD(instr), (s64)((s32)result));
regs.Write(instr.rd(), (s64)((s32)result));
}
void Interpreter::dmultu(const u32 instr) {
const u64 rt = regs.Read<s64>(RT(instr));
const u64 rs = regs.Read<s64>(RS(instr));
void Interpreter::dmultu(const Instruction instr) {
const u64 rt = regs.Read<s64>(instr.rt());
const u64 rs = regs.Read<s64>(instr.rs());
const u128 result = (u128)rt * (u128)rs;
regs.lo = (s64)(result & 0xFFFFFFFFFFFFFFFF);
regs.hi = (s64)(result >> 64);
}
void Interpreter::dmult(const u32 instr) {
const s64 rt = regs.Read<s64>(RT(instr));
const s64 rs = regs.Read<s64>(RS(instr));
void Interpreter::dmult(const Instruction instr) {
const s64 rt = regs.Read<s64>(instr.rt());
const s64 rs = regs.Read<s64>(instr.rs());
const s128 result = (s128)rt * (s128)rs;
regs.lo = result & 0xFFFFFFFFFFFFFFFF;
regs.hi = result >> 64;
}
void Interpreter::multu(const u32 instr) {
const u32 rt = regs.Read<s64>(RT(instr));
const u32 rs = regs.Read<s64>(RS(instr));
void Interpreter::multu(const Instruction instr) {
const u32 rt = regs.Read<s64>(instr.rt());
const u32 rs = regs.Read<s64>(instr.rs());
const u64 result = (u64)rt * (u64)rs;
regs.lo = (s64)((s32)result);
regs.hi = (s64)((s32)(result >> 32));
}
void Interpreter::mult(const u32 instr) {
const s32 rt = regs.Read<s64>(RT(instr));
const s32 rs = regs.Read<s64>(RS(instr));
void Interpreter::mult(const Instruction instr) {
const s32 rt = regs.Read<s64>(instr.rt());
const s32 rs = regs.Read<s64>(instr.rs());
const s64 result = (s64)rt * (s64)rs;
regs.lo = (s64)((s32)result);
regs.hi = (s64)((s32)(result >> 32));
}
void Interpreter::mflo(const u32 instr) { regs.Write(RD(instr), regs.lo); }
void Interpreter::mflo(const Instruction instr) { regs.Write(instr.rd(), regs.lo); }
void Interpreter::mfhi(const u32 instr) { regs.Write(RD(instr), regs.hi); }
void Interpreter::mfhi(const Instruction instr) { regs.Write(instr.rd(), regs.hi); }
void Interpreter::mtlo(const u32 instr) { regs.lo = regs.Read<s64>(RS(instr)); }
void Interpreter::mtlo(const Instruction instr) { regs.lo = regs.Read<s64>(instr.rs()); }
void Interpreter::mthi(const u32 instr) { regs.hi = regs.Read<s64>(RS(instr)); }
void Interpreter::mthi(const Instruction instr) { regs.hi = regs.Read<s64>(instr.rs()); }
void Interpreter::trap(const bool cond) const {
Cop0& cop0 = Core::GetRegs().cop0;
@@ -830,18 +830,18 @@ void Interpreter::trap(const bool cond) const {
}
}
void Interpreter::mtc2(const u32 instr) { cop2Latch = regs.Read<s64>(RT(instr)); }
void Interpreter::mtc2(const Instruction instr) { cop2Latch = regs.Read<s64>(instr.rt()); }
void Interpreter::mfc2(const u32 instr) {
void Interpreter::mfc2(const Instruction instr) {
const s32 value = cop2Latch;
regs.Write(RT(instr), value);
regs.Write(instr.rt(), value);
}
void Interpreter::dmtc2(const u32 instr) { cop2Latch = regs.Read<s64>(RT(instr)); }
void Interpreter::dmtc2(const Instruction instr) { cop2Latch = regs.Read<s64>(instr.rt()); }
void Interpreter::dmfc2(const u32 instr) { regs.Write(RT(instr), cop2Latch); }
void Interpreter::dmfc2(const Instruction instr) { regs.Write(instr.rt(), cop2Latch); }
void Interpreter::ctc2(u32) {}
void Interpreter::ctc2(const Instruction) {}
void Interpreter::cfc2(u32) {}
void Interpreter::cfc2(const Instruction) {}
} // namespace n64