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

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


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

  ViewVC Help
Powered by ViewVC 1.1.26