/[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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 42 - (hide 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 dpavlin 40 /*
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 dpavlin 42 * $Id: cpu_m88k.c,v 1.38 2007/06/07 15:36:24 debug Exp $
29 dpavlin 40 *
30 dpavlin 42 * Motorola M881x0 CPU emulation.
31 dpavlin 40 */
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 dpavlin 42 #include "mvmeprom.h"
44 dpavlin 40 #include "settings.h"
45     #include "symbol.h"
46 dpavlin 42 #include "timer.h"
47 dpavlin 40
48 dpavlin 42 #include "m8820x_pte.h"
49     #include "m88k_dmt.h"
50    
51 dpavlin 40 #define DYNTRANS_32
52     #define DYNTRANS_DELAYSLOT
53     #include "tmp_m88k_head.c"
54    
55    
56 dpavlin 42 extern int native_code_translation_enabled;
57    
58     void m88k_pc_to_pointers(struct cpu *);
59    
60 dpavlin 40 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 dpavlin 42 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 dpavlin 40 /*
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 dpavlin 42 cpu->translate_v2p = m88k_translate_v2p;
121 dpavlin 40
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 dpavlin 42
135     /*
136     * Add register names as settings:
137     */
138    
139 dpavlin 40 CPU_SETTINGS_ADD_REGISTER64("pc", cpu->pc);
140 dpavlin 42
141     for (i=0; i<N_M88K_REGS; i++) {
142 dpavlin 40 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 dpavlin 42 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 dpavlin 40 /* Register the CPU interrupt pin: */
161     {
162     struct interrupt template;
163     char name[50];
164 dpavlin 42 snprintf(name, sizeof(name), "%s", cpu->path);
165 dpavlin 40
166 dpavlin 42 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 dpavlin 40
175 dpavlin 42 /* Set the Processor ID: */
176     cpu->cd.m88k.cr[M88K_CR_PID] = cpu->cd.m88k.cpu_type.pid | M88K_PID_MC;
177 dpavlin 40
178 dpavlin 42 /* 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 dpavlin 40 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 dpavlin 42 * Returns 1 if an opcode has a delay slot after it, 0 otherwise.
234 dpavlin 40 */
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 dpavlin 42 case 0x3b: /* bcnd.n */
250 dpavlin 40 return 1;
251 dpavlin 42 case 0x3d:
252     switch ((iword >> 8) & 0xff) {
253     case 0xc4: /* jmp.n */
254     case 0xcc: /* jsr.n */
255     return 1;
256     }
257 dpavlin 40 }
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 dpavlin 42 debug(" r%-2i = 0x%08"PRIx32,
290     i, cpu->cd.m88k.r[i]);
291 dpavlin 40 if ((i % 4) == 3)
292     debug("\n");
293     }
294     }
295 dpavlin 42
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 dpavlin 40 }
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 dpavlin 42 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 dpavlin 40 }
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 dpavlin 42 * 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 dpavlin 40 * 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 dpavlin 42 * register contents) will not be shown, and dumpaddr will be used instead of
788 dpavlin 40 * 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 dpavlin 42 int supervisor = cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE;
794 dpavlin 40 uint32_t iw;
795     char *symbol, *mnem = NULL;
796     uint64_t offset;
797 dpavlin 42 uint32_t op26, op10, op11, d, s1, s2, w5, cr6, imm16;
798 dpavlin 40 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 dpavlin 42 if (symbol != NULL && offset == 0 && supervisor)
806 dpavlin 40 debug("<%s>\n", symbol);
807    
808     if (cpu->machine->ncpus > 1 && running)
809     debug("cpu%i:\t", cpu->cpu_id);
810    
811 dpavlin 42 debug("%c%08"PRIx32": ",
812     cpu->cd.m88k.cr[M88K_CR_PSR] & M88K_PSR_MODE? 's' : 'u',
813     (uint32_t) dumpaddr);
814 dpavlin 40
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 dpavlin 42 cr6 = (iw >> 5) & 0x3f;
837 dpavlin 40 d16 = ((int16_t) (iw & 0xffff)) * 4;
838     d26 = ((int32_t)((iw & 0x03ffffff) << 6)) >> 4;
839    
840     switch (op26) {
841    
842 dpavlin 42 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 dpavlin 40 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 dpavlin 42 if (symbol != NULL && supervisor)
872 dpavlin 40 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 dpavlin 42 case 0: debug("0x%016"PRIx64, (uint64_t)
880 dpavlin 40 ((((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 dpavlin 42 case 2: debug("0x%04"PRIx16,
888 dpavlin 40 (uint16_t) cpu->cd.m88k.r[d]);
889     break;
890 dpavlin 42 case 3: debug("0x%02"PRIx8,
891 dpavlin 40 (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 dpavlin 42 * st_or_ld rY,rX,B
905 dpavlin 40 */
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 dpavlin 42 if (symbol != NULL && supervisor)
925 dpavlin 40 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 dpavlin 42 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 dpavlin 40 break;
989    
990     case 0x18: /* addu */
991     case 0x19: /* subu */
992     case 0x1a: /* divu */
993     case 0x1b: /* mulu */
994 dpavlin 42 case 0x1c: /* add */
995     case 0x1d: /* sub */
996     case 0x1e: /* div */
997     case 0x1f: /* cmp */
998 dpavlin 40 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 dpavlin 42 debug("%s\tr%i,r%i,%i\n", mnem, d, s1, imm16);
1009 dpavlin 40 break;
1010    
1011 dpavlin 42 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 dpavlin 40 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 dpavlin 42 if (symbol != NULL && supervisor)
1062 dpavlin 40 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 dpavlin 42 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 dpavlin 40 symbol = get_symbol_name(&cpu->machine->symbol_context,
1097     dumpaddr + d16, &offset);
1098 dpavlin 42 if (symbol != NULL && supervisor)
1099 dpavlin 40 debug("\t; <%s>", symbol);
1100     debug("\n");
1101     break;
1102    
1103 dpavlin 42 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 dpavlin 40 case 0x3d:
1175 dpavlin 42 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 dpavlin 40 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 dpavlin 42 debug("\t\t; ");
1318     if (symbol != NULL && supervisor)
1319 dpavlin 40 debug("<%s>", symbol);
1320     else
1321     debug("0x%08"PRIx32, tmpaddr);
1322     }
1323 dpavlin 42 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 dpavlin 40 }
1353     break;
1354    
1355 dpavlin 42 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 dpavlin 40 }
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