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

Contents of /trunk/src/cpus/cpu_arm_instr.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 24 - (show 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 /*
2 * Copyright (C) 2005-2006 Anders Gavare. All rights reserved.
3 *
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 * $Id: cpu_arm_instr.c,v 1.65 2006/06/23 12:49:46 debug Exp $
29 *
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 /* #define GATHER_BDT_STATISTICS */
40
41
42 #ifdef GATHER_BDT_STATISTICS
43 /*
44 * 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 * 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 *
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 */
125
126 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 #define Y(n) void arm_instr_ ## n ## __eq(struct cpu *cpu, \
131 struct arm_instr_call *ic) \
132 { if (cpu->cd.arm.flags & ARM_F_Z) \
133 arm_instr_ ## n (cpu, ic); } \
134 void arm_instr_ ## n ## __ne(struct cpu *cpu, \
135 struct arm_instr_call *ic) \
136 { if (!(cpu->cd.arm.flags & ARM_F_Z)) \
137 arm_instr_ ## n (cpu, ic); } \
138 void arm_instr_ ## n ## __cs(struct cpu *cpu, \
139 struct arm_instr_call *ic) \
140 { if (cpu->cd.arm.flags & ARM_F_C) \
141 arm_instr_ ## n (cpu, ic); } \
142 void arm_instr_ ## n ## __cc(struct cpu *cpu, \
143 struct arm_instr_call *ic) \
144 { if (!(cpu->cd.arm.flags & ARM_F_C)) \
145 arm_instr_ ## n (cpu, ic); } \
146 void arm_instr_ ## n ## __mi(struct cpu *cpu, \
147 struct arm_instr_call *ic) \
148 { if (cpu->cd.arm.flags & ARM_F_N) \
149 arm_instr_ ## n (cpu, ic); } \
150 void arm_instr_ ## n ## __pl(struct cpu *cpu, \
151 struct arm_instr_call *ic) \
152 { if (!(cpu->cd.arm.flags & ARM_F_N)) \
153 arm_instr_ ## n (cpu, ic); } \
154 void arm_instr_ ## n ## __vs(struct cpu *cpu, \
155 struct arm_instr_call *ic) \
156 { if (cpu->cd.arm.flags & ARM_F_V) \
157 arm_instr_ ## n (cpu, ic); } \
158 void arm_instr_ ## n ## __vc(struct cpu *cpu, \
159 struct arm_instr_call *ic) \
160 { if (!(cpu->cd.arm.flags & ARM_F_V)) \
161 arm_instr_ ## n (cpu, ic); } \
162 void arm_instr_ ## n ## __hi(struct cpu *cpu, \
163 struct arm_instr_call *ic) \
164 { if (condition_hi[cpu->cd.arm.flags]) \
165 arm_instr_ ## n (cpu, ic); } \
166 void arm_instr_ ## n ## __ls(struct cpu *cpu, \
167 struct arm_instr_call *ic) \
168 { if (!condition_hi[cpu->cd.arm.flags]) \
169 arm_instr_ ## n (cpu, ic); } \
170 void arm_instr_ ## n ## __ge(struct cpu *cpu, \
171 struct arm_instr_call *ic) \
172 { if (condition_ge[cpu->cd.arm.flags]) \
173 arm_instr_ ## n (cpu, ic); } \
174 void arm_instr_ ## n ## __lt(struct cpu *cpu, \
175 struct arm_instr_call *ic) \
176 { if (!condition_ge[cpu->cd.arm.flags]) \
177 arm_instr_ ## n (cpu, ic); } \
178 void arm_instr_ ## n ## __gt(struct cpu *cpu, \
179 struct arm_instr_call *ic) \
180 { if (condition_gt[cpu->cd.arm.flags]) \
181 arm_instr_ ## n (cpu, ic); } \
182 void arm_instr_ ## n ## __le(struct cpu *cpu, \
183 struct arm_instr_call *ic) \
184 { if (!condition_gt[cpu->cd.arm.flags]) \
185 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 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1)
211 << ARM_INSTR_ALIGNMENT_SHIFT);
212 cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
213
214 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
221
222 /*
223 * nop: Do nothing.
224 */
225 X(nop)
226 {
227 }
228
229
230 /*
231 * b: Branch (to a different translated page)
232 *
233 * arg[0] = relative offset
234 */
235 X(b)
236 {
237 cpu->pc = (uint32_t)((cpu->pc & 0xfffff000) + (int32_t)ic->arg[0]);
238
239 /* Find the new physical page and update the translation pointers: */
240 quick_pc_to_pointers(cpu);
241 }
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 * arg[1] = pointer to the next instruction.
250 *
251 * NOTE: This instruction is manually inlined.
252 */
253 X(b_samepage) {
254 cpu->cd.arm.next_ic = (struct arm_instr_call *) ic->arg[0];
255 }
256 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
326
327 /*
328 * bx: Branch, potentially exchanging Thumb/ARM encoding
329 *
330 * arg[0] = ptr to rm
331 */
332 X(bx)
333 {
334 cpu->pc = reg(ic->arg[0]);
335 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 quick_pc_to_pointers(cpu);
343 }
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 cpu->pc = cpu->cd.arm.r[ARM_LR];
355 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 quick_pc_to_pointers(cpu);
365 }
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 uint32_t pc = ((uint32_t)cpu->pc & 0xfffff000) + (int32_t)ic->arg[1];
377 cpu->cd.arm.r[ARM_LR] = pc + 4;
378
379 /* Calculate new PC from this instruction + arg[0] */
380 cpu->pc = pc + (int32_t)ic->arg[0];
381
382 /* Find the new physical page and update the translation pointers: */
383 quick_pc_to_pointers(cpu);
384 }
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 uint32_t lr = ((uint32_t)cpu->pc & 0xfffff000) + (int32_t)ic->arg[2];
396 cpu->cd.arm.r[ARM_LR] = lr;
397 cpu->pc = reg(ic->arg[0]);
398 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 quick_pc_to_pointers(cpu);
406 }
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 uint32_t pc = ((uint32_t)cpu->pc & 0xfffff000) + (int32_t)ic->arg[1];
418 cpu->cd.arm.r[ARM_LR] = pc + 4;
419
420 /* Calculate new PC from this instruction + arg[0] */
421 cpu->pc = pc + (int32_t)ic->arg[0];
422
423 cpu_functioncall_trace(cpu, cpu->pc);
424
425 /* Find the new physical page and update the translation pointers: */
426 quick_pc_to_pointers(cpu);
427 }
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 cpu->cd.arm.r[ARM_LR] =
439 ((uint32_t)cpu->pc & 0xfffff000) + (int32_t)ic->arg[2];
440 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 uint32_t low_pc, lr = (cpu->pc & 0xfffff000) + ic->arg[2];
453
454 /* Link and branch: */
455 cpu->cd.arm.r[ARM_LR] = lr;
456 cpu->cd.arm.next_ic = (struct arm_instr_call *) ic->arg[0];
457
458 /* Synchronize the program counter: */
459 low_pc = ((size_t)cpu->cd.arm.next_ic - (size_t)
460 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
461 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1)
462 << ARM_INSTR_ALIGNMENT_SHIFT);
463 cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
464
465 /* ... and show trace: */
466 cpu_functioncall_trace(cpu, cpu->pc);
467 }
468 Y(bl_samepage_trace)
469
470
471 /*
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
500
501 /*
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 uint32_t result;
516 result = reg(ic->arg[1]) * reg(ic->arg[2]);
517 cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N);
518 if (result == 0)
519 cpu->cd.arm.flags |= ARM_F_Z;
520 if (result & 0x80000000)
521 cpu->cd.arm.flags |= ARM_F_N;
522 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 int rd, rs, rn, rm;
537 rd = (iw >> 16) & 15; rn = (iw >> 12) & 15,
538 rs = (iw >> 8) & 15; rm = iw & 15;
539 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 int rd, rs, rn, rm;
548 rd = (iw >> 16) & 15; rn = (iw >> 12) & 15,
549 rs = (iw >> 8) & 15; rm = iw & 15;
550 cpu->cd.arm.r[rd] = cpu->cd.arm.r[rm] * cpu->cd.arm.r[rs]
551 + cpu->cd.arm.r[rn];
552 cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N);
553 if (cpu->cd.arm.r[rd] == 0)
554 cpu->cd.arm.flags |= ARM_F_Z;
555 if (cpu->cd.arm.r[rd] & 0x80000000)
556 cpu->cd.arm.flags |= ARM_F_N;
557 }
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 uint32_t iw; uint64_t tmp; int u_bit, a_bit;
570 iw = ic->arg[0];
571 u_bit = iw & 0x00400000; a_bit = iw & 0x00200000;
572 tmp = cpu->cd.arm.r[iw & 15];
573 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 * 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 * 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 * 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 * ret_trace: "mov pc,lr" with trace enabled
653 * ret: "mov pc,lr" without trace enabled
654 *
655 * arg[0] = ignored
656 */
657 X(ret_trace)
658 {
659 uint32_t old_pc, mask_within_page;
660 old_pc = cpu->pc;
661 mask_within_page = ((ARM_IC_ENTRIES_PER_PAGE-1)
662 << ARM_INSTR_ALIGNMENT_SHIFT) |
663 ((1 << ARM_INSTR_ALIGNMENT_SHIFT) - 1);
664
665 /* Update the PC register: */
666 cpu->pc = cpu->cd.arm.r[ARM_LR];
667
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 quick_pc_to_pointers(cpu);
680 }
681 }
682 Y(ret_trace)
683 X(ret)
684 {
685 cpu->pc = cpu->cd.arm.r[ARM_LR];
686 quick_pc_to_pointers(cpu);
687 }
688 Y(ret)
689
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 cpu->cd.arm.cpsr &= 0x0fffffff;
710 cpu->cd.arm.cpsr |= (cpu->cd.arm.flags << 28);
711
712 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 cpu->cd.arm.flags = cpu->cd.arm.cpsr >> 28;
719
720 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 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 printf("msr_spsr: old pc = 0x%08"PRIx32"\n", old_pc);
765 }
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 cpu->cd.arm.cpsr &= 0x0fffffff;
786 cpu->cd.arm.cpsr |= (cpu->cd.arm.flags << 28);
787 reg(ic->arg[0]) = cpu->cd.arm.cpsr;
788 }
789 Y(mrs)
790
791
792 /*
793 * mrs: Move from saved status/flag register to a normal register.
794 *
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 uint32_t low_pc = ((size_t)ic - (size_t)
823 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
824 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
825 cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
826 arm_mcr_mrc(cpu, ic->arg[0]);
827 }
828 Y(mcr_mrc)
829 X(cdp) {
830 uint32_t low_pc = ((size_t)ic - (size_t)
831 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
832 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
833 cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
834 arm_cdp(cpu, ic->arg[0]);
835 }
836 Y(cdp)
837
838
839 /*
840 * openfirmware:
841 */
842 X(openfirmware)
843 {
844 /* TODO: sync pc? */
845 of_emul(cpu);
846 cpu->pc = cpu->cd.arm.r[ARM_LR];
847 if (cpu->machine->show_trace_tree)
848 cpu_functioncall_trace_return(cpu);
849 quick_pc_to_pointers(cpu);
850 }
851
852
853 /*
854 * 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 * 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 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1)
876 << ARM_INSTR_ALIGNMENT_SHIFT);
877 cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
878 old_pc = cpu->pc;
879
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 quick_pc_to_pointers(cpu);
890 }
891 }
892 Y(swi_useremul)
893
894
895 /*
896 * swi: Software interrupt.
897 */
898 X(swi)
899 {
900 /* Synchronize the program counter first: */
901 cpu->pc &= 0xfffff000;
902 cpu->pc += ic->arg[0];
903 arm_exception(cpu, ARM_EXCEPTION_SWI);
904 }
905 Y(swi)
906
907
908 /*
909 * 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 * 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
933 /* 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 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
937 cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
938
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
960 /* 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 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
964 cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
965
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 X(store_w1_word_u1_p0_imm);
986 X(store_w0_byte_u1_p0_imm);
987 X(store_w0_word_u1_p0_imm);
988 X(store_w0_word_u1_p1_imm);
989 X(load_w1_word_u1_p0_imm);
990 X(load_w0_word_u1_p0_imm);
991 X(load_w0_byte_u1_p1_imm);
992 X(load_w0_byte_u1_p1_reg);
993 X(load_w1_byte_u1_p1_imm);
994
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 extern uint32_t (*arm_r[8192])(struct cpu *, struct arm_instr_call *);
1005 extern void arm_r_r3_t0_c0(void);
1006
1007 extern void (*arm_dpi_instr[2 * 2 * 2 * 16 * 16])(struct cpu *,
1008 struct arm_instr_call *);
1009 extern void (*arm_dpi_instr_regshort[2 * 16 * 16])(struct cpu *,
1010 struct arm_instr_call *);
1011 X(cmps);
1012 X(teqs);
1013 X(tsts);
1014 X(sub);
1015 X(add);
1016 X(subs);
1017 X(eor_regshort);
1018 X(cmps_regshort);
1019
1020
1021 #include "cpu_arm_instr_misc.c"
1022
1023
1024 /*
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 int i, return_flag = 0;
1042 uint32_t new_values[16];
1043
1044 #ifdef GATHER_BDT_STATISTICS
1045 if (!s_bit)
1046 update_bdt_statistics(iw);
1047 #endif
1048
1049 /* 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 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
1053 cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
1054
1055 if (s_bit) {
1056 /* Load to USR registers: */
1057 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 }
1061 if (iw & 0x8000) {
1062 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 switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) {
1134 case ARM_MODE_USR32:
1135 case ARM_MODE_SYS32:
1136 cpu->cd.arm.r[i] = new_values[i];
1137 break;
1138 case ARM_MODE_FIQ32:
1139 if (i >= 8 && i <= 14)
1140 cpu->cd.arm.default_r8_r14[i-8] =
1141 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 case ARM_MODE_IRQ32:
1149 if (i >= 13 && i <= 14)
1150 cpu->cd.arm.default_r8_r14[i-8] =
1151 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 cpu->cd.arm.flags = cpu->cd.arm.cpsr >> 28;
1190
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 cpu->pc = cpu->cd.arm.r[ARM_PC] & 0xfffffffc;
1198 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 quick_pc_to_pointers(cpu);
1206 }
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 int i;
1229
1230 #ifdef GATHER_BDT_STATISTICS
1231 if (!s_bit)
1232 update_bdt_statistics(iw);
1233 #endif
1234
1235 /* 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 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
1239 cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
1240
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 switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) {
1251 case ARM_MODE_FIQ32:
1252 if (i >= 8 && i <= 14)
1253 value = cpu->cd.arm.default_r8_r14[i-8];
1254 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 value = cpu->cd.arm.default_r8_r14[i-8];
1261 break;
1262 case ARM_MODE_USR32:
1263 case ARM_MODE_SYS32:
1264 break;
1265 }
1266 }
1267
1268 /* NOTE/TODO: 8 vs 12 on some ARMs */
1269 if (i == ARM_PC)
1270 value = cpu->pc + 12;
1271
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 /* Various load/store multiple instructions: */
1328 extern uint32_t *multi_opcode[256];
1329 extern void (**multi_opcode_f[256])(struct cpu *, struct arm_instr_call *);
1330 X(multi_0x08b15018);
1331 X(multi_0x08ac000c__ge);
1332 X(multi_0x08a05018);
1333
1334
1335 /*****************************************************************************/
1336
1337
1338 /*
1339 * 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 if (((cpu->cd.arm.flags & ARM_F_N)?1:0) !=
1359 ((cpu->cd.arm.flags & ARM_F_V)?1:0)) {
1360 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 } 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
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 } while (((cpu->cd.arm.flags & ARM_F_N)?1:0) ==
1449 ((cpu->cd.arm.flags & ARM_F_V)?1:0));
1450
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 cpu->cd.arm.r[0] += r1;
1472 cpu->cd.arm.r[1] = 0;
1473 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 cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N);
1525 if (t == 0)
1526 cpu->cd.arm.flags |= ARM_F_Z;
1527
1528 cpu->n_translated_instrs += 2;
1529 cpu->cd.arm.next_ic = &ic[3];
1530 }
1531
1532
1533 /*
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 /*****************************************************************************/
2010
2011
2012 X(end_of_page)
2013 {
2014 /* Update the PC: (offset 0, but on the next page) */
2015 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
2018 /* Find the new physical page and update the translation pointers: */
2019 quick_pc_to_pointers(cpu);
2020
2021 /* end_of_page doesn't count as an executed instruction: */
2022 cpu->n_translated_instrs --;
2023 }
2024
2025
2026 /*****************************************************************************/
2027
2028
2029 /*
2030 * Combine: netbsd_memset():
2031 *
2032 * 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 */
2035 void COMBINE(netbsd_memset)(struct cpu *cpu,
2036 struct arm_instr_call *ic, int low_addr)
2037 {
2038 #ifdef HOST_LITTLE_ENDIAN
2039 int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2040 & (ARM_IC_ENTRIES_PER_PAGE-1);
2041
2042 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 #endif
2056 }
2057
2058
2059 /*
2060 * Combine: netbsd_memcpy():
2061 *
2062 * Check for the core of a NetBSD/arm memcpy; large memcpys use a
2063 * sequence of ldmia instructions.
2064 */
2065 void COMBINE(netbsd_memcpy)(struct cpu *cpu, struct arm_instr_call *ic,
2066 int low_addr)
2067 {
2068 #ifdef HOST_LITTLE_ENDIAN
2069 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 #endif
2086 }
2087
2088
2089 /*
2090 * Combine: netbsd_cacheclean():
2091 *
2092 * Check for the core of a NetBSD/arm cache clean. (There are two variants.)
2093 */
2094 void COMBINE(netbsd_cacheclean)(struct cpu *cpu,
2095 struct arm_instr_call *ic, int low_addr)
2096 {
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 * Combine: netbsd_cacheclean2():
2115 *
2116 * Check for the core of a NetBSD/arm cache clean. (Second variant.)
2117 */
2118 void COMBINE(netbsd_cacheclean2)(struct cpu *cpu,
2119 struct arm_instr_call *ic, int low_addr)
2120 {
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 * Combine: netbsd_scanc():
2140 */
2141 void COMBINE(netbsd_scanc)(struct cpu *cpu,
2142 struct arm_instr_call *ic, int low_addr)
2143 {
2144 int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2145 & (ARM_IC_ENTRIES_PER_PAGE-1);
2146
2147 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 }
2161 }
2162
2163
2164 /*
2165 * Combine: strlen():
2166 */
2167 void COMBINE(strlen)(struct cpu *cpu,
2168 struct arm_instr_call *ic, int low_addr)
2169 {
2170 int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2171 & (ARM_IC_ENTRIES_PER_PAGE-1);
2172
2173 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 }
2185 }
2186
2187
2188 /*
2189 * Combine: xchg():
2190 */
2191 void COMBINE(xchg)(struct cpu *cpu,
2192 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
2198 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 * Combine: netbsd_copyin():
2216 */
2217 void COMBINE(netbsd_copyin)(struct cpu *cpu,
2218 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 * Combine: netbsd_copyout():
2248 */
2249 void COMBINE(netbsd_copyout)(struct cpu *cpu,
2250 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 * Combine: cmps_b():
2280 */
2281 void COMBINE(cmps_b)(struct cpu *cpu,
2282 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 combined;
2297 }
2298 return;
2299 }
2300 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
2376
2377 /*****************************************************************************/
2378
2379
2380 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 /*
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 int p_bit, u_bit, w_bit, l_bit, regform, rm, c, t, any_pc_reg;
2467 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 addr = cpu->pc & ~((ARM_IC_ENTRIES_PER_PAGE-1) <<
2473 ARM_INSTR_ALIGNMENT_SHIFT);
2474 addr += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
2475 cpu->pc = addr;
2476 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 /* fatal("TRANSLATION HIT! 0x%08x\n", addr); */
2482 memcpy(ib, page + (addr & 0xfff), sizeof(ib));
2483 } else {
2484 /* fatal("TRANSLATION MISS! 0x%08x\n", addr); */
2485 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 return;
2490 }
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 u_bit = iword & 0x00800000;
2510 w_bit = iword & 0x00200000;
2511 s_bit = l_bit = iword & 0x00100000;
2512 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 if ((iword & 0x0f900ff0) == 0x01000050) {
2577 fatal("TODO: q{,d}{add,sub}\n");
2578 goto bad;
2579 }
2580 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 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 /* 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 }
2635 if ((iword & 0x0ff0f0b0) == 0x012000a0) {
2636 /* TODO: smulwY */
2637 goto bad;
2638 }
2639 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 if (rm == ARM_PC) {
2650 fatal("msr PC?\n");
2651 goto bad;
2652 }
2653 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 ic->arg[1] = (size_t)(void *)arm_r[iword & 0xf];
2715 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 /* "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 break;
2732 }
2733
2734 /* "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 ic->arg[1] = (size_t)(&cpu->cd.arm.r[rd]);
2744 break;
2745 }
2746
2747 /* "mov reg,#0": */
2748 if ((iword & 0x0fff0fff) == 0x03a00000 && rd != ARM_PC) {
2749 arm_switch_clear(ic, rd, condition_code);
2750 break;
2751 }
2752
2753 /* "mov reg,#1": */
2754 if ((iword & 0x0fff0fff) == 0x03a00001 && rd != ARM_PC) {
2755 arm_switch_mov1(ic, rd, condition_code);
2756 break;
2757 }
2758
2759 /* "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 /*
2767 * Generic Data Processing Instructions:
2768 */
2769 if ((main_opcode & 2) == 0)
2770 regform = 1;
2771 else
2772 regform = 0;
2773
2774 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 imm = iword & 0xff;
2788 while (r8-- > 0)
2789 imm = (imm >> 2) | ((imm & 3) << 30);
2790 ic->arg[1] = imm;
2791 }
2792
2793 /* mvn #imm ==> mov #~imm */
2794 if (secondary_opcode == 0xf && !regform) {
2795 secondary_opcode = 0xd;
2796 ic->arg[1] = ~ic->arg[1];
2797 }
2798
2799 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 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
2814 if (ic->f == instr(eor_regshort))
2815 cpu->cd.arm.combination_check = COMBINE(xchg);
2816 if (iword == 0xe113000c)
2817 cpu->cd.arm.combination_check = COMBINE(netbsd_scanc);
2818 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 ic->arg[1] = (size_t)(void *)arm_r[iword & 0xfff];
2842 if ((iword & 0x0e000010) == 0x06000010) {
2843 fatal("Not a Load/store TODO\n");
2844 goto bad;
2845 }
2846 /* 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 cpu->cd.arm.combination_check = COMBINE(netbsd_copyin);
2890 if (iword == 0xe4a17004)
2891 cpu->cd.arm.combination_check = COMBINE(netbsd_copyout);
2892 break;
2893
2894 case 0x8: /* Multiple load/store... (Block data transfer) */
2895 case 0x9: /* xxxx100P USWLnnnn llllllll llllllll */
2896 ic->arg[0] = (size_t)(&cpu->cd.arm.r[rn]);
2897 ic->arg[1] = (size_t)iword;
2898 /* Generic case: */
2899 if (l_bit)
2900 ic->f = cond_instr(bdt_load);
2901 else
2902 ic->f = cond_instr(bdt_store);
2903 #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 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 if (iword == 0xcaffffed)
2943 cpu->cd.arm.combination_check =
2944 COMBINE(netbsd_memset);
2945 if (iword == 0xaafffff9)
2946 cpu->cd.arm.combination_check =
2947 COMBINE(netbsd_memcpy);
2948 } 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 /* 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 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 /*
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 {
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 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 }
3001 }
3002
3003 if (main_opcode == 0xa && (condition_code <= 1
3004 || condition_code == 3 || condition_code == 8
3005 || condition_code == 12 || condition_code == 13))
3006 cpu->cd.arm.combination_check = COMBINE(cmps_b);
3007
3008 if (iword == 0x1afffffc)
3009 cpu->cd.arm.combination_check = COMBINE(strlen);
3010
3011 /* Hm. Does this really increase performance? */
3012 if (iword == 0x8afffffa)
3013 cpu->cd.arm.combination_check =
3014 COMBINE(netbsd_cacheclean2);
3015 break;
3016
3017 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 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 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 #if 0
3042 ic->f = cond_instr(und);
3043 ic->arg[0] = addr & 0xfff;
3044 #else
3045 fatal("LDC/STC: TODO\n");
3046 goto bad;
3047 #endif
3048 break;
3049
3050 case 0xe:
3051 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 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 if (iword == 0xee070f9a)
3067 cpu->cd.arm.combination_check =
3068 COMBINE(netbsd_cacheclean);
3069 break;
3070
3071 case 0xf:
3072 /* SWI: */
3073 /* Default handler: */
3074 ic->f = cond_instr(swi);
3075 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 /* 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