/[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 30 - (show annotations)
Mon Oct 8 16:20:40 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 79657 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1325 2006/08/15 15:38:37 debug Exp $
20060723	More Transputer instructions (pfix, nfix, opr, mint, ldl, ldlp,
		eqc, rev, ajw, stl, stlf, sthf, sub, ldnl, ldnlp, ldpi, move,
		wcnt, add, bcnt).
		Adding more SPARC instructions (andcc, addcc, bl, rdpr).
		Progress on the igsfb framebuffer used by NetBSD/netwinder.
		Enabling 8-bit fills in dev_fb.
		NetBSD/netwinder 3.0.1 can now run from a disk image :-)
20060724	Cleanup/performance fix for 64-bit virtual translation table
		updates (by removing the "timestamp" stuff). A full NetBSD/pmax
		3.0.1 install for R4400 has dropped from 667 seconds to 584 :)
		Fixing the igsfb "almost vga" color (it is 24-bit, not 18-bit).
		Adding some MIPS instruction combinations (3*lw, and 3*addu).
		The 8048 keyboard now turns off interrupt enable between the
		KBR_ACK and the KBR_RSTDONE, to work better with Linux 2.6.
		Not causing PPC DEC interrupts if PPC_NO_DEC is set for a
		specific CPU; NetBSD/bebox gets slightly further than before.
		Adding some more SPARC instructions: branches, udiv.
20060725	Refreshing dev_pckbc.c a little.
		Cleanups for the SH emulation mode, and adding the first
		"compact" (16-bit) instructions: various simple movs, nop,
		shll, stc, or, ldc.
20060726	Adding dummy "pcn" (AMD PCnet NIC) PCI glue.
20060727	Various cleanups; removing stuff from cpu.h, such as
		running_translated (not really meaningful anymore), and
		page flags (breaking into the debugger clears all translations
		anyway).
		Minor MIPS instruction combination updates.
20060807	Expanding the 3*sw and 3*lw MIPS instruction combinations to
		work with 2* and 4* too, resulting in a minor performance gain.
		Implementing a usleep hack for the RM52xx/MIPS32/MIPS64 "wait"
		instruction (when emulating 1 cpu).
20060808	Experimenting with some more MIPS instruction combinations.
		Implementing support for showing a (hardcoded 12x22) text
		cursor in igsfb.
20060809	Simplifying the NetBSD/evbmips (Malta) install instructions
		somewhat (by using a NetBSD/pmax ramdisk install kernel).
20060812	Experimenting more with the MIPS 'wait' instruction.
		PCI configuration register writes can now be handled, which
		allow PCI IDE controllers to work with NetBSD/Malta 3.0.1 and
		NetBSD/cobalt 3.0.1. (Previously only NetBSD 2.1 worked.)
20060813	Updating dev_gt.c based on numbers from Alec Voropay, to enable
		Linux 2.6 to use PCI on Malta.
		Continuing on Algor interrupt stuff.
20060814	Adding support for routing ISA interrupts to two different
		interrupts, making it possible to run NetBSD/algor :-)
20060814-15	Testing for the release.

==============  RELEASE 0.4.2  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26