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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 40 - (show annotations)
Mon Oct 8 16:22:11 2007 UTC (16 years, 5 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 /*
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