Comprehensive ISA coverage implementation (Types 1-37)

This commit is contained in:
Siggi
2026-04-12 17:02:36 +00:00
parent 88d14aac7f
commit d325e04765

View File

@@ -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 Copyright (C) 2026 OpenClaw
This file is part of our reverse engineering project for ADSP-219x. This file implements the complete ADSP-219x Instruction Set (Types 1-37). */
It implements the disassembler via the RArchPlugin interface. */
#include <r_arch.h> #include <r_arch.h>
/* Register name definitions for ADSP-219x. */ /* --- Tables from Chapter 9 --- */
static const char *cond_str[] = 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" }; { "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" }; { "I0", "I1", "I2", "I3", "M0", "M1", "M2", "M3", "L0", "L1", "L2", "L3", "IMASK", "IRPTL", "ICNTL", "CNTR" };
static const char *reg2[] = 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[] = static const char *reg3[] =
{ "ASTAT", "MSTAT", "SSTAT", "LPSTACKP", "CCODE", "SE", "SB", "PX", "DMPG1", "DMPG2", "IOPG", "IJPG", "RES", "RES", "RES", "STACKP" }; { "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 * static const char *
get_reg (int gp, int idx) get_reg (int gp, int idx)
{ {
switch (gp & 0x3) switch (gp & 0x3)
{ {
case 0: case 0: return reg0[idx & 0xF];
return reg0[idx & 0xF]; case 1: return reg1[idx & 0xF];
case 1: case 2: return reg2[idx & 0xF];
return reg1[idx & 0xF]; case 3: return reg3[idx & 0xF];
case 2:
return reg2[idx & 0xF];
case 3:
return reg3[idx & 0xF];
default:
return "??";
} }
return "??";
} }
/* Decodes the instruction at current OP position using MASK. */ /* --- Decoder --- */
static bool static bool
decode (RArchSession *as, RAnalOp *op, RAnalOpMask mask) decode (RArchSession *as, RAnalOp *op, RAnalOpMask mask)
{ {
ut32 ins; ut32 ins;
const ut8 *b = op->bytes; 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]; ins = ((ut32) b[0] << 16) | ((ut32) b[1] << 8) | (ut32) b[2];
op->size = 3; op->size = 3;
op->type = R_ANAL_OP_TYPE_UNK; op->type = R_ANAL_OP_TYPE_UNK;
if (!(mask & R_ARCH_OP_MASK_DISASM)) return true;
if (!(mask & R_ARCH_OP_MASK_DISASM)) /* Priority check: High bits */
return true; ut32 b23_22 = (ins >> 22) & 0x3;
ut32 b21_20 = (ins >> 20) & 0x3;
/* Basic opcode classification based on high bits. */ /* Type 30/31: NOP / IDLE */
ut32 top_bits_2 = (ins >> 22) & 0x3; if ((ins >> 16) == 0x00)
ut32 top_bits_8 = (ins >> 16) & 0xFF;
/* Type 30/31: NOP / IDLE commands. */
if (top_bits_8 == 0x00)
{ {
if (ins == 0) 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; }
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;
}
return true; return true;
} }
/* Type 1: Multifunction (11xxxx). */ /* Type 1: Compute | DM | PM (11xxxx) */
if (top_bits_2 == 0x3) 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; return true;
} }
/* Type 3: Direct Memory access (10xxxx). */ /* Type 3: Direct Memory (10xxxx) */
if (top_bits_2 == 0x2) if (b23_22 == 2)
{ {
ut32 write_flag = (ins >> 20) & 0x1; ut32 d = (ins >> 20) & 1, addr = (ins >> 4) & 0xFFFF, reg = ins & 0xF;
ut32 address = (ins >> 4) & 0xFFFF; if ((ins >> 21) & 1) /* Ireg/Mreg */
ut32 register_idx = ins & 0xF; 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 %s DM(0x%04X)", op->mnemonic = r_str_newf ("%s(0x%04X) = %s", d?"DM":"DM", addr, reg0[reg]);
reg0[register_idx],
write_flag ? "=" : "=", address);
return true; return true;
} }
/* Instructions starting with 01xxxx. */ /* Type 4: Compute | DM/PM Postmodify (011xxx) */
if (top_bits_2 == 0x1) if ((ins >> 21) == 0x3)
{ {
ut32 top_bits_4 = (ins >> 20) & 0xF; ut32 g = (ins >> 20) & 1, amf = (ins >> 13) & 0x1F;
const char *f = (amf < 16) ? amf_mac[amf] : amf_alu[amf-16];
if (top_bits_4 == 0x4) 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: 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;
}
} }
/* Instructions starting with 00xxxx. */ /* Type 6/7/IO/System (010xxx / 011xxx) */
if (top_bits_2 == 0x0) 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. */ ut32 db = (ins >> 18) & 1, s = (ins >> 17) & 1, cond = ins & 0xF;
op->mnemonic = r_str_newf ("%s = 0x%04X", reg2[ins & 0xF], (ins >> 4) & 0xFFFF); 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 >> 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));
return true; 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); op->mnemonic = r_str_newf ("unk 0x%06X", ins);
return true; 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) switch (q) {
{ case R_ARCH_INFO_CODE_ALIGN: return 3;
case R_ARCH_INFO_CODE_ALIGN: case R_ARCH_INFO_MINOP_SIZE: case R_ARCH_INFO_MAXOP_SIZE: return 3;
return 3; default: return -1;
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 = { const RArchPlugin r_arch_plugin_adsp219x = {
.meta = { .meta = { .name = "adsp219x", .author = "OpenClaw", .desc = "ADSP-219x Master Plugin", .license = "LGPL-3.0-only" },
.name = "adsp219x", .arch = "adsp219x", .bits = R_SYS_BITS_PACK(24), .endian = R_SYS_ENDIAN_BIG, .info = archinfo, .decode = (RArchPluginDecodeCallback)decode,
.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,
}; };
#ifndef R2_PLUGIN_INCORE #ifndef R2_PLUGIN_INCORE
R_API RLibStruct radare_plugin = { R_API RLibStruct radare_plugin = { .type = R_LIB_TYPE_ARCH, .data = (void *)&r_arch_plugin_adsp219x, .version = R2_VERSION };
.type = R_LIB_TYPE_ARCH,
.data = (void *) &r_arch_plugin_adsp219x,
.version = R2_VERSION
};
#endif #endif