/[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 24 - (hide annotations)
Mon Oct 8 16:19:56 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 79970 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1256 2006/06/23 20:43:44 debug Exp $
20060219	Various minor updates. Removing the old MIPS16 skeleton code,
		because it will need to be rewritten for dyntrans anyway.
20060220-22	Removing the non-working dyntrans backend support.
		Continuing on the 64-bit dyntrans virtual memory generalization.
20060223	More work on the 64-bit vm generalization.
20060225	Beginning on MIPS dyntrans load/store instructions.
		Minor PPC updates (64-bit load/store, etc).
		Fixes for the variable-instruction-length framework, some
		minor AVR updates (a simple Hello World program works!).
		Beginning on a skeleton for automatically generating documen-
		tation (for devices etc.).
20060226	PPC updates (adding some more 64-bit instructions, etc).
		AVR updates (more instructions).
		FINALLY found and fixed the zs bug, making NetBSD/macppc
		accept the serial console.
20060301	Adding more AVR instructions.
20060304	Continuing on AVR-related stuff. Beginning on a framework for
		cycle-accurate device emulation. Adding an experimental "PAL
		TV" device (just a dummy so far).
20060305	Adding more AVR instructions.
		Adding a dummy epcom serial controller (for TS7200 emulation).
20060310	Removing the emul() command from configuration files, so only
		net() and machine() are supported.
		Minor progress on the MIPS dyntrans rewrite.
20060311	Continuing on the MIPS dyntrans rewrite (adding more
		instructions, etc).
20060315	Adding more instructions (sllv, srav, srlv, bgtz[l], blez[l],
		beql, bnel, slti[u], various loads and stores).
20060316	Removing the ALWAYS_SIGNEXTEND_32 option, since it was rarely
		used.
		Adding more MIPS dyntrans instructions, and fixing bugs.
20060318	Implementing fast loads/stores for MIPS dyntrans (big/little
		endian, 32-bit and 64-bit modes).
20060320	Making MIPS dyntrans the default configure option; use
		"--enable-oldmips" to use the old bintrans system.
		Adding MIPS dyntrans dmult[u]; minor updates.
20060322	Continuing... adding some more instructions.
		Adding a simple skeleton for demangling C++ "_ZN" symbols.
20060323	Moving src/debugger.c into a new directory (src/debugger/).
20060324	Fixing the hack used to load PPC ELFs (useful for relocated
		Linux/ppc kernels), and adding a dummy G3 machine mode.
20060325-26	Beginning to experiment with GDB remote serial protocol
		connections; adding a -G command line option for selecting
		which TCP port to listen to.
20060330	Beginning a major cleanup to replace things like "0x%016llx"
		with more correct "0x%016"PRIx64, etc.
		Continuing on the GDB remote serial protocol support.
20060331	More cleanup, and some minor GDB remote progress.
20060402	Adding a hack to the configure script, to allow compilation
		on systems that lack PRIx64 etc.
20060406	Removing the temporary FreeBSD/arm hack in dev_ns16550.c and
		replacing it with a better fix from Olivier Houchard.
20060407	A remote debugger (gdb or ddd) can now start and stop the
		emulator using the GDB remote serial protocol, and registers
		and memory can be read. MIPS only for now.
20060408	More GDB progress: single-stepping also works, and also adding
		support for ARM, PowerPC, and Alpha targets.
		Continuing on the delay-slot-across-page-boundary issue.
20060412	Minor update: beginning to add support for the SPARC target
		to the remote GDB functionality.
20060414	Various MIPS updates: adding more instructions for dyntrans
		(eret, add), and making some exceptions work. Fixing a bug
		in dmult[u].
		Implementing the first SPARC instructions (sethi, or).
20060415	Adding "magic trap" instructions so that PROM calls can be
		software emulated in MIPS dyntrans.
		Adding more MIPS dyntrans instructions (ddiv, dadd) and
		fixing another bug in dmult.
20060416	More MIPS dyntrans progress: adding [d]addi, movn, movz, dsllv,
		rfi, an ugly hack for supporting R2000/R3000 style faked caches,
		preliminary interrupt support, and various other updates and
		bugfixes.
20060417	Adding more SPARC instructions (add, sub, sll[x], sra[x],
		srl[x]), and useful SPARC header definitions.
		Adding the first (trivial) x86/AMD64 dyntrans instructions (nop,
		cli/sti, stc/clc, std/cld, simple mov, inc ax). Various other
		x86 updates related to variable instruction length stuff.
		Adding unaligned loads/stores to the MIPS dyntrans mode (but
		still using the pre-dyntrans (slow) imlementation).
20060419	Fixing a MIPS dyntrans exception-in-delay-slot bug.
		Removing the old "show opcode statistics" functionality, since
		it wasn't really useful and isn't implemented for dyntrans.
		Single-stepping (or running with instruction trace) now looks
		ok with dyntrans with delay-slot architectures.
20060420	Minor hacks (removing the -B command line option when compiled
		for non-bintrans, and some other very minor updates).
		Adding (slow) MIPS dyntrans load-linked/store-conditional.
20060422	Applying fixes for bugs discovered by Nils Weller's nwcc
		(static DEC memmap => now per machine, and adding an extern
		keyword in cpu_arm_instr.c).
		Finally found one of the MIPS dyntrans bugs that I've been
		looking for (copy/paste spelling error BIG vs LITTLE endian in
		cpu_mips_instr_loadstore.c for 16-bit fast stores).
		FINALLY found the major MIPS dyntrans bug: slti vs sltiu
		signed/unsigned code in cpu_mips_instr.c. :-)
		Adding more MIPS dyntrans instructions (lwc1, swc1, bgezal[l],
		ctc1, tlt[u], tge[u], tne, beginning on rdhwr).
		NetBSD/hpcmips can now reach userland when using dyntrans :-)
		Adding some more x86 dyntrans instructions.
		Finally removed the old Alpha-specific virtual memory code,
		and replaced it with the generic 64-bit version.
		Beginning to add disassembly support for SPECIAL3 MIPS opcodes.
20060423	Continuing on the delay-slot-across-page-boundary issue;
		adding an end_of_page2 ic slot (like I had planned before, but
		had removed for some reason).
		Adding a quick-and-dirty fallback to legacy coprocessor 1
		code (i.e. skipping dyntrans implementation for now).
		NetBSD/hpcmips and NetBSD/pmax (when running on an emulated
		R4400) can now be installed and run. :-)  (Many bugs left
		to fix, though.)
		Adding more MIPS dyntrans instructions: madd[u], msub[u].
		Cleaning up the SPECIAL2 vs R5900/TX79/C790 "MMI" opcode
		maps somewhat (disassembly and dyntrans instruction decoding).
20060424	Adding an isa_revision field to mips_cpu_types.h, and making
		sure that SPECIAL3 opcodes cause Reserved Instruction
		exceptions on MIPS32/64 revisions lower than 2.
		Adding the SPARC 'ba', 'call', 'jmpl/retl', 'and', and 'xor'
		instructions.
20060425	Removing the -m command line option ("run at most x 
		instructions") and -T ("single_step_on_bad_addr"), because
		they never worked correctly with dyntrans anyway.
		Freshening up the man page.
20060428	Adding more MIPS dyntrans instructions: bltzal[l], idle.
		Enabling MIPS dyntrans compare interrupts.
20060429	FINALLY found the weird dyntrans bug, causing NetBSD etc. to
		behave strangely: some floating point code (conditional
		coprocessor branches) could not be reused from the old
		non-dyntrans code. The "quick-and-dirty fallback" only appeared
		to work. Fixing by implementing bc1* for MIPS dyntrans.
		More MIPS instructions: [d]sub, sdc1, ldc1, dmtc1, dmfc1, cfc0.
		Freshening up MIPS floating point disassembly appearance.
20060430	Continuing on C790/R5900/TX79 disassembly; implementing 128-bit
		"por" and "pextlw".
20060504	Disabling -u (userland emulation) unless compiled as unstable
		development version.
		Beginning on freshening up the testmachine include files,
		to make it easier to reuse those files (placing them in
		src/include/testmachine/), and beginning on a set of "demos"
		or "tutorials" for the testmachine functionality.
		Minor updates to the MIPS GDB remote protocol stub.
		Refreshing doc/experiments.html and gdb_remote.html.
		Enabling Alpha emulation in the stable release configuration,
		even though no guest OSes for Alpha can run yet.
20060505	Adding a generic 'settings' object, which will contain
		references to settable variables (which will later be possible
		to access using the debugger).
20060506	Updating dev_disk and corresponding demo/documentation (and
		switching from SCSI to IDE disk types, so it actually works
		with current test machines :-).
20060510	Adding a -D_LARGEFILE_SOURCE hack for 64-bit Linux hosts,
		so that fseeko() doesn't give a warning.
		Updating the section about how dyntrans works (the "runnable
		IR") in doc/intro.html.
		Instruction updates (some x64=1 checks, some more R5900
		dyntrans stuff: better mul/mult separation from MIPS32/64,
		adding ei and di).
		Updating MIPS cpuregs.h to a newer one (from NetBSD).
		Adding more MIPS dyntrans instructions: deret, ehb.
20060514	Adding disassembly and beginning implementation of SPARC wr
		and wrpr instructions.
20060515	Adding a SUN SPARC machine mode, with dummy SS20 and Ultra1
		machines. Adding the 32-bit "rd psr" instruction.
20060517	Disassembly support for the general SPARC rd instruction.
		Partial implementation of the cmp (subcc) instruction.
		Some other minor updates (making sure that R5900 processors
		start up with the EIE bit enabled, otherwise Linux/playstation2
		receives no interrupts).
20060519	Minor MIPS updates/cleanups.
20060521	Moving the MeshCube machine into evbmips; this seems to work
		reasonably well with a snapshot of a NetBSD MeshCube kernel.
		Cleanup/fix of MIPS config0 register initialization.
20060529	Minor MIPS fixes, including a sign-extension fix to the
		unaligned load/store code, which makes NetBSD/pmax on R3000
		work better with dyntrans. (Ultrix and Linux/DECstation still
		don't work, though.)
20060530	Minor updates to the Alpha machine mode: adding an AlphaBook
		mode, an LCA bus (forwarding accesses to an ISA bus), etc.
20060531	Applying a bugfix for the MIPS dyntrans sc[d] instruction from
		Ondrej Palkovsky. (Many thanks.)
20060601	Minifix to allow ARM immediate msr instruction to not give
		an error for some valid values.
		More Alpha updates.
20060602	Some minor Alpha updates.
20060603	Adding the Alpha cmpbge instruction. NetBSD/alpha prints its
		first boot messages :-) on an emulated Alphabook 1.
20060612	Minor updates; adding a dev_ether.h include file for the
		testmachine ether device. Continuing the hunt for the dyntrans
		bug which makes Linux and Ultrix on DECstation behave
		strangely... FINALLY found it! It seems to be related to
		invalidation of the translation cache, on tlbw{r,i}. There
		also seems to be some remaining interrupt-related problems.
20060614	Correcting the implementation of ldc1/sdc1 for MIPS dyntrans
		(so that it uses 16 32-bit registers if the FR bit in the
		status register is not set).
20060616	REMOVING BINTRANS COMPLETELY!
		Removing the old MIPS interpretation mode.
		Removing the MFHILO_DELAY and instruction delay stuff, because
		they wouldn't work with dyntrans anyway.
20060617	Some documentation updates (adding "NetBSD-archive" to some
		URLs, and new Debian/DECstation installation screenshots).
		Removing the "tracenull" and "enable-caches" configure options.
		Improving MIPS dyntrans performance somewhat (only invalidate
		translations if necessary, on writes to the entryhi register,
		instead of doing it for all cop0 writes).
20060618	More cleanup after the removal of the old MIPS emulation.
		Trying to fix the MIPS dyntrans performance bugs/bottlenecks;
		only semi-successful so far (for R3000).
20060620	Minor update to allow clean compilation again on Tru64/Alpha.
20060622	MIPS cleanup and fixes (removing the pc_last stuff, which
		doesn't make sense with dyntrans anyway, and fixing a cross-
		page-delay-slot-with-exception case in end_of_page).
		Removing the old max_random_cycles_per_chunk stuff, and the
		concept of cycles vs instructions for MIPS emulation.
		FINALLY found and fixed the bug which caused NetBSD/pmax
		clocks to behave strangely (it was a load to the zero register,
		which was treated as a NOP; now it is treated as a load to a
		dummy scratch register).
20060623	Increasing the dyntrans chunk size back to
		N_SAFE_DYNTRANS_LIMIT, instead of N_SAFE_DYNTRANS_LIMIT/2.
		Preparing for a quick release, even though there are known
		bugs, and performance for non-R3000 MIPS emulation is very
		poor. :-/
		Reverting to half the dyntrans chunk size again, because
		NetBSD/cats seemed less stable with full size chunks. :(
		NetBSD/sgimips 3.0 can now run :-)  (With release 0.3.8, only
		NetBSD/sgimips 2.1 worked, not 3.0.)

==============  RELEASE 0.4.0  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26