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 - 219 x 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 ] ;
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 ;
2026-04-12 16:59:41 +00:00
}
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 */
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 */
}
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) */
if ( ( ins > > 19 ) = = 0x3 ) /* Type 10/10a Jumps */
2026-04-12 16:59:41 +00:00
{
2026-04-12 17:02:36 +00:00
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) " : " " ) ;
2026-04-12 16:59:41 +00:00
return true ;
}
2026-04-12 17:02:36 +00:00
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 */
2026-04-12 16:59:41 +00:00
}
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