/[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 40 - (hide annotations)
Mon Oct 8 16:22:11 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 13086 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1539 2007/05/01 04:03:51 debug Exp $
20070415	Landisk PCLOCK should be 33.33 MHz, not 50 MHz. (This makes
		the clock run at correct speed.)
		FINALLY found and fixed the bug which caused OpenBSD/landisk
		to randomly bug out: an &-sign was missing in the special case
		handling of FPSCR in the 'LDS.L @Rm+,FPSCR' instruction.
		Adding similar special case handling for 'LDC.L @Rm+,SR'
		(calling sh_update_sr() instead of just loading).
		Implementing the 'FCNVSD FPUL,DRn' and 'FCNVDS DRm,FPUL'
		SuperH instructions.
		The 'LDC Rm,SR' instruction now immediately breaks out of the
		dyntrans loop if an interrupt is to be triggered.
20070416	In memory_rw.c, if mapping a page as writable, make sure to
		invalidate code translations even if the data access was a
		read.
		Minor SuperH updates.
20070418	Removing the dummy M68K emulation mode.
		Minor SH update (turning unnecessary sts_mach_rn, sts_macl_rn,
		and sts_pr_rn instruction handlers into mov_rm_rn).
20070419	Beginning to add a skeleton for an M88K mode: Adding a hack to
		allow OpenBSD/m88k a.out binaries to be loaded, and disassembly
		of a few simple 88K instructions.
		Commenting out the 'LDC Rm,SR' fix from a few days ago, because
		it made Linux/dreamcast bug out.
		Adding a hack to dev_sh4.c (an extra translation cache
		invalidation), which allows OpenBSD/landisk to boot ok after
		an install. Upgrading the Landisk machine mode to stable,
		updating documentation, etc.
20070420	Experimenting with adding a PCI controller (pcic) to dev_sh4.
		Adding a dummy Realtek 8139C+ skeleton device (dev_rtl8139c).
		Implementing the first M88K instructions (br, or[.u] imm), and
		adding disassembly of some more instructions.
20070421	Continuing a little on dev_rtl8139c.
20070422	Implementing the 9346 EEPROM "read" command for dev_rtl8139c.
		Finally found and fixed an old bug in the log n symbol search
		(it sometimes missed symbols). Debug trace (-i, -t etc) should
		now show more symbols. :-)
20070423	Continuing a little on M88K disassembly.
20070428	Fixing a memset arg order bug in src/net/net.c (thanks to
		Nigel Horne for noticing the bug).
		Applying parts of a patch from Carl van Schaik to clear out
		bottom bits of MIPS addresses more correctly, when using large
		page sizes, and doing some other minor cleanup/refactoring.
		Fixing a couple of warnings given by gcc with the -W option (a
		few more warnings than just plain -Wall).
		Reducing SuperH dyntrans physical address space from 64-bit to
		32-bit (since SH5/SH64 isn't imlemented yet anyway).
		Adding address-to-symbol annotation to a few more instructions
		in the SuperH instruction trace output.
		Beginning regression testing for the next release.
		Reverting the value of SCIF_DELAYED_TX_VALUE from 1 to 2,
		because OpenBSD/landisk may otherwise hang randomly.
20070429	The ugly hack/workaround to get OpenBSD/landisk booting without
		crashing does NOT work anymore (with the April 21 snapshot
		of OpenBSD/landisk). Strangely enough, removing the hack
		completely causes OpenBSD/landisk to work (!).
		More regression testing (re-testing everything SuperH-related,
		and some other things).
		Cobalt interrupts were actually broken; fixing by commenting
		out the DEC21143s in the Cobalt machine.
20070430	More regression testing.
20070501	Updating the OpenBSD/landisk install instructions to use
		4.1 instead of the current snapshot.
		GAAAH! OpenBSD/landisk 4.1 _needs_ the ugly hack/workaround;
		reintroducing it again. (The 4.1 kernel is actually from
		2007-03-11.)
		Simplifying the NetBSD/evbarm install instructions a bit.
		More regression testing.

==============  RELEASE 0.4.5.1  ==============


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     * $Id: cpu_m88k.c,v 1.7 2007/04/28 09:19:51 debug Exp $
29     *
30     * M88K CPU emulation.
31     */
32    
33     #include <stdio.h>
34     #include <stdlib.h>
35     #include <string.h>
36     #include <ctype.h>
37    
38     #include "cpu.h"
39     #include "interrupt.h"
40     #include "machine.h"
41     #include "memory.h"
42     #include "misc.h"
43     #include "settings.h"
44     #include "symbol.h"
45    
46     #define DYNTRANS_32
47     #define DYNTRANS_DELAYSLOT
48     #include "tmp_m88k_head.c"
49    
50    
51     static char *memop[4] = { ".d", "", ".h", ".b" };
52    
53     void m88k_irq_interrupt_assert(struct interrupt *interrupt);
54     void m88k_irq_interrupt_deassert(struct interrupt *interrupt);
55    
56    
57     /*
58     * m88k_cpu_new():
59     *
60     * Create a new M88K cpu object by filling the CPU struct.
61     * Return 1 on success, 0 if cpu_type_name isn't a valid M88K processor.
62     */
63     int m88k_cpu_new(struct cpu *cpu, struct memory *mem,
64     struct machine *machine, int cpu_id, char *cpu_type_name)
65     {
66     int i, found;
67     struct m88k_cpu_type_def cpu_type_defs[] = M88K_CPU_TYPE_DEFS;
68    
69     /* Scan the list for this cpu type: */
70     i = 0; found = -1;
71     while (i >= 0 && cpu_type_defs[i].name != NULL) {
72     if (strcasecmp(cpu_type_defs[i].name, cpu_type_name) == 0) {
73     found = i;
74     break;
75     }
76     i++;
77     }
78     if (found == -1)
79     return 0;
80    
81     cpu->run_instr = m88k_run_instr;
82     cpu->memory_rw = m88k_memory_rw;
83     cpu->update_translation_table = m88k_update_translation_table;
84     cpu->invalidate_translation_caches =
85     m88k_invalidate_translation_caches;
86     cpu->invalidate_code_translation = m88k_invalidate_code_translation;
87     /* cpu->translate_v2p = m88k_translate_v2p; */
88    
89     cpu->cd.m88k.cpu_type = cpu_type_defs[found];
90     cpu->name = cpu->cd.m88k.cpu_type.name;
91     cpu->is_32bit = 1;
92     cpu->byte_order = EMUL_BIG_ENDIAN;
93    
94     cpu->instruction_has_delayslot = m88k_cpu_instruction_has_delayslot;
95    
96     /* Only show name and caches etc for CPU nr 0: */
97     if (cpu_id == 0) {
98     debug("%s", cpu->name);
99     }
100    
101     CPU_SETTINGS_ADD_REGISTER64("pc", cpu->pc);
102     for (i=0; i<N_M88K_REGS - 1; i++) {
103     char name[10];
104     snprintf(name, sizeof(name), "r%i", i);
105     CPU_SETTINGS_ADD_REGISTER32(name, cpu->cd.m88k.r[i]);
106     }
107    
108     /* Register the CPU interrupt pin: */
109     {
110     struct interrupt template;
111     char name[50];
112     snprintf(name, sizeof(name), "%s.irq", cpu->path);
113    
114     memset(&template, 0, sizeof(template));
115     template.line = 0;
116     template.name = name;
117     template.extra = cpu;
118     template.interrupt_assert = m88k_irq_interrupt_assert;
119     template.interrupt_deassert = m88k_irq_interrupt_deassert;
120     interrupt_handler_register(&template);
121     }
122    
123    
124     return 1;
125     }
126    
127    
128     /*
129     * m88k_cpu_dumpinfo():
130     */
131     void m88k_cpu_dumpinfo(struct cpu *cpu)
132     {
133     /* struct m88k_cpu_type_def *ct = &cpu->cd.m88k.cpu_type; */
134    
135     debug(", %s-endian",
136     cpu->byte_order == EMUL_BIG_ENDIAN? "Big" : "Little");
137    
138     debug("\n");
139     }
140    
141    
142     /*
143     * m88k_cpu_list_available_types():
144     *
145     * Print a list of available M88K CPU types.
146     */
147     void m88k_cpu_list_available_types(void)
148     {
149     int i, j;
150     struct m88k_cpu_type_def tdefs[] = M88K_CPU_TYPE_DEFS;
151    
152     i = 0;
153     while (tdefs[i].name != NULL) {
154     debug("%s", tdefs[i].name);
155     for (j=13 - strlen(tdefs[i].name); j>0; j--)
156     debug(" ");
157     i++;
158     if ((i % 5) == 0 || tdefs[i].name == NULL)
159     debug("\n");
160     }
161     }
162    
163    
164     /*
165     * m88k_cpu_instruction_has_delayslot():
166     *
167     * Return 1 if an opcode is a branch, 0 otherwise.
168     */
169     int m88k_cpu_instruction_has_delayslot(struct cpu *cpu, unsigned char *ib)
170     {
171     uint32_t iword = *((uint32_t *)&ib[0]);
172    
173     if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
174     iword = LE32_TO_HOST(iword);
175     else
176     iword = BE32_TO_HOST(iword);
177    
178     switch (iword >> 26) {
179     case 0x31: /* br.n */
180     case 0x33: /* bsr.n */
181     case 0x35: /* bb0.n */
182     case 0x37: /* bb1.n */
183     return 1;
184    
185     /* TODO: jsr.n, jmp.n */
186     }
187    
188     return 0;
189     }
190    
191    
192     /*
193     * m88k_cpu_register_dump():
194     *
195     * Dump cpu registers in a relatively readable format.
196     *
197     * gprs: set to non-zero to dump GPRs and some special-purpose registers.
198     * coprocs: set bit 0..3 to dump registers in coproc 0..3.
199     */
200     void m88k_cpu_register_dump(struct cpu *cpu, int gprs, int coprocs)
201     {
202     char *symbol;
203     uint64_t offset;
204     int i, x = cpu->cpu_id;
205    
206     if (gprs) {
207     symbol = get_symbol_name(&cpu->machine->symbol_context,
208     cpu->pc, &offset);
209     debug("cpu%i: pc = 0x%08"PRIx32, x, (uint32_t)cpu->pc);
210     debug(" <%s>\n", symbol != NULL? symbol : " no symbol ");
211    
212     for (i=0; i<N_M88K_REGS; i++) {
213     if ((i % 4) == 0)
214     debug("cpu%i:", x);
215     if (i == 0)
216     debug(" ");
217     else
218     debug(" r%-2i = 0x%08x", i,
219     (int)cpu->cd.m88k.r[i]);
220     if ((i % 4) == 3)
221     debug("\n");
222     }
223     }
224     }
225    
226    
227     /*
228     * m88k_cpu_tlbdump():
229     *
230     * Called from the debugger to dump the TLB in a readable format.
231     * x is the cpu number to dump, or -1 to dump all CPUs.
232     *
233     * If rawflag is nonzero, then the TLB contents isn't formated nicely,
234     * just dumped.
235     */
236     void m88k_cpu_tlbdump(struct machine *m, int x, int rawflag)
237     {
238     }
239    
240    
241     /*
242     * m88k_irq_interrupt_assert():
243     * m88k_irq_interrupt_deassert():
244     */
245     void m88k_irq_interrupt_assert(struct interrupt *interrupt)
246     {
247     struct cpu *cpu = (struct cpu *) interrupt->extra;
248     cpu->cd.m88k.irq_asserted = 1;
249     }
250     void m88k_irq_interrupt_deassert(struct interrupt *interrupt)
251     {
252     struct cpu *cpu = (struct cpu *) interrupt->extra;
253     cpu->cd.m88k.irq_asserted = 0;
254     }
255    
256    
257     /*
258     * m88k_cpu_disassemble_instr():
259     *
260     * Convert an instruction word into human readable format, for instruction
261     * tracing.
262     *
263     * If running is 1, cpu->pc should be the address of the instruction.
264     *
265     * If running is 0, things that depend on the runtime environment (eg.
266     * register contents) will not be shown, and addr will be used instead of
267     * cpu->pc for relative addresses.
268     */
269     int m88k_cpu_disassemble_instr(struct cpu *cpu, unsigned char *ib,
270     int running, uint64_t dumpaddr)
271     {
272     uint32_t iw;
273     char *symbol, *mnem = NULL;
274     uint64_t offset;
275     uint32_t op26, op10, op11, d, s1, s2, w5, imm16;
276     int32_t d16, d26, simm16;
277    
278     if (running)
279     dumpaddr = cpu->pc;
280    
281     symbol = get_symbol_name(&cpu->machine->symbol_context,
282     dumpaddr, &offset);
283     if (symbol != NULL && offset == 0)
284     debug("<%s>\n", symbol);
285    
286     if (cpu->machine->ncpus > 1 && running)
287     debug("cpu%i:\t", cpu->cpu_id);
288    
289     debug("%08x: ", (int)dumpaddr);
290    
291     if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
292     iw = ib[0] + (ib[1]<<8) + (ib[2]<<16) + (ib[3]<<24);
293     else
294     iw = ib[3] + (ib[2]<<8) + (ib[1]<<16) + (ib[0]<<24);
295    
296     debug("%08"PRIx32, (uint32_t) iw);
297    
298     if (running && cpu->delay_slot)
299     debug(" (d)");
300    
301     debug("\t");
302    
303     op26 = (iw >> 26) & 0x3f;
304     op11 = (iw >> 11) & 0x1f;
305     op10 = (iw >> 10) & 0x3f;
306     d = (iw >> 21) & 0x1f;
307     s1 = (iw >> 16) & 0x1f;
308     s2 = iw & 0x1f;
309     imm16 = iw & 0xffff;
310     simm16 = (int16_t) (iw & 0xffff);
311     w5 = (iw >> 5) & 0x1f;
312     d16 = ((int16_t) (iw & 0xffff)) * 4;
313     d26 = ((int32_t)((iw & 0x03ffffff) << 6)) >> 4;
314    
315     switch (op26) {
316    
317     case 0x04: /* ld.d */
318     case 0x05: /* ld */
319     case 0x06: /* ld.h */
320     case 0x07: /* ld.b */
321     case 0x08: /* st.d */
322     case 0x09: /* st */
323     case 0x0a: /* st.h */
324     case 0x0b: /* st.b */
325     debug("%s%s\tr%i,r%i,%i",
326     op26 >= 0x08? "st" : "ld",
327     memop[op26 & 3], d, s1, imm16);
328     if (running) {
329     uint32_t tmpaddr = cpu->cd.m88k.r[s1] + imm16;
330     symbol = get_symbol_name(&cpu->machine->symbol_context,
331     tmpaddr, &offset);
332     if (symbol != NULL)
333     debug("\t; [<%s>]", symbol);
334     else
335     debug("\t; [0x%08"PRIx32"]", tmpaddr);
336     if (op26 >= 0x08) {
337     /* Store: */
338     debug(" = ");
339     switch (op26 & 3) {
340     case 0: /* TODO: Endianness!!! */
341     debug("0x%016"PRIx64, (uint64_t)
342     ((((uint64_t) cpu->cd.m88k.r[d])
343     << 32) + ((uint64_t)
344     cpu->cd.m88k.r[d+1])) );
345     break;
346     case 1: debug("0x%08"PRIx32,
347     (uint32_t) cpu->cd.m88k.r[d]);
348     break;
349     case 2: debug("0x%08"PRIx16,
350     (uint16_t) cpu->cd.m88k.r[d]);
351     break;
352     case 3: debug("0x%08"PRIx8,
353     (uint8_t) cpu->cd.m88k.r[d]);
354     break;
355     }
356     } else {
357     /* Load: */
358     /* TODO */
359     }
360     } else {
361     /*
362     * Not running, but the following instruction
363     * sequence is quite common:
364     *
365     * or.u rX,r0,A
366     * st_or_st rY,rX,B
367     */
368    
369     /* Try loading the instruction before the
370     current one. */
371     uint32_t iw2 = 0;
372     cpu->memory_rw(cpu, cpu->mem,
373     dumpaddr - sizeof(uint32_t), (unsigned char *)&iw2,
374     sizeof(iw2), MEM_READ, CACHE_INSTRUCTION
375     | NO_EXCEPTIONS);
376     if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
377     iw2 = LE32_TO_HOST(iw2);
378     else
379     iw2 = BE32_TO_HOST(iw2);
380     if ((iw2 >> 26) == 0x17 && /* or.u */
381     ((iw2 >> 21) & 0x1f) == s1) {
382     uint32_t tmpaddr = (iw2 << 16) + imm16;
383     symbol = get_symbol_name(
384     &cpu->machine->symbol_context,
385     tmpaddr, &offset);
386     if (symbol != NULL)
387     debug("\t; [<%s>]", symbol);
388     else
389     debug("\t; [0x%08"PRIx32"]", tmpaddr);
390     }
391     }
392     debug("\n");
393     break;
394    
395     case 0x10: /* and */
396     case 0x11: /* and.u */
397     case 0x12: /* mask */
398     case 0x13: /* mask.u */
399     case 0x14: /* xor */
400     case 0x15: /* xor.u */
401     case 0x16: /* or */
402     case 0x17: /* or.u */
403     switch (op26) {
404     case 0x10:
405     case 0x11: mnem = "and"; break;
406     case 0x12:
407     case 0x13: mnem = "mask"; break;
408     case 0x14:
409     case 0x15: mnem = "xor"; break;
410     case 0x16:
411     case 0x17: mnem = "or"; break;
412     }
413     debug("%s%s\t", mnem, op26 & 1? ".u" : "");
414     debug("r%i,r%i,0x%x\n", d, s1, imm16);
415     break;
416    
417     case 0x18: /* addu */
418     case 0x19: /* subu */
419     case 0x1a: /* divu */
420     case 0x1b: /* mulu */
421     switch (op26) {
422     case 0x18: mnem = "addu"; break;
423     case 0x19: mnem = "subu"; break;
424     case 0x1a: mnem = "divu"; break;
425     case 0x1b: mnem = "mulu"; break;
426     }
427     debug("%s\tr%i,r%i,%i\n", mnem, d, s1, imm16);
428     break;
429    
430     case 0x1c: /* add */
431     case 0x1d: /* sub */
432     case 0x1e: /* div */
433     case 0x1f: /* cmp */
434     switch (op26) {
435     case 0x1c: mnem = "add"; break;
436     case 0x1d: mnem = "sub"; break;
437     case 0x1e: mnem = "div"; break;
438     case 0x1f: mnem = "cmp"; break;
439     }
440     debug("%s\tr%i,r%i,%i\n", mnem, d, s1, simm16);
441     break;
442    
443     case 0x30:
444     case 0x31:
445     case 0x32:
446     case 0x33:
447     debug("b%sr%s\t",
448     op26 >= 0x32? "s" : "",
449     op26 & 1? ".n" : "");
450     debug("0x%08"PRIx32, (uint32_t) (dumpaddr + d26));
451     symbol = get_symbol_name(&cpu->machine->symbol_context,
452     dumpaddr + d26, &offset);
453     if (symbol != NULL)
454     debug("\t; <%s>", symbol);
455     debug("\n");
456     break;
457    
458     case 0x34: /* bb0 */
459     case 0x35: /* bb0.n */
460     case 0x36: /* bb1 */
461     case 0x37: /* bb1.n */
462     debug("bb%s%s\t",
463     op26 >= 0x36? "1" : "0",
464     op26 & 1? ".n" : "");
465     debug("%i,r%i,0x%08"PRIx32, d, s1, (uint32_t) (dumpaddr + d16));
466     symbol = get_symbol_name(&cpu->machine->symbol_context,
467     dumpaddr + d16, &offset);
468     if (symbol != NULL)
469     debug("\t; <%s>", symbol);
470     debug("\n");
471     break;
472    
473     case 0x3d:
474     if ((iw & 0x03fff3e0) == 0x0000c000) {
475     debug("%s%s\t(r%i)\n",
476     op11 & 1? "jsr" : "jmp",
477     iw & 0x400? ".n" : "",
478     s2);
479     if (running) {
480     uint32_t tmpaddr = cpu->cd.m88k.r[s2];
481     symbol = get_symbol_name(&cpu->machine->
482     symbol_context, tmpaddr, &offset);
483     debug("\t; ");
484     if (symbol != NULL)
485     debug("<%s>", symbol);
486     else
487     debug("0x%08"PRIx32, tmpaddr);
488     }
489     } else if ((iw & 0x0000ffe0) == 0x00000000) {
490     debug("xmem\tr%i,r%i,r%i\n", d, s1, s2);
491     } else {
492     debug("UNIMPLEMENTED 0x3d\n");
493     }
494     break;
495    
496     default:debug("UNIMPLEMENTED\n");
497     }
498    
499     return sizeof(uint32_t);
500     }
501    
502    
503     #include "tmp_m88k_tail.c"
504    
505    

  ViewVC Help
Powered by ViewVC 1.1.26