mirror of
https://github.com/radareorg/radare2.git
synced 2024-12-13 07:57:35 +00:00
400 lines
8.6 KiB
C
400 lines
8.6 KiB
C
/* radare - LGPL - Copyright 2015 - danielps */
|
|
|
|
#include <r_types.h>
|
|
#include <r_util.h>
|
|
|
|
#include "v810_disas.h"
|
|
|
|
static const char *instrs[] = {
|
|
[V810_MOV] = "mov",
|
|
[V810_ADD] = "add",
|
|
[V810_SUB] = "sub",
|
|
[V810_CMP] = "cmp",
|
|
[V810_SHL] = "shl",
|
|
[V810_SHR] = "shr",
|
|
[V810_JMP] = "jmp",
|
|
[V810_SAR] = "sar",
|
|
[V810_MUL] = "mul",
|
|
[V810_DIV] = "div",
|
|
[V810_MULU] = "mulu",
|
|
[V810_DIVU] = "divu",
|
|
[V810_OR] = "or",
|
|
[V810_AND] = "and",
|
|
[V810_XOR] = "xor",
|
|
[V810_NOT] = "not",
|
|
[V810_MOV_IMM5] = "mov",
|
|
[V810_ADD_IMM5] = "add",
|
|
[V810_CMP_IMM5] = "cmp",
|
|
[V810_SHL_IMM5] = "shl",
|
|
[V810_SHR_IMM5] = "shr",
|
|
[V810_SAR_IMM5] = "sar",
|
|
[V810_MOVEA] = "movea",
|
|
[V810_MOVHI] = "movhi",
|
|
[V810_ADDI] = "addi",
|
|
[V810_ORI] = "ori",
|
|
[V810_ANDI] = "andi",
|
|
[V810_XORI] = "xori",
|
|
[V810_JR] = "jr",
|
|
[V810_JAL] = "jal",
|
|
[V810_LDB] = "ld.b",
|
|
[V810_LDH] = "ld.h",
|
|
[V810_LDW] = "ld.w",
|
|
[V810_STB] = "st.b",
|
|
[V810_STH] = "st.h",
|
|
[V810_STW] = "st.w",
|
|
[V810_INB] = "in.b",
|
|
[V810_INH] = "in.h",
|
|
[V810_CAXI] = "caxi",
|
|
[V810_INW] = "in.w",
|
|
[V810_OUTB] = "out.b",
|
|
[V810_OUTH] = "out.h",
|
|
[V810_OUTW] = "out.w",
|
|
[V810_SETF] = "setf",
|
|
[V810_LDSR] = "ldsr",
|
|
[V810_STSR] = "stsr",
|
|
[V810_TRAP] = "trap",
|
|
[V810_HALT] = "halt",
|
|
[V810_RETI] = "reti",
|
|
[V810_SEI] = "sei",
|
|
[V810_CLI] = "cli",
|
|
};
|
|
|
|
static const char *bit_instrs[] = {
|
|
[V810_BIT_SCH0U] = "sch0bsu",
|
|
[V810_BIT_SCH0D] = "sch0bsd",
|
|
[V810_BIT_SCH1U] = "sch1bsu",
|
|
[V810_BIT_SCH1D] = "sch1bsd",
|
|
[V810_BIT_ORU] = "orbsu",
|
|
[V810_BIT_ANDU] = "andbsu",
|
|
[V810_BIT_XORU] = "xorbsu",
|
|
[V810_BIT_MOVU] = "movbsu",
|
|
[V810_BIT_ORNU] = "ornbsu",
|
|
[V810_BIT_ANDNU] = "andnbsu",
|
|
[V810_BIT_XORNU] = "xornbsu",
|
|
[V810_BIT_NOTU] = "notbsu",
|
|
};
|
|
|
|
static const char *ext_instrs[] = {
|
|
[V810_EXT_CMPF_S] = "cmpf.s",
|
|
[V810_EXT_CVT_WS] = "cvt.ws",
|
|
[V810_EXT_CVT_SW] = "cvt.sw",
|
|
[V810_EXT_ADDF_S] = "addf.s",
|
|
[V810_EXT_SUBF_S] = "subf.s",
|
|
[V810_EXT_MULF_S] = "mulf.s",
|
|
[V810_EXT_DIVF_S] = "divf.s",
|
|
[V810_EXT_XB] = "xb",
|
|
[V810_EXT_XH] = "xh",
|
|
[V810_EXT_REV] = "rev",
|
|
[V810_EXT_TRNC_SW] = "trnc.sw",
|
|
[V810_EXT_MPYHW] = "mpyhw",
|
|
};
|
|
|
|
static const char *conds[] = {
|
|
[V810_COND_V] = "v",
|
|
[V810_COND_L] = "l",
|
|
[V810_COND_E] = "e",
|
|
[V810_COND_NH] = "nh",
|
|
[V810_COND_N] = "n",
|
|
[V810_COND_NONE]= "r",
|
|
[V810_COND_LT] = "lt",
|
|
[V810_COND_LE] = "le",
|
|
[V810_COND_NV] = "nv",
|
|
[V810_COND_NL] = "nl",
|
|
[V810_COND_NE] = "ne",
|
|
[V810_COND_H] = "h",
|
|
[V810_COND_P] = "p",
|
|
[V810_COND_GE] = "ge",
|
|
[V810_COND_GT] = "gt",
|
|
};
|
|
|
|
static const char *sysreg_names[] = {
|
|
[V810_SREG_EIPC] = "EIPC",
|
|
[V810_SREG_EIPSW] = "EIPSW",
|
|
[V810_SREG_FEPC] = "FEPC",
|
|
[V810_SREG_FEPSW] = "FEPSW",
|
|
[V810_SREG_ECR] = "ECR",
|
|
[V810_SREG_PSW] = "PSW",
|
|
[V810_SREG_PIR] = "PIR",
|
|
[V810_SREG_TKCW] = "TKCW",
|
|
[V810_SREG_CHCW] = "CHCW",
|
|
[V810_SREG_ADTRE] = "ADTRE",
|
|
};
|
|
|
|
static int decode_reg_reg(const ut16 instr, struct v810_cmd *cmd) {
|
|
ut8 opcode;
|
|
|
|
opcode = OPCODE(instr);
|
|
|
|
if (opcode >= sizeof(instrs) / sizeof(char *)) {
|
|
return -1;
|
|
}
|
|
|
|
snprintf (cmd->instr, V810_INSTR_MAXLEN - 1, "%s", instrs[opcode]);
|
|
|
|
if (opcode == V810_JMP) {
|
|
snprintf (cmd->operands, V810_INSTR_MAXLEN - 1, "[r%u]",
|
|
REG1(instr));
|
|
} else {
|
|
snprintf (cmd->operands, V810_INSTR_MAXLEN - 1, "r%u, r%u",
|
|
REG1(instr), REG2(instr));
|
|
}
|
|
|
|
return 2;
|
|
}
|
|
|
|
static int decode_imm_reg(const ut16 instr, struct v810_cmd *cmd) {
|
|
ut8 opcode;
|
|
ut8 immed;
|
|
|
|
opcode = OPCODE(instr);
|
|
|
|
if (opcode >= sizeof(instrs) / sizeof(char *)) {
|
|
return -1;
|
|
}
|
|
|
|
snprintf (cmd->instr, V810_INSTR_MAXLEN - 1, "%s", instrs[opcode]);
|
|
|
|
immed = IMM5(instr);
|
|
|
|
switch (opcode) {
|
|
case V810_MOV_IMM5:
|
|
case V810_ADD_IMM5:
|
|
case V810_CMP_IMM5:
|
|
snprintf (cmd->operands, V810_INSTR_MAXLEN - 1, "%d, r%u",
|
|
(st8)SEXT5(immed), REG2(instr));
|
|
break;
|
|
case V810_LDSR:
|
|
case V810_STSR:
|
|
if (immed > 0x19 || (immed > 0x7 && immed < 0x18)) {
|
|
snprintf (cmd->operands, V810_INSTR_MAXLEN - 1, "s%u, r%u",
|
|
(ut8)immed, REG2(instr));
|
|
} else if (sysreg_names[immed]) {
|
|
snprintf (cmd->operands, V810_INSTR_MAXLEN - 1, "%s, r%u",
|
|
sysreg_names[immed], REG2(instr));
|
|
}
|
|
break;
|
|
case V810_SETF:
|
|
case V810_SHL_IMM5:
|
|
case V810_SHR_IMM5:
|
|
case V810_SAR_IMM5:
|
|
snprintf (cmd->operands, V810_INSTR_MAXLEN - 1, "%u, r%u",
|
|
immed, REG2(instr));
|
|
break;
|
|
case V810_TRAP:
|
|
snprintf (cmd->operands, V810_INSTR_MAXLEN - 1, "%u",
|
|
immed);
|
|
break;
|
|
}
|
|
|
|
return 2;
|
|
}
|
|
|
|
static int decode_bcond(const ut16 instr, struct v810_cmd *cmd) {
|
|
st16 disp;
|
|
ut8 cond;
|
|
|
|
cond = (instr >> 9) & 0xF;
|
|
disp = DISP9(instr);
|
|
|
|
if (cond == V810_COND_NOP) {
|
|
snprintf (cmd->instr, V810_INSTR_MAXLEN - 1, "nop");
|
|
} else {
|
|
snprintf (cmd->instr, V810_INSTR_MAXLEN - 1, "b%s", conds[cond]);
|
|
snprintf (cmd->operands, V810_INSTR_MAXLEN - 1, "%d", disp);
|
|
}
|
|
|
|
return 2;
|
|
}
|
|
|
|
static int decode_jump(const ut16 word1, const ut16 word2, struct v810_cmd *cmd) {
|
|
snprintf (cmd->instr, V810_INSTR_MAXLEN - 1, "%s",
|
|
instrs[OPCODE(word1)]);
|
|
snprintf (cmd->operands, V810_INSTR_MAXLEN - 1, "%d",
|
|
DISP26(word1, word2));
|
|
|
|
return 4;
|
|
}
|
|
|
|
static int decode_3operands(const ut16 word1, const ut16 word2, struct v810_cmd *cmd) {
|
|
snprintf (cmd->instr, V810_INSTR_MAXLEN - 1, "%s",
|
|
instrs[OPCODE(word1)]);
|
|
|
|
if (OPCODE(word1) == V810_ADDI) {
|
|
snprintf (cmd->operands, V810_INSTR_MAXLEN - 1, "%d, r%d, r%d",
|
|
(st16) word2, REG1(word1), REG2(word1));
|
|
} else {
|
|
snprintf (cmd->operands, V810_INSTR_MAXLEN - 1, "0x%x, r%d, r%d",
|
|
word2, REG1(word1), REG2(word1));
|
|
}
|
|
|
|
return 4;
|
|
}
|
|
|
|
static int decode_load_store(const ut16 word1, const ut16 word2, struct v810_cmd *cmd) {
|
|
snprintf (cmd->instr, V810_INSTR_MAXLEN - 1, "%s",
|
|
instrs[OPCODE(word1)]);
|
|
|
|
switch (OPCODE(word1)) {
|
|
case V810_STB:
|
|
case V810_STH:
|
|
case V810_STW:
|
|
case V810_OUTB:
|
|
case V810_OUTH:
|
|
case V810_OUTW:
|
|
snprintf (cmd->operands, V810_INSTR_MAXLEN - 1,
|
|
"r%d, %hd[r%d]",
|
|
REG2(word1), (st16)word2, REG1(word1));
|
|
break;
|
|
case V810_LDB:
|
|
case V810_LDH:
|
|
case V810_LDW:
|
|
case V810_INB:
|
|
case V810_INH:
|
|
case V810_INW:
|
|
case V810_CAXI:
|
|
snprintf (cmd->operands, V810_INSTR_MAXLEN - 1,
|
|
"%hd[r%d], r%d",
|
|
(st16)word2, REG1(word1), REG2(word1));
|
|
break;
|
|
}
|
|
|
|
return 4;
|
|
}
|
|
|
|
static int decode_bit_op(const ut16 instr, struct v810_cmd *cmd) {
|
|
ut8 subop;
|
|
|
|
subop = REG1(instr);
|
|
snprintf (cmd->instr, V810_INSTR_MAXLEN - 1, "%s", bit_instrs[subop]);
|
|
|
|
return 2;
|
|
}
|
|
|
|
static int decode_extended(const ut16 word1, const ut16 word2, struct v810_cmd *cmd) {
|
|
ut8 subop = OPCODE(word2);
|
|
if (subop > 0xC) {
|
|
return -1;
|
|
}
|
|
|
|
snprintf (cmd->instr, V810_INSTR_MAXLEN - 1, "%s",
|
|
ext_instrs[subop]);
|
|
|
|
switch (subop) {
|
|
case V810_EXT_CMPF_S:
|
|
case V810_EXT_CVT_WS:
|
|
case V810_EXT_CVT_SW:
|
|
case V810_EXT_ADDF_S:
|
|
case V810_EXT_SUBF_S:
|
|
case V810_EXT_MULF_S:
|
|
case V810_EXT_DIVF_S:
|
|
case V810_EXT_REV:
|
|
case V810_EXT_TRNC_SW:
|
|
case V810_EXT_MPYHW:
|
|
snprintf (cmd->operands, V810_INSTR_MAXLEN - 1, "r%d, r%d",
|
|
REG1(word1), REG2(word1));
|
|
break;
|
|
case V810_EXT_XB:
|
|
case V810_EXT_XH:
|
|
snprintf (cmd->operands, V810_INSTR_MAXLEN - 1, "r%d",
|
|
REG2(word1));
|
|
break;
|
|
default:
|
|
return -1;
|
|
}
|
|
|
|
return 4;
|
|
}
|
|
|
|
int v810_decode_command(const ut8 *instr, int len, struct v810_cmd *cmd) {
|
|
int ret;
|
|
ut16 word1 = 0;
|
|
ut16 word2 = 0;
|
|
|
|
word1 = r_read_le16 (instr);
|
|
if (len >= 4) {
|
|
word2 = r_read_le16 (instr + 2);
|
|
}
|
|
|
|
switch (OPCODE(word1)) {
|
|
case V810_MOV:
|
|
case V810_ADD:
|
|
case V810_SUB:
|
|
case V810_CMP:
|
|
case V810_SHL:
|
|
case V810_SHR:
|
|
case V810_JMP:
|
|
case V810_SAR:
|
|
case V810_MUL:
|
|
case V810_DIV:
|
|
case V810_MULU:
|
|
case V810_DIVU:
|
|
case V810_OR:
|
|
case V810_AND:
|
|
case V810_NOT:
|
|
case V810_XOR:
|
|
ret = decode_reg_reg (word1, cmd);
|
|
break;
|
|
case V810_MOV_IMM5:
|
|
case V810_ADD_IMM5:
|
|
case V810_SETF:
|
|
case V810_CMP_IMM5:
|
|
case V810_SHL_IMM5:
|
|
case V810_SHR_IMM5:
|
|
case V810_CLI:
|
|
case V810_SAR_IMM5:
|
|
case V810_TRAP:
|
|
case V810_RETI:
|
|
case V810_HALT:
|
|
case V810_LDSR:
|
|
case V810_STSR:
|
|
case V810_SEI:
|
|
ret = decode_imm_reg (word1, cmd);
|
|
break;
|
|
case V810_MOVEA:
|
|
case V810_ADDI:
|
|
case V810_ORI:
|
|
case V810_ANDI:
|
|
case V810_XORI:
|
|
case V810_MOVHI:
|
|
ret = decode_3operands (word1, word2, cmd);
|
|
break;
|
|
case V810_JR:
|
|
case V810_JAL:
|
|
ret = decode_jump (word1, word2, cmd);
|
|
break;
|
|
case V810_LDB:
|
|
case V810_LDH:
|
|
case V810_LDW:
|
|
case V810_STB:
|
|
case V810_STH:
|
|
case V810_STW:
|
|
case V810_INB:
|
|
case V810_INH:
|
|
case V810_CAXI:
|
|
case V810_INW:
|
|
case V810_OUTB:
|
|
case V810_OUTH:
|
|
case V810_OUTW:
|
|
ret = decode_load_store (word1, word2, cmd);
|
|
break;
|
|
case V810_BSTR:
|
|
ret = decode_bit_op (word1, cmd);
|
|
break;
|
|
case V810_EXT:
|
|
ret = decode_extended (word1, word2, cmd);
|
|
break;
|
|
default:
|
|
if ((OPCODE(word1) >> 3) == 0x4) {
|
|
ret = decode_bcond (word1, cmd);
|
|
} else {
|
|
ret = -1;
|
|
}
|
|
}
|
|
|
|
if ((ret > 0) && (len < ret)) {
|
|
ret = -1;
|
|
}
|
|
|
|
return ret;
|
|
}
|