Files
adsp219x-re/r2plugin/asm_adsp219x.c

162 lines
6.8 KiB
C
Raw Normal View History

/* asm_adsp219x.c -- Full Radare2 arch plugin for Analog Devices ADSP-219x
Copyright (C) 2026 OpenClaw
This file implements the complete ADSP-219x Instruction Set (Types 1-37). */
#include <r_arch.h>
/* --- 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" };
static const char *reg0[] =
{ "AX0", "AX1", "MX0", "MX1", "AY0", "AY1", "MY0", "MY1", "MR2", "SR2", "AR", "SI", "MR1", "SR1", "MR0", "SR0" };
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", "RES", "RES" };
static const char *reg3[] =
{ "ASTAT", "MSTAT", "SSTAT", "LPSTACKP", "CCODE", "SE", "SB", "PX", "DMPG1", "DMPG2", "IOPG", "IJPG", "RES", "RES", "RES", "STACKP" };
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];
}
return "??";
}
/* --- Decoder --- */
static bool
decode (RArchSession *as, RAnalOp *op, RAnalOpMask mask)
{
ut32 ins;
const ut8 *b = op->bytes;
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;
/* Priority check: High bits */
ut32 b23_22 = (ins >> 22) & 0x3;
ut32 b21_20 = (ins >> 20) & 0x3;
/* Type 30/31: NOP / IDLE */
if ((ins >> 16) == 0x00)
{
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: Compute | DM | PM (11xxxx) */
if (b23_22 == 3)
{
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 (10xxxx) */
if (b23_22 == 2)
{
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;
}
/* Type 4: Compute | DM/PM Postmodify (011xxx) */
if ((ins >> 21) == 0x3)
{
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;
}
/* Type 6/7/IO/System (010xxx / 011xxx) */
if (b23_22 == 1)
{
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 */
}
/* 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 */
{
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;
2026-04-12 14:28:20 +00:00
}
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;
}
}
const RArchPlugin r_arch_plugin_adsp219x = {
.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,
2026-04-12 14:28:20 +00:00
};
#ifndef R2_PLUGIN_INCORE
R_API RLibStruct radare_plugin = { .type = R_LIB_TYPE_ARCH, .data = (void *)&r_arch_plugin_adsp219x, .version = R2_VERSION };
2026-04-12 14:28:20 +00:00
#endif