xref: /plan9-contrib/sys/src/libmach/vdb.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <mach.h>
5 /*
6  * Mips-specific debugger interface
7  */
8 
9 static 	char	*mipsexcep(Map*, Rgetter);
10 static	int	mipsfoll(Map*, ulong, Rgetter, ulong*);
11 static	int	mipsinst(Map*, ulong, char, char*, int);
12 static	int	mipsdas(Map*, ulong, char*, int);
13 static	int	mipsinstlen(Map*, ulong);
14 /*
15  *	Debugger interface
16  */
17 Machdata mipsmach =
18 {
19 	{0, 0, 0, 0xD},		/* break point */
20 	4,			/* break point size */
21 
22 	beswab,			/* short to local byte order */
23 	beswal,			/* long to local byte order */
24 	risctrace,		/* C traceback */
25 	riscframe,		/* Frame finder */
26 	0,			/* ublock fixup */
27 	mipsexcep,		/* print exception */
28 	0,			/* breakpoint fixup */
29 	beieeesftos,		/* single precision float printer */
30 	beieeedftos,		/* double precisioin float printer */
31 	mipsfoll,		/* following addresses */
32 	mipsinst,		/* print instruction */
33 	mipsdas,		/* dissembler */
34 	mipsinstlen,		/* instruction size */
35 };
36 
37 static char *excname[] =
38 {
39 	"external interrupt",
40 	"TLB modification",
41 	"TLB miss (load or fetch)",
42 	"TLB miss (store)",
43 	"address error (load or fetch)",
44 	"address error (store)",
45 	"bus error (fetch)",
46 	"bus error (data load or store)",
47 	"system call",
48 	"breakpoint",
49 	"reserved instruction",
50 	"coprocessor unusable",
51 	"arithmetic overflow",
52 	"undefined 13",
53 	"undefined 14",
54 	"system call",
55 	/* the following is made up */
56 	"floating point exception"		/* FPEXC */
57 };
58 
59 static char*
60 mipsexcep(Map *map, Rgetter rget)
61 {
62 	int e;
63 	long c;
64 
65 	c = (*rget)(map, "CAUSE");
66 	if(c & 0x00002000)	/* INTR3 */
67 		e = 16;		/* Floating point exception */
68 	else
69 		e = (c>>2)&0x0F;
70 	return excname[e];
71 }
72 
73 	/* mips disassembler and related functions */
74 
75 static	char FRAMENAME[] = ".frame";
76 
77 typedef struct {
78 	ulong addr;
79 	uchar op;			/* bits 31-26 */
80 	uchar rs;			/* bits 25-21 */
81 	uchar rt;			/* bits 20-16 */
82 	uchar rd;			/* bits 15-11 */
83 	uchar sa;			/* bits 10-6 */
84 	uchar function;			/* bits 5-0 */
85 	long immediate;			/* bits 15-0 */
86 	ulong cofun;			/* bits 24-0 */
87 	ulong target;			/* bits 25-0 */
88 	long w0;
89 	long w1;
90 	int size;			/* instruction size */
91 	char *curr;			/* fill point in buffer */
92 	char *end;			/* end of buffer */
93 	char *err;			/* error message */
94 } Instr;
95 
96 static Map *mymap;
97 
98 static int
99 decode (ulong pc, Instr *i)
100 {
101 	long w;
102 
103 	if (get4(mymap, pc, &w) < 0) {
104 		werrstr("can't read instruction: %r");
105 		return -1;
106 	}
107 	i->addr = pc;
108 	i->size = 1;
109 	i->op = (w >> 26) & 0x3F;
110 	i->rs = (w >> 21) & 0x1F;
111 	i->rt = (w >> 16) & 0x1F;
112 	i->rd = (w >> 11) & 0x1F;
113 	i->sa = (w >> 6) & 0x1F;
114 	i->function = w & 0x3F;
115 	i->immediate = w & 0x0000FFFF;
116 	if (i->immediate & 0x8000)
117 		i->immediate |= ~0x0000FFFF;
118 	i->cofun = w & 0x01FFFFFF;
119 	i->target = w & 0x03FFFFFF;
120 	i->w0 = w;
121 	return 1;
122 }
123 
124 static int
125 mkinstr(ulong pc, Instr *i)
126 {
127 	Instr x;
128 
129 	if (decode(pc, i) < 0)
130 		return -1;
131 	/*
132 	 * if it's a LUI followed by an ORI,
133 	 * it's an immediate load of a large constant.
134 	 * fix the LUI immediate in any case.
135 	 */
136 	if (i->op == 0x0F) {
137 		if (decode(pc+4, &x) < 0)
138 			return 0;
139 		i->immediate <<= 16;
140 		if (x.op == 0x0D && x.rs == x.rt && x.rt == i->rt) {
141 			i->immediate |= (x.immediate & 0xFFFF);
142 			i->w1 = x.w0;
143 			i->size++;
144 			return 1;
145 		}
146 	}
147 	/*
148 	 * if it's a LWC1 followed by another LWC1
149 	 * into an adjacent register, it's a load of
150 	 * a floating point double.
151 	 */
152 	else if (i->op == 0x31 && (i->rt & 0x01)) {
153 		if (decode(pc+4, &x) < 0)
154 			return 0;
155 		if (x.op == 0x31 && x.rt == (i->rt - 1) && x.rs == i->rs) {
156 			i->rt -= 1;
157 			i->w1 = x.w0;
158 			i->size++;
159 			return 1;
160 		}
161 	}
162 	/*
163 	 * similarly for double stores
164 	 */
165 	else if (i->op == 0x39 && (i->rt & 0x01)) {
166 		if (decode(pc+4, &x) < 0)
167 			return 0;
168 		if (x.op == 0x39 && x.rt == (i->rt - 1) && x.rs == i->rs) {
169 			i->rt -= 1;
170 			i->w1 = x.w0;
171 			i->size++;
172 		}
173 	}
174 	return 1;
175 }
176 
177 static void
178 bprint(Instr *i, char *fmt, ...)
179 {
180 	i->curr = doprint(i->curr, i->end, fmt, (&fmt+1));
181 }
182 
183 typedef struct Opcode Opcode;
184 
185 struct Opcode {
186 	char *mnemonic;
187 	void (*f)(Opcode *, Instr *);
188 	char *ken;
189 };
190 
191 static void format(char *, Instr *, char *);
192 
193 static void
194 branch(Opcode *o, Instr *i)
195 {
196 	if (i->rs == 0 && i->rt == 0)
197 		format("JMP", i, "%b");
198 	else if (i->rs == 0)
199 		format(o->mnemonic, i, "R%t,%b");
200 	else if (i->rt < 2)
201 		format(o->mnemonic, i, "R%s,%b");
202 	else
203 		format(o->mnemonic, i, "R%s,R%t,%b");
204 }
205 
206 static void
207 addi(Opcode *o, Instr *i)
208 {
209 	if (i->rs == i->rt)
210 		format(o->mnemonic, i, "%i,R%t");
211 	else if (i->rs == 0)
212 		format("MOVW", i, "%i,R%t");
213 	else if (i->rs == 30) {
214 		bprint(i, "MOVW\t$");
215 		i->curr += symoff(i->curr, i->end-i->curr,
216 					i->immediate+mach->sb, CANY);
217 		bprint(i, "(SB),R%d", i->rt);
218 	}
219 	else
220 		format(o->mnemonic, i, o->ken);
221 }
222 
223 static void
224 andi(Opcode *o, Instr *i)
225 {
226 	if (i->rs == i->rt)
227 		format(o->mnemonic, i, "%i,R%t");
228 	else
229 		format(o->mnemonic, i, o->ken);
230 }
231 
232 static int
233 plocal(Instr *i, char *m, char r, int store)
234 {
235 	int offset;
236 	char *reg;
237 	Symbol s;
238 
239 	if (!findsym(i->addr, CTEXT, &s) || !findlocal(&s, FRAMENAME, &s))
240 		return 0;
241 	if (s.value > i->immediate) {
242 		if(!getauto(&s, s.value-i->immediate, CAUTO, &s))
243 			return 0;
244 		reg = "(SP)";
245 		offset = i->immediate;
246 	} else {
247 		offset = i->immediate-s.value;
248 		if (!getauto(&s, offset-4, CPARAM, &s))
249 			return 0;
250 		reg = "(FP)";
251 	}
252 	if (store)
253 		bprint(i, "%s\t%c%d,%s+%d%s", m, r, i->rt, s.name, offset, reg);
254 	else
255 		bprint(i, "%s\t%s+%d%s,%c%d", m, s.name, offset, reg, r, i->rt);
256 	return 1;
257 }
258 
259 static void
260 lw(Opcode *o, Instr *i, char r)
261 {
262 	char *m;
263 
264 	if (r == 'F') {
265 		if (i->size == 2)
266 			m = "MOVD";
267 		else
268 			m = "MOVF";
269 	}
270 	else
271 		m = o->mnemonic;
272 	if (i->rs == 29 && plocal(i, m, r, 0))
273 			return;
274 
275 	if (i->rs == 30 && mach->sb) {
276 		bprint(i, "%s\t", m);
277 		i->curr += symoff(i->curr, i->end-i->curr, i->immediate+mach->sb, CANY);
278 		bprint(i, "(SB),%c%d", r, i->rt);
279 		return;
280 	}
281 	if (r == 'F')
282 		format(m, i, "%l,F%t");
283 	else
284 		format(m, i, o->ken);
285 }
286 
287 static void
288 load(Opcode *o, Instr *i)
289 {
290 	lw(o, i, 'R');
291 }
292 
293 static void
294 lwc1(Opcode *o, Instr *i)
295 {
296 	lw(o, i, 'F');
297 }
298 
299 static void
300 sw(Opcode *o, Instr *i, char r)
301 {
302 	char *m;
303 
304 	if (r == 'F') {
305 		if (i->size == 2)
306 			m = "MOVD";
307 		else
308 			m = "MOVF";
309 	}
310 	else
311 		m = o->mnemonic;
312 	if (i->rs == 29 && plocal(i, m, r, 1))
313 			return;
314 
315 	if (i->rs == 30 && mach->sb) {
316 		bprint(i, "%s\t%c%d,", m, r, i->rt);
317 		i->curr += symoff(i->curr, i->end-i->curr, i->immediate+mach->sb, CANY);
318 		bprint(i, "(SB)");
319 		return;
320 	}
321 	if (r == 'F')
322 		format(m, i, "F%t,%l");
323 	else
324 		format(m, i, o->ken);
325 }
326 
327 static void
328 store(Opcode *o, Instr *i)
329 {
330 	sw(o, i, 'R');
331 }
332 
333 static void
334 swc1(Opcode *o, Instr *i)
335 {
336 	sw(o, i, 'F');
337 }
338 
339 static void
340 sll(Opcode *o, Instr *i)
341 {
342 	if (i->w0 == 0)
343 		bprint(i, "NOOP");
344 	else if (i->rd == i->rt)
345 		format(o->mnemonic, i, "$%a,R%d");
346 	else
347 		format(o->mnemonic, i, o->ken);
348 }
349 
350 static void
351 sl32(Opcode *o, Instr *i)
352 {
353 	i->sa += 32;
354 	if (i->rd == i->rt)
355 		format(o->mnemonic, i, "$%a,R%d");
356 	else
357 		format(o->mnemonic, i, o->ken);
358 }
359 
360 static void
361 sllv(Opcode *o, Instr *i)
362 {
363 	if (i->rd == i->rt)
364 		format(o->mnemonic, i, "R%s,R%d");
365 	else
366 		format(o->mnemonic, i, o->ken);
367 }
368 
369 static void
370 jal(Opcode *o, Instr *i)
371 {
372 	if (i->rd == 31)
373 		format("JAL", i, "(R%s)");
374 	else
375 		format(o->mnemonic, i, o->ken);
376 }
377 
378 static void
379 add(Opcode *o, Instr *i)
380 {
381 	if (i->rd == i->rs)
382 		format(o->mnemonic, i, "R%t,R%d");
383 	else if (i->rd == i->rt)
384 		format(o->mnemonic, i, "R%s,R%d");
385 	else
386 		format(o->mnemonic, i, o->ken);
387 }
388 
389 static void
390 sub(Opcode *o, Instr *i)
391 {
392 	if (i->rd == i->rs)
393 		format(o->mnemonic, i, "R%t,R%d");
394 	else
395 		format(o->mnemonic, i, o->ken);
396 }
397 
398 static void
399 or(Opcode *o, Instr *i)
400 {
401 	if (i->rs == 0 && i->rt == 0)
402 		format("MOVW", i, "$0,R%d");
403 	else if (i->rs == 0)
404 		format("MOVW", i, "R%t,R%d");
405 	else if (i->rt == 0)
406 		format("MOVW", i, "R%s,R%d");
407 	else
408 		add(o, i);
409 }
410 
411 static void
412 nor(Opcode *o, Instr *i)
413 {
414 	if (i->rs == 0 && i->rt == 0 && i->rd == 0)
415 		format("NOP", i, 0);
416 	else
417 		add(o, i);
418 }
419 
420 static char mipscoload[] = "r%t,%l";
421 static char mipsload[] = "%l,R%t";
422 static char mipsstore[] = "R%t,%l";
423 static char mipsalui[] = "%i,R%s,R%t";
424 static char mipsalu3op[] = "R%t,R%s,R%d";
425 static char mipsrtrs[] = "R%t,R%s";
426 static char mipscorsrt[] = "r%s,r%t";
427 static char mipscorsi[] = "r%s,%i";
428 static char mipscoxxx[] = "%w";
429 static char mipscofp3[] = "f%a,f%d,f%t";	/* fd,fs,ft */
430 static char mipsfp3[] = "F%t,F%d,F%a";
431 static char mipscofp2[] = "f%a,f%d";		/* fd,fs */
432 static char mipsfp2[] = "F%d,F%a";
433 static char mipscofpc[] = "f%d,f%t";		/* fs,ft */
434 static char mipsfpc[] = "F%t,F%d";
435 
436 static Opcode opcodes[64] = {
437 	0,		0,	0,
438 	0,		0,	0,
439 	"JMP",		0,	"%j",
440 	"JAL",		0,	"%j",
441 	"BEQ",	   branch,	0,
442 	"BNE",	   branch,	0,
443 	"BLEZ",	   branch,	0,
444 	"BGTZ",	   branch,	0,
445 	"ADD",	     addi,	mipsalui,
446 	"ADDU",	     addi,	mipsalui,
447 	"SGT",		0,	mipsalui,
448 	"SGTU",		0,	mipsalui,
449 	"AND",	     andi,	mipsalui,
450 	"OR",	     andi,	mipsalui,
451 	"XOR",	     andi,	mipsalui,
452 	"MOVW",		0,	"$%u,R%t",
453 	"cop0",		0,	0,
454 	"cop1",		0,	0,
455 	"cop2",		0,	0,
456 	"cop3",		0,	0,
457 	"BEQL",	   branch,	0,
458 	"BNEL",	   branch,	0,
459 	"BLEZL",   branch,	0,
460 	"BGTZL",   branch,	0,
461 	"instr18",	0,	mipscoxxx,
462 	"instr19",	0,	mipscoxxx,
463 	"MOVVL",     load,	mipsload,
464 	"MOVVR",     load,	mipsload,
465 	"instr1C",	0,	mipscoxxx,
466 	"instr1D",	0,	mipscoxxx,
467 	"instr1E",	0,	mipscoxxx,
468 	"instr1F",	0,	mipscoxxx,
469 	"MOVB",	     load,	mipsload,
470 	"MOVH",	     load,	mipsload,
471 	"lwl",		0,	mipscoload,
472 	"MOVW",	     load,	mipsload,
473 	"MOVBU",     load,	mipsload,
474 	"MOVHU",     load,	mipsload,
475 	"lwr",		0,	mipscoload,
476 	"instr27",	0,	mipscoxxx,
477 	"MOVB",	    store,	mipsstore,
478 	"MOVH",	    store,	mipsstore,
479 	"swl",		0,	mipscoload,
480 	"MOVW",	    store,	mipsstore,
481 	"MOVVL",    store,	mipsstore,
482 	"MOVVR",    store,	mipsstore,
483 	"swr",		0,	mipscoload,
484 	"CACHE",	0,	"%C,%l",
485 	"ll",		0,	mipscoload,
486 	"MOVW",	     lwc1,	mipscoload,
487 	"lwc2",		0,	mipscoload,
488 	"lwc3",		0,	mipscoload,
489 	"instr34",	0,	mipscoxxx,
490 	"ldc1",		0,	mipscoload,
491 	"ldc2",		0,	mipscoload,
492 	"MOVV",	    load,	mipsload,
493 	"sc",		0,	mipscoload,
494 	"swc1",	     swc1,	mipscoload,
495 	"swc2",		0,	mipscoload,
496 	"swc3",		0,	mipscoload,
497 	"instr3C",	0,	mipscoxxx,
498 	"sdc1",		0,	mipscoload,
499 	"sdc2",		0,	mipscoload,
500 	"MOVV",	    store,	mipsstore,
501 };
502 
503 static Opcode sopcodes[64] = {
504 	"SLL",	      sll,	"$%a,R%t,R%d",
505 	"special01",	0,	mipscoxxx,
506 	"SRL",	      sll,	"$%a,R%t,R%d",
507 	"SRA",	      sll,	"$%a,R%t,R%d",
508 	"SLL",	     sllv,	"R%s,R%t,R%d",
509 	"special05",	0,	mipscoxxx,
510 	"SRL",	     sllv,	"R%s,R%t,R%d",
511 	"SRA",	     sllv,	"R%s,R%t,R%d",
512 	"JMP",		0,	"(R%s)",
513 	"jal",	      jal,	"r%d,r%s",
514 	"special0A",	0,	mipscoxxx,
515 	"special0B",	0,	mipscoxxx,
516 	"SYSCALL",	0,	0,
517 	"BREAK",	0,	0,
518 	"special0E",	0,	mipscoxxx,
519 	"SYNC",		0,	0,
520 	"MOVW",		0,	"HI,R%d",
521 	"MOVW",		0,	"R%s,HI",
522 	"MOVW",		0,	"LO,R%d",
523 	"MOVW",		0,	"R%s,LO",
524 	"SLLV",	     sllv,	"R%s,R%t,R%d",
525 	"special15",	0,	mipscoxxx,
526 	"SRLV",	     sllv,	"R%s,R%t,R%d",
527 	"SRAV",	     sllv,	"R%s,R%t,R%d",
528 	"MUL",		0,	mipsrtrs,
529 	"MULU",		0,	mipsrtrs,
530 	"DIV",		0,	mipsrtrs,
531 	"DIVU",		0,	mipsrtrs,
532 	"special1C",	0,	mipscoxxx,
533 	"special1D",	0,	mipscoxxx,
534 	"special1E",	0,	mipscoxxx,
535 	"special1F",	0,	mipscoxxx,
536 	"ADD",	      add,	mipsalu3op,
537 	"ADDU",	      add,	mipsalu3op,
538 	"SUB",	      sub,	mipsalu3op,
539 	"SUBU",	      sub,	mipsalu3op,
540 	"AND",	      add,	mipsalu3op,
541 	"OR",	       or,	mipsalu3op,
542 	"XOR",	      add,	mipsalu3op,
543 	"NOR",	      nor,	mipsalu3op,
544 	"special28",	0,	mipscoxxx,
545 	"special29",	0,	mipscoxxx,
546 	"SGT",		0,	mipsalu3op,
547 	"SGTU",		0,	mipsalu3op,
548 	"special2C",	0,	mipscoxxx,
549 	"special2D",	0,	mipscoxxx,
550 	"special2E",	0,	mipscoxxx,
551 	"special2F",	0,	mipscoxxx,
552 	"tge",		0,	mipscorsrt,
553 	"tgeu",		0,	mipscorsrt,
554 	"tlt",		0,	mipscorsrt,
555 	"tltu",		0,	mipscorsrt,
556 	"teq",		0,	mipscorsrt,
557 	"special35",	0,	mipscoxxx,
558 	"tne",		0,	mipscorsrt,
559 	"special37",	0,	mipscoxxx,
560 	"SLLV",	      sll,	"$%a,R%t,R%d",
561 	"special39",	0,	mipscoxxx,
562 	"SRLV",	      sll,	"$%a,R%t,R%d",
563 	"SRAV",	      sll,	"$%a,R%t,R%d",
564 	"SLLV",	     sl32,	"$%a,R%t,R%d",
565 	"special3D",	0,	mipscoxxx,
566 	"SRLV",	     sl32,	"$%a,R%t,R%d",
567 	"SRAV",	     sl32,	"$%a,R%t,R%d",
568 };
569 
570 static Opcode ropcodes[32] = {
571 	"BLTZ",	   branch,	0,
572 	"BGEZ",	   branch,	0,
573 	"BLTZL",   branch,	0,
574 	"BGEZL",   branch,	0,
575 	"regimm04",	0,	mipscoxxx,
576 	"regimm05",	0,	mipscoxxx,
577 	"regimm06",	0,	mipscoxxx,
578 	"regimm07",	0,	mipscoxxx,
579 	"tgei",		0,	mipscorsi,
580 	"tgeiu",	0,	mipscorsi,
581 	"tlti",		0,	mipscorsi,
582 	"tltiu",	0,	mipscorsi,
583 	"teqi",		0,	mipscorsi,
584 	"regimm0D",	0,	mipscoxxx,
585 	"tnei",		0,	mipscorsi,
586 	"regimm0F",	0,	mipscoxxx,
587 	"BLTZAL",  branch,	0,
588 	"BGEZAL",  branch,	0,
589 	"BLTZALL", branch,	0,
590 	"BGEZALL", branch,	0,
591 	"regimm14",	0,	mipscoxxx,
592 	"regimm15",	0,	mipscoxxx,
593 	"regimm16",	0,	mipscoxxx,
594 	"regimm17",	0,	mipscoxxx,
595 	"regimm18",	0,	mipscoxxx,
596 	"regimm19",	0,	mipscoxxx,
597 	"regimm1A",	0,	mipscoxxx,
598 	"regimm1B",	0,	mipscoxxx,
599 	"regimm1C",	0,	mipscoxxx,
600 	"regimm1D",	0,	mipscoxxx,
601 	"regimm1E",	0,	mipscoxxx,
602 	"regimm1F",	0,	mipscoxxx,
603 };
604 
605 static Opcode fopcodes[64] = {
606 	"ADD%f",	0,	mipsfp3,
607 	"SUB%f",	0,	mipsfp3,
608 	"MUL%f",	0,	mipsfp3,
609 	"DIV%f",	0,	mipsfp3,
610 	"sqrt.%f",	0,	mipscofp2,
611 	"ABS%f",	0,	mipsfp2,
612 	"MOV%f",	0,	mipsfp2,
613 	"NEG%f",	0,	mipsfp2,
614 	"finstr08",	0,	mipscoxxx,
615 	"finstr09",	0,	mipscoxxx,
616 	"finstr0A",	0,	mipscoxxx,
617 	"finstr0B",	0,	mipscoxxx,
618 	"round.w.%f",	0,	mipscofp2,
619 	"trunc.w%f",	0,	mipscofp2,
620 	"ceil.w%f",	0,	mipscofp2,
621 	"floor.w%f",	0,	mipscofp2,
622 	"finstr10",	0,	mipscoxxx,
623 	"finstr11",	0,	mipscoxxx,
624 	"finstr12",	0,	mipscoxxx,
625 	"finstr13",	0,	mipscoxxx,
626 	"finstr14",	0,	mipscoxxx,
627 	"finstr15",	0,	mipscoxxx,
628 	"finstr16",	0,	mipscoxxx,
629 	"finstr17",	0,	mipscoxxx,
630 	"finstr18",	0,	mipscoxxx,
631 	"finstr19",	0,	mipscoxxx,
632 	"finstr1A",	0,	mipscoxxx,
633 	"finstr1B",	0,	mipscoxxx,
634 	"finstr1C",	0,	mipscoxxx,
635 	"finstr1D",	0,	mipscoxxx,
636 	"finstr1E",	0,	mipscoxxx,
637 	"finstr1F",	0,	mipscoxxx,
638 	"cvt.s.%f",	0,	mipscofp2,
639 	"cvt.d.%f",	0,	mipscofp2,
640 	"cvt.e.%f",	0,	mipscofp2,
641 	"cvt.q.%f",	0,	mipscofp2,
642 	"cvt.w.%f",	0,	mipscofp2,
643 	"finstr25",	0,	mipscoxxx,
644 	"finstr26",	0,	mipscoxxx,
645 	"finstr27",	0,	mipscoxxx,
646 	"finstr28",	0,	mipscoxxx,
647 	"finstr29",	0,	mipscoxxx,
648 	"finstr2A",	0,	mipscoxxx,
649 	"finstr2B",	0,	mipscoxxx,
650 	"finstr2C",	0,	mipscoxxx,
651 	"finstr2D",	0,	mipscoxxx,
652 	"finstr2E",	0,	mipscoxxx,
653 	"finstr2F",	0,	mipscoxxx,
654 	"c.f.%f",	0,	mipscofpc,
655 	"c.un.%f",	0,	mipscofpc,
656 	"CMPEQ%f",	0,	mipsfpc,
657 	"c.ueq.%f",	0,	mipscofpc,
658 	"c.olt.%f",	0,	mipscofpc,
659 	"c.ult.%f",	0,	mipscofpc,
660 	"c.ole.%f",	0,	mipscofpc,
661 	"c.ule.%f",	0,	mipscofpc,
662 	"c.sf.%f",	0,	mipscofpc,
663 	"c.ngle.%f",	0,	mipscofpc,
664 	"c.seq.%f",	0,	mipscofpc,
665 	"c.ngl.%f",	0,	mipscofpc,
666 	"CMPGT%f",	0,	mipsfpc,
667 	"c.nge.%f",	0,	mipscofpc,
668 	"CMPGE%f",	0,	mipsfpc,
669 	"c.ngt.%f",	0,	mipscofpc,
670 };
671 
672 static char *cop0regs[32] = {
673 	"INDEX", "RANDOM", "TLBPHYS", "EntryLo0",
674 	"CONTEXT", "PageMask", "Wired",	"Error",
675 	"BADVADDR", "Count", "TLBVIRT", "Compare",
676 	"STATUS", "CAUSE", "EPC", "PRID",
677 	"Config", "LLadr", "WatchLo", "WatchHi",
678 	"20", "21", "22", "23",
679 	"24", "25", "26", "CacheErr",
680 	"TagLo", "TagHi", "ErrorEPC", "31"
681 };
682 
683 static char fsub[16] = {
684 	'F', 'D', 'e', 'q', 'W', '?', '?', '?',
685 	'?', '?', '?', '?', '?', '?', '?', '?'
686 };
687 
688 static char *cacheps[] = {
689 	"I", "D", "SI", "SD"
690 };
691 
692 static char *cacheop[] = {
693 	"IWBI", "ILT", "IST", "CDE", "HI", "HWBI", "HWB", "HSV"
694 };
695 
696 static void
697 format(char *mnemonic, Instr *i, char *f)
698 {
699 	if (mnemonic)
700 		format(0, i, mnemonic);
701 	if (f == 0)
702 		return;
703 	if (mnemonic)
704 		if (i->curr < i->end)
705 			*i->curr++ = '\t';
706 	for ( ; *f && i->curr < i->end; f++) {
707 		if (*f != '%') {
708 			*i->curr++ = *f;
709 			continue;
710 		}
711 		switch (*++f) {
712 
713 		case 's':
714 			bprint(i, "%d", i->rs);
715 			break;
716 
717 		case 't':
718 			bprint(i, "%d", i->rt);
719 			break;
720 
721 		case 'd':
722 			bprint(i, "%d", i->rd);
723 			break;
724 
725 		case 'a':
726 			bprint(i, "%d", i->sa);
727 			break;
728 
729 		case 'l':
730 			bprint(i, "%lx(R%d)",i->immediate, i->rs);
731 			break;
732 
733 		case 'i':
734 			bprint(i, "$%lx", i->immediate);
735 			break;
736 
737 		case 'u':
738 			i->curr += symoff(i->curr, i->end-i->curr, i->immediate, CANY);
739 			bprint(i, "(SB)");
740 			break;
741 
742 		case 'j':
743 			i->curr += symoff(i->curr, i->end-i->curr,
744 				(i->target<<2)|(i->addr & 0xF0000000), CANY);
745 			bprint(i, "(SB)");
746 			break;
747 
748 		case 'b':
749 			i->curr += symoff(i->curr, i->end-i->curr,
750 				(i->immediate<<2)+i->addr+4, CANY);
751 			break;
752 
753 		case 'c':
754 			bprint(i, "$%lx", i->cofun);
755 			break;
756 
757 		case 'w':
758 			bprint(i, "[%lux]", i->w0);
759 			break;
760 
761 		case 'm':
762 			bprint(i, "M(%s)", cop0regs[i->rd]);
763 			break;
764 
765 		case 'f':
766 			*i->curr++ = fsub[i->rs & 0x0F];
767 			break;
768 
769 		case 'C':
770 			bprint(i, "%s%s", cacheps[i->rt & 3], cacheop[(i->rt>>2) & 7]);
771 			break;
772 
773 		case '\0':
774 			*i->curr++ = '%';
775 			return;
776 
777 		default:
778 			bprint(i, "%%%c", *f);
779 			break;
780 		}
781 	}
782 	*i->curr = 0;
783 }
784 
785 static void
786 copz(int cop, Instr *i)
787 {
788 	char *f, *m, buf[16];
789 
790 	m = buf;
791 	f = "%t,%d";
792 	switch (i->rs) {
793 
794 	case 0:
795 		sprint(buf, "mfc%d", cop);
796 		break;
797 
798 	case 2:
799 		sprint(buf, "cfc%d", cop);
800 		break;
801 
802 	case 4:
803 		sprint(buf, "mtc%d", cop);
804 		break;
805 
806 	case 6:
807 		sprint(buf, "ctc%d", cop);
808 		break;
809 
810 	case 8:
811 		f = "%b";
812 		switch (i->rt) {
813 
814 		case 0:
815 			sprint(buf, "bc%df", cop);
816 			break;
817 
818 		case 1:
819 			sprint(buf, "bc%dt", cop);
820 			break;
821 
822 		case 2:
823 			sprint(buf, "bc%dfl", cop);
824 			break;
825 
826 		case 3:
827 			sprint(buf, "bc%dtl", cop);
828 			break;
829 
830 		default:
831 			sprint(buf, "cop%d", cop);
832 			f = mipscoxxx;
833 			break;
834 		}
835 		break;
836 
837 	default:
838 		sprint(buf, "cop%d", cop);
839 		if (i->rs & 0x10)
840 			f = "function %c";
841 		else
842 			f = mipscoxxx;
843 		break;
844 	}
845 	format(m, i, f);
846 }
847 
848 static void
849 cop0(Instr *i)
850 {
851 	char *m = 0;
852 
853 	if (i->rs < 8) {
854 		switch (i->rs) {
855 
856 		case 0:
857 		case 1:
858 			format("MOVW", i, "%m,R%t");
859 			return;
860 
861 		case 4:
862 		case 5:
863 			format("MOVW", i, "R%t,%m");
864 			return;
865 		}
866 	}
867 	else if (i->rs >= 0x10) {
868 		switch (i->cofun) {
869 
870 		case 1:
871 			m = "TLBR";
872 			break;
873 
874 		case 2:
875 			m = "TLBWI";
876 			break;
877 
878 		case 6:
879 			m = "TLBWR";
880 			break;
881 
882 		case 8:
883 			m = "TLBP";
884 			break;
885 
886 		case 16:
887 			m = "RFE";
888 			break;
889 
890 		case 32:
891 			m = "ERET";
892 			break;
893 		}
894 		if (m) {
895 			format(m, i, 0);
896 			return;
897 		}
898 	}
899 	copz(0, i);
900 }
901 
902 static void
903 cop1(Instr *i)
904 {
905 	char *m = "MOVW";
906 
907 	switch (i->rs) {
908 
909 	case 0:
910 		format(m, i, "F%d,R%t");
911 		return;
912 
913 	case 2:
914 		format(m, i, "FCR%d,R%t");
915 		return;
916 
917 	case 4:
918 		format(m, i, "R%t,F%d");
919 		return;
920 
921 	case 6:
922 		format(m, i, "R%t,FCR%d");
923 		return;
924 
925 	case 8:
926 		switch (i->rt) {
927 
928 		case 0:
929 			format("BFPF", i, "%b");
930 			return;
931 
932 		case 1:
933 			format("BFPT", i, "%b");
934 			return;
935 		}
936 		break;
937 	}
938 	copz(1, i);
939 }
940 
941 static int
942 printins(Map *map, ulong pc, char *buf, int n)
943 {
944 	Instr i;
945 	Opcode *o;
946 	uchar op;
947 
948 	i.curr = buf;
949 	i.end = buf+n-1;
950 	mymap = map;
951 	if (mkinstr(pc, &i) < 0)
952 		return -1;
953 	switch (i.op) {
954 
955 	case 0x00:					/* SPECIAL */
956 		o = sopcodes;
957 		op = i.function;
958 		break;
959 
960 	case 0x01:					/* REGIMM */
961 		o = ropcodes;
962 		op = i.rt;
963 		break;
964 
965 	case 0x10:					/* COP0 */
966 		cop0(&i);
967 		return i.size*4;
968 
969 	case 0x11:					/* COP1 */
970 		if (i.rs & 0x10) {
971 			o = fopcodes;
972 			op = i.function;
973 			break;
974 		}
975 		cop1(&i);
976 		return i.size*4;
977 
978 	case 0x12:					/* COP2 */
979 	case 0x13:					/* COP3 */
980 		copz(i.op-0x10, &i);
981 		return i.size*4;
982 
983 	default:
984 		o = opcodes;
985 		op = i.op;
986 		break;
987 	}
988 	if (o[op].f)
989 		(*o[op].f)(&o[op], &i);
990 	else
991 		format(o[op].mnemonic, &i, o[op].ken);
992 	return i.size*4;
993 }
994 
995 extern	int	_mipscoinst(Map *, ulong, char*, int);
996 
997 	/* modifier 'I' toggles the default disassembler type */
998 static int
999 mipsinst(Map *map, ulong pc, char modifier, char *buf, int n)
1000 {
1001 	if ((asstype == AMIPSCO && modifier == 'i')
1002 		|| (asstype == AMIPS && modifier == 'I'))
1003 		return _mipscoinst(map, pc, buf, n);
1004 	else
1005 		return printins(map, pc, buf, n);
1006 }
1007 
1008 static int
1009 mipsdas(Map *map, ulong pc, char *buf, int n)
1010 {
1011 	Instr i;
1012 
1013 	i.curr = buf;
1014 	i.end = buf+n;
1015 	mymap = map;
1016 	if (mkinstr(pc, &i) < 0)
1017 		return -1;
1018 	if (i.end-i.curr > 8)
1019 		i.curr = _hexify(buf, i.w0, 7);
1020 	if (i.size == 2 && i.end-i.curr > 9) {
1021 		*i.curr++ = ' ';
1022 		i.curr = _hexify(i.curr, i.w1, 7);
1023 	}
1024 	*i.curr = 0;
1025 	return i.size*4;
1026 }
1027 
1028 static int
1029 mipsinstlen(Map *map, ulong pc)
1030 {
1031 	Instr i;
1032 
1033 	mymap = map;
1034 	if (mkinstr(pc, &i) < 0)
1035 		return -1;
1036 	return i.size*4;
1037 }
1038 
1039 static int
1040 mipsfoll(Map *map, ulong pc, Rgetter rget, ulong *foll)
1041 {
1042 	ulong w, l;
1043 	char buf[8];
1044 	Instr i;
1045 
1046 	mymap = map;
1047 	if (mkinstr(pc, &i) < 0)
1048 		return -1;
1049 	w = i.w0;
1050 	if((w&0xF3600000) == 0x41000000){	/* branch on coprocessor */
1051     Conditional:
1052 		foll[0] = pc+8;
1053 		l = ((w&0xFFFF)<<2);
1054 		if(w & 0x8000)
1055 			l |= 0xFFFC0000;
1056 		foll[1] = pc+4 + l;
1057 		return 2;
1058 	}
1059 
1060 	l = (w&0xFC000000)>>26;
1061 	switch(l){
1062 	case 0:		/* SPECIAL */
1063 		if((w&0x3E) == 0x08){	/* JR, JALR */
1064 			sprint(buf, "R%d", (w>>21)&0x1F);
1065 			foll[0] = (*rget)(map, buf);
1066 			return 1;
1067 		}
1068 		foll[0] = pc+i.size*4;
1069 		return 1;
1070 	case 0x30:	/* Load-Linked followed by NOP, STC */
1071 		foll[0] = pc+12;
1072 		return 1;
1073 	case 1:		/* BCOND */
1074 	case 4:		/* BEQ */
1075 	case 5:		/* BNE */
1076 	case 6:		/* BLEZ */
1077 	case 7:		/* BGTZ */
1078 		goto Conditional;
1079 	case 2:		/* J */
1080 	case 3:		/* JAL */
1081 		foll[0] = (pc&0xF0000000) | ((w&0x03FFFFFF)<<2);
1082 		return 1;
1083 	}
1084 
1085 	foll[0] = pc+i.size*4;
1086 	return 1;
1087 }
1088