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:
bsmiles32 2016-07-03 22:03:26 +02:00 committed by radare
parent 87ccfd34f5
commit 622e828e1d
11 changed files with 1437 additions and 2 deletions

View File

@ -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
View 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
View 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}

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

View 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

View File

@ -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
View 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
View 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

View File

@ -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

View File

@ -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

View File

@ -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