xref: /openbsd-src/sys/arch/mips64/mips64/db_disasm.c (revision 479c151d3429b7cfa6228ee428d945620629789d)
1 /*	$OpenBSD: db_disasm.c,v 1.21 2024/09/20 02:00:46 jsg Exp $	*/
2 
3 /*
4  * Copyright (c) 2010 Miodrag Vallat.
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 /*-
19  * Copyright (c) 1991, 1993
20  *	The Regents of the University of California.  All rights reserved.
21  *
22  * This code is derived from software contributed to Berkeley by
23  * Ralph Campbell.
24  *
25  * Redistribution and use in source and binary forms, with or without
26  * modification, are permitted provided that the following conditions
27  * are met:
28  * 1. Redistributions of source code must retain the above copyright
29  *    notice, this list of conditions and the following disclaimer.
30  * 2. Redistributions in binary form must reproduce the above copyright
31  *    notice, this list of conditions and the following disclaimer in the
32  *    documentation and/or other materials provided with the distribution.
33  * 3. All advertising materials mentioning features or use of this software
34  *    must display the following acknowledgement:
35  *	This product includes software developed by the University of
36  *	California, Berkeley and its contributors.
37  * 4. Neither the name of the University nor the names of its contributors
38  *    may be used to endorse or promote products derived from this software
39  *    without specific prior written permission.
40  *
41  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
42  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
45  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51  * SUCH DAMAGE.
52  *
53  *	from: @(#)kadb.c	8.1 (Berkeley) 6/10/93
54  *      $Id: db_disasm.c,v 1.21 2024/09/20 02:00:46 jsg Exp $
55  */
56 
57 #ifdef _KERNEL
58 #include <sys/param.h>
59 #include <sys/systm.h>
60 #else
61 #include <unistd.h>
62 #include <stdio.h>
63 #endif
64 
65 #ifdef _KERNEL
66 #include <machine/db_machdep.h>
67 #endif
68 #include <machine/mips_opcode.h>
69 #include <machine/regnum.h>
70 
71 #ifdef _KERNEL
72 #include <ddb/db_interface.h>
73 #include <ddb/db_output.h>
74 #include <ddb/db_sym.h>
75 #else
76 #define	db_printsym(addr,flags,fn)	(fn)("%p",addr)
77 #endif
78 
79 static const char *op_name[64] = {
80 	NULL,	/* OP_SPECIAL */
81 	NULL,	/* OP_BCOND */
82 	"j",
83 	"jal",
84 	"beq",
85 	"bne",
86 	"blez",
87 	"bgtz",
88 
89 	"addi",
90 	"addiu",
91 	"slti",
92 	"sltiu",
93 	"andi",
94 	"ori",
95 	"xori",
96 	"lui",
97 
98 	"cop0",
99 	"cop1",
100 	"cop2",
101 	"cop1x",
102 	"beql",
103 	"bnel",
104 	"blezl",
105 	"bgtzl",
106 
107 	"daddi",
108 	"daddiu",
109 	"ldl",
110 	"ldr",
111 	NULL,
112 	NULL,
113 	NULL,
114 	NULL,
115 
116 	"lb",
117 	"lh",
118 	"lwl",
119 	"lw",
120 	"lbu",
121 	"lhu",
122 	"lwr",
123 	"lwu",
124 
125 	"sb",
126 	"sh",
127 	"swl",
128 	"sw",
129 	"sdl",
130 	"sdr",
131 	"swr",
132 	"cache",
133 
134 	"ll",
135 	"lwc1",
136 	"lwc2",
137 	"pref",
138 	"lld",
139 	"ldc1",
140 	"ldc2",
141 	"ld",
142 
143 	"sc",
144 	"swc1",
145 	"swc2",
146 	"swc3",
147 	"scd",
148 	"sdc1",
149 	"sdc2",
150 	"sd"
151 };
152 
153 static const char *special_name[64] = {
154 	"sll",
155 	NULL,
156 	"srl",
157 	"sra",
158 	"sllv",
159 	NULL,
160 	"srlv",
161 	"srav",
162 
163 	"jr",
164 	"jalr",
165 	"movz",
166 	"movn",
167 	"syscall",
168 	"break",
169 	NULL,
170 	"sync",
171 
172 	"mfhi",
173 	"mthi",
174 	"mflo",
175 	"mtlo",
176 	"dsllv",
177 	NULL,
178 	"dsrlv",
179 	"dsrav",
180 
181 	"mult",
182 	"multu",
183 	"div",
184 	"divu",
185 	"dmult",
186 	"dmultu",
187 	"ddiv",
188 	"ddivu",
189 
190 	"add",
191 	"addu",
192 	"sub",
193 	"subu",
194 	"and",
195 	"or",
196 	"xor",
197 	"nor",
198 
199 	NULL,
200 	NULL,
201 	"slt",
202 	"sltu",
203 	"dadd",
204 	"daddu",
205 	"dsub",
206 	"dsubu",
207 
208 	"tge",
209 	"tgeu",
210 	"tlt",
211 	"tltu",
212 	"teq",
213 	NULL,
214 	"tne",
215 	NULL,
216 
217 	"dsll",
218 	NULL,
219 	"dsrl",
220 	"dsra",
221 	"dsll32",
222 	NULL,
223 	"dsrl32",
224 	"dsra32"
225 };
226 
227 static const char *bcond_name[32] = {
228 	"bltz",
229 	"bgez",
230 	"bltzl",
231 	"bgezl",
232 	NULL,
233 	NULL,
234 	NULL,
235 	NULL,
236 
237 	"tgei",
238 	"tgeiu",
239 	"tlti",
240 	"tltiu",
241 	"teqi",
242 	NULL,
243 	"tnei",
244 	NULL,
245 
246 	"bltzal",
247 	"bgezal",
248 	"bltzall",
249 	"bgezall",
250 	NULL,
251 	NULL,
252 	NULL,
253 	NULL,
254 
255 	NULL,
256 	NULL,
257 	NULL,
258 	NULL,
259 	NULL,
260 	NULL,
261 	NULL,
262 	"synci"
263 };
264 
265 static const char *cop_std[OP_MTH + 1] = {
266 	"mfc",
267 	"dmfc",
268 	"cfc",
269 	"mfhc",
270 	"mtc",
271 	"dmtc",
272 	"ctc",
273 	"mthc"
274 };
275 
276 static const char *cop1_name[64] = {
277 	"add",
278 	"sub",
279 	"mul",
280 	"div",
281 	"sqrt",
282 	"abs",
283 	"mov",
284 	"neg",
285 
286 	"round.l",
287 	"trunc.l",
288 	"ceil.l",
289 	"floor.l",
290 	"round.w",
291 	"trunc.w",
292 	"ceil.w",
293 	"floor.w",
294 
295 	NULL,
296 	NULL,	/* movf/movt */
297 	"movz",
298 	"movn",
299 	NULL,
300 	"recip",
301 	"rsqrt",
302 	NULL,
303 
304 	NULL,
305 	NULL,
306 	NULL,
307 	NULL,
308 	NULL,
309 	NULL,
310 	NULL,
311 	NULL,
312 
313 	"cvt.s",
314 	"cvt.d",
315 	NULL,
316 	NULL,
317 	"cvt.w",
318 	"cvt.l",
319 	NULL,
320 	NULL,
321 
322 	NULL,
323 	NULL,
324 	NULL,
325 	NULL,
326 	NULL,
327 	NULL,
328 	NULL,
329 	NULL,
330 
331 	"c.f",
332 	"c.un",
333 	"c.eq",
334 	"c.ueq",
335 	"c.olt",
336 	"c.ult",
337 	"c.ole",
338 	"c.ule",
339 
340 	"c.sf",
341 	"c.ngle",
342 	"c.seq",
343 	"c.ngl",
344 	"c.lt",
345 	"c.nge",
346 	"c.le",
347 	"c.ngt"
348 };
349 
350 static const char *fmt_name[16] = {
351 	"s",
352 	"d",
353 	NULL,
354 	NULL,
355 	"w",
356 	"l",
357 	NULL,
358 	NULL,
359 	NULL,
360 	NULL,
361 	NULL,
362 	NULL,
363 	NULL,
364 	NULL,
365 	NULL,
366 	NULL
367 };
368 
369 static const char *cop1x_op4[8] = {
370 	NULL,
371 	NULL,
372 	NULL,
373 	NULL,
374 	"madd",
375 	"msub",
376 	"nmadd",
377 	"nmsub"
378 };
379 
380 static const char *cop1x_std[32] = {
381 	"lwxc1",
382 	"ldxc1",
383 	NULL,
384 	NULL,
385 	NULL,
386 	NULL,
387 	NULL,
388 	NULL,
389 
390 	"swxc1",
391 	"sdxc1",
392 	NULL,
393 	NULL,
394 	NULL,
395 	NULL,
396 	NULL,
397 	"prefx",
398 
399 	NULL,
400 	NULL,
401 	NULL,
402 	NULL,
403 	NULL,
404 	NULL,
405 	NULL,
406 	NULL,
407 
408 	NULL,
409 	NULL,
410 	NULL,
411 	NULL,
412 	NULL,
413 	NULL,
414 	NULL,
415 	NULL
416 };
417 
418 static const char *reg_name[32] = {
419 	"zero",	"at",	"v0",	"v1",	"a0",	"a1",	"a2",	"a3",
420 	"a4",	"a5",	"a6",	"a7",	"t0",	"t1",	"t2",	"t3",
421 	"s0",	"s1",	"s2",	"s3",	"s4",	"s5",	"s6",	"s7",
422 	"t8",	"t9",	"k0",	"k1",	"gp",	"sp",	"s8",	"ra"
423 };
424 
425 static const char *cop0_miscname[64] = {
426 	NULL,
427 	"tlbr",
428 	"tlbwi",
429 	NULL,
430 	NULL,
431 	NULL,
432 	"tlbwr",
433 	NULL,
434 
435 	"tlbp",
436 	NULL,
437 	NULL,
438 	NULL,
439 	NULL,
440 	NULL,
441 	NULL,
442 	NULL,
443 
444 	NULL,	/* rfe */
445 	NULL,
446 	NULL,
447 	NULL,
448 	NULL,
449 	NULL,
450 	NULL,
451 	NULL,
452 
453 	"eret",
454 	NULL,
455 	NULL,
456 	NULL,
457 	NULL,
458 	NULL,
459 	NULL,
460 	NULL,
461 
462 	"wait"	/* RM5200 */
463 };
464 
465 static const char *cop0_tfp_miscname[64] = {
466 	NULL,
467 	"tlbr",
468 	"tlbw",
469 	NULL,
470 	NULL,
471 	NULL,
472 	"tlbwr",
473 	NULL,
474 
475 	"tlbp",
476 	"dctr",
477 	"dctw"
478 };
479 
480 static const char *cop0_reg0[32] = {
481 	"Index",
482 	"Random",
483 	"EntryLo0",
484 	"EntryLo1",
485 	"Context",
486 	"PageMask",
487 	"Wired",
488 	"Info",		/* RM7000 */
489 
490 	"BadVAddr",
491 	"Count",
492 	"EntryHi",
493 	"Compare",
494 	"Status",
495 	"Cause",
496 	"EPC",
497 	"PRId",
498 
499 	"Config",
500 	"LLAddr",
501 	"WatchLo",	/* RM7000 Watch1 */
502 	"WatchHi",	/* RM7000 Watch2 */
503 	"XContext",
504 	NULL,
505 	"PerfControl",	/* RM7000 */
506 	NULL,
507 
508 	"WatchMask",	/* RM7000 */
509 	"PerfCount",	/* RM7000 */
510 	"ECC",
511 	"CacheErr",
512 	"TagLo",
513 	"TagHi",
514 	"ErrorEPC",
515 	NULL
516 };
517 
518 static const char *cop0_reg1[32] = {
519 	NULL,
520 	NULL,
521 	NULL,
522 	NULL,
523 	NULL,
524 	NULL,
525 	NULL,
526 	NULL,
527 
528 	NULL,
529 	NULL,
530 	NULL,
531 	NULL,
532 	NULL,
533 	NULL,
534 	NULL,
535 	NULL,
536 
537 	NULL,
538 	NULL,
539 	"IPLLo",
540 	"IPLHi",
541 	"IntCtl",
542 	NULL,
543 	NULL,
544 	NULL,
545 
546 	NULL,
547 	NULL,
548 	"DErrAddr0",
549 	"DErrAddr1",
550 	NULL,
551 	NULL,
552 	NULL,
553 	NULL,
554 };
555 
556 int
557 dbmd_print_insn(uint32_t ins, vaddr_t mdbdot, int (*pr)(const char *, ...))
558 {
559 	InstFmt i;
560 	int delay = 0;
561 	const char *insn, *descr;
562 
563 	i.word = ins;
564 	insn = op_name[i.JType.op];
565 
566 	switch (i.JType.op) {
567 	case OP_SPECIAL:
568 		/* recognize nop/ssnop variants of sll early */
569 		if (i.word == 0) {
570 			(*pr)("nop");
571 			break;
572 		} else if (i.word == 1 << 6) {
573 			(*pr)("ssnop");
574 			break;
575 		}
576 
577 		/* display `daddu' involving zero as `move' */
578 		if (i.RType.func == OP_DADDU && i.RType.rt == 0) {
579 			(*pr)("move\t%s,%s",
580 			    reg_name[i.RType.rd], reg_name[i.RType.rs]);
581 			break;
582 		}
583 
584 		if (i.RType.func == OP_MOVCI) {
585 			(*pr)("mov%c\t%s,%s,%d",
586 			    i.RType.rt & 1 ? 't' : 'f',
587 			    reg_name[i.RType.rd], reg_name[i.RType.rs],
588 			    i.RType.rt >> 2);
589 			break;
590 		}
591 
592 		/* fix ambiguous opcode memonics */
593 		insn = special_name[i.RType.func];
594 		switch (i.RType.func) {
595 		case OP_SRL:
596 			if (i.RType.rs != 0)
597 				insn = "rotr";
598 			break;
599 		case OP_SRLV:
600 			if (i.RType.shamt != 0)
601 				insn = "rotrv";
602 			break;
603 		case OP_JR:
604 			if (i.RType.shamt != 0)
605 				insn = "jr.hb";
606 			break;
607 		case OP_JALR:
608 			if (i.RType.shamt != 0)
609 				insn = "jalr.hb";
610 			break;
611 		case OP_DSRL:
612 			if (i.RType.rs != 0)
613 				insn = "drotr";
614 			break;
615 		case OP_DSRLV:
616 			if (i.RType.shamt != 0)
617 				insn = "drotrv";
618 			break;
619 		}
620 
621 		if (insn == NULL)
622 			goto unknown;
623 		(*pr)("%s", insn);
624 
625 		switch (i.RType.func) {
626 		case OP_SLL:
627 		case OP_SRL:
628 		case OP_SRA:
629 		case OP_DSLL:
630 		case OP_DSRL:
631 		case OP_DSRA:
632 		case OP_DSLL32:
633 		case OP_DSRL32:
634 		case OP_DSRA32:
635 			(*pr)("\t%s,%s,%d",
636 			    reg_name[i.RType.rd], reg_name[i.RType.rt],
637 			    i.RType.shamt);
638 			break;
639 		case OP_SLLV:
640 		case OP_SRLV:
641 		case OP_SRAV:
642 		case OP_DSLLV:
643 		case OP_DSRLV:
644 		case OP_DSRAV:
645 			(*pr)("\t%s,%s,%s",
646 			    reg_name[i.RType.rd], reg_name[i.RType.rt],
647 			    reg_name[i.RType.rs]);
648 			break;
649 		case OP_MFHI:
650 		case OP_MFLO:
651 			(*pr)("\t%s", reg_name[i.RType.rd]);
652 			break;
653 		case OP_JALR:
654 			delay = 1;
655 			if (i.RType.rd != RA)
656 				(*pr)("\t%s,%s",
657 				    reg_name[i.RType.rd], reg_name[i.RType.rs]);
658 			else
659 				(*pr)("\t%s", reg_name[i.RType.rs]);
660 			break;
661 		case OP_JR:
662 			delay = 1;
663 			/* FALLTHROUGH */
664 		case OP_MTLO:
665 		case OP_MTHI:
666 			(*pr)("\t%s", reg_name[i.RType.rs]);
667 			break;
668 		case OP_MULT:
669 		case OP_MULTU:
670 		case OP_DIV:
671 		case OP_DIVU:
672 		case OP_DMULT:
673 		case OP_DMULTU:
674 		case OP_DDIV:
675 		case OP_DDIVU:
676 		case OP_TGE:
677 		case OP_TGEU:
678 		case OP_TLT:
679 		case OP_TLTU:
680 		case OP_TEQ:
681 		case OP_TNE:
682 			(*pr)("\t%s,%s",
683 			    reg_name[i.RType.rs], reg_name[i.RType.rt]);
684 			break;
685 		case OP_SYSCALL:
686 			if ((ins >> 6) != 0)
687 				(*pr)("\t%d", ins >> 6);
688 			break;
689 		case OP_SYNC:
690 			break;
691 		case OP_BREAK:
692 			(*pr)("\t%d", ins >> 16);
693 			break;
694 		case OP_MOVZ:
695 		case OP_MOVN:
696 		default:
697 			(*pr)("\t%s,%s,%s",
698 			    reg_name[i.RType.rd], reg_name[i.RType.rs],
699 			    reg_name[i.RType.rt]);
700 		}
701 		break;
702 
703 	case OP_BCOND:
704 		insn = bcond_name[i.IType.rt];
705 		if (insn == NULL)
706 			goto unknown;
707 		if (i.IType.rt == 31) {	/* synci */
708 			(*pr)("%s\t", insn);
709 			goto loadstore;
710 		}
711 		(*pr)("%s\t%s,", insn, reg_name[i.IType.rs]);
712 		if ((i.IType.rt & 0x18) == 0x08)	/* trap, not branch */
713 			(*pr)("%d", i.IType.imm);
714 		else
715 			goto pr_displ;
716 
717 	case OP_J:
718 	case OP_JAL:
719 		delay = 1;
720 		(*pr)("%s\t", insn);
721 		db_printsym((mdbdot & ~0x0fffffffUL) |
722 		    (vaddr_t)(i.JType.target << 2), DB_STGY_PROC, pr);
723 		break;
724 
725 	case OP_BEQ:
726 	case OP_BEQL:
727 		if (i.IType.rs == ZERO && i.IType.rt == ZERO) {
728 			(*pr)("b\t");
729 			goto pr_displ;
730 		}
731 		/* FALLTHROUGH */
732 	case OP_BNE:
733 	case OP_BNEL:
734 		if (i.IType.rt == ZERO) {
735 			if (i.IType.op == OP_BEQL || i.IType.op == OP_BNEL) {
736 				/* get the non-l opcode name */
737 				insn = op_name[i.IType.op & 0x07];
738 				(*pr)("%szl\t%s,", insn, reg_name[i.IType.rs]);
739 			} else
740 				(*pr)("%sz\t%s,", insn, reg_name[i.IType.rs]);
741 		} else
742 			(*pr)("%s\t%s,%s,", insn,
743 			    reg_name[i.IType.rs], reg_name[i.IType.rt]);
744 pr_displ:
745 		delay = 1;
746 		db_printsym(mdbdot + 4 + ((int16_t)i.IType.imm << 2),
747 		    DB_STGY_PROC, pr);
748 		break;
749 
750 	case OP_BLEZ:
751 	case OP_BGTZ:
752 	case OP_BLEZL:
753 	case OP_BGTZL:
754 		(*pr)("%s\t%s,", insn, reg_name[i.IType.rs]);
755 		goto pr_displ;
756 
757 	case OP_ADDI:
758 	case OP_ADDIU:
759 	case OP_DADDI:
760 	case OP_DADDIU:
761 		if (i.IType.rs == 0) {
762 			(*pr)("li\t%s,%d",
763 			    reg_name[i.IType.rt], (int16_t)i.IType.imm);
764 			break;
765 		}
766 		/* FALLTHROUGH */
767 	case OP_SLTI:
768 	case OP_SLTIU:
769 	default:
770 		if (insn != NULL)
771 			(*pr)("%s\t%s,%s,%d", insn,
772 			    reg_name[i.IType.rt], reg_name[i.IType.rs],
773 			    (int16_t)i.IType.imm);
774 		else {
775 unknown:
776 			(*pr)(".word\t%08x", ins);
777 		}
778 		break;
779 
780 	case OP_ORI:
781 	case OP_XORI:
782 		if (i.IType.rs == 0) {
783 			(*pr)("li\t%s,0x%x", reg_name[i.IType.rt], i.IType.imm);
784 			break;
785 		}
786 		/* FALLTHROUGH */
787 	case OP_ANDI:
788 		(*pr)("%s\t%s,%s,0x%x", insn,
789 		    reg_name[i.IType.rt], reg_name[i.IType.rs], i.IType.imm);
790 		break;
791 
792 	case OP_LUI:
793 		(*pr)("%s\t%s,0x%x", insn, reg_name[i.IType.rt], i.IType.imm);
794 		break;
795 
796 	case OP_COP0:
797 		switch (i.RType.rs) {
798 		case OP_MF:
799 		case OP_DMF:
800 		case OP_MT:
801 		case OP_DMT:
802 			if ((i.RType.func & 0x07) != 0) {
803 				insn = cop_std[i.RType.rs];
804 				descr = cop0_reg0[i.RType.rd];
805 				if (descr != NULL)
806 					(*pr)("%s0\t%s,%d,%d # %s.%d", insn,
807 					    reg_name[i.RType.rt], i.RType.rd,
808 					    i.RType.func & 0x07, descr,
809 					    i.RType.func & 0x07);
810 				else
811 					(*pr)("%s0\t%s,%d,%d", insn,
812 					    reg_name[i.RType.rt], i.RType.rd,
813 					    i.RType.func & 0x07);
814 				break;
815 			}
816 			/* FALLTHROUGH */
817 		case OP_CF:
818 		case OP_CT:
819 			insn = cop_std[i.RType.rs];
820 			if (i.RType.rs == OP_CF || i.RType.rs == OP_CT)
821 				descr = cop0_reg1[i.RType.rd];
822 			else
823 				descr = cop0_reg0[i.RType.rd];
824 			if (descr != NULL)
825 				(*pr)("%s0\t%s,%d # %s", insn,
826 				    reg_name[i.RType.rt], i.RType.rd, descr);
827 			else
828 				(*pr)("%s0\t%s,%d", insn,
829 				    reg_name[i.RType.rt], i.RType.rd);
830 			break;
831 		case OP_BC:
832 			(*pr)("bc0%c%c\t",
833 			    i.RType.rt & COPz_BC_TF_MASK ? 't' : 'f',
834 			    i.RType.rt & COPz_BCL_TF_MASK ? 'l' : ' ');
835 			goto pr_displ;
836 		case OP_C0MISC:
837 			if (i.FRType.func < nitems(cop0_miscname))
838 				insn = cop0_miscname[i.FRType.func];
839 			else
840 				insn = NULL;
841 			if (insn == NULL)
842 				goto unknown;
843 			else
844 				(*pr)("%s", insn);
845 			break;
846 		case OP_TFP_C0MISC:
847 			if (i.FRType.func < nitems(cop0_tfp_miscname))
848 				insn = cop0_tfp_miscname[i.FRType.func];
849 			else
850 				insn = NULL;
851 			if (insn == NULL)
852 				goto unknown;
853 			else
854 				(*pr)("%s", insn);
855 			break;
856 		default:
857 			goto unknown;
858 		}
859 		break;
860 
861 	case OP_COP1:
862 		switch (i.RType.rs) {
863 		case OP_MF:
864 		case OP_DMF:
865 		case OP_CF:
866 		case OP_MFH:
867 		case OP_MT:
868 		case OP_DMT:
869 		case OP_CT:
870 		case OP_MTH:
871 			insn = cop_std[i.RType.rs];
872 			(*pr)("%s1\t%s,f%d", insn,
873 			    reg_name[i.RType.rt], i.RType.rd);
874 			break;
875 		case OP_BC:
876 			(*pr)("bc1%c%c\t",
877 			    i.RType.rt & COPz_BC_TF_MASK ? 't' : 'f',
878 			    i.RType.rt & COPz_BCL_TF_MASK ? 'l' : ' ');
879 			goto pr_displ;
880 		default:
881 			if (fmt_name[i.FRType.fmt] == NULL)
882 				goto unknown;
883 			if (i.FRType.func == 0x11) {	/* movcf */
884 				insn = i.FRType.ft & 1 ? "movt" : "movf";
885 				(*pr)("%s.%s\tf%d,f%d,%d",
886 				    insn, fmt_name[i.FRType.fmt],
887 				    i.FRType.fd, i.FRType.fs, i.FRType.ft >> 2);
888 				break;
889 			 }
890 			insn = cop1_name[i.FRType.func];
891 			if (insn == NULL)
892 				goto unknown;
893 			(*pr)("%s.%s\tf%d,f%d,f%d",
894 			    insn, fmt_name[i.FRType.fmt],
895 			    i.FRType.fd, i.FRType.fs, i.FRType.ft);
896 		}
897 		break;
898 
899 	case OP_COP2:
900 		switch (i.RType.rs) {
901 		case OP_MF:
902 		case OP_DMF:
903 		case OP_CF:
904 		case OP_MFH:
905 		case OP_MT:
906 		case OP_DMT:
907 		case OP_CT:
908 		case OP_MTH:
909 			insn = cop_std[i.RType.rs];
910 			(*pr)("%s2\t%s,f%d", insn,
911 			    reg_name[i.RType.rt], i.RType.rd);
912 			break;
913 		case OP_BC:
914 			(*pr)("bc2%c%c\t",
915 			    i.RType.rt & COPz_BC_TF_MASK ? 't' : 'f',
916 			    i.RType.rt & COPz_BCL_TF_MASK ? 'l' : ' ');
917 			goto pr_displ;
918 		default:
919 			goto unknown;
920 		}
921 		break;
922 
923 	case OP_COP1X:
924 		switch (i.FQType.op4) {
925 		case OP_MADD:
926 		case OP_MSUB:
927 		case OP_NMADD:
928 		case OP_NMSUB:
929 			if (fmt_name[i.FQType.fmt3] == NULL)
930 				goto unknown;
931 			insn = cop1x_op4[i.FQType.op4];
932 			(*pr)("%s.%s\tf%d,f%d,f%d,f%d",
933 			    insn, fmt_name[i.FQType.fmt3],
934 			    i.FQType.fd, i.FQType.fr,
935 			    i.FQType.fs, i.FQType.ft);
936 			break;
937 		default:
938 			insn = cop1x_std[i.FRType.func];
939 			switch (i.FRType.func) {
940 			case OP_LWXC1:
941 			case OP_LDXC1:
942 				(*pr)("%s\tf%d,%s(%s)", insn,
943 				    i.FQType.fd, reg_name[i.FQType.ft],
944 				    reg_name[i.FQType.fr]);
945 				break;
946 			case OP_SWXC1:
947 			case OP_SDXC1:
948 				(*pr)("%s\tf%d,%s(%s)", insn,
949 				    i.FQType.fs, reg_name[i.FQType.ft],
950 				    reg_name[i.FQType.fr]);
951 				break;
952 			case OP_PREFX:
953 				(*pr)("%s\t%d,%s(%s)", insn,
954 				    i.FQType.fs, reg_name[i.FQType.ft],
955 				    reg_name[i.FQType.fr]);
956 				break;
957 			}
958 			break;
959 		}
960 		break;
961 
962 	case OP_LDL:
963 	case OP_LDR:
964 	case OP_LB:
965 	case OP_LH:
966 	case OP_LWL:
967 	case OP_LW:
968 	case OP_LBU:
969 	case OP_LHU:
970 	case OP_LWR:
971 	case OP_LWU:
972 	case OP_SB:
973 	case OP_SH:
974 	case OP_SWL:
975 	case OP_SW:
976 	case OP_SDL:
977 	case OP_SDR:
978 	case OP_SWR:
979 	case OP_LL:
980 	case OP_LLD:
981 	case OP_LD:
982 	case OP_SC:
983 	case OP_SCD:
984 	case OP_SD:
985 		(*pr)("%s\t%s,", insn, reg_name[i.IType.rt]);
986 loadstore:
987 		(*pr)("%d(%s)", (int16_t)i.IType.imm, reg_name[i.IType.rs]);
988 		break;
989 
990 	case OP_CACHE:
991 		(*pr)("%s\t0x%x,", insn, i.IType.rt);
992 		goto loadstore;
993 		break;
994 
995 	case OP_LWC1:
996 	case OP_LWC2:
997 	/* case OP_LWC3: superseded with OP_PREF */
998 	case OP_LDC1:
999 	case OP_LDC2:
1000 	case OP_SWC1:
1001 	case OP_SWC2:
1002 	case OP_SWC3:
1003 	case OP_SDC1:
1004 	case OP_SDC2:
1005 		(*pr)("%s\tf%d,", insn, i.IType.rt);
1006 		goto loadstore;
1007 
1008 	case OP_PREF:
1009 		(*pr)("%s\t%d,", insn, i.IType.rt);
1010 		goto loadstore;
1011 	}
1012 	(*pr)("\n");
1013 	return delay;
1014 }
1015 
1016 #ifdef _KERNEL
1017 vaddr_t
1018 db_disasm(vaddr_t loc, int altfmt)
1019 {
1020 	extern uint32_t kdbpeek(vaddr_t);
1021 
1022 	if (dbmd_print_insn(kdbpeek(loc), loc, db_printf)) {
1023 		loc += 4;
1024 		db_printsym(loc, DB_STGY_ANY, db_printf);
1025 		db_printf(":\t ");
1026 		dbmd_print_insn(kdbpeek(loc), loc, db_printf);
1027 	}
1028 	loc += 4;
1029 	return loc;
1030 }
1031 #else
1032 /*
1033  * Simple userspace test program (to confirm the logic never tries to print
1034  * NULL, to begin with...)
1035  */
1036 int
1037 main()
1038 {
1039 	uint32_t insn = 0;
1040 
1041 	do {
1042 		printf("%08x\t", insn);
1043 		dbmd_print_insn(insn, 0, printf);
1044 		insn++;
1045 		if ((insn & 0x00ffffff) == 0)
1046 			fprintf(stderr, "%08x\n", insn);
1047 	} while (insn != 0);
1048 
1049 	return 0;
1050 }
1051 #endif
1052