/*
 * disasm.c: version 1.4 of 6/3/85
 *
 * Disassembler for the debugger monitor
 * copyright (c) 1984  American Information Systems Corporation
 *  Dock Williams   March, 1984
 */

#include "monitor.h"
#include "vctype.h"
#include "mondef.h"

extern OP1 ops1[];
extern OP2 ops2[];
extern OP3 ops3[];
extern char *preg[];	/* processor registers */
extern char *rnm[];	/* register for relative addressing modes */
extern char *sname[];	/* mmu registers */
extern short flen[2];	/* length parameters for f, l */


/*
 * disassemble an instruction
 * at address addr, return its length
 */
mdisasm(addr,print,map)
int addr, print;
{
	register int ins,tmp;

	tmp = mapping;		/* save old mapping */
	mapping = map;		/* use argument mapping */
	ins = mrdquad(addr,mapping);

	dot = addr;
	pflag = print;
	switch (ins & 7) {
	case 2:
		incp = 1;
		op1(ins);
		break;
	case 6:
		incp = 3;
		op3(ins);
		break;
	default:
		incp = 2;
		op2(ins);
		break;
	}

	mapping = tmp;		/* restore mapping */
	return(incp);
}

op1(a)
register int a;
{
	register struct o1 *p;

	a &= 0xff;
	for (p=ops1; p->val != 0; p++) {
		if (p->val == a) {
			if (pflag) printf("%s\t", p->name);
			if (p->extra) {
				do_extra(p->extra);
			}
			return;
		}
	}
	if (pflag) OUTCHR('?');
}

op2(a)
register int a;
{
	register struct o2 *p;
	short cmp;

	a &= 0xffff;
	cmp = a>>2;
	for (p=ops2; p->mask != 0; p++) {
		if (p->val == (cmp & p->mask)) {
			if (pflag) printf(p->name);
			if (p->allow != 2) {
				if (pflag) OUTCHR("bw?d"[a&3]);
			}
			if (pflag) OUTCHR('\t');
			switch (p->type) {
			case 0:
				gen2(a>>11, (a>>6)&0x1f, a&3, a&3);
				break;
			case 1:
				quick((a>>7)&0xf);
				if (pflag) OUTCHR(',');
				gen1(a>>11, a&3);
				break;
			case 2:
				gen1(a>>11, a&3);
				break;
			case 3:
				if (pflag) printf("%s,", preg[(a>>7)&0xf]);
				gen1(a>>11, a&3);
				break;
			}
			if (p->extra) {
				if (pflag) OUTCHR(',');
				do_extra(p->extra);
			}
			return;
		}
	}
	if (pflag) printf("??");
}

op3(a)
register int a;
{
	register int itype, ftype;
	int i;
	short l1, l2;
	register struct o3 *p;
	short cmp;

	a &= 0xffffff;
	cmp = a >> 3;
	for (p=ops3; p->mask != 0; p++) {
		if (p->val == (cmp & p->mask)) {
			if (pflag) printf(p->name);
			switch (p->typef) {
			case 0:
				itype = (a>>8)&3;
				l1 = l2 = itype;
				if (pflag) OUTCHR("bw?d"[itype]);
				break;
			case 1:
				ftype = (a>>8)&1;
				l1 = l2 = flen[ftype];
				if (pflag) OUTCHR("lf"[ftype]);
				break;
			case 2:
				itype = (a>>8)&3;
				ftype = (a>>10) & 1;
				l1 = flen[ftype];
				l2 = itype;
				if (pflag) {
					OUTCHR("lf"[ftype]);
					OUTCHR("bw?d"[itype]);
				}
				break;
			case 3:
				itype = (a>>8)&3;
				ftype = (a>>10) & 1;
				l1 = itype;
				l2 = flen[ftype];
				if (pflag) {
					OUTCHR("bw?d"[itype]);
					OUTCHR("lf"[ftype]);
				}
				break;
			case 4:
				l1 = l2 = 3;
				break;
			case 5:
				l1 = flen[0];
				l2 = flen[1];
				break;
			case 6:
				l1 = flen[1];
				l2 = flen[0];
				break;
			}
			if (pflag) OUTCHR('\t');
			if (p->regf == 0) {
				if (pflag) printf("r%d,", (a>>11) & 7);
			}
			if (p->f1 == 0 && p->f2 == 0) {
				gen2(a>>19, (a>>14)&0x1f, l1, l2);
			} else {
				i = (a>>14) & 0x1f;
				if (p->f2 == 3) {
					do_ss(i>>1);
					if (pflag) OUTCHR(',');
				}
				if (p->f1 == 0) {
					gen1(a>>19, l1);
					if (p->f2 != 3)
						if (pflag) OUTCHR(',');
				}
				if (p->f1 >= 4) {
					gen1(a>>19, p->f1 - 4);
					if (pflag) OUTCHR(',');
				}
				switch (p->f2) {
				case 0:
					gen1(i, l1);
					break;
				case 1:
					do_uwb(i>>2);
					break;
				case 2:
					do_xx(i>>1);
					break;
				case 3:
					break;
				default:
					gen1(i, p->f2 - 4);
					break;
				}
			}
			if (p->extra) {
				if (pflag) OUTCHR(',');
				do_extra(p->extra);
			}
			return;
		}
	}
	if (pflag) printf("??");
}

gen2(m1, m2, l1, l2)
register int m1,m2;
int l1,l2;
{
	int idx1, idx2;

	if (m1 >= 0x1c) { /* scaled indexing */
		idx1 = egetchar();
	}
	if (m2 >= 0x1c) {
		idx2 = egetchar();
	}
	if (m1 >= 0x1c)
		sc_gen(idx1, m1&3);
	else
		sub_gen(m1, l1);
	if (pflag) OUTCHR(',');
	if (m2 >= 0x1c)
		sc_gen(idx2, m2&3);
	else
		sub_gen(m2, l2);
}
gen1(mode, len)
{
	int idx;

	if (mode >= 0x1c) {	/* scaled indexing */
		idx = egetchar();
		sc_gen(idx, mode&3);
	} else
		sub_gen(mode, len);
}
quick(x)
{
	if (pflag) {
		if (x <= 7) {
			printf("$%d", x);
		} else
			printf("$%d", x-16);
	}
}

/* scaled indexing - index byte in idx, scale factor in slen */
sc_gen(idx, slen)
{
	int mode, reg;

	mode = idx>>3;
	reg = idx & 7;
	if (mode == 0x14) {	/* immediate */
		if (pflag) printf("BAD");
		return;
	}
	sub_gen(mode, 0);
	if (pflag) printf("[r%d:%c]", reg, "bwdq"[slen]);
}

/* generic, but not scaled - */
sub_gen(mode, len)
register int mode;
int len;
{
	register int d1, d2;

	if (mode <= 7) {	/* register */
		if (pflag) printf("%c%d", (len & 8) ? 'f' : 'r', mode);
		return;
	}
	if (mode <= 15) {	/* register relative */
		d1 = getdisp();
		if (pflag) printf("0x%x(r%d)", d1, mode&7);
		return;
	}
	if (mode <= 18) {	/* memory relative */
		d1 = getdisp();
		d2 = getdisp();
		if (pflag) printf("0x%x(0x%x(%s))", d2, d1, rnm[mode-16]);
		return;
	}
	if (mode >= 0x18) {	/* memory space */
		d1 = getdisp();
		if (pflag) printf("0x%x(%s)", d1, rnm[mode-0x18]);
		return;
	}
	switch (mode) {
	case 0x14:	/* immediate */
		putimm(len);
		return;
	case 0x15:	/* absolute */
		d1 = getdisp();
		if (pflag) printf("@0x%x",d1);
		return;
	case 0x16:	/* external */
		d1 = getdisp();
		d2 = getdisp();
		if (pflag) printf("ext(0x%x)0x%x", d1, d2);
		return;
	case 0x17:	/* top of stack */
		if (pflag) printf("tos");
		return;
	default:
		if (pflag) printf("??");
	}
}

/* get a 1 to 4 byte signed displacement */
int
getdisp()
{
	register int a, b, c, d;

	a = egetchar();
	if ((a & 0x80) == 0) {
		if (a < 0x40)
			return(a);
		else
			return(a-0x80);
	}
	if ((a & 0xc0) == 0x80) {	/* short */
		b = egetchar();
		a = a<<8 | b;
		a &= 0x3fff;
		if (a < 0x2000)
			return(a);
		else
			return(a-0x4000);
	}
	/* long */
	b = egetchar(); c = egetchar(); d = egetchar();
	a = (a << 24) | (b << 16) | (c << 8) | d;
	a &= 0x3fffffff;
	if (a < 0x20000000)
		return(a);
	else
		return(a - 0x40000000);
}

/* print a 1 to 4 byte immediate */
/* or a 4 or 8 byte floating immediate */
int
putimm(len)
{
	register int a, x;
	register int i;
	int flo;

	flo = len & 8;
	len &= 7;
	x = 0;
	for (i=0; i<=len; i++) {
		a = egetchar();
		if (i <= 3)
			x = x<<8 | a;
	/* note that bytes are backwards in immediates! */
	}

#ifdef notdef
/*************** AIS - floating point not supported
	if (flo) {
		int f, e;
		double ldexp();
		double d;

		if (len == 3) {	/* float */
			f = (x & 0x7fffff) | 0x800000;
			e = ((x>>23) & 0xff) - 127;
			e -= 23;
		} else {
			f = (x & 0xfffff) | 0x100000;
			e = ((x>>20) & 0x7ff) - 1023;
			e -= 20;
		}
		d = ldexp((double)f, e);
		if (x < 0)
			d = -d;
		if (pflag) printf("$%-32.18F", d);
	} else {
*************************************************/
#endif notdef

	{
		if (len == 0 && (x & 0x80) != 0)
			x |= 0xffffff00;
		else if (len == 1 && (x & 0x8000) != 0)
			x |= 0xffff0000;
		if (pflag) printf("$0x%x",x);
	}
}

egetchar()
{
	int a;

	a = mrdbyte(dot+incp,mapping);
	incp++;
	return(a);
}

do_extra(x)
register int x;
{
	register int a, i, j;
	int some = 0;
	int disp;

	if (x & (1|8)) {	/* reglist */
		a = egetchar();
		if (pflag) OUTCHR('[');
		for (i=0; i<8; i++) {
			j = (x&1) ? 0x80>>i : 1<<i;
			if (a & j) {
				if (some)
					if (pflag) OUTCHR(',');
				if (pflag) printf("r%d", i);
				some++;
			}
		}
		if (pflag) OUTCHR(']');
		some++;
	}
	if (x & (2|16)) {	/* disp */
		if (some) {
			if (pflag) OUTCHR(',');
		} else
			some++;
		disp = getdisp();
		if (x & 2)
		{
			if (pflag) printf("0x%x", disp);
		} else {
			if (pflag) printf("0x%x", dot + disp);
			/* AIS- if (pflag) psymoff(dot + disp, ISYM, ""); */
		}
	}
	if (x & 4) {	/* short offset,len */
		if (some)
			if (pflag) OUTCHR(',');
		a = egetchar();
		if (pflag) printf("0x%x,0x%x", a>>5, (a&0x1f)+1);
	}
}

do_ss(x)
{
	if (pflag) printf(sname[x]);
}

do_uwb(x)
{
	prbits(x,"bwu");
}

do_xx(x)
{
	prbits(x,"ifmc");
}

prbits(x,str)
register int x;
register char *str;
{
	register int i, some;

	some = 0;
	if (pflag) OUTCHR('[');
	for (i=0; i<4; i++) {
		if (x & (1<<i)) {
			if (some) {
				if (pflag) OUTCHR(',');
			} else
				some++;
			if (pflag) OUTCHR(str[i]);
		}
	}
	if (pflag) OUTCHR(']');
}

