/[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

Annotation of /trunk/src/cpus/cpu_arm.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 42 - (hide 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 dpavlin 14 /*
2 dpavlin 34 * Copyright (C) 2005-2007 Anders Gavare. All rights reserved.
3 dpavlin 14 *
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 dpavlin 42 * $Id: cpu_arm.c,v 1.71 2007/06/15 00:41:21 debug Exp $
29 dpavlin 14 *
30     * ARM CPU emulation.
31     *
32 dpavlin 20 *
33 dpavlin 14 * 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 dpavlin 42 #include <unistd.h>
43 dpavlin 14
44     #include "arm_cpu_types.h"
45     #include "cpu.h"
46 dpavlin 34 #include "interrupt.h"
47 dpavlin 14 #include "machine.h"
48     #include "memory.h"
49     #include "misc.h"
50 dpavlin 22 #include "of.h"
51 dpavlin 32 #include "settings.h"
52 dpavlin 14 #include "symbol.h"
53 dpavlin 42 #include "timer.h"
54     #include "useremul.h"
55 dpavlin 14
56     #define DYNTRANS_32
57     #include "tmp_arm_head.c"
58    
59    
60 dpavlin 42 extern int native_code_translation_enabled;
61    
62 dpavlin 14 /* 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 dpavlin 20 static int arm_exception_to_mode[N_ARM_EXCEPTIONS] = ARM_EXCEPTION_TO_MODE;
72    
73 dpavlin 18 /* For quick_pc_to_pointers(): */
74 dpavlin 22 void arm_pc_to_pointers(struct cpu *cpu);
75     #include "quick_pc_to_pointers.h"
76 dpavlin 14
77 dpavlin 34 void arm_irq_interrupt_assert(struct interrupt *interrupt);
78     void arm_irq_interrupt_deassert(struct interrupt *interrupt);
79 dpavlin 14
80 dpavlin 34
81 dpavlin 14 /*
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 dpavlin 32 int i, found;
91 dpavlin 14 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 dpavlin 28 cpu->run_instr = arm_run_instr;
106 dpavlin 14 cpu->memory_rw = arm_memory_rw;
107     cpu->update_translation_table = arm_update_translation_table;
108 dpavlin 18 cpu->invalidate_translation_caches =
109     arm_invalidate_translation_caches;
110 dpavlin 14 cpu->invalidate_code_translation = arm_invalidate_code_translation;
111 dpavlin 26 cpu->translate_v2p = arm_translate_v2p;
112 dpavlin 14
113 dpavlin 22 cpu->cd.arm.cpu_type = cpu_type_defs[found];
114     cpu->name = cpu->cd.arm.cpu_type.name;
115     cpu->is_32bit = 1;
116 dpavlin 32 cpu->byte_order = EMUL_LITTLE_ENDIAN;
117 dpavlin 14
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 dpavlin 22 /* TODO: default auxctrl contents */
122 dpavlin 14
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 dpavlin 18 cpu->cd.arm.cpsr |= ARM_MODE_SVC32;
128     cpu->cd.arm.control |= ARM_CONTROL_R;
129 dpavlin 14 }
130    
131     /* Only show name and caches etc for CPU nr 0: */
132     if (cpu_id == 0) {
133     debug("%s", cpu->name);
134 dpavlin 32 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 dpavlin 14 }
144     }
145    
146 dpavlin 22 /* 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 dpavlin 14 /* Coprocessor 15 = the system control coprocessor. */
160     cpu->cd.arm.coproc[15] = arm_coproc_15;
161    
162 dpavlin 22 /* 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 dpavlin 14 /*
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 dpavlin 20 cpu->cd.arm.flags = cpu->cd.arm.cpsr >> 28;
176    
177 dpavlin 32 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 dpavlin 34 /* 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 dpavlin 42 if (native_code_translation_enabled)
199     cpu->sampling_timer = timer_add(CPU_SAMPLE_TIMER_HZ,
200     arm_timer_sample_tick, cpu);
201 dpavlin 34
202 dpavlin 14 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 dpavlin 26 cpu->translate_v2p = arm_translate_v2p_mmu;
226 dpavlin 14 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 dpavlin 18
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 dpavlin 14 /*
253 dpavlin 18 * 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 dpavlin 14 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 dpavlin 18 * 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 dpavlin 14 * 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 dpavlin 20 cpu->cd.arm.cpsr &= 0x0fffffff;
358     cpu->cd.arm.cpsr |= (cpu->cd.arm.flags << 28);
359    
360 dpavlin 14 if (gprs) {
361     symbol = get_symbol_name(&cpu->machine->symbol_context,
362 dpavlin 20 cpu->pc, &offset);
363 dpavlin 14 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 dpavlin 20 debug(" pc = 0x%07x", (int)(cpu->pc & 0x03ffffff));
373 dpavlin 14 else
374 dpavlin 20 debug(" pc = 0x%08x", (int)cpu->pc);
375 dpavlin 14
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 dpavlin 22 debug("cpu%i: usr r8-14:", x);
412 dpavlin 14 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 dpavlin 22 debug("cpu%i: fiq r8-14:", x);
419 dpavlin 14 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 dpavlin 22 debug("cpu%i: irq r13-14:", x);
426 dpavlin 14 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 dpavlin 22 debug("cpu%i: svc r13-14:", x);
433 dpavlin 14 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 dpavlin 22 debug("cpu%i: abt r13-14:", x);
440 dpavlin 14 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 dpavlin 22 debug("cpu%i: und r13-14:", x);
447 dpavlin 14 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 dpavlin 22 /* 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 dpavlin 14 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 dpavlin 16 memcpy(cpu->cd.arm.default_r8_r14,
523     &cpu->cd.arm.r[8], sizeof(uint32_t) * 5);
524 dpavlin 14 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 dpavlin 16 memcpy(cpu->cd.arm.default_r8_r14,
529     &cpu->cd.arm.r[8], sizeof(uint32_t) * 5);
530 dpavlin 14 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 dpavlin 16 memcpy(cpu->cd.arm.default_r8_r14,
535     &cpu->cd.arm.r[8], sizeof(uint32_t) * 5);
536 dpavlin 14 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 dpavlin 16 memcpy(cpu->cd.arm.default_r8_r14,
541     &cpu->cd.arm.r[8], sizeof(uint32_t) * 5);
542 dpavlin 14 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 dpavlin 16 memcpy(&cpu->cd.arm.r[8],
570     cpu->cd.arm.default_r8_r14, sizeof(uint32_t) * 5);
571 dpavlin 14 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 dpavlin 16 memcpy(&cpu->cd.arm.r[8],
576     cpu->cd.arm.default_r8_r14, sizeof(uint32_t) * 5);
577 dpavlin 14 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 dpavlin 16 memcpy(&cpu->cd.arm.r[8],
582     cpu->cd.arm.default_r8_r14, sizeof(uint32_t) * 5);
583 dpavlin 14 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 dpavlin 16 memcpy(&cpu->cd.arm.r[8],
588     cpu->cd.arm.default_r8_r14, sizeof(uint32_t) * 5);
589 dpavlin 14 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 dpavlin 18 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 dpavlin 14
643     switch (exception_nr) {
644     case ARM_EXCEPTION_RESET:
645     cpu->running = 0;
646 dpavlin 18 fatal("ARM RESET: TODO");
647 dpavlin 14 exit(1);
648 dpavlin 18 case ARM_EXCEPTION_DATA_ABT:
649 dpavlin 14 retaddr += 4;
650     break;
651     }
652    
653 dpavlin 18 retaddr += 4;
654 dpavlin 14
655     arm_save_register_bank(cpu);
656    
657 dpavlin 20 cpu->cd.arm.cpsr &= 0x0fffffff;
658     cpu->cd.arm.cpsr |= (cpu->cd.arm.flags << 28);
659    
660 dpavlin 14 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 dpavlin 20 /*
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 dpavlin 14 newmode = cpu->cd.arm.cpsr & ARM_FLAG_MODE;
694 dpavlin 20 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 dpavlin 14 }
699 dpavlin 22
700 dpavlin 14 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 dpavlin 20 /*
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 dpavlin 14 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 dpavlin 18 quick_pc_to_pointers(cpu);
720 dpavlin 14 }
721    
722    
723     /*
724 dpavlin 24 * 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 dpavlin 34 * arm_irq_interrupt_assert():
739 dpavlin 38 * arm_irq_interrupt_deassert():
740 dpavlin 14 */
741 dpavlin 34 void arm_irq_interrupt_assert(struct interrupt *interrupt)
742 dpavlin 14 {
743 dpavlin 34 struct cpu *cpu = (struct cpu *) interrupt->extra;
744     cpu->cd.arm.irq_asserted = 1;
745 dpavlin 14 }
746 dpavlin 34 void arm_irq_interrupt_deassert(struct interrupt *interrupt)
747 dpavlin 14 {
748 dpavlin 34 struct cpu *cpu = (struct cpu *) interrupt->extra;
749     cpu->cd.arm.irq_asserted = 0;
750 dpavlin 14 }
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 dpavlin 24 int running, uint64_t dumpaddr)
767 dpavlin 14 {
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 dpavlin 20 debug("%s,%s,", arm_regname[r12], arm_regname[r16]);
840     debug("%s,%s\n", arm_regname[iw&15], arm_regname[r8]);
841 dpavlin 14 break;
842     }
843    
844     /*
845 dpavlin 20 * 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 dpavlin 14 * 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 dpavlin 20 * 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 dpavlin 14 * xxxx000P U1WLnnnn ddddHHHH 1SH1LLLL load/store rd,imm(rn)
971     */
972     if ((iw & 0x0e000090) == 0x00000090) {
973 dpavlin 18 char *op = "st";
974 dpavlin 14 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 dpavlin 18 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 dpavlin 14 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 dpavlin 20 addr = cpu->pc + 8;
1191 dpavlin 14 }
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 dpavlin 20 /*
1255     * xxxx1100 0100nnnn ddddcccc oooommmm MCRR c,op,Rd,Rn,CRm
1256     * xxxx1100 0101nnnn ddddcccc oooommmm MRRC c,op,Rd,Rn,CRm
1257     */
1258 dpavlin 22 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 dpavlin 20 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 dpavlin 14 /* 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 dpavlin 22 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 dpavlin 14 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 dpavlin 20 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 dpavlin 14 }
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 dpavlin 20 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 dpavlin 14 }
1379    
1380    
1381     /*****************************************************************************/
1382    
1383    
1384     #include "tmp_arm_tail.c"
1385    

  ViewVC Help
Powered by ViewVC 1.1.26