/*
 * PowerPC definition
 *	forsyth@plan9.cs.york.ac.uk
 */
#include <u.h>
#include <libc.h>
#include <bio.h>
#include "uregpower.h"
#include <mach.h>

/*
 * PowerPC-specific debugger interface
 *	forsyth@plan9.cs.york.ac.uk
 */

static	char	*powerexcep(Map*, Regs*);
static	int	powerfoll(Map*, Regs*, ulong, ulong*);
static	int	powerdas(Map*, ulong, char, char*, int);
static	int	powerinstlen(Map*, ulong);
static	int	powerhexinst(Map*, ulong, char*, int);

static char *excname[] =
{
	"reserved 0",
	"system reset",
	"machine check",
	"data access",
	"instruction access",
	"external interrupt",
	"alignment",
	"program exception",
	"floating-point unavailable",
	"decrementer",
	"i/o controller interface error",
	"reserved B",
	"system call",
	"trace trap",
	"floating point assist",
	"reserved",
	"ITLB miss",
	"DTLB load miss",
	"DTLB store miss",
	"instruction address breakpoint"
	"SMI interrupt"
	"reserved 15",
	"reserved 16",
	"reserved 17",
	"reserved 18",
	"reserved 19",
	"reserved 1A",
	/* the following are made up on a program exception */
	"floating point exception",		/* FPEXC */
	"illegal instruction",
	"privileged instruction",
	"trap",
	"illegal operation",
};

static char*
powerexcep(Map *map, Regs *regs)
{
	ulong c;
	static char buf[32];

	if(rget(regs, "CAUSE", &c) < 0)
		return "no cause register";
	c >>= 8;
	if(c < nelem(excname))
		return excname[c];
	sprint(buf, "unknown trap #%lux", c);
	return buf;
}

/*
 * disassemble PowerPC opcodes
 */

#define	REGSP	1	/* should come from q.out.h, but there's a clash */
#define	REGSB	2

//static	char FRAMENAME[] = ".frame";

static Map *mymap;

/*
 * ibm conventions for these: bit 0 is top bit
 *	from table 10-1
 */
typedef struct {
	uchar	aa;		/* bit 30 */
	uchar	crba;		/* bits 11-15 */
	uchar	crbb;		/* bits 16-20 */
	long	bd;		/* bits 16-29 */
	uchar	crfd;		/* bits 6-8 */
	uchar	crfs;		/* bits 11-13 */
	uchar	bi;		/* bits 11-15 */
	uchar	bo;		/* bits 6-10 */
	uchar	crbd;		/* bits 6-10 */
	/*union {*/
		short	d;	/* bits 16-31 */
		short	simm;
		ushort	uimm;
	/*};*/
	uchar	fm;		/* bits 7-14 */
	uchar	fra;		/* bits 11-15 */
	uchar	frb;		/* bits 16-20 */
	uchar	frc;		/* bits 21-25 */
	uchar	frs;		/* bits 6-10 */
	uchar	frd;		/* bits 6-10 */
	uchar	crm;		/* bits 12-19 */
	long	li;		/* bits 6-29 || b'00' */
	uchar	lk;		/* bit 31 */
	uchar	mb;		/* bits 21-25 */
	uchar	me;		/* bits 26-30 */
	uchar	nb;		/* bits 16-20 */
	uchar	op;		/* bits 0-5 */
	uchar	oe;		/* bit 21 */
	uchar	ra;		/* bits 11-15 */
	uchar	rb;		/* bits 16-20 */
	uchar	rc;		/* bit 31 */
	/*union {*/
		uchar	rs;	/* bits 6-10 */
		uchar	rd;
	/*};*/
	uchar	sh;		/* bits 16-20 */
	ushort	spr;		/* bits 11-20 */
	uchar	to;		/* bits 6-10 */
	uchar	imm;		/* bits 16-19 */
	ushort	xo;		/* bits 21-30, 22-30, 26-30, or 30 (beware) */
	long	immediate;
	long w0;
	long w1;
	ulong	addr;		/* pc of instruction */
	short	target;
	char	*curr;		/* current fill level in output buffer */
	char	*end;		/* end of buffer */
	int 	size;		/* number of longs in instr */
	char	*err;		/* errmsg */
} Instr;

#define	IBF(v,a,b) (((ulong)(v)>>(32-(b)-1)) & ~(~0L<<(((b)-(a)+1))))
#define	IB(v,b) IBF((v),(b),(b))

static void
bprint(Instr *i, char *fmt, ...)
{
	va_list arg;

	va_start(arg, fmt);
	i->curr = vseprint(i->curr, i->end, fmt, arg);
	va_end(arg);
}

static int
decode(ulong pc, Instr *i)
{
	u32int w;

	if (get4(mymap, pc, &w) < 0) {
		werrstr("can't read instruction: %r");
		return -1;
	}
	i->aa = IB(w, 30);
	i->crba = IBF(w, 11, 15);
	i->crbb = IBF(w, 16, 20);
	i->bd = IBF(w, 16, 29)<<2;
	if(i->bd & 0x8000)
		i->bd |= ~0L<<16;
	i->crfd = IBF(w, 6, 8);
	i->crfs = IBF(w, 11, 13);
	i->bi = IBF(w, 11, 15);
	i->bo = IBF(w, 6, 10);
	i->crbd = IBF(w, 6, 10);
	i->uimm = IBF(w, 16, 31);	/* also d, simm */
	i->fm = IBF(w, 7, 14);
	i->fra = IBF(w, 11, 15);
	i->frb = IBF(w, 16, 20);
	i->frc = IBF(w, 21, 25);
	i->frs = IBF(w, 6, 10);
	i->frd = IBF(w, 6, 10);
	i->crm = IBF(w, 12, 19);
	i->li = IBF(w, 6, 29)<<2;
	if(IB(w, 6))
		i->li |= ~0<<25;
	i->lk = IB(w, 31);
	i->mb = IBF(w, 21, 25);
	i->me = IBF(w, 26, 30);
	i->nb = IBF(w, 16, 20);
	i->op = IBF(w, 0, 5);
	i->oe = IB(w, 21);
	i->ra = IBF(w, 11, 15);
	i->rb = IBF(w, 16, 20);
	i->rc = IB(w, 31);
	i->rs = IBF(w, 6, 10);	/* also rd */
	i->sh = IBF(w, 16, 20);
	i->spr = IBF(w, 11, 20);
	i->to = IBF(w, 6, 10);
	i->imm = IBF(w, 16, 19);
	i->xo = IBF(w, 21, 30);		/* bits 21-30, 22-30, 26-30, or 30 (beware) */
	i->immediate = i->simm;
	if(i->op == 15)
		i->immediate <<= 16;
	i->w0 = w;
	i->target = -1;
	i->addr = pc;
	i->size = 1;
	return 1;
}

static int
mkinstr(ulong pc, Instr *i)
{
	Instr x;

	if(decode(pc, i) < 0)
		return -1;
	/*
	 * combine ADDIS/ORI (CAU/ORIL) into MOVW
	 */
	if (i->op == 15 && i->ra==0) {
		if(decode(pc+4, &x) < 0)
			return -1;
		if (x.op == 24 && x.rs == x.ra && x.ra == i->rd) {
			i->immediate |= (x.immediate & 0xFFFF);
			i->w1 = x.w0;
			i->target = x.rd;
			i->size++;
			return 1;
		}
	}
	return 1;
}

static int
plocal(Instr *i)
{
	Symbol s;
	Loc l, li;

	l.type = LOFFSET;
	l.offset = i->immediate;
	l.reg = "SP";

	li.type = LADDR;
	li.addr = i->addr;
	if (findsym(li, CTEXT, &s)<0 || findlsym(&s, l, &s)<0)
		return -1;
	bprint(i, "%s%+ld(SP)", s.name, (long)i->immediate);
	return 0;
}

static int
pglobal(Instr *i, long off, int anyoff, char *reg)
{
	Symbol s, s2;
	u32int off1;
	Loc l;

	l.type = LADDR;
	l.addr = off;
	if(findsym(l, CANY, &s)>=0 && s.loc.type==LADDR &&
	   s.loc.addr-off < 4096 &&
	   (s.class == CDATA || s.class == CTEXT)) {
		if(off==s.loc.addr && s.name[0]=='$'){
			off1 = 0;
			get4(mymap, s.loc.addr, &off1);
			l.addr = off1;
			if(off1 && findsym(l, CANY, &s2)>=0 && s2.loc.type==LADDR && s2.loc.addr == off1){
				bprint(i, "$%s%s", s2.name, reg);
				return 1;
			}
		}
		bprint(i, "%s", s.name);
		if (s.loc.addr != off)
			bprint(i, "+%lux", off-s.loc.addr);
		bprint(i, reg);
		return 1;
	}
	if(!anyoff)
		return 0;
	bprint(i, "%lux%s", off, reg);
	return 1;
}

static void
address(Instr *i)
{
	if (i->ra == REGSP && plocal(i) >= 0)
		return;
	if (i->ra == REGSB && mach->sb && pglobal(i, mach->sb+i->immediate, 0, "(SB)") >= 0)
		return;
	if(i->simm < 0)
		bprint(i, "-%lx(R%d)", -i->simm, i->ra);
	else
		bprint(i, "%lux(R%d)", i->immediate, i->ra);
}

static	char	*tcrbits[] = {"LT", "GT", "EQ", "VS"};
static	char	*fcrbits[] = {"GE", "LE", "NE", "VC"};

typedef struct Opcode Opcode;

struct Opcode {
	uchar	op;
	ushort	xo;
	ushort	xomask;
	char	*mnemonic;
	void	(*f)(Opcode *, Instr *);
	char	*ken;
	int	flags;
};

static void format(char *, Instr *, char *);

static void
branch(Opcode *o, Instr *i)
{
	char buf[8];
	int bo, bi;

	bo = i->bo & ~1;	/* ignore prediction bit */
	if(bo==4 || bo==12 || bo==20) {	/* simple forms */
		if(bo != 20) {
			bi = i->bi&3;
			sprint(buf, "B%s%%L", bo==12? tcrbits[bi]: fcrbits[bi]);
			format(buf, i, 0);
			bprint(i, "\t");
			if(i->bi > 4)
				bprint(i, "CR(%d),", i->bi/4);
		} else
			format("BR%L\t", i, 0);
		if(i->op == 16)
			format(0, i, "%J");
		else if(i->op == 19 && i->xo == 528)
			format(0, i, "(CTR)");
		else if(i->op == 19 && i->xo == 16)
			format(0, i, "(LR)");
	} else
		format(o->mnemonic, i, o->ken);
}

static void
addi(Opcode *o, Instr *i)
{
	if (i->op==14 && i->ra == 0)
		format("MOVW", i, "%i,R%d");
	else if (i->ra == REGSB) {
		bprint(i, "MOVW\t$");
		address(i);
		bprint(i, ",R%d", i->rd);
	} else if(i->op==14 && i->simm < 0) {
		bprint(i, "SUB\t$%d,R%d", -i->simm, i->ra);
		if(i->rd != i->ra)
			bprint(i, ",R%d", i->rd);
	} else if(i->ra == i->rd) {
		format(o->mnemonic, i, "%i");
		bprint(i, ",R%d", i->rd);
	} else
		format(o->mnemonic, i, o->ken);
}

static void
addis(Opcode *o, Instr *i)
{
	long v;

	v = i->immediate;
	if (i->op==15 && i->ra == 0)
		bprint(i, "MOVW\t$%lux,R%d", v, i->rd);
	else if (i->op==15 && i->ra == REGSB) {
		bprint(i, "MOVW\t$");
		address(i);
		bprint(i, ",R%d", i->rd);
	} else if(i->op==15 && v < 0) {
		bprint(i, "SUB\t$%d,R%d", -v, i->ra);
		if(i->rd != i->ra)
			bprint(i, ",R%d", i->rd);
	} else {
		format(o->mnemonic, i, 0);
		bprint(i, "\t$%ld,R%d", v, i->ra);
		if(i->rd != i->ra)
			bprint(i, ",R%d", i->rd);
	}
}

static void
andi(Opcode *o, Instr *i)
{
	if (i->ra == i->rs)
		format(o->mnemonic, i, "%I,R%d");
	else
		format(o->mnemonic, i, o->ken);
}

static void
gencc(Opcode *o, Instr *i)
{
	format(o->mnemonic, i, o->ken);
}

static void
gen(Opcode *o, Instr *i)
{
	format(o->mnemonic, i, o->ken);
	if (i->rc)
		bprint(i, " [illegal Rc]");
}

static void
ldx(Opcode *o, Instr *i)
{
	if(i->ra == 0)
		format(o->mnemonic, i, "(R%b),R%d");
	else
		format(o->mnemonic, i, "(R%b+R%a),R%d");
	if(i->rc)
		bprint(i, " [illegal Rc]");
}

static void
stx(Opcode *o, Instr *i)
{
	if(i->ra == 0)
		format(o->mnemonic, i, "R%d,(R%b)");
	else
		format(o->mnemonic, i, "R%d,(R%b+R%a)");
	if(i->rc && i->xo != 150)
		bprint(i, " [illegal Rc]");
}

static void
fldx(Opcode *o, Instr *i)
{
	if(i->ra == 0)
		format(o->mnemonic, i, "(R%b),F%d");
	else
		format(o->mnemonic, i, "(R%b+R%a),F%d");
	if(i->rc)
		bprint(i, " [illegal Rc]");
}

static void
fstx(Opcode *o, Instr *i)
{
	if(i->ra == 0)
		format(o->mnemonic, i, "F%d,(R%b)");
	else
		format(o->mnemonic, i, "F%d,(R%b+R%a)");
	if(i->rc)
		bprint(i, " [illegal Rc]");
}

static void
dcb(Opcode *o, Instr *i)
{
	if(i->ra == 0)
		format(o->mnemonic, i, "(R%b)");
	else
		format(o->mnemonic, i, "(R%b+R%a)");
	if(i->rd)
		bprint(i, " [illegal Rd]");
	if(i->rc)
		bprint(i, " [illegal Rc]");
}

static void
lw(Opcode *o, Instr *i, char r)
{
	bprint(i, "%s\t", o->mnemonic);
	address(i);
	bprint(i, ",%c%d", r, i->rd);
}

static void
load(Opcode *o, Instr *i)
{
	lw(o, i, 'R');
}

static void
fload(Opcode *o, Instr *i)
{
	lw(o, i, 'F');
}

static void
sw(Opcode *o, Instr *i, char r)
{
	char *m;
	Symbol s;
	Loc l;

	m = o->mnemonic;
	if (i->rs == REGSP) {
		l.type = LADDR;
		l.addr = i->addr;
		if (findsym(l, CTEXT, &s)>=0) {
			l.type = LOFFSET;
			l.reg = "SP";
			l.offset = i->immediate;
			if (findlsym(&s, l, &s) >= 0) {
				bprint(i, "%s\t%c%d,%s-%d(SP)", m, r, i->rd,
					s.name, i->immediate);
				return;
			}
		}
	}
	if (i->rs == REGSB && mach->sb) {
		bprint(i, "%s\t%c%d,", m, r, i->rd);
		address(i);
		return;
	}
	if (r == 'F')
		format(m, i, "F%d,%l");
	else
		format(m, i, o->ken);
}

static void
store(Opcode *o, Instr *i)
{
	sw(o, i, 'R');
}

static void
fstore(Opcode *o, Instr *i)
{
	sw(o, i, 'F');
}

static void
shifti(Opcode *o, Instr *i)
{
	if (i->ra == i->rs)
		format(o->mnemonic, i, "$%k,R%a");
	else
		format(o->mnemonic, i, o->ken);
}

static void
shift(Opcode *o, Instr *i)
{
	if (i->ra == i->rs)
		format(o->mnemonic, i, "R%b,R%a");
	else
		format(o->mnemonic, i, o->ken);
}

static void
add(Opcode *o, Instr *i)
{
	if (i->rd == i->ra)
		format(o->mnemonic, i, "R%b,R%d");
	else if (i->rd == i->rb)
		format(o->mnemonic, i, "R%a,R%d");
	else
		format(o->mnemonic, i, o->ken);
}

static void
sub(Opcode *o, Instr *i)
{
	format(o->mnemonic, i, 0);
	bprint(i, "\t");
	if(i->op == 31) {
		bprint(i, "\tR%d,R%d", i->ra, i->rb);	/* subtract Ra from Rb */
		if(i->rd != i->rb)
			bprint(i, ",R%d", i->rd);
	} else
		bprint(i, "\tR%d,$%d,R%d", i->ra, i->simm, i->rd);
}

#define div power_div

static void
div(Opcode *o, Instr *i)
{
	format(o->mnemonic, i, 0);
	if(i->op == 31)
		bprint(i, "\tR%d,R%d", i->rb, i->ra);
	else
		bprint(i, "\t$%d,R%d", i->simm, i->ra);
	if(i->ra != i->rd)
		bprint(i, ",R%d", i->rd);
}

static void
and(Opcode *o, Instr *i)
{
	if (i->op == 31) {
		/* Rb,Rs,Ra */
		if (i->ra == i->rs)
			format(o->mnemonic, i, "R%b,R%a");
		else if (i->ra == i->rb)
			format(o->mnemonic, i, "R%s,R%a");
		else
			format(o->mnemonic, i, o->ken);
	} else {
		/* imm,Rs,Ra */
		if (i->ra == i->rs)
			format(o->mnemonic, i, "%I,R%a");
		else
			format(o->mnemonic, i, o->ken);
	}
}

static void
or(Opcode *o, Instr *i)
{
	if (i->op == 31) {
		/* Rb,Rs,Ra */
		if (i->rs == 0 && i->ra == 0 && i->rb == 0)
			format("NOP", i, 0);
		else if (i->rs == i->rb)
			format("MOVW", i, "R%b,R%a");
		else
			and(o, i);
	} else
		and(o, i);
}

static void
shifted(Opcode *o, Instr *i)
{
	format(o->mnemonic, i, 0);
	bprint(i, "\t$%lux,", (ulong)i->uimm<<16);
	if (i->rs == i->ra)
		bprint(i, "R%d", i->ra);
	else
		bprint(i, "R%d,R%d", i->rs, i->ra);
}

static void
neg(Opcode *o, Instr *i)
{
	if (i->rd == i->ra)
		format(o->mnemonic, i, "R%d");
	else
		format(o->mnemonic, i, o->ken);
}

static	char	ir2[] = "R%a,R%d";		/* reverse of IBM order */
static	char	ir3[] = "R%b,R%a,R%d";
static	char	ir3r[] = "R%a,R%b,R%d";
static	char	il3[] = "R%b,R%s,R%a";
static	char	il2u[] = "%I,R%a,R%d";
static	char	il3s[] = "$%k,R%s,R%a";
static	char	il2[] = "R%s,R%a";
static	char	icmp3[] = "R%a,R%b,%D";
static	char	cr3op[] = "%b,%a,%d";
static	char	ir2i[] = "%i,R%a,R%d";
static	char	fp2[] = "F%b,F%d";
static	char	fp3[] = "F%b,F%a,F%d";
static	char	fp3c[] = "F%c,F%a,F%d";
static	char	fp4[] = "F%a,F%c,F%b,F%d";
static	char	fpcmp[] = "F%a,F%b,%D";
static	char	ldop[] = "%l,R%d";
static	char	stop[] = "R%d,%l";
static	char	fldop[] = "%l,F%d";
static	char	fstop[] = "F%d,%l";
static	char	rlim[] = "R%b,R%s,$%z,R%a";
static	char	rlimi[] = "$%k,R%s,$%z,R%a";

#define	OEM	IBF(~0,22,30)
#define	FP4	IBF(~0,26,30)
#define ALL	((ushort)~0)
/*
notes:
	10-26: crfD = rD>>2; rD&3 mbz
		also, L bit (bit 10) mbz or selects 64-bit operands
*/

static Opcode opcodes[] = {
	{31,	360,	OEM,	"ABS%V%C",	0,	ir2},	/* POWER */

	{31,	266,	OEM,	"ADD%V%C",	add,	ir3},
	{31,	 10,	OEM,	"ADDC%V%C",	add,	ir3},
	{31,	138,	OEM,	"ADDE%V%C",	add,	ir3},
	{14,	0,	0,	"ADD",		addi,	ir2i},
	{12,	0,	0,	"ADDC",		addi,	ir2i},
	{13,	0,	0,	"ADDCCC",	addi,	ir2i},
	{15,	0,	0,	"ADD",		addis,	0},
	{31,	234,	OEM,	"ADDME%V%C",	gencc,	ir2},
	{31,	202,	OEM,	"ADDZE%V%C",	gencc,	ir2},

	{31,	28,	ALL,	"AND%C",	and,	il3},
	{31,	60,	ALL,	"ANDN%C",	and,	il3},
	{28,	0,	0,	"ANDCC",		andi,	il2u},
	{29,	0,	0,	"ANDCC",		shifted, 0},

	{18,	0,	0,	"B%L",		gencc,	"%j"},
	{16,	0,	0,	"BC%L",		branch,	"%d,%a,%J"},
	{19,	528,	ALL,	"BC%L",		branch,	"%d,%a,(CTR)"},
	{19,	16,	ALL,	"BC%L",		branch,	"%d,%a,(LR)"},

	{31,	531,	ALL,	"CLCS",		gen,	ir2},	/* POWER */

	{31,	0,	ALL,	"CMP",		0,	icmp3},
	{11,	0,	0,	"CMP",		0,	"R%a,%i,%D"},
	{31,	32,	ALL,	"CMPU",		0,	icmp3},
	{10,	0,	0,	"CMPU",		0,	"R%a,%I,%D"},

	{31,	26,	ALL,	"CNTLZ%C",	gencc,	ir2},

	{19,	257,	ALL,	"CRAND",	gen,	cr3op},
	{19,	129,	ALL,	"CRANDN",	gen,	cr3op},
	{19,	289,	ALL,	"CREQV",	gen,	cr3op},
	{19,	225,	ALL,	"CRNAND",	gen,	cr3op},
	{19,	33,	ALL,	"CRNOR",	gen,	cr3op},
	{19,	449,	ALL,	"CROR",		gen,	cr3op},
	{19,	417,	ALL,	"CRORN",	gen,	cr3op},
	{19,	193,	ALL,	"CRXOR",	gen,	cr3op},

	{31,	86,	ALL,	"DCBF",		dcb,	0},
	{31,	470,	ALL,	"DCBI",		dcb,	0},
	{31,	54,	ALL,	"DCBST",	dcb,	0},
	{31,	278,	ALL,	"DCBT",		dcb,	0},
	{31,	246,	ALL,	"DCBTST",	dcb,	0},
	{31,	1014,	ALL,	"DCBZ",		dcb,	0},

	{31,	331,	OEM,	"DIV%V%C",	div,	ir3},	/* POWER */
	{31,	363,	OEM,	"DIVS%V%C",	div,	ir3},	/* POWER */
	{31,	491,	OEM,	"DIVW%V%C",	div,	ir3},
	{31,	459,	OEM,	"DIVWU%V%C",	div,	ir3},

	{31,	264,	OEM,	"DOZ%V%C",	gencc,	ir3r},	/* POWER */
	{9,	0,	0,	"DOZ",		gen,	ir2i},	/* POWER */

	{31,	310,	ALL,	"ECIWX",	ldx,	0},
	{31,	438,	ALL,	"ECOWX",	stx,	0},
	{31,	854,	ALL,	"EIEIO",	gen,	0},

	{31,	284,	ALL,	"EQV%C",	gencc,	il3},

	{31,	954,	ALL,	"EXTSB%C",	gencc,	il2},
	{31,	922,	ALL,	"EXTSH%C",	gencc,	il2},

	{63,	264,	ALL,	"FABS%C",	gencc,	fp2},
	{63,	21,	ALL,	"FADD%C",	gencc,	fp3},
	{59,	21,	ALL,	"FADDS%C",	gencc,	fp3},
	{63,	32,	ALL,	"FCMPO",	gen,	fpcmp},
	{63,	0,	ALL,	"FCMPU",	gen,	fpcmp},
	{63,	14,	ALL,	"FCTIW%C",	gencc,	fp2},
	{63,	15,	ALL,	"FCTIWZ%C",	gencc,	fp2},
	{63,	18,	ALL,	"FDIV%C",	gencc,	fp3},
	{59,	18,	ALL,	"FDIVS%C",	gencc,	fp3},
	{63,	29,	FP4,	"FMADD%C",	gencc,	fp4},
	{59,	29,	FP4,	"FMADDS%C",	gencc,	fp4},
	{63,	72,	ALL,	"FMOVD%C",	gencc,	fp2},
	{63,	28,	FP4,	"FMSUB%C",	gencc,	fp4},
	{59,	28,	FP4,	"FMSUBS%C",	gencc,	fp4},
	{63,	25,	FP4,	"FMUL%C",	gencc,	fp3c},
	{59,	25,	FP4,	"FMULS%C",	gencc,	fp3c},
	{63,	136,	ALL,	"FNABS%C",	gencc,	fp2},
	{63,	40,	ALL,	"FNEG%C",	gencc,	fp2},
	{63,	31,	FP4,	"FNMADD%C",	gencc,	fp4},
	{59,	31,	FP4,	"FNMADDS%C",	gencc,	fp4},
	{63,	30,	FP4,	"FNMSUB%C",	gencc,	fp4},
	{59,	30,	FP4,	"FNMSUBS%C",	gencc,	fp4},
	{63,	12,	ALL,	"FRSP%C",	gencc,	fp2},
	{63,	20,	FP4,	"FSUB%C",	gencc,	fp3},
	{59,	20,	FP4,	"FSUBS%C",	gencc,	fp3},

	{31,	982,	ALL,	"ICBI",		dcb,	0},
	{19,	150,	ALL,	"ISYNC",	gen,	0},

	{34,	0,	0,	"MOVBZ",	load,	ldop},
	{35,	0,	0,	"MOVBZU",	load,	ldop},
	{31,	119,	ALL,	"MOVBZU",	ldx,	0},
	{31,	87,	ALL,	"MOVBZ",	ldx,	0},
	{50,	0,	0,	"FMOVD",	fload,	fldop},
	{51,	0,	0,	"FMOVDU",	fload,	fldop},
	{31,	631,	ALL,	"FMOVDU",	fldx,	0},
	{31,	599,	ALL,	"FMOVD",	fldx,	0},
	{48,	0,	0,	"FMOVS",	load,	fldop},
	{49,	0,	0,	"FMOVSU",	load,	fldop},
	{31,	567,	ALL,	"FMOVSU",	fldx,	0},
	{31,	535,	ALL,	"FMOVS",	fldx,	0},
	{42,	0,	0,	"MOVH",		load,	ldop},
	{43,	0,	0,	"MOVHU",	load,	ldop},
	{31,	375,	ALL,	"MOVHU",	ldx,	0},
	{31,	343,	ALL,	"MOVH",		ldx,	0},
	{31,	790,	ALL,	"MOVHBR",	ldx,	0},
	{40,	0,	0,	"MOVHZ",	load,	ldop},
	{41,	0,	0,	"MOVHZU",	load,	ldop},
	{31,	311,	ALL,	"MOVHZU",	ldx,	0},
	{31,	279,	ALL,	"MOVHZ",	ldx,	0},
	{46,	0,	0,	"MOVMW",		load,	ldop},
	{31,	277,	ALL,	"LSCBX%C",	ldx,	0},	/* POWER */
	{31,	597,	ALL,	"LSW",		gen,	"(R%a),$%n,R%d"},
	{31,	533,	ALL,	"LSW",		ldx,	0},
	{31,	20,	ALL,	"LWAR",		ldx,	0},
	{31,	534,	ALL,	"MOVWBR",		ldx,	0},
	{32,	0,	0,	"MOVW",		load,	ldop},
	{33,	0,	0,	"MOVWU",	load,	ldop},
	{31,	55,	ALL,	"MOVWU",	ldx,	0},
	{31,	23,	ALL,	"MOVW",		ldx,	0},

	{31,	29,	ALL,	"MASKG%C",	gencc,	"R%s:R%b,R%d"},	/* POWER */
	{31,	541,	ALL,	"MASKIR%C",	gencc,	"R%s,R%b,R%a"},	/* POWER */

	{19,	0,	ALL,	"MOVFL",	gen,	"%S,%D"},
	{63,	64,	ALL,	"MOVCRFS",	gen,	"%S,%D"},
	{31,	512,	ALL,	"MOVW",	gen,	"XER,%D"},
	{31,	19,	ALL,	"MOVW",	gen,	"CR,R%d"},

	{63,	583,	ALL,	"MOVW%C",	gen,	"FPSCR, F%d"},	/* mffs */
	{31,	83,	ALL,	"MOVW",		gen,	"MSR,R%d"},
	{31,	339,	ALL,	"MOVW",		gen,	"%P,R%d"},
	{31,	595,	ALL,	"MOVW",		gen,	"SEG(%a),R%d"},
	{31,	659,	ALL,	"MOVW",		gen,	"SEG(R%b),R%d"},
	{31,	144,	ALL,	"MOVFL",	gen,	"R%s,%m,CR"},
	{63,	70,	ALL,	"MTFSB0%C",	gencc,	"%D"},
	{63,	38,	ALL,	"MTFSB1%C",	gencc,	"%D"},
	{63,	711,	ALL,	"MOVFL%C",	gencc,	"F%b,%M,FPSCR"},	/* mtfsf */
	{63,	134,	ALL,	"MOVFL%C",	gencc,	"%K,%D"},
	{31,	146,	ALL,	"MOVW",		gen,	"R%s,MSR"},
	{31,	467,	ALL,	"MOVW",		gen,	"R%s,%P"},
	{31,	210,	ALL,	"MOVW",		gen,	"R%s,SEG(%a)"},
	{31,	242,	ALL,	"MOVW",		gen,	"R%s,SEG(R%b)"},

	{31,	107,	OEM,	"MUL%V%C",	gencc,	ir3},	/* POWER */
	{31,	75,	ALL,	"MULHW%C",	gencc,	ir3},	/* POWER */
	{31,	11,	ALL,	"MULHWU%C",	gencc,	ir3},	/* POWER */

	{31,	235,	OEM,	"MULLW%V%C",	gencc,	ir3},
	{7,	0,	0,	"MULLW",	div,	"%i,R%a,R%d"},

	{31,	488,	OEM,	"NABS%V%C",	neg,	ir2},	/* POWER */

	{31,	476,	ALL,	"NAND%C",	gencc,	il3},
	{31,	104,	OEM,	"NEG%V%C",	neg,	ir2},
	{31,	124,	ALL,	"NOR%C",	gencc,	il3},
	{31,	444,	ALL,	"OR%C",	or,	il3},
	{31,	412,	ALL,	"ORN%C",	or,	il3},
	{24,	0,	0,	"OR",		and,	"%I,R%d,R%a"},
	{25,	0,	0,	"OR",		shifted, 0},

	{19,	50,	ALL,	"RFI",		gen,	0},

	{22,	0,	0,	"RLMI%C",	gencc,	rlim},	/* POWER */
	{20,	0,	0,	"RLWMI%C",	gencc,	rlimi},
	{21,	0,	0,	"RLWNM%C",	gencc,	rlimi},
	{23,	0,	0,	"RLWNM%C",	gencc,	rlim},

	{31,	537,	ALL,	"RRIB%C",	gencc,	il3},	/* POWER */

	{17,	1,	ALL,	"SYSCALL",	gen,	0},

	{31,	153,	ALL,	"SLE%C",	shift,	il3},	/* POWER */
	{31,	217,	ALL,	"SLEQ%C",	shift,	il3},	/* POWER */
	{31,	184,	ALL,	"SLQ%C",	shifti,	il3s},	/* POWER */
	{31,	248,	ALL,	"SLLQ%C",	shifti,	il3s},	/* POWER */
	{31,	216,	ALL,	"SLLQ%C",	shift,	il3},	/* POWER */
	{31,	152,	ALL,	"SLQ%C",	shift,	il3},	/* POWER */

	{31,	24,	ALL,	"SLW%C",	shift,	il3},

	{31,	920,	ALL,	"SRAQ%C",	shift,	il3},	/* POWER */
	{31,	952,	ALL,	"SRAQ%C",	shifti,	il3s},	/* POWER */

	{31,	792,	ALL,	"SRAW%C",	shift,	il3},
	{31,	824,	ALL,	"SRAW%C",	shifti,	il3s},

	{31,	665,	ALL,	"SRE%C",	shift,	il3},	/* POWER */
	{31,	921,	ALL,	"SREA%C",	shift,	il3},	/* POWER */
	{31,	729,	ALL,	"SREQ%C",	shift,	il3},	/* POWER */
	{31,	696,	ALL,	"SRQ%C",	shifti,	il3s},	/* POWER */
	{31,	760,	ALL,	"SRLQ%C",	shifti,	il3s},	/* POWER */
	{31,	728,	ALL,	"SRLQ%C",	shift,	il3},	/* POWER */
	{31,	664,	ALL,	"SRQ%C",	shift,	il3},	/* POWER */

	{31,	536,	ALL,	"SRW%C",	shift,	il3},

	{38,	0,	0,	"MOVB",		store,	stop},
	{39,	0,	0,	"MOVBU",	store,	stop},
	{31,	247,	ALL,	"MOVBU",	stx,	0},
	{31,	215,	ALL,	"MOVB",		stx,	0},
	{54,	0,	0,	"FMOVD",	fstore,	fstop},
	{55,	0,	0,	"FMOVDU",	fstore,	fstop},
	{31,	759,	ALL,	"FMOVDU",	fstx,	0},
	{31,	727,	ALL,	"FMOVD",	fstx,	0},
	{52,	0,	0,	"FMOVS",	fstore,	fstop},
	{53,	0,	0,	"FMOVSU",	fstore,	fstop},
	{31,	695,	ALL,	"FMOVSU",	fstx,	0},
	{31,	663,	ALL,	"FMOVS",	fstx,	0},
	{44,	0,	0,	"MOVH",		store,	stop},
	{31,	918,	ALL,	"MOVHBR",	stx,	0},
	{45,	0,	0,	"MOVHU",	store,	stop},
	{31,	439,	ALL,	"MOVHU",	stx,	0},
	{31,	407,	ALL,	"MOVH",		stx,	0},
	{47,	0,	0,	"MOVMW",		store,	stop},
	{31,	725,	ALL,	"STSW",		gen,	"R%d,$%n,(R%a)"},
	{31,	661,	ALL,	"STSW",		stx,	0},
	{36,	0,	0,	"MOVW",		store,	stop},
	{31,	662,	ALL,	"MOVWBR",	stx,	0},
	{31,	150,	ALL,	"STWCCC",		stx,	0},
	{37,	0,	0,	"MOVWU",	store,	stop},
	{31,	183,	ALL,	"MOVWU",	stx,	0},
	{31,	151,	ALL,	"MOVW",		stx,	0},

	{31,	40,	OEM,	"SUB%V%C",	sub,	ir3},
	{31,	8,	OEM,	"SUBC%V%C",	sub,	ir3},
	{31,	136,	OEM,	"SUBE%V%C",	sub,	ir3},
	{8,	0,	0,	"SUBC",		gen,	"R%a,%i,R%d"},
	{31,	232,	OEM,	"SUBME%V%C",	sub,	ir2},
	{31,	200,	OEM,	"SUBZE%V%C",	sub,	ir2},

	{31,	598,	ALL,	"SYNC",		gen,	0},
	{31,	370,	ALL,	"TLBIA",	gen,	0},
	{31,	306,	ALL,	"TLBIE",	gen,	"R%b"},
	{31,	1010,	ALL,	"TLBLI",	gen,	"R%b"},
	{31,	978,	ALL,	"TLBLD",	gen,	"R%b"},
	{31,	4,	ALL,	"TW",		gen,	"%d,R%a,R%b"},
	{3,	0,	0,	"TW",		gen,	"%d,R%a,%i"},

	{31,	316,	ALL,	"XOR",		and,	il3},
	{26,	0,	0,	"XOR",		and,	il2u},
	{27,	0,	0,	"XOR",		shifted, 0},

	{0},
};

typedef struct Spr Spr;
struct Spr {
	int	n;
	char	*name;
};

static	Spr	sprname[] = {
	{0, "MQ"},
	{1, "XER"},
	{268, "TBL"},
	{269, "TBU"},
	{8, "LR"},
	{9, "CTR"},
	{528, "IBAT0U"},
	{529, "IBAT0L"},
	{530, "IBAT1U"},
	{531, "IBAT1L"},
	{532, "IBAT2U"},
	{533, "IBAT2L"},
	{534, "IBAT3U"},
	{535, "IBAT3L"},
	{536, "DBAT0U"},
	{537, "DBAT0L"},
	{538, "DBAT1U"},
	{539, "DBAT1L"},
	{540, "DBAT2U"},
	{541, "DBAT2L"},
	{542, "DBAT3U"},
	{543, "DBAT3L"},
	{25, "SDR1"},
	{19, "DAR"},
	{272, "SPRG0"},
	{273, "SPRG1"},
	{274, "SPRG2"},
	{275, "SPRG3"},
	{18, "DSISR"},
	{26, "SRR0"},
	{27, "SRR1"},
	{284, "TBLW"},
	{285, "TBUW"},	
	{22, "DEC"},
	{282, "EAR"},
	{1008, "HID0"},
	{1009, "HID1"},
	{976, "DMISS"},
	{977, "DCMP"},
	{978, "HASH1"},
	{979, "HASH2"},
	{980, "IMISS"},
	{981, "ICMP"},
	{982, "RPA"},
	{1010, "IABR"},
	{0,0},
};

static void
format(char *mnemonic, Instr *i, char *f)
{
	int n, s;
	ulong mask;

	if (mnemonic)
		format(0, i, mnemonic);
	if (f == 0)
		return;
	if (mnemonic)
		bprint(i, "\t");
	for ( ; *f; f++) {
		if (*f != '%') {
			bprint(i, "%c", *f);
			continue;
		}
		switch (*++f) {
		case 'V':
			if(i->oe)
				bprint(i, "V");
			break;

		case 'C':
			if(i->rc)
				bprint(i, "CC");
			break;

		case 'a':
			bprint(i, "%d", i->ra);
			break;

		case 'b':
			bprint(i, "%d", i->rb);
			break;

		case 'c':
			bprint(i, "%d", i->frc);
			break;

		case 'd':
		case 's':
			bprint(i, "%d", i->rd);
			break;

		case 'S':
			if(i->ra & 3)
				bprint(i, "CR(INVAL:%d)", i->ra);
			else if(i->op == 63)
				bprint(i, "FPSCR(%d)", i->crfs);
			else
				bprint(i, "CR(%d)", i->crfs);
			break;

		case 'D':
			if(i->rd & 3)
				bprint(i, "CR(INVAL:%d)", i->rd);
			else if(i->op == 63)
				bprint(i, "FPSCR(%d)", i->crfd);
			else
				bprint(i, "CR(%d)", i->crfd);
			break;

		case 'l':
			if(i->simm < 0)
				bprint(i, "-%lx(R%d)", -i->simm, i->ra);
			else
				bprint(i, "%lx(R%d)", i->simm, i->ra);
			break;

		case 'i':
			bprint(i, "$%ld", i->simm);
			break;

		case 'I':
			bprint(i, "$%lx", i->uimm);
			break;

		case 'w':
			bprint(i, "[%lux]", i->w0);
			break;

		case 'P':
			n = ((i->spr&0x1f)<<5)|((i->spr>>5)&0x1f);
			for(s=0; sprname[s].name; s++)
				if(sprname[s].n == n)
					break;
			if(sprname[s].name) {
				if(s < 10)
					bprint(i, sprname[s].name);
				else
					bprint(i, "SPR(%s)", sprname[s].name);
			} else
				bprint(i, "SPR(%d)", n);
			break;

		case 'n':
			bprint(i, "%d", i->nb==0? 32: i->nb);	/* eg, pg 10-103 */
			break;

		case 'm':
			bprint(i, "%lx", i->crm);
			break;

		case 'M':
			bprint(i, "%lx", i->fm);
			break;

		case 'z':
			if(i->mb <= i->me)
				mask = ((ulong)~0L>>i->mb) & (~0L<<(31-i->me));
			else
				mask = ~(((ulong)~0L>>(i->me+1)) & (~0L<<(31-(i->mb-1))));
			bprint(i, "%lux", mask);
			break;

		case 'k':
			bprint(i, "%d", i->sh);
			break;

		case 'K':
			bprint(i, "$%x", i->imm);
			break;

		case 'L':
			if(i->lk)
				bprint(i, "L");
			break;

		case 'j':
			if(i->aa)
				pglobal(i, i->li, 1, "(SB)");
			else
				pglobal(i, i->addr+i->li, 1, "");
			break;

		case 'J':
			if(i->aa)
				pglobal(i, i->bd, 1, "(SB)");
			else
				pglobal(i, i->addr+i->bd, 1, "");
			break;

		case '\0':
			bprint(i, "%%");
			return;

		default:
			bprint(i, "%%%c", *f);
			break;
		}
	}
}

static int
printins(Map *map, ulong pc, char *buf, int n)
{
	Instr i;
	Opcode *o;

	mymap = map;
	memset(&i, 0, sizeof(i));
	i.curr = buf;
	i.end = buf+n-1;
	if(mkinstr(pc, &i) < 0)
		return -1;
	for(o = opcodes; o->mnemonic != 0; o++)
		if(i.op == o->op && (i.xo & o->xomask) == o->xo) {
			if (o->f)
				(*o->f)(o, &i);
			else
				format(o->mnemonic, &i, o->ken);
			return i.size*4;
		}
	bprint(&i, "unknown %lux", i.w0);
	return i.size*4;
}

static int
powerdas(Map *map, ulong pc, char modifier, char *buf, int n)
{
	USED(modifier);
	return printins(map, pc, buf, n);
}

static int
powerhexinst(Map *map, ulong pc, char *buf, int n)
{
	Instr instr;

	mymap = map;
	memset(&instr, 0, sizeof(instr));
	instr.curr = buf;
	instr.end = buf+n-1;
	if (mkinstr(pc, &instr) < 0)
		return -1;
	if (instr.end-instr.curr > 8)
		instr.curr = _hexify(instr.curr, instr.w0, 7);
	if (instr.end-instr.curr > 9 && instr.size == 2) {
		*instr.curr++ = ' ';
		instr.curr = _hexify(instr.curr, instr.w1, 7);
	}
	*instr.curr = 0;
	return instr.size*4;
}

static int
powerinstlen(Map *map, ulong pc)
{
	Instr i;

	mymap = map;
	if (mkinstr(pc, &i) < 0)
		return -1;
	return i.size*4;
}

static int
powerfoll(Map *map, Regs *regs, ulong pc, ulong *foll)
{
	char *reg;
	Instr i;

	mymap = map;
	if (mkinstr(pc, &i) < 0)
		return -1;
	foll[0] = pc+4;
	foll[1] = pc+4;
	switch(i.op) {
	default:
		return 1;

	case 18:	/* branch */
		foll[0] = i.li;
		if(!i.aa)
			foll[0] += pc;
		break;
			
	case 16:	/* conditional branch */
		foll[0] = i.bd;
		if(!i.aa)
			foll[0] += pc;
		break;

	case 19:	/* conditional branch to register */
		if(i.xo == 528)
			reg = "CTR";
		else if(i.xo == 16)
			reg = "LR";
		else
			return 1;	/* not a branch */
		if(rget(regs, reg, &foll[0]) < 0)
			return -1;
		break;
	}
	if(i.lk)
		return 2;
	return 1;
}

#define	REGOFF(x)	(ulong) (&((struct Ureg *) 0)->x)

#define SP		REGOFF(r1)
#define PC		REGOFF(pc)
#define	R3		REGOFF(r3)	/* return reg */
#define	LR		REGOFF(lr)
#define R31		REGOFF(r31)
#define FP_REG(x)	(R31+4+8*(x))

#define	REGSIZE		sizeof(struct Ureg)
#define	FPREGSIZE	(8*33)	

Regdesc powerreglist[] =
{
	{"CAUSE",	REGOFF(cause),	RINT|RRDONLY,	'X'},
	{"SRR1",	REGOFF(srr1),	RINT|RRDONLY,	'X'},
	{"PC",		REGOFF(pc),	RINT,		'X'},
	{"LR",		REGOFF(lr),	RINT,		'X'},
	{"CR",		REGOFF(cr),	RINT,		'X'},
	{"XER",		REGOFF(xer),	RINT,		'X'},
	{"CTR",		REGOFF(ctr),	RINT,		'X'},
	{"PC",		PC,		RINT,		'X'},
	{"SP",		SP,		RINT,		'X'},
	{"R0",		REGOFF(r0),	RINT,		'X'},
	/* R1 is SP */
	{"R2",		REGOFF(r2),	RINT,		'X'},
	{"R3",		REGOFF(r3),	RINT,		'X'},
	{"R4",		REGOFF(r4),	RINT,		'X'},
	{"R5",		REGOFF(r5),	RINT,		'X'},
	{"R6",		REGOFF(r6),	RINT,		'X'},
	{"R7",		REGOFF(r7),	RINT,		'X'},
	{"R8",		REGOFF(r8),	RINT,		'X'},
	{"R9",		REGOFF(r9),	RINT,		'X'},
	{"R10",		REGOFF(r10),	RINT,		'X'},
	{"R11",		REGOFF(r11),	RINT,		'X'},
	{"R12",		REGOFF(r12),	RINT,		'X'},
	{"R13",		REGOFF(r13),	RINT,		'X'},
	{"R14",		REGOFF(r14),	RINT,		'X'},
	{"R15",		REGOFF(r15),	RINT,		'X'},
	{"R16",		REGOFF(r16),	RINT,		'X'},
	{"R17",		REGOFF(r17),	RINT,		'X'},
	{"R18",		REGOFF(r18),	RINT,		'X'},
	{"R19",		REGOFF(r19),	RINT,		'X'},
	{"R20",		REGOFF(r20),	RINT,		'X'},
	{"R21",		REGOFF(r21),	RINT,		'X'},
	{"R22",		REGOFF(r22),	RINT,		'X'},
	{"R23",		REGOFF(r23),	RINT,		'X'},
	{"R24",		REGOFF(r24),	RINT,		'X'},
	{"R25",		REGOFF(r25),	RINT,		'X'},
	{"R26",		REGOFF(r26),	RINT,		'X'},
	{"R27",		REGOFF(r27),	RINT,		'X'},
	{"R28",		REGOFF(r28),	RINT,		'X'},
	{"R29",		REGOFF(r29),	RINT,		'X'},
	{"R30",		REGOFF(r30),	RINT,		'X'},
	{"R31",		REGOFF(r31),	RINT,		'X'},
	{"VRSAVE",	REGOFF(vrsave),	RINT,	'X'},
	{"F0",		FP_REG(0),	RFLT,		'F'},
	{"F1",		FP_REG(1),	RFLT,		'F'},
	{"F2",		FP_REG(2),	RFLT,		'F'},
	{"F3",		FP_REG(3),	RFLT,		'F'},
	{"F4",		FP_REG(4),	RFLT,		'F'},
	{"F5",		FP_REG(5),	RFLT,		'F'},
	{"F6",		FP_REG(6),	RFLT,		'F'},
	{"F7",		FP_REG(7),	RFLT,		'F'},
	{"F8",		FP_REG(8),	RFLT,		'F'},
	{"F9",		FP_REG(9),	RFLT,		'F'},
	{"F10",		FP_REG(10),	RFLT,		'F'},
	{"F11",		FP_REG(11),	RFLT,		'F'},
	{"F12",		FP_REG(12),	RFLT,		'F'},
	{"F13",		FP_REG(13),	RFLT,		'F'},
	{"F14",		FP_REG(14),	RFLT,		'F'},
	{"F15",		FP_REG(15),	RFLT,		'F'},
	{"F16",		FP_REG(16),	RFLT,		'F'},
	{"F17",		FP_REG(17),	RFLT,		'F'},
	{"F18",		FP_REG(18),	RFLT,		'F'},
	{"F19",		FP_REG(19),	RFLT,		'F'},
	{"F20",		FP_REG(20),	RFLT,		'F'},
	{"F21",		FP_REG(21),	RFLT,		'F'},
	{"F22",		FP_REG(22),	RFLT,		'F'},
	{"F23",		FP_REG(23),	RFLT,		'F'},
	{"F24",		FP_REG(24),	RFLT,		'F'},
	{"F25",		FP_REG(25),	RFLT,		'F'},
	{"F26",		FP_REG(26),	RFLT,		'F'},
	{"F27",		FP_REG(27),	RFLT,		'F'},
	{"F28",		FP_REG(28),	RFLT,		'F'},
	{"F29",		FP_REG(29),	RFLT,		'F'},
	{"F30",		FP_REG(30),	RFLT,		'F'},
	{"F31",		FP_REG(31),	RFLT,		'F'},
	{"FPSCR",	FP_REG(32)+4,	RFLT,		'X'},
	{  0 }
};

static char *powerwindregs[] = 
{
	"PC",
	"SP",
	"LR",
	0,
};

static int
powerunwind(Map *map, Regs *regs, ulong *next, Symbol *sym)
{
	/*
	 * This is tremendously hard.  The best we're going to
	 * do without better debugger support is trace through
	 * the stack frame links and pull the link registers out of 8(R1).
	 * Anything more requires knowing which registers got saved,
	 * and the compiler appears not to record that.  Gdb appears
	 * to disassemble the function prologues in order to figure
	 * this out.
	 */
	// evaluate lr
	// if in this function, no good - go to saved one.
	// set next[sp] to *cur[sp]
	// set next[pc] to lr
	// set next[lr] to lr
	// 
	werrstr("powerunwind not implemented");
	return -1;
}

	/* the machine description */
Mach machpower =
{
	"power",
	MPOWER,		/* machine type */
	powerreglist,	/* register set */
	REGSIZE,	/* number of bytes in register set */
	FPREGSIZE,	/* number of bytes in FP register set */
	"PC",		/* name of PC */
	"SP",		/* name of SP */
	0,		/* name of FP */
	"LR",		/* name of link register */
	"setSB",	/* static base register name */
	0,		/* value */
	0x1000,		/* page size */
	0x80000000,	/* kernel base */
	0,		/* kernel text mask */
	4,		/* quantization of pc */
	4,		/* szaddr */
	4,		/* szreg */
	4,		/* szfloat */
	8,		/* szdouble */

	powerwindregs,	/* locations unwound in stack trace */
	3,

	{0x02, 0x8F, 0xFF, 0xFF},	/* break point */ /* BUG */
	4,

	powerfoll,		/* following addresses */
	powerexcep,		/* print exception */
	powerunwind,		/* stack unwind */

	beswap2,			/* convert short to local byte order */
	beswap4,			/* convert long to local byte order */
	beswap8,			/* convert vlong to local byte order */
	beieeeftoa32,		/* single precision float pointer */
	beieeeftoa64,		/* double precision float pointer */
	beieeeftoa80,		/* long double precision floating point */

	powerdas,		/* dissembler */
	powerdas,		/* plan9-format disassembler */
	0,			/* commercial disassembler */
	powerhexinst,		/* print instruction */
	powerinstlen,		/* instruction size calculation */
};