* Add basic support for N64 RSP processor. This includes: * a table driven instruction decoder (rsp_idec) * a disassembler * a very primitive anal plugin
405 lines
20 KiB
C
405 lines
20 KiB
C
/* radare - LGPL - Copyright 2016 - bobby.smiles32@gmail.com */
|
|
|
|
#include "rsp_idec.h"
|
|
|
|
|
|
const char* rsp_gp_reg_soft_names[] = {
|
|
"zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
|
|
"t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
|
|
"s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
|
|
"t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
|
|
};
|
|
|
|
const char* rsp_c0_reg_soft_names[] = {
|
|
"SP_MEM_ADDR", "SP_DRAM_ADDR", "SP_RD_LEN", "SP_WR_LEN",
|
|
"SP_STATUS", "SP_DMA_FULL", "SP_DMA_BUSY", "SP_SEMAPHORE",
|
|
"DPC_START", "DPC_END", "DPC_CURRENT", "DPC_STATUS",
|
|
"DPC_CLOCK", "DPC_BUF_BUSY", "DPC_PIPE_BUSY", "DPC_TMEM_BUSY"
|
|
};
|
|
|
|
const char* rsp_gp_reg_names[] = {
|
|
"$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7",
|
|
"$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15",
|
|
"$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23",
|
|
"$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31",
|
|
};
|
|
|
|
const char* rsp_c0_reg_names[] = {
|
|
"$c0", "$c1", "$c2", "$c3", "$c4", "$c5", "$c6", "$c7",
|
|
"$c8", "$c9", "$c10", "$c11", "$c12", "$c13", "$c14", "$c15"
|
|
};
|
|
|
|
const char* rsp_c2_creg_names[] = {
|
|
"$vco", "$vcc", "$vce", "???"
|
|
};
|
|
|
|
const char* rsp_c2_accu_names[] = {
|
|
"ACC_H", "ACC_M", "ACC_L", "???"
|
|
};
|
|
|
|
const char* rsp_c2_vreg_names[] = {
|
|
"$v0", "$v1", "$v2", "$v3", "$v4", "$v5", "$v6", "$v7",
|
|
"$v8", "$v9", "$v10", "$v11", "$v12", "$v13", "$v14", "$v15",
|
|
"$v16", "$v17", "$v18", "$v19", "$v20", "$v21", "$v22", "$v23",
|
|
"$v24", "$v25", "$v26", "$v27", "$v28", "$v29", "$v30", "$v31"
|
|
};
|
|
|
|
const char* rsp_c2_vreg_element_names[] = {
|
|
"", "[?]", "[0q]", "[1q]", "[0h]", "[1h]", "[2h]", "[3h]",
|
|
"[0]", "[1]", "[2]", "[3]", "[4]", "[5]", "[6]", "[7]"
|
|
};
|
|
|
|
/* Operand decoders description */
|
|
#define RS_DECODER { RSP_OPND_GP_REG, 21, 0x1f, 0, 0, 0, 0, 0 }
|
|
#define RT_DECODER { RSP_OPND_GP_REG, 16, 0x1f, 0, 0, 0, 0, 0 }
|
|
#define RD_DECODER { RSP_OPND_GP_REG, 11, 0x1f, 0, 0, 0, 0, 0 }
|
|
#define SA_DECODER { RSP_OPND_SHIFT_AMOUNT, 6, 0x1f, 0, 0, 0, 0, 0 }
|
|
#define LUI_DECODER { RSP_OPND_ZIMM, 0, 0xffff, 16, 0, 0, 0, 0 }
|
|
#define ZIMM_DECODER { RSP_OPND_ZIMM, 0, 0xffff, 0, 0, 0, 0, 0 }
|
|
#define SIMM_DECODER { RSP_OPND_SIMM, 0, 0, 0, 0, 0xffff, 0x8000, 0 }
|
|
#define OFFSET_DECODER { RSP_OPND_OFFSET, 0, 0, 0, 0, 0xffff, 0x8000, 2 }
|
|
#define BASE_OFFSET_DECODER { RSP_OPND_BASE_OFFSET, 21, 0x1f, 0, 0, 0xffff, 0x8000, 0 }
|
|
#define TARGET_DECODER { RSP_OPND_TARGET, 0, 0x03ff, 2, 0, 0, 0, 0 }
|
|
#define C0_REG_DECODER { RSP_OPND_C0_REG, 11, 0x0f, 0, 0, 0, 0, 0 }
|
|
#define C2_CREG_DECODER { RSP_OPND_C2_CREG, 11, 0x03, 0, 0, 0, 0, 0 }
|
|
#define C2_ACCU_DECODER { RSP_OPND_C2_ACCU, 21, 0x03, 0, 0, 0, 0, 0 }
|
|
#define VS_DECODER { RSP_OPND_C2_VREG, 11, 0x1f, 0, 0, 0, 0, 0 }
|
|
#define VD_DECODER { RSP_OPND_C2_VREG, 6, 0x1f, 0, 0, 0, 0, 0 }
|
|
#define VT_BYTE_DECODER { RSP_OPND_C2_VREG_BYTE, 16, 0x1f, 0, 7, 0xf, 0, 0 }
|
|
#define VS_BYTE_DECODER { RSP_OPND_C2_VREG_BYTE, 11, 0x1f, 0, 7, 0xf, 0, 0 }
|
|
#define VT_SCALAR_DECODER { RSP_OPND_C2_VREG_SCALAR, 16, 0x1f, 0,21, 0x7, 0, 0 }
|
|
#define VD_SCALAR_DECODER { RSP_OPND_C2_VREG_SCALAR, 6, 0x1f, 0,11, 0x7, 0, 0 }
|
|
#define VT_ELEMENT_DECODER { RSP_OPND_C2_VREG_ELEMENT, 16, 0x1f, 0,21, 0xf, 0, 0 }
|
|
#define BASE_VOFFSET1_DECODER { RSP_OPND_BASE_OFFSET, 21, 0x1f, 0, 0, 0x7f, 0x40, 0 }
|
|
#define BASE_VOFFSET2_DECODER { RSP_OPND_BASE_OFFSET, 21, 0x1f, 0, 0, 0x7f, 0x40, 1 }
|
|
#define BASE_VOFFSET4_DECODER { RSP_OPND_BASE_OFFSET, 21, 0x1f, 0, 0, 0x7f, 0x40, 2 }
|
|
#define BASE_VOFFSET8_DECODER { RSP_OPND_BASE_OFFSET, 21, 0x1f, 0, 0, 0x7f, 0x40, 3 }
|
|
#define BASE_VOFFSET16_DECODER { RSP_OPND_BASE_OFFSET, 21, 0x1f, 0, 0, 0x7f, 0x40, 4 }
|
|
|
|
/* Operands description */
|
|
#define OPNDS_NONE 0,
|
|
#define OPNDS_TARGET 1, { TARGET_DECODER }
|
|
#define OPNDS_RS_OFFSET 2, { RS_DECODER, OFFSET_DECODER }
|
|
#define OPNDS_RS_RT_OFFSET 3, { RS_DECODER, RT_DECODER, OFFSET_DECODER }
|
|
#define OPNDS_RT_BASE_OFFSET 2, { RT_DECODER, BASE_OFFSET_DECODER }
|
|
#define OPNDS_RS 1, { RS_DECODER }
|
|
#define OPNDS_RT_LUI 2, { RT_DECODER, LUI_DECODER }
|
|
#define OPNDS_RT_RS_SIMM 3, { RT_DECODER, RS_DECODER, SIMM_DECODER }
|
|
#define OPNDS_RT_RS_ZIMM 3, { RT_DECODER, RS_DECODER, ZIMM_DECODER }
|
|
#define OPNDS_RD_RT_SA 3, { RD_DECODER, RT_DECODER, SA_DECODER }
|
|
#define OPNDS_RD_RT_RS 3, { RD_DECODER, RT_DECODER, RS_DECODER }
|
|
#define OPNDS_RD_RS_RT 3, { RD_DECODER, RS_DECODER, RT_DECODER }
|
|
#define OPNDS_RT_C0_REG 2, { RT_DECODER, C0_REG_DECODER }
|
|
#define OPNDS_RT_C2_CREG 2, { RT_DECODER, C2_CREG_DECODER }
|
|
#define OPNDS_RT_VSB 2, { RT_DECODER, VS_BYTE_DECODER }
|
|
#define OPNDS_VDS_VTS 2, { VD_SCALAR_DECODER, VT_SCALAR_DECODER }
|
|
#define OPNDS_VTB_BASE_OFFSET1 2, { VT_BYTE_DECODER, BASE_VOFFSET1_DECODER }
|
|
#define OPNDS_VTB_BASE_OFFSET2 2, { VT_BYTE_DECODER, BASE_VOFFSET2_DECODER }
|
|
#define OPNDS_VTB_BASE_OFFSET4 2, { VT_BYTE_DECODER, BASE_VOFFSET4_DECODER }
|
|
#define OPNDS_VTB_BASE_OFFSET8 2, { VT_BYTE_DECODER, BASE_VOFFSET8_DECODER }
|
|
#define OPNDS_VTB_BASE_OFFSET16 2, { VT_BYTE_DECODER, BASE_VOFFSET16_DECODER }
|
|
#define OPNDS_VD_VS_C2_ACCU 3, { VD_DECODER, VS_DECODER, C2_ACCU_DECODER }
|
|
#define OPNDS_VD_VS_VTE 3, { VD_DECODER, VS_DECODER, VT_ELEMENT_DECODER }
|
|
|
|
/* Instructions description */
|
|
#define INVALID { "invalid", RSP_OP_INVALID, OPNDS_NONE }
|
|
#define NOP { "nop", RSP_OP_NOP, OPNDS_NONE }
|
|
#define SLL { "sll", RSP_OP_SLL, OPNDS_RD_RT_SA }
|
|
#define SRL { "srl", RSP_OP_SRL, OPNDS_RD_RT_SA }
|
|
#define SRA { "sra", RSP_OP_SRA, OPNDS_RD_RT_SA }
|
|
#define SLLV { "sllv", RSP_OP_SLLV, OPNDS_RD_RT_RS }
|
|
#define SRLV { "srlv", RSP_OP_SRLV, OPNDS_RD_RT_RS }
|
|
#define SRAV { "srav", RSP_OP_SRAV, OPNDS_RD_RT_RS }
|
|
#define JR { "jr", RSP_OP_JR, OPNDS_RS }
|
|
#define BREAK { "break", RSP_OP_BREAK, OPNDS_NONE }
|
|
#define ADD { "add", RSP_OP_ADD, OPNDS_RD_RS_RT }
|
|
#define ADDU { "addu", RSP_OP_ADDU, OPNDS_RD_RS_RT }
|
|
#define SUB { "sub", RSP_OP_SUB, OPNDS_RD_RS_RT }
|
|
#define SUBU { "subu", RSP_OP_SUBU, OPNDS_RD_RS_RT }
|
|
#define AND { "and", RSP_OP_AND, OPNDS_RD_RS_RT }
|
|
#define OR { "or", RSP_OP_OR, OPNDS_RD_RS_RT }
|
|
#define XOR { "xor", RSP_OP_XOR, OPNDS_RD_RS_RT }
|
|
#define NOR { "nor", RSP_OP_NOR, OPNDS_RD_RS_RT }
|
|
#define SLT { "slt", RSP_OP_SLT, OPNDS_RD_RS_RT }
|
|
#define SLTU { "sltu", RSP_OP_SLTU, OPNDS_RD_RS_RT }
|
|
#define BLTZ { "bltz", RSP_OP_BLTZ, OPNDS_RS_OFFSET }
|
|
#define BGEZ { "bgez", RSP_OP_BGEZ, OPNDS_RS_OFFSET }
|
|
#define BLTZAL { "bltzal", RSP_OP_BLTZAL, OPNDS_RS_OFFSET }
|
|
#define BGEZAL { "bgezal", RSP_OP_BGEZAL, OPNDS_RS_OFFSET }
|
|
#define MFC0 { "mfc0", RSP_OP_MFC0, OPNDS_RT_C0_REG }
|
|
#define MTC0 { "mtc0", RSP_OP_MTC0, OPNDS_RT_C0_REG }
|
|
#define MFC2 { "mfc2", RSP_OP_MFC2, OPNDS_RT_VSB }
|
|
#define MTC2 { "mtc2", RSP_OP_MTC2, OPNDS_RT_VSB }
|
|
#define CFC2 { "cfc2", RSP_OP_CFC2, OPNDS_RT_C2_CREG }
|
|
#define CTC2 { "ctc2", RSP_OP_CTC2, OPNDS_RT_C2_CREG }
|
|
#define VMULF { "vmulf", RSP_OP_VMULF, OPNDS_VD_VS_VTE }
|
|
#define VMULU { "vmulu", RSP_OP_VMULU, OPNDS_VD_VS_VTE }
|
|
#define VMUDL { "vmudl", RSP_OP_VMUDL, OPNDS_VD_VS_VTE }
|
|
#define VMUDM { "vmudm", RSP_OP_VMUDM, OPNDS_VD_VS_VTE }
|
|
#define VMUDN { "vmudn", RSP_OP_VMUDN, OPNDS_VD_VS_VTE }
|
|
#define VMUDH { "vmudh", RSP_OP_VMUDH, OPNDS_VD_VS_VTE }
|
|
#define VMACF { "vmacf", RSP_OP_VMACF, OPNDS_VD_VS_VTE }
|
|
#define VMACU { "vmacu", RSP_OP_VMACU, OPNDS_VD_VS_VTE }
|
|
#define VMADL { "vmadl", RSP_OP_VMADL, OPNDS_VD_VS_VTE }
|
|
#define VMADM { "vmadm", RSP_OP_VMADM, OPNDS_VD_VS_VTE }
|
|
#define VMADN { "vmadn", RSP_OP_VMADN, OPNDS_VD_VS_VTE }
|
|
#define VMADH { "vmadh", RSP_OP_VMADH, OPNDS_VD_VS_VTE }
|
|
#define VADD { "vadd", RSP_OP_VADD, OPNDS_VD_VS_VTE }
|
|
#define VSUB { "vsub", RSP_OP_VSUB, OPNDS_VD_VS_VTE }
|
|
#define VABS { "vabs", RSP_OP_VABS, OPNDS_VD_VS_VTE }
|
|
#define VADDC { "vaddc", RSP_OP_VADDC, OPNDS_VD_VS_VTE }
|
|
#define VSUBC { "vsubc", RSP_OP_VSUBC, OPNDS_VD_VS_VTE }
|
|
#define VSAR { "vsar", RSP_OP_VSAR, OPNDS_VD_VS_C2_ACCU }
|
|
#define VLT { "vlt", RSP_OP_VLT, OPNDS_VD_VS_VTE }
|
|
#define VEQ { "veq", RSP_OP_VEQ, OPNDS_VD_VS_VTE }
|
|
#define VNE { "vne", RSP_OP_VNE, OPNDS_VD_VS_VTE }
|
|
#define VGE { "vge", RSP_OP_VGE, OPNDS_VD_VS_VTE }
|
|
#define VCL { "vcl", RSP_OP_VCL, OPNDS_VD_VS_VTE }
|
|
#define VCH { "vch", RSP_OP_VCH, OPNDS_VD_VS_VTE }
|
|
#define VCR { "vcr", RSP_OP_VCR, OPNDS_VD_VS_VTE }
|
|
#define VMRG { "vmrg", RSP_OP_VMRG, OPNDS_VD_VS_VTE }
|
|
#define VAND { "vand", RSP_OP_VAND, OPNDS_VD_VS_VTE }
|
|
#define VNAND { "vnand", RSP_OP_VNAND, OPNDS_VD_VS_VTE }
|
|
#define VOR { "vor", RSP_OP_VOR, OPNDS_VD_VS_VTE }
|
|
#define VNOR { "vnor", RSP_OP_VNOR, OPNDS_VD_VS_VTE }
|
|
#define VXOR { "vxor", RSP_OP_VXOR, OPNDS_VD_VS_VTE }
|
|
#define VNXOR { "vnxor", RSP_OP_VNXOR, OPNDS_VD_VS_VTE }
|
|
#define VRCP { "vrcp", RSP_OP_VRCP, OPNDS_VDS_VTS }
|
|
#define VRCPL { "vrcpl", RSP_OP_VRCPL, OPNDS_VDS_VTS }
|
|
#define VRCPH { "vrcph", RSP_OP_VRCPH, OPNDS_VDS_VTS }
|
|
#define VMOV { "vmov", RSP_OP_VMOV, OPNDS_VDS_VTS }
|
|
#define VRSQ { "vrsq", RSP_OP_VRSQ, OPNDS_VDS_VTS }
|
|
#define VRSQL { "vrsql", RSP_OP_VRSQL, OPNDS_VDS_VTS }
|
|
#define VRSQH { "vrsqh", RSP_OP_VRSQH, OPNDS_VDS_VTS }
|
|
#define VNOP { "vnop", RSP_OP_VNOP, OPNDS_NONE }
|
|
#define LBV { "lbv", RSP_OP_LBV, OPNDS_VTB_BASE_OFFSET1 }
|
|
#define LSV { "lsv", RSP_OP_LSV, OPNDS_VTB_BASE_OFFSET2 }
|
|
#define LLV { "llv", RSP_OP_LLV, OPNDS_VTB_BASE_OFFSET4 }
|
|
#define LDV { "ldv", RSP_OP_LDV, OPNDS_VTB_BASE_OFFSET8 }
|
|
#define LQV { "lqv", RSP_OP_LQV, OPNDS_VTB_BASE_OFFSET16 }
|
|
#define LRV { "lrv", RSP_OP_LRV, OPNDS_VTB_BASE_OFFSET16 }
|
|
#define LPV { "lpv", RSP_OP_LPV, OPNDS_VTB_BASE_OFFSET8 }
|
|
#define LUV { "luv", RSP_OP_LUV, OPNDS_VTB_BASE_OFFSET8 }
|
|
#define LHV { "lhv", RSP_OP_LHV, OPNDS_VTB_BASE_OFFSET16 }
|
|
#define LFV { "lfv", RSP_OP_LFV, OPNDS_VTB_BASE_OFFSET16 }
|
|
#define LTV { "ltv", RSP_OP_LTV, OPNDS_VTB_BASE_OFFSET16 }
|
|
#define SBV { "sbv", RSP_OP_SBV, OPNDS_VTB_BASE_OFFSET1 }
|
|
#define SSV { "ssv", RSP_OP_SSV, OPNDS_VTB_BASE_OFFSET2 }
|
|
#define SLV { "slv", RSP_OP_SLV, OPNDS_VTB_BASE_OFFSET4 }
|
|
#define SDV { "sdv", RSP_OP_SDV, OPNDS_VTB_BASE_OFFSET8 }
|
|
#define SQV { "sqv", RSP_OP_SQV, OPNDS_VTB_BASE_OFFSET16 }
|
|
#define SRV { "srv", RSP_OP_SRV, OPNDS_VTB_BASE_OFFSET8 }
|
|
#define SPV { "spv", RSP_OP_SPV, OPNDS_VTB_BASE_OFFSET8 }
|
|
#define SUV { "suv", RSP_OP_SUV, OPNDS_VTB_BASE_OFFSET16 }
|
|
#define SHV { "shv", RSP_OP_SHV, OPNDS_VTB_BASE_OFFSET16 }
|
|
#define SFV { "sfv", RSP_OP_SFV, OPNDS_VTB_BASE_OFFSET16 }
|
|
#define SWV { "swv", RSP_OP_SWV, OPNDS_VTB_BASE_OFFSET16 }
|
|
#define STV { "stv", RSP_OP_STV, OPNDS_VTB_BASE_OFFSET16 }
|
|
#define J { "j", RSP_OP_J, OPNDS_TARGET }
|
|
#define JAL { "jal", RSP_OP_JAL, OPNDS_TARGET }
|
|
#define BEQ { "beq", RSP_OP_BEQ, OPNDS_RS_RT_OFFSET }
|
|
#define BNE { "bne", RSP_OP_BNE, OPNDS_RS_RT_OFFSET }
|
|
#define BLEZ { "blez", RSP_OP_BLEZ, OPNDS_RS_RT_OFFSET }
|
|
#define BGTZ { "bgtz", RSP_OP_BGTZ, OPNDS_RS_RT_OFFSET }
|
|
#define ADDI { "addi", RSP_OP_ADDI, OPNDS_RT_RS_SIMM }
|
|
#define ADDIU { "addiu", RSP_OP_ADDIU, OPNDS_RT_RS_SIMM }
|
|
#define SLTI { "slti", RSP_OP_SLTI, OPNDS_RT_RS_SIMM }
|
|
#define SLTIU { "sltiu", RSP_OP_SLTIU, OPNDS_RT_RS_SIMM }
|
|
#define ANDI { "andi", RSP_OP_ANDI, OPNDS_RT_RS_ZIMM }
|
|
#define ORI { "ori", RSP_OP_ORI, OPNDS_RT_RS_ZIMM }
|
|
#define XORI { "xori", RSP_OP_XORI, OPNDS_RT_RS_ZIMM }
|
|
#define LUI { "lui", RSP_OP_LUI, OPNDS_RT_LUI }
|
|
#define LB { "lb", RSP_OP_LB, OPNDS_RT_BASE_OFFSET }
|
|
#define LH { "lh", RSP_OP_LH, OPNDS_RT_BASE_OFFSET }
|
|
#define LW { "lw", RSP_OP_LW, OPNDS_RT_BASE_OFFSET }
|
|
#define LBU { "lbu", RSP_OP_LBU, OPNDS_RT_BASE_OFFSET }
|
|
#define LHU { "lhu", RSP_OP_LHU, OPNDS_RT_BASE_OFFSET }
|
|
#define SB { "sb", RSP_OP_SB, OPNDS_RT_BASE_OFFSET }
|
|
#define SH { "sh", RSP_OP_SH, OPNDS_RT_BASE_OFFSET }
|
|
#define SW { "sw", RSP_OP_SW, OPNDS_RT_BASE_OFFSET }
|
|
|
|
typedef struct {
|
|
rsp_operand_type type;
|
|
unsigned int u_shift;
|
|
ut32 u_mask;
|
|
unsigned int u_lshift;
|
|
unsigned int s_shift;
|
|
ut32 s_mask;
|
|
ut32 s_smask;
|
|
unsigned int s_lshift;
|
|
} rsp_operand_decoder;
|
|
|
|
typedef struct {
|
|
const char* mnemonic;
|
|
rsp_opcode opcode;
|
|
int noperands;
|
|
rsp_operand_decoder odecs[RSP_MAX_OPNDS];
|
|
} rsp_instruction_priv;
|
|
|
|
static const rsp_instruction_priv rsp_op_table[] = {
|
|
/* SPECIAL opcodes table
|
|
* 0-63
|
|
*/
|
|
SLL, INVALID, SRL, SRA, SLLV, INVALID, SRLV, SRAV,
|
|
JR, INVALID, INVALID, INVALID, INVALID, BREAK, INVALID, INVALID,
|
|
INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID,
|
|
INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID,
|
|
ADD, ADDU, SUB, SUBU, AND, OR, XOR, NOR,
|
|
INVALID, INVALID, SLT, SLTU, INVALID, INVALID, INVALID, INVALID,
|
|
INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID,
|
|
INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID,
|
|
/* REGIMM opcodes table
|
|
* 64-95
|
|
*/
|
|
BLTZ, BGEZ, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID,
|
|
INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID,
|
|
BLTZAL, BGEZAL, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID,
|
|
INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID,
|
|
/* COP0 opcodes table
|
|
* 96-127
|
|
*/
|
|
MFC0, INVALID, INVALID, INVALID, MTC0, INVALID, INVALID, INVALID,
|
|
INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID,
|
|
INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID,
|
|
INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID,
|
|
/* COP2/1 opcodes table
|
|
* 128-159
|
|
*/
|
|
MFC2, INVALID, CFC2, INVALID, MTC2, INVALID, CTC2, INVALID,
|
|
INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID,
|
|
INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID,
|
|
INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID,
|
|
/* COP2/2 opcodes table
|
|
* 160-223
|
|
*/
|
|
VMULF, VMULU, INVALID, INVALID, VMUDL, VMUDM, VMUDN, VMUDH,
|
|
VMACF, VMACU, INVALID, INVALID, VMADL, VMADM, VMADN, VMADH,
|
|
VADD, VSUB, INVALID, VABS, VADDC, VSUBC, INVALID, INVALID,
|
|
INVALID, INVALID, INVALID, INVALID, INVALID, VSAR, INVALID, INVALID,
|
|
VLT, VEQ, VNE, VGE, VCL, VCH, VCR, VMRG,
|
|
VAND, VNAND, VOR, VNOR, VXOR, VNXOR, INVALID, INVALID,
|
|
VRCP, VRCPL, VRCPH, VMOV, VRSQ, VRSQL, VRSQH, VNOP,
|
|
INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID,
|
|
/* LWC2 opcodes table
|
|
* 224-255
|
|
*/
|
|
LBV, LSV, LLV, LDV, LQV, LRV, LPV, LUV,
|
|
LHV, LFV, INVALID, LTV, INVALID, INVALID, INVALID, INVALID,
|
|
INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID,
|
|
INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID,
|
|
/* SWC2 opcodes table
|
|
* 256-287
|
|
*/
|
|
SBV, SSV, SLV, SDV, SQV, SRV, SPV, SUV,
|
|
SHV, SFV, SWV, STV, INVALID, INVALID, INVALID, INVALID,
|
|
INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID,
|
|
INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID,
|
|
/* Main opcodes table
|
|
* 288-351
|
|
*/
|
|
INVALID, INVALID, J, JAL, BEQ, BNE, BLEZ, BGTZ,
|
|
ADDI, ADDIU, SLTI, SLTIU, ANDI, ORI, XORI, LUI,
|
|
INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID,
|
|
INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID,
|
|
LB, LH, INVALID, LW, LBU, LHU, INVALID, INVALID,
|
|
SB, SH, INVALID, SW, INVALID, INVALID, INVALID, INVALID,
|
|
INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID,
|
|
INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID,
|
|
/* Pseudo opcodes
|
|
* 352 - ???
|
|
*/
|
|
NOP
|
|
};
|
|
|
|
#define SPECIAL { 0, 0, 0x3f }
|
|
#define REGIMM { 64, 16, 0x1f }
|
|
#define COP0 { 96, 21, 0x1f }
|
|
#define COP2 { 128, 21, 0x1f }
|
|
#define VECTOP { 160, 0, 0x3f }
|
|
#define LWC2 { 224, 11, 0x1f }
|
|
#define SWC2 { 256, 11, 0x1f }
|
|
#define MAIN { 288, 26, 0x3f }
|
|
|
|
typedef struct {
|
|
ut16 offset;
|
|
ut8 shift;
|
|
ut8 mask;
|
|
} rsp_op_escape;
|
|
|
|
static const rsp_op_escape rsp_escapes_table[] = {
|
|
SPECIAL, SPECIAL, REGIMM, REGIMM, MAIN, MAIN, MAIN, MAIN,
|
|
MAIN, MAIN, MAIN, MAIN, MAIN, MAIN, MAIN, MAIN,
|
|
MAIN, MAIN, MAIN, MAIN, MAIN, MAIN, MAIN, MAIN,
|
|
MAIN, MAIN, MAIN, MAIN, MAIN, MAIN, MAIN, MAIN,
|
|
COP0, COP0, MAIN, MAIN, COP2, VECTOP, MAIN, MAIN,
|
|
MAIN, MAIN, MAIN, MAIN, MAIN, MAIN, MAIN, MAIN,
|
|
MAIN, MAIN, MAIN, MAIN, MAIN, MAIN, MAIN, MAIN,
|
|
MAIN, MAIN, MAIN, MAIN, MAIN, MAIN, MAIN, MAIN,
|
|
MAIN, MAIN, MAIN, MAIN, MAIN, MAIN, MAIN, MAIN,
|
|
MAIN, MAIN, MAIN, MAIN, MAIN, MAIN, MAIN, MAIN,
|
|
MAIN, MAIN, MAIN, MAIN, MAIN, MAIN, MAIN, MAIN,
|
|
MAIN, MAIN, MAIN, MAIN, MAIN, MAIN, MAIN, MAIN,
|
|
MAIN, MAIN, MAIN, MAIN, LWC2, LWC2, MAIN, MAIN,
|
|
MAIN, MAIN, MAIN, MAIN, MAIN, MAIN, MAIN, MAIN,
|
|
MAIN, MAIN, MAIN, MAIN, SWC2, SWC2, MAIN, MAIN,
|
|
MAIN, MAIN, MAIN, MAIN, MAIN, MAIN, MAIN, MAIN
|
|
};
|
|
|
|
|
|
static const rsp_instruction_priv* rsp_decode_priv(ut32 iw) {
|
|
const rsp_op_escape* escape;
|
|
|
|
/* handle NOP pseudo instruction */
|
|
if (iw == 0) {
|
|
return &rsp_op_table[352];
|
|
}
|
|
|
|
escape = &rsp_escapes_table[(iw >> 25)];
|
|
return &rsp_op_table[escape->offset + ((iw >> escape->shift) & escape->mask)];
|
|
}
|
|
|
|
static inline st32 rsp_sign_extend(st32 x, st32 m)
|
|
{
|
|
/* assume that bits of x above the m are already zeros
|
|
* which is the case when called from rsp_operand_decode
|
|
*/
|
|
return (x ^ m) - m;
|
|
}
|
|
|
|
static rsp_operand rsp_operand_decode(ut64 pc, ut32 iw, const rsp_operand_decoder* odec) {
|
|
rsp_operand opnd;
|
|
|
|
opnd.type = odec->type;
|
|
opnd.u = ((iw >> odec->u_shift) & odec->u_mask) << odec->u_lshift;
|
|
opnd.s = rsp_sign_extend ((iw >> odec->s_shift) & odec->s_mask, odec->s_smask) << odec->s_lshift;
|
|
|
|
/* handle targets/offsets IMEM addresses */
|
|
switch (opnd.type) {
|
|
case RSP_OPND_TARGET:
|
|
opnd.u = rsp_mem_addr (opnd.u, RSP_IMEM_OFFSET);
|
|
break;
|
|
case RSP_OPND_OFFSET:
|
|
/* +4 for delay slot */
|
|
opnd.u = rsp_mem_addr (pc + 4 + opnd.s, RSP_IMEM_OFFSET);
|
|
break;
|
|
default: /* do nothing */ break;
|
|
}
|
|
|
|
return opnd;
|
|
}
|
|
|
|
rsp_instruction rsp_instruction_decode(ut64 pc, ut32 iw) {
|
|
int opnd;
|
|
const rsp_instruction_priv* priv = rsp_decode_priv (iw);
|
|
|
|
rsp_instruction r_instr;
|
|
|
|
r_instr.mnemonic = priv->mnemonic;
|
|
r_instr.opcode = priv->opcode;
|
|
r_instr.noperands = priv->noperands;
|
|
for (opnd = 0; opnd < r_instr.noperands; ++opnd) {
|
|
r_instr.operands[opnd] = rsp_operand_decode (pc, iw, &priv->odecs[opnd]);
|
|
}
|
|
|
|
return r_instr;
|
|
}
|