Subversion Repositories planix.SVN

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

#include <u.h>
#include <libc.h>
#include <bio.h>
#include <mach.h>
/*
 * Alpha-specific debugger interface
 */

static  char    *alphaexcep(Map*, Rgetter);
static  int     alphafoll(Map*, uvlong, Rgetter, uvlong*);
static  int     alphainst(Map*, uvlong, char, char*, int);
static  int     alphadas(Map*, uvlong, char*, int);
static  int     alphainstlen(Map*, uvlong);
/*
 *      Debugger interface
 */
Machdata alphamach =
{
        {0x80, 0, 0, 0},                /* break point */
        4,                      /* break point size */

        leswab,                 /* short to local byte order */
        leswal,                 /* long to local byte order */
        leswav,                 /* vlong to local byte order */
        risctrace,              /* C traceback */
        riscframe,              /* Frame finder */
        alphaexcep,             /* print exception */
        0,                      /* breakpoint fixup */
        leieeesftos,            /* single precision float printer */
        leieeedftos,            /* double precisioin float printer */
        alphafoll,              /* following addresses */
        alphainst,              /* print instruction */
        alphadas,               /* dissembler */
        alphainstlen,           /* instruction size */
};

static char *illegaltype[] = {
        "breakpoint",
        "bugchk",
        "gentrap",
        "fen",
        "illegal instruction",
};

static char *
alphaexcep(Map *map, Rgetter rget)
{
        ulong type, a0, a1;
        static char buf[256];

        type = (*rget)(map, "TYPE");
        a0 = (*rget)(map, "A0");
        a1 = (*rget)(map, "A1");
/*      a2 = (*rget)(map, "A2"); */

        switch (type) {
        case 1: /* arith */
                sprint(buf, "trap: arithmetic trap 0x%lux", a0);
                break;
        case 2: /* bad instr or FEN */
                if (a0 <= 4)
                        return illegaltype[a0];
                else
                        sprint(buf, "illegal instr trap, unknown type %lud", a0);
                break;
        case 3: /* intr */
                sprint(buf, "interrupt type %lud", a0);
                break;
        case 4: /* memory fault */
                sprint(buf, "fault %s addr=0x%lux", (a1&1)?"write":"read", a0);
                break;
        case 5: /* syscall() */
                return "system call";
        case 6: /* alignment fault */
                sprint(buf, "unaligned op 0x%lux addr 0x%lux", a1, a0);
                break;
        default:        /* cannot happen */
                sprint(buf, "unknown exception type %lud", type);
                break;
        }
        return buf;
}

        /* alpha disassembler and related functions */

static  char FRAMENAME[] = ".frame";

typedef struct {
        uvlong addr;
        uchar op;                       /* bits 31-26 */
        uchar ra;                       /* bits 25-21 */
        uchar rb;                       /* bits 20-16 */
        uchar rc;                       /* bits 4-0 */
        long mem;                       /* bits 15-0 */
        long branch;                    /* bits 20-0 */
        uchar function;                 /* bits 11-5 */
        uchar literal;                  /* bits 20-13 */
        uchar islit;                    /* bit 12 */
        uchar fpfn;                     /* bits 10-5 */
        uchar fpmode;                   /* bits 15-11 */
        long w0;
        long w1;
        int size;                       /* instruction size */
        char *curr;                     /* fill point in buffer */
        char *end;                      /* end of buffer */
        char *err;                      /* error message */
} Instr;

static Map *mymap;

static int
decode(uvlong pc, Instr *i)
{
        ulong w;

        if (get4(mymap, pc, &w) < 0) {
                werrstr("can't read instruction: %r");
                return -1;
        }
        i->addr = pc;
        i->size = 1;
        i->op = (w >> 26) & 0x3F;
        i->ra = (w >> 21) & 0x1F;
        i->rb = (w >> 16) & 0x1F;
        i->rc = w & 0x1F;
        i->function = (w >> 5) & 0x7F;
        i->mem = w & 0xFFFF;
        if (i->mem & 0x8000)
                i->mem -= 0x10000;
        i->branch = w & 0x1FFFFF;
        if (i->branch & 0x100000)
                i->branch -= 0x200000;
        i->function = (w >> 5) & 0x7F;
        i->literal = (w >> 13) & 0xFF;
        i->islit = (w >> 12) & 0x01;
        i->fpfn = (w >> 5) & 0x3F;
        i->fpmode = (w >> 11) & 0x1F;
        i->w0 = w;
        return 1;
}

static int
mkinstr(uvlong pc, Instr *i)
{
/*      Instr x; */

        if (decode(pc, i) < 0)
                return -1;

#ifdef  frommips
/* we probably want to do something like this for alpha... */
        /*
         * if it's a LUI followed by an ORI,
         * it's an immediate load of a large constant.
         * fix the LUI immediate in any case.
         */
        if (i->op == 0x0F) {
                if (decode(pc+4, &x) < 0)
                        return 0;
                i->immediate <<= 16;
                if (x.op == 0x0D && x.rs == x.rt && x.rt == i->rt) {
                        i->immediate |= (x.immediate & 0xFFFF);
                        i->w1 = x.w0;
                        i->size++;
                        return 1;
                }
        }
#endif
        return 1;
}

#pragma varargck        argpos  bprint          2

static void
bprint(Instr *i, char *fmt, ...)
{
        va_list arg;

        va_start(arg, fmt);
        i->curr = vseprint(i->curr, i->end, fmt, arg);
        va_end(arg);
}

typedef struct Opcode Opcode;

struct Opcode {
        char *mnemonic;
        void (*f)(Opcode *, Instr *);
        char *ken;
};

static void format(char *, Instr *, char *);

static int
plocal(Instr *i, char *m, char r, int store)
{
        int offset;
        char *reg;
        Symbol s;

        if (!findsym(i->addr, CTEXT, &s) || !findlocal(&s, FRAMENAME, &s))
                return 0;
        if (s.value > i->mem) {
                if(!getauto(&s, s.value-i->mem, CAUTO, &s))
                        return 0;
                reg = "(SP)";
                offset = i->mem;
        } else {
                offset = i->mem-s.value-8;
                if (!getauto(&s, offset, CPARAM, &s))
                        return 0;
                reg = "(FP)";
        }
        if (store)
                bprint(i, "%s\t%c%d,%s+%d%s", m, r, i->ra, s.name, offset, reg);
        else
                bprint(i, "%s\t%s+%d%s,%c%d", m, s.name, offset, reg, r, i->ra);
        return 1;
}

static void
_load(Opcode *o, Instr *i, char r)
{
        char *m;

        m = o->mnemonic;
        if (i->rb == 30 && plocal(i, m, r, 0))
                return;
        if (i->rb == 29 && mach->sb) {
                bprint(i, "%s\t", m);
                i->curr += symoff(i->curr, i->end-i->curr, i->mem+mach->sb, CANY);
                bprint(i, "(SB),%c%d", r, i->ra);
                return;
        }
        format(m, i, o->ken);
}

static void
load(Opcode *o, Instr *i)
{
        _load(o, i, 'R');
}

static void
loadf(Opcode *o, Instr *i)
{
        _load(o, i, 'F');
}

static void
_store(Opcode *o, Instr *i, char r)
{
        char *m;

        m = o->mnemonic;
        if (i->rb == 30 && plocal(i, m, r, 1))
                return;
        if (i->rb == 29 && mach->sb) {
                bprint(i, "%s\t%c%d,", m, r, i->ra);
                i->curr += symoff(i->curr, i->end-i->curr, i->mem+mach->sb, CANY);
                bprint(i, "(SB)");
                return;
        }
        format(o->mnemonic, i, o->ken);
}

static void
store(Opcode *o, Instr *i)
{
        _store(o, i, 'R');
}

static void
storef(Opcode *o, Instr *i)
{
        _store(o, i, 'F');
}

static void
misc(Opcode *o, Instr *i)
{
        char *f;

        USED(o);
        switch (i->mem&0xFFFF) {
        case 0x0000:
                f = "TRAPB";
                break;
        case 0x4000:
                f = "MB";
                break;
        case 0x8000:
                f = "FETCH\t0(R%b)";
                break;
        case 0xA000:
                f = "FETCH_M\t0(R%b)";
                break;
        case 0xC000:
                f = "RPCC\tR%a";
                break;
        case 0xE000:
                f = "RC\tR%a";
                break;
        case 0xF000:
                f = "RS\tR%a";
                break;
        default:
                f = "%w";
        }
        format(0, i, f);
}

static char     *jmpcode[4] = { "JMP", "JSR", "RET", "JSR_COROUTINE" };

static void
jmp(Opcode *o, Instr *i)
{
        int hint;
        char *m;

        USED(o);
        hint = (i->mem >> 14) & 3;
        m = jmpcode[hint];
        if (i->ra == 31) {
                if (hint == 2 && i->rb == 29)
                        bprint(i, m);
                else
                        format(m, i, "(R%b)");
        }
        else
                format(m, i, "R%a,(R%b)");
}

static void
br(Opcode *o, Instr *i)
{
        if (i->ra == 31)
                format(o->mnemonic, i, "%B");
        else
                format(o->mnemonic, i, o->ken);
}

static void
bsr(Opcode *o, Instr *i)
{
        if (i->ra == 26)
                format(o->mnemonic, i, "%B");
        else
                format(o->mnemonic, i, o->ken);
}

static void
mult(Opcode *o, Instr *i)
{
        char *m;

        switch (i->function) {
        case 0x00:
                m = "MULL";
                break;
        case 0x20:
                m = "MULQ";
                break;
        case 0x40:
                m = "MULL/V";
                break;
        case 0x60:
                m = "MULQ/V";
                break;
        case 0x30:
                m = "UMULH";
                break;
        default:
                format("???", i, "%w");
                return;
        }
        format(m, i, o->ken);
}

static char     alphaload[] = "%l,R%a";
static char     alphafload[] = "%l,F%a";
static char     alphastore[] = "R%a,%l";
static char     alphafstore[] = "F%a,%l";
static char     alphabranch[] = "R%a,%B";
static char     alphafbranch[] = "F%a,%B";
static char     alphaint[] = "%v,R%a,R%c";
static char     alphafp[] = "F%b,F%a,F%c";
static char     alphafp2[] = "F%b,F%c";
static char     alphaxxx[] = "%w";

static Opcode opcodes[64] = {
        "PAL",          0,      alphaxxx,
        "OPC01",        0,      alphaxxx,
        "OPC02",        0,      alphaxxx,
        "OPC03",        0,      alphaxxx,
        "OPC04",        0,      alphaxxx,
        "OPC05",        0,      alphaxxx,
        "OPC06",        0,      alphaxxx,
        "OPC07",        0,      alphaxxx,
        "MOVQA",        load,   alphaload,
        "MOVQAH",       load,   alphaload,
        "MOVBU",        load,   alphaload,              /* v 3 */
        "MOVQU",        load,   alphaload,
        "MOVWU",        load,   alphaload,              /* v 3 */
        "MOVWU",        store,  alphastore,             /* v 3 */
        "MOVBU",        store,  alphastore,             /* v 3 */
        "MOVQU",        store,  alphastore,
        0,              0,      0,                      /* int arith */
        0,              0,      0,                      /* logical */
        0,              0,      0,                      /* shift */
        0,              mult,   alphaint,
        "OPC14",        0,      alphaxxx,
        "vax",          0,      alphafp,                /* vax */
        0,              0,      0,                      /* ieee */
        0,              0,      0,                      /* fp */
        0,              misc,   alphaxxx,
        "PAL19 [HW_MFPR]",0,    alphaxxx,
        "JSR",          jmp,    0,
        "PAL1B [HW_LD]",0,      alphaxxx,
        "OPC1C",        0,      alphaxxx,
        "PAL1D [HW_MTPR]",0,    alphaxxx,
        "PAL1E [HW_REI]",0,     alphaxxx,
        "PAL1F [HW_ST]",0,      alphaxxx,
        "MOVF",         loadf,  alphafload,
        "MOVG",         loadf,  alphafload,
        "MOVS",         loadf,  alphafload,
        "MOVT",         loadf,  alphafload,
        "MOVF",         storef, alphafstore,
        "MOVG",         storef, alphafstore,
        "MOVS",         storef, alphafstore,
        "MOVT",         storef, alphafstore,
        "MOVL",         load,   alphaload,
        "MOVQ",         load,   alphaload,
        "MOVLL",        load,   alphaload,
        "MOVQL",        load,   alphaload,
        "MOVL",         store,  alphastore,
        "MOVQ",         store,  alphastore,
        "MOVLC",        store,  alphastore,
        "MOVQC",        store,  alphastore,
        "JMP",          br,     alphabranch,
        "FBEQ",         0,      alphafbranch,
        "FBLT",         0,      alphafbranch,
        "FBLE",         0,      alphafbranch,
        "JSR",          bsr,    alphabranch,
        "FBNE",         0,      alphafbranch,
        "FBGE",         0,      alphafbranch,
        "FBGT",         0,      alphafbranch,
        "BLBC",         0,      alphafbranch,
        "BEQ",          0,      alphabranch,
        "BLT",          0,      alphabranch,
        "BLE",          0,      alphabranch,
        "BLBS",         0,      alphabranch,
        "BNE",          0,      alphabranch,
        "BGE",          0,      alphabranch,
        "BGT",          0,      alphabranch,
};

static Opcode fpopcodes[64] = {
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,

        "CVTLQ",        0,      alphafp2,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,

        "CPYS",         0,      alphafp,
        "CPYSN",        0,      alphafp,
        "CPYSE",        0,      alphafp,
        "???",          0,      alphaxxx,
        "MOVT",         0,      "FPCR,F%a",
        "MOVT",         0,      "F%a,FPCR",
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "FCMOVEQ",      0,      alphafp,
        "FCMOVNE",      0,      alphafp,
        "FCMOVLT",      0,      alphafp,
        "FCMOVGE",      0,      alphafp,
        "FCMOVLE",      0,      alphafp,
        "FCMOVGT",      0,      alphafp,

        "CVTQL",        0,      alphafp2,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
};

static Opcode ieeeopcodes[64] = {
        "ADDS",         0,      alphafp,
        "SUBS",         0,      alphafp,
        "MULS",         0,      alphafp,
        "DIVS",         0,      alphafp,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,

        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,

        "ADDT",         0,      alphafp,
        "SUBT",         0,      alphafp,
        "MULT",         0,      alphafp,
        "DIVT",         0,      alphafp,
        "CMPTUN",       0,      alphafp,
        "CMPTEQ",       0,      alphafp,
        "CMPTLT",       0,      alphafp,
        "CMPTLE",       0,      alphafp,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "CVTTS",        0,      alphafp2,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "CVTTQ",        0,      alphafp2,

        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "???",          0,      alphaxxx,
        "CVTQS",        0,      alphafp2,
        "???",          0,      alphaxxx,
        "CVTQT",        0,      alphafp2,
        "???",          0,      alphaxxx,
};

static uchar    amap[128] = {
        [0x00]  1,
        [0x40]  2,
        [0x20]  3,
        [0x60]  4,
        [0x09]  5,
        [0x49]  6,
        [0x29]  7,
        [0x69]  8,
        [0x2D]  9,
        [0x4D]  10,
        [0x6D]  11,
        [0x1D]  12,     
        [0x3D]  13,     
        [0x0F]  14,     
        [0x02]  15,     
        [0x0B]  16,     
        [0x12]  17,     
        [0x1B]  18,
        [0x22]  19,     
        [0x2B]  20,     
        [0x32]  21,     
        [0x3B]  22,
};

static Opcode arithopcodes[64] = {
        "???",          0,      alphaxxx,
        "ADDL",         0,      alphaint,
        "ADDL/V",       0,      alphaint,
        "ADDQ",         0,      alphaint,
        "ADDQ/V",       0,      alphaint,
        "SUBL",         0,      alphaint,
        "SUBL/V",       0,      alphaint,
        "SUBQ",         0,      alphaint,
        "SUBQ/V",       0,      alphaint,
        "CMPEQ",        0,      alphaint,
        "CMPLT",        0,      alphaint,
        "CMPLE",        0,      alphaint,
        "CMPULT",       0,      alphaint,
        "CMPULE",       0,      alphaint,
        "CMPBGE",       0,      alphaint,
        "S4ADDL",       0,      alphaint,
        "S4SUBL",       0,      alphaint,
        "S8ADDL",       0,      alphaint,
        "S8SUBL",       0,      alphaint,
        "S4ADDQ",       0,      alphaint,
        "S4SUBQ",       0,      alphaint,
        "S8ADDQ",       0,      alphaint,
        "S8SUBQ",       0,      alphaint,
};

static uchar    lmap[128] = {
        [0x00]  1,
        [0x20]  2,
        [0x40]  3,
        [0x08]  4,
        [0x28]  5,
        [0x48]  6,
        [0x24]  7,
        [0x44]  8,
        [0x64]  9,
        [0x26]  7,
        [0x46]  8,
        [0x66]  9,
        [0x14]  10,
        [0x16]  11,
};

static Opcode logicalopcodes[64] = {
        "???",          0,      alphaxxx,
        "AND",          0,      alphaint,
        "OR",           0,      alphaint,
        "XOR",          0,      alphaint,
        "ANDNOT",       0,      alphaint,
        "ORNOT",        0,      alphaint,
        "XORNOT",       0,      alphaint,
        "CMOVEQ",       0,      alphaint,
        "CMOVLT",       0,      alphaint,
        "CMOVLE",       0,      alphaint,
        "CMOVNE",       0,      alphaint,
        "CMOVGE",       0,      alphaint,
        "CMOVGT",       0,      alphaint,
        "CMOVLBS",      0,      alphaint,
        "CMOVLBC",      0,      alphaint,
};

static uchar    smap[128] = {
        [0x39]  1,
        [0x3C]  2,
        [0x34]  3,
        [0x06]  4,
        [0x16]  5,
        [0x26]  6,
        [0x36]  7,
        [0x5A]  8,
        [0x6A]  9,
        [0x7A]  10,
        [0x0B]  11,
        [0x1B]  12,
        [0x2B]  13,
        [0x3B]  14,
        [0x57]  15,
        [0x67]  16,
        [0x77]  17,
        [0x02]  18,
        [0x12]  19,
        [0x22]  20,
        [0x32]  21,
        [0x52]  22,
        [0x62]  23,
        [0x72]  24,
        [0x30]  25,
        [0x31]  26,
};

static Opcode shiftopcodes[64] = {
        "???",          0,      alphaxxx,
        "SLLQ",         0,      alphaint,
        "SRAQ",         0,      alphaint,
        "SRLQ",         0,      alphaint,
        "EXTBL",        0,      alphaint,
        "EXTWL",        0,      alphaint,
        "EXTLL",        0,      alphaint,
        "EXTQL",        0,      alphaint,
        "EXTWH",        0,      alphaint,
        "EXTLH",        0,      alphaint,
        "EXTQH",        0,      alphaint,
        "INSBL",        0,      alphaint,
        "INSWL",        0,      alphaint,
        "INSLL",        0,      alphaint,
        "INSQL",        0,      alphaint,
        "INSWH",        0,      alphaint,
        "INSLH",        0,      alphaint,
        "INSQH",        0,      alphaint,
        "MSKBL",        0,      alphaint,
        "MSKWL",        0,      alphaint,
        "MSKLL",        0,      alphaint,
        "MSKQL",        0,      alphaint,
        "MSKWH",        0,      alphaint,
        "MSKLH",        0,      alphaint,
        "MSKQH",        0,      alphaint,
        "ZAP",          0,      alphaint,
        "ZAPNOT",       0,      alphaint,
};

static void
format(char *mnemonic, Instr *i, char *f)
{
        if (mnemonic)
                format(0, i, mnemonic);
        if (f == 0)
                return;
        if (mnemonic)
                if (i->curr < i->end)
                        *i->curr++ = '\t';
        for ( ; *f && i->curr < i->end; f++) {
                if (*f != '%') {
                        *i->curr++ = *f;
                        continue;
                }
                switch (*++f) {

                case 'a':
                        bprint(i, "%d", i->ra);
                        break;

                case 'b':
                        bprint(i, "%d", i->rb);
                        break;

                case 'c':
                        bprint(i, "%d", i->rc);
                        break;

                case 'v':
                        if (i->islit)
                                bprint(i, "$%ux", i->literal);
                        else
                                bprint(i, "R%d", i->rb);
                        break;

                case 'l':
                        bprint(i, "%lx(R%d)", i->mem, i->rb);
                        break;

                case 'i':
                        bprint(i, "$%lx", i->mem);
                        break;

                case 'B':
                        i->curr += symoff(i->curr, i->end-i->curr,
                                (i->branch<<2)+i->addr+4, CANY);
                        break;

                case 'w':
                        bprint(i, "[%lux]", i->w0);
                        break;

                case '\0':
                        *i->curr++ = '%';
                        return;

                default:
                        bprint(i, "%%%c", *f);
                        break;
                }
        }
        *i->curr = 0;
}

static int
printins(Map *map, uvlong pc, char *buf, int n)
{
        Instr i;
        Opcode *o;
        uchar op;

        i.curr = buf;
        i.end = buf+n-1;
        mymap = map;
        if (mkinstr(pc, &i) < 0)
                return -1;
        switch (i.op) {

        case 0x10:                                      /* INTA */
                o = arithopcodes;
                op = amap[i.function];
                break;

        case 0x11:                                      /* INTL */
                o = logicalopcodes;
                op = lmap[i.function];
                break;

        case 0x12:                                      /* INTS */
                o = shiftopcodes;
                op = smap[i.function];
                break;

        case 0x16:                                      /* FLTI */
                o = ieeeopcodes;
                op = i.fpfn;
                break;

        case 0x17:                                      /* FLTL */
                o = fpopcodes;
                op = i.fpfn;
                break;

        default:
                o = opcodes;
                op = i.op;
                break;
        }
        if (o[op].f)
                (*o[op].f)(&o[op], &i);
        else
                format(o[op].mnemonic, &i, o[op].ken);
        return i.size*4;
}

static int
alphainst(Map *map, uvlong pc, char modifier, char *buf, int n)
{
        USED(modifier);
        return printins(map, pc, buf, n);
}

static int
alphadas(Map *map, uvlong pc, char *buf, int n)
{
        Instr i;

        i.curr = buf;
        i.end = buf+n;
        mymap = map;
        if (mkinstr(pc, &i) < 0)
                return -1;
        if (i.end-i.curr > 8)
                i.curr = _hexify(buf, i.w0, 7);
        if (i.size == 2 && i.end-i.curr > 9) {
                *i.curr++ = ' ';
                i.curr = _hexify(i.curr, i.w1, 7);
        }
        *i.curr = 0;
        return i.size*4;
}

static int
alphainstlen(Map *map, uvlong pc)
{
        Instr i;

        mymap = map;
        if (mkinstr(pc, &i) < 0)
                return -1;
        return i.size*4;
}

static int
alphafoll(Map *map, uvlong pc, Rgetter rget, uvlong *foll)
{
        char buf[8];
        Instr i;

        mymap = map;
        if (mkinstr(pc, &i) < 0)
                return -1;

        switch(i.op) {
        case 0x1A:                              /* JMP/JSR/RET */
                sprint(buf, "R%d", i.rb);
                foll[0] = (*rget)(map, buf);
                return 1;
        case 0x30:                              /* BR */
        case 0x34:                              /* BSR */
                foll[0] = pc+4 + (i.branch<<2);
                return 1;
        default:
                if (i.op > 0x30) {              /* cond */
                        foll[0] = pc+4;
                        foll[1] = pc+4 + (i.branch<<2);
                        return 2;
                }
                foll[0] = pc+i.size*4;
                return 1;
        }
}