4.4BSD/usr/src/old/adb/adb.hp300/opset.hp300.c

Compare this file to the similar file:
Show the results in this format:

/*
 * Copyright (c) 1988, 1989 University of Utah.
 * All rights reserved.  The Utah Software License Agreement
 * specifies the terms and conditions for redistribution.
 *
 *	Utah $Hdr: opset.hp300.c 1.26 90/02/21$
 */

/*
 * 68020 + 68881 instruction decoder
 * Originated from the mit adb68 code
 */
#include "defs.h"

INT	dotinc;
POS	space;

char *badop = "\t???";

static char _areg[3] = "a0";
static char _dreg[3] = "d0";
#define A(reg)	((reg) == 7 ? "sp" : (_areg[1] = '0' + (reg), _areg))
#define D(reg)	(_dreg[1] = '0' + (reg), _dreg)

/* 68881 data types */
#define	TLONG	0
#define	TSPREAL	1
#define	TXPREAL	2
#define	TPDREAL	3
#define	TWORD	4
#define	TDPREAL	5
#define	TBYTE	6
#define	TDPDREAL	7

char *bname[16] = { "ra", "sr", "hi", "ls", "cc", "cs", "ne",
		    "eq", "vc", "vs", "pl", "mi", "ge", "lt", "gt", "le" };

char *shro[4] = { "as", "ls", "rox", "ro" };

char *bit[4] = { "btst", "bchg", "bclr", "bset" };

char *creg1[] = { "sfc", "dfc", "cacr", "tc", "itt0", "itt1", "dtt0", "dtt1" };
char *creg2[] = { "usp", "vbr", "caar", "msp", "isp", "mmusr", "urp", "srp" };

int omove(),obranch(),oimmed(),ouimmed(),oprint(),oneop(),soneop(),oreg();
int ochk(),olink(),omovem(),oquick(),omoveq(),otrap(),oscc(),opmode(),shroi();
int extend(),biti(),odbcc(),omovec(),odivmul(), omoves();
int ochk2(), ocall(), ocas(), otrapcc(), ortm(), ortd(), obitfield();
int omovep(), omover(), odivmull();
int ofloat(), ofdbcc(), oftrapcc(), ofscc(), ofbranch(), ofsaverestore();
int ocpgen(), ocpdbcc(), ocptrapcc(), ocpscc(), ocpbranch(), ocpsaverestore();

struct opdesc
{			
	unsigned short mask, match;
	int (*opfun)();
	char *farg;
} opdecode[] =
{	/* opcodes are grouped by high nibbles */
	/* within groups, masks and compares are performed serially */
  0xF9C0, 0x00C0, ochk2, 0,
  0xFF00, 0x0000, ouimmed, "or",	/* op class 0  */
  0xF138, 0x0108, omovep, 0,		/* ordered before btst (biti) */
  0xF100, 0x0100, biti, 0,
  0xFF00, 0x0200, ouimmed, "and",
  0xFF00, 0x0400, oimmed, "sub",
  0xFFF0, 0x06C0, ortm, 0,		/* ordered before addi */
  0xFFC0, 0x06C0, ocall, 0,		/* ordered before addi */
  0xFF00, 0x0600, oimmed, "add",
  0xFF00, 0x0800, biti, 0,
  0xF9C0, 0x08C0, ocas, 0,		/* 0x0AC0, 0x0CC0, 0x0EC0 */
  0xFF00, 0x0A00, ouimmed, "eor",
  0xFF00, 0x0C00, oimmed, "cmp",
  0xFF00, 0x0E00, omoves, 0,
  0xF000, 0x1000, omove, "b",		/* move instructions */
  0xF000, 0x2000, omove, "l",
  0xF000, 0x3000, omove, "w",
  0xF9C0, 0x40C0, omover, 0,		/* 0x40C0, 0x42C0, 0x44C0, 0x46C0 */
  0xFF00, 0x4000, soneop, "negx",
  0xFF00, 0x4200, soneop, "clr",
  0xFF00, 0x4400, soneop, "neg",
  0xFF00, 0x4600, soneop, "not",
  0xFFF8, 0x4808, olink, "l",
  0xFFC0, 0x4800, oneop, "nbcd",
  0xFFF8, 0x4840, oreg, "\tswap\td%X",
  0xFFC0, 0x4840, oneop, "pea",
  0xFFF8, 0x4848, oreg, "\tbkpt\t#%X",
  0xFFF8, 0x4880, oreg, "\textw\td%X",
  0xFFF8, 0x48C0, oreg, "\textl\td%X",
  0xFB80, 0x4880, omovem, 0,
  0xFFF8, 0x49C0, oreg, "\textbl\td%X",
  0xFFFF, 0x4AFC, oprint, "illegal",
  0xFFC0, 0x4AC0, oneop, "tas",
  0xFF00, 0x4A00, soneop, "tst",
  0xFFC0, 0x4C40, odivmull, "div",
  0xFFC0, 0x4C00, odivmull, "mul",
  0xFFF0, 0x4E40, otrap, 0,
  0xFFF8, 0x4E50, olink, "w",
  0xFFF8, 0x4E58, oreg, "\tunlk\ta%X",
  0xFFF8, 0x4E60, oreg, "\tmovl\ta%X,usp",
  0xFFF8, 0x4E68, oreg, "\tmovl\tusp,a%X",
  0xFFFF, 0x4E70, oprint, "reset",
  0xFFFF, 0x4E71, oprint, "nop",
  0xFFFF, 0x4E72, oprint, "stop",
  0xFFFF, 0x4E73, oprint, "rte",
  0xFFFF, 0x4E74, ortd, 0,
  0xFFFF, 0x4E75, oprint, "rts",
  0xFFFF, 0x4E76, oprint, "trapv",
  0xFFFF, 0x4E77, oprint, "rtr",
  0xFFFE, 0x4E7A, omovec, 0,
  0xFFC0, 0x4E80, oneop, "jsr",
  0xFFC0, 0x4EC0, oneop, "jmp",
  0xF1C0, 0x4100, ochk, "chkl",		/* keeping company with lea */
  0xF1C0, 0x4180, ochk, "chkw",		/* keeping company with lea */
  0xF1C0, 0x41C0, ochk, "lea",		/* ordered after extbl */
  0xF0F8, 0x50C8, odbcc, 0,
  0xF0F8, 0x50F8, otrapcc, 0,
  0xF0C0, 0x50C0, oscc, 0,
  0xF100, 0x5000, oquick, "addq",	/* ordered after cc instructions */
  0xF100, 0x5100, oquick, "subq",
  0xF000, 0x6000, obranch, 0,		/* branches */
  0xF000, 0x7000, omoveq, 0,
  0xF0C0, 0x80C0, odivmul, "div",
  0xF1F0, 0x8100, extend, "sbcd",
  0xF1F0, 0x8140, extend, "pack",
  0xF1F0, 0x8180, extend, "unpk",
  0xF000, 0x8000, opmode, "or",		/* ordered last in this group */
  0xF1C0, 0x91C0, opmode, "sub",
  0xF130, 0x9100, extend, "subx",
  0xF000, 0x9000, opmode, "sub",	/* ordered last in this group */
  0xF100, 0xB000, opmode, "cmp",
  0xF1C0, 0xB1C0, opmode, "cmp",
  0xF138, 0xB108, extend, "cmpm",
  0xF100, 0xB100, opmode, "eor",	/* ordered after special cmps */
  0xF0C0, 0xC0C0, odivmul, "mul",
  0xF1F0, 0xC100, extend, "abcd",
  0xF1F0, 0xC140, extend, "exg",
  0xF1F8, 0xC188, extend, "exg",
  0xF000, 0xC000, opmode, "and",	/* ordered last in this group */
  0xF1C0, 0xD1C0, opmode, "add",	/* adda; precedes addx */
  0xF130, 0xD100, extend, "addx",	/* precedes add */
  0xF000, 0xD000, opmode, "add",
  0xF8C0, 0xE8C0, obitfield, 0,		/* bitfields; precedes shifts */
  0xF100, 0xE000, shroi, "r",
  0xF100, 0xE100, shroi, "l",
  0xFFC0, 0xF200, ofloat, 0,		/* floating point */
  0xFFF8, 0xF248, ofdbcc, 0,		/* ordered before fscc */
  0xFFF8, 0xF278, oftrapcc, 0,		/* ordered before fscc */
  0xFFC0, 0xF240, ofscc, 0,
  0xFFC0, 0xF280, ofbranch, "w",
  0xFFC0, 0xF2C0, ofbranch, "l",
  0xFFC0, 0xF300, ofsaverestore, "save",
  0xFFC0, 0xF340, ofsaverestore, "restore",
  0xFFC0, 0xF000, ocpgen, 0,		/* generic coprocessor support */
  0xF1F8, 0xF048, ocpdbcc, 0,
  0xF1F8, 0xF078, ocptrapcc, 0,
  0xF1C0, 0xF040, ocpscc, 0,
  0xF1C0, 0xF080, ocpbranch, "w",
  0xF1C0, 0xF0C0, ocpbranch, "l",
  0xF1C0, 0xF100, ocpsaverestore, "save",
  0xF1C0, 0xF140, ocpsaverestore, "restore",
  0, 0, 0, 0
};

extern struct opdesc *ioptab[0x10];

mkioptab() {
	register struct opdesc *p;
	register int i;

	for (p = &opdecode[0]; p->mask; ++p) {
		i = (p->match >> 12) & 0xff;
		if (ioptab[i] == 0)
			ioptab[i] = p;
	}
	for (i = 0; i < 0x10; ++i)
		if (ioptab[i] == 0)
			ioptab[i] = &opdecode[0];
}

printins(f, idsp, inst)
	register int inst;
{
	register struct opdesc *p;

	space = idsp; dotinc = 2;
	for (p = ioptab[(inst >> 12) & 0xff]; p->mask; p++)
		if ((inst & p->mask) == p->match) break;
	if (p->mask != 0) (*p->opfun)(inst, p->farg);
	else printf(badop);
}

long
instfetch(size)
int size;
{
	long l1, l2;

	if (size==4)
	{
		l1 = leng(chkget(inkdot(dotinc), space));
		l1 <<= 16;
		l2 = leng(chkget(inkdot(dotinc += 2), space));
		l1 = (l1 | l2);
	}
	else
	{
		l1 = (long)(chkget(inkdot(dotinc), space)) & 0xFFFF;
	}
	dotinc += 2;
	return(l1);
}

printea(mode,reg,type)
long mode, reg;
int type;
{
	long index;
	union { int i[2]; float f; double d; } uifd;

	switch ((int)(mode)) {
	  case 0:	printf("d%D",reg);
			break;

	  case 1:	printf("%s",A(reg));
			break;

	  case 2:	printf("%s@",A(reg));
			break;

	  case 3:	printf("%s@+",A(reg));
			break;

	  case 4:	printf("%s@-",A(reg));
			break;

	  case 5:	printf("%s@(%w)",A(reg),instfetch(2));
			break;

	  case 6:	printindex(mode, reg);
			break;

	  case 7:	switch ((int)(reg))
			{
			  case 0:	index = instfetch(2);
					printf("%x:w",index);
					break;

			  case 1:	index = instfetch(4);
					psymoff(index, ISYM, "");
					break;

			  case 2:	printf("pc@(%w)",instfetch(2));
					break;

			  case 3:	printindex(mode, reg);
					break;

			  case 4:
				switch (type)
				{
				default:
				case TLONG:	printf("#%W", instfetch(4));
						break;
				case TBYTE:
				case TWORD:	printf("#%w", instfetch(2));
						break;
				case TDPDREAL:
				case TPDREAL:	printf("#pd");
						goto funnyconstant;
				case TXPREAL:	printf("#xp");
				funnyconstant:	printf("<%X,%X,%X>",
							instfetch(4),
							instfetch(4),
							instfetch(4));
						break;
				case TSPREAL:	uifd.i[0] = instfetch(4);
						printf("#%F", uifd.f);
						break;
				case TDPREAL:	uifd.i[0] = instfetch(4);
						uifd.i[1] = instfetch(4);
						printf("#%F", uifd.d);
						break;
				}
				break;

			  default:	printf("???");
					break;
			}
			break;

	  default:	printf("???");
	}
}

printEA(ea,type)
long ea;
int type;
{
	printea((ea>>3)&07,ea&07,type);
}

/*
 * 68020 indexed addressing modes
 */
printindex(mode, breg)
	long mode, breg;
{
	register int ext;
	int scale, regtype, size, ireg;
	int disp;
	int bs, is, bdsize, iis;
#define printbd(bds)	if ((bds) > 2) printf("%W", instfetch(4)); \
			else if ((bds) == 2) printf("%w", instfetch(2))
	char *bregname;

	bregname = mode == 7 ? "pc" : A(breg);

	ext = instfetch(2);
	regtype = (ext & 0x8000) ? 'a' : 'd';
	ireg = (ext >> 12) & 7;
	size = (ext & 0x800) ? 'l' : 'w';
	scale = 1 << ((ext >> 9) & 3);
	if ((ext & 0x100) == 0) {
		/* 'brief' format */
		printf("%s@(", bregname);
		if (disp = (char)(ext & 0377))
			printf("%w,", disp);
		printf("%c%x:%c:%x)", regtype, ireg, size, scale);
		return;
	}
	bs = ext & 0x80;
	is = ext & 0x40;
	bdsize = (ext >> 4) & 3;
	iis = (ext & 7) + (is >> 3);

	if (!bs)
		printf("%s@", bregname);
	printf("(");
	printbd(bdsize);

	switch (iis) {
	case 0: /* no memory indirection */
		if (bdsize >= 2) printf(",");
		printf("%c%x:%c:%x)", regtype, ireg, size, scale);
		break;

	case 1:
	case 2:
	case 3:
		if (bdsize >= 2) printf(",");
		printf("%c%x:%c:%x)@", regtype, ireg, size, scale);
		if (iis == 1)
			break;
		goto od;

	case 5:
	case 6:
	case 7:
		if (bdsize < 2) printf("0");
		printf(")@(");
		printbd(iis & 3);
		if ((iis & 3) >= 2) printf(",");
		printf("%c%x:%c:%x)", regtype, ireg, size, scale);
		break;

	/* index suppressed modes */

	case 8: /* no memory indirection */
		printf(")");
		break;

	case 9:
	case 10:
	case 11:
		if (bdsize < 2) printf("0");
		printf(")@");
		if (iis == 9)
			break;
	od:
		printf("(");
		printbd(iis & 3);
		printf(")");
		break;

	default:
		printf("???");
		break;
	}
}

mapsize(inst)
long inst;
{
	inst >>= 6;
	inst &= 03;
	return((inst==0) ? TBYTE : (inst==1) ? TWORD : (inst==2) ? TLONG : -1);
}

char suffix(type)
register int type;
{
	static char suffices[] = "lsxpwdbp";

	if (type < 0 || type >= sizeof suffices - 1)
		return ('?');
	return (suffices[type]);
}

omove(inst, s)
long inst;
char *s;
{
	int type;

	printf("\tmov%c\t",*s);
	type = ((*s == 'b') ? TBYTE : (*s == 'w') ? TWORD : TLONG);
	printea((inst>>3)&07,inst&07,type);
	printc(',');
	printea((inst>>6)&07,(inst>>9)&07,type);
}

omovec(inst,dummy)
long inst;
{
	long ext = instfetch(2);
	int reg = (ext >> 12) & 07;

	printf("\tmovc\t");
	if (inst&1)
		printf("%s,", ext & 0x8000 ? A(reg) : D(reg));
	printf(((ext&0x800)?creg2:creg1)[ext&0x7FF]);
	if (!(inst&1))
		printf(",%s", ext & 0x8000 ? A(reg) : D(reg));
}

omovep(inst,dummy)
long inst;
{
	long ext = instfetch(2);
	int d = (inst >> 9) & 07;
	int a = inst & 07;

	printf("\tmovep%c\t", inst & 0100 ? 'l' : 'w');
	if (inst & 0200)
		printf("d%X,%s@(%w)", d, A(a), ext);
	else
		printf("%s@(%w),d%X", A(a), ext, d);
}

omover(inst,dummy)
long inst;
{
	int to = inst & 02000;
	char *r = ((inst & 01000) << 1) ^ to ? "ccr" : "sr";

	printf("\tmovw\t");
	if (!to)
		printf("%s,", r);
	printEA(inst, TWORD);
	if (to)
		printf(",%s", r);
}

omoves(inst,dummy)
long inst;
{
	int ext = instfetch(2);
	int reg = (ext >> 12) & 07;
	int type = mapsize(inst);

	printf("\tmovs%c\t", suffix(type));
	if (ext&0x800)
		printf("%s,", ext & 0x8000 ? A(reg) : D(reg));
	printEA(inst, type);
	if (!(ext&0x800))
		printf(",%s", ext & 0x8000 ? A(reg) : D(reg));
}

/* also handles cmp2 */
ochk2(inst, dummy)
long inst;
{
	int ext = instfetch(2);
	int reg = (ext >> 12) & 07;
	int type, typename;

	type = (inst >> 9) & 03;
	type = type > 2 ? TLONG : type == 2 ? TWORD : TBYTE;
	typename = type == TLONG ? 'l' : type == TWORD ? 'w' : 'b';
	printf("\t%s2%c\t", ext & 0x800 ? "chk" : "cmp", typename);
	printEA(inst, type);
	printf(",%s", ext & 0x8000 ? A(reg) : D(reg));
}

ocall(inst, dummy)
long inst;
{
	printf("\tcallm\t#%X,", instfetch(2));
	printEA(inst, TLONG);
}

ocas(inst, dummy)
long inst;
{
	int ext, ext2;
	int type, typename;

	if ((inst & 077) == 074) {
		/* cas2 */
		type = (inst >> 9) & 03;
		type = type > 2 ? TLONG : TWORD;
		typename = type == TLONG ? 'l' : 'w';
		ext = instfetch(2);
		ext2 = instfetch(2);
		printf("\tcas2%c\td%X:d%X,d%X:d%X,(%s):(%s)",
		 typename,
		 ext & 07, ext2 & 07,
		 (ext >> 6) & 07, (ext2 >> 6) & 07,
		 ext & 0x8000 ? A((ext >> 12) & 07) : D((ext >> 12) & 07),
		 ext2 & 0x8000 ? A((ext2 >> 12) & 07) : D((ext2 >> 12) & 07));
		return;
	}
	/* cas */
	type = (inst >> 9) & 03;
	type = type > 2 ? TLONG : type == 2 ? TWORD : TBYTE;
	typename = type == TLONG ? 'l' : type == TWORD ? 'w' : 'b';
	ext = instfetch(2);
	printf("\tcas%c\td%X,d%X,", typename, ext & 07, (ext >> 6) & 07);
	printEA(inst, type);
}

obranch(inst,dummy)
long inst;
{
	long disp = inst & 0377;
	char *s; 


	s = "b ";
	if (disp == 0) {
		s = "w ";
		disp = instfetch(2);
		if (disp > 0x7fff)
			disp |= ~0xffff;
	}
	else if (disp == 0xFF) {
		s = "l ";
		disp = instfetch(4);
	}
	else if (disp > 0x7f)
		disp |= ~0xff;
	printf("\tb%s%s\t",bname[(int)((inst>>8)&017)],s);
	psymoff(disp+inkdot(2), ISYM, "");
}

char *
ccname(cond)
long cond;
{
	char *s;

	if (cond == 0) s = "t";
	else if (cond == 1) s = "f";
	else s = bname[cond];

	return s;
}

odbcc(inst,dummy)
long inst;
{
	long cond = (inst>>8)&0xF;
	long disp;

	printf("\tdb%s\td%X,", ccname(cond), inst&07);
	disp = instfetch(2);
	if (disp > 0x7fff)
		disp |= ~0xffff;
	psymoff(disp+inkdot(2), ISYM, "");
}

oscc(inst,dummy)
long inst;
{
	long cond = (inst>>8)&0xF;

	printf("\ts%s\t",ccname(cond));
	printea((inst>>3)&07,inst&07,TBYTE);
}

otrapcc(inst,dummy)
long inst;
{
	long cond = (inst>>8)&0xF;
	int size = inst & 07;

	printf("\ttrap%s\t",ccname(cond));
	if (size == 2)
		printf("#%w", instfetch(2));
	else if (size == 3)
		printf("#%W", instfetch(4));
}

biti(inst, dummy)
long inst;
{
	printf("\t%s\t", bit[(int)((inst>>6)&03)]);
	if (inst&0x0100) printf("d%D,", inst>>9);
	else { printf("#%x", instfetch(2)); printc(','); }
	printEA(inst, TLONG);
}

opmode(inst,opcode)
long inst;
char *opcode;
{
	register int mode = (int)((inst>>6) & 07);
	register int reg = (int)((inst>>9) & 07);
	int type;

	type = (mode==0 || mode==4) ?
		TBYTE : (mode==1 || mode==3 || mode==5) ? TWORD : TLONG;
	printf("\t%s%c\t", opcode, suffix(type));
	if (mode>=4 && mode<=6)
	{
		printf("d%d,",reg);
		printea((inst>>3)&07,inst&07,type);
	}
	else
	{
		printea((inst>>3)&07,inst&07,type);
		printf(",%s",(mode<=2)? D(reg) : A(reg));
	}
}


char *bfnames[] = { "tst", "extu", "chg", "exts", "clr", "ffo", "set", "ins" };

#define BFTST	0
#define BFEXTU	1
#define BFCHG	2
#define BFEXTS	3
#define BFCLR	4
#define BFFFO	5
#define BFSET	6
#define BFINS	7

obitfield(inst, dummy)
long inst;
{
	long bfop = (inst >> 8) & 7;
	long d_o, d_w, o, w;
	register long ext = instfetch(2);

	d_o = ext & 04000;
	o = (ext >> 6) & 037;
	d_w = ext & 040;
	w = ext & 037;

	printf("\tbf%s\t", bfnames[bfop]);

	if (bfop == BFINS)
		printf("d%X,", (ext >> 12) & 7);

	printEA(inst, TBYTE);
	printf("{%c%X:%c%X}", d_o ? 'd' : '#', o, d_w ? 'd' : '#', w);

	/* sleazy, but it works */
	if (bfop != BFINS && (bfop & 1))
		printf(",d%X", (ext >> 12) & 7);
}

shroi(inst,ds)
long inst;
char *ds;
{
	int rx, ry;
	char *opcode;
	if ((inst & 0xC0) == 0xC0)
	{
		opcode = shro[(int)((inst>>9)&03)];
		printf("\t%s%s\t", opcode, ds);
		printEA(inst, TLONG);
	}
	else
	{
		opcode = shro[(int)((inst>>3)&03)];
		printf("\t%s%s%c\t", opcode, ds, suffix(mapsize(inst)));
		rx = (int)((inst>>9)&07); ry = (int)(inst&07);
		if ((inst>>5)&01) printf("d%d,d%d", rx, ry);
		else
		{
			printf("#%X", (rx ? rx : 8));
			printf(",d%d", ry);
		}
	}
}		

oimmed(inst,opcode) 
long inst;
register char *opcode;
{
	register int type = mapsize(inst);
	long con;

	if ((unsigned) type <= TDPDREAL)
	{
		con = instfetch(type==TLONG?4:2);
		printf("\t%s%c\t", opcode, suffix(type));
		printf(type == TWORD ? "#%w" : "#%W", con);
		printc(',');
		printEA(inst,type);
	}
	else printf(badop);
}

ouimmed(inst,opcode) 
long inst;
register char *opcode;
{
	register int type = mapsize(inst);
	long con;

	if ((unsigned) type <= TDPDREAL)
	{
		con = instfetch(type==TLONG?4:2);
		if ((inst & 077) == 074) {
			printf("\t%si\t", opcode);
			printf("#%X,", con);
			printf((inst & 0300) == 0 ? "cc" : "sr");
			return;
		}
		printf("\t%s%c\t", opcode, suffix(type));
		printf("#%X", con); printc(',');
		printEA(inst,type);
	}
	else printf(badop);
}

oreg(inst,opcode)
long inst;
register char *opcode;
{
	printf(opcode, (inst & 07));
}

extend(inst, opcode)
long	inst;
char	*opcode;
{
	register int type = mapsize(inst);
	int ry = (inst&07), rx = ((inst>>9)&07);
	char c;

	c = ((inst & 0x1000) ? suffix(type) : ' ');
	printf("\t%s%c\t", opcode, c);
	if (*opcode == 'e')
	{
		if (inst & 0x0080) printf("d%D,%s", rx, A(ry));
		else if (inst & 0x0008) {
			printf("%s,", A(rx));
			printf("%s", A(ry));
		} else printf("d%D,d%D", rx, ry);
	}
	else if ((inst & 0xF000) == 0xB000) {
		printf("%s@+,", A(ry));
		printf("%s@+", A(rx));
	} else if (inst & 0x8) {
		printf("%s@-,", A(ry));
		printf("%s@-", A(rx));
	} else printf("d%D,d%D", ry, rx);
	if (*opcode == 'p' || *opcode == 'u') /* pack and unpk */
		printf(",#%X", instfetch(2));
}

olink(inst,s)
long inst;
char *s;
{
	int size = (*s == 'w') ? 2 : 4;

	printf("\tlink%c\ta%D,", *s, inst&07);
	printf(size == 2 ? "#%w" : "#%W", instfetch(size));
}

ortd(inst, dummy)
long inst;
{
	printf("\trtd\t#%W", instfetch(2));
}

ortm(inst, dummy)
long inst;
{
	printf("\trtm\t%s", inst & 8 ? A(inst & 7) : D(inst & 7));
}

otrap(inst,dummy)
long inst;
{
	printf("\ttrap\t");
	printf("#%X", inst&017);
}

oneop(inst,opcode)
long inst;
register char *opcode;
{
	printf("\t%s\t",opcode);
	printEA(inst,TLONG);
}

pregmask(mask)
register int mask;
{
	register int i;
	register int flag = 0;

	printf("#<");
	for (i=0; i<16; i++)
	{
		if (mask&1)
		{
			if (flag) printc(','); else flag++;
			printf("%s",(i<8)? D(i) : A(i&7));
		}
		mask >>= 1;
	}
	printf(">");
}

omovem(inst,dummy)
long inst;
{
	register int i, list = 0, mask = 0100000;
	register int reglist = (int)(instfetch(2));

	if ((inst & 070) == 040)	/* predecrement */
	{
		for(i = 15; i > 0; i -= 2)
		{ list |= ((mask & reglist) >> i); mask >>= 1; }
		for(i = 1; i < 16; i += 2)
		{ list |= ((mask & reglist) << i); mask >>= 1; }
		reglist = list;
	}
	printf("\tmovem%c\t",(inst&100)?'l':'w');
	if (inst&02000)
	{
		printEA(inst,TLONG);
		printc(',');
		pregmask(reglist);
	}
	else
	{
		pregmask(reglist);
		printc(',');
		printEA(inst,TLONG);
	}
}

ochk(inst,opcode)
long inst;
register char *opcode;
{
	int reg = (inst>>9)&07;

	printf("\t%s\t",opcode);
	printEA(inst, (inst & 0700) == 0600 ? TWORD : TLONG);
	printf(",%s", (*opcode=='l') ? A(reg) : D(reg));
}

odivmul(inst,opcode)
long inst;
register char *opcode;
{
	printf("\t%s%c",opcode,(inst&0x0100)?'s':'u');
	printc('w');
	printc('\t');
	printEA(inst,TWORD);
	printf(",d%D",(inst>>9)&07);
}

odivmull(inst, opcode)
long inst;
register char *opcode;
{
	long inst2 = instfetch(2);
	int dl, dr;

	dl = inst2 & 07;
	dr = (inst2>>12)&07;
	printf("\t%s%cl", opcode, (inst2 & 0x0800) ? 's' : 'u');
	if ((inst2 & 0x0400) == 0 && *opcode == 'd' && dl != dr)
		printc('l');
	printc('\t');
	printEA(inst,TLONG);
	printc(',');
	if ((inst2 & 0x0400) || (*opcode == 'd' && dl != dr))
		printf("d%D:", dl);
	printf("d%D", dr);
}

soneop(inst,opcode)
long inst;
register char *opcode;
{
	register int type = mapsize(inst);

	if ((unsigned) type <= TDPDREAL)
	{
		printf("\t%s%c\t",opcode,suffix(type));
		printEA(inst,type);
	}
	else printf(badop);
}

oquick(inst,opcode)
long inst;
register char *opcode;
{
	register int type = mapsize(inst);
	register int data = (int)((inst>>9) & 07);

	if (data == 0) data = 8;
	if ((unsigned) type <= TDPDREAL)
	{
		printf("\t%s%c\t", opcode, suffix(type));
		printf("#%X", data); printc(',');
		printEA(inst, type);
	}
	else printf(badop);
}

omoveq(inst,dummy)
long inst;
{
	register int data = (int)(inst & 0377);

	if (data > 127) data |= ~0377;
	printf("\tmoveq\t"); printf("#%W", data);
	printf(",d%D", (inst>>9)&07);
}

oprint(inst,opcode)
long inst;
register char *opcode;
{
	printf("\t%s",opcode);
}

/*
 * Print 68881 floating point instructions.
 */

extern fop(), foneop(), fmovem(), fmovex(), fmemmove();
extern fmover(), fmovec(), fsincos();

struct opdesc fopdecode[] = {
  0xc700, 0xc000, fmovem, 0,
  0xe000, 0x2000, fmovex, 0,
  0xe000, 0x6000, fmemmove, 0,
  0xc3ff, 0x8000, fmover, 0,
  0xfc00, 0x5c00, fmovec, 0,
  0xa07f, 0x0000, fop, "move",
  0xa07f, 0x0001, fop, "int",
  0xa07f, 0x0002, fop, "sinh",
  0xa07f, 0x0003, fop, "intrz",
  0xa07f, 0x0004, fop, "sqrt",
  0xa07f, 0x0006, fop, "lognp1",
  0xa07f, 0x0008, fop, "etoxm1",
  0xa07f, 0x0009, fop, "tanh",
  0xa07f, 0x000a, fop, "atan",
  0xa07f, 0x000c, fop, "asin",
  0xa07f, 0x000d, fop, "atanh",
  0xa07f, 0x000e, fop, "sin",
  0xa07f, 0x000f, fop, "tan",
  0xa07f, 0x0010, fop, "etox",
  0xa07f, 0x0011, fop, "twotox",
  0xa07f, 0x0012, fop, "tentox",
  0xa07f, 0x0014, fop, "logn",
  0xa07f, 0x0015, fop, "log10",
  0xa07f, 0x0016, fop, "log2",
  0xa07f, 0x0018, fop, "abs",
  0xa07f, 0x0019, fop, "cosh",
  0xa07f, 0x001a, fop, "neg",
  0xa07f, 0x001c, fop, "acos",
  0xa07f, 0x001d, fop, "cos",
  0xa07f, 0x001e, fop, "getexp",
  0xa07f, 0x001f, fop, "getman",
  0xa07f, 0x0020, fop, "div",
  0xa07f, 0x0021, fop, "mod",
  0xa07f, 0x0022, fop, "add",
  0xa07f, 0x0023, fop, "mul",
  0xa07f, 0x0024, fop, "sgldiv",
  0xa07f, 0x0025, fop, "rem",
  0xa07f, 0x0026, fop, "scale",
  0xa07f, 0x0027, fop, "sglmul",
  0xa07f, 0x0028, fop, "sub",
  0xa078, 0x0030, fsincos, 0,
  0xa07f, 0x0038, fop, "cmp",
  0xa07f, 0x003a, foneop, "tst",
  0, 0, 0, 0
};

ofloat(inst, dummy)
	long inst;
{
	register struct opdesc *p;
	register long inst2 = instfetch(2);

	for (p = fopdecode; p->mask; p++)
		if ((inst2 & p->mask) == p->match) break;
	if (p->mask != 0) (*p->opfun)(inst, inst2, p->farg);
	else printf(badop);
}

#define	fmemsrc(i2)	((i2) & 0x4000)
#define	fmode(i)	(((i) >> 3) & 7)
#define	freg(i)		((i) & 7)
#define	ftype(i2)	(int)(((i2) >> 10) & 7)
#define	fregsrc(i2)	ftype(i2)
#define	fregdst(i2)	(((i2) >> 7) & 7)

fop(inst, inst2, opcode)
	long inst, inst2;
	char *opcode;
{
	if (fmemsrc(inst2)) {
		printf("\tf%s%c\t", opcode, suffix(ftype(inst2)));
		printea(fmode(inst), freg(inst), ftype(inst2));
	} else
		printf("\tf%sx\tfp%X", opcode, fregsrc(inst2));
	if (fmemsrc(inst2) || fregsrc(inst2) != fregdst(inst2))
		printf(",fp%X", fregdst(inst2));
}

foneop(inst, inst2, opcode)
	long inst, inst2;
	char *opcode;
{
	if (fmemsrc(inst2)) {
		printf("\tf%s%c\t", opcode, suffix(ftype(inst2)));
		printea(fmode(inst), freg(inst), ftype(inst2));
	} else
		printf("\tf%sx\tfp%X", opcode, fregsrc(inst2));
}

/*ARGSUSED*/
fmemmove(inst, inst2, dummy)
	long inst, inst2;
	char *dummy;
{
	int type = ftype(inst2);

	printf("\tfmove%c\tfp%X,", suffix(type), fregdst(inst2));
	printea(fmode(inst), freg(inst), type);
	if (type == 3)
		printf("{#%d}", (inst2&0x7f));
	else if (type == 7)
		printf("{d%D}", ((inst2>>4)&0x7));
}

fpregmask(mask)
	register int mask;
{
	register int i;
	register int flag = 0;

	printf("#<");
	for (i=0; i<8; i++) {
		if (mask&1) {
			if (flag)
				printc(',');
			else
				flag++;
			printf("fp%X", i);
		}
		mask >>= 1;
	}
	printf(">");
}

#define ffromreg(i2)	((i2) & 0x2000)
#define	fmmode(i2)	(((i2) >> 11) & 3)
#define	freglist(i2)	((i2) & 0xff)
#define	fdynreg(i2)	(((i2) >> 4) & 7)

/*ARGSUSED*/
fmovem(inst, inst2, dummy)
	long inst, inst2;
	char *dummy;
{
	register int i, reglist, oreglist;
	int dynreg;

	switch ((int)fmmode(inst2)) {

	case 0:	/* static + predecrement */
		dynreg = -1;
		reglist = freglist(inst2);
		break;

	case 2:	/* static + postincrement or control mode */
		/* reverse the register mask */
		/* is this really backwards from movem?!? */
		dynreg = -1;
		oreglist = freglist(inst2);
		reglist = 0;
		for (i = 0; i < 8; ++i)
			if (oreglist & 1 << (7 - i))
				reglist |= 1 << i;
		break;

	case 1:	/* dynamic + predecrement */
	case 3:	/* dynamic + postincrement or control */
		dynreg = fdynreg(inst2);
		break;
	}

	printf("\tfmovem\t");
	if (ffromreg(inst2)) {
		if (dynreg >= 0)
			printf("d%X<>", dynreg);
		else
			fpregmask(reglist);
		printf(",");
		printea(fmode(inst), freg(inst), TXPREAL);
	} else {
		printea(fmode(inst), freg(inst), TXPREAL);
		printf(",");
		if (dynreg >= 0)
			printf("d%X<>", dynreg);
		else
			fpregmask(reglist);
	}
}

fpintregname(regnum)
	int regnum;
{
	switch (regnum) {
	case 1:	printf("FPIAR"); break;
	case 2:	printf("FPSR"); break;
	case 4:	printf("FPCR"); break;
	default: printf("???"); break;
	}
}

#define	fintregname(i2)	(int)(((i2) >> 10) & 7)

/*ARGSUSED*/
fmovex(inst, inst2, dummy)
	long inst, inst2;
	char *dummy;
{
	printf("\tfmover\t");
	if (ffromreg(inst2)) {
		fpintregname(fintregname(inst2));
		printf(",");
		printea(fmode(inst), freg(inst), TLONG);
	} else {
		printea(fmode(inst), freg(inst), TLONG);
		printf(",");
		fpintregname(fintregname(inst2));
	}
}

fpintregmask(reglist)
	register int reglist;
{
	printf("#<");
	if (reglist & 1) {
		printf("FPIAR");
		if (reglist & 6)
			printf(",");
	}
	if (reglist & 2)
		printf("FPSR");
	if (reglist & 4) {
		if (reglist & 3)
			printf(",");
		printf("FPCR");
	}
	printf(">");
}

#define	fintreglist(i2)	(int)(((i2) >> 10) & 7)

/*ARGSUSED*/
fmover(inst, inst2, dummy)
	long inst, inst2;
	char *dummy;
{
	printf("\tfmover\t");
	if (ffromreg(inst2)) {
		fpintregmask(fintreglist(inst2));
		printf(",");
		printea(fmode(inst), freg(inst), TLONG);
	} else {
		printea(fmode(inst), freg(inst), TLONG);
		printf(",");
		fpintregmask(fintreglist(inst2));
	}
}

static struct romtab {
	int romoff;
	char *romname;
} romtab[] = {
	0x00,	"pi",
	0x0b,	"log10_2",
	0x0c,	"e",
	0x0d,	"log2_e",
	0x0e,	"log10_e",
	0x0f,	"0",
	0x30,	"ln_2",
	0x31,	"ln_10",
	0x32,	"1",
	0x33,	"10",
	0x34,	"10e2",
	0x35,	"10e4",
	0x36,	"10e8",
	0x37,	"10e16",
	0x38,	"10e32",
	0x39,	"10e64",
	0x3a,	"10e128",
	0x3b,	"10e256",
	0x3c,	"10e512",
	0x3d,	"10e1024",
	0x3e,	"10e2048",
	0x3f,	"10e4096",
	-1,	"???"
};

#define	foffrom(i2)	((i2) & 0x7f)

/*ARGSUSED*/
fmovec(inst, inst2, dummy)
	long inst, inst2;
	char *dummy;
{
	register struct romtab *p;
	register int off;

	off = foffrom(inst2);
	for (p = romtab; p->romoff >= 0 && p->romoff != off; ++p)
		;
	printf("\tfmovec\t#%s,fp%X", p->romname, fregdst(inst2));
}

#define	fcosdst(i2)	((i2) & 7)

/*ARGSUSED*/
fsincos(inst, inst2, dummy)
	long inst, inst2;
	char *dummy;
{
	if (fmemsrc(inst2)) {
		printf("\tfsincos%c\t", suffix(ftype(inst2)));
		printea(fmode(inst), freg(inst), ftype(inst2));
	} else
		printf("\tfsincosx\tfp%X", fregsrc(inst2));
	/* so why does motorola insist on the order cos:sin? */
	printf(",fp%X:fp%X", fcosdst(inst2), fregdst(inst2));
}

static char *fbnames[32] = {
	"f", "eq", "ogt", "oge", "olt", "ole", "ogl", "or",
	"un", "ueq", "ugt", "uge", "ult", "ule", "ne", "t",
	"sf", "seq", "gt", "ge", "lt", "le", "gl", "gle",
	"ngle", "ngl", "nle", "nlt", "nge", "ngt", "sne", "st"
};

#define	fbname(c)	((unsigned)(c) < 32 ? fbnames[(c)] : "???")
#define	fcountreg(i)	((i) & 7)

/*ARGSUSED*/
ofdbcc(inst, dummy)
	long inst;
	char *dummy;
{
	int cond = instfetch(2);
	long disp = instfetch(2);

	printf("\tfdb%s\td%X,", fbname(cond), fcountreg(inst));
	if (disp > 0x7fff)
		disp |= ~0xffff;
	psymoff(disp+inkdot(4), ISYM, "");
}

#define	ftrapmode(i)	((i) & 7)

/*ARGSUSED*/
oftrapcc(inst, dummy)
	long inst;
	char *dummy;
{
	int cond;

	if (ftrapmode(inst) < 2)		/* XXX */
		ofscc(inst, dummy);
	else {
		cond = instfetch(2);
		printf("\tftrap%s", fbname(cond));
		if (ftrapmode(inst) == 2)
			printf("w\t#%w", instfetch(2));
		else if (ftrapmode(inst) == 3)
			printf("l\t#%W", instfetch(4));
	}
}

/*ARGSUSED*/
ofscc(inst, dummy)
	long inst;
	char *dummy;
{
	int cond = instfetch(2);

	printf("\tfs%s\t", fbname(cond));
	printea(fmode(inst), freg(inst), TBYTE);
}

#define	fbcond(i)	((i) & 0x3f)

ofbranch(inst, size)
	long inst;
	char *size;
{
	int cond = fbcond(inst);
	long disp;

	if (*size == 'w') {
		disp = instfetch(2);
		if (disp > 0x7fff)
			disp |= ~0xffff;
	} else
		disp = instfetch(4);
	if (inst == 0xf280 && disp == 0)	/* XXX */
		printf("\tfnop");
	else {
		printf("\tfb%s%s\t", fbname(cond), size);
		psymoff(disp+inkdot(2), ISYM, "");
	}
}

ofsaverestore(inst, opcode)
	long inst;
	char *opcode;
{
	printf("\tf%s\t", opcode);
	printea(fmode(inst), freg(inst), TLONG);
}



/*
 * Generic coprocessor instruction support.
 */

ocpgen(inst, dummy)
	long inst;
{
	register long inst2 = instfetch(2);

	printf("\tcp%Xgen_%x\t", (inst >> 9) & 07, inst2);
	printea(fmode(inst), freg(inst), TLONG);
}

/*ARGSUSED*/
ocpdbcc(inst, dummy)
	long inst;
	char *dummy;
{
	int cond = instfetch(2);
	long disp = instfetch(2);

	printf("\tcp%Xdb%s\td%X,", (inst >> 9) & 07,
		fbname(cond), fcountreg(inst));
	if (disp > 0x7fff)
		disp |= ~0xffff;
	psymoff(disp+inkdot(4), ISYM, "");
}

/*ARGSUSED*/
ocptrapcc(inst, dummy)
	long inst;
	char *dummy;
{
	int cond;

	if (ftrapmode(inst) < 2)		/* XXX */
		ocpscc(inst, dummy);
	else {
		cond = instfetch(2);
		printf("\tcp%Xtrap%s", (inst >> 9) & 07, fbname(cond));
		if (ftrapmode(inst) == 2)
			printf("w\t#%w", instfetch(2));
		else if (ftrapmode(inst) == 3)
			printf("l\t#%W", instfetch(4));
	}
}

/*ARGSUSED*/
ocpscc(inst, dummy)
	long inst;
	char *dummy;
{
	int cond = instfetch(2);

	printf("\tcp%Xs%s\t", (inst >> 9) & 07, fbname(cond));
	printea(fmode(inst), freg(inst), TBYTE);
}

ocpbranch(inst, size)
	long inst;
	char *size;
{
	int cond = fbcond(inst);
	int cpid = (inst >> 9) & 07;
	long disp;

	if (*size == 'w') {
		disp = instfetch(2);
		if (disp > 0x7fff)
			disp |= ~0xffff;
	} else
		disp = instfetch(4);
	if ((inst & 0x7f) == 0 && disp == 0)	/* XXX */
		printf("\tcp%Xnop", cpid);
	else {
		printf("\tcp%Xb%s%s\t", cpid, fbname(cond), size);
		psymoff(disp+inkdot(2), ISYM, "");
	}
}

ocpsaverestore(inst, opcode)
	long inst;
	char *opcode;
{
	printf("\tcp%X%s\t", (inst >> 9) & 07, opcode);
	printea(fmode(inst), freg(inst), TLONG);
}