/[gxemul]/trunk/src/cpus/cpu_sparc.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_sparc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 22 - (show annotations)
Mon Oct 8 16:19:37 2007 UTC (13 years, 1 month ago) by dpavlin
File MIME type: text/plain
File size: 12582 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1121 2006/02/18 21:03:08 debug Exp $
20051126	Cobalt and PReP now work with the 21143 NIC.
		Continuing on Alpha dyntrans things.
		Fixing some more left-shift-by-24 to unsigned.
20051127	Working on OpenFirmware emulation; major cleanup/redesign.
		Progress on MacPPC emulation: NetBSD detects two CPUs (when
		running with -n 2), framebuffer output (for text) works.
		Adding quick-hack Bandit PCI controller and "gc" interrupt
		controller for MacPPC.
20051128	Changing from a Bandit to a Uni-North controller for macppc.
		Continuing on OpenFirmware and MacPPC emulation in general
		(obio controller, and wdc attached to the obio seems to work).
20051129	More work on MacPPC emulation (adding a dummy ADB controller).
		Continuing the PCI bus cleanup (endianness and tag composition)
		and rewriting all PCI controllers' access functions.
20051130	Various minor PPC dyntrans optimizations.
		Manually inlining some parts of the framebuffer redraw routine.
		Slowly beginning the conversion of the old MIPS emulation into
		dyntrans (but this will take quite some time to get right).
		Generalizing quick_pc_to_pointers.
20051201	Documentation update (David Muse has made available a kernel
		which simplifies Debian/DECstation installation).
		Continuing on the ADB bus controller.
20051202	Beginning a rewrite of the Zilog serial controller (dev_zs).
20051203	Continuing on the zs rewrite (now called dev_z8530); conversion
		to devinit style.
		Reworking some of the input-only vs output-only vs input-output
		details of src/console.c, better warning messages, and adding
		a debug dump.
		Removing the concept of "device state"; it wasn't really used.
		Changing some debug output (-vv should now be used to show all
		details about devices and busses; not shown during normal
		startup anymore).
		Beginning on some SPARC instruction disassembly support.
20051204	Minor PPC updates (WALNUT skeleton stuff).
		Continuing on the MIPS dyntrans rewrite.
		More progress on the ADB controller (a keyboard is "detected"
		by NetBSD and OpenBSD).
		Downgrading OpenBSD/arc as a guest OS from "working" to
		"almost working" in the documentation.
		Progress on Algor emulation ("v3" PCI controller).
20051205	Minor updates.
20051207	Sorting devices according to address; this reduces complexity
		of device lookups from O(n) to O(log n) in memory_rw (but no
		real performance increase (yet) in experiments).
20051210	Beginning the work on native dyntrans backends (by making a
		simple skeleton; so far only for Alpha hosts).
20051211	Some very minor SPARC updates.
20051215	Fixing a bug in the MIPS mul (note: not mult) instruction,
		so it also works with non-64-bit emulation. (Thanks to Alec
		Voropay for noticing the problem.)
20051216	More work on the fake/empty/simple/skeleton/whatever backend;
		performance doesn't increase, so this isn't really worth it,
		but it was probably worth it to prepare for a real backend
		later.
20051219	More instr call statistics gathering and analysis stuff.
20051220	Another fix for MIPS 'mul'. Also converting mul and {d,}cl{o,z}
		to dyntrans.
		memory_ppc.c syntax error fix (noticed by Peter Valchev).
		Beginning to move out machines from src/machine.c into
		individual files in src/machines (in a way similar to the
		autodev system for devices).
20051222	Updating the documentation regarding NetBSD/pmax 3.0.
20051223	- " - NetBSD/cats 3.0.
20051225	- " - NetBSD/hpcmips 3.0.
20051226	Continuing on the machine registry redesign.
		Adding support for ARM rrx (33-bit rotate).
		Fixing some signed/unsigned issues (exposed by gcc -W).
20051227	Fixing the bug which prevented a NetBSD/prep 3.0 install kernel
		from starting (triggered when an mtmsr was the last instruction
		on a page). Unfortunately not enough to get the kernel to run
		as well as the 2.1 kernels did.
20051230	Some dyntrans refactoring.
20051231	Continuing on the machine registry redesign.
20060101-10	Continuing... moving more machines. Moving MD interrupt stuff
		from machine.c into a new src/machines/interrupts.c.
20060114	Adding various mvmeppc machine skeletons.
20060115	Continuing on mvme* stuff. NetBSD/mvmeppc prints boot messages
		(for MVME1600) and reaches the root device prompt, but no
		specific hardware devices are emulated yet.
20060116	Minor updates to the mvme1600 emulation mode; the Eagle PCI bus
		seems to work without much modification, and a 21143 can be
		detected, interrupts might work (but untested so far).
		Adding a fake MK48Txx (mkclock) device, for NetBSD/mvmeppc.
20060121	Adding an aux control register for ARM. (A BIG thank you to
		Olivier Houchard for tracking down this bug.)
20060122	Adding more ARM instructions (smulXY), and dev_iq80321_7seg.
20060124	Adding disassembly of more ARM instructions (mia*, mra/mar),
		and some semi-bogus XScale and i80321 registers.
20060201-02	Various minor updates. Moving the last machines out of
		machine.c.
20060204	Adding a -c command line option, for running debugger commands
		before the simulation starts, but after all files have been
		loaded.
		Minor iq80321-related updates.
20060209	Minor hacks (DEVINIT macro, etc).
		Preparing for the generalization of the 64-bit dyntrans address
		translation subsystem.
20060216	Adding ARM ldrd (double-register load).
20060217	Continuing on various ARM-related stuff.
20060218	More progress on the ATA/wdc emulation for NetBSD/iq80321.
		NetBSD/evbarm can now be installed :-)  Updating the docs, etc.
		Continuing on Algor emulation.

==============  RELEASE 0.3.8  ==============


1 /*
2 * Copyright (C) 2005 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_sparc.c,v 1.11 2005/12/11 21:34:43 debug Exp $
29 *
30 * SPARC 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 "machine.h"
40 #include "memory.h"
41 #include "misc.h"
42 #include "symbol.h"
43
44
45 #define DYNTRANS_DUALMODE_32
46 #include "tmp_sparc_head.c"
47
48
49 static char *sparc_regnames[N_SPARC_REG] = SPARC_REG_NAMES;
50 static char *sparc_regbranch_names[N_SPARC_REGBRANCH_TYPES] =
51 SPARC_REGBRANCH_NAMES;
52 static char *sparc_branch_names[N_SPARC_BRANCH_TYPES] = SPARC_BRANCH_NAMES;
53 static char *sparc_alu_names[N_ALU_INSTR_TYPES] = SPARC_ALU_NAMES;
54 static char *sparc_loadstore_names[N_LOADSTORE_TYPES] = SPARC_LOADSTORE_NAMES;
55
56
57 /*
58 * sparc_cpu_new():
59 *
60 * Create a new SPARC cpu object.
61 *
62 * Returns 1 on success, 0 if there was no matching SPARC processor with
63 * this cpu_type_name.
64 */
65 int sparc_cpu_new(struct cpu *cpu, struct memory *mem, struct machine *machine,
66 int cpu_id, char *cpu_type_name)
67 {
68 int any_cache = 0;
69 int i = 0;
70 struct sparc_cpu_type_def cpu_type_defs[] = SPARC_CPU_TYPE_DEFS;
71
72 /* Scan the cpu_type_defs list for this cpu type: */
73 while (cpu_type_defs[i].name != NULL) {
74 if (strcasecmp(cpu_type_defs[i].name, cpu_type_name) == 0) {
75 break;
76 }
77 i++;
78 }
79 if (cpu_type_defs[i].name == NULL)
80 return 0;
81
82 cpu->memory_rw = sparc_memory_rw;
83
84 cpu->cd.sparc.cpu_type = cpu_type_defs[i];
85 cpu->name = cpu->cd.sparc.cpu_type.name;
86 cpu->byte_order = EMUL_BIG_ENDIAN;
87 cpu->is_32bit = (cpu->cd.sparc.cpu_type.bits == 32)? 1 : 0;
88
89 if (cpu->is_32bit) {
90 cpu->update_translation_table =
91 sparc32_update_translation_table;
92 cpu->invalidate_translation_caches =
93 sparc32_invalidate_translation_caches;
94 cpu->invalidate_code_translation =
95 sparc32_invalidate_code_translation;
96 } else {
97 cpu->update_translation_table = sparc_update_translation_table;
98 cpu->invalidate_translation_caches =
99 sparc_invalidate_translation_caches;
100 cpu->invalidate_code_translation =
101 sparc_invalidate_code_translation;
102 }
103
104 /* Only show name and caches etc for CPU nr 0 (in SMP machines): */
105 if (cpu_id == 0) {
106 debug("%s", cpu->name);
107
108 if (cpu->cd.sparc.cpu_type.icache_shift != 0)
109 any_cache = 1;
110 if (cpu->cd.sparc.cpu_type.dcache_shift != 0)
111 any_cache = 1;
112 if (cpu->cd.sparc.cpu_type.l2cache_shift != 0)
113 any_cache = 1;
114
115 if (any_cache) {
116 debug(" (I+D = %i+%i KB", (int)
117 (1 << (cpu->cd.sparc.cpu_type.icache_shift-10)),
118 (int)(1<<(cpu->cd.sparc.cpu_type.dcache_shift-10)));
119 if (cpu->cd.sparc.cpu_type.l2cache_shift != 0) {
120 debug(", L2 = %i KB",
121 (int)(1 << (cpu->cd.sparc.cpu_type.
122 l2cache_shift-10)));
123 }
124 debug(")");
125 }
126 }
127
128 return 1;
129 }
130
131
132 /*
133 * sparc_cpu_list_available_types():
134 *
135 * Print a list of available SPARC CPU types.
136 */
137 void sparc_cpu_list_available_types(void)
138 {
139 int i, j;
140 struct sparc_cpu_type_def tdefs[] = SPARC_CPU_TYPE_DEFS;
141
142 i = 0;
143 while (tdefs[i].name != NULL) {
144 debug("%s", tdefs[i].name);
145 for (j=10 - strlen(tdefs[i].name); j>0; j--)
146 debug(" ");
147 i++;
148 if ((i % 6) == 0 || tdefs[i].name == NULL)
149 debug("\n");
150 }
151 }
152
153
154 /*
155 * sparc_cpu_dumpinfo():
156 */
157 void sparc_cpu_dumpinfo(struct cpu *cpu)
158 {
159 debug(", %i-bit\n", cpu->cd.sparc.cpu_type.bits);
160 }
161
162
163 /*
164 * sparc_cpu_register_dump():
165 *
166 * Dump cpu registers in a relatively readable format.
167 *
168 * gprs: set to non-zero to dump GPRs and some special-purpose registers.
169 * coprocs: set bit 0..3 to dump registers in coproc 0..3.
170 */
171 void sparc_cpu_register_dump(struct cpu *cpu, int gprs, int coprocs)
172 {
173 char *symbol;
174 uint64_t offset;
175 int i, x = cpu->cpu_id;
176 int bits32 = cpu->is_32bit;
177
178 if (gprs) {
179 /* Special registers (pc, ...) first: */
180 symbol = get_symbol_name(&cpu->machine->symbol_context,
181 cpu->pc, &offset);
182
183 debug("cpu%i: pc = 0x", x);
184 if (bits32)
185 debug("%08x", (int)cpu->pc);
186 else
187 debug("%016llx", (long long)cpu->pc);
188 debug(" <%s>\n", symbol != NULL? symbol : " no symbol ");
189
190 if (bits32) {
191 for (i=0; i<N_SPARC_REG; i++) {
192 if ((i & 3) == 0)
193 debug("cpu%i: ", x);
194 /* Skip the zero register: */
195 if (i==0) {
196 debug(" ");
197 continue;
198 }
199 debug("%s=", sparc_regnames[i]);
200 debug("0x%08x", (int) cpu->cd.sparc.r[i]);
201 if ((i & 3) < 3)
202 debug(" ");
203 else
204 debug("\n");
205 }
206 } else {
207 for (i=0; i<N_SPARC_REG; i++) {
208 int r = ((i >> 1) & 15) | ((i&1) << 4);
209 if ((i & 1) == 0)
210 debug("cpu%i: ", x);
211 /* Skip the zero register: */
212 if (r==0) {
213 debug(" ");
214 continue;
215 }
216 debug("%s = ", sparc_regnames[r]);
217 debug("0x%016llx", (long long)
218 cpu->cd.sparc.r[r]);
219 if ((i & 1) < 1)
220 debug(" ");
221 else
222 debug("\n");
223 }
224 }
225 }
226 }
227
228
229 /*
230 * sparc_cpu_register_match():
231 */
232 void sparc_cpu_register_match(struct machine *m, char *name,
233 int writeflag, uint64_t *valuep, int *match_register)
234 {
235 int cpunr = 0;
236
237 /* CPU number: */
238
239 /* TODO */
240
241 /* Register name: */
242 if (strcasecmp(name, "pc") == 0) {
243 if (writeflag) {
244 m->cpus[cpunr]->pc = *valuep;
245 } else
246 *valuep = m->cpus[cpunr]->pc;
247 *match_register = 1;
248 }
249 }
250
251
252 /*
253 * sparc_cpu_interrupt():
254 */
255 int sparc_cpu_interrupt(struct cpu *cpu, uint64_t irq_nr)
256 {
257 fatal("sparc_cpu_interrupt(): TODO\n");
258 return 0;
259 }
260
261
262 /*
263 * sparc_cpu_interrupt_ack():
264 */
265 int sparc_cpu_interrupt_ack(struct cpu *cpu, uint64_t irq_nr)
266 {
267 /* fatal("sparc_cpu_interrupt_ack(): TODO\n"); */
268 return 0;
269 }
270
271
272 /*
273 * sparc_cpu_disassemble_instr():
274 *
275 * Convert an instruction word into human readable format, for instruction
276 * tracing.
277 *
278 * If running is 1, cpu->pc should be the address of the instruction.
279 *
280 * If running is 0, things that depend on the runtime environment (eg.
281 * register contents) will not be shown, and addr will be used instead of
282 * cpu->pc for relative addresses.
283 */
284 int sparc_cpu_disassemble_instr(struct cpu *cpu, unsigned char *instr,
285 int running, uint64_t dumpaddr, int bintrans)
286 {
287 uint64_t offset, tmp;
288 uint32_t iword;
289 int hi2, op2, rd, rs1, rs2, siconst, btype, tmps, no_rd = 0;
290 int asi, no_rs1 = 0, no_rs2 = 0, jmpl = 0, shift_x = 0, cc, p;
291 char *symbol, *mnem;
292
293 if (running)
294 dumpaddr = cpu->pc;
295
296 symbol = get_symbol_name(&cpu->machine->symbol_context,
297 dumpaddr, &offset);
298 if (symbol != NULL && offset==0)
299 debug("<%s>\n", symbol);
300
301 if (cpu->machine->ncpus > 1 && running)
302 debug("cpu%i: ", cpu->cpu_id);
303
304 if (cpu->is_32bit)
305 debug("%08x", (int)dumpaddr);
306 else
307 debug("%016llx", (long long)dumpaddr);
308
309 iword = *(uint32_t *)&instr[0];
310 iword = BE32_TO_HOST(iword);
311
312 debug(": %08x\t", iword);
313
314 /*
315 * Decode the instruction:
316 *
317 * http://www.cs.unm.edu/~maccabe/classes/341/labman/node9.html is a
318 * good quick description of SPARC instruction encoding.
319 */
320
321 hi2 = iword >> 30;
322 rd = (iword >> 25) & 31;
323 btype = rd & (N_SPARC_BRANCH_TYPES - 1);
324 rs1 = (iword >> 14) & 31;
325 asi = (iword >> 5) & 0xff;
326 rs2 = iword & 31;
327 siconst = (int16_t)((iword & 0x1fff) << 3) >> 3;
328 op2 = (hi2 == 0)? ((iword >> 22) & 7) : ((iword >> 19) & 0x3f);
329 cc = (iword >> 20) & 3;
330 p = (iword >> 19) & 1;
331
332 switch (hi2) {
333
334 case 0: switch (op2) {
335
336 case 0: debug("illtrap\t0x%x", iword & 0x3fffff);
337 break;
338
339 case 1:
340 case 2:
341 case 3: if (op2 == 3)
342 debug("%s", sparc_regbranch_names[btype & 7]);
343 else
344 debug("%s", sparc_branch_names[btype]);
345 if (rd & 16)
346 debug(",a");
347 tmps = iword;
348 switch (op2) {
349 case 1: tmps <<= 13;
350 tmps >>= 11;
351 if (!p)
352 debug(",pn");
353 debug("\t%%%s,", cc==0 ? "icc" :
354 (cc==2 ? "xcc" : "UNKNOWN"));
355 break;
356 case 2: tmps <<= 10;
357 tmps >>= 8;
358 debug("\t");
359 break;
360 case 3: if (btype & 8)
361 debug("(INVALID)");
362 if (!p)
363 debug(",pn");
364 debug("\t%%%s,", sparc_regnames[rs1]);
365 tmps = ((iword & 0x300000) >> 6)
366 | (iword & 0x3fff);
367 tmps <<= 16;
368 tmps >>= 14;
369 break;
370 }
371 tmp = (int64_t)(int32_t)tmps;
372 tmp += dumpaddr;
373 debug("0x%llx", (long long)tmp);
374 symbol = get_symbol_name(&cpu->machine->
375 symbol_context, tmp, &offset);
376 if (symbol != NULL)
377 debug(" \t<%s>", symbol);
378 break;
379
380 case 4: if (rd == 0) {
381 debug("nop");
382 break;
383 }
384 debug("sethi\t%%hi(0x%x),", (iword & 0x3fffff) << 10);
385 debug("%%%s", sparc_regnames[rd]);
386 break;
387
388 default:debug("UNIMPLEMENTED hi2=%i, op2=0x%x", hi2, op2);
389 }
390 break;
391
392 case 1: tmp = (int32_t)iword << 2;
393 tmp += dumpaddr;
394 debug("call\t0x%llx", (long long)tmp);
395 symbol = get_symbol_name(&cpu->machine->symbol_context,
396 tmp, &offset);
397 if (symbol != NULL)
398 debug(" \t<%s>", symbol);
399 break;
400
401 case 2: mnem = sparc_alu_names[op2];
402 switch (op2) {
403 case 0: /* add */
404 if (rd == rs1 && (iword & 0x3fff) == 0x2001) {
405 mnem = "inc";
406 no_rs1 = no_rs2 = 1;
407 }
408 break;
409 case 2: /* or */
410 if (rs1 == 0) {
411 mnem = "mov";
412 no_rs1 = 1;
413 }
414 break;
415 case 4: /* sub */
416 if (rd == rs1 && (iword & 0x3fff) == 0x2001) {
417 mnem = "dec";
418 no_rs1 = no_rs2 = 1;
419 }
420 break;
421 case 20:/* subcc */
422 if (rd == 0) {
423 mnem = "cmp";
424 no_rd = 1;
425 }
426 break;
427 case 37:/* sll */
428 case 38:/* srl */
429 case 39:/* sra */
430 if (siconst & 0x1000) {
431 siconst &= 0x3f;
432 shift_x = 1;
433 } else
434 siconst &= 0x1f;
435 break;
436 case 43:/* ? */
437 if (iword == 0x81580000) {
438 mnem = "flushw";
439 no_rs1 = no_rs2 = no_rd = 1;
440 }
441 break;
442 case 49:/* ? */
443 if (iword == 0x83880000) {
444 mnem = "restored";
445 no_rs1 = no_rs2 = no_rd = 1;
446 }
447 break;
448 case 56:/* jmpl */
449 jmpl = 1;
450 if (iword == 0x81c7e008) {
451 mnem = "ret";
452 no_rs1 = no_rs2 = no_rd = 1;
453 }
454 if (iword == 0x81c3e008) {
455 mnem = "retl";
456 no_rs1 = no_rs2 = no_rd = 1;
457 }
458 break;
459 case 61:/* restore */
460 if (iword == 0x81e80000)
461 no_rs1 = no_rs2 = no_rd = 1;
462 break;
463 case 62:if (iword == 0x83f00000) {
464 mnem = "retry";
465 no_rs1 = no_rs2 = no_rd = 1;
466 }
467 break;
468 }
469 debug("%s", mnem);
470 if (shift_x)
471 debug("x");
472 debug("\t");
473 if (!no_rs1)
474 debug("%%%s", sparc_regnames[rs1]);
475 if (!no_rs1 && !no_rs2) {
476 if (jmpl)
477 debug("+");
478 else
479 debug(",");
480 }
481 if (!no_rs2) {
482 if ((iword >> 13) & 1) {
483 if (siconst >= -9 && siconst <= 9)
484 debug("%i", siconst);
485 else
486 debug("0x%x", siconst);
487 } else {
488 debug("%%%s", sparc_regnames[rs2]);
489 }
490 }
491 if ((!no_rs1 || !no_rs2) && !no_rd)
492 debug(",");
493 if (!no_rd)
494 debug("%%%s", sparc_regnames[rd]);
495 break;
496
497 case 3: debug("%s\t", sparc_loadstore_names[op2]);
498 if (op2 & 4)
499 debug("%%%s,", sparc_regnames[rd]);
500 debug("[%%%s", sparc_regnames[rs1]);
501 if ((iword >> 13) & 1) {
502 if (siconst > 0)
503 debug("+");
504 if (siconst != 0)
505 debug("%i", siconst);
506 } else {
507 if (rs2 != 0)
508 debug("+%%%s", sparc_regnames[rs2]);
509 }
510 debug("]");
511 if (asi != 0)
512 debug("(%i)", asi);
513 if (!(op2 & 4))
514 debug(",%%%s", sparc_regnames[rd]);
515 break;
516 }
517
518 debug("\n");
519 return sizeof(iword);
520 }
521
522
523 #include "tmp_sparc_tail.c"
524

  ViewVC Help
Powered by ViewVC 1.1.26