diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/qi |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/qi')
-rwxr-xr-x | sys/src/cmd/qi/bpt.c | 129 | ||||
-rwxr-xr-x | sys/src/cmd/qi/branch.c | 272 | ||||
-rwxr-xr-x | sys/src/cmd/qi/cmd.c | 644 | ||||
-rwxr-xr-x | sys/src/cmd/qi/float.c | 741 | ||||
-rwxr-xr-x | sys/src/cmd/qi/icache.c | 18 | ||||
-rwxr-xr-x | sys/src/cmd/qi/iu.c | 2029 | ||||
-rwxr-xr-x | sys/src/cmd/qi/mem.c | 271 | ||||
-rwxr-xr-x | sys/src/cmd/qi/mkfile | 29 | ||||
-rwxr-xr-x | sys/src/cmd/qi/power.h | 285 | ||||
-rwxr-xr-x | sys/src/cmd/qi/qi.c | 423 | ||||
-rwxr-xr-x | sys/src/cmd/qi/run.c | 205 | ||||
-rwxr-xr-x | sys/src/cmd/qi/stats.c | 209 | ||||
-rwxr-xr-x | sys/src/cmd/qi/symbols.c | 97 | ||||
-rwxr-xr-x | sys/src/cmd/qi/syscall.c | 740 | ||||
-rwxr-xr-x | sys/src/cmd/qi/timing | 27 |
15 files changed, 6119 insertions, 0 deletions
diff --git a/sys/src/cmd/qi/bpt.c b/sys/src/cmd/qi/bpt.c new file mode 100755 index 000000000..0e9d693c6 --- /dev/null +++ b/sys/src/cmd/qi/bpt.c @@ -0,0 +1,129 @@ +#include <u.h> +#include <libc.h> +#include <ctype.h> +#include <bio.h> +#include <mach.h> +#define Extern extern +#include "power.h" + +void +dobplist(void) +{ + Breakpoint *b; + char buf[512]; + + for(b = bplist; b; b = b->next) { + switch(b->type) { + case Instruction: + Bprint(bioout, "0x%lux,%d:b %d done, at ", b->addr, b->count, b->done); + symoff(buf, sizeof(buf), b->addr, CTEXT); + Bprint(bioout, "%s", buf); + break; + + case Access: + Bprint(bioout, "0x%lux,%d:ba %d done, at ", b->addr, b->count, b->done); + symoff(buf, sizeof(buf), b->addr, CDATA); + Bprint(bioout, "%s", buf); + break; + + case Read: + Bprint(bioout, "0x%lux,%d:br %d done, at ", b->addr, b->count, b->done); + symoff(buf, sizeof(buf), b->addr, CDATA); + Bprint(bioout, "%s", buf); + break; + + case Write: + Bprint(bioout, "0x%lux,%d:bw %d done, at ", b->addr, b->count, b->done); + symoff(buf, sizeof(buf), b->addr, CDATA); + Bprint(bioout, "%s", buf); + break; + + case Equal: + Bprint(bioout, "0x%lux,%d:be at ", b->addr, b->count); + symoff(buf, sizeof(buf), b->addr, CDATA); + Bprint(bioout, "%s", buf); + break; + } + Bprint(bioout, "\n"); + } +} + +void +breakpoint(char *addr, char *cp) +{ + Breakpoint *b; + int type; + + cp = nextc(cp); + type = Instruction; + switch(*cp) { + case 'r': + membpt++; + type = Read; + break; + case 'a': + membpt++; + type = Access; + break; + case 'w': + membpt++; + type = Write; + break; + case 'e': + membpt++; + type = Equal; + break; + } + b = emalloc(sizeof(Breakpoint)); + b->addr = expr(addr); + b->type = type; + b->count = cmdcount; + b->done = cmdcount; + + b->next = bplist; + bplist = b; +} + +void +delbpt(char *addr) +{ + Breakpoint *b, **l; + ulong baddr; + + baddr = expr(addr); + l = &bplist; + for(b = *l; b; b = b->next) { + if(b->addr == baddr) { + if(b->type != Instruction) + membpt++; + *l = b->next; + free(b); + return; + } + l = &b->next; + } + + Bprint(bioout, "no breakpoint\n"); +} + +void +brkchk(ulong addr, int type) +{ + Breakpoint *b; + + for(b = bplist; b; b = b->next) { + if(b->addr == addr && (b->type&type)) { + if(b->type == Equal && getmem_4(addr) == b->count) { + count = 1; + atbpt = 1; + return; + } + if(--b->done == 0) { + b->done = b->count; + count = 1; + atbpt = 1; + return; + } + } + } +} diff --git a/sys/src/cmd/qi/branch.c b/sys/src/cmd/qi/branch.c new file mode 100755 index 000000000..a7a04d6aa --- /dev/null +++ b/sys/src/cmd/qi/branch.c @@ -0,0 +1,272 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <mach.h> +#define Extern extern +#include "power.h" + +void mcrf(ulong); +void bclr(ulong); +void crop(ulong); +void bcctr(ulong); +void call(ulong); +void ret(ulong); +void isync(ulong); + +Inst op19[] = { +[0] {mcrf, "mcrf", Ibranch}, +[16] {bclr, "bclr", Ibranch}, +[33] {crop, "crnor", Ibranch}, +[15] {0, "rfi", Ibranch}, +[129] {crop, "crandc", Ibranch}, +[150] {isync, "isync", Ibranch}, +[193] {crop, "crxor", Ibranch}, +[225] {crop, "crnand", Ibranch}, +[257] {crop, "crand", Ibranch}, +[289] {crop, "creqv", Ibranch}, +[417] {crop, "crorc", Ibranch}, +[449] {crop, "cror", Ibranch}, +[528] {bcctr, "bcctr", Ibranch}, + {0, 0, 0} +}; + +Inset ops19 = {op19, nelem(op19)-1}; + +static char * +boname(int bo) +{ + static char buf[8]; + + switch(bo>>1){ + case 0: return "dnzf"; + case 1: return "dzf"; + case 2: return "f"; + case 4: return "dnzt"; + case 5: return "dzt"; + case 6: return "t"; + case 8: return "dnz"; + case 9: return "dz"; + case 10: return "a"; + default: + sprint(buf, "%d?", bo); + return buf; + } +} + +static char * +cname(int bo, int bi) +{ + int f; + char *p; + static char buf[20]; + static char *f0[] = {"lt", "gt", "eq", "so/un"}; + + if(bo == 0x14){ /* branch always */ + sprint(buf,"%d", bi); + return buf; + } + for(f = 0; bi >= 4; bi -= 4) + f++; + p = buf; + p += sprint(buf, "%d[", bi); + if(f) + p += sprint(buf, "cr%d+", f); + strcpy(p, f0[bi&3]); + strcat(p, "]"); + return buf; +} + +static int +condok(ulong ir, int ctr) +{ + int bo, bi, xx; + + getbobi(ir); + if(xx) + undef(ir); + if((bo & 0x4) == 0) { + if(!ctr) + undef(ir); + reg.ctr--; + } + if(bo & 0x4 || (reg.ctr!=0)^((bo>>1)&1)) { + if(bo & 0x10 || (((reg.cr & bits[bi])!=0)==((bo>>3)&1))) + return 1; + } + return 0; +} + +static void +dobranch(ulong ir, ulong *r, int ctr) +{ + int bo, bi, xx; + ulong nia; + + getbobi(ir); + USED(xx); + if(condok(ir, ctr)) { + ci->taken++; + nia = *r & ~3; + if(bo & 4) /* assume counting branches aren't returns */ + ret(nia); + } else + nia = reg.pc + 4; + if(trace) + itrace("%s%s\t%s,%s,#%.8lux", ci->name, ir&1? "l": "", boname(bo), cname(bo, bi), nia); + if(ir & 1) { + call(nia); + reg.lr = reg.pc + 4; + } + reg.pc = nia-4; + /* branch delays? */ +} + +void +bcctr(ulong ir) +{ + dobranch(ir, ®.ctr, 1); +} + +void +bclr(ulong ir) +{ + dobranch(ir, ®.lr, 0); +} + +void +bcx(ulong ir) +{ + int bo, bi, xx; + ulong ea; + long imm; + static char *opc[] = {"bc", "bcl", "bca", "bcla"}; + + getbobi(ir); + USED(xx); + imm = ir & 0xFFFC; + if(ir & 0x08000) + imm |= 0xFFFF0000; + if((ir & 2) == 0) { /* not absolute address */ + ea = reg.pc + imm; + if(trace) + itrace("%s\t%s,%s,.%s%ld\tea = #%.8lux", opc[ir&3], boname(bo), cname(bo, bi), imm<0?"":"+", imm, ea); + } else { + ea = imm; + if(trace) + itrace("%s\t%s,%s,#%.8lux", opc[ir&3], boname(bo), cname(bo, bi), ea); + } + if(condok(ir&0xFFFF0000, 1)) + ci->taken++; + else + ea = reg.pc + 4; + if(ir & 1) { + call(ea); + reg.lr = reg.pc+4; + } + reg.pc = ea-4; + /* branch delay? */ +} + +void +crop(ulong ir) +{ + int rd, ra, rb, d; + + getarrr(ir); + if(trace) + itrace("%s\tcrb%d,crb%d,crb%d", ci->name, rd, ra, rb); + ra = (reg.cr & bits[ra]) != 0; + rb = (reg.cr & bits[rb]) != 0; + d = 0; + switch(getxo(ir)) { + case 257: d = ra & rb; break; + case 129: d = ra & !rb; break; + case 289: d = ra == rb; break; + case 225: d = !(ra & rb); break; + case 33: d = !(ra | rb); break; + case 449: d = ra | rb; break; + case 417: d = ra | !rb; break; + case 193: d = ra ^ rb; break; + default: undef(ir); break; + } + if(d) + reg.cr |= bits[rd]; +} + +void +mcrf(ulong ir) +{ + int rd, ra, rb; + + getarrr(ir); + if(ir & 1 || rd & 3 || ra & 3 || rb) + undef(ir); + ra >>= 2; + rd >>= 2; + reg.cr = (reg.cr & ~mkCR(rd, 0xF)) | mkCR(rd, getCR(ra, reg.cr)); + if(trace) + itrace("mcrf\tcrf%d,crf%d", rd, ra); +} + +void +call(ulong npc) +{ + Symbol s; + + if(calltree) { + findsym(npc, CTEXT, &s); + Bprint(bioout, "%8lux %s(", reg.pc, s.name); + printparams(&s, reg.r[1]); + Bprint(bioout, "from "); + printsource(reg.pc); + Bputc(bioout, '\n'); + } +} + +void +ret(ulong npc) +{ + Symbol s; + + if(calltree) { + findsym(npc, CTEXT, &s); + Bprint(bioout, "%8lux return to #%lux %s r3=#%lux (%ld)\n", + reg.pc, npc, s.name, reg.r[3], reg.r[3]); + } +} + +void +bx(ulong ir) +{ + ulong ea; + long imm; + static char *opc[] = {"b", "bl", "ba", "bla"}; + + imm = ir & 0x03FFFFFC; + if(ir & 0x02000000) + imm |= 0xFC000000; + if((ir & 2) == 0) { /* not absolute address */ + ea = reg.pc + imm; + if(trace) + itrace("%s\t.%s%ld\tea = #%.8lux", opc[ir&3], imm<0?"":"+", imm, ea); + } else { + ea = imm; + if(trace) + itrace("%s\t#%.8lux", opc[ir&3], ea); + } + ci->taken++; + if(ir & 1) { + call(ea); + reg.lr = reg.pc+4; + } + reg.pc = ea-4; + /* branch delay? */ +} + +void +isync(ulong ir) +{ + USED(ir); + if(trace) + itrace("isync"); +} diff --git a/sys/src/cmd/qi/cmd.c b/sys/src/cmd/qi/cmd.c new file mode 100755 index 000000000..02fc422e7 --- /dev/null +++ b/sys/src/cmd/qi/cmd.c @@ -0,0 +1,644 @@ +#include <u.h> +#include <libc.h> +#include <ctype.h> +#include <bio.h> +#include <mach.h> +#define Extern extern +#include "power.h" + +char buf[128], lastcmd[128]; +char fmt = 'X'; +int width = 60; +int inc; + +ulong expr(char*); +ulong expr1(char*); +char* term(char*, ulong*); + +char * +nextc(char *p) +{ + while(*p && (*p == ' ' || *p == '\t') && *p != '\n') + p++; + + if(*p == '\n') + *p = '\0'; + + return p; +} + +char * +numsym(char *addr, ulong *val) +{ + char tsym[128], *t; + static char *delim = "`'<>/\\@*|-~+-/=?\n"; + Symbol s; + char c; + + t = tsym; + while(c = *addr) { + if(strchr(delim, c)) + break; + *t++ = c; + addr++; + } + t[0] = '\0'; + + if(strcmp(tsym, ".") == 0) { + *val = dot; + return addr; + } + + if(lookup(0, tsym, &s)) + *val = s.value; + else { + if(tsym[0] == '#') + *val = strtoul(tsym+1, 0, 16); + else + *val = strtoul(tsym, 0, 0); + } + return addr; +} + +ulong +expr(char *addr) +{ + ulong t, t2; + char op; + + if(*addr == '\0') + return dot; + + addr = numsym(addr, &t); + + if(*addr == '\0') + return t; + + addr = nextc(addr); + op = *addr++; + numsym(addr, &t2); + switch(op) { + default: + Bprint(bioout, "expr syntax\n"); + return 0; + case '+': + t += t2; + break; + case '-': + t -= t2; + break; + case '%': + t /= t2; + break; + case '&': + t &= t2; + break; + case '|': + t |= t2; + break; + } + + return t; +} + +int +buildargv(char *str, char **args, int max) +{ + int na = 0; + + while (na < max) { + while((*str == ' ' || *str == '\t' || *str == '\n') && *str != '\0') + str++; + + if(*str == '\0') + return na; + + args[na++] = str; + while(!(*str == ' ' || *str == '\t'|| *str == '\n') && *str != '\0') + str++; + + if(*str == '\n') + *str = '\0'; + + if(*str == '\0') + break; + + *str++ = '\0'; + } + return na; +} + +void +colon(char *addr, char *cp) +{ + int argc; + char *argv[100]; + char tbuf[512]; + + cp = nextc(cp); + switch(*cp) { + default: + Bprint(bioout, "?\n"); + return; + case 'b': + breakpoint(addr, cp+1); + return; + + case 'd': + delbpt(addr); + return; + + /* These fall through to print the stopped address */ + case 'r': + reset(); + argc = buildargv(cp+1, argv, 100); + initstk(argc, argv); + count = 0; + atbpt = 0; + run(); + break; + case 'c': + count = 0; + atbpt = 0; + run(); + break; + case 's': + cp = nextc(cp+1); + count = 0; + if(*cp) + count = strtoul(cp, 0, 0); + if(count == 0) + count = 1; + atbpt = 0; + run(); + break; + } + + dot = reg.pc; + Bprint(bioout, "%s at #%lux ", atbpt ? "breakpoint" : "stopped", dot); + symoff(tbuf, sizeof(tbuf), dot, CTEXT); + Bprint(bioout, tbuf); + if(fmt == 'z') + printsource(dot); + + Bprint(bioout, "\n"); +} + + +void +dollar(char *cp) +{ + cp = nextc(cp); + switch(*cp) { + default: + Bprint(bioout, "?\n"); + break; + + case 'c': + case 'C': + stktrace(*cp); + break; + + case 'b': + dobplist(); + break; + + case 'r': + dumpreg(); + break; + + case 'R': + dumpreg(); + /* fall through */ + + case 'f': + dumpfreg(); + break; + + case 'F': + dumpdreg(); + break; + + case 'q': + exits(0); + break; + + case 'Q': + isum(); + segsum(); + break; + + case 't': + cp++; + switch(*cp) { + default: + Bprint(bioout, ":t[0sic]\n"); + break; + case '\0': + trace = 1; + break; + case '0': + trace = 0; + sysdbg = 0; + calltree = 0; + break; + case 's': + sysdbg = 1; + break; + case 'i': + trace = 1; + break; + case 'c': + calltree = 1; + break; + } + break; + + case 'i': + cp++; + switch(*cp) { + default: + Bprint(bioout, "$i[isa]\n"); + break; + case 'i': + isum(); + break; + case 's': + segsum(); + break; + case 'a': + isum(); + segsum(); + iprofile(); + break; + case 'p': + iprofile(); + break; + } + } +} + +int +pfmt(char fmt, int mem, ulong val) +{ + int c, i; + Symbol s; + char *p, ch, str[1024]; + + c = 0; + switch(fmt) { + default: + Bprint(bioout, "bad modifier\n"); + return 0; + case 'o': + c = Bprint(bioout, "%-4lo ", mem ? (ushort)getmem_2(dot) : val); + inc = 2; + break; + + case 'O': + c = Bprint(bioout, "%-8lo ", mem ? getmem_4(dot) : val); + inc = 4; + break; + + case 'q': + c = Bprint(bioout, "%-4lo ", mem ? (short)getmem_2(dot) : val); + inc = 2; + break; + + case 'Q': + c = Bprint(bioout, "%-8lo ", mem ? (long)getmem_4(dot) : val); + inc = 4; + break; + + case 'd': + c = Bprint(bioout, "%-5ld ", mem ? (short)getmem_2(dot) : val); + inc = 2; + break; + + + case 'D': + c = Bprint(bioout, "%-8ld ", mem ? (long)getmem_4(dot) : val); + inc = 4; + break; + + case 'x': + c = Bprint(bioout, "#%-4lux ", mem ? (long)getmem_2(dot) : val); + inc = 2; + break; + + case 'X': + c = Bprint(bioout, "#%-8lux ", mem ? (long)getmem_4(dot) : val); + inc = 4; + break; + + case 'u': + c = Bprint(bioout, "%-5ld ", mem ? (ushort)getmem_2(dot) : val); + inc = 2; + break; + + case 'U': + c = Bprint(bioout, "%-8ld ", mem ? (ulong)getmem_4(dot) : val); + inc = 4; + break; + + case 'b': + c = Bprint(bioout, "%-3ld ", mem ? getmem_b(dot) : val); + inc = 1; + break; + + case 'c': + c = Bprint(bioout, "%c ", (int)(mem ? getmem_b(dot) : val)); + inc = 1; + break; + + case 'C': + ch = mem ? getmem_b(dot) : val; + if(isprint(ch)) + c = Bprint(bioout, "%c ", ch); + else + c = Bprint(bioout, "\\x%.2x ", ch); + inc = 1; + break; + + case 's': + i = 0; + while(ch = getmem_b(dot+i)) + str[i++] = ch; + str[i] = '\0'; + dot += i; + c = Bprint(bioout, "%s", str); + inc = 0; + break; + + case 'S': + i = 0; + while(ch = getmem_b(dot+i)) + str[i++] = ch; + str[i] = '\0'; + dot += i; + for(p = str; *p; p++) + if(isprint(*p)) + c += Bprint(bioout, "%c", *p); + else + c += Bprint(bioout, "\\x%.2ux", *p); + inc = 0; + break; + + case 'Y': + p = ctime(mem ? getmem_b(dot) : val); + p[30] = '\0'; + c = Bprint(bioout, "%s", p); + inc = 4; + break; + + case 'a': + symoff(str, sizeof(str), dot, CTEXT); + Bprint(bioout, "%s", str); + inc = 0; + break; + + case 'e': + for (i = 0; globalsym(&s, i); i++) + Bprint(bioout, "%-15s #%lux\n", s.name, getmem_4(s.value)); + inc = 0; + break; + + case 'I': + case 'i': + inc = machdata->das(symmap, dot, fmt, str, sizeof(str)); + if (inc < 0) { + Bprint(bioout, "qi: %r\n"); + return 0; + } + c = Bprint(bioout, "\t%s", str); + break; + + case 'n': + c = width+1; + inc = 0; + break; + + case '-': + c = 0; + inc = -1; + break; + + case '+': + c = 0; + inc = 1; + break; + + case '^': + c = 0; + if(inc > 0) + inc = -inc; + break; + + case 'z': + if (findsym(dot, CTEXT, &s)) + Bprint(bioout, " %s() ", s.name); + printsource(dot); + inc = 0; + break; + } + return c; +} + +void +eval(char *addr, char *p) +{ + ulong val; + + val = expr(addr); + p = nextc(p); + if(*p == '\0') { + p[0] = fmt; + p[1] = '\0'; + } + pfmt(*p, 0, val); + Bprint(bioout, "\n"); +} + +void +quesie(char *p) +{ + int c, count, i; + char tbuf[512]; + + c = 0; + symoff(tbuf, sizeof(tbuf), dot, CTEXT); + Bprint(bioout, "%s?\t", tbuf); + + while(*p) { + p = nextc(p); + if(*p == '"') { + for(p++; *p && *p != '"'; p++) { + Bputc(bioout, *p); + c++; + } + if(*p) + p++; + continue; + } + count = 0; + while(*p >= '0' && *p <= '9') + count = count*10 + (*p++ - '0'); + if(count == 0) + count = 1; + p = nextc(p); + if(*p == '\0') { + p[0] = fmt; + p[1] = '\0'; + } + for(i = 0; i < count; i++) { + c += pfmt(*p, 1, 0); + dot += inc; + if(c > width) { + Bprint(bioout, "\n"); + symoff(tbuf, sizeof(tbuf), dot, CTEXT); + Bprint(bioout, "%s?\t", tbuf); + c = 0; + } + } + fmt = *p++; + p = nextc(p); + } + Bprint(bioout, "\n"); +} + +void +catcher(void *a, char *msg) +{ + USED(a); + if(strcmp(msg, "interrupt") != 0) + noted(NDFLT); + + count = 1; + print("qi\n"); + noted(NCONT); +} + +void +setreg(char *addr, char *cp) +{ + int rn; + + dot = expr(addr); + cp = nextc(cp); + if(strcmp(cp, "pc") == 0) { + reg.pc = dot; + return; + } + if(strcmp(cp, "sp") == 0) { + reg.r[1] = dot; + return; + } + if(strcmp(cp, "lr") == 0) { + reg.lr = dot; + return; + } + if(strcmp(cp, "ctr") == 0) { + reg.ctr = dot; + return; + } + if(strcmp(cp, "fpscr") == 0) { + reg.fpscr = dot; + return; + } + if(strcmp(cp, "xer") == 0) { + reg.xer = dot; + return; + } + if(strcmp(cp, "cr") == 0) { + reg.cr = dot; + return; + } + if(*cp++ == 'r') { + rn = strtoul(cp, 0, 10); + if(rn > 0 && rn < 32) { + reg.r[rn] = dot; + return; + } + } + Bprint(bioout, "bad register\n"); +} + +void +cmd(void) +{ + char *p, *a, *cp, *gotint; + char addr[128]; + static char *cmdlet = ":$?/=>"; + int n, i; + + notify(catcher); + + dot = reg.pc; + setjmp(errjmp); + + for(;;) { + Bflush(bioout); + p = buf; + n = 0; + for(;;) { + i = Bgetc(bin); + if(i < 0) + exits(0); + *p++ = i; + n++; + if(i == '\n') + break; + } + + if(buf[0] == '\n') + strcpy(buf, lastcmd); + else { + buf[n-1] = '\0'; + strcpy(lastcmd, buf); + } + p = buf; + a = addr; + + for(;;) { + p = nextc(p); + if(*p == 0 || strchr(cmdlet, *p)) + break; + *a++ = *p++; + } + + *a = '\0'; + cmdcount = 1; + cp = strchr(addr, ','); + if(cp != 0) { + if(cp[1] == '#') + cmdcount = strtoul(cp+2, &gotint, 16); + else + cmdcount = strtoul(cp+1, &gotint, 0); + *cp = '\0'; + } + + switch(*p) { + case '$': + dollar(p+1); + break; + case ':': + colon(addr, p+1); + break; + case '/': + case '?': + dot = expr(addr); + for(i = 0; i < cmdcount; i++) + quesie(p+1); + break; + case '=': + eval(addr, p+1); + break; + case '>': + setreg(addr, p+1); + break; + default: + Bprint(bioout, "?\n"); + break; + } + } +} diff --git a/sys/src/cmd/qi/float.c b/sys/src/cmd/qi/float.c new file mode 100755 index 000000000..2602adc33 --- /dev/null +++ b/sys/src/cmd/qi/float.c @@ -0,0 +1,741 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <mach.h> +#define Extern extern +#include "power.h" + +ulong setfpscr(void); +void setfpcc(double); +void farith(ulong); +void farith2(ulong); +void fariths(ulong); +void fcmp(ulong); +void mtfsb1(ulong); +void mcrfs(ulong); +void mtfsb0(ulong); +void mtfsf(ulong); +void mtfsfi(ulong); +void mffs(ulong); +void mtfsf(ulong); + +Inst op59[] = { +[18] {fariths, "fdivs", Ifloat}, +[20] {fariths, "fsubs", Ifloat}, +[21] {fariths, "fadds", Ifloat}, +[22] {unimp, "fsqrts", Ifloat}, +[24] {unimp, "fres", Ifloat}, +[25] {fariths, "fmuls", Ifloat}, +[28] {fariths, "fmsubs", Ifloat}, +[29] {fariths, "fmadds", Ifloat}, +[30] {fariths, "fnmsubs", Ifloat}, +[31] {fariths, "fnmadds", Ifloat}, +}; + +Inset ops59 = {op59, nelem(op59)}; + +Inst op63a[] = { +[12] {farith, "frsp", Ifloat}, +[14] {farith, "fctiw", Ifloat}, +[15] {farith, "fctiwz", Ifloat}, +[18] {farith, "fdiv", Ifloat}, +[20] {farith, "fsub", Ifloat}, +[21] {farith, "fadd", Ifloat}, +[22] {unimp, "frsqrt", Ifloat}, +[23] {unimp, "fsel", Ifloat}, +[25] {farith, "fmul", Ifloat}, +[26] {unimp, "frsqrte", Ifloat}, +[28] {farith, "fmsub", Ifloat}, +[29] {farith, "fmadd", Ifloat}, +[30] {farith, "fnmsub", Ifloat}, +[31] {farith, "fnmadd", Ifloat}, +}; + +Inset ops63a= {op63a, nelem(op63a)}; + +Inst op63b[] = { +[0] {fcmp, "fcmpu", Ifloat}, +[32] {fcmp, "fcmpo", Ifloat}, +[38] {mtfsb1, "mtfsb1", Ifloat}, +[40] {farith2, "fneg", Ifloat}, +[64] {mcrfs, "mcrfs", Ifloat}, +[70] {mtfsb0, "mtfsb0", Ifloat}, +[72] {farith2, "fmr", Ifloat}, +[134] {mtfsfi, "mtfsfi", Ifloat}, +[136] {farith2, "fnabs", Ifloat}, +[264] {farith2, "fabs", Ifloat}, +[583] {mffs, "mffs", Ifloat}, +[711] {mtfsf, "mtfsf", Ifloat}, +}; + +Inset ops63b = {op63b, nelem(op63b)}; + +void +fpreginit(void) +{ + int i; + + /* Normally initialised by the kernel */ + reg.fd[27] = 4503601774854144.0; + reg.fd[29] = 0.5; + reg.fd[28] = 0.0; + reg.fd[30] = 1.0; + reg.fd[31] = 2.0; + for(i = 0; i < 27; i++) + reg.fd[i] = reg.fd[28]; +} + +static double +v2fp(uvlong v) +{ + FPdbleword f; + + f.hi = v>>32; + f.lo = v; + return f.x; +} + +static uvlong +fp2v(double d) +{ + FPdbleword f; + + f.x = d; + return ((uvlong)f.hi<<32) | f.lo; +} + +void +lfs(ulong ir) +{ + ulong ea; + int imm, ra, rd, upd; + union { + ulong i; + float f; + } u; + + getairr(ir); + ea = imm; + upd = (ir&(1L<<26))!=0; + if(ra) { + ea += reg.r[ra]; + if(upd) + reg.r[ra] = ea; + } else { + if(upd) + undef(ir); + } + if(trace) + itrace("%s\tf%d,%ld(r%d) ea=%lux", ci->name, rd, imm, ra, ea); + + u.i = getmem_w(ea); + reg.fd[rd] = u.f; +} + +void +lfsx(ulong ir) +{ + ulong ea; + int rd, ra, rb, upd; + union { + ulong i; + float f; + } u; + + getarrr(ir); + ea = reg.r[rb]; + upd = ((ir>>1)&0x3FF)==567; + if(ra){ + ea += reg.r[ra]; + if(upd) + reg.r[ra] = ea; + if(trace) + itrace("%s\tf%d,(r%d+r%d) ea=%lux", ci->name, rd, ra, rb, ea); + } else { + if(upd) + undef(ir); + if(trace) + itrace("%s\tf%d,(r%d) ea=%lux", ci->name, rd, rb, ea); + } + + u.i = getmem_w(ea); + reg.fd[rd] = u.f; +} + +void +lfd(ulong ir) +{ + ulong ea; + int imm, ra, rd, upd; + + getairr(ir); + ea = imm; + upd = (ir&(1L<<26))!=0; + if(ra) { + ea += reg.r[ra]; + if(upd) + reg.r[ra] = ea; + } else { + if(upd) + undef(ir); + } + if(trace) + itrace("%s\tf%d,%ld(r%d) ea=%lux", ci->name, rd, imm, ra, ea); + + reg.fd[rd] = v2fp(getmem_v(ea)); +} + +void +lfdx(ulong ir) +{ + ulong ea; + int rd, ra, rb, upd; + + getarrr(ir); + ea = reg.r[rb]; + upd = ((ir>>1)&0x3FF)==631; + if(ra){ + ea += reg.r[ra]; + if(upd) + reg.r[ra] = ea; + if(trace) + itrace("%s\tf%d,(r%d+r%d) ea=%lux", ci->name, rd, ra, rb, ea); + } else { + if(upd) + undef(ir); + if(trace) + itrace("%s\tf%d,(r%d) ea=%lux", ci->name, rd, rb, ea); + } + + reg.fd[rd] = v2fp(getmem_v(ea)); +} + +void +stfs(ulong ir) +{ + ulong ea; + int imm, ra, rd, upd; + union { + float f; + ulong w; + } u; + + getairr(ir); + ea = imm; + upd = (ir&(1L<<26))!=0; + if(ra) { + ea += reg.r[ra]; + if(upd) + reg.r[ra] = ea; + } else { + if(upd) + undef(ir); + } + if(trace) + itrace("%s\tf%d,%ld(r%d) %lux=%g", + ci->name, rd, imm, ra, ea, reg.fd[rd]); + u.f = reg.fd[rd]; /* BUG: actual PPC conversion is more subtle than this */ + putmem_w(ea, u.w); +} + +void +stfsx(ulong ir) +{ + ulong ea; + int rd, ra, rb, upd; + union { + float f; + ulong w; + } u; + + getarrr(ir); + ea = reg.r[rb]; + upd = getxo(ir)==695; + if(ra){ + ea += reg.r[ra]; + if(upd) + reg.r[ra] = ea; + if(trace) + itrace("%s\tf%d,(r%d+r%d) %lux=%g", ci->name, rd, ra, rb, ea, (float)reg.fd[rd]); + } else { + if(upd) + undef(ir); + if(trace) + itrace("%s\tf%d,(r%d) %lux=%g", ci->name, rd, rb, ea, (float)reg.fd[rd]); + } + + u.f = reg.fd[rd]; /* BUG: actual PPC conversion is more subtle than this */ + putmem_w(ea, u.w); +} + +void +stfd(ulong ir) +{ + ulong ea; + int imm, ra, rd, upd; + + getairr(ir); + ea = imm; + upd = (ir&(1L<<26))!=0; + if(ra) { + ea += reg.r[ra]; + if(upd) + reg.r[ra] = ea; + } else { + if(upd) + undef(ir); + } + if(trace) + itrace("%s\tf%d,%ld(r%d) %lux=%g", + ci->name, rd, imm, ra, ea, reg.fd[rd]); + + putmem_v(ea, fp2v(reg.fd[rd])); +} + +void +stfdx(ulong ir) +{ + ulong ea; + int rd, ra, rb, upd; + + getarrr(ir); + ea = reg.r[rb]; + upd = ((ir>>1)&0x3FF)==759; + if(ra){ + ea += reg.r[ra]; + if(upd) + reg.r[ra] = ea; + if(trace) + itrace("%s\tf%d,(r%d+r%d) %lux=%g", ci->name, rd, ra, rb, ea, reg.fd[rd]); + } else { + if(upd) + undef(ir); + if(trace) + itrace("%s\tf%d,(r%d) %lux=%g", ci->name, rd, rb, ea, reg.fd[rd]); + } + + putmem_v(ea, fp2v(reg.fd[rd])); +} + +void +mcrfs(ulong ir) +{ + ulong rd, ra, rb; + static ulong fpscr0[] ={ + FPS_FX|FPS_OX, + FPS_UX|FPS_ZX|FPS_XX|FPS_VXSNAN, + FPS_VXISI|FPS_VXIDI|FPS_VXZDZ|FPS_VXIMZ, + FPS_VXVC, + 0, + FPS_VXCVI, + }; + + getarrr(ir); + if(rb || ra&3 || rd&3) + undef(ir); + ra >>= 2; + rd >>= 2; + reg.cr = (reg.cr & ~mkCR(rd, 0xF)) | mkCR(rd, getCR(ra, reg.fpscr)); + reg.fpscr &= ~fpscr0[ra]; + if(trace) + itrace("mcrfs\tcrf%d,crf%d\n", rd, ra); +} + +void +mffs(ulong ir) +{ + int rd, ra, rb; + FPdbleword d; + + getarrr(ir); + if(ra || rb) + undef(ir); + d.hi = 0xFFF80000UL; + d.lo = reg.fpscr; + reg.fd[rd] = d.x; + /* it's anyone's guess how CR1 should be set when ir&1 */ + reg.cr &= ~mkCR(1, 0xE); /* leave SO, reset others */ + if(trace) + itrace("mffs%s\tfr%d\n", ir&1?".":"", rd); +} + +void +mtfsb1(ulong ir) +{ + int rd, ra, rb; + + getarrr(ir); + if(ra || rb) + undef(ir); + reg.fpscr |= (1L << (31-rd)); + /* BUG: should set summary bits */ + if(ir & 1) + reg.cr &= ~mkCR(1, 0xE); /* BUG: manual unclear: leave SO, reset others? */ + if(trace) + itrace("mtfsb1%s\tfr%d\n", ir&1?".":"", rd); +} + +void +mtfsb0(ulong ir) +{ + int rd, ra, rb; + + getarrr(ir); + if(ra || rb) + undef(ir); + reg.fpscr &= ~(1L << (31-rd)); + if(ir & 1) + reg.cr &= ~mkCR(1, 0xE); /* BUG: manual unclear: leave SO, reset others? */ + if(trace) + itrace("mtfsb0%s\tfr%d\n", ir&1?".":"", rd); +} + +void +mtfsf(ulong ir) +{ + int fm, rb, i; + FPdbleword d; + ulong v; + + if(ir & ((1L << 25)|(1L << 16))) + undef(ir); + rb = (ir >> 11) & 0x1F; + fm = (ir >> 17) & 0xFF; + d.x = reg.fd[rb]; + v = d.lo; + for(i=0; i<8; i++) + if(fm & (1 << (7-i))) + reg.fpscr = (reg.fpscr & ~mkCR(i, 0xF)) | mkCR(i, getCR(i, v)); + /* BUG: should set FEX and VX `according to the usual rule' */ + if(ir & 1) + reg.cr &= ~mkCR(1, 0xE); /* BUG: manual unclear: leave SO, reset others? */ + if(trace) + itrace("mtfsf%s\t#%.2x,fr%d", ir&1?".":"", fm, rb); +} + +void +mtfsfi(ulong ir) +{ + int imm, rd; + + if(ir & ((0x7F << 16)|(1L << 11))) + undef(ir); + rd = (ir >> 23) & 0xF; + imm = (ir >> 12) & 0xF; + reg.fpscr = (reg.fpscr & ~mkCR(rd, 0xF)) | mkCR(rd, imm); + /* BUG: should set FEX and VX `according to the usual rule' */ + if(ir & 1) + reg.cr &= ~mkCR(1, 0xE); /* BUG: manual unclear: leave SO, reset others? */ + if(trace) + itrace("mtfsfi%s\tcrf%d,#%x", ir&1?".":"", rd, imm); +} + +void +fcmp(ulong ir) +{ + int fc, rd, ra, rb; + + getarrr(ir); + if(rd & 3) + undef(ir); + rd >>= 2; + SET(fc); + switch(getxo(ir)) { + default: + undef(ir); + case 0: + if(trace) + itrace("fcmpu\tcr%d,f%d,f%d", rd, ra, rb); + if(isNaN(reg.fd[ra]) || isNaN(reg.fd[rb])) { + fc = CRFU; + break; + } + if(reg.fd[ra] == reg.fd[rb]) { + fc = CREQ; + break; + } + if(reg.fd[ra] < reg.fd[rb]) { + fc = CRLT; + break; + } + if(reg.fd[ra] > reg.fd[rb]) { + fc = CRGT; + break; + } + print("qi: fcmp error\n"); + break; + case 32: + if(trace) + itrace("fcmpo\tcr%d,f%d,f%d", rd, ra, rb); + if(isNaN(reg.fd[ra]) || isNaN(reg.fd[rb])) { /* BUG: depends whether quiet or signalling ... */ + fc = CRFU; + Bprint(bioout, "invalid_fp_register\n"); + longjmp(errjmp, 0); + } + if(reg.fd[ra] == reg.fd[rb]) { + fc = CREQ; + break; + } + if(reg.fd[ra] < reg.fd[rb]) { + fc = CRLT; + break; + } + if(reg.fd[ra] > reg.fd[rb]) { + fc = CRGT; + break; + } + print("qi: fcmp error\n"); + break; + + } + fc >>= 28; + reg.cr = (reg.cr & ~mkCR(rd,~0)) | mkCR(rd, fc); + reg.fpscr = (reg.fpscr & ~0xF800) | (fc<<11); + /* BUG: update FX, VXSNAN, VXVC */ +} + +/* + * the farith functions probably don't produce the right results + * in the presence of NaNs, Infs, etc., esp. wrt exception handling, + */ +void +fariths(ulong ir) +{ + int rd, ra, rb, rc, fmt; + char *cc; + ulong fpscr; + + fmt = 0; + rc = (ir>>6)&0x1F; + getarrr(ir); + switch(getxo(ir)&0x1F) { /* partial XO decode */ + default: + undef(ir); + case 18: + if((float)reg.fd[rb] == 0.0) { + Bprint(bioout, "fp_exception ZX\n"); + reg.fpscr |= FPS_ZX | FPS_FX; + longjmp(errjmp, 0); + } + reg.fd[rd] = (float)(reg.fd[ra] / reg.fd[rb]); + break; + case 20: + reg.fd[rd] = (float)(reg.fd[ra] - reg.fd[rb]); + break; + case 21: + reg.fd[rd] = (float)(reg.fd[ra] + reg.fd[rb]); + break; + case 25: + reg.fd[rd] = (float)(reg.fd[ra] * reg.fd[rc]); + rb = rc; + break; + case 28: + reg.fd[rd] = (float)((reg.fd[ra] * reg.fd[rc]) - reg.fd[rb]); + fmt = 2; + break; + case 29: + reg.fd[rd] = (float)((reg.fd[ra] * reg.fd[rc]) + reg.fd[rb]); + fmt = 2; + break; + case 30: + reg.fd[rd] = (float)-((reg.fd[ra] * reg.fd[rc]) - reg.fd[rb]); + fmt = 2; + break; + case 31: + reg.fd[rd] = (float)-((reg.fd[ra] * reg.fd[rc]) + reg.fd[rb]); + fmt = 2; + break; + } + if(fmt==1 && ra) + undef(ir); + fpscr = setfpscr(); + setfpcc(reg.fd[rd]); + cc = ""; + if(ir & 1) { + cc = "."; + reg.cr = (reg.cr & ~mkCR(1, ~0)) | mkCR(1, (fpscr>>28)); + } + if(trace) { + switch(fmt) { + case 0: + itrace("%s%s\tfr%d,fr%d,fr%d", ci->name, cc, rd, ra, rb); + break; + case 1: + itrace("%s%s\tfr%d,fr%d", ci->name, cc, rd, rb); + break; + case 2: + itrace("%s%s\tfr%d,fr%d,fr%d,fr%d", ci->name, cc, rd, ra, rc, rb); + break; + } + } +} + +void +farith(ulong ir) +{ + vlong vl; + int rd, ra, rb, rc, fmt; + char *cc; + ulong fpscr; + int nocc; + double d; + + fmt = 0; + nocc = 0; + rc = (ir>>6)&0x1F; + getarrr(ir); + switch(getxo(ir)&0x1F) { /* partial XO decode */ + default: + undef(ir); + case 12: /* frsp */ + reg.fd[rd] = (float)reg.fd[rb]; + fmt = 1; + break; + case 14: /* fctiw */ /* BUG: ignores rounding mode */ + case 15: /* fctiwz */ + d = reg.fd[rb]; + if(d >= 0x7fffffff) + vl = 0x7fffffff; + else if(d < 0x80000000) + vl = 0x80000000; + else + vl = d; + reg.fd[rd] = v2fp(vl); + fmt = 1; + nocc = 1; + break; + case 18: + if(reg.fd[rb] == 0.0) { + Bprint(bioout, "fp_exception ZX\n"); + reg.fpscr |= FPS_ZX | FPS_FX; + longjmp(errjmp, 0); + } + reg.fd[rd] = reg.fd[ra] / reg.fd[rb]; + break; + case 20: + reg.fd[rd] = reg.fd[ra] - reg.fd[rb]; + break; + case 21: + reg.fd[rd] = reg.fd[ra] + reg.fd[rb]; + break; + case 25: + reg.fd[rd] = reg.fd[ra] * reg.fd[rc]; + rb = rc; + break; + case 28: + reg.fd[rd] = (reg.fd[ra] * reg.fd[rc]) - reg.fd[rb]; + fmt = 2; + break; + case 29: + reg.fd[rd] = (reg.fd[ra] * reg.fd[rc]) + reg.fd[rb]; + fmt = 2; + break; + case 30: + reg.fd[rd] = -((reg.fd[ra] * reg.fd[rc]) - reg.fd[rb]); + fmt = 2; + break; + case 31: + reg.fd[rd] = -((reg.fd[ra] * reg.fd[rc]) + reg.fd[rb]); + fmt = 2; + break; + } + if(fmt==1 && ra) + undef(ir); + fpscr = setfpscr(); + if(nocc == 0) + setfpcc(reg.fd[rd]); + cc = ""; + if(ir & 1) { + cc = "."; + reg.cr = (reg.cr & ~mkCR(1, ~0)) | mkCR(1, (fpscr>>28)); + } + if(trace) { + switch(fmt) { + case 0: + itrace("%s%s\tfr%d,fr%d,fr%d", ci->name, cc, rd, ra, rb); + break; + case 1: + itrace("%s%s\tfr%d,fr%d", ci->name, cc, rd, rb); + break; + case 2: + itrace("%s%s\tfr%d,fr%d,fr%d,fr%d", ci->name, cc, rd, ra, rc, rb); + break; + } + } +} + +void +farith2(ulong ir) +{ + int rd, ra, rb; + char *cc; + ulong fpscr; + + getarrr(ir); + switch(getxo(ir)) { /* full XO decode */ + default: + undef(ir); + case 40: + reg.fd[rd] = -reg.fd[rb]; + break; + case 72: + reg.fd[rd] = reg.fd[rb]; + break; + case 136: + reg.fd[rd] = -fabs(reg.fd[rb]); + break; + case 264: + reg.fd[rd] = fabs(reg.fd[rb]); + break; + } + if(ra) + undef(ir); + fpscr = setfpscr(); + setfpcc(reg.fd[rd]); + cc = ""; + if(ir & 1) { + cc = "."; + reg.cr = (reg.cr & ~mkCR(1, ~0)) | mkCR(1, (fpscr>>28)); + } + if(trace) + itrace("%s%s\tfr%d,fr%d", ci->name, cc, rd, rb); +} + +ulong +setfpscr(void) +{ + ulong fps, fpscr; + + fps = getfsr(); + fpscr = reg.fpscr; + if(fps & FPAOVFL) + fpscr |= FPS_OX; + if(fps & FPAINEX) + fpscr |= FPS_XX; + if(fps & FPAUNFL) + fpscr |= FPS_UX; + if(fps & FPAZDIV) + fpscr |= FPS_ZX; + if(fpscr != reg.fpscr) { + fpscr |= FPS_FX; + reg.fpscr = fpscr; + } + return fpscr; +} + +void +setfpcc(double r) +{ + int c; + + c = 0; + if(r == 0) + c |= 2; + else if(r < 0) + c |= 4; + else + c |= 8; + if(isNaN(r)) + c |= 1; + reg.fpscr = (reg.fpscr & ~0xF800) | (0<<15) | (c<<11); /* unsure about class bit */ +} diff --git a/sys/src/cmd/qi/icache.c b/sys/src/cmd/qi/icache.c new file mode 100755 index 000000000..311810e86 --- /dev/null +++ b/sys/src/cmd/qi/icache.c @@ -0,0 +1,18 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <mach.h> +#define Extern extern +#include "power.h" + +void +icacheinit(void) +{ +} + +void +updateicache(ulong addr) +{ + USED(addr); +} + diff --git a/sys/src/cmd/qi/iu.c b/sys/src/cmd/qi/iu.c new file mode 100755 index 000000000..4204d1a64 --- /dev/null +++ b/sys/src/cmd/qi/iu.c @@ -0,0 +1,2029 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <mach.h> +#define Extern extern +#include "power.h" + +void add(ulong); +void addc(ulong); +void adde(ulong); +void addme(ulong); +void addze(ulong); +void and(ulong); +void andc(ulong); +void cmp(ulong); +void cmpl(ulong); +void cntlzw(ulong); +void dcbf(ulong); +void dcbi(ulong); +void dcbst(ulong); +void dcbt(ulong); +void dcbtst(ulong); +void dcbz(ulong); +void divw(ulong); +void divwu(ulong); +void eciwx(ulong); +void ecowx(ulong); +void eieio(ulong); +void eqv(ulong); +void extsb(ulong); +void extsh(ulong); +void icbi(ulong); +void lbzx(ulong); +void lfdx(ulong); +void lfsx(ulong); +void lhax(ulong); +void lhbrx(ulong); +void lhzx(ulong); +void lswi(ulong); +void lswx(ulong); +void lwarx(ulong); +void lwbrx(ulong); +void lwzx(ulong); +void mcrxr(ulong); +void mfcr(ulong); +void mfmsr(ulong); +void mfpmr(ulong); +void mfspr(ulong); +void mfsr(ulong); +void mfsrin(ulong); +void mftb(ulong); +void mftbu(ulong); +void mspr(ulong); +void mtcrf(ulong); +void mtmsr(ulong); +void mtpmr(ulong); +void mtspr(ulong); +void mtsr(ulong); +void mtsrin(ulong); +void mttb(ulong); +void mttbu(ulong); +void mulhw(ulong); +void mulhwu(ulong); +void mullw(ulong); +void nand(ulong); +void neg(ulong); +void nor(ulong); +void or(ulong); +void orc(ulong); +void slbia(ulong); +void slbia(ulong); +void slw(ulong); +void sraw(ulong); +void srawi(ulong); +void srw(ulong); +void stbx(ulong); +void stfdx(ulong); +void stfiwx(ulong); +void stfsx(ulong); +void sthbrx(ulong); +void sthx(ulong); +void stswi(ulong); +void stswx(ulong); +void stwbrx(ulong); +void stwcx(ulong); +void stwx(ulong); +void subf(ulong); +void subfc(ulong); +void subfe(ulong); +void subfme(ulong); +void subfze(ulong); +void sync(ulong); +void tlbie(ulong); +void tw(ulong); +void xor(ulong); + +Inst op31[] = { +[0] {cmp, "cmp", Iarith}, +[4] {tw, "tw", Iarith}, +[8] {subfc, "subfc", Iarith}, +[10] {addc, "addc", Iarith}, +[11] {mulhwu, "mulhwu", Iarith}, +[19] {mfcr, "mfcr", Iarith}, +[20] {lwarx, "lwarx", Iload}, +[23] {lwzx, "lwzx", Iload}, +[24] {slw, "slw", Ilog}, +[26] {cntlzw, "cntlzw", Ilog}, +[28] {and, "and", Ilog}, +[32] {cmpl, "cmpl", Iarith}, +[40] {subf, "subf", Iarith}, +[54] {dcbst, "dcbst", Icontrol}, +[55] {lwzx, "lwzux", Iload}, +[60] {andc, "andc", Ilog}, +[75] {mulhw, "mulhw", Iarith}, +[83] {0, "mfmsr", Icontrol}, +[86] {dcbf, "dcbf", Icontrol}, +[87] {lbzx, "lbzx", Iload}, +[104] {neg, "neg", Iarith}, +[115] {0, "mfpmr", Iarith}, +[119] {lbzx, "lbzux", Iload}, +[124] {nor, "nor", Iarith}, +[136] {subfe, "subfe", Iarith}, +[138] {adde, "adde", Iarith}, +[144] {mtcrf, "mtcrf", Ireg}, +[146] {0, "mtmsr", Icontrol}, +[150] {stwcx, "stwcx.", Istore}, +[151] {stwx, "stwx", Istore}, +[178] {0, "mtpmr", Icontrol}, +[183] {stwx, "stwux", Istore}, +[200] {subfze, "subfze", Iarith}, +[202] {addze, "addze", Iarith}, +[210] {0, "mtsr", Ireg}, +[215] {stbx, "stbx", Istore}, +[232] {subfme, "subfme", Iarith}, +[234] {addme, "addme", Iarith}, +[235] {mullw, "mullw", Iarith}, +[242] {0, "mtsrin", Ireg}, +[246] {dcbtst, "dcbtst", Icontrol}, +[247] {stbx, "stbux", Istore}, +[266] {add, "add", Iarith}, +[275] {0, "mftb", Icontrol}, +[278] {dcbt, "dcbt", Icontrol}, +[279] {lhzx, "lhzx", Iload}, +[284] {eqv, "eqv", Ilog}, +[306] {0, "tlbie", Icontrol}, +[307] {0, "mftbu", Icontrol}, +[310] {0, "eciwx", Icontrol}, +[311] {lhzx, "lhzux", Iload}, +[316] {xor, "xor", Ilog}, +[339] {mspr, "mfspr", Ireg}, +[343] {lhax, "lhax", Iload}, +[375] {lhax, "lhaux", Iload}, +[403] {0, "mttb", Icontrol}, +[407] {sthx, "sthx", Istore}, +[412] {orc, "orc", Ilog}, +[434] {0, "slbia", Iarith}, +[435] {0, "mttbu", Icontrol}, +[438] {0, "ecowx", Icontrol}, +[439] {sthx, "sthux", Istore}, +[444] {or, "or", Ilog}, +[459] {divwu, "divwu", Iarith}, +[467] {mspr, "mtspr", Ireg}, +[470] {0, "dcbi", Icontrol}, +[476] {nand, "nand", Ilog}, +[491] {divw, "divw", Iarith}, +[498] {0, "slbia", Icontrol}, +[512] {mcrxr, "mcrxr", Ireg}, +[533] {lswx, "lswx", Iload}, +[534] {lwbrx, "lwbrx", Iload}, +[535] {lfsx, "lfsx", Ifloat}, +[536] {srw, "srw", Ilog}, +[567] {lfsx, "lfsux", Ifloat}, +[595] {0, "mfsr", Iarith}, +[597] {lswi, "lswi", Iarith}, +[598] {sync, "sync", Iarith}, +[599] {lfdx, "lfdx", Ifloat}, +[631] {lfdx, "lfdux", Ifloat}, +[659] {0, "mfsrin", Ireg}, +[661] {stswx, "stswx", Istore}, +[662] {stwbrx, "stwbrx", Istore}, +[663] {stfsx, "stfsx", Istore}, +[695] {stfsx, "stfsux", Istore}, +[725] {stswi, "stswi", Istore}, +[727] {stfdx, "stfdx", Istore}, +[759] {stfdx, "stfdux", Istore}, +[790] {lhbrx, "lhbrx", Iload}, +[792] {sraw, "sraw", Ilog}, +[824] {srawi, "srawi", Ilog}, +[854] {0, "eieio", Icontrol}, +[918] {sthbrx, "sthbrx", Istore}, +[922] {extsh, "extsh", Iarith}, +[954] {extsb, "extsb", Iarith}, +[982] {icbi, "icbi", Icontrol}, +[983] {unimp, "stfiwx", Istore}, +[1014] {dcbz, "dcbz", Icontrol}, +}; + +Inset ops31 = {op31, nelem(op31)}; + +void +mspr(ulong ir) +{ + int rd, ra, rb; + ulong *d; + char *n; + char buf[20]; + + getarrr(ir); + switch((rb<<5) | ra) { + case 0: + undef(ir); /* was mq */ + return; + case 1: + d = ®.xer; n = "xer"; + break; + case 268: + case 284: + d = ®.tbl; n = "tbl"; + break; + case 269: + case 285: + d = ®.tbu; n = "tbu"; + break; + case 22: + d = ®.dec; n = "dec"; + break; + case 8: + d = ®.lr; n = "lr"; + break; + case 9: + d = ®.ctr; n = "ctr"; + break; + default: + d = 0; sprint(n = buf, "spr%d", rd); + break; + } + if(getxo(ir) == 339) { + if(trace) + itrace("%s\tr%d,%s", ci->name, rd, n); + if(d != nil) + reg.r[rd] = *d; + } else { + if(trace) + itrace("%s\t%s,r%d", ci->name, n, rd); + if(d != nil) + *d = reg.r[rd]; + } +} + +static void +setcr(int d, long r) +{ + int c; + + c = 0; + if(reg.xer & XER_SO) + c |= 1; + if(r == 0) + c |= 2; + else if(r > 0) + c |= 4; + else + c |= 8; + reg.cr = (reg.cr & ~mkCR(d, 0xF)) | mkCR(d, c); +} + +void +addi(ulong ir) +{ + int rd, ra; + long imm; + + getairr(ir); + if(trace) { + if(ra) + itrace("%s\tr%d,r%d,$0x%lux", ci->name, rd, ra, imm); + else + itrace("li\tr%d,$0x%lux", rd, imm); + } + if(ra) + imm += reg.r[ra]; + reg.r[rd] = imm; +} + +void +addis(ulong ir) +{ + int rd, ra; + long imm; + + getairr(ir); + if(trace) { + if(ra) + itrace("%s\tr%d,r%d,$0x%lux", ci->name, rd, ra, imm); + else + itrace("lis\tr%d,$0x%lux", rd, imm); + } + imm <<= 16; + if(ra) + imm += reg.r[ra]; + reg.r[rd] = imm; +} + +void +and(ulong ir) +{ + int rs, ra, rb; + + getlrrr(ir); + reg.r[ra] = reg.r[rs] & reg.r[rb]; + if(trace) + itrace("%s%s\tr%d,r%d,r%d", ci->name, ir&1?".":"", ra, rs, rb); + if(ir & 1) + setcr(0, reg.r[ra]); +} + +void +andc(ulong ir) +{ + int rs, ra, rb; + + getlrrr(ir); + reg.r[ra] = reg.r[rs] & ~reg.r[rb]; + if(trace) + itrace("%s%s\tr%d,r%d,r%d", ci->name, ir&1?".":"", ra, rs, rb); + if(ir & 1) + setcr(0, reg.r[ra]); +} + +void +andicc(ulong ir) +{ + int rs, ra; + ulong imm; + + getlirr(ir); + reg.r[ra] = reg.r[rs] & imm; + if(trace) + itrace("%s\tr%d,r%d,$0x%lx", ci->name, ra, rs, imm); + setcr(0, reg.r[ra]); +} + +void +andiscc(ulong ir) +{ + int rs, ra; + ulong imm; + + getlirr(ir); + reg.r[ra] = reg.r[rs] & (imm<<16); + if(trace) + itrace("%s\tr%d,r%d,$0x%lx", ci->name, ra, rs, imm); + setcr(0, reg.r[ra]); +} + +void +cmpli(ulong ir) +{ + int rd, ra; + ulong c; + ulong imm, v; + + getairr(ir); + imm &= 0xFFFF; + if(rd & 3) + undef(ir); + rd >>= 2; + v = reg.r[ra]; + c = 0; + if(reg.xer & XER_SO) + c |= CRSO; + if(v < imm) + c |= CRLT; + else if(v == imm) + c |= CREQ; + else + c |= CRGT; + c >>= 28; + reg.cr = (reg.cr & ~mkCR(rd, 0xF)) | mkCR(rd, c); + if(trace) + itrace("%s\tcrf%d,r%d,0x%lux [cr=#%x]", ci->name, rd, ra, imm, c); +} + +void +cmp(ulong ir) +{ + int rd, ra, rb; + ulong c; + long va, vb; + + getarrr(ir); + if(rd & 3) + undef(ir); + rd >>= 2; + c = 0; + if(reg.xer & XER_SO) + c |= CRSO; + va = reg.r[ra]; + vb = reg.r[rb]; + if(va < vb) + c |= CRLT; + else if(va == vb) + c |= CREQ; + else + c |= CRGT; + c >>= 28; + reg.cr = (reg.cr & ~mkCR(rd, 0xF)) | mkCR(rd, c); + if(trace) + itrace("%s\tcrf%d,r%d,r%d [cr=#%x]", ci->name, rd, ra, rb, c); +} + +void +cmpi(ulong ir) +{ + int rd, ra; + ulong c; + long imm, v; + + getairr(ir); + if(rd & 3) + undef(ir); + rd >>= 2; + v = reg.r[ra]; + c = 0; + if(reg.xer & XER_SO) + c |= CRSO; + if(v < imm) + c |= CRLT; + else if(v == imm) + c |= CREQ; + else + c |= CRGT; + c >>= 28; + reg.cr = (reg.cr & ~mkCR(rd, 0xF)) | mkCR(rd, c); + if(trace) + itrace("%s\tcrf%d,r%d,0x%lux [cr=#%x]", ci->name, rd, ra, imm, c); +} + +void +cmpl(ulong ir) +{ + int rd, ra, rb; + ulong c; + ulong va, vb; + + getarrr(ir); + if(rd & 3) + undef(ir); + rd >>= 2; + c = 0; + if(reg.xer & XER_SO) + c |= CRSO; + va = reg.r[ra]; + vb = reg.r[rb]; + if(va < vb) + c |= CRLT; + else if(va == vb) + c |= CREQ; + else + c |= CRGT; + c >>= 28; + reg.cr = (reg.cr & ~mkCR(rd, 0xF)) | mkCR(rd, c); + if(trace) + itrace("%s\tcrf%d,r%d,r%d [cr=#%x]", ci->name, rd, ra, rb, c); +} + +void +cntlzw(ulong ir) +{ + int rs, ra, rb, n; + + getlrrr(ir); + if(rb) + undef(ir); + for(n=0; n<32 && (reg.r[rs] & (1L<<(31-n))) == 0; n++) + ; + reg.r[ra] = n; + if(trace) + itrace("%s%s\tr%d,r%d", ci->name, ir&1?".":"", ra, rs); + if(ir & 1) + setcr(0, reg.r[ra]); +} + +void +eqv(ulong ir) +{ + int rs, ra, rb; + + getlrrr(ir); + reg.r[ra] = ~(reg.r[rs] ^ reg.r[rb]); + if(trace) + itrace("%s%s\tr%d,r%d,r%d", ci->name, ir&1?".":"", ra, rs, rb); + if(ir & 1) + setcr(0, reg.r[ra]); +} + +void +extsb(ulong ir) +{ + int rs, ra, rb; + + getlrrr(ir); + if(rb) + undef(ir); + reg.r[ra] = (schar)reg.r[rs]; + if(trace) + itrace("%s%s\tr%d,r%d", ci->name, ir&1?".":"", ra, rs); + if(ir & 1) + setcr(0, reg.r[ra]); +} + +void +extsh(ulong ir) +{ + int rs, ra, rb; + + getlrrr(ir); + if(rb) + undef(ir); + reg.r[ra] = (short)reg.r[rs]; + if(trace) + itrace("%s%s\tr%d,r%d", ci->name, ir&1?".":"", ra, rs); + if(ir & 1) + setcr(0, reg.r[ra]); +} + +void +add(ulong ir) +{ + int rd, ra, rb; + uvlong r; + + getarrr(ir); + r = (uvlong)(ulong)reg.r[ra] + (uvlong)(ulong)reg.r[rb]; + if(ir & OE) { + reg.xer &= ~XER_OV; + if(r >> 16) + reg.xer |= XER_SO | XER_OV; /* TO DO: rubbish */ + } + reg.r[rd] = (ulong)r; + if(ir & Rc) + setcr(0, reg.r[rd]); + if(trace) + itrace("%s%s%s\tr%d,r%d,r%d", ci->name, ir&OE?"o":"", ir&1?".":"", rd, ra, rb); +} + +void +addc(ulong ir) +{ + int rd, ra, rb; + ulong v; + uvlong r; + + getarrr(ir); + r = (uvlong)(ulong)reg.r[ra] + (uvlong)(ulong)reg.r[rb]; + v = r>>32; + reg.xer &= ~XER_CA; + if(v) + reg.xer |= XER_CA; + if(ir & OE) { + reg.xer &= ~XER_OV; + if(v>>1) + reg.xer |= XER_SO | XER_OV; + } + reg.r[rd] = (ulong)r; + if(ir & Rc) + setcr(0, reg.r[rd]); + if(trace) + itrace("%s%s%s\tr%d,r%d,r%d", ci->name, ir&OE?"o":"", ir&1?".":"", rd, ra, rb); +} + +void +adde(ulong ir) +{ + int rd, ra, rb; + ulong v; + uvlong r; + + getarrr(ir); + r = (uvlong)(ulong)reg.r[ra] + (uvlong)(ulong)reg.r[rb] + ((reg.xer&XER_CA)!=0); + v = r>>32; + reg.xer &= ~XER_CA; + if(v) + reg.xer |= XER_CA; + if(ir & OE) { + reg.xer &= ~XER_OV; + if(v>>1) + reg.xer |= XER_SO | XER_OV; + } + reg.r[rd] = (ulong)r; + if(ir & Rc) + setcr(0, reg.r[rd]); + if(trace) + itrace("%s%s%s\tr%d,r%d,r%d", ci->name, ir&OE?"o":"", ir&1?".":"", rd, ra, rb); +} + +void +addic(ulong ir) +{ + int rd, ra; + long imm; + ulong v; + uvlong r; + + getairr(ir); + r = (uvlong)(ulong)reg.r[ra] + (uvlong)(ulong)imm; + v = r>>32; + reg.xer &= ~XER_CA; + if(v) + reg.xer |= XER_CA; + reg.r[rd] = (ulong)r; + if(trace) + itrace("%s\tr%d,r%d,$%ld", ci->name, rd, ra, imm); +} + +void +addiccc(ulong ir) +{ + int rd, ra; + long imm; + ulong v; + uvlong r; + + getairr(ir); + r = (uvlong)(ulong)reg.r[ra] + (uvlong)(ulong)imm; + v = r>>32; + reg.xer &= ~XER_CA; + if(v) + reg.xer |= XER_CA; + reg.r[rd] = (ulong)r; + setcr(0, reg.r[rd]); + if(trace) + itrace("%s\tr%d,r%d,$%ld", ci->name, rd, ra, imm); +} + +void +addme(ulong ir) +{ + int rd, ra, rb; + ulong v; + uvlong r; + + getarrr(ir); + if(rb) + undef(ir); + r = (uvlong)(ulong)reg.r[ra] + (uvlong)0xFFFFFFFFU + ((reg.xer&XER_CA)!=0); + v = r>>32; + reg.xer &= ~XER_CA; + if(v) + reg.xer |= XER_CA; + if(ir & OE) { + reg.xer &= ~XER_OV; + if(v>>1) + reg.xer |= XER_SO | XER_OV; + } + reg.r[rd] = (ulong)r; + if(ir & Rc) + setcr(0, reg.r[rd]); + if(trace) + itrace("%s%s%s\tr%d,r%d", ci->name, ir&OE?"o":"", ir&1?".":"", rd, ra); +} + +void +addze(ulong ir) +{ + int rd, ra, rb; + ulong v; + uvlong r; + + getarrr(ir); + if(rb) + undef(ir); + r = (uvlong)(ulong)reg.r[ra] + ((reg.xer&XER_CA)!=0); + v = r>>32; + reg.xer &= ~XER_CA; + if(v) + reg.xer |= XER_CA; + if(ir & OE) { + reg.xer &= ~XER_OV; + if(v>>1) + reg.xer |= XER_SO | XER_OV; + } + reg.r[rd] = (ulong)r; + if(ir & Rc) + setcr(0, reg.r[rd]); + if(trace) + itrace("%s%s%s\tr%d,r%d", ci->name, ir&OE?"o":"", ir&1?".":"", rd, ra); +} + +void +divw(ulong ir) +{ + int rd, ra, rb; + + getarrr(ir); + if(reg.r[rb] != 0 && ((ulong)reg.r[ra] != 0x80000000 || reg.r[rb] != -1)) + reg.r[rd] = reg.r[ra]/reg.r[rb]; + else if(ir & OE) + reg.xer |= XER_SO | XER_OV; + if(ir & Rc) + setcr(0, reg.r[rd]); + if(trace) + itrace("%s%s%s\tr%d,r%d,r%d", ci->name, ir&OE?"o":"", ir&1?".":"", rd, ra, rb); +} + +void +divwu(ulong ir) +{ + int rd, ra, rb; + + getarrr(ir); + if(reg.r[rb] != 0) + reg.r[rd] = (ulong)reg.r[ra]/(ulong)reg.r[rb]; + else if(ir & OE) + reg.xer |= XER_SO | XER_OV; + if(ir & Rc) + setcr(0, reg.r[rd]); + if(trace) + itrace("%s%s%s\tr%d,r%d,r%d", ci->name, ir&OE?"o":"", ir&1?".":"", rd, ra, rb); +} + +void +mcrxr(ulong ir) +{ + int rd, ra, rb; + + getarrr(ir); + if(rd & 3 || ra != 0 || rb != 0 || ir & Rc) + undef(ir); + rd >>= 2; + reg.cr = (reg.cr & ~mkCR(rd, 0xF)) | mkCR(rd, reg.xer>>28); + reg.xer &= ~(0xF<<28); +} + +void +mtcrf(ulong ir) +{ + int rs, crm, i; + ulong m; + + if(ir & ((1<<20)|(1<<11)|Rc)) + undef(ir); + rs = (ir>>21)&0x1F; + crm = (ir>>12)&0xFF; + m = 0; + for(i = 0x80; i; i >>= 1) { + m <<= 4; + if(crm & i) + m |= 0xF; + } + reg.cr = (reg.cr & ~m) | (reg.r[rs] & m); +} + +void +mfcr(ulong ir) +{ + int rd, ra, rb; + + getarrr(ir); + if(ra != 0 || rb != 0 || ir & Rc) + undef(ir); + reg.r[rd] = reg.cr; +} + +void +mulhw(ulong ir) +{ + int rd, ra, rb; + + getarrr(ir); + reg.r[rd] = ((vlong)(long)reg.r[ra]*(long)reg.r[rb])>>32; + if(ir & Rc) + setcr(0, reg.r[rd]); + if(trace) + itrace("%s%s%s\tr%d,r%d,r%d", ci->name, ir&OE?"o":"", ir&Rc?".":"", rd, ra, rb); + /* BUG: doesn't set OV */ +} + +void +mulhwu(ulong ir) +{ + int rd, ra, rb; + + getarrr(ir); + reg.r[rd] = ((uvlong)(ulong)reg.r[ra]*(ulong)reg.r[rb])>>32; + if(ir & Rc) + setcr(0, reg.r[rd]); /* not sure whether CR setting is signed or unsigned */ + if(trace) + itrace("%s%s%s\tr%d,r%d,r%d", ci->name, ir&OE?"o":"", ir&Rc?".":"", rd, ra, rb); + /* BUG: doesn't set OV */ +} + +void +mullw(ulong ir) +{ + int rd, ra, rb; + + getarrr(ir); + reg.r[rd] = (uvlong)(ulong)reg.r[ra]*(ulong)reg.r[rb]; + if(ir & Rc) + setcr(0, reg.r[rd]); + if(trace) + itrace("%s%s%s\tr%d,r%d,r%d", ci->name, ir&OE?"o":"", ir&Rc?".":"", rd, ra, rb); + /* BUG: doesn't set OV */ +} + +void +mulli(ulong ir) +{ + int rd, ra; + long imm; + + getairr(ir); + reg.r[rd] = (uvlong)(ulong)reg.r[ra]*(ulong)imm; + if(trace) + itrace("%s\tr%d,r%d,$%ld", ci->name, rd, ra, imm); +} + +void +nand(ulong ir) +{ + int rs, ra, rb; + + getlrrr(ir); + reg.r[ra] = ~(reg.r[rs] & reg.r[rb]); + if(ir & Rc) + setcr(0, reg.r[ra]); + if(trace) + itrace("%s%s\tr%d,r%d,r%d", ci->name, ir&1?".":"", ra, rs, rb); +} + +void +neg(ulong ir) +{ + int rd, ra, rb; + + getarrr(ir); + if(rb) + undef(ir); + if(ir & OE) + reg.xer &= ~XER_OV; + if((ulong)reg.r[ra] == 0x80000000) { + if(ir & OE) + reg.xer |= XER_SO | XER_OV; + reg.r[rd] = reg.r[ra]; + } else + reg.r[rd] = -reg.r[ra]; + if(ir & Rc) + setcr(0, reg.r[rd]); +} + +void +nor(ulong ir) +{ + int rs, ra, rb; + + getlrrr(ir); + reg.r[ra] = ~(reg.r[rs] | reg.r[rb]); + if(ir & Rc) + setcr(0, reg.r[ra]); + if(trace) + itrace("%s%s\tr%d,r%d,r%d", ci->name, ir&1?".":"", ra, rs, rb); +} + +void +or(ulong ir) +{ + int rs, ra, rb; + + getlrrr(ir); + reg.r[ra] = reg.r[rs] | reg.r[rb]; + if(ir & Rc) + setcr(0, reg.r[ra]); + if(trace) { + if(rs == rb) + itrace("mr%s\tr%d,r%d", ir&1?".":"", ra, rs); + else + itrace("%s%s\tr%d,r%d,r%d", ci->name, ir&1?".":"", ra, rs, rb); + } +} + +void +orc(ulong ir) +{ + int rs, ra, rb; + + getlrrr(ir); + reg.r[ra] = reg.r[rs] | ~reg.r[rb]; + if(ir & Rc) + setcr(0, reg.r[ra]); + if(trace) + itrace("%s%s\tr%d,r%d,r%d", ci->name, ir&1?".":"", ra, rs, rb); +} + +void +ori(ulong ir) +{ + int rs, ra; + ulong imm; + + getlirr(ir); + reg.r[ra] = reg.r[rs] | imm; + if(trace) + itrace("%s\tr%d,r%d,$0x%lx", ci->name, ra, rs, imm); +} + +void +oris(ulong ir) +{ + int rs, ra; + ulong imm; + + getlirr(ir); + reg.r[ra] = reg.r[rs] | (imm<<16); + if(trace) + itrace("%s\tr%d,r%d,$0x%lx", ci->name, ra, rs, imm); +} + +static ulong +mkmask(int mb, int me) +{ + int i; + ulong v; + + if(mb > me) + return mkmask(0, me) | mkmask(mb, 31); + v = 0; + for(i=mb; i<=me; i++) + v |= 1L << (31-i); /* don't need a loop, but i'm lazy */ + return v; +} + +static ulong +rotl(ulong v, int sh) +{ + if(sh == 0) + return v; + return (v<<sh) | (v>>(32-sh)); +} + +void +rlwimi(ulong ir) +{ + int rs, ra, rb, sh; + ulong m; + + getlrrr(ir); + sh = rb; + m = mkmask((ir>>6)&0x1F, (ir>>1)&0x1F); + reg.r[ra] = (reg.r[ra] & ~m) | (rotl(reg.r[rs], sh) & m); + if(trace) + itrace("%s\tr%d,r%d,%d,#%lux", ci->name, ra, rs, sh, m); + if(ir & 1) + setcr(0, reg.r[ra]); +} + +void +rlwinm(ulong ir) +{ + int rs, ra, rb, sh; + ulong m; + + getlrrr(ir); + sh = rb; + m = mkmask((ir>>6)&0x1F, (ir>>1)&0x1F); + reg.r[ra] = rotl(reg.r[rs], sh) & m; + if(trace) + itrace("%s%s\tr%d,r%d,%d,#%lux", ci->name, ir&Rc?".":"", ra, rs, sh, m); + if(ir & Rc) + setcr(0, reg.r[ra]); +} + +void +rlwnm(ulong ir) +{ + int rs, ra, rb, sh; + ulong m; + + getlrrr(ir); + sh = reg.r[rb] & 0x1F; + m = mkmask((ir>>6)&0x1F, (ir>>1)&0x1F); + reg.r[ra] = rotl(reg.r[rs], sh) & m; + if(trace) + itrace("%s\tr%d,r%d,r%d,#%lux", ci->name, ra, rs, rb, m); + if(ir & 1) + setcr(0, reg.r[ra]); +} + +void +slw(ulong ir) +{ + int rs, ra, rb; + long v; + + getlrrr(ir); + v = reg.r[rb]; + if((v & 0x20) == 0) { + v &= 0x1F; + reg.r[ra] = (ulong)reg.r[rs] << v; + } else + reg.r[ra] = 0; + if(ir & Rc) + setcr(0, reg.r[ra]); + if(trace) + itrace("%s%s\tr%d,r%d,r%d", ci->name, ir&1?".":"", ra, rs, rb); +} + +void +sraw(ulong ir) +{ + int rs, ra, rb; + long v; + + getlrrr(ir); + v = reg.r[rb]; + if((v & 0x20) == 0) { + v &= 0x1F; + if(reg.r[rs]&SIGNBIT && v) + reg.r[ra] = reg.r[rs]>>v | ~((1<<(32-v))-1); + else + reg.r[ra] = reg.r[rs]>>v; + } else + reg.r[ra] = reg.r[rs]&SIGNBIT? ~0: 0; + if(ir & Rc) + setcr(0, reg.r[ra]); + if(trace) + itrace("%s%s\tr%d,r%d,r%d", ci->name, ir&1?".":"", ra, rs, rb); +} + +void +srawi(ulong ir) +{ + int rs, ra, rb; + long v; + + getlrrr(ir); + v = rb; + if((v & 0x20) == 0) { + v &= 0x1F; + if(reg.r[rs]&SIGNBIT && v) + reg.r[ra] = reg.r[rs]>>v | ~((1<<(32-v))-1); + else + reg.r[ra] = reg.r[rs]>>v; + } else + reg.r[ra] = reg.r[rs]&SIGNBIT? ~0: 0; + if(ir & Rc) + setcr(0, reg.r[ra]); + if(trace) + itrace("%s%s\tr%d,r%d,$%d", ci->name, ir&1?".":"", ra, rs, v); +} + +void +srw(ulong ir) +{ + int rs, ra, rb; + long v; + + getlrrr(ir); + v = reg.r[rb]; + if((v & 0x20) == 0) + reg.r[ra] = (ulong)reg.r[rs] >> (v&0x1F); + else + reg.r[ra] = 0; + if(ir & Rc) + setcr(0, reg.r[ra]); + if(trace) + itrace("%s%s\tr%d,r%d,r%d", ci->name, ir&1?".":"", ra, rs, rb); +} + +void +subf(ulong ir) +{ + int rd, ra, rb; + uvlong r; + + getarrr(ir); + r = (uvlong)((ulong)~reg.r[ra]) + (uvlong)(ulong)reg.r[rb] + 1; + if(ir & OE) { + reg.xer &= ~XER_OV; + if(r >> 16) + reg.xer |= XER_SO | XER_OV; + } + reg.r[rd] = (ulong)r; + if(ir & Rc) + setcr(0, reg.r[rd]); + if(trace) + itrace("%s%s%s\tr%d,r%d,r%d", ci->name, ir&OE?"o":"", ir&1?".":"", rd, ra, rb); +} + +void +subfc(ulong ir) +{ + int rd, ra, rb; + ulong v; + uvlong r; + + getarrr(ir); + r = (uvlong)((ulong)~reg.r[ra]) + (uvlong)(ulong)reg.r[rb] + 1; + v = r>>32; + reg.xer &= ~XER_CA; + if(v) + reg.xer |= XER_CA; + if(ir & OE) { + reg.xer &= ~XER_OV; + if(v>>1) + reg.xer |= XER_SO | XER_OV; + } + reg.r[rd] = (ulong)r; + if(ir & Rc) + setcr(0, reg.r[rd]); + if(trace) + itrace("%s%s%s\tr%d,r%d,r%d", ci->name, ir&OE?"o":"", ir&1?".":"", rd, ra, rb); +} + +void +subfe(ulong ir) +{ + int rd, ra, rb; + ulong v; + uvlong r; + + getarrr(ir); + r = (uvlong)((ulong)~reg.r[ra]) + (uvlong)(ulong)reg.r[rb] + ((reg.xer&XER_CA)!=0); + v = r>>32; + reg.xer &= ~XER_CA; + if(v) + reg.xer |= XER_CA; + if(ir & OE) { + reg.xer &= ~XER_OV; + if(v>>1) + reg.xer |= XER_SO | XER_OV; + } + reg.r[rd] = (ulong)r; + if(ir & Rc) + setcr(0, reg.r[rd]); + if(trace) + itrace("%s%s%s\tr%d,r%d,r%d", ci->name, ir&OE?"o":"", ir&1?".":"", rd, ra, rb); +} + +void +subfic(ulong ir) +{ + int rd, ra; + long imm; + ulong v; + uvlong r; + + getairr(ir); + r = (uvlong)((ulong)~reg.r[ra]) + (uvlong)(ulong)imm + 1; + v = r>>32; + reg.xer &= ~XER_CA; + if(v) + reg.xer |= XER_CA; + reg.r[rd] = (ulong)r; + if(trace) + itrace("%s\tr%d,r%d,$%ld", ci->name, rd, ra, imm); +} + +void +subfme(ulong ir) +{ + int rd, ra, rb; + ulong v; + uvlong r; + + getarrr(ir); + if(rb) + undef(ir); + r = (uvlong)((ulong)~reg.r[ra]) + (uvlong)0xFFFFFFFFU + ((reg.xer&XER_CA)!=0); + v = r>>32; + reg.xer &= ~XER_CA; + if(v) + reg.xer |= XER_CA; + if(ir & OE) { + reg.xer &= ~XER_OV; + if(v>>1) + reg.xer |= XER_SO | XER_OV; + } + reg.r[rd] = (ulong)r; + if(ir & Rc) + setcr(0, reg.r[rd]); + if(trace) + itrace("%s%s%s\tr%d,r%d", ci->name, ir&OE?"o":"", ir&1?".":"", rd, ra); +} + +void +subfze(ulong ir) +{ + int rd, ra, rb; + ulong v; + uvlong r; + + getarrr(ir); + if(rb) + undef(ir); + r = (uvlong)((ulong)~reg.r[ra]) + ((reg.xer&XER_CA)!=0); + v = r>>32; + reg.xer &= ~XER_CA; + if(v) + reg.xer |= XER_CA; + if(ir & OE) { + reg.xer &= ~XER_OV; + if(v>>1) + reg.xer |= XER_SO | XER_OV; + } + reg.r[rd] = (ulong)r; + if(ir & Rc) + setcr(0, reg.r[rd]); + if(trace) + itrace("%s%s%s\tr%d,r%d", ci->name, ir&OE?"o":"", ir&1?".":"", rd, ra); +} + +void +xor(ulong ir) +{ + int rs, ra, rb; + + getlrrr(ir); + reg.r[ra] = reg.r[rs] ^ reg.r[rb]; + if(trace) + itrace("%s\tr%d,r%d,r%d", ci->name, ra, rs, rb); +} + +void +xori(ulong ir) +{ + int rs, ra; + ulong imm; + + getlirr(ir); + reg.r[ra] = reg.r[rs] ^ imm; + if(trace) + itrace("%s\tr%d,r%d,$0x%lx", ci->name, ra, rs, imm); +} + +void +xoris(ulong ir) +{ + int rs, ra; + ulong imm; + + getlirr(ir); + reg.r[ra] = reg.r[rs] ^ (imm<<16); + if(trace) + itrace("%s\tr%d,r%d,$0x%lx", ci->name, ra, rs, imm); +} + +void +lwz(ulong ir) +{ + ulong ea; + int ra, rd, upd; + long imm; + + getairr(ir); + ea = imm; + upd = (ir&(1L<<26))!=0; + if(ra) { + ea += reg.r[ra]; + if(upd) + reg.r[ra] = ea; + } else { + if(upd) + undef(ir); + } + if(trace) + itrace("%s\tr%d,%ld(r%d) ea=%lux", ci->name, rd, imm, ra, ea); + + reg.r[rd] = getmem_w(ea); +} + +void +lwzx(ulong ir) +{ + ulong ea; + int rb, ra, rd, upd; + + getarrr(ir); + ea = reg.r[rb]; + upd = getxo(ir)==55; + if(ra) { + ea += reg.r[ra]; + if(upd) + reg.r[ra] = ea; + if(trace) + itrace("%s\tr%d,(r%d+r%d) ea=%lux", ci->name, rd, ra, rb, ea); + } else { + if(upd) + undef(ir); + if(trace) + itrace("%s\tr%d,(r%d) ea=%lux", ci->name, rd, rb, ea); + } + + reg.r[rd] = getmem_w(ea); +} + +void +lwarx(ulong ir) +{ + lwzx(ir); +} + +void +lbz(ulong ir) +{ + ulong ea; + int ra, rd, upd; + long imm; + + getairr(ir); + ea = imm; + upd = (ir&(1L<<26))!=0; + if(ra) { + ea += reg.r[ra]; + if(upd) + reg.r[ra] = ea; + } else { + if(upd) + undef(ir); + } + if(trace) + itrace("%s\tr%d,%ld(r%d) ea=%lux", ci->name, rd, imm, ra, ea); + + reg.r[rd] = getmem_b(ea); +} + +void +lbzx(ulong ir) +{ + ulong ea; + int rb, ra, rd, upd; + + getarrr(ir); + ea = reg.r[rb]; + upd = getxo(ir)==119; + if(ra) { + ea += reg.r[ra]; + if(upd) + reg.r[ra] = ea; + if(trace) + itrace("%s\tr%d,(r%d+r%d) ea=%lux", ci->name, rd, ra, rb, ea); + } else { + if(upd) + undef(ir); + if(trace) + itrace("%s\tr%d,(r%d) ea=%lux", ci->name, rd, rb, ea); + } + + reg.r[rd] = getmem_b(ea); +} + +void +stw(ulong ir) +{ + ulong ea; + int ra, rd, upd; + long imm; + + getairr(ir); + ea = imm; + upd = (ir&(1L<<26))!=0; + if(ra) { + ea += reg.r[ra]; + if(upd) + reg.r[ra] = ea; + } else { + if(upd) + undef(ir); + } + if(trace) + itrace("%s\tr%d,%ld(r%d) #%lux=#%lux (%ld)", + ci->name, rd, imm, ra, ea, reg.r[rd], reg.r[rd]); + putmem_w(ea, reg.r[rd]); + +} + +void +stwx(ulong ir) +{ + ulong ea; + int ra, rd, upd, rb; + + getarrr(ir); + ea = reg.r[rb]; + upd = getxo(ir)==183; + if(ra) { + ea += reg.r[ra]; + if(upd) + reg.r[ra] = ea; + if(trace) + itrace("%s\tr%d,(r%d+r%d) #%lux=#%lux (%ld)", + ci->name, rd, ra, rb, ea, reg.r[rd], reg.r[rd]); + } else { + if(upd) + undef(ir); + if(trace) + itrace("%s\tr%d,(r%d) #%lux=#%lux (%ld)", + ci->name, rd, rb, ea, reg.r[rd], reg.r[rd]); + } + putmem_w(ea, reg.r[rd]); + +} + +void +stwcx(ulong ir) +{ + ulong ea; + int ra, rd, rb; + + if((ir & Rc) == 0) + undef(ir); + getarrr(ir); + ea = reg.r[rb]; + if(ra) { + ea += reg.r[ra]; + if(trace) + itrace("%s\tr%d,(r%d+r%d) #%lux=#%lux (%ld)", + ci->name, rd, ra, rb, ea, reg.r[rd], reg.r[rd]); + } else { + if(trace) + itrace("%s\tr%d,(r%d) #%lux=#%lux (%ld)", + ci->name, rd, rb, ea, reg.r[rd], reg.r[rd]); + } + putmem_w(ea, reg.r[rd]); /* assume a reservation exists; store succeeded */ + setcr(0, 0); + +} + +void +stb(ulong ir) +{ + ulong ea; + int ra, rd, upd, v; + long imm; + + getairr(ir); + ea = imm; + upd = (ir&(1L<<26))!=0; + if(ra) { + ea += reg.r[ra]; + if(upd) + reg.r[ra] = ea; + } else { + if(upd) + undef(ir); + } + v = reg.r[rd] & 0xFF; + if(trace) + itrace("%s\tr%d,%ld(r%d) #%lux=#%lux (%ld)", + ci->name, rd, imm, ra, ea, v, v); + putmem_b(ea, v); +} + +void +stbx(ulong ir) +{ + ulong ea; + int ra, rd, upd, rb, v; + + getarrr(ir); + ea = reg.r[rb]; + upd = getxo(ir)==247; + v = reg.r[rd] & 0xFF; + if(ra) { + ea += reg.r[ra]; + if(upd) + reg.r[ra] = ea; + if(trace) + itrace("%s\tr%d,(r%d+r%d) #%lux=#%lux (%ld)", + ci->name, rd, ra, rb, ea, v, v); + } else { + if(upd) + undef(ir); + if(trace) + itrace("%s\tr%d,(r%d) #%lux=#%lux (%ld)", + ci->name, rd, rb, ea, v, v); + } + putmem_b(ea, v); + +} + +void +lhz(ulong ir) +{ + ulong ea; + int imm, ra, rd, upd; + + getairr(ir); + ea = imm; + upd = (ir&(1L<<26))!=0; + if(ra) { + ea += reg.r[ra]; + if(upd) + reg.r[ra] = ea; + } else { + if(upd) + undef(ir); + } + if(trace) + itrace("%s\tr%d,%ld(r%d) ea=%lux", ci->name, rd, imm, ra, ea); + + reg.r[rd] = getmem_h(ea); +} + +void +lhzx(ulong ir) +{ + ulong ea; + int rb, ra, rd, upd; + + getarrr(ir); + ea = reg.r[rb]; + upd = getxo(ir)==311; + if(ra) { + ea += reg.r[ra]; + if(upd) + reg.r[ra] = ea; + if(trace) + itrace("%s\tr%d,(r%d+r%d) ea=%lux", ci->name, rd, ra, rb, ea); + } else { + if(upd) + undef(ir); + if(trace) + itrace("%s\tr%d,(r%d) ea=%lux", ci->name, rd, rb, ea); + } + + reg.r[rd] = getmem_h(ea); +} + +void +lha(ulong ir) +{ + ulong ea; + int imm, ra, rd, upd; + + getairr(ir); + ea = imm; + upd = (ir&(1L<<26))!=0; + if(ra) { + ea += reg.r[ra]; + if(upd) + reg.r[ra] = ea; + } else { + if(upd) + undef(ir); + } + if(trace) + itrace("%s\tr%d,%ld(r%d) ea=%lux", ci->name, rd, imm, ra, ea); + + reg.r[rd] = (short)getmem_h(ea); +} + +void +lhax(ulong ir) +{ + ulong ea; + int rb, ra, rd, upd; + + getarrr(ir); + ea = reg.r[rb]; + upd = getxo(ir)==311; + if(ra) { + ea += reg.r[ra]; + if(upd) + reg.r[ra] = ea; + if(trace) + itrace("%s\tr%d,(r%d+r%d) ea=%lux", ci->name, rd, ra, rb, ea); + } else { + if(upd) + undef(ir); + if(trace) + itrace("%s\tr%d,(r%d) ea=%lux", ci->name, rd, rb, ea); + } + + reg.r[rd] = (short)getmem_h(ea); +} + +void +lhbrx(ulong ir) +{ + ulong ea; + int rb, ra, rd; + ulong v; + + getarrr(ir); + ea = reg.r[rb]; + if(ra) { + ea += reg.r[ra]; + if(trace) + itrace("%s\tr%d,(r%d+r%d) ea=%lux", ci->name, rd, ra, rb, ea); + } else { + if(trace) + itrace("%s\tr%d,(r%d) ea=%lux", ci->name, rd, rb, ea); + } + v = getmem_h(ea); + + reg.r[rd] = ((v&0xFF)<<8)|(v&0xFF); +} + +void +sth(ulong ir) +{ + ulong ea; + int imm, ra, rd, upd, v; + + getairr(ir); + ea = imm; + upd = (ir&(1L<<26))!=0; + if(ra) { + ea += reg.r[ra]; + if(upd) + reg.r[ra] = ea; + } else { + if(upd) + undef(ir); + } + v = reg.r[rd] & 0xFFFF; + if(trace) + itrace("%s\tr%d,%ld(r%d) #%lux=#%lux (%ld)", + ci->name, rd, imm, ra, ea, v, v); + putmem_h(ea, v); + +} + +void +sthx(ulong ir) +{ + ulong ea; + int ra, rd, upd, rb, v; + + getarrr(ir); + ea = reg.r[rb]; + upd = getxo(ir)==247; + v = reg.r[rd] & 0xFFFF; + if(ra) { + ea += reg.r[ra]; + if(upd) + reg.r[ra] = ea; + if(trace) + itrace("%s\tr%d,(r%d+r%d) #%lux=#%lux (%ld)", + ci->name, rd, ra, rb, ea, v, v); + } else { + if(upd) + undef(ir); + if(trace) + itrace("%s\tr%d,(r%d) #%lux=#%lux (%ld)", + ci->name, rd, rb, ea, v, v); + } + putmem_h(ea, v); +} + +void +sthbrx(ulong ir) +{ + ulong ea; + int ra, rd, rb; + ulong v; + + getarrr(ir); + ea = reg.r[rb]; + v = reg.r[rd]; + v = ((v&0xFF)<<8)|(v&0xFF); + if(ra) { + ea += reg.r[ra]; + if(trace) + itrace("%s\tr%d,(r%d+r%d) #%lux=#%lux (%ld)", + ci->name, rd, ra, rb, ea, v, v); + } else { + if(trace) + itrace("%s\tr%d,(r%d) #%lux=#%lux (%ld)", + ci->name, rd, rb, ea, v, v); + } + putmem_h(ea, v); +} + +void +lwbrx(ulong ir) +{ + ulong ea; + int rb, ra, rd, i; + ulong v; + + getarrr(ir); + if(ir & Rc) + undef(ir); + ea = reg.r[rb]; + if(ra) { + ea += reg.r[ra]; + if(trace) + itrace("%s\tr%d,(r%d+r%d) ea=%lux", ci->name, rd, ra, rb, ea); + } else { + if(trace) + itrace("%s\tr%d,(r%d) ea=%lux", ci->name, rd, rb, ea); + } + v = 0; + for(i = 0; i < 4; i++) + v = v>>8 | getmem_b(ea++); /* assume unaligned load is allowed */ + reg.r[rd] = v; +} + +void +stwbrx(ulong ir) +{ + ulong ea; + int rb, ra, rd, i; + ulong v; + + getarrr(ir); + if(ir & Rc) + undef(ir); + ea = reg.r[rb]; + if(ra) { + ea += reg.r[ra]; + if(trace) + itrace("%s\tr%d,(r%d+r%d) ea=%lux", ci->name, rd, ra, rb, ea); + } else { + if(trace) + itrace("%s\tr%d,(r%d) ea=%lux", ci->name, rd, rb, ea); + } + v = 0; + for(i = 0; i < 4; i++) { + putmem_b(ea++, v & 0xFF); /* assume unaligned store is allowed */ + v >>= 8; + } +} + +void +lswi(ulong ir) +{ + ulong ea; + int rb, ra, rd, n, i, r, b; + + getarrr(ir); + if(ir & Rc) + undef(ir); + n = rb; + if(n == 0) + n = 32; + ea = 0; + if(ra) { + ea += reg.r[ra]; + if(trace) + itrace("%s\tr%d,(r%d),%d ea=%lux", ci->name, rd, ra, n, ea); + } else { + if(trace) + itrace("%s\tr%d,(0),%d ea=0", ci->name, rd, n); + } + i = -1; + r = rd-1; + while(--n >= 0) { + if(i < 0) { + r = (r+1)&0x1F; + if(ra == 0 || r != ra) + reg.r[r] = 0; + i = 24; + } + b = getmem_b(ea++); + if(ra == 0 || r != ra) + reg.r[r] = (reg.r[r] & ~(0xFF<<i)) | (b << i); + i -= 8; + } +} + +void +lswx(ulong ir) +{ + ulong ea; + int rb, ra, rd, n, i, r, b; + + getarrr(ir); + if(ir & Rc) + undef(ir); + n = reg.xer & 0x7F; + ea = reg.r[rb]; + if(ra) { + ea += reg.r[ra]; + if(trace) + itrace("%s\tr%d,(r%d+r%d) ea=%lux n=%d", ci->name, rd, ra, rb, ea, n); + } else { + if(trace) + itrace("%s\tr%d,(r%d) ea=%lux n=%d", ci->name, rd, rb, ea, n); + } + i = -1; + r = rd-1; + while(--n >= 0) { + if(i < 0) { + r = (r+1)&0x1F; + if((ra == 0 || r != ra) && r != rb) + reg.r[r] = 0; + i = 24; + } + b = getmem_b(ea++); + if((ra == 0 || r != ra) && r != rb) + reg.r[r] = (reg.r[r] & ~(0xFF<<i)) | (b << i); + i -= 8; + } +} + +void +stswx(ulong ir) +{ + ulong ea; + int rb, ra, rd, n, i, r; + + getarrr(ir); + if(ir & Rc) + undef(ir); + n = reg.xer & 0x7F; + ea = reg.r[rb]; + if(ra) { + ea += reg.r[ra]; + if(trace) + itrace("%s\tr%d,(r%d+r%d) ea=%lux n=%d", ci->name, rd, ra, rb, ea, n); + } else { + if(trace) + itrace("%s\tr%d,(r%d) ea=%lux n=%d", ci->name, rd, rb, ea, n); + } + i = -1; + r = rd-1; + while(--n >= 0) { + if(i < 0) { + r = (r+1)&0x1F; + i = 24; + } + putmem_b(ea++, (reg.r[r]>>i)&0xFF); + i -= 8; + } +} + +void +stswi(ulong ir) +{ + ulong ea; + int rb, ra, rd, n, i, r; + + getarrr(ir); + if(ir & Rc) + undef(ir); + n = rb; + if(n == 0) + n = 32; + ea = 0; + if(ra) { + ea += reg.r[ra]; + if(trace) + itrace("%s\tr%d,(r%d),%d ea=%lux", ci->name, rd, ra, n, ea); + } else { + if(trace) + itrace("%s\tr%d,(0),%d ea=0", ci->name, rd, n); + } + i = -1; + r = rd-1; + while(--n >= 0) { + if(i < 0) { + r = (r+1)&0x1F; + i = 24; + } + putmem_b(ea++, (reg.r[r]>>i)&0xFF); + i -= 8; + } +} + +void +lmw(ulong ir) +{ + ulong ea; + int ra, rd, r; + long imm; + + getairr(ir); + ea = imm; + if(ra) + ea += reg.r[ra]; + if(trace) + itrace("%s\tr%d,%ld(r%d) ea=%lux", ci->name, rd, imm, ra, ea); + + for(r = rd; r <= 31; r++) { + if(r != 0 && r != rd) + reg.r[rd] = getmem_w(ea); + ea += 4; + } +} + +void +stmw(ulong ir) +{ + ulong ea; + int ra, rd, r; + long imm; + + getairr(ir); + ea = imm; + if(ra) + ea += reg.r[ra]; + if(trace) + itrace("%s\tr%d,%ld(r%d) ea=%lux", ci->name, rd, imm, ra, ea); + + for(r = rd; r <= 31; r++) { + putmem_w(ea, reg.r[rd]); + ea += 4; + } +} + +void +twi(ulong ir) +{ + int rd, ra; + long a, imm; + + getairr(ir); + a = reg.r[ra]; + if(trace) + itrace("twi\t#%.2x,r%d,$0x%lux (%ld)", rd, ra, imm, imm); + if(a < imm && rd&0x10 || + a > imm && rd&0x08 || + a == imm && rd&0x04 || + (ulong)a < imm && rd&0x02 || + (ulong)a > imm && rd&0x01) { + Bprint(bioout, "program_exception (trap type)\n"); + longjmp(errjmp, 0); + } +} + +void +tw(ulong ir) +{ + int rd, ra, rb; + long a, b; + + getarrr(ir); + a = reg.r[ra]; + b = reg.r[rb]; + if(trace) + itrace("tw\t#%.2x,r%d,r%d", rd, ra, rb); + if(a < b && rd&0x10 || + a > b && rd&0x08 || + a == b && rd&0x04 || + (ulong)a < b && rd&0x02 || + (ulong)a > b && rd&0x01) { + Bprint(bioout, "program_exception (trap type)\n"); + longjmp(errjmp, 0); + } +} + +void +sync(ulong ir) +{ + USED(ir); + if(trace) + itrace("sync"); +} + +void +icbi(ulong ir) +{ + int rd, ra, rb; + + if(ir & Rc) + undef(ir); + getarrr(ir); + USED(rd); + if(trace) + itrace("%s\tr%d,r%d", ci->name, ra, rb); +} + +void +dcbf(ulong ir) +{ + int rd, ra, rb; + + if(ir & Rc) + undef(ir); + getarrr(ir); + USED(rd); + if(trace) + itrace("%s\tr%d,r%d", ci->name, ra, rb); +} + +void +dcbst(ulong ir) +{ + int rd, ra, rb; + + if(ir & Rc) + undef(ir); + getarrr(ir); + USED(rd); + if(trace) + itrace("%s\tr%d,r%d", ci->name, ra, rb); +} + +void +dcbt(ulong ir) +{ + int rd, ra, rb; + + if(ir & Rc) + undef(ir); + getarrr(ir); + USED(rd); + if(trace) + itrace("%s\tr%d,r%d", ci->name, ra, rb); +} + +void +dcbtst(ulong ir) +{ + int rd, ra, rb; + + if(ir & Rc) + undef(ir); + getarrr(ir); + USED(rd); + if(trace) + itrace("%s\tr%d,r%d", ci->name, ra, rb); +} + +void +dcbz(ulong ir) +{ + int rd, ra, rb; + + if(ir & Rc) + undef(ir); + getarrr(ir); + USED(rd); + if(trace) + itrace("%s\tr%d,r%d", ci->name, ra, rb); +} diff --git a/sys/src/cmd/qi/mem.c b/sys/src/cmd/qi/mem.c new file mode 100755 index 000000000..7a1c87228 --- /dev/null +++ b/sys/src/cmd/qi/mem.c @@ -0,0 +1,271 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <mach.h> +#define Extern extern +#include "power.h" + +extern ulong textbase; + +ulong +ifetch(ulong addr) +{ + uchar *va; + ulong px; + + if(addr&3) { + Bprint(bioout, "instruction_address_not_aligned [addr %.8lux]\n", addr); + longjmp(errjmp, 0); + } + + if(icache.on) + updateicache(addr); + + va = vaddr(addr); + px = (addr-textbase)/PROFGRAN; + if(px < iprofsize) + iprof[px]++; + + va += addr&(BY2PG-1); + + return va[0]<<24 | va[1]<<16 | va[2]<<8 | va[3]; +} + +ulong +getmem_4(ulong addr) +{ + ulong val; + int i; + + val = 0; + for(i = 0; i < 4; i++) + val = val<<8 | getmem_b(addr++); + return val; +} + +ulong +getmem_2(ulong addr) +{ + ulong val; + + val = getmem_b(addr); + val = val<<8 | getmem_b(addr+1); + + return val; +} + +uvlong +getmem_v(ulong addr) +{ + if(addr&3) { /* 7? */ + Bprint(bioout, "mem_address_not_aligned [load addr %.8lux]\n", addr); + longjmp(errjmp, 0); + } + + return ((uvlong)getmem_w(addr) << 32) | getmem_w(addr+4); +} + +ulong +getmem_w(ulong addr) +{ + uchar *va; + + if(addr&3) { + Bprint(bioout, "mem_address_not_aligned [load addr %.8lux]\n", addr); + longjmp(errjmp, 0); + } + if(membpt) + brkchk(addr, Read); + + va = vaddr(addr); + va += addr&(BY2PG-1); + + return va[0]<<24 | va[1]<<16 | va[2]<<8 | va[3]; +} + +ushort +getmem_h(ulong addr) +{ + uchar *va; + + if(addr&1) { + Bprint(bioout, "mem_address_not_aligned [load addr %.8lux]\n", addr); + longjmp(errjmp, 0); + } + if(membpt) + brkchk(addr, Read); + + va = vaddr(addr); + va += addr&(BY2PG-1); + + return va[0]<<8 | va[1]; +} + +uchar +getmem_b(ulong addr) +{ + uchar *va; + + if(membpt) + brkchk(addr, Read); + + va = vaddr(addr); + va += addr&(BY2PG-1); + return va[0]; +} + +void +putmem_v(ulong addr, uvlong data) +{ + if(addr&3) { /* 7? */ + Bprint(bioout, "mem_address_not_aligned [store addr %.8lux]\n", addr); + longjmp(errjmp, 0); + } + + putmem_w(addr, data>>32); /* two stages, to catch brkchk */ + putmem_w(addr+4, data); +} + +void +putmem_w(ulong addr, ulong data) +{ + uchar *va; + + if(addr&3) { + Bprint(bioout, "mem_address_not_aligned [store addr %.8lux]\n", addr); + longjmp(errjmp, 0); + } + + va = vaddr(addr); + va += addr&(BY2PG-1); + + va[0] = data>>24; + va[1] = data>>16; + va[2] = data>>8; + va[3] = data; + if(membpt) + brkchk(addr, Write); +} + +void +putmem_b(ulong addr, uchar data) +{ + uchar *va; + + va = vaddr(addr); + va += addr&(BY2PG-1); + va[0] = data; + if(membpt) + brkchk(addr, Write); +} + +void +putmem_h(ulong addr, short data) +{ + uchar *va; + + if(addr&1) { + Bprint(bioout, "mem_address_not_aligned [store addr %.8lux]\n", addr); + longjmp(errjmp, 0); + } + + va = vaddr(addr); + va += addr&(BY2PG-1); + va[0] = data>>8; + va[1] = data; + if(membpt) + brkchk(addr, Write); +} + +char * +memio(char *mb, ulong mem, int size, int dir) +{ + int i; + char *buf, c; + + if(size < 0) { + Bprint(bioout, "memio: invalid size: %d\n", size); + longjmp(errjmp, 0); + } + if(mb == 0) + mb = emalloc(size); + + buf = mb; + switch(dir) { + default: + fatal(0, "memio"); + case MemRead: + while(size--) + *mb++ = getmem_b(mem++); + break; + case MemReadstring: + for(;;) { + if(size-- == 0) { + Bprint(bioout, "memio: user/kernel copy too long for qi\n"); + longjmp(errjmp, 0); + } + c = getmem_b(mem++); + *mb++ = c; + if(c == '\0') + break; + } + break; + case MemWrite: + for(i = 0; i < size; i++) + putmem_b(mem++, *mb++); + break; + } + return buf; +} + +void * +vaddr(ulong addr) +{ + Segment *s, *es; + int off, foff, l, n; + uchar **p, *a; + + es = &memory.seg[Nseg]; + for(s = memory.seg; s < es; s++) { + if(addr >= s->base && addr < s->end) { + s->refs++; + off = (addr-s->base)/BY2PG; + p = &s->table[off]; + if(*p) + return *p; + s->rss++; + switch(s->type) { + default: + fatal(0, "vaddr"); + case Text: + *p = emalloc(BY2PG); + if(seek(text, s->fileoff+(off*BY2PG), 0) < 0) + fatal(1, "vaddr text seek"); + if(read(text, *p, BY2PG) < 0) + fatal(1, "vaddr text read"); + return *p; + case Data: + *p = emalloc(BY2PG); + foff = s->fileoff+(off*BY2PG); + if(seek(text, foff, 0) < 0) + fatal(1, "vaddr text seek"); + n = read(text, *p, BY2PG); + if(n < 0) + fatal(1, "vaddr text read"); + if(foff + n > s->fileend) { + l = BY2PG - (s->fileend-foff); + a = *p+(s->fileend-foff); + memset(a, 0, l); + } + return *p; + case Bss: + case Stack: + *p = emalloc(BY2PG); + return *p; + } + } + } + Bprint(bioout, "data_access_MMU_miss [addr 0x%.8lux]\n", addr); + longjmp(errjmp, 0); + return 0; /*to stop compiler whining*/ +} diff --git a/sys/src/cmd/qi/mkfile b/sys/src/cmd/qi/mkfile new file mode 100755 index 000000000..5fa9ab529 --- /dev/null +++ b/sys/src/cmd/qi/mkfile @@ -0,0 +1,29 @@ +</$objtype/mkfile + +TARG=qi +OFILES= qi.$O\ + run.$O\ + mem.$O\ + syscall.$O\ + stats.$O\ + icache.$O\ + symbols.$O\ + cmd.$O\ + bpt.$O\ + float.$O\ + branch.$O\ + iu.$O\ + +HFILES=power.h\ + +BIN=/$objtype/bin + +UPDATE=\ + mkfile\ + $HFILES\ + ${OFILES:%.$O=%.c}\ + +</sys/src/cmd/mkone + +acid: + $CC -a run.c > acid.def diff --git a/sys/src/cmd/qi/power.h b/sys/src/cmd/qi/power.h new file mode 100755 index 000000000..e24ca8a34 --- /dev/null +++ b/sys/src/cmd/qi/power.h @@ -0,0 +1,285 @@ +/* + * power sim.h + * + * The integer instruction side of this emulator is portable if sizeof(long) >= 4 + * Floating point emulation assumes: + * sizeof(ulong) == sizeof(float) + * sizeof(ulong)*2 == sizeof(double) <= sizeof(vlong) + * unions of double & vlong have no padding + * vlongs provide at least 64 bits precision + */ +#include "/power/include/ureg.h" +#define USERADDR 0xC0000000 +#define UREGADDR (USERADDR+BY2PG-4-0xA0) +#define USER_REG(x) (UREGADDR+(ulong)(x)) +#define REGOFF(x) (USER_REG(&((struct Ureg *) 0)->x)) + +typedef struct Registers Registers; +typedef struct Segment Segment; +typedef struct Memory Memory; +typedef struct Inset Inset; +typedef struct Inst Inst; +typedef struct Icache Icache; +typedef struct Breakpoint Breakpoint; + +enum +{ + Instruction = 1, + Read = 2, + Write = 4, + Access = 2|4, + Equal = 4|8, +}; + +struct Breakpoint +{ + int type; /* Instruction/Read/Access/Write/Equal */ + ulong addr; /* Place at address */ + int count; /* To execute count times or value */ + int done; /* How many times passed through */ + Breakpoint *next; /* Link to next one */ +}; + +enum +{ + Iload, + Istore, + Iarith, + Ilog, + Ibranch, + Ireg, + Isyscall, + Ifloat, + Inop, + Icontrol, +}; + +struct Icache +{ + int on; /* Turned on */ + int linesize; /* Line size in bytes */ + int stall; /* Cache stalls */ + int *lines; /* Tag array */ + int* (*hash)(ulong); /* Hash function */ + char *hashtext; /* What the function looks like */ +}; + +struct Inset +{ + Inst *tab; /* indexed by extended opcode */ + int nel; +}; + +struct Inst +{ + void (*func)(ulong); + char *name; + int type; + int count; + int taken; +}; + +struct Registers +{ + ulong pc; + ulong ir; + Inst *ip; + long r[32]; + ulong ctr; + ulong cr; + ulong xer; + ulong lr; + ulong fpscr; + ulong dec; + ulong tbl; + ulong tbu; + double fd[32]; +}; + +enum +{ + MemRead, + MemReadstring, + MemWrite, +}; + +enum +{ + Stack, + Text, + Data, + Bss, + Nseg, +}; + +struct Segment +{ + short type; + ulong base; + ulong end; + ulong fileoff; + ulong fileend; + int rss; + int refs; + uchar **table; +}; + +struct Memory +{ + Segment seg[Nseg]; +}; + +void fatal(int, char*, ...); +void fpreginit(void); +void run(void); +void undef(ulong); +void unimp(ulong); +void dumpreg(void); +void dumpfreg(void); +void dumpdreg(void); +void* emalloc(ulong); +void* erealloc(void*, ulong, ulong); +void* vaddr(ulong); +void itrace(char *, ...); +void segsum(void); +void sc(ulong); +char* memio(char*, ulong, int, int); +ulong getmem_w(ulong); +ulong ifetch(ulong); +ushort getmem_h(ulong); +void putmem_w(ulong, ulong); +uchar getmem_b(ulong); +void putmem_b(ulong, uchar); +uvlong getmem_v(ulong); +ulong getmem_4(ulong); +ulong getmem_2(ulong); +void putmem_v(ulong, uvlong); +void putmem_h(ulong, short); +void isum(void); +void initicache(void); +void updateicache(ulong addr); +long lnrand(long); +void randseed(long, long); +void cmd(void); +void brkchk(ulong, int); +void delbpt(char*); +void breakpoint(char*, char*); +char* nextc(char*); +ulong expr(char*); +void initstk(int, char**); +void initmap(void); +void inithdr(int); +void reset(void); +void dobplist(void); +void procinit(int); +void printsource(long); +void printparams(Symbol *, ulong); +void printlocals(Symbol *, ulong); +void stktrace(int); +void iprofile(void); + +/* Globals */ +Extern Registers reg; +Extern Memory memory; +Extern int text; +Extern int trace; +Extern int sysdbg; +Extern int calltree; +Extern Icache icache; +Extern int count; +Extern jmp_buf errjmp; +Extern Breakpoint *bplist; +Extern int atbpt; +Extern int membpt; +Extern int cmdcount; +Extern int nopcount; +Extern ulong dot; +extern char *file; +Extern Biobuf *bioout; +Extern Biobuf *bin; +Extern Inst *ci; +Extern ulong *iprof; +Extern ulong iprofsize; +Extern ulong loadlock; +extern int datasize; +extern int printcol; +Extern Map *symmap; +extern ulong bits[]; + +extern Inset ops0, ops19, ops31, ops59, ops63a, ops63b; + +/* Plan9 Kernel constants */ +#define BY2PG 4096 +#define BY2WD 4 +#define UTZERO 0x1000 +#define TSTKSIZ 32 +#define TSTACKTOP 0x20000000 +#define STACKTOP (TSTACKTOP-TSTKSIZ*BY2PG) +#define STACKSIZE (4*1024*1024) + +#define PROFGRAN 4 +#define NOP 0x80300000 +#define SIGNBIT 0x80000000 + + +enum { + CRLT = 1<<31, + CRGT = 1<<30, + CREQ = 1<<29, + CRSO = 1<<28, + CRFU = CRSO, + + CRFX = 1<<27, + CRFEX = 1<<26, + CRVX = 1<<25, + CROX = 1<<24, +}; + +#define getCR(x,w) (((w)>>(28-(x*4)))&0xF) +#define mkCR(x,v) (((v)&0xF)<<(28-(x*4))) + +#define simm(xx, ii) xx = (short)(ii&0xFFFF); +#define uimm(xx, ii) xx = ii&0xFFFF; +#define imms(xx, ii) xx = ii<<16; +#define getairr(i) rd = (i>>21)&0x1f; ra = (i>>16)&0x1f; simm(imm,i) +#define getarrr(i) rd = (i>>21)&0x1f; ra = (i>>16)&0x1f; rb = (i>>11)&0x1f; +#define getbobi(i) bo = (i>>21)&0x1f; bi = (i>>16)&0x1f; xx = (i>>11)&0x1f; +#define getlirr(i) rs = (i>>21)&0x1f; ra = (i>>16)&0x1f; uimm(imm,i) +#define getlrrr(i) rs = (i>>21)&0x1f; ra = (i>>16)&0x1f; rb = (i>>11)&0x1f; + +#define OP(o,xo) ((o<<26)|(xo<<1)) /* build an operation */ +#define xop(a,b) ((b<<6)|a) /* compact form for use in a decoding switch on op/xo */ +#define getop(i) ((i>>26)&0x3F) +#define getxo(i) ((i>>1)&0x3FF) + +#define FPS_FX (1<<31) /* exception summary (sticky) */ +#define FPS_EX (1<<30) /* enabled exception summary */ +#define FPS_VX (1<<29) /* invalid operation exception summary */ +#define FPS_OX (1<<28) /* overflow exception OX (sticky) */ +#define FPS_UX (1<<27) /* underflow exception UX (sticky) */ +#define FPS_ZX (1<<26) /* zero divide exception ZX (sticky) */ +#define FPS_XX (1<<25) /* inexact exception XX (sticky) */ +#define FPS_VXSNAN (1<<24) /* invalid operation exception for SNaN (sticky) */ +#define FPS_VXISI (1<<23) /* invalid operation exception for ∞-∞ (sticky) */ +#define FPS_VXIDI (1<<22) /* invalid operation exception for ∞/∞ (sticky) */ +#define FPS_VXZDZ (1<<21) /* invalid operation exception for 0/0 (sticky) */ +#define FPS_VXIMZ (1<<20) /* invalid operation exception for ∞*0 (sticky) */ +#define FPS_VXVC (1<<19) /* invalid operation exception for invalid compare (sticky) */ +#define FPS_FR (1<<18) /* fraction rounded */ +#define FPS_FI (1<<17) /* fraction inexact */ +#define FPS_FPRF (1<<16) /* floating point result class */ +#define FPS_FPCC (0xF<<12) /* <, >, =, unordered */ +#define FPS_VXCVI (1<<8) /* enable exception for invalid integer convert (sticky) */ +#define FPS_VE (1<<7) /* invalid operation exception enable */ +#define FPS_OE (1<<6) /* enable overflow exceptions */ +#define FPS_UE (1<<5) /* enable underflow */ +#define FPS_ZE (1<<4) /* enable zero divide */ +#define FPS_XE (1<<3) /* enable inexact exceptions */ +#define FPS_RN (3<<0) /* rounding mode */ + +#define XER_SO (1<<31) +#define XER_OV (1<<30) +#define XER_CA (1<<29) + +#define Rc 1 +#define OE 0x400 diff --git a/sys/src/cmd/qi/qi.c b/sys/src/cmd/qi/qi.c new file mode 100755 index 000000000..ebccc5e46 --- /dev/null +++ b/sys/src/cmd/qi/qi.c @@ -0,0 +1,423 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <mach.h> +#define Extern +#include "power.h" + +char *file = "q.out"; +int datasize; +ulong textbase; +Biobuf bp, bi; +Fhdr fhdr; +ulong bits[32]; + +void +main(int argc, char **argv) +{ + int pid, i; + + argc--; + argv++; + + bioout = &bp; + bin = &bi; + Binit(bioout, 1, OWRITE); + Binit(bin, 0, OREAD); + + if(argc) { + pid = atoi(argv[0]); + if(pid != 0) { + procinit(pid); + cmd(); + } + file = argv[0]; + } + argc--; + argv++; + + text = open(file, OREAD); + if(text < 0) + fatal(1, "open text '%s'", file); + + Bprint(bioout, "qi\n"); + inithdr(text); + initstk(argc, argv); + + for(i=0; i<32; i++) + bits[i] = 1L << (31-i); + + fpreginit(); + cmd(); +} + +void +initmap(void) +{ + + ulong t, d, b, bssend; + Segment *s; + + t = (fhdr.txtaddr+fhdr.txtsz+(BY2PG-1)) & ~(BY2PG-1); + d = (t + fhdr.datsz + (BY2PG-1)) & ~(BY2PG-1); + bssend = t + fhdr.datsz + fhdr.bsssz; + b = (bssend + (BY2PG-1)) & ~(BY2PG-1); + + s = &memory.seg[Text]; + s->type = Text; + s->base = fhdr.txtaddr - fhdr.hdrsz; + s->end = t; + s->fileoff = fhdr.txtoff - fhdr.hdrsz; + s->fileend = s->fileoff + fhdr.txtsz; + s->table = emalloc(((s->end-s->base)/BY2PG)*sizeof(uchar*)); + + iprofsize = (s->end-s->base)/PROFGRAN; + iprof = emalloc(iprofsize*sizeof(long)); + textbase = s->base; + + s = &memory.seg[Data]; + s->type = Data; + s->base = t; + s->end = t+(d-t); + s->fileoff = fhdr.datoff; + s->fileend = s->fileoff + fhdr.datsz; + datasize = fhdr.datsz; + s->table = emalloc(((s->end-s->base)/BY2PG)*sizeof(uchar*)); + + s = &memory.seg[Bss]; + s->type = Bss; + s->base = d; + s->end = d+(b-d); + s->table = emalloc(((s->end-s->base)/BY2PG)*sizeof(uchar*)); + + s = &memory.seg[Stack]; + s->type = Stack; + s->base = STACKTOP-STACKSIZE; + s->end = STACKTOP; + s->table = emalloc(((s->end-s->base)/BY2PG)*sizeof(uchar*)); + + reg.pc = fhdr.entry; +} + +void +inithdr(int fd) +{ + Symbol s; + + extern Machdata powermach; + + seek(fd, 0, 0); + if (!crackhdr(fd, &fhdr)) + fatal(0, "read text header"); + + if(fhdr.type != FPOWER) + fatal(0, "bad magic number"); + + if(syminit(fd, &fhdr) < 0) + fatal(0, "%r\n"); + symmap = loadmap(symmap, fd, &fhdr); + if (mach->sbreg && lookup(0, mach->sbreg, &s)) + mach->sb = s.value; + machdata = &powermach; +} + +ulong +greg(int f, ulong off) +{ + int n; + ulong l; + uchar wd[BY2WD]; + + seek(f, off, 0); + n = read(f, wd, BY2WD); + if(n != BY2WD) + fatal(1, "read register"); + + l = wd[0]<<24; + l |= wd[1]<<16; + l |= wd[2]<<8; + l |= wd[3]; + return l; +} + +ulong +roff[] = { + REGOFF(r0), + REGOFF(r1), REGOFF(r2), REGOFF(r3), + REGOFF(r4), REGOFF(r5), REGOFF(r6), + REGOFF(r7), REGOFF(r8), REGOFF(r9), + REGOFF(r10), REGOFF(r11), REGOFF(r12), + REGOFF(r13), REGOFF(r14), REGOFF(r15), + REGOFF(r16), REGOFF(r17), REGOFF(r18), + REGOFF(r19), REGOFF(r20), REGOFF(r21), + REGOFF(r22), REGOFF(r23), REGOFF(r24), + REGOFF(r25), REGOFF(r26), REGOFF(r27), + REGOFF(r28), REGOFF(r29), REGOFF(r30), + REGOFF(r31), +}; + +void +seginit(int fd, Segment *s, int idx, ulong vastart, ulong vaend) +{ + int n; + + while(vastart < vaend) { + seek(fd, vastart, 0); + s->table[idx] = emalloc(BY2PG); + n = read(fd, s->table[idx], BY2PG); + if(n != BY2PG) + fatal(1, "data read"); + vastart += BY2PG; + idx++; + } +} + +void +procinit(int pid) +{ + char *p; + Segment *s; + int n, m, sg, i; + ulong vastart, vaend; + char mfile[128], tfile[128], sfile[1024]; + + sprint(mfile, "/proc/%d/mem", pid); + sprint(tfile, "/proc/%d/text", pid); + sprint(sfile, "/proc/%d/segment", pid); + + text = open(tfile, OREAD); + if(text < 0) + fatal(1, "open text %s", tfile); + inithdr(text); + + sg = open(sfile, OREAD); + if(sg < 0) + fatal(1, "open text %s", sfile); + + n = read(sg, sfile, sizeof(sfile)); + if(n >= sizeof(sfile)) + fatal(0, "segment file buffer too small"); + close(sg); + + m = open(mfile, OREAD); + if(m < 0) + fatal(1, "open %s", mfile); + + initmap(); + + p = strstr(sfile, "Data"); + if(p == 0) + fatal(0, "no data"); + + vastart = strtoul(p+9, 0, 16); + vaend = strtoul(p+18, 0, 16); + s = &memory.seg[Data]; + if(s->base != vastart || s->end != vaend) { + s->base = vastart; + s->end = vaend; + free(s->table); + s->table = malloc(((s->end-s->base)/BY2PG)*sizeof(uchar*)); + } + seginit(m, s, 0, vastart, vaend); + + p = strstr(sfile, "Bss"); + if(p == 0) + fatal(0, "no bss"); + + vastart = strtoul(p+9, 0, 16); + vaend = strtoul(p+18, 0, 16); + s = &memory.seg[Bss]; + if(s->base != vastart || s->end != vaend) { + s->base = vastart; + s->end = vaend; + free(s->table); + s->table = malloc(((s->end-s->base)/BY2PG)*sizeof(uchar*)); + } + seginit(m, s, 0, vastart, vaend); + + reg.pc = greg(m, REGOFF(pc)); + reg.r[1] = greg(m, REGOFF(sp)); + reg.r[2] = greg(m, REGOFF(r2)); + reg.r[30] = greg(m, REGOFF(r30)); + reg.r[31] = greg(m, REGOFF(r31)); + + for(i = 0; i < 32; i++) + reg.r[i] = greg(m, roff[i-1]); + + s = &memory.seg[Stack]; + vastart = reg.r[1] & ~(BY2PG-1); + seginit(m, s, (vastart-s->base)/BY2PG, vastart, STACKTOP); + close(m); + Bprint(bioout, "qi\n"); +} + +void +reset(void) +{ + int i, l, m; + Segment *s; + Breakpoint *b; + + memset(®, 0, sizeof(Registers)); + fpreginit(); + for(i = 0; i > Nseg; i++) { + s = &memory.seg[i]; + l = ((s->end-s->base)/BY2PG)*sizeof(uchar*); + for(m = 0; m < l; m++) + if(s->table[m]) + free(s->table[m]); + free(s->table); + } + free(iprof); + memset(&memory, 0, sizeof(memory)); + + for(b = bplist; b; b = b->next) + b->done = b->count; +} + +void +initstk(int argc, char *argv[]) +{ + ulong size, sp, ap; + int i; + char *p; + + initmap(); + sp = STACKTOP - 4; + + /* Build exec stack */ + size = strlen(file)+1+BY2WD+BY2WD+(BY2WD*2); + for(i = 0; i < argc; i++) + size += strlen(argv[i])+BY2WD+1; + + sp -= size; + sp &= ~7; + reg.r[1] = sp; + reg.r[3] = STACKTOP-4; /* Plan 9 profiling clock */ + + /* Push argc */ + putmem_w(sp, argc+1); + sp += BY2WD; + + /* Compute sizeof(argv) and push argv[0] */ + ap = sp+((argc+1)*BY2WD)+BY2WD; + putmem_w(sp, ap); + sp += BY2WD; + + /* Build argv[0] string into stack */ + for(p = file; *p; p++) + putmem_b(ap++, *p); + + putmem_b(ap++, '\0'); + + /* Loop through pushing the arguments */ + for(i = 0; i < argc; i++) { + putmem_w(sp, ap); + sp += BY2WD; + for(p = argv[i]; *p; p++) + putmem_b(ap++, *p); + putmem_b(ap++, '\0'); + } + /* Null terminate argv */ + putmem_w(sp, 0); + +} + +void +fatal(int syserr, char *fmt, ...) +{ + char buf[ERRMAX], *s; + va_list ap; + + va_start(ap, fmt); + vseprint(buf, buf+sizeof(buf), fmt, ap); + va_end(ap); + s = "qi: %s\n"; + if(syserr) + s = "qi: %s: %r\n"; + fprint(2, s, buf); + exits(buf); +} + +void +itrace(char *fmt, ...) +{ + char buf[128]; + va_list ap; + + va_start(ap, fmt); + vseprint(buf, buf+sizeof(buf), fmt, ap); + va_end(ap); + Bprint(bioout, "%8lux %.8lux %s\n", reg.pc, reg.ir, buf); +Bflush(bioout); +} + +void +dumpreg(void) +{ + int i; + + Bprint(bioout, "PC #%-8lux SP #%-8lux CR #%-8lux LR #%-8lux CTR #%-8lux XER #%-8lux\n", + reg.pc, reg.r[1], reg.cr, reg.lr, reg.ctr, reg.xer); + + for(i = 0; i < 32; i++) { + if((i%4) == 0 && i != 0) + Bprint(bioout, "\n"); + Bprint(bioout, "R%-2d #%-8lux ", i, reg.r[i]); + } + Bprint(bioout, "\n"); +} + +void +dumpfreg(void) +{ + dumpdreg(); +} + +void +dumpdreg(void) +{ + int i; + char buf[64]; + FPdbleword d; + + i = 0; + while(i < 32) { + d.x = reg.fd[i]; + ieeedftos(buf, sizeof(buf), d.hi, d.lo); + Bprint(bioout, "F%-2d %s\t", i, buf); + i++; + d.x = reg.fd[i]; + ieeedftos(buf, sizeof(buf), d.hi, d.lo); + Bprint(bioout, "\tF%-2d %s\n", i, buf); + i++; + } +} + +void * +emalloc(ulong size) +{ + void *a; + + a = malloc(size); + if(a == 0) + fatal(0, "no memory"); + + memset(a, 0, size); + return a; +} + +void * +erealloc(void *a, ulong oldsize, ulong size) +{ + void *n; + + n = malloc(size); + if(n == 0) + fatal(0, "no memory"); + memset(n, 0, size); + if(size > oldsize) + size = oldsize; + memmove(n, a, size); + return n; +} diff --git a/sys/src/cmd/qi/run.c b/sys/src/cmd/qi/run.c new file mode 100755 index 000000000..ea376b956 --- /dev/null +++ b/sys/src/cmd/qi/run.c @@ -0,0 +1,205 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <mach.h> +#define Extern extern +#include "power.h" + + +void lfs(ulong); +void lfd(ulong); +void stfs(ulong); +void stfd(ulong); +/* indexed versions are in 31 */ + +void addic(ulong); +void addiccc(ulong); +void addi(ulong); +void addis(ulong); +void andicc(ulong); +void andiscc(ulong); +void bcx(ulong); +void bx(ulong); +void cmpi(ulong); +void cmpli(ulong); +void lbz(ulong); +void lha(ulong); +void lhz(ulong); +void lmw(ulong); +void lwz(ulong); +void mulli(ulong); +void ori(ulong); +void oris(ulong); +void rlwimi(ulong); +void rlwinm(ulong); +void rlwnm(ulong); +void sc(ulong); +void stb(ulong); +void sth(ulong); +void stmw(ulong); +void stw(ulong); +void subfic(ulong); +void twi(ulong); +void xori(ulong); +void xoris(ulong); + +Inst op0[] = { +[3] {twi, "twi", Ibranch}, +[7] {mulli, "mulli", Iarith}, +[8] {subfic, "subfic", Iarith}, +[10] {cmpli, "cmpli", Iarith}, +[11] {cmpi, "cmpi", Iarith}, +[12] {addic, "addic", Iarith}, +[13] {addiccc, "addic.", Iarith}, +[14] {addi, "addi", Iarith}, +[15] {addis, "addis", Iarith}, +[16] {bcx, "bc⋯", Ibranch}, +[17] {sc, "sc", Isyscall}, +[18] {bx, "b⋯", Ibranch}, +/* group 19; branch unit */ +[20] {rlwimi, "rlwimi", Ilog}, +[21] {rlwinm, "rlwinm", Ilog}, +[23] {rlwnm, "rlwnm", Ilog}, +[24] {ori, "ori", Ilog}, +[25] {oris, "oris", Ilog}, +[26] {xori, "xori", Ilog}, +[27] {xoris, "xoris", Ilog}, +[28] {andicc, "andi.", Ilog}, +[29] {andiscc, "andis.", Ilog}, +/* group 31; integer & misc. */ +[32] {lwz, "lwz", Iload}, +[33] {lwz, "lwzu", Iload}, +[34] {lbz, "lbz", Iload}, +[35] {lbz, "lbzu", Iload}, +[36] {stw, "stw", Istore}, +[37] {stw, "stwu", Istore}, +[38] {stb, "stb", Istore}, +[39] {stb, "stbu", Istore}, +[40] {lhz, "lhz", Iload}, +[41] {lhz, "lhzu", Iload}, +[42] {lha, "lha", Iload}, +[43] {lha, "lhau", Iload}, +[44] {sth, "sth", Istore}, +[45] {sth, "sthu", Istore}, +[46] {lmw, "lmw", Iload}, +[47] {stmw, "stmw", Istore}, +[48] {lfs, "lfs", Iload}, +[49] {lfs, "lfsu", Iload}, +[50] {lfd, "lfd", Iload}, +[51] {lfd, "lfdu", Iload}, +[52] {stfs, "stfs", Istore}, +[53] {stfs, "stfsu", Istore}, +[54] {stfd, "stfd", Istore}, +[55] {stfd, "stfdu", Istore}, +/* group 59; single precision floating point */ +/* group 63; double precision floating point; fpscr */ + {0, 0, 0}, +}; + +Inset ops0 = {op0, nelem(op0)-1}; + +static char oemflag[] = { + [104] 1, + [10] 1, + [136] 1, + [138] 1, + [200] 1, + [202] 1, + [232] 1, + [234] 1, + [235] 1, + [266] 1, + [40] 1, + [459] 1, + [491] 1, + [8] 1, +}; + + +void +run(void) +{ + int xo, f; + + do { + reg.ir = ifetch(reg.pc); + ci = 0; + switch(reg.ir>>26) { + default: + xo = reg.ir>>26; + if(xo >= nelem(op0)) + break; + ci = &op0[xo]; + break; + case 19: + xo = getxo(reg.ir); + if(xo >= ops19.nel) + break; + ci = &ops19.tab[xo]; + break; + case 31: + xo = getxo(reg.ir); + f = xo & ~getxo(OE); + if(reg.ir&OE && f < sizeof(oemflag) && oemflag[f]) + xo = f; + if(xo >= ops31.nel) + break; + ci = &ops31.tab[xo]; + break; + case 59: + xo = getxo(reg.ir) & 0x1F; + if(xo >= ops59.nel) + break; + ci = &ops59.tab[xo]; + break; + case 63: + xo = getxo(reg.ir) & 0x1F; + if(xo < ops63a.nel) { + ci = &ops63a.tab[xo]; + if(ci->func || ci->name) + break; + ci = 0; + } + xo = getxo(reg.ir); + if(xo >= ops63b.nel) + break; + ci = &ops63b.tab[xo]; + break; + } + if(ci && ci->func){ + ci->count++; + (*ci->func)(reg.ir); + } else { + if(ci && ci->name && trace) + itrace("%s\t[not yet done]", ci->name); + else + undef(reg.ir); + } + reg.pc += 4; + if(bplist) + brkchk(reg.pc, Instruction); + }while(--count); +} + +void +ilock(int) +{ +} + +void +undef(ulong ir) +{ +/* Bprint(bioout, "op=%d op2=%d op3=%d\n", ir>>30, (ir>>21)&0x7, (ir>>19)&0x3f); */ + Bprint(bioout, "illegal_instruction IR #%.8lux (op=%ld/%ld, pc=#%.8lux)\n", ir, getop(ir), getxo(ir), reg.pc); + if(ci && ci->name && ci->func==0) + Bprint(bioout, "(%s not yet implemented)\n", ci->name); + longjmp(errjmp, 0); +} + +void +unimp(ulong ir) +{ +/* Bprint(bioout, "op=%d op2=%d op3=%d\n", ir>>30, (ir>>21)&0x7, (ir>>19)&0x3f); */ + Bprint(bioout, "illegal_instruction IR #%.8lux (op=%ld/%ld, pc=#%.8lux) %s not in MPC601\n", ir, getop(ir), getxo(ir), reg.pc, ci->name?ci->name: "-"); + longjmp(errjmp, 0); +} diff --git a/sys/src/cmd/qi/stats.c b/sys/src/cmd/qi/stats.c new file mode 100755 index 000000000..733bca4b8 --- /dev/null +++ b/sys/src/cmd/qi/stats.c @@ -0,0 +1,209 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <mach.h> +#define Extern extern +#include "power.h" + +#define prof profqi +#define Percent(num, max) (int)(((vlong)(num)*100)/(max)) + +Inset *tables[] = { &ops0, &ops19, &ops31, &ops59, &ops63a, &ops63b, 0 }; + +void +isum(void) +{ + Inst *i; + int pct, j, k; + int total, loads, stores, arith, branch; + int taken, powerreg, syscall, realarith, control; + + total = 0; + loads = 0; + stores = 0; + arith = 0; + branch = 0; + taken = 0; + powerreg = 0; + syscall = 0; + realarith = 0; + control = 0; + + /* Compute the total so we can have percentages */ + for(j = 0; tables[j]; j++) + for(k = tables[j]->nel; --k >= 0;) { + i = &tables[j]->tab[k]; + if(i->name && i->func) + total += i->count; + } + + Bprint(bioout, "\nInstruction summary.\n\n"); + + for(j = 0; tables[j]; j++) { + for(k =tables[j]->nel; --k>=0; ) { + i = &tables[j]->tab[k]; + if(i->name && i->func) { + if(i->count == 0) + continue; + pct = Percent(i->count, total); + if(pct != 0) + Bprint(bioout, "%-8ud %3d%% %s\n", + i->count, Percent(i->count, total), i->name); + else + Bprint(bioout, "%-8ud %s\n", + i->count, i->name); + + switch(i->type) { + default: + fatal(0, "isum bad stype %d\n", i->type); + case Iload: + loads += i->count; + break; + case Istore: + stores += i->count; + break; + case Ilog: + case Iarith: + arith += i->count; + break; + case Ibranch: + branch += i->count; + taken += i->taken; + break; + case Ireg: + powerreg += i->count; + break; + case Isyscall: + syscall += i->count; + break; + case Ifloat: + realarith += i->count; + break; + case Inop: + arith += i->count; + i->count -= nopcount; + break; + case Icontrol: + control += i->count; + break; + } + } + } + } + + Bprint(bioout, "\n%-8ud Memory cycles\n", loads+stores+total); + + if(total == 0) + return; + + Bprint(bioout, "%-8ud %3d%% Instruction cycles\n", + total, Percent(total, loads+stores+total)); + + Bprint(bioout, "%-8ud %3d%% Data cycles\n\n", + loads+stores, Percent(loads+stores, loads+stores+total)); + + Bprint(bioout, "%-8ud %3d%% Stores\n", stores, Percent(stores, total)); + + Bprint(bioout, "%-8ud %3d%% Loads\n", loads, Percent(loads, total)); + + Bprint(bioout, " %-8ud Store stall\n", stores*2); + + Bprint(bioout, " %-8lud Load stall\n", loadlock); + + Bprint(bioout, "%-8ud %3d%% Arithmetic\n", arith, Percent(arith, total)); + + Bprint(bioout, "%-8ud %3d%% Floating point\n", + realarith, Percent(realarith, total)); + + Bprint(bioout, "%-8ud %3d%% PowerPC special register load/stores\n", + powerreg, Percent(powerreg, total)); + + Bprint(bioout, "%-8ud %3d%% PowerPC control instructions\n", + control, Percent(control, total)); + + Bprint(bioout, "%-8ud %3d%% System calls\n", syscall, Percent(syscall, total)); + + Bprint(bioout, "%-8ud %3d%% Branches\n", branch, Percent(branch, total)); + + Bprint(bioout, " %-8ud %3d%% Branches taken\n", + taken, Percent(taken, branch)); +} + +char *stype[] = { "Stack", "Text", "Data", "Bss" }; + +void +segsum(void) +{ + Segment *s; + int i; + + Bprint(bioout, "\n\nMemory Summary\n\n"); + Bprint(bioout, " Base End Resident References\n"); + for(i = 0; i < Nseg; i++) { + s = &memory.seg[i]; + Bprint(bioout, "%-5s %.8lux %.8lux %-8d %-8d\n", + stype[i], s->base, s->end, s->rss*BY2PG, s->refs); + } +} + +typedef struct Prof Prof; +struct Prof +{ + Symbol s; + long count; +}; +Prof prof[5000]; + +int +profcmp(void *a, void *b) +{ + return ((Prof*)b)->count - ((Prof*)a)->count; +} + +void +iprofile(void) +{ + Prof *p, *n; + int i, b, e; + ulong total; + extern ulong textbase; + + i = 0; + p = prof; + if(textsym(&p->s, i) == 0) + return; + i++; + for(;;) { + n = p+1; + if(textsym(&n->s, i) == 0) + break; + b = (p->s.value-textbase)/PROFGRAN; + e = (n->s.value-textbase)/PROFGRAN; + while(b < e) + p->count += iprof[b++]; + i++; + p = n; + } + + qsort(prof, i, sizeof(Prof), profcmp); + + total = 0; + for(b = 0; b < i; b++) + total += prof[b].count; + + Bprint(bioout, " cycles %% symbol file\n"); + for(b = 0; b < i; b++) { + if(prof[b].count == 0) + continue; + + Bprint(bioout, "%8ld %3ld.%ld %-15s ", + prof[b].count, + 100*prof[b].count/total, + (1000*prof[b].count/total)%10, + prof[b].s.name); + + printsource(prof[b].s.value); + Bputc(bioout, '\n'); + } + memset(prof, 0, sizeof(Prof)*i); +} diff --git a/sys/src/cmd/qi/symbols.c b/sys/src/cmd/qi/symbols.c new file mode 100755 index 000000000..01727b0cd --- /dev/null +++ b/sys/src/cmd/qi/symbols.c @@ -0,0 +1,97 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <mach.h> +#define Extern extern +#include "power.h" + +#define STRINGSZ 128 + +/* + * print the value of dot as file:line + */ +void +printsource(long dot) +{ + char str[STRINGSZ]; + + if (fileline(str, STRINGSZ, dot)) + Bprint(bioout, "%s", str); +} + +void +printlocals(Symbol *fn, ulong fp) +{ + int i; + Symbol s; + + s = *fn; + for (i = 0; localsym(&s, i); i++) { + if (s.class != CAUTO) + continue; + Bprint(bioout, "\t%s=#%lux\n", s.name, getmem_4(fp-s.value)); + } +} + +void +printparams(Symbol *fn, ulong fp) +{ + int i; + Symbol s; + int first; + + fp += mach->szreg; /* skip saved pc */ + s = *fn; + for (first = i = 0; localsym(&s, i); i++) { + if (s.class != CPARAM) + continue; + if (first++) + Bprint(bioout, ", "); + Bprint(bioout, "%s=#%lux", s.name, getmem_4(fp+s.value)); + } + Bprint(bioout, ") "); +} + +#define STARTSYM "_main" +#define FRAMENAME ".frame" + +void +stktrace(int modif) +{ + ulong pc, sp; + Symbol s, f; + int i; + char buf[512]; + + pc = reg.pc; + sp = reg.r[1]; + i = 0; + while (findsym(pc, CTEXT, &s)) { + if(strcmp(STARTSYM, s.name) == 0) { + Bprint(bioout, "%s() at #%llux\n", s.name, s.value); + break; + } + if (pc == s.value) /* at first instruction */ + f.value = 0; + else if (findlocal(&s, FRAMENAME, &f) == 0) + break; + if (s.type == 'L' || s.type == 'l' || pc <= s.value+4) + pc = reg.lr; + else pc = getmem_4(sp); + sp += f.value; + Bprint(bioout, "%s(", s.name); + printparams(&s, sp); + printsource(s.value); + Bprint(bioout, " called from "); + symoff(buf, sizeof(buf), pc-4, CTEXT); + Bprint(bioout, buf); + printsource(pc-8); + Bprint(bioout, "\n"); + if(modif == 'C') + printlocals(&s, sp); + if(++i > 40){ + Bprint(bioout, "(trace truncated)\n"); + break; + } + } +} diff --git a/sys/src/cmd/qi/syscall.c b/sys/src/cmd/qi/syscall.c new file mode 100755 index 000000000..0c5a82cca --- /dev/null +++ b/sys/src/cmd/qi/syscall.c @@ -0,0 +1,740 @@ +#include <u.h> +#include <libc.h> +#include <auth.h> +#include <bio.h> +#include <mach.h> +#define Extern extern +#include "power.h" + + +#define REGSP 1 +#define REGRET 3 + +#define ODIRLEN 116 /* compatibility; used in _stat etc. */ +#define OERRLEN 64 /* compatibility; used in _stat etc. */ + +char errbuf[ERRMAX]; +ulong nofunc; + +#include "/sys/src/libc/9syscall/sys.h" + +char *sysctab[]={ + [SYSR1] "SYSR1", + [_ERRSTR] "_errstr", + [BIND] "Bind", + [CHDIR] "Chdir", + [CLOSE] "Close", + [DUP] "Dup", + [ALARM] "Alarm", + [EXEC] "Exec", + [EXITS] "Exits", + [_FSESSION] "_Fsession", + [FAUTH] "Fauth", + [_FSTAT] "_fstat", + [SEGBRK] "Segbrk", + [_MOUNT] "_Mount", + [OPEN] "Open", + [_READ] "_Read", + [OSEEK] "Oseek", + [SLEEP] "Sleep", + [_STAT] "_Stat", + [RFORK] "Rfork", + [_WRITE] "_Write", + [PIPE] "Pipe", + [CREATE] "Create", + [FD2PATH] "Fd2path", + [BRK_] "Brk_", + [REMOVE] "Remove", + [_WSTAT] "_Wstat", + [_FWSTAT] "_Fwstat", + [NOTIFY] "Notify", + [NOTED] "Noted", + [SEGATTACH] "Segattach", + [SEGDETACH] "Segdetach", + [SEGFREE] "Segfree", + [SEGFLUSH] "Segflush", + [RENDEZVOUS] "Rendezvous", + [UNMOUNT] "Unmount", + [_WAIT] "Wait", + [SEEK] "Seek", + [FVERSION] "Fversion", + [ERRSTR] "Errstr", + [STAT] "Stat", + [FSTAT] "Fstat", + [WSTAT] "Wstat", + [FWSTAT] "Fwstat", + [MOUNT] "Mount", + [AWAIT] "Await", + [PREAD] "Pread", + [PWRITE] "Pwrite", +}; + +void sys1(void) { Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGRET]]); exits(0); } + +void +sys_errstr(void) +{ + ulong str; + char tmp[OERRLEN]; + + str = getmem_w(reg.r[REGSP]+4); + if(sysdbg) + itrace("errstr(0x%lux)", str); + + memio(tmp, str, OERRLEN, MemRead); + memio(errbuf, str, OERRLEN, MemWrite); + memmove(errbuf, tmp, OERRLEN); + errbuf[OERRLEN-1] = 0; + reg.r[REGRET] = 0; +} + +void +syserrstr(void) +{ + ulong str; + uint n; + char tmp[ERRMAX]; + + str = getmem_w(reg.r[REGSP]+4); + n = getmem_w(reg.r[REGSP]+8); + if(sysdbg) + itrace("errstr(0x%lux, 0x%lux)", str, n); + + if(n > strlen(errbuf)+1) + n = strlen(errbuf)+1; + if(n > ERRMAX) + n = ERRMAX; + memio(tmp, str, n, MemRead); + memio(errbuf, str, n, MemWrite); + memmove(errbuf, tmp, n); + errbuf[ERRMAX-1] = 0; + reg.r[REGRET] = n; + +} + +void +sysfd2path(void) +{ + int n; + uint fd; + ulong str; + char buf[1024]; + + fd = getmem_w(reg.r[REGSP]+4); + str = getmem_w(reg.r[REGSP]+8); + n = getmem_w(reg.r[REGSP]+12); + if(sysdbg) + itrace("fd2path(0x%lux, 0x%lux, 0x%lux)", fd, str, n); + reg.r[REGRET] = -1; + if(n > sizeof buf){ + strcpy(errbuf, "buffer too big"); + return; + } + n = fd2path(fd, buf, sizeof buf); + if(n < 0) + errstr(buf, sizeof buf); + else + memio(errbuf, str, n, MemWrite); + reg.r[REGRET] = n; + +} + +void +sysbind(void) +{ + ulong pname, pold, flags; + char name[1024], old[1024]; + int n; + + pname = getmem_w(reg.r[REGSP]+4); + pold = getmem_w(reg.r[REGSP]+8); + flags = getmem_w(reg.r[REGSP]+12); + memio(name, pname, sizeof(name), MemReadstring); + memio(old, pold, sizeof(old), MemReadstring); + if(sysdbg) + itrace("bind(0x%lux='%s', 0x%lux='%s', 0x%lux)", name, old, flags); + + n = bind(name, old, flags); + if(n < 0) + errstr(errbuf, sizeof errbuf); + + reg.r[REGRET] = n; +} + +void +syschdir(void) +{ + char file[1024]; + int n; + ulong name; + + name = getmem_w(reg.r[REGSP]+4); + memio(file, name, sizeof(file), MemReadstring); + if(sysdbg) + itrace("chdir(0x%lux='%s', 0x%lux)", name, file); + + n = chdir(file); + if(n < 0) + errstr(errbuf, sizeof errbuf); + + reg.r[REGRET] = n; +} + +void +sysclose(void) +{ + int n; + ulong fd; + + fd = getmem_w(reg.r[REGSP]+4); + if(sysdbg) + itrace("close(%d)", fd); + + n = close(fd); + if(n < 0) + errstr(errbuf, sizeof errbuf); + reg.r[REGRET] = n; +} + +void +sysdup(void) +{ + int oldfd, newfd; + int n; + + oldfd = getmem_w(reg.r[REGSP]+4); + newfd = getmem_w(reg.r[REGSP]+8); + if(sysdbg) + itrace("dup(%d, %d)", oldfd, newfd); + + n = dup(oldfd, newfd); + if(n < 0) + errstr(errbuf, sizeof errbuf); + reg.r[REGRET] = n; +} + +void +sysexits(void) +{ + char buf[ERRMAX]; + ulong str; + + str = getmem_w(reg.r[REGSP]+4); + if(sysdbg) + itrace("exits(0x%lux)", str); + + count = 1; + if(str != 0) { + memio(buf, str, sizeof buf, MemRead); + buf[ERRMAX-1] = 0; + Bprint(bioout, "exits(%s)\n", buf); + } + else + Bprint(bioout, "exits(0)\n"); +} + +void +sysopen(void) +{ + char file[1024]; + int n; + ulong mode, name; + + name = getmem_w(reg.r[REGSP]+4); + mode = getmem_w(reg.r[REGSP]+8); + memio(file, name, sizeof(file), MemReadstring); + if(sysdbg) + itrace("open(0x%lux='%s', 0x%lux)", name, file, mode); + + n = open(file, mode); + if(n < 0) + errstr(errbuf, sizeof errbuf); + + reg.r[REGRET] = n; +}; + +void +sysread(vlong offset) +{ + int fd; + ulong size, a; + char *buf, *p; + int n, cnt, c; + + fd = getmem_w(reg.r[REGSP]+4); + a = getmem_w(reg.r[REGSP]+8); + size = getmem_w(reg.r[REGSP]+12); + + buf = emalloc(size); + if(fd == 0) { + print("\nstdin>>"); + p = buf; + n = 0; + cnt = size; + while(cnt) { + c = Bgetc(bin); + if(c <= 0) + break; + *p++ = c; + n++; + cnt--; + if(c == '\n') + break; + } + } + else + n = pread(fd, buf, size, offset); + + if(n < 0) + errstr(errbuf, sizeof errbuf); + else + memio(buf, a, n, MemWrite); + + if(sysdbg) + itrace("read(%d, 0x%lux, %d, 0x%llx) = %d", fd, a, size, offset, n); + + free(buf); + reg.r[REGRET] = n; +} + +void +sys_read(void) +{ + sysread(-1LL); +} + +void +syspread(void) +{ + union { + vlong v; + ulong u[2]; + } o; + + o.u[0] = getmem_w(reg.r[REGSP]+16); + o.u[1] = getmem_w(reg.r[REGSP]+20); + sysread(o.v); +} + +void +sysseek(void) +{ + int fd; + ulong mode; + ulong retp; + union { + vlong v; + ulong u[2]; + } o; + + retp = getmem_w(reg.r[REGSP]+4); + fd = getmem_w(reg.r[REGSP]+8); + o.u[0] = getmem_w(reg.r[REGSP]+12); + o.u[1] = getmem_w(reg.r[REGSP]+16); + mode = getmem_w(reg.r[REGSP]+20); + if(sysdbg) + itrace("seek(%d, %lld, %d)", fd, o.v, mode); + + o.v = seek(fd, o.v, mode); + if(o.v < 0) + errstr(errbuf, sizeof errbuf); + + memio((char*)o.u, retp, sizeof(vlong), MemWrite); +} + +void +sysoseek(void) +{ + int fd, n; + ulong off, mode; + + fd = getmem_w(reg.r[REGSP]+4); + off = getmem_w(reg.r[REGSP]+8); + mode = getmem_w(reg.r[REGSP]+12); + if(sysdbg) + itrace("seek(%d, %lud, %d)", fd, off, mode); + + n = seek(fd, off, mode); + if(n < 0) + errstr(errbuf, sizeof errbuf); + + reg.r[REGRET] = n; +} + +void +sysrfork(void) +{ + int flag; + + flag = getmem_w(reg.r[REGSP]+4); + if(sysdbg) + itrace("rfork(%d)", flag); + if(flag & RFPROC) { + Bprint(bioout, "rfork: cannot create process, rfork(0x%.8ux)\n", flag); + exits(0); + } + reg.r[REGRET] = rfork(flag); +} + +void +syssleep(void) +{ + ulong len; + int n; + + len = getmem_w(reg.r[REGSP]+4); + if(sysdbg) + itrace("sleep(%d)", len); + + n = sleep(len); + if(n < 0) + errstr(errbuf, sizeof errbuf); + + reg.r[REGRET] = n; +} + +void +sys_stat(void) +{ + char nambuf[1024]; + char buf[ODIRLEN]; + ulong edir, name; + extern int _stat(char*, char*); /* old system call */ + int n; + + name = getmem_w(reg.r[REGSP]+4); + edir = getmem_w(reg.r[REGSP]+8); + memio(nambuf, name, sizeof(nambuf), MemReadstring); + if(sysdbg) + itrace("stat(0x%lux='%s', 0x%lux)", name, nambuf, edir); + + n = _stat(nambuf, buf); + if(n < 0) + errstr(errbuf, sizeof errbuf); + else + memio(buf, edir, ODIRLEN, MemWrite); + + reg.r[REGRET] = n; +} + +void +sysstat(void) +{ + char nambuf[1024]; + uchar buf[STATMAX]; + ulong edir, name; + int n; + + name = getmem_w(reg.r[REGSP]+4); + edir = getmem_w(reg.r[REGSP]+8); + n = getmem_w(reg.r[REGSP]+12); + memio(nambuf, name, sizeof(nambuf), MemReadstring); + if(sysdbg) + itrace("stat(0x%lux='%s', 0x%lux, 0x%lux)", name, nambuf, edir, n); + if(n > sizeof buf) + errstr(errbuf, sizeof errbuf); + else{ + n = stat(nambuf, buf, n); + if(n < 0) + errstr(errbuf, sizeof errbuf); + else + memio((char*)buf, edir, n, MemWrite); + } + reg.r[REGRET] = n; +} + +void +sys_fstat(void) +{ + char buf[ODIRLEN]; + ulong edir; + extern int _fstat(int, char*); /* old system call */ + int n, fd; + + fd = getmem_w(reg.r[REGSP]+4); + edir = getmem_w(reg.r[REGSP]+8); + if(sysdbg) + itrace("fstat(%d, 0x%lux)", fd, edir); + + n = _fstat(fd, buf); + if(n < 0) + errstr(errbuf, sizeof errbuf); + else + memio(buf, edir, ODIRLEN, MemWrite); + + reg.r[REGRET] = n; +} + +void +sysfstat(void) +{ + uchar buf[STATMAX]; + ulong edir; + int n, fd; + + fd = getmem_w(reg.r[REGSP]+4); + edir = getmem_w(reg.r[REGSP]+8); + n = getmem_w(reg.r[REGSP]+12); + if(sysdbg) + itrace("fstat(%d, 0x%lux, 0x%lux)", fd, edir, n); + + reg.r[REGRET] = -1; + if(n > sizeof buf){ + strcpy(errbuf, "stat buffer too big"); + return; + } + n = fstat(fd, buf, n); + if(n < 0) + errstr(errbuf, sizeof errbuf); + else + memio((char*)buf, edir, n, MemWrite); + reg.r[REGRET] = n; +} + +void +syswrite(vlong offset) +{ + int fd; + ulong size, a; + char *buf; + int n; + + fd = getmem_w(reg.r[REGSP]+4); + a = getmem_w(reg.r[REGSP]+8); + size = getmem_w(reg.r[REGSP]+12); + + Bflush(bioout); + buf = memio(0, a, size, MemRead); + n = pwrite(fd, buf, size, offset); + if(n < 0) + errstr(errbuf, sizeof errbuf); + if(sysdbg) + itrace("write(%d, %lux, %d, 0xllx) = %d", fd, a, size, offset, n); + free(buf); + + reg.r[REGRET] = n; +} + +void +sys_write(void) +{ + syswrite(-1LL); +} + +void +syspwrite(void) +{ + union { + vlong v; + ulong u[2]; + } o; + + o.u[0] = getmem_w(reg.r[REGSP]+16); + o.u[1] = getmem_w(reg.r[REGSP]+20); + syswrite(o.v); +} + +void +syspipe(void) +{ + int n, p[2]; + ulong fd; + + fd = getmem_w(reg.r[REGSP]+4); + if(sysdbg) + itrace("pipe(%lux)", fd); + + n = pipe(p); + if(n < 0) + errstr(errbuf, sizeof errbuf); + else { + putmem_w(fd, p[0]); + putmem_w(fd+4, p[1]); + } + reg.r[REGRET] = n; +} + +void +syscreate(void) +{ + char file[1024]; + int n; + ulong mode, name, perm; + + name = getmem_w(reg.r[REGSP]+4); + mode = getmem_w(reg.r[REGSP]+8); + perm = getmem_w(reg.r[REGSP]+12); + memio(file, name, sizeof(file), MemReadstring); + if(sysdbg) + itrace("create(0x%lux='%s', 0x%lux, 0x%lux)", name, file, mode, perm); + + n = create(file, mode, perm); + if(n < 0) + errstr(errbuf, sizeof errbuf); + + reg.r[REGRET] = n; +} + +void +sysbrk_(void) +{ + ulong addr, osize, nsize; + Segment *s; + + addr = getmem_w(reg.r[REGSP]+4); + if(sysdbg) + itrace("brk_(0x%lux)", addr); + + reg.r[REGRET] = -1; + if(addr < memory.seg[Data].base+datasize) { + strcpy(errbuf, "address below segment"); + return; + } + if(addr > memory.seg[Stack].base) { + strcpy(errbuf, "segment too big"); + return; + } + s = &memory.seg[Bss]; + if(addr > s->end) { + osize = ((s->end-s->base)/BY2PG)*sizeof(uchar*); + addr = ((addr)+(BY2PG-1))&~(BY2PG-1); + s->end = addr; + nsize = ((s->end-s->base)/BY2PG)*sizeof(uchar*); + s->table = erealloc(s->table, osize, nsize); + } + + reg.r[REGRET] = 0; +} + +void +sysremove(void) +{ + char nambuf[1024]; + ulong name; + int n; + + name = getmem_w(reg.r[REGSP]+4); + memio(nambuf, name, sizeof(nambuf), MemReadstring); + if(sysdbg) + itrace("remove(0x%lux='%s')", name, nambuf); + + n = remove(nambuf); + if(n < 0) + errstr(errbuf, sizeof errbuf); + reg.r[REGRET] = n; +} + +void +sysnotify(void) +{ + nofunc = getmem_w(reg.r[REGSP]+4); + if(sysdbg) + itrace("notify(0x%lux)", nofunc); + + reg.r[REGRET] = 0; +} + +void +syssegflush(void) +{ + ulong start, len; + + start = getmem_w(reg.r[REGSP]+4); + len = getmem_w(reg.r[REGSP]+8); + if(sysdbg) + itrace("segflush(va=0x%lux, n=%lud)", start, len); + reg.r[REGRET] = 0; +} + +void sysfversion(void) { Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGRET]]); exits(0); } +void sysfsession(void) { Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGRET]]); exits(0); } +void sysfauth(void) { Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGRET]]); exits(0); } +void syswait(void) { Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGRET]]); exits(0); } +void syswstat(void) { Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGRET]]); exits(0);} +void sys_wstat(void) { Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGRET]]); exits(0);} +void sysfwstat(void) { Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGRET]]); exits(0);} +void sys_fwstat(void) { Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGRET]]); exits(0);} +void sysnoted(void) { Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGRET]]); exits(0);} +void syssegattach(void) { Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGRET]]); exits(0);} +void syssegdetach(void) { Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGRET]]); exits(0);} +void syssegfree(void) { Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGRET]]); exits(0);} +void sysrendezvous(void) { Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGRET]]); exits(0);} +void sysunmount(void) { Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGRET]]); exits(0);} +void sysfork(void) { Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGRET]]); exits(0);} +void sysforkpgrp(void) { Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGRET]]); exits(0);} +void syssegbrk(void) { Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGRET]]); exits(0);} +void _sysmount(void) { Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGRET]]); exits(0);} +void sysalarm(void) { Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGRET]]); exits(0);} +void sysexec(void) { Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGRET]]); exits(0);} +void sysmount(void) { Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGRET]]); exits(0);} +void sysawait(void) { Bprint(bioout, "No system call %s\n", sysctab[reg.r[REGRET]]); exits(0);} + +void (*systab[])(void) ={ + [SYSR1] sys1, + [_ERRSTR] sys_errstr, + [BIND] sysbind, + [CHDIR] syschdir, + [CLOSE] sysclose, + [DUP] sysdup, + [ALARM] sysalarm, + [EXEC] sysexec, + [EXITS] sysexits, + [_FSESSION] sysfsession, + [FAUTH] sysfauth, + [_FSTAT] sys_fstat, + [SEGBRK] syssegbrk, + [_MOUNT] _sysmount, + [OPEN] sysopen, + [_READ] sys_read, + [OSEEK] sysoseek, + [SLEEP] syssleep, + [_STAT] sys_stat, + [RFORK] sysrfork, + [_WRITE] sys_write, + [PIPE] syspipe, + [CREATE] syscreate, + [FD2PATH] sysfd2path, + [BRK_] sysbrk_, + [REMOVE] sysremove, + [_WSTAT] sys_wstat, + [_FWSTAT] sys_fwstat, + [NOTIFY] sysnotify, + [NOTED] sysnoted, + [SEGATTACH] syssegattach, + [SEGDETACH] syssegdetach, + [SEGFREE] syssegfree, + [SEGFLUSH] syssegflush, + [RENDEZVOUS] sysrendezvous, + [UNMOUNT] sysunmount, + [_WAIT] syswait, + [SEEK] sysseek, + [FVERSION] sysfversion, + [ERRSTR] syserrstr, + [STAT] sysstat, + [FSTAT] sysfstat, + [WSTAT] syswstat, + [FWSTAT] sysfwstat, + [MOUNT] sysmount, + [AWAIT] sysawait, + [PREAD] syspread, + [PWRITE] syspwrite, +}; + +void +sc(ulong inst) +{ + int call; + + if(inst != ((17<<26)|2)) + undef(inst); + call = reg.r[REGRET]; + if(call < 0 || call > PWRITE || systab[call] == nil) { + Bprint(bioout, "Bad system call\n"); + dumpreg(); + } + if(trace) + itrace("sc\t(%s)", sysctab[call]); + + (*systab[call])(); + Bflush(bioout); +} diff --git a/sys/src/cmd/qi/timing b/sys/src/cmd/qi/timing new file mode 100755 index 000000000..dd746eb68 --- /dev/null +++ b/sys/src/cmd/qi/timing @@ -0,0 +1,27 @@ +units + branch + integer + floating point +on 601 + issue at most one per unit per cycle + eight entry instruction queue + can fill queue from cache in one clock cycle + loads from requested address to end of cache block +pipeline + prefetch + includes ins. cache access cycles + decode + execute + writeback + +fpu + IQ[3210] → fpu buffer/decode [≥1 cycle] → execute 1 → execute 2 → writeback +iu + IQ0/decode → buffer [if exec busy] → execute [hold for dependency] → + circulate in load/store + writeback +bpu + IQ[3210] → decode/execute → writeback + +notes + address calculation must complete before stored value enters write buffer |