* Copyright (c) 1991 The Regents of the University of California.
* %sccs.include.proprietary.c%
static char sccsid
[] = "@(#)opset.c 4.9 (Berkeley) %G%";
* adb - instruction printing routines: VAX version
* Get assembler definitions; declare tables that appear in optab.c.
extern struct insttab insttab
[];
/* these are shared with the assembler: */
extern int ty_float
[]; /* must update assizetab.c */
* Definitions for registers and for operand classes.
#define OC_IMM0 0x0 /* literal, aka immediate */
#define OC_INDEX 0x4 /* [rN] */
#define OC_REG 0x5 /* rN */
#define OC_DREG 0x6 /* (rN) */
#define OC_ADREG 0x7 /* -(rN) */
#define OC_AIREG 0x8 /* (rN)+ */
#define OC_DAIREG 0x9 /* *(rN)+ */
#define OC_BDISP 0xA /* b(rN) */
#define OC_DBDISP 0xB /* *b(rN) */
#define OC_WDISP 0xC /* w(rN) */
#define OC_DWDISP 0xD /* *w(rN) */
#define OC_LDISP 0xE /* l(rN) */
#define OC_DLDISP 0xF /* *l(rN) */
#define OC_CONS(oc,reg) (((oc & 0xF) << OC_SHIFT) | (reg & 0xF))
#define OC_AMEXT(x) (((x) >> OC_SHIFT) & 0xF)
#define OC_REGEXT(x) ((x) & 0xF)
* Definitions for special instructions.
* ioptab is a two level 1-based index by opcode into insttab.
* The first level into ioptab is given by mapescbyte().
* Since ioptab is 1-based, references would be expected to
* ptr = &insttab[ioptab[a][b] - 1];
* ptr = &(insttab - 1)[ioptab[a][b]]
* is equivalent and generates less code (!) (time to work on the
static short ioptab
[3][256];
#define mapescbyte(b) ((b) == ESCD ? 1 : (b) == ESCF ? 2 : 0)
register struct insttab
*p
;
* The idea here is that whenever two opcodes have the same
* codes, but different mnemonics, we want to prefer the one
* with the `simpler' type. Here lower numbers make simpler
* types. This seems (likely) to work reasonably well.
* At present, this affects the following opcodes:
* 7e movaq | movad | movag
* 7f pushaq | pushad | pushag
* In each case, the leftmost mnemonics are preferred.
#define PREFER(a, b) (A_TYPEXT((a)->argtype[0]) < A_TYPEXT((b)->argtype[0]))
for (p
= insttab
; p
->iname
!= NULL
; p
++) {
mapchar
= mapescbyte(p
->eopcode
);
iop
= &ioptab
[mapchar
][p
->popcode
];
if (*iop
== 0 || PREFER(p
, &(insttab
- 1)[*iop
]))
*iop
= p
- (insttab
- 1);
* Global variables for communication between the minions and printins.
static int idsp
; /* which space we are in (INSTR or DATA) */
static int argno
; /* which argument we are working on */
static int dotoff
; /* offset from dot for this arg */
static int vset
[7]; /* set by savevar, cleared by clrvar */
#define savevar(v) (vset[argno] = 1, var[argno] = v)
#define clrvar(v) (vset[argno] = 0, var[argno] = 0x80000000)
* Read some bytes, checking for errors, and updating the offset.
#define getsomebytes(ptr, nbytes) \
(void) adbread(idsp, inkdot(dotoff), ptr, nbytes); \
* Read one byte, and advance the offset.
getsomebytes(&c
, sizeof(c
));
* adb's view: printins() prints one instruction, and sets dotinc.
register struct insttab
*ip
;
int ins
, mode
, optype
, mapchar
, t
;
* Set up the module variables, pick up the instruction, and
ins
= idsp
== SP_NONE
? (u_char
)dot
: getbyte();
if ((mapchar
= mapescbyte(ins
)) != 0) {
if (ioptab
[mapchar
][t
] == 0) {
* Oops; not a defined instruction; back over this
if ((t
= ioptab
[mapchar
][ins
]) == 0) {
adbprintf("<undefined operator byte>: %x", ins
);
adbprintf("%s%8t", ip
->iname
);
* For each argument, decode that argument.
* We set t if we notice something fishy.
for (ap
= ip
->argtype
, argno
= 0; argno
< ip
->nargs
; argno
++) {
* lastix and ixreg track the register indexed addressing
* mode, which is written as <stuff>[reg] but encoded as
* [reg]<stuff>. Only one [reg] is legal.
/* check for special pc-relative (branch) */
if (A_ACCEXT(optype
) & ACCB
) {
switch (A_TYPEXT(optype
)) {
mode
= OC_CONS(OC_BDISP
, R_PC
);
mode
= OC_CONS(OC_WDISP
, R_PC
);
ixreg
= operandout(mode
, optype
, ins
== CHMK
);
adbprintf("[%s]", lastix
);
} while ((lastix
= ixreg
) != NULL
);
adbprintf("%4t# not code? illegal arguments detected ");
if (mapchar
== 0 && vset
[1] && vset
[2])
casebody(var
[1], var
[2]);
adbprintf("\n%4t# not code? non-constant cases ");
* Print out the locations to which each of the cases branch.
* This routine carefully allows expressions such as
* casel <val>,$<const>,$0x7fffffff
* even though they do not fit on a VAX.
register expr_t base
, limit
;
register addr_t a
, baseaddr
= inkdot(dotoff
);
adbprintf("\n %R: ", base
++);
getsomebytes(&displ
, sizeof(displ
));
psymoff("%R", a
, SP_DATA
, maxoff
, "");
* Handle a normal operand. Return pointer to register
* name if this is an index instruction, else return NULL.
operandout(mode
, optype
, ischmk
)
register int regnumber
, nbytes
, n
;
regnumber
= OC_REGEXT(mode
);
switch (OC_AMEXT(mode
)) {
case OC_IMM0
: case OC_IMM1
:
case OC_IMM2
: case OC_IMM3
:
if (ty_float
[A_TYPEXT(optype
)])
else if (ischmk
&& (u_int
)mode
< nsys
&& syscalls
[mode
])
switch (A_TYPEXT(optype
)) {
if (ischmk
&& (u_int
)mode
< nsys
&& syscalls
[mode
])
return (r
); /* will be printed later */
if (mode
== OC_CONS(OC_DAIREG
, R_PC
))
/* PC absolute, always 4 bytes */
nbytes
= ty_nbyte
[A_TYPEXT(optype
)];
if (ty_NORELOC
[A_TYPEXT(optype
)]) {
bignumprint(nbytes
, optype
);
* Print a displacement format.
getsomebytes(&displ
, nbytes
);
switch (OC_AMEXT(mode
)) {
if (ischmk
&& (u_int
)n
< nsys
&& syscalls
[n
]) {
case OC_BDISP
: case OC_DBDISP
:
case OC_WDISP
: case OC_DWDISP
:
case OC_LDISP
: case OC_DLDISP
:
psymoff("%V", (addr_t
)n
, SP_DATA
, maxoff
, "");
adbprintf("%V(%s)", (expr_t
)n
, regname
[regnumber
]);
* Print an F-float, D-float, G-float, H-float, quadword, or octaword.
* F- and D-floating values are printed as themselves, unless they are
* reserved operand bit patterns; these, and the others, are printed
* instead in hex, with leading zeroes suppressed.
bignumprint(nbytes
, optype
)
float f
; /* if f-floating */
double d
; /* if d-floating */
u_char c
[16]; /* if G, H, Q, or O */
char expbuf
[4*8+1]; /* max 4 8-character hex ints */
static char tohex
[] = "0123456789abcdef";
* Read in the number, then figure out how to print it.
getsomebytes(&n
, nbytes
);
switch (A_TYPEXT(optype
)) {
if ((p
= checkfloat((caddr_t
)&n
.f
, 0)) == NULL
) {
if ((p
= checkfloat((caddr_t
)&n
.d
, 1)) == NULL
) {
* Expand the number into expbuf, then skip leading zeroes.
* Be careful not to skip the entire number.
for (p
= expbuf
, i
= nbytes
; --i
>= 0;) {
*p
++ = tohex
[n
.c
[i
] >> 4];
*p
++ = tohex
[n
.c
[i
] & 15];
for (p
= expbuf
; *p
== '0'; p
++)