176 lines
6.8 KiB
C++
176 lines
6.8 KiB
C++
#include <core/Interpreter.hpp>
|
|
#include <log.hpp>
|
|
#include <CpuDefinitions.hpp>
|
|
|
|
namespace n64 {
|
|
void Interpreter::special(u32 instr) {
|
|
u8 mask = (instr & 0x3F);
|
|
// 00rr_rccc
|
|
switch (mask) { // TODO: named constants for clearer code
|
|
case SLL:
|
|
if (instr != 0) {
|
|
sll(instr);
|
|
}
|
|
break;
|
|
case SRL: srl(instr); break;
|
|
case SRA: sra(instr); break;
|
|
case SLLV: sllv(instr); break;
|
|
case SRLV: srlv(instr); break;
|
|
case SRAV: srav(instr); break;
|
|
case JR: jr(instr); break;
|
|
case JALR: jalr(instr); break;
|
|
case SYSCALL: regs.cop0.FireException(ExceptionCode::Syscall, 0, regs.oldPC); break;
|
|
case BREAK: regs.cop0.FireException(ExceptionCode::Breakpoint, 0, regs.oldPC); break;
|
|
case SYNC: break; // SYNC
|
|
case MFHI: mfhi(instr); break;
|
|
case MTHI: mthi(instr); break;
|
|
case MFLO: mflo(instr); break;
|
|
case MTLO: mtlo(instr); break;
|
|
case DSLLV: dsllv(instr); break;
|
|
case DSRLV: dsrlv(instr); break;
|
|
case DSRAV: dsrav(instr); break;
|
|
case MULT: mult(instr); break;
|
|
case MULTU: multu(instr); break;
|
|
case DIV: div(instr); break;
|
|
case DIVU: divu(instr); break;
|
|
case DMULT: dmult(instr); break;
|
|
case DMULTU: dmultu(instr); break;
|
|
case DDIV: ddiv(instr); break;
|
|
case DDIVU: ddivu(instr); break;
|
|
case ADD: add(instr); break;
|
|
case ADDU: addu(instr); break;
|
|
case SUB: sub(instr); break;
|
|
case SUBU: subu(instr); break;
|
|
case AND: and_(instr); break;
|
|
case OR: or_(instr); break;
|
|
case XOR: xor_(instr); break;
|
|
case NOR: nor(instr); break;
|
|
case SLT: slt(instr); break;
|
|
case SLTU: sltu(instr); break;
|
|
case DADD: dadd(instr); break;
|
|
case DADDU: daddu(instr); break;
|
|
case DSUB: dsub(instr); break;
|
|
case DSUBU: dsubu(instr); break;
|
|
case TGE: trap(regs.gpr[RS(instr)] >= regs.gpr[RT(instr)]); break;
|
|
case TGEU: trap((u64)regs.gpr[RS(instr)] >= (u64)regs.gpr[RT(instr)]); break;
|
|
case TLT: trap(regs.gpr[RS(instr)] < regs.gpr[RT(instr)]); break;
|
|
case TLTU: trap((u64)regs.gpr[RS(instr)] < (u64)regs.gpr[RT(instr)]); break;
|
|
case TEQ: trap(regs.gpr[RS(instr)] == regs.gpr[RT(instr)]); break;
|
|
case TNE: trap(regs.gpr[RS(instr)] != regs.gpr[RT(instr)]); break;
|
|
case DSLL: dsll(instr); break;
|
|
case DSRL: dsrl(instr); break;
|
|
case DSRA: dsra(instr); break;
|
|
case DSLL32: dsll32(instr); break;
|
|
case DSRL32: dsrl32(instr); break;
|
|
case DSRA32: dsra32(instr); break;
|
|
default:
|
|
Util::panic("Unimplemented special {} {} ({:08X}) (pc: {:016X})", (mask >> 3) & 7, mask & 7, instr, (u64)regs.oldPC);
|
|
}
|
|
}
|
|
|
|
void Interpreter::regimm(u32 instr) {
|
|
u8 mask = ((instr >> 16) & 0x1F);
|
|
// 000r_rccc
|
|
switch (mask) { // TODO: named constants for clearer code
|
|
case BLTZ: b(instr, regs.gpr[RS(instr)] < 0); break;
|
|
case BGEZ: b(instr, regs.gpr[RS(instr)] >= 0); break;
|
|
case BLTZL: bl(instr, regs.gpr[RS(instr)] < 0); break;
|
|
case BGEZL: bl(instr, regs.gpr[RS(instr)] >= 0); break;
|
|
case TGEI: trap(regs.gpr[RS(instr)] >= s64(s16(instr))); break;
|
|
case TGEIU: trap(u64(regs.gpr[RS(instr)]) >= u64(s64(s16(instr)))); break;
|
|
case TLTI: trap(regs.gpr[RS(instr)] < s64(s16(instr))); break;
|
|
case TLTIU: trap(u64(regs.gpr[RS(instr)]) < u64(s64(s16(instr)))); break;
|
|
case TEQI: trap(regs.gpr[RS(instr)] == s64(s16(instr))); break;
|
|
case TNEI: trap(regs.gpr[RS(instr)] != s64(s16(instr))); break;
|
|
case BLTZAL: blink(instr, regs.gpr[RS(instr)] < 0); break;
|
|
case BGEZAL: blink(instr, regs.gpr[RS(instr)] >= 0); break;
|
|
case BLTZALL: bllink(instr, regs.gpr[RS(instr)] < 0); break;
|
|
case BGEZALL: bllink(instr, regs.gpr[RS(instr)] >= 0); break;
|
|
default:
|
|
Util::panic("Unimplemented regimm {} {} ({:08X}) (pc: {:016X})", (mask >> 3) & 3, mask & 7, instr, (u64)regs.oldPC);
|
|
}
|
|
}
|
|
|
|
void Interpreter::cop2Decode(u32 instr) {
|
|
if(!regs.cop0.status.cu2) {
|
|
regs.cop0.FireException(ExceptionCode::CoprocessorUnusable, 2, regs.oldPC);
|
|
return;
|
|
}
|
|
switch(RS(instr)) {
|
|
case 0x00: mfc2(instr); break;
|
|
case 0x01: dmfc2(instr); break;
|
|
case 0x02: cfc2(instr); break;
|
|
case 0x04: mtc2(instr); break;
|
|
case 0x05: dmtc2(instr); break;
|
|
case 0x06: ctc2(instr); break;
|
|
default:
|
|
regs.cop0.FireException(ExceptionCode::ReservedInstruction, 2, regs.oldPC);
|
|
}
|
|
}
|
|
|
|
void Interpreter::Exec(u32 instr) {
|
|
u8 mask = (instr >> 26) & 0x3f;
|
|
// 00rr_rccc
|
|
switch(mask) { // TODO: named constants for clearer code
|
|
case SPECIAL: special(instr); break;
|
|
case REGIMM: regimm(instr); break;
|
|
case J: j(instr); break;
|
|
case JAL: jal(instr); break;
|
|
case BEQ: b(instr, regs.gpr[RS(instr)] == regs.gpr[RT(instr)]); break;
|
|
case BNE: {
|
|
//fmt::print("RS: {:016X}, RT: {:016X}", (u64)regs.gpr[RS(instr)], (u64)regs.gpr[RT(instr)]);
|
|
b(instr, regs.gpr[RS(instr)] != regs.gpr[RT(instr)]);
|
|
} break;
|
|
case BLEZ: b(instr, regs.gpr[RS(instr)] <= 0); break;
|
|
case BGTZ: b(instr, regs.gpr[RS(instr)] > 0); break;
|
|
case ADDI: addi(instr); break;
|
|
case ADDIU: addiu(instr); break;
|
|
case SLTI: slti(instr); break;
|
|
case SLTIU: sltiu(instr); break;
|
|
case ANDI: andi(instr); break;
|
|
case ORI: ori(instr); break;
|
|
case XORI: xori(instr); break;
|
|
case LUI: lui(instr); break;
|
|
case COP0: regs.cop0.decode(*this, instr); break;
|
|
case COP1: regs.cop1.decode(*this, instr); break;
|
|
case COP2: cop2Decode(instr); break;
|
|
case BEQL: bl(instr, regs.gpr[RS(instr)] == regs.gpr[RT(instr)]); break;
|
|
case BNEL: bl(instr, regs.gpr[RS(instr)] != regs.gpr[RT(instr)]); break;
|
|
case BLEZL: bl(instr, regs.gpr[RS(instr)] <= 0); break;
|
|
case BGTZL: bl(instr, regs.gpr[RS(instr)] > 0); break;
|
|
case DADDI: daddi(instr); break;
|
|
case DADDIU: daddiu(instr); break;
|
|
case LDL: ldl(instr); break;
|
|
case LDR: ldr(instr); break;
|
|
case 0x1F: regs.cop0.FireException(ExceptionCode::ReservedInstruction, 0, regs.oldPC); break;
|
|
case LB: lb(instr); break;
|
|
case LH: lh(instr); break;
|
|
case LWL: lwl(instr); break;
|
|
case LW: lw(instr); break;
|
|
case LBU: lbu(instr); break;
|
|
case LHU: lhu(instr); break;
|
|
case LWR: lwr(instr); break;
|
|
case LWU: lwu(instr); break;
|
|
case SB: sb(instr); break;
|
|
case SH: sh(instr); break;
|
|
case SWL: swl(instr); break;
|
|
case SW: sw(instr); break;
|
|
case SDL: sdl(instr); break;
|
|
case SDR: sdr(instr); break;
|
|
case SWR: swr(instr); break;
|
|
case CACHE: break; // CACHE
|
|
case LL: ll(instr); break;
|
|
case LWC1: regs.cop1.lwc1(*this, mem, instr); break;
|
|
case LLD: lld(instr); break;
|
|
case LDC1: regs.cop1.ldc1(*this, mem, instr); break;
|
|
case LD: ld(instr); break;
|
|
case SC: sc(instr); break;
|
|
case SWC1: regs.cop1.swc1(*this, mem, instr); break;
|
|
case SCD: scd(instr); break;
|
|
case SDC1: regs.cop1.sdc1(*this, mem, instr); break;
|
|
case SD: sd(instr); break;
|
|
default:
|
|
Util::panic("Unimplemented instruction {:02X} ({:08X}) (pc: {:016X})", mask, instr, (u64)regs.oldPC);
|
|
}
|
|
}
|
|
} |