/[gxemul]/trunk/src/cpus/cpu_m88k.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /trunk/src/cpus/cpu_m88k.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 44 - (show annotations)
Mon Oct 8 16:22:56 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 35186 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1632 2007/09/11 21:46:35 debug Exp $
20070616	Implementing the MIPS32/64 revision 2 "ror" instruction.
20070617	Adding a struct for each physpage which keeps track of which
		ranges within that page (base offset, length) that are
		continuously translatable. When running with native code
		generation enabled (-b), a range is added after each read-
		ahead loop.
		Experimenting with using the physical program counter sample
		data (implemented 20070608) together with the "translatable
		range" information, to figure out which physical address ranges
		would be worth translating to native code (if the number of
		samples falling within a range is above a certain threshold).
20070618	Adding automagic building of .index comment files for
		src/file/, src/promemul/, src src/useremul/ as well.
		Adding a "has been translated" bit to the ranges, so that only
		not-yet-translated ranges will be sampled.
20070619	Moving src/cpu.c and src/memory_rw.c into src/cpus/,
		src/device.c into src/devices/, and src/machine.c into
		src/machines/.
		Creating a skeleton cc/ld native backend module; beginning on
		the function which will detect cc command line, etc.
20070620	Continuing on the native code generation infrastructure.
20070621	Moving src/x11.c and src/console.c into a new src/console/
		subdir (for everything that is console or framebuffer related).
		Moving src/symbol*.c into a new src/symbol/, which should
		contain anything that is symbol handling related.
20070624	Making the program counter sampling threshold a "settings
		variable" (sampling_threshold), i.e. it can now be changed
		during runtime.
		Switching the RELEASE notes format from plain text to HTML.
		If the TMPDIR environment variable is set, it is used instead
		of "/tmp" for temporary files.
		Continuing on the cc/ld backend: simple .c code is generated,
		the compiler and linker are called, etc.
		Adding detection of host architecture to the configure script
		(again), and adding icache invalidation support (only
		implemented for Alpha hosts so far).
20070625	Simplifying the program counter sampling mechanism.
20070626	Removing the cc/ld native code generation stuff, program
		counter sampling, etc; it would not have worked well in the
		general case.
20070627	Removing everything related to native code generation.
20070629	Removing the (practically unusable) support for multiple
		emulations. (The single emulation allowed now still supports
		multiple simultaneous machines, as before.)
		Beginning on PCCTWO and M88K interrupts.
20070723	Adding a dummy skeleton for emulation of M32R processors.
20070901	Fixing a warning found by "gcc version 4.3.0 20070817
		(experimental)" on amd64.
20070905	Removing some more traces of the old "multiple emulations"
		code.
		Also looking in /usr/local/include and /usr/local/lib for
		X11 libs, when running configure.
20070909	Minor updates to the guest OS install instructions, in
		preparation for the NetBSD 4.0 release.
20070918	More testing of NetBSD 4.0 RC1.

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

  ViewVC Help
Powered by ViewVC 1.1.26