diff --git a/librz/asm/arch/v850/v850_disas.c b/librz/asm/arch/v850/v850_disas.c index 725cfe19930..0b5624b7db8 100644 --- a/librz/asm/arch/v850/v850_disas.c +++ b/librz/asm/arch/v850/v850_disas.c @@ -753,7 +753,64 @@ static bool decode_formatXII(V850_Inst *inst) { return true; } -static bool decode_formatXIII(V850_Inst *inst) { +static const ut8 list12_map[] = { + /*[0] = */ 30, + /*[21] = */ 31, + /*[22] = */ 29, + /*[23] = */ 28, + /*[24] = */ 23, + /*[25] = */ 22, + /*[26] = */ 21, + /*[27] = */ 20, + /*[28] = */ 27, + /*[29] = */ 26, + /*[30] = */ 25, + /*[31] = */ 24, +}; + +static int ut8_cmp(const void *a, const void *b) { + return ((ut8 *)a)[0] - ((ut8 *)b)[0]; +} + +static char *fmt_list(ut32 lst) { + ut8 set[12] = { 0 }; + for (ut32 i = 0; i < 12; i++) { + set[i] = (lst & (1 << i)) ? list12_map[i] : UT8_MAX; + } + qsort(set, 12, sizeof(ut8), ut8_cmp); + RzStrBuf sb = { 0 }; + rz_strbuf_initf(&sb, "{"); + ut8 begin = set[0]; + ut8 end = set[0]; + bool sep = false; + for (ut32 i = 1; i < 12; i++) { + ut8 x = set[i]; + if (x == UT8_MAX) { + break; + } + if (x - end == 1) { + end = x; + continue; + } + if (sep) { + rz_strbuf_append(&sb, ", "); + } + if (begin != end) { + rz_strbuf_appendf(&sb, "%s - %s", GR_get(begin), GR_get(end)); + } else { + rz_strbuf_appendf(&sb, "%s", GR_get(begin)); + } + sep = true; + + rz_strbuf_appendf(&sb, ", %s", GR_get(x)); + sep = true; + begin = end = x; + } + rz_strbuf_append(&sb, "}"); + return rz_strbuf_drain_nofree(&sb); +} + +static bool decode_formatXIII(V850_Inst *inst, RzBuffer *b) { inst->opcode = get_opcode(inst, 6, 10); inst->sub_opcode = get_reg2(inst); inst->imm = inst->w1 & 0x3f >> 1; @@ -764,27 +821,68 @@ static bool decode_formatXIII(V850_Inst *inst) { return false; } + char *list_str = NULL; switch (inst->opcode) { - case 0b11001: + case 0b11001: { inst->id = V850_DISPOSE; - // if (inst->reg2 == 0) { - // - // } else { - // } + ut8 RRRRR = inst->w2 & 0x1f; + PRINT_INSTR; + list_str = fmt_list(inst->list); + if (RRRRR > 0) { + OPERANDS("%d, %s, %s", inst->imm, list_str, GR_get(RRRRR)); + } else { + OPERANDS("%d, %s", inst->imm, list_str); + } break; + } + case 0b11110: - if (inst->reg2 == 1 || (inst->reg2 & 0x7) == 0x3) { + if (inst->reg2 == 1) { + inst->id = V850_PREPARE; + list_str = fmt_list(inst->list); + OPERANDS("%s, %x", list_str, inst->imm); + } else if ((inst->reg2 & 0x7) == 0x3) { inst->id = V850_PREPARE; + ut8 ff = inst->reg2 >> 3; + switch (ff) { + case 0b00: OPERANDS("%s, %x, sp", list_str, inst->imm); break; + case 0b01: { + ut16 imm = 0; + if (!rz_buf_read_le16(b, &imm)) { + return false; + } + OPERANDS("%s, %x, %d", list_str, inst->imm, sext32(imm, 16)); + break; + } + case 0b10: { + ut16 imm = 0; + if (!rz_buf_read_le16(b, &imm)) { + return false; + } + OPERANDS("%s, %x, %d", list_str, inst->imm, (ut32)(imm) << 16); + break; + } + case 0b11: { + ut32 imm = 0; + if (!rz_buf_read_le32(b, &imm)) { + return false; + } + OPERANDS("%s, %x, %d", list_str, inst->imm, imm); + break; + } + default: break; + } + } else { return false; } + PRINT_INSTR; break; default: return false; } - PRINT_INSTR; - OPERANDS("[%d], %08x", inst->imm, inst->list); + free(list_str); return true; } @@ -851,7 +949,7 @@ int v850_decode_command(const ut8 *bytes, int len, V850_Inst *inst) { decode_formatX(inst) || decode_formatXI(inst) || decode_formatXII(inst) || - decode_formatXIII(inst)) { + decode_formatXIII(inst, b)) { goto ok; } diff --git a/librz/asm/arch/v850/v850_disas.h b/librz/asm/arch/v850/v850_disas.h index 8c93baf97d4..338c06f7b39 100644 --- a/librz/asm/arch/v850/v850_disas.h +++ b/librz/asm/arch/v850/v850_disas.h @@ -338,7 +338,7 @@ static inline ut16 get_disp22(const V850_Inst *i) { } static inline ut16 get_list(const V850_Inst *i) { - return ((i->w2 & ~0x1f) >> 5) | ((i->w1 & 1) << 11); + return ((i->w2 >> 5) << 1) | (i->w1 & 1); } static inline int32_t sext32(uint32_t X, unsigned B) {