#pragma once #include #include #include #include #include #define RSP_BYTE(addr) (dmem[BYTE_ADDRESS(addr) & 0xFFF]) #define GET_RSP_HALF(addr) ((RSP_BYTE(addr) << 8) | RSP_BYTE((addr) + 1)) #define SET_RSP_HALF(addr, value) \ do { \ RSP_BYTE(addr) = ((value) >> 8) & 0xFF; \ RSP_BYTE((addr) + 1) = (value) & 0xFF; \ } \ while (0) #define GET_RSP_WORD(addr) ((GET_RSP_HALF(addr) << 16) | GET_RSP_HALF((addr) + 2)) #define SET_RSP_WORD(addr, value) \ do { \ SET_RSP_HALF(addr, ((value) >> 16) & 0xFFFF); \ SET_RSP_HALF((addr) + 2, (value) & 0xFFFF); \ } \ while (0) namespace n64 { union SPStatus { u32 raw; struct { unsigned halt : 1; unsigned broke : 1; unsigned dmaBusy : 1; unsigned dmaFull : 1; unsigned ioFull : 1; unsigned singleStep : 1; unsigned interruptOnBreak : 1; unsigned signal0 : 1; unsigned signal1 : 1; unsigned signal2 : 1; unsigned signal3 : 1; unsigned signal4 : 1; unsigned signal5 : 1; unsigned signal6 : 1; unsigned signal7 : 1; unsigned : 17; }; }; union SPStatusWrite { u32 raw; struct { unsigned clearHalt : 1; unsigned setHalt : 1; unsigned clearBroke : 1; unsigned clearIntr : 1; unsigned setIntr : 1; unsigned clearSstep : 1; unsigned setSstep : 1; unsigned clearIntrOnBreak : 1; unsigned setIntrOnBreak : 1; unsigned clearSignal0 : 1; unsigned setSignal0 : 1; unsigned clearSignal1 : 1; unsigned setSignal1 : 1; unsigned clearSignal2 : 1; unsigned setSignal2 : 1; unsigned clearSignal3 : 1; unsigned setSignal3 : 1; unsigned clearSignal4 : 1; unsigned setSignal4 : 1; unsigned clearSignal5 : 1; unsigned setSignal5 : 1; unsigned clearSignal6 : 1; unsigned setSignal6 : 1; unsigned clearSignal7 : 1; unsigned setSignal7 : 1; unsigned : 7; }; }; union SPDMALen { struct { unsigned len : 12; unsigned count : 8; unsigned skip : 12; }; u32 raw; }; union SPDMASPAddr { struct { unsigned address : 12; unsigned bank : 1; unsigned : 19; }; u32 raw; }; union SPDMADRAMAddr { struct { unsigned address : 24; unsigned : 8; }; u32 raw; }; union VPR { s16 selement[8]; u16 element[8]; u8 byte[16]; u32 word[4]; m128i single; } __attribute__((packed)); static_assert(sizeof(VPR) == 16); struct Mem; struct Registers; #define DE(x) (((x) >> 11) & 0x1F) struct RSP { RSP(); void Reset(); FORCE_INLINE void Step() { gpr[0] = 0; const u32 instr = Util::ReadAccess(imem, pc & IMEM_DSIZE); oldPC = pc & 0xFFC; pc = nextPC & 0xFFC; nextPC += 4; Exec(instr); } void SetVTE(const VPR &vt, u8 e); auto Read(u32 addr) -> u32; void Write(u32 addr, u32 val); void Exec(u32 instr); SPStatus spStatus{}; u16 oldPC{}, pc{}, nextPC{}; SPDMASPAddr spDMASPAddr{}; SPDMADRAMAddr spDMADRAMAddr{}; SPDMASPAddr lastSuccessfulSPAddr{}; SPDMADRAMAddr lastSuccessfulDRAMAddr{}; SPDMALen spDMALen{}; std::array dmem{}; std::array imem{}; VPR vpr[32]{}; VPR vte{}; s32 gpr[32]{}; VPR vce{}; s16 divIn{}, divOut{}; bool divInLoaded = false; int steps = 0; struct { VPR h{}, m{}, l{}; } acc; struct { VPR l{}, h{}; } vcc, vco; bool semaphore = false; FORCE_INLINE void SetPC(const u16 val) { oldPC = pc & 0xFFC; pc = val & 0xFFC; nextPC = pc + 4; } [[nodiscard]] FORCE_INLINE s64 GetACC(const int e) const { 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) { acc.h.element[e] = val >> 32; acc.m.element[e] = val >> 16; acc.l.element[e] = val; } [[nodiscard]] FORCE_INLINE u16 GetVCO() const { u16 value = 0; 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; const u32 mask = (l << i) | (h << (i + 8)); value |= mask; } return value; } [[nodiscard]] FORCE_INLINE u16 GetVCC() const { u16 value = 0; for (int i = 0; i < 8; i++) { const bool h = vcc.h.element[7 - i] != 0; const bool l = vcc.l.element[7 - i] != 0; const u32 mask = (l << i) | (h << (i + 8)); value |= mask; } return value; } [[nodiscard]] FORCE_INLINE u8 GetVCE() const { u8 value = 0; for (int i = 0; i < 8; i++) { const bool l = vce.element[ELEMENT_INDEX(i)] != 0; value |= (l << i); } 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(const u32 instr); void regimm(const u32 instr); void lwc2(const u32 instr); void swc2(const u32 instr); void cop2(const u32 instr); void cop0(const u32 instr); void add(u32 instr); void addi(u32 instr); void and_(u32 instr); void andi(u32 instr); void b(u32 instr, bool cond); void blink(u32 instr, bool cond); void cfc2(u32 instr); void ctc2(u32 instr); void lb(u32 instr); void lh(u32 instr); void lw(u32 instr); void lbu(u32 instr); void lhu(u32 instr); void lui(u32 instr); void luv(u32 instr); void lbv(u32 instr); void ldv(u32 instr); void lsv(u32 instr); void llv(u32 instr); void lrv(u32 instr); void lqv(u32 instr); void lfv(u32 instr); void lhv(u32 instr); void ltv(u32 instr); void lpv(u32 instr); void j(u32 instr); void jal(u32 instr); void jr(u32 instr); void jalr(u32 instr); void nor(u32 instr); void or_(u32 instr); void ori(u32 instr); void xor_(u32 instr); void xori(u32 instr); void sb(u32 instr); void sh(u32 instr); void sw(u32 instr); void swv(u32 instr); void sub(u32 instr); void sbv(u32 instr); void sdv(u32 instr); void stv(u32 instr); void sqv(u32 instr); void ssv(u32 instr); void suv(u32 instr); void slv(u32 instr); void shv(u32 instr); void sfv(u32 instr); void srv(u32 instr); void spv(u32 instr); void sllv(u32 instr); void srlv(u32 instr); void srav(u32 instr); void sll(u32 instr); void srl(u32 instr); void sra(u32 instr); void slt(u32 instr); void sltu(u32 instr); void slti(u32 instr); void sltiu(u32 instr); void vabs(u32 instr); void vadd(u32 instr); void vaddc(u32 instr); void vand(u32 instr); void vnand(u32 instr); void vch(u32 instr); void vcr(u32 instr); void vcl(u32 instr); void vmacf(u32 instr); void vmacu(u32 instr); void vmacq(u32 instr); void vmadh(u32 instr); void vmadl(u32 instr); void vmadm(u32 instr); void vmadn(u32 instr); void vmov(u32 instr); void vmulf(u32 instr); void vmulu(u32 instr); void vmulq(u32 instr); void vmudl(u32 instr); void vmudh(u32 instr); void vmudm(u32 instr); void vmudn(u32 instr); void vmrg(u32 instr); void vlt(u32 instr); void veq(u32 instr); void vne(u32 instr); void vge(u32 instr); void vrcp(u32 instr); void vrsq(u32 instr); void vrcpl(u32 instr); void vrsql(u32 instr); void vrndp(u32 instr); void vrndn(u32 instr); void vrcph(u32 instr); void vsar(u32 instr); void vsub(u32 instr); void vsubc(u32 instr); void vxor(u32 instr); void vnxor(u32 instr); void vor(u32 instr); void vnor(u32 instr); void vzero(u32 instr); void mfc0(const RDP &rdp, u32 instr); void mtc0(u32 instr) const; void mfc2(u32 instr); void mtc2(u32 instr); template 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) { if (cond) { nextPC = address & 0xFFC; } else { pc = nextPC & 0xFFC; nextPC = pc + 4; } } }; } // namespace n64