cpu_arm_instr.cc Source File

Back to the index.

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

Generated on Fri Dec 7 2018 19:52:23 for GXemul by doxygen 1.8.13