/[gxemul]/upstream/0.4.4.1/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 /upstream/0.4.4.1/src/cpus/cpu_arm_instr.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26