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