/[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 20 - (show annotations)
Mon Oct 8 16:19:23 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 78511 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1055 2005/11/25 22:48:36 debug Exp $
20051031	Adding disassembly support for more ARM instructions (clz,
		smul* etc), and adding a hack to support "new tiny" pages
		for StrongARM.
20051101	Minor documentation updates (NetBSD 2.0.2 -> 2.1, and OpenBSD
		3.7 -> 3.8, and lots of testing).
		Changing from 1-sector PIO mode 0 transfers to 128-sector PIO
		mode 3 (in dev_wdc).
		Various minor ARM dyntrans updates (pc-relative loads from
		within the same page as the instruction are now treated as
		constant "mov").
20051102	Re-enabling instruction combinations (they were accidentally
		disabled).
		Dyntrans TLB entries are now overwritten using a round-robin
		scheme instead of randomly. This increases performance.
		Fixing a typo in file.c (thanks to Chuan-Hua Chang for
		noticing it).
		Experimenting with adding ATAPI support to dev_wdc (to make
		emulated *BSD detect cdroms as cdroms, not harddisks).
20051104	Various minor updates.
20051105	Continuing on the ATAPI emulation. Seems to work well enough
		for a NetBSD/cats installation, but not OpenBSD/cats.
		Various other updates.
20051106	Modifying the -Y command line option to allow scaleup with
		certain graphic controllers (only dev_vga so far), not just
		scaledown.
		Some minor dyntrans cleanups.
20051107	Beginning a cleanup up the PCI subsystem (removing the
		read_register hack, etc).
20051108	Continuing the cleanup; splitting up some pci devices into a
		normal autodev device and some separate pci glue code.
20051109	Continuing on the PCI bus stuff; all old pci_*.c have been
		incorporated into normal devices and/or rewritten as glue code
		only, adding a dummy Intel 82371AB PIIX4 for Malta (not really
		tested yet).
		Minor pckbc fix so that Linux doesn't complain.
		Working on the DEC 21143 NIC (ethernet mac rom stuff mostly).
		Various other minor fixes.
20051110	Some more ARM dyntrans fine-tuning (e.g. some instruction
		combinations (cmps followed by conditional branch within the
		same page) and special cases for DPIs with regform when the
		shifter isn't used).
20051111	ARM dyntrans updates: O(n)->O(1) for just-mark-as-non-
		writable in the generic pc_to_pointers function, and some other
		minor hacks.
		Merging Cobalt and evbmips (Malta) ISA interrupt handling,
		and some minor fixes to allow Linux to accept harddisk irqs.
20051112	Minor device updates (pckbc, dec21143, lpt, ...), most
		importantly fixing the ALI M1543/M5229 so that harddisk irqs
		work with Linux/CATS.
20051113	Some more generalizations of the PCI subsystem.
		Finally took the time to add a hack for SCSI CDROM TOCs; this
		enables OpenBSD to use partition 'a' (as needed by the OpenBSD
		installer), and Windows NT's installer to get a bit further.
		Also fixing dev_wdc to allow Linux to detect ATAPI CDROMs.
		Continuing on the DEC 21143.
20051114	Minor ARM dyntrans tweaks; ARM cmps+branch optimization when
		comparing with 0, and generalizing the xchg instr. comb.
		Adding disassembly of ARM mrrc/mcrr and q{,d}{add,sub}.
20051115	Continuing on various PPC things (BATs, other address trans-
		lation things, various loads/stores, BeBox emulation, etc.).
		Beginning to work on PPC interrupt/exception support.
20051116	Factoring out some code which initializes legacy ISA devices
		from those machines that use them (bus_isa).
		Continuing on PPC interrupt/exception support.
20051117	Minor Malta fixes: RTC year offset = 80, disabling a speed hack
		which caused NetBSD to detect a too fast cpu, and adding a new
		hack to make Linux detect a faster cpu.
		Continuing on the Artesyn PM/PPC emulation mode.
		Adding an Algor emulation skeleton (P4032 and P5064);
		implementing some of the basics.
		Continuing on PPC emulation in general; usage of unimplemented
		SPRs is now easier to track, continuing on memory/exception
		related issues, etc.
20051118	More work on PPC emulation (tgpr0..3, exception handling,
		memory stuff, syscalls, etc.).
20051119	Changing the ARM dyntrans code to mostly use cpu->pc, and not
		necessarily use arm reg 15. Seems to work.
		Various PPC updates; continuing on the PReP emulation mode.
20051120	Adding a workaround/hack to dev_mc146818 to allow NetBSD/prep
		to detect the clock.
20051121	More cleanup of the PCI bus (memory and I/O bases, etc).
		Continuing on various PPC things (decrementer and timebase,
		WDCs on obio (on PReP) use irq 13, not 14/15).
20051122	Continuing on the CPC700 controller (interrupts etc) for PMPPC,
		and on PPC stuff in general.
		Finally! After some bug fixes to the virtual to physical addr
		translation, NetBSD/{prep,pmppc} 2.1 reach userland and are
		stable enough to be interacted with.
		More PCI updates; reverse-endian device access for PowerPC etc.
20051123	Generalizing the IEEE floating point subsystem (moving it out
		from src/cpus/cpu_mips_coproc.c into a new src/float_emul.c).
		Input via slave xterms was sometimes not really working; fixing
		this for ns16550, and a warning message is now displayed if
		multiple non-xterm consoles are active.
		Adding some PPC floating point support, etc.
		Various interrupt related updates (dev_wdc, _ns16550, _8259,
		and the isa32 common code in machine.c).
		NetBSD/prep can now be installed! :-) (Well, with some manual
		commands necessary before running sysinst.) Updating the
		documentation and various other things to reflect this.
20051124	Various minor documentation updates.
		Continuing the work on the DEC 21143 NIC.
20051125	LOTS of work on the 21143. Both OpenBSD and NetBSD work fine
		with it now, except that OpenBSD sometimes gives a time-out
		warning.
		Minor documentation updates.

==============  RELEASE 0.3.7  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26