Fix exception in delay slot
This commit is contained in:
@@ -53,9 +53,6 @@ void Core::Run(Window& window) {
|
|||||||
for(;cycles <= mmio.vi.cyclesPerHalfline; cycles++, frameCycles++) {
|
for(;cycles <= mmio.vi.cyclesPerHalfline; cycles++, frameCycles++) {
|
||||||
cpu.Step(mem);
|
cpu.Step(mem);
|
||||||
mmio.rsp.Step(mmio.mi, cpu.regs, mmio.rdp);
|
mmio.rsp.Step(mmio.mi, cpu.regs, mmio.rdp);
|
||||||
mmio.rsp.Step(mmio.mi, cpu.regs, mmio.rdp);
|
|
||||||
mmio.rsp.Step(mmio.mi, cpu.regs, mmio.rdp);
|
|
||||||
mmio.rsp.Step(mmio.mi, cpu.regs, mmio.rdp);
|
|
||||||
|
|
||||||
mmio.ai.Step(mem, cpu.regs, 1);
|
mmio.ai.Step(mem, cpu.regs, 1);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ void FireException(Registers& regs, ExceptionCode code, int cop, s64 pc) {
|
|||||||
bool old_exl = regs.cop0.status.exl;
|
bool old_exl = regs.cop0.status.exl;
|
||||||
|
|
||||||
if(!regs.cop0.status.exl) {
|
if(!regs.cop0.status.exl) {
|
||||||
if(regs.delaySlot) { // TODO: cached value of delay_slot should be used, but Namco Museum breaks!
|
if(regs.prevDelaySlot) {
|
||||||
regs.cop0.cause.branchDelay = true;
|
regs.cop0.cause.branchDelay = true;
|
||||||
pc -= 4;
|
pc -= 4;
|
||||||
} else {
|
} else {
|
||||||
@@ -94,30 +94,15 @@ void Cpu::Step(Mem& mem) {
|
|||||||
CheckCompareInterrupt(mem.mmio.mi, regs);
|
CheckCompareInterrupt(mem.mmio.mi, regs);
|
||||||
HandleInterrupt(regs);
|
HandleInterrupt(regs);
|
||||||
|
|
||||||
regs.prevDelaySlot = regs.delaySlot;
|
|
||||||
regs.delaySlot = false;
|
|
||||||
|
|
||||||
u32 instruction = mem.Read<u32>(regs, regs.pc, regs.pc);
|
u32 instruction = mem.Read<u32>(regs, regs.pc, regs.pc);
|
||||||
|
|
||||||
/*cs_insn* insn;
|
|
||||||
u8 code[4]{};
|
|
||||||
memcpy(code, &instruction, 4);
|
|
||||||
|
|
||||||
u32 pc = regs.pc;
|
|
||||||
|
|
||||||
size_t count = cs_disasm(handle, code, 4, (u64)pc, 0, &insn);
|
|
||||||
if(count > 0) {
|
|
||||||
for(int i = 0; i < count; i++) {
|
|
||||||
fprintf(log, "%s", fmt::format("0x{:016X}\t{}\t{}\n", insn[i].address, insn[i].mnemonic, insn[i].op_str).c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
cs_free(insn, count);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
regs.oldPC = regs.pc;
|
regs.oldPC = regs.pc;
|
||||||
regs.pc = regs.nextPC;
|
regs.pc = regs.nextPC;
|
||||||
regs.nextPC += 4;
|
regs.nextPC += 4;
|
||||||
|
|
||||||
Exec(mem, instruction);
|
Exec(mem, instruction);
|
||||||
|
|
||||||
|
regs.prevDelaySlot = regs.delaySlot;
|
||||||
|
regs.delaySlot = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -40,7 +40,7 @@ void RSP::Step(MI& mi, Registers& regs, RDP& rdp) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto RSP::Read(u32 addr) const -> u32{
|
auto RSP::Read(u32 addr) -> u32{
|
||||||
switch (addr) {
|
switch (addr) {
|
||||||
case 0x04040000: return spDMASPAddr.raw & 0xFFFFF8;
|
case 0x04040000: return spDMASPAddr.raw & 0xFFFFF8;
|
||||||
case 0x04040004: return spDMADRAMAddr.raw & 0x1FF8;
|
case 0x04040004: return spDMADRAMAddr.raw & 0x1FF8;
|
||||||
@@ -48,10 +48,11 @@ auto RSP::Read(u32 addr) const -> u32{
|
|||||||
case 0x0404000C: return spDMAWRLen.raw;
|
case 0x0404000C: return spDMAWRLen.raw;
|
||||||
case 0x04040010: return spStatus.raw;
|
case 0x04040010: return spStatus.raw;
|
||||||
case 0x04040018: return 0;
|
case 0x04040018: return 0;
|
||||||
case 0x04080000: return pc & 0xFFF;
|
case 0x0404001C: return AcquireSemaphore();
|
||||||
default: util::panic("Unimplemented SP register read %08X\n", addr);
|
case 0x04080000:
|
||||||
|
return pc & 0xFFC;
|
||||||
|
default: util::panic("Unimplemented SP register read {:08X}\n", addr);
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <bool isDRAMdest>
|
template <bool isDRAMdest>
|
||||||
@@ -99,8 +100,7 @@ void RSP::Write(Mem& mem, Registers& regs, u32 addr, u32 value) {
|
|||||||
spDMAWRLen.raw = 0xFF8 | (spDMAWRLen.skip << 20);
|
spDMAWRLen.raw = 0xFF8 | (spDMAWRLen.skip << 20);
|
||||||
} break;
|
} break;
|
||||||
case 0x04040010: {
|
case 0x04040010: {
|
||||||
SPStatusWrite write;
|
auto write = SPStatusWrite{.raw = value};
|
||||||
write.raw = value;
|
|
||||||
CLEAR_SET(spStatus.halt, write.clearHalt, write.setHalt);
|
CLEAR_SET(spStatus.halt, write.clearHalt, write.setHalt);
|
||||||
CLEAR_SET(spStatus.broke, write.clearBroke, false);
|
CLEAR_SET(spStatus.broke, write.clearBroke, false);
|
||||||
if(write.clearIntr) InterruptLower(mi, regs, Interrupt::SP);
|
if(write.clearIntr) InterruptLower(mi, regs, Interrupt::SP);
|
||||||
@@ -116,10 +116,11 @@ void RSP::Write(Mem& mem, Registers& regs, u32 addr, u32 value) {
|
|||||||
CLEAR_SET(spStatus.signal6Set, write.clearSignal6, write.setSignal6);
|
CLEAR_SET(spStatus.signal6Set, write.clearSignal6, write.setSignal6);
|
||||||
CLEAR_SET(spStatus.signal7Set, write.clearSignal7, write.setSignal7);
|
CLEAR_SET(spStatus.signal7Set, write.clearSignal7, write.setSignal7);
|
||||||
} break;
|
} break;
|
||||||
|
case 0x0404001C: ReleaseSemaphore(); break;
|
||||||
case 0x04080000:
|
case 0x04080000:
|
||||||
if(spStatus.halt) {
|
if(spStatus.halt) {
|
||||||
oldPC = pc;
|
oldPC = pc & 0xFFC;
|
||||||
pc = nextPC;
|
pc = value & 0xFFC;
|
||||||
nextPC = value & 0xFFC;
|
nextPC = value & 0xFFC;
|
||||||
} break;
|
} break;
|
||||||
default: util::panic("Unimplemented SP register write {:08X}, val: {:08X}\n", addr, value);
|
default: util::panic("Unimplemented SP register write {:08X}, val: {:08X}\n", addr, value);
|
||||||
|
|||||||
@@ -110,17 +110,17 @@ struct RSP {
|
|||||||
RSP();
|
RSP();
|
||||||
void Reset();
|
void Reset();
|
||||||
void Step(MI& mi, Registers& regs, RDP& rdp);
|
void Step(MI& mi, Registers& regs, RDP& rdp);
|
||||||
auto Read(u32 addr) const -> u32;
|
auto Read(u32 addr) -> u32;
|
||||||
void Write(Mem& mem, Registers& regs, u32 addr, u32 value);
|
void Write(Mem& mem, Registers& regs, u32 addr, u32 value);
|
||||||
void Exec(MI& mi, Registers& regs, RDP& rdp, u32 instr);
|
void Exec(MI& mi, Registers& regs, RDP& rdp, u32 instr);
|
||||||
SPStatus spStatus;
|
SPStatus spStatus;
|
||||||
u16 oldPC{}, pc{}, nextPC = 4;
|
u16 oldPC{}, pc{}, nextPC{};
|
||||||
SPDMASPAddr spDMASPAddr{};
|
SPDMASPAddr spDMASPAddr{};
|
||||||
SPDMADRAMAddr spDMADRAMAddr{};
|
SPDMADRAMAddr spDMADRAMAddr{};
|
||||||
SPDMALen spDMARDLen{}, spDMAWRLen{};
|
SPDMALen spDMARDLen{}, spDMAWRLen{};
|
||||||
u8 dmem[DMEM_SIZE]{}, imem[IMEM_SIZE]{};
|
u8 dmem[DMEM_SIZE]{}, imem[IMEM_SIZE]{};
|
||||||
VPR vpr[32]{};
|
VPR vpr[32]{};
|
||||||
u32 gpr[32]{};
|
s32 gpr[32]{};
|
||||||
u8 vce{};
|
u8 vce{};
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
@@ -177,11 +177,24 @@ struct RSP {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline u8 ReadByte(u32 addr) {
|
inline u8 ReadByte(u32 addr) {
|
||||||
return GET_RSP_WORD(addr);
|
return RSP_BYTE(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void WriteByte(u32 addr, u8 val) {
|
inline void WriteByte(u32 addr, u8 val) {
|
||||||
SET_RSP_WORD(addr, val);
|
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 add(u32 instr);
|
||||||
@@ -190,22 +203,38 @@ struct RSP {
|
|||||||
void andi(u32 instr);
|
void andi(u32 instr);
|
||||||
void cfc2(u32 instr);
|
void cfc2(u32 instr);
|
||||||
void b(u32 instr, bool cond);
|
void b(u32 instr, bool cond);
|
||||||
|
void bl(u32 instr, bool cond);
|
||||||
|
void lb(u32 instr);
|
||||||
void lh(u32 instr);
|
void lh(u32 instr);
|
||||||
void lw(u32 instr);
|
void lw(u32 instr);
|
||||||
|
void lbu(u32 instr);
|
||||||
|
void lhu(u32 instr);
|
||||||
void lui(u32 instr);
|
void lui(u32 instr);
|
||||||
void lqv(u32 instr);
|
void lqv(u32 instr);
|
||||||
void j(u32 instr);
|
void j(u32 instr);
|
||||||
void jal(u32 instr);
|
void jal(u32 instr);
|
||||||
void jr(u32 instr);
|
void jr(u32 instr);
|
||||||
|
void jalr(u32 instr);
|
||||||
void nor(u32 instr);
|
void nor(u32 instr);
|
||||||
void or_(u32 instr);
|
void or_(u32 instr);
|
||||||
void ori(u32 instr);
|
void ori(u32 instr);
|
||||||
|
void xor_(u32 instr);
|
||||||
|
void xori(u32 instr);
|
||||||
void sb(u32 instr);
|
void sb(u32 instr);
|
||||||
void sh(u32 instr);
|
void sh(u32 instr);
|
||||||
void sw(u32 instr);
|
void sw(u32 instr);
|
||||||
|
void sub(u32 instr);
|
||||||
void sqv(u32 instr);
|
void sqv(u32 instr);
|
||||||
void sllv(u32 instr);
|
void sllv(u32 instr);
|
||||||
|
void srlv(u32 instr);
|
||||||
|
void srav(u32 instr);
|
||||||
void sll(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 vabs(u32 instr);
|
||||||
void vmov(u32 instr);
|
void vmov(u32 instr);
|
||||||
void veq(u32 instr);
|
void veq(u32 instr);
|
||||||
@@ -216,7 +245,16 @@ struct RSP {
|
|||||||
private:
|
private:
|
||||||
inline void branch(u16 address, bool cond) {
|
inline void branch(u16 address, bool cond) {
|
||||||
if(cond) {
|
if(cond) {
|
||||||
nextPC = address & 0xFFF;
|
nextPC = address & 0xFFC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void branch_likely(u16 address, bool cond) {
|
||||||
|
if(cond) {
|
||||||
|
nextPC = address & 0xFFC;
|
||||||
|
} else {
|
||||||
|
pc = nextPC & 0xFFC;
|
||||||
|
nextPC = pc + 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -179,9 +179,9 @@ void Cpu::lb(Mem& mem, u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Cpu::lh(Mem& mem, u32 instr) {
|
void Cpu::lh(Mem& mem, u32 instr) {
|
||||||
u32 address = regs.gpr[RS(instr)] + (s16)instr;
|
s64 address = regs.gpr[RS(instr)] + (s16)instr;
|
||||||
if ((address & 1) != 0) {
|
if (((address & 1) != 0) || (address > 0)) {
|
||||||
HandleTLBException(regs, s64(s32(address)));
|
HandleTLBException(regs, address);
|
||||||
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,9 +189,9 @@ void Cpu::lh(Mem& mem, u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Cpu::lw(Mem& mem, u32 instr) {
|
void Cpu::lw(Mem& mem, u32 instr) {
|
||||||
u32 address = regs.gpr[RS(instr)] + (s16)instr;
|
s64 address = regs.gpr[RS(instr)] + (s16)instr;
|
||||||
if ((address & 3) != 0) {
|
if (((address & 3) != 0) || (address > 0)) {
|
||||||
HandleTLBException(regs, s64(s32(address)));
|
HandleTLBException(regs, address);
|
||||||
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,9 +199,9 @@ void Cpu::lw(Mem& mem, u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Cpu::ll(Mem& mem, u32 instr) {
|
void Cpu::ll(Mem& mem, u32 instr) {
|
||||||
u32 address = regs.gpr[RS(instr)] + (s16)instr;
|
s64 address = regs.gpr[RS(instr)] + (s16)instr;
|
||||||
if ((address & 3) != 0) {
|
if ((address & 3) != 0 || (address > 0)) {
|
||||||
HandleTLBException(regs, s64(s32(address)));
|
HandleTLBException(regs, address);
|
||||||
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,9 +232,9 @@ void Cpu::lwr(Mem& mem, u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Cpu::ld(Mem& mem, u32 instr) {
|
void Cpu::ld(Mem& mem, u32 instr) {
|
||||||
u32 address = regs.gpr[RS(instr)] + (s16)instr;
|
s64 address = regs.gpr[RS(instr)] + (s16)instr;
|
||||||
if ((address & 7) != 0) {
|
if ((address & 7) != 0 || (address > 0)) {
|
||||||
HandleTLBException(regs, (s64)((s32)address));
|
HandleTLBException(regs, address);
|
||||||
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,9 +243,9 @@ void Cpu::ld(Mem& mem, u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Cpu::lld(Mem& mem, u32 instr) {
|
void Cpu::lld(Mem& mem, u32 instr) {
|
||||||
u32 address = regs.gpr[RS(instr)] + (s16)instr;
|
s64 address = regs.gpr[RS(instr)] + (s16)instr;
|
||||||
if ((address & 7) != 0) {
|
if ((address & 7) != 0 || (address > 0)) {
|
||||||
HandleTLBException(regs, (s64)((s32)address));
|
HandleTLBException(regs, address);
|
||||||
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -283,9 +283,9 @@ void Cpu::lbu(Mem& mem, u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Cpu::lhu(Mem& mem, u32 instr) {
|
void Cpu::lhu(Mem& mem, u32 instr) {
|
||||||
u32 address = regs.gpr[RS(instr)] + (s16)instr;
|
s64 address = regs.gpr[RS(instr)] + (s16)instr;
|
||||||
if ((address & 1) != 0) {
|
if ((address & 1) != 0 || (address > 0)) {
|
||||||
HandleTLBException(regs, (s64)((s32)address));
|
HandleTLBException(regs, address);
|
||||||
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -294,9 +294,9 @@ void Cpu::lhu(Mem& mem, u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Cpu::lwu(Mem& mem, u32 instr) {
|
void Cpu::lwu(Mem& mem, u32 instr) {
|
||||||
u32 address = regs.gpr[RS(instr)] + (s16)instr;
|
s64 address = regs.gpr[RS(instr)] + (s16)instr;
|
||||||
if ((address & 3) != 0) {
|
if ((address & 3) != 0 || (address > 0)) {
|
||||||
HandleTLBException(regs, (s64)((s32)address));
|
HandleTLBException(regs, address);
|
||||||
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -310,9 +310,9 @@ void Cpu::sb(Mem& mem, u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Cpu::sc(Mem& mem, u32 instr) {
|
void Cpu::sc(Mem& mem, u32 instr) {
|
||||||
u32 address = regs.gpr[RS(instr)] + (s16)instr;
|
s64 address = regs.gpr[RS(instr)] + (s16)instr;
|
||||||
if ((address & 3) != 0) {
|
if ((address & 3) != 0 || (address > 0)) {
|
||||||
HandleTLBException(regs, (s64)((s32)address));
|
HandleTLBException(regs, address);
|
||||||
FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -325,9 +325,9 @@ void Cpu::sc(Mem& mem, u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Cpu::scd(Mem& mem, u32 instr) {
|
void Cpu::scd(Mem& mem, u32 instr) {
|
||||||
u32 address = regs.gpr[RS(instr)] + (s16)instr;
|
s64 address = regs.gpr[RS(instr)] + (s16)instr;
|
||||||
if ((address & 7) != 0) {
|
if ((address & 7) != 0 || (address > 0)) {
|
||||||
HandleTLBException(regs, (s64)((s32)address));
|
HandleTLBException(regs, address);
|
||||||
FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -340,9 +340,9 @@ void Cpu::scd(Mem& mem, u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Cpu::sh(Mem& mem, u32 instr) {
|
void Cpu::sh(Mem& mem, u32 instr) {
|
||||||
u32 address = regs.gpr[RS(instr)] + (s16)instr;
|
s64 address = regs.gpr[RS(instr)] + (s16)instr;
|
||||||
if ((address & 1) != 0) {
|
if ((address & 1) != 0 || (address > 0)) {
|
||||||
HandleTLBException(regs, (s64)((s32)address));
|
HandleTLBException(regs, address);
|
||||||
FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -350,9 +350,9 @@ void Cpu::sh(Mem& mem, u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Cpu::sw(Mem& mem, u32 instr) {
|
void Cpu::sw(Mem& mem, u32 instr) {
|
||||||
u32 address = regs.gpr[RS(instr)] + (s16)instr;
|
s64 address = regs.gpr[RS(instr)] + (s16)instr;
|
||||||
if ((address & 3) != 0) {
|
if ((address & 3) != 0 || (address > 0)) {
|
||||||
HandleTLBException(regs, (s64)((s32)address));
|
HandleTLBException(regs, address);
|
||||||
FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -360,9 +360,9 @@ void Cpu::sw(Mem& mem, u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Cpu::sd(Mem& mem, u32 instr) {
|
void Cpu::sd(Mem& mem, u32 instr) {
|
||||||
u32 address = regs.gpr[RS(instr)] + (s16)instr;
|
s64 address = regs.gpr[RS(instr)] + (s16)instr;
|
||||||
if ((address & 7) != 0) {
|
if ((address & 7) != 0 || (address > 0)) {
|
||||||
HandleTLBException(regs, (s64)((s32)address));
|
HandleTLBException(regs, address);
|
||||||
FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -421,9 +421,9 @@ void Cpu::nor(u32 instr) {
|
|||||||
|
|
||||||
void Cpu::j(u32 instr) {
|
void Cpu::j(u32 instr) {
|
||||||
s32 target = (instr & 0x3ffffff) << 2;
|
s32 target = (instr & 0x3ffffff) << 2;
|
||||||
s32 address = (regs.oldPC & ~0xfffffff) | target;
|
s64 address = (regs.oldPC & ~0xfffffff) | target;
|
||||||
if ((address & 3) != 0) {
|
if ((address & 3) != 0 || (address > 0)) {
|
||||||
HandleTLBException(regs, (s64)((s32)address));
|
HandleTLBException(regs, address);
|
||||||
FireException(regs, ExceptionCode::DataBusError, 0, regs.oldPC);
|
FireException(regs, ExceptionCode::DataBusError, 0, regs.oldPC);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -578,8 +578,8 @@ void Cpu::dsra32(u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Cpu::jr(u32 instr) {
|
void Cpu::jr(u32 instr) {
|
||||||
s32 address = regs.gpr[RS(instr)];
|
s64 address = regs.gpr[RS(instr)];
|
||||||
if ((address & 3) != 0) {
|
if ((address & 3) != 0 || (address > 0)) {
|
||||||
HandleTLBException(regs, address);
|
HandleTLBException(regs, address);
|
||||||
FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,9 +7,18 @@ namespace n64 {
|
|||||||
inline void special(MI& mi, Registers& regs, RSP& rsp, u32 instr) {
|
inline void special(MI& mi, Registers& regs, RSP& rsp, u32 instr) {
|
||||||
u8 mask = instr & 0x3f;
|
u8 mask = instr & 0x3f;
|
||||||
switch(mask) {
|
switch(mask) {
|
||||||
case 0x00: rsp.sll(instr); break;
|
case 0x00:
|
||||||
|
if(instr != 0) {
|
||||||
|
rsp.sll(instr);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x02: rsp.srl(instr); break;
|
||||||
|
case 0x03: rsp.sra(instr); break;
|
||||||
case 0x04: rsp.sllv(instr); break;
|
case 0x04: rsp.sllv(instr); break;
|
||||||
//case 0x08: rsp.jr(instr); break;
|
case 0x06: rsp.srlv(instr); break;
|
||||||
|
case 0x07: rsp.srav(instr); break;
|
||||||
|
case 0x08: rsp.jr(instr); break;
|
||||||
|
case 0x09: rsp.jalr(instr); break;
|
||||||
case 0x0C:
|
case 0x0C:
|
||||||
case 0x0D:
|
case 0x0D:
|
||||||
rsp.spStatus.halt = true;
|
rsp.spStatus.halt = true;
|
||||||
@@ -18,12 +27,18 @@ inline void special(MI& mi, Registers& regs, RSP& rsp, u32 instr) {
|
|||||||
InterruptRaise(mi, regs, Interrupt::SP);
|
InterruptRaise(mi, regs, Interrupt::SP);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
//case 0x20: case 0x21:
|
case 0x20: case 0x21:
|
||||||
// rsp.add(instr);
|
rsp.add(instr);
|
||||||
// break;
|
break;
|
||||||
|
case 0x22: case 0x23:
|
||||||
|
rsp.sub(instr);
|
||||||
|
break;
|
||||||
case 0x24: rsp.and_(instr); break;
|
case 0x24: rsp.and_(instr); break;
|
||||||
case 0x25: rsp.or_(instr); break;
|
case 0x25: rsp.or_(instr); break;
|
||||||
//case 0x27: rsp.nor(instr); break;
|
case 0x26: rsp.xor_(instr); break;
|
||||||
|
case 0x27: rsp.nor(instr); break;
|
||||||
|
case 0x2A: rsp.slt(instr); break;
|
||||||
|
case 0x2B: rsp.sltu(instr); break;
|
||||||
default: util::panic("Unhandled RSP special instruction ({:06b})\n", mask);
|
default: util::panic("Unhandled RSP special instruction ({:06b})\n", mask);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -31,9 +46,11 @@ inline void special(MI& mi, Registers& regs, RSP& rsp, u32 instr) {
|
|||||||
inline void regimm(RSP& rsp, u32 instr) {
|
inline void regimm(RSP& rsp, u32 instr) {
|
||||||
u8 mask = ((instr >> 16) & 0x1F);
|
u8 mask = ((instr >> 16) & 0x1F);
|
||||||
switch(mask) {
|
switch(mask) {
|
||||||
//case 0x00: rsp.b(instr, (s32)rsp.gpr[RS(instr)] < 0); break;
|
case 0x00: rsp.b(instr, (s32)rsp.gpr[RS(instr)] < 0); break;
|
||||||
//case 0x01: rsp.b(instr, (s32)rsp.gpr[RS(instr)] >= 0); break;
|
case 0x01: rsp.b(instr, (s32)rsp.gpr[RS(instr)] >= 0); break;
|
||||||
default: util::panic("Unhandled RSP regimm instruction {} {}\n", (mask >> 3) & 3, mask & 7);
|
case 0x10: rsp.bl(instr, (s32)rsp.gpr[RS(instr)] < 0); break;
|
||||||
|
case 0x11: rsp.bl(instr, (s32)rsp.gpr[RS(instr)] >= 0); break;
|
||||||
|
default: util::panic("Unhandled RSP regimm instruction ({:06b})\n", mask);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,19 +105,28 @@ void RSP::Exec(MI &mi, Registers ®s, RDP &rdp, u32 instr) {
|
|||||||
case 0x01: regimm(*this, instr); break;
|
case 0x01: regimm(*this, instr); break;
|
||||||
case 0x02: j(instr); break;
|
case 0x02: j(instr); break;
|
||||||
case 0x03: jal(instr); break;
|
case 0x03: jal(instr); break;
|
||||||
case 0x04: b(instr, gpr[RT(instr)] == gpr[RS(instr)]); break;
|
case 0x04: b(instr, (s32)gpr[RT(instr)] == (s32)gpr[RS(instr)]); break;
|
||||||
case 0x05: b(instr, gpr[RT(instr)] != gpr[RS(instr)]); break;
|
case 0x05: b(instr, (s32)gpr[RT(instr)] != (s32)gpr[RS(instr)]); break;
|
||||||
case 0x07: b(instr, gpr[RS(instr)] > 0); break;
|
case 0x06: b(instr, (s32)gpr[RS(instr)] <= 0); break;
|
||||||
|
case 0x07: b(instr, (s32)gpr[RS(instr)] > 0); break;
|
||||||
case 0x08: case 0x09: addi(instr); break;
|
case 0x08: case 0x09: addi(instr); break;
|
||||||
|
case 0x0A: slti(instr); break;
|
||||||
|
case 0x0B: sltiu(instr); break;
|
||||||
case 0x0C: andi(instr); break;
|
case 0x0C: andi(instr); break;
|
||||||
case 0x0D: ori(instr); break;
|
case 0x0D: ori(instr); break;
|
||||||
|
case 0x0E: xori(instr); break;
|
||||||
case 0x0F: lui(instr); break;
|
case 0x0F: lui(instr); break;
|
||||||
case 0x10: cop0(mi, regs, *this, rdp, instr); break;
|
case 0x10: cop0(mi, regs, *this, rdp, instr); break;
|
||||||
//case 0x12: cop2(*this, instr); break;
|
//case 0x12: cop2(*this, instr); break;
|
||||||
//case 0x21: lh(instr); break;
|
case 0x20: lb(instr); break;
|
||||||
case 0x23: lw(instr); break;
|
case 0x21: lh(instr); break;
|
||||||
//case 0x28: sb(instr); break;
|
case 0x23: case 0x27:
|
||||||
//case 0x29: sh(instr); break;
|
lw(instr);
|
||||||
|
break;
|
||||||
|
case 0x24: lbu(instr); break;
|
||||||
|
case 0x25: lhu(instr); break;
|
||||||
|
case 0x28: sb(instr); break;
|
||||||
|
case 0x29: sh(instr); break;
|
||||||
case 0x2B: sw(instr); break;
|
case 0x2B: sw(instr); break;
|
||||||
//case 0x32: lwc2(*this, instr); break;
|
//case 0x32: lwc2(*this, instr); break;
|
||||||
//case 0x3A: swc2(*this, instr); break;
|
//case 0x3A: swc2(*this, instr); break;
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ inline VPR GetVTE(VPR vt, u8 e) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RSP::add(u32 instr) {
|
void RSP::add(u32 instr) {
|
||||||
|
gpr[RD(instr)] = gpr[RS(instr)] + gpr[RT(instr)];
|
||||||
}
|
}
|
||||||
|
|
||||||
void RSP::addi(u32 instr) {
|
void RSP::addi(u32 instr) {
|
||||||
@@ -114,8 +114,19 @@ void RSP::b(u32 instr, bool cond) {
|
|||||||
branch(address, cond);
|
branch(address, cond);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RSP::lh(u32 instr) {
|
void RSP::bl(u32 instr, bool cond) {
|
||||||
|
b(instr, cond);
|
||||||
|
gpr[31] = pc + 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RSP::lb(u32 instr) {
|
||||||
|
u32 address = gpr[BASE(instr)] + (s16)instr;
|
||||||
|
gpr[RT(instr)] = (s32)(s8)ReadByte(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RSP::lh(u32 instr) {
|
||||||
|
u32 address = gpr[BASE(instr)] + (s16)instr;
|
||||||
|
gpr[RT(instr)] = (s32)(s16)ReadHalf(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RSP::lw(u32 instr) {
|
void RSP::lw(u32 instr) {
|
||||||
@@ -123,6 +134,16 @@ void RSP::lw(u32 instr) {
|
|||||||
gpr[RT(instr)] = ReadWord(address);
|
gpr[RT(instr)] = ReadWord(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RSP::lbu(u32 instr) {
|
||||||
|
u32 address = gpr[BASE(instr)] + (s16)instr;
|
||||||
|
gpr[RT(instr)] = ReadByte(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RSP::lhu(u32 instr) {
|
||||||
|
u32 address = gpr[BASE(instr)] + (s16)instr;
|
||||||
|
gpr[RT(instr)] = ReadHalf(address);
|
||||||
|
}
|
||||||
|
|
||||||
void RSP::lui(u32 instr) {
|
void RSP::lui(u32 instr) {
|
||||||
u32 imm = ((u16)instr) << 16;
|
u32 imm = ((u16)instr) << 16;
|
||||||
gpr[RT(instr)] = imm;
|
gpr[RT(instr)] = imm;
|
||||||
@@ -138,33 +159,53 @@ void RSP::j(u32 instr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RSP::jal(u32 instr) {
|
void RSP::jal(u32 instr) {
|
||||||
gpr[31] = nextPC;
|
|
||||||
j(instr);
|
j(instr);
|
||||||
|
gpr[31] = pc + 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RSP::jr(u32 instr) {
|
void RSP::jr(u32 instr) {
|
||||||
|
nextPC = gpr[RS(instr)];
|
||||||
|
}
|
||||||
|
|
||||||
|
void RSP::jalr(u32 instr) {
|
||||||
|
jr(instr);
|
||||||
|
gpr[RD(instr)] = pc + 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RSP::nor(u32 instr) {
|
void RSP::nor(u32 instr) {
|
||||||
|
gpr[RD(instr)] = ~(gpr[RT(instr)] | gpr[RS(instr)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RSP::ori(u32 instr) {
|
void RSP::ori(u32 instr) {
|
||||||
s16 imm = instr;
|
s32 op1 = gpr[RS(instr)];
|
||||||
gpr[RT(instr)] = imm | gpr[RS(instr)];
|
u32 op2 = instr & 0xffff;
|
||||||
|
s32 result = op1 | op2;
|
||||||
|
gpr[RT(instr)] = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RSP::xori(u32 instr) {
|
||||||
|
s32 op1 = gpr[RS(instr)];
|
||||||
|
u32 op2 = instr & 0xffff;
|
||||||
|
s32 result = op1 ^ op2;
|
||||||
|
gpr[RT(instr)] = result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RSP::or_(u32 instr) {
|
void RSP::or_(u32 instr) {
|
||||||
gpr[RD(instr)] = gpr[RT(instr)] | gpr[RS(instr)];
|
gpr[RD(instr)] = gpr[RT(instr)] | gpr[RS(instr)];
|
||||||
}
|
}
|
||||||
|
|
||||||
void RSP::sb(u32 instr) {
|
void RSP::xor_(u32 instr) {
|
||||||
|
gpr[RD(instr)] = gpr[RT(instr)] ^ gpr[RS(instr)];
|
||||||
|
}
|
||||||
|
|
||||||
|
void RSP::sb(u32 instr) {
|
||||||
|
u32 address = gpr[BASE(instr)] + (s16)instr;
|
||||||
|
WriteByte(address, gpr[RT(instr)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RSP::sh(u32 instr) {
|
void RSP::sh(u32 instr) {
|
||||||
|
u32 address = gpr[BASE(instr)] + (s16)instr;
|
||||||
|
WriteHalf(address, gpr[RT(instr)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RSP::sw(u32 instr) {
|
void RSP::sw(u32 instr) {
|
||||||
@@ -172,6 +213,10 @@ void RSP::sw(u32 instr) {
|
|||||||
WriteWord(address, gpr[RT(instr)]);
|
WriteWord(address, gpr[RT(instr)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RSP::sub(u32 instr) {
|
||||||
|
gpr[RD(instr)] = gpr[RS(instr)] - gpr[RT(instr)];
|
||||||
|
}
|
||||||
|
|
||||||
void RSP::sqv(u32 instr) {
|
void RSP::sqv(u32 instr) {
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -181,11 +226,49 @@ void RSP::sllv(u32 instr) {
|
|||||||
gpr[RD(instr)] = gpr[RT(instr)] << sa;
|
gpr[RD(instr)] = gpr[RT(instr)] << sa;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RSP::srlv(u32 instr) {
|
||||||
|
u8 sa = gpr[RS(instr)] & 0x1F;
|
||||||
|
gpr[RD(instr)] = (u32)gpr[RT(instr)] >> sa;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RSP::srav(u32 instr) {
|
||||||
|
u8 sa = gpr[RS(instr)] & 0x1F;
|
||||||
|
gpr[RD(instr)] = gpr[RT(instr)] >> sa;
|
||||||
|
}
|
||||||
|
|
||||||
void RSP::sll(u32 instr) {
|
void RSP::sll(u32 instr) {
|
||||||
u8 sa = (instr >> 6) & 0x1f;
|
u8 sa = (instr >> 6) & 0x1f;
|
||||||
gpr[RD(instr)] = gpr[RT(instr)] << sa;
|
gpr[RD(instr)] = gpr[RT(instr)] << sa;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RSP::srl(u32 instr) {
|
||||||
|
u8 sa = (instr >> 6) & 0x1f;
|
||||||
|
gpr[RD(instr)] = (u32)gpr[RT(instr)] >> sa;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RSP::sra(u32 instr) {
|
||||||
|
u8 sa = (instr >> 6) & 0x1f;
|
||||||
|
gpr[RD(instr)] = gpr[RT(instr)] >> sa;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RSP::slt(u32 instr) {
|
||||||
|
gpr[RD(instr)] = gpr[RS(instr)] < gpr[RT(instr)];
|
||||||
|
}
|
||||||
|
|
||||||
|
void RSP::sltu(u32 instr) {
|
||||||
|
gpr[RD(instr)] = (u32)gpr[RS(instr)] < (u32)gpr[RT(instr)];
|
||||||
|
}
|
||||||
|
|
||||||
|
void RSP::slti(u32 instr) {
|
||||||
|
s32 imm = (s16)instr;
|
||||||
|
gpr[RT(instr)] = gpr[RS(instr)] < imm;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RSP::sltiu(u32 instr) {
|
||||||
|
s32 imm = (s16)instr;
|
||||||
|
gpr[RT(instr)] = (u32)gpr[RS(instr)] < imm;
|
||||||
|
}
|
||||||
|
|
||||||
void RSP::vabs(u32 instr) {
|
void RSP::vabs(u32 instr) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user