/* $OpenBSD: db_disasm.c,v 1.8 2006/05/04 19:32:21 miod Exp $ */ /* * Copyright (c) 2006, Miodrag Vallat * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * Mach Operating System * Copyright (c) 1993-1991 Carnegie Mellon University * Copyright (c) 1991 OMRON Corporation * All Rights Reserved. * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. * * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 * * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. */ /* * m88k disassembler for use in ddb */ #include #include #include #include /* DB_STGY_PROC, db_printsym() */ #include /* db_get_value() */ #include /* db_printf() */ #include void oimmed(int, u_int32_t, const char *, vaddr_t); void ctrlregs(int, u_int32_t, const char *, vaddr_t); void sindou(int, u_int32_t, const char *, vaddr_t); void jump(int, u_int32_t, const char *, vaddr_t); void instset(int, u_int32_t, const char *, vaddr_t); void obranch(int, u_int32_t, const char *, vaddr_t); void brcond(int, u_int32_t, const char *, vaddr_t); void otrap(int, u_int32_t, const char *, vaddr_t); void obit(int, u_int32_t, const char *, vaddr_t); void bitman(int, u_int32_t, const char *, vaddr_t); void immem(int, u_int32_t, const char *, vaddr_t); void nimmem(int, u_int32_t, const char *, vaddr_t); void lognim(int, u_int32_t, const char *, vaddr_t); void onimmed(int, u_int32_t, const char *, vaddr_t); void pinst(int, u_int32_t, const char *, vaddr_t); void printcmp(int, u_int); void printcond(u_int); void symofset(u_int, u_int, vaddr_t); const char *cregname(int, u_int, u_int); /* * Common instruction modifiers */ static const char *instwidth[] = { ".d", " ", ".h", ".b", ".x" /* see nimmem() for use of last value */ }; static const char *xinstwidth[4] = { ".d", " ", ".x", ".?" }; static const char *cmpname[] = { NULL, NULL, "eq", "ne", "gt", "le", "lt", "ge", "hi", "ls", "lo", "hs", "be", "nb", "he", "nh" }; static const char *condname[0x1f] = { NULL, "gt", /* 00001 */ "eq", /* 00010 */ "ge", /* 00011 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "lt", /* 01100 */ "ne", /* 01101 */ "le" /* 01110 */ }; static const char sodname[4] = "sdx?"; /* * Descriptive control register names */ static const char *m88100_ctrlreg[2][64] = { { /* main unit */ "PID", "PSR", "EPSR", "SSBR", "SXIP", "SNIP", "SFIP", "VBR", "DMT0", "DMD0", "DMA0", "DMT1", "DMD1", "DMA1", "DMT2", "DMD2", "DMA2", "SR0", "SR1", "SR2", "SR3", }, { /* SFU1 = FPU */ "FPECR", "FPHS1", "FPLS1", "FPHS2", "FPLS2", "FPPT", "FPRH", "FPRL", "FPIT", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "FPSR", "FPCR" } }; static const char *m88110_ctrlreg[2][64] = { { /* main unit */ "PID", "PSR", "EPSR", NULL, "EXIP", "ENIP", NULL, "VBR", NULL, NULL, NULL, NULL, NULL, NULL, "RES1", "RES2", "SRX", "SR0", "SR1", "SR2", "SR3", NULL, NULL, NULL, NULL, "ICMD", "ICTL", "ISAR", "ISAP", "IUAP", "IIR", "IBP", "IPPU", "IPPL", "ISR", "ILAR", "IPAR", NULL, NULL, NULL, "DCMD", "DCTL", "DSAR", "DSAP", "DUAP", "DIR", "DBP", "DPPU", "DPPL", "DSR", "DLAR", "DPAR", }, { /* SFU1 = FPU */ "FPECR", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "FPSR", "FPCR" } }; /* print a comparison code */ /* XXX favors cmp vs fcmp or pcmp */ void printcmp(int cpu, u_int code) { const char *cmp; if (cpu == CPU_88100 && code > 11) cmp = NULL; else cmp = cmpname[code]; if (cmp != NULL) db_printf("%s(%d)", cmp, code); else db_printf("%d", code); } /* print a condition mnemnonic */ void printcond(u_int match) { const char *cond; cond = condname[match]; if (cond != NULL) db_printf("%s0", cond); else db_printf("%d", match); } const char * cregname(int cpu, u_int sfu, u_int regno) { static char regbuf[20]; const char *regname; switch (sfu) { case 0: /* main unit */ case 1: /* SFU1 = FPU */ regname = cpu != CPU_88100 ? m88110_ctrlreg[sfu][regno] : m88100_ctrlreg[sfu][regno]; if (regname == NULL) snprintf(regbuf, sizeof regbuf, sfu == 0 ? "cr%d" : "fcr%d", regno); else snprintf(regbuf, sizeof regbuf, sfu == 0 ? "cr%d (%s)" : "fcr%d (%s)", regno, regname); break; default: /* can't happen */ snprintf(regbuf, sizeof regbuf, "sfu%dcr%d", sfu, regno); break; } return (regbuf); } void symofset(u_int disp, u_int bit, vaddr_t iadr) { vaddr_t addr; if (disp & (1 << (bit - 1))) { /* negative value */ addr = iadr + ((disp << 2) | (~0U << bit)); } else { addr = iadr + (disp << 2); } db_printsym(addr, DB_STGY_PROC, db_printf); } /* Handles immediate integer arithmetic instructions */ void oimmed(int cpu, u_int32_t inst, const char *opcode, vaddr_t iadr) { int32_t Linst = inst & 0xffff; u_int32_t H6inst = inst >> 26; u_int32_t rs1 = (inst >> 16) & 0x1f; u_int32_t rd = (inst >> 21) & 0x1f; switch (H6inst) { case 0x11: /* and.u */ case 0x13: /* mask.u */ case 0x15: /* xor.u */ case 0x17: /* or.u */ db_printf("\t%s.u", opcode); break; default: db_printf("\t%s ", opcode); break; } db_printf("\t\tr%d, r%d, 0x%04x", rd, rs1, Linst); } /* Handles instructions dealing with control registers */ void ctrlregs(int cpu, u_int32_t inst, const char *opcode, vaddr_t iadr) { u_int32_t dir = (inst >> 14) & 0x03; u_int32_t sfu = (inst >> 11) & 0x07; u_int32_t creg = (inst >> 5) & 0x3f; u_int32_t rd = (inst >> 21) & 0x1f; u_int32_t rs1 = (inst >> 16) & 0x1f; db_printf("\t%s\t\t", opcode); switch (dir) { case 0x01: /* ldcr, fldcr */ db_printf("r%d, %s", rd, cregname(cpu, sfu, creg)); break; case 0x02: /* stcr, fstcr */ db_printf("r%d, %s", rs1, cregname(cpu, sfu, creg)); break; default: case 0x03: /* xcr, fxcr */ db_printf("r%d, r%d, %s", rd, rs1, cregname(cpu, sfu, creg)); break; } } /* Handles floating point instructions */ void sindou(int cpu, u_int32_t inst, const char *opcode, vaddr_t iadr) { u_int32_t rs2 = inst & 0x1f; u_int32_t td = (inst >> 5) & 0x03; u_int32_t t2 = (inst >> 7) & 0x03; u_int32_t t1 = (inst >> 9) & 0x03; u_int32_t rs1 = (inst >> 16) & 0x1f; u_int32_t rd = (inst >> 21) & 0x1f; u_int32_t checkbits = (inst >> 11) & 0x0f; u_int32_t rf = (inst >> 15) & 0x01; /* do not display a specific fcmpu.s encoding as non-existing fcmpu.d */ if (checkbits == 0x07) td = 0; /* do not display dot modifiers for mov.x */ if (checkbits == 0x08) { db_printf("\t%s", opcode); } else { db_printf("\t%s.%c", opcode, sodname[td]); } switch (checkbits) { default: case 0x00: /* fmul */ case 0x05: /* fadd */ case 0x06: /* fsub */ case 0x0e: /* fdiv */ db_printf("%c%c\t\t", sodname[t1], sodname[t2]); if (rf != 0) db_printf("x%d,x%d,x%d", rd, rs1, rs2); else db_printf("r%d,r%d,r%d", rd, rs1, rs2); break; case 0x01: /* fcvt */ case 0x0f: /* fsqrt */ db_printf("%c \t\t", sodname[t2]); if (rf != 0) db_printf("x%d, x%d", rd, rs2); else db_printf("r%d, r%d", rd, rs2); break; case 0x04: /* flt */ db_printf("%c \t\t", sodname[t2]); if ((inst & 0x200) != 0) /* does not use the RF bit... */ db_printf("x%d, x%d", rd, rs2); else db_printf("r%d, r%d", rd, rs2); break; case 0x07: /* fcmp, fcmpu */ db_printf("%c%c\t\t", sodname[t1], sodname[t2]); db_printf("r%d, ", rd); if (rf != 0) db_printf("x%d, x%d", rs1, rs2); else db_printf("r%d, r%d", rs1, rs2); break; case 0x08: /* mov */ if (rf != 0 && t1 == 0x01) { /* mov.x, displayed as mov */ db_printf(" \t\t"); db_printf("x%d, x%d", rd, rs2); } else { db_printf(".%c \t\t", sodname[t2]); if (t1 == 0) db_printf("r%d, x%d", rd, rs2); else db_printf("x%d, r%d", rd, rs2); } break; case 0x09: /* int */ case 0x0a: /* nint */ case 0x0b: /* trnc */ db_printf("%c \t\t", sodname[t2]); if (rf != 0) db_printf("r%d, x%d", rd, rs2); else db_printf("r%d, r%d", rd, rs2); break; } } void jump(int cpu, u_int32_t inst, const char *opcode, vaddr_t iadr) { u_int32_t rs2 = inst & 0x1f; db_printf("\t%s", opcode); if ((inst & (1 << 10)) != 0) db_printf(".n"); else db_printf(" "); db_printf("\t\tr%d", rs2); } /* Handles ff1, ff0, tbnd and rte instructions */ void instset(int cpu, u_int32_t inst, const char *opcode, vaddr_t iadr) { u_int32_t rs2 = inst & 0x1f; u_int32_t rs1 = (inst >> 16) & 0x1f; u_int32_t rd = (inst >> 21) & 0x1f; u_int32_t checkbits = (inst >> 10) & 0x3f; u_int32_t H6inst = (inst >> 26) & 0x3f; db_printf("\t%s", opcode); if (H6inst == 0x3e) { /* tbnd with imm16 */ db_printf("\t\tr%d, 0x%04x", rs1, inst & 0xffff); } else { switch (checkbits) { case 0x3a: /* ff1 */ case 0x3b: /* ff0 */ db_printf("\t\tr%d,r%d", rd, rs2); break; case 0x3e: /* tbnd */ db_printf("\t\tr%d,r%d", rs1, rs2); break; case 0x3f: /* rte, illop */ if (rs2 != 0) db_printf("%d", rs2); break; } } } /* Handles unconditionnal branches */ void obranch(int cpu, u_int32_t inst, const char *opcode, vaddr_t iadr) { u_int32_t disp = inst & 0x3ffffff; db_printf("\t%s", opcode); if ((inst & (1 << 26)) != 0) db_printf(".n"); else db_printf(" "); db_printf("\t\t"); symofset(disp, 26, iadr); } /* Handles branch on conditions instructions */ void brcond(int cpu, u_int32_t inst, const char *opcode, vaddr_t iadr) { u_int32_t match = (inst >> 21) & 0x1f; u_int32_t rs = (inst >> 16) & 0x1f; u_int32_t disp = inst & 0xffff; db_printf("\t%s", opcode); if ((inst & (1 << 26)) != 0) db_printf(".n"); else db_printf(" "); db_printf("\t\t"); if (((inst >> 27) & 0x03) == 1) /* bcnd */ printcond(match); else printcmp(cpu, match); db_printf(", r%d, ", rs); symofset(disp, 16, iadr); } /* Handles trap instructions */ void otrap(int cpu, u_int32_t inst, const char *opcode, vaddr_t iadr) { u_int32_t vecno = inst & 0x1ff; u_int32_t match = (inst >> 21) & 0x1f; u_int32_t rs = (inst >> 16) & 0x1f; db_printf("\t%s\t", opcode); if (((inst >> 12) & 0x0f) == 0xe) /* tcnd */ printcond(match); else printcmp(cpu, match); db_printf(", r%d, 0x%x", rs, vecno); } /* Handles 10 bit immediate bit field operations */ void obit(int cpu, u_int32_t inst, const char *opcode, vaddr_t iadr) { u_int32_t rs = (inst >> 16) & 0x1f; u_int32_t rd = (inst >> 21) & 0x1f; u_int32_t width = (inst >> 5) & 0x1f; u_int32_t offset = inst & 0x1f; db_printf("\t%s\t\tr%d, r%d, ", opcode, rd, rs); if (((inst >> 10) & 0x3f) != 0x2a) /* rot */ db_printf("%d", width); db_printf("<%d>", offset); } /* Handles triadic mode bit field instructions */ void bitman(int cpu, u_int32_t inst, const char *opcode, vaddr_t iadr) { u_int32_t rs1 = (inst >> 16) & 0x1f; u_int32_t rd = (inst >> 21) & 0x1f; u_int32_t rs2 = inst & 0x1f; db_printf("\t%s\t\tr%d, r%d, r%d", opcode, rd, rs1, rs2); } /* Handles immediate load/store/exchange instructions */ void immem(int cpu, u_int32_t inst, const char *opcode, vaddr_t iadr) { u_int32_t rd = (inst >> 21) & 0x1f; u_int32_t rs = (inst >> 16) & 0x1f; u_int32_t st_lda = (inst >> 28) & 0x03; u_int32_t aryno = (inst >> 26) & 0x03; int rf = 0; char c = ' '; switch (st_lda) { case 0x00: if ((aryno & 0x02) != 0) { /* 0x02, 0x03: ld.hu, ld.bu */ opcode = "ld"; c = 'u'; } else { if (cpu == CPU_88100) { opcode = "xmem"; if (aryno == 0) { /* xmem.bu */ aryno = 3; c = 'u'; } } else { /* opcode = "ld"; */ rf = 1; } } break; case 0x03: if (cpu != CPU_88100) { rf = 1; switch (st_lda) { case 0x00: /* ld.x */ aryno = 2; break; case 0x03: /* st, st.d, st.x */ break; } } break; } db_printf("\t%s%s%c\t\t", opcode, rf != 0 ? xinstwidth[aryno] : instwidth[aryno], c); if (rf != 0) db_printf("x%d, r%d, ", rd, rs); else db_printf("r%d, r%d, ", rd, rs); db_printf("0x%x", inst & 0xffff); } /* Handles triadic mode load/store/exchange instructions */ void nimmem(int cpu, u_int32_t inst, const char *opcode, vaddr_t iadr) { u_int32_t scaled = (inst >> 9) & 0x01; u_int32_t rd = (inst >> 21) & 0x1f; u_int32_t rs1 = (inst >> 16) & 0x1f; u_int32_t rs2 = inst & 0x1f; u_int32_t st_lda = (inst >> 12) & 0x03; u_int32_t aryno = (inst >> 10) & 0x03; char c = ' '; int rf = 0, wt = 0, usr = 0; switch (st_lda) { case 0x00: switch (aryno) { case 0x00: /* xmem.bu */ aryno = 3; c = 'u'; /* FALLTHROUGH */ case 0x01: /* xmem */ opcode = "xmem"; break; default: case 0x02: /* ld.hu */ case 0x03: /* ld.bu */ opcode = "ld"; c = 'u'; break; } break; case 0x01: opcode = "ld"; if (cpu != CPU_88100) { if ((inst & (1 << 26)) == 0) rf = 1; } break; case 0x02: /* st */ if (cpu != CPU_88100) { if ((inst & (1 << 26)) == 0) rf = 1; if ((inst & (1 << 7)) != 0) wt = 1; } break; case 0x03: if (cpu != CPU_88100) { /* cheat instwidth for lda.x */ if (aryno == 3) aryno = 4; } break; } if (st_lda != 0x03 && (inst & (1 << 8)) != 0) usr = 1; db_printf("\t%s%s%c%s%s\t", opcode, rf != 0 ? xinstwidth[aryno] : instwidth[aryno], c, usr != 0 ? ".usr" : " ", wt != 0 ? ".wt" : " "); if (rf != 0) db_printf("x%d, r%d", rd, rs1); else db_printf("r%d, r%d", rd, rs1); if (scaled != 0) db_printf("[r%d]", rs2); else db_printf(", r%d", rs2); } /* Handles triadic mode logical instructions */ void lognim(int cpu, u_int32_t inst, const char *opcode, vaddr_t iadr) { u_int32_t rd = (inst >> 21) & 0x1f; u_int32_t rs1 = (inst >> 16) & 0x1f; u_int32_t rs2 = inst & 0x1f; db_printf("\t%s", opcode); if ((inst & (1 << 10)) != 0) db_printf(".c"); db_printf("\t\tr%d, r%d, r%d", rd, rs1, rs2); } /* Handles triadic mode arithmetic instructions */ void onimmed(int cpu, u_int32_t inst, const char *opcode, vaddr_t iadr) { u_int32_t rd = (inst >> 21) & 0x1f; u_int32_t rs1 = (inst >> 16) & 0x1f; u_int32_t rs2 = inst & 0x1f; u_int32_t carry = (inst >> 8) & 0x03; db_printf("\t%s", opcode); if ((inst & (1 << 11)) == 0) { switch (carry) { case 0x01: db_printf(".co"); break; case 0x02: db_printf(".ci"); break; case 0x03: db_printf(".cio"); break; } } else { if (cpu != CPU_88100 && carry == 0x01) db_printf(".d"); } db_printf("\tr%d, r%d, r%d", rd, rs1, rs2); } /* Handles 88110 SFU2 instructions */ void pinst(int cpu, u_int32_t inst, const char *opcode, vaddr_t iadr) { u_int32_t rd = (inst >> 21) & 0x1f; u_int32_t rs1 = (inst >> 16) & 0x1f; u_int32_t rs2 = inst & 0x1f; u_int32_t tfield = (inst >> 5) & 0x03; u_int32_t pfunc = (inst >> 11) & 0x1f; const char *saturation[] = { NULL, ".u", ".us", ".s" }; db_printf("\t%s", opcode); switch (pfunc) { case 0x0c: /* ppack */ db_printf(".%d", (inst >> 5) & 0x3c); break; case 0x0e: /* prot */ break; default: /* other instructions have an S field or zero */ { u_int32_t sfield = (inst >> 7) & 0x03; if (sfield != 0) db_printf("%s", saturation[sfield]); } break; } if (tfield != 0 || pfunc == 0x0d /* punpk */) { if (tfield != 3) db_printf(".%c", "nbh"[tfield]); } switch (pfunc) { case 0x0d: /* punpk */ db_printf("\tr%d, r%d", rd, rs1); break; case 0x0e: /* prot with immediate */ db_printf("\tr%d, r%d, %d", rd, rs1, (inst >> 5) & 0x3f); break; default: db_printf("\tr%d, r%d, r%d", rd, rs1, rs2); break; } } static const struct opdesc { u_int32_t mask, match; void (*opfun)(int, u_int32_t, const char *, vaddr_t); const char *opcode; } opdecode_88100[] = { /* ORDER IS IMPORTANT BELOW */ { 0xf0000000, 0x00000000, immem, NULL }, /* xmem/ld */ { 0xf0000000, 0x10000000, immem, "ld" }, { 0xf0000000, 0x20000000, immem, "st" }, { 0xf0000000, 0x30000000, immem, "lda" }, { 0xf8000000, 0x40000000, oimmed, "and" }, { 0xf8000000, 0x48000000, oimmed, "mask" }, { 0xf8000000, 0x50000000, oimmed, "xor" }, { 0xf8000000, 0x58000000, oimmed, "or" }, { 0xfc000000, 0x60000000, oimmed, "addu" }, { 0xfc000000, 0x64000000, oimmed, "subu" }, { 0xfc000000, 0x68000000, oimmed, "divu" }, { 0xfc000000, 0x6c000000, oimmed, "mul" }, { 0xfc000000, 0x70000000, oimmed, "add" }, { 0xfc000000, 0x74000000, oimmed, "sub" }, { 0xfc000000, 0x78000000, oimmed, "div" }, { 0xfc000000, 0x7c000000, oimmed, "cmp" }, { 0xfc00f800, 0x80004000, ctrlregs, "ldcr" }, { 0xfc00f800, 0x80004800, ctrlregs, "fldcr" }, { 0xfc00f800, 0x80008000, ctrlregs, "stcr" }, { 0xfc00f800, 0x80008800, ctrlregs, "fstcr" }, { 0xfc00f800, 0x8000c000, ctrlregs, "xcr" }, { 0xfc00f800, 0x8000c800, ctrlregs, "fxcr" }, { 0xfc00f800, 0x84000000, sindou, "fmul" }, { 0xfc1fff80, 0x84002000, sindou, "flt" }, { 0xfc00f800, 0x84002800, sindou, "fadd" }, { 0xfc00f800, 0x84003000, sindou, "fsub" }, { 0xfc00f860, 0x84003800, sindou, "fcmp" }, { 0xfc1ffe60, 0x84004800, sindou, "int" }, { 0xfc1ffe60, 0x84005000, sindou, "nint" }, { 0xfc1ffe60, 0x84005800, sindou, "trnc" }, { 0xfc00f800, 0x84007000, sindou, "fdiv" }, { 0xf8000000, 0xc0000000, obranch, "br" }, { 0xf8000000, 0xc8000000, obranch, "bsr" }, { 0xf8000000, 0xd0000000, brcond, "bb0" }, { 0xf8000000, 0xd8000000, brcond, "bb1" }, { 0xf8000000, 0xe8000000, brcond, "bcnd" }, { 0xfc00fc00, 0xf0008000, obit, "clr" }, { 0xfc00fc00, 0xf0008800, obit, "set" }, { 0xfc00fc00, 0xf0009000, obit, "ext" }, { 0xfc00fc00, 0xf0009800, obit, "extu" }, { 0xfc00fc00, 0xf000a000, obit, "mak" }, { 0xfc00fc00, 0xf000a800, obit, "rot" }, { 0xfc00fe00, 0xf000d000, otrap, "tb0" }, { 0xfc00fe00, 0xf000d800, otrap, "tb1" }, { 0xfc00fe00, 0xf000e800, otrap, "tcnd" }, { 0xfc00f0e0, 0xf4000000, nimmem, NULL }, /* xmem/ld */ { 0xfc00f0e0, 0xf4001000, nimmem, "ld" }, { 0xfc00f0e0, 0xf4002000, nimmem, "st" }, { 0xfc00f0e0, 0xf4003000, nimmem, "lda" }, { 0xfc00fbe0, 0xf4004000, lognim, "and" }, { 0xfc00fbe0, 0xf4005000, lognim, "xor" }, { 0xfc00fbe0, 0xf4005800, lognim, "or" }, { 0xfc00fce0, 0xf4006000, onimmed, "addu" }, { 0xfc00fce0, 0xf4006400, onimmed, "subu" }, { 0xfc00fce0, 0xf4006800, onimmed, "divu" }, { 0xfc00fce0, 0xf4006c00, onimmed, "mul" }, { 0xfc00fce0, 0xf4007000, onimmed, "add" }, { 0xfc00fce0, 0xf4007400, onimmed, "sub" }, { 0xfc00fce0, 0xf4007800, onimmed, "div" }, { 0xfc00fce0, 0xf4007c00, onimmed, "cmp" }, { 0xfc00ffe0, 0xf4008000, bitman, "clr" }, { 0xfc00ffe0, 0xf4008800, bitman, "set" }, { 0xfc00ffe0, 0xf4009000, bitman, "ext" }, { 0xfc00ffe0, 0xf4009800, bitman, "extu" }, { 0xfc00ffe0, 0xf400a000, bitman, "mak" }, { 0xfc00ffe0, 0xf400a800, bitman, "rot" }, { 0xfc00fbe0, 0xf400c000, jump, "jmp" }, { 0xfc00fbe0, 0xf400c800, jump, "jsr" }, { 0xfc00ffe0, 0xf400e800, instset, "ff1" }, { 0xfc00ffe0, 0xf400ec00, instset, "ff0" }, { 0xfc00ffe0, 0xf400f800, instset, "tbnd" }, { 0xfc00ffe0, 0xf400fc00, instset, "rte" }, { 0xfc000000, 0xf8000000, instset, "tbnd" }, { 0, 0, NULL, NULL } }, opdecode_88110[] = { /* ORDER IS IMPORTANT BELOW */ { 0xe0000000, 0x00000000, immem, "ld" }, { 0xf0000000, 0x20000000, immem, "st" }, { 0xfc000000, 0x3c000000, immem, "ld" }, { 0xf0000000, 0x30000000, immem, "st" }, { 0xf8000000, 0x40000000, oimmed, "and" }, { 0xf8000000, 0x48000000, oimmed, "mask" }, { 0xf8000000, 0x50000000, oimmed, "xor" }, { 0xf8000000, 0x58000000, oimmed, "or" }, { 0xfc000000, 0x60000000, oimmed, "addu" }, { 0xfc000000, 0x64000000, oimmed, "subu" }, { 0xfc000000, 0x68000000, oimmed, "divu" }, { 0xfc000000, 0x6c000000, oimmed, "mulu" }, { 0xfc000000, 0x70000000, oimmed, "add" }, { 0xfc000000, 0x74000000, oimmed, "sub" }, { 0xfc000000, 0x78000000, oimmed, "divs" }, { 0xfc000000, 0x7c000000, oimmed, "cmp" }, { 0xfc1ff81f, 0x80004000, ctrlregs, "ldcr" }, { 0xfc1ff81f, 0x80004800, ctrlregs, "fldcr" }, { 0xffe0f800, 0x80008000, ctrlregs, "stcr" }, { 0xffe0f800, 0x80008800, ctrlregs, "fstcr" }, { 0xfc00f800, 0x8000c000, ctrlregs, "xcr" }, { 0xfc00f800, 0x8000c800, ctrlregs, "fxcr" }, { 0xfc007800, 0x84000000, sindou, "fmul" }, { 0xfc1f7e00, 0x84000800, sindou, "fcvt" }, { 0xfc1ffd80, 0x84002000, sindou, "flt" }, { 0xfc007800, 0x84002800, sindou, "fadd" }, { 0xfc007800, 0x84003000, sindou, "fsub" }, { 0xfc007860, 0x84003800, sindou, "fcmp" }, { 0xfc007860, 0x84003820, sindou, "fcmpu" }, { 0xfc1ffe60, 0x8400c000, sindou, "mov" }, { 0xfc17fe60, 0x84004200, sindou, "mov" }, { 0xfc1f7e60, 0x84004800, sindou, "int" }, { 0xfc1f7e60, 0x84005000, sindou, "nint" }, { 0xfc1f7e60, 0x84005800, sindou, "trnc" }, { 0xfc007800, 0x84007000, sindou, "fdiv" }, { 0xfc1f7e00, 0x84007800, sindou, "fsqrt" }, { 0xfc00ffe0, 0x88000000, pinst, "pmul" }, { 0xfc00ff80, 0x88002000, pinst, "padd" }, { 0xfc00fe00, 0x88002000, pinst, "padds" }, { 0xfc00ff80, 0x88003000, pinst, "psub" }, { 0xfc00fe00, 0x88003000, pinst, "psubs" }, { 0xfc00ffe0, 0x88003860, pinst, "pcmp" }, { 0xfc00f800, 0x88006000, pinst, "ppack" }, { 0xfc00ff9f, 0x88006800, pinst, "punpk" }, { 0xfc00f87f, 0x88007000, pinst, "prot" }, { 0xfc00ffe0, 0x88007800, pinst, "prot" }, { 0xf8000000, 0xc0000000, obranch, "br" }, { 0xf8000000, 0xc8000000, obranch, "bsr" }, { 0xf8000000, 0xd0000000, brcond, "bb0" }, { 0xf8000000, 0xd8000000, brcond, "bb1" }, { 0xf8000000, 0xe8000000, brcond, "bcnd" }, { 0xfc00fc00, 0xf0008000, obit, "clr" }, { 0xfc00fc00, 0xf0008800, obit, "set" }, { 0xfc00fc00, 0xf0009000, obit, "ext" }, { 0xfc00fc00, 0xf0009800, obit, "extu" }, { 0xfc00fc00, 0xf000a000, obit, "mak" }, { 0xfc00ffe0, 0xf000a800, obit, "rot" }, { 0xfc00fe00, 0xf000d000, otrap, "tb0" }, { 0xfc00fe00, 0xf000d800, otrap, "tb1" }, { 0xfc00fe00, 0xf000e800, otrap, "tcnd" }, { 0xfc00f0e0, 0xf4000000, nimmem, NULL }, /* ld/xmem */ { 0xf800f0e0, 0xf0001000, nimmem, "ld" }, { 0xf800f060, 0xf0002000, nimmem, "st" }, { 0xfc00f2e0, 0xf4003200, nimmem, "lda" }, { 0xfc00fbe0, 0xf4004000, lognim, "and" }, { 0xfc00fbe0, 0xf4005000, lognim, "xor" }, { 0xfc00fbe0, 0xf4005800, lognim, "or" }, { 0xfc00fce0, 0xf4006000, onimmed, "addu" }, { 0xfc00fce0, 0xf4006400, onimmed, "subu" }, { 0xfc00fee0, 0xf4006800, onimmed, "divu" }, { 0xfc00fee0, 0xf4006c00, onimmed, "mulu" }, { 0xfc00ffe0, 0xf4006e00, onimmed, "muls" }, { 0xfc00fce0, 0xf4007000, onimmed, "add" }, { 0xfc00fce0, 0xf4007400, onimmed, "sub" }, { 0xfc00ffe0, 0xf4007800, onimmed, "divs" }, { 0xfc00ffe0, 0xf4007c00, onimmed, "cmp" }, { 0xfc00ffe0, 0xf4008000, bitman, "clr" }, { 0xfc00ffe0, 0xf4008800, bitman, "set" }, { 0xfc00ffe0, 0xf4009000, bitman, "ext" }, { 0xfc00ffe0, 0xf4009800, bitman, "extu" }, { 0xfc00ffe0, 0xf400a000, bitman, "mak" }, { 0xfc00ffe0, 0xf400a800, bitman, "rot" }, { 0xfffffbe0, 0xf400c000, jump, "jmp" }, { 0xfffffbe0, 0xf400c800, jump, "jsr" }, { 0xfc1fffe0, 0xf400e800, instset, "ff1" }, { 0xfc1fffe0, 0xf400ec00, instset, "ff0" }, { 0xffe0ffe0, 0xf400f800, instset, "tbnd" }, { 0xffffffff, 0xf400fc00, instset, "rte" }, { 0xfffffffc, 0xf400fc00, instset, "illop" }, { 0xffe00000, 0xf8000000, instset, "tbnd" }, { 0, 0, NULL, NULL } }; void m88k_print_instruction(int cpu, u_int iadr, u_int32_t inst) { const struct opdesc *p; /* * This messes up "or.b" instructions ever so slightly, * but keeps us in sync between routines... */ if (inst == 0) { db_printf("\t.word\t0\n"); } else { p = cpu != CPU_88100 ? opdecode_88110 : opdecode_88100; while (p->mask != 0) { if ((inst & p->mask) == p->match) { (*p->opfun)(cpu, inst, p->opcode, iadr); db_printf("\n"); return; } p++; } db_printf("\t.word\t0x%x\n", inst); } } db_addr_t db_disasm(db_addr_t loc, boolean_t altfmt) { int cpu; if (altfmt) cpu = CPU_IS88100 ? CPU_88110 : CPU_88100; else cpu = cputyp; m88k_print_instruction(cpu, loc, db_get_value(loc, 4, FALSE)); return (loc + 4); }