1*47821Sbostic /*-
2*47821Sbostic * Copyright (c) 1991 The Regents of the University of California.
3*47821Sbostic * All rights reserved.
4*47821Sbostic *
5*47821Sbostic * %sccs.include.proprietary.c%
6*47821Sbostic */
7*47821Sbostic
88912Srrh #ifndef lint
9*47821Sbostic static char sccsid[] = "@(#)opset.c 4.9 (Berkeley) 04/04/91";
10*47821Sbostic #endif /* not lint */
1136564Sbostic
123760Sroot /*
1336564Sbostic * adb - instruction printing routines: VAX version
143760Sroot */
153760Sroot
163760Sroot #include "defs.h"
173760Sroot
1836564Sbostic /*
1936564Sbostic * Get assembler definitions; declare tables that appear in optab.c.
2036564Sbostic */
2136564Sbostic #define ADB
228912Srrh #undef INSTTAB
238912Srrh #include "instrs.h"
243760Sroot
2536564Sbostic extern struct insttab insttab[];
2636564Sbostic extern char *regname[];
2736564Sbostic extern char *fltimm[];
2836564Sbostic
2936564Sbostic /* these are shared with the assembler: */
3036564Sbostic extern int ty_NORELOC[];
3136564Sbostic extern int ty_nbyte[];
3236564Sbostic #ifdef notyet
3336564Sbostic extern int ty_float[]; /* must update assizetab.c */
3436564Sbostic #endif
3536564Sbostic
363760Sroot /*
3736564Sbostic * Definitions for registers and for operand classes.
383760Sroot */
398912Srrh #define R_PC 0xF
408912Srrh
4136564Sbostic #define OC_IMM0 0x0 /* literal, aka immediate */
428912Srrh #define OC_IMM1 0x1
438912Srrh #define OC_IMM2 0x2
448912Srrh #define OC_IMM3 0x3
4536564Sbostic #define OC_INDEX 0x4 /* [rN] */
4636564Sbostic #define OC_REG 0x5 /* rN */
4736564Sbostic #define OC_DREG 0x6 /* (rN) */
4836564Sbostic #define OC_ADREG 0x7 /* -(rN) */
4936564Sbostic #define OC_AIREG 0x8 /* (rN)+ */
5036564Sbostic #define OC_DAIREG 0x9 /* *(rN)+ */
5136564Sbostic #define OC_BDISP 0xA /* b(rN) */
5236564Sbostic #define OC_DBDISP 0xB /* *b(rN) */
5336564Sbostic #define OC_WDISP 0xC /* w(rN) */
5436564Sbostic #define OC_DWDISP 0xD /* *w(rN) */
5536564Sbostic #define OC_LDISP 0xE /* l(rN) */
5636564Sbostic #define OC_DLDISP 0xF /* *l(rN) */
578912Srrh
588912Srrh #define OC_SHIFT 4
598912Srrh #define OC_CONS(oc,reg) (((oc & 0xF) << OC_SHIFT) | (reg & 0xF))
608912Srrh #define OC_AMEXT(x) (((x) >> OC_SHIFT) & 0xF)
618912Srrh #define OC_REGEXT(x) ((x) & 0xF)
628912Srrh
633760Sroot /*
6436564Sbostic * Definitions for special instructions.
653760Sroot */
668912Srrh #define CASEB 0x8F
678912Srrh #define CASEW 0xAF
688912Srrh #define CASEL 0xCF
6936564Sbostic #define CHMK 0xBC
7036564Sbostic
718912Srrh /*
7236564Sbostic * ioptab is a two level 1-based index by opcode into insttab.
7336564Sbostic * The first level into ioptab is given by mapescbyte().
7436564Sbostic * Since ioptab is 1-based, references would be expected to
7536564Sbostic * be of the form
7636564Sbostic *
7736564Sbostic * ptr = &insttab[ioptab[a][b] - 1];
7836564Sbostic *
7936564Sbostic * but the form
8036564Sbostic *
8136564Sbostic * ptr = &(insttab - 1)[ioptab[a][b]]
8236564Sbostic *
8336564Sbostic * is equivalent and generates less code (!) (time to work on the
8436564Sbostic * compiler again...).
858912Srrh */
8636564Sbostic static short ioptab[3][256];
8736564Sbostic #define mapescbyte(b) ((b) == ESCD ? 1 : (b) == ESCF ? 2 : 0)
883760Sroot
mkioptab()898912Srrh mkioptab()
908912Srrh {
9136564Sbostic register struct insttab *p;
9236564Sbostic register int mapchar;
9336564Sbostic register short *iop;
943760Sroot
9536564Sbostic /*
9636564Sbostic * The idea here is that whenever two opcodes have the same
9736564Sbostic * codes, but different mnemonics, we want to prefer the one
9836564Sbostic * with the `simpler' type. Here lower numbers make simpler
9936564Sbostic * types. This seems (likely) to work reasonably well.
10036564Sbostic *
10136564Sbostic * At present, this affects the following opcodes:
10236564Sbostic *
10336564Sbostic * 7c clrq | clrd | clrg
10436564Sbostic * 7e movaq | movad | movag
10536564Sbostic * 7f pushaq | pushad | pushag
10636564Sbostic * d4 clrl | clrf
10736564Sbostic * de moval | movaf
10836564Sbostic * df pushal | pushaf
10936564Sbostic *
11036564Sbostic * In each case, the leftmost mnemonics are preferred.
11136564Sbostic */
11236564Sbostic #define PREFER(a, b) (A_TYPEXT((a)->argtype[0]) < A_TYPEXT((b)->argtype[0]))
11336564Sbostic
11436564Sbostic for (p = insttab; p->iname != NULL; p++) {
1158912Srrh mapchar = mapescbyte(p->eopcode);
11636564Sbostic iop = &ioptab[mapchar][p->popcode];
11736564Sbostic if (*iop == 0 || PREFER(p, &(insttab - 1)[*iop]))
11836564Sbostic *iop = p - (insttab - 1);
1193760Sroot }
12036564Sbostic #undef PREFER
1213760Sroot }
1223760Sroot
1238912Srrh /*
12436564Sbostic * Global variables for communication between the minions and printins.
1258912Srrh */
12636564Sbostic static int idsp; /* which space we are in (INSTR or DATA) */
12736564Sbostic static int argno; /* which argument we are working on */
12836564Sbostic static int dotoff; /* offset from dot for this arg */
12936564Sbostic static int vset[7]; /* set by savevar, cleared by clrvar */
1303760Sroot
13136564Sbostic #define savevar(v) (vset[argno] = 1, var[argno] = v)
13236564Sbostic #define clrvar(v) (vset[argno] = 0, var[argno] = 0x80000000)
13336564Sbostic
13436564Sbostic /*
13536564Sbostic * Read some bytes, checking for errors, and updating the offset.
13636564Sbostic */
13736564Sbostic #define getsomebytes(ptr, nbytes) \
13836564Sbostic (void) adbread(idsp, inkdot(dotoff), ptr, nbytes); \
13936564Sbostic checkerr(); \
14036564Sbostic dotoff += (nbytes)
14136564Sbostic
14236564Sbostic /*
14336564Sbostic * Read one byte, and advance the offset.
14436564Sbostic */
14536564Sbostic static int
getbyte()14636564Sbostic getbyte()
1478912Srrh {
14836564Sbostic u_char c;
14936564Sbostic
15036564Sbostic getsomebytes(&c, sizeof(c));
15136564Sbostic return (c);
1528912Srrh }
1538912Srrh
15436564Sbostic /*
15536564Sbostic * adb's view: printins() prints one instruction, and sets dotinc.
15636564Sbostic */
printins(space)15736564Sbostic printins(space)
15836564Sbostic int space;
1593760Sroot {
16036564Sbostic register u_char *ap;
16136564Sbostic register struct insttab *ip;
16236564Sbostic int ins, mode, optype, mapchar, t;
16336564Sbostic char *lastix, *ixreg;
16436564Sbostic char *operandout();
1653760Sroot
16636564Sbostic /*
16736564Sbostic * Set up the module variables, pick up the instruction, and
16836564Sbostic * find its table entry.
16936564Sbostic */
17036564Sbostic idsp = space;
17136564Sbostic dotoff = 0;
17236564Sbostic ins = idsp == SP_NONE ? (u_char)dot : getbyte();
17336564Sbostic if ((mapchar = mapescbyte(ins)) != 0) {
17436564Sbostic t = getbyte();
17536564Sbostic if (ioptab[mapchar][t] == 0) {
1768912Srrh /*
17736564Sbostic * Oops; not a defined instruction; back over this
17836564Sbostic * escape byte.
1798912Srrh */
18036564Sbostic dotoff--;
1818912Srrh mapchar = 0;
18236564Sbostic } else
18336564Sbostic ins = t;
1848912Srrh }
18536564Sbostic if ((t = ioptab[mapchar][ins]) == 0) {
18636564Sbostic adbprintf("<undefined operator byte>: %x", ins);
18736564Sbostic dotinc = 1;
18836564Sbostic return;
1898912Srrh }
19036564Sbostic ip = &(insttab - 1)[t];
19136564Sbostic adbprintf("%s%8t", ip->iname);
1928912Srrh
19336564Sbostic /*
19436564Sbostic * For each argument, decode that argument.
19536564Sbostic * We set t if we notice something fishy.
19636564Sbostic */
19736564Sbostic t = 0;
19836564Sbostic for (ap = ip->argtype, argno = 0; argno < ip->nargs; argno++) {
19936564Sbostic optype = *ap++;
20036564Sbostic clrvar();
2018912Srrh if (argno != 0)
2028912Srrh printc(',');
20336564Sbostic /*
20436564Sbostic * lastix and ixreg track the register indexed addressing
20536564Sbostic * mode, which is written as <stuff>[reg] but encoded as
20636564Sbostic * [reg]<stuff>. Only one [reg] is legal.
20736564Sbostic */
20836564Sbostic lastix = NULL;
20936564Sbostic do {
21036564Sbostic /* check for special pc-relative (branch) */
21136564Sbostic if (A_ACCEXT(optype) & ACCB) {
21236564Sbostic switch (A_TYPEXT(optype)) {
2138912Srrh case TYPB:
2148912Srrh mode = OC_CONS(OC_BDISP, R_PC);
2153760Sroot break;
2168912Srrh case TYPW:
2178912Srrh mode = OC_CONS(OC_WDISP, R_PC);
2183760Sroot break;
2198912Srrh }
22036564Sbostic } else
22136564Sbostic mode = getbyte();
22236564Sbostic ixreg = operandout(mode, optype, ins == CHMK);
22336564Sbostic if (lastix) {
22436564Sbostic adbprintf("[%s]", lastix);
22536564Sbostic if (ixreg)
22636564Sbostic t = 1;
2278912Srrh }
22836564Sbostic } while ((lastix = ixreg) != NULL);
2293760Sroot }
23036564Sbostic if (t)
23136564Sbostic adbprintf("%4t# not code? illegal arguments detected ");
23236564Sbostic switch (ins) {
23336564Sbostic case CASEB:
23436564Sbostic case CASEW:
23536564Sbostic case CASEL:
23636564Sbostic if (mapchar == 0 && vset[1] && vset[2])
23736564Sbostic casebody(var[1], var[2]);
23836564Sbostic else
23936564Sbostic adbprintf("\n%4t# not code? non-constant cases ");
2403760Sroot }
24136564Sbostic dotinc = dotoff;
2423760Sroot }
2433760Sroot
24436564Sbostic /*
24536564Sbostic * Print out the locations to which each of the cases branch.
24636564Sbostic * This routine carefully allows expressions such as
24736564Sbostic *
24836564Sbostic * casel <val>,$<const>,$0x7fffffff
24936564Sbostic *
25036564Sbostic * even though they do not fit on a VAX.
25136564Sbostic */
25236564Sbostic static
casebody(base,limit)2538912Srrh casebody(base, limit)
25436564Sbostic register expr_t base, limit;
2558912Srrh {
25636564Sbostic register expr_t i = -1;
25736564Sbostic register addr_t a, baseaddr = inkdot(dotoff);
25836564Sbostic short displ;
25936564Sbostic
2608912Srrh argno = 0;
26136564Sbostic do {
26236564Sbostic i++;
26336564Sbostic adbprintf("\n %R: ", base++);
26436564Sbostic getsomebytes(&displ, sizeof(displ));
26536564Sbostic a = displ + baseaddr;
26636564Sbostic psymoff("%R", a, SP_DATA, maxoff, "");
26736564Sbostic savevar(a);
26836564Sbostic } while (i != limit);
2698912Srrh }
2708912Srrh
2713760Sroot /*
27236564Sbostic * Handle a normal operand. Return pointer to register
27336564Sbostic * name if this is an index instruction, else return NULL.
2743760Sroot */
27536564Sbostic static char *
operandout(mode,optype,ischmk)27636564Sbostic operandout(mode, optype, ischmk)
27736564Sbostic register int mode;
27836564Sbostic int optype, ischmk;
2798912Srrh {
28036564Sbostic register char *r;
28136564Sbostic register int regnumber, nbytes, n;
28236564Sbostic union {
28336564Sbostic char b;
28436564Sbostic short w;
28536564Sbostic int l;
28636564Sbostic } displ;
28736564Sbostic extern char *syscalls[];
28836564Sbostic extern int nsys;
2893760Sroot
29036564Sbostic regnumber = OC_REGEXT(mode);
29136564Sbostic r = regname[regnumber];
29236564Sbostic switch (OC_AMEXT(mode)) {
2938912Srrh
29436564Sbostic case OC_IMM0: case OC_IMM1:
29536564Sbostic case OC_IMM2: case OC_IMM3:
29636564Sbostic savevar(mode);
29736564Sbostic printc('$');
29836564Sbostic #ifdef notyet
29936564Sbostic if (ty_float[A_TYPEXT(optype)])
30036564Sbostic prints(fltimm[mode]);
30136564Sbostic else if (ischmk && (u_int)mode < nsys && syscalls[mode])
30236564Sbostic prints(syscalls[mode]);
30336564Sbostic else
30436564Sbostic adbprintf("%V", mode);
30536564Sbostic #else
30636564Sbostic switch (A_TYPEXT(optype)) {
3073760Sroot
30836564Sbostic case TYPF:
30936564Sbostic case TYPD:
31036564Sbostic case TYPG:
31136564Sbostic case TYPH:
31236564Sbostic prints(fltimm[mode]);
31336564Sbostic break;
31436564Sbostic
31536564Sbostic default:
31636564Sbostic if (ischmk && (u_int)mode < nsys && syscalls[mode])
31736564Sbostic prints(syscalls[mode]);
31836564Sbostic else
31936564Sbostic adbprintf("%V", mode);
32036564Sbostic break;
32136564Sbostic }
32236564Sbostic #endif
32336564Sbostic return (0);
32436564Sbostic
3258912Srrh case OC_INDEX:
32636564Sbostic return (r); /* will be printed later */
32736564Sbostic
3288912Srrh case OC_REG:
32936564Sbostic adbprintf("%s", r);
33036564Sbostic return (0);
33136564Sbostic
3328912Srrh case OC_DREG:
33336564Sbostic adbprintf("(%s)", r);
33436564Sbostic return (0);
33536564Sbostic
3368912Srrh case OC_ADREG:
33736564Sbostic adbprintf("-(%s)", r);
33836564Sbostic return (0);
33936564Sbostic
3408912Srrh case OC_DAIREG:
3418912Srrh printc('*');
34236564Sbostic /* FALLTHROUGH */
34336564Sbostic
3448912Srrh case OC_AIREG:
34536564Sbostic if (regnumber != R_PC) {
34636564Sbostic adbprintf("(%s)+", r);
34736564Sbostic return (0);
3488912Srrh }
34936564Sbostic /* PC immediate */
35036564Sbostic printc('$');
35136564Sbostic if (mode == OC_CONS(OC_DAIREG, R_PC))
35236564Sbostic /* PC absolute, always 4 bytes */
35336564Sbostic nbytes = 4;
35436564Sbostic else {
35536564Sbostic nbytes = ty_nbyte[A_TYPEXT(optype)];
35636564Sbostic if (ty_NORELOC[A_TYPEXT(optype)]) {
35736564Sbostic bignumprint(nbytes, optype);
35836564Sbostic return (0);
35936564Sbostic }
36036564Sbostic }
36136564Sbostic break;
36236564Sbostic
3638912Srrh case OC_DBDISP:
3648912Srrh printc('*');
36536564Sbostic /* FALLTHROUGH */
36636564Sbostic
3678912Srrh case OC_BDISP:
3688912Srrh nbytes = 1;
3698912Srrh break;
37036564Sbostic
3718912Srrh case OC_DWDISP:
3728912Srrh printc('*');
37336564Sbostic /* FALLTHROUGH */
37436564Sbostic
3758912Srrh case OC_WDISP:
3768912Srrh nbytes = 2;
3778912Srrh break;
37836564Sbostic
3798912Srrh case OC_DLDISP:
3808912Srrh printc('*');
38136564Sbostic /* FALLTHROUGH */
38236564Sbostic
3838912Srrh case OC_LDISP:
3848912Srrh nbytes = 4;
3858912Srrh break;
38636564Sbostic
38736564Sbostic default:
38836564Sbostic panic("operandout 1");
38936564Sbostic /* NOTREACHED */
3903760Sroot }
3913760Sroot
39236564Sbostic /*
39336564Sbostic * Print a displacement format.
39436564Sbostic */
39536564Sbostic getsomebytes(&displ, nbytes);
39636564Sbostic switch (nbytes) {
39736564Sbostic case 1:
39836564Sbostic n = displ.b;
3998912Srrh break;
40036564Sbostic case 2:
40136564Sbostic n = displ.w;
40236564Sbostic break;
40336564Sbostic case 4:
40436564Sbostic n = displ.l;
40536564Sbostic break;
4068912Srrh default:
40736564Sbostic panic("operandout 2");
40836564Sbostic /* NOTREACHED */
4098912Srrh }
41036564Sbostic if (regnumber == R_PC) {
41136564Sbostic switch (OC_AMEXT(mode)) {
4123760Sroot
41336564Sbostic case OC_DAIREG:
41436564Sbostic if (ischmk && (u_int)n < nsys && syscalls[n]) {
41536564Sbostic prints(syscalls[n]);
41636564Sbostic return (0);
41736564Sbostic }
41836564Sbostic break;
4198912Srrh
42036564Sbostic case OC_BDISP: case OC_DBDISP:
42136564Sbostic case OC_WDISP: case OC_DWDISP:
42236564Sbostic case OC_LDISP: case OC_DLDISP:
42336564Sbostic /* PC offset */
42436564Sbostic n += dot + dotoff;
42536564Sbostic }
42636564Sbostic psymoff("%V", (addr_t)n, SP_DATA, maxoff, "");
42736564Sbostic } else
42836564Sbostic adbprintf("%V(%s)", (expr_t)n, regname[regnumber]);
42936564Sbostic savevar(n);
43036564Sbostic return (0);
4318912Srrh }
4328912Srrh
43336564Sbostic /*
43436564Sbostic * Print an F-float, D-float, G-float, H-float, quadword, or octaword.
43536564Sbostic * F- and D-floating values are printed as themselves, unless they are
43636564Sbostic * reserved operand bit patterns; these, and the others, are printed
43736564Sbostic * instead in hex, with leading zeroes suppressed.
43836564Sbostic */
43936564Sbostic static
bignumprint(nbytes,optype)4408912Srrh bignumprint(nbytes, optype)
44136564Sbostic int nbytes, optype;
4428912Srrh {
44336564Sbostic register char *p;
44436564Sbostic register int i;
44536564Sbostic union {
44636564Sbostic float f; /* if f-floating */
44736564Sbostic double d; /* if d-floating */
44836564Sbostic u_char c[16]; /* if G, H, Q, or O */
44936564Sbostic } n;
45036564Sbostic char expbuf[4*8+1]; /* max 4 8-character hex ints */
45136564Sbostic static char tohex[] = "0123456789abcdef";
4523760Sroot
45336564Sbostic /*
45436564Sbostic * Read in the number, then figure out how to print it.
45536564Sbostic */
45636564Sbostic getsomebytes(&n, nbytes);
45736564Sbostic switch (A_TYPEXT(optype)) {
45836564Sbostic
45936564Sbostic case TYPF:
46036564Sbostic if ((p = checkfloat((caddr_t)&n.f, 0)) == NULL) {
46136564Sbostic adbprintf("0f%f", n.f);
46236564Sbostic return;
46335100Sbostic }
46436564Sbostic adbprintf("%s 0f::", p);
4658912Srrh break;
46636564Sbostic
4678912Srrh case TYPD:
46836564Sbostic if ((p = checkfloat((caddr_t)&n.d, 1)) == NULL) {
46936564Sbostic adbprintf("0d%f", n.d);
47036564Sbostic return;
47135100Sbostic }
47236564Sbostic adbprintf("%s 0d::", p);
4738912Srrh break;
47436564Sbostic
4758912Srrh case TYPG:
47636564Sbostic adbprintf("0g::");
47736564Sbostic break;
47836564Sbostic
4798912Srrh case TYPH:
48036564Sbostic adbprintf("0h::");
48136564Sbostic break;
48236564Sbostic
4838912Srrh case TYPQ:
4848912Srrh case TYPO:
4858912Srrh break;
4868912Srrh
48736564Sbostic default:
48836564Sbostic panic("bignumprint");
4898912Srrh }
4908912Srrh
49136564Sbostic /*
49236564Sbostic * Expand the number into expbuf, then skip leading zeroes.
49336564Sbostic * Be careful not to skip the entire number.
49436564Sbostic */
49536564Sbostic for (p = expbuf, i = nbytes; --i >= 0;) {
49636564Sbostic *p++ = tohex[n.c[i] >> 4];
49736564Sbostic *p++ = tohex[n.c[i] & 15];
4988912Srrh }
49936564Sbostic for (p = expbuf; *p == '0'; p++)
50036564Sbostic /* void */;
50136564Sbostic prints(*p ? p : p - 1);
5028912Srrh }
503