mirror of
https://github.com/radareorg/radare2.git
synced 2025-02-21 06:40:33 +00:00
Add basic support for N64 RSP processor. (#5269)
* Add basic support for N64 RSP processor. This includes: * a table driven instruction decoder (rsp_idec) * a disassembler * a very primitive anal plugin
This commit is contained in:
parent
87ccfd34f5
commit
622e828e1d
@ -12,7 +12,7 @@ all: ${ALL_TARGETS} ;
|
||||
|
||||
ALL_TARGETS=
|
||||
# TODO: rename to enabled plugins
|
||||
ARCHS=null.mk x86_udis.mk ppc_gnu.mk ppc_cs.mk arm_gnu.mk avr.mk csr.mk dalvik.mk sh.mk ebc.mk gb.mk malbolge.mk ws.mk h8300.mk cr16.mk v850.mk msp430.mk sparc_gnu.mk sparc_cs.mk x86_cs.mk cris.mk 6502.mk snes.mk riscv.mk vax.mk xtensa.mk
|
||||
ARCHS=null.mk x86_udis.mk ppc_gnu.mk ppc_cs.mk arm_gnu.mk avr.mk csr.mk dalvik.mk sh.mk ebc.mk gb.mk malbolge.mk ws.mk h8300.mk cr16.mk v850.mk msp430.mk sparc_gnu.mk sparc_cs.mk x86_cs.mk cris.mk 6502.mk snes.mk riscv.mk vax.mk xtensa.mk rsp.mk
|
||||
include $(ARCHS)
|
||||
|
||||
clean:
|
||||
|
699
libr/anal/p/anal_rsp.c
Normal file
699
libr/anal/p/anal_rsp.c
Normal file
@ -0,0 +1,699 @@
|
||||
/* radare - LGPL - Copyright 2016 - bobby.smiles32@gmail.com */
|
||||
/*
|
||||
* TODO: finish esil support of the non vector instructions
|
||||
* TODO: implement vector instruction using custom esil commands
|
||||
* (will be easier than pure esil approach)
|
||||
* TODO: refactor code to simplify per opcode analysis
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <r_types.h>
|
||||
#include <r_lib.h>
|
||||
#include <r_asm.h>
|
||||
#include <r_anal.h>
|
||||
|
||||
#include "rsp_idec.h"
|
||||
|
||||
|
||||
static int rsp_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *b, int len) {
|
||||
int i;
|
||||
struct {
|
||||
RAnalValue* value;
|
||||
char esil[32];
|
||||
} parsed_operands[RSP_MAX_OPNDS];
|
||||
ut32 iw;
|
||||
rsp_instruction r_instr;
|
||||
|
||||
if (!op) {
|
||||
return 4;
|
||||
}
|
||||
|
||||
memset (op, 0, sizeof (RAnalOp));
|
||||
op->type = R_ANAL_OP_TYPE_UNK;
|
||||
op->size = 4;
|
||||
op->jump = UT64_MAX;
|
||||
op->fail = UT64_MAX;
|
||||
op->addr = addr;
|
||||
r_strbuf_init (&op->esil);
|
||||
r_strbuf_set (&op->esil, "TODO");
|
||||
|
||||
iw = r_read_ble32 (b, anal->big_endian);
|
||||
r_instr = rsp_instruction_decode (addr, iw);
|
||||
|
||||
/* parse operands */
|
||||
for (i = 0; i < r_instr.noperands; ++i) {
|
||||
|
||||
parsed_operands[i].value = r_anal_value_new ();
|
||||
parsed_operands[i].esil[0] = '\0';
|
||||
|
||||
switch (r_instr.operands[i].type) {
|
||||
case RSP_OPND_GP_REG:
|
||||
snprintf (parsed_operands[i].esil, sizeof (parsed_operands[i].esil), "%s", rsp_gp_reg_soft_names[r_instr.operands[i].u]);
|
||||
parsed_operands[i].value->reg = r_reg_get (anal->reg, rsp_gp_reg_soft_names[r_instr.operands[i].u], R_REG_TYPE_GPR);
|
||||
break;
|
||||
case RSP_OPND_ZIMM:
|
||||
case RSP_OPND_SHIFT_AMOUNT:
|
||||
snprintf (parsed_operands[i].esil, sizeof (parsed_operands[i].esil), "%u", r_instr.operands[i].u);
|
||||
parsed_operands[i].value->imm = op->val = r_instr.operands[i].u;
|
||||
break;
|
||||
case RSP_OPND_SIMM:
|
||||
snprintf (parsed_operands[i].esil, sizeof (parsed_operands[i].esil), "%d", r_instr.operands[i].s);
|
||||
parsed_operands[i].value->imm = op->val = r_instr.operands[i].s;
|
||||
break;
|
||||
case RSP_OPND_BASE_OFFSET:
|
||||
snprintf (parsed_operands[i].esil, sizeof (parsed_operands[i].esil),
|
||||
"%d,%s,+", r_instr.operands[i].s, rsp_gp_reg_soft_names[r_instr.operands[i].u]);
|
||||
parsed_operands[i].value->reg = r_reg_get (anal->reg, rsp_gp_reg_soft_names[r_instr.operands[i].u], R_REG_TYPE_GPR);
|
||||
parsed_operands[i].value->imm = r_instr.operands[i].s;
|
||||
break;
|
||||
case RSP_OPND_OFFSET:
|
||||
case RSP_OPND_TARGET:
|
||||
op->delay = 1;
|
||||
op->jump = r_instr.operands[i].u;
|
||||
op->fail = rsp_mem_addr (addr + 8, RSP_IMEM_OFFSET);
|
||||
op->eob = 1;
|
||||
snprintf (parsed_operands[i].esil, sizeof (parsed_operands[i].esil), "%u", r_instr.operands[i].u);
|
||||
parsed_operands[i].value->imm = r_instr.operands[i].u;
|
||||
parsed_operands[i].value->memref = 4;
|
||||
break;
|
||||
case RSP_OPND_C0_REG:
|
||||
snprintf (parsed_operands[i].esil, sizeof (parsed_operands[i].esil), "%s", rsp_c0_reg_names[r_instr.operands[i].u]);
|
||||
parsed_operands[i].value->reg = r_reg_get (anal->reg, rsp_c0_reg_names[r_instr.operands[i].u], R_REG_TYPE_GPR);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (r_instr.opcode) {
|
||||
case RSP_OP_INVALID:
|
||||
op->type = R_ANAL_OP_TYPE_ILL;
|
||||
break;
|
||||
case RSP_OP_NOP:
|
||||
op->type = R_ANAL_OP_TYPE_NOP;
|
||||
r_strbuf_set (&op->esil, ",");
|
||||
break;
|
||||
case RSP_OP_BREAK:
|
||||
op->type = R_ANAL_OP_TYPE_TRAP;
|
||||
// TODO
|
||||
break;
|
||||
case RSP_OP_LUI:
|
||||
op->type = R_ANAL_OP_TYPE_MOV;
|
||||
op->dst = parsed_operands[0].value;
|
||||
op->src[0] = parsed_operands[1].value;
|
||||
r_strbuf_setf (&op->esil, "%s,%s,=", parsed_operands[1].esil, parsed_operands[0].esil);
|
||||
break;
|
||||
case RSP_OP_ADD:
|
||||
case RSP_OP_ADDU:
|
||||
case RSP_OP_ADDI:
|
||||
case RSP_OP_ADDIU:
|
||||
op->type = R_ANAL_OP_TYPE_ADD;
|
||||
op->dst = parsed_operands[0].value;
|
||||
op->src[0] = parsed_operands[1].value;
|
||||
op->src[1] = parsed_operands[2].value;
|
||||
r_strbuf_setf (&op->esil, "%s,%s,+,%s,=", parsed_operands[2].esil, parsed_operands[1].esil, parsed_operands[0].esil);
|
||||
break;
|
||||
case RSP_OP_SUB:
|
||||
case RSP_OP_SUBU:
|
||||
op->type = R_ANAL_OP_TYPE_SUB;
|
||||
op->dst = parsed_operands[0].value;
|
||||
op->src[0] = parsed_operands[1].value;
|
||||
op->src[1] = parsed_operands[2].value;
|
||||
r_strbuf_setf (&op->esil, "%s,%s,-,%s,=", parsed_operands[2].esil, parsed_operands[1].esil, parsed_operands[0].esil);
|
||||
break;
|
||||
case RSP_OP_AND:
|
||||
case RSP_OP_ANDI:
|
||||
op->type = R_ANAL_OP_TYPE_AND;
|
||||
op->dst = parsed_operands[0].value;
|
||||
op->src[0] = parsed_operands[1].value;
|
||||
op->src[1] = parsed_operands[2].value;
|
||||
r_strbuf_setf (&op->esil, "%s,%s,&,%s,=", parsed_operands[2].esil, parsed_operands[1].esil, parsed_operands[0].esil);
|
||||
break;
|
||||
case RSP_OP_OR:
|
||||
case RSP_OP_ORI:
|
||||
op->type = R_ANAL_OP_TYPE_OR;
|
||||
op->dst = parsed_operands[0].value;
|
||||
op->src[0] = parsed_operands[1].value;
|
||||
op->src[1] = parsed_operands[2].value;
|
||||
r_strbuf_setf (&op->esil, "%s,%s,|,%s,=", parsed_operands[2].esil, parsed_operands[1].esil, parsed_operands[0].esil);
|
||||
break;
|
||||
case RSP_OP_XOR:
|
||||
case RSP_OP_XORI:
|
||||
op->type = R_ANAL_OP_TYPE_XOR;
|
||||
op->dst = parsed_operands[0].value;
|
||||
op->src[0] = parsed_operands[1].value;
|
||||
op->src[1] = parsed_operands[2].value;
|
||||
r_strbuf_setf (&op->esil, "%s,%s,^,%s,=", parsed_operands[2].esil, parsed_operands[1].esil, parsed_operands[0].esil);
|
||||
break;
|
||||
case RSP_OP_NOR:
|
||||
op->type = R_ANAL_OP_TYPE_NOR;
|
||||
op->dst = parsed_operands[0].value;
|
||||
op->src[0] = parsed_operands[1].value;
|
||||
op->src[1] = parsed_operands[2].value;
|
||||
// TODO
|
||||
break;
|
||||
case RSP_OP_SLL:
|
||||
case RSP_OP_SLLV:
|
||||
op->type = R_ANAL_OP_TYPE_SHL;
|
||||
op->dst = parsed_operands[0].value;
|
||||
op->src[0] = parsed_operands[1].value;
|
||||
op->src[1] = parsed_operands[2].value;
|
||||
r_strbuf_setf (&op->esil, "%s,%s,<<,%s,=", parsed_operands[2].esil, parsed_operands[1].esil, parsed_operands[0].esil);
|
||||
break;
|
||||
case RSP_OP_SRL:
|
||||
case RSP_OP_SRLV:
|
||||
op->type = R_ANAL_OP_TYPE_SHR;
|
||||
op->dst = parsed_operands[0].value;
|
||||
op->src[0] = parsed_operands[1].value;
|
||||
op->src[1] = parsed_operands[2].value;
|
||||
r_strbuf_setf (&op->esil, "%s,%s,>>,%s,=", parsed_operands[2].esil, parsed_operands[1].esil, parsed_operands[0].esil);
|
||||
break;
|
||||
case RSP_OP_SRA:
|
||||
case RSP_OP_SRAV:
|
||||
op->type = R_ANAL_OP_TYPE_SAR;
|
||||
op->dst = parsed_operands[0].value;
|
||||
op->src[0] = parsed_operands[1].value;
|
||||
op->src[1] = parsed_operands[2].value;
|
||||
// TODO
|
||||
break;
|
||||
case RSP_OP_SLT:
|
||||
case RSP_OP_SLTU:
|
||||
case RSP_OP_SLTI:
|
||||
case RSP_OP_SLTIU:
|
||||
op->type = R_ANAL_OP_TYPE_CMOV;
|
||||
op->cond = R_ANAL_COND_LT;
|
||||
op->dst = parsed_operands[0].value;
|
||||
op->src[0] = parsed_operands[1].value;
|
||||
op->src[1] = parsed_operands[2].value;
|
||||
r_strbuf_setf (&op->esil, "%s,%s,<,$z,?{,1,%s,=,}{,0,%s,=,}", parsed_operands[2].esil, parsed_operands[1].esil, parsed_operands[0].esil, parsed_operands[0].esil);
|
||||
break;
|
||||
case RSP_OP_J:
|
||||
op->type = R_ANAL_OP_TYPE_JMP;
|
||||
op->dst = r_anal_value_new ();
|
||||
op->dst->reg = r_reg_get (anal->reg, "PC", R_REG_TYPE_GPR);
|
||||
op->src[0] = parsed_operands[0].value;
|
||||
r_strbuf_setf (&op->esil, "%s,PC,=", parsed_operands[0].esil);
|
||||
break;
|
||||
case RSP_OP_JAL:
|
||||
op->type = R_ANAL_OP_TYPE_CALL;
|
||||
op->dst = r_anal_value_new ();
|
||||
op->dst->reg = r_reg_get (anal->reg, "PC", R_REG_TYPE_GPR);
|
||||
op->src[0] = parsed_operands[0].value;
|
||||
r_strbuf_setf (&op->esil, "%s,PC,=,0x%08x,RA,=", parsed_operands[0].esil, op->fail);
|
||||
break;
|
||||
case RSP_OP_JR:
|
||||
/* if register is RA, this is a return */
|
||||
op->type = (r_instr.operands[0].u == 29)
|
||||
? R_ANAL_OP_TYPE_RET
|
||||
: R_ANAL_OP_TYPE_UJMP;
|
||||
op->delay = 1;
|
||||
op->eob = 1;
|
||||
op->fail = rsp_mem_addr (addr + 8, RSP_IMEM_OFFSET);
|
||||
op->dst = r_anal_value_new ();
|
||||
op->dst->reg = r_reg_get (anal->reg, "PC", R_REG_TYPE_GPR);
|
||||
op->src[0] = parsed_operands[0].value;
|
||||
r_strbuf_setf (&op->esil, "%s,PC,=", parsed_operands[0].esil);
|
||||
break;
|
||||
case RSP_OP_BEQ:
|
||||
op->type = R_ANAL_OP_TYPE_CJMP;
|
||||
op->cond = R_ANAL_COND_EQ;
|
||||
op->dst = r_anal_value_new ();
|
||||
op->dst->reg = r_reg_get (anal->reg, "PC", R_REG_TYPE_GPR);
|
||||
op->src[0] = parsed_operands[0].value;
|
||||
op->src[1] = parsed_operands[1].value;
|
||||
r_strbuf_setf (&op->esil, "%s,%s,==,$z,?{,%s,PC,=,}", parsed_operands[0].esil, parsed_operands[1].esil, parsed_operands[2].esil);
|
||||
break;
|
||||
case RSP_OP_BNE:
|
||||
op->type = R_ANAL_OP_TYPE_CJMP;
|
||||
op->cond = R_ANAL_COND_NE;
|
||||
op->dst = r_anal_value_new ();
|
||||
op->dst->reg = r_reg_get (anal->reg, "PC", R_REG_TYPE_GPR);
|
||||
op->src[0] = parsed_operands[0].value;
|
||||
op->src[1] = parsed_operands[1].value;
|
||||
r_strbuf_setf (&op->esil, "%s,%s,==,$z,!,?{,%s,PC,=,}", parsed_operands[0].esil, parsed_operands[1].esil, parsed_operands[2].esil);
|
||||
break;
|
||||
case RSP_OP_BLEZ:
|
||||
op->type = R_ANAL_OP_TYPE_CJMP;
|
||||
op->cond = R_ANAL_COND_LE;
|
||||
op->dst = r_anal_value_new ();
|
||||
op->dst->reg = r_reg_get (anal->reg, "PC", R_REG_TYPE_GPR);
|
||||
op->src[0] = parsed_operands[0].value;
|
||||
op->src[1] = parsed_operands[1].value;
|
||||
r_strbuf_setf (&op->esil, "0,%s,<=,$z,?{,%s,PC,=,}", parsed_operands[0].esil, parsed_operands[1].esil);
|
||||
break;
|
||||
case RSP_OP_BGTZ:
|
||||
op->type = R_ANAL_OP_TYPE_CJMP;
|
||||
op->cond = R_ANAL_COND_GT;
|
||||
op->dst = r_anal_value_new ();
|
||||
op->dst->reg = r_reg_get (anal->reg, "PC", R_REG_TYPE_GPR);
|
||||
op->src[0] = parsed_operands[0].value;
|
||||
op->src[1] = parsed_operands[1].value;
|
||||
r_strbuf_setf (&op->esil, "0,%s,>,$z,?{,%s,PC,=,}", parsed_operands[0].esil, parsed_operands[1].esil);
|
||||
break;
|
||||
case RSP_OP_BLTZ:
|
||||
op->type = R_ANAL_OP_TYPE_CJMP;
|
||||
op->cond = R_ANAL_COND_LT;
|
||||
op->dst = r_anal_value_new ();
|
||||
op->dst->reg = r_reg_get (anal->reg, "PC", R_REG_TYPE_GPR);
|
||||
op->src[0] = parsed_operands[0].value;
|
||||
op->src[1] = parsed_operands[1].value;
|
||||
r_strbuf_setf (&op->esil, "0,%s,<,?{,%s,PC,=,}", parsed_operands[0].esil, parsed_operands[1].esil);
|
||||
break;
|
||||
case RSP_OP_BGEZ:
|
||||
op->type = R_ANAL_OP_TYPE_CJMP;
|
||||
op->cond = R_ANAL_COND_GE;
|
||||
op->dst = r_anal_value_new ();
|
||||
op->dst->reg = r_reg_get (anal->reg, "PC", R_REG_TYPE_GPR);
|
||||
op->src[0] = parsed_operands[0].value;
|
||||
op->src[1] = parsed_operands[1].value;
|
||||
r_strbuf_setf (&op->esil, "0,%s,>=,?{,%s,PC,=,}", parsed_operands[0].esil, parsed_operands[1].esil);
|
||||
break;
|
||||
case RSP_OP_BLTZAL:
|
||||
op->type = R_ANAL_OP_TYPE_CCALL;
|
||||
op->cond = R_ANAL_COND_LT;
|
||||
op->dst = r_anal_value_new ();
|
||||
op->dst->reg = r_reg_get (anal->reg, "PC", R_REG_TYPE_GPR);
|
||||
op->src[0] = parsed_operands[0].value;
|
||||
op->src[1] = parsed_operands[1].value;
|
||||
// TODO
|
||||
break;
|
||||
case RSP_OP_BGEZAL:
|
||||
op->type = R_ANAL_OP_TYPE_CCALL;
|
||||
op->cond = R_ANAL_COND_GE;
|
||||
op->dst = r_anal_value_new ();
|
||||
op->dst->reg = r_reg_get (anal->reg, "PC", R_REG_TYPE_GPR);
|
||||
op->src[0] = parsed_operands[0].value;
|
||||
op->src[1] = parsed_operands[1].value;
|
||||
// TODO
|
||||
break;
|
||||
case RSP_OP_LB:
|
||||
op->type = R_ANAL_OP_TYPE_LOAD;
|
||||
op->dst = parsed_operands[0].value;
|
||||
op->src[0] = parsed_operands[1].value;
|
||||
op->src[0]->memref = op->refptr = 1;
|
||||
// FIXME: sign extend
|
||||
r_strbuf_setf (&op->esil, "%s,[1],%s,=", parsed_operands[1].esil, parsed_operands[0].esil);
|
||||
break;
|
||||
case RSP_OP_LH:
|
||||
op->type = R_ANAL_OP_TYPE_LOAD;
|
||||
op->dst = parsed_operands[0].value;
|
||||
op->src[0] = parsed_operands[1].value;
|
||||
op->src[0]->memref = op->refptr = 2;
|
||||
// FIXME: sign extend
|
||||
r_strbuf_setf (&op->esil, "%s,[2],%s,=", parsed_operands[1].esil, parsed_operands[0].esil);
|
||||
break;
|
||||
case RSP_OP_LW:
|
||||
op->type = R_ANAL_OP_TYPE_LOAD;
|
||||
op->dst = parsed_operands[0].value;
|
||||
op->src[0] = parsed_operands[1].value;
|
||||
op->src[0]->memref = op->refptr = 4;
|
||||
r_strbuf_setf (&op->esil, "%s,[4],%s,=", parsed_operands[1].esil, parsed_operands[0].esil);
|
||||
break;
|
||||
case RSP_OP_LBU:
|
||||
op->type = R_ANAL_OP_TYPE_LOAD;
|
||||
op->dst = parsed_operands[0].value;
|
||||
op->src[0] = parsed_operands[1].value;
|
||||
op->src[0]->memref = op->refptr = 1;
|
||||
r_strbuf_setf (&op->esil, "%s,[1],%s,=", parsed_operands[1].esil, parsed_operands[0].esil);
|
||||
break;
|
||||
case RSP_OP_LHU:
|
||||
op->type = R_ANAL_OP_TYPE_LOAD;
|
||||
op->dst = parsed_operands[0].value;
|
||||
op->src[0] = parsed_operands[1].value;
|
||||
op->src[0]->memref = op->refptr = 2;
|
||||
r_strbuf_setf (&op->esil, "%s,[2],%s,=", parsed_operands[1].esil, parsed_operands[0].esil);
|
||||
break;
|
||||
case RSP_OP_SB:
|
||||
op->type = R_ANAL_OP_TYPE_STORE;
|
||||
op->src[0] = parsed_operands[0].value;
|
||||
op->dst = parsed_operands[1].value;
|
||||
op->dst->memref = op->refptr = 1;
|
||||
r_strbuf_setf (&op->esil, "%s,%s,=[1]", parsed_operands[0].esil, parsed_operands[1].esil);
|
||||
break;
|
||||
case RSP_OP_SH:
|
||||
op->type = R_ANAL_OP_TYPE_STORE;
|
||||
op->src[0] = parsed_operands[0].value;
|
||||
op->dst = parsed_operands[1].value;
|
||||
op->dst->memref = op->refptr = 2;
|
||||
r_strbuf_setf (&op->esil, "%s,%s,=[2]", parsed_operands[0].esil, parsed_operands[1].esil);
|
||||
break;
|
||||
case RSP_OP_SW:
|
||||
op->type = R_ANAL_OP_TYPE_STORE;
|
||||
op->src[0] = parsed_operands[0].value;
|
||||
op->dst = parsed_operands[1].value;
|
||||
op->dst->memref = op->refptr = 4;
|
||||
r_strbuf_setf (&op->esil, "%s,%s,=[4]", parsed_operands[0].esil, parsed_operands[1].esil);
|
||||
break;
|
||||
case RSP_OP_MFC0:
|
||||
op->type = R_ANAL_OP_TYPE_MOV;
|
||||
op->dst = parsed_operands[0].value;
|
||||
op->src[0] = parsed_operands[1].value;
|
||||
r_strbuf_setf (&op->esil, "%s,%s,=", parsed_operands[1].esil, parsed_operands[0].esil);
|
||||
break;
|
||||
case RSP_OP_MTC0:
|
||||
op->type = R_ANAL_OP_TYPE_MOV;
|
||||
op->src[0] = parsed_operands[0].value;
|
||||
op->dst = parsed_operands[1].value;
|
||||
r_strbuf_setf (&op->esil, "%s,%s,=", parsed_operands[0].esil, parsed_operands[1].esil);
|
||||
break;
|
||||
case RSP_OP_MFC2:
|
||||
op->type = R_ANAL_OP_TYPE_MOV;
|
||||
op->dst = parsed_operands[0].value;
|
||||
//op->src[0] = parsed_operands[1].value;
|
||||
break;
|
||||
case RSP_OP_MTC2:
|
||||
op->type = R_ANAL_OP_TYPE_MOV;
|
||||
op->src[0] = parsed_operands[0].value;
|
||||
//op->dst = parsed_operands[1].value;
|
||||
break;
|
||||
case RSP_OP_CFC2:
|
||||
op->type = R_ANAL_OP_TYPE_MOV;
|
||||
break;
|
||||
case RSP_OP_CTC2:
|
||||
op->type = R_ANAL_OP_TYPE_MOV;
|
||||
break;
|
||||
case RSP_OP_VMULF:
|
||||
op->type = R_ANAL_OP_TYPE_MUL;
|
||||
break;
|
||||
case RSP_OP_VMULU:
|
||||
op->type = R_ANAL_OP_TYPE_MUL;
|
||||
break;
|
||||
case RSP_OP_VMUDL:
|
||||
op->type = R_ANAL_OP_TYPE_MUL;
|
||||
break;
|
||||
case RSP_OP_VMUDM:
|
||||
op->type = R_ANAL_OP_TYPE_MUL;
|
||||
break;
|
||||
case RSP_OP_VMUDN:
|
||||
op->type = R_ANAL_OP_TYPE_MUL;
|
||||
break;
|
||||
case RSP_OP_VMUDH:
|
||||
op->type = R_ANAL_OP_TYPE_MUL;
|
||||
break;
|
||||
case RSP_OP_VMACF:
|
||||
op->type = R_ANAL_OP_TYPE_MUL;
|
||||
break;
|
||||
case RSP_OP_VMACU:
|
||||
op->type = R_ANAL_OP_TYPE_MUL;
|
||||
break;
|
||||
case RSP_OP_VMADL:
|
||||
op->type = R_ANAL_OP_TYPE_MUL;
|
||||
break;
|
||||
case RSP_OP_VMADM:
|
||||
op->type = R_ANAL_OP_TYPE_MUL;
|
||||
break;
|
||||
case RSP_OP_VMADN:
|
||||
op->type = R_ANAL_OP_TYPE_MUL;
|
||||
break;
|
||||
case RSP_OP_VMADH:
|
||||
op->type = R_ANAL_OP_TYPE_MUL;
|
||||
break;
|
||||
case RSP_OP_VADD:
|
||||
op->type = R_ANAL_OP_TYPE_ADD;
|
||||
break;
|
||||
case RSP_OP_VSUB:
|
||||
op->type = R_ANAL_OP_TYPE_SUB;
|
||||
break;
|
||||
case RSP_OP_VABS:
|
||||
op->type = R_ANAL_OP_TYPE_ABS;
|
||||
break;
|
||||
case RSP_OP_VADDC:
|
||||
op->type = R_ANAL_OP_TYPE_ADD;
|
||||
break;
|
||||
case RSP_OP_VSUBC:
|
||||
op->type = R_ANAL_OP_TYPE_SUB;
|
||||
break;
|
||||
case RSP_OP_VSAR:
|
||||
op->type = R_ANAL_OP_TYPE_MOV;
|
||||
break;
|
||||
case RSP_OP_VLT:
|
||||
op->type = R_ANAL_OP_TYPE_CMP;
|
||||
op->cond = R_ANAL_COND_LT;
|
||||
break;
|
||||
case RSP_OP_VEQ:
|
||||
op->type = R_ANAL_OP_TYPE_CMP;
|
||||
op->cond = R_ANAL_COND_EQ;
|
||||
break;
|
||||
case RSP_OP_VNE:
|
||||
op->type = R_ANAL_OP_TYPE_CMP;
|
||||
op->cond = R_ANAL_COND_NE;
|
||||
break;
|
||||
case RSP_OP_VGE:
|
||||
op->type = R_ANAL_OP_TYPE_CMP;
|
||||
op->cond = R_ANAL_COND_GE;
|
||||
break;
|
||||
case RSP_OP_VCL:
|
||||
op->type = R_ANAL_OP_TYPE_UNK;
|
||||
break;
|
||||
case RSP_OP_VCH:
|
||||
op->type = R_ANAL_OP_TYPE_UNK;
|
||||
break;
|
||||
case RSP_OP_VCR:
|
||||
op->type = R_ANAL_OP_TYPE_UNK;
|
||||
break;
|
||||
case RSP_OP_VMRG:
|
||||
op->type = R_ANAL_OP_TYPE_UNK;
|
||||
break;
|
||||
case RSP_OP_VAND:
|
||||
op->type = R_ANAL_OP_TYPE_AND;
|
||||
break;
|
||||
case RSP_OP_VNAND:
|
||||
op->type = R_ANAL_OP_TYPE_AND;
|
||||
break;
|
||||
case RSP_OP_VOR:
|
||||
op->type = R_ANAL_OP_TYPE_OR;
|
||||
break;
|
||||
case RSP_OP_VNOR:
|
||||
op->type = R_ANAL_OP_TYPE_NOR;
|
||||
break;
|
||||
case RSP_OP_VXOR:
|
||||
op->type = R_ANAL_OP_TYPE_XOR;
|
||||
break;
|
||||
case RSP_OP_VNXOR:
|
||||
op->type = R_ANAL_OP_TYPE_XOR;
|
||||
break;
|
||||
case RSP_OP_VRCP:
|
||||
op->type = R_ANAL_OP_TYPE_UNK;
|
||||
break;
|
||||
case RSP_OP_VRCPL:
|
||||
op->type = R_ANAL_OP_TYPE_UNK;
|
||||
break;
|
||||
case RSP_OP_VRCPH:
|
||||
op->type = R_ANAL_OP_TYPE_UNK;
|
||||
break;
|
||||
case RSP_OP_VMOV:
|
||||
op->type = R_ANAL_OP_TYPE_MOV;
|
||||
break;
|
||||
case RSP_OP_VRSQ:
|
||||
op->type = R_ANAL_OP_TYPE_UNK;
|
||||
break;
|
||||
case RSP_OP_VRSQL:
|
||||
op->type = R_ANAL_OP_TYPE_UNK;
|
||||
break;
|
||||
case RSP_OP_VRSQH:
|
||||
op->type = R_ANAL_OP_TYPE_UNK;
|
||||
break;
|
||||
case RSP_OP_VNOP:
|
||||
op->type = R_ANAL_OP_TYPE_NOP;
|
||||
break;
|
||||
case RSP_OP_LBV:
|
||||
op->type = R_ANAL_OP_TYPE_LOAD;
|
||||
break;
|
||||
case RSP_OP_LSV:
|
||||
op->type = R_ANAL_OP_TYPE_LOAD;
|
||||
break;
|
||||
case RSP_OP_LLV:
|
||||
op->type = R_ANAL_OP_TYPE_LOAD;
|
||||
break;
|
||||
case RSP_OP_LDV:
|
||||
op->type = R_ANAL_OP_TYPE_LOAD;
|
||||
break;
|
||||
case RSP_OP_LQV:
|
||||
op->type = R_ANAL_OP_TYPE_LOAD;
|
||||
break;
|
||||
case RSP_OP_LRV:
|
||||
op->type = R_ANAL_OP_TYPE_LOAD;
|
||||
break;
|
||||
case RSP_OP_LPV:
|
||||
op->type = R_ANAL_OP_TYPE_LOAD;
|
||||
break;
|
||||
case RSP_OP_LUV:
|
||||
op->type = R_ANAL_OP_TYPE_LOAD;
|
||||
break;
|
||||
case RSP_OP_LHV:
|
||||
op->type = R_ANAL_OP_TYPE_LOAD;
|
||||
break;
|
||||
case RSP_OP_LFV:
|
||||
op->type = R_ANAL_OP_TYPE_LOAD;
|
||||
break;
|
||||
case RSP_OP_LTV:
|
||||
op->type = R_ANAL_OP_TYPE_LOAD;
|
||||
break;
|
||||
case RSP_OP_SBV:
|
||||
op->type = R_ANAL_OP_TYPE_STORE;
|
||||
break;
|
||||
case RSP_OP_SSV:
|
||||
op->type = R_ANAL_OP_TYPE_STORE;
|
||||
break;
|
||||
case RSP_OP_SLV:
|
||||
op->type = R_ANAL_OP_TYPE_STORE;
|
||||
break;
|
||||
case RSP_OP_SDV:
|
||||
op->type = R_ANAL_OP_TYPE_STORE;
|
||||
break;
|
||||
case RSP_OP_SQV:
|
||||
op->type = R_ANAL_OP_TYPE_STORE;
|
||||
break;
|
||||
case RSP_OP_SRV:
|
||||
op->type = R_ANAL_OP_TYPE_STORE;
|
||||
break;
|
||||
case RSP_OP_SPV:
|
||||
op->type = R_ANAL_OP_TYPE_STORE;
|
||||
break;
|
||||
case RSP_OP_SUV:
|
||||
op->type = R_ANAL_OP_TYPE_STORE;
|
||||
break;
|
||||
case RSP_OP_SHV:
|
||||
op->type = R_ANAL_OP_TYPE_STORE;
|
||||
break;
|
||||
case RSP_OP_SFV:
|
||||
op->type = R_ANAL_OP_TYPE_STORE;
|
||||
break;
|
||||
case RSP_OP_SWV:
|
||||
op->type = R_ANAL_OP_TYPE_STORE;
|
||||
break;
|
||||
case RSP_OP_STV:
|
||||
op->type = R_ANAL_OP_TYPE_STORE;
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
return op->size;
|
||||
}
|
||||
|
||||
|
||||
static char *get_reg_profile(RAnal *anal) {
|
||||
static const char *p =
|
||||
"=PC pc\n"
|
||||
"=SP sp\n"
|
||||
"=A0 a0\n"
|
||||
"=A1 a1\n"
|
||||
"=A2 a2\n"
|
||||
"=A3 a3\n"
|
||||
"=R0 v0\n"
|
||||
"=R1 v1\n"
|
||||
/* GP registers */
|
||||
"gpr zero .32 0 0\n"
|
||||
"gpr at .32 4 0\n"
|
||||
"gpr v0 .32 8 0\n"
|
||||
"gpr v1 .32 12 0\n"
|
||||
"gpr a0 .32 16 0\n"
|
||||
"gpr a1 .32 20 0\n"
|
||||
"gpr a2 .32 24 0\n"
|
||||
"gpr a3 .32 28 0\n"
|
||||
"gpr t0 .32 32 0\n"
|
||||
"gpr t1 .32 36 0\n"
|
||||
"gpr t2 .32 40 0\n"
|
||||
"gpr t3 .32 44 0\n"
|
||||
"gpr t4 .32 48 0\n"
|
||||
"gpr t5 .32 52 0\n"
|
||||
"gpr t6 .32 56 0\n"
|
||||
"gpr t7 .32 60 0\n"
|
||||
"gpr s0 .32 64 0\n"
|
||||
"gpr s1 .32 68 0\n"
|
||||
"gpr s2 .32 72 0\n"
|
||||
"gpr s3 .32 76 0\n"
|
||||
"gpr s4 .32 80 0\n"
|
||||
"gpr s5 .32 84 0\n"
|
||||
"gpr s6 .32 88 0\n"
|
||||
"gpr s7 .32 92 0\n"
|
||||
"gpr t8 .32 96 0\n"
|
||||
"gpr t9 .32 100 0\n"
|
||||
"gpr k0 .32 104 0\n"
|
||||
"gpr k1 .32 108 0\n"
|
||||
"gpr gp .32 112 0\n"
|
||||
"gpr sp .32 116 0\n"
|
||||
"gpr s8 .32 120 0\n"
|
||||
"gpr ra .32 124 0\n"
|
||||
/* PC register */
|
||||
"gpr pc .32 128 0\n"
|
||||
/* C0 registers */
|
||||
"gpr $c0 .32 132 0\n"
|
||||
"gpr $c1 .32 136 0\n"
|
||||
"gpr $c2 .32 140 0\n"
|
||||
"gpr $c3 .32 144 0\n"
|
||||
"gpr $c4 .32 148 0\n"
|
||||
"gpr $c5 .32 152 0\n"
|
||||
"gpr $c6 .32 156 0\n"
|
||||
"gpr $c7 .32 160 0\n"
|
||||
"gpr $c8 .32 164 0\n"
|
||||
"gpr $c9 .32 168 0\n"
|
||||
"gpr $c10 .32 172 0\n"
|
||||
"gpr $c11 .32 176 0\n"
|
||||
"gpr $c12 .32 180 0\n"
|
||||
"gpr $c13 .32 184 0\n"
|
||||
"gpr $c14 .32 188 0\n"
|
||||
"gpr $c15 .32 192 0\n"
|
||||
/* C2 vector registers - (32 x 128 bit) */
|
||||
"gpr $v0 .128 196 0\n"
|
||||
"gpr $v1 .128 212 0\n"
|
||||
"gpr $v2 .128 228 0\n"
|
||||
"gpr $v3 .128 244 0\n"
|
||||
"gpr $v4 .128 260 0\n"
|
||||
"gpr $v5 .128 276 0\n"
|
||||
"gpr $v6 .128 292 0\n"
|
||||
"gpr $v7 .128 308 0\n"
|
||||
"gpr $v8 .128 324 0\n"
|
||||
"gpr $v9 .128 340 0\n"
|
||||
"gpr $v10 .128 356 0\n"
|
||||
"gpr $v11 .128 372 0\n"
|
||||
"gpr $v12 .128 388 0\n"
|
||||
"gpr $v13 .128 404 0\n"
|
||||
"gpr $v14 .128 420 0\n"
|
||||
"gpr $v15 .128 436 0\n"
|
||||
"gpr $v16 .128 452 0\n"
|
||||
"gpr $v17 .128 468 0\n"
|
||||
"gpr $v18 .128 484 0\n"
|
||||
"gpr $v19 .128 500 0\n"
|
||||
"gpr $v20 .128 516 0\n"
|
||||
"gpr $v21 .128 532 0\n"
|
||||
"gpr $v22 .128 548 0\n"
|
||||
"gpr $v23 .128 564 0\n"
|
||||
"gpr $v24 .128 580 0\n"
|
||||
"gpr $v25 .128 596 0\n"
|
||||
"gpr $v26 .128 612 0\n"
|
||||
"gpr $v27 .128 628 0\n"
|
||||
"gpr $v28 .128 644 0\n"
|
||||
"gpr $v29 .128 660 0\n"
|
||||
"gpr $v30 .128 676 0\n"
|
||||
"gpr $v31 .128 692 0\n"
|
||||
/* C2 control registers - (vco, vcc, vce) */
|
||||
"gpr $vco .128 708 0\n"
|
||||
"gpr $vcc .128 724 0\n"
|
||||
"gpr $vce .128 740 0\n"
|
||||
;
|
||||
|
||||
return strdup (p);
|
||||
}
|
||||
|
||||
static int archinfo(RAnal *anal, int q) {
|
||||
return 4;
|
||||
}
|
||||
|
||||
struct r_anal_plugin_t r_anal_plugin_rsp = {
|
||||
.name = "rsp",
|
||||
.desc = "RSP code analysis plugin",
|
||||
.license = "LGPL3",
|
||||
.arch = "rsp",
|
||||
.esil = true,
|
||||
.bits = 32,
|
||||
.op = &rsp_op,
|
||||
.archinfo = &archinfo,
|
||||
.get_reg_profile = &get_reg_profile,
|
||||
};
|
||||
|
||||
#ifndef CORELIB
|
||||
struct r_lib_struct_t radare_plugin = {
|
||||
.type = R_LIB_TYPE_ANAL,
|
||||
.data = &r_anal_plugin_rsp,
|
||||
.version = R2_VERSION
|
||||
};
|
||||
#endif
|
12
libr/anal/p/rsp.mk
Normal file
12
libr/anal/p/rsp.mk
Normal file
@ -0,0 +1,12 @@
|
||||
OBJ_RSP=anal_rsp.o
|
||||
#RSP_ROOT=$(LIBR)/asm/arch/rsp
|
||||
CFLAGS+=-I../asm/arch/rsp
|
||||
|
||||
STATIC_OBJ+=${OBJ_RSP}
|
||||
OBJ_RSP+=../../asm/arch/rsp/rsp_idec.o
|
||||
TARGET_RSP=anal_rsp.${EXT_SO}
|
||||
|
||||
ALL_TARGETS+=${TARGET_RSP}
|
||||
|
||||
${TARGET_RSP}: ${OBJ_RSP}
|
||||
${CC} $(call libname,anal_rsp) ${LDFLAGS} ${CFLAGS} -o ${TARGET_RSP} ${OBJ_RSP}
|
405
libr/asm/arch/rsp/rsp_idec.c
Normal file
405
libr/asm/arch/rsp/rsp_idec.c
Normal file
@ -0,0 +1,405 @@
|
||||
/* 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;
|
||||
}
|
179
libr/asm/arch/rsp/rsp_idec.h
Normal file
179
libr/asm/arch/rsp/rsp_idec.h
Normal file
@ -0,0 +1,179 @@
|
||||
/* radare - LGPL - Copyright 2016 - bobby.smiles32@gmail.com */
|
||||
#ifndef R_ASM_ARCH_RSP_RSP_IDEC_H
|
||||
#define R_ASM_ARCH_RSP_RSP_IDEC_H
|
||||
|
||||
#include <r_types.h>
|
||||
|
||||
|
||||
extern const char* rsp_gp_reg_soft_names[];
|
||||
extern const char* rsp_c0_reg_soft_names[];
|
||||
extern const char* rsp_gp_reg_names[];
|
||||
extern const char* rsp_c0_reg_names[];
|
||||
extern const char* rsp_c2_creg_names[];
|
||||
extern const char* rsp_c2_accu_names[];
|
||||
extern const char* rsp_c2_vreg_names[];
|
||||
extern const char* rsp_c2_vreg_element_names[];
|
||||
|
||||
|
||||
enum {
|
||||
RSP_DMEM_OFFSET = 0x0000,
|
||||
RSP_IMEM_OFFSET = 0x1000
|
||||
};
|
||||
|
||||
/* restrict address inside rsp MEM */
|
||||
static inline ut64 rsp_mem_addr(ut64 addr, ut64 base) { addr &= 0xfff; addr |= base; return addr; }
|
||||
|
||||
|
||||
typedef enum {
|
||||
RSP_OP_INVALID,
|
||||
RSP_OP_NOP,
|
||||
RSP_OP_SLL,
|
||||
RSP_OP_SRL,
|
||||
RSP_OP_SRA,
|
||||
RSP_OP_SLLV,
|
||||
RSP_OP_SRLV,
|
||||
RSP_OP_SRAV,
|
||||
RSP_OP_JR,
|
||||
RSP_OP_BREAK,
|
||||
RSP_OP_ADD,
|
||||
RSP_OP_ADDU,
|
||||
RSP_OP_SUB,
|
||||
RSP_OP_SUBU,
|
||||
RSP_OP_AND,
|
||||
RSP_OP_OR,
|
||||
RSP_OP_XOR,
|
||||
RSP_OP_NOR,
|
||||
RSP_OP_SLT,
|
||||
RSP_OP_SLTU,
|
||||
RSP_OP_BLTZ,
|
||||
RSP_OP_BGEZ,
|
||||
RSP_OP_BLTZAL,
|
||||
RSP_OP_BGEZAL,
|
||||
RSP_OP_MFC0,
|
||||
RSP_OP_MTC0,
|
||||
RSP_OP_MFC2,
|
||||
RSP_OP_MTC2,
|
||||
RSP_OP_CFC2,
|
||||
RSP_OP_CTC2,
|
||||
RSP_OP_VMULF,
|
||||
RSP_OP_VMULU,
|
||||
RSP_OP_VMUDL,
|
||||
RSP_OP_VMUDM,
|
||||
RSP_OP_VMUDN,
|
||||
RSP_OP_VMUDH,
|
||||
RSP_OP_VMACF,
|
||||
RSP_OP_VMACU,
|
||||
RSP_OP_VMADL,
|
||||
RSP_OP_VMADM,
|
||||
RSP_OP_VMADN,
|
||||
RSP_OP_VMADH,
|
||||
RSP_OP_VADD,
|
||||
RSP_OP_VSUB,
|
||||
RSP_OP_VABS,
|
||||
RSP_OP_VADDC,
|
||||
RSP_OP_VSUBC,
|
||||
RSP_OP_VSAR,
|
||||
RSP_OP_VLT,
|
||||
RSP_OP_VEQ,
|
||||
RSP_OP_VNE,
|
||||
RSP_OP_VGE,
|
||||
RSP_OP_VCL,
|
||||
RSP_OP_VCH,
|
||||
RSP_OP_VCR,
|
||||
RSP_OP_VMRG,
|
||||
RSP_OP_VAND,
|
||||
RSP_OP_VNAND,
|
||||
RSP_OP_VOR,
|
||||
RSP_OP_VNOR,
|
||||
RSP_OP_VXOR,
|
||||
RSP_OP_VNXOR,
|
||||
RSP_OP_VRCP,
|
||||
RSP_OP_VRCPL,
|
||||
RSP_OP_VRCPH,
|
||||
RSP_OP_VMOV,
|
||||
RSP_OP_VRSQ,
|
||||
RSP_OP_VRSQL,
|
||||
RSP_OP_VRSQH,
|
||||
RSP_OP_VNOP,
|
||||
RSP_OP_LBV,
|
||||
RSP_OP_LSV,
|
||||
RSP_OP_LLV,
|
||||
RSP_OP_LDV,
|
||||
RSP_OP_LQV,
|
||||
RSP_OP_LRV,
|
||||
RSP_OP_LPV,
|
||||
RSP_OP_LUV,
|
||||
RSP_OP_LHV,
|
||||
RSP_OP_LFV,
|
||||
RSP_OP_LTV,
|
||||
RSP_OP_SBV,
|
||||
RSP_OP_SSV,
|
||||
RSP_OP_SLV,
|
||||
RSP_OP_SDV,
|
||||
RSP_OP_SQV,
|
||||
RSP_OP_SRV,
|
||||
RSP_OP_SPV,
|
||||
RSP_OP_SUV,
|
||||
RSP_OP_SHV,
|
||||
RSP_OP_SFV,
|
||||
RSP_OP_SWV,
|
||||
RSP_OP_STV,
|
||||
RSP_OP_J,
|
||||
RSP_OP_JAL,
|
||||
RSP_OP_BEQ,
|
||||
RSP_OP_BNE,
|
||||
RSP_OP_BLEZ,
|
||||
RSP_OP_BGTZ,
|
||||
RSP_OP_ADDI,
|
||||
RSP_OP_ADDIU,
|
||||
RSP_OP_SLTI,
|
||||
RSP_OP_SLTIU,
|
||||
RSP_OP_ANDI,
|
||||
RSP_OP_ORI,
|
||||
RSP_OP_XORI,
|
||||
RSP_OP_LUI,
|
||||
RSP_OP_LB,
|
||||
RSP_OP_LH,
|
||||
RSP_OP_LW,
|
||||
RSP_OP_LBU,
|
||||
RSP_OP_LHU,
|
||||
RSP_OP_SB,
|
||||
RSP_OP_SH,
|
||||
RSP_OP_SW
|
||||
} rsp_opcode;
|
||||
|
||||
typedef enum {
|
||||
RSP_OPND_GP_REG, /* u=reg_num */
|
||||
RSP_OPND_TARGET, /* u=imem_address */
|
||||
RSP_OPND_OFFSET, /* u=imem_address, s=offset */
|
||||
RSP_OPND_ZIMM, /* u=zero-extended imm */
|
||||
RSP_OPND_SIMM, /* s=sign extended imm */
|
||||
RSP_OPND_SHIFT_AMOUNT, /* u=shift amount */
|
||||
RSP_OPND_BASE_OFFSET, /* u=reg_numm, s=offset */
|
||||
RSP_OPND_C0_REG, /* u=reg_num */
|
||||
RSP_OPND_C2_CREG, /* u=reg_num */
|
||||
RSP_OPND_C2_ACCU, /* u=reg_num */
|
||||
RSP_OPND_C2_VREG, /* u=reg_num */
|
||||
RSP_OPND_C2_VREG_BYTE, /* u=reg_num, s=byte element (0-15) */
|
||||
RSP_OPND_C2_VREG_SCALAR, /* u=reg_num, s=scalar element (0-7) */
|
||||
RSP_OPND_C2_VREG_ELEMENT /* u=reg_num, s=element (0-15) */
|
||||
} rsp_operand_type;
|
||||
|
||||
typedef struct {
|
||||
rsp_operand_type type;
|
||||
ut64 u;
|
||||
st64 s;
|
||||
} rsp_operand;
|
||||
|
||||
enum { RSP_MAX_OPNDS = 3 };
|
||||
|
||||
typedef struct {
|
||||
const char* mnemonic;
|
||||
rsp_opcode opcode;
|
||||
int noperands;
|
||||
rsp_operand operands[RSP_MAX_OPNDS];
|
||||
} rsp_instruction;
|
||||
|
||||
rsp_instruction rsp_instruction_decode(ut64 pc, ut32 iw);
|
||||
|
||||
#endif
|
@ -18,7 +18,7 @@ ARCHS+=ppc_gnu.mk ppc_cs.mk x86_olly.mk x86_udis.mk csr.mk x86_nasm.mk avr.mk
|
||||
ARCHS+=sh.mk arm_winedbg.mk tms320.mk gb.mk snes.mk ebc.mk malbolge.mk ws.mk
|
||||
ARCHS+=6502.mk h8300.mk cr16.mk v850.mk spc700.mk propeller.mk msp430.mk i4004.mk z80_cr.mk
|
||||
ARCHS+=lh5801.mk v810.mk mcs96.mk lm32.mk
|
||||
ARCHS+=riscv.mk
|
||||
ARCHS+=riscv.mk rsp.mk
|
||||
include $(ARCHS)
|
||||
|
||||
all: ${ALL_TARGETS}
|
||||
|
121
libr/asm/p/asm_rsp.c
Normal file
121
libr/asm/p/asm_rsp.c
Normal file
@ -0,0 +1,121 @@
|
||||
/* radare - LGPL - Copyright 2016 - bobby.smiles32@gmail.com */
|
||||
// TODO: add assembler
|
||||
|
||||
#include <r_types.h>
|
||||
#include <r_util.h>
|
||||
#include <r_asm.h>
|
||||
#include <r_lib.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "rsp_idec.h"
|
||||
|
||||
|
||||
static void snappendf(char** dst, size_t* size, const char* format, ...) {
|
||||
size_t n;
|
||||
va_list va;
|
||||
|
||||
va_start (va, format);
|
||||
n = vsnprintf (*dst, *size, format, va);
|
||||
|
||||
*dst += n;
|
||||
*size -= n;
|
||||
|
||||
va_end (va);
|
||||
}
|
||||
|
||||
static int disassemble(RAsm *a, RAsmOp *op, const ut8 *buf, int len) {
|
||||
ut32 iw;
|
||||
rsp_instruction r_instr;
|
||||
int i;
|
||||
char* buffer;
|
||||
size_t size;
|
||||
|
||||
/* all instructions are 32bit words */
|
||||
if (len < 4) {
|
||||
op->size = 0;
|
||||
return 0;
|
||||
}
|
||||
op->size = 4;
|
||||
|
||||
iw = r_read_ble32 (buf, a->big_endian);
|
||||
r_instr = rsp_instruction_decode (a->pc, iw);
|
||||
|
||||
buffer = op->buf_asm;
|
||||
size = sizeof (op->buf_asm);
|
||||
|
||||
snappendf (&buffer, &size, r_instr.mnemonic);
|
||||
for (i = 0; i < r_instr.noperands; ++i) {
|
||||
snappendf (&buffer, &size, "%s", (i == 0) ? " " : ", ");
|
||||
|
||||
switch (r_instr.operands[i].type) {
|
||||
case RSP_OPND_GP_REG:
|
||||
snappendf (&buffer, &size, "%s", rsp_gp_reg_soft_names[r_instr.operands[i].u]);
|
||||
break;
|
||||
case RSP_OPND_OFFSET:
|
||||
case RSP_OPND_TARGET:
|
||||
snappendf (&buffer, &size, "0x%08x", r_instr.operands[i].u);
|
||||
break;
|
||||
case RSP_OPND_ZIMM:
|
||||
snappendf (&buffer, &size, "0x%04x", r_instr.operands[i].u >> ((r_instr.operands[i].u & ~0xffff) ? 16 : 0));
|
||||
break;
|
||||
case RSP_OPND_SIMM:
|
||||
snappendf (&buffer, &size, "%s0x%04x",
|
||||
(r_instr.operands[i].s<0)?"-":"",
|
||||
(r_instr.operands[i].s<0)?-r_instr.operands[i].s:r_instr.operands[i].s);
|
||||
break;
|
||||
case RSP_OPND_SHIFT_AMOUNT:
|
||||
snappendf (&buffer, &size, "%u", r_instr.operands[i].u);
|
||||
break;
|
||||
case RSP_OPND_BASE_OFFSET:
|
||||
snappendf (&buffer, &size, "%s0x%04x(%s)",
|
||||
(r_instr.operands[i].s<0)?"-":"",
|
||||
(r_instr.operands[i].s<0)?-r_instr.operands[i].s:r_instr.operands[i].s,
|
||||
rsp_gp_reg_soft_names[r_instr.operands[i].u]);
|
||||
break;
|
||||
case RSP_OPND_C0_REG:
|
||||
snappendf (&buffer, &size, "%s", rsp_c0_reg_soft_names[r_instr.operands[i].u]);
|
||||
break;
|
||||
case RSP_OPND_C2_CREG:
|
||||
snappendf (&buffer, &size, "%s", rsp_c2_creg_names[r_instr.operands[i].u]);
|
||||
break;
|
||||
case RSP_OPND_C2_ACCU:
|
||||
snappendf (&buffer, &size, "%s", rsp_c2_accu_names[r_instr.operands[i].u]);
|
||||
break;
|
||||
case RSP_OPND_C2_VREG:
|
||||
snappendf (&buffer, &size, "%s", rsp_c2_vreg_names[r_instr.operands[i].u]);
|
||||
break;
|
||||
case RSP_OPND_C2_VREG_BYTE:
|
||||
case RSP_OPND_C2_VREG_SCALAR:
|
||||
snappendf (&buffer, &size, "%s[%u]", rsp_c2_vreg_names[r_instr.operands[i].u], r_instr.operands[i].s);
|
||||
break;
|
||||
case RSP_OPND_C2_VREG_ELEMENT:
|
||||
snappendf (&buffer, &size, "%s%s", rsp_c2_vreg_names[r_instr.operands[i].u], rsp_c2_vreg_element_names[r_instr.operands[i].s]);
|
||||
break;
|
||||
default: /* should not happend */
|
||||
snappendf (&buffer, &size, "???");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return op->size;
|
||||
}
|
||||
|
||||
RAsmPlugin r_asm_plugin_rsp = {
|
||||
.name = "rsp",
|
||||
.desc = "Reality Signal Processor",
|
||||
.arch = "rsp",
|
||||
.bits = 32,
|
||||
.endian = R_SYS_ENDIAN_BI, /* For conveniance, we don't force BIG endian but allow both to be used */
|
||||
.license = "LGPL3",
|
||||
.disassemble = &disassemble
|
||||
};
|
||||
|
||||
#ifndef CORELIB
|
||||
struct r_lib_struct_t radare_plugin = {
|
||||
.type = R_LIB_TYPE_ASM,
|
||||
.data = &r_asm_plugin_rsp,
|
||||
.version = R2_VERSION
|
||||
};
|
||||
#endif
|
15
libr/asm/p/rsp.mk
Normal file
15
libr/asm/p/rsp.mk
Normal file
@ -0,0 +1,15 @@
|
||||
OBJ_RSP=asm_rsp.o
|
||||
RSP_ROOT=$(LIBR)/asm/arch/rsp
|
||||
OBJ_RSP+=$(RSP_ROOT)/rsp_idec.o
|
||||
CFLAGS+=-I$(RSP_ROOT)
|
||||
|
||||
|
||||
STATIC_OBJ+=${OBJ_RSP}
|
||||
TARGET_RSP=asm_rsp.${EXT_SO}
|
||||
|
||||
ifeq ($(WITHPIC),1)
|
||||
ALL_TARGETS+=${TARGET_RSP}
|
||||
|
||||
${TARGET_RSP}: ${OBJ_RSP}
|
||||
${CC} $(call libname,asm_rsp) ${LDFLAGS} ${CFLAGS} -o ${TARGET_RSP} ${OBJ_RSP}
|
||||
endif
|
@ -1595,6 +1595,7 @@ extern RAnalPlugin r_anal_plugin_vax;
|
||||
extern RAnalPlugin r_anal_plugin_i4004;
|
||||
extern RAnalPlugin r_anal_plugin_xtensa;
|
||||
extern RAnalPlugin r_anal_plugin_pic18c;
|
||||
extern RAnalPlugin r_anal_plugin_rsp;
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -234,6 +234,7 @@ extern RAsmPlugin r_asm_plugin_lanai_gnu;
|
||||
extern RAsmPlugin r_asm_plugin_xtensa;
|
||||
extern RAsmPlugin r_asm_plugin_tricore;
|
||||
extern RAsmPlugin r_asm_plugin_pic18c;
|
||||
extern RAsmPlugin r_asm_plugin_rsp;
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -42,6 +42,7 @@ anal.6502
|
||||
anal.snes
|
||||
anal.riscv
|
||||
anal.pic18c
|
||||
anal.rsp
|
||||
asm.6502
|
||||
asm.8051
|
||||
asm.arc
|
||||
@ -76,6 +77,7 @@ asm.ppc_cs
|
||||
asm.ppc_gnu
|
||||
asm.rar
|
||||
asm.riscv
|
||||
asm.rsp
|
||||
asm.lanai_gnu
|
||||
asm.sh
|
||||
asm.snes
|
||||
|
Loading…
x
Reference in New Issue
Block a user