/[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 22 - (show annotations)
Mon Oct 8 16:19:37 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 80066 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1121 2006/02/18 21:03:08 debug Exp $
20051126	Cobalt and PReP now work with the 21143 NIC.
		Continuing on Alpha dyntrans things.
		Fixing some more left-shift-by-24 to unsigned.
20051127	Working on OpenFirmware emulation; major cleanup/redesign.
		Progress on MacPPC emulation: NetBSD detects two CPUs (when
		running with -n 2), framebuffer output (for text) works.
		Adding quick-hack Bandit PCI controller and "gc" interrupt
		controller for MacPPC.
20051128	Changing from a Bandit to a Uni-North controller for macppc.
		Continuing on OpenFirmware and MacPPC emulation in general
		(obio controller, and wdc attached to the obio seems to work).
20051129	More work on MacPPC emulation (adding a dummy ADB controller).
		Continuing the PCI bus cleanup (endianness and tag composition)
		and rewriting all PCI controllers' access functions.
20051130	Various minor PPC dyntrans optimizations.
		Manually inlining some parts of the framebuffer redraw routine.
		Slowly beginning the conversion of the old MIPS emulation into
		dyntrans (but this will take quite some time to get right).
		Generalizing quick_pc_to_pointers.
20051201	Documentation update (David Muse has made available a kernel
		which simplifies Debian/DECstation installation).
		Continuing on the ADB bus controller.
20051202	Beginning a rewrite of the Zilog serial controller (dev_zs).
20051203	Continuing on the zs rewrite (now called dev_z8530); conversion
		to devinit style.
		Reworking some of the input-only vs output-only vs input-output
		details of src/console.c, better warning messages, and adding
		a debug dump.
		Removing the concept of "device state"; it wasn't really used.
		Changing some debug output (-vv should now be used to show all
		details about devices and busses; not shown during normal
		startup anymore).
		Beginning on some SPARC instruction disassembly support.
20051204	Minor PPC updates (WALNUT skeleton stuff).
		Continuing on the MIPS dyntrans rewrite.
		More progress on the ADB controller (a keyboard is "detected"
		by NetBSD and OpenBSD).
		Downgrading OpenBSD/arc as a guest OS from "working" to
		"almost working" in the documentation.
		Progress on Algor emulation ("v3" PCI controller).
20051205	Minor updates.
20051207	Sorting devices according to address; this reduces complexity
		of device lookups from O(n) to O(log n) in memory_rw (but no
		real performance increase (yet) in experiments).
20051210	Beginning the work on native dyntrans backends (by making a
		simple skeleton; so far only for Alpha hosts).
20051211	Some very minor SPARC updates.
20051215	Fixing a bug in the MIPS mul (note: not mult) instruction,
		so it also works with non-64-bit emulation. (Thanks to Alec
		Voropay for noticing the problem.)
20051216	More work on the fake/empty/simple/skeleton/whatever backend;
		performance doesn't increase, so this isn't really worth it,
		but it was probably worth it to prepare for a real backend
		later.
20051219	More instr call statistics gathering and analysis stuff.
20051220	Another fix for MIPS 'mul'. Also converting mul and {d,}cl{o,z}
		to dyntrans.
		memory_ppc.c syntax error fix (noticed by Peter Valchev).
		Beginning to move out machines from src/machine.c into
		individual files in src/machines (in a way similar to the
		autodev system for devices).
20051222	Updating the documentation regarding NetBSD/pmax 3.0.
20051223	- " - NetBSD/cats 3.0.
20051225	- " - NetBSD/hpcmips 3.0.
20051226	Continuing on the machine registry redesign.
		Adding support for ARM rrx (33-bit rotate).
		Fixing some signed/unsigned issues (exposed by gcc -W).
20051227	Fixing the bug which prevented a NetBSD/prep 3.0 install kernel
		from starting (triggered when an mtmsr was the last instruction
		on a page). Unfortunately not enough to get the kernel to run
		as well as the 2.1 kernels did.
20051230	Some dyntrans refactoring.
20051231	Continuing on the machine registry redesign.
20060101-10	Continuing... moving more machines. Moving MD interrupt stuff
		from machine.c into a new src/machines/interrupts.c.
20060114	Adding various mvmeppc machine skeletons.
20060115	Continuing on mvme* stuff. NetBSD/mvmeppc prints boot messages
		(for MVME1600) and reaches the root device prompt, but no
		specific hardware devices are emulated yet.
20060116	Minor updates to the mvme1600 emulation mode; the Eagle PCI bus
		seems to work without much modification, and a 21143 can be
		detected, interrupts might work (but untested so far).
		Adding a fake MK48Txx (mkclock) device, for NetBSD/mvmeppc.
20060121	Adding an aux control register for ARM. (A BIG thank you to
		Olivier Houchard for tracking down this bug.)
20060122	Adding more ARM instructions (smulXY), and dev_iq80321_7seg.
20060124	Adding disassembly of more ARM instructions (mia*, mra/mar),
		and some semi-bogus XScale and i80321 registers.
20060201-02	Various minor updates. Moving the last machines out of
		machine.c.
20060204	Adding a -c command line option, for running debugger commands
		before the simulation starts, but after all files have been
		loaded.
		Minor iq80321-related updates.
20060209	Minor hacks (DEVINIT macro, etc).
		Preparing for the generalization of the 64-bit dyntrans address
		translation subsystem.
20060216	Adding ARM ldrd (double-register load).
20060217	Continuing on various ARM-related stuff.
20060218	More progress on the ATA/wdc emulation for NetBSD/iq80321.
		NetBSD/evbarm can now be installed :-)  Updating the docs, etc.
		Continuing on Algor emulation.

==============  RELEASE 0.3.8  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26