xref: /plan9/sys/src/libmach/vdb.c (revision 426f2a32150b219ea919a1d76cbd0c50d6d55686)
1219b2ee8SDavid du Colombier #include <u.h>
2219b2ee8SDavid du Colombier #include <libc.h>
3219b2ee8SDavid du Colombier #include <bio.h>
4219b2ee8SDavid du Colombier #include <mach.h>
5219b2ee8SDavid du Colombier /*
6219b2ee8SDavid du Colombier  * Mips-specific debugger interface
7219b2ee8SDavid du Colombier  */
8219b2ee8SDavid du Colombier 
9219b2ee8SDavid du Colombier static	char	*mipsexcep(Map*, Rgetter);
104de34a7eSDavid du Colombier static	int	mipsfoll(Map*, uvlong, Rgetter, uvlong*);
114de34a7eSDavid du Colombier static	int	mipsinst(Map*, uvlong, char, char*, int);
124de34a7eSDavid du Colombier static	int	mipsdas(Map*, uvlong, char*, int);
134de34a7eSDavid du Colombier static	int	mipsinstlen(Map*, uvlong);
147dd7cddfSDavid du Colombier 
15219b2ee8SDavid du Colombier /*
16219b2ee8SDavid du Colombier  *	Debugger interface
17219b2ee8SDavid du Colombier  */
18219b2ee8SDavid du Colombier Machdata mipsmach =
19219b2ee8SDavid du Colombier {
20219b2ee8SDavid du Colombier 	{0, 0, 0, 0xD},		/* break point */
21219b2ee8SDavid du Colombier 	4,			/* break point size */
22219b2ee8SDavid du Colombier 
23219b2ee8SDavid du Colombier 	beswab,			/* short to local byte order */
24219b2ee8SDavid du Colombier 	beswal,			/* long to local byte order */
257dd7cddfSDavid du Colombier 	beswav,			/* vlong to local byte order */
26219b2ee8SDavid du Colombier 	risctrace,		/* C traceback */
27219b2ee8SDavid du Colombier 	riscframe,		/* Frame finder */
28219b2ee8SDavid du Colombier 	mipsexcep,		/* print exception */
29219b2ee8SDavid du Colombier 	0,			/* breakpoint fixup */
30219b2ee8SDavid du Colombier 	beieeesftos,		/* single precision float printer */
31*426f2a32SDavid du Colombier 	/*
32*426f2a32SDavid du Colombier 	 * this works for doubles in memory, but FP register pairs have
33*426f2a32SDavid du Colombier 	 * the words in little-endian order, so they will print as
34*426f2a32SDavid du Colombier 	 * denormalised doubles.
35*426f2a32SDavid du Colombier 	 */
36*426f2a32SDavid du Colombier 	beieeedftos,		/* double precision float printer */
37219b2ee8SDavid du Colombier 	mipsfoll,		/* following addresses */
38219b2ee8SDavid du Colombier 	mipsinst,		/* print instruction */
39219b2ee8SDavid du Colombier 	mipsdas,		/* dissembler */
40219b2ee8SDavid du Colombier 	mipsinstlen,		/* instruction size */
41219b2ee8SDavid du Colombier };
42219b2ee8SDavid du Colombier 
431a4050f5SDavid du Colombier Machdata mipsmachle =
441a4050f5SDavid du Colombier {
451a4050f5SDavid du Colombier 	{0, 0, 0, 0xD},		/* break point */
461a4050f5SDavid du Colombier 	4,			/* break point size */
471a4050f5SDavid du Colombier 
481a4050f5SDavid du Colombier 	leswab,			/* short to local byte order */
491a4050f5SDavid du Colombier 	leswal,			/* long to local byte order */
501a4050f5SDavid du Colombier 	leswav,			/* vlong to local byte order */
511a4050f5SDavid du Colombier 	risctrace,		/* C traceback */
521a4050f5SDavid du Colombier 	riscframe,		/* Frame finder */
531a4050f5SDavid du Colombier 	mipsexcep,		/* print exception */
541a4050f5SDavid du Colombier 	0,			/* breakpoint fixup */
551a4050f5SDavid du Colombier 	leieeesftos,		/* single precision float printer */
56*426f2a32SDavid du Colombier 	leieeedftos,		/* double precision float printer */
571a4050f5SDavid du Colombier 	mipsfoll,		/* following addresses */
581a4050f5SDavid du Colombier 	mipsinst,		/* print instruction */
591a4050f5SDavid du Colombier 	mipsdas,		/* dissembler */
601a4050f5SDavid du Colombier 	mipsinstlen,		/* instruction size */
611a4050f5SDavid du Colombier };
621a4050f5SDavid du Colombier 
637dd7cddfSDavid du Colombier /*
6459cc4ca5SDavid du Colombier  *	mips r4k little-endian
657dd7cddfSDavid du Colombier  */
667dd7cddfSDavid du Colombier Machdata mipsmach2le =
677dd7cddfSDavid du Colombier {
687dd7cddfSDavid du Colombier 	{0, 0, 0, 0xD},		/* break point */
697dd7cddfSDavid du Colombier 	4,			/* break point size */
707dd7cddfSDavid du Colombier 
717dd7cddfSDavid du Colombier 	leswab,			/* short to local byte order */
727dd7cddfSDavid du Colombier 	leswal,			/* long to local byte order */
737dd7cddfSDavid du Colombier 	leswav,			/* vlong to local byte order */
747dd7cddfSDavid du Colombier 	risctrace,		/* C traceback */
757dd7cddfSDavid du Colombier 	riscframe,		/* Frame finder */
767dd7cddfSDavid du Colombier 	mipsexcep,		/* print exception */
777dd7cddfSDavid du Colombier 	0,			/* breakpoint fixup */
787dd7cddfSDavid du Colombier 	leieeesftos,		/* single precision float printer */
79*426f2a32SDavid du Colombier 	leieeedftos,		/* double precision float printer */
807dd7cddfSDavid du Colombier 	mipsfoll,		/* following addresses */
817dd7cddfSDavid du Colombier 	mipsinst,		/* print instruction */
827dd7cddfSDavid du Colombier 	mipsdas,		/* dissembler */
837dd7cddfSDavid du Colombier 	mipsinstlen,		/* instruction size */
847dd7cddfSDavid du Colombier };
857dd7cddfSDavid du Colombier 
8659cc4ca5SDavid du Colombier /*
8759cc4ca5SDavid du Colombier  *	mips r4k big-endian
8859cc4ca5SDavid du Colombier  */
8959cc4ca5SDavid du Colombier Machdata mipsmach2be =
9059cc4ca5SDavid du Colombier {
9159cc4ca5SDavid du Colombier 	{0, 0, 0, 0xD},		/* break point */
9259cc4ca5SDavid du Colombier 	4,			/* break point size */
9359cc4ca5SDavid du Colombier 
9459cc4ca5SDavid du Colombier 	beswab,			/* short to local byte order */
9559cc4ca5SDavid du Colombier 	beswal,			/* long to local byte order */
9659cc4ca5SDavid du Colombier 	beswav,			/* vlong to local byte order */
9759cc4ca5SDavid du Colombier 	risctrace,		/* C traceback */
9859cc4ca5SDavid du Colombier 	riscframe,		/* Frame finder */
9959cc4ca5SDavid du Colombier 	mipsexcep,		/* print exception */
10059cc4ca5SDavid du Colombier 	0,			/* breakpoint fixup */
10159cc4ca5SDavid du Colombier 	beieeesftos,		/* single precision float printer */
102*426f2a32SDavid du Colombier 	beieeedftos,		/* double precision float printer */
10359cc4ca5SDavid du Colombier 	mipsfoll,		/* following addresses */
10459cc4ca5SDavid du Colombier 	mipsinst,		/* print instruction */
10559cc4ca5SDavid du Colombier 	mipsdas,		/* dissembler */
10659cc4ca5SDavid du Colombier 	mipsinstlen,		/* instruction size */
10759cc4ca5SDavid du Colombier };
10859cc4ca5SDavid du Colombier 
10959cc4ca5SDavid du Colombier 
110219b2ee8SDavid du Colombier static char *excname[] =
111219b2ee8SDavid du Colombier {
112219b2ee8SDavid du Colombier 	"external interrupt",
113219b2ee8SDavid du Colombier 	"TLB modification",
114219b2ee8SDavid du Colombier 	"TLB miss (load or fetch)",
115219b2ee8SDavid du Colombier 	"TLB miss (store)",
116219b2ee8SDavid du Colombier 	"address error (load or fetch)",
117219b2ee8SDavid du Colombier 	"address error (store)",
118219b2ee8SDavid du Colombier 	"bus error (fetch)",
119219b2ee8SDavid du Colombier 	"bus error (data load or store)",
120219b2ee8SDavid du Colombier 	"system call",
121219b2ee8SDavid du Colombier 	"breakpoint",
122219b2ee8SDavid du Colombier 	"reserved instruction",
123219b2ee8SDavid du Colombier 	"coprocessor unusable",
124219b2ee8SDavid du Colombier 	"arithmetic overflow",
125219b2ee8SDavid du Colombier 	"undefined 13",
126219b2ee8SDavid du Colombier 	"undefined 14",
127219b2ee8SDavid du Colombier 	"system call",
128219b2ee8SDavid du Colombier 	/* the following is made up */
129219b2ee8SDavid du Colombier 	"floating point exception"		/* FPEXC */
130219b2ee8SDavid du Colombier };
131219b2ee8SDavid du Colombier 
132219b2ee8SDavid du Colombier static char*
mipsexcep(Map * map,Rgetter rget)133219b2ee8SDavid du Colombier mipsexcep(Map *map, Rgetter rget)
134219b2ee8SDavid du Colombier {
135219b2ee8SDavid du Colombier 	int e;
136219b2ee8SDavid du Colombier 	long c;
137219b2ee8SDavid du Colombier 
138219b2ee8SDavid du Colombier 	c = (*rget)(map, "CAUSE");
1394e3613abSDavid du Colombier 	/* i don't think this applies to any current machines */
1404e3613abSDavid du Colombier 	if(0 && c & 0x00002000)	/* INTR3 */
141219b2ee8SDavid du Colombier 		e = 16;		/* Floating point exception */
142219b2ee8SDavid du Colombier 	else
143219b2ee8SDavid du Colombier 		e = (c>>2)&0x0F;
144219b2ee8SDavid du Colombier 	return excname[e];
145219b2ee8SDavid du Colombier }
146219b2ee8SDavid du Colombier 
147219b2ee8SDavid du Colombier 	/* mips disassembler and related functions */
148219b2ee8SDavid du Colombier 
149219b2ee8SDavid du Colombier static	char FRAMENAME[] = ".frame";
150219b2ee8SDavid du Colombier 
151219b2ee8SDavid du Colombier typedef struct {
1524de34a7eSDavid du Colombier 	uvlong addr;
153219b2ee8SDavid du Colombier 	uchar op;			/* bits 31-26 */
154219b2ee8SDavid du Colombier 	uchar rs;			/* bits 25-21 */
155219b2ee8SDavid du Colombier 	uchar rt;			/* bits 20-16 */
156219b2ee8SDavid du Colombier 	uchar rd;			/* bits 15-11 */
157219b2ee8SDavid du Colombier 	uchar sa;			/* bits 10-6 */
158219b2ee8SDavid du Colombier 	uchar function;			/* bits 5-0 */
159219b2ee8SDavid du Colombier 	long immediate;			/* bits 15-0 */
160219b2ee8SDavid du Colombier 	ulong cofun;			/* bits 24-0 */
161219b2ee8SDavid du Colombier 	ulong target;			/* bits 25-0 */
162219b2ee8SDavid du Colombier 	long w0;
163219b2ee8SDavid du Colombier 	long w1;
164219b2ee8SDavid du Colombier 	int size;			/* instruction size */
165219b2ee8SDavid du Colombier 	char *curr;			/* fill point in buffer */
166219b2ee8SDavid du Colombier 	char *end;			/* end of buffer */
167219b2ee8SDavid du Colombier 	char *err;			/* error message */
168219b2ee8SDavid du Colombier } Instr;
169219b2ee8SDavid du Colombier 
170219b2ee8SDavid du Colombier static Map *mymap;
171219b2ee8SDavid du Colombier 
172219b2ee8SDavid du Colombier static int
decode(uvlong pc,Instr * i)1734de34a7eSDavid du Colombier decode(uvlong pc, Instr *i)
174219b2ee8SDavid du Colombier {
1754de34a7eSDavid du Colombier 	ulong w;
176219b2ee8SDavid du Colombier 
177219b2ee8SDavid du Colombier 	if (get4(mymap, pc, &w) < 0) {
178219b2ee8SDavid du Colombier 		werrstr("can't read instruction: %r");
179219b2ee8SDavid du Colombier 		return -1;
180219b2ee8SDavid du Colombier 	}
1817dd7cddfSDavid du Colombier 
182219b2ee8SDavid du Colombier 	i->addr = pc;
183219b2ee8SDavid du Colombier 	i->size = 1;
184219b2ee8SDavid du Colombier 	i->op = (w >> 26) & 0x3F;
185219b2ee8SDavid du Colombier 	i->rs = (w >> 21) & 0x1F;
186219b2ee8SDavid du Colombier 	i->rt = (w >> 16) & 0x1F;
187219b2ee8SDavid du Colombier 	i->rd = (w >> 11) & 0x1F;
188219b2ee8SDavid du Colombier 	i->sa = (w >> 6) & 0x1F;
189219b2ee8SDavid du Colombier 	i->function = w & 0x3F;
190219b2ee8SDavid du Colombier 	i->immediate = w & 0x0000FFFF;
191219b2ee8SDavid du Colombier 	if (i->immediate & 0x8000)
192219b2ee8SDavid du Colombier 		i->immediate |= ~0x0000FFFF;
193219b2ee8SDavid du Colombier 	i->cofun = w & 0x01FFFFFF;
194219b2ee8SDavid du Colombier 	i->target = w & 0x03FFFFFF;
195219b2ee8SDavid du Colombier 	i->w0 = w;
196219b2ee8SDavid du Colombier 	return 1;
197219b2ee8SDavid du Colombier }
198219b2ee8SDavid du Colombier 
199219b2ee8SDavid du Colombier static int
mkinstr(uvlong pc,Instr * i)2004de34a7eSDavid du Colombier mkinstr(uvlong pc, Instr *i)
201219b2ee8SDavid du Colombier {
202219b2ee8SDavid du Colombier 	Instr x;
203219b2ee8SDavid du Colombier 
204219b2ee8SDavid du Colombier 	if (decode(pc, i) < 0)
205219b2ee8SDavid du Colombier 		return -1;
206219b2ee8SDavid du Colombier 	/*
207219b2ee8SDavid du Colombier 	 * if it's a LUI followed by an ORI,
208219b2ee8SDavid du Colombier 	 * it's an immediate load of a large constant.
209219b2ee8SDavid du Colombier 	 * fix the LUI immediate in any case.
210219b2ee8SDavid du Colombier 	 */
211219b2ee8SDavid du Colombier 	if (i->op == 0x0F) {
212219b2ee8SDavid du Colombier 		if (decode(pc+4, &x) < 0)
213219b2ee8SDavid du Colombier 			return 0;
214219b2ee8SDavid du Colombier 		i->immediate <<= 16;
215219b2ee8SDavid du Colombier 		if (x.op == 0x0D && x.rs == x.rt && x.rt == i->rt) {
216219b2ee8SDavid du Colombier 			i->immediate |= (x.immediate & 0xFFFF);
217219b2ee8SDavid du Colombier 			i->w1 = x.w0;
218219b2ee8SDavid du Colombier 			i->size++;
219219b2ee8SDavid du Colombier 			return 1;
220219b2ee8SDavid du Colombier 		}
221219b2ee8SDavid du Colombier 	}
222219b2ee8SDavid du Colombier 	/*
223219b2ee8SDavid du Colombier 	 * if it's a LWC1 followed by another LWC1
224219b2ee8SDavid du Colombier 	 * into an adjacent register, it's a load of
225219b2ee8SDavid du Colombier 	 * a floating point double.
226219b2ee8SDavid du Colombier 	 */
227219b2ee8SDavid du Colombier 	else if (i->op == 0x31 && (i->rt & 0x01)) {
228219b2ee8SDavid du Colombier 		if (decode(pc+4, &x) < 0)
229219b2ee8SDavid du Colombier 			return 0;
230219b2ee8SDavid du Colombier 		if (x.op == 0x31 && x.rt == (i->rt - 1) && x.rs == i->rs) {
231219b2ee8SDavid du Colombier 			i->rt -= 1;
232219b2ee8SDavid du Colombier 			i->w1 = x.w0;
233219b2ee8SDavid du Colombier 			i->size++;
234219b2ee8SDavid du Colombier 			return 1;
235219b2ee8SDavid du Colombier 		}
236219b2ee8SDavid du Colombier 	}
237219b2ee8SDavid du Colombier 	/*
238219b2ee8SDavid du Colombier 	 * similarly for double stores
239219b2ee8SDavid du Colombier 	 */
240219b2ee8SDavid du Colombier 	else if (i->op == 0x39 && (i->rt & 0x01)) {
241219b2ee8SDavid du Colombier 		if (decode(pc+4, &x) < 0)
242219b2ee8SDavid du Colombier 			return 0;
243219b2ee8SDavid du Colombier 		if (x.op == 0x39 && x.rt == (i->rt - 1) && x.rs == i->rs) {
244219b2ee8SDavid du Colombier 			i->rt -= 1;
245219b2ee8SDavid du Colombier 			i->w1 = x.w0;
246219b2ee8SDavid du Colombier 			i->size++;
247219b2ee8SDavid du Colombier 		}
248219b2ee8SDavid du Colombier 	}
249219b2ee8SDavid du Colombier 	return 1;
250219b2ee8SDavid du Colombier }
251219b2ee8SDavid du Colombier 
2521bd28109SDavid du Colombier #pragma	varargck	argpos	bprint		2
2531bd28109SDavid du Colombier 
254219b2ee8SDavid du Colombier static void
bprint(Instr * i,char * fmt,...)255219b2ee8SDavid du Colombier bprint(Instr *i, char *fmt, ...)
256219b2ee8SDavid du Colombier {
2577dd7cddfSDavid du Colombier 	va_list arg;
2587dd7cddfSDavid du Colombier 
2597dd7cddfSDavid du Colombier 	va_start(arg, fmt);
2609a747e4fSDavid du Colombier 	i->curr = vseprint(i->curr, i->end, fmt, arg);
2617dd7cddfSDavid du Colombier 	va_end(arg);
262219b2ee8SDavid du Colombier }
263219b2ee8SDavid du Colombier 
264219b2ee8SDavid du Colombier typedef struct Opcode Opcode;
265219b2ee8SDavid du Colombier 
266219b2ee8SDavid du Colombier struct Opcode {
267219b2ee8SDavid du Colombier 	char *mnemonic;
268219b2ee8SDavid du Colombier 	void (*f)(Opcode *, Instr *);
269219b2ee8SDavid du Colombier 	char *ken;
270219b2ee8SDavid du Colombier };
271219b2ee8SDavid du Colombier 
272219b2ee8SDavid du Colombier static void format(char *, Instr *, char *);
273219b2ee8SDavid du Colombier 
274219b2ee8SDavid du Colombier static void
branch(Opcode * o,Instr * i)275219b2ee8SDavid du Colombier branch(Opcode *o, Instr *i)
276219b2ee8SDavid du Colombier {
277219b2ee8SDavid du Colombier 	if (i->rs == 0 && i->rt == 0)
278219b2ee8SDavid du Colombier 		format("JMP", i, "%b");
279219b2ee8SDavid du Colombier 	else if (i->rs == 0)
280219b2ee8SDavid du Colombier 		format(o->mnemonic, i, "R%t,%b");
281219b2ee8SDavid du Colombier 	else if (i->rt < 2)
282219b2ee8SDavid du Colombier 		format(o->mnemonic, i, "R%s,%b");
283219b2ee8SDavid du Colombier 	else
284219b2ee8SDavid du Colombier 		format(o->mnemonic, i, "R%s,R%t,%b");
285219b2ee8SDavid du Colombier }
286219b2ee8SDavid du Colombier 
287219b2ee8SDavid du Colombier static void
addi(Opcode * o,Instr * i)288219b2ee8SDavid du Colombier addi(Opcode *o, Instr *i)
289219b2ee8SDavid du Colombier {
290219b2ee8SDavid du Colombier 	if (i->rs == i->rt)
291219b2ee8SDavid du Colombier 		format(o->mnemonic, i, "%i,R%t");
292219b2ee8SDavid du Colombier 	else if (i->rs == 0)
293219b2ee8SDavid du Colombier 		format("MOVW", i, "%i,R%t");
294219b2ee8SDavid du Colombier 	else if (i->rs == 30) {
295219b2ee8SDavid du Colombier 		bprint(i, "MOVW\t$");
296219b2ee8SDavid du Colombier 		i->curr += symoff(i->curr, i->end-i->curr,
297219b2ee8SDavid du Colombier 					i->immediate+mach->sb, CANY);
298219b2ee8SDavid du Colombier 		bprint(i, "(SB),R%d", i->rt);
299219b2ee8SDavid du Colombier 	}
300219b2ee8SDavid du Colombier 	else
301219b2ee8SDavid du Colombier 		format(o->mnemonic, i, o->ken);
302219b2ee8SDavid du Colombier }
303219b2ee8SDavid du Colombier 
304219b2ee8SDavid du Colombier static void
andi(Opcode * o,Instr * i)305219b2ee8SDavid du Colombier andi(Opcode *o, Instr *i)
306219b2ee8SDavid du Colombier {
307219b2ee8SDavid du Colombier 	if (i->rs == i->rt)
308219b2ee8SDavid du Colombier 		format(o->mnemonic, i, "%i,R%t");
309219b2ee8SDavid du Colombier 	else
310219b2ee8SDavid du Colombier 		format(o->mnemonic, i, o->ken);
311219b2ee8SDavid du Colombier }
312219b2ee8SDavid du Colombier 
313219b2ee8SDavid du Colombier static int
plocal(Instr * i,char * m,char r,int store)314219b2ee8SDavid du Colombier plocal(Instr *i, char *m, char r, int store)
315219b2ee8SDavid du Colombier {
316219b2ee8SDavid du Colombier 	int offset;
317219b2ee8SDavid du Colombier 	char *reg;
318219b2ee8SDavid du Colombier 	Symbol s;
319219b2ee8SDavid du Colombier 
320219b2ee8SDavid du Colombier 	if (!findsym(i->addr, CTEXT, &s) || !findlocal(&s, FRAMENAME, &s))
321219b2ee8SDavid du Colombier 		return 0;
322219b2ee8SDavid du Colombier 	if (s.value > i->immediate) {
323219b2ee8SDavid du Colombier 		if(!getauto(&s, s.value-i->immediate, CAUTO, &s))
324219b2ee8SDavid du Colombier 			return 0;
325219b2ee8SDavid du Colombier 		reg = "(SP)";
326219b2ee8SDavid du Colombier 		offset = i->immediate;
327219b2ee8SDavid du Colombier 	} else {
328219b2ee8SDavid du Colombier 		offset = i->immediate-s.value;
329219b2ee8SDavid du Colombier 		if (!getauto(&s, offset-4, CPARAM, &s))
330219b2ee8SDavid du Colombier 			return 0;
331219b2ee8SDavid du Colombier 		reg = "(FP)";
332219b2ee8SDavid du Colombier 	}
333219b2ee8SDavid du Colombier 	if (store)
334219b2ee8SDavid du Colombier 		bprint(i, "%s\t%c%d,%s+%d%s", m, r, i->rt, s.name, offset, reg);
335219b2ee8SDavid du Colombier 	else
336219b2ee8SDavid du Colombier 		bprint(i, "%s\t%s+%d%s,%c%d", m, s.name, offset, reg, r, i->rt);
337219b2ee8SDavid du Colombier 	return 1;
338219b2ee8SDavid du Colombier }
339219b2ee8SDavid du Colombier 
340219b2ee8SDavid du Colombier static void
lw(Opcode * o,Instr * i,char r)341219b2ee8SDavid du Colombier lw(Opcode *o, Instr *i, char r)
342219b2ee8SDavid du Colombier {
343219b2ee8SDavid du Colombier 	char *m;
344219b2ee8SDavid du Colombier 
345219b2ee8SDavid du Colombier 	if (r == 'F') {
346219b2ee8SDavid du Colombier 		if (i->size == 2)
347219b2ee8SDavid du Colombier 			m = "MOVD";
348219b2ee8SDavid du Colombier 		else
349219b2ee8SDavid du Colombier 			m = "MOVF";
350219b2ee8SDavid du Colombier 	}
351219b2ee8SDavid du Colombier 	else
352219b2ee8SDavid du Colombier 		m = o->mnemonic;
353219b2ee8SDavid du Colombier 	if (i->rs == 29 && plocal(i, m, r, 0))
354219b2ee8SDavid du Colombier 			return;
355219b2ee8SDavid du Colombier 
356219b2ee8SDavid du Colombier 	if (i->rs == 30 && mach->sb) {
357219b2ee8SDavid du Colombier 		bprint(i, "%s\t", m);
358219b2ee8SDavid du Colombier 		i->curr += symoff(i->curr, i->end-i->curr, i->immediate+mach->sb, CANY);
359219b2ee8SDavid du Colombier 		bprint(i, "(SB),%c%d", r, i->rt);
360219b2ee8SDavid du Colombier 		return;
361219b2ee8SDavid du Colombier 	}
362219b2ee8SDavid du Colombier 	if (r == 'F')
363219b2ee8SDavid du Colombier 		format(m, i, "%l,F%t");
364219b2ee8SDavid du Colombier 	else
365219b2ee8SDavid du Colombier 		format(m, i, o->ken);
366219b2ee8SDavid du Colombier }
367219b2ee8SDavid du Colombier 
368219b2ee8SDavid du Colombier static void
load(Opcode * o,Instr * i)369219b2ee8SDavid du Colombier load(Opcode *o, Instr *i)
370219b2ee8SDavid du Colombier {
371219b2ee8SDavid du Colombier 	lw(o, i, 'R');
372219b2ee8SDavid du Colombier }
373219b2ee8SDavid du Colombier 
374219b2ee8SDavid du Colombier static void
lwc1(Opcode * o,Instr * i)375219b2ee8SDavid du Colombier lwc1(Opcode *o, Instr *i)
376219b2ee8SDavid du Colombier {
377219b2ee8SDavid du Colombier 	lw(o, i, 'F');
378219b2ee8SDavid du Colombier }
379219b2ee8SDavid du Colombier 
380219b2ee8SDavid du Colombier static void
sw(Opcode * o,Instr * i,char r)381219b2ee8SDavid du Colombier sw(Opcode *o, Instr *i, char r)
382219b2ee8SDavid du Colombier {
383219b2ee8SDavid du Colombier 	char *m;
384219b2ee8SDavid du Colombier 
385219b2ee8SDavid du Colombier 	if (r == 'F') {
386219b2ee8SDavid du Colombier 		if (i->size == 2)
387219b2ee8SDavid du Colombier 			m = "MOVD";
388219b2ee8SDavid du Colombier 		else
389219b2ee8SDavid du Colombier 			m = "MOVF";
390219b2ee8SDavid du Colombier 	}
391219b2ee8SDavid du Colombier 	else
392219b2ee8SDavid du Colombier 		m = o->mnemonic;
393219b2ee8SDavid du Colombier 	if (i->rs == 29 && plocal(i, m, r, 1))
394219b2ee8SDavid du Colombier 			return;
395219b2ee8SDavid du Colombier 
396219b2ee8SDavid du Colombier 	if (i->rs == 30 && mach->sb) {
397219b2ee8SDavid du Colombier 		bprint(i, "%s\t%c%d,", m, r, i->rt);
398219b2ee8SDavid du Colombier 		i->curr += symoff(i->curr, i->end-i->curr, i->immediate+mach->sb, CANY);
399219b2ee8SDavid du Colombier 		bprint(i, "(SB)");
400219b2ee8SDavid du Colombier 		return;
401219b2ee8SDavid du Colombier 	}
402219b2ee8SDavid du Colombier 	if (r == 'F')
403219b2ee8SDavid du Colombier 		format(m, i, "F%t,%l");
404219b2ee8SDavid du Colombier 	else
405219b2ee8SDavid du Colombier 		format(m, i, o->ken);
406219b2ee8SDavid du Colombier }
407219b2ee8SDavid du Colombier 
408219b2ee8SDavid du Colombier static void
store(Opcode * o,Instr * i)409219b2ee8SDavid du Colombier store(Opcode *o, Instr *i)
410219b2ee8SDavid du Colombier {
411219b2ee8SDavid du Colombier 	sw(o, i, 'R');
412219b2ee8SDavid du Colombier }
413219b2ee8SDavid du Colombier 
414219b2ee8SDavid du Colombier static void
swc1(Opcode * o,Instr * i)415219b2ee8SDavid du Colombier swc1(Opcode *o, Instr *i)
416219b2ee8SDavid du Colombier {
417219b2ee8SDavid du Colombier 	sw(o, i, 'F');
418219b2ee8SDavid du Colombier }
419219b2ee8SDavid du Colombier 
420219b2ee8SDavid du Colombier static void
sll(Opcode * o,Instr * i)421219b2ee8SDavid du Colombier sll(Opcode *o, Instr *i)
422219b2ee8SDavid du Colombier {
423219b2ee8SDavid du Colombier 	if (i->w0 == 0)
424eaba85aaSDavid du Colombier 		bprint(i, "NOOP");		/* unofficial nop */
425eaba85aaSDavid du Colombier 	else if (i->w0 == 0xc0)			/* 0xc0: SLL $3,R0 */
426eaba85aaSDavid du Colombier 		bprint(i, "EHB");
427219b2ee8SDavid du Colombier 	else if (i->rd == i->rt)
428219b2ee8SDavid du Colombier 		format(o->mnemonic, i, "$%a,R%d");
429219b2ee8SDavid du Colombier 	else
430219b2ee8SDavid du Colombier 		format(o->mnemonic, i, o->ken);
431219b2ee8SDavid du Colombier }
432219b2ee8SDavid du Colombier 
433219b2ee8SDavid du Colombier static void
sl32(Opcode * o,Instr * i)434219b2ee8SDavid du Colombier sl32(Opcode *o, Instr *i)
435219b2ee8SDavid du Colombier {
436219b2ee8SDavid du Colombier 	i->sa += 32;
437219b2ee8SDavid du Colombier 	if (i->rd == i->rt)
438219b2ee8SDavid du Colombier 		format(o->mnemonic, i, "$%a,R%d");
439219b2ee8SDavid du Colombier 	else
440219b2ee8SDavid du Colombier 		format(o->mnemonic, i, o->ken);
441219b2ee8SDavid du Colombier }
442219b2ee8SDavid du Colombier 
443219b2ee8SDavid du Colombier static void
sllv(Opcode * o,Instr * i)444219b2ee8SDavid du Colombier sllv(Opcode *o, Instr *i)
445219b2ee8SDavid du Colombier {
446219b2ee8SDavid du Colombier 	if (i->rd == i->rt)
447219b2ee8SDavid du Colombier 		format(o->mnemonic, i, "R%s,R%d");
448219b2ee8SDavid du Colombier 	else
449219b2ee8SDavid du Colombier 		format(o->mnemonic, i, o->ken);
450219b2ee8SDavid du Colombier }
451219b2ee8SDavid du Colombier 
452219b2ee8SDavid du Colombier static void
jal(Opcode * o,Instr * i)453219b2ee8SDavid du Colombier jal(Opcode *o, Instr *i)
454219b2ee8SDavid du Colombier {
455219b2ee8SDavid du Colombier 	if (i->rd == 31)
456219b2ee8SDavid du Colombier 		format("JAL", i, "(R%s)");
457219b2ee8SDavid du Colombier 	else
458219b2ee8SDavid du Colombier 		format(o->mnemonic, i, o->ken);
459219b2ee8SDavid du Colombier }
460219b2ee8SDavid du Colombier 
461219b2ee8SDavid du Colombier static void
add(Opcode * o,Instr * i)462219b2ee8SDavid du Colombier add(Opcode *o, Instr *i)
463219b2ee8SDavid du Colombier {
464219b2ee8SDavid du Colombier 	if (i->rd == i->rs)
465219b2ee8SDavid du Colombier 		format(o->mnemonic, i, "R%t,R%d");
466219b2ee8SDavid du Colombier 	else if (i->rd == i->rt)
467219b2ee8SDavid du Colombier 		format(o->mnemonic, i, "R%s,R%d");
468219b2ee8SDavid du Colombier 	else
469219b2ee8SDavid du Colombier 		format(o->mnemonic, i, o->ken);
470219b2ee8SDavid du Colombier }
471219b2ee8SDavid du Colombier 
472219b2ee8SDavid du Colombier static void
sub(Opcode * o,Instr * i)473219b2ee8SDavid du Colombier sub(Opcode *o, Instr *i)
474219b2ee8SDavid du Colombier {
475219b2ee8SDavid du Colombier 	if (i->rd == i->rs)
476219b2ee8SDavid du Colombier 		format(o->mnemonic, i, "R%t,R%d");
477219b2ee8SDavid du Colombier 	else
478219b2ee8SDavid du Colombier 		format(o->mnemonic, i, o->ken);
479219b2ee8SDavid du Colombier }
480219b2ee8SDavid du Colombier 
481219b2ee8SDavid du Colombier static void
or(Opcode * o,Instr * i)482219b2ee8SDavid du Colombier or(Opcode *o, Instr *i)
483219b2ee8SDavid du Colombier {
484219b2ee8SDavid du Colombier 	if (i->rs == 0 && i->rt == 0)
485219b2ee8SDavid du Colombier 		format("MOVW", i, "$0,R%d");
486219b2ee8SDavid du Colombier 	else if (i->rs == 0)
487219b2ee8SDavid du Colombier 		format("MOVW", i, "R%t,R%d");
488219b2ee8SDavid du Colombier 	else if (i->rt == 0)
489219b2ee8SDavid du Colombier 		format("MOVW", i, "R%s,R%d");
490219b2ee8SDavid du Colombier 	else
491219b2ee8SDavid du Colombier 		add(o, i);
492219b2ee8SDavid du Colombier }
493219b2ee8SDavid du Colombier 
494219b2ee8SDavid du Colombier static void
nor(Opcode * o,Instr * i)495219b2ee8SDavid du Colombier nor(Opcode *o, Instr *i)
496219b2ee8SDavid du Colombier {
497219b2ee8SDavid du Colombier 	if (i->rs == 0 && i->rt == 0 && i->rd == 0)
498219b2ee8SDavid du Colombier 		format("NOP", i, 0);
499219b2ee8SDavid du Colombier 	else
500219b2ee8SDavid du Colombier 		add(o, i);
501219b2ee8SDavid du Colombier }
502219b2ee8SDavid du Colombier 
503219b2ee8SDavid du Colombier static char mipscoload[] = "r%t,%l";
504219b2ee8SDavid du Colombier static char mipsload[] = "%l,R%t";
505219b2ee8SDavid du Colombier static char mipsstore[] = "R%t,%l";
506219b2ee8SDavid du Colombier static char mipsalui[] = "%i,R%s,R%t";
507219b2ee8SDavid du Colombier static char mipsalu3op[] = "R%t,R%s,R%d";
508219b2ee8SDavid du Colombier static char mipsrtrs[] = "R%t,R%s";
509219b2ee8SDavid du Colombier static char mipscorsrt[] = "r%s,r%t";
510219b2ee8SDavid du Colombier static char mipscorsi[] = "r%s,%i";
511219b2ee8SDavid du Colombier static char mipscoxxx[] = "%w";
512219b2ee8SDavid du Colombier static char mipscofp3[] = "f%a,f%d,f%t";	/* fd,fs,ft */
513219b2ee8SDavid du Colombier static char mipsfp3[] = "F%t,F%d,F%a";
514219b2ee8SDavid du Colombier static char mipscofp2[] = "f%a,f%d";		/* fd,fs */
515219b2ee8SDavid du Colombier static char mipsfp2[] = "F%d,F%a";
516219b2ee8SDavid du Colombier static char mipscofpc[] = "f%d,f%t";		/* fs,ft */
517219b2ee8SDavid du Colombier static char mipsfpc[] = "F%t,F%d";
518219b2ee8SDavid du Colombier 
519219b2ee8SDavid du Colombier static Opcode opcodes[64] = {
520219b2ee8SDavid du Colombier 	0,		0,	0,
521219b2ee8SDavid du Colombier 	0,		0,	0,
522219b2ee8SDavid du Colombier 	"JMP",		0,	"%j",
523219b2ee8SDavid du Colombier 	"JAL",		0,	"%j",
524219b2ee8SDavid du Colombier 	"BEQ",	   branch,	0,
525219b2ee8SDavid du Colombier 	"BNE",	   branch,	0,
526219b2ee8SDavid du Colombier 	"BLEZ",	   branch,	0,
527219b2ee8SDavid du Colombier 	"BGTZ",	   branch,	0,
528219b2ee8SDavid du Colombier 	"ADD",	     addi,	mipsalui,
529219b2ee8SDavid du Colombier 	"ADDU",	     addi,	mipsalui,
530219b2ee8SDavid du Colombier 	"SGT",		0,	mipsalui,
531219b2ee8SDavid du Colombier 	"SGTU",		0,	mipsalui,
532219b2ee8SDavid du Colombier 	"AND",	     andi,	mipsalui,
533219b2ee8SDavid du Colombier 	"OR",	     andi,	mipsalui,
534219b2ee8SDavid du Colombier 	"XOR",	     andi,	mipsalui,
535219b2ee8SDavid du Colombier 	"MOVW",		0,	"$%u,R%t",
536219b2ee8SDavid du Colombier 	"cop0",		0,	0,
537219b2ee8SDavid du Colombier 	"cop1",		0,	0,
538219b2ee8SDavid du Colombier 	"cop2",		0,	0,
539219b2ee8SDavid du Colombier 	"cop3",		0,	0,
540219b2ee8SDavid du Colombier 	"BEQL",	   branch,	0,
541219b2ee8SDavid du Colombier 	"BNEL",	   branch,	0,
542219b2ee8SDavid du Colombier 	"BLEZL",   branch,	0,
543219b2ee8SDavid du Colombier 	"BGTZL",   branch,	0,
544219b2ee8SDavid du Colombier 	"instr18",	0,	mipscoxxx,
545219b2ee8SDavid du Colombier 	"instr19",	0,	mipscoxxx,
546219b2ee8SDavid du Colombier 	"MOVVL",     load,	mipsload,
547219b2ee8SDavid du Colombier 	"MOVVR",     load,	mipsload,
548219b2ee8SDavid du Colombier 	"instr1C",	0,	mipscoxxx,
549219b2ee8SDavid du Colombier 	"instr1D",	0,	mipscoxxx,
550219b2ee8SDavid du Colombier 	"instr1E",	0,	mipscoxxx,
551219b2ee8SDavid du Colombier 	"instr1F",	0,	mipscoxxx,
552219b2ee8SDavid du Colombier 	"MOVB",	     load,	mipsload,
553219b2ee8SDavid du Colombier 	"MOVH",	     load,	mipsload,
554219b2ee8SDavid du Colombier 	"lwl",		0,	mipscoload,
555219b2ee8SDavid du Colombier 	"MOVW",	     load,	mipsload,
556219b2ee8SDavid du Colombier 	"MOVBU",     load,	mipsload,
557219b2ee8SDavid du Colombier 	"MOVHU",     load,	mipsload,
558219b2ee8SDavid du Colombier 	"lwr",		0,	mipscoload,
559219b2ee8SDavid du Colombier 	"instr27",	0,	mipscoxxx,
560219b2ee8SDavid du Colombier 	"MOVB",	    store,	mipsstore,
561219b2ee8SDavid du Colombier 	"MOVH",	    store,	mipsstore,
562219b2ee8SDavid du Colombier 	"swl",		0,	mipscoload,
563219b2ee8SDavid du Colombier 	"MOVW",	    store,	mipsstore,
564219b2ee8SDavid du Colombier 	"MOVVL",    store,	mipsstore,
565219b2ee8SDavid du Colombier 	"MOVVR",    store,	mipsstore,
566219b2ee8SDavid du Colombier 	"swr",		0,	mipscoload,
567219b2ee8SDavid du Colombier 	"CACHE",	0,	"%C,%l",
568219b2ee8SDavid du Colombier 	"ll",		0,	mipscoload,
569219b2ee8SDavid du Colombier 	"MOVW",	     lwc1,	mipscoload,
570219b2ee8SDavid du Colombier 	"lwc2",		0,	mipscoload,
571219b2ee8SDavid du Colombier 	"lwc3",		0,	mipscoload,
572219b2ee8SDavid du Colombier 	"instr34",	0,	mipscoxxx,
573219b2ee8SDavid du Colombier 	"ldc1",		0,	mipscoload,
574219b2ee8SDavid du Colombier 	"ldc2",		0,	mipscoload,
575219b2ee8SDavid du Colombier 	"MOVV",	    load,	mipsload,
576219b2ee8SDavid du Colombier 	"sc",		0,	mipscoload,
577219b2ee8SDavid du Colombier 	"swc1",	     swc1,	mipscoload,
578219b2ee8SDavid du Colombier 	"swc2",		0,	mipscoload,
579219b2ee8SDavid du Colombier 	"swc3",		0,	mipscoload,
580219b2ee8SDavid du Colombier 	"instr3C",	0,	mipscoxxx,
581219b2ee8SDavid du Colombier 	"sdc1",		0,	mipscoload,
582219b2ee8SDavid du Colombier 	"sdc2",		0,	mipscoload,
583219b2ee8SDavid du Colombier 	"MOVV",	    store,	mipsstore,
584219b2ee8SDavid du Colombier };
585219b2ee8SDavid du Colombier 
586219b2ee8SDavid du Colombier static Opcode sopcodes[64] = {
587219b2ee8SDavid du Colombier 	"SLL",	      sll,	"$%a,R%t,R%d",
588219b2ee8SDavid du Colombier 	"special01",	0,	mipscoxxx,
589219b2ee8SDavid du Colombier 	"SRL",	      sll,	"$%a,R%t,R%d",
590219b2ee8SDavid du Colombier 	"SRA",	      sll,	"$%a,R%t,R%d",
591219b2ee8SDavid du Colombier 	"SLL",	     sllv,	"R%s,R%t,R%d",
592219b2ee8SDavid du Colombier 	"special05",	0,	mipscoxxx,
593219b2ee8SDavid du Colombier 	"SRL",	     sllv,	"R%s,R%t,R%d",
594219b2ee8SDavid du Colombier 	"SRA",	     sllv,	"R%s,R%t,R%d",
595219b2ee8SDavid du Colombier 	"JMP",		0,	"(R%s)",
596219b2ee8SDavid du Colombier 	"jal",	      jal,	"r%d,r%s",
597219b2ee8SDavid du Colombier 	"special0A",	0,	mipscoxxx,
598219b2ee8SDavid du Colombier 	"special0B",	0,	mipscoxxx,
599219b2ee8SDavid du Colombier 	"SYSCALL",	0,	0,
600219b2ee8SDavid du Colombier 	"BREAK",	0,	0,
601219b2ee8SDavid du Colombier 	"special0E",	0,	mipscoxxx,
602219b2ee8SDavid du Colombier 	"SYNC",		0,	0,
603219b2ee8SDavid du Colombier 	"MOVW",		0,	"HI,R%d",
604219b2ee8SDavid du Colombier 	"MOVW",		0,	"R%s,HI",
605219b2ee8SDavid du Colombier 	"MOVW",		0,	"LO,R%d",
606219b2ee8SDavid du Colombier 	"MOVW",		0,	"R%s,LO",
607219b2ee8SDavid du Colombier 	"SLLV",	     sllv,	"R%s,R%t,R%d",
608219b2ee8SDavid du Colombier 	"special15",	0,	mipscoxxx,
609219b2ee8SDavid du Colombier 	"SRLV",	     sllv,	"R%s,R%t,R%d",
610219b2ee8SDavid du Colombier 	"SRAV",	     sllv,	"R%s,R%t,R%d",
611219b2ee8SDavid du Colombier 	"MUL",		0,	mipsrtrs,
612219b2ee8SDavid du Colombier 	"MULU",		0,	mipsrtrs,
613219b2ee8SDavid du Colombier 	"DIV",		0,	mipsrtrs,
614219b2ee8SDavid du Colombier 	"DIVU",		0,	mipsrtrs,
615219b2ee8SDavid du Colombier 	"special1C",	0,	mipscoxxx,
616219b2ee8SDavid du Colombier 	"special1D",	0,	mipscoxxx,
6177dd7cddfSDavid du Colombier 	"DDIV",		0,	"R%s,R%t",
618219b2ee8SDavid du Colombier 	"special1F",	0,	mipscoxxx,
619219b2ee8SDavid du Colombier 	"ADD",	      add,	mipsalu3op,
620219b2ee8SDavid du Colombier 	"ADDU",	      add,	mipsalu3op,
621219b2ee8SDavid du Colombier 	"SUB",	      sub,	mipsalu3op,
622219b2ee8SDavid du Colombier 	"SUBU",	      sub,	mipsalu3op,
623219b2ee8SDavid du Colombier 	"AND",	      add,	mipsalu3op,
624219b2ee8SDavid du Colombier 	"OR",	       or,	mipsalu3op,
625219b2ee8SDavid du Colombier 	"XOR",	      add,	mipsalu3op,
626219b2ee8SDavid du Colombier 	"NOR",	      nor,	mipsalu3op,
627219b2ee8SDavid du Colombier 	"special28",	0,	mipscoxxx,
628219b2ee8SDavid du Colombier 	"special29",	0,	mipscoxxx,
629219b2ee8SDavid du Colombier 	"SGT",		0,	mipsalu3op,
630219b2ee8SDavid du Colombier 	"SGTU",		0,	mipsalu3op,
631219b2ee8SDavid du Colombier 	"special2C",	0,	mipscoxxx,
632219b2ee8SDavid du Colombier 	"special2D",	0,	mipscoxxx,
633219b2ee8SDavid du Colombier 	"special2E",	0,	mipscoxxx,
6347dd7cddfSDavid du Colombier 	"DSUBU",	0,	"R%s,R%t,R%d",
635219b2ee8SDavid du Colombier 	"tge",		0,	mipscorsrt,
636219b2ee8SDavid du Colombier 	"tgeu",		0,	mipscorsrt,
637219b2ee8SDavid du Colombier 	"tlt",		0,	mipscorsrt,
638219b2ee8SDavid du Colombier 	"tltu",		0,	mipscorsrt,
639219b2ee8SDavid du Colombier 	"teq",		0,	mipscorsrt,
640219b2ee8SDavid du Colombier 	"special35",	0,	mipscoxxx,
641219b2ee8SDavid du Colombier 	"tne",		0,	mipscorsrt,
642219b2ee8SDavid du Colombier 	"special37",	0,	mipscoxxx,
643219b2ee8SDavid du Colombier 	"SLLV",	      sll,	"$%a,R%t,R%d",
644219b2ee8SDavid du Colombier 	"special39",	0,	mipscoxxx,
645219b2ee8SDavid du Colombier 	"SRLV",	      sll,	"$%a,R%t,R%d",
646219b2ee8SDavid du Colombier 	"SRAV",	      sll,	"$%a,R%t,R%d",
647219b2ee8SDavid du Colombier 	"SLLV",	     sl32,	"$%a,R%t,R%d",
648219b2ee8SDavid du Colombier 	"special3D",	0,	mipscoxxx,
649219b2ee8SDavid du Colombier 	"SRLV",	     sl32,	"$%a,R%t,R%d",
650219b2ee8SDavid du Colombier 	"SRAV",	     sl32,	"$%a,R%t,R%d",
651219b2ee8SDavid du Colombier };
652219b2ee8SDavid du Colombier 
653219b2ee8SDavid du Colombier static Opcode ropcodes[32] = {
654219b2ee8SDavid du Colombier 	"BLTZ",	   branch,	0,
655219b2ee8SDavid du Colombier 	"BGEZ",	   branch,	0,
656219b2ee8SDavid du Colombier 	"BLTZL",   branch,	0,
657219b2ee8SDavid du Colombier 	"BGEZL",   branch,	0,
658219b2ee8SDavid du Colombier 	"regimm04",	0,	mipscoxxx,
659219b2ee8SDavid du Colombier 	"regimm05",	0,	mipscoxxx,
660219b2ee8SDavid du Colombier 	"regimm06",	0,	mipscoxxx,
661219b2ee8SDavid du Colombier 	"regimm07",	0,	mipscoxxx,
662219b2ee8SDavid du Colombier 	"tgei",		0,	mipscorsi,
663219b2ee8SDavid du Colombier 	"tgeiu",	0,	mipscorsi,
664219b2ee8SDavid du Colombier 	"tlti",		0,	mipscorsi,
665219b2ee8SDavid du Colombier 	"tltiu",	0,	mipscorsi,
666219b2ee8SDavid du Colombier 	"teqi",		0,	mipscorsi,
667219b2ee8SDavid du Colombier 	"regimm0D",	0,	mipscoxxx,
668219b2ee8SDavid du Colombier 	"tnei",		0,	mipscorsi,
669219b2ee8SDavid du Colombier 	"regimm0F",	0,	mipscoxxx,
670219b2ee8SDavid du Colombier 	"BLTZAL",  branch,	0,
671219b2ee8SDavid du Colombier 	"BGEZAL",  branch,	0,
672219b2ee8SDavid du Colombier 	"BLTZALL", branch,	0,
673219b2ee8SDavid du Colombier 	"BGEZALL", branch,	0,
674219b2ee8SDavid du Colombier 	"regimm14",	0,	mipscoxxx,
675219b2ee8SDavid du Colombier 	"regimm15",	0,	mipscoxxx,
676219b2ee8SDavid du Colombier 	"regimm16",	0,	mipscoxxx,
677219b2ee8SDavid du Colombier 	"regimm17",	0,	mipscoxxx,
678219b2ee8SDavid du Colombier 	"regimm18",	0,	mipscoxxx,
679219b2ee8SDavid du Colombier 	"regimm19",	0,	mipscoxxx,
680219b2ee8SDavid du Colombier 	"regimm1A",	0,	mipscoxxx,
681219b2ee8SDavid du Colombier 	"regimm1B",	0,	mipscoxxx,
682219b2ee8SDavid du Colombier 	"regimm1C",	0,	mipscoxxx,
683219b2ee8SDavid du Colombier 	"regimm1D",	0,	mipscoxxx,
684219b2ee8SDavid du Colombier 	"regimm1E",	0,	mipscoxxx,
685219b2ee8SDavid du Colombier 	"regimm1F",	0,	mipscoxxx,
686219b2ee8SDavid du Colombier };
687219b2ee8SDavid du Colombier 
688219b2ee8SDavid du Colombier static Opcode fopcodes[64] = {
689219b2ee8SDavid du Colombier 	"ADD%f",	0,	mipsfp3,
690219b2ee8SDavid du Colombier 	"SUB%f",	0,	mipsfp3,
691219b2ee8SDavid du Colombier 	"MUL%f",	0,	mipsfp3,
692219b2ee8SDavid du Colombier 	"DIV%f",	0,	mipsfp3,
693219b2ee8SDavid du Colombier 	"sqrt.%f",	0,	mipscofp2,
694219b2ee8SDavid du Colombier 	"ABS%f",	0,	mipsfp2,
695219b2ee8SDavid du Colombier 	"MOV%f",	0,	mipsfp2,
696219b2ee8SDavid du Colombier 	"NEG%f",	0,	mipsfp2,
697219b2ee8SDavid du Colombier 	"finstr08",	0,	mipscoxxx,
698219b2ee8SDavid du Colombier 	"finstr09",	0,	mipscoxxx,
699219b2ee8SDavid du Colombier 	"finstr0A",	0,	mipscoxxx,
700219b2ee8SDavid du Colombier 	"finstr0B",	0,	mipscoxxx,
701219b2ee8SDavid du Colombier 	"round.w.%f",	0,	mipscofp2,
702219b2ee8SDavid du Colombier 	"trunc.w%f",	0,	mipscofp2,
703219b2ee8SDavid du Colombier 	"ceil.w%f",	0,	mipscofp2,
704219b2ee8SDavid du Colombier 	"floor.w%f",	0,	mipscofp2,
705219b2ee8SDavid du Colombier 	"finstr10",	0,	mipscoxxx,
706219b2ee8SDavid du Colombier 	"finstr11",	0,	mipscoxxx,
707219b2ee8SDavid du Colombier 	"finstr12",	0,	mipscoxxx,
708219b2ee8SDavid du Colombier 	"finstr13",	0,	mipscoxxx,
709219b2ee8SDavid du Colombier 	"finstr14",	0,	mipscoxxx,
710219b2ee8SDavid du Colombier 	"finstr15",	0,	mipscoxxx,
711219b2ee8SDavid du Colombier 	"finstr16",	0,	mipscoxxx,
712219b2ee8SDavid du Colombier 	"finstr17",	0,	mipscoxxx,
713219b2ee8SDavid du Colombier 	"finstr18",	0,	mipscoxxx,
714219b2ee8SDavid du Colombier 	"finstr19",	0,	mipscoxxx,
715219b2ee8SDavid du Colombier 	"finstr1A",	0,	mipscoxxx,
716219b2ee8SDavid du Colombier 	"finstr1B",	0,	mipscoxxx,
717219b2ee8SDavid du Colombier 	"finstr1C",	0,	mipscoxxx,
718219b2ee8SDavid du Colombier 	"finstr1D",	0,	mipscoxxx,
719219b2ee8SDavid du Colombier 	"finstr1E",	0,	mipscoxxx,
720219b2ee8SDavid du Colombier 	"finstr1F",	0,	mipscoxxx,
721219b2ee8SDavid du Colombier 	"cvt.s.%f",	0,	mipscofp2,
722219b2ee8SDavid du Colombier 	"cvt.d.%f",	0,	mipscofp2,
723219b2ee8SDavid du Colombier 	"cvt.e.%f",	0,	mipscofp2,
724219b2ee8SDavid du Colombier 	"cvt.q.%f",	0,	mipscofp2,
725219b2ee8SDavid du Colombier 	"cvt.w.%f",	0,	mipscofp2,
726219b2ee8SDavid du Colombier 	"finstr25",	0,	mipscoxxx,
727219b2ee8SDavid du Colombier 	"finstr26",	0,	mipscoxxx,
728219b2ee8SDavid du Colombier 	"finstr27",	0,	mipscoxxx,
729219b2ee8SDavid du Colombier 	"finstr28",	0,	mipscoxxx,
730219b2ee8SDavid du Colombier 	"finstr29",	0,	mipscoxxx,
731219b2ee8SDavid du Colombier 	"finstr2A",	0,	mipscoxxx,
732219b2ee8SDavid du Colombier 	"finstr2B",	0,	mipscoxxx,
733219b2ee8SDavid du Colombier 	"finstr2C",	0,	mipscoxxx,
734219b2ee8SDavid du Colombier 	"finstr2D",	0,	mipscoxxx,
735219b2ee8SDavid du Colombier 	"finstr2E",	0,	mipscoxxx,
736219b2ee8SDavid du Colombier 	"finstr2F",	0,	mipscoxxx,
737219b2ee8SDavid du Colombier 	"c.f.%f",	0,	mipscofpc,
738219b2ee8SDavid du Colombier 	"c.un.%f",	0,	mipscofpc,
739219b2ee8SDavid du Colombier 	"CMPEQ%f",	0,	mipsfpc,
740219b2ee8SDavid du Colombier 	"c.ueq.%f",	0,	mipscofpc,
741219b2ee8SDavid du Colombier 	"c.olt.%f",	0,	mipscofpc,
742219b2ee8SDavid du Colombier 	"c.ult.%f",	0,	mipscofpc,
743219b2ee8SDavid du Colombier 	"c.ole.%f",	0,	mipscofpc,
744219b2ee8SDavid du Colombier 	"c.ule.%f",	0,	mipscofpc,
745219b2ee8SDavid du Colombier 	"c.sf.%f",	0,	mipscofpc,
746219b2ee8SDavid du Colombier 	"c.ngle.%f",	0,	mipscofpc,
747219b2ee8SDavid du Colombier 	"c.seq.%f",	0,	mipscofpc,
748219b2ee8SDavid du Colombier 	"c.ngl.%f",	0,	mipscofpc,
749219b2ee8SDavid du Colombier 	"CMPGT%f",	0,	mipsfpc,
750219b2ee8SDavid du Colombier 	"c.nge.%f",	0,	mipscofpc,
751219b2ee8SDavid du Colombier 	"CMPGE%f",	0,	mipsfpc,
752219b2ee8SDavid du Colombier 	"c.ngt.%f",	0,	mipscofpc,
753219b2ee8SDavid du Colombier };
754219b2ee8SDavid du Colombier 
755219b2ee8SDavid du Colombier static char *cop0regs[32] = {
756219b2ee8SDavid du Colombier 	"INDEX", "RANDOM", "TLBPHYS", "EntryLo0",
757219b2ee8SDavid du Colombier 	"CONTEXT", "PageMask", "Wired",	"Error",
758219b2ee8SDavid du Colombier 	"BADVADDR", "Count", "TLBVIRT", "Compare",
759219b2ee8SDavid du Colombier 	"STATUS", "CAUSE", "EPC", "PRID",
760219b2ee8SDavid du Colombier 	"Config", "LLadr", "WatchLo", "WatchHi",
761219b2ee8SDavid du Colombier 	"20", "21", "22", "23",
762219b2ee8SDavid du Colombier 	"24", "25", "26", "CacheErr",
763219b2ee8SDavid du Colombier 	"TagLo", "TagHi", "ErrorEPC", "31"
764219b2ee8SDavid du Colombier };
765219b2ee8SDavid du Colombier 
766219b2ee8SDavid du Colombier static char fsub[16] = {
767219b2ee8SDavid du Colombier 	'F', 'D', 'e', 'q', 'W', '?', '?', '?',
768219b2ee8SDavid du Colombier 	'?', '?', '?', '?', '?', '?', '?', '?'
769219b2ee8SDavid du Colombier };
770219b2ee8SDavid du Colombier 
771219b2ee8SDavid du Colombier static char *cacheps[] = {
772219b2ee8SDavid du Colombier 	"I", "D", "SI", "SD"
773219b2ee8SDavid du Colombier };
774219b2ee8SDavid du Colombier 
775219b2ee8SDavid du Colombier static char *cacheop[] = {
776219b2ee8SDavid du Colombier 	"IWBI", "ILT", "IST", "CDE", "HI", "HWBI", "HWB", "HSV"
777219b2ee8SDavid du Colombier };
778219b2ee8SDavid du Colombier 
779219b2ee8SDavid du Colombier static void
format(char * mnemonic,Instr * i,char * f)780219b2ee8SDavid du Colombier format(char *mnemonic, Instr *i, char *f)
781219b2ee8SDavid du Colombier {
782219b2ee8SDavid du Colombier 	if (mnemonic)
783219b2ee8SDavid du Colombier 		format(0, i, mnemonic);
784219b2ee8SDavid du Colombier 	if (f == 0)
785219b2ee8SDavid du Colombier 		return;
786219b2ee8SDavid du Colombier 	if (mnemonic)
787219b2ee8SDavid du Colombier 		if (i->curr < i->end)
788219b2ee8SDavid du Colombier 			*i->curr++ = '\t';
789219b2ee8SDavid du Colombier 	for ( ; *f && i->curr < i->end; f++) {
790219b2ee8SDavid du Colombier 		if (*f != '%') {
791219b2ee8SDavid du Colombier 			*i->curr++ = *f;
792219b2ee8SDavid du Colombier 			continue;
793219b2ee8SDavid du Colombier 		}
794219b2ee8SDavid du Colombier 		switch (*++f) {
795219b2ee8SDavid du Colombier 
796219b2ee8SDavid du Colombier 		case 's':
797219b2ee8SDavid du Colombier 			bprint(i, "%d", i->rs);
798219b2ee8SDavid du Colombier 			break;
799219b2ee8SDavid du Colombier 
800219b2ee8SDavid du Colombier 		case 't':
801219b2ee8SDavid du Colombier 			bprint(i, "%d", i->rt);
802219b2ee8SDavid du Colombier 			break;
803219b2ee8SDavid du Colombier 
804219b2ee8SDavid du Colombier 		case 'd':
805219b2ee8SDavid du Colombier 			bprint(i, "%d", i->rd);
806219b2ee8SDavid du Colombier 			break;
807219b2ee8SDavid du Colombier 
808219b2ee8SDavid du Colombier 		case 'a':
809219b2ee8SDavid du Colombier 			bprint(i, "%d", i->sa);
810219b2ee8SDavid du Colombier 			break;
811219b2ee8SDavid du Colombier 
812219b2ee8SDavid du Colombier 		case 'l':
813219b2ee8SDavid du Colombier 			bprint(i, "%lx(R%d)",i->immediate, i->rs);
814219b2ee8SDavid du Colombier 			break;
815219b2ee8SDavid du Colombier 
816219b2ee8SDavid du Colombier 		case 'i':
817219b2ee8SDavid du Colombier 			bprint(i, "$%lx", i->immediate);
818219b2ee8SDavid du Colombier 			break;
819219b2ee8SDavid du Colombier 
820219b2ee8SDavid du Colombier 		case 'u':
821219b2ee8SDavid du Colombier 			i->curr += symoff(i->curr, i->end-i->curr, i->immediate, CANY);
822219b2ee8SDavid du Colombier 			bprint(i, "(SB)");
823219b2ee8SDavid du Colombier 			break;
824219b2ee8SDavid du Colombier 
825219b2ee8SDavid du Colombier 		case 'j':
826219b2ee8SDavid du Colombier 			i->curr += symoff(i->curr, i->end-i->curr,
827219b2ee8SDavid du Colombier 				(i->target<<2)|(i->addr & 0xF0000000), CANY);
828219b2ee8SDavid du Colombier 			bprint(i, "(SB)");
829219b2ee8SDavid du Colombier 			break;
830219b2ee8SDavid du Colombier 
831219b2ee8SDavid du Colombier 		case 'b':
832219b2ee8SDavid du Colombier 			i->curr += symoff(i->curr, i->end-i->curr,
833219b2ee8SDavid du Colombier 				(i->immediate<<2)+i->addr+4, CANY);
834219b2ee8SDavid du Colombier 			break;
835219b2ee8SDavid du Colombier 
836219b2ee8SDavid du Colombier 		case 'c':
837219b2ee8SDavid du Colombier 			bprint(i, "$%lx", i->cofun);
838219b2ee8SDavid du Colombier 			break;
839219b2ee8SDavid du Colombier 
840219b2ee8SDavid du Colombier 		case 'w':
841219b2ee8SDavid du Colombier 			bprint(i, "[%lux]", i->w0);
842219b2ee8SDavid du Colombier 			break;
843219b2ee8SDavid du Colombier 
844219b2ee8SDavid du Colombier 		case 'm':
845219b2ee8SDavid du Colombier 			bprint(i, "M(%s)", cop0regs[i->rd]);
846219b2ee8SDavid du Colombier 			break;
847219b2ee8SDavid du Colombier 
848219b2ee8SDavid du Colombier 		case 'f':
849219b2ee8SDavid du Colombier 			*i->curr++ = fsub[i->rs & 0x0F];
850219b2ee8SDavid du Colombier 			break;
851219b2ee8SDavid du Colombier 
852219b2ee8SDavid du Colombier 		case 'C':
853219b2ee8SDavid du Colombier 			bprint(i, "%s%s", cacheps[i->rt & 3], cacheop[(i->rt>>2) & 7]);
854219b2ee8SDavid du Colombier 			break;
855219b2ee8SDavid du Colombier 
856219b2ee8SDavid du Colombier 		case '\0':
857219b2ee8SDavid du Colombier 			*i->curr++ = '%';
858219b2ee8SDavid du Colombier 			return;
859219b2ee8SDavid du Colombier 
860219b2ee8SDavid du Colombier 		default:
861219b2ee8SDavid du Colombier 			bprint(i, "%%%c", *f);
862219b2ee8SDavid du Colombier 			break;
863219b2ee8SDavid du Colombier 		}
864219b2ee8SDavid du Colombier 	}
865219b2ee8SDavid du Colombier 	*i->curr = 0;
866219b2ee8SDavid du Colombier }
867219b2ee8SDavid du Colombier 
868219b2ee8SDavid du Colombier static void
copz(int cop,Instr * i)869219b2ee8SDavid du Colombier copz(int cop, Instr *i)
870219b2ee8SDavid du Colombier {
871219b2ee8SDavid du Colombier 	char *f, *m, buf[16];
872219b2ee8SDavid du Colombier 
873219b2ee8SDavid du Colombier 	m = buf;
874219b2ee8SDavid du Colombier 	f = "%t,%d";
875219b2ee8SDavid du Colombier 	switch (i->rs) {
876219b2ee8SDavid du Colombier 
877219b2ee8SDavid du Colombier 	case 0:
878219b2ee8SDavid du Colombier 		sprint(buf, "mfc%d", cop);
879219b2ee8SDavid du Colombier 		break;
880219b2ee8SDavid du Colombier 
881219b2ee8SDavid du Colombier 	case 2:
882219b2ee8SDavid du Colombier 		sprint(buf, "cfc%d", cop);
883219b2ee8SDavid du Colombier 		break;
884219b2ee8SDavid du Colombier 
885219b2ee8SDavid du Colombier 	case 4:
886219b2ee8SDavid du Colombier 		sprint(buf, "mtc%d", cop);
887219b2ee8SDavid du Colombier 		break;
888219b2ee8SDavid du Colombier 
889219b2ee8SDavid du Colombier 	case 6:
890219b2ee8SDavid du Colombier 		sprint(buf, "ctc%d", cop);
891219b2ee8SDavid du Colombier 		break;
892219b2ee8SDavid du Colombier 
893219b2ee8SDavid du Colombier 	case 8:
894219b2ee8SDavid du Colombier 		f = "%b";
895219b2ee8SDavid du Colombier 		switch (i->rt) {
896219b2ee8SDavid du Colombier 
897219b2ee8SDavid du Colombier 		case 0:
898219b2ee8SDavid du Colombier 			sprint(buf, "bc%df", cop);
899219b2ee8SDavid du Colombier 			break;
900219b2ee8SDavid du Colombier 
901219b2ee8SDavid du Colombier 		case 1:
902219b2ee8SDavid du Colombier 			sprint(buf, "bc%dt", cop);
903219b2ee8SDavid du Colombier 			break;
904219b2ee8SDavid du Colombier 
905219b2ee8SDavid du Colombier 		case 2:
906219b2ee8SDavid du Colombier 			sprint(buf, "bc%dfl", cop);
907219b2ee8SDavid du Colombier 			break;
908219b2ee8SDavid du Colombier 
909219b2ee8SDavid du Colombier 		case 3:
910219b2ee8SDavid du Colombier 			sprint(buf, "bc%dtl", cop);
911219b2ee8SDavid du Colombier 			break;
912219b2ee8SDavid du Colombier 
913219b2ee8SDavid du Colombier 		default:
914219b2ee8SDavid du Colombier 			sprint(buf, "cop%d", cop);
915219b2ee8SDavid du Colombier 			f = mipscoxxx;
916219b2ee8SDavid du Colombier 			break;
917219b2ee8SDavid du Colombier 		}
918219b2ee8SDavid du Colombier 		break;
919219b2ee8SDavid du Colombier 
920219b2ee8SDavid du Colombier 	default:
921219b2ee8SDavid du Colombier 		sprint(buf, "cop%d", cop);
922219b2ee8SDavid du Colombier 		if (i->rs & 0x10)
923219b2ee8SDavid du Colombier 			f = "function %c";
924219b2ee8SDavid du Colombier 		else
925219b2ee8SDavid du Colombier 			f = mipscoxxx;
926219b2ee8SDavid du Colombier 		break;
927219b2ee8SDavid du Colombier 	}
928219b2ee8SDavid du Colombier 	format(m, i, f);
929219b2ee8SDavid du Colombier }
930219b2ee8SDavid du Colombier 
931219b2ee8SDavid du Colombier static void
cop0(Instr * i)932219b2ee8SDavid du Colombier cop0(Instr *i)
933219b2ee8SDavid du Colombier {
934219b2ee8SDavid du Colombier 	char *m = 0;
935219b2ee8SDavid du Colombier 
936219b2ee8SDavid du Colombier 	if (i->rs < 8) {
937219b2ee8SDavid du Colombier 		switch (i->rs) {
938219b2ee8SDavid du Colombier 
939219b2ee8SDavid du Colombier 		case 0:
940219b2ee8SDavid du Colombier 		case 1:
941219b2ee8SDavid du Colombier 			format("MOVW", i, "%m,R%t");
942219b2ee8SDavid du Colombier 			return;
943219b2ee8SDavid du Colombier 
944219b2ee8SDavid du Colombier 		case 4:
945219b2ee8SDavid du Colombier 		case 5:
946219b2ee8SDavid du Colombier 			format("MOVW", i, "R%t,%m");
947219b2ee8SDavid du Colombier 			return;
948219b2ee8SDavid du Colombier 		}
949219b2ee8SDavid du Colombier 	}
950219b2ee8SDavid du Colombier 	else if (i->rs >= 0x10) {
951219b2ee8SDavid du Colombier 		switch (i->cofun) {
952219b2ee8SDavid du Colombier 
953219b2ee8SDavid du Colombier 		case 1:
954219b2ee8SDavid du Colombier 			m = "TLBR";
955219b2ee8SDavid du Colombier 			break;
956219b2ee8SDavid du Colombier 
957219b2ee8SDavid du Colombier 		case 2:
958219b2ee8SDavid du Colombier 			m = "TLBWI";
959219b2ee8SDavid du Colombier 			break;
960219b2ee8SDavid du Colombier 
961219b2ee8SDavid du Colombier 		case 6:
962219b2ee8SDavid du Colombier 			m = "TLBWR";
963219b2ee8SDavid du Colombier 			break;
964219b2ee8SDavid du Colombier 
965219b2ee8SDavid du Colombier 		case 8:
966219b2ee8SDavid du Colombier 			m = "TLBP";
967219b2ee8SDavid du Colombier 			break;
968219b2ee8SDavid du Colombier 
969219b2ee8SDavid du Colombier 		case 16:
970219b2ee8SDavid du Colombier 			m = "RFE";
971219b2ee8SDavid du Colombier 			break;
972219b2ee8SDavid du Colombier 
973eaba85aaSDavid du Colombier 		case 24:
974219b2ee8SDavid du Colombier 			m = "ERET";
975219b2ee8SDavid du Colombier 			break;
976eaba85aaSDavid du Colombier 
977eaba85aaSDavid du Colombier 		case 32:
978eaba85aaSDavid du Colombier 			m = "WAIT";
979eaba85aaSDavid du Colombier 			break;
980219b2ee8SDavid du Colombier 		}
981219b2ee8SDavid du Colombier 		if (m) {
982219b2ee8SDavid du Colombier 			format(m, i, 0);
983219b2ee8SDavid du Colombier 			return;
984219b2ee8SDavid du Colombier 		}
985219b2ee8SDavid du Colombier 	}
986219b2ee8SDavid du Colombier 	copz(0, i);
987219b2ee8SDavid du Colombier }
988219b2ee8SDavid du Colombier 
989219b2ee8SDavid du Colombier static void
cop1(Instr * i)990219b2ee8SDavid du Colombier cop1(Instr *i)
991219b2ee8SDavid du Colombier {
992219b2ee8SDavid du Colombier 	char *m = "MOVW";
993219b2ee8SDavid du Colombier 
994219b2ee8SDavid du Colombier 	switch (i->rs) {
995219b2ee8SDavid du Colombier 
996219b2ee8SDavid du Colombier 	case 0:
997219b2ee8SDavid du Colombier 		format(m, i, "F%d,R%t");
998219b2ee8SDavid du Colombier 		return;
999219b2ee8SDavid du Colombier 
1000219b2ee8SDavid du Colombier 	case 2:
1001219b2ee8SDavid du Colombier 		format(m, i, "FCR%d,R%t");
1002219b2ee8SDavid du Colombier 		return;
1003219b2ee8SDavid du Colombier 
1004219b2ee8SDavid du Colombier 	case 4:
1005219b2ee8SDavid du Colombier 		format(m, i, "R%t,F%d");
1006219b2ee8SDavid du Colombier 		return;
1007219b2ee8SDavid du Colombier 
1008219b2ee8SDavid du Colombier 	case 6:
1009219b2ee8SDavid du Colombier 		format(m, i, "R%t,FCR%d");
1010219b2ee8SDavid du Colombier 		return;
1011219b2ee8SDavid du Colombier 
1012219b2ee8SDavid du Colombier 	case 8:
1013219b2ee8SDavid du Colombier 		switch (i->rt) {
1014219b2ee8SDavid du Colombier 
1015219b2ee8SDavid du Colombier 		case 0:
1016219b2ee8SDavid du Colombier 			format("BFPF", i, "%b");
1017219b2ee8SDavid du Colombier 			return;
1018219b2ee8SDavid du Colombier 
1019219b2ee8SDavid du Colombier 		case 1:
1020219b2ee8SDavid du Colombier 			format("BFPT", i, "%b");
1021219b2ee8SDavid du Colombier 			return;
1022219b2ee8SDavid du Colombier 		}
1023219b2ee8SDavid du Colombier 		break;
1024219b2ee8SDavid du Colombier 	}
1025219b2ee8SDavid du Colombier 	copz(1, i);
1026219b2ee8SDavid du Colombier }
1027219b2ee8SDavid du Colombier 
1028219b2ee8SDavid du Colombier static int
printins(Map * map,uvlong pc,char * buf,int n)10294de34a7eSDavid du Colombier printins(Map *map, uvlong pc, char *buf, int n)
1030219b2ee8SDavid du Colombier {
1031219b2ee8SDavid du Colombier 	Instr i;
1032219b2ee8SDavid du Colombier 	Opcode *o;
1033219b2ee8SDavid du Colombier 	uchar op;
1034219b2ee8SDavid du Colombier 
1035219b2ee8SDavid du Colombier 	i.curr = buf;
1036219b2ee8SDavid du Colombier 	i.end = buf+n-1;
1037219b2ee8SDavid du Colombier 	mymap = map;
1038219b2ee8SDavid du Colombier 	if (mkinstr(pc, &i) < 0)
1039219b2ee8SDavid du Colombier 		return -1;
1040219b2ee8SDavid du Colombier 	switch (i.op) {
1041219b2ee8SDavid du Colombier 
1042219b2ee8SDavid du Colombier 	case 0x00:					/* SPECIAL */
1043219b2ee8SDavid du Colombier 		o = sopcodes;
1044219b2ee8SDavid du Colombier 		op = i.function;
1045219b2ee8SDavid du Colombier 		break;
1046219b2ee8SDavid du Colombier 
1047219b2ee8SDavid du Colombier 	case 0x01:					/* REGIMM */
1048219b2ee8SDavid du Colombier 		o = ropcodes;
1049219b2ee8SDavid du Colombier 		op = i.rt;
1050219b2ee8SDavid du Colombier 		break;
1051219b2ee8SDavid du Colombier 
1052219b2ee8SDavid du Colombier 	case 0x10:					/* COP0 */
1053219b2ee8SDavid du Colombier 		cop0(&i);
1054219b2ee8SDavid du Colombier 		return i.size*4;
1055219b2ee8SDavid du Colombier 
1056219b2ee8SDavid du Colombier 	case 0x11:					/* COP1 */
1057219b2ee8SDavid du Colombier 		if (i.rs & 0x10) {
1058219b2ee8SDavid du Colombier 			o = fopcodes;
1059219b2ee8SDavid du Colombier 			op = i.function;
1060219b2ee8SDavid du Colombier 			break;
1061219b2ee8SDavid du Colombier 		}
1062219b2ee8SDavid du Colombier 		cop1(&i);
1063219b2ee8SDavid du Colombier 		return i.size*4;
1064219b2ee8SDavid du Colombier 
1065219b2ee8SDavid du Colombier 	case 0x12:					/* COP2 */
1066219b2ee8SDavid du Colombier 	case 0x13:					/* COP3 */
1067219b2ee8SDavid du Colombier 		copz(i.op-0x10, &i);
1068219b2ee8SDavid du Colombier 		return i.size*4;
1069219b2ee8SDavid du Colombier 
1070219b2ee8SDavid du Colombier 	default:
1071219b2ee8SDavid du Colombier 		o = opcodes;
1072219b2ee8SDavid du Colombier 		op = i.op;
1073219b2ee8SDavid du Colombier 		break;
1074219b2ee8SDavid du Colombier 	}
1075219b2ee8SDavid du Colombier 	if (o[op].f)
1076219b2ee8SDavid du Colombier 		(*o[op].f)(&o[op], &i);
1077219b2ee8SDavid du Colombier 	else
1078219b2ee8SDavid du Colombier 		format(o[op].mnemonic, &i, o[op].ken);
1079219b2ee8SDavid du Colombier 	return i.size*4;
1080219b2ee8SDavid du Colombier }
1081219b2ee8SDavid du Colombier 
10824de34a7eSDavid du Colombier extern	int	_mipscoinst(Map *, uvlong, char*, int);
1083219b2ee8SDavid du Colombier 
1084219b2ee8SDavid du Colombier 	/* modifier 'I' toggles the default disassembler type */
1085219b2ee8SDavid du Colombier static int
mipsinst(Map * map,uvlong pc,char modifier,char * buf,int n)10864de34a7eSDavid du Colombier mipsinst(Map *map, uvlong pc, char modifier, char *buf, int n)
1087219b2ee8SDavid du Colombier {
1088219b2ee8SDavid du Colombier 	if ((asstype == AMIPSCO && modifier == 'i')
1089219b2ee8SDavid du Colombier 		|| (asstype == AMIPS && modifier == 'I'))
1090219b2ee8SDavid du Colombier 		return _mipscoinst(map, pc, buf, n);
1091219b2ee8SDavid du Colombier 	else
1092219b2ee8SDavid du Colombier 		return printins(map, pc, buf, n);
1093219b2ee8SDavid du Colombier }
1094219b2ee8SDavid du Colombier 
1095219b2ee8SDavid du Colombier static int
mipsdas(Map * map,uvlong pc,char * buf,int n)10964de34a7eSDavid du Colombier mipsdas(Map *map, uvlong pc, char *buf, int n)
1097219b2ee8SDavid du Colombier {
1098219b2ee8SDavid du Colombier 	Instr i;
1099219b2ee8SDavid du Colombier 
1100219b2ee8SDavid du Colombier 	i.curr = buf;
1101219b2ee8SDavid du Colombier 	i.end = buf+n;
1102219b2ee8SDavid du Colombier 	mymap = map;
1103219b2ee8SDavid du Colombier 	if (mkinstr(pc, &i) < 0)
1104219b2ee8SDavid du Colombier 		return -1;
1105219b2ee8SDavid du Colombier 	if (i.end-i.curr > 8)
1106219b2ee8SDavid du Colombier 		i.curr = _hexify(buf, i.w0, 7);
1107219b2ee8SDavid du Colombier 	if (i.size == 2 && i.end-i.curr > 9) {
1108219b2ee8SDavid du Colombier 		*i.curr++ = ' ';
1109219b2ee8SDavid du Colombier 		i.curr = _hexify(i.curr, i.w1, 7);
1110219b2ee8SDavid du Colombier 	}
1111219b2ee8SDavid du Colombier 	*i.curr = 0;
1112219b2ee8SDavid du Colombier 	return i.size*4;
1113219b2ee8SDavid du Colombier }
1114219b2ee8SDavid du Colombier 
1115219b2ee8SDavid du Colombier static int
mipsinstlen(Map * map,uvlong pc)11164de34a7eSDavid du Colombier mipsinstlen(Map *map, uvlong pc)
1117219b2ee8SDavid du Colombier {
1118219b2ee8SDavid du Colombier 	Instr i;
1119219b2ee8SDavid du Colombier 
1120219b2ee8SDavid du Colombier 	mymap = map;
1121219b2ee8SDavid du Colombier 	if (mkinstr(pc, &i) < 0)
1122219b2ee8SDavid du Colombier 		return -1;
1123219b2ee8SDavid du Colombier 	return i.size*4;
1124219b2ee8SDavid du Colombier }
1125219b2ee8SDavid du Colombier 
1126219b2ee8SDavid du Colombier static int
mipsfoll(Map * map,uvlong pc,Rgetter rget,uvlong * foll)11274de34a7eSDavid du Colombier mipsfoll(Map *map, uvlong pc, Rgetter rget, uvlong *foll)
1128219b2ee8SDavid du Colombier {
1129219b2ee8SDavid du Colombier 	ulong w, l;
1130219b2ee8SDavid du Colombier 	char buf[8];
1131219b2ee8SDavid du Colombier 	Instr i;
1132219b2ee8SDavid du Colombier 
1133219b2ee8SDavid du Colombier 	mymap = map;
1134219b2ee8SDavid du Colombier 	if (mkinstr(pc, &i) < 0)
1135219b2ee8SDavid du Colombier 		return -1;
1136219b2ee8SDavid du Colombier 	w = i.w0;
1137219b2ee8SDavid du Colombier 	if((w&0xF3600000) == 0x41000000){	/* branch on coprocessor */
1138219b2ee8SDavid du Colombier     Conditional:
1139219b2ee8SDavid du Colombier 		foll[0] = pc+8;
1140219b2ee8SDavid du Colombier 		l = ((w&0xFFFF)<<2);
1141219b2ee8SDavid du Colombier 		if(w & 0x8000)
1142219b2ee8SDavid du Colombier 			l |= 0xFFFC0000;
1143219b2ee8SDavid du Colombier 		foll[1] = pc+4 + l;
1144219b2ee8SDavid du Colombier 		return 2;
1145219b2ee8SDavid du Colombier 	}
1146219b2ee8SDavid du Colombier 
1147219b2ee8SDavid du Colombier 	l = (w&0xFC000000)>>26;
1148219b2ee8SDavid du Colombier 	switch(l){
1149219b2ee8SDavid du Colombier 	case 0:		/* SPECIAL */
1150219b2ee8SDavid du Colombier 		if((w&0x3E) == 0x08){	/* JR, JALR */
11517dd7cddfSDavid du Colombier 			sprint(buf, "R%ld", (w>>21)&0x1F);
1152219b2ee8SDavid du Colombier 			foll[0] = (*rget)(map, buf);
1153219b2ee8SDavid du Colombier 			return 1;
1154219b2ee8SDavid du Colombier 		}
1155219b2ee8SDavid du Colombier 		foll[0] = pc+i.size*4;
1156219b2ee8SDavid du Colombier 		return 1;
1157219b2ee8SDavid du Colombier 	case 0x30:	/* Load-Linked followed by NOP, STC */
1158219b2ee8SDavid du Colombier 		foll[0] = pc+12;
1159219b2ee8SDavid du Colombier 		return 1;
1160219b2ee8SDavid du Colombier 	case 1:		/* BCOND */
1161219b2ee8SDavid du Colombier 	case 4:		/* BEQ */
11627dd7cddfSDavid du Colombier 	case 20:	/* BEQL */
1163219b2ee8SDavid du Colombier 	case 5:		/* BNE */
11647dd7cddfSDavid du Colombier 	case 21:	/* BNEL */
1165219b2ee8SDavid du Colombier 	case 6:		/* BLEZ */
11667dd7cddfSDavid du Colombier 	case 22:	/* BLEZL */
1167219b2ee8SDavid du Colombier 	case 7:		/* BGTZ */
11687dd7cddfSDavid du Colombier 	case 23:	/* BGTZL */
1169219b2ee8SDavid du Colombier 		goto Conditional;
1170219b2ee8SDavid du Colombier 	case 2:		/* J */
1171219b2ee8SDavid du Colombier 	case 3:		/* JAL */
1172219b2ee8SDavid du Colombier 		foll[0] = (pc&0xF0000000) | ((w&0x03FFFFFF)<<2);
1173219b2ee8SDavid du Colombier 		return 1;
1174219b2ee8SDavid du Colombier 	}
1175219b2ee8SDavid du Colombier 
1176219b2ee8SDavid du Colombier 	foll[0] = pc+i.size*4;
1177219b2ee8SDavid du Colombier 	return 1;
1178219b2ee8SDavid du Colombier }
1179