xref: /openbsd-src/sys/arch/m88k/m88k/db_disasm.c (revision 36fd90dcf1acf2ddb4ef5dbabe5313b3a8d46ee2)
1 /*	$OpenBSD: db_disasm.c,v 1.12 2021/03/11 11:16:58 jsg Exp $	*/
2 /*
3  * Copyright (c) 2006, Miodrag Vallat
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
18  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
22  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
23  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24  * POSSIBILITY OF SUCH DAMAGE.
25  */
26 /*
27  * Mach Operating System
28  * Copyright (c) 1993-1991 Carnegie Mellon University
29  * Copyright (c) 1991 OMRON Corporation
30  * All Rights Reserved.
31  *
32  * Permission to use, copy, modify and distribute this software and its
33  * documentation is hereby granted, provided that both the copyright
34  * notice and this permission notice appear in all copies of the
35  * software, derivative works or modified versions, and any portions
36  * thereof, and that both notices appear in supporting documentation.
37  *
38  * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS"
39  * CONDITION.  CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND
40  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
41  *
42  * Carnegie Mellon requests users of this software to return to
43  *
44  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
45  *  School of Computer Science
46  *  Carnegie Mellon University
47  *  Pittsburgh PA 15213-3890
48  *
49  * any improvements or extensions that they make and grant Carnegie the
50  * rights to redistribute these changes.
51  */
52 
53 /*
54  * m88k disassembler for use in ddb
55  */
56 
57 #include <sys/param.h>
58 #include <sys/systm.h>
59 
60 #include <machine/db_machdep.h>
61 
62 #include <ddb/db_sym.h>		/* DB_STGY_PROC, db_printsym() */
63 #include <ddb/db_access.h>	/* db_get_value() */
64 #include <ddb/db_output.h>	/* db_printf() */
65 #include <ddb/db_interface.h>
66 
67 int	oimmed(int, u_int32_t, const char *, vaddr_t);
68 int	ctrlregs(int, u_int32_t, const char *, vaddr_t);
69 int	sindou(int, u_int32_t, const char *, vaddr_t);
70 int	jump(int, u_int32_t, const char *, vaddr_t);
71 int	instset(int, u_int32_t, const char *, vaddr_t);
72 int	obranch(int, u_int32_t, const char *, vaddr_t);
73 int	brcond(int, u_int32_t, const char *, vaddr_t);
74 int	otrap(int, u_int32_t, const char *, vaddr_t);
75 int	obit(int, u_int32_t, const char *, vaddr_t);
76 int	bitman(int, u_int32_t, const char *, vaddr_t);
77 int	immem(int, u_int32_t, const char *, vaddr_t);
78 int	nimmem(int, u_int32_t, const char *, vaddr_t);
79 int	lognim(int, u_int32_t, const char *, vaddr_t);
80 int	onimmed(int, u_int32_t, const char *, vaddr_t);
81 int	pinst(int, u_int32_t, const char *, vaddr_t);
82 
83 void	printcmp(int, u_int);
84 void	symofset(u_int, u_int, vaddr_t);
85 const char *cregname(int, u_int, u_int);
86 
87 /*
88  * Common instruction modifiers
89  */
90 
91 static const char *instwidth[] = {
92 	".d", "  ", ".h", ".b", ".x"	/* see nimmem() for use of last value */
93 };
94 static const char *xinstwidth[4] = {
95 	".d", "  ", ".x", ".?"
96 };
97 static const char *cmpname[0x20] = {
98 	NULL,
99 	NULL,
100 	"eq",
101 	"ne",
102 	"gt",
103 	"le",
104 	"lt",
105 	"ge",
106 	"hi",
107 	"ls",
108 	"lo",
109 	"hs",
110 	"be",
111 	"nb",
112 	"he",
113 	"nh"
114 };
115 static const char *condname[0x20] = {
116 	NULL,
117 	"gt",	/* 00001 */
118 	"eq",	/* 00010 */
119 	"ge",	/* 00011 */
120 	NULL,
121 	NULL,
122 	NULL,
123 	NULL,
124 	NULL,
125 	NULL,
126 	NULL,
127 	NULL,
128 	"lt",	/* 01100 */
129 	"ne",	/* 01101 */
130 	"le"	/* 01110 */
131 };
132 static const char sodname[4] = "sdx?";
133 
134 /*
135  * Descriptive control register names
136  */
137 
138 static const char *m88100_ctrlreg[2][64] = {
139 	{	/* main unit */
140 		"PID",
141 		"PSR",
142 		"EPSR",
143 		"SSBR",
144 		"SXIP",
145 		"SNIP",
146 		"SFIP",
147 		"VBR",
148 		"DMT0",
149 		"DMD0",
150 		"DMA0",
151 		"DMT1",
152 		"DMD1",
153 		"DMA1",
154 		"DMT2",
155 		"DMD2",
156 		"DMA2",
157 		"SR0",
158 		"SR1",
159 		"SR2",
160 		"SR3",
161 	},
162 	{	/* SFU1 = FPU */
163 		"FPECR",
164 		"FPHS1",
165 		"FPLS1",
166 		"FPHS2",
167 		"FPLS2",
168 		"FPPT",
169 		"FPRH",
170 		"FPRL",
171 		"FPIT",
172 		NULL, NULL,
173 		NULL, NULL, NULL, NULL, NULL,
174 		NULL, NULL, NULL, NULL, NULL,
175 		NULL, NULL, NULL, NULL, NULL,
176 		NULL, NULL, NULL, NULL, NULL,
177 		NULL, NULL, NULL, NULL, NULL,
178 		NULL, NULL, NULL, NULL, NULL,
179 		NULL, NULL, NULL, NULL, NULL,
180 		NULL, NULL, NULL, NULL, NULL,
181 		NULL, NULL, NULL, NULL, NULL,
182 		NULL, NULL, NULL, NULL, NULL,
183 		NULL,
184 		"FPSR",
185 		"FPCR"
186 	}
187 };
188 
189 static const char *m88110_ctrlreg[2][64] = {
190 	{	/* main unit */
191 		"PID",
192 		"PSR",
193 		"EPSR",
194 		NULL,
195 		"EXIP",
196 		"ENIP",
197 		NULL,
198 		"VBR",
199 		NULL,
200 		NULL,
201 		NULL,
202 		NULL,
203 		NULL,
204 		NULL,
205 		"RES1",
206 		"RES2",
207 		"SRX",
208 		"SR0",
209 		"SR1",
210 		"SR2",
211 		"SR3",
212 		NULL,
213 		NULL,
214 		NULL,
215 		NULL,
216 		"ICMD",
217 		"ICTL",
218 		"ISAR",
219 		"ISAP",
220 		"IUAP",
221 		"IIR",
222 		"IBP",
223 		"IPPU",
224 		"IPPL",
225 		"ISR",
226 		"ILAR",
227 		"IPAR",
228 		NULL,
229 		NULL,
230 		NULL,
231 		"DCMD",
232 		"DCTL",
233 		"DSAR",
234 		"DSAP",
235 		"DUAP",
236 		"DIR",
237 		"DBP",
238 		"DPPU",
239 		"DPPL",
240 		"DSR",
241 		"DLAR",
242 		"DPAR",
243 	},
244 	{	/* SFU1 = FPU */
245 		"FPECR",
246 		NULL, NULL, NULL, NULL, NULL,
247 		NULL, NULL, NULL, NULL, NULL,
248 		NULL, NULL, NULL, NULL, NULL,
249 		NULL, NULL, NULL, NULL, NULL,
250 		NULL, NULL, NULL, NULL, NULL,
251 		NULL, NULL, NULL, NULL, NULL,
252 		NULL, NULL, NULL, NULL, NULL,
253 		NULL, NULL, NULL, NULL, NULL,
254 		NULL, NULL, NULL, NULL, NULL,
255 		NULL, NULL, NULL, NULL, NULL,
256 		NULL, NULL, NULL, NULL, NULL,
257 		NULL, NULL, NULL, NULL, NULL,
258 		NULL,
259 		"FPSR",
260 		"FPCR"
261 	}
262 };
263 
264 /* print a comparison code */		/* XXX favors cmp vs fcmp or pcmp */
265 void
printcmp(int cpu,u_int code)266 printcmp(int cpu, u_int code)
267 {
268 	const char *cmp;
269 
270 	if (cpu == CPU_88100 && code > 11)
271 		cmp = NULL;
272 	else
273 		cmp = cmpname[code];
274 	if (cmp != NULL)
275 		db_printf("%s(%d)", cmp, code);
276 	else
277 		db_printf("%d", code);
278 }
279 
280 const char *
cregname(int cpu,u_int sfu,u_int regno)281 cregname(int cpu, u_int sfu, u_int regno)
282 {
283 	static char regbuf[20];
284 	const char *regname;
285 
286 	switch (sfu) {
287 	case 0:	/* main unit */
288 	case 1:	/* SFU1 = FPU */
289 		regname = cpu != CPU_88100 ?
290 		    m88110_ctrlreg[sfu][regno] : m88100_ctrlreg[sfu][regno];
291 		if (regname == NULL)
292 			snprintf(regbuf, sizeof regbuf,
293 			    sfu == 0 ? "cr%d" : "fcr%d", regno);
294 		else
295 			snprintf(regbuf, sizeof regbuf,
296 			    sfu == 0 ? "cr%d (%s)" : "fcr%d (%s)",
297 			    regno, regname);
298 		break;
299 	default:	/* can't happen */
300 		snprintf(regbuf, sizeof regbuf, "sfu%dcr%d", sfu, regno);
301 		break;
302 	}
303 
304 	return (regbuf);
305 }
306 
307 void
symofset(u_int disp,u_int bit,vaddr_t iadr)308 symofset(u_int disp, u_int bit, vaddr_t iadr)
309 {
310 	vaddr_t addr;
311 
312 	if (disp & (1 << (bit - 1))) {
313 		/* negative value */
314 		addr = iadr + ((disp << 2) | (~0U << bit));
315 	} else {
316 		addr = iadr + (disp << 2);
317 	}
318 	db_printsym(addr, DB_STGY_PROC, db_printf);
319 }
320 
321 /* Handles immediate integer arithmetic instructions */
322 int
oimmed(int cpu,u_int32_t inst,const char * opcode,vaddr_t iadr)323 oimmed(int cpu, u_int32_t inst, const char *opcode, vaddr_t iadr)
324 {
325 	int32_t Linst = inst & 0xffff;
326 	u_int32_t H6inst = inst >> 26;
327 	u_int32_t rs1 = (inst >> 16) & 0x1f;
328 	u_int32_t rd = (inst >> 21) & 0x1f;
329 
330 	switch (H6inst) {
331 	case 0x11:	/* and.u */
332 	case 0x13:	/* mask.u */
333 	case 0x15:	/* xor.u */
334 	case 0x17:	/* or.u */
335 		db_printf("\t%s.u", opcode);
336 		break;
337 	default:
338 		db_printf("\t%s  ", opcode);
339 		break;
340 	}
341 	db_printf("\t\tr%d, r%d, 0x%04x", rd, rs1, Linst);
342 
343 	return (1);
344 }
345 
346 /* Handles instructions dealing with control registers */
347 int
ctrlregs(int cpu,u_int32_t inst,const char * opcode,vaddr_t iadr)348 ctrlregs(int cpu, u_int32_t inst, const char *opcode, vaddr_t iadr)
349 {
350 	u_int32_t dir = (inst >> 14) & 0x03;
351 	u_int32_t sfu = (inst >> 11) & 0x07;
352 	u_int32_t creg = (inst >> 5) & 0x3f;
353 	u_int32_t rd = (inst >> 21) & 0x1f;
354 	u_int32_t rs1 = (inst >> 16) & 0x1f;
355 	u_int32_t rs2 = (inst >> 0) & 0x1f;
356 
357 	/* s1 and s2 must match on {,f}{st,x}cr instructions */
358 	if (rs1 != rs2 && (dir == 0x02 || dir == 0x03))
359 		return (0);
360 
361 	db_printf("\t%s\t\t", opcode);
362 
363 	switch (dir) {
364 	case 0x01:	/* ldcr, fldcr */
365 		db_printf("r%d, %s", rd, cregname(cpu, sfu, creg));
366 		break;
367 	case 0x02:	/* stcr, fstcr */
368 		db_printf("r%d, %s", rs1, cregname(cpu, sfu, creg));
369 		break;
370 	default:
371 	case 0x03:	/* xcr, fxcr */
372 		db_printf("r%d, r%d, %s",
373 		    rd, rs1, cregname(cpu, sfu, creg));
374 		break;
375 	}
376 
377 	return (1);
378 }
379 
380 /* Handles floating point instructions */
381 int
sindou(int cpu,u_int32_t inst,const char * opcode,vaddr_t iadr)382 sindou(int cpu, u_int32_t inst, const char *opcode, vaddr_t iadr)
383 {
384 	u_int32_t rs2 = inst & 0x1f;
385 	u_int32_t td = (inst >> 5) & 0x03;
386 	u_int32_t t2 = (inst >> 7) & 0x03;
387 	u_int32_t t1 = (inst >> 9) & 0x03;
388 	u_int32_t rs1 = (inst >> 16) & 0x1f;
389 	u_int32_t rd = (inst >> 21) & 0x1f;
390 	u_int32_t checkbits = (inst >> 11) & 0x0f;
391 	u_int32_t rf = (inst >> 15) & 0x01;
392 
393 	/* do not display a specific fcmpu.s encoding as non-existing fcmpu.d */
394 	if (checkbits == 0x07)
395 		td = 0;
396 
397 	/* do not display dot modifiers for mov.x */
398 	if (checkbits == 0x08) {
399 		db_printf("\t%s", opcode);
400 	} else {
401 		db_printf("\t%s.%c", opcode, sodname[td]);
402 	}
403 
404 	switch (checkbits) {
405 	default:
406 	case 0x00:	/* fmul */
407 	case 0x05:	/* fadd */
408 	case 0x06:	/* fsub */
409 	case 0x0e:	/* fdiv */
410 		db_printf("%c%c\t\t", sodname[t1], sodname[t2]);
411 		if (rf != 0)
412 			db_printf("x%d,x%d,x%d", rd, rs1, rs2);
413 		else
414 			db_printf("r%d,r%d,r%d", rd, rs1, rs2);
415 		break;
416 	case 0x01:	/* fcvt */
417 	case 0x0f:	/* fsqrt */
418 		db_printf("%c \t\t", sodname[t2]);
419 		if (rf != 0)
420 			db_printf("x%d, x%d", rd, rs2);
421 		else
422 			db_printf("r%d, r%d", rd, rs2);
423 		break;
424 	case 0x04:	/* flt */
425 		db_printf("%c \t\t", sodname[t2]);
426 		if ((inst & 0x200) != 0)	/* does not use the RF bit... */
427 			db_printf("x%d, x%d", rd, rs2);
428 		else
429 			db_printf("r%d, r%d", rd, rs2);
430 		break;
431 	case 0x07:	/* fcmp, fcmpu */
432 		db_printf("%c%c\t\t", sodname[t1], sodname[t2]);
433 		db_printf("r%d, ", rd);
434 		if (rf != 0)
435 			db_printf("x%d, x%d", rs1, rs2);
436 		else
437 			db_printf("r%d, r%d", rs1, rs2);
438 		break;
439 	case 0x08:	/* mov */
440 		if (rf != 0 && t1 == 0x01) {	/* mov.x, displayed as mov */
441 			db_printf("   \t\t");
442 			db_printf("x%d, x%d", rd, rs2);
443 		} else {
444 			db_printf(".%c \t\t", sodname[t2]);
445 
446 			if (t1 == 0)
447 				db_printf("r%d, x%d", rd, rs2);
448 			else
449 				db_printf("x%d, r%d", rd, rs2);
450 		}
451 		break;
452 	case 0x09:	/* int */
453 	case 0x0a:	/* nint */
454 	case 0x0b:	/* trnc */
455 		db_printf("%c \t\t", sodname[t2]);
456 		if (rf != 0)
457 			db_printf("r%d, x%d", rd, rs2);
458 		else
459 			db_printf("r%d, r%d", rd, rs2);
460 		break;
461 	}
462 
463 	return (1);
464 }
465 
466 int
jump(int cpu,u_int32_t inst,const char * opcode,vaddr_t iadr)467 jump(int cpu, u_int32_t inst, const char *opcode, vaddr_t iadr)
468 {
469 	u_int32_t rs2 = inst & 0x1f;
470 
471 	db_printf("\t%s", opcode);
472 	if ((inst & (1 << 10)) != 0)
473 		db_printf(".n");
474 	else
475 		db_printf("  ");
476 	db_printf("\t\tr%d", rs2);
477 
478 	return (1);
479 }
480 
481 /* Handles ff1, ff0, tbnd and rte instructions */
482 int
instset(int cpu,u_int32_t inst,const char * opcode,vaddr_t iadr)483 instset(int cpu, u_int32_t inst, const char *opcode, vaddr_t iadr)
484 {
485 	u_int32_t rs2 = inst & 0x1f;
486 	u_int32_t rs1 = (inst >> 16) & 0x1f;
487 	u_int32_t rd = (inst >> 21) & 0x1f;
488 	u_int32_t checkbits = (inst >> 10) & 0x3f;
489 	u_int32_t H6inst = (inst >> 26) & 0x3f;
490 
491 	db_printf("\t%s", opcode);
492 	if (H6inst == 0x3e) { /* tbnd with imm16 */
493 		db_printf("\t\tr%d, 0x%04x", rs1, inst & 0xffff);
494 	} else {
495 		switch (checkbits) {
496 		case 0x3a:	/* ff1 */
497 		case 0x3b:	/* ff0 */
498 			db_printf("\t\tr%d,r%d", rd, rs2);
499 			break;
500 		case 0x3e:	/* tbnd */
501 			db_printf("\t\tr%d,r%d", rs1, rs2);
502 			break;
503 		case 0x3f:	/* rte, illop */
504 			if (rs2 != 0)
505 				db_printf("%d", rs2);
506 			break;
507 		}
508 	}
509 
510 	return (1);
511 }
512 
513 /* Handles unconditional branches */
514 int
obranch(int cpu,u_int32_t inst,const char * opcode,vaddr_t iadr)515 obranch(int cpu, u_int32_t inst, const char *opcode, vaddr_t iadr)
516 {
517 	u_int32_t disp = inst & 0x3ffffff;
518 
519 	db_printf("\t%s", opcode);
520 	if ((inst & (1 << 26)) != 0)
521 		db_printf(".n");
522 	else
523 		db_printf("  ");
524 	db_printf("\t\t");
525 	symofset(disp, 26, iadr);
526 
527 	return (1);
528 }
529 
530 /* Handles branch on conditions instructions */
531 int
brcond(int cpu,u_int32_t inst,const char * opcode,vaddr_t iadr)532 brcond(int cpu, u_int32_t inst, const char *opcode, vaddr_t iadr)
533 {
534 	u_int32_t match = (inst >> 21) & 0x1f;
535 	u_int32_t rs = (inst >> 16) & 0x1f;
536 	u_int32_t disp = inst & 0xffff;
537 	int bcnd = ((inst >> 27) & 0x03) == 1;
538 
539 	/* skip invalid conditions if bcnd */
540 	if (bcnd && condname[match] == NULL)
541 		return (0);
542 
543 	db_printf("\t%s", opcode);
544 	if ((inst & (1 << 26)) != 0)
545 		db_printf(".n");
546 	else
547 		db_printf("  ");
548 	db_printf("\t\t");
549 
550 	if (bcnd)
551 		db_printf("%s0", condname[match]);
552 	else
553 		printcmp(cpu, match);
554 
555 	db_printf(", r%d, ", rs);
556 	symofset(disp, 16, iadr);
557 
558 	return (1);
559 }
560 
561 /* Handles trap instructions */
562 int
otrap(int cpu,u_int32_t inst,const char * opcode,vaddr_t iadr)563 otrap(int cpu, u_int32_t inst, const char *opcode, vaddr_t iadr)
564 {
565 	u_int32_t vecno = inst & 0x1ff;
566 	u_int32_t match = (inst >> 21) & 0x1f;
567 	u_int32_t rs = (inst >> 16) & 0x1f;
568 	int tcnd = ((inst >> 12) & 0x0f) == 0xe;
569 
570 	/* skip invalid conditions if tcnd */
571 	if (tcnd && condname[match] == NULL)
572 		return (0);
573 
574 	db_printf("\t%s\t", opcode);
575 	if (tcnd)
576 		db_printf("%s0", condname[match]);
577 	else
578 		printcmp(cpu, match);
579 	db_printf(", r%d, 0x%x", rs, vecno);
580 
581 	return (1);
582 }
583 
584 /* Handles 10 bit immediate bit field operations */
585 int
obit(int cpu,u_int32_t inst,const char * opcode,vaddr_t iadr)586 obit(int cpu, u_int32_t inst, const char *opcode, vaddr_t iadr)
587 {
588 	u_int32_t rs = (inst >> 16) & 0x1f;
589 	u_int32_t rd = (inst >> 21) & 0x1f;
590 	u_int32_t width = (inst >> 5) & 0x1f;
591 	u_int32_t offset = inst & 0x1f;
592 
593 	db_printf("\t%s\t\tr%d, r%d, ", opcode, rd, rs);
594 	if (((inst >> 10) & 0x3f) != 0x2a)	/* rot */
595 		db_printf("%d", width);
596 	db_printf("<%d>", offset);
597 
598 	return (1);
599 }
600 
601 /* Handles triadic mode bit field instructions */
602 int
bitman(int cpu,u_int32_t inst,const char * opcode,vaddr_t iadr)603 bitman(int cpu, u_int32_t inst, const char *opcode, vaddr_t iadr)
604 {
605 	u_int32_t rs1 = (inst >> 16) & 0x1f;
606 	u_int32_t rd = (inst >> 21) & 0x1f;
607 	u_int32_t rs2 = inst & 0x1f;
608 
609 	db_printf("\t%s\t\tr%d, r%d, r%d", opcode, rd, rs1, rs2);
610 
611 	return (1);
612 }
613 
614 /* Handles immediate load/store/exchange instructions */
615 int
immem(int cpu,u_int32_t inst,const char * opcode,vaddr_t iadr)616 immem(int cpu, u_int32_t inst, const char *opcode, vaddr_t iadr)
617 {
618 	u_int32_t rd = (inst >> 21) & 0x1f;
619 	u_int32_t rs = (inst >> 16) & 0x1f;
620 	u_int32_t st_lda = (inst >> 28) & 0x03;
621 	u_int32_t aryno = (inst >> 26) & 0x03;
622 	int rf = 0;
623 	char c = ' ';
624 
625 	switch (st_lda) {
626 	case 0x00:
627 		if ((aryno & 0x02) != 0) {	/* 0x02, 0x03: ld.hu, ld.bu */
628 			opcode = "ld";
629 			c = 'u';
630 		} else {
631 			if (cpu == CPU_88100) {
632 				opcode = "xmem";
633 				if (aryno == 0) {	/* xmem.bu */
634 					aryno = 3;
635 					c = 'u';
636 				}
637 			} else {
638 				/* opcode = "ld"; */
639 				rf = 1;
640 			}
641 		}
642 		break;
643 
644 	case 0x03:
645 		if (cpu != CPU_88100) {
646 			rf = 1;
647 			switch (st_lda) {
648 			case 0x00:		/* ld.x */
649 				aryno = 2;
650 				break;
651 			case 0x03:		/* st, st.d, st.x */
652 				break;
653 			}
654 		}
655 		break;
656 	}
657 
658 	db_printf("\t%s%s%c\t\t", opcode,
659 	    rf != 0 ? xinstwidth[aryno] : instwidth[aryno], c);
660 	if (rf != 0)
661 		db_printf("x%d, r%d, ", rd, rs);
662 	else
663 		db_printf("r%d, r%d, ", rd, rs);
664 	db_printf("0x%x", inst & 0xffff);
665 
666 	return (1);
667 }
668 
669 /* Handles triadic mode load/store/exchange instructions */
670 int
nimmem(int cpu,u_int32_t inst,const char * opcode,vaddr_t iadr)671 nimmem(int cpu, u_int32_t inst, const char *opcode, vaddr_t iadr)
672 {
673 	u_int32_t scaled = (inst >> 9) & 0x01;
674 	u_int32_t rd = (inst >> 21) & 0x1f;
675 	u_int32_t rs1 = (inst >> 16) & 0x1f;
676 	u_int32_t rs2 = inst & 0x1f;
677 	u_int32_t st_lda = (inst >> 12) & 0x03;
678 	u_int32_t aryno = (inst >> 10) & 0x03;
679 	char c = ' ';
680 	int rf = 0, wt = 0, usr = 0;
681 
682 	switch (st_lda) {
683 	case 0x00:
684 		switch (aryno) {
685 		case 0x00:			/* xmem.bu */
686 			aryno = 3;
687 			c = 'u';
688 			/* FALLTHROUGH */
689 		case 0x01:			/* xmem */
690 			opcode = "xmem";
691 			break;
692 		default:
693 		case 0x02:			/* ld.hu */
694 		case 0x03:			/* ld.bu */
695 			opcode = "ld";
696 			c = 'u';
697 			break;
698 		}
699 		break;
700 	case 0x01:
701 		opcode = "ld";
702 		if (cpu != CPU_88100) {
703 			if ((inst & (1 << 26)) == 0)
704 				rf = 1;
705 		}
706 		break;
707 	case 0x02:	/* st */
708 		if (cpu != CPU_88100) {
709 			if ((inst & (1 << 26)) == 0)
710 				rf = 1;
711 			if ((inst & (1 << 7)) != 0)
712 				wt = 1;
713 		}
714 		break;
715 	case 0x03:
716 		if (cpu != CPU_88100) {
717 			/* cheat instwidth for lda.x */
718 			if (aryno == 3)
719 				aryno = 4;
720 		}
721 		break;
722 	}
723 
724 	if (st_lda != 0x03 && (inst & (1 << 8)) != 0)
725 		usr = 1;
726 
727 	db_printf("\t%s%s%c%s%s\t",
728 	    opcode, rf != 0 ? xinstwidth[aryno] : instwidth[aryno], c,
729 	    usr != 0 ? ".usr" : "    ", wt != 0 ? ".wt" : "   ");
730 	if (rf != 0)
731 		db_printf("x%d, r%d", rd, rs1);
732 	else
733 		db_printf("r%d, r%d", rd, rs1);
734 
735 	if (scaled != 0)
736 		db_printf("[r%d]", rs2);
737 	else
738 		db_printf(", r%d", rs2);
739 
740 	return (1);
741 }
742 
743 /* Handles triadic mode logical instructions */
744 int
lognim(int cpu,u_int32_t inst,const char * opcode,vaddr_t iadr)745 lognim(int cpu, u_int32_t inst, const char *opcode, vaddr_t iadr)
746 {
747 	u_int32_t rd = (inst >> 21) & 0x1f;
748 	u_int32_t rs1 = (inst >> 16) & 0x1f;
749 	u_int32_t rs2 = inst & 0x1f;
750 
751 	db_printf("\t%s", opcode);
752 	if ((inst & (1 << 10)) != 0)
753 		db_printf(".c");
754 
755 	db_printf("\t\tr%d, r%d, r%d", rd, rs1, rs2);
756 
757 	return (1);
758 }
759 
760 /* Handles triadic mode arithmetic instructions */
761 int
onimmed(int cpu,u_int32_t inst,const char * opcode,vaddr_t iadr)762 onimmed(int cpu, u_int32_t inst, const char *opcode, vaddr_t iadr)
763 {
764 	u_int32_t rd = (inst >> 21) & 0x1f;
765 	u_int32_t rs1 = (inst >> 16) & 0x1f;
766 	u_int32_t rs2 = inst & 0x1f;
767 	u_int32_t carry = (inst >> 8) & 0x03;
768 
769 	db_printf("\t%s", opcode);
770 
771 	if ((inst & (1 << 11)) == 0) {
772 		switch (carry) {
773 		case 0x01:
774 			db_printf(".co");
775 			break;
776 		case 0x02:
777 			db_printf(".ci");
778 			break;
779 		case 0x03:
780 			db_printf(".cio");
781 			break;
782 		}
783 	} else {
784 		if (cpu != CPU_88100 && carry == 0x01)
785 			db_printf(".d");
786 	}
787 
788 	db_printf("\tr%d, r%d, r%d", rd, rs1, rs2);
789 
790 	return (1);
791 }
792 
793 /* Handles 88110 SFU2 instructions */
794 int
pinst(int cpu,u_int32_t inst,const char * opcode,vaddr_t iadr)795 pinst(int cpu, u_int32_t inst, const char *opcode, vaddr_t iadr)
796 {
797 	u_int32_t rd = (inst >> 21) & 0x1f;
798 	u_int32_t rs1 = (inst >> 16) & 0x1f;
799 	u_int32_t rs2 = inst & 0x1f;
800 	u_int32_t tfield = (inst >> 5) & 0x03;
801 	u_int32_t pfunc = (inst >> 11) & 0x1f;
802 	const char *saturation[] = { NULL, ".u", ".us", ".s" };
803 
804 	db_printf("\t%s", opcode);
805 
806 	switch (pfunc) {
807 	case 0x0c:	/* ppack */
808 		db_printf(".%d", (inst >> 5) & 0x3c);
809 		break;
810 	case 0x0e:	/* prot */
811 		break;
812 	default:	/* other instructions have an S field or zero */
813 	    {
814 		u_int32_t sfield = (inst >> 7) & 0x03;
815 
816 		if (sfield != 0)
817 			db_printf("%s", saturation[sfield]);
818 	    }
819 		break;
820 	}
821 
822 	if (tfield != 0 || pfunc == 0x0d /* punpk */) {
823 		if (tfield != 3)
824 			db_printf(".%c", "nbh"[tfield]);
825 	}
826 
827 	switch (pfunc) {
828 	case 0x0d:	/* punpk */
829 		db_printf("\tr%d, r%d", rd, rs1);
830 		break;
831 	case 0x0e:	/* prot with immediate */
832 		db_printf("\tr%d, r%d, %d", rd, rs1, (inst >> 5) & 0x3f);
833 		break;
834 	default:
835 		db_printf("\tr%d, r%d, r%d", rd, rs1, rs2);
836 		break;
837 	}
838 
839 	return (1);
840 }
841 
842 static const struct opdesc {
843 	u_int32_t mask, match;
844 	int (*opfun)(int, u_int32_t, const char *, vaddr_t);
845 	const char *opcode;
846 } opdecode_88100[] = {
847 	/* ORDER IS IMPORTANT BELOW */
848 	{ 0xf0000000,	0x00000000,	immem,		NULL },	/* xmem/ld */
849 	{ 0xf0000000,	0x10000000,	immem,		"ld" },
850 	{ 0xf0000000,	0x20000000,	immem,		"st" },
851 	{ 0xf0000000,	0x30000000,	immem,		"lda" },
852 
853 	{ 0xf8000000,	0x40000000,	oimmed,		"and" },
854 	{ 0xf8000000,	0x48000000,	oimmed,		"mask" },
855 	{ 0xf8000000,	0x50000000,	oimmed,		"xor" },
856 	{ 0xf8000000,	0x58000000,	oimmed,		"or" },
857 	{ 0xfc000000,	0x60000000,	oimmed,		"addu" },
858 	{ 0xfc000000,	0x64000000,	oimmed,		"subu" },
859 	{ 0xfc000000,	0x68000000,	oimmed,		"divu" },
860 	{ 0xfc000000,	0x6c000000,	oimmed,		"mul" },
861 	{ 0xfc000000,	0x70000000,	oimmed,		"add" },
862 	{ 0xfc000000,	0x74000000,	oimmed,		"sub" },
863 	{ 0xfc000000,	0x78000000,	oimmed,		"div" },
864 	{ 0xfc000000,	0x7c000000,	oimmed,		"cmp" },
865 
866 	{ 0xfc00f800,	0x80004000,	ctrlregs,	"ldcr" },
867 	{ 0xfc00f800,	0x80004800,	ctrlregs,	"fldcr" },
868 	{ 0xfc00f800,	0x80008000,	ctrlregs,	"stcr" },
869 	{ 0xfc00f800,	0x80008800,	ctrlregs,	"fstcr" },
870 	{ 0xfc00f800,	0x8000c000,	ctrlregs,	"xcr" },
871 	{ 0xfc00f800,	0x8000c800,	ctrlregs,	"fxcr" },
872 
873 	{ 0xfc00f800,	0x84000000,	sindou,		"fmul" },
874 	{ 0xfc1fff80,	0x84002000,	sindou,		"flt" },
875 	{ 0xfc00f800,	0x84002800,	sindou,		"fadd" },
876 	{ 0xfc00f800,	0x84003000,	sindou,		"fsub" },
877 	{ 0xfc00f860,	0x84003800,	sindou,		"fcmp" },
878 	{ 0xfc1ffe60,	0x84004800,	sindou,		"int" },
879 	{ 0xfc1ffe60,	0x84005000,	sindou,		"nint" },
880 	{ 0xfc1ffe60,	0x84005800,	sindou,		"trnc" },
881 	{ 0xfc00f800,	0x84007000,	sindou,		"fdiv" },
882 
883 	{ 0xf8000000,	0xc0000000,	obranch,	"br" },
884 	{ 0xf8000000,	0xc8000000,	obranch,	"bsr" },
885 
886 	{ 0xf8000000,	0xd0000000,	brcond,		"bb0" },
887 	{ 0xf8000000,	0xd8000000,	brcond,		"bb1" },
888 	{ 0xf8000000,	0xe8000000,	brcond,		"bcnd" },
889 
890 	{ 0xfc00fc00,	0xf0008000,	obit,		"clr" },
891 	{ 0xfc00fc00,	0xf0008800,	obit,		"set" },
892 	{ 0xfc00fc00,	0xf0009000,	obit,		"ext" },
893 	{ 0xfc00fc00,	0xf0009800,	obit,		"extu" },
894 	{ 0xfc00fc00,	0xf000a000,	obit,		"mak" },
895 	{ 0xfc00fc00,	0xf000a800,	obit,		"rot" },
896 
897 	{ 0xfc00fe00,	0xf000d000,	otrap,		"tb0" },
898 	{ 0xfc00fe00,	0xf000d800,	otrap,		"tb1" },
899 	{ 0xfc00fe00,	0xf000e800,	otrap,		"tcnd" },
900 
901 	{ 0xfc00f0e0,	0xf4000000,	nimmem,		NULL },	/* xmem/ld */
902 	{ 0xfc00f0e0,	0xf4001000,	nimmem,		"ld" },
903 	{ 0xfc00f0e0,	0xf4002000,	nimmem,		"st" },
904 	{ 0xfc00f0e0,	0xf4003000,	nimmem,		"lda" },
905 
906 	{ 0xfc00fbe0,	0xf4004000,	lognim,		"and" },
907 	{ 0xfc00fbe0,	0xf4005000,	lognim,		"xor" },
908 	{ 0xfc00fbe0,	0xf4005800,	lognim,		"or" },
909 
910 	{ 0xfc00fce0,	0xf4006000,	onimmed,	"addu" },
911 	{ 0xfc00fce0,	0xf4006400,	onimmed,	"subu" },
912 	{ 0xfc00fce0,	0xf4006800,	onimmed,	"divu" },
913 	{ 0xfc00fce0,	0xf4006c00,	onimmed,	"mul" },
914 	{ 0xfc00fce0,	0xf4007000,	onimmed,	"add" },
915 	{ 0xfc00fce0,	0xf4007400,	onimmed,	"sub" },
916 	{ 0xfc00fce0,	0xf4007800,	onimmed,	"div" },
917 	{ 0xfc00fce0,	0xf4007c00,	onimmed,	"cmp" },
918 
919 	{ 0xfc00ffe0,	0xf4008000,	bitman,		"clr" },
920 	{ 0xfc00ffe0,	0xf4008800,	bitman,		"set" },
921 	{ 0xfc00ffe0,	0xf4009000,	bitman,		"ext" },
922 	{ 0xfc00ffe0,	0xf4009800,	bitman,		"extu" },
923 	{ 0xfc00ffe0,	0xf400a000,	bitman,		"mak" },
924 	{ 0xfc00ffe0,	0xf400a800,	bitman,		"rot" },
925 
926 	{ 0xfc00fbe0,	0xf400c000,	jump,		"jmp" },
927 	{ 0xfc00fbe0,	0xf400c800,	jump,		"jsr" },
928 
929 	{ 0xfc00ffe0,	0xf400e800,	instset,	"ff1" },
930 	{ 0xfc00ffe0,	0xf400ec00,	instset,	"ff0" },
931 	{ 0xfc00ffe0,	0xf400f800,	instset,	"tbnd" },
932 	{ 0xfc00ffe0,	0xf400fc00,	instset,	"rte" },
933 	{ 0xfc000000,	0xf8000000,	instset,	"tbnd" },
934 	{ 0,		0,		NULL,		NULL }
935 }, opdecode_88110[] = {
936 	/* ORDER IS IMPORTANT BELOW */
937 	{ 0xe0000000,	0x00000000,	immem,		"ld" },
938 	{ 0xf0000000,	0x20000000,	immem,		"st" },
939 	{ 0xfc000000,	0x3c000000,	immem,		"ld" },
940 	{ 0xf0000000,	0x30000000,	immem,		"st" },
941 
942 	{ 0xf8000000,	0x40000000,	oimmed,		"and" },
943 	{ 0xf8000000,	0x48000000,	oimmed,		"mask" },
944 	{ 0xf8000000,	0x50000000,	oimmed,		"xor" },
945 	{ 0xf8000000,	0x58000000,	oimmed,		"or" },
946 	{ 0xfc000000,	0x60000000,	oimmed,		"addu" },
947 	{ 0xfc000000,	0x64000000,	oimmed,		"subu" },
948 	{ 0xfc000000,	0x68000000,	oimmed,		"divu" },
949 	{ 0xfc000000,	0x6c000000,	oimmed,		"mulu" },
950 	{ 0xfc000000,	0x70000000,	oimmed,		"add" },
951 	{ 0xfc000000,	0x74000000,	oimmed,		"sub" },
952 	{ 0xfc000000,	0x78000000,	oimmed,		"divs" },
953 	{ 0xfc000000,	0x7c000000,	oimmed,		"cmp" },
954 
955 	{ 0xfc1ff81f,	0x80004000,	ctrlregs,	"ldcr" },
956 	{ 0xfc1ff81f,	0x80004800,	ctrlregs,	"fldcr" },
957 	{ 0xffe0f800,	0x80008000,	ctrlregs,	"stcr" },
958 	{ 0xffe0f800,	0x80008800,	ctrlregs,	"fstcr" },
959 	{ 0xfc00f800,	0x8000c000,	ctrlregs,	"xcr" },
960 	{ 0xfc00f800,	0x8000c800,	ctrlregs,	"fxcr" },
961 
962 	{ 0xfc007800,	0x84000000,	sindou,		"fmul" },
963 	{ 0xfc1f7e00,	0x84000800,	sindou,		"fcvt" },
964 	{ 0xfc1ffd80,	0x84002000,	sindou,		"flt" },
965 	{ 0xfc007800,	0x84002800,	sindou,		"fadd" },
966 	{ 0xfc007800,	0x84003000,	sindou,		"fsub" },
967 	{ 0xfc007860,	0x84003800,	sindou,		"fcmp" },
968 	{ 0xfc007860,	0x84003820,	sindou,		"fcmpu" },
969 	{ 0xfc1ffe60,	0x8400c000,	sindou,		"mov" },
970 	{ 0xfc17fe60,	0x84004200,	sindou,		"mov" },
971 	{ 0xfc1f7e60,	0x84004800,	sindou,		"int" },
972 	{ 0xfc1f7e60,	0x84005000,	sindou,		"nint" },
973 	{ 0xfc1f7e60,	0x84005800,	sindou,		"trnc" },
974 	{ 0xfc007800,	0x84007000,	sindou,		"fdiv" },
975 	{ 0xfc1f7e00,	0x84007800,	sindou,		"fsqrt" },
976 
977 	{ 0xfc00ffe0,	0x88000000,	pinst,		"pmul" },
978 	{ 0xfc00ff80,	0x88002000,	pinst,		"padd" },
979 	{ 0xfc00fe00,	0x88002000,	pinst,		"padds" },
980 	{ 0xfc00ff80,	0x88003000,	pinst,		"psub" },
981 	{ 0xfc00fe00,	0x88003000,	pinst,		"psubs" },
982 	{ 0xfc00ffe0,	0x88003860,	pinst,		"pcmp" },
983 	{ 0xfc00f800,	0x88006000,	pinst,		"ppack" },
984 	{ 0xfc00ff9f,	0x88006800,	pinst,		"punpk" },
985 	{ 0xfc00f87f,	0x88007000,	pinst,		"prot" },
986 	{ 0xfc00ffe0,	0x88007800,	pinst,		"prot" },
987 
988 	{ 0xf8000000,	0xc0000000,	obranch,	"br" },
989 	{ 0xf8000000,	0xc8000000,	obranch,	"bsr" },
990 
991 	{ 0xf8000000,	0xd0000000,	brcond,		"bb0" },
992 	{ 0xf8000000,	0xd8000000,	brcond,		"bb1" },
993 	{ 0xf8000000,	0xe8000000,	brcond,		"bcnd" },
994 
995 	{ 0xfc00fc00,	0xf0008000,	obit,		"clr" },
996 	{ 0xfc00fc00,	0xf0008800,	obit,		"set" },
997 	{ 0xfc00fc00,	0xf0009000,	obit,		"ext" },
998 	{ 0xfc00fc00,	0xf0009800,	obit,		"extu" },
999 	{ 0xfc00fc00,	0xf000a000,	obit,		"mak" },
1000 	{ 0xfc00ffe0,	0xf000a800,	obit,		"rot" },
1001 
1002 	{ 0xfc00fe00,	0xf000d000,	otrap,		"tb0" },
1003 	{ 0xfc00fe00,	0xf000d800,	otrap,		"tb1" },
1004 	{ 0xfc00fe00,	0xf000e800,	otrap,		"tcnd" },
1005 
1006 	{ 0xfc00f0e0,	0xf4000000,	nimmem,		NULL },	/* ld/xmem */
1007 	{ 0xf800f0e0,	0xf0001000,	nimmem,		"ld" },
1008 	{ 0xf800f060,	0xf0002000,	nimmem,		"st" },
1009 	{ 0xfc00f2e0,	0xf4003200,	nimmem,		"lda" },
1010 
1011 	{ 0xfc00fbe0,	0xf4004000,	lognim,		"and" },
1012 	{ 0xfc00fbe0,	0xf4005000,	lognim,		"xor" },
1013 	{ 0xfc00fbe0,	0xf4005800,	lognim,		"or" },
1014 
1015 	{ 0xfc00fce0,	0xf4006000,	onimmed,	"addu" },
1016 	{ 0xfc00fce0,	0xf4006400,	onimmed,	"subu" },
1017 	{ 0xfc00fee0,	0xf4006800,	onimmed,	"divu" },
1018 	{ 0xfc00fee0,	0xf4006c00,	onimmed,	"mulu" },
1019 	{ 0xfc00ffe0,	0xf4006e00,	onimmed,	"muls" },
1020 	{ 0xfc00fce0,	0xf4007000,	onimmed,	"add" },
1021 	{ 0xfc00fce0,	0xf4007400,	onimmed,	"sub" },
1022 	{ 0xfc00ffe0,	0xf4007800,	onimmed,	"divs" },
1023 	{ 0xfc00ffe0,	0xf4007c00,	onimmed,	"cmp" },
1024 
1025 	{ 0xfc00ffe0,	0xf4008000,	bitman,		"clr" },
1026 	{ 0xfc00ffe0,	0xf4008800,	bitman,		"set" },
1027 	{ 0xfc00ffe0,	0xf4009000,	bitman,		"ext" },
1028 	{ 0xfc00ffe0,	0xf4009800,	bitman,		"extu" },
1029 	{ 0xfc00ffe0,	0xf400a000,	bitman,		"mak" },
1030 	{ 0xfc00ffe0,	0xf400a800,	bitman,		"rot" },
1031 
1032 	{ 0xfffffbe0,	0xf400c000,	jump,		"jmp" },
1033 	{ 0xfffffbe0,	0xf400c800,	jump,		"jsr" },
1034 
1035 	{ 0xfc1fffe0,	0xf400e800,	instset,	"ff1" },
1036 	{ 0xfc1fffe0,	0xf400ec00,	instset,	"ff0" },
1037 	{ 0xffe0ffe0,	0xf400f800,	instset,	"tbnd" },
1038 	{ 0xffffffff,	0xf400fc00,	instset,	"rte" },
1039 	{ 0xfffffffc,	0xf400fc00,	instset,	"illop" },
1040 	{ 0xffe00000,	0xf8000000,	instset,	"tbnd" },
1041 	{ 0,		0,		NULL,		NULL }
1042 };
1043 
1044 void
m88k_print_instruction(int cpu,u_int iadr,u_int32_t inst)1045 m88k_print_instruction(int cpu, u_int iadr, u_int32_t inst)
1046 {
1047 	const struct opdesc *p;
1048 
1049 	/*
1050 	 * This messes up "or.b" instructions ever so slightly,
1051 	 * but keeps us in sync between routines...
1052 	 */
1053 	if (inst == 0) {
1054 		db_printf("\t.word\t0\n");
1055 	} else {
1056 		p = cpu != CPU_88100 ? opdecode_88110 : opdecode_88100;
1057 		while (p->mask != 0) {
1058 			if ((inst & p->mask) == p->match) {
1059 				if ((*p->opfun)(cpu, inst, p->opcode, iadr)) {
1060 					db_printf("\n");
1061 					return;
1062 				}
1063 				break;
1064 			}
1065 			p++;
1066 		}
1067 		db_printf("\t.word\t0x%x\n", inst);
1068 	}
1069 }
1070 
1071 vaddr_t
db_disasm(vaddr_t loc,int altfmt)1072 db_disasm(vaddr_t loc, int altfmt)
1073 {
1074 	int cpu;
1075 
1076 	if (altfmt)
1077 		cpu = CPU_IS88100 ? CPU_88110 : CPU_88100;
1078 	else
1079 		cpu = cputyp;
1080 
1081 	m88k_print_instruction(cpu, loc, db_get_value(loc, 4, 0));
1082 	return (loc + 4);
1083 }
1084