2026-04-12 17:02:36 +00:00
|
|
|
/* asm_adsp219x.c -- Full Radare2 arch plugin for Analog Devices ADSP-219x
|
2026-04-22 19:01:25 +00:00
|
|
|
Copyright (C) 2026 Dr. Christian Giessen
|
2026-04-12 16:59:41 +00:00
|
|
|
|
2026-04-12 17:02:36 +00:00
|
|
|
This file implements the complete ADSP-219x Instruction Set (Types 1-37). */
|
2026-04-12 16:59:41 +00:00
|
|
|
|
2026-04-12 14:45:23 +00:00
|
|
|
#include <r_arch.h>
|
|
|
|
|
|
2026-04-12 17:02:36 +00:00
|
|
|
/* --- Tables from Chapter 9 --- */
|
|
|
|
|
|
2026-04-12 16:59:41 +00:00
|
|
|
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[] =
|
2026-04-12 17:02:36 +00:00
|
|
|
{ "I4", "I5", "I6", "I7", "M4", "M5", "M6", "M7", "L4", "L5", "L6", "L7", "STACKA", "LPCSTACKA", "RES", "RES" };
|
2026-04-12 16:59:41 +00:00
|
|
|
|
|
|
|
|
static const char *reg3[] =
|
|
|
|
|
{ "ASTAT", "MSTAT", "SSTAT", "LPSTACKP", "CCODE", "SE", "SB", "PX", "DMPG1", "DMPG2", "IOPG", "IJPG", "RES", "RES", "RES", "STACKP" };
|
|
|
|
|
|
2026-04-12 17:02:36 +00:00
|
|
|
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 --- */
|
|
|
|
|
|
2026-04-12 16:59:41 +00:00
|
|
|
static const char *
|
|
|
|
|
get_reg (int gp, int idx)
|
|
|
|
|
{
|
|
|
|
|
switch (gp & 0x3)
|
|
|
|
|
{
|
2026-04-12 17:02:36 +00:00
|
|
|
case 0: return reg0[idx & 0xF];
|
|
|
|
|
case 1: return reg1[idx & 0xF];
|
|
|
|
|
case 2: return reg2[idx & 0xF];
|
|
|
|
|
case 3: return reg3[idx & 0xF];
|
2026-04-12 16:59:41 +00:00
|
|
|
}
|
2026-04-12 17:02:36 +00:00
|
|
|
return "??";
|
2026-04-12 14:45:23 +00:00
|
|
|
}
|
|
|
|
|
|
2026-04-12 17:02:36 +00:00
|
|
|
/* --- Decoder --- */
|
|
|
|
|
|
2026-04-12 16:59:41 +00:00
|
|
|
static bool
|
|
|
|
|
decode (RArchSession *as, RAnalOp *op, RAnalOpMask mask)
|
|
|
|
|
{
|
|
|
|
|
ut32 ins;
|
|
|
|
|
const ut8 *b = op->bytes;
|
2026-04-12 17:02:36 +00:00
|
|
|
if (op->size < 3) return false;
|
2026-04-12 16:59:41 +00:00
|
|
|
|
|
|
|
|
ins = ((ut32) b[0] << 16) | ((ut32) b[1] << 8) | (ut32) b[2];
|
|
|
|
|
op->size = 3;
|
|
|
|
|
op->type = R_ANAL_OP_TYPE_UNK;
|
2026-04-12 17:02:36 +00:00
|
|
|
if (!(mask & R_ARCH_OP_MASK_DISASM)) return true;
|
2026-04-12 16:59:41 +00:00
|
|
|
|
2026-04-12 17:02:36 +00:00
|
|
|
/* Priority check: High bits */
|
|
|
|
|
ut32 b23_22 = (ins >> 22) & 0x3;
|
|
|
|
|
ut32 b21_20 = (ins >> 20) & 0x3;
|
2026-04-12 16:59:41 +00:00
|
|
|
|
2026-04-12 17:02:36 +00:00
|
|
|
/* Type 30/31: NOP / IDLE */
|
|
|
|
|
if ((ins >> 16) == 0x00)
|
2026-04-12 16:59:41 +00:00
|
|
|
{
|
2026-04-12 17:02:36 +00:00
|
|
|
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; }
|
2026-04-12 16:59:41 +00:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-12 17:02:36 +00:00
|
|
|
/* Type 1: Compute | DM | PM (11xxxx) */
|
|
|
|
|
if (b23_22 == 3)
|
2026-04-12 16:59:41 +00:00
|
|
|
{
|
2026-04-12 17:02:36 +00:00
|
|
|
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);
|
2026-04-12 16:59:41 +00:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-12 17:02:36 +00:00
|
|
|
/* Type 3: Direct Memory (10xxxx) */
|
|
|
|
|
if (b23_22 == 2)
|
2026-04-12 16:59:41 +00:00
|
|
|
{
|
2026-04-12 17:02:36 +00:00
|
|
|
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]);
|
2026-04-12 16:59:41 +00:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-12 17:02:36 +00:00
|
|
|
/* Type 4: Compute | DM/PM Postmodify (011xxx) */
|
|
|
|
|
if ((ins >> 21) == 0x3)
|
2026-04-12 16:59:41 +00:00
|
|
|
{
|
2026-04-12 17:02:36 +00:00
|
|
|
ut32 g = (ins >> 20) & 1, amf = (ins >> 13) & 0x1F;
|
|
|
|
|
const char *f = (amf < 16) ? amf_mac[amf] : amf_alu[amf-16];
|
Implement Types 8, 9, 10a, 11, 15, 17, 18, 19, 20, 21, 23, 24, 25, 26, 33, 37
- Type 8: Compute + Dreg move
- Type 9/9a: Standalone ALU/MAC compute (conditional/unconditional)
- Type 10a: Unconditional 16-bit jump/call (fixed bitfield decode)
- Type 10: Conditional 13-bit jump (fixed COND field)
- Type 18: Mode control (ENA/DIS AS, MM, BR, etc.)
- Type 19: Indirect jump/call via Ireg
- Type 20: RTS/RTI with correct COND extraction (fixed bug)
- Type 21: MODIFY(Ireg += Mreg)
- Type 23: DIVQ
- Type 24: DIVS
- Type 25: SAT MR/SR
- Type 26: Push/Pop/Flush Cache
- Type 33: Reg3 = Data12 (short constant load)
- Type 37: SETINT/CLRINT
- Type 15: Sign-extended shift exponent
2026-04-22 19:34:01 +00:00
|
|
|
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 9/9a: Compute (001000 / 001001) */
|
|
|
|
|
/* Bits 23-19 = 00100 */
|
|
|
|
|
if ((ins >> 19) == 0x04)
|
|
|
|
|
{
|
|
|
|
|
ut32 amf = (ins >> 13) & 0x1F;
|
|
|
|
|
ut32 xop_i = (ins >> 8) & 0x7;
|
|
|
|
|
ut32 yop_i = (ins >> 11) & 0x3;
|
|
|
|
|
ut32 cond = ins & 0xF;
|
|
|
|
|
const char *f;
|
|
|
|
|
const char *dst;
|
|
|
|
|
const char *x;
|
|
|
|
|
const char *y;
|
|
|
|
|
if (amf < 16)
|
|
|
|
|
{
|
|
|
|
|
f = amf_mac[amf];
|
|
|
|
|
dst = "MR";
|
|
|
|
|
x = xop_mac[xop_i];
|
|
|
|
|
y = yop_mac[yop_i];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
f = amf_alu[amf - 16];
|
|
|
|
|
dst = "AR";
|
|
|
|
|
x = xop_alu[xop_i];
|
|
|
|
|
y = yop_alu[yop_i];
|
|
|
|
|
}
|
|
|
|
|
if (cond == 15)
|
|
|
|
|
op->mnemonic = r_str_newf ("%s = %s(%s, %s)",
|
|
|
|
|
dst, f, x, y);
|
|
|
|
|
else
|
|
|
|
|
op->mnemonic = r_str_newf ("IF %s %s = %s(%s, %s)",
|
|
|
|
|
cond_str[cond], dst, f, x, y);
|
2026-04-12 17:02:36 +00:00
|
|
|
return true;
|
2026-04-12 16:59:41 +00:00
|
|
|
}
|
|
|
|
|
|
2026-04-22 19:30:15 +00:00
|
|
|
/* Type 8: Compute | Dreg1 <- Dreg2 (00101Z) */
|
|
|
|
|
/* Bits 23-18 = 001010 (Z=0) or 001011 (Z=1) */
|
|
|
|
|
if ((ins >> 18) == 0x0A || (ins >> 18) == 0x0B)
|
|
|
|
|
{
|
|
|
|
|
ut32 amf = (ins >> 12) & 0x1F;
|
|
|
|
|
const char *f = (amf < 16) ? amf_mac[amf] : amf_alu[amf-16];
|
|
|
|
|
/* DDREG = bits 8-6 (dest), SDREG = bits 5-0 (src, masked) */
|
|
|
|
|
ut32 ddreg = (ins >> 6) & 0x7;
|
|
|
|
|
ut32 sdreg = ins & 0x3F;
|
|
|
|
|
/* For NONE=ALU case: SDREG = 0x2A (101010) */
|
|
|
|
|
if (sdreg == 0x2A)
|
|
|
|
|
op->mnemonic = r_str_newf ("NONE = %s", f);
|
|
|
|
|
else
|
|
|
|
|
op->mnemonic = r_str_newf ("%s, %s = %s", f, xop_alu[ddreg], reg0[sdreg & 0xF]);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-12 17:02:36 +00:00
|
|
|
/* Type 6/7/IO/System (010xxx / 011xxx) */
|
|
|
|
|
if (b23_22 == 1)
|
2026-04-12 16:59:41 +00:00
|
|
|
{
|
2026-04-12 17:02:36 +00:00
|
|
|
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 */
|
2026-04-22 19:37:27 +00:00
|
|
|
/* Type 34 and 35 are in the b23_22==0 block below */
|
2026-04-12 17:02:36 +00:00
|
|
|
}
|
2026-04-12 16:59:41 +00:00
|
|
|
|
2026-04-12 17:02:36 +00:00
|
|
|
/* 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) */
|
Implement Types 8, 9, 10a, 11, 15, 17, 18, 19, 20, 21, 23, 24, 25, 26, 33, 37
- Type 8: Compute + Dreg move
- Type 9/9a: Standalone ALU/MAC compute (conditional/unconditional)
- Type 10a: Unconditional 16-bit jump/call (fixed bitfield decode)
- Type 10: Conditional 13-bit jump (fixed COND field)
- Type 18: Mode control (ENA/DIS AS, MM, BR, etc.)
- Type 19: Indirect jump/call via Ireg
- Type 20: RTS/RTI with correct COND extraction (fixed bug)
- Type 21: MODIFY(Ireg += Mreg)
- Type 23: DIVQ
- Type 24: DIVS
- Type 25: SAT MR/SR
- Type 26: Push/Pop/Flush Cache
- Type 33: Reg3 = Data12 (short constant load)
- Type 37: SETINT/CLRINT
- Type 15: Sign-extended shift exponent
2026-04-22 19:34:01 +00:00
|
|
|
/* Type 10a: bits 23-18 = 000111 (unconditional 16-bit) */
|
|
|
|
|
if ((ins >> 18) == 0x07)
|
|
|
|
|
{
|
|
|
|
|
/* addr = bits 17-4 (14 bits) | bits 1-0 (2 MSBs) */
|
|
|
|
|
ut32 addr = ((ins >> 4) & 0x3FFF) | ((ins & 0x3) << 14);
|
|
|
|
|
ut32 b_bit = (ins >> 3) & 1;
|
|
|
|
|
ut32 s_bit = (ins >> 2) & 1;
|
|
|
|
|
op->mnemonic = r_str_newf ("%s 0x%04X%s",
|
|
|
|
|
s_bit ? "CALL" : "JUMP",
|
|
|
|
|
addr,
|
|
|
|
|
b_bit ? " (DB)" : "");
|
|
|
|
|
op->type = s_bit ? R_ANAL_OP_TYPE_CALL
|
|
|
|
|
: R_ANAL_OP_TYPE_JMP;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
/* Type 10: bits 23-19 = 00011, bit18 = 0 (conditional 13-bit) */
|
|
|
|
|
if ((ins >> 19) == 0x03 && !((ins >> 18) & 1))
|
|
|
|
|
{
|
|
|
|
|
ut32 b_bit = (ins >> 17) & 1;
|
|
|
|
|
ut32 addr = (ins >> 4) & 0x1FFF;
|
|
|
|
|
ut32 cond = ins & 0xF;
|
|
|
|
|
if (cond == 15)
|
|
|
|
|
op->mnemonic = r_str_newf ("JUMP 0x%04X%s",
|
|
|
|
|
addr,
|
|
|
|
|
b_bit ? " (DB)" : "");
|
|
|
|
|
else
|
|
|
|
|
op->mnemonic = r_str_newf ("IF %s JUMP 0x%04X%s",
|
|
|
|
|
cond_str[cond], addr,
|
|
|
|
|
b_bit ? " (DB)" : "");
|
|
|
|
|
op->type = R_ANAL_OP_TYPE_CJMP;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
/* Type 17: Reg = Reg (bits 23-16 = 00001101) */
|
|
|
|
|
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 20: RTS/RTI (bits 23-16 = 00001010) */
|
|
|
|
|
if ((ins >> 16) == 0x0A)
|
|
|
|
|
{
|
|
|
|
|
ut32 b_bit = (ins >> 15) & 1;
|
|
|
|
|
ut32 t_bit = (ins >> 14) & 1;
|
|
|
|
|
ut32 cond = (ins >> 4) & 0xF;
|
|
|
|
|
const char *ret = t_bit ? "RTI" : "RTS";
|
|
|
|
|
if (cond == 15)
|
|
|
|
|
op->mnemonic = r_str_newf ("%s%s", ret,
|
|
|
|
|
b_bit ? " (DB)" : "");
|
|
|
|
|
else
|
|
|
|
|
op->mnemonic = r_str_newf ("IF %s %s%s",
|
|
|
|
|
cond_str[cond], ret,
|
|
|
|
|
b_bit ? " (DB)" : "");
|
|
|
|
|
op->type = R_ANAL_OP_TYPE_RET;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-22 19:37:27 +00:00
|
|
|
/* Type 12: Shift | DM/PM (bits 23-17 = 0001001) */
|
|
|
|
|
if ((ins >> 17) == 0x09)
|
|
|
|
|
{
|
|
|
|
|
ut32 g = (ins >> 16) & 1;
|
|
|
|
|
ut32 sf = (ins >> 13) & 0x7;
|
|
|
|
|
ut32 d = (ins >> 12) & 1;
|
|
|
|
|
ut32 xop_i = (ins >> 9) & 0x7;
|
|
|
|
|
ut32 dreg = (ins >> 4) & 0xF;
|
|
|
|
|
ut32 ireg = (ins >> 2) & 0x3;
|
|
|
|
|
ut32 mreg = ins & 0x3;
|
|
|
|
|
int base = g ? 4 : 0;
|
|
|
|
|
if (d)
|
|
|
|
|
op->mnemonic = r_str_newf ("%s %s, %cM(I%d += M%d) = %s",
|
|
|
|
|
sf_names[sf], xop_shift[xop_i],
|
|
|
|
|
g ? 'P' : 'D', ireg + base, mreg + base,
|
|
|
|
|
reg0[dreg]);
|
|
|
|
|
else
|
|
|
|
|
op->mnemonic = r_str_newf ("%s %s, %s = %cM(I%d += M%d)",
|
|
|
|
|
sf_names[sf], xop_shift[xop_i],
|
|
|
|
|
reg0[dreg],
|
|
|
|
|
g ? 'P' : 'D', ireg + base, mreg + base);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Type 14: Shift | Dreg move (bits 23-16 = 00010100) */
|
|
|
|
|
if ((ins >> 16) == 0x14)
|
|
|
|
|
{
|
|
|
|
|
ut32 sf = (ins >> 12) & 0x7;
|
|
|
|
|
ut32 xreg = (ins >> 9) & 0x7;
|
|
|
|
|
ut32 ddreg = (ins >> 4) & 0xF;
|
|
|
|
|
ut32 sdreg = ins & 0xF;
|
|
|
|
|
op->mnemonic = r_str_newf ("%s %s, %s = %s",
|
|
|
|
|
sf_names[sf], xop_shift[xreg],
|
|
|
|
|
reg0[ddreg], reg0[sdreg]);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Type 16: Conditional Shift (bits 23-16 = 00001110) */
|
|
|
|
|
if ((ins >> 16) == 0x0E)
|
|
|
|
|
{
|
|
|
|
|
ut32 sf = (ins >> 12) & 0xF;
|
|
|
|
|
ut32 xreg = (ins >> 8) & 0x7;
|
|
|
|
|
ut32 cond = ins & 0xF;
|
|
|
|
|
if (cond == 15)
|
|
|
|
|
op->mnemonic = r_str_newf ("SR = %s %s",
|
|
|
|
|
sf_names[sf], xop_shift[xreg]);
|
|
|
|
|
else
|
|
|
|
|
op->mnemonic = r_str_newf ("IF %s SR = %s %s",
|
|
|
|
|
cond_str[cond], sf_names[sf],
|
|
|
|
|
xop_shift[xreg]);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
Implement Types 8, 9, 10a, 11, 15, 17, 18, 19, 20, 21, 23, 24, 25, 26, 33, 37
- Type 8: Compute + Dreg move
- Type 9/9a: Standalone ALU/MAC compute (conditional/unconditional)
- Type 10a: Unconditional 16-bit jump/call (fixed bitfield decode)
- Type 10: Conditional 13-bit jump (fixed COND field)
- Type 18: Mode control (ENA/DIS AS, MM, BR, etc.)
- Type 19: Indirect jump/call via Ireg
- Type 20: RTS/RTI with correct COND extraction (fixed bug)
- Type 21: MODIFY(Ireg += Mreg)
- Type 23: DIVQ
- Type 24: DIVS
- Type 25: SAT MR/SR
- Type 26: Push/Pop/Flush Cache
- Type 33: Reg3 = Data12 (short constant load)
- Type 37: SETINT/CLRINT
- Type 15: Sign-extended shift exponent
2026-04-22 19:34:01 +00:00
|
|
|
/* Type 11: DO UNTIL (bits 23-16 = 00010110) */
|
|
|
|
|
if ((ins >> 16) == 0x16)
|
|
|
|
|
{
|
|
|
|
|
ut32 addr = (ins >> 4) & 0xFFF;
|
|
|
|
|
ut32 term = ins & 0xF;
|
|
|
|
|
op->mnemonic = r_str_newf ("DO 0x%03X UNTIL %s",
|
|
|
|
|
addr, cond_str[term]);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Type 15: Shift Imm (bits 23-16 = 00001111) */
|
|
|
|
|
if ((ins >> 16) == 0x0F)
|
|
|
|
|
{
|
|
|
|
|
ut32 sf = (ins >> 12) & 0xF;
|
|
|
|
|
ut32 xreg = (ins >> 8) & 0xF;
|
|
|
|
|
int8_t exp = (int8_t)(ins & 0xFF);
|
|
|
|
|
op->mnemonic = r_str_newf ("SR = %s %s BY %d",
|
|
|
|
|
sf_names[sf], reg0[xreg],
|
|
|
|
|
exp);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Type 18: Mode Control (bits 23-16 = 00001100) */
|
|
|
|
|
if ((ins >> 16) == 0x0C)
|
|
|
|
|
{
|
|
|
|
|
static const char *mbits[] =
|
|
|
|
|
{ "INT", "SD", "SR", "BR", "OL", "AS", "MM", "TI" };
|
|
|
|
|
char buf[128];
|
|
|
|
|
int pos = 0, i;
|
|
|
|
|
for (i = 0; i < 8; i++)
|
|
|
|
|
{
|
|
|
|
|
ut32 v = (ins >> (i * 2)) & 0x3;
|
|
|
|
|
if (v == 1)
|
|
|
|
|
pos += snprintf (buf + pos,
|
|
|
|
|
sizeof (buf) - pos, "%sDIS %s",
|
|
|
|
|
pos ? ", " : "", mbits[i]);
|
|
|
|
|
else if (v == 3)
|
|
|
|
|
pos += snprintf (buf + pos,
|
|
|
|
|
sizeof (buf) - pos, "%sENA %s",
|
|
|
|
|
pos ? ", " : "", mbits[i]);
|
|
|
|
|
}
|
|
|
|
|
op->mnemonic = pos ? strdup (buf)
|
|
|
|
|
: strdup ("MODE NOP");
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Type 25: SAT MR/SR (bits 23-14 = 0000001100) */
|
|
|
|
|
if ((ins >> 14) == 0x0C)
|
|
|
|
|
{
|
|
|
|
|
ut32 r = (ins >> 13) & 1;
|
|
|
|
|
op->mnemonic = r_str_newf ("SAT %s",
|
|
|
|
|
r ? "SR" : "MR");
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Type 33: Reg3 = Data12 (bits 23-16 = 00010000) */
|
|
|
|
|
if ((ins >> 16) == 0x10)
|
|
|
|
|
{
|
|
|
|
|
ut32 data = (ins >> 4) & 0xFFF;
|
|
|
|
|
ut32 reg = ins & 0xF;
|
|
|
|
|
op->mnemonic = r_str_newf ("%s = 0x%03X",
|
|
|
|
|
reg3[reg], data);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Type 19: Indirect Jump/Call (bits 23-16 = 00001011) */
|
|
|
|
|
if ((ins >> 16) == 0x0B)
|
|
|
|
|
{
|
|
|
|
|
ut32 b_bit = (ins >> 15) & 1;
|
|
|
|
|
ut32 s_bit = (ins >> 14) & 1;
|
|
|
|
|
ut32 g = (ins >> 13) & 1;
|
|
|
|
|
ut32 cond = (ins >> 4) & 0xF;
|
|
|
|
|
ut32 ireg = ins & 0x3;
|
|
|
|
|
int base = g ? 4 : 0;
|
|
|
|
|
if (cond == 15)
|
|
|
|
|
op->mnemonic = r_str_newf ("%s (I%d)%s",
|
|
|
|
|
s_bit ? "CALL" : "JUMP",
|
|
|
|
|
ireg + base,
|
|
|
|
|
b_bit ? " (DB)" : "");
|
|
|
|
|
else
|
|
|
|
|
op->mnemonic = r_str_newf ("IF %s %s (I%d)%s",
|
|
|
|
|
cond_str[cond],
|
|
|
|
|
s_bit ? "CALL" : "JUMP",
|
|
|
|
|
ireg + base,
|
|
|
|
|
b_bit ? " (DB)" : "");
|
|
|
|
|
op->type = s_bit ? R_ANAL_OP_TYPE_CALL
|
|
|
|
|
: R_ANAL_OP_TYPE_JMP;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Type 21: MODIFY (bits 23-16 = 00000001, bit15=1) */
|
|
|
|
|
if ((ins >> 16) == 0x01 && ((ins >> 15) & 1))
|
|
|
|
|
{
|
|
|
|
|
ut32 g = (ins >> 12) & 1;
|
|
|
|
|
ut32 ireg = ins & 0x3;
|
|
|
|
|
ut32 mreg = (ins >> 2) & 0x3;
|
|
|
|
|
int base = g ? 4 : 0;
|
|
|
|
|
op->mnemonic = r_str_newf ("MODIFY(I%d += M%d)",
|
|
|
|
|
ireg + base, mreg + base);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Type 23: DIVQ (bits 23-12 = 000000111101) */
|
|
|
|
|
if ((ins >> 12) == 0x03D)
|
|
|
|
|
{
|
|
|
|
|
ut32 xop_i = (ins >> 8) & 0x7;
|
|
|
|
|
op->mnemonic = r_str_newf ("DIVQ %s",
|
|
|
|
|
xop_alu[xop_i]);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Type 24: DIVS (bits 23-13 = 00000011100) */
|
|
|
|
|
if ((ins >> 13) == 0x1C)
|
|
|
|
|
{
|
|
|
|
|
ut32 yop_i = (ins >> 11) & 0x3;
|
|
|
|
|
ut32 xop_i = (ins >> 8) & 0x7;
|
|
|
|
|
op->mnemonic = r_str_newf ("DIVS %s, %s",
|
|
|
|
|
yop_alu[yop_i],
|
|
|
|
|
xop_alu[xop_i]);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Type 26: Push/Pop/Cache (bits 23-16 = 00001000) */
|
|
|
|
|
if ((ins >> 16) == 0x08)
|
|
|
|
|
{
|
|
|
|
|
ut32 cf = (ins >> 7) & 1;
|
|
|
|
|
ut32 ppp = (ins >> 4) & 0x7;
|
|
|
|
|
ut32 lpp = (ins >> 2) & 0x3;
|
|
|
|
|
ut32 spp = ins & 0x3;
|
|
|
|
|
char buf[64];
|
|
|
|
|
int pos = 0;
|
|
|
|
|
if (cf)
|
|
|
|
|
pos += snprintf (buf + pos,
|
|
|
|
|
sizeof (buf) - pos, "FLUSH CACHE");
|
|
|
|
|
if (ppp == 1)
|
|
|
|
|
pos += snprintf (buf + pos,
|
|
|
|
|
sizeof (buf) - pos, "%sPUSH PC",
|
|
|
|
|
pos ? ", " : "");
|
|
|
|
|
else if (ppp == 2)
|
|
|
|
|
pos += snprintf (buf + pos,
|
|
|
|
|
sizeof (buf) - pos, "%sPOP PC",
|
|
|
|
|
pos ? ", " : "");
|
|
|
|
|
if (lpp == 1)
|
|
|
|
|
pos += snprintf (buf + pos,
|
|
|
|
|
sizeof (buf) - pos, "%sPUSH LOOP",
|
|
|
|
|
pos ? ", " : "");
|
|
|
|
|
else if (lpp == 2)
|
|
|
|
|
pos += snprintf (buf + pos,
|
|
|
|
|
sizeof (buf) - pos, "%sPOP LOOP",
|
|
|
|
|
pos ? ", " : "");
|
|
|
|
|
if (spp == 1)
|
|
|
|
|
pos += snprintf (buf + pos,
|
|
|
|
|
sizeof (buf) - pos, "%sPUSH STS",
|
|
|
|
|
pos ? ", " : "");
|
|
|
|
|
else if (spp == 2)
|
|
|
|
|
pos += snprintf (buf + pos,
|
|
|
|
|
sizeof (buf) - pos, "%sPOP STS",
|
|
|
|
|
pos ? ", " : "");
|
|
|
|
|
op->mnemonic = pos ? strdup (buf)
|
|
|
|
|
: strdup ("STACK NOP");
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-22 19:37:27 +00:00
|
|
|
/* Type 29: Dreg <-> DM imm modify (bits 23-18 = 000010) */
|
|
|
|
|
if ((ins >> 18) == 0x02)
|
|
|
|
|
{
|
|
|
|
|
ut32 u = (ins >> 16) & 1;
|
|
|
|
|
ut32 dru = (ins >> 14) & 0x3;
|
|
|
|
|
ut32 g = (ins >> 13) & 1;
|
|
|
|
|
ut32 d = (ins >> 12) & 1;
|
|
|
|
|
ut32 mod = (ins >> 4) & 0xFF;
|
|
|
|
|
ut32 ireg = (ins >> 2) & 0x3;
|
|
|
|
|
ut32 drl = ins & 0x3;
|
|
|
|
|
ut32 dreg = (dru << 2) | drl;
|
|
|
|
|
int8_t smod = (int8_t) mod;
|
|
|
|
|
int base = g ? 4 : 0;
|
|
|
|
|
const char *mem = g ? "PM" : "DM";
|
|
|
|
|
const char *op_str = u ? "+=" : "+";
|
|
|
|
|
if (d)
|
|
|
|
|
op->mnemonic = r_str_newf ("%s(I%d %s %d) = %s",
|
|
|
|
|
mem, ireg + base, op_str, smod,
|
|
|
|
|
reg0[dreg]);
|
|
|
|
|
else
|
|
|
|
|
op->mnemonic = r_str_newf ("%s = %s(I%d %s %d)",
|
|
|
|
|
reg0[dreg], mem, ireg + base, op_str,
|
|
|
|
|
smod);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Type 32: Any Reg <-> DM/PM (bits 23-17 = 0001010, bit11=0) */
|
|
|
|
|
if ((ins >> 17) == 0x0A && !((ins >> 11) & 1))
|
|
|
|
|
{
|
|
|
|
|
ut32 ms = (ins >> 15) & 1;
|
|
|
|
|
ut32 u_bit = (ins >> 14) & 1;
|
|
|
|
|
ut32 g = (ins >> 13) & 1;
|
|
|
|
|
ut32 d = (ins >> 12) & 1;
|
|
|
|
|
ut32 rgp = (ins >> 8) & 0x3;
|
|
|
|
|
ut32 reg = (ins >> 4) & 0xF;
|
|
|
|
|
ut32 ireg = (ins >> 2) & 0x3;
|
|
|
|
|
ut32 mreg = ins & 0x3;
|
|
|
|
|
int base = g ? 4 : 0;
|
|
|
|
|
const char *mem = (ms || g) ? "PM" : "DM";
|
|
|
|
|
const char *mod = u_bit ? "+=" : "+";
|
|
|
|
|
const char *rname = get_reg (rgp, reg);
|
|
|
|
|
if (d)
|
|
|
|
|
op->mnemonic = r_str_newf ("%s(I%d %s M%d) = %s",
|
|
|
|
|
mem, ireg + base, mod, mreg + base,
|
|
|
|
|
rname);
|
|
|
|
|
else
|
|
|
|
|
op->mnemonic = r_str_newf ("%s = %s(I%d %s M%d)",
|
|
|
|
|
rname, mem, ireg + base, mod,
|
|
|
|
|
mreg + base);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Type 21a: MODIFY imm (bits 23-16 = 00000001, bit15=0) */
|
|
|
|
|
if ((ins >> 16) == 0x01 && !((ins >> 15) & 1))
|
|
|
|
|
{
|
|
|
|
|
ut32 g = (ins >> 12) & 1;
|
|
|
|
|
ut32 ireg = ins & 0x3;
|
|
|
|
|
int8_t mod = (int8_t)((ins >> 4) & 0xFF);
|
|
|
|
|
int base = g ? 4 : 0;
|
|
|
|
|
op->mnemonic = r_str_newf ("MODIFY(I%d += %d)",
|
|
|
|
|
ireg + base, mod);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Type 34: IO reg (bits 23-16 = 00000110, bit15=1) */
|
|
|
|
|
if ((ins >> 16) == 0x06 && ((ins >> 15) & 1))
|
|
|
|
|
{
|
|
|
|
|
ut32 d = (ins >> 12) & 1;
|
|
|
|
|
ut32 addr_hi = (ins >> 13) & 0x3;
|
|
|
|
|
ut32 addr = (addr_hi << 8) | ((ins >> 4) & 0xFF);
|
|
|
|
|
ut32 dreg = ins & 0xF;
|
|
|
|
|
if (d)
|
|
|
|
|
op->mnemonic = r_str_newf ("IO(0x%03X) = %s",
|
|
|
|
|
addr, reg0[dreg]);
|
|
|
|
|
else
|
|
|
|
|
op->mnemonic = r_str_newf ("%s = IO(0x%03X)",
|
|
|
|
|
reg0[dreg], addr);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
/* Type 35: Sys ctrl reg (bits 23-16 = 00000110, bit15=0) */
|
|
|
|
|
if ((ins >> 16) == 0x06 && !((ins >> 15) & 1))
|
|
|
|
|
{
|
|
|
|
|
ut32 d = (ins >> 12) & 1;
|
|
|
|
|
ut32 addr = (ins >> 4) & 0xFF;
|
|
|
|
|
ut32 dreg = ins & 0xF;
|
|
|
|
|
if (d)
|
|
|
|
|
op->mnemonic = r_str_newf ("REG(0x%02X) = %s",
|
|
|
|
|
addr, reg0[dreg]);
|
|
|
|
|
else
|
|
|
|
|
op->mnemonic = r_str_newf ("%s = REG(0x%02X)",
|
|
|
|
|
reg0[dreg], addr);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
Implement Types 8, 9, 10a, 11, 15, 17, 18, 19, 20, 21, 23, 24, 25, 26, 33, 37
- Type 8: Compute + Dreg move
- Type 9/9a: Standalone ALU/MAC compute (conditional/unconditional)
- Type 10a: Unconditional 16-bit jump/call (fixed bitfield decode)
- Type 10: Conditional 13-bit jump (fixed COND field)
- Type 18: Mode control (ENA/DIS AS, MM, BR, etc.)
- Type 19: Indirect jump/call via Ireg
- Type 20: RTS/RTI with correct COND extraction (fixed bug)
- Type 21: MODIFY(Ireg += Mreg)
- Type 23: DIVQ
- Type 24: DIVS
- Type 25: SAT MR/SR
- Type 26: Push/Pop/Flush Cache
- Type 33: Reg3 = Data12 (short constant load)
- Type 37: SETINT/CLRINT
- Type 15: Sign-extended shift exponent
2026-04-22 19:34:01 +00:00
|
|
|
/* Type 37: SETINT/CLRINT (bits 23-15 = 000001110) */
|
|
|
|
|
if ((ins >> 15) == 0x0E)
|
2026-04-12 16:59:41 +00:00
|
|
|
{
|
Implement Types 8, 9, 10a, 11, 15, 17, 18, 19, 20, 21, 23, 24, 25, 26, 33, 37
- Type 8: Compute + Dreg move
- Type 9/9a: Standalone ALU/MAC compute (conditional/unconditional)
- Type 10a: Unconditional 16-bit jump/call (fixed bitfield decode)
- Type 10: Conditional 13-bit jump (fixed COND field)
- Type 18: Mode control (ENA/DIS AS, MM, BR, etc.)
- Type 19: Indirect jump/call via Ireg
- Type 20: RTS/RTI with correct COND extraction (fixed bug)
- Type 21: MODIFY(Ireg += Mreg)
- Type 23: DIVQ
- Type 24: DIVS
- Type 25: SAT MR/SR
- Type 26: Push/Pop/Flush Cache
- Type 33: Reg3 = Data12 (short constant load)
- Type 37: SETINT/CLRINT
- Type 15: Sign-extended shift exponent
2026-04-22 19:34:01 +00:00
|
|
|
ut32 c = (ins >> 5) & 1;
|
|
|
|
|
ut32 bit = ins & 0xF;
|
|
|
|
|
op->mnemonic = r_str_newf ("%s %d",
|
|
|
|
|
c ? "CLRINT" : "SETINT", bit);
|
2026-04-12 16:59:41 +00:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
op->mnemonic = r_str_newf ("unk 0x%06X", ins);
|
|
|
|
|
return true;
|
2026-04-12 14:28:20 +00:00
|
|
|
}
|
|
|
|
|
|
2026-04-12 17:02:36 +00:00
|
|
|
static int archinfo (RArchSession *s, ut32 q)
|
2026-04-12 16:59:41 +00:00
|
|
|
{
|
2026-04-12 17:02:36 +00:00
|
|
|
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;
|
|
|
|
|
}
|
2026-04-12 14:45:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const RArchPlugin r_arch_plugin_adsp219x = {
|
2026-04-22 19:01:25 +00:00
|
|
|
.meta = { .name = "adsp219x", .author = "Dr. Christian Giessen", .desc = "ADSP-219x Master Plugin", .license = "LGPL-3.0-only" },
|
2026-04-12 17:02:36 +00:00
|
|
|
.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
|
|
|
};
|
|
|
|
|
|
2026-04-12 14:45:23 +00:00
|
|
|
#ifndef R2_PLUGIN_INCORE
|
2026-04-12 17:02:36 +00:00
|
|
|
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
|