/[gxemul]/trunk/src/cpus/cpu_arm_instr.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 42 - (hide annotations)
Mon Oct 8 16:22:32 2007 UTC (16 years, 7 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 dpavlin 14 /*
2 dpavlin 34 * Copyright (C) 2005-2007 Anders Gavare. All rights reserved.
3 dpavlin 14 *
4     * Redistribution and use in source and binary forms, with or without
5     * modification, are permitted provided that the following conditions are met:
6     *
7     * 1. Redistributions of source code must retain the above copyright
8     * notice, this list of conditions and the following disclaimer.
9     * 2. Redistributions in binary form must reproduce the above copyright
10     * notice, this list of conditions and the following disclaimer in the
11     * documentation and/or other materials provided with the distribution.
12     * 3. The name of the author may not be used to endorse or promote products
13     * derived from this software without specific prior written permission.
14     *
15     * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16     * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18     * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19     * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20     * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21     * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24     * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25     * SUCH DAMAGE.
26     *
27     *
28 dpavlin 42 * $Id: cpu_arm_instr.c,v 1.74 2007/06/14 04:53:46 debug Exp $
29 dpavlin 14 *
30     * ARM instructions.
31     *
32     * Individual functions should keep track of cpu->n_translated_instrs.
33     * (If no instruction was executed, then it should be decreased. If, say, 4
34     * instructions were combined into one function and executed, then it should
35     * be increased by 3.)
36 dpavlin 32 *
37     * Note: cpu->pc is prefered over r[ARM_PC]. r[ARM_PC] is only used in a
38     * few places, and should always be kept in synch with the real
39     * program counter.
40 dpavlin 14 */
41    
42    
43 dpavlin 18 /* #define GATHER_BDT_STATISTICS */
44    
45    
46     #ifdef GATHER_BDT_STATISTICS
47 dpavlin 14 /*
48 dpavlin 18 * update_bdt_statistics():
49     *
50     * Gathers statistics about load/store multiple instructions.
51     *
52     * NOTE/TODO: Perhaps it would be more memory efficient to swap the high
53     * and low parts of the instruction word, so that the lllllll bits become
54     * the high bits; this would cause fewer host pages to be used. Anyway, the
55     * current implementation works on hosts with lots of RAM.
56     *
57     * The resulting file, bdt_statistics.txt, should then be processed like
58     * this to give a new cpu_arm_multi.txt:
59     *
60     * uniq -c bdt_statistics.txt|sort -nr|head -256|cut -f 2 > cpu_arm_multi.txt
61     */
62     static void update_bdt_statistics(uint32_t iw)
63     {
64     static FILE *f = NULL;
65     static long long *counts;
66     static char *counts_used;
67     static long long n = 0;
68    
69     if (f == NULL) {
70     size_t s = (1 << 24) * sizeof(long long);
71     f = fopen("bdt_statistics.txt", "w");
72     if (f == NULL) {
73     fprintf(stderr, "update_bdt_statistics(): :-(\n");
74     exit(1);
75     }
76     counts = zeroed_alloc(s);
77     counts_used = zeroed_alloc(65536);
78     }
79    
80     /* Drop the s-bit: xxxx100P USWLnnnn llllllll llllllll */
81     iw = ((iw & 0x01800000) >> 1) | (iw & 0x003fffff);
82    
83     counts_used[iw & 0xffff] = 1;
84     counts[iw] ++;
85    
86     n ++;
87     if ((n % 500000) == 0) {
88     int i;
89     long long j;
90     fatal("[ update_bdt_statistics(): n = %lli ]\n", (long long) n);
91     fseek(f, 0, SEEK_SET);
92     for (i=0; i<0x1000000; i++)
93     if (counts_used[i & 0xffff] && counts[i] != 0) {
94     /* Recreate the opcode: */
95     uint32_t opcode = ((i & 0x00c00000) << 1)
96     | (i & 0x003fffff) | 0x08000000;
97     for (j=0; j<counts[i]; j++)
98     fprintf(f, "0x%08x\n", opcode);
99     }
100     fflush(f);
101     }
102     }
103     #endif
104    
105    
106     /*****************************************************************************/
107    
108    
109     /*
110 dpavlin 14 * Helper definitions:
111     *
112     * Each instruction is defined like this:
113     *
114     * X(foo)
115     * {
116     * code for foo;
117     * }
118     * Y(foo)
119     *
120     * The Y macro defines 14 copies of the instruction, one for each possible
121     * condition code. (The NV condition code is not included, and the AL code
122     * uses the main foo function.) Y also defines an array with pointers to
123     * all of these functions.
124 dpavlin 18 *
125     * If the compiler is good enough (i.e. allows long enough code sequences
126     * to be inlined), then the Y functions will be compiled as full (inlined)
127     * functions, otherwise they will simply call the X function.
128 dpavlin 14 */
129    
130 dpavlin 20 uint8_t condition_hi[16] = { 0,0,1,1, 0,0,0,0, 0,0,1,1, 0,0,0,0 };
131     uint8_t condition_ge[16] = { 1,0,1,0, 1,0,1,0, 0,1,0,1, 0,1,0,1 };
132     uint8_t condition_gt[16] = { 1,0,1,0, 0,0,0,0, 0,1,0,1, 0,0,0,0 };
133    
134 dpavlin 14 #define Y(n) void arm_instr_ ## n ## __eq(struct cpu *cpu, \
135     struct arm_instr_call *ic) \
136 dpavlin 20 { if (cpu->cd.arm.flags & ARM_F_Z) \
137 dpavlin 14 arm_instr_ ## n (cpu, ic); } \
138     void arm_instr_ ## n ## __ne(struct cpu *cpu, \
139     struct arm_instr_call *ic) \
140 dpavlin 20 { if (!(cpu->cd.arm.flags & ARM_F_Z)) \
141 dpavlin 14 arm_instr_ ## n (cpu, ic); } \
142     void arm_instr_ ## n ## __cs(struct cpu *cpu, \
143     struct arm_instr_call *ic) \
144 dpavlin 20 { if (cpu->cd.arm.flags & ARM_F_C) \
145 dpavlin 14 arm_instr_ ## n (cpu, ic); } \
146     void arm_instr_ ## n ## __cc(struct cpu *cpu, \
147     struct arm_instr_call *ic) \
148 dpavlin 20 { if (!(cpu->cd.arm.flags & ARM_F_C)) \
149 dpavlin 14 arm_instr_ ## n (cpu, ic); } \
150     void arm_instr_ ## n ## __mi(struct cpu *cpu, \
151     struct arm_instr_call *ic) \
152 dpavlin 20 { if (cpu->cd.arm.flags & ARM_F_N) \
153 dpavlin 14 arm_instr_ ## n (cpu, ic); } \
154     void arm_instr_ ## n ## __pl(struct cpu *cpu, \
155     struct arm_instr_call *ic) \
156 dpavlin 20 { if (!(cpu->cd.arm.flags & ARM_F_N)) \
157 dpavlin 14 arm_instr_ ## n (cpu, ic); } \
158     void arm_instr_ ## n ## __vs(struct cpu *cpu, \
159     struct arm_instr_call *ic) \
160 dpavlin 20 { if (cpu->cd.arm.flags & ARM_F_V) \
161 dpavlin 14 arm_instr_ ## n (cpu, ic); } \
162     void arm_instr_ ## n ## __vc(struct cpu *cpu, \
163     struct arm_instr_call *ic) \
164 dpavlin 20 { if (!(cpu->cd.arm.flags & ARM_F_V)) \
165 dpavlin 14 arm_instr_ ## n (cpu, ic); } \
166     void arm_instr_ ## n ## __hi(struct cpu *cpu, \
167     struct arm_instr_call *ic) \
168 dpavlin 20 { if (condition_hi[cpu->cd.arm.flags]) \
169 dpavlin 14 arm_instr_ ## n (cpu, ic); } \
170     void arm_instr_ ## n ## __ls(struct cpu *cpu, \
171     struct arm_instr_call *ic) \
172 dpavlin 20 { if (!condition_hi[cpu->cd.arm.flags]) \
173 dpavlin 14 arm_instr_ ## n (cpu, ic); } \
174     void arm_instr_ ## n ## __ge(struct cpu *cpu, \
175     struct arm_instr_call *ic) \
176 dpavlin 20 { if (condition_ge[cpu->cd.arm.flags]) \
177 dpavlin 14 arm_instr_ ## n (cpu, ic); } \
178     void arm_instr_ ## n ## __lt(struct cpu *cpu, \
179     struct arm_instr_call *ic) \
180 dpavlin 20 { if (!condition_ge[cpu->cd.arm.flags]) \
181 dpavlin 14 arm_instr_ ## n (cpu, ic); } \
182     void arm_instr_ ## n ## __gt(struct cpu *cpu, \
183     struct arm_instr_call *ic) \
184 dpavlin 20 { if (condition_gt[cpu->cd.arm.flags]) \
185 dpavlin 14 arm_instr_ ## n (cpu, ic); } \
186     void arm_instr_ ## n ## __le(struct cpu *cpu, \
187     struct arm_instr_call *ic) \
188 dpavlin 20 { if (!condition_gt[cpu->cd.arm.flags]) \
189 dpavlin 14 arm_instr_ ## n (cpu, ic); } \
190     void (*arm_cond_instr_ ## n [16])(struct cpu *, \
191     struct arm_instr_call *) = { \
192     arm_instr_ ## n ## __eq, arm_instr_ ## n ## __ne, \
193     arm_instr_ ## n ## __cs, arm_instr_ ## n ## __cc, \
194     arm_instr_ ## n ## __mi, arm_instr_ ## n ## __pl, \
195     arm_instr_ ## n ## __vs, arm_instr_ ## n ## __vc, \
196     arm_instr_ ## n ## __hi, arm_instr_ ## n ## __ls, \
197     arm_instr_ ## n ## __ge, arm_instr_ ## n ## __lt, \
198     arm_instr_ ## n ## __gt, arm_instr_ ## n ## __le, \
199     arm_instr_ ## n , arm_instr_nop };
200    
201     #define cond_instr(n) ( arm_cond_instr_ ## n [condition_code] )
202    
203    
204     /*****************************************************************************/
205    
206    
207     /*
208     * invalid: Invalid instructions end up here.
209     */
210     X(invalid) {
211     uint32_t low_pc;
212     low_pc = ((size_t)ic - (size_t)
213     cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
214 dpavlin 20 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1)
215 dpavlin 14 << ARM_INSTR_ALIGNMENT_SHIFT);
216 dpavlin 20 cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
217 dpavlin 14
218 dpavlin 24 fatal("FATAL ERROR: An internal error occured in the ARM"
219     " dyntrans code. Please contact the author with detailed"
220     " repro steps on how to trigger this bug. pc = 0x%08"PRIx32"\n",
221     (uint32_t)cpu->pc);
222 dpavlin 30
223     cpu->cd.arm.next_ic = &nothing_call;
224 dpavlin 24 }
225 dpavlin 14
226 dpavlin 24
227     /*
228     * nop: Do nothing.
229     */
230     X(nop)
231     {
232 dpavlin 14 }
233    
234    
235     /*
236     * b: Branch (to a different translated page)
237     *
238 dpavlin 40 * arg[0] = relative offset from start of page
239 dpavlin 14 */
240     X(b)
241     {
242 dpavlin 20 cpu->pc = (uint32_t)((cpu->pc & 0xfffff000) + (int32_t)ic->arg[0]);
243 dpavlin 14
244     /* Find the new physical page and update the translation pointers: */
245 dpavlin 18 quick_pc_to_pointers(cpu);
246 dpavlin 14 }
247     Y(b)
248    
249    
250     /*
251     * b_samepage: Branch (to within the same translated page)
252     *
253     * arg[0] = pointer to new arm_instr_call
254 dpavlin 20 * arg[1] = pointer to the next instruction.
255     *
256     * NOTE: This instruction is manually inlined.
257 dpavlin 14 */
258 dpavlin 20 X(b_samepage) {
259 dpavlin 14 cpu->cd.arm.next_ic = (struct arm_instr_call *) ic->arg[0];
260     }
261 dpavlin 20 X(b_samepage__eq) {
262     cpu->cd.arm.next_ic = (struct arm_instr_call *)
263     ic->arg[cpu->cd.arm.flags & ARM_F_Z? 0 : 1];
264     }
265     X(b_samepage__ne) {
266     cpu->cd.arm.next_ic = (struct arm_instr_call *)
267     ic->arg[cpu->cd.arm.flags & ARM_F_Z? 1 : 0];
268     }
269     X(b_samepage__cs) {
270     cpu->cd.arm.next_ic = (struct arm_instr_call *)
271     ic->arg[cpu->cd.arm.flags & ARM_F_C? 0 : 1];
272     }
273     X(b_samepage__cc) {
274     cpu->cd.arm.next_ic = (struct arm_instr_call *)
275     ic->arg[cpu->cd.arm.flags & ARM_F_C? 1 : 0];
276     }
277     X(b_samepage__mi) {
278     cpu->cd.arm.next_ic = (struct arm_instr_call *)
279     ic->arg[cpu->cd.arm.flags & ARM_F_N? 0 : 1];
280     }
281     X(b_samepage__pl) {
282     cpu->cd.arm.next_ic = (struct arm_instr_call *)
283     ic->arg[cpu->cd.arm.flags & ARM_F_N? 1 : 0];
284     }
285     X(b_samepage__vs) {
286     cpu->cd.arm.next_ic = (struct arm_instr_call *)
287     ic->arg[cpu->cd.arm.flags & ARM_F_V? 0 : 1];
288     }
289     X(b_samepage__vc) {
290     cpu->cd.arm.next_ic = (struct arm_instr_call *)
291     ic->arg[cpu->cd.arm.flags & ARM_F_V? 1 : 0];
292     }
293     X(b_samepage__hi) {
294     cpu->cd.arm.next_ic = (condition_hi[cpu->cd.arm.flags])?
295     (struct arm_instr_call *) ic->arg[0] :
296     (struct arm_instr_call *) ic->arg[1];
297     }
298     X(b_samepage__ls) {
299     cpu->cd.arm.next_ic = (struct arm_instr_call *)
300     ic->arg[condition_hi[cpu->cd.arm.flags]];
301     }
302     X(b_samepage__ge) {
303     cpu->cd.arm.next_ic = (condition_ge[cpu->cd.arm.flags])?
304     (struct arm_instr_call *) ic->arg[0] :
305     (struct arm_instr_call *) ic->arg[1];
306     }
307     X(b_samepage__lt) {
308     cpu->cd.arm.next_ic = (struct arm_instr_call *)
309     ic->arg[condition_ge[cpu->cd.arm.flags]];
310     }
311     X(b_samepage__gt) {
312     cpu->cd.arm.next_ic = (condition_gt[cpu->cd.arm.flags])?
313     (struct arm_instr_call *) ic->arg[0] :
314     (struct arm_instr_call *) ic->arg[1];
315     }
316     X(b_samepage__le) {
317     cpu->cd.arm.next_ic = (struct arm_instr_call *)
318     ic->arg[condition_gt[cpu->cd.arm.flags]];
319     }
320     void (*arm_cond_instr_b_samepage[16])(struct cpu *,
321     struct arm_instr_call *) = {
322     arm_instr_b_samepage__eq, arm_instr_b_samepage__ne,
323     arm_instr_b_samepage__cs, arm_instr_b_samepage__cc,
324     arm_instr_b_samepage__mi, arm_instr_b_samepage__pl,
325     arm_instr_b_samepage__vs, arm_instr_b_samepage__vc,
326     arm_instr_b_samepage__hi, arm_instr_b_samepage__ls,
327     arm_instr_b_samepage__ge, arm_instr_b_samepage__lt,
328     arm_instr_b_samepage__gt, arm_instr_b_samepage__le,
329     arm_instr_b_samepage, arm_instr_nop };
330 dpavlin 14
331    
332     /*
333     * bx: Branch, potentially exchanging Thumb/ARM encoding
334     *
335     * arg[0] = ptr to rm
336     */
337     X(bx)
338     {
339 dpavlin 20 cpu->pc = reg(ic->arg[0]);
340 dpavlin 14 if (cpu->pc & 1) {
341     fatal("thumb: TODO\n");
342     exit(1);
343     }
344     cpu->pc &= ~3;
345    
346     /* Find the new physical page and update the translation pointers: */
347 dpavlin 18 quick_pc_to_pointers(cpu);
348 dpavlin 14 }
349     Y(bx)
350    
351    
352     /*
353     * bx_trace: As bx, but with trace enabled, arg[0] = the link register.
354     *
355     * arg[0] = ignored
356     */
357     X(bx_trace)
358     {
359 dpavlin 20 cpu->pc = cpu->cd.arm.r[ARM_LR];
360 dpavlin 14 if (cpu->pc & 1) {
361     fatal("thumb: TODO\n");
362     exit(1);
363     }
364     cpu->pc &= ~3;
365    
366     cpu_functioncall_trace_return(cpu);
367    
368     /* Find the new physical page and update the translation pointers: */
369 dpavlin 18 quick_pc_to_pointers(cpu);
370 dpavlin 14 }
371     Y(bx_trace)
372    
373    
374     /*
375     * bl: Branch and Link (to a different translated page)
376     *
377     * arg[0] = relative address
378     */
379     X(bl)
380     {
381 dpavlin 20 uint32_t pc = ((uint32_t)cpu->pc & 0xfffff000) + (int32_t)ic->arg[1];
382     cpu->cd.arm.r[ARM_LR] = pc + 4;
383 dpavlin 14
384     /* Calculate new PC from this instruction + arg[0] */
385 dpavlin 20 cpu->pc = pc + (int32_t)ic->arg[0];
386 dpavlin 14
387     /* Find the new physical page and update the translation pointers: */
388 dpavlin 18 quick_pc_to_pointers(cpu);
389 dpavlin 14 }
390     Y(bl)
391    
392    
393     /*
394     * blx: Branch and Link, potentially exchanging Thumb/ARM encoding
395     *
396     * arg[0] = ptr to rm
397     */
398     X(blx)
399     {
400 dpavlin 20 uint32_t lr = ((uint32_t)cpu->pc & 0xfffff000) + (int32_t)ic->arg[2];
401 dpavlin 14 cpu->cd.arm.r[ARM_LR] = lr;
402 dpavlin 20 cpu->pc = reg(ic->arg[0]);
403 dpavlin 14 if (cpu->pc & 1) {
404     fatal("thumb: TODO\n");
405     exit(1);
406     }
407     cpu->pc &= ~3;
408    
409     /* Find the new physical page and update the translation pointers: */
410 dpavlin 18 quick_pc_to_pointers(cpu);
411 dpavlin 14 }
412     Y(blx)
413    
414    
415     /*
416     * bl_trace: Branch and Link (to a different translated page), with trace
417     *
418     * Same as for bl.
419     */
420     X(bl_trace)
421     {
422 dpavlin 20 uint32_t pc = ((uint32_t)cpu->pc & 0xfffff000) + (int32_t)ic->arg[1];
423     cpu->cd.arm.r[ARM_LR] = pc + 4;
424 dpavlin 14
425     /* Calculate new PC from this instruction + arg[0] */
426 dpavlin 20 cpu->pc = pc + (int32_t)ic->arg[0];
427 dpavlin 14
428     cpu_functioncall_trace(cpu, cpu->pc);
429    
430     /* Find the new physical page and update the translation pointers: */
431 dpavlin 18 quick_pc_to_pointers(cpu);
432 dpavlin 14 }
433     Y(bl_trace)
434    
435    
436     /*
437     * bl_samepage: A branch + link within the same page
438     *
439     * arg[0] = pointer to new arm_instr_call
440     */
441     X(bl_samepage)
442     {
443 dpavlin 20 cpu->cd.arm.r[ARM_LR] =
444     ((uint32_t)cpu->pc & 0xfffff000) + (int32_t)ic->arg[2];
445 dpavlin 14 cpu->cd.arm.next_ic = (struct arm_instr_call *) ic->arg[0];
446     }
447     Y(bl_samepage)
448    
449    
450     /*
451     * bl_samepage_trace: Branch and Link (to the same page), with trace
452     *
453     * Same as for bl_samepage.
454     */
455     X(bl_samepage_trace)
456     {
457 dpavlin 20 uint32_t low_pc, lr = (cpu->pc & 0xfffff000) + ic->arg[2];
458 dpavlin 14
459 dpavlin 20 /* Link and branch: */
460 dpavlin 14 cpu->cd.arm.r[ARM_LR] = lr;
461     cpu->cd.arm.next_ic = (struct arm_instr_call *) ic->arg[0];
462    
463 dpavlin 20 /* Synchronize the program counter: */
464 dpavlin 14 low_pc = ((size_t)cpu->cd.arm.next_ic - (size_t)
465     cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
466 dpavlin 20 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1)
467 dpavlin 14 << ARM_INSTR_ALIGNMENT_SHIFT);
468 dpavlin 20 cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
469    
470     /* ... and show trace: */
471     cpu_functioncall_trace(cpu, cpu->pc);
472 dpavlin 14 }
473     Y(bl_samepage_trace)
474    
475    
476 dpavlin 20 /*
477     * clz: Count leading zeroes.
478     *
479     * arg[0] = ptr to rm
480     * arg[1] = ptr to rd
481     */
482     X(clz)
483     {
484     uint32_t rm = reg(ic->arg[0]);
485     int i = 32, n = 0, j;
486     while (i>0) {
487     if (rm & 0xff000000) {
488     for (j=0; j<8; j++) {
489     if (rm & 0x80000000)
490     break;
491     n ++;
492     rm <<= 1;
493     }
494     break;
495     } else {
496     rm <<= 8;
497     i -= 8;
498     n += 8;
499     }
500     }
501     reg(ic->arg[1]) = n;
502     }
503     Y(clz)
504 dpavlin 18
505    
506 dpavlin 14 /*
507     * mul: Multiplication
508     *
509     * arg[0] = ptr to rd
510     * arg[1] = ptr to rm
511     * arg[2] = ptr to rs
512     */
513     X(mul)
514     {
515     reg(ic->arg[0]) = reg(ic->arg[1]) * reg(ic->arg[2]);
516     }
517     Y(mul)
518     X(muls)
519     {
520 dpavlin 18 uint32_t result;
521     result = reg(ic->arg[1]) * reg(ic->arg[2]);
522 dpavlin 20 cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N);
523 dpavlin 14 if (result == 0)
524 dpavlin 20 cpu->cd.arm.flags |= ARM_F_Z;
525 dpavlin 14 if (result & 0x80000000)
526 dpavlin 20 cpu->cd.arm.flags |= ARM_F_N;
527 dpavlin 14 reg(ic->arg[0]) = result;
528     }
529     Y(muls)
530    
531    
532     /*
533     * mla: Multiplication with addition
534     *
535     * arg[0] = copy of instruction word
536     */
537     X(mla)
538     {
539     /* xxxx0000 00ASdddd nnnnssss 1001mmmm (Rd,Rm,Rs[,Rn]) */
540     uint32_t iw = ic->arg[0];
541 dpavlin 18 int rd, rs, rn, rm;
542     rd = (iw >> 16) & 15; rn = (iw >> 12) & 15,
543     rs = (iw >> 8) & 15; rm = iw & 15;
544 dpavlin 14 cpu->cd.arm.r[rd] = cpu->cd.arm.r[rm] * cpu->cd.arm.r[rs]
545     + cpu->cd.arm.r[rn];
546     }
547     Y(mla)
548     X(mlas)
549     {
550     /* xxxx0000 00ASdddd nnnnssss 1001mmmm (Rd,Rm,Rs[,Rn]) */
551     uint32_t iw = ic->arg[0];
552 dpavlin 18 int rd, rs, rn, rm;
553     rd = (iw >> 16) & 15; rn = (iw >> 12) & 15,
554     rs = (iw >> 8) & 15; rm = iw & 15;
555 dpavlin 14 cpu->cd.arm.r[rd] = cpu->cd.arm.r[rm] * cpu->cd.arm.r[rs]
556     + cpu->cd.arm.r[rn];
557 dpavlin 20 cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N);
558 dpavlin 14 if (cpu->cd.arm.r[rd] == 0)
559 dpavlin 20 cpu->cd.arm.flags |= ARM_F_Z;
560 dpavlin 14 if (cpu->cd.arm.r[rd] & 0x80000000)
561 dpavlin 20 cpu->cd.arm.flags |= ARM_F_N;
562 dpavlin 14 }
563     Y(mlas)
564    
565    
566     /*
567     * mull: Long multiplication
568     *
569     * arg[0] = copy of instruction word
570     */
571     X(mull)
572     {
573     /* xxxx0000 1UAShhhh llllssss 1001mmmm */
574 dpavlin 18 uint32_t iw; uint64_t tmp; int u_bit, a_bit;
575     iw = ic->arg[0];
576 dpavlin 20 u_bit = iw & 0x00400000; a_bit = iw & 0x00200000;
577 dpavlin 18 tmp = cpu->cd.arm.r[iw & 15];
578 dpavlin 14 if (u_bit)
579     tmp = (int64_t)(int32_t)tmp
580     * (int64_t)(int32_t)cpu->cd.arm.r[(iw >> 8) & 15];
581     else
582     tmp *= (uint64_t)cpu->cd.arm.r[(iw >> 8) & 15];
583     if (a_bit) {
584     uint64_t x = ((uint64_t)cpu->cd.arm.r[(iw >> 16) & 15] << 32)
585     | cpu->cd.arm.r[(iw >> 12) & 15];
586     x += tmp;
587     cpu->cd.arm.r[(iw >> 16) & 15] = (x >> 32);
588     cpu->cd.arm.r[(iw >> 12) & 15] = x;
589     } else {
590     cpu->cd.arm.r[(iw >> 16) & 15] = (tmp >> 32);
591     cpu->cd.arm.r[(iw >> 12) & 15] = tmp;
592     }
593     }
594     Y(mull)
595    
596    
597     /*
598 dpavlin 22 * smulXY: 16-bit * 16-bit multiplication (32-bit result)
599     *
600     * arg[0] = ptr to rm
601     * arg[1] = ptr to rs
602     * arg[2] = ptr to rd
603     */
604     X(smulbb)
605     {
606     reg(ic->arg[2]) = (int32_t)(int16_t)reg(ic->arg[0]) *
607     (int32_t)(int16_t)reg(ic->arg[1]);
608     }
609     Y(smulbb)
610     X(smultb)
611     {
612     reg(ic->arg[2]) = (int32_t)(int16_t)(reg(ic->arg[0]) >> 16) *
613     (int32_t)(int16_t)reg(ic->arg[1]);
614     }
615     Y(smultb)
616     X(smulbt)
617     {
618     reg(ic->arg[2]) = (int32_t)(int16_t)reg(ic->arg[0]) *
619     (int32_t)(int16_t)(reg(ic->arg[1]) >> 16);
620     }
621     Y(smulbt)
622     X(smultt)
623     {
624     reg(ic->arg[2]) = (int32_t)(int16_t)(reg(ic->arg[0]) >> 16) *
625     (int32_t)(int16_t)(reg(ic->arg[1]) >> 16);
626     }
627     Y(smultt)
628    
629    
630     /*
631 dpavlin 14 * mov_reg_reg: Move a register to another.
632     *
633     * arg[0] = ptr to source register
634     * arg[1] = ptr to destination register
635     */
636     X(mov_reg_reg)
637     {
638     reg(ic->arg[1]) = reg(ic->arg[0]);
639     }
640     Y(mov_reg_reg)
641    
642    
643     /*
644 dpavlin 20 * mov_reg_pc: Move the PC register to a normal register.
645     *
646     * arg[0] = offset compared to start of current page + 8
647     * arg[1] = ptr to destination register
648     */
649     X(mov_reg_pc)
650     {
651     reg(ic->arg[1]) = ((uint32_t)cpu->pc&0xfffff000) + (int32_t)ic->arg[0];
652     }
653     Y(mov_reg_pc)
654    
655    
656     /*
657 dpavlin 14 * ret_trace: "mov pc,lr" with trace enabled
658 dpavlin 18 * ret: "mov pc,lr" without trace enabled
659 dpavlin 14 *
660     * arg[0] = ignored
661     */
662     X(ret_trace)
663     {
664 dpavlin 18 uint32_t old_pc, mask_within_page;
665 dpavlin 20 old_pc = cpu->pc;
666 dpavlin 18 mask_within_page = ((ARM_IC_ENTRIES_PER_PAGE-1)
667 dpavlin 14 << ARM_INSTR_ALIGNMENT_SHIFT) |
668     ((1 << ARM_INSTR_ALIGNMENT_SHIFT) - 1);
669    
670     /* Update the PC register: */
671 dpavlin 20 cpu->pc = cpu->cd.arm.r[ARM_LR];
672 dpavlin 14
673     cpu_functioncall_trace_return(cpu);
674    
675     /*
676     * Is this a return to code within the same page? Then there is no
677     * need to update all pointers, just next_ic.
678     */
679     if ((old_pc & ~mask_within_page) == (cpu->pc & ~mask_within_page)) {
680     cpu->cd.arm.next_ic = cpu->cd.arm.cur_ic_page +
681     ((cpu->pc & mask_within_page) >> ARM_INSTR_ALIGNMENT_SHIFT);
682     } else {
683     /* Find the new physical page and update pointers: */
684 dpavlin 18 quick_pc_to_pointers(cpu);
685 dpavlin 14 }
686     }
687     Y(ret_trace)
688 dpavlin 18 X(ret)
689     {
690 dpavlin 20 cpu->pc = cpu->cd.arm.r[ARM_LR];
691 dpavlin 18 quick_pc_to_pointers(cpu);
692     }
693     Y(ret)
694 dpavlin 14
695    
696     /*
697     * msr: Move to status register from a normal register or immediate value.
698     *
699     * arg[0] = immediate value
700     * arg[1] = mask
701     * arg[2] = pointer to rm
702     *
703     * msr_imm and msr_imm_spsr use arg[1] and arg[0].
704     * msr and msr_spsr use arg[1] and arg[2].
705     */
706     X(msr_imm)
707     {
708     uint32_t mask = ic->arg[1];
709     int switch_register_banks = (mask & ARM_FLAG_MODE) &&
710     ((cpu->cd.arm.cpsr & ARM_FLAG_MODE) !=
711     (ic->arg[0] & ARM_FLAG_MODE));
712     uint32_t new_value = ic->arg[0];
713    
714 dpavlin 20 cpu->cd.arm.cpsr &= 0x0fffffff;
715     cpu->cd.arm.cpsr |= (cpu->cd.arm.flags << 28);
716    
717 dpavlin 14 if (switch_register_banks)
718     arm_save_register_bank(cpu);
719    
720     cpu->cd.arm.cpsr &= ~mask;
721     cpu->cd.arm.cpsr |= (new_value & mask);
722    
723 dpavlin 20 cpu->cd.arm.flags = cpu->cd.arm.cpsr >> 28;
724    
725 dpavlin 14 if (switch_register_banks)
726     arm_load_register_bank(cpu);
727     }
728     Y(msr_imm)
729     X(msr)
730     {
731     ic->arg[0] = reg(ic->arg[2]);
732     instr(msr_imm)(cpu, ic);
733     }
734     Y(msr)
735     X(msr_imm_spsr)
736     {
737     uint32_t mask = ic->arg[1];
738     uint32_t new_value = ic->arg[0];
739     switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) {
740     case ARM_MODE_FIQ32:
741     cpu->cd.arm.spsr_fiq &= ~mask;
742     cpu->cd.arm.spsr_fiq |= (new_value & mask);
743     break;
744     case ARM_MODE_ABT32:
745     cpu->cd.arm.spsr_abt &= ~mask;
746     cpu->cd.arm.spsr_abt |= (new_value & mask);
747     break;
748     case ARM_MODE_UND32:
749     cpu->cd.arm.spsr_und &= ~mask;
750     cpu->cd.arm.spsr_und |= (new_value & mask);
751     break;
752     case ARM_MODE_IRQ32:
753     cpu->cd.arm.spsr_irq &= ~mask;
754     cpu->cd.arm.spsr_irq |= (new_value & mask);
755     break;
756     case ARM_MODE_SVC32:
757     cpu->cd.arm.spsr_svc &= ~mask;
758     cpu->cd.arm.spsr_svc |= (new_value & mask);
759     break;
760     default:fatal("msr_spsr: unimplemented mode %i\n",
761     cpu->cd.arm.cpsr & ARM_FLAG_MODE);
762     {
763     /* Synchronize the program counter: */
764     uint32_t old_pc, low_pc = ((size_t)ic - (size_t)
765     cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
766 dpavlin 20 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
767     cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
768     old_pc = cpu->pc;
769 dpavlin 24 printf("msr_spsr: old pc = 0x%08"PRIx32"\n", old_pc);
770 dpavlin 14 }
771     exit(1);
772     }
773     }
774     Y(msr_imm_spsr)
775     X(msr_spsr)
776     {
777     ic->arg[0] = reg(ic->arg[2]);
778     instr(msr_imm_spsr)(cpu, ic);
779     }
780     Y(msr_spsr)
781    
782    
783     /*
784     * mrs: Move from status/flag register to a normal register.
785     *
786     * arg[0] = pointer to rd
787     */
788     X(mrs)
789     {
790 dpavlin 20 cpu->cd.arm.cpsr &= 0x0fffffff;
791     cpu->cd.arm.cpsr |= (cpu->cd.arm.flags << 28);
792 dpavlin 14 reg(ic->arg[0]) = cpu->cd.arm.cpsr;
793     }
794     Y(mrs)
795    
796    
797     /*
798 dpavlin 20 * mrs: Move from saved status/flag register to a normal register.
799 dpavlin 14 *
800     * arg[0] = pointer to rd
801     */
802     X(mrs_spsr)
803     {
804     switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) {
805     case ARM_MODE_FIQ32: reg(ic->arg[0]) = cpu->cd.arm.spsr_fiq; break;
806     case ARM_MODE_ABT32: reg(ic->arg[0]) = cpu->cd.arm.spsr_abt; break;
807     case ARM_MODE_UND32: reg(ic->arg[0]) = cpu->cd.arm.spsr_und; break;
808     case ARM_MODE_IRQ32: reg(ic->arg[0]) = cpu->cd.arm.spsr_irq; break;
809     case ARM_MODE_SVC32: reg(ic->arg[0]) = cpu->cd.arm.spsr_svc; break;
810     case ARM_MODE_USR32:
811     case ARM_MODE_SYS32: reg(ic->arg[0]) = 0; break;
812     default:fatal("mrs_spsr: unimplemented mode %i\n",
813     cpu->cd.arm.cpsr & ARM_FLAG_MODE);
814     exit(1);
815     }
816     }
817     Y(mrs_spsr)
818    
819    
820     /*
821     * mcr_mrc: Coprocessor move
822     * cdp: Coprocessor operation
823     *
824     * arg[0] = copy of the instruction word
825     */
826     X(mcr_mrc) {
827 dpavlin 20 uint32_t low_pc = ((size_t)ic - (size_t)
828 dpavlin 14 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
829 dpavlin 20 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
830     cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
831 dpavlin 14 arm_mcr_mrc(cpu, ic->arg[0]);
832     }
833     Y(mcr_mrc)
834     X(cdp) {
835 dpavlin 20 uint32_t low_pc = ((size_t)ic - (size_t)
836 dpavlin 14 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
837 dpavlin 20 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
838     cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
839 dpavlin 14 arm_cdp(cpu, ic->arg[0]);
840     }
841     Y(cdp)
842    
843    
844     /*
845     * openfirmware:
846     */
847     X(openfirmware)
848     {
849 dpavlin 20 /* TODO: sync pc? */
850 dpavlin 14 of_emul(cpu);
851 dpavlin 20 cpu->pc = cpu->cd.arm.r[ARM_LR];
852 dpavlin 14 if (cpu->machine->show_trace_tree)
853     cpu_functioncall_trace_return(cpu);
854 dpavlin 18 quick_pc_to_pointers(cpu);
855 dpavlin 14 }
856    
857    
858     /*
859 dpavlin 20 * reboot:
860     */
861     X(reboot)
862     {
863     cpu->running = 0;
864     cpu->n_translated_instrs --;
865     cpu->cd.arm.next_ic = &nothing_call;
866     }
867    
868    
869     /*
870 dpavlin 14 * swi_useremul: Syscall.
871     *
872     * arg[0] = swi number
873     */
874     X(swi_useremul)
875     {
876     /* Synchronize the program counter: */
877     uint32_t old_pc, low_pc = ((size_t)ic - (size_t)
878     cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
879 dpavlin 20 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1)
880 dpavlin 14 << ARM_INSTR_ALIGNMENT_SHIFT);
881 dpavlin 20 cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
882     old_pc = cpu->pc;
883 dpavlin 14
884     useremul_syscall(cpu, ic->arg[0]);
885    
886     if (!cpu->running) {
887     cpu->n_translated_instrs --;
888     cpu->cd.arm.next_ic = &nothing_call;
889     } else if (cpu->pc != old_pc) {
890     /* PC was changed by the SWI call. Find the new physical
891     page and update the translation pointers: */
892 dpavlin 18 quick_pc_to_pointers(cpu);
893 dpavlin 14 }
894     }
895     Y(swi_useremul)
896    
897    
898     /*
899     * swi: Software interrupt.
900     */
901     X(swi)
902     {
903 dpavlin 20 /* Synchronize the program counter first: */
904     cpu->pc &= 0xfffff000;
905     cpu->pc += ic->arg[0];
906 dpavlin 14 arm_exception(cpu, ARM_EXCEPTION_SWI);
907     }
908     Y(swi)
909    
910    
911     /*
912 dpavlin 20 * und: Undefined instruction.
913     */
914     X(und)
915     {
916     /* Synchronize the program counter first: */
917     cpu->pc &= 0xfffff000;
918     cpu->pc += ic->arg[0];
919     arm_exception(cpu, ARM_EXCEPTION_UND);
920     }
921     Y(und)
922    
923    
924     /*
925 dpavlin 14 * swp, swpb: Swap (word or byte).
926     *
927     * arg[0] = ptr to rd
928     * arg[1] = ptr to rm
929     * arg[2] = ptr to rn
930     */
931     X(swp)
932     {
933     uint32_t addr = reg(ic->arg[2]), data, data2;
934     unsigned char d[4];
935 dpavlin 20
936 dpavlin 14 /* Synchronize the program counter: */
937     uint32_t low_pc = ((size_t)ic - (size_t)
938     cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
939 dpavlin 20 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
940     cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
941 dpavlin 14
942     if (!cpu->memory_rw(cpu, cpu->mem, addr, d, sizeof(d), MEM_READ,
943     CACHE_DATA)) {
944     fatal("swp: load failed\n");
945     return;
946     }
947     data = d[0] + (d[1] << 8) + (d[2] << 16) + (d[3] << 24);
948     data2 = reg(ic->arg[1]);
949     d[0] = data2; d[1] = data2 >> 8; d[2] = data2 >> 16; d[3] = data2 >> 24;
950     if (!cpu->memory_rw(cpu, cpu->mem, addr, d, sizeof(d), MEM_WRITE,
951     CACHE_DATA)) {
952     fatal("swp: store failed\n");
953     return;
954     }
955     reg(ic->arg[0]) = data;
956     }
957     Y(swp)
958     X(swpb)
959     {
960     uint32_t addr = reg(ic->arg[2]), data;
961     unsigned char d[1];
962 dpavlin 20
963 dpavlin 14 /* Synchronize the program counter: */
964     uint32_t low_pc = ((size_t)ic - (size_t)
965     cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
966 dpavlin 20 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
967     cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
968 dpavlin 14
969     if (!cpu->memory_rw(cpu, cpu->mem, addr, d, sizeof(d), MEM_READ,
970     CACHE_DATA)) {
971     fatal("swp: load failed\n");
972     return;
973     }
974     data = d[0];
975     d[0] = reg(ic->arg[1]);
976     if (!cpu->memory_rw(cpu, cpu->mem, addr, d, sizeof(d), MEM_WRITE,
977     CACHE_DATA)) {
978     fatal("swp: store failed\n");
979     return;
980     }
981     reg(ic->arg[0]) = data;
982     }
983     Y(swpb)
984    
985    
986     extern void (*arm_load_store_instr[1024])(struct cpu *,
987     struct arm_instr_call *);
988 dpavlin 20 X(store_w1_word_u1_p0_imm);
989 dpavlin 14 X(store_w0_byte_u1_p0_imm);
990     X(store_w0_word_u1_p0_imm);
991 dpavlin 20 X(store_w0_word_u1_p1_imm);
992 dpavlin 42 X(load_w0_word_u1_p0_imm);
993     X(load_w0_word_u1_p1_imm);
994 dpavlin 20 X(load_w1_word_u1_p0_imm);
995 dpavlin 18 X(load_w0_byte_u1_p1_imm);
996     X(load_w0_byte_u1_p1_reg);
997 dpavlin 20 X(load_w1_byte_u1_p1_imm);
998 dpavlin 14
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 dpavlin 16 extern uint32_t (*arm_r[8192])(struct cpu *, struct arm_instr_call *);
1009 dpavlin 20 extern void arm_r_r3_t0_c0(void);
1010 dpavlin 16
1011 dpavlin 14 extern void (*arm_dpi_instr[2 * 2 * 2 * 16 * 16])(struct cpu *,
1012     struct arm_instr_call *);
1013 dpavlin 20 extern void (*arm_dpi_instr_regshort[2 * 16 * 16])(struct cpu *,
1014     struct arm_instr_call *);
1015 dpavlin 14 X(cmps);
1016 dpavlin 20 X(teqs);
1017     X(tsts);
1018 dpavlin 14 X(sub);
1019 dpavlin 18 X(add);
1020 dpavlin 14 X(subs);
1021 dpavlin 20 X(eor_regshort);
1022     X(cmps_regshort);
1023 dpavlin 14
1024    
1025 dpavlin 20 #include "cpu_arm_instr_misc.c"
1026 dpavlin 14
1027 dpavlin 20
1028 dpavlin 14 /*
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 dpavlin 16 int i, return_flag = 0;
1046 dpavlin 14 uint32_t new_values[16];
1047    
1048 dpavlin 18 #ifdef GATHER_BDT_STATISTICS
1049     if (!s_bit)
1050     update_bdt_statistics(iw);
1051     #endif
1052    
1053 dpavlin 14 /* 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 dpavlin 20 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
1057     cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
1058 dpavlin 14
1059     if (s_bit) {
1060 dpavlin 16 /* Load to USR registers: */
1061 dpavlin 14 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 dpavlin 16 }
1065     if (iw & 0x8000) {
1066 dpavlin 14 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 dpavlin 16 switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) {
1138 dpavlin 14 case ARM_MODE_USR32:
1139     case ARM_MODE_SYS32:
1140 dpavlin 16 cpu->cd.arm.r[i] = new_values[i];
1141 dpavlin 14 break;
1142     case ARM_MODE_FIQ32:
1143     if (i >= 8 && i <= 14)
1144 dpavlin 16 cpu->cd.arm.default_r8_r14[i-8] =
1145 dpavlin 14 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 dpavlin 16 case ARM_MODE_IRQ32:
1153 dpavlin 14 if (i >= 13 && i <= 14)
1154 dpavlin 16 cpu->cd.arm.default_r8_r14[i-8] =
1155 dpavlin 14 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 dpavlin 20 cpu->cd.arm.flags = cpu->cd.arm.cpsr >> 28;
1194 dpavlin 14
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 dpavlin 20 cpu->pc = cpu->cd.arm.r[ARM_PC] & 0xfffffffc;
1202 dpavlin 14 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 dpavlin 18 quick_pc_to_pointers(cpu);
1210 dpavlin 14 }
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 dpavlin 16 int i;
1233 dpavlin 14
1234 dpavlin 18 #ifdef GATHER_BDT_STATISTICS
1235     if (!s_bit)
1236     update_bdt_statistics(iw);
1237     #endif
1238    
1239 dpavlin 14 /* 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 dpavlin 20 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
1243     cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
1244 dpavlin 14
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 dpavlin 16 switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) {
1255 dpavlin 14 case ARM_MODE_FIQ32:
1256     if (i >= 8 && i <= 14)
1257 dpavlin 16 value = cpu->cd.arm.default_r8_r14[i-8];
1258 dpavlin 14 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 dpavlin 16 value = cpu->cd.arm.default_r8_r14[i-8];
1265 dpavlin 14 break;
1266     case ARM_MODE_USR32:
1267     case ARM_MODE_SYS32:
1268     break;
1269     }
1270     }
1271    
1272 dpavlin 20 /* NOTE/TODO: 8 vs 12 on some ARMs */
1273 dpavlin 14 if (i == ARM_PC)
1274 dpavlin 20 value = cpu->pc + 12;
1275 dpavlin 14
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 dpavlin 18 /* Various load/store multiple instructions: */
1332 dpavlin 24 extern uint32_t *multi_opcode[256];
1333     extern void (**multi_opcode_f[256])(struct cpu *, struct arm_instr_call *);
1334 dpavlin 20 X(multi_0x08b15018);
1335     X(multi_0x08ac000c__ge);
1336     X(multi_0x08a05018);
1337 dpavlin 18
1338    
1339 dpavlin 14 /*****************************************************************************/
1340    
1341    
1342     /*
1343 dpavlin 18 * 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 dpavlin 20 if (((cpu->cd.arm.flags & ARM_F_N)?1:0) !=
1363     ((cpu->cd.arm.flags & ARM_F_V)?1:0)) {
1364 dpavlin 18 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 dpavlin 20 } 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 dpavlin 18
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 dpavlin 20 } while (((cpu->cd.arm.flags & ARM_F_N)?1:0) ==
1453     ((cpu->cd.arm.flags & ARM_F_V)?1:0));
1454 dpavlin 18
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 dpavlin 20 cpu->cd.arm.r[0] += r1;
1476     cpu->cd.arm.r[1] = 0;
1477 dpavlin 18 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 dpavlin 20 cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N);
1529 dpavlin 18 if (t == 0)
1530 dpavlin 20 cpu->cd.arm.flags |= ARM_F_Z;
1531 dpavlin 18
1532     cpu->n_translated_instrs += 2;
1533     cpu->cd.arm.next_ic = &ic[3];
1534     }
1535    
1536    
1537 dpavlin 20 /*
1538 dpavlin 42 * 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 dpavlin 20 * 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 dpavlin 14 /*****************************************************************************/
2070    
2071    
2072     X(end_of_page)
2073     {
2074     /* Update the PC: (offset 0, but on the next page) */
2075 dpavlin 20 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 dpavlin 14
2078     /* Find the new physical page and update the translation pointers: */
2079 dpavlin 18 quick_pc_to_pointers(cpu);
2080 dpavlin 14
2081     /* end_of_page doesn't count as an executed instruction: */
2082     cpu->n_translated_instrs --;
2083     }
2084    
2085    
2086     /*****************************************************************************/
2087    
2088    
2089     /*
2090 dpavlin 22 * Combine: netbsd_memset():
2091 dpavlin 14 *
2092 dpavlin 18 * 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 dpavlin 14 */
2095 dpavlin 22 void COMBINE(netbsd_memset)(struct cpu *cpu,
2096 dpavlin 20 struct arm_instr_call *ic, int low_addr)
2097 dpavlin 14 {
2098 dpavlin 20 #ifdef HOST_LITTLE_ENDIAN
2099 dpavlin 18 int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2100 dpavlin 14 & (ARM_IC_ENTRIES_PER_PAGE-1);
2101    
2102 dpavlin 18 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 dpavlin 20 #endif
2115 dpavlin 18 }
2116    
2117    
2118     /*
2119 dpavlin 22 * Combine: netbsd_memcpy():
2120 dpavlin 18 *
2121     * Check for the core of a NetBSD/arm memcpy; large memcpys use a
2122     * sequence of ldmia instructions.
2123     */
2124 dpavlin 22 void COMBINE(netbsd_memcpy)(struct cpu *cpu, struct arm_instr_call *ic,
2125     int low_addr)
2126 dpavlin 18 {
2127 dpavlin 20 #ifdef HOST_LITTLE_ENDIAN
2128 dpavlin 18 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 dpavlin 20 #endif
2144 dpavlin 18 }
2145    
2146    
2147     /*
2148 dpavlin 22 * Combine: netbsd_cacheclean():
2149 dpavlin 18 *
2150     * Check for the core of a NetBSD/arm cache clean. (There are two variants.)
2151     */
2152 dpavlin 22 void COMBINE(netbsd_cacheclean)(struct cpu *cpu,
2153 dpavlin 20 struct arm_instr_call *ic, int low_addr)
2154 dpavlin 18 {
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 dpavlin 22 * Combine: netbsd_cacheclean2():
2172 dpavlin 18 *
2173     * Check for the core of a NetBSD/arm cache clean. (Second variant.)
2174     */
2175 dpavlin 22 void COMBINE(netbsd_cacheclean2)(struct cpu *cpu,
2176 dpavlin 20 struct arm_instr_call *ic, int low_addr)
2177 dpavlin 18 {
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 dpavlin 22 * Combine: netbsd_scanc():
2196 dpavlin 18 */
2197 dpavlin 22 void COMBINE(netbsd_scanc)(struct cpu *cpu,
2198 dpavlin 20 struct arm_instr_call *ic, int low_addr)
2199 dpavlin 18 {
2200     int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2201     & (ARM_IC_ENTRIES_PER_PAGE-1);
2202    
2203 dpavlin 20 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 dpavlin 18 }
2216     }
2217    
2218    
2219     /*
2220 dpavlin 22 * Combine: strlen():
2221 dpavlin 18 */
2222 dpavlin 22 void COMBINE(strlen)(struct cpu *cpu,
2223 dpavlin 20 struct arm_instr_call *ic, int low_addr)
2224 dpavlin 18 {
2225     int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2226     & (ARM_IC_ENTRIES_PER_PAGE-1);
2227    
2228 dpavlin 20 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 dpavlin 14 }
2239 dpavlin 18 }
2240 dpavlin 14
2241 dpavlin 18
2242 dpavlin 20 /*
2243 dpavlin 22 * Combine: xchg():
2244 dpavlin 20 */
2245 dpavlin 22 void COMBINE(xchg)(struct cpu *cpu,
2246 dpavlin 20 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 dpavlin 18
2252 dpavlin 20 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 dpavlin 22 * Combine: netbsd_copyin():
2269 dpavlin 20 */
2270 dpavlin 22 void COMBINE(netbsd_copyin)(struct cpu *cpu,
2271 dpavlin 20 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 dpavlin 22 * Combine: netbsd_copyout():
2300 dpavlin 20 */
2301 dpavlin 22 void COMBINE(netbsd_copyout)(struct cpu *cpu,
2302 dpavlin 20 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 dpavlin 42 * Combine: cmps + beq, etc:
2331 dpavlin 20 */
2332 dpavlin 42 void COMBINE(beq_etc)(struct cpu *cpu,
2333 dpavlin 20 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 dpavlin 14 }
2348 dpavlin 20 return;
2349 dpavlin 14 }
2350 dpavlin 20 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 dpavlin 42 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 dpavlin 20 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 dpavlin 14
2428    
2429     /*****************************************************************************/
2430    
2431    
2432 dpavlin 20 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 dpavlin 14 /*
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 dpavlin 20 int p_bit, u_bit, w_bit, l_bit, regform, rm, c, t, any_pc_reg;
2519 dpavlin 14 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 dpavlin 20 addr = cpu->pc & ~((ARM_IC_ENTRIES_PER_PAGE-1) <<
2525 dpavlin 14 ARM_INSTR_ALIGNMENT_SHIFT);
2526     addr += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
2527 dpavlin 20 cpu->pc = addr;
2528 dpavlin 14 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 dpavlin 20 /* fatal("TRANSLATION HIT! 0x%08x\n", addr); */
2534 dpavlin 14 memcpy(ib, page + (addr & 0xfff), sizeof(ib));
2535     } else {
2536 dpavlin 20 /* fatal("TRANSLATION MISS! 0x%08x\n", addr); */
2537 dpavlin 14 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 dpavlin 18 return;
2542 dpavlin 14 }
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 dpavlin 20 u_bit = iword & 0x00800000;
2562     w_bit = iword & 0x00200000;
2563     s_bit = l_bit = iword & 0x00100000;
2564 dpavlin 14 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 dpavlin 42 if (!cpu->translation_readahead)
2579     fatal("TODO: ARM condition code 0x%x\n",
2580     condition_code);
2581 dpavlin 14 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 dpavlin 42 if (!cpu->translation_readahead)
2623     fatal("TODO: sbit mull\n");
2624 dpavlin 14 goto bad;
2625     }
2626     ic->f = cond_instr(mull);
2627     ic->arg[0] = iword;
2628     break;
2629     }
2630 dpavlin 20 if ((iword & 0x0f900ff0) == 0x01000050) {
2631 dpavlin 42 if (!cpu->translation_readahead)
2632     fatal("TODO: q{,d}{add,sub}\n");
2633 dpavlin 20 goto bad;
2634     }
2635 dpavlin 14 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 dpavlin 20 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 dpavlin 22 /* 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 dpavlin 20 }
2690     if ((iword & 0x0ff0f0b0) == 0x012000a0) {
2691     /* TODO: smulwY */
2692     goto bad;
2693     }
2694 dpavlin 14 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 dpavlin 24 if (rm == ARM_PC) {
2705 dpavlin 42 if (!cpu->translation_readahead)
2706     fatal("msr PC?\n");
2707 dpavlin 24 goto bad;
2708     }
2709 dpavlin 14 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 dpavlin 42 default:if (!cpu->translation_readahead)
2724     fatal("unimpl a: msr regform\n");
2725 dpavlin 14 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 dpavlin 42 if (!cpu->translation_readahead)
2733     fatal("mrs PC?\n");
2734 dpavlin 14 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 dpavlin 16 ic->arg[1] = (size_t)(void *)arm_r[iword & 0xf];
2773 dpavlin 14 else
2774     ic->arg[1] = imm;
2775     break;
2776     }
2777    
2778     if (iword & 0x80 && !(main_opcode & 2) && iword & 0x10) {
2779 dpavlin 42 if (!cpu->translation_readahead)
2780     fatal("reg form blah blah\n");
2781 dpavlin 14 goto bad;
2782     }
2783    
2784 dpavlin 18 /* "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 dpavlin 14 break;
2791     }
2792    
2793 dpavlin 20 /* "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 dpavlin 14 ic->arg[1] = (size_t)(&cpu->cd.arm.r[rd]);
2803     break;
2804     }
2805    
2806 dpavlin 18 /* "mov reg,#0": */
2807 dpavlin 20 if ((iword & 0x0fff0fff) == 0x03a00000 && rd != ARM_PC) {
2808     arm_switch_clear(ic, rd, condition_code);
2809 dpavlin 18 break;
2810     }
2811    
2812     /* "mov reg,#1": */
2813 dpavlin 20 if ((iword & 0x0fff0fff) == 0x03a00001 && rd != ARM_PC) {
2814     arm_switch_mov1(ic, rd, condition_code);
2815 dpavlin 18 break;
2816     }
2817    
2818 dpavlin 20 /* "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 dpavlin 14 /*
2826     * Generic Data Processing Instructions:
2827     */
2828     if ((main_opcode & 2) == 0)
2829     regform = 1;
2830     else
2831     regform = 0;
2832    
2833 dpavlin 16 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 dpavlin 14 imm = iword & 0xff;
2847     while (r8-- > 0)
2848     imm = (imm >> 2) | ((imm & 3) << 30);
2849     ic->arg[1] = imm;
2850     }
2851    
2852 dpavlin 20 /* mvn #imm ==> mov #~imm */
2853     if (secondary_opcode == 0xf && !regform) {
2854     secondary_opcode = 0xd;
2855     ic->arg[1] = ~ic->arg[1];
2856     }
2857    
2858 dpavlin 14 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 dpavlin 20 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 dpavlin 18
2873 dpavlin 20 if (ic->f == instr(eor_regshort))
2874 dpavlin 22 cpu->cd.arm.combination_check = COMBINE(xchg);
2875 dpavlin 18 if (iword == 0xe113000c)
2876 dpavlin 22 cpu->cd.arm.combination_check = COMBINE(netbsd_scanc);
2877 dpavlin 14 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 dpavlin 16 ic->arg[1] = (size_t)(void *)arm_r[iword & 0xfff];
2901 dpavlin 14 if ((iword & 0x0e000010) == 0x06000010) {
2902 dpavlin 42 if (!cpu->translation_readahead)
2903     fatal("Not a Load/store TODO\n");
2904 dpavlin 14 goto bad;
2905     }
2906 dpavlin 20 /* 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 dpavlin 42 if (!cpu->translation_readahead)
2933     fatal("read failed X:"
2934     " TODO\n");
2935 dpavlin 20 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 dpavlin 22 cpu->cd.arm.combination_check = COMBINE(netbsd_copyin);
2951 dpavlin 20 if (iword == 0xe4a17004)
2952 dpavlin 22 cpu->cd.arm.combination_check = COMBINE(netbsd_copyout);
2953 dpavlin 14 break;
2954    
2955     case 0x8: /* Multiple load/store... (Block data transfer) */
2956     case 0x9: /* xxxx100P USWLnnnn llllllll llllllll */
2957 dpavlin 18 ic->arg[0] = (size_t)(&cpu->cd.arm.r[rn]);
2958     ic->arg[1] = (size_t)iword;
2959     /* Generic case: */
2960 dpavlin 14 if (l_bit)
2961     ic->f = cond_instr(bdt_load);
2962     else
2963     ic->f = cond_instr(bdt_store);
2964 dpavlin 18 #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 dpavlin 14 if (rn == ARM_PC) {
2993 dpavlin 42 if (!cpu->translation_readahead)
2994     fatal("TODO: bdt with PC as base\n");
2995 dpavlin 14 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 dpavlin 42
3005     /* Abort read-ahead on unconditional branches: */
3006     if (condition_code == 0xe &&
3007     cpu->translation_readahead > 1)
3008     cpu->translation_readahead = 1;
3009    
3010 dpavlin 18 if (iword == 0xcaffffed)
3011 dpavlin 20 cpu->cd.arm.combination_check =
3012 dpavlin 22 COMBINE(netbsd_memset);
3013 dpavlin 18 if (iword == 0xaafffff9)
3014 dpavlin 20 cpu->cd.arm.combination_check =
3015 dpavlin 22 COMBINE(netbsd_memcpy);
3016 dpavlin 14 } 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 dpavlin 20 /* 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 dpavlin 14 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 dpavlin 20 /*
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 dpavlin 14 {
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 dpavlin 20 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 dpavlin 14 }
3069     }
3070 dpavlin 18
3071 dpavlin 20 if (main_opcode == 0xa && (condition_code <= 1
3072     || condition_code == 3 || condition_code == 8
3073     || condition_code == 12 || condition_code == 13))
3074 dpavlin 42 cpu->cd.arm.combination_check = COMBINE(beq_etc);
3075 dpavlin 20
3076     if (iword == 0x1afffffc)
3077 dpavlin 22 cpu->cd.arm.combination_check = COMBINE(strlen);
3078 dpavlin 20
3079     /* Hm. Does this really increase performance? */
3080 dpavlin 18 if (iword == 0x8afffffa)
3081 dpavlin 20 cpu->cd.arm.combination_check =
3082 dpavlin 22 COMBINE(netbsd_cacheclean2);
3083 dpavlin 14 break;
3084    
3085 dpavlin 20 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 dpavlin 22 if ((iword & 0x0fe00fff) == 0x0c400000) {
3092     /* Special case: mar/mra DSP instructions */
3093 dpavlin 42 if (!cpu->translation_readahead)
3094     fatal("TODO: mar/mra DSP instructions!\n");
3095 dpavlin 22 /* Perhaps these are actually identical to MCRR/MRRC */
3096     goto bad;
3097     }
3098    
3099 dpavlin 20 if ((iword & 0x0fe00000) == 0x0c400000) {
3100 dpavlin 42 if (!cpu->translation_readahead)
3101     fatal("MCRR/MRRC: TODO\n");
3102 dpavlin 20 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 dpavlin 22 #if 0
3112 dpavlin 20 ic->f = cond_instr(und);
3113     ic->arg[0] = addr & 0xfff;
3114 dpavlin 22 #else
3115 dpavlin 42 if (!cpu->translation_readahead)
3116     fatal("LDC/STC: TODO\n");
3117 dpavlin 22 goto bad;
3118     #endif
3119 dpavlin 20 break;
3120    
3121 dpavlin 14 case 0xe:
3122 dpavlin 22 if ((iword & 0x0ff00ff0) == 0x0e200010) {
3123     /* Special case: mia* DSP instructions */
3124     /* See Intel's 27343601.pdf, page 16-20 */
3125 dpavlin 42 if (!cpu->translation_readahead)
3126     fatal("TODO: mia* DSP instructions!\n");
3127 dpavlin 22 goto bad;
3128     }
3129 dpavlin 14 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 dpavlin 18 if (iword == 0xee070f9a)
3139 dpavlin 20 cpu->cd.arm.combination_check =
3140 dpavlin 22 COMBINE(netbsd_cacheclean);
3141 dpavlin 14 break;
3142    
3143     case 0xf:
3144     /* SWI: */
3145     /* Default handler: */
3146     ic->f = cond_instr(swi);
3147 dpavlin 20 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 dpavlin 14 /* 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 dpavlin 42 if (!cpu->translation_readahead)
3160     fatal("Bad userland SWI?\n");
3161 dpavlin 14 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