/[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 42 - (show annotations)
Mon Oct 8 16:22:32 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 35380 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1613 2007/06/15 20:11:26 debug Exp $
20070501	Continuing a little on m88k disassembly (control registers,
		more instructions).
		Adding a dummy mvme88k machine mode.
20070502	Re-adding MIPS load/store alignment exceptions.
20070503	Implementing more of the M88K disassembly code.
20070504	Adding disassembly of some more M88K load/store instructions.
		Implementing some relatively simple M88K instructions (br.n,
		xor[.u] imm, and[.u] imm).
20070505	Implementing M88K three-register and, or, xor, and jmp[.n],
		bsr[.n] including function call trace stuff.
		Applying a patch from Bruce M. Simpson which implements the
		SYSCON_BOARD_CPU_CLOCK_FREQ_ID object of the syscon call in
		the yamon PROM emulation.
20070506	Implementing M88K bb0[.n] and bb1[.n], and skeletons for
		ldcr and stcr (although no control regs are implemented yet).
20070509	Found and fixed the bug which caused Linux for QEMU_MIPS to
		stop working in 0.4.5.1: It was a faulty change to the MIPS
		'sc' and 'scd' instructions I made while going through gcc -W
		warnings on 20070428.
20070510	Updating the Linux/QEMU_MIPS section in guestoses.html to
		use mips-test-0.2.tar.gz instead of 0.1.
		A big thank you to Miod Vallat for sending me M88K manuals.
		Implementing more M88K instructions (addu, subu, div[u], mulu,
		ext[u], clr, set, cmp).
20070511	Fixing bugs in the M88K "and" and "and.u" instructions (found
		by comparing against the manual).
		Implementing more M88K instructions (mask[.u], mak, bcnd (auto-
		generated)) and some more control register details.
		Cleanup: Removing the experimental AVR emulation mode and
		corresponding devices; AVR emulation wasn't really meaningful.
		Implementing autogeneration of most M88K loads/stores. The
		rectangle drawing demo (with -O0) for M88K runs :-)
		Beginning on M88K exception handling.
		More M88K instructions: tb0, tb1, rte, sub, jsr[.n].
		Adding some skeleton MVME PROM ("BUG") emulation.
20070512	Fixing a bug in the M88K cmp instruction.
		Adding the M88K lda (scaled register) instruction.
		Fixing bugs in 64-bit (32-bit pairs) M88K loads/stores.
		Removing the unused tick_hz stuff from the machine struct.
		Implementing the M88K xmem instruction. OpenBSD/mvme88k gets
		far enough to display the Copyright banner :-)
		Implementing subu.co (guess), addu.co, addu.ci, ff0, and ff1.
		Adding a dev_mvme187, for MVME187-specific devices/registers.
		OpenBSD/mvme88k prints more boot messages. :)
20070515	Continuing on MVME187 emulation (adding more devices, beginning
		on the CMMUs, etc).
		Adding the M88K and.c, xor.c, and or.c instructions, and making
		sure that mul, div, etc cause exceptions if executed when SFD1
		is disabled.
20070517	Continuing on M88K and MVME187 emulation in general; moving
		the CMMU registers to the CPU struct, separating dev_pcc2 from
		dev_mvme187, and beginning on memory_m88k.c (BATC and PATC).
		Fixing a bug in 64-bit (32-bit pairs) M88K fast stores.
		Implementing the clock part of dev_mk48txx.
		Implementing the M88K fstcr and xcr instructions.
		Implementing m88k_cpu_tlbdump().
		Beginning on the implementation of a separate address space
		for M88K .usr loads/stores.
20070520	Removing the non-working (skeleton) Sandpoint, SonyNEWS, SHARK
		Dnard, and Zaurus machine modes.
		Experimenting with dyntrans to_be_translated read-ahead. It
		seems to give a very small performance increase for MIPS
		emulation, but a large performance degradation for SuperH. Hm.
20070522	Disabling correct SuperH ITLB emulation; it does not seem to be
		necessary in order to let SH4 guest OSes run, and it slows down
		userspace code.
		Implementing "samepage" branches for SuperH emulation, and some
		other minor speed hacks.
20070525	Continuing on M88K memory-related stuff: exceptions, memory
		transaction register contents, etc.
		Implementing the M88K subu.ci instruction.
		Removing the non-working (skeleton) Iyonix machine mode.
		OpenBSD/mvme88k reaches userland :-), starts executing
		/sbin/init's instructions, and issues a few syscalls, before
		crashing.
20070526	Fixing bugs in dev_mk48txx, so that OpenBSD/mvme88k detects
		the correct time-of-day.
		Implementing a generic IRQ controller for the test machines
		(dev_irqc), similar to a proposed patch from Petr Stepan.
		Experimenting some more with translation read-ahead.
		Adding an "expect" script for automated OpenBSD/landisk
		install regression/performance tests.
20070527	Adding a dummy mmEye (SH3) machine mode skeleton.
		FINALLY found the strange M88K bug I have been hunting: I had
		not emulated the SNIP value for exceptions occurring in
		branch delay slots correctly.
		Implementing correct exceptions for 64-bit M88K loads/stores.
		Address to symbol lookups are now disabled when M88K is
		running in usermode (because usermode addresses don't have
		anything to do with supervisor addresses).
20070531	Removing the mmEye machine mode skeleton.
20070604	Some minor code cleanup.
20070605	Moving src/useremul.c into a subdir (src/useremul/), and
		cleaning up some more legacy constructs.
		Adding -Wstrict-aliasing and -fstrict-aliasing detection to
		the configure script.
20070606	Adding a check for broken GCC on Solaris to the configure
		script. (GCC 3.4.3 on Solaris cannot handle static variables
		which are initialized to 0 or NULL. :-/)
		Removing the old (non-working) ARC emulation modes: NEC RD94,
		R94, R96, and R98, and the last traces of Olivetti M700 and
		Deskstation Tyne.
		Removing the non-working skeleton WDSC device (dev_wdsc).
20070607	Thinking about how to use the host's cc + ld at runtime to
		generate native code. (See experiments/native_cc_ld_test.i
		for an example.)
20070608	Adding a program counter sampling timer, which could be useful
		for native code generation experiments.
		The KN02_CSR_NRMMOD bit in the DECstation 5000/200 (KN02) CSR
		should always be set, to allow a 5000/200 PROM to boot.
20070609	Moving out breakpoint details from the machine struct into
		a helper struct, and removing the limit on max nr of
		breakpoints.
20070610	Moving out tick functions into a helper struct as well (which
		also gets rid of the max limit).
20070612	FINALLY figured out why Debian/DECstation stopped working when
		translation read-ahead was enabled: in src/memory_rw.c, the
		call to invalidate_code_translation was made also if the
		memory access was an instruction load (if the page was mapped
		as writable); it shouldn't be called in that case.
20070613	Implementing some more MIPS32/64 revision 2 instructions: di,
		ei, ext, dext, dextm, dextu, and ins.
20070614	Implementing an instruction combination for the NetBSD/arm
		idle loop (making the host not use any cpu if NetBSD/arm
		inside the emulator is not using any cpu).
		Increasing the nr of ARM VPH entries from 128 to 384.
20070615	Removing the ENABLE_arch stuff from the configure script, so
		that all included architectures are included in both release
		and development builds.
		Moving memory related helper functions from misc.c to memory.c.
		Adding preliminary instructions for netbooting NetBSD/pmppc to
		guestoses.html; it doesn't work yet, there are weird timeouts.
		Beginning a total rewrite of the userland emulation modes
		(removing all emulation modes, beginning from scratch with
		NetBSD/MIPS and FreeBSD/Alpha only).
20070616	After fixing a bug in the DEC21143 NIC (the TDSTAT_OWN bit was
		only cleared for the last segment when transmitting, not all
		segments), NetBSD/pmppc boots with root-on-nfs without the
		timeouts. Updating guestoses.html.
		Removing the skeleton PSP (Playstation Portable) mode.
		Moving X11-related stuff in the machine struct into a helper
		struct.
		Cleanup of out-of-memory checks, to use a new CHECK_ALLOCATION
		macro (which prints a meaningful error message).
		Adding a COMMENT to each machine and device (for automagic
		.index comment generation).
		Doing regression testing for the next release.

==============  RELEASE 0.4.6  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26