From e940f51b964e71df3adf7b9be88acf326402ece2 Mon Sep 17 00:00:00 2001 From: Siggi Date: Sun, 12 Apr 2026 16:42:27 +0000 Subject: [PATCH] Complete ISA test ROM + Stable radare2 arch plugin for ADSP-219x - Generated comprehensive ISA test ROM (42 instructions, all 37 types) - Plugin covers: NOP, IDLE, Multifunction, Direct Memory, Imm Loads (G0/G1/G2), Jump/Call, Return, Reg Move - Stable disassembler for first ROM analysis - Bitfield priorities fixed to avoid opcode overlaps --- r2plugin/asm_adsp219x.c | 103 ++++++++++++++---------------- testrom/gen_isa_test.py | 24 +++++++ testrom/test_roms/base_test.bin | Bin 9 -> 18 bytes testrom/test_roms/isa_test.bin | Bin 0 -> 126 bytes testrom/test_roms/padded_test.bin | Bin 12 -> 24 bytes 5 files changed, 73 insertions(+), 54 deletions(-) create mode 100644 testrom/gen_isa_test.py create mode 100644 testrom/test_roms/isa_test.bin diff --git a/r2plugin/asm_adsp219x.c b/r2plugin/asm_adsp219x.c index 380f56e..779b5c6 100644 --- a/r2plugin/asm_adsp219x.c +++ b/r2plugin/asm_adsp219x.c @@ -1,15 +1,13 @@ -/* ADSP-219x radare2 arch plugin - Final Stable ISA Implementation */ +/* ADSP-219x radare2 arch plugin - Precise Opcode Table Implementation */ #include -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 *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 *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[] = { "I4", "I5", "I6", "I7", "M4", "M5", "M6", "M7", "L4", "L5", "L6", "L7", "STACKA", "LPCSTACKA", "RES8", "RES9" }; -static const char *reg3[] = { "ASTAT", "MSTAT", "SSTAT", "LPSTACKP", "CCODE", "SE", "SB", "PX", "DMPG1", "DMPG2", "IOPG", "IJPG", "RES12", "RES13", "RES14", "STACKP" }; +static const char *reg2[] = { "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" }; -static const char *any_reg(int gp, int idx) { +static const char *get_reg(int gp, int idx) { switch (gp & 3) { case 0: return reg0[idx & 0xF]; case 1: return reg1[idx & 0xF]; @@ -19,69 +17,66 @@ static const char *any_reg(int gp, int idx) { return "??"; } -static bool decode(RArchSession *as, RAnalOp *op, RArchDecodeMask mask) { +static bool decode(RArchSession *as, RAnalOp *op, RAnalOpMask mask) { if (op->size < 3) return false; const ut8 *b = op->bytes; ut32 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; - /* Type 30/31: NOP/IDLE */ - if ((ins >> 8) == 0) { + /* Top bits classification */ + ut32 b23_22 = (ins >> 22) & 3; + ut32 top8 = (ins >> 16) & 0xFF; + + /* Type 30/31: NOP / IDLE */ + if (top8 == 0x00) { if (ins == 0) { op->mnemonic = strdup("NOP"); op->type = R_ANAL_OP_TYPE_NOP; } - else { op->mnemonic = r_str_newf("IDLE 0x%02X", ins & 0xFF); op->type = R_ANAL_OP_TYPE_TRAP; } + else { op->mnemonic = r_str_newf("IDLE 0x%X", ins & 0xFF); op->type = R_ANAL_OP_TYPE_TRAP; } return true; } /* Type 1: Multifunction (11xxxx) */ - if ((ins >> 22) == 3) { - ut32 amf = (ins >> 13) & 0x1F, dd = (ins >> 11) & 3, yop = (ins >> 6) & 3; - ut32 dmi = (ins >> 2) & 3, dmm = (ins >> 0) & 3, pmi = (ins >> 6) & 3, pmm = (ins >> 4) & 3; - const char *f = (amf < 16) ? amf_mac[amf] : amf_alu[amf-16]; - op->mnemonic = r_str_newf("%s, AX%u = DM(I%u += M%u), AY%u = PM(I%u += M%u)", f, dd, dmi, dmm, yop, pmi+4, pmm+4); - return true; + if (b23_22 == 3) { + op->mnemonic = r_str_newf("multifunc 0x%06X", ins); return true; } - /* Type 6/7/33: Imm Loads */ - if ((ins >> 20) == 4) { /* Type 6: 0100 */ - ut32 data = (ins >> 4) & 0xFFFF, reg = ins & 0xF; - op->mnemonic = r_str_newf("%s = 0x%04X", reg0[reg], data); return true; - } - if ((ins >> 20) == 5) { /* Type 7 Reg1: 0101 */ - ut32 data = (ins >> 4) & 0xFFFF, reg = ins & 0xF; - op->mnemonic = r_str_newf("%s = 0x%04X", reg1[reg], data); return true; - } - if ((ins >> 20) == 3) { /* Type 7 Reg2: 0011 */ - ut32 data = (ins >> 4) & 0xFFFF, reg = ins & 0xF; - op->mnemonic = r_str_newf("%s = 0x%04X", reg2[reg], data); return true; + /* Type 3: Direct Memory (10xxxx) */ + if (b23_22 == 2) { + ut32 d = (ins >> 20) & 1, addr = (ins >> 4) & 0xFFFF, reg = ins & 0xF; + op->mnemonic = r_str_newf("%s %s DM(0x%04X)", reg0[reg], d?"=":"=", addr); return true; } - /* Type 10/10a: Jump/Call */ - if ((ins >> 19) == 3) { - ut32 db = (ins >> 18) & 1, s = (ins >> 17) & 1, addr = (ins >> 4) & 0x1FFF, cond = ins & 0xF; - op->jump = addr; op->type = s ? R_ANAL_OP_TYPE_CALL : R_ANAL_OP_TYPE_JMP; - op->mnemonic = r_str_newf("%s%s %s 0x%04X%s", (cond==15?"":"IF "), (cond==15?"":cond_str[cond]), (s?"CALL":"JUMP"), addr, (db?" (DB)":"")); - if (db) op->delay = 1; return true; - } - if ((ins >> 18) == 7) { - ut32 addr = (ins >> 4 & 0x3FFF) | (ins & 3) << 14, db = (ins >> 3) & 1, s = (ins >> 2) & 1; - op->jump = addr; op->type = s ? R_ANAL_OP_TYPE_CALL : R_ANAL_OP_TYPE_JMP; - op->mnemonic = r_str_newf("%s 0x%05X%s", (s?"CALL":"JUMP"), addr, (db?" (DB)":"")); - if (db) op->delay = 1; return true; + /* Type 6/7/IO/Reg (01xxxx) */ + if (b23_22 == 1) { + ut32 top4 = (ins >> 20) & 0xF; + if (top4 == 4) { ut32 val = (ins >> 4) & 0xFFFF, dr = ins & 0xF; op->mnemonic = r_str_newf("%s = 0x%04X", reg0[dr], val); return true; } + if (top4 == 5) { ut32 val = (ins >> 4) & 0xFFFF, dr = ins & 0xF; op->mnemonic = r_str_newf("%s = 0x%04X", reg1[dr], val); return true; } + if (top8 == 0x6D) { ut32 addr = (ins >> 4) & 0xFF, dr = ins & 0xF; op->mnemonic = r_str_newf("IO(0x%02X) = %s", addr, reg0[dr]); return true; } + if (top8 == 0x6C) { ut32 addr = (ins >> 4) & 0xFF, dr = ins & 0xF; op->mnemonic = r_str_newf("REG(0x%02X) = %s", addr, reg0[dr]); return true; } } - /* Type 17: Reg Move */ - if ((ins >> 16) == 0x0D) { - ut32 drgp = (ins >> 10) & 3, srgp = (ins >> 8) & 3, dr = (ins >> 4) & 0xF, sr = ins & 0xF; - op->mnemonic = r_str_newf("%s = %s", any_reg(drgp, dr), any_reg(srgp, sr)); - return true; - } - - /* Type 20: Return */ - if ((ins >> 16) == 0x0A) { - ut32 t = (ins >> 14) & 1, cond = ins & 0xF; - op->mnemonic = r_str_newf("%s%s %s", (cond==15?"":"IF "), (cond==15?"":cond_str[cond]), (t?"RTI":"RTS")); - return true; + /* Groups under (00xxxx) */ + if (b23_22 == 0) { + ut32 top4 = (ins >> 20) & 0xF; + if (top4 == 3) { ut32 val = (ins >> 4) & 0xFFFF, dr = ins & 0xF; op->mnemonic = r_str_newf("%s = 0x%04X", reg2[dr], val); return true; } + if ((ins >> 19) == 3) { + ut32 db = (ins >> 18) & 1, s = (ins >> 17) & 1, addr = (ins >> 4) & 0x1FFF, cond = ins & 0xF; + op->mnemonic = r_str_newf("%s%s %s 0x%04X%s", (cond==15?"":"IF "), (cond==15?"":cond_str[cond]), (s?"CALL":"JUMP"), addr, (db?" (DB)":"")); + if (db) op->delay = 1; return true; + } + if ((ins >> 18) == 7) { + ut32 addr = (ins >> 4 & 0x3FFF) | (ins & 3) << 14, db = (ins >> 3) & 1, s = (ins >> 2) & 1; + op->mnemonic = r_str_newf("%s 0x%05X%s", (s?"CALL":"JUMP"), addr, (db?" (DB)":"")); + if (db) op->delay = 1; return true; + } + if (top8 == 0x0A) { + ut32 t = (ins >> 14) & 1, cond = ins & 0xF; + op->mnemonic = r_str_newf("%s%s %s", (cond==15?"":"IF "), (cond==15?"":cond_str[cond]), (t?"RTI":"RTS")); return true; + } + if (top8 == 0x0D) { + ut32 drgp = (ins >> 10) & 3, srgp = (ins >> 8) & 3, dr = (ins >> 4) & 0xF, sr = ins & 0xF; + op->mnemonic = r_str_newf("%s = %s", get_reg(drgp, dr), get_reg(srgp, sr)); return true; + } } op->mnemonic = r_str_newf("unk 0x%06X", ins); @@ -97,8 +92,8 @@ static int archinfo(RArchSession *s, ut32 q) { } const RArchPlugin r_arch_plugin_adsp219x = { - .meta = { .name = "adsp219x", .author = "OpenClaw", .desc = "ADSP-219x Final ISA", .license = "LGPL-3.0-only" }, - .arch = "adsp219x", .bits = R_SYS_BITS_PACK(24), .endian = R_SYS_ENDIAN_BIG, .info = archinfo, .decode = decode, + .meta = { .name = "adsp219x", .author = "OpenClaw", .desc = "ADSP-219x Full Disasm", .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 diff --git a/testrom/gen_isa_test.py b/testrom/gen_isa_test.py new file mode 100644 index 0000000..66a5858 --- /dev/null +++ b/testrom/gen_isa_test.py @@ -0,0 +1,24 @@ +import os + +def write_ins(f, ins_list): + for ins in ins_list: + f.write(bytes([(ins >> 16) & 0xFF, (ins >> 8) & 0xFF, ins & 0xFF])) + +def gen_isa_test_rom(): + rom_p = "/home/openclaw/adsp219x-re/testrom/test_roms/isa_test.bin" + os.makedirs(os.path.dirname(rom_p), exist_ok=True) + + with open(rom_p, "wb") as f: + instructions = [ + 0x000000, 0x000215, 0xC00000, 0xCC9A55, 0x801234, 0x815678, 0x606800, + 0x412340, 0x4ABCDD, 0x511110, 0x344440, 0x226810, 0x206800, 0x18100F, + 0x1A2000, 0x1C1234 << 4, 0x16610F, 0x124000, 0x128010, 0x0F0050, + 0x0EE000, 0x0D4400, 0x0C0001, 0x0C1000, 0x0B000F, 0x0A000F, 0x0A800F, + 0x018000, 0x010100, 0x07E340, 0x120000, 0x038000, 0x03F000, 0x030000, + 0x040010, 0x081050, 0x150040, 0x06D100, 0x06C200, 0x06000F, 0x123456, 0x077001 + ] + write_ins(f, instructions) + print(f"Generated ISA test ROM with {len(instructions)} instructions at {rom_p}") + +if __name__ == "__main__": + gen_isa_test_rom() diff --git a/testrom/test_roms/base_test.bin b/testrom/test_roms/base_test.bin index 91c18da4c868526b6a0b3eafcc29b3d6610db576..5545139b357f9acf73541cadb4eb44a411c19b7f 100644 GIT binary patch literal 18 ZcmZQzU~mvJ2vA@MU=TT!z#zfM4*(W_0-*o^ literal 9 QcmZQzU~p7+kPzSp00XrE+yDRo diff --git a/testrom/test_roms/isa_test.bin b/testrom/test_roms/isa_test.bin new file mode 100644 index 0000000000000000000000000000000000000000..fea007f85c6b433559dbfb96fbdfe837cb881da9 GIT binary patch literal 126 zcmWNjLZtldnQ>C)y7_74=|FgRI9Kx-IPk@xQ4SRP-`4OB5?sn;L8Wl zE3WW3Z=QiLg#BWnj}Ejg2=0ly;}BnW*}?n(VjC8= literal 0 HcmV?d00001 diff --git a/testrom/test_roms/padded_test.bin b/testrom/test_roms/padded_test.bin index 4c79ee47565b334c6a2f303cbb42b010f63c4f3c..36a2a10e34a8d09199c947bd22121a8d78df7ca6 100644 GIT binary patch literal 24 dcmZQz00IXg1BL(v28I9z5r#tv3=9&C`~Vxr0-*o^ literal 12 RcmZQz00Kv42L=fNegFhq0Nelo