Browse Source

Plan 9 from Bell Labs 2004-02-14

David du Colombier 20 years ago
parent
commit
b04da4770a

+ 19 - 3
dist/replica/plan9.db

@@ -4731,7 +4731,7 @@ sys/man/1/uniq - 664 sys sys 944959674 995
 sys/man/1/units - 664 sys sys 944959673 2049
 sys/man/1/uptime - 664 sys sys 1074733782 380
 sys/man/1/vac - 664 sys sys 1021579977 3227
-sys/man/1/vi - 664 sys sys 1015024741 2920
+sys/man/1/vi - 664 sys sys 1076688637 2980
 sys/man/1/vnc - 664 sys sys 1045501432 4186
 sys/man/1/vt - 664 sys sys 1018386774 2210
 sys/man/1/wc - 664 sys sys 944959675 908
@@ -9597,7 +9597,7 @@ sys/src/cmd/ki/run.c - 664 sys sys 944961015 22231
 sys/src/cmd/ki/sparc.h - 664 sys sys 944961015 4419
 sys/src/cmd/ki/stats.c - 664 sys sys 1068859845 4536
 sys/src/cmd/ki/symbols.c - 664 sys sys 944961015 1744
-sys/src/cmd/ki/syscall.c - 664 sys sys 1014925953 14072
+sys/src/cmd/ki/syscall.c - 664 sys sys 1076688578 14057
 sys/src/cmd/kl - 20000000775 sys sys 944961016 0
 sys/src/cmd/kl/asm.c - 664 sys sys 1045503967 26003
 sys/src/cmd/kl/compat.c - 664 sys sys 947099591 465
@@ -10132,6 +10132,22 @@ sys/src/cmd/qc/reg.c - 664 sys sys 1014936817 19024
 sys/src/cmd/qc/sgen.c - 664 sys sys 952627604 8742
 sys/src/cmd/qc/swt.c - 664 sys sys 984718309 11266
 sys/src/cmd/qc/txt.c - 664 sys sys 1067720684 20029
+sys/src/cmd/qi - 20000000775 sys sys 1076688570 0
+sys/src/cmd/qi/bpt.c - 644 sys sys 1076688568 2247
+sys/src/cmd/qi/branch.c - 644 sys sys 1076688568 4696
+sys/src/cmd/qi/cmd.c - 644 sys sys 1076688568 9114
+sys/src/cmd/qi/float.c - 644 sys sys 1076688568 12703
+sys/src/cmd/qi/icache.c - 644 sys sys 1076688569 185
+sys/src/cmd/qi/iu.c - 644 sys sys 1076688569 32978
+sys/src/cmd/qi/mem.c - 644 sys sys 1076688569 4429
+sys/src/cmd/qi/mkfile - 644 sys sys 1076688569 214
+sys/src/cmd/qi/power.h - 644 sys sys 1076688569 6854
+sys/src/cmd/qi/qi.c - 644 sys sys 1076688569 7804
+sys/src/cmd/qi/run.c - 644 sys sys 1076688569 4173
+sys/src/cmd/qi/stats.c - 644 sys sys 1076688569 4338
+sys/src/cmd/qi/symbols.c - 644 sys sys 1076688569 1741
+sys/src/cmd/qi/syscall.c - 644 sys sys 1076688569 14402
+sys/src/cmd/qi/timing - 644 sys sys 1076688570 641
 sys/src/cmd/ql - 20000000775 sys sys 954037972 0
 sys/src/cmd/ql/asm.c - 664 sys sys 1055699283 12469
 sys/src/cmd/ql/asmout.c - 664 sys sys 1055699283 30140
@@ -11034,7 +11050,7 @@ sys/src/cmd/vi/run.c - 664 sys sys 1014926560 13214
 sys/src/cmd/vi/special.c - 664 sys sys 944961342 6723
 sys/src/cmd/vi/stats.c - 664 sys sys 1067746789 5386
 sys/src/cmd/vi/symbols.c - 664 sys sys 944961342 1743
-sys/src/cmd/vi/syscall.c - 664 sys sys 1014926560 14180
+sys/src/cmd/vi/syscall.c - 664 sys sys 1076688599 14165
 sys/src/cmd/vi/vi.c - 664 sys sys 1014926560 8924
 sys/src/cmd/vl - 20000000775 sys sys 944961343 0
 sys/src/cmd/vl/asm.c - 664 sys sys 1055699754 30723

+ 19 - 0
dist/replica/plan9.log

@@ -13821,3 +13821,22 @@
 1076614318 0 c sys/src/9/ip/tcp.c - 664 sys sys 1076613357 65462
 1076614318 1 c sys/src/cmd/tail.c - 664 sys sys 1076614068 5990
 1076644923 0 c 386/bin/tail - 775 sys sys 1076644755 64896
+1076689810 0 c sys/man/1/vi - 664 sys sys 1076688637 2980
+1076689810 1 c sys/src/cmd/ki/syscall.c - 664 sys sys 1076688578 14057
+1076689810 2 c sys/src/cmd/vi/syscall.c - 664 sys sys 1076688599 14165
+1076689810 3 a sys/src/cmd/qi - 20000000775 sys sys 1076688570 0
+1076689810 4 a sys/src/cmd/qi/bpt.c - 644 sys sys 1076688568 2247
+1076689810 5 a sys/src/cmd/qi/branch.c - 644 sys sys 1076688568 4696
+1076689810 6 a sys/src/cmd/qi/cmd.c - 644 sys sys 1076688568 9114
+1076689810 7 a sys/src/cmd/qi/float.c - 644 sys sys 1076688568 12703
+1076689810 8 a sys/src/cmd/qi/icache.c - 644 sys sys 1076688569 185
+1076689810 9 a sys/src/cmd/qi/iu.c - 644 sys sys 1076688569 32978
+1076689810 10 a sys/src/cmd/qi/mem.c - 644 sys sys 1076688569 4429
+1076689810 11 a sys/src/cmd/qi/mkfile - 644 sys sys 1076688569 214
+1076689810 12 a sys/src/cmd/qi/power.h - 644 sys sys 1076688569 6854
+1076689810 13 a sys/src/cmd/qi/qi.c - 644 sys sys 1076688569 7804
+1076689810 14 a sys/src/cmd/qi/run.c - 644 sys sys 1076688569 4173
+1076689810 15 a sys/src/cmd/qi/stats.c - 644 sys sys 1076688569 4338
+1076689810 16 a sys/src/cmd/qi/symbols.c - 644 sys sys 1076688569 1741
+1076689810 17 a sys/src/cmd/qi/syscall.c - 644 sys sys 1076688569 14402
+1076689810 18 a sys/src/cmd/qi/timing - 644 sys sys 1076688570 641

+ 12 - 3
sys/man/1/vi

@@ -1,6 +1,6 @@
 .TH VI 1
 .SH NAME
-0i, 5i, ki, vi \- instruction simulators
+0i, 5i, ki, vi, qi \- instruction simulators
 .SH SYNOPSIS
 .B vi
 [
@@ -33,6 +33,14 @@
 .br
 .B ki
 .I pid
+.br
+.B qi
+[
+.I textfile
+]
+.br
+.B qi
+.I pid
 .SH DESCRIPTION
 .I Vi
 simulates the execution of a MIPS binary in
@@ -47,11 +55,12 @@ single stepping under
 .IR db .
 .IR 0i ,
 .IR 5i ,
+.IR ki ,
 and
-.IR ki
+.IR qi
 are similar to
 .I vi
-but interpret little-endian MIPS, ARM 7500, and SPARC binaries.
+but interpret little-endian MIPS, ARM, SPARC, and PowerPC binaries.
 The following discussion refers to
 .I vi
 but applies to the others

+ 3 - 3
sys/src/cmd/ki/syscall.c

@@ -301,7 +301,7 @@ syspread(void)
 	} o;
 
 	o.u[0] = getmem_w(reg.r[REGSP]+16);
-	o.u[REGRET] = getmem_w(reg.r[REGSP]+20);
+	o.u[1] = getmem_w(reg.r[REGSP]+20);
 	sysread(o.v);
 }
 
@@ -319,7 +319,7 @@ sysseek(void)
 	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[REGRET] = getmem_w(reg.r[REGSP]+16);
+	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);
@@ -519,7 +519,7 @@ syspwrite(void)
 	} o;
 
 	o.u[0] = getmem_w(reg.r[REGSP]+16);
-	o.u[REGRET] = getmem_w(reg.r[REGSP]+20);
+	o.u[1] = getmem_w(reg.r[REGSP]+20);
 	syswrite(o.v);
 }
 

+ 129 - 0
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;
+			}
+		}
+	}	
+}

+ 272 - 0
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");
+}

+ 644 - 0
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;
+		}
+	}
+}

+ 702 - 0
sys/src/cmd/qi/float.c

@@ -0,0 +1,702 @@
+#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
+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.dv[rd] = 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.dv[rd] = 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, reg.dv[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, reg.dv[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;
+
+	getarrr(ir);
+	if(ra || rb)
+		undef(ir);
+	reg.dv[rd] = ((uvlong)0xFFF8000L<<16)|reg.fpscr;
+	/* 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;
+	ulong v;
+
+	if(ir & ((1L << 25)|(1L << 16)))
+		undef(ir);
+	rb = (ir >> 11) & 0x1F;
+	fm = (ir >> 17) & 0xFF;
+	v = reg.dv[rb];
+	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.dv[rd] = 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 */
+}

+ 18 - 0
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);
+}
+

+ 2027 - 0
sys/src/cmd/qi/iu.c

@@ -0,0 +1,2027 @@
+#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);
+		reg.r[rd] = *d;
+	} else {
+		if(trace)
+			itrace("%s\t%s,r%d", ci->name, n, rd);
+		*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] + reg.r[rb];
+	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
+addc(ulong ir)
+{
+	int rd, ra, rb;
+	ulong v;
+	uvlong r;
+
+	getarrr(ir);
+	r = (uvlong)(ulong)reg.r[ra] + 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] + 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] + 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] + 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] + 0xFFFFFFFF + (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]) + 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]) + 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]) + 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]) + 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]) + 0xFFFFFFFF + (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);
+}

+ 271 - 0
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*/
+}

+ 20 - 0
sys/src/cmd/qi/mkfile

@@ -0,0 +1,20 @@
+</$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
+</sys/src/cmd/mkone

+ 302 - 0
sys/src/cmd/qi/power.h

@@ -0,0 +1,302 @@
+/*
+ * 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 Mul Mul;
+typedef struct Mulu Mulu;
+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;
+
+	union {
+		double	fd[32];
+		uvlong	dv[32];
+	};
+};
+
+struct Mulu{
+	ulong lo;
+	ulong hi;
+};
+
+struct Mul{
+	long lo;
+	long hi;
+};
+
+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		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);
+Mul		mul(long, long);
+Mulu		mulu(ulong, ulong);
+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

+ 427 - 0
sys/src/cmd/qi/qi.c

@@ -0,0 +1,427 @@
+#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);
+
+	reg.fd[27] = 4503601774854144.0;
+	reg.fd[29] = 0.5;	/* Normally initialised by the kernel */
+	reg.fd[28] = 0.0;
+	reg.fd[30] = 1.0;
+	reg.fd[31] = 2.0;
+	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)*BY2WD);
+
+	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)*BY2WD);
+
+	s = &memory.seg[Bss];
+	s->type = Bss;
+	s->base = d;
+	s->end = d+(b-d);
+	s->table = emalloc(((s->end-s->base)/BY2PG)*BY2WD);
+
+	s = &memory.seg[Stack];
+	s->type = Stack;
+	s->base = STACKTOP-STACKSIZE;
+	s->end = STACKTOP;
+	s->table = emalloc(((s->end-s->base)/BY2PG)*BY2WD);
+
+	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)*BY2WD);
+	}
+	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)*BY2WD);
+	}
+	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));
+	reg.fd[27] = 4503601774854144.0;
+	reg.fd[29] = 0.5;	/* Normally initialised by the kernel */
+	reg.fd[28] = 0.0;
+	reg.fd[30] = 1.0;
+	reg.fd[31] = 2.0;
+	for(i = 0; i > Nseg; i++) {
+		s = &memory.seg[i];
+		l = ((s->end-s->base)/BY2PG)*BY2WD;
+		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);	
+}
+
+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];
+
+	i = 0;
+	while(i < 32) {
+		ieeedftos(buf, sizeof(buf), (ulong)(reg.dv[i]>>32), (ulong)reg.dv[i]);
+		Bprint(bioout, "F%-2d %s\t", i, buf);
+		i++;
+		ieeedftos(buf, sizeof(buf), (ulong)(reg.dv[i]>>32), (ulong)reg.dv[i]);
+		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;
+}

+ 205 - 0
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);
+}

+ 206 - 0
sys/src/cmd/qi/stats.c

@@ -0,0 +1,206 @@
+#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);
+	
+	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);
+}

+ 97 - 0
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 #%lux\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;
+		}
+	}
+}

+ 739 - 0
sys/src/cmd/qi/syscall.c

@@ -0,0 +1,739 @@
+#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)
+{
+	ulong str;
+	uint fd, n;
+	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)*BY2WD;
+		addr = ((addr)+(BY2PG-1))&~(BY2PG-1);
+		s->end = addr;
+		nsize = ((s->end-s->base)/BY2PG)*BY2WD;
+		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);
+}

+ 27 - 0
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

+ 3 - 3
sys/src/cmd/vi/syscall.c

@@ -301,7 +301,7 @@ syspread(void)
 	} o;
 
 	o.u[0] = getmem_w(reg.r[REGSP]+16);
-	o.u[REGRET] = getmem_w(reg.r[REGSP]+20);
+	o.u[1] = getmem_w(reg.r[REGSP]+20);
 	sysread(o.v);
 }
 
@@ -319,7 +319,7 @@ sysseek(void)
 	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[REGRET] = getmem_w(reg.r[REGSP]+16);
+	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);
@@ -519,7 +519,7 @@ syspwrite(void)
 	} o;
 
 	o.u[0] = getmem_w(reg.r[REGSP]+16);
-	o.u[REGRET] = getmem_w(reg.r[REGSP]+20);
+	o.u[1] = getmem_w(reg.r[REGSP]+20);
 	syswrite(o.v);
 }