From ce3789315aeff55ba1c863a0534fa3103e87c7ba Mon Sep 17 00:00:00 2001 From: CocoSimone Date: Sun, 11 Sep 2022 15:49:34 +0200 Subject: [PATCH] Fix exception in delay slot --- src/n64/Core.cpp | 3 - src/n64/core/Cpu.cpp | 23 ++----- src/n64/core/RSP.cpp | 17 +++--- src/n64/core/RSP.hpp | 50 ++++++++++++++-- src/n64/core/cpu/instructions.cpp | 82 ++++++++++++------------- src/n64/core/rsp/decode.cpp | 58 +++++++++++++----- src/n64/core/rsp/instructions.cpp | 99 ++++++++++++++++++++++++++++--- 7 files changed, 231 insertions(+), 101 deletions(-) diff --git a/src/n64/Core.cpp b/src/n64/Core.cpp index c76c0158..a866314e 100644 --- a/src/n64/Core.cpp +++ b/src/n64/Core.cpp @@ -53,9 +53,6 @@ void Core::Run(Window& window) { for(;cycles <= mmio.vi.cyclesPerHalfline; cycles++, frameCycles++) { 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.ai.Step(mem, cpu.regs, 1); } diff --git a/src/n64/core/Cpu.cpp b/src/n64/core/Cpu.cpp index 9af85720..df24faf9 100644 --- a/src/n64/core/Cpu.cpp +++ b/src/n64/core/Cpu.cpp @@ -41,7 +41,7 @@ void FireException(Registers& regs, ExceptionCode code, int cop, s64 pc) { bool old_exl = 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; pc -= 4; } else { @@ -94,30 +94,15 @@ void Cpu::Step(Mem& mem) { CheckCompareInterrupt(mem.mmio.mi, regs); HandleInterrupt(regs); - regs.prevDelaySlot = regs.delaySlot; - regs.delaySlot = false; - u32 instruction = mem.Read(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.pc = regs.nextPC; regs.nextPC += 4; Exec(mem, instruction); + + regs.prevDelaySlot = regs.delaySlot; + regs.delaySlot = false; } } \ No newline at end of file diff --git a/src/n64/core/RSP.cpp b/src/n64/core/RSP.cpp index 9cacc2a4..828479d4 100644 --- a/src/n64/core/RSP.cpp +++ b/src/n64/core/RSP.cpp @@ -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) { case 0x04040000: return spDMASPAddr.raw & 0xFFFFF8; case 0x04040004: return spDMADRAMAddr.raw & 0x1FF8; @@ -48,10 +48,11 @@ auto RSP::Read(u32 addr) const -> u32{ case 0x0404000C: return spDMAWRLen.raw; case 0x04040010: return spStatus.raw; case 0x04040018: return 0; - case 0x04080000: return pc & 0xFFF; - default: util::panic("Unimplemented SP register read %08X\n", addr); + case 0x0404001C: return AcquireSemaphore(); + case 0x04080000: + return pc & 0xFFC; + default: util::panic("Unimplemented SP register read {:08X}\n", addr); } - return 0; } template @@ -99,8 +100,7 @@ void RSP::Write(Mem& mem, Registers& regs, u32 addr, u32 value) { spDMAWRLen.raw = 0xFF8 | (spDMAWRLen.skip << 20); } break; case 0x04040010: { - SPStatusWrite write; - write.raw = value; + auto write = SPStatusWrite{.raw = value}; CLEAR_SET(spStatus.halt, write.clearHalt, write.setHalt); CLEAR_SET(spStatus.broke, write.clearBroke, false); 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.signal7Set, write.clearSignal7, write.setSignal7); } break; + case 0x0404001C: ReleaseSemaphore(); break; case 0x04080000: if(spStatus.halt) { - oldPC = pc; - pc = nextPC; + oldPC = pc & 0xFFC; + pc = value & 0xFFC; nextPC = value & 0xFFC; } break; default: util::panic("Unimplemented SP register write {:08X}, val: {:08X}\n", addr, value); diff --git a/src/n64/core/RSP.hpp b/src/n64/core/RSP.hpp index 3a221798..c4aa0e88 100644 --- a/src/n64/core/RSP.hpp +++ b/src/n64/core/RSP.hpp @@ -110,17 +110,17 @@ struct RSP { RSP(); void Reset(); 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 Exec(MI& mi, Registers& regs, RDP& rdp, u32 instr); SPStatus spStatus; - u16 oldPC{}, pc{}, nextPC = 4; + u16 oldPC{}, pc{}, nextPC{}; SPDMASPAddr spDMASPAddr{}; SPDMADRAMAddr spDMADRAMAddr{}; SPDMALen spDMARDLen{}, spDMAWRLen{}; u8 dmem[DMEM_SIZE]{}, imem[IMEM_SIZE]{}; VPR vpr[32]{}; - u32 gpr[32]{}; + s32 gpr[32]{}; u8 vce{}; struct { @@ -177,11 +177,24 @@ struct RSP { } inline u8 ReadByte(u32 addr) { - return GET_RSP_WORD(addr); + return RSP_BYTE(addr); } 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); @@ -190,22 +203,38 @@ struct RSP { void andi(u32 instr); void cfc2(u32 instr); void b(u32 instr, bool cond); + void bl(u32 instr, bool cond); + 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 lqv(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 sub(u32 instr); void sqv(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 vmov(u32 instr); void veq(u32 instr); @@ -216,7 +245,16 @@ struct RSP { private: inline void branch(u16 address, bool 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; } } }; diff --git a/src/n64/core/cpu/instructions.cpp b/src/n64/core/cpu/instructions.cpp index ea1e8a8d..f6c4e182 100644 --- a/src/n64/core/cpu/instructions.cpp +++ b/src/n64/core/cpu/instructions.cpp @@ -179,9 +179,9 @@ void Cpu::lb(Mem& mem, u32 instr) { } void Cpu::lh(Mem& mem, u32 instr) { - u32 address = regs.gpr[RS(instr)] + (s16)instr; - if ((address & 1) != 0) { - HandleTLBException(regs, s64(s32(address))); + s64 address = regs.gpr[RS(instr)] + (s16)instr; + if (((address & 1) != 0) || (address > 0)) { + HandleTLBException(regs, address); 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) { - u32 address = regs.gpr[RS(instr)] + (s16)instr; - if ((address & 3) != 0) { - HandleTLBException(regs, s64(s32(address))); + s64 address = regs.gpr[RS(instr)] + (s16)instr; + if (((address & 3) != 0) || (address > 0)) { + HandleTLBException(regs, address); 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) { - u32 address = regs.gpr[RS(instr)] + (s16)instr; - if ((address & 3) != 0) { - HandleTLBException(regs, s64(s32(address))); + s64 address = regs.gpr[RS(instr)] + (s16)instr; + if ((address & 3) != 0 || (address > 0)) { + HandleTLBException(regs, address); 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) { - u32 address = regs.gpr[RS(instr)] + (s16)instr; - if ((address & 7) != 0) { - HandleTLBException(regs, (s64)((s32)address)); + s64 address = regs.gpr[RS(instr)] + (s16)instr; + if ((address & 7) != 0 || (address > 0)) { + HandleTLBException(regs, address); 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) { - u32 address = regs.gpr[RS(instr)] + (s16)instr; - if ((address & 7) != 0) { - HandleTLBException(regs, (s64)((s32)address)); + s64 address = regs.gpr[RS(instr)] + (s16)instr; + if ((address & 7) != 0 || (address > 0)) { + HandleTLBException(regs, address); 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) { - u32 address = regs.gpr[RS(instr)] + (s16)instr; - if ((address & 1) != 0) { - HandleTLBException(regs, (s64)((s32)address)); + s64 address = regs.gpr[RS(instr)] + (s16)instr; + if ((address & 1) != 0 || (address > 0)) { + HandleTLBException(regs, address); 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) { - u32 address = regs.gpr[RS(instr)] + (s16)instr; - if ((address & 3) != 0) { - HandleTLBException(regs, (s64)((s32)address)); + s64 address = regs.gpr[RS(instr)] + (s16)instr; + if ((address & 3) != 0 || (address > 0)) { + HandleTLBException(regs, address); 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) { - u32 address = regs.gpr[RS(instr)] + (s16)instr; - if ((address & 3) != 0) { - HandleTLBException(regs, (s64)((s32)address)); + s64 address = regs.gpr[RS(instr)] + (s16)instr; + if ((address & 3) != 0 || (address > 0)) { + HandleTLBException(regs, address); 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) { - u32 address = regs.gpr[RS(instr)] + (s16)instr; - if ((address & 7) != 0) { - HandleTLBException(regs, (s64)((s32)address)); + s64 address = regs.gpr[RS(instr)] + (s16)instr; + if ((address & 7) != 0 || (address > 0)) { + HandleTLBException(regs, address); 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) { - u32 address = regs.gpr[RS(instr)] + (s16)instr; - if ((address & 1) != 0) { - HandleTLBException(regs, (s64)((s32)address)); + s64 address = regs.gpr[RS(instr)] + (s16)instr; + if ((address & 1) != 0 || (address > 0)) { + HandleTLBException(regs, address); 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) { - u32 address = regs.gpr[RS(instr)] + (s16)instr; - if ((address & 3) != 0) { - HandleTLBException(regs, (s64)((s32)address)); + s64 address = regs.gpr[RS(instr)] + (s16)instr; + if ((address & 3) != 0 || (address > 0)) { + HandleTLBException(regs, address); 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) { - u32 address = regs.gpr[RS(instr)] + (s16)instr; - if ((address & 7) != 0) { - HandleTLBException(regs, (s64)((s32)address)); + s64 address = regs.gpr[RS(instr)] + (s16)instr; + if ((address & 7) != 0 || (address > 0)) { + HandleTLBException(regs, address); FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC); } @@ -421,9 +421,9 @@ void Cpu::nor(u32 instr) { void Cpu::j(u32 instr) { s32 target = (instr & 0x3ffffff) << 2; - s32 address = (regs.oldPC & ~0xfffffff) | target; - if ((address & 3) != 0) { - HandleTLBException(regs, (s64)((s32)address)); + s64 address = (regs.oldPC & ~0xfffffff) | target; + if ((address & 3) != 0 || (address > 0)) { + HandleTLBException(regs, address); FireException(regs, ExceptionCode::DataBusError, 0, regs.oldPC); } @@ -578,8 +578,8 @@ void Cpu::dsra32(u32 instr) { } void Cpu::jr(u32 instr) { - s32 address = regs.gpr[RS(instr)]; - if ((address & 3) != 0) { + s64 address = regs.gpr[RS(instr)]; + if ((address & 3) != 0 || (address > 0)) { HandleTLBException(regs, address); FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC); } diff --git a/src/n64/core/rsp/decode.cpp b/src/n64/core/rsp/decode.cpp index 0d8042e1..c7d052c9 100644 --- a/src/n64/core/rsp/decode.cpp +++ b/src/n64/core/rsp/decode.cpp @@ -7,9 +7,18 @@ namespace n64 { inline void special(MI& mi, Registers& regs, RSP& rsp, u32 instr) { u8 mask = instr & 0x3f; 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 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 0x0D: rsp.spStatus.halt = true; @@ -18,12 +27,18 @@ inline void special(MI& mi, Registers& regs, RSP& rsp, u32 instr) { InterruptRaise(mi, regs, Interrupt::SP); } break; - //case 0x20: case 0x21: - // rsp.add(instr); - // break; + case 0x20: case 0x21: + rsp.add(instr); + break; + case 0x22: case 0x23: + rsp.sub(instr); + break; case 0x24: rsp.and_(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); } } @@ -31,9 +46,11 @@ inline void special(MI& mi, Registers& regs, RSP& rsp, u32 instr) { inline void regimm(RSP& rsp, u32 instr) { u8 mask = ((instr >> 16) & 0x1F); switch(mask) { - //case 0x00: 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 0x00: rsp.b(instr, (s32)rsp.gpr[RS(instr)] < 0); break; + case 0x01: rsp.b(instr, (s32)rsp.gpr[RS(instr)] >= 0); break; + 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 0x02: j(instr); break; case 0x03: jal(instr); break; - case 0x04: b(instr, gpr[RT(instr)] == gpr[RS(instr)]); break; - case 0x05: b(instr, gpr[RT(instr)] != gpr[RS(instr)]); break; - case 0x07: b(instr, gpr[RS(instr)] > 0); break; + case 0x04: b(instr, (s32)gpr[RT(instr)] == (s32)gpr[RS(instr)]); break; + case 0x05: b(instr, (s32)gpr[RT(instr)] != (s32)gpr[RS(instr)]); 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 0x0A: slti(instr); break; + case 0x0B: sltiu(instr); break; case 0x0C: andi(instr); break; case 0x0D: ori(instr); break; + case 0x0E: xori(instr); break; case 0x0F: lui(instr); break; case 0x10: cop0(mi, regs, *this, rdp, instr); break; //case 0x12: cop2(*this, instr); break; - //case 0x21: lh(instr); break; - case 0x23: lw(instr); break; - //case 0x28: sb(instr); break; - //case 0x29: sh(instr); break; + case 0x20: lb(instr); break; + case 0x21: lh(instr); break; + case 0x23: case 0x27: + 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 0x32: lwc2(*this, instr); break; //case 0x3A: swc2(*this, instr); break; diff --git a/src/n64/core/rsp/instructions.cpp b/src/n64/core/rsp/instructions.cpp index 44ee1c02..8cac1956 100644 --- a/src/n64/core/rsp/instructions.cpp +++ b/src/n64/core/rsp/instructions.cpp @@ -87,7 +87,7 @@ inline VPR GetVTE(VPR vt, u8 e) { } void RSP::add(u32 instr) { - + gpr[RD(instr)] = gpr[RS(instr)] + gpr[RT(instr)]; } void RSP::addi(u32 instr) { @@ -114,8 +114,19 @@ void RSP::b(u32 instr, bool 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) { @@ -123,6 +134,16 @@ void RSP::lw(u32 instr) { 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) { u32 imm = ((u16)instr) << 16; gpr[RT(instr)] = imm; @@ -138,33 +159,53 @@ void RSP::j(u32 instr) { } void RSP::jal(u32 instr) { - gpr[31] = nextPC; j(instr); + gpr[31] = pc + 4; } 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) { - + gpr[RD(instr)] = ~(gpr[RT(instr)] | gpr[RS(instr)]); } void RSP::ori(u32 instr) { - s16 imm = instr; - gpr[RT(instr)] = imm | gpr[RS(instr)]; + s32 op1 = 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) { 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) { - + u32 address = gpr[BASE(instr)] + (s16)instr; + WriteHalf(address, gpr[RT(instr)]); } void RSP::sw(u32 instr) { @@ -172,6 +213,10 @@ void RSP::sw(u32 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) { } @@ -181,11 +226,49 @@ void RSP::sllv(u32 instr) { 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) { u8 sa = (instr >> 6) & 0x1f; 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) { }