cpu_m88k.cc Source File

Back to the index.

cpu_m88k.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2005-2018 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 
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 
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 */
80  cr_names = m88k_cr_197_names;
81 
82  return cr_names[i];
83 }
84 
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  */
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;
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;
131 
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;
178  }
179 
180  /* Set the Processor ID: */
182 
183  /* Start in supervisor mode, with interrupts disabled. */
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  */
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  */
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  */
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  */
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 */
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  */
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);
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  */
408 {
409  struct cpu *cpu = (struct cpu *) interrupt->extra;
410  cpu->cd.m88k.irq_asserted = 1;
411 }
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  */
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  */
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 Regoster */
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))
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  */
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  */
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  */
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) {
655  debug("RESET"); break;
657  debug("INTERRUPT"); break;
659  debug("INSTRUCTION_ACCESS"); break;
661  debug("DATA_ACCESS"); break;
663  debug("MISALIGNED_ACCESS"); break;
665  debug("UNIMPLEMENTED_OPCODE"); break;
667  debug("PRIVILEGE_VIOLATION"); break;
669  debug("BOUNDS_CHECK_VIOLATION"); break;
671  debug("ILLEGAL_INTEGER_DIVIDE"); break;
673  debug("INTEGER_OVERFLOW"); break;
675  debug("ERROR"); break;
677  debug("SFU1_PRECISE"); break;
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]);
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) {
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). */
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;
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)
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 
770  fatal("[ m88k_exception: reset ]\n");
771  exit(1);
772 
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 
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 
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
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  default:fatal("m88k_exception(): 0x%x: TODO\n", vector);
814  fflush(stdout);
815  exit(1);
816  }
817  }
818 
819  m88k_pc_to_pointers(cpu);
820 }
821 
822 
823 /*
824  * m88k_cpu_disassemble_instr():
825  *
826  * Convert an instruction word into human readable format, for instruction
827  * tracing.
828  *
829  * If running is 1, cpu->pc should be the address of the instruction.
830  *
831  * If running is 0, things that depend on the runtime environment (eg.
832  * register contents) will not be shown, and dumpaddr will be used instead of
833  * cpu->pc for relative addresses.
834  */
835 int m88k_cpu_disassemble_instr(struct cpu *cpu, unsigned char *ib,
836  int running, uint64_t dumpaddr)
837 {
838  int supervisor = cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE;
839  uint32_t iw;
840  const char *symbol, *mnem = NULL;
841  uint64_t offset;
842  uint32_t op26, op10, op11, d, s1, s2, w5, cr6, imm16;
843  int32_t d16, d26;
844 
845  if (running)
846  dumpaddr = cpu->pc;
847 
848  symbol = get_symbol_name(&cpu->machine->symbol_context,
849  dumpaddr, &offset);
850  if (symbol != NULL && offset == 0 && supervisor)
851  debug("<%s>\n", symbol);
852 
853  if (cpu->machine->ncpus > 1 && running)
854  debug("cpu%i:\t", cpu->cpu_id);
855 
856  debug("%c%08" PRIx32": ",
857  cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE? 's' : 'u',
858  (uint32_t) dumpaddr);
859 
860  if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
861  iw = ib[0] + (ib[1]<<8) + (ib[2]<<16) + (ib[3]<<24);
862  else
863  iw = ib[3] + (ib[2]<<8) + (ib[1]<<16) + (ib[0]<<24);
864 
865  debug("%08" PRIx32, (uint32_t) iw);
866 
867  if (running && cpu->delay_slot)
868  debug(" (d)");
869 
870  debug("\t");
871 
872  op26 = (iw >> 26) & 0x3f;
873  op11 = (iw >> 11) & 0x1f;
874  op10 = (iw >> 10) & 0x3f;
875  d = (iw >> 21) & 0x1f;
876  s1 = (iw >> 16) & 0x1f;
877  s2 = iw & 0x1f;
878  imm16 = iw & 0xffff;
879  w5 = (iw >> 5) & 0x1f;
880  cr6 = (iw >> 5) & 0x3f;
881  d16 = ((int16_t) (iw & 0xffff)) * 4;
882  d26 = ((int32_t)((iw & 0x03ffffff) << 6)) >> 4;
883 
884  switch (op26) {
885 
886  case 0x00: /* xmem.bu */
887  case 0x01: /* xmem */
888  case 0x02: /* ld.hu */
889  case 0x03: /* ld.bu */
890  case 0x04: /* ld.d */
891  case 0x05: /* ld */
892  case 0x06: /* ld.h */
893  case 0x07: /* ld.b */
894  case 0x08: /* st.d */
895  case 0x09: /* st */
896  case 0x0a: /* st.h */
897  case 0x0b: /* st.b */
898  if (iw == 0x00000000) {
899  debug("-\n");
900  break;
901  }
902  switch (op26) {
903  case 0x00: debug("xmem.bu"); break;
904  case 0x01: debug("xmem"); break;
905  case 0x02: debug("ld.hu"); break;
906  case 0x03: debug("ld.bu"); break;
907  default: debug("%s%s", op26 >= 0x08? "st" : "ld",
908  memop[op26 & 3]);
909  }
910  debug("\tr%i,r%i,0x%x", d, s1, imm16);
911  if (running) {
912  uint32_t tmpaddr = cpu->cd.m88k.r[s1] + imm16;
913  symbol = get_symbol_name(&cpu->machine->symbol_context,
914  tmpaddr, &offset);
915  if (symbol != NULL && supervisor)
916  debug("\t; [<%s>]", symbol);
917  else
918  debug("\t; [0x%08" PRIx32"]", tmpaddr);
919  if (op26 >= 0x08) {
920  /* Store: */
921  debug(" = ");
922  switch (op26 & 3) {
923  case 0: debug("0x%016" PRIx64, (uint64_t)
924  ((((uint64_t) cpu->cd.m88k.r[d])
925  << 32) + ((uint64_t)
926  cpu->cd.m88k.r[d+1])) );
927  break;
928  case 1: debug("0x%08" PRIx32,
929  (uint32_t) cpu->cd.m88k.r[d]);
930  break;
931  case 2: debug("0x%04" PRIx16,
932  (uint16_t) cpu->cd.m88k.r[d]);
933  break;
934  case 3: debug("0x%02" PRIx8,
935  (uint8_t) cpu->cd.m88k.r[d]);
936  break;
937  }
938  } else {
939  /* Load: */
940  /* TODO */
941  }
942  } else {
943  /*
944  * Not running, but the following instruction
945  * sequence is quite common:
946  *
947  * or.u rX,r0,A
948  * st_or_ld rY,rX,B
949  */
950 
951  /* Try loading the instruction before the
952  current one. */
953  uint32_t iw2 = 0;
954  cpu->memory_rw(cpu, cpu->mem,
955  dumpaddr - sizeof(uint32_t), (unsigned char *)&iw2,
956  sizeof(iw2), MEM_READ, CACHE_INSTRUCTION
957  | NO_EXCEPTIONS);
958  if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
959  iw2 = LE32_TO_HOST(iw2);
960  else
961  iw2 = BE32_TO_HOST(iw2);
962  if ((iw2 >> 26) == 0x17 && /* or.u */
963  ((iw2 >> 21) & 0x1f) == s1) {
964  uint32_t tmpaddr = (iw2 << 16) + imm16;
965  symbol = get_symbol_name(
966  &cpu->machine->symbol_context,
967  tmpaddr, &offset);
968  if (symbol != NULL && supervisor)
969  debug("\t; [<%s>]", symbol);
970  else
971  debug("\t; [0x%08" PRIx32"]", tmpaddr);
972  }
973  }
974  debug("\n");
975  break;
976 
977  case 0x10: /* and */
978  case 0x11: /* and.u */
979  case 0x12: /* mask */
980  case 0x13: /* mask.u */
981  case 0x14: /* xor */
982  case 0x15: /* xor.u */
983  case 0x16: /* or */
984  case 0x17: /* or.u */
985  if (d == M88K_ZERO_REG)
986  debug("nop");
987 
988  switch (op26) {
989  case 0x10:
990  case 0x11: mnem = "and"; break;
991  case 0x12:
992  case 0x13: mnem = "mask"; break;
993  case 0x14:
994  case 0x15: mnem = "xor"; break;
995  case 0x16:
996  case 0x17: mnem = "or"; break;
997  }
998 
999  if (d != M88K_ZERO_REG || op26 != 0x16 || s1 != M88K_ZERO_REG) {
1000  if (d == M88K_ZERO_REG)
1001  debug("\t\t; weird nop encoding: ");
1002  debug("%s%s\t", mnem, op26 & 1? ".u" : "");
1003  debug("r%i,r%i,0x%x", d, s1, imm16);
1004  }
1005 
1006  if (op26 == 0x16 && d != M88K_ZERO_REG) {
1007  /*
1008  * The following instruction sequence is common:
1009  *
1010  * or.u rX,r0,A
1011  * or rY,rX,B ; rY = AAAABBBB
1012  */
1013 
1014  /* Try loading the instruction before the
1015  current one. */
1016  uint32_t iw2 = 0;
1017  cpu->memory_rw(cpu, cpu->mem,
1018  dumpaddr - sizeof(uint32_t), (unsigned char *)&iw2,
1019  sizeof(iw2), MEM_READ, CACHE_INSTRUCTION
1020  | NO_EXCEPTIONS);
1021  if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
1022  iw2 = LE32_TO_HOST(iw2);
1023  else
1024  iw2 = BE32_TO_HOST(iw2);
1025  if ((iw2 >> 26) == 0x17 && /* or.u */
1026  ((iw2 >> 21) & 0x1f) == s1) {
1027  uint32_t tmpaddr = (iw2 << 16) + imm16;
1028  symbol = get_symbol_name(
1029  &cpu->machine->symbol_context,
1030  tmpaddr, &offset);
1031  debug("\t; ");
1032  if (symbol != NULL && supervisor)
1033  debug("<%s>", symbol);
1034  else
1035  debug("0x%08" PRIx32, tmpaddr);
1036  }
1037  }
1038 
1039  debug("\n");
1040  break;
1041 
1042  case 0x18: /* addu */
1043  case 0x19: /* subu */
1044  case 0x1a: /* divu */
1045  case 0x1b: /* mulu */
1046  case 0x1c: /* add */
1047  case 0x1d: /* sub */
1048  case 0x1e: /* div */
1049  case 0x1f: /* cmp */
1050  switch (op26) {
1051  case 0x18: mnem = "addu"; break;
1052  case 0x19: mnem = "subu"; break;
1053  case 0x1a: mnem = "divu"; break;
1054  case 0x1b: mnem = "mulu"; break;
1055  case 0x1c: mnem = "add"; break;
1056  case 0x1d: mnem = "sub"; break;
1057  case 0x1e: mnem = "div"; break;
1058  case 0x1f: mnem = "cmp"; break;
1059  }
1060  debug("%s\tr%i,r%i,%i\n", mnem, d, s1, imm16);
1061  break;
1062 
1063  case 0x20:
1064  if ((iw & 0x001ff81f) == 0x00004000) {
1065  debug("ldcr\tr%i,%s", d, m88k_cr_name(cpu, cr6));
1066  if (running)
1067  debug("\t\t; %s = 0x%08x", m88k_cr_name(cpu, cr6), cpu->cd.m88k.cr[cr6]);
1068  debug("\n");
1069  } else if ((iw & 0x001ff81f) == 0x00004800) {
1070  debug("fldcr\tr%i,%s\n", d, m88k_fcr_name(cpu, cr6));
1071  } else if ((iw & 0x03e0f800) == 0x00008000) {
1072  debug("stcr\tr%i,%s", s1, m88k_cr_name(cpu, cr6));
1073  if (s1 != s2)
1074  debug("\t\t; NOTE: weird encoding: "
1075  "low 5 bits = 0x%02x", s2);
1076  if (running)
1077  debug("\t\t; r%i = 0x%08x", s1, cpu->cd.m88k.r[s1]);
1078  debug("\n");
1079  } else if ((iw & 0x03e0f800) == 0x00008800) {
1080  debug("fstcr\tr%i,%s", s1,
1081  m88k_fcr_name(cpu, cr6));
1082  if (s1 != s2)
1083  debug("\t\t; NOTE: weird encoding: "
1084  "low 5 bits = 0x%02x", s2);
1085  debug("\n");
1086  } else if ((iw & 0x0000f800) == 0x0000c000) {
1087  debug("xcr\tr%i,r%i,%s", d, s1,
1088  m88k_cr_name(cpu, cr6));
1089  if (s1 != s2)
1090  debug("\t\t; NOTE: weird encoding: "
1091  "low 5 bits = 0x%02x", s2);
1092  debug("\n");
1093  } else if ((iw & 0x0000f800) == 0x0000c800) {
1094  debug("fxcr\tr%i,r%i,%s", d, 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 {
1101  debug("UNIMPLEMENTED 0x20\n");
1102  }
1103  break;
1104 
1105  case 0x21:
1106  switch (op11) {
1107  case 0x00: /* fmul */
1108  case 0x05: /* fadd */
1109  case 0x06: /* fsub */
1110  case 0x07: /* fcmp */
1111  case 0x0e: /* fdiv */
1112  switch (op11) {
1113  case 0x00: mnem = "fmul"; break;
1114  case 0x05: mnem = "fadd"; break;
1115  case 0x06: mnem = "fsub"; break;
1116  case 0x07: mnem = "fcmp"; break;
1117  case 0x0e: mnem = "fdiv"; break;
1118  }
1119  debug("%s.%c%c%c r%i,r%i,r%i\n",
1120  mnem,
1121  ((iw >> 5) & 1)? 'd' : 's',
1122  ((iw >> 9) & 1)? 'd' : 's',
1123  ((iw >> 7) & 1)? 'd' : 's',
1124  d, s1, s2);
1125  break;
1126  case 0x04: /* flt */
1127  switch (op11) {
1128  case 0x04: mnem = "flt"; break;
1129  }
1130  debug("%s.%cs\tr%i,r%i\n",
1131  mnem,
1132  ((iw >> 5) & 1)? 'd' : 's',
1133  d, s2);
1134  break;
1135  case 0x09: /* int */
1136  case 0x0a: /* nint */
1137  case 0x0b: /* trnc */
1138  switch (op11) {
1139  case 0x09: mnem = "int"; break;
1140  case 0x0a: mnem = "nint"; break;
1141  case 0x0b: mnem = "trnc"; break;
1142  }
1143  debug("%s.s%c r%i,r%i\n",
1144  mnem,
1145  ((iw >> 7) & 1)? 'd' : 's',
1146  d, s2);
1147  break;
1148  default:debug("UNIMPLEMENTED 0x21, op11=0x%02x\n", op11);
1149  }
1150  break;
1151 
1152  case 0x30:
1153  case 0x31:
1154  case 0x32:
1155  case 0x33:
1156  debug("b%sr%s\t",
1157  op26 >= 0x32? "s" : "",
1158  op26 & 1? ".n" : "");
1159  debug("0x%08" PRIx32, (uint32_t) (dumpaddr + d26));
1160  symbol = get_symbol_name(&cpu->machine->symbol_context,
1161  dumpaddr + d26, &offset);
1162  if (symbol != NULL && supervisor)
1163  debug("\t; <%s>", symbol);
1164  debug("\n");
1165  break;
1166 
1167  case 0x34: /* bb0 */
1168  case 0x35: /* bb0.n */
1169  case 0x36: /* bb1 */
1170  case 0x37: /* bb1.n */
1171  case 0x3a: /* bcnd */
1172  case 0x3b: /* bcnd.n */
1173  switch (op26) {
1174  case 0x34:
1175  case 0x35: mnem = "bb0"; break;
1176  case 0x36:
1177  case 0x37: mnem = "bb1"; break;
1178  case 0x3a:
1179  case 0x3b: mnem = "bcnd"; break;
1180  }
1181  debug("%s%s\t", mnem, op26 & 1? ".n" : "");
1182  if (op26 == 0x3a || op26 == 0x3b) {
1183  /* Attempt to decode bcnd condition: */
1184  switch (d) {
1185  case 0x1: debug("gt0"); break;
1186  case 0x2: debug("eq0"); break;
1187  case 0x3: debug("ge0"); break;
1188  case 0x7: debug("not_maxneg"); break;
1189  case 0x8: debug("maxneg"); break;
1190  case 0xc: debug("lt0"); break;
1191  case 0xd: debug("ne0"); break;
1192  case 0xe: debug("le0"); break;
1193  default: debug("unimplemented_%i", d);
1194  }
1195  } else {
1196  debug("%i", d);
1197  }
1198  debug(",r%i,0x%08" PRIx32, s1, (uint32_t) (dumpaddr + d16));
1199  symbol = get_symbol_name(&cpu->machine->symbol_context,
1200  dumpaddr + d16, &offset);
1201  if (symbol != NULL && supervisor)
1202  debug("\t; <%s>", symbol);
1203  debug("\n");
1204  break;
1205 
1206  case 0x3c:
1207  if ((iw & 0x0000f000)==0x1000 || (iw & 0x0000f000)==0x2000) {
1208  int scale = 0;
1209 
1210  /* Load/store: */
1211  debug("%s", (iw & 0x0000f000) == 0x1000? "ld" : "st");
1212  switch (iw & 0x00000c00) {
1213  case 0x000: scale = 8; debug(".d"); break;
1214  case 0x400: scale = 4; break;
1215  case 0x800: debug(".x"); break;
1216  default: debug(".UNIMPLEMENTED");
1217  }
1218  if (iw & 0x100)
1219  debug(".usr");
1220  if (iw & 0x80)
1221  debug(".wt");
1222  debug("\tr%i,r%i", d, s1);
1223  if (iw & 0x200)
1224  debug("[r%i]", s2);
1225  else
1226  debug(",r%i", s2);
1227 
1228  if (running && scale >= 1) {
1229  uint32_t tmpaddr = cpu->cd.m88k.r[s1];
1230  if (iw & 0x200)
1231  tmpaddr += scale * cpu->cd.m88k.r[s2];
1232  else
1233  tmpaddr += cpu->cd.m88k.r[s2];
1234  symbol = get_symbol_name(&cpu->machine->
1235  symbol_context, tmpaddr, &offset);
1236  if (symbol != NULL && supervisor)
1237  debug("\t; [<%s>]", symbol);
1238  else
1239  debug("\t; [0x%08" PRIx32"]", tmpaddr);
1240  }
1241 
1242  debug("\n");
1243  } else switch (op10) {
1244  case 0x20: /* clr */
1245  case 0x22: /* set */
1246  case 0x24: /* ext */
1247  case 0x26: /* extu */
1248  case 0x28: /* mak */
1249  case 0x2a: /* rot */
1250  switch (op10) {
1251  case 0x20: mnem = "clr"; break;
1252  case 0x22: mnem = "set"; break;
1253  case 0x24: mnem = "ext"; break;
1254  case 0x26: mnem = "extu"; break;
1255  case 0x28: mnem = "mak"; break;
1256  case 0x2a: mnem = "rot"; break;
1257  }
1258  debug("%s\tr%i,r%i,", mnem, d, s1);
1259  /* Don't include w5 for the rot instruction: */
1260  if (op10 != 0x2a)
1261  debug("%i", w5);
1262  /* Note: o5 = s2: */
1263  debug("<%i>\n", s2);
1264  break;
1265  case 0x34: /* tb0 */
1266  case 0x36: /* tb1 */
1267  switch (op10) {
1268  case 0x34: mnem = "tb0"; break;
1269  case 0x36: mnem = "tb1"; break;
1270  }
1271  debug("%s\t%i,r%i,0x%x\n", mnem, d, s1, iw & 0x1ff);
1272  break;
1273  default:debug("UNIMPLEMENTED 0x3c, op10=0x%02x\n", op10);
1274  }
1275  break;
1276 
1277  case 0x3d:
1278  if ((iw & 0xf000) <= 0x3fff) {
1279  int scale = 0;
1280 
1281  /* Load, Store, xmem, and lda: */
1282  switch (iw & 0xf000) {
1283  case 0x2000: debug("st"); break;
1284  case 0x3000: debug("lda"); break;
1285  default: if ((iw & 0xf800) >= 0x0800)
1286  debug("ld");
1287  else
1288  debug("xmem");
1289  }
1290  if ((iw & 0xf000) >= 0x1000) {
1291  /* ld, st, lda */
1292  scale = 1 << (3 - ((iw >> 10) & 3));
1293  debug("%s", memop[(iw >> 10) & 3]);
1294  } else if ((iw & 0xf800) == 0x0000) {
1295  /* xmem */
1296  if (iw & 0x400)
1297  scale = 4;
1298  else
1299  debug(".bu"), scale = 1;
1300  } else {
1301  /* ld */
1302  if ((iw & 0xf00) < 0xc00)
1303  debug(".hu"), scale = 2;
1304  else
1305  debug(".bu"), scale = 1;
1306  }
1307  if (iw & 0x100)
1308  debug(".usr");
1309  if (iw & 0x80)
1310  debug(".wt");
1311  debug("\tr%i,r%i", d, s1);
1312  if (iw & 0x200)
1313  debug("[r%i]", s2);
1314  else
1315  debug(",r%i", s2);
1316 
1317  if (running && scale >= 1) {
1318  uint32_t tmpaddr = cpu->cd.m88k.r[s1];
1319  if (iw & 0x200)
1320  tmpaddr += scale * cpu->cd.m88k.r[s2];
1321  else
1322  tmpaddr += cpu->cd.m88k.r[s2];
1323  symbol = get_symbol_name(&cpu->machine->
1324  symbol_context, tmpaddr, &offset);
1325  if (symbol != NULL && supervisor)
1326  debug("\t; [<%s>]", symbol);
1327  else
1328  debug("\t; [0x%08" PRIx32"]", tmpaddr);
1329  }
1330 
1331  debug("\n");
1332  } else switch ((iw >> 8) & 0xff) {
1333  case 0x40: /* and */
1334  case 0x44: /* and.c */
1335  case 0x50: /* xor */
1336  case 0x54: /* xor.c */
1337  case 0x58: /* or */
1338  case 0x5c: /* or.c */
1339  case 0x60: /* addu */
1340  case 0x61: /* addu.co */
1341  case 0x62: /* addu.ci */
1342  case 0x63: /* addu.cio */
1343  case 0x64: /* subu */
1344  case 0x65: /* subu.co */
1345  case 0x66: /* subu.ci */
1346  case 0x67: /* subu.cio */
1347  case 0x68: /* divu */
1348  case 0x69: /* divu.d */
1349  case 0x6c: /* mul */
1350  case 0x6d: /* mulu.d */
1351  case 0x6e: /* muls */
1352  case 0x70: /* add */
1353  case 0x71: /* add.co */
1354  case 0x72: /* add.ci */
1355  case 0x73: /* add.cio */
1356  case 0x74: /* sub */
1357  case 0x75: /* sub.co */
1358  case 0x76: /* sub.ci */
1359  case 0x77: /* sub.cio */
1360  case 0x78: /* div */
1361  case 0x7c: /* cmp */
1362  case 0x80: /* clr */
1363  case 0x88: /* set */
1364  case 0x90: /* ext */
1365  case 0x98: /* extu */
1366  case 0xa0: /* mak */
1367  case 0xa8: /* rot */
1368  /* Three-register opcodes: */
1369  switch ((iw >> 8) & 0xff) {
1370  case 0x40: mnem = "and"; break;
1371  case 0x44: mnem = "and.c"; break;
1372  case 0x50: mnem = "xor"; break;
1373  case 0x54: mnem = "xor.c"; break;
1374  case 0x58: mnem = "or"; break;
1375  case 0x5c: mnem = "or.c"; break;
1376  case 0x60: mnem = "addu"; break;
1377  case 0x61: mnem = "addu.co"; break;
1378  case 0x62: mnem = "addu.ci"; break;
1379  case 0x63: mnem = "addu.cio"; break;
1380  case 0x64: mnem = "subu"; break;
1381  case 0x65: mnem = "subu.co"; break;
1382  case 0x66: mnem = "subu.ci"; break;
1383  case 0x67: mnem = "subu.cio"; break;
1384  case 0x68: mnem = "divu"; break;
1385  case 0x69: mnem = "divu.d"; break;
1386  case 0x6c: mnem = "mul"; break;
1387  case 0x6d: mnem = "mulu.d"; break;
1388  case 0x6e: mnem = "muls"; break;
1389  case 0x70: mnem = "add"; break;
1390  case 0x71: mnem = "add.co"; break;
1391  case 0x72: mnem = "add.ci"; break;
1392  case 0x73: mnem = "add.cio"; break;
1393  case 0x74: mnem = "sub"; break;
1394  case 0x75: mnem = "sub.co"; break;
1395  case 0x76: mnem = "sub.ci"; break;
1396  case 0x77: mnem = "sub.cio"; break;
1397  case 0x78: mnem = "div"; break;
1398  case 0x7c: mnem = "cmp"; break;
1399  case 0x80: mnem = "clr"; break;
1400  case 0x88: mnem = "set"; break;
1401  case 0x90: mnem = "ext"; break;
1402  case 0x98: mnem = "extu"; break;
1403  case 0xa0: mnem = "mak"; break;
1404  case 0xa8: mnem = "rot"; break;
1405  }
1406 
1407  if (((iw >> 8) & 0xff) == 0x58 && d == M88K_ZERO_REG)
1408  debug("nop");
1409 
1410  if (((iw >> 8) & 0xff) != 0x58 || d != M88K_ZERO_REG) {
1411  if (d == M88K_ZERO_REG)
1412  debug("\t\t; weird nop encoding: ");
1413  debug("%s\tr%i,r%i,r%i", mnem, d, s1, s2);
1414  }
1415 
1416  debug("\n");
1417  break;
1418  case 0xc0: /* jmp */
1419  case 0xc4: /* jmp.n */
1420  case 0xc8: /* jsr */
1421  case 0xcc: /* jsr.n */
1422  debug("%s%s\t(r%i)",
1423  op11 & 1? "jsr" : "jmp",
1424  iw & 0x400? ".n" : "",
1425  s2);
1426  if (running) {
1427  uint32_t tmpaddr = cpu->cd.m88k.r[s2];
1428  symbol = get_symbol_name(&cpu->machine->
1429  symbol_context, tmpaddr, &offset);
1430  debug("\t\t; ");
1431  if (symbol != NULL && supervisor)
1432  debug("<%s>", symbol);
1433  else
1434  debug("0x%08" PRIx32, tmpaddr);
1435  }
1436  debug("\n");
1437  break;
1438  case 0xe8: /* ff1 */
1439  case 0xec: /* ff0 */
1440  debug("%s\tr%i,r%i\n",
1441  ((iw >> 8) & 0xff) == 0xe8 ? "ff1" : "ff0", d, s2);
1442  break;
1443  case 0xf8: /* tbnd */
1444  debug("tbnd\tr%i,r%i\n", s1, s2);
1445  break;
1446  case 0xfc:
1447  switch (iw & 0xff) {
1448  case 0x00:
1449  debug("rte\n");
1450  break;
1451  case 0x01:
1452  case 0x02:
1453  case 0x03:
1454  debug("illop%i\n", iw & 0xff);
1455  break;
1456  case (M88K_PROM_INSTR & 0xff):
1457  debug("gxemul_prom_call\n");
1458  break;
1459  default:debug("UNIMPLEMENTED 0x3d,0xfc: 0x%02x\n",
1460  iw & 0xff);
1461  }
1462  break;
1463  default:debug("UNIMPLEMENTED 0x3d, opbyte = 0x%02x\n",
1464  (iw >> 8) & 0xff);
1465  }
1466  break;
1467 
1468  case 0x3e:
1469  debug("tbnd\tr%i,0x%x\n", s1, imm16);
1470  break;
1471 
1472  default:debug("UNIMPLEMENTED op26=0x%02x\n", op26);
1473  }
1474 
1475  return sizeof(uint32_t);
1476 }
1477 
1478 
1479 #include "tmp_m88k_tail.cc"
1480 
1481 
#define M88K_CR_DMA1
#define MVMEPROM_VECTOR
Definition: mvmeprom.h:34
int m88k_cpu_instruction_has_delayslot(struct cpu *cpu, unsigned char *ib)
Definition: cpu_m88k.cc:236
void fatal(const char *fmt,...)
Definition: main.cc:152
char * name
Definition: cpu.h:334
#define M88K_CR_SR0
#define BATC_PROT
Definition: m8820x_pte.h:94
#define M88K_EXCEPTION_ILLEGAL_INTEGER_DIVIDE
#define M88K_CR_VBR
void(* interrupt_assert)(struct interrupt *)
Definition: interrupt.h:38
#define N_M88K_REGS
int(* translate_v2p)(struct cpu *, uint64_t vaddr, uint64_t *return_paddr, int flags)
Definition: cpu.h:369
#define NOT_DELAYED
Definition: cpu.h:305
#define M88K_EXCEPTION_USER_TRAPS_START
#define M88K_CR_SSBR
#define DMT_DREGBITS(x)
Definition: m88k_dmt.h:57
#define PG_SO
Definition: m8820x_pte.h:132
uint8_t delay_slot
Definition: cpu.h:356
uint8_t is_32bit
Definition: cpu.h:350
#define INVALIDATE_ALL
Definition: cpu.h:478
uint32_t patc_v_and_control[N_M88200_PATC_ENTRIES]
#define MACHINE_MVME88K_197
Definition: machine.h:330
#define M88K_PSR_MODE
Definition: m88k_psl.h:70
union cpu::@1 cd
#define BE32_TO_HOST(x)
Definition: misc.h:181
struct memory * mem
Definition: cpu.h:362
#define DMT_ENBITS(x)
Definition: m88k_dmt.h:58
#define M88K_CR_DMT0
void m88k_irq_interrupt_assert(struct interrupt *interrupt)
Definition: cpu_m88k.cc:407
#define M88K_CR_PID
void m88k_ldcr(struct cpu *cpu, uint32_t *r32ptr, int cr)
Definition: cpu_m88k.cc:425
struct machine * machine
Definition: cpu.h:328
void interrupt_handler_register(struct interrupt *templ)
Definition: interrupt.cc:81
#define M88K_EXCEPTION_BOUNDS_CHECK_VIOLATION
#define MEM_READ
Definition: memory.h:116
#define M88K_EXCEPTION_RESET
void(* interrupt_deassert)(struct interrupt *)
Definition: interrupt.h:39
#define BATC_SO
Definition: m8820x_pte.h:98
#define BATC_GLOBAL
Definition: m8820x_pte.h:96
#define DMT_DAS
Definition: m88k_dmt.h:45
#define M88K_CR_SNIP
#define PG_V
Definition: m8820x_pte.h:124
uint32_t r[N_M88K_REGS+1]
Definition: cpu_m88k.h:235
#define M88K_EXCEPTION_SFU1_IMPRECISE
#define M88K_EXCEPTION_UNIMPLEMENTED_OPCODE
void m88k_irq_interrupt_deassert(struct interrupt *interrupt)
Definition: cpu_m88k.cc:412
void m88k_exception(struct cpu *cpu, int vector, int is_trap)
Definition: cpu_m88k.cc:648
#define MAX_M8820X_CMMUS
#define M88K_CR_NAMES
int(* run_instr)(struct cpu *cpu)
Definition: cpu.h:364
uint32_t patc_p_and_supervisorbit[N_M88200_PATC_ENTRIES]
#define DMT_SIGNED
Definition: m88k_dmt.h:49
char * get_symbol_name(struct symbol_context *, uint64_t addr, uint64_t *offset)
Definition: symbol.cc:188
#define M88K_CR_SR2
#define N_M88K_CONTROL_REGS
struct cpu ** cpus
Definition: machine.h:140
#define M88K_XIP_E
Definition: m88k_psl.h:91
#define M88K_EXCEPTION_INTERRUPT
int m88k_translate_v2p(struct cpu *cpu, uint64_t vaddr64, uint64_t *return_paddr, int flags)
Definition: memory_m88k.cc:103
int physical_ram_in_mb
Definition: machine.h:147
#define M88K_PROM_INSTR
#define M88K_CR_DMT2
uint32_t dma[2]
Definition: cpu_m88k.h:255
#define M88K_EXCEPTION_SFU1_PRECISE
int ncpus
Definition: machine.h:139
#define M88K_PSR_SFRZ
Definition: m88k_psl.h:82
#define M88K_EXCEPTION_MISALIGNED_ACCESS
#define EMUL_LITTLE_ENDIAN
Definition: misc.h:164
void m88k_cpu_dumpinfo(struct cpu *cpu)
Definition: cpu_m88k.cc:198
#define M88K_PSR_MXM
Definition: m88k_psl.h:80
uint64_t pc
Definition: cpu.h:383
#define M88K_EXCEPTION_INTEGER_OVERFLOW
void m88k_invalidate_translation_caches(struct cpu *cpu, uint64_t, int)
#define M88K_CR_PSR
#define LE32_TO_HOST(x)
Definition: misc.h:180
void m88k_stcr(struct cpu *cpu, uint32_t value, int cr, int rte)
Definition: cpu_m88k.cc:503
#define M88K_NIP_V
Definition: m88k_psl.h:87
#define M88K_CR_EPSR
int(* memory_rw)(struct cpu *cpu, struct memory *mem, uint64_t vaddr, unsigned char *data, size_t len, int writeflag, int cache_flags)
Definition: cpu.h:365
char * path
Definition: cpu.h:337
void m88k_cpu_list_available_types(void)
Definition: cpu_m88k.cc:214
void m88k_cpu_functioncall_trace(struct cpu *cpu, int n_args)
uint32_t dmt[2]
Definition: cpu_m88k.h:253
void m88k_cpu_register_dump(struct cpu *cpu, int gprs, int coprocs)
Definition: cpu_m88k.cc:272
#define BATC_WT
Definition: m8820x_pte.h:97
#define M88K_PID_MC
Definition: m88k_psl.h:64
uint8_t running
Definition: cpu.h:353
#define M88K_CR_NAMES_197
#define M8820X_PATC_SUPERVISOR_BIT
#define M88K_CR_SR3
#define PG_U0
Definition: m8820x_pte.h:134
uint32_t dmd[2]
Definition: cpu_m88k.h:254
#define DMT_VALID
Definition: m88k_dmt.h:52
#define M88K_EXCEPTION_PRIVILEGE_VIOLATION
#define N_M88200_PATC_ENTRIES
#define CPU_SETTINGS_ADD_REGISTER32(name, var)
Definition: cpu.h:490
#define debug
Definition: dev_adb.cc:57
#define M88K_PSR_IND
Definition: m88k_psl.h:81
int cpu_id
Definition: cpu.h:359
#define DMT_LOCKBAR
Definition: m88k_dmt.h:47
#define M88K_CR_DMD0
#define DMT_WRITE
Definition: m88k_dmt.h:51
#define M88K_CR_SR1
void m88k_fstcr(struct cpu *cpu, uint32_t value, int fcr)
Definition: cpu_m88k.cc:587
uint32_t cr[N_M88K_CONTROL_REGS]
Definition: cpu_m88k.h:241
uint32_t line
Definition: interrupt.h:51
Definition: cpu.h:326
#define NO_EXCEPTIONS
Definition: memory.h:125
int(* instruction_has_delayslot)(struct cpu *cpu, unsigned char *ib)
Definition: cpu.h:379
#define N_M88200_BATC_REGS
char * name
Definition: interrupt.h:66
void COMBINE() strlen(struct cpu *cpu, struct arm_instr_call *ic, int low_addr)
struct m88k_cpu_type_def cpu_type
Definition: cpu_m88k.h:226
#define PG_PROT
Definition: m8820x_pte.h:126
#define CACHE_INSTRUCTION
Definition: memory.h:122
#define M88K_CR_SXIP
#define M88K_CPU_TYPE_DEFS
#define BATC_INH
Definition: m8820x_pte.h:95
struct symbol_context symbol_context
Definition: machine.h:144
void m88k_invalidate_code_translation(struct cpu *cpu, uint64_t, int)
int m88k_cpu_disassemble_instr(struct cpu *cpu, unsigned char *ib, int running, uint64_t dumpaddr)
Definition: cpu_m88k.cc:835
#define N_M88K_FPU_CONTROL_REGS
#define M88K_EXCEPTION_INSTRUCTION_ACCESS
uint8_t byte_order
Definition: cpu.h:347
#define EXCEPTION_IN_DELAY_SLOT
Definition: cpu.h:308
#define M88K_PSR_SFD1
Definition: m88k_psl.h:79
#define DMT_DOUB1
Definition: m88k_dmt.h:46
void(* update_translation_table)(struct cpu *, uint64_t vaddr_page, unsigned char *host_page, int writeflag, uint64_t paddr_page)
Definition: cpu.h:371
#define M88K_ZERO_REG
#define M88K_CR_DMA2
Definition: memory.h:75
uint32_t fcr[N_M88K_FPU_CONTROL_REGS]
Definition: cpu_m88k.h:244
#define M88K_EXCEPTION_DATA_ACCESS
#define PG_U
Definition: m8820x_pte.h:127
struct m8820x_cmmu * cmmu[MAX_M8820X_CMMUS]
Definition: cpu_m88k.h:250
int m88k_run_instr(struct cpu *cpu)
Definition: symbol.h:37
uint32_t delay_target
Definition: cpu_m88k.h:258
#define M88K_CR_SFIP
void m88k_pc_to_pointers(struct cpu *)
#define PG_M
Definition: m8820x_pte.h:128
int m88k_memory_rw(struct cpu *cpu, struct memory *mem, uint64_t vaddr, unsigned char *data, size_t len, int writeflag, int cache_flags)
uint32_t batc[N_M88200_BATC_REGS]
void m88k_cpu_tlbdump(struct machine *m, int x, int rawflag)
Definition: cpu_m88k.cc:338
#define M88K_PSR_BO
Definition: m88k_psl.h:71
void * extra
Definition: interrupt.h:59
int machine_subtype
Definition: machine.h:112
struct m88k_cpu m88k
Definition: cpu.h:442
#define PG_U1
Definition: m8820x_pte.h:135
void(* invalidate_code_translation)(struct cpu *, uint64_t paddr, int flags)
Definition: cpu.h:376
#define M88K_CR_DMD1
void m88k_update_translation_table(struct cpu *cpu, uint64_t vaddr_page, unsigned char *host_page, int writeflag, uint64_t paddr_page)
#define M88K_CR_DMA0
#define CPU_SETTINGS_ADD_REGISTER64(name, var)
Definition: cpu.h:486
#define DMT_BO
Definition: m88k_dmt.h:44
int irq_asserted
Definition: cpu_m88k.h:247
int m88k_cpu_new(struct cpu *cpu, struct memory *mem, struct machine *machine, int cpu_id, char *cpu_type_name)
Definition: cpu_m88k.cc:101
#define M88K_EXCEPTION_ERROR
#define M88K_CR_DMT1
void(* invalidate_translation_caches)(struct cpu *, uint64_t paddr, int flags)
Definition: cpu.h:374
#define M88K_CR_DMD2
#define EMUL_BIG_ENDIAN
Definition: misc.h:165
#define M88K_XIP_V
Definition: m88k_psl.h:90

Generated on Sun Sep 30 2018 16:05:18 for GXemul by doxygen 1.8.13