#include "insn.h" #include #include #include "cpu.h" #include "log.h" #define TABLE_SIZE 0x34 #define BITS(x, start, len) (((x) >> (start)) & ((1 << (len)) - 1)) #define OP(insn) BITS(insn, 26, 6) #define RS(insn) BITS(insn, 21, 5) #define RT(insn) BITS(insn, 16, 5) #define RD(insn) BITS(insn, 11, 5) #define COMMENT(insn) BITS(insn, 6, 20) #define IMM5(insn) BITS(insn, 6, 5) #define OP2(insn) BITS(insn, 0, 6) #define IMM(insn) BITS(insn, 0, 16) static cpu_insn_handler primary_insn_handler[TABLE_SIZE]; static cpu_insn_handler secondary_insn_handler[TABLE_SIZE]; void insn_execute(cpu_t *cpu, uint32_t insn) { const op_primary_t op = OP(insn); if (op == SPECIAL) { const op_secondary_t op2 = OP2(insn); if (op2 > TABLE_SIZE || secondary_insn_handler[op2] == NULL) { fatal("Unsupported instruction: insn=%08x, op=%02x, op2=%02x", insn, op, op2); } secondary_insn_handler[op2](cpu, insn); return; } if (op > TABLE_SIZE || primary_insn_handler[op] == NULL) { fatal("Unsupported instruction: insn=%08x, op=%02x", insn, op); } primary_insn_handler[op](cpu, insn); } void insn_lw(cpu_t *cpu, uint32_t insn) { const uint8_t rt = RT(insn); const uint8_t rs = RS(insn); const uint16_t imm = IMM(insn); debug("LW %s, [%s + %x]", REG_NAMES[rt], REG_NAMES[rs], imm); cpu->regs[rt] = cpu_read32(cpu, cpu->regs[rs] + imm); } void insn_srl(cpu_t *cpu, uint32_t insn) { const uint8_t rd = RD(insn); const uint8_t rt = RT(insn); const uint8_t imm5 = IMM5(insn); debug("SRL %s, %s, %u", REG_NAMES[rd], REG_NAMES[rt], imm5); cpu->regs[rd] = cpu->regs[rt] >> imm5; } void insn_addu(cpu_t *cpu, uint32_t insn) { const uint8_t rd = RD(insn); const uint8_t rs = RS(insn); const uint8_t rt = RT(insn); debug("ADDU %s, %s, %s", REG_NAMES[rd], REG_NAMES[rs], REG_NAMES[rt]); cpu->regs[rd] = cpu->regs[rs] + cpu->regs[rt]; } void insn_addiu(cpu_t *cpu, uint32_t insn) { const uint8_t rt = RT(insn); const uint8_t rs = RS(insn); const int16_t imm = (int16_t)IMM(insn); debug("ADDIU %s, %s, %x", REG_NAMES[rt], REG_NAMES[rs], imm); cpu->regs[rt] = cpu->regs[rs] + imm; } void insn_sw(cpu_t *cpu, uint32_t insn) { const uint8_t rt = RT(insn); const uint8_t rs = RS(insn); const uint16_t imm = IMM(insn); debug("SW %s, [%s + %x]", REG_NAMES[rt], REG_NAMES[rt], imm); cpu_write32(cpu, cpu->regs[rt], imm + cpu->regs[rs]); } void insn_sll(cpu_t *cpu, uint32_t insn) { const uint8_t rd = RD(insn); const uint8_t rt = RT(insn); const uint8_t imm5 = IMM5(insn); debug("SLL %s, %s, %u", REG_NAMES[rd], REG_NAMES[rt], imm5); cpu->regs[rd] = cpu->regs[rt] << imm5; } static cpu_insn_handler primary_insn_handler[TABLE_SIZE] = { [LW] = insn_lw, [ADDIU] = insn_addiu, [SW] = insn_sw, }; static cpu_insn_handler secondary_insn_handler[TABLE_SIZE] = { [SLL] = insn_sll, [ADDU] = insn_addu, [SRL] = insn_srl, };