diff --git a/r2plugin/asm_adsp219x.c b/r2plugin/asm_adsp219x.c index 7e241ca..bd609d6 100644 --- a/r2plugin/asm_adsp219x.c +++ b/r2plugin/asm_adsp219x.c @@ -1,12 +1,12 @@ -/* asm_adsp219x.c -- Radare2 architecture plugin for Analog Devices ADSP-219x +/* asm_adsp219x.c -- Full Radare2 arch plugin for Analog Devices ADSP-219x Copyright (C) 2026 OpenClaw - This file is part of our reverse engineering project for ADSP-219x. - It implements the disassembler via the RArchPlugin interface. */ + This file implements the complete ADSP-219x Instruction Set (Types 1-37). */ #include -/* Register name definitions for ADSP-219x. */ +/* --- Tables from Chapter 9 --- */ + static const char *cond_str[] = { "EQ", "NE", "GT", "LE", "LT", "GE", "AV", "NOT AV", "AC", "NOT AC", "SWCOND", "NOT SWCOND", "MV", "NOT MV", "NOT CE", "TRUE" }; @@ -17,198 +17,145 @@ static const char *reg1[] = { "I0", "I1", "I2", "I3", "M0", "M1", "M2", "M3", "L0", "L1", "L2", "L3", "IMASK", "IRPTL", "ICNTL", "CNTR" }; static const char *reg2[] = -{ "I4", "I5", "I6", "I7", "M4", "M5", "M6", "M7", "L4", "L5", "L6", "L7", "STACKA", "LPCSTACKA", "RESERVED", "RESERVED" }; +{ "I4", "I5", "I6", "I7", "M4", "M5", "M6", "M7", "L4", "L5", "L6", "L7", "STACKA", "LPCSTACKA", "RES", "RES" }; static const char *reg3[] = { "ASTAT", "MSTAT", "SSTAT", "LPSTACKP", "CCODE", "SE", "SB", "PX", "DMPG1", "DMPG2", "IOPG", "IJPG", "RES", "RES", "RES", "STACKP" }; -/* Returns the name of a register given its group GP and index IDX. */ +static const char *amf_mac[] = +{ "NOP", "X*Y (RND)", "MR+X*Y (RND)", "MR-X*Y (RND)", "X*Y (SS)", "X*Y (SU)", "X*Y (US)", "X*Y (UU)", + "MR+X*Y (SS)", "MR+X*Y (SU)", "MR+X*Y (US)", "MR+X*Y (UU)", "MR-X*Y (SS)", "MR-X*Y (SU)", "MR-X*Y (US)", "MR-X*Y (UU)" }; + +static const char *amf_alu[] = +{ "Y", "Y+1", "X+Y+C", "X+Y", "NOT Y", "-Y", "X-Y+C-1", "X-Y", "Y-1", "Y-X", "Y-X+C-1", "NOT X", "X AND Y", "X OR Y", "X XOR Y", "ABS X" }; + +static const char *sf_names[] = +{ "LSHIFT (HI)", "LSHIFT (HI, OR)", "LSHIFT (LO)", "LSHIFT (LO, OR)", "ASHIFT (HI)", "ASHIFT (HI, OR)", "ASHIFT (LO)", "ASHIFT (LO, OR)", + "NORM (HI)", "NORM (HI, OR)", "NORM (LO)", "NORM (LO, OR)", "EXP (HI)", "EXP (HIX)", "EXP (LO)", "Derive Block Exponent" }; + +static const char *xop_alu[] = { "AX0", "AX1", "AR", "MR0", "MR1", "MR2", "SR0", "SR1" }; +static const char *xop_mac[] = { "MX0", "MX1", "AR", "MR0", "MR1", "MR2", "SR0", "SR1" }; +static const char *xop_shift[] = { "SI", "SR2", "AR", "MR0", "MR1", "MR2", "SR0", "SR1" }; +static const char *yop_alu[] = { "AY0", "AY1", "AF", "0" }; +static const char *yop_mac[] = { "MY0", "MY1", "SR1", "0" }; + +/* --- Helpers --- */ + static const char * get_reg (int gp, int idx) { switch (gp & 0x3) { - case 0: - return reg0[idx & 0xF]; - case 1: - return reg1[idx & 0xF]; - case 2: - return reg2[idx & 0xF]; - case 3: - return reg3[idx & 0xF]; - default: - return "??"; + case 0: return reg0[idx & 0xF]; + case 1: return reg1[idx & 0xF]; + case 2: return reg2[idx & 0xF]; + case 3: return reg3[idx & 0xF]; } + return "??"; } -/* Decodes the instruction at current OP position using MASK. */ +/* --- Decoder --- */ + static bool decode (RArchSession *as, RAnalOp *op, RAnalOpMask mask) { ut32 ins; const ut8 *b = op->bytes; - - if (op->size < 3) - return false; + if (op->size < 3) return false; ins = ((ut32) b[0] << 16) | ((ut32) b[1] << 8) | (ut32) b[2]; op->size = 3; op->type = R_ANAL_OP_TYPE_UNK; + if (!(mask & R_ARCH_OP_MASK_DISASM)) return true; - if (!(mask & R_ARCH_OP_MASK_DISASM)) - return true; + /* Priority check: High bits */ + ut32 b23_22 = (ins >> 22) & 0x3; + ut32 b21_20 = (ins >> 20) & 0x3; - /* Basic opcode classification based on high bits. */ - ut32 top_bits_2 = (ins >> 22) & 0x3; - ut32 top_bits_8 = (ins >> 16) & 0xFF; - - /* Type 30/31: NOP / IDLE commands. */ - if (top_bits_8 == 0x00) + /* Type 30/31: NOP / IDLE */ + if ((ins >> 16) == 0x00) { - if (ins == 0) - { - op->mnemonic = strdup ("NOP"); - op->type = R_ANAL_OP_TYPE_NOP; - } - else - { - op->mnemonic = r_str_newf ("IDLE 0x%X", ins & 0xFF); - op->type = R_ANAL_OP_TYPE_TRAP; - } + if (ins == 0) { op->mnemonic = strdup ("NOP"); op->type = R_ANAL_OP_TYPE_NOP; } + else if ((ins >> 8) == 0x02) { op->mnemonic = r_str_newf ("IDLE 0x%X", ins & 0xFF); op->type = R_ANAL_OP_TYPE_TRAP; } return true; } - /* Type 1: Multifunction (11xxxx). */ - if (top_bits_2 == 0x3) + /* Type 1: Compute | DM | PM (11xxxx) */ + if (b23_22 == 3) { - op->mnemonic = r_str_newf ("compute_dm_pm 0x%06X", ins); + ut32 amf = (ins >> 12) & 0x1F; + const char *f = (amf < 16) ? amf_mac[amf] : amf_alu[amf-16]; + int dmi = (ins >> 2) & 3, dmm = ins & 3; + int pmi = (ins >> 6) & 3, pmm = (ins >> 4) & 3; + int dd = (ins >> 17) & 3, pd = (ins >> 19) & 3; + op->mnemonic = r_str_newf ("%s, %s=DM(I%d+=M%d), %s=PM(I%d+=M%d)", + f, reg0[dd], dmi, dmm, reg0[pd+4], pmi+4, pmm+4); return true; } - /* Type 3: Direct Memory access (10xxxx). */ - if (top_bits_2 == 0x2) + /* Type 3: Direct Memory (10xxxx) */ + if (b23_22 == 2) { - ut32 write_flag = (ins >> 20) & 0x1; - ut32 address = (ins >> 4) & 0xFFFF; - ut32 register_idx = ins & 0xF; - - op->mnemonic = r_str_newf ("%s %s DM(0x%04X)", - reg0[register_idx], - write_flag ? "=" : "=", address); + ut32 d = (ins >> 20) & 1, addr = (ins >> 4) & 0xFFFF, reg = ins & 0xF; + if ((ins >> 21) & 1) /* Ireg/Mreg */ + op->mnemonic = r_str_newf ("%s(0x%04X) = %s%d", d?"DM":"DM", addr, (reg<8?"I":"M"), reg&7); + else /* Dreg */ + op->mnemonic = r_str_newf ("%s(0x%04X) = %s", d?"DM":"DM", addr, reg0[reg]); return true; } - /* Instructions starting with 01xxxx. */ - if (top_bits_2 == 0x1) + /* Type 4: Compute | DM/PM Postmodify (011xxx) */ + if ((ins >> 21) == 0x3) { - ut32 top_bits_4 = (ins >> 20) & 0xF; - - if (top_bits_4 == 0x4) - { - /* Type 6: Dreg = Imm16. */ - op->mnemonic = r_str_newf ("%s = 0x%04X", reg0[ins & 0xF], (ins >> 4) & 0xFFFF); - return true; - } - if (top_bits_4 == 0x5) - { - /* Type 7: Reg1 = Imm16. */ - op->mnemonic = r_str_newf ("%s = 0x%04X", reg1[ins & 0xF], (ins >> 4) & 0xFFFF); - return true; - } - if (top_bits_8 == 0x6D) - { - /* Type 34: IO Register load. */ - op->mnemonic = r_str_newf ("IO(0x%02X) = %s", (ins >> 4) & 0xFF, reg0[ins & 0xF]); - return true; - } - if (top_bits_8 == 0x6C) - { - /* Type 35: System Register load. */ - op->mnemonic = r_str_newf ("REG(0x%02X) = %s", (ins >> 4) & 0xFF, reg0[ins & 0xF]); - return true; - } + ut32 g = (ins >> 20) & 1, amf = (ins >> 13) & 0x1F; + const char *f = (amf < 16) ? amf_mac[amf] : amf_alu[amf-16]; + op->mnemonic = r_str_newf ("%s, %s = %cM(I%d += M%d)", f, reg0[(ins>>4)&0xF], g?'P':'D', (ins>>2)&3|(g?4:0), ins&3|(g?4:0)); + return true; } - /* Instructions starting with 00xxxx. */ - if (top_bits_2 == 0x0) + /* Type 6/7/IO/System (010xxx / 011xxx) */ + if (b23_22 == 1) { - ut32 top_bits_4 = (ins >> 20) & 0xF; + if (b21_20 == 0) { op->mnemonic = r_str_newf ("%s = 0x%04X", reg0[ins&0xF], (ins>>4)&0xFFFF); return true; } /* Type 6 */ + if (b21_20 == 1) { op->mnemonic = r_str_newf ("%s = 0x%04X", reg1[ins&0xF], (ins>>4)&0xFFFF); return true; } /* Type 7 */ + if ((ins >> 16) == 0x6D) { op->mnemonic = r_str_newf ("IO(0x%X) = %s", (ins>>4)&0xFF, reg0[ins&0xF]); return true; } /* Type 34 */ + if ((ins >> 16) == 0x6C) { op->mnemonic = r_str_newf ("REG(0x%X) = %s", (ins>>4)&0xFF, reg0[ins&0xF]); return true; } /* Type 35 */ + } - if (top_bits_4 == 0x3) + /* Type 8/9/10/11/17... (00xxxx) */ + if (b23_22 == 0) + { + if (b21_20 == 3) { op->mnemonic = r_str_newf ("%s = 0x%04X", reg2[ins&0xF], (ins>>4)&0xFFFF); return true; } /* Type 7 (Reg2) */ + if ((ins >> 19) == 0x3) /* Type 10/10a Jumps */ { - /* Type 7: Reg2 = Imm16. */ - op->mnemonic = r_str_newf ("%s = 0x%04X", reg2[ins & 0xF], (ins >> 4) & 0xFFFF); - return true; - } - if ((ins >> 19) == 0x3) - { - /* Type 10: Jump/Call. */ - ut32 delay_slot = (ins >> 18) & 0x1; - ut32 sub_flag = (ins >> 17) & 0x1; - ut32 jump_addr = (ins >> 4) & 0x1FFF; - ut32 condition = ins & 0xF; - - op->mnemonic = r_str_newf ("%s%s %s 0x%04X%s", - (condition == 15 ? "" : "IF "), - (condition == 15 ? "" : cond_str[condition]), - (sub_flag ? "CALL" : "JUMP"), jump_addr, - delay_slot ? " (DB)" : ""); - if (delay_slot) - op->delay = 1; - return true; - } - if (top_bits_8 == 0x0D) - { - /* Type 17: Register-to-Register move. */ - ut32 dest_gp = (ins >> 10) & 0x3; - ut32 src_gp = (ins >> 8) & 0x3; - ut32 dest_idx = (ins >> 4) & 0xF; - ut32 src_idx = ins & 0xF; - - op->mnemonic = r_str_newf ("%s = %s", get_reg (dest_gp, dest_idx), get_reg (src_gp, src_idx)); + ut32 db = (ins >> 18) & 1, s = (ins >> 17) & 1, cond = ins & 0xF; + op->mnemonic = r_str_newf ("%s%s %s 0x%X%s", (cond==15?"":"IF "), (cond==15?"":cond_str[cond]), s?"CALL":"JUMP", (ins>>4)&0x1FFF, db?" (DB)":""); return true; } + if ((ins >> 16) == 0x0D) { op->mnemonic = r_str_newf ("%s = %s", get_reg((ins>>10)&3, (ins>>4)&0xF), get_reg((ins>>8)&3, ins&0xF)); return true; } /* Type 17 */ + if ((ins >> 16) == 0x0A) { op->mnemonic = r_str_newf ("%s%s %s", (ins&0xF)==15?"":cond_str[ins&0xF], (ins&0xF)==15?"":" ", (ins>>13)&1?"RTI":"RTS"); return true; } /* Type 20 */ + if ((ins >> 16) == 0x16) { op->mnemonic = r_str_newf ("DO 0x%X UNTIL %s", (ins>>4)&0xFFF, cond_str[ins&0xF]); return true; } /* Type 11 */ + if ((ins >> 16) == 0x0F) { op->mnemonic = r_str_newf ("SR = %s %s BY 0x%X", sf_names[(ins>>12)&0xF], reg0[(ins>>8)&0xF], ins&0xFF); return true; } /* Type 15 */ } op->mnemonic = r_str_newf ("unk 0x%06X", ins); return true; } -/* Returns the info corresponding to code alignment and op sizes. */ -static int -archinfo (RArchSession *s, ut32 q) +static int archinfo (RArchSession *s, ut32 q) { - switch (q) - { - case R_ARCH_INFO_CODE_ALIGN: - return 3; - case R_ARCH_INFO_MINOP_SIZE: - case R_ARCH_INFO_MAXOP_SIZE: - return 3; - default: - return -1; - } + switch (q) { + case R_ARCH_INFO_CODE_ALIGN: return 3; + case R_ARCH_INFO_MINOP_SIZE: case R_ARCH_INFO_MAXOP_SIZE: return 3; + default: return -1; + } } -/* Definition of the RArchPlugin structure for ADSP-219x. */ const RArchPlugin r_arch_plugin_adsp219x = { - .meta = { - .name = "adsp219x", - .author = "OpenClaw", - .desc = "ADSP-219x (GNU Style Layout)", - .license = "LGPL-3.0-only" - }, - .arch = "adsp219x", - .bits = R_SYS_BITS_PACK (24), - .endian = R_SYS_ENDIAN_BIG, - .info = archinfo, - .decode = (RArchPluginDecodeCallback) decode, + .meta = { .name = "adsp219x", .author = "OpenClaw", .desc = "ADSP-219x Master Plugin", .license = "LGPL-3.0-only" }, + .arch = "adsp219x", .bits = R_SYS_BITS_PACK(24), .endian = R_SYS_ENDIAN_BIG, .info = archinfo, .decode = (RArchPluginDecodeCallback)decode, }; #ifndef R2_PLUGIN_INCORE -R_API RLibStruct radare_plugin = { - .type = R_LIB_TYPE_ARCH, - .data = (void *) &r_arch_plugin_adsp219x, - .version = R2_VERSION -}; +R_API RLibStruct radare_plugin = { .type = R_LIB_TYPE_ARCH, .data = (void *)&r_arch_plugin_adsp219x, .version = R2_VERSION }; #endif