Fix Types 3, 4, 29, 32; add relative addressing; truncation guards

Type 3: Fix D-bit read/write direction (was always write).
  DM-only (no PM), use reg1[] for Ireg/Mreg variant.
Type 4: Add D-bit for read vs write direction (was always read).
  Properly distinguish DM(I+=M)=Dreg vs Dreg=DM(I+=M).
Type 29: G selects DAG register group, not memory bus.
  Always DM (was incorrectly PM when G=1).
Type 32: MS selects bus (DM/PM), G selects DAG group only.
  (was: MS||G for bus, causing false PM on G=1 MS=0).
Type 10/10a/11: Relative offsets resolved to absolute byte addresses
  using PC + (offset * 3). op->jump set for r2 xref analysis.
Type 36: op->jump set for LJUMP/LCALL.
2-word instructions: Truncation guard when buffer < 6 bytes.
  Emits 'trunc ...' instead of decoding with zeroed second word.
Zero warnings, full regression pass on isa_test/fir/iir.
This commit is contained in:
Dr. Christian Giessen
2026-04-22 19:57:35 +00:00
parent adfc7b34b4
commit dbcf04eb62
2 changed files with 93 additions and 31 deletions

View File

@@ -98,23 +98,47 @@ decode (RArchSession *as, RAnalOp *op, RAnalOpMask mask)
return true; return true;
} }
/* Type 3: Direct Memory (10xxxx) */ /* Type 3: Direct Memory (10xxxx)
bit21: 1=Ireg/Mreg, 0=Dreg. D=bit20: 0=read, 1=write.
Addr16=bits19-4. Reg=bits3-0. DM only (no PM). */
if (b23_22 == 2) if (b23_22 == 2)
{ {
ut32 d = (ins >> 20) & 1, addr = (ins >> 4) & 0xFFFF, reg = ins & 0xF; ut32 d = (ins >> 20) & 1;
if ((ins >> 21) & 1) /* Ireg/Mreg */ ut32 addr = (ins >> 4) & 0xFFFF;
op->mnemonic = r_str_newf ("%s(0x%04X) = %s%d", d?"DM":"DM", addr, (reg<8?"I":"M"), reg&7); ut32 reg = ins & 0xF;
else /* Dreg */ const char *rname = ((ins >> 21) & 1)
op->mnemonic = r_str_newf ("%s(0x%04X) = %s", d?"DM":"DM", addr, reg0[reg]); ? reg1[reg] : reg0[reg];
if (d)
op->mnemonic = r_str_newf ("DM(0x%04X) = %s",
addr, rname);
else
op->mnemonic = r_str_newf ("%s = DM(0x%04X)",
rname, addr);
return true; return true;
} }
/* Type 4: Compute | DM/PM Postmodify (011xxx) */ /* Type 4: Compute | DM/PM Postmodify (011xxx)
G=bit20 (0=DM/DAG1, 1=PM/DAG2), D=bit19 (0=read, 1=write),
Z=bit18, AMF=bits17-13, YOP=bits12-11, XOP=bits10-8,
DREG=bits7-4, I=bits3-2, M=bits1-0. */
if ((ins >> 21) == 0x3) if ((ins >> 21) == 0x3)
{ {
ut32 g = (ins >> 20) & 1, amf = (ins >> 13) & 0x1F; ut32 g = (ins >> 20) & 1;
const char *f = (amf < 16) ? amf_mac[amf] : amf_alu[amf-16]; ut32 d = (ins >> 19) & 1;
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)); ut32 amf = (ins >> 13) & 0x1F;
const char *f = (amf < 16) ? amf_mac[amf] : amf_alu[amf - 16];
ut32 dreg = (ins >> 4) & 0xF;
ut32 ireg = ((ins >> 2) & 3) | (g ? 4 : 0);
ut32 mreg = (ins & 3) | (g ? 4 : 0);
char mem = g ? 'P' : 'D';
if (d)
op->mnemonic = r_str_newf ("%s, %cM(I%d += M%d) = %s",
f, mem, ireg, mreg,
reg0[dreg]);
else
op->mnemonic = r_str_newf ("%s, %s = %cM(I%d += M%d)",
f, reg0[dreg], mem,
ireg, mreg);
return true; return true;
} }
@@ -208,11 +232,18 @@ decode (RArchSession *as, RAnalOp *op, RAnalOpMask mask)
/* Type 36: Long Jump/Call (2-word, bits 23-16 = 00000101) */ /* Type 36: Long Jump/Call (2-word, bits 23-16 = 00000101) */
if ((ins >> 16) == 0x05) if ((ins >> 16) == 0x05)
{ {
if (op->size < 6)
{
op->mnemonic = r_str_newf ("trunc L%s 0x%06X",
((ins >> 12) & 1) ? "CALL" : "JUMP", ins);
return true;
}
ut32 s_bit = (ins >> 12) & 1; ut32 s_bit = (ins >> 12) & 1;
ut32 cond = ins & 0xF; ut32 cond = ins & 0xF;
ut32 addr_hi = (ins >> 4) & 0xFF; ut32 addr_hi = (ins >> 4) & 0xFF;
ut32 addr_lo = ins2 & 0xFFFFFF; ut32 addr_lo = ins2 & 0xFFFFFF;
ut32 addr = (addr_hi << 16) | (addr_lo & 0xFFFF); ut32 addr = (addr_hi << 16) | (addr_lo & 0xFFFF);
/* 24-bit absolute address for long jump/call */
op->size = 6; op->size = 6;
if (cond == 15) if (cond == 15)
op->mnemonic = r_str_newf ("%s 0x%06X", op->mnemonic = r_str_newf ("%s 0x%06X",
@@ -223,12 +254,19 @@ decode (RArchSession *as, RAnalOp *op, RAnalOpMask mask)
s_bit ? "LCALL" : "LJUMP", addr); s_bit ? "LCALL" : "LJUMP", addr);
op->type = s_bit ? R_ANAL_OP_TYPE_CALL op->type = s_bit ? R_ANAL_OP_TYPE_CALL
: R_ANAL_OP_TYPE_JMP; : R_ANAL_OP_TYPE_JMP;
op->jump = addr;
return true; return true;
} }
/* Type 22: DM/PM = Data16 (2-word, bits 23-13 = 00000011110) */ /* Type 22: DM/PM = Data16 (2-word, bits 23-13 = 00000011110) */
if ((ins >> 13) == 0x1E && !((ins >> 12) & 1)) if ((ins >> 13) == 0x1E && !((ins >> 12) & 1))
{ {
if (op->size < 6)
{
op->mnemonic = r_str_newf ("trunc DM_IMM16 0x%06X",
ins);
return true;
}
ut32 g = (ins >> 12) & 1; ut32 g = (ins >> 12) & 1;
ut32 ireg = (ins >> 2) & 0x3; ut32 ireg = (ins >> 2) & 0x3;
ut32 mreg = ins & 0x3; ut32 mreg = ins & 0x3;
@@ -245,6 +283,12 @@ decode (RArchSession *as, RAnalOp *op, RAnalOpMask mask)
/* Type 22a: PM = Data24 (2-word, bits 23-13 = 00000011111) */ /* Type 22a: PM = Data24 (2-word, bits 23-13 = 00000011111) */
if ((ins >> 13) == 0x1F) if ((ins >> 13) == 0x1F)
{ {
if (op->size < 6)
{
op->mnemonic = r_str_newf ("trunc PM_IMM24 0x%06X",
ins);
return true;
}
ut32 g = (ins >> 12) & 1; ut32 g = (ins >> 12) & 1;
ut32 ireg = (ins >> 2) & 0x3; ut32 ireg = (ins >> 2) & 0x3;
ut32 mreg = ins & 0x3; ut32 mreg = ins & 0x3;
@@ -258,36 +302,45 @@ decode (RArchSession *as, RAnalOp *op, RAnalOpMask mask)
ireg + base, mreg + base, data); ireg + base, mreg + base, data);
return true; return true;
} }
/* Type 10a: bits 23-18 = 000111 (unconditional 16-bit) */ /* Type 10a: bits 23-18 = 000111 (unconditional 16-bit rel) */
if ((ins >> 18) == 0x07) if ((ins >> 18) == 0x07)
{ {
/* addr = bits 17-4 (14 bits) | bits 1-0 (2 MSBs) */ /* addr = bits 17-4 (14 bits) | bits 1-0 (2 MSBs) */
ut32 addr = ((ins >> 4) & 0x3FFF) | ((ins & 0x3) << 14); ut32 rel = ((ins >> 4) & 0x3FFF) | ((ins & 0x3) << 14);
ut32 b_bit = (ins >> 3) & 1; ut32 b_bit = (ins >> 3) & 1;
ut32 s_bit = (ins >> 2) & 1; ut32 s_bit = (ins >> 2) & 1;
op->mnemonic = r_str_newf ("%s 0x%04X%s", /* Sign-extend 16-bit relative offset */
int32_t srel = (int32_t)(int16_t) rel;
ut64 target = op->addr + (srel * 3);
op->mnemonic = r_str_newf ("%s 0x%06" PFMT64x "%s",
s_bit ? "CALL" : "JUMP", s_bit ? "CALL" : "JUMP",
addr, target,
b_bit ? " (DB)" : ""); b_bit ? " (DB)" : "");
op->type = s_bit ? R_ANAL_OP_TYPE_CALL op->type = s_bit ? R_ANAL_OP_TYPE_CALL
: R_ANAL_OP_TYPE_JMP; : R_ANAL_OP_TYPE_JMP;
op->jump = target;
return true; return true;
} }
/* Type 10: bits 23-19 = 00011, bit18 = 0 (conditional 13-bit) */ /* Type 10: bits 23-19 = 00011, bit18 = 0 (conditional 13-bit rel) */
if ((ins >> 19) == 0x03 && !((ins >> 18) & 1)) if ((ins >> 19) == 0x03 && !((ins >> 18) & 1))
{ {
ut32 b_bit = (ins >> 17) & 1; ut32 b_bit = (ins >> 17) & 1;
ut32 addr = (ins >> 4) & 0x1FFF; ut32 rel = (ins >> 4) & 0x1FFF;
ut32 cond = ins & 0xF; ut32 cond = ins & 0xF;
/* Sign-extend 13-bit relative offset */
int32_t srel = (rel & 0x1000)
? (int32_t)(rel | 0xFFFFE000) : (int32_t) rel;
ut64 target = op->addr + (srel * 3);
if (cond == 15) if (cond == 15)
op->mnemonic = r_str_newf ("JUMP 0x%04X%s", op->mnemonic = r_str_newf ("JUMP 0x%06" PFMT64x "%s",
addr, target,
b_bit ? " (DB)" : ""); b_bit ? " (DB)" : "");
else else
op->mnemonic = r_str_newf ("IF %s JUMP 0x%04X%s", op->mnemonic = r_str_newf ("IF %s JUMP 0x%06" PFMT64x "%s",
cond_str[cond], addr, cond_str[cond], target,
b_bit ? " (DB)" : ""); b_bit ? " (DB)" : "");
op->type = R_ANAL_OP_TYPE_CJMP; op->type = R_ANAL_OP_TYPE_CJMP;
op->jump = target;
return true; return true;
} }
/* Type 17: Reg = Reg (bits 23-16 = 00001101) */ /* Type 17: Reg = Reg (bits 23-16 = 00001101) */
@@ -370,13 +423,17 @@ decode (RArchSession *as, RAnalOp *op, RAnalOpMask mask)
return true; return true;
} }
/* Type 11: DO UNTIL (bits 23-16 = 00010110) */ /* Type 11: DO UNTIL (bits 23-16 = 00010110, 12-bit rel) */
if ((ins >> 16) == 0x16) if ((ins >> 16) == 0x16)
{ {
ut32 addr = (ins >> 4) & 0xFFF; ut32 rel = (ins >> 4) & 0xFFF;
ut32 term = ins & 0xF; ut32 term = ins & 0xF;
op->mnemonic = r_str_newf ("DO 0x%03X UNTIL %s", int32_t srel = (rel & 0x800)
addr, cond_str[term]); ? (int32_t)(rel | 0xFFFFF000) : (int32_t) rel;
ut64 target = op->addr + (srel * 3);
op->mnemonic = r_str_newf (
"DO 0x%06" PFMT64x " UNTIL %s",
target, cond_str[term]);
return true; return true;
} }
@@ -533,7 +590,11 @@ decode (RArchSession *as, RAnalOp *op, RAnalOpMask mask)
return true; return true;
} }
/* Type 29: Dreg <-> DM imm modify (bits 23-18 = 000010) */ /* Type 29: Dreg <-> DM imm modify (bits 23-18 = 000010)
Always DM. G=bit13 selects DAG group (I0-3 vs I4-7),
not the memory bus. U=bit16 (post/pre), D=bit12 (r/w),
DRU=bits15-14, DRL=bits1-0, DREG=(DRU<<2)|DRL,
MOD=bits11-4 (signed), I=bits3-2. */
if ((ins >> 18) == 0x02) if ((ins >> 18) == 0x02)
{ {
ut32 u = (ins >> 16) & 1; ut32 u = (ins >> 16) & 1;
@@ -546,15 +607,14 @@ decode (RArchSession *as, RAnalOp *op, RAnalOpMask mask)
ut32 dreg = (dru << 2) | drl; ut32 dreg = (dru << 2) | drl;
int8_t smod = (int8_t) mod; int8_t smod = (int8_t) mod;
int base = g ? 4 : 0; int base = g ? 4 : 0;
const char *mem = g ? "PM" : "DM";
const char *op_str = u ? "+=" : "+"; const char *op_str = u ? "+=" : "+";
if (d) if (d)
op->mnemonic = r_str_newf ("%s(I%d %s %d) = %s", op->mnemonic = r_str_newf ("DM(I%d %s %d) = %s",
mem, ireg + base, op_str, smod, ireg + base, op_str, smod,
reg0[dreg]); reg0[dreg]);
else else
op->mnemonic = r_str_newf ("%s = %s(I%d %s %d)", op->mnemonic = r_str_newf ("%s = DM(I%d %s %d)",
reg0[dreg], mem, ireg + base, op_str, reg0[dreg], ireg + base, op_str,
smod); smod);
return true; return true;
} }
@@ -571,7 +631,9 @@ decode (RArchSession *as, RAnalOp *op, RAnalOpMask mask)
ut32 ireg = (ins >> 2) & 0x3; ut32 ireg = (ins >> 2) & 0x3;
ut32 mreg = ins & 0x3; ut32 mreg = ins & 0x3;
int base = g ? 4 : 0; int base = g ? 4 : 0;
const char *mem = (ms || g) ? "PM" : "DM"; /* MS selects bus (0=DM 16-bit, 1=PM 24-bit).
G selects DAG group only. */
const char *mem = ms ? "PM" : "DM";
const char *mod = u_bit ? "+=" : "+"; const char *mod = u_bit ? "+=" : "+";
const char *rname = get_reg (rgp, reg); const char *rname = get_reg (rgp, reg);
if (d) if (d)

Binary file not shown.