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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 42 - (hide annotations)
Mon Oct 8 16:22:32 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 19592 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1613 2007/06/15 20:11:26 debug Exp $
20070501	Continuing a little on m88k disassembly (control registers,
		more instructions).
		Adding a dummy mvme88k machine mode.
20070502	Re-adding MIPS load/store alignment exceptions.
20070503	Implementing more of the M88K disassembly code.
20070504	Adding disassembly of some more M88K load/store instructions.
		Implementing some relatively simple M88K instructions (br.n,
		xor[.u] imm, and[.u] imm).
20070505	Implementing M88K three-register and, or, xor, and jmp[.n],
		bsr[.n] including function call trace stuff.
		Applying a patch from Bruce M. Simpson which implements the
		SYSCON_BOARD_CPU_CLOCK_FREQ_ID object of the syscon call in
		the yamon PROM emulation.
20070506	Implementing M88K bb0[.n] and bb1[.n], and skeletons for
		ldcr and stcr (although no control regs are implemented yet).
20070509	Found and fixed the bug which caused Linux for QEMU_MIPS to
		stop working in 0.4.5.1: It was a faulty change to the MIPS
		'sc' and 'scd' instructions I made while going through gcc -W
		warnings on 20070428.
20070510	Updating the Linux/QEMU_MIPS section in guestoses.html to
		use mips-test-0.2.tar.gz instead of 0.1.
		A big thank you to Miod Vallat for sending me M88K manuals.
		Implementing more M88K instructions (addu, subu, div[u], mulu,
		ext[u], clr, set, cmp).
20070511	Fixing bugs in the M88K "and" and "and.u" instructions (found
		by comparing against the manual).
		Implementing more M88K instructions (mask[.u], mak, bcnd (auto-
		generated)) and some more control register details.
		Cleanup: Removing the experimental AVR emulation mode and
		corresponding devices; AVR emulation wasn't really meaningful.
		Implementing autogeneration of most M88K loads/stores. The
		rectangle drawing demo (with -O0) for M88K runs :-)
		Beginning on M88K exception handling.
		More M88K instructions: tb0, tb1, rte, sub, jsr[.n].
		Adding some skeleton MVME PROM ("BUG") emulation.
20070512	Fixing a bug in the M88K cmp instruction.
		Adding the M88K lda (scaled register) instruction.
		Fixing bugs in 64-bit (32-bit pairs) M88K loads/stores.
		Removing the unused tick_hz stuff from the machine struct.
		Implementing the M88K xmem instruction. OpenBSD/mvme88k gets
		far enough to display the Copyright banner :-)
		Implementing subu.co (guess), addu.co, addu.ci, ff0, and ff1.
		Adding a dev_mvme187, for MVME187-specific devices/registers.
		OpenBSD/mvme88k prints more boot messages. :)
20070515	Continuing on MVME187 emulation (adding more devices, beginning
		on the CMMUs, etc).
		Adding the M88K and.c, xor.c, and or.c instructions, and making
		sure that mul, div, etc cause exceptions if executed when SFD1
		is disabled.
20070517	Continuing on M88K and MVME187 emulation in general; moving
		the CMMU registers to the CPU struct, separating dev_pcc2 from
		dev_mvme187, and beginning on memory_m88k.c (BATC and PATC).
		Fixing a bug in 64-bit (32-bit pairs) M88K fast stores.
		Implementing the clock part of dev_mk48txx.
		Implementing the M88K fstcr and xcr instructions.
		Implementing m88k_cpu_tlbdump().
		Beginning on the implementation of a separate address space
		for M88K .usr loads/stores.
20070520	Removing the non-working (skeleton) Sandpoint, SonyNEWS, SHARK
		Dnard, and Zaurus machine modes.
		Experimenting with dyntrans to_be_translated read-ahead. It
		seems to give a very small performance increase for MIPS
		emulation, but a large performance degradation for SuperH. Hm.
20070522	Disabling correct SuperH ITLB emulation; it does not seem to be
		necessary in order to let SH4 guest OSes run, and it slows down
		userspace code.
		Implementing "samepage" branches for SuperH emulation, and some
		other minor speed hacks.
20070525	Continuing on M88K memory-related stuff: exceptions, memory
		transaction register contents, etc.
		Implementing the M88K subu.ci instruction.
		Removing the non-working (skeleton) Iyonix machine mode.
		OpenBSD/mvme88k reaches userland :-), starts executing
		/sbin/init's instructions, and issues a few syscalls, before
		crashing.
20070526	Fixing bugs in dev_mk48txx, so that OpenBSD/mvme88k detects
		the correct time-of-day.
		Implementing a generic IRQ controller for the test machines
		(dev_irqc), similar to a proposed patch from Petr Stepan.
		Experimenting some more with translation read-ahead.
		Adding an "expect" script for automated OpenBSD/landisk
		install regression/performance tests.
20070527	Adding a dummy mmEye (SH3) machine mode skeleton.
		FINALLY found the strange M88K bug I have been hunting: I had
		not emulated the SNIP value for exceptions occurring in
		branch delay slots correctly.
		Implementing correct exceptions for 64-bit M88K loads/stores.
		Address to symbol lookups are now disabled when M88K is
		running in usermode (because usermode addresses don't have
		anything to do with supervisor addresses).
20070531	Removing the mmEye machine mode skeleton.
20070604	Some minor code cleanup.
20070605	Moving src/useremul.c into a subdir (src/useremul/), and
		cleaning up some more legacy constructs.
		Adding -Wstrict-aliasing and -fstrict-aliasing detection to
		the configure script.
20070606	Adding a check for broken GCC on Solaris to the configure
		script. (GCC 3.4.3 on Solaris cannot handle static variables
		which are initialized to 0 or NULL. :-/)
		Removing the old (non-working) ARC emulation modes: NEC RD94,
		R94, R96, and R98, and the last traces of Olivetti M700 and
		Deskstation Tyne.
		Removing the non-working skeleton WDSC device (dev_wdsc).
20070607	Thinking about how to use the host's cc + ld at runtime to
		generate native code. (See experiments/native_cc_ld_test.i
		for an example.)
20070608	Adding a program counter sampling timer, which could be useful
		for native code generation experiments.
		The KN02_CSR_NRMMOD bit in the DECstation 5000/200 (KN02) CSR
		should always be set, to allow a 5000/200 PROM to boot.
20070609	Moving out breakpoint details from the machine struct into
		a helper struct, and removing the limit on max nr of
		breakpoints.
20070610	Moving out tick functions into a helper struct as well (which
		also gets rid of the max limit).
20070612	FINALLY figured out why Debian/DECstation stopped working when
		translation read-ahead was enabled: in src/memory_rw.c, the
		call to invalidate_code_translation was made also if the
		memory access was an instruction load (if the page was mapped
		as writable); it shouldn't be called in that case.
20070613	Implementing some more MIPS32/64 revision 2 instructions: di,
		ei, ext, dext, dextm, dextu, and ins.
20070614	Implementing an instruction combination for the NetBSD/arm
		idle loop (making the host not use any cpu if NetBSD/arm
		inside the emulator is not using any cpu).
		Increasing the nr of ARM VPH entries from 128 to 384.
20070615	Removing the ENABLE_arch stuff from the configure script, so
		that all included architectures are included in both release
		and development builds.
		Moving memory related helper functions from misc.c to memory.c.
		Adding preliminary instructions for netbooting NetBSD/pmppc to
		guestoses.html; it doesn't work yet, there are weird timeouts.
		Beginning a total rewrite of the userland emulation modes
		(removing all emulation modes, beginning from scratch with
		NetBSD/MIPS and FreeBSD/Alpha only).
20070616	After fixing a bug in the DEC21143 NIC (the TDSTAT_OWN bit was
		only cleared for the last segment when transmitting, not all
		segments), NetBSD/pmppc boots with root-on-nfs without the
		timeouts. Updating guestoses.html.
		Removing the skeleton PSP (Playstation Portable) mode.
		Moving X11-related stuff in the machine struct into a helper
		struct.
		Cleanup of out-of-memory checks, to use a new CHECK_ALLOCATION
		macro (which prints a meaningful error message).
		Adding a COMMENT to each machine and device (for automagic
		.index comment generation).
		Doing regression testing for the next release.

==============  RELEASE 0.4.6  ==============


1 dpavlin 14 /*
2 dpavlin 34 * Copyright (C) 2005-2007 Anders Gavare. All rights reserved.
3 dpavlin 14 *
4     * Redistribution and use in source and binary forms, with or without
5     * modification, are permitted provided that the following conditions are met:
6     *
7     * 1. Redistributions of source code must retain the above copyright
8     * notice, this list of conditions and the following disclaimer.
9     * 2. Redistributions in binary form must reproduce the above copyright
10     * notice, this list of conditions and the following disclaimer in the
11     * documentation and/or other materials provided with the distribution.
12     * 3. The name of the author may not be used to endorse or promote products
13     * derived from this software without specific prior written permission.
14     *
15     * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16     * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18     * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19     * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20     * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21     * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24     * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25     * SUCH DAMAGE.
26     *
27     *
28 dpavlin 42 * $Id: cpu_sparc.c,v 1.46 2007/06/07 15:36:24 debug Exp $
29 dpavlin 14 *
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 dpavlin 32 #include "settings.h"
43 dpavlin 14 #include "symbol.h"
44 dpavlin 42 #include "timer.h"
45 dpavlin 14
46 dpavlin 22
47 dpavlin 14 #define DYNTRANS_DUALMODE_32
48 dpavlin 24 #define DYNTRANS_DELAYSLOT
49 dpavlin 14 #include "tmp_sparc_head.c"
50    
51    
52 dpavlin 42 extern int native_code_translation_enabled;
53    
54 dpavlin 22 static char *sparc_regnames[N_SPARC_REG] = SPARC_REG_NAMES;
55 dpavlin 24 static char *sparc_pregnames[N_SPARC_PREG] = SPARC_PREG_NAMES;
56 dpavlin 22 static char *sparc_regbranch_names[N_SPARC_REGBRANCH_TYPES] =
57     SPARC_REGBRANCH_NAMES;
58     static char *sparc_branch_names[N_SPARC_BRANCH_TYPES] = SPARC_BRANCH_NAMES;
59     static char *sparc_alu_names[N_ALU_INSTR_TYPES] = SPARC_ALU_NAMES;
60     static char *sparc_loadstore_names[N_LOADSTORE_TYPES] = SPARC_LOADSTORE_NAMES;
61    
62    
63 dpavlin 14 /*
64     * sparc_cpu_new():
65     *
66     * Create a new SPARC cpu object.
67     *
68     * Returns 1 on success, 0 if there was no matching SPARC processor with
69     * this cpu_type_name.
70     */
71     int sparc_cpu_new(struct cpu *cpu, struct memory *mem, struct machine *machine,
72     int cpu_id, char *cpu_type_name)
73     {
74 dpavlin 22 int any_cache = 0;
75     int i = 0;
76     struct sparc_cpu_type_def cpu_type_defs[] = SPARC_CPU_TYPE_DEFS;
77    
78     /* Scan the cpu_type_defs list for this cpu type: */
79     while (cpu_type_defs[i].name != NULL) {
80     if (strcasecmp(cpu_type_defs[i].name, cpu_type_name) == 0) {
81     break;
82     }
83     i++;
84     }
85     if (cpu_type_defs[i].name == NULL)
86 dpavlin 14 return 0;
87    
88     cpu->memory_rw = sparc_memory_rw;
89    
90 dpavlin 22 cpu->cd.sparc.cpu_type = cpu_type_defs[i];
91     cpu->name = cpu->cd.sparc.cpu_type.name;
92     cpu->byte_order = EMUL_BIG_ENDIAN;
93     cpu->is_32bit = (cpu->cd.sparc.cpu_type.bits == 32)? 1 : 0;
94 dpavlin 14
95 dpavlin 24 cpu->instruction_has_delayslot = sparc_cpu_instruction_has_delayslot;
96    
97 dpavlin 32 /* TODO: Separate this into 64-bit vs 32-bit? */
98     cpu->translate_v2p = sparc_translate_v2p;
99    
100 dpavlin 22 if (cpu->is_32bit) {
101 dpavlin 28 cpu->run_instr = sparc32_run_instr;
102 dpavlin 22 cpu->update_translation_table =
103     sparc32_update_translation_table;
104     cpu->invalidate_translation_caches =
105     sparc32_invalidate_translation_caches;
106     cpu->invalidate_code_translation =
107     sparc32_invalidate_code_translation;
108     } else {
109 dpavlin 28 cpu->run_instr = sparc_run_instr;
110 dpavlin 22 cpu->update_translation_table = sparc_update_translation_table;
111     cpu->invalidate_translation_caches =
112     sparc_invalidate_translation_caches;
113     cpu->invalidate_code_translation =
114     sparc_invalidate_code_translation;
115     }
116    
117 dpavlin 14 /* Only show name and caches etc for CPU nr 0 (in SMP machines): */
118     if (cpu_id == 0) {
119     debug("%s", cpu->name);
120 dpavlin 22
121     if (cpu->cd.sparc.cpu_type.icache_shift != 0)
122     any_cache = 1;
123     if (cpu->cd.sparc.cpu_type.dcache_shift != 0)
124     any_cache = 1;
125     if (cpu->cd.sparc.cpu_type.l2cache_shift != 0)
126     any_cache = 1;
127    
128     if (any_cache) {
129     debug(" (I+D = %i+%i KB", (int)
130     (1 << (cpu->cd.sparc.cpu_type.icache_shift-10)),
131     (int)(1<<(cpu->cd.sparc.cpu_type.dcache_shift-10)));
132     if (cpu->cd.sparc.cpu_type.l2cache_shift != 0) {
133     debug(", L2 = %i KB",
134     (int)(1 << (cpu->cd.sparc.cpu_type.
135     l2cache_shift-10)));
136     }
137     debug(")");
138     }
139 dpavlin 14 }
140    
141 dpavlin 24 /* After a reset, the Tick register is not readable by user code: */
142     cpu->cd.sparc.tick |= SPARC_TICK_NPT;
143    
144     /* Insert number of Windows and Trap levels into the version reg.: */
145 dpavlin 36 cpu->cd.sparc.ver |= N_REG_WINDOWS | (MAXTL << SPARC_VER_MAXTL_SHIFT);
146 dpavlin 24
147 dpavlin 28 /* Misc. initial settings suitable for userland emulation: */
148 dpavlin 36 cpu->cd.sparc.cansave = cpu->cd.sparc.cpu_type.nwindows - 2;
149     cpu->cd.sparc.canrestore = 0;
150     cpu->cd.sparc.cleanwin = 1;
151     cpu->cd.sparc.otherwin = 0;
152 dpavlin 28
153 dpavlin 36 if (cpu->cd.sparc.cansave + cpu->cd.sparc.canrestore
154     + cpu->cd.sparc.otherwin != cpu->cd.sparc.cpu_type.nwindows - 2) {
155     fatal("Fatal internal error: inconsistent windowing "
156     "parameters!\n");
157     exit(1);
158     }
159    
160     if (cpu->cd.sparc.cpu_type.nwindows > N_REG_WINDOWS) {
161 dpavlin 28 fatal("Fatal internal error: nwindows = %1 is more than %i\n",
162 dpavlin 36 cpu->cd.sparc.cpu_type.nwindows, N_REG_WINDOWS);
163 dpavlin 28 exit(1);
164     }
165    
166 dpavlin 32 CPU_SETTINGS_ADD_REGISTER64("pc", cpu->pc);
167     CPU_SETTINGS_ADD_REGISTER64("y", cpu->cd.sparc.y);
168     CPU_SETTINGS_ADD_REGISTER64("pstate", cpu->cd.sparc.pstate);
169     for (i=0; i<N_SPARC_REG; i++)
170     CPU_SETTINGS_ADD_REGISTER64(sparc_regnames[i],
171     cpu->cd.sparc.r[i]);
172     /* TODO: Handler for writes to the zero register! */
173    
174 dpavlin 42 if (native_code_translation_enabled)
175     cpu->sampling_timer = timer_add(CPU_SAMPLE_TIMER_HZ,
176     sparc_timer_sample_tick, cpu);
177    
178 dpavlin 14 return 1;
179     }
180    
181    
182     /*
183     * sparc_cpu_list_available_types():
184     *
185     * Print a list of available SPARC CPU types.
186     */
187     void sparc_cpu_list_available_types(void)
188     {
189 dpavlin 22 int i, j;
190     struct sparc_cpu_type_def tdefs[] = SPARC_CPU_TYPE_DEFS;
191    
192     i = 0;
193     while (tdefs[i].name != NULL) {
194     debug("%s", tdefs[i].name);
195 dpavlin 24 for (j=16 - strlen(tdefs[i].name); j>0; j--)
196 dpavlin 22 debug(" ");
197     i++;
198 dpavlin 24 if ((i % 4) == 0 || tdefs[i].name == NULL)
199 dpavlin 22 debug("\n");
200     }
201 dpavlin 14 }
202    
203    
204     /*
205     * sparc_cpu_dumpinfo():
206     */
207     void sparc_cpu_dumpinfo(struct cpu *cpu)
208     {
209 dpavlin 22 debug(", %i-bit\n", cpu->cd.sparc.cpu_type.bits);
210 dpavlin 14 }
211    
212    
213     /*
214     * sparc_cpu_register_dump():
215     *
216     * Dump cpu registers in a relatively readable format.
217     *
218     * gprs: set to non-zero to dump GPRs and some special-purpose registers.
219     * coprocs: set bit 0..3 to dump registers in coproc 0..3.
220     */
221     void sparc_cpu_register_dump(struct cpu *cpu, int gprs, int coprocs)
222     {
223     char *symbol;
224 dpavlin 20 uint64_t offset;
225 dpavlin 22 int i, x = cpu->cpu_id;
226     int bits32 = cpu->is_32bit;
227 dpavlin 14
228     if (gprs) {
229     /* Special registers (pc, ...) first: */
230     symbol = get_symbol_name(&cpu->machine->symbol_context,
231     cpu->pc, &offset);
232    
233 dpavlin 22 debug("cpu%i: pc = 0x", x);
234 dpavlin 14 if (bits32)
235 dpavlin 24 debug("%08"PRIx32, (uint32_t) cpu->pc);
236 dpavlin 14 else
237 dpavlin 24 debug("%016"PRIx64, (uint64_t) cpu->pc);
238 dpavlin 14 debug(" <%s>\n", symbol != NULL? symbol : " no symbol ");
239    
240 dpavlin 24 debug("cpu%i: y = 0x%08"PRIx32" ",
241     x, (uint32_t)cpu->cd.sparc.y);
242     debug("icc = ");
243     debug(cpu->cd.sparc.ccr & SPARC_CCR_N? "N" : "n");
244     debug(cpu->cd.sparc.ccr & SPARC_CCR_Z? "Z" : "z");
245     debug(cpu->cd.sparc.ccr & SPARC_CCR_V? "V" : "v");
246     debug(cpu->cd.sparc.ccr & SPARC_CCR_C? "C" : "c");
247     if (!bits32) {
248     debug(" xcc = ");
249     debug((cpu->cd.sparc.ccr >> SPARC_CCR_XCC_SHIFT)
250     & SPARC_CCR_N? "N" : "n");
251     debug((cpu->cd.sparc.ccr >> SPARC_CCR_XCC_SHIFT)
252     & SPARC_CCR_Z? "Z" : "z");
253     debug((cpu->cd.sparc.ccr >> SPARC_CCR_XCC_SHIFT)
254     & SPARC_CCR_V? "V" : "v");
255     debug((cpu->cd.sparc.ccr >> SPARC_CCR_XCC_SHIFT)
256     & SPARC_CCR_C? "C" : "c");
257     }
258     debug("\n");
259    
260     if (bits32)
261     debug("cpu%i: psr = 0x%08"PRIx32"\n",
262     x, (uint32_t) cpu->cd.sparc.psr);
263     else
264     debug("cpu%i: pstate = 0x%016"PRIx64"\n",
265     x, (uint64_t) cpu->cd.sparc.pstate);
266    
267 dpavlin 22 if (bits32) {
268     for (i=0; i<N_SPARC_REG; i++) {
269     if ((i & 3) == 0)
270     debug("cpu%i: ", x);
271     /* Skip the zero register: */
272 dpavlin 24 if (i == SPARC_ZEROREG) {
273 dpavlin 22 debug(" ");
274     continue;
275     }
276     debug("%s=", sparc_regnames[i]);
277 dpavlin 42 debug("0x%08"PRIx32,
278     (uint32_t) cpu->cd.sparc.r[i]);
279 dpavlin 22 if ((i & 3) < 3)
280     debug(" ");
281     else
282     debug("\n");
283     }
284     } else {
285     for (i=0; i<N_SPARC_REG; i++) {
286     int r = ((i >> 1) & 15) | ((i&1) << 4);
287     if ((i & 1) == 0)
288     debug("cpu%i: ", x);
289 dpavlin 24
290 dpavlin 22 /* Skip the zero register: */
291 dpavlin 24 if (i == SPARC_ZEROREG) {
292 dpavlin 22 debug(" ");
293     continue;
294     }
295 dpavlin 24
296 dpavlin 22 debug("%s = ", sparc_regnames[r]);
297 dpavlin 24 debug("0x%016"PRIx64, (uint64_t)
298 dpavlin 22 cpu->cd.sparc.r[r]);
299 dpavlin 24
300 dpavlin 22 if ((i & 1) < 1)
301     debug(" ");
302     else
303     debug("\n");
304     }
305     }
306 dpavlin 14 }
307 dpavlin 36
308     if (coprocs & 1) {
309     int sum;
310    
311     debug("cpu%i: cwp = 0x%02x\n", x, cpu->cd.sparc.cwp);
312     debug("cpu%i: cansave = 0x%02x\n", x, cpu->cd.sparc.cansave);
313     debug("cpu%i: canrestore = 0x%02x\n", x,
314     cpu->cd.sparc.canrestore);
315     debug("cpu%i: otherwin = 0x%02x\n", x,
316     cpu->cd.sparc.otherwin);
317     debug("cpu%i: cleanwin = 0x%02x\n", x,
318     cpu->cd.sparc.cleanwin);
319    
320     sum = cpu->cd.sparc.cansave + cpu->cd.sparc.canrestore +
321     cpu->cd.sparc.otherwin;
322     debug("cpu%i: cansave + canrestore + otherwin = %i + %i + %i"
323     " = %i", x, cpu->cd.sparc.cansave, cpu->cd.sparc.canrestore,
324     cpu->cd.sparc.otherwin, sum);
325     if (sum == cpu->cd.sparc.cpu_type.nwindows - 2)
326     debug(" (consistent)\n");
327     else
328     debug(" (INCONSISTENT!)\n");
329    
330     debug("cpu%i: wstate: other = %i, normal = %i\n",
331     x, (cpu->cd.sparc.wstate & SPARC_WSTATE_OTHER_MASK)
332     >> SPARC_WSTATE_OTHER_SHIFT, cpu->cd.sparc.wstate &
333     SPARC_WSTATE_NORMAL_MASK);
334    
335     debug("cpu%i: asi = 0x%02x\n", x, cpu->cd.sparc.asi);
336     debug("cpu%i: tl = 0x%02x\n", x, cpu->cd.sparc.tl);
337     debug("cpu%i: pil = 0x%02x\n", x, cpu->cd.sparc.pil);
338    
339     for (i=0; i<MAXTL; i++) {
340     debug("cpu%i: tpc[%i] = 0x", x, i);
341     if (bits32)
342     debug("%08"PRIx32"\n",
343     (uint32_t) cpu->cd.sparc.tpc[i]);
344     else
345     debug("%016"PRIx64"\n",
346     (uint64_t) cpu->cd.sparc.tpc[i]);
347    
348     debug("cpu%i: tnpc[%i] = 0x", x, i);
349     if (bits32)
350     debug("%08"PRIx32"\n",
351     (uint32_t) cpu->cd.sparc.tnpc[i]);
352     else
353     debug("%016"PRIx64"\n",
354     (uint64_t) cpu->cd.sparc.tnpc[i]);
355    
356     debug("cpu%i: tstate[%i] = 0x", x, i);
357     if (bits32)
358     debug("%08"PRIx32"\n",
359     (uint32_t) cpu->cd.sparc.tstate[i]);
360     else
361     debug("%016"PRIx64"\n",
362     (uint64_t) cpu->cd.sparc.tstate[i]);
363    
364     debug("cpu%i: ttype[%i] = 0x"PRIx32"\n",
365     x, i, cpu->cd.sparc.ttype[i]);
366     }
367    
368     debug("cpu%i: tba = 0x", x);
369     if (bits32)
370     debug("%08"PRIx32"\n", (uint32_t) cpu->cd.sparc.tba);
371     else
372     debug("%016"PRIx64"\n", (uint64_t) cpu->cd.sparc.tba);
373     }
374 dpavlin 14 }
375    
376    
377     /*
378 dpavlin 24 * sparc_cpu_tlbdump():
379     *
380     * Called from the debugger to dump the TLB in a readable format.
381     * x is the cpu number to dump, or -1 to dump all CPUs.
382     *
383     * If rawflag is nonzero, then the TLB contents isn't formated nicely,
384     * just dumped.
385     */
386     void sparc_cpu_tlbdump(struct machine *m, int x, int rawflag)
387     {
388     }
389    
390    
391     /*
392     * sparc_cpu_instruction_has_delayslot():
393     *
394     * Return 1 if an opcode is a branch, 0 otherwise.
395     */
396     int sparc_cpu_instruction_has_delayslot(struct cpu *cpu, unsigned char *ib)
397     {
398     uint32_t iword = *((uint32_t *)&ib[0]);
399     int hi2, op2;
400    
401     iword = BE32_TO_HOST(iword);
402    
403     hi2 = iword >> 30;
404     op2 = (hi2 == 0)? ((iword >> 22) & 7) : ((iword >> 19) & 0x3f);
405    
406     switch (hi2) {
407     case 0: /* conditional branch */
408     switch (op2) {
409     case 1:
410     case 2:
411     case 3: return 1;
412     }
413     break;
414     case 1: /* call */
415     return 1;
416     case 2: /* misc alu instructions */
417     switch (op2) {
418     case 56:/* jump and link */
419     return 1;
420 dpavlin 32 case 57:/* return */
421     return 1;
422 dpavlin 24 }
423     break;
424     }
425    
426     return 0;
427     }
428    
429    
430     /*
431 dpavlin 14 * sparc_cpu_disassemble_instr():
432     *
433     * Convert an instruction word into human readable format, for instruction
434     * tracing.
435     *
436     * If running is 1, cpu->pc should be the address of the instruction.
437     *
438     * If running is 0, things that depend on the runtime environment (eg.
439     * register contents) will not be shown, and addr will be used instead of
440     * cpu->pc for relative addresses.
441     */
442     int sparc_cpu_disassemble_instr(struct cpu *cpu, unsigned char *instr,
443 dpavlin 24 int running, uint64_t dumpaddr)
444 dpavlin 14 {
445 dpavlin 22 uint64_t offset, tmp;
446 dpavlin 14 uint32_t iword;
447 dpavlin 22 int hi2, op2, rd, rs1, rs2, siconst, btype, tmps, no_rd = 0;
448     int asi, no_rs1 = 0, no_rs2 = 0, jmpl = 0, shift_x = 0, cc, p;
449 dpavlin 24 char *symbol, *mnem, *rd_name, *rs_name;
450 dpavlin 14
451     if (running)
452     dumpaddr = cpu->pc;
453    
454     symbol = get_symbol_name(&cpu->machine->symbol_context,
455     dumpaddr, &offset);
456     if (symbol != NULL && offset==0)
457     debug("<%s>\n", symbol);
458    
459     if (cpu->machine->ncpus > 1 && running)
460     debug("cpu%i: ", cpu->cpu_id);
461    
462 dpavlin 22 if (cpu->is_32bit)
463 dpavlin 24 debug("%08"PRIx32, (uint32_t) dumpaddr);
464 dpavlin 14 else
465 dpavlin 24 debug("%016"PRIx64, (uint64_t) dumpaddr);
466 dpavlin 14
467 dpavlin 22 iword = *(uint32_t *)&instr[0];
468     iword = BE32_TO_HOST(iword);
469 dpavlin 14
470 dpavlin 42 debug(": %08"PRIx32, iword);
471 dpavlin 14
472 dpavlin 24 if (running && cpu->delay_slot)
473     debug(" (d)");
474    
475     debug("\t");
476    
477    
478 dpavlin 14 /*
479     * Decode the instruction:
480 dpavlin 22 *
481     * http://www.cs.unm.edu/~maccabe/classes/341/labman/node9.html is a
482     * good quick description of SPARC instruction encoding.
483 dpavlin 14 */
484    
485 dpavlin 22 hi2 = iword >> 30;
486     rd = (iword >> 25) & 31;
487     btype = rd & (N_SPARC_BRANCH_TYPES - 1);
488     rs1 = (iword >> 14) & 31;
489     asi = (iword >> 5) & 0xff;
490     rs2 = iword & 31;
491     siconst = (int16_t)((iword & 0x1fff) << 3) >> 3;
492     op2 = (hi2 == 0)? ((iword >> 22) & 7) : ((iword >> 19) & 0x3f);
493     cc = (iword >> 20) & 3;
494     p = (iword >> 19) & 1;
495 dpavlin 14
496 dpavlin 22 switch (hi2) {
497    
498     case 0: switch (op2) {
499    
500     case 0: debug("illtrap\t0x%x", iword & 0x3fffff);
501     break;
502    
503     case 1:
504     case 2:
505     case 3: if (op2 == 3)
506     debug("%s", sparc_regbranch_names[btype & 7]);
507     else
508     debug("%s", sparc_branch_names[btype]);
509     if (rd & 16)
510     debug(",a");
511     tmps = iword;
512     switch (op2) {
513     case 1: tmps <<= 13;
514     tmps >>= 11;
515     if (!p)
516     debug(",pn");
517     debug("\t%%%s,", cc==0 ? "icc" :
518     (cc==2 ? "xcc" : "UNKNOWN"));
519     break;
520     case 2: tmps <<= 10;
521     tmps >>= 8;
522     debug("\t");
523     break;
524     case 3: if (btype & 8)
525     debug("(INVALID)");
526     if (!p)
527     debug(",pn");
528     debug("\t%%%s,", sparc_regnames[rs1]);
529     tmps = ((iword & 0x300000) >> 6)
530     | (iword & 0x3fff);
531     tmps <<= 16;
532     tmps >>= 14;
533     break;
534     }
535     tmp = (int64_t)(int32_t)tmps;
536     tmp += dumpaddr;
537 dpavlin 24 debug("0x%"PRIx64, (uint64_t) tmp);
538 dpavlin 22 symbol = get_symbol_name(&cpu->machine->
539     symbol_context, tmp, &offset);
540     if (symbol != NULL)
541     debug(" \t<%s>", symbol);
542     break;
543    
544     case 4: if (rd == 0) {
545     debug("nop");
546     break;
547     }
548     debug("sethi\t%%hi(0x%x),", (iword & 0x3fffff) << 10);
549     debug("%%%s", sparc_regnames[rd]);
550     break;
551    
552     default:debug("UNIMPLEMENTED hi2=%i, op2=0x%x", hi2, op2);
553     }
554     break;
555    
556     case 1: tmp = (int32_t)iword << 2;
557     tmp += dumpaddr;
558 dpavlin 24 debug("call\t0x%"PRIx64, (uint64_t) tmp);
559 dpavlin 22 symbol = get_symbol_name(&cpu->machine->symbol_context,
560     tmp, &offset);
561     if (symbol != NULL)
562     debug(" \t<%s>", symbol);
563     break;
564    
565     case 2: mnem = sparc_alu_names[op2];
566 dpavlin 24 rs_name = sparc_regnames[rs1];
567     rd_name = sparc_regnames[rd];
568 dpavlin 22 switch (op2) {
569     case 0: /* add */
570     if (rd == rs1 && (iword & 0x3fff) == 0x2001) {
571     mnem = "inc";
572     no_rs1 = no_rs2 = 1;
573     }
574     break;
575     case 2: /* or */
576     if (rs1 == 0) {
577     mnem = "mov";
578     no_rs1 = 1;
579     }
580     break;
581     case 4: /* sub */
582     if (rd == rs1 && (iword & 0x3fff) == 0x2001) {
583     mnem = "dec";
584     no_rs1 = no_rs2 = 1;
585     }
586     break;
587     case 20:/* subcc */
588     if (rd == 0) {
589     mnem = "cmp";
590     no_rd = 1;
591     }
592     break;
593     case 37:/* sll */
594     case 38:/* srl */
595     case 39:/* sra */
596     if (siconst & 0x1000) {
597     siconst &= 0x3f;
598     shift_x = 1;
599     } else
600     siconst &= 0x1f;
601     break;
602 dpavlin 24 case 40:/* rd on pre-sparcv9, membar etc on sparcv9 */
603     no_rs2 = 1;
604     rs_name = "UNIMPLEMENTED";
605     switch (rs1) {
606     case 0: rs_name = "y"; break;
607     case 2: rs_name = "ccr"; break;
608     case 3: rs_name = "asi"; break;
609     case 4: rs_name = "tick"; break;
610     case 5: rs_name = "pc"; break;
611     case 6: rs_name = "fprs"; break;
612     case 15:/* membar etc. */
613     if ((iword >> 13) & 1) {
614     no_rd = 1;
615     mnem = "membar";
616     rs_name = "#TODO";
617     }
618     break;
619     case 23:rs_name = "tick_cmpr"; break; /* v9 ? */
620     }
621     break;
622     case 41:rs_name = "psr";
623     no_rs2 = 1;
624     break;
625 dpavlin 30 case 42:/* TODO: something with wim only, on sparc v8? */
626     rs_name = sparc_pregnames[rs1];
627 dpavlin 24 no_rs2 = 1;
628     break;
629 dpavlin 22 case 43:/* ? */
630 dpavlin 24 /* TODO: pre-sparcv9: rd, rs_name = "tbr"; */
631 dpavlin 22 if (iword == 0x81580000) {
632     mnem = "flushw";
633     no_rs1 = no_rs2 = no_rd = 1;
634     }
635     break;
636 dpavlin 24 case 48:/* wr* (SPARCv8) */
637     mnem = "wr";
638     if (rs1 == SPARC_ZEROREG)
639     no_rs1 = 1;
640     switch (rd) {
641     case 0: rd_name = "y"; break;
642     case 2: rd_name = "ccr"; break;
643     case 3: rd_name = "asi"; break;
644     case 6: rd_name = "fprs"; break;
645     case 23:rd_name = "tick_cmpr"; break; /* v9 ? */
646     default:rd_name = "UNIMPLEMENTED";
647     }
648     break;
649 dpavlin 22 case 49:/* ? */
650     if (iword == 0x83880000) {
651     mnem = "restored";
652     no_rs1 = no_rs2 = no_rd = 1;
653     }
654     break;
655 dpavlin 24 case 50:/* wrpr */
656     rd_name = sparc_pregnames[rd];
657     if (rs1 == SPARC_ZEROREG)
658     no_rs1 = 1;
659     break;
660 dpavlin 22 case 56:/* jmpl */
661     jmpl = 1;
662     if (iword == 0x81c7e008) {
663     mnem = "ret";
664     no_rs1 = no_rs2 = no_rd = 1;
665     }
666     if (iword == 0x81c3e008) {
667     mnem = "retl";
668     no_rs1 = no_rs2 = no_rd = 1;
669     }
670     break;
671     case 61:/* restore */
672     if (iword == 0x81e80000)
673     no_rs1 = no_rs2 = no_rd = 1;
674     break;
675     case 62:if (iword == 0x83f00000) {
676     mnem = "retry";
677     no_rs1 = no_rs2 = no_rd = 1;
678     }
679     break;
680     }
681     debug("%s", mnem);
682     if (shift_x)
683     debug("x");
684     debug("\t");
685     if (!no_rs1)
686 dpavlin 24 debug("%%%s", rs_name);
687 dpavlin 22 if (!no_rs1 && !no_rs2) {
688     if (jmpl)
689     debug("+");
690     else
691     debug(",");
692     }
693     if (!no_rs2) {
694     if ((iword >> 13) & 1) {
695     if (siconst >= -9 && siconst <= 9)
696     debug("%i", siconst);
697 dpavlin 28 else if (siconst < 0 && (op2 == 0 ||
698     op2 == 4 || op2 == 20 || op2 == 60))
699     debug("-0x%x", -siconst);
700 dpavlin 22 else
701     debug("0x%x", siconst);
702     } else {
703     debug("%%%s", sparc_regnames[rs2]);
704     }
705     }
706     if ((!no_rs1 || !no_rs2) && !no_rd)
707     debug(",");
708     if (!no_rd)
709 dpavlin 24 debug("%%%s", rd_name);
710 dpavlin 22 break;
711    
712 dpavlin 28 case 3: mnem = sparc_loadstore_names[op2];
713     switch (op2) {
714     case 0: /* 'lduw' was called only 'ld' in pre-v9 */
715     if (cpu->cd.sparc.cpu_type.v < 9)
716     mnem = "ld";
717     break;
718     }
719     debug("%s\t", mnem);
720 dpavlin 22 if (op2 & 4)
721     debug("%%%s,", sparc_regnames[rd]);
722     debug("[%%%s", sparc_regnames[rs1]);
723     if ((iword >> 13) & 1) {
724     if (siconst > 0)
725     debug("+");
726     if (siconst != 0)
727     debug("%i", siconst);
728     } else {
729     if (rs2 != 0)
730     debug("+%%%s", sparc_regnames[rs2]);
731     }
732     debug("]");
733 dpavlin 28 if ((op2 & 0x30) == 0x10)
734 dpavlin 22 debug("(%i)", asi);
735     if (!(op2 & 4))
736     debug(",%%%s", sparc_regnames[rd]);
737     break;
738 dpavlin 14 }
739    
740     debug("\n");
741     return sizeof(iword);
742     }
743    
744    
745 dpavlin 24 /*
746     * sparc_update_pstate():
747     *
748     * Update the pstate register (64-bit sparcs).
749     */
750     static void sparc_update_pstate(struct cpu *cpu, uint64_t new_pstate)
751     {
752     /* uint64_t old_pstate = cpu->cd.sparc.pstate; */
753    
754     /* TODO: Check individual bits. */
755    
756     cpu->cd.sparc.pstate = new_pstate;
757     }
758    
759    
760 dpavlin 14 #include "tmp_sparc_tail.c"
761    

  ViewVC Help
Powered by ViewVC 1.1.26