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