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

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

  ViewVC Help
Powered by ViewVC 1.1.26