xref: /inferno-os/utils/libmach/qdb.c (revision 2b69dba5038ffd0b59cf30a4c44bce549e5097f8)
1 #include <lib9.h>
2 #include <bio.h>
3 #include "mach.h"
4 
5 /*
6  * PowerPC-specific debugger interface,
7  * including 64-bit modes
8  *	forsyth@terzarima.net
9  */
10 
11 static	char	*powerexcep(Map*, Rgetter);
12 static	int	powerfoll(Map*, uvlong, Rgetter, uvlong*);
13 static	int	powerinst(Map*, uvlong, char, char*, int);
14 static	int	powerinstlen(Map*, uvlong);
15 static	int	powerdas(Map*, uvlong, char*, int);
16 
17 /*
18  *	Machine description
19  */
20 Machdata powermach =
21 {
22 	{0x07f, 0xe0, 0x00, 0x08},		/* breakpoint (tw 31,r0,r0) */
23 	4,			/* break point size */
24 
25 	beswab,			/* short to local byte order */
26 	beswal,			/* long to local byte order */
27 	beswav,			/* vlong to local byte order */
28 	risctrace,		/* print C traceback */
29 	riscframe,		/* frame finder */
30 	powerexcep,		/* print exception */
31 	0,			/* breakpoint fixup */
32 	beieeesftos,		/* single precision float printer */
33 	beieeedftos,		/* double precisioin float printer */
34 	powerfoll,		/* following addresses */
35 	powerinst,		/* print instruction */
36 	powerdas,		/* dissembler */
37 	powerinstlen,		/* instruction size */
38 };
39 
40 static char *excname[] =
41 {
42 	"reserved 0",
43 	"system reset",
44 	"machine check",
45 	"data access",
46 	"instruction access",
47 	"external interrupt",
48 	"alignment",
49 	"program exception",
50 	"floating-point unavailable",
51 	"decrementer",
52 	"i/o controller interface error",
53 	"reserved B",
54 	"system call",
55 	"trace trap",
56 	"floating point assist",
57 	"reserved",
58 	"ITLB miss",
59 	"DTLB load miss",
60 	"DTLB store miss",
61 	"instruction address breakpoint"
62 	"SMI interrupt"
63 	"reserved 15",
64 	"reserved 16",
65 	"reserved 17",
66 	"reserved 18",
67 	"reserved 19",
68 	"reserved 1A",
69 	/* the following are made up on a program exception */
70 	"floating point exception",		/* FPEXC */
71 	"illegal instruction",
72 	"privileged instruction",
73 	"trap",
74 	"illegal operation",
75 	"breakpoint",	/* 20 */
76 };
77 
78 static char*
79 powerexcep(Map *map, Rgetter rget)
80 {
81 	long c;
82 	static char buf[32];
83 
84 	c = (*rget)(map, "CAUSE") >> 8;
85 	if(c < nelem(excname))
86 		return excname[c];
87 	sprint(buf, "unknown trap #%lx", c);
88 	return buf;
89 }
90 
91 /*
92  * disassemble PowerPC opcodes
93  */
94 
95 #define	REGSP	1	/* should come from q.out.h, but there's a clash */
96 #define	REGSB	2
97 
98 static	char FRAMENAME[] = ".frame";
99 
100 static Map *mymap;
101 
102 /*
103  * ibm conventions for these: bit 0 is top bit
104  *	from table 10-1
105  */
106 typedef struct {
107 	uchar	aa;		/* bit 30 */
108 	uchar	crba;		/* bits 11-15 */
109 	uchar	crbb;		/* bits 16-20 */
110 	long	bd;		/* bits 16-29 */
111 	uchar	crfd;		/* bits 6-8 */
112 	uchar	crfs;		/* bits 11-13 */
113 	uchar	bi;		/* bits 11-15 */
114 	uchar	bo;		/* bits 6-10 */
115 	uchar	crbd;		/* bits 6-10 */
116 	/* union { */
117 		short	d;	/* bits 16-31 */
118 		short	simm;
119 		ushort	uimm;
120 	/*}; */
121 	uchar	fm;		/* bits 7-14 */
122 	uchar	fra;		/* bits 11-15 */
123 	uchar	frb;		/* bits 16-20 */
124 	uchar	frc;		/* bits 21-25 */
125 	uchar	frs;		/* bits 6-10 */
126 	uchar	frd;		/* bits 6-10 */
127 	uchar	crm;		/* bits 12-19 */
128 	long	li;		/* bits 6-29 || b'00' */
129 	uchar	lk;		/* bit 31 */
130 	uchar	mb;		/* bits 21-25 */
131 	uchar	me;		/* bits 26-30 */
132 	uchar	xmbe;		/* bits 26,21-25: mb[5] || mb[0:4], also xme */
133 	uchar	xsh;		/* bits 30,16-20: sh[5] || sh[0:4] */
134 	uchar	nb;		/* bits 16-20 */
135 	uchar	op;		/* bits 0-5 */
136 	uchar	oe;		/* bit 21 */
137 	uchar	ra;		/* bits 11-15 */
138 	uchar	rb;		/* bits 16-20 */
139 	uchar	rc;		/* bit 31 */
140 	/* union { */
141 		uchar	rs;	/* bits 6-10 */
142 		uchar	rd;
143 	/*};*/
144 	uchar	sh;		/* bits 16-20 */
145 	ushort	spr;		/* bits 11-20 */
146 	uchar	to;		/* bits 6-10 */
147 	uchar	imm;		/* bits 16-19 */
148 	ushort	xo;		/* bits 21-30, 22-30, 26-30, or 30 (beware) */
149 	uvlong	imm64;
150 	long w0;
151 	long w1;
152 	uvlong	addr;		/* pc of instruction */
153 	short	target;
154 	short	m64;		/* 64-bit mode */
155 	char	*curr;		/* current fill level in output buffer */
156 	char	*end;		/* end of buffer */
157 	int 	size;		/* number of longs in instr */
158 	char	*err;		/* errmsg */
159 } Instr;
160 
161 #define	IBF(v,a,b) (((ulong)(v)>>(32-(b)-1)) & ~(~0L<<(((b)-(a)+1))))
162 #define	IB(v,b) IBF((v),(b),(b))
163 
164 #pragma	varargck	argpos	bprint		2
165 
166 static void
167 bprint(Instr *i, char *fmt, ...)
168 {
169 	va_list arg;
170 
171 	va_start(arg, fmt);
172 	i->curr = vseprint(i->curr, i->end, fmt, arg);
173 	va_end(arg);
174 }
175 
176 static int
177 decode(uvlong pc, Instr *i)
178 {
179 	ulong w;
180 
181 	if (get4(mymap, pc, &w) < 0) {
182 		werrstr("can't read instruction: %r");
183 		return -1;
184 	}
185 	i->m64 = asstype == APOWER64;
186 	i->aa = IB(w, 30);
187 	i->crba = IBF(w, 11, 15);
188 	i->crbb = IBF(w, 16, 20);
189 	i->bd = IBF(w, 16, 29)<<2;
190 	if(i->bd & 0x8000)
191 		i->bd |= ~0L<<16;
192 	i->crfd = IBF(w, 6, 8);
193 	i->crfs = IBF(w, 11, 13);
194 	i->bi = IBF(w, 11, 15);
195 	i->bo = IBF(w, 6, 10);
196 	i->crbd = IBF(w, 6, 10);
197 	i->uimm = IBF(w, 16, 31);	/* also d, simm */
198 	i->fm = IBF(w, 7, 14);
199 	i->fra = IBF(w, 11, 15);
200 	i->frb = IBF(w, 16, 20);
201 	i->frc = IBF(w, 21, 25);
202 	i->frs = IBF(w, 6, 10);
203 	i->frd = IBF(w, 6, 10);
204 	i->crm = IBF(w, 12, 19);
205 	i->li = IBF(w, 6, 29)<<2;
206 	if(IB(w, 6))
207 		i->li |= ~0<<25;
208 	i->lk = IB(w, 31);
209 	i->mb = IBF(w, 21, 25);
210 	i->me = IBF(w, 26, 30);
211 	i->xmbe = (IB(w,26)<<5) | i->mb;
212 	i->nb = IBF(w, 16, 20);
213 	i->op = IBF(w, 0, 5);
214 	i->oe = IB(w, 21);
215 	i->ra = IBF(w, 11, 15);
216 	i->rb = IBF(w, 16, 20);
217 	i->rc = IB(w, 31);
218 	i->rs = IBF(w, 6, 10);	/* also rd */
219 	i->sh = IBF(w, 16, 20);
220 	i->xsh = (IB(w, 30)<<5) | i->sh;
221 	i->spr = IBF(w, 11, 20);
222 	i->to = IBF(w, 6, 10);
223 	i->imm = IBF(w, 16, 19);
224 	i->xo = IBF(w, 21, 30);		/* bits 21-30, 22-30, 26-30, or 30 (beware) */
225 	if(i->op == 58){	/* class of 64-bit loads */
226 		i->xo = i->simm & 3;
227 		i->simm &= ~3;
228 	}
229 	i->imm64 = i->simm;
230 	if(i->op == 15)
231 		i->imm64 <<= 16;
232 	else if(i->op == 25 || i->op == 27 || i->op == 29)
233 		i->imm64 = (uvlong)(i->uimm<<16);
234 	i->w0 = w;
235 	i->target = -1;
236 	i->addr = pc;
237 	i->size = 1;
238 	return 1;
239 }
240 
241 static int
242 mkinstr(uvlong pc, Instr *i)
243 {
244 	Instr x;
245 
246 	if(decode(pc, i) < 0)
247 		return -1;
248 	/*
249 	 * combine ADDIS/ORI (CAU/ORIL) into MOVW
250 	 * also ORIS/ORIL for unsigned in 64-bit mode
251 	 */
252 	if ((i->op == 15 || i->op == 25) && i->ra==0) {
253 		if(decode(pc+4, &x) < 0)
254 			return -1;
255 		if (x.op == 24 && x.rs == x.ra && x.ra == i->rd) {
256 			i->imm64 |= (x.imm64 & 0xFFFF);
257 			if(i->op != 15)
258 				i->imm64 &= 0xFFFFFFFFUL;
259 			i->w1 = x.w0;
260 			i->target = x.rd;
261 			i->size++;
262 			return 1;
263 		}
264 	}
265 	return 1;
266 }
267 
268 static int
269 plocal(Instr *i)
270 {
271 	long offset;
272 	Symbol s;
273 
274 	if (!findsym(i->addr, CTEXT, &s) || !findlocal(&s, FRAMENAME, &s))
275 		return -1;
276 	offset = s.value - i->imm64;
277 	if (offset > 0) {
278 		if(getauto(&s, offset, CAUTO, &s)) {
279 			bprint(i, "%s+%lld(SP)", s.name, s.value);
280 			return 1;
281 		}
282 	} else {
283 		if (getauto(&s, -offset-4, CPARAM, &s)) {
284 			bprint(i, "%s+%ld(FP)", s.name, -offset);
285 			return 1;
286 		}
287 	}
288 	return -1;
289 }
290 
291 static int
292 pglobal(Instr *i, uvlong off, int anyoff, char *reg)
293 {
294 	Symbol s, s2;
295 	uvlong off1;
296 
297 	if(findsym(off, CANY, &s) &&
298 	   s.value-off < 4096 &&
299 	   (s.class == CDATA || s.class == CTEXT)) {
300 		if(off==s.value && s.name[0]=='$'){
301 			off1 = 0;
302 			geta(mymap, s.value, &off1);
303 			if(off1 && findsym(off1, CANY, &s2) && s2.value == off1){
304 				bprint(i, "$%s%s", s2.name, reg);
305 				return 1;
306 			}
307 		}
308 		bprint(i, "%s", s.name);
309 		if (s.value != off)
310 			bprint(i, "+%llux", off-s.value);
311 		bprint(i, reg);
312 		return 1;
313 	}
314 	if(!anyoff)
315 		return 0;
316 	bprint(i, "%llux%s", off, reg);
317 	return 1;
318 }
319 
320 static void
321 address(Instr *i)
322 {
323 	if (i->ra == REGSP && plocal(i) >= 0)
324 		return;
325 	if (i->ra == REGSB && mach->sb && pglobal(i, mach->sb+i->imm64, 0, "(SB)") >= 0)
326 		return;
327 	if(i->simm < 0)
328 		bprint(i, "-%x(R%d)", -i->simm, i->ra);
329 	else
330 		bprint(i, "%llux(R%d)", i->imm64, i->ra);
331 }
332 
333 static	char	*tcrbits[] = {"LT", "GT", "EQ", "VS"};
334 static	char	*fcrbits[] = {"GE", "LE", "NE", "VC"};
335 
336 typedef struct Opcode Opcode;
337 
338 struct Opcode {
339 	uchar	op;
340 	ushort	xo;
341 	ushort	xomask;
342 	char	*mnemonic;
343 	void	(*f)(Opcode *, Instr *);
344 	char	*ken;
345 	int	flags;
346 };
347 
348 static void format(char *, Instr *, char *);
349 
350 static void
351 branch(Opcode *o, Instr *i)
352 {
353 	char buf[8];
354 	int bo, bi;
355 
356 	bo = i->bo & ~1;	/* ignore prediction bit */
357 	if(bo==4 || bo==12 || bo==20) {	/* simple forms */
358 		if(bo != 20) {
359 			bi = i->bi&3;
360 			sprint(buf, "B%s%%L", bo==12? tcrbits[bi]: fcrbits[bi]);
361 			format(buf, i, nil);
362 			bprint(i, "\t");
363 			if(i->bi > 4)
364 				bprint(i, "CR(%d),", i->bi/4);
365 		} else
366 			format("BR%L\t", i, nil);
367 		if(i->op == 16)
368 			format(0, i, "%J");
369 		else if(i->op == 19 && i->xo == 528)
370 			format(0, i, "(CTR)");
371 		else if(i->op == 19 && i->xo == 16)
372 			format(0, i, "(LR)");
373 	} else
374 		format(o->mnemonic, i, o->ken);
375 }
376 
377 static void
378 addi(Opcode *o, Instr *i)
379 {
380 	if (i->op==14 && i->ra == 0)
381 		format("MOVW", i, "%i,R%d");
382 	else if (i->ra == REGSB) {
383 		bprint(i, "MOVW\t$");
384 		address(i);
385 		bprint(i, ",R%d", i->rd);
386 	} else if(i->op==14 && i->simm < 0) {
387 		bprint(i, "SUB\t$%d,R%d", -i->simm, i->ra);
388 		if(i->rd != i->ra)
389 			bprint(i, ",R%d", i->rd);
390 	} else if(i->ra == i->rd) {
391 		format(o->mnemonic, i, "%i");
392 		bprint(i, ",R%d", i->rd);
393 	} else
394 		format(o->mnemonic, i, o->ken);
395 }
396 
397 static void
398 addis(Opcode *o, Instr *i)
399 {
400 	long v;
401 
402 	v = i->imm64;
403 	if (i->op==15 && i->ra == 0)
404 		bprint(i, "MOVW\t$%lux,R%d", v, i->rd);
405 	else if (i->op==15 && i->ra == REGSB) {
406 		bprint(i, "MOVW\t$");
407 		address(i);
408 		bprint(i, ",R%d", i->rd);
409 	} else if(i->op==15 && v < 0) {
410 		bprint(i, "SUB\t$%ld,R%d", -v, i->ra);
411 		if(i->rd != i->ra)
412 			bprint(i, ",R%d", i->rd);
413 	} else {
414 		format(o->mnemonic, i, nil);
415 		bprint(i, "\t$%ld,R%d", v, i->ra);
416 		if(i->rd != i->ra)
417 			bprint(i, ",R%d", i->rd);
418 	}
419 }
420 
421 static void
422 andi(Opcode *o, Instr *i)
423 {
424 	if (i->ra == i->rs)
425 		format(o->mnemonic, i, "%I,R%d");
426 	else
427 		format(o->mnemonic, i, o->ken);
428 }
429 
430 static void
431 gencc(Opcode *o, Instr *i)
432 {
433 	format(o->mnemonic, i, o->ken);
434 }
435 
436 static void
437 gen(Opcode *o, Instr *i)
438 {
439 	format(o->mnemonic, i, o->ken);
440 	if (i->rc)
441 		bprint(i, " [illegal Rc]");
442 }
443 
444 static void
445 ldx(Opcode *o, Instr *i)
446 {
447 	if(i->ra == 0)
448 		format(o->mnemonic, i, "(R%b),R%d");
449 	else
450 		format(o->mnemonic, i, "(R%b+R%a),R%d");
451 	if(i->rc)
452 		bprint(i, " [illegal Rc]");
453 }
454 
455 static void
456 stx(Opcode *o, Instr *i)
457 {
458 	if(i->ra == 0)
459 		format(o->mnemonic, i, "R%d,(R%b)");
460 	else
461 		format(o->mnemonic, i, "R%d,(R%b+R%a)");
462 	if(i->rc && i->xo != 150)
463 		bprint(i, " [illegal Rc]");
464 }
465 
466 static void
467 fldx(Opcode *o, Instr *i)
468 {
469 	if(i->ra == 0)
470 		format(o->mnemonic, i, "(R%b),F%d");
471 	else
472 		format(o->mnemonic, i, "(R%b+R%a),F%d");
473 	if(i->rc)
474 		bprint(i, " [illegal Rc]");
475 }
476 
477 static void
478 fstx(Opcode *o, Instr *i)
479 {
480 	if(i->ra == 0)
481 		format(o->mnemonic, i, "F%d,(R%b)");
482 	else
483 		format(o->mnemonic, i, "F%d,(R%b+R%a)");
484 	if(i->rc)
485 		bprint(i, " [illegal Rc]");
486 }
487 
488 static void
489 dcb(Opcode *o, Instr *i)
490 {
491 	if(i->ra == 0)
492 		format(o->mnemonic, i, "(R%b)");
493 	else
494 		format(o->mnemonic, i, "(R%b+R%a)");
495 	if(i->rd)
496 		bprint(i, " [illegal Rd]");
497 	if(i->rc)
498 		bprint(i, " [illegal Rc]");
499 }
500 
501 static void
502 lw(Opcode *o, Instr *i, char r)
503 {
504 	format(o->mnemonic, i, nil);
505 	bprint(i, "\t");
506 	address(i);
507 	bprint(i, ",%c%d", r, i->rd);
508 }
509 
510 static void
511 load(Opcode *o, Instr *i)
512 {
513 	lw(o, i, 'R');
514 }
515 
516 static void
517 fload(Opcode *o, Instr *i)
518 {
519 	lw(o, i, 'F');
520 }
521 
522 static void
523 sw(Opcode *o, Instr *i, char r)
524 {
525 	int offset;
526 	Symbol s;
527 
528 	if (i->rs == REGSP) {
529 		if (findsym(i->addr, CTEXT, &s) && findlocal(&s, FRAMENAME, &s)) {
530 			offset = s.value-i->imm64;
531 			if (offset > 0 && getauto(&s, offset, CAUTO, &s)) {
532 				format(o->mnemonic, i, nil);
533 				bprint(i, "\t%c%d,%s-%d(SP)", r, i->rd, s.name, offset);
534 				return;
535 			}
536 		}
537 	}
538 	if (i->rs == REGSB && mach->sb) {
539 		format(o->mnemonic, i, nil);
540 		bprint(i, "\t%c%d,", r, i->rd);
541 		address(i);
542 		return;
543 	}
544 	if (r == 'F')
545 		format(o->mnemonic, i, "F%d,%l");
546 	else
547 		format(o->mnemonic, i, o->ken);
548 }
549 
550 static void
551 store(Opcode *o, Instr *i)
552 {
553 	sw(o, i, 'R');
554 }
555 
556 static void
557 fstore(Opcode *o, Instr *i)
558 {
559 	sw(o, i, 'F');
560 }
561 
562 static void
563 shifti(Opcode *o, Instr *i)
564 {
565 	if (i->ra == i->rs)
566 		format(o->mnemonic, i, "$%k,R%a");
567 	else
568 		format(o->mnemonic, i, o->ken);
569 }
570 
571 static void
572 shift(Opcode *o, Instr *i)
573 {
574 	if (i->ra == i->rs)
575 		format(o->mnemonic, i, "R%b,R%a");
576 	else
577 		format(o->mnemonic, i, o->ken);
578 }
579 
580 static void
581 add(Opcode *o, Instr *i)
582 {
583 	if (i->rd == i->ra)
584 		format(o->mnemonic, i, "R%b,R%d");
585 	else if (i->rd == i->rb)
586 		format(o->mnemonic, i, "R%a,R%d");
587 	else
588 		format(o->mnemonic, i, o->ken);
589 }
590 
591 static void
592 sub(Opcode *o, Instr *i)
593 {
594 	format(o->mnemonic, i, nil);
595 	bprint(i, "\t");
596 	if(i->op == 31) {
597 		bprint(i, "\tR%d,R%d", i->ra, i->rb);	/* subtract Ra from Rb */
598 		if(i->rd != i->rb)
599 			bprint(i, ",R%d", i->rd);
600 	} else
601 		bprint(i, "\tR%d,$%d,R%d", i->ra, i->simm, i->rd);
602 }
603 
604 static void
605 qmuldiv(Opcode *o, Instr *i)
606 {
607 	format(o->mnemonic, i, nil);
608 	if(i->op == 31)
609 		bprint(i, "\tR%d,R%d", i->rb, i->ra);
610 	else
611 		bprint(i, "\t$%d,R%d", i->simm, i->ra);
612 	if(i->ra != i->rd)
613 		bprint(i, ",R%d", i->rd);
614 }
615 
616 static void
617 and(Opcode *o, Instr *i)
618 {
619 	if (i->op == 31) {
620 		/* Rb,Rs,Ra */
621 		if (i->ra == i->rs)
622 			format(o->mnemonic, i, "R%b,R%a");
623 		else if (i->ra == i->rb)
624 			format(o->mnemonic, i, "R%s,R%a");
625 		else
626 			format(o->mnemonic, i, o->ken);
627 	} else {
628 		/* imm,Rs,Ra */
629 		if (i->ra == i->rs)
630 			format(o->mnemonic, i, "%I,R%a");
631 		else
632 			format(o->mnemonic, i, o->ken);
633 	}
634 }
635 
636 static void
637 or(Opcode *o, Instr *i)
638 {
639 	if (i->op == 31) {
640 		/* Rb,Rs,Ra */
641 		if (i->rs == 0 && i->ra == 0 && i->rb == 0)
642 			format("NOP", i, nil);
643 		else if (i->rs == i->rb)
644 			format("MOVW", i, "R%b,R%a");
645 		else
646 			and(o, i);
647 	} else
648 		and(o, i);
649 }
650 
651 static void
652 shifted(Opcode *o, Instr *i)
653 {
654 	format(o->mnemonic, i, nil);
655 	bprint(i, "\t$%lux,", (ulong)i->uimm<<16);
656 	if (i->rs == i->ra)
657 		bprint(i, "R%d", i->ra);
658 	else
659 		bprint(i, "R%d,R%d", i->rs, i->ra);
660 }
661 
662 static void
663 neg(Opcode *o, Instr *i)
664 {
665 	if (i->rd == i->ra)
666 		format(o->mnemonic, i, "R%d");
667 	else
668 		format(o->mnemonic, i, o->ken);
669 }
670 
671 static	char	ir2[] = "R%a,R%d";		/* reverse of IBM order */
672 static	char	ir3[] = "R%b,R%a,R%d";
673 static	char	ir3r[] = "R%a,R%b,R%d";
674 static	char	il3[] = "R%b,R%s,R%a";
675 static	char	il2u[] = "%I,R%a,R%d";
676 static	char	il3s[] = "$%k,R%s,R%a";
677 static	char	il2[] = "R%s,R%a";
678 static	char	icmp3[] = "R%a,R%b,%D";
679 static	char	cr3op[] = "%b,%a,%d";
680 static	char	ir2i[] = "%i,R%a,R%d";
681 static	char	fp2[] = "F%b,F%d";
682 static	char	fp3[] = "F%b,F%a,F%d";
683 static	char	fp3c[] = "F%c,F%a,F%d";
684 static	char	fp4[] = "F%a,F%c,F%b,F%d";
685 static	char	fpcmp[] = "F%a,F%b,%D";
686 static	char	ldop[] = "%l,R%d";
687 static	char	stop[] = "R%d,%l";
688 static	char	fldop[] = "%l,F%d";
689 static	char	fstop[] = "F%d,%l";
690 static	char	rldc[] = "R%b,R%s,$%E,R%a";
691 static	char	rlim[] = "R%b,R%s,$%z,R%a";
692 static	char	rlimi[] = "$%k,R%s,$%z,R%a";
693 static	char	rldi[] = "$%e,R%s,$%E,R%a";
694 
695 #define	OEM	IBF(~0,22,30)
696 #define	FP4	IBF(~0,26,30)
697 #define	ALL	(~0)
698 #define	RLDC	0xF
699 #define	RLDI	0xE
700 /*
701 notes:
702 	10-26: crfD = rD>>2; rD&3 mbz
703 		also, L bit (bit 10) mbz or selects 64-bit operands
704 */
705 
706 static Opcode opcodes[] = {
707 	{31,	266,	OEM,	"ADD%V%C",	add,	ir3},
708 	{31,	 10,	OEM,	"ADDC%V%C",	add,	ir3},
709 	{31,	138,	OEM,	"ADDE%V%C",	add,	ir3},
710 	{14,	0,	0,	"ADD",		addi,	ir2i},
711 	{12,	0,	0,	"ADDC",		addi,	ir2i},
712 	{13,	0,	0,	"ADDCCC",	addi,	ir2i},
713 	{15,	0,	0,	"ADD",		addis,	0},
714 	{31,	234,	OEM,	"ADDME%V%C",	gencc,	ir2},
715 	{31,	202,	OEM,	"ADDZE%V%C",	gencc,	ir2},
716 
717 	{31,	28,	ALL,	"AND%C",	and,	il3},
718 	{31,	60,	ALL,	"ANDN%C",	and,	il3},
719 	{28,	0,	0,	"ANDCC",	andi,	il2u},
720 	{29,	0,	0,	"ANDCC",	shifted, 0},
721 
722 	{18,	0,	0,	"B%L",		gencc,	"%j"},
723 	{16,	0,	0,	"BC%L",		branch,	"%d,%a,%J"},
724 	{19,	528,	ALL,	"BC%L",		branch,	"%d,%a,(CTR)"},
725 	{19,	16,	ALL,	"BC%L",		branch,	"%d,%a,(LR)"},
726 
727 	{31,	0,	ALL,	"CMP",		0,	icmp3},
728 	{11,	0,	0,	"CMP",		0,	"R%a,%i,%D"},
729 	{31,	32,	ALL,	"CMPU",		0,	icmp3},
730 	{10,	0,	0,	"CMPU",		0,	"R%a,%I,%D"},
731 
732 	{31,	58,	ALL,	"CNTLZD%C",	gencc,	ir2},	/* 64 */
733 	{31,	26,	ALL,	"CNTLZ%W%C",	gencc,	ir2},
734 
735 	{19,	257,	ALL,	"CRAND",	gen,	cr3op},
736 	{19,	129,	ALL,	"CRANDN",	gen,	cr3op},
737 	{19,	289,	ALL,	"CREQV",	gen,	cr3op},
738 	{19,	225,	ALL,	"CRNAND",	gen,	cr3op},
739 	{19,	33,	ALL,	"CRNOR",	gen,	cr3op},
740 	{19,	449,	ALL,	"CROR",		gen,	cr3op},
741 	{19,	417,	ALL,	"CRORN",	gen,	cr3op},
742 	{19,	193,	ALL,	"CRXOR",	gen,	cr3op},
743 
744 	{31,	86,	ALL,	"DCBF",		dcb,	0},
745 	{31,	470,	ALL,	"DCBI",		dcb,	0},
746 	{31,	54,	ALL,	"DCBST",	dcb,	0},
747 	{31,	278,	ALL,	"DCBT",		dcb,	0},
748 	{31,	246,	ALL,	"DCBTST",	dcb,	0},
749 	{31,	1014,	ALL,	"DCBZ",		dcb,	0},
750 	{31,	454,	ALL,	"DCCCI",	dcb,	0},
751 	{31,	966,	ALL,	"ICCCI",	dcb,	0},
752 
753 	{31,	489,	OEM,	"DIVD%V%C",	qmuldiv,	ir3},	/* 64 */
754 	{31,	457,	OEM,	"DIVDU%V%C",	qmuldiv,	ir3},	/* 64 */
755 	{31,	491,	OEM,	"DIVW%V%C",	qmuldiv,	ir3},
756 	{31,	459,	OEM,	"DIVWU%V%C",	qmuldiv,	ir3},
757 
758 	{31,	310,	ALL,	"ECIWX",	ldx,	0},
759 	{31,	438,	ALL,	"ECOWX",	stx,	0},
760 	{31,	854,	ALL,	"EIEIO",	gen,	0},
761 
762 	{31,	284,	ALL,	"EQV%C",	gencc,	il3},
763 
764 	{31,	954,	ALL,	"EXTSB%C",	gencc,	il2},
765 	{31,	922,	ALL,	"EXTSH%C",	gencc,	il2},
766 	{31,	986,	ALL,	"EXTSW%C",	gencc,	il2},	/* 64 */
767 
768 	{63,	264,	ALL,	"FABS%C",	gencc,	fp2},
769 	{63,	21,	ALL,	"FADD%C",	gencc,	fp3},
770 	{59,	21,	ALL,	"FADDS%C",	gencc,	fp3},
771 	{63,	32,	ALL,	"FCMPO",	gen,	fpcmp},
772 	{63,	0,	ALL,	"FCMPU",	gen,	fpcmp},
773 	{63,	846,	ALL,	"FCFID%C",	gencc,	fp2},	/* 64 */
774 	{63,	814,	ALL,	"FCTID%C",	gencc,	fp2},	/* 64 */
775 	{63,	815,	ALL,	"FCTIDZ%C",	gencc,	fp2},	/* 64 */
776 	{63,	14,	ALL,	"FCTIW%C",	gencc,	fp2},
777 	{63,	15,	ALL,	"FCTIWZ%C",	gencc,	fp2},
778 	{63,	18,	ALL,	"FDIV%C",	gencc,	fp3},
779 	{59,	18,	ALL,	"FDIVS%C",	gencc,	fp3},
780 	{63,	29,	FP4,	"FMADD%C",	gencc,	fp4},
781 	{59,	29,	FP4,	"FMADDS%C",	gencc,	fp4},
782 	{63,	72,	ALL,	"FMOVD%C",	gencc,	fp2},
783 	{63,	28,	FP4,	"FMSUB%C",	gencc,	fp4},
784 	{59,	28,	FP4,	"FMSUBS%C",	gencc,	fp4},
785 	{63,	25,	FP4,	"FMUL%C",	gencc,	fp3c},
786 	{59,	25,	FP4,	"FMULS%C",	gencc,	fp3c},
787 	{63,	136,	ALL,	"FNABS%C",	gencc,	fp2},
788 	{63,	40,	ALL,	"FNEG%C",	gencc,	fp2},
789 	{63,	31,	FP4,	"FNMADD%C",	gencc,	fp4},
790 	{59,	31,	FP4,	"FNMADDS%C",	gencc,	fp4},
791 	{63,	30,	FP4,	"FNMSUB%C",	gencc,	fp4},
792 	{59,	30,	FP4,	"FNMSUBS%C",	gencc,	fp4},
793 	{59,	24,	ALL,	"FRES%C",	gencc,	fp2},	/* optional */
794 	{63,	12,	ALL,	"FRSP%C",	gencc,	fp2},
795 	{63,	26,	ALL,	"FRSQRTE%C",	gencc,	fp2},	/* optional */
796 	{63,	23,	FP4,	"FSEL%CC",	gencc,	fp4},	/* optional */
797 	{63,	22,	ALL,	"FSQRT%C",	gencc,	fp2},	/* optional */
798 	{59,	22,	ALL,	"FSQRTS%C",	gencc,	fp2},	/* optional */
799 	{63,	20,	FP4,	"FSUB%C",	gencc,	fp3},
800 	{59,	20,	FP4,	"FSUBS%C",	gencc,	fp3},
801 
802 	{31,	982,	ALL,	"ICBI",		dcb,	0},	/* optional */
803 	{19,	150,	ALL,	"ISYNC",	gen,	0},
804 
805 	{34,	0,	0,	"MOVBZ",	load,	ldop},
806 	{35,	0,	0,	"MOVBZU",	load,	ldop},
807 	{31,	119,	ALL,	"MOVBZU",	ldx,	0},
808 	{31,	87,	ALL,	"MOVBZ",	ldx,	0},
809 	{50,	0,	0,	"FMOVD",	fload,	fldop},
810 	{51,	0,	0,	"FMOVDU",	fload,	fldop},
811 	{31,	631,	ALL,	"FMOVDU",	fldx,	0},
812 	{31,	599,	ALL,	"FMOVD",	fldx,	0},
813 	{48,	0,	0,	"FMOVS",	load,	fldop},
814 	{49,	0,	0,	"FMOVSU",	load,	fldop},
815 	{31,	567,	ALL,	"FMOVSU",	fldx,	0},
816 	{31,	535,	ALL,	"FMOVS",	fldx,	0},
817 	{42,	0,	0,	"MOVH",		load,	ldop},
818 	{43,	0,	0,	"MOVHU",	load,	ldop},
819 	{31,	375,	ALL,	"MOVHU",	ldx,	0},
820 	{31,	343,	ALL,	"MOVH",		ldx,	0},
821 	{31,	790,	ALL,	"MOVHBR",	ldx,	0},
822 	{40,	0,	0,	"MOVHZ",	load,	ldop},
823 	{41,	0,	0,	"MOVHZU",	load,	ldop},
824 	{31,	311,	ALL,	"MOVHZU",	ldx,	0},
825 	{31,	279,	ALL,	"MOVHZ",	ldx,	0},
826 	{46,	0,	0,	"MOVMW",	load,	ldop},
827 	{31,	597,	ALL,	"LSW",		gen,	"(R%a),$%n,R%d"},
828 	{31,	533,	ALL,	"LSW",		ldx,	0},
829 	{31,	20,	ALL,	"LWAR",		ldx,	0},
830 	{31,	84,	ALL,	"LWARD",	ldx,	0},	/* 64 */
831 
832 	{58,	0,	ALL,	"MOVD",		load,	ldop},	/* 64 */
833 	{58,	1,	ALL,	"MOVDU",	load,	ldop},	/* 64 */
834 	{31,	53,	ALL,	"MOVDU",	ldx,	0},	/* 64 */
835 	{31,	21,	ALL,	"MOVD",		ldx,	0},	/* 64 */
836 
837 	{31,	534,	ALL,	"MOVWBR",	ldx,	0},
838 
839 	{58,	2,	ALL,	"MOVW",		load,	ldop},	/* 64 (lwa) */
840 	{31,	373,	ALL,	"MOVWU",	ldx,	0},	/* 64 */
841 	{31,	341,	ALL,	"MOVW",		ldx,	0},	/* 64 */
842 
843 	{32,	0,	0,	"MOVW%Z",	load,	ldop},
844 	{33,	0,	0,	"MOVW%ZU",	load,	ldop},
845 	{31,	55,	ALL,	"MOVW%ZU",	ldx,	0},
846 	{31,	23,	ALL,	"MOVW%Z",	ldx,	0},
847 
848 	{19,	0,	ALL,	"MOVFL",	gen,	"%S,%D"},
849 	{63,	64,	ALL,	"MOVCRFS",	gen,	"%S,%D"},
850 	{31,	512,	ALL,	"MOVW",		gen,	"XER,%D"},
851 	{31,	19,	ALL,	"MOVW",		gen,	"CR,R%d"},
852 
853 	{63,	583,	ALL,	"MOVW%C",	gen,	"FPSCR, F%d"},	/* mffs */
854 	{31,	83,	ALL,	"MOVW",		gen,	"MSR,R%d"},
855 	{31,	339,	ALL,	"MOVW",		gen,	"%P,R%d"},
856 	{31,	595,	ALL,	"MOVW",		gen,	"SEG(%a),R%d"},
857 	{31,	659,	ALL,	"MOVW",		gen,	"SEG(R%b),R%d"},
858 	{31,	323,	ALL,	"MOVW",		gen,	"DCR(%Q),R%d"},
859 	{31,	451,	ALL,	"MOVW",		gen,	"R%s,DCR(%Q)"},
860 	{31,	144,	ALL,	"MOVFL",	gen,	"R%s,%m,CR"},
861 	{63,	70,	ALL,	"MTFSB0%C",	gencc,	"%D"},
862 	{63,	38,	ALL,	"MTFSB1%C",	gencc,	"%D"},
863 	{63,	711,	ALL,	"MOVFL%C",	gencc,	"F%b,%M,FPSCR"},	/* mtfsf */
864 	{63,	134,	ALL,	"MOVFL%C",	gencc,	"%K,%D"},
865 	{31,	146,	ALL,	"MOVW",		gen,	"R%s,MSR"},
866 	{31,	178,	ALL,	"MOVD",		gen,	"R%s,MSR"},
867 	{31,	467,	ALL,	"MOVW",		gen,	"R%s,%P"},
868 	{31,	210,	ALL,	"MOVW",		gen,	"R%s,SEG(%a)"},
869 	{31,	242,	ALL,	"MOVW",		gen,	"R%s,SEG(R%b)"},
870 
871 	{31,	73,	ALL,	"MULHD%C",	gencc,	ir3},
872 	{31,	9,	ALL,	"MULHDU%C",	gencc,	ir3},
873 	{31,	233,	OEM,	"MULLD%V%C",	gencc,	ir3},
874 
875 	{31,	75,	ALL,	"MULHW%C",	gencc,	ir3},
876 	{31,	11,	ALL,	"MULHWU%C",	gencc,	ir3},
877 	{31,	235,	OEM,	"MULLW%V%C",	gencc,	ir3},
878 
879 	{7,	0,	0,	"MULLW",	qmuldiv,	"%i,R%a,R%d"},
880 
881 	{31,	476,	ALL,	"NAND%C",	gencc,	il3},
882 	{31,	104,	OEM,	"NEG%V%C",	neg,	ir2},
883 	{31,	124,	ALL,	"NOR%C",	gencc,	il3},
884 	{31,	444,	ALL,	"OR%C",		or,	il3},
885 	{31,	412,	ALL,	"ORN%C",	or,	il3},
886 	{24,	0,	0,	"OR",		and,	"%I,R%d,R%a"},
887 	{25,	0,	0,	"OR",		shifted, 0},
888 
889 	{19,	50,	ALL,	"RFI",		gen,	0},
890 	{19,	51,	ALL,	"RFCI",		gen,	0},
891 
892 	{30,	8,	RLDC,	"RLDCL%C",	gencc,	rldc},	/* 64 */
893 	{30,	9,	RLDC,	"RLDCR%C",	gencc,	rldc},	/* 64 */
894 	{30,	0,	RLDI,	"RLDCL%C",	gencc,	rldi},	/* 64 */
895 	{30,	1<<1, RLDI,	"RLDCR%C",	gencc,	rldi},	/* 64 */
896 	{30,	2<<1, RLDI,	"RLDC%C",	gencc,	rldi},	/* 64 */
897 	{30,	3<<1, RLDI,	"RLDMI%C",	gencc,	rldi},	/* 64 */
898 
899 	{20,	0,	0,	"RLWMI%C",	gencc,	rlimi},
900 	{21,	0,	0,	"RLWNM%C",	gencc,	rlimi},
901 	{23,	0,	0,	"RLWNM%C",	gencc,	rlim},
902 
903 	{17,	1,	ALL,	"SYSCALL",	gen,	0},
904 
905 	{31,	27,	ALL,	"SLD%C",	shift,	il3},	/* 64 */
906 	{31,	24,	ALL,	"SLW%C",	shift,	il3},
907 
908 	{31,	794,	ALL,	"SRAD%C",	shift,	il3},	/* 64 */
909 	{31,	(413<<1)|0,	ALL,	"SRAD%C",	shifti,	il3s},	/* 64 */
910 	{31,	(413<<1)|1,	ALL,	"SRAD%C",	shifti,	il3s},	/* 64 */
911 	{31,	792,	ALL,	"SRAW%C",	shift,	il3},
912 	{31,	824,	ALL,	"SRAW%C",	shifti,	il3s},
913 
914 	{31,	539,	ALL,	"SRD%C",	shift,	il3},	/* 64 */
915 	{31,	536,	ALL,	"SRW%C",	shift,	il3},
916 
917 	{38,	0,	0,	"MOVB",		store,	stop},
918 	{39,	0,	0,	"MOVBU",	store,	stop},
919 	{31,	247,	ALL,	"MOVBU",	stx,	0},
920 	{31,	215,	ALL,	"MOVB",		stx,	0},
921 	{54,	0,	0,	"FMOVD",	fstore,	fstop},
922 	{55,	0,	0,	"FMOVDU",	fstore,	fstop},
923 	{31,	759,	ALL,	"FMOVDU",	fstx,	0},
924 	{31,	727,	ALL,	"FMOVD",	fstx,	0},
925 	{52,	0,	0,	"FMOVS",	fstore,	fstop},
926 	{53,	0,	0,	"FMOVSU",	fstore,	fstop},
927 	{31,	695,	ALL,	"FMOVSU",	fstx,	0},
928 	{31,	663,	ALL,	"FMOVS",	fstx,	0},
929 	{44,	0,	0,	"MOVH",		store,	stop},
930 	{31,	918,	ALL,	"MOVHBR",	stx,	0},
931 	{45,	0,	0,	"MOVHU",	store,	stop},
932 	{31,	439,	ALL,	"MOVHU",	stx,	0},
933 	{31,	407,	ALL,	"MOVH",		stx,	0},
934 	{47,	0,	0,	"MOVMW",	store,	stop},
935 	{31,	725,	ALL,	"STSW",		gen,	"R%d,$%n,(R%a)"},
936 	{31,	661,	ALL,	"STSW",		stx,	0},
937 	{36,	0,	0,	"MOVW",		store,	stop},
938 	{31,	662,	ALL,	"MOVWBR",	stx,	0},
939 	{31,	150,	ALL,	"STWCCC",	stx,	0},
940 	{31,	214,	ALL,	"STDCCC",	stx,	0},	/* 64 */
941 	{37,	0,	0,	"MOVWU",	store,	stop},
942 	{31,	183,	ALL,	"MOVWU",	stx,	0},
943 	{31,	151,	ALL,	"MOVW",		stx,	0},
944 
945 	{62,	0,	0,	"MOVD%U",	store,	stop},	/* 64 */
946 	{31,	149,	ALL,	"MOVD",		stx,	0,},	/* 64 */
947 	{31,	181,	ALL,	"MOVDU",	stx,	0},	/* 64 */
948 
949 	{31,	498,	ALL,	"SLBIA",	gen,	0},	/* 64 */
950 	{31,	434,	ALL,	"SLBIE",	gen,	"R%b"},	/* 64 */
951 	{31,	466,	ALL,	"SLBIEX",	gen,	"R%b"},	/* 64 */
952 	{31,	915,	ALL,	"SLBMFEE",	gen,	"R%b,R%d"},	/* 64 */
953 	{31,	851,	ALL,	"SLBMFEV",	gen,	"R%b,R%d"},	/* 64 */
954 	{31,	402,	ALL,	"SLBMTE",	gen,	"R%s,R%b"},	/* 64 */
955 
956 	{31,	40,	OEM,	"SUB%V%C",	sub,	ir3},
957 	{31,	8,	OEM,	"SUBC%V%C",	sub,	ir3},
958 	{31,	136,	OEM,	"SUBE%V%C",	sub,	ir3},
959 	{8,	0,	0,	"SUBC",		gen,	"R%a,%i,R%d"},
960 	{31,	232,	OEM,	"SUBME%V%C",	sub,	ir2},
961 	{31,	200,	OEM,	"SUBZE%V%C",	sub,	ir2},
962 
963 	{31,	598,	ALL,	"SYNC",		gen,	0},	/* TO DO: there's a parameter buried in there */
964 	{2,	0,	0,	"TD",		gen,	"%d,R%a,%i"},	/* 64 */
965 	{31,	370,	ALL,	"TLBIA",	gen,	0},	/* optional */
966 	{31,	306,	ALL,	"TLBIE",	gen,	"R%b"},	/* optional */
967 	{31,	274,	ALL,	"TLBIEL",	gen,	"R%b"},	/* optional */
968 	{31,	1010,	ALL,	"TLBLI",	gen,	"R%b"},	/* optional */
969 	{31,	978,	ALL,	"TLBLD",	gen,	"R%b"},	/* optional */
970 	{31,	566,	ALL,	"TLBSYNC",	gen,	0},	/* optional */
971 	{31,	68,	ALL,	"TD",		gen,	"%d,R%a,R%b"},	/* 64 */
972 	{31,	4,	ALL,	"TW",		gen,	"%d,R%a,R%b"},
973 	{3,	0,	0,	"TW",		gen,	"%d,R%a,%i"},
974 
975 	{31,	316,	ALL,	"XOR",		and,	il3},
976 	{26,	0,	0,	"XOR",		and,	il2u},
977 	{27,	0,	0,	"XOR",		shifted, 0},
978 
979 	{0},
980 };
981 
982 typedef struct Spr Spr;
983 struct Spr {
984 	int	n;
985 	char	*name;
986 };
987 
988 static	Spr	sprname[] = {
989 	{0, "MQ"},
990 	{1, "XER"},
991 	{268, "TBL"},
992 	{269, "TBU"},
993 	{8, "LR"},
994 	{9, "CTR"},
995 	{528, "IBAT0U"},
996 	{529, "IBAT0L"},
997 	{530, "IBAT1U"},
998 	{531, "IBAT1L"},
999 	{532, "IBAT2U"},
1000 	{533, "IBAT2L"},
1001 	{534, "IBAT3U"},
1002 	{535, "IBAT3L"},
1003 	{536, "DBAT0U"},
1004 	{537, "DBAT0L"},
1005 	{538, "DBAT1U"},
1006 	{539, "DBAT1L"},
1007 	{540, "DBAT2U"},
1008 	{541, "DBAT2L"},
1009 	{542, "DBAT3U"},
1010 	{543, "DBAT3L"},
1011 	{25, "SDR1"},
1012 	{19, "DAR"},
1013 	{272, "SPRG0"},
1014 	{273, "SPRG1"},
1015 	{274, "SPRG2"},
1016 	{275, "SPRG3"},
1017 	{18, "DSISR"},
1018 	{26, "SRR0"},
1019 	{27, "SRR1"},
1020 	{284, "TBLW"},
1021 	{285, "TBUW"},
1022 	{22, "DEC"},
1023 	{282, "EAR"},
1024 	{1008, "HID0"},
1025 	{1009, "HID1"},
1026 	{976, "DMISS"},
1027 	{977, "DCMP"},
1028 	{978, "HASH1"},
1029 	{979, "HASH2"},
1030 	{980, "IMISS"},
1031 	{981, "ICMP"},
1032 	{982, "RPA"},
1033 	{1010, "IABR"},
1034 	{1013, "DABR"},
1035 	{0,0},
1036 };
1037 
1038 static int
1039 shmask(uvlong *m)
1040 {
1041 	int i;
1042 
1043 	for(i=0; i<63; i++)
1044 		if(*m & ((uvlong)1<<i))
1045 			break;
1046 	if(i > 63)
1047 		return 0;
1048 	if(*m & ~((uvlong)1<<i)){	/* more than one bit: do multiples of bytes */
1049 		i = (i/8)*8;
1050 		if(i == 0)
1051 			return 0;
1052 	}
1053 	*m >>= i;
1054 	return i;
1055 }
1056 
1057 static void
1058 format(char *mnemonic, Instr *i, char *f)
1059 {
1060 	int n, s;
1061 	ulong mask;
1062 	uvlong vmask;
1063 
1064 	if (mnemonic)
1065 		format(0, i, mnemonic);
1066 	if (f == 0)
1067 		return;
1068 	if (mnemonic)
1069 		bprint(i, "\t");
1070 	for ( ; *f; f++) {
1071 		if (*f != '%') {
1072 			bprint(i, "%c", *f);
1073 			continue;
1074 		}
1075 		switch (*++f) {
1076 
1077 		case 'a':
1078 			bprint(i, "%d", i->ra);
1079 			break;
1080 
1081 		case 'b':
1082 			bprint(i, "%d", i->rb);
1083 			break;
1084 
1085 		case 'c':
1086 			bprint(i, "%d", i->frc);
1087 			break;
1088 
1089 		case 'd':
1090 		case 's':
1091 			bprint(i, "%d", i->rd);
1092 			break;
1093 
1094 		case 'C':
1095 			if(i->rc)
1096 				bprint(i, "CC");
1097 			break;
1098 
1099 		case 'D':
1100 			if(i->rd & 3)
1101 				bprint(i, "CR(INVAL:%d)", i->rd);
1102 			else if(i->op == 63)
1103 				bprint(i, "FPSCR(%d)", i->crfd);
1104 			else
1105 				bprint(i, "CR(%d)", i->crfd);
1106 			break;
1107 
1108 		case 'e':
1109 			bprint(i, "%d", i->xsh);
1110 			break;
1111 
1112 		case 'E':
1113 			switch(IBF(i->w0,27,30)){	/* low bit is top bit of shift in rldiX cases */
1114 			case 8:	i->mb = i->xmbe; i->me = 63; break;	/* rldcl */
1115 			case 9:	i->mb = 0; i->me = i->xmbe; break;	/* rldcr */
1116 			case 4: case 5:
1117 					i->mb = i->xmbe; i->me = 63-i->xsh; break;	/* rldic */
1118 			case 0: case 1:
1119 					i->mb = i->xmbe; i->me = 63; break;	/* rldicl */
1120 			case 2: case 3:
1121 					i->mb = 0; i->me = i->xmbe; break;	/* rldicr */
1122 			case 6: case 7:
1123 					i->mb = i->xmbe; i->me = 63-i->xsh; break;	/* rldimi */
1124 			}
1125 			vmask = (~(uvlong)0>>i->mb) & (~(uvlong)0<<(63-i->me));
1126 			s = shmask(&vmask);
1127 			if(s)
1128 				bprint(i, "(%llux<<%d)", vmask, s);
1129 			else
1130 				bprint(i, "%llux", vmask);
1131 			break;
1132 
1133 		case 'i':
1134 			bprint(i, "$%d", i->simm);
1135 			break;
1136 
1137 		case 'I':
1138 			bprint(i, "$%ux", i->uimm);
1139 			break;
1140 
1141 		case 'j':
1142 			if(i->aa)
1143 				pglobal(i, i->li, 1, "(SB)");
1144 			else
1145 				pglobal(i, i->addr+i->li, 1, "");
1146 			break;
1147 
1148 		case 'J':
1149 			if(i->aa)
1150 				pglobal(i, i->bd, 1, "(SB)");
1151 			else
1152 				pglobal(i, i->addr+i->bd, 1, "");
1153 			break;
1154 
1155 		case 'k':
1156 			bprint(i, "%d", i->sh);
1157 			break;
1158 
1159 		case 'K':
1160 			bprint(i, "$%x", i->imm);
1161 			break;
1162 
1163 		case 'L':
1164 			if(i->lk)
1165 				bprint(i, "L");
1166 			break;
1167 
1168 		case 'l':
1169 			if(i->simm < 0)
1170 				bprint(i, "-%x(R%d)", -i->simm, i->ra);
1171 			else
1172 				bprint(i, "%x(R%d)", i->simm, i->ra);
1173 			break;
1174 
1175 		case 'm':
1176 			bprint(i, "%ux", i->crm);
1177 			break;
1178 
1179 		case 'M':
1180 			bprint(i, "%ux", i->fm);
1181 			break;
1182 
1183 		case 'n':
1184 			bprint(i, "%d", i->nb==0? 32: i->nb);	/* eg, pg 10-103 */
1185 			break;
1186 
1187 		case 'P':
1188 			n = ((i->spr&0x1f)<<5)|((i->spr>>5)&0x1f);
1189 			for(s=0; sprname[s].name; s++)
1190 				if(sprname[s].n == n)
1191 					break;
1192 			if(sprname[s].name) {
1193 				if(s < 10)
1194 					bprint(i, sprname[s].name);
1195 				else
1196 					bprint(i, "SPR(%s)", sprname[s].name);
1197 			} else
1198 				bprint(i, "SPR(%d)", n);
1199 			break;
1200 
1201 		case 'Q':
1202 			n = ((i->spr&0x1f)<<5)|((i->spr>>5)&0x1f);
1203 			bprint(i, "%d", n);
1204 			break;
1205 
1206 		case 'S':
1207 			if(i->ra & 3)
1208 				bprint(i, "CR(INVAL:%d)", i->ra);
1209 			else if(i->op == 63)
1210 				bprint(i, "FPSCR(%d)", i->crfs);
1211 			else
1212 				bprint(i, "CR(%d)", i->crfs);
1213 			break;
1214 
1215 		case 'U':
1216 			if(i->rc)
1217 				bprint(i, "U");
1218 			break;
1219 
1220 		case 'V':
1221 			if(i->oe)
1222 				bprint(i, "V");
1223 			break;
1224 
1225 		case 'w':
1226 			bprint(i, "[%lux]", i->w0);
1227 			break;
1228 
1229 		case 'W':
1230 			if(i->m64)
1231 				bprint(i, "W");
1232 			break;
1233 
1234 		case 'Z':
1235 			if(i->m64)
1236 				bprint(i, "Z");
1237 			break;
1238 
1239 		case 'z':
1240 			if(i->mb <= i->me)
1241 				mask = ((ulong)~0L>>i->mb) & (~0L<<(31-i->me));
1242 			else
1243 				mask = ~(((ulong)~0L>>(i->me+1)) & (~0L<<(31-(i->mb-1))));
1244 			bprint(i, "%lux", mask);
1245 			break;
1246 
1247 		case '\0':
1248 			bprint(i, "%%");
1249 			return;
1250 
1251 		default:
1252 			bprint(i, "%%%c", *f);
1253 			break;
1254 		}
1255 	}
1256 }
1257 
1258 static int
1259 printins(Map *map, uvlong pc, char *buf, int n)
1260 {
1261 	Instr i;
1262 	Opcode *o;
1263 
1264 	mymap = map;
1265 	memset(&i, 0, sizeof(i));
1266 	i.curr = buf;
1267 	i.end = buf+n-1;
1268 	if(mkinstr(pc, &i) < 0)
1269 		return -1;
1270 	for(o = opcodes; o->mnemonic != 0; o++)
1271 		if(i.op == o->op && (i.xo & o->xomask) == o->xo) {
1272 			if (o->f)
1273 				(*o->f)(o, &i);
1274 			else
1275 				format(o->mnemonic, &i, o->ken);
1276 			return i.size*4;
1277 		}
1278 	bprint(&i, "unknown %lux", i.w0);
1279 	return i.size*4;
1280 }
1281 
1282 static int
1283 powerinst(Map *map, uvlong pc, char modifier, char *buf, int n)
1284 {
1285 	USED(modifier);
1286 	return printins(map, pc, buf, n);
1287 }
1288 
1289 static int
1290 powerdas(Map *map, uvlong pc, char *buf, int n)
1291 {
1292 	Instr instr;
1293 
1294 	mymap = map;
1295 	memset(&instr, 0, sizeof(instr));
1296 	instr.curr = buf;
1297 	instr.end = buf+n-1;
1298 	if (mkinstr(pc, &instr) < 0)
1299 		return -1;
1300 	if (instr.end-instr.curr > 8)
1301 		instr.curr = _hexify(instr.curr, instr.w0, 7);
1302 	if (instr.end-instr.curr > 9 && instr.size == 2) {
1303 		*instr.curr++ = ' ';
1304 		instr.curr = _hexify(instr.curr, instr.w1, 7);
1305 	}
1306 	*instr.curr = 0;
1307 	return instr.size*4;
1308 }
1309 
1310 static int
1311 powerinstlen(Map *map, uvlong pc)
1312 {
1313 	Instr i;
1314 
1315 	mymap = map;
1316 	if (mkinstr(pc, &i) < 0)
1317 		return -1;
1318 	return i.size*4;
1319 }
1320 
1321 static int
1322 powerfoll(Map *map, uvlong pc, Rgetter rget, uvlong *foll)
1323 {
1324 	char *reg;
1325 	Instr i;
1326 
1327 	mymap = map;
1328 	if (mkinstr(pc, &i) < 0)
1329 		return -1;
1330 	foll[0] = pc+4;
1331 	foll[1] = pc+4;
1332 	switch(i.op) {
1333 	default:
1334 		return 1;
1335 
1336 	case 18:	/* branch */
1337 		foll[0] = i.li;
1338 		if(!i.aa)
1339 			foll[0] += pc;
1340 		break;
1341 
1342 	case 16:	/* conditional branch */
1343 		foll[0] = i.bd;
1344 		if(!i.aa)
1345 			foll[0] += pc;
1346 		break;
1347 
1348 	case 19:	/* conditional branch to register */
1349 		if(i.xo == 528)
1350 			reg = "CTR";
1351 		else if(i.xo == 16)
1352 			reg = "LR";
1353 		else
1354 			return 1;	/* not a branch */
1355 		foll[0] = (*rget)(map, reg);
1356 		break;
1357 	}
1358 	if(i.lk)
1359 		return 2;
1360 	return 1;
1361 }
1362