/[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 24 - (show annotations)
Mon Oct 8 16:19:56 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 40668 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1256 2006/06/23 20:43:44 debug Exp $
20060219	Various minor updates. Removing the old MIPS16 skeleton code,
		because it will need to be rewritten for dyntrans anyway.
20060220-22	Removing the non-working dyntrans backend support.
		Continuing on the 64-bit dyntrans virtual memory generalization.
20060223	More work on the 64-bit vm generalization.
20060225	Beginning on MIPS dyntrans load/store instructions.
		Minor PPC updates (64-bit load/store, etc).
		Fixes for the variable-instruction-length framework, some
		minor AVR updates (a simple Hello World program works!).
		Beginning on a skeleton for automatically generating documen-
		tation (for devices etc.).
20060226	PPC updates (adding some more 64-bit instructions, etc).
		AVR updates (more instructions).
		FINALLY found and fixed the zs bug, making NetBSD/macppc
		accept the serial console.
20060301	Adding more AVR instructions.
20060304	Continuing on AVR-related stuff. Beginning on a framework for
		cycle-accurate device emulation. Adding an experimental "PAL
		TV" device (just a dummy so far).
20060305	Adding more AVR instructions.
		Adding a dummy epcom serial controller (for TS7200 emulation).
20060310	Removing the emul() command from configuration files, so only
		net() and machine() are supported.
		Minor progress on the MIPS dyntrans rewrite.
20060311	Continuing on the MIPS dyntrans rewrite (adding more
		instructions, etc).
20060315	Adding more instructions (sllv, srav, srlv, bgtz[l], blez[l],
		beql, bnel, slti[u], various loads and stores).
20060316	Removing the ALWAYS_SIGNEXTEND_32 option, since it was rarely
		used.
		Adding more MIPS dyntrans instructions, and fixing bugs.
20060318	Implementing fast loads/stores for MIPS dyntrans (big/little
		endian, 32-bit and 64-bit modes).
20060320	Making MIPS dyntrans the default configure option; use
		"--enable-oldmips" to use the old bintrans system.
		Adding MIPS dyntrans dmult[u]; minor updates.
20060322	Continuing... adding some more instructions.
		Adding a simple skeleton for demangling C++ "_ZN" symbols.
20060323	Moving src/debugger.c into a new directory (src/debugger/).
20060324	Fixing the hack used to load PPC ELFs (useful for relocated
		Linux/ppc kernels), and adding a dummy G3 machine mode.
20060325-26	Beginning to experiment with GDB remote serial protocol
		connections; adding a -G command line option for selecting
		which TCP port to listen to.
20060330	Beginning a major cleanup to replace things like "0x%016llx"
		with more correct "0x%016"PRIx64, etc.
		Continuing on the GDB remote serial protocol support.
20060331	More cleanup, and some minor GDB remote progress.
20060402	Adding a hack to the configure script, to allow compilation
		on systems that lack PRIx64 etc.
20060406	Removing the temporary FreeBSD/arm hack in dev_ns16550.c and
		replacing it with a better fix from Olivier Houchard.
20060407	A remote debugger (gdb or ddd) can now start and stop the
		emulator using the GDB remote serial protocol, and registers
		and memory can be read. MIPS only for now.
20060408	More GDB progress: single-stepping also works, and also adding
		support for ARM, PowerPC, and Alpha targets.
		Continuing on the delay-slot-across-page-boundary issue.
20060412	Minor update: beginning to add support for the SPARC target
		to the remote GDB functionality.
20060414	Various MIPS updates: adding more instructions for dyntrans
		(eret, add), and making some exceptions work. Fixing a bug
		in dmult[u].
		Implementing the first SPARC instructions (sethi, or).
20060415	Adding "magic trap" instructions so that PROM calls can be
		software emulated in MIPS dyntrans.
		Adding more MIPS dyntrans instructions (ddiv, dadd) and
		fixing another bug in dmult.
20060416	More MIPS dyntrans progress: adding [d]addi, movn, movz, dsllv,
		rfi, an ugly hack for supporting R2000/R3000 style faked caches,
		preliminary interrupt support, and various other updates and
		bugfixes.
20060417	Adding more SPARC instructions (add, sub, sll[x], sra[x],
		srl[x]), and useful SPARC header definitions.
		Adding the first (trivial) x86/AMD64 dyntrans instructions (nop,
		cli/sti, stc/clc, std/cld, simple mov, inc ax). Various other
		x86 updates related to variable instruction length stuff.
		Adding unaligned loads/stores to the MIPS dyntrans mode (but
		still using the pre-dyntrans (slow) imlementation).
20060419	Fixing a MIPS dyntrans exception-in-delay-slot bug.
		Removing the old "show opcode statistics" functionality, since
		it wasn't really useful and isn't implemented for dyntrans.
		Single-stepping (or running with instruction trace) now looks
		ok with dyntrans with delay-slot architectures.
20060420	Minor hacks (removing the -B command line option when compiled
		for non-bintrans, and some other very minor updates).
		Adding (slow) MIPS dyntrans load-linked/store-conditional.
20060422	Applying fixes for bugs discovered by Nils Weller's nwcc
		(static DEC memmap => now per machine, and adding an extern
		keyword in cpu_arm_instr.c).
		Finally found one of the MIPS dyntrans bugs that I've been
		looking for (copy/paste spelling error BIG vs LITTLE endian in
		cpu_mips_instr_loadstore.c for 16-bit fast stores).
		FINALLY found the major MIPS dyntrans bug: slti vs sltiu
		signed/unsigned code in cpu_mips_instr.c. :-)
		Adding more MIPS dyntrans instructions (lwc1, swc1, bgezal[l],
		ctc1, tlt[u], tge[u], tne, beginning on rdhwr).
		NetBSD/hpcmips can now reach userland when using dyntrans :-)
		Adding some more x86 dyntrans instructions.
		Finally removed the old Alpha-specific virtual memory code,
		and replaced it with the generic 64-bit version.
		Beginning to add disassembly support for SPECIAL3 MIPS opcodes.
20060423	Continuing on the delay-slot-across-page-boundary issue;
		adding an end_of_page2 ic slot (like I had planned before, but
		had removed for some reason).
		Adding a quick-and-dirty fallback to legacy coprocessor 1
		code (i.e. skipping dyntrans implementation for now).
		NetBSD/hpcmips and NetBSD/pmax (when running on an emulated
		R4400) can now be installed and run. :-)  (Many bugs left
		to fix, though.)
		Adding more MIPS dyntrans instructions: madd[u], msub[u].
		Cleaning up the SPECIAL2 vs R5900/TX79/C790 "MMI" opcode
		maps somewhat (disassembly and dyntrans instruction decoding).
20060424	Adding an isa_revision field to mips_cpu_types.h, and making
		sure that SPECIAL3 opcodes cause Reserved Instruction
		exceptions on MIPS32/64 revisions lower than 2.
		Adding the SPARC 'ba', 'call', 'jmpl/retl', 'and', and 'xor'
		instructions.
20060425	Removing the -m command line option ("run at most x 
		instructions") and -T ("single_step_on_bad_addr"), because
		they never worked correctly with dyntrans anyway.
		Freshening up the man page.
20060428	Adding more MIPS dyntrans instructions: bltzal[l], idle.
		Enabling MIPS dyntrans compare interrupts.
20060429	FINALLY found the weird dyntrans bug, causing NetBSD etc. to
		behave strangely: some floating point code (conditional
		coprocessor branches) could not be reused from the old
		non-dyntrans code. The "quick-and-dirty fallback" only appeared
		to work. Fixing by implementing bc1* for MIPS dyntrans.
		More MIPS instructions: [d]sub, sdc1, ldc1, dmtc1, dmfc1, cfc0.
		Freshening up MIPS floating point disassembly appearance.
20060430	Continuing on C790/R5900/TX79 disassembly; implementing 128-bit
		"por" and "pextlw".
20060504	Disabling -u (userland emulation) unless compiled as unstable
		development version.
		Beginning on freshening up the testmachine include files,
		to make it easier to reuse those files (placing them in
		src/include/testmachine/), and beginning on a set of "demos"
		or "tutorials" for the testmachine functionality.
		Minor updates to the MIPS GDB remote protocol stub.
		Refreshing doc/experiments.html and gdb_remote.html.
		Enabling Alpha emulation in the stable release configuration,
		even though no guest OSes for Alpha can run yet.
20060505	Adding a generic 'settings' object, which will contain
		references to settable variables (which will later be possible
		to access using the debugger).
20060506	Updating dev_disk and corresponding demo/documentation (and
		switching from SCSI to IDE disk types, so it actually works
		with current test machines :-).
20060510	Adding a -D_LARGEFILE_SOURCE hack for 64-bit Linux hosts,
		so that fseeko() doesn't give a warning.
		Updating the section about how dyntrans works (the "runnable
		IR") in doc/intro.html.
		Instruction updates (some x64=1 checks, some more R5900
		dyntrans stuff: better mul/mult separation from MIPS32/64,
		adding ei and di).
		Updating MIPS cpuregs.h to a newer one (from NetBSD).
		Adding more MIPS dyntrans instructions: deret, ehb.
20060514	Adding disassembly and beginning implementation of SPARC wr
		and wrpr instructions.
20060515	Adding a SUN SPARC machine mode, with dummy SS20 and Ultra1
		machines. Adding the 32-bit "rd psr" instruction.
20060517	Disassembly support for the general SPARC rd instruction.
		Partial implementation of the cmp (subcc) instruction.
		Some other minor updates (making sure that R5900 processors
		start up with the EIE bit enabled, otherwise Linux/playstation2
		receives no interrupts).
20060519	Minor MIPS updates/cleanups.
20060521	Moving the MeshCube machine into evbmips; this seems to work
		reasonably well with a snapshot of a NetBSD MeshCube kernel.
		Cleanup/fix of MIPS config0 register initialization.
20060529	Minor MIPS fixes, including a sign-extension fix to the
		unaligned load/store code, which makes NetBSD/pmax on R3000
		work better with dyntrans. (Ultrix and Linux/DECstation still
		don't work, though.)
20060530	Minor updates to the Alpha machine mode: adding an AlphaBook
		mode, an LCA bus (forwarding accesses to an ISA bus), etc.
20060531	Applying a bugfix for the MIPS dyntrans sc[d] instruction from
		Ondrej Palkovsky. (Many thanks.)
20060601	Minifix to allow ARM immediate msr instruction to not give
		an error for some valid values.
		More Alpha updates.
20060602	Some minor Alpha updates.
20060603	Adding the Alpha cmpbge instruction. NetBSD/alpha prints its
		first boot messages :-) on an emulated Alphabook 1.
20060612	Minor updates; adding a dev_ether.h include file for the
		testmachine ether device. Continuing the hunt for the dyntrans
		bug which makes Linux and Ultrix on DECstation behave
		strangely... FINALLY found it! It seems to be related to
		invalidation of the translation cache, on tlbw{r,i}. There
		also seems to be some remaining interrupt-related problems.
20060614	Correcting the implementation of ldc1/sdc1 for MIPS dyntrans
		(so that it uses 16 32-bit registers if the FR bit in the
		status register is not set).
20060616	REMOVING BINTRANS COMPLETELY!
		Removing the old MIPS interpretation mode.
		Removing the MFHILO_DELAY and instruction delay stuff, because
		they wouldn't work with dyntrans anyway.
20060617	Some documentation updates (adding "NetBSD-archive" to some
		URLs, and new Debian/DECstation installation screenshots).
		Removing the "tracenull" and "enable-caches" configure options.
		Improving MIPS dyntrans performance somewhat (only invalidate
		translations if necessary, on writes to the entryhi register,
		instead of doing it for all cop0 writes).
20060618	More cleanup after the removal of the old MIPS emulation.
		Trying to fix the MIPS dyntrans performance bugs/bottlenecks;
		only semi-successful so far (for R3000).
20060620	Minor update to allow clean compilation again on Tru64/Alpha.
20060622	MIPS cleanup and fixes (removing the pc_last stuff, which
		doesn't make sense with dyntrans anyway, and fixing a cross-
		page-delay-slot-with-exception case in end_of_page).
		Removing the old max_random_cycles_per_chunk stuff, and the
		concept of cycles vs instructions for MIPS emulation.
		FINALLY found and fixed the bug which caused NetBSD/pmax
		clocks to behave strangely (it was a load to the zero register,
		which was treated as a NOP; now it is treated as a load to a
		dummy scratch register).
20060623	Increasing the dyntrans chunk size back to
		N_SAFE_DYNTRANS_LIMIT, instead of N_SAFE_DYNTRANS_LIMIT/2.
		Preparing for a quick release, even though there are known
		bugs, and performance for non-R3000 MIPS emulation is very
		poor. :-/
		Reverting to half the dyntrans chunk size again, because
		NetBSD/cats seemed less stable with full size chunks. :(
		NetBSD/sgimips 3.0 can now run :-)  (With release 0.3.8, only
		NetBSD/sgimips 2.1 worked, not 3.0.)

==============  RELEASE 0.4.0  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26