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