xref: /inferno-os/utils/libmach/vdb.c (revision d67b7dad77bb8aa973dad1f7c3ab0c309b114278)
174a4d8c2SCharles.Forsyth #include <lib9.h>
274a4d8c2SCharles.Forsyth #include <bio.h>
374a4d8c2SCharles.Forsyth #include "mach.h"
474a4d8c2SCharles.Forsyth /*
574a4d8c2SCharles.Forsyth  * Mips-specific debugger interface
674a4d8c2SCharles.Forsyth  */
774a4d8c2SCharles.Forsyth 
8*d67b7dadSforsyth static	char	*mipsexcep(Map*, Rgetter);
9*d67b7dadSforsyth static	int	mipsfoll(Map*, uvlong, Rgetter, uvlong*);
10*d67b7dadSforsyth static	int	mipsinst(Map*, uvlong, char, char*, int);
11*d67b7dadSforsyth static	int	mipsdas(Map*, uvlong, char*, int);
12*d67b7dadSforsyth static	int	mipsinstlen(Map*, uvlong);
13*d67b7dadSforsyth 
1474a4d8c2SCharles.Forsyth /*
1574a4d8c2SCharles.Forsyth  *	Debugger interface
1674a4d8c2SCharles.Forsyth  */
1774a4d8c2SCharles.Forsyth Machdata mipsmach =
1874a4d8c2SCharles.Forsyth {
1974a4d8c2SCharles.Forsyth 	{0, 0, 0, 0xD},		/* break point */
2074a4d8c2SCharles.Forsyth 	4,			/* break point size */
2174a4d8c2SCharles.Forsyth 
2274a4d8c2SCharles.Forsyth 	beswab,			/* short to local byte order */
2374a4d8c2SCharles.Forsyth 	beswal,			/* long to local byte order */
2474a4d8c2SCharles.Forsyth 	beswav,			/* vlong to local byte order */
2574a4d8c2SCharles.Forsyth 	risctrace,		/* C traceback */
2674a4d8c2SCharles.Forsyth 	riscframe,		/* Frame finder */
2774a4d8c2SCharles.Forsyth 	mipsexcep,		/* print exception */
2874a4d8c2SCharles.Forsyth 	0,			/* breakpoint fixup */
2974a4d8c2SCharles.Forsyth 	beieeesftos,		/* single precision float printer */
3074a4d8c2SCharles.Forsyth 	beieeedftos,		/* double precisioin float printer */
3174a4d8c2SCharles.Forsyth 	mipsfoll,		/* following addresses */
3274a4d8c2SCharles.Forsyth 	mipsinst,		/* print instruction */
3374a4d8c2SCharles.Forsyth 	mipsdas,		/* dissembler */
3474a4d8c2SCharles.Forsyth 	mipsinstlen,		/* instruction size */
3574a4d8c2SCharles.Forsyth };
3674a4d8c2SCharles.Forsyth 
37*d67b7dadSforsyth Machdata mipsmachle =
38*d67b7dadSforsyth {
39*d67b7dadSforsyth 	{0, 0, 0, 0xD},		/* break point */
40*d67b7dadSforsyth 	4,			/* break point size */
41*d67b7dadSforsyth 
42*d67b7dadSforsyth 	leswab,			/* short to local byte order */
43*d67b7dadSforsyth 	leswal,			/* long to local byte order */
44*d67b7dadSforsyth 	leswav,			/* vlong to local byte order */
45*d67b7dadSforsyth 	risctrace,		/* C traceback */
46*d67b7dadSforsyth 	riscframe,		/* Frame finder */
47*d67b7dadSforsyth 	mipsexcep,		/* print exception */
48*d67b7dadSforsyth 	0,			/* breakpoint fixup */
49*d67b7dadSforsyth 	leieeesftos,		/* single precision float printer */
50*d67b7dadSforsyth 	leieeedftos,		/* double precisioin float printer */
51*d67b7dadSforsyth 	mipsfoll,		/* following addresses */
52*d67b7dadSforsyth 	mipsinst,		/* print instruction */
53*d67b7dadSforsyth 	mipsdas,		/* dissembler */
54*d67b7dadSforsyth 	mipsinstlen,		/* instruction size */
55*d67b7dadSforsyth };
56*d67b7dadSforsyth 
57*d67b7dadSforsyth /*
58*d67b7dadSforsyth  *	mips r4k little-endian
59*d67b7dadSforsyth  */
60*d67b7dadSforsyth Machdata mipsmach2le =
61*d67b7dadSforsyth {
62*d67b7dadSforsyth 	{0, 0, 0, 0xD},		/* break point */
63*d67b7dadSforsyth 	4,			/* break point size */
64*d67b7dadSforsyth 
65*d67b7dadSforsyth 	leswab,			/* short to local byte order */
66*d67b7dadSforsyth 	leswal,			/* long to local byte order */
67*d67b7dadSforsyth 	leswav,			/* vlong to local byte order */
68*d67b7dadSforsyth 	risctrace,		/* C traceback */
69*d67b7dadSforsyth 	riscframe,		/* Frame finder */
70*d67b7dadSforsyth 	mipsexcep,		/* print exception */
71*d67b7dadSforsyth 	0,			/* breakpoint fixup */
72*d67b7dadSforsyth 	leieeesftos,		/* single precision float printer */
73*d67b7dadSforsyth 	leieeedftos,		/* double precisioin float printer */
74*d67b7dadSforsyth 	mipsfoll,		/* following addresses */
75*d67b7dadSforsyth 	mipsinst,		/* print instruction */
76*d67b7dadSforsyth 	mipsdas,		/* dissembler */
77*d67b7dadSforsyth 	mipsinstlen,		/* instruction size */
78*d67b7dadSforsyth };
79*d67b7dadSforsyth 
80*d67b7dadSforsyth /*
81*d67b7dadSforsyth  *	mips r4k big-endian
82*d67b7dadSforsyth  */
83*d67b7dadSforsyth Machdata mipsmach2be =
84*d67b7dadSforsyth {
85*d67b7dadSforsyth 	{0, 0, 0, 0xD},		/* break point */
86*d67b7dadSforsyth 	4,			/* break point size */
87*d67b7dadSforsyth 
88*d67b7dadSforsyth 	beswab,			/* short to local byte order */
89*d67b7dadSforsyth 	beswal,			/* long to local byte order */
90*d67b7dadSforsyth 	beswav,			/* vlong to local byte order */
91*d67b7dadSforsyth 	risctrace,		/* C traceback */
92*d67b7dadSforsyth 	riscframe,		/* Frame finder */
93*d67b7dadSforsyth 	mipsexcep,		/* print exception */
94*d67b7dadSforsyth 	0,			/* breakpoint fixup */
95*d67b7dadSforsyth 	beieeesftos,		/* single precision float printer */
96*d67b7dadSforsyth 	beieeedftos,		/* double precisioin float printer */
97*d67b7dadSforsyth 	mipsfoll,		/* following addresses */
98*d67b7dadSforsyth 	mipsinst,		/* print instruction */
99*d67b7dadSforsyth 	mipsdas,		/* dissembler */
100*d67b7dadSforsyth 	mipsinstlen,		/* instruction size */
101*d67b7dadSforsyth };
102*d67b7dadSforsyth 
103*d67b7dadSforsyth 
10474a4d8c2SCharles.Forsyth static char *excname[] =
10574a4d8c2SCharles.Forsyth {
10674a4d8c2SCharles.Forsyth 	"external interrupt",
10774a4d8c2SCharles.Forsyth 	"TLB modification",
10874a4d8c2SCharles.Forsyth 	"TLB miss (load or fetch)",
10974a4d8c2SCharles.Forsyth 	"TLB miss (store)",
11074a4d8c2SCharles.Forsyth 	"address error (load or fetch)",
11174a4d8c2SCharles.Forsyth 	"address error (store)",
11274a4d8c2SCharles.Forsyth 	"bus error (fetch)",
11374a4d8c2SCharles.Forsyth 	"bus error (data load or store)",
11474a4d8c2SCharles.Forsyth 	"system call",
11574a4d8c2SCharles.Forsyth 	"breakpoint",
11674a4d8c2SCharles.Forsyth 	"reserved instruction",
11774a4d8c2SCharles.Forsyth 	"coprocessor unusable",
11874a4d8c2SCharles.Forsyth 	"arithmetic overflow",
11974a4d8c2SCharles.Forsyth 	"undefined 13",
12074a4d8c2SCharles.Forsyth 	"undefined 14",
12174a4d8c2SCharles.Forsyth 	"system call",
12274a4d8c2SCharles.Forsyth 	/* the following is made up */
12374a4d8c2SCharles.Forsyth 	"floating point exception"		/* FPEXC */
12474a4d8c2SCharles.Forsyth };
12574a4d8c2SCharles.Forsyth 
126*d67b7dadSforsyth static char*
mipsexcep(Map * map,Rgetter rget)12774a4d8c2SCharles.Forsyth mipsexcep(Map *map, Rgetter rget)
12874a4d8c2SCharles.Forsyth {
12974a4d8c2SCharles.Forsyth 	int e;
13074a4d8c2SCharles.Forsyth 	long c;
13174a4d8c2SCharles.Forsyth 
13274a4d8c2SCharles.Forsyth 	c = (*rget)(map, "CAUSE");
13374a4d8c2SCharles.Forsyth 	if(c & 0x00002000)	/* INTR3 */
13474a4d8c2SCharles.Forsyth 		e = 16;		/* Floating point exception */
13574a4d8c2SCharles.Forsyth 	else
13674a4d8c2SCharles.Forsyth 		e = (c>>2)&0x0F;
13774a4d8c2SCharles.Forsyth 	return excname[e];
13874a4d8c2SCharles.Forsyth }
13974a4d8c2SCharles.Forsyth 
14074a4d8c2SCharles.Forsyth 	/* mips disassembler and related functions */
14174a4d8c2SCharles.Forsyth 
14274a4d8c2SCharles.Forsyth static	char FRAMENAME[] = ".frame";
14374a4d8c2SCharles.Forsyth 
14474a4d8c2SCharles.Forsyth typedef struct {
145*d67b7dadSforsyth 	uvlong addr;
14674a4d8c2SCharles.Forsyth 	uchar op;			/* bits 31-26 */
14774a4d8c2SCharles.Forsyth 	uchar rs;			/* bits 25-21 */
14874a4d8c2SCharles.Forsyth 	uchar rt;			/* bits 20-16 */
14974a4d8c2SCharles.Forsyth 	uchar rd;			/* bits 15-11 */
15074a4d8c2SCharles.Forsyth 	uchar sa;			/* bits 10-6 */
15174a4d8c2SCharles.Forsyth 	uchar function;			/* bits 5-0 */
15274a4d8c2SCharles.Forsyth 	long immediate;			/* bits 15-0 */
15374a4d8c2SCharles.Forsyth 	ulong cofun;			/* bits 24-0 */
15474a4d8c2SCharles.Forsyth 	ulong target;			/* bits 25-0 */
15574a4d8c2SCharles.Forsyth 	long w0;
15674a4d8c2SCharles.Forsyth 	long w1;
15774a4d8c2SCharles.Forsyth 	int size;			/* instruction size */
15874a4d8c2SCharles.Forsyth 	char *curr;			/* fill point in buffer */
15974a4d8c2SCharles.Forsyth 	char *end;			/* end of buffer */
16074a4d8c2SCharles.Forsyth 	char *err;			/* error message */
16174a4d8c2SCharles.Forsyth } Instr;
16274a4d8c2SCharles.Forsyth 
16374a4d8c2SCharles.Forsyth static Map *mymap;
16474a4d8c2SCharles.Forsyth 
16574a4d8c2SCharles.Forsyth static int
decode(uvlong pc,Instr * i)166*d67b7dadSforsyth decode(uvlong pc, Instr *i)
16774a4d8c2SCharles.Forsyth {
168*d67b7dadSforsyth 	ulong w;
16974a4d8c2SCharles.Forsyth 
17074a4d8c2SCharles.Forsyth 	if (get4(mymap, pc, &w) < 0) {
17174a4d8c2SCharles.Forsyth 		werrstr("can't read instruction: %r");
17274a4d8c2SCharles.Forsyth 		return -1;
17374a4d8c2SCharles.Forsyth 	}
174*d67b7dadSforsyth 
17574a4d8c2SCharles.Forsyth 	i->addr = pc;
17674a4d8c2SCharles.Forsyth 	i->size = 1;
17774a4d8c2SCharles.Forsyth 	i->op = (w >> 26) & 0x3F;
17874a4d8c2SCharles.Forsyth 	i->rs = (w >> 21) & 0x1F;
17974a4d8c2SCharles.Forsyth 	i->rt = (w >> 16) & 0x1F;
18074a4d8c2SCharles.Forsyth 	i->rd = (w >> 11) & 0x1F;
18174a4d8c2SCharles.Forsyth 	i->sa = (w >> 6) & 0x1F;
18274a4d8c2SCharles.Forsyth 	i->function = w & 0x3F;
18374a4d8c2SCharles.Forsyth 	i->immediate = w & 0x0000FFFF;
18474a4d8c2SCharles.Forsyth 	if (i->immediate & 0x8000)
18574a4d8c2SCharles.Forsyth 		i->immediate |= ~0x0000FFFF;
18674a4d8c2SCharles.Forsyth 	i->cofun = w & 0x01FFFFFF;
18774a4d8c2SCharles.Forsyth 	i->target = w & 0x03FFFFFF;
18874a4d8c2SCharles.Forsyth 	i->w0 = w;
18974a4d8c2SCharles.Forsyth 	return 1;
19074a4d8c2SCharles.Forsyth }
19174a4d8c2SCharles.Forsyth 
19274a4d8c2SCharles.Forsyth static int
mkinstr(uvlong pc,Instr * i)193*d67b7dadSforsyth mkinstr(uvlong pc, Instr *i)
19474a4d8c2SCharles.Forsyth {
19574a4d8c2SCharles.Forsyth 	Instr x;
19674a4d8c2SCharles.Forsyth 
19774a4d8c2SCharles.Forsyth 	if (decode(pc, i) < 0)
19874a4d8c2SCharles.Forsyth 		return -1;
19974a4d8c2SCharles.Forsyth 	/*
20074a4d8c2SCharles.Forsyth 	 * if it's a LUI followed by an ORI,
20174a4d8c2SCharles.Forsyth 	 * it's an immediate load of a large constant.
20274a4d8c2SCharles.Forsyth 	 * fix the LUI immediate in any case.
20374a4d8c2SCharles.Forsyth 	 */
20474a4d8c2SCharles.Forsyth 	if (i->op == 0x0F) {
20574a4d8c2SCharles.Forsyth 		if (decode(pc+4, &x) < 0)
20674a4d8c2SCharles.Forsyth 			return 0;
20774a4d8c2SCharles.Forsyth 		i->immediate <<= 16;
20874a4d8c2SCharles.Forsyth 		if (x.op == 0x0D && x.rs == x.rt && x.rt == i->rt) {
20974a4d8c2SCharles.Forsyth 			i->immediate |= (x.immediate & 0xFFFF);
21074a4d8c2SCharles.Forsyth 			i->w1 = x.w0;
21174a4d8c2SCharles.Forsyth 			i->size++;
21274a4d8c2SCharles.Forsyth 			return 1;
21374a4d8c2SCharles.Forsyth 		}
21474a4d8c2SCharles.Forsyth 	}
21574a4d8c2SCharles.Forsyth 	/*
21674a4d8c2SCharles.Forsyth 	 * if it's a LWC1 followed by another LWC1
21774a4d8c2SCharles.Forsyth 	 * into an adjacent register, it's a load of
21874a4d8c2SCharles.Forsyth 	 * a floating point double.
21974a4d8c2SCharles.Forsyth 	 */
22074a4d8c2SCharles.Forsyth 	else if (i->op == 0x31 && (i->rt & 0x01)) {
22174a4d8c2SCharles.Forsyth 		if (decode(pc+4, &x) < 0)
22274a4d8c2SCharles.Forsyth 			return 0;
22374a4d8c2SCharles.Forsyth 		if (x.op == 0x31 && x.rt == (i->rt - 1) && x.rs == i->rs) {
22474a4d8c2SCharles.Forsyth 			i->rt -= 1;
22574a4d8c2SCharles.Forsyth 			i->w1 = x.w0;
22674a4d8c2SCharles.Forsyth 			i->size++;
22774a4d8c2SCharles.Forsyth 			return 1;
22874a4d8c2SCharles.Forsyth 		}
22974a4d8c2SCharles.Forsyth 	}
23074a4d8c2SCharles.Forsyth 	/*
23174a4d8c2SCharles.Forsyth 	 * similarly for double stores
23274a4d8c2SCharles.Forsyth 	 */
23374a4d8c2SCharles.Forsyth 	else if (i->op == 0x39 && (i->rt & 0x01)) {
23474a4d8c2SCharles.Forsyth 		if (decode(pc+4, &x) < 0)
23574a4d8c2SCharles.Forsyth 			return 0;
23674a4d8c2SCharles.Forsyth 		if (x.op == 0x39 && x.rt == (i->rt - 1) && x.rs == i->rs) {
23774a4d8c2SCharles.Forsyth 			i->rt -= 1;
23874a4d8c2SCharles.Forsyth 			i->w1 = x.w0;
23974a4d8c2SCharles.Forsyth 			i->size++;
24074a4d8c2SCharles.Forsyth 		}
24174a4d8c2SCharles.Forsyth 	}
24274a4d8c2SCharles.Forsyth 	return 1;
24374a4d8c2SCharles.Forsyth }
24474a4d8c2SCharles.Forsyth 
245*d67b7dadSforsyth #pragma	varargck	argpos	bprint		2
246*d67b7dadSforsyth 
24774a4d8c2SCharles.Forsyth static void
bprint(Instr * i,char * fmt,...)24874a4d8c2SCharles.Forsyth bprint(Instr *i, char *fmt, ...)
24974a4d8c2SCharles.Forsyth {
25074a4d8c2SCharles.Forsyth 	va_list arg;
25174a4d8c2SCharles.Forsyth 
25274a4d8c2SCharles.Forsyth 	va_start(arg, fmt);
25374a4d8c2SCharles.Forsyth 	i->curr = vseprint(i->curr, i->end, fmt, arg);
25474a4d8c2SCharles.Forsyth 	va_end(arg);
25574a4d8c2SCharles.Forsyth }
25674a4d8c2SCharles.Forsyth 
25774a4d8c2SCharles.Forsyth typedef struct Opcode Opcode;
25874a4d8c2SCharles.Forsyth 
25974a4d8c2SCharles.Forsyth struct Opcode {
26074a4d8c2SCharles.Forsyth 	char *mnemonic;
26174a4d8c2SCharles.Forsyth 	void (*f)(Opcode *, Instr *);
26274a4d8c2SCharles.Forsyth 	char *ken;
26374a4d8c2SCharles.Forsyth };
26474a4d8c2SCharles.Forsyth 
26574a4d8c2SCharles.Forsyth static void format(char *, Instr *, char *);
26674a4d8c2SCharles.Forsyth 
26774a4d8c2SCharles.Forsyth static void
branch(Opcode * o,Instr * i)26874a4d8c2SCharles.Forsyth branch(Opcode *o, Instr *i)
26974a4d8c2SCharles.Forsyth {
27074a4d8c2SCharles.Forsyth 	if (i->rs == 0 && i->rt == 0)
27174a4d8c2SCharles.Forsyth 		format("JMP", i, "%b");
27274a4d8c2SCharles.Forsyth 	else if (i->rs == 0)
27374a4d8c2SCharles.Forsyth 		format(o->mnemonic, i, "R%t,%b");
27474a4d8c2SCharles.Forsyth 	else if (i->rt < 2)
27574a4d8c2SCharles.Forsyth 		format(o->mnemonic, i, "R%s,%b");
27674a4d8c2SCharles.Forsyth 	else
27774a4d8c2SCharles.Forsyth 		format(o->mnemonic, i, "R%s,R%t,%b");
27874a4d8c2SCharles.Forsyth }
27974a4d8c2SCharles.Forsyth 
28074a4d8c2SCharles.Forsyth static void
addi(Opcode * o,Instr * i)28174a4d8c2SCharles.Forsyth addi(Opcode *o, Instr *i)
28274a4d8c2SCharles.Forsyth {
28374a4d8c2SCharles.Forsyth 	if (i->rs == i->rt)
28474a4d8c2SCharles.Forsyth 		format(o->mnemonic, i, "%i,R%t");
28574a4d8c2SCharles.Forsyth 	else if (i->rs == 0)
28674a4d8c2SCharles.Forsyth 		format("MOVW", i, "%i,R%t");
28774a4d8c2SCharles.Forsyth 	else if (i->rs == 30) {
28874a4d8c2SCharles.Forsyth 		bprint(i, "MOVW\t$");
28974a4d8c2SCharles.Forsyth 		i->curr += symoff(i->curr, i->end-i->curr,
29074a4d8c2SCharles.Forsyth 					i->immediate+mach->sb, CANY);
29174a4d8c2SCharles.Forsyth 		bprint(i, "(SB),R%d", i->rt);
29274a4d8c2SCharles.Forsyth 	}
29374a4d8c2SCharles.Forsyth 	else
29474a4d8c2SCharles.Forsyth 		format(o->mnemonic, i, o->ken);
29574a4d8c2SCharles.Forsyth }
29674a4d8c2SCharles.Forsyth 
29774a4d8c2SCharles.Forsyth static void
andi(Opcode * o,Instr * i)29874a4d8c2SCharles.Forsyth andi(Opcode *o, Instr *i)
29974a4d8c2SCharles.Forsyth {
30074a4d8c2SCharles.Forsyth 	if (i->rs == i->rt)
30174a4d8c2SCharles.Forsyth 		format(o->mnemonic, i, "%i,R%t");
30274a4d8c2SCharles.Forsyth 	else
30374a4d8c2SCharles.Forsyth 		format(o->mnemonic, i, o->ken);
30474a4d8c2SCharles.Forsyth }
30574a4d8c2SCharles.Forsyth 
30674a4d8c2SCharles.Forsyth static int
plocal(Instr * i,char * m,char r,int store)30774a4d8c2SCharles.Forsyth plocal(Instr *i, char *m, char r, int store)
30874a4d8c2SCharles.Forsyth {
30974a4d8c2SCharles.Forsyth 	int offset;
31074a4d8c2SCharles.Forsyth 	char *reg;
31174a4d8c2SCharles.Forsyth 	Symbol s;
31274a4d8c2SCharles.Forsyth 
31374a4d8c2SCharles.Forsyth 	if (!findsym(i->addr, CTEXT, &s) || !findlocal(&s, FRAMENAME, &s))
31474a4d8c2SCharles.Forsyth 		return 0;
31574a4d8c2SCharles.Forsyth 	if (s.value > i->immediate) {
31674a4d8c2SCharles.Forsyth 		if(!getauto(&s, s.value-i->immediate, CAUTO, &s))
31774a4d8c2SCharles.Forsyth 			return 0;
31874a4d8c2SCharles.Forsyth 		reg = "(SP)";
31974a4d8c2SCharles.Forsyth 		offset = i->immediate;
32074a4d8c2SCharles.Forsyth 	} else {
32174a4d8c2SCharles.Forsyth 		offset = i->immediate-s.value;
32274a4d8c2SCharles.Forsyth 		if (!getauto(&s, offset-4, CPARAM, &s))
32374a4d8c2SCharles.Forsyth 			return 0;
32474a4d8c2SCharles.Forsyth 		reg = "(FP)";
32574a4d8c2SCharles.Forsyth 	}
32674a4d8c2SCharles.Forsyth 	if (store)
32774a4d8c2SCharles.Forsyth 		bprint(i, "%s\t%c%d,%s+%d%s", m, r, i->rt, s.name, offset, reg);
32874a4d8c2SCharles.Forsyth 	else
32974a4d8c2SCharles.Forsyth 		bprint(i, "%s\t%s+%d%s,%c%d", m, s.name, offset, reg, r, i->rt);
33074a4d8c2SCharles.Forsyth 	return 1;
33174a4d8c2SCharles.Forsyth }
33274a4d8c2SCharles.Forsyth 
33374a4d8c2SCharles.Forsyth static void
lw(Opcode * o,Instr * i,char r)33474a4d8c2SCharles.Forsyth lw(Opcode *o, Instr *i, char r)
33574a4d8c2SCharles.Forsyth {
33674a4d8c2SCharles.Forsyth 	char *m;
33774a4d8c2SCharles.Forsyth 
33874a4d8c2SCharles.Forsyth 	if (r == 'F') {
33974a4d8c2SCharles.Forsyth 		if (i->size == 2)
34074a4d8c2SCharles.Forsyth 			m = "MOVD";
34174a4d8c2SCharles.Forsyth 		else
34274a4d8c2SCharles.Forsyth 			m = "MOVF";
34374a4d8c2SCharles.Forsyth 	}
34474a4d8c2SCharles.Forsyth 	else
34574a4d8c2SCharles.Forsyth 		m = o->mnemonic;
34674a4d8c2SCharles.Forsyth 	if (i->rs == 29 && plocal(i, m, r, 0))
34774a4d8c2SCharles.Forsyth 			return;
34874a4d8c2SCharles.Forsyth 
34974a4d8c2SCharles.Forsyth 	if (i->rs == 30 && mach->sb) {
35074a4d8c2SCharles.Forsyth 		bprint(i, "%s\t", m);
35174a4d8c2SCharles.Forsyth 		i->curr += symoff(i->curr, i->end-i->curr, i->immediate+mach->sb, CANY);
35274a4d8c2SCharles.Forsyth 		bprint(i, "(SB),%c%d", r, i->rt);
35374a4d8c2SCharles.Forsyth 		return;
35474a4d8c2SCharles.Forsyth 	}
35574a4d8c2SCharles.Forsyth 	if (r == 'F')
35674a4d8c2SCharles.Forsyth 		format(m, i, "%l,F%t");
35774a4d8c2SCharles.Forsyth 	else
35874a4d8c2SCharles.Forsyth 		format(m, i, o->ken);
35974a4d8c2SCharles.Forsyth }
36074a4d8c2SCharles.Forsyth 
36174a4d8c2SCharles.Forsyth static void
load(Opcode * o,Instr * i)36274a4d8c2SCharles.Forsyth load(Opcode *o, Instr *i)
36374a4d8c2SCharles.Forsyth {
36474a4d8c2SCharles.Forsyth 	lw(o, i, 'R');
36574a4d8c2SCharles.Forsyth }
36674a4d8c2SCharles.Forsyth 
36774a4d8c2SCharles.Forsyth static void
lwc1(Opcode * o,Instr * i)36874a4d8c2SCharles.Forsyth lwc1(Opcode *o, Instr *i)
36974a4d8c2SCharles.Forsyth {
37074a4d8c2SCharles.Forsyth 	lw(o, i, 'F');
37174a4d8c2SCharles.Forsyth }
37274a4d8c2SCharles.Forsyth 
37374a4d8c2SCharles.Forsyth static void
sw(Opcode * o,Instr * i,char r)37474a4d8c2SCharles.Forsyth sw(Opcode *o, Instr *i, char r)
37574a4d8c2SCharles.Forsyth {
37674a4d8c2SCharles.Forsyth 	char *m;
37774a4d8c2SCharles.Forsyth 
37874a4d8c2SCharles.Forsyth 	if (r == 'F') {
37974a4d8c2SCharles.Forsyth 		if (i->size == 2)
38074a4d8c2SCharles.Forsyth 			m = "MOVD";
38174a4d8c2SCharles.Forsyth 		else
38274a4d8c2SCharles.Forsyth 			m = "MOVF";
38374a4d8c2SCharles.Forsyth 	}
38474a4d8c2SCharles.Forsyth 	else
38574a4d8c2SCharles.Forsyth 		m = o->mnemonic;
38674a4d8c2SCharles.Forsyth 	if (i->rs == 29 && plocal(i, m, r, 1))
38774a4d8c2SCharles.Forsyth 			return;
38874a4d8c2SCharles.Forsyth 
38974a4d8c2SCharles.Forsyth 	if (i->rs == 30 && mach->sb) {
39074a4d8c2SCharles.Forsyth 		bprint(i, "%s\t%c%d,", m, r, i->rt);
39174a4d8c2SCharles.Forsyth 		i->curr += symoff(i->curr, i->end-i->curr, i->immediate+mach->sb, CANY);
39274a4d8c2SCharles.Forsyth 		bprint(i, "(SB)");
39374a4d8c2SCharles.Forsyth 		return;
39474a4d8c2SCharles.Forsyth 	}
39574a4d8c2SCharles.Forsyth 	if (r == 'F')
39674a4d8c2SCharles.Forsyth 		format(m, i, "F%t,%l");
39774a4d8c2SCharles.Forsyth 	else
39874a4d8c2SCharles.Forsyth 		format(m, i, o->ken);
39974a4d8c2SCharles.Forsyth }
40074a4d8c2SCharles.Forsyth 
40174a4d8c2SCharles.Forsyth static void
store(Opcode * o,Instr * i)40274a4d8c2SCharles.Forsyth store(Opcode *o, Instr *i)
40374a4d8c2SCharles.Forsyth {
40474a4d8c2SCharles.Forsyth 	sw(o, i, 'R');
40574a4d8c2SCharles.Forsyth }
40674a4d8c2SCharles.Forsyth 
40774a4d8c2SCharles.Forsyth static void
swc1(Opcode * o,Instr * i)40874a4d8c2SCharles.Forsyth swc1(Opcode *o, Instr *i)
40974a4d8c2SCharles.Forsyth {
41074a4d8c2SCharles.Forsyth 	sw(o, i, 'F');
41174a4d8c2SCharles.Forsyth }
41274a4d8c2SCharles.Forsyth 
41374a4d8c2SCharles.Forsyth static void
sll(Opcode * o,Instr * i)41474a4d8c2SCharles.Forsyth sll(Opcode *o, Instr *i)
41574a4d8c2SCharles.Forsyth {
41674a4d8c2SCharles.Forsyth 	if (i->w0 == 0)
41774a4d8c2SCharles.Forsyth 		bprint(i, "NOOP");
41874a4d8c2SCharles.Forsyth 	else if (i->rd == i->rt)
41974a4d8c2SCharles.Forsyth 		format(o->mnemonic, i, "$%a,R%d");
42074a4d8c2SCharles.Forsyth 	else
42174a4d8c2SCharles.Forsyth 		format(o->mnemonic, i, o->ken);
42274a4d8c2SCharles.Forsyth }
42374a4d8c2SCharles.Forsyth 
42474a4d8c2SCharles.Forsyth static void
sl32(Opcode * o,Instr * i)42574a4d8c2SCharles.Forsyth sl32(Opcode *o, Instr *i)
42674a4d8c2SCharles.Forsyth {
42774a4d8c2SCharles.Forsyth 	i->sa += 32;
42874a4d8c2SCharles.Forsyth 	if (i->rd == i->rt)
42974a4d8c2SCharles.Forsyth 		format(o->mnemonic, i, "$%a,R%d");
43074a4d8c2SCharles.Forsyth 	else
43174a4d8c2SCharles.Forsyth 		format(o->mnemonic, i, o->ken);
43274a4d8c2SCharles.Forsyth }
43374a4d8c2SCharles.Forsyth 
43474a4d8c2SCharles.Forsyth static void
sllv(Opcode * o,Instr * i)43574a4d8c2SCharles.Forsyth sllv(Opcode *o, Instr *i)
43674a4d8c2SCharles.Forsyth {
43774a4d8c2SCharles.Forsyth 	if (i->rd == i->rt)
43874a4d8c2SCharles.Forsyth 		format(o->mnemonic, i, "R%s,R%d");
43974a4d8c2SCharles.Forsyth 	else
44074a4d8c2SCharles.Forsyth 		format(o->mnemonic, i, o->ken);
44174a4d8c2SCharles.Forsyth }
44274a4d8c2SCharles.Forsyth 
44374a4d8c2SCharles.Forsyth static void
jal(Opcode * o,Instr * i)44474a4d8c2SCharles.Forsyth jal(Opcode *o, Instr *i)
44574a4d8c2SCharles.Forsyth {
44674a4d8c2SCharles.Forsyth 	if (i->rd == 31)
44774a4d8c2SCharles.Forsyth 		format("JAL", i, "(R%s)");
44874a4d8c2SCharles.Forsyth 	else
44974a4d8c2SCharles.Forsyth 		format(o->mnemonic, i, o->ken);
45074a4d8c2SCharles.Forsyth }
45174a4d8c2SCharles.Forsyth 
45274a4d8c2SCharles.Forsyth static void
add(Opcode * o,Instr * i)45374a4d8c2SCharles.Forsyth add(Opcode *o, Instr *i)
45474a4d8c2SCharles.Forsyth {
45574a4d8c2SCharles.Forsyth 	if (i->rd == i->rs)
45674a4d8c2SCharles.Forsyth 		format(o->mnemonic, i, "R%t,R%d");
45774a4d8c2SCharles.Forsyth 	else if (i->rd == i->rt)
45874a4d8c2SCharles.Forsyth 		format(o->mnemonic, i, "R%s,R%d");
45974a4d8c2SCharles.Forsyth 	else
46074a4d8c2SCharles.Forsyth 		format(o->mnemonic, i, o->ken);
46174a4d8c2SCharles.Forsyth }
46274a4d8c2SCharles.Forsyth 
46374a4d8c2SCharles.Forsyth static void
sub(Opcode * o,Instr * i)46474a4d8c2SCharles.Forsyth sub(Opcode *o, Instr *i)
46574a4d8c2SCharles.Forsyth {
46674a4d8c2SCharles.Forsyth 	if (i->rd == i->rs)
46774a4d8c2SCharles.Forsyth 		format(o->mnemonic, i, "R%t,R%d");
46874a4d8c2SCharles.Forsyth 	else
46974a4d8c2SCharles.Forsyth 		format(o->mnemonic, i, o->ken);
47074a4d8c2SCharles.Forsyth }
47174a4d8c2SCharles.Forsyth 
47274a4d8c2SCharles.Forsyth static void
or(Opcode * o,Instr * i)47374a4d8c2SCharles.Forsyth or(Opcode *o, Instr *i)
47474a4d8c2SCharles.Forsyth {
47574a4d8c2SCharles.Forsyth 	if (i->rs == 0 && i->rt == 0)
47674a4d8c2SCharles.Forsyth 		format("MOVW", i, "$0,R%d");
47774a4d8c2SCharles.Forsyth 	else if (i->rs == 0)
47874a4d8c2SCharles.Forsyth 		format("MOVW", i, "R%t,R%d");
47974a4d8c2SCharles.Forsyth 	else if (i->rt == 0)
48074a4d8c2SCharles.Forsyth 		format("MOVW", i, "R%s,R%d");
48174a4d8c2SCharles.Forsyth 	else
48274a4d8c2SCharles.Forsyth 		add(o, i);
48374a4d8c2SCharles.Forsyth }
48474a4d8c2SCharles.Forsyth 
48574a4d8c2SCharles.Forsyth static void
nor(Opcode * o,Instr * i)48674a4d8c2SCharles.Forsyth nor(Opcode *o, Instr *i)
48774a4d8c2SCharles.Forsyth {
48874a4d8c2SCharles.Forsyth 	if (i->rs == 0 && i->rt == 0 && i->rd == 0)
48974a4d8c2SCharles.Forsyth 		format("NOP", i, 0);
49074a4d8c2SCharles.Forsyth 	else
49174a4d8c2SCharles.Forsyth 		add(o, i);
49274a4d8c2SCharles.Forsyth }
49374a4d8c2SCharles.Forsyth 
49474a4d8c2SCharles.Forsyth static char mipscoload[] = "r%t,%l";
49574a4d8c2SCharles.Forsyth static char mipsload[] = "%l,R%t";
49674a4d8c2SCharles.Forsyth static char mipsstore[] = "R%t,%l";
49774a4d8c2SCharles.Forsyth static char mipsalui[] = "%i,R%s,R%t";
49874a4d8c2SCharles.Forsyth static char mipsalu3op[] = "R%t,R%s,R%d";
49974a4d8c2SCharles.Forsyth static char mipsrtrs[] = "R%t,R%s";
50074a4d8c2SCharles.Forsyth static char mipscorsrt[] = "r%s,r%t";
50174a4d8c2SCharles.Forsyth static char mipscorsi[] = "r%s,%i";
50274a4d8c2SCharles.Forsyth static char mipscoxxx[] = "%w";
50374a4d8c2SCharles.Forsyth static char mipscofp3[] = "f%a,f%d,f%t";	/* fd,fs,ft */
50474a4d8c2SCharles.Forsyth static char mipsfp3[] = "F%t,F%d,F%a";
50574a4d8c2SCharles.Forsyth static char mipscofp2[] = "f%a,f%d";		/* fd,fs */
50674a4d8c2SCharles.Forsyth static char mipsfp2[] = "F%d,F%a";
50774a4d8c2SCharles.Forsyth static char mipscofpc[] = "f%d,f%t";		/* fs,ft */
50874a4d8c2SCharles.Forsyth static char mipsfpc[] = "F%t,F%d";
50974a4d8c2SCharles.Forsyth 
51074a4d8c2SCharles.Forsyth static Opcode opcodes[64] = {
51174a4d8c2SCharles.Forsyth 	0,		0,	0,
51274a4d8c2SCharles.Forsyth 	0,		0,	0,
51374a4d8c2SCharles.Forsyth 	"JMP",		0,	"%j",
51474a4d8c2SCharles.Forsyth 	"JAL",		0,	"%j",
51574a4d8c2SCharles.Forsyth 	"BEQ",	   branch,	0,
51674a4d8c2SCharles.Forsyth 	"BNE",	   branch,	0,
51774a4d8c2SCharles.Forsyth 	"BLEZ",	   branch,	0,
51874a4d8c2SCharles.Forsyth 	"BGTZ",	   branch,	0,
51974a4d8c2SCharles.Forsyth 	"ADD",	     addi,	mipsalui,
52074a4d8c2SCharles.Forsyth 	"ADDU",	     addi,	mipsalui,
52174a4d8c2SCharles.Forsyth 	"SGT",		0,	mipsalui,
52274a4d8c2SCharles.Forsyth 	"SGTU",		0,	mipsalui,
52374a4d8c2SCharles.Forsyth 	"AND",	     andi,	mipsalui,
52474a4d8c2SCharles.Forsyth 	"OR",	     andi,	mipsalui,
52574a4d8c2SCharles.Forsyth 	"XOR",	     andi,	mipsalui,
52674a4d8c2SCharles.Forsyth 	"MOVW",		0,	"$%u,R%t",
52774a4d8c2SCharles.Forsyth 	"cop0",		0,	0,
52874a4d8c2SCharles.Forsyth 	"cop1",		0,	0,
52974a4d8c2SCharles.Forsyth 	"cop2",		0,	0,
53074a4d8c2SCharles.Forsyth 	"cop3",		0,	0,
53174a4d8c2SCharles.Forsyth 	"BEQL",	   branch,	0,
53274a4d8c2SCharles.Forsyth 	"BNEL",	   branch,	0,
53374a4d8c2SCharles.Forsyth 	"BLEZL",   branch,	0,
53474a4d8c2SCharles.Forsyth 	"BGTZL",   branch,	0,
53574a4d8c2SCharles.Forsyth 	"instr18",	0,	mipscoxxx,
53674a4d8c2SCharles.Forsyth 	"instr19",	0,	mipscoxxx,
53774a4d8c2SCharles.Forsyth 	"MOVVL",     load,	mipsload,
53874a4d8c2SCharles.Forsyth 	"MOVVR",     load,	mipsload,
53974a4d8c2SCharles.Forsyth 	"instr1C",	0,	mipscoxxx,
54074a4d8c2SCharles.Forsyth 	"instr1D",	0,	mipscoxxx,
54174a4d8c2SCharles.Forsyth 	"instr1E",	0,	mipscoxxx,
54274a4d8c2SCharles.Forsyth 	"instr1F",	0,	mipscoxxx,
54374a4d8c2SCharles.Forsyth 	"MOVB",	     load,	mipsload,
54474a4d8c2SCharles.Forsyth 	"MOVH",	     load,	mipsload,
54574a4d8c2SCharles.Forsyth 	"lwl",		0,	mipscoload,
54674a4d8c2SCharles.Forsyth 	"MOVW",	     load,	mipsload,
54774a4d8c2SCharles.Forsyth 	"MOVBU",     load,	mipsload,
54874a4d8c2SCharles.Forsyth 	"MOVHU",     load,	mipsload,
54974a4d8c2SCharles.Forsyth 	"lwr",		0,	mipscoload,
55074a4d8c2SCharles.Forsyth 	"instr27",	0,	mipscoxxx,
55174a4d8c2SCharles.Forsyth 	"MOVB",	    store,	mipsstore,
55274a4d8c2SCharles.Forsyth 	"MOVH",	    store,	mipsstore,
55374a4d8c2SCharles.Forsyth 	"swl",		0,	mipscoload,
55474a4d8c2SCharles.Forsyth 	"MOVW",	    store,	mipsstore,
55574a4d8c2SCharles.Forsyth 	"MOVVL",    store,	mipsstore,
55674a4d8c2SCharles.Forsyth 	"MOVVR",    store,	mipsstore,
55774a4d8c2SCharles.Forsyth 	"swr",		0,	mipscoload,
55874a4d8c2SCharles.Forsyth 	"CACHE",	0,	"%C,%l",
55974a4d8c2SCharles.Forsyth 	"ll",		0,	mipscoload,
56074a4d8c2SCharles.Forsyth 	"MOVW",	     lwc1,	mipscoload,
56174a4d8c2SCharles.Forsyth 	"lwc2",		0,	mipscoload,
56274a4d8c2SCharles.Forsyth 	"lwc3",		0,	mipscoload,
56374a4d8c2SCharles.Forsyth 	"instr34",	0,	mipscoxxx,
56474a4d8c2SCharles.Forsyth 	"ldc1",		0,	mipscoload,
56574a4d8c2SCharles.Forsyth 	"ldc2",		0,	mipscoload,
56674a4d8c2SCharles.Forsyth 	"MOVV",	    load,	mipsload,
56774a4d8c2SCharles.Forsyth 	"sc",		0,	mipscoload,
56874a4d8c2SCharles.Forsyth 	"swc1",	     swc1,	mipscoload,
56974a4d8c2SCharles.Forsyth 	"swc2",		0,	mipscoload,
57074a4d8c2SCharles.Forsyth 	"swc3",		0,	mipscoload,
57174a4d8c2SCharles.Forsyth 	"instr3C",	0,	mipscoxxx,
57274a4d8c2SCharles.Forsyth 	"sdc1",		0,	mipscoload,
57374a4d8c2SCharles.Forsyth 	"sdc2",		0,	mipscoload,
57474a4d8c2SCharles.Forsyth 	"MOVV",	    store,	mipsstore,
57574a4d8c2SCharles.Forsyth };
57674a4d8c2SCharles.Forsyth 
57774a4d8c2SCharles.Forsyth static Opcode sopcodes[64] = {
57874a4d8c2SCharles.Forsyth 	"SLL",	      sll,	"$%a,R%t,R%d",
57974a4d8c2SCharles.Forsyth 	"special01",	0,	mipscoxxx,
58074a4d8c2SCharles.Forsyth 	"SRL",	      sll,	"$%a,R%t,R%d",
58174a4d8c2SCharles.Forsyth 	"SRA",	      sll,	"$%a,R%t,R%d",
58274a4d8c2SCharles.Forsyth 	"SLL",	     sllv,	"R%s,R%t,R%d",
58374a4d8c2SCharles.Forsyth 	"special05",	0,	mipscoxxx,
58474a4d8c2SCharles.Forsyth 	"SRL",	     sllv,	"R%s,R%t,R%d",
58574a4d8c2SCharles.Forsyth 	"SRA",	     sllv,	"R%s,R%t,R%d",
58674a4d8c2SCharles.Forsyth 	"JMP",		0,	"(R%s)",
58774a4d8c2SCharles.Forsyth 	"jal",	      jal,	"r%d,r%s",
58874a4d8c2SCharles.Forsyth 	"special0A",	0,	mipscoxxx,
58974a4d8c2SCharles.Forsyth 	"special0B",	0,	mipscoxxx,
59074a4d8c2SCharles.Forsyth 	"SYSCALL",	0,	0,
59174a4d8c2SCharles.Forsyth 	"BREAK",	0,	0,
59274a4d8c2SCharles.Forsyth 	"special0E",	0,	mipscoxxx,
59374a4d8c2SCharles.Forsyth 	"SYNC",		0,	0,
59474a4d8c2SCharles.Forsyth 	"MOVW",		0,	"HI,R%d",
59574a4d8c2SCharles.Forsyth 	"MOVW",		0,	"R%s,HI",
59674a4d8c2SCharles.Forsyth 	"MOVW",		0,	"LO,R%d",
59774a4d8c2SCharles.Forsyth 	"MOVW",		0,	"R%s,LO",
59874a4d8c2SCharles.Forsyth 	"SLLV",	     sllv,	"R%s,R%t,R%d",
59974a4d8c2SCharles.Forsyth 	"special15",	0,	mipscoxxx,
60074a4d8c2SCharles.Forsyth 	"SRLV",	     sllv,	"R%s,R%t,R%d",
60174a4d8c2SCharles.Forsyth 	"SRAV",	     sllv,	"R%s,R%t,R%d",
60274a4d8c2SCharles.Forsyth 	"MUL",		0,	mipsrtrs,
60374a4d8c2SCharles.Forsyth 	"MULU",		0,	mipsrtrs,
60474a4d8c2SCharles.Forsyth 	"DIV",		0,	mipsrtrs,
60574a4d8c2SCharles.Forsyth 	"DIVU",		0,	mipsrtrs,
60674a4d8c2SCharles.Forsyth 	"special1C",	0,	mipscoxxx,
60774a4d8c2SCharles.Forsyth 	"special1D",	0,	mipscoxxx,
60874a4d8c2SCharles.Forsyth 	"DDIV",		0,	"R%s,R%t",
60974a4d8c2SCharles.Forsyth 	"special1F",	0,	mipscoxxx,
61074a4d8c2SCharles.Forsyth 	"ADD",	      add,	mipsalu3op,
61174a4d8c2SCharles.Forsyth 	"ADDU",	      add,	mipsalu3op,
61274a4d8c2SCharles.Forsyth 	"SUB",	      sub,	mipsalu3op,
61374a4d8c2SCharles.Forsyth 	"SUBU",	      sub,	mipsalu3op,
61474a4d8c2SCharles.Forsyth 	"AND",	      add,	mipsalu3op,
61574a4d8c2SCharles.Forsyth 	"OR",	       or,	mipsalu3op,
61674a4d8c2SCharles.Forsyth 	"XOR",	      add,	mipsalu3op,
61774a4d8c2SCharles.Forsyth 	"NOR",	      nor,	mipsalu3op,
61874a4d8c2SCharles.Forsyth 	"special28",	0,	mipscoxxx,
61974a4d8c2SCharles.Forsyth 	"special29",	0,	mipscoxxx,
62074a4d8c2SCharles.Forsyth 	"SGT",		0,	mipsalu3op,
62174a4d8c2SCharles.Forsyth 	"SGTU",		0,	mipsalu3op,
62274a4d8c2SCharles.Forsyth 	"special2C",	0,	mipscoxxx,
62374a4d8c2SCharles.Forsyth 	"special2D",	0,	mipscoxxx,
62474a4d8c2SCharles.Forsyth 	"special2E",	0,	mipscoxxx,
62574a4d8c2SCharles.Forsyth 	"DSUBU",	0,	"R%s,R%t,R%d",
62674a4d8c2SCharles.Forsyth 	"tge",		0,	mipscorsrt,
62774a4d8c2SCharles.Forsyth 	"tgeu",		0,	mipscorsrt,
62874a4d8c2SCharles.Forsyth 	"tlt",		0,	mipscorsrt,
62974a4d8c2SCharles.Forsyth 	"tltu",		0,	mipscorsrt,
63074a4d8c2SCharles.Forsyth 	"teq",		0,	mipscorsrt,
63174a4d8c2SCharles.Forsyth 	"special35",	0,	mipscoxxx,
63274a4d8c2SCharles.Forsyth 	"tne",		0,	mipscorsrt,
63374a4d8c2SCharles.Forsyth 	"special37",	0,	mipscoxxx,
63474a4d8c2SCharles.Forsyth 	"SLLV",	      sll,	"$%a,R%t,R%d",
63574a4d8c2SCharles.Forsyth 	"special39",	0,	mipscoxxx,
63674a4d8c2SCharles.Forsyth 	"SRLV",	      sll,	"$%a,R%t,R%d",
63774a4d8c2SCharles.Forsyth 	"SRAV",	      sll,	"$%a,R%t,R%d",
63874a4d8c2SCharles.Forsyth 	"SLLV",	     sl32,	"$%a,R%t,R%d",
63974a4d8c2SCharles.Forsyth 	"special3D",	0,	mipscoxxx,
64074a4d8c2SCharles.Forsyth 	"SRLV",	     sl32,	"$%a,R%t,R%d",
64174a4d8c2SCharles.Forsyth 	"SRAV",	     sl32,	"$%a,R%t,R%d",
64274a4d8c2SCharles.Forsyth };
64374a4d8c2SCharles.Forsyth 
64474a4d8c2SCharles.Forsyth static Opcode ropcodes[32] = {
64574a4d8c2SCharles.Forsyth 	"BLTZ",	   branch,	0,
64674a4d8c2SCharles.Forsyth 	"BGEZ",	   branch,	0,
64774a4d8c2SCharles.Forsyth 	"BLTZL",   branch,	0,
64874a4d8c2SCharles.Forsyth 	"BGEZL",   branch,	0,
64974a4d8c2SCharles.Forsyth 	"regimm04",	0,	mipscoxxx,
65074a4d8c2SCharles.Forsyth 	"regimm05",	0,	mipscoxxx,
65174a4d8c2SCharles.Forsyth 	"regimm06",	0,	mipscoxxx,
65274a4d8c2SCharles.Forsyth 	"regimm07",	0,	mipscoxxx,
65374a4d8c2SCharles.Forsyth 	"tgei",		0,	mipscorsi,
65474a4d8c2SCharles.Forsyth 	"tgeiu",	0,	mipscorsi,
65574a4d8c2SCharles.Forsyth 	"tlti",		0,	mipscorsi,
65674a4d8c2SCharles.Forsyth 	"tltiu",	0,	mipscorsi,
65774a4d8c2SCharles.Forsyth 	"teqi",		0,	mipscorsi,
65874a4d8c2SCharles.Forsyth 	"regimm0D",	0,	mipscoxxx,
65974a4d8c2SCharles.Forsyth 	"tnei",		0,	mipscorsi,
66074a4d8c2SCharles.Forsyth 	"regimm0F",	0,	mipscoxxx,
66174a4d8c2SCharles.Forsyth 	"BLTZAL",  branch,	0,
66274a4d8c2SCharles.Forsyth 	"BGEZAL",  branch,	0,
66374a4d8c2SCharles.Forsyth 	"BLTZALL", branch,	0,
66474a4d8c2SCharles.Forsyth 	"BGEZALL", branch,	0,
66574a4d8c2SCharles.Forsyth 	"regimm14",	0,	mipscoxxx,
66674a4d8c2SCharles.Forsyth 	"regimm15",	0,	mipscoxxx,
66774a4d8c2SCharles.Forsyth 	"regimm16",	0,	mipscoxxx,
66874a4d8c2SCharles.Forsyth 	"regimm17",	0,	mipscoxxx,
66974a4d8c2SCharles.Forsyth 	"regimm18",	0,	mipscoxxx,
67074a4d8c2SCharles.Forsyth 	"regimm19",	0,	mipscoxxx,
67174a4d8c2SCharles.Forsyth 	"regimm1A",	0,	mipscoxxx,
67274a4d8c2SCharles.Forsyth 	"regimm1B",	0,	mipscoxxx,
67374a4d8c2SCharles.Forsyth 	"regimm1C",	0,	mipscoxxx,
67474a4d8c2SCharles.Forsyth 	"regimm1D",	0,	mipscoxxx,
67574a4d8c2SCharles.Forsyth 	"regimm1E",	0,	mipscoxxx,
67674a4d8c2SCharles.Forsyth 	"regimm1F",	0,	mipscoxxx,
67774a4d8c2SCharles.Forsyth };
67874a4d8c2SCharles.Forsyth 
67974a4d8c2SCharles.Forsyth static Opcode fopcodes[64] = {
68074a4d8c2SCharles.Forsyth 	"ADD%f",	0,	mipsfp3,
68174a4d8c2SCharles.Forsyth 	"SUB%f",	0,	mipsfp3,
68274a4d8c2SCharles.Forsyth 	"MUL%f",	0,	mipsfp3,
68374a4d8c2SCharles.Forsyth 	"DIV%f",	0,	mipsfp3,
68474a4d8c2SCharles.Forsyth 	"sqrt.%f",	0,	mipscofp2,
68574a4d8c2SCharles.Forsyth 	"ABS%f",	0,	mipsfp2,
68674a4d8c2SCharles.Forsyth 	"MOV%f",	0,	mipsfp2,
68774a4d8c2SCharles.Forsyth 	"NEG%f",	0,	mipsfp2,
68874a4d8c2SCharles.Forsyth 	"finstr08",	0,	mipscoxxx,
68974a4d8c2SCharles.Forsyth 	"finstr09",	0,	mipscoxxx,
69074a4d8c2SCharles.Forsyth 	"finstr0A",	0,	mipscoxxx,
69174a4d8c2SCharles.Forsyth 	"finstr0B",	0,	mipscoxxx,
69274a4d8c2SCharles.Forsyth 	"round.w.%f",	0,	mipscofp2,
69374a4d8c2SCharles.Forsyth 	"trunc.w%f",	0,	mipscofp2,
69474a4d8c2SCharles.Forsyth 	"ceil.w%f",	0,	mipscofp2,
69574a4d8c2SCharles.Forsyth 	"floor.w%f",	0,	mipscofp2,
69674a4d8c2SCharles.Forsyth 	"finstr10",	0,	mipscoxxx,
69774a4d8c2SCharles.Forsyth 	"finstr11",	0,	mipscoxxx,
69874a4d8c2SCharles.Forsyth 	"finstr12",	0,	mipscoxxx,
69974a4d8c2SCharles.Forsyth 	"finstr13",	0,	mipscoxxx,
70074a4d8c2SCharles.Forsyth 	"finstr14",	0,	mipscoxxx,
70174a4d8c2SCharles.Forsyth 	"finstr15",	0,	mipscoxxx,
70274a4d8c2SCharles.Forsyth 	"finstr16",	0,	mipscoxxx,
70374a4d8c2SCharles.Forsyth 	"finstr17",	0,	mipscoxxx,
70474a4d8c2SCharles.Forsyth 	"finstr18",	0,	mipscoxxx,
70574a4d8c2SCharles.Forsyth 	"finstr19",	0,	mipscoxxx,
70674a4d8c2SCharles.Forsyth 	"finstr1A",	0,	mipscoxxx,
70774a4d8c2SCharles.Forsyth 	"finstr1B",	0,	mipscoxxx,
70874a4d8c2SCharles.Forsyth 	"finstr1C",	0,	mipscoxxx,
70974a4d8c2SCharles.Forsyth 	"finstr1D",	0,	mipscoxxx,
71074a4d8c2SCharles.Forsyth 	"finstr1E",	0,	mipscoxxx,
71174a4d8c2SCharles.Forsyth 	"finstr1F",	0,	mipscoxxx,
71274a4d8c2SCharles.Forsyth 	"cvt.s.%f",	0,	mipscofp2,
71374a4d8c2SCharles.Forsyth 	"cvt.d.%f",	0,	mipscofp2,
71474a4d8c2SCharles.Forsyth 	"cvt.e.%f",	0,	mipscofp2,
71574a4d8c2SCharles.Forsyth 	"cvt.q.%f",	0,	mipscofp2,
71674a4d8c2SCharles.Forsyth 	"cvt.w.%f",	0,	mipscofp2,
71774a4d8c2SCharles.Forsyth 	"finstr25",	0,	mipscoxxx,
71874a4d8c2SCharles.Forsyth 	"finstr26",	0,	mipscoxxx,
71974a4d8c2SCharles.Forsyth 	"finstr27",	0,	mipscoxxx,
72074a4d8c2SCharles.Forsyth 	"finstr28",	0,	mipscoxxx,
72174a4d8c2SCharles.Forsyth 	"finstr29",	0,	mipscoxxx,
72274a4d8c2SCharles.Forsyth 	"finstr2A",	0,	mipscoxxx,
72374a4d8c2SCharles.Forsyth 	"finstr2B",	0,	mipscoxxx,
72474a4d8c2SCharles.Forsyth 	"finstr2C",	0,	mipscoxxx,
72574a4d8c2SCharles.Forsyth 	"finstr2D",	0,	mipscoxxx,
72674a4d8c2SCharles.Forsyth 	"finstr2E",	0,	mipscoxxx,
72774a4d8c2SCharles.Forsyth 	"finstr2F",	0,	mipscoxxx,
72874a4d8c2SCharles.Forsyth 	"c.f.%f",	0,	mipscofpc,
72974a4d8c2SCharles.Forsyth 	"c.un.%f",	0,	mipscofpc,
73074a4d8c2SCharles.Forsyth 	"CMPEQ%f",	0,	mipsfpc,
73174a4d8c2SCharles.Forsyth 	"c.ueq.%f",	0,	mipscofpc,
73274a4d8c2SCharles.Forsyth 	"c.olt.%f",	0,	mipscofpc,
73374a4d8c2SCharles.Forsyth 	"c.ult.%f",	0,	mipscofpc,
73474a4d8c2SCharles.Forsyth 	"c.ole.%f",	0,	mipscofpc,
73574a4d8c2SCharles.Forsyth 	"c.ule.%f",	0,	mipscofpc,
73674a4d8c2SCharles.Forsyth 	"c.sf.%f",	0,	mipscofpc,
73774a4d8c2SCharles.Forsyth 	"c.ngle.%f",	0,	mipscofpc,
73874a4d8c2SCharles.Forsyth 	"c.seq.%f",	0,	mipscofpc,
73974a4d8c2SCharles.Forsyth 	"c.ngl.%f",	0,	mipscofpc,
74074a4d8c2SCharles.Forsyth 	"CMPGT%f",	0,	mipsfpc,
74174a4d8c2SCharles.Forsyth 	"c.nge.%f",	0,	mipscofpc,
74274a4d8c2SCharles.Forsyth 	"CMPGE%f",	0,	mipsfpc,
74374a4d8c2SCharles.Forsyth 	"c.ngt.%f",	0,	mipscofpc,
74474a4d8c2SCharles.Forsyth };
74574a4d8c2SCharles.Forsyth 
74674a4d8c2SCharles.Forsyth static char *cop0regs[32] = {
74774a4d8c2SCharles.Forsyth 	"INDEX", "RANDOM", "TLBPHYS", "EntryLo0",
74874a4d8c2SCharles.Forsyth 	"CONTEXT", "PageMask", "Wired",	"Error",
74974a4d8c2SCharles.Forsyth 	"BADVADDR", "Count", "TLBVIRT", "Compare",
75074a4d8c2SCharles.Forsyth 	"STATUS", "CAUSE", "EPC", "PRID",
75174a4d8c2SCharles.Forsyth 	"Config", "LLadr", "WatchLo", "WatchHi",
75274a4d8c2SCharles.Forsyth 	"20", "21", "22", "23",
75374a4d8c2SCharles.Forsyth 	"24", "25", "26", "CacheErr",
75474a4d8c2SCharles.Forsyth 	"TagLo", "TagHi", "ErrorEPC", "31"
75574a4d8c2SCharles.Forsyth };
75674a4d8c2SCharles.Forsyth 
75774a4d8c2SCharles.Forsyth static char fsub[16] = {
75874a4d8c2SCharles.Forsyth 	'F', 'D', 'e', 'q', 'W', '?', '?', '?',
75974a4d8c2SCharles.Forsyth 	'?', '?', '?', '?', '?', '?', '?', '?'
76074a4d8c2SCharles.Forsyth };
76174a4d8c2SCharles.Forsyth 
76274a4d8c2SCharles.Forsyth static char *cacheps[] = {
76374a4d8c2SCharles.Forsyth 	"I", "D", "SI", "SD"
76474a4d8c2SCharles.Forsyth };
76574a4d8c2SCharles.Forsyth 
76674a4d8c2SCharles.Forsyth static char *cacheop[] = {
76774a4d8c2SCharles.Forsyth 	"IWBI", "ILT", "IST", "CDE", "HI", "HWBI", "HWB", "HSV"
76874a4d8c2SCharles.Forsyth };
76974a4d8c2SCharles.Forsyth 
77074a4d8c2SCharles.Forsyth static void
format(char * mnemonic,Instr * i,char * f)77174a4d8c2SCharles.Forsyth format(char *mnemonic, Instr *i, char *f)
77274a4d8c2SCharles.Forsyth {
77374a4d8c2SCharles.Forsyth 	if (mnemonic)
77474a4d8c2SCharles.Forsyth 		format(0, i, mnemonic);
77574a4d8c2SCharles.Forsyth 	if (f == 0)
77674a4d8c2SCharles.Forsyth 		return;
77774a4d8c2SCharles.Forsyth 	if (mnemonic)
77874a4d8c2SCharles.Forsyth 		if (i->curr < i->end)
77974a4d8c2SCharles.Forsyth 			*i->curr++ = '\t';
78074a4d8c2SCharles.Forsyth 	for ( ; *f && i->curr < i->end; f++) {
78174a4d8c2SCharles.Forsyth 		if (*f != '%') {
78274a4d8c2SCharles.Forsyth 			*i->curr++ = *f;
78374a4d8c2SCharles.Forsyth 			continue;
78474a4d8c2SCharles.Forsyth 		}
78574a4d8c2SCharles.Forsyth 		switch (*++f) {
78674a4d8c2SCharles.Forsyth 
78774a4d8c2SCharles.Forsyth 		case 's':
78874a4d8c2SCharles.Forsyth 			bprint(i, "%d", i->rs);
78974a4d8c2SCharles.Forsyth 			break;
79074a4d8c2SCharles.Forsyth 
79174a4d8c2SCharles.Forsyth 		case 't':
79274a4d8c2SCharles.Forsyth 			bprint(i, "%d", i->rt);
79374a4d8c2SCharles.Forsyth 			break;
79474a4d8c2SCharles.Forsyth 
79574a4d8c2SCharles.Forsyth 		case 'd':
79674a4d8c2SCharles.Forsyth 			bprint(i, "%d", i->rd);
79774a4d8c2SCharles.Forsyth 			break;
79874a4d8c2SCharles.Forsyth 
79974a4d8c2SCharles.Forsyth 		case 'a':
80074a4d8c2SCharles.Forsyth 			bprint(i, "%d", i->sa);
80174a4d8c2SCharles.Forsyth 			break;
80274a4d8c2SCharles.Forsyth 
80374a4d8c2SCharles.Forsyth 		case 'l':
80474a4d8c2SCharles.Forsyth 			bprint(i, "%lx(R%d)",i->immediate, i->rs);
80574a4d8c2SCharles.Forsyth 			break;
80674a4d8c2SCharles.Forsyth 
80774a4d8c2SCharles.Forsyth 		case 'i':
80874a4d8c2SCharles.Forsyth 			bprint(i, "$%lx", i->immediate);
80974a4d8c2SCharles.Forsyth 			break;
81074a4d8c2SCharles.Forsyth 
81174a4d8c2SCharles.Forsyth 		case 'u':
81274a4d8c2SCharles.Forsyth 			i->curr += symoff(i->curr, i->end-i->curr, i->immediate, CANY);
81374a4d8c2SCharles.Forsyth 			bprint(i, "(SB)");
81474a4d8c2SCharles.Forsyth 			break;
81574a4d8c2SCharles.Forsyth 
81674a4d8c2SCharles.Forsyth 		case 'j':
81774a4d8c2SCharles.Forsyth 			i->curr += symoff(i->curr, i->end-i->curr,
81874a4d8c2SCharles.Forsyth 				(i->target<<2)|(i->addr & 0xF0000000), CANY);
81974a4d8c2SCharles.Forsyth 			bprint(i, "(SB)");
82074a4d8c2SCharles.Forsyth 			break;
82174a4d8c2SCharles.Forsyth 
82274a4d8c2SCharles.Forsyth 		case 'b':
82374a4d8c2SCharles.Forsyth 			i->curr += symoff(i->curr, i->end-i->curr,
82474a4d8c2SCharles.Forsyth 				(i->immediate<<2)+i->addr+4, CANY);
82574a4d8c2SCharles.Forsyth 			break;
82674a4d8c2SCharles.Forsyth 
82774a4d8c2SCharles.Forsyth 		case 'c':
82874a4d8c2SCharles.Forsyth 			bprint(i, "$%lx", i->cofun);
82974a4d8c2SCharles.Forsyth 			break;
83074a4d8c2SCharles.Forsyth 
83174a4d8c2SCharles.Forsyth 		case 'w':
83274a4d8c2SCharles.Forsyth 			bprint(i, "[%lux]", i->w0);
83374a4d8c2SCharles.Forsyth 			break;
83474a4d8c2SCharles.Forsyth 
83574a4d8c2SCharles.Forsyth 		case 'm':
83674a4d8c2SCharles.Forsyth 			bprint(i, "M(%s)", cop0regs[i->rd]);
83774a4d8c2SCharles.Forsyth 			break;
83874a4d8c2SCharles.Forsyth 
83974a4d8c2SCharles.Forsyth 		case 'f':
84074a4d8c2SCharles.Forsyth 			*i->curr++ = fsub[i->rs & 0x0F];
84174a4d8c2SCharles.Forsyth 			break;
84274a4d8c2SCharles.Forsyth 
84374a4d8c2SCharles.Forsyth 		case 'C':
84474a4d8c2SCharles.Forsyth 			bprint(i, "%s%s", cacheps[i->rt & 3], cacheop[(i->rt>>2) & 7]);
84574a4d8c2SCharles.Forsyth 			break;
84674a4d8c2SCharles.Forsyth 
84774a4d8c2SCharles.Forsyth 		case '\0':
84874a4d8c2SCharles.Forsyth 			*i->curr++ = '%';
84974a4d8c2SCharles.Forsyth 			return;
85074a4d8c2SCharles.Forsyth 
85174a4d8c2SCharles.Forsyth 		default:
85274a4d8c2SCharles.Forsyth 			bprint(i, "%%%c", *f);
85374a4d8c2SCharles.Forsyth 			break;
85474a4d8c2SCharles.Forsyth 		}
85574a4d8c2SCharles.Forsyth 	}
85674a4d8c2SCharles.Forsyth 	*i->curr = 0;
85774a4d8c2SCharles.Forsyth }
85874a4d8c2SCharles.Forsyth 
85974a4d8c2SCharles.Forsyth static void
copz(int cop,Instr * i)86074a4d8c2SCharles.Forsyth copz(int cop, Instr *i)
86174a4d8c2SCharles.Forsyth {
86274a4d8c2SCharles.Forsyth 	char *f, *m, buf[16];
86374a4d8c2SCharles.Forsyth 
86474a4d8c2SCharles.Forsyth 	m = buf;
86574a4d8c2SCharles.Forsyth 	f = "%t,%d";
86674a4d8c2SCharles.Forsyth 	switch (i->rs) {
86774a4d8c2SCharles.Forsyth 
86874a4d8c2SCharles.Forsyth 	case 0:
86974a4d8c2SCharles.Forsyth 		sprint(buf, "mfc%d", cop);
87074a4d8c2SCharles.Forsyth 		break;
87174a4d8c2SCharles.Forsyth 
87274a4d8c2SCharles.Forsyth 	case 2:
87374a4d8c2SCharles.Forsyth 		sprint(buf, "cfc%d", cop);
87474a4d8c2SCharles.Forsyth 		break;
87574a4d8c2SCharles.Forsyth 
87674a4d8c2SCharles.Forsyth 	case 4:
87774a4d8c2SCharles.Forsyth 		sprint(buf, "mtc%d", cop);
87874a4d8c2SCharles.Forsyth 		break;
87974a4d8c2SCharles.Forsyth 
88074a4d8c2SCharles.Forsyth 	case 6:
88174a4d8c2SCharles.Forsyth 		sprint(buf, "ctc%d", cop);
88274a4d8c2SCharles.Forsyth 		break;
88374a4d8c2SCharles.Forsyth 
88474a4d8c2SCharles.Forsyth 	case 8:
88574a4d8c2SCharles.Forsyth 		f = "%b";
88674a4d8c2SCharles.Forsyth 		switch (i->rt) {
88774a4d8c2SCharles.Forsyth 
88874a4d8c2SCharles.Forsyth 		case 0:
88974a4d8c2SCharles.Forsyth 			sprint(buf, "bc%df", cop);
89074a4d8c2SCharles.Forsyth 			break;
89174a4d8c2SCharles.Forsyth 
89274a4d8c2SCharles.Forsyth 		case 1:
89374a4d8c2SCharles.Forsyth 			sprint(buf, "bc%dt", cop);
89474a4d8c2SCharles.Forsyth 			break;
89574a4d8c2SCharles.Forsyth 
89674a4d8c2SCharles.Forsyth 		case 2:
89774a4d8c2SCharles.Forsyth 			sprint(buf, "bc%dfl", cop);
89874a4d8c2SCharles.Forsyth 			break;
89974a4d8c2SCharles.Forsyth 
90074a4d8c2SCharles.Forsyth 		case 3:
90174a4d8c2SCharles.Forsyth 			sprint(buf, "bc%dtl", cop);
90274a4d8c2SCharles.Forsyth 			break;
90374a4d8c2SCharles.Forsyth 
90474a4d8c2SCharles.Forsyth 		default:
90574a4d8c2SCharles.Forsyth 			sprint(buf, "cop%d", cop);
90674a4d8c2SCharles.Forsyth 			f = mipscoxxx;
90774a4d8c2SCharles.Forsyth 			break;
90874a4d8c2SCharles.Forsyth 		}
90974a4d8c2SCharles.Forsyth 		break;
91074a4d8c2SCharles.Forsyth 
91174a4d8c2SCharles.Forsyth 	default:
91274a4d8c2SCharles.Forsyth 		sprint(buf, "cop%d", cop);
91374a4d8c2SCharles.Forsyth 		if (i->rs & 0x10)
91474a4d8c2SCharles.Forsyth 			f = "function %c";
91574a4d8c2SCharles.Forsyth 		else
91674a4d8c2SCharles.Forsyth 			f = mipscoxxx;
91774a4d8c2SCharles.Forsyth 		break;
91874a4d8c2SCharles.Forsyth 	}
91974a4d8c2SCharles.Forsyth 	format(m, i, f);
92074a4d8c2SCharles.Forsyth }
92174a4d8c2SCharles.Forsyth 
92274a4d8c2SCharles.Forsyth static void
cop0(Instr * i)92374a4d8c2SCharles.Forsyth cop0(Instr *i)
92474a4d8c2SCharles.Forsyth {
92574a4d8c2SCharles.Forsyth 	char *m = 0;
92674a4d8c2SCharles.Forsyth 
92774a4d8c2SCharles.Forsyth 	if (i->rs < 8) {
92874a4d8c2SCharles.Forsyth 		switch (i->rs) {
92974a4d8c2SCharles.Forsyth 
93074a4d8c2SCharles.Forsyth 		case 0:
93174a4d8c2SCharles.Forsyth 		case 1:
93274a4d8c2SCharles.Forsyth 			format("MOVW", i, "%m,R%t");
93374a4d8c2SCharles.Forsyth 			return;
93474a4d8c2SCharles.Forsyth 
93574a4d8c2SCharles.Forsyth 		case 4:
93674a4d8c2SCharles.Forsyth 		case 5:
93774a4d8c2SCharles.Forsyth 			format("MOVW", i, "R%t,%m");
93874a4d8c2SCharles.Forsyth 			return;
93974a4d8c2SCharles.Forsyth 		}
94074a4d8c2SCharles.Forsyth 	}
94174a4d8c2SCharles.Forsyth 	else if (i->rs >= 0x10) {
94274a4d8c2SCharles.Forsyth 		switch (i->cofun) {
94374a4d8c2SCharles.Forsyth 
94474a4d8c2SCharles.Forsyth 		case 1:
94574a4d8c2SCharles.Forsyth 			m = "TLBR";
94674a4d8c2SCharles.Forsyth 			break;
94774a4d8c2SCharles.Forsyth 
94874a4d8c2SCharles.Forsyth 		case 2:
94974a4d8c2SCharles.Forsyth 			m = "TLBWI";
95074a4d8c2SCharles.Forsyth 			break;
95174a4d8c2SCharles.Forsyth 
95274a4d8c2SCharles.Forsyth 		case 6:
95374a4d8c2SCharles.Forsyth 			m = "TLBWR";
95474a4d8c2SCharles.Forsyth 			break;
95574a4d8c2SCharles.Forsyth 
95674a4d8c2SCharles.Forsyth 		case 8:
95774a4d8c2SCharles.Forsyth 			m = "TLBP";
95874a4d8c2SCharles.Forsyth 			break;
95974a4d8c2SCharles.Forsyth 
96074a4d8c2SCharles.Forsyth 		case 16:
96174a4d8c2SCharles.Forsyth 			m = "RFE";
96274a4d8c2SCharles.Forsyth 			break;
96374a4d8c2SCharles.Forsyth 
96474a4d8c2SCharles.Forsyth 		case 32:
96574a4d8c2SCharles.Forsyth 			m = "ERET";
96674a4d8c2SCharles.Forsyth 			break;
96774a4d8c2SCharles.Forsyth 		}
96874a4d8c2SCharles.Forsyth 		if (m) {
96974a4d8c2SCharles.Forsyth 			format(m, i, 0);
97074a4d8c2SCharles.Forsyth 			return;
97174a4d8c2SCharles.Forsyth 		}
97274a4d8c2SCharles.Forsyth 	}
97374a4d8c2SCharles.Forsyth 	copz(0, i);
97474a4d8c2SCharles.Forsyth }
97574a4d8c2SCharles.Forsyth 
97674a4d8c2SCharles.Forsyth static void
cop1(Instr * i)97774a4d8c2SCharles.Forsyth cop1(Instr *i)
97874a4d8c2SCharles.Forsyth {
97974a4d8c2SCharles.Forsyth 	char *m = "MOVW";
98074a4d8c2SCharles.Forsyth 
98174a4d8c2SCharles.Forsyth 	switch (i->rs) {
98274a4d8c2SCharles.Forsyth 
98374a4d8c2SCharles.Forsyth 	case 0:
98474a4d8c2SCharles.Forsyth 		format(m, i, "F%d,R%t");
98574a4d8c2SCharles.Forsyth 		return;
98674a4d8c2SCharles.Forsyth 
98774a4d8c2SCharles.Forsyth 	case 2:
98874a4d8c2SCharles.Forsyth 		format(m, i, "FCR%d,R%t");
98974a4d8c2SCharles.Forsyth 		return;
99074a4d8c2SCharles.Forsyth 
99174a4d8c2SCharles.Forsyth 	case 4:
99274a4d8c2SCharles.Forsyth 		format(m, i, "R%t,F%d");
99374a4d8c2SCharles.Forsyth 		return;
99474a4d8c2SCharles.Forsyth 
99574a4d8c2SCharles.Forsyth 	case 6:
99674a4d8c2SCharles.Forsyth 		format(m, i, "R%t,FCR%d");
99774a4d8c2SCharles.Forsyth 		return;
99874a4d8c2SCharles.Forsyth 
99974a4d8c2SCharles.Forsyth 	case 8:
100074a4d8c2SCharles.Forsyth 		switch (i->rt) {
100174a4d8c2SCharles.Forsyth 
100274a4d8c2SCharles.Forsyth 		case 0:
100374a4d8c2SCharles.Forsyth 			format("BFPF", i, "%b");
100474a4d8c2SCharles.Forsyth 			return;
100574a4d8c2SCharles.Forsyth 
100674a4d8c2SCharles.Forsyth 		case 1:
100774a4d8c2SCharles.Forsyth 			format("BFPT", i, "%b");
100874a4d8c2SCharles.Forsyth 			return;
100974a4d8c2SCharles.Forsyth 		}
101074a4d8c2SCharles.Forsyth 		break;
101174a4d8c2SCharles.Forsyth 	}
101274a4d8c2SCharles.Forsyth 	copz(1, i);
101374a4d8c2SCharles.Forsyth }
101474a4d8c2SCharles.Forsyth 
101574a4d8c2SCharles.Forsyth static int
printins(Map * map,uvlong pc,char * buf,int n)1016*d67b7dadSforsyth printins(Map *map, uvlong pc, char *buf, int n)
101774a4d8c2SCharles.Forsyth {
101874a4d8c2SCharles.Forsyth 	Instr i;
101974a4d8c2SCharles.Forsyth 	Opcode *o;
102074a4d8c2SCharles.Forsyth 	uchar op;
102174a4d8c2SCharles.Forsyth 
102274a4d8c2SCharles.Forsyth 	i.curr = buf;
102374a4d8c2SCharles.Forsyth 	i.end = buf+n-1;
102474a4d8c2SCharles.Forsyth 	mymap = map;
102574a4d8c2SCharles.Forsyth 	if (mkinstr(pc, &i) < 0)
102674a4d8c2SCharles.Forsyth 		return -1;
102774a4d8c2SCharles.Forsyth 	switch (i.op) {
102874a4d8c2SCharles.Forsyth 
102974a4d8c2SCharles.Forsyth 	case 0x00:					/* SPECIAL */
103074a4d8c2SCharles.Forsyth 		o = sopcodes;
103174a4d8c2SCharles.Forsyth 		op = i.function;
103274a4d8c2SCharles.Forsyth 		break;
103374a4d8c2SCharles.Forsyth 
103474a4d8c2SCharles.Forsyth 	case 0x01:					/* REGIMM */
103574a4d8c2SCharles.Forsyth 		o = ropcodes;
103674a4d8c2SCharles.Forsyth 		op = i.rt;
103774a4d8c2SCharles.Forsyth 		break;
103874a4d8c2SCharles.Forsyth 
103974a4d8c2SCharles.Forsyth 	case 0x10:					/* COP0 */
104074a4d8c2SCharles.Forsyth 		cop0(&i);
104174a4d8c2SCharles.Forsyth 		return i.size*4;
104274a4d8c2SCharles.Forsyth 
104374a4d8c2SCharles.Forsyth 	case 0x11:					/* COP1 */
104474a4d8c2SCharles.Forsyth 		if (i.rs & 0x10) {
104574a4d8c2SCharles.Forsyth 			o = fopcodes;
104674a4d8c2SCharles.Forsyth 			op = i.function;
104774a4d8c2SCharles.Forsyth 			break;
104874a4d8c2SCharles.Forsyth 		}
104974a4d8c2SCharles.Forsyth 		cop1(&i);
105074a4d8c2SCharles.Forsyth 		return i.size*4;
105174a4d8c2SCharles.Forsyth 
105274a4d8c2SCharles.Forsyth 	case 0x12:					/* COP2 */
105374a4d8c2SCharles.Forsyth 	case 0x13:					/* COP3 */
105474a4d8c2SCharles.Forsyth 		copz(i.op-0x10, &i);
105574a4d8c2SCharles.Forsyth 		return i.size*4;
105674a4d8c2SCharles.Forsyth 
105774a4d8c2SCharles.Forsyth 	default:
105874a4d8c2SCharles.Forsyth 		o = opcodes;
105974a4d8c2SCharles.Forsyth 		op = i.op;
106074a4d8c2SCharles.Forsyth 		break;
106174a4d8c2SCharles.Forsyth 	}
106274a4d8c2SCharles.Forsyth 	if (o[op].f)
106374a4d8c2SCharles.Forsyth 		(*o[op].f)(&o[op], &i);
106474a4d8c2SCharles.Forsyth 	else
106574a4d8c2SCharles.Forsyth 		format(o[op].mnemonic, &i, o[op].ken);
106674a4d8c2SCharles.Forsyth 	return i.size*4;
106774a4d8c2SCharles.Forsyth }
106874a4d8c2SCharles.Forsyth 
1069*d67b7dadSforsyth extern	int	_mipscoinst(Map *, uvlong, char*, int);
107074a4d8c2SCharles.Forsyth 
107174a4d8c2SCharles.Forsyth 	/* modifier 'I' toggles the default disassembler type */
1072*d67b7dadSforsyth static int
mipsinst(Map * map,uvlong pc,char modifier,char * buf,int n)1073*d67b7dadSforsyth mipsinst(Map *map, uvlong pc, char modifier, char *buf, int n)
107474a4d8c2SCharles.Forsyth {
107574a4d8c2SCharles.Forsyth 	if ((asstype == AMIPSCO && modifier == 'i')
107674a4d8c2SCharles.Forsyth 		|| (asstype == AMIPS && modifier == 'I'))
107774a4d8c2SCharles.Forsyth 		return _mipscoinst(map, pc, buf, n);
107874a4d8c2SCharles.Forsyth 	else
107974a4d8c2SCharles.Forsyth 		return printins(map, pc, buf, n);
108074a4d8c2SCharles.Forsyth }
108174a4d8c2SCharles.Forsyth 
1082*d67b7dadSforsyth static int
mipsdas(Map * map,uvlong pc,char * buf,int n)1083*d67b7dadSforsyth mipsdas(Map *map, uvlong pc, char *buf, int n)
108474a4d8c2SCharles.Forsyth {
108574a4d8c2SCharles.Forsyth 	Instr i;
108674a4d8c2SCharles.Forsyth 
108774a4d8c2SCharles.Forsyth 	i.curr = buf;
108874a4d8c2SCharles.Forsyth 	i.end = buf+n;
108974a4d8c2SCharles.Forsyth 	mymap = map;
109074a4d8c2SCharles.Forsyth 	if (mkinstr(pc, &i) < 0)
109174a4d8c2SCharles.Forsyth 		return -1;
109274a4d8c2SCharles.Forsyth 	if (i.end-i.curr > 8)
109374a4d8c2SCharles.Forsyth 		i.curr = _hexify(buf, i.w0, 7);
109474a4d8c2SCharles.Forsyth 	if (i.size == 2 && i.end-i.curr > 9) {
109574a4d8c2SCharles.Forsyth 		*i.curr++ = ' ';
109674a4d8c2SCharles.Forsyth 		i.curr = _hexify(i.curr, i.w1, 7);
109774a4d8c2SCharles.Forsyth 	}
109874a4d8c2SCharles.Forsyth 	*i.curr = 0;
109974a4d8c2SCharles.Forsyth 	return i.size*4;
110074a4d8c2SCharles.Forsyth }
110174a4d8c2SCharles.Forsyth 
1102*d67b7dadSforsyth static int
mipsinstlen(Map * map,uvlong pc)1103*d67b7dadSforsyth mipsinstlen(Map *map, uvlong pc)
110474a4d8c2SCharles.Forsyth {
110574a4d8c2SCharles.Forsyth 	Instr i;
110674a4d8c2SCharles.Forsyth 
110774a4d8c2SCharles.Forsyth 	mymap = map;
110874a4d8c2SCharles.Forsyth 	if (mkinstr(pc, &i) < 0)
110974a4d8c2SCharles.Forsyth 		return -1;
111074a4d8c2SCharles.Forsyth 	return i.size*4;
111174a4d8c2SCharles.Forsyth }
111274a4d8c2SCharles.Forsyth 
1113*d67b7dadSforsyth static int
mipsfoll(Map * map,uvlong pc,Rgetter rget,uvlong * foll)1114*d67b7dadSforsyth mipsfoll(Map *map, uvlong pc, Rgetter rget, uvlong *foll)
111574a4d8c2SCharles.Forsyth {
111674a4d8c2SCharles.Forsyth 	ulong w, l;
111774a4d8c2SCharles.Forsyth 	char buf[8];
111874a4d8c2SCharles.Forsyth 	Instr i;
111974a4d8c2SCharles.Forsyth 
112074a4d8c2SCharles.Forsyth 	mymap = map;
112174a4d8c2SCharles.Forsyth 	if (mkinstr(pc, &i) < 0)
112274a4d8c2SCharles.Forsyth 		return -1;
112374a4d8c2SCharles.Forsyth 	w = i.w0;
112474a4d8c2SCharles.Forsyth 	if((w&0xF3600000) == 0x41000000){	/* branch on coprocessor */
112574a4d8c2SCharles.Forsyth     Conditional:
112674a4d8c2SCharles.Forsyth 		foll[0] = pc+8;
112774a4d8c2SCharles.Forsyth 		l = ((w&0xFFFF)<<2);
112874a4d8c2SCharles.Forsyth 		if(w & 0x8000)
112974a4d8c2SCharles.Forsyth 			l |= 0xFFFC0000;
113074a4d8c2SCharles.Forsyth 		foll[1] = pc+4 + l;
113174a4d8c2SCharles.Forsyth 		return 2;
113274a4d8c2SCharles.Forsyth 	}
113374a4d8c2SCharles.Forsyth 
113474a4d8c2SCharles.Forsyth 	l = (w&0xFC000000)>>26;
113574a4d8c2SCharles.Forsyth 	switch(l){
113674a4d8c2SCharles.Forsyth 	case 0:		/* SPECIAL */
113774a4d8c2SCharles.Forsyth 		if((w&0x3E) == 0x08){	/* JR, JALR */
113874a4d8c2SCharles.Forsyth 			sprint(buf, "R%ld", (w>>21)&0x1F);
113974a4d8c2SCharles.Forsyth 			foll[0] = (*rget)(map, buf);
114074a4d8c2SCharles.Forsyth 			return 1;
114174a4d8c2SCharles.Forsyth 		}
114274a4d8c2SCharles.Forsyth 		foll[0] = pc+i.size*4;
114374a4d8c2SCharles.Forsyth 		return 1;
114474a4d8c2SCharles.Forsyth 	case 0x30:	/* Load-Linked followed by NOP, STC */
114574a4d8c2SCharles.Forsyth 		foll[0] = pc+12;
114674a4d8c2SCharles.Forsyth 		return 1;
114774a4d8c2SCharles.Forsyth 	case 1:		/* BCOND */
114874a4d8c2SCharles.Forsyth 	case 4:		/* BEQ */
114974a4d8c2SCharles.Forsyth 	case 20:	/* BEQL */
115074a4d8c2SCharles.Forsyth 	case 5:		/* BNE */
115174a4d8c2SCharles.Forsyth 	case 21:	/* BNEL */
115274a4d8c2SCharles.Forsyth 	case 6:		/* BLEZ */
115374a4d8c2SCharles.Forsyth 	case 22:	/* BLEZL */
115474a4d8c2SCharles.Forsyth 	case 7:		/* BGTZ */
115574a4d8c2SCharles.Forsyth 	case 23:	/* BGTZL */
115674a4d8c2SCharles.Forsyth 		goto Conditional;
115774a4d8c2SCharles.Forsyth 	case 2:		/* J */
115874a4d8c2SCharles.Forsyth 	case 3:		/* JAL */
115974a4d8c2SCharles.Forsyth 		foll[0] = (pc&0xF0000000) | ((w&0x03FFFFFF)<<2);
116074a4d8c2SCharles.Forsyth 		return 1;
116174a4d8c2SCharles.Forsyth 	}
116274a4d8c2SCharles.Forsyth 
116374a4d8c2SCharles.Forsyth 	foll[0] = pc+i.size*4;
116474a4d8c2SCharles.Forsyth 	return 1;
116574a4d8c2SCharles.Forsyth }
1166