1/*	$OpenBSD: db_disasm.c,v 1.1 1998/03/16 09:03:24 pefo Exp $	*/
2/*-
3 * Copyright (c) 1991, 1993
4 *	The Regents of the University of California.  All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Ralph Campbell.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 *    must display the following acknowledgement:
19 *	This product includes software developed by the University of
20 *	California, Berkeley and its contributors.
21 * 4. Neither the name of the University nor the names of its contributors
22 *    may be used to endorse or promote products derived from this software
23 *    without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 *
37 *	from: @(#)kadb.c	8.1 (Berkeley) 6/10/93
38 *	Id: db_disasm.c,v 1.1 1998/03/16 09:03:24 pefo Exp
39 *	JNPR: db_disasm.c,v 1.1 2006/08/07 05:38:57 katta
40 */
41
42#include <sys/cdefs.h>
43__FBSDID("$FreeBSD$");
44
45#include <sys/param.h>
46#include <vm/vm_param.h>
47#include <vm/vm.h>
48#include <vm/pmap.h>
49#include <sys/systm.h>
50
51#include <machine/mips_opcode.h>
52#include <machine/db_machdep.h>
53#include <ddb/ddb.h>
54#include <ddb/db_output.h>
55
56static char *op_name[64] = {
57/* 0 */ "spec", "bcond","j",	"jal",	"beq",	"bne",	"blez",	"bgtz",
58/* 8 */ "addi", "addiu","slti",	"sltiu","andi",	"ori",	"xori",	"lui",
59/*16 */ "cop0", "cop1",	"cop2",	"cop3", "beql",	"bnel",	"blezl","bgtzl",
60/*24 */ "daddi","daddiu","ldl",	"ldr",	"op34",	"op35",	"op36",	"op37",
61/*32 */ "lb",	"lh",	"lwl",	"lw",	"lbu",	"lhu",	"lwr",	"lwu",
62/*40 */ "sb",	"sh",	"swl",	"sw",	"sdl",	"sdr",	"swr",	"cache",
63/*48 */ "ll",	"lwc1",	"lwc2",	"lwc3", "lld",	"ldc1",	"ldc2",	"ld",
64/*56 */ "sc",	"swc1",	"swc2",	"swc3", "scd",	"sdc1",	"sdc2",	"sd"
65};
66
67static char *spec_name[64] = {
68/* 0 */ "sll",	"spec01","srl", "sra",	"sllv",	"spec05","srlv","srav",
69/* 8 */ "jr",	"jalr",	"spec12","spec13","syscall","break","spec16","sync",
70/*16 */ "mfhi",	"mthi",	"mflo", "mtlo",	"dsllv","spec25","dsrlv","dsrav",
71/*24 */ "mult",	"multu","div",	"divu",	"dmult","dmultu","ddiv","ddivu",
72/*32 */ "add",	"addu",	"sub",	"subu",	"and",	"or",	"xor",	"nor",
73/*40 */ "spec50","spec51","slt","sltu",	"dadd","daddu","dsub","dsubu",
74/*48 */ "tge","tgeu","tlt","tltu","teq","spec65","tne","spec67",
75/*56 */ "dsll","spec71","dsrl","dsra","dsll32","spec75","dsrl32","dsra32"
76};
77
78static char *bcond_name[32] = {
79/* 0 */ "bltz",	"bgez",	"bltzl", "bgezl", "?", "?", "?", "?",
80/* 8 */ "tgei",	"tgeiu", "tlti", "tltiu", "teqi", "?", "tnei", "?",
81/*16 */ "bltzal", "bgezal", "bltzall", "bgezall", "?", "?", "?", "?",
82/*24 */ "?", "?", "?", "?", "?", "?", "?", "?",
83};
84
85static char *cop1_name[64] = {
86/* 0 */ "fadd",	"fsub",	"fmpy",	"fdiv",	"fsqrt","fabs",	"fmov",	"fneg",
87/* 8 */ "fop08","fop09","fop0a","fop0b","fop0c","fop0d","fop0e","fop0f",
88/*16 */ "fop10","fop11","fop12","fop13","fop14","fop15","fop16","fop17",
89/*24 */ "fop18","fop19","fop1a","fop1b","fop1c","fop1d","fop1e","fop1f",
90/*32 */ "fcvts","fcvtd","fcvte","fop23","fcvtw","fop25","fop26","fop27",
91/*40 */ "fop28","fop29","fop2a","fop2b","fop2c","fop2d","fop2e","fop2f",
92/*48 */ "fcmp.f","fcmp.un","fcmp.eq","fcmp.ueq","fcmp.olt","fcmp.ult",
93	"fcmp.ole","fcmp.ule",
94/*56 */ "fcmp.sf","fcmp.ngle","fcmp.seq","fcmp.ngl","fcmp.lt","fcmp.nge",
95	"fcmp.le","fcmp.ngt"
96};
97
98static char *fmt_name[16] = {
99	"s",	"d",	"e",	"fmt3",
100	"w",	"fmt5",	"fmt6",	"fmt7",
101	"fmt8",	"fmt9",	"fmta",	"fmtb",
102	"fmtc",	"fmtd",	"fmte",	"fmtf"
103};
104
105static char *reg_name[32] = {
106	"zero",	"at",	"v0",	"v1",	"a0",	"a1",	"a2",	"a3",
107	"t0",	"t1",	"t2",	"t3",	"t4",	"t5",	"t6",	"t7",
108	"s0",	"s1",	"s2",	"s3",	"s4",	"s5",	"s6",	"s7",
109	"t8",	"t9",	"k0",	"k1",	"gp",	"sp",	"s8",	"ra"
110};
111
112static char *c0_opname[64] = {
113	"c0op00","tlbr",  "tlbwi", "c0op03","c0op04","c0op05","tlbwr", "c0op07",
114	"tlbp",	"c0op11","c0op12","c0op13","c0op14","c0op15","c0op16","c0op17",
115	"rfe",	"c0op21","c0op22","c0op23","c0op24","c0op25","c0op26","c0op27",
116	"eret","c0op31","c0op32","c0op33","c0op34","c0op35","c0op36","c0op37",
117	"c0op40","c0op41","c0op42","c0op43","c0op44","c0op45","c0op46","c0op47",
118	"c0op50","c0op51","c0op52","c0op53","c0op54","c0op55","c0op56","c0op57",
119	"c0op60","c0op61","c0op62","c0op63","c0op64","c0op65","c0op66","c0op67",
120	"c0op70","c0op71","c0op72","c0op73","c0op74","c0op75","c0op77","c0op77",
121};
122
123static char *c0_reg[32] = {
124	"index","random","tlblo0","tlblo1","context","tlbmask","wired","c0r7",
125	"badvaddr","count","tlbhi","c0r11","sr","cause","epc",	"prid",
126	"config","lladr","watchlo","watchhi","xcontext","c0r21","c0r22","c0r23",
127	"c0r24","c0r25","ecc","cacheerr","taglo","taghi","errepc","c0r31"
128};
129
130static int md_printins(int ins, int mdbdot);
131
132db_addr_t
133db_disasm(db_addr_t loc, bool altfmt)
134
135{
136	int ins;
137
138	if (vtophys((vm_offset_t)loc)) {
139		db_read_bytes((vm_offset_t)loc, (size_t)sizeof(int),
140		    (char *)&ins);
141		md_printins(ins, loc);
142	}
143
144	return (loc + sizeof(int));
145}
146
147/* ARGSUSED */
148static int
149md_printins(int ins, int mdbdot)
150{
151	InstFmt i;
152	int delay = 0;
153
154	i.word = ins;
155
156	switch (i.JType.op) {
157	case OP_SPECIAL:
158		if (i.word == 0) {
159			db_printf("nop");
160			break;
161		}
162		if (i.RType.func == OP_ADDU && i.RType.rt == 0) {
163			db_printf("move\t%s,%s",
164			    reg_name[i.RType.rd], reg_name[i.RType.rs]);
165			break;
166		}
167		db_printf("%s", spec_name[i.RType.func]);
168		switch (i.RType.func) {
169		case OP_SLL:
170		case OP_SRL:
171		case OP_SRA:
172		case OP_DSLL:
173		case OP_DSRL:
174		case OP_DSRA:
175		case OP_DSLL32:
176		case OP_DSRL32:
177		case OP_DSRA32:
178			db_printf("\t%s,%s,%d", reg_name[i.RType.rd],
179			    reg_name[i.RType.rt], i.RType.shamt);
180			break;
181
182		case OP_SLLV:
183		case OP_SRLV:
184		case OP_SRAV:
185		case OP_DSLLV:
186		case OP_DSRLV:
187		case OP_DSRAV:
188			db_printf("\t%s,%s,%s", reg_name[i.RType.rd],
189			    reg_name[i.RType.rt], reg_name[i.RType.rs]);
190			break;
191
192		case OP_MFHI:
193		case OP_MFLO:
194			db_printf("\t%s", reg_name[i.RType.rd]);
195			break;
196
197		case OP_JR:
198		case OP_JALR:
199			delay = 1;
200			/* FALLTHROUGH */
201		case OP_MTLO:
202		case OP_MTHI:
203			db_printf("\t%s", reg_name[i.RType.rs]);
204			break;
205
206		case OP_MULT:
207		case OP_MULTU:
208		case OP_DMULT:
209		case OP_DMULTU:
210		case OP_DIV:
211		case OP_DIVU:
212		case OP_DDIV:
213		case OP_DDIVU:
214			db_printf("\t%s,%s",
215			    reg_name[i.RType.rs], reg_name[i.RType.rt]);
216			break;
217
218		case OP_SYSCALL:
219		case OP_SYNC:
220			break;
221
222		case OP_BREAK:
223			db_printf("\t%d", (i.RType.rs << 5) | i.RType.rt);
224			break;
225
226		default:
227			db_printf("\t%s,%s,%s", reg_name[i.RType.rd],
228			    reg_name[i.RType.rs], reg_name[i.RType.rt]);
229		}
230		break;
231
232	case OP_BCOND:
233		db_printf("%s\t%s,", bcond_name[i.IType.rt],
234		    reg_name[i.IType.rs]);
235		goto pr_displ;
236
237	case OP_BLEZ:
238	case OP_BLEZL:
239	case OP_BGTZ:
240	case OP_BGTZL:
241		db_printf("%s\t%s,", op_name[i.IType.op],
242		    reg_name[i.IType.rs]);
243		goto pr_displ;
244
245	case OP_BEQ:
246	case OP_BEQL:
247		if (i.IType.rs == 0 && i.IType.rt == 0) {
248			db_printf("b\t");
249			goto pr_displ;
250		}
251		/* FALLTHROUGH */
252	case OP_BNE:
253	case OP_BNEL:
254		db_printf("%s\t%s,%s,", op_name[i.IType.op],
255		    reg_name[i.IType.rs], reg_name[i.IType.rt]);
256	pr_displ:
257		delay = 1;
258		db_printf("0x%08x", mdbdot + 4 + ((short)i.IType.imm << 2));
259		break;
260
261	case OP_COP0:
262		switch (i.RType.rs) {
263		case OP_BCx:
264		case OP_BCy:
265			db_printf("bc0%c\t",
266			    "ft"[i.RType.rt & COPz_BC_TF_MASK]);
267			goto pr_displ;
268
269		case OP_MT:
270			db_printf("mtc0\t%s,%s",
271			    reg_name[i.RType.rt], c0_reg[i.RType.rd]);
272			break;
273
274		case OP_DMT:
275			db_printf("dmtc0\t%s,%s",
276			    reg_name[i.RType.rt], c0_reg[i.RType.rd]);
277			break;
278
279		case OP_MF:
280			db_printf("mfc0\t%s,%s",
281			    reg_name[i.RType.rt], c0_reg[i.RType.rd]);
282			break;
283
284		case OP_DMF:
285			db_printf("dmfc0\t%s,%s",
286			    reg_name[i.RType.rt], c0_reg[i.RType.rd]);
287			break;
288
289		default:
290			db_printf("%s", c0_opname[i.FRType.func]);
291		}
292		break;
293
294	case OP_COP1:
295		switch (i.RType.rs) {
296		case OP_BCx:
297		case OP_BCy:
298			db_printf("bc1%c\t",
299			    "ft"[i.RType.rt & COPz_BC_TF_MASK]);
300			goto pr_displ;
301
302		case OP_MT:
303			db_printf("mtc1\t%s,f%d",
304			    reg_name[i.RType.rt], i.RType.rd);
305			break;
306
307		case OP_MF:
308			db_printf("mfc1\t%s,f%d",
309			    reg_name[i.RType.rt], i.RType.rd);
310			break;
311
312		case OP_CT:
313			db_printf("ctc1\t%s,f%d",
314			    reg_name[i.RType.rt], i.RType.rd);
315			break;
316
317		case OP_CF:
318			db_printf("cfc1\t%s,f%d",
319			    reg_name[i.RType.rt], i.RType.rd);
320			break;
321
322		default:
323			db_printf("%s.%s\tf%d,f%d,f%d",
324			    cop1_name[i.FRType.func], fmt_name[i.FRType.fmt],
325			    i.FRType.fd, i.FRType.fs, i.FRType.ft);
326		}
327		break;
328
329	case OP_J:
330	case OP_JAL:
331		db_printf("%s\t", op_name[i.JType.op]);
332		db_printf("0x%8x",(mdbdot & 0xF0000000) | (i.JType.target << 2));
333		delay = 1;
334		break;
335
336	case OP_LWC1:
337	case OP_SWC1:
338		db_printf("%s\tf%d,", op_name[i.IType.op], i.IType.rt);
339		goto loadstore;
340
341	case OP_LB:
342	case OP_LH:
343	case OP_LW:
344	case OP_LD:
345	case OP_LBU:
346	case OP_LHU:
347	case OP_LWU:
348	case OP_SB:
349	case OP_SH:
350	case OP_SW:
351	case OP_SD:
352		db_printf("%s\t%s,", op_name[i.IType.op],
353		    reg_name[i.IType.rt]);
354	loadstore:
355		db_printf("%d(%s)", (short)i.IType.imm, reg_name[i.IType.rs]);
356		break;
357
358	case OP_ORI:
359	case OP_XORI:
360		if (i.IType.rs == 0) {
361			db_printf("li\t%s,0x%x",
362			    reg_name[i.IType.rt], i.IType.imm);
363			break;
364		}
365		/* FALLTHROUGH */
366	case OP_ANDI:
367		db_printf("%s\t%s,%s,0x%x", op_name[i.IType.op],
368		    reg_name[i.IType.rt], reg_name[i.IType.rs], i.IType.imm);
369		break;
370
371	case OP_LUI:
372		db_printf("%s\t%s,0x%x", op_name[i.IType.op],
373		    reg_name[i.IType.rt], i.IType.imm);
374		break;
375
376	case OP_ADDI:
377	case OP_DADDI:
378	case OP_ADDIU:
379	case OP_DADDIU:
380		if (i.IType.rs == 0) {
381			db_printf("li\t%s,%d", reg_name[i.IType.rt],
382			    (short)i.IType.imm);
383			break;
384		}
385		/* FALLTHROUGH */
386	default:
387		db_printf("%s\t%s,%s,%d", op_name[i.IType.op],
388		    reg_name[i.IType.rt], reg_name[i.IType.rs],
389		    (short)i.IType.imm);
390	}
391	db_printf("\n");
392	return (delay);
393}
394