From 032174867492f0c62609b567858935132d59e932 Mon Sep 17 00:00:00 2001 From: bubblepipe Date: Tue, 16 Dec 2025 00:09:37 +0800 Subject: [PATCH] librz/arch: add analysis plugin for MCS96 (#5622) --- librz/arch/isa/mcs96/mcs96.h | 405 +++++++++ librz/arch/p/analysis/analysis_mcs96.c | 1098 ++++++++++++++++++++++++ librz/arch/p/arch_mcs96.c | 3 +- librz/arch/p/asm/asm_mcs96.c | 349 +++----- test/db/analysis/mcs96 | 92 ++ test/db/cmd/cmd_aL | 2 +- test/db/cmd/cmd_list | 8 +- 7 files changed, 1714 insertions(+), 243 deletions(-) create mode 100644 librz/arch/p/analysis/analysis_mcs96.c create mode 100644 test/db/analysis/mcs96 diff --git a/librz/arch/isa/mcs96/mcs96.h b/librz/arch/isa/mcs96/mcs96.h index 6fd3166c06..5d7180ad98 100644 --- a/librz/arch/isa/mcs96/mcs96.h +++ b/librz/arch/isa/mcs96/mcs96.h @@ -12,6 +12,9 @@ * https://archive.org/details/manualzilla-id-5702485/page/n469/mode/2up */ +#ifndef MCS96_H +#define MCS96_H + #include #include @@ -327,5 +330,407 @@ static Mcs96Op mcs96_op[] = { { "rst", MCS96_1B, MCS96_SUPPORT_SINCE_8096 } }; +typedef enum { + MCS96_SKIP_00, + MCS96_CLR_01, + MCS96_NOT_02, + MCS96_NEG_03, + MCS96_XCH_04, + MCS96_DEC_05, + MCS96_EXT_06, + MCS96_INC_07, + MCS96_SHR_08, + MCS96_SHL_09, + MCS96_SHRA_0A, + MCS96_XCH_0B, + MCS96_SHRL_0C, + MCS96_SHLL_0D, + MCS96_SHRAL_0E, + MCS96_NORML_0F, + MCS96_INVALID_10, + MCS96_CLRB_11, + MCS96_NOTB_12, + MCS96_NEGB_13, + MCS96_XCHB_14, + MCS96_DECB_15, + MCS96_EXTB_16, + MCS96_INCB_17, + MCS96_SHRB_18, + MCS96_SHLB_19, + MCS96_SHRAB_1A, + MCS96_XCHB_1B, + MCS96_EST_1C, + MCS96_EST_1D, + MCS96_ESTB_1E, + MCS96_ESTB_1F, + MCS96_SJMP_20, + MCS96_SJMP_21, + MCS96_SJMP_22, + MCS96_SJMP_23, + MCS96_SJMP_24, + MCS96_SJMP_25, + MCS96_SJMP_26, + MCS96_SJMP_27, + MCS96_SCALL_28, + MCS96_SCALL_29, + MCS96_SCALL_2A, + MCS96_SCALL_2B, + MCS96_SCALL_2C, + MCS96_SCALL_2D, + MCS96_SCALL_2E, + MCS96_SCALL_2F, + MCS96_JBC_30, + MCS96_JBC_31, + MCS96_JBC_32, + MCS96_JBC_33, + MCS96_JBC_34, + MCS96_JBC_35, + MCS96_JBC_36, + MCS96_JBC_37, + MCS96_JBS_38, + MCS96_JBS_39, + MCS96_JBS_3A, + MCS96_JBS_3B, + MCS96_JBS_3C, + MCS96_JBS_3D, + MCS96_JBS_3E, + MCS96_JBS_3F, + MCS96_AND_40, + MCS96_AND_41, + MCS96_AND_42, + MCS96_AND_43, + MCS96_ADD_44, + MCS96_ADD_45, + MCS96_ADD_46, + MCS96_ADD_47, + MCS96_SUB_48, + MCS96_SUB_49, + MCS96_SUB_4A, + MCS96_SUB_4B, + MCS96_MULU_4C, + MCS96_MULU_4D, + MCS96_MULU_4E, + MCS96_MULU_4F, + MCS96_ANDB_50, + MCS96_ANDB_51, + MCS96_ANDB_52, + MCS96_ANDB_53, + MCS96_ADDB_54, + MCS96_ADDB_55, + MCS96_ADDB_56, + MCS96_ADDB_57, + MCS96_SUBB_58, + MCS96_SUBB_59, + MCS96_SUBB_5A, + MCS96_SUBB_5B, + MCS96_MULUB_5C, + MCS96_MULUB_5D, + MCS96_MULUB_5E, + MCS96_MULUB_5F, + MCS96_AND_60, + MCS96_AND_61, + MCS96_AND_62, + MCS96_AND_63, + MCS96_ADD_64, + MCS96_ADD_65, + MCS96_ADD_66, + MCS96_ADD_67, + MCS96_SUB_68, + MCS96_SUB_69, + MCS96_SUB_6A, + MCS96_SUB_6B, + MCS96_MULU_6C, + MCS96_MULU_6D, + MCS96_MULU_6E, + MCS96_MULU_6F, + MCS96_ANDB_70, + MCS96_ANDB_71, + MCS96_ANDB_72, + MCS96_ANDB_73, + MCS96_ADDB_74, + MCS96_ADDB_75, + MCS96_ADDB_76, + MCS96_ADDB_77, + MCS96_SUBB_78, + MCS96_SUBB_79, + MCS96_SUBB_7A, + MCS96_SUBB_7B, + MCS96_MULUB_7C, + MCS96_MULUB_7D, + MCS96_MULUB_7E, + MCS96_MULUB_7F, + MCS96_OR_80, + MCS96_OR_81, + MCS96_OR_82, + MCS96_OR_83, + MCS96_XOR_84, + MCS96_XOR_85, + MCS96_XOR_86, + MCS96_XOR_87, + MCS96_CMP_88, + MCS96_CMP_89, + MCS96_CMP_8A, + MCS96_CMP_8B, + MCS96_DIVU_8C, + MCS96_DIVU_8D, + MCS96_DIVU_8E, + MCS96_DIVU_8F, + MCS96_ORB_90, + MCS96_ORB_91, + MCS96_ORB_92, + MCS96_ORB_93, + MCS96_XORB_94, + MCS96_XORB_95, + MCS96_XORB_96, + MCS96_XORB_97, + MCS96_CMPB_98, + MCS96_CMPB_99, + MCS96_CMPB_9A, + MCS96_CMPB_9B, + MCS96_DIVUB_9C, + MCS96_DIVUB_9D, + MCS96_DIVUB_9E, + MCS96_DIVUB_9F, + MCS96_LD_A0, + MCS96_LD_A1, + MCS96_LD_A2, + MCS96_LD_A3, + MCS96_ADDC_A4, + MCS96_ADDC_A5, + MCS96_ADDC_A6, + MCS96_ADDC_A7, + MCS96_SUBC_A8, + MCS96_SUBC_A9, + MCS96_SUBC_AA, + MCS96_SUBC_AB, + MCS96_LDBZE_AC, + MCS96_LDBZE_AD, + MCS96_LDBZE_AE, + MCS96_LDBZE_AF, + MCS96_LDB_B0, + MCS96_LDB_B1, + MCS96_LDB_B2, + MCS96_LDB_B3, + MCS96_ADDCB_B4, + MCS96_ADDCB_B5, + MCS96_ADDCB_B6, + MCS96_ADDCB_B7, + MCS96_SUBCB_B8, + MCS96_SUBCB_B9, + MCS96_SUBCB_BA, + MCS96_SUBCB_BB, + MCS96_LDBSE_BC, + MCS96_LDBSE_BD, + MCS96_LDBSE_BE, + MCS96_LDBSE_BF, + MCS96_ST_C0, + MCS96_BMOV_C1, + MCS96_ST_C2, + MCS96_ST_C3, + MCS96_STB_C4, + MCS96_CMPL_C5, + MCS96_STB_C6, + MCS96_STB_C7, + MCS96_PUSH_C8, + MCS96_PUSH_C9, + MCS96_PUSH_CA, + MCS96_PUSH_CB, + MCS96_POP_CC, + MCS96_BMOVI_CD, + MCS96_POP_CE, + MCS96_POP_CF, + MCS96_JNST_D0, + MCS96_JNH_D1, + MCS96_JGT_D2, + MCS96_JNC_D3, + MCS96_JNVT_D4, + MCS96_JNV_D5, + MCS96_JGE_D6, + MCS96_JNE_D7, + MCS96_JST_D8, + MCS96_JH_D9, + MCS96_JLE_DA, + MCS96_JC_DB, + MCS96_JVT_DC, + MCS96_JV_DD, + MCS96_JLT_DE, + MCS96_JE_DF, + MCS96_DJNZ_E0, + MCS96_DJNZW_E1, + MCS96_TIJMP_E2, + MCS96_BR_E3, + MCS96_EBMOVI_E4, + MCS96_RETI_E5, + MCS96_EJMP_E6, + MCS96_LJMP_E7, + MCS96_ELD_E8, + MCS96_ELD_E9, + MCS96_ELDB_EA, + MCS96_ELDB_EB, + MCS96_DPTS_EC, + MCS96_EPTS_ED, + MCS96_INVALID_EE, + MCS96_LCALL_EF, + MCS96_RET_F0, + MCS96_ECALL_F1, + MCS96_PUSHF_F2, + MCS96_POPF_F3, + MCS96_PUSHA_F4, + MCS96_POPA_F5, + MCS96_IDLPD_F6, + MCS96_TRAP_F7, + MCS96_CLRC_F8, + MCS96_SETC_F9, + MCS96_DI_FA, + MCS96_EI_FB, + MCS96_CLRVT_FC, + MCS96_NOP_FD, + MCS96_MUL_DIV_FE, + MCS96_RST_FF, +} Mcs96Instructions; + static const char *mcs96_fe_op[] = { "mul", "mulb", "mul", "mulb", "div", "divb", "invalid", "invalid" }; // in theory these invalids can never happen + +typedef enum { + MCS96_ADDRESSING_REG_DIRECT = 0, + MCS96_ADDRESSING_IMMEDIATE = 1, + MCS96_ADDRESSING_INDIRECT = 2, + MCS96_ADDRESSING_INDEXED = 3, +} Mcs96AddressingMode; + +static inline ut32 compute_fe_index(ut8 byte) { + return ((byte & 0x70) >> 4) ^ 0x4; +} + +/** + * \brief computes the length of an instruction. + * \return int the length of the instruction. returns -1 when invalid. + */ +static int mcs96_len(ut32 isa_bit, const ut8 *buf, int len) { + if (len < 1) { + return 0; + } + + if (!(mcs96_op[buf[0]].isa & isa_bit)) { // unsupported instruction + return -1; + } + + int ret = 1; + if (buf[0] == 0xfe) { + if (isa_bit == MCS96_80296) { + return -1; + } + + if (len < 2) { + return 0; + } + if (mcs96_op[buf[1]].type & MCS96_FE) { + if (mcs96_op[buf[1]].type & MCS96_5B_OR_6B) { + if (len < 3) { + return 0; + } + ret = 6 + (buf[2] & 0x1); + } + if (mcs96_op[buf[1]].type & MCS96_4B_OR_5B) { + if (len < 3) { + return 0; + } + ret = 5 + (buf[2] & 0x1); + } + if (mcs96_op[buf[1]].type & MCS96_3B_OR_4B) { + if (len < 3) { + return 0; + } + ret = 4 + (buf[1] & 0x1); + } + if (mcs96_op[buf[1]].type & MCS96_5B) { + ret = 6; + } + if (mcs96_op[buf[1]].type & MCS96_4B) { + ret = 5; + } + if (mcs96_op[buf[1]].type & MCS96_3B) { + ret = 4; + } + if (mcs96_op[buf[1]].type & MCS96_2B) { + ret = 3; + } + if (ret > len) { + ret = 0; + } + return ret; + } + } + if (mcs96_op[buf[0]].type & MCS96_5B_OR_6B) { + if (len < 2) { + return 0; + } + ret = 5 + (buf[1] & 0x1); + } + if (mcs96_op[buf[0]].type & MCS96_4B_OR_5B) { + if (len < 2) { + return 0; + } + ret = 4 + (buf[1] & 0x1); + } + if (mcs96_op[buf[0]].type & MCS96_3B_OR_4B) { + if (len < 2) { + return 0; + } + ret = 3 + (buf[1] & 0x1); + } + if (mcs96_op[buf[0]].type & MCS96_6B) { + ret = 6; + } + if (mcs96_op[buf[0]].type & MCS96_5B) { + ret = 5; + } + if (mcs96_op[buf[0]].type & MCS96_4B) { + ret = 4; + } + if (mcs96_op[buf[0]].type & MCS96_3B) { + ret = 3; + } + if (mcs96_op[buf[0]].type & MCS96_2B) { + ret = 2; + } + if (ret > len) { + ret = 0; + } + return ret; +} + +/** + * Extract addressing mode from MCS-96 instruction opcode. + * The lower 2 bits (aa) encode the addressing mode for many instructions. + * Format: (xxxxxxaa) + * + * \param opcode The instruction opcode byte + * \return Addressing mode (0-3) + */ +static inline Mcs96AddressingMode extract_addressing_mode(ut8 opcode) { + return (Mcs96AddressingMode)(opcode & 0x03); +} + +/** + * Extract 11-bit signed displacement from sjmp/scall instruction. + * Format: (instr|xxx)(disp-low) + * + * \param opcode First byte of the instruction, containing upper 3 bits of the displacement + * \param disp_low Second byte of the instruction, containing lower 8 bits of the displacement + * \return Sign-extended 16-bit displacement (-1024 to +1023) + */ +static inline st16 extract_disp11(ut8 opcode, ut8 disp_low) { + st16 upper3bits = (st16)(opcode & 0x07); // 0b00000111 + st16 disp = (upper3bits << 8) | disp_low; + + // Sign-extend from 11 bits to 16 bits + if (disp & 0x400) { // Check if bit 10 (sign bit) is set + disp |= 0xF800; // Set bits 15-11 to extend the sign + } + + return disp; +} + +#endif /* MCS96_H */ diff --git a/librz/arch/p/analysis/analysis_mcs96.c b/librz/arch/p/analysis/analysis_mcs96.c new file mode 100644 index 0000000000..1041fe8309 --- /dev/null +++ b/librz/arch/p/analysis/analysis_mcs96.c @@ -0,0 +1,1098 @@ +// SPDX-FileCopyrightText: 2025 bubblepipe +// SPDX-License-Identifier: LGPL-3.0-only + +#include +#include +#include +#include +#include +#include +#include "mcs96/mcs96.h" + +static int archinfo(RzAnalysis *a, RzAnalysisInfoType query) { + switch (query) { + case RZ_ANALYSIS_ARCHINFO_MIN_OP_SIZE: + return 1; + case RZ_ANALYSIS_ARCHINFO_MAX_OP_SIZE: + return 6; + case RZ_ANALYSIS_ARCHINFO_TEXT_ALIGN: + return 1; + case RZ_ANALYSIS_ARCHINFO_DATA_ALIGN: + return 2; // WORDs must be aligned at even byte boundaries in the address space. + case RZ_ANALYSIS_ARCHINFO_CAN_USE_POINTERS: + return true; + default: + return -1; + } +} + +static char *get_reg_profile(RzAnalysis *analysis) { + const char *p = + "=PC pc\n" + "=SP sp\n" + "=SR psw\n" + "=A0 garbage\n" + "=A1 garbage\n" + "=A2 garbage\n" + "gpr pc .16 0 0\n" // Program counter + "gpr sp .16 2 0\n" // Stack pointer + "gpr psw .16 4 0\n" // Processor status word + "gpr garbage .16 6 0\n" + "gpr garbage .16 8 0\n" + "gpr garbage .16 10 0\n"; + return rz_str_dup(p); +} + +/** + * Extract shift count from the second byte of shift instructions, and update + * the analysis op accordingly. + * The count may be specified either as an immediate value in the range of 0 to + * 15 (0FH), inclusive, or as the content of any register (10H – 0FFH) with a + * value in the range of 0 to 31 (1FH), inclusive. + */ +static inline void analyze_shift_count(RzAnalysisOp *op, ut8 byte) { + if (byte <= 0x0F) { // immediate value + op->val = byte; + } else { // register value + op->ptr = byte; + } +} + +static void opex_add_reg(PJ *pj, ut8 reg) { + pj_o(pj); + pj_ks(pj, "type", "reg"); + pj_kn(pj, "value", reg); + pj_end(pj); +} + +static void opex_add_imm(PJ *pj, st64 imm) { + pj_o(pj); + pj_ks(pj, "type", "imm"); + pj_kn(pj, "value", imm); + pj_end(pj); +} + +static void opex_add_mem(PJ *pj, ut8 base, st64 offset, bool autoincrement) { + pj_o(pj); + pj_ks(pj, "type", "mem"); + pj_kn(pj, "base", base); + if (offset != 0) { + pj_kn(pj, "disp", offset); + } + if (autoincrement) { + pj_kb(pj, "autoincrement", true); + } + pj_end(pj); +} + +static void mcs96_opex(RzStrBuf *opex, const ut8 *buf, int size, ut32 isa_bit) { + if (size < 1) { + return; + } + + PJ *pj = pj_new(); + if (!pj) { + return; + } + pj_o(pj); + pj_ka(pj, "operands"); + + ut8 opcode = buf[0]; + ut32 instr_fmt = mcs96_op[opcode].type; + Mcs96AddressingMode addr_mode = extract_addressing_mode(opcode); + + if (instr_fmt & MCS96_FMT_OPC_BYTEOPR && size == 2) { + ut8 operand = buf[1]; + opex_add_reg(pj, operand); + } else if (instr_fmt & MCS96_FMT_2_BYTE_NOP && size == 2) { + // No operands + } else if (instr_fmt & MCS96_FMT_OPC_IMM11 && size == 2) { + st16 imm11 = extract_disp11(opcode, buf[1]); + opex_add_imm(pj, imm11); + } else if (instr_fmt & MCS96_FMT_OPC_BYTEOPR_X2 && size == 3) { + ut8 opr0 = buf[2]; + ut8 opr1 = buf[1]; + opex_add_reg(pj, opr0); + opex_add_reg(pj, opr1); + } else if (instr_fmt & MCS96_FMT_OPC_IMM16 && size == 3) { + st16 imm = (st16)rz_read_le16(buf + 1); + opex_add_imm(pj, imm); + } else if (instr_fmt & MCS96_FMT_TIJMP && size == 4) { + ut8 index = buf[1]; + ut8 mask = buf[2]; + ut8 tbase = buf[3]; + opex_add_reg(pj, tbase); + opex_add_reg(pj, index); + opex_add_imm(pj, mask); + } else if (instr_fmt & MCS96_FMT_OPC_IMM11_BYTEOPR && size == 3) { + st16 imm11 = extract_disp11(opcode, buf[2]); + ut8 reg = buf[1]; + opex_add_reg(pj, reg); + opex_add_imm(pj, imm11); + } else if (instr_fmt & MCS96_FMT_OPC_IMM24 && size == 4) { + ut32 imm = (ut32)rz_read_le24(buf + 1); + opex_add_imm(pj, imm); + } else if (instr_fmt & MCS96_FMT_OPC_INDEX && size >= 1) { + ut8 reg = buf[1] & 0xFE; // erase lsb + if (size == 3) { + ut8 offset = buf[2]; + opex_add_mem(pj, reg, offset, false); + } else if (size == 4) { + ut16 offset = rz_read_le16(buf + 2); + opex_add_mem(pj, reg, offset, false); + } + } else if (instr_fmt & MCS96_FMT_EXTENDED_INDEXED && size == 6) { + ut8 dst = buf[5]; + ut8 base = buf[1]; + st32 offset = (st32)rz_read_le24(buf + 2); + opex_add_reg(pj, dst); + opex_add_mem(pj, base, offset, false); + } else if (instr_fmt & MCS96_FMT_2OP) { + if (addr_mode == MCS96_ADDRESSING_REG_DIRECT && size == 3) { + ut8 dst = buf[2]; + ut8 src_reg = buf[1]; + opex_add_reg(pj, dst); + opex_add_reg(pj, src_reg); + } else if (addr_mode == MCS96_ADDRESSING_IMMEDIATE) { + if (size == 3) { + ut8 dst = buf[2]; + ut8 src_imm8 = buf[1]; + opex_add_reg(pj, dst); + opex_add_imm(pj, src_imm8); + } else if (size == 4) { + ut8 dst = buf[3]; + ut16 src_imm16 = rz_read_le16(buf + 1); + opex_add_reg(pj, dst); + opex_add_imm(pj, src_imm16); + } + } else if (addr_mode == MCS96_ADDRESSING_INDIRECT && size == 3) { + ut8 dst = buf[2]; + bool autoincrement = buf[1] & 0x1; + ut8 src_reg = buf[1] & 0xFE; + opex_add_reg(pj, dst); + opex_add_mem(pj, src_reg, 0, autoincrement); + } else if (addr_mode == MCS96_ADDRESSING_INDEXED) { + if (size == 4) { + ut8 dst = buf[3]; + ut8 offset = buf[2]; + ut8 base = buf[1] & 0xFE; // erase lsb + opex_add_reg(pj, dst); + opex_add_mem(pj, base, offset, false); + } else if (size == 5) { + ut8 dst = buf[4]; + ut16 offset = rz_read_le16(buf + 2); + ut8 base = buf[1] & 0xFE; // erase lsb + opex_add_reg(pj, dst); + opex_add_mem(pj, base, offset, false); + } + } + } else if (instr_fmt & MCS96_FMT_3OP) { + if (addr_mode == MCS96_ADDRESSING_REG_DIRECT && size == 4) { + ut8 dst = buf[3]; + ut8 src0_reg = buf[2]; + ut8 src1_reg = buf[1]; + opex_add_reg(pj, dst); + opex_add_reg(pj, src0_reg); + opex_add_reg(pj, src1_reg); + } else if (addr_mode == MCS96_ADDRESSING_IMMEDIATE) { + if (size == 4) { + ut8 dst = buf[3]; + ut8 src0_reg = buf[2]; + ut8 src_imm8 = buf[1]; + opex_add_reg(pj, dst); + opex_add_reg(pj, src0_reg); + opex_add_imm(pj, src_imm8); + } else if (size == 5) { + ut8 dst = buf[4]; + ut8 src0_reg = buf[3]; + ut16 src_imm16 = rz_read_le16(buf + 1); + opex_add_reg(pj, dst); + opex_add_reg(pj, src0_reg); + opex_add_imm(pj, src_imm16); + } + } else if (addr_mode == MCS96_ADDRESSING_INDIRECT && size == 4) { + ut8 dst = buf[3]; + ut8 src0_reg = buf[2]; + ut8 src1_reg = buf[1] & 0xFE; + bool autoincrement = buf[1] & 0x1; + opex_add_reg(pj, dst); + opex_add_reg(pj, src0_reg); + opex_add_mem(pj, src1_reg, 0, autoincrement); + } else if (addr_mode == MCS96_ADDRESSING_INDEXED) { + if (size == 5) { + ut8 dst = buf[4]; + ut8 src1_reg = buf[3]; + ut8 offset = buf[2]; + ut8 base = buf[1] & 0xFE; // erase lsb + opex_add_reg(pj, dst); + opex_add_reg(pj, src1_reg); + opex_add_mem(pj, base, offset, false); + } else if (size == 6) { + ut8 dst = buf[5]; + ut8 src1_reg = buf[4]; + ut16 offset = rz_read_le16(buf + 2); + ut8 base = buf[1] & 0xFE; // erase lsb + opex_add_reg(pj, dst); + opex_add_reg(pj, src1_reg); + opex_add_mem(pj, base, offset, false); + } + } + } + + pj_end(pj); // operands array + pj_end(pj); // root object + rz_strbuf_init(opex); + rz_strbuf_append(opex, pj_string(pj)); + pj_free(pj); +} + +static int analyze_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr, const ut8 *buf, int len, RzAnalysisOpMask mask) { + // Determine CPU variant from analysis->cpu + ut32 isa_bit = MCS96_8096; // default + if (analysis->cpu && *analysis->cpu) { + if (strstr(analysis->cpu, "80296")) { + isa_bit = MCS96_80296; + } else if (strstr(analysis->cpu, "80196")) { + isa_bit = MCS96_80196; + } + } + + int size = mcs96_len(isa_bit, buf, len); + + // for valid instructions, a positive integer returned from mcs96_len guarantees: + // 1. size > 0 + // 2. size >= len + // there should be no need to check for size > len after this point. + if (size <= 0) { + return -1; + } + + ut8 opcode = buf[0]; + op->size = size; + op->addr = addr; + op->nopcode = 1; + op->id = opcode; + op->family = RZ_ANALYSIS_OP_FAMILY_CPU; + + Mcs96AddressingMode addr_mode = extract_addressing_mode(opcode); + + switch (opcode) { + case MCS96_SKIP_00: + op->type = RZ_ANALYSIS_OP_TYPE_NOP; + break; + case MCS96_CLR_01: + op->type = RZ_ANALYSIS_OP_TYPE_MOV; + break; + case MCS96_NOT_02: + op->type = RZ_ANALYSIS_OP_TYPE_NOT; + break; + case MCS96_NEG_03: + op->type = RZ_ANALYSIS_OP_TYPE_SUB; + break; + case MCS96_XCH_04: + if (isa_bit == MCS96_8096) { + op->type = RZ_ANALYSIS_OP_TYPE_ILL; + } else { + op->type = RZ_ANALYSIS_OP_TYPE_XCHG; + } + break; + case MCS96_DEC_05: + op->type = RZ_ANALYSIS_OP_TYPE_SUB; + break; + case MCS96_EXT_06: + op->type = RZ_ANALYSIS_OP_TYPE_CAST; + break; + case MCS96_INC_07: + op->type = RZ_ANALYSIS_OP_TYPE_ADD; + break; + case MCS96_SHR_08: + op->type = RZ_ANALYSIS_OP_TYPE_SHR; + op->sign = false; + analyze_shift_count(op, buf[1]); + break; + case MCS96_SHL_09: + op->type = RZ_ANALYSIS_OP_TYPE_SHL; + op->sign = false; + analyze_shift_count(op, buf[1]); + break; + case MCS96_SHRA_0A: + op->type = RZ_ANALYSIS_OP_TYPE_SAR; + op->sign = true; + analyze_shift_count(op, buf[1]); + break; + case MCS96_XCH_0B: + op->type = RZ_ANALYSIS_OP_TYPE_ILL; + break; + case MCS96_SHRL_0C: + op->type = RZ_ANALYSIS_OP_TYPE_SHR; + op->sign = false; + analyze_shift_count(op, buf[1]); + break; + case MCS96_SHLL_0D: { + bool is_shll = false; + if (isa_bit == MCS96_80296) { // shll, mvac, reserved, masc + ut8 lreg_bits = buf[2] & 0x3; + if (lreg_bits == 0x0) { + is_shll = true; + } else if (lreg_bits == 0x1 || lreg_bits == 0x3) { + op->type = RZ_ANALYSIS_OP_TYPE_MOV; + } else if (lreg_bits == 0x2) { + op->type = RZ_ANALYSIS_OP_TYPE_ILL; + } + } else { + is_shll = true; + } + if (is_shll) { + op->type = RZ_ANALYSIS_OP_TYPE_SHL; + op->sign = false; + analyze_shift_count(op, buf[1]); + } + break; + } + case MCS96_SHRAL_0E: + op->type = RZ_ANALYSIS_OP_TYPE_SAR; + op->sign = true; + analyze_shift_count(op, buf[1]); + break; + case MCS96_NORML_0F: + op->type = RZ_ANALYSIS_OP_TYPE_UNK; + break; + case MCS96_INVALID_10: + op->type = RZ_ANALYSIS_OP_TYPE_ILL; + break; + case MCS96_CLRB_11: + op->type = RZ_ANALYSIS_OP_TYPE_MOV; + break; + case MCS96_NOTB_12: + op->type = RZ_ANALYSIS_OP_TYPE_NOT; + break; + case MCS96_NEGB_13: + op->type = RZ_ANALYSIS_OP_TYPE_SUB; + break; + case MCS96_XCHB_14: + if (isa_bit == MCS96_8096) { + op->type = RZ_ANALYSIS_OP_TYPE_ILL; + } else { + op->type = RZ_ANALYSIS_OP_TYPE_XCHG; + } + break; + case MCS96_DECB_15: + op->type = RZ_ANALYSIS_OP_TYPE_SUB; + break; + case MCS96_EXTB_16: + op->type = RZ_ANALYSIS_OP_TYPE_CAST; + break; + case MCS96_INCB_17: + op->type = RZ_ANALYSIS_OP_TYPE_ADD; + break; + case MCS96_SHRB_18: + op->type = RZ_ANALYSIS_OP_TYPE_SHR; + op->sign = false; + analyze_shift_count(op, buf[1]); + break; + case MCS96_SHLB_19: + op->type = RZ_ANALYSIS_OP_TYPE_SHL; + op->sign = false; + analyze_shift_count(op, buf[1]); + break; + case MCS96_SHRAB_1A: + op->type = RZ_ANALYSIS_OP_TYPE_SAR; + op->sign = true; + analyze_shift_count(op, buf[1]); + break; + case MCS96_XCHB_1B: + op->type = RZ_ANALYSIS_OP_TYPE_XCHG; + break; + case MCS96_EST_1C: + case MCS96_EST_1D: + case MCS96_ESTB_1E: + case MCS96_ESTB_1F: + if (isa_bit == MCS96_8096) { + op->type = RZ_ANALYSIS_OP_TYPE_ILL; + } else { + op->type = RZ_ANALYSIS_OP_TYPE_STORE; + } + break; + case MCS96_SJMP_20: + case MCS96_SJMP_21: + case MCS96_SJMP_22: + case MCS96_SJMP_23: + case MCS96_SJMP_24: + case MCS96_SJMP_25: + case MCS96_SJMP_26: + case MCS96_SJMP_27: + op->type = RZ_ANALYSIS_OP_TYPE_JMP; + op->id = opcode & 0xF8; // chop off lower 3 bits + st16 imm = extract_disp11(opcode, buf[1]); + op->val = imm; + op->jump = addr + op->size + imm; + op->eob = true; + break; + case MCS96_SCALL_28: + case MCS96_SCALL_29: + case MCS96_SCALL_2A: + case MCS96_SCALL_2B: + case MCS96_SCALL_2C: + case MCS96_SCALL_2D: + case MCS96_SCALL_2E: + case MCS96_SCALL_2F: + op->type = RZ_ANALYSIS_OP_TYPE_CALL; + op->id = opcode & 0xF8; // chop off lower 3 bits + imm = extract_disp11(opcode, buf[1]); + op->val = imm; + op->jump = addr + op->size + imm; + op->eob = true; + op->stackptr = -2; + break; + case MCS96_JBC_30: + case MCS96_JBC_31: + case MCS96_JBC_32: + case MCS96_JBC_33: + case MCS96_JBC_34: + case MCS96_JBC_35: + case MCS96_JBC_36: + case MCS96_JBC_37: + case MCS96_JBS_38: + case MCS96_JBS_39: + case MCS96_JBS_3A: + case MCS96_JBS_3B: + case MCS96_JBS_3C: + case MCS96_JBS_3D: + case MCS96_JBS_3E: + case MCS96_JBS_3F: + op->type = RZ_ANALYSIS_OP_TYPE_CJMP; + imm = (st8)buf[2]; // 8-bit displacement + op->val = imm; + op->jump = addr + op->size + imm; + op->fail = addr + op->size; + op->eob = true; + break; + case MCS96_AND_40: + if (size == 4 && buf[size - 1] == 0x04) { // RPT/RPTxxx/RPTI/RPTIxxx + op->type = RZ_ANALYSIS_OP_TYPE_UNK; + } else { + op->type = RZ_ANALYSIS_OP_TYPE_AND; + } + break; + case MCS96_AND_41: + case MCS96_AND_42: + case MCS96_AND_43: + op->type = RZ_ANALYSIS_OP_TYPE_AND; + break; + case MCS96_ADD_44: + case MCS96_ADD_45: + case MCS96_ADD_46: + case MCS96_ADD_47: + op->type = RZ_ANALYSIS_OP_TYPE_ADD; + break; + case MCS96_SUB_48: + case MCS96_SUB_49: + case MCS96_SUB_4A: + case MCS96_SUB_4B: + op->type = RZ_ANALYSIS_OP_TYPE_SUB; + break; + case MCS96_MULU_4C: + case MCS96_MULU_4D: + case MCS96_MULU_4E: + case MCS96_MULU_4F: + op->type = RZ_ANALYSIS_OP_TYPE_MUL; + break; + case MCS96_ANDB_50: + case MCS96_ANDB_51: + case MCS96_ANDB_52: + case MCS96_ANDB_53: + op->type = RZ_ANALYSIS_OP_TYPE_AND; + break; + case MCS96_ADDB_54: + case MCS96_ADDB_55: + case MCS96_ADDB_56: + case MCS96_ADDB_57: + op->type = RZ_ANALYSIS_OP_TYPE_ADD; + break; + case MCS96_SUBB_58: + case MCS96_SUBB_59: + case MCS96_SUBB_5A: + case MCS96_SUBB_5B: + op->type = RZ_ANALYSIS_OP_TYPE_SUB; + break; + case MCS96_MULUB_5C: + case MCS96_MULUB_5D: + case MCS96_MULUB_5E: + case MCS96_MULUB_5F: + op->type = RZ_ANALYSIS_OP_TYPE_MUL; + break; + case MCS96_AND_60: + case MCS96_AND_61: + case MCS96_AND_62: + case MCS96_AND_63: + op->type = RZ_ANALYSIS_OP_TYPE_AND; + break; + case MCS96_ADD_64: + case MCS96_ADD_65: + case MCS96_ADD_66: + case MCS96_ADD_67: + op->type = RZ_ANALYSIS_OP_TYPE_ADD; + break; + case MCS96_SUB_68: + case MCS96_SUB_69: + case MCS96_SUB_6A: + case MCS96_SUB_6B: + op->type = RZ_ANALYSIS_OP_TYPE_SUB; + break; + case MCS96_MULU_6C: + case MCS96_MULU_6D: + case MCS96_MULU_6E: + case MCS96_MULU_6F: + op->type = RZ_ANALYSIS_OP_TYPE_MUL; + break; + case MCS96_ANDB_70: + case MCS96_ANDB_71: + case MCS96_ANDB_72: + case MCS96_ANDB_73: + op->type = RZ_ANALYSIS_OP_TYPE_AND; + break; + case MCS96_ADDB_74: + case MCS96_ADDB_75: + case MCS96_ADDB_76: + case MCS96_ADDB_77: + op->type = RZ_ANALYSIS_OP_TYPE_ADD; + break; + case MCS96_SUBB_78: + case MCS96_SUBB_79: + case MCS96_SUBB_7A: + case MCS96_SUBB_7B: + op->type = RZ_ANALYSIS_OP_TYPE_SUB; + break; + case MCS96_MULUB_7C: + case MCS96_MULUB_7D: + case MCS96_MULUB_7E: + case MCS96_MULUB_7F: + op->type = RZ_ANALYSIS_OP_TYPE_MUL; + break; + case MCS96_OR_80: + case MCS96_OR_81: + case MCS96_OR_82: + case MCS96_OR_83: + op->type = RZ_ANALYSIS_OP_TYPE_OR; + break; + case MCS96_XOR_84: + case MCS96_XOR_85: + case MCS96_XOR_86: + case MCS96_XOR_87: + op->type = RZ_ANALYSIS_OP_TYPE_XOR; + break; + case MCS96_CMP_88: + case MCS96_CMP_89: + case MCS96_CMP_8A: + case MCS96_CMP_8B: + op->type = RZ_ANALYSIS_OP_TYPE_CMP; + break; + case MCS96_DIVU_8C: + case MCS96_DIVU_8D: + case MCS96_DIVU_8E: + case MCS96_DIVU_8F: + op->type = RZ_ANALYSIS_OP_TYPE_DIV; + break; + case MCS96_ORB_90: + case MCS96_ORB_91: + case MCS96_ORB_92: + case MCS96_ORB_93: + op->type = RZ_ANALYSIS_OP_TYPE_OR; + break; + case MCS96_XORB_94: + case MCS96_XORB_95: + case MCS96_XORB_96: + case MCS96_XORB_97: + op->type = RZ_ANALYSIS_OP_TYPE_XOR; + break; + case MCS96_CMPB_98: + case MCS96_CMPB_99: + case MCS96_CMPB_9A: + case MCS96_CMPB_9B: + op->type = RZ_ANALYSIS_OP_TYPE_CMP; + break; + case MCS96_DIVUB_9C: + case MCS96_DIVUB_9D: + case MCS96_DIVUB_9E: + case MCS96_DIVUB_9F: + op->type = RZ_ANALYSIS_OP_TYPE_DIV; + break; + case MCS96_LD_A0: + case MCS96_LD_A1: + case MCS96_LD_A2: + case MCS96_LD_A3: + op->type = RZ_ANALYSIS_OP_TYPE_LOAD; + break; + case MCS96_ADDC_A4: + case MCS96_ADDC_A5: + case MCS96_ADDC_A6: + case MCS96_ADDC_A7: + op->type = RZ_ANALYSIS_OP_TYPE_ADD; + break; + case MCS96_SUBC_A8: + case MCS96_SUBC_A9: + case MCS96_SUBC_AA: + case MCS96_SUBC_AB: + op->type = RZ_ANALYSIS_OP_TYPE_SUB; + break; + case MCS96_LDBZE_AC: + case MCS96_LDBZE_AD: + case MCS96_LDBZE_AE: + case MCS96_LDBZE_AF: + op->type = RZ_ANALYSIS_OP_TYPE_LOAD; + break; + case MCS96_LDB_B0: + case MCS96_LDB_B1: + case MCS96_LDB_B2: + case MCS96_LDB_B3: + op->type = RZ_ANALYSIS_OP_TYPE_LOAD; + break; + case MCS96_ADDCB_B4: + case MCS96_ADDCB_B5: + case MCS96_ADDCB_B6: + case MCS96_ADDCB_B7: + op->type = RZ_ANALYSIS_OP_TYPE_ADD; + break; + case MCS96_SUBCB_B8: + case MCS96_SUBCB_B9: + case MCS96_SUBCB_BA: + case MCS96_SUBCB_BB: + op->type = RZ_ANALYSIS_OP_TYPE_SUB; + break; + case MCS96_LDBSE_BC: + case MCS96_LDBSE_BD: + case MCS96_LDBSE_BE: + case MCS96_LDBSE_BF: + op->type = RZ_ANALYSIS_OP_TYPE_LOAD; + break; + case MCS96_ST_C0: + op->type = RZ_ANALYSIS_OP_TYPE_STORE; + op->ptr = buf[1]; + break; + case MCS96_BMOV_C1: + if (isa_bit == MCS96_8096) { + op->type = RZ_ANALYSIS_OP_TYPE_ILL; + } else { + op->type = RZ_ANALYSIS_OP_TYPE_MOV; + } + break; + case MCS96_ST_C2: + op->type = RZ_ANALYSIS_OP_TYPE_STORE; + break; + case MCS96_ST_C3: + op->type = RZ_ANALYSIS_OP_TYPE_STORE; + break; + case MCS96_STB_C4: + op->type = RZ_ANALYSIS_OP_TYPE_STORE; + break; + case MCS96_CMPL_C5: + if (isa_bit == MCS96_8096) { + op->type = RZ_ANALYSIS_OP_TYPE_ILL; + } else { + op->type = RZ_ANALYSIS_OP_TYPE_CMP; + } + break; + case MCS96_STB_C6: + case MCS96_STB_C7: + op->type = RZ_ANALYSIS_OP_TYPE_STORE; + break; + case MCS96_PUSH_C8: + case MCS96_PUSH_C9: + case MCS96_PUSH_CA: + case MCS96_PUSH_CB: + op->type = RZ_ANALYSIS_OP_TYPE_PUSH; + op->stackptr = -2; + break; + case MCS96_POP_CC: + op->type = RZ_ANALYSIS_OP_TYPE_POP; + op->stackptr = 2; + break; + case MCS96_BMOVI_CD: + if (isa_bit == MCS96_8096) { + op->type = RZ_ANALYSIS_OP_TYPE_ILL; + } else { + op->type = RZ_ANALYSIS_OP_TYPE_MOV; + } + break; + case MCS96_POP_CE: + case MCS96_POP_CF: + op->type = RZ_ANALYSIS_OP_TYPE_POP; + op->stackptr = 2; + break; + case MCS96_JNST_D0: + case MCS96_JNH_D1: + case MCS96_JGT_D2: + case MCS96_JNC_D3: + case MCS96_JNVT_D4: + case MCS96_JNV_D5: + case MCS96_JGE_D6: + case MCS96_JNE_D7: + case MCS96_JST_D8: + case MCS96_JH_D9: + case MCS96_JLE_DA: + case MCS96_JC_DB: + case MCS96_JVT_DC: + case MCS96_JV_DD: + case MCS96_JLT_DE: + case MCS96_JE_DF: + imm = (st8)buf[1]; + op->jump = addr + op->size + imm; + op->fail = addr + op->size; + op->type = RZ_ANALYSIS_OP_TYPE_CJMP; + op->eob = true; + break; + case MCS96_DJNZ_E0: + imm = (st8)buf[2]; + op->jump = addr + op->size + imm; + op->fail = addr + op->size; + op->type = RZ_ANALYSIS_OP_TYPE_CJMP; + op->eob = true; + break; + case MCS96_DJNZW_E1: + if (isa_bit == MCS96_8096) { + op->type = RZ_ANALYSIS_OP_TYPE_ILL; + break; + } else { + imm = (st8)buf[2]; + op->jump = addr + op->size + imm; + op->fail = addr + op->size; + op->type = RZ_ANALYSIS_OP_TYPE_CJMP; + op->eob = true; + } + break; + case MCS96_TIJMP_E2: + if (isa_bit == MCS96_8096) { + op->type = RZ_ANALYSIS_OP_TYPE_ILL; + break; + } else { + op->type = RZ_ANALYSIS_OP_TYPE_JMP; + op->eob = true; + } + break; + case MCS96_BR_E3: + op->type = RZ_ANALYSIS_OP_TYPE_JMP; + op->eob = true; + break; + case MCS96_EBMOVI_E4: + if (isa_bit == MCS96_8096) { + op->type = RZ_ANALYSIS_OP_TYPE_ILL; + } else { + op->type = RZ_ANALYSIS_OP_TYPE_MOV; + } + break; + case MCS96_RETI_E5: + if (isa_bit == MCS96_8096 || isa_bit == MCS96_80196) { + op->type = RZ_ANALYSIS_OP_TYPE_ILL; + break; + } else { + op->type = RZ_ANALYSIS_OP_TYPE_RET; + op->eob = true; + op->stackptr = 2; + } + break; + case MCS96_EJMP_E6: + if (isa_bit == MCS96_8096) { + op->type = RZ_ANALYSIS_OP_TYPE_ILL; + break; + } else { + op->type = RZ_ANALYSIS_OP_TYPE_JMP; + op->eob = true; + } + break; + case MCS96_LJMP_E7: + op->type = RZ_ANALYSIS_OP_TYPE_JMP; + imm = (st16)rz_read_le16(buf + 1); + op->val = imm; + op->jump = addr + op->size + imm; + op->eob = true; + break; + case MCS96_ELD_E8: + case MCS96_ELD_E9: + case MCS96_ELDB_EA: + case MCS96_ELDB_EB: + if (isa_bit == MCS96_8096) { + op->type = RZ_ANALYSIS_OP_TYPE_ILL; + } else { + op->type = RZ_ANALYSIS_OP_TYPE_LOAD; + } + break; + case MCS96_DPTS_EC: + case MCS96_EPTS_ED: + if (isa_bit == MCS96_8096) { + op->type = RZ_ANALYSIS_OP_TYPE_UNK; + } else { + op->type = RZ_ANALYSIS_OP_TYPE_UNK; + } + break; + case MCS96_INVALID_EE: + op->type = RZ_ANALYSIS_OP_TYPE_ILL; + break; + case MCS96_LCALL_EF: + op->type = RZ_ANALYSIS_OP_TYPE_CALL; + imm = (st16)rz_read_le16(buf + 1); + op->val = imm; + op->jump = addr + op->size + imm; + op->stackptr = -2; + op->eob = true; + break; + case MCS96_RET_F0: + op->type = RZ_ANALYSIS_OP_TYPE_RET; + op->eob = true; + op->stackptr = 2; + break; + case MCS96_ECALL_F1: + if (isa_bit == MCS96_8096) { + op->type = RZ_ANALYSIS_OP_TYPE_ILL; + } else { + op->type = RZ_ANALYSIS_OP_TYPE_CALL; + op->eob = true; + op->stackptr = -2; + } + break; + case MCS96_PUSHF_F2: + op->type = RZ_ANALYSIS_OP_TYPE_PUSH; + op->stackptr = -2; + break; + case MCS96_POPF_F3: + op->type = RZ_ANALYSIS_OP_TYPE_POP; + op->stackptr = 2; + break; + case MCS96_PUSHA_F4: + if (isa_bit == MCS96_8096) { + op->type = RZ_ANALYSIS_OP_TYPE_ILL; + } else { + op->type = RZ_ANALYSIS_OP_TYPE_PUSH; + op->stackptr = -4; + } + break; + case MCS96_POPA_F5: + if (isa_bit == MCS96_8096) { + op->type = RZ_ANALYSIS_OP_TYPE_ILL; + } else { + op->type = RZ_ANALYSIS_OP_TYPE_POP; + op->stackptr = 4; + } + break; + case MCS96_IDLPD_F6: + if (isa_bit == MCS96_8096) { + op->type = RZ_ANALYSIS_OP_TYPE_ILL; + } else { + op->type = RZ_ANALYSIS_OP_TYPE_UNK; + } + break; + case MCS96_TRAP_F7: + op->type = RZ_ANALYSIS_OP_TYPE_TRAP; + break; + case MCS96_CLRC_F8: + case MCS96_SETC_F9: + case MCS96_DI_FA: + case MCS96_EI_FB: + case MCS96_CLRVT_FC: + op->type = RZ_ANALYSIS_OP_TYPE_UNK; + break; + case MCS96_NOP_FD: + op->type = RZ_ANALYSIS_OP_TYPE_NOP; + break; + case MCS96_MUL_DIV_FE: { + const ut32 fe_idx = compute_fe_index(buf[1]); + switch (fe_idx) { + case 0: + case 1: + case 2: + case 3: + op->type = RZ_ANALYSIS_OP_TYPE_MUL; + break; + case 4: + case 5: + op->type = RZ_ANALYSIS_OP_TYPE_DIV; + default: + break; + } + break; + } + case MCS96_RST_FF: + op->type = RZ_ANALYSIS_OP_TYPE_UNK; + break; + default: + return -1; + } + + switch (opcode) { + case MCS96_AND_40: + case MCS96_AND_41: + case MCS96_AND_42: + case MCS96_AND_43: + case MCS96_ADD_44: + case MCS96_ADD_45: + case MCS96_ADD_46: + case MCS96_ADD_47: + case MCS96_SUB_48: + case MCS96_SUB_49: + case MCS96_SUB_4A: + case MCS96_SUB_4B: + case MCS96_MULU_4C: + case MCS96_MULU_4D: + case MCS96_MULU_4E: + case MCS96_MULU_4F: + case MCS96_AND_60: + case MCS96_AND_61: + case MCS96_AND_62: + case MCS96_AND_63: + case MCS96_ADD_64: + case MCS96_ADD_65: + case MCS96_ADD_66: + case MCS96_ADD_67: + case MCS96_SUB_68: + case MCS96_SUB_69: + case MCS96_SUB_6A: + case MCS96_SUB_6B: + case MCS96_MULU_6C: + case MCS96_MULU_6D: + case MCS96_MULU_6E: + case MCS96_MULU_6F: + case MCS96_OR_80: + case MCS96_OR_81: + case MCS96_OR_82: + case MCS96_OR_83: + case MCS96_XOR_84: + case MCS96_XOR_85: + case MCS96_XOR_86: + case MCS96_XOR_87: + case MCS96_CMP_88: + case MCS96_CMP_89: + case MCS96_CMP_8A: + case MCS96_CMP_8B: + case MCS96_DIVU_8C: + case MCS96_DIVU_8D: + case MCS96_DIVU_8E: + case MCS96_DIVU_8F: + case MCS96_LD_A0: + case MCS96_LD_A1: + case MCS96_LD_A2: + case MCS96_LD_A3: + case MCS96_ADDC_A4: + case MCS96_ADDC_A5: + case MCS96_ADDC_A6: + case MCS96_ADDC_A7: + case MCS96_SUBC_A8: + case MCS96_SUBC_A9: + case MCS96_SUBC_AA: + case MCS96_SUBC_AB: + case MCS96_PUSH_C8: + case MCS96_PUSH_C9: + case MCS96_PUSH_CA: + case MCS96_PUSH_CB: + switch (addr_mode) { + case MCS96_ADDRESSING_REG_DIRECT: + op->ptr = rz_read_le16(buf + 1); + op->refptr = 2; + break; + case MCS96_ADDRESSING_IMMEDIATE: + op->val = rz_read_le16(buf + 1); + break; + default: + break; + } + break; + case MCS96_ANDB_50: + case MCS96_ANDB_51: + case MCS96_ANDB_52: + case MCS96_ANDB_53: + case MCS96_ADDB_54: + case MCS96_ADDB_55: + case MCS96_ADDB_56: + case MCS96_ADDB_57: + case MCS96_SUBB_58: + case MCS96_SUBB_59: + case MCS96_SUBB_5A: + case MCS96_SUBB_5B: + case MCS96_MULUB_5C: + case MCS96_MULUB_5D: + case MCS96_MULUB_5E: + case MCS96_MULUB_5F: + case MCS96_ANDB_70: + case MCS96_ANDB_71: + case MCS96_ANDB_72: + case MCS96_ANDB_73: + case MCS96_ADDB_74: + case MCS96_ADDB_75: + case MCS96_ADDB_76: + case MCS96_ADDB_77: + case MCS96_SUBB_78: + case MCS96_SUBB_79: + case MCS96_SUBB_7A: + case MCS96_SUBB_7B: + case MCS96_MULUB_7C: + case MCS96_MULUB_7D: + case MCS96_MULUB_7E: + case MCS96_MULUB_7F: + case MCS96_ORB_90: + case MCS96_ORB_91: + case MCS96_ORB_92: + case MCS96_ORB_93: + case MCS96_XORB_94: + case MCS96_XORB_95: + case MCS96_XORB_96: + case MCS96_XORB_97: + case MCS96_CMPB_98: + case MCS96_CMPB_99: + case MCS96_CMPB_9A: + case MCS96_CMPB_9B: + case MCS96_DIVUB_9C: + case MCS96_DIVUB_9D: + case MCS96_DIVUB_9E: + case MCS96_DIVUB_9F: + case MCS96_LDBZE_AC: + case MCS96_LDBZE_AD: + case MCS96_LDBZE_AE: + case MCS96_LDBZE_AF: + case MCS96_LDB_B0: + case MCS96_LDB_B1: + case MCS96_LDB_B2: + case MCS96_LDB_B3: + case MCS96_ADDCB_B4: + case MCS96_ADDCB_B5: + case MCS96_ADDCB_B6: + case MCS96_ADDCB_B7: + case MCS96_SUBCB_B8: + case MCS96_SUBCB_B9: + case MCS96_SUBCB_BA: + case MCS96_SUBCB_BB: + case MCS96_LDBSE_BC: + case MCS96_LDBSE_BD: + case MCS96_LDBSE_BE: + case MCS96_LDBSE_BF: + switch (addr_mode) { + case MCS96_ADDRESSING_REG_DIRECT: + op->ptr = buf[1]; + op->refptr = 1; + break; + case MCS96_ADDRESSING_IMMEDIATE: + op->val = buf[1]; + break; + default: + break; + } + break; + default: + break; + } + + if (mask & RZ_ANALYSIS_OP_MASK_OPEX) { + mcs96_opex(&op->opex, buf, size, isa_bit); + } + + return op->size; +} + +RzAnalysisPlugin rz_analysis_plugin_mcs96 = { + .name = "mcs96", + .desc = "Intel MCS-96 analyzer", + .license = "LGPL3", + .arch = "mcs96", + .author = "bubblepipe", + .bits = 16, + .archinfo = archinfo, + .get_reg_profile = get_reg_profile, + .op = analyze_op, +}; \ No newline at end of file diff --git a/librz/arch/p/arch_mcs96.c b/librz/arch/p/arch_mcs96.c index 949b87d126..4da0b29143 100644 --- a/librz/arch/p/arch_mcs96.c +++ b/librz/arch/p/arch_mcs96.c @@ -5,5 +5,6 @@ #include #include "asm/asm_mcs96.c" +#include "analysis/analysis_mcs96.c" -RZ_ARCH_ASM_ONLY_PLUGIN_DEFINE_DEPRECATED(mcs96); +RZ_ARCH_PLUGIN_DEFINE_DEPRECATED(mcs96); diff --git a/librz/arch/p/asm/asm_mcs96.c b/librz/arch/p/asm/asm_mcs96.c index fa3e63b86b..9d4ab4dd66 100644 --- a/librz/arch/p/asm/asm_mcs96.c +++ b/librz/arch/p/asm/asm_mcs96.c @@ -10,13 +10,6 @@ #include "rz_analysis.h" #include "rz_util/rz_pj.h" -typedef enum { - MCS96_ADDRESSING_REG_DIRECT = 0, // 2 reg - MCS96_ADDRESSING_IMMEDIATE = 1, // 1 reg + 1 imm - MCS96_ADDRESSING_INDIRECT = 2, // - MCS96_ADDRESSING_INDEXED = 3, -} MCS96_ADDRESSING_MODE; - typedef struct { RzPVector /**/ *token_patterns; } Mcs96Context; @@ -44,235 +37,6 @@ static RZ_OWN RzPVector /**/ *get_token_patterns() { return pvec; } -/** - * @brief computes the length of an instruction. - * @return int the length of the instruction. returns -1 when invalid. - */ -static int mcs96_len(ut32 isa_bit, const ut8 *buf, int len) { - if (len < 1) { - return 0; - } - - if (!(mcs96_op[buf[0]].isa & isa_bit)) { // unsupported instruction - return -1; - } - - int ret = 1; - if (buf[0] == 0xfe) { - if (isa_bit == MCS96_80296) { - return -1; - } - - if (len < 2) { - return 0; - } - if (mcs96_op[buf[1]].type & MCS96_FE) { - if (mcs96_op[buf[1]].type & MCS96_5B_OR_6B) { - if (len < 3) { - return 0; - } - ret = 6 + (buf[2] & 0x1); - } - if (mcs96_op[buf[1]].type & MCS96_4B_OR_5B) { - if (len < 3) { - return 0; - } - ret = 5 + (buf[2] & 0x1); - } - if (mcs96_op[buf[1]].type & MCS96_3B_OR_4B) { - if (len < 3) { - return 0; - } - ret = 4 + (buf[1] & 0x1); - } - if (mcs96_op[buf[1]].type & MCS96_5B) { - ret = 6; - } - if (mcs96_op[buf[1]].type & MCS96_4B) { - ret = 5; - } - if (mcs96_op[buf[1]].type & MCS96_3B) { - ret = 4; - } - if (mcs96_op[buf[1]].type & MCS96_2B) { - ret = 3; - } - if (ret > len) { - ret = 0; - } - return ret; - } - } - if (mcs96_op[buf[0]].type & MCS96_5B_OR_6B) { - if (len < 2) { - return 0; - } - ret = 5 + (buf[1] & 0x1); - } - if (mcs96_op[buf[0]].type & MCS96_4B_OR_5B) { - if (len < 2) { - return 0; - } - ret = 4 + (buf[1] & 0x1); - } - if (mcs96_op[buf[0]].type & MCS96_3B_OR_4B) { - if (len < 2) { - return 0; - } - ret = 3 + (buf[1] & 0x1); - } - if (mcs96_op[buf[0]].type & MCS96_6B) { - ret = 6; - } - if (mcs96_op[buf[0]].type & MCS96_5B) { - ret = 5; - } - if (mcs96_op[buf[0]].type & MCS96_4B) { - ret = 4; - } - if (mcs96_op[buf[0]].type & MCS96_3B) { - ret = 3; - } - if (mcs96_op[buf[0]].type & MCS96_2B) { - ret = 2; - } - if (ret > len) { - ret = 0; - } - return ret; -} - -static const char *decode_mnemonic(const ut8 *buf, int size, ut32 isa_bit) { - if (size <= 0) { - return "invalid"; - } - - if (buf[0] == 0x0d && isa_bit == MCS96_80296 && size == 3) { // SHLL/MVAC/MSAC - ut8 lreg_bits = buf[2] & 0x3; - // lreg.1 lreg.0 Execute - // 0 0 SHLL - // 0 1 MVAC - // 1 0 Reserved - // 1 1 MSAC - switch (lreg_bits) { - case 0x0: - return "shll"; - case 0x1: - return "mvac"; - case 0x3: - return "msac"; - default: - return "invalid"; - } - } else if (buf[0] == 0x40 && isa_bit == MCS96_80296 && buf[size - 1] == 0x04 && size == 4) { // AND/RPT/RPTxxx/RPTI/RPTIxxx - // RPT waop - // (010000aa) (waop) (00) (04) - // RPTxxx - // (010000aa) (waop) (10 - 1F) (04) - // RPTI - // (010000aa) (waop) (20) (04) - // RPTIxxx - // (010000aa) (waop) (30 - 3F) (04) - switch (buf[size - 2]) { - case 0x00: - return "rpt"; - case 0x10: - return "rptnst"; - case 0x11: - return "rptnh"; - case 0x12: - return "rptgt"; - case 0x13: - return "rptnc"; - case 0x14: - return "rptnvt"; - case 0x15: - return "rptnv"; - case 0x16: - return "rptge"; - case 0x17: - return "rptne"; - case 0x18: - return "rptst"; - case 0x19: - return "rpth"; - case 0x1a: - return "rptle"; - case 0x1b: - return "rptc"; - case 0x1c: - return "rptvt"; - case 0x1d: - return "rptv"; - case 0x1e: - return "rptlt"; - case 0x1f: - return "rpte"; - case 0x20: - return "rpti"; - case 0x30: - return "rptinst"; - case 0x31: - return "rptinh"; - case 0x32: - return "rptigt"; - case 0x33: - return "rptinc"; - case 0x34: - return "rptinvt"; - case 0x35: - return "rptinv"; - case 0x36: - return "rptige"; - case 0x37: - return "rptine"; - case 0x38: - return "rptist"; - case 0x39: - return "rptih"; - case 0x3a: - return "rptile"; - case 0x3b: - return "rptic"; - case 0x3c: - return "rptivt"; - case 0x3d: - return "rptiv"; - case 0x3e: - return "rptilt"; - case 0x3f: - return "rptie"; - default: - return "and"; - } - } else if (mcs96_op[buf[1]].type & MCS96_FE && size > 2) { - const ut32 fe_idx = ((buf[1] & 0x70) >> 4) ^ 0x4; - return mcs96_fe_op[fe_idx]; - } else { - return mcs96_op[buf[0]].ins; - } -} - -/** - * Extract 11-bit signed displacement from sjmp/scall instruction. - * Format: (instr|xxx)(disp-low) - * - * \param opcode First byte of the instruction, containing upper 3 bits of the displacement - * \param disp_low Second byte of the instruction, containing lower 8 bits of the displacement - * \return Sign-extended 16-bit displacement (-1024 to +1023) - */ -static st16 extract_disp11(ut8 opcode, ut8 disp_low) { - st16 upper3bits = (st16)(opcode & 0x07); // 0b00000111 - st16 disp = (upper3bits << 8) | disp_low; - - // Sign-extend from 11 bits to 16 bits - if (disp & 0x400) { // Check if bit 10 (sign bit) is set - disp |= 0xF800; // Set bits 15-11 to extend the sign - } - - return disp; -} - static void decode_operands(RzAsmOp *op, const char *mnemonic, const ut8 *buf, int size, ut32 isa_bit) { if (size < 1) { return; @@ -415,6 +179,117 @@ static void decode_operands(RzAsmOp *op, const char *mnemonic, const ut8 *buf, i } } +static const char *decode_mnemonic(const ut8 *buf, int size, ut32 isa_bit) { + if (size <= 0) { + return "invalid"; + } + + if (buf[0] == 0x0d && isa_bit == MCS96_80296 && size == 3) { // SHLL/MVAC/MSAC + ut8 lreg_bits = buf[2] & 0x3; + // lreg.1 lreg.0 Execute + // 0 0 SHLL + // 0 1 MVAC + // 1 0 Reserved + // 1 1 MSAC + switch (lreg_bits) { + case 0x0: + return "shll"; + case 0x1: + return "mvac"; + case 0x3: + return "msac"; + default: + return "invalid"; + } + } else if (buf[0] == 0x40 && isa_bit == MCS96_80296 && size == 4 && buf[size - 1] == 0x04) { // AND/RPT/RPTxxx/RPTI/RPTIxxx + // RPT waop + // (010000aa) (waop) (00) (04) + // RPTxxx + // (010000aa) (waop) (10 - 1F) (04) + // RPTI + // (010000aa) (waop) (20) (04) + // RPTIxxx + // (010000aa) (waop) (30 - 3F) (04) + switch (buf[size - 2]) { + case 0x00: + return "rpt"; + case 0x10: + return "rptnst"; + case 0x11: + return "rptnh"; + case 0x12: + return "rptgt"; + case 0x13: + return "rptnc"; + case 0x14: + return "rptnvt"; + case 0x15: + return "rptnv"; + case 0x16: + return "rptge"; + case 0x17: + return "rptne"; + case 0x18: + return "rptst"; + case 0x19: + return "rpth"; + case 0x1a: + return "rptle"; + case 0x1b: + return "rptc"; + case 0x1c: + return "rptvt"; + case 0x1d: + return "rptv"; + case 0x1e: + return "rptlt"; + case 0x1f: + return "rpte"; + case 0x20: + return "rpti"; + case 0x30: + return "rptinst"; + case 0x31: + return "rptinh"; + case 0x32: + return "rptigt"; + case 0x33: + return "rptinc"; + case 0x34: + return "rptinvt"; + case 0x35: + return "rptinv"; + case 0x36: + return "rptige"; + case 0x37: + return "rptine"; + case 0x38: + return "rptist"; + case 0x39: + return "rptih"; + case 0x3a: + return "rptile"; + case 0x3b: + return "rptic"; + case 0x3c: + return "rptivt"; + case 0x3d: + return "rptiv"; + case 0x3e: + return "rptilt"; + case 0x3f: + return "rptie"; + default: + return "and"; + } + } else if (size > 2 && mcs96_op[buf[1]].type & MCS96_FE) { + const ut32 fe_idx = ((buf[1] & 0x70) >> 4) ^ 0x4; + return mcs96_fe_op[fe_idx]; + } else { + return mcs96_op[buf[0]].ins; + } +} + static bool init(void **u) { if (!u) { return false; @@ -480,7 +355,7 @@ RzAsmPlugin rz_asm_plugin_mcs96 = { .license = "LGPL3", .author = "condret", .bits = 16, - .endian = RZ_SYS_ENDIAN_NONE, + .endian = RZ_SYS_ENDIAN_LITTLE, .init = &init, .fini = &fini, .disassemble = &disassemble diff --git a/test/db/analysis/mcs96 b/test/db/analysis/mcs96 new file mode 100644 index 0000000000..2236a9aa3a --- /dev/null +++ b/test/db/analysis/mcs96 @@ -0,0 +1,92 @@ +NAME=mcs96 byte tests +FILE=malloc://4096 +CMDS=< 0x00002091 ld 0x1c 0x1a ; [0x1c1a:2]=0xffff +| | 0x00002094 dec 0x1c +| | 0x00002096 push 0x1c ; [0x2f1c:2]=0xffff +| | 0x00002098 scall 0xffe6 +| | 0x0000209a add 0x18 0x0002 +| | 0x0000209e push 0x1c ; [0x491c:2]=0xffff +| | 0x000020a0 sub 0x1c 0x1a 0x0002 +| | 0x000020a5 push 0x1c ; [0x2f1c:2]=0xffff +| | 0x000020a7 scall 0xffd7 +| | 0x000020a9 add 0x18 0x0002 +| | 0x000020ad pop 0x1e +| | 0x000020af add 0x1e 0x1c ; [0x1e1c:2]=0xffff +| | 0x000020b2 ld 0x1c 0x1e ; [0x1c1e:2]=0xffff +| |,=< 0x000020b5 sjmp 0x0000 +| || ; CODE XREFS from fcn.00002080 @ 0x208f, 0x20b5 +| ``-> 0x000020b7 pop 0x1a +\ 0x000020b9 ret +EOF +RUN + diff --git a/test/db/cmd/cmd_aL b/test/db/cmd/cmd_aL index 02c7f2363a..17457a96e7 100644 --- a/test/db/cmd/cmd_aL +++ b/test/db/cmd/cmd_aL @@ -35,7 +35,7 @@ _dA__ 8 32 m680x BSD Motorola 680X Capstone-based disassembler _dA__ 32 m68k BSD Motorola 68K Capstone-based disassembler _dA__ 32 malbolge LGPL3 Malbolge Ternary VM bytecode disassembler (by condret) _dA__ 32 mcore LGPL3 Motorola MCORE disassembler -_d___ 16 mcs96 LGPL3 Intel MCS-96 disassembler (by condret) +_dA__ 16 mcs96 LGPL3 Intel MCS-96 disassembler (by condret) adAeI 16 32 64 mips BSD MIPS Capstone-based disassembler _dA_I 16 msp430 LGPL3 Texas Instruments MSP430 disassembler adA__ 16 32 64 null MIT NULL (empty) disassembler (by pancake) v1.0.0 diff --git a/test/db/cmd/cmd_list b/test/db/cmd/cmd_list index 304270c977..cc01763949 100644 --- a/test/db/cmd/cmd_list +++ b/test/db/cmd/cmd_list @@ -684,7 +684,7 @@ _dA__ 8 32 m680x BSD Motorola 680X Capstone-based disassembler _dA__ 32 m68k BSD Motorola 68K Capstone-based disassembler _dA__ 32 malbolge LGPL3 Malbolge Ternary VM bytecode disassembler (by condret) _dA__ 32 mcore LGPL3 Motorola MCORE disassembler -_d___ 16 mcs96 LGPL3 Intel MCS-96 disassembler (by condret) +_dA__ 16 mcs96 LGPL3 Intel MCS-96 disassembler (by condret) adAeI 16 32 64 mips BSD MIPS Capstone-based disassembler _dA_I 16 msp430 LGPL3 Texas Instruments MSP430 disassembler adA__ 16 32 64 null MIT NULL (empty) disassembler (by pancake) v1.0.0 @@ -718,7 +718,7 @@ _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":"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"},"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 ","license":"GPL3","description":"HP PA-RISC","features":"_d___"},"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":"8 ","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":"_d___","author":"condret"},"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":"GPL3","description":"RISC-V disassembler","features":"_dAe_"},"riscv.cs":{"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 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__"},"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":"8 32 ","license":"GPL3","description":"DEC VAX disassembler","features":"_dA__"},"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"}] +["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":"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"},"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 ","license":"GPL3","description":"HP PA-RISC","features":"_d___"},"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":"8 ","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"},"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":"GPL3","description":"RISC-V disassembler","features":"_dAe_"},"riscv.cs":{"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 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__"},"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":"8 32 ","license":"GPL3","description":"DEC VAX disassembler","features":"_dA__"},"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 @@ -754,7 +754,7 @@ _dA__ 8 32 m680x BSD Motorola 680X Capstone- _dA__ 32 m68k BSD Motorola 68K Capstone-based disassembler _dA__ 32 malbolge LGPL3 condret Malbolge Ternary VM bytecode disassembler _dA__ 32 mcore LGPL3 Motorola MCORE disassembler -_d___ 16 mcs96 LGPL3 condret Intel MCS-96 disassembler +_dA__ 16 mcs96 LGPL3 condret Intel MCS-96 disassembler adAeI 16 32 64 mips BSD MIPS Capstone-based disassembler _dA_I 16 msp430 LGPL3 Texas Instruments MSP430 disassembler adA__ 16 32 64 null MIT 1.0.0 pancake NULL (empty) disassembler @@ -1064,7 +1064,7 @@ NAME=Print the asm/analysis plugins in JSON FILE== CMDS=Laj EXPECT=<