radare2/libr/asm/arch/v810/v810_disas.c
2018-09-13 10:17:26 +02:00

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