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/units - 664 sys sys 944959673 2049
 sys/man/1/uptime - 664 sys sys 1074733782 380
 sys/man/1/uptime - 664 sys sys 1074733782 380
 sys/man/1/vac - 664 sys sys 1021579977 3227
 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/vnc - 664 sys sys 1045501432 4186
 sys/man/1/vt - 664 sys sys 1018386774 2210
 sys/man/1/vt - 664 sys sys 1018386774 2210
 sys/man/1/wc - 664 sys sys 944959675 908
 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/sparc.h - 664 sys sys 944961015 4419
 sys/src/cmd/ki/stats.c - 664 sys sys 1068859845 4536
 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/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 - 20000000775 sys sys 944961016 0
 sys/src/cmd/kl/asm.c - 664 sys sys 1045503967 26003
 sys/src/cmd/kl/asm.c - 664 sys sys 1045503967 26003
 sys/src/cmd/kl/compat.c - 664 sys sys 947099591 465
 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/sgen.c - 664 sys sys 952627604 8742
 sys/src/cmd/qc/swt.c - 664 sys sys 984718309 11266
 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/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 - 20000000775 sys sys 954037972 0
 sys/src/cmd/ql/asm.c - 664 sys sys 1055699283 12469
 sys/src/cmd/ql/asm.c - 664 sys sys 1055699283 12469
 sys/src/cmd/ql/asmout.c - 664 sys sys 1055699283 30140
 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/special.c - 664 sys sys 944961342 6723
 sys/src/cmd/vi/stats.c - 664 sys sys 1067746789 5386
 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/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/vi/vi.c - 664 sys sys 1014926560 8924
 sys/src/cmd/vl - 20000000775 sys sys 944961343 0
 sys/src/cmd/vl - 20000000775 sys sys 944961343 0
 sys/src/cmd/vl/asm.c - 664 sys sys 1055699754 30723
 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 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
 1076614318 1 c sys/src/cmd/tail.c - 664 sys sys 1076614068 5990
 1076644923 0 c 386/bin/tail - 775 sys sys 1076644755 64896
 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
 .TH VI 1
 .SH NAME
 .SH NAME
-0i, 5i, ki, vi \- instruction simulators
+0i, 5i, ki, vi, qi \- instruction simulators
 .SH SYNOPSIS
 .SH SYNOPSIS
 .B vi
 .B vi
 [
 [
@@ -33,6 +33,14 @@
 .br
 .br
 .B ki
 .B ki
 .I pid
 .I pid
+.br
+.B qi
+[
+.I textfile
+]
+.br
+.B qi
+.I pid
 .SH DESCRIPTION
 .SH DESCRIPTION
 .I Vi
 .I Vi
 simulates the execution of a MIPS binary in
 simulates the execution of a MIPS binary in
@@ -47,11 +55,12 @@ single stepping under
 .IR db .
 .IR db .
 .IR 0i ,
 .IR 0i ,
 .IR 5i ,
 .IR 5i ,
+.IR ki ,
 and
 and
-.IR ki
+.IR qi
 are similar to
 are similar to
 .I vi
 .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
 The following discussion refers to
 .I vi
 .I vi
 but applies to the others
 but applies to the others

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

@@ -301,7 +301,7 @@ syspread(void)
 	} o;
 	} o;
 
 
 	o.u[0] = getmem_w(reg.r[REGSP]+16);
 	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);
 	sysread(o.v);
 }
 }
 
 
@@ -319,7 +319,7 @@ sysseek(void)
 	retp = getmem_w(reg.r[REGSP]+4);
 	retp = getmem_w(reg.r[REGSP]+4);
 	fd = getmem_w(reg.r[REGSP]+8);
 	fd = getmem_w(reg.r[REGSP]+8);
 	o.u[0] = getmem_w(reg.r[REGSP]+12);
 	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);
 	mode = getmem_w(reg.r[REGSP]+20);
 	if(sysdbg)
 	if(sysdbg)
 		itrace("seek(%d, %lld, %d)", fd, o.v, mode);
 		itrace("seek(%d, %lld, %d)", fd, o.v, mode);
@@ -519,7 +519,7 @@ syspwrite(void)
 	} o;
 	} o;
 
 
 	o.u[0] = getmem_w(reg.r[REGSP]+16);
 	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);
 	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;
 
 
 	o.u[0] = getmem_w(reg.r[REGSP]+16);
 	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);
 	sysread(o.v);
 }
 }
 
 
@@ -319,7 +319,7 @@ sysseek(void)
 	retp = getmem_w(reg.r[REGSP]+4);
 	retp = getmem_w(reg.r[REGSP]+4);
 	fd = getmem_w(reg.r[REGSP]+8);
 	fd = getmem_w(reg.r[REGSP]+8);
 	o.u[0] = getmem_w(reg.r[REGSP]+12);
 	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);
 	mode = getmem_w(reg.r[REGSP]+20);
 	if(sysdbg)
 	if(sysdbg)
 		itrace("seek(%d, %lld, %d)", fd, o.v, mode);
 		itrace("seek(%d, %lld, %d)", fd, o.v, mode);
@@ -519,7 +519,7 @@ syspwrite(void)
 	} o;
 	} o;
 
 
 	o.u[0] = getmem_w(reg.r[REGSP]+16);
 	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);
 	syswrite(o.v);
 }
 }