/[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 42 - (show annotations)
Mon Oct 8 16:22:32 2007 UTC (16 years, 5 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 /*
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_sparc.c,v 1.46 2007/06/07 15:36:24 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 "settings.h"
43 #include "symbol.h"
44 #include "timer.h"
45
46
47 #define DYNTRANS_DUALMODE_32
48 #define DYNTRANS_DELAYSLOT
49 #include "tmp_sparc_head.c"
50
51
52 extern int native_code_translation_enabled;
53
54 static char *sparc_regnames[N_SPARC_REG] = SPARC_REG_NAMES;
55 static char *sparc_pregnames[N_SPARC_PREG] = SPARC_PREG_NAMES;
56 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 /*
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 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 return 0;
87
88 cpu->memory_rw = sparc_memory_rw;
89
90 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
95 cpu->instruction_has_delayslot = sparc_cpu_instruction_has_delayslot;
96
97 /* TODO: Separate this into 64-bit vs 32-bit? */
98 cpu->translate_v2p = sparc_translate_v2p;
99
100 if (cpu->is_32bit) {
101 cpu->run_instr = sparc32_run_instr;
102 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 cpu->run_instr = sparc_run_instr;
110 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 /* Only show name and caches etc for CPU nr 0 (in SMP machines): */
118 if (cpu_id == 0) {
119 debug("%s", cpu->name);
120
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 }
140
141 /* 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 cpu->cd.sparc.ver |= N_REG_WINDOWS | (MAXTL << SPARC_VER_MAXTL_SHIFT);
146
147 /* Misc. initial settings suitable for userland emulation: */
148 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
153 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 fatal("Fatal internal error: nwindows = %1 is more than %i\n",
162 cpu->cd.sparc.cpu_type.nwindows, N_REG_WINDOWS);
163 exit(1);
164 }
165
166 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 if (native_code_translation_enabled)
175 cpu->sampling_timer = timer_add(CPU_SAMPLE_TIMER_HZ,
176 sparc_timer_sample_tick, cpu);
177
178 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 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 for (j=16 - strlen(tdefs[i].name); j>0; j--)
196 debug(" ");
197 i++;
198 if ((i % 4) == 0 || tdefs[i].name == NULL)
199 debug("\n");
200 }
201 }
202
203
204 /*
205 * sparc_cpu_dumpinfo():
206 */
207 void sparc_cpu_dumpinfo(struct cpu *cpu)
208 {
209 debug(", %i-bit\n", cpu->cd.sparc.cpu_type.bits);
210 }
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 uint64_t offset;
225 int i, x = cpu->cpu_id;
226 int bits32 = cpu->is_32bit;
227
228 if (gprs) {
229 /* Special registers (pc, ...) first: */
230 symbol = get_symbol_name(&cpu->machine->symbol_context,
231 cpu->pc, &offset);
232
233 debug("cpu%i: pc = 0x", x);
234 if (bits32)
235 debug("%08"PRIx32, (uint32_t) cpu->pc);
236 else
237 debug("%016"PRIx64, (uint64_t) cpu->pc);
238 debug(" <%s>\n", symbol != NULL? symbol : " no symbol ");
239
240 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 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 if (i == SPARC_ZEROREG) {
273 debug(" ");
274 continue;
275 }
276 debug("%s=", sparc_regnames[i]);
277 debug("0x%08"PRIx32,
278 (uint32_t) cpu->cd.sparc.r[i]);
279 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
290 /* Skip the zero register: */
291 if (i == SPARC_ZEROREG) {
292 debug(" ");
293 continue;
294 }
295
296 debug("%s = ", sparc_regnames[r]);
297 debug("0x%016"PRIx64, (uint64_t)
298 cpu->cd.sparc.r[r]);
299
300 if ((i & 1) < 1)
301 debug(" ");
302 else
303 debug("\n");
304 }
305 }
306 }
307
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 }
375
376
377 /*
378 * 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 case 57:/* return */
421 return 1;
422 }
423 break;
424 }
425
426 return 0;
427 }
428
429
430 /*
431 * 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 int running, uint64_t dumpaddr)
444 {
445 uint64_t offset, tmp;
446 uint32_t iword;
447 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 char *symbol, *mnem, *rd_name, *rs_name;
450
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 if (cpu->is_32bit)
463 debug("%08"PRIx32, (uint32_t) dumpaddr);
464 else
465 debug("%016"PRIx64, (uint64_t) dumpaddr);
466
467 iword = *(uint32_t *)&instr[0];
468 iword = BE32_TO_HOST(iword);
469
470 debug(": %08"PRIx32, iword);
471
472 if (running && cpu->delay_slot)
473 debug(" (d)");
474
475 debug("\t");
476
477
478 /*
479 * Decode the instruction:
480 *
481 * http://www.cs.unm.edu/~maccabe/classes/341/labman/node9.html is a
482 * good quick description of SPARC instruction encoding.
483 */
484
485 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
496 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 debug("0x%"PRIx64, (uint64_t) tmp);
538 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 debug("call\t0x%"PRIx64, (uint64_t) tmp);
559 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 rs_name = sparc_regnames[rs1];
567 rd_name = sparc_regnames[rd];
568 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 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 case 42:/* TODO: something with wim only, on sparc v8? */
626 rs_name = sparc_pregnames[rs1];
627 no_rs2 = 1;
628 break;
629 case 43:/* ? */
630 /* TODO: pre-sparcv9: rd, rs_name = "tbr"; */
631 if (iword == 0x81580000) {
632 mnem = "flushw";
633 no_rs1 = no_rs2 = no_rd = 1;
634 }
635 break;
636 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 case 49:/* ? */
650 if (iword == 0x83880000) {
651 mnem = "restored";
652 no_rs1 = no_rs2 = no_rd = 1;
653 }
654 break;
655 case 50:/* wrpr */
656 rd_name = sparc_pregnames[rd];
657 if (rs1 == SPARC_ZEROREG)
658 no_rs1 = 1;
659 break;
660 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 debug("%%%s", rs_name);
687 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 else if (siconst < 0 && (op2 == 0 ||
698 op2 == 4 || op2 == 20 || op2 == 60))
699 debug("-0x%x", -siconst);
700 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 debug("%%%s", rd_name);
710 break;
711
712 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 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 if ((op2 & 0x30) == 0x10)
734 debug("(%i)", asi);
735 if (!(op2 & 4))
736 debug(",%%%s", sparc_regnames[rd]);
737 break;
738 }
739
740 debug("\n");
741 return sizeof(iword);
742 }
743
744
745 /*
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 #include "tmp_sparc_tail.c"
761

  ViewVC Help
Powered by ViewVC 1.1.26