1 /*
2 * Copyright (C) 2005-2021 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * Motorola M881x0 CPU emulation.
29 *
30 * M88100: Disassembly of (almost?) everything, and execution of most
31 * instructions. Exception handling and virtual memory has also
32 * been implemented. Exceptions while in delay slots may not work
33 * fully yet, though.
34 *
35 * M88110: Not yet.
36 */
37
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <ctype.h>
42 #include <unistd.h>
43
44 #include "cpu.h"
45 #include "float_emul.h"
46 #include "interrupt.h"
47 #include "machine.h"
48 #include "memory.h"
49 #include "misc.h"
50 #include "settings.h"
51 #include "symbol.h"
52
53 #include "thirdparty/m8820x_pte.h"
54 #include "thirdparty/m88k_dmt.h"
55 #include "thirdparty/mvmeprom.h"
56
57 #define DYNTRANS_32
58 #define DYNTRANS_DELAYSLOT
59 #include "tmp_m88k_head.cc"
60
61
62 void m88k_pc_to_pointers(struct cpu *);
63 void m88k_cpu_functioncall_trace(struct cpu *cpu, int n_args);
64
65 static const char *memop[4] = { ".d", "", ".h", ".b" };
66
67 void m88k_irq_interrupt_assert(struct interrupt *interrupt);
68 void m88k_irq_interrupt_deassert(struct interrupt *interrupt);
69
70
71 static const char *m88k_cr_names[] = M88K_CR_NAMES;
72 static const char *m88k_cr_197_names[] = M88K_CR_NAMES_197;
73
m88k_cr_name(struct cpu * cpu,int i)74 static const char *m88k_cr_name(struct cpu *cpu, int i)
75 {
76 const char **cr_names = m88k_cr_names;
77
78 /* Hm. Is this really MVME197 specific? TODO */
79 if (cpu->machine->machine_subtype == MACHINE_MVME88K_197)
80 cr_names = m88k_cr_197_names;
81
82 return cr_names[i];
83 }
84
m88k_fcr_name(struct cpu * cpu,int fi)85 static char *m88k_fcr_name(struct cpu *cpu, int fi)
86 {
87 /* TODO */
88 static char fcr_name[10];
89 snprintf(fcr_name, sizeof(fcr_name), "FCR%i", fi);
90 return fcr_name;
91 }
92
93
94
95 /*
96 * m88k_cpu_new():
97 *
98 * Create a new M88K cpu object by filling the CPU struct.
99 * Return 1 on success, 0 if cpu_type_name isn't a valid M88K processor.
100 */
m88k_cpu_new(struct cpu * cpu,struct memory * mem,struct machine * machine,int cpu_id,char * cpu_type_name)101 int m88k_cpu_new(struct cpu *cpu, struct memory *mem,
102 struct machine *machine, int cpu_id, char *cpu_type_name)
103 {
104 int i, found;
105 struct m88k_cpu_type_def cpu_type_defs[] = M88K_CPU_TYPE_DEFS;
106
107 /* Scan the list for this cpu type: */
108 i = 0; found = -1;
109 while (i >= 0 && cpu_type_defs[i].name != NULL) {
110 if (strcasecmp(cpu_type_defs[i].name, cpu_type_name) == 0) {
111 found = i;
112 break;
113 }
114 i++;
115 }
116 if (found == -1)
117 return 0;
118
119 cpu->run_instr = m88k_run_instr;
120 cpu->memory_rw = m88k_memory_rw;
121 cpu->update_translation_table = m88k_update_translation_table;
122 cpu->invalidate_translation_caches =
123 m88k_invalidate_translation_caches;
124 cpu->invalidate_code_translation = m88k_invalidate_code_translation;
125 cpu->translate_v2p = m88k_translate_v2p;
126
127 cpu->cd.m88k.cpu_type = cpu_type_defs[found];
128 cpu->name = strdup(cpu->cd.m88k.cpu_type.name);
129 cpu->is_32bit = 1;
130 cpu->byte_order = EMUL_BIG_ENDIAN;
131
132 cpu->instruction_has_delayslot = m88k_cpu_instruction_has_delayslot;
133
134 /* Only show name and caches etc for CPU nr 0: */
135 if (cpu_id == 0) {
136 debug("%s", cpu->name);
137 }
138
139
140 /*
141 * Add register names as settings:
142 */
143
144 CPU_SETTINGS_ADD_REGISTER64("pc", cpu->pc);
145
146 for (i=0; i<N_M88K_REGS; i++) {
147 char name[10];
148 snprintf(name, sizeof(name), "r%i", i);
149 CPU_SETTINGS_ADD_REGISTER32(name, cpu->cd.m88k.r[i]);
150 }
151
152 for (i=0; i<N_M88K_CONTROL_REGS; i++) {
153 char name[10];
154 snprintf(name, sizeof(name), "%s", m88k_cr_name(cpu, i));
155 CPU_SETTINGS_ADD_REGISTER32(name, cpu->cd.m88k.cr[i]);
156 }
157
158 for (i=0; i<N_M88K_FPU_CONTROL_REGS; i++) {
159 char name[10];
160 snprintf(name, sizeof(name), "%s", m88k_fcr_name(cpu, i));
161 CPU_SETTINGS_ADD_REGISTER32(name, cpu->cd.m88k.fcr[i]);
162 }
163
164
165 /* Register the CPU interrupt pin: */
166 {
167 struct interrupt templ;
168 char name[50];
169 snprintf(name, sizeof(name), "%s", cpu->path);
170
171 memset(&templ, 0, sizeof(templ));
172 templ.line = 0;
173 templ.name = name;
174 templ.extra = cpu;
175 templ.interrupt_assert = m88k_irq_interrupt_assert;
176 templ.interrupt_deassert = m88k_irq_interrupt_deassert;
177 interrupt_handler_register(&templ);
178 }
179
180 /* Set the Processor ID: */
181 cpu->cd.m88k.cr[M88K_CR_PID] = cpu->cd.m88k.cpu_type.pid | M88K_PID_MC;
182
183 /* Start in supervisor mode, with interrupts disabled. */
184 cpu->cd.m88k.cr[M88K_CR_PSR] = M88K_PSR_MODE | M88K_PSR_IND;
185 if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
186 cpu->cd.m88k.cr[M88K_CR_PSR] |= M88K_PSR_BO;
187
188 /* Initial stack pointer: */
189 cpu->cd.m88k.r[31] = 1048576 * cpu->machine->physical_ram_in_mb - 1024;
190
191 return 1;
192 }
193
194
195 /*
196 * m88k_cpu_dumpinfo():
197 */
m88k_cpu_dumpinfo(struct cpu * cpu)198 void m88k_cpu_dumpinfo(struct cpu *cpu)
199 {
200 /* struct m88k_cpu_type_def *ct = &cpu->cd.m88k.cpu_type; */
201
202 debug(", %s-endian",
203 cpu->byte_order == EMUL_BIG_ENDIAN? "Big" : "Little");
204
205 debug("\n");
206 }
207
208
209 /*
210 * m88k_cpu_list_available_types():
211 *
212 * Print a list of available M88K CPU types.
213 */
m88k_cpu_list_available_types(void)214 void m88k_cpu_list_available_types(void)
215 {
216 int i, j;
217 struct m88k_cpu_type_def tdefs[] = M88K_CPU_TYPE_DEFS;
218
219 i = 0;
220 while (tdefs[i].name != NULL) {
221 debug("%s", tdefs[i].name);
222 for (j=13 - strlen(tdefs[i].name); j>0; j--)
223 debug(" ");
224 i++;
225 if ((i % 5) == 0 || tdefs[i].name == NULL)
226 debug("\n");
227 }
228 }
229
230
231 /*
232 * m88k_cpu_instruction_has_delayslot():
233 *
234 * Returns 1 if an opcode has a delay slot after it, 0 otherwise.
235 */
m88k_cpu_instruction_has_delayslot(struct cpu * cpu,unsigned char * ib)236 int m88k_cpu_instruction_has_delayslot(struct cpu *cpu, unsigned char *ib)
237 {
238 uint32_t iword = *((uint32_t *)&ib[0]);
239
240 if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
241 iword = LE32_TO_HOST(iword);
242 else
243 iword = BE32_TO_HOST(iword);
244
245 switch (iword >> 26) {
246 case 0x31: /* br.n */
247 case 0x33: /* bsr.n */
248 case 0x35: /* bb0.n */
249 case 0x37: /* bb1.n */
250 case 0x3b: /* bcnd.n */
251 return 1;
252 case 0x3d:
253 switch ((iword >> 8) & 0xff) {
254 case 0xc4: /* jmp.n */
255 case 0xcc: /* jsr.n */
256 return 1;
257 }
258 }
259
260 return 0;
261 }
262
263
264 /*
265 * m88k_cpu_register_dump():
266 *
267 * Dump cpu registers in a relatively readable format.
268 *
269 * gprs: set to non-zero to dump GPRs and some special-purpose registers.
270 * coprocs: set bit 0..3 to dump registers in coproc 0..3.
271 */
m88k_cpu_register_dump(struct cpu * cpu,int gprs,int coprocs)272 void m88k_cpu_register_dump(struct cpu *cpu, int gprs, int coprocs)
273 {
274 char *symbol;
275 uint64_t offset;
276 int i, x = cpu->cpu_id;
277
278 if (gprs) {
279 symbol = get_symbol_name(&cpu->machine->symbol_context,
280 cpu->pc, &offset);
281 debug("cpu%i: pc = 0x%08" PRIx32, x, (uint32_t)cpu->pc);
282 debug(" <%s>\n", symbol != NULL? symbol : " no symbol ");
283
284 for (i=0; i<N_M88K_REGS; i++) {
285 if ((i % 4) == 0)
286 debug("cpu%i:", x);
287 if (i == 0)
288 debug(" ");
289 else
290 debug(" r%-2i = 0x%08" PRIx32,
291 i, cpu->cd.m88k.r[i]);
292 if ((i % 4) == 3)
293 debug("\n");
294 }
295 }
296
297 if (coprocs & 1) {
298 int n_control_regs = 32;
299
300 /* Hm. Is this really MVME197 specific? TODO */
301 if (cpu->machine->machine_subtype == MACHINE_MVME88K_197)
302 n_control_regs = 64;
303
304 for (i=0; i<n_control_regs; i++) {
305 if ((i % 4) == 0)
306 debug("cpu%i:", x);
307 debug(" %4s=0x%08" PRIx32,
308 m88k_cr_name(cpu, i), cpu->cd.m88k.cr[i]);
309 if ((i % 4) == 3)
310 debug("\n");
311 }
312 }
313
314 if (coprocs & 2) {
315 int n_fpu_control_regs = 64;
316
317 for (i=0; i<n_fpu_control_regs; i++) {
318 if ((i % 4) == 0)
319 debug("cpu%i:", x);
320 debug(" %5s=0x%08" PRIx32,
321 m88k_fcr_name(cpu, i), cpu->cd.m88k.fcr[i]);
322 if ((i % 4) == 3)
323 debug("\n");
324 }
325 }
326 }
327
328
329 /*
330 * m88k_cpu_tlbdump():
331 *
332 * Called from the debugger to dump the TLB in a readable format.
333 * x is the cpu number to dump, or -1 to dump all CPUs.
334 *
335 * If rawflag is nonzero, then the TLB contents isn't formated nicely,
336 * just dumped.
337 */
m88k_cpu_tlbdump(struct machine * m,int x,int rawflag)338 void m88k_cpu_tlbdump(struct machine *m, int x, int rawflag)
339 {
340 int cpu_nr, cmmu_nr, i;
341
342 for (cpu_nr = 0; cpu_nr < m->ncpus; cpu_nr++) {
343 struct cpu *cpu = m->cpus[cpu_nr];
344
345 if (x != -1 && cpu_nr != x)
346 continue;
347
348 for (cmmu_nr = 0; cmmu_nr < MAX_M8820X_CMMUS; cmmu_nr++) {
349 struct m8820x_cmmu *cmmu = cpu->cd.m88k.cmmu[cmmu_nr];
350 if (cmmu == NULL)
351 continue;
352
353 printf("cpu%i: CMMU %i (%s)\n", cpu_nr, cmmu_nr,
354 cmmu_nr & 1? "data" : "instruction");
355
356 /* BATC: */
357 for (i = 0; i < N_M88200_BATC_REGS; i++) {
358 uint32_t b = cmmu->batc[i];
359 printf("cpu%i: BATC[%2i]: ", cpu_nr, i);
360 printf("v=0x%08" PRIx32, b & 0xfff80000);
361 printf(", p=0x%08" PRIx32,
362 (b << 13) & 0xfff80000);
363 printf(", %s %s %s %s %s %s\n",
364 b & BATC_SO? "SP " : "!sp",
365 b & BATC_WT? "WT " : "!wt",
366 b & BATC_GLOBAL? "G " : "!g ",
367 b & BATC_INH? "CI " : "!ci",
368 b & BATC_PROT? "WP " : "!wp",
369 b & BATC_SO? "V " : "!v");
370 }
371
372 /* PATC: */
373 for (i = 0; i < N_M88200_PATC_ENTRIES; i++) {
374 uint32_t v = cmmu->patc_v_and_control[i];
375 uint32_t p = cmmu->patc_p_and_supervisorbit[i];
376
377 printf("cpu%i: patc[%2i]: ", cpu_nr, i);
378 if (p & M8820X_PATC_SUPERVISOR_BIT)
379 printf("superv");
380 else
381 printf("user ");
382 printf(" v=0x%08" PRIx32, v & 0xfffff000);
383 printf(", p=0x%08" PRIx32, p & 0xfffff000);
384
385 printf(" %s %s %s %s %s %s %s",
386 v & PG_U1? "U1 " : "!u1",
387 v & PG_U0? "U0 " : "!u0",
388 v & PG_SO? "SP " : "!sp",
389 v & PG_M? "M " : "!m",
390 v & PG_U? "U " : "!u",
391 v & PG_PROT? "WP " : "!wp",
392 v & PG_V? "V " : "!v");
393
394 if (i == cmmu->patc_update_index)
395 printf(" <--");
396 printf("\n");
397 }
398 }
399 }
400 }
401
402
403 /*
404 * m88k_irq_interrupt_assert():
405 * m88k_irq_interrupt_deassert():
406 */
m88k_irq_interrupt_assert(struct interrupt * interrupt)407 void m88k_irq_interrupt_assert(struct interrupt *interrupt)
408 {
409 struct cpu *cpu = (struct cpu *) interrupt->extra;
410 cpu->cd.m88k.irq_asserted = 1;
411 }
m88k_irq_interrupt_deassert(struct interrupt * interrupt)412 void m88k_irq_interrupt_deassert(struct interrupt *interrupt)
413 {
414 struct cpu *cpu = (struct cpu *) interrupt->extra;
415 cpu->cd.m88k.irq_asserted = 0;
416 }
417
418
419 /*
420 * m88k_ldcr():
421 *
422 * Read from a control register. Store the resulting value in a register
423 * (pointed to by r32ptr).
424 */
m88k_ldcr(struct cpu * cpu,uint32_t * r32ptr,int cr)425 void m88k_ldcr(struct cpu *cpu, uint32_t *r32ptr, int cr)
426 {
427 uint32_t retval = cpu->cd.m88k.cr[cr];
428
429 switch (cr) {
430
431 case M88K_CR_PID:
432 case M88K_CR_PSR:
433 case M88K_CR_EPSR:
434 case M88K_CR_SSBR:
435 case M88K_CR_SXIP:
436 case M88K_CR_SNIP:
437 case M88K_CR_SFIP:
438 case M88K_CR_VBR:
439 case M88K_CR_DMD0:
440 case M88K_CR_DMD1:
441 case M88K_CR_DMD2:
442 case M88K_CR_SR0:
443 case M88K_CR_SR1:
444 case M88K_CR_SR2:
445 case M88K_CR_SR3:
446 break;
447
448 case M88K_CR_DMT0:
449 case M88K_CR_DMT1:
450 case M88K_CR_DMT2:
451 /*
452 * Catch some possible internal errors in the emulator:
453 *
454 * For valid memory Load transactions, the Destination Register
455 * should not be zero.
456 *
457 * The Byte Order bit should be the same as the CPU's.
458 */
459 if (retval & DMT_VALID && !(retval & DMT_WRITE)) {
460 if (DMT_DREGBITS(retval) == M88K_ZERO_REG) {
461 fatal("DMT DREG = zero? Internal error.\n");
462 exit(1);
463 }
464 }
465 if (!!(cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_BO)
466 != !!(retval & DMT_BO) && retval & DMT_VALID) {
467 fatal("DMT byte order not same as CPUs?\n");
468 exit(1);
469 }
470
471 break;
472
473 case M88K_CR_DMA0:
474 case M88K_CR_DMA1:
475 case M88K_CR_DMA2:
476 /*
477 * Catch some possible internal errors in the emulator:
478 * The lowest 2 bits of the transaction address registers
479 * should always be zero.
480 */
481 if (retval & 3) {
482 fatal("DMAx not word-aligned? Internal error.\n");
483 exit(1);
484 }
485
486 break;
487
488 default:fatal("m88k_ldcr: UNIMPLEMENTED cr = 0x%02x (%s)\n",
489 cr, m88k_cr_name(cpu, cr));
490 exit(1);
491 }
492
493 *r32ptr = retval;
494 }
495
496
497 /*
498 * m88k_stcr():
499 *
500 * Write to a control register.
501 * (Used by both the stcr and rte instructions.)
502 */
m88k_stcr(struct cpu * cpu,uint32_t value,int cr,int rte)503 void m88k_stcr(struct cpu *cpu, uint32_t value, int cr, int rte)
504 {
505 uint32_t old = cpu->cd.m88k.cr[cr];
506
507 switch (cr) {
508
509 case M88K_CR_PSR: /* Processor Status Register */
510 if ((cpu->byte_order == EMUL_LITTLE_ENDIAN
511 && !(value & M88K_PSR_BO)) ||
512 (cpu->byte_order == EMUL_BIG_ENDIAN
513 && (value & M88K_PSR_BO))) {
514 fatal("TODO: attempt to change endianness by flipping"
515 " the endianness bit in the PSR. How should this"
516 " be handled? Aborting.\n");
517 exit(1);
518 }
519
520 if (!rte && old & M88K_PSR_MODE && !(value & M88K_PSR_MODE))
521 fatal("[ m88k_stcr: WARNING! the PSR_MODE bit is being"
522 " cleared; this should be done using the RTE "
523 "instruction only, according to the M88100 "
524 "manual! Continuing anyway. ]\n");
525
526 if (value & M88K_PSR_MXM) {
527 fatal("m88k_stcr: TODO: MXM support\n");
528 exit(1);
529 }
530
531 if ((old & M88K_PSR_MODE) != (value & M88K_PSR_MODE))
532 cpu->invalidate_translation_caches(
533 cpu, 0, INVALIDATE_ALL);
534
535 cpu->cd.m88k.cr[cr] = value;
536 break;
537
538 case M88K_CR_EPSR:
539 cpu->cd.m88k.cr[cr] = value;
540 break;
541
542 case M88K_CR_SXIP:
543 case M88K_CR_SNIP:
544 case M88K_CR_SFIP:
545 cpu->cd.m88k.cr[cr] = value;
546 break;
547
548 case M88K_CR_SSBR: /* Shadow ScoreBoard Register */
549 if (value & 1)
550 fatal("[ m88k_stcr: WARNING! bit 0 non-zero when"
551 " writing to SSBR (?) ]\n");
552 cpu->cd.m88k.cr[cr] = value;
553 break;
554
555 case M88K_CR_VBR:
556 if (value & 0x00000fff)
557 fatal("[ m88k_stcr: WARNING! bits 0..11 non-zero when"
558 " writing to VBR (?) ]\n");
559 cpu->cd.m88k.cr[cr] = value;
560 break;
561
562 case M88K_CR_DMT0:
563 case M88K_CR_DMT1:
564 case M88K_CR_DMT2:
565 cpu->cd.m88k.cr[cr] = value;
566 break;
567
568 case M88K_CR_SR0: /* Supervisor Storage Registers 0..3 */
569 case M88K_CR_SR1:
570 case M88K_CR_SR2:
571 case M88K_CR_SR3:
572 cpu->cd.m88k.cr[cr] = value;
573 break;
574
575 default:fatal("m88k_stcr: UNIMPLEMENTED cr = 0x%02x (%s)\n",
576 cr, m88k_cr_name(cpu, cr));
577 exit(1);
578 }
579 }
580
581
582 /*
583 * m88k_fstcr():
584 *
585 * Write to a floating-point control register.
586 */
m88k_fstcr(struct cpu * cpu,uint32_t value,int fcr)587 void m88k_fstcr(struct cpu *cpu, uint32_t value, int fcr)
588 {
589 #if 0
590 /* TODO (?) */
591 uint32_t old = cpu->cd.m88k.cr[fcr];
592
593 switch (fcr) {
594 default:fatal("m88k_fstcr: UNIMPLEMENTED fcr = 0x%02x (%s)\n",
595 fcr, m88k_fcr_name(cpu, fcr));
596 exit(1);
597 }
598 #else
599 cpu->cd.m88k.cr[fcr] = value;
600 #endif
601 }
602
603
604 /*
605 * m88k_memory_transaction_debug_dump():
606 *
607 * Debug dump of the memory transaction registers of a cpu.
608 */
m88k_memory_transaction_debug_dump(struct cpu * cpu,int n)609 static void m88k_memory_transaction_debug_dump(struct cpu *cpu, int n)
610 {
611 uint32_t dmt = cpu->cd.m88k.dmt[n];
612
613 debug("[ DMT%i: ", n);
614 if (dmt & DMT_VALID) {
615 if (dmt & DMT_BO)
616 debug("Little-Endian, ");
617 else
618 debug("Big-Endian, ");
619 if (dmt & DMT_DAS)
620 debug("Supervisor, ");
621 else
622 debug("User, ");
623 if (dmt & DMT_DOUB1)
624 debug("DOUB1, ");
625 if (dmt & DMT_LOCKBAR)
626 debug("LOCKBAR, ");
627 if (dmt & DMT_WRITE)
628 debug("store, ");
629 else {
630 debug("load.%c(r%i), ",
631 dmt & DMT_SIGNED? 's' : 'u',
632 DMT_DREGBITS(dmt));
633 }
634 debug("bytebits=0x%x ]\n", DMT_ENBITS(dmt));
635
636 debug("[ DMD%i: 0x%08" PRIx32"; ", n, cpu->cd.m88k.dmd[n]);
637 debug("DMA%i: 0x%08" PRIx32" ]\n", n, cpu->cd.m88k.dma[n]);
638 } else
639 debug("not valid ]\n");
640 }
641
642
643 /*
644 * m88k_exception():
645 *
646 * Cause an exception.
647 */
m88k_exception(struct cpu * cpu,int vector,int is_trap)648 void m88k_exception(struct cpu *cpu, int vector, int is_trap)
649 {
650 int update_shadow_regs = 1;
651
652 debug("[ EXCEPTION 0x%03x: ", vector);
653 switch (vector) {
654 case M88K_EXCEPTION_RESET:
655 debug("RESET"); break;
656 case M88K_EXCEPTION_INTERRUPT:
657 debug("INTERRUPT"); break;
658 case M88K_EXCEPTION_INSTRUCTION_ACCESS:
659 debug("INSTRUCTION_ACCESS"); break;
660 case M88K_EXCEPTION_DATA_ACCESS:
661 debug("DATA_ACCESS"); break;
662 case M88K_EXCEPTION_MISALIGNED_ACCESS:
663 debug("MISALIGNED_ACCESS"); break;
664 case M88K_EXCEPTION_UNIMPLEMENTED_OPCODE:
665 debug("UNIMPLEMENTED_OPCODE"); break;
666 case M88K_EXCEPTION_PRIVILEGE_VIOLATION:
667 debug("PRIVILEGE_VIOLATION"); break;
668 case M88K_EXCEPTION_BOUNDS_CHECK_VIOLATION:
669 debug("BOUNDS_CHECK_VIOLATION"); break;
670 case M88K_EXCEPTION_ILLEGAL_INTEGER_DIVIDE:
671 debug("ILLEGAL_INTEGER_DIVIDE"); break;
672 case M88K_EXCEPTION_INTEGER_OVERFLOW:
673 debug("INTEGER_OVERFLOW"); break;
674 case M88K_EXCEPTION_ERROR:
675 debug("ERROR"); break;
676 case M88K_EXCEPTION_SFU1_PRECISE:
677 debug("SFU1_PRECISE"); break;
678 case M88K_EXCEPTION_SFU1_IMPRECISE:
679 debug("SFU1_IMPRECISE"); break;
680 case 0x80: /* up to OpenBSD 5.2 */
681 case 0x1c2: /* from OpenBSD 5.3 and forward... */
682 #if 0
683 fatal("[ syscall %i(", cpu->cd.m88k.r[13]);
684 m88k_cpu_functioncall_trace(cpu, 8);
685 fatal(") ]\n");
686 #endif
687 debug("syscall, r13=%i", cpu->cd.m88k.r[13]); break;
688 case MVMEPROM_VECTOR:
689 debug("MVMEPROM_VECTOR"); break;
690 default:debug("unknown"); break;
691 }
692 debug(" ]\n");
693
694 /* Stuff common for all exceptions: */
695 if (cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_SFRZ) {
696 /*
697 * Non-trap exceptions when the shadow freeze bit is already
698 * set result in an Error exception:
699 */
700 if (!is_trap) {
701 vector = M88K_EXCEPTION_ERROR;
702 fatal("[ SFRZ already set in PSR => ERROR ]\n");
703 }
704
705 update_shadow_regs = 0;
706 } else {
707 /* Freeze shadow registers, and save the PSR: */
708 cpu->cd.m88k.cr[M88K_CR_EPSR] = cpu->cd.m88k.cr[M88K_CR_PSR];
709 }
710
711 m88k_stcr(cpu, cpu->cd.m88k.cr[M88K_CR_PSR]
712 | M88K_PSR_SFRZ /* Freeze shadow registers, */
713 | M88K_PSR_IND /* disable interrupts, */
714 | M88K_PSR_SFD1 /* disable the floating point unit, */
715 | M88K_PSR_MODE, /* and switch to supervisor mode. */
716 M88K_CR_PSR, 0);
717
718 if (update_shadow_regs) {
719 cpu->cd.m88k.cr[M88K_CR_SSBR] = 0;
720
721 cpu->cd.m88k.cr[M88K_CR_SXIP] = cpu->pc | M88K_XIP_V;
722
723 /* SNIP is the address to return to, when executing rte: */
724 if (cpu->delay_slot) {
725 if (vector == M88K_EXCEPTION_DATA_ACCESS) {
726 cpu->cd.m88k.cr[M88K_CR_SNIP] = cpu->cd.m88k.delay_target | M88K_NIP_V;
727 cpu->cd.m88k.cr[M88K_CR_SFIP] = cpu->cd.m88k.cr[M88K_CR_SNIP]+4;
728 } else if (vector == M88K_EXCEPTION_INSTRUCTION_ACCESS) {
729 /* If we are in a delay slot, then pc is
730 something like 0xc6000 here (not 0xc5ffc). */
731 cpu->cd.m88k.cr[M88K_CR_SNIP] = cpu->cd.m88k.delay_target | M88K_NIP_V;
732 cpu->cd.m88k.cr[M88K_CR_SFIP] = 0;
733 } else {
734 /* Perhaps something like this could work: */
735 cpu->cd.m88k.cr[M88K_CR_SNIP] = (cpu->pc + 4) | M88K_NIP_V;
736 cpu->cd.m88k.cr[M88K_CR_SFIP] = cpu->cd.m88k.delay_target | M88K_NIP_V;
737 }
738 } else {
739 cpu->cd.m88k.cr[M88K_CR_SNIP] = (cpu->pc + 4) | M88K_NIP_V;
740 cpu->cd.m88k.cr[M88K_CR_SFIP] = cpu->cd.m88k.cr[M88K_CR_SNIP]+4;
741 }
742
743 if (vector == M88K_EXCEPTION_INSTRUCTION_ACCESS)
744 cpu->cd.m88k.cr[M88K_CR_SXIP] |= M88K_XIP_E;
745 }
746
747 cpu->pc = cpu->cd.m88k.cr[M88K_CR_VBR] + 8 * vector;
748
749 if (cpu->delay_slot)
750 cpu->delay_slot = EXCEPTION_IN_DELAY_SLOT;
751 else
752 cpu->delay_slot = NOT_DELAYED;
753
754 /* Default to no memory transactions: */
755 cpu->cd.m88k.cr[M88K_CR_DMT0] = 0;
756 cpu->cd.m88k.cr[M88K_CR_DMD0] = 0;
757 cpu->cd.m88k.cr[M88K_CR_DMA0] = 0;
758 cpu->cd.m88k.cr[M88K_CR_DMT1] = 0;
759 cpu->cd.m88k.cr[M88K_CR_DMD1] = 0;
760 cpu->cd.m88k.cr[M88K_CR_DMA1] = 0;
761 cpu->cd.m88k.cr[M88K_CR_DMT2] = 0;
762 cpu->cd.m88k.cr[M88K_CR_DMD2] = 0;
763 cpu->cd.m88k.cr[M88K_CR_DMA2] = 0;
764
765 /* Vector-specific handling: */
766 if (vector < M88K_EXCEPTION_USER_TRAPS_START) {
767 switch (vector) {
768
769 case M88K_EXCEPTION_RESET:
770 fatal("[ m88k_exception: reset ]\n");
771 exit(1);
772
773 case M88K_EXCEPTION_INTERRUPT:
774 /* When returning with rte, we want to re- */
775 /* execute the interrupted instruction: */
776 cpu->cd.m88k.cr[M88K_CR_SNIP] -= 4;
777 cpu->cd.m88k.cr[M88K_CR_SFIP] -= 4;
778 break;
779
780 case M88K_EXCEPTION_INSTRUCTION_ACCESS:
781 /* When returning with rte, we want to re- */
782 /* execute the instruction in SXIP, not SNIP/SFIP, */
783 /* (unless the exception was in a delay-slot): */
784 if (!(cpu->delay_slot & EXCEPTION_IN_DELAY_SLOT)) {
785 cpu->cd.m88k.cr[M88K_CR_SNIP] = 0;
786 cpu->cd.m88k.cr[M88K_CR_SFIP] = 0;
787 }
788 break;
789
790 case M88K_EXCEPTION_DATA_ACCESS:
791 /* Update the memory transaction registers: */
792 cpu->cd.m88k.cr[M88K_CR_DMT0] = cpu->cd.m88k.dmt[0];
793 cpu->cd.m88k.cr[M88K_CR_DMD0] = cpu->cd.m88k.dmd[0];
794 cpu->cd.m88k.cr[M88K_CR_DMA0] = cpu->cd.m88k.dma[0];
795 cpu->cd.m88k.cr[M88K_CR_DMT1] = cpu->cd.m88k.dmt[1];
796 cpu->cd.m88k.cr[M88K_CR_DMD1] = cpu->cd.m88k.dmd[1];
797 cpu->cd.m88k.cr[M88K_CR_DMA1] = cpu->cd.m88k.dma[1];
798 cpu->cd.m88k.cr[M88K_CR_DMT2] = 0;
799 cpu->cd.m88k.cr[M88K_CR_DMD2] = 0;
800 cpu->cd.m88k.cr[M88K_CR_DMA2] = 0;
801 m88k_memory_transaction_debug_dump(cpu, 0);
802 m88k_memory_transaction_debug_dump(cpu, 1);
803 break;
804
805 #if 0
806 case M88K_EXCEPTION_ILLEGAL_INTEGER_DIVIDE:
807 /* TODO: Is it correct to continue on the instruction
808 _after_ the division by zero? Or should the PC
809 be backed up one step? */
810 break;
811 #endif
812
813 #if 0
814 // TODO: Read up more about SFU1 exceptions and how the
815 // control registers look when they happen.
816 case M88K_EXCEPTION_SFU1_PRECISE:
817 cpu->cd.m88k.cr[M88K_CR_SNIP] = 0; //?
818 cpu->cd.m88k.cr[M88K_CR_SFIP] = 0;
819 //cpu->cd.m88k.cr[M88K_CR_SNIP] -= 4;
820 //cpu->cd.m88k.cr[M88K_CR_SFIP] -= 4;
821 break;
822 #endif
823
824 default:fatal("m88k_exception(): 0x%x: SXIP=0x%08x pc=0x%08x TODO\n",
825 vector,
826 cpu->cd.m88k.cr[M88K_CR_SXIP],
827 (int)cpu->pc);
828 fflush(stdout);
829 exit(1);
830 }
831 }
832
833 m88k_pc_to_pointers(cpu);
834 }
835
836
837 /*
838 * m88k_cpu_disassemble_instr():
839 *
840 * Convert an instruction word into human readable format, for instruction
841 * tracing.
842 *
843 * If running is 1, cpu->pc should be the address of the instruction.
844 *
845 * If running is 0, things that depend on the runtime environment (eg.
846 * register contents) will not be shown, and dumpaddr will be used instead of
847 * cpu->pc for relative addresses.
848 */
m88k_cpu_disassemble_instr(struct cpu * cpu,unsigned char * ib,int running,uint64_t dumpaddr)849 int m88k_cpu_disassemble_instr(struct cpu *cpu, unsigned char *ib,
850 int running, uint64_t dumpaddr)
851 {
852 int supervisor = cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE;
853 uint32_t iw;
854 const char *symbol, *mnem = NULL;
855 uint64_t offset;
856 uint32_t op26, op10, op11, d, s1, s2, w5, cr6, imm16;
857 int32_t d16, d26;
858
859 if (running)
860 dumpaddr = cpu->pc;
861
862 symbol = get_symbol_name(&cpu->machine->symbol_context,
863 dumpaddr, &offset);
864 if (symbol != NULL && offset == 0 && supervisor)
865 debug("<%s>\n", symbol);
866
867 if (cpu->machine->ncpus > 1 && running)
868 debug("cpu%i:\t", cpu->cpu_id);
869
870 debug("%c%08" PRIx32": ",
871 cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE? 's' : 'u',
872 (uint32_t) dumpaddr);
873
874 if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
875 iw = ib[0] + (ib[1]<<8) + (ib[2]<<16) + (ib[3]<<24);
876 else
877 iw = ib[3] + (ib[2]<<8) + (ib[1]<<16) + (ib[0]<<24);
878
879 debug("%08" PRIx32, (uint32_t) iw);
880
881 if (running && cpu->delay_slot)
882 debug(" (d)");
883
884 debug("\t");
885
886 op26 = (iw >> 26) & 0x3f;
887 op11 = (iw >> 11) & 0x1f;
888 op10 = (iw >> 10) & 0x3f;
889 d = (iw >> 21) & 0x1f;
890 s1 = (iw >> 16) & 0x1f;
891 s2 = iw & 0x1f;
892 imm16 = iw & 0xffff;
893 w5 = (iw >> 5) & 0x1f;
894 cr6 = (iw >> 5) & 0x3f;
895 d16 = ((int16_t) (iw & 0xffff)) * 4;
896 d26 = ((int32_t)((iw & 0x03ffffff) << 6)) >> 4;
897
898 switch (op26) {
899
900 case 0x00: /* xmem.bu */
901 case 0x01: /* xmem */
902 case 0x02: /* ld.hu */
903 case 0x03: /* ld.bu */
904 case 0x04: /* ld.d */
905 case 0x05: /* ld */
906 case 0x06: /* ld.h */
907 case 0x07: /* ld.b */
908 case 0x08: /* st.d */
909 case 0x09: /* st */
910 case 0x0a: /* st.h */
911 case 0x0b: /* st.b */
912 if (iw == 0x00000000) {
913 debug("-\n");
914 break;
915 }
916 switch (op26) {
917 case 0x00: debug("xmem.bu"); break;
918 case 0x01: debug("xmem"); break;
919 case 0x02: debug("ld.hu"); break;
920 case 0x03: debug("ld.bu"); break;
921 default: debug("%s%s", op26 >= 0x08? "st" : "ld",
922 memop[op26 & 3]);
923 }
924 debug("\tr%i,r%i,0x%x", d, s1, imm16);
925 if (running) {
926 uint32_t tmpaddr = cpu->cd.m88k.r[s1] + imm16;
927 symbol = get_symbol_name(&cpu->machine->symbol_context,
928 tmpaddr, &offset);
929 if (symbol != NULL && supervisor)
930 debug("\t; [<%s>]", symbol);
931 else
932 debug("\t; [0x%08" PRIx32"]", tmpaddr);
933 if (op26 >= 0x08) {
934 /* Store: */
935 debug(" = ");
936 switch (op26 & 3) {
937 case 0: debug("0x%016" PRIx64, (uint64_t)
938 ((((uint64_t) cpu->cd.m88k.r[d])
939 << 32) + ((uint64_t)
940 cpu->cd.m88k.r[d+1])) );
941 break;
942 case 1: debug("0x%08" PRIx32,
943 (uint32_t) cpu->cd.m88k.r[d]);
944 break;
945 case 2: debug("0x%04" PRIx16,
946 (uint16_t) cpu->cd.m88k.r[d]);
947 break;
948 case 3: debug("0x%02" PRIx8,
949 (uint8_t) cpu->cd.m88k.r[d]);
950 break;
951 }
952 } else {
953 /* Load: */
954 /* TODO */
955 }
956 } else {
957 /*
958 * Not running, but the following instruction
959 * sequence is quite common:
960 *
961 * or.u rX,r0,A
962 * st_or_ld rY,rX,B
963 */
964
965 /* Try loading the instruction before the
966 current one. */
967 uint32_t iw2 = 0;
968 cpu->memory_rw(cpu, cpu->mem,
969 dumpaddr - sizeof(uint32_t), (unsigned char *)&iw2,
970 sizeof(iw2), MEM_READ, CACHE_INSTRUCTION
971 | NO_EXCEPTIONS);
972 if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
973 iw2 = LE32_TO_HOST(iw2);
974 else
975 iw2 = BE32_TO_HOST(iw2);
976 if ((iw2 >> 26) == 0x17 && /* or.u */
977 ((iw2 >> 21) & 0x1f) == s1) {
978 uint32_t tmpaddr = (iw2 << 16) + imm16;
979 symbol = get_symbol_name(
980 &cpu->machine->symbol_context,
981 tmpaddr, &offset);
982 if (symbol != NULL && supervisor)
983 debug("\t; [<%s>]", symbol);
984 else
985 debug("\t; [0x%08" PRIx32"]", tmpaddr);
986 }
987 }
988 debug("\n");
989 break;
990
991 case 0x10: /* and */
992 case 0x11: /* and.u */
993 case 0x12: /* mask */
994 case 0x13: /* mask.u */
995 case 0x14: /* xor */
996 case 0x15: /* xor.u */
997 case 0x16: /* or */
998 case 0x17: /* or.u */
999 if (d == M88K_ZERO_REG)
1000 debug("nop");
1001
1002 switch (op26) {
1003 case 0x10:
1004 case 0x11: mnem = "and"; break;
1005 case 0x12:
1006 case 0x13: mnem = "mask"; break;
1007 case 0x14:
1008 case 0x15: mnem = "xor"; break;
1009 case 0x16:
1010 case 0x17: mnem = "or"; break;
1011 }
1012
1013 if (d != M88K_ZERO_REG || op26 != 0x16 || s1 != M88K_ZERO_REG) {
1014 if (d == M88K_ZERO_REG)
1015 debug("\t\t; weird nop encoding: ");
1016 debug("%s%s\t", mnem, op26 & 1? ".u" : "");
1017 debug("r%i,r%i,0x%x", d, s1, imm16);
1018 }
1019
1020 if (op26 == 0x16 && d != M88K_ZERO_REG) {
1021 /*
1022 * The following instruction sequence is common:
1023 *
1024 * or.u rX,r0,A
1025 * or rY,rX,B ; rY = AAAABBBB
1026 */
1027
1028 /* Try loading the instruction before the
1029 current one. */
1030 uint32_t iw2 = 0;
1031 cpu->memory_rw(cpu, cpu->mem,
1032 dumpaddr - sizeof(uint32_t), (unsigned char *)&iw2,
1033 sizeof(iw2), MEM_READ, CACHE_INSTRUCTION
1034 | NO_EXCEPTIONS);
1035 if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
1036 iw2 = LE32_TO_HOST(iw2);
1037 else
1038 iw2 = BE32_TO_HOST(iw2);
1039 if ((iw2 >> 26) == 0x17 && /* or.u */
1040 ((iw2 >> 21) & 0x1f) == s1) {
1041 uint32_t tmpaddr = (iw2 << 16) + imm16;
1042 symbol = get_symbol_name(
1043 &cpu->machine->symbol_context,
1044 tmpaddr, &offset);
1045 debug("\t; ");
1046 if (symbol != NULL && supervisor)
1047 debug("<%s>", symbol);
1048 else
1049 debug("0x%08" PRIx32, tmpaddr);
1050 }
1051 }
1052
1053 debug("\n");
1054 break;
1055
1056 case 0x18: /* addu */
1057 case 0x19: /* subu */
1058 case 0x1a: /* divu */
1059 case 0x1b: /* mulu */
1060 case 0x1c: /* add */
1061 case 0x1d: /* sub */
1062 case 0x1e: /* div */
1063 case 0x1f: /* cmp */
1064 switch (op26) {
1065 case 0x18: mnem = "addu"; break;
1066 case 0x19: mnem = "subu"; break;
1067 case 0x1a: mnem = "divu"; break;
1068 case 0x1b: mnem = "mulu"; break;
1069 case 0x1c: mnem = "add"; break;
1070 case 0x1d: mnem = "sub"; break;
1071 case 0x1e: mnem = "div"; break;
1072 case 0x1f: mnem = "cmp"; break;
1073 }
1074 debug("%s\tr%i,r%i,%i\n", mnem, d, s1, imm16);
1075 break;
1076
1077 case 0x20:
1078 if ((iw & 0x001ff81f) == 0x00004000) {
1079 debug("ldcr\tr%i,%s", d, m88k_cr_name(cpu, cr6));
1080 if (running)
1081 debug("\t\t; %s = 0x%08x", m88k_cr_name(cpu, cr6), cpu->cd.m88k.cr[cr6]);
1082 debug("\n");
1083 } else if ((iw & 0x001ff81f) == 0x00004800) {
1084 debug("fldcr\tr%i,%s\n", d, m88k_fcr_name(cpu, cr6));
1085 } else if ((iw & 0x03e0f800) == 0x00008000) {
1086 debug("stcr\tr%i,%s", s1, m88k_cr_name(cpu, cr6));
1087 if (s1 != s2)
1088 debug("\t\t; NOTE: weird encoding: "
1089 "low 5 bits = 0x%02x", s2);
1090 if (running)
1091 debug("\t\t; r%i = 0x%08x", s1, cpu->cd.m88k.r[s1]);
1092 debug("\n");
1093 } else if ((iw & 0x03e0f800) == 0x00008800) {
1094 debug("fstcr\tr%i,%s", s1,
1095 m88k_fcr_name(cpu, cr6));
1096 if (s1 != s2)
1097 debug("\t\t; NOTE: weird encoding: "
1098 "low 5 bits = 0x%02x", s2);
1099 debug("\n");
1100 } else if ((iw & 0x0000f800) == 0x0000c000) {
1101 debug("xcr\tr%i,r%i,%s", d, s1,
1102 m88k_cr_name(cpu, cr6));
1103 if (s1 != s2)
1104 debug("\t\t; NOTE: weird encoding: "
1105 "low 5 bits = 0x%02x", s2);
1106 debug("\n");
1107 } else if ((iw & 0x0000f800) == 0x0000c800) {
1108 debug("fxcr\tr%i,r%i,%s", d, s1,
1109 m88k_fcr_name(cpu, cr6));
1110 if (s1 != s2)
1111 debug("\t\t; NOTE: weird encoding: "
1112 "low 5 bits = 0x%02x", s2);
1113 debug("\n");
1114 } else {
1115 debug("UNIMPLEMENTED 0x20\n");
1116 }
1117 break;
1118
1119 case 0x21:
1120 switch (op11) {
1121 case 0x00: /* fmul */
1122 case 0x05: /* fadd */
1123 case 0x06: /* fsub */
1124 case 0x07: /* fcmp */
1125 case 0x0e: /* fdiv */
1126 switch (op11) {
1127 case 0x00: mnem = "fmul"; break;
1128 case 0x05: mnem = "fadd"; break;
1129 case 0x06: mnem = "fsub"; break;
1130 case 0x07: mnem = "fcmp"; break;
1131 case 0x0e: mnem = "fdiv"; break;
1132 }
1133 debug("%s.%c%c%c r%i,r%i,r%i\n",
1134 mnem,
1135 ((iw >> 5) & 1)? 'd' : 's',
1136 ((iw >> 9) & 1)? 'd' : 's',
1137 ((iw >> 7) & 1)? 'd' : 's',
1138 d, s1, s2);
1139 break;
1140 case 0x04: /* flt */
1141 switch (op11) {
1142 case 0x04: mnem = "flt"; break;
1143 }
1144 debug("%s.%cs\tr%i,r%i\n",
1145 mnem,
1146 ((iw >> 5) & 1)? 'd' : 's',
1147 d, s2);
1148 break;
1149 case 0x09: /* int */
1150 case 0x0a: /* nint */
1151 case 0x0b: /* trnc */
1152 switch (op11) {
1153 case 0x09: mnem = "int"; break;
1154 case 0x0a: mnem = "nint"; break;
1155 case 0x0b: mnem = "trnc"; break;
1156 }
1157 debug("%s.s%c r%i,r%i\n",
1158 mnem,
1159 ((iw >> 7) & 1)? 'd' : 's',
1160 d, s2);
1161 break;
1162 default:debug("UNIMPLEMENTED 0x21, op11=0x%02x\n", op11);
1163 }
1164 break;
1165
1166 case 0x30:
1167 case 0x31:
1168 case 0x32:
1169 case 0x33:
1170 debug("b%sr%s\t",
1171 op26 >= 0x32? "s" : "",
1172 op26 & 1? ".n" : "");
1173 debug("0x%08" PRIx32, (uint32_t) (dumpaddr + d26));
1174 symbol = get_symbol_name(&cpu->machine->symbol_context,
1175 dumpaddr + d26, &offset);
1176 if (symbol != NULL && supervisor)
1177 debug("\t; <%s>", symbol);
1178 debug("\n");
1179 break;
1180
1181 case 0x34: /* bb0 */
1182 case 0x35: /* bb0.n */
1183 case 0x36: /* bb1 */
1184 case 0x37: /* bb1.n */
1185 case 0x3a: /* bcnd */
1186 case 0x3b: /* bcnd.n */
1187 switch (op26) {
1188 case 0x34:
1189 case 0x35: mnem = "bb0"; break;
1190 case 0x36:
1191 case 0x37: mnem = "bb1"; break;
1192 case 0x3a:
1193 case 0x3b: mnem = "bcnd"; break;
1194 }
1195 debug("%s%s\t", mnem, op26 & 1? ".n" : "");
1196 if (op26 == 0x3a || op26 == 0x3b) {
1197 /* Attempt to decode bcnd condition: */
1198 switch (d) {
1199 case 0x1: debug("gt0"); break;
1200 case 0x2: debug("eq0"); break;
1201 case 0x3: debug("ge0"); break;
1202 case 0x7: debug("not_maxneg"); break;
1203 case 0x8: debug("maxneg"); break;
1204 case 0xc: debug("lt0"); break;
1205 case 0xd: debug("ne0"); break;
1206 case 0xe: debug("le0"); break;
1207 default: debug("unimplemented_%i", d);
1208 }
1209 } else {
1210 debug("%i", d);
1211 }
1212 debug(",r%i,0x%08" PRIx32, s1, (uint32_t) (dumpaddr + d16));
1213 symbol = get_symbol_name(&cpu->machine->symbol_context,
1214 dumpaddr + d16, &offset);
1215 if (symbol != NULL && supervisor)
1216 debug("\t; <%s>", symbol);
1217 debug("\n");
1218 break;
1219
1220 case 0x3c:
1221 if ((iw & 0x0000f000)==0x1000 || (iw & 0x0000f000)==0x2000) {
1222 int scale = 0;
1223
1224 /* Load/store: */
1225 debug("%s", (iw & 0x0000f000) == 0x1000? "ld" : "st");
1226 switch (iw & 0x00000c00) {
1227 case 0x000: scale = 8; debug(".d"); break;
1228 case 0x400: scale = 4; break;
1229 case 0x800: debug(".x"); break;
1230 default: debug(".UNIMPLEMENTED");
1231 }
1232 if (iw & 0x100)
1233 debug(".usr");
1234 if (iw & 0x80)
1235 debug(".wt");
1236 debug("\tr%i,r%i", d, s1);
1237 if (iw & 0x200)
1238 debug("[r%i]", s2);
1239 else
1240 debug(",r%i", s2);
1241
1242 if (running && scale >= 1) {
1243 uint32_t tmpaddr = cpu->cd.m88k.r[s1];
1244 if (iw & 0x200)
1245 tmpaddr += scale * cpu->cd.m88k.r[s2];
1246 else
1247 tmpaddr += cpu->cd.m88k.r[s2];
1248 symbol = get_symbol_name(&cpu->machine->
1249 symbol_context, tmpaddr, &offset);
1250 if (symbol != NULL && supervisor)
1251 debug("\t; [<%s>]", symbol);
1252 else
1253 debug("\t; [0x%08" PRIx32"]", tmpaddr);
1254 }
1255
1256 debug("\n");
1257 } else switch (op10) {
1258 case 0x20: /* clr */
1259 case 0x22: /* set */
1260 case 0x24: /* ext */
1261 case 0x26: /* extu */
1262 case 0x28: /* mak */
1263 case 0x2a: /* rot */
1264 switch (op10) {
1265 case 0x20: mnem = "clr"; break;
1266 case 0x22: mnem = "set"; break;
1267 case 0x24: mnem = "ext"; break;
1268 case 0x26: mnem = "extu"; break;
1269 case 0x28: mnem = "mak"; break;
1270 case 0x2a: mnem = "rot"; break;
1271 }
1272 debug("%s\tr%i,r%i,", mnem, d, s1);
1273 /* Don't include w5 for the rot instruction: */
1274 if (op10 != 0x2a)
1275 debug("%i", w5);
1276 /* Note: o5 = s2: */
1277 debug("<%i>\n", s2);
1278 break;
1279 case 0x34: /* tb0 */
1280 case 0x36: /* tb1 */
1281 switch (op10) {
1282 case 0x34: mnem = "tb0"; break;
1283 case 0x36: mnem = "tb1"; break;
1284 }
1285 debug("%s\t%i,r%i,0x%x\n", mnem, d, s1, iw & 0x1ff);
1286 break;
1287 default:debug("UNIMPLEMENTED 0x3c, op10=0x%02x\n", op10);
1288 }
1289 break;
1290
1291 case 0x3d:
1292 if ((iw & 0xf000) <= 0x3fff) {
1293 int scale = 0;
1294
1295 /* Load, Store, xmem, and lda: */
1296 switch (iw & 0xf000) {
1297 case 0x2000: debug("st"); break;
1298 case 0x3000: debug("lda"); break;
1299 default: if ((iw & 0xf800) >= 0x0800)
1300 debug("ld");
1301 else
1302 debug("xmem");
1303 }
1304 if ((iw & 0xf000) >= 0x1000) {
1305 /* ld, st, lda */
1306 scale = 1 << (3 - ((iw >> 10) & 3));
1307 debug("%s", memop[(iw >> 10) & 3]);
1308 } else if ((iw & 0xf800) == 0x0000) {
1309 /* xmem */
1310 if (iw & 0x400)
1311 scale = 4;
1312 else
1313 debug(".bu"), scale = 1;
1314 } else {
1315 /* ld */
1316 if ((iw & 0xf00) < 0xc00)
1317 debug(".hu"), scale = 2;
1318 else
1319 debug(".bu"), scale = 1;
1320 }
1321 if (iw & 0x100)
1322 debug(".usr");
1323 if (iw & 0x80)
1324 debug(".wt");
1325 debug("\tr%i,r%i", d, s1);
1326 if (iw & 0x200)
1327 debug("[r%i]", s2);
1328 else
1329 debug(",r%i", s2);
1330
1331 if (running && scale >= 1) {
1332 uint32_t tmpaddr = cpu->cd.m88k.r[s1];
1333 if (iw & 0x200)
1334 tmpaddr += scale * cpu->cd.m88k.r[s2];
1335 else
1336 tmpaddr += cpu->cd.m88k.r[s2];
1337 symbol = get_symbol_name(&cpu->machine->
1338 symbol_context, tmpaddr, &offset);
1339 if (symbol != NULL && supervisor)
1340 debug("\t; [<%s>]", symbol);
1341 else
1342 debug("\t; [0x%08" PRIx32"]", tmpaddr);
1343 }
1344
1345 debug("\n");
1346 } else switch ((iw >> 8) & 0xff) {
1347 case 0x40: /* and */
1348 case 0x44: /* and.c */
1349 case 0x50: /* xor */
1350 case 0x54: /* xor.c */
1351 case 0x58: /* or */
1352 case 0x5c: /* or.c */
1353 case 0x60: /* addu */
1354 case 0x61: /* addu.co */
1355 case 0x62: /* addu.ci */
1356 case 0x63: /* addu.cio */
1357 case 0x64: /* subu */
1358 case 0x65: /* subu.co */
1359 case 0x66: /* subu.ci */
1360 case 0x67: /* subu.cio */
1361 case 0x68: /* divu */
1362 case 0x69: /* divu.d */
1363 case 0x6c: /* mul */
1364 case 0x6d: /* mulu.d */
1365 case 0x6e: /* muls */
1366 case 0x70: /* add */
1367 case 0x71: /* add.co */
1368 case 0x72: /* add.ci */
1369 case 0x73: /* add.cio */
1370 case 0x74: /* sub */
1371 case 0x75: /* sub.co */
1372 case 0x76: /* sub.ci */
1373 case 0x77: /* sub.cio */
1374 case 0x78: /* div */
1375 case 0x7c: /* cmp */
1376 case 0x80: /* clr */
1377 case 0x88: /* set */
1378 case 0x90: /* ext */
1379 case 0x98: /* extu */
1380 case 0xa0: /* mak */
1381 case 0xa8: /* rot */
1382 /* Three-register opcodes: */
1383 switch ((iw >> 8) & 0xff) {
1384 case 0x40: mnem = "and"; break;
1385 case 0x44: mnem = "and.c"; break;
1386 case 0x50: mnem = "xor"; break;
1387 case 0x54: mnem = "xor.c"; break;
1388 case 0x58: mnem = "or"; break;
1389 case 0x5c: mnem = "or.c"; break;
1390 case 0x60: mnem = "addu"; break;
1391 case 0x61: mnem = "addu.co"; break;
1392 case 0x62: mnem = "addu.ci"; break;
1393 case 0x63: mnem = "addu.cio"; break;
1394 case 0x64: mnem = "subu"; break;
1395 case 0x65: mnem = "subu.co"; break;
1396 case 0x66: mnem = "subu.ci"; break;
1397 case 0x67: mnem = "subu.cio"; break;
1398 case 0x68: mnem = "divu"; break;
1399 case 0x69: mnem = "divu.d"; break;
1400 case 0x6c: mnem = "mul"; break;
1401 case 0x6d: mnem = "mulu.d"; break;
1402 case 0x6e: mnem = "muls"; break;
1403 case 0x70: mnem = "add"; break;
1404 case 0x71: mnem = "add.co"; break;
1405 case 0x72: mnem = "add.ci"; break;
1406 case 0x73: mnem = "add.cio"; break;
1407 case 0x74: mnem = "sub"; break;
1408 case 0x75: mnem = "sub.co"; break;
1409 case 0x76: mnem = "sub.ci"; break;
1410 case 0x77: mnem = "sub.cio"; break;
1411 case 0x78: mnem = "div"; break;
1412 case 0x7c: mnem = "cmp"; break;
1413 case 0x80: mnem = "clr"; break;
1414 case 0x88: mnem = "set"; break;
1415 case 0x90: mnem = "ext"; break;
1416 case 0x98: mnem = "extu"; break;
1417 case 0xa0: mnem = "mak"; break;
1418 case 0xa8: mnem = "rot"; break;
1419 }
1420
1421 if (((iw >> 8) & 0xff) == 0x58 && d == M88K_ZERO_REG)
1422 debug("nop");
1423
1424 if (((iw >> 8) & 0xff) != 0x58 || d != M88K_ZERO_REG) {
1425 if (d == M88K_ZERO_REG)
1426 debug("\t\t; weird nop encoding: ");
1427 debug("%s\tr%i,r%i,r%i", mnem, d, s1, s2);
1428 }
1429
1430 debug("\n");
1431 break;
1432 case 0xc0: /* jmp */
1433 case 0xc4: /* jmp.n */
1434 case 0xc8: /* jsr */
1435 case 0xcc: /* jsr.n */
1436 debug("%s%s\t(r%i)",
1437 op11 & 1? "jsr" : "jmp",
1438 iw & 0x400? ".n" : "",
1439 s2);
1440 if (running) {
1441 uint32_t tmpaddr = cpu->cd.m88k.r[s2];
1442 symbol = get_symbol_name(&cpu->machine->
1443 symbol_context, tmpaddr, &offset);
1444 debug("\t\t; ");
1445 if (symbol != NULL && supervisor)
1446 debug("<%s>", symbol);
1447 else
1448 debug("0x%08" PRIx32, tmpaddr);
1449 }
1450 debug("\n");
1451 break;
1452 case 0xe8: /* ff1 */
1453 case 0xec: /* ff0 */
1454 debug("%s\tr%i,r%i\n",
1455 ((iw >> 8) & 0xff) == 0xe8 ? "ff1" : "ff0", d, s2);
1456 break;
1457 case 0xf8: /* tbnd */
1458 debug("tbnd\tr%i,r%i\n", s1, s2);
1459 break;
1460 case 0xfc:
1461 switch (iw & 0xff) {
1462 case 0x00:
1463 debug("rte\n");
1464 break;
1465 case 0x01:
1466 case 0x02:
1467 case 0x03:
1468 debug("illop%i\n", iw & 0xff);
1469 break;
1470 case (M88K_PROM_INSTR & 0xff):
1471 debug("gxemul_prom_call\n");
1472 break;
1473 default:debug("UNIMPLEMENTED 0x3d,0xfc: 0x%02x\n",
1474 iw & 0xff);
1475 }
1476 break;
1477 default:debug("UNIMPLEMENTED 0x3d, opbyte = 0x%02x\n",
1478 (iw >> 8) & 0xff);
1479 }
1480 break;
1481
1482 case 0x3e:
1483 debug("tbnd\tr%i,0x%x\n", s1, imm16);
1484 break;
1485
1486 default:debug("UNIMPLEMENTED op26=0x%02x\n", op26);
1487 }
1488
1489 return sizeof(uint32_t);
1490 }
1491
1492
1493 #include "tmp_m88k_tail.cc"
1494
1495
1496