diff --git a/librz/arch/isa/tms320/c2x/c2x.c b/librz/arch/isa/tms320/c2x/c2x.c new file mode 100644 index 00000000000..af4ad7e15bd --- /dev/null +++ b/librz/arch/isa/tms320/c2x/c2x.c @@ -0,0 +1,606 @@ +// SPDX-FileCopyrightText: 2026 RizinOrg +// SPDX-License-Identifier: LGPL-3.0-only + +/** + * \file + * TMS320C2x (legacy single-accumulator fixed-point DSP, e.g. TMS320C25) + * disassembly + analysis, built on the shared C55 decode engine (c55_ir.[ch]). + * + * The C2x is a 16-bit word-addressed Harvard machine. Memory-reference + * instructions carry one addressing byte (the low 8 bits of the opcode word): + * bit 7 selects direct (0) or indirect (1) addressing. + * - Direct: bits 6-0 are a 7-bit data-page offset (dma); the effective + * address is (DP[8:0] << 7) | dma. + * - Indirect: bits 6-4 (M) select an auxiliary-register modification applied + * to the ARP-selected AR; bits 3-0 (N), when N>=8, reload ARP to + * N&7 (rendered ",arX"). M: 0=* 1=*- 2=*+ 4=*BR0- 5=*0- 6=*0+ + * 7=*BR0+. + * + * Opcode bit patterns are transcribed from the public TMS320C2x instruction set + * (matching MAME's tested TMS320x25 disassembler). Words are stored MSB-first, + * so the engine's per-word byte-swap (words_le) is NOT used. mask/match operate + * on the engine's 4-byte MSB-first "head" (opcode word in head bits 31:16); + * operand extractors index the c55_pack() word (opcode word in the low 16 bits + * for a 2-byte instruction, the leading word in bits 31:16 for a 4-byte one). + * + * Validation status: written against the encoding reference and the engine + * contracts; NOT yet round-tripped through a built rz-asm or cross-checked + * against a hardware/reference disassembler. The F8..FF branch tail in + * particular (B/CALL/BANZ/BBZ/BBNZ/BIOZ opcodes) is reconstructed and should be + * verified before merge. + */ + +#include "c2x.h" + +// bitfield helper (c55_field is private to the engine) + +static ut64 c2x_field(ut64 bits, ut8 lo, ut8 width) { + if (width >= 64) { + return bits >> lo; + } + return (bits >> lo) & (((ut64)1 << width) - 1); +} + +// operand extractors + +static const char *const c2x_indir_raw[8] = { + "*", "*-", "*+", "*?", "*br0-", "*0-", "*0+", "*br0+" +}; +static const C55AddrMode c2x_indir_amode[8] = { + C55_AM_INDIRECT, C55_AM_POSTDEC, C55_AM_POSTINC, C55_AM_INDIRECT /* reserved */, + C55_AM_BITREV_SUB, C55_AM_POSTSUB, C55_AM_POSTADD, C55_AM_BITREV +}; +static const char *const c2x_arx_raw[8] = { + "ar0", "ar1", "ar2", "ar3", "ar4", "ar5", "ar6", "ar7" +}; + +// Single data-memory operand: the byte at d->lo is the addressing byte. Direct +// addressing is represented structurally (C55_AM_DIRECT + 7-bit dma in disp) so +// the lifter can form its EA via c2x_ea(); indirect addressing is ARP-relative +// (no statically known AR), so it renders verbatim via raw and is opaque to IL. +RZ_IPI void c2x_x_mem(RZ_UNUSED const C55ArchDesc *a, ut64 bits, const C55OpDesc *d, C55Operand *out) { + ut8 b = (ut8)c2x_field(bits, d->lo, 8); + out->kind = C55_OP_MEM; + out->access = 16; + if (b & 0x80) { + ut8 m = (b >> 4) & 7; + out->amode = c2x_indir_amode[m]; + out->reg.cls = C55_RC_AR; // ARP-selected at run time; placeholder index + out->reg.num = 0; + out->raw = c2x_indir_raw[m]; + } else { + out->amode = C55_AM_DIRECT; + out->disp = (st32)(b & 0x7f); + } +} + +// next-ARP nibble (N field): N>=8 reloads ARP to N&7, rendered ",arX". +RZ_IPI void c2x_x_nextarp(RZ_UNUSED const C55ArchDesc *a, ut64 bits, const C55OpDesc *d, C55Operand *out) { + ut8 n = (ut8)c2x_field(bits, d->lo, 4); + if (n & 0x8) { + out->kind = C55_OP_REG; + out->reg.cls = C55_RC_AR; + out->reg.num = n & 7; + out->width = 16; + out->raw = c2x_arx_raw[n & 7]; + } else { + out->kind = C55_OP_NONE; + } +} + +// shift count (T 4-bit / S 3-bit), rendered as an immediate. +RZ_IPI void c2x_x_shift(RZ_UNUSED const C55ArchDesc *a, ut64 bits, const C55OpDesc *d, C55Operand *out) { + out->kind = C55_OP_IMM; + out->imm = c2x_field(bits, d->lo, d->width); + out->width = 16; +} + +// auxiliary-register number (R field) -> arX register operand. +RZ_IPI void c2x_x_reg(RZ_UNUSED const C55ArchDesc *a, ut64 bits, const C55OpDesc *d, C55Operand *out) { + out->kind = C55_OP_REG; + out->reg.cls = C55_RC_AR; + out->reg.num = (ut8)c2x_field(bits, d->lo, d->width); + out->width = 16; + out->raw = (out->reg.num < 8) ? c2x_arx_raw[out->reg.num] : NULL; +} + +// immediate (D 8-bit / K small / W 16-bit / MPYK 13-bit); param 1 => signed. +RZ_IPI void c2x_x_imm(RZ_UNUSED const C55ArchDesc *a, ut64 bits, const C55OpDesc *d, C55Operand *out) { + out->kind = C55_OP_IMM; + out->imm = c2x_field(bits, d->lo, d->width); + out->width = d->width; + out->imm_signed = (d->param == 1); +} + +// 16-bit absolute branch/call target carried in the trailing word. +RZ_IPI void c2x_x_branch(RZ_UNUSED const C55ArchDesc *a, ut64 bits, const C55OpDesc *d, C55Operand *out) { + out->kind = C55_OP_IMM; + out->imm = c2x_field(bits, d->lo, 16); + out->width = 16; + out->addr = true; + out->abs_target = true; +} + +// decode table + +#include "c2x_rowdefs.h" + +static const C55InsnDef c2x_table[] = { +#include "c2x_core_rows.inc" +}; + +#include "c2x_rowundefs.h" + +// register resolver + +static const C55RegInfo c2x_reg_acc = { "acc", "acc", 32 }; +static const C55RegInfo c2x_reg_t = { "t", "t", 16 }; +static const C55RegInfo c2x_reg_dp = { "dp", "dp", 16 }; +static const C55RegInfo c2x_reg_arp = { "arp", "arp", 16 }; +static const C55RegInfo c2x_reg_p = { "p", "p", 32 }; +static const C55RegInfo c2x_reg_pc = { "pc", "pc", 16 }; +static const C55RegInfo c2x_reg_ar[8] = { + { "ar0", "ar0", 16 }, { "ar1", "ar1", 16 }, { "ar2", "ar2", 16 }, { "ar3", "ar3", 16 }, + { "ar4", "ar4", 16 }, { "ar5", "ar5", 16 }, { "ar6", "ar6", 16 }, { "ar7", "ar7", 16 } +}; +static const C55RegInfo c2x_reg_st[2] = { { "st0", "st0", 16 }, { "st1", "st1", 16 } }; + +RZ_IPI const C55RegInfo *c2x_reg_info(C55RegClass cls, ut8 num, RZ_UNUSED C55SubReg sub) { + switch (cls) { + case C55_RC_AC: return &c2x_reg_acc; + case C55_RC_T: return &c2x_reg_t; + case C55_RC_DP: return &c2x_reg_dp; + case C55_RC_ARP: return &c2x_reg_arp; + case C55_RC_AR: return num < 8 ? &c2x_reg_ar[num] : NULL; + case C55_RC_ST: return num < 2 ? &c2x_reg_st[num] : NULL; + // SPECIAL num 0 is the product register P, 1 is PC. + case C55_RC_SPECIAL: return num == 0 ? &c2x_reg_p : &c2x_reg_pc; + default: return NULL; + } +} + +// id -> RzAnalysisOp type + +RZ_IPI ut32 c2x_op_type(ut16 id) { + switch (id) { + case C2X_INS_NOP: + return RZ_ANALYSIS_OP_TYPE_NOP; + case C2X_INS_ADD: + case C2X_INS_ADDH: + case C2X_INS_ADDS: + case C2X_INS_ADDT: + case C2X_INS_ADDC: + case C2X_INS_ADDK: + case C2X_INS_ADLK: + case C2X_INS_APAC: + case C2X_INS_ADRK: + return RZ_ANALYSIS_OP_TYPE_ADD; + case C2X_INS_SUB: + case C2X_INS_SUBH: + case C2X_INS_SUBS: + case C2X_INS_SUBT: + case C2X_INS_SUBC: + case C2X_INS_SUBB: + case C2X_INS_SUBK: + case C2X_INS_SBLK: + case C2X_INS_SPAC: + case C2X_INS_SBRK: + case C2X_INS_NEG: + return RZ_ANALYSIS_OP_TYPE_SUB; + case C2X_INS_AND: + case C2X_INS_ANDK: + return RZ_ANALYSIS_OP_TYPE_AND; + case C2X_INS_OR: + case C2X_INS_ORK: + return RZ_ANALYSIS_OP_TYPE_OR; + case C2X_INS_XOR: + case C2X_INS_XORK: + return RZ_ANALYSIS_OP_TYPE_XOR; + case C2X_INS_CMPL: + return RZ_ANALYSIS_OP_TYPE_NOT; + case C2X_INS_SFL: + case C2X_INS_ROL: + return RZ_ANALYSIS_OP_TYPE_SHL; + case C2X_INS_SFR: + case C2X_INS_ROR: + return RZ_ANALYSIS_OP_TYPE_SHR; + case C2X_INS_MPY: + case C2X_INS_MPYK: + case C2X_INS_MPYA: + case C2X_INS_MPYS: + case C2X_INS_MPYU: + case C2X_INS_SQRA: + case C2X_INS_SQRS: + case C2X_INS_PAC: + case C2X_INS_MAC: + case C2X_INS_MACD: + return RZ_ANALYSIS_OP_TYPE_MUL; + case C2X_INS_LAC: + case C2X_INS_LACT: + case C2X_INS_LACK: + case C2X_INS_ZAC: + case C2X_INS_ZALH: + case C2X_INS_ZALS: + case C2X_INS_ZALR: + case C2X_INS_LAR: + case C2X_INS_LARK: + case C2X_INS_LRLK: + case C2X_INS_LALK: + case C2X_INS_LDP: + case C2X_INS_LDPK: + case C2X_INS_LT: + case C2X_INS_LTA: + case C2X_INS_LTD: + case C2X_INS_LTP: + case C2X_INS_LTS: + case C2X_INS_LST: + case C2X_INS_LST1: + case C2X_INS_LPH: + case C2X_INS_DMOV: + case C2X_INS_PSHD: + case C2X_INS_PUSH: + case C2X_INS_ABS: + return RZ_ANALYSIS_OP_TYPE_MOV; + case C2X_INS_SACL: + case C2X_INS_SACH: + case C2X_INS_SAR: + case C2X_INS_SST: + case C2X_INS_SST1: + case C2X_INS_SPL: + case C2X_INS_SPH: + case C2X_INS_POPD: + case C2X_INS_POP: + case C2X_INS_TBLW: + return RZ_ANALYSIS_OP_TYPE_STORE; + case C2X_INS_TBLR: + return RZ_ANALYSIS_OP_TYPE_LOAD; + case C2X_INS_IN: + case C2X_INS_OUT: + return RZ_ANALYSIS_OP_TYPE_IO; + case C2X_INS_B: + return RZ_ANALYSIS_OP_TYPE_JMP; + case C2X_INS_BACC: + return RZ_ANALYSIS_OP_TYPE_UJMP; + case C2X_INS_BV: + case C2X_INS_BGZ: + case C2X_INS_BLEZ: + case C2X_INS_BLZ: + case C2X_INS_BGEZ: + case C2X_INS_BNZ: + case C2X_INS_BZ: + case C2X_INS_BNV: + case C2X_INS_BBZ: + case C2X_INS_BBNZ: + case C2X_INS_BIOZ: + case C2X_INS_BANZ: + case C2X_INS_BC: + case C2X_INS_BNC: + return RZ_ANALYSIS_OP_TYPE_CJMP; + case C2X_INS_CALL: + return RZ_ANALYSIS_OP_TYPE_CALL; + case C2X_INS_CALA: + return RZ_ANALYSIS_OP_TYPE_UCALL; + case C2X_INS_RET: + return RZ_ANALYSIS_OP_TYPE_RET; + case C2X_INS_TRAP: + return RZ_ANALYSIS_OP_TYPE_TRAP; + default: + return RZ_ANALYSIS_OP_TYPE_NULL; + } +} + +// id -> mnemonic (indexed by the C2X_INS_* id; unset ids read back "invalid") +static const char *const c2x_mnemonics[] = { + [C2X_INS_NOP] = "nop", + [C2X_INS_ADD] = "add", + [C2X_INS_ADDH] = "addh", + [C2X_INS_ADDS] = "adds", + [C2X_INS_ADDT] = "addt", + [C2X_INS_ADDC] = "addc", + [C2X_INS_SUB] = "sub", + [C2X_INS_SUBH] = "subh", + [C2X_INS_SUBS] = "subs", + [C2X_INS_SUBT] = "subt", + [C2X_INS_SUBC] = "subc", + [C2X_INS_SUBB] = "subb", + [C2X_INS_LAC] = "lac", + [C2X_INS_LACT] = "lact", + [C2X_INS_LACK] = "lack", + [C2X_INS_ZAC] = "zac", + [C2X_INS_ZALH] = "zalh", + [C2X_INS_ZALS] = "zals", + [C2X_INS_ZALR] = "zalr", + [C2X_INS_ADDK] = "addk", + [C2X_INS_SUBK] = "subk", + [C2X_INS_ABS] = "abs", + [C2X_INS_NEG] = "neg", + [C2X_INS_CMPL] = "cmpl", + [C2X_INS_SFL] = "sfl", + [C2X_INS_SFR] = "sfr", + [C2X_INS_ROL] = "rol", + [C2X_INS_ROR] = "ror", + [C2X_INS_NORM] = "norm", + [C2X_INS_SACL] = "sacl", + [C2X_INS_SACH] = "sach", + [C2X_INS_PAC] = "pac", + [C2X_INS_APAC] = "apac", + [C2X_INS_SPAC] = "spac", + [C2X_INS_LPH] = "lph", + [C2X_INS_SPL] = "spl", + [C2X_INS_SPH] = "sph", + [C2X_INS_LAR] = "lar", + [C2X_INS_SAR] = "sar", + [C2X_INS_LARK] = "lark", + [C2X_INS_LARP] = "larp", + [C2X_INS_MAR] = "mar", + [C2X_INS_LDP] = "ldp", + [C2X_INS_LDPK] = "ldpk", + [C2X_INS_ADRK] = "adrk", + [C2X_INS_SBRK] = "sbrk", + [C2X_INS_LT] = "lt", + [C2X_INS_LTA] = "lta", + [C2X_INS_LTD] = "ltd", + [C2X_INS_LTP] = "ltp", + [C2X_INS_LTS] = "lts", + [C2X_INS_MPY] = "mpy", + [C2X_INS_MPYK] = "mpyk", + [C2X_INS_MPYA] = "mpya", + [C2X_INS_MPYS] = "mpys", + [C2X_INS_MPYU] = "mpyu", + [C2X_INS_SQRA] = "sqra", + [C2X_INS_SQRS] = "sqrs", + [C2X_INS_MAC] = "mac", + [C2X_INS_MACD] = "macd", + [C2X_INS_AND] = "and", + [C2X_INS_OR] = "or", + [C2X_INS_XOR] = "xor", + [C2X_INS_ANDK] = "andk", + [C2X_INS_ORK] = "ork", + [C2X_INS_XORK] = "xork", + [C2X_INS_LST] = "lst", + [C2X_INS_LST1] = "lst1", + [C2X_INS_SST] = "sst", + [C2X_INS_SST1] = "sst1", + [C2X_INS_LALK] = "lalk", + [C2X_INS_ADLK] = "adlk", + [C2X_INS_SBLK] = "sblk", + [C2X_INS_LRLK] = "lrlk", + [C2X_INS_RPT] = "rpt", + [C2X_INS_RPTK] = "rptk", + [C2X_INS_DMOV] = "dmov", + [C2X_INS_PSHD] = "pshd", + [C2X_INS_POPD] = "popd", + [C2X_INS_PUSH] = "push", + [C2X_INS_POP] = "pop", + [C2X_INS_BITT] = "bitt", + [C2X_INS_BIT] = "bit", + [C2X_INS_TBLR] = "tblr", + [C2X_INS_TBLW] = "tblw", + [C2X_INS_BLKD] = "blkd", + [C2X_INS_BLKP] = "blkp", + [C2X_INS_IN] = "in", + [C2X_INS_OUT] = "out", + [C2X_INS_B] = "b", + [C2X_INS_BACC] = "bacc", + [C2X_INS_CALA] = "cala", + [C2X_INS_CALL] = "call", + [C2X_INS_RET] = "ret", + [C2X_INS_BANZ] = "banz", + [C2X_INS_BV] = "bv", + [C2X_INS_BGZ] = "bgz", + [C2X_INS_BLEZ] = "blez", + [C2X_INS_BLZ] = "blz", + [C2X_INS_BGEZ] = "bgez", + [C2X_INS_BNZ] = "bnz", + [C2X_INS_BZ] = "bz", + [C2X_INS_BNV] = "bnv", + [C2X_INS_BBZ] = "bbz", + [C2X_INS_BBNZ] = "bbnz", + [C2X_INS_BIOZ] = "bioz", + [C2X_INS_BC] = "bc", + [C2X_INS_BNC] = "bnc", + [C2X_INS_TRAP] = "trap", + [C2X_INS_IDLE] = "idle", + [C2X_INS_EINT] = "eint", + [C2X_INS_DINT] = "dint", + [C2X_INS_ROVM] = "rovm", + [C2X_INS_SOVM] = "sovm", + [C2X_INS_CNFD] = "cnfd", + [C2X_INS_CNFP] = "cnfp", + [C2X_INS_RSXM] = "rsxm", + [C2X_INS_SSXM] = "ssxm", + [C2X_INS_SPM] = "spm", + [C2X_INS_RXF] = "rxf", + [C2X_INS_SXF] = "sxf", + [C2X_INS_FORT] = "fort", + [C2X_INS_RC] = "rc", + [C2X_INS_SC] = "sc", + [C2X_INS_RTC] = "rtc", + [C2X_INS_STC] = "stc", + [C2X_INS_RFSM] = "rfsm", + [C2X_INS_SFSM] = "sfsm", + [C2X_INS_RHM] = "rhm", + [C2X_INS_SHM] = "shm", + [C2X_INS_RTXM] = "rtxm", + [C2X_INS_STXM] = "stxm", + [C2X_INS_CMPR] = "cmpr", + [C2X_INS_CONF] = "conf", +}; + +RZ_IPI const char *c2x_mnemonic(ut16 id) { + if (id < RZ_ARRAY_SIZE(c2x_mnemonics) && c2x_mnemonics[id]) { + return c2x_mnemonics[id]; + } + return "invalid"; +} + +// descriptor + analysis entry + +const C55ArchDesc c2x_arch_desc = { + .arch = C55_ARCH_C2X, + .cpu_name = "c2x", + .table = c2x_table, + .table_len = sizeof(c2x_table) / sizeof(c2x_table[0]), + .insn_len = NULL, // every row carries a fixed .len + .reg_info = c2x_reg_info, + .mnemonic = c2x_mnemonic, + .op_type = c2x_op_type, + .lift = c2x_lift, + .mem = { .addr_unit_log2 = 0, .ptr_width = 16, .big_endian = true, .page_reg = "dp" }, + .ea = c2x_ea, + .fill_dual = NULL, + .words_le = false, // C2x words are stored MSB-first; no per-word swap + .cond_exec_prefix = false, + .parallel_prefix = false, +}; + +// Populate the data-flow analysis fields from the decoded operands so variable +// and argument analysis (and data-xref tracking) can inspect the instruction: +// the source/destination access values (op->src/op->dst) for register and memory +// operands, and op->ptr for direct (data-page-relative) data accesses. Shared by +// the C2x and C5x analysis paths, which use the same operand representation. The +// register/memory roles follow the load/store direction the shared filler has +// already resolved (a load's register operand is the destination; a store's +// memory operand is the destination), with the accumulator left implicit. +RZ_IPI void c2x_fill_op_access(RzAnalysis *analysis, const C55ArchDesc *a, + const C55Insn *insn, RzAnalysisOp *op) { + if (!analysis || !a || !insn || !op) { + return; + } + RzReg *reg = rz_analysis_get_reg(analysis); + // Resolve the memory role from the analysis op type: a store writes its + // memory operand, a load / accumulator-move reads it; everything else + // (arithmetic, logic, ...) reads its operands into the implicit + // accumulator. The shared filler's load/store direction targets the C54x + // operand layout, so set the read/write direction here for the C2x/C5x + // memory forms. + const bool is_store = op->type == RZ_ANALYSIS_OP_TYPE_STORE; + const bool is_load = op->type == RZ_ANALYSIS_OP_TYPE_LOAD || + op->type == RZ_ANALYSIS_OP_TYPE_MOV; + bool has_mem = false; + size_t srci = 0; + for (ut8 i = 0; i < insn->n_ops; i++) { + const C55Operand *o = &insn->ops[i]; + if (o->kind == C55_OP_MEM) { + has_mem = true; + RzAnalysisValue *v = rz_analysis_value_new(); + if (!v) { + continue; + } + v->type = RZ_ANALYSIS_VAL_MEM; + v->memref = (o->access ? o->access : 16) / 8; + if (o->amode == C55_AM_DIRECT) { + // Direct addressing: the 7-bit field is the data offset within + // the current data page; expose it as the access pointer. + v->base = (ut64)(o->disp & 0x7f); + op->ptr = v->base; + op->ptrsize = v->memref; + } else if (a->reg_info) { + const C55RegInfo *bri = a->reg_info(o->reg.cls, o->reg.num, C55_SUB_NONE); + if (bri) { + v->reg = rz_reg_get(reg, bri->name, RZ_REG_TYPE_ANY); + } + } + if (is_store && !op->dst) { + op->dst = v; + } else if (srci < RZ_ARRAY_SIZE(op->src)) { + op->src[srci++] = v; + } else { + rz_analysis_value_free(v); + } + } else if (o->kind == C55_OP_REG && a->reg_info) { + const C55RegInfo *ri = a->reg_info(o->reg.cls, o->reg.num, o->reg.sub); + if (!ri) { + continue; + } + RzAnalysisValue *v = rz_analysis_value_new(); + if (!v) { + continue; + } + v->type = RZ_ANALYSIS_VAL_REG; + v->reg = rz_reg_get(reg, ri->name, RZ_REG_TYPE_ANY); + if (is_load && !op->dst) { + op->dst = v; + } else if (srci < RZ_ARRAY_SIZE(op->src)) { + op->src[srci++] = v; + } else { + rz_analysis_value_free(v); + } + } else if (o->kind == C55_OP_IMM && srci < RZ_ARRAY_SIZE(op->src)) { + RzAnalysisValue *v = rz_analysis_value_new(); + if (!v) { + continue; + } + v->type = RZ_ANALYSIS_VAL_IMM; + v->imm = (st64)o->imm; + op->src[srci++] = v; + } + } + if (has_mem) { + if (is_store) { + op->direction = RZ_ANALYSIS_OP_DIR_WRITE; + } else if (is_load || op->direction == 0) { + op->direction = RZ_ANALYSIS_OP_DIR_READ; + } + } +} + +RZ_IPI int tms320_c2x_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr, + const ut8 *buf, int len, RzAnalysisOpMask mask) { + if (!op || !buf || len < 1) { + return 0; + } + op->addr = addr; + op->type = RZ_ANALYSIS_OP_TYPE_NULL; + C55Insn ci; + if (c55_decode(&c2x_arch_desc, buf, len, &ci)) { + c55_fill_analysis(&c2x_arch_desc, &ci, op); + c2x_fill_op_access(analysis, &c2x_arch_desc, &ci, op); + if (mask & RZ_ANALYSIS_OP_MASK_IL) { + op->il_op = c55_lift(&c2x_arch_desc, &ci, op->addr); + } + } else { + // Undecodable word: flag it and give a one-word fallback size, but + // report the failure to the caller with -1 (the common plugin convention). + op->type = RZ_ANALYSIS_OP_TYPE_ILL; + op->size = 1; + return -1; + } + return op->size; +} + +/* + * Complete TMS320C2x encoding map (for extending c2x_table). Bit legend: + * A 7-bit direct dma | M 3-bit AR-modify | N 4-bit next-ARP | T 4-bit shift + * S 3-bit shift | R 3-bit AR# | P 4-bit port | D 8-bit imm | K small imm + * W 16-bit imm (next word) | C 2-bit compare | B 16-bit branch target (word) + * + * 0xxx ADD A,T / M,T,N 40xx ZALH 50xx LST 78xx SST 8xxx IN A,P + * 1xxx SUB 41xx ZALS 51xx LST1 79xx SST1 9xxx BIT A,T + * 2xxx LAC 42xx LACT 52xx LDP 7Axx POPD Axx-Bxx MPYK W + * 3xxx LAR R,A 43xx ADDC 53xx LPH 7Bxx ZALR Cxxx LARK R,D + * 38xx MPY 3Cxx LT 44xx SUBH 54xx PSHD 7Cxx SPL C8xx LDPK K + * 39xx SQRA 3Dxx LTA 45xx SUBS 55xx MAR/NOP 7Dxx SPH CAxx LACK (CA00=ZAC) + * 3Axx MPYA 3Exx LTP 46xx SUBT 56xx DMOV 7Exx ADRK CBxx RPTK + * 3Bxx MPYS 3Fxx LTD 47xx SUBC 57xx BITT 7Fxx SBRK CCxx ADDK + * 48xx ADDH 58xx TBLR CDxx SUBK + * 49xx ADDS 59xx TBLW 5Cxx MACD B,* CExx (no-op block) + * 4Axx ADDT 5Axx SQRS 5Dxx MAC B,* CFxx MPYS + * 4Bxx RPT 5Bxx LTS 5Exx BC B Dx00 LRLK R,W + * 4Cxx XOR 5Fxx BNC B Dx01 LALK W,T + * 4Dxx OR 60xx SACL S Dx02 ADLK + * 4Exx AND 68xx SACH S Exxx OUT A,P Dx03 SBLK + * 4Fxx SUBB 70xx SAR R,A Dx04 ANDK + * Dx05 ORK + * CE block (exact): CE00 EINT CE01 DINT CE02 ROVM CE03 SOVM CE04 CNFD Dx06 XORK + * CE05 CNFP CE06 RSXM CE07 SSXM CE08-B SPM K CE0C RXF CE0D SXF + * CE0E-F FORT K CE14 PAC CE15 APAC CE16 SPAC CE18 SFL CE19 SFR CE1B ABS + * CE1C PUSH CE1D POP CE1E TRAP CE1F IDLE CE20 RTXM CE21 STXM CE23 NEG + * CE24 CALA CE25 BACC CE26 RET CE27 CMPL CE30 RC CE31 SC CE32 RTC CE33 STC + * CE34 ROL CE35 ROR CE36 RFSM CE37 SFSM CE38 RHM CE39 SHM CE3C-F CONF K + * CE50-3 CMPR C CEx2 (110011101mmm0010) NORM M + * F-block branches (opcode + B word + addressing byte, bit7=1): F0 BV F1 BGZ + * F2 BLEZ F3 BLZ F4 BGEZ F5 BNZ F6 BZ F7 BNV (F8 BBZ F9 BBNZ FA BIOZ + * FB BANZ FE CALL FF B are the conventional assignments; verify the tail). + * BLKD/BLKP are the block-move forms (opcode + source-address word). + */ diff --git a/librz/arch/isa/tms320/c2x/c2x.h b/librz/arch/isa/tms320/c2x/c2x.h new file mode 100644 index 00000000000..91899f008af --- /dev/null +++ b/librz/arch/isa/tms320/c2x/c2x.h @@ -0,0 +1,219 @@ +// SPDX-FileCopyrightText: 2026 RizinOrg +// SPDX-License-Identifier: LGPL-3.0-only + +#ifndef RZ_TMS320_C2X_H +#define RZ_TMS320_C2X_H + +#include "../c55_ir.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \file + * TMS320C2x (legacy, e.g. TMS320C25) disassembly + RzIL, plugged into the + * shared C55 decode engine. The C2x is a 16-bit word-addressed fixed-point DSP + * with a single 32-bit accumulator (ACC) plus carry, a 16-bit temporary T, a + * 32-bit product register P (with a programmable product shifter PM), eight + * 16-bit auxiliary registers AR0..7 selected by the 3-bit ARP, a 9-bit data + * page pointer DP, and ST0/ST1 status words. Program/data addresses are 16-bit. + * + * Encodings are taken from the public TMS320C2x instruction set (the opcode bit + * patterns match MAME's tested TMS320x25 disassembler). Instruction words are + * stored MSB-first (big-endian), so the engine's words_le swap is NOT used: the + * leading byte already carries the opcode field that the table matches on. + */ + +/// TMS320C2x instruction identifiers (the C55Insn.id / RzAnalysisOp.id values). +enum { + C2X_INS_INVALID = 0, + C2X_INS_NOP, + // accumulator arithmetic + C2X_INS_ADD, + C2X_INS_ADDH, + C2X_INS_ADDS, + C2X_INS_ADDT, + C2X_INS_ADDC, + C2X_INS_SUB, + C2X_INS_SUBH, + C2X_INS_SUBS, + C2X_INS_SUBT, + C2X_INS_SUBC, + C2X_INS_SUBB, + C2X_INS_LAC, + C2X_INS_LACT, + C2X_INS_LACK, + C2X_INS_ZAC, + C2X_INS_ZALH, + C2X_INS_ZALS, + C2X_INS_ZALR, + C2X_INS_ADDK, + C2X_INS_SUBK, + C2X_INS_ABS, + C2X_INS_NEG, + C2X_INS_CMPL, + C2X_INS_SFL, + C2X_INS_SFR, + C2X_INS_ROL, + C2X_INS_ROR, + C2X_INS_NORM, + // store / load accumulator parts + C2X_INS_SACL, + C2X_INS_SACH, + C2X_INS_PAC, + C2X_INS_APAC, + C2X_INS_SPAC, + C2X_INS_LPH, + C2X_INS_SPL, + C2X_INS_SPH, + // auxiliary registers / pointers + C2X_INS_LAR, + C2X_INS_SAR, + C2X_INS_LARK, + C2X_INS_LARP, + C2X_INS_MAR, + C2X_INS_LDP, + C2X_INS_LDPK, + C2X_INS_ADRK, + C2X_INS_SBRK, + // T / P register and multiply + C2X_INS_LT, + C2X_INS_LTA, + C2X_INS_LTD, + C2X_INS_LTP, + C2X_INS_LTS, + C2X_INS_MPY, + C2X_INS_MPYK, + C2X_INS_MPYA, + C2X_INS_MPYS, + C2X_INS_MPYU, + C2X_INS_SQRA, + C2X_INS_SQRS, + C2X_INS_MAC, + C2X_INS_MACD, + // logical + C2X_INS_AND, + C2X_INS_OR, + C2X_INS_XOR, + C2X_INS_ANDK, + C2X_INS_ORK, + C2X_INS_XORK, + // status / long immediate + C2X_INS_LST, + C2X_INS_LST1, + C2X_INS_SST, + C2X_INS_SST1, + C2X_INS_LALK, + C2X_INS_ADLK, + C2X_INS_SBLK, + C2X_INS_LRLK, + C2X_INS_RPT, + C2X_INS_RPTK, + // memory move / table / IO + C2X_INS_DMOV, + C2X_INS_PSHD, + C2X_INS_POPD, + C2X_INS_PUSH, + C2X_INS_POP, + C2X_INS_BITT, + C2X_INS_BIT, + C2X_INS_TBLR, + C2X_INS_TBLW, + C2X_INS_BLKD, + C2X_INS_BLKP, + C2X_INS_IN, + C2X_INS_OUT, + // control flow + C2X_INS_B, + C2X_INS_BACC, + C2X_INS_CALA, + C2X_INS_CALL, + C2X_INS_RET, + C2X_INS_BANZ, + C2X_INS_BV, + C2X_INS_BGZ, + C2X_INS_BLEZ, + C2X_INS_BLZ, + C2X_INS_BGEZ, + C2X_INS_BNZ, + C2X_INS_BZ, + C2X_INS_BNV, + C2X_INS_BBZ, + C2X_INS_BBNZ, + C2X_INS_BIOZ, + C2X_INS_BC, + C2X_INS_BNC, + C2X_INS_TRAP, + C2X_INS_IDLE, + // status-bit / mode controls (CE block) + C2X_INS_EINT, + C2X_INS_DINT, + C2X_INS_ROVM, + C2X_INS_SOVM, + C2X_INS_CNFD, + C2X_INS_CNFP, + C2X_INS_RSXM, + C2X_INS_SSXM, + C2X_INS_SPM, + C2X_INS_RXF, + C2X_INS_SXF, + C2X_INS_FORT, + C2X_INS_RC, + C2X_INS_SC, + C2X_INS_RTC, + C2X_INS_STC, + C2X_INS_RFSM, + C2X_INS_SFSM, + C2X_INS_RHM, + C2X_INS_SHM, + C2X_INS_RTXM, + C2X_INS_STXM, + C2X_INS_CMPR, + C2X_INS_CONF, +}; + +// Legacy C2x/C5x memory model (shared by both cores). The data/program space +// is word-addressed, but the RzIL VM memory is byte-addressed, so a word +// address scales to a byte address by C2X_WORD_BYTES. C2X_MEM_ADDR_BITS is the +// width of that byte-address space (the il_config mem_key_size): 24 bits leave +// room for a 16-bit word address to scale x2 without wrapping. +#define C2X_WORD_BYTES 2 +#define C2X_MEM_ADDR_BITS 24 + +/// TMS320C2x disassembly, plugged into the shared C55 decode engine. +extern const C55ArchDesc c2x_arch_desc; + +// Shared decode-table pieces, reused by the C5x superset (c5x/c5x.c). The +// operand extractors are referenced by the row macros in c2x_rowdefs.h; the +// resolver/classifier/mnemonic helpers are reused (and extended) by C5x. +RZ_IPI void c2x_x_mem(const C55ArchDesc *a, ut64 bits, const C55OpDesc *d, C55Operand *out); +RZ_IPI void c2x_x_nextarp(const C55ArchDesc *a, ut64 bits, const C55OpDesc *d, C55Operand *out); +RZ_IPI void c2x_x_shift(const C55ArchDesc *a, ut64 bits, const C55OpDesc *d, C55Operand *out); +RZ_IPI void c2x_x_reg(const C55ArchDesc *a, ut64 bits, const C55OpDesc *d, C55Operand *out); +RZ_IPI void c2x_x_imm(const C55ArchDesc *a, ut64 bits, const C55OpDesc *d, C55Operand *out); +RZ_IPI void c2x_x_branch(const C55ArchDesc *a, ut64 bits, const C55OpDesc *d, C55Operand *out); +RZ_IPI const C55RegInfo *c2x_reg_info(C55RegClass cls, ut8 num, C55SubReg sub); +RZ_IPI ut32 c2x_op_type(ut16 id); +RZ_IPI const char *c2x_mnemonic(ut16 id); + +/// Analysis entry point: decode once, fill the RzAnalysisOp. +RZ_IPI int tms320_c2x_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr, + const ut8 *buf, int len, RzAnalysisOpMask mask); +RZ_IPI void c2x_fill_op_access(RzAnalysis *analysis, const C55ArchDesc *a, const C55Insn *insn, RzAnalysisOp *op); + +/// RzIL VM configuration (register bindings) for the C2x core. +RZ_IPI RzAnalysisILConfig *tms320_c2x_il_config(RZ_NONNULL RzAnalysis *analysis); + +/// Per-instruction RzIL lifter wired into \ref c2x_arch_desc (defined in c2x_il.c). +RZ_IPI RzILOpEffect *c2x_lift(const C55Insn *insn, ut64 pc); + +/// Arch-specific effective-address hook for C2x DP-direct addressing (defined in c2x_il.c). +RZ_IPI RzILOpPure *c2x_ea(const C55ArchDesc *a, const C55Operand *m); + +#ifdef __cplusplus +} +#endif + +#endif /* RZ_TMS320_C2X_H */ diff --git a/librz/arch/isa/tms320/c2x/c2x_core_rows.inc b/librz/arch/isa/tms320/c2x/c2x_core_rows.inc new file mode 100644 index 00000000000..610c801f319 --- /dev/null +++ b/librz/arch/isa/tms320/c2x/c2x_core_rows.inc @@ -0,0 +1,154 @@ +// SPDX-FileCopyrightText: 2026 RizinOrg +// SPDX-License-Identifier: LGPL-3.0-only + +// clang-format off + // TMS320C2x core instruction rows (shared with the C5x superset) + // top-nibble arithmetic with 4-bit shift: ADD / SUB / LAC + { OP(0xf080, 0x0000), .id = C2X_INS_ADD, .len = 2, .ops = { MEM(0), SHF(8, 4) } }, + { OP(0xf080, 0x0080), .id = C2X_INS_ADD, .len = 2, .ops = { MEM(0), SHF(8, 4), NARP(0) } }, + { OP(0xf080, 0x1000), .id = C2X_INS_SUB, .len = 2, .ops = { MEM(0), SHF(8, 4) } }, + { OP(0xf080, 0x1080), .id = C2X_INS_SUB, .len = 2, .ops = { MEM(0), SHF(8, 4), NARP(0) } }, + { OP(0xf080, 0x2000), .id = C2X_INS_LAC, .len = 2, .ops = { MEM(0), SHF(8, 4) } }, + { OP(0xf080, 0x2080), .id = C2X_INS_LAC, .len = 2, .ops = { MEM(0), SHF(8, 4), NARP(0) } }, + + // LAR / SAR: 5-bit opcode (00110rrr / 01110rrr) + R + { OP(0xf880, 0x3000), .id = C2X_INS_LAR, .len = 2, .ops = { AR(8), MEM(0) } }, + { OP(0xf880, 0x3080), .id = C2X_INS_LAR, .len = 2, .ops = { AR(8), MEM(0), NARP(0) } }, + { OP(0xf880, 0x7000), .id = C2X_INS_SAR, .len = 2, .ops = { AR(8), MEM(0) } }, + { OP(0xf880, 0x7080), .id = C2X_INS_SAR, .len = 2, .ops = { AR(8), MEM(0), NARP(0) } }, + + // single-byte-opcode memory block 0x38..0x5B: multiply / T-P / logical / move + MEMOP_D(0x38, C2X_INS_MPY), MEMOP_I(0x38, C2X_INS_MPY), + MEMOP_D(0x39, C2X_INS_SQRA), MEMOP_I(0x39, C2X_INS_SQRA), + MEMOP_D(0x3a, C2X_INS_MPYA), MEMOP_I(0x3a, C2X_INS_MPYA), + MEMOP_D(0x3b, C2X_INS_MPYS), MEMOP_I(0x3b, C2X_INS_MPYS), + MEMOP_D(0x3c, C2X_INS_LT), MEMOP_I(0x3c, C2X_INS_LT), + MEMOP_D(0x3d, C2X_INS_LTA), MEMOP_I(0x3d, C2X_INS_LTA), + MEMOP_D(0x3e, C2X_INS_LTP), MEMOP_I(0x3e, C2X_INS_LTP), + MEMOP_D(0x3f, C2X_INS_LTD), MEMOP_I(0x3f, C2X_INS_LTD), + MEMOP_D(0x40, C2X_INS_ZALH), MEMOP_I(0x40, C2X_INS_ZALH), + MEMOP_D(0x41, C2X_INS_ZALS), MEMOP_I(0x41, C2X_INS_ZALS), + MEMOP_D(0x42, C2X_INS_LACT), MEMOP_I(0x42, C2X_INS_LACT), + MEMOP_D(0x43, C2X_INS_ADDC), MEMOP_I(0x43, C2X_INS_ADDC), + MEMOP_D(0x44, C2X_INS_SUBH), MEMOP_I(0x44, C2X_INS_SUBH), + MEMOP_D(0x45, C2X_INS_SUBS), MEMOP_I(0x45, C2X_INS_SUBS), + MEMOP_D(0x46, C2X_INS_SUBT), MEMOP_I(0x46, C2X_INS_SUBT), + MEMOP_D(0x47, C2X_INS_SUBC), MEMOP_I(0x47, C2X_INS_SUBC), + MEMOP_D(0x48, C2X_INS_ADDH), MEMOP_I(0x48, C2X_INS_ADDH), + MEMOP_D(0x49, C2X_INS_ADDS), MEMOP_I(0x49, C2X_INS_ADDS), + MEMOP_D(0x4a, C2X_INS_ADDT), MEMOP_I(0x4a, C2X_INS_ADDT), + MEMOP_D(0x4b, C2X_INS_RPT), MEMOP_I(0x4b, C2X_INS_RPT), + MEMOP_D(0x4c, C2X_INS_XOR), MEMOP_I(0x4c, C2X_INS_XOR), + MEMOP_D(0x4d, C2X_INS_OR), MEMOP_I(0x4d, C2X_INS_OR), + MEMOP_D(0x4e, C2X_INS_AND), MEMOP_I(0x4e, C2X_INS_AND), + MEMOP_D(0x4f, C2X_INS_SUBB), MEMOP_I(0x4f, C2X_INS_SUBB), + MEMOP_D(0x50, C2X_INS_LST), MEMOP_I(0x50, C2X_INS_LST), + MEMOP_D(0x51, C2X_INS_LST1), MEMOP_I(0x51, C2X_INS_LST1), + MEMOP_D(0x52, C2X_INS_LDP), MEMOP_I(0x52, C2X_INS_LDP), + MEMOP_D(0x53, C2X_INS_LPH), MEMOP_I(0x53, C2X_INS_LPH), + MEMOP_D(0x54, C2X_INS_PSHD), MEMOP_I(0x54, C2X_INS_PSHD), + MEMOP_D(0x56, C2X_INS_DMOV), MEMOP_I(0x56, C2X_INS_DMOV), + MEMOP_D(0x57, C2X_INS_BITT), MEMOP_I(0x57, C2X_INS_BITT), + MEMOP_D(0x58, C2X_INS_TBLR), MEMOP_I(0x58, C2X_INS_TBLR), + MEMOP_D(0x59, C2X_INS_TBLW), MEMOP_I(0x59, C2X_INS_TBLW), + MEMOP_D(0x5a, C2X_INS_SQRS), MEMOP_I(0x5a, C2X_INS_SQRS), + MEMOP_D(0x5b, C2X_INS_LTS), MEMOP_I(0x5b, C2X_INS_LTS), + + // 0x5C/0x5D: multiply-accumulate with program memory (2-word, %B = pma) + PMAOP_D(0x5c, C2X_INS_MACD), PMAOP_I(0x5c, C2X_INS_MACD), + PMAOP_D(0x5d, C2X_INS_MAC), PMAOP_I(0x5d, C2X_INS_MAC), + + // store accumulator low/high with 3-bit shift (%S) + { OP(0xf880, 0x6000), .id = C2X_INS_SACL, .len = 2, .ops = { MEM(0), SHF(8, 3) } }, + { OP(0xf880, 0x6080), .id = C2X_INS_SACL, .len = 2, .ops = { MEM(0), SHF(8, 3), NARP(0) } }, + { OP(0xf880, 0x6800), .id = C2X_INS_SACH, .len = 2, .ops = { MEM(0), SHF(8, 3) } }, + { OP(0xf880, 0x6880), .id = C2X_INS_SACH, .len = 2, .ops = { MEM(0), SHF(8, 3), NARP(0) } }, + + // 0x78..0x7D single-byte-opcode block: store status / stack + MEMOP_D(0x78, C2X_INS_SST), MEMOP_I(0x78, C2X_INS_SST), + MEMOP_D(0x79, C2X_INS_SST1), MEMOP_I(0x79, C2X_INS_SST1), + MEMOP_D(0x7a, C2X_INS_POPD), MEMOP_I(0x7a, C2X_INS_POPD), + MEMOP_D(0x7b, C2X_INS_ZALR), MEMOP_I(0x7b, C2X_INS_ZALR), + MEMOP_D(0x7c, C2X_INS_SPL), MEMOP_I(0x7c, C2X_INS_SPL), + MEMOP_D(0x7d, C2X_INS_SPH), MEMOP_I(0x7d, C2X_INS_SPH), + + // ADRK / SBRK: add/subtract short immediate (full low byte) to/from AR(ARP) + { OP(0xff00, 0x7e00), .id = C2X_INS_ADRK, .len = 2, .ops = { IMM(0, 8, 0) } }, + { OP(0xff00, 0x7f00), .id = C2X_INS_SBRK, .len = 2, .ops = { IMM(0, 8, 0) } }, + + // IN / OUT: 4-bit port (%P) in bits 11-8 + { OP(0xf080, 0x8000), .id = C2X_INS_IN, .len = 2, .ops = { MEM(0), IMM(8, 4, 0) } }, + { OP(0xf080, 0x8080), .id = C2X_INS_IN, .len = 2, .ops = { MEM(0), IMM(8, 4, 0), NARP(0) } }, + { OP(0xf080, 0xe000), .id = C2X_INS_OUT, .len = 2, .ops = { MEM(0), IMM(8, 4, 0) } }, + { OP(0xf080, 0xe080), .id = C2X_INS_OUT, .len = 2, .ops = { MEM(0), IMM(8, 4, 0), NARP(0) } }, + + // BIT: 4-bit bit-code (%T) in bits 11-8 + { OP(0xf080, 0x9000), .id = C2X_INS_BIT, .len = 2, .ops = { MEM(0), SHF(8, 4) } }, + { OP(0xf080, 0x9080), .id = C2X_INS_BIT, .len = 2, .ops = { MEM(0), SHF(8, 4), NARP(0) } }, + + // immediate-operand instructions + { OP(0xe000, 0xa000), .id = C2X_INS_MPYK, .len = 2, .ops = { IMM(0, 13, 1) } }, + { OP(0xf800, 0xc000), .id = C2X_INS_LARK, .len = 2, .ops = { AR(8), IMM(0, 8, 0) } }, + { OP(0xfe00, 0xc800), .id = C2X_INS_LDPK, .len = 2, .ops = { IMM(0, 9, 0) } }, + { FIX(0xca00, C2X_INS_ZAC) }, // LACK #0 == ZAC (specific row before the range) + { OP(0xff00, 0xca00), .id = C2X_INS_LACK, .len = 2, .ops = { IMM(0, 8, 0) } }, + { OP(0xff00, 0xcb00), .id = C2X_INS_RPTK, .len = 2, .ops = { IMM(0, 8, 0) } }, + // NORM is CEx2 with the indirect AR-modify field in bits 6:4 (always indirect). + { OP(0xff8f, 0xce82), .id = C2X_INS_NORM, .len = 2, .ops = { MEM(0) } }, + { OP(0xff00, 0xcc00), .id = C2X_INS_ADDK, .len = 2, .ops = { IMM(0, 8, 0) } }, + { OP(0xff00, 0xcd00), .id = C2X_INS_SUBK, .len = 2, .ops = { IMM(0, 8, 0) } }, + + // 0xCF is MPYU (multiply unsigned). The MAME *disassembler* table mislabels + // it as a second "mpys", but the MAME execution table (and the TI ISA) run + // MPYU here; we follow the architecturally-correct mnemonic. + MEMOP_D(0xcf, C2X_INS_MPYU), MEMOP_I(0xcf, C2X_INS_MPYU), + + // CE block: no-operand status / mode / control + { FIX(0xce00, C2X_INS_EINT) }, { FIX(0xce01, C2X_INS_DINT) }, + { FIX(0xce02, C2X_INS_ROVM) }, { FIX(0xce03, C2X_INS_SOVM) }, + { FIX(0xce04, C2X_INS_CNFD) }, { FIX(0xce05, C2X_INS_CNFP) }, + { FIX(0xce06, C2X_INS_RSXM) }, { FIX(0xce07, C2X_INS_SSXM) }, + { OP(0xfffc, 0xce08), .id = C2X_INS_SPM, .len = 2, .ops = { IMM(0, 2, 0) } }, + { FIX(0xce0c, C2X_INS_RXF) }, { FIX(0xce0d, C2X_INS_SXF) }, + { FIX(0xce14, C2X_INS_PAC) }, { FIX(0xce15, C2X_INS_APAC) }, { FIX(0xce16, C2X_INS_SPAC) }, + { FIX(0xce18, C2X_INS_SFL) }, { FIX(0xce19, C2X_INS_SFR) }, + { FIX(0xce1b, C2X_INS_ABS) }, { FIX(0xce1c, C2X_INS_PUSH) }, { FIX(0xce1d, C2X_INS_POP) }, + { FIX(0xce1e, C2X_INS_TRAP) }, { FIX(0xce1f, C2X_INS_IDLE) }, + { FIX(0xce20, C2X_INS_RTXM) }, { FIX(0xce21, C2X_INS_STXM) }, + { FIX(0xce23, C2X_INS_NEG) }, { FIX(0xce24, C2X_INS_CALA) }, { FIX(0xce25, C2X_INS_BACC) }, + { FIX(0xce26, C2X_INS_RET) }, { FIX(0xce27, C2X_INS_CMPL) }, + { FIX(0xce30, C2X_INS_RC) }, { FIX(0xce31, C2X_INS_SC) }, + { FIX(0xce32, C2X_INS_RTC) }, { FIX(0xce33, C2X_INS_STC) }, + { FIX(0xce34, C2X_INS_ROL) }, { FIX(0xce35, C2X_INS_ROR) }, + { FIX(0xce36, C2X_INS_RFSM) }, { FIX(0xce37, C2X_INS_SFSM) }, + { FIX(0xce38, C2X_INS_RHM) }, { FIX(0xce39, C2X_INS_SHM) }, + // CONF K (TMS320C26): two low bits select the RAM block configuration (ST1.CNF) + { OP(0xfffc, 0xce3c), .id = C2X_INS_CONF, .len = 2, .ops = { IMM(0, 2, 0) } }, + { OP(0xfffc, 0xce50), .id = C2X_INS_CMPR, .len = 2, .ops = { IMM(0, 2, 0) } }, + + // D block: long-immediate (opcode word + 16-bit data word) + { OP(0xf8ff, 0xd000), .id = C2X_INS_LRLK, .len = 4, .ops = { AR(24), IMM(0, 16, 0) } }, + { OP(0xf0ff, 0xd001), .id = C2X_INS_LALK, .len = 4, .ops = { IMM(0, 16, 0), SHF(24, 4) } }, + { OP(0xf0ff, 0xd002), .id = C2X_INS_ADLK, .len = 4, .ops = { IMM(0, 16, 0), SHF(24, 4) } }, + { OP(0xf0ff, 0xd003), .id = C2X_INS_SBLK, .len = 4, .ops = { IMM(0, 16, 0), SHF(24, 4) } }, + { OP(0xf0ff, 0xd004), .id = C2X_INS_ANDK, .len = 4, .ops = { IMM(0, 16, 0), SHF(24, 4) } }, + { OP(0xf0ff, 0xd005), .id = C2X_INS_ORK, .len = 4, .ops = { IMM(0, 16, 0), SHF(24, 4) } }, + { OP(0xf0ff, 0xd006), .id = C2X_INS_XORK, .len = 4, .ops = { IMM(0, 16, 0), SHF(24, 4) } }, + + // control transfer (opcode word + 16-bit target word). BC/BNC confirmed at + // 0x5E/0x5F; the F-block follows the same opcode-byte + bit7 pattern. + BROP(0x5e, C2X_INS_BC), BROP(0x5f, C2X_INS_BNC), + BROP(0xf0, C2X_INS_BV), BROP(0xf1, C2X_INS_BGZ), BROP(0xf2, C2X_INS_BLEZ), + BROP(0xf3, C2X_INS_BLZ), BROP(0xf4, C2X_INS_BGEZ), BROP(0xf5, C2X_INS_BNZ), + BROP(0xf6, C2X_INS_BZ), BROP(0xf7, C2X_INS_BNV), BROP(0xf8, C2X_INS_BBZ), + BROP(0xf9, C2X_INS_BBNZ), BROP(0xfa, C2X_INS_BIOZ), BANZOP(0xfb, C2X_INS_BANZ), + // 0xFC/0xFD: block move from program/data memory (2-word, %B = source addr) + PMAOP_D(0xfc, C2X_INS_BLKP), PMAOP_I(0xfc, C2X_INS_BLKP), + PMAOP_D(0xfd, C2X_INS_BLKD), PMAOP_I(0xfd, C2X_INS_BLKD), + BROP(0xfe, C2X_INS_CALL), BROP(0xff, C2X_INS_B), + + // AR-pointer / nop (specific rows before the general MAR indirect row) + { FIX(0x5500, C2X_INS_NOP) }, + { OP(0xfff8, 0x5588), .id = C2X_INS_LARP, .len = 2, .ops = { IMM(0, 3, 0) } }, + { OP(0xff80, 0x5580), .id = C2X_INS_MAR, .len = 2, .ops = { MEM(0), NARP(0) } }, + // clang-format on diff --git a/librz/arch/isa/tms320/c2x/c2x_il.c b/librz/arch/isa/tms320/c2x/c2x_il.c new file mode 100644 index 00000000000..1bbc04dfd39 --- /dev/null +++ b/librz/arch/isa/tms320/c2x/c2x_il.c @@ -0,0 +1,688 @@ +// SPDX-FileCopyrightText: 2026 RizinOrg +// SPDX-License-Identifier: LGPL-3.0-only + +/** + * \file + * RzIL lifter and VM configuration for the TMS320C2x core. + * + * Register model: a 32-bit accumulator ACC, a 16-bit temporary T, a 32-bit + * product register P, eight 16-bit auxiliary registers AR0..7, a 9-bit data + * page DP, the 3-bit ARP pointer, ST0/ST1 status words, a 16-bit PC, a + * synthetic stack pointer SP and the live status bits carry (C), overflow (OV), + * test/control (TC) plus the OVM/SXM/PM mode bits. + * + * Addressing: both DP-direct and the ARP-relative indirect modes are lifted. + * Indirect reads/writes resolve AR[ARP] with an 8-way ITE over ARP, and the + * post-modify (*+, *-, *0+, *0-) writes the selected AR back conditionally; the + * reverse-carry (*BR0+/-) modes resolve the address but leave AR unmodified. + * + * Flags: ADD/SUB-family carry and overflow follow the silicon (MAME) exactly, + * including the OVM saturation of ACC and the sticky OV that the BV/BNV branches + * consume. The hardware stack is internal (not memory-mapped); push/pop/call/ + * ret model it through SP into the data space so values round-trip. + */ + +#include "c2x.h" +#include + +static const char *const c2x_ar[8] = { + "ar0", "ar1", "ar2", "ar3", "ar4", "ar5", "ar6", "ar7" +}; + +// addressing + +// AR[ARP] resolved at run time via an 8-way select over ARP (16-bit value). +static RzILOpPure *c2x_ind_addr(void) { + RzILOpPure *v = VARG("ar7"); + int k; + for (k = 6; k >= 0; k--) { + v = ITE(EQ(VARG("arp"), UN(16, (ut32)k)), VARG(c2x_ar[k]), v); + } + return v; +} + +// Effective address for a memory operand: DP-direct => (DP[8:0]<<7)|dma7; +// any indirect mode => AR[ARP]. The data space is word-addressed. +static RzILOpPure *c2x_addr(const C55Operand *m) { + if (m->amode == C55_AM_DIRECT) { + RzILOpPure *page = SHIFTL0(LOGAND(VARG("dp"), UN(16, 0x1ff)), UN(16, 7)); + return LOGOR(page, UN(16, (ut32)m->disp & 0x7f)); + } + return c2x_ind_addr(); +} + +// Public effective-address hook used by the shared engine for direct forms. +// Returns the *word* address (the analysis/CFG convention for this arch). +RZ_IPI RzILOpPure *c2x_ea(RZ_UNUSED const C55ArchDesc *a, const C55Operand *m) { + if (m->amode != C55_AM_DIRECT) { + return NULL; + } + return c2x_addr(m); +} + +// The IL VM memory is byte-addressed while the C2x is word-addressed: one data +// word spans C2X_WORD_BYTES byte-address units, so a word address scales to a +// byte address by that factor (matching the C54x lifter's C54X_WORD_BYTES). +// AR/DP/SP keep word values; only the byte at which a word is read/written is +// scaled. The scaling is done in the C2X_MEM_ADDR_BITS-wide address space. +static RzILOpPure *c2x_byte(RzILOpPure *word_addr) { + return MUL(UNSIGNED(C2X_MEM_ADDR_BITS, word_addr), UN(C2X_MEM_ADDR_BITS, C2X_WORD_BYTES)); +} + +static RzILOpPure *c2x_mem_read(const C55Operand *m) { + return LOADW(16, c2x_byte(c2x_addr(m))); +} + +static RzILOpEffect *c2x_mem_write(const C55Operand *m, RzILOpPure *val) { + return STOREW(c2x_byte(c2x_addr(m)), val); +} + +// SST/SST1 use a special direct form: the 7-bit offset addresses data page 0 +// (DP is ignored). Indirect forms use AR[ARP] as usual. +static RzILOpPure *c2x_sst_addr(const C55Operand *m) { + if (m->amode == C55_AM_DIRECT) { + return UN(16, (ut32)m->disp & 0x7f); + } + return c2x_ind_addr(); +} + +// Read one program-memory word at a constant word address (program and data +// share the IL byte-address space; the word scales x2). +static RzILOpPure *c2x_prog_read(ut16 pma) { + return LOADW(16, c2x_byte(UN(16, pma))); +} + +// AR post-modification (and next-ARP reload) encoded by an indirect operand. +// Returns NULL when there is nothing to do (direct, or *no-modify). +// The AR post-modify only (no next-ARP load); used by the status load/store +// instructions, whose addressing ignores the next-ARP field (IgnoreARPHack). +static RzILOpEffect *c2x_ar_post(const C55Insn *insn, ut8 memidx) { + if (memidx >= insn->n_ops) { + return NULL; + } + const C55Operand *m = &insn->ops[memidx]; + if (m->kind != C55_OP_MEM || m->amode == C55_AM_DIRECT) { + return NULL; + } + switch (m->amode) { + case C55_AM_POSTINC: + case C55_AM_POSTDEC: + case C55_AM_POSTADD: + case C55_AM_POSTSUB: + break; + default: + return NULL; // *no-modify or reverse-carry (AR left as-is) + } + RzILOpEffect *sets[8]; + int k; + for (k = 0; k < 8; k++) { + RzILOpPure *mod; + switch (m->amode) { + case C55_AM_POSTINC: mod = ADD(VARG(c2x_ar[k]), UN(16, 1)); break; + case C55_AM_POSTDEC: mod = SUB(VARG(c2x_ar[k]), UN(16, 1)); break; + case C55_AM_POSTADD: mod = ADD(VARG(c2x_ar[k]), VARG("ar0")); break; + default: mod = SUB(VARG(c2x_ar[k]), VARG("ar0")); break; // C55_AM_POSTSUB + } + sets[k] = SETG(c2x_ar[k], ITE(EQ(VARG("arp"), UN(16, (ut32)k)), mod, VARG(c2x_ar[k]))); + } + return SEQ8(sets[0], sets[1], sets[2], sets[3], sets[4], sets[5], sets[6], sets[7]); +} + +// Full post-modify: AR update plus the next-ARP load encoded by a following AR +// register operand. +static RzILOpEffect *c2x_ar_modify(const C55Insn *insn, ut8 memidx) { + RzILOpEffect *eff = c2x_ar_post(insn, memidx); + if (memidx + 1 < insn->n_ops && insn->ops[memidx + 1].kind == C55_OP_REG && + insn->ops[memidx + 1].reg.cls == C55_RC_AR) { + // next-ARP is a MODIFY_ARP: previous ARP is buffered into ARB. + RzILOpEffect *sa = SEQ2(SETG("arb", VARG("arp")), + SETG("arp", UN(16, insn->ops[memidx + 1].reg.num & 7))); + eff = eff ? SEQ2(eff, sa) : sa; + } + return eff; +} + +// Append the (optional) AR post-modify to a core effect. The post-modify is +// legitimately absent (NULL) for direct and *no-modify forms, so it is the only +// operand allowed to be NULL; a NULL core would be a lifter bug and is passed +// straight to SEQ2, which keeps its NULL warning. Mirrors the sibling C54x +// lifter's c54x_seq_post. +static RzILOpEffect *c2x_seq_post(RzILOpEffect *core, RzILOpEffect *post) { + return post ? SEQ2(core, post) : core; +} + +// read mem into local "m", run body (which uses VARL("m")), then post-modify AR +static RzILOpEffect *c2x_with_mem(const C55Insn *insn, ut8 memidx, RzILOpEffect *body) { + return c2x_seq_post(SEQ2(SETL("m", c2x_mem_read(&insn->ops[memidx])), body), + c2x_ar_modify(insn, memidx)); +} + +// the GETDATA value: local "m" extended to 32 bits (per SXM when sxm_ext) and +// shifted left by sh. +static RzILOpPure *c2x_mval(ut8 sh, bool sxm_ext) { + RzILOpPure *v = sxm_ext + ? ITE(VARG("sxm"), SIGNED(32, VARL("m")), UNSIGNED(32, VARL("m"))) + : UNSIGNED(32, VARL("m")); + if (sh) { + v = SHIFTL0(v, UN(6, sh)); + } + return v; +} + +// accumulator arithmetic with carry/overflow + +typedef enum { CM_ASSIGN, + CM_SETONLY, + CM_NONE } c2x_cmode; + +// acc += val (val 32-bit). Sets ACC (with OVM saturation), sticky OV and, +// per cm, the carry. Implemented exactly as the MAME C2x core. +static RzILOpEffect *c2x_acc_add(RzILOpPure *val, c2x_cmode cm) { + RzILOpEffect *flags = SETG("ov", OR(VARG("ov"), VARL("ovn"))); + if (cm == CM_ASSIGN) { + flags = SEQ2(SETG("c", ULT(VARL("na"), VARL("oa"))), flags); + } else if (cm == CM_SETONLY) { + flags = SEQ2(SETG("c", OR(VARG("c"), ULT(VARL("na"), VARL("oa")))), flags); + } + return SEQ5( + SETL("oa", VARG("acc")), + SETL("av", val), + SETL("na", ADD(VARL("oa"), VARL("av"))), + SEQ2( + SETL("ovn", MSB(LOGAND(LOGXOR(VARL("na"), VARL("av")), LOGXOR(VARL("oa"), VARL("na"))))), + SETG("acc", ITE(AND(VARG("ovm"), VARL("ovn")), ITE(SLT(VARL("oa"), SN(32, 0)), UN(32, 0x80000000), UN(32, 0x7fffffff)), VARL("na")))), + flags); +} + +// acc -= val (val 32-bit), MAME semantics. +static RzILOpEffect *c2x_acc_sub(RzILOpPure *val, c2x_cmode cm) { + RzILOpEffect *flags = SETG("ov", OR(VARG("ov"), VARL("ovn"))); + if (cm == CM_ASSIGN) { + flags = SEQ2(SETG("c", INV(ULT(VARL("oa"), VARL("na")))), flags); + } else if (cm == CM_SETONLY) { // SUBH: clears carry only on borrow + flags = SEQ2(SETG("c", AND(VARG("c"), INV(ULT(VARL("oa"), VARL("na"))))), flags); + } + return SEQ5( + SETL("oa", VARG("acc")), + SETL("av", val), + SETL("na", SUB(VARL("oa"), VARL("av"))), + SEQ2( + SETL("ovn", MSB(LOGAND(LOGXOR(VARL("oa"), VARL("av")), LOGXOR(VARL("oa"), VARL("na"))))), + SETG("acc", ITE(AND(VARG("ovm"), VARL("ovn")), ITE(SLT(VARL("oa"), SN(32, 0)), UN(32, 0x80000000), UN(32, 0x7fffffff)), VARL("na")))), + flags); +} + +// P register shifted into the ALU per the PM mode (0:none 1:<<1 2:<<4 3:>>6 asr) +static RzILOpPure *c2x_pshift(void) { + return ITE(EQ(VARG("pm"), UN(2, 0)), VARG("p"), + ITE(EQ(VARG("pm"), UN(2, 1)), SHIFTL0(VARG("p"), UN(6, 1)), + ITE(EQ(VARG("pm"), UN(2, 2)), SHIFTL0(VARG("p"), UN(6, 4)), + SHIFTR(MSB(VARG("p")), VARG("p"), UN(6, 6))))); +} + +// 13-bit sign-extended MPYK constant +static st32 c2x_mpyk_imm(const C55Insn *insn) { + return rz_bits_sign_ext32((ut32)(insn->ops[0].imm & 0x1fff), 13); +} + +// long (16-bit) immediate value of a Dxxx instruction, extended per SXM and +// shifted; ANDK/ORK/XORK pass sxm_ext=false (always zero-extended). +static RzILOpPure *c2x_longimm(const C55Insn *insn, bool sxm_ext) { + ut16 imm = (ut16)(insn->ops[0].imm & 0xffff); + ut8 sh = (ut8)(insn->ops[1].imm & 0xf); + RzILOpPure *v = sxm_ext + ? ITE(VARG("sxm"), SN(32, (st16)imm), UN(32, imm)) + : UN(32, imm); + if (sh) { + v = SHIFTL0(v, UN(6, sh)); + } + return v; +} + +// Branch/call target: the encoded value is a *word* address; the IL PC is byte- +// addressed, so scale x2 (word code addresses up to 0x7fff fit the 16-bit PC). +static RzILOpPure *c2x_jt(const C55Insn *insn, ut8 i) { + return UN(16, ((ut32)insn->ops[i].imm & 0xffff) * C2X_WORD_BYTES); +} + +// add/subtract the same 8-bit immediate to/from the ARP-selected AR (ADRK/SBRK) +static RzILOpEffect *c2x_ar_addimm(const C55Insn *insn, bool sub) { + ut32 k = (ut32)insn->ops[0].imm & 0xff; + RzILOpEffect *sets[8]; + int i; + for (i = 0; i < 8; i++) { + RzILOpPure *mod = sub ? SUB(VARG(c2x_ar[i]), UN(16, k)) : ADD(VARG(c2x_ar[i]), UN(16, k)); + sets[i] = SETG(c2x_ar[i], ITE(EQ(VARG("arp"), UN(16, (ut32)i)), mod, VARG(c2x_ar[i]))); + } + return SEQ8(sets[0], sets[1], sets[2], sets[3], sets[4], sets[5], sets[6], sets[7]); +} + +// main lifter + +RZ_IPI RzILOpEffect *c2x_lift(const C55Insn *insn, ut64 pc) { + switch (insn->id) { + case C2X_INS_NOP: + case C2X_INS_CNFD: + case C2X_INS_CNFP: + case C2X_INS_CONF: + case C2X_INS_RFSM: + case C2X_INS_SFSM: + case C2X_INS_RHM: + case C2X_INS_SHM: + case C2X_INS_RTXM: + case C2X_INS_STXM: + case C2X_INS_FORT: + case C2X_INS_RXF: + case C2X_INS_SXF: + case C2X_INS_EINT: + case C2X_INS_DINT: + case C2X_INS_IDLE: + return NOP(); + case C2X_INS_MAR: { + RzILOpEffect *e = c2x_ar_modify(insn, 0); + return e ? e : NOP(); + } + case C2X_INS_LARP: + // MODIFY_ARP: the previous ARP is saved into ARB, then ARP is loaded. + return SEQ2(SETG("arb", VARG("arp")), SETG("arp", UN(16, (ut32)insn->ops[0].imm & 7))); + + // mode / status bit set & clear + case C2X_INS_RC: + return SETG("c", IL_FALSE); + case C2X_INS_SC: + return SETG("c", IL_TRUE); + case C2X_INS_RTC: + return SETG("tc", IL_FALSE); + case C2X_INS_STC: + return SETG("tc", IL_TRUE); + case C2X_INS_ROVM: + return SETG("ovm", IL_FALSE); + case C2X_INS_SOVM: + return SETG("ovm", IL_TRUE); + case C2X_INS_RSXM: + return SETG("sxm", IL_FALSE); + case C2X_INS_SSXM: + return SETG("sxm", IL_TRUE); + case C2X_INS_SPM: + return SETG("pm", UN(2, (ut32)insn->ops[0].imm & 3)); + + // immediate loads + case C2X_INS_ZAC: + return SETG("acc", UN(32, 0)); + case C2X_INS_LACK: + return SETG("acc", UN(32, (ut32)insn->ops[0].imm & 0xff)); + case C2X_INS_LDPK: + return SETG("dp", UN(16, (ut32)insn->ops[0].imm & 0x1ff)); + case C2X_INS_LARK: + return SETG(c2x_ar[insn->ops[0].reg.num & 7], UN(16, (ut32)insn->ops[1].imm & 0xff)); + case C2X_INS_ADDK: + return c2x_acc_add(UN(32, (ut32)insn->ops[0].imm & 0xff), CM_ASSIGN); + case C2X_INS_SUBK: + return c2x_acc_sub(UN(32, (ut32)insn->ops[0].imm & 0xff), CM_ASSIGN); + case C2X_INS_LALK: + return SETG("acc", c2x_longimm(insn, true)); + case C2X_INS_ADLK: + return c2x_acc_add(c2x_longimm(insn, true), CM_ASSIGN); + case C2X_INS_SBLK: + return c2x_acc_sub(c2x_longimm(insn, true), CM_ASSIGN); + case C2X_INS_ANDK: + return SETG("acc", LOGAND(VARG("acc"), c2x_longimm(insn, false))); + case C2X_INS_ORK: + return SETG("acc", LOGOR(VARG("acc"), c2x_longimm(insn, false))); + case C2X_INS_XORK: + return SETG("acc", LOGXOR(VARG("acc"), c2x_longimm(insn, false))); + case C2X_INS_LRLK: + return SETG(c2x_ar[insn->ops[0].reg.num & 7], UN(16, (ut32)insn->ops[1].imm & 0xffff)); + + // accumulator unary + case C2X_INS_ABS: + return SEQ2(SETG("acc", ITE(SLT(VARG("acc"), SN(32, 0)), NEG(VARG("acc")), VARG("acc"))), + SETG("c", IL_FALSE)); + case C2X_INS_NEG: + return SEQ3(SETL("oa", VARG("acc")), SETG("acc", NEG(VARL("oa"))), + SETG("c", IS_ZERO(VARL("oa")))); + case C2X_INS_CMPL: + return SETG("acc", LOGNOT(VARG("acc"))); + case C2X_INS_SFL: + return SEQ3(SETL("oa", VARG("acc")), + SETG("acc", SHIFTL0(VARL("oa"), UN(6, 1))), + SETG("c", MSB(VARL("oa")))); + case C2X_INS_SFR: + return SEQ3(SETL("oa", VARG("acc")), + SETG("acc", ITE(VARG("sxm"), SHIFTR(MSB(VARL("oa")), VARL("oa"), UN(6, 1)), SHIFTR0(VARL("oa"), UN(6, 1)))), + SETG("c", LSB(VARL("oa")))); + case C2X_INS_ROL: + return SEQ3(SETL("oa", VARG("acc")), + SETG("acc", LOGOR(SHIFTL0(VARL("oa"), UN(6, 1)), ITE(VARG("c"), UN(32, 1), UN(32, 0)))), + SETG("c", MSB(VARL("oa")))); + case C2X_INS_ROR: + return SEQ3(SETL("oa", VARG("acc")), + SETG("acc", LOGOR(SHIFTR0(VARL("oa"), UN(6, 1)), ITE(VARG("c"), UN(32, 0x80000000), UN(32, 0)))), + SETG("c", LSB(VARL("oa")))); + + // product register moves + case C2X_INS_PAC: + return SETG("acc", c2x_pshift()); + case C2X_INS_APAC: + return c2x_acc_add(c2x_pshift(), CM_ASSIGN); + case C2X_INS_SPAC: + return c2x_acc_sub(c2x_pshift(), CM_ASSIGN); + case C2X_INS_MPYK: + return SETG("p", MUL(SIGNED(32, VARG("t")), SN(32, c2x_mpyk_imm(insn)))); + case C2X_INS_SPL: + return c2x_seq_post(c2x_mem_write(&insn->ops[0], CAST(16, IL_FALSE, c2x_pshift())), + c2x_ar_modify(insn, 0)); + case C2X_INS_SPH: + return c2x_seq_post(c2x_mem_write(&insn->ops[0], CAST(16, IL_FALSE, SHIFTR0(c2x_pshift(), UN(6, 16)))), + c2x_ar_modify(insn, 0)); + + // DP-direct / indirect memory: load-accumulator family + case C2X_INS_LAC: + return c2x_with_mem(insn, 0, SETG("acc", c2x_mval(insn->ops[1].imm & 0xf, true))); + case C2X_INS_LACT: + return c2x_with_mem(insn, 0, SETG("acc", SHIFTL0(ITE(VARG("sxm"), SIGNED(32, VARL("m")), UNSIGNED(32, VARL("m"))), LOGAND(VARG("t"), UN(16, 0xf))))); + case C2X_INS_ZALH: + return c2x_with_mem(insn, 0, SETG("acc", SHIFTL0(UNSIGNED(32, VARL("m")), UN(6, 16)))); + case C2X_INS_ZALS: + return c2x_with_mem(insn, 0, SETG("acc", UNSIGNED(32, VARL("m")))); + case C2X_INS_ZALR: + return c2x_with_mem(insn, 0, SETG("acc", LOGOR(SHIFTL0(UNSIGNED(32, VARL("m")), UN(6, 16)), UN(32, 0x8000)))); + case C2X_INS_ADD: + return c2x_with_mem(insn, 0, c2x_acc_add(c2x_mval(insn->ops[1].imm & 0xf, true), CM_ASSIGN)); + case C2X_INS_ADDS: + return c2x_with_mem(insn, 0, c2x_acc_add(c2x_mval(0, false), CM_ASSIGN)); + case C2X_INS_ADDT: + return c2x_with_mem(insn, 0, c2x_acc_add(SHIFTL0(ITE(VARG("sxm"), SIGNED(32, VARL("m")), UNSIGNED(32, VARL("m"))), LOGAND(VARG("t"), UN(16, 0xf))), CM_ASSIGN)); + case C2X_INS_ADDH: + return c2x_with_mem(insn, 0, c2x_acc_add(SHIFTL0(UNSIGNED(32, VARL("m")), UN(6, 16)), CM_SETONLY)); + case C2X_INS_SUB: + return c2x_with_mem(insn, 0, c2x_acc_sub(c2x_mval(insn->ops[1].imm & 0xf, true), CM_ASSIGN)); + case C2X_INS_SUBS: + return c2x_with_mem(insn, 0, c2x_acc_sub(c2x_mval(0, false), CM_ASSIGN)); + case C2X_INS_SUBT: + return c2x_with_mem(insn, 0, c2x_acc_sub(SHIFTL0(ITE(VARG("sxm"), SIGNED(32, VARL("m")), UNSIGNED(32, VARL("m"))), LOGAND(VARG("t"), UN(16, 0xf))), CM_ASSIGN)); + case C2X_INS_SUBH: + return c2x_with_mem(insn, 0, c2x_acc_sub(SHIFTL0(UNSIGNED(32, VARL("m")), UN(6, 16)), CM_SETONLY)); + case C2X_INS_ADDC: + return c2x_with_mem(insn, 0, SEQ6(SETL("oa", VARG("acc")), SETL("av", UNSIGNED(32, VARL("m"))), SETL("na", ADD(ADD(VARL("oa"), VARL("av")), ITE(VARG("c"), UN(32, 1), UN(32, 0)))), SETG("acc", VARL("na")), SETG("ov", OR(VARG("ov"), MSB(LOGAND(LOGXOR(VARL("na"), VARL("av")), LOGXOR(VARL("oa"), VARL("na")))))), SETG("c", ITE(EQ(VARL("na"), VARL("oa")), VARG("c"), ULT(VARL("na"), VARL("oa")))))); + case C2X_INS_SUBB: + return c2x_with_mem(insn, 0, SEQ6(SETL("oa", VARG("acc")), SETL("av", UNSIGNED(32, VARL("m"))), SETL("na", SUB(SUB(VARL("oa"), VARL("av")), ITE(VARG("c"), UN(32, 0), UN(32, 1)))), SETG("acc", VARL("na")), SETG("ov", OR(VARG("ov"), MSB(LOGAND(LOGXOR(VARL("oa"), VARL("av")), LOGXOR(VARL("oa"), VARL("na")))))), SETG("c", ITE(EQ(VARL("na"), VARL("oa")), VARG("c"), INV(ULT(VARL("oa"), VARL("na"))))))); + case C2X_INS_SUBC: + return c2x_with_mem(insn, 0, SEQ6(SETL("oa", VARG("acc")), SETL("av", SHIFTL0(ITE(VARG("sxm"), SIGNED(32, VARL("m")), UNSIGNED(32, VARL("m"))), UN(6, 15))), SETL("na", SUB(VARL("oa"), VARL("av"))), SETG("ov", OR(VARG("ov"), MSB(LOGAND(LOGXOR(VARL("oa"), VARL("av")), LOGXOR(VARL("oa"), VARL("na")))))), SETG("c", INV(ULT(VARL("oa"), VARL("na")))), SETG("acc", ITE(INV(ULT(VARL("oa"), VARL("av"))), LOGOR(SHIFTL0(VARL("na"), UN(6, 1)), UN(32, 1)), SHIFTL0(VARL("oa"), UN(6, 1)))))); + + // logical with memory + case C2X_INS_AND: + return c2x_with_mem(insn, 0, SETG("acc", LOGAND(VARG("acc"), UNSIGNED(32, VARL("m"))))); + case C2X_INS_OR: + return c2x_with_mem(insn, 0, SETG("acc", LOGOR(VARG("acc"), UNSIGNED(32, VARL("m"))))); + case C2X_INS_XOR: + return c2x_with_mem(insn, 0, SETG("acc", LOGXOR(VARG("acc"), UNSIGNED(32, VARL("m"))))); + + // T / P loads & multiply with memory + case C2X_INS_LT: + return c2x_with_mem(insn, 0, SETG("t", VARL("m"))); + case C2X_INS_LTA: + return c2x_with_mem(insn, 0, SEQ2(SETG("t", VARL("m")), c2x_acc_add(c2x_pshift(), CM_ASSIGN))); + case C2X_INS_LTP: + return c2x_with_mem(insn, 0, SEQ2(SETG("t", VARL("m")), SETG("acc", c2x_pshift()))); + case C2X_INS_LTS: + return c2x_with_mem(insn, 0, SEQ2(SETG("t", VARL("m")), c2x_acc_sub(c2x_pshift(), CM_ASSIGN))); + case C2X_INS_LTD: + return c2x_with_mem(insn, 0, SEQ3(SETG("t", VARL("m")), STOREW(c2x_byte(ADD(c2x_addr(&insn->ops[0]), UN(16, 1))), VARL("m")), c2x_acc_add(c2x_pshift(), CM_ASSIGN))); + case C2X_INS_LPH: + return c2x_with_mem(insn, 0, SETG("p", LOGOR(LOGAND(VARG("p"), UN(32, 0xffff)), SHIFTL0(UNSIGNED(32, VARL("m")), UN(6, 16))))); + case C2X_INS_MPY: + return c2x_with_mem(insn, 0, SETG("p", MUL(SIGNED(32, VARL("m")), SIGNED(32, VARG("t"))))); + case C2X_INS_MPYU: + return c2x_with_mem(insn, 0, SETG("p", MUL(UNSIGNED(32, VARL("m")), UNSIGNED(32, VARG("t"))))); + case C2X_INS_MPYA: + return SEQ2(c2x_acc_add(c2x_pshift(), CM_ASSIGN), + c2x_with_mem(insn, 0, SETG("p", MUL(SIGNED(32, VARL("m")), SIGNED(32, VARG("t")))))); + case C2X_INS_MPYS: + return SEQ2(c2x_acc_sub(c2x_pshift(), CM_ASSIGN), + c2x_with_mem(insn, 0, SETG("p", MUL(SIGNED(32, VARL("m")), SIGNED(32, VARG("t")))))); + case C2X_INS_SQRA: + return SEQ2(c2x_acc_add(c2x_pshift(), CM_ASSIGN), + c2x_with_mem(insn, 0, SEQ2(SETG("t", VARL("m")), SETG("p", MUL(SIGNED(32, VARL("m")), SIGNED(32, VARL("m"))))))); + case C2X_INS_SQRS: + return SEQ2(c2x_acc_sub(c2x_pshift(), CM_ASSIGN), + c2x_with_mem(insn, 0, SEQ2(SETG("t", VARL("m")), SETG("p", MUL(SIGNED(32, VARL("m")), SIGNED(32, VARL("m"))))))); + + // bit test + case C2X_INS_BIT: + return c2x_with_mem(insn, 0, SETG("tc", LSB(SHIFTR0(VARL("m"), UN(4, (ut32)(15 - (insn->ops[1].imm & 0xf))))))); + case C2X_INS_BITT: + return c2x_with_mem(insn, 0, SETG("tc", LSB(SHIFTR0(VARL("m"), SUB(UN(16, 15), LOGAND(VARG("t"), UN(16, 0xf))))))); + + // AR load/store + case C2X_INS_LAR: { + ut8 n = insn->ops[0].reg.num & 7; + // The C5x "lar arN, #imm16" form carries an immediate (a load-AR-long, + // rendered "lar"); the C2x/C5x memory form takes an addressing byte. + if (insn->ops[1].kind == C55_OP_IMM) { + return SETG(c2x_ar[n], UN(16, (ut32)insn->ops[1].imm & 0xffff)); + } + RzILOpEffect *mod = c2x_ar_modify(insn, 1); + RzILOpEffect *ld = SETG(c2x_ar[n], VARL("m")); + // MAME applies the AR post-modify (part of GETDATA) before the load, + // so a self-load (N==ARP) keeps the loaded value. + return SEQ2(SETL("m", c2x_mem_read(&insn->ops[1])), mod ? SEQ2(mod, ld) : ld); + } + case C2X_INS_SAR: + return c2x_seq_post(c2x_mem_write(&insn->ops[1], VARG(c2x_ar[insn->ops[0].reg.num & 7])), + c2x_ar_modify(insn, 1)); + case C2X_INS_ADRK: + return c2x_ar_addimm(insn, false); + case C2X_INS_SBRK: + return c2x_ar_addimm(insn, true); + + // store accumulator + case C2X_INS_SACL: { + ut8 sh = (ut8)(insn->ops[1].imm & 7); + RzILOpPure *v = sh ? SHIFTL0(VARG("acc"), UN(6, sh)) : VARG("acc"); + return c2x_seq_post(c2x_mem_write(&insn->ops[0], CAST(16, IL_FALSE, v)), c2x_ar_modify(insn, 0)); + } + case C2X_INS_SACH: { + ut8 sh = (ut8)(insn->ops[1].imm & 7); + RzILOpPure *v = sh ? SHIFTL0(VARG("acc"), UN(6, sh)) : VARG("acc"); + return c2x_seq_post(c2x_mem_write(&insn->ops[0], CAST(16, IL_FALSE, SHIFTR0(v, UN(6, 16)))), c2x_ar_modify(insn, 0)); + } + + // data move / transfer + case C2X_INS_DMOV: + return c2x_with_mem(insn, 0, STOREW(c2x_byte(ADD(c2x_addr(&insn->ops[0]), UN(16, 1))), VARL("m"))); + case C2X_INS_TBLR: + return c2x_seq_post(c2x_mem_write(&insn->ops[0], LOADW(16, c2x_byte(CAST(16, IL_FALSE, VARG("acc"))))), + c2x_ar_modify(insn, 0)); + case C2X_INS_TBLW: + return c2x_with_mem(insn, 0, STOREW(c2x_byte(CAST(16, IL_FALSE, VARG("acc"))), VARL("m"))); + + // stack (modelled through SP into data space) + case C2X_INS_PUSH: + return SEQ2(SETG("sp", SUB(VARG("sp"), UN(16, 1))), STOREW(c2x_byte(VARG("sp")), CAST(16, IL_FALSE, VARG("acc")))); + case C2X_INS_POP: + return SEQ2(SETG("acc", UNSIGNED(32, LOADW(16, c2x_byte(VARG("sp"))))), SETG("sp", ADD(VARG("sp"), UN(16, 1)))); + case C2X_INS_PSHD: + return c2x_with_mem(insn, 0, SEQ2(SETG("sp", SUB(VARG("sp"), UN(16, 1))), STOREW(c2x_byte(VARG("sp")), VARL("m")))); + case C2X_INS_POPD: + return c2x_seq_post(SEQ3(SETL("v", LOADW(16, c2x_byte(VARG("sp")))), SETG("sp", ADD(VARG("sp"), UN(16, 1))), + c2x_mem_write(&insn->ops[0], VARL("v"))), + c2x_ar_modify(insn, 0)); + + // control transfer + case C2X_INS_B: + return JMP(c2x_jt(insn, 0)); + case C2X_INS_BACC: + return JMP(MUL(CAST(16, IL_FALSE, VARG("acc")), UN(16, 2))); + case C2X_INS_CALL: + return SEQ3(SETG("sp", SUB(VARG("sp"), UN(16, 1))), + STOREW(c2x_byte(VARG("sp")), UN(16, (ut32)(pc + 2) & 0xffff)), JMP(c2x_jt(insn, 0))); + case C2X_INS_CALA: + return SEQ3(SETG("sp", SUB(VARG("sp"), UN(16, 1))), + STOREW(c2x_byte(VARG("sp")), UN(16, (ut32)(pc + 1) & 0xffff)), JMP(MUL(CAST(16, IL_FALSE, VARG("acc")), UN(16, 2)))); + case C2X_INS_RET: + return SEQ2(SETL("r", LOADW(16, c2x_byte(VARG("sp")))), + SEQ2(SETG("sp", ADD(VARG("sp"), UN(16, 1))), JMP(VARL("r")))); + case C2X_INS_TRAP: + return SEQ3(SETG("sp", SUB(VARG("sp"), UN(16, 1))), + STOREW(c2x_byte(VARG("sp")), UN(16, (ut32)(pc + 1) & 0xffff)), JMP(UN(16, 0x1e))); + case C2X_INS_BZ: + return BRANCH(IS_ZERO(VARG("acc")), JMP(c2x_jt(insn, 0)), NOP()); + case C2X_INS_BNZ: + return BRANCH(NON_ZERO(VARG("acc")), JMP(c2x_jt(insn, 0)), NOP()); + case C2X_INS_BGZ: + return BRANCH(SGT(VARG("acc"), SN(32, 0)), JMP(c2x_jt(insn, 0)), NOP()); + case C2X_INS_BLZ: + return BRANCH(SLT(VARG("acc"), SN(32, 0)), JMP(c2x_jt(insn, 0)), NOP()); + case C2X_INS_BGEZ: + return BRANCH(SGE(VARG("acc"), SN(32, 0)), JMP(c2x_jt(insn, 0)), NOP()); + case C2X_INS_BLEZ: + return BRANCH(SLE(VARG("acc"), SN(32, 0)), JMP(c2x_jt(insn, 0)), NOP()); + case C2X_INS_BC: + return BRANCH(VARG("c"), JMP(c2x_jt(insn, 0)), NOP()); + case C2X_INS_BNC: + return BRANCH(IS_ZERO(VARG("c")), JMP(c2x_jt(insn, 0)), NOP()); + case C2X_INS_BBZ: + return BRANCH(IS_ZERO(VARG("tc")), JMP(c2x_jt(insn, 0)), NOP()); + case C2X_INS_BBNZ: + return BRANCH(VARG("tc"), JMP(c2x_jt(insn, 0)), NOP()); + case C2X_INS_BV: + return BRANCH(VARG("ov"), SEQ2(SETG("ov", IL_FALSE), JMP(c2x_jt(insn, 0))), NOP()); + case C2X_INS_BNV: + return BRANCH(IS_ZERO(VARG("ov")), JMP(c2x_jt(insn, 0)), SETG("ov", IL_FALSE)); + case C2X_INS_BANZ: { + // Test the loop-counter AR (ARP-selected) before modifying it, branch + // while non-zero, and apply the indirect post-modify (*- decrement) plus + // any next-ARP reload. The post-modify must run before the branch so the + // control effect ends the sequence (a ctrl op cannot be followed by more + // effects); the pre-modify AR value is captured first for the test. + RzILOpEffect *upd = c2x_ar_modify(insn, 1); + if (!upd) { + return BRANCH(NON_ZERO(c2x_ind_addr()), JMP(c2x_jt(insn, 0)), NOP()); + } + return SEQ3(SETL("ba", c2x_ind_addr()), upd, + BRANCH(NON_ZERO(VARL("ba")), JMP(c2x_jt(insn, 0)), NOP())); + } + + // compare AR to AR0 -> TC + case C2X_INS_CMPR: { + ut8 mode = (ut8)(insn->ops[0].imm & 3); + RzILOpPure *a = c2x_ind_addr(); + RzILOpPure *z = VARG("ar0"); + RzILOpPure *cmp; + switch (mode) { + case 0: cmp = EQ(a, z); break; + case 1: cmp = ULT(a, z); break; + case 2: cmp = UGT(a, z); break; + default: cmp = INV(EQ(a, z)); break; + } + return SETG("tc", cmp); + } + + // status load / store (compose / decompose the modelled bits) + // ST0: ARP[15:13] OV[12] OVM[11] (INTM[9] unmodelled) DP[8:0], bit10 reserved. + // ST1: ARB[15:13] (CNF0[12]) TC[11] SXM[10] C[9] fixed[8:7] (HM/FSM/XF/FO/TXM) + // PM[1:0]. Unmodelled bits read back as 0 (status round-trips the bits + // the IL tracks). LST/LST1 use IgnoreARPHack: AR is post-modified but the + // next-ARP field is not applied. + case C2X_INS_LST: + return c2x_seq_post(SEQ2(SETL("m", c2x_mem_read(&insn->ops[0])), SEQ4(SETG("arp", LOGAND(SHIFTR0(VARL("m"), UN(4, 13)), UN(16, 7))), SETG("ov", LSB(SHIFTR0(VARL("m"), UN(4, 12)))), SETG("ovm", LSB(SHIFTR0(VARL("m"), UN(4, 11)))), SETG("dp", LOGAND(VARL("m"), UN(16, 0x1ff))))), c2x_ar_post(insn, 0)); + case C2X_INS_LST1: + return c2x_seq_post(SEQ2(SETL("m", c2x_mem_read(&insn->ops[0])), SEQ6(SETG("tc", LSB(SHIFTR0(VARL("m"), UN(4, 11)))), SETG("sxm", LSB(SHIFTR0(VARL("m"), UN(4, 10)))), SETG("c", LSB(SHIFTR0(VARL("m"), UN(4, 9)))), SETG("pm", CAST(2, IL_FALSE, VARL("m"))), SETG("arp", LOGAND(SHIFTR0(VARL("m"), UN(4, 13)), UN(16, 7))), SETG("arb", LOGAND(SHIFTR0(VARL("m"), UN(4, 13)), UN(16, 7))))), c2x_ar_post(insn, 0)); + case C2X_INS_SST: { + RzILOpPure *st0 = LOGOR(LOGOR(LOGOR( + SHIFTL0(UNSIGNED(16, VARG("arp")), UN(4, 13)), + ITE(VARG("ov"), UN(16, 0x1000), UN(16, 0))), + ITE(VARG("ovm"), UN(16, 0x0800), UN(16, 0))), + LOGAND(VARG("dp"), UN(16, 0x1ff))); + return c2x_seq_post(STOREW(c2x_byte(c2x_sst_addr(&insn->ops[0])), st0), c2x_ar_post(insn, 0)); + } + case C2X_INS_SST1: { + RzILOpPure *st1 = LOGOR(LOGOR(LOGOR(LOGOR(LOGOR( + SHIFTL0(UNSIGNED(16, VARG("arb")), UN(4, 13)), + ITE(VARG("tc"), UN(16, 0x0800), UN(16, 0))), + ITE(VARG("sxm"), UN(16, 0x0400), UN(16, 0))), + ITE(VARG("c"), UN(16, 0x0200), UN(16, 0))), + UN(16, 0x0180)), + UNSIGNED(16, VARG("pm"))); + return c2x_seq_post(STOREW(c2x_byte(c2x_sst_addr(&insn->ops[0])), st1), c2x_ar_post(insn, 0)); + } + + // multiply-accumulate and block moves (single iteration; the RPT-driven + // repetition and PFC auto-increment are control-flow constructs not modelled + // in straight-line IL). ops[0]=program/data address, ops[1]=data operand. + case C2X_INS_MAC: + return SEQ2(c2x_acc_add(c2x_pshift(), CM_ASSIGN), + c2x_with_mem(insn, 1, SEQ2(SETG("t", VARL("m")), SETG("p", MUL(SIGNED(32, VARL("m")), SIGNED(32, c2x_prog_read((ut16)insn->ops[0].imm))))))); + case C2X_INS_MACD: + return SEQ2(c2x_acc_add(c2x_pshift(), CM_ASSIGN), + c2x_with_mem(insn, 1, SEQ3(SETG("t", VARL("m")), STOREW(c2x_byte(ADD(c2x_addr(&insn->ops[1]), UN(16, 1))), VARL("m")), SETG("p", MUL(SIGNED(32, VARL("m")), SIGNED(32, c2x_prog_read((ut16)insn->ops[0].imm))))))); + case C2X_INS_BLKP: + return c2x_seq_post(c2x_mem_write(&insn->ops[1], c2x_prog_read((ut16)insn->ops[0].imm)), + c2x_ar_modify(insn, 1)); + case C2X_INS_BLKD: + return c2x_seq_post(c2x_mem_write(&insn->ops[1], + LOADW(16, c2x_byte(UN(16, (ut32)insn->ops[0].imm & 0xffff)))), + c2x_ar_modify(insn, 1)); + + case C2X_INS_RPTK: + // RPTC := 8-bit immediate. The repeat of the *next* instruction is a + // control-flow effect the per-instruction IL cannot express; the + // architected RPTC update is modelled. + return SETG("rptc", UN(16, (ut32)insn->ops[0].imm & 0xff)); + case C2X_INS_RPT: + // RPTC := low byte of the addressed word (plus the AR post-modify). + return c2x_seq_post(SEQ2(SETL("m", c2x_mem_read(&insn->ops[0])), + SETG("rptc", LOGAND(VARL("m"), UN(16, 0xff)))), + c2x_ar_modify(insn, 0)); + case C2X_INS_NORM: { + // If ACC != 0 and bit31 == bit30 it is not yet normalised: clear TC, + // shift ACC left one and apply the AR post-modify. Otherwise set TC. + RzILOpPure *bit30 = LSB(SHIFTR0(VARG("acc"), UN(5, 30))); + RzILOpPure *cond = AND(NON_ZERO(VARG("acc")), INV(XOR(MSB(VARG("acc")), bit30))); + RzILOpEffect *post = c2x_ar_post(insn, 0); + RzILOpEffect *shift = post + ? SEQ3(SETG("tc", IL_FALSE), SETG("acc", SHIFTL0(VARG("acc"), UN(6, 1))), post) + : SEQ2(SETG("tc", IL_FALSE), SETG("acc", SHIFTL0(VARG("acc"), UN(6, 1)))); + return BRANCH(cond, shift, SETG("tc", IL_TRUE)); + } + case C2X_INS_IN: + // IN reads an external port into the addressed word; with no I/O model + // the open-bus value 0 is stored (matching the reference emulator), and + // the AR post-modify is applied. + return c2x_seq_post(c2x_mem_write(&insn->ops[0], UN(16, 0)), c2x_ar_modify(insn, 0)); + case C2X_INS_OUT: { + // OUT writes the addressed word to an external port; the only modelled + // state effect is the AR post-modify. + RzILOpEffect *post = c2x_ar_modify(insn, 0); + return post ? post : NOP(); + } + default: + // nothing else is unmodelled at this point. + return NULL; + } +} + +// register bindings: every name the lifter SET/VARs, matching the reg profile +static const char *c2x_il_regs[] = { + "acc", "t", "p", + "ar0", "ar1", "ar2", "ar3", "ar4", "ar5", "ar6", "ar7", + "arp", "dp", "st0", "st1", "pc", "sp", + "c", "ov", "tc", "ovm", "sxm", "pm", "arb", "rptc", + NULL +}; + +RZ_IPI RzAnalysisILConfig *tms320_c2x_il_config(RZ_NONNULL RzAnalysis *analysis) { + rz_return_val_if_fail(analysis, NULL); + // PC is the 16-bit byte-addressed code pointer; the data/program byte- + // address space is C2X_MEM_ADDR_BITS wide so a 16-bit word address scales + // (x2) without wrapping. Words are stored MSB-first (big-endian). + RzAnalysisILConfig *cfg = rz_analysis_il_config_new(16, true, C2X_MEM_ADDR_BITS); + if (!cfg) { + return NULL; + } + cfg->reg_bindings = c2x_il_regs; + return cfg; +} + +#include diff --git a/librz/arch/isa/tms320/c2x/c2x_rowdefs.h b/librz/arch/isa/tms320/c2x/c2x_rowdefs.h new file mode 100644 index 00000000000..4144016d6b0 --- /dev/null +++ b/librz/arch/isa/tms320/c2x/c2x_rowdefs.h @@ -0,0 +1,59 @@ +// SPDX-FileCopyrightText: 2026 RizinOrg +// SPDX-License-Identifier: LGPL-3.0-only + +/** + * \file + * Shared decode-table row macros for the TMS320C2x/C5x tables. Included + * immediately before a `static const C55InsnDef _table[] = {` body and + * paired with c2x_rowundefs.h afterwards. Requires the c2x_x_* operand + * extractors (declared in c2x.h) to be visible. + */ + +// head-space mask/match: the 16-bit opcode word occupies head bits 31:16. +#define OP(wmask, wmatch) .mask = ((ut32)(wmask) << 16), .match = ((ut32)(wmatch) << 16) +#define MEM(lo_) { .lo = (lo_), .width = 8, .fn = c2x_x_mem } +#define NARP(lo_) { .lo = (lo_), .width = 4, .fn = c2x_x_nextarp } +#define SHF(lo_, w_) { .lo = (lo_), .width = (w_), .fn = c2x_x_shift } +#define AR(lo_) { .lo = (lo_), .width = 3, .fn = c2x_x_reg } +#define IMM(lo_, w_, p_) { .lo = (lo_), .width = (w_), .fn = c2x_x_imm, .param = (p_) } +#define BR(lo_) { .lo = (lo_), .width = 16, .fn = c2x_x_branch } + +// memory-reference opcode keyed on the whole high byte + the direct/indirect bit +#define MEMOP_D(hb, id_) \ + { \ + OP(0xff80, ((ut16)(hb) << 8) | 0x0000), .id = (id_), .len = 2, .ops = { MEM(0) } \ + } +#define MEMOP_I(hb, id_) \ + { \ + OP(0xff80, ((ut16)(hb) << 8) | 0x0080), .id = (id_), .len = 2, .ops = { MEM(0), \ + NARP(0) } \ + } +#define FIX(word, id_) OP(0xffff, (word)), .id = (id_), .len = 2 +#define BROP(hb, id_) \ + { \ + OP(0xff80, ((ut16)(hb) << 8) | 0x0080), .id = (id_), .len = 4, .ops = { BR(0) } \ + } +// BANZ also carries the indirect addressing byte (in the leading word, bits +// 31:16) that selects the loop-counter AR post-modify (*- etc.); decode it so +// the lifter can apply the auxiliary-register update. +#define BANZOP(hb, id_) \ + { \ + OP(0xff80, ((ut16)(hb) << 8) | 0x0080), .id = (id_), .len = 4, .ops = { BR(0), \ + MEM(16), \ + NARP(16) } \ + } + +// 2-word instruction carrying a 16-bit memory address in the trailing word plus +// a destination addressing byte in the leading word (mac/macd/blkp/blkd). The +// leading word sits in packed bits 31:16, so MEM/NARP index from bit 16. +#define PMAOP_D(hb, id_) \ + { \ + OP(0xff80, ((ut16)(hb) << 8) | 0x0000), .id = (id_), .len = 4, .ops = { IMM(0, 16, 0), \ + MEM(16) } \ + } +#define PMAOP_I(hb, id_) \ + { \ + OP(0xff80, ((ut16)(hb) << 8) | 0x0080), .id = (id_), .len = 4, .ops = { IMM(0, 16, 0), \ + MEM(16), \ + NARP(16) } \ + } diff --git a/librz/arch/isa/tms320/c2x/c2x_rowundefs.h b/librz/arch/isa/tms320/c2x/c2x_rowundefs.h new file mode 100644 index 00000000000..b9993b0bed0 --- /dev/null +++ b/librz/arch/isa/tms320/c2x/c2x_rowundefs.h @@ -0,0 +1,17 @@ +// SPDX-FileCopyrightText: 2026 RizinOrg +// SPDX-License-Identifier: LGPL-3.0-only + +#undef OP +#undef MEM +#undef NARP +#undef SHF +#undef AR +#undef IMM +#undef BR +#undef MEMOP_D +#undef MEMOP_I +#undef FIX +#undef BROP +#undef BANZOP +#undef PMAOP_D +#undef PMAOP_I diff --git a/librz/arch/isa/tms320/c55_ir.c b/librz/arch/isa/tms320/c55_ir.c index 7e7bb0a52d8..59ef78c3f77 100644 --- a/librz/arch/isa/tms320/c55_ir.c +++ b/librz/arch/isa/tms320/c55_ir.c @@ -150,7 +150,9 @@ bool c55_decode(const C55ArchDesc *a, const ut8 *buf, int len, C55Insn *out) { // (e.g. 0xfe000000), in which case the bit's value selects the parallel // form; rows that pin the bit (0xff000000) treat it as opcode. C54x is // word-oriented and has no such bit, so it never carries a parallel flag. - out->parallel = a->arch != C55_ARCH_C54X && !def->no_parallel && (def->mask & 0x01000000) == 0 && (head & 0x01000000) != 0; + // C54x and C2x are word-oriented and have no parallel-execution bit, so + // they never carry a parallel flag. + out->parallel = a->arch != C55_ARCH_C54X && a->arch != C55_ARCH_C2X && a->arch != C55_ARCH_C5X && !def->no_parallel && (def->mask & 0x01000000) == 0 && (head & 0x01000000) != 0; const ut64 bits = c55_pack(buf, ilen); if (def->alt_bit && (c55_field(bits, (ut8)(def->alt_bit - 1), 1) != 0)) { // a variant selector beyond the 4-byte match head (e.g. firssub vs @@ -3708,6 +3710,14 @@ static void c55_fmt_reg(RzStrBuf *sb, const C55ArchDesc *a, const C55Reg *r) { } static void c55_fmt_mem(RzStrBuf *sb, const C55ArchDesc *a, const C55Operand *m) { + if (a->arch == C55_ARCH_C2X || a->arch == C55_ARCH_C5X) { + // C2x direct addressing renders as the bare 7-bit data-page offset (the + // page comes from DP at run time). The indirect forms (*, *+, *BR0+ and + // the ",arX" next-ARP suffix) are emitted verbatim through + // C55Operand.raw and never reach this helper. + rz_strbuf_appendf(sb, "0x%" PFMT32x, (ut32)m->disp & 0x7f); + return; + } if (a->arch == C55_ARCH_C54X) { // C54x addressing syntax differs from C55x (AR0-indexed *arN+0, circular // *arN+%, bit-reverse *arN+0B). Render it self-contained and return; the @@ -4145,8 +4155,8 @@ char *c55_format(const C55ArchDesc *a, const C55Insn *insn) { // with the '#' prefix (the sftl dst, #1 / #-1 forms). rz_strbuf_appendf(&sb, "#%" PFMT64d, (st64)op->imm); } else if (op->addr) { - if (a->arch == C55_ARCH_C54X) { - // C54x renders program/data addresses as a bare hex value + if (a->arch == C55_ARCH_C54X || a->arch == C55_ARCH_C2X || a->arch == C55_ARCH_C5X) { + // C54x/C2x render program/data addresses as a bare hex value // (the '#' prefix is reserved for immediates). rz_strbuf_appendf(&sb, "0x%" PFMT64x, op->imm); } else { diff --git a/librz/arch/isa/tms320/c55_ir.h b/librz/arch/isa/tms320/c55_ir.h index 2d7c05e16d1..a19a4766c5f 100644 --- a/librz/arch/isa/tms320/c55_ir.h +++ b/librz/arch/isa/tms320/c55_ir.h @@ -36,6 +36,8 @@ typedef enum { C55_ARCH_C54X = 0, ///< TMS320C54x C55_ARCH_C55X, ///< TMS320C55x C55_ARCH_C55XPLUS, ///< TMS320C55x+ + C55_ARCH_C2X, ///< TMS320C2x (legacy single-accumulator fixed-point) + C55_ARCH_C5X, ///< TMS320C5x (second-generation fixed-point; C2x-compatible superset) } C55Arch; /** Register class; family-wide superset, each arch uses only its subset. */ diff --git a/librz/arch/isa/tms320/c5x/c5x.c b/librz/arch/isa/tms320/c5x/c5x.c new file mode 100644 index 00000000000..7d4325412d6 --- /dev/null +++ b/librz/arch/isa/tms320/c5x/c5x.c @@ -0,0 +1,255 @@ +// SPDX-FileCopyrightText: 2026 RizinOrg +// SPDX-License-Identifier: LGPL-3.0-only + +/** + * \file + * TMS320C5x architecture descriptor, analysis entry and RzIL VM configuration. + * + * The C5x has its own decode front-end (c5x_decode, the real C5x object + * encoding) and reuses the shared C55 consumers (c55_format, c55_fill_analysis, + * c55_lift) through the descriptor below. Shared-semantics instructions carry + * the C2x ids and route through the C2x mnemonic/op-type/lifter; the C5x-only + * ids are handled by c5x_mnemonic/c5x_op_type/c5x_lift. + */ + +#include "c5x.h" +#include "../c2x/c2x.h" + +RZ_IPI const char *c5x_mnemonic(ut16 id) { + switch (id) { + // shared ids whose canonical C5x spelling differs from the C2x mnemonic + case C2X_INS_ADDK: return "add"; + case C2X_INS_SUBK: return "sub"; + case C2X_INS_LARK: return "lar"; + // 16-bit immediate ALU forms (decoded as the C2x long-immediate ops) + case C2X_INS_LALK: return "lacc"; + case C2X_INS_ADLK: return "add"; + case C2X_INS_SBLK: return "sub"; + case C2X_INS_ANDK: return "and"; + case C2X_INS_ORK: return "or"; + case C2X_INS_XORK: return "xor"; + case C2X_INS_RPTK: return "rpt"; + case C2X_INS_LDPK: return "ldp"; + // C5x-only mnemonics + case C5X_INS_LACC: return "lacc"; + case C5X_INS_LACL: return "lacl"; + case C5X_INS_LACB: return "lacb"; + case C5X_INS_SACB: return "sacb"; + case C5X_INS_EXAR: return "exar"; + case C5X_INS_ADDB: return "addb"; + case C5X_INS_SBB: return "sbb"; + case C5X_INS_ADCB: return "adcb"; + case C5X_INS_SBBB: return "sbbb"; + case C5X_INS_CRGT: return "crgt"; + case C5X_INS_CRLT: return "crlt"; + case C5X_INS_ANDB: return "andb"; + case C5X_INS_ORB: return "orb"; + case C5X_INS_XORB: return "xorb"; + case C5X_INS_ROLB: return "rolb"; + case C5X_INS_RORB: return "rorb"; + case C5X_INS_SFLB: return "sflb"; + case C5X_INS_SFRB: return "sfrb"; + case C5X_INS_SAMM: return "samm"; + case C5X_INS_LAMM: return "lamm"; + case C5X_INS_LMMR: return "lmmr"; + case C5X_INS_SMMR: return "smmr"; + case C5X_INS_BLDD: return "bldd"; + case C5X_INS_BLPD: return "blpd"; + case C5X_INS_BLDP: return "bldp"; + case C5X_INS_MADS: return "mads"; + case C5X_INS_MADD: return "madd"; + case C5X_INS_SPLK: return "splk"; + case C5X_INS_BCND: return "bcnd"; + case C5X_INS_BCNDD: return "bcndd"; + case C5X_INS_CC: return "cc"; + case C5X_INS_CCD: return "ccd"; + case C5X_INS_RETC: return "retc"; + case C5X_INS_RETCD: return "retcd"; + case C5X_INS_RETD: return "retd"; + case C5X_INS_XC: return "xc"; + case C5X_INS_BSAR: return "bsar"; + case C5X_INS_ZAP: return "zap"; + case C5X_INS_ZPR: return "zpr"; + case C5X_INS_SATH: return "sath"; + case C5X_INS_SATL: return "satl"; + case C5X_INS_BACCD: return "baccd"; + case C5X_INS_CALAD: return "calad"; + case C5X_INS_APL: return "apl"; + case C5X_INS_OPL: return "opl"; + case C5X_INS_XPL: return "xpl"; + case C5X_INS_CPL: return "cpl"; + case C5X_INS_RPTB: return "rptb"; + case C5X_INS_RPTZ: return "rptz"; + case C5X_INS_SETC: return "setc"; + case C5X_INS_CLRC: return "clrc"; + case C5X_INS_IDLE2: return "idle2"; + case C5X_INS_NMI: return "nmi"; + case C5X_INS_RETE: return "rete"; + case C5X_INS_RETI: return "reti"; + case C5X_INS_INTR: return "intr"; + case C5X_INS_BD: return "bd"; + case C5X_INS_CALLD: return "calld"; + case C5X_INS_BANZD: return "banzd"; + case C5X_INS_LST: return "lst"; + case C5X_INS_SST: return "sst"; + default: return c2x_mnemonic(id); + } +} + +RZ_IPI ut32 c5x_op_type(ut16 id) { + switch (id) { + case C5X_INS_LACC: + case C5X_INS_LACL: + case C5X_INS_LACB: + case C5X_INS_SACB: + case C5X_INS_EXAR: + case C5X_INS_SAMM: + case C5X_INS_LAMM: + case C5X_INS_LMMR: + case C5X_INS_SMMR: + case C5X_INS_BLDD: + case C5X_INS_BLPD: + case C5X_INS_BLDP: + case C5X_INS_SPLK: + return RZ_ANALYSIS_OP_TYPE_MOV; + case C5X_INS_ADDB: + case C5X_INS_ADCB: + return RZ_ANALYSIS_OP_TYPE_ADD; + case C5X_INS_SBB: + case C5X_INS_SBBB: + return RZ_ANALYSIS_OP_TYPE_SUB; + case C5X_INS_ANDB: + return RZ_ANALYSIS_OP_TYPE_AND; + case C5X_INS_ORB: + return RZ_ANALYSIS_OP_TYPE_OR; + case C5X_INS_XORB: + return RZ_ANALYSIS_OP_TYPE_XOR; + case C5X_INS_CRGT: + case C5X_INS_CRLT: + case C5X_INS_SATH: + case C5X_INS_SATL: + case C5X_INS_APL: + case C5X_INS_OPL: + case C5X_INS_XPL: + case C5X_INS_CPL: + case C5X_INS_MADS: + case C5X_INS_MADD: + return RZ_ANALYSIS_OP_TYPE_MOV; + case C5X_INS_ROLB: + case C5X_INS_SFLB: + return RZ_ANALYSIS_OP_TYPE_SHL; + case C5X_INS_RORB: + case C5X_INS_SFRB: + case C5X_INS_BSAR: + return RZ_ANALYSIS_OP_TYPE_SHR; + case C5X_INS_ZAP: + case C5X_INS_ZPR: + return RZ_ANALYSIS_OP_TYPE_MOV; + case C5X_INS_SETC: + case C5X_INS_CLRC: + return RZ_ANALYSIS_OP_TYPE_MOV; + case C5X_INS_LST: + case C5X_INS_SST: + return RZ_ANALYSIS_OP_TYPE_MOV; + case C5X_INS_BCND: + case C5X_INS_BCNDD: + case C5X_INS_XC: + case C5X_INS_BANZD: + return RZ_ANALYSIS_OP_TYPE_CJMP; + case C5X_INS_BD: + return RZ_ANALYSIS_OP_TYPE_JMP; + case C5X_INS_CC: + case C5X_INS_CCD: + return RZ_ANALYSIS_OP_TYPE_CCALL; + case C5X_INS_CALLD: + return RZ_ANALYSIS_OP_TYPE_CALL; + case C5X_INS_BACCD: + return RZ_ANALYSIS_OP_TYPE_UJMP; + case C5X_INS_CALAD: + return RZ_ANALYSIS_OP_TYPE_UCALL; + case C5X_INS_RETC: + case C5X_INS_RETCD: + return RZ_ANALYSIS_OP_TYPE_CRET; + case C5X_INS_RETD: + return RZ_ANALYSIS_OP_TYPE_RET; + case C5X_INS_RPTB: + case C5X_INS_RPTZ: + return RZ_ANALYSIS_OP_TYPE_NOP; + case C5X_INS_IDLE2: + case C5X_INS_NMI: + case C5X_INS_INTR: + return RZ_ANALYSIS_OP_TYPE_NULL; + case C5X_INS_RETE: + case C5X_INS_RETI: + return RZ_ANALYSIS_OP_TYPE_RET; + default: + return c2x_op_type(id); + } +} + +const C55ArchDesc c5x_arch_desc = { + .arch = C55_ARCH_C5X, + .cpu_name = "c5x", + .table = NULL, // decoded by c5x_decode(), not the shared table engine + .table_len = 0, + .insn_len = NULL, + .reg_info = c2x_reg_info, // operands reference only C2x reg classes (ARn) + .mnemonic = c5x_mnemonic, + .op_type = c5x_op_type, + .lift = c5x_lift, + .mem = { .addr_unit_log2 = 0, .ptr_width = 16, .big_endian = true, .page_reg = "dp" }, + .ea = c2x_ea, + .fill_dual = NULL, + .words_le = false, + .cond_exec_prefix = false, + .parallel_prefix = false, +}; + +RZ_IPI int tms320_c5x_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr, + const ut8 *buf, int len, RzAnalysisOpMask mask) { + if (!op || !buf || len < 1) { + return 0; + } + op->addr = addr; + op->type = RZ_ANALYSIS_OP_TYPE_NULL; + C55Insn ci; + int n = c5x_decode(buf, len, &ci); + if (n > 0) { + c55_fill_analysis(&c5x_arch_desc, &ci, op); + c2x_fill_op_access(analysis, &c5x_arch_desc, &ci, op); + if (mask & RZ_ANALYSIS_OP_MASK_IL) { + op->il_op = c55_lift(&c5x_arch_desc, &ci, op->addr); + } + } else { + // Undecodable word: flag it and give a one-word fallback size, but + // report the failure to the caller with -1 (the common plugin convention). + op->type = RZ_ANALYSIS_OP_TYPE_ILL; + op->size = 1; + return -1; + } + return op->size; +} + +// IL register bindings: the C2x core registers the shared lifter uses, plus the +// C5x-specific registers (ACCB and friends) referenced by the C5x lifter. +static const char *c5x_il_regs[] = { + "acc", "accb", "t", "treg1", "treg2", "p", + "ar0", "ar1", "ar2", "ar3", "ar4", "ar5", "ar6", "ar7", + "arp", "dp", "st0", "st1", "pmst", + "indx", "arcr", "cbsr1", "cber1", "cbsr2", "cber2", + "brcr", "pasr", "paer", "bmar", "dbmr", "greg", + "pc", "sp", + "c", "ov", "tc", "ovm", "sxm", "pm", "arb", "rptc", + NULL +}; + +RZ_IPI RzAnalysisILConfig *tms320_c5x_il_config(RZ_NONNULL RzAnalysis *analysis) { + rz_return_val_if_fail(analysis, NULL); + // Same word-addressed memory model as the C2x (see C2X_MEM_ADDR_BITS). + RzAnalysisILConfig *cfg = rz_analysis_il_config_new(16, true, C2X_MEM_ADDR_BITS); + if (!cfg) { + return NULL; + } + cfg->reg_bindings = c5x_il_regs; + return cfg; +} diff --git a/librz/arch/isa/tms320/c5x/c5x.h b/librz/arch/isa/tms320/c5x/c5x.h new file mode 100644 index 00000000000..6d0fa8912ad --- /dev/null +++ b/librz/arch/isa/tms320/c5x/c5x.h @@ -0,0 +1,120 @@ +// SPDX-FileCopyrightText: 2026 RizinOrg +// SPDX-License-Identifier: LGPL-3.0-only + +/** + * \file + * TMS320C5x (second-generation fixed-point DSP, e.g. TMS320C50/C51/C53). + * + * The C5x is source-compatible with the C2x (same assembly mnemonics) but uses + * a completely different object encoding, so it has its own decode front-end + * (c5x_decode, ported from the authoritative TMS320C5x opcode table) rather than + * the C2x decode table. The decoder fills the shared C55Insn; shared-semantics + * instructions reuse the C2x instruction ids and the C2x lifter, while the + * C5x-only instructions (ACCB buffer ops, parallel-logic, memory-mapped register + * access, conditional execute/call/return, block moves, ...) carry the C5X_INS_* + * ids below and are handled by c5x_mnemonic/c5x_op_type/c5x_lift, which delegate + * to the C2x consumers for the shared ids. + */ + +#ifndef RZ_TMS320_C5X_H +#define RZ_TMS320_C5X_H + +#include "../c2x/c2x.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/// C5x-only instruction ids (shared-semantics ops reuse the C2X_INS_* ids). The +/// base sits above the C2x enum so the two id spaces never collide. +enum { + C5X_INS_BASE = 0x200, + C5X_INS_LACC, ///< load ACC with shift (C2x LAC) + C5X_INS_LACL, ///< load ACC low, zero-extended + C5X_INS_LACB, ///< load ACC from ACCB + C5X_INS_SACB, ///< store ACC to ACCB + C5X_INS_EXAR, ///< exchange ACC and ACCB + C5X_INS_ADDB, ///< ACC += ACCB + C5X_INS_SBB, ///< ACC -= ACCB + C5X_INS_ADCB, ///< ACC += ACCB + carry + C5X_INS_SBBB, ///< ACC -= ACCB + borrow + C5X_INS_CRGT, ///< ACC = max(ACC, ACCB) + C5X_INS_CRLT, ///< ACC = min(ACC, ACCB) + C5X_INS_ANDB, ///< ACC &= ACCB + C5X_INS_ORB, ///< ACC |= ACCB + C5X_INS_XORB, ///< ACC ^= ACCB + C5X_INS_ROLB, ///< rotate ACC:ACCB left through carry + C5X_INS_RORB, ///< rotate ACC:ACCB right through carry + C5X_INS_SFLB, ///< shift ACC:ACCB left + C5X_INS_SFRB, ///< shift ACC:ACCB right + C5X_INS_SAMM, ///< store ACC to a memory-mapped register + C5X_INS_LAMM, ///< load ACC from a memory-mapped register + C5X_INS_LMMR, ///< load a memory-mapped register (long immediate addr) + C5X_INS_SMMR, ///< store a memory-mapped register (long immediate addr) + C5X_INS_BLDD, ///< block move data to data + C5X_INS_BLPD, ///< block move program to data + C5X_INS_BLDP, ///< block move data to program + C5X_INS_MADS, ///< multiply-accumulate with data move (BMAR address) + C5X_INS_MADD, ///< multiply-accumulate with data move and delay + C5X_INS_SPLK, ///< store parallel long immediate constant + C5X_INS_BCND, ///< conditional branch + C5X_INS_BCNDD, ///< delayed conditional branch + C5X_INS_CC, ///< conditional call + C5X_INS_CCD, ///< delayed conditional call + C5X_INS_RETC, ///< conditional return + C5X_INS_RETCD, ///< delayed conditional return + C5X_INS_RETD, ///< unconditional delayed return + C5X_INS_XC, ///< conditionally execute next n words + C5X_INS_BSAR, ///< barrel shift ACC right + C5X_INS_ZAP, ///< clear ACC and PREG + C5X_INS_ZPR, ///< clear PREG + C5X_INS_SATH, ///< saturate ACC high + C5X_INS_SATL, ///< saturate ACC low + C5X_INS_BACCD, ///< delayed branch to ACC address + C5X_INS_CALAD, ///< delayed call to ACC address + C5X_INS_APL, ///< AND data with DBMR / long immediate + C5X_INS_OPL, ///< OR data with DBMR / long immediate + C5X_INS_XPL, ///< XOR data with DBMR / long immediate + C5X_INS_CPL, ///< compare data with DBMR / long immediate + C5X_INS_RPTB, ///< repeat block + C5X_INS_RPTZ, ///< repeat next instruction, clearing ACC and PREG + C5X_INS_SETC, ///< set a control bit + C5X_INS_CLRC, ///< clear a control bit + C5X_INS_IDLE2, ///< idle until interrupt (low-power) + C5X_INS_NMI, ///< non-maskable interrupt + C5X_INS_RETE, ///< return from interrupt with enable + C5X_INS_RETI, ///< return from interrupt + C5X_INS_INTR, ///< software interrupt + C5X_INS_BD, ///< delayed branch + C5X_INS_CALLD, ///< delayed call + C5X_INS_BANZD, ///< delayed branch on AR not zero + C5X_INS_LST, ///< load status register STn (C5x #n, mem form) + C5X_INS_SST, ///< store status register STn (C5x #n, mem form) +}; + +/// Decode one C5x instruction from \p buf (\p len bytes) into \p out. +/// Returns the instruction length in bytes, or 0 on an undefined opcode. +RZ_IPI int c5x_decode(const ut8 *buf, int len, C55Insn *out); + +/// id -> C5x mnemonic (delegates to c2x_mnemonic for shared ids). +RZ_IPI const char *c5x_mnemonic(ut16 id); +/// id -> RzAnalysisOp type (delegates to c2x_op_type for shared ids). +RZ_IPI ut32 c5x_op_type(ut16 id); +/// Per-instruction RzIL lifter (delegates to c2x_lift for shared ids). +RZ_IPI RzILOpEffect *c5x_lift(const C55Insn *insn, ut64 pc); + +/// C5x architecture descriptor (own decoder; C2x consumers for shared ids). +extern const C55ArchDesc c5x_arch_desc; + +/// Analysis entry point for the "c5x" CPU (wired into analysis_tms320.c). +RZ_IPI int tms320_c5x_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr, + const ut8 *buf, int len, RzAnalysisOpMask mask); + +/// RzIL VM configuration for the "c5x" CPU (C5x register file). +RZ_IPI RzAnalysisILConfig *tms320_c5x_il_config(RZ_NONNULL RzAnalysis *analysis); + +#ifdef __cplusplus +} +#endif + +#endif /* RZ_TMS320_C5X_H */ diff --git a/librz/arch/isa/tms320/c5x/c5x_decode.c b/librz/arch/isa/tms320/c5x/c5x_decode.c new file mode 100644 index 00000000000..e1804356842 --- /dev/null +++ b/librz/arch/isa/tms320/c5x/c5x_decode.c @@ -0,0 +1,658 @@ +// SPDX-FileCopyrightText: 2026 RizinOrg +// SPDX-License-Identifier: LGPL-3.0-only + +/** + * \file + * TMS320C5x decode front-end (the real C5x object encoding). + * + * The C5x is source-compatible with the C2x but encodes instructions + * differently, so it cannot reuse the C2x decode table. c5x_decode() ports the + * authoritative TMS320C5x opcode table directly and fills the shared C55Insn: + * shared-semantics instructions carry the C2X_INS_* ids (so the C2x lifter, + * op-type and mnemonic tables apply unchanged) and C5x-only instructions carry + * the C5X_INS_* ids handled by c5x.c. + * + * Memory operands use one addressing byte (the low 8 bits of the opcode word): + * bit 7 selects direct (0) or indirect (1). For indirect, bits 6:3 are a 4-bit + * sub-mode (the LSB of which requests a next-ARP load from bits 2:0): 0=*, 2=*-, + * 4=*+, 8=*BR0-, A=*0-, C=*0+, E=*BR0+. Operand order matches the C2x + * convention so the shared consumers render and lift them identically. + */ + +#include "c5x.h" +#include + +static const char *const c5x_indir_raw[16] = { + "*", "*", "*-", "*-", "*+", "*+", "*?", "*?", + "*br0-", "*br0-", "*0-", "*0-", "*0+", "*0+", "*br0+", "*br0+" +}; +static const C55AddrMode c5x_indir_amode[16] = { + C55_AM_INDIRECT, C55_AM_INDIRECT, C55_AM_POSTDEC, C55_AM_POSTDEC, + C55_AM_POSTINC, C55_AM_POSTINC, C55_AM_INDIRECT, C55_AM_INDIRECT, + C55_AM_BITREV_SUB, C55_AM_BITREV_SUB, C55_AM_POSTSUB, C55_AM_POSTSUB, + C55_AM_POSTADD, C55_AM_POSTADD, C55_AM_BITREV, C55_AM_BITREV +}; +static const char *const c5x_arx_raw[8] = { + "ar0", "ar1", "ar2", "ar3", "ar4", "ar5", "ar6", "ar7" +}; + +// A data-memory operand from one addressing byte: direct (DP-relative, in disp) +// or indirect (ARP-relative, rendered via raw). +static void mem_op(C55Operand *out, ut8 low) { + out->kind = C55_OP_MEM; + out->access = 16; + if (low & 0x80) { + ut8 sub = (low >> 3) & 0xf; + out->amode = c5x_indir_amode[sub]; + out->reg.cls = C55_RC_AR; + out->raw = c5x_indir_raw[sub]; + } else { + out->amode = C55_AM_DIRECT; + out->disp = (st32)(low & 0x7f); + } +} + +// The next-ARP operand (rendered ",arN") when an indirect sub-mode is odd. +static bool narp_op(C55Operand *out, ut8 low) { + if ((low & 0x80) && ((low >> 3) & 1)) { + out->kind = C55_OP_REG; + out->reg.cls = C55_RC_AR; + out->reg.num = low & 7; + out->width = 16; + out->raw = c5x_arx_raw[low & 7]; + return true; + } + return false; +} + +static void imm_op(C55Operand *out, ut64 v, ut8 width, bool is_signed) { + out->kind = C55_OP_IMM; + out->imm = v; + out->width = width; + out->imm_signed = is_signed; +} + +static void shift_op(C55Operand *out, ut8 sh) { + out->kind = C55_OP_IMM; + out->imm = sh; + out->width = 16; +} + +static void ar_op(C55Operand *out, ut8 n) { + out->kind = C55_OP_REG; + out->reg.cls = C55_RC_AR; + out->reg.num = n & 7; + out->width = 16; + out->raw = c5x_arx_raw[n & 7]; +} + +// 16-bit absolute branch/call target carried in the trailing word. +static void target_op(C55Operand *out, ut16 t) { + out->kind = C55_OP_IMM; + out->imm = t; + out->width = 16; + out->addr = true; + out->abs_target = true; +} + +// Condition fragments for the 0xE0-0xFF group, rendered verbatim. zl/cv/tp are +// packed across the opcode's high and low nibbles (see the C5x opcode table). +static const char *const c5x_zl[16] = { + "", "gt", "neq", "gt", "", "lt", "neq", "lt", "", "gt", "eq", "geq", "", "lt", "eq", "leq" +}; +static const char *const c5x_cv[16] = { + "", "nc", "nov", "nc nov", "", "c", "nov", "c nov", "", "nc", "ov", "nc ov", "", "c", "ov", "c ov" +}; +static const char *const c5x_tp[4] = { "bio", "tc", "ntc", "" }; + +// Control bits addressed by SETC/CLRC (sub 0x40-0x4f), selected by (sub >> 1). +static const char *const c5x_ctrl_bits[8] = { + "intm", "ovm", "cnf", "sxm", "hold", "tc", "xf", "carry" +}; + +// 16-bit long-immediate ALU forms in the 0xB group, indexed by the low +// nibble; the zero entries are not long-immediate ops. +static const ut16 c5x_long_imm_alu[16] = { + [0x8] = C2X_INS_LALK, [0x9] = C2X_INS_ADLK, [0xa] = C2X_INS_SBLK, [0xb] = C2X_INS_ANDK, [0xc] = C2X_INS_ORK, [0xd] = C2X_INS_XORK +}; + +// Append the active zl/cv/tp condition fragments as verbatim operands. +static void cond_ops(C55Insn *out, ut16 op) { + ut8 zlcvmask = op & 0xf; + ut8 zlcv = (op >> 4) & 0xf; + ut8 zl = (zlcv & 0xc) | ((zlcvmask >> 2) & 3); + ut8 cv = ((zlcv << 2) & 0xc) | (zlcvmask & 3); + ut8 tp = (op >> 8) & 3; + const char *frag[3] = { c5x_zl[zl], c5x_cv[cv], c5x_tp[tp] }; + for (int i = 0; i < 3; i++) { + if (frag[i][0]) { + out->ops[out->n_ops].kind = C55_OP_NONE; + out->ops[out->n_ops].raw = frag[i]; + out->n_ops++; + } + } +} + +#define ID(_id) (out->id = (ut16)(_id)) + +// The BE group (0xBExx): ACCB ops, control bits, 2-word immediates. +static int decode_be(C55Insn *out, ut16 op, ut16 w2) { + ut8 sub = op & 0xff; + switch (sub) { + case 0x00: ID(C2X_INS_ABS); return 2; + case 0x01: ID(C2X_INS_CMPL); return 2; + case 0x02: ID(C2X_INS_NEG); return 2; + case 0x03: ID(C2X_INS_PAC); return 2; + case 0x04: ID(C2X_INS_APAC); return 2; + case 0x05: ID(C2X_INS_SPAC); return 2; + case 0x09: ID(C2X_INS_SFL); return 2; + case 0x0a: ID(C2X_INS_SFR); return 2; + case 0x0c: ID(C2X_INS_ROL); return 2; + case 0x0d: ID(C2X_INS_ROR); return 2; + case 0x10: ID(C5X_INS_ADDB); return 2; + case 0x11: ID(C5X_INS_ADCB); return 2; + case 0x12: ID(C5X_INS_ANDB); return 2; + case 0x13: ID(C5X_INS_ORB); return 2; + case 0x14: ID(C5X_INS_ROLB); return 2; + case 0x15: ID(C5X_INS_RORB); return 2; + case 0x16: ID(C5X_INS_SFLB); return 2; + case 0x17: ID(C5X_INS_SFRB); return 2; + case 0x18: ID(C5X_INS_SBB); return 2; + case 0x19: ID(C5X_INS_SBBB); return 2; + case 0x1a: ID(C5X_INS_XORB); return 2; + case 0x1b: ID(C5X_INS_CRGT); return 2; + case 0x1c: ID(C5X_INS_CRLT); return 2; + case 0x1d: ID(C5X_INS_EXAR); return 2; + case 0x1e: ID(C5X_INS_SACB); return 2; + case 0x1f: ID(C5X_INS_LACB); return 2; + case 0x20: ID(C2X_INS_BACC); return 2; + case 0x21: ID(C5X_INS_BACCD); return 2; + case 0x22: ID(C2X_INS_IDLE); return 2; + case 0x23: ID(C5X_INS_IDLE2); return 2; + case 0x30: ID(C2X_INS_CALA); return 2; + case 0x32: ID(C2X_INS_POP); return 2; + case 0x38: ID(C5X_INS_RETI); return 2; + case 0x3a: ID(C5X_INS_RETE); return 2; + case 0x3c: ID(C2X_INS_PUSH); return 2; + case 0x3d: ID(C5X_INS_CALAD); return 2; + case 0x51: ID(C2X_INS_TRAP); return 2; + case 0x52: ID(C5X_INS_NMI); return 2; + case 0x58: ID(C5X_INS_ZPR); return 2; + case 0x59: ID(C5X_INS_ZAP); return 2; + case 0x5a: ID(C5X_INS_SATH); return 2; + case 0x5b: ID(C5X_INS_SATL); return 2; + default: break; + } + if (sub >= 0x40 && sub <= 0x4f) { + ID((sub & 1) ? C5X_INS_SETC : C5X_INS_CLRC); + out->ops[0].kind = C55_OP_NONE; + out->ops[0].raw = c5x_ctrl_bits[(sub >> 1) & 7]; + out->n_ops = 1; + return 2; + } + if (sub >= 0x60 && sub <= 0x7f) { + ID(C5X_INS_INTR); + imm_op(&out->ops[0], op & 0x1f, 8, false); + out->n_ops = 1; + return 2; + } + switch (sub) { + case 0x80: + ID(C2X_INS_MPY); + imm_op(&out->ops[0], w2, 16, true); + out->n_ops = 1; + return 4; + case 0x81: + ID(C2X_INS_AND); + imm_op(&out->ops[0], w2, 16, false); + out->n_ops = 1; + return 4; + case 0x82: + ID(C2X_INS_OR); + imm_op(&out->ops[0], w2, 16, false); + out->n_ops = 1; + return 4; + case 0x83: + ID(C2X_INS_XOR); + imm_op(&out->ops[0], w2, 16, false); + out->n_ops = 1; + return 4; + case 0xc4: + ID(C2X_INS_RPT); + imm_op(&out->ops[0], w2, 16, false); + out->n_ops = 1; + return 4; + case 0xc5: + ID(C5X_INS_RPTZ); + imm_op(&out->ops[0], w2, 16, false); + out->n_ops = 1; + return 4; + case 0xc6: + ID(C5X_INS_RPTB); + target_op(&out->ops[0], w2); + out->n_ops = 1; + return 4; + default: return 0; + } +} + +// The BF group (0xBFxx): LAR/SPM, CMPR, shifted long-immediate ALU, BSAR. +static int decode_bf(C55Insn *out, ut16 op, ut16 w2) { + ut8 sub = (op >> 4) & 0xf; + ut8 shift = op & 0xf; + if (sub == 0x0) { + if (op & 0x8) { + ID(C2X_INS_LAR); + ar_op(&out->ops[0], op & 7); + imm_op(&out->ops[1], w2, 16, false); + out->n_ops = 2; + return 4; + } + ID(C2X_INS_SPM); + imm_op(&out->ops[0], op & 3, 8, false); + out->n_ops = 1; + return 2; + } + if (sub == 0x4) { + ID(C2X_INS_CMPR); + imm_op(&out->ops[0], op & 3, 8, false); + out->n_ops = 1; + return 2; + } + if (sub == 0xe) { + ID(C5X_INS_BSAR); + imm_op(&out->ops[0], shift + 1, 8, false); + out->n_ops = 1; + return 2; + } + if (c5x_long_imm_alu[sub]) { + ID(c5x_long_imm_alu[sub]); + imm_op(&out->ops[0], w2, 16, false); + out->n_ops = 1; + if (shift) { + shift_op(&out->ops[1], shift); + out->n_ops = 2; + } + return 4; + } + return 0; +} + +// Decode one C5x instruction word (with the following word w2 for 2-word forms). +RZ_IPI int c5x_decode(const ut8 *buf, int len, C55Insn *out) { + if (!buf || !out || len < 2) { + return 0; + } + memset(out, 0, sizeof(*out)); + out->arch = C55_ARCH_C5X; + ut16 op = ((ut16)buf[0] << 8) | buf[1]; + ut16 w2 = (len >= 4) ? (((ut16)buf[2] << 8) | buf[3]) : 0; + ut8 base = (op >> 8) & 0xff; + ut8 low = op & 0xff; + ut8 sh4 = (op >> 8) & 0xf; + ut8 sh3 = (op >> 8) & 7; + ut8 ar = (op >> 8) & 7; + + // mem [shift] [narp]; shift present for the shifted-ALU and store ops. +#define MEM_SHIFT(_id, _sh) \ + do { \ + ID(_id); \ + mem_op(&out->ops[0], low); \ + shift_op(&out->ops[1], (_sh)); \ + out->n_ops = 2; \ + if (narp_op(&out->ops[2], low)) { \ + out->n_ops++; \ + } \ + out->size = 2; \ + return 2; \ + } while (0) + + // mem [narp] +#define MEM_PLAIN(_id) \ + do { \ + ID(_id); \ + mem_op(&out->ops[0], low); \ + out->n_ops = 1; \ + if (narp_op(&out->ops[1], low)) { \ + out->n_ops++; \ + } \ + out->size = 2; \ + return 2; \ + } while (0) + + // mem [narp] #imm16 (2-word forms carrying a trailing long immediate) +#define MEM_IMM2(_id) \ + do { \ + ID(_id); \ + mem_op(&out->ops[0], low); \ + out->n_ops = 1; \ + if (narp_op(&out->ops[1], low)) { \ + out->n_ops++; \ + } \ + imm_op(&out->ops[out->n_ops], w2, 16, false); \ + out->n_ops++; \ + out->size = 4; \ + return 4; \ + } while (0) + + if (base <= 0x07) { // lar arN, mem + ID(C2X_INS_LAR); + ar_op(&out->ops[0], ar); + mem_op(&out->ops[1], low); + out->n_ops = 2; + if (narp_op(&out->ops[2], low)) { + out->n_ops++; + } + out->size = 2; + return 2; + } + switch (base) { + case 0x08: MEM_PLAIN(C5X_INS_LAMM); + case 0x09: MEM_IMM2(C5X_INS_SMMR); + case 0x0a: MEM_PLAIN(C2X_INS_SUBC); + case 0x0b: MEM_PLAIN(C2X_INS_RPT); + case 0x0c: MEM_IMM2(C2X_INS_OUT); + case 0x0d: MEM_PLAIN(C2X_INS_LDP); + case 0x0e: + case 0x0f: { + ID(C5X_INS_LST); + imm_op(&out->ops[0], base & 1, 8, false); + mem_op(&out->ops[1], low); + out->n_ops = 2; + if (narp_op(&out->ops[2], low)) { + out->n_ops++; + } + out->size = 2; + return 2; + } + default: break; + } + if (base >= 0x10 && base <= 0x1f) { + MEM_SHIFT(C5X_INS_LACC, sh4); + } + if (base >= 0x20 && base <= 0x2f) { + MEM_SHIFT(C2X_INS_ADD, sh4); + } + if (base >= 0x30 && base <= 0x3f) { + MEM_SHIFT(C2X_INS_SUB, sh4); + } + if (base >= 0x40 && base <= 0x4f) { // bit code, mem + ID(C2X_INS_BIT); + imm_op(&out->ops[0], sh4, 8, false); + mem_op(&out->ops[1], low); + out->n_ops = 2; + if (narp_op(&out->ops[2], low)) { + out->n_ops++; + } + out->size = 2; + return 2; + } + switch (base) { + case 0x50: MEM_PLAIN(C2X_INS_MPYA); + case 0x51: MEM_PLAIN(C2X_INS_MPYS); + case 0x52: MEM_PLAIN(C2X_INS_SQRA); + case 0x53: MEM_PLAIN(C2X_INS_SQRS); + case 0x54: MEM_PLAIN(C2X_INS_MPY); + case 0x55: MEM_PLAIN(C2X_INS_MPYU); + case 0x57: MEM_PLAIN(C5X_INS_BLDP); + case 0x58: MEM_PLAIN(C5X_INS_XPL); + case 0x59: MEM_PLAIN(C5X_INS_OPL); + case 0x5a: MEM_PLAIN(C5X_INS_APL); + case 0x5b: MEM_PLAIN(C5X_INS_CPL); + case 0x5c: MEM_IMM2(C5X_INS_XPL); + case 0x5d: MEM_IMM2(C5X_INS_OPL); + case 0x5e: MEM_IMM2(C5X_INS_APL); + case 0x5f: MEM_IMM2(C5X_INS_CPL); + case 0x60: MEM_PLAIN(C2X_INS_ADDC); + case 0x61: MEM_SHIFT(C2X_INS_ADD, 16); + case 0x62: MEM_PLAIN(C2X_INS_ADDS); + case 0x63: MEM_PLAIN(C2X_INS_ADDT); + case 0x64: MEM_PLAIN(C2X_INS_SUBB); + case 0x65: MEM_SHIFT(C2X_INS_SUB, 16); + case 0x66: MEM_PLAIN(C2X_INS_SUBS); + case 0x67: MEM_PLAIN(C2X_INS_SUBT); + case 0x68: MEM_PLAIN(C2X_INS_ZALR); + case 0x69: MEM_PLAIN(C5X_INS_LACL); + case 0x6a: MEM_SHIFT(C5X_INS_LACC, 16); + case 0x6b: MEM_PLAIN(C2X_INS_LACT); + case 0x6c: MEM_PLAIN(C2X_INS_XOR); + case 0x6d: MEM_PLAIN(C2X_INS_OR); + case 0x6e: MEM_PLAIN(C2X_INS_AND); + case 0x6f: MEM_PLAIN(C2X_INS_BITT); + case 0x70: MEM_PLAIN(C2X_INS_LTA); + case 0x71: MEM_PLAIN(C2X_INS_LTP); + case 0x72: MEM_PLAIN(C2X_INS_LTD); + case 0x73: MEM_PLAIN(C2X_INS_LT); + case 0x74: MEM_PLAIN(C2X_INS_LTS); + case 0x75: MEM_PLAIN(C2X_INS_LPH); + case 0x76: MEM_PLAIN(C2X_INS_PSHD); + case 0x77: MEM_PLAIN(C2X_INS_DMOV); + default: break; + } + if (base == 0x78 || base == 0x7c) { + ID(base == 0x78 ? C2X_INS_ADRK : C2X_INS_SBRK); + imm_op(&out->ops[0], low, 8, false); + out->n_ops = 1; + out->size = 2; + return 2; + } + { + ut16 brid = 0; + switch (base) { + case 0x79: brid = C2X_INS_B; break; + case 0x7a: brid = C2X_INS_CALL; break; + case 0x7b: brid = C2X_INS_BANZ; break; + case 0x7d: brid = C5X_INS_BD; break; + case 0x7e: brid = C5X_INS_CALLD; break; + case 0x7f: brid = C5X_INS_BANZD; break; + default: break; + } + if (brid) { + ID(brid); + target_op(&out->ops[0], w2); + mem_op(&out->ops[1], low | 0x80); // branch addressing is always indirect + out->n_ops = 2; + if (narp_op(&out->ops[2], low | 0x80)) { + out->n_ops++; + } + out->has_branch = true; + out->branch_target = w2; + out->size = 4; + return 4; + } + } + if (base >= 0x80 && base <= 0x87) { // sar arN, mem + ID(C2X_INS_SAR); + ar_op(&out->ops[0], ar); + mem_op(&out->ops[1], low); + out->n_ops = 2; + if (narp_op(&out->ops[2], low)) { + out->n_ops++; + } + out->size = 2; + return 2; + } + switch (base) { + case 0x88: MEM_PLAIN(C5X_INS_SAMM); + case 0x89: MEM_IMM2(C5X_INS_LMMR); + case 0x8a: MEM_PLAIN(C2X_INS_POPD); + case 0x8b: + if (low == 0) { + ID(C2X_INS_NOP); + out->n_ops = 0; + out->size = 2; + return 2; + } + MEM_PLAIN(C2X_INS_MAR); + case 0x8c: MEM_PLAIN(C2X_INS_SPL); + case 0x8d: MEM_PLAIN(C2X_INS_SPH); + case 0x8e: + case 0x8f: { + ID(C5X_INS_SST); + imm_op(&out->ops[0], base & 1, 8, false); + mem_op(&out->ops[1], low); + out->n_ops = 2; + if (narp_op(&out->ops[2], low)) { + out->n_ops++; + } + out->size = 2; + return 2; + } + default: break; + } + if (base >= 0x90 && base <= 0x97) { + MEM_SHIFT(C2X_INS_SACL, sh3); + } + if (base >= 0x98 && base <= 0x9f) { + MEM_SHIFT(C2X_INS_SACH, sh3); + } + switch (base) { + case 0xa0: MEM_IMM2(C2X_INS_NORM); // norm mem, #w2 (the trailing word is a count/operand) + case 0xa2: MEM_IMM2(C2X_INS_MAC); + case 0xa3: MEM_PLAIN(C2X_INS_MACD); + case 0xa4: MEM_PLAIN(C5X_INS_BLPD); + case 0xa5: MEM_IMM2(C5X_INS_BLPD); + case 0xa6: MEM_PLAIN(C2X_INS_TBLR); + case 0xa7: MEM_PLAIN(C2X_INS_TBLW); + case 0xa8: + case 0xa9: MEM_IMM2(C5X_INS_BLDD); + case 0xaa: MEM_PLAIN(C5X_INS_MADS); + case 0xab: MEM_PLAIN(C5X_INS_MADD); + case 0xac: + case 0xad: MEM_PLAIN(C5X_INS_BLDD); + case 0xae: MEM_IMM2(C5X_INS_SPLK); + case 0xaf: MEM_IMM2(C2X_INS_IN); + default: break; + } + if (base >= 0xb0 && base <= 0xb7) { // lar arN, #imm8 (C2x LARK; rendered "lar") + ID(C2X_INS_LARK); + ar_op(&out->ops[0], ar); + imm_op(&out->ops[1], low, 8, false); + out->n_ops = 2; + out->size = 2; + return 2; + } + switch (base) { + case 0xb8: + ID(C2X_INS_ADDK); + imm_op(&out->ops[0], low, 8, false); + out->n_ops = 1; + out->size = 2; + return 2; + case 0xb9: + ID(C5X_INS_LACL); + imm_op(&out->ops[0], low, 8, false); + out->n_ops = 1; + out->size = 2; + return 2; + case 0xba: + ID(C2X_INS_SUBK); + imm_op(&out->ops[0], low, 8, false); + out->n_ops = 1; + out->size = 2; + return 2; + case 0xbb: + ID(C2X_INS_RPTK); + imm_op(&out->ops[0], low, 8, false); + out->n_ops = 1; + out->size = 2; + return 2; + case 0xbc: + case 0xbd: + ID(C2X_INS_LDPK); + imm_op(&out->ops[0], op & 0x1ff, 16, false); + out->n_ops = 1; + out->size = 2; + return 2; + case 0xbe: { + int r = decode_be(out, op, w2); + if (r) { + out->size = (ut8)r; + } + return r; + } + case 0xbf: { + int r = decode_bf(out, op, w2); + if (r) { + out->size = (ut8)r; + } + return r; + } + default: break; + } + if (base >= 0xc0 && base <= 0xdf) { + return 0; // undefined opcode range + } + // 0xE0-0xFF: conditional branch / call / return / execute group. + if (base >= 0xe0 && base <= 0xe3) { + ID(C5X_INS_BCND); + target_op(&out->ops[0], w2); + out->n_ops = 1; + cond_ops(out, op); + out->has_branch = true; + out->branch_target = w2; + out->size = 4; + return 4; + } + if ((base >= 0xe4 && base <= 0xe7) || (base >= 0xf4 && base <= 0xf7)) { + ID(C5X_INS_XC); + imm_op(&out->ops[0], ((op >> 12) & 1) + 1, 8, false); + out->n_ops = 1; + cond_ops(out, op); + out->size = 2; + return 2; + } + if (base >= 0xe8 && base <= 0xeb) { + ID(C5X_INS_CC); + target_op(&out->ops[0], w2); + out->n_ops = 1; + cond_ops(out, op); + out->has_branch = true; + out->branch_target = w2; + out->size = 4; + return 4; + } + if (base >= 0xec && base <= 0xef) { + if (op == 0xef00) { + ID(C2X_INS_RET); + out->size = 2; + return 2; + } + ID(C5X_INS_RETC); + cond_ops(out, op); + out->size = 2; + return 2; + } + if (base >= 0xf0 && base <= 0xf3) { + ID(C5X_INS_BCNDD); + target_op(&out->ops[0], w2); + out->n_ops = 1; + cond_ops(out, op); + out->has_branch = true; + out->branch_target = w2; + out->size = 4; + return 4; + } + if (base >= 0xf8 && base <= 0xfb) { + ID(C5X_INS_CCD); + target_op(&out->ops[0], w2); + out->n_ops = 1; + cond_ops(out, op); + out->has_branch = true; + out->branch_target = w2; + out->size = 4; + return 4; + } + if (base >= 0xfc && base <= 0xff) { + if (op == 0xff00) { + ID(C5X_INS_RETD); // unconditional delayed return + out->size = 2; + return 2; + } + ID(C5X_INS_RETCD); + cond_ops(out, op); + out->size = 2; + return 2; + } + return 0; +} diff --git a/librz/arch/isa/tms320/c5x/c5x_il.c b/librz/arch/isa/tms320/c5x/c5x_il.c new file mode 100644 index 00000000000..55df4267243 --- /dev/null +++ b/librz/arch/isa/tms320/c5x/c5x_il.c @@ -0,0 +1,141 @@ +// SPDX-FileCopyrightText: 2026 RizinOrg +// SPDX-License-Identifier: LGPL-3.0-only + +/** + * \file + * TMS320C5x mnemonic, op-type and RzIL lifter. + * + * Shared-semantics instructions carry the C2X_INS_* ids and are handled by the + * C2x consumers; this file only adds the C5x-only ids (the C5X_INS_* enum) and + * the few shared ids whose C5x mnemonic differs from the C2x spelling (the + * immediate forms add/sub/lar/rpt/ldp). The lifter reuses the C2x lifter for + * the shared ids and for C5x-only ops that are semantically a renamed C2x op + * (LACC == LAC, the delayed branches == their non-delayed forms); the remaining + * C5x-only core ops (ACCB loads/logical, ZAP/ZPR, SETC/CLRC, SPLK) are lifted + * here. C5x-only ops with effects the per-instruction RzIL cannot model cleanly + * (conditional control transfers, block moves, parallel-logic, memory-mapped + * register access, the MAC fetch forms) are decoded and analysed but left + * without IL, exactly as the C2x leaves RPT/RPTK. + */ + +#include "c5x.h" +#include + +// A single 0/1 flag write helper for SETC/CLRC. +static RzILOpEffect *c5x_set_flag(const char *name, bool set) { + return SETG(name, set ? IL_TRUE : IL_FALSE); +} + +// AR[ARP] resolved at run time (mirrors the C2x model), for the page-0 / direct +// access of the simple C5x-only ops lifted here. +static const char *const c5x_ar[8] = { + "ar0", "ar1", "ar2", "ar3", "ar4", "ar5", "ar6", "ar7" +}; +static RzILOpPure *c5x_ind_addr(void) { + RzILOpPure *v = VARG("ar7"); + for (int k = 6; k >= 0; k--) { + v = ITE(EQ(VARG("arp"), UN(16, (ut32)k)), VARG(c5x_ar[k]), v); + } + return v; +} +static RzILOpPure *c5x_addr(const C55Operand *m) { + if (m->amode == C55_AM_DIRECT) { + RzILOpPure *page = SHIFTL0(LOGAND(VARG("dp"), UN(16, 0x1ff)), UN(16, 7)); + return LOGOR(page, UN(16, (ut32)m->disp & 0x7f)); + } + return c5x_ind_addr(); +} +// Scale a word address to the byte-addressed IL VM space (see the C2x notes on +// C2X_WORD_BYTES / C2X_MEM_ADDR_BITS; the C5x shares that memory model). +static RzILOpPure *c5x_byte(RzILOpPure *word_addr) { + return MUL(UNSIGNED(C2X_MEM_ADDR_BITS, word_addr), UN(C2X_MEM_ADDR_BITS, C2X_WORD_BYTES)); +} +static RzILOpPure *c5x_mem_read(const C55Operand *m) { + return LOADW(16, c5x_byte(c5x_addr(m))); +} +static RzILOpEffect *c5x_mem_write(const C55Operand *m, RzILOpPure *val) { + return STOREW(c5x_byte(c5x_addr(m)), val); +} + +RZ_IPI RzILOpEffect *c5x_lift(const C55Insn *insn, ut64 pc) { + // Shared-semantics ops, and C5x-only ops that are a renamed C2x op, are + // lifted by the C2x lifter after mapping the id to its C2x equivalent. + ut16 cid = 0; + switch (insn->id) { + case C5X_INS_LACC: cid = C2X_INS_LAC; break; + case C5X_INS_BD: cid = C2X_INS_B; break; + case C5X_INS_CALLD: cid = C2X_INS_CALL; break; + case C5X_INS_BANZD: cid = C2X_INS_BANZ; break; + case C5X_INS_BACCD: cid = C2X_INS_BACC; break; + case C5X_INS_CALAD: cid = C2X_INS_CALA; break; + case C5X_INS_RETE: + case C5X_INS_RETI: + case C5X_INS_RETD: cid = C2X_INS_RET; break; + default: break; + } + if (cid) { + C55Insn tmp = *insn; + tmp.id = cid; + return c2x_lift(&tmp, pc); + } + + switch (insn->id) { + case C5X_INS_LACL: + // load ACC with a zero-extended 16-bit memory word or 8-bit immediate + if (insn->ops[0].kind == C55_OP_IMM) { + return SETG("acc", UN(32, (ut32)insn->ops[0].imm & 0xff)); + } + return SETG("acc", UNSIGNED(32, c5x_mem_read(&insn->ops[0]))); + case C5X_INS_LACB: + return SETG("acc", VARG("accb")); + case C5X_INS_SACB: + return SETG("accb", VARG("acc")); + case C5X_INS_EXAR: + return SEQ3(SETL("t", VARG("acc")), SETG("acc", VARG("accb")), + SETG("accb", VARL("t"))); + case C5X_INS_ANDB: + return SETG("acc", LOGAND(VARG("acc"), VARG("accb"))); + case C5X_INS_ORB: + return SETG("acc", LOGOR(VARG("acc"), VARG("accb"))); + case C5X_INS_XORB: + return SETG("acc", LOGXOR(VARG("acc"), VARG("accb"))); + case C5X_INS_ZAP: + return SEQ2(SETG("acc", UN(32, 0)), SETG("p", UN(32, 0))); + case C5X_INS_ZPR: + return SETG("p", UN(32, 0)); + case C5X_INS_SPLK: + // store a long immediate constant to the memory operand + return c5x_mem_write(&insn->ops[0], UN(16, (ut32)insn->ops[insn->n_ops - 1].imm & 0xffff)); + case C5X_INS_SETC: + case C5X_INS_CLRC: { + // only the control bits with a dedicated IL flag are modelled + const char *r = insn->ops[0].raw; + bool set = (insn->id == C5X_INS_SETC); + if (!r) { + return NULL; + } + if (!strcmp(r, "ovm")) { + return c5x_set_flag("ovm", set); + } + if (!strcmp(r, "sxm")) { + return c5x_set_flag("sxm", set); + } + if (!strcmp(r, "carry")) { + return c5x_set_flag("c", set); + } + if (!strcmp(r, "tc")) { + return c5x_set_flag("tc", set); + } + return NULL; // intm/cnf/xf/hold: no dedicated IL state + } + default: + break; + } + + // Shared ids -> the C2x lifter. C5x-only ops not handled above are decoded + // and analysed but intentionally left without IL. + if (insn->id < C5X_INS_BASE) { + return c2x_lift(insn, pc); + } + return NULL; +} diff --git a/librz/arch/meson.build b/librz/arch/meson.build index 7d86bee3b17..e867f4a7f2e 100644 --- a/librz/arch/meson.build +++ b/librz/arch/meson.build @@ -321,6 +321,11 @@ arch_isa_sources = [ 'isa/tms320/c55_ir.c', 'isa/tms320/c54x/c54x.c', 'isa/tms320/c54x/c54x_il.c', + 'isa/tms320/c2x/c2x.c', + 'isa/tms320/c2x/c2x_il.c', + 'isa/tms320/c5x/c5x.c', + 'isa/tms320/c5x/c5x_decode.c', + 'isa/tms320/c5x/c5x_il.c', 'isa/tms320/c55x_plus/c55plus_arch.c', 'isa/tms320/c55x/c55x_analysis.c', 'isa/tms320/c55x_plus/c55plus_analysis.c', diff --git a/librz/arch/p/analysis/analysis_tms320.c b/librz/arch/p/analysis/analysis_tms320.c index bce401a8126..fbf3cfc8d35 100644 --- a/librz/arch/p/analysis/analysis_tms320.c +++ b/librz/arch/p/analysis/analysis_tms320.c @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include typedef struct tms320_ctx_t { @@ -25,6 +27,10 @@ int tms320_analysis_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr, const return tms320_c64x_op(analysis, op, addr, buf, len, mask, context->c64x); } else if (cpu && rz_str_casecmp(cpu, "c54x") == 0) { return tms320_c54x_op(analysis, op, addr, buf, len, mask); + } else if (cpu && rz_str_casecmp(cpu, "c2x") == 0) { + return tms320_c2x_op(analysis, op, addr, buf, len, mask); + } else if (cpu && rz_str_casecmp(cpu, "c5x") == 0) { + return tms320_c5x_op(analysis, op, addr, buf, len, mask); } return tms320_c55x_op_byte(analysis, op, addr, buf, len, mask); } @@ -109,6 +115,122 @@ static char *get_reg_profile(RZ_BORROW RzAnalysis *a) { "ctr xpc .16 52 0 # Extended program counter\n" "ctr pc .24 54 0 # Program counter\n"); } + if (cpu0 && rz_str_casecmp(cpu0, "c2x") == 0) { + // TMS320C2x: a single 32-bit accumulator ACC (with ACCL/ACCH 16-bit + // halves overlapping it), the 16-bit temporary T, the 32-bit product + // register P (PL/PH halves), eight 16-bit auxiliary registers AR0-AR7, + // the 3-bit ARP pointer (held in a 16-bit slot), the 9-bit DP data page, + // the ST0/ST1 status words and a 16-bit PC. SP is a synthetic stack + // pointer (the hardware stack is not memory-mapped). These names match + // c2x_reg_info()'s il_var bindings so the lifter resolves in the IL VM. + return rz_str_dup( + "=PC\tpc\n" + "=SP\tsp\n" + "=BP\tsp\n" + "=A0\tar0\n" + "=A1\tar1\n" + "=A2\tar2\n" + "=A3\tar3\n" + "=R0\tacc\n" + "ctr acc .32 0 0 # Accumulator\n" + "gpr accl .16 0 0 # Accumulator low word\n" + "gpr acch .16 2 0 # Accumulator high word\n" + "ctr t .16 4 0 # Temporary register\n" + "ctr p .32 6 0 # Product register\n" + "gpr pl .16 6 0 # Product low word\n" + "gpr ph .16 8 0 # Product high word\n" + "gpr ar0 .16 10 0 # Auxiliary register 0\n" + "gpr ar1 .16 12 0 # Auxiliary register 1\n" + "gpr ar2 .16 14 0 # Auxiliary register 2\n" + "gpr ar3 .16 16 0 # Auxiliary register 3\n" + "gpr ar4 .16 18 0 # Auxiliary register 4\n" + "gpr ar5 .16 20 0 # Auxiliary register 5\n" + "gpr ar6 .16 22 0 # Auxiliary register 6\n" + "gpr ar7 .16 24 0 # Auxiliary register 7\n" + "ctr arp .16 26 0 # Auxiliary register pointer\n" + "ctr dp .16 28 0 # Data page pointer\n" + "ctr st0 .16 30 0 # Status register 0\n" + "ctr st1 .16 32 0 # Status register 1\n" + "ctr sp .16 34 0 # Stack pointer (synthetic)\n" + "ctr pc .16 36 0 # Program counter\n" + // status/mode bits modelled individually for the IL lifter (they + // also live inside ST0/ST1 on real silicon; ST0/ST1 are composed + // from / decomposed to these by SST/SST1/LST/LST1) + "flg c .1 38.0 0 # Carry\n" + "flg ov .1 39.0 0 # Overflow (sticky until tested)\n" + "flg tc .1 40.0 0 # Test/control bit\n" + "gpr ovm .1 41.0 0 # Overflow saturation mode\n" + "gpr sxm .1 42.0 0 # Sign-extension mode\n" + "gpr pm .2 43.0 0 # Product shift mode\n" + "gpr arb .16 44 0 # Auxiliary register pointer backup\n" + "gpr rptc .16 46 0 # Repeat counter\n"); + } + if (cpu0 && rz_str_casecmp(cpu0, "c5x") == 0) { + // TMS320C5x: the C2x register file plus the C5x additions — the 32-bit + // accumulator buffer ACCB, the TREG1/TREG2 multiplier/shift registers, + // the processor-mode status PMST, the index register INDX, the + // auxiliary-compare register ARCR, the circular-buffer start/end + // pointers CBSR1/CBER1/CBSR2/CBER2, the block-repeat registers + // BRCR/PASR/PAER, the block-move address BMAR, the dynamic bit-mask + // DBMR and the global-memory register GREG. The core names match the + // C2x lifter's il_var bindings (the C5x lifter reuses it). + return rz_str_dup( + "=PC\tpc\n" + "=SP\tsp\n" + "=BP\tsp\n" + "=A0\tar0\n" + "=A1\tar1\n" + "=A2\tar2\n" + "=A3\tar3\n" + "=R0\tacc\n" + "ctr acc .32 0 0 # Accumulator\n" + "gpr accl .16 0 0 # Accumulator low word\n" + "gpr acch .16 2 0 # Accumulator high word\n" + "ctr accb .32 4 0 # Accumulator buffer\n" + "ctr t .16 8 0 # Temporary/multiplicand register (TREG0)\n" + "ctr treg1 .16 10 0 # TREG1 (dynamic shift count)\n" + "ctr treg2 .16 12 0 # TREG2 (dynamic bit position)\n" + "ctr p .32 14 0 # Product register\n" + "gpr pl .16 14 0 # Product low word\n" + "gpr ph .16 16 0 # Product high word\n" + "gpr ar0 .16 18 0 # Auxiliary register 0\n" + "gpr ar1 .16 20 0 # Auxiliary register 1\n" + "gpr ar2 .16 22 0 # Auxiliary register 2\n" + "gpr ar3 .16 24 0 # Auxiliary register 3\n" + "gpr ar4 .16 26 0 # Auxiliary register 4\n" + "gpr ar5 .16 28 0 # Auxiliary register 5\n" + "gpr ar6 .16 30 0 # Auxiliary register 6\n" + "gpr ar7 .16 32 0 # Auxiliary register 7\n" + "ctr arp .16 34 0 # Auxiliary register pointer\n" + "ctr dp .16 36 0 # Data page pointer\n" + "ctr st0 .16 38 0 # Status register 0\n" + "ctr st1 .16 40 0 # Status register 1\n" + "ctr pmst .16 42 0 # Processor mode status register\n" + "ctr indx .16 44 0 # Index register\n" + "ctr arcr .16 46 0 # Auxiliary register compare register\n" + "ctr cbsr1 .16 48 0 # Circular buffer 1 start address\n" + "ctr cber1 .16 50 0 # Circular buffer 1 end address\n" + "ctr cbsr2 .16 52 0 # Circular buffer 2 start address\n" + "ctr cber2 .16 54 0 # Circular buffer 2 end address\n" + "ctr brcr .16 56 0 # Block repeat counter register\n" + "ctr pasr .16 58 0 # Block repeat program address start\n" + "ctr paer .16 60 0 # Block repeat program address end\n" + "ctr bmar .16 62 0 # Block move address register\n" + "ctr dbmr .16 64 0 # Dynamic bit manipulation register\n" + "ctr greg .16 66 0 # Global memory allocation register\n" + "ctr sp .16 68 0 # Stack pointer (synthetic)\n" + "ctr pc .16 70 0 # Program counter\n" + // status/mode bits modelled individually for the shared C2x-core + // lifter (they also live inside ST0/ST1 on silicon) + "flg c .1 72.0 0 # Carry\n" + "flg ov .1 73.0 0 # Overflow (sticky until tested)\n" + "flg tc .1 74.0 0 # Test/control bit\n" + "gpr ovm .1 75.0 0 # Overflow saturation mode\n" + "gpr sxm .1 76.0 0 # Sign-extension mode\n" + "gpr pm .2 77.0 0 # Product shift mode\n" + "gpr arb .16 78 0 # Auxiliary register pointer backup\n" + "gpr rptc .16 80 0 # Repeat counter\n"); + } if (is_c5000(rz_analysis_get_cpu(a))) { p = "=PC pc\n" @@ -451,13 +573,19 @@ static RzAnalysisILConfig *tms320_il_config(RzAnalysis *analysis) { if (cpu && rz_str_casecmp(cpu, "c54x") == 0) { return tms320_c54x_il_config(analysis); } + if (cpu && rz_str_casecmp(cpu, "c2x") == 0) { + return tms320_c2x_il_config(analysis); + } + if (cpu && rz_str_casecmp(cpu, "c5x") == 0) { + return tms320_c5x_il_config(analysis); + } return NULL; } RzAnalysisPlugin rz_analysis_plugin_tms320 = { .name = "tms320", .arch = "tms320", - .bits = 32, + .bits = 16 | 32, .desc = "TMS320 DSP family code analysis plugin", .init = tms320_analysis_init, .fini = tms320_analysis_fini, diff --git a/librz/arch/p/asm/asm_tms320.c b/librz/arch/p/asm/asm_tms320.c index 165c68b82e9..8d8184c8dd3 100644 --- a/librz/arch/p/asm/asm_tms320.c +++ b/librz/arch/p/asm/asm_tms320.c @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include typedef struct tms_cs_context_t { @@ -28,13 +30,24 @@ static int tms320_disassemble(const RzAsm *a, RzAsmOp *op, const ut8 *buf, int l desc = &c55x_arch_desc; } else if (a->cpu && !rz_str_casecmp(a->cpu, "c54x")) { desc = &c54x_arch_desc; + } else if (a->cpu && !rz_str_casecmp(a->cpu, "c2x")) { + desc = &c2x_arch_desc; + } else if (a->cpu && !rz_str_casecmp(a->cpu, "c5x")) { + desc = &c5x_arch_desc; } else { rz_asm_op_set_asm(op, "unknown asm.cpu"); return op->size = -1; } if (desc) { C55Insn insn; - if (c55_decode(desc, buf, len, &insn)) { + bool ok; + if (desc == &c5x_arch_desc) { + // The C5x has its own decode front-end (real C5x encoding). + ok = c5x_decode(buf, len, &insn) > 0; + } else { + ok = c55_decode(desc, buf, len, &insn); + } + if (ok) { char *s = c55_format(desc, &insn); if (s) { rz_asm_op_set_asm(op, s); @@ -76,6 +89,8 @@ static char *tms320_mnemonics(const RzAsm *a, int id, bool json) { static char **tms320_cpu_descriptions() { static char *cpu_desc[] = { "c54x", "Texas Instruments TMS320C54x DSP family", + "c2x", "Texas Instruments TMS320C2x legacy fixed-point DSP family", + "c5x", "Texas Instruments TMS320C5x fixed-point DSP family (C2x-compatible superset)", "c55x", "Texas Instruments TMS320C55x DSP family", "c55x+", "Texas Instruments TMS320C55x+ DSP family", "c64x", "Texas Instruments TMS320C64x DSP family", @@ -87,10 +102,10 @@ static char **tms320_cpu_descriptions() { RzAsmPlugin rz_asm_plugin_tms320 = { .name = "tms320", .arch = "tms320", - .cpus = "c54x,c55x,c55x+,c64x", - .desc = "Texas Instruments TMS320 DSP family (c54x,c55x,c55x+,c64x) disassembler", + .cpus = "c54x,c55x,c55x+,c2x,c5x,c64x", + .desc = "Texas Instruments TMS320 DSP family (c54x,c55x,c55x+,c2x,c5x,c64x) disassembler", .license = "LGPL3", - .bits = 32, + .bits = 16 | 32, .endian = RZ_SYS_ENDIAN_LITTLE | RZ_SYS_ENDIAN_BIG, .init = tms320_init, .fini = tms320_fini, diff --git a/librz/arch/types/cc-tms320-16.sdb.txt b/librz/arch/types/cc-tms320-16.sdb.txt new file mode 100644 index 00000000000..df0b0fa0a5f --- /dev/null +++ b/librz/arch/types/cc-tms320-16.sdb.txt @@ -0,0 +1,19 @@ +default.cc=c2x + +c2x=cc +cc.c2x.arg0=ar0 +cc.c2x.arg1=ar1 +cc.c2x.arg2=ar2 +cc.c2x.arg3=ar3 +cc.c2x.argn=stack +cc.c2x.maxargs=4 +cc.c2x.ret=acc + +c5x=cc +cc.c5x.arg0=ar0 +cc.c5x.arg1=ar1 +cc.c5x.arg2=ar2 +cc.c5x.arg3=ar3 +cc.c5x.argn=stack +cc.c5x.maxargs=4 +cc.c5x.ret=acc diff --git a/librz/arch/types/meson.build b/librz/arch/types/meson.build index dc979005b15..0c6a3313462 100644 --- a/librz/arch/types/meson.build +++ b/librz/arch/types/meson.build @@ -13,6 +13,7 @@ sdb_types_files = [ 'cc-sparc-32', 'cc-spc700-16', 'cc-sysz-64', + 'cc-tms320-16', 'cc-tms320-32', 'cc-tricore-32', 'cc-x86-16', diff --git a/librz/bin/format/coff/coff.c b/librz/bin/format/coff/coff.c index ea3b095efd7..2ea35e8d501 100644 --- a/librz/bin/format/coff/coff.c +++ b/librz/bin/format/coff/coff.c @@ -91,6 +91,11 @@ static bool coff_is_magic(ut16 arch) { /* fall-thru */ case COFF_FILE_MACHINE_TI_2: /* fall-thru */ + case COFF_FILE_TARGET_TI_TMS320C1x2x5x: + /* first-generation TI fixed-point COFF (C1x/C2x/C5x): the target id + * doubles as the file magic, unlike the later COFF1/COFF2 (0xc1/0xc2) + * which carry a separate target id field. */ + /* fall-thru */ case COFF_FILE_MACHINE_MIL1750: return true; default: diff --git a/librz/bin/format/coff/coff_specs.h b/librz/bin/format/coff/coff_specs.h index 672c7658e5b..3c92a5b81bf 100644 --- a/librz/bin/format/coff/coff_specs.h +++ b/librz/bin/format/coff/coff_specs.h @@ -49,6 +49,7 @@ #define COFF_FILE_MACHINE_TI_2 0x00c2 #define COFF_FILE_MACHINE_MIL1750 0x00db +#define COFF_FILE_TARGET_TI_TMS320C1x2x5x 0x0092 #define COFF_FILE_TARGET_TI_TMS320C3x4x 0x0093 #define COFF_FILE_TARGET_TI_TMS470 0x0097 #define COFF_FILE_TARGET_TI_TMS320C5400 0x0098 diff --git a/librz/bin/p/bin_coff.c b/librz/bin/p/bin_coff.c index 8f137e5ff6c..061cc59a1a3 100644 --- a/librz/bin/p/bin_coff.c +++ b/librz/bin/p/bin_coff.c @@ -640,10 +640,31 @@ static RzBinInfo *coff_info(RzBinFile *bf) { ret->cpu = rz_str_dup("r10000"); ret->bits = 32; break; + case COFF_FILE_TARGET_TI_TMS320C1x2x5x: + // Legacy first-generation TI fixed-point COFF (COFF0 style): the magic + // IS the target id (no separate target_id field, unlike COFF1/COFF2). + // Shared by the C1x/C2x/C5x assemblers; default to the C2x disassembler + // (override with -c c5x for a C5x image). + ret->machine = rz_str_dup("TMS320C1x/C2x/C5x"); + ret->cpu = rz_str_dup("c2x"); + ret->arch = rz_str_dup("tms320"); + ret->bits = 16; + break; case COFF_FILE_MACHINE_TI_1: /* fall-thru */ case COFF_FILE_MACHINE_TI_2: switch (obj->target_id) { + case COFF_FILE_TARGET_TI_TMS320C1x2x5x: + // First-generation TI fixed-point COFF id, shared by the TMS320C1x/ + // C2x/C5x assemblers. Map it to the legacy single-accumulator C2x + // disassembler by default; override with -c for a C5x image. (The + // id is rarely present on raw firmware dumps; verify on real object + // files before relying on autodetection.) + ret->machine = rz_str_dup("TMS320C1x/C2x/C5x"); + ret->cpu = rz_str_dup("c2x"); + ret->arch = rz_str_dup("tms320"); + ret->bits = 16; + break; case COFF_FILE_TARGET_TI_TMS320C3x4x: ret->machine = rz_str_dup("TMS320C3x/4x"); /* TMS320C3x/C4x is a floating-point DSP family that diff --git a/test/db/analysis/tms320.c2x_16 b/test/db/analysis/tms320.c2x_16 new file mode 100644 index 00000000000..0f932afc6f0 --- /dev/null +++ b/test/db/analysis/tms320.c2x_16 @@ -0,0 +1,148 @@ +NAME=c2x analysis: register profile (PC alias resolves) +FILE== +CMDS=<> (var p) (bv 6 0x6) (msb (var p))))))) +EOF +RUN diff --git a/test/db/asm/tms320_c2x_16 b/test/db/asm/tms320_c2x_16 new file mode 100644 index 00000000000..4128482d71a --- /dev/null +++ b/test/db/asm/tms320_c2x_16 @@ -0,0 +1,118 @@ +# TMS320C2x (legacy single-accumulator fixed-point) disassembly + RzIL. +# Encodings are MSB-first 16-bit words (4-byte forms are two words). +# Vectors derive from the public C2x instruction set (MAME TMS320x25 map). +# IL is asserted only for the lifted core; indirect-addressed and +# carry/status-dependent forms decode but carry no IL yet. + +# no-operand control / status (CE block) +d "nop" 5500 0x0 nop +d "eint" ce00 0x0 nop +d "dint" ce01 0x0 nop +d "rovm" ce02 0x0 (set ovm false) +d "sovm" ce03 0x0 (set ovm true) +d "ssxm" ce07 0x0 (set sxm true) +d "abs" ce1b 0x0 (seq (set acc (ite (&& (sle (var acc) (bv 32 0x0)) (! (== (var acc) (bv 32 0x0)))) (~- (var acc)) (var acc))) (set c false)) +d "push" ce1c 0x0 (seq (set sp (- (var sp) (bv 16 0x1))) (storew 0 (* (cast 24 false (var sp)) (bv 24 0x2)) (cast 16 false (var acc)))) +d "pop" ce1d 0x0 (seq (set acc (cast 32 false (loadw 0 16 (* (cast 24 false (var sp)) (bv 24 0x2))))) (set sp (+ (var sp) (bv 16 0x1)))) +d "ret" ce26 0x0 (seq (set r (loadw 0 16 (* (cast 24 false (var sp)) (bv 24 0x2)))) (set sp (+ (var sp) (bv 16 0x1))) (jmp (var r))) +d "conf #0x0" ce3c 0x0 nop +d "conf #0x3" ce3f 0x0 nop +d "cala" ce24 0x0 (seq (set sp (- (var sp) (bv 16 0x1))) (storew 0 (* (cast 24 false (var sp)) (bv 24 0x2)) (bv 16 0x1)) (jmp (* (cast 16 false (var acc)) (bv 16 0x2)))) +d "bacc" ce25 0x0 (jmp (* (cast 16 false (var acc)) (bv 16 0x2))) +d "pac" ce14 0x0 (set acc (ite (== (var pm) (bv 2 0x0)) (var p) (ite (== (var pm) (bv 2 0x1)) (<< (var p) (bv 6 0x1) false) (ite (== (var pm) (bv 2 0x2)) (<< (var p) (bv 6 0x4) false) (>> (var p) (bv 6 0x6) (msb (var p))))))) +d "apac" ce15 0x0 (seq (set oa (var acc)) (set av (ite (== (var pm) (bv 2 0x0)) (var p) (ite (== (var pm) (bv 2 0x1)) (<< (var p) (bv 6 0x1) false) (ite (== (var pm) (bv 2 0x2)) (<< (var p) (bv 6 0x4) false) (>> (var p) (bv 6 0x6) (msb (var p))))))) (set na (+ (var oa) (var av))) (set ovn (msb (& (^ (var na) (var av)) (^ (var oa) (var na))))) (set acc (ite (&& (var ovm) (var ovn)) (ite (&& (sle (var oa) (bv 32 0x0)) (! (== (var oa) (bv 32 0x0)))) (bv 32 0x80000000) (bv 32 0x7fffffff)) (var na))) (set c (&& (ule (var na) (var oa)) (! (== (var na) (var oa))))) (set ov (|| (var ov) (var ovn)))) +d "spac" ce16 0x0 (seq (set oa (var acc)) (set av (ite (== (var pm) (bv 2 0x0)) (var p) (ite (== (var pm) (bv 2 0x1)) (<< (var p) (bv 6 0x1) false) (ite (== (var pm) (bv 2 0x2)) (<< (var p) (bv 6 0x4) false) (>> (var p) (bv 6 0x6) (msb (var p))))))) (set na (- (var oa) (var av))) (set ovn (msb (& (^ (var oa) (var av)) (^ (var oa) (var na))))) (set acc (ite (&& (var ovm) (var ovn)) (ite (&& (sle (var oa) (bv 32 0x0)) (! (== (var oa) (bv 32 0x0)))) (bv 32 0x80000000) (bv 32 0x7fffffff)) (var na))) (set c (! (&& (ule (var oa) (var na)) (! (== (var oa) (var na)))))) (set ov (|| (var ov) (var ovn)))) + +# accumulator immediates +d "zac" ca00 0x0 (set acc (bv 32 0x0)) +d "lack #0x5" ca05 0x0 (set acc (bv 32 0x5)) +d "addk #0x2" cc02 0x0 (seq (set oa (var acc)) (set av (bv 32 0x2)) (set na (+ (var oa) (var av))) (set ovn (msb (& (^ (var na) (var av)) (^ (var oa) (var na))))) (set acc (ite (&& (var ovm) (var ovn)) (ite (&& (sle (var oa) (bv 32 0x0)) (! (== (var oa) (bv 32 0x0)))) (bv 32 0x80000000) (bv 32 0x7fffffff)) (var na))) (set c (&& (ule (var na) (var oa)) (! (== (var na) (var oa))))) (set ov (|| (var ov) (var ovn)))) +d "subk #0x3" cd03 0x0 (seq (set oa (var acc)) (set av (bv 32 0x3)) (set na (- (var oa) (var av))) (set ovn (msb (& (^ (var oa) (var av)) (^ (var oa) (var na))))) (set acc (ite (&& (var ovm) (var ovn)) (ite (&& (sle (var oa) (bv 32 0x0)) (! (== (var oa) (bv 32 0x0)))) (bv 32 0x80000000) (bv 32 0x7fffffff)) (var na))) (set c (! (&& (ule (var oa) (var na)) (! (== (var oa) (var na)))))) (set ov (|| (var ov) (var ovn)))) +d "ldpk #0x1" c801 0x0 (set dp (bv 16 0x1)) +d "lark ar0, #0x10" c010 0x0 (set ar0 (bv 16 0x10)) +d "lark ar3, #0x7f" c37f 0x0 (set ar3 (bv 16 0x7f)) +d "mpyk #0x100" a100 0x0 (set p (* (cast 32 (msb (var t)) (var t)) (bv 32 0x100))) + +# direct (DP-relative) data-memory forms +d "add 0x9, #0x0" 0009 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x9))) (bv 24 0x2)))) (set oa (var acc)) (set av (ite (var sxm) (cast 32 (msb (var m)) (var m)) (cast 32 false (var m)))) (set na (+ (var oa) (var av))) (set ovn (msb (& (^ (var na) (var av)) (^ (var oa) (var na))))) (set acc (ite (&& (var ovm) (var ovn)) (ite (&& (sle (var oa) (bv 32 0x0)) (! (== (var oa) (bv 32 0x0)))) (bv 32 0x80000000) (bv 32 0x7fffffff)) (var na))) (set c (&& (ule (var na) (var oa)) (! (== (var na) (var oa))))) (set ov (|| (var ov) (var ovn)))) +d "add 0x9, #0x4" 0409 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x9))) (bv 24 0x2)))) (set oa (var acc)) (set av (<< (ite (var sxm) (cast 32 (msb (var m)) (var m)) (cast 32 false (var m))) (bv 6 0x4) false)) (set na (+ (var oa) (var av))) (set ovn (msb (& (^ (var na) (var av)) (^ (var oa) (var na))))) (set acc (ite (&& (var ovm) (var ovn)) (ite (&& (sle (var oa) (bv 32 0x0)) (! (== (var oa) (bv 32 0x0)))) (bv 32 0x80000000) (bv 32 0x7fffffff)) (var na))) (set c (&& (ule (var na) (var oa)) (! (== (var na) (var oa))))) (set ov (|| (var ov) (var ovn)))) +d "sub 0x20, #0x0" 1020 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x20))) (bv 24 0x2)))) (set oa (var acc)) (set av (ite (var sxm) (cast 32 (msb (var m)) (var m)) (cast 32 false (var m)))) (set na (- (var oa) (var av))) (set ovn (msb (& (^ (var oa) (var av)) (^ (var oa) (var na))))) (set acc (ite (&& (var ovm) (var ovn)) (ite (&& (sle (var oa) (bv 32 0x0)) (! (== (var oa) (bv 32 0x0)))) (bv 32 0x80000000) (bv 32 0x7fffffff)) (var na))) (set c (! (&& (ule (var oa) (var na)) (! (== (var oa) (var na)))))) (set ov (|| (var ov) (var ovn)))) +d "lac 0x20, #0x0" 2020 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x20))) (bv 24 0x2)))) (set acc (ite (var sxm) (cast 32 (msb (var m)) (var m)) (cast 32 false (var m))))) +d "sacl 0x10, #0x0" 6010 0x0 (storew 0 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x10))) (bv 24 0x2)) (cast 16 false (var acc))) +d "sach 0x10, #0x0" 6810 0x0 (storew 0 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x10))) (bv 24 0x2)) (cast 16 false (>> (var acc) (bv 6 0x10) false))) +d "lar ar1, 0x5" 3105 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x5))) (bv 24 0x2)))) (set ar1 (var m))) +d "sar ar1, 0x5" 7105 0x0 (storew 0 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x5))) (bv 24 0x2)) (var ar1)) +d "lt 0x9" 3c09 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x9))) (bv 24 0x2)))) (set t (var m))) +d "mpy 0x9" 3809 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x9))) (bv 24 0x2)))) (set p (* (cast 32 (msb (var m)) (var m)) (cast 32 (msb (var t)) (var t))))) +d "and 0xc" 4e0c 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0xc))) (bv 24 0x2)))) (set acc (& (var acc) (cast 32 false (var m))))) +d "or 0xc" 4d0c 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0xc))) (bv 24 0x2)))) (set acc (| (var acc) (cast 32 false (var m))))) +d "in 0x0, #0x1" 8100 0x0 (storew 0 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x0))) (bv 24 0x2)) (bv 16 0x0)) +d "out 0x0, #0x1" e100 0x0 nop + +# indirect addressing (ARP-relative; decode/disasm only, no IL) +d "add *, #0x0" 0080 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (ite (== (var arp) (bv 16 0x0)) (var ar0) (ite (== (var arp) (bv 16 0x1)) (var ar1) (ite (== (var arp) (bv 16 0x2)) (var ar2) (ite (== (var arp) (bv 16 0x3)) (var ar3) (ite (== (var arp) (bv 16 0x4)) (var ar4) (ite (== (var arp) (bv 16 0x5)) (var ar5) (ite (== (var arp) (bv 16 0x6)) (var ar6) (var ar7))))))))) (bv 24 0x2)))) (set oa (var acc)) (set av (ite (var sxm) (cast 32 (msb (var m)) (var m)) (cast 32 false (var m)))) (set na (+ (var oa) (var av))) (set ovn (msb (& (^ (var na) (var av)) (^ (var oa) (var na))))) (set acc (ite (&& (var ovm) (var ovn)) (ite (&& (sle (var oa) (bv 32 0x0)) (! (== (var oa) (bv 32 0x0)))) (bv 32 0x80000000) (bv 32 0x7fffffff)) (var na))) (set c (&& (ule (var na) (var oa)) (! (== (var na) (var oa))))) (set ov (|| (var ov) (var ovn)))) +d "add *+, #0x0" 00a0 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (ite (== (var arp) (bv 16 0x0)) (var ar0) (ite (== (var arp) (bv 16 0x1)) (var ar1) (ite (== (var arp) (bv 16 0x2)) (var ar2) (ite (== (var arp) (bv 16 0x3)) (var ar3) (ite (== (var arp) (bv 16 0x4)) (var ar4) (ite (== (var arp) (bv 16 0x5)) (var ar5) (ite (== (var arp) (bv 16 0x6)) (var ar6) (var ar7))))))))) (bv 24 0x2)))) (set oa (var acc)) (set av (ite (var sxm) (cast 32 (msb (var m)) (var m)) (cast 32 false (var m)))) (set na (+ (var oa) (var av))) (set ovn (msb (& (^ (var na) (var av)) (^ (var oa) (var na))))) (set acc (ite (&& (var ovm) (var ovn)) (ite (&& (sle (var oa) (bv 32 0x0)) (! (== (var oa) (bv 32 0x0)))) (bv 32 0x80000000) (bv 32 0x7fffffff)) (var na))) (set c (&& (ule (var na) (var oa)) (! (== (var na) (var oa))))) (set ov (|| (var ov) (var ovn))) (set ar0 (ite (== (var arp) (bv 16 0x0)) (+ (var ar0) (bv 16 0x1)) (var ar0))) (set ar1 (ite (== (var arp) (bv 16 0x1)) (+ (var ar1) (bv 16 0x1)) (var ar1))) (set ar2 (ite (== (var arp) (bv 16 0x2)) (+ (var ar2) (bv 16 0x1)) (var ar2))) (set ar3 (ite (== (var arp) (bv 16 0x3)) (+ (var ar3) (bv 16 0x1)) (var ar3))) (set ar4 (ite (== (var arp) (bv 16 0x4)) (+ (var ar4) (bv 16 0x1)) (var ar4))) (set ar5 (ite (== (var arp) (bv 16 0x5)) (+ (var ar5) (bv 16 0x1)) (var ar5))) (set ar6 (ite (== (var arp) (bv 16 0x6)) (+ (var ar6) (bv 16 0x1)) (var ar6))) (set ar7 (ite (== (var arp) (bv 16 0x7)) (+ (var ar7) (bv 16 0x1)) (var ar7)))) +d "add *-, #0x0" 0090 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (ite (== (var arp) (bv 16 0x0)) (var ar0) (ite (== (var arp) (bv 16 0x1)) (var ar1) (ite (== (var arp) (bv 16 0x2)) (var ar2) (ite (== (var arp) (bv 16 0x3)) (var ar3) (ite (== (var arp) (bv 16 0x4)) (var ar4) (ite (== (var arp) (bv 16 0x5)) (var ar5) (ite (== (var arp) (bv 16 0x6)) (var ar6) (var ar7))))))))) (bv 24 0x2)))) (set oa (var acc)) (set av (ite (var sxm) (cast 32 (msb (var m)) (var m)) (cast 32 false (var m)))) (set na (+ (var oa) (var av))) (set ovn (msb (& (^ (var na) (var av)) (^ (var oa) (var na))))) (set acc (ite (&& (var ovm) (var ovn)) (ite (&& (sle (var oa) (bv 32 0x0)) (! (== (var oa) (bv 32 0x0)))) (bv 32 0x80000000) (bv 32 0x7fffffff)) (var na))) (set c (&& (ule (var na) (var oa)) (! (== (var na) (var oa))))) (set ov (|| (var ov) (var ovn))) (set ar0 (ite (== (var arp) (bv 16 0x0)) (- (var ar0) (bv 16 0x1)) (var ar0))) (set ar1 (ite (== (var arp) (bv 16 0x1)) (- (var ar1) (bv 16 0x1)) (var ar1))) (set ar2 (ite (== (var arp) (bv 16 0x2)) (- (var ar2) (bv 16 0x1)) (var ar2))) (set ar3 (ite (== (var arp) (bv 16 0x3)) (- (var ar3) (bv 16 0x1)) (var ar3))) (set ar4 (ite (== (var arp) (bv 16 0x4)) (- (var ar4) (bv 16 0x1)) (var ar4))) (set ar5 (ite (== (var arp) (bv 16 0x5)) (- (var ar5) (bv 16 0x1)) (var ar5))) (set ar6 (ite (== (var arp) (bv 16 0x6)) (- (var ar6) (bv 16 0x1)) (var ar6))) (set ar7 (ite (== (var arp) (bv 16 0x7)) (- (var ar7) (bv 16 0x1)) (var ar7)))) +d "add *+, #0x0, ar2" 00aa 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (ite (== (var arp) (bv 16 0x0)) (var ar0) (ite (== (var arp) (bv 16 0x1)) (var ar1) (ite (== (var arp) (bv 16 0x2)) (var ar2) (ite (== (var arp) (bv 16 0x3)) (var ar3) (ite (== (var arp) (bv 16 0x4)) (var ar4) (ite (== (var arp) (bv 16 0x5)) (var ar5) (ite (== (var arp) (bv 16 0x6)) (var ar6) (var ar7))))))))) (bv 24 0x2)))) (set oa (var acc)) (set av (ite (var sxm) (cast 32 (msb (var m)) (var m)) (cast 32 false (var m)))) (set na (+ (var oa) (var av))) (set ovn (msb (& (^ (var na) (var av)) (^ (var oa) (var na))))) (set acc (ite (&& (var ovm) (var ovn)) (ite (&& (sle (var oa) (bv 32 0x0)) (! (== (var oa) (bv 32 0x0)))) (bv 32 0x80000000) (bv 32 0x7fffffff)) (var na))) (set c (&& (ule (var na) (var oa)) (! (== (var na) (var oa))))) (set ov (|| (var ov) (var ovn))) (set ar0 (ite (== (var arp) (bv 16 0x0)) (+ (var ar0) (bv 16 0x1)) (var ar0))) (set ar1 (ite (== (var arp) (bv 16 0x1)) (+ (var ar1) (bv 16 0x1)) (var ar1))) (set ar2 (ite (== (var arp) (bv 16 0x2)) (+ (var ar2) (bv 16 0x1)) (var ar2))) (set ar3 (ite (== (var arp) (bv 16 0x3)) (+ (var ar3) (bv 16 0x1)) (var ar3))) (set ar4 (ite (== (var arp) (bv 16 0x4)) (+ (var ar4) (bv 16 0x1)) (var ar4))) (set ar5 (ite (== (var arp) (bv 16 0x5)) (+ (var ar5) (bv 16 0x1)) (var ar5))) (set ar6 (ite (== (var arp) (bv 16 0x6)) (+ (var ar6) (bv 16 0x1)) (var ar6))) (set ar7 (ite (== (var arp) (bv 16 0x7)) (+ (var ar7) (bv 16 0x1)) (var ar7)))) +d "lac *br0+, #0x0" 20f0 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (ite (== (var arp) (bv 16 0x0)) (var ar0) (ite (== (var arp) (bv 16 0x1)) (var ar1) (ite (== (var arp) (bv 16 0x2)) (var ar2) (ite (== (var arp) (bv 16 0x3)) (var ar3) (ite (== (var arp) (bv 16 0x4)) (var ar4) (ite (== (var arp) (bv 16 0x5)) (var ar5) (ite (== (var arp) (bv 16 0x6)) (var ar6) (var ar7))))))))) (bv 24 0x2)))) (set acc (ite (var sxm) (cast 32 (msb (var m)) (var m)) (cast 32 false (var m))))) +d "sacl *0+, #0x0" 60e0 0x0 (seq (storew 0 (* (cast 24 false (ite (== (var arp) (bv 16 0x0)) (var ar0) (ite (== (var arp) (bv 16 0x1)) (var ar1) (ite (== (var arp) (bv 16 0x2)) (var ar2) (ite (== (var arp) (bv 16 0x3)) (var ar3) (ite (== (var arp) (bv 16 0x4)) (var ar4) (ite (== (var arp) (bv 16 0x5)) (var ar5) (ite (== (var arp) (bv 16 0x6)) (var ar6) (var ar7))))))))) (bv 24 0x2)) (cast 16 false (var acc))) (set ar0 (ite (== (var arp) (bv 16 0x0)) (+ (var ar0) (var ar0)) (var ar0))) (set ar1 (ite (== (var arp) (bv 16 0x1)) (+ (var ar1) (var ar0)) (var ar1))) (set ar2 (ite (== (var arp) (bv 16 0x2)) (+ (var ar2) (var ar0)) (var ar2))) (set ar3 (ite (== (var arp) (bv 16 0x3)) (+ (var ar3) (var ar0)) (var ar3))) (set ar4 (ite (== (var arp) (bv 16 0x4)) (+ (var ar4) (var ar0)) (var ar4))) (set ar5 (ite (== (var arp) (bv 16 0x5)) (+ (var ar5) (var ar0)) (var ar5))) (set ar6 (ite (== (var arp) (bv 16 0x6)) (+ (var ar6) (var ar0)) (var ar6))) (set ar7 (ite (== (var arp) (bv 16 0x7)) (+ (var ar7) (var ar0)) (var ar7)))) +d "mar *+" 55a0 0x0 (seq (set ar0 (ite (== (var arp) (bv 16 0x0)) (+ (var ar0) (bv 16 0x1)) (var ar0))) (set ar1 (ite (== (var arp) (bv 16 0x1)) (+ (var ar1) (bv 16 0x1)) (var ar1))) (set ar2 (ite (== (var arp) (bv 16 0x2)) (+ (var ar2) (bv 16 0x1)) (var ar2))) (set ar3 (ite (== (var arp) (bv 16 0x3)) (+ (var ar3) (bv 16 0x1)) (var ar3))) (set ar4 (ite (== (var arp) (bv 16 0x4)) (+ (var ar4) (bv 16 0x1)) (var ar4))) (set ar5 (ite (== (var arp) (bv 16 0x5)) (+ (var ar5) (bv 16 0x1)) (var ar5))) (set ar6 (ite (== (var arp) (bv 16 0x6)) (+ (var ar6) (bv 16 0x1)) (var ar6))) (set ar7 (ite (== (var arp) (bv 16 0x7)) (+ (var ar7) (bv 16 0x1)) (var ar7)))) + +# long-immediate (two-word) +d "lrlk ar0, #0x1234" d0001234 0x0 (set ar0 (bv 16 0x1234)) +d "lalk #0x5678, #0x0" d0015678 0x0 (set acc (ite (var sxm) (bv 32 0x5678) (bv 32 0x5678))) +d "andk #0xff, #0x0" d00400ff 0x0 (set acc (& (var acc) (bv 32 0xff))) + +# control transfer (two-word: opcode + target) +d "b 0x40" ff800040 0x0 (jmp (bv 16 0x80)) +d "call 0x50" fe800050 0x0 (seq (set sp (- (var sp) (bv 16 0x1))) (storew 0 (* (cast 24 false (var sp)) (bv 24 0x2)) (bv 16 0x2)) (jmp (bv 16 0xa0))) +d "bz 0x60" f6800060 0x0 (branch (is_zero (var acc)) (jmp (bv 16 0xc0)) nop) +d "bnz 0x70" f5800070 0x0 (branch (! (is_zero (var acc))) (jmp (bv 16 0xe0)) nop) +d "bgz 0x80" f1800080 0x0 (branch (! (sle (var acc) (bv 32 0x0))) (jmp (bv 16 0x100)) nop) +d "blz 0x90" f3800090 0x0 (branch (&& (sle (var acc) (bv 32 0x0)) (! (== (var acc) (bv 32 0x0)))) (jmp (bv 16 0x120)) nop) + +# NORM (normalize, CEx2) +d "norm *" ce82 0x0 (branch (&& (! (is_zero (var acc))) (! (^^ (msb (var acc)) (lsb (>> (var acc) (bv 5 0x1e) false))))) (seq (set tc false) (set acc (<< (var acc) (bv 6 0x1) false))) (set tc true)) +d "norm *+" cea2 0x0 (branch (&& (! (is_zero (var acc))) (! (^^ (msb (var acc)) (lsb (>> (var acc) (bv 5 0x1e) false))))) (seq (set tc false) (set acc (<< (var acc) (bv 6 0x1) false)) (set ar0 (ite (== (var arp) (bv 16 0x0)) (+ (var ar0) (bv 16 0x1)) (var ar0))) (set ar1 (ite (== (var arp) (bv 16 0x1)) (+ (var ar1) (bv 16 0x1)) (var ar1))) (set ar2 (ite (== (var arp) (bv 16 0x2)) (+ (var ar2) (bv 16 0x1)) (var ar2))) (set ar3 (ite (== (var arp) (bv 16 0x3)) (+ (var ar3) (bv 16 0x1)) (var ar3))) (set ar4 (ite (== (var arp) (bv 16 0x4)) (+ (var ar4) (bv 16 0x1)) (var ar4))) (set ar5 (ite (== (var arp) (bv 16 0x5)) (+ (var ar5) (bv 16 0x1)) (var ar5))) (set ar6 (ite (== (var arp) (bv 16 0x6)) (+ (var ar6) (bv 16 0x1)) (var ar6))) (set ar7 (ite (== (var arp) (bv 16 0x7)) (+ (var ar7) (bv 16 0x1)) (var ar7)))) (set tc true)) +d "norm *-" ce92 0x0 (branch (&& (! (is_zero (var acc))) (! (^^ (msb (var acc)) (lsb (>> (var acc) (bv 5 0x1e) false))))) (seq (set tc false) (set acc (<< (var acc) (bv 6 0x1) false)) (set ar0 (ite (== (var arp) (bv 16 0x0)) (- (var ar0) (bv 16 0x1)) (var ar0))) (set ar1 (ite (== (var arp) (bv 16 0x1)) (- (var ar1) (bv 16 0x1)) (var ar1))) (set ar2 (ite (== (var arp) (bv 16 0x2)) (- (var ar2) (bv 16 0x1)) (var ar2))) (set ar3 (ite (== (var arp) (bv 16 0x3)) (- (var ar3) (bv 16 0x1)) (var ar3))) (set ar4 (ite (== (var arp) (bv 16 0x4)) (- (var ar4) (bv 16 0x1)) (var ar4))) (set ar5 (ite (== (var arp) (bv 16 0x5)) (- (var ar5) (bv 16 0x1)) (var ar5))) (set ar6 (ite (== (var arp) (bv 16 0x6)) (- (var ar6) (bv 16 0x1)) (var ar6))) (set ar7 (ite (== (var arp) (bv 16 0x7)) (- (var ar7) (bv 16 0x1)) (var ar7)))) (set tc true)) + +# BANZ: branch-on-AR-not-zero with addressing-mode AR post-modify +d "banz 0x6, *-" fb900006 0x0 (seq (set ba (ite (== (var arp) (bv 16 0x0)) (var ar0) (ite (== (var arp) (bv 16 0x1)) (var ar1) (ite (== (var arp) (bv 16 0x2)) (var ar2) (ite (== (var arp) (bv 16 0x3)) (var ar3) (ite (== (var arp) (bv 16 0x4)) (var ar4) (ite (== (var arp) (bv 16 0x5)) (var ar5) (ite (== (var arp) (bv 16 0x6)) (var ar6) (var ar7))))))))) (set ar0 (ite (== (var arp) (bv 16 0x0)) (- (var ar0) (bv 16 0x1)) (var ar0))) (set ar1 (ite (== (var arp) (bv 16 0x1)) (- (var ar1) (bv 16 0x1)) (var ar1))) (set ar2 (ite (== (var arp) (bv 16 0x2)) (- (var ar2) (bv 16 0x1)) (var ar2))) (set ar3 (ite (== (var arp) (bv 16 0x3)) (- (var ar3) (bv 16 0x1)) (var ar3))) (set ar4 (ite (== (var arp) (bv 16 0x4)) (- (var ar4) (bv 16 0x1)) (var ar4))) (set ar5 (ite (== (var arp) (bv 16 0x5)) (- (var ar5) (bv 16 0x1)) (var ar5))) (set ar6 (ite (== (var arp) (bv 16 0x6)) (- (var ar6) (bv 16 0x1)) (var ar6))) (set ar7 (ite (== (var arp) (bv 16 0x7)) (- (var ar7) (bv 16 0x1)) (var ar7))) (branch (! (is_zero (var ba))) (jmp (bv 16 0xc)) nop)) +d "banz 0x6, *+" fba00006 0x0 (seq (set ba (ite (== (var arp) (bv 16 0x0)) (var ar0) (ite (== (var arp) (bv 16 0x1)) (var ar1) (ite (== (var arp) (bv 16 0x2)) (var ar2) (ite (== (var arp) (bv 16 0x3)) (var ar3) (ite (== (var arp) (bv 16 0x4)) (var ar4) (ite (== (var arp) (bv 16 0x5)) (var ar5) (ite (== (var arp) (bv 16 0x6)) (var ar6) (var ar7))))))))) (set ar0 (ite (== (var arp) (bv 16 0x0)) (+ (var ar0) (bv 16 0x1)) (var ar0))) (set ar1 (ite (== (var arp) (bv 16 0x1)) (+ (var ar1) (bv 16 0x1)) (var ar1))) (set ar2 (ite (== (var arp) (bv 16 0x2)) (+ (var ar2) (bv 16 0x1)) (var ar2))) (set ar3 (ite (== (var arp) (bv 16 0x3)) (+ (var ar3) (bv 16 0x1)) (var ar3))) (set ar4 (ite (== (var arp) (bv 16 0x4)) (+ (var ar4) (bv 16 0x1)) (var ar4))) (set ar5 (ite (== (var arp) (bv 16 0x5)) (+ (var ar5) (bv 16 0x1)) (var ar5))) (set ar6 (ite (== (var arp) (bv 16 0x6)) (+ (var ar6) (bv 16 0x1)) (var ar6))) (set ar7 (ite (== (var arp) (bv 16 0x7)) (+ (var ar7) (bv 16 0x1)) (var ar7))) (branch (! (is_zero (var ba))) (jmp (bv 16 0xc)) nop)) +d "banz 0x6, *" fb800006 0x0 (branch (! (is_zero (ite (== (var arp) (bv 16 0x0)) (var ar0) (ite (== (var arp) (bv 16 0x1)) (var ar1) (ite (== (var arp) (bv 16 0x2)) (var ar2) (ite (== (var arp) (bv 16 0x3)) (var ar3) (ite (== (var arp) (bv 16 0x4)) (var ar4) (ite (== (var arp) (bv 16 0x5)) (var ar5) (ite (== (var arp) (bv 16 0x6)) (var ar6) (var ar7)))))))))) (jmp (bv 16 0xc)) nop) + +# additional lifted forms: accumulator arithmetic, logic, shifts, +# zero-accumulate loads and P/T transfers. IL cross-checked by +# executing each in the RzIL VM and comparing acc/t/p against the +# external TMS320 emulator (identical results). +d "addc 0x0" 4300 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x0))) (bv 24 0x2)))) (set oa (var acc)) (set av (cast 32 false (var m))) (set na (+ (+ (var oa) (var av)) (ite (var c) (bv 32 0x1) (bv 32 0x0)))) (set acc (var na)) (set ov (|| (var ov) (msb (& (^ (var na) (var av)) (^ (var oa) (var na)))))) (set c (ite (== (var na) (var oa)) (var c) (&& (ule (var na) (var oa)) (! (== (var na) (var oa))))))) +d "addh 0x0" 4800 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x0))) (bv 24 0x2)))) (set oa (var acc)) (set av (<< (cast 32 false (var m)) (bv 6 0x10) false)) (set na (+ (var oa) (var av))) (set ovn (msb (& (^ (var na) (var av)) (^ (var oa) (var na))))) (set acc (ite (&& (var ovm) (var ovn)) (ite (&& (sle (var oa) (bv 32 0x0)) (! (== (var oa) (bv 32 0x0)))) (bv 32 0x80000000) (bv 32 0x7fffffff)) (var na))) (set c (|| (var c) (&& (ule (var na) (var oa)) (! (== (var na) (var oa)))))) (set ov (|| (var ov) (var ovn)))) +d "adds 0x0" 4900 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x0))) (bv 24 0x2)))) (set oa (var acc)) (set av (cast 32 false (var m))) (set na (+ (var oa) (var av))) (set ovn (msb (& (^ (var na) (var av)) (^ (var oa) (var na))))) (set acc (ite (&& (var ovm) (var ovn)) (ite (&& (sle (var oa) (bv 32 0x0)) (! (== (var oa) (bv 32 0x0)))) (bv 32 0x80000000) (bv 32 0x7fffffff)) (var na))) (set c (&& (ule (var na) (var oa)) (! (== (var na) (var oa))))) (set ov (|| (var ov) (var ovn)))) +d "addt 0x0" 4a00 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x0))) (bv 24 0x2)))) (set oa (var acc)) (set av (<< (ite (var sxm) (cast 32 (msb (var m)) (var m)) (cast 32 false (var m))) (& (var t) (bv 16 0xf)) false)) (set na (+ (var oa) (var av))) (set ovn (msb (& (^ (var na) (var av)) (^ (var oa) (var na))))) (set acc (ite (&& (var ovm) (var ovn)) (ite (&& (sle (var oa) (bv 32 0x0)) (! (== (var oa) (bv 32 0x0)))) (bv 32 0x80000000) (bv 32 0x7fffffff)) (var na))) (set c (&& (ule (var na) (var oa)) (! (== (var na) (var oa))))) (set ov (|| (var ov) (var ovn)))) +d "subb 0x0" 4f00 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x0))) (bv 24 0x2)))) (set oa (var acc)) (set av (cast 32 false (var m))) (set na (- (- (var oa) (var av)) (ite (var c) (bv 32 0x0) (bv 32 0x1)))) (set acc (var na)) (set ov (|| (var ov) (msb (& (^ (var oa) (var av)) (^ (var oa) (var na)))))) (set c (ite (== (var na) (var oa)) (var c) (! (&& (ule (var oa) (var na)) (! (== (var oa) (var na)))))))) +d "subh 0x0" 4400 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x0))) (bv 24 0x2)))) (set oa (var acc)) (set av (<< (cast 32 false (var m)) (bv 6 0x10) false)) (set na (- (var oa) (var av))) (set ovn (msb (& (^ (var oa) (var av)) (^ (var oa) (var na))))) (set acc (ite (&& (var ovm) (var ovn)) (ite (&& (sle (var oa) (bv 32 0x0)) (! (== (var oa) (bv 32 0x0)))) (bv 32 0x80000000) (bv 32 0x7fffffff)) (var na))) (set c (&& (var c) (! (&& (ule (var oa) (var na)) (! (== (var oa) (var na))))))) (set ov (|| (var ov) (var ovn)))) +d "subs 0x0" 4500 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x0))) (bv 24 0x2)))) (set oa (var acc)) (set av (cast 32 false (var m))) (set na (- (var oa) (var av))) (set ovn (msb (& (^ (var oa) (var av)) (^ (var oa) (var na))))) (set acc (ite (&& (var ovm) (var ovn)) (ite (&& (sle (var oa) (bv 32 0x0)) (! (== (var oa) (bv 32 0x0)))) (bv 32 0x80000000) (bv 32 0x7fffffff)) (var na))) (set c (! (&& (ule (var oa) (var na)) (! (== (var oa) (var na)))))) (set ov (|| (var ov) (var ovn)))) +d "subt 0x0" 4600 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x0))) (bv 24 0x2)))) (set oa (var acc)) (set av (<< (ite (var sxm) (cast 32 (msb (var m)) (var m)) (cast 32 false (var m))) (& (var t) (bv 16 0xf)) false)) (set na (- (var oa) (var av))) (set ovn (msb (& (^ (var oa) (var av)) (^ (var oa) (var na))))) (set acc (ite (&& (var ovm) (var ovn)) (ite (&& (sle (var oa) (bv 32 0x0)) (! (== (var oa) (bv 32 0x0)))) (bv 32 0x80000000) (bv 32 0x7fffffff)) (var na))) (set c (! (&& (ule (var oa) (var na)) (! (== (var oa) (var na)))))) (set ov (|| (var ov) (var ovn)))) +# accumulator unary: negate / complement / shift / rotate-through-carry +d "neg" ce23 0x0 (seq (set oa (var acc)) (set acc (~- (var oa))) (set c (is_zero (var oa)))) +d "cmpl" ce27 0x0 (set acc (~ (var acc))) +d "sfl" ce18 0x0 (seq (set oa (var acc)) (set acc (<< (var oa) (bv 6 0x1) false)) (set c (msb (var oa)))) +d "sfr" ce19 0x0 (seq (set oa (var acc)) (set acc (ite (var sxm) (>> (var oa) (bv 6 0x1) (msb (var oa))) (>> (var oa) (bv 6 0x1) false))) (set c (lsb (var oa)))) +d "rol" ce34 0x0 (seq (set oa (var acc)) (set acc (| (<< (var oa) (bv 6 0x1) false) (ite (var c) (bv 32 0x1) (bv 32 0x0)))) (set c (msb (var oa)))) +d "ror" ce35 0x0 (seq (set oa (var acc)) (set acc (| (>> (var oa) (bv 6 0x1) false) (ite (var c) (bv 32 0x80000000) (bv 32 0x0)))) (set c (lsb (var oa)))) +# logic +d "xor 0x0" 4c00 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x0))) (bv 24 0x2)))) (set acc (^ (var acc) (cast 32 false (var m))))) +d "ork #0x0, #0x0" d0050000 0x0 (set acc (| (var acc) (bv 32 0x0))) +# zero accumulator then load high / low / low-with-round +d "zalh 0x0" 4000 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x0))) (bv 24 0x2)))) (set acc (<< (cast 32 false (var m)) (bv 6 0x10) false))) +d "zals 0x0" 4100 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x0))) (bv 24 0x2)))) (set acc (cast 32 false (var m)))) +d "zalr 0x0" 7b00 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x0))) (bv 24 0x2)))) (set acc (| (<< (cast 32 false (var m)) (bv 6 0x10) false) (bv 32 0x8000)))) +# P/T register loads and stores +d "lph 0x0" 5300 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x0))) (bv 24 0x2)))) (set p (| (& (var p) (bv 32 0xffff)) (<< (cast 32 false (var m)) (bv 6 0x10) false)))) +d "lta 0x0" 3d00 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x0))) (bv 24 0x2)))) (set t (var m)) (set oa (var acc)) (set av (ite (== (var pm) (bv 2 0x0)) (var p) (ite (== (var pm) (bv 2 0x1)) (<< (var p) (bv 6 0x1) false) (ite (== (var pm) (bv 2 0x2)) (<< (var p) (bv 6 0x4) false) (>> (var p) (bv 6 0x6) (msb (var p))))))) (set na (+ (var oa) (var av))) (set ovn (msb (& (^ (var na) (var av)) (^ (var oa) (var na))))) (set acc (ite (&& (var ovm) (var ovn)) (ite (&& (sle (var oa) (bv 32 0x0)) (! (== (var oa) (bv 32 0x0)))) (bv 32 0x80000000) (bv 32 0x7fffffff)) (var na))) (set c (&& (ule (var na) (var oa)) (! (== (var na) (var oa))))) (set ov (|| (var ov) (var ovn)))) +d "ltp 0x0" 3e00 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x0))) (bv 24 0x2)))) (set t (var m)) (set acc (ite (== (var pm) (bv 2 0x0)) (var p) (ite (== (var pm) (bv 2 0x1)) (<< (var p) (bv 6 0x1) false) (ite (== (var pm) (bv 2 0x2)) (<< (var p) (bv 6 0x4) false) (>> (var p) (bv 6 0x6) (msb (var p)))))))) +d "lts 0x0" 5b00 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x0))) (bv 24 0x2)))) (set t (var m)) (set oa (var acc)) (set av (ite (== (var pm) (bv 2 0x0)) (var p) (ite (== (var pm) (bv 2 0x1)) (<< (var p) (bv 6 0x1) false) (ite (== (var pm) (bv 2 0x2)) (<< (var p) (bv 6 0x4) false) (>> (var p) (bv 6 0x6) (msb (var p))))))) (set na (- (var oa) (var av))) (set ovn (msb (& (^ (var oa) (var av)) (^ (var oa) (var na))))) (set acc (ite (&& (var ovm) (var ovn)) (ite (&& (sle (var oa) (bv 32 0x0)) (! (== (var oa) (bv 32 0x0)))) (bv 32 0x80000000) (bv 32 0x7fffffff)) (var na))) (set c (! (&& (ule (var oa) (var na)) (! (== (var oa) (var na)))))) (set ov (|| (var ov) (var ovn)))) +d "sph 0x0" 7d00 0x0 (storew 0 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x0))) (bv 24 0x2)) (cast 16 false (>> (ite (== (var pm) (bv 2 0x0)) (var p) (ite (== (var pm) (bv 2 0x1)) (<< (var p) (bv 6 0x1) false) (ite (== (var pm) (bv 2 0x2)) (<< (var p) (bv 6 0x4) false) (>> (var p) (bv 6 0x6) (msb (var p)))))) (bv 6 0x10) false))) +d "spl 0x0" 7c00 0x0 (storew 0 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x0))) (bv 24 0x2)) (cast 16 false (ite (== (var pm) (bv 2 0x0)) (var p) (ite (== (var pm) (bv 2 0x1)) (<< (var p) (bv 6 0x1) false) (ite (== (var pm) (bv 2 0x2)) (<< (var p) (bv 6 0x4) false) (>> (var p) (bv 6 0x6) (msb (var p)))))))) +# data-memory move (dma copy with implicit AR post-adjust) +d "dmov 0x0" 5600 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x0))) (bv 24 0x2)))) (storew 0 (* (cast 24 false (+ (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x0)) (bv 16 0x1))) (bv 24 0x2)) (var m))) diff --git a/test/db/asm/tms320_c5x_16 b/test/db/asm/tms320_c5x_16 new file mode 100644 index 00000000000..931694604bc --- /dev/null +++ b/test/db/asm/tms320_c5x_16 @@ -0,0 +1,148 @@ +# TMS320C5x disassembly + RzIL. The C5x is source-compatible with the C2x but +# uses a different object encoding, decoded by the dedicated C5x front-end +# (c5x_decode). Shared-semantics instructions carry the C2x ids and lift through +# the C2x lifter; the C5x-only instructions (ACCB ops, parallel-logic, memory- +# mapped register access, conditional execute/call/return, block moves, ...) +# carry the C5X_INS_* ids. Vectors are real C5x opcodes (assembled by the C5x +# tool-chain) covering direct/indirect/shift/next-ARP forms. +d "lacc 0x9, #0x0" 1009 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x9))) (bv 24 0x2)))) (set acc (ite (var sxm) (cast 32 (msb (var m)) (var m)) (cast 32 false (var m))))) +d "lacc 0x9, #0x4" 1409 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x9))) (bv 24 0x2)))) (set acc (<< (ite (var sxm) (cast 32 (msb (var m)) (var m)) (cast 32 false (var m))) (bv 6 0x4) false))) +d "lacc *+, #0x0" 10a0 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (ite (== (var arp) (bv 16 0x0)) (var ar0) (ite (== (var arp) (bv 16 0x1)) (var ar1) (ite (== (var arp) (bv 16 0x2)) (var ar2) (ite (== (var arp) (bv 16 0x3)) (var ar3) (ite (== (var arp) (bv 16 0x4)) (var ar4) (ite (== (var arp) (bv 16 0x5)) (var ar5) (ite (== (var arp) (bv 16 0x6)) (var ar6) (var ar7))))))))) (bv 24 0x2)))) (set acc (ite (var sxm) (cast 32 (msb (var m)) (var m)) (cast 32 false (var m)))) (set ar0 (ite (== (var arp) (bv 16 0x0)) (+ (var ar0) (bv 16 0x1)) (var ar0))) (set ar1 (ite (== (var arp) (bv 16 0x1)) (+ (var ar1) (bv 16 0x1)) (var ar1))) (set ar2 (ite (== (var arp) (bv 16 0x2)) (+ (var ar2) (bv 16 0x1)) (var ar2))) (set ar3 (ite (== (var arp) (bv 16 0x3)) (+ (var ar3) (bv 16 0x1)) (var ar3))) (set ar4 (ite (== (var arp) (bv 16 0x4)) (+ (var ar4) (bv 16 0x1)) (var ar4))) (set ar5 (ite (== (var arp) (bv 16 0x5)) (+ (var ar5) (bv 16 0x1)) (var ar5))) (set ar6 (ite (== (var arp) (bv 16 0x6)) (+ (var ar6) (bv 16 0x1)) (var ar6))) (set ar7 (ite (== (var arp) (bv 16 0x7)) (+ (var ar7) (bv 16 0x1)) (var ar7)))) +d "lacc *+, #0x0, ar2" 10aa 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (ite (== (var arp) (bv 16 0x0)) (var ar0) (ite (== (var arp) (bv 16 0x1)) (var ar1) (ite (== (var arp) (bv 16 0x2)) (var ar2) (ite (== (var arp) (bv 16 0x3)) (var ar3) (ite (== (var arp) (bv 16 0x4)) (var ar4) (ite (== (var arp) (bv 16 0x5)) (var ar5) (ite (== (var arp) (bv 16 0x6)) (var ar6) (var ar7))))))))) (bv 24 0x2)))) (set acc (ite (var sxm) (cast 32 (msb (var m)) (var m)) (cast 32 false (var m)))) (set ar0 (ite (== (var arp) (bv 16 0x0)) (+ (var ar0) (bv 16 0x1)) (var ar0))) (set ar1 (ite (== (var arp) (bv 16 0x1)) (+ (var ar1) (bv 16 0x1)) (var ar1))) (set ar2 (ite (== (var arp) (bv 16 0x2)) (+ (var ar2) (bv 16 0x1)) (var ar2))) (set ar3 (ite (== (var arp) (bv 16 0x3)) (+ (var ar3) (bv 16 0x1)) (var ar3))) (set ar4 (ite (== (var arp) (bv 16 0x4)) (+ (var ar4) (bv 16 0x1)) (var ar4))) (set ar5 (ite (== (var arp) (bv 16 0x5)) (+ (var ar5) (bv 16 0x1)) (var ar5))) (set ar6 (ite (== (var arp) (bv 16 0x6)) (+ (var ar6) (bv 16 0x1)) (var ar6))) (set ar7 (ite (== (var arp) (bv 16 0x7)) (+ (var ar7) (bv 16 0x1)) (var ar7)))) +d "lacc 0x9, #0x10" 6a09 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x9))) (bv 24 0x2)))) (set acc (ite (var sxm) (cast 32 (msb (var m)) (var m)) (cast 32 false (var m))))) +d "add 0x9, #0x0" 2009 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x9))) (bv 24 0x2)))) (set oa (var acc)) (set av (ite (var sxm) (cast 32 (msb (var m)) (var m)) (cast 32 false (var m)))) (set na (+ (var oa) (var av))) (set ovn (msb (& (^ (var na) (var av)) (^ (var oa) (var na))))) (set acc (ite (&& (var ovm) (var ovn)) (ite (&& (sle (var oa) (bv 32 0x0)) (! (== (var oa) (bv 32 0x0)))) (bv 32 0x80000000) (bv 32 0x7fffffff)) (var na))) (set c (&& (ule (var na) (var oa)) (! (== (var na) (var oa))))) (set ov (|| (var ov) (var ovn)))) +d "add 0x9, #0x4" 2409 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x9))) (bv 24 0x2)))) (set oa (var acc)) (set av (<< (ite (var sxm) (cast 32 (msb (var m)) (var m)) (cast 32 false (var m))) (bv 6 0x4) false)) (set na (+ (var oa) (var av))) (set ovn (msb (& (^ (var na) (var av)) (^ (var oa) (var na))))) (set acc (ite (&& (var ovm) (var ovn)) (ite (&& (sle (var oa) (bv 32 0x0)) (! (== (var oa) (bv 32 0x0)))) (bv 32 0x80000000) (bv 32 0x7fffffff)) (var na))) (set c (&& (ule (var na) (var oa)) (! (== (var na) (var oa))))) (set ov (|| (var ov) (var ovn)))) +d "add *-, #0x0" 2090 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (ite (== (var arp) (bv 16 0x0)) (var ar0) (ite (== (var arp) (bv 16 0x1)) (var ar1) (ite (== (var arp) (bv 16 0x2)) (var ar2) (ite (== (var arp) (bv 16 0x3)) (var ar3) (ite (== (var arp) (bv 16 0x4)) (var ar4) (ite (== (var arp) (bv 16 0x5)) (var ar5) (ite (== (var arp) (bv 16 0x6)) (var ar6) (var ar7))))))))) (bv 24 0x2)))) (set oa (var acc)) (set av (ite (var sxm) (cast 32 (msb (var m)) (var m)) (cast 32 false (var m)))) (set na (+ (var oa) (var av))) (set ovn (msb (& (^ (var na) (var av)) (^ (var oa) (var na))))) (set acc (ite (&& (var ovm) (var ovn)) (ite (&& (sle (var oa) (bv 32 0x0)) (! (== (var oa) (bv 32 0x0)))) (bv 32 0x80000000) (bv 32 0x7fffffff)) (var na))) (set c (&& (ule (var na) (var oa)) (! (== (var na) (var oa))))) (set ov (|| (var ov) (var ovn))) (set ar0 (ite (== (var arp) (bv 16 0x0)) (- (var ar0) (bv 16 0x1)) (var ar0))) (set ar1 (ite (== (var arp) (bv 16 0x1)) (- (var ar1) (bv 16 0x1)) (var ar1))) (set ar2 (ite (== (var arp) (bv 16 0x2)) (- (var ar2) (bv 16 0x1)) (var ar2))) (set ar3 (ite (== (var arp) (bv 16 0x3)) (- (var ar3) (bv 16 0x1)) (var ar3))) (set ar4 (ite (== (var arp) (bv 16 0x4)) (- (var ar4) (bv 16 0x1)) (var ar4))) (set ar5 (ite (== (var arp) (bv 16 0x5)) (- (var ar5) (bv 16 0x1)) (var ar5))) (set ar6 (ite (== (var arp) (bv 16 0x6)) (- (var ar6) (bv 16 0x1)) (var ar6))) (set ar7 (ite (== (var arp) (bv 16 0x7)) (- (var ar7) (bv 16 0x1)) (var ar7)))) +d "add 0x9, #0x10" 6109 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x9))) (bv 24 0x2)))) (set oa (var acc)) (set av (ite (var sxm) (cast 32 (msb (var m)) (var m)) (cast 32 false (var m)))) (set na (+ (var oa) (var av))) (set ovn (msb (& (^ (var na) (var av)) (^ (var oa) (var na))))) (set acc (ite (&& (var ovm) (var ovn)) (ite (&& (sle (var oa) (bv 32 0x0)) (! (== (var oa) (bv 32 0x0)))) (bv 32 0x80000000) (bv 32 0x7fffffff)) (var na))) (set c (&& (ule (var na) (var oa)) (! (== (var na) (var oa))))) (set ov (|| (var ov) (var ovn)))) +d "sub 0x9, #0x0" 3009 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x9))) (bv 24 0x2)))) (set oa (var acc)) (set av (ite (var sxm) (cast 32 (msb (var m)) (var m)) (cast 32 false (var m)))) (set na (- (var oa) (var av))) (set ovn (msb (& (^ (var oa) (var av)) (^ (var oa) (var na))))) (set acc (ite (&& (var ovm) (var ovn)) (ite (&& (sle (var oa) (bv 32 0x0)) (! (== (var oa) (bv 32 0x0)))) (bv 32 0x80000000) (bv 32 0x7fffffff)) (var na))) (set c (! (&& (ule (var oa) (var na)) (! (== (var oa) (var na)))))) (set ov (|| (var ov) (var ovn)))) +d "sub *0+, #0x0, ar3" 30eb 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (ite (== (var arp) (bv 16 0x0)) (var ar0) (ite (== (var arp) (bv 16 0x1)) (var ar1) (ite (== (var arp) (bv 16 0x2)) (var ar2) (ite (== (var arp) (bv 16 0x3)) (var ar3) (ite (== (var arp) (bv 16 0x4)) (var ar4) (ite (== (var arp) (bv 16 0x5)) (var ar5) (ite (== (var arp) (bv 16 0x6)) (var ar6) (var ar7))))))))) (bv 24 0x2)))) (set oa (var acc)) (set av (ite (var sxm) (cast 32 (msb (var m)) (var m)) (cast 32 false (var m)))) (set na (- (var oa) (var av))) (set ovn (msb (& (^ (var oa) (var av)) (^ (var oa) (var na))))) (set acc (ite (&& (var ovm) (var ovn)) (ite (&& (sle (var oa) (bv 32 0x0)) (! (== (var oa) (bv 32 0x0)))) (bv 32 0x80000000) (bv 32 0x7fffffff)) (var na))) (set c (! (&& (ule (var oa) (var na)) (! (== (var oa) (var na)))))) (set ov (|| (var ov) (var ovn))) (set ar0 (ite (== (var arp) (bv 16 0x0)) (+ (var ar0) (var ar0)) (var ar0))) (set ar1 (ite (== (var arp) (bv 16 0x1)) (+ (var ar1) (var ar0)) (var ar1))) (set ar2 (ite (== (var arp) (bv 16 0x2)) (+ (var ar2) (var ar0)) (var ar2))) (set ar3 (ite (== (var arp) (bv 16 0x3)) (+ (var ar3) (var ar0)) (var ar3))) (set ar4 (ite (== (var arp) (bv 16 0x4)) (+ (var ar4) (var ar0)) (var ar4))) (set ar5 (ite (== (var arp) (bv 16 0x5)) (+ (var ar5) (var ar0)) (var ar5))) (set ar6 (ite (== (var arp) (bv 16 0x6)) (+ (var ar6) (var ar0)) (var ar6))) (set ar7 (ite (== (var arp) (bv 16 0x7)) (+ (var ar7) (var ar0)) (var ar7)))) +d "sacl 0x10, #0x0" 9010 0x0 (storew 0 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x10))) (bv 24 0x2)) (cast 16 false (var acc))) +d "sacl *+, #0x1" 91a0 0x0 (seq (storew 0 (* (cast 24 false (ite (== (var arp) (bv 16 0x0)) (var ar0) (ite (== (var arp) (bv 16 0x1)) (var ar1) (ite (== (var arp) (bv 16 0x2)) (var ar2) (ite (== (var arp) (bv 16 0x3)) (var ar3) (ite (== (var arp) (bv 16 0x4)) (var ar4) (ite (== (var arp) (bv 16 0x5)) (var ar5) (ite (== (var arp) (bv 16 0x6)) (var ar6) (var ar7))))))))) (bv 24 0x2)) (cast 16 false (<< (var acc) (bv 6 0x1) false))) (set ar0 (ite (== (var arp) (bv 16 0x0)) (+ (var ar0) (bv 16 0x1)) (var ar0))) (set ar1 (ite (== (var arp) (bv 16 0x1)) (+ (var ar1) (bv 16 0x1)) (var ar1))) (set ar2 (ite (== (var arp) (bv 16 0x2)) (+ (var ar2) (bv 16 0x1)) (var ar2))) (set ar3 (ite (== (var arp) (bv 16 0x3)) (+ (var ar3) (bv 16 0x1)) (var ar3))) (set ar4 (ite (== (var arp) (bv 16 0x4)) (+ (var ar4) (bv 16 0x1)) (var ar4))) (set ar5 (ite (== (var arp) (bv 16 0x5)) (+ (var ar5) (bv 16 0x1)) (var ar5))) (set ar6 (ite (== (var arp) (bv 16 0x6)) (+ (var ar6) (bv 16 0x1)) (var ar6))) (set ar7 (ite (== (var arp) (bv 16 0x7)) (+ (var ar7) (bv 16 0x1)) (var ar7)))) +d "sach 0x10, #0x1" 9910 0x0 (storew 0 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x10))) (bv 24 0x2)) (cast 16 false (>> (<< (var acc) (bv 6 0x1) false) (bv 6 0x10) false))) +d "and 0x9" 6e09 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x9))) (bv 24 0x2)))) (set acc (& (var acc) (cast 32 false (var m))))) +d "or 0x9" 6d09 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x9))) (bv 24 0x2)))) (set acc (| (var acc) (cast 32 false (var m))))) +d "xor 0x9" 6c09 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x9))) (bv 24 0x2)))) (set acc (^ (var acc) (cast 32 false (var m))))) +d "lacl 0x9" 6909 0x0 (set acc (cast 32 false (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x9))) (bv 24 0x2))))) +d "lacl #0x42" b942 0x0 (set acc (bv 32 0x42)) +d "lar ar0, 0x9" 0009 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x9))) (bv 24 0x2)))) (set ar0 (var m))) +d "lar ar1, #0x10" b110 0x0 (set ar1 (bv 16 0x10)) +d "sar ar0, 0x9" 8009 0x0 (storew 0 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x9))) (bv 24 0x2)) (var ar0)) +d "lt 0x9" 7309 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x9))) (bv 24 0x2)))) (set t (var m))) +d "lta 0x9" 7009 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x9))) (bv 24 0x2)))) (set t (var m)) (set oa (var acc)) (set av (ite (== (var pm) (bv 2 0x0)) (var p) (ite (== (var pm) (bv 2 0x1)) (<< (var p) (bv 6 0x1) false) (ite (== (var pm) (bv 2 0x2)) (<< (var p) (bv 6 0x4) false) (>> (var p) (bv 6 0x6) (msb (var p))))))) (set na (+ (var oa) (var av))) (set ovn (msb (& (^ (var na) (var av)) (^ (var oa) (var na))))) (set acc (ite (&& (var ovm) (var ovn)) (ite (&& (sle (var oa) (bv 32 0x0)) (! (== (var oa) (bv 32 0x0)))) (bv 32 0x80000000) (bv 32 0x7fffffff)) (var na))) (set c (&& (ule (var na) (var oa)) (! (== (var na) (var oa))))) (set ov (|| (var ov) (var ovn)))) +d "ltp 0x9" 7109 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x9))) (bv 24 0x2)))) (set t (var m)) (set acc (ite (== (var pm) (bv 2 0x0)) (var p) (ite (== (var pm) (bv 2 0x1)) (<< (var p) (bv 6 0x1) false) (ite (== (var pm) (bv 2 0x2)) (<< (var p) (bv 6 0x4) false) (>> (var p) (bv 6 0x6) (msb (var p)))))))) +d "ltd 0x9" 7209 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x9))) (bv 24 0x2)))) (set t (var m)) (storew 0 (* (cast 24 false (+ (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x9)) (bv 16 0x1))) (bv 24 0x2)) (var m)) (set oa (var acc)) (set av (ite (== (var pm) (bv 2 0x0)) (var p) (ite (== (var pm) (bv 2 0x1)) (<< (var p) (bv 6 0x1) false) (ite (== (var pm) (bv 2 0x2)) (<< (var p) (bv 6 0x4) false) (>> (var p) (bv 6 0x6) (msb (var p))))))) (set na (+ (var oa) (var av))) (set ovn (msb (& (^ (var na) (var av)) (^ (var oa) (var na))))) (set acc (ite (&& (var ovm) (var ovn)) (ite (&& (sle (var oa) (bv 32 0x0)) (! (== (var oa) (bv 32 0x0)))) (bv 32 0x80000000) (bv 32 0x7fffffff)) (var na))) (set c (&& (ule (var na) (var oa)) (! (== (var na) (var oa))))) (set ov (|| (var ov) (var ovn)))) +d "mpy 0x9" 5409 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x9))) (bv 24 0x2)))) (set p (* (cast 32 (msb (var m)) (var m)) (cast 32 (msb (var t)) (var t))))) +d "mpyu 0x9" 5509 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x9))) (bv 24 0x2)))) (set p (* (cast 32 false (var m)) (cast 32 false (var t))))) +d "sqra 0x9" 5209 0x0 (seq (set oa (var acc)) (set av (ite (== (var pm) (bv 2 0x0)) (var p) (ite (== (var pm) (bv 2 0x1)) (<< (var p) (bv 6 0x1) false) (ite (== (var pm) (bv 2 0x2)) (<< (var p) (bv 6 0x4) false) (>> (var p) (bv 6 0x6) (msb (var p))))))) (set na (+ (var oa) (var av))) (set ovn (msb (& (^ (var na) (var av)) (^ (var oa) (var na))))) (set acc (ite (&& (var ovm) (var ovn)) (ite (&& (sle (var oa) (bv 32 0x0)) (! (== (var oa) (bv 32 0x0)))) (bv 32 0x80000000) (bv 32 0x7fffffff)) (var na))) (set c (&& (ule (var na) (var oa)) (! (== (var na) (var oa))))) (set ov (|| (var ov) (var ovn))) (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x9))) (bv 24 0x2)))) (set t (var m)) (set p (* (cast 32 (msb (var m)) (var m)) (cast 32 (msb (var m)) (var m))))) +d "pac" be03 0x0 (set acc (ite (== (var pm) (bv 2 0x0)) (var p) (ite (== (var pm) (bv 2 0x1)) (<< (var p) (bv 6 0x1) false) (ite (== (var pm) (bv 2 0x2)) (<< (var p) (bv 6 0x4) false) (>> (var p) (bv 6 0x6) (msb (var p))))))) +d "apac" be04 0x0 (seq (set oa (var acc)) (set av (ite (== (var pm) (bv 2 0x0)) (var p) (ite (== (var pm) (bv 2 0x1)) (<< (var p) (bv 6 0x1) false) (ite (== (var pm) (bv 2 0x2)) (<< (var p) (bv 6 0x4) false) (>> (var p) (bv 6 0x6) (msb (var p))))))) (set na (+ (var oa) (var av))) (set ovn (msb (& (^ (var na) (var av)) (^ (var oa) (var na))))) (set acc (ite (&& (var ovm) (var ovn)) (ite (&& (sle (var oa) (bv 32 0x0)) (! (== (var oa) (bv 32 0x0)))) (bv 32 0x80000000) (bv 32 0x7fffffff)) (var na))) (set c (&& (ule (var na) (var oa)) (! (== (var na) (var oa))))) (set ov (|| (var ov) (var ovn)))) +d "spac" be05 0x0 (seq (set oa (var acc)) (set av (ite (== (var pm) (bv 2 0x0)) (var p) (ite (== (var pm) (bv 2 0x1)) (<< (var p) (bv 6 0x1) false) (ite (== (var pm) (bv 2 0x2)) (<< (var p) (bv 6 0x4) false) (>> (var p) (bv 6 0x6) (msb (var p))))))) (set na (- (var oa) (var av))) (set ovn (msb (& (^ (var oa) (var av)) (^ (var oa) (var na))))) (set acc (ite (&& (var ovm) (var ovn)) (ite (&& (sle (var oa) (bv 32 0x0)) (! (== (var oa) (bv 32 0x0)))) (bv 32 0x80000000) (bv 32 0x7fffffff)) (var na))) (set c (! (&& (ule (var oa) (var na)) (! (== (var oa) (var na)))))) (set ov (|| (var ov) (var ovn)))) +d "abs" be00 0x0 (seq (set acc (ite (&& (sle (var acc) (bv 32 0x0)) (! (== (var acc) (bv 32 0x0)))) (~- (var acc)) (var acc))) (set c false)) +d "neg" be02 0x0 (seq (set oa (var acc)) (set acc (~- (var oa))) (set c (is_zero (var oa)))) +d "cmpl" be01 0x0 (set acc (~ (var acc))) +d "sfl" be09 0x0 (seq (set oa (var acc)) (set acc (<< (var oa) (bv 6 0x1) false)) (set c (msb (var oa)))) +d "sfr" be0a 0x0 (seq (set oa (var acc)) (set acc (ite (var sxm) (>> (var oa) (bv 6 0x1) (msb (var oa))) (>> (var oa) (bv 6 0x1) false))) (set c (lsb (var oa)))) +d "rol" be0c 0x0 (seq (set oa (var acc)) (set acc (| (<< (var oa) (bv 6 0x1) false) (ite (var c) (bv 32 0x1) (bv 32 0x0)))) (set c (msb (var oa)))) +d "ror" be0d 0x0 (seq (set oa (var acc)) (set acc (| (>> (var oa) (bv 6 0x1) false) (ite (var c) (bv 32 0x80000000) (bv 32 0x0)))) (set c (lsb (var oa)))) +d "zalr 0x9" 6809 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x9))) (bv 24 0x2)))) (set acc (| (<< (cast 32 false (var m)) (bv 6 0x10) false) (bv 32 0x8000)))) +d "lph 0x9" 7509 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x9))) (bv 24 0x2)))) (set p (| (& (var p) (bv 32 0xffff)) (<< (cast 32 false (var m)) (bv 6 0x10) false)))) +d "spl 0x9" 8c09 0x0 (storew 0 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x9))) (bv 24 0x2)) (cast 16 false (ite (== (var pm) (bv 2 0x0)) (var p) (ite (== (var pm) (bv 2 0x1)) (<< (var p) (bv 6 0x1) false) (ite (== (var pm) (bv 2 0x2)) (<< (var p) (bv 6 0x4) false) (>> (var p) (bv 6 0x6) (msb (var p)))))))) +d "sph 0x9" 8d09 0x0 (storew 0 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x9))) (bv 24 0x2)) (cast 16 false (>> (ite (== (var pm) (bv 2 0x0)) (var p) (ite (== (var pm) (bv 2 0x1)) (<< (var p) (bv 6 0x1) false) (ite (== (var pm) (bv 2 0x2)) (<< (var p) (bv 6 0x4) false) (>> (var p) (bv 6 0x6) (msb (var p)))))) (bv 6 0x10) false))) +d "add #0x12" b812 0x0 (seq (set oa (var acc)) (set av (bv 32 0x12)) (set na (+ (var oa) (var av))) (set ovn (msb (& (^ (var na) (var av)) (^ (var oa) (var na))))) (set acc (ite (&& (var ovm) (var ovn)) (ite (&& (sle (var oa) (bv 32 0x0)) (! (== (var oa) (bv 32 0x0)))) (bv 32 0x80000000) (bv 32 0x7fffffff)) (var na))) (set c (&& (ule (var na) (var oa)) (! (== (var na) (var oa))))) (set ov (|| (var ov) (var ovn)))) +d "sub #0x12" ba12 0x0 (seq (set oa (var acc)) (set av (bv 32 0x12)) (set na (- (var oa) (var av))) (set ovn (msb (& (^ (var oa) (var av)) (^ (var oa) (var na))))) (set acc (ite (&& (var ovm) (var ovn)) (ite (&& (sle (var oa) (bv 32 0x0)) (! (== (var oa) (bv 32 0x0)))) (bv 32 0x80000000) (bv 32 0x7fffffff)) (var na))) (set c (! (&& (ule (var oa) (var na)) (! (== (var oa) (var na)))))) (set ov (|| (var ov) (var ovn)))) +d "rpt #0x7" bb07 0x0 (set rptc (bv 16 0x7)) +d "ldp #0x4" bc04 0x0 (set dp (bv 16 0x4)) +d "adrk #0x8" 7808 0x0 (seq (set ar0 (ite (== (var arp) (bv 16 0x0)) (+ (var ar0) (bv 16 0x8)) (var ar0))) (set ar1 (ite (== (var arp) (bv 16 0x1)) (+ (var ar1) (bv 16 0x8)) (var ar1))) (set ar2 (ite (== (var arp) (bv 16 0x2)) (+ (var ar2) (bv 16 0x8)) (var ar2))) (set ar3 (ite (== (var arp) (bv 16 0x3)) (+ (var ar3) (bv 16 0x8)) (var ar3))) (set ar4 (ite (== (var arp) (bv 16 0x4)) (+ (var ar4) (bv 16 0x8)) (var ar4))) (set ar5 (ite (== (var arp) (bv 16 0x5)) (+ (var ar5) (bv 16 0x8)) (var ar5))) (set ar6 (ite (== (var arp) (bv 16 0x6)) (+ (var ar6) (bv 16 0x8)) (var ar6))) (set ar7 (ite (== (var arp) (bv 16 0x7)) (+ (var ar7) (bv 16 0x8)) (var ar7)))) +d "sbrk #0x8" 7c08 0x0 (seq (set ar0 (ite (== (var arp) (bv 16 0x0)) (- (var ar0) (bv 16 0x8)) (var ar0))) (set ar1 (ite (== (var arp) (bv 16 0x1)) (- (var ar1) (bv 16 0x8)) (var ar1))) (set ar2 (ite (== (var arp) (bv 16 0x2)) (- (var ar2) (bv 16 0x8)) (var ar2))) (set ar3 (ite (== (var arp) (bv 16 0x3)) (- (var ar3) (bv 16 0x8)) (var ar3))) (set ar4 (ite (== (var arp) (bv 16 0x4)) (- (var ar4) (bv 16 0x8)) (var ar4))) (set ar5 (ite (== (var arp) (bv 16 0x5)) (- (var ar5) (bv 16 0x8)) (var ar5))) (set ar6 (ite (== (var arp) (bv 16 0x6)) (- (var ar6) (bv 16 0x8)) (var ar6))) (set ar7 (ite (== (var arp) (bv 16 0x7)) (- (var ar7) (bv 16 0x8)) (var ar7)))) +d "spm #0x2" bf02 0x0 (set pm (bv 2 0x2)) +d "lacb" be1f 0x0 (set acc (var accb)) +d "sacb" be1e 0x0 (set accb (var acc)) +d "exar" be1d 0x0 (seq (set t (var acc)) (set acc (var accb)) (set accb (var t))) +d "addb" be10 +d "sbb" be18 +d "andb" be12 0x0 (set acc (& (var acc) (var accb))) +d "orb" be13 0x0 (set acc (| (var acc) (var accb))) +d "xorb" be1a 0x0 (set acc (^ (var acc) (var accb))) +d "crgt" be1b +d "crlt" be1c +d "zap" be59 0x0 (seq (set acc (bv 32 0x0)) (set p (bv 32 0x0))) +d "zpr" be58 0x0 (set p (bv 32 0x0)) +d "setc ovm" be43 0x0 (set ovm true) +d "clrc sxm" be46 0x0 (set sxm false) +d "setc carry" be4f 0x0 (set c true) +d "clrc tc" be4a 0x0 (set tc false) +d "samm 0x10" 8810 +d "lamm 0x10" 0810 +d "bldd 0x9" ac09 +d "blpd 0x9" a409 +d "splk 0x10, #0x1234" ae101234 0x0 (storew 0 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x10))) (bv 24 0x2)) (bv 16 0x1234)) +d "in 0x9, #0x5" af090005 0x0 (storew 0 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x9))) (bv 24 0x2)) (bv 16 0x0)) +d "out 0x9, #0x5" 0c090005 0x0 nop +d "mac 0x9, #0x1234" a2091234 0x0 (seq (set oa (var acc)) (set av (ite (== (var pm) (bv 2 0x0)) (var p) (ite (== (var pm) (bv 2 0x1)) (<< (var p) (bv 6 0x1) false) (ite (== (var pm) (bv 2 0x2)) (<< (var p) (bv 6 0x4) false) (>> (var p) (bv 6 0x6) (msb (var p))))))) (set na (+ (var oa) (var av))) (set ovn (msb (& (^ (var na) (var av)) (^ (var oa) (var na))))) (set acc (ite (&& (var ovm) (var ovn)) (ite (&& (sle (var oa) (bv 32 0x0)) (! (== (var oa) (bv 32 0x0)))) (bv 32 0x80000000) (bv 32 0x7fffffff)) (var na))) (set c (&& (ule (var na) (var oa)) (! (== (var na) (var oa))))) (set ov (|| (var ov) (var ovn))) (set m (loadw 0 16 (* (cast 24 false (ite (== (var arp) (bv 16 0x0)) (var ar0) (ite (== (var arp) (bv 16 0x1)) (var ar1) (ite (== (var arp) (bv 16 0x2)) (var ar2) (ite (== (var arp) (bv 16 0x3)) (var ar3) (ite (== (var arp) (bv 16 0x4)) (var ar4) (ite (== (var arp) (bv 16 0x5)) (var ar5) (ite (== (var arp) (bv 16 0x6)) (var ar6) (var ar7))))))))) (bv 24 0x2)))) (set t (var m)) (set p (* (cast 32 (msb (var m)) (var m)) (cast 32 (msb (loadw 0 16 (* (cast 24 false (bv 16 0x0)) (bv 24 0x2)))) (loadw 0 16 (* (cast 24 false (bv 16 0x0)) (bv 24 0x2))))))) +d "ret" ef00 0x0 (seq (set r (loadw 0 16 (* (cast 24 false (var sp)) (bv 24 0x2)))) (set sp (+ (var sp) (bv 16 0x1))) (jmp (var r))) +d "retd" ff00 0x0 (seq (set r (loadw 0 16 (* (cast 24 false (var sp)) (bv 24 0x2)))) (set sp (+ (var sp) (bv 16 0x1))) (jmp (var r))) +d "b 0x40, *" 79800040 0x0 (jmp (bv 16 0x80)) +d "call 0x50, *" 7a800050 0x0 (seq (set sp (- (var sp) (bv 16 0x1))) (storew 0 (* (cast 24 false (var sp)) (bv 24 0x2)) (bv 16 0x2)) (jmp (bv 16 0xa0))) +d "bcnd 0x40, geq" e38c0040 +d "cc 0x50, neq" eb080050 +d "retc geq" ef8c +d "bd 0x40, *" 7d800040 0x0 (jmp (bv 16 0x80)) +d "calld 0x50, *" 7e800050 0x0 (seq (set sp (- (var sp) (bv 16 0x1))) (storew 0 (* (cast 24 false (var sp)) (bv 24 0x2)) (bv 16 0x2)) (jmp (bv 16 0xa0))) +d "rptz #0x7" bec50007 0x0 nop +d "rptb 0x40" bec60040 0x0 nop +d "bsar #0x4" bfe3 +d "bsar #0x1" bfe0 +d "bsar #0x10" bfef +d "lst #0x0, 0x9" 0e09 +d "sst #0x1, 0x10" 8f10 +d "tblr 0x9" a609 0x0 (storew 0 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x9))) (bv 24 0x2)) (loadw 0 16 (* (cast 24 false (cast 16 false (var acc))) (bv 24 0x2)))) +d "tblw 0x9" a709 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x9))) (bv 24 0x2)))) (storew 0 (* (cast 24 false (cast 16 false (var acc))) (bv 24 0x2)) (var m))) +d "dmov 0x9" 7709 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x9))) (bv 24 0x2)))) (storew 0 (* (cast 24 false (+ (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x9)) (bv 16 0x1))) (bv 24 0x2)) (var m))) +d "subc 0x9" 0a09 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x9))) (bv 24 0x2)))) (set oa (var acc)) (set av (<< (ite (var sxm) (cast 32 (msb (var m)) (var m)) (cast 32 false (var m))) (bv 6 0xf) false)) (set na (- (var oa) (var av))) (set ov (|| (var ov) (msb (& (^ (var oa) (var av)) (^ (var oa) (var na)))))) (set c (! (&& (ule (var oa) (var na)) (! (== (var oa) (var na)))))) (set acc (ite (! (&& (ule (var oa) (var av)) (! (== (var oa) (var av))))) (| (<< (var na) (bv 6 0x1) false) (bv 32 0x1)) (<< (var oa) (bv 6 0x1) false)))) +d "bldp 0x9" 5709 +d "mads 0x9" aa09 +d "madd 0x9" ab09 +d "apl 0x9" 5a09 +d "opl 0x9" 5909 +d "xpl 0x9" 5809 +d "cpl 0x9" 5b09 +d "addc 0x9" 6009 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x9))) (bv 24 0x2)))) (set oa (var acc)) (set av (cast 32 false (var m))) (set na (+ (+ (var oa) (var av)) (ite (var c) (bv 32 0x1) (bv 32 0x0)))) (set acc (var na)) (set ov (|| (var ov) (msb (& (^ (var na) (var av)) (^ (var oa) (var na)))))) (set c (ite (== (var na) (var oa)) (var c) (&& (ule (var na) (var oa)) (! (== (var na) (var oa))))))) +d "subb 0x9" 6409 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x9))) (bv 24 0x2)))) (set oa (var acc)) (set av (cast 32 false (var m))) (set na (- (- (var oa) (var av)) (ite (var c) (bv 32 0x0) (bv 32 0x1)))) (set acc (var na)) (set ov (|| (var ov) (msb (& (^ (var oa) (var av)) (^ (var oa) (var na)))))) (set c (ite (== (var na) (var oa)) (var c) (! (&& (ule (var oa) (var na)) (! (== (var oa) (var na)))))))) +d "adds 0x9" 6209 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x9))) (bv 24 0x2)))) (set oa (var acc)) (set av (cast 32 false (var m))) (set na (+ (var oa) (var av))) (set ovn (msb (& (^ (var na) (var av)) (^ (var oa) (var na))))) (set acc (ite (&& (var ovm) (var ovn)) (ite (&& (sle (var oa) (bv 32 0x0)) (! (== (var oa) (bv 32 0x0)))) (bv 32 0x80000000) (bv 32 0x7fffffff)) (var na))) (set c (&& (ule (var na) (var oa)) (! (== (var na) (var oa))))) (set ov (|| (var ov) (var ovn)))) +d "subs 0x9" 6609 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x9))) (bv 24 0x2)))) (set oa (var acc)) (set av (cast 32 false (var m))) (set na (- (var oa) (var av))) (set ovn (msb (& (^ (var oa) (var av)) (^ (var oa) (var na))))) (set acc (ite (&& (var ovm) (var ovn)) (ite (&& (sle (var oa) (bv 32 0x0)) (! (== (var oa) (bv 32 0x0)))) (bv 32 0x80000000) (bv 32 0x7fffffff)) (var na))) (set c (! (&& (ule (var oa) (var na)) (! (== (var oa) (var na)))))) (set ov (|| (var ov) (var ovn)))) +d "addt 0x9" 6309 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x9))) (bv 24 0x2)))) (set oa (var acc)) (set av (<< (ite (var sxm) (cast 32 (msb (var m)) (var m)) (cast 32 false (var m))) (& (var t) (bv 16 0xf)) false)) (set na (+ (var oa) (var av))) (set ovn (msb (& (^ (var na) (var av)) (^ (var oa) (var na))))) (set acc (ite (&& (var ovm) (var ovn)) (ite (&& (sle (var oa) (bv 32 0x0)) (! (== (var oa) (bv 32 0x0)))) (bv 32 0x80000000) (bv 32 0x7fffffff)) (var na))) (set c (&& (ule (var na) (var oa)) (! (== (var na) (var oa))))) (set ov (|| (var ov) (var ovn)))) +d "subt 0x9" 6709 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x9))) (bv 24 0x2)))) (set oa (var acc)) (set av (<< (ite (var sxm) (cast 32 (msb (var m)) (var m)) (cast 32 false (var m))) (& (var t) (bv 16 0xf)) false)) (set na (- (var oa) (var av))) (set ovn (msb (& (^ (var oa) (var av)) (^ (var oa) (var na))))) (set acc (ite (&& (var ovm) (var ovn)) (ite (&& (sle (var oa) (bv 32 0x0)) (! (== (var oa) (bv 32 0x0)))) (bv 32 0x80000000) (bv 32 0x7fffffff)) (var na))) (set c (! (&& (ule (var oa) (var na)) (! (== (var oa) (var na)))))) (set ov (|| (var ov) (var ovn)))) +d "lact 0x9" 6b09 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x9))) (bv 24 0x2)))) (set acc (<< (ite (var sxm) (cast 32 (msb (var m)) (var m)) (cast 32 false (var m))) (& (var t) (bv 16 0xf)) false))) +d "bacc" be20 0x0 (jmp (* (cast 16 false (var acc)) (bv 16 0x2))) +d "cala" be30 0x0 (seq (set sp (- (var sp) (bv 16 0x1))) (storew 0 (* (cast 24 false (var sp)) (bv 24 0x2)) (bv 16 0x1)) (jmp (* (cast 16 false (var acc)) (bv 16 0x2)))) +d "push" be3c 0x0 (seq (set sp (- (var sp) (bv 16 0x1))) (storew 0 (* (cast 24 false (var sp)) (bv 24 0x2)) (cast 16 false (var acc)))) +d "pop" be32 0x0 (seq (set acc (cast 32 false (loadw 0 16 (* (cast 24 false (var sp)) (bv 24 0x2))))) (set sp (+ (var sp) (bv 16 0x1)))) +d "pshd 0x9" 7609 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x9))) (bv 24 0x2)))) (set sp (- (var sp) (bv 16 0x1))) (storew 0 (* (cast 24 false (var sp)) (bv 24 0x2)) (var m))) +d "popd 0x9" 8a09 0x0 (seq (set v (loadw 0 16 (* (cast 24 false (var sp)) (bv 24 0x2)))) (set sp (+ (var sp) (bv 16 0x1))) (storew 0 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x9))) (bv 24 0x2)) (var v))) +d "bit #0x9, 0x0" 4900 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (ite (== (var arp) (bv 16 0x0)) (var ar0) (ite (== (var arp) (bv 16 0x1)) (var ar1) (ite (== (var arp) (bv 16 0x2)) (var ar2) (ite (== (var arp) (bv 16 0x3)) (var ar3) (ite (== (var arp) (bv 16 0x4)) (var ar4) (ite (== (var arp) (bv 16 0x5)) (var ar5) (ite (== (var arp) (bv 16 0x6)) (var ar6) (var ar7))))))))) (bv 24 0x2)))) (set tc (lsb (>> (var m) (bv 4 0xf) false)))) +d "bitt 0x9" 6f09 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x9))) (bv 24 0x2)))) (set tc (lsb (>> (var m) (- (bv 16 0xf) (& (var t) (bv 16 0xf))) false)))) +d "idle" be22 0x0 nop +d "idle2" be23 +d "trap" be51 0x0 (seq (set sp (- (var sp) (bv 16 0x1))) (storew 0 (* (cast 24 false (var sp)) (bv 24 0x2)) (bv 16 0x1)) (jmp (bv 16 0x1e))) +d "rete" be3a 0x0 (seq (set r (loadw 0 16 (* (cast 24 false (var sp)) (bv 24 0x2)))) (set sp (+ (var sp) (bv 16 0x1))) (jmp (var r))) +d "reti" be38 0x0 (seq (set r (loadw 0 16 (* (cast 24 false (var sp)) (bv 24 0x2)))) (set sp (+ (var sp) (bv 16 0x1))) (jmp (var r))) + +# BANZ, lar #imm16, and 16-bit immediate ALU forms (bf-prefixed) +d "banz 0x6, *-" 7b900006 0x0 (seq (set ba (ite (== (var arp) (bv 16 0x0)) (var ar0) (ite (== (var arp) (bv 16 0x1)) (var ar1) (ite (== (var arp) (bv 16 0x2)) (var ar2) (ite (== (var arp) (bv 16 0x3)) (var ar3) (ite (== (var arp) (bv 16 0x4)) (var ar4) (ite (== (var arp) (bv 16 0x5)) (var ar5) (ite (== (var arp) (bv 16 0x6)) (var ar6) (var ar7))))))))) (set ar0 (ite (== (var arp) (bv 16 0x0)) (- (var ar0) (bv 16 0x1)) (var ar0))) (set ar1 (ite (== (var arp) (bv 16 0x1)) (- (var ar1) (bv 16 0x1)) (var ar1))) (set ar2 (ite (== (var arp) (bv 16 0x2)) (- (var ar2) (bv 16 0x1)) (var ar2))) (set ar3 (ite (== (var arp) (bv 16 0x3)) (- (var ar3) (bv 16 0x1)) (var ar3))) (set ar4 (ite (== (var arp) (bv 16 0x4)) (- (var ar4) (bv 16 0x1)) (var ar4))) (set ar5 (ite (== (var arp) (bv 16 0x5)) (- (var ar5) (bv 16 0x1)) (var ar5))) (set ar6 (ite (== (var arp) (bv 16 0x6)) (- (var ar6) (bv 16 0x1)) (var ar6))) (set ar7 (ite (== (var arp) (bv 16 0x7)) (- (var ar7) (bv 16 0x1)) (var ar7))) (branch (! (is_zero (var ba))) (jmp (bv 16 0xc)) nop)) +d "lar ar1, #0x300" bf090300 0x0 (set ar1 (bv 16 0x300)) +d "lacc #0x42" bf800042 0x0 (set acc (ite (var sxm) (bv 32 0x42) (bv 32 0x42))) +d "add #0xff" bf9000ff 0x0 (seq (set oa (var acc)) (set av (ite (var sxm) (bv 32 0xff) (bv 32 0xff))) (set na (+ (var oa) (var av))) (set ovn (msb (& (^ (var na) (var av)) (^ (var oa) (var na))))) (set acc (ite (&& (var ovm) (var ovn)) (ite (&& (sle (var oa) (bv 32 0x0)) (! (== (var oa) (bv 32 0x0)))) (bv 32 0x80000000) (bv 32 0x7fffffff)) (var na))) (set c (&& (ule (var na) (var oa)) (! (== (var na) (var oa))))) (set ov (|| (var ov) (var ovn)))) +d "sub #0x5" bfa00005 0x0 (seq (set oa (var acc)) (set av (ite (var sxm) (bv 32 0x5) (bv 32 0x5))) (set na (- (var oa) (var av))) (set ovn (msb (& (^ (var oa) (var av)) (^ (var oa) (var na))))) (set acc (ite (&& (var ovm) (var ovn)) (ite (&& (sle (var oa) (bv 32 0x0)) (! (== (var oa) (bv 32 0x0)))) (bv 32 0x80000000) (bv 32 0x7fffffff)) (var na))) (set c (! (&& (ule (var oa) (var na)) (! (== (var oa) (var na)))))) (set ov (|| (var ov) (var ovn)))) +d "and #0xff" bfb000ff 0x0 (set acc (& (var acc) (bv 32 0xff))) +d "or #0x100" bfc00100 0x0 (set acc (| (var acc) (bv 32 0x100))) +d "xor #0x55" bfd00055 0x0 (set acc (^ (var acc) (bv 32 0x55))) + +# additional lifted forms: compare-and-set-TC, T-load-with-signed-subtract, +# square-subtract and the MPYA/MPYS accumulate-then-multiply pair. IL +# cross-checked by executing each in the RzIL VM and comparing acc/t/p +# against the external TMS320 emulator (identical results). +d "cmpr #0x0" bf40 0x0 (set tc (== (ite (== (var arp) (bv 16 0x0)) (var ar0) (ite (== (var arp) (bv 16 0x1)) (var ar1) (ite (== (var arp) (bv 16 0x2)) (var ar2) (ite (== (var arp) (bv 16 0x3)) (var ar3) (ite (== (var arp) (bv 16 0x4)) (var ar4) (ite (== (var arp) (bv 16 0x5)) (var ar5) (ite (== (var arp) (bv 16 0x6)) (var ar6) (var ar7)))))))) (var ar0))) +d "lts 0x0" 7400 0x0 (seq (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x0))) (bv 24 0x2)))) (set t (var m)) (set oa (var acc)) (set av (ite (== (var pm) (bv 2 0x0)) (var p) (ite (== (var pm) (bv 2 0x1)) (<< (var p) (bv 6 0x1) false) (ite (== (var pm) (bv 2 0x2)) (<< (var p) (bv 6 0x4) false) (>> (var p) (bv 6 0x6) (msb (var p))))))) (set na (- (var oa) (var av))) (set ovn (msb (& (^ (var oa) (var av)) (^ (var oa) (var na))))) (set acc (ite (&& (var ovm) (var ovn)) (ite (&& (sle (var oa) (bv 32 0x0)) (! (== (var oa) (bv 32 0x0)))) (bv 32 0x80000000) (bv 32 0x7fffffff)) (var na))) (set c (! (&& (ule (var oa) (var na)) (! (== (var oa) (var na)))))) (set ov (|| (var ov) (var ovn)))) +d "sqrs 0x0" 5300 0x0 (seq (set oa (var acc)) (set av (ite (== (var pm) (bv 2 0x0)) (var p) (ite (== (var pm) (bv 2 0x1)) (<< (var p) (bv 6 0x1) false) (ite (== (var pm) (bv 2 0x2)) (<< (var p) (bv 6 0x4) false) (>> (var p) (bv 6 0x6) (msb (var p))))))) (set na (- (var oa) (var av))) (set ovn (msb (& (^ (var oa) (var av)) (^ (var oa) (var na))))) (set acc (ite (&& (var ovm) (var ovn)) (ite (&& (sle (var oa) (bv 32 0x0)) (! (== (var oa) (bv 32 0x0)))) (bv 32 0x80000000) (bv 32 0x7fffffff)) (var na))) (set c (! (&& (ule (var oa) (var na)) (! (== (var oa) (var na)))))) (set ov (|| (var ov) (var ovn))) (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x0))) (bv 24 0x2)))) (set t (var m)) (set p (* (cast 32 (msb (var m)) (var m)) (cast 32 (msb (var m)) (var m))))) +d "mpya 0x0" 5000 0x0 (seq (set oa (var acc)) (set av (ite (== (var pm) (bv 2 0x0)) (var p) (ite (== (var pm) (bv 2 0x1)) (<< (var p) (bv 6 0x1) false) (ite (== (var pm) (bv 2 0x2)) (<< (var p) (bv 6 0x4) false) (>> (var p) (bv 6 0x6) (msb (var p))))))) (set na (+ (var oa) (var av))) (set ovn (msb (& (^ (var na) (var av)) (^ (var oa) (var na))))) (set acc (ite (&& (var ovm) (var ovn)) (ite (&& (sle (var oa) (bv 32 0x0)) (! (== (var oa) (bv 32 0x0)))) (bv 32 0x80000000) (bv 32 0x7fffffff)) (var na))) (set c (&& (ule (var na) (var oa)) (! (== (var na) (var oa))))) (set ov (|| (var ov) (var ovn))) (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x0))) (bv 24 0x2)))) (set p (* (cast 32 (msb (var m)) (var m)) (cast 32 (msb (var t)) (var t))))) +d "mpys 0x0" 5100 0x0 (seq (set oa (var acc)) (set av (ite (== (var pm) (bv 2 0x0)) (var p) (ite (== (var pm) (bv 2 0x1)) (<< (var p) (bv 6 0x1) false) (ite (== (var pm) (bv 2 0x2)) (<< (var p) (bv 6 0x4) false) (>> (var p) (bv 6 0x6) (msb (var p))))))) (set na (- (var oa) (var av))) (set ovn (msb (& (^ (var oa) (var av)) (^ (var oa) (var na))))) (set acc (ite (&& (var ovm) (var ovn)) (ite (&& (sle (var oa) (bv 32 0x0)) (! (== (var oa) (bv 32 0x0)))) (bv 32 0x80000000) (bv 32 0x7fffffff)) (var na))) (set c (! (&& (ule (var oa) (var na)) (! (== (var oa) (var na)))))) (set ov (|| (var ov) (var ovn))) (set m (loadw 0 16 (* (cast 24 false (| (<< (& (var dp) (bv 16 0x1ff)) (bv 16 0x7) false) (bv 16 0x0))) (bv 24 0x2)))) (set p (* (cast 32 (msb (var m)) (var m)) (cast 32 (msb (var t)) (var t))))) diff --git a/test/db/cmd/cmd_aL b/test/db/cmd/cmd_aL index 891249440f0..22bb285112e 100644 --- a/test/db/cmd/cmd_aL +++ b/test/db/cmd/cmd_aL @@ -57,7 +57,7 @@ _dA__ 8 16 snes LGPL3 SuperNES CPU disassembler _dA_I 32 64 sparc BSD Sun SPARC Capstone-based disassembler _dA__ 16 spc700 LGPL3 Sony SPC700 (Nintendo SuperNES sound-chip) disassembler _dA__ 32 64 sysz BSD IBM SystemZ (S/390) Capstone-based disassembler -_dA_I 32 tms320 LGPL3 Texas Instruments TMS320 DSP family (c54x,c55x,c55x+,c64x) disassembler +_dA_I 16 32 tms320 LGPL3 Texas Instruments TMS320 DSP family (c54x,c55x,c55x+,c2x,c5x,c64x) disassembler _dA_I 32 tricore BSD Siemens TriCore Capstone-based disassembler (by billow) _dAeI 32 v810 LGPL3 NEC V810 disassembler (by pancake) _dAeI 32 v850 LGPL3 NEC/Renesas V850 disassembler @@ -183,6 +183,8 @@ ps PowerPC with Paired Single SIMD extension qpx PowerPC with Quad Processing eXtensions v9 SPARC V9: 64-bit RISC architecture specification c54x Texas Instruments TMS320C54x DSP family +c2x Texas Instruments TMS320C2x legacy fixed-point DSP family +c5x Texas Instruments TMS320C5x fixed-point DSP family (C2x-compatible superset) c55x Texas Instruments TMS320C55x DSP family c55x+ Texas Instruments TMS320C55x+ DSP family c64x Texas Instruments TMS320C64x DSP family diff --git a/test/db/cmd/cmd_list b/test/db/cmd/cmd_list index 08a5332423a..8b44ae1f6ee 100644 --- a/test/db/cmd/cmd_list +++ b/test/db/cmd/cmd_list @@ -796,7 +796,7 @@ _dA__ 8 16 snes LGPL3 SuperNES CPU disassembler _dA_I 32 64 sparc BSD Sun SPARC Capstone-based disassembler _dA__ 16 spc700 LGPL3 Sony SPC700 (Nintendo SuperNES sound-chip) disassembler _dA__ 32 64 sysz BSD IBM SystemZ (S/390) Capstone-based disassembler -_dA_I 32 tms320 LGPL3 Texas Instruments TMS320 DSP family (c54x,c55x,c55x+,c64x) disassembler +_dA_I 16 32 tms320 LGPL3 Texas Instruments TMS320 DSP family (c54x,c55x,c55x+,c2x,c5x,c64x) disassembler _dA_I 32 tricore BSD Siemens TriCore Capstone-based disassembler (by billow) _dAeI 32 v810 LGPL3 NEC V810 disassembler (by pancake) _dAeI 32 v850 LGPL3 NEC/Renesas V850 disassembler @@ -810,9 +810,9 @@ _dA__ 16 xap PD Cambridge Consultants XAP4 RISC (CSR) disas _dA__ 32 xcore BSD XCore Capstone-based disassembler (by pancake) _dAeI 32 xtensa LGPL3 Tensilica Xtensa Capstone-based disassembler (by billow) adA__ 8 z80 GPL3 Zilog Z80 disassembler (by condret) -["6502":{"bits":"8 16 ","license":"LGPL3","description":"6502/NES/C64/Tamagotchi/T-1000 CPU","features":"_dAeI"},"8051":{"bits":"8 ","license":"PD","description":"Intel 8051 disassembler","features":"adAeI"},"alpha":{"bits":"32 64","license":"LGPL3","description":"DEC Alpha Capstone-based disassembler","features":"_dA__"},"amd29k":{"bits":"32 ","license":"LGPL3","description":"AMD 29k RISC disassembler","features":"_dA__","author":"deroad"},"arc":{"bits":"16 32 ","license":"GPL3","description":"Argonaut RISC Core","features":"_dA__"},"arm":{"bits":"16 32 64","license":"BSD","description":"ARM Capstone-based disassembler","features":"adAeI"},"arm.as":{"bits":"16 32 64","license":"LGPL3","description":"as ARM Assembler (use RZ_ARM32_AS and RZ_ARM64_AS environment)","features":"a____","author":"pancake"},"avr":{"bits":"8 16 ","license":"LGPL3","description":"Atmel AVR disassembler","features":"adAeI"},"bf":{"bits":"16 32 64","license":"LGPL3","description":"Brainfuck","features":"adA_I","author":"pancake, nibble","version":"4.0.0"},"c166":{"bits":"16 ","license":"LGPL3","description":"Siemens/Infineon C166 microcontroller disassembler","features":"_dA__"},"cbpf":{"bits":"32 ","license":"LGPL3","description":"CBPF disassembly plugin","features":"_dA__"},"chip8":{"bits":"32 ","license":"LGPL3","description":"Chip8 disassembler","features":"_dA__"},"cil":{"bits":"16 32 64","license":"LGPL3","description":".NET CIL/MSIL (Common Intermediate Language) bytecode disassembler","features":"_dA__"},"cr16":{"bits":"16 ","license":"LGPL3","description":"CompactRISC CR16 disassembler","features":"_dA__"},"cris":{"bits":"32 ","license":"GPL3","description":"Axis Communications 32-bit embedded processor disassembler","features":"_dA__","author":"pancake"},"dalvik":{"bits":"32 64","license":"LGPL3","description":"Dalvik (Android VM) bytecode disassembler","features":"adA__"},"dcpu16":{"bits":"16 ","license":"PD","description":"Mojang's DCPU-16 disassembler","features":"ad___"},"ebc":{"bits":"32 64","license":"LGPL3","description":"EFI bytecode disassembler","features":"_dA__","author":"Fedor Sakharov"},"gb":{"bits":"16 ","license":"LGPL3","description":"GameBoy(TM) (z80-like)","features":"adAeI","author":"condret"},"h8300":{"bits":"16 ","license":"LGPL3","description":"Hitachi/Renesas H8/300 disassembly plugin","features":"_dAeI"},"h8500":{"bits":"16 ","license":"LGPL3","description":"Hitachi/Renesas H8/500 disassembler","features":"_dA__","author":"billow"},"hexagon":{"bits":"32 ","license":"LGPL3","description":"Qualcomm Hexagon (QDSP6) V6","features":"_dA_I","author":"Rot127"},"hppa":{"bits":"32 64","license":"LGPL3","description":"HP PA-RISC Capstone-based disassembler","features":"_dA__","author":"xvilka"},"i4004":{"bits":"4 ","license":"LGPL3","description":"Intel 4004 disassembler","features":"_dA__"},"i8080":{"bits":"8 ","license":"BSD","description":"Intel 8080 disassembler","features":"_dA__"},"java":{"bits":"32 ","license":"LGPL-3","description":"Java bytecode disassembler","features":"adA__","author":"deroad"},"lanai":{"bits":"32 ","license":"GPL3","description":"Google LANAI disassembler","features":"_d___"},"lh5801":{"bits":"8 ","license":"LGPL3","description":"SHARP LH5801 disassembler","features":"_d___"},"lm32":{"bits":"32 ","license":"BSD","description":"Lattice Micro 32 ISA disassembler","features":"_d___","author":"Felix Held"},"loongarch":{"bits":"32 64","license":"LGPL3","description":"Loongson LoongArch disassembler","features":"_dA__"},"luac":{"bits":"32 ","license":"LGPL3","description":"Lua bytecode (LUAC) disassembler","features":"adA__"},"m680x":{"bits":"8 32 ","license":"BSD","description":"Motorola 680X Capstone-based disassembler","features":"_dA__"},"m68k":{"bits":"32 ","license":"BSD","description":"Motorola 68K Capstone-based disassembler","features":"_dA__"},"malbolge":{"bits":"32 ","license":"LGPL3","description":"Malbolge Ternary VM bytecode disassembler","features":"_dA__","author":"condret"},"mcore":{"bits":"32 ","license":"LGPL3","description":"Motorola MCORE disassembler","features":"_dA__"},"mcs96":{"bits":"16 ","license":"LGPL3","description":"Intel MCS-96 disassembler","features":"_dA__","author":"condret"},"milstd1750":{"bits":"8 ","license":"MIT","description":"MIL-STD 1750 ISA disassembler","features":"_dA__"},"mips":{"bits":"16 32 64","license":"BSD","description":"MIPS Capstone-based disassembler","features":"adAeI"},"msp430":{"bits":"16 ","license":"LGPL3","description":"Texas Instruments MSP430 disassembler","features":"_dA_I"},"null":{"bits":"16 32 64","license":"MIT","description":"NULL (empty) disassembler","features":"adA__","author":"pancake","version":"1.0.0"},"or1k":{"bits":"32 ","license":"LGPL3","description":"OpenRISC 1000 disassembler","features":"_dA__"},"pic":{"bits":"16 32 ","license":"LGPL3","description":"Microchip PIC disassembler","features":"_dAeI"},"ppc":{"bits":"32 64","license":"BSD","description":"PowerPC Capstone-based disassembler","features":"_dAeI","author":"pancake"},"ppc.as":{"bits":"32 64","license":"LGPL3","description":"as PPC Assembler (use RZ_PPC_AS environment)","features":"a____","author":"eagleoflqj"},"propeller":{"bits":"32 ","license":"LGPL3","description":"Parallax Propeller disassembler","features":"_dA__"},"pyc":{"bits":"8 16 ","license":"LGPL3","description":"Python bytecode (PYC) disassembler","features":"_dA__"},"riscv":{"bits":"32 64","license":"BSD","description":"RISC-V Capstone-based disassembler","features":"_dA__"},"rl78":{"bits":"32 ","license":"LGPL3","description":"Renesas RL78 disassembler","features":"adA__","author":"Bastian Engel"},"rsp":{"bits":"32 ","license":"LGPL3","description":"Nintendo N64 Reality Signal Processor disassembler","features":"_dA__"},"rx":{"bits":"32 ","license":"LGPL3","description":"Renesas RX Family disassembler","features":"_dA__","author":"Heersin"},"sh":{"bits":"32 ","license":"LGPL3","description":"Hitachi/Renesas SuperH-4/SuperH-3 disassembler","features":"adAeI","author":"DMaroo"},"snes":{"bits":"8 16 ","license":"LGPL3","description":"SuperNES CPU disassembler","features":"_dA__"},"sparc":{"bits":"32 64","license":"BSD","description":"Sun SPARC Capstone-based disassembler","features":"_dA_I"},"spc700":{"bits":"16 ","license":"LGPL3","description":"Sony SPC700 (Nintendo SuperNES sound-chip) disassembler","features":"_dA__"},"sysz":{"bits":"32 64","license":"BSD","description":"IBM SystemZ (S/390) Capstone-based disassembler","features":"_dA__"},"tms320":{"bits":"32 ","license":"LGPL3","description":"Texas Instruments TMS320 DSP family (c54x,c55x,c55x+,c64x) disassembler","features":"_dA_I"},"tricore":{"bits":"32 ","license":"BSD","description":"Siemens TriCore Capstone-based disassembler","features":"_dA_I","author":"billow"},"v810":{"bits":"32 ","license":"LGPL3","description":"NEC V810 disassembler","features":"_dAeI","author":"pancake"},"v850":{"bits":"32 ","license":"LGPL3","description":"NEC/Renesas V850 disassembler","features":"_dAeI"},"vax":{"bits":"32 ","license":"LGPL3","description":"DEC VAX-11 disassembler","features":"_dA__","author":"xvilka"},"wasm":{"bits":"32 ","license":"MIT","description":"WebAssembly disassembler","features":"adA__","author":"cgvwzq","version":"0.1.0"},"x86":{"bits":"16 32 64","license":"MIT","description":"X86/X86_64 Zydis-based disassembler","features":"_dAeI"},"x86.as":{"bits":"16 32 64","license":"LGPL3","description":"Intel X86 GNU Assembler (Use RZ_X86_AS env)","features":"a____"},"x86.nasm":{"bits":"16 32 64","license":"LGPL3","description":"X86 nasm assembler","features":"a____"},"x86.nz":{"bits":"16 32 64","license":"LGPL3","description":"x86 handmade assembler","features":"a____"},"xap":{"bits":"16 ","license":"PD","description":"Cambridge Consultants XAP4 RISC (CSR) disassembler","features":"_dA__"},"xcore":{"bits":"32 ","license":"BSD","description":"XCore Capstone-based disassembler","features":"_dA__","author":"pancake"},"xtensa":{"bits":"32 ","license":"LGPL3","description":"Tensilica Xtensa Capstone-based disassembler","features":"_dAeI","author":"billow"},"z80":{"bits":"8 ","license":"GPL3","description":"Zilog Z80 disassembler","features":"adA__","author":"condret"}] -name bits features license version author description ----------------------------------------------------------------------------------------------------------------------------------- +["6502":{"bits":"8 16 ","license":"LGPL3","description":"6502/NES/C64/Tamagotchi/T-1000 CPU","features":"_dAeI"},"8051":{"bits":"8 ","license":"PD","description":"Intel 8051 disassembler","features":"adAeI"},"alpha":{"bits":"32 64","license":"LGPL3","description":"DEC Alpha Capstone-based disassembler","features":"_dA__"},"amd29k":{"bits":"32 ","license":"LGPL3","description":"AMD 29k RISC disassembler","features":"_dA__","author":"deroad"},"arc":{"bits":"16 32 ","license":"GPL3","description":"Argonaut RISC Core","features":"_dA__"},"arm":{"bits":"16 32 64","license":"BSD","description":"ARM Capstone-based disassembler","features":"adAeI"},"arm.as":{"bits":"16 32 64","license":"LGPL3","description":"as ARM Assembler (use RZ_ARM32_AS and RZ_ARM64_AS environment)","features":"a____","author":"pancake"},"avr":{"bits":"8 16 ","license":"LGPL3","description":"Atmel AVR disassembler","features":"adAeI"},"bf":{"bits":"16 32 64","license":"LGPL3","description":"Brainfuck","features":"adA_I","author":"pancake, nibble","version":"4.0.0"},"c166":{"bits":"16 ","license":"LGPL3","description":"Siemens/Infineon C166 microcontroller disassembler","features":"_dA__"},"cbpf":{"bits":"32 ","license":"LGPL3","description":"CBPF disassembly plugin","features":"_dA__"},"chip8":{"bits":"32 ","license":"LGPL3","description":"Chip8 disassembler","features":"_dA__"},"cil":{"bits":"16 32 64","license":"LGPL3","description":".NET CIL/MSIL (Common Intermediate Language) bytecode disassembler","features":"_dA__"},"cr16":{"bits":"16 ","license":"LGPL3","description":"CompactRISC CR16 disassembler","features":"_dA__"},"cris":{"bits":"32 ","license":"GPL3","description":"Axis Communications 32-bit embedded processor disassembler","features":"_dA__","author":"pancake"},"dalvik":{"bits":"32 64","license":"LGPL3","description":"Dalvik (Android VM) bytecode disassembler","features":"adA__"},"dcpu16":{"bits":"16 ","license":"PD","description":"Mojang's DCPU-16 disassembler","features":"ad___"},"ebc":{"bits":"32 64","license":"LGPL3","description":"EFI bytecode disassembler","features":"_dA__","author":"Fedor Sakharov"},"gb":{"bits":"16 ","license":"LGPL3","description":"GameBoy(TM) (z80-like)","features":"adAeI","author":"condret"},"h8300":{"bits":"16 ","license":"LGPL3","description":"Hitachi/Renesas H8/300 disassembly plugin","features":"_dAeI"},"h8500":{"bits":"16 ","license":"LGPL3","description":"Hitachi/Renesas H8/500 disassembler","features":"_dA__","author":"billow"},"hexagon":{"bits":"32 ","license":"LGPL3","description":"Qualcomm Hexagon (QDSP6) V6","features":"_dA_I","author":"Rot127"},"hppa":{"bits":"32 64","license":"LGPL3","description":"HP PA-RISC Capstone-based disassembler","features":"_dA__","author":"xvilka"},"i4004":{"bits":"4 ","license":"LGPL3","description":"Intel 4004 disassembler","features":"_dA__"},"i8080":{"bits":"8 ","license":"BSD","description":"Intel 8080 disassembler","features":"_dA__"},"java":{"bits":"32 ","license":"LGPL-3","description":"Java bytecode disassembler","features":"adA__","author":"deroad"},"lanai":{"bits":"32 ","license":"GPL3","description":"Google LANAI disassembler","features":"_d___"},"lh5801":{"bits":"8 ","license":"LGPL3","description":"SHARP LH5801 disassembler","features":"_d___"},"lm32":{"bits":"32 ","license":"BSD","description":"Lattice Micro 32 ISA disassembler","features":"_d___","author":"Felix Held"},"loongarch":{"bits":"32 64","license":"LGPL3","description":"Loongson LoongArch disassembler","features":"_dA__"},"luac":{"bits":"32 ","license":"LGPL3","description":"Lua bytecode (LUAC) disassembler","features":"adA__"},"m680x":{"bits":"8 32 ","license":"BSD","description":"Motorola 680X Capstone-based disassembler","features":"_dA__"},"m68k":{"bits":"32 ","license":"BSD","description":"Motorola 68K Capstone-based disassembler","features":"_dA__"},"malbolge":{"bits":"32 ","license":"LGPL3","description":"Malbolge Ternary VM bytecode disassembler","features":"_dA__","author":"condret"},"mcore":{"bits":"32 ","license":"LGPL3","description":"Motorola MCORE disassembler","features":"_dA__"},"mcs96":{"bits":"16 ","license":"LGPL3","description":"Intel MCS-96 disassembler","features":"_dA__","author":"condret"},"milstd1750":{"bits":"8 ","license":"MIT","description":"MIL-STD 1750 ISA disassembler","features":"_dA__"},"mips":{"bits":"16 32 64","license":"BSD","description":"MIPS Capstone-based disassembler","features":"adAeI"},"msp430":{"bits":"16 ","license":"LGPL3","description":"Texas Instruments MSP430 disassembler","features":"_dA_I"},"null":{"bits":"16 32 64","license":"MIT","description":"NULL (empty) disassembler","features":"adA__","author":"pancake","version":"1.0.0"},"or1k":{"bits":"32 ","license":"LGPL3","description":"OpenRISC 1000 disassembler","features":"_dA__"},"pic":{"bits":"16 32 ","license":"LGPL3","description":"Microchip PIC disassembler","features":"_dAeI"},"ppc":{"bits":"32 64","license":"BSD","description":"PowerPC Capstone-based disassembler","features":"_dAeI","author":"pancake"},"ppc.as":{"bits":"32 64","license":"LGPL3","description":"as PPC Assembler (use RZ_PPC_AS environment)","features":"a____","author":"eagleoflqj"},"propeller":{"bits":"32 ","license":"LGPL3","description":"Parallax Propeller disassembler","features":"_dA__"},"pyc":{"bits":"8 16 ","license":"LGPL3","description":"Python bytecode (PYC) disassembler","features":"_dA__"},"riscv":{"bits":"32 64","license":"BSD","description":"RISC-V Capstone-based disassembler","features":"_dA__"},"rl78":{"bits":"32 ","license":"LGPL3","description":"Renesas RL78 disassembler","features":"adA__","author":"Bastian Engel"},"rsp":{"bits":"32 ","license":"LGPL3","description":"Nintendo N64 Reality Signal Processor disassembler","features":"_dA__"},"rx":{"bits":"32 ","license":"LGPL3","description":"Renesas RX Family disassembler","features":"_dA__","author":"Heersin"},"sh":{"bits":"32 ","license":"LGPL3","description":"Hitachi/Renesas SuperH-4/SuperH-3 disassembler","features":"adAeI","author":"DMaroo"},"snes":{"bits":"8 16 ","license":"LGPL3","description":"SuperNES CPU disassembler","features":"_dA__"},"sparc":{"bits":"32 64","license":"BSD","description":"Sun SPARC Capstone-based disassembler","features":"_dA_I"},"spc700":{"bits":"16 ","license":"LGPL3","description":"Sony SPC700 (Nintendo SuperNES sound-chip) disassembler","features":"_dA__"},"sysz":{"bits":"32 64","license":"BSD","description":"IBM SystemZ (S/390) Capstone-based disassembler","features":"_dA__"},"tms320":{"bits":"16 32 ","license":"LGPL3","description":"Texas Instruments TMS320 DSP family (c54x,c55x,c55x+,c2x,c5x,c64x) disassembler","features":"_dA_I"},"tricore":{"bits":"32 ","license":"BSD","description":"Siemens TriCore Capstone-based disassembler","features":"_dA_I","author":"billow"},"v810":{"bits":"32 ","license":"LGPL3","description":"NEC V810 disassembler","features":"_dAeI","author":"pancake"},"v850":{"bits":"32 ","license":"LGPL3","description":"NEC/Renesas V850 disassembler","features":"_dAeI"},"vax":{"bits":"32 ","license":"LGPL3","description":"DEC VAX-11 disassembler","features":"_dA__","author":"xvilka"},"wasm":{"bits":"32 ","license":"MIT","description":"WebAssembly disassembler","features":"adA__","author":"cgvwzq","version":"0.1.0"},"x86":{"bits":"16 32 64","license":"MIT","description":"X86/X86_64 Zydis-based disassembler","features":"_dAeI"},"x86.as":{"bits":"16 32 64","license":"LGPL3","description":"Intel X86 GNU Assembler (Use RZ_X86_AS env)","features":"a____"},"x86.nasm":{"bits":"16 32 64","license":"LGPL3","description":"X86 nasm assembler","features":"a____"},"x86.nz":{"bits":"16 32 64","license":"LGPL3","description":"x86 handmade assembler","features":"a____"},"xap":{"bits":"16 ","license":"PD","description":"Cambridge Consultants XAP4 RISC (CSR) disassembler","features":"_dA__"},"xcore":{"bits":"32 ","license":"BSD","description":"XCore Capstone-based disassembler","features":"_dA__","author":"pancake"},"xtensa":{"bits":"32 ","license":"LGPL3","description":"Tensilica Xtensa Capstone-based disassembler","features":"_dAeI","author":"billow"},"z80":{"bits":"8 ","license":"GPL3","description":"Zilog Z80 disassembler","features":"adA__","author":"condret"}] +name bits features license version author description +------------------------------------------------------------------------------------------------------------------------------------------ _dAeI 8 16 6502 LGPL3 6502/NES/C64/Tamagotchi/T-1000 CPU adAeI 8 8051 PD Intel 8051 disassembler _dA__ 32 64 alpha LGPL3 DEC Alpha Capstone-based disassembler @@ -868,7 +868,7 @@ _dA__ 8 16 snes LGPL3 SuperNES CPU disassemb _dA_I 32 64 sparc BSD Sun SPARC Capstone-based disassembler _dA__ 16 spc700 LGPL3 Sony SPC700 (Nintendo SuperNES sound-chip) disassembler _dA__ 32 64 sysz BSD IBM SystemZ (S/390) Capstone-based disassembler -_dA_I 32 tms320 LGPL3 Texas Instruments TMS320 DSP family (c54x,c55x,c55x+,c64x) disassembler +_dA_I 16 32 tms320 LGPL3 Texas Instruments TMS320 DSP family (c54x,c55x,c55x+,c2x,c5x,c64x) disassembler _dA_I 32 tricore BSD billow Siemens TriCore Capstone-based disassembler _dAeI 32 v810 LGPL3 pancake NEC V810 disassembler _dAeI 32 v850 LGPL3 NEC/Renesas V850 disassembler @@ -996,7 +996,7 @@ _dAeI 16 32 pic LGPL3 Microchip PIC disassembler _dAeI 32 64 ppc BSD PowerPC Capstone-based disassembler (by pancake) adAeI 32 sh LGPL3 Hitachi/Renesas SuperH-4/SuperH-3 disassembler (by DMaroo) _dA_I 32 64 sparc BSD Sun SPARC Capstone-based disassembler -_dA_I 32 tms320 LGPL3 Texas Instruments TMS320 DSP family (c54x,c55x,c55x+,c64x) disassembler +_dA_I 16 32 tms320 LGPL3 Texas Instruments TMS320 DSP family (c54x,c55x,c55x+,c2x,c5x,c64x) disassembler _dA_I 32 tricore BSD Siemens TriCore Capstone-based disassembler (by billow) _dAeI 32 v810 LGPL3 NEC V810 disassembler (by pancake) _dAeI 32 v850 LGPL3 NEC/Renesas V850 disassembler @@ -1124,7 +1124,7 @@ a____ 16 32 64 x86.as LGPL3 Intel X86 GNU Assembler (Use RZ_X86_AS env) a____ 16 32 64 x86.nasm LGPL3 X86 nasm assembler a____ 16 32 64 x86.nz LGPL3 x86 handmade assembler adA__ 8 z80 GPL3 Zilog Z80 disassembler (by condret) -["6502":{"bits":"8 16 ","license":"LGPL3","description":"6502/NES/C64/Tamagotchi/T-1000 CPU","features":"_dAeI"},"8051":{"bits":"8 ","license":"PD","description":"Intel 8051 disassembler","features":"adAeI"},"arm":{"bits":"16 32 64","license":"BSD","description":"ARM Capstone-based disassembler","features":"adAeI"},"avr":{"bits":"8 16 ","license":"LGPL3","description":"Atmel AVR disassembler","features":"adAeI"},"bf":{"bits":"16 32 64","license":"LGPL3","description":"Brainfuck","features":"adA_I","author":"pancake, nibble","version":"4.0.0"},"gb":{"bits":"16 ","license":"LGPL3","description":"GameBoy(TM) (z80-like)","features":"adAeI","author":"condret"},"h8300":{"bits":"16 ","license":"LGPL3","description":"Hitachi/Renesas H8/300 disassembly plugin","features":"_dAeI"},"hexagon":{"bits":"32 ","license":"LGPL3","description":"Qualcomm Hexagon (QDSP6) V6","features":"_dA_I","author":"Rot127"},"mips":{"bits":"16 32 64","license":"BSD","description":"MIPS Capstone-based disassembler","features":"adAeI"},"msp430":{"bits":"16 ","license":"LGPL3","description":"Texas Instruments MSP430 disassembler","features":"_dA_I"},"pic":{"bits":"16 32 ","license":"LGPL3","description":"Microchip PIC disassembler","features":"_dAeI"},"ppc":{"bits":"32 64","license":"BSD","description":"PowerPC Capstone-based disassembler","features":"_dAeI","author":"pancake"},"sh":{"bits":"32 ","license":"LGPL3","description":"Hitachi/Renesas SuperH-4/SuperH-3 disassembler","features":"adAeI","author":"DMaroo"},"sparc":{"bits":"32 64","license":"BSD","description":"Sun SPARC Capstone-based disassembler","features":"_dA_I"},"tms320":{"bits":"32 ","license":"LGPL3","description":"Texas Instruments TMS320 DSP family (c54x,c55x,c55x+,c64x) disassembler","features":"_dA_I"},"tricore":{"bits":"32 ","license":"BSD","description":"Siemens TriCore Capstone-based disassembler","features":"_dA_I","author":"billow"},"v810":{"bits":"32 ","license":"LGPL3","description":"NEC V810 disassembler","features":"_dAeI","author":"pancake"},"v850":{"bits":"32 ","license":"LGPL3","description":"NEC/Renesas V850 disassembler","features":"_dAeI"},"x86":{"bits":"16 32 64","license":"MIT","description":"X86/X86_64 Zydis-based disassembler","features":"_dAeI"},"xtensa":{"bits":"32 ","license":"LGPL3","description":"Tensilica Xtensa Capstone-based disassembler","features":"_dAeI","author":"billow"}] +["6502":{"bits":"8 16 ","license":"LGPL3","description":"6502/NES/C64/Tamagotchi/T-1000 CPU","features":"_dAeI"},"8051":{"bits":"8 ","license":"PD","description":"Intel 8051 disassembler","features":"adAeI"},"arm":{"bits":"16 32 64","license":"BSD","description":"ARM Capstone-based disassembler","features":"adAeI"},"avr":{"bits":"8 16 ","license":"LGPL3","description":"Atmel AVR disassembler","features":"adAeI"},"bf":{"bits":"16 32 64","license":"LGPL3","description":"Brainfuck","features":"adA_I","author":"pancake, nibble","version":"4.0.0"},"gb":{"bits":"16 ","license":"LGPL3","description":"GameBoy(TM) (z80-like)","features":"adAeI","author":"condret"},"h8300":{"bits":"16 ","license":"LGPL3","description":"Hitachi/Renesas H8/300 disassembly plugin","features":"_dAeI"},"hexagon":{"bits":"32 ","license":"LGPL3","description":"Qualcomm Hexagon (QDSP6) V6","features":"_dA_I","author":"Rot127"},"mips":{"bits":"16 32 64","license":"BSD","description":"MIPS Capstone-based disassembler","features":"adAeI"},"msp430":{"bits":"16 ","license":"LGPL3","description":"Texas Instruments MSP430 disassembler","features":"_dA_I"},"pic":{"bits":"16 32 ","license":"LGPL3","description":"Microchip PIC disassembler","features":"_dAeI"},"ppc":{"bits":"32 64","license":"BSD","description":"PowerPC Capstone-based disassembler","features":"_dAeI","author":"pancake"},"sh":{"bits":"32 ","license":"LGPL3","description":"Hitachi/Renesas SuperH-4/SuperH-3 disassembler","features":"adAeI","author":"DMaroo"},"sparc":{"bits":"32 64","license":"BSD","description":"Sun SPARC Capstone-based disassembler","features":"_dA_I"},"tms320":{"bits":"16 32 ","license":"LGPL3","description":"Texas Instruments TMS320 DSP family (c54x,c55x,c55x+,c2x,c5x,c64x) disassembler","features":"_dA_I"},"tricore":{"bits":"32 ","license":"BSD","description":"Siemens TriCore Capstone-based disassembler","features":"_dA_I","author":"billow"},"v810":{"bits":"32 ","license":"LGPL3","description":"NEC V810 disassembler","features":"_dAeI","author":"pancake"},"v850":{"bits":"32 ","license":"LGPL3","description":"NEC/Renesas V850 disassembler","features":"_dAeI"},"x86":{"bits":"16 32 64","license":"MIT","description":"X86/X86_64 Zydis-based disassembler","features":"_dAeI"},"xtensa":{"bits":"32 ","license":"LGPL3","description":"Tensilica Xtensa Capstone-based disassembler","features":"_dAeI","author":"billow"}] name bits features license version author description ----------------------------------------------------------------------------------------------- _dAeI 8 16 6502 LGPL3 6502/NES/C64/Tamagotchi/T-1000 CPU @@ -1162,7 +1162,7 @@ NAME=Print the asm/analysis plugins in JSON FILE== CMDS=Laj EXPECT=<