-/* jit/mips/disass.c - primitive disassembler for mips machine code
+/* src/vm/jit/mips/disass.c - primitive disassembler for MIPS machine code
- Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
- Institut f. Computersprachen, TU Wien
- R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser, M. Probst,
- S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich,
- J. Wenninger
+ Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel,
+ C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
+ E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
+ J. Wenninger, Institut f. Computersprachen - TU Wien
This file is part of CACAO.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- 02111-1307, USA.
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
- Contact: cacao@complang.tuwien.ac.at
+*/
- Authors: Andreas Krall
- $Id: disass.c 1109 2004-05-28 13:11:16Z twisti $
+#include "config.h"
-*/
+#include <stdio.h>
+#include "vm/types.h"
-#include <stdio.h>
-#include "types.h"
-#include "disass.h"
+#include "vm/jit/abi.h"
/* The disassembler uses four tables for decoding the instructions. The first
};
-/* instruction decode table for 32 integer registers */
-
-char *regs[] = {
- /* 0x00 */ "zero", /* "$0", */
- /* 0x01 */ "at", /* "$1", */
- /* 0x02 */ "v0", /* "$2", */
- /* 0x03 */ "v1", /* "$3", */
- /* 0x04 */ "a0", /* "$4", */
- /* 0x05 */ "a1", /* "$5", */
- /* 0x06 */ "a2", /* "$6", */
- /* 0x07 */ "a3", /* "$7", */
-
- /* 0x08 */ "a4", /* "$8", */
- /* 0x09 */ "a5", /* "$9", */
- /* 0x0a */ "a6", /* "$10", */
- /* 0x0b */ "a7", /* "$11", */
- /* 0x0c */ "t4", /* "$12", */
- /* 0x0d */ "t5", /* "$13", */
- /* 0x0e */ "t6", /* "$14", */
- /* 0x0f */ "t7", /* "$15", */
-
- /* 0x10 */ "s0", /* "$16", */
- /* 0x11 */ "s1", /* "$17", */
- /* 0x12 */ "s2", /* "$18", */
- /* 0x13 */ "s3", /* "$19", */
- /* 0x14 */ "s4", /* "$20", */
- /* 0x15 */ "s5", /* "$21", */
- /* 0x16 */ "s6", /* "$22", */
- /* 0x17 */ "s7", /* "$23", */
-
- /* 0x18 */ "t8", /* "$24", */
- /* 0x19 */ "t9", /* "$25", */
- /* 0x1a */ "k0", /* "$26", */
- /* 0x1b */ "k1", /* "$27", */
- /* 0x1c */ "gp", /* "$28", */
- /* 0x1d */ "sp", /* "$29", */
- /* 0x1e */ "s8", /* "$30", */
- /* 0x1f */ "ra" /* "$31" */
-};
-
-
/* instruction decode table for 32 floating point registers */
#if 0
#endif
-/* function disassinstr ********************************************************
+/* disassinstr *****************************************************************
- outputs a disassembler listing of one machine code instruction on 'stdout'
- c: instructions machine code
- pos: instructions address relative to method start
+ Outputs a disassembler listing of one machine code instruction on
+ 'stdout'.
+
+ code: pointer to instructions machine code
*******************************************************************************/
-void disassinstr(s4 *code, int pos)
+u1 *disassinstr(u1 *code)
{
- int op; /* 6 bit op code */
- int opfun; /* 6 bit function code */
- int rs, rt, rd; /* 5 bit integer register specifiers */
- int fs, ft, fd; /* 5 bit floating point register specifiers */
- int shift; /* 5 bit unsigned shift amount */
- s4 c = *code;
+ s4 op; /* 6 bit op code */
+ s4 opfun; /* 6 bit function code */
+ s4 rs, rt, rd; /* 5 bit integer register specifiers */
+ s4 fs, ft, fd; /* 5 bit floating point register specifiers */
+ s4 shift; /* 5 bit unsigned shift amount */
+ s4 c;
+
+ c = *((s4 *) code);
op = (c >> 26) & 0x3f; /* 6 bit op code */
opfun = (c >> 0) & 0x3f; /* 6 bit function code */
rd = (c >> 11) & 0x1f; /* 5 bit destination register specifier */
shift = (c >> 6) & 0x1f; /* 5 bit unsigned shift amount */
+#if SIZEOF_VOID_P == 8
printf("0x%016lx: %08x ", (u8) code, c);
-
+#else
+ printf("0x%08x: %08x ", (u4) code, c);
+#endif
+
switch (ops[op].itype) {
- case ITYPE_JMP: /* 26 bit unsigned jump offset */
- printf ("%s %#09x\n", ops[op].name, (c & 0x3ffffff) << 2);
+ case ITYPE_JMP: /* 26 bit unsigned jump offset */
+ printf("%s %#09x\n", ops[op].name, (c & 0x3ffffff) << 2);
+ break;
+
+ case ITYPE_IMM: /* 16 bit signed immediate value */
+ printf("%s %s,%s,%d\n", ops[op].name, abi_registers_integer_name[rt],
+ abi_registers_integer_name[rs], (c << 16) >> 16);
+ break;
+
+ case ITYPE_MEM: /* 16 bit signed memory offset */
+ printf("%s %s,%d(%s)\n", ops[op].name, abi_registers_integer_name[rt],
+ (c << 16) >> 16, abi_registers_integer_name[rs]);
+ break;
+
+ case ITYPE_FMEM: /* 16 bit signed memory offset */
+ printf("%s $f%d,%d(%s)\n", ops[op].name, rt, (c << 16) >> 16,
+ abi_registers_integer_name[rs]);
+ break;
+
+ case ITYPE_BRA: /* 16 bit signed branch offset */
+ if (op == 0x04 && rs == 0 && rt == 0) {
+#if SIZEOF_VOID_P == 8
+ printf("b 0x%016lx\n", (u8) code + 4 + ((c << 16) >> 14));
+#else
+ printf("b 0x%08x\n", (u4) code + 4 + ((c << 16) >> 14));
+#endif
break;
+ }
+#if SIZEOF_VOID_P == 8
+ printf("%s %s,%s,0x%016lx\n", ops[op].name,
+ abi_registers_integer_name[rs],
+ abi_registers_integer_name[rt],
+ (u8) code + 4 + ((c << 16) >> 14));
+#else
+ printf("%s %s,%s,0x%08x\n", ops[op].name,
+ abi_registers_integer_name[rs],
+ abi_registers_integer_name[rt],
+ (u4) code + 4 + ((c << 16) >> 14));
+#endif
+ break;
+
+ case ITYPE_RIMM:
+ if (regimms[rt].ftype == ITYPE_IMM)
+ printf("%s %s,%d\n", regimms[rt].name,
+ abi_registers_integer_name[rs], (c << 16) >> 16);
+ else if (regimms[rt].ftype == ITYPE_BRA)
+#if SIZEOF_VOID_P == 8
+ printf("%s %s,0x%016lx\n", regimms[rt].name,
+ abi_registers_integer_name[rs],
+ (u8) code + 4 + ((c << 16) >> 14));
+#else
+ printf("%s %s,0x%08x\n", regimms[rt].name,
+ abi_registers_integer_name[rs],
+ (u4) code + 4 + ((c << 16) >> 14));
+#endif
+ else
+ printf("regimm %#04x,$%d,%d\n", rt, rs, (c << 16) >> 16);
+ break;
- case ITYPE_IMM: /* 16 bit signed immediate value */
- printf ("%s %s,%s,%d\n", ops[op].name, regs[rt],
- regs[rs], (c << 16) >> 16);
+ case ITYPE_OP:
+ if (c == 0) {
+ printf("nop\n");
break;
-
- case ITYPE_MEM: /* 16 bit signed memory offset */
- printf ("%s %s,%d(%s)\n", ops[op].name, regs[rt],
- (c << 16) >> 16, regs[rs]);
+ }
+ if (opfun == 0x25 && rt == 0) {
+ if (rs == 0)
+ printf("clr %s\n", abi_registers_integer_name[rd]);
+ else
+ printf("move %s,%s\n", abi_registers_integer_name[rd],
+ abi_registers_integer_name[rs]);
break;
-
- case ITYPE_FMEM: /* 16 bit signed memory offset */
- printf ("%s $f%d,%d(%s)\n", ops[op].name, rt,
- (c << 16) >> 16, regs[rs]);
+ }
+ switch (regops[opfun].ftype) {
+ case ITYPE_OP:
+ printf("%s %s,%s,%s\n", regops[opfun].name,
+ abi_registers_integer_name[rd],
+ abi_registers_integer_name[rs],
+ abi_registers_integer_name[rt]);
break;
-
- case ITYPE_BRA: /* 16 bit signed branch offset */
- if (op == 0x04 && rs == 0 && rt == 0) {
- printf("b 0x%016lx\n", (u8) code + 4 + ((c << 16) >> 14));
- break;
- }
- printf("%s %s,%s,0x%016lx\n", ops[op].name, regs[rs], regs[rt],
- (u8) code + 4 + ((c << 16) >> 14));
+ case ITYPE_IMM: /* immediate instruction */
+ printf("%s %s,%s,%d\n",
+ regops[opfun].name, abi_registers_integer_name[rd],
+ abi_registers_integer_name[rt], shift);
break;
-
- case ITYPE_RIMM:
- if (regimms[rt].ftype == ITYPE_IMM)
- printf("%s %s,%d\n", regimms[rt].name, regs[rs],
- (c << 16) >> 16);
- else if (regimms[rt].ftype == ITYPE_BRA)
- printf("%s %s,0x%016lx\n", regimms[rt].name, regs[rs],
- (u8) code + 4 + ((c << 16) >> 14));
- else
- printf("regimm %#04x,$%d,%d\n", rt, rs, (c << 16) >> 16);
+ case ITYPE_TRAP:
+ printf("%s %s,%s,%d\n", regops[opfun].name,
+ abi_registers_integer_name[rs],
+ abi_registers_integer_name[rt], (c << 16) >> 22);
break;
-
- case ITYPE_OP:
- if (c == 0) {
- printf("nop\n");
- return;
- }
- if (opfun == 0x25 && rt == 0) {
- if (rs == 0)
- printf("clr %s\n", regs[rd]);
- else
- printf("move %s,%s\n", regs[rd], regs[rs]);
- return;
- }
- switch (regops[opfun].ftype) {
- case ITYPE_OP:
- printf("%s %s,%s,%s\n", regops[opfun].name, regs[rd],
- regs[rs], regs[rt]);
- break;
- case ITYPE_IMM: /* immediate instruction */
- printf("%s %s,%s,%d\n",
- regops[opfun].name, regs[rd], regs[rt], shift);
- break;
- case ITYPE_TRAP:
- printf("%s %s,%s,%d\n", regops[opfun].name,
- regs[rs], regs[rt], (c << 16) >> 22);
- break;
- case ITYPE_DIVMUL: /* div/mul instruction */
- printf("%s %s,%s\n", regops[opfun].name, regs[rs], regs[rt]);
- break;
- case ITYPE_JMP:
- if (rd == 31) {
- printf("%s %s\n", regops[opfun].name, regs[rs]);
- break;
- }
- printf("%s %s,%s\n", regops[opfun].name, regs[rd], regs[rs]);
- break;
- case ITYPE_MTOJR:
- if (opfun == 8 && rs == 31) {
- printf("ret\n");
- break;
- }
- printf("%s %s\n", regops[opfun].name, regs[rs]);
- break;
- case ITYPE_MFROM:
- printf("%s %s\n", regops[opfun].name, regs[rd]);
- break;
- case ITYPE_SYS:
- printf("%s\n", regops[opfun].name);
- default:
- printf("special (%#04x) $%d,$%d,$%d\n", opfun, rd, rs, rt);
- }
+ case ITYPE_DIVMUL: /* div/mul instruction */
+ printf("%s %s,%s\n", regops[opfun].name,
+ abi_registers_integer_name[rs],
+ abi_registers_integer_name[rt]);
break;
- case ITYPE_FOP:
- fs = (c >> 11) & 0x1f; /* 5 bit source register */
- ft = (c >> 16) & 0x1f; /* 5 bit source/destination register */
- fd = (c >> 6) & 0x1f; /* 5 bit destination register */
-
- if (rs == 8) { /* floating point branch */
- printf("%s %x\n", fbra[ft&3], pos + 4 + ((c << 16) >> 14));
+ case ITYPE_JMP:
+ if (rd == 31) {
+ printf("%s %s\n", regops[opfun].name,
+ abi_registers_integer_name[rs]);
break;
- }
-
- if (rs == 0) { /* move from */
- printf("mfc1 %s,$f%d\n", regs[rt], fs);
- break;
- }
-
- if (rs == 1) { /* double move from */
- printf("dmfc1 %s,$f%d\n", regs[rt], fs);
+ }
+ printf("%s %s,%s\n", regops[opfun].name,
+ abi_registers_integer_name[rd],
+ abi_registers_integer_name[rs]);
+ break;
+ case ITYPE_MTOJR:
+ if (opfun == 8 && rs == 31) {
+ printf("ret\n");
break;
- }
+ }
+ printf("%s %s\n", regops[opfun].name,
+ abi_registers_integer_name[rs]);
+ break;
+ case ITYPE_MFROM:
+ printf("%s %s\n", regops[opfun].name,
+ abi_registers_integer_name[rd]);
+ break;
+ case ITYPE_SYS:
+ printf("%s\n", regops[opfun].name);
+ default:
+ printf("special (%#04x) $%d,$%d,$%d\n", opfun, rd, rs, rt);
+ }
+ break;
+
+ case ITYPE_FOP:
+ fs = (c >> 11) & 0x1f; /* 5 bit source register */
+ ft = (c >> 16) & 0x1f; /* 5 bit source/destination register */
+ fd = (c >> 6) & 0x1f; /* 5 bit destination register */
+
+ if (rs == 8) { /* floating point branch */
+#if SIZEOF_VOID_P == 8
+ printf("%s 0x%016lx\n", fbra[ft & 3],
+ (u8) code + 4 + ((c << 16) >> 14));
+#else
+ printf("%s 0x%08x\n", fbra[ft & 3],
+ (u4) code + 4 + ((c << 16) >> 14));
+#endif
+ break;
+ }
- if (rs == 4) { /* move to */
- printf("mtc1 %s,$f%d\n", regs[rt], fs);
- break;
- }
+ if (rs == 0) { /* move from */
+ printf("mfc1 %s,$f%d\n", abi_registers_integer_name[rt], fs);
+ break;
+ }
- if (rs == 5) { /* double move to */
- printf("dmtc1 %s,$f%d\n", regs[rt], fs);
- break;
- }
-
- rs = rs & 7; /* truncate to 3 bit format specifier */
-
- if (fops[opfun].ftype == ITYPE_FOP)
- printf("%s%s%s $f%d,$f%d,$f%d\n", fops[opfun].name, fmt[rs],
- fops[opfun].fill, fd, fs, ft);
- else if (fops[opfun].ftype == ITYPE_FOP2)
- printf("%s%s%s $f%d,$f%d\n", fops[opfun].name, fmt[rs],
- fops[opfun].fill, fd, fs);
- else if (fops[opfun].ftype == ITYPE_FCMP)
- printf("%s%s%s $f%d,$f%d\n", fops[opfun].name, fmt[rs],
- fops[opfun].fill, fs, ft);
- else
- printf("cop1 (%#04x) $f%d,$f%d,$f%d\n", opfun, fd, fs, ft);
+ if (rs == 1) { /* double move from */
+ printf("dmfc1 %s,$f%d\n", abi_registers_integer_name[rt], fs);
+ break;
+ }
+ if (rs == 4) { /* move to */
+ printf("mtc1 %s,$f%d\n", abi_registers_integer_name[rt], fs);
break;
+ }
- default:
- printf("undef %#04x(%#04x) $%d,$%d,$%d\n", op, opfun, rd, rs, rt);
+ if (rs == 5) { /* double move to */
+ printf("dmtc1 %s,$f%d\n", abi_registers_integer_name[rt], fs);
+ break;
}
+
+ rs = rs & 7; /* truncate to 3 bit format specifier */
+
+ if (fops[opfun].ftype == ITYPE_FOP)
+ printf("%s%s%s $f%d,$f%d,$f%d\n", fops[opfun].name, fmt[rs],
+ fops[opfun].fill, fd, fs, ft);
+ else if (fops[opfun].ftype == ITYPE_FOP2)
+ printf("%s%s%s $f%d,$f%d\n", fops[opfun].name, fmt[rs],
+ fops[opfun].fill, fd, fs);
+ else if (fops[opfun].ftype == ITYPE_FCMP)
+ printf("%s%s%s $f%d,$f%d\n", fops[opfun].name, fmt[rs],
+ fops[opfun].fill, fs, ft);
+ else
+ printf("cop1 (%#04x) $f%d,$f%d,$f%d\n", opfun, fd, fs, ft);
+ break;
+
+ default:
+ printf("undef %#04x(%#04x) $%d,$%d,$%d\n", op, opfun, rd, rs, rt);
+ }
+
+ return code + 4;
}
-/* function disassemble ********************************************************
+/* disassemble *****************************************************************
+
+ Outputs a disassembler listing of some machine code on 'stdout'.
- outputs a disassembler listing of some machine code on 'stdout'
- code: pointer to first instruction
- len: code size (number of instructions * 4)
+ start: pointer to first instruction
+ end: pointer to last instruction
*******************************************************************************/
-void disassemble(s4 *code, int len)
+void disassemble(u1 *start, u1 *end)
{
- int p;
-
printf(" --- disassembler listing ---\n");
- for (p = 0; p < len; p += 4, code++)
- disassinstr(code, p);
+ for (; start < end; )
+ start = disassinstr(start);
}