xref: /csrg-svn/old/adb/adb.vax/opset.c (revision 47821)
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