/* ADSP-219x radare2 arch plugin - LGPL - OpenClaw / adsp219x-re project */ /* Targets radare2 >= 5.8 (RArchPlugin API) */ #include /* ---- lookup tables ---- */ 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 *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 *cond_str[] = { "EQ", "NE", "GT", "LE", "LT", "GE", "AV", "NOT AV", "AC", "NOT AC", "SWCOND", "NOT SWCOND", "MV", "NOT MV", "NOT CE", "TRUE" }; static const char *reg0[] = { "AX0", "AX1", "MX0", "MX1", "AY0", "AY1", "MY0", "MY1", "MR2", "SR2", "AR", "SI", "MR1", "SR1", "MR0", "SR0" }; static const char *dd_str[] = { "AX0", "AX1", "MX0", "MX1" }; static const char *pd_str[] = { "AY0", "AY1", "MY0", "MY1" }; /* ---- helpers ---- */ static const char *ireg(int g, int idx) { static const char *names[2][4] = { {"I0", "I1", "I2", "I3"}, {"I4", "I5", "I6", "I7"} }; return names[g & 1][idx & 3]; } static const char *mreg(int g, int idx) { static const char *names[2][4] = { {"M0", "M1", "M2", "M3"}, {"M4", "M5", "M6", "M7"} }; return names[g & 1][idx & 3]; } static const char *amf_str(int code) { if (code < 16) { return amf_mac[code]; } return amf_alu[code - 16]; } /* ---- decode ---- */ static bool decode(RArchSession *as, RAnalOp *op, RArchDecodeMask mask) { const int len = op->size; if (len < 3) { return false; } const ut8 *buf = op->bytes; ut32 ins = ((ut32)buf[0] << 16) | ((ut32)buf[1] << 8) | (ut32)buf[2]; op->size = 3; op->type = R_ANAL_OP_TYPE_UNK; if (!(mask & R_ARCH_OP_MASK_DISASM)) { /* lightweight decode: just set size + type */ if (ins == 0) { op->type = R_ANAL_OP_TYPE_NOP; } return true; } /* ---- Type 30: NOP (0x000000) ---- */ if (ins == 0) { op->type = R_ANAL_OP_TYPE_NOP; op->mnemonic = strdup ("NOP"); return true; } ut32 top2 = ins >> 22; /* ---- Type 1: Compute | DM | PM (top2 == 11) ---- */ if (top2 == 3) { ut32 amf = (ins >> 13) & 0x1F; ut32 dmi = (ins >> 10) & 0x3; ut32 dmm = (ins >> 8) & 0x3; ut32 pmi = (ins >> 6) & 0x3; ut32 pmm = (ins >> 4) & 0x3; ut32 dd = (ins >> 2) & 0x3; ut32 pd = (ins >> 0) & 0x3; if (amf == 0 && (ins & 0x3FFFFF) == 0) { op->type = R_ANAL_OP_TYPE_NOP; op->mnemonic = strdup ("NOP /* Type 1 */"); } else { op->type = R_ANAL_OP_TYPE_ADD; op->mnemonic = r_str_newf ("%s, %s = DM(%s += %s), %s = PM(%s += %s)", amf_str (amf), dd_str[dd], ireg (0, dmi), mreg (0, dmm), pd_str[pd], ireg (1, pmi), mreg (1, pmm)); } return true; } /* ---- Type 6: Dreg = Imm16 (bits 23-20 == 0100) ---- */ if ((ins >> 20) == 4) { ut32 dreg = ins & 0xF; ut32 data = (ins >> 4) & 0xFFFF; op->type = R_ANAL_OP_TYPE_MOV; op->val = data; op->mnemonic = r_str_newf ("%s = 0x%04X", reg0[dreg], data); return true; } /* ---- Type 10: Direct Jump/Call (bits 23-19 == 00011) ---- */ if ((ins >> 19) == 3) { ut32 b = (ins >> 18) & 1; /* delayed branch */ ut32 s = (ins >> 17) & 1; /* 0=jump, 1=call */ ut32 addr = (ins >> 4) & 0x1FFF; ut32 cond = ins & 0xF; const char *db = b ? " (DB)" : ""; const char *type = s ? "CALL" : "JUMP"; op->jump = addr; if (s) { op->type = (cond == 0xF) ? R_ANAL_OP_TYPE_CALL : R_ANAL_OP_TYPE_CCALL; } else { op->type = (cond == 0xF) ? R_ANAL_OP_TYPE_JMP : R_ANAL_OP_TYPE_CJMP; } if (cond != 0xF) { op->fail = op->addr + 3; } if (cond == 0xF) { op->mnemonic = r_str_newf ("%s 0x%04X%s", type, addr, db); } else { op->mnemonic = r_str_newf ("IF %s %s 0x%04X%s", cond_str[cond], type, addr, db); } if (b) { op->delay = 1; } return true; } /* ---- Type 20: RTS / RTI (bits 23-19 == 00101) ---- */ if ((ins >> 19) == 5) { ut32 t = (ins >> 18) & 1; /* 0=RTS, 1=RTI */ ut32 cond = ins & 0xF; const char *type = t ? "RTI" : "RTS"; op->type = (cond == 0xF) ? R_ANAL_OP_TYPE_RET : R_ANAL_OP_TYPE_CRET; op->eob = true; if (cond == 0xF) { op->mnemonic = r_str_newf ("%s", type); } else { op->mnemonic = r_str_newf ("IF %s %s", cond_str[cond], type); } return true; } /* ---- Type 11: DO UNTIL (bits 23-20 == 0010) ---- */ if ((ins >> 20) == 2) { ut32 addr = (ins >> 4) & 0x3FFF; ut32 term = ins & 0xF; op->type = R_ANAL_OP_TYPE_JMP; op->jump = addr; op->mnemonic = r_str_newf ("DO 0x%04X UNTIL %s", addr, cond_str[term]); return true; } /* ---- fallback ---- */ op->mnemonic = r_str_newf ("unknown 0x%06X", ins); return true; } static int archinfo(RArchSession *s, ut32 q) { switch (q) { case R_ARCH_INFO_CODE_ALIGN: return 3; case R_ARCH_INFO_DATA_ALIGN: return 1; case R_ARCH_INFO_MINOP_SIZE: return 3; case R_ARCH_INFO_MAXOP_SIZE: return 3; default: return -1; } } const RArchPlugin r_arch_plugin_adsp219x = { .meta = { .name = "adsp219x", .author = "OpenClaw", .desc = "Analog Devices ADSP-219x DSP", .license = "LGPL-3.0-only", }, .arch = "adsp219x", .bits = R_SYS_BITS_PACK (24), .endian = R_SYS_ENDIAN_BIG, .info = archinfo, .decode = decode, }; #ifndef R2_PLUGIN_INCORE R_API RLibStruct radare_plugin = { .type = R_LIB_TYPE_ARCH, .data = &r_arch_plugin_adsp219x, .version = R2_VERSION }; #endif