/[gxemul]/trunk/src/cpus/cpu_arm_instr.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_instr.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: 79832 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_instr.c,v 1.70 2006/12/30 13:30:53 debug Exp $
29 dpavlin 14 *
30     * ARM instructions.
31     *
32     * Individual functions should keep track of cpu->n_translated_instrs.
33     * (If no instruction was executed, then it should be decreased. If, say, 4
34     * instructions were combined into one function and executed, then it should
35     * be increased by 3.)
36 dpavlin 32 *
37     * Note: cpu->pc is prefered over r[ARM_PC]. r[ARM_PC] is only used in a
38     * few places, and should always be kept in synch with the real
39     * program counter.
40 dpavlin 14 */
41    
42    
43 dpavlin 18 /* #define GATHER_BDT_STATISTICS */
44    
45    
46     #ifdef GATHER_BDT_STATISTICS
47 dpavlin 14 /*
48 dpavlin 18 * update_bdt_statistics():
49     *
50     * Gathers statistics about load/store multiple instructions.
51     *
52     * NOTE/TODO: Perhaps it would be more memory efficient to swap the high
53     * and low parts of the instruction word, so that the lllllll bits become
54     * the high bits; this would cause fewer host pages to be used. Anyway, the
55     * current implementation works on hosts with lots of RAM.
56     *
57     * The resulting file, bdt_statistics.txt, should then be processed like
58     * this to give a new cpu_arm_multi.txt:
59     *
60     * uniq -c bdt_statistics.txt|sort -nr|head -256|cut -f 2 > cpu_arm_multi.txt
61     */
62     static void update_bdt_statistics(uint32_t iw)
63     {
64     static FILE *f = NULL;
65     static long long *counts;
66     static char *counts_used;
67     static long long n = 0;
68    
69     if (f == NULL) {
70     size_t s = (1 << 24) * sizeof(long long);
71     f = fopen("bdt_statistics.txt", "w");
72     if (f == NULL) {
73     fprintf(stderr, "update_bdt_statistics(): :-(\n");
74     exit(1);
75     }
76     counts = zeroed_alloc(s);
77     counts_used = zeroed_alloc(65536);
78     }
79    
80     /* Drop the s-bit: xxxx100P USWLnnnn llllllll llllllll */
81     iw = ((iw & 0x01800000) >> 1) | (iw & 0x003fffff);
82    
83     counts_used[iw & 0xffff] = 1;
84     counts[iw] ++;
85    
86     n ++;
87     if ((n % 500000) == 0) {
88     int i;
89     long long j;
90     fatal("[ update_bdt_statistics(): n = %lli ]\n", (long long) n);
91     fseek(f, 0, SEEK_SET);
92     for (i=0; i<0x1000000; i++)
93     if (counts_used[i & 0xffff] && counts[i] != 0) {
94     /* Recreate the opcode: */
95     uint32_t opcode = ((i & 0x00c00000) << 1)
96     | (i & 0x003fffff) | 0x08000000;
97     for (j=0; j<counts[i]; j++)
98     fprintf(f, "0x%08x\n", opcode);
99     }
100     fflush(f);
101     }
102     }
103     #endif
104    
105    
106     /*****************************************************************************/
107    
108    
109     /*
110 dpavlin 14 * Helper definitions:
111     *
112     * Each instruction is defined like this:
113     *
114     * X(foo)
115     * {
116     * code for foo;
117     * }
118     * Y(foo)
119     *
120     * The Y macro defines 14 copies of the instruction, one for each possible
121     * condition code. (The NV condition code is not included, and the AL code
122     * uses the main foo function.) Y also defines an array with pointers to
123     * all of these functions.
124 dpavlin 18 *
125     * If the compiler is good enough (i.e. allows long enough code sequences
126     * to be inlined), then the Y functions will be compiled as full (inlined)
127     * functions, otherwise they will simply call the X function.
128 dpavlin 14 */
129    
130 dpavlin 20 uint8_t condition_hi[16] = { 0,0,1,1, 0,0,0,0, 0,0,1,1, 0,0,0,0 };
131     uint8_t condition_ge[16] = { 1,0,1,0, 1,0,1,0, 0,1,0,1, 0,1,0,1 };
132     uint8_t condition_gt[16] = { 1,0,1,0, 0,0,0,0, 0,1,0,1, 0,0,0,0 };
133    
134 dpavlin 14 #define Y(n) void arm_instr_ ## n ## __eq(struct cpu *cpu, \
135     struct arm_instr_call *ic) \
136 dpavlin 20 { if (cpu->cd.arm.flags & ARM_F_Z) \
137 dpavlin 14 arm_instr_ ## n (cpu, ic); } \
138     void arm_instr_ ## n ## __ne(struct cpu *cpu, \
139     struct arm_instr_call *ic) \
140 dpavlin 20 { if (!(cpu->cd.arm.flags & ARM_F_Z)) \
141 dpavlin 14 arm_instr_ ## n (cpu, ic); } \
142     void arm_instr_ ## n ## __cs(struct cpu *cpu, \
143     struct arm_instr_call *ic) \
144 dpavlin 20 { if (cpu->cd.arm.flags & ARM_F_C) \
145 dpavlin 14 arm_instr_ ## n (cpu, ic); } \
146     void arm_instr_ ## n ## __cc(struct cpu *cpu, \
147     struct arm_instr_call *ic) \
148 dpavlin 20 { if (!(cpu->cd.arm.flags & ARM_F_C)) \
149 dpavlin 14 arm_instr_ ## n (cpu, ic); } \
150     void arm_instr_ ## n ## __mi(struct cpu *cpu, \
151     struct arm_instr_call *ic) \
152 dpavlin 20 { if (cpu->cd.arm.flags & ARM_F_N) \
153 dpavlin 14 arm_instr_ ## n (cpu, ic); } \
154     void arm_instr_ ## n ## __pl(struct cpu *cpu, \
155     struct arm_instr_call *ic) \
156 dpavlin 20 { if (!(cpu->cd.arm.flags & ARM_F_N)) \
157 dpavlin 14 arm_instr_ ## n (cpu, ic); } \
158     void arm_instr_ ## n ## __vs(struct cpu *cpu, \
159     struct arm_instr_call *ic) \
160 dpavlin 20 { if (cpu->cd.arm.flags & ARM_F_V) \
161 dpavlin 14 arm_instr_ ## n (cpu, ic); } \
162     void arm_instr_ ## n ## __vc(struct cpu *cpu, \
163     struct arm_instr_call *ic) \
164 dpavlin 20 { if (!(cpu->cd.arm.flags & ARM_F_V)) \
165 dpavlin 14 arm_instr_ ## n (cpu, ic); } \
166     void arm_instr_ ## n ## __hi(struct cpu *cpu, \
167     struct arm_instr_call *ic) \
168 dpavlin 20 { if (condition_hi[cpu->cd.arm.flags]) \
169 dpavlin 14 arm_instr_ ## n (cpu, ic); } \
170     void arm_instr_ ## n ## __ls(struct cpu *cpu, \
171     struct arm_instr_call *ic) \
172 dpavlin 20 { if (!condition_hi[cpu->cd.arm.flags]) \
173 dpavlin 14 arm_instr_ ## n (cpu, ic); } \
174     void arm_instr_ ## n ## __ge(struct cpu *cpu, \
175     struct arm_instr_call *ic) \
176 dpavlin 20 { if (condition_ge[cpu->cd.arm.flags]) \
177 dpavlin 14 arm_instr_ ## n (cpu, ic); } \
178     void arm_instr_ ## n ## __lt(struct cpu *cpu, \
179     struct arm_instr_call *ic) \
180 dpavlin 20 { if (!condition_ge[cpu->cd.arm.flags]) \
181 dpavlin 14 arm_instr_ ## n (cpu, ic); } \
182     void arm_instr_ ## n ## __gt(struct cpu *cpu, \
183     struct arm_instr_call *ic) \
184 dpavlin 20 { if (condition_gt[cpu->cd.arm.flags]) \
185 dpavlin 14 arm_instr_ ## n (cpu, ic); } \
186     void arm_instr_ ## n ## __le(struct cpu *cpu, \
187     struct arm_instr_call *ic) \
188 dpavlin 20 { if (!condition_gt[cpu->cd.arm.flags]) \
189 dpavlin 14 arm_instr_ ## n (cpu, ic); } \
190     void (*arm_cond_instr_ ## n [16])(struct cpu *, \
191     struct arm_instr_call *) = { \
192     arm_instr_ ## n ## __eq, arm_instr_ ## n ## __ne, \
193     arm_instr_ ## n ## __cs, arm_instr_ ## n ## __cc, \
194     arm_instr_ ## n ## __mi, arm_instr_ ## n ## __pl, \
195     arm_instr_ ## n ## __vs, arm_instr_ ## n ## __vc, \
196     arm_instr_ ## n ## __hi, arm_instr_ ## n ## __ls, \
197     arm_instr_ ## n ## __ge, arm_instr_ ## n ## __lt, \
198     arm_instr_ ## n ## __gt, arm_instr_ ## n ## __le, \
199     arm_instr_ ## n , arm_instr_nop };
200    
201     #define cond_instr(n) ( arm_cond_instr_ ## n [condition_code] )
202    
203    
204     /*****************************************************************************/
205    
206    
207     /*
208     * invalid: Invalid instructions end up here.
209     */
210     X(invalid) {
211     uint32_t low_pc;
212     low_pc = ((size_t)ic - (size_t)
213     cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
214 dpavlin 20 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1)
215 dpavlin 14 << ARM_INSTR_ALIGNMENT_SHIFT);
216 dpavlin 20 cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
217 dpavlin 14
218 dpavlin 24 fatal("FATAL ERROR: An internal error occured in the ARM"
219     " dyntrans code. Please contact the author with detailed"
220     " repro steps on how to trigger this bug. pc = 0x%08"PRIx32"\n",
221     (uint32_t)cpu->pc);
222 dpavlin 30
223     cpu->cd.arm.next_ic = &nothing_call;
224 dpavlin 24 }
225 dpavlin 14
226 dpavlin 24
227     /*
228     * nop: Do nothing.
229     */
230     X(nop)
231     {
232 dpavlin 14 }
233    
234    
235     /*
236     * b: Branch (to a different translated page)
237     *
238     * arg[0] = relative offset
239     */
240     X(b)
241     {
242 dpavlin 20 cpu->pc = (uint32_t)((cpu->pc & 0xfffff000) + (int32_t)ic->arg[0]);
243 dpavlin 14
244     /* Find the new physical page and update the translation pointers: */
245 dpavlin 18 quick_pc_to_pointers(cpu);
246 dpavlin 14 }
247     Y(b)
248    
249    
250     /*
251     * b_samepage: Branch (to within the same translated page)
252     *
253     * arg[0] = pointer to new arm_instr_call
254 dpavlin 20 * arg[1] = pointer to the next instruction.
255     *
256     * NOTE: This instruction is manually inlined.
257 dpavlin 14 */
258 dpavlin 20 X(b_samepage) {
259 dpavlin 14 cpu->cd.arm.next_ic = (struct arm_instr_call *) ic->arg[0];
260     }
261 dpavlin 20 X(b_samepage__eq) {
262     cpu->cd.arm.next_ic = (struct arm_instr_call *)
263     ic->arg[cpu->cd.arm.flags & ARM_F_Z? 0 : 1];
264     }
265     X(b_samepage__ne) {
266     cpu->cd.arm.next_ic = (struct arm_instr_call *)
267     ic->arg[cpu->cd.arm.flags & ARM_F_Z? 1 : 0];
268     }
269     X(b_samepage__cs) {
270     cpu->cd.arm.next_ic = (struct arm_instr_call *)
271     ic->arg[cpu->cd.arm.flags & ARM_F_C? 0 : 1];
272     }
273     X(b_samepage__cc) {
274     cpu->cd.arm.next_ic = (struct arm_instr_call *)
275     ic->arg[cpu->cd.arm.flags & ARM_F_C? 1 : 0];
276     }
277     X(b_samepage__mi) {
278     cpu->cd.arm.next_ic = (struct arm_instr_call *)
279     ic->arg[cpu->cd.arm.flags & ARM_F_N? 0 : 1];
280     }
281     X(b_samepage__pl) {
282     cpu->cd.arm.next_ic = (struct arm_instr_call *)
283     ic->arg[cpu->cd.arm.flags & ARM_F_N? 1 : 0];
284     }
285     X(b_samepage__vs) {
286     cpu->cd.arm.next_ic = (struct arm_instr_call *)
287     ic->arg[cpu->cd.arm.flags & ARM_F_V? 0 : 1];
288     }
289     X(b_samepage__vc) {
290     cpu->cd.arm.next_ic = (struct arm_instr_call *)
291     ic->arg[cpu->cd.arm.flags & ARM_F_V? 1 : 0];
292     }
293     X(b_samepage__hi) {
294     cpu->cd.arm.next_ic = (condition_hi[cpu->cd.arm.flags])?
295     (struct arm_instr_call *) ic->arg[0] :
296     (struct arm_instr_call *) ic->arg[1];
297     }
298     X(b_samepage__ls) {
299     cpu->cd.arm.next_ic = (struct arm_instr_call *)
300     ic->arg[condition_hi[cpu->cd.arm.flags]];
301     }
302     X(b_samepage__ge) {
303     cpu->cd.arm.next_ic = (condition_ge[cpu->cd.arm.flags])?
304     (struct arm_instr_call *) ic->arg[0] :
305     (struct arm_instr_call *) ic->arg[1];
306     }
307     X(b_samepage__lt) {
308     cpu->cd.arm.next_ic = (struct arm_instr_call *)
309     ic->arg[condition_ge[cpu->cd.arm.flags]];
310     }
311     X(b_samepage__gt) {
312     cpu->cd.arm.next_ic = (condition_gt[cpu->cd.arm.flags])?
313     (struct arm_instr_call *) ic->arg[0] :
314     (struct arm_instr_call *) ic->arg[1];
315     }
316     X(b_samepage__le) {
317     cpu->cd.arm.next_ic = (struct arm_instr_call *)
318     ic->arg[condition_gt[cpu->cd.arm.flags]];
319     }
320     void (*arm_cond_instr_b_samepage[16])(struct cpu *,
321     struct arm_instr_call *) = {
322     arm_instr_b_samepage__eq, arm_instr_b_samepage__ne,
323     arm_instr_b_samepage__cs, arm_instr_b_samepage__cc,
324     arm_instr_b_samepage__mi, arm_instr_b_samepage__pl,
325     arm_instr_b_samepage__vs, arm_instr_b_samepage__vc,
326     arm_instr_b_samepage__hi, arm_instr_b_samepage__ls,
327     arm_instr_b_samepage__ge, arm_instr_b_samepage__lt,
328     arm_instr_b_samepage__gt, arm_instr_b_samepage__le,
329     arm_instr_b_samepage, arm_instr_nop };
330 dpavlin 14
331    
332     /*
333     * bx: Branch, potentially exchanging Thumb/ARM encoding
334     *
335     * arg[0] = ptr to rm
336     */
337     X(bx)
338     {
339 dpavlin 20 cpu->pc = reg(ic->arg[0]);
340 dpavlin 14 if (cpu->pc & 1) {
341     fatal("thumb: TODO\n");
342     exit(1);
343     }
344     cpu->pc &= ~3;
345    
346     /* Find the new physical page and update the translation pointers: */
347 dpavlin 18 quick_pc_to_pointers(cpu);
348 dpavlin 14 }
349     Y(bx)
350    
351    
352     /*
353     * bx_trace: As bx, but with trace enabled, arg[0] = the link register.
354     *
355     * arg[0] = ignored
356     */
357     X(bx_trace)
358     {
359 dpavlin 20 cpu->pc = cpu->cd.arm.r[ARM_LR];
360 dpavlin 14 if (cpu->pc & 1) {
361     fatal("thumb: TODO\n");
362     exit(1);
363     }
364     cpu->pc &= ~3;
365    
366     cpu_functioncall_trace_return(cpu);
367    
368     /* Find the new physical page and update the translation pointers: */
369 dpavlin 18 quick_pc_to_pointers(cpu);
370 dpavlin 14 }
371     Y(bx_trace)
372    
373    
374     /*
375     * bl: Branch and Link (to a different translated page)
376     *
377     * arg[0] = relative address
378     */
379     X(bl)
380     {
381 dpavlin 20 uint32_t pc = ((uint32_t)cpu->pc & 0xfffff000) + (int32_t)ic->arg[1];
382     cpu->cd.arm.r[ARM_LR] = pc + 4;
383 dpavlin 14
384     /* Calculate new PC from this instruction + arg[0] */
385 dpavlin 20 cpu->pc = pc + (int32_t)ic->arg[0];
386 dpavlin 14
387     /* Find the new physical page and update the translation pointers: */
388 dpavlin 18 quick_pc_to_pointers(cpu);
389 dpavlin 14 }
390     Y(bl)
391    
392    
393     /*
394     * blx: Branch and Link, potentially exchanging Thumb/ARM encoding
395     *
396     * arg[0] = ptr to rm
397     */
398     X(blx)
399     {
400 dpavlin 20 uint32_t lr = ((uint32_t)cpu->pc & 0xfffff000) + (int32_t)ic->arg[2];
401 dpavlin 14 cpu->cd.arm.r[ARM_LR] = lr;
402 dpavlin 20 cpu->pc = reg(ic->arg[0]);
403 dpavlin 14 if (cpu->pc & 1) {
404     fatal("thumb: TODO\n");
405     exit(1);
406     }
407     cpu->pc &= ~3;
408    
409     /* Find the new physical page and update the translation pointers: */
410 dpavlin 18 quick_pc_to_pointers(cpu);
411 dpavlin 14 }
412     Y(blx)
413    
414    
415     /*
416     * bl_trace: Branch and Link (to a different translated page), with trace
417     *
418     * Same as for bl.
419     */
420     X(bl_trace)
421     {
422 dpavlin 20 uint32_t pc = ((uint32_t)cpu->pc & 0xfffff000) + (int32_t)ic->arg[1];
423     cpu->cd.arm.r[ARM_LR] = pc + 4;
424 dpavlin 14
425     /* Calculate new PC from this instruction + arg[0] */
426 dpavlin 20 cpu->pc = pc + (int32_t)ic->arg[0];
427 dpavlin 14
428     cpu_functioncall_trace(cpu, cpu->pc);
429    
430     /* Find the new physical page and update the translation pointers: */
431 dpavlin 18 quick_pc_to_pointers(cpu);
432 dpavlin 14 }
433     Y(bl_trace)
434    
435    
436     /*
437     * bl_samepage: A branch + link within the same page
438     *
439     * arg[0] = pointer to new arm_instr_call
440     */
441     X(bl_samepage)
442     {
443 dpavlin 20 cpu->cd.arm.r[ARM_LR] =
444     ((uint32_t)cpu->pc & 0xfffff000) + (int32_t)ic->arg[2];
445 dpavlin 14 cpu->cd.arm.next_ic = (struct arm_instr_call *) ic->arg[0];
446     }
447     Y(bl_samepage)
448    
449    
450     /*
451     * bl_samepage_trace: Branch and Link (to the same page), with trace
452     *
453     * Same as for bl_samepage.
454     */
455     X(bl_samepage_trace)
456     {
457 dpavlin 20 uint32_t low_pc, lr = (cpu->pc & 0xfffff000) + ic->arg[2];
458 dpavlin 14
459 dpavlin 20 /* Link and branch: */
460 dpavlin 14 cpu->cd.arm.r[ARM_LR] = lr;
461     cpu->cd.arm.next_ic = (struct arm_instr_call *) ic->arg[0];
462    
463 dpavlin 20 /* Synchronize the program counter: */
464 dpavlin 14 low_pc = ((size_t)cpu->cd.arm.next_ic - (size_t)
465     cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
466 dpavlin 20 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1)
467 dpavlin 14 << ARM_INSTR_ALIGNMENT_SHIFT);
468 dpavlin 20 cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
469    
470     /* ... and show trace: */
471     cpu_functioncall_trace(cpu, cpu->pc);
472 dpavlin 14 }
473     Y(bl_samepage_trace)
474    
475    
476 dpavlin 20 /*
477     * clz: Count leading zeroes.
478     *
479     * arg[0] = ptr to rm
480     * arg[1] = ptr to rd
481     */
482     X(clz)
483     {
484     uint32_t rm = reg(ic->arg[0]);
485     int i = 32, n = 0, j;
486     while (i>0) {
487     if (rm & 0xff000000) {
488     for (j=0; j<8; j++) {
489     if (rm & 0x80000000)
490     break;
491     n ++;
492     rm <<= 1;
493     }
494     break;
495     } else {
496     rm <<= 8;
497     i -= 8;
498     n += 8;
499     }
500     }
501     reg(ic->arg[1]) = n;
502     }
503     Y(clz)
504 dpavlin 18
505    
506 dpavlin 14 /*
507     * mul: Multiplication
508     *
509     * arg[0] = ptr to rd
510     * arg[1] = ptr to rm
511     * arg[2] = ptr to rs
512     */
513     X(mul)
514     {
515     reg(ic->arg[0]) = reg(ic->arg[1]) * reg(ic->arg[2]);
516     }
517     Y(mul)
518     X(muls)
519     {
520 dpavlin 18 uint32_t result;
521     result = reg(ic->arg[1]) * reg(ic->arg[2]);
522 dpavlin 20 cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N);
523 dpavlin 14 if (result == 0)
524 dpavlin 20 cpu->cd.arm.flags |= ARM_F_Z;
525 dpavlin 14 if (result & 0x80000000)
526 dpavlin 20 cpu->cd.arm.flags |= ARM_F_N;
527 dpavlin 14 reg(ic->arg[0]) = result;
528     }
529     Y(muls)
530    
531    
532     /*
533     * mla: Multiplication with addition
534     *
535     * arg[0] = copy of instruction word
536     */
537     X(mla)
538     {
539     /* xxxx0000 00ASdddd nnnnssss 1001mmmm (Rd,Rm,Rs[,Rn]) */
540     uint32_t iw = ic->arg[0];
541 dpavlin 18 int rd, rs, rn, rm;
542     rd = (iw >> 16) & 15; rn = (iw >> 12) & 15,
543     rs = (iw >> 8) & 15; rm = iw & 15;
544 dpavlin 14 cpu->cd.arm.r[rd] = cpu->cd.arm.r[rm] * cpu->cd.arm.r[rs]
545     + cpu->cd.arm.r[rn];
546     }
547     Y(mla)
548     X(mlas)
549     {
550     /* xxxx0000 00ASdddd nnnnssss 1001mmmm (Rd,Rm,Rs[,Rn]) */
551     uint32_t iw = ic->arg[0];
552 dpavlin 18 int rd, rs, rn, rm;
553     rd = (iw >> 16) & 15; rn = (iw >> 12) & 15,
554     rs = (iw >> 8) & 15; rm = iw & 15;
555 dpavlin 14 cpu->cd.arm.r[rd] = cpu->cd.arm.r[rm] * cpu->cd.arm.r[rs]
556     + cpu->cd.arm.r[rn];
557 dpavlin 20 cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N);
558 dpavlin 14 if (cpu->cd.arm.r[rd] == 0)
559 dpavlin 20 cpu->cd.arm.flags |= ARM_F_Z;
560 dpavlin 14 if (cpu->cd.arm.r[rd] & 0x80000000)
561 dpavlin 20 cpu->cd.arm.flags |= ARM_F_N;
562 dpavlin 14 }
563     Y(mlas)
564    
565    
566     /*
567     * mull: Long multiplication
568     *
569     * arg[0] = copy of instruction word
570     */
571     X(mull)
572     {
573     /* xxxx0000 1UAShhhh llllssss 1001mmmm */
574 dpavlin 18 uint32_t iw; uint64_t tmp; int u_bit, a_bit;
575     iw = ic->arg[0];
576 dpavlin 20 u_bit = iw & 0x00400000; a_bit = iw & 0x00200000;
577 dpavlin 18 tmp = cpu->cd.arm.r[iw & 15];
578 dpavlin 14 if (u_bit)
579     tmp = (int64_t)(int32_t)tmp
580     * (int64_t)(int32_t)cpu->cd.arm.r[(iw >> 8) & 15];
581     else
582     tmp *= (uint64_t)cpu->cd.arm.r[(iw >> 8) & 15];
583     if (a_bit) {
584     uint64_t x = ((uint64_t)cpu->cd.arm.r[(iw >> 16) & 15] << 32)
585     | cpu->cd.arm.r[(iw >> 12) & 15];
586     x += tmp;
587     cpu->cd.arm.r[(iw >> 16) & 15] = (x >> 32);
588     cpu->cd.arm.r[(iw >> 12) & 15] = x;
589     } else {
590     cpu->cd.arm.r[(iw >> 16) & 15] = (tmp >> 32);
591     cpu->cd.arm.r[(iw >> 12) & 15] = tmp;
592     }
593     }
594     Y(mull)
595    
596    
597     /*
598 dpavlin 22 * smulXY: 16-bit * 16-bit multiplication (32-bit result)
599     *
600     * arg[0] = ptr to rm
601     * arg[1] = ptr to rs
602     * arg[2] = ptr to rd
603     */
604     X(smulbb)
605     {
606     reg(ic->arg[2]) = (int32_t)(int16_t)reg(ic->arg[0]) *
607     (int32_t)(int16_t)reg(ic->arg[1]);
608     }
609     Y(smulbb)
610     X(smultb)
611     {
612     reg(ic->arg[2]) = (int32_t)(int16_t)(reg(ic->arg[0]) >> 16) *
613     (int32_t)(int16_t)reg(ic->arg[1]);
614     }
615     Y(smultb)
616     X(smulbt)
617     {
618     reg(ic->arg[2]) = (int32_t)(int16_t)reg(ic->arg[0]) *
619     (int32_t)(int16_t)(reg(ic->arg[1]) >> 16);
620     }
621     Y(smulbt)
622     X(smultt)
623     {
624     reg(ic->arg[2]) = (int32_t)(int16_t)(reg(ic->arg[0]) >> 16) *
625     (int32_t)(int16_t)(reg(ic->arg[1]) >> 16);
626     }
627     Y(smultt)
628    
629    
630     /*
631 dpavlin 14 * mov_reg_reg: Move a register to another.
632     *
633     * arg[0] = ptr to source register
634     * arg[1] = ptr to destination register
635     */
636     X(mov_reg_reg)
637     {
638     reg(ic->arg[1]) = reg(ic->arg[0]);
639     }
640     Y(mov_reg_reg)
641    
642    
643     /*
644 dpavlin 20 * mov_reg_pc: Move the PC register to a normal register.
645     *
646     * arg[0] = offset compared to start of current page + 8
647     * arg[1] = ptr to destination register
648     */
649     X(mov_reg_pc)
650     {
651     reg(ic->arg[1]) = ((uint32_t)cpu->pc&0xfffff000) + (int32_t)ic->arg[0];
652     }
653     Y(mov_reg_pc)
654    
655    
656     /*
657 dpavlin 14 * ret_trace: "mov pc,lr" with trace enabled
658 dpavlin 18 * ret: "mov pc,lr" without trace enabled
659 dpavlin 14 *
660     * arg[0] = ignored
661     */
662     X(ret_trace)
663     {
664 dpavlin 18 uint32_t old_pc, mask_within_page;
665 dpavlin 20 old_pc = cpu->pc;
666 dpavlin 18 mask_within_page = ((ARM_IC_ENTRIES_PER_PAGE-1)
667 dpavlin 14 << ARM_INSTR_ALIGNMENT_SHIFT) |
668     ((1 << ARM_INSTR_ALIGNMENT_SHIFT) - 1);
669    
670     /* Update the PC register: */
671 dpavlin 20 cpu->pc = cpu->cd.arm.r[ARM_LR];
672 dpavlin 14
673     cpu_functioncall_trace_return(cpu);
674    
675     /*
676     * Is this a return to code within the same page? Then there is no
677     * need to update all pointers, just next_ic.
678     */
679     if ((old_pc & ~mask_within_page) == (cpu->pc & ~mask_within_page)) {
680     cpu->cd.arm.next_ic = cpu->cd.arm.cur_ic_page +
681     ((cpu->pc & mask_within_page) >> ARM_INSTR_ALIGNMENT_SHIFT);
682     } else {
683     /* Find the new physical page and update pointers: */
684 dpavlin 18 quick_pc_to_pointers(cpu);
685 dpavlin 14 }
686     }
687     Y(ret_trace)
688 dpavlin 18 X(ret)
689     {
690 dpavlin 20 cpu->pc = cpu->cd.arm.r[ARM_LR];
691 dpavlin 18 quick_pc_to_pointers(cpu);
692     }
693     Y(ret)
694 dpavlin 14
695    
696     /*
697     * msr: Move to status register from a normal register or immediate value.
698     *
699     * arg[0] = immediate value
700     * arg[1] = mask
701     * arg[2] = pointer to rm
702     *
703     * msr_imm and msr_imm_spsr use arg[1] and arg[0].
704     * msr and msr_spsr use arg[1] and arg[2].
705     */
706     X(msr_imm)
707     {
708     uint32_t mask = ic->arg[1];
709     int switch_register_banks = (mask & ARM_FLAG_MODE) &&
710     ((cpu->cd.arm.cpsr & ARM_FLAG_MODE) !=
711     (ic->arg[0] & ARM_FLAG_MODE));
712     uint32_t new_value = ic->arg[0];
713    
714 dpavlin 20 cpu->cd.arm.cpsr &= 0x0fffffff;
715     cpu->cd.arm.cpsr |= (cpu->cd.arm.flags << 28);
716    
717 dpavlin 14 if (switch_register_banks)
718     arm_save_register_bank(cpu);
719    
720     cpu->cd.arm.cpsr &= ~mask;
721     cpu->cd.arm.cpsr |= (new_value & mask);
722    
723 dpavlin 20 cpu->cd.arm.flags = cpu->cd.arm.cpsr >> 28;
724    
725 dpavlin 14 if (switch_register_banks)
726     arm_load_register_bank(cpu);
727     }
728     Y(msr_imm)
729     X(msr)
730     {
731     ic->arg[0] = reg(ic->arg[2]);
732     instr(msr_imm)(cpu, ic);
733     }
734     Y(msr)
735     X(msr_imm_spsr)
736     {
737     uint32_t mask = ic->arg[1];
738     uint32_t new_value = ic->arg[0];
739     switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) {
740     case ARM_MODE_FIQ32:
741     cpu->cd.arm.spsr_fiq &= ~mask;
742     cpu->cd.arm.spsr_fiq |= (new_value & mask);
743     break;
744     case ARM_MODE_ABT32:
745     cpu->cd.arm.spsr_abt &= ~mask;
746     cpu->cd.arm.spsr_abt |= (new_value & mask);
747     break;
748     case ARM_MODE_UND32:
749     cpu->cd.arm.spsr_und &= ~mask;
750     cpu->cd.arm.spsr_und |= (new_value & mask);
751     break;
752     case ARM_MODE_IRQ32:
753     cpu->cd.arm.spsr_irq &= ~mask;
754     cpu->cd.arm.spsr_irq |= (new_value & mask);
755     break;
756     case ARM_MODE_SVC32:
757     cpu->cd.arm.spsr_svc &= ~mask;
758     cpu->cd.arm.spsr_svc |= (new_value & mask);
759     break;
760     default:fatal("msr_spsr: unimplemented mode %i\n",
761     cpu->cd.arm.cpsr & ARM_FLAG_MODE);
762     {
763     /* Synchronize the program counter: */
764     uint32_t old_pc, low_pc = ((size_t)ic - (size_t)
765     cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
766 dpavlin 20 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
767     cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
768     old_pc = cpu->pc;
769 dpavlin 24 printf("msr_spsr: old pc = 0x%08"PRIx32"\n", old_pc);
770 dpavlin 14 }
771     exit(1);
772     }
773     }
774     Y(msr_imm_spsr)
775     X(msr_spsr)
776     {
777     ic->arg[0] = reg(ic->arg[2]);
778     instr(msr_imm_spsr)(cpu, ic);
779     }
780     Y(msr_spsr)
781    
782    
783     /*
784     * mrs: Move from status/flag register to a normal register.
785     *
786     * arg[0] = pointer to rd
787     */
788     X(mrs)
789     {
790 dpavlin 20 cpu->cd.arm.cpsr &= 0x0fffffff;
791     cpu->cd.arm.cpsr |= (cpu->cd.arm.flags << 28);
792 dpavlin 14 reg(ic->arg[0]) = cpu->cd.arm.cpsr;
793     }
794     Y(mrs)
795    
796    
797     /*
798 dpavlin 20 * mrs: Move from saved status/flag register to a normal register.
799 dpavlin 14 *
800     * arg[0] = pointer to rd
801     */
802     X(mrs_spsr)
803     {
804     switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) {
805     case ARM_MODE_FIQ32: reg(ic->arg[0]) = cpu->cd.arm.spsr_fiq; break;
806     case ARM_MODE_ABT32: reg(ic->arg[0]) = cpu->cd.arm.spsr_abt; break;
807     case ARM_MODE_UND32: reg(ic->arg[0]) = cpu->cd.arm.spsr_und; break;
808     case ARM_MODE_IRQ32: reg(ic->arg[0]) = cpu->cd.arm.spsr_irq; break;
809     case ARM_MODE_SVC32: reg(ic->arg[0]) = cpu->cd.arm.spsr_svc; break;
810     case ARM_MODE_USR32:
811     case ARM_MODE_SYS32: reg(ic->arg[0]) = 0; break;
812     default:fatal("mrs_spsr: unimplemented mode %i\n",
813     cpu->cd.arm.cpsr & ARM_FLAG_MODE);
814     exit(1);
815     }
816     }
817     Y(mrs_spsr)
818    
819    
820     /*
821     * mcr_mrc: Coprocessor move
822     * cdp: Coprocessor operation
823     *
824     * arg[0] = copy of the instruction word
825     */
826     X(mcr_mrc) {
827 dpavlin 20 uint32_t low_pc = ((size_t)ic - (size_t)
828 dpavlin 14 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
829 dpavlin 20 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
830     cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
831 dpavlin 14 arm_mcr_mrc(cpu, ic->arg[0]);
832     }
833     Y(mcr_mrc)
834     X(cdp) {
835 dpavlin 20 uint32_t low_pc = ((size_t)ic - (size_t)
836 dpavlin 14 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
837 dpavlin 20 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
838     cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
839 dpavlin 14 arm_cdp(cpu, ic->arg[0]);
840     }
841     Y(cdp)
842    
843    
844     /*
845     * openfirmware:
846     */
847     X(openfirmware)
848     {
849 dpavlin 20 /* TODO: sync pc? */
850 dpavlin 14 of_emul(cpu);
851 dpavlin 20 cpu->pc = cpu->cd.arm.r[ARM_LR];
852 dpavlin 14 if (cpu->machine->show_trace_tree)
853     cpu_functioncall_trace_return(cpu);
854 dpavlin 18 quick_pc_to_pointers(cpu);
855 dpavlin 14 }
856    
857    
858     /*
859 dpavlin 20 * reboot:
860     */
861     X(reboot)
862     {
863     cpu->running = 0;
864     cpu->n_translated_instrs --;
865     cpu->cd.arm.next_ic = &nothing_call;
866     }
867    
868    
869     /*
870 dpavlin 14 * swi_useremul: Syscall.
871     *
872     * arg[0] = swi number
873     */
874     X(swi_useremul)
875     {
876     /* Synchronize the program counter: */
877     uint32_t old_pc, low_pc = ((size_t)ic - (size_t)
878     cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
879 dpavlin 20 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1)
880 dpavlin 14 << ARM_INSTR_ALIGNMENT_SHIFT);
881 dpavlin 20 cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
882     old_pc = cpu->pc;
883 dpavlin 14
884     useremul_syscall(cpu, ic->arg[0]);
885    
886     if (!cpu->running) {
887     cpu->n_translated_instrs --;
888     cpu->cd.arm.next_ic = &nothing_call;
889     } else if (cpu->pc != old_pc) {
890     /* PC was changed by the SWI call. Find the new physical
891     page and update the translation pointers: */
892 dpavlin 18 quick_pc_to_pointers(cpu);
893 dpavlin 14 }
894     }
895     Y(swi_useremul)
896    
897    
898     /*
899     * swi: Software interrupt.
900     */
901     X(swi)
902     {
903 dpavlin 20 /* Synchronize the program counter first: */
904     cpu->pc &= 0xfffff000;
905     cpu->pc += ic->arg[0];
906 dpavlin 14 arm_exception(cpu, ARM_EXCEPTION_SWI);
907     }
908     Y(swi)
909    
910    
911     /*
912 dpavlin 20 * und: Undefined instruction.
913     */
914     X(und)
915     {
916     /* Synchronize the program counter first: */
917     cpu->pc &= 0xfffff000;
918     cpu->pc += ic->arg[0];
919     arm_exception(cpu, ARM_EXCEPTION_UND);
920     }
921     Y(und)
922    
923    
924     /*
925 dpavlin 14 * swp, swpb: Swap (word or byte).
926     *
927     * arg[0] = ptr to rd
928     * arg[1] = ptr to rm
929     * arg[2] = ptr to rn
930     */
931     X(swp)
932     {
933     uint32_t addr = reg(ic->arg[2]), data, data2;
934     unsigned char d[4];
935 dpavlin 20
936 dpavlin 14 /* Synchronize the program counter: */
937     uint32_t low_pc = ((size_t)ic - (size_t)
938     cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
939 dpavlin 20 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
940     cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
941 dpavlin 14
942     if (!cpu->memory_rw(cpu, cpu->mem, addr, d, sizeof(d), MEM_READ,
943     CACHE_DATA)) {
944     fatal("swp: load failed\n");
945     return;
946     }
947     data = d[0] + (d[1] << 8) + (d[2] << 16) + (d[3] << 24);
948     data2 = reg(ic->arg[1]);
949     d[0] = data2; d[1] = data2 >> 8; d[2] = data2 >> 16; d[3] = data2 >> 24;
950     if (!cpu->memory_rw(cpu, cpu->mem, addr, d, sizeof(d), MEM_WRITE,
951     CACHE_DATA)) {
952     fatal("swp: store failed\n");
953     return;
954     }
955     reg(ic->arg[0]) = data;
956     }
957     Y(swp)
958     X(swpb)
959     {
960     uint32_t addr = reg(ic->arg[2]), data;
961     unsigned char d[1];
962 dpavlin 20
963 dpavlin 14 /* Synchronize the program counter: */
964     uint32_t low_pc = ((size_t)ic - (size_t)
965     cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
966 dpavlin 20 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
967     cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
968 dpavlin 14
969     if (!cpu->memory_rw(cpu, cpu->mem, addr, d, sizeof(d), MEM_READ,
970     CACHE_DATA)) {
971     fatal("swp: load failed\n");
972     return;
973     }
974     data = d[0];
975     d[0] = reg(ic->arg[1]);
976     if (!cpu->memory_rw(cpu, cpu->mem, addr, d, sizeof(d), MEM_WRITE,
977     CACHE_DATA)) {
978     fatal("swp: store failed\n");
979     return;
980     }
981     reg(ic->arg[0]) = data;
982     }
983     Y(swpb)
984    
985    
986     extern void (*arm_load_store_instr[1024])(struct cpu *,
987     struct arm_instr_call *);
988 dpavlin 20 X(store_w1_word_u1_p0_imm);
989 dpavlin 14 X(store_w0_byte_u1_p0_imm);
990     X(store_w0_word_u1_p0_imm);
991 dpavlin 20 X(store_w0_word_u1_p1_imm);
992     X(load_w1_word_u1_p0_imm);
993 dpavlin 18 X(load_w0_word_u1_p0_imm);
994     X(load_w0_byte_u1_p1_imm);
995     X(load_w0_byte_u1_p1_reg);
996 dpavlin 20 X(load_w1_byte_u1_p1_imm);
997 dpavlin 14
998     extern void (*arm_load_store_instr_pc[1024])(struct cpu *,
999     struct arm_instr_call *);
1000    
1001     extern void (*arm_load_store_instr_3[2048])(struct cpu *,
1002     struct arm_instr_call *);
1003    
1004     extern void (*arm_load_store_instr_3_pc[2048])(struct cpu *,
1005     struct arm_instr_call *);
1006    
1007 dpavlin 16 extern uint32_t (*arm_r[8192])(struct cpu *, struct arm_instr_call *);
1008 dpavlin 20 extern void arm_r_r3_t0_c0(void);
1009 dpavlin 16
1010 dpavlin 14 extern void (*arm_dpi_instr[2 * 2 * 2 * 16 * 16])(struct cpu *,
1011     struct arm_instr_call *);
1012 dpavlin 20 extern void (*arm_dpi_instr_regshort[2 * 16 * 16])(struct cpu *,
1013     struct arm_instr_call *);
1014 dpavlin 14 X(cmps);
1015 dpavlin 20 X(teqs);
1016     X(tsts);
1017 dpavlin 14 X(sub);
1018 dpavlin 18 X(add);
1019 dpavlin 14 X(subs);
1020 dpavlin 20 X(eor_regshort);
1021     X(cmps_regshort);
1022 dpavlin 14
1023    
1024 dpavlin 20 #include "cpu_arm_instr_misc.c"
1025 dpavlin 14
1026 dpavlin 20
1027 dpavlin 14 /*
1028     * bdt_load: Block Data Transfer, Load
1029     *
1030     * arg[0] = pointer to uint32_t in host memory, pointing to the base register
1031     * arg[1] = 32-bit instruction word. Most bits are read from this.
1032     */
1033     X(bdt_load)
1034     {
1035     unsigned char data[4];
1036     uint32_t *np = (uint32_t *)ic->arg[0];
1037     uint32_t addr = *np, low_pc;
1038     unsigned char *page;
1039     uint32_t iw = ic->arg[1]; /* xxxx100P USWLnnnn llllllll llllllll */
1040     int p_bit = iw & 0x01000000;
1041     int u_bit = iw & 0x00800000;
1042     int s_bit = iw & 0x00400000;
1043     int w_bit = iw & 0x00200000;
1044 dpavlin 16 int i, return_flag = 0;
1045 dpavlin 14 uint32_t new_values[16];
1046    
1047 dpavlin 18 #ifdef GATHER_BDT_STATISTICS
1048     if (!s_bit)
1049     update_bdt_statistics(iw);
1050     #endif
1051    
1052 dpavlin 14 /* Synchronize the program counter: */
1053     low_pc = ((size_t)ic - (size_t)
1054     cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
1055 dpavlin 20 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
1056     cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
1057 dpavlin 14
1058     if (s_bit) {
1059 dpavlin 16 /* Load to USR registers: */
1060 dpavlin 14 if ((cpu->cd.arm.cpsr & ARM_FLAG_MODE) == ARM_MODE_USR32) {
1061     fatal("[ bdt_load: s-bit: in usermode? ]\n");
1062     s_bit = 0;
1063 dpavlin 16 }
1064     if (iw & 0x8000) {
1065 dpavlin 14 s_bit = 0;
1066     return_flag = 1;
1067     }
1068     }
1069    
1070     for (i=(u_bit? 0 : 15); i>=0 && i<=15; i+=(u_bit? 1 : -1)) {
1071     uint32_t value;
1072    
1073     if (!((iw >> i) & 1)) {
1074     /* Skip register i: */
1075     continue;
1076     }
1077    
1078     if (p_bit) {
1079     if (u_bit)
1080     addr += sizeof(uint32_t);
1081     else
1082     addr -= sizeof(uint32_t);
1083     }
1084    
1085     page = cpu->cd.arm.host_load[addr >> 12];
1086     if (page != NULL) {
1087     uint32_t *p32 = (uint32_t *) page;
1088     value = p32[(addr & 0xfff) >> 2];
1089     /* Change byte order of value if
1090     host and emulated endianness differ: */
1091     #ifdef HOST_LITTLE_ENDIAN
1092     if (cpu->byte_order == EMUL_BIG_ENDIAN)
1093     #else
1094     if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
1095     #endif
1096     value = ((value & 0xff) << 24) |
1097     ((value & 0xff00) << 8) |
1098     ((value & 0xff0000) >> 8) |
1099     ((value & 0xff000000) >> 24);
1100     } else {
1101     if (!cpu->memory_rw(cpu, cpu->mem, addr, data,
1102     sizeof(data), MEM_READ, CACHE_DATA)) {
1103     /* load failed */
1104     return;
1105     }
1106     if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
1107     value = data[0] +
1108     (data[1] << 8) + (data[2] << 16)
1109     + (data[3] << 24);
1110     } else {
1111     value = data[3] +
1112     (data[2] << 8) + (data[1] << 16)
1113     + (data[0] << 24);
1114     }
1115     }
1116    
1117     new_values[i] = value;
1118    
1119     if (!p_bit) {
1120     if (u_bit)
1121     addr += sizeof(uint32_t);
1122     else
1123     addr -= sizeof(uint32_t);
1124     }
1125     }
1126    
1127     for (i=(u_bit? 0 : 15); i>=0 && i<=15; i+=(u_bit? 1 : -1)) {
1128     if (!((iw >> i) & 1)) {
1129     /* Skip register i: */
1130     continue;
1131     }
1132    
1133     if (!s_bit) {
1134     cpu->cd.arm.r[i] = new_values[i];
1135     } else {
1136 dpavlin 16 switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) {
1137 dpavlin 14 case ARM_MODE_USR32:
1138     case ARM_MODE_SYS32:
1139 dpavlin 16 cpu->cd.arm.r[i] = new_values[i];
1140 dpavlin 14 break;
1141     case ARM_MODE_FIQ32:
1142     if (i >= 8 && i <= 14)
1143 dpavlin 16 cpu->cd.arm.default_r8_r14[i-8] =
1144 dpavlin 14 new_values[i];
1145     else
1146     cpu->cd.arm.r[i] = new_values[i];
1147     break;
1148     case ARM_MODE_SVC32:
1149     case ARM_MODE_ABT32:
1150     case ARM_MODE_UND32:
1151 dpavlin 16 case ARM_MODE_IRQ32:
1152 dpavlin 14 if (i >= 13 && i <= 14)
1153 dpavlin 16 cpu->cd.arm.default_r8_r14[i-8] =
1154 dpavlin 14 new_values[i];
1155     else
1156     cpu->cd.arm.r[i] = new_values[i];
1157     break;
1158     }
1159     }
1160     }
1161    
1162     if (w_bit)
1163     *np = addr;
1164    
1165     if (return_flag) {
1166     uint32_t new_cpsr;
1167     int switch_register_banks;
1168    
1169     switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) {
1170     case ARM_MODE_FIQ32:
1171     new_cpsr = cpu->cd.arm.spsr_fiq; break;
1172     case ARM_MODE_ABT32:
1173     new_cpsr = cpu->cd.arm.spsr_abt; break;
1174     case ARM_MODE_UND32:
1175     new_cpsr = cpu->cd.arm.spsr_und; break;
1176     case ARM_MODE_IRQ32:
1177     new_cpsr = cpu->cd.arm.spsr_irq; break;
1178     case ARM_MODE_SVC32:
1179     new_cpsr = cpu->cd.arm.spsr_svc; break;
1180     default:fatal("bdt_load: unimplemented mode %i\n",
1181     cpu->cd.arm.cpsr & ARM_FLAG_MODE);
1182     exit(1);
1183     }
1184    
1185     switch_register_banks = (cpu->cd.arm.cpsr & ARM_FLAG_MODE) !=
1186     (new_cpsr & ARM_FLAG_MODE);
1187    
1188     if (switch_register_banks)
1189     arm_save_register_bank(cpu);
1190    
1191     cpu->cd.arm.cpsr = new_cpsr;
1192 dpavlin 20 cpu->cd.arm.flags = cpu->cd.arm.cpsr >> 28;
1193 dpavlin 14
1194     if (switch_register_banks)
1195     arm_load_register_bank(cpu);
1196     }
1197    
1198     /* NOTE: Special case: Loading the PC */
1199     if (iw & 0x8000) {
1200 dpavlin 20 cpu->pc = cpu->cd.arm.r[ARM_PC] & 0xfffffffc;
1201 dpavlin 14 if (cpu->machine->show_trace_tree)
1202     cpu_functioncall_trace_return(cpu);
1203     /* TODO: There is no need to update the
1204     pointers if this is a return to the
1205     same page! */
1206     /* Find the new physical page and update the
1207     translation pointers: */
1208 dpavlin 18 quick_pc_to_pointers(cpu);
1209 dpavlin 14 }
1210     }
1211     Y(bdt_load)
1212    
1213    
1214     /*
1215     * bdt_store: Block Data Transfer, Store
1216     *
1217     * arg[0] = pointer to uint32_t in host memory, pointing to the base register
1218     * arg[1] = 32-bit instruction word. Most bits are read from this.
1219     */
1220     X(bdt_store)
1221     {
1222     unsigned char data[4];
1223     uint32_t *np = (uint32_t *)ic->arg[0];
1224     uint32_t low_pc, value, addr = *np;
1225     uint32_t iw = ic->arg[1]; /* xxxx100P USWLnnnn llllllll llllllll */
1226     unsigned char *page;
1227     int p_bit = iw & 0x01000000;
1228     int u_bit = iw & 0x00800000;
1229     int s_bit = iw & 0x00400000;
1230     int w_bit = iw & 0x00200000;
1231 dpavlin 16 int i;
1232 dpavlin 14
1233 dpavlin 18 #ifdef GATHER_BDT_STATISTICS
1234     if (!s_bit)
1235     update_bdt_statistics(iw);
1236     #endif
1237    
1238 dpavlin 14 /* Synchronize the program counter: */
1239     low_pc = ((size_t)ic - (size_t)
1240     cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
1241 dpavlin 20 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
1242     cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
1243 dpavlin 14
1244     for (i=(u_bit? 0 : 15); i>=0 && i<=15; i+=(u_bit? 1 : -1)) {
1245     if (!((iw >> i) & 1)) {
1246     /* Skip register i: */
1247     continue;
1248     }
1249    
1250     value = cpu->cd.arm.r[i];
1251    
1252     if (s_bit) {
1253 dpavlin 16 switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) {
1254 dpavlin 14 case ARM_MODE_FIQ32:
1255     if (i >= 8 && i <= 14)
1256 dpavlin 16 value = cpu->cd.arm.default_r8_r14[i-8];
1257 dpavlin 14 break;
1258     case ARM_MODE_ABT32:
1259     case ARM_MODE_UND32:
1260     case ARM_MODE_IRQ32:
1261     case ARM_MODE_SVC32:
1262     if (i >= 13 && i <= 14)
1263 dpavlin 16 value = cpu->cd.arm.default_r8_r14[i-8];
1264 dpavlin 14 break;
1265     case ARM_MODE_USR32:
1266     case ARM_MODE_SYS32:
1267     break;
1268     }
1269     }
1270    
1271 dpavlin 20 /* NOTE/TODO: 8 vs 12 on some ARMs */
1272 dpavlin 14 if (i == ARM_PC)
1273 dpavlin 20 value = cpu->pc + 12;
1274 dpavlin 14
1275     if (p_bit) {
1276     if (u_bit)
1277     addr += sizeof(uint32_t);
1278     else
1279     addr -= sizeof(uint32_t);
1280     }
1281    
1282     page = cpu->cd.arm.host_store[addr >> 12];
1283     if (page != NULL) {
1284     uint32_t *p32 = (uint32_t *) page;
1285     /* Change byte order of value if
1286     host and emulated endianness differ: */
1287     #ifdef HOST_LITTLE_ENDIAN
1288     if (cpu->byte_order == EMUL_BIG_ENDIAN)
1289     #else
1290     if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
1291     #endif
1292     value = ((value & 0xff) << 24) |
1293     ((value & 0xff00) << 8) |
1294     ((value & 0xff0000) >> 8) |
1295     ((value & 0xff000000) >> 24);
1296     p32[(addr & 0xfff) >> 2] = value;
1297     } else {
1298     if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
1299     data[0] = value;
1300     data[1] = value >> 8;
1301     data[2] = value >> 16;
1302     data[3] = value >> 24;
1303     } else {
1304     data[0] = value >> 24;
1305     data[1] = value >> 16;
1306     data[2] = value >> 8;
1307     data[3] = value;
1308     }
1309     if (!cpu->memory_rw(cpu, cpu->mem, addr, data,
1310     sizeof(data), MEM_WRITE, CACHE_DATA)) {
1311     /* store failed */
1312     return;
1313     }
1314     }
1315    
1316     if (!p_bit) {
1317     if (u_bit)
1318     addr += sizeof(uint32_t);
1319     else
1320     addr -= sizeof(uint32_t);
1321     }
1322     }
1323    
1324     if (w_bit)
1325     *np = addr;
1326     }
1327     Y(bdt_store)
1328    
1329    
1330 dpavlin 18 /* Various load/store multiple instructions: */
1331 dpavlin 24 extern uint32_t *multi_opcode[256];
1332     extern void (**multi_opcode_f[256])(struct cpu *, struct arm_instr_call *);
1333 dpavlin 20 X(multi_0x08b15018);
1334     X(multi_0x08ac000c__ge);
1335     X(multi_0x08a05018);
1336 dpavlin 18
1337    
1338 dpavlin 14 /*****************************************************************************/
1339    
1340    
1341     /*
1342 dpavlin 18 * netbsd_memset:
1343     *
1344     * The core of a NetBSD/arm memset.
1345     *
1346     * f01bc420: e25XX080 subs rX,rX,#0x80
1347     * f01bc424: a8ac000c stmgeia ip!,{r2,r3} (16 of these)
1348     * ..
1349     * f01bc464: caffffed bgt 0xf01bc420 <memset+0x38>
1350     */
1351     X(netbsd_memset)
1352     {
1353     unsigned char *page;
1354     uint32_t addr;
1355    
1356     do {
1357     addr = cpu->cd.arm.r[ARM_IP];
1358    
1359     instr(subs)(cpu, ic);
1360    
1361 dpavlin 20 if (((cpu->cd.arm.flags & ARM_F_N)?1:0) !=
1362     ((cpu->cd.arm.flags & ARM_F_V)?1:0)) {
1363 dpavlin 18 cpu->n_translated_instrs += 16;
1364     /* Skip the store multiples: */
1365     cpu->cd.arm.next_ic = &ic[17];
1366     return;
1367     }
1368    
1369     /* Crossing a page boundary? Then continue non-combined. */
1370     if ((addr & 0xfff) + 128 > 0x1000)
1371     return;
1372    
1373     /* R2/R3 non-zero? Not allowed here. */
1374     if (cpu->cd.arm.r[2] != 0 || cpu->cd.arm.r[3] != 0)
1375     return;
1376    
1377     /* printf("addr = 0x%08x\n", addr); */
1378    
1379     page = cpu->cd.arm.host_store[addr >> 12];
1380     /* No page translation? Continue non-combined. */
1381     if (page == NULL)
1382     return;
1383    
1384     /* Clear: */
1385     memset(page + (addr & 0xfff), 0, 128);
1386     cpu->cd.arm.r[ARM_IP] = addr + 128;
1387     cpu->n_translated_instrs += 16;
1388    
1389     /* Branch back if greater: */
1390     cpu->n_translated_instrs += 1;
1391 dpavlin 20 } while (((cpu->cd.arm.flags & ARM_F_N)?1:0) ==
1392     ((cpu->cd.arm.flags & ARM_F_V)?1:0) &&
1393     !(cpu->cd.arm.flags & ARM_F_Z));
1394 dpavlin 18
1395     /* Continue at the instruction after the bgt: */
1396     cpu->cd.arm.next_ic = &ic[18];
1397     }
1398    
1399    
1400     /*
1401     * netbsd_memcpy:
1402     *
1403     * The core of a NetBSD/arm memcpy.
1404     *
1405     * f01bc530: e8b15018 ldmia r1!,{r3,r4,ip,lr}
1406     * f01bc534: e8a05018 stmia r0!,{r3,r4,ip,lr}
1407     * f01bc538: e8b15018 ldmia r1!,{r3,r4,ip,lr}
1408     * f01bc53c: e8a05018 stmia r0!,{r3,r4,ip,lr}
1409     * f01bc540: e2522020 subs r2,r2,#0x20
1410     * f01bc544: aafffff9 bge 0xf01bc530
1411     */
1412     X(netbsd_memcpy)
1413     {
1414     unsigned char *page_0, *page_1;
1415     uint32_t addr_r0, addr_r1;
1416    
1417     do {
1418     addr_r0 = cpu->cd.arm.r[0];
1419     addr_r1 = cpu->cd.arm.r[1];
1420    
1421     /* printf("addr_r0 = %08x r1 = %08x\n", addr_r0, addr_r1); */
1422    
1423     /* Crossing a page boundary? Then continue non-combined. */
1424     if ((addr_r0 & 0xfff) + 32 > 0x1000 ||
1425     (addr_r1 & 0xfff) + 32 > 0x1000) {
1426     instr(multi_0x08b15018)(cpu, ic);
1427     return;
1428     }
1429    
1430     page_0 = cpu->cd.arm.host_store[addr_r0 >> 12];
1431     page_1 = cpu->cd.arm.host_store[addr_r1 >> 12];
1432    
1433     /* No page translations? Continue non-combined. */
1434     if (page_0 == NULL || page_1 == NULL) {
1435     instr(multi_0x08b15018)(cpu, ic);
1436     return;
1437     }
1438    
1439     memcpy(page_0 + (addr_r0 & 0xfff),
1440     page_1 + (addr_r1 & 0xfff), 32);
1441     cpu->cd.arm.r[0] = addr_r0 + 32;
1442     cpu->cd.arm.r[1] = addr_r1 + 32;
1443    
1444     cpu->n_translated_instrs += 4;
1445    
1446     instr(subs)(cpu, ic + 4);
1447     cpu->n_translated_instrs ++;
1448    
1449     /* Loop while greater or equal: */
1450     cpu->n_translated_instrs ++;
1451 dpavlin 20 } while (((cpu->cd.arm.flags & ARM_F_N)?1:0) ==
1452     ((cpu->cd.arm.flags & ARM_F_V)?1:0));
1453 dpavlin 18
1454     /* Continue at the instruction after the bge: */
1455     cpu->cd.arm.next_ic = &ic[6];
1456     cpu->n_translated_instrs --;
1457     }
1458    
1459    
1460     /*
1461     * netbsd_cacheclean:
1462     *
1463     * The core of a NetBSD/arm cache clean routine, variant 1:
1464     *
1465     * f015f88c: e4902020 ldr r2,[r0],#32
1466     * f015f890: e2511020 subs r1,r1,#0x20
1467     * f015f894: 1afffffc bne 0xf015f88c
1468     * f015f898: ee070f9a mcr 15,0,r0,cr7,cr10,4
1469     */
1470     X(netbsd_cacheclean)
1471     {
1472     uint32_t r1 = cpu->cd.arm.r[1];
1473     cpu->n_translated_instrs += ((r1 >> 5) * 3);
1474 dpavlin 20 cpu->cd.arm.r[0] += r1;
1475     cpu->cd.arm.r[1] = 0;
1476 dpavlin 18 cpu->cd.arm.next_ic = &ic[4];
1477     }
1478    
1479    
1480     /*
1481     * netbsd_cacheclean2:
1482     *
1483     * The core of a NetBSD/arm cache clean routine, variant 2:
1484     *
1485     * f015f93c: ee070f3a mcr 15,0,r0,cr7,cr10,1
1486     * f015f940: ee070f36 mcr 15,0,r0,cr7,cr6,1
1487     * f015f944: e2800020 add r0,r0,#0x20
1488     * f015f948: e2511020 subs r1,r1,#0x20
1489     * f015f94c: 8afffffa bhi 0xf015f93c
1490     */
1491     X(netbsd_cacheclean2)
1492     {
1493     cpu->n_translated_instrs += ((cpu->cd.arm.r[1] >> 5) * 5) - 1;
1494     cpu->cd.arm.next_ic = &ic[5];
1495     }
1496    
1497    
1498     /*
1499     * netbsd_scanc:
1500     *
1501     * f01bccbc: e5d13000 ldrb r3,[r1]
1502     * f01bccc0: e7d23003 ldrb r3,[r2,r3]
1503     * f01bccc4: e113000c tsts r3,ip
1504     */
1505     X(netbsd_scanc)
1506     {
1507     unsigned char *page = cpu->cd.arm.host_load[cpu->cd.arm.r[1] >> 12];
1508     uint32_t t;
1509    
1510     if (page == NULL) {
1511     instr(load_w0_byte_u1_p1_imm)(cpu, ic);
1512     return;
1513     }
1514    
1515     t = page[cpu->cd.arm.r[1] & 0xfff];
1516     t += cpu->cd.arm.r[2];
1517     page = cpu->cd.arm.host_load[t >> 12];
1518    
1519     if (page == NULL) {
1520     instr(load_w0_byte_u1_p1_imm)(cpu, ic);
1521     return;
1522     }
1523    
1524     cpu->cd.arm.r[3] = page[t & 0xfff];
1525    
1526     t = cpu->cd.arm.r[3] & cpu->cd.arm.r[ARM_IP];
1527 dpavlin 20 cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N);
1528 dpavlin 18 if (t == 0)
1529 dpavlin 20 cpu->cd.arm.flags |= ARM_F_Z;
1530 dpavlin 18
1531     cpu->n_translated_instrs += 2;
1532     cpu->cd.arm.next_ic = &ic[3];
1533     }
1534    
1535    
1536 dpavlin 20 /*
1537     * strlen:
1538     *
1539     * S: e5f03001 ldrb rY,[rX,#1]!
1540     * e3530000 cmps rY,#0
1541     * 1afffffc bne S
1542     */
1543     X(strlen)
1544     {
1545     unsigned int n_loops = 0;
1546     uint32_t rY, rX = reg(ic[0].arg[0]);
1547     unsigned char *p;
1548    
1549     do {
1550     rX ++;
1551     p = cpu->cd.arm.host_load[rX >> 12];
1552     if (p == NULL) {
1553     cpu->n_translated_instrs += (n_loops * 3);
1554     instr(load_w1_byte_u1_p1_imm)(cpu, ic);
1555     return;
1556     }
1557    
1558     rY = reg(ic[0].arg[2]) = p[rX & 0xfff]; /* load */
1559     reg(ic[0].arg[0]) = rX; /* writeback */
1560     n_loops ++;
1561    
1562     /* Compare rY to zero: */
1563     cpu->cd.arm.flags = ARM_F_C;
1564     if (rY == 0)
1565     cpu->cd.arm.flags |= ARM_F_Z;
1566     } while (rY != 0);
1567    
1568     cpu->n_translated_instrs += (n_loops * 3) - 1;
1569     cpu->cd.arm.next_ic = &ic[3];
1570     }
1571    
1572    
1573     /*
1574     * xchg:
1575     *
1576     * e02YX00X eor rX,rY,rX
1577     * e02XY00Y eor rY,rX,rY
1578     * e02YX00X eor rX,rY,rX
1579     */
1580     X(xchg)
1581     {
1582     uint32_t tmp = reg(ic[0].arg[0]);
1583     cpu->n_translated_instrs += 2;
1584     cpu->cd.arm.next_ic = &ic[3];
1585     reg(ic[0].arg[0]) = reg(ic[1].arg[0]);
1586     reg(ic[1].arg[0]) = tmp;
1587     }
1588    
1589    
1590     /*
1591     * netbsd_copyin:
1592     *
1593     * e4b0a004 ldrt sl,[r0],#4
1594     * e4b0b004 ldrt fp,[r0],#4
1595     * e4b06004 ldrt r6,[r0],#4
1596     * e4b07004 ldrt r7,[r0],#4
1597     * e4b08004 ldrt r8,[r0],#4
1598     * e4b09004 ldrt r9,[r0],#4
1599     */
1600     X(netbsd_copyin)
1601     {
1602     uint32_t r0 = cpu->cd.arm.r[0], ofs = (r0 & 0xffc), index = r0 >> 12;
1603     unsigned char *p = cpu->cd.arm.host_load[index];
1604     uint32_t *p32 = (uint32_t *) p, *q32;
1605     int ok = cpu->cd.arm.is_userpage[index >> 5] & (1 << (index & 31));
1606    
1607     if (ofs > 0x1000 - 6*4 || !ok || p == NULL) {
1608     instr(load_w1_word_u1_p0_imm)(cpu, ic);
1609     return;
1610     }
1611     q32 = &cpu->cd.arm.r[6];
1612     ofs >>= 2;
1613     q32[0] = p32[ofs+2];
1614     q32[1] = p32[ofs+3];
1615     q32[2] = p32[ofs+4];
1616     q32[3] = p32[ofs+5];
1617     q32[4] = p32[ofs+0];
1618     q32[5] = p32[ofs+1];
1619     cpu->cd.arm.r[0] = r0 + 24;
1620     cpu->n_translated_instrs += 5;
1621     cpu->cd.arm.next_ic = &ic[6];
1622     }
1623    
1624    
1625     /*
1626     * netbsd_copyout:
1627     *
1628     * e4a18004 strt r8,[r1],#4
1629     * e4a19004 strt r9,[r1],#4
1630     * e4a1a004 strt sl,[r1],#4
1631     * e4a1b004 strt fp,[r1],#4
1632     * e4a16004 strt r6,[r1],#4
1633     * e4a17004 strt r7,[r1],#4
1634     */
1635     X(netbsd_copyout)
1636     {
1637     uint32_t r1 = cpu->cd.arm.r[1], ofs = (r1 & 0xffc), index = r1 >> 12;
1638     unsigned char *p = cpu->cd.arm.host_store[index];
1639     uint32_t *p32 = (uint32_t *) p, *q32;
1640     int ok = cpu->cd.arm.is_userpage[index >> 5] & (1 << (index & 31));
1641    
1642     if (ofs > 0x1000 - 6*4 || !ok || p == NULL) {
1643     instr(store_w1_word_u1_p0_imm)(cpu, ic);
1644     return;
1645     }
1646     q32 = &cpu->cd.arm.r[6];
1647     ofs >>= 2;
1648     p32[ofs ] = q32[2];
1649     p32[ofs+1] = q32[3];
1650     p32[ofs+2] = q32[4];
1651     p32[ofs+3] = q32[5];
1652     p32[ofs+4] = q32[0];
1653     p32[ofs+5] = q32[1];
1654     cpu->cd.arm.r[1] = r1 + 24;
1655     cpu->n_translated_instrs += 5;
1656     cpu->cd.arm.next_ic = &ic[6];
1657     }
1658    
1659    
1660     /*
1661     * cmps by 0, followed by beq (inside the same page):
1662     */
1663     X(cmps0_beq_samepage)
1664     {
1665     uint32_t a = reg(ic->arg[0]);
1666     cpu->n_translated_instrs ++;
1667     if (a == 0) {
1668     cpu->cd.arm.flags = ARM_F_Z | ARM_F_C;
1669     } else {
1670     /* Semi-ugly hack which sets the negative-bit if a < 0: */
1671     cpu->cd.arm.flags = ARM_F_C | ((a >> 28) & 8);
1672     }
1673     if (a == 0)
1674     cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0];
1675     else
1676     cpu->cd.arm.next_ic = &ic[2];
1677     }
1678    
1679    
1680     /*
1681     * cmps followed by beq (inside the same page):
1682     */
1683     X(cmps_beq_samepage)
1684     {
1685     uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a - b;
1686     cpu->n_translated_instrs ++;
1687     cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0;
1688     if (((int32_t)a >= 0 && (int32_t)b < 0 && (int32_t)c < 0) ||
1689     ((int32_t)a < 0 && (int32_t)b >= 0 && (int32_t)c >= 0))
1690     cpu->cd.arm.flags |= ARM_F_V;
1691     if (c == 0) {
1692     cpu->cd.arm.flags |= ARM_F_Z;
1693     cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0];
1694     } else {
1695     cpu->cd.arm.next_ic = &ic[2];
1696     if (c & 0x80000000)
1697     cpu->cd.arm.flags |= ARM_F_N;
1698     }
1699     }
1700    
1701    
1702     /*
1703     * cmps followed by beq (not the same page):
1704     */
1705     X(cmps_0_beq)
1706     {
1707     uint32_t a = reg(ic->arg[0]);
1708     cpu->n_translated_instrs ++;
1709     if (a == 0) {
1710     cpu->cd.arm.flags = ARM_F_Z | ARM_F_C;
1711     cpu->pc = (uint32_t)(((uint32_t)cpu->pc & 0xfffff000)
1712     + (int32_t)ic[1].arg[0]);
1713     quick_pc_to_pointers(cpu);
1714     } else {
1715     /* Semi-ugly hack which sets the negative-bit if a < 0: */
1716     cpu->cd.arm.flags = ARM_F_C | ((a >> 28) & 8);
1717     cpu->cd.arm.next_ic = &ic[2];
1718     }
1719     }
1720     X(cmps_pos_beq)
1721     {
1722     uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a - b;
1723     cpu->n_translated_instrs ++;
1724     cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0;
1725     if ((int32_t)a < 0 && (int32_t)c >= 0)
1726     cpu->cd.arm.flags |= ARM_F_V;
1727     if (c == 0) {
1728     cpu->cd.arm.flags |= ARM_F_Z;
1729     cpu->pc = (uint32_t)(((uint32_t)cpu->pc & 0xfffff000)
1730     + (int32_t)ic[1].arg[0]);
1731     quick_pc_to_pointers(cpu);
1732     } else {
1733     cpu->cd.arm.next_ic = &ic[2];
1734     if (c & 0x80000000)
1735     cpu->cd.arm.flags |= ARM_F_N;
1736     }
1737     }
1738     X(cmps_neg_beq)
1739     {
1740     uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a - b;
1741     cpu->n_translated_instrs ++;
1742     cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0;
1743     if ((int32_t)a >= 0 && (int32_t)c < 0)
1744     cpu->cd.arm.flags |= ARM_F_V;
1745     if (c == 0) {
1746     cpu->cd.arm.flags |= ARM_F_Z;
1747     cpu->pc = (uint32_t)(((uint32_t)cpu->pc & 0xfffff000)
1748     + (int32_t)ic[1].arg[0]);
1749     quick_pc_to_pointers(cpu);
1750     } else {
1751     cpu->cd.arm.next_ic = &ic[2];
1752     if (c & 0x80000000)
1753     cpu->cd.arm.flags |= ARM_F_N;
1754     }
1755     }
1756    
1757    
1758     /*
1759     * cmps by 0, followed by bne (inside the same page):
1760     */
1761     X(cmps0_bne_samepage)
1762     {
1763     uint32_t a = reg(ic->arg[0]);
1764     cpu->n_translated_instrs ++;
1765     if (a == 0) {
1766     cpu->cd.arm.flags = ARM_F_Z | ARM_F_C;
1767     } else {
1768     /* Semi-ugly hack which sets the negative-bit if a < 0: */
1769     cpu->cd.arm.flags = ARM_F_C | ((a >> 28) & 8);
1770     }
1771     if (a == 0)
1772     cpu->cd.arm.next_ic = &ic[2];
1773     else
1774     cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0];
1775     }
1776    
1777    
1778     /*
1779     * cmps followed by bne (inside the same page):
1780     */
1781     X(cmps_bne_samepage)
1782     {
1783     uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a - b;
1784     cpu->n_translated_instrs ++;
1785     cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0;
1786     if (((int32_t)a >= 0 && (int32_t)b < 0 && (int32_t)c < 0) ||
1787     ((int32_t)a < 0 && (int32_t)b >= 0 && (int32_t)c >= 0))
1788     cpu->cd.arm.flags |= ARM_F_V;
1789     if (c == 0) {
1790     cpu->cd.arm.flags |= ARM_F_Z;
1791     cpu->cd.arm.next_ic = &ic[2];
1792     } else {
1793     if (c & 0x80000000)
1794     cpu->cd.arm.flags |= ARM_F_N;
1795     cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0];
1796     }
1797     }
1798    
1799    
1800     /*
1801     * cmps followed by bcc (inside the same page):
1802     */
1803     X(cmps_bcc_samepage)
1804     {
1805     uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a - b;
1806     cpu->n_translated_instrs ++;
1807     cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0;
1808     if (c & 0x80000000)
1809     cpu->cd.arm.flags |= ARM_F_N;
1810     else if (c == 0)
1811     cpu->cd.arm.flags |= ARM_F_Z;
1812     if (((int32_t)a >= 0 && (int32_t)b < 0 && (int32_t)c < 0) ||
1813     ((int32_t)a < 0 && (int32_t)b >= 0 && (int32_t)c >= 0))
1814     cpu->cd.arm.flags |= ARM_F_V;
1815     if (a >= b)
1816     cpu->cd.arm.next_ic = &ic[2];
1817     else
1818     cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0];
1819     }
1820    
1821    
1822     /*
1823     * cmps (reg) followed by bcc (inside the same page):
1824     */
1825     X(cmps_reg_bcc_samepage)
1826     {
1827     uint32_t a = reg(ic->arg[0]), b = reg(ic->arg[1]), c = a - b;
1828     cpu->n_translated_instrs ++;
1829     cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0;
1830     if (c & 0x80000000)
1831     cpu->cd.arm.flags |= ARM_F_N;
1832     else if (c == 0)
1833     cpu->cd.arm.flags |= ARM_F_Z;
1834     if (((int32_t)a >= 0 && (int32_t)b < 0 && (int32_t)c < 0) ||
1835     ((int32_t)a < 0 && (int32_t)b >= 0 && (int32_t)c >= 0))
1836     cpu->cd.arm.flags |= ARM_F_V;
1837     if (a >= b)
1838     cpu->cd.arm.next_ic = &ic[2];
1839     else
1840     cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0];
1841     }
1842    
1843    
1844     /*
1845     * cmps followed by bhi (inside the same page):
1846     */
1847     X(cmps_bhi_samepage)
1848     {
1849     uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a - b;
1850     cpu->n_translated_instrs ++;
1851     cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0;
1852     if (c & 0x80000000)
1853     cpu->cd.arm.flags |= ARM_F_N;
1854     else if (c == 0)
1855     cpu->cd.arm.flags |= ARM_F_Z;
1856     if (((int32_t)a >= 0 && (int32_t)b < 0 && (int32_t)c < 0) ||
1857     ((int32_t)a < 0 && (int32_t)b >= 0 && (int32_t)c >= 0))
1858     cpu->cd.arm.flags |= ARM_F_V;
1859     if (a > b)
1860     cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0];
1861     else
1862     cpu->cd.arm.next_ic = &ic[2];
1863     }
1864    
1865    
1866     /*
1867     * cmps (reg) followed by bhi (inside the same page):
1868     */
1869     X(cmps_reg_bhi_samepage)
1870     {
1871     uint32_t a = reg(ic->arg[0]), b = reg(ic->arg[1]), c = a - b;
1872     cpu->n_translated_instrs ++;
1873     cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0;
1874     if (c & 0x80000000)
1875     cpu->cd.arm.flags |= ARM_F_N;
1876     else if (c == 0)
1877     cpu->cd.arm.flags |= ARM_F_Z;
1878     if (((int32_t)a >= 0 && (int32_t)b < 0 && (int32_t)c < 0) ||
1879     ((int32_t)a < 0 && (int32_t)b >= 0 && (int32_t)c >= 0))
1880     cpu->cd.arm.flags |= ARM_F_V;
1881     if (a > b)
1882     cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0];
1883     else
1884     cpu->cd.arm.next_ic = &ic[2];
1885     }
1886    
1887    
1888     /*
1889     * cmps followed by bgt (inside the same page):
1890     */
1891     X(cmps_bgt_samepage)
1892     {
1893     uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a - b;
1894     cpu->n_translated_instrs ++;
1895     cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0;
1896     if (c & 0x80000000)
1897     cpu->cd.arm.flags |= ARM_F_N;
1898     else if (c == 0)
1899     cpu->cd.arm.flags |= ARM_F_Z;
1900     if (((int32_t)a >= 0 && (int32_t)b < 0 && (int32_t)c < 0) ||
1901     ((int32_t)a < 0 && (int32_t)b >= 0 && (int32_t)c >= 0))
1902     cpu->cd.arm.flags |= ARM_F_V;
1903     if ((int32_t)a > (int32_t)b)
1904     cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0];
1905     else
1906     cpu->cd.arm.next_ic = &ic[2];
1907     }
1908    
1909    
1910     /*
1911     * cmps followed by ble (inside the same page):
1912     */
1913     X(cmps_ble_samepage)
1914     {
1915     uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a - b;
1916     cpu->n_translated_instrs ++;
1917     cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0;
1918     if (c & 0x80000000)
1919     cpu->cd.arm.flags |= ARM_F_N;
1920     else if (c == 0)
1921     cpu->cd.arm.flags |= ARM_F_Z;
1922     if (((int32_t)a >= 0 && (int32_t)b < 0 && (int32_t)c < 0) ||
1923     ((int32_t)a < 0 && (int32_t)b >= 0 && (int32_t)c >= 0))
1924     cpu->cd.arm.flags |= ARM_F_V;
1925     if ((int32_t)a <= (int32_t)b)
1926     cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0];
1927     else
1928     cpu->cd.arm.next_ic = &ic[2];
1929     }
1930    
1931    
1932     /*
1933     * teqs followed by beq (inside the same page):
1934     */
1935     X(teqs_beq_samepage)
1936     {
1937     uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a ^ b;
1938     cpu->n_translated_instrs ++;
1939     cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N);
1940     if (c == 0) {
1941     cpu->cd.arm.flags |= ARM_F_Z;
1942     cpu->cd.arm.next_ic = (struct arm_instr_call *)
1943     ic[1].arg[0];
1944     } else {
1945     if (c & 0x80000000)
1946     cpu->cd.arm.flags |= ARM_F_N;
1947     cpu->cd.arm.next_ic = &ic[2];
1948     }
1949     }
1950    
1951    
1952     /*
1953     * tsts followed by beq (inside the same page):
1954     * (arg[1] must not have its highest bit set))
1955     */
1956     X(tsts_lo_beq_samepage)
1957     {
1958     uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a & b;
1959     cpu->n_translated_instrs ++;
1960     cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N);
1961     if (c == 0)
1962     cpu->cd.arm.flags |= ARM_F_Z;
1963     if (c == 0)
1964     cpu->cd.arm.next_ic = (struct arm_instr_call *)
1965     ic[1].arg[0];
1966     else
1967     cpu->cd.arm.next_ic = &ic[2];
1968     }
1969    
1970    
1971     /*
1972     * teqs followed by bne (inside the same page):
1973     */
1974     X(teqs_bne_samepage)
1975     {
1976     uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a ^ b;
1977     cpu->n_translated_instrs ++;
1978     cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N);
1979     if (c == 0) {
1980     cpu->cd.arm.flags |= ARM_F_Z;
1981     } else {
1982     if (c & 0x80000000)
1983     cpu->cd.arm.flags |= ARM_F_N;
1984     }
1985     if (c == 0)
1986     cpu->cd.arm.next_ic = &ic[2];
1987     else
1988     cpu->cd.arm.next_ic = (struct arm_instr_call *)
1989     ic[1].arg[0];
1990     }
1991    
1992    
1993     /*
1994     * tsts followed by bne (inside the same page):
1995     * (arg[1] must not have its highest bit set))
1996     */
1997     X(tsts_lo_bne_samepage)
1998     {
1999     uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a & b;
2000     cpu->n_translated_instrs ++;
2001     cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N);
2002     if (c == 0)
2003     cpu->cd.arm.flags |= ARM_F_Z;
2004     if (c == 0)
2005     cpu->cd.arm.next_ic = &ic[2];
2006     else
2007     cpu->cd.arm.next_ic = (struct arm_instr_call *)
2008     ic[1].arg[0];
2009     }
2010    
2011    
2012 dpavlin 14 /*****************************************************************************/
2013    
2014    
2015     X(end_of_page)
2016     {
2017     /* Update the PC: (offset 0, but on the next page) */
2018 dpavlin 20 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
2019     cpu->pc += (ARM_IC_ENTRIES_PER_PAGE << ARM_INSTR_ALIGNMENT_SHIFT);
2020 dpavlin 14
2021     /* Find the new physical page and update the translation pointers: */
2022 dpavlin 18 quick_pc_to_pointers(cpu);
2023 dpavlin 14
2024     /* end_of_page doesn't count as an executed instruction: */
2025     cpu->n_translated_instrs --;
2026     }
2027    
2028    
2029     /*****************************************************************************/
2030    
2031    
2032     /*
2033 dpavlin 22 * Combine: netbsd_memset():
2034 dpavlin 14 *
2035 dpavlin 18 * Check for the core of a NetBSD/arm memset; large memsets use a sequence
2036     * of 16 store-multiple instructions, each storing 2 registers at a time.
2037 dpavlin 14 */
2038 dpavlin 22 void COMBINE(netbsd_memset)(struct cpu *cpu,
2039 dpavlin 20 struct arm_instr_call *ic, int low_addr)
2040 dpavlin 14 {
2041 dpavlin 20 #ifdef HOST_LITTLE_ENDIAN
2042 dpavlin 18 int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2043 dpavlin 14 & (ARM_IC_ENTRIES_PER_PAGE-1);
2044    
2045 dpavlin 18 if (n_back >= 17) {
2046     int i;
2047     for (i=-16; i<=-1; i++)
2048     if (ic[i].f != instr(multi_0x08ac000c__ge))
2049     return;
2050     if (ic[-17].f == instr(subs) &&
2051     ic[-17].arg[0]==ic[-17].arg[2] && ic[-17].arg[1] == 128 &&
2052     ic[ 0].f == instr(b_samepage__gt) &&
2053     ic[ 0].arg[0] == (size_t)&ic[-17]) {
2054     ic[-17].f = instr(netbsd_memset);
2055     }
2056     }
2057 dpavlin 20 #endif
2058 dpavlin 18 }
2059    
2060    
2061     /*
2062 dpavlin 22 * Combine: netbsd_memcpy():
2063 dpavlin 18 *
2064     * Check for the core of a NetBSD/arm memcpy; large memcpys use a
2065     * sequence of ldmia instructions.
2066     */
2067 dpavlin 22 void COMBINE(netbsd_memcpy)(struct cpu *cpu, struct arm_instr_call *ic,
2068     int low_addr)
2069 dpavlin 18 {
2070 dpavlin 20 #ifdef HOST_LITTLE_ENDIAN
2071 dpavlin 18 int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2072     & (ARM_IC_ENTRIES_PER_PAGE-1);
2073    
2074     if (n_back >= 5) {
2075     if (ic[-5].f==instr(multi_0x08b15018) &&
2076     ic[-4].f==instr(multi_0x08a05018) &&
2077     ic[-3].f==instr(multi_0x08b15018) &&
2078     ic[-2].f==instr(multi_0x08a05018) &&
2079     ic[-1].f == instr(subs) &&
2080     ic[-1].arg[0]==ic[-1].arg[2] && ic[-1].arg[1] == 0x20 &&
2081     ic[ 0].f == instr(b_samepage__ge) &&
2082     ic[ 0].arg[0] == (size_t)&ic[-5]) {
2083     ic[-5].f = instr(netbsd_memcpy);
2084     }
2085     }
2086 dpavlin 20 #endif
2087 dpavlin 18 }
2088    
2089    
2090     /*
2091 dpavlin 22 * Combine: netbsd_cacheclean():
2092 dpavlin 18 *
2093     * Check for the core of a NetBSD/arm cache clean. (There are two variants.)
2094     */
2095 dpavlin 22 void COMBINE(netbsd_cacheclean)(struct cpu *cpu,
2096 dpavlin 20 struct arm_instr_call *ic, int low_addr)
2097 dpavlin 18 {
2098     int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2099     & (ARM_IC_ENTRIES_PER_PAGE-1);
2100    
2101     if (n_back >= 3) {
2102     if (ic[-3].f==instr(load_w0_word_u1_p0_imm) &&
2103     ic[-2].f == instr(subs) &&
2104     ic[-2].arg[0]==ic[-2].arg[2] && ic[-2].arg[1] == 0x20 &&
2105     ic[-1].f == instr(b_samepage__ne) &&
2106     ic[-1].arg[0] == (size_t)&ic[-3]) {
2107     ic[-3].f = instr(netbsd_cacheclean);
2108     }
2109     }
2110     }
2111    
2112    
2113     /*
2114 dpavlin 22 * Combine: netbsd_cacheclean2():
2115 dpavlin 18 *
2116     * Check for the core of a NetBSD/arm cache clean. (Second variant.)
2117     */
2118 dpavlin 22 void COMBINE(netbsd_cacheclean2)(struct cpu *cpu,
2119 dpavlin 20 struct arm_instr_call *ic, int low_addr)
2120 dpavlin 18 {
2121     int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2122     & (ARM_IC_ENTRIES_PER_PAGE-1);
2123    
2124     if (n_back >= 4) {
2125     if (ic[-4].f == instr(mcr_mrc) && ic[-4].arg[0] == 0xee070f3a &&
2126     ic[-3].f == instr(mcr_mrc) && ic[-3].arg[0] == 0xee070f36 &&
2127     ic[-2].f == instr(add) &&
2128     ic[-2].arg[0]==ic[-2].arg[2] && ic[-2].arg[1] == 0x20 &&
2129     ic[-1].f == instr(subs) &&
2130     ic[-1].arg[0]==ic[-1].arg[2] && ic[-1].arg[1] == 0x20) {
2131     ic[-4].f = instr(netbsd_cacheclean2);
2132     }
2133     }
2134     }
2135    
2136    
2137     /*
2138 dpavlin 22 * Combine: netbsd_scanc():
2139 dpavlin 18 */
2140 dpavlin 22 void COMBINE(netbsd_scanc)(struct cpu *cpu,
2141 dpavlin 20 struct arm_instr_call *ic, int low_addr)
2142 dpavlin 18 {
2143     int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2144     & (ARM_IC_ENTRIES_PER_PAGE-1);
2145    
2146 dpavlin 20 if (n_back < 2)
2147     return;
2148    
2149     if (ic[-2].f == instr(load_w0_byte_u1_p1_imm) &&
2150     ic[-2].arg[0] == (size_t)(&cpu->cd.arm.r[1]) &&
2151     ic[-2].arg[1] == 0 &&
2152     ic[-2].arg[2] == (size_t)(&cpu->cd.arm.r[3]) &&
2153     ic[-1].f == instr(load_w0_byte_u1_p1_reg) &&
2154     ic[-1].arg[0] == (size_t)(&cpu->cd.arm.r[2]) &&
2155     ic[-1].arg[1] == (size_t)arm_r_r3_t0_c0 &&
2156     ic[-1].arg[2] == (size_t)(&cpu->cd.arm.r[3])) {
2157     ic[-2].f = instr(netbsd_scanc);
2158 dpavlin 18 }
2159     }
2160    
2161    
2162     /*
2163 dpavlin 22 * Combine: strlen():
2164 dpavlin 18 */
2165 dpavlin 22 void COMBINE(strlen)(struct cpu *cpu,
2166 dpavlin 20 struct arm_instr_call *ic, int low_addr)
2167 dpavlin 18 {
2168     int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2169     & (ARM_IC_ENTRIES_PER_PAGE-1);
2170    
2171 dpavlin 20 if (n_back < 2)
2172     return;
2173    
2174     if (ic[-2].f == instr(load_w1_byte_u1_p1_imm) &&
2175     ic[-2].arg[1] == 1 &&
2176     ic[-2].arg[2] == (size_t)(&cpu->cd.arm.r[3]) &&
2177     ic[-1].f == instr(cmps) &&
2178     ic[-1].arg[0] == (size_t)(&cpu->cd.arm.r[3]) &&
2179     ic[-1].arg[1] == 0) {
2180     ic[-2].f = instr(strlen);
2181 dpavlin 14 }
2182 dpavlin 18 }
2183 dpavlin 14
2184 dpavlin 18
2185 dpavlin 20 /*
2186 dpavlin 22 * Combine: xchg():
2187 dpavlin 20 */
2188 dpavlin 22 void COMBINE(xchg)(struct cpu *cpu,
2189 dpavlin 20 struct arm_instr_call *ic, int low_addr)
2190     {
2191     int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2192     & (ARM_IC_ENTRIES_PER_PAGE-1);
2193     size_t a, b;
2194 dpavlin 18
2195 dpavlin 20 if (n_back < 2)
2196     return;
2197    
2198     a = ic[-2].arg[0]; b = ic[-1].arg[0];
2199    
2200     if (ic[-2].f == instr(eor_regshort) &&
2201     ic[-1].f == instr(eor_regshort) &&
2202     ic[-2].arg[0] == a && ic[-2].arg[1] == b && ic[-2].arg[2] == b &&
2203     ic[-1].arg[0] == b && ic[-1].arg[1] == a && ic[-1].arg[2] == a &&
2204     ic[ 0].arg[0] == a && ic[ 0].arg[1] == b && ic[ 0].arg[2] == b) {
2205     ic[-2].f = instr(xchg);
2206     }
2207     }
2208    
2209    
2210     /*
2211 dpavlin 22 * Combine: netbsd_copyin():
2212 dpavlin 20 */
2213 dpavlin 22 void COMBINE(netbsd_copyin)(struct cpu *cpu,
2214 dpavlin 20 struct arm_instr_call *ic, int low_addr)
2215     {
2216     #ifdef HOST_LITTLE_ENDIAN
2217     int i, n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2218     & (ARM_IC_ENTRIES_PER_PAGE-1);
2219    
2220     if (n_back < 5)
2221     return;
2222    
2223     for (i=-5; i<0; i++) {
2224     if (ic[i].f != instr(load_w1_word_u1_p0_imm) ||
2225     ic[i].arg[0] != (size_t)(&cpu->cd.arm.r[0]) ||
2226     ic[i].arg[1] != 4)
2227     return;
2228     }
2229    
2230     if (ic[-5].arg[2] == (size_t)(&cpu->cd.arm.r[10]) &&
2231     ic[-4].arg[2] == (size_t)(&cpu->cd.arm.r[11]) &&
2232     ic[-3].arg[2] == (size_t)(&cpu->cd.arm.r[6]) &&
2233     ic[-2].arg[2] == (size_t)(&cpu->cd.arm.r[7]) &&
2234     ic[-1].arg[2] == (size_t)(&cpu->cd.arm.r[8])) {
2235     ic[-5].f = instr(netbsd_copyin);
2236     }
2237     #endif
2238     }
2239    
2240    
2241     /*
2242 dpavlin 22 * Combine: netbsd_copyout():
2243 dpavlin 20 */
2244 dpavlin 22 void COMBINE(netbsd_copyout)(struct cpu *cpu,
2245 dpavlin 20 struct arm_instr_call *ic, int low_addr)
2246     {
2247     #ifdef HOST_LITTLE_ENDIAN
2248     int i, n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2249     & (ARM_IC_ENTRIES_PER_PAGE-1);
2250    
2251     if (n_back < 5)
2252     return;
2253    
2254     for (i=-5; i<0; i++) {
2255     if (ic[i].f != instr(store_w1_word_u1_p0_imm) ||
2256     ic[i].arg[0] != (size_t)(&cpu->cd.arm.r[1]) ||
2257     ic[i].arg[1] != 4)
2258     return;
2259     }
2260    
2261     if (ic[-5].arg[2] == (size_t)(&cpu->cd.arm.r[8]) &&
2262     ic[-4].arg[2] == (size_t)(&cpu->cd.arm.r[9]) &&
2263     ic[-3].arg[2] == (size_t)(&cpu->cd.arm.r[10]) &&
2264     ic[-2].arg[2] == (size_t)(&cpu->cd.arm.r[11]) &&
2265     ic[-1].arg[2] == (size_t)(&cpu->cd.arm.r[6])) {
2266     ic[-5].f = instr(netbsd_copyout);
2267     }
2268     #endif
2269     }
2270    
2271    
2272     /*
2273 dpavlin 22 * Combine: cmps_b():
2274 dpavlin 20 */
2275 dpavlin 22 void COMBINE(cmps_b)(struct cpu *cpu,
2276 dpavlin 20 struct arm_instr_call *ic, int low_addr)
2277     {
2278     int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2279     & (ARM_IC_ENTRIES_PER_PAGE-1);
2280     if (n_back < 1)
2281     return;
2282     if (ic[0].f == instr(b__eq)) {
2283     if (ic[-1].f == instr(cmps)) {
2284     if (ic[-1].arg[1] == 0)
2285     ic[-1].f = instr(cmps_0_beq);
2286     else if (ic[-1].arg[1] & 0x80000000)
2287     ic[-1].f = instr(cmps_neg_beq);
2288     else
2289     ic[-1].f = instr(cmps_pos_beq);
2290 dpavlin 14 }
2291 dpavlin 20 return;
2292 dpavlin 14 }
2293 dpavlin 20 if (ic[0].f == instr(b_samepage__eq)) {
2294     if (ic[-1].f == instr(cmps)) {
2295     if (ic[-1].arg[1] == 0)
2296     ic[-1].f = instr(cmps0_beq_samepage);
2297     else
2298     ic[-1].f = instr(cmps_beq_samepage);
2299     }
2300     if (ic[-1].f == instr(tsts) &&
2301     !(ic[-1].arg[1] & 0x80000000)) {
2302     ic[-1].f = instr(tsts_lo_beq_samepage);
2303     }
2304     if (ic[-1].f == instr(teqs)) {
2305     ic[-1].f = instr(teqs_beq_samepage);
2306     }
2307     return;
2308     }
2309     if (ic[0].f == instr(b_samepage__ne)) {
2310     if (ic[-1].f == instr(cmps)) {
2311     if (ic[-1].arg[1] == 0)
2312     ic[-1].f = instr(cmps0_bne_samepage);
2313     else
2314     ic[-1].f = instr(cmps_bne_samepage);
2315     }
2316     if (ic[-1].f == instr(tsts) &&
2317     !(ic[-1].arg[1] & 0x80000000)) {
2318     ic[-1].f = instr(tsts_lo_bne_samepage);
2319     }
2320     if (ic[-1].f == instr(teqs)) {
2321     ic[-1].f = instr(teqs_bne_samepage);
2322     }
2323     return;
2324     }
2325     if (ic[0].f == instr(b_samepage__cc)) {
2326     if (ic[-1].f == instr(cmps)) {
2327     ic[-1].f = instr(cmps_bcc_samepage);
2328     }
2329     if (ic[-1].f == instr(cmps_regshort)) {
2330     ic[-1].f = instr(cmps_reg_bcc_samepage);
2331     }
2332     return;
2333     }
2334     if (ic[0].f == instr(b_samepage__hi)) {
2335     if (ic[-1].f == instr(cmps)) {
2336     ic[-1].f = instr(cmps_bhi_samepage);
2337     }
2338     if (ic[-1].f == instr(cmps_regshort)) {
2339     ic[-1].f = instr(cmps_reg_bhi_samepage);
2340     }
2341     return;
2342     }
2343     if (ic[0].f == instr(b_samepage__gt)) {
2344     if (ic[-1].f == instr(cmps)) {
2345     ic[-1].f = instr(cmps_bgt_samepage);
2346     }
2347     return;
2348     }
2349     if (ic[0].f == instr(b_samepage__le)) {
2350     if (ic[-1].f == instr(cmps)) {
2351     ic[-1].f = instr(cmps_ble_samepage);
2352     }
2353     return;
2354     }
2355     }
2356 dpavlin 14
2357    
2358     /*****************************************************************************/
2359    
2360    
2361 dpavlin 20 static void arm_switch_clear(struct arm_instr_call *ic, int rd,
2362     int condition_code)
2363     {
2364     switch (rd) {
2365     case 0: ic->f = cond_instr(clear_r0); break;
2366     case 1: ic->f = cond_instr(clear_r1); break;
2367     case 2: ic->f = cond_instr(clear_r2); break;
2368     case 3: ic->f = cond_instr(clear_r3); break;
2369     case 4: ic->f = cond_instr(clear_r4); break;
2370     case 5: ic->f = cond_instr(clear_r5); break;
2371     case 6: ic->f = cond_instr(clear_r6); break;
2372     case 7: ic->f = cond_instr(clear_r7); break;
2373     case 8: ic->f = cond_instr(clear_r8); break;
2374     case 9: ic->f = cond_instr(clear_r9); break;
2375     case 10: ic->f = cond_instr(clear_r10); break;
2376     case 11: ic->f = cond_instr(clear_r11); break;
2377     case 12: ic->f = cond_instr(clear_r12); break;
2378     case 13: ic->f = cond_instr(clear_r13); break;
2379     case 14: ic->f = cond_instr(clear_r14); break;
2380     }
2381     }
2382    
2383    
2384     static void arm_switch_mov1(struct arm_instr_call *ic, int rd,
2385     int condition_code)
2386     {
2387     switch (rd) {
2388     case 0: ic->f = cond_instr(mov1_r0); break;
2389     case 1: ic->f = cond_instr(mov1_r1); break;
2390     case 2: ic->f = cond_instr(mov1_r2); break;
2391     case 3: ic->f = cond_instr(mov1_r3); break;
2392     case 4: ic->f = cond_instr(mov1_r4); break;
2393     case 5: ic->f = cond_instr(mov1_r5); break;
2394     case 6: ic->f = cond_instr(mov1_r6); break;
2395     case 7: ic->f = cond_instr(mov1_r7); break;
2396     case 8: ic->f = cond_instr(mov1_r8); break;
2397     case 9: ic->f = cond_instr(mov1_r9); break;
2398     case 10: ic->f = cond_instr(mov1_r10); break;
2399     case 11: ic->f = cond_instr(mov1_r11); break;
2400     case 12: ic->f = cond_instr(mov1_r12); break;
2401     case 13: ic->f = cond_instr(mov1_r13); break;
2402     case 14: ic->f = cond_instr(mov1_r14); break;
2403     }
2404     }
2405    
2406    
2407     static void arm_switch_add1(struct arm_instr_call *ic, int rd,
2408     int condition_code)
2409     {
2410     switch (rd) {
2411     case 0: ic->f = cond_instr(add1_r0); break;
2412     case 1: ic->f = cond_instr(add1_r1); break;
2413     case 2: ic->f = cond_instr(add1_r2); break;
2414     case 3: ic->f = cond_instr(add1_r3); break;
2415     case 4: ic->f = cond_instr(add1_r4); break;
2416     case 5: ic->f = cond_instr(add1_r5); break;
2417     case 6: ic->f = cond_instr(add1_r6); break;
2418     case 7: ic->f = cond_instr(add1_r7); break;
2419     case 8: ic->f = cond_instr(add1_r8); break;
2420     case 9: ic->f = cond_instr(add1_r9); break;
2421     case 10: ic->f = cond_instr(add1_r10); break;
2422     case 11: ic->f = cond_instr(add1_r11); break;
2423     case 12: ic->f = cond_instr(add1_r12); break;
2424     case 13: ic->f = cond_instr(add1_r13); break;
2425     case 14: ic->f = cond_instr(add1_r14); break;
2426     }
2427     }
2428    
2429    
2430     /*****************************************************************************/
2431    
2432    
2433 dpavlin 14 /*
2434     * arm_instr_to_be_translated():
2435     *
2436     * Translate an instruction word into an arm_instr_call. ic is filled in with
2437     * valid data for the translated instruction, or a "nothing" instruction if
2438     * there was a translation failure. The newly translated instruction is then
2439     * executed.
2440     */
2441     X(to_be_translated)
2442     {
2443     uint32_t addr, low_pc, iword, imm = 0;
2444     unsigned char *page;
2445     unsigned char ib[4];
2446     int condition_code, main_opcode, secondary_opcode, s_bit, rn, rd, r8;
2447 dpavlin 20 int p_bit, u_bit, w_bit, l_bit, regform, rm, c, t, any_pc_reg;
2448 dpavlin 14 void (*samepage_function)(struct cpu *, struct arm_instr_call *);
2449    
2450     /* Figure out the address of the instruction: */
2451     low_pc = ((size_t)ic - (size_t)cpu->cd.arm.cur_ic_page)
2452     / sizeof(struct arm_instr_call);
2453 dpavlin 20 addr = cpu->pc & ~((ARM_IC_ENTRIES_PER_PAGE-1) <<
2454 dpavlin 14 ARM_INSTR_ALIGNMENT_SHIFT);
2455     addr += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
2456 dpavlin 20 cpu->pc = addr;
2457 dpavlin 14 addr &= ~((1 << ARM_INSTR_ALIGNMENT_SHIFT) - 1);
2458    
2459     /* Read the instruction word from memory: */
2460     page = cpu->cd.arm.host_load[addr >> 12];
2461     if (page != NULL) {
2462 dpavlin 20 /* fatal("TRANSLATION HIT! 0x%08x\n", addr); */
2463 dpavlin 14 memcpy(ib, page + (addr & 0xfff), sizeof(ib));
2464     } else {
2465 dpavlin 20 /* fatal("TRANSLATION MISS! 0x%08x\n", addr); */
2466 dpavlin 14 if (!cpu->memory_rw(cpu, cpu->mem, addr, &ib[0],
2467     sizeof(ib), MEM_READ, CACHE_INSTRUCTION)) {
2468     fatal("to_be_translated(): "
2469     "read failed: TODO\n");
2470 dpavlin 18 return;
2471 dpavlin 14 }
2472     }
2473    
2474     if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
2475     iword = ib[0] + (ib[1]<<8) + (ib[2]<<16) + (ib[3]<<24);
2476     else
2477     iword = ib[3] + (ib[2]<<8) + (ib[1]<<16) + (ib[0]<<24);
2478    
2479    
2480     #define DYNTRANS_TO_BE_TRANSLATED_HEAD
2481     #include "cpu_dyntrans.c"
2482     #undef DYNTRANS_TO_BE_TRANSLATED_HEAD
2483    
2484    
2485     /* The idea of taking bits 27..24 was found here:
2486     http://armphetamine.sourceforge.net/oldinfo.html */
2487     condition_code = iword >> 28;
2488     main_opcode = (iword >> 24) & 15;
2489     secondary_opcode = (iword >> 21) & 15;
2490 dpavlin 20 u_bit = iword & 0x00800000;
2491     w_bit = iword & 0x00200000;
2492     s_bit = l_bit = iword & 0x00100000;
2493 dpavlin 14 rn = (iword >> 16) & 15;
2494     rd = (iword >> 12) & 15;
2495     r8 = (iword >> 8) & 15;
2496     c = (iword >> 7) & 31;
2497     t = (iword >> 4) & 7;
2498     rm = iword & 15;
2499    
2500     if (condition_code == 0xf) {
2501     if ((iword & 0xfc70f000) == 0xf450f000) {
2502     /* Preload: TODO. Treat as NOP for now. */
2503     ic->f = instr(nop);
2504     goto okay;
2505     }
2506    
2507     fatal("TODO: ARM condition code 0x%x\n",
2508     condition_code);
2509     goto bad;
2510     }
2511    
2512    
2513     /*
2514     * Translate the instruction:
2515     */
2516    
2517     switch (main_opcode) {
2518    
2519     case 0x0:
2520     case 0x1:
2521     case 0x2:
2522     case 0x3:
2523     /* Check special cases first: */
2524     if ((iword & 0x0fc000f0) == 0x00000090) {
2525     /*
2526     * Multiplication:
2527     * xxxx0000 00ASdddd nnnnssss 1001mmmm (Rd,Rm,Rs[,Rn])
2528     */
2529     if (iword & 0x00200000) {
2530     if (s_bit)
2531     ic->f = cond_instr(mlas);
2532     else
2533     ic->f = cond_instr(mla);
2534     ic->arg[0] = iword;
2535     } else {
2536     if (s_bit)
2537     ic->f = cond_instr(muls);
2538     else
2539     ic->f = cond_instr(mul);
2540     /* NOTE: rn means rd in this case: */
2541     ic->arg[0] = (size_t)(&cpu->cd.arm.r[rn]);
2542     ic->arg[1] = (size_t)(&cpu->cd.arm.r[rm]);
2543     ic->arg[2] = (size_t)(&cpu->cd.arm.r[r8]);
2544     }
2545     break;
2546     }
2547     if ((iword & 0x0f8000f0) == 0x00800090) {
2548     /* Long multiplication: */
2549     if (s_bit) {
2550     fatal("TODO: sbit mull\n");
2551     goto bad;
2552     }
2553     ic->f = cond_instr(mull);
2554     ic->arg[0] = iword;
2555     break;
2556     }
2557 dpavlin 20 if ((iword & 0x0f900ff0) == 0x01000050) {
2558     fatal("TODO: q{,d}{add,sub}\n");
2559     goto bad;
2560     }
2561 dpavlin 14 if ((iword & 0x0ff000d0) == 0x01200010) {
2562     /* bx or blx */
2563     if (iword & 0x20)
2564     ic->f = cond_instr(blx);
2565     else {
2566     if (cpu->machine->show_trace_tree &&
2567     rm == ARM_LR)
2568     ic->f = cond_instr(bx_trace);
2569     else
2570     ic->f = cond_instr(bx);
2571     }
2572     ic->arg[0] = (size_t)(&cpu->cd.arm.r[rm]);
2573     break;
2574     }
2575     if ((iword & 0x0fb00ff0) == 0x1000090) {
2576     if (iword & 0x00400000)
2577     ic->f = cond_instr(swpb);
2578     else
2579     ic->f = cond_instr(swp);
2580     ic->arg[0] = (size_t)(&cpu->cd.arm.r[rd]);
2581     ic->arg[1] = (size_t)(&cpu->cd.arm.r[rm]);
2582     ic->arg[2] = (size_t)(&cpu->cd.arm.r[rn]);
2583     break;
2584     }
2585 dpavlin 20 if ((iword & 0x0fff0ff0) == 0x016f0f10) {
2586     ic->f = cond_instr(clz);
2587     ic->arg[0] = (size_t)(&cpu->cd.arm.r[rm]);
2588     ic->arg[1] = (size_t)(&cpu->cd.arm.r[rd]);
2589     break;
2590     }
2591     if ((iword & 0x0ff00090) == 0x01000080) {
2592     /* TODO: smlaXX */
2593     goto bad;
2594     }
2595     if ((iword & 0x0ff00090) == 0x01400080) {
2596     /* TODO: smlalY */
2597     goto bad;
2598     }
2599     if ((iword & 0x0ff000b0) == 0x01200080) {
2600     /* TODO: smlawY */
2601     goto bad;
2602     }
2603     if ((iword & 0x0ff0f090) == 0x01600080) {
2604 dpavlin 22 /* smulXY (16-bit * 16-bit => 32-bit) */
2605     switch (iword & 0x60) {
2606     case 0x00: ic->f = cond_instr(smulbb); break;
2607     case 0x20: ic->f = cond_instr(smultb); break;
2608     case 0x40: ic->f = cond_instr(smulbt); break;
2609     default: ic->f = cond_instr(smultt); break;
2610     }
2611     ic->arg[0] = (size_t)(&cpu->cd.arm.r[rm]);
2612     ic->arg[1] = (size_t)(&cpu->cd.arm.r[r8]);
2613     ic->arg[2] = (size_t)(&cpu->cd.arm.r[rn]); /* Rd */
2614     break;
2615 dpavlin 20 }
2616     if ((iword & 0x0ff0f0b0) == 0x012000a0) {
2617     /* TODO: smulwY */
2618     goto bad;
2619     }
2620 dpavlin 14 if ((iword & 0x0fb0fff0) == 0x0120f000 ||
2621     (iword & 0x0fb0f000) == 0x0320f000) {
2622     /* msr: move to [S|C]PSR from a register or
2623     immediate value */
2624     if (iword & 0x02000000) {
2625     if (iword & 0x00400000)
2626     ic->f = cond_instr(msr_imm_spsr);
2627     else
2628     ic->f = cond_instr(msr_imm);
2629     } else {
2630 dpavlin 24 if (rm == ARM_PC) {
2631     fatal("msr PC?\n");
2632     goto bad;
2633     }
2634 dpavlin 14 if (iword & 0x00400000)
2635     ic->f = cond_instr(msr_spsr);
2636     else
2637     ic->f = cond_instr(msr);
2638     }
2639     imm = iword & 0xff;
2640     while (r8-- > 0)
2641     imm = (imm >> 2) | ((imm & 3) << 30);
2642     ic->arg[0] = imm;
2643     ic->arg[2] = (size_t)(&cpu->cd.arm.r[rm]);
2644     switch ((iword >> 16) & 15) {
2645     case 1: ic->arg[1] = 0x000000ff; break;
2646     case 8: ic->arg[1] = 0xff000000; break;
2647     case 9: ic->arg[1] = 0xff0000ff; break;
2648     default:fatal("unimpl a: msr regform\n");
2649     goto bad;
2650     }
2651     break;
2652     }
2653     if ((iword & 0x0fbf0fff) == 0x010f0000) {
2654     /* mrs: move from CPSR/SPSR to a register: */
2655     if (rd == ARM_PC) {
2656     fatal("mrs PC?\n");
2657     goto bad;
2658     }
2659     if (iword & 0x00400000)
2660     ic->f = cond_instr(mrs_spsr);
2661     else
2662     ic->f = cond_instr(mrs);
2663     ic->arg[0] = (size_t)(&cpu->cd.arm.r[rd]);
2664     break;
2665     }
2666     if ((iword & 0x0e000090) == 0x00000090) {
2667     int imm = ((iword >> 4) & 0xf0) | (iword & 0xf);
2668     int regform = !(iword & 0x00400000);
2669     p_bit = main_opcode & 1;
2670     ic->arg[0] = (size_t)(&cpu->cd.arm.r[rn]);
2671     ic->arg[2] = (size_t)(&cpu->cd.arm.r[rd]);
2672     if (rd == ARM_PC || rn == ARM_PC) {
2673     ic->f = arm_load_store_instr_3_pc[
2674     condition_code + (l_bit? 16 : 0)
2675     + (iword & 0x40? 32 : 0)
2676     + (w_bit? 64 : 0)
2677     + (iword & 0x20? 128 : 0)
2678     + (u_bit? 256 : 0) + (p_bit? 512 : 0)
2679     + (regform? 1024 : 0)];
2680     if (rn == ARM_PC)
2681     ic->arg[0] = (size_t)
2682     (&cpu->cd.arm.tmp_pc);
2683     if (!l_bit && rd == ARM_PC)
2684     ic->arg[2] = (size_t)
2685     (&cpu->cd.arm.tmp_pc);
2686     } else
2687     ic->f = arm_load_store_instr_3[
2688     condition_code + (l_bit? 16 : 0)
2689     + (iword & 0x40? 32 : 0)
2690     + (w_bit? 64 : 0)
2691     + (iword & 0x20? 128 : 0)
2692     + (u_bit? 256 : 0) + (p_bit? 512 : 0)
2693     + (regform? 1024 : 0)];
2694     if (regform)
2695 dpavlin 16 ic->arg[1] = (size_t)(void *)arm_r[iword & 0xf];
2696 dpavlin 14 else
2697     ic->arg[1] = imm;
2698     break;
2699     }
2700    
2701     if (iword & 0x80 && !(main_opcode & 2) && iword & 0x10) {
2702     fatal("reg form blah blah\n");
2703     goto bad;
2704     }
2705    
2706 dpavlin 18 /* "mov pc,lr": */
2707     if ((iword & 0x0fffffff) == 0x01a0f00e) {
2708     if (cpu->machine->show_trace_tree)
2709     ic->f = cond_instr(ret_trace);
2710     else
2711     ic->f = cond_instr(ret);
2712 dpavlin 14 break;
2713     }
2714    
2715 dpavlin 20 /* "mov reg,reg" or "mov reg,pc": */
2716     if ((iword & 0x0fff0ff0) == 0x01a00000 && rd != ARM_PC) {
2717     if (rm != ARM_PC) {
2718     ic->f = cond_instr(mov_reg_reg);
2719     ic->arg[0] = (size_t)(&cpu->cd.arm.r[rm]);
2720     } else {
2721     ic->f = cond_instr(mov_reg_pc);
2722     ic->arg[0] = (addr & 0xfff) + 8;
2723     }
2724 dpavlin 14 ic->arg[1] = (size_t)(&cpu->cd.arm.r[rd]);
2725     break;
2726     }
2727    
2728 dpavlin 18 /* "mov reg,#0": */
2729 dpavlin 20 if ((iword & 0x0fff0fff) == 0x03a00000 && rd != ARM_PC) {
2730     arm_switch_clear(ic, rd, condition_code);
2731 dpavlin 18 break;
2732     }
2733    
2734     /* "mov reg,#1": */
2735 dpavlin 20 if ((iword & 0x0fff0fff) == 0x03a00001 && rd != ARM_PC) {
2736     arm_switch_mov1(ic, rd, condition_code);
2737 dpavlin 18 break;
2738     }
2739    
2740 dpavlin 20 /* "add reg,reg,#1": */
2741     if ((iword & 0x0ff00fff) == 0x02800001 && rd != ARM_PC
2742     && rn == rd) {
2743     arm_switch_add1(ic, rd, condition_code);
2744     break;
2745     }
2746    
2747 dpavlin 14 /*
2748     * Generic Data Processing Instructions:
2749     */
2750     if ((main_opcode & 2) == 0)
2751     regform = 1;
2752     else
2753     regform = 0;
2754    
2755 dpavlin 16 if (regform) {
2756     /* 0x1000 signifies Carry bit update on rotation,
2757     which is not necessary for add,adc,sub,sbc,
2758     rsb,rsc,cmp, or cmn, because they update the
2759     Carry bit manually anyway. */
2760     int q = 0x1000;
2761     if (s_bit == 0)
2762     q = 0;
2763     if ((secondary_opcode >= 2 && secondary_opcode <= 7)
2764     || secondary_opcode==0xa || secondary_opcode==0xb)
2765     q = 0;
2766     ic->arg[1] = (size_t)(void *)arm_r[(iword & 0xfff) + q];
2767     } else {
2768 dpavlin 14 imm = iword & 0xff;
2769     while (r8-- > 0)
2770     imm = (imm >> 2) | ((imm & 3) << 30);
2771     ic->arg[1] = imm;
2772     }
2773    
2774 dpavlin 20 /* mvn #imm ==> mov #~imm */
2775     if (secondary_opcode == 0xf && !regform) {
2776     secondary_opcode = 0xd;
2777     ic->arg[1] = ~ic->arg[1];
2778     }
2779    
2780 dpavlin 14 ic->arg[0] = (size_t)(&cpu->cd.arm.r[rn]);
2781     ic->arg[2] = (size_t)(&cpu->cd.arm.r[rd]);
2782     any_pc_reg = 0;
2783     if (rn == ARM_PC || rd == ARM_PC)
2784     any_pc_reg = 1;
2785    
2786 dpavlin 20 if (!any_pc_reg && regform && (iword & 0xfff) < ARM_PC) {
2787     ic->arg[1] = (size_t)(&cpu->cd.arm.r[rm]);
2788     ic->f = arm_dpi_instr_regshort[condition_code +
2789     16 * secondary_opcode + (s_bit? 256 : 0)];
2790     } else
2791     ic->f = arm_dpi_instr[condition_code +
2792     16 * secondary_opcode + (s_bit? 256 : 0) +
2793     (any_pc_reg? 512 : 0) + (regform? 1024 : 0)];
2794 dpavlin 18
2795 dpavlin 20 if (ic->f == instr(eor_regshort))
2796 dpavlin 22 cpu->cd.arm.combination_check = COMBINE(xchg);
2797 dpavlin 18 if (iword == 0xe113000c)
2798 dpavlin 22 cpu->cd.arm.combination_check = COMBINE(netbsd_scanc);
2799 dpavlin 14 break;
2800    
2801     case 0x4: /* Load and store... */
2802     case 0x5: /* xxxx010P UBWLnnnn ddddoooo oooooooo Immediate */
2803     case 0x6: /* xxxx011P UBWLnnnn ddddcccc ctt0mmmm Register */
2804     case 0x7:
2805     ic->arg[0] = (size_t)(&cpu->cd.arm.r[rn]);
2806     ic->arg[2] = (size_t)(&cpu->cd.arm.r[rd]);
2807     if (rd == ARM_PC || rn == ARM_PC) {
2808     ic->f = arm_load_store_instr_pc[((iword >> 16)
2809     & 0x3f0) + condition_code];
2810     if (rn == ARM_PC)
2811     ic->arg[0] = (size_t)(&cpu->cd.arm.tmp_pc);
2812     if (!l_bit && rd == ARM_PC)
2813     ic->arg[2] = (size_t)(&cpu->cd.arm.tmp_pc);
2814     } else {
2815     ic->f = arm_load_store_instr[((iword >> 16) &
2816     0x3f0) + condition_code];
2817     }
2818     imm = iword & 0xfff;
2819     if (main_opcode < 6)
2820     ic->arg[1] = imm;
2821     else
2822 dpavlin 16 ic->arg[1] = (size_t)(void *)arm_r[iword & 0xfff];
2823 dpavlin 14 if ((iword & 0x0e000010) == 0x06000010) {
2824     fatal("Not a Load/store TODO\n");
2825     goto bad;
2826     }
2827 dpavlin 20 /* Special case: pc-relative load within the same page: */
2828     if (rn == ARM_PC && rd != ARM_PC && main_opcode < 6) {
2829     int ofs = (addr & 0xfff) + 8, max = 0xffc;
2830     int b_bit = iword & 0x00400000;
2831     if (b_bit)
2832     max = 0xfff;
2833     if (u_bit)
2834     ofs += (iword & 0xfff);
2835     else
2836     ofs -= (iword & 0xfff);
2837     /* NOTE/TODO: This assumes 4KB pages,
2838     it will not work with 1KB pages. */
2839     if (ofs >= 0 && ofs <= max) {
2840     unsigned char *p;
2841     unsigned char c[4];
2842     int len = b_bit? 1 : 4;
2843     uint32_t x, a = (addr & 0xfffff000) | ofs;
2844     /* ic->f = cond_instr(mov); */
2845     ic->f = arm_dpi_instr[condition_code + 16*0xd];
2846     ic->arg[2] = (size_t)(&cpu->cd.arm.r[rd]);
2847     p = cpu->cd.arm.host_load[a >> 12];
2848     if (p != NULL) {
2849     memcpy(c, p + (a & 0xfff), len);
2850     } else {
2851     if (!cpu->memory_rw(cpu, cpu->mem, a,
2852     c, len, MEM_READ, CACHE_DATA)) {
2853     fatal("to_be_translated(): "
2854     "read failed X: TODO\n");
2855     goto bad;
2856     }
2857     }
2858     if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
2859     x = c[0] + (c[1]<<8) +
2860     (c[2]<<16) + (c[3]<<24);
2861     else
2862     x = c[3] + (c[2]<<8) +
2863     (c[1]<<16) + (c[0]<<24);
2864     if (b_bit)
2865     x = c[0];
2866     ic->arg[1] = x;
2867     }
2868     }
2869     if (iword == 0xe4b09004)
2870 dpavlin 22 cpu->cd.arm.combination_check = COMBINE(netbsd_copyin);
2871 dpavlin 20 if (iword == 0xe4a17004)
2872 dpavlin 22 cpu->cd.arm.combination_check = COMBINE(netbsd_copyout);
2873 dpavlin 14 break;
2874    
2875     case 0x8: /* Multiple load/store... (Block data transfer) */
2876     case 0x9: /* xxxx100P USWLnnnn llllllll llllllll */
2877 dpavlin 18 ic->arg[0] = (size_t)(&cpu->cd.arm.r[rn]);
2878     ic->arg[1] = (size_t)iword;
2879     /* Generic case: */
2880 dpavlin 14 if (l_bit)
2881     ic->f = cond_instr(bdt_load);
2882     else
2883     ic->f = cond_instr(bdt_store);
2884 dpavlin 18 #if defined(HOST_LITTLE_ENDIAN) && !defined(GATHER_BDT_STATISTICS)
2885     /*
2886     * Check for availability of optimized implementation:
2887     * xxxx100P USWLnnnn llllllll llllllll
2888     * ^ ^ ^ ^ ^ ^ ^ ^ (0x00950154)
2889     * These bits are used to select which list to scan, and then
2890     * the list is scanned linearly.
2891     *
2892     * The optimized functions do not support show_trace_tree,
2893     * but it's ok to use the unoptimized version in that case.
2894     */
2895     if (!cpu->machine->show_trace_tree) {
2896     int i = 0, j = iword;
2897     j = ((j & 0x00800000) >> 16) | ((j & 0x00100000) >> 14)
2898     | ((j & 0x00040000) >> 13) | ((j & 0x00010000) >> 12)
2899     | ((j & 0x00000100) >> 5) | ((j & 0x00000040) >> 4)
2900     | ((j & 0x00000010) >> 3) | ((j & 0x00000004) >> 2);
2901     while (multi_opcode[j][i] != 0) {
2902     if ((iword & 0x0fffffff) ==
2903     multi_opcode[j][i]) {
2904     ic->f = multi_opcode_f[j]
2905     [i*16 + condition_code];
2906     break;
2907     }
2908     i ++;
2909     }
2910     }
2911     #endif
2912 dpavlin 14 if (rn == ARM_PC) {
2913     fatal("TODO: bdt with PC as base\n");
2914     goto bad;
2915     }
2916     break;
2917    
2918     case 0xa: /* B: branch */
2919     case 0xb: /* BL: branch+link */
2920     if (main_opcode == 0x0a) {
2921     ic->f = cond_instr(b);
2922     samepage_function = cond_instr(b_samepage);
2923 dpavlin 18 if (iword == 0xcaffffed)
2924 dpavlin 20 cpu->cd.arm.combination_check =
2925 dpavlin 22 COMBINE(netbsd_memset);
2926 dpavlin 18 if (iword == 0xaafffff9)
2927 dpavlin 20 cpu->cd.arm.combination_check =
2928 dpavlin 22 COMBINE(netbsd_memcpy);
2929 dpavlin 14 } else {
2930     if (cpu->machine->show_trace_tree) {
2931     ic->f = cond_instr(bl_trace);
2932     samepage_function =
2933     cond_instr(bl_samepage_trace);
2934     } else {
2935     ic->f = cond_instr(bl);
2936     samepage_function = cond_instr(bl_samepage);
2937     }
2938     }
2939    
2940 dpavlin 20 /* arg 1 = offset of current instruction */
2941     /* arg 2 = offset of the following instruction */
2942     ic->arg[1] = addr & 0xffc;
2943     ic->arg[2] = (addr & 0xffc) + 4;
2944    
2945 dpavlin 14 ic->arg[0] = (iword & 0x00ffffff) << 2;
2946     /* Sign-extend: */
2947     if (ic->arg[0] & 0x02000000)
2948     ic->arg[0] |= 0xfc000000;
2949     /*
2950     * Branches are calculated as PC + 8 + offset.
2951     */
2952     ic->arg[0] = (int32_t)(ic->arg[0] + 8);
2953    
2954 dpavlin 20 /*
2955     * Special case: branch within the same page:
2956     *
2957     * arg[0] = addr of the arm_instr_call of the target
2958     * arg[1] = addr of the next arm_instr_call.
2959     */
2960 dpavlin 14 {
2961     uint32_t mask_within_page =
2962     ((ARM_IC_ENTRIES_PER_PAGE-1) <<
2963     ARM_INSTR_ALIGNMENT_SHIFT) |
2964     ((1 << ARM_INSTR_ALIGNMENT_SHIFT) - 1);
2965     uint32_t old_pc = addr;
2966     uint32_t new_pc = old_pc + (int32_t)ic->arg[0];
2967     if ((old_pc & ~mask_within_page) ==
2968     (new_pc & ~mask_within_page)) {
2969     ic->f = samepage_function;
2970     ic->arg[0] = (size_t) (
2971     cpu->cd.arm.cur_ic_page +
2972     ((new_pc & mask_within_page) >>
2973     ARM_INSTR_ALIGNMENT_SHIFT));
2974 dpavlin 20 ic->arg[1] = (size_t) (
2975     cpu->cd.arm.cur_ic_page +
2976     (((addr & mask_within_page) + 4) >>
2977     ARM_INSTR_ALIGNMENT_SHIFT));
2978     } else if (main_opcode == 0x0a) {
2979     /* Special hack for a plain "b": */
2980     ic->arg[0] += ic->arg[1];
2981 dpavlin 14 }
2982     }
2983 dpavlin 18
2984 dpavlin 20 if (main_opcode == 0xa && (condition_code <= 1
2985     || condition_code == 3 || condition_code == 8
2986     || condition_code == 12 || condition_code == 13))
2987 dpavlin 22 cpu->cd.arm.combination_check = COMBINE(cmps_b);
2988 dpavlin 20
2989     if (iword == 0x1afffffc)
2990 dpavlin 22 cpu->cd.arm.combination_check = COMBINE(strlen);
2991 dpavlin 20
2992     /* Hm. Does this really increase performance? */
2993 dpavlin 18 if (iword == 0x8afffffa)
2994 dpavlin 20 cpu->cd.arm.combination_check =
2995 dpavlin 22 COMBINE(netbsd_cacheclean2);
2996 dpavlin 14 break;
2997    
2998 dpavlin 20 case 0xc:
2999     case 0xd:
3000     /*
3001     * xxxx1100 0100nnnn ddddcccc oooommmm MCRR c,op,Rd,Rn,CRm
3002     * xxxx1100 0101nnnn ddddcccc oooommmm MRRC c,op,Rd,Rn,CRm
3003     */
3004 dpavlin 22 if ((iword & 0x0fe00fff) == 0x0c400000) {
3005     /* Special case: mar/mra DSP instructions */
3006     fatal("TODO: mar/mra DSP instructions!\n");
3007     /* Perhaps these are actually identical to MCRR/MRRC */
3008     goto bad;
3009     }
3010    
3011 dpavlin 20 if ((iword & 0x0fe00000) == 0x0c400000) {
3012     fatal("MCRR/MRRC: TODO\n");
3013     goto bad;
3014     }
3015    
3016     /*
3017     * TODO: LDC/STC
3018     *
3019     * For now, treat as Undefined instructions. This causes e.g.
3020     * Linux/ARM to emulate these instructions (floating point).
3021     */
3022 dpavlin 22 #if 0
3023 dpavlin 20 ic->f = cond_instr(und);
3024     ic->arg[0] = addr & 0xfff;
3025 dpavlin 22 #else
3026     fatal("LDC/STC: TODO\n");
3027     goto bad;
3028     #endif
3029 dpavlin 20 break;
3030    
3031 dpavlin 14 case 0xe:
3032 dpavlin 22 if ((iword & 0x0ff00ff0) == 0x0e200010) {
3033     /* Special case: mia* DSP instructions */
3034     /* See Intel's 27343601.pdf, page 16-20 */
3035     fatal("TODO: mia* DSP instructions!\n");
3036     goto bad;
3037     }
3038 dpavlin 14 if (iword & 0x10) {
3039     /* xxxx1110 oooLNNNN ddddpppp qqq1MMMM MCR/MRC */
3040     ic->arg[0] = iword;
3041     ic->f = cond_instr(mcr_mrc);
3042     } else {
3043     /* xxxx1110 oooonnnn ddddpppp qqq0mmmm CDP */
3044     ic->arg[0] = iword;
3045     ic->f = cond_instr(cdp);
3046     }
3047 dpavlin 18 if (iword == 0xee070f9a)
3048 dpavlin 20 cpu->cd.arm.combination_check =
3049 dpavlin 22 COMBINE(netbsd_cacheclean);
3050 dpavlin 14 break;
3051    
3052     case 0xf:
3053     /* SWI: */
3054     /* Default handler: */
3055     ic->f = cond_instr(swi);
3056 dpavlin 20 ic->arg[0] = addr & 0xfff;
3057     if (iword == 0xef8c64eb) {
3058     /* Hack for rebooting a machine: */
3059     ic->f = instr(reboot);
3060     } else if (iword == 0xef8c64be) {
3061 dpavlin 14 /* Hack for openfirmware prom emulation: */
3062     ic->f = instr(openfirmware);
3063     } else if (cpu->machine->userland_emul != NULL) {
3064     if ((iword & 0x00f00000) == 0x00a00000) {
3065     ic->arg[0] = iword & 0x00ffffff;
3066     ic->f = cond_instr(swi_useremul);
3067     } else {
3068     fatal("Bad userland SWI?\n");
3069     goto bad;
3070     }
3071     }
3072     break;
3073    
3074     default:goto bad;
3075     }
3076    
3077     okay:
3078    
3079     #define DYNTRANS_TO_BE_TRANSLATED_TAIL
3080     #include "cpu_dyntrans.c"
3081     #undef DYNTRANS_TO_BE_TRANSLATED_TAIL
3082     }
3083    

  ViewVC Help
Powered by ViewVC 1.1.26