Browse Source

Plan 9 from Bell Labs 2004-02-14

David du Colombier 21 years ago
parent
commit
b04da4770a

+ 19 - 3
dist/replica/plan9.db

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

+ 19 - 0
dist/replica/plan9.log

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

+ 12 - 3
sys/man/1/vi

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

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

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

+ 129 - 0
sys/src/cmd/qi/bpt.c

@@ -0,0 +1,129 @@
+#include <u.h>
+#include <libc.h>
+#include <ctype.h>
+#include <bio.h>
+#include <mach.h>
+#define Extern extern
+#include "power.h"
+
+void
+dobplist(void)
+{
+	Breakpoint *b;
+	char buf[512];
+
+	for(b = bplist; b; b = b->next) {
+		switch(b->type) {
+		case Instruction:
+			Bprint(bioout, "0x%lux,%d:b %d done, at ", b->addr, b->count, b->done);
+			symoff(buf, sizeof(buf), b->addr, CTEXT);
+			Bprint(bioout, "%s", buf);
+			break;
+
+		case Access:
+			Bprint(bioout, "0x%lux,%d:ba %d done, at ", b->addr, b->count, b->done);
+			symoff(buf, sizeof(buf), b->addr, CDATA);
+			Bprint(bioout, "%s", buf);
+			break;
+
+		case Read:
+			Bprint(bioout, "0x%lux,%d:br %d done, at ", b->addr, b->count, b->done);
+			symoff(buf, sizeof(buf), b->addr, CDATA);
+			Bprint(bioout, "%s", buf);
+			break;
+
+		case Write:
+			Bprint(bioout, "0x%lux,%d:bw %d done, at ", b->addr, b->count, b->done);
+			symoff(buf, sizeof(buf), b->addr, CDATA);
+			Bprint(bioout, "%s", buf);
+			break;
+
+		case Equal:
+			Bprint(bioout, "0x%lux,%d:be at ", b->addr, b->count);
+			symoff(buf, sizeof(buf), b->addr, CDATA);
+			Bprint(bioout, "%s", buf);
+			break;
+		}
+		Bprint(bioout, "\n");
+	}
+}
+
+void
+breakpoint(char *addr, char *cp)
+{
+	Breakpoint *b;
+	int type;
+
+	cp = nextc(cp);
+	type = Instruction;
+	switch(*cp) {
+	case 'r':
+		membpt++;
+		type = Read;
+		break;
+	case 'a':
+		membpt++;
+		type = Access;
+		break;
+	case 'w':
+		membpt++;
+		type = Write;
+		break;
+	case 'e':
+		membpt++;
+		type = Equal;
+		break;
+	}
+	b = emalloc(sizeof(Breakpoint));
+	b->addr = expr(addr);
+	b->type = type;
+	b->count = cmdcount;
+	b->done = cmdcount;
+
+	b->next = bplist;
+	bplist = b;
+}
+
+void
+delbpt(char *addr)
+{
+	Breakpoint *b, **l;
+	ulong baddr;
+
+	baddr = expr(addr);
+	l = &bplist;
+	for(b = *l; b; b = b->next) {
+		if(b->addr == baddr) {
+			if(b->type != Instruction)
+				membpt++;
+			*l = b->next;
+			free(b);
+			return;
+		}
+		l = &b->next;	
+	}
+
+	Bprint(bioout, "no breakpoint\n");
+}
+
+void
+brkchk(ulong addr, int type)
+{
+	Breakpoint *b;
+
+	for(b = bplist; b; b = b->next) {
+		if(b->addr == addr && (b->type&type)) {
+			if(b->type == Equal && getmem_4(addr) == b->count) {
+				count = 1;
+				atbpt = 1;
+				return;
+			}
+			if(--b->done == 0) {
+				b->done = b->count;
+				count = 1;
+				atbpt = 1;
+				return;
+			}
+		}
+	}	
+}

+ 272 - 0
sys/src/cmd/qi/branch.c

@@ -0,0 +1,272 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+#define Extern extern
+#include "power.h"
+
+void	mcrf(ulong);
+void	bclr(ulong);
+void	crop(ulong);
+void	bcctr(ulong);
+void	call(ulong);
+void	ret(ulong);
+void isync(ulong);
+
+Inst	op19[] = {
+[0] {mcrf, "mcrf", Ibranch},
+[16] {bclr, "bclr", Ibranch},
+[33] {crop, "crnor", Ibranch},
+[15] {0, "rfi", Ibranch},
+[129] {crop, "crandc", Ibranch},
+[150] {isync, "isync", Ibranch},
+[193] {crop, "crxor", Ibranch},
+[225] {crop, "crnand", Ibranch},
+[257] {crop, "crand", Ibranch},
+[289] {crop, "creqv", Ibranch},
+[417] {crop, "crorc", Ibranch},
+[449] {crop, "cror", Ibranch},
+[528] {bcctr, "bcctr", Ibranch},
+	{0, 0, 0}
+};
+
+Inset	ops19 = {op19, nelem(op19)-1};
+
+static char *
+boname(int bo)
+{
+	static char buf[8];
+
+	switch(bo>>1){
+	case 0:	return "dnzf";
+	case 1:	return "dzf";
+	case 2:	return "f";
+	case 4:	return "dnzt";
+	case 5:	return "dzt";
+	case 6:	return "t";
+	case 8:	return "dnz";
+	case 9:	return "dz";
+	case 10:	return "a";
+	default:
+		sprint(buf, "%d?", bo);
+		return buf;
+	}
+}
+
+static char *
+cname(int bo, int bi)
+{
+	int f;
+	char *p;
+	static char buf[20];
+	static char *f0[] = {"lt", "gt", "eq", "so/un"};
+
+	if(bo == 0x14){	/* branch always */
+		sprint(buf,"%d", bi);
+		return buf;
+	}
+	for(f = 0; bi >= 4; bi -= 4)
+		f++;
+	p = buf;
+	p += sprint(buf, "%d[", bi);
+	if(f)
+		p += sprint(buf, "cr%d+", f);
+	strcpy(p, f0[bi&3]);
+	strcat(p, "]");
+	return buf;
+}
+
+static int
+condok(ulong ir, int ctr)
+{
+	int bo, bi, xx;
+
+	getbobi(ir);
+	if(xx)
+		undef(ir);
+	if((bo & 0x4) == 0) {
+		if(!ctr)
+			undef(ir);
+		reg.ctr--;
+	}
+	if(bo & 0x4 || (reg.ctr!=0)^((bo>>1)&1)) {
+		if(bo & 0x10 || (((reg.cr & bits[bi])!=0)==((bo>>3)&1)))
+			return 1;
+	}
+	return 0;
+}
+
+static void
+dobranch(ulong ir, ulong *r, int ctr)
+{
+	int bo, bi, xx;
+	ulong nia;
+
+	getbobi(ir);
+	USED(xx);
+	if(condok(ir, ctr)) {
+		ci->taken++;
+		nia = *r & ~3;
+		if(bo & 4)	/* assume counting branches aren't returns */
+			ret(nia);
+	} else
+		nia = reg.pc + 4;
+	if(trace)
+		itrace("%s%s\t%s,%s,#%.8lux", ci->name, ir&1? "l": "", boname(bo), cname(bo, bi), nia);
+	if(ir & 1) {
+		call(nia);
+		reg.lr = reg.pc + 4;
+	}
+	reg.pc = nia-4;
+	/* branch delays? */
+}
+
+void
+bcctr(ulong ir)
+{
+	dobranch(ir, &reg.ctr, 1);
+}
+
+void
+bclr(ulong ir)
+{
+	dobranch(ir, &reg.lr, 0);
+}
+
+void
+bcx(ulong ir)
+{
+	int bo, bi, xx;
+	ulong ea;
+	long imm;
+	static char *opc[] = {"bc", "bcl", "bca", "bcla"};
+
+	getbobi(ir);
+	USED(xx);
+	imm = ir & 0xFFFC;
+	if(ir & 0x08000)
+		imm |= 0xFFFF0000;
+	if((ir & 2) == 0) {	/* not absolute address */
+		ea = reg.pc + imm;
+		if(trace)
+			itrace("%s\t%s,%s,.%s%ld\tea = #%.8lux", opc[ir&3], boname(bo), cname(bo, bi), imm<0?"":"+", imm, ea);
+	} else {
+		ea = imm;
+		if(trace)
+			itrace("%s\t%s,%s,#%.8lux", opc[ir&3], boname(bo), cname(bo, bi), ea);
+	}
+	if(condok(ir&0xFFFF0000, 1))
+		ci->taken++;
+	else
+		ea = reg.pc + 4;
+	if(ir & 1) {
+		call(ea);
+		reg.lr = reg.pc+4;
+	}
+	reg.pc = ea-4;
+	/* branch delay? */
+}
+
+void
+crop(ulong ir)
+{
+	int rd, ra, rb, d;
+
+	getarrr(ir);
+	if(trace)
+		itrace("%s\tcrb%d,crb%d,crb%d", ci->name, rd, ra, rb);
+	ra = (reg.cr & bits[ra]) != 0;
+	rb = (reg.cr & bits[rb]) != 0;
+	d = 0;
+	switch(getxo(ir)) {
+	case 257:	d = ra & rb; break;
+	case 129:	d = ra & !rb; break;
+	case 289:	d = ra == rb; break;
+	case 225:	d = !(ra & rb); break;
+	case 33:	d = !(ra | rb); break;
+	case 449:	d = ra | rb; break;
+	case 417:	d = ra | !rb; break;
+	case 193:	d = ra ^ rb; break;
+	default:	undef(ir); break;
+	}
+	if(d)
+		reg.cr |= bits[rd];
+}
+
+void
+mcrf(ulong ir)
+{
+	int rd, ra, rb;
+
+	getarrr(ir);
+	if(ir & 1 || rd & 3 || ra & 3 || rb)
+		undef(ir);
+	ra >>= 2;
+	rd >>= 2;
+	reg.cr = (reg.cr & ~mkCR(rd, 0xF)) | mkCR(rd, getCR(ra, reg.cr));
+	if(trace)
+		itrace("mcrf\tcrf%d,crf%d", rd, ra);
+}
+
+void
+call(ulong npc)
+{
+	Symbol s;
+
+	if(calltree) {
+		findsym(npc, CTEXT, &s);
+		Bprint(bioout, "%8lux %s(", reg.pc, s.name);
+		printparams(&s, reg.r[1]);
+		Bprint(bioout, "from ");
+		printsource(reg.pc);
+		Bputc(bioout, '\n');
+	}
+}
+
+void
+ret(ulong npc)
+{
+	Symbol s;
+
+	if(calltree) {
+		findsym(npc, CTEXT, &s);
+		Bprint(bioout, "%8lux return to #%lux %s r3=#%lux (%ld)\n",
+					reg.pc, npc, s.name, reg.r[3], reg.r[3]);
+	}
+}
+
+void
+bx(ulong ir)
+{
+	ulong ea;
+	long imm;
+	static char *opc[] = {"b", "bl", "ba", "bla"};
+
+	imm = ir & 0x03FFFFFC;
+	if(ir & 0x02000000)
+		imm |= 0xFC000000;
+	if((ir & 2) == 0) {	/* not absolute address */
+		ea = reg.pc + imm;
+		if(trace)
+			itrace("%s\t.%s%ld\tea = #%.8lux", opc[ir&3], imm<0?"":"+", imm, ea);
+	} else {
+		ea = imm;
+		if(trace)
+			itrace("%s\t#%.8lux", opc[ir&3], ea);
+	}
+	ci->taken++;
+	if(ir & 1) {
+		call(ea);
+		reg.lr = reg.pc+4;
+	}
+	reg.pc = ea-4;
+	/* branch delay? */
+}
+
+void
+isync(ulong ir)
+{
+	USED(ir);
+	if(trace)
+		itrace("isync");
+}

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

@@ -0,0 +1,644 @@
+#include <u.h>
+#include <libc.h>
+#include <ctype.h>
+#include <bio.h>
+#include <mach.h>
+#define Extern extern
+#include "power.h"
+
+char	buf[128], lastcmd[128];
+char	fmt = 'X';
+int	width = 60;
+int	inc;
+
+ulong	expr(char*);
+ulong	expr1(char*);
+char*	term(char*, ulong*);
+
+char *
+nextc(char *p)
+{
+	while(*p && (*p == ' ' || *p == '\t') && *p != '\n')
+		p++;
+
+	if(*p == '\n')
+		*p = '\0';
+
+	return p;
+}
+
+char *
+numsym(char *addr, ulong *val)
+{
+	char tsym[128], *t;
+	static char *delim = "`'<>/\\@*|-~+-/=?\n";
+	Symbol s;
+	char c;
+
+	t = tsym;
+	while(c = *addr) {
+		if(strchr(delim, c))
+			break;
+		*t++ = c;
+		addr++;
+	}
+	t[0] = '\0';
+
+	if(strcmp(tsym, ".") == 0) {
+		*val = dot;
+		return addr;
+	}
+
+	if(lookup(0, tsym, &s))
+		*val = s.value;
+	else {
+		if(tsym[0] == '#')
+			*val = strtoul(tsym+1, 0, 16);
+		else
+			*val = strtoul(tsym, 0, 0);
+	}
+	return addr;
+}
+
+ulong
+expr(char *addr)
+{
+	ulong t, t2;
+	char op;
+
+	if(*addr == '\0')
+		return dot;
+
+	addr = numsym(addr, &t);
+
+	if(*addr == '\0')
+		return t;
+
+	addr = nextc(addr);
+	op = *addr++;
+	numsym(addr, &t2);
+	switch(op) {
+	default:
+		Bprint(bioout, "expr syntax\n");
+		return 0;
+	case '+':
+		t += t2;
+		break;
+	case '-':
+		t -= t2;
+		break;
+	case '%':
+		t /= t2;
+		break;
+	case '&':
+		t &= t2;
+		break;
+	case '|':
+		t |= t2;
+		break;
+	}
+
+	return t;
+}
+
+int
+buildargv(char *str, char **args, int max)
+{
+	int na = 0;
+
+	while (na < max) {
+		while((*str == ' ' || *str == '\t' || *str == '\n') && *str != '\0')
+			str++;
+
+		if(*str == '\0')
+			return na;
+
+		args[na++] = str;
+		while(!(*str == ' ' || *str == '\t'|| *str == '\n') && *str != '\0')
+			str++;
+
+		if(*str == '\n')
+			*str = '\0';
+
+		if(*str == '\0')
+			break;
+
+		*str++ = '\0';
+	}
+	return na;
+}
+
+void
+colon(char *addr, char *cp)
+{
+	int argc;
+	char *argv[100];
+	char tbuf[512];
+
+	cp = nextc(cp);
+	switch(*cp) {
+	default:
+		Bprint(bioout, "?\n");
+		return;
+	case 'b':
+		breakpoint(addr, cp+1);
+		return;
+
+	case 'd':
+		delbpt(addr);
+		return;
+
+	/* These fall through to print the stopped address */
+	case 'r':
+		reset();
+		argc = buildargv(cp+1, argv, 100);
+		initstk(argc, argv);
+		count = 0;
+		atbpt = 0;
+		run();
+		break;
+	case 'c':
+		count = 0;
+		atbpt = 0;
+		run();
+		break;
+	case 's':
+		cp = nextc(cp+1);
+		count = 0;
+		if(*cp)
+			count = strtoul(cp, 0, 0);
+		if(count == 0)
+			count = 1;
+		atbpt = 0;
+		run();
+		break;
+	}
+
+	dot = reg.pc;
+	Bprint(bioout, "%s at #%lux ", atbpt ? "breakpoint" : "stopped", dot);
+	symoff(tbuf, sizeof(tbuf), dot, CTEXT);
+	Bprint(bioout, tbuf);
+	if(fmt == 'z')
+		printsource(dot);
+
+	Bprint(bioout, "\n");
+}
+
+
+void
+dollar(char *cp)
+{
+	cp = nextc(cp);
+	switch(*cp) {
+	default:
+		Bprint(bioout, "?\n");
+		break;
+
+	case 'c':
+	case 'C':
+		stktrace(*cp);
+		break;
+
+	case 'b':
+		dobplist();
+		break;
+
+	case 'r':
+		dumpreg();
+		break;
+
+	case 'R':
+		dumpreg();
+		/* fall through */
+
+	case 'f':
+		dumpfreg();
+		break;
+
+	case 'F':
+		dumpdreg();
+		break;
+
+	case 'q':
+		exits(0);
+		break;
+
+	case 'Q':
+		isum();
+		segsum();
+		break;
+
+	case 't':
+		cp++;
+		switch(*cp) {
+		default:
+			Bprint(bioout, ":t[0sic]\n");
+			break;
+		case '\0':
+			trace = 1;
+			break;
+		case '0':
+			trace = 0;
+			sysdbg = 0;
+			calltree = 0;
+			break;
+		case 's':
+			sysdbg = 1;
+			break;
+		case 'i':
+			trace = 1;
+			break;
+		case 'c':
+			calltree = 1;
+			break;
+		}
+		break;
+
+	case 'i':
+		cp++;
+		switch(*cp) {
+		default:
+			Bprint(bioout, "$i[isa]\n");
+			break;
+		case 'i':
+			isum();
+			break;
+		case 's':
+			segsum();
+			break;
+		case 'a':
+			isum();
+			segsum();
+			iprofile();
+			break;
+		case 'p':
+			iprofile();
+			break;
+		}
+	}
+}
+
+int
+pfmt(char fmt, int mem, ulong val)
+{
+	int c, i;
+	Symbol s;
+	char *p, ch, str[1024];
+
+	c = 0;
+	switch(fmt) {
+	default:
+		Bprint(bioout, "bad modifier\n");
+		return 0;
+	case 'o':
+		c = Bprint(bioout, "%-4lo ", mem ? (ushort)getmem_2(dot) : val);
+		inc = 2;
+		break;
+
+	case 'O':
+		c = Bprint(bioout, "%-8lo ", mem ? getmem_4(dot) : val);
+		inc = 4;
+		break;
+
+	case 'q':
+		c = Bprint(bioout, "%-4lo ", mem ? (short)getmem_2(dot) : val);
+		inc = 2;
+		break;
+
+	case 'Q':
+		c = Bprint(bioout, "%-8lo ", mem ? (long)getmem_4(dot) : val);
+		inc = 4;
+		break;
+
+	case 'd':
+		c = Bprint(bioout, "%-5ld ", mem ? (short)getmem_2(dot) : val);
+		inc = 2;
+		break;
+
+
+	case 'D':
+		c = Bprint(bioout, "%-8ld ", mem ? (long)getmem_4(dot) : val);
+		inc = 4;
+		break;
+
+	case 'x':
+		c = Bprint(bioout, "#%-4lux ", mem ? (long)getmem_2(dot) : val);
+		inc = 2;
+		break;
+
+	case 'X':
+		c = Bprint(bioout, "#%-8lux ", mem ? (long)getmem_4(dot) : val);
+		inc = 4;
+		break;
+
+	case 'u':
+		c = Bprint(bioout, "%-5ld ", mem ? (ushort)getmem_2(dot) : val);
+		inc = 2;
+		break;
+
+	case 'U':
+		c = Bprint(bioout, "%-8ld ", mem ? (ulong)getmem_4(dot) : val);
+		inc = 4;
+		break;
+
+	case 'b':
+		c = Bprint(bioout, "%-3ld ", mem ? getmem_b(dot) : val);
+		inc = 1;
+		break;
+
+	case 'c':
+		c = Bprint(bioout, "%c ", (int)(mem ? getmem_b(dot) : val));
+		inc = 1;
+		break;
+
+	case 'C':
+		ch = mem ? getmem_b(dot) : val;
+		if(isprint(ch))
+			c = Bprint(bioout, "%c ", ch);
+		else
+			c = Bprint(bioout, "\\x%.2x ", ch);
+		inc = 1;
+		break;
+
+	case 's':
+		i = 0;
+		while(ch = getmem_b(dot+i))
+			str[i++] = ch;
+		str[i] = '\0';
+		dot += i;
+		c = Bprint(bioout, "%s", str);
+		inc = 0;
+		break;
+
+	case 'S':
+		i = 0;
+		while(ch = getmem_b(dot+i))
+			str[i++] = ch;
+		str[i] = '\0';
+		dot += i;
+		for(p = str; *p; p++)
+			if(isprint(*p))
+				c += Bprint(bioout, "%c", *p);
+			else
+				c += Bprint(bioout, "\\x%.2ux", *p);
+		inc = 0;
+		break;
+
+	case 'Y':
+		p = ctime(mem ? getmem_b(dot) : val);
+		p[30] = '\0';
+		c = Bprint(bioout, "%s", p);
+		inc = 4;
+		break;
+
+	case 'a':
+		symoff(str, sizeof(str), dot, CTEXT);
+		Bprint(bioout, "%s", str);
+		inc = 0;
+		break;
+
+	case 'e':
+		for (i = 0; globalsym(&s, i); i++)
+			Bprint(bioout, "%-15s #%lux\n", s.name,	getmem_4(s.value));
+		inc = 0;
+		break;
+
+	case 'I':
+	case 'i':
+		inc = machdata->das(symmap, dot, fmt, str, sizeof(str));
+		if (inc < 0) {
+			Bprint(bioout, "qi: %r\n");
+			return 0;
+		}
+		c = Bprint(bioout, "\t%s", str);
+		break;
+
+	case 'n':
+		c = width+1;
+		inc = 0;
+		break;
+
+	case '-':
+		c = 0;
+		inc = -1;
+		break;
+
+	case '+':
+		c = 0;
+		inc = 1;
+		break;
+
+	case '^':
+		c = 0;
+		if(inc > 0)
+			inc = -inc;
+		break;
+
+	case 'z':
+		if (findsym(dot, CTEXT, &s))
+			Bprint(bioout, "  %s() ", s.name);
+		printsource(dot);
+		inc = 0;
+		break;
+	}
+	return c;
+}
+
+void
+eval(char *addr, char *p)
+{
+	ulong val;
+
+	val = expr(addr);
+	p = nextc(p);
+	if(*p == '\0') {
+		p[0] = fmt;
+		p[1] = '\0';
+	}
+	pfmt(*p, 0, val);
+	Bprint(bioout, "\n");
+}
+
+void
+quesie(char *p)
+{
+	int c, count, i;
+	char tbuf[512];
+
+	c = 0;
+	symoff(tbuf, sizeof(tbuf), dot, CTEXT);
+	Bprint(bioout, "%s?\t", tbuf);
+
+	while(*p) {
+		p = nextc(p);
+		if(*p == '"') {
+			for(p++; *p && *p != '"'; p++) {
+				Bputc(bioout, *p);
+				c++;
+			}
+			if(*p)
+				p++;
+			continue;
+		}
+		count = 0;
+		while(*p >= '0' && *p <= '9')
+			count = count*10 + (*p++ - '0');
+		if(count == 0)
+			count = 1;
+		p = nextc(p);
+		if(*p == '\0') {
+			p[0] = fmt;
+			p[1] = '\0';
+		}
+		for(i = 0; i < count; i++) {
+			c += pfmt(*p, 1, 0);
+			dot += inc;
+			if(c > width) {
+				Bprint(bioout, "\n");
+				symoff(tbuf, sizeof(tbuf), dot, CTEXT);
+				Bprint(bioout, "%s?\t", tbuf);
+				c = 0;
+			}
+		}
+		fmt = *p++;
+		p = nextc(p);
+	}
+	Bprint(bioout, "\n");
+}
+
+void
+catcher(void *a, char *msg)
+{
+	USED(a);
+	if(strcmp(msg, "interrupt") != 0)
+		noted(NDFLT);
+
+	count = 1;
+	print("qi\n");
+	noted(NCONT);
+}
+
+void
+setreg(char *addr, char *cp)
+{
+	int rn;
+
+	dot = expr(addr);
+	cp = nextc(cp);
+	if(strcmp(cp, "pc") == 0) {
+		reg.pc = dot;
+		return;
+	}
+	if(strcmp(cp, "sp") == 0) {
+		reg.r[1] = dot;
+		return;
+	}
+	if(strcmp(cp, "lr") == 0) {
+		reg.lr = dot;
+		return;
+	}
+	if(strcmp(cp, "ctr") == 0) {
+		reg.ctr = dot;
+		return;
+	}
+	if(strcmp(cp, "fpscr") == 0) {
+		reg.fpscr = dot;
+		return;
+	}
+	if(strcmp(cp, "xer") == 0) {
+		reg.xer = dot;
+		return;
+	}
+	if(strcmp(cp, "cr") == 0) {
+		reg.cr = dot;
+		return;
+	}
+	if(*cp++ == 'r') {
+		rn = strtoul(cp, 0, 10);
+		if(rn > 0 && rn < 32) {
+			reg.r[rn] = dot;
+			return;
+		}
+	}
+	Bprint(bioout, "bad register\n");
+}
+
+void
+cmd(void)
+{
+	char *p, *a, *cp, *gotint;
+	char addr[128];
+	static char *cmdlet = ":$?/=>";
+	int n, i;
+
+	notify(catcher);
+
+	dot = reg.pc;
+	setjmp(errjmp);
+
+	for(;;) {
+		Bflush(bioout);
+		p = buf;
+		n = 0;
+		for(;;) {
+			i = Bgetc(bin);
+			if(i < 0)
+				exits(0);
+			*p++ = i;
+			n++;
+			if(i == '\n')
+				break;
+		}
+
+		if(buf[0] == '\n')
+			strcpy(buf, lastcmd);
+		else {
+			buf[n-1] = '\0';
+			strcpy(lastcmd, buf);
+		}
+		p = buf;
+		a = addr;
+
+		for(;;) {
+			p = nextc(p);
+			if(*p == 0 || strchr(cmdlet, *p))
+				break;
+			*a++ = *p++;
+		}
+
+		*a = '\0';
+		cmdcount = 1;
+		cp = strchr(addr, ',');
+		if(cp != 0) {
+			if(cp[1] == '#')
+				cmdcount = strtoul(cp+2, &gotint, 16);
+			else
+				cmdcount = strtoul(cp+1, &gotint, 0);
+			*cp = '\0';
+		}
+
+		switch(*p) {
+		case '$':
+			dollar(p+1);
+			break;
+		case ':':
+			colon(addr, p+1);
+			break;
+		case '/':
+		case '?':
+			dot = expr(addr);
+			for(i = 0; i < cmdcount; i++)
+				quesie(p+1);
+			break;
+		case '=':
+			eval(addr, p+1);
+			break;
+		case '>':
+			setreg(addr, p+1);
+			break;
+		default:
+			Bprint(bioout, "?\n");
+			break;
+		}
+	}
+}

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

@@ -0,0 +1,702 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+#define Extern extern
+#include "power.h"
+
+ulong	setfpscr(void);
+void	setfpcc(double);
+void	farith(ulong);
+void	farith2(ulong);
+void	fariths(ulong);
+void	fcmp(ulong);
+void	mtfsb1(ulong);
+void	mcrfs(ulong);
+void	mtfsb0(ulong);
+void	mtfsf(ulong);
+void	mtfsfi(ulong);
+void	mffs(ulong);
+void	mtfsf(ulong);
+
+Inst	op59[] = {
+[18] {fariths, "fdivs", Ifloat},
+[20] {fariths, "fsubs", Ifloat},
+[21] {fariths, "fadds", Ifloat},
+[22] {unimp, "fsqrts", Ifloat},
+[24] {unimp, "fres", Ifloat},
+[25] {fariths, "fmuls", Ifloat},
+[28] {fariths, "fmsubs", Ifloat},
+[29] {fariths, "fmadds", Ifloat},
+[30] {fariths, "fnmsubs", Ifloat},
+[31] {fariths, "fnmadds", Ifloat},
+};
+
+Inset	ops59 = {op59, nelem(op59)};
+
+Inst	op63a[] = {
+[12] {farith, "frsp", Ifloat},
+[14] {farith, "fctiw", Ifloat},
+[15] {farith, "fctiwz", Ifloat},
+[18] {farith, "fdiv", Ifloat},
+[20] {farith, "fsub", Ifloat},
+[21] {farith, "fadd", Ifloat},
+[22] {unimp, "frsqrt", Ifloat},
+[23] {unimp, "fsel", Ifloat},
+[25] {farith, "fmul", Ifloat},
+[26] {unimp, "frsqrte", Ifloat},
+[28] {farith, "fmsub", Ifloat},
+[29] {farith, "fmadd", Ifloat},
+[30] {farith, "fnmsub", Ifloat},
+[31] {farith, "fnmadd", Ifloat},
+};
+
+Inset	ops63a= {op63a, nelem(op63a)};
+
+Inst	op63b[] = {
+[0] {fcmp, "fcmpu", Ifloat},
+[32] {fcmp, "fcmpo", Ifloat},
+[38] {mtfsb1, "mtfsb1", Ifloat},
+[40] {farith2, "fneg", Ifloat},
+[64] {mcrfs, "mcrfs", Ifloat},
+[70] {mtfsb0, "mtfsb0", Ifloat},
+[72] {farith2, "fmr", Ifloat},
+[134] {mtfsfi, "mtfsfi", Ifloat},
+[136] {farith2, "fnabs", Ifloat},
+[264] {farith2, "fabs", Ifloat},
+[583] {mffs, "mffs", Ifloat},
+[711] {mtfsf, "mtfsf", Ifloat},
+};
+
+Inset	ops63b = {op63b, nelem(op63b)};
+
+void
+lfs(ulong ir)
+{
+	ulong ea;
+	int imm, ra, rd, upd;
+	union {
+		ulong	i;
+		float	f;
+	} u;
+
+	getairr(ir);
+	ea = imm;
+	upd = (ir&(1L<<26))!=0;
+	if(ra) {
+		ea += reg.r[ra];
+		if(upd)
+			reg.r[ra] = ea;
+	} else {
+		if(upd)
+			undef(ir);
+	}
+	if(trace)
+		itrace("%s\tf%d,%ld(r%d) ea=%lux", ci->name, rd, imm, ra, ea);
+
+	u.i = getmem_w(ea);
+	reg.fd[rd] = u.f;
+}
+
+void
+lfsx(ulong ir)
+{
+	ulong ea;
+	int rd, ra, rb, upd;
+	union {
+		ulong	i;
+		float	f;
+	} u;
+
+	getarrr(ir);
+	ea = reg.r[rb];
+	upd = ((ir>>1)&0x3FF)==567;
+	if(ra){
+		ea += reg.r[ra];
+		if(upd)
+			reg.r[ra] = ea;
+		if(trace)
+			itrace("%s\tf%d,(r%d+r%d) ea=%lux", ci->name, rd, ra, rb, ea);
+	} else {
+		if(upd)
+			undef(ir);
+		if(trace)
+			itrace("%s\tf%d,(r%d) ea=%lux", ci->name, rd, rb, ea);
+	}
+
+	u.i = getmem_w(ea);
+	reg.fd[rd] = u.f;
+}
+
+void
+lfd(ulong ir)
+{
+	ulong ea;
+	int imm, ra, rd, upd;
+
+	getairr(ir);
+	ea = imm;
+	upd = (ir&(1L<<26))!=0;
+	if(ra) {
+		ea += reg.r[ra];
+		if(upd)
+			reg.r[ra] = ea;
+	} else {
+		if(upd)
+			undef(ir);
+	}
+	if(trace)
+		itrace("%s\tf%d,%ld(r%d) ea=%lux", ci->name, rd, imm, ra, ea);
+
+	reg.dv[rd] = getmem_v(ea);
+}
+
+void
+lfdx(ulong ir)
+{
+	ulong ea;
+	int rd, ra, rb, upd;
+
+	getarrr(ir);
+	ea = reg.r[rb];
+	upd = ((ir>>1)&0x3FF)==631;
+	if(ra){
+		ea += reg.r[ra];
+		if(upd)
+			reg.r[ra] = ea;
+		if(trace)
+			itrace("%s\tf%d,(r%d+r%d) ea=%lux", ci->name, rd, ra, rb, ea);
+	} else {
+		if(upd)
+			undef(ir);
+		if(trace)
+			itrace("%s\tf%d,(r%d) ea=%lux", ci->name, rd, rb, ea);
+	}
+
+	reg.dv[rd] = getmem_v(ea);
+}
+
+void
+stfs(ulong ir)
+{
+	ulong ea;
+	int imm, ra, rd, upd;
+	union {
+		float f;
+		ulong w;
+	} u;
+
+	getairr(ir);
+	ea = imm;
+	upd = (ir&(1L<<26))!=0;
+	if(ra) {
+		ea += reg.r[ra];
+		if(upd)
+			reg.r[ra] = ea;
+	} else {
+		if(upd)
+			undef(ir);
+	}
+	if(trace)
+		itrace("%s\tf%d,%ld(r%d) %lux=%g",
+					ci->name, rd, imm, ra, ea, reg.fd[rd]);
+	u.f = reg.fd[rd];	/* BUG: actual PPC conversion is more subtle than this */
+	putmem_w(ea, u.w);
+}
+
+void
+stfsx(ulong ir)
+{
+	ulong ea;
+	int rd, ra, rb, upd;
+	union {
+		float	f;
+		ulong	w;
+	} u;
+
+	getarrr(ir);
+	ea = reg.r[rb];
+	upd = getxo(ir)==695;
+	if(ra){
+		ea += reg.r[ra];
+		if(upd)
+			reg.r[ra] = ea;
+		if(trace)
+			itrace("%s\tf%d,(r%d+r%d) %lux=%g", ci->name, rd, ra, rb, ea, (float)reg.fd[rd]);
+	} else {
+		if(upd)
+			undef(ir);
+		if(trace)
+			itrace("%s\tf%d,(r%d) %lux=%g", ci->name, rd, rb, ea, (float)reg.fd[rd]);
+	}
+
+	u.f = reg.fd[rd];	/* BUG: actual PPC conversion is more subtle than this */
+	putmem_w(ea, u.w);
+}
+
+void
+stfd(ulong ir)
+{
+	ulong ea;
+	int imm, ra, rd, upd;
+
+	getairr(ir);
+	ea = imm;
+	upd = (ir&(1L<<26))!=0;
+	if(ra) {
+		ea += reg.r[ra];
+		if(upd)
+			reg.r[ra] = ea;
+	} else {
+		if(upd)
+			undef(ir);
+	}
+	if(trace)
+		itrace("%s\tf%d,%ld(r%d) %lux=%g",
+					ci->name, rd, imm, ra, ea, reg.fd[rd]);
+
+	putmem_v(ea, reg.dv[rd]);
+}
+
+void
+stfdx(ulong ir)
+{
+	ulong ea;
+	int rd, ra, rb, upd;
+
+	getarrr(ir);
+	ea = reg.r[rb];
+	upd = ((ir>>1)&0x3FF)==759;
+	if(ra){
+		ea += reg.r[ra];
+		if(upd)
+			reg.r[ra] = ea;
+		if(trace)
+			itrace("%s\tf%d,(r%d+r%d) %lux=%g", ci->name, rd, ra, rb, ea, reg.fd[rd]);
+	} else {
+		if(upd)
+			undef(ir);
+		if(trace)
+			itrace("%s\tf%d,(r%d) %lux=%g", ci->name, rd, rb, ea, reg.fd[rd]);
+	}
+
+	putmem_v(ea, reg.dv[rd]);
+}
+
+void
+mcrfs(ulong ir)
+{
+	ulong rd, ra, rb;
+	static ulong fpscr0[] ={
+		FPS_FX|FPS_OX,
+		FPS_UX|FPS_ZX|FPS_XX|FPS_VXSNAN,
+		FPS_VXISI|FPS_VXIDI|FPS_VXZDZ|FPS_VXIMZ,
+		FPS_VXVC,
+		0,
+		FPS_VXCVI,
+	};
+
+	getarrr(ir);
+	if(rb || ra&3 || rd&3)
+		undef(ir);
+	ra >>= 2;
+	rd >>= 2;
+	reg.cr = (reg.cr & ~mkCR(rd, 0xF)) | mkCR(rd, getCR(ra, reg.fpscr));
+	reg.fpscr &= ~fpscr0[ra];
+	if(trace)
+		itrace("mcrfs\tcrf%d,crf%d\n", rd, ra);
+}
+
+void
+mffs(ulong ir)
+{
+	int rd, ra, rb;
+
+	getarrr(ir);
+	if(ra || rb)
+		undef(ir);
+	reg.dv[rd] = ((uvlong)0xFFF8000L<<16)|reg.fpscr;
+	/* it's anyone's guess how CR1 should be set when ir&1 */
+	reg.cr &= ~mkCR(1, 0xE);	/* leave SO, reset others */
+	if(trace)
+		itrace("mffs%s\tfr%d\n", ir&1?".":"", rd);
+}
+
+void
+mtfsb1(ulong ir)
+{
+	int rd, ra, rb;
+
+	getarrr(ir);
+	if(ra || rb)
+		undef(ir);
+	reg.fpscr |= (1L << (31-rd));
+	/* BUG: should set summary bits */
+	if(ir & 1)
+		reg.cr &= ~mkCR(1, 0xE);	/* BUG: manual unclear: leave SO, reset others? */
+	if(trace)
+		itrace("mtfsb1%s\tfr%d\n", ir&1?".":"", rd);
+}
+
+void
+mtfsb0(ulong ir)
+{
+	int rd, ra, rb;
+
+	getarrr(ir);
+	if(ra || rb)
+		undef(ir);
+	reg.fpscr &= ~(1L << (31-rd));
+	if(ir & 1)
+		reg.cr &= ~mkCR(1, 0xE);		/* BUG: manual unclear: leave SO, reset others? */
+	if(trace)
+		itrace("mtfsb0%s\tfr%d\n", ir&1?".":"", rd);
+}
+
+void
+mtfsf(ulong ir)
+{
+	int fm, rb, i;
+	ulong v;
+
+	if(ir & ((1L << 25)|(1L << 16)))
+		undef(ir);
+	rb = (ir >> 11) & 0x1F;
+	fm = (ir >> 17) & 0xFF;
+	v = reg.dv[rb];
+	for(i=0; i<8; i++)
+		if(fm & (1 << (7-i)))
+			reg.fpscr = (reg.fpscr & ~mkCR(i, 0xF)) | mkCR(i, getCR(i, v));
+	/* BUG: should set FEX and VX `according to the usual rule' */
+	if(ir & 1)
+		reg.cr &= ~mkCR(1, 0xE);		/* BUG: manual unclear: leave SO, reset others? */
+	if(trace)
+		itrace("mtfsf%s\t#%.2x,fr%d", ir&1?".":"", fm, rb);
+}
+
+void
+mtfsfi(ulong ir)
+{
+	int imm, rd;
+
+	if(ir & ((0x7F << 16)|(1L << 11)))
+		undef(ir);
+	rd = (ir >> 23) & 0xF;
+	imm = (ir >> 12) & 0xF;
+	reg.fpscr = (reg.fpscr & ~mkCR(rd, 0xF)) | mkCR(rd, imm);
+	/* BUG: should set FEX and VX `according to the usual rule' */
+	if(ir & 1)
+		reg.cr &= ~mkCR(1, 0xE);		/* BUG: manual unclear: leave SO, reset others? */
+	if(trace)
+		itrace("mtfsfi%s\tcrf%d,#%x", ir&1?".":"", rd, imm);
+}
+
+void
+fcmp(ulong ir)
+{
+	int fc, rd, ra, rb;
+
+	getarrr(ir);
+	if(rd & 3)
+		undef(ir);
+	rd >>= 2;
+	SET(fc);
+	switch(getxo(ir)) {
+	default:
+		undef(ir);
+	case 0:
+		if(trace)
+			itrace("fcmpu\tcr%d,f%d,f%d", rd, ra, rb);
+		if(isNaN(reg.fd[ra]) || isNaN(reg.fd[rb])) {
+			fc = CRFU;
+			break;
+		}
+		if(reg.fd[ra] == reg.fd[rb]) {
+			fc = CREQ;
+			break;
+		}
+		if(reg.fd[ra] < reg.fd[rb]) {
+			fc = CRLT;
+			break;
+		}
+		if(reg.fd[ra] > reg.fd[rb]) {
+			fc = CRGT;
+			break;
+		}
+		print("qi: fcmp error\n");
+		break;
+	case 32:
+		if(trace)
+			itrace("fcmpo\tcr%d,f%d,f%d", rd, ra, rb);
+		if(isNaN(reg.fd[ra]) || isNaN(reg.fd[rb])) {	/* BUG: depends whether quiet or signalling ... */
+			fc = CRFU;
+			Bprint(bioout, "invalid_fp_register\n");
+			longjmp(errjmp, 0);
+		}
+		if(reg.fd[ra] == reg.fd[rb]) {
+			fc = CREQ;
+			break;
+		}
+		if(reg.fd[ra] < reg.fd[rb]) {
+			fc = CRLT;
+			break;
+		}
+		if(reg.fd[ra] > reg.fd[rb]) {
+			fc = CRGT;
+			break;
+		}
+		print("qi: fcmp error\n");
+		break;
+
+	}
+	fc >>= 28;
+	reg.cr = (reg.cr & ~mkCR(rd,~0)) | mkCR(rd, fc);
+	reg.fpscr = (reg.fpscr & ~0xF800) | (fc<<11);
+	/* BUG: update FX, VXSNAN, VXVC */
+}
+
+/*
+ * the farith functions probably don't produce the right results
+ * in the presence of NaNs, Infs, etc., esp. wrt exception handling, 
+ */
+void
+fariths(ulong ir)
+{
+	int rd, ra, rb, rc, fmt;
+	char *cc;
+	ulong fpscr;
+
+	fmt = 0;
+	rc = (ir>>6)&0x1F;
+	getarrr(ir);
+	switch(getxo(ir)&0x1F) {	/* partial XO decode */
+	default:
+		undef(ir);
+	case 18:
+		if((float)reg.fd[rb] == 0.0) {
+			Bprint(bioout, "fp_exception ZX\n");
+			reg.fpscr |= FPS_ZX | FPS_FX;
+			longjmp(errjmp, 0);
+		}
+		reg.fd[rd] = (float)(reg.fd[ra] / reg.fd[rb]);
+		break;
+	case 20:
+		reg.fd[rd] = (float)(reg.fd[ra] - reg.fd[rb]);
+		break;
+	case 21:
+		reg.fd[rd] = (float)(reg.fd[ra] + reg.fd[rb]);
+		break;
+	case 25:
+		reg.fd[rd] = (float)(reg.fd[ra] * reg.fd[rc]);
+		rb = rc;
+		break;
+	case 28:
+		reg.fd[rd] = (float)((reg.fd[ra] * reg.fd[rc]) - reg.fd[rb]);
+		fmt = 2;
+		break;
+	case 29:
+		reg.fd[rd] = (float)((reg.fd[ra] * reg.fd[rc]) + reg.fd[rb]);
+		fmt = 2;
+		break;
+	case 30:
+		reg.fd[rd] = (float)-((reg.fd[ra] * reg.fd[rc]) - reg.fd[rb]);
+		fmt = 2;
+		break;
+	case 31:
+		reg.fd[rd] = (float)-((reg.fd[ra] * reg.fd[rc]) + reg.fd[rb]);
+		fmt = 2;
+		break;
+	}
+	if(fmt==1 && ra)
+		undef(ir);
+	fpscr = setfpscr();
+	setfpcc(reg.fd[rd]);
+	cc = "";
+	if(ir & 1) {
+		cc = ".";
+		reg.cr = (reg.cr & ~mkCR(1, ~0)) | mkCR(1, (fpscr>>28));
+	}
+	if(trace) {
+		switch(fmt) {
+		case 0:
+			itrace("%s%s\tfr%d,fr%d,fr%d", ci->name, cc, rd, ra, rb);
+			break;
+		case 1:
+			itrace("%s%s\tfr%d,fr%d", ci->name, cc, rd, rb);
+			break;
+		case 2:
+			itrace("%s%s\tfr%d,fr%d,fr%d,fr%d", ci->name, cc, rd, ra, rc, rb);
+			break;
+		}
+	}
+}
+
+void
+farith(ulong ir)
+{
+	vlong vl;
+	int rd, ra, rb, rc, fmt;
+	char *cc;
+	ulong fpscr;
+	int nocc;
+	double d;
+
+	fmt = 0;
+	nocc = 0;
+	rc = (ir>>6)&0x1F;
+	getarrr(ir);
+	switch(getxo(ir)&0x1F) { /* partial XO decode */
+	default:
+		undef(ir);
+	case 12:	/* frsp */
+		reg.fd[rd] = (float)reg.fd[rb];
+		fmt = 1;
+		break;
+	case 14:	/* fctiw */	/* BUG: ignores rounding mode */
+	case 15:	/* fctiwz */
+		d = reg.fd[rb];
+		if(d >= 0x7fffffff)
+			vl = 0x7fffffff;
+		else if(d < 0x80000000)
+			vl = 0x80000000;
+		else
+			vl = d;
+		reg.dv[rd] = vl;
+		fmt = 1;
+		nocc = 1;
+		break;
+	case 18:
+		if(reg.fd[rb] == 0.0) {
+			Bprint(bioout, "fp_exception ZX\n");
+			reg.fpscr |= FPS_ZX | FPS_FX;
+			longjmp(errjmp, 0);
+		}
+		reg.fd[rd] = reg.fd[ra] / reg.fd[rb];
+		break;
+	case 20:
+		reg.fd[rd] = reg.fd[ra] - reg.fd[rb];
+		break;
+	case 21:
+		reg.fd[rd] = reg.fd[ra] + reg.fd[rb];
+		break;
+	case 25:
+		reg.fd[rd] = reg.fd[ra] * reg.fd[rc];
+		rb = rc;
+		break;
+	case 28:
+		reg.fd[rd] = (reg.fd[ra] * reg.fd[rc]) - reg.fd[rb];
+		fmt = 2;
+		break;
+	case 29:
+		reg.fd[rd] = (reg.fd[ra] * reg.fd[rc]) + reg.fd[rb];
+		fmt = 2;
+		break;
+	case 30:
+		reg.fd[rd] = -((reg.fd[ra] * reg.fd[rc]) - reg.fd[rb]);
+		fmt = 2;
+		break;
+	case 31:
+		reg.fd[rd] = -((reg.fd[ra] * reg.fd[rc]) + reg.fd[rb]);
+		fmt = 2;
+		break;
+	}
+	if(fmt==1 && ra)
+		undef(ir);
+	fpscr = setfpscr();
+	if(nocc == 0)
+		setfpcc(reg.fd[rd]);
+	cc = "";
+	if(ir & 1) {
+		cc = ".";
+		reg.cr = (reg.cr & ~mkCR(1, ~0)) | mkCR(1, (fpscr>>28));
+	}
+	if(trace) {
+		switch(fmt) {
+		case 0:
+			itrace("%s%s\tfr%d,fr%d,fr%d", ci->name, cc, rd, ra, rb);
+			break;
+		case 1:
+			itrace("%s%s\tfr%d,fr%d", ci->name, cc, rd, rb);
+			break;
+		case 2:
+			itrace("%s%s\tfr%d,fr%d,fr%d,fr%d", ci->name, cc, rd, ra, rc, rb);
+			break;
+		}
+	}
+}
+
+void
+farith2(ulong ir)
+{
+	int rd, ra, rb;
+	char *cc;
+	ulong fpscr;
+
+	getarrr(ir);
+	switch(getxo(ir)) { /* full XO decode */
+	default:
+		undef(ir);
+	case 40:
+		reg.fd[rd] = -reg.fd[rb];
+		break;
+	case 72:
+		reg.fd[rd] = reg.fd[rb];
+		break;
+	case 136:
+		reg.fd[rd] = -fabs(reg.fd[rb]);
+		break;
+	case 264:
+		reg.fd[rd] = fabs(reg.fd[rb]);
+		break;
+	}
+	if(ra)
+		undef(ir);
+	fpscr = setfpscr();
+	setfpcc(reg.fd[rd]);
+	cc = "";
+	if(ir & 1) {
+		cc = ".";
+		reg.cr = (reg.cr & ~mkCR(1, ~0)) | mkCR(1, (fpscr>>28));
+	}
+	if(trace)
+		itrace("%s%s\tfr%d,fr%d", ci->name, cc, rd, rb);
+}
+
+ulong
+setfpscr(void)
+{
+	ulong fps, fpscr;
+
+	fps = getfsr();
+	fpscr = reg.fpscr;
+	if(fps & FPAOVFL)
+		fpscr |= FPS_OX;
+	if(fps & FPAINEX)
+		fpscr |= FPS_XX;
+	if(fps & FPAUNFL)
+		fpscr |= FPS_UX;
+	if(fps & FPAZDIV)
+		fpscr |= FPS_ZX;
+	if(fpscr != reg.fpscr) {
+		fpscr |= FPS_FX;
+		reg.fpscr = fpscr;
+	}
+	return fpscr;
+}
+
+void
+setfpcc(double r)
+{
+	int c;
+
+	c = 0;
+	if(r == 0)
+		c |= 2;
+	else if(r < 0)
+		c |= 4;
+	else
+		c |= 8;
+	if(isNaN(r))
+		c |= 1;
+	reg.fpscr = (reg.fpscr & ~0xF800) | (0<<15) | (c<<11); /* unsure about class bit */
+}

+ 18 - 0
sys/src/cmd/qi/icache.c

@@ -0,0 +1,18 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+#define Extern extern
+#include "power.h"
+
+void
+icacheinit(void)
+{
+}
+
+void
+updateicache(ulong addr)
+{
+	USED(addr);
+}
+

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

@@ -0,0 +1,2027 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+#define Extern extern
+#include "power.h"
+
+void	add(ulong);
+void	addc(ulong);
+void	adde(ulong);
+void	addme(ulong);
+void	addze(ulong);
+void	and(ulong);
+void	andc(ulong);
+void	cmp(ulong);
+void	cmpl(ulong);
+void	cntlzw(ulong);
+void	dcbf(ulong);
+void	dcbi(ulong);
+void	dcbst(ulong);
+void	dcbt(ulong);
+void	dcbtst(ulong);
+void	dcbz(ulong);
+void	divw(ulong);
+void	divwu(ulong);
+void	eciwx(ulong);
+void	ecowx(ulong);
+void	eieio(ulong);
+void	eqv(ulong);
+void	extsb(ulong);
+void	extsh(ulong);
+void	icbi(ulong);
+void	lbzx(ulong);
+void	lfdx(ulong);
+void	lfsx(ulong);
+void	lhax(ulong);
+void	lhbrx(ulong);
+void	lhzx(ulong);
+void	lswi(ulong);
+void	lswx(ulong);
+void	lwarx(ulong);
+void	lwbrx(ulong);
+void	lwzx(ulong);
+void	mcrxr(ulong);
+void	mfcr(ulong);
+void	mfmsr(ulong);
+void	mfpmr(ulong);
+void	mfspr(ulong);
+void	mfsr(ulong);
+void	mfsrin(ulong);
+void	mftb(ulong);
+void	mftbu(ulong);
+void	mspr(ulong);
+void	mtcrf(ulong);
+void	mtmsr(ulong);
+void	mtpmr(ulong);
+void	mtspr(ulong);
+void	mtsr(ulong);
+void	mtsrin(ulong);
+void	mttb(ulong);
+void	mttbu(ulong);
+void	mulhw(ulong);
+void	mulhwu(ulong);
+void	mullw(ulong);
+void	nand(ulong);
+void	neg(ulong);
+void	nor(ulong);
+void	or(ulong);
+void	orc(ulong);
+void	slbia(ulong);
+void	slbia(ulong);
+void	slw(ulong);
+void	sraw(ulong);
+void	srawi(ulong);
+void	srw(ulong);
+void	stbx(ulong);
+void	stfdx(ulong);
+void	stfiwx(ulong);
+void	stfsx(ulong);
+void	sthbrx(ulong);
+void	sthx(ulong);
+void	stswi(ulong);
+void	stswx(ulong);
+void	stwbrx(ulong);
+void	stwcx(ulong);
+void	stwx(ulong);
+void	subf(ulong);
+void	subfc(ulong);
+void	subfe(ulong);
+void	subfme(ulong);
+void	subfze(ulong);
+void	sync(ulong);
+void	tlbie(ulong);
+void	tw(ulong);
+void	xor(ulong);
+
+Inst	op31[] = {
+[0] {cmp, "cmp", Iarith},
+[4] {tw, "tw", Iarith},
+[8] {subfc, "subfc", Iarith},
+[10] {addc, "addc", Iarith},
+[11] {mulhwu, "mulhwu", Iarith},
+[19] {mfcr, "mfcr", Iarith},
+[20] {lwarx, "lwarx", Iload},
+[23] {lwzx, "lwzx", Iload},
+[24] {slw, "slw", Ilog},
+[26] {cntlzw, "cntlzw", Ilog},
+[28] {and, "and", Ilog},
+[32] {cmpl, "cmpl", Iarith},
+[40] {subf, "subf", Iarith},
+[54] {dcbst, "dcbst", Icontrol},
+[55] {lwzx, "lwzux", Iload},
+[60] {andc, "andc", Ilog},
+[75] {mulhw, "mulhw", Iarith},
+[83] {0, "mfmsr", Icontrol},
+[86] {dcbf, "dcbf", Icontrol},
+[87] {lbzx, "lbzx", Iload},
+[104] {neg, "neg", Iarith},
+[115] {0, "mfpmr", Iarith},
+[119] {lbzx, "lbzux", Iload},
+[124] {nor, "nor", Iarith},
+[136] {subfe, "subfe", Iarith},
+[138] {adde, "adde", Iarith},
+[144] {mtcrf, "mtcrf", Ireg},
+[146] {0, "mtmsr", Icontrol},
+[150] {stwcx, "stwcx.", Istore},
+[151] {stwx, "stwx", Istore},
+[178] {0, "mtpmr", Icontrol},
+[183] {stwx, "stwux", Istore},
+[200] {subfze, "subfze", Iarith},
+[202] {addze, "addze", Iarith},
+[210] {0, "mtsr", Ireg},
+[215] {stbx, "stbx", Istore},
+[232] {subfme, "subfme", Iarith},
+[234] {addme, "addme", Iarith},
+[235] {mullw, "mullw", Iarith},
+[242] {0, "mtsrin", Ireg},
+[246] {dcbtst, "dcbtst", Icontrol},
+[247] {stbx, "stbux", Istore},
+[266] {add, "add", Iarith},
+[275] {0, "mftb", Icontrol},
+[278] {dcbt, "dcbt", Icontrol},
+[279] {lhzx, "lhzx", Iload},
+[284] {eqv, "eqv", Ilog},
+[306] {0, "tlbie", Icontrol},
+[307] {0, "mftbu", Icontrol},
+[310] {0, "eciwx", Icontrol},
+[311] {lhzx, "lhzux", Iload},
+[316] {xor, "xor", Ilog},
+[339] {mspr, "mfspr", Ireg},
+[343] {lhax, "lhax", Iload},
+[375] {lhax, "lhaux", Iload},
+[403] {0, "mttb", Icontrol},
+[407] {sthx, "sthx", Istore},
+[412] {orc, "orc", Ilog},
+[434] {0, "slbia", Iarith},
+[435] {0, "mttbu", Icontrol},
+[438] {0, "ecowx", Icontrol},
+[439] {sthx, "sthux", Istore},
+[444] {or, "or", Ilog},
+[459] {divwu, "divwu", Iarith},
+[467] {mspr, "mtspr", Ireg},
+[470] {0, "dcbi", Icontrol},
+[476] {nand, "nand", Ilog},
+[491] {divw, "divw", Iarith},
+[498] {0, "slbia", Icontrol},
+[512] {mcrxr, "mcrxr", Ireg},
+[533] {lswx, "lswx", Iload},
+[534] {lwbrx, "lwbrx", Iload},
+[535] {lfsx, "lfsx", Ifloat},
+[536] {srw, "srw", Ilog},
+[567] {lfsx, "lfsux", Ifloat},
+[595] {0, "mfsr", Iarith},
+[597] {lswi, "lswi", Iarith},
+[598] {sync, "sync", Iarith},
+[599] {lfdx, "lfdx", Ifloat},
+[631] {lfdx, "lfdux", Ifloat},
+[659] {0, "mfsrin", Ireg},
+[661] {stswx, "stswx", Istore},
+[662] {stwbrx, "stwbrx", Istore},
+[663] {stfsx, "stfsx", Istore},
+[695] {stfsx, "stfsux", Istore},
+[725] {stswi, "stswi", Istore},
+[727] {stfdx, "stfdx", Istore},
+[759] {stfdx, "stfdux", Istore},
+[790] {lhbrx, "lhbrx", Iload},
+[792] {sraw, "sraw", Ilog},
+[824] {srawi, "srawi", Ilog},
+[854] {0, "eieio", Icontrol},
+[918] {sthbrx, "sthbrx", Istore},
+[922] {extsh, "extsh", Iarith},
+[954] {extsb, "extsb", Iarith},
+[982] {icbi, "icbi", Icontrol},
+[983] {unimp, "stfiwx", Istore},
+[1014] {dcbz, "dcbz", Icontrol},
+};
+
+Inset	ops31 = {op31, nelem(op31)};
+
+void
+mspr(ulong ir)
+{
+	int rd, ra, rb;
+	ulong *d;
+	char *n;
+	char buf[20];
+
+	getarrr(ir);
+	switch((rb<<5) | ra) {
+	case 0:
+		undef(ir);	/* was mq */
+		return;
+	case 1:
+		d = &reg.xer; n = "xer";
+		break;
+	case 268:
+	case 284:
+		d = &reg.tbl; n = "tbl";
+		break;
+	case 269:
+	case 285:
+		d = &reg.tbu; n = "tbu";
+		break;
+	case 22:
+		d = &reg.dec; n = "dec";
+		break;
+	case 8:
+		d = &reg.lr; n = "lr";
+		break;
+	case 9:
+		d = &reg.ctr; n = "ctr";
+		break;
+	default:
+		d = 0; sprint(n = buf, "spr%d", rd);
+		break;
+	}
+	if(getxo(ir) == 339) {
+		if(trace)
+			itrace("%s\tr%d,%s", ci->name, rd, n);
+		reg.r[rd] = *d;
+	} else {
+		if(trace)
+			itrace("%s\t%s,r%d", ci->name, n, rd);
+		*d = reg.r[rd];
+	}
+}
+
+static void
+setcr(int d, long r)
+{
+	int c;
+
+	c = 0;
+	if(reg.xer & XER_SO)
+		c |= 1;
+	if(r == 0)
+		c |= 2;
+	else if(r > 0)
+		c |= 4;
+	else
+		c |= 8;
+	reg.cr = (reg.cr & ~mkCR(d, 0xF)) | mkCR(d, c);
+}
+
+void
+addi(ulong ir)
+{
+	int rd, ra;
+	long imm;
+
+	getairr(ir);
+	if(trace) {
+		if(ra)
+			itrace("%s\tr%d,r%d,$0x%lux", ci->name, rd, ra, imm);
+		else
+			itrace("li\tr%d,$0x%lux", rd, imm);
+	}
+	if(ra)
+		imm += reg.r[ra];
+	reg.r[rd] = imm;
+}
+
+void
+addis(ulong ir)
+{
+	int rd, ra;
+	long imm;
+
+	getairr(ir);
+	if(trace) {
+		if(ra)
+			itrace("%s\tr%d,r%d,$0x%lux", ci->name, rd, ra, imm);
+		else
+			itrace("lis\tr%d,$0x%lux", rd, imm);
+	}
+	imm <<= 16;
+	if(ra)
+		imm += reg.r[ra];
+	reg.r[rd] = imm;
+}
+
+void
+and(ulong ir)
+{
+	int rs, ra, rb;
+
+	getlrrr(ir);
+	reg.r[ra] = reg.r[rs] & reg.r[rb];
+	if(trace)
+		itrace("%s%s\tr%d,r%d,r%d", ci->name, ir&1?".":"", ra, rs, rb);
+	if(ir & 1)
+		setcr(0, reg.r[ra]);
+}
+
+void
+andc(ulong ir)
+{
+	int rs, ra, rb;
+
+	getlrrr(ir);
+	reg.r[ra] = reg.r[rs] & ~reg.r[rb];
+	if(trace)
+		itrace("%s%s\tr%d,r%d,r%d", ci->name, ir&1?".":"", ra, rs, rb);
+	if(ir & 1)
+		setcr(0, reg.r[ra]);
+}
+
+void
+andicc(ulong ir)
+{
+	int rs, ra;
+	ulong imm;
+
+	getlirr(ir);
+	reg.r[ra] = reg.r[rs] & imm;
+	if(trace)
+		itrace("%s\tr%d,r%d,$0x%lx", ci->name, ra, rs, imm);
+	setcr(0, reg.r[ra]);
+}
+
+void
+andiscc(ulong ir)
+{
+	int rs, ra;
+	ulong imm;
+
+	getlirr(ir);
+	reg.r[ra] = reg.r[rs] & (imm<<16);
+	if(trace)
+		itrace("%s\tr%d,r%d,$0x%lx", ci->name, ra, rs, imm);
+	setcr(0, reg.r[ra]);
+}
+
+void
+cmpli(ulong ir)
+{
+	int rd, ra;
+	ulong c;
+	ulong imm, v;
+
+	getairr(ir);
+	imm &= 0xFFFF;
+	if(rd & 3)
+		undef(ir);
+	rd >>= 2;
+	v = reg.r[ra];
+	c = 0;
+	if(reg.xer & XER_SO)
+		c |= CRSO;
+	if(v < imm)
+		c |= CRLT;
+	else if(v == imm)
+		c |= CREQ;
+	else
+		c |= CRGT;
+	c >>= 28;
+	reg.cr = (reg.cr & ~mkCR(rd, 0xF)) | mkCR(rd, c);
+	if(trace)
+		itrace("%s\tcrf%d,r%d,0x%lux [cr=#%x]", ci->name, rd, ra, imm, c);
+}
+
+void
+cmp(ulong ir)
+{
+	int rd, ra, rb;
+	ulong c;
+	long va, vb;
+
+	getarrr(ir);
+	if(rd & 3)
+		undef(ir);
+	rd >>= 2;
+	c = 0;
+	if(reg.xer & XER_SO)
+		c |= CRSO;
+	va = reg.r[ra];
+	vb = reg.r[rb];
+	if(va < vb)
+		c |= CRLT;
+	else if(va == vb)
+		c |= CREQ;
+	else
+		c |= CRGT;
+	c >>= 28;
+	reg.cr = (reg.cr & ~mkCR(rd, 0xF)) | mkCR(rd, c);
+	if(trace)
+		itrace("%s\tcrf%d,r%d,r%d [cr=#%x]", ci->name, rd, ra, rb, c);
+}
+
+void
+cmpi(ulong ir)
+{
+	int rd, ra;
+	ulong c;
+	long imm, v;
+
+	getairr(ir);
+	if(rd & 3)
+		undef(ir);
+	rd >>= 2;
+	v = reg.r[ra];
+	c = 0;
+	if(reg.xer & XER_SO)
+		c |= CRSO;
+	if(v < imm)
+		c |= CRLT;
+	else if(v == imm)
+		c |= CREQ;
+	else
+		c |= CRGT;
+	c >>= 28;
+	reg.cr = (reg.cr & ~mkCR(rd, 0xF)) | mkCR(rd, c);
+	if(trace)
+		itrace("%s\tcrf%d,r%d,0x%lux [cr=#%x]", ci->name, rd, ra, imm, c);
+}
+
+void
+cmpl(ulong ir)
+{
+	int rd, ra, rb;
+	ulong c;
+	ulong va, vb;
+
+	getarrr(ir);
+	if(rd & 3)
+		undef(ir);
+	rd >>= 2;
+	c = 0;
+	if(reg.xer & XER_SO)
+		c |= CRSO;
+	va = reg.r[ra];
+	vb = reg.r[rb];
+	if(va < vb)
+		c |= CRLT;
+	else if(va == vb)
+		c |= CREQ;
+	else
+		c |= CRGT;
+	c >>= 28;
+	reg.cr = (reg.cr & ~mkCR(rd, 0xF)) | mkCR(rd, c);
+	if(trace)
+		itrace("%s\tcrf%d,r%d,r%d [cr=#%x]", ci->name, rd, ra, rb, c);
+}
+
+void
+cntlzw(ulong ir)
+{
+	int rs, ra, rb, n;
+
+	getlrrr(ir);
+	if(rb)
+		undef(ir);
+	for(n=0; n<32 && (reg.r[rs] & (1L<<(31-n))) == 0; n++)
+		;
+	reg.r[ra] = n;
+	if(trace)
+		itrace("%s%s\tr%d,r%d", ci->name, ir&1?".":"", ra, rs);
+	if(ir & 1)
+		setcr(0, reg.r[ra]);
+}
+
+void
+eqv(ulong ir)
+{
+	int rs, ra, rb;
+
+	getlrrr(ir);
+	reg.r[ra] = ~(reg.r[rs] ^ reg.r[rb]);
+	if(trace)
+		itrace("%s%s\tr%d,r%d,r%d", ci->name, ir&1?".":"", ra, rs, rb);
+	if(ir & 1)
+		setcr(0, reg.r[ra]);
+}
+
+void
+extsb(ulong ir)
+{
+	int rs, ra, rb;
+
+	getlrrr(ir);
+	if(rb)
+		undef(ir);
+	reg.r[ra] = (schar)reg.r[rs];
+	if(trace)
+		itrace("%s%s\tr%d,r%d", ci->name, ir&1?".":"", ra, rs);
+	if(ir & 1)
+		setcr(0, reg.r[ra]);
+}
+
+void
+extsh(ulong ir)
+{
+	int rs, ra, rb;
+
+	getlrrr(ir);
+	if(rb)
+		undef(ir);
+	reg.r[ra] = (short)reg.r[rs];
+	if(trace)
+		itrace("%s%s\tr%d,r%d", ci->name, ir&1?".":"", ra, rs);
+	if(ir & 1)
+		setcr(0, reg.r[ra]);
+}
+
+void
+add(ulong ir)
+{
+	int rd, ra, rb;
+	uvlong r;
+
+	getarrr(ir);
+	r = (uvlong)(ulong)reg.r[ra] + reg.r[rb];
+	if(ir & OE) {
+		reg.xer &= ~XER_OV;
+		if(r >> 16)
+			reg.xer |= XER_SO | XER_OV;
+	}
+	reg.r[rd] = (ulong)r;
+	if(ir & Rc)
+		setcr(0, reg.r[rd]);
+	if(trace)
+		itrace("%s%s%s\tr%d,r%d,r%d", ci->name, ir&OE?"o":"", ir&1?".":"", rd, ra, rb);
+}
+
+void
+addc(ulong ir)
+{
+	int rd, ra, rb;
+	ulong v;
+	uvlong r;
+
+	getarrr(ir);
+	r = (uvlong)(ulong)reg.r[ra] + reg.r[rb];
+	v = r>>32;
+	reg.xer &= ~XER_CA;
+	if(v)
+		reg.xer |= XER_CA;
+	if(ir & OE) {
+		reg.xer &= ~XER_OV;
+		if(v>>1)
+			reg.xer |= XER_SO | XER_OV;
+	}
+	reg.r[rd] = (ulong)r;
+	if(ir & Rc)
+		setcr(0, reg.r[rd]);
+	if(trace)
+		itrace("%s%s%s\tr%d,r%d,r%d", ci->name, ir&OE?"o":"", ir&1?".":"", rd, ra, rb);
+}
+
+void
+adde(ulong ir)
+{
+	int rd, ra, rb;
+	ulong v;
+	uvlong r;
+
+	getarrr(ir);
+	r = (uvlong)(ulong)reg.r[ra] + reg.r[rb] + (reg.xer&XER_CA)!=0;
+	v = r>>32;
+	reg.xer &= ~XER_CA;
+	if(v)
+		reg.xer |= XER_CA;
+	if(ir & OE) {
+		reg.xer &= ~XER_OV;
+		if(v>>1)
+			reg.xer |= XER_SO | XER_OV;
+	}
+	reg.r[rd] = (ulong)r;
+	if(ir & Rc)
+		setcr(0, reg.r[rd]);
+	if(trace)
+		itrace("%s%s%s\tr%d,r%d,r%d", ci->name, ir&OE?"o":"", ir&1?".":"", rd, ra, rb);
+}
+
+void
+addic(ulong ir)
+{
+	int rd, ra;
+	long imm;
+	ulong v;
+	uvlong r;
+
+	getairr(ir);
+	r = (uvlong)(ulong)reg.r[ra] + imm;
+	v = r>>32;
+	reg.xer &= ~XER_CA;
+	if(v)
+		reg.xer |= XER_CA;
+	reg.r[rd] = (ulong)r;
+	if(trace)
+		itrace("%s\tr%d,r%d,$%ld", ci->name, rd, ra, imm);
+}
+
+void
+addiccc(ulong ir)
+{
+	int rd, ra;
+	long imm;
+	ulong v;
+	uvlong r;
+
+	getairr(ir);
+	r = (uvlong)(ulong)reg.r[ra] + imm;
+	v = r>>32;
+	reg.xer &= ~XER_CA;
+	if(v)
+		reg.xer |= XER_CA;
+	reg.r[rd] = (ulong)r;
+	setcr(0, reg.r[rd]);
+	if(trace)
+		itrace("%s\tr%d,r%d,$%ld", ci->name, rd, ra, imm);
+}
+
+void
+addme(ulong ir)
+{
+	int rd, ra, rb;
+	ulong v;
+	uvlong r;
+
+	getarrr(ir);
+	if(rb)
+		undef(ir);
+	r = (uvlong)(ulong)reg.r[ra] + 0xFFFFFFFF + (reg.xer&XER_CA)!=0;
+	v = r>>32;
+	reg.xer &= ~XER_CA;
+	if(v)
+		reg.xer |= XER_CA;
+	if(ir & OE) {
+		reg.xer &= ~XER_OV;
+		if(v>>1)
+			reg.xer |= XER_SO | XER_OV;
+	}
+	reg.r[rd] = (ulong)r;
+	if(ir & Rc)
+		setcr(0, reg.r[rd]);
+	if(trace)
+		itrace("%s%s%s\tr%d,r%d", ci->name, ir&OE?"o":"", ir&1?".":"", rd, ra);
+}
+
+void
+addze(ulong ir)
+{
+	int rd, ra, rb;
+	ulong v;
+	uvlong r;
+
+	getarrr(ir);
+	if(rb)
+		undef(ir);
+	r = (uvlong)(ulong)reg.r[ra] + (reg.xer&XER_CA)!=0;
+	v = r>>32;
+	reg.xer &= ~XER_CA;
+	if(v)
+		reg.xer |= XER_CA;
+	if(ir & OE) {
+		reg.xer &= ~XER_OV;
+		if(v>>1)
+			reg.xer |= XER_SO | XER_OV;
+	}
+	reg.r[rd] = (ulong)r;
+	if(ir & Rc)
+		setcr(0, reg.r[rd]);
+	if(trace)
+		itrace("%s%s%s\tr%d,r%d", ci->name, ir&OE?"o":"", ir&1?".":"", rd, ra);
+}
+
+void
+divw(ulong ir)
+{
+	int rd, ra, rb;
+
+	getarrr(ir);
+	if(reg.r[rb] != 0 && ((ulong)reg.r[ra] != 0x80000000 || reg.r[rb] != -1))
+		reg.r[rd] = reg.r[ra]/reg.r[rb];
+	else if(ir & OE)
+		reg.xer |= XER_SO | XER_OV;
+	if(ir & Rc)
+		setcr(0, reg.r[rd]);
+	if(trace)
+		itrace("%s%s%s\tr%d,r%d,r%d", ci->name, ir&OE?"o":"", ir&1?".":"", rd, ra, rb);
+}
+
+void
+divwu(ulong ir)
+{
+	int rd, ra, rb;
+
+	getarrr(ir);
+	if(reg.r[rb] != 0)
+		reg.r[rd] = (ulong)reg.r[ra]/(ulong)reg.r[rb];
+	else if(ir & OE)
+		reg.xer |= XER_SO | XER_OV;
+	if(ir & Rc)
+		setcr(0, reg.r[rd]);
+	if(trace)
+		itrace("%s%s%s\tr%d,r%d,r%d", ci->name, ir&OE?"o":"", ir&1?".":"", rd, ra, rb);
+}
+
+void
+mcrxr(ulong ir)
+{
+	int rd, ra, rb;
+
+	getarrr(ir);
+	if(rd & 3 || ra != 0 || rb != 0 || ir & Rc)
+		undef(ir);
+	rd >>= 2;
+	reg.cr = (reg.cr & ~mkCR(rd, 0xF)) | mkCR(rd, reg.xer>>28);
+	reg.xer &= ~(0xF<<28);
+}
+
+void
+mtcrf(ulong ir)
+{
+	int rs, crm, i;
+	ulong m;
+
+	if(ir & ((1<<20)|(1<<11)|Rc))
+		undef(ir);
+	rs = (ir>>21)&0x1F;
+	crm = (ir>>12)&0xFF;
+	m = 0;
+	for(i = 0x80; i; i >>= 1) {
+		m <<= 4;
+		if(crm & i)
+			m |= 0xF;
+	}
+	reg.cr = (reg.cr & ~m) | (reg.r[rs] & m);
+}
+
+void
+mfcr(ulong ir)
+{
+	int rd, ra, rb;
+
+	getarrr(ir);
+	if(ra != 0 || rb != 0 || ir & Rc)
+		undef(ir);
+	reg.r[rd] = reg.cr;
+}
+
+void
+mulhw(ulong ir)
+{
+	int rd, ra, rb;
+
+	getarrr(ir);
+	reg.r[rd] = ((vlong)(long)reg.r[ra]*(long)reg.r[rb])>>32;
+	if(ir & Rc)
+		setcr(0, reg.r[rd]);
+	if(trace)
+		itrace("%s%s%s\tr%d,r%d,r%d", ci->name, ir&OE?"o":"", ir&Rc?".":"", rd, ra, rb);
+	/* BUG: doesn't set OV */
+}
+
+void
+mulhwu(ulong ir)
+{
+	int rd, ra, rb;
+
+	getarrr(ir);
+	reg.r[rd] = ((uvlong)(ulong)reg.r[ra]*(ulong)reg.r[rb])>>32;
+	if(ir & Rc)
+		setcr(0, reg.r[rd]);	/* not sure whether CR setting is signed or unsigned */
+	if(trace)
+		itrace("%s%s%s\tr%d,r%d,r%d", ci->name, ir&OE?"o":"", ir&Rc?".":"", rd, ra, rb);
+	/* BUG: doesn't set OV */
+}
+
+void
+mullw(ulong ir)
+{
+	int rd, ra, rb;
+
+	getarrr(ir);
+	reg.r[rd] = (uvlong)(ulong)reg.r[ra]*(ulong)reg.r[rb];
+	if(ir & Rc)
+		setcr(0, reg.r[rd]);
+	if(trace)
+		itrace("%s%s%s\tr%d,r%d,r%d", ci->name, ir&OE?"o":"", ir&Rc?".":"", rd, ra, rb);
+	/* BUG: doesn't set OV */
+}
+
+void
+mulli(ulong ir)
+{
+	int rd, ra;
+	long imm;
+
+	getairr(ir);
+	reg.r[rd] = (uvlong)(ulong)reg.r[ra]*(ulong)imm;
+	if(trace)
+		itrace("%s\tr%d,r%d,$%ld", ci->name, rd, ra, imm);
+}
+
+void
+nand(ulong ir)
+{
+	int rs, ra, rb;
+
+	getlrrr(ir);
+	reg.r[ra] = ~(reg.r[rs] & reg.r[rb]);
+	if(ir & Rc)
+		setcr(0, reg.r[ra]);
+	if(trace)
+		itrace("%s%s\tr%d,r%d,r%d", ci->name, ir&1?".":"", ra, rs, rb);
+}
+
+void
+neg(ulong ir)
+{
+	int rd, ra, rb;
+
+	getarrr(ir);
+	if(rb)
+		undef(ir);
+	if(ir & OE)
+		reg.xer &= ~XER_OV;
+	if((ulong)reg.r[ra] == 0x80000000) {
+		if(ir & OE)
+			reg.xer |= XER_SO | XER_OV;
+		reg.r[rd] = reg.r[ra];
+	} else
+		reg.r[rd] = -reg.r[ra];
+	if(ir & Rc)
+		setcr(0, reg.r[rd]);
+}
+
+void
+nor(ulong ir)
+{
+	int rs, ra, rb;
+
+	getlrrr(ir);
+	reg.r[ra] = ~(reg.r[rs] | reg.r[rb]);
+	if(ir & Rc)
+		setcr(0, reg.r[ra]);
+	if(trace)
+		itrace("%s%s\tr%d,r%d,r%d", ci->name, ir&1?".":"", ra, rs, rb);
+}
+
+void
+or(ulong ir)
+{
+	int rs, ra, rb;
+
+	getlrrr(ir);
+	reg.r[ra] = reg.r[rs] | reg.r[rb];
+	if(ir & Rc)
+		setcr(0, reg.r[ra]);
+	if(trace) {
+		if(rs == rb)
+			itrace("mr%s\tr%d,r%d", ir&1?".":"", ra, rs);
+		else
+			itrace("%s%s\tr%d,r%d,r%d", ci->name, ir&1?".":"", ra, rs, rb);
+	}
+}
+
+void
+orc(ulong ir)
+{
+	int rs, ra, rb;
+
+	getlrrr(ir);
+	reg.r[ra] = reg.r[rs] | ~reg.r[rb];
+	if(ir & Rc)
+		setcr(0, reg.r[ra]);
+	if(trace)
+		itrace("%s%s\tr%d,r%d,r%d", ci->name, ir&1?".":"", ra, rs, rb);
+}
+
+void
+ori(ulong ir)
+{
+	int rs, ra;
+	ulong imm;
+
+	getlirr(ir);
+	reg.r[ra] = reg.r[rs] | imm;
+	if(trace)
+		itrace("%s\tr%d,r%d,$0x%lx", ci->name, ra, rs, imm);
+}
+
+void
+oris(ulong ir)
+{
+	int rs, ra;
+	ulong imm;
+
+	getlirr(ir);
+	reg.r[ra] = reg.r[rs] | (imm<<16);
+	if(trace)
+		itrace("%s\tr%d,r%d,$0x%lx", ci->name, ra, rs, imm);
+}
+
+static ulong
+mkmask(int mb, int me)
+{
+	int i;
+	ulong v;
+
+	if(mb > me)
+		return mkmask(0, me) | mkmask(mb, 31);
+	v = 0;
+	for(i=mb; i<=me; i++)
+		v |= 1L << (31-i);	/* don't need a loop, but i'm lazy */
+	return v;
+}
+
+static ulong
+rotl(ulong v, int sh)
+{
+	if(sh == 0)
+		return v;
+	return (v<<sh) | (v>>(32-sh));
+}
+
+void
+rlwimi(ulong ir)
+{
+	int rs, ra, rb, sh;
+	ulong m;
+
+	getlrrr(ir);
+	sh = rb;
+	m = mkmask((ir>>6)&0x1F, (ir>>1)&0x1F);
+	reg.r[ra] = (reg.r[ra] & ~m) | (rotl(reg.r[rs], sh) & m);
+	if(trace)
+		itrace("%s\tr%d,r%d,%d,#%lux", ci->name, ra, rs, sh, m);
+	if(ir & 1)
+		setcr(0, reg.r[ra]);
+}
+
+void
+rlwinm(ulong ir)
+{
+	int rs, ra, rb, sh;
+	ulong m;
+
+	getlrrr(ir);
+	sh = rb;
+	m = mkmask((ir>>6)&0x1F, (ir>>1)&0x1F);
+	reg.r[ra] = rotl(reg.r[rs], sh) & m;
+	if(trace)
+		itrace("%s%s\tr%d,r%d,%d,#%lux", ci->name, ir&Rc?".":"", ra, rs, sh, m);
+	if(ir & Rc)
+		setcr(0, reg.r[ra]);
+}
+
+void
+rlwnm(ulong ir)
+{
+	int rs, ra, rb, sh;
+	ulong m;
+
+	getlrrr(ir);
+	sh = reg.r[rb] & 0x1F;
+	m = mkmask((ir>>6)&0x1F, (ir>>1)&0x1F);
+	reg.r[ra] = rotl(reg.r[rs], sh) & m;
+	if(trace)
+		itrace("%s\tr%d,r%d,r%d,#%lux", ci->name, ra, rs, rb, m);
+	if(ir & 1)
+		setcr(0, reg.r[ra]);
+}
+
+void
+slw(ulong ir)
+{
+	int rs, ra, rb;
+	long v;
+
+	getlrrr(ir);
+	v = reg.r[rb];
+	if((v & 0x20) == 0) {
+		v &= 0x1F;
+		reg.r[ra] = (ulong)reg.r[rs] << v;
+	} else
+		reg.r[ra] = 0;
+	if(ir & Rc)
+		setcr(0, reg.r[ra]);
+	if(trace)
+		itrace("%s%s\tr%d,r%d,r%d", ci->name, ir&1?".":"", ra, rs, rb);
+}
+
+void
+sraw(ulong ir)
+{
+	int rs, ra, rb;
+	long v;
+
+	getlrrr(ir);
+	v = reg.r[rb];
+	if((v & 0x20) == 0) {
+		v &= 0x1F;
+		if(reg.r[rs]&SIGNBIT && v)
+			reg.r[ra] = reg.r[rs]>>v | ~((1<<(32-v))-1);
+		else
+			reg.r[ra] = reg.r[rs]>>v;
+	} else
+		reg.r[ra] = reg.r[rs]&SIGNBIT? ~0: 0;
+	if(ir & Rc)
+		setcr(0, reg.r[ra]);
+	if(trace)
+		itrace("%s%s\tr%d,r%d,r%d", ci->name, ir&1?".":"", ra, rs, rb);
+}
+
+void
+srawi(ulong ir)
+{
+	int rs, ra, rb;
+	long v;
+
+	getlrrr(ir);
+	v = rb;
+	if((v & 0x20) == 0) {
+		v &= 0x1F;
+		if(reg.r[rs]&SIGNBIT && v)
+			reg.r[ra] = reg.r[rs]>>v | ~((1<<(32-v))-1);
+		else
+			reg.r[ra] = reg.r[rs]>>v;
+	} else
+		reg.r[ra] = reg.r[rs]&SIGNBIT? ~0: 0;
+	if(ir & Rc)
+		setcr(0, reg.r[ra]);
+	if(trace)
+		itrace("%s%s\tr%d,r%d,$%d", ci->name, ir&1?".":"", ra, rs, v);
+}
+
+void
+srw(ulong ir)
+{
+	int rs, ra, rb;
+	long v;
+
+	getlrrr(ir);
+	v = reg.r[rb];
+	if((v & 0x20) == 0)
+		reg.r[ra] = (ulong)reg.r[rs] >> (v&0x1F);
+	else
+		reg.r[ra] = 0;
+	if(ir & Rc)
+		setcr(0, reg.r[ra]);
+	if(trace)
+		itrace("%s%s\tr%d,r%d,r%d", ci->name, ir&1?".":"", ra, rs, rb);
+}
+
+void
+subf(ulong ir)
+{
+	int rd, ra, rb;
+	uvlong r;
+
+	getarrr(ir);
+	r = (uvlong)((ulong)~reg.r[ra]) + reg.r[rb] + 1;
+	if(ir & OE) {
+		reg.xer &= ~XER_OV;
+		if(r >> 16)
+			reg.xer |= XER_SO | XER_OV;
+	}
+	reg.r[rd] = (ulong)r;
+	if(ir & Rc)
+		setcr(0, reg.r[rd]);
+	if(trace)
+		itrace("%s%s%s\tr%d,r%d,r%d", ci->name, ir&OE?"o":"", ir&1?".":"", rd, ra, rb);
+}
+
+void
+subfc(ulong ir)
+{
+	int rd, ra, rb;
+	ulong v;
+	uvlong r;
+
+	getarrr(ir);
+	r = (uvlong)((ulong)~reg.r[ra]) + reg.r[rb] + 1;
+	v = r>>32;
+	reg.xer &= ~XER_CA;
+	if(v)
+		reg.xer |= XER_CA;
+	if(ir & OE) {
+		reg.xer &= ~XER_OV;
+		if(v>>1)
+			reg.xer |= XER_SO | XER_OV;
+	}
+	reg.r[rd] = (ulong)r;
+	if(ir & Rc)
+		setcr(0, reg.r[rd]);
+	if(trace)
+		itrace("%s%s%s\tr%d,r%d,r%d", ci->name, ir&OE?"o":"", ir&1?".":"", rd, ra, rb);
+}
+
+void
+subfe(ulong ir)
+{
+	int rd, ra, rb;
+	ulong v;
+	uvlong r;
+
+	getarrr(ir);
+	r = (uvlong)((ulong)~reg.r[ra]) + reg.r[rb] + (reg.xer&XER_CA)!=0;
+	v = r>>32;
+	reg.xer &= ~XER_CA;
+	if(v)
+		reg.xer |= XER_CA;
+	if(ir & OE) {
+		reg.xer &= ~XER_OV;
+		if(v>>1)
+			reg.xer |= XER_SO | XER_OV;
+	}
+	reg.r[rd] = (ulong)r;
+	if(ir & Rc)
+		setcr(0, reg.r[rd]);
+	if(trace)
+		itrace("%s%s%s\tr%d,r%d,r%d", ci->name, ir&OE?"o":"", ir&1?".":"", rd, ra, rb);
+}
+
+void
+subfic(ulong ir)
+{
+	int rd, ra;
+	long imm;
+	ulong v;
+	uvlong r;
+
+	getairr(ir);
+	r = (uvlong)((ulong)~reg.r[ra]) + imm + 1;
+	v = r>>32;
+	reg.xer &= ~XER_CA;
+	if(v)
+		reg.xer |= XER_CA;
+	reg.r[rd] = (ulong)r;
+	if(trace)
+		itrace("%s\tr%d,r%d,$%ld", ci->name, rd, ra, imm);
+}
+