BSD 4_4 release
[unix-history] / usr / src / old / adb / adb.tahoe / opset.c
/*-
* Copyright (c) 1991 The Regents of the University of California.
* All rights reserved.
*
* This module is believed to contain source code proprietary to AT&T.
* Use and redistribution is subject to the Berkeley Software License
* Agreement and your Software Agreement with AT&T (Western Electric).
*/
#ifndef lint
static char sccsid[] = "@(#)opset.c 5.1 (Berkeley) 4/4/91";
#endif /* not lint */
/*
* adb - instruction decoding
*/
#include "defs.h"
#include "optab.h"
struct optab *ioptab[256]; /* index by opcode to optab */
/* set up ioptab */
mkioptab()
{
register struct optab *p;
for (p = optab; p->iname; p++)
ioptab[p->val] = p;
}
/*
* Print one instruction, and leave dotinc set to the number of bytes
* it occupied.
*/
printins(space)
int space;
{
u_char ins; /* instruction opcode */
int argno; /* argument index */
register int mode; /* mode */
register int r; /* register name */
register int d; /* assembled byte, word, long or float */
register int dotoff; /* offset from dot of current byte */
register u_char *ap;
register struct optab *ip;
union {
u_char ub;
char b;
short w;
int l;
} mem;
extern char *syscalls[];
extern int nsys;
#define snarfbytes(nbytes) \
(void) adbread(space, inkdot(dotoff), &mem.b, nbytes); \
checkerr(); \
dotoff += (nbytes)
if (space == SP_NONE)
ins = (u_char)dot;
else {
(void) adbread(space, dot, &ins, 1);
checkerr();
}
if ((ip = ioptab[ins]) == NULL) {
adbprintf("?%2x", ins);
dotinc = 1;
return;
}
adbprintf("%s%8t", ip->iname);
dotoff = 1;
ap = ip->argtype;
for (argno = 0; argno < ip->nargs; argno++, ap++) {
var[argno] = 0x80000000;
if (argno != 0)
printc(',');
again:
if (*ap & ACCB) /* branch displacement */
mode = 0xAF + ((*ap & 7) << 5);
else {
snarfbytes(1);
mode = mem.ub;
}
r = mode & 0xF;
mode >>= 4;
switch (mode) {
case 0: case 1: case 2: case 3:
/* short literal */
d = mode << 4 | r;
goto immed;
case 4: /* [r] */
adbprintf("[%s]", regname[r]);
goto again;
case 5: /* r */
adbprintf("%s", regname[r]);
continue;
case 6: /* (r) */
adbprintf("(%s)", regname[r]);
continue;
case 7: /* -(r) */
adbprintf("-(%s)", regname[r]);
continue;
case 9: /* *(r)+ */
printc('*');
/* FALLTHROUGH */
case 8: /* (r)+ */
if (r == 0xf) {
/* PC immediate */
snarfbytes(4);
d = mem.l;
} else if (mode == 8 && (r == 8 || r == 9)) {
/* absolute */
snarfbytes((r & 1) + 1);
d = r == 8 ? mem.b : mem.w;
} else {
adbprintf("(%s)+", regname[r]);
continue;
}
immed:
printc('$');
if (ins == KCALL && (u_int)d < nsys && syscalls[d])
prints(syscalls[d]);
else
adbprintf("%R", d);
var[argno] = d;
continue;
case 0xA: /* byte displacement */
case 0xB: /* byte displacement deferred */
d = 1;
break;
case 0xC: /* word displacement */
case 0xD: /* word displacement deferred */
d = 2;
break;
case 0xE: /* long displacement */
case 0xF: /* long displacement deferred */
d = 4;
break;
}
/* displacement or displacement deferred */
if (mode & 1)
printc('*');
snarfbytes(d);
switch (d) {
case 1:
d = mem.b;
break;
case 2:
d = mem.w;
break;
case 4:
d = mem.l;
break;
}
if (r == 0xF) { /* PC offset addressing */
d += dot + dotoff;
psymoff("%R", (addr_t)d, SP_DATA, maxoff, "");
} else
adbprintf("%V(%s)", d, regname[r]);
var[argno] = d;
}
if (ins == CASEL) {
register addr_t adjdot;
if (inkdot(dotoff) & 01) /* align */
dotoff++;
adjdot = inkdot(dotoff);
for (argno = 0; argno <= var[2]; ++argno) {
adbprintf("\n %R: ", argno + var[1]);
snarfbytes(2);
psymoff("%R", adjdot + mem.w, SP_DATA, maxoff, "");
}
}
dotinc = dotoff;
}