7 * PowerPC-specific debugger interface,
8 * including 64-bit modes
9 * forsyth@terzarima.net
12 static char *powerexcep(Map*, Rgetter);
13 static int powerfoll(Map*, uvlong, Rgetter, uvlong*);
14 static int powerinst(Map*, uvlong, char, char*, int);
15 static int powerinstlen(Map*, uvlong);
16 static int powerdas(Map*, uvlong, char*, int);
23 {0x02, 0x8f, 0xff, 0xff}, /* break point */ /* BUG */
24 4, /* break point size */
26 beswab, /* short to local byte order */
27 beswal, /* long to local byte order */
28 beswav, /* vlong to local byte order */
29 risctrace, /* print C traceback */
30 riscframe, /* frame finder */
31 powerexcep, /* print exception */
32 0, /* breakpoint fixup */
33 beieeesftos, /* single precision float printer */
34 beieeedftos, /* double precisioin float printer */
35 powerfoll, /* following addresses */
36 powerinst, /* print instruction */
37 powerdas, /* dissembler */
38 powerinstlen, /* instruction size */
41 static char *excname[] =
51 "floating-point unavailable",
53 "i/o controller interface error",
57 "floating point assist",
62 "instruction address breakpoint"
70 /* the following are made up on a program exception */
71 "floating point exception", /* FPEXC */
72 "illegal instruction",
73 "privileged instruction",
79 powerexcep(Map *map, Rgetter rget)
84 c = (*rget)(map, "CAUSE") >> 8;
85 if(c < nelem(excname))
87 sprint(buf, "unknown trap #%lx", c);
92 * disassemble PowerPC opcodes
95 #define REGSP 1 /* should come from q.out.h, but there's a clash */
98 static char FRAMENAME[] = ".frame";
103 * ibm conventions for these: bit 0 is top bit
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 */
117 short d; /* bits 16-31 */
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 */
141 uchar rs; /* bits 6-10 */
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) */
152 uvlong addr; /* pc of instruction */
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 */
161 #define IBF(v,a,b) (((ulong)(v)>>(32-(b)-1)) & ~(~0L<<(((b)-(a)+1))))
162 #define IB(v,b) IBF((v),(b),(b))
164 #pragma varargck argpos bprint 2
167 bprint(Instr *i, char *fmt, ...)
172 i->curr = vseprint(i->curr, i->end, fmt, arg);
177 decode(uvlong pc, Instr *i)
181 if (get4(mymap, pc, &w) < 0) {
182 werrstr("can't read instruction: %r");
185 i->m64 = asstype == APOWER64;
187 i->crba = IBF(w, 11, 15);
188 i->crbb = IBF(w, 16, 20);
189 i->bd = IBF(w, 16, 29)<<2;
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;
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);
215 i->ra = IBF(w, 11, 15);
216 i->rb = IBF(w, 16, 20);
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 */
232 else if(i->op == 25 || i->op == 27 || i->op == 29)
233 i->imm64 = (uvlong)(i->uimm<<16);
242 mkinstr(uvlong pc, Instr *i)
246 if(decode(pc, i) < 0)
249 * combine ADDIS/ORI (CAU/ORIL) into MOVW
250 * also ORIS/ORIL for unsigned in 64-bit mode
252 if ((i->op == 15 || i->op == 25) && i->ra==0) {
253 if(decode(pc+4, &x) < 0)
255 if (x.op == 24 && x.rs == x.ra && x.ra == i->rd) {
256 i->imm64 |= (x.imm64 & 0xFFFF);
258 i->imm64 &= 0xFFFFFFFFUL;
274 if (!findsym(i->addr, CTEXT, &s) || !findlocal(&s, FRAMENAME, &s))
276 offset = s.value - i->imm64;
278 if(getauto(&s, offset, CAUTO, &s)) {
279 bprint(i, "%s+%lld(SP)", s.name, s.value);
283 if (getauto(&s, -offset-4, CPARAM, &s)) {
284 bprint(i, "%s+%ld(FP)", s.name, -offset);
292 pglobal(Instr *i, uvlong off, int anyoff, char *reg)
297 if(findsym(off, CANY, &s) &&
298 off-s.value < 4096 &&
299 (s.class == CDATA || s.class == CTEXT)) {
300 if(off==s.value && s.name[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);
308 bprint(i, "%s", s.name);
310 bprint(i, "+%llux", off-s.value);
316 bprint(i, "%llux%s", off, reg);
323 if (i->ra == REGSP && plocal(i) >= 0)
325 if (i->ra == REGSB && mach->sb && pglobal(i, mach->sb+i->imm64, 0, "(SB)"))
328 bprint(i, "-%x(R%d)", -i->simm, i->ra);
330 bprint(i, "%llux(R%d)", i->imm64, i->ra);
333 static char *tcrbits[] = {"LT", "GT", "EQ", "VS"};
334 static char *fcrbits[] = {"GE", "LE", "NE", "VC"};
336 typedef struct Opcode Opcode;
343 void (*f)(Opcode *, Instr *);
348 static void format(char *, Instr *, char *);
351 branch(Opcode *o, Instr *i)
356 bo = i->bo & ~1; /* ignore prediction bit */
357 if(bo==4 || bo==12 || bo==20) { /* simple forms */
360 sprint(buf, "B%s%%L", bo==12? tcrbits[bi]: fcrbits[bi]);
364 bprint(i, "CR(%d),", i->bi/4);
366 format("BR%L\t", i, nil);
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)");
374 format(o->mnemonic, i, o->ken);
378 addi(Opcode *o, Instr *i)
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$");
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);
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);
394 format(o->mnemonic, i, o->ken);
398 addis(Opcode *o, Instr *i)
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$");
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);
412 bprint(i, ",R%d", i->rd);
414 format(o->mnemonic, i, nil);
415 bprint(i, "\t$%ld,R%d", v, i->ra);
417 bprint(i, ",R%d", i->rd);
422 andi(Opcode *o, Instr *i)
425 format(o->mnemonic, i, "%I,R%d");
427 format(o->mnemonic, i, o->ken);
431 gencc(Opcode *o, Instr *i)
433 format(o->mnemonic, i, o->ken);
437 gen(Opcode *o, Instr *i)
439 format(o->mnemonic, i, o->ken);
441 bprint(i, " [illegal Rc]");
445 ldx(Opcode *o, Instr *i)
448 format(o->mnemonic, i, "(R%b),R%d");
450 format(o->mnemonic, i, "(R%b+R%a),R%d");
452 bprint(i, " [illegal Rc]");
456 stx(Opcode *o, Instr *i)
459 format(o->mnemonic, i, "R%d,(R%b)");
461 format(o->mnemonic, i, "R%d,(R%b+R%a)");
462 if(i->rc && i->xo != 150)
463 bprint(i, " [illegal Rc]");
467 fldx(Opcode *o, Instr *i)
470 format(o->mnemonic, i, "(R%b),F%d");
472 format(o->mnemonic, i, "(R%b+R%a),F%d");
474 bprint(i, " [illegal Rc]");
478 fstx(Opcode *o, Instr *i)
481 format(o->mnemonic, i, "F%d,(R%b)");
483 format(o->mnemonic, i, "F%d,(R%b+R%a)");
485 bprint(i, " [illegal Rc]");
489 dcb(Opcode *o, Instr *i)
492 format(o->mnemonic, i, "(R%b)");
494 format(o->mnemonic, i, "(R%b+R%a)");
496 bprint(i, " [illegal Rd]");
498 bprint(i, " [illegal Rc]");
502 lw(Opcode *o, Instr *i, char r)
504 format(o->mnemonic, i, nil);
507 bprint(i, ",%c%d", r, i->rd);
511 load(Opcode *o, Instr *i)
517 fload(Opcode *o, Instr *i)
523 sw(Opcode *o, Instr *i, char r)
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);
538 if (i->rs == REGSB && mach->sb) {
539 format(o->mnemonic, i, nil);
540 bprint(i, "\t%c%d,", r, i->rd);
545 format(o->mnemonic, i, "F%d,%l");
547 format(o->mnemonic, i, o->ken);
551 store(Opcode *o, Instr *i)
557 fstore(Opcode *o, Instr *i)
563 shifti(Opcode *o, Instr *i)
566 format(o->mnemonic, i, "$%k,R%a");
568 format(o->mnemonic, i, o->ken);
572 shift(Opcode *o, Instr *i)
575 format(o->mnemonic, i, "R%b,R%a");
577 format(o->mnemonic, i, o->ken);
581 add(Opcode *o, Instr *i)
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");
588 format(o->mnemonic, i, o->ken);
592 sub(Opcode *o, Instr *i)
594 format(o->mnemonic, i, nil);
597 bprint(i, "\tR%d,R%d", i->ra, i->rb); /* subtract Ra from Rb */
599 bprint(i, ",R%d", i->rd);
601 bprint(i, "\tR%d,$%d,R%d", i->ra, i->simm, i->rd);
605 qdiv(Opcode *o, Instr *i)
607 format(o->mnemonic, i, nil);
609 bprint(i, "\tR%d,R%d", i->rb, i->ra);
611 bprint(i, "\t$%d,R%d", i->simm, i->ra);
613 bprint(i, ",R%d", i->rd);
617 and(Opcode *o, Instr *i)
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");
626 format(o->mnemonic, i, o->ken);
630 format(o->mnemonic, i, "%I,R%a");
632 format(o->mnemonic, i, o->ken);
637 or(Opcode *o, Instr *i)
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");
652 shifted(Opcode *o, Instr *i)
654 format(o->mnemonic, i, nil);
655 bprint(i, "\t$%lux,", (ulong)i->uimm<<16);
657 bprint(i, "R%d", i->ra);
659 bprint(i, "R%d,R%d", i->rs, i->ra);
663 neg(Opcode *o, Instr *i)
666 format(o->mnemonic, i, "R%d");
668 format(o->mnemonic, i, o->ken);
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%d,R%a";
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";
695 #define OEM IBF(~0,22,30)
696 #define FP4 IBF(~0,26,30)
702 10-26: crfD = rD>>2; rD&3 mbz
703 also, L bit (bit 10) mbz or selects 64-bit operands
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},
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},
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)"},
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"},
732 {31, 58, ALL, "CNTLZD%C", gencc, ir2}, /* 64 */
733 {31, 26, ALL, "CNTLZ%W%C", gencc, ir2},
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},
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},
753 {31, 489, OEM, "DIVD%V%C", qdiv, ir3}, /* 64 */
754 {31, 457, OEM, "DIVDU%V%C", qdiv, ir3}, /* 64 */
755 {31, 491, OEM, "DIVW%V%C", qdiv, ir3},
756 {31, 459, OEM, "DIVWU%V%C", qdiv, ir3},
758 {31, 310, ALL, "ECIWX", ldx, 0},
759 {31, 438, ALL, "ECOWX", stx, 0},
760 {31, 854, ALL, "EIEIO", gen, 0},
762 {31, 284, ALL, "EQV%C", gencc, il3},
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 */
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},
802 {31, 982, ALL, "ICBI", dcb, 0}, /* optional */
803 {19, 150, ALL, "ISYNC", gen, 0},
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 */
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 */
837 {31, 534, ALL, "MOVWBR", ldx, 0},
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 */
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},
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"},
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, 259, ALL, "MOVW", gen, "DCR(R%a),R%d"},
861 {31, 387, ALL, "MOVW", gen, "R%s,DCR(R%a)"},
862 {31, 144, ALL, "MOVFL", gen, "R%s,%m,CR"},
863 {63, 70, ALL, "MTFSB0%C", gencc, "%D"},
864 {63, 38, ALL, "MTFSB1%C", gencc, "%D"},
865 {63, 711, ALL, "MOVFL%C", gencc, "F%b,%M,FPSCR"}, /* mtfsf */
866 {63, 134, ALL, "MOVFL%C", gencc, "%K,%D"},
867 {31, 146, ALL, "MOVW", gen, "R%s,MSR"},
868 {31, 178, ALL, "MOVD", gen, "R%s,MSR"},
869 {31, 467, ALL, "MOVW", gen, "R%s,%P"},
870 {31, 210, ALL, "MOVW", gen, "R%s,SEG(%a)"},
871 {31, 242, ALL, "MOVW", gen, "R%s,SEG(R%b)"},
873 {31, 73, ALL, "MULHD%C", gencc, ir3},
874 {31, 9, ALL, "MULHDU%C", gencc, ir3},
875 {31, 233, OEM, "MULLD%V%C", gencc, ir3},
877 {31, 75, ALL, "MULHW%C", gencc, ir3},
878 {31, 11, ALL, "MULHWU%C", gencc, ir3},
879 {31, 235, OEM, "MULLW%V%C", gencc, ir3},
881 {7, 0, 0, "MULLW", qdiv, "%i,R%a,R%d"},
883 {31, 476, ALL, "NAND%C", gencc, il3},
884 {31, 104, OEM, "NEG%V%C", neg, ir2},
885 {31, 124, ALL, "NOR%C", gencc, il3},
886 {31, 444, ALL, "OR%C", or, il3},
887 {31, 412, ALL, "ORN%C", or, il3},
888 {24, 0, 0, "OR", and, "%I,R%d,R%a"},
889 {25, 0, 0, "OR", shifted, 0},
891 {19, 50, ALL, "RFI", gen, 0},
892 {19, 51, ALL, "RFCI", gen, 0},
894 {30, 8, RLDC, "RLDCL%C", gencc, rldc}, /* 64 */
895 {30, 9, RLDC, "RLDCR%C", gencc, rldc}, /* 64 */
896 {30, 0, RLDI, "RLDCL%C", gencc, rldi}, /* 64 */
897 {30, 1<<1, RLDI, "RLDCR%C", gencc, rldi}, /* 64 */
898 {30, 2<<1, RLDI, "RLDC%C", gencc, rldi}, /* 64 */
899 {30, 3<<1, RLDI, "RLDMI%C", gencc, rldi}, /* 64 */
901 {20, 0, 0, "RLWMI%C", gencc, rlimi},
902 {21, 0, 0, "RLWNM%C", gencc, rlimi},
903 {23, 0, 0, "RLWNM%C", gencc, rlim},
905 {17, 1, ALL, "SYSCALL", gen, 0},
907 {31, 27, ALL, "SLD%C", shift, il3}, /* 64 */
908 {31, 24, ALL, "SLW%C", shift, il3},
910 {31, 794, ALL, "SRAD%C", shift, il3}, /* 64 */
911 {31, (413<<1)|0, ALL, "SRAD%C", shifti, il3s}, /* 64 */
912 {31, (413<<1)|1, ALL, "SRAD%C", shifti, il3s}, /* 64 */
913 {31, 792, ALL, "SRAW%C", shift, il3},
914 {31, 824, ALL, "SRAW%C", shifti, il3s},
916 {31, 539, ALL, "SRD%C", shift, il3}, /* 64 */
917 {31, 536, ALL, "SRW%C", shift, il3},
919 {38, 0, 0, "MOVB", store, stop},
920 {39, 0, 0, "MOVBU", store, stop},
921 {31, 247, ALL, "MOVBU", stx, 0},
922 {31, 215, ALL, "MOVB", stx, 0},
923 {54, 0, 0, "FMOVD", fstore, fstop},
924 {55, 0, 0, "FMOVDU", fstore, fstop},
925 {31, 759, ALL, "FMOVDU", fstx, 0},
926 {31, 727, ALL, "FMOVD", fstx, 0},
927 {52, 0, 0, "FMOVS", fstore, fstop},
928 {53, 0, 0, "FMOVSU", fstore, fstop},
929 {31, 695, ALL, "FMOVSU", fstx, 0},
930 {31, 663, ALL, "FMOVS", fstx, 0},
931 {44, 0, 0, "MOVH", store, stop},
932 {31, 918, ALL, "MOVHBR", stx, 0},
933 {45, 0, 0, "MOVHU", store, stop},
934 {31, 439, ALL, "MOVHU", stx, 0},
935 {31, 407, ALL, "MOVH", stx, 0},
936 {47, 0, 0, "MOVMW", store, stop},
937 {31, 725, ALL, "STSW", gen, "R%d,$%n,(R%a)"},
938 {31, 661, ALL, "STSW", stx, 0},
939 {36, 0, 0, "MOVW", store, stop},
940 {31, 662, ALL, "MOVWBR", stx, 0},
941 {31, 150, ALL, "STWCCC", stx, 0},
942 {31, 214, ALL, "STDCCC", stx, 0}, /* 64 */
943 {37, 0, 0, "MOVWU", store, stop},
944 {31, 183, ALL, "MOVWU", stx, 0},
945 {31, 151, ALL, "MOVW", stx, 0},
947 {62, 0, 0, "MOVD%U", store, stop}, /* 64 */
948 {31, 149, ALL, "MOVD", stx, 0,}, /* 64 */
949 {31, 181, ALL, "MOVDU", stx, 0}, /* 64 */
951 {31, 498, ALL, "SLBIA", gen, 0}, /* 64 */
952 {31, 434, ALL, "SLBIE", gen, "R%b"}, /* 64 */
953 {31, 466, ALL, "SLBIEX", gen, "R%b"}, /* 64 */
954 {31, 915, ALL, "SLBMFEE", gen, "R%b,R%d"}, /* 64 */
955 {31, 851, ALL, "SLBMFEV", gen, "R%b,R%d"}, /* 64 */
956 {31, 402, ALL, "SLBMTE", gen, "R%s,R%b"}, /* 64 */
958 {31, 40, OEM, "SUB%V%C", sub, ir3},
959 {31, 8, OEM, "SUBC%V%C", sub, ir3},
960 {31, 136, OEM, "SUBE%V%C", sub, ir3},
961 {8, 0, 0, "SUBC", gen, "R%a,%i,R%d"},
962 {31, 232, OEM, "SUBME%V%C", sub, ir2},
963 {31, 200, OEM, "SUBZE%V%C", sub, ir2},
965 {31, 598, ALL, "SYNC", gen, 0}, /* TO DO: there's a parameter buried in there */
966 {2, 0, 0, "TD", gen, "%d,R%a,%i"}, /* 64 */
967 {31, 370, ALL, "TLBIA", gen, 0}, /* optional */
968 {31, 306, ALL, "TLBIE", gen, "R%b"}, /* optional */
969 {31, 274, ALL, "TLBIEL", gen, "R%b"}, /* optional */
970 {31, 1010, ALL, "TLBLI", gen, "R%b"}, /* optional */
971 {31, 978, ALL, "TLBLD", gen, "R%b"}, /* optional */
972 {31, 566, ALL, "TLBSYNC", gen, 0}, /* optional */
973 {31, 68, ALL, "TD", gen, "%d,R%a,R%b"}, /* 64 */
974 {31, 4, ALL, "TW", gen, "%d,R%a,R%b"},
975 {3, 0, 0, "TW", gen, "%d,R%a,%i"},
977 {31, 316, ALL, "XOR", and, il3},
978 {26, 0, 0, "XOR", and, il2u},
979 {27, 0, 0, "XOR", shifted, 0},
984 typedef struct Spr Spr;
990 static Spr sprname[] = {
1046 if(*m & ((uvlong)1<<i))
1050 if(*m & ~((uvlong)1<<i)){ /* more than one bit: do multiples of bytes */
1060 format(char *mnemonic, Instr *i, char *f)
1067 format(0, i, mnemonic);
1074 bprint(i, "%c", *f);
1080 bprint(i, "%d", i->ra);
1084 bprint(i, "%d", i->rb);
1088 bprint(i, "%d", i->frc);
1093 bprint(i, "%d", i->rd);
1103 bprint(i, "CR(INVAL:%d)", i->rd);
1104 else if(i->op == 63)
1105 bprint(i, "FPSCR(%d)", i->crfd);
1107 bprint(i, "CR(%d)", i->crfd);
1111 bprint(i, "%d", i->xsh);
1115 switch(IBF(i->w0,27,30)){ /* low bit is top bit of shift in rldiX cases */
1116 case 8: i->mb = i->xmbe; i->me = 63; break; /* rldcl */
1117 case 9: i->mb = 0; i->me = i->xmbe; break; /* rldcr */
1119 i->mb = i->xmbe; i->me = 63-i->xsh; break; /* rldic */
1121 i->mb = i->xmbe; i->me = 63; break; /* rldicl */
1123 i->mb = 0; i->me = i->xmbe; break; /* rldicr */
1125 i->mb = i->xmbe; i->me = 63-i->xsh; break; /* rldimi */
1127 vmask = (~(uvlong)0>>i->mb) & (~(uvlong)0<<(63-i->me));
1130 bprint(i, "(%llux<<%d)", vmask, s);
1132 bprint(i, "%llux", vmask);
1136 bprint(i, "$%d", i->simm);
1140 bprint(i, "$%ux", i->uimm);
1145 pglobal(i, i->li, 1, "(SB)");
1147 pglobal(i, i->addr+i->li, 1, "");
1152 pglobal(i, i->bd, 1, "(SB)");
1154 pglobal(i, i->addr+i->bd, 1, "");
1158 bprint(i, "%d", i->sh);
1162 bprint(i, "$%x", i->imm);
1172 bprint(i, "-%x(R%d)", -i->simm, i->ra);
1174 bprint(i, "%x(R%d)", i->simm, i->ra);
1178 bprint(i, "%ux", i->crm);
1182 bprint(i, "%ux", i->fm);
1186 bprint(i, "%d", i->nb==0? 32: i->nb); /* eg, pg 10-103 */
1190 n = ((i->spr&0x1f)<<5)|((i->spr>>5)&0x1f);
1191 for(s=0; sprname[s].name; s++)
1192 if(sprname[s].n == n)
1194 if(sprname[s].name) {
1196 bprint(i, sprname[s].name);
1198 bprint(i, "SPR(%s)", sprname[s].name);
1200 bprint(i, "SPR(%d)", n);
1204 n = ((i->spr&0x1f)<<5)|((i->spr>>5)&0x1f);
1210 bprint(i, "CR(INVAL:%d)", i->ra);
1211 else if(i->op == 63)
1212 bprint(i, "FPSCR(%d)", i->crfs);
1214 bprint(i, "CR(%d)", i->crfs);
1228 bprint(i, "[%lux]", i->w0);
1243 mask = ((ulong)~0L>>i->mb) & (~0L<<(31-i->me));
1245 mask = ~(((ulong)~0L>>(i->me+1)) & (~0L<<(31-(i->mb-1))));
1246 bprint(i, "%lux", mask);
1254 bprint(i, "%%%c", *f);
1261 printins(Map *map, uvlong pc, char *buf, int n)
1267 memset(&i, 0, sizeof(i));
1270 if(mkinstr(pc, &i) < 0)
1272 for(o = opcodes; o->mnemonic != 0; o++)
1273 if(i.op == o->op && (i.xo & o->xomask) == o->xo) {
1277 format(o->mnemonic, &i, o->ken);
1280 bprint(&i, "unknown %lux", i.w0);
1285 powerinst(Map *map, uvlong pc, char modifier, char *buf, int n)
1288 return printins(map, pc, buf, n);
1292 powerdas(Map *map, uvlong pc, char *buf, int n)
1297 memset(&instr, 0, sizeof(instr));
1299 instr.end = buf+n-1;
1300 if (mkinstr(pc, &instr) < 0)
1302 if (instr.end-instr.curr > 8)
1303 instr.curr = _hexify(instr.curr, instr.w0, 7);
1304 if (instr.end-instr.curr > 9 && instr.size == 2) {
1305 *instr.curr++ = ' ';
1306 instr.curr = _hexify(instr.curr, instr.w1, 7);
1309 return instr.size*4;
1313 powerinstlen(Map *map, uvlong pc)
1318 if (mkinstr(pc, &i) < 0)
1324 powerfoll(Map *map, uvlong pc, Rgetter rget, uvlong *foll)
1330 if (mkinstr(pc, &i) < 0)
1338 case 18: /* branch */
1344 case 16: /* conditional branch */
1350 case 19: /* conditional branch to register */
1356 return 1; /* not a branch */
1357 foll[0] = (*rget)(map, reg);