From aa486f09b084816f698ca447a1d835cfe904cf9a Mon Sep 17 00:00:00 2001 From: "Dr. Christian Giessen" Date: Wed, 22 Apr 2026 19:37:27 +0000 Subject: [PATCH] Add Types 12, 14, 16, 19, 21a, 29, 32, 34, 35 decode - Type 12: Shift with DM/PM memory access - Type 14: Shift with Dreg move - Type 16: Conditional shift - Type 29: DM/PM read/write with immediate modify - Type 32: Any Reg <-> DM/PM with DAG postmodify - Type 34: IO register read/write (both directions) - Type 35: System control register read/write (both directions) - Type 21a: MODIFY with immediate offset - Fix: Move Type 34/35 from b23_22==1 block to b23_22==0 - Fix: Type 12 prefix corrected to bits 23-17 = 0001001 - Zero compiler warnings (except unused xop_shift, now used) - Full regression test: all 48 isa_test.bin instructions pass --- r2plugin/asm_adsp219x.c | 150 ++++++++++++++++++++++++++++++++++++++- r2plugin/asm_adsp219x.so | Bin 20288 -> 24416 bytes 2 files changed, 148 insertions(+), 2 deletions(-) diff --git a/r2plugin/asm_adsp219x.c b/r2plugin/asm_adsp219x.c index f85aff1..1c72b2e 100644 --- a/r2plugin/asm_adsp219x.c +++ b/r2plugin/asm_adsp219x.c @@ -170,8 +170,7 @@ decode (RArchSession *as, RAnalOp *op, RAnalOpMask mask) { 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 34 and 35 are in the b23_22==0 block below */ } /* Type 8/9/10/11/17... (00xxxx) */ @@ -237,6 +236,59 @@ decode (RArchSession *as, RAnalOp *op, RAnalOpMask mask) return true; } + /* 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; + } + /* Type 11: DO UNTIL (bits 23-16 = 00010110) */ if ((ins >> 16) == 0x16) { @@ -400,6 +452,100 @@ decode (RArchSession *as, RAnalOp *op, RAnalOpMask mask) return true; } + /* 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; + } + /* Type 37: SETINT/CLRINT (bits 23-15 = 000001110) */ if ((ins >> 15) == 0x0E) { diff --git a/r2plugin/asm_adsp219x.so b/r2plugin/asm_adsp219x.so index feccfca0d8c4bac04ede5a0534a35e8cfbd54eb2..bb388d5c40f60c2741309199e2238e4720b52e42 100755 GIT binary patch literal 24416 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