/[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 22 - (hide annotations)
Mon Oct 8 16:19:37 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 80066 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1121 2006/02/18 21:03:08 debug Exp $
20051126	Cobalt and PReP now work with the 21143 NIC.
		Continuing on Alpha dyntrans things.
		Fixing some more left-shift-by-24 to unsigned.
20051127	Working on OpenFirmware emulation; major cleanup/redesign.
		Progress on MacPPC emulation: NetBSD detects two CPUs (when
		running with -n 2), framebuffer output (for text) works.
		Adding quick-hack Bandit PCI controller and "gc" interrupt
		controller for MacPPC.
20051128	Changing from a Bandit to a Uni-North controller for macppc.
		Continuing on OpenFirmware and MacPPC emulation in general
		(obio controller, and wdc attached to the obio seems to work).
20051129	More work on MacPPC emulation (adding a dummy ADB controller).
		Continuing the PCI bus cleanup (endianness and tag composition)
		and rewriting all PCI controllers' access functions.
20051130	Various minor PPC dyntrans optimizations.
		Manually inlining some parts of the framebuffer redraw routine.
		Slowly beginning the conversion of the old MIPS emulation into
		dyntrans (but this will take quite some time to get right).
		Generalizing quick_pc_to_pointers.
20051201	Documentation update (David Muse has made available a kernel
		which simplifies Debian/DECstation installation).
		Continuing on the ADB bus controller.
20051202	Beginning a rewrite of the Zilog serial controller (dev_zs).
20051203	Continuing on the zs rewrite (now called dev_z8530); conversion
		to devinit style.
		Reworking some of the input-only vs output-only vs input-output
		details of src/console.c, better warning messages, and adding
		a debug dump.
		Removing the concept of "device state"; it wasn't really used.
		Changing some debug output (-vv should now be used to show all
		details about devices and busses; not shown during normal
		startup anymore).
		Beginning on some SPARC instruction disassembly support.
20051204	Minor PPC updates (WALNUT skeleton stuff).
		Continuing on the MIPS dyntrans rewrite.
		More progress on the ADB controller (a keyboard is "detected"
		by NetBSD and OpenBSD).
		Downgrading OpenBSD/arc as a guest OS from "working" to
		"almost working" in the documentation.
		Progress on Algor emulation ("v3" PCI controller).
20051205	Minor updates.
20051207	Sorting devices according to address; this reduces complexity
		of device lookups from O(n) to O(log n) in memory_rw (but no
		real performance increase (yet) in experiments).
20051210	Beginning the work on native dyntrans backends (by making a
		simple skeleton; so far only for Alpha hosts).
20051211	Some very minor SPARC updates.
20051215	Fixing a bug in the MIPS mul (note: not mult) instruction,
		so it also works with non-64-bit emulation. (Thanks to Alec
		Voropay for noticing the problem.)
20051216	More work on the fake/empty/simple/skeleton/whatever backend;
		performance doesn't increase, so this isn't really worth it,
		but it was probably worth it to prepare for a real backend
		later.
20051219	More instr call statistics gathering and analysis stuff.
20051220	Another fix for MIPS 'mul'. Also converting mul and {d,}cl{o,z}
		to dyntrans.
		memory_ppc.c syntax error fix (noticed by Peter Valchev).
		Beginning to move out machines from src/machine.c into
		individual files in src/machines (in a way similar to the
		autodev system for devices).
20051222	Updating the documentation regarding NetBSD/pmax 3.0.
20051223	- " - NetBSD/cats 3.0.
20051225	- " - NetBSD/hpcmips 3.0.
20051226	Continuing on the machine registry redesign.
		Adding support for ARM rrx (33-bit rotate).
		Fixing some signed/unsigned issues (exposed by gcc -W).
20051227	Fixing the bug which prevented a NetBSD/prep 3.0 install kernel
		from starting (triggered when an mtmsr was the last instruction
		on a page). Unfortunately not enough to get the kernel to run
		as well as the 2.1 kernels did.
20051230	Some dyntrans refactoring.
20051231	Continuing on the machine registry redesign.
20060101-10	Continuing... moving more machines. Moving MD interrupt stuff
		from machine.c into a new src/machines/interrupts.c.
20060114	Adding various mvmeppc machine skeletons.
20060115	Continuing on mvme* stuff. NetBSD/mvmeppc prints boot messages
		(for MVME1600) and reaches the root device prompt, but no
		specific hardware devices are emulated yet.
20060116	Minor updates to the mvme1600 emulation mode; the Eagle PCI bus
		seems to work without much modification, and a 21143 can be
		detected, interrupts might work (but untested so far).
		Adding a fake MK48Txx (mkclock) device, for NetBSD/mvmeppc.
20060121	Adding an aux control register for ARM. (A BIG thank you to
		Olivier Houchard for tracking down this bug.)
20060122	Adding more ARM instructions (smulXY), and dev_iq80321_7seg.
20060124	Adding disassembly of more ARM instructions (mia*, mra/mar),
		and some semi-bogus XScale and i80321 registers.
20060201-02	Various minor updates. Moving the last machines out of
		machine.c.
20060204	Adding a -c command line option, for running debugger commands
		before the simulation starts, but after all files have been
		loaded.
		Minor iq80321-related updates.
20060209	Minor hacks (DEVINIT macro, etc).
		Preparing for the generalization of the 64-bit dyntrans address
		translation subsystem.
20060216	Adding ARM ldrd (double-register load).
20060217	Continuing on various ARM-related stuff.
20060218	More progress on the ATA/wdc emulation for NetBSD/iq80321.
		NetBSD/evbarm can now be installed :-)  Updating the docs, etc.
		Continuing on Algor emulation.

==============  RELEASE 0.3.8  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26