/[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 42 - (show annotations)
Mon Oct 8 16:22:32 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 82339 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1613 2007/06/15 20:11:26 debug Exp $
20070501	Continuing a little on m88k disassembly (control registers,
		more instructions).
		Adding a dummy mvme88k machine mode.
20070502	Re-adding MIPS load/store alignment exceptions.
20070503	Implementing more of the M88K disassembly code.
20070504	Adding disassembly of some more M88K load/store instructions.
		Implementing some relatively simple M88K instructions (br.n,
		xor[.u] imm, and[.u] imm).
20070505	Implementing M88K three-register and, or, xor, and jmp[.n],
		bsr[.n] including function call trace stuff.
		Applying a patch from Bruce M. Simpson which implements the
		SYSCON_BOARD_CPU_CLOCK_FREQ_ID object of the syscon call in
		the yamon PROM emulation.
20070506	Implementing M88K bb0[.n] and bb1[.n], and skeletons for
		ldcr and stcr (although no control regs are implemented yet).
20070509	Found and fixed the bug which caused Linux for QEMU_MIPS to
		stop working in 0.4.5.1: It was a faulty change to the MIPS
		'sc' and 'scd' instructions I made while going through gcc -W
		warnings on 20070428.
20070510	Updating the Linux/QEMU_MIPS section in guestoses.html to
		use mips-test-0.2.tar.gz instead of 0.1.
		A big thank you to Miod Vallat for sending me M88K manuals.
		Implementing more M88K instructions (addu, subu, div[u], mulu,
		ext[u], clr, set, cmp).
20070511	Fixing bugs in the M88K "and" and "and.u" instructions (found
		by comparing against the manual).
		Implementing more M88K instructions (mask[.u], mak, bcnd (auto-
		generated)) and some more control register details.
		Cleanup: Removing the experimental AVR emulation mode and
		corresponding devices; AVR emulation wasn't really meaningful.
		Implementing autogeneration of most M88K loads/stores. The
		rectangle drawing demo (with -O0) for M88K runs :-)
		Beginning on M88K exception handling.
		More M88K instructions: tb0, tb1, rte, sub, jsr[.n].
		Adding some skeleton MVME PROM ("BUG") emulation.
20070512	Fixing a bug in the M88K cmp instruction.
		Adding the M88K lda (scaled register) instruction.
		Fixing bugs in 64-bit (32-bit pairs) M88K loads/stores.
		Removing the unused tick_hz stuff from the machine struct.
		Implementing the M88K xmem instruction. OpenBSD/mvme88k gets
		far enough to display the Copyright banner :-)
		Implementing subu.co (guess), addu.co, addu.ci, ff0, and ff1.
		Adding a dev_mvme187, for MVME187-specific devices/registers.
		OpenBSD/mvme88k prints more boot messages. :)
20070515	Continuing on MVME187 emulation (adding more devices, beginning
		on the CMMUs, etc).
		Adding the M88K and.c, xor.c, and or.c instructions, and making
		sure that mul, div, etc cause exceptions if executed when SFD1
		is disabled.
20070517	Continuing on M88K and MVME187 emulation in general; moving
		the CMMU registers to the CPU struct, separating dev_pcc2 from
		dev_mvme187, and beginning on memory_m88k.c (BATC and PATC).
		Fixing a bug in 64-bit (32-bit pairs) M88K fast stores.
		Implementing the clock part of dev_mk48txx.
		Implementing the M88K fstcr and xcr instructions.
		Implementing m88k_cpu_tlbdump().
		Beginning on the implementation of a separate address space
		for M88K .usr loads/stores.
20070520	Removing the non-working (skeleton) Sandpoint, SonyNEWS, SHARK
		Dnard, and Zaurus machine modes.
		Experimenting with dyntrans to_be_translated read-ahead. It
		seems to give a very small performance increase for MIPS
		emulation, but a large performance degradation for SuperH. Hm.
20070522	Disabling correct SuperH ITLB emulation; it does not seem to be
		necessary in order to let SH4 guest OSes run, and it slows down
		userspace code.
		Implementing "samepage" branches for SuperH emulation, and some
		other minor speed hacks.
20070525	Continuing on M88K memory-related stuff: exceptions, memory
		transaction register contents, etc.
		Implementing the M88K subu.ci instruction.
		Removing the non-working (skeleton) Iyonix machine mode.
		OpenBSD/mvme88k reaches userland :-), starts executing
		/sbin/init's instructions, and issues a few syscalls, before
		crashing.
20070526	Fixing bugs in dev_mk48txx, so that OpenBSD/mvme88k detects
		the correct time-of-day.
		Implementing a generic IRQ controller for the test machines
		(dev_irqc), similar to a proposed patch from Petr Stepan.
		Experimenting some more with translation read-ahead.
		Adding an "expect" script for automated OpenBSD/landisk
		install regression/performance tests.
20070527	Adding a dummy mmEye (SH3) machine mode skeleton.
		FINALLY found the strange M88K bug I have been hunting: I had
		not emulated the SNIP value for exceptions occurring in
		branch delay slots correctly.
		Implementing correct exceptions for 64-bit M88K loads/stores.
		Address to symbol lookups are now disabled when M88K is
		running in usermode (because usermode addresses don't have
		anything to do with supervisor addresses).
20070531	Removing the mmEye machine mode skeleton.
20070604	Some minor code cleanup.
20070605	Moving src/useremul.c into a subdir (src/useremul/), and
		cleaning up some more legacy constructs.
		Adding -Wstrict-aliasing and -fstrict-aliasing detection to
		the configure script.
20070606	Adding a check for broken GCC on Solaris to the configure
		script. (GCC 3.4.3 on Solaris cannot handle static variables
		which are initialized to 0 or NULL. :-/)
		Removing the old (non-working) ARC emulation modes: NEC RD94,
		R94, R96, and R98, and the last traces of Olivetti M700 and
		Deskstation Tyne.
		Removing the non-working skeleton WDSC device (dev_wdsc).
20070607	Thinking about how to use the host's cc + ld at runtime to
		generate native code. (See experiments/native_cc_ld_test.i
		for an example.)
20070608	Adding a program counter sampling timer, which could be useful
		for native code generation experiments.
		The KN02_CSR_NRMMOD bit in the DECstation 5000/200 (KN02) CSR
		should always be set, to allow a 5000/200 PROM to boot.
20070609	Moving out breakpoint details from the machine struct into
		a helper struct, and removing the limit on max nr of
		breakpoints.
20070610	Moving out tick functions into a helper struct as well (which
		also gets rid of the max limit).
20070612	FINALLY figured out why Debian/DECstation stopped working when
		translation read-ahead was enabled: in src/memory_rw.c, the
		call to invalidate_code_translation was made also if the
		memory access was an instruction load (if the page was mapped
		as writable); it shouldn't be called in that case.
20070613	Implementing some more MIPS32/64 revision 2 instructions: di,
		ei, ext, dext, dextm, dextu, and ins.
20070614	Implementing an instruction combination for the NetBSD/arm
		idle loop (making the host not use any cpu if NetBSD/arm
		inside the emulator is not using any cpu).
		Increasing the nr of ARM VPH entries from 128 to 384.
20070615	Removing the ENABLE_arch stuff from the configure script, so
		that all included architectures are included in both release
		and development builds.
		Moving memory related helper functions from misc.c to memory.c.
		Adding preliminary instructions for netbooting NetBSD/pmppc to
		guestoses.html; it doesn't work yet, there are weird timeouts.
		Beginning a total rewrite of the userland emulation modes
		(removing all emulation modes, beginning from scratch with
		NetBSD/MIPS and FreeBSD/Alpha only).
20070616	After fixing a bug in the DEC21143 NIC (the TDSTAT_OWN bit was
		only cleared for the last segment when transmitting, not all
		segments), NetBSD/pmppc boots with root-on-nfs without the
		timeouts. Updating guestoses.html.
		Removing the skeleton PSP (Playstation Portable) mode.
		Moving X11-related stuff in the machine struct into a helper
		struct.
		Cleanup of out-of-memory checks, to use a new CHECK_ALLOCATION
		macro (which prints a meaningful error message).
		Adding a COMMENT to each machine and device (for automagic
		.index comment generation).
		Doing regression testing for the next release.

==============  RELEASE 0.4.6  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26