xref: /inferno-os/libinterp/das-power.c (revision d2caef7bfa67181341fe2f1cbf68884ae6e45639)
1 #include <lib9.h>
2 
3 /*
4  * disassemble PowerPC opcodes in Plan9 format
5  * Copyright © 1997 C H Forsyth (forsyth@terzarima.net)
6  */
7 
8 /*
9  * ibm conventions for these: bit 0 is top bit
10  *	from table 10-1
11  */
12 typedef struct {
13 	uchar	aa;		/* bit 30 */
14 	uchar	crba;		/* bits 11-15 */
15 	uchar	crbb;		/* bits 16-20 */
16 	long	bd;		/* bits 16-29 */
17 	uchar	crfd;		/* bits 6-8 */
18 	uchar	crfs;		/* bits 11-13 */
19 	uchar	bi;		/* bits 11-15 */
20 	uchar	bo;		/* bits 6-10 */
21 	uchar	crbd;		/* bits 6-10 */
22 	union {
23 		short	d;	/* bits 16-31 */
24 		short	simm;
25 		ushort	uimm;
26 	};
27 	uchar	fm;		/* bits 7-14 */
28 	uchar	fra;		/* bits 11-15 */
29 	uchar	frb;		/* bits 16-20 */
30 	uchar	frc;		/* bits 21-25 */
31 	uchar	frs;		/* bits 6-10 */
32 	uchar	frd;		/* bits 6-10 */
33 	uchar	crm;		/* bits 12-19 */
34 	long	li;		/* bits 6-29 || b'00' */
35 	uchar	lk;		/* bit 31 */
36 	uchar	mb;		/* bits 21-25 */
37 	uchar	me;		/* bits 26-30 */
38 	uchar	nb;		/* bits 16-20 */
39 	uchar	op;		/* bits 0-5 */
40 	uchar	oe;		/* bit 21 */
41 	uchar	ra;		/* bits 11-15 */
42 	uchar	rb;		/* bits 16-20 */
43 	uchar	rc;		/* bit 31 */
44 	union {
45 		uchar	rs;	/* bits 6-10 */
46 		uchar	rd;
47 	};
48 	uchar	sh;		/* bits 16-20 */
49 	ushort	spr;		/* bits 11-20 */
50 	uchar	to;		/* bits 6-10 */
51 	uchar	imm;		/* bits 16-19 */
52 	ushort	xo;		/* bits 21-30, 22-30, 26-30, or 30 (beware) */
53 	long	immediate;
54 	long w0;
55 	long w1;
56 	ulong	addr;		/* pc of instruction */
57 	short	target;
58 	char	*curr;		/* current fill level in output buffer */
59 	char	*end;		/* end of buffer */
60 	int 	size;		/* number of longs in instr */
61 	char	*err;		/* errmsg */
62 } Instr;
63 
64 #define	IBF(v,a,b) (((ulong)(v)>>(32-(b)-1)) & ~(~0L<<(((b)-(a)+1))))
65 #define	IB(v,b) IBF((v),(b),(b))
66 
67 static void
bprint(Instr * i,char * fmt,...)68 bprint(Instr *i, char *fmt, ...)
69 {
70 	va_list arg;
71 
72 	va_start(arg, fmt);
73 	i->curr = vseprint(i->curr, i->end, fmt, arg);
74 	va_end(arg);
75 }
76 
77 static int
decode(ulong * pc,Instr * i)78 decode(ulong *pc, Instr *i)
79 {
80 	ulong w;
81 
82 	w = *pc;
83 	i->aa = IB(w, 30);
84 	i->crba = IBF(w, 11, 15);
85 	i->crbb = IBF(w, 16, 20);
86 	i->bd = IBF(w, 16, 29)<<2;
87 	if(i->bd & 0x8000)
88 		i->bd |= ~0L<<16;
89 	i->crfd = IBF(w, 6, 8);
90 	i->crfs = IBF(w, 11, 13);
91 	i->bi = IBF(w, 11, 15);
92 	i->bo = IBF(w, 6, 10);
93 	i->crbd = IBF(w, 6, 10);
94 	i->uimm = IBF(w, 16, 31);	/* also d, simm */
95 	i->fm = IBF(w, 7, 14);
96 	i->fra = IBF(w, 11, 15);
97 	i->frb = IBF(w, 16, 20);
98 	i->frc = IBF(w, 21, 25);
99 	i->frs = IBF(w, 6, 10);
100 	i->frd = IBF(w, 6, 10);
101 	i->crm = IBF(w, 12, 19);
102 	i->li = IBF(w, 6, 29)<<2;
103 	if(IB(w, 6))
104 		i->li |= ~0<<25;
105 	i->lk = IB(w, 31);
106 	i->mb = IBF(w, 21, 25);
107 	i->me = IBF(w, 26, 30);
108 	i->nb = IBF(w, 16, 20);
109 	i->op = IBF(w, 0, 5);
110 	i->oe = IB(w, 21);
111 	i->ra = IBF(w, 11, 15);
112 	i->rb = IBF(w, 16, 20);
113 	i->rc = IB(w, 31);
114 	i->rs = IBF(w, 6, 10);	/* also rd */
115 	i->sh = IBF(w, 16, 20);
116 	i->spr = IBF(w, 11, 20);
117 	i->to = IBF(w, 6, 10);
118 	i->imm = IBF(w, 16, 19);
119 	i->xo = IBF(w, 21, 30);		/* bits 21-30, 22-30, 26-30, or 30 (beware) */
120 	i->immediate = i->simm;
121 	if(i->op == 15)
122 		i->immediate <<= 16;
123 	i->w0 = w;
124 	i->target = -1;
125 	i->addr = (ulong)pc;
126 	i->size = 1;
127 	return 1;
128 }
129 
130 static int
mkinstr(ulong * pc,Instr * i)131 mkinstr(ulong *pc, Instr *i)
132 {
133 	Instr x;
134 
135 	if(decode(pc, i) < 0)
136 		return -1;
137 	/*
138 	 * combine ADDIS/ORI (CAU/ORIL) into MOVW
139 	 */
140 	if (i->op == 15 && i->ra==0) {
141 		if(decode(pc+1, &x) < 0)
142 			return -1;
143 		if (x.op == 24 && x.rs == x.ra && x.ra == i->rd) {
144 			i->immediate |= (x.immediate & 0xFFFF);
145 			i->w1 = x.w0;
146 			i->target = x.rd;
147 			i->size++;
148 			return 1;
149 		}
150 	}
151 	return 1;
152 }
153 
154 static void
pglobal(Instr * i,long off,char * reg)155 pglobal(Instr *i, long off, char *reg)
156 {
157 	bprint(i, "%lux%s", off, reg);
158 }
159 
160 static void
address(Instr * i)161 address(Instr *i)
162 {
163 	if(i->simm < 0)
164 		bprint(i, "-%lx(R%d)", -i->simm, i->ra);
165 	else
166 		bprint(i, "%lux(R%d)", i->immediate, i->ra);
167 }
168 
169 static	char	*tcrbits[] = {"LT", "GT", "EQ", "VS"};
170 static	char	*fcrbits[] = {"GE", "LE", "NE", "VC"};
171 
172 typedef struct Opcode Opcode;
173 
174 struct Opcode {
175 	uchar	op;
176 	ushort	xo;
177 	ushort	xomask;
178 	char	*mnemonic;
179 	void	(*f)(Opcode *, Instr *);
180 	char	*ken;
181 	int	flags;
182 };
183 
184 static void format(char *, Instr *, char *);
185 
186 static void
branch(Opcode * o,Instr * i)187 branch(Opcode *o, Instr *i)
188 {
189 	char buf[8];
190 	int bo, bi;
191 
192 	bo = i->bo & ~1;	/* ignore prediction bit */
193 	if(bo==4 || bo==12 || bo==20) {	/* simple forms */
194 		if(bo != 20) {
195 			bi = i->bi&3;
196 			sprint(buf, "B%s%%L", bo==12? tcrbits[bi]: fcrbits[bi]);
197 			format(buf, i, 0);
198 			bprint(i, "\t");
199 			if(i->bi > 4)
200 				bprint(i, "CR(%d),", i->bi/4);
201 		} else
202 			format("BR%L\t", i, 0);
203 		if(i->op == 16)
204 			format(0, i, "%J");
205 		else if(i->op == 19 && i->xo == 528)
206 			format(0, i, "(CTR)");
207 		else if(i->op == 19 && i->xo == 16)
208 			format(0, i, "(LR)");
209 	} else
210 		format(o->mnemonic, i, o->ken);
211 }
212 
213 static void
addi(Opcode * o,Instr * i)214 addi(Opcode *o, Instr *i)
215 {
216 	if (i->op==14 && i->ra == 0)
217 		format("MOVW", i, "%i,R%d");
218 	else if(i->op==14 && i->simm < 0) {
219 		bprint(i, "SUB\t$%d,R%d", -i->simm, i->ra);
220 		if(i->rd != i->ra)
221 			bprint(i, ",R%d", i->rd);
222 	} else if(i->ra == i->rd) {
223 		format(o->mnemonic, i, "%i");
224 		bprint(i, ",R%d", i->rd);
225 	} else
226 		format(o->mnemonic, i, o->ken);
227 }
228 
229 static void
addis(Opcode * o,Instr * i)230 addis(Opcode *o, Instr *i)
231 {
232 	long v;
233 
234 	v = i->immediate;
235 	if (i->op==15 && i->ra == 0)
236 		bprint(i, "MOVW\t$%lux,R%d", v, i->rd);
237 	else if(i->op==15 && v < 0) {
238 		bprint(i, "SUB\t$%d,R%d", -v, i->ra);
239 		if(i->rd != i->ra)
240 			bprint(i, ",R%d", i->rd);
241 	} else {
242 		format(o->mnemonic, i, 0);
243 		bprint(i, "\t$%ld,R%d", v, i->ra);
244 		if(i->rd != i->ra)
245 			bprint(i, ",R%d", i->rd);
246 	}
247 }
248 
249 static void
andi(Opcode * o,Instr * i)250 andi(Opcode *o, Instr *i)
251 {
252 	if (i->ra == i->rs)
253 		format(o->mnemonic, i, "%I,R%d");
254 	else
255 		format(o->mnemonic, i, o->ken);
256 }
257 
258 static void
gencc(Opcode * o,Instr * i)259 gencc(Opcode *o, Instr *i)
260 {
261 	format(o->mnemonic, i, o->ken);
262 }
263 
264 static void
gen(Opcode * o,Instr * i)265 gen(Opcode *o, Instr *i)
266 {
267 	format(o->mnemonic, i, o->ken);
268 	if (i->rc)
269 		bprint(i, " [illegal Rc]");
270 }
271 
272 static void
ldx(Opcode * o,Instr * i)273 ldx(Opcode *o, Instr *i)
274 {
275 	if(i->ra == 0)
276 		format(o->mnemonic, i, "(R%b),R%d");
277 	else
278 		format(o->mnemonic, i, "(R%b+R%a),R%d");
279 	if(i->rc)
280 		bprint(i, " [illegal Rc]");
281 }
282 
283 static void
stx(Opcode * o,Instr * i)284 stx(Opcode *o, Instr *i)
285 {
286 	if(i->ra == 0)
287 		format(o->mnemonic, i, "R%d,(R%b)");
288 	else
289 		format(o->mnemonic, i, "R%d,(R%b+R%a)");
290 	if(i->rc && i->xo != 150)
291 		bprint(i, " [illegal Rc]");
292 }
293 
294 static void
fldx(Opcode * o,Instr * i)295 fldx(Opcode *o, Instr *i)
296 {
297 	if(i->ra == 0)
298 		format(o->mnemonic, i, "(R%b),F%d");
299 	else
300 		format(o->mnemonic, i, "(R%b+R%a),F%d");
301 	if(i->rc)
302 		bprint(i, " [illegal Rc]");
303 }
304 
305 static void
fstx(Opcode * o,Instr * i)306 fstx(Opcode *o, Instr *i)
307 {
308 	if(i->ra == 0)
309 		format(o->mnemonic, i, "F%d,(R%b)");
310 	else
311 		format(o->mnemonic, i, "F%d,(R%b+R%a)");
312 	if(i->rc)
313 		bprint(i, " [illegal Rc]");
314 }
315 
316 static void
dcb(Opcode * o,Instr * i)317 dcb(Opcode *o, Instr *i)
318 {
319 	if(i->ra == 0)
320 		format(o->mnemonic, i, "(R%b)");
321 	else
322 		format(o->mnemonic, i, "(R%b+R%a)");
323 	if(i->rd)
324 		bprint(i, " [illegal Rd]");
325 	if(i->rc)
326 		bprint(i, " [illegal Rc]");
327 }
328 
329 static void
lw(Opcode * o,Instr * i,char r)330 lw(Opcode *o, Instr *i, char r)
331 {
332 	bprint(i, "%s\t", o->mnemonic);
333 	address(i);
334 	bprint(i, ",%c%d", r, i->rd);
335 }
336 
337 static void
load(Opcode * o,Instr * i)338 load(Opcode *o, Instr *i)
339 {
340 	lw(o, i, 'R');
341 }
342 
343 static void
fload(Opcode * o,Instr * i)344 fload(Opcode *o, Instr *i)
345 {
346 	lw(o, i, 'F');
347 }
348 
349 static void
sw(Opcode * o,Instr * i,char r)350 sw(Opcode *o, Instr *i, char r)
351 {
352 	char *m;
353 
354 	m = o->mnemonic;
355 	if (r == 'F')
356 		format(m, i, "F%d,%l");
357 	else
358 		format(m, i, o->ken);
359 }
360 
361 static void
store(Opcode * o,Instr * i)362 store(Opcode *o, Instr *i)
363 {
364 	sw(o, i, 'R');
365 }
366 
367 static void
fstore(Opcode * o,Instr * i)368 fstore(Opcode *o, Instr *i)
369 {
370 	sw(o, i, 'F');
371 }
372 
373 static void
shifti(Opcode * o,Instr * i)374 shifti(Opcode *o, Instr *i)
375 {
376 	if (i->ra == i->rs)
377 		format(o->mnemonic, i, "$%k,R%a");
378 	else
379 		format(o->mnemonic, i, o->ken);
380 }
381 
382 static void
shift(Opcode * o,Instr * i)383 shift(Opcode *o, Instr *i)
384 {
385 	if (i->ra == i->rs)
386 		format(o->mnemonic, i, "R%b,R%a");
387 	else
388 		format(o->mnemonic, i, o->ken);
389 }
390 
391 static void
add(Opcode * o,Instr * i)392 add(Opcode *o, Instr *i)
393 {
394 	if (i->rd == i->ra)
395 		format(o->mnemonic, i, "R%b,R%d");
396 	else if (i->rd == i->rb)
397 		format(o->mnemonic, i, "R%a,R%d");
398 	else
399 		format(o->mnemonic, i, o->ken);
400 }
401 
402 static void
sub(Opcode * o,Instr * i)403 sub(Opcode *o, Instr *i)
404 {
405 	format(o->mnemonic, i, 0);
406 	bprint(i, "\t");
407 	if(i->op == 31) {
408 		bprint(i, "\tR%d,R%d", i->ra, i->rb);	/* subtract Ra from Rb */
409 		if(i->rd != i->rb)
410 			bprint(i, ",R%d", i->rd);
411 	} else
412 		bprint(i, "\tR%d,$%d,R%d", i->ra, i->simm, i->rd);
413 }
414 
415 static void
idiv(Opcode * o,Instr * i)416 idiv(Opcode *o, Instr *i)
417 {
418 	format(o->mnemonic, i, 0);
419 	if(i->op == 31)
420 		bprint(i, "\tR%d,R%d", i->rb, i->ra);
421 	else
422 		bprint(i, "\t$%d,R%d", i->simm, i->ra);
423 	if(i->ra != i->rd)
424 		bprint(i, ",R%d", i->rd);
425 }
426 
427 static void
and(Opcode * o,Instr * i)428 and(Opcode *o, Instr *i)
429 {
430 	if (i->op == 31) {
431 		/* Rb,Rs,Ra */
432 		if (i->ra == i->rs)
433 			format(o->mnemonic, i, "R%b,R%a");
434 		else if (i->ra == i->rb)
435 			format(o->mnemonic, i, "R%s,R%a");
436 		else
437 			format(o->mnemonic, i, o->ken);
438 	} else {
439 		/* imm,Rs,Ra */
440 		if (i->ra == i->rs)
441 			format(o->mnemonic, i, "%I,R%a");
442 		else
443 			format(o->mnemonic, i, o->ken);
444 	}
445 }
446 
447 static void
or(Opcode * o,Instr * i)448 or(Opcode *o, Instr *i)
449 {
450 	if (i->op == 31) {
451 		/* Rb,Rs,Ra */
452 		if (i->rs == 0 && i->ra == 0 && i->rb == 0)
453 			format("NOP", i, 0);
454 		else if (i->rs == i->rb)
455 			format("MOVW", i, "R%b,R%a");
456 		else
457 			and(o, i);
458 	} else
459 		and(o, i);
460 }
461 
462 static void
shifted(Opcode * o,Instr * i)463 shifted(Opcode *o, Instr *i)
464 {
465 	format(o->mnemonic, i, 0);
466 	bprint(i, "\t$%lux,", (ulong)i->uimm<<16);
467 	if (i->rs == i->ra)
468 		bprint(i, "R%d", i->ra);
469 	else
470 		bprint(i, "R%d,R%d", i->rs, i->ra);
471 }
472 
473 static void
neg(Opcode * o,Instr * i)474 neg(Opcode *o, Instr *i)
475 {
476 	if (i->rd == i->ra)
477 		format(o->mnemonic, i, "R%d");
478 	else
479 		format(o->mnemonic, i, o->ken);
480 }
481 
482 static	char	ir2[] = "R%a,R%d";		/* reverse of IBM order */
483 static	char	ir3[] = "R%b,R%a,R%d";
484 static	char	ir3r[] = "R%a,R%b,R%d";
485 static	char	il3[] = "R%b,R%s,R%a";
486 static	char	il2u[] = "%I,R%s,R%a";
487 static	char	il3s[] = "$%k,R%s,R%a";
488 static	char	il2[] = "R%s,R%a";
489 static	char	icmp3[] = "R%a,R%b,%D";
490 static	char	cr3op[] = "%b,%a,%d";
491 static	char	ir2i[] = "%i,R%a,R%d";
492 static	char	fp2[] = "F%b,F%d";
493 static	char	fp3[] = "F%b,F%a,F%d";
494 static	char	fp3c[] = "F%c,F%a,F%d";
495 static	char	fp4[] = "F%a,F%c,F%b,F%d";
496 static	char	fpcmp[] = "F%a,F%b,%D";
497 static	char	ldop[] = "%l,R%d";
498 static	char	stop[] = "R%d,%l";
499 static	char	fldop[] = "%l,F%d";
500 static	char	fstop[] = "F%d,%l";
501 static	char	rlim[] = "R%b,R%s,$%z,R%a";
502 static	char	rlimi[] = "$%k,R%s,$%z,R%a";
503 
504 #define	OEM	IBF(~0,22,30)
505 #define	FP4	IBF(~0,26,30)
506 #define	ALL	(~0)
507 /*
508 notes:
509 	10-26: crfD = rD>>2; rD&3 mbz
510 		also, L bit (bit 10) mbz or selects 64-bit operands
511 */
512 
513 static Opcode opcodes[] = {
514 	{31,	266,	OEM,	"ADD%V%C",	add,	ir3},
515 	{31,	 10,	OEM,	"ADDC%V%C",	add,	ir3},
516 	{31,	138,	OEM,	"ADDE%V%C",	add,	ir3},
517 	{14,	0,	0,	"ADD",		addi,	ir2i},
518 	{12,	0,	0,	"ADDC",		addi,	ir2i},
519 	{13,	0,	0,	"ADDCCC",	addi,	ir2i},
520 	{15,	0,	0,	"ADD",		addis,	0},
521 	{31,	234,	OEM,	"ADDME%V%C",	gencc,	ir2},
522 	{31,	202,	OEM,	"ADDZE%V%C",	gencc,	ir2},
523 
524 	{31,	28,	ALL,	"AND%C",	and,	il3},
525 	{31,	60,	ALL,	"ANDN%C",	and,	il3},
526 	{28,	0,	0,	"ANDCC",		andi,	il2u},
527 	{29,	0,	0,	"ANDCC",		shifted, 0},
528 
529 	{18,	0,	0,	"B%L",		gencc,	"%j"},
530 	{16,	0,	0,	"BC%L",		branch,	"%d,%a,%J"},
531 	{19,	528,	ALL,	"BC%L",		branch,	"%d,%a,(CTR)"},
532 	{19,	16,	ALL,	"BC%L",		branch,	"%d,%a,(LR)"},
533 
534 	{31,	0,	ALL,	"CMP",		0,	icmp3},
535 	{11,	0,	0,	"CMP",		0,	"R%a,%i,%D"},
536 	{31,	32,	ALL,	"CMPU",		0,	icmp3},
537 	{10,	0,	0,	"CMPU",		0,	"R%a,%I,%D"},
538 
539 	{31,	26,	ALL,	"CNTLZ%C",	gencc,	ir2},
540 
541 	{19,	257,	ALL,	"CRAND",	gen,	cr3op},
542 	{19,	129,	ALL,	"CRANDN",	gen,	cr3op},
543 	{19,	289,	ALL,	"CREQV",	gen,	cr3op},
544 	{19,	225,	ALL,	"CRNAND",	gen,	cr3op},
545 	{19,	33,	ALL,	"CRNOR",	gen,	cr3op},
546 	{19,	449,	ALL,	"CROR",		gen,	cr3op},
547 	{19,	417,	ALL,	"CRORN",	gen,	cr3op},
548 	{19,	193,	ALL,	"CRXOR",	gen,	cr3op},
549 
550 	{31,	86,	ALL,	"DCBF",		dcb,	0},
551 	{31,	470,	ALL,	"DCBI",		dcb,	0},
552 	{31,	54,	ALL,	"DCBST",	dcb,	0},
553 	{31,	278,	ALL,	"DCBT",		dcb,	0},
554 	{31,	246,	ALL,	"DCBTST",	dcb,	0},
555 	{31,	1014,	ALL,	"DCBZ",		dcb,	0},
556 
557 	{31,	491,	OEM,	"DIVW%V%C",	idiv,	ir3},
558 	{31,	459,	OEM,	"DIVWU%V%C",	idiv,	ir3},
559 
560 	{31,	310,	ALL,	"ECIWX",	ldx,	0},
561 	{31,	438,	ALL,	"ECOWX",	stx,	0},
562 	{31,	854,	ALL,	"EIEIO",	gen,	0},
563 
564 	{31,	284,	ALL,	"EQV%C",	gencc,	il3},
565 
566 	{31,	954,	ALL,	"EXTSB%C",	gencc,	il2},
567 	{31,	922,	ALL,	"EXTSH%C",	gencc,	il2},
568 
569 	{63,	264,	ALL,	"FABS%C",	gencc,	fp2},
570 	{63,	21,	ALL,	"FADD%C",	gencc,	fp3},
571 	{59,	21,	ALL,	"FADDS%C",	gencc,	fp3},
572 	{63,	32,	ALL,	"FCMPO",	gen,	fpcmp},
573 	{63,	0,	ALL,	"FCMPU",	gen,	fpcmp},
574 	{63,	14,	ALL,	"FCTIW%C",	gencc,	fp2},
575 	{63,	15,	ALL,	"FCTIWZ%C",	gencc,	fp2},
576 	{63,	18,	ALL,	"FDIV%C",	gencc,	fp3},
577 	{59,	18,	ALL,	"FDIVS%C",	gencc,	fp3},
578 	{63,	29,	FP4,	"FMADD%C",	gencc,	fp4},
579 	{59,	29,	FP4,	"FMADDS%C",	gencc,	fp4},
580 	{63,	72,	ALL,	"FMOVD%C",	gencc,	fp2},
581 	{63,	28,	FP4,	"FMSUB%C",	gencc,	fp4},
582 	{59,	28,	FP4,	"FMSUBS%C",	gencc,	fp4},
583 	{63,	25,	FP4,	"FMUL%C",	gencc,	fp3c},
584 	{59,	25,	FP4,	"FMULS%C",	gencc,	fp3c},
585 	{63,	136,	ALL,	"FNABS%C",	gencc,	fp2},
586 	{63,	40,	ALL,	"FNEG%C",	gencc,	fp2},
587 	{63,	31,	FP4,	"FNMADD%C",	gencc,	fp4},
588 	{59,	31,	FP4,	"FNMADDS%C",	gencc,	fp4},
589 	{63,	30,	FP4,	"FNMSUB%C",	gencc,	fp4},
590 	{59,	30,	FP4,	"FNMSUBS%C",	gencc,	fp4},
591 	{63,	12,	ALL,	"FRSP%C",	gencc,	fp2},
592 	{63,	20,	FP4,	"FSUB%C",	gencc,	fp3},
593 	{59,	20,	FP4,	"FSUBS%C",	gencc,	fp3},
594 
595 	{31,	982,	ALL,	"ICBI",		dcb,	0},
596 	{19,	150,	ALL,	"ISYNC",	gen,	0},
597 
598 	{34,	0,	0,	"MOVBZ",	load,	ldop},
599 	{35,	0,	0,	"MOVBZU",	load,	ldop},
600 	{31,	119,	ALL,	"MOVBZU",	ldx,	0},
601 	{31,	87,	ALL,	"MOVBZ",	ldx,	0},
602 	{50,	0,	0,	"FMOVD",	fload,	fldop},
603 	{51,	0,	0,	"FMOVDU",	fload,	fldop},
604 	{31,	631,	ALL,	"FMOVDU",	fldx,	0},
605 	{31,	599,	ALL,	"FMOVD",	fldx,	0},
606 	{48,	0,	0,	"FMOVS",	load,	fldop},
607 	{49,	0,	0,	"FMOVSU",	load,	fldop},
608 	{31,	567,	ALL,	"FMOVSU",	fldx,	0},
609 	{31,	535,	ALL,	"FMOVS",	fldx,	0},
610 	{42,	0,	0,	"MOVH",		load,	ldop},
611 	{43,	0,	0,	"MOVHU",	load,	ldop},
612 	{31,	375,	ALL,	"MOVHU",	ldx,	0},
613 	{31,	343,	ALL,	"MOVH",		ldx,	0},
614 	{31,	790,	ALL,	"MOVHBR",	ldx,	0},
615 	{40,	0,	0,	"MOVHZ",	load,	ldop},
616 	{41,	0,	0,	"MOVHZU",	load,	ldop},
617 	{31,	311,	ALL,	"MOVHZU",	ldx,	0},
618 	{31,	279,	ALL,	"MOVHZ",	ldx,	0},
619 	{46,	0,	0,	"MOVMW",		load,	ldop},
620 	{31,	597,	ALL,	"LSW",		gen,	"(R%a),$%n,R%d"},
621 	{31,	533,	ALL,	"LSW",		ldx,	0},
622 	{31,	20,	ALL,	"LWAR",		ldx,	0},
623 	{31,	534,	ALL,	"MOVWBR",		ldx,	0},
624 	{32,	0,	0,	"MOVW",		load,	ldop},
625 	{33,	0,	0,	"MOVWU",	load,	ldop},
626 	{31,	55,	ALL,	"MOVWU",	ldx,	0},
627 	{31,	23,	ALL,	"MOVW",		ldx,	0},
628 
629 	{19,	0,	ALL,	"MOVFL",	gen,	"%S,%D"},
630 	{63,	64,	ALL,	"MOVCRFS",	gen,	"%S,%D"},
631 	{31,	512,	ALL,	"MOVW",	gen,	"XER,%D"},
632 	{31,	19,	ALL,	"MOVW",	gen,	"CR,R%d"},
633 
634 	{63,	583,	ALL,	"MOVW%C",	gen,	"FPSCR, F%d"},	/* mffs */
635 	{31,	83,	ALL,	"MOVW",		gen,	"MSR,R%d"},
636 	{31,	339,	ALL,	"MOVW",		gen,	"%P,R%d"},
637 	{31,	595,	ALL,	"MOVW",		gen,	"SEG(%a),R%d"},
638 	{31,	659,	ALL,	"MOVW",		gen,	"SEG(R%b),R%d"},
639 	{31,	144,	ALL,	"MOVFL",	gen,	"R%s,%m,CR"},
640 	{63,	70,	ALL,	"MTFSB0%C",	gencc,	"%D"},
641 	{63,	38,	ALL,	"MTFSB1%C",	gencc,	"%D"},
642 	{63,	711,	ALL,	"MOVFL%C",	gencc,	"F%b,%M,FPSCR"},	/* mtfsf */
643 	{63,	134,	ALL,	"MOVFL%C",	gencc,	"%K,%D"},
644 	{31,	146,	ALL,	"MOVW",		gen,	"R%s,MSR"},
645 	{31,	467,	ALL,	"MOVW",		gen,	"R%s,%P"},
646 	{31,	210,	ALL,	"MOVW",		gen,	"R%s,SEG(%a)"},
647 	{31,	242,	ALL,	"MOVW",		gen,	"R%s,SEG(R%b)"},
648 
649 	{31,	235,	OEM,	"MULLW%V%C",	gencc,	ir3},
650 	{7,	0,	0,	"MULLW",	idiv,	"%i,R%a,R%d"},
651 
652 	{31,	476,	ALL,	"NAND%C",	gencc,	il3},
653 	{31,	104,	OEM,	"NEG%V%C",	neg,	ir2},
654 	{31,	124,	ALL,	"NOR%C",	gencc,	il3},
655 	{31,	444,	ALL,	"OR%C",	or,	il3},
656 	{31,	412,	ALL,	"ORN%C",	or,	il3},
657 	{24,	0,	0,	"OR",		and,	"%I,R%d,R%a"},
658 	{25,	0,	0,	"OR",		shifted, 0},
659 
660 	{19,	50,	ALL,	"RFI",		gen,	0},
661 
662 	{20,	0,	0,	"RLWMI%C",	gencc,	rlimi},
663 	{21,	0,	0,	"RLWNM%C",	gencc,	rlimi},
664 	{23,	0,	0,	"RLWNM%C",	gencc,	rlim},
665 
666 	{17,	1,	ALL,	"SYSCALL",	gen,	0},
667 
668 	{31,	24,	ALL,	"SLW%C",	shift,	il3},
669 
670 	{31,	792,	ALL,	"SRAW%C",	shift,	il3},
671 	{31,	824,	ALL,	"SRAW%C",	shifti,	il3s},
672 
673 	{31,	536,	ALL,	"SRW%C",	shift,	il3},
674 
675 	{38,	0,	0,	"MOVB",		store,	stop},
676 	{39,	0,	0,	"MOVBU",	store,	stop},
677 	{31,	247,	ALL,	"MOVBU",	stx,	0},
678 	{31,	215,	ALL,	"MOVB",		stx,	0},
679 	{54,	0,	0,	"FMOVD",	fstore,	fstop},
680 	{55,	0,	0,	"FMOVDU",	fstore,	fstop},
681 	{31,	759,	ALL,	"FMOVDU",	fstx,	0},
682 	{31,	727,	ALL,	"FMOVD",	fstx,	0},
683 	{52,	0,	0,	"FMOVS",	fstore,	fstop},
684 	{53,	0,	0,	"FMOVSU",	fstore,	fstop},
685 	{31,	695,	ALL,	"FMOVSU",	fstx,	0},
686 	{31,	663,	ALL,	"FMOVS",	fstx,	0},
687 	{44,	0,	0,	"MOVH",		store,	stop},
688 	{31,	918,	ALL,	"MOVHBR",	stx,	0},
689 	{45,	0,	0,	"MOVHU",	store,	stop},
690 	{31,	439,	ALL,	"MOVHU",	stx,	0},
691 	{31,	407,	ALL,	"MOVH",		stx,	0},
692 	{47,	0,	0,	"MOVMW",		store,	stop},
693 	{31,	725,	ALL,	"STSW",		gen,	"R%d,$%n,(R%a)"},
694 	{31,	661,	ALL,	"STSW",		stx,	0},
695 	{36,	0,	0,	"MOVW",		store,	stop},
696 	{31,	662,	ALL,	"MOVWBR",	stx,	0},
697 	{31,	150,	ALL,	"STWCCC",		stx,	0},
698 	{37,	0,	0,	"MOVWU",	store,	stop},
699 	{31,	183,	ALL,	"MOVWU",	stx,	0},
700 	{31,	151,	ALL,	"MOVW",		stx,	0},
701 
702 	{31,	40,	OEM,	"SUB%V%C",	sub,	ir3},
703 	{31,	8,	OEM,	"SUBC%V%C",	sub,	ir3},
704 	{31,	136,	OEM,	"SUBE%V%C",	sub,	ir3},
705 	{8,	0,	0,	"SUBC",		gen,	"R%a,%i,R%d"},
706 	{31,	232,	OEM,	"SUBME%V%C",	sub,	ir2},
707 	{31,	200,	OEM,	"SUBZE%V%C",	sub,	ir2},
708 
709 	{31,	598,	ALL,	"SYNC",		gen,	0},
710 	{31,	306,	ALL,	"TLBIE",	gen,	"R%b"},
711 	{31,	1010,	ALL,	"TLBLI",	gen,	"R%b"},
712 	{31,	978,	ALL,	"TLBLD",	gen,	"R%b"},
713 	{31,	4,	ALL,	"TW",		gen,	"%d,R%a,R%b"},
714 	{3,	0,	0,	"TW",		gen,	"%d,R%a,%i"},
715 
716 	{31,	316,	ALL,	"XOR",		and,	il3},
717 	{26,	0,	0,	"XOR",		and,	il2u},
718 	{27,	0,	0,	"XOR",		shifted, 0},
719 
720 	{0},
721 };
722 
723 typedef struct Spr Spr;
724 struct Spr {
725 	int	n;
726 	char	*name;
727 };
728 
729 static	Spr	sprname[] = {
730 	{0, "MQ"},
731 	{1, "XER"},
732 	{268, "TBL"},
733 	{269, "TBU"},
734 	{8, "LR"},
735 	{9, "CTR"},
736 	{528, "IBAT0U"},
737 	{529, "IBAT0L"},
738 	{530, "IBAT1U"},
739 	{531, "IBAT1L"},
740 	{532, "IBAT2U"},
741 	{533, "IBAT2L"},
742 	{534, "IBAT3U"},
743 	{535, "IBAT3L"},
744 	{536, "DBAT0U"},
745 	{537, "DBAT0L"},
746 	{538, "DBAT1U"},
747 	{539, "DBAT1L"},
748 	{540, "DBAT2U"},
749 	{541, "DBAT2L"},
750 	{542, "DBAT3U"},
751 	{543, "DBAT3L"},
752 	{25, "SDR1"},
753 	{19, "DAR"},
754 	{272, "SPRG0"},
755 	{273, "SPRG1"},
756 	{274, "SPRG2"},
757 	{275, "SPRG3"},
758 	{18, "DSISR"},
759 	{26, "SRR0"},
760 	{27, "SRR1"},
761 	{284, "TBLW"},
762 	{285, "TBUW"},
763 	{22, "DEC"},
764 	{282, "EAR"},
765 	{1008, "HID0"},
766 	{1009, "HID1"},
767 	{976, "DMISS"},
768 	{977, "DCMP"},
769 	{978, "HASH1"},
770 	{979, "HASH2"},
771 	{980, "IMISS"},
772 	{981, "ICMP"},
773 	{982, "RPA"},
774 	{1010, "IABR"},
775 	{0,0},
776 };
777 
778 static void
format(char * mnemonic,Instr * i,char * f)779 format(char *mnemonic, Instr *i, char *f)
780 {
781 	int n, s;
782 	ulong mask;
783 
784 	if (mnemonic)
785 		format(0, i, mnemonic);
786 	if (f == 0)
787 		return;
788 	if (mnemonic)
789 		bprint(i, "\t");
790 	for ( ; *f; f++) {
791 		if (*f != '%') {
792 			bprint(i, "%c", *f);
793 			continue;
794 		}
795 		switch (*++f) {
796 		case 'V':
797 			if(i->oe)
798 				bprint(i, "V");
799 			break;
800 
801 		case 'C':
802 			if(i->rc)
803 				bprint(i, "CC");
804 			break;
805 
806 		case 'a':
807 			bprint(i, "%d", i->ra);
808 			break;
809 
810 		case 'b':
811 			bprint(i, "%d", i->rb);
812 			break;
813 
814 		case 'c':
815 			bprint(i, "%d", i->frc);
816 			break;
817 
818 		case 'd':
819 		case 's':
820 			bprint(i, "%d", i->rd);
821 			break;
822 
823 		case 'S':
824 			if(i->ra & 3)
825 				bprint(i, "CR(INVAL:%d)", i->ra);
826 			else if(i->op == 63)
827 				bprint(i, "FPSCR(%d)", i->crfs);
828 			else
829 				bprint(i, "CR(%d)", i->crfs);
830 			break;
831 
832 		case 'D':
833 			if(i->rd & 3)
834 				bprint(i, "CR(INVAL:%d)", i->rd);
835 			else if(i->op == 63)
836 				bprint(i, "FPSCR(%d)", i->crfd);
837 			else
838 				bprint(i, "CR(%d)", i->crfd);
839 			break;
840 
841 		case 'l':
842 			if(i->simm < 0)
843 				bprint(i, "-%lx(R%d)", -i->simm, i->ra);
844 			else
845 				bprint(i, "%lx(R%d)", i->simm, i->ra);
846 			break;
847 
848 		case 'i':
849 			bprint(i, "$%ld", i->simm);
850 			break;
851 
852 		case 'I':
853 			bprint(i, "$%lx", i->uimm);
854 			break;
855 
856 		case 'w':
857 			bprint(i, "[%lux]", i->w0);
858 			break;
859 
860 		case 'P':
861 			n = ((i->spr&0x1f)<<5)|((i->spr>>5)&0x1f);
862 			for(s=0; sprname[s].name; s++)
863 				if(sprname[s].n == n)
864 					break;
865 			if(sprname[s].name) {
866 				if(n < 10)
867 					bprint(i, sprname[s].name);
868 				else
869 					bprint(i, "SPR(%s)", sprname[s].name);
870 			} else
871 				bprint(i, "SPR(%d)", n);
872 			break;
873 
874 		case 'n':
875 			bprint(i, "%d", i->nb==0? 32: i->nb);	/* eg, pg 10-103 */
876 			break;
877 
878 		case 'm':
879 			bprint(i, "%lx", i->crm);
880 			break;
881 
882 		case 'M':
883 			bprint(i, "%lx", i->fm);
884 			break;
885 
886 		case 'z':
887 			if(i->mb <= i->me)
888 				mask = ((ulong)~0L>>i->mb) & (~0L<<(31-i->me));
889 			else
890 				mask = ~(((ulong)~0L>>(i->me+1)) & (~0L<<(31-(i->mb-1))));
891 			bprint(i, "%lux", mask);
892 			break;
893 
894 		case 'k':
895 			bprint(i, "%d", i->sh);
896 			break;
897 
898 		case 'K':
899 			bprint(i, "$%x", i->imm);
900 			break;
901 
902 		case 'L':
903 			if(i->lk)
904 				bprint(i, "L");
905 			break;
906 
907 		case 'j':
908 			if(i->aa)
909 				pglobal(i, i->li, "(ABS)");
910 			else
911 				pglobal(i, i->addr+i->li, "(REL)");
912 			break;
913 
914 		case 'J':
915 			if(i->aa)
916 				pglobal(i, i->bd, "(ABS)");
917 			else
918 				pglobal(i, i->addr+i->bd, "(REL)");
919 			break;
920 
921 		case '\0':
922 			bprint(i, "%%");
923 			return;
924 
925 		default:
926 			bprint(i, "%%%c", *f);
927 			break;
928 		}
929 	}
930 }
931 
932 int
das(ulong * pc)933 das(ulong *pc)
934 {
935 	Instr i;
936 	Opcode *o;
937 	char buf[100];
938 	int r;
939 
940 	memset(&i, 0, sizeof(i));
941 	i.curr = buf;
942 	i.end = buf+sizeof(buf)-1;
943 	r = mkinstr(pc, &i);
944 	i.curr += sprint(i.curr, "	%.8lux %.8lux ", (ulong)pc, i.w0);
945 	if(r >= 0){
946 		if(i.size == 2)
947 			i.curr += sprint(i.curr, "%.8lux ", i.w1);
948 		for(o = opcodes; o->mnemonic != 0; o++)
949 			if(i.op == o->op && (i.xo & o->xomask) == o->xo) {
950 				if (o->f)
951 					(*o->f)(o, &i);
952 				else
953 					format(o->mnemonic, &i, o->ken);
954 				print("%s\n", buf);
955 				return i.size;
956 			}
957 	}
958 	strcpy(i.curr, "ILLEGAL");
959 	print("%s\n", buf);
960 	return i.size;
961 }
962