Restructure
This commit is contained in:
396
src/backend/core/RSP.hpp
Normal file
396
src/backend/core/RSP.hpp
Normal file
@@ -0,0 +1,396 @@
|
||||
#pragma once
|
||||
#include <core/mmio/MI.hpp>
|
||||
#include <core/RDP.hpp>
|
||||
#include <MemoryRegions.hpp>
|
||||
#include <Interrupt.hpp>
|
||||
|
||||
#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];
|
||||
} __attribute__((packed));
|
||||
|
||||
static_assert(sizeof(VPR) == 16);
|
||||
|
||||
struct Mem;
|
||||
struct Registers;
|
||||
|
||||
#define DE(x) (((x) >> 11) & 0x1F)
|
||||
#define CLEAR_SET(val, clear, set) do { \
|
||||
if(clear && !set) (val) = 0; \
|
||||
if(set && !clear) (val) = 1; \
|
||||
} while(0)
|
||||
|
||||
struct RSP {
|
||||
RSP();
|
||||
void Reset();
|
||||
void Step(Registers& regs, Mem& mem);
|
||||
auto Read(u32 addr) -> u32;
|
||||
void Write(Mem& mem, Registers& regs, u32 addr, u32 value);
|
||||
void Exec(Registers& regs, Mem& mem, u32 instr);
|
||||
SPStatus spStatus;
|
||||
u16 oldPC{}, pc{}, nextPC{};
|
||||
SPDMASPAddr spDMASPAddr{};
|
||||
SPDMADRAMAddr spDMADRAMAddr{};
|
||||
SPDMASPAddr lastSuccessfulSPAddr;
|
||||
SPDMADRAMAddr lastSuccessfulDRAMAddr;
|
||||
SPDMALen spDMALen{};
|
||||
u8 dmem[DMEM_SIZE]{}, imem[IMEM_SIZE]{};
|
||||
VPR vpr[32]{};
|
||||
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;
|
||||
|
||||
inline void SetPC(u16 val) {
|
||||
oldPC = pc & 0xFFC;
|
||||
pc = val & 0xFFC;
|
||||
nextPC = pc + 4;
|
||||
}
|
||||
|
||||
inline s64 GetACC(int e) const {
|
||||
s64 val = s64(acc.h.element[e]) << 32;
|
||||
val |= s64(acc.m.element[e]) << 16;
|
||||
val |= s64(acc.l.element[e]) << 00;
|
||||
if((val & 0x0000800000000000) != 0) {
|
||||
val |= 0xFFFF000000000000;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
inline void SetACC(int e, s64 val) {
|
||||
acc.h.element[e] = val >> 32;
|
||||
acc.m.element[e] = val >> 16;
|
||||
acc.l.element[e] = val;
|
||||
}
|
||||
|
||||
inline u16 GetVCO() const {
|
||||
u16 value = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
bool h = vco.h.element[7 - i] != 0;
|
||||
bool l = vco.l.element[7 - i] != 0;
|
||||
u32 mask = (l << i) | (h << (i + 8));
|
||||
value |= mask;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
inline u16 GetVCC() const {
|
||||
u16 value = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
bool h = vcc.h.element[7 - i] != 0;
|
||||
bool l = vcc.l.element[7 - i] != 0;
|
||||
u32 mask = (l << i) | (h << (i + 8));
|
||||
value |= mask;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
inline u8 GetVCE() const {
|
||||
u8 value = 0;
|
||||
for(int i = 0; i < 8; i++) {
|
||||
bool l = vce.element[ELEMENT_INDEX(i)] != 0;
|
||||
value |= (l << i);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
inline u32 ReadWord(u32 addr) {
|
||||
addr &= 0xfff;
|
||||
return GET_RSP_WORD(addr);
|
||||
}
|
||||
|
||||
inline void WriteWord(u32 addr, u32 val) {
|
||||
addr &= 0xfff;
|
||||
SET_RSP_WORD(addr, val);
|
||||
}
|
||||
|
||||
inline u16 ReadHalf(u32 addr) {
|
||||
addr &= 0xfff;
|
||||
return GET_RSP_HALF(addr);
|
||||
}
|
||||
|
||||
inline void WriteHalf(u32 addr, u16 val) {
|
||||
addr &= 0xfff;
|
||||
SET_RSP_HALF(addr, val);
|
||||
}
|
||||
|
||||
inline u8 ReadByte(u32 addr) {
|
||||
addr &= 0xfff;
|
||||
return RSP_BYTE(addr);
|
||||
}
|
||||
|
||||
inline void WriteByte(u32 addr, u8 val) {
|
||||
addr &= 0xfff;
|
||||
RSP_BYTE(addr) = val;
|
||||
}
|
||||
|
||||
inline bool AcquireSemaphore() {
|
||||
if(semaphore) {
|
||||
return true;
|
||||
} else {
|
||||
semaphore = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline void ReleaseSemaphore() {
|
||||
semaphore = false;
|
||||
}
|
||||
|
||||
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 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 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 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 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 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 mfc0(RDP& rdp, u32 instr);
|
||||
void mtc0(Registers& regs, Mem& mem, u32 instr);
|
||||
void mfc2(u32 instr);
|
||||
void mtc2(u32 instr);
|
||||
|
||||
template <bool isDRAMdest>
|
||||
inline void DMA(SPDMALen len, u8* rdram, RSP& rsp, bool bank) {
|
||||
u32 length = len.len + 1;
|
||||
|
||||
length = (length + 0x7) & ~0x7;
|
||||
|
||||
u8* dst, *src;
|
||||
if constexpr (isDRAMdest) {
|
||||
dst = rdram;
|
||||
src = bank ? rsp.imem : rsp.dmem;
|
||||
} else {
|
||||
src = rdram;
|
||||
dst = bank ? rsp.imem : rsp.dmem;
|
||||
}
|
||||
|
||||
u32 mem_address = rsp.spDMASPAddr.address & 0xFF8;
|
||||
u32 dram_address = rsp.spDMADRAMAddr.address & 0xFFFFF8;
|
||||
|
||||
for (int i = 0; i < len.count + 1; i++) {
|
||||
for(int j = 0; j < length; j++) {
|
||||
if constexpr (isDRAMdest) {
|
||||
dst[dram_address + j] = src[(mem_address + j) & 0xFFF];
|
||||
} else {
|
||||
dst[(mem_address + j) & 0xFFF] = src[dram_address + j];
|
||||
}
|
||||
}
|
||||
|
||||
int skip = i == len.count ? 0 : len.skip;
|
||||
|
||||
dram_address += (length + skip);
|
||||
dram_address &= 0xFFFFF8;
|
||||
mem_address += length;
|
||||
mem_address &= 0xFF8;
|
||||
}
|
||||
|
||||
rsp.lastSuccessfulSPAddr.address = mem_address;
|
||||
rsp.lastSuccessfulSPAddr.bank = bank;
|
||||
rsp.lastSuccessfulDRAMAddr.address = dram_address;
|
||||
rsp.spDMALen.raw = 0xFF8 | (rsp.spDMALen.skip << 20);
|
||||
}
|
||||
|
||||
void WriteStatus(MI& mi, Registers& regs, u32 value);
|
||||
private:
|
||||
inline void branch(u16 address, bool cond) {
|
||||
if(cond) {
|
||||
nextPC = address & 0xFFC;
|
||||
}
|
||||
}
|
||||
|
||||
inline void branch_likely(u16 address, bool cond) {
|
||||
if(cond) {
|
||||
nextPC = address & 0xFFC;
|
||||
} else {
|
||||
pc = nextPC & 0xFFC;
|
||||
nextPC = pc + 4;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user