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