Disassembler arch for RX microcontroller (MCU) family (#4198)

* Basic framework of rx implemented
* Add match and parse flow
* Add part of description for RxV1 instruction set
* Add datasheet for rxv1
* Implement stringify op for rx
* Add missing TST instruction in datasheet
* Test to div instruction and fix bugs
* Test known rxv1 instruction set
* Fix bugs in rx disasm plugin and add SPDX
* Add rz_analysis for renesas rx
* Fix rz_analysis bug for renesas rx
* Add rz_asm test and fix bug in datasheet
* Add analysis test and fix bugs for renesas rx
This commit is contained in:
Heersin 2024-02-17 22:29:16 +08:00 committed by GitHub
parent f98ab29273
commit 5c79c42a56
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 2533 additions and 1 deletions

View file

@ -0,0 +1,9 @@
default.cc=rx
rx=cc
cc.rx.arg0=r1
cc.rx.arg1=r2
cc.rx.arg2=r3
cc.rx.arg3=r4
cc.rx.argn=stack_rev
cc.rx.ret=r1

View file

@ -30,6 +30,7 @@ analysis_plugins_list = [
'propeller',
'pyc',
'rl78',
'rx',
'rsp',
'snes',
'sparc_cs',
@ -142,6 +143,7 @@ rz_analysis_sources = [
'p/analysis_pyc.c',
'p/analysis_rl78.c',
'p/analysis_rsp.c',
'p/analysis_rx.c',
'p/analysis_snes.c',
'p/analysis_sparc_cs.c',
'p/analysis_spc700.c',

View file

@ -0,0 +1,256 @@
// SPDX-FileCopyrightText: 2024 heersin <teablearcher@gmail.com>
// SPDX-License-Identifier: LGPL-3.0-only
#include <asm/arch/rx/rx.h>
#include <rz_types.h>
#include <rz_util.h>
#include <rz_lib.h>
#include <rz_asm.h>
#include <rz_analysis.h>
static void calculate_jmp_addr(RxInst *inst, RzAnalysisOp *op) {
if (inst->v0.kind == RX_OPERAND_COND) {
ut8 pcdsp_l = inst->v0.v.cond.pc_dsp_len;
ut32 pcdsp_val = inst->v0.v.cond.pc_dsp_val;
ut64 addr_inc = pcdsp_val;
if (pcdsp_l >= 8) {
// as SIMM, use signed extend
ut8 shift = pcdsp_l - 1;
if ((1 << shift) & pcdsp_val) {
// as negative
ut32 mask = 0xffffffff << shift;
addr_inc = abs((st32)(pcdsp_val | mask));
op->jump = op->addr - addr_inc;
return;
}
}
op->jump = op->addr + addr_inc;
}
op->fail = op->addr + op->size;
}
static int analysis_rx_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr,
const ut8 *buf, int len, RzAnalysisOpMask mask) {
op->addr = addr;
op->type = RZ_ANALYSIS_OP_TYPE_ILL;
RxInst inst = { 0 };
st32 bytes_read = 0;
if (!rx_dis(&inst, &bytes_read, buf, len)) {
return bytes_read;
} else {
op->type = RZ_ANALYSIS_OP_TYPE_UNK;
}
op->size = bytes_read;
switch (inst.op) {
// jump related instructions
case RX_OP_RTS:
op->type = RZ_ANALYSIS_OP_TYPE_RET;
break;
case RX_OP_BSR_A:
case RX_OP_BSR_L:
case RX_OP_BSR_W:
case RX_OP_JSR:
op->type = RZ_ANALYSIS_OP_TYPE_CALL;
calculate_jmp_addr(&inst, op);
break;
case RX_OP_BCND_W:
case RX_OP_BCND_B:
case RX_OP_BCND_S:
op->type = RZ_ANALYSIS_OP_TYPE_CJMP;
calculate_jmp_addr(&inst, op);
break;
case RX_OP_BRA_L:
case RX_OP_BRA_A:
case RX_OP_BRA_B:
case RX_OP_BRA_S:
case RX_OP_BRA_W:
op->type = RZ_ANALYSIS_OP_TYPE_JMP;
calculate_jmp_addr(&inst, op);
break;
case RX_OP_JMP:
// use register
op->type = RZ_ANALYSIS_OP_TYPE_JMP;
break;
// normal instruction
case RX_OP_ADD:
case RX_OP_ADD_UB:
case RX_OP_ADC:
op->type = RZ_ANALYSIS_OP_TYPE_ADD;
break;
case RX_OP_SUB:
case RX_OP_SUB_UB:
op->type = RZ_ANALYSIS_OP_TYPE_SUB;
break;
case RX_OP_DIV:
case RX_OP_DIV_UB:
case RX_OP_DIVU:
case RX_OP_DIVU_UB:
op->type = RZ_ANALYSIS_OP_TYPE_DIV;
break;
case RX_OP_MUL:
case RX_OP_MULLO:
case RX_OP_EMUL:
case RX_OP_EMULU:
case RX_OP_EMULU_UB:
case RX_OP_EMUL_UB:
case RX_OP_MUL_UB:
case RX_OP_MULHI:
case RX_OP_MACHI:
case RX_OP_MACLO:
op->type = RZ_ANALYSIS_OP_TYPE_MUL;
break;
case RX_OP_AND:
case RX_OP_AND_UB:
op->type = RZ_ANALYSIS_OP_TYPE_AND;
break;
case RX_OP_OR:
case RX_OP_OR_UB:
op->type = RZ_ANALYSIS_OP_TYPE_OR;
break;
case RX_OP_NOT:
op->type = RZ_ANALYSIS_OP_TYPE_NOT;
break;
case RX_OP_NOP:
op->type = RZ_ANALYSIS_OP_TYPE_NOP;
break;
case RX_OP_CMP:
case RX_OP_CMP_UB:
op->type = RZ_ANALYSIS_OP_TYPE_CMP;
break;
case RX_OP_PUSH:
case RX_OP_PUSHM:
case RX_OP_PUSHC:
op->type = RZ_ANALYSIS_OP_TYPE_PUSH;
break;
case RX_OP_POP:
case RX_OP_POPM:
case RX_OP_POPC:
op->type = RZ_ANALYSIS_OP_TYPE_POP;
break;
case RX_OP_ROTL:
case RX_OP_ROLC:
op->type = RZ_ANALYSIS_OP_TYPE_ROL;
break;
case RX_OP_ROTR:
case RX_OP_RORC:
op->type = RZ_ANALYSIS_OP_TYPE_ROR;
break;
case RX_OP_SHAR:
op->type = RZ_ANALYSIS_OP_TYPE_SAR;
break;
case RX_OP_SHLR:
op->type = RZ_ANALYSIS_OP_TYPE_SHR;
break;
case RX_OP_SHLL:
op->type = RZ_ANALYSIS_OP_TYPE_SHL;
break;
case RX_OP_XCHG_UB:
case RX_OP_XCHG:
op->type = RZ_ANALYSIS_OP_TYPE_XCHG;
break;
case RX_OP_XOR:
case RX_OP_XOR_UB:
op->type = RZ_ANALYSIS_OP_TYPE_XOR;
break;
case RX_OP_ITOF:
case RX_OP_FTOI:
case RX_OP_ITOF_UB:
op->type = RZ_ANALYSIS_OP_TYPE_CAST;
break;
case RX_OP_INT:
op->type = RZ_ANALYSIS_OP_TYPE_SWI;
break;
case RX_OP_MOV:
case RX_OP_MOVU:
case RX_OP_MVTIPL:
case RX_OP_MVTC:
case RX_OP_MVTACLO:
case RX_OP_MVTACHI:
case RX_OP_MVFACMI:
case RX_OP_MVFACHI:
case RX_OP_MVFC:
op->type = RZ_ANALYSIS_OP_TYPE_MOV;
break;
default:
break;
}
return op->size;
}
static char *analysis_rx_reg_profile(RzAnalysis *analysis) {
// check librz/reg/profile for register profile description
const char *p =
"=PC pc\n"
"=SP r0\n"
"=ZF zf\n"
"=CF cf\n"
"=SF sf\n"
"=OF of\n"
// ABI: https://www.renesas.com/us/en/document/mat/cc-rx-compiler-users-manual
"=R0 r1\n"
"=A0 r1\n"
"=A1 r2\n"
"=A2 r3\n"
"=A3 r4\n"
// general
"gpr r0 .32 0 0\n"
"gpr r1 .32 4 0\n"
"gpr r2 .32 8 0\n"
"gpr r3 .32 12 0\n"
"gpr r4 .32 16 0\n"
"gpr r5 .32 20 0\n"
"gpr r6 .32 24 0\n"
"gpr r7 .32 28 0\n"
"gpr r8 .32 32 0\n"
"gpr r9 .32 36 0\n"
"gpr r10 .32 40 0\n"
"gpr r11 .32 44 0\n"
"gpr r12 .32 48 0\n"
"gpr r13 .32 52 0\n"
"gpr r14 .32 56 0\n"
"gpr r15 .32 60 0\n"
// control register
"gpr isp .32 64 0\n"
"gpr usp .32 68 0\n"
"gpr intb .32 72 0\n"
"gpr pc .32 76 0\n"
// psw
"gpr psw .32 80 0\n"
"flg ipl .4 .644 0\n"
"flg pm .1 .651 0\n"
"flg u .1 .654 0\n"
"flg i .1 .655 0\n"
"flg of .1 .668 0\n"
"flg sf .1 .669 0\n"
"flg zf .1 .670 0\n"
"flg cf .1 .671 0\n"
"gpr bpc .32 84 0\n"
"gpr bpsw .32 88 0\n"
"gpr fintv .32 92 0\n"
// fpsw, contains multiple flags but ignore now
"gpr fpsw .32 96 0\n"
"flg fsf .1 .768 0\n"
"flg fxf .1 .769 0\n"
"flg fuf .1 .770 0\n"
"flg fzf .1 .771 0\n"
"flg fof .1 .772 0\n"
"flg fvf .1 .773 0\n"
"flg rmode .2 .798 0\n";
return strdup(p);
}
RzAnalysisPlugin rz_analysis_plugin_rx = {
.name = "rx",
.arch = "rx",
.desc = "Renesas RX Family analysis",
.license = "LGPL3",
.bits = 32,
.op = &analysis_rx_op,
.get_reg_profile = &analysis_rx_reg_profile,
};

166
librz/asm/arch/rx/rx.c Normal file
View file

@ -0,0 +1,166 @@
// SPDX-FileCopyrightText: 2024 heersin <teablearcher@gmail.com>
// SPDX-License-Identifier: LGPL-3.0-only
#include "rx.h"
#include "rx_str.inc"
static ut64 prefetch_bytes(const ut8 *buf, size_t buf_len) {
ut64 result = 0;
size_t i;
size_t end = buf_len < 8 ? buf_len : 8; // Determine end based on buf_len
for (i = 0; i < end; i++) {
result |= ((ut64)buf[i]) << ((7 - i) * 8); // Shift and combine
}
return result;
}
bool rx_operand_stringify(RxInst *inst, RxOperand *opr, RZ_OUT RzStrBuf *buf) {
// construct string output to RzStrBuf
if (opr->kind == RX_OPERAND_NULL) {
// ignore
return false;
}
if (opr->kind == RX_OPERAND_COND) {
if (opr->v.cond.pc_dsp_len) {
rz_strbuf_appendf(buf, " #0x%" PFMT32x, opr->v.cond.pc_dsp_val);
}
return true;
}
if (opr->kind == RX_OPERAND_FLAG) {
rz_strf(buf->buf, "%s", RxNameFlag(opr->v.flag));
return true;
}
if (opr->kind == RX_OPERAND_IMM) {
rz_strf(buf->buf, "#0x%" PFMT32x,
opr->v.imm.imm);
return true;
}
if (opr->kind == RX_OPERAND_REG) {
if (opr->v.reg.dsp_width) {
// dsp value
rz_strbuf_appendf(buf, "0x%" PFMT32x,
opr->v.reg.dsp_val);
}
if (opr->v.reg.as_indirect) {
rz_strbuf_append(buf, "[");
}
if (opr->v.reg.fix_mode == RX_FIXOP_PRE_DEC) {
rz_strbuf_append(buf, "-");
}
if (opr->v.reg.as_base) {
rz_strbuf_appendf(buf, "%s,%s",
RxNameReg(opr->v.reg.ri),
RxNameReg(opr->v.reg.reg));
} else {
rz_strbuf_appendf(buf, "%s", RxNameReg(opr->v.reg.reg));
}
if (opr->v.reg.fix_mode == RX_FIXOP_POST_INC) {
rz_strbuf_append(buf, "+");
}
if (opr->v.reg.as_indirect) {
rz_strbuf_append(buf, "]");
}
if (opr->v.reg.memex != RX_EXT_NON) {
rz_strbuf_appendf(buf, ".%s", RxNameExt(opr->v.reg.memex));
}
}
return true;
}
bool rx_inst_stringify(RxInst *inst, RzStrBuf *buf) {
// construct string output to RzStrBuf
if (inst->op == RX_OP_INVALID) {
return false;
}
RzStrBuf opr0_buf, opr1_buf, opr2_buf;
rz_strbuf_init(&opr0_buf);
rz_strbuf_init(&opr1_buf);
rz_strbuf_init(&opr2_buf);
bool has_opr0 = inst->v0.kind != RX_OPERAND_NULL &&
rx_operand_stringify(inst, &inst->v0, &opr0_buf);
bool has_opr1 = inst->v1.kind != RX_OPERAND_NULL &&
rx_operand_stringify(inst, &inst->v1, &opr1_buf);
bool has_opr2 = inst->v2.kind != RX_OPERAND_NULL &&
rx_operand_stringify(inst, &inst->v2, &opr2_buf);
if (inst->op == RX_OP_BCND_W || inst->op == RX_OP_BCND_B || inst->op == RX_OP_BCND_S ||
inst->op == RX_OP_BMCND || inst->op == RX_OP_SCCOND) {
if (has_opr0 && inst->v0.kind == RX_OPERAND_COND) {
// build b[cnd]
RzStrBuf cond_buf;
rz_strbuf_init(&cond_buf);
rz_strf(cond_buf.buf, "%s", RxNameCond(inst->v0.v.cond.cond));
rz_strbuf_appendf(buf, RxNameOp(inst->op), cond_buf.buf);
if (!inst->v0.v.cond.pc_dsp_len) {
has_opr0 = false;
}
} else {
rz_strbuf_appendf(buf, "%s[invalid]",
RxNameOp(inst->op));
}
} else {
rz_strbuf_appendf(buf, "%s", RxNameOp(inst->op));
}
if (inst->sz_mark != RX_EXT_NON) {
rz_strbuf_appendf(buf, ".%s ", RxNameExt(inst->sz_mark));
} else {
rz_strbuf_append(buf, " ");
}
if (has_opr0) {
rz_strbuf_appendf(buf, "%s, ", opr0_buf.buf);
}
if (has_opr1) {
rz_strbuf_appendf(buf, "%s, ", opr1_buf.buf);
}
if (has_opr2) {
rz_strbuf_appendf(buf, "%s", opr2_buf.buf);
}
return true;
}
/**
* \brief Parse binary data to RxInst according to RxDesc
* \details RX instruction can be 1-8 Bytes, consisted by 2 main parts: [(code) (code data)],
* in rizin rx plugin, we defined an `RX instruction description` as an array of tokens, with RxEnd as the end mark.
* The parser will fetch 8Bytes, and try to match a predefined instruction description to get a valid interpretation.
* \param inst RxInst to be filled
* \param bytes_read count bytes read from buf
* \param buf rz raw binary data, provided by rizin
* \param buf_len length of buf, provided by rizin
* \return true if parse success, false otherwise
*/
RZ_API bool rx_dis(RZ_NONNULL RxInst RZ_OUT *inst, RZ_NONNULL st32 RZ_OUT *bytes_read, RZ_NONNULL const ut8 *buf, size_t buf_len) {
rz_return_val_if_fail(inst && bytes_read && buf, false);
// rx instruction length vary from 1 to 8 Bytes
ut64 prefetched_bytes = prefetch_bytes(buf, buf_len);
RxInst current_inst = { 0 };
st32 bytes_read_real = 0;
for (ut32 desc_id = 0; desc_id < RX_DESC_SIZE; ++desc_id) {
memset(&current_inst, 0, sizeof(RxInst));
bool is_valid = rx_try_match_and_parse(&current_inst, &rx_inst_descs[desc_id],
&bytes_read_real, prefetched_bytes);
if (is_valid) {
*inst = current_inst;
*bytes_read = bytes_read_real;
return true;
}
}
// nothing matched known instruction
return false;
}

13
librz/asm/arch/rx/rx.h Normal file
View file

@ -0,0 +1,13 @@
// SPDX-FileCopyrightText: 2024 heersin <teablearcher@gmail.com>
// SPDX-License-Identifier: LGPL-3.0-only
#ifndef RZ_ARCH_RX_H
#define RZ_ARCH_RX_H
#include <rz_util.h>
#include "rx_inst.h"
RZ_API bool rx_dis(RZ_NONNULL RxInst RZ_OUT *inst, RZ_NONNULL st32 RZ_OUT *bytes_read, RZ_NONNULL const ut8 *buf, size_t buf_len);
bool rx_inst_stringify(RxInst *inst, RzStrBuf *buf);
#endif

605
librz/asm/arch/rx/rx_inst.c Normal file
View file

@ -0,0 +1,605 @@
// SPDX-FileCopyrightText: 2024 heersin <teablearcher@gmail.com>
// SPDX-License-Identifier: LGPL-3.0-only
#include "rx_inst.h"
#define AssignOpVar(vid, field, expr) \
{ \
switch (vid) { \
case 0: inst->v0.field = (expr); break; \
case 1: inst->v1.field = (expr); break; \
default: inst->v2.field = (expr); break; \
} \
}
RxOperandFlag rx_cb_map[16] = {
RX_FLAG_C,
RX_FLAG_Z,
RX_FLAG_S,
RX_FLAG_O,
RX_FLAG_RESERVED,
RX_FLAG_RESERVED,
RX_FLAG_RESERVED,
RX_FLAG_RESERVED,
RX_FLAG_I,
RX_FLAG_U,
RX_FLAG_RESERVED,
RX_FLAG_RESERVED,
RX_FLAG_RESERVED,
RX_FLAG_RESERVED,
RX_FLAG_RESERVED,
RX_FLAG_RESERVED,
};
RxReg rx_cr_map[32] = {
RX_REG_PSW,
RX_REG_PC,
RX_REG_USP,
RX_REG_FPSW,
RX_REG_RESERVED,
RX_REG_RESERVED,
RX_REG_RESERVED,
RX_REG_RESERVED,
RX_REG_BPSW,
RX_REG_BPC,
RX_REG_ISP,
RX_REG_FINTV,
RX_REG_INTB,
RX_REG_RESERVED,
RX_REG_RESERVED,
RX_REG_RESERVED,
RX_REG_RESERVED,
RX_REG_RESERVED,
RX_REG_RESERVED,
RX_REG_RESERVED,
RX_REG_RESERVED,
RX_REG_RESERVED,
RX_REG_RESERVED,
RX_REG_RESERVED,
RX_REG_RESERVED,
RX_REG_RESERVED,
RX_REG_RESERVED,
RX_REG_RESERVED,
RX_REG_RESERVED,
RX_REG_RESERVED,
RX_REG_RESERVED,
RX_REG_RESERVED,
};
static inline ut64 getbits(ut64 bytes, ut8 s, ut8 l) {
return (bytes >> (64 - s - l)) & ((1ULL << l) - 1);
}
bool match_code(RZ_OUT RxInst *inst, RxToken *token, RZ_OUT ut8 *bits_read, ut64 bytes) {
ut8 s = *bits_read;
ut8 l = token->tk.inst.tk_len;
ut64 bits = getbits(bytes, s, l);
if (bits == token->tk.inst.detail) {
*bits_read += l;
return true;
}
return false;
}
RxOpExtMark bits2mark(ut64 bits) {
// 00 - B, 01 - W, 10 - L, 11 - UW
return RX_EXT_B + bits;
}
bool match_mi(RZ_OUT RxInst *inst, RxToken *token, RZ_OUT ut8 *bits_read, ut64 bytes) {
ut8 s = *bits_read;
ut8 l = token->tk.mi.tk_len;
RxOpCode op = inst->op;
ut64 bits = getbits(bytes, s, l);
if (op == RX_OP_ADC) {
if (bits != 2) {
// only 10 - L allowed
return false;
}
}
inst->v0.v.reg.memex = bits2mark(bits);
*bits_read += l;
return true;
}
bool match_ld(RZ_OUT RxInst *inst, RxToken *token, RZ_OUT ut8 *bits_read, ut64 bytes) {
ut8 s = *bits_read;
ut8 l = token->tk.ld.tk_len;
ut64 ld_bits = getbits(bytes, s, l);
ut8 dsp_len;
// 11 - Rs
switch (ld_bits) {
case 3:
*bits_read += l;
return true;
case 0:
dsp_len = 0;
break;
case 1:
dsp_len = 8;
break;
case 2:
dsp_len = 16;
break;
default:
rz_warn_if_reached();
return 0;
}
AssignOpVar(token->tk.ld.vid, v.reg.as_indirect, true);
AssignOpVar(token->tk.ld.vid, v.reg.dsp_width, dsp_len);
*bits_read += l;
return true;
}
bool match_ld_part(RZ_OUT RxInst *inst, RxToken *token, RZ_OUT ut8 *bits_read, ut64 bytes) {
ut8 s = *bits_read;
ut8 l = token->tk.ld_part.tk_len;
ut8 ldr = getbits(bytes, s, l);
ut8 dsp_width;
// 00 - None, 01 - dsp:8, 10 - dsp:16, 11 - invalid
switch (ldr) {
case 3:
// invalid 11
return false;
case 0:
dsp_width = 0;
break;
case 1:
dsp_width = 8;
break;
case 2:
dsp_width = 16;
break;
default:
rz_warn_if_reached();
return false;
}
AssignOpVar(token->tk.ld_part.vid, v.reg.dsp_width, dsp_width);
AssignOpVar(token->tk.ld_part.vid, v.reg.as_indirect, true);
*bits_read += l;
return true;
}
ut8 bits2immlen(ut64 bits) {
// 01 - SIMM: 8, 10 - SIMM: 16
// 11 - SIMM: 24, 00 - IMM: 32
switch (bits) {
case 0:
return 32;
case 1:
return 8;
case 2:
return 16;
case 3:
return 24;
default:
rz_warn_if_reached();
return 0;
}
}
bool match_li(RZ_OUT RxInst *inst, RxToken *token, RZ_OUT ut8 *bits_read, ut64 bytes) {
ut8 s = *bits_read;
ut8 l = token->tk.li.tk_len;
AssignOpVar(token->tk.li.vid, v.imm.imm_width, bits2immlen(getbits(bytes, s, l)));
*bits_read += l;
return true;
}
bool match_reg(RZ_OUT RxInst *inst, RxToken *token, RZ_OUT ut8 *bits_read, ut64 bytes) {
ut8 s = *bits_read;
ut8 l = token->tk.reg.tk_len;
ut8 operand_id = token->tk.reg.vid;
AssignOpVar(operand_id, v.reg.reg, RX_REG_R0 + getbits(bytes, s, l));
AssignOpVar(operand_id, kind, RX_OPERAND_REG);
*bits_read += l;
return true;
}
bool match_reg_patched(RZ_OUT RxInst *inst, RxToken *token, RZ_OUT ut8 *bits_read, ut64 bytes) {
ut8 s = *bits_read;
ut8 l = token->tk.reg.tk_len;
ut8 operand_id = token->tk.reg.vid;
ut64 reg_bits = getbits(bytes, s, l);
RxOpCode op = inst->op;
RxReg reg = RX_REG_R0 + reg_bits;
if (op == RX_OP_PUSHM || op == RX_OP_POPM) {
if (operand_id == 0) {
// for opr0, R1 -> R14
if (reg < RX_REG_R1 || reg > RX_REG_R14) {
return false;
}
}
if (operand_id == 1) {
// for opr1
if (reg < RX_REG_R2 || reg > RX_REG_R15) {
return false;
}
}
}
if (op == RX_OP_EMUL || op == RX_OP_EMULU) {
if (operand_id == 1) {
// dest reg limit: R0 -> R14
if (reg > RX_REG_R14) {
return false;
}
}
}
if (op == RX_OP_RTSD) {
if (reg < RX_REG_R1 || reg > RX_REG_R15) {
return false;
}
}
AssignOpVar(operand_id, v.reg.reg, RX_REG_R0 + reg_bits);
AssignOpVar(operand_id, kind, RX_OPERAND_REG);
*bits_read += l;
return true;
}
bool match_ri(RZ_OUT RxInst *inst, RxToken *token, RZ_OUT ut8 *bits_read, ut64 bytes) {
ut8 s = *bits_read;
ut8 l = token->tk.reg.tk_len;
ut8 operand_id = token->tk.reg.vid;
ut64 reg_bits = getbits(bytes, s, l);
AssignOpVar(operand_id, v.reg.as_indirect, true);
AssignOpVar(operand_id, v.reg.as_base, true);
AssignOpVar(operand_id, v.reg.ri, RX_REG_R0 + reg_bits);
*bits_read += l;
return true;
}
bool match_cr(RZ_OUT RxInst *inst, RxToken *token, RZ_OUT ut8 *bits_read, ut64 bytes) {
ut8 s = *bits_read;
ut8 l = token->tk.cr.tk_len;
ut8 operand_id = token->tk.cr.vid;
AssignOpVar(operand_id, v.reg.reg, rx_cr_map[(getbits(bytes, s, l))]);
AssignOpVar(operand_id, kind, RX_OPERAND_REG);
*bits_read += l;
return true;
}
bool match_imm(RZ_OUT RxInst *inst, RxToken *token, RZ_OUT ut8 *bits_read, ut64 bytes) {
ut8 s = *bits_read;
ut8 l = token->tk.imm.tk_len;
ut8 operand_id = token->tk.imm.vid;
AssignOpVar(operand_id, v.imm.imm, getbits(bytes, s, l));
AssignOpVar(operand_id, v.imm.imm_width, l);
AssignOpVar(operand_id, kind, RX_OPERAND_IMM);
*bits_read += l;
return true;
}
bool match_cond(RZ_OUT RxInst *inst, RxToken *token, RZ_OUT ut8 *bits_read, ut64 bytes) {
ut8 s = *bits_read;
ut8 l = token->tk.cond.tk_len;
ut8 operand_id = token->tk.cond.vid;
ut64 cond_bits = getbits(bytes, s, l);
RxOpCondMark cond_mark;
if (inst->op == RX_OP_BMCND) {
if (cond_bits >= 0xe) {
// reserved val for cond
return false;
}
cond_mark = RX_COND_EQ + cond_bits;
} else {
cond_mark = RX_COND_EQ + cond_bits;
}
AssignOpVar(operand_id, v.cond.cond, cond_mark);
AssignOpVar(operand_id, kind, RX_OPERAND_COND);
*bits_read += l;
return true;
}
bool match_jump(RZ_OUT RxInst *inst, RxToken *token) {
// judge as a unconditional jump
inst->v0.kind = RX_OPERAND_COND;
inst->v0.v.cond.cond = RX_COND_JUMP;
return true;
}
bool match_cb(RZ_OUT RxInst *inst, RxToken *token, RZ_OUT ut8 *bits_read, ut64 bytes) {
ut8 s = *bits_read;
ut8 l = token->tk.cb.tk_len;
ut8 control_bits = getbits(bytes, s, l);
inst->v0.v.flag = rx_cb_map[control_bits];
inst->v0.kind = RX_OPERAND_FLAG;
if (inst->v0.v.flag == RX_FLAG_RESERVED) {
// TODO: should we use strict policy ?
return false;
}
*bits_read += l;
return true;
}
bool match_dsp(RZ_OUT RxInst *inst, RxToken *token, RZ_OUT ut8 *bits_read, ut64 bytes) {
// DSP mark should follow a jump
ut8 s = *bits_read;
ut8 l = token->tk.dsp.tk_len;
ut8 dsp_bits = getbits(bytes, s, l);
// for condition dsp
if (dsp_bits > 10 || dsp_bits < 3) {
return false;
}
inst->v0.v.cond.pc_dsp_len = 3;
inst->v0.v.cond.pc_dsp_val = dsp_bits;
*bits_read += l;
return true;
}
bool match_dsp_split(RZ_OUT RxInst *inst, RxToken *token, RZ_OUT ut8 *bits_read, ut64 bytes) {
ut8 s = *bits_read;
ut8 l = token->tk.dsp_sp.tk_len;
ut8 interval = token->tk.dsp_sp.interval;
ut8 ll = token->tk.dsp_sp.tk_len_more;
// | dsp_A | interval_bits | dsp_B |
// dsp_bits = concat(dsp_A, dsp_B)
ut8 dsp_bits = (getbits(bytes, s, l) << ll) | getbits(bytes, s + l + interval, ll);
ut8 operand_id = token->tk.dsp_sp.vid;
AssignOpVar(operand_id, v.reg.dsp_val, dsp_bits);
AssignOpVar(operand_id, v.reg.dsp_width, l + ll);
AssignOpVar(operand_id, v.reg.as_indirect, true);
*bits_read += l;
return true;
}
bool match_ignore(RxToken *token, RZ_OUT ut8 *bits_read) {
ut8 l = token->tk.reserved.tk_len;
*bits_read += l;
return true;
}
bool match_sz(RZ_OUT RxInst *inst, RxToken *token, RZ_OUT ut8 *bits_read, ut64 bytes) {
ut8 s = *bits_read;
ut8 l = token->tk.sz.tk_len;
ut8 sz = getbits(bytes, s, l);
if (sz == 3) {
// invalid 11
return false;
}
inst->sz_mark = RX_EXT_B + sz;
*bits_read += l;
return true;
}
bool match_ad(RZ_OUT RxInst *inst, RxToken *token, RZ_OUT ut8 *bits_read, ut64 bytes) {
ut8 s = *bits_read;
ut8 l = token->tk.ad.tk_len;
ut8 addr_bits = getbits(bytes, s, l);
if (inst->op == RX_OP_MOVU) {
// 10 [Rs+] and 11 [-Rs] is allowed
if (addr_bits < 2) {
return false;
}
}
// 00 Rs, [Rd+], 01: Rs, [-Rd], inc/dec on Rd
// 10 [Rs+], Rd, 11: [-Rs], Rd, inc/dec on Rs
switch (addr_bits) {
case 0:
inst->v1.v.reg.as_indirect = true;
inst->v1.v.reg.fix_mode = RX_FIXOP_POST_INC;
break;
case 1:
inst->v1.v.reg.as_indirect = true;
inst->v1.v.reg.fix_mode = RX_FIXOP_PRE_DEC;
break;
case 2:
inst->v0.v.reg.as_indirect = true;
inst->v0.v.reg.fix_mode = RX_FIXOP_POST_INC;
break;
case 3:
inst->v0.v.reg.as_indirect = true;
inst->v0.v.reg.fix_mode = RX_FIXOP_PRE_DEC;
break;
default:
rz_warn_if_reached();
return false;
}
*bits_read += l;
return true;
}
static ut32 pack_big(ut32 raw_data, ut8 len_in_bytes) {
ut32 result = 0;
for (int i = 0; i < len_in_bytes; i++) {
ut32 byte = (raw_data >> (8 * i)) & 0xFF;
result = (result << 8) | byte;
}
return result;
}
bool pack_data(RZ_OUT RxInst *inst, RxToken *token, RZ_OUT ut8 *bits_read, ut64 bytes) {
ut8 s = *bits_read;
ut8 vid = token->tk.data.vid;
ut8 l;
ut32 follow_data;
RxOperand *opr = vid == 0 ? &(inst->v0) : vid == 1 ? &(inst->v1)
: &(inst->v2);
ut8 data_type = token->tk.data.data_type;
if (data_type == 2) {
// pack dsp
l = opr->v.reg.dsp_width;
follow_data = getbits(bytes, s, l);
opr->v.reg.dsp_val = pack_big(follow_data, l / 8);
*bits_read += l;
return true;
}
if (data_type == 1) {
// pack imm
if (token->tk.data.fixed_len) {
l = token->tk.data.fixed_len;
opr->v.imm.imm_width = l;
} else {
l = opr->v.imm.imm_width;
}
opr->kind = RX_OPERAND_IMM;
follow_data = getbits(bytes, s, l);
opr->v.imm.imm = pack_big(follow_data, l / 8);
*bits_read += l;
return true;
}
if (data_type == 3) {
// pack pcdsp
if (token->tk.data.fixed_len) {
l = token->tk.data.fixed_len;
opr->v.cond.pc_dsp_len = l;
} else {
l = opr->v.cond.pc_dsp_len;
}
follow_data = getbits(bytes, s, l);
opr->v.cond.pc_dsp_val = pack_big(follow_data, l / 8);
*bits_read += l;
return true;
}
rz_warn_if_reached();
return false;
}
bool check_some(RZ_OUT RxInst *inst, RxToken *token, RZ_OUT ut8 *bits_read, ut64 bytes) {
// a token hook for parser loop
if (inst->op == RX_OP_MOV) {
// check order of src and dest
// for ad[1:0], if 00 or 01, mov dst, src
// for ad[0:1], if 10 or 11, mov src, dst
if (inst->v1.kind == RX_OPERAND_REG) {
// parse RegBist[3:0] as dest(V1)
if (inst->v0.v.reg.fix_mode != RX_FIXOP_NON) {
// but set src fixed, parse failed
return false;
}
}
if (inst->v0.kind == RX_OPERAND_REG) {
if (inst->v1.v.reg.fix_mode != RX_FIXOP_NON) {
return false;
}
}
}
return true;
}
/**
* \brief Parse bytes according to the given RX instruction description to see if it matches
* \param inst an empty RxInst to be filled
* \param desc an RxDesc to be matched
* \param bytes_read bytes read
* \param bytes prefetched bytes
* \return true if parse success, false otherwise
*/
bool rx_try_match_and_parse(RZ_OUT RxInst *inst, RxDesc *desc, st32 RZ_OUT *bytes_read, ut64 bytes) {
ut8 read_bits = 0;
bool is_valid = true;
inst->op = desc->op;
for (int tki = 0; tki < MAX_TOKEN; ++tki) {
if (!is_valid) {
return false;
}
RxTokenType tk_type = desc->tks[tki].type;
RxToken *token = &(desc->tks[tki]);
if (tk_type == RX_TOKEN_NON) {
// break the loop
break;
}
switch (tk_type) {
case RX_TOKEN_INST:
is_valid = match_code(inst, token, &read_bits, bytes);
break;
case RX_TOKEN_LD:
is_valid = match_ld(inst, token, &read_bits, bytes);
break;
case RX_TOKEN_LD_PART:
is_valid = match_ld_part(inst, token, &read_bits, bytes);
break;
case RX_TOKEN_LI:
is_valid = match_li(inst, token, &read_bits, bytes);
break;
case RX_TOKEN_MI:
is_valid = match_mi(inst, token, &read_bits, bytes);
break;
case RX_TOKEN_DSP:
is_valid = match_dsp(inst, token, &read_bits, bytes);
break;
case RX_TOKEN_DSP_SPLIT:
is_valid = match_dsp_split(inst, token, &read_bits, bytes);
break;
case RX_TOKEN_SZ:
is_valid = match_sz(inst, token, &read_bits, bytes);
break;
case RX_TOKEN_AD:
is_valid = match_ad(inst, token, &read_bits, bytes);
break;
case RX_TOKEN_REG:
is_valid = match_reg(inst, token, &read_bits, bytes);
break;
case RX_TOKEN_CR:
is_valid = match_cr(inst, token, &read_bits, bytes);
break;
case RX_TOKEN_CB:
is_valid = match_cb(inst, token, &read_bits, bytes);
break;
case RX_TOKEN_IMM:
is_valid = match_imm(inst, token, &read_bits, bytes);
break;
case RX_TOKEN_COND:
is_valid = match_cond(inst, token, &read_bits, bytes);
break;
case RX_TOKEN_IGNORE:
match_ignore(token, &read_bits);
break;
case RX_TOKEN_JMP:
is_valid = match_jump(inst, token);
break;
case RX_TOKEN_REG_LIMIT:
is_valid = match_reg_patched(inst, token, &read_bits, bytes);
break;
case RX_TOKEN_HOOK:
is_valid = check_some(inst, token, &read_bits, bytes);
break;
case RX_TOKEN_RI:
is_valid = match_ri(inst, token, &read_bits, bytes);
break;
case RX_TOKEN_DATA:
pack_data(inst, token, &read_bits, bytes);
break;
default:
rz_warn_if_reached();
return false;
}
}
// assume bits / 8 = bytes should be integer
if ((read_bits & 7)) {
// instruction are defined as bytes
rz_warn_if_reached();
return false;
}
*bytes_read = (st32)read_bits / 8;
return true;
}

100
librz/asm/arch/rx/rx_inst.h Normal file
View file

@ -0,0 +1,100 @@
// SPDX-FileCopyrightText: 2024 heersin <teablearcher@gmail.com>
// SPDX-License-Identifier: LGPL-3.0-only
#ifndef RX_ARCH_INST_H
#define RX_ARCH_INST_H
#include "rx_opcode_detail.h"
typedef enum rx_operand_kind_enum {
RX_OPERAND_NULL,
RX_OPERAND_IMM,
RX_OPERAND_REG,
RX_OPERAND_FLAG,
RX_OPERAND_COND,
} RxOperandKind;
typedef enum {
RX_FIXOP_NON,
RX_FIXOP_POST_INC,
RX_FIXOP_PRE_DEC
} RxOpFixMark;
typedef enum {
RX_FLAG_C,
RX_FLAG_Z,
RX_FLAG_S,
RX_FLAG_O,
RX_FLAG_I,
RX_FLAG_U,
RX_FLAG_RESERVED
} RxOperandFlag;
typedef enum {
RX_COND_EQ, // BZ
RX_COND_NE, // BNZ
RX_COND_GEU, // BC
RX_COND_LTU, // BNC
RX_COND_GTU,
RX_COND_LEU,
RX_COND_PZ,
RX_COND_N,
RX_COND_GE,
RX_COND_LT,
RX_COND_GT,
RX_COND_LE,
RX_COND_O,
RX_COND_NO,
RX_COND_RA,
RX_COND_JUMP,
RX_COND_RESERVED,
} RxOpCondMark;
typedef struct {
RxOpCondMark cond;
ut8 pc_dsp_len;
ut32 pc_dsp_val;
} RxOperandCond;
typedef struct {
bool as_indirect;
bool as_base;
ut8 dsp_width;
RxOpExtMark memex;
RxReg ri;
RxReg reg;
RxOpFixMark fix_mode;
ut32 dsp_val;
} RxOperandReg;
typedef struct {
ut8 imm_width;
ut32 imm;
} RxOperandImm;
typedef struct rx_operand_t {
RxOperandKind kind;
union {
RxOperandReg reg;
RxOperandImm imm;
RxOperandFlag flag;
RxOperandCond cond;
} v;
} RxOperand;
typedef struct rx_inst_t {
RxOpCode op;
RxOperand v0;
RxOperand v1;
RxOperand v2;
RxOpExtMark sz_mark;
} RxInst;
// TODO make them into function, not static defined here
// TODO: call in init
extern RxOperandFlag rx_cb_map[16];
extern RxReg rx_cr_map[32];
bool rx_try_match_and_parse(RZ_OUT RxInst *inst, RxDesc *desc, st32 RZ_OUT *bytes_read, ut64 bytes);
#endif

View file

@ -0,0 +1,307 @@
// SPDX-FileCopyrightText: 2024 heersin <teablearcher@gmail.com>
// SPDX-License-Identifier: LGPL-3.0-only
#include "rx_opcode_detail.h"
#define RxCode(x, y) \
{ \
.type = RX_TOKEN_INST, .tk.inst = {.tk_len = (x), \
.detail = (y) } \
}
#define RxReg(x, v) \
{ .type = RX_TOKEN_REG, .tk.reg.tk_len = (x), .tk.reg.vid = (v) }
#define RxLi(x, v) \
{ .type = RX_TOKEN_LI, .tk.li.tk_len = (x), .tk.li.vid = (v) }
#define RxImm(x, v) \
{ .type = RX_TOKEN_IMM, .tk.imm.tk_len = (x), .tk.imm.vid = (v) }
#define RxMi(x) \
{ .type = RX_TOKEN_MI, .tk.mi.tk_len = (x) }
#define RxLd(x, v) \
{ .type = RX_TOKEN_LD, .tk.ld.tk_len = (x), .tk.ld.vid = (v) }
#define RxLdPart(x, v) \
{ .type = RX_TOKEN_LD_PART, .tk.ld_part.tk_len = (x), .tk.ld_part.vid = (v) }
#define RxCond(x, v) \
{ .type = RX_TOKEN_COND, .tk.cond.tk_len = (x), .tk.cond.vid = (v) }
#define RxDsp(x) \
{ .type = RX_TOKEN_DSP, .tk.dsp.tk_len = (x) }
#define RxSz(x) \
{ .type = RX_TOKEN_SZ, .tk.sz.tk_len = (x) }
#define RxAd(x) \
{ .type = RX_TOKEN_AD, .tk.ad.tk_len = (x) }
#define RxCr(x, v) \
{ .type = RX_TOKEN_CR, .tk.cr.tk_len = (x), .tk.cr.vid = (v) }
#define RxCb(x) \
{ .type = RX_TOKEN_CB, .tk.cb.tk_len = (x) }
#define RxDspSplit(x, v, it, xx) \
{ .type = RX_TOKEN_DSP_SPLIT, \
.tk.dsp_sp.tk_len = (x), .tk.dsp_sp.vid = (v), .tk.dsp_sp.tk_len_more = (xx), .tk.dsp_sp.interval = (it) }
#define RxIgnore(x) \
{ .type = RX_TOKEN_IGNORE, .tk.reserved.tk_len = (x) }
#define RxRi(x, bind_v) \
{ .type = RX_TOKEN_RI, .tk.reg.tk_len = (x), .tk.reg.vid = (bind_v) }
// TODO: Jmp maybe removed or an empty mark
#define RxJmp \
{ .type = RX_TOKEN_JMP }
#define RxRegLimit(x, v) \
{ .type = RX_TOKEN_REG_LIMIT, .tk.reg_li.tk_len = (x), .tk.reg_li.vid = (v) }
#define ImmData(v) \
{ .type = RX_TOKEN_DATA, .tk.data.vid = (v), .tk.data.data_type = 1 }
#define DspData(v) \
{ .type = RX_TOKEN_DATA, .tk.data.vid = (v), .tk.data.data_type = 2 }
#define PcDspData(v, l) \
{ .type = RX_TOKEN_DATA, .tk.data.vid = (v), .tk.data.fixed_len = (l), .tk.data.data_type = 3 }
#define ImmFixedData(v, l) \
{ .type = RX_TOKEN_DATA, .tk.data.vid = (v), .tk.data.fixed_len = (l), .tk.data.data_type = 1 }
#define RxHook \
{ .type = RX_TOKEN_HOOK }
#define RxEnd \
{ .type = RX_TOKEN_NON }
#define V0 0
#define V1 1
#define V2 2
RxDesc rx_inst_descs[RX_DESC_SIZE] = {
{ .op = RX_OP_ABS, .tks = { RxCode(12, 0x07e2), RxReg(4, V0), RxEnd } },
{ .op = RX_OP_ABS, .tks = { RxCode(16, 0xfc0f), RxReg(4, V0), RxReg(4, V1), RxEnd } },
{ .op = RX_OP_ADC, .tks = { RxCode(12, 0x0fd7), RxLi(2, V0), RxCode(6, 0x02), RxReg(4, V1), ImmData(V0), RxEnd } },
{ .op = RX_OP_ADC, .tks = { RxCode(16, 0xfc0b), RxReg(4, V0), RxReg(4, V1), RxEnd } },
{ .op = RX_OP_ADC, .tks = { RxCode(8, 0x06), RxMi(2), RxCode(4, 0x08), RxLdPart(2, V0), RxCode(8, 0x02), RxReg(4, V0), RxReg(4, V1), DspData(V0), RxEnd } },
{ .op = RX_OP_ADD, .tks = { RxCode(8, 0x62), RxImm(4, V0), RxReg(4, V1), RxEnd } },
// { .op = RX_OP_ADD, .tks = { RxCode(6, 0x1c), RxLi(2, V0), RxReg(4, V1), RxReg(4, V1), ImmData(V0), RxEnd } },
{ .op = RX_OP_ADD_UB, .tks = { RxCode(6, 0x12), RxLd(2, V0), RxReg(4, V0), RxReg(4, V1), DspData(V0), RxEnd } },
{ .op = RX_OP_ADD, .tks = { RxCode(8, 0x06), RxMi(2), RxCode(4, 0x02), RxLd(2, V0), RxReg(4, V0), RxReg(4, V1), DspData(V0), RxEnd } },
{ .op = RX_OP_ADD, .tks = { RxCode(6, 0x1c), RxLi(2, V0), RxReg(4, V1), RxReg(4, V2), ImmData(V0), RxEnd } },
{ .op = RX_OP_ADD, .tks = { RxCode(12, 0x0ff2), RxReg(4, V2), RxReg(4, V0), RxReg(4, V1), RxEnd } },
{ .op = RX_OP_AND, .tks = { RxCode(8, 0x64), RxImm(4, V0), RxReg(4, V1), RxEnd } },
{ .op = RX_OP_AND, .tks = { RxCode(6, 0x1d), RxLi(2, V0), RxCode(4, 0x02), RxReg(4, V1), ImmData(V0), RxEnd } },
{ .op = RX_OP_AND_UB, .tks = { RxCode(6, 0x14), RxLd(2, V0), RxReg(4, V0), RxReg(4, V1), DspData(V0), RxEnd } },
{ .op = RX_OP_AND, .tks = { RxCode(8, 0x06), RxMi(2), RxCode(4, 0x04), RxLd(2, V0), RxReg(4, V0), RxReg(4, V1), DspData(V0), RxEnd } },
{ .op = RX_OP_AND, .tks = { RxCode(12, 0xff4), RxReg(4, V2), RxReg(4, V0), RxReg(4, V1), RxEnd } },
{ .op = RX_OP_BCLR, .tks = { RxCode(6, 0x3c), RxLdPart(2, V1), RxReg(4, V1), RxCode(1, 0x1), RxImm(3, V0), DspData(V1), RxEnd } },
{ .op = RX_OP_BCLR, .tks = { RxCode(14, 0x3f19), RxLdPart(2, V1), RxReg(4, V1), RxReg(4, V0), DspData(V1), RxEnd } },
{ .op = RX_OP_BCLR, .tks = { RxCode(7, 0x3d), RxImm(5, V0), RxReg(4, V1), RxEnd } },
{ .op = RX_OP_BCLR, .tks = { RxCode(16, 0xfc67), RxReg(4, V1), RxReg(4, V0), RxEnd } },
{ .op = RX_OP_BCND_S, .tks = { RxCode(4, 0x1), RxCond(1, V0), RxDsp(3), RxEnd } },
{ .op = RX_OP_BCND_B, .tks = { RxCode(4, 0x2), RxCond(4, V0), PcDspData(V0, 8), RxEnd } },
{ .op = RX_OP_BCND_W, .tks = { RxCode(7, 0x1d), RxCond(1, V0), PcDspData(V0, 16), RxEnd } },
{ .op = RX_OP_BMCND, .tks = { RxCode(11, 0x7e7), RxImm(3, V1), RxLdPart(2, V2), RxReg(4, V2), RxCond(4, V0), DspData(V2), RxEnd } },
{ .op = RX_OP_BMCND, .tks = { RxCode(11, 0x7ef), RxImm(5, V1), RxCond(4, V0), RxReg(4, V2), RxEnd } },
{ .op = RX_OP_BNOT, .tks = { RxCode(11, 0x7e7), RxImm(3, V0), RxLdPart(2, V1), RxReg(4, V1), RxCode(4, 0xf), DspData(V1), RxEnd } },
{ .op = RX_OP_BNOT, .tks = { RxCode(14, 0x3f1b), RxLdPart(2, V1), RxReg(4, V1), RxReg(4, V0), DspData(V1), RxEnd } },
{ .op = RX_OP_BNOT, .tks = { RxCode(11, 0x7ef), RxImm(5, V0), RxCode(4, 0xf), RxReg(4, V1), RxEnd } },
{ .op = RX_OP_BNOT, .tks = { RxCode(16, 0xfc6f), RxReg(4, V1), RxReg(4, V0), RxEnd } },
{ .op = RX_OP_BRA_S, .tks = { RxCode(5, 0x1), RxJmp, RxDsp(3), RxEnd } },
{ .op = RX_OP_BRA_B, .tks = { RxCode(8, 0x2e), RxJmp, PcDspData(V0, 8), RxEnd } },
{ .op = RX_OP_BRA_W, .tks = { RxCode(8, 0x38), RxJmp, PcDspData(V0, 16), RxEnd } },
{ .op = RX_OP_BRA_A, .tks = { RxCode(8, 0x04), RxJmp, PcDspData(V0, 24), RxEnd } },
{ .op = RX_OP_BRA_L, .tks = { RxCode(12, 0x7f4), RxReg(4, V0), RxEnd } },
{ .op = RX_OP_BRK, .tks = { RxCode(8, 0x0), RxEnd } },
{ .op = RX_OP_BSET, .tks = { RxCode(6, 0x3c), RxLdPart(2, V1), RxReg(4, V1), RxCode(1, 0x0), RxImm(3, V0), DspData(V1), RxEnd } },
{ .op = RX_OP_BSET, .tks = { RxCode(14, 0x3f18), RxLdPart(2, V1), RxReg(4, V1), RxReg(4, V0), DspData(V1), RxEnd } },
{ .op = RX_OP_BSET, .tks = { RxCode(7, 0x3c), RxImm(5, V0), RxReg(4, V1), RxEnd } },
{ .op = RX_OP_BSET, .tks = { RxCode(16, 0xfc63), RxReg(4, V1), RxReg(4, V0), RxEnd } },
{ .op = RX_OP_BSR_W, .tks = { RxCode(8, 0x39), RxJmp, PcDspData(V0, 16), RxEnd } },
{ .op = RX_OP_BSR_A, .tks = { RxCode(8, 0x05), RxJmp, PcDspData(V0, 24), RxEnd } },
{ .op = RX_OP_BSR_L, .tks = { RxCode(12, 0x07f5), RxReg(4, V0), RxEnd } },
{ .op = RX_OP_BTST, .tks = { RxCode(6, 0x3d), RxLdPart(2, V1), RxReg(4, V1), RxCode(1, 0x0), RxImm(3, V0), DspData(V1), RxEnd } },
{ .op = RX_OP_BTST, .tks = { RxCode(14, 0x3f1a), RxLdPart(2, V1), RxReg(4, V1), RxReg(4, V0), DspData(V1), RxEnd } },
{ .op = RX_OP_BTST, .tks = { RxCode(7, 0x3e), RxImm(5, V0), RxReg(4, V1), RxEnd } },
{ .op = RX_OP_BTST, .tks = { RxCode(16, 0xfc6b), RxReg(4, V1), RxReg(4, V0), RxEnd } },
{ .op = RX_OP_CLRPSW, .tks = { RxCode(12, 0x07fb), RxCb(4), RxEnd } },
{ .op = RX_OP_CMP, .tks = { RxCode(8, 0x61), RxImm(4, V0), RxReg(4, V1), RxEnd } },
{ .op = RX_OP_CMP, .tks = { RxCode(12, 0x0755), RxReg(4, V1), ImmFixedData(V0, 8), RxEnd } },
{ .op = RX_OP_CMP, .tks = { RxCode(6, 0x1d), RxLi(2, V0), RxCode(4, 0x0), RxReg(4, V1), ImmData(V0), RxEnd } },
{ .op = RX_OP_CMP_UB, .tks = { RxCode(6, 0x11), RxLd(2, V0), RxReg(4, V0), RxReg(4, V1), DspData(V0), RxEnd } },
{ .op = RX_OP_CMP, .tks = { RxCode(8, 0x06), RxMi(2), RxCode(4, 0x1), RxLd(2, V0), RxReg(4, V0), RxReg(4, V1), DspData(V0), RxEnd } },
{ .op = RX_OP_DIV, .tks = { RxCode(12, 0xfd7), RxLi(2, V0), RxCode(6, 0x08), RxReg(4, V1), ImmData(V0), RxEnd } },
{ .op = RX_OP_DIV_UB, .tks = { RxCode(14, 0x3f08), RxLd(2, V0), RxReg(4, V0), RxReg(4, V1), DspData(V0), RxEnd } },
{ .op = RX_OP_DIV, .tks = { RxCode(8, 0x06), RxMi(2), RxCode(4, 0x08), RxLd(2, V0), RxCode(8, 0x08), RxReg(4, V0), RxReg(4, V1), DspData(V0), RxEnd } },
{ .op = RX_OP_DIVU, .tks = { RxCode(12, 0xfd7), RxLi(2, V0), RxCode(6, 0x9), RxReg(4, V1), ImmData(V0), RxEnd } },
{ .op = RX_OP_DIVU_UB, .tks = { RxCode(14, 0x3f09), RxLd(2, V0), RxReg(4, V0), RxReg(4, V1), DspData(V0), RxEnd } },
{ .op = RX_OP_DIVU, .tks = { RxCode(8, 0x06), RxMi(2), RxCode(4, 0x8), RxLd(2, V0), RxCode(8, 0x09), RxReg(4, V0), RxReg(4, V1), DspData(V0), RxEnd } },
// EMUL family special Rd Range
{ .op = RX_OP_EMUL, .tks = { RxCode(12, 0xfd7), RxLi(2, V0), RxCode(6, 0x06), RxRegLimit(4, V1), ImmData(V0), RxEnd } },
{ .op = RX_OP_EMUL_UB, .tks = { RxCode(14, 0x3f06), RxLd(2, V0), RxReg(4, V0), RxRegLimit(4, V1), DspData(V0), RxEnd } },
{ .op = RX_OP_EMUL, .tks = { RxCode(8, 0x06), RxMi(2), RxCode(4, 0x08), RxLd(2, V0), RxCode(8, 0x06), RxReg(4, V0), RxRegLimit(4, V1), DspData(V0), RxEnd } },
{ .op = RX_OP_EMULU, .tks = { RxCode(12, 0xfd7), RxLi(2, V0), RxCode(6, 0x07), RxRegLimit(4, V1), ImmData(V0), RxEnd } },
{ .op = RX_OP_EMULU_UB, .tks = { RxCode(14, 0x3f07), RxLd(2, V0), RxReg(4, V0), RxRegLimit(4, V1), DspData(V0), RxEnd } },
{ .op = RX_OP_EMULU, .tks = { RxCode(8, 0x06), RxMi(2), RxCode(4, 0x8), RxLd(2, V0), RxCode(8, 0x07), RxReg(4, V0), RxRegLimit(4, V1), DspData(V0), RxEnd } },
{ .op = RX_OP_FADD, .tks = { RxCode(20, 0xfd722), RxReg(4, V1), ImmFixedData(V0, 32), RxEnd } },
{ .op = RX_OP_FADD, .tks = { RxCode(14, 0x3f22), RxLd(2, V0), RxReg(4, V0), RxReg(4, V1), DspData(V0), RxEnd } },
{ .op = RX_OP_FCMP, .tks = { RxCode(20, 0xfd721), RxReg(4, V1), ImmFixedData(V0, 32), RxEnd } },
{ .op = RX_OP_FCMP, .tks = { RxCode(14, 0x3f21), RxLd(2, V0), RxReg(4, V0), RxReg(4, V1), DspData(V0), RxEnd } },
{ .op = RX_OP_FDIV, .tks = { RxCode(20, 0xfd724), RxReg(4, V1), ImmFixedData(V0, 32), RxEnd } },
{ .op = RX_OP_FDIV, .tks = { RxCode(14, 0x3f24), RxLd(2, V0), RxReg(4, V0), RxReg(4, V1), DspData(V0), RxEnd } },
{ .op = RX_OP_FMUL, .tks = { RxCode(20, 0xfd723), RxReg(4, V1), ImmFixedData(V0, 32), RxEnd } },
{ .op = RX_OP_FMUL, .tks = { RxCode(14, 0x3f23), RxLd(2, V0), RxReg(4, V0), RxReg(4, V1), DspData(V0), RxEnd } },
{ .op = RX_OP_FSUB, .tks = { RxCode(20, 0xfd720), RxReg(4, V1), ImmFixedData(V0, 32), RxEnd } },
{ .op = RX_OP_FSUB, .tks = { RxCode(14, 0x3f20), RxLd(2, V0), RxReg(4, V0), RxReg(4, V1), DspData(V0), RxEnd } },
{ .op = RX_OP_FTOI, .tks = { RxCode(14, 0x3f25), RxLd(2, V0), RxReg(4, V0), RxReg(4, V1), DspData(V0), RxEnd } },
{ .op = RX_OP_INT, .tks = { RxCode(16, 0x7560), ImmFixedData(V0, 8), RxEnd } },
{ .op = RX_OP_ITOF_UB, .tks = { RxCode(14, 0x3f11), RxLd(2, V0), RxReg(4, V0), RxReg(4, V1), DspData(V0), RxEnd } },
{ .op = RX_OP_ITOF, .tks = { RxCode(8, 0x06), RxMi(2), RxCode(4, 0x8), RxLd(2, V0), RxCode(8, 0x11), RxReg(4, V0), RxReg(4, V1), DspData(V0), RxEnd } },
{ .op = RX_OP_JMP, .tks = { RxCode(12, 0x07f0), RxReg(4, V0), RxEnd } },
{ .op = RX_OP_JSR, .tks = { RxCode(12, 0x07f1), RxReg(4, V0), RxEnd } },
// Mov family
{ .op = RX_OP_MOV, .tks = { RxCode(2, 0x2), RxSz(2), RxCode(1, 0x0), RxDspSplit(4, V1, 3, 1), RxReg(3, V1), RxIgnore(1), RxReg(3, V0), RxEnd } },
{ .op = RX_OP_MOV, .tks = { RxCode(2, 0x2), RxSz(2), RxCode(1, 0x1), RxDspSplit(4, V0, 3, 1), RxReg(3, V0), RxIgnore(1), RxReg(3, V1), RxEnd } },
{ .op = RX_OP_MOV, .tks = { RxCode(8, 0x66), RxImm(4, V0), RxReg(4, V1), RxEnd } },
{ .op = RX_OP_MOV, .tks = { RxCode(6, 0x0f), RxSz(2), RxDspSplit(1, V1, 3, 4), RxReg(3, V1), RxIgnore(4), ImmFixedData(V0, 8), RxEnd } },
{ .op = RX_OP_MOV, .tks = { RxCode(12, 0x0754), RxReg(4, V1), ImmFixedData(V0, 8) } },
{ .op = RX_OP_MOV, .tks = { RxCode(8, 0xfb), RxReg(4, V1), RxLi(2, V0), RxCode(2, 0x02), ImmData(V0), RxEnd } },
{ .op = RX_OP_MOV, .tks = { RxCode(2, 0x3), RxSz(2), RxCode(4, 0xf), RxReg(4, V0), RxReg(4, V1), RxEnd } },
// ld are limited to 0-2
{ .op = RX_OP_MOV, .tks = { RxCode(6, 0x3e), RxLdPart(2, V1), RxReg(4, V1), RxLi(2, V0), RxSz(2), DspData(V1), ImmData(V0), RxEnd } },
{ .op = RX_OP_MOV, .tks = { RxCode(2, 0x3), RxSz(2), RxCode(2, 0x3), RxLdPart(2, V0), RxReg(4, V0), RxReg(4, V1), DspData(V0), RxEnd } },
{ .op = RX_OP_MOV, .tks = { RxCode(10, 0x03f9), RxSz(2), RxRi(4, V0), RxReg(4, V0), RxReg(4, V1), RxEnd } },
{ .op = RX_OP_MOV, .tks = { RxCode(2, 0x3), RxSz(2), RxLdPart(2, V1), RxCode(2, 0x3), RxReg(4, V1), RxReg(4, V0), DspData(V1), RxEnd } },
{ .op = RX_OP_MOV, .tks = { RxCode(10, 0x03f8), RxSz(2), RxRi(4, V1), RxReg(4, V1), RxReg(4, V0), RxEnd } },
{ .op = RX_OP_MOV, .tks = { RxCode(2, 0x3), RxSz(2), RxLdPart(2, V1), RxLdPart(2, V0), RxReg(4, V0), RxReg(4, V1), DspData(V0), DspData(V1), RxEnd } },
{ .op = RX_OP_MOV, .tks = { RxCode(12, 0xfd2), RxAd(2), RxSz(2), RxReg(4, V1), RxHook, RxReg(4, V0), RxEnd } },
{ .op = RX_OP_MOV, .tks = { RxCode(12, 0xfd2), RxAd(2), RxSz(2), RxReg(4, V0), RxHook, RxReg(4, V1), RxEnd } },
{ .op = RX_OP_MOVU, .tks = { RxCode(4, 0xb), RxSz(1), RxDspSplit(4, V0, 3, 1), RxReg(3, V0), RxIgnore(1), RxReg(3, V1), RxEnd } },
{ .op = RX_OP_MOVU, .tks = { RxCode(5, 0x0b), RxSz(1), RxLd(2, V0), RxReg(4, V0), RxReg(4, V1), DspData(V0), RxEnd } },
{ .op = RX_OP_MOVU, .tks = { RxCode(11, 0x07f6), RxSz(1), RxRi(4, V0), RxReg(4, V0), RxReg(4, V1), RxEnd } },
{ .op = RX_OP_MOVU, .tks = { RxCode(12, 0x0fd3), RxAd(2), RxCode(1, 0x0), RxSz(1), RxReg(4, V0), RxReg(4, V1), RxEnd } },
{ .op = RX_OP_MACHI, .tks = { RxCode(16, 0xfd04), RxReg(4, V0), RxReg(4, V1), RxEnd } },
{ .op = RX_OP_MACLO, .tks = { RxCode(16, 0xfd05), RxReg(4, V0), RxReg(4, V1), RxEnd } },
{ .op = RX_OP_MAX, .tks = { RxCode(12, 0xfd7), RxLi(2, V0), RxCode(6, 0x4), RxReg(4, V1), ImmData(V0), RxEnd } },
{ .op = RX_OP_MAX_UB, .tks = { RxCode(14, 0x3f04), RxLd(2, V0), RxReg(4, V0), RxReg(4, V1), DspData(V0), RxEnd } },
{ .op = RX_OP_MAX, .tks = { RxCode(8, 0x06), RxMi(2), RxCode(4, 0x8), RxLd(2, V0), RxCode(8, 0x04), RxReg(4, V0), RxReg(4, V1), DspData(V0), RxEnd } },
{ .op = RX_OP_MIN, .tks = { RxCode(12, 0xfd7), RxLi(2, V0), RxCode(6, 0x5), RxReg(4, V1), ImmData(V0), RxEnd } },
{ .op = RX_OP_MIN_UB, .tks = { RxCode(14, 0x3f05), RxLd(2, V0), RxReg(4, V0), RxReg(4, V1), DspData(V0), RxEnd } },
{ .op = RX_OP_MIN, .tks = { RxCode(8, 0x06), RxMi(2), RxCode(4, 0x8), RxLd(2, V0), RxCode(8, 0x05), RxReg(4, V0), RxReg(4, V1), DspData(V0), RxEnd } },
{ .op = RX_OP_MUL, .tks = { RxCode(8, 0x63), RxImm(4, V0), RxReg(4, V1), RxEnd } },
{ .op = RX_OP_MUL, .tks = { RxCode(6, 0x1d), RxLi(2, V0), RxCode(4, 0x01), RxReg(4, V1), ImmData(V0), RxEnd } },
{ .op = RX_OP_MUL_UB, .tks = { RxCode(6, 0x13), RxLd(2, V0), RxReg(4, V0), RxReg(4, V1), DspData(V0), RxEnd } },
{ .op = RX_OP_MUL, .tks = { RxCode(8, 0x06), RxMi(2), RxCode(4, 0x3), RxLd(2, V0), RxReg(4, V0), RxReg(4, V1), DspData(V0), RxEnd } },
{ .op = RX_OP_MUL, .tks = { RxCode(12, 0xff3), RxReg(4, V2), RxReg(4, V0), RxReg(4, V1), RxEnd } },
{ .op = RX_OP_MULHI, .tks = { RxCode(16, 0xfd00), RxReg(4, V0), RxReg(4, V1), RxEnd } },
{ .op = RX_OP_MULLO, .tks = { RxCode(16, 0xfd01), RxReg(4, V0), RxReg(4, V1), RxEnd } },
{ .op = RX_OP_NOP, .tks = { RxCode(8, 0x03), RxEnd } },
{ .op = RX_OP_NEG, .tks = { RxCode(12, 0x07e1), RxReg(4, V0), RxEnd } },
{ .op = RX_OP_NEG, .tks = { RxCode(16, 0xfc07), RxReg(4, V0), RxReg(4, V1), RxEnd } },
{ .op = RX_OP_NOT, .tks = { RxCode(12, 0x07e0), RxReg(4, V0), RxEnd } },
{ .op = RX_OP_NOT, .tks = { RxCode(16, 0xfc3b), RxReg(4, V0), RxReg(4, V1), RxEnd } },
{ .op = RX_OP_OR, .tks = { RxCode(8, 0x65), RxImm(4, V0), RxReg(4, V1), RxEnd } },
{ .op = RX_OP_OR, .tks = { RxCode(6, 0x1d), RxLi(2, V0), RxCode(4, 0x03), RxReg(4, V1), ImmData(V0), RxEnd } },
{ .op = RX_OP_OR_UB, .tks = { RxCode(6, 0x15), RxLd(2, V0), RxReg(4, V0), RxReg(4, V1), DspData(V0), RxEnd } },
{ .op = RX_OP_OR, .tks = { RxCode(8, 0x06), RxMi(2), RxCode(4, 0x5), RxLd(2, V0), RxReg(4, V0), RxReg(4, V1), DspData(V0), RxEnd } },
{ .op = RX_OP_OR, .tks = { RxCode(12, 0xff5), RxReg(4, V2), RxReg(4, V0), RxReg(4, V1), RxEnd } },
{ .op = RX_OP_MVFACHI, .tks = { RxCode(20, 0xfd1f0), RxReg(4, V0), RxEnd } },
{ .op = RX_OP_MVFACMI, .tks = { RxCode(20, 0xfd1f2), RxReg(4, V0), RxEnd } },
{ .op = RX_OP_MVFC, .tks = { RxCode(16, 0xfd6a), RxCr(4, V0), RxReg(4, V1), RxEnd } },
{ .op = RX_OP_MVTACHI, .tks = { RxCode(20, 0xfd170), RxReg(4, V0), RxEnd } },
{ .op = RX_OP_MVTACLO, .tks = { RxCode(20, 0xfd171), RxReg(4, V0), RxEnd } },
{ .op = RX_OP_MVTC, .tks = { RxCode(12, 0xfd7), RxLi(2, V0), RxCode(6, 0x30), RxCr(4, V1), ImmData(V0), RxEnd } },
{ .op = RX_OP_MVTC, .tks = { RxCode(16, 0xfd68), RxReg(4, V0), RxCr(4, V1), RxEnd } },
{ .op = RX_OP_MVTIPL, .tks = { RxCode(20, 0x75700), RxImm(4, V0), RxEnd } },
{ .op = RX_OP_POP, .tks = { RxCode(12, 0x7eb), RxReg(4, V0), RxEnd } },
{ .op = RX_OP_POPC, .tks = { RxCode(12, 0x7ee), RxCr(4, V0), RxEnd } },
{ .op = RX_OP_POPM, .tks = { RxCode(8, 0x6f), RxRegLimit(4, V0), RxRegLimit(4, V1), RxEnd } }, // special rn
{ .op = RX_OP_PUSH, .tks = { RxCode(10, 0x1fa), RxSz(2), RxReg(4, V0), RxEnd } },
{ .op = RX_OP_PUSH, .tks = { RxCode(6, 0x3d), RxLdPart(2, V0), RxReg(4, V0), RxCode(2, 0x2), RxSz(2), DspData(V0), RxEnd } },
{ .op = RX_OP_PUSHC, .tks = { RxCode(12, 0x7ec), RxCr(4, V0), RxEnd } },
{ .op = RX_OP_PUSHM, .tks = { RxCode(8, 0x6e), RxRegLimit(4, V0), RxRegLimit(4, V1), RxEnd } }, // special rn
{ .op = RX_OP_RACW, .tks = { RxCode(19, 0x7e8c0), RxImm(1, V0), RxCode(4, 0x0), RxEnd } },
{ .op = RX_OP_REVL, .tks = { RxCode(16, 0xfd67), RxReg(4, V0), RxReg(4, V1), RxEnd } },
{ .op = RX_OP_REVW, .tks = { RxCode(16, 0xfd65), RxReg(4, V0), RxReg(4, V1), RxEnd } },
{ .op = RX_OP_RMPA, .tks = { RxCode(14, 0x1fe3), RxSz(2), RxEnd } },
{ .op = RX_OP_ROLC, .tks = { RxCode(12, 0x7e5), RxReg(4, V0), RxEnd } },
{ .op = RX_OP_RORC, .tks = { RxCode(12, 0x7e4), RxReg(4, V0), RxEnd } },
{ .op = RX_OP_ROTL, .tks = { RxCode(15, 0x7eb7), RxImm(5, V0), RxReg(4, V1), RxEnd } },
{ .op = RX_OP_ROTL, .tks = { RxCode(16, 0xfd66), RxReg(4, V0), RxReg(4, V1), RxEnd } },
{ .op = RX_OP_ROTR, .tks = { RxCode(15, 0x7eb6), RxImm(5, V0), RxReg(4, V1), RxEnd } },
{ .op = RX_OP_ROTR, .tks = { RxCode(16, 0xfd64), RxReg(4, V0), RxReg(4, V1), RxEnd } },
{ .op = RX_OP_ROUND, .tks = { RxCode(14, 0x3f26), RxLd(2, V0), RxReg(4, V0), RxReg(4, V1), DspData(V0), RxEnd } },
{ .op = RX_OP_RTE, .tks = { RxCode(16, 0x7f95), RxEnd } },
{ .op = RX_OP_RTFI, .tks = { RxCode(16, 0x7f94), RxEnd } },
{ .op = RX_OP_RTS, .tks = { RxCode(8, 0x02), RxEnd } },
{ .op = RX_OP_RTE, .tks = { RxCode(16, 0x7f94), RxEnd } },
{ .op = RX_OP_RTSD, .tks = { RxCode(8, 0x67), ImmFixedData(V0, 8), RxEnd } },
{ .op = RX_OP_RTSD, .tks = { RxCode(8, 0x3f), RxRegLimit(4, V0), RxRegLimit(4, V1), ImmFixedData(V0, 8), RxEnd } }, // special rn
{ .op = RX_OP_SAT, .tks = { RxCode(12, 0x7e3), RxReg(4, V0), RxEnd } },
{ .op = RX_OP_SATR, .tks = { RxCode(16, 0x7f93), RxEnd } },
{ .op = RX_OP_WAIT, .tks = { RxCode(16, 0x7f96), RxEnd } },
{ .op = RX_OP_SCCOND, .tks = { RxCode(12, 0xfcd), RxSz(2), RxLd(2, V1), RxReg(4, V1), RxCond(4, V0), DspData(V1), RxEnd } },
{ .op = RX_OP_SCMPU, .tks = { RxCode(16, 0x7f83), RxEnd } },
{ .op = RX_OP_SETPSW, .tks = { RxCode(12, 0x7fa), RxCb(4), RxEnd } },
{ .op = RX_OP_SHAR, .tks = { RxCode(7, 0x35), RxImm(5, V0), RxReg(4, V1), RxEnd } },
{ .op = RX_OP_SHAR, .tks = { RxCode(16, 0xfd61), RxReg(4, V0), RxReg(4, V1), RxEnd } },
{ .op = RX_OP_SHAR, .tks = { RxCode(11, 0x07ed), RxImm(5, V0), RxReg(4, V1), RxReg(4, V2), RxEnd } },
{ .op = RX_OP_SHLL, .tks = { RxCode(7, 0x36), RxImm(5, V0), RxReg(4, V1), RxEnd } },
{ .op = RX_OP_SHLL, .tks = { RxCode(16, 0xfd62), RxReg(4, V0), RxReg(4, V1), RxEnd } },
{ .op = RX_OP_SHLL, .tks = { RxCode(11, 0x07ee), RxImm(5, V0), RxReg(4, V1), RxReg(4, V2), RxEnd } },
{ .op = RX_OP_SHLR, .tks = { RxCode(7, 0x34), RxImm(5, V0), RxReg(4, V1), RxEnd } },
{ .op = RX_OP_SHLR, .tks = { RxCode(16, 0xfd60), RxReg(4, V0), RxReg(4, V1), RxEnd } },
{ .op = RX_OP_SHLR, .tks = { RxCode(11, 0x07ec), RxImm(5, V0), RxReg(4, V1), RxReg(4, V2), RxEnd } },
{ .op = RX_OP_SBB, .tks = { RxCode(16, 0xfc03), RxReg(4, V0), RxReg(4, V1), RxEnd } },
{ .op = RX_OP_SBB, .tks = { RxCode(14, 0x01a8), RxLdPart(2, V0), RxCode(8, 0x00), RxReg(4, V0), RxReg(4, V1), DspData(V0), RxEnd } },
{ .op = RX_OP_SUB, .tks = { RxCode(8, 0x60), RxImm(4, V0), RxReg(4, V1), RxEnd } },
{ .op = RX_OP_SUB_UB, .tks = { RxCode(6, 0x10), RxLd(2, V0), RxReg(4, V0), RxReg(4, V1), DspData(V0), RxEnd } },
{ .op = RX_OP_SUB, .tks = { RxCode(8, 0x06), RxMi(2), RxCode(4, 0x0), RxLd(2, V0), RxReg(4, V0), RxReg(4, V1), DspData(V0), RxEnd } },
{ .op = RX_OP_SUB, .tks = { RxCode(12, 0xff0), RxReg(4, V2), RxReg(4, V0), RxReg(4, V1), RxEnd } },
{ .op = RX_OP_SMOVB, .tks = { RxCode(16, 0x7f8b), RxEnd } },
{ .op = RX_OP_SMOVF, .tks = { RxCode(16, 0x7f8f), RxEnd } },
{ .op = RX_OP_SMOVU, .tks = { RxCode(16, 0x7f87), RxEnd } },
{ .op = RX_OP_SSTR, .tks = { RxCode(14, 0x1fe2), RxSz(2), RxEnd } },
{ .op = RX_OP_STNZ, .tks = { RxCode(12, 0x0fd7), RxLi(2, V0), RxCode(6, 0x0f), RxReg(4, V1), ImmData(V0), RxEnd } },
{ .op = RX_OP_STZ, .tks = { RxCode(12, 0x0fd7), RxLi(2, V0), RxCode(6, 0x0e), RxReg(4, V1), ImmData(V0), RxEnd } },
{ .op = RX_OP_SUNTIL, .tks = { RxCode(14, 0x1fe0), RxSz(2), RxEnd } },
{ .op = RX_OP_SWHILE, .tks = { RxCode(14, 0x1fe1), RxSz(2), RxEnd } },
{ .op = RX_OP_TST, .tks = { RxCode(12, 0xfd7), RxLi(2, V0), RxCode(6, 0x0c), RxReg(4, V1), ImmData(V0), RxEnd } },
{ .op = RX_OP_TST_UB, .tks = { RxCode(14, 0x3f0c), RxLd(2, V0), RxReg(4, V0), RxReg(4, V1), DspData(V0), RxEnd } },
{ .op = RX_OP_TST, .tks = { RxCode(8, 0x06), RxMi(2), RxCode(4, 0x8), RxLd(2, V0), RxCode(8, 0x0c), RxReg(4, V0), RxReg(4, V1), DspData(V0), RxEnd } },
{ .op = RX_OP_XCHG_UB, .tks = { RxCode(14, 0x3f10), RxLd(2, V0), RxReg(4, V0), RxReg(4, V1), DspData(V0), RxEnd } },
{ .op = RX_OP_XCHG, .tks = { RxCode(8, 0x06), RxMi(2), RxCode(4, 0x8), RxLd(2, V0), RxCode(8, 0x10), RxReg(4, V0), RxReg(4, V1), DspData(V0), RxEnd } },
{ .op = RX_OP_XOR, .tks = { RxCode(12, 0xfd7), RxLi(2, V0), RxCode(6, 0x0d), RxReg(4, V1), ImmData(V0), RxEnd } },
{ .op = RX_OP_XOR, .tks = { RxCode(8, 0x06), RxMi(2), RxCode(4, 0x08), RxLd(2, V0), RxCode(8, 0x0d), RxReg(4, V0), RxReg(4, V1), DspData(V0), RxEnd } },
{ .op = RX_OP_XOR_UB, .tks = { RxCode(14, 0x3f0d), RxLd(2, V0), RxReg(4, V0), RxReg(4, V1), DspData(V0), RxEnd } },
};
#undef RxCode
#undef RxReg
#undef RxLi
#undef RxIm
#undef RxMi
#undef RxLd
#undef RxLds
#undef RxLdd
#undef RxCond
#undef RxDsp
#undef RxSz
#undef RxAd
#undef RxCr
#undef RxCb
#undef RxDspSplit
#undef RxIgnore
#undef RxJmp
#undef RxHook
#undef RxEnd
#undef ImmData
#undef DspData
#undef PcDspData
#undef ImmFixedData
#undef RxRi
#undef V0
#undef V1
#undef V2

View file

@ -0,0 +1,281 @@
// SPDX-FileCopyrightText: 2024 heersin <teablearcher@gmail.com>
// SPDX-License-Identifier: LGPL-3.0-only
#ifndef RX_OPCODE_DETAIL_H
#define RX_OPCODE_DETAIL_H
#include <rz_util.h>
typedef enum {
RX_OP_INVALID,
RX_OP_ABS,
RX_OP_ADC,
RX_OP_ADD,
RX_OP_ADD_UB,
RX_OP_AND,
RX_OP_AND_UB,
RX_OP_BCLR,
RX_OP_BCND_S,
RX_OP_BCND_B,
RX_OP_BCND_W,
RX_OP_BMCND,
RX_OP_BNOT,
RX_OP_BRA_S,
RX_OP_BRA_B,
RX_OP_BRA_W,
RX_OP_BRA_A,
RX_OP_BRA_L,
RX_OP_BRK,
RX_OP_BSET,
RX_OP_BSR_W,
RX_OP_BSR_A,
RX_OP_BSR_L,
RX_OP_BTST,
RX_OP_CLRPSW,
RX_OP_CMP,
RX_OP_CMP_UB,
RX_OP_DIV,
RX_OP_DIV_UB,
RX_OP_DIVU,
RX_OP_DIVU_UB,
RX_OP_EMUL,
RX_OP_EMUL_UB,
RX_OP_EMULU,
RX_OP_EMULU_UB,
RX_OP_FADD,
RX_OP_FCMP,
RX_OP_FDIV,
RX_OP_FMUL,
RX_OP_FSUB,
RX_OP_FTOI,
RX_OP_INT,
RX_OP_ITOF,
RX_OP_ITOF_UB,
RX_OP_JMP,
RX_OP_JSR,
RX_OP_MACHI,
RX_OP_MACLO,
RX_OP_MAX,
RX_OP_MAX_UB,
RX_OP_MIN,
RX_OP_MIN_UB,
RX_OP_MOV,
RX_OP_MOVU,
RX_OP_MUL,
RX_OP_MUL_UB,
RX_OP_MULHI,
RX_OP_MULLO,
RX_OP_MVFACHI,
RX_OP_MVFACMI,
RX_OP_MVFC,
RX_OP_MVTACHI,
RX_OP_MVTACLO,
RX_OP_MVTC,
RX_OP_MVTIPL,
RX_OP_NEG,
RX_OP_NOP,
RX_OP_NOT,
RX_OP_OR,
RX_OP_OR_UB,
RX_OP_POP,
RX_OP_POPC,
RX_OP_POPM,
RX_OP_PUSH,
RX_OP_PUSHC,
RX_OP_PUSHM,
RX_OP_RACW,
RX_OP_REVL,
RX_OP_REVW,
RX_OP_RMPA,
RX_OP_ROLC,
RX_OP_RORC,
RX_OP_ROTL,
RX_OP_ROTR,
RX_OP_ROUND,
RX_OP_RTE,
RX_OP_RTFI,
RX_OP_RTS,
RX_OP_RTSD,
RX_OP_SAT,
RX_OP_SATR,
RX_OP_SBB,
RX_OP_SCCOND,
RX_OP_SCMPU,
RX_OP_SETPSW,
RX_OP_SHAR,
RX_OP_SHLL,
RX_OP_SHLR,
RX_OP_SMOVB,
RX_OP_SMOVF,
RX_OP_SMOVU,
RX_OP_SSTR,
RX_OP_STNZ,
RX_OP_STZ,
RX_OP_SUB,
RX_OP_SUB_UB,
RX_OP_SUNTIL,
RX_OP_SWHILE,
RX_OP_TST,
RX_OP_TST_UB,
RX_OP_WAIT,
RX_OP_XCHG,
RX_OP_XCHG_UB,
RX_OP_XOR,
RX_OP_XOR_UB,
_RX_OP_COUNT,
} RxOpCode;
typedef enum {
// General Purpose Register
// R0 as SP
RX_REG_R0,
RX_REG_R1,
RX_REG_R2,
RX_REG_R3,
RX_REG_R4,
RX_REG_R5,
RX_REG_R6,
RX_REG_R7,
RX_REG_R8,
RX_REG_R9,
RX_REG_R10,
RX_REG_R11,
RX_REG_R12,
RX_REG_R13,
RX_REG_R14,
RX_REG_R15,
// Control Register
RX_REG_ISP,
RX_REG_USP,
RX_REG_INTB,
RX_REG_PC,
RX_REG_PSW,
RX_REG_BPC,
RX_REG_BPSW,
RX_REG_FINTV,
RX_REG_FPSW,
RX_REG_ACC, // dsp
RX_REG_RESERVED
} RxReg;
typedef enum {
RX_EXT_NON,
RX_EXT_UB,
RX_EXT_B,
RX_EXT_W,
RX_EXT_L,
RX_EXT_UW,
_RX_EXT_COUNT,
} RxOpExtMark;
typedef enum {
RX_TOKEN_NON,
RX_TOKEN_INST,
RX_TOKEN_LD,
RX_TOKEN_LI,
RX_TOKEN_LD_PART,
RX_TOKEN_MI,
RX_TOKEN_IMM,
RX_TOKEN_REG,
RX_TOKEN_COND,
RX_TOKEN_DSP,
RX_TOKEN_DSP_SPLIT,
RX_TOKEN_IGNORE,
RX_TOKEN_SZ,
RX_TOKEN_AD,
RX_TOKEN_CR,
RX_TOKEN_CB,
RX_TOKEN_JMP,
RX_TOKEN_DATA,
RX_TOKEN_RI,
RX_TOKEN_REG_LIMIT,
RX_TOKEN_HOOK, // for validation at the end of token
} RxTokenType;
struct rx_inst_token_t {
ut8 tk_len;
ut32 detail;
};
typedef struct rx_inst_token_t RxInstToken;
struct rx_oprand_related_token_t {
ut8 tk_len;
ut8 vid;
};
typedef struct rx_oprand_related_token_t RxDispLenToken;
typedef struct rx_oprand_related_token_t RxImmLenToken;
typedef struct rx_oprand_related_token_t RxVarDispLenToken;
typedef struct rx_oprand_related_token_t RxRegToken;
typedef struct rx_oprand_related_token_t RxImmToken;
typedef struct rx_oprand_related_token_t RxControlRegToken;
typedef struct rx_oprand_related_token_t RxCondToken;
typedef struct {
ut8 fixed_len;
ut8 vid;
ut8 data_type;
} RxDataToken;
typedef struct {
ut8 tk_len;
ut8 vid;
ut8 interval;
ut8 tk_len_more;
} RxDspSplitToken;
struct rx_simple_token_t {
ut8 tk_len;
};
typedef struct rx_simple_token_t RxMemexToken;
typedef struct rx_simple_token_t RxSizeToken;
typedef struct rx_simple_token_t RxFlagToken;
typedef struct rx_simple_token_t RxAddrToken;
typedef struct rx_simple_token_t RxSimpleToken;
typedef struct rx_simple_token_t RxDispToken;
typedef union rx_token_union {
RxInstToken inst;
RxDispLenToken ld;
RxImmLenToken li;
RxVarDispLenToken ld_part; // ld for partial valid bits range
RxMemexToken mi;
RxImmToken imm;
RxRegToken reg;
RxRegToken reg_li; // reg for limited range
RxRegToken ri;
RxCondToken cond;
RxDispToken dsp;
RxDspSplitToken dsp_sp;
RxSizeToken sz;
RxAddrToken ad;
RxControlRegToken cr;
RxFlagToken cb;
RxSimpleToken jmp;
RxDataToken data;
RxSimpleToken reserved;
} RxTokenUnion;
struct rx_token_t {
RxTokenType type;
RxTokenUnion tk;
};
typedef struct rx_token_t RxToken;
#define MAX_TOKEN 10
#define RX_SET_V1_SZ 90
#define RX_SET_V2_SZ (RX_SET_V1_SZ + 19)
#define RX_SET_V3_SZ (RX_SET_V2_SZ + 4)
#define RX_SET_SIZE RX_SET_V3_SZ
// todo: accurate num
#define RX_DESC_SIZE (RX_SET_SIZE * 3)
struct rx_desc_t {
RxOpCode op;
RxToken tks[MAX_TOKEN];
};
typedef struct rx_desc_t RxDesc;
extern RxDesc rx_inst_descs[RX_DESC_SIZE];
#endif

View file

@ -0,0 +1,171 @@
// SPDX-FileCopyrightText: 2024 heersin <teablearcher@gmail.com>
// SPDX-License-Identifier: LGPL-3.0-only
const char *opnames[_RX_OP_COUNT] = {
"invalid",
"abs",
"adc",
"add",
"add.UB",
"and",
"and.UB",
"bclr",
// bcnd.s, cnd provided by cond_names
"b%s.S",
"b%s.B",
"b%s.W",
"bm%s",
"bnot",
"bra.S",
"bra.B",
"bra.W",
"bra.A",
"bra.L",
"brk",
"bset",
"bsr.W",
"bsr.A",
"bsr.L",
"btst",
"clrpsw",
"cmp",
"cmp.UB",
"div",
"div.UB",
"divu",
"divu.UB",
"emul",
"emul.UB",
"emulu",
"emulu.UB",
"fadd",
"fcmp",
"fdiv",
"fmul",
"fsub",
"ftoi",
"int",
"itof",
"itof.UB",
"jmp",
"jsr",
"machi",
"maclo",
"max",
"max.UB",
"min",
"min.UB",
"mov",
"movu",
"mul",
"mul.UB",
"mulhi",
"mullo",
"mvfachi",
"mvfacmi",
"mvfc",
"mvtachi",
"mvtaclo",
"mvtc",
"mvtipl",
"neg",
"nop",
"not",
"or",
"or.UB",
"pop",
"popc",
"popm",
"push",
"pushc",
"pushm",
"racw",
"revl",
"revw",
"rmpa",
"rolc",
"rorc",
"rotl",
"rotr",
"round",
"rte",
"rtfi",
"rts",
"rtsd",
"sat",
"satr",
"sbb",
"sc%s",
"scmpu",
"setpsw",
"shar",
"shll",
"shlr",
"smovb",
"smovf",
"smovu",
"sstr",
"stnz",
"stz",
"sub",
"sub.UB",
"suntil",
"swhile",
"tst",
"tst.UB",
"wait",
"xchg",
"xchg.UB",
"xor",
"xor.UB"
};
const char *extmark_names[_RX_EXT_COUNT] = {
"B",
"W",
"L",
"UW",
};
const char *reg_names[RX_REG_RESERVED] = {
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
"isp", "usp", "intb", "pc",
"psw", "bpc", "bpsw", "fintv",
"fpsw", "acc"
};
const char *flag_names[7] = {
"C",
"Z",
"S",
"O",
"I",
"U",
"",
};
const char *cond_names[RX_COND_RESERVED] = {
"eq",
"ne",
"geu",
"ltu",
"gtu",
"leu",
"pz",
"n",
"ge",
"lt",
"gt",
"le",
"o",
"no",
"ra",
"jump",
};
#define RxNameOp(op) ((op) < _RX_OP_COUNT ? opnames[(op)] : "invalid")
#define RxNameExt(ext) ((ext) < _RX_EXT_COUNT ? extmark_names[((ext)-RX_EXT_B)] : "invalid")
#define RxNameReg(reg) ((reg) < RX_REG_RESERVED ? reg_names[(reg)-RX_REG_R0] : "invalid")
#define RxNameFlag(flag) ((flag) < 7 ? flag_names[(flag)] : "invalid")
#define RxNameCond(cond) ((cond) < RX_COND_RESERVED ? cond_names[(cond)] : "invalid")

View file

@ -37,6 +37,7 @@ asm_plugins_list = [
'pyc',
'rl78',
'rsp',
'rx',
'sh',
'snes',
'sparc_cs',
@ -124,6 +125,7 @@ rz_asm_sources = [
'p/asm_propeller.c',
'p/asm_pyc.c',
'p/asm_rl78.c',
'p/asm_rx.c',
'p/asm_rsp.c',
'p/asm_sh.c',
'p/asm_snes.c',
@ -220,6 +222,9 @@ rz_asm_sources = [
'arch/rl78/rl78_maps.c',
'arch/rl78/rl78_operand.c',
'arch/rl78/rl78.c',
'arch/rx/rx.c',
'arch/rx/rx_opcode_detail.c',
'arch/rx/rx_inst.c',
'arch/rsp/rsp_idec.c',
'arch/sh/disassembler.c',
'arch/sh/assembler.c',

41
librz/asm/p/asm_rx.c Normal file
View file

@ -0,0 +1,41 @@
// SPDX-FileCopyrightText: 2024 Heersin <teablearcher@gmail.com>
// SPDX-License-Identifier: LGPL-3.0-only
#include <rz_types.h>
#include <rz_util.h>
#include <rz_lib.h>
#include <rz_asm.h>
#include <asm/arch/rx/rx.h>
static int disassemble(RzAsm *a, RzAsmOp *op, const ut8 *buf, int len) {
RxInst inst = { 0 };
st32 bytes_read;
if (!rx_dis(&inst, &bytes_read, buf, len)) {
rz_asm_op_set_asm(op, "(invalid)");
return bytes_read;
}
rx_inst_stringify(&inst, &op->buf_asm);
op->size = bytes_read;
return bytes_read;
}
RzAsmPlugin rz_asm_plugin_rx = {
.name = "rx",
.arch = "rx",
.desc = "Renesas RX Family disassembler",
.author = "Heersin",
.license = "LGPL3",
.bits = 32,
.endian = RZ_SYS_ENDIAN_LITTLE | RZ_SYS_ENDIAN_BIG,
.disassemble = &disassemble
};
#ifndef RZ_PLUGIN_INCORE
RZ_API RzLibStruct rizin_plugin = {
.type = RZ_LIB_TYPE_ASM,
.data = &rz_asm_plugin_rx,
.version = RZ_VERSION
};
#endif

View file

@ -269,6 +269,7 @@ static const struct arch_translation arch_translation_table[] = {
{ EM_MICROBLAZE, "microblaze.gnu" },
{ EM_RISCV, "riscv" },
{ EM_RL78, "rl78" },
{ EM_RX, "rx" },
{ EM_VAX, "vax" },
{ EM_XTENSA, "xtensa" },
{ EM_LANAI, "lanai" },

View file

@ -2459,6 +2459,7 @@ extern RzAnalysisPlugin rz_analysis_plugin_riscv;
extern RzAnalysisPlugin rz_analysis_plugin_riscv_cs;
extern RzAnalysisPlugin rz_analysis_plugin_rl78;
extern RzAnalysisPlugin rz_analysis_plugin_rsp;
extern RzAnalysisPlugin rz_analysis_plugin_rx;
extern RzAnalysisPlugin rz_analysis_plugin_sh;
extern RzAnalysisPlugin rz_analysis_plugin_snes;
extern RzAnalysisPlugin rz_analysis_plugin_sparc_cs;

View file

@ -261,6 +261,7 @@ extern RzAsmPlugin rz_asm_plugin_riscv;
extern RzAsmPlugin rz_asm_plugin_riscv_cs;
extern RzAsmPlugin rz_asm_plugin_rl78;
extern RzAsmPlugin rz_asm_plugin_rsp;
extern RzAsmPlugin rz_asm_plugin_rx;
extern RzAsmPlugin rz_asm_plugin_sh;
extern RzAsmPlugin rz_asm_plugin_snes;
extern RzAsmPlugin rz_asm_plugin_sparc_cs;

367
test/db/analysis/rx Normal file
View file

@ -0,0 +1,367 @@
NAME=RX morse info
FILE=bins/rx/morse
ARGS=
CMDS=<<EOF
pd 4 @ entry0
iI
EOF
EXPECT=<<EOF
;-- entry0:
;-- section..text:
;-- segment.LOAD0:
;-- segment.ehdr:
;-- .text:
;-- L0:
;-- .LFB2:
;-- _start:
0xfff40000 mvtc #0x0, psw, ; crt0.S:36 ; [00] -r-x section size 20866 named .text
0xfff40004 mvtc #0x100, fpsw, ; crt0.S:39
0xfff40009 mov #loc.__stack, r0, ; crt0.S:40
0xfff4000f mvtc #loc.__vectors, intb, ; crt0.S:41
arch rx
cpu N/A
baddr 0xfff40000
binsz 0x0000a623
bintype elf
bits 32
class ELF32
compiler GCC: (GCC_Build_20231120) 8.3.0.202311-GNURX 20190222
dbg_file N/A
endian LE
hdr.csum N/A
guid N/A
intrp N/A
laddr 0x00000000
lang c
machine Renesas RX family
minopsz 1
os linux
cc N/A
rpath NONE
subsys linux
stripped false
crypto false
havecode true
va true
sanitiz false
static true
linenum true
lsyms true
canary false
PIE false
RELROCS true
NX false
EOF
RUN
NAME=RX morse function
FILE=bins/rx/morse
ARGS=
CMDS=<<EOF
aaa
pdf @ sym._main
pdf @ sym._text_to_morse
pdf @ sym._morse_to_text
pdf @ sym._exit
EOF
EXPECT=<<EOF
/ int sym._main(int argc, char **argv, char **envp);
| 0xfff40257 push.L r10,
| 0xfff40259 add #0xc8, r0, r10
| 0xfff4025c mov.L r10, r0,
| 0xfff4025e mov.L r10, r5,
| 0xfff40260 mov.L #0x6c6c6548, [r5],
| 0xfff40266 add #0x4, r5,
| 0xfff40268 mov.L #0x6f57206f, [r5],
| 0xfff4026e add #0x4, r5,
| 0xfff40270 mov.L #0x646c72, [r5],
| 0xfff40275 add #0x4, r5,
| 0xfff40277 mov.L r10, r1,
| 0xfff40279 bsr.A #0xfffecf, ; sym._text_to_morse
| 0xfff4027d mov #loc..LC28, r3,
| 0xfff40283 mov #0x2c, r4,
| 0xfff40286 add #0xc, r10, r5
| 0xfff40289 mov.L r5, r1,
| 0xfff4028b mov.L r3, r2,
| 0xfff4028d mov.L r4, r3,
| 0xfff4028f smovf
| 0xfff40291 add #0xc, r10, r5
| 0xfff40294 mov.L r5, r1,
| 0xfff40296 bsr.A #0xffff4a, ; sym._morse_to_text
| 0xfff4029a mov #0x0, r5,
| 0xfff4029c mov.L r5, r1,
\ 0xfff4029e rtsd #0xf, r10,
; CALL XREF from sym._main @ 0xfff40279
/ sym._text_to_morse();
| 0xfff40148 push.L r10,
| 0xfff4014a add #0xfc, r0, r10
| 0xfff4014d add #0xf8, r10, r0
| 0xfff40150 mov.L r1, [r10],
| ,=< 0xfff40152 bra.B #0x7a,
| .--> 0xfff40154 mov.L [r10], r5,
| :| 0xfff40156 mov.B [r5], r5,
| :| 0xfff40158 movu.B r5, r5,
| :| 0xfff4015a cmp #0x60, r5,
| ,===< 0xfff4015d bleu.B #0x2d,
| |:| 0xfff4015f mov.L [r10], r5,
| |:| 0xfff40161 mov.B [r5], r5,
| |:| 0xfff40163 movu.B r5, r5,
| |:| 0xfff40165 cmp #0x7a, r5,
| ,====< 0xfff40168 bgtu.B #0x22,
| ||:| 0xfff4016a mov.L [r10], r5,
| ||:| 0xfff4016c mov.B [r5], r5,
| ||:| 0xfff4016e movu.B r5, r5,
| ||:| 0xfff40170 add #0x9f, r5, r5
| ||:| 0xfff40173 mov #0x10, r4,
| ||:| 0xfff40179 mov.L [r5,r4], r5,
| ||:| 0xfff4017c mov.L r5, 0x1[r0],
| ||:| 0xfff4017e mov.L #loc..LC26, [r0],
| ||:| 0xfff40184 bsr.A #0x14d, ; sym._printf ; int printf(const char *format)
| ,=====< 0xfff40188 bra.B #0x3e,
| |``---> 0xfff4018a mov.L [r10], r5,
| | :| 0xfff4018c mov.B [r5], r5,
| | :| 0xfff4018e movu.B r5, r5,
| | :| 0xfff40190 cmp #0x40, r5,
| | ,===< 0xfff40193 bleu.B #0x2c,
| | |:| 0xfff40195 mov.L [r10], r5,
| | |:| 0xfff40197 mov.B [r5], r5,
| | |:| 0xfff40199 movu.B r5, r5,
| | |:| 0xfff4019b cmp #0x5a, r5,
| |,====< 0xfff4019e bgtu.B #0x21,
| |||:| 0xfff401a0 mov.L [r10], r5,
| |||:| 0xfff401a2 mov.B [r5], r5,
| |||:| 0xfff401a4 movu.B r5, r5,
| |||:| 0xfff401a6 add #0xbf, r5, r5
| |||:| 0xfff401a9 mov #0x10, r4,
| |||:| 0xfff401af mov.L [r5,r4], r5,
| |||:| 0xfff401b2 mov.L r5, 0x1[r0],
| |||:| 0xfff401b4 mov.L #loc..LC26, [r0],
| |||:| 0xfff401ba bsr.A #0x117, ; sym._printf ; int printf(const char *format)
..
| |``---> 0xfff401bf mov #0x20, r1,
| | :| 0xfff401c2 bsr.A #0x12e, ; sym._putchar ; int putchar(int c)
| `-----> 0xfff401c6 mov.L [r10], r5,
| :| 0xfff401c8 add #0x1, r5,
| :| 0xfff401ca mov.L r5, [r10],
| :`-> 0xfff401cc mov.L [r10], r5,
| : 0xfff401ce mov.B [r5], r5,
| : 0xfff401d0 movu.B r5, r5,
| : 0xfff401d2 cmp #0x0, r5,
\ `==< 0xfff401d4 bne.B #0x80,
; CALL XREF from sym._main @ 0xfff40296
/ sym._morse_to_text();
| 0xfff401e0 push.L r10,
| 0xfff401e2 add #0xf4, r0, r10
| 0xfff401e5 mov.L r10, r0,
| 0xfff401e7 mov.L r1, 0x2[r10],
| 0xfff401ea mov #loc..LC27, r2,
| 0xfff401f0 mov.L 0x2[r10], r1,
| 0xfff401f3 bsr.A #0x178, ; sym._strtok ; char *strtok(char *s1, const char *s2)
| 0xfff401f7 mov.L r1, [r10],
| ,=< 0xfff401f9 bra.B #0x4e,
| .--> 0xfff401fb mov.L #0x0, 0x1[r10],
| ,===< 0xfff401ff bra.B #0x32,
| .----> 0xfff40201 mov #0x10, r5,
| :|:| 0xfff40207 mov.L 0x1[r10], r4,
| :|:| 0xfff4020a mov.L [r4,r5], r5,
| :|:| 0xfff4020d mov.L r5, r2,
| :|:| 0xfff4020f mov.L [r10], r1,
| :|:| 0xfff40211 bsr.A #0x14b, ; sym._strcmp ; int strcmp(const char *s1, const char *s2)
| :|:| 0xfff40215 mov.L r1, r5,
| :|:| 0xfff40217 cmp #0x0, r5,
| ,=====< 0xfff40219 bne.B #0x10,
| |:|:| 0xfff4021b mov.L 0x1[r10], r5,
| |:|:| 0xfff4021e add #0x41, r5, r5
| |:|:| 0xfff40221 mov.L r5, r1,
| |:|:| 0xfff40223 bsr.A #0xcd, ; sym._putchar ; int putchar(int c)
| ,======< 0xfff40227 bra.B #0x12,
| |`-----> 0xfff40229 mov.L 0x1[r10], r5,
| | :|:| 0xfff4022c add #0x1, r5,
| | :|:| 0xfff4022e mov.L r5, 0x1[r10],
| | :`---> 0xfff40231 mov.L 0x1[r10], r5,
| | : :| 0xfff40234 cmp #0x19, r5,
| | `====< 0xfff40237 ble.B #0xca,
| `------> 0xfff40239 mov #loc..LC27, r2,
| :| 0xfff4023f mov #0x0, r1,
| :| 0xfff40241 bsr.A #0x12a, ; sym._strtok ; char *strtok(char *s1, const char *s2)
| :| 0xfff40245 mov.L r1, [r10],
| :`-> 0xfff40247 mov.L [r10], r5,
| : 0xfff40249 cmp #0x0, r5,
\ `==< 0xfff4024b bne.B #0xb0,
/ void sym._exit(int status);
| 0xfff402a1 push.L r7,
| 0xfff402a3 mov.L r1, r7,
| 0xfff402a5 mov #0x0, r2,
| 0xfff402a7 bsr.A #0x132b, ; sym.___call_exitprocs
| 0xfff402ab mov #obj.__global_impure_ptr, r5,
| 0xfff402b1 mov.L [r5], r1,
| 0xfff402b3 mov.L 0xf[r1], r5,
| 0xfff402b5 cmp #0x0, r5,
| ,=< 0xfff402b7 beq.S #0x3,
| | 0xfff402b8 jsr r5,
| `-> 0xfff402ba mov.L r7, r1,
\ 0xfff402bc bsr.A #0x471c, ; sym.__exit ; void _exit(int status)
EOF
RUN
NAME=RX morse function list
FILE=bins/rx/morse
ARGS=
CMDS=<<EOF
aaa
afl
EOF
EXPECT=<<EOF
0xfff40000 1 94 entry0
0xfff4005e 7 75 -> 42 sym._rx_run_preinit_array
0xfff4006e 1 18 sym._rx_run_init_array
0xfff40080 1 15 sym._rx_run_fini_array
0xfff400b0 3 32 -> 23 sym._deregister_tm_clones
0xfff400d0 4 43 sym._register_tm_clones
0xfff400fb 5 43 sym.___do_global_dtors_aux
0xfff40126 1 1 sym._call___do_global_dtors_aux
0xfff40127 3 28 sym._frame_dummy
0xfff40143 1 1 sym._call_frame_dummy
0xfff40148 10 142 -> 141 sym._text_to_morse
0xfff401e0 8 109 sym._morse_to_text
0xfff40257 1 74 sym._main
0xfff402a1 3 31 sym._exit
0xfff402c0 1 17 sym.__printf_r
0xfff402d1 1 25 sym._printf
0xfff402ea 1 6 sym.__putchar_r
0xfff402f0 1 18 sym._putchar
0xfff40302 8 74 sym.__putc_r
0xfff4034c 1 16 sym._putc
0xfff4035c 1 15 sym._strcmp
0xfff4036b 1 17 sym._strtok
0xfff4037c 13 103 -> 81 sym.___strtok_r
0xfff403e3 1 6 sym._strtok_r
0xfff403e9 35 4023 -> 411 sym.__vfprintf_r
0xfff413ee 1 18 sym._vfprintf
0xfff41400 5 119 sym.___sbprintf
0xfff41477 1 10 sym.___swbuf_r
0xfff41511 1 16 sym.___swbuf
0xfff41521 1 16 sym.___swsetup_r
0xfff415d2 11 112 -> 79 sym.___call_exitprocs
0xfff41657 11 263 -> 215 sym._quorem
0xfff4175e 33 2479 -> 400 sym.__dtoa_r
0xfff4210d 6 223 -> 53 sym.___sflush_r
0xfff42229 5 43 -> 34 sym.__fflush_r
0xfff42254 3 35 sym._fflush
0xfff42277 1 3 sym.___fp_lock
0xfff4227a 1 73 sym._std
0xfff422c3 1 10 sym.__cleanup_r
0xfff422cd 1 3 sym.___fp_unlock
0xfff422d0 3 46 sym.___sfmoreglue
0xfff422fe 1 12 sym.__cleanup
0xfff4230a 3 69 sym.___sinit
0xfff4234f 11 132 sym.___sfp
0xfff423d8 1 1 sym.___sfp_lock_acquire
0xfff423d9 1 1 sym.___sfp_lock_release
0xfff423da 1 1 sym.___sinit_lock_acquire
0xfff423db 1 1 sym.___sinit_lock_release
0xfff423dc 1 18 sym.___fp_lock_all
0xfff423ee 1 18 sym.___fp_unlock_all
0xfff42400 3 74 sym.__malloc_trim_r
0xfff424a3 19 392 -> 214 sym.__free_r
0xfff4262b 10 57 sym.__fwalk
0xfff42664 9 61 -> 52 sym.__fwalk_reent
0xfff426a1 1 5 sym.___localeconv_l
0xfff426a6 1 7 sym.__localeconv_r
0xfff426ad 1 7 sym._localeconv
0xfff426b4 4 40 sym.__setlocale_r
0xfff42700 1 11 sym.___locale_mb_cur_max
0xfff4270b 1 16 sym._setlocale
0xfff4271b 6 76 -> 51 sym.___swhatbuf_r
0xfff42767 8 123 -> 104 sym.___smakebuf_r
0xfff427e2 5 34 sym.__malloc_r
0xfff42c16 1 18 sym.__mbtowc_r
0xfff42c28 8 37 sym.___ascii_mbtowc
0xfff42c4d 1 11 sym._memchr
0xfff42c58 1 7 sym._memcpy
0xfff42c5f 1 7 sym._memset
0xfff42c66 1 1 sym.___malloc_lock
0xfff42c67 1 1 sym.___malloc_unlock
0xfff42c68 9 84 sym.__Balloc
0xfff42cbc 3 17 sym.__Bfree
0xfff42ccd 2 59 sym.___multadd
0xfff42d60 13 156 -> 151 sym.___s2b
0xfff42dfc 12 72 sym.___hi0bits
0xfff42e44 18 100 -> 85 sym.___lo0bits
0xfff42ea8 3 44 sym.___i2b
0xfff42ed4 22 291 -> 287 sym.___multiply
0xfff42ffc 13 122 -> 98 sym.___pow5mult
0xfff43076 12 179 -> 153 sym.___lshift
0xfff4312b 7 45 sym.___mcmp
0xfff4315a 12 190 sym.___mdiff
0xfff43251 3 37 -> 25 sym.___ulp
0xfff43276 7 86 -> 71 sym.___b2d
0xfff432cc 8 124 sym.___d2b
0xfff43348 4 69 sym.___ratio
0xfff4338d 4 34 sym.__mprec_log10
0xfff433b0 6 50 sym.___copybits
0xfff433e2 10 59 sym.___any_on
0xfff4341d 1 22 sym.__sbrk_r
0xfff4343e 7 50 sym.___fpclassifyf
0xfff43470 4 31 sym.___sread
0xfff4348f 1 3 sym.___seofread
0xfff43492 3 48 sym.___swrite
0xfff434c2 1 15 sym.___sseek
0xfff434e1 1 6 sym.___sclose
0xfff434e7 1 13 sym._strlen
0xfff434f4 1 9 sym.___sprint_r
0xfff43554 139 2076 -> 1058 sym.__vfiprintf_r
0xfff43d70 1 18 sym._vfiprintf
0xfff43d82 5 119 sym.___sbprintf_0xfff43d82
0xfff43df9 1 12 sym.__wctomb_r
0xfff43e05 5 25 sym.___ascii_wctomb
0xfff43e1e 1 26 sym.__write_r
0xfff43e43 4 60 sym.___assert_func
0xfff43e7f 1 8 sym.___assert
0xfff43e87 4 32 sym.__calloc_r
0xfff43efa 1 22 sym.__close_r
0xfff43f1b 1 9 sym.___errno
0xfff43f24 1 4 sym.__fclose_r
0xfff43fa1 1 14 sym._fclose
0xfff43faf 1 15 sym.__fiprintf_r
0xfff43fbe 1 25 sym._fiprintf
0xfff43fd7 13 115 -> 109 sym.___fputwc
0xfff4404c 3 26 sym.__fputwc_r
0xfff44066 4 41 sym._fputwc
0xfff4408f 1 24 sym.__fstat_r
0xfff440b2 39 671 -> 320 sym.___sfvwrite_r
0xfff44351 1 22 sym.__isatty_r
0xfff44372 1 26 sym.__lseek_r
0xfff44397 3 24 sym._memmove
0xfff443af 1 26 sym.__read_r
0xfff443d4 1 10 sym.__realloc_r
0xfff446f8 3 25 sym._cleanup_glue
0xfff44711 18 151 -> 129 sym.__reclaim_reent
0xfff447a8 3 29 sym.__wcrtomb_r
0xfff447d0 1 18 sym._wcrtomb
0xfff447e2 1 12 sym._abort
0xfff447ee 7 52 -> 50 sym.__init_signal_r
0xfff44822 6 50 sym.__signal_r
0xfff44856 9 81 -> 75 sym.__raise_r
0xfff448a7 12 81 -> 78 sym.___sigtramp_r
0xfff448f8 1 14 sym._raise
0xfff44906 1 16 sym._signal
0xfff44916 1 12 sym.__init_signal
0xfff44922 1 14 sym.___sigtramp
0xfff44930 1 24 sym.__kill_r
0xfff44953 1 4 sym.__getpid_r
0xfff44957 1 13 sym._close
0xfff44964 1 13 sym._fstat
0xfff44971 1 13 sym._getpid
0xfff4497e 1 12 sym._isatty
0xfff4498a 1 13 sym._kill
0xfff44997 1 13 sym._lseek
0xfff449a4 1 13 sym._read
0xfff449b1 3 26 sym._sbrk
0xfff449cb 1 13 sym._write
0xfff449d8 2 8 sym.__exit
0xfff449e0 104 971 -> 944 sym.___udivdi3
0xfff44db0 97 938 sym.__COM_MOD64u
0xfff45548 1 4 loc..LANCHOR0_0xfff45548
EOF
RUN

204
test/db/asm/rx Normal file
View file

@ -0,0 +1,204 @@
d "itof.UB r1, r2," fc4712
d "mov.W [r1], r2," dc12
d "bclr r1, r2," fc6721
d "itof 0x4[r1].L, r2," 06a1111204
d "sub r1, r2, r3" ff0312
d "xor.UB r1, r2," fc3712
d "sub.UB r1, r2," 4312
d "bmgeu #0x7, [r2]" fcfc22
d "rts" 02
d "emulu 0x4[r1].UW, r2," 06e1071204
d "shlr #0x3, r1, r2" fd8312
d "bset #0x7, [r2]," f027
d "div 0x3[r1].B, r2," 0621081203
d "divu.UB 0x3[r1], r2," fc251203
d "divu [r1].L, r2," 06a00912
d "mvtipl #0x2," 757002
d "racw #0x0," fd1800
d "mul.UB r1, r2," 4f12
d "setpsw C," 7fa0
d "add [r1].L, r2," 068812
d "bltu.B #0x5," 2305
d "mov.W [r1,r2], r3," fe5123
d "or #0x8, r1," 6581
d "bnot #0x1f, r2," fdfff2
d "rmpa.W" 7f8d
d "bclr r1, [r2]," fc6421
d "cmp #0x7, r2," 6172
d "emul #0xa, r2," fd74620a
d "max #0xa, r2," fd74420a
d "or r1, r2, r3" ff5312
d "revw r1, r2," fd6512
d "shlr #0x3, r2," 6832
d "shar #0x3, r2," 6a32
d "rtfi" 7f94
d "shar r1, r2," fd6112
d "or 0x2[r1].L, r2," 06951202
d "smovb" 7f8b
d "xor 0x4[r1].L, r2," 06a10d1204
d "btst #0x7, [r2]," f427
d "emul [r1].L, r2," 06a00612
d "push.B r1," 7e81
d "setpsw Z," 7fa1
d "bra.L r2," 7f42
d "mov #0x0, r2," 6602
d "mov.W r1, [r2]," d321
d "max 0x3[r1].B, r2," 0621041203
d "max.UB r1, r2," fc1312
d "fmul [r1], r2," fc8c12
d "bra.L r1," 7f41
d "mullo r1, r2," fd0112
d "bsr.L r2," 7f52
d "satr" 7f93
d "add #0x7f, r1, r2" 71127f
d "mov.B [-r1], r2," fd2c12
d "and [r1].UW, r2," 06d012
d "mvfachi r1," fd1f01
d "clrpsw C," 7fb0
d "bmeq #0x1f, r2" fdff02
d "round [r1], r2," fc9812
d "rotl r1, r2," fd6612
d "btst r1, r2," fc6b21
d "emul 0x4[r1].W, r2," 0661061204
d "popc psw," 7ee0
d "fdiv [r1], r2," fc9012
d "neg r1, r2," fc0712
d "emul.UB r1, r2," fc1b12
d "mov.L r1, r2," ef12
d "bnot r1, [r2]," fc6c21
d "or [r1].L, r2," 069412
d "movu.W 0x1[r1], r2," b81a
d "mul #0xa, r2," 63a2
d "bnot r1, r2," fc6f21
d "mov.B r1, [r2+]," fd2021
d "abs r0," 7e20
d "neg r1," 7e11
d "min #0xa, r2," fd74520a
d "bsr.L r1," 7f51
d "div.UB r1, r2," fc2312
d "add #0xf, r2," 62f2
d "rorc r1," 7e41
d "scgeu.L r2," fcdb22
d "suntil.W" 7f81
d "or.UB r1, r2," 5712
d "tst #0x7, r2," fd74c207
d "add r1, r2, r3" ff2312
d "mvtc r1, usp," fd6812
d "divu.UB r1, r2," fc2712
d "revl r1, r2," fd6712
d "adc [r1].L, r2," 06a00212
d "ftoi [r1], r2," fc9412
d "machi r1, r2," fd0412
d "sat r1," 7e31
d "max [r1].L, r2," 06a00412
d "mul [r1].L, r2," 068c12
d "fsub [r1], r2," fc8012
d "tst.UB 0x1[r1], r2," fc311201
d "sbb [r1], r2," 06a00012
d "sub #0xf, r2," 60f2
d "mul r1, r2, r3" ff3312
d "bra.W #0xfc8," 38c80f
d "and #0xf, r2," 64f2
d "btst r1, [r2]," fc6821
d "mulhi r0, r0," fd0000
d "rolc r1," 7e51
d "bnot #0x7, [r2]," fcfc2f
d "not r1," 7e01
d "adc r1, r2," fc0b12
d "emulu.UB r1, r2," fc1f12
d "add.UB [r1], r2," 4812
d "mul 0x2[r1].W, r2," 064d1202
d "adc #0x7f, r2," fd74227f
d "fmul r1, r2," fc8f12
d "mvfacmi r1," fd1f21
d "abs r1, r0," fc0f10
d "cmp.UB r1, r2," 4712
d "push.L [r1]," f41a
d "btst #0x1f, r2," 7df2
d "xor #0x8, r1," fd74d108
d "maclo r1, r2," fd0512
d "popm r4, r8," 6f48
d "mov.B [r1+], r2," fd2812
d "ftoi r1, r2," fc9712
d "mvfc usp, r1," fd6a21
d "rotr #0x1, r1," fd6c11
d "bra.A #0x0," 04000000
d "rtsd #0x1," 6701
d "not r1, r2," fc3b12
d "stz #0x1, r2," fd74e201
d "swhile.W" 7f85
d "div #0xa, r2," fd74820a
d "fcmp r1, r2," fc8712
d "bset r1, [r2]," fc6021
d "emulu #0xa, r2," fd74720a
d "bset r1, r2," fc6321
d "fadd r1, r2," fc8b12
d "itof [r1].L, r2," 06a01112
d "cmp [r1].L, r2," 068412
d "jmp r1," 7f01
d "add.UB r1, r2," 4b12
d "fcmp [r1], r2," fc8412
d "mvtachi r1," fd1701
d "clrpsw Z," 7fb1
d "scmpu" 7f83
d "rte" 7f95
d "bclr #0x7, [r2]," f02f
d "min 0x3[r1].B, r2," 0621051203
d "mov.W r1, [r2,r3]," fe1231
d "mvtaclo r1," fd1711
d "round r1, r2," fc9b12
d "bclr #0x1f, r2," 7bf2
d "pushm r4, r8," 6e48
d "rotr r1, r2," fd6412
d "shar #0x3, r1, r2" fda312
d "mov #0x80, r2," fb2680
d "shll #0x3, r2," 6c32
d "stnz #0x1, r2," fd74f201
d "fsub r1, r2," fc8312
d "pushm r1, r3," 6e13
d "emulu [r1].L, r2," 06a00712
d "rtsd #0x4, r7," 3f5704
d "smovu" 7f87
d "pop r1," 7eb1
d "scne.W [r2]," fcd421
d "mvtc #0xf000, intb," fd7b0c00f0
d "mov #0x80, r2," 754280
d "pushc psw," 7ec0
d "rotl #0x1, r1," fd6e11
d "and [r1].L, r2," 069012
d "nop" 03
d "shll #0x3, r1, r2" fdc312
d "tst [r1].L, r2," 06a00c12
d "brk" 00
d "sub 0x1[r1].B, r2," 06011201
d "wait" 7f96
d "fadd [r1], r2," fc8812
d "fdiv r1, r2," fc9312
d "sstr.W" 7f89
d "shll r1, r2," fd6212
d "tst.UB r1, r2," fc3312
d "sub [r1].L, r2," 068012
d "sbb r1, r2," fc0312
d "movu.W r1, r2," 5f12
d "div [r1].L, r2," 06a00812
d "mov.W [r1], [r2]," d012
d "bset #0x1f, r2," 79f2
d "int #0x0," 756000
d "divu #0xa, r2," fd74920a
d "smovf" 7f8f
d "jsr r1," 7f11
d "mulhi r1, r2," fd0012
d "xchg.UB r1, r2," fc4312
d "racw #0x1," fd1810
d "movu.B [-r1], r2," fd3c12
d "xchg [r1].W, r2," 06601012
d "mov.L #0x0, [r2]," f82600
d "xor [r1].L, r2," 06a00d12
d "and.UB r1, r2," 5312
d "and r1, r2, r3" ff4312
d "min [r1].L, r2," 06a00512
d "movu.B [r1+], r2," fd3812
d "mov.B r1, [-r2]," fd2421
d "popm r1, r3," 6f13
d "bsr.A #0x0," 05000000
d "min.UB r1, r2," fc1712

File diff suppressed because one or more lines are too long