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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 32 - (show annotations)
Mon Oct 8 16:20:58 2007 UTC (13 years 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 /*
2 * Copyright (C) 2005-2006 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * $Id: cpu_arm_instr.c,v 1.69 2006/09/09 09:04:32 debug Exp $
29 *
30 * ARM instructions.
31 *
32 * Individual functions should keep track of cpu->n_translated_instrs.
33 * (If no instruction was executed, then it should be decreased. If, say, 4
34 * instructions were combined into one function and executed, then it should
35 * be increased by 3.)
36 *
37 * Note: cpu->pc is prefered over r[ARM_PC]. r[ARM_PC] is only used in a
38 * few places, and should always be kept in synch with the real
39 * program counter.
40 */
41
42
43 /* #define GATHER_BDT_STATISTICS */
44
45
46 #ifdef GATHER_BDT_STATISTICS
47 /*
48 * update_bdt_statistics():
49 *
50 * Gathers statistics about load/store multiple instructions.
51 *
52 * NOTE/TODO: Perhaps it would be more memory efficient to swap the high
53 * and low parts of the instruction word, so that the lllllll bits become
54 * the high bits; this would cause fewer host pages to be used. Anyway, the
55 * current implementation works on hosts with lots of RAM.
56 *
57 * The resulting file, bdt_statistics.txt, should then be processed like
58 * this to give a new cpu_arm_multi.txt:
59 *
60 * uniq -c bdt_statistics.txt|sort -nr|head -256|cut -f 2 > cpu_arm_multi.txt
61 */
62 static void update_bdt_statistics(uint32_t iw)
63 {
64 static FILE *f = NULL;
65 static long long *counts;
66 static char *counts_used;
67 static long long n = 0;
68
69 if (f == NULL) {
70 size_t s = (1 << 24) * sizeof(long long);
71 f = fopen("bdt_statistics.txt", "w");
72 if (f == NULL) {
73 fprintf(stderr, "update_bdt_statistics(): :-(\n");
74 exit(1);
75 }
76 counts = zeroed_alloc(s);
77 counts_used = zeroed_alloc(65536);
78 }
79
80 /* Drop the s-bit: xxxx100P USWLnnnn llllllll llllllll */
81 iw = ((iw & 0x01800000) >> 1) | (iw & 0x003fffff);
82
83 counts_used[iw & 0xffff] = 1;
84 counts[iw] ++;
85
86 n ++;
87 if ((n % 500000) == 0) {
88 int i;
89 long long j;
90 fatal("[ update_bdt_statistics(): n = %lli ]\n", (long long) n);
91 fseek(f, 0, SEEK_SET);
92 for (i=0; i<0x1000000; i++)
93 if (counts_used[i & 0xffff] && counts[i] != 0) {
94 /* Recreate the opcode: */
95 uint32_t opcode = ((i & 0x00c00000) << 1)
96 | (i & 0x003fffff) | 0x08000000;
97 for (j=0; j<counts[i]; j++)
98 fprintf(f, "0x%08x\n", opcode);
99 }
100 fflush(f);
101 }
102 }
103 #endif
104
105
106 /*****************************************************************************/
107
108
109 /*
110 * Helper definitions:
111 *
112 * Each instruction is defined like this:
113 *
114 * X(foo)
115 * {
116 * code for foo;
117 * }
118 * Y(foo)
119 *
120 * The Y macro defines 14 copies of the instruction, one for each possible
121 * condition code. (The NV condition code is not included, and the AL code
122 * uses the main foo function.) Y also defines an array with pointers to
123 * all of these functions.
124 *
125 * If the compiler is good enough (i.e. allows long enough code sequences
126 * to be inlined), then the Y functions will be compiled as full (inlined)
127 * functions, otherwise they will simply call the X function.
128 */
129
130 uint8_t condition_hi[16] = { 0,0,1,1, 0,0,0,0, 0,0,1,1, 0,0,0,0 };
131 uint8_t condition_ge[16] = { 1,0,1,0, 1,0,1,0, 0,1,0,1, 0,1,0,1 };
132 uint8_t condition_gt[16] = { 1,0,1,0, 0,0,0,0, 0,1,0,1, 0,0,0,0 };
133
134 #define Y(n) void arm_instr_ ## n ## __eq(struct cpu *cpu, \
135 struct arm_instr_call *ic) \
136 { if (cpu->cd.arm.flags & ARM_F_Z) \
137 arm_instr_ ## n (cpu, ic); } \
138 void arm_instr_ ## n ## __ne(struct cpu *cpu, \
139 struct arm_instr_call *ic) \
140 { if (!(cpu->cd.arm.flags & ARM_F_Z)) \
141 arm_instr_ ## n (cpu, ic); } \
142 void arm_instr_ ## n ## __cs(struct cpu *cpu, \
143 struct arm_instr_call *ic) \
144 { if (cpu->cd.arm.flags & ARM_F_C) \
145 arm_instr_ ## n (cpu, ic); } \
146 void arm_instr_ ## n ## __cc(struct cpu *cpu, \
147 struct arm_instr_call *ic) \
148 { if (!(cpu->cd.arm.flags & ARM_F_C)) \
149 arm_instr_ ## n (cpu, ic); } \
150 void arm_instr_ ## n ## __mi(struct cpu *cpu, \
151 struct arm_instr_call *ic) \
152 { if (cpu->cd.arm.flags & ARM_F_N) \
153 arm_instr_ ## n (cpu, ic); } \
154 void arm_instr_ ## n ## __pl(struct cpu *cpu, \
155 struct arm_instr_call *ic) \
156 { if (!(cpu->cd.arm.flags & ARM_F_N)) \
157 arm_instr_ ## n (cpu, ic); } \
158 void arm_instr_ ## n ## __vs(struct cpu *cpu, \
159 struct arm_instr_call *ic) \
160 { if (cpu->cd.arm.flags & ARM_F_V) \
161 arm_instr_ ## n (cpu, ic); } \
162 void arm_instr_ ## n ## __vc(struct cpu *cpu, \
163 struct arm_instr_call *ic) \
164 { if (!(cpu->cd.arm.flags & ARM_F_V)) \
165 arm_instr_ ## n (cpu, ic); } \
166 void arm_instr_ ## n ## __hi(struct cpu *cpu, \
167 struct arm_instr_call *ic) \
168 { if (condition_hi[cpu->cd.arm.flags]) \
169 arm_instr_ ## n (cpu, ic); } \
170 void arm_instr_ ## n ## __ls(struct cpu *cpu, \
171 struct arm_instr_call *ic) \
172 { if (!condition_hi[cpu->cd.arm.flags]) \
173 arm_instr_ ## n (cpu, ic); } \
174 void arm_instr_ ## n ## __ge(struct cpu *cpu, \
175 struct arm_instr_call *ic) \
176 { if (condition_ge[cpu->cd.arm.flags]) \
177 arm_instr_ ## n (cpu, ic); } \
178 void arm_instr_ ## n ## __lt(struct cpu *cpu, \
179 struct arm_instr_call *ic) \
180 { if (!condition_ge[cpu->cd.arm.flags]) \
181 arm_instr_ ## n (cpu, ic); } \
182 void arm_instr_ ## n ## __gt(struct cpu *cpu, \
183 struct arm_instr_call *ic) \
184 { if (condition_gt[cpu->cd.arm.flags]) \
185 arm_instr_ ## n (cpu, ic); } \
186 void arm_instr_ ## n ## __le(struct cpu *cpu, \
187 struct arm_instr_call *ic) \
188 { if (!condition_gt[cpu->cd.arm.flags]) \
189 arm_instr_ ## n (cpu, ic); } \
190 void (*arm_cond_instr_ ## n [16])(struct cpu *, \
191 struct arm_instr_call *) = { \
192 arm_instr_ ## n ## __eq, arm_instr_ ## n ## __ne, \
193 arm_instr_ ## n ## __cs, arm_instr_ ## n ## __cc, \
194 arm_instr_ ## n ## __mi, arm_instr_ ## n ## __pl, \
195 arm_instr_ ## n ## __vs, arm_instr_ ## n ## __vc, \
196 arm_instr_ ## n ## __hi, arm_instr_ ## n ## __ls, \
197 arm_instr_ ## n ## __ge, arm_instr_ ## n ## __lt, \
198 arm_instr_ ## n ## __gt, arm_instr_ ## n ## __le, \
199 arm_instr_ ## n , arm_instr_nop };
200
201 #define cond_instr(n) ( arm_cond_instr_ ## n [condition_code] )
202
203
204 /*****************************************************************************/
205
206
207 /*
208 * invalid: Invalid instructions end up here.
209 */
210 X(invalid) {
211 uint32_t low_pc;
212 low_pc = ((size_t)ic - (size_t)
213 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
214 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1)
215 << ARM_INSTR_ALIGNMENT_SHIFT);
216 cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
217
218 fatal("FATAL ERROR: An internal error occured in the ARM"
219 " dyntrans code. Please contact the author with detailed"
220 " repro steps on how to trigger this bug. pc = 0x%08"PRIx32"\n",
221 (uint32_t)cpu->pc);
222
223 cpu->cd.arm.next_ic = &nothing_call;
224 }
225
226
227 /*
228 * nop: Do nothing.
229 */
230 X(nop)
231 {
232 }
233
234
235 /*
236 * b: Branch (to a different translated page)
237 *
238 * arg[0] = relative offset
239 */
240 X(b)
241 {
242 cpu->pc = (uint32_t)((cpu->pc & 0xfffff000) + (int32_t)ic->arg[0]);
243
244 /* Find the new physical page and update the translation pointers: */
245 quick_pc_to_pointers(cpu);
246 }
247 Y(b)
248
249
250 /*
251 * b_samepage: Branch (to within the same translated page)
252 *
253 * arg[0] = pointer to new arm_instr_call
254 * arg[1] = pointer to the next instruction.
255 *
256 * NOTE: This instruction is manually inlined.
257 */
258 X(b_samepage) {
259 cpu->cd.arm.next_ic = (struct arm_instr_call *) ic->arg[0];
260 }
261 X(b_samepage__eq) {
262 cpu->cd.arm.next_ic = (struct arm_instr_call *)
263 ic->arg[cpu->cd.arm.flags & ARM_F_Z? 0 : 1];
264 }
265 X(b_samepage__ne) {
266 cpu->cd.arm.next_ic = (struct arm_instr_call *)
267 ic->arg[cpu->cd.arm.flags & ARM_F_Z? 1 : 0];
268 }
269 X(b_samepage__cs) {
270 cpu->cd.arm.next_ic = (struct arm_instr_call *)
271 ic->arg[cpu->cd.arm.flags & ARM_F_C? 0 : 1];
272 }
273 X(b_samepage__cc) {
274 cpu->cd.arm.next_ic = (struct arm_instr_call *)
275 ic->arg[cpu->cd.arm.flags & ARM_F_C? 1 : 0];
276 }
277 X(b_samepage__mi) {
278 cpu->cd.arm.next_ic = (struct arm_instr_call *)
279 ic->arg[cpu->cd.arm.flags & ARM_F_N? 0 : 1];
280 }
281 X(b_samepage__pl) {
282 cpu->cd.arm.next_ic = (struct arm_instr_call *)
283 ic->arg[cpu->cd.arm.flags & ARM_F_N? 1 : 0];
284 }
285 X(b_samepage__vs) {
286 cpu->cd.arm.next_ic = (struct arm_instr_call *)
287 ic->arg[cpu->cd.arm.flags & ARM_F_V? 0 : 1];
288 }
289 X(b_samepage__vc) {
290 cpu->cd.arm.next_ic = (struct arm_instr_call *)
291 ic->arg[cpu->cd.arm.flags & ARM_F_V? 1 : 0];
292 }
293 X(b_samepage__hi) {
294 cpu->cd.arm.next_ic = (condition_hi[cpu->cd.arm.flags])?
295 (struct arm_instr_call *) ic->arg[0] :
296 (struct arm_instr_call *) ic->arg[1];
297 }
298 X(b_samepage__ls) {
299 cpu->cd.arm.next_ic = (struct arm_instr_call *)
300 ic->arg[condition_hi[cpu->cd.arm.flags]];
301 }
302 X(b_samepage__ge) {
303 cpu->cd.arm.next_ic = (condition_ge[cpu->cd.arm.flags])?
304 (struct arm_instr_call *) ic->arg[0] :
305 (struct arm_instr_call *) ic->arg[1];
306 }
307 X(b_samepage__lt) {
308 cpu->cd.arm.next_ic = (struct arm_instr_call *)
309 ic->arg[condition_ge[cpu->cd.arm.flags]];
310 }
311 X(b_samepage__gt) {
312 cpu->cd.arm.next_ic = (condition_gt[cpu->cd.arm.flags])?
313 (struct arm_instr_call *) ic->arg[0] :
314 (struct arm_instr_call *) ic->arg[1];
315 }
316 X(b_samepage__le) {
317 cpu->cd.arm.next_ic = (struct arm_instr_call *)
318 ic->arg[condition_gt[cpu->cd.arm.flags]];
319 }
320 void (*arm_cond_instr_b_samepage[16])(struct cpu *,
321 struct arm_instr_call *) = {
322 arm_instr_b_samepage__eq, arm_instr_b_samepage__ne,
323 arm_instr_b_samepage__cs, arm_instr_b_samepage__cc,
324 arm_instr_b_samepage__mi, arm_instr_b_samepage__pl,
325 arm_instr_b_samepage__vs, arm_instr_b_samepage__vc,
326 arm_instr_b_samepage__hi, arm_instr_b_samepage__ls,
327 arm_instr_b_samepage__ge, arm_instr_b_samepage__lt,
328 arm_instr_b_samepage__gt, arm_instr_b_samepage__le,
329 arm_instr_b_samepage, arm_instr_nop };
330
331
332 /*
333 * bx: Branch, potentially exchanging Thumb/ARM encoding
334 *
335 * arg[0] = ptr to rm
336 */
337 X(bx)
338 {
339 cpu->pc = reg(ic->arg[0]);
340 if (cpu->pc & 1) {
341 fatal("thumb: TODO\n");
342 exit(1);
343 }
344 cpu->pc &= ~3;
345
346 /* Find the new physical page and update the translation pointers: */
347 quick_pc_to_pointers(cpu);
348 }
349 Y(bx)
350
351
352 /*
353 * bx_trace: As bx, but with trace enabled, arg[0] = the link register.
354 *
355 * arg[0] = ignored
356 */
357 X(bx_trace)
358 {
359 cpu->pc = cpu->cd.arm.r[ARM_LR];
360 if (cpu->pc & 1) {
361 fatal("thumb: TODO\n");
362 exit(1);
363 }
364 cpu->pc &= ~3;
365
366 cpu_functioncall_trace_return(cpu);
367
368 /* Find the new physical page and update the translation pointers: */
369 quick_pc_to_pointers(cpu);
370 }
371 Y(bx_trace)
372
373
374 /*
375 * bl: Branch and Link (to a different translated page)
376 *
377 * arg[0] = relative address
378 */
379 X(bl)
380 {
381 uint32_t pc = ((uint32_t)cpu->pc & 0xfffff000) + (int32_t)ic->arg[1];
382 cpu->cd.arm.r[ARM_LR] = pc + 4;
383
384 /* Calculate new PC from this instruction + arg[0] */
385 cpu->pc = pc + (int32_t)ic->arg[0];
386
387 /* Find the new physical page and update the translation pointers: */
388 quick_pc_to_pointers(cpu);
389 }
390 Y(bl)
391
392
393 /*
394 * blx: Branch and Link, potentially exchanging Thumb/ARM encoding
395 *
396 * arg[0] = ptr to rm
397 */
398 X(blx)
399 {
400 uint32_t lr = ((uint32_t)cpu->pc & 0xfffff000) + (int32_t)ic->arg[2];
401 cpu->cd.arm.r[ARM_LR] = lr;
402 cpu->pc = reg(ic->arg[0]);
403 if (cpu->pc & 1) {
404 fatal("thumb: TODO\n");
405 exit(1);
406 }
407 cpu->pc &= ~3;
408
409 /* Find the new physical page and update the translation pointers: */
410 quick_pc_to_pointers(cpu);
411 }
412 Y(blx)
413
414
415 /*
416 * bl_trace: Branch and Link (to a different translated page), with trace
417 *
418 * Same as for bl.
419 */
420 X(bl_trace)
421 {
422 uint32_t pc = ((uint32_t)cpu->pc & 0xfffff000) + (int32_t)ic->arg[1];
423 cpu->cd.arm.r[ARM_LR] = pc + 4;
424
425 /* Calculate new PC from this instruction + arg[0] */
426 cpu->pc = pc + (int32_t)ic->arg[0];
427
428 cpu_functioncall_trace(cpu, cpu->pc);
429
430 /* Find the new physical page and update the translation pointers: */
431 quick_pc_to_pointers(cpu);
432 }
433 Y(bl_trace)
434
435
436 /*
437 * bl_samepage: A branch + link within the same page
438 *
439 * arg[0] = pointer to new arm_instr_call
440 */
441 X(bl_samepage)
442 {
443 cpu->cd.arm.r[ARM_LR] =
444 ((uint32_t)cpu->pc & 0xfffff000) + (int32_t)ic->arg[2];
445 cpu->cd.arm.next_ic = (struct arm_instr_call *) ic->arg[0];
446 }
447 Y(bl_samepage)
448
449
450 /*
451 * bl_samepage_trace: Branch and Link (to the same page), with trace
452 *
453 * Same as for bl_samepage.
454 */
455 X(bl_samepage_trace)
456 {
457 uint32_t low_pc, lr = (cpu->pc & 0xfffff000) + ic->arg[2];
458
459 /* Link and branch: */
460 cpu->cd.arm.r[ARM_LR] = lr;
461 cpu->cd.arm.next_ic = (struct arm_instr_call *) ic->arg[0];
462
463 /* Synchronize the program counter: */
464 low_pc = ((size_t)cpu->cd.arm.next_ic - (size_t)
465 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
466 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1)
467 << ARM_INSTR_ALIGNMENT_SHIFT);
468 cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
469
470 /* ... and show trace: */
471 cpu_functioncall_trace(cpu, cpu->pc);
472 }
473 Y(bl_samepage_trace)
474
475
476 /*
477 * clz: Count leading zeroes.
478 *
479 * arg[0] = ptr to rm
480 * arg[1] = ptr to rd
481 */
482 X(clz)
483 {
484 uint32_t rm = reg(ic->arg[0]);
485 int i = 32, n = 0, j;
486 while (i>0) {
487 if (rm & 0xff000000) {
488 for (j=0; j<8; j++) {
489 if (rm & 0x80000000)
490 break;
491 n ++;
492 rm <<= 1;
493 }
494 break;
495 } else {
496 rm <<= 8;
497 i -= 8;
498 n += 8;
499 }
500 }
501 reg(ic->arg[1]) = n;
502 }
503 Y(clz)
504
505
506 /*
507 * mul: Multiplication
508 *
509 * arg[0] = ptr to rd
510 * arg[1] = ptr to rm
511 * arg[2] = ptr to rs
512 */
513 X(mul)
514 {
515 reg(ic->arg[0]) = reg(ic->arg[1]) * reg(ic->arg[2]);
516 }
517 Y(mul)
518 X(muls)
519 {
520 uint32_t result;
521 result = reg(ic->arg[1]) * reg(ic->arg[2]);
522 cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N);
523 if (result == 0)
524 cpu->cd.arm.flags |= ARM_F_Z;
525 if (result & 0x80000000)
526 cpu->cd.arm.flags |= ARM_F_N;
527 reg(ic->arg[0]) = result;
528 }
529 Y(muls)
530
531
532 /*
533 * mla: Multiplication with addition
534 *
535 * arg[0] = copy of instruction word
536 */
537 X(mla)
538 {
539 /* xxxx0000 00ASdddd nnnnssss 1001mmmm (Rd,Rm,Rs[,Rn]) */
540 uint32_t iw = ic->arg[0];
541 int rd, rs, rn, rm;
542 rd = (iw >> 16) & 15; rn = (iw >> 12) & 15,
543 rs = (iw >> 8) & 15; rm = iw & 15;
544 cpu->cd.arm.r[rd] = cpu->cd.arm.r[rm] * cpu->cd.arm.r[rs]
545 + cpu->cd.arm.r[rn];
546 }
547 Y(mla)
548 X(mlas)
549 {
550 /* xxxx0000 00ASdddd nnnnssss 1001mmmm (Rd,Rm,Rs[,Rn]) */
551 uint32_t iw = ic->arg[0];
552 int rd, rs, rn, rm;
553 rd = (iw >> 16) & 15; rn = (iw >> 12) & 15,
554 rs = (iw >> 8) & 15; rm = iw & 15;
555 cpu->cd.arm.r[rd] = cpu->cd.arm.r[rm] * cpu->cd.arm.r[rs]
556 + cpu->cd.arm.r[rn];
557 cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N);
558 if (cpu->cd.arm.r[rd] == 0)
559 cpu->cd.arm.flags |= ARM_F_Z;
560 if (cpu->cd.arm.r[rd] & 0x80000000)
561 cpu->cd.arm.flags |= ARM_F_N;
562 }
563 Y(mlas)
564
565
566 /*
567 * mull: Long multiplication
568 *
569 * arg[0] = copy of instruction word
570 */
571 X(mull)
572 {
573 /* xxxx0000 1UAShhhh llllssss 1001mmmm */
574 uint32_t iw; uint64_t tmp; int u_bit, a_bit;
575 iw = ic->arg[0];
576 u_bit = iw & 0x00400000; a_bit = iw & 0x00200000;
577 tmp = cpu->cd.arm.r[iw & 15];
578 if (u_bit)
579 tmp = (int64_t)(int32_t)tmp
580 * (int64_t)(int32_t)cpu->cd.arm.r[(iw >> 8) & 15];
581 else
582 tmp *= (uint64_t)cpu->cd.arm.r[(iw >> 8) & 15];
583 if (a_bit) {
584 uint64_t x = ((uint64_t)cpu->cd.arm.r[(iw >> 16) & 15] << 32)
585 | cpu->cd.arm.r[(iw >> 12) & 15];
586 x += tmp;
587 cpu->cd.arm.r[(iw >> 16) & 15] = (x >> 32);
588 cpu->cd.arm.r[(iw >> 12) & 15] = x;
589 } else {
590 cpu->cd.arm.r[(iw >> 16) & 15] = (tmp >> 32);
591 cpu->cd.arm.r[(iw >> 12) & 15] = tmp;
592 }
593 }
594 Y(mull)
595
596
597 /*
598 * smulXY: 16-bit * 16-bit multiplication (32-bit result)
599 *
600 * arg[0] = ptr to rm
601 * arg[1] = ptr to rs
602 * arg[2] = ptr to rd
603 */
604 X(smulbb)
605 {
606 reg(ic->arg[2]) = (int32_t)(int16_t)reg(ic->arg[0]) *
607 (int32_t)(int16_t)reg(ic->arg[1]);
608 }
609 Y(smulbb)
610 X(smultb)
611 {
612 reg(ic->arg[2]) = (int32_t)(int16_t)(reg(ic->arg[0]) >> 16) *
613 (int32_t)(int16_t)reg(ic->arg[1]);
614 }
615 Y(smultb)
616 X(smulbt)
617 {
618 reg(ic->arg[2]) = (int32_t)(int16_t)reg(ic->arg[0]) *
619 (int32_t)(int16_t)(reg(ic->arg[1]) >> 16);
620 }
621 Y(smulbt)
622 X(smultt)
623 {
624 reg(ic->arg[2]) = (int32_t)(int16_t)(reg(ic->arg[0]) >> 16) *
625 (int32_t)(int16_t)(reg(ic->arg[1]) >> 16);
626 }
627 Y(smultt)
628
629
630 /*
631 * mov_reg_reg: Move a register to another.
632 *
633 * arg[0] = ptr to source register
634 * arg[1] = ptr to destination register
635 */
636 X(mov_reg_reg)
637 {
638 reg(ic->arg[1]) = reg(ic->arg[0]);
639 }
640 Y(mov_reg_reg)
641
642
643 /*
644 * mov_reg_pc: Move the PC register to a normal register.
645 *
646 * arg[0] = offset compared to start of current page + 8
647 * arg[1] = ptr to destination register
648 */
649 X(mov_reg_pc)
650 {
651 reg(ic->arg[1]) = ((uint32_t)cpu->pc&0xfffff000) + (int32_t)ic->arg[0];
652 }
653 Y(mov_reg_pc)
654
655
656 /*
657 * ret_trace: "mov pc,lr" with trace enabled
658 * ret: "mov pc,lr" without trace enabled
659 *
660 * arg[0] = ignored
661 */
662 X(ret_trace)
663 {
664 uint32_t old_pc, mask_within_page;
665 old_pc = cpu->pc;
666 mask_within_page = ((ARM_IC_ENTRIES_PER_PAGE-1)
667 << ARM_INSTR_ALIGNMENT_SHIFT) |
668 ((1 << ARM_INSTR_ALIGNMENT_SHIFT) - 1);
669
670 /* Update the PC register: */
671 cpu->pc = cpu->cd.arm.r[ARM_LR];
672
673 cpu_functioncall_trace_return(cpu);
674
675 /*
676 * Is this a return to code within the same page? Then there is no
677 * need to update all pointers, just next_ic.
678 */
679 if ((old_pc & ~mask_within_page) == (cpu->pc & ~mask_within_page)) {
680 cpu->cd.arm.next_ic = cpu->cd.arm.cur_ic_page +
681 ((cpu->pc & mask_within_page) >> ARM_INSTR_ALIGNMENT_SHIFT);
682 } else {
683 /* Find the new physical page and update pointers: */
684 quick_pc_to_pointers(cpu);
685 }
686 }
687 Y(ret_trace)
688 X(ret)
689 {
690 cpu->pc = cpu->cd.arm.r[ARM_LR];
691 quick_pc_to_pointers(cpu);
692 }
693 Y(ret)
694
695
696 /*
697 * msr: Move to status register from a normal register or immediate value.
698 *
699 * arg[0] = immediate value
700 * arg[1] = mask
701 * arg[2] = pointer to rm
702 *
703 * msr_imm and msr_imm_spsr use arg[1] and arg[0].
704 * msr and msr_spsr use arg[1] and arg[2].
705 */
706 X(msr_imm)
707 {
708 uint32_t mask = ic->arg[1];
709 int switch_register_banks = (mask & ARM_FLAG_MODE) &&
710 ((cpu->cd.arm.cpsr & ARM_FLAG_MODE) !=
711 (ic->arg[0] & ARM_FLAG_MODE));
712 uint32_t new_value = ic->arg[0];
713
714 cpu->cd.arm.cpsr &= 0x0fffffff;
715 cpu->cd.arm.cpsr |= (cpu->cd.arm.flags << 28);
716
717 if (switch_register_banks)
718 arm_save_register_bank(cpu);
719
720 cpu->cd.arm.cpsr &= ~mask;
721 cpu->cd.arm.cpsr |= (new_value & mask);
722
723 cpu->cd.arm.flags = cpu->cd.arm.cpsr >> 28;
724
725 if (switch_register_banks)
726 arm_load_register_bank(cpu);
727 }
728 Y(msr_imm)
729 X(msr)
730 {
731 ic->arg[0] = reg(ic->arg[2]);
732 instr(msr_imm)(cpu, ic);
733 }
734 Y(msr)
735 X(msr_imm_spsr)
736 {
737 uint32_t mask = ic->arg[1];
738 uint32_t new_value = ic->arg[0];
739 switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) {
740 case ARM_MODE_FIQ32:
741 cpu->cd.arm.spsr_fiq &= ~mask;
742 cpu->cd.arm.spsr_fiq |= (new_value & mask);
743 break;
744 case ARM_MODE_ABT32:
745 cpu->cd.arm.spsr_abt &= ~mask;
746 cpu->cd.arm.spsr_abt |= (new_value & mask);
747 break;
748 case ARM_MODE_UND32:
749 cpu->cd.arm.spsr_und &= ~mask;
750 cpu->cd.arm.spsr_und |= (new_value & mask);
751 break;
752 case ARM_MODE_IRQ32:
753 cpu->cd.arm.spsr_irq &= ~mask;
754 cpu->cd.arm.spsr_irq |= (new_value & mask);
755 break;
756 case ARM_MODE_SVC32:
757 cpu->cd.arm.spsr_svc &= ~mask;
758 cpu->cd.arm.spsr_svc |= (new_value & mask);
759 break;
760 default:fatal("msr_spsr: unimplemented mode %i\n",
761 cpu->cd.arm.cpsr & ARM_FLAG_MODE);
762 {
763 /* Synchronize the program counter: */
764 uint32_t old_pc, low_pc = ((size_t)ic - (size_t)
765 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
766 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
767 cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
768 old_pc = cpu->pc;
769 printf("msr_spsr: old pc = 0x%08"PRIx32"\n", old_pc);
770 }
771 exit(1);
772 }
773 }
774 Y(msr_imm_spsr)
775 X(msr_spsr)
776 {
777 ic->arg[0] = reg(ic->arg[2]);
778 instr(msr_imm_spsr)(cpu, ic);
779 }
780 Y(msr_spsr)
781
782
783 /*
784 * mrs: Move from status/flag register to a normal register.
785 *
786 * arg[0] = pointer to rd
787 */
788 X(mrs)
789 {
790 cpu->cd.arm.cpsr &= 0x0fffffff;
791 cpu->cd.arm.cpsr |= (cpu->cd.arm.flags << 28);
792 reg(ic->arg[0]) = cpu->cd.arm.cpsr;
793 }
794 Y(mrs)
795
796
797 /*
798 * mrs: Move from saved status/flag register to a normal register.
799 *
800 * arg[0] = pointer to rd
801 */
802 X(mrs_spsr)
803 {
804 switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) {
805 case ARM_MODE_FIQ32: reg(ic->arg[0]) = cpu->cd.arm.spsr_fiq; break;
806 case ARM_MODE_ABT32: reg(ic->arg[0]) = cpu->cd.arm.spsr_abt; break;
807 case ARM_MODE_UND32: reg(ic->arg[0]) = cpu->cd.arm.spsr_und; break;
808 case ARM_MODE_IRQ32: reg(ic->arg[0]) = cpu->cd.arm.spsr_irq; break;
809 case ARM_MODE_SVC32: reg(ic->arg[0]) = cpu->cd.arm.spsr_svc; break;
810 case ARM_MODE_USR32:
811 case ARM_MODE_SYS32: reg(ic->arg[0]) = 0; break;
812 default:fatal("mrs_spsr: unimplemented mode %i\n",
813 cpu->cd.arm.cpsr & ARM_FLAG_MODE);
814 exit(1);
815 }
816 }
817 Y(mrs_spsr)
818
819
820 /*
821 * mcr_mrc: Coprocessor move
822 * cdp: Coprocessor operation
823 *
824 * arg[0] = copy of the instruction word
825 */
826 X(mcr_mrc) {
827 uint32_t low_pc = ((size_t)ic - (size_t)
828 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
829 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
830 cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
831 arm_mcr_mrc(cpu, ic->arg[0]);
832 }
833 Y(mcr_mrc)
834 X(cdp) {
835 uint32_t low_pc = ((size_t)ic - (size_t)
836 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
837 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
838 cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
839 arm_cdp(cpu, ic->arg[0]);
840 }
841 Y(cdp)
842
843
844 /*
845 * openfirmware:
846 */
847 X(openfirmware)
848 {
849 /* TODO: sync pc? */
850 of_emul(cpu);
851 cpu->pc = cpu->cd.arm.r[ARM_LR];
852 if (cpu->machine->show_trace_tree)
853 cpu_functioncall_trace_return(cpu);
854 quick_pc_to_pointers(cpu);
855 }
856
857
858 /*
859 * reboot:
860 */
861 X(reboot)
862 {
863 cpu->running = 0;
864 cpu->n_translated_instrs --;
865 cpu->cd.arm.next_ic = &nothing_call;
866 }
867
868
869 /*
870 * swi_useremul: Syscall.
871 *
872 * arg[0] = swi number
873 */
874 X(swi_useremul)
875 {
876 /* Synchronize the program counter: */
877 uint32_t old_pc, low_pc = ((size_t)ic - (size_t)
878 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
879 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1)
880 << ARM_INSTR_ALIGNMENT_SHIFT);
881 cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
882 old_pc = cpu->pc;
883
884 useremul_syscall(cpu, ic->arg[0]);
885
886 if (!cpu->running) {
887 cpu->n_translated_instrs --;
888 cpu->cd.arm.next_ic = &nothing_call;
889 } else if (cpu->pc != old_pc) {
890 /* PC was changed by the SWI call. Find the new physical
891 page and update the translation pointers: */
892 quick_pc_to_pointers(cpu);
893 }
894 }
895 Y(swi_useremul)
896
897
898 /*
899 * swi: Software interrupt.
900 */
901 X(swi)
902 {
903 /* Synchronize the program counter first: */
904 cpu->pc &= 0xfffff000;
905 cpu->pc += ic->arg[0];
906 arm_exception(cpu, ARM_EXCEPTION_SWI);
907 }
908 Y(swi)
909
910
911 /*
912 * und: Undefined instruction.
913 */
914 X(und)
915 {
916 /* Synchronize the program counter first: */
917 cpu->pc &= 0xfffff000;
918 cpu->pc += ic->arg[0];
919 arm_exception(cpu, ARM_EXCEPTION_UND);
920 }
921 Y(und)
922
923
924 /*
925 * swp, swpb: Swap (word or byte).
926 *
927 * arg[0] = ptr to rd
928 * arg[1] = ptr to rm
929 * arg[2] = ptr to rn
930 */
931 X(swp)
932 {
933 uint32_t addr = reg(ic->arg[2]), data, data2;
934 unsigned char d[4];
935
936 /* Synchronize the program counter: */
937 uint32_t low_pc = ((size_t)ic - (size_t)
938 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
939 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
940 cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
941
942 if (!cpu->memory_rw(cpu, cpu->mem, addr, d, sizeof(d), MEM_READ,
943 CACHE_DATA)) {
944 fatal("swp: load failed\n");
945 return;
946 }
947 data = d[0] + (d[1] << 8) + (d[2] << 16) + (d[3] << 24);
948 data2 = reg(ic->arg[1]);
949 d[0] = data2; d[1] = data2 >> 8; d[2] = data2 >> 16; d[3] = data2 >> 24;
950 if (!cpu->memory_rw(cpu, cpu->mem, addr, d, sizeof(d), MEM_WRITE,
951 CACHE_DATA)) {
952 fatal("swp: store failed\n");
953 return;
954 }
955 reg(ic->arg[0]) = data;
956 }
957 Y(swp)
958 X(swpb)
959 {
960 uint32_t addr = reg(ic->arg[2]), data;
961 unsigned char d[1];
962
963 /* Synchronize the program counter: */
964 uint32_t low_pc = ((size_t)ic - (size_t)
965 cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
966 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
967 cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
968
969 if (!cpu->memory_rw(cpu, cpu->mem, addr, d, sizeof(d), MEM_READ,
970 CACHE_DATA)) {
971 fatal("swp: load failed\n");
972 return;
973 }
974 data = d[0];
975 d[0] = reg(ic->arg[1]);
976 if (!cpu->memory_rw(cpu, cpu->mem, addr, d, sizeof(d), MEM_WRITE,
977 CACHE_DATA)) {
978 fatal("swp: store failed\n");
979 return;
980 }
981 reg(ic->arg[0]) = data;
982 }
983 Y(swpb)
984
985
986 extern void (*arm_load_store_instr[1024])(struct cpu *,
987 struct arm_instr_call *);
988 X(store_w1_word_u1_p0_imm);
989 X(store_w0_byte_u1_p0_imm);
990 X(store_w0_word_u1_p0_imm);
991 X(store_w0_word_u1_p1_imm);
992 X(load_w1_word_u1_p0_imm);
993 X(load_w0_word_u1_p0_imm);
994 X(load_w0_byte_u1_p1_imm);
995 X(load_w0_byte_u1_p1_reg);
996 X(load_w1_byte_u1_p1_imm);
997
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 extern uint32_t (*arm_r[8192])(struct cpu *, struct arm_instr_call *);
1008 extern void arm_r_r3_t0_c0(void);
1009
1010 extern void (*arm_dpi_instr[2 * 2 * 2 * 16 * 16])(struct cpu *,
1011 struct arm_instr_call *);
1012 extern void (*arm_dpi_instr_regshort[2 * 16 * 16])(struct cpu *,
1013 struct arm_instr_call *);
1014 X(cmps);
1015 X(teqs);
1016 X(tsts);
1017 X(sub);
1018 X(add);
1019 X(subs);
1020 X(eor_regshort);
1021 X(cmps_regshort);
1022
1023
1024 #include "cpu_arm_instr_misc.c"
1025
1026
1027 /*
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 int i, return_flag = 0;
1045 uint32_t new_values[16];
1046
1047 #ifdef GATHER_BDT_STATISTICS
1048 if (!s_bit)
1049 update_bdt_statistics(iw);
1050 #endif
1051
1052 /* 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 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
1056 cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
1057
1058 if (s_bit) {
1059 /* Load to USR registers: */
1060 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 }
1064 if (iw & 0x8000) {
1065 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 switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) {
1137 case ARM_MODE_USR32:
1138 case ARM_MODE_SYS32:
1139 cpu->cd.arm.r[i] = new_values[i];
1140 break;
1141 case ARM_MODE_FIQ32:
1142 if (i >= 8 && i <= 14)
1143 cpu->cd.arm.default_r8_r14[i-8] =
1144 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 case ARM_MODE_IRQ32:
1152 if (i >= 13 && i <= 14)
1153 cpu->cd.arm.default_r8_r14[i-8] =
1154 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 cpu->cd.arm.flags = cpu->cd.arm.cpsr >> 28;
1193
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 cpu->pc = cpu->cd.arm.r[ARM_PC] & 0xfffffffc;
1201 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 quick_pc_to_pointers(cpu);
1209 }
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 int i;
1232
1233 #ifdef GATHER_BDT_STATISTICS
1234 if (!s_bit)
1235 update_bdt_statistics(iw);
1236 #endif
1237
1238 /* 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 cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
1242 cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
1243
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 switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) {
1254 case ARM_MODE_FIQ32:
1255 if (i >= 8 && i <= 14)
1256 value = cpu->cd.arm.default_r8_r14[i-8];
1257 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 value = cpu->cd.arm.default_r8_r14[i-8];
1264 break;
1265 case ARM_MODE_USR32:
1266 case ARM_MODE_SYS32:
1267 break;
1268 }
1269 }
1270
1271 /* NOTE/TODO: 8 vs 12 on some ARMs */
1272 if (i == ARM_PC)
1273 value = cpu->pc + 12;
1274
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 /* Various load/store multiple instructions: */
1331 extern uint32_t *multi_opcode[256];
1332 extern void (**multi_opcode_f[256])(struct cpu *, struct arm_instr_call *);
1333 X(multi_0x08b15018);
1334 X(multi_0x08ac000c__ge);
1335 X(multi_0x08a05018);
1336
1337
1338 /*****************************************************************************/
1339
1340
1341 /*
1342 * 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 if (((cpu->cd.arm.flags & ARM_F_N)?1:0) !=
1362 ((cpu->cd.arm.flags & ARM_F_V)?1:0)) {
1363 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 } 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
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 } while (((cpu->cd.arm.flags & ARM_F_N)?1:0) ==
1452 ((cpu->cd.arm.flags & ARM_F_V)?1:0));
1453
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 cpu->cd.arm.r[0] += r1;
1475 cpu->cd.arm.r[1] = 0;
1476 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 cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N);
1528 if (t == 0)
1529 cpu->cd.arm.flags |= ARM_F_Z;
1530
1531 cpu->n_translated_instrs += 2;
1532 cpu->cd.arm.next_ic = &ic[3];
1533 }
1534
1535
1536 /*
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 /*****************************************************************************/
2013
2014
2015 X(end_of_page)
2016 {
2017 /* Update the PC: (offset 0, but on the next page) */
2018 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
2021 /* Find the new physical page and update the translation pointers: */
2022 quick_pc_to_pointers(cpu);
2023
2024 /* end_of_page doesn't count as an executed instruction: */
2025 cpu->n_translated_instrs --;
2026 }
2027
2028
2029 /*****************************************************************************/
2030
2031
2032 /*
2033 * Combine: netbsd_memset():
2034 *
2035 * 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 */
2038 void COMBINE(netbsd_memset)(struct cpu *cpu,
2039 struct arm_instr_call *ic, int low_addr)
2040 {
2041 #ifdef HOST_LITTLE_ENDIAN
2042 int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2043 & (ARM_IC_ENTRIES_PER_PAGE-1);
2044
2045 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 #endif
2058 }
2059
2060
2061 /*
2062 * Combine: netbsd_memcpy():
2063 *
2064 * Check for the core of a NetBSD/arm memcpy; large memcpys use a
2065 * sequence of ldmia instructions.
2066 */
2067 void COMBINE(netbsd_memcpy)(struct cpu *cpu, struct arm_instr_call *ic,
2068 int low_addr)
2069 {
2070 #ifdef HOST_LITTLE_ENDIAN
2071 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 #endif
2087 }
2088
2089
2090 /*
2091 * Combine: netbsd_cacheclean():
2092 *
2093 * Check for the core of a NetBSD/arm cache clean. (There are two variants.)
2094 */
2095 void COMBINE(netbsd_cacheclean)(struct cpu *cpu,
2096 struct arm_instr_call *ic, int low_addr)
2097 {
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 * Combine: netbsd_cacheclean2():
2115 *
2116 * Check for the core of a NetBSD/arm cache clean. (Second variant.)
2117 */
2118 void COMBINE(netbsd_cacheclean2)(struct cpu *cpu,
2119 struct arm_instr_call *ic, int low_addr)
2120 {
2121 int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2122 & (ARM_IC_ENTRIES_PER_PAGE-1);
2123
2124 if (n_back >= 4) {
2125 if (ic[-4].f == instr(mcr_mrc) && ic[-4].arg[0] == 0xee070f3a &&
2126 ic[-3].f == instr(mcr_mrc) && ic[-3].arg[0] == 0xee070f36 &&
2127 ic[-2].f == instr(add) &&
2128 ic[-2].arg[0]==ic[-2].arg[2] && ic[-2].arg[1] == 0x20 &&
2129 ic[-1].f == instr(subs) &&
2130 ic[-1].arg[0]==ic[-1].arg[2] && ic[-1].arg[1] == 0x20) {
2131 ic[-4].f = instr(netbsd_cacheclean2);
2132 }
2133 }
2134 }
2135
2136
2137 /*
2138 * Combine: netbsd_scanc():
2139 */
2140 void COMBINE(netbsd_scanc)(struct cpu *cpu,
2141 struct arm_instr_call *ic, int low_addr)
2142 {
2143 int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2144 & (ARM_IC_ENTRIES_PER_PAGE-1);
2145
2146 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 }
2159 }
2160
2161
2162 /*
2163 * Combine: strlen():
2164 */
2165 void COMBINE(strlen)(struct cpu *cpu,
2166 struct arm_instr_call *ic, int low_addr)
2167 {
2168 int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2169 & (ARM_IC_ENTRIES_PER_PAGE-1);
2170
2171 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 }
2182 }
2183
2184
2185 /*
2186 * Combine: xchg():
2187 */
2188 void COMBINE(xchg)(struct cpu *cpu,
2189 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
2195 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 * Combine: netbsd_copyin():
2212 */
2213 void COMBINE(netbsd_copyin)(struct cpu *cpu,
2214 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 * Combine: netbsd_copyout():
2243 */
2244 void COMBINE(netbsd_copyout)(struct cpu *cpu,
2245 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 * Combine: cmps_b():
2274 */
2275 void COMBINE(cmps_b)(struct cpu *cpu,
2276 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 }
2291 return;
2292 }
2293 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
2357
2358 /*****************************************************************************/
2359
2360
2361 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 /*
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 int p_bit, u_bit, w_bit, l_bit, regform, rm, c, t, any_pc_reg;
2448 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 addr = cpu->pc & ~((ARM_IC_ENTRIES_PER_PAGE-1) <<
2454 ARM_INSTR_ALIGNMENT_SHIFT);
2455 addr += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
2456 cpu->pc = addr;
2457 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 /* fatal("TRANSLATION HIT! 0x%08x\n", addr); */
2463 memcpy(ib, page + (addr & 0xfff), sizeof(ib));
2464 } else {
2465 /* fatal("TRANSLATION MISS! 0x%08x\n", addr); */
2466 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 return;
2471 }
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 u_bit = iword & 0x00800000;
2491 w_bit = iword & 0x00200000;
2492 s_bit = l_bit = iword & 0x00100000;
2493 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 if ((iword & 0x0f900ff0) == 0x01000050) {
2558 fatal("TODO: q{,d}{add,sub}\n");
2559 goto bad;
2560 }
2561 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 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 /* 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 }
2616 if ((iword & 0x0ff0f0b0) == 0x012000a0) {
2617 /* TODO: smulwY */
2618 goto bad;
2619 }
2620 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 if (rm == ARM_PC) {
2631 fatal("msr PC?\n");
2632 goto bad;
2633 }
2634 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 ic->arg[1] = (size_t)(void *)arm_r[iword & 0xf];
2696 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 /* "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 break;
2713 }
2714
2715 /* "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 ic->arg[1] = (size_t)(&cpu->cd.arm.r[rd]);
2725 break;
2726 }
2727
2728 /* "mov reg,#0": */
2729 if ((iword & 0x0fff0fff) == 0x03a00000 && rd != ARM_PC) {
2730 arm_switch_clear(ic, rd, condition_code);
2731 break;
2732 }
2733
2734 /* "mov reg,#1": */
2735 if ((iword & 0x0fff0fff) == 0x03a00001 && rd != ARM_PC) {
2736 arm_switch_mov1(ic, rd, condition_code);
2737 break;
2738 }
2739
2740 /* "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 /*
2748 * Generic Data Processing Instructions:
2749 */
2750 if ((main_opcode & 2) == 0)
2751 regform = 1;
2752 else
2753 regform = 0;
2754
2755 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 imm = iword & 0xff;
2769 while (r8-- > 0)
2770 imm = (imm >> 2) | ((imm & 3) << 30);
2771 ic->arg[1] = imm;
2772 }
2773
2774 /* mvn #imm ==> mov #~imm */
2775 if (secondary_opcode == 0xf && !regform) {
2776 secondary_opcode = 0xd;
2777 ic->arg[1] = ~ic->arg[1];
2778 }
2779
2780 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 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
2795 if (ic->f == instr(eor_regshort))
2796 cpu->cd.arm.combination_check = COMBINE(xchg);
2797 if (iword == 0xe113000c)
2798 cpu->cd.arm.combination_check = COMBINE(netbsd_scanc);
2799 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 ic->arg[1] = (size_t)(void *)arm_r[iword & 0xfff];
2823 if ((iword & 0x0e000010) == 0x06000010) {
2824 fatal("Not a Load/store TODO\n");
2825 goto bad;
2826 }
2827 /* 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 cpu->cd.arm.combination_check = COMBINE(netbsd_copyin);
2871 if (iword == 0xe4a17004)
2872 cpu->cd.arm.combination_check = COMBINE(netbsd_copyout);
2873 break;
2874
2875 case 0x8: /* Multiple load/store... (Block data transfer) */
2876 case 0x9: /* xxxx100P USWLnnnn llllllll llllllll */
2877 ic->arg[0] = (size_t)(&cpu->cd.arm.r[rn]);
2878 ic->arg[1] = (size_t)iword;
2879 /* Generic case: */
2880 if (l_bit)
2881 ic->f = cond_instr(bdt_load);
2882 else
2883 ic->f = cond_instr(bdt_store);
2884 #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 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 if (iword == 0xcaffffed)
2924 cpu->cd.arm.combination_check =
2925 COMBINE(netbsd_memset);
2926 if (iword == 0xaafffff9)
2927 cpu->cd.arm.combination_check =
2928 COMBINE(netbsd_memcpy);
2929 } 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 /* 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 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 /*
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 {
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 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 }
2982 }
2983
2984 if (main_opcode == 0xa && (condition_code <= 1
2985 || condition_code == 3 || condition_code == 8
2986 || condition_code == 12 || condition_code == 13))
2987 cpu->cd.arm.combination_check = COMBINE(cmps_b);
2988
2989 if (iword == 0x1afffffc)
2990 cpu->cd.arm.combination_check = COMBINE(strlen);
2991
2992 /* Hm. Does this really increase performance? */
2993 if (iword == 0x8afffffa)
2994 cpu->cd.arm.combination_check =
2995 COMBINE(netbsd_cacheclean2);
2996 break;
2997
2998 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 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 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 #if 0
3023 ic->f = cond_instr(und);
3024 ic->arg[0] = addr & 0xfff;
3025 #else
3026 fatal("LDC/STC: TODO\n");
3027 goto bad;
3028 #endif
3029 break;
3030
3031 case 0xe:
3032 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 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 if (iword == 0xee070f9a)
3048 cpu->cd.arm.combination_check =
3049 COMBINE(netbsd_cacheclean);
3050 break;
3051
3052 case 0xf:
3053 /* SWI: */
3054 /* Default handler: */
3055 ic->f = cond_instr(swi);
3056 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 /* 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