Improve disassembly of branch instructions

- I kept getting confused trying to read these instructions, so now their
  disassembly looks more MIPS-like:
  * All mnemonics have had 'b' prepended to them for "branch".
  * The CMP_CHECK bit alters the displayed mnemonic for the inverted
    versions. e.g. BEQ can be displayed as BNE.
  * The following JMP instruction that encodes the branch destination has
    been folded into the disassembly of the branch instruction. Unlike
    MIPS, I chose to display it offset from the branch check with =>
    instead of another comma.
This commit is contained in:
Randy Heit 2015-03-13 23:14:42 -05:00
parent 775e33ede7
commit 5d2cbf4ecb
3 changed files with 85 additions and 34 deletions

View file

@ -193,6 +193,7 @@ enum EVMOpMode
MODE_IMMS,
MODE_IMMZ,
MODE_JOINT,
MODE_CMP,
MODE_PARAM,
MODE_THROW,
@ -209,6 +210,7 @@ enum EVMOpMode
MODE_AUNUSED = MODE_UNUSED << MODE_ASHIFT,
MODE_AIMMS = MODE_IMMS << MODE_ASHIFT,
MODE_AIMMZ = MODE_IMMZ << MODE_ASHIFT,
MODE_ACMP = MODE_CMP << MODE_ASHIFT,
MODE_BI = MODE_I << MODE_BSHIFT,
MODE_BF = MODE_F << MODE_BSHIFT,

View file

@ -93,6 +93,17 @@
#define I8RPRP MODE_AIMMZ | MODE_BP | MODE_CP
#define I8RPKP MODE_AIMMZ | MODE_BP | MODE_CKP
#define CIRR MODE_ACMP | MODE_BI | MODE_CI
#define CIRK MODE_ACMP | MODE_BI | MODE_CKI
#define CIKR MODE_ACMP | MODE_BKI | MODE_CI
#define CFRR MODE_ACMP | MODE_BF | MODE_CF
#define CFRK MODE_ACMP | MODE_BF | MODE_CKF
#define CFKR MODE_ACMP | MODE_BKF | MODE_CF
#define CVRR MODE_ACMP | MODE_BV | MODE_CV
#define CVRK MODE_ACMP | MODE_BV | MODE_CKV
#define CPRR MODE_ACMP | MODE_BP | MODE_CP
#define CPRK MODE_ACMP | MODE_BP | MODE_CKP
const VMOpInfo OpInfo[NUM_OPS] =
{
#define xx(op, name, mode) { #name, mode }
@ -214,28 +225,51 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction
int col;
int mode;
int a;
bool cmp;
char cmpname[8];
for (int i = 0; i < codesize; ++i)
{
name = OpInfo[code[i].op].Name;
mode = OpInfo[code[i].op].Mode;
a = code[i].a;
cmp = (mode & MODE_ATYPE) == MODE_ACMP;
// String comparison encodes everything in a single instruction.
if (code[i].op == OP_CMPS)
{
switch (a & CMP_METHOD_MASK)
{
case CMP_EQ: name = "eq"; break;
case CMP_LT: name = "lt"; break;
case CMP_LE: name = "le"; break;
case CMP_EQ: name = "beq"; break;
case CMP_LT: name = "blt"; break;
case CMP_LE: name = "ble"; break;
}
mode = MODE_AIMMZ;
mode |= (a & CMP_BK) ? MODE_BKS : MODE_BS;
mode |= (a & CMP_CK) ? MODE_CKS : MODE_CS;
a &= CMP_CHECK | CMP_APPROX;
cmp = true;
}
if (cmp)
{ // Comparison instruction. Modify name for inverted test.
if (!(a & CMP_CHECK))
{
strcpy(cmpname, name);
if (name[1] == 'e')
{ // eq -> ne
cmpname[1] = 'n', cmpname[2] = 'e';
}
else if (name[2] == 't')
{ // lt -> ge
cmpname[1] = 'g', cmpname[2] = 'e';
}
else
{ // le -> gt
cmpname[1] = 'g', cmpname[2] = 't';
}
name = cmpname;
}
}
printf_wrapper(out, "%08x: %02x%02x%02x%02x %-8s", i << 2, code[i].op, code[i].a, code[i].b, code[i].c, name);
col = 0;
switch (code[i].op)
@ -299,7 +333,7 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction
col = printf_wrapper(out, "f%d,f%d,%d", code[i].a, code[i].b, code[i].c);
if (code[i].c < countof(FlopNames))
{
col +=printf_wrapper(out, " [%s]", FlopNames[code[i].c]);
col += printf_wrapper(out, " [%s]", FlopNames[code[i].c]);
}
break;
@ -371,19 +405,34 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction
}
break;
}
if (cmp && i + 1 < codesize)
{
if (code[i+1].op != OP_JMP)
{ // comparison instructions must be followed by jump
col += printf_wrapper(out, " => *!*!*!*\n");
}
else
{
col += printf_wrapper(out, " => %08x", (i + 2 + code[i+1].i24) << 2);
}
}
if (col > 30)
{
col = 30;
}
printf_wrapper(out, "%*c", 30 - col, ';');
if (code[i].op == OP_JMP || code[i].op == OP_TRY || code[i].op == OP_PARAMI)
if (!cmp && (code[i].op == OP_JMP || code[i].op == OP_TRY || code[i].op == OP_PARAMI))
{
printf_wrapper(out, "%d\n", code[i].i24);
}
else
{
printf_wrapper(out, "%d,%d,%d", code[i].a, code[i].b, code[i].c);
if (code[i].op == OP_CALL_K || code[i].op == OP_TAIL_K)
if (cmp && i + 1 < codesize && code[i+1].op == OP_JMP)
{
printf_wrapper(out, ",%d\n", code[++i].i24);
}
else if (code[i].op == OP_CALL_K || code[i].op == OP_TAIL_K)
{
printf_wrapper(out, " [%p]\n", callfunc);
}
@ -397,7 +446,7 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction
static int print_reg(FILE *out, int col, int arg, int mode, int immshift, const VMScriptFunction *func)
{
if (mode == MODE_UNUSED)
if (mode == MODE_UNUSED || mode == MODE_CMP)
{
return 0;
}

View file

@ -146,20 +146,20 @@ xx(ZAP_R, zap, RIRIRI), // dA = dB, with bytes zeroed where bits in C/dC are o
xx(ZAP_I, zap, RIRII8),
xx(ZAPNOT_R, zapnot, RIRIRI), // dA = dB, with bytes zeroed where bits in C/dC are zero
xx(ZAPNOT_I, zapnot, RIRII8),
xx(EQ_R, eq, I8RIRI), // if ((dB == dkC) != A) then pc++
xx(EQ_K, eq, I8RIKI),
xx(LT_RR, lt, I8RIRI), // if ((dkB < dkC) != A) then pc++
xx(LT_RK, lt, I8RIKI),
xx(LT_KR, lt, I8KIRI),
xx(LE_RR, le, I8RIRI), // if ((dkB <= dkC) != A) then pc++
xx(LE_RK, le, I8RIKI),
xx(LE_KR, le, I8KIRI),
xx(LTU_RR, ltu, I8RIRI), // if ((dkB < dkC) != A) then pc++ -- unsigned
xx(LTU_RK, ltu, I8RIKI),
xx(LTU_KR, ltu, I8KIRI),
xx(LEU_RR, leu, I8RIRI), // if ((dkB <= dkC) != A) then pc++ -- unsigned
xx(LEU_RK, leu, I8RIKI),
xx(LEU_KR, leu, I8KIRI),
xx(EQ_R, beq, CIRR), // if ((dB == dkC) != A) then pc++
xx(EQ_K, beq, CIRK),
xx(LT_RR, blt, CIRR), // if ((dkB < dkC) != A) then pc++
xx(LT_RK, blt, CIRK),
xx(LT_KR, blt, CIKR),
xx(LE_RR, ble, CIRR), // if ((dkB <= dkC) != A) then pc++
xx(LE_RK, ble, CIRK),
xx(LE_KR, ble, CIKR),
xx(LTU_RR, bltu, CIRR), // if ((dkB < dkC) != A) then pc++ -- unsigned
xx(LTU_RK, bltu, CIRK),
xx(LTU_KR, bltu, CIKR),
xx(LEU_RR, bleu, CIRR), // if ((dkB <= dkC) != A) then pc++ -- unsigned
xx(LEU_RK, bleu, CIRK),
xx(LEU_KR, bleu, CIKR),
// Double-precision floating point math.
xx(ADDF_RR, add, RFRFRF), // fA = fB + fkC
@ -183,14 +183,14 @@ xx(MINF_RK, min, RFRFKF),
xx(MAXF_RR, max, RFRFRF), // fA = max(fB),fkC)
xx(MAXF_RK, max, RFRFKF),
xx(FLOP, flop, RFRFI8), // fA = f(fB), where function is selected by C
xx(EQF_R, eq, I8RFRF), // if ((fB == fkC) != (A & 1)) then pc++
xx(EQF_K, eq, I8RFKF),
xx(LTF_RR, lt, I8RFRF), // if ((fkB < fkC) != (A & 1)) then pc++
xx(LTF_RK, lt, I8RFKF),
xx(LTF_KR, lt, I8KFRF),
xx(LEF_RR, le, I8RFRF), // if ((fkb <= fkC) != (A & 1)) then pc++
xx(LEF_RK, le, I8RFKF),
xx(LEF_KR, le, I8KFRF),
xx(EQF_R, beq, CFRR), // if ((fB == fkC) != (A & 1)) then pc++
xx(EQF_K, beq, CFRK),
xx(LTF_RR, blt, CFRR), // if ((fkB < fkC) != (A & 1)) then pc++
xx(LTF_RK, blt, CFRK),
xx(LTF_KR, blt, CFKR),
xx(LEF_RR, ble, CFRR), // if ((fkb <= fkC) != (A & 1)) then pc++
xx(LEF_RK, ble, CFRK),
xx(LEF_KR, ble, CFKR),
// Vector math.
xx(NEGV, negv, RVRV), // vA = -vB
@ -208,14 +208,14 @@ xx(MULVF_RR, mulv, RVRVRV), // vA = vkB * fkC
xx(MULVF_RK, mulv, RVRVKV),
xx(MULVF_KR, mulv, RVKVRV),
xx(LENV, lenv, RFRV), // fA = vB.Length
xx(EQV_R, eqv, I8RVRV), // if ((vB == vkC) != A) then pc++ (inexact if A & 32)
xx(EQV_K, eqv, I8RVKV),
xx(EQV_R, beqv, CVRR), // if ((vB == vkC) != A) then pc++ (inexact if A & 32)
xx(EQV_K, beqv, CVRK),
// Pointer math.
xx(ADDA_RR, add, RPRPRI), // pA = pB + dkC
xx(ADDA_RK, add, RPRPKI),
xx(SUBA, sub, RIRPRP), // dA = pB - pC
xx(EQA_R, eq, I8RPRP), // if ((pB == pkC) != A) then pc++
xx(EQA_K, eq, I8RPKP),
xx(EQA_R, beq, CPRR), // if ((pB == pkC) != A) then pc++
xx(EQA_K, beq, CPRK),
#undef xx