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
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 <r_arch.h>
/* 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