/*
 * 5799-WZQ (C) COPYRIGHT IBM CORPORATION 1986
 * LICENSED MATERIALS - PROPERTY OF IBM
 * REFER TO COPYRIGHT INSTRUCTIONS FORM NUMBER G120-2083
 */
/* $Header:unasm.c 12.0$ */
/* $ACIS:unasm.c 12.0$ */
/* $Source: /ibm/acis/usr/sys/standca/RCS/unasm.c,v $ */

#ifndef lint
static char *rcsid = "$Header:unasm.c 12.0$";
#endif

/* disassembler for ibm032 -- 1/84 by J.Christensen */

/* instruction formats */

#define UNK   0
#define JI    1
#define RI    2
#define RI16  3
#define RR    4
#define SRI   5
#define SRR   6
#define R00   7
#define R0R   8
#define RRR   9
#define RC   10
#define BI   11
#define BRI  12
#define BA   13
#define DSC  14			       /* see note 1 */
#define DSH  15			       /* see note 1 */
#define DSL  16			       /* see note 1 */
#define DIR  17
#define DRI  18
#define DIIR 19
#define DRIR 20
#define DRRI 21
#define DTI  22

/* instruction decode tables */

static char ltab[] = {
	2,			       /* UNK  */
	2,			       /* JI   */
	2,			       /* RI   */
	2,			       /* RI16 */
	2,			       /* RR   */
	2,			       /* SRI  */
	2,			       /* SRR  */
	2,			       /* R00  */
	2,			       /* R0R  */
	2,			       /* RRR  */
	2,			       /* RC   */
	4,			       /* BI   */
	4,			       /* BRI  */
	4,			       /* BA   */
	2,			       /* DSC  */
	2,			       /* DSH  */
	2,			       /* DSL  */
	4,			       /* DIR  */
	4,			       /* DRI  */
	4,			       /* DIIR */
	4,			       /* DRIR */
	4,			       /* DRRI */
	4,			       /* DTI  */
};

struct s_tXX {
	char opc[7];
	char fmt;
};

static struct s_tXX t0X[] = {
	"j     ", JI,
};
static struct s_tXX t1X[] = {
	"stcs  ", DSC,
};
static struct s_tXX t2X[] = {
	"sths  ", DSH,
};
static struct s_tXX t3X[] = {
	"sts   ", DSL,
};
static struct s_tXX t4X[] = {
	"lcs   ", DSC,
};
static struct s_tXX t5X[] = {
	"lhas  ", DSH,
};
static struct s_tXX t6X[] = {
	"cas   ", RRR,
};
static struct s_tXX t7X[] = {
	"ls    ", DSL,
};
static struct s_tXX t8X[] = {
	"???   ", UNK,		       /* 0x80 */
	"???   ", UNK,		       /* 0x81 */
	"???   ", UNK,		       /* 0x82 */
	"???   ", UNK,		       /* 0x83 */
	"???   ", UNK,		       /* 0x84 */
	"???   ", UNK,		       /* 0x85 */
	"???   ", UNK,		       /* 0x86 */
	"???   ", UNK,		       /* 0x87 */
	"b     ", BI,		       /* 0x88 */
	"b     ", BI,		       /* 0x89 */
	"bala  ", BA,		       /* 0x8A */
	"balax ", BA,		       /* 0x8B */
	"bali  ", BRI,		       /* 0x8C */
	"balix ", BRI,		       /* 0x8D */
	"b     ", BI,		       /* 0x8E */
	"b     ", BI,		       /* 0x8F */
};
static struct s_tXX t9X[] = {
	"ais   ", RI,		       /* 0x90 */
	"inc   ", RI,		       /* 0x91 */
	"sis   ", RI,		       /* 0x92 */
	"dec   ", RI,		       /* 0x93 */
	"cis   ", RI,		       /* 0x94 */
	"clrsb ", SRI,		       /* 0x95 */
	"mfs   ", SRR,		       /* 0x96 */
	"setsb ", SRI,		       /* 0x97 */
	"clrb  ", RI,		       /* 0x98 *//* clbbu */
	"clrb  ", RI16,		       /* 0x99 *//* clbbl */
	"setb  ", RI,		       /* 0x9A *//* setbu */
	"setb  ", RI16,		       /* 0x9B *//* setbl */
	"mftbi ", RI,		       /* 0x9C *//* mftbiu */
	"mftbi ", RI16,		       /* 0x9D *//* mftbil */
	"mttbi ", RI,		       /* 0x9E *//* mttbiu */
	"mttbi ", RI16,		       /* 0x9F *//* mttbil */
};
static struct s_tXX tAX[] = {
	"sari  ", RI,		       /* 0xA0 *//* sari   */
	"sari  ", RI16,		       /* 0xA1 *//* sari16 */
	"???   ", UNK,		       /* 0xA2 */
	"???   ", UNK,		       /* 0xA3 */
	"lis   ", RI,		       /* 0xA4 */
	"???   ", UNK,		       /* 0xA5 */
	"???   ", UNK,		       /* 0xA6 */
	"???   ", UNK,		       /* 0xA7 */
	"sri   ", RI,		       /* 0xA8 *//* sri   */
	"sri   ", RI16,		       /* 0xA9 *//* sri16 */
	"sli   ", RI,		       /* 0xAA *//* sli   */
	"sli   ", RI16,		       /* 0xAB *//* sli16 */
	"srpi  ", RI,		       /* 0xAC *//* srpi   */
	"srpi  ", RI16,		       /* 0xAD *//* srpi16 */
	"slpi  ", RI,		       /* 0xAE *//* slpi   */
	"slpi  ", RI16,		       /* 0xAF *//* slpi16 */
};
static struct s_tXX tBX[] = {
	"sar   ", RR,		       /* 0xB0 */
	"exts  ", RR,		       /* 0xB1 */
	"sf    ", RR,		       /* 0xB2 */
	"cl    ", RR,		       /* 0xB3 */
	"c     ", RR,		       /* 0xB4 */
	"mts   ", SRR,		       /* 0xB5 */
	"d     ", RR,		       /* 0xB6 */
	"???   ", UNK,		       /* 0xB7 */
	"sr    ", RR,		       /* 0xB8 */
	"srp   ", RR,		       /* 0xB9 */
	"sl    ", RR,		       /* 0xBA */
	"slp   ", RR,		       /* 0xBB */
	"mftb  ", RR,		       /* 0xBC */
	"tge   ", RR,		       /* 0xBD */
	"tlt   ", RR,		       /* 0xBE */
	"mttb  ", RR,		       /* 0xBF */
};
static struct s_tXX tCX[] = {
	"svc   ", DIR,		       /* 0xC0 */
	"ai    ", DRRI,		       /* 0xC1 */
	"cal16 ", DRIR,		       /* 0xC2 */
	"oiu   ", DRRI,		       /* 0xC3 */
	"oil   ", DRRI,		       /* 0xC4 */
	"nilz  ", DRRI,		       /* 0xC5 */
	"nilo  ", DRRI,		       /* 0xC6 */
	"xil   ", DRRI,		       /* 0xC7 */
	"cal   ", DRIR,		       /* 0xC8 */
	"lm    ", DRIR,		       /* 0xC9 */
	"lha   ", DRIR,		       /* 0xCA */
	"ior   ", DRIR,		       /* 0xCB */
	"t     ", DTI,		       /* 0xCC */
	"l     ", DRIR,		       /* 0xCD */
	"lc    ", DRIR,		       /* 0xCE */
	"tsh   ", DRIR,		       /* 0xCF */
};
static struct s_tXX tDX[] = {
	"lps   ", DIIR,		       /* 0xD0 */
	"aei   ", DRRI,		       /* 0xD1 */
	"sfi   ", DRRI,		       /* 0xD2 */
	"cli   ", DRI,		       /* 0xD3 */
	"ci    ", DRI,		       /* 0xD4 */
	"niuz  ", DRRI,		       /* 0xD5 */
	"niuo  ", DRRI,		       /* 0xD6 */
	"xiu   ", DRRI,		       /* 0xD7 */
	"cau   ", DRIR,		       /* 0xD8 */
	"stm   ", DRIR,		       /* 0xD9 */
	"lh    ", DRIR,		       /* 0xDA */
	"iow   ", DRIR,		       /* 0xDB */
	"sth   ", DRIR,		       /* 0xDC */
	"st    ", DRIR,		       /* 0xDD */
	"stc   ", DRIR,		       /* 0xDE */
	"???   ", UNK,		       /* 0xDF */
};
static struct s_tXX tEX[] = {
	"abs   ", RR,		       /* 0xE0 */
	"a     ", RR,		       /* 0xE1 */
	"s     ", RR,		       /* 0xE2 */
	"o     ", RR,		       /* 0xE3 */
	"twoc  ", RR,		       /* 0xE4 */
	"n     ", RR,		       /* 0xE5 */
	"m     ", RR,		       /* 0xE6 */
	"x     ", RR,		       /* 0xE7 */
	"b     ", RC,		       /* 0xE8 */
	"b     ", RC,		       /* 0xE9 */
	"???   ", UNK,		       /* 0xEA */
	"lhs   ", R0R,		       /* 0xEB */
	"balr  ", RR,		       /* 0xEC */
	"balrx ", RR,		       /* 0xED */
	"b     ", RC,		       /* 0xEE */
	"b     ", RC,		       /* 0xEF */
};
static struct s_tXX tFX[] = {
	"wait  ", R00,		       /* 0xF0 */
	"ae    ", RR,		       /* 0xF1 */
	"se    ", RR,		       /* 0xF2 */
	"ca16  ", RR,		       /* 0xF3 */
	"onec  ", RR,		       /* 0xF4 */
	"clz   ", RR,		       /* 0xF5 */
	"m     ", UNK,		       /* 0xF6 */
	"x     ", UNK,		       /* 0xF7 */
	"b     ", UNK,		       /* 0xF8 */
	"mc03  ", RR,		       /* 0xF9 */
	"mc13  ", RR,		       /* 0xFA */
	"mc23  ", RR,		       /* 0xFB */
	"mc33  ", RR,		       /* 0xFC */
	"mc30  ", RR,		       /* 0xFD */
	"mc31  ", RR,		       /* 0xFE */
	"mc32  ", RR,		       /* 0xFF */
};

static struct s_tXX *p_tXX[] = {
	t0X, t1X, t2X, t3X, t4X, t5X, t6X, t7X,
	t8X, t9X, tAX, tBX, tCX, tDX, tEX, tFX,
};

static char bc[17][4] = {
	"   ",			       /* 0 */
	"ge ",			       /* 1 */
	"ne ",			       /* 2 */
	"le ",			       /* 3 */
	"nc ",			       /* 4 */
	"?? ",			       /* 5 */
	"no ",			       /* 6 */
	"ntb",			       /* 7 */
	"nop",			       /* 8 */
	"lt ",			       /* 9 */
	"eq ",			       /* A */
	"gt ",			       /* B */
	"c  ",			       /* C */
	"?? ",			       /* D */
	"o  ",			       /* E */
	"tb ",			       /* F */
	"?? ",			       /* undefined */
};
#define BUNK 16			       /* index in bc for undefined branch condition */

static char tc[8][4] = {
	"nop",			       /* 0 */
	"gt ",			       /* 1 */
	"eq ",			       /* 2 */
	"ge ",			       /* 3 */
	"lt ",			       /* 4 */
	"ne ",			       /* 5 */
	"le ",			       /* 6 */
	"rap",			       /* 7 */
};

static char sr[16][6] = {
	"scr0 ",		       /* 0 */
	"scr1 ",		       /* 1 */
	"scr2 ",		       /* 2 */
	"scr3 ",		       /* 3 */
	"scr4 ",		       /* 4 */
	"scr5 ",		       /* 5 */
	"cous ",		       /* 6 */
	"cou  ",		       /* 7 */
	"ts   ",		       /* 8 */
	"scr9 ",		       /* 9 */
	"mq   ",		       /* A */
	"mpcs ",		       /* B */
	"irb  ",		       /* C */
	"iar  ",		       /* D */
	"ics  ",		       /* E */
	"cs   ",		       /* F */
};

#define bits(x,n,m)  ((x >> (31-m)) & ((1 << (m-n+1)) - 1))
#define signed(x,n,m) ((x << n) >> 31-m+n)

static char *buf;		       /* current append addr for formatted inst */

/* 8*(formatted inst length) + (inst byte length) */
int
unasm(ip, bp)
	register unsigned short *ip;   /* addr of inst to be formatted */
	register char *bp;	       /* addr of buffer for formatted inst */
{
	return(_unasm(ip, ip, bp));
}

/* internal form of unasm that allows an effective execution address
 * as well as a pointer to the instruction itself.
 * ip	address (for printing and disassemby purposes (never dereferenced)
 * dp	address of the actual instruction in memory (often same as dp)
 * bp	buffer pointer
 */
int
_unasm(ip, dp, bp)
	register unsigned short *ip;   /* addr (of inst to be formatted) */
	register unsigned short *dp;   /* (addr of) inst to be formatted */
	register char *bp;	       /* addr of buffer for formatted inst */
{
	register long inst = (*dp << 16) | (*(dp + 1));
	register struct s_tXX *tp;
	register int info;
	register char *cp;
	register int ifmt;
	register char *sbp = bp;
	char *zaps();

	buf = bp;

	tp = p_tXX[info = bits(inst, 0, 3)];
	if (info > 7)
		tp = &tp[bits(inst, 4, 7)];
	info = ltab[ifmt = tp->fmt];

	fixput(ip, 7);
	padd(2);
	fixput(inst >> 8 * (4 - info), 2 * info - 1);
	padd(12 - 2 * info);
	cp = tp->opc;
	bp = buf + 1;
	while (*buf++ = *cp++);
	--buf;

	switch (ifmt) {

	case JI:
		zaps(bp, bc[bits(inst, 4, 7)]);
		varput((long)ip + 2 * signed(inst, 8, 15));
		break;
	case RI:
		reg(bits(inst, 8, 11));
		addc(',');
		fixput(bits(inst, 12, 15), 0);
		break;
	case RI16:
		reg(bits(inst, 8, 11));
		addc(',');
		fixput(bits(inst, 12, 15) + 16, 1);
		break;
	case RR:
		reg(bits(inst, 8, 11));
		addc(',');
		reg(bits(inst, 12, 15));
		break;
	case SRI:
		sreg(bits(inst, 8, 11));
		addc(',');
		fixput(bits(inst, 12, 15) + 16, 1);
		break;
	case SRR:
		sreg(bits(inst, 8, 11));
		addc(',');
		reg(bits(inst, 12, 15));
		break;
	case R0R:
		reg(bits(inst, 8, 11));
		addc(',');
		addc('0');
		addc('(');
		reg(bits(inst, 12, 15));
		addc(')');
		break;
	case RRR:
		reg(bits(inst, 4, 7));
		addc(',');
		reg(bits(inst, 8, 11));
		ireg(',', bits(inst, 12, 15));
		break;
	case RC:
		info = bits(inst, 9, 11);
		if (bits(inst, 5, 6))
			info += 8;
		if (!bits(inst, 8, 8))
			info = BUNK;
		bp = zaps(bp, bc[info]);
		*bp++ = 'r';
		if (bits(inst, 7, 7))
			*bp = 'x';
		reg(bits(inst, 12, 15));
		break;
	case BI:
		info = bits(inst, 9, 11);
		if (bits(inst, 5, 6))
			info += 8;
		if (!bits(inst, 8, 8))
			info = BUNK;
		bp = zaps(bp, bc[info]);
		if (bits(inst, 7, 7))
			*bp = 'x';
		varput((long)ip + 2 * signed(inst, 12, 31));
		break;
	case BRI:
		reg(bits(inst, 8, 11));
		addc(',');
		varput((long)ip + 2 * signed(inst, 12, 31));
		break;
	case BA:
		reg(15);
		addc(',');
		varput(2 * bits(inst, 8, 30));
		break;
	case DSC:
	case DSH:
	case DSL:
		reg(bits(inst, 8, 11));
		addc(',');
		varput(bits(inst, 4, 7) << (ifmt - DSC), 0); /* <=== NOTE 1 === */
		if (ireg('(', bits(inst, 12, 15)))
			addc(')');
		break;
	case DIR:
		varput(bits(inst, 16, 31));
		if (ireg('(', bits(inst, 12, 15)))
			addc(')');
		break;
	case DRI:
		reg(bits(inst, 12, 15));
		addc(',');
		vsiput(signed(inst, 16, 31));
		break;
	case DIIR:
		fixput(bits(inst, 8, 11), 0);
		addc(',');
		vsiput(signed(inst, 16, 31));
		if (ireg('(', bits(inst, 12, 15)))
			addc(')');
		break;
	case DRIR:
		reg(bits(inst, 8, 11));
		addc(',');
		vsiput(signed(inst, 16, 31));
		if (ireg('(', bits(inst, 12, 15)))
			addc(')');
		break;
	case DRRI:
		reg(bits(inst, 8, 11));
		addc(',');
		reg(bits(inst, 12, 15));
		addc(',');
		vsiput(signed(inst, 16, 31));
		break;
	case DTI:
		zaps(bp, tc[bits(inst, 9, 11)]);
		reg(bits(inst, 12, 15));
		addc(',');
		vsiput(signed(inst, 16, 31));
		break;
	case R00:
	case UNK:
		break;
	}
	addc(0x0A);
	addc(0x0D);
	addc(0x00);
	return (8 * (bp - sbp) + ltab[ifmt]);
}


static
addc(c)
	register char c;
{
	*buf++ = c;
}


static
padd(n)
	register int n;
{
	while (n--)
		addc(' ');
}


static
ireg(c, r)
	register char c;
	register int r;
{
	if (r) {
		addc(c);
		reg(r);
	}
	return (r);
}


static
reg(r)
	register int r;
{
	addc('r');
	if (r > 9) {
		addc('1');
		r -= 10;
	}
	fixput(r, 0);
}


static
sreg(r)
	register int r;
{
	register char c, *cp;

	for (cp = sr[r]; (c = *cp) > ' '; ++cp)
		addc(c);
}


static
fixput(x, i)			       /* output the least significant i+1 hex digits of
				          x */
	register long x;
	register int i;
{
	static char hexdig[17] = "0123456789ABCDEF";

	i *= 4;
	do
		addc(hexdig[(x >> i) & 0xF]);
	while ((i -= 4) >= 0);
}


static
varput(x)			       /* output all significant hex digits of x */
	register long x;
{
	register long mask = 0xF;
	register int i, digs = 0;

	for (i = 0; i < 2 * sizeof(long); ++i) {
		if (mask & x)
			digs = i;
		mask <<= 4;
	}
	fixput(x, digs);
}


static
vsiput(x)			       /* output all significant hex digits of x as a
				          signed number */
	register long x;
{
	if (x < 0) {
		addc('-');
		x = -x;
	}
	varput(x);
}


static char *zaps(p, q)		       /* modify the substring starting at p with the
				          substring       */
 /* starting at q and ending with the 1st blank or the end of q */
	register char *p, *q;
{
	register char c;

	while ((c = *q++) > ' ') {
		*p++ = c;
	}
	return (p);
}


/* end of file */
