/[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 32 - (hide annotations)
Mon Oct 8 16:20:58 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 79832 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1421 2006/11/06 05:32:37 debug Exp $
20060816	Adding a framework for emulated/virtual timers (src/timer.c),
		using only setitimer().
		Rewriting the mc146818 to use the new timer framework.
20060817	Adding a call to gettimeofday() every now and then (once every
		second, at the moment) to resynch the timer if it drifts.
		Beginning to convert the ISA timer interrupt mechanism (8253
		and 8259) to use the new timer framework.
		Removing the -I command line option.
20060819	Adding the -I command line option again, with new semantics.
		Working on Footbridge timer interrupts; NetBSD/NetWinder and
		NetBSD/CATS now run at correct speed, but unfortunately with
		HUGE delays during bootup.
20060821	Some minor m68k updates. Adding the first instruction: nop. :)
		Minor Alpha emulation updates.
20060822	Adding a FreeBSD development specific YAMON environment
		variable ("khz") (as suggested by Bruce M. Simpson).
		Moving YAMON environment variable initialization from
		machine_evbmips.c into promemul/yamon.c, and adding some more
		variables.
		Continuing on the LCA PCI bus controller (for Alpha machines).
20060823	Continuing on the timer stuff: experimenting with MIPS count/
		compare interrupts connected to the timer framework.
20060825	Adding bogus SCSI commands 0x51 (SCSICDROM_READ_DISCINFO) and
		0x52 (SCSICDROM_READ_TRACKINFO) to the SCSI emulation layer,
		to allow NetBSD/pmax 4.0_BETA to be installed from CDROM.
		Minor updates to the LCA PCI controller.
20060827	Implementing a CHIP8 cpu mode, and a corresponding CHIP8
		machine, for fun. Disassembly support for all instructions,
		and most of the common instructions have been implemented: mvi,
		mov_imm, add_imm, jmp, rand, cls, sprite, skeq_imm, jsr,
		skne_imm, bcd, rts, ldr, str, mov, or, and, xor, add, sub,
		font, ssound, sdelay, gdelay, bogus skup/skpr, skeq, skne.
20060828	Beginning to convert the CHIP8 cpu in the CHIP8 machine to a
		(more correct) RCA 180x cpu. (Disassembly for all 1802
		instructions has been implemented, but no execution yet, and
		no 1805 extended instructions.)
20060829	Minor Alpha emulation updates.
20060830	Beginning to experiment a little with PCI IDE for SGI O2.
		Fixing the cursor key mappings for MobilePro 770 emulation.
		Fixing the LK201 warning caused by recent NetBSD/pmax.
		The MIPS R41xx standby, suspend, and hibernate instructions now
		behave like the RM52xx/MIPS32/MIPS64 wait instruction.
		Fixing dev_wdc so it calculates correct (64-bit) offsets before
		giving them to diskimage_access().
20060831	Continuing on Alpha emulation (OSF1 PALcode).
20060901	Minor Alpha updates; beginning on virtual memory pagetables.
		Removed the limit for max nr of devices (in preparation for
		allowing devices' base addresses to be changed during runtime).
		Adding a hack for MIPS [d]mfc0 select 0 (except the count
		register), so that the coproc register is simply copied.
		The MIPS suspend instruction now exits the emulator, instead
		of being treated as a wait instruction (this causes NetBSD/
		hpcmips to get correct 'halt' behavior).
		The VR41xx RTC now returns correct time.
		Connecting the VR41xx timer to the timer framework (fixed at
		128 Hz, for now).
		Continuing on SPARC emulation, adding more instructions:
		restore, ba_xcc, ble. The rectangle drawing demo works :)
		Removing the last traces of the old ENABLE_CACHE_EMULATION
		MIPS stuff (not usable with dyntrans anyway).
20060902	Splitting up src/net.c into several smaller files in its own
		subdirectory (src/net/).
20060903	Cleanup of the files in src/net/, to make them less ugly.
20060904	Continuing on the 'settings' subsystem.
		Minor progress on the SPARC emulation mode.
20060905	Cleanup of various things, and connecting the settings
		infrastructure to various subsystems (emul, machine, cpu, etc).
		Changing the lk201 mouse update routine to not rely on any
		emulated hardware framebuffer cursor coordinates, but instead
		always do (semi-usable) relative movements.
20060906	Continuing on the lk201 mouse stuff. Mouse behaviour with
		multiple framebuffers (which was working in Ultrix) is now
		semi-broken (but it still works, in a way).
		Moving the documentation about networking into its own file
		(networking.html), and refreshing it a bit. Adding an example
		of how to use ethernet frame direct-access (udp_snoop).
20060907	Continuing on the settings infrastructure.
20060908	Minor updates to SH emulation: for 32-bit emulation: delay
		slots and the 'jsr @Rn' instruction. I'm putting 64-bit SH5 on
		ice, for now.
20060909-10	Implementing some more 32-bit SH instructions. Removing the
		64-bit mode completely. Enough has now been implemented to run
		the rectangle drawing demo. :-)
20060912	Adding more SH instructions.
20060916	Continuing on SH emulation (some more instructions: div0u,
		div1, rotcl/rotcr, more mov instructions, dt, braf, sets, sett,
		tst_imm, dmuls.l, subc, ldc_rm_vbr, movt, clrt, clrs, clrmac).
		Continuing on the settings subsystem (beginning on reading/
		writing settings, removing bugs, and connecting more cpus to
		the framework).
20060919	More work on SH emulation; adding an ldc banked instruction,
		and attaching a 640x480 framebuffer to the Dreamcast machine
		mode (NetBSD/dreamcast prints the NetBSD copyright banner :-),
		and then panics).
20060920	Continuing on the settings subsystem.
20060921	Fixing the Footbridge timer stuff so that NetBSD/cats and
		NetBSD/netwinder boot up without the delays.
20060922	Temporarily hardcoding MIPS timer interrupt to 100 Hz. With
		'wait' support disabled, NetBSD/malta and Linux/malta run at
		correct speed.
20060923	Connecting dev_gt to the timer framework, so that NetBSD/cobalt
		runs at correct speed.
		Moving SH4-specific memory mapped registers into its own
		device (dev_sh4.c).
		Running with -N now prints "idling" instead of bogus nr of
		instrs/second (which isn't valid anyway) while idling.
20060924	Algor emulation should now run at correct speed.
		Adding disassembly support for some MIPS64 revision 2
		instructions: ext, dext, dextm, dextu.
20060926	The timer framework now works also when the MIPS wait
		instruction is used.
20060928	Re-implementing checks for coprocessor availability for MIPS
		cop0 instructions. (Thanks to Carl van Schaik for noticing the
		lack of cop0 availability checks.)
20060929	Implementing an instruction combination hack which treats
		NetBSD/pmax' idle loop as a wait-like instruction.
20060930	The ENTRYHI_R_MASK was missing in (at least) memory_mips_v2p.c,
		causing TLB lookups to sometimes succeed when they should have
		failed. (A big thank you to Juli Mallett for noticing the
		problem.)
		Adding disassembly support for more MIPS64 revision 2 opcodes
		(seb, seh, wsbh, jalr.hb, jr.hb, synci, ins, dins, dinsu,
		dinsm, dsbh, dshd, ror, dror, rorv, drorv, dror32). Also
		implementing seb, seh, dsbh, dshd, and wsbh.
		Implementing an instruction combination hack for Linux/pmax'
		idle loop, similar to the NetBSD/pmax case.
20061001	Changing the NetBSD/sgimips install instructions to extract
		files from an iso image, instead of downloading them via ftp.
20061002	More-than-31-bit userland addresses in memory_mips_v2p.c were
		not actually working; applying a fix from Carl van Schaik to
		enable them to work + making some other updates (adding kuseg
		support).
		Fixing hpcmips (vr41xx) timer initialization.
		Experimenting with O(n)->O(1) reduction in the MIPS TLB lookup
		loop. Seems to work both for R3000 and non-R3000.
20061003	Continuing a little on SH emulation (adding more control
		registers; mini-cleanup of memory_sh.c).
20061004	Beginning on a dev_rtc, a clock/timer device for the test
		machines; also adding a demo, and some documentation.
		Fixing a bug in SH "mov.w @(disp,pc),Rn" (the result wasn't
		sign-extended), and adding the addc and ldtlb instructions.
20061005	Contining on SH emulation: virtual to physical address
		translation, and a skeleton exception mechanism.
20061006	Adding more SH instructions (various loads and stores, rte,
		negc, muls.w, various privileged register-move instructions).
20061007	More SH instructions: various move instructions, trapa, div0s,
		float, fdiv, ftrc.
		Continuing on dev_rtc; removing the rtc demo.
20061008	Adding a dummy Dreamcast PROM module. (Homebrew Dreamcast
		programs using KOS libs need this.)
		Adding more SH instructions: "stc vbr,rn", rotl, rotr, fsca,
		fmul, fadd, various floating-point moves, etc. A 256-byte
		demo for Dreamcast runs :-)
20061012	Adding the SH "lds Rm,pr" and bsr instructions.
20061013	More SH instructions: "sts fpscr,rn", tas.b, and some more
		floating point instructions, cmp/str, and more moves.
		Adding a dummy dev_pvr (Dreamcast graphics controller).
20061014	Generalizing the expression evaluator (used in the built-in
		debugger) to support parentheses and +-*/%^&|.
20061015	Removing the experimental tlb index hint code in
		mips_memory_v2p.c, since it didn't really have any effect.
20061017	Minor SH updates; adding the "sts pr,Rn", fcmp/gt, fneg,
		frchg, and some other instructions. Fixing missing sign-
		extension in an 8-bit load instruction.
20061019	Adding a simple dev_dreamcast_rtc.
		Implementing memory-mapped access to the SH ITLB/UTLB arrays.
20061021	Continuing on various SH and Dreamcast things: sh4 timers,
		debug messages for dev_pvr, fixing some virtual address
		translation bugs, adding the bsrf instruction.
		The NetBSD/dreamcast GENERIC_MD kernel now reaches userland :)
		Adding a dummy dev_dreamcast_asic.c (not really useful yet).
		Implementing simple support for Store Queues.
		Beginning on the PVR Tile Accelerator.
20061022	Generalizing the PVR framebuffer to support off-screen drawing,
		multiple bit-depths, etc. (A small speed penalty, but most
		likely worth it.)
		Adding more SH instructions (mulu.w, fcmp/eq, fsub, fmac,
		fschg, and some more); correcting bugs in "fsca" and "float".
20061024	Adding the SH ftrv (matrix * vector) instruction. Marcus
		Comstedt's "tatest" example runs :) (wireframe only).
		Correcting disassembly for SH floating point instructions that
		use the xd* registers.
		Adding the SH fsts instruction.
		In memory_device_dyntrans_access(), only the currently used
		range is now invalidated, and not the entire device range.
20061025	Adding a dummy AVR32 cpu mode skeleton.
20061026	Various Dreamcast updates; beginning on a Maple bus controller.
20061027	Continuing on the Maple bus. A bogus Controller, Keyboard, and
		Mouse can now be detected by NetBSD and KOS homebrew programs.
		Cleaning up the SH4 Timer Management Unit, and beginning on
		SH4 interrupts.
		Implementing the Dreamcast SYSASIC.
20061028	Continuing on the SYSASIC.
		Adding the SH fsqrt instruction.
		memory_sh.c now actually scans the ITLB.
		Fixing a bug in dev_sh4.c, related to associative writes into
		the memory-mapped UTLB array. NetBSD/dreamcast now reaches
		userland stably, and prints the "Terminal type?" message :-]
		Implementing enough of the Dreamcast keyboard to make NetBSD
		accept it for input.
		Enabling SuperH for stable (non-development) builds.
		Adding NetBSD/dreamcast to the documentation, although it
		doesn't support root-on-nfs yet.
20061029	Changing usleep(1) calls in the debugger to to usleep(10000)
		(according to Brian Foley, this makes GXemul run better on
		MacOS X).
		Making the Maple "Controller" do something (enough to barely
		interact with dcircus.elf).
20061030-31	Some progress on the PVR. More test programs start running (but
		with strange output).
		Various other SH4-related updates.
20061102	Various Dreamcast and SH4 updates; more KOS demos run now.
20061104	Adding a skeleton dev_mb8696x.c (the Dreamcast's LAN adapter).
20061105	Continuing on the MB8696x; NetBSD/dreamcast detects it as mbe0.
		Testing for the release.

==============  RELEASE 0.4.3  ==============


1 dpavlin 14 /*
2 dpavlin 22 * Copyright (C) 2005-2006 Anders Gavare. All rights reserved.
3 dpavlin 14 *
4     * Redistribution and use in source and binary forms, with or without
5     * modification, are permitted provided that the following conditions are met:
6     *
7     * 1. Redistributions of source code must retain the above copyright
8     * notice, this list of conditions and the following disclaimer.
9     * 2. Redistributions in binary form must reproduce the above copyright
10     * notice, this list of conditions and the following disclaimer in the
11     * documentation and/or other materials provided with the distribution.
12     * 3. The name of the author may not be used to endorse or promote products
13     * derived from this software without specific prior written permission.
14     *
15     * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16     * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18     * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19     * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20     * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21     * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24     * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25     * SUCH DAMAGE.
26     *
27     *
28 dpavlin 32 * $Id: cpu_arm_instr.c,v 1.69 2006/09/09 09:04:32 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     * arg[0] = relative offset
239     */
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     X(load_w1_word_u1_p0_imm);
993 dpavlin 18 X(load_w0_word_u1_p0_imm);
994     X(load_w0_byte_u1_p1_imm);
995     X(load_w0_byte_u1_p1_reg);
996 dpavlin 20 X(load_w1_byte_u1_p1_imm);
997 dpavlin 14
998     extern void (*arm_load_store_instr_pc[1024])(struct cpu *,
999     struct arm_instr_call *);
1000    
1001     extern void (*arm_load_store_instr_3[2048])(struct cpu *,
1002     struct arm_instr_call *);
1003    
1004     extern void (*arm_load_store_instr_3_pc[2048])(struct cpu *,
1005     struct arm_instr_call *);
1006    
1007 dpavlin 16 extern uint32_t (*arm_r[8192])(struct cpu *, struct arm_instr_call *);
1008 dpavlin 20 extern void arm_r_r3_t0_c0(void);
1009 dpavlin 16
1010 dpavlin 14 extern void (*arm_dpi_instr[2 * 2 * 2 * 16 * 16])(struct cpu *,
1011     struct arm_instr_call *);
1012 dpavlin 20 extern void (*arm_dpi_instr_regshort[2 * 16 * 16])(struct cpu *,
1013     struct arm_instr_call *);
1014 dpavlin 14 X(cmps);
1015 dpavlin 20 X(teqs);
1016     X(tsts);
1017 dpavlin 14 X(sub);
1018 dpavlin 18 X(add);
1019 dpavlin 14 X(subs);
1020 dpavlin 20 X(eor_regshort);
1021     X(cmps_regshort);
1022 dpavlin 14
1023    
1024 dpavlin 20 #include "cpu_arm_instr_misc.c"
1025 dpavlin 14
1026 dpavlin 20
1027 dpavlin 14 /*
1028     * bdt_load: Block Data Transfer, Load
1029     *
1030     * arg[0] = pointer to uint32_t in host memory, pointing to the base register
1031     * arg[1] = 32-bit instruction word. Most bits are read from this.
1032     */
1033     X(bdt_load)
1034     {
1035     unsigned char data[4];
1036     uint32_t *np = (uint32_t *)ic->arg[0];
1037     uint32_t addr = *np, low_pc;
1038     unsigned char *page;
1039     uint32_t iw = ic->arg[1]; /* xxxx100P USWLnnnn llllllll llllllll */
1040     int p_bit = iw & 0x01000000;
1041     int u_bit = iw & 0x00800000;
1042     int s_bit = iw & 0x00400000;
1043     int w_bit = iw & 0x00200000;
1044 dpavlin 16 int i, return_flag = 0;
1045 dpavlin 14 uint32_t new_values[16];
1046    
1047 dpavlin 18 #ifdef GATHER_BDT_STATISTICS
1048     if (!s_bit)
1049     update_bdt_statistics(iw);
1050     #endif
1051    
1052 dpavlin 14 /* Synchronize the program counter: */
1053     low_pc = ((size_t)ic - (size_t)
1054     cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
1055 dpavlin 20 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
1056     cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
1057 dpavlin 14
1058     if (s_bit) {
1059 dpavlin 16 /* Load to USR registers: */
1060 dpavlin 14 if ((cpu->cd.arm.cpsr & ARM_FLAG_MODE) == ARM_MODE_USR32) {
1061     fatal("[ bdt_load: s-bit: in usermode? ]\n");
1062     s_bit = 0;
1063 dpavlin 16 }
1064     if (iw & 0x8000) {
1065 dpavlin 14 s_bit = 0;
1066     return_flag = 1;
1067     }
1068     }
1069    
1070     for (i=(u_bit? 0 : 15); i>=0 && i<=15; i+=(u_bit? 1 : -1)) {
1071     uint32_t value;
1072    
1073     if (!((iw >> i) & 1)) {
1074     /* Skip register i: */
1075     continue;
1076     }
1077    
1078     if (p_bit) {
1079     if (u_bit)
1080     addr += sizeof(uint32_t);
1081     else
1082     addr -= sizeof(uint32_t);
1083     }
1084    
1085     page = cpu->cd.arm.host_load[addr >> 12];
1086     if (page != NULL) {
1087     uint32_t *p32 = (uint32_t *) page;
1088     value = p32[(addr & 0xfff) >> 2];
1089     /* Change byte order of value if
1090     host and emulated endianness differ: */
1091     #ifdef HOST_LITTLE_ENDIAN
1092     if (cpu->byte_order == EMUL_BIG_ENDIAN)
1093     #else
1094     if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
1095     #endif
1096     value = ((value & 0xff) << 24) |
1097     ((value & 0xff00) << 8) |
1098     ((value & 0xff0000) >> 8) |
1099     ((value & 0xff000000) >> 24);
1100     } else {
1101     if (!cpu->memory_rw(cpu, cpu->mem, addr, data,
1102     sizeof(data), MEM_READ, CACHE_DATA)) {
1103     /* load failed */
1104     return;
1105     }
1106     if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
1107     value = data[0] +
1108     (data[1] << 8) + (data[2] << 16)
1109     + (data[3] << 24);
1110     } else {
1111     value = data[3] +
1112     (data[2] << 8) + (data[1] << 16)
1113     + (data[0] << 24);
1114     }
1115     }
1116    
1117     new_values[i] = value;
1118    
1119     if (!p_bit) {
1120     if (u_bit)
1121     addr += sizeof(uint32_t);
1122     else
1123     addr -= sizeof(uint32_t);
1124     }
1125     }
1126    
1127     for (i=(u_bit? 0 : 15); i>=0 && i<=15; i+=(u_bit? 1 : -1)) {
1128     if (!((iw >> i) & 1)) {
1129     /* Skip register i: */
1130     continue;
1131     }
1132    
1133     if (!s_bit) {
1134     cpu->cd.arm.r[i] = new_values[i];
1135     } else {
1136 dpavlin 16 switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) {
1137 dpavlin 14 case ARM_MODE_USR32:
1138     case ARM_MODE_SYS32:
1139 dpavlin 16 cpu->cd.arm.r[i] = new_values[i];
1140 dpavlin 14 break;
1141     case ARM_MODE_FIQ32:
1142     if (i >= 8 && i <= 14)
1143 dpavlin 16 cpu->cd.arm.default_r8_r14[i-8] =
1144 dpavlin 14 new_values[i];
1145     else
1146     cpu->cd.arm.r[i] = new_values[i];
1147     break;
1148     case ARM_MODE_SVC32:
1149     case ARM_MODE_ABT32:
1150     case ARM_MODE_UND32:
1151 dpavlin 16 case ARM_MODE_IRQ32:
1152 dpavlin 14 if (i >= 13 && i <= 14)
1153 dpavlin 16 cpu->cd.arm.default_r8_r14[i-8] =
1154 dpavlin 14 new_values[i];
1155     else
1156     cpu->cd.arm.r[i] = new_values[i];
1157     break;
1158     }
1159     }
1160     }
1161    
1162     if (w_bit)
1163     *np = addr;
1164    
1165     if (return_flag) {
1166     uint32_t new_cpsr;
1167     int switch_register_banks;
1168    
1169     switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) {
1170     case ARM_MODE_FIQ32:
1171     new_cpsr = cpu->cd.arm.spsr_fiq; break;
1172     case ARM_MODE_ABT32:
1173     new_cpsr = cpu->cd.arm.spsr_abt; break;
1174     case ARM_MODE_UND32:
1175     new_cpsr = cpu->cd.arm.spsr_und; break;
1176     case ARM_MODE_IRQ32:
1177     new_cpsr = cpu->cd.arm.spsr_irq; break;
1178     case ARM_MODE_SVC32:
1179     new_cpsr = cpu->cd.arm.spsr_svc; break;
1180     default:fatal("bdt_load: unimplemented mode %i\n",
1181     cpu->cd.arm.cpsr & ARM_FLAG_MODE);
1182     exit(1);
1183     }
1184    
1185     switch_register_banks = (cpu->cd.arm.cpsr & ARM_FLAG_MODE) !=
1186     (new_cpsr & ARM_FLAG_MODE);
1187    
1188     if (switch_register_banks)
1189     arm_save_register_bank(cpu);
1190    
1191     cpu->cd.arm.cpsr = new_cpsr;
1192 dpavlin 20 cpu->cd.arm.flags = cpu->cd.arm.cpsr >> 28;
1193 dpavlin 14
1194     if (switch_register_banks)
1195     arm_load_register_bank(cpu);
1196     }
1197    
1198     /* NOTE: Special case: Loading the PC */
1199     if (iw & 0x8000) {
1200 dpavlin 20 cpu->pc = cpu->cd.arm.r[ARM_PC] & 0xfffffffc;
1201 dpavlin 14 if (cpu->machine->show_trace_tree)
1202     cpu_functioncall_trace_return(cpu);
1203     /* TODO: There is no need to update the
1204     pointers if this is a return to the
1205     same page! */
1206     /* Find the new physical page and update the
1207     translation pointers: */
1208 dpavlin 18 quick_pc_to_pointers(cpu);
1209 dpavlin 14 }
1210     }
1211     Y(bdt_load)
1212    
1213    
1214     /*
1215     * bdt_store: Block Data Transfer, Store
1216     *
1217     * arg[0] = pointer to uint32_t in host memory, pointing to the base register
1218     * arg[1] = 32-bit instruction word. Most bits are read from this.
1219     */
1220     X(bdt_store)
1221     {
1222     unsigned char data[4];
1223     uint32_t *np = (uint32_t *)ic->arg[0];
1224     uint32_t low_pc, value, addr = *np;
1225     uint32_t iw = ic->arg[1]; /* xxxx100P USWLnnnn llllllll llllllll */
1226     unsigned char *page;
1227     int p_bit = iw & 0x01000000;
1228     int u_bit = iw & 0x00800000;
1229     int s_bit = iw & 0x00400000;
1230     int w_bit = iw & 0x00200000;
1231 dpavlin 16 int i;
1232 dpavlin 14
1233 dpavlin 18 #ifdef GATHER_BDT_STATISTICS
1234     if (!s_bit)
1235     update_bdt_statistics(iw);
1236     #endif
1237    
1238 dpavlin 14 /* Synchronize the program counter: */
1239     low_pc = ((size_t)ic - (size_t)
1240     cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
1241 dpavlin 20 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
1242     cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
1243 dpavlin 14
1244     for (i=(u_bit? 0 : 15); i>=0 && i<=15; i+=(u_bit? 1 : -1)) {
1245     if (!((iw >> i) & 1)) {
1246     /* Skip register i: */
1247     continue;
1248     }
1249    
1250     value = cpu->cd.arm.r[i];
1251    
1252     if (s_bit) {
1253 dpavlin 16 switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) {
1254 dpavlin 14 case ARM_MODE_FIQ32:
1255     if (i >= 8 && i <= 14)
1256 dpavlin 16 value = cpu->cd.arm.default_r8_r14[i-8];
1257 dpavlin 14 break;
1258     case ARM_MODE_ABT32:
1259     case ARM_MODE_UND32:
1260     case ARM_MODE_IRQ32:
1261     case ARM_MODE_SVC32:
1262     if (i >= 13 && i <= 14)
1263 dpavlin 16 value = cpu->cd.arm.default_r8_r14[i-8];
1264 dpavlin 14 break;
1265     case ARM_MODE_USR32:
1266     case ARM_MODE_SYS32:
1267     break;
1268     }
1269     }
1270    
1271 dpavlin 20 /* NOTE/TODO: 8 vs 12 on some ARMs */
1272 dpavlin 14 if (i == ARM_PC)
1273 dpavlin 20 value = cpu->pc + 12;
1274 dpavlin 14
1275     if (p_bit) {
1276     if (u_bit)
1277     addr += sizeof(uint32_t);
1278     else
1279     addr -= sizeof(uint32_t);
1280     }
1281    
1282     page = cpu->cd.arm.host_store[addr >> 12];
1283     if (page != NULL) {
1284     uint32_t *p32 = (uint32_t *) page;
1285     /* Change byte order of value if
1286     host and emulated endianness differ: */
1287     #ifdef HOST_LITTLE_ENDIAN
1288     if (cpu->byte_order == EMUL_BIG_ENDIAN)
1289     #else
1290     if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
1291     #endif
1292     value = ((value & 0xff) << 24) |
1293     ((value & 0xff00) << 8) |
1294     ((value & 0xff0000) >> 8) |
1295     ((value & 0xff000000) >> 24);
1296     p32[(addr & 0xfff) >> 2] = value;
1297     } else {
1298     if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
1299     data[0] = value;
1300     data[1] = value >> 8;
1301     data[2] = value >> 16;
1302     data[3] = value >> 24;
1303     } else {
1304     data[0] = value >> 24;
1305     data[1] = value >> 16;
1306     data[2] = value >> 8;
1307     data[3] = value;
1308     }
1309     if (!cpu->memory_rw(cpu, cpu->mem, addr, data,
1310     sizeof(data), MEM_WRITE, CACHE_DATA)) {
1311     /* store failed */
1312     return;
1313     }
1314     }
1315    
1316     if (!p_bit) {
1317     if (u_bit)
1318     addr += sizeof(uint32_t);
1319     else
1320     addr -= sizeof(uint32_t);
1321     }
1322     }
1323    
1324     if (w_bit)
1325     *np = addr;
1326     }
1327     Y(bdt_store)
1328    
1329    
1330 dpavlin 18 /* Various load/store multiple instructions: */
1331 dpavlin 24 extern uint32_t *multi_opcode[256];
1332     extern void (**multi_opcode_f[256])(struct cpu *, struct arm_instr_call *);
1333 dpavlin 20 X(multi_0x08b15018);
1334     X(multi_0x08ac000c__ge);
1335     X(multi_0x08a05018);
1336 dpavlin 18
1337    
1338 dpavlin 14 /*****************************************************************************/
1339    
1340    
1341     /*
1342 dpavlin 18 * netbsd_memset:
1343     *
1344     * The core of a NetBSD/arm memset.
1345     *
1346     * f01bc420: e25XX080 subs rX,rX,#0x80
1347     * f01bc424: a8ac000c stmgeia ip!,{r2,r3} (16 of these)
1348     * ..
1349     * f01bc464: caffffed bgt 0xf01bc420 <memset+0x38>
1350     */
1351     X(netbsd_memset)
1352     {
1353     unsigned char *page;
1354     uint32_t addr;
1355    
1356     do {
1357     addr = cpu->cd.arm.r[ARM_IP];
1358    
1359     instr(subs)(cpu, ic);
1360    
1361 dpavlin 20 if (((cpu->cd.arm.flags & ARM_F_N)?1:0) !=
1362     ((cpu->cd.arm.flags & ARM_F_V)?1:0)) {
1363 dpavlin 18 cpu->n_translated_instrs += 16;
1364     /* Skip the store multiples: */
1365     cpu->cd.arm.next_ic = &ic[17];
1366     return;
1367     }
1368    
1369     /* Crossing a page boundary? Then continue non-combined. */
1370     if ((addr & 0xfff) + 128 > 0x1000)
1371     return;
1372    
1373     /* R2/R3 non-zero? Not allowed here. */
1374     if (cpu->cd.arm.r[2] != 0 || cpu->cd.arm.r[3] != 0)
1375     return;
1376    
1377     /* printf("addr = 0x%08x\n", addr); */
1378    
1379     page = cpu->cd.arm.host_store[addr >> 12];
1380     /* No page translation? Continue non-combined. */
1381     if (page == NULL)
1382     return;
1383    
1384     /* Clear: */
1385     memset(page + (addr & 0xfff), 0, 128);
1386     cpu->cd.arm.r[ARM_IP] = addr + 128;
1387     cpu->n_translated_instrs += 16;
1388    
1389     /* Branch back if greater: */
1390     cpu->n_translated_instrs += 1;
1391 dpavlin 20 } while (((cpu->cd.arm.flags & ARM_F_N)?1:0) ==
1392     ((cpu->cd.arm.flags & ARM_F_V)?1:0) &&
1393     !(cpu->cd.arm.flags & ARM_F_Z));
1394 dpavlin 18
1395     /* Continue at the instruction after the bgt: */
1396     cpu->cd.arm.next_ic = &ic[18];
1397     }
1398    
1399    
1400     /*
1401     * netbsd_memcpy:
1402     *
1403     * The core of a NetBSD/arm memcpy.
1404     *
1405     * f01bc530: e8b15018 ldmia r1!,{r3,r4,ip,lr}
1406     * f01bc534: e8a05018 stmia r0!,{r3,r4,ip,lr}
1407     * f01bc538: e8b15018 ldmia r1!,{r3,r4,ip,lr}
1408     * f01bc53c: e8a05018 stmia r0!,{r3,r4,ip,lr}
1409     * f01bc540: e2522020 subs r2,r2,#0x20
1410     * f01bc544: aafffff9 bge 0xf01bc530
1411     */
1412     X(netbsd_memcpy)
1413     {
1414     unsigned char *page_0, *page_1;
1415     uint32_t addr_r0, addr_r1;
1416    
1417     do {
1418     addr_r0 = cpu->cd.arm.r[0];
1419     addr_r1 = cpu->cd.arm.r[1];
1420    
1421     /* printf("addr_r0 = %08x r1 = %08x\n", addr_r0, addr_r1); */
1422    
1423     /* Crossing a page boundary? Then continue non-combined. */
1424     if ((addr_r0 & 0xfff) + 32 > 0x1000 ||
1425     (addr_r1 & 0xfff) + 32 > 0x1000) {
1426     instr(multi_0x08b15018)(cpu, ic);
1427     return;
1428     }
1429    
1430     page_0 = cpu->cd.arm.host_store[addr_r0 >> 12];
1431     page_1 = cpu->cd.arm.host_store[addr_r1 >> 12];
1432    
1433     /* No page translations? Continue non-combined. */
1434     if (page_0 == NULL || page_1 == NULL) {
1435     instr(multi_0x08b15018)(cpu, ic);
1436     return;
1437     }
1438    
1439     memcpy(page_0 + (addr_r0 & 0xfff),
1440     page_1 + (addr_r1 & 0xfff), 32);
1441     cpu->cd.arm.r[0] = addr_r0 + 32;
1442     cpu->cd.arm.r[1] = addr_r1 + 32;
1443    
1444     cpu->n_translated_instrs += 4;
1445    
1446     instr(subs)(cpu, ic + 4);
1447     cpu->n_translated_instrs ++;
1448    
1449     /* Loop while greater or equal: */
1450     cpu->n_translated_instrs ++;
1451 dpavlin 20 } while (((cpu->cd.arm.flags & ARM_F_N)?1:0) ==
1452     ((cpu->cd.arm.flags & ARM_F_V)?1:0));
1453 dpavlin 18
1454     /* Continue at the instruction after the bge: */
1455     cpu->cd.arm.next_ic = &ic[6];
1456     cpu->n_translated_instrs --;
1457     }
1458    
1459    
1460     /*
1461     * netbsd_cacheclean:
1462     *
1463     * The core of a NetBSD/arm cache clean routine, variant 1:
1464     *
1465     * f015f88c: e4902020 ldr r2,[r0],#32
1466     * f015f890: e2511020 subs r1,r1,#0x20
1467     * f015f894: 1afffffc bne 0xf015f88c
1468     * f015f898: ee070f9a mcr 15,0,r0,cr7,cr10,4
1469     */
1470     X(netbsd_cacheclean)
1471     {
1472     uint32_t r1 = cpu->cd.arm.r[1];
1473     cpu->n_translated_instrs += ((r1 >> 5) * 3);
1474 dpavlin 20 cpu->cd.arm.r[0] += r1;
1475     cpu->cd.arm.r[1] = 0;
1476 dpavlin 18 cpu->cd.arm.next_ic = &ic[4];
1477     }
1478    
1479    
1480     /*
1481     * netbsd_cacheclean2:
1482     *
1483     * The core of a NetBSD/arm cache clean routine, variant 2:
1484     *
1485     * f015f93c: ee070f3a mcr 15,0,r0,cr7,cr10,1
1486     * f015f940: ee070f36 mcr 15,0,r0,cr7,cr6,1
1487     * f015f944: e2800020 add r0,r0,#0x20
1488     * f015f948: e2511020 subs r1,r1,#0x20
1489     * f015f94c: 8afffffa bhi 0xf015f93c
1490     */
1491     X(netbsd_cacheclean2)
1492     {
1493     cpu->n_translated_instrs += ((cpu->cd.arm.r[1] >> 5) * 5) - 1;
1494     cpu->cd.arm.next_ic = &ic[5];
1495     }
1496    
1497    
1498     /*
1499     * netbsd_scanc:
1500     *
1501     * f01bccbc: e5d13000 ldrb r3,[r1]
1502     * f01bccc0: e7d23003 ldrb r3,[r2,r3]
1503     * f01bccc4: e113000c tsts r3,ip
1504     */
1505     X(netbsd_scanc)
1506     {
1507     unsigned char *page = cpu->cd.arm.host_load[cpu->cd.arm.r[1] >> 12];
1508     uint32_t t;
1509    
1510     if (page == NULL) {
1511     instr(load_w0_byte_u1_p1_imm)(cpu, ic);
1512     return;
1513     }
1514    
1515     t = page[cpu->cd.arm.r[1] & 0xfff];
1516     t += cpu->cd.arm.r[2];
1517     page = cpu->cd.arm.host_load[t >> 12];
1518    
1519     if (page == NULL) {
1520     instr(load_w0_byte_u1_p1_imm)(cpu, ic);
1521     return;
1522     }
1523    
1524     cpu->cd.arm.r[3] = page[t & 0xfff];
1525    
1526     t = cpu->cd.arm.r[3] & cpu->cd.arm.r[ARM_IP];
1527 dpavlin 20 cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N);
1528 dpavlin 18 if (t == 0)
1529 dpavlin 20 cpu->cd.arm.flags |= ARM_F_Z;
1530 dpavlin 18
1531     cpu->n_translated_instrs += 2;
1532     cpu->cd.arm.next_ic = &ic[3];
1533     }
1534    
1535    
1536 dpavlin 20 /*
1537     * strlen:
1538     *
1539     * S: e5f03001 ldrb rY,[rX,#1]!
1540     * e3530000 cmps rY,#0
1541     * 1afffffc bne S
1542     */
1543     X(strlen)
1544     {
1545     unsigned int n_loops = 0;
1546     uint32_t rY, rX = reg(ic[0].arg[0]);
1547     unsigned char *p;
1548    
1549     do {
1550     rX ++;
1551     p = cpu->cd.arm.host_load[rX >> 12];
1552     if (p == NULL) {
1553     cpu->n_translated_instrs += (n_loops * 3);
1554     instr(load_w1_byte_u1_p1_imm)(cpu, ic);
1555     return;
1556     }
1557    
1558     rY = reg(ic[0].arg[2]) = p[rX & 0xfff]; /* load */
1559     reg(ic[0].arg[0]) = rX; /* writeback */
1560     n_loops ++;
1561    
1562     /* Compare rY to zero: */
1563     cpu->cd.arm.flags = ARM_F_C;
1564     if (rY == 0)
1565     cpu->cd.arm.flags |= ARM_F_Z;
1566     } while (rY != 0);
1567    
1568     cpu->n_translated_instrs += (n_loops * 3) - 1;
1569     cpu->cd.arm.next_ic = &ic[3];
1570     }
1571    
1572    
1573     /*
1574     * xchg:
1575     *
1576     * e02YX00X eor rX,rY,rX
1577     * e02XY00Y eor rY,rX,rY
1578     * e02YX00X eor rX,rY,rX
1579     */
1580     X(xchg)
1581     {
1582     uint32_t tmp = reg(ic[0].arg[0]);
1583     cpu->n_translated_instrs += 2;
1584     cpu->cd.arm.next_ic = &ic[3];
1585     reg(ic[0].arg[0]) = reg(ic[1].arg[0]);
1586     reg(ic[1].arg[0]) = tmp;
1587     }
1588    
1589    
1590     /*
1591     * netbsd_copyin:
1592     *
1593     * e4b0a004 ldrt sl,[r0],#4
1594     * e4b0b004 ldrt fp,[r0],#4
1595     * e4b06004 ldrt r6,[r0],#4
1596     * e4b07004 ldrt r7,[r0],#4
1597     * e4b08004 ldrt r8,[r0],#4
1598     * e4b09004 ldrt r9,[r0],#4
1599     */
1600     X(netbsd_copyin)
1601     {
1602     uint32_t r0 = cpu->cd.arm.r[0], ofs = (r0 & 0xffc), index = r0 >> 12;
1603     unsigned char *p = cpu->cd.arm.host_load[index];
1604     uint32_t *p32 = (uint32_t *) p, *q32;
1605     int ok = cpu->cd.arm.is_userpage[index >> 5] & (1 << (index & 31));
1606    
1607     if (ofs > 0x1000 - 6*4 || !ok || p == NULL) {
1608     instr(load_w1_word_u1_p0_imm)(cpu, ic);
1609     return;
1610     }
1611     q32 = &cpu->cd.arm.r[6];
1612     ofs >>= 2;
1613     q32[0] = p32[ofs+2];
1614     q32[1] = p32[ofs+3];
1615     q32[2] = p32[ofs+4];
1616     q32[3] = p32[ofs+5];
1617     q32[4] = p32[ofs+0];
1618     q32[5] = p32[ofs+1];
1619     cpu->cd.arm.r[0] = r0 + 24;
1620     cpu->n_translated_instrs += 5;
1621     cpu->cd.arm.next_ic = &ic[6];
1622     }
1623    
1624    
1625     /*
1626     * netbsd_copyout:
1627     *
1628     * e4a18004 strt r8,[r1],#4
1629     * e4a19004 strt r9,[r1],#4
1630     * e4a1a004 strt sl,[r1],#4
1631     * e4a1b004 strt fp,[r1],#4
1632     * e4a16004 strt r6,[r1],#4
1633     * e4a17004 strt r7,[r1],#4
1634     */
1635     X(netbsd_copyout)
1636     {
1637     uint32_t r1 = cpu->cd.arm.r[1], ofs = (r1 & 0xffc), index = r1 >> 12;
1638     unsigned char *p = cpu->cd.arm.host_store[index];
1639     uint32_t *p32 = (uint32_t *) p, *q32;
1640     int ok = cpu->cd.arm.is_userpage[index >> 5] & (1 << (index & 31));
1641    
1642     if (ofs > 0x1000 - 6*4 || !ok || p == NULL) {
1643     instr(store_w1_word_u1_p0_imm)(cpu, ic);
1644     return;
1645     }
1646     q32 = &cpu->cd.arm.r[6];
1647     ofs >>= 2;
1648     p32[ofs ] = q32[2];
1649     p32[ofs+1] = q32[3];
1650     p32[ofs+2] = q32[4];
1651     p32[ofs+3] = q32[5];
1652     p32[ofs+4] = q32[0];
1653     p32[ofs+5] = q32[1];
1654     cpu->cd.arm.r[1] = r1 + 24;
1655     cpu->n_translated_instrs += 5;
1656     cpu->cd.arm.next_ic = &ic[6];
1657     }
1658    
1659    
1660     /*
1661     * cmps by 0, followed by beq (inside the same page):
1662     */
1663     X(cmps0_beq_samepage)
1664     {
1665     uint32_t a = reg(ic->arg[0]);
1666     cpu->n_translated_instrs ++;
1667     if (a == 0) {
1668     cpu->cd.arm.flags = ARM_F_Z | ARM_F_C;
1669     } else {
1670     /* Semi-ugly hack which sets the negative-bit if a < 0: */
1671     cpu->cd.arm.flags = ARM_F_C | ((a >> 28) & 8);
1672     }
1673     if (a == 0)
1674     cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0];
1675     else
1676     cpu->cd.arm.next_ic = &ic[2];
1677     }
1678    
1679    
1680     /*
1681     * cmps followed by beq (inside the same page):
1682     */
1683     X(cmps_beq_samepage)
1684     {
1685     uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a - b;
1686     cpu->n_translated_instrs ++;
1687     cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0;
1688     if (((int32_t)a >= 0 && (int32_t)b < 0 && (int32_t)c < 0) ||
1689     ((int32_t)a < 0 && (int32_t)b >= 0 && (int32_t)c >= 0))
1690     cpu->cd.arm.flags |= ARM_F_V;
1691     if (c == 0) {
1692     cpu->cd.arm.flags |= ARM_F_Z;
1693     cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0];
1694     } else {
1695     cpu->cd.arm.next_ic = &ic[2];
1696     if (c & 0x80000000)
1697     cpu->cd.arm.flags |= ARM_F_N;
1698     }
1699     }
1700    
1701    
1702     /*
1703     * cmps followed by beq (not the same page):
1704     */
1705     X(cmps_0_beq)
1706     {
1707     uint32_t a = reg(ic->arg[0]);
1708     cpu->n_translated_instrs ++;
1709     if (a == 0) {
1710     cpu->cd.arm.flags = ARM_F_Z | ARM_F_C;
1711     cpu->pc = (uint32_t)(((uint32_t)cpu->pc & 0xfffff000)
1712     + (int32_t)ic[1].arg[0]);
1713     quick_pc_to_pointers(cpu);
1714     } else {
1715     /* Semi-ugly hack which sets the negative-bit if a < 0: */
1716     cpu->cd.arm.flags = ARM_F_C | ((a >> 28) & 8);
1717     cpu->cd.arm.next_ic = &ic[2];
1718     }
1719     }
1720     X(cmps_pos_beq)
1721     {
1722     uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a - b;
1723     cpu->n_translated_instrs ++;
1724     cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0;
1725     if ((int32_t)a < 0 && (int32_t)c >= 0)
1726     cpu->cd.arm.flags |= ARM_F_V;
1727     if (c == 0) {
1728     cpu->cd.arm.flags |= ARM_F_Z;
1729     cpu->pc = (uint32_t)(((uint32_t)cpu->pc & 0xfffff000)
1730     + (int32_t)ic[1].arg[0]);
1731     quick_pc_to_pointers(cpu);
1732     } else {
1733     cpu->cd.arm.next_ic = &ic[2];
1734     if (c & 0x80000000)
1735     cpu->cd.arm.flags |= ARM_F_N;
1736     }
1737     }
1738     X(cmps_neg_beq)
1739     {
1740     uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a - b;
1741     cpu->n_translated_instrs ++;
1742     cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0;
1743     if ((int32_t)a >= 0 && (int32_t)c < 0)
1744     cpu->cd.arm.flags |= ARM_F_V;
1745     if (c == 0) {
1746     cpu->cd.arm.flags |= ARM_F_Z;
1747     cpu->pc = (uint32_t)(((uint32_t)cpu->pc & 0xfffff000)
1748     + (int32_t)ic[1].arg[0]);
1749     quick_pc_to_pointers(cpu);
1750     } else {
1751     cpu->cd.arm.next_ic = &ic[2];
1752     if (c & 0x80000000)
1753     cpu->cd.arm.flags |= ARM_F_N;
1754     }
1755     }
1756    
1757    
1758     /*
1759     * cmps by 0, followed by bne (inside the same page):
1760     */
1761     X(cmps0_bne_samepage)
1762     {
1763     uint32_t a = reg(ic->arg[0]);
1764     cpu->n_translated_instrs ++;
1765     if (a == 0) {
1766     cpu->cd.arm.flags = ARM_F_Z | ARM_F_C;
1767     } else {
1768     /* Semi-ugly hack which sets the negative-bit if a < 0: */
1769     cpu->cd.arm.flags = ARM_F_C | ((a >> 28) & 8);
1770     }
1771     if (a == 0)
1772     cpu->cd.arm.next_ic = &ic[2];
1773     else
1774     cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0];
1775     }
1776    
1777    
1778     /*
1779     * cmps followed by bne (inside the same page):
1780     */
1781     X(cmps_bne_samepage)
1782     {
1783     uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a - b;
1784     cpu->n_translated_instrs ++;
1785     cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0;
1786     if (((int32_t)a >= 0 && (int32_t)b < 0 && (int32_t)c < 0) ||
1787     ((int32_t)a < 0 && (int32_t)b >= 0 && (int32_t)c >= 0))
1788     cpu->cd.arm.flags |= ARM_F_V;
1789     if (c == 0) {
1790     cpu->cd.arm.flags |= ARM_F_Z;
1791     cpu->cd.arm.next_ic = &ic[2];
1792     } else {
1793     if (c & 0x80000000)
1794     cpu->cd.arm.flags |= ARM_F_N;
1795     cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0];
1796     }
1797     }
1798    
1799    
1800     /*
1801     * cmps followed by bcc (inside the same page):
1802     */
1803     X(cmps_bcc_samepage)
1804     {
1805     uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a - b;
1806     cpu->n_translated_instrs ++;
1807     cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0;
1808     if (c & 0x80000000)
1809     cpu->cd.arm.flags |= ARM_F_N;
1810     else if (c == 0)
1811     cpu->cd.arm.flags |= ARM_F_Z;
1812     if (((int32_t)a >= 0 && (int32_t)b < 0 && (int32_t)c < 0) ||
1813     ((int32_t)a < 0 && (int32_t)b >= 0 && (int32_t)c >= 0))
1814     cpu->cd.arm.flags |= ARM_F_V;
1815     if (a >= b)
1816     cpu->cd.arm.next_ic = &ic[2];
1817     else
1818     cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0];
1819     }
1820    
1821    
1822     /*
1823     * cmps (reg) followed by bcc (inside the same page):
1824     */
1825     X(cmps_reg_bcc_samepage)
1826     {
1827     uint32_t a = reg(ic->arg[0]), b = reg(ic->arg[1]), c = a - b;
1828     cpu->n_translated_instrs ++;
1829     cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0;
1830     if (c & 0x80000000)
1831     cpu->cd.arm.flags |= ARM_F_N;
1832     else if (c == 0)
1833     cpu->cd.arm.flags |= ARM_F_Z;
1834     if (((int32_t)a >= 0 && (int32_t)b < 0 && (int32_t)c < 0) ||
1835     ((int32_t)a < 0 && (int32_t)b >= 0 && (int32_t)c >= 0))
1836     cpu->cd.arm.flags |= ARM_F_V;
1837     if (a >= b)
1838     cpu->cd.arm.next_ic = &ic[2];
1839     else
1840     cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0];
1841     }
1842    
1843    
1844     /*
1845     * cmps followed by bhi (inside the same page):
1846     */
1847     X(cmps_bhi_samepage)
1848     {
1849     uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a - b;
1850     cpu->n_translated_instrs ++;
1851     cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0;
1852     if (c & 0x80000000)
1853     cpu->cd.arm.flags |= ARM_F_N;
1854     else if (c == 0)
1855     cpu->cd.arm.flags |= ARM_F_Z;
1856     if (((int32_t)a >= 0 && (int32_t)b < 0 && (int32_t)c < 0) ||
1857     ((int32_t)a < 0 && (int32_t)b >= 0 && (int32_t)c >= 0))
1858     cpu->cd.arm.flags |= ARM_F_V;
1859     if (a > b)
1860     cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0];
1861     else
1862     cpu->cd.arm.next_ic = &ic[2];
1863     }
1864    
1865    
1866     /*
1867     * cmps (reg) followed by bhi (inside the same page):
1868     */
1869     X(cmps_reg_bhi_samepage)
1870     {
1871     uint32_t a = reg(ic->arg[0]), b = reg(ic->arg[1]), c = a - b;
1872     cpu->n_translated_instrs ++;
1873     cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0;
1874     if (c & 0x80000000)
1875     cpu->cd.arm.flags |= ARM_F_N;
1876     else if (c == 0)
1877     cpu->cd.arm.flags |= ARM_F_Z;
1878     if (((int32_t)a >= 0 && (int32_t)b < 0 && (int32_t)c < 0) ||
1879     ((int32_t)a < 0 && (int32_t)b >= 0 && (int32_t)c >= 0))
1880     cpu->cd.arm.flags |= ARM_F_V;
1881     if (a > b)
1882     cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0];
1883     else
1884     cpu->cd.arm.next_ic = &ic[2];
1885     }
1886    
1887    
1888     /*
1889     * cmps followed by bgt (inside the same page):
1890     */
1891     X(cmps_bgt_samepage)
1892     {
1893     uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a - b;
1894     cpu->n_translated_instrs ++;
1895     cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0;
1896     if (c & 0x80000000)
1897     cpu->cd.arm.flags |= ARM_F_N;
1898     else if (c == 0)
1899     cpu->cd.arm.flags |= ARM_F_Z;
1900     if (((int32_t)a >= 0 && (int32_t)b < 0 && (int32_t)c < 0) ||
1901     ((int32_t)a < 0 && (int32_t)b >= 0 && (int32_t)c >= 0))
1902     cpu->cd.arm.flags |= ARM_F_V;
1903     if ((int32_t)a > (int32_t)b)
1904     cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0];
1905     else
1906     cpu->cd.arm.next_ic = &ic[2];
1907     }
1908    
1909    
1910     /*
1911     * cmps followed by ble (inside the same page):
1912     */
1913     X(cmps_ble_samepage)
1914     {
1915     uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a - b;
1916     cpu->n_translated_instrs ++;
1917     cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0;
1918     if (c & 0x80000000)
1919     cpu->cd.arm.flags |= ARM_F_N;
1920     else if (c == 0)
1921     cpu->cd.arm.flags |= ARM_F_Z;
1922     if (((int32_t)a >= 0 && (int32_t)b < 0 && (int32_t)c < 0) ||
1923     ((int32_t)a < 0 && (int32_t)b >= 0 && (int32_t)c >= 0))
1924     cpu->cd.arm.flags |= ARM_F_V;
1925     if ((int32_t)a <= (int32_t)b)
1926     cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0];
1927     else
1928     cpu->cd.arm.next_ic = &ic[2];
1929     }
1930    
1931    
1932     /*
1933     * teqs followed by beq (inside the same page):
1934     */
1935     X(teqs_beq_samepage)
1936     {
1937     uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a ^ b;
1938     cpu->n_translated_instrs ++;
1939     cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N);
1940     if (c == 0) {
1941     cpu->cd.arm.flags |= ARM_F_Z;
1942     cpu->cd.arm.next_ic = (struct arm_instr_call *)
1943     ic[1].arg[0];
1944     } else {
1945     if (c & 0x80000000)
1946     cpu->cd.arm.flags |= ARM_F_N;
1947     cpu->cd.arm.next_ic = &ic[2];
1948     }
1949     }
1950    
1951    
1952     /*
1953     * tsts followed by beq (inside the same page):
1954     * (arg[1] must not have its highest bit set))
1955     */
1956     X(tsts_lo_beq_samepage)
1957     {
1958     uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a & b;
1959     cpu->n_translated_instrs ++;
1960     cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N);
1961     if (c == 0)
1962     cpu->cd.arm.flags |= ARM_F_Z;
1963     if (c == 0)
1964     cpu->cd.arm.next_ic = (struct arm_instr_call *)
1965     ic[1].arg[0];
1966     else
1967     cpu->cd.arm.next_ic = &ic[2];
1968     }
1969    
1970    
1971     /*
1972     * teqs followed by bne (inside the same page):
1973     */
1974     X(teqs_bne_samepage)
1975     {
1976     uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a ^ b;
1977     cpu->n_translated_instrs ++;
1978     cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N);
1979     if (c == 0) {
1980     cpu->cd.arm.flags |= ARM_F_Z;
1981     } else {
1982     if (c & 0x80000000)
1983     cpu->cd.arm.flags |= ARM_F_N;
1984     }
1985     if (c == 0)
1986     cpu->cd.arm.next_ic = &ic[2];
1987     else
1988     cpu->cd.arm.next_ic = (struct arm_instr_call *)
1989     ic[1].arg[0];
1990     }
1991    
1992    
1993     /*
1994     * tsts followed by bne (inside the same page):
1995     * (arg[1] must not have its highest bit set))
1996     */
1997     X(tsts_lo_bne_samepage)
1998     {
1999     uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a & b;
2000     cpu->n_translated_instrs ++;
2001     cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N);
2002     if (c == 0)
2003     cpu->cd.arm.flags |= ARM_F_Z;
2004     if (c == 0)
2005     cpu->cd.arm.next_ic = &ic[2];
2006     else
2007     cpu->cd.arm.next_ic = (struct arm_instr_call *)
2008     ic[1].arg[0];
2009     }
2010    
2011    
2012 dpavlin 14 /*****************************************************************************/
2013    
2014    
2015     X(end_of_page)
2016     {
2017     /* Update the PC: (offset 0, but on the next page) */
2018 dpavlin 20 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
2019     cpu->pc += (ARM_IC_ENTRIES_PER_PAGE << ARM_INSTR_ALIGNMENT_SHIFT);
2020 dpavlin 14
2021     /* Find the new physical page and update the translation pointers: */
2022 dpavlin 18 quick_pc_to_pointers(cpu);
2023 dpavlin 14
2024     /* end_of_page doesn't count as an executed instruction: */
2025     cpu->n_translated_instrs --;
2026     }
2027    
2028    
2029     /*****************************************************************************/
2030    
2031    
2032     /*
2033 dpavlin 22 * Combine: netbsd_memset():
2034 dpavlin 14 *
2035 dpavlin 18 * Check for the core of a NetBSD/arm memset; large memsets use a sequence
2036     * of 16 store-multiple instructions, each storing 2 registers at a time.
2037 dpavlin 14 */
2038 dpavlin 22 void COMBINE(netbsd_memset)(struct cpu *cpu,
2039 dpavlin 20 struct arm_instr_call *ic, int low_addr)
2040 dpavlin 14 {
2041 dpavlin 20 #ifdef HOST_LITTLE_ENDIAN
2042 dpavlin 18 int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2043 dpavlin 14 & (ARM_IC_ENTRIES_PER_PAGE-1);
2044    
2045 dpavlin 18 if (n_back >= 17) {
2046     int i;
2047     for (i=-16; i<=-1; i++)
2048     if (ic[i].f != instr(multi_0x08ac000c__ge))
2049     return;
2050     if (ic[-17].f == instr(subs) &&
2051     ic[-17].arg[0]==ic[-17].arg[2] && ic[-17].arg[1] == 128 &&
2052     ic[ 0].f == instr(b_samepage__gt) &&
2053     ic[ 0].arg[0] == (size_t)&ic[-17]) {
2054     ic[-17].f = instr(netbsd_memset);
2055     }
2056     }
2057 dpavlin 20 #endif
2058 dpavlin 18 }
2059    
2060    
2061     /*
2062 dpavlin 22 * Combine: netbsd_memcpy():
2063 dpavlin 18 *
2064     * Check for the core of a NetBSD/arm memcpy; large memcpys use a
2065     * sequence of ldmia instructions.
2066     */
2067 dpavlin 22 void COMBINE(netbsd_memcpy)(struct cpu *cpu, struct arm_instr_call *ic,
2068     int low_addr)
2069 dpavlin 18 {
2070 dpavlin 20 #ifdef HOST_LITTLE_ENDIAN
2071 dpavlin 18 int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2072     & (ARM_IC_ENTRIES_PER_PAGE-1);
2073    
2074     if (n_back >= 5) {
2075     if (ic[-5].f==instr(multi_0x08b15018) &&
2076     ic[-4].f==instr(multi_0x08a05018) &&
2077     ic[-3].f==instr(multi_0x08b15018) &&
2078     ic[-2].f==instr(multi_0x08a05018) &&
2079     ic[-1].f == instr(subs) &&
2080     ic[-1].arg[0]==ic[-1].arg[2] && ic[-1].arg[1] == 0x20 &&
2081     ic[ 0].f == instr(b_samepage__ge) &&
2082     ic[ 0].arg[0] == (size_t)&ic[-5]) {
2083     ic[-5].f = instr(netbsd_memcpy);
2084     }
2085     }
2086 dpavlin 20 #endif
2087 dpavlin 18 }
2088    
2089    
2090     /*
2091 dpavlin 22 * Combine: netbsd_cacheclean():
2092 dpavlin 18 *
2093     * Check for the core of a NetBSD/arm cache clean. (There are two variants.)
2094     */
2095 dpavlin 22 void COMBINE(netbsd_cacheclean)(struct cpu *cpu,
2096 dpavlin 20 struct arm_instr_call *ic, int low_addr)
2097 dpavlin 18 {
2098     int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2099     & (ARM_IC_ENTRIES_PER_PAGE-1);
2100    
2101     if (n_back >= 3) {
2102     if (ic[-3].f==instr(load_w0_word_u1_p0_imm) &&
2103     ic[-2].f == instr(subs) &&
2104     ic[-2].arg[0]==ic[-2].arg[2] && ic[-2].arg[1] == 0x20 &&
2105     ic[-1].f == instr(b_samepage__ne) &&
2106     ic[-1].arg[0] == (size_t)&ic[-3]) {
2107     ic[-3].f = instr(netbsd_cacheclean);
2108     }
2109     }
2110     }
2111    
2112    
2113     /*
2114 dpavlin 22 * Combine: netbsd_cacheclean2():
2115 dpavlin 18 *
2116     * Check for the core of a NetBSD/arm cache clean. (Second variant.)
2117     */
2118 dpavlin 22 void COMBINE(netbsd_cacheclean2)(struct cpu *cpu,
2119 dpavlin 20 struct arm_instr_call *ic, int low_addr)
2120 dpavlin 18 {
2121     int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2122     & (ARM_IC_ENTRIES_PER_PAGE-1);
2123    
2124     if (n_back >= 4) {
2125     if (ic[-4].f == instr(mcr_mrc) && ic[-4].arg[0] == 0xee070f3a &&
2126     ic[-3].f == instr(mcr_mrc) && ic[-3].arg[0] == 0xee070f36 &&
2127     ic[-2].f == instr(add) &&
2128     ic[-2].arg[0]==ic[-2].arg[2] && ic[-2].arg[1] == 0x20 &&
2129     ic[-1].f == instr(subs) &&
2130     ic[-1].arg[0]==ic[-1].arg[2] && ic[-1].arg[1] == 0x20) {
2131     ic[-4].f = instr(netbsd_cacheclean2);
2132     }
2133     }
2134     }
2135    
2136    
2137     /*
2138 dpavlin 22 * Combine: netbsd_scanc():
2139 dpavlin 18 */
2140 dpavlin 22 void COMBINE(netbsd_scanc)(struct cpu *cpu,
2141 dpavlin 20 struct arm_instr_call *ic, int low_addr)
2142 dpavlin 18 {
2143     int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2144     & (ARM_IC_ENTRIES_PER_PAGE-1);
2145    
2146 dpavlin 20 if (n_back < 2)
2147     return;
2148    
2149     if (ic[-2].f == instr(load_w0_byte_u1_p1_imm) &&
2150     ic[-2].arg[0] == (size_t)(&cpu->cd.arm.r[1]) &&
2151     ic[-2].arg[1] == 0 &&
2152     ic[-2].arg[2] == (size_t)(&cpu->cd.arm.r[3]) &&
2153     ic[-1].f == instr(load_w0_byte_u1_p1_reg) &&
2154     ic[-1].arg[0] == (size_t)(&cpu->cd.arm.r[2]) &&
2155     ic[-1].arg[1] == (size_t)arm_r_r3_t0_c0 &&
2156     ic[-1].arg[2] == (size_t)(&cpu->cd.arm.r[3])) {
2157     ic[-2].f = instr(netbsd_scanc);
2158 dpavlin 18 }
2159     }
2160    
2161    
2162     /*
2163 dpavlin 22 * Combine: strlen():
2164 dpavlin 18 */
2165 dpavlin 22 void COMBINE(strlen)(struct cpu *cpu,
2166 dpavlin 20 struct arm_instr_call *ic, int low_addr)
2167 dpavlin 18 {
2168     int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2169     & (ARM_IC_ENTRIES_PER_PAGE-1);
2170    
2171 dpavlin 20 if (n_back < 2)
2172     return;
2173    
2174     if (ic[-2].f == instr(load_w1_byte_u1_p1_imm) &&
2175     ic[-2].arg[1] == 1 &&
2176     ic[-2].arg[2] == (size_t)(&cpu->cd.arm.r[3]) &&
2177     ic[-1].f == instr(cmps) &&
2178     ic[-1].arg[0] == (size_t)(&cpu->cd.arm.r[3]) &&
2179     ic[-1].arg[1] == 0) {
2180     ic[-2].f = instr(strlen);
2181 dpavlin 14 }
2182 dpavlin 18 }
2183 dpavlin 14
2184 dpavlin 18
2185 dpavlin 20 /*
2186 dpavlin 22 * Combine: xchg():
2187 dpavlin 20 */
2188 dpavlin 22 void COMBINE(xchg)(struct cpu *cpu,
2189 dpavlin 20 struct arm_instr_call *ic, int low_addr)
2190     {
2191     int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2192     & (ARM_IC_ENTRIES_PER_PAGE-1);
2193     size_t a, b;
2194 dpavlin 18
2195 dpavlin 20 if (n_back < 2)
2196     return;
2197    
2198     a = ic[-2].arg[0]; b = ic[-1].arg[0];
2199    
2200     if (ic[-2].f == instr(eor_regshort) &&
2201     ic[-1].f == instr(eor_regshort) &&
2202     ic[-2].arg[0] == a && ic[-2].arg[1] == b && ic[-2].arg[2] == b &&
2203     ic[-1].arg[0] == b && ic[-1].arg[1] == a && ic[-1].arg[2] == a &&
2204     ic[ 0].arg[0] == a && ic[ 0].arg[1] == b && ic[ 0].arg[2] == b) {
2205     ic[-2].f = instr(xchg);
2206     }
2207     }
2208    
2209    
2210     /*
2211 dpavlin 22 * Combine: netbsd_copyin():
2212 dpavlin 20 */
2213 dpavlin 22 void COMBINE(netbsd_copyin)(struct cpu *cpu,
2214 dpavlin 20 struct arm_instr_call *ic, int low_addr)
2215     {
2216     #ifdef HOST_LITTLE_ENDIAN
2217     int i, n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2218     & (ARM_IC_ENTRIES_PER_PAGE-1);
2219    
2220     if (n_back < 5)
2221     return;
2222    
2223     for (i=-5; i<0; i++) {
2224     if (ic[i].f != instr(load_w1_word_u1_p0_imm) ||
2225     ic[i].arg[0] != (size_t)(&cpu->cd.arm.r[0]) ||
2226     ic[i].arg[1] != 4)
2227     return;
2228     }
2229    
2230     if (ic[-5].arg[2] == (size_t)(&cpu->cd.arm.r[10]) &&
2231     ic[-4].arg[2] == (size_t)(&cpu->cd.arm.r[11]) &&
2232     ic[-3].arg[2] == (size_t)(&cpu->cd.arm.r[6]) &&
2233     ic[-2].arg[2] == (size_t)(&cpu->cd.arm.r[7]) &&
2234     ic[-1].arg[2] == (size_t)(&cpu->cd.arm.r[8])) {
2235     ic[-5].f = instr(netbsd_copyin);
2236     }
2237     #endif
2238     }
2239    
2240    
2241     /*
2242 dpavlin 22 * Combine: netbsd_copyout():
2243 dpavlin 20 */
2244 dpavlin 22 void COMBINE(netbsd_copyout)(struct cpu *cpu,
2245 dpavlin 20 struct arm_instr_call *ic, int low_addr)
2246     {
2247     #ifdef HOST_LITTLE_ENDIAN
2248     int i, n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2249     & (ARM_IC_ENTRIES_PER_PAGE-1);
2250    
2251     if (n_back < 5)
2252     return;
2253    
2254     for (i=-5; i<0; i++) {
2255     if (ic[i].f != instr(store_w1_word_u1_p0_imm) ||
2256     ic[i].arg[0] != (size_t)(&cpu->cd.arm.r[1]) ||
2257     ic[i].arg[1] != 4)
2258     return;
2259     }
2260    
2261     if (ic[-5].arg[2] == (size_t)(&cpu->cd.arm.r[8]) &&
2262     ic[-4].arg[2] == (size_t)(&cpu->cd.arm.r[9]) &&
2263     ic[-3].arg[2] == (size_t)(&cpu->cd.arm.r[10]) &&
2264     ic[-2].arg[2] == (size_t)(&cpu->cd.arm.r[11]) &&
2265     ic[-1].arg[2] == (size_t)(&cpu->cd.arm.r[6])) {
2266     ic[-5].f = instr(netbsd_copyout);
2267     }
2268     #endif
2269     }
2270    
2271    
2272     /*
2273 dpavlin 22 * Combine: cmps_b():
2274 dpavlin 20 */
2275 dpavlin 22 void COMBINE(cmps_b)(struct cpu *cpu,
2276 dpavlin 20 struct arm_instr_call *ic, int low_addr)
2277     {
2278     int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2279     & (ARM_IC_ENTRIES_PER_PAGE-1);
2280     if (n_back < 1)
2281     return;
2282     if (ic[0].f == instr(b__eq)) {
2283     if (ic[-1].f == instr(cmps)) {
2284     if (ic[-1].arg[1] == 0)
2285     ic[-1].f = instr(cmps_0_beq);
2286     else if (ic[-1].arg[1] & 0x80000000)
2287     ic[-1].f = instr(cmps_neg_beq);
2288     else
2289     ic[-1].f = instr(cmps_pos_beq);
2290 dpavlin 14 }
2291 dpavlin 20 return;
2292 dpavlin 14 }
2293 dpavlin 20 if (ic[0].f == instr(b_samepage__eq)) {
2294     if (ic[-1].f == instr(cmps)) {
2295     if (ic[-1].arg[1] == 0)
2296     ic[-1].f = instr(cmps0_beq_samepage);
2297     else
2298     ic[-1].f = instr(cmps_beq_samepage);
2299     }
2300     if (ic[-1].f == instr(tsts) &&
2301     !(ic[-1].arg[1] & 0x80000000)) {
2302     ic[-1].f = instr(tsts_lo_beq_samepage);
2303     }
2304     if (ic[-1].f == instr(teqs)) {
2305     ic[-1].f = instr(teqs_beq_samepage);
2306     }
2307     return;
2308     }
2309     if (ic[0].f == instr(b_samepage__ne)) {
2310     if (ic[-1].f == instr(cmps)) {
2311     if (ic[-1].arg[1] == 0)
2312     ic[-1].f = instr(cmps0_bne_samepage);
2313     else
2314     ic[-1].f = instr(cmps_bne_samepage);
2315     }
2316     if (ic[-1].f == instr(tsts) &&
2317     !(ic[-1].arg[1] & 0x80000000)) {
2318     ic[-1].f = instr(tsts_lo_bne_samepage);
2319     }
2320     if (ic[-1].f == instr(teqs)) {
2321     ic[-1].f = instr(teqs_bne_samepage);
2322     }
2323     return;
2324     }
2325     if (ic[0].f == instr(b_samepage__cc)) {
2326     if (ic[-1].f == instr(cmps)) {
2327     ic[-1].f = instr(cmps_bcc_samepage);
2328     }
2329     if (ic[-1].f == instr(cmps_regshort)) {
2330     ic[-1].f = instr(cmps_reg_bcc_samepage);
2331     }
2332     return;
2333     }
2334     if (ic[0].f == instr(b_samepage__hi)) {
2335     if (ic[-1].f == instr(cmps)) {
2336     ic[-1].f = instr(cmps_bhi_samepage);
2337     }
2338     if (ic[-1].f == instr(cmps_regshort)) {
2339     ic[-1].f = instr(cmps_reg_bhi_samepage);
2340     }
2341     return;
2342     }
2343     if (ic[0].f == instr(b_samepage__gt)) {
2344     if (ic[-1].f == instr(cmps)) {
2345     ic[-1].f = instr(cmps_bgt_samepage);
2346     }
2347     return;
2348     }
2349     if (ic[0].f == instr(b_samepage__le)) {
2350     if (ic[-1].f == instr(cmps)) {
2351     ic[-1].f = instr(cmps_ble_samepage);
2352     }
2353     return;
2354     }
2355     }
2356 dpavlin 14
2357    
2358     /*****************************************************************************/
2359    
2360    
2361 dpavlin 20 static void arm_switch_clear(struct arm_instr_call *ic, int rd,
2362     int condition_code)
2363     {
2364     switch (rd) {
2365     case 0: ic->f = cond_instr(clear_r0); break;
2366     case 1: ic->f = cond_instr(clear_r1); break;
2367     case 2: ic->f = cond_instr(clear_r2); break;
2368     case 3: ic->f = cond_instr(clear_r3); break;
2369     case 4: ic->f = cond_instr(clear_r4); break;
2370     case 5: ic->f = cond_instr(clear_r5); break;
2371     case 6: ic->f = cond_instr(clear_r6); break;
2372     case 7: ic->f = cond_instr(clear_r7); break;
2373     case 8: ic->f = cond_instr(clear_r8); break;
2374     case 9: ic->f = cond_instr(clear_r9); break;
2375     case 10: ic->f = cond_instr(clear_r10); break;
2376     case 11: ic->f = cond_instr(clear_r11); break;
2377     case 12: ic->f = cond_instr(clear_r12); break;
2378     case 13: ic->f = cond_instr(clear_r13); break;
2379     case 14: ic->f = cond_instr(clear_r14); break;
2380     }
2381     }
2382    
2383    
2384     static void arm_switch_mov1(struct arm_instr_call *ic, int rd,
2385     int condition_code)
2386     {
2387     switch (rd) {
2388     case 0: ic->f = cond_instr(mov1_r0); break;
2389     case 1: ic->f = cond_instr(mov1_r1); break;
2390     case 2: ic->f = cond_instr(mov1_r2); break;
2391     case 3: ic->f = cond_instr(mov1_r3); break;
2392     case 4: ic->f = cond_instr(mov1_r4); break;
2393     case 5: ic->f = cond_instr(mov1_r5); break;
2394     case 6: ic->f = cond_instr(mov1_r6); break;
2395     case 7: ic->f = cond_instr(mov1_r7); break;
2396     case 8: ic->f = cond_instr(mov1_r8); break;
2397     case 9: ic->f = cond_instr(mov1_r9); break;
2398     case 10: ic->f = cond_instr(mov1_r10); break;
2399     case 11: ic->f = cond_instr(mov1_r11); break;
2400     case 12: ic->f = cond_instr(mov1_r12); break;
2401     case 13: ic->f = cond_instr(mov1_r13); break;
2402     case 14: ic->f = cond_instr(mov1_r14); break;
2403     }
2404     }
2405    
2406    
2407     static void arm_switch_add1(struct arm_instr_call *ic, int rd,
2408     int condition_code)
2409     {
2410     switch (rd) {
2411     case 0: ic->f = cond_instr(add1_r0); break;
2412     case 1: ic->f = cond_instr(add1_r1); break;
2413     case 2: ic->f = cond_instr(add1_r2); break;
2414     case 3: ic->f = cond_instr(add1_r3); break;
2415     case 4: ic->f = cond_instr(add1_r4); break;
2416     case 5: ic->f = cond_instr(add1_r5); break;
2417     case 6: ic->f = cond_instr(add1_r6); break;
2418     case 7: ic->f = cond_instr(add1_r7); break;
2419     case 8: ic->f = cond_instr(add1_r8); break;
2420     case 9: ic->f = cond_instr(add1_r9); break;
2421     case 10: ic->f = cond_instr(add1_r10); break;
2422     case 11: ic->f = cond_instr(add1_r11); break;
2423     case 12: ic->f = cond_instr(add1_r12); break;
2424     case 13: ic->f = cond_instr(add1_r13); break;
2425     case 14: ic->f = cond_instr(add1_r14); break;
2426     }
2427     }
2428    
2429    
2430     /*****************************************************************************/
2431    
2432    
2433 dpavlin 14 /*
2434     * arm_instr_to_be_translated():
2435     *
2436     * Translate an instruction word into an arm_instr_call. ic is filled in with
2437     * valid data for the translated instruction, or a "nothing" instruction if
2438     * there was a translation failure. The newly translated instruction is then
2439     * executed.
2440     */
2441     X(to_be_translated)
2442     {
2443     uint32_t addr, low_pc, iword, imm = 0;
2444     unsigned char *page;
2445     unsigned char ib[4];
2446     int condition_code, main_opcode, secondary_opcode, s_bit, rn, rd, r8;
2447 dpavlin 20 int p_bit, u_bit, w_bit, l_bit, regform, rm, c, t, any_pc_reg;
2448 dpavlin 14 void (*samepage_function)(struct cpu *, struct arm_instr_call *);
2449    
2450     /* Figure out the address of the instruction: */
2451     low_pc = ((size_t)ic - (size_t)cpu->cd.arm.cur_ic_page)
2452     / sizeof(struct arm_instr_call);
2453 dpavlin 20 addr = cpu->pc & ~((ARM_IC_ENTRIES_PER_PAGE-1) <<
2454 dpavlin 14 ARM_INSTR_ALIGNMENT_SHIFT);
2455     addr += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
2456 dpavlin 20 cpu->pc = addr;
2457 dpavlin 14 addr &= ~((1 << ARM_INSTR_ALIGNMENT_SHIFT) - 1);
2458    
2459     /* Read the instruction word from memory: */
2460     page = cpu->cd.arm.host_load[addr >> 12];
2461     if (page != NULL) {
2462 dpavlin 20 /* fatal("TRANSLATION HIT! 0x%08x\n", addr); */
2463 dpavlin 14 memcpy(ib, page + (addr & 0xfff), sizeof(ib));
2464     } else {
2465 dpavlin 20 /* fatal("TRANSLATION MISS! 0x%08x\n", addr); */
2466 dpavlin 14 if (!cpu->memory_rw(cpu, cpu->mem, addr, &ib[0],
2467     sizeof(ib), MEM_READ, CACHE_INSTRUCTION)) {
2468     fatal("to_be_translated(): "
2469     "read failed: TODO\n");
2470 dpavlin 18 return;
2471 dpavlin 14 }
2472     }
2473    
2474     if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
2475     iword = ib[0] + (ib[1]<<8) + (ib[2]<<16) + (ib[3]<<24);
2476     else
2477     iword = ib[3] + (ib[2]<<8) + (ib[1]<<16) + (ib[0]<<24);
2478    
2479    
2480     #define DYNTRANS_TO_BE_TRANSLATED_HEAD
2481     #include "cpu_dyntrans.c"
2482     #undef DYNTRANS_TO_BE_TRANSLATED_HEAD
2483    
2484    
2485     /* The idea of taking bits 27..24 was found here:
2486     http://armphetamine.sourceforge.net/oldinfo.html */
2487     condition_code = iword >> 28;
2488     main_opcode = (iword >> 24) & 15;
2489     secondary_opcode = (iword >> 21) & 15;
2490 dpavlin 20 u_bit = iword & 0x00800000;
2491     w_bit = iword & 0x00200000;
2492     s_bit = l_bit = iword & 0x00100000;
2493 dpavlin 14 rn = (iword >> 16) & 15;
2494     rd = (iword >> 12) & 15;
2495     r8 = (iword >> 8) & 15;
2496     c = (iword >> 7) & 31;
2497     t = (iword >> 4) & 7;
2498     rm = iword & 15;
2499    
2500     if (condition_code == 0xf) {
2501     if ((iword & 0xfc70f000) == 0xf450f000) {
2502     /* Preload: TODO. Treat as NOP for now. */
2503     ic->f = instr(nop);
2504     goto okay;
2505     }
2506    
2507     fatal("TODO: ARM condition code 0x%x\n",
2508     condition_code);
2509     goto bad;
2510     }
2511    
2512    
2513     /*
2514     * Translate the instruction:
2515     */
2516    
2517     switch (main_opcode) {
2518    
2519     case 0x0:
2520     case 0x1:
2521     case 0x2:
2522     case 0x3:
2523     /* Check special cases first: */
2524     if ((iword & 0x0fc000f0) == 0x00000090) {
2525     /*
2526     * Multiplication:
2527     * xxxx0000 00ASdddd nnnnssss 1001mmmm (Rd,Rm,Rs[,Rn])
2528     */
2529     if (iword & 0x00200000) {
2530     if (s_bit)
2531     ic->f = cond_instr(mlas);
2532     else
2533     ic->f = cond_instr(mla);
2534     ic->arg[0] = iword;
2535     } else {
2536     if (s_bit)
2537     ic->f = cond_instr(muls);
2538     else
2539     ic->f = cond_instr(mul);
2540     /* NOTE: rn means rd in this case: */
2541     ic->arg[0] = (size_t)(&cpu->cd.arm.r[rn]);
2542     ic->arg[1] = (size_t)(&cpu->cd.arm.r[rm]);
2543     ic->arg[2] = (size_t)(&cpu->cd.arm.r[r8]);
2544     }
2545     break;
2546     }
2547     if ((iword & 0x0f8000f0) == 0x00800090) {
2548     /* Long multiplication: */
2549     if (s_bit) {
2550     fatal("TODO: sbit mull\n");
2551     goto bad;
2552     }
2553     ic->f = cond_instr(mull);
2554     ic->arg[0] = iword;
2555     break;
2556     }
2557 dpavlin 20 if ((iword & 0x0f900ff0) == 0x01000050) {
2558     fatal("TODO: q{,d}{add,sub}\n");
2559     goto bad;
2560     }
2561 dpavlin 14 if ((iword & 0x0ff000d0) == 0x01200010) {
2562     /* bx or blx */
2563     if (iword & 0x20)
2564     ic->f = cond_instr(blx);
2565     else {
2566     if (cpu->machine->show_trace_tree &&
2567     rm == ARM_LR)
2568     ic->f = cond_instr(bx_trace);
2569     else
2570     ic->f = cond_instr(bx);
2571     }
2572     ic->arg[0] = (size_t)(&cpu->cd.arm.r[rm]);
2573     break;
2574     }
2575     if ((iword & 0x0fb00ff0) == 0x1000090) {
2576     if (iword & 0x00400000)
2577     ic->f = cond_instr(swpb);
2578     else
2579     ic->f = cond_instr(swp);
2580     ic->arg[0] = (size_t)(&cpu->cd.arm.r[rd]);
2581     ic->arg[1] = (size_t)(&cpu->cd.arm.r[rm]);
2582     ic->arg[2] = (size_t)(&cpu->cd.arm.r[rn]);
2583     break;
2584     }
2585 dpavlin 20 if ((iword & 0x0fff0ff0) == 0x016f0f10) {
2586     ic->f = cond_instr(clz);
2587     ic->arg[0] = (size_t)(&cpu->cd.arm.r[rm]);
2588     ic->arg[1] = (size_t)(&cpu->cd.arm.r[rd]);
2589     break;
2590     }
2591     if ((iword & 0x0ff00090) == 0x01000080) {
2592     /* TODO: smlaXX */
2593     goto bad;
2594     }
2595     if ((iword & 0x0ff00090) == 0x01400080) {
2596     /* TODO: smlalY */
2597     goto bad;
2598     }
2599     if ((iword & 0x0ff000b0) == 0x01200080) {
2600     /* TODO: smlawY */
2601     goto bad;
2602     }
2603     if ((iword & 0x0ff0f090) == 0x01600080) {
2604 dpavlin 22 /* smulXY (16-bit * 16-bit => 32-bit) */
2605     switch (iword & 0x60) {
2606     case 0x00: ic->f = cond_instr(smulbb); break;
2607     case 0x20: ic->f = cond_instr(smultb); break;
2608     case 0x40: ic->f = cond_instr(smulbt); break;
2609     default: ic->f = cond_instr(smultt); break;
2610     }
2611     ic->arg[0] = (size_t)(&cpu->cd.arm.r[rm]);
2612     ic->arg[1] = (size_t)(&cpu->cd.arm.r[r8]);
2613     ic->arg[2] = (size_t)(&cpu->cd.arm.r[rn]); /* Rd */
2614     break;
2615 dpavlin 20 }
2616     if ((iword & 0x0ff0f0b0) == 0x012000a0) {
2617     /* TODO: smulwY */
2618     goto bad;
2619     }
2620 dpavlin 14 if ((iword & 0x0fb0fff0) == 0x0120f000 ||
2621     (iword & 0x0fb0f000) == 0x0320f000) {
2622     /* msr: move to [S|C]PSR from a register or
2623     immediate value */
2624     if (iword & 0x02000000) {
2625     if (iword & 0x00400000)
2626     ic->f = cond_instr(msr_imm_spsr);
2627     else
2628     ic->f = cond_instr(msr_imm);
2629     } else {
2630 dpavlin 24 if (rm == ARM_PC) {
2631     fatal("msr PC?\n");
2632     goto bad;
2633     }
2634 dpavlin 14 if (iword & 0x00400000)
2635     ic->f = cond_instr(msr_spsr);
2636     else
2637     ic->f = cond_instr(msr);
2638     }
2639     imm = iword & 0xff;
2640     while (r8-- > 0)
2641     imm = (imm >> 2) | ((imm & 3) << 30);
2642     ic->arg[0] = imm;
2643     ic->arg[2] = (size_t)(&cpu->cd.arm.r[rm]);
2644     switch ((iword >> 16) & 15) {
2645     case 1: ic->arg[1] = 0x000000ff; break;
2646     case 8: ic->arg[1] = 0xff000000; break;
2647     case 9: ic->arg[1] = 0xff0000ff; break;
2648     default:fatal("unimpl a: msr regform\n");
2649     goto bad;
2650     }
2651     break;
2652     }
2653     if ((iword & 0x0fbf0fff) == 0x010f0000) {
2654     /* mrs: move from CPSR/SPSR to a register: */
2655     if (rd == ARM_PC) {
2656     fatal("mrs PC?\n");
2657     goto bad;
2658     }
2659     if (iword & 0x00400000)
2660     ic->f = cond_instr(mrs_spsr);
2661     else
2662     ic->f = cond_instr(mrs);
2663     ic->arg[0] = (size_t)(&cpu->cd.arm.r[rd]);
2664     break;
2665     }
2666     if ((iword & 0x0e000090) == 0x00000090) {
2667     int imm = ((iword >> 4) & 0xf0) | (iword & 0xf);
2668     int regform = !(iword & 0x00400000);
2669     p_bit = main_opcode & 1;
2670     ic->arg[0] = (size_t)(&cpu->cd.arm.r[rn]);
2671     ic->arg[2] = (size_t)(&cpu->cd.arm.r[rd]);
2672     if (rd == ARM_PC || rn == ARM_PC) {
2673     ic->f = arm_load_store_instr_3_pc[
2674     condition_code + (l_bit? 16 : 0)
2675     + (iword & 0x40? 32 : 0)
2676     + (w_bit? 64 : 0)
2677     + (iword & 0x20? 128 : 0)
2678     + (u_bit? 256 : 0) + (p_bit? 512 : 0)
2679     + (regform? 1024 : 0)];
2680     if (rn == ARM_PC)
2681     ic->arg[0] = (size_t)
2682     (&cpu->cd.arm.tmp_pc);
2683     if (!l_bit && rd == ARM_PC)
2684     ic->arg[2] = (size_t)
2685     (&cpu->cd.arm.tmp_pc);
2686     } else
2687     ic->f = arm_load_store_instr_3[
2688     condition_code + (l_bit? 16 : 0)
2689     + (iword & 0x40? 32 : 0)
2690     + (w_bit? 64 : 0)
2691     + (iword & 0x20? 128 : 0)
2692     + (u_bit? 256 : 0) + (p_bit? 512 : 0)
2693     + (regform? 1024 : 0)];
2694     if (regform)
2695 dpavlin 16 ic->arg[1] = (size_t)(void *)arm_r[iword & 0xf];
2696 dpavlin 14 else
2697     ic->arg[1] = imm;
2698     break;
2699     }
2700    
2701     if (iword & 0x80 && !(main_opcode & 2) && iword & 0x10) {
2702     fatal("reg form blah blah\n");
2703     goto bad;
2704     }
2705    
2706 dpavlin 18 /* "mov pc,lr": */
2707     if ((iword & 0x0fffffff) == 0x01a0f00e) {
2708     if (cpu->machine->show_trace_tree)
2709     ic->f = cond_instr(ret_trace);
2710     else
2711     ic->f = cond_instr(ret);
2712 dpavlin 14 break;
2713     }
2714    
2715 dpavlin 20 /* "mov reg,reg" or "mov reg,pc": */
2716     if ((iword & 0x0fff0ff0) == 0x01a00000 && rd != ARM_PC) {
2717     if (rm != ARM_PC) {
2718     ic->f = cond_instr(mov_reg_reg);
2719     ic->arg[0] = (size_t)(&cpu->cd.arm.r[rm]);
2720     } else {
2721     ic->f = cond_instr(mov_reg_pc);
2722     ic->arg[0] = (addr & 0xfff) + 8;
2723     }
2724 dpavlin 14 ic->arg[1] = (size_t)(&cpu->cd.arm.r[rd]);
2725     break;
2726     }
2727    
2728 dpavlin 18 /* "mov reg,#0": */
2729 dpavlin 20 if ((iword & 0x0fff0fff) == 0x03a00000 && rd != ARM_PC) {
2730     arm_switch_clear(ic, rd, condition_code);
2731 dpavlin 18 break;
2732     }
2733    
2734     /* "mov reg,#1": */
2735 dpavlin 20 if ((iword & 0x0fff0fff) == 0x03a00001 && rd != ARM_PC) {
2736     arm_switch_mov1(ic, rd, condition_code);
2737 dpavlin 18 break;
2738     }
2739    
2740 dpavlin 20 /* "add reg,reg,#1": */
2741     if ((iword & 0x0ff00fff) == 0x02800001 && rd != ARM_PC
2742     && rn == rd) {
2743     arm_switch_add1(ic, rd, condition_code);
2744     break;
2745     }
2746    
2747 dpavlin 14 /*
2748     * Generic Data Processing Instructions:
2749     */
2750     if ((main_opcode & 2) == 0)
2751     regform = 1;
2752     else
2753     regform = 0;
2754    
2755 dpavlin 16 if (regform) {
2756     /* 0x1000 signifies Carry bit update on rotation,
2757     which is not necessary for add,adc,sub,sbc,
2758     rsb,rsc,cmp, or cmn, because they update the
2759     Carry bit manually anyway. */
2760     int q = 0x1000;
2761     if (s_bit == 0)
2762     q = 0;
2763     if ((secondary_opcode >= 2 && secondary_opcode <= 7)
2764     || secondary_opcode==0xa || secondary_opcode==0xb)
2765     q = 0;
2766     ic->arg[1] = (size_t)(void *)arm_r[(iword & 0xfff) + q];
2767     } else {
2768 dpavlin 14 imm = iword & 0xff;
2769     while (r8-- > 0)
2770     imm = (imm >> 2) | ((imm & 3) << 30);
2771     ic->arg[1] = imm;
2772     }
2773    
2774 dpavlin 20 /* mvn #imm ==> mov #~imm */
2775     if (secondary_opcode == 0xf && !regform) {
2776     secondary_opcode = 0xd;
2777     ic->arg[1] = ~ic->arg[1];
2778     }
2779    
2780 dpavlin 14 ic->arg[0] = (size_t)(&cpu->cd.arm.r[rn]);
2781     ic->arg[2] = (size_t)(&cpu->cd.arm.r[rd]);
2782     any_pc_reg = 0;
2783     if (rn == ARM_PC || rd == ARM_PC)
2784     any_pc_reg = 1;
2785    
2786 dpavlin 20 if (!any_pc_reg && regform && (iword & 0xfff) < ARM_PC) {
2787     ic->arg[1] = (size_t)(&cpu->cd.arm.r[rm]);
2788     ic->f = arm_dpi_instr_regshort[condition_code +
2789     16 * secondary_opcode + (s_bit? 256 : 0)];
2790     } else
2791     ic->f = arm_dpi_instr[condition_code +
2792     16 * secondary_opcode + (s_bit? 256 : 0) +
2793     (any_pc_reg? 512 : 0) + (regform? 1024 : 0)];
2794 dpavlin 18
2795 dpavlin 20 if (ic->f == instr(eor_regshort))
2796 dpavlin 22 cpu->cd.arm.combination_check = COMBINE(xchg);
2797 dpavlin 18 if (iword == 0xe113000c)
2798 dpavlin 22 cpu->cd.arm.combination_check = COMBINE(netbsd_scanc);
2799 dpavlin 14 break;
2800    
2801     case 0x4: /* Load and store... */
2802     case 0x5: /* xxxx010P UBWLnnnn ddddoooo oooooooo Immediate */
2803     case 0x6: /* xxxx011P UBWLnnnn ddddcccc ctt0mmmm Register */
2804     case 0x7:
2805     ic->arg[0] = (size_t)(&cpu->cd.arm.r[rn]);
2806     ic->arg[2] = (size_t)(&cpu->cd.arm.r[rd]);
2807     if (rd == ARM_PC || rn == ARM_PC) {
2808     ic->f = arm_load_store_instr_pc[((iword >> 16)
2809     & 0x3f0) + condition_code];
2810     if (rn == ARM_PC)
2811     ic->arg[0] = (size_t)(&cpu->cd.arm.tmp_pc);
2812     if (!l_bit && rd == ARM_PC)
2813     ic->arg[2] = (size_t)(&cpu->cd.arm.tmp_pc);
2814     } else {
2815     ic->f = arm_load_store_instr[((iword >> 16) &
2816     0x3f0) + condition_code];
2817     }
2818     imm = iword & 0xfff;
2819     if (main_opcode < 6)
2820     ic->arg[1] = imm;
2821     else
2822 dpavlin 16 ic->arg[1] = (size_t)(void *)arm_r[iword & 0xfff];
2823 dpavlin 14 if ((iword & 0x0e000010) == 0x06000010) {
2824     fatal("Not a Load/store TODO\n");
2825     goto bad;
2826     }
2827 dpavlin 20 /* Special case: pc-relative load within the same page: */
2828     if (rn == ARM_PC && rd != ARM_PC && main_opcode < 6) {
2829     int ofs = (addr & 0xfff) + 8, max = 0xffc;
2830     int b_bit = iword & 0x00400000;
2831     if (b_bit)
2832     max = 0xfff;
2833     if (u_bit)
2834     ofs += (iword & 0xfff);
2835     else
2836     ofs -= (iword & 0xfff);
2837     /* NOTE/TODO: This assumes 4KB pages,
2838     it will not work with 1KB pages. */
2839     if (ofs >= 0 && ofs <= max) {
2840     unsigned char *p;
2841     unsigned char c[4];
2842     int len = b_bit? 1 : 4;
2843     uint32_t x, a = (addr & 0xfffff000) | ofs;
2844     /* ic->f = cond_instr(mov); */
2845     ic->f = arm_dpi_instr[condition_code + 16*0xd];
2846     ic->arg[2] = (size_t)(&cpu->cd.arm.r[rd]);
2847     p = cpu->cd.arm.host_load[a >> 12];
2848     if (p != NULL) {
2849     memcpy(c, p + (a & 0xfff), len);
2850     } else {
2851     if (!cpu->memory_rw(cpu, cpu->mem, a,
2852     c, len, MEM_READ, CACHE_DATA)) {
2853     fatal("to_be_translated(): "
2854     "read failed X: TODO\n");
2855     goto bad;
2856     }
2857     }
2858     if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
2859     x = c[0] + (c[1]<<8) +
2860     (c[2]<<16) + (c[3]<<24);
2861     else
2862     x = c[3] + (c[2]<<8) +
2863     (c[1]<<16) + (c[0]<<24);
2864     if (b_bit)
2865     x = c[0];
2866     ic->arg[1] = x;
2867     }
2868     }
2869     if (iword == 0xe4b09004)
2870 dpavlin 22 cpu->cd.arm.combination_check = COMBINE(netbsd_copyin);
2871 dpavlin 20 if (iword == 0xe4a17004)
2872 dpavlin 22 cpu->cd.arm.combination_check = COMBINE(netbsd_copyout);
2873 dpavlin 14 break;
2874    
2875     case 0x8: /* Multiple load/store... (Block data transfer) */
2876     case 0x9: /* xxxx100P USWLnnnn llllllll llllllll */
2877 dpavlin 18 ic->arg[0] = (size_t)(&cpu->cd.arm.r[rn]);
2878     ic->arg[1] = (size_t)iword;
2879     /* Generic case: */
2880 dpavlin 14 if (l_bit)
2881     ic->f = cond_instr(bdt_load);
2882     else
2883     ic->f = cond_instr(bdt_store);
2884 dpavlin 18 #if defined(HOST_LITTLE_ENDIAN) && !defined(GATHER_BDT_STATISTICS)
2885     /*
2886     * Check for availability of optimized implementation:
2887     * xxxx100P USWLnnnn llllllll llllllll
2888     * ^ ^ ^ ^ ^ ^ ^ ^ (0x00950154)
2889     * These bits are used to select which list to scan, and then
2890     * the list is scanned linearly.
2891     *
2892     * The optimized functions do not support show_trace_tree,
2893     * but it's ok to use the unoptimized version in that case.
2894     */
2895     if (!cpu->machine->show_trace_tree) {
2896     int i = 0, j = iword;
2897     j = ((j & 0x00800000) >> 16) | ((j & 0x00100000) >> 14)
2898     | ((j & 0x00040000) >> 13) | ((j & 0x00010000) >> 12)
2899     | ((j & 0x00000100) >> 5) | ((j & 0x00000040) >> 4)
2900     | ((j & 0x00000010) >> 3) | ((j & 0x00000004) >> 2);
2901     while (multi_opcode[j][i] != 0) {
2902     if ((iword & 0x0fffffff) ==
2903     multi_opcode[j][i]) {
2904     ic->f = multi_opcode_f[j]
2905     [i*16 + condition_code];
2906     break;
2907     }
2908     i ++;
2909     }
2910     }
2911     #endif
2912 dpavlin 14 if (rn == ARM_PC) {
2913     fatal("TODO: bdt with PC as base\n");
2914     goto bad;
2915     }
2916     break;
2917    
2918     case 0xa: /* B: branch */
2919     case 0xb: /* BL: branch+link */
2920     if (main_opcode == 0x0a) {
2921     ic->f = cond_instr(b);
2922     samepage_function = cond_instr(b_samepage);
2923 dpavlin 18 if (iword == 0xcaffffed)
2924 dpavlin 20 cpu->cd.arm.combination_check =
2925 dpavlin 22 COMBINE(netbsd_memset);
2926 dpavlin 18 if (iword == 0xaafffff9)
2927 dpavlin 20 cpu->cd.arm.combination_check =
2928 dpavlin 22 COMBINE(netbsd_memcpy);
2929 dpavlin 14 } else {
2930     if (cpu->machine->show_trace_tree) {
2931     ic->f = cond_instr(bl_trace);
2932     samepage_function =
2933     cond_instr(bl_samepage_trace);
2934     } else {
2935     ic->f = cond_instr(bl);
2936     samepage_function = cond_instr(bl_samepage);
2937     }
2938     }
2939    
2940 dpavlin 20 /* arg 1 = offset of current instruction */
2941     /* arg 2 = offset of the following instruction */
2942     ic->arg[1] = addr & 0xffc;
2943     ic->arg[2] = (addr & 0xffc) + 4;
2944    
2945 dpavlin 14 ic->arg[0] = (iword & 0x00ffffff) << 2;
2946     /* Sign-extend: */
2947     if (ic->arg[0] & 0x02000000)
2948     ic->arg[0] |= 0xfc000000;
2949     /*
2950     * Branches are calculated as PC + 8 + offset.
2951     */
2952     ic->arg[0] = (int32_t)(ic->arg[0] + 8);
2953    
2954 dpavlin 20 /*
2955     * Special case: branch within the same page:
2956     *
2957     * arg[0] = addr of the arm_instr_call of the target
2958     * arg[1] = addr of the next arm_instr_call.
2959     */
2960 dpavlin 14 {
2961     uint32_t mask_within_page =
2962     ((ARM_IC_ENTRIES_PER_PAGE-1) <<
2963     ARM_INSTR_ALIGNMENT_SHIFT) |
2964     ((1 << ARM_INSTR_ALIGNMENT_SHIFT) - 1);
2965     uint32_t old_pc = addr;
2966     uint32_t new_pc = old_pc + (int32_t)ic->arg[0];
2967     if ((old_pc & ~mask_within_page) ==
2968     (new_pc & ~mask_within_page)) {
2969     ic->f = samepage_function;
2970     ic->arg[0] = (size_t) (
2971     cpu->cd.arm.cur_ic_page +
2972     ((new_pc & mask_within_page) >>
2973     ARM_INSTR_ALIGNMENT_SHIFT));
2974 dpavlin 20 ic->arg[1] = (size_t) (
2975     cpu->cd.arm.cur_ic_page +
2976     (((addr & mask_within_page) + 4) >>
2977     ARM_INSTR_ALIGNMENT_SHIFT));
2978     } else if (main_opcode == 0x0a) {
2979     /* Special hack for a plain "b": */
2980     ic->arg[0] += ic->arg[1];
2981 dpavlin 14 }
2982     }
2983 dpavlin 18
2984 dpavlin 20 if (main_opcode == 0xa && (condition_code <= 1
2985     || condition_code == 3 || condition_code == 8
2986     || condition_code == 12 || condition_code == 13))
2987 dpavlin 22 cpu->cd.arm.combination_check = COMBINE(cmps_b);
2988 dpavlin 20
2989     if (iword == 0x1afffffc)
2990 dpavlin 22 cpu->cd.arm.combination_check = COMBINE(strlen);
2991 dpavlin 20
2992     /* Hm. Does this really increase performance? */
2993 dpavlin 18 if (iword == 0x8afffffa)
2994 dpavlin 20 cpu->cd.arm.combination_check =
2995 dpavlin 22 COMBINE(netbsd_cacheclean2);
2996 dpavlin 14 break;
2997    
2998 dpavlin 20 case 0xc:
2999     case 0xd:
3000     /*
3001     * xxxx1100 0100nnnn ddddcccc oooommmm MCRR c,op,Rd,Rn,CRm
3002     * xxxx1100 0101nnnn ddddcccc oooommmm MRRC c,op,Rd,Rn,CRm
3003     */
3004 dpavlin 22 if ((iword & 0x0fe00fff) == 0x0c400000) {
3005     /* Special case: mar/mra DSP instructions */
3006     fatal("TODO: mar/mra DSP instructions!\n");
3007     /* Perhaps these are actually identical to MCRR/MRRC */
3008     goto bad;
3009     }
3010    
3011 dpavlin 20 if ((iword & 0x0fe00000) == 0x0c400000) {
3012     fatal("MCRR/MRRC: TODO\n");
3013     goto bad;
3014     }
3015    
3016     /*
3017     * TODO: LDC/STC
3018     *
3019     * For now, treat as Undefined instructions. This causes e.g.
3020     * Linux/ARM to emulate these instructions (floating point).
3021     */
3022 dpavlin 22 #if 0
3023 dpavlin 20 ic->f = cond_instr(und);
3024     ic->arg[0] = addr & 0xfff;
3025 dpavlin 22 #else
3026     fatal("LDC/STC: TODO\n");
3027     goto bad;
3028     #endif
3029 dpavlin 20 break;
3030    
3031 dpavlin 14 case 0xe:
3032 dpavlin 22 if ((iword & 0x0ff00ff0) == 0x0e200010) {
3033     /* Special case: mia* DSP instructions */
3034     /* See Intel's 27343601.pdf, page 16-20 */
3035     fatal("TODO: mia* DSP instructions!\n");
3036     goto bad;
3037     }
3038 dpavlin 14 if (iword & 0x10) {
3039     /* xxxx1110 oooLNNNN ddddpppp qqq1MMMM MCR/MRC */
3040     ic->arg[0] = iword;
3041     ic->f = cond_instr(mcr_mrc);
3042     } else {
3043     /* xxxx1110 oooonnnn ddddpppp qqq0mmmm CDP */
3044     ic->arg[0] = iword;
3045     ic->f = cond_instr(cdp);
3046     }
3047 dpavlin 18 if (iword == 0xee070f9a)
3048 dpavlin 20 cpu->cd.arm.combination_check =
3049 dpavlin 22 COMBINE(netbsd_cacheclean);
3050 dpavlin 14 break;
3051    
3052     case 0xf:
3053     /* SWI: */
3054     /* Default handler: */
3055     ic->f = cond_instr(swi);
3056 dpavlin 20 ic->arg[0] = addr & 0xfff;
3057     if (iword == 0xef8c64eb) {
3058     /* Hack for rebooting a machine: */
3059     ic->f = instr(reboot);
3060     } else if (iword == 0xef8c64be) {
3061 dpavlin 14 /* Hack for openfirmware prom emulation: */
3062     ic->f = instr(openfirmware);
3063     } else if (cpu->machine->userland_emul != NULL) {
3064     if ((iword & 0x00f00000) == 0x00a00000) {
3065     ic->arg[0] = iword & 0x00ffffff;
3066     ic->f = cond_instr(swi_useremul);
3067     } else {
3068     fatal("Bad userland SWI?\n");
3069     goto bad;
3070     }
3071     }
3072     break;
3073    
3074     default:goto bad;
3075     }
3076    
3077     okay:
3078    
3079     #define DYNTRANS_TO_BE_TRANSLATED_TAIL
3080     #include "cpu_dyntrans.c"
3081     #undef DYNTRANS_TO_BE_TRANSLATED_TAIL
3082     }
3083    

  ViewVC Help
Powered by ViewVC 1.1.26