/[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 34 - (show annotations)
Mon Oct 8 16:21:17 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 40440 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1480 2007/02/19 01:34:42 debug Exp $
20061029	Changing usleep(1) calls in the debugger to usleep(10000)
20061107	Adding a new disk image option (-d o...) which sets the ISO9660
		filesystem base offset; also making some other hacks to allow
		NetBSD/dreamcast and homebrew demos/games to boot directly
		from a filesystem image.
		Moving Dreamcast-specific stuff in the documentation to its
		own page (dreamcast.html).
		Adding a border to the Dreamcast PVR framebuffer.
20061108	Adding a -T command line option (again?), for halting the
		emulator on unimplemented memory accesses.
20061109	Continuing on various SH4 and Dreamcast related things.
		The emulator should now halt on more unimplemented device
		accesses, instead of just printing a warning, forcing me to
		actually implement missing stuff :)
20061111	Continuing on SH4 and Dreamcast stuff.
		Adding a bogus Landisk (SH4) machine mode.
20061112	Implementing some parts of the Dreamcast GDROM device. With
		some ugly hacks, NetBSD can (barely) mount an ISO image.
20061113	NetBSD/dreamcast now starts booting from the Live CD image,
		but crashes randomly quite early on in the boot process.
20061122	Beginning on a skeleton interrupt.h and interrupt.c for the
		new interrupt subsystem.
20061124	Continuing on the new interrupt system; taking the first steps
		to attempt to connect CPUs (SuperH and MIPS) and devices
		(dev_cons and SH4 timer interrupts) to it. Many things will
		probably break from now on.
20061125	Converting dev_ns16550, dev_8253 to the new interrupt system.
		Attempting to begin to convert the ISA bus.
20061130	Incorporating a patch from Brian Foley for the configure
		script, which checks for X11 libs in /usr/X11R6/lib64 (which
		is used on some Linux systems).
20061227	Adding a note in the man page about booting from Dreamcast
		CDROM images (i.e. that no external kernel is needed).
20061229	Continuing on the interrupt system rewrite: beginning to
		convert more devices, adding abort() calls for legacy interrupt
		system calls so that everything now _has_ to be rewritten!
		Almost all machine modes are now completely broken.
20061230	More progress on removing old interrupt code, mostly related
		to the ISA bus + devices, the LCA bus (on AlphaBook1), and
		the Footbridge bus (for CATS). And some minor PCI stuff.
		Connecting the ARM cpu to the new interrupt system.
		The CATS, NetWinder, and QEMU_MIPS machine modes now work with
		the new interrupt system :)
20061231	Connecting PowerPC CPUs to the new interrupt system.
		Making PReP machines (IBM 6050) work again.
		Beginning to convert the GT PCI controller (for e.g. Malta
		and Cobalt emulation). Some things work, but not everything.
		Updating Copyright notices for 2007.
20070101	Converting dev_kn02 from legacy style to devinit; the 3max
		machine mode now works with the new interrupt system :-]
20070105	Beginning to convert the SGI O2 machine to the new interrupt
		system; finally converting O2 (IP32) devices to devinit, etc.
20070106	Continuing on the interrupt system redesign/rewrite; KN01
		(PMAX), KN230, and Dreamcast ASIC interrupts should work again,
		moving out stuff from machine.h and devices.h into the
		corresponding devices, beginning the rewrite of i80321
		interrupts, etc.
20070107	Beginning on the rewrite of Eagle interrupt stuff (PReP, etc).
20070117	Beginning the rewrite of Algor (V3) interrupts (finally
		changing dev_v3 into devinit style).
20070118	Removing the "bus" registry concept from machine.h, because
		it was practically meaningless.
		Continuing on the rewrite of Algor V3 ISA interrupts.
20070121	More work on Algor interrupts; they are now working again,
		well enough to run NetBSD/algor. :-)
20070122	Converting VR41xx (HPCmips) interrupts. NetBSD/hpcmips
		can be installed using the new interrupt system :-)
20070123	Making the testmips mode work with the new interrupt system.
20070127	Beginning to convert DEC5800 devices to devinit, and to the
		new interrupt system.
		Converting Playstation 2 devices to devinit, and converting
		the interrupt system. Also fixing a severe bug: the interrupt
		mask register on Playstation 2 is bitwise _toggled_ on writes.
20070128	Removing the dummy NetGear machine mode and the 8250 device
		(which was only used by the NetGear machine).
		Beginning to convert the MacPPC GC (Grand Central) interrupt
		controller to the new interrupt system.
		Converting Jazz interrupts (PICA61 etc.) to the new interrupt
		system. NetBSD/arc can be installed again :-)
		Fixing the JAZZ timer (hardcoding it at 100 Hz, works with
		NetBSD and it is better than a completely dummy timer as it
		was before).
		Converting dev_mp to the new interrupt system, although I
		haven't had time to actually test it yet.
		Completely removing src/machines/interrupts.c, cpu_interrupt
		and cpu_interrupt_ack in src/cpu.c, and
		src/include/machine_interrupts.h! Adding fatal error messages
		+ abort() in the few places that are left to fix.
		Converting dev_z8530 to the new interrupt system.
		FINALLY removing the md_int struct completely from the
		machine struct.
		SH4 fixes (adding a PADDR invalidation in the ITLB replacement
		code in memory_sh.c); the NetBSD/dreamcast LiveCD now runs
		all the way to the login prompt, and can be interacted with :-)
		Converting the CPC700 controller (PCI and interrupt controller
		for PM/PPC) to the new interrupt system.
20070129	Fixing MACE ISA interrupts (SGI IP32 emulation). Both NetBSD/
		sgimips' and OpenBSD/sgi's ramdisk kernels can now be
		interacted with again.
20070130	Moving out the MIPS multi_lw and _sw instruction combinations
		so that they are auto-generated at compile time instead.
20070131	Adding detection of amd64/x86_64 hosts in the configure script,
		for doing initial experiments (again :-) with native code
		generation.
		Adding a -k command line option to set the size of the dyntrans
		cache, and a -B command line option to disable native code
		generation, even if GXemul was compiled with support for
		native code generation for the specific host CPU architecture.
20070201	Experimenting with a skeleton for native code generation.
		Changing the default behaviour, so that native code generation
		is now disabled by default, and has to be enabled by using
		-b on the command line.
20070202	Continuing the native code generation experiments.
		Making PCI interrupts work for Footbridge again.
20070203	More native code generation experiments.
		Removing most of the native code generation experimental code,
		it does not make sense to include any quick hacks like this.
		Minor cleanup/removal of some more legacy MIPS interrupt code.
20070204	Making i80321 interrupts work again (for NetBSD/evbarm etc.),
		and fixing the timer at 100 Hz.
20070206	Experimenting with removing the wdc interrupt slowness hack.
20070207	Lowering the number of dyntrans TLB entries for MIPS from
		192 to 128, resulting in a minor speed improvement.
		Minor optimization to the code invalidation routine in
		cpu_dyntrans.c.
20070208	Increasing (experimentally) the nr of dyntrans instructions per
		loop from 60 to 120.
20070210	Commenting out (experimentally) the dyntrans_device_danger
		detection in memory_rw.c.
		Changing the testmips and baremips machines to use a revision 2
		MIPS64 CPU by default, instead of revision 1.
		Removing the dummy i960, IA64, x86, AVR32, and HP PA-RISC
		files, the PC bios emulation, and the Olivetti M700 (ARC) and
		db64360 emulation modes.
20070211	Adding an "mp" demo to the demos directory, which tests the
		SMP functionality of the testmips machine.
		Fixing PReP interrupts some more. NetBSD/prep now boots again.
20070216	Adding a "nop workaround" for booting Mach/PMAX to the
		documentation; thanks to Artur Bujdoso for the values.
		Converting more of the MacPPC interrupt stuff to the new
		system.
		Beginning to convert BeBox interrupts to the new system.
		PPC603e should NOT have the PPC_NO_DEC flag! Removing it.
		Correcting BeBox clock speed (it was set to 100 in the NetBSD
		bootinfo block, but should be 33000000/4), allowing NetBSD
		to start without using the (incorrect) PPC_NO_DEC hack.
20070217	Implementing (slow) AltiVec vector loads and stores, allowing
		NetBSD/macppc to finally boot using the GENERIC kernel :-)
		Updating the documentation with install instructions for
		NetBSD/macppc.
20070218-19	Regression testing for the release.

==============  RELEASE 0.4.4  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26