/[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 32 - (show annotations)
Mon Oct 8 16:20:58 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 19429 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1421 2006/11/06 05:32:37 debug Exp $
20060816	Adding a framework for emulated/virtual timers (src/timer.c),
		using only setitimer().
		Rewriting the mc146818 to use the new timer framework.
20060817	Adding a call to gettimeofday() every now and then (once every
		second, at the moment) to resynch the timer if it drifts.
		Beginning to convert the ISA timer interrupt mechanism (8253
		and 8259) to use the new timer framework.
		Removing the -I command line option.
20060819	Adding the -I command line option again, with new semantics.
		Working on Footbridge timer interrupts; NetBSD/NetWinder and
		NetBSD/CATS now run at correct speed, but unfortunately with
		HUGE delays during bootup.
20060821	Some minor m68k updates. Adding the first instruction: nop. :)
		Minor Alpha emulation updates.
20060822	Adding a FreeBSD development specific YAMON environment
		variable ("khz") (as suggested by Bruce M. Simpson).
		Moving YAMON environment variable initialization from
		machine_evbmips.c into promemul/yamon.c, and adding some more
		variables.
		Continuing on the LCA PCI bus controller (for Alpha machines).
20060823	Continuing on the timer stuff: experimenting with MIPS count/
		compare interrupts connected to the timer framework.
20060825	Adding bogus SCSI commands 0x51 (SCSICDROM_READ_DISCINFO) and
		0x52 (SCSICDROM_READ_TRACKINFO) to the SCSI emulation layer,
		to allow NetBSD/pmax 4.0_BETA to be installed from CDROM.
		Minor updates to the LCA PCI controller.
20060827	Implementing a CHIP8 cpu mode, and a corresponding CHIP8
		machine, for fun. Disassembly support for all instructions,
		and most of the common instructions have been implemented: mvi,
		mov_imm, add_imm, jmp, rand, cls, sprite, skeq_imm, jsr,
		skne_imm, bcd, rts, ldr, str, mov, or, and, xor, add, sub,
		font, ssound, sdelay, gdelay, bogus skup/skpr, skeq, skne.
20060828	Beginning to convert the CHIP8 cpu in the CHIP8 machine to a
		(more correct) RCA 180x cpu. (Disassembly for all 1802
		instructions has been implemented, but no execution yet, and
		no 1805 extended instructions.)
20060829	Minor Alpha emulation updates.
20060830	Beginning to experiment a little with PCI IDE for SGI O2.
		Fixing the cursor key mappings for MobilePro 770 emulation.
		Fixing the LK201 warning caused by recent NetBSD/pmax.
		The MIPS R41xx standby, suspend, and hibernate instructions now
		behave like the RM52xx/MIPS32/MIPS64 wait instruction.
		Fixing dev_wdc so it calculates correct (64-bit) offsets before
		giving them to diskimage_access().
20060831	Continuing on Alpha emulation (OSF1 PALcode).
20060901	Minor Alpha updates; beginning on virtual memory pagetables.
		Removed the limit for max nr of devices (in preparation for
		allowing devices' base addresses to be changed during runtime).
		Adding a hack for MIPS [d]mfc0 select 0 (except the count
		register), so that the coproc register is simply copied.
		The MIPS suspend instruction now exits the emulator, instead
		of being treated as a wait instruction (this causes NetBSD/
		hpcmips to get correct 'halt' behavior).
		The VR41xx RTC now returns correct time.
		Connecting the VR41xx timer to the timer framework (fixed at
		128 Hz, for now).
		Continuing on SPARC emulation, adding more instructions:
		restore, ba_xcc, ble. The rectangle drawing demo works :)
		Removing the last traces of the old ENABLE_CACHE_EMULATION
		MIPS stuff (not usable with dyntrans anyway).
20060902	Splitting up src/net.c into several smaller files in its own
		subdirectory (src/net/).
20060903	Cleanup of the files in src/net/, to make them less ugly.
20060904	Continuing on the 'settings' subsystem.
		Minor progress on the SPARC emulation mode.
20060905	Cleanup of various things, and connecting the settings
		infrastructure to various subsystems (emul, machine, cpu, etc).
		Changing the lk201 mouse update routine to not rely on any
		emulated hardware framebuffer cursor coordinates, but instead
		always do (semi-usable) relative movements.
20060906	Continuing on the lk201 mouse stuff. Mouse behaviour with
		multiple framebuffers (which was working in Ultrix) is now
		semi-broken (but it still works, in a way).
		Moving the documentation about networking into its own file
		(networking.html), and refreshing it a bit. Adding an example
		of how to use ethernet frame direct-access (udp_snoop).
20060907	Continuing on the settings infrastructure.
20060908	Minor updates to SH emulation: for 32-bit emulation: delay
		slots and the 'jsr @Rn' instruction. I'm putting 64-bit SH5 on
		ice, for now.
20060909-10	Implementing some more 32-bit SH instructions. Removing the
		64-bit mode completely. Enough has now been implemented to run
		the rectangle drawing demo. :-)
20060912	Adding more SH instructions.
20060916	Continuing on SH emulation (some more instructions: div0u,
		div1, rotcl/rotcr, more mov instructions, dt, braf, sets, sett,
		tst_imm, dmuls.l, subc, ldc_rm_vbr, movt, clrt, clrs, clrmac).
		Continuing on the settings subsystem (beginning on reading/
		writing settings, removing bugs, and connecting more cpus to
		the framework).
20060919	More work on SH emulation; adding an ldc banked instruction,
		and attaching a 640x480 framebuffer to the Dreamcast machine
		mode (NetBSD/dreamcast prints the NetBSD copyright banner :-),
		and then panics).
20060920	Continuing on the settings subsystem.
20060921	Fixing the Footbridge timer stuff so that NetBSD/cats and
		NetBSD/netwinder boot up without the delays.
20060922	Temporarily hardcoding MIPS timer interrupt to 100 Hz. With
		'wait' support disabled, NetBSD/malta and Linux/malta run at
		correct speed.
20060923	Connecting dev_gt to the timer framework, so that NetBSD/cobalt
		runs at correct speed.
		Moving SH4-specific memory mapped registers into its own
		device (dev_sh4.c).
		Running with -N now prints "idling" instead of bogus nr of
		instrs/second (which isn't valid anyway) while idling.
20060924	Algor emulation should now run at correct speed.
		Adding disassembly support for some MIPS64 revision 2
		instructions: ext, dext, dextm, dextu.
20060926	The timer framework now works also when the MIPS wait
		instruction is used.
20060928	Re-implementing checks for coprocessor availability for MIPS
		cop0 instructions. (Thanks to Carl van Schaik for noticing the
		lack of cop0 availability checks.)
20060929	Implementing an instruction combination hack which treats
		NetBSD/pmax' idle loop as a wait-like instruction.
20060930	The ENTRYHI_R_MASK was missing in (at least) memory_mips_v2p.c,
		causing TLB lookups to sometimes succeed when they should have
		failed. (A big thank you to Juli Mallett for noticing the
		problem.)
		Adding disassembly support for more MIPS64 revision 2 opcodes
		(seb, seh, wsbh, jalr.hb, jr.hb, synci, ins, dins, dinsu,
		dinsm, dsbh, dshd, ror, dror, rorv, drorv, dror32). Also
		implementing seb, seh, dsbh, dshd, and wsbh.
		Implementing an instruction combination hack for Linux/pmax'
		idle loop, similar to the NetBSD/pmax case.
20061001	Changing the NetBSD/sgimips install instructions to extract
		files from an iso image, instead of downloading them via ftp.
20061002	More-than-31-bit userland addresses in memory_mips_v2p.c were
		not actually working; applying a fix from Carl van Schaik to
		enable them to work + making some other updates (adding kuseg
		support).
		Fixing hpcmips (vr41xx) timer initialization.
		Experimenting with O(n)->O(1) reduction in the MIPS TLB lookup
		loop. Seems to work both for R3000 and non-R3000.
20061003	Continuing a little on SH emulation (adding more control
		registers; mini-cleanup of memory_sh.c).
20061004	Beginning on a dev_rtc, a clock/timer device for the test
		machines; also adding a demo, and some documentation.
		Fixing a bug in SH "mov.w @(disp,pc),Rn" (the result wasn't
		sign-extended), and adding the addc and ldtlb instructions.
20061005	Contining on SH emulation: virtual to physical address
		translation, and a skeleton exception mechanism.
20061006	Adding more SH instructions (various loads and stores, rte,
		negc, muls.w, various privileged register-move instructions).
20061007	More SH instructions: various move instructions, trapa, div0s,
		float, fdiv, ftrc.
		Continuing on dev_rtc; removing the rtc demo.
20061008	Adding a dummy Dreamcast PROM module. (Homebrew Dreamcast
		programs using KOS libs need this.)
		Adding more SH instructions: "stc vbr,rn", rotl, rotr, fsca,
		fmul, fadd, various floating-point moves, etc. A 256-byte
		demo for Dreamcast runs :-)
20061012	Adding the SH "lds Rm,pr" and bsr instructions.
20061013	More SH instructions: "sts fpscr,rn", tas.b, and some more
		floating point instructions, cmp/str, and more moves.
		Adding a dummy dev_pvr (Dreamcast graphics controller).
20061014	Generalizing the expression evaluator (used in the built-in
		debugger) to support parentheses and +-*/%^&|.
20061015	Removing the experimental tlb index hint code in
		mips_memory_v2p.c, since it didn't really have any effect.
20061017	Minor SH updates; adding the "sts pr,Rn", fcmp/gt, fneg,
		frchg, and some other instructions. Fixing missing sign-
		extension in an 8-bit load instruction.
20061019	Adding a simple dev_dreamcast_rtc.
		Implementing memory-mapped access to the SH ITLB/UTLB arrays.
20061021	Continuing on various SH and Dreamcast things: sh4 timers,
		debug messages for dev_pvr, fixing some virtual address
		translation bugs, adding the bsrf instruction.
		The NetBSD/dreamcast GENERIC_MD kernel now reaches userland :)
		Adding a dummy dev_dreamcast_asic.c (not really useful yet).
		Implementing simple support for Store Queues.
		Beginning on the PVR Tile Accelerator.
20061022	Generalizing the PVR framebuffer to support off-screen drawing,
		multiple bit-depths, etc. (A small speed penalty, but most
		likely worth it.)
		Adding more SH instructions (mulu.w, fcmp/eq, fsub, fmac,
		fschg, and some more); correcting bugs in "fsca" and "float".
20061024	Adding the SH ftrv (matrix * vector) instruction. Marcus
		Comstedt's "tatest" example runs :) (wireframe only).
		Correcting disassembly for SH floating point instructions that
		use the xd* registers.
		Adding the SH fsts instruction.
		In memory_device_dyntrans_access(), only the currently used
		range is now invalidated, and not the entire device range.
20061025	Adding a dummy AVR32 cpu mode skeleton.
20061026	Various Dreamcast updates; beginning on a Maple bus controller.
20061027	Continuing on the Maple bus. A bogus Controller, Keyboard, and
		Mouse can now be detected by NetBSD and KOS homebrew programs.
		Cleaning up the SH4 Timer Management Unit, and beginning on
		SH4 interrupts.
		Implementing the Dreamcast SYSASIC.
20061028	Continuing on the SYSASIC.
		Adding the SH fsqrt instruction.
		memory_sh.c now actually scans the ITLB.
		Fixing a bug in dev_sh4.c, related to associative writes into
		the memory-mapped UTLB array. NetBSD/dreamcast now reaches
		userland stably, and prints the "Terminal type?" message :-]
		Implementing enough of the Dreamcast keyboard to make NetBSD
		accept it for input.
		Enabling SuperH for stable (non-development) builds.
		Adding NetBSD/dreamcast to the documentation, although it
		doesn't support root-on-nfs yet.
20061029	Changing usleep(1) calls in the debugger to to usleep(10000)
		(according to Brian Foley, this makes GXemul run better on
		MacOS X).
		Making the Maple "Controller" do something (enough to barely
		interact with dcircus.elf).
20061030-31	Some progress on the PVR. More test programs start running (but
		with strange output).
		Various other SH4-related updates.
20061102	Various Dreamcast and SH4 updates; more KOS demos run now.
20061104	Adding a skeleton dev_mb8696x.c (the Dreamcast's LAN adapter).
20061105	Continuing on the MB8696x; NetBSD/dreamcast detects it as mbe0.
		Testing for the release.

==============  RELEASE 0.4.3  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26