rizin/librz/arch/isa/v850/v850_disas.c
Khairul Azhar Kasmiran c8878d3139
Convert %ll format specifiers to PFMT64 (#6267)
* Convert `%ll` format specifiers to PFMT64
* Remove ` ""` at end of some PFMT64
2026-04-22 05:57:04 +08:00

1693 lines
44 KiB
C

// SPDX-FileCopyrightText: 2014-2018 Fedor Sakharov <fedor.sakharov@gmail.com>
// SPDX-License-Identifier: LGPL-3.0-only
#include <rz_types.h>
#include <rz_util.h>
#include "v850_disas.h"
#define R1 GR_get(get_reg1(inst))
#define R2 GR_get(get_reg2(inst))
#define R3 GR_get(get_reg3(inst))
static const char *instrs[] = {
[V850_MOV] = "mov",
[V850_NOT] = "not",
[V850_DIVH] = "divh",
[V850_JMP] = "jmp",
[V850_SATSUBR] = "satsubr",
[V850_SATSUB] = "stasub",
[V850_SATADD] = "satadd",
[V850_MULH] = "mulh",
[V850_OR] = "or",
[V850_XOR] = "xor",
[V850_AND] = "and",
[V850_TST] = "tst",
[V850_SUBR] = "subr",
[V850_SUB] = "sub",
[V850_ADD] = "add",
[V850_CMP] = "cmp",
[V850_SLDB] = "sldb",
[V850_SSTB] = "sstb",
[V850_SLDH] = "sldh",
[V850_SSTH] = "ssth",
[V850_SLDW] = "sldw",
[V850_SSTW] = "sstw",
[V850_BCOND] = "bcond",
[V850_ADDI] = "addi",
[V850_MOVEA] = "movea",
[V850_MOVHI] = "movhi",
[V850_SATSUBI] = "satsubi",
[V850_ORI] = "ori",
[V850_XORI] = "xori",
[V850_ANDI] = "andi",
[V850_MULHI] = "mulhi",
[V850_LDB] = "ld.b",
[V850_LDH] = "ld.h",
[V850_LDW] = "ld.w",
[V850_STB] = "st.b",
[V850_STH] = "st.h",
[V850_STW] = "st.w",
[V850_LDBU] = "ld.bu",
[V850_LDHU] = "ld.hu",
[V850_LDDW] = "ld.dw",
[V850_SLDBU] = "sld.bu",
[V850_SLDHU] = "sld.hu",
[V850_STDW] = "st.dw",
[V850_MULU] = "mulu",
[V850_MAC] = "mac",
[V850_MACU] = "macu",
[V850_ADF] = "adf",
[V850_SBF] = "sbf",
[V850_BINS] = "bins",
[V850_BSH] = "bsh",
[V850_BSW] = "bsw",
[V850_CMOV] = "cmov",
[V850_HSH] = "hsh",
[V850_HSW] = "hsw",
[V850_ROTL] = "rotl",
[V850_SAR] = "sar",
[V850_SASF] = "sasf",
[V850_SETF] = "setf",
[V850_SHL] = "shl",
[V850_SHR] = "shr",
[V850_SXB] = "sxb",
[V850_SXH] = "sxh",
[V850_ZXB] = "zxb",
[V850_ZXH] = "zxh",
[V850_SCH0L] = "sch0l",
[V850_SCH0R] = "sch0r",
[V850_SCH1L] = "sch1l",
[V850_SCH1R] = "sch1r",
[V850_DIVHU] = "divhu",
[V850_DIVU] = "divu",
[V850_DIVQ] = "divq",
[V850_DIVQU] = "divqu",
[V850_DIV] = "div",
[V850_MUL] = "mul",
[V850_LOOP] = "loop",
[V850_SET1] = "set1",
[V850_NOT1] = "not1",
[V850_CLR1] = "clr1",
[V850_TST1] = "tst1",
[V850_JARL] = "jarl",
[V850_JR] = "jr",
[V850_CALLT] = "callt",
[V850_CAXI] = "caxi",
[V850_CLL] = "cll",
[V850_CTRET] = "ctret",
[V850_DI] = "di",
[V850_DISPOSE] = "dispose",
[V850_EI] = "ei",
[V850_EIRET] = "eiret",
[V850_FERET] = "feret",
[V850_FETRAP] = "fetrap",
[V850_HALT] = "halt",
[V850_LDSR] = "ldsr",
[V850_LDLW] = "ldl.w",
[V850_NOP] = "nop",
[V850_POPSP] = "popsp",
[V850_PREPARE] = "prepare",
[V850_PUSHSP] = "pushsp",
[V850_RIE] = "rie",
[V850_SNOOZE] = "snooze",
[V850_STSR] = "stsr",
[V850_STCW] = "stc.w",
[V850_SWITCH] = "switch",
[V850_SYNCE] = "synce",
[V850_SYNCI] = "synci",
[V850_SYNCM] = "syncm",
[V850_SYNCP] = "syncp",
[V850_SYSCALL] = "syscall",
[V850_TRAP] = "trap",
[V850_CACHE] = "cache",
[V850_PREF] = "pref",
[V850_ABSF_D] = "absf.d",
[V850_ABSF_S] = "absf.s",
[V850_ADDF_D] = "addf.d",
[V850_ADDF_S] = "addf.s",
[V850_CEILF_DL] = "ceilf.dl",
[V850_CEILF_DUL] = "ceilf.dul",
[V850_CEILF_DUW] = "ceilf.duw",
[V850_CEILF_DW] = "ceilf.dw",
[V850_CEILF_SL] = "ceilf.sl",
[V850_CEILF_SUL] = "ceilf.sul",
[V850_CEILF_SUW] = "ceilf.suw",
[V850_CEILF_SW] = "ceilf.sw",
[V850_CMOVF_D] = "cmovf.d",
[V850_CMOVF_S] = "cmovf.s",
[V850_CMPF_D] = "cmpf.d",
[V850_CMPF_S] = "cmpf.s",
[V850_CVTF_DL] = "cvtf.dl",
[V850_CVTF_DS] = "cvtf.ds",
[V850_CVTF_DUL] = "cvtf.dul",
[V850_CVTF_DUW] = "cvtf.duw",
[V850_CVTF_DW] = "cvtf.dw",
[V850_CVTF_LD] = "cvtf.ld",
[V850_CVTF_LS] = "cvtf.ls",
[V850_CVTF_SD] = "cvtf.sd",
[V850_CVTF_SL] = "cvtf.sl",
[V850_CVTF_SUL] = "cvtf.sul",
[V850_CVTF_SUW] = "cvtf.suw",
[V850_CVTF_SW] = "cvtf.sw",
[V850_CVTF_ULD] = "cvtf.uld",
[V850_CVTF_ULS] = "cvtf.uls",
[V850_CVTF_UWD] = "cvtf.uwd",
[V850_CVTF_UWS] = "cvtf.uws",
[V850_CVTF_WD] = "cvtf.wd",
[V850_CVTF_WS] = "cvtf.ws",
[V850_DIVF_D] = "divf.d",
[V850_DIVF_S] = "divf.s",
[V850_FLOORF_DL] = "floorf.dl",
[V850_FLOORF_DUL] = "floorf.dul",
[V850_FLOORF_DUW] = "floorf.duw",
[V850_FLOORF_DW] = "floorf.dw",
[V850_FLOORF_SL] = "floorf.sl",
[V850_FLOORF_SUL] = "floorf.sul",
[V850_FLOORF_SUW] = "floorf.suw",
[V850_FLOORF_SW] = "floorf.sw",
[V850_MADDF_S] = "maddf.s",
[V850_MAXF_D] = "maxf.d",
[V850_MAXF_S] = "maxf.s",
[V850_MINF_D] = "minf.d",
[V850_MINF_S] = "minf.s",
[V850_MSUBF_S] = "msubf.s",
[V850_MULF_D] = "mulf.d",
[V850_MULF_S] = "mulf.s",
[V850_NEGF_D] = "negf.d",
[V850_NEGF_S] = "negf.s",
[V850_NMADDF_S] = "nmaddf.s",
[V850_NMSUBF_S] = "nmsubf.s",
[V850_RECIPF_D] = "recipf.d",
[V850_RECIPF_S] = "recipf.s",
[V850_RSQRTF_D] = "rsqrtf.d",
[V850_RSQRTF_S] = "rsqrtf.s",
[V850_SQRTF_D] = "sqrtf.d",
[V850_SQRTF_S] = "sqrtf.s",
[V850_SUBF_D] = "subf.d",
[V850_SUBF_S] = "subf.s",
[V850_TRFSR] = "trfsr",
[V850_TRNCF_DL] = "trncf.dl",
[V850_TRNCF_DUL] = "trncf.dul",
[V850_TRNCF_DUW] = "trncf.duw",
[V850_TRNCF_DW] = "trncf.dw",
[V850_TRNCF_SL] = "trncf.sl",
[V850_TRNCF_SUL] = "trncf.sul",
[V850_TRNCF_SUW] = "trncf.suw",
[V850_TRNCF_SW] = "trncf.sw",
};
static const char *conds[] = {
[V850_COND_BV] = "v",
[V850_COND_BL] = "l",
[V850_COND_BE] = "e",
[V850_COND_BNH] = "nh",
[V850_COND_BN] = "n",
[V850_COND_BR] = "r",
[V850_COND_BLT] = "lt",
[V850_COND_BLE] = "le",
[V850_COND_BNV] = "nv",
[V850_COND_BNL] = "nl",
[V850_COND_BNE] = "ne",
[V850_COND_BH] = "h",
[V850_COND_BP] = "p",
[V850_COND_BSA] = "sa",
[V850_COND_BGE] = "ge",
[V850_COND_BGT] = "gt",
};
#define INSTR(...) snprintf(inst->instr, V850_INSTR_MAXLEN - 1, __VA_ARGS__);
#define OPERANDS(...) snprintf(inst->operands, V850_OPERANDS_MAXLEN - 1, __VA_ARGS__);
#define PRINT_INSTR INSTR("%s", instrs[inst->id])
#define ALSO(x, y) \
{ \
if ((x)) { \
inst->id = y; \
goto ok; \
}; \
break; \
}
static bool decode_formatI(V850_Inst *inst) {
if (V850_word(inst, 1) == 0) {
inst->id = V850_NOP;
goto ok;
}
ut8 opcode = get_opcode(inst, 5, 10);
ut8 r1 = get_reg1(inst);
ut8 r2 = get_reg2(inst);
switch (opcode) {
case V850_DIVH: ALSO(r1 && r2, opcode);
case V850_MOV:
case V850_SATADD:
case V850_SATSUB:
case V850_SATSUBR:
case V850_MULH: ALSO(r2, opcode);
case V850_ADD:
case V850_AND:
case V850_CMP:
case V850_NOT:
case V850_OR:
case V850_SUB:
case V850_SUBR:
case V850_TST:
case V850_XOR: inst->id = opcode; goto ok;
default: break;
}
ut16 w1 = V850_word(inst, 1);
if (w1 == 0b0000000001000000) {
inst->id = V850_RIE;
goto ok;
} else if (w1 == 0b0000000000011101) {
inst->id = V850_SYNCE;
goto ok;
} else if (w1 == 0b0000000000011100) {
inst->id = V850_SYNCI;
goto ok;
} else if (w1 == 0b0000000000011110) {
inst->id = V850_SYNCM;
goto ok;
} else if (w1 == 0b0000000000011111) {
inst->id = V850_SYNCP;
goto ok;
} else if ((w1 & ~(0xf << 11)) == 0b0000000001000000) {
inst->id = V850_FETRAP;
goto ok;
} else if (r2 == 0) {
switch (opcode) {
case V850_JMP: inst->id = V850_JMP; goto ok;
case 0b000010: inst->id = V850_SWITCH; goto ok;
case 0b000101: inst->id = V850_SXB; goto ok;
case 0b000111: inst->id = V850_SXH; goto ok;
case 0b000100: inst->id = V850_ZXB; goto ok;
case 0b000110: inst->id = V850_ZXH; goto ok;
default: break;
}
}
return false;
ok:
switch (inst->id) {
case V850_RIE:
case V850_SYNCP:
case V850_SYNCI:
case V850_SYNCE:
case V850_SYNCM:
break;
case V850_JMP:
OPERANDS("[%s]", R1);
break;
case V850_SWITCH:
case V850_SXB:
case V850_SXH:
case V850_ZXB:
case V850_ZXH:
OPERANDS("%s", R1);
break;
case V850_FETRAP:
OPERANDS("0x%x", i_vec4(inst));
break;
case V850_NOP:
break;
default: {
OPERANDS("%s, %s", R1, R2);
break;
}
}
PRINT_INSTR;
inst->format = I_reg_reg;
return true;
}
static bool decode_formatII(V850_Inst *inst) {
ut8 opcode = get_opcode(inst, 5, 10);
if (get_reg2(inst) != 0) {
switch (opcode) {
case 0x10:
inst->id = V850_MOV;
inst->imm = sext32(get_reg1(inst), 5);
break;
case 0x11:
inst->id = V850_SATADD;
inst->imm = sext32(get_reg1(inst), 5);
break;
case 0x12:
inst->id = V850_ADD;
inst->imm = sext32(get_reg1(inst), 5);
break;
case 0x13:
inst->id = V850_CMP;
inst->imm = sext32(get_reg1(inst), 5);
break;
case 0x14:
inst->id = V850_SHR;
inst->imm = get_reg1(inst);
break;
case 0x15:
inst->id = V850_SAR;
inst->imm = get_reg1(inst);
break;
case 0x16:
inst->id = V850_SHL;
inst->imm = get_reg1(inst);
break;
case 0x17:
inst->id = V850_MULH;
inst->imm = sext32(get_reg1(inst), 5);
break;
default:
return false;
}
} else {
// CALLT
if (inst->d >> 6 == 0x8) {
inst->id = V850_CALLT;
inst->imm = (inst->d & 0x3f) << 1;
} else {
return false;
}
}
PRINT_INSTR;
if (inst->id == V850_CALLT) {
OPERANDS("%u", inst->imm);
} else {
OPERANDS("%d, %s", inst->imm, R2);
}
inst->format = II_imm_reg;
return true;
}
static bool decode_formatIII(V850_Inst *inst) {
ut8 opcode = get_opcode(inst, 7, 10);
if (opcode != 0xb) {
return false;
}
inst->id = V850_BCOND;
inst->disp = sext32(get_disp9(inst), 9);
ut8 cond = get_cond(inst);
const char *cond_s = conds[cond];
if (!cond_s) {
rz_warn_if_reached();
return false;
}
INSTR("b%s", cond_s);
OPERANDS("0x%" PFMT64x, (st64)(inst->addr) + (st32)inst->disp);
inst->format = III_conditional_branch;
return true;
}
static bool decode_formatIV_1(V850_Inst *inst) {
ut8 opcode = get_opcode(inst, 7, 10);
inst->disp = V850_word(inst, 2) & 0x7f;
switch (opcode) {
case 0x6: inst->id = V850_SLDB; break;
case 0x8:
inst->id = V850_SLDH;
inst->disp <<= 1;
break;
case 0x7: inst->id = V850_SSTB; break;
case 0x9:
inst->id = V850_SSTH;
inst->disp <<= 1;
break;
default:
if (opcode != 0xa) {
return false;
}
if (V850_word(inst, 1) & 1) {
inst->id = V850_SSTW;
} else {
inst->id = V850_SLDW;
}
inst->disp = (inst->disp & ~1) << 1;
break;
}
PRINT_INSTR;
OPERANDS("%d[ep] %s", inst->disp, R2);
inst->format = IV_load_store16;
return true;
}
static bool decode_formatIV_2(V850_Inst *inst) {
ut8 opcode = get_opcode(inst, 4, 10);
inst->disp = V850_word(inst, 2) & 0xf;
switch (opcode) {
case 0x6: inst->id = V850_SLDBU; break;
case 0x7:
inst->id = V850_SLDHU;
inst->disp <<= 1;
break;
default: return false;
}
PRINT_INSTR;
OPERANDS("%d[ep] %s", inst->disp, R2);
inst->format = IV_load_store16;
return true;
}
static bool decode_formatV(V850_Inst *inst) {
if (V850_word(inst, 2) & 1) {
return false;
}
ut8 opcode = get_opcode(inst, 6, 10);
if (opcode != 0x1e) {
return false;
}
ut32 disp22 = get_disp22(inst);
inst->sdisp = sext32(disp22, 22);
ut64 target = inst->addr + inst->sdisp;
ut8 reg2 = get_reg2(inst);
if (reg2 == 0) {
inst->id = V850_JR;
OPERANDS("0x%" PFMT64x, target);
} else {
inst->id = V850_JARL;
OPERANDS("0x%" PFMT64x ", %s", target, R2);
}
PRINT_INSTR;
inst->format = V_jump;
return true;
}
static bool decode_formatVI(V850_Inst *inst, RzBuffer *b) {
ut8 opcode = get_opcode(inst, 5, 10);
ut8 reg1 = get_reg1(inst);
ut8 reg2 = get_reg2(inst);
inst->imm = get_imm16(inst);
if (reg2 == 0) {
switch (opcode) {
case 0x17:
if (reg1) {
inst->id = V850_JARL;
} else {
inst->id = V850_JR;
}
break;
case 0x37: inst->id = V850_JMP; break;
case 0x31: inst->id = V850_MOV; break;
default:
return false;
}
ut16 tmp;
if (!rz_buf_read_le16_at(b, 4, &tmp)) {
return false;
}
inst->byte_size += 2;
inst->d |= ((ut64)(tmp) << 32);
inst->imm |= (ut32)(V850_word(inst, 3)) << 16;
} else {
switch (opcode) {
case V850_ADDI:
case V850_MOVEA:
case V850_SATSUBI:
inst->id = opcode;
inst->imm = sext32(inst->imm, 16);
break;
case V850_ANDI:
case V850_MULHI:
case V850_MOVHI:
case V850_ORI:
case V850_XORI:
inst->id = opcode;
break;
default: return false;
}
}
PRINT_INSTR;
switch (inst->id) {
case V850_MOV:
OPERANDS("0x%x, %s", inst->imm, R1);
break;
case V850_ANDI:
case V850_ADDI:
case V850_MOVHI:
case V850_MULHI:
case V850_ORI:
case V850_SATSUBI:
case V850_XORI:
OPERANDS("%d, %s, %s", inst->imm, R1, R2);
break;
default:
OPERANDS("0x%x, %s, %s", inst->imm, R1, R2);
break;
}
inst->format = VI_3operand;
return true;
}
static bool decode_formatVII(V850_Inst *inst) {
ut8 opcode = get_opcode(inst, 5, 10);
ut8 sub1 = V850_word(inst, 2) & 1;
ut16 sub2 = extract(V850_word(inst, 2), 0, 11);
ut8 reg2 = get_reg2(inst);
inst->disp = get_imm16(inst);
switch (opcode) {
case 0x38:
inst->id = V850_LDB;
break;
case 0x3a:
inst->id = V850_STB;
break;
case 0x3b:
if (!(sub1)) {
inst->id = V850_STH;
} else {
inst->id = V850_STW;
}
inst->disp &= ~1;
break;
case 0x3c:
case 0x3d:
if (sub1 && reg2) {
inst->id = V850_LDBU;
inst->disp = inst->disp | (opcode & 1);
break;
}
return false;
case 0x39: {
if (!(sub1)) {
inst->id = V850_LDH;
} else {
inst->id = V850_LDW;
}
inst->disp &= ~1;
break;
}
case 0x37:
if (reg2 == 0 && sub1) {
inst->id = V850_LOOP;
inst->disp &= ~1;
break;
}
return false;
case 0x3f: {
if (reg2 == 0 && sub1) {
inst->id = V850_BCOND;
ut8 cond = get_cond(inst);
inst->disp = sext32(((inst->disp >> 1) | (((V850_word(inst, 1) >> 4) & 1) << 15)) << 1, 17);
INSTR("b%s", conds[cond]);
OPERANDS("0x%" PFMT64x, (st64)inst->addr + (st32)inst->disp);
goto ok;
}
if (sub1) {
inst->id = V850_LDHU;
break;
}
if (reg2 == 0 && sub2 == 0x378) {
inst->id = V850_LDLW;
break;
}
if (reg2 == 0 && sub2 == 0x37a) {
inst->id = V850_STCW;
break;
}
if (reg2 != 0 && (sub2 == 0xc4 || sub2 == 0xc6)) {
inst->id = V850_ROTL;
inst->imm = get_reg1(inst);
break;
}
return false;
}
default: return false;
}
PRINT_INSTR;
switch (inst->id) {
case V850_LDB:
case V850_LDBU:
case V850_LDH:
case V850_LDHU:
case V850_LDW:
inst->disp = sext32(inst->disp, 16);
OPERANDS("%d[%s], %s", (st32)inst->disp, R1, R2);
break;
case V850_STB:
case V850_STH:
case V850_STW:
OPERANDS("%s, %d[%s]", R2, inst->disp, R1);
break;
case V850_BCOND:
break;
case V850_LDLW:
OPERANDS("[%s], %s", R1, R3);
break;
case V850_STCW:
OPERANDS("%s, [%s]", R3, R1);
break;
case V850_LOOP:
OPERANDS("%s, %d", R1, inst->disp);
break;
case V850_ROTL:
if (sub2 == 0xc4) {
OPERANDS("%d, %s, %s", inst->imm, R2, R3);
} else if (sub2 == 0xc6) {
OPERANDS("%s, %s, %s", R1, R2, R3);
} else {
rz_warn_if_reached();
}
break;
default: break;
}
ok:
inst->format = VII_load_store32;
return true;
}
static bool decode_formatVIII(V850_Inst *inst) {
ut8 opcode = get_opcode(inst, 5, 10);
ut8 sub_opcode = V850_word(inst, 1) >> 14;
switch (opcode | (sub_opcode << 6)) {
case 0x38 | (0x2 << 6): inst->id = V850_CLR1; break;
case 0x3e | (0x1 << 6): inst->id = V850_NOT1; break;
case 0x3e | (0x0 << 6): inst->id = V850_SET1; break;
case 0x3e | (0x3 << 6): inst->id = V850_TST1; break;
default: return false;
}
ut8 bit = (V850_word(inst, 1) >> 11) & 0x7;
inst->disp = get_imm16(inst);
PRINT_INSTR;
OPERANDS("%d, %d[%s]", bit, inst->disp, R1);
inst->format = VIII_bit;
return true;
}
static bool decode_formatIX(V850_Inst *inst) {
if (V850_word(inst, 2) & 1) {
return false;
}
ut8 reg1 = get_reg1(inst);
if (extract(inst->d, 4, 6) == 0x3e && V850_word(inst, 2) == 0b0000001000000000) {
inst->id = V850_SASF;
} else if (extract(inst->d, 4, 6) == 0x3e && V850_word(inst, 2) == 0b0000000000000000) {
inst->id = V850_SETF;
} else {
ut8 opcode = get_opcode(inst, 5, 10);
ut16 sub_opcode = get_imm16(inst) & ~1;
if (reg1 == 0) {
if (extract(sub_opcode, 0, 11) == 0x364) {
inst->id = V850_SCH0L;
} else if (extract(sub_opcode, 0, 11) == 0x360) {
inst->id = V850_SCH0R;
} else if (extract(sub_opcode, 0, 11) == 0x366) {
inst->id = V850_SCH1L;
} else if (extract(sub_opcode, 0, 11) == 0x362) {
inst->id = V850_SCH1R;
} else {
return false;
}
} else {
if (opcode == 0x3f) {
switch (V850_word(inst, 2)) {
case 0b0000000011100100: inst->id = V850_CLR1; break;
case 0b0000000011100010: inst->id = V850_NOT1; break;
case 0b0000000011100110: inst->id = V850_TST1; break;
case 0b0000000011100000: inst->id = V850_SET1; break;
case 0b0000000010100000: inst->id = V850_SAR; break;
case 0b0000000011000000: inst->id = V850_SHL; break;
case 0b0000000010000000: inst->id = V850_SHR; break;
default:
if (extract(sub_opcode, 0, 11) == 0x020) {
inst->id = V850_LDSR;
} else if (extract(sub_opcode, 0, 11) == 0x040) {
inst->id = V850_STSR;
} else if (extract(sub_opcode, 4, 7) == 0x09 ||
extract(sub_opcode, 4, 7) == 0x0b ||
extract(sub_opcode, 4, 7) == 0x0d) {
inst->id = V850_BINS;
} else {
return false;
}
break;
}
} else {
return false;
}
}
}
PRINT_INSTR;
ut8 reg2 = get_reg2(inst);
switch (inst->id) {
case V850_STSR:
OPERANDS("%s, %s, %d", SR_get(reg1, get_selID(inst)), R2, get_reg3(inst));
break;
case V850_LDSR:
OPERANDS("%s, %s, %d", R1, SR_get(reg2, get_selID(inst)), get_reg3(inst));
break;
case V850_SHR:
case V850_SAR:
case V850_SHL: OPERANDS("%s, %s", R1, R2); break;
case V850_CLR1:
case V850_NOT1:
case V850_TST1:
case V850_SET1: OPERANDS("%s, [%s]", R2, R1); break;
case V850_SASF:
case V850_SETF: OPERANDS("%s, %s", conds[get_cond(inst)], R2); break;
case V850_BINS: OPERANDS("%s, %d, %d, %s", R1, bins_pos(inst), bins_width(inst), R2); break;
case V850_SCH0L:
case V850_SCH0R:
case V850_SCH1L:
case V850_SCH1R: OPERANDS("%s, %s", R2, R3); break;
default: break;
}
inst->format = IX_extended1;
return true;
}
static bool decode_formatX(V850_Inst *inst) {
if (V850_word(inst, 2) & 1) {
return false;
}
ut32 dword = V850_word(inst, 1) | ((ut32)(V850_word(inst, 2)) << 16);
if (dword == 0xf160ffff) {
inst->id = V850_CLL;
} else if (dword == 0b00000001010001000000011111100000) {
inst->id = V850_CTRET;
} else if (dword == 0b00000001011000000000011111100000) {
inst->id = V850_DI;
} else if (dword == 0b00000001011000001000011111100000) {
inst->id = V850_EI;
} else if (dword == 0b00000001010010000000011111100000) {
inst->id = V850_EIRET;
} else if (dword == 0b00000001010010100000011111100000) {
inst->id = V850_FERET;
} else if (dword == 0b00000001001000000000011111100000) {
inst->id = V850_HALT;
} else if (dword == 0b00000001001000000000111111100000) {
inst->id = V850_SNOOZE;
} else if (V850_word(inst, 2) == 0 && extract(V850_word(inst, 1), 4, 7) == 0x7f) {
inst->id = V850_RIE;
OPERANDS("%d %d", extract(V850_word(inst, 1), 11, 5), extract(V850_word(inst, 1), 0, 4));
goto ok;
} else if ((V850_word(inst, 2) & 0xc7ff) == 0x0160 && (V850_word(inst, 1) >> 5) == 0b11010111111) {
inst->id = V850_SYSCALL;
OPERANDS("0x%02x", x_vector8(inst));
goto ok;
} else if (V850_word(inst, 2) == 0b0000000100000000 && (V850_word(inst, 1) >> 5) == 0b00000111111) {
inst->id = V850_TRAP;
OPERANDS("%d", V850_word(inst, 1) & 0x1f);
goto ok;
} else if (extract(V850_word(inst, 2), 0, 11) == 0b00101100000 && (extract(V850_word(inst, 1), 5, 6) | extract(V850_word(inst, 1), 13, 3) << 6) == 0x1ff) {
inst->id = V850_CACHE;
ut16 cacheop = extract(V850_word(inst, 2), 11, 5) | extract(V850_word(inst, 1), 11, 2);
OPERANDS("0x%02x [%s]", cacheop, R1);
goto ok;
} else if (extract(V850_word(inst, 2), 0, 11) == 0b00101100000 && extract(V850_word(inst, 1), 5, 11) == 0b11011111111) {
inst->id = V850_PREF;
ut16 prefop = extract(V850_word(inst, 2), 11, 5);
OPERANDS("0x%02x [%s]", prefop, R1);
goto ok;
} else {
return false;
}
ok:
PRINT_INSTR;
inst->format = X_extended2;
return true;
}
static bool decode_formatXI(V850_Inst *inst) {
if (V850_word(inst, 2) & 1) {
return false;
}
ut8 opcode = get_opcode(inst, 5, 10);
ut8 reg2 = get_reg2(inst);
ut16 sub_opcode = extract(V850_word(inst, 2), 1, 10);
if (opcode != 0x3f) {
return false;
}
switch (sub_opcode) {
case 0b0001110111: inst->id = V850_CAXI; break;
case 0b0101100000: inst->id = V850_DIV; break;
case 0b0101000000: inst->id = V850_DIVH; break;
case 0b0101000001: inst->id = V850_DIVHU; break;
case 0b0101111110: inst->id = V850_DIVQ; break;
case 0b0101111111: inst->id = V850_DIVQU; break;
case 0b0101100001: inst->id = V850_DIVU; break;
case 0b0100010000: inst->id = V850_MUL; break;
case 0b0100010001: inst->id = V850_MULU; break;
case 0b0001010001: inst->id = V850_SAR; break;
case 0b0111011101: inst->id = V850_SATADD; break;
case 0b0111001101: inst->id = V850_SATSUB; break;
case 0b0001100001: inst->id = V850_SHL; break;
case 0b0001000001: inst->id = V850_SHR; break;
case 0b1000101100: inst->id = V850_ABSF_D; break;
default:
if (sub_opcode == 0b0010110000) {
switch (reg2) {
case 0x18: inst->id = V850_JARL; break;
case 0x0c: inst->id = V850_POPSP; break;
case 0x08: inst->id = V850_PUSHSP; break;
default: break;
}
} else {
ut16 sub_opcode_shifted = sub_opcode >> 4;
switch (sub_opcode_shifted) {
case 0b011101: inst->id = V850_ADF; break;
case 0b011100: inst->id = V850_SBF; break;
case 0b011001: inst->id = V850_CMOV; break;
default: {
ut16 ext_res = extract(V850_word(inst, 2), 5, 7);
switch (ext_res) {
case 0b0011110: inst->id = V850_MAC; break;
case 0b0011111: inst->id = V850_MACU; break;
default: return false;
}
}
}
}
break;
}
PRINT_INSTR;
ut8 cccc = extract(V850_word(inst, 2), 1, 4);
switch (inst->id) {
case V850_MACU:
case V850_MAC: OPERANDS("[%s], %s, %s, %s", R1, R2, R3, GR_get(xi_reg4(inst))); break;
case V850_CMOV:
case V850_SBF:
case V850_ADF: OPERANDS("%s, %s, %s, %s", conds[cccc], R1, R2, R3); break;
case V850_JARL: OPERANDS("[%s], %s", R1, R3); break;
case V850_PUSHSP:
case V850_POPSP: OPERANDS("%d-%d", xi_rh(inst), xi_rt(inst)); break;
case V850_ABSF_D: OPERANDS("%s, %s", R2, R3); break;
default: OPERANDS("[%s], %s, %s", R1, R2, R3); break;
}
inst->format = XI_extended3;
return true;
}
static bool decode_formatXII(V850_Inst *inst) {
ut8 opcode = get_opcode(inst, 5, 10);
ut16 sub_opcode = extract(V850_word(inst, 2), 1, 10) | (get_reg1(inst) << 10);
if (opcode != 0x3f) {
return false;
}
switch (sub_opcode) {
case 0b0110100001: inst->id = V850_BSH; break;
case 0b0110100000: inst->id = V850_BSW; break;
case 0b0110100011: inst->id = V850_HSH; break;
case 0b0110100010: inst->id = V850_HSW; break;
default:
if ((sub_opcode >> 4 & 0x3f) == 0b011000) {
inst->id = V850_CMOV;
} else if ((sub_opcode & 0x3e1) == 0b0100100000) {
inst->id = V850_MUL;
} else if ((sub_opcode & 0x3e1) == 0b0100100001) {
inst->id = V850_MULU;
} else {
return false;
}
break;
}
PRINT_INSTR;
if (inst->id == V850_CMOV) {
OPERANDS("%s, %d, %s, %s", conds[xi_cond(inst)], xii_imm5(inst), R2, R3);
} else {
OPERANDS("%s, %s", R2, R3);
}
inst->format = XII_extended4;
return true;
}
typedef struct {
ut8 l;
ut8 r;
} Range;
static void list12_to_range(const ut8 lst[], unsigned n, Range xs[], unsigned *pnxs) {
Range *r = xs;
for (int i = 0; i < n; ++i) {
ut8 x = lst[i];
if (r->l == 0) {
r->l = r->r = x;
continue;
}
if (x - r->r == 1) {
r->r = x;
continue;
}
r++;
r->l = r->r = x;
}
if (pnxs) {
*pnxs = r - xs + 1;
}
}
static char *fmt_list(ut32 lst) {
ut8 set[12] = { 0 };
unsigned n = 0;
xiii_sorted_list(lst, set, &n, false);
Range xs[12] = { 0 };
unsigned nxs = 0;
list12_to_range(set, n, xs, &nxs);
RzStrBuf sb = { 0 };
rz_strbuf_initf(&sb, "{");
bool sep = false;
for (int i = 0; i < nxs; ++i) {
Range *r = xs + i;
if (!(r && r->l && r->r)) {
break;
}
if (sep) {
rz_strbuf_append(&sb, ", ");
}
if (r->l == r->r) {
rz_strbuf_appendf(&sb, "%s", GR_get(r->l));
} else {
rz_strbuf_appendf(&sb, "%s - %s", GR_get(r->l), GR_get(r->r));
}
sep = true;
}
rz_strbuf_append(&sb, "}");
return rz_strbuf_drain_nofree(&sb);
}
static bool decode_formatXIII(V850_Inst *inst, RzBuffer *b) {
ut16 opcode = get_opcode(inst, 6, 15);
ut16 list12 = xiii_list(inst);
char *list_str = fmt_list(list12);
if (!list_str) {
rz_warn_if_reached();
return false;
}
ut8 sub_opcode = xiii_sub_r1(inst);
switch (opcode) {
case 0b11001: {
inst->id = V850_DISPOSE;
PRINT_INSTR;
if (sub_opcode > 0) {
OPERANDS("%d, %s, %s", xiii_imm5(inst), list_str, GR_get(sub_opcode));
} else {
OPERANDS("%d, %s", xiii_imm5(inst), list_str);
}
break;
}
case 0b11110:
if (sub_opcode == 1) {
inst->id = V850_PREPARE;
OPERANDS("%s, %d", list_str, xiii_imm5(inst));
} else if ((sub_opcode & 0x7) == 0x3) {
inst->id = V850_PREPARE;
switch (xiii_ff(inst)) {
case 0b00: OPERANDS("%s, %d, sp", list_str, xiii_imm5(inst)); goto ok;
case 0b01: {
ut16 tmp;
if (!rz_buf_read_le16(b, &tmp)) {
return false;
}
inst->byte_size += 2;
inst->d |= (ut64)(tmp) << 32;
inst->imm = sext32(V850_word(inst, 3), 16);
break;
}
case 0b10: {
ut16 tmp;
if (!rz_buf_read_le16(b, &tmp)) {
return false;
}
inst->byte_size += 2;
inst->d |= tmp < 32;
inst->imm = (V850_word(inst, 3)) << 16;
break;
}
case 0b11: {
ut32 tmp = 0;
if (!rz_buf_read_le32(b, &tmp)) {
return false;
}
inst->imm = tmp;
inst->d |= (ut64)(tmp) << 32;
break;
}
default: break;
}
OPERANDS("%s, %d, %d", list_str, xiii_imm5(inst), inst->imm);
} else {
goto err;
}
PRINT_INSTR;
break;
default:
goto err;
}
ok:
free(list_str);
inst->format = XIII_stack;
return true;
err:
free(list_str);
return false;
}
static bool decode_formatXIV(V850_Inst *inst) {
ut8 opcode = get_opcode(inst, 5, 10);
ut8 sub_opcode = (V850_word(inst, 2) & 0xf) | ((V850_word(inst, 1) >> 11) << 4);
ut16 sub_opcode2 = (V850_word(inst, 2) & 0x1f) | ((V850_word(inst, 1) >> 11) << 5);
switch (opcode | (sub_opcode << 6)) {
case 0b111100 | (0b0101 << 6): inst->id = V850_LDB; break;
case 0b111101 | (0b0101 << 6): inst->id = V850_LDBU; break;
case 0b111100 | (0b1101 << 6): inst->id = V850_STB; break;
default:
switch (opcode | (sub_opcode2 << 6)) {
case 0b111101 | (0b01001 << 6): inst->id = V850_LDDW; break;
case 0b111100 | (0b00111 << 6): inst->id = V850_LDH; break;
case 0b111101 | (0b00111 << 6): inst->id = V850_LDHU; break;
case 0b111100 | (0b01001 << 6): inst->id = V850_LDW; break;
case 0b111101 | (0b01111 << 6): inst->id = V850_STDW; break;
case 0b111101 | (0b01101 << 6): inst->id = V850_STH; break;
case 0b111100 | (0b01111 << 6): inst->id = V850_STW; break;
default: return false;
}
}
inst->disp = ((V850_word(inst, 2) >> 4) & 0x7f) | (V850_word(inst, 3) << 7);
inst->disp = sext32(inst->disp, 23);
PRINT_INSTR;
switch (inst->id) {
case V850_LDB:
case V850_LDBU:
case V850_LDH:
case V850_LDHU:
case V850_LDW:
case V850_LDDW:
OPERANDS("%d[%s], %s", (st32)inst->disp, R1, R3);
break;
case V850_STB:
case V850_STH:
case V850_STW:
case V850_STDW:
OPERANDS("%s, %d[%s]", R3, (st32)inst->disp, R1);
default: break;
}
inst->format = XIV_load_store48;
return true;
}
#define slice(x, l, r) extract(x, l, r - l + 1)
#define OP(l, r) slice(inst->d, l, r)
static ut8 get_reg4(V850_Inst *i) {
return slice(i->d, 17, 20);
}
#define R4 GR_get(get_reg4(inst))
static bool v850_decode_formatUnk_float(V850_Inst *inst) {
// absf.d
if ((OP(05, 10) == 0x3f && OP(00, 04) == 0x0) && (OP(21, 26) == 0x22 && OP(16, 20) == 0x18)) {
inst->id = V850_ABSF_D;
INSTR("absf.d");
OPERANDS("%s, %s", R2, R3);
return true;
}
// absf.s
if ((get_reg2(inst) && OP(05, 10) == 0x3f && OP(00, 04) == 0x0) && (get_reg3(inst) && OP(21, 26) == 0x22 && OP(16, 20) == 0x8)) {
inst->id = V850_ABSF_S;
INSTR("absf.s");
OPERANDS("%s, %s", R2, R3);
return true;
}
// addf.d
if ((OP(05, 10) == 0x3f) && (OP(21, 26) == 0x23 && OP(16, 20) == 0x10)) {
inst->id = V850_ADDF_D;
INSTR("addf.d");
OPERANDS("%s, %s, %s", R1, R2, R3);
return true;
}
// addf.s
if ((get_reg2(inst) && OP(05, 10) == 0x3f && get_reg1(inst)) && (get_reg3(inst) && OP(21, 26) == 0x23 && OP(16, 20) == 0x0)) {
inst->id = V850_ADDF_S;
INSTR("addf.s");
OPERANDS("%s, %s, %s", R1, R2, R3);
return true;
}
// ceilf.dl
if ((OP(05, 10) == 0x3f && OP(00, 04) == 0x2) && (OP(21, 26) == 0x22 && OP(16, 20) == 0x14)) {
inst->id = V850_CEILF_DL;
INSTR("ceilf.dl");
OPERANDS("%s, %s", R2, R3);
return true;
}
// ceilf.dul
if ((OP(05, 10) == 0x3f && OP(00, 04) == 0x12) && (OP(21, 26) == 0x22 && OP(16, 20) == 0x14)) {
inst->id = V850_CEILF_DUL;
INSTR("ceilf.dul");
OPERANDS("%s, %s", R2, R3);
return true;
}
// ceilf.duw
if ((OP(05, 10) == 0x3f && OP(00, 04) == 0x12) && (get_reg3(inst) && OP(21, 26) == 0x22 && OP(16, 20) == 0x10)) {
inst->id = V850_CEILF_DUW;
INSTR("ceilf.duw");
OPERANDS("%s, %s", R2, R3);
return true;
}
// ceilf.dw
if ((OP(05, 10) == 0x3f && OP(00, 04) == 0x2) && (get_reg3(inst) && OP(21, 26) == 0x22 && OP(16, 20) == 0x10)) {
inst->id = V850_CEILF_DW;
INSTR("ceilf.dw");
OPERANDS("%s, %s", R2, R3);
return true;
}
// ceilf.sl
if ((get_reg2(inst) && OP(05, 10) == 0x3f && OP(00, 04) == 0x2) && (OP(21, 26) == 0x22 && OP(16, 20) == 0x4)) {
inst->id = V850_CEILF_SL;
INSTR("ceilf.sl");
OPERANDS("%s, %s", R2, R3);
return true;
}
// ceilf.sul
if ((get_reg2(inst) && OP(05, 10) == 0x3f && OP(00, 04) == 0x12) && (OP(21, 26) == 0x22 && OP(16, 20) == 0x4)) {
inst->id = V850_CEILF_SUL;
INSTR("ceilf.sul");
OPERANDS("%s, %s", R2, R3);
return true;
}
// ceilf.suw
if ((get_reg2(inst) && OP(05, 10) == 0x3f && OP(00, 04) == 0x12) && (get_reg3(inst) && OP(21, 26) == 0x22 && OP(16, 20) == 0x0)) {
inst->id = V850_CEILF_SUW;
INSTR("ceilf.suw");
OPERANDS("%s, %s", R2, R3);
return true;
}
// ceilf.sw
if ((get_reg2(inst) && OP(05, 10) == 0x3f && OP(00, 04) == 0x2) && (get_reg3(inst) && OP(21, 26) == 0x22 && OP(16, 20) == 0x0)) {
inst->id = V850_CEILF_SW;
INSTR("ceilf.sw");
OPERANDS("%s, %s", R2, R3);
return true;
}
// cmovf.d
if ((OP(05, 10) == 0x3f) && (OP(21, 26) == 0x20 && OP(20, 20) == 0x1 && OP(16, 16) == 0x0)) {
inst->id = V850_CMOVF_D;
INSTR("cmovf.d");
OPERANDS("%d, %s, %s, %s", slice(inst->d, 17, 19), R2, R1, R3);
return true;
}
// cmovf.s
if ((get_reg2(inst) && OP(05, 10) == 0x3f && get_reg1(inst)) && (get_reg3(inst) && OP(21, 26) == 0x20 && OP(20, 20) == 0x0 && OP(16, 16) == 0x0)) {
inst->id = V850_CMOVF_S;
INSTR("cmovf.s");
OPERANDS("%d, %s, %s, %s", slice(inst->d, 17, 19), R2, R1, R3);
return true;
}
// cmpf.d
if ((OP(05, 10) == 0x3f) && (OP(31, 31) == 0x0 && OP(21, 26) == 0x21 && OP(20, 20) == 0x1 && OP(16, 16) == 0x0)) {
inst->id = V850_CMPF_D;
INSTR("cmpf.d");
OPERANDS("%s, %s, %s, %d", conds[slice(inst->d, 27, 30)], R2, R1, slice(inst->d, 17, 19));
return true;
}
// cmpf.s
if ((get_reg2(inst) && OP(05, 10) == 0x3f && get_reg1(inst)) && (OP(31, 31) == 0x0 && OP(21, 26) == 0x21 && OP(20, 20) == 0x0 && OP(16, 16) == 0x0)) {
inst->id = V850_CMPF_S;
INSTR("cmpf.s");
OPERANDS("%s, %s, %s, %d", conds[slice(inst->d, 27, 30)], R2, R1, slice(inst->d, 17, 19));
return true;
}
// cvtf.dl
if ((OP(05, 10) == 0x3f && OP(00, 04) == 0x4) && (OP(21, 26) == 0x22 && OP(16, 20) == 0x14)) {
inst->id = V850_CVTF_DL;
INSTR("cvtf.dl");
OPERANDS("%s, %s", R2, R3);
return true;
}
// cvtf.ds
if ((OP(05, 10) == 0x3f && OP(00, 04) == 0x3) && (get_reg3(inst) && OP(21, 26) == 0x22 && OP(16, 20) == 0x12)) {
inst->id = V850_CVTF_DS;
INSTR("cvtf.ds");
OPERANDS("%s, %s", R2, R3);
return true;
}
// cvtf.dul
if ((OP(05, 10) == 0x3f && OP(00, 04) == 0x14) && (OP(21, 26) == 0x22 && OP(16, 20) == 0x14)) {
inst->id = V850_CVTF_DUL;
INSTR("cvtf.dul");
OPERANDS("%s, %s", R2, R3);
return true;
}
// cvtf.duw
if ((OP(05, 10) == 0x3f && OP(00, 04) == 0x14) && (get_reg3(inst) && OP(21, 26) == 0x22 && OP(16, 20) == 0x10)) {
inst->id = V850_CVTF_DUW;
INSTR("cvtf.duw");
OPERANDS("%s, %s", R2, R3);
return true;
}
// cvtf.dw
if ((OP(05, 10) == 0x3f && OP(00, 04) == 0x4) && (get_reg3(inst) && OP(21, 26) == 0x22 && OP(16, 20) == 0x10)) {
inst->id = V850_CVTF_DW;
INSTR("cvtf.dw");
OPERANDS("%s, %s", R2, R3);
return true;
}
// cvtf.ld
if ((OP(05, 10) == 0x3f && OP(00, 04) == 0x1) && (OP(21, 26) == 0x22 && OP(16, 20) == 0x12)) {
inst->id = V850_CVTF_LD;
INSTR("cvtf.ld");
OPERANDS("%s, %s", R2, R3);
return true;
}
// cvtf.ls
if ((OP(05, 10) == 0x3f && OP(00, 04) == 0x1) && (get_reg3(inst) && OP(21, 26) == 0x22 && OP(16, 20) == 0x2)) {
inst->id = V850_CVTF_LS;
INSTR("cvtf.ls");
OPERANDS("%s, %s", R2, R3);
return true;
}
// cvtf.sd
if ((get_reg2(inst) && OP(05, 10) == 0x3f && OP(00, 04) == 0x2) && (OP(21, 26) == 0x22 && OP(16, 20) == 0x12)) {
inst->id = V850_CVTF_SD;
INSTR("cvtf.sd");
OPERANDS("%s, %s", R2, R3);
return true;
}
// cvtf.sl
if ((get_reg2(inst) && OP(05, 10) == 0x3f && OP(00, 04) == 0x4) && (OP(21, 26) == 0x22 && OP(16, 20) == 0x4)) {
inst->id = V850_CVTF_SL;
INSTR("cvtf.sl");
OPERANDS("%s, %s", R2, R3);
return true;
}
// cvtf.sul
if ((get_reg2(inst) && OP(05, 10) == 0x3f && OP(00, 04) == 0x14) && (OP(21, 26) == 0x22 && OP(16, 20) == 0x4)) {
inst->id = V850_CVTF_SUL;
INSTR("cvtf.sul");
OPERANDS("%s, %s", R2, R3);
return true;
}
// cvtf.suw
if ((get_reg2(inst) && OP(05, 10) == 0x3f && OP(00, 04) == 0x14) && (get_reg3(inst) && OP(21, 26) == 0x22 && OP(16, 20) == 0x0)) {
inst->id = V850_CVTF_SUW;
INSTR("cvtf.suw");
OPERANDS("%s, %s", R2, R3);
return true;
}
// cvtf.sw
if ((get_reg2(inst) && OP(05, 10) == 0x3f && OP(00, 04) == 0x4) && (get_reg3(inst) && OP(21, 26) == 0x22 && OP(16, 20) == 0x0)) {
inst->id = V850_CVTF_SW;
INSTR("cvtf.sw");
OPERANDS("%s, %s", R2, R3);
return true;
}
// cvtf.uld
if ((OP(05, 10) == 0x3f && OP(00, 04) == 0x11) && (OP(21, 26) == 0x22 && OP(16, 20) == 0x12)) {
inst->id = V850_CVTF_ULD;
INSTR("cvtf.uld");
OPERANDS("%s, %s", R2, R3);
return true;
}
// cvtf.uls
if ((OP(05, 10) == 0x3f && OP(00, 04) == 0x11) && (get_reg3(inst) && OP(21, 26) == 0x22 && OP(16, 20) == 0x2)) {
inst->id = V850_CVTF_ULS;
INSTR("cvtf.uls");
OPERANDS("%s, %s", R2, R3);
return true;
}
// cvtf.uwd
if ((get_reg2(inst) && OP(05, 10) == 0x3f && OP(00, 04) == 0x10) && (OP(21, 26) == 0x22 && OP(16, 20) == 0x12)) {
inst->id = V850_CVTF_UWD;
INSTR("cvtf.uwd");
OPERANDS("%s, %s", R2, R3);
return true;
}
// cvtf.uws
if ((get_reg2(inst) && OP(05, 10) == 0x3f && OP(00, 04) == 0x10) && (get_reg3(inst) && OP(21, 26) == 0x22 && OP(16, 20) == 0x2)) {
inst->id = V850_CVTF_UWS;
INSTR("cvtf.uws");
OPERANDS("%s, %s", R2, R3);
return true;
}
// cvtf.wd
if ((get_reg2(inst) && OP(05, 10) == 0x3f && OP(00, 04) == 0x0) && (OP(21, 26) == 0x22 && OP(16, 20) == 0x12)) {
inst->id = V850_CVTF_WD;
INSTR("cvtf.wd");
OPERANDS("%s, %s", R2, R3);
return true;
}
// cvtf.ws
if ((get_reg2(inst) && OP(05, 10) == 0x3f && OP(00, 04) == 0x0) && (get_reg3(inst) && OP(21, 26) == 0x22 && OP(16, 20) == 0x2)) {
inst->id = V850_CVTF_WS;
INSTR("cvtf.ws");
OPERANDS("%s, %s", R2, R3);
return true;
}
// divf.d
if ((OP(05, 10) == 0x3f) && (OP(21, 26) == 0x23 && OP(16, 20) == 0x1e)) {
inst->id = V850_DIVF_D;
INSTR("divf.d");
OPERANDS("%s, %s, %s", R1, R2, R3);
return true;
}
// divf.s
if ((get_reg1(inst) && OP(05, 10) == 0x3f && get_reg2(inst)) && (get_reg3(inst) && OP(21, 26) == 0x23 && OP(16, 20) == 0xe)) {
inst->id = V850_DIVF_S;
INSTR("divf.s");
OPERANDS("%s, %s, %s", R1, R2, R3);
return true;
}
// floorf.dl
if ((OP(05, 10) == 0x3f && OP(00, 04) == 0x3) && (OP(21, 26) == 0x22 && OP(16, 20) == 0x14)) {
inst->id = V850_FLOORF_DL;
INSTR("floorf.dl");
OPERANDS("%s, %s", R2, R3);
return true;
}
// floorf.dul
if ((OP(05, 10) == 0x3f && OP(00, 04) == 0x13) && (OP(21, 26) == 0x22 && OP(16, 20) == 0x14)) {
inst->id = V850_FLOORF_DUL;
INSTR("floorf.dul");
OPERANDS("%s, %s", R2, R3);
return true;
}
// floorf.duw
if ((OP(05, 10) == 0x3f && OP(00, 04) == 0x13) && (get_reg3(inst) && OP(21, 26) == 0x22 && OP(16, 20) == 0x10)) {
inst->id = V850_FLOORF_DUW;
INSTR("floorf.duw");
OPERANDS("%s, %s", R2, R3);
return true;
}
// floorf.dw
if ((OP(05, 10) == 0x3f && OP(00, 04) == 0x3) && (get_reg3(inst) && OP(21, 26) == 0x22 && OP(16, 20) == 0x10)) {
inst->id = V850_FLOORF_DW;
INSTR("floorf.dw");
OPERANDS("%s, %s", R2, R3);
return true;
}
// floorf.sl
if ((get_reg2(inst) && OP(05, 10) == 0x3f && OP(00, 04) == 0x3) && (OP(21, 26) == 0x22 && OP(16, 20) == 0x4)) {
inst->id = V850_FLOORF_SL;
INSTR("floorf.sl");
OPERANDS("%s, %s", R2, R3);
return true;
}
// floorf.sul
if ((get_reg2(inst) && OP(05, 10) == 0x3f && OP(00, 04) == 0x13) && (OP(21, 26) == 0x22 && OP(16, 20) == 0x4)) {
inst->id = V850_FLOORF_SUL;
INSTR("floorf.sul");
OPERANDS("%s, %s", R2, R3);
return true;
}
// floorf.suw
if ((get_reg2(inst) && OP(05, 10) == 0x3f && OP(00, 04) == 0x13) && (get_reg3(inst) && OP(21, 26) == 0x22 && OP(16, 20) == 0x0)) {
inst->id = V850_FLOORF_SUW;
INSTR("floorf.suw");
OPERANDS("%s, %s", R2, R3);
return true;
}
// floorf.sw
if ((get_reg2(inst) && OP(05, 10) == 0x3f && OP(00, 04) == 0x3) && (get_reg3(inst) && OP(21, 26) == 0x22 && OP(16, 20) == 0x0)) {
inst->id = V850_FLOORF_SW;
INSTR("floorf.sw");
OPERANDS("%s, %s", R2, R3);
return true;
}
// maddf.s
if ((get_reg1(inst) && OP(05, 10) == 0x3f && get_reg2(inst)) && (get_reg3(inst) && OP(24, 26) == 0x5 && OP(21, 22) == 0x0 && OP(16, 16) == 0x0 && get_reg4(inst))) {
inst->id = V850_MADDF_S;
INSTR("maddf.s");
OPERANDS("%s, %s, %s, %s", R1, R2, R3, R4);
return true;
}
// maxf.d
if ((OP(05, 10) == 0x3f) && (OP(21, 26) == 0x23 && OP(16, 20) == 0x18)) {
inst->id = V850_MAXF_D;
INSTR("maxf.d");
OPERANDS("%s, %s, %s", R1, R2, R3);
return true;
}
// maxf.s
if ((get_reg1(inst) && OP(05, 10) == 0x3f && get_reg2(inst)) && (get_reg3(inst) && OP(21, 26) == 0x23 && OP(16, 20) == 0x8)) {
inst->id = V850_MAXF_S;
INSTR("maxf.s");
OPERANDS("%s, %s, %s", R1, R2, R3);
return true;
}
// minf.d
if ((OP(05, 10) == 0x3f) && (OP(21, 26) == 0x23 && OP(16, 20) == 0x1a)) {
inst->id = V850_MINF_D;
INSTR("minf.d");
OPERANDS("%s, %s, %s", R1, R2, R3);
return true;
}
// minf.s
if ((get_reg1(inst) && OP(05, 10) == 0x3f && get_reg2(inst)) && (get_reg3(inst) && OP(21, 26) == 0x23 && OP(16, 20) == 0xa)) {
inst->id = V850_MINF_S;
INSTR("minf.s");
OPERANDS("%s, %s, %s", R1, R2, R3);
return true;
}
// msubf.s
if ((get_reg1(inst) && OP(05, 10) == 0x3f && get_reg2(inst)) && (get_reg3(inst) && OP(24, 26) == 0x5 && OP(21, 22) == 0x1 && OP(16, 16) == 0x0 && get_reg4(inst))) {
inst->id = V850_MSUBF_S;
INSTR("msubf.s");
OPERANDS("%s, %s, %s, %s", R1, R2, R3, R4);
return true;
}
// mulf.d
if ((OP(05, 10) == 0x3f) && (OP(21, 26) == 0x23 && OP(16, 20) == 0x14)) {
inst->id = V850_MULF_D;
INSTR("mulf.d");
OPERANDS("%s, %s, %s", R1, R2, R3);
return true;
}
// mulf.s
if ((get_reg1(inst) && OP(05, 10) == 0x3f && get_reg2(inst)) && (get_reg3(inst) && OP(21, 26) == 0x23 && OP(16, 20) == 0x4)) {
inst->id = V850_MULF_S;
INSTR("mulf.s");
OPERANDS("%s, %s, %s", R1, R2, R3);
return true;
}
// negf.d
if ((OP(05, 10) == 0x3f && OP(00, 04) == 0x1) && (OP(21, 26) == 0x22 && OP(16, 20) == 0x18)) {
inst->id = V850_NEGF_D;
INSTR("negf.d");
OPERANDS("%s, %s", R2, R3);
return true;
}
// negf.s
if ((get_reg2(inst) && OP(05, 10) == 0x3f && OP(00, 04) == 0x1) && (get_reg3(inst) && OP(21, 26) == 0x22 && OP(16, 20) == 0x8)) {
inst->id = V850_NEGF_S;
INSTR("negf.s");
OPERANDS("%s, %s", R2, R3);
return true;
}
// nmaddf.s
if ((get_reg1(inst) && OP(05, 10) == 0x3f && get_reg2(inst)) && (get_reg3(inst) && OP(24, 26) == 0x5 && OP(21, 22) == 0x2 && OP(16, 16) == 0x0 && get_reg4(inst))) {
inst->id = V850_NMADDF_S;
INSTR("nmaddf.s");
OPERANDS("%s, %s, %s, %s", R1, R2, R3, R4);
return true;
}
// nmsubf.s
if ((get_reg1(inst) && OP(05, 10) == 0x3f && get_reg2(inst)) && (get_reg3(inst) && OP(24, 26) == 0x5 && OP(21, 22) == 0x3 && OP(16, 16) == 0x0 && get_reg4(inst))) {
inst->id = V850_NMSUBF_S;
INSTR("nmsubf.s");
OPERANDS("%s, %s, %s, %s", R1, R2, R3, R4);
return true;
}
// recipf.d
if ((OP(05, 10) == 0x3f && OP(00, 04) == 0x1) && (OP(21, 26) == 0x22 && OP(16, 20) == 0x1e)) {
inst->id = V850_RECIPF_D;
INSTR("recipf.d");
OPERANDS("%s, %s", R2, R3);
return true;
}
// recipf.s
if ((get_reg2(inst) && OP(05, 10) == 0x3f && OP(00, 04) == 0x1) && (get_reg3(inst) && OP(21, 26) == 0x22 && OP(16, 20) == 0xe)) {
inst->id = V850_RECIPF_S;
INSTR("recipf.s");
OPERANDS("%s, %s", R2, R3);
return true;
}
// rsqrtf.d
if ((OP(05, 10) == 0x3f && OP(00, 04) == 0x2) && (OP(21, 26) == 0x22 && OP(16, 20) == 0x1e)) {
inst->id = V850_RSQRTF_D;
INSTR("rsqrtf.d");
OPERANDS("%s, %s", R2, R3);
return true;
}
// rsqrtf.s
if ((get_reg2(inst) && OP(05, 10) == 0x3f && OP(00, 04) == 0x2) && (get_reg3(inst) && OP(21, 26) == 0x22 && OP(16, 20) == 0xe)) {
inst->id = V850_RSQRTF_S;
INSTR("rsqrtf.s");
OPERANDS("%s, %s", R2, R3);
return true;
}
// sqrtf.d
if ((OP(05, 10) == 0x3f && OP(00, 04) == 0x0) && (OP(21, 26) == 0x22 && OP(16, 20) == 0x1e)) {
inst->id = V850_SQRTF_D;
INSTR("sqrtf.d");
OPERANDS("%s, %s", R2, R3);
return true;
}
// sqrtf.s
if ((get_reg2(inst) && OP(05, 10) == 0x3f && OP(00, 04) == 0x0) && (get_reg3(inst) && OP(21, 26) == 0x22 && OP(16, 20) == 0xe)) {
inst->id = V850_SQRTF_S;
INSTR("sqrtf.s");
OPERANDS("%s, %s", R2, R3);
return true;
}
// subf.d
if ((OP(05, 10) == 0x3f) && (OP(21, 26) == 0x23 && OP(16, 20) == 0x12)) {
inst->id = V850_SUBF_D;
INSTR("subf.d");
OPERANDS("%s, %s, %s", R1, R2, R3);
return true;
}
// subf.s
if ((get_reg1(inst) && OP(05, 10) == 0x3f && get_reg2(inst)) && (get_reg3(inst) && OP(21, 26) == 0x23 && OP(16, 20) == 0x2)) {
inst->id = V850_SUBF_S;
INSTR("subf.s");
OPERANDS("%s, %s, %s", R1, R2, R3);
return true;
}
// trfsr
if ((OP(11, 15) == 0x0 && OP(05, 10) == 0x3f && OP(00, 04) == 0x0) && (OP(27, 31) == 0x0 && OP(21, 26) == 0x20 && OP(20, 20) == 0x0 && OP(16, 16) == 0x0)) {
inst->id = V850_TRFSR;
INSTR("trfsr");
OPERANDS("%d", slice(inst->d, 17, 19));
return true;
}
// trncf.dl
if ((OP(05, 10) == 0x3f && OP(00, 04) == 0x1) && (OP(21, 26) == 0x22 && OP(16, 20) == 0x14)) {
inst->id = V850_TRNCF_DL;
INSTR("trncf.dl");
OPERANDS("%s, %s", R2, R3);
return true;
}
// trncf.dul
if ((OP(05, 10) == 0x3f && OP(00, 04) == 0x11) && (OP(21, 26) == 0x22 && OP(16, 20) == 0x14)) {
inst->id = V850_TRNCF_DUL;
INSTR("trncf.dul");
OPERANDS("%s, %s", R2, R3);
return true;
}
// trncf.duw
if ((OP(05, 10) == 0x3f && OP(00, 04) == 0x11) && (get_reg3(inst) && OP(21, 26) == 0x22 && OP(16, 20) == 0x10)) {
inst->id = V850_TRNCF_DUW;
INSTR("trncf.duw");
OPERANDS("%s, %s", R2, R3);
return true;
}
// trncf.dw
if ((OP(05, 10) == 0x3f && OP(00, 04) == 0x1) && (get_reg3(inst) && OP(21, 26) == 0x22 && OP(16, 20) == 0x10)) {
inst->id = V850_TRNCF_DW;
INSTR("trncf.dw");
OPERANDS("%s, %s", R2, R3);
return true;
}
// trncf.sl
if ((get_reg2(inst) && OP(05, 10) == 0x3f && OP(00, 04) == 0x1) && (OP(21, 26) == 0x22 && OP(16, 20) == 0x4)) {
inst->id = V850_TRNCF_SL;
INSTR("trncf.sl");
OPERANDS("%s, %s", R2, R3);
return true;
}
// trncf.sul
if ((get_reg2(inst) && OP(05, 10) == 0x3f && OP(00, 04) == 0x11) && (OP(21, 26) == 0x22 && OP(16, 20) == 0x4)) {
inst->id = V850_TRNCF_SUL;
INSTR("trncf.sul");
OPERANDS("%s, %s", R2, R3);
return true;
}
// trncf.suw
if ((get_reg2(inst) && OP(05, 10) == 0x3f && OP(00, 04) == 0x11) && (get_reg3(inst) && OP(21, 26) == 0x22 && OP(16, 20) == 0x0)) {
inst->id = V850_TRNCF_SUW;
INSTR("trncf.suw");
OPERANDS("%s, %s", R2, R3);
return true;
}
// trncf.sw
if ((get_reg2(inst) && OP(05, 10) == 0x3f && OP(00, 04) == 0x1) && (get_reg3(inst) && OP(21, 26) == 0x22 && OP(16, 20) == 0x0)) {
inst->id = V850_TRNCF_SW;
INSTR("trncf.sw");
OPERANDS("%s, %s", R2, R3);
return true;
}
return false;
}
int v850_decode_command(const ut8 *bytes, int len, V850_Inst *inst) {
if (len < 2) {
return -1;
}
RzBuffer *b = rz_buf_new_with_pointers(bytes, len, false);
if (!b) {
return -1;
}
for (int i = 0; i < RZ_MIN(8, len) / 2; ++i) {
ut16 tmp;
if (!rz_buf_read_le16(b, &tmp)) {
goto err;
}
inst->d |= (ut64)(tmp) << (i * 16);
}
inst->byte_size = 2;
if (decode_formatI(inst) ||
decode_formatII(inst) ||
decode_formatIII(inst) ||
decode_formatIV_1(inst) ||
decode_formatIV_2(inst)) {
goto ok;
}
inst->byte_size = 4;
if (decode_formatV(inst) ||
decode_formatVI(inst, b) ||
decode_formatVII(inst) ||
decode_formatVIII(inst) ||
decode_formatIX(inst) ||
decode_formatX(inst) ||
decode_formatXI(inst) ||
decode_formatXII(inst) ||
decode_formatXIII(inst, b) ||
v850_decode_formatUnk_float(inst)) {
goto ok;
}
inst->byte_size = 6;
if (decode_formatXIV(inst)) {
goto ok;
}
goto err;
ok:
rz_buf_free(b);
return inst->byte_size;
err:
inst->byte_size = -1;
rz_buf_free(b);
return -1;
}