xref: /inferno-os/utils/libmach/qdb.c (revision 45a20ab721a513710138340faff3d59a31c3e01e)
174a4d8c2SCharles.Forsyth #include <lib9.h>
274a4d8c2SCharles.Forsyth #include <bio.h>
374a4d8c2SCharles.Forsyth #include "mach.h"
474a4d8c2SCharles.Forsyth 
574a4d8c2SCharles.Forsyth /*
6d67b7dadSforsyth  * PowerPC-specific debugger interface,
7d67b7dadSforsyth  * including 64-bit modes
874a4d8c2SCharles.Forsyth  *	forsyth@terzarima.net
974a4d8c2SCharles.Forsyth  */
1074a4d8c2SCharles.Forsyth 
1174a4d8c2SCharles.Forsyth static	char	*powerexcep(Map*, Rgetter);
12d67b7dadSforsyth static	int	powerfoll(Map*, uvlong, Rgetter, uvlong*);
13d67b7dadSforsyth static	int	powerinst(Map*, uvlong, char, char*, int);
14d67b7dadSforsyth static	int	powerinstlen(Map*, uvlong);
15d67b7dadSforsyth static	int	powerdas(Map*, uvlong, char*, int);
1674a4d8c2SCharles.Forsyth 
1774a4d8c2SCharles.Forsyth /*
1874a4d8c2SCharles.Forsyth  *	Machine description
1974a4d8c2SCharles.Forsyth  */
2074a4d8c2SCharles.Forsyth Machdata powermach =
2174a4d8c2SCharles.Forsyth {
2274a4d8c2SCharles.Forsyth 	{0x07f, 0xe0, 0x00, 0x08},		/* breakpoint (tw 31,r0,r0) */
2374a4d8c2SCharles.Forsyth 	4,			/* break point size */
2474a4d8c2SCharles.Forsyth 
25d67b7dadSforsyth 	beswab,			/* short to local byte order */
26d67b7dadSforsyth 	beswal,			/* long to local byte order */
2774a4d8c2SCharles.Forsyth 	beswav,			/* vlong to local byte order */
2874a4d8c2SCharles.Forsyth 	risctrace,		/* print C traceback */
2974a4d8c2SCharles.Forsyth 	riscframe,		/* frame finder */
3074a4d8c2SCharles.Forsyth 	powerexcep,		/* print exception */
3174a4d8c2SCharles.Forsyth 	0,			/* breakpoint fixup */
3274a4d8c2SCharles.Forsyth 	beieeesftos,		/* single precision float printer */
3374a4d8c2SCharles.Forsyth 	beieeedftos,		/* double precisioin float printer */
3474a4d8c2SCharles.Forsyth 	powerfoll,		/* following addresses */
3574a4d8c2SCharles.Forsyth 	powerinst,		/* print instruction */
3674a4d8c2SCharles.Forsyth 	powerdas,		/* dissembler */
3774a4d8c2SCharles.Forsyth 	powerinstlen,		/* instruction size */
3874a4d8c2SCharles.Forsyth };
3974a4d8c2SCharles.Forsyth 
4074a4d8c2SCharles.Forsyth static char *excname[] =
4174a4d8c2SCharles.Forsyth {
4274a4d8c2SCharles.Forsyth 	"reserved 0",
4374a4d8c2SCharles.Forsyth 	"system reset",
4474a4d8c2SCharles.Forsyth 	"machine check",
4574a4d8c2SCharles.Forsyth 	"data access",
4674a4d8c2SCharles.Forsyth 	"instruction access",
4774a4d8c2SCharles.Forsyth 	"external interrupt",
4874a4d8c2SCharles.Forsyth 	"alignment",
4974a4d8c2SCharles.Forsyth 	"program exception",
5074a4d8c2SCharles.Forsyth 	"floating-point unavailable",
5174a4d8c2SCharles.Forsyth 	"decrementer",
5274a4d8c2SCharles.Forsyth 	"i/o controller interface error",
5374a4d8c2SCharles.Forsyth 	"reserved B",
5474a4d8c2SCharles.Forsyth 	"system call",
5574a4d8c2SCharles.Forsyth 	"trace trap",
5674a4d8c2SCharles.Forsyth 	"floating point assist",
5774a4d8c2SCharles.Forsyth 	"reserved",
5874a4d8c2SCharles.Forsyth 	"ITLB miss",
5974a4d8c2SCharles.Forsyth 	"DTLB load miss",
6074a4d8c2SCharles.Forsyth 	"DTLB store miss",
6174a4d8c2SCharles.Forsyth 	"instruction address breakpoint"
6274a4d8c2SCharles.Forsyth 	"SMI interrupt"
6374a4d8c2SCharles.Forsyth 	"reserved 15",
6474a4d8c2SCharles.Forsyth 	"reserved 16",
6574a4d8c2SCharles.Forsyth 	"reserved 17",
6674a4d8c2SCharles.Forsyth 	"reserved 18",
6774a4d8c2SCharles.Forsyth 	"reserved 19",
6874a4d8c2SCharles.Forsyth 	"reserved 1A",
6974a4d8c2SCharles.Forsyth 	/* the following are made up on a program exception */
70d67b7dadSforsyth 	"floating point exception",		/* FPEXC */
71d67b7dadSforsyth 	"illegal instruction",
72d67b7dadSforsyth 	"privileged instruction",
73d67b7dadSforsyth 	"trap",
74d67b7dadSforsyth 	"illegal operation",
7574a4d8c2SCharles.Forsyth 	"breakpoint",	/* 20 */
7674a4d8c2SCharles.Forsyth };
7774a4d8c2SCharles.Forsyth 
7874a4d8c2SCharles.Forsyth static char*
powerexcep(Map * map,Rgetter rget)7974a4d8c2SCharles.Forsyth powerexcep(Map *map, Rgetter rget)
8074a4d8c2SCharles.Forsyth {
8174a4d8c2SCharles.Forsyth 	long c;
8274a4d8c2SCharles.Forsyth 	static char buf[32];
8374a4d8c2SCharles.Forsyth 
8474a4d8c2SCharles.Forsyth 	c = (*rget)(map, "CAUSE") >> 8;
8574a4d8c2SCharles.Forsyth 	if(c < nelem(excname))
8674a4d8c2SCharles.Forsyth 		return excname[c];
8774a4d8c2SCharles.Forsyth 	sprint(buf, "unknown trap #%lx", c);
8874a4d8c2SCharles.Forsyth 	return buf;
8974a4d8c2SCharles.Forsyth }
9074a4d8c2SCharles.Forsyth 
9174a4d8c2SCharles.Forsyth /*
9274a4d8c2SCharles.Forsyth  * disassemble PowerPC opcodes
9374a4d8c2SCharles.Forsyth  */
9474a4d8c2SCharles.Forsyth 
9574a4d8c2SCharles.Forsyth #define	REGSP	1	/* should come from q.out.h, but there's a clash */
9674a4d8c2SCharles.Forsyth #define	REGSB	2
9774a4d8c2SCharles.Forsyth 
9874a4d8c2SCharles.Forsyth static	char FRAMENAME[] = ".frame";
9974a4d8c2SCharles.Forsyth 
10074a4d8c2SCharles.Forsyth static Map *mymap;
10174a4d8c2SCharles.Forsyth 
10274a4d8c2SCharles.Forsyth /*
10374a4d8c2SCharles.Forsyth  * ibm conventions for these: bit 0 is top bit
10474a4d8c2SCharles.Forsyth  *	from table 10-1
10574a4d8c2SCharles.Forsyth  */
10674a4d8c2SCharles.Forsyth typedef struct {
10774a4d8c2SCharles.Forsyth 	uchar	aa;		/* bit 30 */
10874a4d8c2SCharles.Forsyth 	uchar	crba;		/* bits 11-15 */
10974a4d8c2SCharles.Forsyth 	uchar	crbb;		/* bits 16-20 */
11074a4d8c2SCharles.Forsyth 	long	bd;		/* bits 16-29 */
11174a4d8c2SCharles.Forsyth 	uchar	crfd;		/* bits 6-8 */
11274a4d8c2SCharles.Forsyth 	uchar	crfs;		/* bits 11-13 */
11374a4d8c2SCharles.Forsyth 	uchar	bi;		/* bits 11-15 */
11474a4d8c2SCharles.Forsyth 	uchar	bo;		/* bits 6-10 */
11574a4d8c2SCharles.Forsyth 	uchar	crbd;		/* bits 6-10 */
11674a4d8c2SCharles.Forsyth 	/* union { */
11774a4d8c2SCharles.Forsyth 		short	d;	/* bits 16-31 */
11874a4d8c2SCharles.Forsyth 		short	simm;
11974a4d8c2SCharles.Forsyth 		ushort	uimm;
12074a4d8c2SCharles.Forsyth 	/*}; */
12174a4d8c2SCharles.Forsyth 	uchar	fm;		/* bits 7-14 */
12274a4d8c2SCharles.Forsyth 	uchar	fra;		/* bits 11-15 */
12374a4d8c2SCharles.Forsyth 	uchar	frb;		/* bits 16-20 */
12474a4d8c2SCharles.Forsyth 	uchar	frc;		/* bits 21-25 */
12574a4d8c2SCharles.Forsyth 	uchar	frs;		/* bits 6-10 */
12674a4d8c2SCharles.Forsyth 	uchar	frd;		/* bits 6-10 */
12774a4d8c2SCharles.Forsyth 	uchar	crm;		/* bits 12-19 */
12874a4d8c2SCharles.Forsyth 	long	li;		/* bits 6-29 || b'00' */
12974a4d8c2SCharles.Forsyth 	uchar	lk;		/* bit 31 */
13074a4d8c2SCharles.Forsyth 	uchar	mb;		/* bits 21-25 */
13174a4d8c2SCharles.Forsyth 	uchar	me;		/* bits 26-30 */
132d67b7dadSforsyth 	uchar	xmbe;		/* bits 26,21-25: mb[5] || mb[0:4], also xme */
133d67b7dadSforsyth 	uchar	xsh;		/* bits 30,16-20: sh[5] || sh[0:4] */
13474a4d8c2SCharles.Forsyth 	uchar	nb;		/* bits 16-20 */
13574a4d8c2SCharles.Forsyth 	uchar	op;		/* bits 0-5 */
13674a4d8c2SCharles.Forsyth 	uchar	oe;		/* bit 21 */
13774a4d8c2SCharles.Forsyth 	uchar	ra;		/* bits 11-15 */
13874a4d8c2SCharles.Forsyth 	uchar	rb;		/* bits 16-20 */
13974a4d8c2SCharles.Forsyth 	uchar	rc;		/* bit 31 */
14074a4d8c2SCharles.Forsyth 	/* union { */
14174a4d8c2SCharles.Forsyth 		uchar	rs;	/* bits 6-10 */
14274a4d8c2SCharles.Forsyth 		uchar	rd;
14374a4d8c2SCharles.Forsyth 	/*};*/
14474a4d8c2SCharles.Forsyth 	uchar	sh;		/* bits 16-20 */
14574a4d8c2SCharles.Forsyth 	ushort	spr;		/* bits 11-20 */
14674a4d8c2SCharles.Forsyth 	uchar	to;		/* bits 6-10 */
14774a4d8c2SCharles.Forsyth 	uchar	imm;		/* bits 16-19 */
14874a4d8c2SCharles.Forsyth 	ushort	xo;		/* bits 21-30, 22-30, 26-30, or 30 (beware) */
149d67b7dadSforsyth 	uvlong	imm64;
15074a4d8c2SCharles.Forsyth 	long w0;
15174a4d8c2SCharles.Forsyth 	long w1;
152d67b7dadSforsyth 	uvlong	addr;		/* pc of instruction */
15374a4d8c2SCharles.Forsyth 	short	target;
154d67b7dadSforsyth 	short	m64;		/* 64-bit mode */
15574a4d8c2SCharles.Forsyth 	char	*curr;		/* current fill level in output buffer */
15674a4d8c2SCharles.Forsyth 	char	*end;		/* end of buffer */
15774a4d8c2SCharles.Forsyth 	int 	size;		/* number of longs in instr */
15874a4d8c2SCharles.Forsyth 	char	*err;		/* errmsg */
15974a4d8c2SCharles.Forsyth } Instr;
16074a4d8c2SCharles.Forsyth 
16174a4d8c2SCharles.Forsyth #define	IBF(v,a,b) (((ulong)(v)>>(32-(b)-1)) & ~(~0L<<(((b)-(a)+1))))
16274a4d8c2SCharles.Forsyth #define	IB(v,b) IBF((v),(b),(b))
16374a4d8c2SCharles.Forsyth 
164d67b7dadSforsyth #pragma	varargck	argpos	bprint		2
165d67b7dadSforsyth 
16674a4d8c2SCharles.Forsyth static void
bprint(Instr * i,char * fmt,...)16774a4d8c2SCharles.Forsyth bprint(Instr *i, char *fmt, ...)
16874a4d8c2SCharles.Forsyth {
16974a4d8c2SCharles.Forsyth 	va_list arg;
17074a4d8c2SCharles.Forsyth 
17174a4d8c2SCharles.Forsyth 	va_start(arg, fmt);
17274a4d8c2SCharles.Forsyth 	i->curr = vseprint(i->curr, i->end, fmt, arg);
17374a4d8c2SCharles.Forsyth 	va_end(arg);
17474a4d8c2SCharles.Forsyth }
17574a4d8c2SCharles.Forsyth 
17674a4d8c2SCharles.Forsyth static int
decode(uvlong pc,Instr * i)177d67b7dadSforsyth decode(uvlong pc, Instr *i)
17874a4d8c2SCharles.Forsyth {
179d67b7dadSforsyth 	ulong w;
18074a4d8c2SCharles.Forsyth 
18174a4d8c2SCharles.Forsyth 	if (get4(mymap, pc, &w) < 0) {
18274a4d8c2SCharles.Forsyth 		werrstr("can't read instruction: %r");
18374a4d8c2SCharles.Forsyth 		return -1;
18474a4d8c2SCharles.Forsyth 	}
185d67b7dadSforsyth 	i->m64 = asstype == APOWER64;
18674a4d8c2SCharles.Forsyth 	i->aa = IB(w, 30);
18774a4d8c2SCharles.Forsyth 	i->crba = IBF(w, 11, 15);
18874a4d8c2SCharles.Forsyth 	i->crbb = IBF(w, 16, 20);
18974a4d8c2SCharles.Forsyth 	i->bd = IBF(w, 16, 29)<<2;
19074a4d8c2SCharles.Forsyth 	if(i->bd & 0x8000)
19174a4d8c2SCharles.Forsyth 		i->bd |= ~0L<<16;
19274a4d8c2SCharles.Forsyth 	i->crfd = IBF(w, 6, 8);
19374a4d8c2SCharles.Forsyth 	i->crfs = IBF(w, 11, 13);
19474a4d8c2SCharles.Forsyth 	i->bi = IBF(w, 11, 15);
19574a4d8c2SCharles.Forsyth 	i->bo = IBF(w, 6, 10);
19674a4d8c2SCharles.Forsyth 	i->crbd = IBF(w, 6, 10);
19774a4d8c2SCharles.Forsyth 	i->uimm = IBF(w, 16, 31);	/* also d, simm */
19874a4d8c2SCharles.Forsyth 	i->fm = IBF(w, 7, 14);
19974a4d8c2SCharles.Forsyth 	i->fra = IBF(w, 11, 15);
20074a4d8c2SCharles.Forsyth 	i->frb = IBF(w, 16, 20);
20174a4d8c2SCharles.Forsyth 	i->frc = IBF(w, 21, 25);
20274a4d8c2SCharles.Forsyth 	i->frs = IBF(w, 6, 10);
20374a4d8c2SCharles.Forsyth 	i->frd = IBF(w, 6, 10);
20474a4d8c2SCharles.Forsyth 	i->crm = IBF(w, 12, 19);
20574a4d8c2SCharles.Forsyth 	i->li = IBF(w, 6, 29)<<2;
20674a4d8c2SCharles.Forsyth 	if(IB(w, 6))
20774a4d8c2SCharles.Forsyth 		i->li |= ~0<<25;
20874a4d8c2SCharles.Forsyth 	i->lk = IB(w, 31);
20974a4d8c2SCharles.Forsyth 	i->mb = IBF(w, 21, 25);
21074a4d8c2SCharles.Forsyth 	i->me = IBF(w, 26, 30);
211d67b7dadSforsyth 	i->xmbe = (IB(w,26)<<5) | i->mb;
21274a4d8c2SCharles.Forsyth 	i->nb = IBF(w, 16, 20);
21374a4d8c2SCharles.Forsyth 	i->op = IBF(w, 0, 5);
21474a4d8c2SCharles.Forsyth 	i->oe = IB(w, 21);
21574a4d8c2SCharles.Forsyth 	i->ra = IBF(w, 11, 15);
21674a4d8c2SCharles.Forsyth 	i->rb = IBF(w, 16, 20);
21774a4d8c2SCharles.Forsyth 	i->rc = IB(w, 31);
21874a4d8c2SCharles.Forsyth 	i->rs = IBF(w, 6, 10);	/* also rd */
21974a4d8c2SCharles.Forsyth 	i->sh = IBF(w, 16, 20);
220d67b7dadSforsyth 	i->xsh = (IB(w, 30)<<5) | i->sh;
22174a4d8c2SCharles.Forsyth 	i->spr = IBF(w, 11, 20);
22274a4d8c2SCharles.Forsyth 	i->to = IBF(w, 6, 10);
22374a4d8c2SCharles.Forsyth 	i->imm = IBF(w, 16, 19);
22474a4d8c2SCharles.Forsyth 	i->xo = IBF(w, 21, 30);		/* bits 21-30, 22-30, 26-30, or 30 (beware) */
225d67b7dadSforsyth 	if(i->op == 58){	/* class of 64-bit loads */
226d67b7dadSforsyth 		i->xo = i->simm & 3;
227d67b7dadSforsyth 		i->simm &= ~3;
228d67b7dadSforsyth 	}
229d67b7dadSforsyth 	i->imm64 = i->simm;
23074a4d8c2SCharles.Forsyth 	if(i->op == 15)
231d67b7dadSforsyth 		i->imm64 <<= 16;
232d67b7dadSforsyth 	else if(i->op == 25 || i->op == 27 || i->op == 29)
233d67b7dadSforsyth 		i->imm64 = (uvlong)(i->uimm<<16);
23474a4d8c2SCharles.Forsyth 	i->w0 = w;
23574a4d8c2SCharles.Forsyth 	i->target = -1;
23674a4d8c2SCharles.Forsyth 	i->addr = pc;
23774a4d8c2SCharles.Forsyth 	i->size = 1;
23874a4d8c2SCharles.Forsyth 	return 1;
23974a4d8c2SCharles.Forsyth }
24074a4d8c2SCharles.Forsyth 
24174a4d8c2SCharles.Forsyth static int
mkinstr(uvlong pc,Instr * i)242d67b7dadSforsyth mkinstr(uvlong pc, Instr *i)
24374a4d8c2SCharles.Forsyth {
24474a4d8c2SCharles.Forsyth 	Instr x;
24574a4d8c2SCharles.Forsyth 
24674a4d8c2SCharles.Forsyth 	if(decode(pc, i) < 0)
24774a4d8c2SCharles.Forsyth 		return -1;
24874a4d8c2SCharles.Forsyth 	/*
24974a4d8c2SCharles.Forsyth 	 * combine ADDIS/ORI (CAU/ORIL) into MOVW
250d67b7dadSforsyth 	 * also ORIS/ORIL for unsigned in 64-bit mode
25174a4d8c2SCharles.Forsyth 	 */
252d67b7dadSforsyth 	if ((i->op == 15 || i->op == 25) && i->ra==0) {
25374a4d8c2SCharles.Forsyth 		if(decode(pc+4, &x) < 0)
25474a4d8c2SCharles.Forsyth 			return -1;
25574a4d8c2SCharles.Forsyth 		if (x.op == 24 && x.rs == x.ra && x.ra == i->rd) {
256d67b7dadSforsyth 			i->imm64 |= (x.imm64 & 0xFFFF);
257d67b7dadSforsyth 			if(i->op != 15)
258d67b7dadSforsyth 				i->imm64 &= 0xFFFFFFFFUL;
25974a4d8c2SCharles.Forsyth 			i->w1 = x.w0;
26074a4d8c2SCharles.Forsyth 			i->target = x.rd;
26174a4d8c2SCharles.Forsyth 			i->size++;
26274a4d8c2SCharles.Forsyth 			return 1;
26374a4d8c2SCharles.Forsyth 		}
26474a4d8c2SCharles.Forsyth 	}
26574a4d8c2SCharles.Forsyth 	return 1;
26674a4d8c2SCharles.Forsyth }
26774a4d8c2SCharles.Forsyth 
26874a4d8c2SCharles.Forsyth static int
plocal(Instr * i)26974a4d8c2SCharles.Forsyth plocal(Instr *i)
27074a4d8c2SCharles.Forsyth {
271d67b7dadSforsyth 	long offset;
27274a4d8c2SCharles.Forsyth 	Symbol s;
27374a4d8c2SCharles.Forsyth 
27474a4d8c2SCharles.Forsyth 	if (!findsym(i->addr, CTEXT, &s) || !findlocal(&s, FRAMENAME, &s))
27574a4d8c2SCharles.Forsyth 		return -1;
276d67b7dadSforsyth 	offset = s.value - i->imm64;
27774a4d8c2SCharles.Forsyth 	if (offset > 0) {
27874a4d8c2SCharles.Forsyth 		if(getauto(&s, offset, CAUTO, &s)) {
279d67b7dadSforsyth 			bprint(i, "%s+%lld(SP)", s.name, s.value);
28074a4d8c2SCharles.Forsyth 			return 1;
28174a4d8c2SCharles.Forsyth 		}
28274a4d8c2SCharles.Forsyth 	} else {
28374a4d8c2SCharles.Forsyth 		if (getauto(&s, -offset-4, CPARAM, &s)) {
284d67b7dadSforsyth 			bprint(i, "%s+%ld(FP)", s.name, -offset);
28574a4d8c2SCharles.Forsyth 			return 1;
28674a4d8c2SCharles.Forsyth 		}
28774a4d8c2SCharles.Forsyth 	}
28874a4d8c2SCharles.Forsyth 	return -1;
28974a4d8c2SCharles.Forsyth }
29074a4d8c2SCharles.Forsyth 
29174a4d8c2SCharles.Forsyth static int
pglobal(Instr * i,uvlong off,int anyoff,char * reg)292d67b7dadSforsyth pglobal(Instr *i, uvlong off, int anyoff, char *reg)
29374a4d8c2SCharles.Forsyth {
29474a4d8c2SCharles.Forsyth 	Symbol s, s2;
295d67b7dadSforsyth 	uvlong off1;
29674a4d8c2SCharles.Forsyth 
29774a4d8c2SCharles.Forsyth 	if(findsym(off, CANY, &s) &&
298d67b7dadSforsyth 	   s.value-off < 4096 &&
29974a4d8c2SCharles.Forsyth 	   (s.class == CDATA || s.class == CTEXT)) {
30074a4d8c2SCharles.Forsyth 		if(off==s.value && s.name[0]=='$'){
30174a4d8c2SCharles.Forsyth 			off1 = 0;
302d67b7dadSforsyth 			geta(mymap, s.value, &off1);
30374a4d8c2SCharles.Forsyth 			if(off1 && findsym(off1, CANY, &s2) && s2.value == off1){
30474a4d8c2SCharles.Forsyth 				bprint(i, "$%s%s", s2.name, reg);
30574a4d8c2SCharles.Forsyth 				return 1;
30674a4d8c2SCharles.Forsyth 			}
30774a4d8c2SCharles.Forsyth 		}
30874a4d8c2SCharles.Forsyth 		bprint(i, "%s", s.name);
30974a4d8c2SCharles.Forsyth 		if (s.value != off)
310d67b7dadSforsyth 			bprint(i, "+%llux", off-s.value);
31174a4d8c2SCharles.Forsyth 		bprint(i, reg);
31274a4d8c2SCharles.Forsyth 		return 1;
31374a4d8c2SCharles.Forsyth 	}
31474a4d8c2SCharles.Forsyth 	if(!anyoff)
31574a4d8c2SCharles.Forsyth 		return 0;
316d67b7dadSforsyth 	bprint(i, "%llux%s", off, reg);
31774a4d8c2SCharles.Forsyth 	return 1;
31874a4d8c2SCharles.Forsyth }
31974a4d8c2SCharles.Forsyth 
32074a4d8c2SCharles.Forsyth static void
address(Instr * i)32174a4d8c2SCharles.Forsyth address(Instr *i)
32274a4d8c2SCharles.Forsyth {
32374a4d8c2SCharles.Forsyth 	if (i->ra == REGSP && plocal(i) >= 0)
32474a4d8c2SCharles.Forsyth 		return;
325d67b7dadSforsyth 	if (i->ra == REGSB && mach->sb && pglobal(i, mach->sb+i->imm64, 0, "(SB)") >= 0)
32674a4d8c2SCharles.Forsyth 		return;
327d67b7dadSforsyth 	if(i->simm < 0)
328d67b7dadSforsyth 		bprint(i, "-%x(R%d)", -i->simm, i->ra);
32974a4d8c2SCharles.Forsyth 	else
330d67b7dadSforsyth 		bprint(i, "%llux(R%d)", i->imm64, i->ra);
33174a4d8c2SCharles.Forsyth }
33274a4d8c2SCharles.Forsyth 
33374a4d8c2SCharles.Forsyth static	char	*tcrbits[] = {"LT", "GT", "EQ", "VS"};
33474a4d8c2SCharles.Forsyth static	char	*fcrbits[] = {"GE", "LE", "NE", "VC"};
33574a4d8c2SCharles.Forsyth 
33674a4d8c2SCharles.Forsyth typedef struct Opcode Opcode;
33774a4d8c2SCharles.Forsyth 
33874a4d8c2SCharles.Forsyth struct Opcode {
33974a4d8c2SCharles.Forsyth 	uchar	op;
34074a4d8c2SCharles.Forsyth 	ushort	xo;
34174a4d8c2SCharles.Forsyth 	ushort	xomask;
34274a4d8c2SCharles.Forsyth 	char	*mnemonic;
34374a4d8c2SCharles.Forsyth 	void	(*f)(Opcode *, Instr *);
34474a4d8c2SCharles.Forsyth 	char	*ken;
34574a4d8c2SCharles.Forsyth 	int	flags;
34674a4d8c2SCharles.Forsyth };
34774a4d8c2SCharles.Forsyth 
34874a4d8c2SCharles.Forsyth static void format(char *, Instr *, char *);
34974a4d8c2SCharles.Forsyth 
35074a4d8c2SCharles.Forsyth static void
branch(Opcode * o,Instr * i)35174a4d8c2SCharles.Forsyth branch(Opcode *o, Instr *i)
35274a4d8c2SCharles.Forsyth {
35374a4d8c2SCharles.Forsyth 	char buf[8];
35474a4d8c2SCharles.Forsyth 	int bo, bi;
35574a4d8c2SCharles.Forsyth 
35674a4d8c2SCharles.Forsyth 	bo = i->bo & ~1;	/* ignore prediction bit */
35774a4d8c2SCharles.Forsyth 	if(bo==4 || bo==12 || bo==20) {	/* simple forms */
35874a4d8c2SCharles.Forsyth 		if(bo != 20) {
35974a4d8c2SCharles.Forsyth 			bi = i->bi&3;
36074a4d8c2SCharles.Forsyth 			sprint(buf, "B%s%%L", bo==12? tcrbits[bi]: fcrbits[bi]);
361d67b7dadSforsyth 			format(buf, i, nil);
36274a4d8c2SCharles.Forsyth 			bprint(i, "\t");
36374a4d8c2SCharles.Forsyth 			if(i->bi > 4)
36474a4d8c2SCharles.Forsyth 				bprint(i, "CR(%d),", i->bi/4);
36574a4d8c2SCharles.Forsyth 		} else
366d67b7dadSforsyth 			format("BR%L\t", i, nil);
36774a4d8c2SCharles.Forsyth 		if(i->op == 16)
36874a4d8c2SCharles.Forsyth 			format(0, i, "%J");
36974a4d8c2SCharles.Forsyth 		else if(i->op == 19 && i->xo == 528)
37074a4d8c2SCharles.Forsyth 			format(0, i, "(CTR)");
37174a4d8c2SCharles.Forsyth 		else if(i->op == 19 && i->xo == 16)
37274a4d8c2SCharles.Forsyth 			format(0, i, "(LR)");
37374a4d8c2SCharles.Forsyth 	} else
37474a4d8c2SCharles.Forsyth 		format(o->mnemonic, i, o->ken);
37574a4d8c2SCharles.Forsyth }
37674a4d8c2SCharles.Forsyth 
37774a4d8c2SCharles.Forsyth static void
addi(Opcode * o,Instr * i)37874a4d8c2SCharles.Forsyth addi(Opcode *o, Instr *i)
37974a4d8c2SCharles.Forsyth {
38074a4d8c2SCharles.Forsyth 	if (i->op==14 && i->ra == 0)
38174a4d8c2SCharles.Forsyth 		format("MOVW", i, "%i,R%d");
382d67b7dadSforsyth 	else if (i->ra == REGSB) {
38374a4d8c2SCharles.Forsyth 		bprint(i, "MOVW\t$");
38474a4d8c2SCharles.Forsyth 		address(i);
38574a4d8c2SCharles.Forsyth 		bprint(i, ",R%d", i->rd);
38674a4d8c2SCharles.Forsyth 	} else if(i->op==14 && i->simm < 0) {
38774a4d8c2SCharles.Forsyth 		bprint(i, "SUB\t$%d,R%d", -i->simm, i->ra);
38874a4d8c2SCharles.Forsyth 		if(i->rd != i->ra)
38974a4d8c2SCharles.Forsyth 			bprint(i, ",R%d", i->rd);
39074a4d8c2SCharles.Forsyth 	} else if(i->ra == i->rd) {
39174a4d8c2SCharles.Forsyth 		format(o->mnemonic, i, "%i");
39274a4d8c2SCharles.Forsyth 		bprint(i, ",R%d", i->rd);
39374a4d8c2SCharles.Forsyth 	} else
39474a4d8c2SCharles.Forsyth 		format(o->mnemonic, i, o->ken);
39574a4d8c2SCharles.Forsyth }
39674a4d8c2SCharles.Forsyth 
39774a4d8c2SCharles.Forsyth static void
addis(Opcode * o,Instr * i)39874a4d8c2SCharles.Forsyth addis(Opcode *o, Instr *i)
39974a4d8c2SCharles.Forsyth {
40074a4d8c2SCharles.Forsyth 	long v;
40174a4d8c2SCharles.Forsyth 
402d67b7dadSforsyth 	v = i->imm64;
403d67b7dadSforsyth 	if (i->op==15 && i->ra == 0)
404d67b7dadSforsyth 		bprint(i, "MOVW\t$%lux,R%d", v, i->rd);
405d67b7dadSforsyth 	else if (i->op==15 && i->ra == REGSB) {
40674a4d8c2SCharles.Forsyth 		bprint(i, "MOVW\t$");
40774a4d8c2SCharles.Forsyth 		address(i);
40874a4d8c2SCharles.Forsyth 		bprint(i, ",R%d", i->rd);
40974a4d8c2SCharles.Forsyth 	} else if(i->op==15 && v < 0) {
410d67b7dadSforsyth 		bprint(i, "SUB\t$%ld,R%d", -v, i->ra);
41174a4d8c2SCharles.Forsyth 		if(i->rd != i->ra)
41274a4d8c2SCharles.Forsyth 			bprint(i, ",R%d", i->rd);
41374a4d8c2SCharles.Forsyth 	} else {
414d67b7dadSforsyth 		format(o->mnemonic, i, nil);
41574a4d8c2SCharles.Forsyth 		bprint(i, "\t$%ld,R%d", v, i->ra);
41674a4d8c2SCharles.Forsyth 		if(i->rd != i->ra)
41774a4d8c2SCharles.Forsyth 			bprint(i, ",R%d", i->rd);
41874a4d8c2SCharles.Forsyth 	}
41974a4d8c2SCharles.Forsyth }
42074a4d8c2SCharles.Forsyth 
42174a4d8c2SCharles.Forsyth static void
andi(Opcode * o,Instr * i)42274a4d8c2SCharles.Forsyth andi(Opcode *o, Instr *i)
42374a4d8c2SCharles.Forsyth {
42474a4d8c2SCharles.Forsyth 	if (i->ra == i->rs)
42574a4d8c2SCharles.Forsyth 		format(o->mnemonic, i, "%I,R%d");
42674a4d8c2SCharles.Forsyth 	else
42774a4d8c2SCharles.Forsyth 		format(o->mnemonic, i, o->ken);
42874a4d8c2SCharles.Forsyth }
42974a4d8c2SCharles.Forsyth 
43074a4d8c2SCharles.Forsyth static void
gencc(Opcode * o,Instr * i)43174a4d8c2SCharles.Forsyth gencc(Opcode *o, Instr *i)
43274a4d8c2SCharles.Forsyth {
43374a4d8c2SCharles.Forsyth 	format(o->mnemonic, i, o->ken);
43474a4d8c2SCharles.Forsyth }
43574a4d8c2SCharles.Forsyth 
43674a4d8c2SCharles.Forsyth static void
gen(Opcode * o,Instr * i)43774a4d8c2SCharles.Forsyth gen(Opcode *o, Instr *i)
43874a4d8c2SCharles.Forsyth {
43974a4d8c2SCharles.Forsyth 	format(o->mnemonic, i, o->ken);
44074a4d8c2SCharles.Forsyth 	if (i->rc)
44174a4d8c2SCharles.Forsyth 		bprint(i, " [illegal Rc]");
44274a4d8c2SCharles.Forsyth }
44374a4d8c2SCharles.Forsyth 
44474a4d8c2SCharles.Forsyth static void
ldx(Opcode * o,Instr * i)44574a4d8c2SCharles.Forsyth ldx(Opcode *o, Instr *i)
44674a4d8c2SCharles.Forsyth {
44774a4d8c2SCharles.Forsyth 	if(i->ra == 0)
44874a4d8c2SCharles.Forsyth 		format(o->mnemonic, i, "(R%b),R%d");
44974a4d8c2SCharles.Forsyth 	else
45074a4d8c2SCharles.Forsyth 		format(o->mnemonic, i, "(R%b+R%a),R%d");
45174a4d8c2SCharles.Forsyth 	if(i->rc)
45274a4d8c2SCharles.Forsyth 		bprint(i, " [illegal Rc]");
45374a4d8c2SCharles.Forsyth }
45474a4d8c2SCharles.Forsyth 
45574a4d8c2SCharles.Forsyth static void
stx(Opcode * o,Instr * i)45674a4d8c2SCharles.Forsyth stx(Opcode *o, Instr *i)
45774a4d8c2SCharles.Forsyth {
45874a4d8c2SCharles.Forsyth 	if(i->ra == 0)
45974a4d8c2SCharles.Forsyth 		format(o->mnemonic, i, "R%d,(R%b)");
46074a4d8c2SCharles.Forsyth 	else
46174a4d8c2SCharles.Forsyth 		format(o->mnemonic, i, "R%d,(R%b+R%a)");
46274a4d8c2SCharles.Forsyth 	if(i->rc && i->xo != 150)
46374a4d8c2SCharles.Forsyth 		bprint(i, " [illegal Rc]");
46474a4d8c2SCharles.Forsyth }
46574a4d8c2SCharles.Forsyth 
46674a4d8c2SCharles.Forsyth static void
fldx(Opcode * o,Instr * i)46774a4d8c2SCharles.Forsyth fldx(Opcode *o, Instr *i)
46874a4d8c2SCharles.Forsyth {
46974a4d8c2SCharles.Forsyth 	if(i->ra == 0)
47074a4d8c2SCharles.Forsyth 		format(o->mnemonic, i, "(R%b),F%d");
47174a4d8c2SCharles.Forsyth 	else
47274a4d8c2SCharles.Forsyth 		format(o->mnemonic, i, "(R%b+R%a),F%d");
47374a4d8c2SCharles.Forsyth 	if(i->rc)
47474a4d8c2SCharles.Forsyth 		bprint(i, " [illegal Rc]");
47574a4d8c2SCharles.Forsyth }
47674a4d8c2SCharles.Forsyth 
47774a4d8c2SCharles.Forsyth static void
fstx(Opcode * o,Instr * i)47874a4d8c2SCharles.Forsyth fstx(Opcode *o, Instr *i)
47974a4d8c2SCharles.Forsyth {
48074a4d8c2SCharles.Forsyth 	if(i->ra == 0)
48174a4d8c2SCharles.Forsyth 		format(o->mnemonic, i, "F%d,(R%b)");
48274a4d8c2SCharles.Forsyth 	else
48374a4d8c2SCharles.Forsyth 		format(o->mnemonic, i, "F%d,(R%b+R%a)");
48474a4d8c2SCharles.Forsyth 	if(i->rc)
48574a4d8c2SCharles.Forsyth 		bprint(i, " [illegal Rc]");
48674a4d8c2SCharles.Forsyth }
48774a4d8c2SCharles.Forsyth 
48874a4d8c2SCharles.Forsyth static void
dcb(Opcode * o,Instr * i)48974a4d8c2SCharles.Forsyth dcb(Opcode *o, Instr *i)
49074a4d8c2SCharles.Forsyth {
49174a4d8c2SCharles.Forsyth 	if(i->ra == 0)
49274a4d8c2SCharles.Forsyth 		format(o->mnemonic, i, "(R%b)");
49374a4d8c2SCharles.Forsyth 	else
49474a4d8c2SCharles.Forsyth 		format(o->mnemonic, i, "(R%b+R%a)");
49574a4d8c2SCharles.Forsyth 	if(i->rd)
49674a4d8c2SCharles.Forsyth 		bprint(i, " [illegal Rd]");
49774a4d8c2SCharles.Forsyth 	if(i->rc)
49874a4d8c2SCharles.Forsyth 		bprint(i, " [illegal Rc]");
49974a4d8c2SCharles.Forsyth }
50074a4d8c2SCharles.Forsyth 
50174a4d8c2SCharles.Forsyth static void
lw(Opcode * o,Instr * i,char r)50274a4d8c2SCharles.Forsyth lw(Opcode *o, Instr *i, char r)
50374a4d8c2SCharles.Forsyth {
504d67b7dadSforsyth 	format(o->mnemonic, i, nil);
505d67b7dadSforsyth 	bprint(i, "\t");
50674a4d8c2SCharles.Forsyth 	address(i);
50774a4d8c2SCharles.Forsyth 	bprint(i, ",%c%d", r, i->rd);
50874a4d8c2SCharles.Forsyth }
50974a4d8c2SCharles.Forsyth 
51074a4d8c2SCharles.Forsyth static void
load(Opcode * o,Instr * i)51174a4d8c2SCharles.Forsyth load(Opcode *o, Instr *i)
51274a4d8c2SCharles.Forsyth {
51374a4d8c2SCharles.Forsyth 	lw(o, i, 'R');
51474a4d8c2SCharles.Forsyth }
51574a4d8c2SCharles.Forsyth 
51674a4d8c2SCharles.Forsyth static void
fload(Opcode * o,Instr * i)51774a4d8c2SCharles.Forsyth fload(Opcode *o, Instr *i)
51874a4d8c2SCharles.Forsyth {
51974a4d8c2SCharles.Forsyth 	lw(o, i, 'F');
52074a4d8c2SCharles.Forsyth }
52174a4d8c2SCharles.Forsyth 
52274a4d8c2SCharles.Forsyth static void
sw(Opcode * o,Instr * i,char r)52374a4d8c2SCharles.Forsyth sw(Opcode *o, Instr *i, char r)
52474a4d8c2SCharles.Forsyth {
52574a4d8c2SCharles.Forsyth 	int offset;
52674a4d8c2SCharles.Forsyth 	Symbol s;
52774a4d8c2SCharles.Forsyth 
528d67b7dadSforsyth 	if (i->rs == REGSP) {
52974a4d8c2SCharles.Forsyth 		if (findsym(i->addr, CTEXT, &s) && findlocal(&s, FRAMENAME, &s)) {
530d67b7dadSforsyth 			offset = s.value-i->imm64;
53174a4d8c2SCharles.Forsyth 			if (offset > 0 && getauto(&s, offset, CAUTO, &s)) {
532d67b7dadSforsyth 				format(o->mnemonic, i, nil);
533d67b7dadSforsyth 				bprint(i, "\t%c%d,%s-%d(SP)", r, i->rd, s.name, offset);
53474a4d8c2SCharles.Forsyth 				return;
53574a4d8c2SCharles.Forsyth 			}
53674a4d8c2SCharles.Forsyth 		}
53774a4d8c2SCharles.Forsyth 	}
538d67b7dadSforsyth 	if (i->rs == REGSB && mach->sb) {
539d67b7dadSforsyth 		format(o->mnemonic, i, nil);
540d67b7dadSforsyth 		bprint(i, "\t%c%d,", r, i->rd);
54174a4d8c2SCharles.Forsyth 		address(i);
54274a4d8c2SCharles.Forsyth 		return;
54374a4d8c2SCharles.Forsyth 	}
54474a4d8c2SCharles.Forsyth 	if (r == 'F')
545d67b7dadSforsyth 		format(o->mnemonic, i, "F%d,%l");
54674a4d8c2SCharles.Forsyth 	else
547d67b7dadSforsyth 		format(o->mnemonic, i, o->ken);
54874a4d8c2SCharles.Forsyth }
54974a4d8c2SCharles.Forsyth 
55074a4d8c2SCharles.Forsyth static void
store(Opcode * o,Instr * i)55174a4d8c2SCharles.Forsyth store(Opcode *o, Instr *i)
55274a4d8c2SCharles.Forsyth {
55374a4d8c2SCharles.Forsyth 	sw(o, i, 'R');
55474a4d8c2SCharles.Forsyth }
55574a4d8c2SCharles.Forsyth 
55674a4d8c2SCharles.Forsyth static void
fstore(Opcode * o,Instr * i)55774a4d8c2SCharles.Forsyth fstore(Opcode *o, Instr *i)
55874a4d8c2SCharles.Forsyth {
55974a4d8c2SCharles.Forsyth 	sw(o, i, 'F');
56074a4d8c2SCharles.Forsyth }
56174a4d8c2SCharles.Forsyth 
56274a4d8c2SCharles.Forsyth static void
shifti(Opcode * o,Instr * i)56374a4d8c2SCharles.Forsyth shifti(Opcode *o, Instr *i)
56474a4d8c2SCharles.Forsyth {
56574a4d8c2SCharles.Forsyth 	if (i->ra == i->rs)
56674a4d8c2SCharles.Forsyth 		format(o->mnemonic, i, "$%k,R%a");
56774a4d8c2SCharles.Forsyth 	else
56874a4d8c2SCharles.Forsyth 		format(o->mnemonic, i, o->ken);
56974a4d8c2SCharles.Forsyth }
57074a4d8c2SCharles.Forsyth 
57174a4d8c2SCharles.Forsyth static void
shift(Opcode * o,Instr * i)57274a4d8c2SCharles.Forsyth shift(Opcode *o, Instr *i)
57374a4d8c2SCharles.Forsyth {
57474a4d8c2SCharles.Forsyth 	if (i->ra == i->rs)
57574a4d8c2SCharles.Forsyth 		format(o->mnemonic, i, "R%b,R%a");
57674a4d8c2SCharles.Forsyth 	else
57774a4d8c2SCharles.Forsyth 		format(o->mnemonic, i, o->ken);
57874a4d8c2SCharles.Forsyth }
57974a4d8c2SCharles.Forsyth 
58074a4d8c2SCharles.Forsyth static void
add(Opcode * o,Instr * i)58174a4d8c2SCharles.Forsyth add(Opcode *o, Instr *i)
58274a4d8c2SCharles.Forsyth {
58374a4d8c2SCharles.Forsyth 	if (i->rd == i->ra)
58474a4d8c2SCharles.Forsyth 		format(o->mnemonic, i, "R%b,R%d");
58574a4d8c2SCharles.Forsyth 	else if (i->rd == i->rb)
58674a4d8c2SCharles.Forsyth 		format(o->mnemonic, i, "R%a,R%d");
58774a4d8c2SCharles.Forsyth 	else
58874a4d8c2SCharles.Forsyth 		format(o->mnemonic, i, o->ken);
58974a4d8c2SCharles.Forsyth }
59074a4d8c2SCharles.Forsyth 
59174a4d8c2SCharles.Forsyth static void
sub(Opcode * o,Instr * i)59274a4d8c2SCharles.Forsyth sub(Opcode *o, Instr *i)
59374a4d8c2SCharles.Forsyth {
594d67b7dadSforsyth 	format(o->mnemonic, i, nil);
595d67b7dadSforsyth 	bprint(i, "\t");
59674a4d8c2SCharles.Forsyth 	if(i->op == 31) {
59774a4d8c2SCharles.Forsyth 		bprint(i, "\tR%d,R%d", i->ra, i->rb);	/* subtract Ra from Rb */
59874a4d8c2SCharles.Forsyth 		if(i->rd != i->rb)
59974a4d8c2SCharles.Forsyth 			bprint(i, ",R%d", i->rd);
60074a4d8c2SCharles.Forsyth 	} else
60174a4d8c2SCharles.Forsyth 		bprint(i, "\tR%d,$%d,R%d", i->ra, i->simm, i->rd);
60274a4d8c2SCharles.Forsyth }
60374a4d8c2SCharles.Forsyth 
60474a4d8c2SCharles.Forsyth static void
qmuldiv(Opcode * o,Instr * i)605b6b4a404Sforsyth qmuldiv(Opcode *o, Instr *i)
60674a4d8c2SCharles.Forsyth {
607d67b7dadSforsyth 	format(o->mnemonic, i, nil);
60874a4d8c2SCharles.Forsyth 	if(i->op == 31)
60974a4d8c2SCharles.Forsyth 		bprint(i, "\tR%d,R%d", i->rb, i->ra);
61074a4d8c2SCharles.Forsyth 	else
61174a4d8c2SCharles.Forsyth 		bprint(i, "\t$%d,R%d", i->simm, i->ra);
61274a4d8c2SCharles.Forsyth 	if(i->ra != i->rd)
61374a4d8c2SCharles.Forsyth 		bprint(i, ",R%d", i->rd);
61474a4d8c2SCharles.Forsyth }
61574a4d8c2SCharles.Forsyth 
61674a4d8c2SCharles.Forsyth static void
and(Opcode * o,Instr * i)61774a4d8c2SCharles.Forsyth and(Opcode *o, Instr *i)
61874a4d8c2SCharles.Forsyth {
61974a4d8c2SCharles.Forsyth 	if (i->op == 31) {
62074a4d8c2SCharles.Forsyth 		/* Rb,Rs,Ra */
62174a4d8c2SCharles.Forsyth 		if (i->ra == i->rs)
62274a4d8c2SCharles.Forsyth 			format(o->mnemonic, i, "R%b,R%a");
62374a4d8c2SCharles.Forsyth 		else if (i->ra == i->rb)
62474a4d8c2SCharles.Forsyth 			format(o->mnemonic, i, "R%s,R%a");
62574a4d8c2SCharles.Forsyth 		else
62674a4d8c2SCharles.Forsyth 			format(o->mnemonic, i, o->ken);
62774a4d8c2SCharles.Forsyth 	} else {
62874a4d8c2SCharles.Forsyth 		/* imm,Rs,Ra */
62974a4d8c2SCharles.Forsyth 		if (i->ra == i->rs)
63074a4d8c2SCharles.Forsyth 			format(o->mnemonic, i, "%I,R%a");
63174a4d8c2SCharles.Forsyth 		else
63274a4d8c2SCharles.Forsyth 			format(o->mnemonic, i, o->ken);
63374a4d8c2SCharles.Forsyth 	}
63474a4d8c2SCharles.Forsyth }
63574a4d8c2SCharles.Forsyth 
63674a4d8c2SCharles.Forsyth static void
or(Opcode * o,Instr * i)63774a4d8c2SCharles.Forsyth or(Opcode *o, Instr *i)
63874a4d8c2SCharles.Forsyth {
63974a4d8c2SCharles.Forsyth 	if (i->op == 31) {
64074a4d8c2SCharles.Forsyth 		/* Rb,Rs,Ra */
64174a4d8c2SCharles.Forsyth 		if (i->rs == 0 && i->ra == 0 && i->rb == 0)
642d67b7dadSforsyth 			format("NOP", i, nil);
64374a4d8c2SCharles.Forsyth 		else if (i->rs == i->rb)
64474a4d8c2SCharles.Forsyth 			format("MOVW", i, "R%b,R%a");
64574a4d8c2SCharles.Forsyth 		else
64674a4d8c2SCharles.Forsyth 			and(o, i);
64774a4d8c2SCharles.Forsyth 	} else
64874a4d8c2SCharles.Forsyth 		and(o, i);
64974a4d8c2SCharles.Forsyth }
65074a4d8c2SCharles.Forsyth 
65174a4d8c2SCharles.Forsyth static void
shifted(Opcode * o,Instr * i)65274a4d8c2SCharles.Forsyth shifted(Opcode *o, Instr *i)
65374a4d8c2SCharles.Forsyth {
654d67b7dadSforsyth 	format(o->mnemonic, i, nil);
65574a4d8c2SCharles.Forsyth 	bprint(i, "\t$%lux,", (ulong)i->uimm<<16);
65674a4d8c2SCharles.Forsyth 	if (i->rs == i->ra)
65774a4d8c2SCharles.Forsyth 		bprint(i, "R%d", i->ra);
65874a4d8c2SCharles.Forsyth 	else
65974a4d8c2SCharles.Forsyth 		bprint(i, "R%d,R%d", i->rs, i->ra);
66074a4d8c2SCharles.Forsyth }
66174a4d8c2SCharles.Forsyth 
66274a4d8c2SCharles.Forsyth static void
neg(Opcode * o,Instr * i)66374a4d8c2SCharles.Forsyth neg(Opcode *o, Instr *i)
66474a4d8c2SCharles.Forsyth {
66574a4d8c2SCharles.Forsyth 	if (i->rd == i->ra)
66674a4d8c2SCharles.Forsyth 		format(o->mnemonic, i, "R%d");
66774a4d8c2SCharles.Forsyth 	else
66874a4d8c2SCharles.Forsyth 		format(o->mnemonic, i, o->ken);
66974a4d8c2SCharles.Forsyth }
67074a4d8c2SCharles.Forsyth 
67174a4d8c2SCharles.Forsyth static	char	ir2[] = "R%a,R%d";		/* reverse of IBM order */
67274a4d8c2SCharles.Forsyth static	char	ir3[] = "R%b,R%a,R%d";
67374a4d8c2SCharles.Forsyth static	char	ir3r[] = "R%a,R%b,R%d";
67474a4d8c2SCharles.Forsyth static	char	il3[] = "R%b,R%s,R%a";
675*45a20ab7Sforsyth static	char	il2u[] = "%I,R%d,R%a";
67674a4d8c2SCharles.Forsyth static	char	il3s[] = "$%k,R%s,R%a";
67774a4d8c2SCharles.Forsyth static	char	il2[] = "R%s,R%a";
67874a4d8c2SCharles.Forsyth static	char	icmp3[] = "R%a,R%b,%D";
67974a4d8c2SCharles.Forsyth static	char	cr3op[] = "%b,%a,%d";
68074a4d8c2SCharles.Forsyth static	char	ir2i[] = "%i,R%a,R%d";
68174a4d8c2SCharles.Forsyth static	char	fp2[] = "F%b,F%d";
68274a4d8c2SCharles.Forsyth static	char	fp3[] = "F%b,F%a,F%d";
68374a4d8c2SCharles.Forsyth static	char	fp3c[] = "F%c,F%a,F%d";
68474a4d8c2SCharles.Forsyth static	char	fp4[] = "F%a,F%c,F%b,F%d";
68574a4d8c2SCharles.Forsyth static	char	fpcmp[] = "F%a,F%b,%D";
68674a4d8c2SCharles.Forsyth static	char	ldop[] = "%l,R%d";
68774a4d8c2SCharles.Forsyth static	char	stop[] = "R%d,%l";
68874a4d8c2SCharles.Forsyth static	char	fldop[] = "%l,F%d";
68974a4d8c2SCharles.Forsyth static	char	fstop[] = "F%d,%l";
690d67b7dadSforsyth static	char	rldc[] = "R%b,R%s,$%E,R%a";
69174a4d8c2SCharles.Forsyth static	char	rlim[] = "R%b,R%s,$%z,R%a";
69274a4d8c2SCharles.Forsyth static	char	rlimi[] = "$%k,R%s,$%z,R%a";
693d67b7dadSforsyth static	char	rldi[] = "$%e,R%s,$%E,R%a";
69474a4d8c2SCharles.Forsyth 
69574a4d8c2SCharles.Forsyth #define	OEM	IBF(~0,22,30)
69674a4d8c2SCharles.Forsyth #define	FP4	IBF(~0,26,30)
697d67b7dadSforsyth #define	ALL	(~0)
698d67b7dadSforsyth #define	RLDC	0xF
699d67b7dadSforsyth #define	RLDI	0xE
70074a4d8c2SCharles.Forsyth /*
70174a4d8c2SCharles.Forsyth notes:
70274a4d8c2SCharles.Forsyth 	10-26: crfD = rD>>2; rD&3 mbz
70374a4d8c2SCharles.Forsyth 		also, L bit (bit 10) mbz or selects 64-bit operands
70474a4d8c2SCharles.Forsyth */
70574a4d8c2SCharles.Forsyth 
70674a4d8c2SCharles.Forsyth static Opcode opcodes[] = {
70774a4d8c2SCharles.Forsyth 	{31,	266,	OEM,	"ADD%V%C",	add,	ir3},
70874a4d8c2SCharles.Forsyth 	{31,	 10,	OEM,	"ADDC%V%C",	add,	ir3},
70974a4d8c2SCharles.Forsyth 	{31,	138,	OEM,	"ADDE%V%C",	add,	ir3},
71074a4d8c2SCharles.Forsyth 	{14,	0,	0,	"ADD",		addi,	ir2i},
71174a4d8c2SCharles.Forsyth 	{12,	0,	0,	"ADDC",		addi,	ir2i},
71274a4d8c2SCharles.Forsyth 	{13,	0,	0,	"ADDCCC",	addi,	ir2i},
71374a4d8c2SCharles.Forsyth 	{15,	0,	0,	"ADD",		addis,	0},
71474a4d8c2SCharles.Forsyth 	{31,	234,	OEM,	"ADDME%V%C",	gencc,	ir2},
71574a4d8c2SCharles.Forsyth 	{31,	202,	OEM,	"ADDZE%V%C",	gencc,	ir2},
71674a4d8c2SCharles.Forsyth 
71774a4d8c2SCharles.Forsyth 	{31,	28,	ALL,	"AND%C",	and,	il3},
71874a4d8c2SCharles.Forsyth 	{31,	60,	ALL,	"ANDN%C",	and,	il3},
71974a4d8c2SCharles.Forsyth 	{28,	0,	0,	"ANDCC",	andi,	il2u},
72074a4d8c2SCharles.Forsyth 	{29,	0,	0,	"ANDCC",	shifted, 0},
72174a4d8c2SCharles.Forsyth 
72274a4d8c2SCharles.Forsyth 	{18,	0,	0,	"B%L",		gencc,	"%j"},
72374a4d8c2SCharles.Forsyth 	{16,	0,	0,	"BC%L",		branch,	"%d,%a,%J"},
72474a4d8c2SCharles.Forsyth 	{19,	528,	ALL,	"BC%L",		branch,	"%d,%a,(CTR)"},
72574a4d8c2SCharles.Forsyth 	{19,	16,	ALL,	"BC%L",		branch,	"%d,%a,(LR)"},
72674a4d8c2SCharles.Forsyth 
72774a4d8c2SCharles.Forsyth 	{31,	0,	ALL,	"CMP",		0,	icmp3},
72874a4d8c2SCharles.Forsyth 	{11,	0,	0,	"CMP",		0,	"R%a,%i,%D"},
72974a4d8c2SCharles.Forsyth 	{31,	32,	ALL,	"CMPU",		0,	icmp3},
73074a4d8c2SCharles.Forsyth 	{10,	0,	0,	"CMPU",		0,	"R%a,%I,%D"},
73174a4d8c2SCharles.Forsyth 
732d67b7dadSforsyth 	{31,	58,	ALL,	"CNTLZD%C",	gencc,	ir2},	/* 64 */
733d67b7dadSforsyth 	{31,	26,	ALL,	"CNTLZ%W%C",	gencc,	ir2},
73474a4d8c2SCharles.Forsyth 
73574a4d8c2SCharles.Forsyth 	{19,	257,	ALL,	"CRAND",	gen,	cr3op},
73674a4d8c2SCharles.Forsyth 	{19,	129,	ALL,	"CRANDN",	gen,	cr3op},
73774a4d8c2SCharles.Forsyth 	{19,	289,	ALL,	"CREQV",	gen,	cr3op},
73874a4d8c2SCharles.Forsyth 	{19,	225,	ALL,	"CRNAND",	gen,	cr3op},
73974a4d8c2SCharles.Forsyth 	{19,	33,	ALL,	"CRNOR",	gen,	cr3op},
74074a4d8c2SCharles.Forsyth 	{19,	449,	ALL,	"CROR",		gen,	cr3op},
74174a4d8c2SCharles.Forsyth 	{19,	417,	ALL,	"CRORN",	gen,	cr3op},
74274a4d8c2SCharles.Forsyth 	{19,	193,	ALL,	"CRXOR",	gen,	cr3op},
74374a4d8c2SCharles.Forsyth 
74474a4d8c2SCharles.Forsyth 	{31,	86,	ALL,	"DCBF",		dcb,	0},
74574a4d8c2SCharles.Forsyth 	{31,	470,	ALL,	"DCBI",		dcb,	0},
74674a4d8c2SCharles.Forsyth 	{31,	54,	ALL,	"DCBST",	dcb,	0},
74774a4d8c2SCharles.Forsyth 	{31,	278,	ALL,	"DCBT",		dcb,	0},
74874a4d8c2SCharles.Forsyth 	{31,	246,	ALL,	"DCBTST",	dcb,	0},
74974a4d8c2SCharles.Forsyth 	{31,	1014,	ALL,	"DCBZ",		dcb,	0},
750d67b7dadSforsyth 	{31,	454,	ALL,	"DCCCI",	dcb,	0},
751d67b7dadSforsyth 	{31,	966,	ALL,	"ICCCI",	dcb,	0},
75274a4d8c2SCharles.Forsyth 
753b6b4a404Sforsyth 	{31,	489,	OEM,	"DIVD%V%C",	qmuldiv,	ir3},	/* 64 */
754b6b4a404Sforsyth 	{31,	457,	OEM,	"DIVDU%V%C",	qmuldiv,	ir3},	/* 64 */
755b6b4a404Sforsyth 	{31,	491,	OEM,	"DIVW%V%C",	qmuldiv,	ir3},
756b6b4a404Sforsyth 	{31,	459,	OEM,	"DIVWU%V%C",	qmuldiv,	ir3},
75774a4d8c2SCharles.Forsyth 
75874a4d8c2SCharles.Forsyth 	{31,	310,	ALL,	"ECIWX",	ldx,	0},
75974a4d8c2SCharles.Forsyth 	{31,	438,	ALL,	"ECOWX",	stx,	0},
76074a4d8c2SCharles.Forsyth 	{31,	854,	ALL,	"EIEIO",	gen,	0},
76174a4d8c2SCharles.Forsyth 
76274a4d8c2SCharles.Forsyth 	{31,	284,	ALL,	"EQV%C",	gencc,	il3},
76374a4d8c2SCharles.Forsyth 
76474a4d8c2SCharles.Forsyth 	{31,	954,	ALL,	"EXTSB%C",	gencc,	il2},
76574a4d8c2SCharles.Forsyth 	{31,	922,	ALL,	"EXTSH%C",	gencc,	il2},
766d67b7dadSforsyth 	{31,	986,	ALL,	"EXTSW%C",	gencc,	il2},	/* 64 */
76774a4d8c2SCharles.Forsyth 
76874a4d8c2SCharles.Forsyth 	{63,	264,	ALL,	"FABS%C",	gencc,	fp2},
76974a4d8c2SCharles.Forsyth 	{63,	21,	ALL,	"FADD%C",	gencc,	fp3},
77074a4d8c2SCharles.Forsyth 	{59,	21,	ALL,	"FADDS%C",	gencc,	fp3},
77174a4d8c2SCharles.Forsyth 	{63,	32,	ALL,	"FCMPO",	gen,	fpcmp},
77274a4d8c2SCharles.Forsyth 	{63,	0,	ALL,	"FCMPU",	gen,	fpcmp},
773d67b7dadSforsyth 	{63,	846,	ALL,	"FCFID%C",	gencc,	fp2},	/* 64 */
774d67b7dadSforsyth 	{63,	814,	ALL,	"FCTID%C",	gencc,	fp2},	/* 64 */
775d67b7dadSforsyth 	{63,	815,	ALL,	"FCTIDZ%C",	gencc,	fp2},	/* 64 */
77674a4d8c2SCharles.Forsyth 	{63,	14,	ALL,	"FCTIW%C",	gencc,	fp2},
77774a4d8c2SCharles.Forsyth 	{63,	15,	ALL,	"FCTIWZ%C",	gencc,	fp2},
77874a4d8c2SCharles.Forsyth 	{63,	18,	ALL,	"FDIV%C",	gencc,	fp3},
77974a4d8c2SCharles.Forsyth 	{59,	18,	ALL,	"FDIVS%C",	gencc,	fp3},
78074a4d8c2SCharles.Forsyth 	{63,	29,	FP4,	"FMADD%C",	gencc,	fp4},
78174a4d8c2SCharles.Forsyth 	{59,	29,	FP4,	"FMADDS%C",	gencc,	fp4},
78274a4d8c2SCharles.Forsyth 	{63,	72,	ALL,	"FMOVD%C",	gencc,	fp2},
78374a4d8c2SCharles.Forsyth 	{63,	28,	FP4,	"FMSUB%C",	gencc,	fp4},
78474a4d8c2SCharles.Forsyth 	{59,	28,	FP4,	"FMSUBS%C",	gencc,	fp4},
78574a4d8c2SCharles.Forsyth 	{63,	25,	FP4,	"FMUL%C",	gencc,	fp3c},
78674a4d8c2SCharles.Forsyth 	{59,	25,	FP4,	"FMULS%C",	gencc,	fp3c},
78774a4d8c2SCharles.Forsyth 	{63,	136,	ALL,	"FNABS%C",	gencc,	fp2},
78874a4d8c2SCharles.Forsyth 	{63,	40,	ALL,	"FNEG%C",	gencc,	fp2},
78974a4d8c2SCharles.Forsyth 	{63,	31,	FP4,	"FNMADD%C",	gencc,	fp4},
79074a4d8c2SCharles.Forsyth 	{59,	31,	FP4,	"FNMADDS%C",	gencc,	fp4},
79174a4d8c2SCharles.Forsyth 	{63,	30,	FP4,	"FNMSUB%C",	gencc,	fp4},
79274a4d8c2SCharles.Forsyth 	{59,	30,	FP4,	"FNMSUBS%C",	gencc,	fp4},
793d67b7dadSforsyth 	{59,	24,	ALL,	"FRES%C",	gencc,	fp2},	/* optional */
79474a4d8c2SCharles.Forsyth 	{63,	12,	ALL,	"FRSP%C",	gencc,	fp2},
795d67b7dadSforsyth 	{63,	26,	ALL,	"FRSQRTE%C",	gencc,	fp2},	/* optional */
796d67b7dadSforsyth 	{63,	23,	FP4,	"FSEL%CC",	gencc,	fp4},	/* optional */
797d67b7dadSforsyth 	{63,	22,	ALL,	"FSQRT%C",	gencc,	fp2},	/* optional */
798d67b7dadSforsyth 	{59,	22,	ALL,	"FSQRTS%C",	gencc,	fp2},	/* optional */
79974a4d8c2SCharles.Forsyth 	{63,	20,	FP4,	"FSUB%C",	gencc,	fp3},
80074a4d8c2SCharles.Forsyth 	{59,	20,	FP4,	"FSUBS%C",	gencc,	fp3},
80174a4d8c2SCharles.Forsyth 
802d67b7dadSforsyth 	{31,	982,	ALL,	"ICBI",		dcb,	0},	/* optional */
80374a4d8c2SCharles.Forsyth 	{19,	150,	ALL,	"ISYNC",	gen,	0},
80474a4d8c2SCharles.Forsyth 
80574a4d8c2SCharles.Forsyth 	{34,	0,	0,	"MOVBZ",	load,	ldop},
80674a4d8c2SCharles.Forsyth 	{35,	0,	0,	"MOVBZU",	load,	ldop},
80774a4d8c2SCharles.Forsyth 	{31,	119,	ALL,	"MOVBZU",	ldx,	0},
80874a4d8c2SCharles.Forsyth 	{31,	87,	ALL,	"MOVBZ",	ldx,	0},
80974a4d8c2SCharles.Forsyth 	{50,	0,	0,	"FMOVD",	fload,	fldop},
81074a4d8c2SCharles.Forsyth 	{51,	0,	0,	"FMOVDU",	fload,	fldop},
81174a4d8c2SCharles.Forsyth 	{31,	631,	ALL,	"FMOVDU",	fldx,	0},
81274a4d8c2SCharles.Forsyth 	{31,	599,	ALL,	"FMOVD",	fldx,	0},
81374a4d8c2SCharles.Forsyth 	{48,	0,	0,	"FMOVS",	load,	fldop},
81474a4d8c2SCharles.Forsyth 	{49,	0,	0,	"FMOVSU",	load,	fldop},
81574a4d8c2SCharles.Forsyth 	{31,	567,	ALL,	"FMOVSU",	fldx,	0},
81674a4d8c2SCharles.Forsyth 	{31,	535,	ALL,	"FMOVS",	fldx,	0},
81774a4d8c2SCharles.Forsyth 	{42,	0,	0,	"MOVH",		load,	ldop},
81874a4d8c2SCharles.Forsyth 	{43,	0,	0,	"MOVHU",	load,	ldop},
81974a4d8c2SCharles.Forsyth 	{31,	375,	ALL,	"MOVHU",	ldx,	0},
82074a4d8c2SCharles.Forsyth 	{31,	343,	ALL,	"MOVH",		ldx,	0},
82174a4d8c2SCharles.Forsyth 	{31,	790,	ALL,	"MOVHBR",	ldx,	0},
82274a4d8c2SCharles.Forsyth 	{40,	0,	0,	"MOVHZ",	load,	ldop},
82374a4d8c2SCharles.Forsyth 	{41,	0,	0,	"MOVHZU",	load,	ldop},
82474a4d8c2SCharles.Forsyth 	{31,	311,	ALL,	"MOVHZU",	ldx,	0},
82574a4d8c2SCharles.Forsyth 	{31,	279,	ALL,	"MOVHZ",	ldx,	0},
82674a4d8c2SCharles.Forsyth 	{46,	0,	0,	"MOVMW",	load,	ldop},
82774a4d8c2SCharles.Forsyth 	{31,	597,	ALL,	"LSW",		gen,	"(R%a),$%n,R%d"},
82874a4d8c2SCharles.Forsyth 	{31,	533,	ALL,	"LSW",		ldx,	0},
82974a4d8c2SCharles.Forsyth 	{31,	20,	ALL,	"LWAR",		ldx,	0},
830d67b7dadSforsyth 	{31,	84,	ALL,	"LWARD",	ldx,	0},	/* 64 */
83174a4d8c2SCharles.Forsyth 
832d67b7dadSforsyth 	{58,	0,	ALL,	"MOVD",		load,	ldop},	/* 64 */
833d67b7dadSforsyth 	{58,	1,	ALL,	"MOVDU",	load,	ldop},	/* 64 */
834d67b7dadSforsyth 	{31,	53,	ALL,	"MOVDU",	ldx,	0},	/* 64 */
835d67b7dadSforsyth 	{31,	21,	ALL,	"MOVD",		ldx,	0},	/* 64 */
836d67b7dadSforsyth 
837d67b7dadSforsyth 	{31,	534,	ALL,	"MOVWBR",	ldx,	0},
838d67b7dadSforsyth 
839d67b7dadSforsyth 	{58,	2,	ALL,	"MOVW",		load,	ldop},	/* 64 (lwa) */
840d67b7dadSforsyth 	{31,	373,	ALL,	"MOVWU",	ldx,	0},	/* 64 */
841d67b7dadSforsyth 	{31,	341,	ALL,	"MOVW",		ldx,	0},	/* 64 */
842d67b7dadSforsyth 
843d67b7dadSforsyth 	{32,	0,	0,	"MOVW%Z",	load,	ldop},
844d67b7dadSforsyth 	{33,	0,	0,	"MOVW%ZU",	load,	ldop},
845d67b7dadSforsyth 	{31,	55,	ALL,	"MOVW%ZU",	ldx,	0},
846d67b7dadSforsyth 	{31,	23,	ALL,	"MOVW%Z",	ldx,	0},
84774a4d8c2SCharles.Forsyth 
84874a4d8c2SCharles.Forsyth 	{19,	0,	ALL,	"MOVFL",	gen,	"%S,%D"},
84974a4d8c2SCharles.Forsyth 	{63,	64,	ALL,	"MOVCRFS",	gen,	"%S,%D"},
85074a4d8c2SCharles.Forsyth 	{31,	512,	ALL,	"MOVW",		gen,	"XER,%D"},
85174a4d8c2SCharles.Forsyth 	{31,	19,	ALL,	"MOVW",		gen,	"CR,R%d"},
85274a4d8c2SCharles.Forsyth 
85374a4d8c2SCharles.Forsyth 	{63,	583,	ALL,	"MOVW%C",	gen,	"FPSCR, F%d"},	/* mffs */
85474a4d8c2SCharles.Forsyth 	{31,	83,	ALL,	"MOVW",		gen,	"MSR,R%d"},
85574a4d8c2SCharles.Forsyth 	{31,	339,	ALL,	"MOVW",		gen,	"%P,R%d"},
85674a4d8c2SCharles.Forsyth 	{31,	595,	ALL,	"MOVW",		gen,	"SEG(%a),R%d"},
85774a4d8c2SCharles.Forsyth 	{31,	659,	ALL,	"MOVW",		gen,	"SEG(R%b),R%d"},
858d67b7dadSforsyth 	{31,	323,	ALL,	"MOVW",		gen,	"DCR(%Q),R%d"},
859d67b7dadSforsyth 	{31,	451,	ALL,	"MOVW",		gen,	"R%s,DCR(%Q)"},
860*45a20ab7Sforsyth 	{31,	259,	ALL,	"MOVW",		gen,	"DCR(R%a),R%d"},
861*45a20ab7Sforsyth 	{31,	387,	ALL,	"MOVW",		gen,	"R%s,DCR(R%a)"},
86274a4d8c2SCharles.Forsyth 	{31,	144,	ALL,	"MOVFL",	gen,	"R%s,%m,CR"},
86374a4d8c2SCharles.Forsyth 	{63,	70,	ALL,	"MTFSB0%C",	gencc,	"%D"},
86474a4d8c2SCharles.Forsyth 	{63,	38,	ALL,	"MTFSB1%C",	gencc,	"%D"},
86574a4d8c2SCharles.Forsyth 	{63,	711,	ALL,	"MOVFL%C",	gencc,	"F%b,%M,FPSCR"},	/* mtfsf */
86674a4d8c2SCharles.Forsyth 	{63,	134,	ALL,	"MOVFL%C",	gencc,	"%K,%D"},
86774a4d8c2SCharles.Forsyth 	{31,	146,	ALL,	"MOVW",		gen,	"R%s,MSR"},
868d67b7dadSforsyth 	{31,	178,	ALL,	"MOVD",		gen,	"R%s,MSR"},
86974a4d8c2SCharles.Forsyth 	{31,	467,	ALL,	"MOVW",		gen,	"R%s,%P"},
87074a4d8c2SCharles.Forsyth 	{31,	210,	ALL,	"MOVW",		gen,	"R%s,SEG(%a)"},
87174a4d8c2SCharles.Forsyth 	{31,	242,	ALL,	"MOVW",		gen,	"R%s,SEG(R%b)"},
87274a4d8c2SCharles.Forsyth 
873d67b7dadSforsyth 	{31,	73,	ALL,	"MULHD%C",	gencc,	ir3},
874d67b7dadSforsyth 	{31,	9,	ALL,	"MULHDU%C",	gencc,	ir3},
875d67b7dadSforsyth 	{31,	233,	OEM,	"MULLD%V%C",	gencc,	ir3},
87674a4d8c2SCharles.Forsyth 
877d67b7dadSforsyth 	{31,	75,	ALL,	"MULHW%C",	gencc,	ir3},
878d67b7dadSforsyth 	{31,	11,	ALL,	"MULHWU%C",	gencc,	ir3},
87974a4d8c2SCharles.Forsyth 	{31,	235,	OEM,	"MULLW%V%C",	gencc,	ir3},
88074a4d8c2SCharles.Forsyth 
881b6b4a404Sforsyth 	{7,	0,	0,	"MULLW",	qmuldiv,	"%i,R%a,R%d"},
88274a4d8c2SCharles.Forsyth 
88374a4d8c2SCharles.Forsyth 	{31,	476,	ALL,	"NAND%C",	gencc,	il3},
88474a4d8c2SCharles.Forsyth 	{31,	104,	OEM,	"NEG%V%C",	neg,	ir2},
88574a4d8c2SCharles.Forsyth 	{31,	124,	ALL,	"NOR%C",	gencc,	il3},
88674a4d8c2SCharles.Forsyth 	{31,	444,	ALL,	"OR%C",		or,	il3},
88774a4d8c2SCharles.Forsyth 	{31,	412,	ALL,	"ORN%C",	or,	il3},
88874a4d8c2SCharles.Forsyth 	{24,	0,	0,	"OR",		and,	"%I,R%d,R%a"},
88974a4d8c2SCharles.Forsyth 	{25,	0,	0,	"OR",		shifted, 0},
89074a4d8c2SCharles.Forsyth 
89174a4d8c2SCharles.Forsyth 	{19,	50,	ALL,	"RFI",		gen,	0},
892d67b7dadSforsyth 	{19,	51,	ALL,	"RFCI",		gen,	0},
89374a4d8c2SCharles.Forsyth 
894d67b7dadSforsyth 	{30,	8,	RLDC,	"RLDCL%C",	gencc,	rldc},	/* 64 */
895d67b7dadSforsyth 	{30,	9,	RLDC,	"RLDCR%C",	gencc,	rldc},	/* 64 */
896d67b7dadSforsyth 	{30,	0,	RLDI,	"RLDCL%C",	gencc,	rldi},	/* 64 */
897d67b7dadSforsyth 	{30,	1<<1, RLDI,	"RLDCR%C",	gencc,	rldi},	/* 64 */
898d67b7dadSforsyth 	{30,	2<<1, RLDI,	"RLDC%C",	gencc,	rldi},	/* 64 */
899d67b7dadSforsyth 	{30,	3<<1, RLDI,	"RLDMI%C",	gencc,	rldi},	/* 64 */
900d67b7dadSforsyth 
90174a4d8c2SCharles.Forsyth 	{20,	0,	0,	"RLWMI%C",	gencc,	rlimi},
90274a4d8c2SCharles.Forsyth 	{21,	0,	0,	"RLWNM%C",	gencc,	rlimi},
90374a4d8c2SCharles.Forsyth 	{23,	0,	0,	"RLWNM%C",	gencc,	rlim},
90474a4d8c2SCharles.Forsyth 
90574a4d8c2SCharles.Forsyth 	{17,	1,	ALL,	"SYSCALL",	gen,	0},
90674a4d8c2SCharles.Forsyth 
907d67b7dadSforsyth 	{31,	27,	ALL,	"SLD%C",	shift,	il3},	/* 64 */
90874a4d8c2SCharles.Forsyth 	{31,	24,	ALL,	"SLW%C",	shift,	il3},
90974a4d8c2SCharles.Forsyth 
910d67b7dadSforsyth 	{31,	794,	ALL,	"SRAD%C",	shift,	il3},	/* 64 */
911d67b7dadSforsyth 	{31,	(413<<1)|0,	ALL,	"SRAD%C",	shifti,	il3s},	/* 64 */
912d67b7dadSforsyth 	{31,	(413<<1)|1,	ALL,	"SRAD%C",	shifti,	il3s},	/* 64 */
91374a4d8c2SCharles.Forsyth 	{31,	792,	ALL,	"SRAW%C",	shift,	il3},
91474a4d8c2SCharles.Forsyth 	{31,	824,	ALL,	"SRAW%C",	shifti,	il3s},
91574a4d8c2SCharles.Forsyth 
916d67b7dadSforsyth 	{31,	539,	ALL,	"SRD%C",	shift,	il3},	/* 64 */
91774a4d8c2SCharles.Forsyth 	{31,	536,	ALL,	"SRW%C",	shift,	il3},
91874a4d8c2SCharles.Forsyth 
91974a4d8c2SCharles.Forsyth 	{38,	0,	0,	"MOVB",		store,	stop},
92074a4d8c2SCharles.Forsyth 	{39,	0,	0,	"MOVBU",	store,	stop},
92174a4d8c2SCharles.Forsyth 	{31,	247,	ALL,	"MOVBU",	stx,	0},
92274a4d8c2SCharles.Forsyth 	{31,	215,	ALL,	"MOVB",		stx,	0},
92374a4d8c2SCharles.Forsyth 	{54,	0,	0,	"FMOVD",	fstore,	fstop},
92474a4d8c2SCharles.Forsyth 	{55,	0,	0,	"FMOVDU",	fstore,	fstop},
92574a4d8c2SCharles.Forsyth 	{31,	759,	ALL,	"FMOVDU",	fstx,	0},
92674a4d8c2SCharles.Forsyth 	{31,	727,	ALL,	"FMOVD",	fstx,	0},
92774a4d8c2SCharles.Forsyth 	{52,	0,	0,	"FMOVS",	fstore,	fstop},
92874a4d8c2SCharles.Forsyth 	{53,	0,	0,	"FMOVSU",	fstore,	fstop},
92974a4d8c2SCharles.Forsyth 	{31,	695,	ALL,	"FMOVSU",	fstx,	0},
93074a4d8c2SCharles.Forsyth 	{31,	663,	ALL,	"FMOVS",	fstx,	0},
93174a4d8c2SCharles.Forsyth 	{44,	0,	0,	"MOVH",		store,	stop},
93274a4d8c2SCharles.Forsyth 	{31,	918,	ALL,	"MOVHBR",	stx,	0},
93374a4d8c2SCharles.Forsyth 	{45,	0,	0,	"MOVHU",	store,	stop},
93474a4d8c2SCharles.Forsyth 	{31,	439,	ALL,	"MOVHU",	stx,	0},
93574a4d8c2SCharles.Forsyth 	{31,	407,	ALL,	"MOVH",		stx,	0},
93674a4d8c2SCharles.Forsyth 	{47,	0,	0,	"MOVMW",	store,	stop},
93774a4d8c2SCharles.Forsyth 	{31,	725,	ALL,	"STSW",		gen,	"R%d,$%n,(R%a)"},
93874a4d8c2SCharles.Forsyth 	{31,	661,	ALL,	"STSW",		stx,	0},
93974a4d8c2SCharles.Forsyth 	{36,	0,	0,	"MOVW",		store,	stop},
94074a4d8c2SCharles.Forsyth 	{31,	662,	ALL,	"MOVWBR",	stx,	0},
94174a4d8c2SCharles.Forsyth 	{31,	150,	ALL,	"STWCCC",	stx,	0},
942d67b7dadSforsyth 	{31,	214,	ALL,	"STDCCC",	stx,	0},	/* 64 */
94374a4d8c2SCharles.Forsyth 	{37,	0,	0,	"MOVWU",	store,	stop},
94474a4d8c2SCharles.Forsyth 	{31,	183,	ALL,	"MOVWU",	stx,	0},
94574a4d8c2SCharles.Forsyth 	{31,	151,	ALL,	"MOVW",		stx,	0},
94674a4d8c2SCharles.Forsyth 
947d67b7dadSforsyth 	{62,	0,	0,	"MOVD%U",	store,	stop},	/* 64 */
948d67b7dadSforsyth 	{31,	149,	ALL,	"MOVD",		stx,	0,},	/* 64 */
949d67b7dadSforsyth 	{31,	181,	ALL,	"MOVDU",	stx,	0},	/* 64 */
950d67b7dadSforsyth 
951d67b7dadSforsyth 	{31,	498,	ALL,	"SLBIA",	gen,	0},	/* 64 */
952d67b7dadSforsyth 	{31,	434,	ALL,	"SLBIE",	gen,	"R%b"},	/* 64 */
953d67b7dadSforsyth 	{31,	466,	ALL,	"SLBIEX",	gen,	"R%b"},	/* 64 */
954d67b7dadSforsyth 	{31,	915,	ALL,	"SLBMFEE",	gen,	"R%b,R%d"},	/* 64 */
955d67b7dadSforsyth 	{31,	851,	ALL,	"SLBMFEV",	gen,	"R%b,R%d"},	/* 64 */
956d67b7dadSforsyth 	{31,	402,	ALL,	"SLBMTE",	gen,	"R%s,R%b"},	/* 64 */
957d67b7dadSforsyth 
95874a4d8c2SCharles.Forsyth 	{31,	40,	OEM,	"SUB%V%C",	sub,	ir3},
95974a4d8c2SCharles.Forsyth 	{31,	8,	OEM,	"SUBC%V%C",	sub,	ir3},
96074a4d8c2SCharles.Forsyth 	{31,	136,	OEM,	"SUBE%V%C",	sub,	ir3},
96174a4d8c2SCharles.Forsyth 	{8,	0,	0,	"SUBC",		gen,	"R%a,%i,R%d"},
96274a4d8c2SCharles.Forsyth 	{31,	232,	OEM,	"SUBME%V%C",	sub,	ir2},
96374a4d8c2SCharles.Forsyth 	{31,	200,	OEM,	"SUBZE%V%C",	sub,	ir2},
96474a4d8c2SCharles.Forsyth 
965d67b7dadSforsyth 	{31,	598,	ALL,	"SYNC",		gen,	0},	/* TO DO: there's a parameter buried in there */
966d67b7dadSforsyth 	{2,	0,	0,	"TD",		gen,	"%d,R%a,%i"},	/* 64 */
967d67b7dadSforsyth 	{31,	370,	ALL,	"TLBIA",	gen,	0},	/* optional */
968d67b7dadSforsyth 	{31,	306,	ALL,	"TLBIE",	gen,	"R%b"},	/* optional */
969d67b7dadSforsyth 	{31,	274,	ALL,	"TLBIEL",	gen,	"R%b"},	/* optional */
970d67b7dadSforsyth 	{31,	1010,	ALL,	"TLBLI",	gen,	"R%b"},	/* optional */
971d67b7dadSforsyth 	{31,	978,	ALL,	"TLBLD",	gen,	"R%b"},	/* optional */
972d67b7dadSforsyth 	{31,	566,	ALL,	"TLBSYNC",	gen,	0},	/* optional */
973d67b7dadSforsyth 	{31,	68,	ALL,	"TD",		gen,	"%d,R%a,R%b"},	/* 64 */
97474a4d8c2SCharles.Forsyth 	{31,	4,	ALL,	"TW",		gen,	"%d,R%a,R%b"},
97574a4d8c2SCharles.Forsyth 	{3,	0,	0,	"TW",		gen,	"%d,R%a,%i"},
97674a4d8c2SCharles.Forsyth 
97774a4d8c2SCharles.Forsyth 	{31,	316,	ALL,	"XOR",		and,	il3},
97874a4d8c2SCharles.Forsyth 	{26,	0,	0,	"XOR",		and,	il2u},
97974a4d8c2SCharles.Forsyth 	{27,	0,	0,	"XOR",		shifted, 0},
98074a4d8c2SCharles.Forsyth 
98174a4d8c2SCharles.Forsyth 	{0},
98274a4d8c2SCharles.Forsyth };
98374a4d8c2SCharles.Forsyth 
98474a4d8c2SCharles.Forsyth typedef struct Spr Spr;
98574a4d8c2SCharles.Forsyth struct Spr {
98674a4d8c2SCharles.Forsyth 	int	n;
98774a4d8c2SCharles.Forsyth 	char	*name;
98874a4d8c2SCharles.Forsyth };
98974a4d8c2SCharles.Forsyth 
99074a4d8c2SCharles.Forsyth static	Spr	sprname[] = {
99174a4d8c2SCharles.Forsyth 	{0, "MQ"},
99274a4d8c2SCharles.Forsyth 	{1, "XER"},
99374a4d8c2SCharles.Forsyth 	{268, "TBL"},
99474a4d8c2SCharles.Forsyth 	{269, "TBU"},
99574a4d8c2SCharles.Forsyth 	{8, "LR"},
99674a4d8c2SCharles.Forsyth 	{9, "CTR"},
99774a4d8c2SCharles.Forsyth 	{528, "IBAT0U"},
99874a4d8c2SCharles.Forsyth 	{529, "IBAT0L"},
99974a4d8c2SCharles.Forsyth 	{530, "IBAT1U"},
100074a4d8c2SCharles.Forsyth 	{531, "IBAT1L"},
100174a4d8c2SCharles.Forsyth 	{532, "IBAT2U"},
100274a4d8c2SCharles.Forsyth 	{533, "IBAT2L"},
100374a4d8c2SCharles.Forsyth 	{534, "IBAT3U"},
100474a4d8c2SCharles.Forsyth 	{535, "IBAT3L"},
100574a4d8c2SCharles.Forsyth 	{536, "DBAT0U"},
100674a4d8c2SCharles.Forsyth 	{537, "DBAT0L"},
100774a4d8c2SCharles.Forsyth 	{538, "DBAT1U"},
100874a4d8c2SCharles.Forsyth 	{539, "DBAT1L"},
100974a4d8c2SCharles.Forsyth 	{540, "DBAT2U"},
101074a4d8c2SCharles.Forsyth 	{541, "DBAT2L"},
101174a4d8c2SCharles.Forsyth 	{542, "DBAT3U"},
101274a4d8c2SCharles.Forsyth 	{543, "DBAT3L"},
101374a4d8c2SCharles.Forsyth 	{25, "SDR1"},
101474a4d8c2SCharles.Forsyth 	{19, "DAR"},
101574a4d8c2SCharles.Forsyth 	{272, "SPRG0"},
101674a4d8c2SCharles.Forsyth 	{273, "SPRG1"},
101774a4d8c2SCharles.Forsyth 	{274, "SPRG2"},
101874a4d8c2SCharles.Forsyth 	{275, "SPRG3"},
101974a4d8c2SCharles.Forsyth 	{18, "DSISR"},
102074a4d8c2SCharles.Forsyth 	{26, "SRR0"},
102174a4d8c2SCharles.Forsyth 	{27, "SRR1"},
102274a4d8c2SCharles.Forsyth 	{284, "TBLW"},
102374a4d8c2SCharles.Forsyth 	{285, "TBUW"},
102474a4d8c2SCharles.Forsyth 	{22, "DEC"},
102574a4d8c2SCharles.Forsyth 	{282, "EAR"},
102674a4d8c2SCharles.Forsyth 	{1008, "HID0"},
102774a4d8c2SCharles.Forsyth 	{1009, "HID1"},
102874a4d8c2SCharles.Forsyth 	{976, "DMISS"},
102974a4d8c2SCharles.Forsyth 	{977, "DCMP"},
103074a4d8c2SCharles.Forsyth 	{978, "HASH1"},
103174a4d8c2SCharles.Forsyth 	{979, "HASH2"},
103274a4d8c2SCharles.Forsyth 	{980, "IMISS"},
103374a4d8c2SCharles.Forsyth 	{981, "ICMP"},
103474a4d8c2SCharles.Forsyth 	{982, "RPA"},
103574a4d8c2SCharles.Forsyth 	{1010, "IABR"},
103674a4d8c2SCharles.Forsyth 	{1013, "DABR"},
103774a4d8c2SCharles.Forsyth 	{0,0},
103874a4d8c2SCharles.Forsyth };
103974a4d8c2SCharles.Forsyth 
1040d67b7dadSforsyth static int
shmask(uvlong * m)1041d67b7dadSforsyth shmask(uvlong *m)
1042d67b7dadSforsyth {
1043d67b7dadSforsyth 	int i;
1044d67b7dadSforsyth 
1045d67b7dadSforsyth 	for(i=0; i<63; i++)
1046d67b7dadSforsyth 		if(*m & ((uvlong)1<<i))
1047d67b7dadSforsyth 			break;
1048d67b7dadSforsyth 	if(i > 63)
1049d67b7dadSforsyth 		return 0;
1050d67b7dadSforsyth 	if(*m & ~((uvlong)1<<i)){	/* more than one bit: do multiples of bytes */
1051d67b7dadSforsyth 		i = (i/8)*8;
1052d67b7dadSforsyth 		if(i == 0)
1053d67b7dadSforsyth 			return 0;
1054d67b7dadSforsyth 	}
1055d67b7dadSforsyth 	*m >>= i;
1056d67b7dadSforsyth 	return i;
1057d67b7dadSforsyth }
1058d67b7dadSforsyth 
105974a4d8c2SCharles.Forsyth static void
format(char * mnemonic,Instr * i,char * f)106074a4d8c2SCharles.Forsyth format(char *mnemonic, Instr *i, char *f)
106174a4d8c2SCharles.Forsyth {
106274a4d8c2SCharles.Forsyth 	int n, s;
106374a4d8c2SCharles.Forsyth 	ulong mask;
1064d67b7dadSforsyth 	uvlong vmask;
106574a4d8c2SCharles.Forsyth 
106674a4d8c2SCharles.Forsyth 	if (mnemonic)
106774a4d8c2SCharles.Forsyth 		format(0, i, mnemonic);
106874a4d8c2SCharles.Forsyth 	if (f == 0)
106974a4d8c2SCharles.Forsyth 		return;
107074a4d8c2SCharles.Forsyth 	if (mnemonic)
107174a4d8c2SCharles.Forsyth 		bprint(i, "\t");
107274a4d8c2SCharles.Forsyth 	for ( ; *f; f++) {
107374a4d8c2SCharles.Forsyth 		if (*f != '%') {
107474a4d8c2SCharles.Forsyth 			bprint(i, "%c", *f);
107574a4d8c2SCharles.Forsyth 			continue;
107674a4d8c2SCharles.Forsyth 		}
107774a4d8c2SCharles.Forsyth 		switch (*++f) {
107874a4d8c2SCharles.Forsyth 
107974a4d8c2SCharles.Forsyth 		case 'a':
108074a4d8c2SCharles.Forsyth 			bprint(i, "%d", i->ra);
108174a4d8c2SCharles.Forsyth 			break;
108274a4d8c2SCharles.Forsyth 
108374a4d8c2SCharles.Forsyth 		case 'b':
108474a4d8c2SCharles.Forsyth 			bprint(i, "%d", i->rb);
108574a4d8c2SCharles.Forsyth 			break;
108674a4d8c2SCharles.Forsyth 
108774a4d8c2SCharles.Forsyth 		case 'c':
108874a4d8c2SCharles.Forsyth 			bprint(i, "%d", i->frc);
108974a4d8c2SCharles.Forsyth 			break;
109074a4d8c2SCharles.Forsyth 
109174a4d8c2SCharles.Forsyth 		case 'd':
109274a4d8c2SCharles.Forsyth 		case 's':
109374a4d8c2SCharles.Forsyth 			bprint(i, "%d", i->rd);
109474a4d8c2SCharles.Forsyth 			break;
109574a4d8c2SCharles.Forsyth 
1096d67b7dadSforsyth 		case 'C':
1097d67b7dadSforsyth 			if(i->rc)
1098d67b7dadSforsyth 				bprint(i, "CC");
109974a4d8c2SCharles.Forsyth 			break;
110074a4d8c2SCharles.Forsyth 
110174a4d8c2SCharles.Forsyth 		case 'D':
110274a4d8c2SCharles.Forsyth 			if(i->rd & 3)
110374a4d8c2SCharles.Forsyth 				bprint(i, "CR(INVAL:%d)", i->rd);
110474a4d8c2SCharles.Forsyth 			else if(i->op == 63)
110574a4d8c2SCharles.Forsyth 				bprint(i, "FPSCR(%d)", i->crfd);
110674a4d8c2SCharles.Forsyth 			else
110774a4d8c2SCharles.Forsyth 				bprint(i, "CR(%d)", i->crfd);
110874a4d8c2SCharles.Forsyth 			break;
110974a4d8c2SCharles.Forsyth 
1110d67b7dadSforsyth 		case 'e':
1111d67b7dadSforsyth 			bprint(i, "%d", i->xsh);
1112d67b7dadSforsyth 			break;
1113d67b7dadSforsyth 
1114d67b7dadSforsyth 		case 'E':
1115d67b7dadSforsyth 			switch(IBF(i->w0,27,30)){	/* low bit is top bit of shift in rldiX cases */
1116d67b7dadSforsyth 			case 8:	i->mb = i->xmbe; i->me = 63; break;	/* rldcl */
1117d67b7dadSforsyth 			case 9:	i->mb = 0; i->me = i->xmbe; break;	/* rldcr */
1118d67b7dadSforsyth 			case 4: case 5:
1119d67b7dadSforsyth 					i->mb = i->xmbe; i->me = 63-i->xsh; break;	/* rldic */
1120d67b7dadSforsyth 			case 0: case 1:
1121d67b7dadSforsyth 					i->mb = i->xmbe; i->me = 63; break;	/* rldicl */
1122d67b7dadSforsyth 			case 2: case 3:
1123d67b7dadSforsyth 					i->mb = 0; i->me = i->xmbe; break;	/* rldicr */
1124d67b7dadSforsyth 			case 6: case 7:
1125d67b7dadSforsyth 					i->mb = i->xmbe; i->me = 63-i->xsh; break;	/* rldimi */
1126d67b7dadSforsyth 			}
1127d67b7dadSforsyth 			vmask = (~(uvlong)0>>i->mb) & (~(uvlong)0<<(63-i->me));
1128d67b7dadSforsyth 			s = shmask(&vmask);
1129d67b7dadSforsyth 			if(s)
1130d67b7dadSforsyth 				bprint(i, "(%llux<<%d)", vmask, s);
1131d67b7dadSforsyth 			else
1132d67b7dadSforsyth 				bprint(i, "%llux", vmask);
113374a4d8c2SCharles.Forsyth 			break;
113474a4d8c2SCharles.Forsyth 
113574a4d8c2SCharles.Forsyth 		case 'i':
1136d67b7dadSforsyth 			bprint(i, "$%d", i->simm);
113774a4d8c2SCharles.Forsyth 			break;
113874a4d8c2SCharles.Forsyth 
113974a4d8c2SCharles.Forsyth 		case 'I':
1140d67b7dadSforsyth 			bprint(i, "$%ux", i->uimm);
114174a4d8c2SCharles.Forsyth 			break;
114274a4d8c2SCharles.Forsyth 
114374a4d8c2SCharles.Forsyth 		case 'j':
114474a4d8c2SCharles.Forsyth 			if(i->aa)
114574a4d8c2SCharles.Forsyth 				pglobal(i, i->li, 1, "(SB)");
114674a4d8c2SCharles.Forsyth 			else
114774a4d8c2SCharles.Forsyth 				pglobal(i, i->addr+i->li, 1, "");
114874a4d8c2SCharles.Forsyth 			break;
114974a4d8c2SCharles.Forsyth 
115074a4d8c2SCharles.Forsyth 		case 'J':
115174a4d8c2SCharles.Forsyth 			if(i->aa)
115274a4d8c2SCharles.Forsyth 				pglobal(i, i->bd, 1, "(SB)");
115374a4d8c2SCharles.Forsyth 			else
115474a4d8c2SCharles.Forsyth 				pglobal(i, i->addr+i->bd, 1, "");
115574a4d8c2SCharles.Forsyth 			break;
115674a4d8c2SCharles.Forsyth 
1157d67b7dadSforsyth 		case 'k':
1158d67b7dadSforsyth 			bprint(i, "%d", i->sh);
1159d67b7dadSforsyth 			break;
1160d67b7dadSforsyth 
1161d67b7dadSforsyth 		case 'K':
1162d67b7dadSforsyth 			bprint(i, "$%x", i->imm);
1163d67b7dadSforsyth 			break;
1164d67b7dadSforsyth 
1165d67b7dadSforsyth 		case 'L':
1166d67b7dadSforsyth 			if(i->lk)
1167d67b7dadSforsyth 				bprint(i, "L");
1168d67b7dadSforsyth 			break;
1169d67b7dadSforsyth 
1170d67b7dadSforsyth 		case 'l':
1171d67b7dadSforsyth 			if(i->simm < 0)
1172d67b7dadSforsyth 				bprint(i, "-%x(R%d)", -i->simm, i->ra);
1173d67b7dadSforsyth 			else
1174d67b7dadSforsyth 				bprint(i, "%x(R%d)", i->simm, i->ra);
1175d67b7dadSforsyth 			break;
1176d67b7dadSforsyth 
1177d67b7dadSforsyth 		case 'm':
1178d67b7dadSforsyth 			bprint(i, "%ux", i->crm);
1179d67b7dadSforsyth 			break;
1180d67b7dadSforsyth 
1181d67b7dadSforsyth 		case 'M':
1182d67b7dadSforsyth 			bprint(i, "%ux", i->fm);
1183d67b7dadSforsyth 			break;
1184d67b7dadSforsyth 
1185d67b7dadSforsyth 		case 'n':
1186d67b7dadSforsyth 			bprint(i, "%d", i->nb==0? 32: i->nb);	/* eg, pg 10-103 */
1187d67b7dadSforsyth 			break;
1188d67b7dadSforsyth 
1189d67b7dadSforsyth 		case 'P':
1190d67b7dadSforsyth 			n = ((i->spr&0x1f)<<5)|((i->spr>>5)&0x1f);
1191d67b7dadSforsyth 			for(s=0; sprname[s].name; s++)
1192d67b7dadSforsyth 				if(sprname[s].n == n)
1193d67b7dadSforsyth 					break;
1194d67b7dadSforsyth 			if(sprname[s].name) {
1195d67b7dadSforsyth 				if(s < 10)
1196d67b7dadSforsyth 					bprint(i, sprname[s].name);
1197d67b7dadSforsyth 				else
1198d67b7dadSforsyth 					bprint(i, "SPR(%s)", sprname[s].name);
1199d67b7dadSforsyth 			} else
1200d67b7dadSforsyth 				bprint(i, "SPR(%d)", n);
1201d67b7dadSforsyth 			break;
1202d67b7dadSforsyth 
1203d67b7dadSforsyth 		case 'Q':
1204d67b7dadSforsyth 			n = ((i->spr&0x1f)<<5)|((i->spr>>5)&0x1f);
1205d67b7dadSforsyth 			bprint(i, "%d", n);
1206d67b7dadSforsyth 			break;
1207d67b7dadSforsyth 
1208d67b7dadSforsyth 		case 'S':
1209d67b7dadSforsyth 			if(i->ra & 3)
1210d67b7dadSforsyth 				bprint(i, "CR(INVAL:%d)", i->ra);
1211d67b7dadSforsyth 			else if(i->op == 63)
1212d67b7dadSforsyth 				bprint(i, "FPSCR(%d)", i->crfs);
1213d67b7dadSforsyth 			else
1214d67b7dadSforsyth 				bprint(i, "CR(%d)", i->crfs);
1215d67b7dadSforsyth 			break;
1216d67b7dadSforsyth 
1217d67b7dadSforsyth 		case 'U':
1218d67b7dadSforsyth 			if(i->rc)
1219d67b7dadSforsyth 				bprint(i, "U");
1220d67b7dadSforsyth 			break;
1221d67b7dadSforsyth 
1222d67b7dadSforsyth 		case 'V':
1223d67b7dadSforsyth 			if(i->oe)
1224d67b7dadSforsyth 				bprint(i, "V");
1225d67b7dadSforsyth 			break;
1226d67b7dadSforsyth 
1227d67b7dadSforsyth 		case 'w':
1228d67b7dadSforsyth 			bprint(i, "[%lux]", i->w0);
1229d67b7dadSforsyth 			break;
1230d67b7dadSforsyth 
1231d67b7dadSforsyth 		case 'W':
1232d67b7dadSforsyth 			if(i->m64)
1233d67b7dadSforsyth 				bprint(i, "W");
1234d67b7dadSforsyth 			break;
1235d67b7dadSforsyth 
1236d67b7dadSforsyth 		case 'Z':
1237d67b7dadSforsyth 			if(i->m64)
1238d67b7dadSforsyth 				bprint(i, "Z");
1239d67b7dadSforsyth 			break;
1240d67b7dadSforsyth 
1241d67b7dadSforsyth 		case 'z':
1242d67b7dadSforsyth 			if(i->mb <= i->me)
1243d67b7dadSforsyth 				mask = ((ulong)~0L>>i->mb) & (~0L<<(31-i->me));
1244d67b7dadSforsyth 			else
1245d67b7dadSforsyth 				mask = ~(((ulong)~0L>>(i->me+1)) & (~0L<<(31-(i->mb-1))));
1246d67b7dadSforsyth 			bprint(i, "%lux", mask);
1247d67b7dadSforsyth 			break;
1248d67b7dadSforsyth 
124974a4d8c2SCharles.Forsyth 		case '\0':
125074a4d8c2SCharles.Forsyth 			bprint(i, "%%");
125174a4d8c2SCharles.Forsyth 			return;
125274a4d8c2SCharles.Forsyth 
125374a4d8c2SCharles.Forsyth 		default:
125474a4d8c2SCharles.Forsyth 			bprint(i, "%%%c", *f);
125574a4d8c2SCharles.Forsyth 			break;
125674a4d8c2SCharles.Forsyth 		}
125774a4d8c2SCharles.Forsyth 	}
125874a4d8c2SCharles.Forsyth }
125974a4d8c2SCharles.Forsyth 
126074a4d8c2SCharles.Forsyth static int
printins(Map * map,uvlong pc,char * buf,int n)1261d67b7dadSforsyth printins(Map *map, uvlong pc, char *buf, int n)
126274a4d8c2SCharles.Forsyth {
126374a4d8c2SCharles.Forsyth 	Instr i;
126474a4d8c2SCharles.Forsyth 	Opcode *o;
126574a4d8c2SCharles.Forsyth 
126674a4d8c2SCharles.Forsyth 	mymap = map;
126774a4d8c2SCharles.Forsyth 	memset(&i, 0, sizeof(i));
126874a4d8c2SCharles.Forsyth 	i.curr = buf;
126974a4d8c2SCharles.Forsyth 	i.end = buf+n-1;
127074a4d8c2SCharles.Forsyth 	if(mkinstr(pc, &i) < 0)
127174a4d8c2SCharles.Forsyth 		return -1;
127274a4d8c2SCharles.Forsyth 	for(o = opcodes; o->mnemonic != 0; o++)
127374a4d8c2SCharles.Forsyth 		if(i.op == o->op && (i.xo & o->xomask) == o->xo) {
127474a4d8c2SCharles.Forsyth 			if (o->f)
127574a4d8c2SCharles.Forsyth 				(*o->f)(o, &i);
127674a4d8c2SCharles.Forsyth 			else
127774a4d8c2SCharles.Forsyth 				format(o->mnemonic, &i, o->ken);
127874a4d8c2SCharles.Forsyth 			return i.size*4;
127974a4d8c2SCharles.Forsyth 		}
128074a4d8c2SCharles.Forsyth 	bprint(&i, "unknown %lux", i.w0);
128174a4d8c2SCharles.Forsyth 	return i.size*4;
128274a4d8c2SCharles.Forsyth }
128374a4d8c2SCharles.Forsyth 
128474a4d8c2SCharles.Forsyth static int
powerinst(Map * map,uvlong pc,char modifier,char * buf,int n)1285d67b7dadSforsyth powerinst(Map *map, uvlong pc, char modifier, char *buf, int n)
128674a4d8c2SCharles.Forsyth {
128774a4d8c2SCharles.Forsyth 	USED(modifier);
128874a4d8c2SCharles.Forsyth 	return printins(map, pc, buf, n);
128974a4d8c2SCharles.Forsyth }
129074a4d8c2SCharles.Forsyth 
129174a4d8c2SCharles.Forsyth static int
powerdas(Map * map,uvlong pc,char * buf,int n)1292d67b7dadSforsyth powerdas(Map *map, uvlong pc, char *buf, int n)
129374a4d8c2SCharles.Forsyth {
129474a4d8c2SCharles.Forsyth 	Instr instr;
129574a4d8c2SCharles.Forsyth 
129674a4d8c2SCharles.Forsyth 	mymap = map;
129774a4d8c2SCharles.Forsyth 	memset(&instr, 0, sizeof(instr));
129874a4d8c2SCharles.Forsyth 	instr.curr = buf;
129974a4d8c2SCharles.Forsyth 	instr.end = buf+n-1;
130074a4d8c2SCharles.Forsyth 	if (mkinstr(pc, &instr) < 0)
130174a4d8c2SCharles.Forsyth 		return -1;
130274a4d8c2SCharles.Forsyth 	if (instr.end-instr.curr > 8)
130374a4d8c2SCharles.Forsyth 		instr.curr = _hexify(instr.curr, instr.w0, 7);
130474a4d8c2SCharles.Forsyth 	if (instr.end-instr.curr > 9 && instr.size == 2) {
130574a4d8c2SCharles.Forsyth 		*instr.curr++ = ' ';
130674a4d8c2SCharles.Forsyth 		instr.curr = _hexify(instr.curr, instr.w1, 7);
130774a4d8c2SCharles.Forsyth 	}
130874a4d8c2SCharles.Forsyth 	*instr.curr = 0;
130974a4d8c2SCharles.Forsyth 	return instr.size*4;
131074a4d8c2SCharles.Forsyth }
131174a4d8c2SCharles.Forsyth 
131274a4d8c2SCharles.Forsyth static int
powerinstlen(Map * map,uvlong pc)1313d67b7dadSforsyth powerinstlen(Map *map, uvlong pc)
131474a4d8c2SCharles.Forsyth {
131574a4d8c2SCharles.Forsyth 	Instr i;
131674a4d8c2SCharles.Forsyth 
131774a4d8c2SCharles.Forsyth 	mymap = map;
131874a4d8c2SCharles.Forsyth 	if (mkinstr(pc, &i) < 0)
131974a4d8c2SCharles.Forsyth 		return -1;
132074a4d8c2SCharles.Forsyth 	return i.size*4;
132174a4d8c2SCharles.Forsyth }
132274a4d8c2SCharles.Forsyth 
132374a4d8c2SCharles.Forsyth static int
powerfoll(Map * map,uvlong pc,Rgetter rget,uvlong * foll)1324d67b7dadSforsyth powerfoll(Map *map, uvlong pc, Rgetter rget, uvlong *foll)
132574a4d8c2SCharles.Forsyth {
132674a4d8c2SCharles.Forsyth 	char *reg;
132774a4d8c2SCharles.Forsyth 	Instr i;
132874a4d8c2SCharles.Forsyth 
132974a4d8c2SCharles.Forsyth 	mymap = map;
133074a4d8c2SCharles.Forsyth 	if (mkinstr(pc, &i) < 0)
133174a4d8c2SCharles.Forsyth 		return -1;
133274a4d8c2SCharles.Forsyth 	foll[0] = pc+4;
133374a4d8c2SCharles.Forsyth 	foll[1] = pc+4;
133474a4d8c2SCharles.Forsyth 	switch(i.op) {
133574a4d8c2SCharles.Forsyth 	default:
133674a4d8c2SCharles.Forsyth 		return 1;
133774a4d8c2SCharles.Forsyth 
133874a4d8c2SCharles.Forsyth 	case 18:	/* branch */
133974a4d8c2SCharles.Forsyth 		foll[0] = i.li;
134074a4d8c2SCharles.Forsyth 		if(!i.aa)
134174a4d8c2SCharles.Forsyth 			foll[0] += pc;
134274a4d8c2SCharles.Forsyth 		break;
134374a4d8c2SCharles.Forsyth 
134474a4d8c2SCharles.Forsyth 	case 16:	/* conditional branch */
134574a4d8c2SCharles.Forsyth 		foll[0] = i.bd;
134674a4d8c2SCharles.Forsyth 		if(!i.aa)
134774a4d8c2SCharles.Forsyth 			foll[0] += pc;
134874a4d8c2SCharles.Forsyth 		break;
134974a4d8c2SCharles.Forsyth 
135074a4d8c2SCharles.Forsyth 	case 19:	/* conditional branch to register */
135174a4d8c2SCharles.Forsyth 		if(i.xo == 528)
135274a4d8c2SCharles.Forsyth 			reg = "CTR";
135374a4d8c2SCharles.Forsyth 		else if(i.xo == 16)
135474a4d8c2SCharles.Forsyth 			reg = "LR";
135574a4d8c2SCharles.Forsyth 		else
135674a4d8c2SCharles.Forsyth 			return 1;	/* not a branch */
135774a4d8c2SCharles.Forsyth 		foll[0] = (*rget)(map, reg);
135874a4d8c2SCharles.Forsyth 		break;
135974a4d8c2SCharles.Forsyth 	}
136074a4d8c2SCharles.Forsyth 	if(i.lk)
136174a4d8c2SCharles.Forsyth 		return 2;
136274a4d8c2SCharles.Forsyth 	return 1;
136374a4d8c2SCharles.Forsyth }
1364