| /* |
| * PowerPC definition |
| * forsyth@plan9.cs.york.ac.uk |
| */ |
| #include <u.h> |
| #include <libc.h> |
| #include <bio.h> |
| #include "uregpower.h" |
| #include <mach.h> |
| |
| /* |
| * PowerPC-specific debugger interface |
| * forsyth@plan9.cs.york.ac.uk |
| */ |
| |
| static char *powerexcep(Map*, Regs*); |
| static int powerfoll(Map*, Regs*, u64int, u64int*); |
| static int powerdas(Map*, u64int, char, char*, int); |
| static int powerinstlen(Map*, u64int); |
| static int powerhexinst(Map*, u64int, char*, int); |
| |
| static char *excname[] = |
| { |
| "reserved 0", |
| "system reset", |
| "machine check", |
| "data access", |
| "instruction access", |
| "external interrupt", |
| "alignment", |
| "program exception", |
| "floating-point unavailable", |
| "decrementer", |
| "i/o controller interface error", |
| "reserved B", |
| "system call", |
| "trace trap", |
| "floating point assist", |
| "reserved", |
| "ITLB miss", |
| "DTLB load miss", |
| "DTLB store miss", |
| "instruction address breakpoint" |
| "SMI interrupt" |
| "reserved 15", |
| "reserved 16", |
| "reserved 17", |
| "reserved 18", |
| "reserved 19", |
| "reserved 1A", |
| /* the following are made up on a program exception */ |
| "floating point exception", /* FPEXC */ |
| "illegal instruction", |
| "privileged instruction", |
| "trap", |
| "illegal operation", |
| }; |
| |
| static char* |
| powerexcep(Map *map, Regs *regs) |
| { |
| u64int c; |
| static char buf[32]; |
| |
| if(rget(regs, "CAUSE", &c) < 0) |
| return "no cause register"; |
| c >>= 8; |
| if(c < nelem(excname)) |
| return excname[c]; |
| sprint(buf, "unknown trap #%lux", c); |
| return buf; |
| } |
| |
| /* |
| * disassemble PowerPC opcodes |
| */ |
| |
| #define REGSP 1 /* should come from q.out.h, but there's a clash */ |
| #define REGSB 2 |
| |
| /*static char FRAMENAME[] = ".frame"; */ |
| |
| static Map *mymap; |
| |
| /* |
| * ibm conventions for these: bit 0 is top bit |
| * from table 10-1 |
| */ |
| typedef struct { |
| uchar aa; /* bit 30 */ |
| uchar crba; /* bits 11-15 */ |
| uchar crbb; /* bits 16-20 */ |
| long bd; /* bits 16-29 */ |
| uchar crfd; /* bits 6-8 */ |
| uchar crfs; /* bits 11-13 */ |
| uchar bi; /* bits 11-15 */ |
| uchar bo; /* bits 6-10 */ |
| uchar crbd; /* bits 6-10 */ |
| /*union {*/ |
| short d; /* bits 16-31 */ |
| short simm; |
| ushort uimm; |
| /*};*/ |
| uchar fm; /* bits 7-14 */ |
| uchar fra; /* bits 11-15 */ |
| uchar frb; /* bits 16-20 */ |
| uchar frc; /* bits 21-25 */ |
| uchar frs; /* bits 6-10 */ |
| uchar frd; /* bits 6-10 */ |
| uchar crm; /* bits 12-19 */ |
| long li; /* bits 6-29 || b'00' */ |
| uchar lk; /* bit 31 */ |
| uchar mb; /* bits 21-25 */ |
| uchar me; /* bits 26-30 */ |
| uchar nb; /* bits 16-20 */ |
| uchar op; /* bits 0-5 */ |
| uchar oe; /* bit 21 */ |
| uchar ra; /* bits 11-15 */ |
| uchar rb; /* bits 16-20 */ |
| uchar rc; /* bit 31 */ |
| /*union {*/ |
| uchar rs; /* bits 6-10 */ |
| uchar rd; |
| /*};*/ |
| uchar sh; /* bits 16-20 */ |
| ushort spr; /* bits 11-20 */ |
| uchar to; /* bits 6-10 */ |
| uchar imm; /* bits 16-19 */ |
| ushort xo; /* bits 21-30, 22-30, 26-30, or 30 (beware) */ |
| long immediate; |
| long w0; |
| long w1; |
| u64int addr; /* pc of instruction */ |
| short target; |
| char *curr; /* current fill level in output buffer */ |
| char *end; /* end of buffer */ |
| int size; /* number of longs in instr */ |
| char *err; /* errmsg */ |
| } Instr; |
| |
| #define IBF(v,a,b) (((ulong)(v)>>(32-(b)-1)) & ~(~0L<<(((b)-(a)+1)))) |
| #define IB(v,b) IBF((v),(b),(b)) |
| |
| static void |
| bprint(Instr *i, char *fmt, ...) |
| { |
| va_list arg; |
| |
| va_start(arg, fmt); |
| i->curr = vseprint(i->curr, i->end, fmt, arg); |
| va_end(arg); |
| } |
| |
| static int |
| decode(ulong pc, Instr *i) |
| { |
| u32int w; |
| |
| if (get4(mymap, pc, &w) < 0) { |
| werrstr("can't read instruction: %r"); |
| return -1; |
| } |
| i->aa = IB(w, 30); |
| i->crba = IBF(w, 11, 15); |
| i->crbb = IBF(w, 16, 20); |
| i->bd = IBF(w, 16, 29)<<2; |
| if(i->bd & 0x8000) |
| i->bd |= ~0L<<16; |
| i->crfd = IBF(w, 6, 8); |
| i->crfs = IBF(w, 11, 13); |
| i->bi = IBF(w, 11, 15); |
| i->bo = IBF(w, 6, 10); |
| i->crbd = IBF(w, 6, 10); |
| i->uimm = IBF(w, 16, 31); /* also d, simm */ |
| i->fm = IBF(w, 7, 14); |
| i->fra = IBF(w, 11, 15); |
| i->frb = IBF(w, 16, 20); |
| i->frc = IBF(w, 21, 25); |
| i->frs = IBF(w, 6, 10); |
| i->frd = IBF(w, 6, 10); |
| i->crm = IBF(w, 12, 19); |
| i->li = IBF(w, 6, 29)<<2; |
| if(IB(w, 6)) |
| i->li |= ~0<<25; |
| i->lk = IB(w, 31); |
| i->mb = IBF(w, 21, 25); |
| i->me = IBF(w, 26, 30); |
| i->nb = IBF(w, 16, 20); |
| i->op = IBF(w, 0, 5); |
| i->oe = IB(w, 21); |
| i->ra = IBF(w, 11, 15); |
| i->rb = IBF(w, 16, 20); |
| i->rc = IB(w, 31); |
| i->rs = IBF(w, 6, 10); /* also rd */ |
| i->sh = IBF(w, 16, 20); |
| i->spr = IBF(w, 11, 20); |
| i->to = IBF(w, 6, 10); |
| i->imm = IBF(w, 16, 19); |
| i->xo = IBF(w, 21, 30); /* bits 21-30, 22-30, 26-30, or 30 (beware) */ |
| i->immediate = i->simm; |
| if(i->op == 15) |
| i->immediate <<= 16; |
| i->w0 = w; |
| i->target = -1; |
| i->addr = pc; |
| i->size = 1; |
| return 1; |
| } |
| |
| static int |
| mkinstr(ulong pc, Instr *i) |
| { |
| Instr x; |
| |
| if(decode(pc, i) < 0) |
| return -1; |
| /* |
| * combine ADDIS/ORI (CAU/ORIL) into MOVW |
| */ |
| if (i->op == 15 && i->ra==0) { |
| if(decode(pc+4, &x) < 0) |
| return -1; |
| if (x.op == 24 && x.rs == x.ra && x.ra == i->rd) { |
| i->immediate |= (x.immediate & 0xFFFF); |
| i->w1 = x.w0; |
| i->target = x.rd; |
| i->size++; |
| return 1; |
| } |
| } |
| return 1; |
| } |
| |
| static int |
| plocal(Instr *i) |
| { |
| Symbol s; |
| Loc l, li; |
| |
| l.type = LOFFSET; |
| l.offset = i->immediate; |
| l.reg = "SP"; |
| |
| li.type = LADDR; |
| li.addr = i->addr; |
| if (findsym(li, CTEXT, &s)<0 || findlsym(&s, l, &s)<0) |
| return -1; |
| bprint(i, "%s%+ld(SP)", s.name, (long)i->immediate); |
| return 0; |
| } |
| |
| static int |
| pglobal(Instr *i, long off, int anyoff, char *reg) |
| { |
| Symbol s, s2; |
| u32int off1; |
| Loc l; |
| |
| l.type = LADDR; |
| l.addr = off; |
| if(findsym(l, CANY, &s)>=0 && s.loc.type==LADDR && |
| s.loc.addr-off < 4096 && |
| (s.class == CDATA || s.class == CTEXT)) { |
| if(off==s.loc.addr && s.name[0]=='$'){ |
| off1 = 0; |
| get4(mymap, s.loc.addr, &off1); |
| l.addr = off1; |
| if(off1 && findsym(l, CANY, &s2)>=0 && s2.loc.type==LADDR && s2.loc.addr == off1){ |
| bprint(i, "$%s%s", s2.name, reg); |
| return 1; |
| } |
| } |
| bprint(i, "%s", s.name); |
| if (s.loc.addr != off) |
| bprint(i, "+%lux", off-s.loc.addr); |
| bprint(i, reg); |
| return 1; |
| } |
| if(!anyoff) |
| return 0; |
| bprint(i, "%lux%s", off, reg); |
| return 1; |
| } |
| |
| static void |
| address(Instr *i) |
| { |
| if (i->ra == REGSP && plocal(i) >= 0) |
| return; |
| if (i->ra == REGSB && mach->sb && pglobal(i, mach->sb+i->immediate, 0, "(SB)") >= 0) |
| return; |
| if(i->simm < 0) |
| bprint(i, "-%lx(R%d)", -i->simm, i->ra); |
| else |
| bprint(i, "%lux(R%d)", i->immediate, i->ra); |
| } |
| |
| static char *tcrbits[] = {"LT", "GT", "EQ", "VS"}; |
| static char *fcrbits[] = {"GE", "LE", "NE", "VC"}; |
| |
| typedef struct Opcode Opcode; |
| |
| struct Opcode { |
| uchar op; |
| ushort xo; |
| ushort xomask; |
| char *mnemonic; |
| void (*f)(Opcode *, Instr *); |
| char *ken; |
| int flags; |
| }; |
| |
| static void format(char *, Instr *, char *); |
| |
| static void |
| branch(Opcode *o, Instr *i) |
| { |
| char buf[8]; |
| int bo, bi; |
| |
| bo = i->bo & ~1; /* ignore prediction bit */ |
| if(bo==4 || bo==12 || bo==20) { /* simple forms */ |
| if(bo != 20) { |
| bi = i->bi&3; |
| sprint(buf, "B%s%%L", bo==12? tcrbits[bi]: fcrbits[bi]); |
| format(buf, i, 0); |
| bprint(i, "\t"); |
| if(i->bi > 4) |
| bprint(i, "CR(%d),", i->bi/4); |
| } else |
| format("BR%L\t", i, 0); |
| if(i->op == 16) |
| format(0, i, "%J"); |
| else if(i->op == 19 && i->xo == 528) |
| format(0, i, "(CTR)"); |
| else if(i->op == 19 && i->xo == 16) |
| format(0, i, "(LR)"); |
| } else |
| format(o->mnemonic, i, o->ken); |
| } |
| |
| static void |
| addi(Opcode *o, Instr *i) |
| { |
| if (i->op==14 && i->ra == 0) |
| format("MOVW", i, "%i,R%d"); |
| else if (i->ra == REGSB) { |
| bprint(i, "MOVW\t$"); |
| address(i); |
| bprint(i, ",R%d", i->rd); |
| } else if(i->op==14 && i->simm < 0) { |
| bprint(i, "SUB\t$%d,R%d", -i->simm, i->ra); |
| if(i->rd != i->ra) |
| bprint(i, ",R%d", i->rd); |
| } else if(i->ra == i->rd) { |
| format(o->mnemonic, i, "%i"); |
| bprint(i, ",R%d", i->rd); |
| } else |
| format(o->mnemonic, i, o->ken); |
| } |
| |
| static void |
| addis(Opcode *o, Instr *i) |
| { |
| long v; |
| |
| v = i->immediate; |
| if (i->op==15 && i->ra == 0) |
| bprint(i, "MOVW\t$%lux,R%d", v, i->rd); |
| else if (i->op==15 && i->ra == REGSB) { |
| bprint(i, "MOVW\t$"); |
| address(i); |
| bprint(i, ",R%d", i->rd); |
| } else if(i->op==15 && v < 0) { |
| bprint(i, "SUB\t$%d,R%d", -v, i->ra); |
| if(i->rd != i->ra) |
| bprint(i, ",R%d", i->rd); |
| } else { |
| format(o->mnemonic, i, 0); |
| bprint(i, "\t$%ld,R%d", v, i->ra); |
| if(i->rd != i->ra) |
| bprint(i, ",R%d", i->rd); |
| } |
| } |
| |
| static void |
| andi(Opcode *o, Instr *i) |
| { |
| if (i->ra == i->rs) |
| format(o->mnemonic, i, "%I,R%d"); |
| else |
| format(o->mnemonic, i, o->ken); |
| } |
| |
| static void |
| gencc(Opcode *o, Instr *i) |
| { |
| format(o->mnemonic, i, o->ken); |
| } |
| |
| static void |
| gen(Opcode *o, Instr *i) |
| { |
| format(o->mnemonic, i, o->ken); |
| if (i->rc) |
| bprint(i, " [illegal Rc]"); |
| } |
| |
| static void |
| ldx(Opcode *o, Instr *i) |
| { |
| if(i->ra == 0) |
| format(o->mnemonic, i, "(R%b),R%d"); |
| else |
| format(o->mnemonic, i, "(R%b+R%a),R%d"); |
| if(i->rc) |
| bprint(i, " [illegal Rc]"); |
| } |
| |
| static void |
| stx(Opcode *o, Instr *i) |
| { |
| if(i->ra == 0) |
| format(o->mnemonic, i, "R%d,(R%b)"); |
| else |
| format(o->mnemonic, i, "R%d,(R%b+R%a)"); |
| if(i->rc && i->xo != 150) |
| bprint(i, " [illegal Rc]"); |
| } |
| |
| static void |
| fldx(Opcode *o, Instr *i) |
| { |
| if(i->ra == 0) |
| format(o->mnemonic, i, "(R%b),F%d"); |
| else |
| format(o->mnemonic, i, "(R%b+R%a),F%d"); |
| if(i->rc) |
| bprint(i, " [illegal Rc]"); |
| } |
| |
| static void |
| fstx(Opcode *o, Instr *i) |
| { |
| if(i->ra == 0) |
| format(o->mnemonic, i, "F%d,(R%b)"); |
| else |
| format(o->mnemonic, i, "F%d,(R%b+R%a)"); |
| if(i->rc) |
| bprint(i, " [illegal Rc]"); |
| } |
| |
| static void |
| dcb(Opcode *o, Instr *i) |
| { |
| if(i->ra == 0) |
| format(o->mnemonic, i, "(R%b)"); |
| else |
| format(o->mnemonic, i, "(R%b+R%a)"); |
| if(i->rd) |
| bprint(i, " [illegal Rd]"); |
| if(i->rc) |
| bprint(i, " [illegal Rc]"); |
| } |
| |
| static void |
| lw(Opcode *o, Instr *i, char r) |
| { |
| bprint(i, "%s\t", o->mnemonic); |
| address(i); |
| bprint(i, ",%c%d", r, i->rd); |
| } |
| |
| static void |
| load(Opcode *o, Instr *i) |
| { |
| lw(o, i, 'R'); |
| } |
| |
| static void |
| fload(Opcode *o, Instr *i) |
| { |
| lw(o, i, 'F'); |
| } |
| |
| static void |
| sw(Opcode *o, Instr *i, char r) |
| { |
| char *m; |
| Symbol s; |
| Loc l; |
| |
| m = o->mnemonic; |
| if (i->rs == REGSP) { |
| l.type = LADDR; |
| l.addr = i->addr; |
| if (findsym(l, CTEXT, &s)>=0) { |
| l.type = LOFFSET; |
| l.reg = "SP"; |
| l.offset = i->immediate; |
| if (findlsym(&s, l, &s) >= 0) { |
| bprint(i, "%s\t%c%d,%s-%d(SP)", m, r, i->rd, |
| s.name, i->immediate); |
| return; |
| } |
| } |
| } |
| if (i->rs == REGSB && mach->sb) { |
| bprint(i, "%s\t%c%d,", m, r, i->rd); |
| address(i); |
| return; |
| } |
| if (r == 'F') |
| format(m, i, "F%d,%l"); |
| else |
| format(m, i, o->ken); |
| } |
| |
| static void |
| store(Opcode *o, Instr *i) |
| { |
| sw(o, i, 'R'); |
| } |
| |
| static void |
| fstore(Opcode *o, Instr *i) |
| { |
| sw(o, i, 'F'); |
| } |
| |
| static void |
| shifti(Opcode *o, Instr *i) |
| { |
| if (i->ra == i->rs) |
| format(o->mnemonic, i, "$%k,R%a"); |
| else |
| format(o->mnemonic, i, o->ken); |
| } |
| |
| static void |
| shift(Opcode *o, Instr *i) |
| { |
| if (i->ra == i->rs) |
| format(o->mnemonic, i, "R%b,R%a"); |
| else |
| format(o->mnemonic, i, o->ken); |
| } |
| |
| static void |
| add(Opcode *o, Instr *i) |
| { |
| if (i->rd == i->ra) |
| format(o->mnemonic, i, "R%b,R%d"); |
| else if (i->rd == i->rb) |
| format(o->mnemonic, i, "R%a,R%d"); |
| else |
| format(o->mnemonic, i, o->ken); |
| } |
| |
| static void |
| sub(Opcode *o, Instr *i) |
| { |
| format(o->mnemonic, i, 0); |
| bprint(i, "\t"); |
| if(i->op == 31) { |
| bprint(i, "\tR%d,R%d", i->ra, i->rb); /* subtract Ra from Rb */ |
| if(i->rd != i->rb) |
| bprint(i, ",R%d", i->rd); |
| } else |
| bprint(i, "\tR%d,$%d,R%d", i->ra, i->simm, i->rd); |
| } |
| |
| #define div power_div |
| |
| static void |
| div(Opcode *o, Instr *i) |
| { |
| format(o->mnemonic, i, 0); |
| if(i->op == 31) |
| bprint(i, "\tR%d,R%d", i->rb, i->ra); |
| else |
| bprint(i, "\t$%d,R%d", i->simm, i->ra); |
| if(i->ra != i->rd) |
| bprint(i, ",R%d", i->rd); |
| } |
| |
| static void |
| and(Opcode *o, Instr *i) |
| { |
| if (i->op == 31) { |
| /* Rb,Rs,Ra */ |
| if (i->ra == i->rs) |
| format(o->mnemonic, i, "R%b,R%a"); |
| else if (i->ra == i->rb) |
| format(o->mnemonic, i, "R%s,R%a"); |
| else |
| format(o->mnemonic, i, o->ken); |
| } else { |
| /* imm,Rs,Ra */ |
| if (i->ra == i->rs) |
| format(o->mnemonic, i, "%I,R%a"); |
| else |
| format(o->mnemonic, i, o->ken); |
| } |
| } |
| |
| static void |
| or(Opcode *o, Instr *i) |
| { |
| if (i->op == 31) { |
| /* Rb,Rs,Ra */ |
| if (i->rs == 0 && i->ra == 0 && i->rb == 0) |
| format("NOP", i, 0); |
| else if (i->rs == i->rb) |
| format("MOVW", i, "R%b,R%a"); |
| else |
| and(o, i); |
| } else |
| and(o, i); |
| } |
| |
| static void |
| shifted(Opcode *o, Instr *i) |
| { |
| format(o->mnemonic, i, 0); |
| bprint(i, "\t$%lux,", (ulong)i->uimm<<16); |
| if (i->rs == i->ra) |
| bprint(i, "R%d", i->ra); |
| else |
| bprint(i, "R%d,R%d", i->rs, i->ra); |
| } |
| |
| static void |
| neg(Opcode *o, Instr *i) |
| { |
| if (i->rd == i->ra) |
| format(o->mnemonic, i, "R%d"); |
| else |
| format(o->mnemonic, i, o->ken); |
| } |
| |
| static char ir2[] = "R%a,R%d"; /* reverse of IBM order */ |
| static char ir3[] = "R%b,R%a,R%d"; |
| static char ir3r[] = "R%a,R%b,R%d"; |
| static char il3[] = "R%b,R%s,R%a"; |
| static char il2u[] = "%I,R%a,R%d"; |
| static char il3s[] = "$%k,R%s,R%a"; |
| static char il2[] = "R%s,R%a"; |
| static char icmp3[] = "R%a,R%b,%D"; |
| static char cr3op[] = "%b,%a,%d"; |
| static char ir2i[] = "%i,R%a,R%d"; |
| static char fp2[] = "F%b,F%d"; |
| static char fp3[] = "F%b,F%a,F%d"; |
| static char fp3c[] = "F%c,F%a,F%d"; |
| static char fp4[] = "F%a,F%c,F%b,F%d"; |
| static char fpcmp[] = "F%a,F%b,%D"; |
| static char ldop[] = "%l,R%d"; |
| static char stop[] = "R%d,%l"; |
| static char fldop[] = "%l,F%d"; |
| static char fstop[] = "F%d,%l"; |
| static char rlim[] = "R%b,R%s,$%z,R%a"; |
| static char rlimi[] = "$%k,R%s,$%z,R%a"; |
| |
| #define OEM IBF(~0,22,30) |
| #define FP4 IBF(~0,26,30) |
| #define ALL ((ushort)~0) |
| /* |
| notes: |
| 10-26: crfD = rD>>2; rD&3 mbz |
| also, L bit (bit 10) mbz or selects 64-bit operands |
| */ |
| |
| static Opcode opcodes[] = { |
| {31, 360, OEM, "ABS%V%C", 0, ir2}, /* POWER */ |
| |
| {31, 266, OEM, "ADD%V%C", add, ir3}, |
| {31, 10, OEM, "ADDC%V%C", add, ir3}, |
| {31, 138, OEM, "ADDE%V%C", add, ir3}, |
| {14, 0, 0, "ADD", addi, ir2i}, |
| {12, 0, 0, "ADDC", addi, ir2i}, |
| {13, 0, 0, "ADDCCC", addi, ir2i}, |
| {15, 0, 0, "ADD", addis, 0}, |
| {31, 234, OEM, "ADDME%V%C", gencc, ir2}, |
| {31, 202, OEM, "ADDZE%V%C", gencc, ir2}, |
| |
| {31, 28, ALL, "AND%C", and, il3}, |
| {31, 60, ALL, "ANDN%C", and, il3}, |
| {28, 0, 0, "ANDCC", andi, il2u}, |
| {29, 0, 0, "ANDCC", shifted, 0}, |
| |
| {18, 0, 0, "B%L", gencc, "%j"}, |
| {16, 0, 0, "BC%L", branch, "%d,%a,%J"}, |
| {19, 528, ALL, "BC%L", branch, "%d,%a,(CTR)"}, |
| {19, 16, ALL, "BC%L", branch, "%d,%a,(LR)"}, |
| |
| {31, 531, ALL, "CLCS", gen, ir2}, /* POWER */ |
| |
| {31, 0, ALL, "CMP", 0, icmp3}, |
| {11, 0, 0, "CMP", 0, "R%a,%i,%D"}, |
| {31, 32, ALL, "CMPU", 0, icmp3}, |
| {10, 0, 0, "CMPU", 0, "R%a,%I,%D"}, |
| |
| {31, 26, ALL, "CNTLZ%C", gencc, ir2}, |
| |
| {19, 257, ALL, "CRAND", gen, cr3op}, |
| {19, 129, ALL, "CRANDN", gen, cr3op}, |
| {19, 289, ALL, "CREQV", gen, cr3op}, |
| {19, 225, ALL, "CRNAND", gen, cr3op}, |
| {19, 33, ALL, "CRNOR", gen, cr3op}, |
| {19, 449, ALL, "CROR", gen, cr3op}, |
| {19, 417, ALL, "CRORN", gen, cr3op}, |
| {19, 193, ALL, "CRXOR", gen, cr3op}, |
| |
| {31, 86, ALL, "DCBF", dcb, 0}, |
| {31, 470, ALL, "DCBI", dcb, 0}, |
| {31, 54, ALL, "DCBST", dcb, 0}, |
| {31, 278, ALL, "DCBT", dcb, 0}, |
| {31, 246, ALL, "DCBTST", dcb, 0}, |
| {31, 1014, ALL, "DCBZ", dcb, 0}, |
| |
| {31, 331, OEM, "DIV%V%C", div, ir3}, /* POWER */ |
| {31, 363, OEM, "DIVS%V%C", div, ir3}, /* POWER */ |
| {31, 491, OEM, "DIVW%V%C", div, ir3}, |
| {31, 459, OEM, "DIVWU%V%C", div, ir3}, |
| |
| {31, 264, OEM, "DOZ%V%C", gencc, ir3r}, /* POWER */ |
| {9, 0, 0, "DOZ", gen, ir2i}, /* POWER */ |
| |
| {31, 310, ALL, "ECIWX", ldx, 0}, |
| {31, 438, ALL, "ECOWX", stx, 0}, |
| {31, 854, ALL, "EIEIO", gen, 0}, |
| |
| {31, 284, ALL, "EQV%C", gencc, il3}, |
| |
| {31, 954, ALL, "EXTSB%C", gencc, il2}, |
| {31, 922, ALL, "EXTSH%C", gencc, il2}, |
| |
| {63, 264, ALL, "FABS%C", gencc, fp2}, |
| {63, 21, ALL, "FADD%C", gencc, fp3}, |
| {59, 21, ALL, "FADDS%C", gencc, fp3}, |
| {63, 32, ALL, "FCMPO", gen, fpcmp}, |
| {63, 0, ALL, "FCMPU", gen, fpcmp}, |
| {63, 14, ALL, "FCTIW%C", gencc, fp2}, |
| {63, 15, ALL, "FCTIWZ%C", gencc, fp2}, |
| {63, 18, ALL, "FDIV%C", gencc, fp3}, |
| {59, 18, ALL, "FDIVS%C", gencc, fp3}, |
| {63, 29, FP4, "FMADD%C", gencc, fp4}, |
| {59, 29, FP4, "FMADDS%C", gencc, fp4}, |
| {63, 72, ALL, "FMOVD%C", gencc, fp2}, |
| {63, 28, FP4, "FMSUB%C", gencc, fp4}, |
| {59, 28, FP4, "FMSUBS%C", gencc, fp4}, |
| {63, 25, FP4, "FMUL%C", gencc, fp3c}, |
| {59, 25, FP4, "FMULS%C", gencc, fp3c}, |
| {63, 136, ALL, "FNABS%C", gencc, fp2}, |
| {63, 40, ALL, "FNEG%C", gencc, fp2}, |
| {63, 31, FP4, "FNMADD%C", gencc, fp4}, |
| {59, 31, FP4, "FNMADDS%C", gencc, fp4}, |
| {63, 30, FP4, "FNMSUB%C", gencc, fp4}, |
| {59, 30, FP4, "FNMSUBS%C", gencc, fp4}, |
| {63, 12, ALL, "FRSP%C", gencc, fp2}, |
| {63, 20, FP4, "FSUB%C", gencc, fp3}, |
| {59, 20, FP4, "FSUBS%C", gencc, fp3}, |
| |
| {31, 982, ALL, "ICBI", dcb, 0}, |
| {19, 150, ALL, "ISYNC", gen, 0}, |
| |
| {34, 0, 0, "MOVBZ", load, ldop}, |
| {35, 0, 0, "MOVBZU", load, ldop}, |
| {31, 119, ALL, "MOVBZU", ldx, 0}, |
| {31, 87, ALL, "MOVBZ", ldx, 0}, |
| {50, 0, 0, "FMOVD", fload, fldop}, |
| {51, 0, 0, "FMOVDU", fload, fldop}, |
| {31, 631, ALL, "FMOVDU", fldx, 0}, |
| {31, 599, ALL, "FMOVD", fldx, 0}, |
| {48, 0, 0, "FMOVS", load, fldop}, |
| {49, 0, 0, "FMOVSU", load, fldop}, |
| {31, 567, ALL, "FMOVSU", fldx, 0}, |
| {31, 535, ALL, "FMOVS", fldx, 0}, |
| {42, 0, 0, "MOVH", load, ldop}, |
| {43, 0, 0, "MOVHU", load, ldop}, |
| {31, 375, ALL, "MOVHU", ldx, 0}, |
| {31, 343, ALL, "MOVH", ldx, 0}, |
| {31, 790, ALL, "MOVHBR", ldx, 0}, |
| {40, 0, 0, "MOVHZ", load, ldop}, |
| {41, 0, 0, "MOVHZU", load, ldop}, |
| {31, 311, ALL, "MOVHZU", ldx, 0}, |
| {31, 279, ALL, "MOVHZ", ldx, 0}, |
| {46, 0, 0, "MOVMW", load, ldop}, |
| {31, 277, ALL, "LSCBX%C", ldx, 0}, /* POWER */ |
| {31, 597, ALL, "LSW", gen, "(R%a),$%n,R%d"}, |
| {31, 533, ALL, "LSW", ldx, 0}, |
| {31, 20, ALL, "LWAR", ldx, 0}, |
| {31, 534, ALL, "MOVWBR", ldx, 0}, |
| {32, 0, 0, "MOVW", load, ldop}, |
| {33, 0, 0, "MOVWU", load, ldop}, |
| {31, 55, ALL, "MOVWU", ldx, 0}, |
| {31, 23, ALL, "MOVW", ldx, 0}, |
| |
| {31, 29, ALL, "MASKG%C", gencc, "R%s:R%b,R%d"}, /* POWER */ |
| {31, 541, ALL, "MASKIR%C", gencc, "R%s,R%b,R%a"}, /* POWER */ |
| |
| {19, 0, ALL, "MOVFL", gen, "%S,%D"}, |
| {63, 64, ALL, "MOVCRFS", gen, "%S,%D"}, |
| {31, 512, ALL, "MOVW", gen, "XER,%D"}, |
| {31, 19, ALL, "MOVW", gen, "CR,R%d"}, |
| |
| {63, 583, ALL, "MOVW%C", gen, "FPSCR, F%d"}, /* mffs */ |
| {31, 83, ALL, "MOVW", gen, "MSR,R%d"}, |
| {31, 339, ALL, "MOVW", gen, "%P,R%d"}, |
| {31, 595, ALL, "MOVW", gen, "SEG(%a),R%d"}, |
| {31, 659, ALL, "MOVW", gen, "SEG(R%b),R%d"}, |
| {31, 144, ALL, "MOVFL", gen, "R%s,%m,CR"}, |
| {63, 70, ALL, "MTFSB0%C", gencc, "%D"}, |
| {63, 38, ALL, "MTFSB1%C", gencc, "%D"}, |
| {63, 711, ALL, "MOVFL%C", gencc, "F%b,%M,FPSCR"}, /* mtfsf */ |
| {63, 134, ALL, "MOVFL%C", gencc, "%K,%D"}, |
| {31, 146, ALL, "MOVW", gen, "R%s,MSR"}, |
| {31, 467, ALL, "MOVW", gen, "R%s,%P"}, |
| {31, 210, ALL, "MOVW", gen, "R%s,SEG(%a)"}, |
| {31, 242, ALL, "MOVW", gen, "R%s,SEG(R%b)"}, |
| |
| {31, 107, OEM, "MUL%V%C", gencc, ir3}, /* POWER */ |
| {31, 75, ALL, "MULHW%C", gencc, ir3}, /* POWER */ |
| {31, 11, ALL, "MULHWU%C", gencc, ir3}, /* POWER */ |
| |
| {31, 235, OEM, "MULLW%V%C", gencc, ir3}, |
| {7, 0, 0, "MULLW", div, "%i,R%a,R%d"}, |
| |
| {31, 488, OEM, "NABS%V%C", neg, ir2}, /* POWER */ |
| |
| {31, 476, ALL, "NAND%C", gencc, il3}, |
| {31, 104, OEM, "NEG%V%C", neg, ir2}, |
| {31, 124, ALL, "NOR%C", gencc, il3}, |
| {31, 444, ALL, "OR%C", or, il3}, |
| {31, 412, ALL, "ORN%C", or, il3}, |
| {24, 0, 0, "OR", and, "%I,R%d,R%a"}, |
| {25, 0, 0, "OR", shifted, 0}, |
| |
| {19, 50, ALL, "RFI", gen, 0}, |
| |
| {22, 0, 0, "RLMI%C", gencc, rlim}, /* POWER */ |
| {20, 0, 0, "RLWMI%C", gencc, rlimi}, |
| {21, 0, 0, "RLWNM%C", gencc, rlimi}, |
| {23, 0, 0, "RLWNM%C", gencc, rlim}, |
| |
| {31, 537, ALL, "RRIB%C", gencc, il3}, /* POWER */ |
| |
| {17, 1, ALL, "SYSCALL", gen, 0}, |
| |
| {31, 153, ALL, "SLE%C", shift, il3}, /* POWER */ |
| {31, 217, ALL, "SLEQ%C", shift, il3}, /* POWER */ |
| {31, 184, ALL, "SLQ%C", shifti, il3s}, /* POWER */ |
| {31, 248, ALL, "SLLQ%C", shifti, il3s}, /* POWER */ |
| {31, 216, ALL, "SLLQ%C", shift, il3}, /* POWER */ |
| {31, 152, ALL, "SLQ%C", shift, il3}, /* POWER */ |
| |
| {31, 24, ALL, "SLW%C", shift, il3}, |
| |
| {31, 920, ALL, "SRAQ%C", shift, il3}, /* POWER */ |
| {31, 952, ALL, "SRAQ%C", shifti, il3s}, /* POWER */ |
| |
| {31, 792, ALL, "SRAW%C", shift, il3}, |
| {31, 824, ALL, "SRAW%C", shifti, il3s}, |
| |
| {31, 665, ALL, "SRE%C", shift, il3}, /* POWER */ |
| {31, 921, ALL, "SREA%C", shift, il3}, /* POWER */ |
| {31, 729, ALL, "SREQ%C", shift, il3}, /* POWER */ |
| {31, 696, ALL, "SRQ%C", shifti, il3s}, /* POWER */ |
| {31, 760, ALL, "SRLQ%C", shifti, il3s}, /* POWER */ |
| {31, 728, ALL, "SRLQ%C", shift, il3}, /* POWER */ |
| {31, 664, ALL, "SRQ%C", shift, il3}, /* POWER */ |
| |
| {31, 536, ALL, "SRW%C", shift, il3}, |
| |
| {38, 0, 0, "MOVB", store, stop}, |
| {39, 0, 0, "MOVBU", store, stop}, |
| {31, 247, ALL, "MOVBU", stx, 0}, |
| {31, 215, ALL, "MOVB", stx, 0}, |
| {54, 0, 0, "FMOVD", fstore, fstop}, |
| {55, 0, 0, "FMOVDU", fstore, fstop}, |
| {31, 759, ALL, "FMOVDU", fstx, 0}, |
| {31, 727, ALL, "FMOVD", fstx, 0}, |
| {52, 0, 0, "FMOVS", fstore, fstop}, |
| {53, 0, 0, "FMOVSU", fstore, fstop}, |
| {31, 695, ALL, "FMOVSU", fstx, 0}, |
| {31, 663, ALL, "FMOVS", fstx, 0}, |
| {44, 0, 0, "MOVH", store, stop}, |
| {31, 918, ALL, "MOVHBR", stx, 0}, |
| {45, 0, 0, "MOVHU", store, stop}, |
| {31, 439, ALL, "MOVHU", stx, 0}, |
| {31, 407, ALL, "MOVH", stx, 0}, |
| {47, 0, 0, "MOVMW", store, stop}, |
| {31, 725, ALL, "STSW", gen, "R%d,$%n,(R%a)"}, |
| {31, 661, ALL, "STSW", stx, 0}, |
| {36, 0, 0, "MOVW", store, stop}, |
| {31, 662, ALL, "MOVWBR", stx, 0}, |
| {31, 150, ALL, "STWCCC", stx, 0}, |
| {37, 0, 0, "MOVWU", store, stop}, |
| {31, 183, ALL, "MOVWU", stx, 0}, |
| {31, 151, ALL, "MOVW", stx, 0}, |
| |
| {31, 40, OEM, "SUB%V%C", sub, ir3}, |
| {31, 8, OEM, "SUBC%V%C", sub, ir3}, |
| {31, 136, OEM, "SUBE%V%C", sub, ir3}, |
| {8, 0, 0, "SUBC", gen, "R%a,%i,R%d"}, |
| {31, 232, OEM, "SUBME%V%C", sub, ir2}, |
| {31, 200, OEM, "SUBZE%V%C", sub, ir2}, |
| |
| {31, 598, ALL, "SYNC", gen, 0}, |
| {31, 370, ALL, "TLBIA", gen, 0}, |
| {31, 306, ALL, "TLBIE", gen, "R%b"}, |
| {31, 1010, ALL, "TLBLI", gen, "R%b"}, |
| {31, 978, ALL, "TLBLD", gen, "R%b"}, |
| {31, 4, ALL, "TW", gen, "%d,R%a,R%b"}, |
| {3, 0, 0, "TW", gen, "%d,R%a,%i"}, |
| |
| {31, 316, ALL, "XOR", and, il3}, |
| {26, 0, 0, "XOR", and, il2u}, |
| {27, 0, 0, "XOR", shifted, 0}, |
| |
| {0}, |
| }; |
| |
| typedef struct Spr Spr; |
| struct Spr { |
| int n; |
| char *name; |
| }; |
| |
| static Spr sprname[] = { |
| {0, "MQ"}, |
| {1, "XER"}, |
| {268, "TBL"}, |
| {269, "TBU"}, |
| {8, "LR"}, |
| {9, "CTR"}, |
| {528, "IBAT0U"}, |
| {529, "IBAT0L"}, |
| {530, "IBAT1U"}, |
| {531, "IBAT1L"}, |
| {532, "IBAT2U"}, |
| {533, "IBAT2L"}, |
| {534, "IBAT3U"}, |
| {535, "IBAT3L"}, |
| {536, "DBAT0U"}, |
| {537, "DBAT0L"}, |
| {538, "DBAT1U"}, |
| {539, "DBAT1L"}, |
| {540, "DBAT2U"}, |
| {541, "DBAT2L"}, |
| {542, "DBAT3U"}, |
| {543, "DBAT3L"}, |
| {25, "SDR1"}, |
| {19, "DAR"}, |
| {272, "SPRG0"}, |
| {273, "SPRG1"}, |
| {274, "SPRG2"}, |
| {275, "SPRG3"}, |
| {18, "DSISR"}, |
| {26, "SRR0"}, |
| {27, "SRR1"}, |
| {284, "TBLW"}, |
| {285, "TBUW"}, |
| {22, "DEC"}, |
| {282, "EAR"}, |
| {1008, "HID0"}, |
| {1009, "HID1"}, |
| {976, "DMISS"}, |
| {977, "DCMP"}, |
| {978, "HASH1"}, |
| {979, "HASH2"}, |
| {980, "IMISS"}, |
| {981, "ICMP"}, |
| {982, "RPA"}, |
| {1010, "IABR"}, |
| {0,0}, |
| }; |
| |
| static void |
| format(char *mnemonic, Instr *i, char *f) |
| { |
| int n, s; |
| ulong mask; |
| |
| if (mnemonic) |
| format(0, i, mnemonic); |
| if (f == 0) |
| return; |
| if (mnemonic) |
| bprint(i, "\t"); |
| for ( ; *f; f++) { |
| if (*f != '%') { |
| bprint(i, "%c", *f); |
| continue; |
| } |
| switch (*++f) { |
| case 'V': |
| if(i->oe) |
| bprint(i, "V"); |
| break; |
| |
| case 'C': |
| if(i->rc) |
| bprint(i, "CC"); |
| break; |
| |
| case 'a': |
| bprint(i, "%d", i->ra); |
| break; |
| |
| case 'b': |
| bprint(i, "%d", i->rb); |
| break; |
| |
| case 'c': |
| bprint(i, "%d", i->frc); |
| break; |
| |
| case 'd': |
| case 's': |
| bprint(i, "%d", i->rd); |
| break; |
| |
| case 'S': |
| if(i->ra & 3) |
| bprint(i, "CR(INVAL:%d)", i->ra); |
| else if(i->op == 63) |
| bprint(i, "FPSCR(%d)", i->crfs); |
| else |
| bprint(i, "CR(%d)", i->crfs); |
| break; |
| |
| case 'D': |
| if(i->rd & 3) |
| bprint(i, "CR(INVAL:%d)", i->rd); |
| else if(i->op == 63) |
| bprint(i, "FPSCR(%d)", i->crfd); |
| else |
| bprint(i, "CR(%d)", i->crfd); |
| break; |
| |
| case 'l': |
| if(i->simm < 0) |
| bprint(i, "-%lx(R%d)", -i->simm, i->ra); |
| else |
| bprint(i, "%lx(R%d)", i->simm, i->ra); |
| break; |
| |
| case 'i': |
| bprint(i, "$%ld", i->simm); |
| break; |
| |
| case 'I': |
| bprint(i, "$%lx", i->uimm); |
| break; |
| |
| case 'w': |
| bprint(i, "[%lux]", i->w0); |
| break; |
| |
| case 'P': |
| n = ((i->spr&0x1f)<<5)|((i->spr>>5)&0x1f); |
| for(s=0; sprname[s].name; s++) |
| if(sprname[s].n == n) |
| break; |
| if(sprname[s].name) { |
| if(s < 10) |
| bprint(i, sprname[s].name); |
| else |
| bprint(i, "SPR(%s)", sprname[s].name); |
| } else |
| bprint(i, "SPR(%d)", n); |
| break; |
| |
| case 'n': |
| bprint(i, "%d", i->nb==0? 32: i->nb); /* eg, pg 10-103 */ |
| break; |
| |
| case 'm': |
| bprint(i, "%lx", i->crm); |
| break; |
| |
| case 'M': |
| bprint(i, "%lx", i->fm); |
| break; |
| |
| case 'z': |
| if(i->mb <= i->me) |
| mask = ((ulong)~0L>>i->mb) & (~0L<<(31-i->me)); |
| else |
| mask = ~(((ulong)~0L>>(i->me+1)) & (~0L<<(31-(i->mb-1)))); |
| bprint(i, "%lux", mask); |
| break; |
| |
| case 'k': |
| bprint(i, "%d", i->sh); |
| break; |
| |
| case 'K': |
| bprint(i, "$%x", i->imm); |
| break; |
| |
| case 'L': |
| if(i->lk) |
| bprint(i, "L"); |
| break; |
| |
| case 'j': |
| if(i->aa) |
| pglobal(i, i->li, 1, "(SB)"); |
| else |
| pglobal(i, i->addr+i->li, 1, ""); |
| break; |
| |
| case 'J': |
| if(i->aa) |
| pglobal(i, i->bd, 1, "(SB)"); |
| else |
| pglobal(i, i->addr+i->bd, 1, ""); |
| break; |
| |
| case '\0': |
| bprint(i, "%%"); |
| return; |
| |
| default: |
| bprint(i, "%%%c", *f); |
| break; |
| } |
| } |
| } |
| |
| static int |
| printins(Map *map, ulong pc, char *buf, int n) |
| { |
| Instr i; |
| Opcode *o; |
| |
| mymap = map; |
| memset(&i, 0, sizeof(i)); |
| i.curr = buf; |
| i.end = buf+n-1; |
| if(mkinstr(pc, &i) < 0) |
| return -1; |
| for(o = opcodes; o->mnemonic != 0; o++) |
| if(i.op == o->op && (i.xo & o->xomask) == o->xo) { |
| if (o->f) |
| (*o->f)(o, &i); |
| else |
| format(o->mnemonic, &i, o->ken); |
| return i.size*4; |
| } |
| bprint(&i, "unknown %lux", i.w0); |
| return i.size*4; |
| } |
| |
| static int |
| powerdas(Map *map, u64int pc, char modifier, char *buf, int n) |
| { |
| USED(modifier); |
| return printins(map, pc, buf, n); |
| } |
| |
| static int |
| powerhexinst(Map *map, u64int pc, char *buf, int n) |
| { |
| Instr instr; |
| |
| mymap = map; |
| memset(&instr, 0, sizeof(instr)); |
| instr.curr = buf; |
| instr.end = buf+n-1; |
| if (mkinstr(pc, &instr) < 0) |
| return -1; |
| if (instr.end-instr.curr > 8) |
| instr.curr = _hexify(instr.curr, instr.w0, 7); |
| if (instr.end-instr.curr > 9 && instr.size == 2) { |
| *instr.curr++ = ' '; |
| instr.curr = _hexify(instr.curr, instr.w1, 7); |
| } |
| *instr.curr = 0; |
| return instr.size*4; |
| } |
| |
| static int |
| powerinstlen(Map *map, u64int pc) |
| { |
| Instr i; |
| |
| mymap = map; |
| if (mkinstr(pc, &i) < 0) |
| return -1; |
| return i.size*4; |
| } |
| |
| static int |
| powerfoll(Map *map, Regs *regs, u64int pc, u64int *foll) |
| { |
| char *reg; |
| Instr i; |
| |
| mymap = map; |
| if (mkinstr(pc, &i) < 0) |
| return -1; |
| foll[0] = pc+4; |
| foll[1] = pc+4; |
| switch(i.op) { |
| default: |
| return 1; |
| |
| case 18: /* branch */ |
| foll[0] = i.li; |
| if(!i.aa) |
| foll[0] += pc; |
| break; |
| |
| case 16: /* conditional branch */ |
| foll[0] = i.bd; |
| if(!i.aa) |
| foll[0] += pc; |
| break; |
| |
| case 19: /* conditional branch to register */ |
| if(i.xo == 528) |
| reg = "CTR"; |
| else if(i.xo == 16) |
| reg = "LR"; |
| else |
| return 1; /* not a branch */ |
| if(rget(regs, reg, &foll[0]) < 0) |
| return -1; |
| break; |
| } |
| if(i.lk) |
| return 2; |
| return 1; |
| } |
| |
| #define REGOFF(x) (ulong) (&((struct Ureg *) 0)->x) |
| |
| #define SP REGOFF(r1) |
| #define PC REGOFF(pc) |
| #define R3 REGOFF(r3) /* return reg */ |
| #define LR REGOFF(lr) |
| #define R31 REGOFF(r31) |
| #define FP_REG(x) (R31+4+8*(x)) |
| |
| #define REGSIZE sizeof(struct Ureg) |
| #define FPREGSIZE (8*33) |
| |
| Regdesc powerreglist[] = |
| { |
| {"CAUSE", REGOFF(cause), RINT|RRDONLY, 'X'}, |
| {"SRR1", REGOFF(srr1), RINT|RRDONLY, 'X'}, |
| {"PC", REGOFF(pc), RINT, 'X'}, |
| {"LR", REGOFF(lr), RINT, 'X'}, |
| {"CR", REGOFF(cr), RINT, 'X'}, |
| {"XER", REGOFF(xer), RINT, 'X'}, |
| {"CTR", REGOFF(ctr), RINT, 'X'}, |
| {"PC", PC, RINT, 'X'}, |
| {"SP", SP, RINT, 'X'}, |
| {"R0", REGOFF(r0), RINT, 'X'}, |
| /* R1 is SP */ |
| {"R2", REGOFF(r2), RINT, 'X'}, |
| {"R3", REGOFF(r3), RINT, 'X'}, |
| {"R4", REGOFF(r4), RINT, 'X'}, |
| {"R5", REGOFF(r5), RINT, 'X'}, |
| {"R6", REGOFF(r6), RINT, 'X'}, |
| {"R7", REGOFF(r7), RINT, 'X'}, |
| {"R8", REGOFF(r8), RINT, 'X'}, |
| {"R9", REGOFF(r9), RINT, 'X'}, |
| {"R10", REGOFF(r10), RINT, 'X'}, |
| {"R11", REGOFF(r11), RINT, 'X'}, |
| {"R12", REGOFF(r12), RINT, 'X'}, |
| {"R13", REGOFF(r13), RINT, 'X'}, |
| {"R14", REGOFF(r14), RINT, 'X'}, |
| {"R15", REGOFF(r15), RINT, 'X'}, |
| {"R16", REGOFF(r16), RINT, 'X'}, |
| {"R17", REGOFF(r17), RINT, 'X'}, |
| {"R18", REGOFF(r18), RINT, 'X'}, |
| {"R19", REGOFF(r19), RINT, 'X'}, |
| {"R20", REGOFF(r20), RINT, 'X'}, |
| {"R21", REGOFF(r21), RINT, 'X'}, |
| {"R22", REGOFF(r22), RINT, 'X'}, |
| {"R23", REGOFF(r23), RINT, 'X'}, |
| {"R24", REGOFF(r24), RINT, 'X'}, |
| {"R25", REGOFF(r25), RINT, 'X'}, |
| {"R26", REGOFF(r26), RINT, 'X'}, |
| {"R27", REGOFF(r27), RINT, 'X'}, |
| {"R28", REGOFF(r28), RINT, 'X'}, |
| {"R29", REGOFF(r29), RINT, 'X'}, |
| {"R30", REGOFF(r30), RINT, 'X'}, |
| {"R31", REGOFF(r31), RINT, 'X'}, |
| {"VRSAVE", REGOFF(vrsave), RINT, 'X'}, |
| {"F0", FP_REG(0), RFLT, 'F'}, |
| {"F1", FP_REG(1), RFLT, 'F'}, |
| {"F2", FP_REG(2), RFLT, 'F'}, |
| {"F3", FP_REG(3), RFLT, 'F'}, |
| {"F4", FP_REG(4), RFLT, 'F'}, |
| {"F5", FP_REG(5), RFLT, 'F'}, |
| {"F6", FP_REG(6), RFLT, 'F'}, |
| {"F7", FP_REG(7), RFLT, 'F'}, |
| {"F8", FP_REG(8), RFLT, 'F'}, |
| {"F9", FP_REG(9), RFLT, 'F'}, |
| {"F10", FP_REG(10), RFLT, 'F'}, |
| {"F11", FP_REG(11), RFLT, 'F'}, |
| {"F12", FP_REG(12), RFLT, 'F'}, |
| {"F13", FP_REG(13), RFLT, 'F'}, |
| {"F14", FP_REG(14), RFLT, 'F'}, |
| {"F15", FP_REG(15), RFLT, 'F'}, |
| {"F16", FP_REG(16), RFLT, 'F'}, |
| {"F17", FP_REG(17), RFLT, 'F'}, |
| {"F18", FP_REG(18), RFLT, 'F'}, |
| {"F19", FP_REG(19), RFLT, 'F'}, |
| {"F20", FP_REG(20), RFLT, 'F'}, |
| {"F21", FP_REG(21), RFLT, 'F'}, |
| {"F22", FP_REG(22), RFLT, 'F'}, |
| {"F23", FP_REG(23), RFLT, 'F'}, |
| {"F24", FP_REG(24), RFLT, 'F'}, |
| {"F25", FP_REG(25), RFLT, 'F'}, |
| {"F26", FP_REG(26), RFLT, 'F'}, |
| {"F27", FP_REG(27), RFLT, 'F'}, |
| {"F28", FP_REG(28), RFLT, 'F'}, |
| {"F29", FP_REG(29), RFLT, 'F'}, |
| {"F30", FP_REG(30), RFLT, 'F'}, |
| {"F31", FP_REG(31), RFLT, 'F'}, |
| {"FPSCR", FP_REG(32)+4, RFLT, 'X'}, |
| { 0 } |
| }; |
| |
| static char *powerwindregs[] = |
| { |
| "PC", |
| "SP", |
| "LR", |
| 0, |
| }; |
| |
| static int |
| powerunwind(Map *map, Regs *regs, u64int *next, Symbol *sym) |
| { |
| /* |
| * This is tremendously hard. The best we're going to |
| * do without better debugger support is trace through |
| * the stack frame links and pull the link registers out of 8(R1). |
| * Anything more requires knowing which registers got saved, |
| * and the compiler appears not to record that. Gdb appears |
| * to disassemble the function prologues in order to figure |
| * this out. |
| */ |
| /* evaluate lr */ |
| /* if in this function, no good - go to saved one. */ |
| /* set next[sp] to *cur[sp] */ |
| /* set next[pc] to lr */ |
| /* set next[lr] to lr */ |
| /* */ |
| werrstr("powerunwind not implemented"); |
| return -1; |
| } |
| |
| /* the machine description */ |
| Mach machpower = |
| { |
| "power", |
| MPOWER, /* machine type */ |
| powerreglist, /* register set */ |
| REGSIZE, /* number of bytes in register set */ |
| FPREGSIZE, /* number of bytes in FP register set */ |
| "PC", /* name of PC */ |
| "SP", /* name of SP */ |
| 0, /* name of FP */ |
| "LR", /* name of link register */ |
| "setSB", /* static base register name */ |
| 0, /* value */ |
| 0x1000, /* page size */ |
| 0x80000000, /* kernel base */ |
| 0, /* kernel text mask */ |
| 4, /* quantization of pc */ |
| 4, /* szaddr */ |
| 4, /* szreg */ |
| 4, /* szfloat */ |
| 8, /* szdouble */ |
| |
| powerwindregs, /* locations unwound in stack trace */ |
| 3, |
| |
| {0x02, 0x8F, 0xFF, 0xFF}, /* break point */ /* BUG */ |
| 4, |
| |
| powerfoll, /* following addresses */ |
| powerexcep, /* print exception */ |
| powerunwind, /* stack unwind */ |
| |
| beswap2, /* convert short to local byte order */ |
| beswap4, /* convert long to local byte order */ |
| beswap8, /* convert vlong to local byte order */ |
| beieeeftoa32, /* single precision float pointer */ |
| beieeeftoa64, /* double precision float pointer */ |
| beieeeftoa80, /* long double precision floating point */ |
| |
| powerdas, /* dissembler */ |
| powerdas, /* plan9-format disassembler */ |
| 0, /* commercial disassembler */ |
| powerhexinst, /* print instruction */ |
| powerinstlen, /* instruction size calculation */ |
| }; |
| |