Files
kaizen/src/backend/core/interpreter/decode.cpp
2024-05-13 20:55:55 +02:00

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);
}
}
}