need dependency, from Chris Torek
[unix-history] / usr / src / old / adb / adb.vax / opset.c
CommitLineData
f02effa0 1#ifndef lint
2222b6d9
KB
2static char sccsid[] = "@(#)opset.c 4.8 (Berkeley) %G%";
3#endif
4
7cb4340a 5/*
2222b6d9 6 * adb - instruction printing routines: VAX version
7cb4340a
BJ
7 */
8
9#include "defs.h"
7cb4340a 10
2222b6d9
KB
11/*
12 * Get assembler definitions; declare tables that appear in optab.c.
13 */
14#define ADB
f02effa0
RH
15#undef INSTTAB
16#include "instrs.h"
7cb4340a 17
2222b6d9
KB
18extern struct insttab insttab[];
19extern char *regname[];
20extern char *fltimm[];
21
22/* these are shared with the assembler: */
23extern int ty_NORELOC[];
24extern int ty_nbyte[];
25#ifdef notyet
26extern int ty_float[]; /* must update assizetab.c */
27#endif
28
7cb4340a 29/*
2222b6d9 30 * Definitions for registers and for operand classes.
7cb4340a 31 */
f02effa0
RH
32#define R_PC 0xF
33
2222b6d9 34#define OC_IMM0 0x0 /* literal, aka immediate */
f02effa0
RH
35#define OC_IMM1 0x1
36#define OC_IMM2 0x2
37#define OC_IMM3 0x3
2222b6d9
KB
38#define OC_INDEX 0x4 /* [rN] */
39#define OC_REG 0x5 /* rN */
40#define OC_DREG 0x6 /* (rN) */
41#define OC_ADREG 0x7 /* -(rN) */
42#define OC_AIREG 0x8 /* (rN)+ */
43#define OC_DAIREG 0x9 /* *(rN)+ */
44#define OC_BDISP 0xA /* b(rN) */
45#define OC_DBDISP 0xB /* *b(rN) */
46#define OC_WDISP 0xC /* w(rN) */
47#define OC_DWDISP 0xD /* *w(rN) */
48#define OC_LDISP 0xE /* l(rN) */
49#define OC_DLDISP 0xF /* *l(rN) */
f02effa0
RH
50
51#define OC_SHIFT 4
52#define OC_CONS(oc,reg) (((oc & 0xF) << OC_SHIFT) | (reg & 0xF))
53#define OC_AMEXT(x) (((x) >> OC_SHIFT) & 0xF)
54#define OC_REGEXT(x) ((x) & 0xF)
7cb4340a
BJ
55
56/*
2222b6d9 57 * Definitions for special instructions.
f02effa0
RH
58 */
59#define CASEB 0x8F
60#define CASEW 0xAF
61#define CASEL 0xCF
2222b6d9
KB
62#define CHMK 0xBC
63
f02effa0 64/*
2222b6d9
KB
65 * ioptab is a two level 1-based index by opcode into insttab.
66 * The first level into ioptab is given by mapescbyte().
67 * Since ioptab is 1-based, references would be expected to
68 * be of the form
69 *
70 * ptr = &insttab[ioptab[a][b] - 1];
71 *
72 * but the form
73 *
74 * ptr = &(insttab - 1)[ioptab[a][b]]
75 *
76 * is equivalent and generates less code (!) (time to work on the
77 * compiler again...).
f02effa0 78 */
2222b6d9
KB
79static short ioptab[3][256];
80#define mapescbyte(b) ((b) == ESCD ? 1 : (b) == ESCF ? 2 : 0)
7cb4340a 81
f02effa0
RH
82mkioptab()
83{
2222b6d9
KB
84 register struct insttab *p;
85 register int mapchar;
86 register short *iop;
7cb4340a 87
2222b6d9
KB
88 /*
89 * The idea here is that whenever two opcodes have the same
90 * codes, but different mnemonics, we want to prefer the one
91 * with the `simpler' type. Here lower numbers make simpler
92 * types. This seems (likely) to work reasonably well.
93 *
94 * At present, this affects the following opcodes:
95 *
96 * 7c clrq | clrd | clrg
97 * 7e movaq | movad | movag
98 * 7f pushaq | pushad | pushag
99 * d4 clrl | clrf
100 * de moval | movaf
101 * df pushal | pushaf
102 *
103 * In each case, the leftmost mnemonics are preferred.
104 */
105#define PREFER(a, b) (A_TYPEXT((a)->argtype[0]) < A_TYPEXT((b)->argtype[0]))
106
107 for (p = insttab; p->iname != NULL; p++) {
f02effa0 108 mapchar = mapescbyte(p->eopcode);
2222b6d9
KB
109 iop = &ioptab[mapchar][p->popcode];
110 if (*iop == 0 || PREFER(p, &(insttab - 1)[*iop]))
111 *iop = p - (insttab - 1);
7cb4340a 112 }
2222b6d9 113#undef PREFER
7cb4340a
BJ
114}
115
f02effa0 116/*
2222b6d9 117 * Global variables for communication between the minions and printins.
f02effa0 118 */
2222b6d9
KB
119static int idsp; /* which space we are in (INSTR or DATA) */
120static int argno; /* which argument we are working on */
121static int dotoff; /* offset from dot for this arg */
122static int vset[7]; /* set by savevar, cleared by clrvar */
123
124#define savevar(v) (vset[argno] = 1, var[argno] = v)
125#define clrvar(v) (vset[argno] = 0, var[argno] = 0x80000000)
126
127/*
128 * Read some bytes, checking for errors, and updating the offset.
129 */
130#define getsomebytes(ptr, nbytes) \
131 (void) adbread(idsp, inkdot(dotoff), ptr, nbytes); \
132 checkerr(); \
133 dotoff += (nbytes)
134
135/*
136 * Read one byte, and advance the offset.
137 */
138static int
139getbyte()
f02effa0 140{
2222b6d9
KB
141 u_char c;
142
143 getsomebytes(&c, sizeof(c));
144 return (c);
f02effa0 145}
7cb4340a 146
2222b6d9
KB
147/*
148 * adb's view: printins() prints one instruction, and sets dotinc.
149 */
150printins(space)
151 int space;
7cb4340a 152{
2222b6d9
KB
153 register u_char *ap;
154 register struct insttab *ip;
155 int ins, mode, optype, mapchar, t;
156 char *lastix, *ixreg;
157 char *operandout();
158
159 /*
160 * Set up the module variables, pick up the instruction, and
161 * find its table entry.
162 */
163 idsp = space;
164 dotoff = 0;
165 ins = idsp == SP_NONE ? (u_char)dot : getbyte();
166 if ((mapchar = mapescbyte(ins)) != 0) {
167 t = getbyte();
168 if (ioptab[mapchar][t] == 0) {
f02effa0 169 /*
2222b6d9
KB
170 * Oops; not a defined instruction; back over this
171 * escape byte.
f02effa0 172 */
2222b6d9 173 dotoff--;
f02effa0 174 mapchar = 0;
2222b6d9
KB
175 } else
176 ins = t;
f02effa0 177 }
2222b6d9
KB
178 if ((t = ioptab[mapchar][ins]) == 0) {
179 adbprintf("<undefined operator byte>: %x", ins);
180 dotinc = 1;
181 return;
f02effa0 182 }
2222b6d9
KB
183 ip = &(insttab - 1)[t];
184 adbprintf("%s%8t", ip->iname);
f02effa0 185
2222b6d9
KB
186 /*
187 * For each argument, decode that argument.
188 * We set t if we notice something fishy.
189 */
190 t = 0;
191 for (ap = ip->argtype, argno = 0; argno < ip->nargs; argno++) {
192 optype = *ap++;
193 clrvar();
f02effa0
RH
194 if (argno != 0)
195 printc(',');
2222b6d9
KB
196 /*
197 * lastix and ixreg track the register indexed addressing
198 * mode, which is written as <stuff>[reg] but encoded as
199 * [reg]<stuff>. Only one [reg] is legal.
200 */
201 lastix = NULL;
202 do {
203 /* check for special pc-relative (branch) */
204 if (A_ACCEXT(optype) & ACCB) {
205 switch (A_TYPEXT(optype)) {
f02effa0
RH
206 case TYPB:
207 mode = OC_CONS(OC_BDISP, R_PC);
7cb4340a 208 break;
f02effa0
RH
209 case TYPW:
210 mode = OC_CONS(OC_WDISP, R_PC);
7cb4340a 211 break;
f02effa0 212 }
2222b6d9
KB
213 } else
214 mode = getbyte();
215 ixreg = operandout(mode, optype, ins == CHMK);
216 if (lastix) {
217 adbprintf("[%s]", lastix);
218 if (ixreg)
219 t = 1;
f02effa0 220 }
2222b6d9 221 } while ((lastix = ixreg) != NULL);
7cb4340a 222 }
2222b6d9
KB
223 if (t)
224 adbprintf("%4t# not code? illegal arguments detected ");
225 switch (ins) {
226 case CASEB:
227 case CASEW:
228 case CASEL:
229 if (mapchar == 0 && vset[1] && vset[2])
230 casebody(var[1], var[2]);
231 else
232 adbprintf("\n%4t# not code? non-constant cases ");
7cb4340a 233 }
2222b6d9 234 dotinc = dotoff;
f02effa0
RH
235}
236
2222b6d9
KB
237/*
238 * Print out the locations to which each of the cases branch.
239 * This routine carefully allows expressions such as
240 *
241 * casel <val>,$<const>,$0x7fffffff
242 *
243 * even though they do not fit on a VAX.
244 */
245static
f02effa0 246casebody(base, limit)
2222b6d9 247 register expr_t base, limit;
f02effa0 248{
2222b6d9
KB
249 register expr_t i = -1;
250 register addr_t a, baseaddr = inkdot(dotoff);
251 short displ;
252
f02effa0 253 argno = 0;
2222b6d9
KB
254 do {
255 i++;
256 adbprintf("\n %R: ", base++);
257 getsomebytes(&displ, sizeof(displ));
258 a = displ + baseaddr;
259 psymoff("%R", a, SP_DATA, maxoff, "");
260 savevar(a);
261 } while (i != limit);
7cb4340a
BJ
262}
263
264/*
2222b6d9
KB
265 * Handle a normal operand. Return pointer to register
266 * name if this is an index instruction, else return NULL.
f02effa0 267 */
2222b6d9
KB
268static char *
269operandout(mode, optype, ischmk)
270 register int mode;
271 int optype, ischmk;
f02effa0 272{
2222b6d9
KB
273 register char *r;
274 register int regnumber, nbytes, n;
275 union {
276 char b;
277 short w;
278 int l;
279 } displ;
280 extern char *syscalls[];
281 extern int nsys;
f02effa0 282
2222b6d9
KB
283 regnumber = OC_REGEXT(mode);
284 r = regname[regnumber];
285 switch (OC_AMEXT(mode)) {
286
287 case OC_IMM0: case OC_IMM1:
288 case OC_IMM2: case OC_IMM3:
289 savevar(mode);
290 printc('$');
291#ifdef notyet
292 if (ty_float[A_TYPEXT(optype)])
293 prints(fltimm[mode]);
294 else if (ischmk && (u_int)mode < nsys && syscalls[mode])
295 prints(syscalls[mode]);
296 else
297 adbprintf("%V", mode);
298#else
299 switch (A_TYPEXT(optype)) {
7cb4340a 300
2222b6d9
KB
301 case TYPF:
302 case TYPD:
303 case TYPG:
304 case TYPH:
305 prints(fltimm[mode]);
306 break;
307
308 default:
309 if (ischmk && (u_int)mode < nsys && syscalls[mode])
310 prints(syscalls[mode]);
311 else
312 adbprintf("%V", mode);
313 break;
314 }
315#endif
316 return (0);
f02effa0 317
f02effa0 318 case OC_INDEX:
2222b6d9
KB
319 return (r); /* will be printed later */
320
f02effa0 321 case OC_REG:
2222b6d9
KB
322 adbprintf("%s", r);
323 return (0);
324
f02effa0 325 case OC_DREG:
2222b6d9
KB
326 adbprintf("(%s)", r);
327 return (0);
328
f02effa0 329 case OC_ADREG:
2222b6d9
KB
330 adbprintf("-(%s)", r);
331 return (0);
332
f02effa0
RH
333 case OC_DAIREG:
334 printc('*');
2222b6d9
KB
335 /* FALLTHROUGH */
336
f02effa0 337 case OC_AIREG:
2222b6d9
KB
338 if (regnumber != R_PC) {
339 adbprintf("(%s)+", r);
340 return (0);
f02effa0 341 }
2222b6d9
KB
342 /* PC immediate */
343 printc('$');
344 if (mode == OC_CONS(OC_DAIREG, R_PC))
345 /* PC absolute, always 4 bytes */
346 nbytes = 4;
347 else {
348 nbytes = ty_nbyte[A_TYPEXT(optype)];
349 if (ty_NORELOC[A_TYPEXT(optype)]) {
350 bignumprint(nbytes, optype);
351 return (0);
352 }
353 }
354 break;
355
f02effa0
RH
356 case OC_DBDISP:
357 printc('*');
2222b6d9
KB
358 /* FALLTHROUGH */
359
f02effa0
RH
360 case OC_BDISP:
361 nbytes = 1;
362 break;
2222b6d9 363
f02effa0
RH
364 case OC_DWDISP:
365 printc('*');
2222b6d9
KB
366 /* FALLTHROUGH */
367
f02effa0
RH
368 case OC_WDISP:
369 nbytes = 2;
370 break;
2222b6d9 371
f02effa0
RH
372 case OC_DLDISP:
373 printc('*');
2222b6d9
KB
374 /* FALLTHROUGH */
375
f02effa0
RH
376 case OC_LDISP:
377 nbytes = 4;
378 break;
7cb4340a 379
2222b6d9
KB
380 default:
381 panic("operandout 1");
382 /* NOTREACHED */
f02effa0 383 }
2222b6d9
KB
384
385 /*
386 * Print a displacement format.
387 */
388 getsomebytes(&displ, nbytes);
389 switch (nbytes) {
390 case 1:
391 n = displ.b;
f02effa0 392 break;
2222b6d9
KB
393 case 2:
394 n = displ.w;
395 break;
396 case 4:
397 n = displ.l;
f02effa0 398 break;
2222b6d9
KB
399 default:
400 panic("operandout 2");
401 /* NOTREACHED */
f02effa0 402 }
2222b6d9
KB
403 if (regnumber == R_PC) {
404 switch (OC_AMEXT(mode)) {
7cb4340a 405
2222b6d9
KB
406 case OC_DAIREG:
407 if (ischmk && (u_int)n < nsys && syscalls[n]) {
408 prints(syscalls[n]);
409 return (0);
410 }
411 break;
f02effa0 412
2222b6d9
KB
413 case OC_BDISP: case OC_DBDISP:
414 case OC_WDISP: case OC_DWDISP:
415 case OC_LDISP: case OC_DLDISP:
416 /* PC offset */
417 n += dot + dotoff;
418 }
419 psymoff("%V", (addr_t)n, SP_DATA, maxoff, "");
420 } else
421 adbprintf("%V(%s)", (expr_t)n, regname[regnumber]);
422 savevar(n);
423 return (0);
f02effa0
RH
424}
425
2222b6d9
KB
426/*
427 * Print an F-float, D-float, G-float, H-float, quadword, or octaword.
428 * F- and D-floating values are printed as themselves, unless they are
429 * reserved operand bit patterns; these, and the others, are printed
430 * instead in hex, with leading zeroes suppressed.
431 */
432static
f02effa0 433bignumprint(nbytes, optype)
2222b6d9 434 int nbytes, optype;
f02effa0 435{
2222b6d9
KB
436 register char *p;
437 register int i;
438 union {
439 float f; /* if f-floating */
440 double d; /* if d-floating */
441 u_char c[16]; /* if G, H, Q, or O */
442 } n;
443 char expbuf[4*8+1]; /* max 4 8-character hex ints */
444 static char tohex[] = "0123456789abcdef";
445
446 /*
447 * Read in the number, then figure out how to print it.
448 */
449 getsomebytes(&n, nbytes);
450 switch (A_TYPEXT(optype)) {
451
452 case TYPF:
453 if ((p = checkfloat((caddr_t)&n.f, 0)) == NULL) {
454 adbprintf("0f%f", n.f);
455 return;
5f2ce988 456 }
2222b6d9 457 adbprintf("%s 0f::", p);
f02effa0 458 break;
2222b6d9 459
f02effa0 460 case TYPD:
2222b6d9
KB
461 if ((p = checkfloat((caddr_t)&n.d, 1)) == NULL) {
462 adbprintf("0d%f", n.d);
463 return;
5f2ce988 464 }
2222b6d9 465 adbprintf("%s 0d::", p);
f02effa0 466 break;
2222b6d9 467
f02effa0 468 case TYPG:
2222b6d9
KB
469 adbprintf("0g::");
470 break;
471
f02effa0 472 case TYPH:
2222b6d9
KB
473 adbprintf("0h::");
474 break;
475
f02effa0
RH
476 case TYPQ:
477 case TYPO:
f02effa0 478 break;
f02effa0 479
2222b6d9
KB
480 default:
481 panic("bignumprint");
7cb4340a 482 }
f02effa0 483
2222b6d9
KB
484 /*
485 * Expand the number into expbuf, then skip leading zeroes.
486 * Be careful not to skip the entire number.
487 */
488 for (p = expbuf, i = nbytes; --i >= 0;) {
489 *p++ = tohex[n.c[i] >> 4];
490 *p++ = tohex[n.c[i] & 15];
f02effa0 491 }
2222b6d9
KB
492 for (p = expbuf; *p == '0'; p++)
493 /* void */;
494 prints(*p ? p : p - 1);
7cb4340a 495}