summaryrefslogtreecommitdiff
path: root/sys/src/cmd/qi
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/qi
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/qi')
-rwxr-xr-xsys/src/cmd/qi/bpt.c129
-rwxr-xr-xsys/src/cmd/qi/branch.c272
-rwxr-xr-xsys/src/cmd/qi/cmd.c644
-rwxr-xr-xsys/src/cmd/qi/float.c741
-rwxr-xr-xsys/src/cmd/qi/icache.c18
-rwxr-xr-xsys/src/cmd/qi/iu.c2029
-rwxr-xr-xsys/src/cmd/qi/mem.c271
-rwxr-xr-xsys/src/cmd/qi/mkfile29
-rwxr-xr-xsys/src/cmd/qi/power.h285
-rwxr-xr-xsys/src/cmd/qi/qi.c423
-rwxr-xr-xsys/src/cmd/qi/run.c205
-rwxr-xr-xsys/src/cmd/qi/stats.c209
-rwxr-xr-xsys/src/cmd/qi/symbols.c97
-rwxr-xr-xsys/src/cmd/qi/syscall.c740
-rwxr-xr-xsys/src/cmd/qi/timing27
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, &reg.ctr, 1);
+}
+
+void
+bclr(ulong ir)
+{
+ dobranch(ir, &reg.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 = &reg.xer; n = "xer";
+ break;
+ case 268:
+ case 284:
+ d = &reg.tbl; n = "tbl";
+ break;
+ case 269:
+ case 285:
+ d = &reg.tbu; n = "tbu";
+ break;
+ case 22:
+ d = &reg.dec; n = "dec";
+ break;
+ case 8:
+ d = &reg.lr; n = "lr";
+ break;
+ case 9:
+ d = &reg.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(&reg, 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