it's a start...

This commit is contained in:
2026-05-28 17:53:52 +02:00
parent 4f42a673a3
commit 430ccdab40
4 changed files with 402 additions and 333 deletions
+3
View File
@@ -88,6 +88,9 @@ void Core::StepRSP(const u32 cpuCycles) {
return; return;
} }
if (cpuType == CachedInterpreter)
return mmio.rsp.ExecuteCached();
static constexpr u32 cpuRatio = 3, rspRatio = 2; static constexpr u32 cpuRatio = 3, rspRatio = 2;
regs.steps += cpuCycles; regs.steps += cpuCycles;
-2
View File
@@ -152,8 +152,6 @@ u32 Interpreter::ExecuteCached() {
// 0, making so the emulator halts cause the outer loop won't advance // 0, making so the emulator halts cause the outer loop won't advance
const auto blockCycles = line->cycles; const auto blockCycles = line->cycles;
for (u32 i = 0; i < line->len; i++) { for (u32 i = 0; i < line->len; i++) {
addr += 4;
if (!MaybeAdvance()) if (!MaybeAdvance())
return i + 1; return i + 1;
+67
View File
@@ -1,5 +1,6 @@
#include <Core.hpp> #include <Core.hpp>
#include <log.hpp> #include <log.hpp>
#include <jit/helpers.hpp>
namespace n64 { namespace n64 {
RSP::RSP() { Reset(); } RSP::RSP() { Reset(); }
@@ -230,4 +231,70 @@ void RSP::Write(const u32 addr, const u32 val) {
panic("Unimplemented SP register write {:08X}, val: {:08X}", addr, val); panic("Unimplemented SP register write {:08X}, val: {:08X}", addr, val);
} }
} }
void RSP::CacheBlock(u16 addr) {
auto blockAddr = addr;
CachedLine line;
u32 i;
bool fetchDelaySlot = false;
for (i = 0; i < MAX_INSTR_PER_BLOCK; i++) {
Instruction instr = ircolib::ReadAccess<u32>(imem, addr & IMEM_DSIZE);
addr += 4;
line.code[i] = instr;
if (fetchDelaySlot) {
i++;
break;
}
if (InstrEndsBlock(instr)) {
if (InstrHasDelaySlot(instr) && !fetchDelaySlot) {
fetchDelaySlot = true;
continue;
}
if (i == 0)
i = 1;
break;
}
}
line.cycles = i;
line.len = i;
cachedState.blocks[CACHE_GET_BLOCK(blockAddr)]->lines[CACHE_GET_LINE(blockAddr)] = new CachedLine(line);
return ExecuteCached();
}
void RSP::ExecuteCached() {
u16 addr = pc;
auto &blocks = cachedState.blocks;
if (!blocks[CACHE_GET_BLOCK(addr)]) {
blocks[CACHE_GET_BLOCK(addr)] = new CachedBlock<cachedState.MAX_LINES / 4>();
return CacheBlock(addr);
}
const auto line = blocks[CACHE_GET_BLOCK(addr)]->lines[CACHE_GET_LINE(addr)];
if (line) {
for (u32 i = 0; i < line->len; i++) {
prevDelaySlot = delaySlot;
delaySlot = false;
oldPC = pc & 0xFFC;
pc = nextPC & 0xFFC;
nextPC += 4;
Instruction instr = line->code[i];
Exec(instr);
}
return;
}
return CacheBlock(addr);
}
} // namespace n64 } // namespace n64
+332 -331
View File
@@ -5,110 +5,111 @@
#include <core/RDP.hpp> #include <core/RDP.hpp>
#include <core/mmio/MI.hpp> #include <core/mmio/MI.hpp>
#include <Instruction.hpp> #include <Instruction.hpp>
#include <JITUtils.hpp>
#define RSP_BYTE(addr) (dmem[BYTE_ADDRESS(addr) & 0xFFF]) #define RSP_BYTE(addr) (dmem[BYTE_ADDRESS(addr) & 0xFFF])
#define GET_RSP_HALF(addr) ((RSP_BYTE(addr) << 8) | RSP_BYTE((addr) + 1)) #define GET_RSP_HALF(addr) ((RSP_BYTE(addr) << 8) | RSP_BYTE((addr) + 1))
#define SET_RSP_HALF(addr, value) \ #define SET_RSP_HALF(addr, value) \
do { \ do { \
RSP_BYTE(addr) = ((value) >> 8) & 0xFF; \ RSP_BYTE(addr) = ((value) >> 8) & 0xFF; \
RSP_BYTE((addr) + 1) = (value) & 0xFF; \ RSP_BYTE((addr) + 1) = (value) & 0xFF; \
} \ } \
while (0) while (0)
#define GET_RSP_WORD(addr) ((GET_RSP_HALF(addr) << 16) | GET_RSP_HALF((addr) + 2)) #define GET_RSP_WORD(addr) ((GET_RSP_HALF(addr) << 16) | GET_RSP_HALF((addr) + 2))
#define SET_RSP_WORD(addr, value) \ #define SET_RSP_WORD(addr, value) \
do { \ do { \
SET_RSP_HALF(addr, ((value) >> 16) & 0xFFFF); \ SET_RSP_HALF(addr, ((value) >> 16) & 0xFFFF); \
SET_RSP_HALF((addr) + 2, (value) & 0xFFFF); \ SET_RSP_HALF((addr) + 2, (value) & 0xFFFF); \
} \ } \
while (0) while (0)
namespace n64 { namespace n64 {
union SPStatus { union SPStatus {
u32 raw; u32 raw;
struct { struct {
unsigned halt : 1; unsigned halt : 1;
unsigned broke : 1; unsigned broke : 1;
unsigned dmaBusy : 1; unsigned dmaBusy : 1;
unsigned dmaFull : 1; unsigned dmaFull : 1;
unsigned ioFull : 1; unsigned ioFull : 1;
unsigned singleStep : 1; unsigned singleStep : 1;
unsigned interruptOnBreak : 1; unsigned interruptOnBreak : 1;
unsigned signal0 : 1; unsigned signal0 : 1;
unsigned signal1 : 1; unsigned signal1 : 1;
unsigned signal2 : 1; unsigned signal2 : 1;
unsigned signal3 : 1; unsigned signal3 : 1;
unsigned signal4 : 1; unsigned signal4 : 1;
unsigned signal5 : 1; unsigned signal5 : 1;
unsigned signal6 : 1; unsigned signal6 : 1;
unsigned signal7 : 1; unsigned signal7 : 1;
unsigned : 17; unsigned : 17;
}; };
}; };
union SPStatusWrite { union SPStatusWrite {
u32 raw; u32 raw;
struct { struct {
unsigned clearHalt : 1; unsigned clearHalt : 1;
unsigned setHalt : 1; unsigned setHalt : 1;
unsigned clearBroke : 1; unsigned clearBroke : 1;
unsigned clearIntr : 1; unsigned clearIntr : 1;
unsigned setIntr : 1; unsigned setIntr : 1;
unsigned clearSstep : 1; unsigned clearSstep : 1;
unsigned setSstep : 1; unsigned setSstep : 1;
unsigned clearIntrOnBreak : 1; unsigned clearIntrOnBreak : 1;
unsigned setIntrOnBreak : 1; unsigned setIntrOnBreak : 1;
unsigned clearSignal0 : 1; unsigned clearSignal0 : 1;
unsigned setSignal0 : 1; unsigned setSignal0 : 1;
unsigned clearSignal1 : 1; unsigned clearSignal1 : 1;
unsigned setSignal1 : 1; unsigned setSignal1 : 1;
unsigned clearSignal2 : 1; unsigned clearSignal2 : 1;
unsigned setSignal2 : 1; unsigned setSignal2 : 1;
unsigned clearSignal3 : 1; unsigned clearSignal3 : 1;
unsigned setSignal3 : 1; unsigned setSignal3 : 1;
unsigned clearSignal4 : 1; unsigned clearSignal4 : 1;
unsigned setSignal4 : 1; unsigned setSignal4 : 1;
unsigned clearSignal5 : 1; unsigned clearSignal5 : 1;
unsigned setSignal5 : 1; unsigned setSignal5 : 1;
unsigned clearSignal6 : 1; unsigned clearSignal6 : 1;
unsigned setSignal6 : 1; unsigned setSignal6 : 1;
unsigned clearSignal7 : 1; unsigned clearSignal7 : 1;
unsigned setSignal7 : 1; unsigned setSignal7 : 1;
unsigned : 7; unsigned : 7;
}; };
}; };
union SPDMALen { union SPDMALen {
struct { struct {
unsigned len : 12; unsigned len : 12;
unsigned count : 8; unsigned count : 8;
unsigned skip : 12; unsigned skip : 12;
}; };
u32 raw; u32 raw;
}; };
union SPDMASPAddr { union SPDMASPAddr {
struct { struct {
unsigned address : 12; unsigned address : 12;
unsigned bank : 1; unsigned bank : 1;
unsigned : 19; unsigned : 19;
}; };
u32 raw; u32 raw;
}; };
union SPDMADRAMAddr { union SPDMADRAMAddr {
struct { struct {
unsigned address : 24; unsigned address : 24;
unsigned : 8; unsigned : 8;
}; };
u32 raw; u32 raw;
}; };
union VPR { union VPR {
s16 selement[8]; s16 selement[8];
u16 element[8]; u16 element[8];
u8 byte[16]; u8 byte[16];
u32 word[4]; u32 word[4];
m128i single; m128i single;
} __attribute__((packed)); } __attribute__((packed));
static_assert(sizeof(VPR) == 16); static_assert(sizeof(VPR) == 16);
@@ -119,277 +120,277 @@ struct Registers;
#define DE(x) (((x) >> 11) & 0x1F) #define DE(x) (((x) >> 11) & 0x1F)
struct RSP { struct RSP {
bool divInLoaded = false; bool divInLoaded = false;
bool semaphore = false; bool semaphore = false;
std::array<u8, DMEM_SIZE> dmem{}; std::array<u8, DMEM_SIZE> dmem{};
std::array<u8, IMEM_SIZE> imem{}; std::array<u8, IMEM_SIZE> imem{};
u16 oldPC{}, pc{}, nextPC{}; u16 oldPC{}, pc{}, nextPC{};
s16 divIn{}, divOut{}; s16 divIn{}, divOut{};
u32 steps = 0; u32 steps = 0;
SPStatus spStatus{}; SPStatus spStatus{};
SPDMASPAddr spDMASPAddr{}; SPDMASPAddr spDMASPAddr{};
SPDMADRAMAddr spDMADRAMAddr{}; SPDMADRAMAddr spDMADRAMAddr{};
SPDMASPAddr lastSuccessfulSPAddr{}; SPDMASPAddr lastSuccessfulSPAddr{};
SPDMADRAMAddr lastSuccessfulDRAMAddr{}; SPDMADRAMAddr lastSuccessfulDRAMAddr{};
SPDMALen spDMALen{}; SPDMALen spDMALen{};
s32 gpr[32]{}; s32 gpr[32]{};
VPR vpr[32]{}; VPR vpr[32]{};
VPR vte{}; VPR vte{};
VPR vce{}; VPR vce{};
struct { struct {
VPR h{}, m{}, l{}; VPR h{}, m{}, l{};
} acc; } acc;
struct { struct {
VPR l{}, h{}; VPR l{}, h{};
} vcc, vco; } vcc, vco;
RSP(); CachedState<4, 0xFFF> cachedState;
void Reset(); bool delaySlot = false, prevDelaySlot = false;
FORCE_INLINE void Step() { RSP();
gpr[0] = 0; void Reset();
const u32 instr = ircolib::ReadAccess<u32>(imem, pc & IMEM_DSIZE);
oldPC = pc & 0xFFC;
pc = nextPC & 0xFFC;
nextPC += 4;
Exec(instr); void ExecuteCached();
} void CacheBlock(u16 addr);
void SetVTE(const VPR &vt, u8 e); FORCE_INLINE void Step() {
auto Read(u32 addr) -> u32; prevDelaySlot = delaySlot;
void Write(u32 addr, u32 val); delaySlot = false;
void Exec(Instruction instr); gpr[0] = 0;
const u32 instr = ircolib::ReadAccess<u32>(imem, pc & IMEM_DSIZE);
FORCE_INLINE void SetPC(const u16 val) { oldPC = pc & 0xFFC;
oldPC = pc & 0xFFC; pc = nextPC & 0xFFC;
pc = val & 0xFFC; nextPC += 4;
nextPC = pc + 4;
}
[[nodiscard]] FORCE_INLINE s64 GetACC(const int e) const { Exec(instr);
s64 val = u64(acc.h.element[e]) << 32;
val |= u64(acc.m.element[e]) << 16;
val |= u64(acc.l.element[e]) << 00;
if ((val & 0x0000800000000000) != 0) {
val |= 0xFFFF000000000000;
} }
return val;
}
FORCE_INLINE void SetACC(const int e, const s64 val) { void SetVTE(const VPR &vt, u8 e);
acc.h.element[e] = val >> 32; auto Read(u32 addr) -> u32;
acc.m.element[e] = val >> 16; void Write(u32 addr, u32 val);
acc.l.element[e] = val; void Exec(Instruction instr);
}
[[nodiscard]] FORCE_INLINE u16 GetVCO() const { FORCE_INLINE void SetPC(const u16 val) {
u16 value = 0; oldPC = pc & 0xFFC;
for (int i = 0; i < 8; i++) { pc = val & 0xFFC;
const bool h = vco.h.element[7 - i] != 0; nextPC = pc + 4;
const bool l = vco.l.element[7 - i] != 0;
const u32 mask = (l << i) | (h << (i + 8));
value |= mask;
} }
return value;
}
[[nodiscard]] FORCE_INLINE u16 GetVCC() const { [[nodiscard]] FORCE_INLINE s64 GetACC(const int e) const {
u16 value = 0; s64 val = u64(acc.h.element[e]) << 32;
for (int i = 0; i < 8; i++) { val |= u64(acc.m.element[e]) << 16;
const bool h = vcc.h.element[7 - i] != 0; val |= u64(acc.l.element[e]) << 00;
const bool l = vcc.l.element[7 - i] != 0; if ((val & 0x0000800000000000) != 0) {
const u32 mask = (l << i) | (h << (i + 8)); val |= 0xFFFF000000000000;
value |= mask; }
return val;
} }
return value;
}
[[nodiscard]] FORCE_INLINE u8 GetVCE() const { FORCE_INLINE void SetACC(const int e, const s64 val) {
u8 value = 0; acc.h.element[e] = val >> 32;
for (int i = 0; i < 8; i++) { acc.m.element[e] = val >> 16;
const bool l = vce.element[ELEMENT_INDEX(i)] != 0; acc.l.element[e] = val;
value |= (l << i);
} }
return value;
}
[[nodiscard]] FORCE_INLINE u32 ReadWord(u32 addr) const { [[nodiscard]] FORCE_INLINE u16 GetVCO() const {
addr &= 0xfff; u16 value = 0;
return GET_RSP_WORD(addr); for (int i = 0; i < 8; i++) {
} const bool h = vco.h.element[7 - i] != 0;
const bool l = vco.l.element[7 - i] != 0;
FORCE_INLINE void WriteWord(u32 addr, const u32 val) { const u32 mask = (l << i) | (h << (i + 8));
addr &= 0xfff; value |= mask;
SET_RSP_WORD(addr, val); }
} return value;
[[nodiscard]] FORCE_INLINE u16 ReadHalf(u32 addr) const {
addr &= 0xfff;
return GET_RSP_HALF(addr);
}
FORCE_INLINE void WriteHalf(u32 addr, const u16 val) {
addr &= 0xfff;
SET_RSP_HALF(addr, val);
}
[[nodiscard]] FORCE_INLINE u8 ReadByte(u32 addr) const {
addr &= 0xfff;
return RSP_BYTE(addr);
}
FORCE_INLINE void WriteByte(u32 addr, const u8 val) {
addr &= 0xfff;
RSP_BYTE(addr) = val;
}
FORCE_INLINE bool AcquireSemaphore() {
if (semaphore) {
return true;
} else {
semaphore = true;
return false;
} }
}
FORCE_INLINE void ReleaseSemaphore() { semaphore = false; } [[nodiscard]] FORCE_INLINE u16 GetVCC() const {
u16 value = 0;
void special(Instruction instr); for (int i = 0; i < 8; i++) {
void regimm(Instruction instr); const bool h = vcc.h.element[7 - i] != 0;
void lwc2(Instruction instr); const bool l = vcc.l.element[7 - i] != 0;
void swc2(Instruction instr); const u32 mask = (l << i) | (h << (i + 8));
void cop2(Instruction instr); value |= mask;
void cop0(Instruction instr); }
return value;
void add(Instruction instr);
void addi(Instruction instr);
void and_(Instruction instr);
void andi(Instruction instr);
void b(Instruction instr, bool cond);
void blink(Instruction instr, bool cond);
void cfc2(Instruction instr);
void ctc2(Instruction instr);
void lb(Instruction instr);
void lh(Instruction instr);
void lw(Instruction instr);
void lbu(Instruction instr);
void lhu(Instruction instr);
void lui(Instruction instr);
void luv(Instruction instr);
void lbv(Instruction instr);
void ldv(Instruction instr);
void lsv(Instruction instr);
void llv(Instruction instr);
void lrv(Instruction instr);
void lqv(Instruction instr);
void lfv(Instruction instr);
void lhv(Instruction instr);
void ltv(Instruction instr);
void lpv(Instruction instr);
void j(Instruction instr);
void jal(Instruction instr);
void jr(Instruction instr);
void jalr(Instruction instr);
void nor(Instruction instr);
void or_(Instruction instr);
void ori(Instruction instr);
void xor_(Instruction instr);
void xori(Instruction instr);
void sb(Instruction instr);
void sh(Instruction instr);
void sw(Instruction instr);
void swv(Instruction instr);
void sub(Instruction instr);
void sbv(Instruction instr);
void sdv(Instruction instr);
void stv(Instruction instr);
void sqv(Instruction instr);
void ssv(Instruction instr);
void suv(Instruction instr);
void slv(Instruction instr);
void shv(Instruction instr);
void sfv(Instruction instr);
void srv(Instruction instr);
void spv(Instruction instr);
void sllv(Instruction instr);
void srlv(Instruction instr);
void srav(Instruction instr);
void sll(Instruction instr);
void srl(Instruction instr);
void sra(Instruction instr);
void slt(Instruction instr);
void sltu(Instruction instr);
void slti(Instruction instr);
void sltiu(Instruction instr);
void vabs(Instruction instr);
void vadd(Instruction instr);
void vaddc(Instruction instr);
void vand(Instruction instr);
void vnand(Instruction instr);
void vch(Instruction instr);
void vcr(Instruction instr);
void vcl(Instruction instr);
void vmacf(Instruction instr);
void vmacu(Instruction instr);
void vmacq(Instruction instr);
void vmadh(Instruction instr);
void vmadl(Instruction instr);
void vmadm(Instruction instr);
void vmadn(Instruction instr);
void vmov(Instruction instr);
void vmulf(Instruction instr);
void vmulu(Instruction instr);
void vmulq(Instruction instr);
void vmudl(Instruction instr);
void vmudh(Instruction instr);
void vmudm(Instruction instr);
void vmudn(Instruction instr);
void vmrg(Instruction instr);
void vlt(Instruction instr);
void veq(Instruction instr);
void vne(Instruction instr);
void vge(Instruction instr);
void vrcp(Instruction instr);
void vrsq(Instruction instr);
void vrcpl(Instruction instr);
void vrsql(Instruction instr);
void vrndp(Instruction instr);
void vrndn(Instruction instr);
void vrcph(Instruction instr);
void vsar(Instruction instr);
void vsub(Instruction instr);
void vsubc(Instruction instr);
void vxor(Instruction instr);
void vnxor(Instruction instr);
void vor(Instruction instr);
void vnor(Instruction instr);
void vzero(Instruction instr);
void mfc0(const RDP &rdp, Instruction instr);
void mtc0(Instruction instr) const;
void mfc2(Instruction instr);
void mtc2(Instruction instr);
template <bool toRdram>
void DMA();
void WriteStatus(u32 value);
private:
FORCE_INLINE void branch(const u16 address, const bool cond) {
if (cond) {
nextPC = address & 0xFFC;
} }
}
FORCE_INLINE void branch_likely(const u16 address, const bool cond) { [[nodiscard]] FORCE_INLINE u8 GetVCE() const {
if (cond) { u8 value = 0;
nextPC = address & 0xFFC; for (int i = 0; i < 8; i++) {
} else { const bool l = vce.element[ELEMENT_INDEX(i)] != 0;
pc = nextPC & 0xFFC; value |= (l << i);
nextPC = pc + 4; }
return value;
}
[[nodiscard]] FORCE_INLINE u32 ReadWord(u32 addr) const {
addr &= 0xfff;
return GET_RSP_WORD(addr);
}
FORCE_INLINE void WriteWord(u32 addr, const u32 val) {
addr &= 0xfff;
SET_RSP_WORD(addr, val);
}
[[nodiscard]] FORCE_INLINE u16 ReadHalf(u32 addr) const {
addr &= 0xfff;
return GET_RSP_HALF(addr);
}
FORCE_INLINE void WriteHalf(u32 addr, const u16 val) {
addr &= 0xfff;
SET_RSP_HALF(addr, val);
}
[[nodiscard]] FORCE_INLINE u8 ReadByte(u32 addr) const {
addr &= 0xfff;
return RSP_BYTE(addr);
}
FORCE_INLINE void WriteByte(u32 addr, const u8 val) {
addr &= 0xfff;
RSP_BYTE(addr) = val;
}
FORCE_INLINE bool AcquireSemaphore() {
if (semaphore) {
return true;
} else {
semaphore = true;
return false;
}
}
FORCE_INLINE void ReleaseSemaphore() { semaphore = false; }
void special(Instruction instr);
void regimm(Instruction instr);
void lwc2(Instruction instr);
void swc2(Instruction instr);
void cop2(Instruction instr);
void cop0(Instruction instr);
void add(Instruction instr);
void addi(Instruction instr);
void and_(Instruction instr);
void andi(Instruction instr);
void b(Instruction instr, bool cond);
void blink(Instruction instr, bool cond);
void cfc2(Instruction instr);
void ctc2(Instruction instr);
void lb(Instruction instr);
void lh(Instruction instr);
void lw(Instruction instr);
void lbu(Instruction instr);
void lhu(Instruction instr);
void lui(Instruction instr);
void luv(Instruction instr);
void lbv(Instruction instr);
void ldv(Instruction instr);
void lsv(Instruction instr);
void llv(Instruction instr);
void lrv(Instruction instr);
void lqv(Instruction instr);
void lfv(Instruction instr);
void lhv(Instruction instr);
void ltv(Instruction instr);
void lpv(Instruction instr);
void j(Instruction instr);
void jal(Instruction instr);
void jr(Instruction instr);
void jalr(Instruction instr);
void nor(Instruction instr);
void or_(Instruction instr);
void ori(Instruction instr);
void xor_(Instruction instr);
void xori(Instruction instr);
void sb(Instruction instr);
void sh(Instruction instr);
void sw(Instruction instr);
void swv(Instruction instr);
void sub(Instruction instr);
void sbv(Instruction instr);
void sdv(Instruction instr);
void stv(Instruction instr);
void sqv(Instruction instr);
void ssv(Instruction instr);
void suv(Instruction instr);
void slv(Instruction instr);
void shv(Instruction instr);
void sfv(Instruction instr);
void srv(Instruction instr);
void spv(Instruction instr);
void sllv(Instruction instr);
void srlv(Instruction instr);
void srav(Instruction instr);
void sll(Instruction instr);
void srl(Instruction instr);
void sra(Instruction instr);
void slt(Instruction instr);
void sltu(Instruction instr);
void slti(Instruction instr);
void sltiu(Instruction instr);
void vabs(Instruction instr);
void vadd(Instruction instr);
void vaddc(Instruction instr);
void vand(Instruction instr);
void vnand(Instruction instr);
void vch(Instruction instr);
void vcr(Instruction instr);
void vcl(Instruction instr);
void vmacf(Instruction instr);
void vmacu(Instruction instr);
void vmacq(Instruction instr);
void vmadh(Instruction instr);
void vmadl(Instruction instr);
void vmadm(Instruction instr);
void vmadn(Instruction instr);
void vmov(Instruction instr);
void vmulf(Instruction instr);
void vmulu(Instruction instr);
void vmulq(Instruction instr);
void vmudl(Instruction instr);
void vmudh(Instruction instr);
void vmudm(Instruction instr);
void vmudn(Instruction instr);
void vmrg(Instruction instr);
void vlt(Instruction instr);
void veq(Instruction instr);
void vne(Instruction instr);
void vge(Instruction instr);
void vrcp(Instruction instr);
void vrsq(Instruction instr);
void vrcpl(Instruction instr);
void vrsql(Instruction instr);
void vrndp(Instruction instr);
void vrndn(Instruction instr);
void vrcph(Instruction instr);
void vsar(Instruction instr);
void vsub(Instruction instr);
void vsubc(Instruction instr);
void vxor(Instruction instr);
void vnxor(Instruction instr);
void vor(Instruction instr);
void vnor(Instruction instr);
void vzero(Instruction instr);
void mfc0(const RDP &rdp, Instruction instr);
void mtc0(Instruction instr) const;
void mfc2(Instruction instr);
void mtc2(Instruction instr);
template <bool toRdram>
void DMA();
void WriteStatus(u32 value);
private:
FORCE_INLINE void branch(const u16 address, const bool cond) {
if (cond) {
nextPC = address & 0xFFC;
delaySlot = true;
}
} }
}
}; };
} // namespace n64 } // namespace n64