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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 32 - (show annotations)
Mon Oct 8 16:20:58 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 40328 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_arm.c,v 1.64 2006/09/09 09:04:32 debug Exp $
29 *
30 * ARM CPU emulation.
31 *
32 *
33 * A good source of quick info on ARM instruction encoding:
34 *
35 * http://www.pinknoise.demon.co.uk/ARMinstrs/ARMinstrs.html
36 */
37
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <ctype.h>
42
43 #include "arm_cpu_types.h"
44 #include "cpu.h"
45 #include "machine.h"
46 #include "memory.h"
47 #include "misc.h"
48 #include "of.h"
49 #include "settings.h"
50 #include "symbol.h"
51
52 #define DYNTRANS_32
53 #include "tmp_arm_head.c"
54
55
56 /* ARM symbolic register names and condition strings: */
57 static char *arm_regname[N_ARM_REGS] = ARM_REG_NAMES;
58 static char *arm_condition_string[16] = ARM_CONDITION_STRINGS;
59
60 /* Data Processing Instructions: */
61 static char *arm_dpiname[16] = ARM_DPI_NAMES;
62 static int arm_dpi_uses_d[16] = { 1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1 };
63 static int arm_dpi_uses_n[16] = { 1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0 };
64
65 static int arm_exception_to_mode[N_ARM_EXCEPTIONS] = ARM_EXCEPTION_TO_MODE;
66
67 /* For quick_pc_to_pointers(): */
68 void arm_pc_to_pointers(struct cpu *cpu);
69 #include "quick_pc_to_pointers.h"
70
71
72 /*
73 * arm_cpu_new():
74 *
75 * Create a new ARM cpu object by filling the CPU struct.
76 * Return 1 on success, 0 if cpu_type_name isn't a valid ARM processor.
77 */
78 int arm_cpu_new(struct cpu *cpu, struct memory *mem,
79 struct machine *machine, int cpu_id, char *cpu_type_name)
80 {
81 int i, found;
82 struct arm_cpu_type_def cpu_type_defs[] = ARM_CPU_TYPE_DEFS;
83
84 /* Scan the list for this cpu type: */
85 i = 0; found = -1;
86 while (i >= 0 && cpu_type_defs[i].name != NULL) {
87 if (strcasecmp(cpu_type_defs[i].name, cpu_type_name) == 0) {
88 found = i;
89 break;
90 }
91 i++;
92 }
93 if (found == -1)
94 return 0;
95
96 cpu->run_instr = arm_run_instr;
97 cpu->memory_rw = arm_memory_rw;
98 cpu->update_translation_table = arm_update_translation_table;
99 cpu->invalidate_translation_caches =
100 arm_invalidate_translation_caches;
101 cpu->invalidate_code_translation = arm_invalidate_code_translation;
102 cpu->translate_v2p = arm_translate_v2p;
103
104 cpu->cd.arm.cpu_type = cpu_type_defs[found];
105 cpu->name = cpu->cd.arm.cpu_type.name;
106 cpu->is_32bit = 1;
107 cpu->byte_order = EMUL_LITTLE_ENDIAN;
108
109 cpu->cd.arm.cpsr = ARM_FLAG_I | ARM_FLAG_F;
110 cpu->cd.arm.control = ARM_CONTROL_PROG32 | ARM_CONTROL_DATA32
111 | ARM_CONTROL_CACHE | ARM_CONTROL_ICACHE | ARM_CONTROL_ALIGN;
112 /* TODO: default auxctrl contents */
113
114 if (cpu->machine->prom_emulation) {
115 cpu->cd.arm.cpsr |= ARM_MODE_SVC32;
116 cpu->cd.arm.control |= ARM_CONTROL_S;
117 } else {
118 cpu->cd.arm.cpsr |= ARM_MODE_SVC32;
119 cpu->cd.arm.control |= ARM_CONTROL_R;
120 }
121
122 /* Only show name and caches etc for CPU nr 0: */
123 if (cpu_id == 0) {
124 debug("%s", cpu->name);
125 if (cpu->cd.arm.cpu_type.icache_shift != 0 ||
126 cpu->cd.arm.cpu_type.dcache_shift != 0) {
127 int isize = cpu->cd.arm.cpu_type.icache_shift;
128 int dsize = cpu->cd.arm.cpu_type.dcache_shift;
129 if (isize != 0)
130 isize = 1 << (isize - 10);
131 if (dsize != 0)
132 dsize = 1 << (dsize - 10);
133 debug(" (I+D = %i+%i KB)", isize, dsize);
134 }
135 }
136
137 /* TODO: Some of these values (iway and dway) aren't used yet: */
138 cpu->cd.arm.cachetype =
139 (5 << ARM_CACHETYPE_CLASS_SHIFT)
140 | (1 << ARM_CACHETYPE_HARVARD_SHIFT)
141 | ((cpu->cd.arm.cpu_type.dcache_shift - 9) <<
142 ARM_CACHETYPE_DSIZE_SHIFT)
143 | (5 << ARM_CACHETYPE_DASSOC_SHIFT) /* 32-way */
144 | (2 << ARM_CACHETYPE_DLINE_SHIFT) /* 8 words/line */
145 | ((cpu->cd.arm.cpu_type.icache_shift - 9) <<
146 ARM_CACHETYPE_ISIZE_SHIFT)
147 | (5 << ARM_CACHETYPE_IASSOC_SHIFT) /* 32-way */
148 | (2 << ARM_CACHETYPE_ILINE_SHIFT); /* 8 words/line */
149
150 /* Coprocessor 15 = the system control coprocessor. */
151 cpu->cd.arm.coproc[15] = arm_coproc_15;
152
153 /* Coprocessor 14 for XScale: */
154 if (cpu->cd.arm.cpu_type.flags & ARM_XSCALE)
155 cpu->cd.arm.coproc[14] = arm_coproc_xscale_14;
156
157 /*
158 * NOTE/TODO: Ugly hack for OpenFirmware emulation:
159 */
160 if (cpu->machine->prom_emulation) {
161 cpu->cd.arm.of_emul_addr = cpu->machine->physical_ram_in_mb
162 * 1048576 - 8;
163 store_32bit_word(cpu, cpu->cd.arm.of_emul_addr, 0xef8c64be);
164 }
165
166 cpu->cd.arm.flags = cpu->cd.arm.cpsr >> 28;
167
168 CPU_SETTINGS_ADD_REGISTER64("pc", cpu->pc);
169 for (i=0; i<N_ARM_REGS - 1; i++)
170 CPU_SETTINGS_ADD_REGISTER32(arm_regname[i], cpu->cd.arm.r[i]);
171
172 return 1;
173 }
174
175
176 /*
177 * arm_setup_initial_translation_table():
178 *
179 * When booting kernels (such as OpenBSD or NetBSD) directly, it is assumed
180 * that the MMU is already enabled by the boot-loader. This function tries
181 * to emulate that.
182 */
183 void arm_setup_initial_translation_table(struct cpu *cpu, uint32_t ttb_addr)
184 {
185 unsigned char nothing[16384];
186 unsigned int i, j;
187
188 if (cpu->machine->userland_emul != NULL) {
189 fatal("arm_setup_initial_translation_table(): should not "
190 "be called for userland emulation!\n");
191 exit(1);
192 }
193
194 cpu->cd.arm.control |= ARM_CONTROL_MMU;
195 cpu->translate_v2p = arm_translate_v2p_mmu;
196 cpu->cd.arm.dacr |= 0x00000003;
197 cpu->cd.arm.ttb = ttb_addr;
198
199 memset(nothing, 0, sizeof(nothing));
200 cpu->memory_rw(cpu, cpu->mem, cpu->cd.arm.ttb, nothing,
201 sizeof(nothing), MEM_WRITE, PHYSICAL | NO_EXCEPTIONS);
202 for (i=0; i<256; i++)
203 for (j=0x0; j<=0xf; j++) {
204 unsigned char descr[4];
205 uint32_t addr = cpu->cd.arm.ttb +
206 (((j << 28) + (i << 20)) >> 18);
207 uint32_t d = (1048576*i) | 0xc02;
208
209 if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
210 descr[0] = d; descr[1] = d >> 8;
211 descr[2] = d >> 16; descr[3] = d >> 24;
212 } else {
213 descr[3] = d; descr[2] = d >> 8;
214 descr[1] = d >> 16; descr[0] = d >> 24;
215 }
216 cpu->memory_rw(cpu, cpu->mem, addr, &descr[0],
217 sizeof(descr), MEM_WRITE, PHYSICAL | NO_EXCEPTIONS);
218 }
219 }
220
221
222 /*
223 * arm_translation_table_set_l1():
224 */
225 void arm_translation_table_set_l1(struct cpu *cpu, uint32_t vaddr,
226 uint32_t paddr)
227 {
228 unsigned int i, j, vhigh = vaddr >> 28, phigh = paddr >> 28;
229
230 for (i=0; i<256; i++)
231 for (j=vhigh; j<=vhigh; j++) {
232 unsigned char descr[4];
233 uint32_t addr = cpu->cd.arm.ttb +
234 (((j << 28) + (i << 20)) >> 18);
235 uint32_t d = ((phigh << 28) + 1048576*i) | 0xc02;
236
237 if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
238 descr[0] = d; descr[1] = d >> 8;
239 descr[2] = d >> 16; descr[3] = d >> 24;
240 } else {
241 descr[3] = d; descr[2] = d >> 8;
242 descr[1] = d >> 16; descr[0] = d >> 24;
243 }
244 cpu->memory_rw(cpu, cpu->mem, addr, &descr[0],
245 sizeof(descr), MEM_WRITE, PHYSICAL | NO_EXCEPTIONS);
246 }
247 }
248
249
250 /*
251 * arm_translation_table_set_l1_b():
252 */
253 void arm_translation_table_set_l1_b(struct cpu *cpu, uint32_t vaddr,
254 uint32_t paddr)
255 {
256 unsigned int i, j, vhigh = vaddr >> 24, phigh = paddr >> 24;
257
258 for (i=0; i<16; i++)
259 for (j=vhigh; j<=vhigh; j++) {
260 unsigned char descr[4];
261 uint32_t addr = cpu->cd.arm.ttb +
262 (((j << 24) + (i << 20)) >> 18);
263 uint32_t d = ((phigh << 24) + 1048576*i) | 0xc02;
264
265 if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
266 descr[0] = d; descr[1] = d >> 8;
267 descr[2] = d >> 16; descr[3] = d >> 24;
268 } else {
269 descr[3] = d; descr[2] = d >> 8;
270 descr[1] = d >> 16; descr[0] = d >> 24;
271 }
272 cpu->memory_rw(cpu, cpu->mem, addr, &descr[0],
273 sizeof(descr), MEM_WRITE, PHYSICAL | NO_EXCEPTIONS);
274 }
275 }
276
277
278 /*
279 * arm_cpu_dumpinfo():
280 */
281 void arm_cpu_dumpinfo(struct cpu *cpu)
282 {
283 struct arm_cpu_type_def *ct = &cpu->cd.arm.cpu_type;
284
285 debug(" (I+D = %i+%i KB)\n",
286 (1 << ct->icache_shift) / 1024, (1 << ct->dcache_shift) / 1024);
287 }
288
289
290 /*
291 * arm_cpu_list_available_types():
292 *
293 * Print a list of available ARM CPU types.
294 */
295 void arm_cpu_list_available_types(void)
296 {
297 int i, j;
298 struct arm_cpu_type_def tdefs[] = ARM_CPU_TYPE_DEFS;
299
300 i = 0;
301 while (tdefs[i].name != NULL) {
302 debug("%s", tdefs[i].name);
303 for (j=13 - strlen(tdefs[i].name); j>0; j--)
304 debug(" ");
305 i++;
306 if ((i % 5) == 0 || tdefs[i].name == NULL)
307 debug("\n");
308 }
309 }
310
311
312 /*
313 * arm_cpu_register_dump():
314 *
315 * Dump cpu registers in a relatively readable format.
316 *
317 * gprs: set to non-zero to dump GPRs and some special-purpose registers.
318 * coprocs: set bit 0..3 to dump registers in coproc 0..3.
319 */
320 void arm_cpu_register_dump(struct cpu *cpu, int gprs, int coprocs)
321 {
322 char *symbol;
323 uint64_t offset;
324 int mode = cpu->cd.arm.cpsr & ARM_FLAG_MODE;
325 int i, x = cpu->cpu_id;
326
327 cpu->cd.arm.cpsr &= 0x0fffffff;
328 cpu->cd.arm.cpsr |= (cpu->cd.arm.flags << 28);
329
330 if (gprs) {
331 symbol = get_symbol_name(&cpu->machine->symbol_context,
332 cpu->pc, &offset);
333 debug("cpu%i: cpsr = ", x);
334 debug("%s%s%s%s%s%s",
335 (cpu->cd.arm.cpsr & ARM_FLAG_N)? "N" : "n",
336 (cpu->cd.arm.cpsr & ARM_FLAG_Z)? "Z" : "z",
337 (cpu->cd.arm.cpsr & ARM_FLAG_C)? "C" : "c",
338 (cpu->cd.arm.cpsr & ARM_FLAG_V)? "V" : "v",
339 (cpu->cd.arm.cpsr & ARM_FLAG_I)? "I" : "i",
340 (cpu->cd.arm.cpsr & ARM_FLAG_F)? "F" : "f");
341 if (mode < ARM_MODE_USR32)
342 debug(" pc = 0x%07x", (int)(cpu->pc & 0x03ffffff));
343 else
344 debug(" pc = 0x%08x", (int)cpu->pc);
345
346 debug(" <%s>\n", symbol != NULL? symbol : " no symbol ");
347
348 for (i=0; i<N_ARM_REGS; i++) {
349 if ((i % 4) == 0)
350 debug("cpu%i:", x);
351 if (i != ARM_PC)
352 debug(" %s = 0x%08x", arm_regname[i],
353 (int)cpu->cd.arm.r[i]);
354 if ((i % 4) == 3)
355 debug("\n");
356 }
357 }
358
359 if (coprocs & 1) {
360 int m = cpu->cd.arm.cpsr & ARM_FLAG_MODE;
361 debug("cpu%i: cpsr = 0x%08x (", x, cpu->cd.arm.cpsr);
362 switch (m) {
363 case ARM_MODE_USR32:
364 debug("USR32)\n"); break;
365 case ARM_MODE_SYS32:
366 debug("SYS32)\n"); break;
367 case ARM_MODE_FIQ32:
368 debug("FIQ32)\n"); break;
369 case ARM_MODE_IRQ32:
370 debug("IRQ32)\n"); break;
371 case ARM_MODE_SVC32:
372 debug("SVC32)\n"); break;
373 case ARM_MODE_ABT32:
374 debug("ABT32)\n"); break;
375 case ARM_MODE_UND32:
376 debug("UND32)\n"); break;
377 default:debug("unimplemented)\n");
378 }
379
380 if (m != ARM_MODE_USR32 && m != ARM_MODE_SYS32) {
381 debug("cpu%i: usr r8-14:", x);
382 for (i=0; i<7; i++)
383 debug(" %08x", cpu->cd.arm.default_r8_r14[i]);
384 debug("\n");
385 }
386
387 if (m != ARM_MODE_FIQ32) {
388 debug("cpu%i: fiq r8-14:", x);
389 for (i=0; i<7; i++)
390 debug(" %08x", cpu->cd.arm.fiq_r8_r14[i]);
391 debug("\n");
392 }
393
394 if (m != ARM_MODE_IRQ32) {
395 debug("cpu%i: irq r13-14:", x);
396 for (i=0; i<2; i++)
397 debug(" %08x", cpu->cd.arm.irq_r13_r14[i]);
398 debug("\n");
399 }
400
401 if (m != ARM_MODE_SVC32) {
402 debug("cpu%i: svc r13-14:", x);
403 for (i=0; i<2; i++)
404 debug(" %08x", cpu->cd.arm.svc_r13_r14[i]);
405 debug("\n");
406 }
407
408 if (m != ARM_MODE_ABT32) {
409 debug("cpu%i: abt r13-14:", x);
410 for (i=0; i<2; i++)
411 debug(" %08x", cpu->cd.arm.abt_r13_r14[i]);
412 debug("\n");
413 }
414
415 if (m != ARM_MODE_UND32) {
416 debug("cpu%i: und r13-14:", x);
417 for (i=0; i<2; i++)
418 debug(" %08x", cpu->cd.arm.und_r13_r14[i]);
419 debug("\n");
420 }
421 }
422
423 if (coprocs & 2) {
424 debug("cpu%i: control = 0x%08x\n", x, cpu->cd.arm.control);
425 debug("cpu%i: MMU: %s\n", x,
426 cpu->cd.arm.control &
427 ARM_CONTROL_MMU? "enabled" : "disabled");
428 debug("cpu%i: alignment checks: %s\n", x,
429 cpu->cd.arm.control &
430 ARM_CONTROL_ALIGN? "enabled" : "disabled");
431 debug("cpu%i: [data] cache: %s\n", x,
432 cpu->cd.arm.control &
433 ARM_CONTROL_CACHE? "enabled" : "disabled");
434 debug("cpu%i: instruction cache: %s\n", x,
435 cpu->cd.arm.control &
436 ARM_CONTROL_ICACHE? "enabled" : "disabled");
437 debug("cpu%i: write buffer: %s\n", x,
438 cpu->cd.arm.control &
439 ARM_CONTROL_WBUFFER? "enabled" : "disabled");
440 debug("cpu%i: prog32: %s\n", x,
441 cpu->cd.arm.control &
442 ARM_CONTROL_PROG32? "yes" : "no (using prog26)");
443 debug("cpu%i: data32: %s\n", x,
444 cpu->cd.arm.control &
445 ARM_CONTROL_DATA32? "yes" : "no (using data26)");
446 debug("cpu%i: endianness: %s\n", x,
447 cpu->cd.arm.control &
448 ARM_CONTROL_BIG? "big endian" : "little endian");
449 debug("cpu%i: high vectors: %s\n", x,
450 cpu->cd.arm.control &
451 ARM_CONTROL_V? "yes (0xffff0000)" : "no");
452
453 /* TODO: auxctrl on which CPU types? */
454 if (cpu->cd.arm.cpu_type.flags & ARM_XSCALE) {
455 debug("cpu%i: auxctrl = 0x%08x\n", x,
456 cpu->cd.arm.auxctrl);
457 debug("cpu%i: minidata cache attr = 0x%x\n", x,
458 (cpu->cd.arm.auxctrl & ARM_AUXCTRL_MD)
459 >> ARM_AUXCTRL_MD_SHIFT);
460 debug("cpu%i: page table memory attr: %i\n", x,
461 (cpu->cd.arm.auxctrl & ARM_AUXCTRL_P)? 1 : 0);
462 debug("cpu%i: write buffer coalescing: %s\n", x,
463 (cpu->cd.arm.auxctrl & ARM_AUXCTRL_K)?
464 "disabled" : "enabled");
465 }
466
467 debug("cpu%i: ttb = 0x%08x dacr = 0x%08x\n", x,
468 cpu->cd.arm.ttb, cpu->cd.arm.dacr);
469 debug("cpu%i: fsr = 0x%08x far = 0x%08x\n", x,
470 cpu->cd.arm.fsr, cpu->cd.arm.far);
471 }
472 }
473
474
475 /*
476 * arm_save_register_bank():
477 */
478 void arm_save_register_bank(struct cpu *cpu)
479 {
480 /* Save away current registers: */
481 switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) {
482 case ARM_MODE_USR32:
483 case ARM_MODE_SYS32:
484 memcpy(cpu->cd.arm.default_r8_r14,
485 &cpu->cd.arm.r[8], sizeof(uint32_t) * 7);
486 break;
487 case ARM_MODE_FIQ32:
488 memcpy(cpu->cd.arm.fiq_r8_r14,
489 &cpu->cd.arm.r[8], sizeof(uint32_t) * 7);
490 break;
491 case ARM_MODE_IRQ32:
492 memcpy(cpu->cd.arm.default_r8_r14,
493 &cpu->cd.arm.r[8], sizeof(uint32_t) * 5);
494 cpu->cd.arm.irq_r13_r14[0] = cpu->cd.arm.r[13];
495 cpu->cd.arm.irq_r13_r14[1] = cpu->cd.arm.r[14];
496 break;
497 case ARM_MODE_SVC32:
498 memcpy(cpu->cd.arm.default_r8_r14,
499 &cpu->cd.arm.r[8], sizeof(uint32_t) * 5);
500 cpu->cd.arm.svc_r13_r14[0] = cpu->cd.arm.r[13];
501 cpu->cd.arm.svc_r13_r14[1] = cpu->cd.arm.r[14];
502 break;
503 case ARM_MODE_ABT32:
504 memcpy(cpu->cd.arm.default_r8_r14,
505 &cpu->cd.arm.r[8], sizeof(uint32_t) * 5);
506 cpu->cd.arm.abt_r13_r14[0] = cpu->cd.arm.r[13];
507 cpu->cd.arm.abt_r13_r14[1] = cpu->cd.arm.r[14];
508 break;
509 case ARM_MODE_UND32:
510 memcpy(cpu->cd.arm.default_r8_r14,
511 &cpu->cd.arm.r[8], sizeof(uint32_t) * 5);
512 cpu->cd.arm.und_r13_r14[0] = cpu->cd.arm.r[13];
513 cpu->cd.arm.und_r13_r14[1] = cpu->cd.arm.r[14];
514 break;
515 default:fatal("arm_save_register_bank: unimplemented mode %i\n",
516 cpu->cd.arm.cpsr & ARM_FLAG_MODE);
517 exit(1);
518 }
519 }
520
521
522 /*
523 * arm_load_register_bank():
524 */
525 void arm_load_register_bank(struct cpu *cpu)
526 {
527 /* Load new registers: */
528 switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) {
529 case ARM_MODE_USR32:
530 case ARM_MODE_SYS32:
531 memcpy(&cpu->cd.arm.r[8],
532 cpu->cd.arm.default_r8_r14, sizeof(uint32_t) * 7);
533 break;
534 case ARM_MODE_FIQ32:
535 memcpy(&cpu->cd.arm.r[8], cpu->cd.arm.fiq_r8_r14,
536 sizeof(uint32_t) * 7);
537 break;
538 case ARM_MODE_IRQ32:
539 memcpy(&cpu->cd.arm.r[8],
540 cpu->cd.arm.default_r8_r14, sizeof(uint32_t) * 5);
541 cpu->cd.arm.r[13] = cpu->cd.arm.irq_r13_r14[0];
542 cpu->cd.arm.r[14] = cpu->cd.arm.irq_r13_r14[1];
543 break;
544 case ARM_MODE_SVC32:
545 memcpy(&cpu->cd.arm.r[8],
546 cpu->cd.arm.default_r8_r14, sizeof(uint32_t) * 5);
547 cpu->cd.arm.r[13] = cpu->cd.arm.svc_r13_r14[0];
548 cpu->cd.arm.r[14] = cpu->cd.arm.svc_r13_r14[1];
549 break;
550 case ARM_MODE_ABT32:
551 memcpy(&cpu->cd.arm.r[8],
552 cpu->cd.arm.default_r8_r14, sizeof(uint32_t) * 5);
553 cpu->cd.arm.r[13] = cpu->cd.arm.abt_r13_r14[0];
554 cpu->cd.arm.r[14] = cpu->cd.arm.abt_r13_r14[1];
555 break;
556 case ARM_MODE_UND32:
557 memcpy(&cpu->cd.arm.r[8],
558 cpu->cd.arm.default_r8_r14, sizeof(uint32_t) * 5);
559 cpu->cd.arm.r[13] = cpu->cd.arm.und_r13_r14[0];
560 cpu->cd.arm.r[14] = cpu->cd.arm.und_r13_r14[1];
561 break;
562 default:fatal("arm_load_register_bank: unimplemented mode %i\n",
563 cpu->cd.arm.cpsr & ARM_FLAG_MODE);
564 exit(1);
565 }
566 }
567
568
569 /*
570 * arm_exception():
571 */
572 void arm_exception(struct cpu *cpu, int exception_nr)
573 {
574 int oldmode, newmode;
575 uint32_t retaddr;
576
577 if (exception_nr < 0 || exception_nr >= N_ARM_EXCEPTIONS) {
578 fatal("arm_exception(): exception_nr = %i\n", exception_nr);
579 exit(1);
580 }
581
582 retaddr = cpu->pc;
583
584 if (!quiet_mode) {
585 debug("[ arm_exception(): ");
586 switch (exception_nr) {
587 case ARM_EXCEPTION_RESET:
588 fatal("RESET: TODO");
589 break;
590 case ARM_EXCEPTION_UND:
591 debug("UNDEFINED");
592 break;
593 case ARM_EXCEPTION_SWI:
594 debug("SWI");
595 break;
596 case ARM_EXCEPTION_PREF_ABT:
597 debug("PREFETCH ABORT");
598 break;
599 case ARM_EXCEPTION_IRQ:
600 debug("IRQ");
601 break;
602 case ARM_EXCEPTION_FIQ:
603 debug("FIQ");
604 break;
605 case ARM_EXCEPTION_DATA_ABT:
606 debug("DATA ABORT, far=0x%08x fsr=0x%02x",
607 cpu->cd.arm.far, cpu->cd.arm.fsr);
608 break;
609 }
610 debug(" ]\n");
611 }
612
613 switch (exception_nr) {
614 case ARM_EXCEPTION_RESET:
615 cpu->running = 0;
616 fatal("ARM RESET: TODO");
617 exit(1);
618 case ARM_EXCEPTION_DATA_ABT:
619 retaddr += 4;
620 break;
621 }
622
623 retaddr += 4;
624
625 arm_save_register_bank(cpu);
626
627 cpu->cd.arm.cpsr &= 0x0fffffff;
628 cpu->cd.arm.cpsr |= (cpu->cd.arm.flags << 28);
629
630 switch (arm_exception_to_mode[exception_nr]) {
631 case ARM_MODE_SVC32:
632 cpu->cd.arm.spsr_svc = cpu->cd.arm.cpsr; break;
633 case ARM_MODE_ABT32:
634 cpu->cd.arm.spsr_abt = cpu->cd.arm.cpsr; break;
635 case ARM_MODE_UND32:
636 cpu->cd.arm.spsr_und = cpu->cd.arm.cpsr; break;
637 case ARM_MODE_IRQ32:
638 cpu->cd.arm.spsr_irq = cpu->cd.arm.cpsr; break;
639 case ARM_MODE_FIQ32:
640 cpu->cd.arm.spsr_fiq = cpu->cd.arm.cpsr; break;
641 default:fatal("arm_exception(): unimplemented exception nr\n");
642 exit(1);
643 }
644
645 /*
646 * Disable Thumb mode (because exception handlers always execute
647 * in ARM mode), set the exception mode, and disable interrupts:
648 */
649 cpu->cd.arm.cpsr &= ~ARM_FLAG_T;
650
651 oldmode = cpu->cd.arm.cpsr & ARM_FLAG_MODE;
652
653 cpu->cd.arm.cpsr &= ~ARM_FLAG_MODE;
654 cpu->cd.arm.cpsr |= arm_exception_to_mode[exception_nr];
655
656 /*
657 * Usually, an exception should change modes (so that saved status
658 * bits don't get lost). However, Linux on ARM seems to use floating
659 * point instructions in the kernel (!), and it emulates those using
660 * its own fp emulation code. This leads to a situation where we
661 * sometimes change from SVC32 to SVC32.
662 */
663 newmode = cpu->cd.arm.cpsr & ARM_FLAG_MODE;
664 if (oldmode == newmode && oldmode != ARM_MODE_SVC32) {
665 fatal("[ WARNING! Exception caused no mode change? "
666 "mode 0x%02x (pc=0x%x) ]\n", newmode, (int)cpu->pc);
667 /* exit(1); */
668 }
669
670 cpu->cd.arm.cpsr |= ARM_FLAG_I;
671 if (exception_nr == ARM_EXCEPTION_RESET ||
672 exception_nr == ARM_EXCEPTION_FIQ)
673 cpu->cd.arm.cpsr |= ARM_FLAG_F;
674
675 /* Load the new register bank, if we switched: */
676 arm_load_register_bank(cpu);
677
678 /*
679 * Set the return address and new PC.
680 *
681 * NOTE: r[ARM_PC] is also set; see cpu_arm_instr_loadstore.c for
682 * details. (If an exception occurs during a load into the pc
683 * register, the code in that file assumes that the r[ARM_PC]
684 * was changed to the address of the exception handler.)
685 */
686 cpu->cd.arm.r[ARM_LR] = retaddr;
687 cpu->pc = cpu->cd.arm.r[ARM_PC] = exception_nr * 4 +
688 ((cpu->cd.arm.control & ARM_CONTROL_V)? 0xffff0000 : 0);
689 quick_pc_to_pointers(cpu);
690 }
691
692
693 /*
694 * arm_cpu_tlbdump():
695 *
696 * Called from the debugger to dump the TLB in a readable format.
697 * x is the cpu number to dump, or -1 to dump all CPUs.
698 *
699 * If rawflag is nonzero, then the TLB contents isn't formated nicely,
700 * just dumped.
701 */
702 void arm_cpu_tlbdump(struct machine *m, int x, int rawflag)
703 {
704 }
705
706
707 static void add_response_word(struct cpu *cpu, char *r, uint32_t value,
708 size_t maxlen)
709 {
710 if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
711 value = ((value & 0xff) << 24) +
712 ((value & 0xff00) << 8) +
713 ((value & 0xff0000) >> 8) +
714 ((value & 0xff000000) >> 24);
715 }
716 snprintf(r + strlen(r), maxlen - strlen(r), "%08"PRIx32, value);
717 }
718
719
720 /*
721 * arm_cpu_gdb_stub():
722 *
723 * Execute a "remote GDB" command. Returns a newly allocated response string
724 * on success, NULL on failure.
725 */
726 char *arm_cpu_gdb_stub(struct cpu *cpu, char *cmd)
727 {
728 if (strcmp(cmd, "g") == 0) {
729 /* 15 gprs, pc, 8 fprs, fps, cpsr. */
730 int i;
731 char *r;
732 size_t len = 1 + 18 * sizeof(uint32_t);
733 r = malloc(len);
734 if (r == NULL) {
735 fprintf(stderr, "out of memory\n");
736 exit(1);
737 }
738 r[0] = '\0';
739 for (i=0; i<15; i++)
740 add_response_word(cpu, r, cpu->cd.arm.r[i], len);
741 add_response_word(cpu, r, cpu->pc, len);
742 /* TODO: fprs: */
743 for (i=0; i<8; i++)
744 add_response_word(cpu, r, 0, len);
745 /* TODO: fps */
746 add_response_word(cpu, r, 0, len);
747 add_response_word(cpu, r, cpu->cd.arm.cpsr, len);
748 return r;
749 }
750
751 if (cmd[0] == 'p') {
752 int regnr = strtol(cmd + 1, NULL, 16);
753 size_t len = 2 * sizeof(uint32_t) + 1;
754 char *r = malloc(len);
755 r[0] = '\0';
756 if (regnr == ARM_PC) {
757 add_response_word(cpu, r, cpu->pc, len);
758 } else if (regnr >= 0 && regnr < ARM_PC) {
759 add_response_word(cpu, r, cpu->cd.arm.r[regnr], len);
760 } else if (regnr >= 0x10 && regnr <= 0x17) {
761 /* TODO: fprs */
762 add_response_word(cpu, r, 0, len);
763 add_response_word(cpu, r, 0, len);
764 add_response_word(cpu, r, 0, len);
765 } else if (regnr == 0x18) {
766 /* TODO: fps */
767 add_response_word(cpu, r, 0, len);
768 } else if (regnr == 0x19) {
769 add_response_word(cpu, r, cpu->cd.arm.cpsr, len);
770 }
771 return r;
772 }
773
774 fatal("arm_cpu_gdb_stub(): TODO\n");
775 return NULL;
776 }
777
778
779 /*
780 * arm_cpu_interrupt():
781 *
782 * 0..31 are used as footbridge interrupt numbers, 32..47 = ISA,
783 * 64 is used as a "re-assert" signal to cpu->machine->md_interrupt().
784 *
785 * TODO: don't hardcode to footbridge!
786 */
787 int arm_cpu_interrupt(struct cpu *cpu, uint64_t irq_nr)
788 {
789 /* fatal("arm_cpu_interrupt(): 0x%x\n", (int)irq_nr); */
790 if (irq_nr <= 64) {
791 if (cpu->machine->md_interrupt != NULL)
792 cpu->machine->md_interrupt(cpu->machine,
793 cpu, irq_nr, 1);
794 else
795 fatal("arm_cpu_interrupt(): irq_nr=%i md_interrupt =="
796 " NULL\n", (int)irq_nr);
797 } else {
798 /* Assert ARM IRQs: */
799 cpu->cd.arm.irq_asserted = 1;
800 }
801
802 return 1;
803 }
804
805
806 /*
807 * arm_cpu_interrupt_ack():
808 */
809 int arm_cpu_interrupt_ack(struct cpu *cpu, uint64_t irq_nr)
810 {
811 if (irq_nr <= 64) {
812 if (cpu->machine->md_interrupt != NULL)
813 cpu->machine->md_interrupt(cpu->machine,
814 cpu, irq_nr, 0);
815 } else {
816 /* De-assert ARM IRQs: */
817 cpu->cd.arm.irq_asserted = 0;
818 }
819
820 return 1;
821 }
822
823
824 /*
825 * arm_cpu_disassemble_instr():
826 *
827 * Convert an instruction word into human readable format, for instruction
828 * tracing.
829 *
830 * If running is 1, cpu->pc should be the address of the instruction.
831 *
832 * If running is 0, things that depend on the runtime environment (eg.
833 * register contents) will not be shown, and addr will be used instead of
834 * cpu->pc for relative addresses.
835 */
836 int arm_cpu_disassemble_instr(struct cpu *cpu, unsigned char *ib,
837 int running, uint64_t dumpaddr)
838 {
839 uint32_t iw, tmp;
840 int main_opcode, secondary_opcode, s_bit, r16, r12, r8;
841 int i, n, p_bit, u_bit, b_bit, w_bit, l_bit;
842 char *symbol, *condition;
843 uint64_t offset;
844
845 if (running)
846 dumpaddr = cpu->pc;
847
848 symbol = get_symbol_name(&cpu->machine->symbol_context,
849 dumpaddr, &offset);
850 if (symbol != NULL && offset == 0)
851 debug("<%s>\n", symbol);
852
853 if (cpu->machine->ncpus > 1 && running)
854 debug("cpu%i:\t", cpu->cpu_id);
855
856 debug("%08x: ", (int)dumpaddr);
857
858 if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
859 iw = ib[0] + (ib[1]<<8) + (ib[2]<<16) + (ib[3]<<24);
860 else
861 iw = ib[3] + (ib[2]<<8) + (ib[1]<<16) + (ib[0]<<24);
862 debug("%08x\t", (int)iw);
863
864 condition = arm_condition_string[iw >> 28];
865 main_opcode = (iw >> 24) & 15;
866 secondary_opcode = (iw >> 21) & 15;
867 u_bit = (iw >> 23) & 1;
868 b_bit = (iw >> 22) & 1;
869 w_bit = (iw >> 21) & 1;
870 s_bit = l_bit = (iw >> 20) & 1;
871 r16 = (iw >> 16) & 15;
872 r12 = (iw >> 12) & 15;
873 r8 = (iw >> 8) & 15;
874
875 switch (main_opcode) {
876 case 0x0:
877 case 0x1:
878 case 0x2:
879 case 0x3:
880 /*
881 * Special cases first:
882 */
883
884 /*
885 * Multiplication:
886 * xxxx0000 00ASdddd nnnnssss 1001mmmm (Rd, Rm, Rs [,Rn])
887 */
888 if ((iw & 0x0fc000f0) == 0x00000090) {
889 int a_bit = (iw >> 21) & 1;
890 debug("%s%s%s\t", a_bit? "mla" : "mul",
891 condition, s_bit? "s" : "");
892 debug("%s,", arm_regname[r16]);
893 debug("%s,", arm_regname[iw & 15]);
894 debug("%s", arm_regname[r8]);
895 if (a_bit)
896 debug(",%s", arm_regname[r12]);
897 debug("\n");
898 break;
899 }
900
901 /*
902 * Long multiplication:
903 * xxxx0000 1UAShhhh llllssss 1001mmmm (Rl,Rh,Rm,Rs)
904 */
905 if ((iw & 0x0f8000f0) == 0x00800090) {
906 int u_bit = (iw >> 22) & 1;
907 int a_bit = (iw >> 21) & 1;
908 debug("%s%sl%s%s\t", u_bit? "s" : "u",
909 a_bit? "mla" : "mul", condition, s_bit? "s" : "");
910 debug("%s,%s,", arm_regname[r12], arm_regname[r16]);
911 debug("%s,%s\n", arm_regname[iw&15], arm_regname[r8]);
912 break;
913 }
914
915 /*
916 * xxxx0001 0000nnnn dddd0000 0101mmmm qadd Rd,Rm,Rn
917 * xxxx0001 0010nnnn dddd0000 0101mmmm qsub Rd,Rm,Rn
918 * xxxx0001 0100nnnn dddd0000 0101mmmm qdadd Rd,Rm,Rn
919 * xxxx0001 0110nnnn dddd0000 0101mmmm qdsub Rd,Rm,Rn
920 */
921 if ((iw & 0x0f900ff0) == 0x01000050) {
922 debug("q%s%s%s\t", iw & 0x400000? "d" : "",
923 iw & 0x200000? "sub" : "add", condition);
924 debug("%s,%s,%s\n", arm_regname[r12],
925 arm_regname[iw&15], arm_regname[r16]);
926 break;
927 }
928
929 /*
930 * xxxx0001 0010.... ........ 00L1mmmm bx/blx rm
931 */
932 if ((iw & 0x0ff000d0) == 0x01200010) {
933 int l_bit = iw & 0x20;
934 debug("b%sx%s\t%s\n", l_bit? "l" : "", condition,
935 arm_regname[iw & 15]);
936 break;
937 }
938
939 /*
940 * xxxx0001 0s10aaaa 11110000 0000mmmm MSR Regform
941 * xxxx0011 0s10aaaa 1111rrrr bbbbbbbb MSR Immform
942 * xxxx0001 0s001111 dddd0000 00000000 MRS
943 */
944 if ((iw & 0x0fb0fff0) == 0x0120f000 ||
945 (iw & 0x0fb0f000) == 0x0320f000) {
946 int a = (iw >> 16) & 15;
947 debug("msr%s\t%s", condition, (iw&0x400000)? "S":"C");
948 debug("PSR_");
949 switch (a) {
950 case 1: debug("ctl"); break;
951 case 8: debug("flg"); break;
952 case 9: debug("all"); break;
953 default:debug(" UNIMPLEMENTED (a=%i)", a);
954 }
955 if (iw & 0x02000000) {
956 int r = (iw >> 7) & 30;
957 uint32_t b = iw & 0xff;
958 while (r-- > 0)
959 b = (b >> 1) | ((b & 1) << 31);
960 debug(",#0x%x\n", b);
961 } else
962 debug(",%s\n", arm_regname[iw & 15]);
963 break;
964 }
965 if ((iw & 0x0fbf0fff) == 0x010f0000) {
966 debug("mrs%s\t", condition);
967 debug("%s,%sPSR\n", arm_regname[r12],
968 (iw&0x400000)? "S":"C");
969 break;
970 }
971
972 /*
973 * xxxx0001 0B00nnnn dddd0000 1001mmmm SWP Rd,Rm,[Rn]
974 */
975 if ((iw & 0x0fb00ff0) == 0x01000090) {
976 debug("swp%s%s\t", condition, (iw&0x400000)? "b":"");
977 debug("%s,%s,[%s]\n", arm_regname[r12],
978 arm_regname[iw & 15], arm_regname[r16]);
979 break;
980 }
981
982 /*
983 * xxxx0001 01101111 dddd1111 0001mmmm CLZ Rd,Rm
984 */
985 if ((iw & 0x0fff0ff0) == 0x016f0f10) {
986 debug("clz%s\t", condition);
987 debug("%s,%s\n", arm_regname[r12], arm_regname[iw&15]);
988 break;
989 }
990
991 /*
992 * xxxx0001 0000dddd nnnnssss 1yx0mmmm SMLAxy Rd,Rm,Rs,Rn
993 * xxxx0001 0100dddd DDDDssss 1yx0mmmm SMLALxy RdL,RdH,Rm,Rs
994 * xxxx0001 0010dddd nnnnssss 1y00mmmm SMLAWy Rd,Rm,Rs,Rn
995 * xxxx0001 0110dddd 0000ssss 1yx0mmmm SMULxy Rd,Rm,Rs
996 * xxxx0001 0010dddd 0000ssss 1y10mmmm SMULWy Rd,Rm,Rs
997 */
998 if ((iw & 0x0ff00090) == 0x01000080) {
999 debug("smla%s%s%s\t",
1000 iw & 0x20? "t" : "b", iw & 0x40? "t" : "b",
1001 condition);
1002 debug("%s,%s,%s,%s\n", arm_regname[r16],
1003 arm_regname[iw&15], arm_regname[r8],
1004 arm_regname[r12]);
1005 break;
1006 }
1007 if ((iw & 0x0ff00090) == 0x01400080) {
1008 debug("smlal%s%s%s\t",
1009 iw & 0x20? "t" : "b", iw & 0x40? "t" : "b",
1010 condition);
1011 debug("%s,%s,%s,%s\n", arm_regname[r12],
1012 arm_regname[r16], arm_regname[iw&15],
1013 arm_regname[r8]);
1014 break;
1015 }
1016 if ((iw & 0x0ff000b0) == 0x01200080) {
1017 debug("smlaw%s%s\t", iw & 0x40? "t" : "b",
1018 condition);
1019 debug("%s,%s,%s,%s\n", arm_regname[r16],
1020 arm_regname[iw&15], arm_regname[r8],
1021 arm_regname[r12]);
1022 break;
1023 }
1024 if ((iw & 0x0ff0f090) == 0x01600080) {
1025 debug("smul%s%s%s\t",
1026 iw & 0x20? "t" : "b", iw & 0x40? "t" : "b",
1027 condition);
1028 debug("%s,%s,%s\n", arm_regname[r16],
1029 arm_regname[iw&15], arm_regname[r8]);
1030 break;
1031 }
1032 if ((iw & 0x0ff0f0b0) == 0x012000a0) {
1033 debug("smulw%s%s\t", iw & 0x40? "t" : "b",
1034 condition);
1035 debug("%s,%s,%s\n", arm_regname[r16],
1036 arm_regname[iw&15], arm_regname[r8]);
1037 break;
1038 }
1039
1040 /*
1041 * xxxx000P U1WLnnnn ddddHHHH 1SH1LLLL load/store rd,imm(rn)
1042 */
1043 if ((iw & 0x0e000090) == 0x00000090) {
1044 char *op = "st";
1045 int imm = ((iw >> 4) & 0xf0) | (iw & 0xf);
1046 int regform = !(iw & 0x00400000);
1047 p_bit = main_opcode & 1;
1048 /*
1049 * TODO: detect some illegal variants:
1050 * signed store, or unsigned byte load/store
1051 */
1052 if (!l_bit && (iw & 0xd0) == 0xd0 && (r12 & 1)) {
1053 debug("TODO: r12 odd, not load/store\n");
1054 break;
1055 }
1056 /* Semi-generic case: */
1057 if (iw & 0x00100000)
1058 op = "ld";
1059 if (!l_bit && (iw & 0xd0) == 0xd0)
1060 op = iw & 0x20? "st" : "ld";
1061 debug("%sr%s", op, condition);
1062 if (!l_bit && (iw & 0xd0) == 0xd0) {
1063 debug("d"); /* Double-register */
1064 } else {
1065 if (iw & 0x40)
1066 debug("s"); /* signed */
1067 if (iw & 0x20)
1068 debug("h"); /* half-word */
1069 else
1070 debug("b"); /* byte */
1071 }
1072 debug("\t%s,[%s", arm_regname[r12], arm_regname[r16]);
1073 if (p_bit) {
1074 /* Pre-index: */
1075 if (regform)
1076 debug(",%s%s", u_bit? "" : "-",
1077 arm_regname[iw & 15]);
1078 else {
1079 if (imm != 0)
1080 debug(",#%s%i", u_bit? "" : "-",
1081 imm);
1082 }
1083 debug("]%s\n", w_bit? "!" : "");
1084 } else {
1085 /* Post-index: */
1086 debug("],");
1087 if (regform)
1088 debug("%s%s\n", u_bit? "" : "-",
1089 arm_regname[iw & 15]);
1090 else
1091 debug("#%s%i\n", u_bit? "" : "-", imm);
1092 }
1093 break;
1094 }
1095
1096 /* Other special cases: */
1097 if (iw & 0x80 && !(main_opcode & 2) && iw & 0x10) {
1098 debug("UNIMPLEMENTED reg (c!=0), t odd\n");
1099 break;
1100 }
1101
1102 /*
1103 * Generic Data Processing Instructions:
1104 *
1105 * xxxx000a aaaSnnnn ddddcccc ctttmmmm Register form
1106 * xxxx001a aaaSnnnn ddddrrrr bbbbbbbb Immediate form
1107 */
1108
1109 debug("%s%s%s\t", arm_dpiname[secondary_opcode],
1110 condition, s_bit? "s" : "");
1111 if (arm_dpi_uses_d[secondary_opcode])
1112 debug("%s,", arm_regname[r12]);
1113 if (arm_dpi_uses_n[secondary_opcode])
1114 debug("%s,", arm_regname[r16]);
1115
1116 if (main_opcode & 2) {
1117 /* Immediate form: */
1118 int r = (iw >> 7) & 30;
1119 uint32_t b = iw & 0xff;
1120 while (r-- > 0)
1121 b = (b >> 1) | ((b & 1) << 31);
1122 if (b < 15)
1123 debug("#%i", b);
1124 else
1125 debug("#0x%x", b);
1126 } else {
1127 /* Register form: */
1128 int t = (iw >> 4) & 7;
1129 int c = (iw >> 7) & 31;
1130 debug("%s", arm_regname[iw & 15]);
1131 switch (t) {
1132 case 0: if (c != 0)
1133 debug(", lsl #%i", c);
1134 break;
1135 case 1: debug(", lsl %s", arm_regname[c >> 1]);
1136 break;
1137 case 2: debug(", lsr #%i", c? c : 32);
1138 break;
1139 case 3: debug(", lsr %s", arm_regname[c >> 1]);
1140 break;
1141 case 4: debug(", asr #%i", c? c : 32);
1142 break;
1143 case 5: debug(", asr %s", arm_regname[c >> 1]);
1144 break;
1145 case 6: if (c != 0)
1146 debug(", ror #%i", c);
1147 else
1148 debug(", rrx");
1149 break;
1150 case 7: debug(", ror %s", arm_regname[c >> 1]);
1151 break;
1152 }
1153
1154 /* mov pc,reg: */
1155 if (running && t == 0 && c == 0 && secondary_opcode
1156 == 0xd && r12 == ARM_PC && (iw&15)!=ARM_PC) {
1157 symbol = get_symbol_name(&cpu->machine->
1158 symbol_context, cpu->cd.arm.r[iw & 15],
1159 &offset);
1160 if (symbol != NULL)
1161 debug(" \t<%s>", symbol);
1162 }
1163 }
1164 debug("\n");
1165 break;
1166 case 0x4: /* Single Data Transfer */
1167 case 0x5:
1168 case 0x6:
1169 case 0x7:
1170 /* Special case first: */
1171 if ((iw & 0xfc70f000) == 0xf450f000) {
1172 /* Preload: */
1173 debug("pld\t[%s]\n", arm_regname[r16]);
1174 break;
1175 }
1176
1177 /*
1178 * xxxx010P UBWLnnnn ddddoooo oooooooo Immediate form
1179 * xxxx011P UBWLnnnn ddddcccc ctt0mmmm Register form
1180 */
1181 p_bit = main_opcode & 1;
1182 if (main_opcode >= 6 && iw & 0x10) {
1183 debug("TODO: single data transf. but 0x10\n");
1184 break;
1185 }
1186 debug("%s%s%s", l_bit? "ldr" : "str",
1187 condition, b_bit? "b" : "");
1188 if (!p_bit && w_bit)
1189 debug("t");
1190 debug("\t%s,[%s", arm_regname[r12], arm_regname[r16]);
1191 if ((iw & 0x0e000000) == 0x04000000) {
1192 /* Immediate form: */
1193 uint32_t imm = iw & 0xfff;
1194 if (!p_bit)
1195 debug("]");
1196 if (imm != 0)
1197 debug(",#%s%i", u_bit? "" : "-", imm);
1198 if (p_bit)
1199 debug("]");
1200 } else if ((iw & 0x0e000010) == 0x06000000) {
1201 /* Register form: */
1202 if (!p_bit)
1203 debug("]");
1204 if ((iw & 0xfff) != 0)
1205 debug(",%s%s", u_bit? "" : "-",
1206 arm_regname[iw & 15]);
1207 if ((iw & 0xff0) != 0x000) {
1208 int c = (iw >> 7) & 31;
1209 int t = (iw >> 4) & 7;
1210 switch (t) {
1211 case 0: if (c != 0)
1212 debug(", lsl #%i", c);
1213 break;
1214 case 2: debug(", lsr #%i", c? c : 32);
1215 break;
1216 case 4: debug(", asr #%i", c? c : 32);
1217 break;
1218 case 6: if (c != 0)
1219 debug(", ror #%i", c);
1220 else
1221 debug(", rrx");
1222 break;
1223 }
1224 }
1225 if (p_bit)
1226 debug("]");
1227 } else {
1228 debug("UNKNOWN\n");
1229 break;
1230 }
1231 debug("%s", (p_bit && w_bit)? "!" : "");
1232 if ((iw & 0x0f000000) == 0x05000000 &&
1233 (r16 == ARM_PC || running)) {
1234 unsigned char tmpw[4];
1235 uint32_t imm = iw & 0xfff;
1236 uint32_t addr = (u_bit? imm : -imm);
1237 if (r16 == ARM_PC)
1238 addr += dumpaddr + 8;
1239 else
1240 addr += cpu->cd.arm.r[r16];
1241 symbol = get_symbol_name(&cpu->machine->symbol_context,
1242 addr, &offset);
1243 if (symbol != NULL)
1244 debug(" \t<%s", symbol);
1245 else
1246 debug(" \t<0x%08x", addr);
1247 if ((l_bit && cpu->memory_rw(cpu, cpu->mem, addr, tmpw,
1248 b_bit? 1 : sizeof(tmpw), MEM_READ, NO_EXCEPTIONS))
1249 || (!l_bit && running)) {
1250 if (l_bit) {
1251 if (cpu->byte_order ==
1252 EMUL_LITTLE_ENDIAN)
1253 addr = tmpw[0] +(tmpw[1] << 8) +
1254 (tmpw[2]<<16)+(tmpw[3]<<24);
1255 else
1256 addr = tmpw[3] + (tmpw[2]<<8) +
1257 (tmpw[1]<<16)+(tmpw[0]<<24);
1258 } else {
1259 tmpw[0] = addr = cpu->cd.arm.r[r12];
1260 if (r12 == ARM_PC)
1261 addr = cpu->pc + 8;
1262 }
1263 debug(": ");
1264 if (b_bit)
1265 debug("%i", tmpw[0]);
1266 else {
1267 symbol = get_symbol_name(&cpu->machine->
1268 symbol_context, addr, &offset);
1269 if (symbol != NULL)
1270 debug("%s", symbol);
1271 else if ((int32_t)addr > -256 &&
1272 (int32_t)addr < 256)
1273 debug("%i", addr);
1274 else
1275 debug("0x%x", addr);
1276 }
1277 }
1278 debug(">");
1279 }
1280 debug("\n");
1281 break;
1282 case 0x8: /* Block Data Transfer */
1283 case 0x9:
1284 /* xxxx100P USWLnnnn llllllll llllllll */
1285 p_bit = main_opcode & 1;
1286 s_bit = b_bit;
1287 debug("%s%s", l_bit? "ldm" : "stm", condition);
1288 switch (u_bit * 2 + p_bit) {
1289 case 0: debug("da"); break;
1290 case 1: debug("db"); break;
1291 case 2: debug("ia"); break;
1292 case 3: debug("ib"); break;
1293 }
1294 debug("\t%s", arm_regname[r16]);
1295 if (w_bit)
1296 debug("!");
1297 debug(",{");
1298 n = 0;
1299 for (i=0; i<16; i++)
1300 if ((iw >> i) & 1) {
1301 debug("%s%s", (n > 0)? ",":"", arm_regname[i]);
1302 n++;
1303 }
1304 debug("}");
1305 if (s_bit)
1306 debug("^");
1307 debug("\n");
1308 break;
1309 case 0xa: /* B: branch */
1310 case 0xb: /* BL: branch and link */
1311 debug("b%s%s\t", main_opcode == 0xa? "" : "l", condition);
1312 tmp = (iw & 0x00ffffff) << 2;
1313 if (tmp & 0x02000000)
1314 tmp |= 0xfc000000;
1315 tmp = (int32_t)(dumpaddr + tmp + 8);
1316 debug("0x%x", (int)tmp);
1317 symbol = get_symbol_name(&cpu->machine->symbol_context,
1318 tmp, &offset);
1319 if (symbol != NULL)
1320 debug(" \t<%s>", symbol);
1321 debug("\n");
1322 break;
1323 case 0xc: /* Coprocessor */
1324 case 0xd: /* LDC/STC */
1325 /*
1326 * xxxx1100 0100nnnn ddddcccc oooommmm MCRR c,op,Rd,Rn,CRm
1327 * xxxx1100 0101nnnn ddddcccc oooommmm MRRC c,op,Rd,Rn,CRm
1328 */
1329 if ((iw & 0x0fe00fff) == 0x0c400000) {
1330 debug("%s%s\t", iw & 0x100000? "mra" : "mar",
1331 condition);
1332 if (iw & 0x100000)
1333 debug("%s,%s,acc0\n",
1334 arm_regname[r12], arm_regname[r16]);
1335 else
1336 debug("acc0,%s,%s\n",
1337 arm_regname[r12], arm_regname[r16]);
1338 break;
1339 }
1340 if ((iw & 0x0fe00000) == 0x0c400000) {
1341 debug("%s%s\t", iw & 0x100000? "mrrc" : "mcrr",
1342 condition);
1343 debug("%i,%i,%s,%s,cr%i\n", r8, (iw >> 4) & 15,
1344 arm_regname[r12], arm_regname[r16], iw & 15);
1345 break;
1346 }
1347
1348 /* xxxx110P UNWLnnnn DDDDpppp oooooooo LDC/STC */
1349 debug("TODO: coprocessor LDC/STC\n");
1350 break;
1351 case 0xe: /* CDP (Coprocessor Op) */
1352 /* or MRC/MCR!
1353 * xxxx1110 oooonnnn ddddpppp qqq0mmmm CDP
1354 * xxxx1110 oooLNNNN ddddpppp qqq1MMMM MRC/MCR
1355 */
1356 if ((iw & 0x0ff00ff0) == 0x0e200010) {
1357 /* Special case: mia* DSP instructions */
1358 switch ((iw >> 16) & 0xf) {
1359 case 0: debug("mia"); break;
1360 case 8: debug("miaph"); break;
1361 case 12: debug("miaBB"); break;
1362 case 13: debug("miaTB"); break;
1363 case 14: debug("miaBT"); break;
1364 case 15: debug("miaTT"); break;
1365 default: debug("UNKNOWN mia vector instruction?");
1366 }
1367 debug("%s\t", condition);
1368 debug("acc%i,%s,%s\n", ((iw >> 5) & 7),
1369 arm_regname[iw & 15], arm_regname[r12]);
1370 break;
1371 }
1372 if (iw & 0x10) {
1373 debug("%s%s\t",
1374 (iw & 0x00100000)? "mrc" : "mcr", condition);
1375 debug("%i,%i,r%i,cr%i,cr%i,%i",
1376 (int)((iw >> 8) & 15), (int)((iw >>21) & 7),
1377 (int)((iw >>12) & 15), (int)((iw >>16) & 15),
1378 (int)((iw >> 0) & 15), (int)((iw >> 5) & 7));
1379 } else {
1380 debug("cdp%s\t", condition);
1381 debug("%i,%i,cr%i,cr%i,cr%i",
1382 (int)((iw >> 8) & 15),
1383 (int)((iw >>20) & 15),
1384 (int)((iw >>12) & 15),
1385 (int)((iw >>16) & 15),
1386 (int)((iw >> 0) & 15));
1387 if ((iw >> 5) & 7)
1388 debug(",0x%x", (int)((iw >> 5) & 7));
1389 }
1390 debug("\n");
1391 break;
1392 case 0xf: /* SWI */
1393 debug("swi%s\t", condition);
1394 debug("0x%x\n", (int)(iw & 0x00ffffff));
1395 break;
1396 default:debug("UNIMPLEMENTED\n");
1397 }
1398
1399 return sizeof(uint32_t);
1400 }
1401
1402
1403 /*****************************************************************************/
1404
1405
1406 /*
1407 * arm_mcr_mrc():
1408 *
1409 * Coprocessor register move.
1410 *
1411 * The program counter should be synched before calling this function (to
1412 * make debug output with the correct PC value possible).
1413 */
1414 void arm_mcr_mrc(struct cpu *cpu, uint32_t iword)
1415 {
1416 int opcode1 = (iword >> 21) & 7;
1417 int l_bit = (iword >> 20) & 1;
1418 int crn = (iword >> 16) & 15;
1419 int rd = (iword >> 12) & 15;
1420 int cp_num = (iword >> 8) & 15;
1421 int opcode2 = (iword >> 5) & 7;
1422 int crm = iword & 15;
1423
1424 if (cpu->cd.arm.coproc[cp_num] != NULL)
1425 cpu->cd.arm.coproc[cp_num](cpu, opcode1, opcode2, l_bit,
1426 crn, crm, rd);
1427 else {
1428 fatal("[ arm_mcr_mrc: pc=0x%08x, iword=0x%08x: "
1429 "cp_num=%i ]\n", (int)cpu->pc, iword, cp_num);
1430 arm_exception(cpu, ARM_EXCEPTION_UND);
1431 /* exit(1); */
1432 }
1433 }
1434
1435
1436 /*
1437 * arm_cdp():
1438 *
1439 * Coprocessor operations.
1440 *
1441 * The program counter should be synched before calling this function (to
1442 * make debug output with the correct PC value possible).
1443 */
1444 void arm_cdp(struct cpu *cpu, uint32_t iword)
1445 {
1446 fatal("[ arm_cdp: pc=0x%08x, iword=0x%08x ]\n", (int)cpu->pc, iword);
1447 arm_exception(cpu, ARM_EXCEPTION_UND);
1448 /* exit(1); */
1449 }
1450
1451
1452 /*****************************************************************************/
1453
1454
1455 #include "tmp_arm_tail.c"
1456

  ViewVC Help
Powered by ViewVC 1.1.26