/[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 42 - (show annotations)
Mon Oct 8 16:22:32 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 38816 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1613 2007/06/15 20:11:26 debug Exp $
20070501	Continuing a little on m88k disassembly (control registers,
		more instructions).
		Adding a dummy mvme88k machine mode.
20070502	Re-adding MIPS load/store alignment exceptions.
20070503	Implementing more of the M88K disassembly code.
20070504	Adding disassembly of some more M88K load/store instructions.
		Implementing some relatively simple M88K instructions (br.n,
		xor[.u] imm, and[.u] imm).
20070505	Implementing M88K three-register and, or, xor, and jmp[.n],
		bsr[.n] including function call trace stuff.
		Applying a patch from Bruce M. Simpson which implements the
		SYSCON_BOARD_CPU_CLOCK_FREQ_ID object of the syscon call in
		the yamon PROM emulation.
20070506	Implementing M88K bb0[.n] and bb1[.n], and skeletons for
		ldcr and stcr (although no control regs are implemented yet).
20070509	Found and fixed the bug which caused Linux for QEMU_MIPS to
		stop working in 0.4.5.1: It was a faulty change to the MIPS
		'sc' and 'scd' instructions I made while going through gcc -W
		warnings on 20070428.
20070510	Updating the Linux/QEMU_MIPS section in guestoses.html to
		use mips-test-0.2.tar.gz instead of 0.1.
		A big thank you to Miod Vallat for sending me M88K manuals.
		Implementing more M88K instructions (addu, subu, div[u], mulu,
		ext[u], clr, set, cmp).
20070511	Fixing bugs in the M88K "and" and "and.u" instructions (found
		by comparing against the manual).
		Implementing more M88K instructions (mask[.u], mak, bcnd (auto-
		generated)) and some more control register details.
		Cleanup: Removing the experimental AVR emulation mode and
		corresponding devices; AVR emulation wasn't really meaningful.
		Implementing autogeneration of most M88K loads/stores. The
		rectangle drawing demo (with -O0) for M88K runs :-)
		Beginning on M88K exception handling.
		More M88K instructions: tb0, tb1, rte, sub, jsr[.n].
		Adding some skeleton MVME PROM ("BUG") emulation.
20070512	Fixing a bug in the M88K cmp instruction.
		Adding the M88K lda (scaled register) instruction.
		Fixing bugs in 64-bit (32-bit pairs) M88K loads/stores.
		Removing the unused tick_hz stuff from the machine struct.
		Implementing the M88K xmem instruction. OpenBSD/mvme88k gets
		far enough to display the Copyright banner :-)
		Implementing subu.co (guess), addu.co, addu.ci, ff0, and ff1.
		Adding a dev_mvme187, for MVME187-specific devices/registers.
		OpenBSD/mvme88k prints more boot messages. :)
20070515	Continuing on MVME187 emulation (adding more devices, beginning
		on the CMMUs, etc).
		Adding the M88K and.c, xor.c, and or.c instructions, and making
		sure that mul, div, etc cause exceptions if executed when SFD1
		is disabled.
20070517	Continuing on M88K and MVME187 emulation in general; moving
		the CMMU registers to the CPU struct, separating dev_pcc2 from
		dev_mvme187, and beginning on memory_m88k.c (BATC and PATC).
		Fixing a bug in 64-bit (32-bit pairs) M88K fast stores.
		Implementing the clock part of dev_mk48txx.
		Implementing the M88K fstcr and xcr instructions.
		Implementing m88k_cpu_tlbdump().
		Beginning on the implementation of a separate address space
		for M88K .usr loads/stores.
20070520	Removing the non-working (skeleton) Sandpoint, SonyNEWS, SHARK
		Dnard, and Zaurus machine modes.
		Experimenting with dyntrans to_be_translated read-ahead. It
		seems to give a very small performance increase for MIPS
		emulation, but a large performance degradation for SuperH. Hm.
20070522	Disabling correct SuperH ITLB emulation; it does not seem to be
		necessary in order to let SH4 guest OSes run, and it slows down
		userspace code.
		Implementing "samepage" branches for SuperH emulation, and some
		other minor speed hacks.
20070525	Continuing on M88K memory-related stuff: exceptions, memory
		transaction register contents, etc.
		Implementing the M88K subu.ci instruction.
		Removing the non-working (skeleton) Iyonix machine mode.
		OpenBSD/mvme88k reaches userland :-), starts executing
		/sbin/init's instructions, and issues a few syscalls, before
		crashing.
20070526	Fixing bugs in dev_mk48txx, so that OpenBSD/mvme88k detects
		the correct time-of-day.
		Implementing a generic IRQ controller for the test machines
		(dev_irqc), similar to a proposed patch from Petr Stepan.
		Experimenting some more with translation read-ahead.
		Adding an "expect" script for automated OpenBSD/landisk
		install regression/performance tests.
20070527	Adding a dummy mmEye (SH3) machine mode skeleton.
		FINALLY found the strange M88K bug I have been hunting: I had
		not emulated the SNIP value for exceptions occurring in
		branch delay slots correctly.
		Implementing correct exceptions for 64-bit M88K loads/stores.
		Address to symbol lookups are now disabled when M88K is
		running in usermode (because usermode addresses don't have
		anything to do with supervisor addresses).
20070531	Removing the mmEye machine mode skeleton.
20070604	Some minor code cleanup.
20070605	Moving src/useremul.c into a subdir (src/useremul/), and
		cleaning up some more legacy constructs.
		Adding -Wstrict-aliasing and -fstrict-aliasing detection to
		the configure script.
20070606	Adding a check for broken GCC on Solaris to the configure
		script. (GCC 3.4.3 on Solaris cannot handle static variables
		which are initialized to 0 or NULL. :-/)
		Removing the old (non-working) ARC emulation modes: NEC RD94,
		R94, R96, and R98, and the last traces of Olivetti M700 and
		Deskstation Tyne.
		Removing the non-working skeleton WDSC device (dev_wdsc).
20070607	Thinking about how to use the host's cc + ld at runtime to
		generate native code. (See experiments/native_cc_ld_test.i
		for an example.)
20070608	Adding a program counter sampling timer, which could be useful
		for native code generation experiments.
		The KN02_CSR_NRMMOD bit in the DECstation 5000/200 (KN02) CSR
		should always be set, to allow a 5000/200 PROM to boot.
20070609	Moving out breakpoint details from the machine struct into
		a helper struct, and removing the limit on max nr of
		breakpoints.
20070610	Moving out tick functions into a helper struct as well (which
		also gets rid of the max limit).
20070612	FINALLY figured out why Debian/DECstation stopped working when
		translation read-ahead was enabled: in src/memory_rw.c, the
		call to invalidate_code_translation was made also if the
		memory access was an instruction load (if the page was mapped
		as writable); it shouldn't be called in that case.
20070613	Implementing some more MIPS32/64 revision 2 instructions: di,
		ei, ext, dext, dextm, dextu, and ins.
20070614	Implementing an instruction combination for the NetBSD/arm
		idle loop (making the host not use any cpu if NetBSD/arm
		inside the emulator is not using any cpu).
		Increasing the nr of ARM VPH entries from 128 to 384.
20070615	Removing the ENABLE_arch stuff from the configure script, so
		that all included architectures are included in both release
		and development builds.
		Moving memory related helper functions from misc.c to memory.c.
		Adding preliminary instructions for netbooting NetBSD/pmppc to
		guestoses.html; it doesn't work yet, there are weird timeouts.
		Beginning a total rewrite of the userland emulation modes
		(removing all emulation modes, beginning from scratch with
		NetBSD/MIPS and FreeBSD/Alpha only).
20070616	After fixing a bug in the DEC21143 NIC (the TDSTAT_OWN bit was
		only cleared for the last segment when transmitting, not all
		segments), NetBSD/pmppc boots with root-on-nfs without the
		timeouts. Updating guestoses.html.
		Removing the skeleton PSP (Playstation Portable) mode.
		Moving X11-related stuff in the machine struct into a helper
		struct.
		Cleanup of out-of-memory checks, to use a new CHECK_ALLOCATION
		macro (which prints a meaningful error message).
		Adding a COMMENT to each machine and device (for automagic
		.index comment generation).
		Doing regression testing for the next release.

==============  RELEASE 0.4.6  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26