xref: /csrg-svn/old/adb/adb.vax/opset.c (revision 36564)
18912Srrh #ifndef lint
2*36564Sbostic static char sccsid[] = "@(#)opset.c	4.8 (Berkeley) 01/16/89";
3*36564Sbostic #endif
4*36564Sbostic 
53760Sroot /*
6*36564Sbostic  * adb - instruction printing routines: VAX version
73760Sroot  */
83760Sroot 
93760Sroot #include "defs.h"
103760Sroot 
11*36564Sbostic /*
12*36564Sbostic  * Get assembler definitions; declare tables that appear in optab.c.
13*36564Sbostic  */
14*36564Sbostic #define	ADB
158912Srrh #undef	INSTTAB
168912Srrh #include "instrs.h"
173760Sroot 
18*36564Sbostic extern struct insttab insttab[];
19*36564Sbostic extern char *regname[];
20*36564Sbostic extern char *fltimm[];
21*36564Sbostic 
22*36564Sbostic /* these are shared with the assembler: */
23*36564Sbostic extern int ty_NORELOC[];
24*36564Sbostic extern int ty_nbyte[];
25*36564Sbostic #ifdef notyet
26*36564Sbostic extern int ty_float[];		/* must update assizetab.c */
27*36564Sbostic #endif
28*36564Sbostic 
293760Sroot /*
30*36564Sbostic  * Definitions for registers and for operand classes.
313760Sroot  */
328912Srrh #define	R_PC		0xF
338912Srrh 
34*36564Sbostic #define	OC_IMM0		0x0		/* literal, aka immediate */
358912Srrh #define	OC_IMM1		0x1
368912Srrh #define	OC_IMM2		0x2
378912Srrh #define	OC_IMM3		0x3
38*36564Sbostic #define	OC_INDEX	0x4		/*   [rN]  */
39*36564Sbostic #define	OC_REG		0x5		/*    rN   */
40*36564Sbostic #define	OC_DREG		0x6		/*   (rN)  */
41*36564Sbostic #define	OC_ADREG	0x7		/*  -(rN)  */
42*36564Sbostic #define	OC_AIREG	0x8		/*   (rN)+ */
43*36564Sbostic #define	OC_DAIREG	0x9		/*  *(rN)+ */
44*36564Sbostic #define	OC_BDISP	0xA		/*  b(rN)  */
45*36564Sbostic #define	OC_DBDISP	0xB		/* *b(rN)  */
46*36564Sbostic #define	OC_WDISP	0xC		/*  w(rN)  */
47*36564Sbostic #define	OC_DWDISP	0xD		/* *w(rN)  */
48*36564Sbostic #define	OC_LDISP	0xE		/*  l(rN)  */
49*36564Sbostic #define	OC_DLDISP	0xF		/* *l(rN)  */
508912Srrh 
518912Srrh #define	OC_SHIFT	4
528912Srrh #define	OC_CONS(oc,reg)	(((oc & 0xF) << OC_SHIFT) | (reg & 0xF))
538912Srrh #define	OC_AMEXT(x)	(((x) >> OC_SHIFT) & 0xF)
548912Srrh #define	OC_REGEXT(x)	((x) & 0xF)
558912Srrh 
563760Sroot /*
57*36564Sbostic  * Definitions for special instructions.
583760Sroot  */
598912Srrh #define	CASEB	0x8F
608912Srrh #define	CASEW	0xAF
618912Srrh #define	CASEL	0xCF
62*36564Sbostic #define	CHMK	0xBC
63*36564Sbostic 
648912Srrh /*
65*36564Sbostic  * ioptab is a two level 1-based index by opcode into insttab.
66*36564Sbostic  * The first level into ioptab is given by mapescbyte().
67*36564Sbostic  * Since ioptab is 1-based, references would be expected to
68*36564Sbostic  * be of the form
69*36564Sbostic  *
70*36564Sbostic  *	ptr = &insttab[ioptab[a][b] - 1];
71*36564Sbostic  *
72*36564Sbostic  * but the form
73*36564Sbostic  *
74*36564Sbostic  *	ptr = &(insttab - 1)[ioptab[a][b]]
75*36564Sbostic  *
76*36564Sbostic  * is equivalent and generates less code (!) (time to work on the
77*36564Sbostic  * compiler again...).
788912Srrh  */
79*36564Sbostic static short ioptab[3][256];
80*36564Sbostic #define	mapescbyte(b)	((b) == ESCD ? 1 : (b) == ESCF ? 2 : 0)
813760Sroot 
828912Srrh mkioptab()
838912Srrh {
84*36564Sbostic 	register struct insttab *p;
85*36564Sbostic 	register int mapchar;
86*36564Sbostic 	register short *iop;
873760Sroot 
88*36564Sbostic 	/*
89*36564Sbostic 	 * The idea here is that whenever two opcodes have the same
90*36564Sbostic 	 * codes, but different mnemonics, we want to prefer the one
91*36564Sbostic 	 * with the `simpler' type.  Here lower numbers make simpler
92*36564Sbostic 	 * types.  This seems (likely) to work reasonably well.
93*36564Sbostic 	 *
94*36564Sbostic 	 * At present, this affects the following opcodes:
95*36564Sbostic 	 *
96*36564Sbostic 	 *  7c	clrq   | clrd   | clrg
97*36564Sbostic 	 *  7e	movaq  | movad  | movag
98*36564Sbostic 	 *  7f	pushaq | pushad | pushag
99*36564Sbostic 	 *  d4	clrl   | clrf
100*36564Sbostic 	 *  de	moval  | movaf
101*36564Sbostic 	 *  df	pushal | pushaf
102*36564Sbostic 	 *
103*36564Sbostic 	 * In each case, the leftmost mnemonics are preferred.
104*36564Sbostic 	 */
105*36564Sbostic #define PREFER(a, b) (A_TYPEXT((a)->argtype[0]) < A_TYPEXT((b)->argtype[0]))
106*36564Sbostic 
107*36564Sbostic 	for (p = insttab; p->iname != NULL; p++) {
1088912Srrh 		mapchar = mapescbyte(p->eopcode);
109*36564Sbostic 		iop = &ioptab[mapchar][p->popcode];
110*36564Sbostic 		if (*iop == 0 || PREFER(p, &(insttab - 1)[*iop]))
111*36564Sbostic 			*iop = p - (insttab - 1);
1123760Sroot 	}
113*36564Sbostic #undef PREFER
1143760Sroot }
1153760Sroot 
1168912Srrh /*
117*36564Sbostic  * Global variables for communication between the minions and printins.
1188912Srrh  */
119*36564Sbostic static int idsp;		/* which space we are in (INSTR or DATA) */
120*36564Sbostic static int argno;		/* which argument we are working on */
121*36564Sbostic static int dotoff;		/* offset from dot for this arg */
122*36564Sbostic static int vset[7];		/* set by savevar, cleared by clrvar */
1233760Sroot 
124*36564Sbostic #define	savevar(v)	(vset[argno] = 1, var[argno] = v)
125*36564Sbostic #define	clrvar(v)	(vset[argno] = 0, var[argno] = 0x80000000)
126*36564Sbostic 
127*36564Sbostic /*
128*36564Sbostic  * Read some bytes, checking for errors, and updating the offset.
129*36564Sbostic  */
130*36564Sbostic #define	getsomebytes(ptr, nbytes) \
131*36564Sbostic 	(void) adbread(idsp, inkdot(dotoff), ptr, nbytes); \
132*36564Sbostic 	checkerr(); \
133*36564Sbostic 	dotoff += (nbytes)
134*36564Sbostic 
135*36564Sbostic /*
136*36564Sbostic  * Read one byte, and advance the offset.
137*36564Sbostic  */
138*36564Sbostic static int
139*36564Sbostic getbyte()
1408912Srrh {
141*36564Sbostic 	u_char c;
142*36564Sbostic 
143*36564Sbostic 	getsomebytes(&c, sizeof(c));
144*36564Sbostic 	return (c);
1458912Srrh }
1468912Srrh 
147*36564Sbostic /*
148*36564Sbostic  * adb's view: printins() prints one instruction, and sets dotinc.
149*36564Sbostic  */
150*36564Sbostic printins(space)
151*36564Sbostic 	int space;
1523760Sroot {
153*36564Sbostic 	register u_char *ap;
154*36564Sbostic 	register struct insttab *ip;
155*36564Sbostic 	int ins, mode, optype, mapchar, t;
156*36564Sbostic 	char *lastix, *ixreg;
157*36564Sbostic 	char *operandout();
1583760Sroot 
159*36564Sbostic 	/*
160*36564Sbostic 	 * Set up the module variables, pick up the instruction, and
161*36564Sbostic 	 * find its table entry.
162*36564Sbostic 	 */
163*36564Sbostic 	idsp = space;
164*36564Sbostic 	dotoff = 0;
165*36564Sbostic 	ins = idsp == SP_NONE ? (u_char)dot : getbyte();
166*36564Sbostic 	if ((mapchar = mapescbyte(ins)) != 0) {
167*36564Sbostic 		t = getbyte();
168*36564Sbostic 		if (ioptab[mapchar][t] == 0) {
1698912Srrh 			/*
170*36564Sbostic 			 * Oops; not a defined instruction; back over this
171*36564Sbostic 			 * escape byte.
1728912Srrh 			 */
173*36564Sbostic 			dotoff--;
1748912Srrh 			mapchar = 0;
175*36564Sbostic 		} else
176*36564Sbostic 			ins = t;
1778912Srrh 	}
178*36564Sbostic 	if ((t = ioptab[mapchar][ins]) == 0) {
179*36564Sbostic 		adbprintf("<undefined operator byte>: %x", ins);
180*36564Sbostic 		dotinc = 1;
181*36564Sbostic 		return;
1828912Srrh 	}
183*36564Sbostic 	ip = &(insttab - 1)[t];
184*36564Sbostic 	adbprintf("%s%8t", ip->iname);
1858912Srrh 
186*36564Sbostic 	/*
187*36564Sbostic 	 * For each argument, decode that argument.
188*36564Sbostic 	 * We set t if we notice something fishy.
189*36564Sbostic 	 */
190*36564Sbostic 	t = 0;
191*36564Sbostic 	for (ap = ip->argtype, argno = 0; argno < ip->nargs; argno++) {
192*36564Sbostic 		optype = *ap++;
193*36564Sbostic 		clrvar();
1948912Srrh 		if (argno != 0)
1958912Srrh 			printc(',');
196*36564Sbostic 		/*
197*36564Sbostic 		 * lastix and ixreg track the register indexed addressing
198*36564Sbostic 		 * mode, which is written as <stuff>[reg] but encoded as
199*36564Sbostic 		 * [reg]<stuff>.  Only one [reg] is legal.
200*36564Sbostic 		 */
201*36564Sbostic 		lastix = NULL;
202*36564Sbostic 		do {
203*36564Sbostic 			/* check for special pc-relative (branch) */
204*36564Sbostic 			if (A_ACCEXT(optype) & ACCB) {
205*36564Sbostic 				switch (A_TYPEXT(optype)) {
2068912Srrh 				case TYPB:
2078912Srrh 					mode = OC_CONS(OC_BDISP, R_PC);
2083760Sroot 					break;
2098912Srrh 				case TYPW:
2108912Srrh 					mode = OC_CONS(OC_WDISP, R_PC);
2113760Sroot 					break;
2128912Srrh 				}
213*36564Sbostic 			} else
214*36564Sbostic 				mode = getbyte();
215*36564Sbostic 			ixreg = operandout(mode, optype, ins == CHMK);
216*36564Sbostic 			if (lastix) {
217*36564Sbostic 				adbprintf("[%s]", lastix);
218*36564Sbostic 				if (ixreg)
219*36564Sbostic 					t = 1;
2208912Srrh 			}
221*36564Sbostic 		} while ((lastix = ixreg) != NULL);
2223760Sroot 	}
223*36564Sbostic 	if (t)
224*36564Sbostic 		adbprintf("%4t# not code? illegal arguments detected  ");
225*36564Sbostic 	switch (ins) {
226*36564Sbostic 	case CASEB:
227*36564Sbostic 	case CASEW:
228*36564Sbostic 	case CASEL:
229*36564Sbostic 		if (mapchar == 0 && vset[1] && vset[2])
230*36564Sbostic 			casebody(var[1], var[2]);
231*36564Sbostic 		else
232*36564Sbostic 			adbprintf("\n%4t# not code? non-constant cases  ");
2333760Sroot 	}
234*36564Sbostic 	dotinc = dotoff;
2353760Sroot }
2363760Sroot 
237*36564Sbostic /*
238*36564Sbostic  * Print out the locations to which each of the cases branch.
239*36564Sbostic  * This routine carefully allows expressions such as
240*36564Sbostic  *
241*36564Sbostic  *	casel	<val>,$<const>,$0x7fffffff
242*36564Sbostic  *
243*36564Sbostic  * even though they do not fit on a VAX.
244*36564Sbostic  */
245*36564Sbostic static
2468912Srrh casebody(base, limit)
247*36564Sbostic 	register expr_t base, limit;
2488912Srrh {
249*36564Sbostic 	register expr_t i = -1;
250*36564Sbostic 	register addr_t a, baseaddr = inkdot(dotoff);
251*36564Sbostic 	short displ;
252*36564Sbostic 
2538912Srrh 	argno = 0;
254*36564Sbostic 	do {
255*36564Sbostic 		i++;
256*36564Sbostic 		adbprintf("\n    %R:  ", base++);
257*36564Sbostic 		getsomebytes(&displ, sizeof(displ));
258*36564Sbostic 		a = displ + baseaddr;
259*36564Sbostic 		psymoff("%R", a, SP_DATA, maxoff, "");
260*36564Sbostic 		savevar(a);
261*36564Sbostic 	} while (i != limit);
2628912Srrh }
2638912Srrh 
2643760Sroot /*
265*36564Sbostic  * Handle a normal operand.  Return pointer to register
266*36564Sbostic  * name if this is an index instruction, else return NULL.
2673760Sroot  */
268*36564Sbostic static char *
269*36564Sbostic operandout(mode, optype, ischmk)
270*36564Sbostic 	register int mode;
271*36564Sbostic 	int optype, ischmk;
2728912Srrh {
273*36564Sbostic 	register char *r;
274*36564Sbostic 	register int regnumber, nbytes, n;
275*36564Sbostic 	union {
276*36564Sbostic 		char b;
277*36564Sbostic 		short w;
278*36564Sbostic 		int l;
279*36564Sbostic 	} displ;
280*36564Sbostic 	extern char *syscalls[];
281*36564Sbostic 	extern int nsys;
2823760Sroot 
283*36564Sbostic 	regnumber = OC_REGEXT(mode);
284*36564Sbostic 	r = regname[regnumber];
285*36564Sbostic 	switch (OC_AMEXT(mode)) {
2868912Srrh 
287*36564Sbostic 	case OC_IMM0: case OC_IMM1:
288*36564Sbostic 	case OC_IMM2: case OC_IMM3:
289*36564Sbostic 		savevar(mode);
290*36564Sbostic 		printc('$');
291*36564Sbostic #ifdef notyet
292*36564Sbostic 		if (ty_float[A_TYPEXT(optype)])
293*36564Sbostic 			prints(fltimm[mode]);
294*36564Sbostic 		else if (ischmk && (u_int)mode < nsys && syscalls[mode])
295*36564Sbostic 			prints(syscalls[mode]);
296*36564Sbostic 		else
297*36564Sbostic 			adbprintf("%V", mode);
298*36564Sbostic #else
299*36564Sbostic 		switch (A_TYPEXT(optype)) {
3003760Sroot 
301*36564Sbostic 		case TYPF:
302*36564Sbostic 		case TYPD:
303*36564Sbostic 		case TYPG:
304*36564Sbostic 		case TYPH:
305*36564Sbostic 			prints(fltimm[mode]);
306*36564Sbostic 			break;
307*36564Sbostic 
308*36564Sbostic 		default:
309*36564Sbostic 			if (ischmk && (u_int)mode < nsys && syscalls[mode])
310*36564Sbostic 				prints(syscalls[mode]);
311*36564Sbostic 			else
312*36564Sbostic 				adbprintf("%V", mode);
313*36564Sbostic 			break;
314*36564Sbostic 		}
315*36564Sbostic #endif
316*36564Sbostic 		return (0);
317*36564Sbostic 
3188912Srrh 	case OC_INDEX:
319*36564Sbostic 		return (r);	/* will be printed later */
320*36564Sbostic 
3218912Srrh 	case OC_REG:
322*36564Sbostic 		adbprintf("%s", r);
323*36564Sbostic 		return (0);
324*36564Sbostic 
3258912Srrh 	case OC_DREG:
326*36564Sbostic 		adbprintf("(%s)", r);
327*36564Sbostic 		return (0);
328*36564Sbostic 
3298912Srrh 	case OC_ADREG:
330*36564Sbostic 		adbprintf("-(%s)", r);
331*36564Sbostic 		return (0);
332*36564Sbostic 
3338912Srrh 	case OC_DAIREG:
3348912Srrh 		printc('*');
335*36564Sbostic 		/* FALLTHROUGH */
336*36564Sbostic 
3378912Srrh 	case OC_AIREG:
338*36564Sbostic 		if (regnumber != R_PC) {
339*36564Sbostic 			adbprintf("(%s)+", r);
340*36564Sbostic 			return (0);
3418912Srrh 		}
342*36564Sbostic 		/* PC immediate */
343*36564Sbostic 		printc('$');
344*36564Sbostic 		if (mode == OC_CONS(OC_DAIREG, R_PC))
345*36564Sbostic 			/* PC absolute, always 4 bytes */
346*36564Sbostic 			nbytes = 4;
347*36564Sbostic 		else {
348*36564Sbostic 			nbytes = ty_nbyte[A_TYPEXT(optype)];
349*36564Sbostic 			if (ty_NORELOC[A_TYPEXT(optype)]) {
350*36564Sbostic 				bignumprint(nbytes, optype);
351*36564Sbostic 				return (0);
352*36564Sbostic 			}
353*36564Sbostic 		}
354*36564Sbostic 		break;
355*36564Sbostic 
3568912Srrh 	case OC_DBDISP:
3578912Srrh 		printc('*');
358*36564Sbostic 		/* FALLTHROUGH */
359*36564Sbostic 
3608912Srrh 	case OC_BDISP:
3618912Srrh 		nbytes = 1;
3628912Srrh 		break;
363*36564Sbostic 
3648912Srrh 	case OC_DWDISP:
3658912Srrh 		printc('*');
366*36564Sbostic 		/* FALLTHROUGH */
367*36564Sbostic 
3688912Srrh 	case OC_WDISP:
3698912Srrh 		nbytes = 2;
3708912Srrh 		break;
371*36564Sbostic 
3728912Srrh 	case OC_DLDISP:
3738912Srrh 		printc('*');
374*36564Sbostic 		/* FALLTHROUGH */
375*36564Sbostic 
3768912Srrh 	case OC_LDISP:
3778912Srrh 		nbytes = 4;
3788912Srrh 		break;
379*36564Sbostic 
380*36564Sbostic 	default:
381*36564Sbostic 		panic("operandout 1");
382*36564Sbostic 		/* NOTREACHED */
3833760Sroot 	}
3843760Sroot 
385*36564Sbostic 	/*
386*36564Sbostic 	 * Print a displacement format.
387*36564Sbostic 	 */
388*36564Sbostic 	getsomebytes(&displ, nbytes);
389*36564Sbostic 	switch (nbytes) {
390*36564Sbostic 	case 1:
391*36564Sbostic 		n = displ.b;
3928912Srrh 		break;
393*36564Sbostic 	case 2:
394*36564Sbostic 		n = displ.w;
395*36564Sbostic 		break;
396*36564Sbostic 	case 4:
397*36564Sbostic 		n = displ.l;
398*36564Sbostic 		break;
3998912Srrh 	default:
400*36564Sbostic 		panic("operandout 2");
401*36564Sbostic 		/* NOTREACHED */
4028912Srrh 	}
403*36564Sbostic 	if (regnumber == R_PC) {
404*36564Sbostic 		switch (OC_AMEXT(mode)) {
4053760Sroot 
406*36564Sbostic 		case OC_DAIREG:
407*36564Sbostic 			if (ischmk && (u_int)n < nsys && syscalls[n]) {
408*36564Sbostic 				prints(syscalls[n]);
409*36564Sbostic 				return (0);
410*36564Sbostic 			}
411*36564Sbostic 			break;
4128912Srrh 
413*36564Sbostic 		case OC_BDISP: case OC_DBDISP:
414*36564Sbostic 		case OC_WDISP: case OC_DWDISP:
415*36564Sbostic 		case OC_LDISP: case OC_DLDISP:
416*36564Sbostic 			/* PC offset */
417*36564Sbostic 			n += dot + dotoff;
418*36564Sbostic 		}
419*36564Sbostic 		psymoff("%V", (addr_t)n, SP_DATA, maxoff, "");
420*36564Sbostic 	} else
421*36564Sbostic 		adbprintf("%V(%s)", (expr_t)n, regname[regnumber]);
422*36564Sbostic 	savevar(n);
423*36564Sbostic 	return (0);
4248912Srrh }
4258912Srrh 
426*36564Sbostic /*
427*36564Sbostic  * Print an F-float, D-float, G-float, H-float, quadword, or octaword.
428*36564Sbostic  * F- and D-floating values are printed as themselves, unless they are
429*36564Sbostic  * reserved operand bit patterns; these, and the others, are printed
430*36564Sbostic  * instead in hex, with leading zeroes suppressed.
431*36564Sbostic  */
432*36564Sbostic static
4338912Srrh bignumprint(nbytes, optype)
434*36564Sbostic 	int nbytes, optype;
4358912Srrh {
436*36564Sbostic 	register char *p;
437*36564Sbostic 	register int i;
438*36564Sbostic 	union {
439*36564Sbostic 		float	f;	/* if f-floating */
440*36564Sbostic 		double	d;	/* if d-floating */
441*36564Sbostic 		u_char	c[16];	/* if G, H, Q, or O */
442*36564Sbostic 	} n;
443*36564Sbostic 	char expbuf[4*8+1];	/* max 4 8-character hex ints */
444*36564Sbostic 	static char tohex[] = "0123456789abcdef";
4453760Sroot 
446*36564Sbostic 	/*
447*36564Sbostic 	 * Read in the number, then figure out how to print it.
448*36564Sbostic 	 */
449*36564Sbostic 	getsomebytes(&n, nbytes);
450*36564Sbostic 	switch (A_TYPEXT(optype)) {
451*36564Sbostic 
452*36564Sbostic 	case TYPF:
453*36564Sbostic 		if ((p = checkfloat((caddr_t)&n.f, 0)) == NULL) {
454*36564Sbostic 			adbprintf("0f%f", n.f);
455*36564Sbostic 			return;
45635100Sbostic 		}
457*36564Sbostic 		adbprintf("%s 0f::", p);
4588912Srrh 		break;
459*36564Sbostic 
4608912Srrh 	case TYPD:
461*36564Sbostic 		if ((p = checkfloat((caddr_t)&n.d, 1)) == NULL) {
462*36564Sbostic 			adbprintf("0d%f", n.d);
463*36564Sbostic 			return;
46435100Sbostic 		}
465*36564Sbostic 		adbprintf("%s 0d::", p);
4668912Srrh 		break;
467*36564Sbostic 
4688912Srrh 	case TYPG:
469*36564Sbostic 		adbprintf("0g::");
470*36564Sbostic 		break;
471*36564Sbostic 
4728912Srrh 	case TYPH:
473*36564Sbostic 		adbprintf("0h::");
474*36564Sbostic 		break;
475*36564Sbostic 
4768912Srrh 	case TYPQ:
4778912Srrh 	case TYPO:
4788912Srrh 		break;
4798912Srrh 
480*36564Sbostic 	default:
481*36564Sbostic 		panic("bignumprint");
4828912Srrh 	}
4838912Srrh 
484*36564Sbostic 	/*
485*36564Sbostic 	 * Expand the number into expbuf, then skip leading zeroes.
486*36564Sbostic 	 * Be careful not to skip the entire number.
487*36564Sbostic 	 */
488*36564Sbostic 	for (p = expbuf, i = nbytes; --i >= 0;) {
489*36564Sbostic 		*p++ = tohex[n.c[i] >> 4];
490*36564Sbostic 		*p++ = tohex[n.c[i] & 15];
4918912Srrh 	}
492*36564Sbostic 	for (p = expbuf; *p == '0'; p++)
493*36564Sbostic 		/* void */;
494*36564Sbostic 	prints(*p ? p : p - 1);
4958912Srrh }
496