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-2019 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. This could be due to an unimplemented instruction"
218  " encoding. 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  * mla: Multiplication with subtraction
664  *
665  * arg[0] = copy of instruction word
666  */
667 X(mls)
668 {
669  /* xxxx0000 0110dddd aaaammmm 1001nnnn mls Rd,Rn,Rm,Ra */
670  uint32_t iw = ic->arg[0];
671  int rd = (iw >> 16) & 15;
672  int rn = (iw >> 0) & 15;
673  int rm = (iw >> 8) & 15;
674  int ra = (iw >> 12) & 15;
675 
676  cpu->cd.arm.r[rd] = cpu->cd.arm.r[ra] -
677  cpu->cd.arm.r[rn] * cpu->cd.arm.r[rm];
678 }
679 Y(mls)
680 
681 
682 /*
683  * mull: Long multiplication
684  *
685  * arg[0] = copy of instruction word
686  */
687 X(mull)
688 {
689  /* xxxx0000 1UAShhhh llllssss 1001mmmm */
690  uint32_t iw; uint64_t tmp; int u_bit, a_bit;
691  iw = ic->arg[0];
692  u_bit = iw & 0x00400000; a_bit = iw & 0x00200000;
693  tmp = cpu->cd.arm.r[iw & 15];
694  if (u_bit)
695  tmp = (int64_t)(int32_t)tmp
696  * (int64_t)(int32_t)cpu->cd.arm.r[(iw >> 8) & 15];
697  else
698  tmp *= (uint64_t)cpu->cd.arm.r[(iw >> 8) & 15];
699  if (a_bit) {
700  uint64_t x = ((uint64_t)cpu->cd.arm.r[(iw >> 16) & 15] << 32)
701  | cpu->cd.arm.r[(iw >> 12) & 15];
702  x += tmp;
703  cpu->cd.arm.r[(iw >> 16) & 15] = (x >> 32);
704  cpu->cd.arm.r[(iw >> 12) & 15] = x;
705  } else {
706  cpu->cd.arm.r[(iw >> 16) & 15] = (tmp >> 32);
707  cpu->cd.arm.r[(iw >> 12) & 15] = tmp;
708  }
709 }
710 Y(mull)
711 
712 
713 /*
714  * smulXY: 16-bit * 16-bit multiplication (32-bit result)
715  *
716  * arg[0] = ptr to rm
717  * arg[1] = ptr to rs
718  * arg[2] = ptr to rd
719  */
720 X(smulbb)
721 {
722  reg(ic->arg[2]) = (int32_t)(int16_t)reg(ic->arg[0]) *
723  (int32_t)(int16_t)reg(ic->arg[1]);
724 }
725 Y(smulbb)
726 X(smultb)
727 {
728  reg(ic->arg[2]) = (int32_t)(int16_t)(reg(ic->arg[0]) >> 16) *
729  (int32_t)(int16_t)reg(ic->arg[1]);
730 }
731 Y(smultb)
732 X(smulbt)
733 {
734  reg(ic->arg[2]) = (int32_t)(int16_t)reg(ic->arg[0]) *
735  (int32_t)(int16_t)(reg(ic->arg[1]) >> 16);
736 }
737 Y(smulbt)
738 X(smultt)
739 {
740  reg(ic->arg[2]) = (int32_t)(int16_t)(reg(ic->arg[0]) >> 16) *
741  (int32_t)(int16_t)(reg(ic->arg[1]) >> 16);
742 }
743 Y(smultt)
744 
745 
746 /*
747  * mov_reg_reg: Move a register to another.
748  *
749  * arg[0] = ptr to source register
750  * arg[1] = ptr to destination register
751  */
752 X(mov_reg_reg)
753 {
754  reg(ic->arg[1]) = reg(ic->arg[0]);
755 }
756 Y(mov_reg_reg)
757 
758 
759 /*
760  * mov_reg_pc: Move the PC register to a normal register.
761  *
762  * arg[0] = offset compared to start of current page + 8
763  * arg[1] = ptr to destination register
764  */
765 X(mov_reg_pc)
766 {
767  reg(ic->arg[1]) = ((uint32_t)cpu->pc&0xfffff000) + (int32_t)ic->arg[0];
768 }
769 Y(mov_reg_pc)
770 
771 
772 /*
773  * ret_trace: "mov pc,lr" with trace enabled
774  * ret: "mov pc,lr" without trace enabled
775  *
776  * arg[0] = ignored
777  */
778 X(ret_trace)
779 {
780  uint32_t old_pc, mask_within_page;
781  old_pc = cpu->pc;
782  mask_within_page = ((ARM_IC_ENTRIES_PER_PAGE-1)
784  ((1 << ARM_INSTR_ALIGNMENT_SHIFT) - 1);
785 
786  /* Update the PC register: */
787  cpu->pc = cpu->cd.arm.r[ARM_LR];
788 
790 
791  /*
792  * Is this a return to code within the same page? Then there is no
793  * need to update all pointers, just next_ic.
794  */
795  if ((old_pc & ~mask_within_page) == (cpu->pc & ~mask_within_page)) {
796  cpu->cd.arm.next_ic = cpu->cd.arm.cur_ic_page +
797  ((cpu->pc & mask_within_page) >> ARM_INSTR_ALIGNMENT_SHIFT);
798  } else {
799  /* Find the new physical page and update pointers: */
800  quick_pc_to_pointers_arm(cpu);
801  }
802 }
803 Y(ret_trace)
804 X(ret)
805 {
806  cpu->pc = cpu->cd.arm.r[ARM_LR];
807  quick_pc_to_pointers_arm(cpu);
808 }
809 Y(ret)
810 
811 
812 /*
813  * msr: Move to status register from a normal register or immediate value.
814  *
815  * arg[0] = immediate value
816  * arg[1] = mask
817  * arg[2] = pointer to rm
818  *
819  * msr_imm and msr_imm_spsr use arg[1] and arg[0].
820  * msr and msr_spsr use arg[1] and arg[2].
821  */
822 X(msr_imm)
823 {
824  uint32_t mask = ic->arg[1];
825 
826  if ((cpu->cd.arm.cpsr & ARM_FLAG_MODE) == ARM_MODE_USR32) {
827  mask &= 0xff000000;
828  }
829 
830  int switch_register_banks = (mask & ARM_FLAG_MODE) &&
831  ((cpu->cd.arm.cpsr & ARM_FLAG_MODE) !=
832  (ic->arg[0] & ARM_FLAG_MODE));
833  uint32_t new_value = ic->arg[0];
834 
835  cpu->cd.arm.cpsr &= 0x0fffffff;
836  cpu->cd.arm.cpsr |= (cpu->cd.arm.flags << 28);
837 
838  if (switch_register_banks)
840 
841  cpu->cd.arm.cpsr &= ~mask;
842  cpu->cd.arm.cpsr |= (new_value & mask);
843 
844  cpu->cd.arm.flags = cpu->cd.arm.cpsr >> 28;
845 
846  if (switch_register_banks)
848 }
849 Y(msr_imm)
850 X(msr)
851 {
852  ic->arg[0] = reg(ic->arg[2]);
853  instr(msr_imm)(cpu, ic);
854 }
855 Y(msr)
856 X(msr_imm_spsr)
857 {
858  uint32_t mask = ic->arg[1];
859  uint32_t new_value = ic->arg[0];
860  switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) {
861  case ARM_MODE_FIQ32:
862  cpu->cd.arm.spsr_fiq &= ~mask;
863  cpu->cd.arm.spsr_fiq |= (new_value & mask);
864  break;
865  case ARM_MODE_ABT32:
866  cpu->cd.arm.spsr_abt &= ~mask;
867  cpu->cd.arm.spsr_abt |= (new_value & mask);
868  break;
869  case ARM_MODE_UND32:
870  cpu->cd.arm.spsr_und &= ~mask;
871  cpu->cd.arm.spsr_und |= (new_value & mask);
872  break;
873  case ARM_MODE_IRQ32:
874  cpu->cd.arm.spsr_irq &= ~mask;
875  cpu->cd.arm.spsr_irq |= (new_value & mask);
876  break;
877  case ARM_MODE_SVC32:
878  cpu->cd.arm.spsr_svc &= ~mask;
879  cpu->cd.arm.spsr_svc |= (new_value & mask);
880  break;
881  default:fatal("msr_spsr: unimplemented mode %i\n",
883  {
884  /* Synchronize the program counter: */
885  uint32_t old_pc, low_pc = ((size_t)ic - (size_t)
886  cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
888  cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
889  old_pc = cpu->pc;
890  printf("msr_spsr: old pc = 0x%08" PRIx32"\n", old_pc);
891  }
892  exit(1);
893  }
894 }
895 Y(msr_imm_spsr)
896 X(msr_spsr)
897 {
898  ic->arg[0] = reg(ic->arg[2]);
899  instr(msr_imm_spsr)(cpu, ic);
900 }
901 Y(msr_spsr)
902 
903 
904 /*
905  * mrs: Move from status/flag register to a normal register.
906  *
907  * arg[0] = pointer to rd
908  */
909 X(mrs)
910 {
911  cpu->cd.arm.cpsr &= 0x0fffffff;
912  cpu->cd.arm.cpsr |= (cpu->cd.arm.flags << 28);
913  reg(ic->arg[0]) = cpu->cd.arm.cpsr;
914 }
915 Y(mrs)
916 
917 
918 /*
919  * mrs: Move from saved status/flag register to a normal register.
920  *
921  * arg[0] = pointer to rd
922  */
923 X(mrs_spsr)
924 {
925  switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) {
926  case ARM_MODE_FIQ32: reg(ic->arg[0]) = cpu->cd.arm.spsr_fiq; break;
927  case ARM_MODE_ABT32: reg(ic->arg[0]) = cpu->cd.arm.spsr_abt; break;
928  case ARM_MODE_UND32: reg(ic->arg[0]) = cpu->cd.arm.spsr_und; break;
929  case ARM_MODE_IRQ32: reg(ic->arg[0]) = cpu->cd.arm.spsr_irq; break;
930  case ARM_MODE_SVC32: reg(ic->arg[0]) = cpu->cd.arm.spsr_svc; break;
931  case ARM_MODE_USR32:
932  case ARM_MODE_SYS32: reg(ic->arg[0]) = 0; break;
933  default:fatal("mrs_spsr: unimplemented mode %i\n",
935  exit(1);
936  }
937 }
938 Y(mrs_spsr)
939 
940 
941 /*
942  * mcr_mrc: Coprocessor move
943  * cdp: Coprocessor operation
944  *
945  * arg[0] = copy of the instruction word
946  */
947 X(mcr_mrc) {
948  uint32_t low_pc = ((size_t)ic - (size_t)
949  cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
951  cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
952  arm_mcr_mrc(cpu, ic->arg[0]);
953 }
954 Y(mcr_mrc)
955 X(cdp) {
956  uint32_t low_pc = ((size_t)ic - (size_t)
957  cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
959  cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
960  arm_cdp(cpu, ic->arg[0]);
961 }
962 Y(cdp)
963 
964 
965 /*
966  * openfirmware:
967  */
968 X(openfirmware)
969 {
970  /* TODO: sync pc? */
971  of_emul(cpu);
972  cpu->pc = cpu->cd.arm.r[ARM_LR];
975  quick_pc_to_pointers_arm(cpu);
976 }
977 
978 
979 /*
980  * reboot:
981  */
982 X(reboot)
983 {
984  cpu->running = 0;
986  cpu->cd.arm.next_ic = &nothing_call;
987 }
988 
989 
990 /*
991  * swi: Software interrupt.
992  */
993 X(swi)
994 {
995  /* Synchronize the program counter first: */
996  cpu->pc &= 0xfffff000;
997  cpu->pc += ic->arg[0];
999 }
1000 Y(swi)
1001 
1002 
1003 /*
1004  * bkpt: Breakpoint instruction.
1005  */
1006 X(bkpt)
1007 {
1008  /* Synchronize the program counter first: */
1009  cpu->pc &= 0xfffff000;
1010  cpu->pc += ic->arg[0];
1012 }
1013 Y(bkpt)
1014 
1015 
1016 /*
1017  * und: Undefined instruction.
1018  */
1019 X(und)
1020 {
1021  /* Synchronize the program counter first: */
1022  cpu->pc &= 0xfffff000;
1023  cpu->pc += ic->arg[0];
1025 }
1026 Y(und)
1027 
1028 
1029 /*
1030  * movt: Move Top.
1031  *
1032  * arg[1] = 32-bit immediate value. Top 16 bits are those of interest.
1033  * arg[2] = ptr to rd
1034  */
1035 X(movt)
1036 {
1037  reg(ic->arg[2]) &= 0xffff;
1038  reg(ic->arg[2]) |= ic->arg[1];
1039 }
1040 Y(movt)
1041 
1042 
1043 /*
1044  * movw: Move (Word).
1045  *
1046  * arg[1] = 32-bit immediate value.
1047  * arg[2] = ptr to rd
1048  */
1049 X(movw)
1050 {
1051  reg(ic->arg[2]) = ic->arg[1];
1052 }
1053 Y(movw)
1054 
1055 
1056 /*
1057  * rev: Reverse endian.
1058  *
1059  * arg[0] = ptr to rd
1060  * arg[1] = ptr to rm
1061  */
1062 X(rev)
1063 {
1064  uint32_t v = reg(ic->arg[1]);
1065 
1066  reg(ic->arg[0]) = (v >> 24) | ((v & 0x00ff0000) >> 8)
1067  | ((v & 0x0000ff00) << 8) | ((v & 0xff) << 24);
1068 }
1069 Y(rev)
1070 
1071 
1072 /*
1073  * uxtb: Unsigned Extend Byte.
1074  *
1075  * arg[0] = ptr to rd
1076  * arg[1] = ptr to rm
1077  * arg[2] = rotation amount (shift works too)
1078  */
1079 X(uxtb)
1080 {
1081  uint32_t x = reg(ic->arg[1]);
1082  reg(ic->arg[0]) = (uint8_t)(x >> ic->arg[2]);
1083 }
1084 Y(uxtb)
1085 
1086 
1087 /*
1088  * sxth: Signed Extend Halfword.
1089  *
1090  * TODO: Could be optimized so that the rotation amount is "inlined".
1091  *
1092  * arg[0] = ptr to rd
1093  * arg[1] = ptr to rm
1094  * arg[2] = rotation amount
1095  */
1096 X(sxth)
1097 {
1098  uint32_t x = reg(ic->arg[1]);
1099 
1100  switch (ic->arg[2]) {
1101  case 0: break;
1102  case 8: x >>= 8; break;
1103  case 16: x >>= 16; break;
1104  case 24: x = (x >> 24) | ((x & 255) << 8); break;
1105  }
1106 
1107  int16_t rotated = x;
1108  reg(ic->arg[0]) = (int32_t)rotated;
1109 }
1110 Y(sxth)
1111 
1112 
1113 /*
1114  * uxth: Unsigned Extend Halfword.
1115  *
1116  * TODO: Could be optimized so that the rotation amount is "inlined".
1117  *
1118  * arg[0] = ptr to rd
1119  * arg[1] = ptr to rm
1120  * arg[2] = rotation amount
1121  */
1122 X(uxth)
1123 {
1124  uint32_t x = reg(ic->arg[1]);
1125 
1126  switch (ic->arg[2]) {
1127  case 0: break;
1128  case 8: x >>= 8; break;
1129  case 16: x >>= 16; break;
1130  case 24: x = (x >> 24) | ((x & 255) << 8); break;
1131  }
1132 
1133  uint16_t rotated = x;
1134  reg(ic->arg[0]) = (uint32_t)rotated;
1135 }
1136 Y(uxth)
1137 
1138 
1139 /*
1140  * uxtah: Unsigned Extend and Add Byte.
1141  *
1142  * arg[0] = ptr to rd
1143  * arg[1] = ptr to rn
1144  * arg[2] = ptr to rm
1145  */
1146 X(uxtab)
1147 {
1148  reg(ic->arg[0]) = reg(ic->arg[1]) + (uint8_t)reg(ic->arg[2]);
1149 }
1150 Y(uxtab)
1151 
1152 
1153 /*
1154  * uxtah: Unsigned Extend and Add Halfword.
1155  *
1156  * arg[0] = ptr to rd
1157  * arg[1] = ptr to rn
1158  * arg[2] = ptr to rm
1159  */
1160 X(uxtah)
1161 {
1162  reg(ic->arg[0]) = reg(ic->arg[1]) + (uint16_t)reg(ic->arg[2]);
1163 }
1164 Y(uxtah)
1165 
1166 
1167 /*
1168  * ubfx: Unsigned Bit-Field Extract.
1169  *
1170  * arg[0] = ptr to rd
1171  * arg[1] = ptr to rn
1172  * arg[2] = (width << 16) + lsb
1173  */
1174 X(ubfx)
1175 {
1176  uint32_t x = reg(ic->arg[1]);
1177 
1178  int lsb = (uint8_t)ic->arg[2];
1179  int width = ic->arg[2] >> 16;
1180 
1181  uint32_t mask = (1 << width) - 1;
1182 
1183  x >>= lsb;
1184  x &= mask;
1185 
1186  reg(ic->arg[0]) = x;
1187 }
1188 Y(ubfx)
1189 
1190 
1191 /*
1192  * sbfx: Signed Bit-Field Extract.
1193  *
1194  * arg[0] = ptr to rd
1195  * arg[1] = ptr to rn
1196  * arg[2] = (width << 16) + lsb
1197  */
1198 X(sbfx)
1199 {
1200  uint32_t x = reg(ic->arg[1]);
1201 
1202  int lsb = (uint8_t)ic->arg[2];
1203  int width = ic->arg[2] >> 16;
1204 
1205  uint32_t mask = (1 << width) - 1;
1206  x >>= lsb;
1207  x &= mask;
1208 
1209  uint32_t topBitMask = 1 << (width-1);
1210  if (x & topBitMask && width < 32)
1211  x |= ~mask;
1212 
1213  reg(ic->arg[0]) = x;
1214 }
1215 Y(sbfx)
1216 
1217 
1218 /*
1219  * bfi: Bit-Field Insert.
1220  *
1221  * arg[0] = ptr to rd
1222  * arg[1] = ptr to rn
1223  * arg[2] = (msb << 16) + lsb
1224  */
1225 X(bfi)
1226 {
1227  uint32_t x = reg(ic->arg[1]);
1228 
1229  int lsb = (uint8_t)ic->arg[2];
1230  int msb = ic->arg[2] >> 16;
1231  int width = msb - lsb + 1;
1232 
1233  x <<= lsb;
1234 
1235  uint32_t mask = (1 << width) - 1;
1236 
1237  mask <<= lsb;
1238 
1239  reg(ic->arg[0]) &= ~mask;
1240  reg(ic->arg[0]) |= (x & mask);
1241 }
1242 Y(bfi)
1243 
1244 
1245 /*
1246  * swp, swpb: Swap (word or byte).
1247  *
1248  * arg[0] = ptr to rd
1249  * arg[1] = ptr to rm
1250  * arg[2] = ptr to rn
1251  */
1252 X(swp)
1253 {
1254  uint32_t addr = reg(ic->arg[2]), data, data2;
1255  unsigned char d[4];
1256 
1257  /* Synchronize the program counter: */
1258  uint32_t low_pc = ((size_t)ic - (size_t)
1259  cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
1261  cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
1262 
1263  if (!cpu->memory_rw(cpu, cpu->mem, addr, d, sizeof(d), MEM_READ,
1264  CACHE_DATA)) {
1265  fatal("swp: load failed\n");
1266  return;
1267  }
1268  data = d[0] + (d[1] << 8) + (d[2] << 16) + (d[3] << 24);
1269  data2 = reg(ic->arg[1]);
1270  d[0] = data2; d[1] = data2 >> 8; d[2] = data2 >> 16; d[3] = data2 >> 24;
1271  if (!cpu->memory_rw(cpu, cpu->mem, addr, d, sizeof(d), MEM_WRITE,
1272  CACHE_DATA)) {
1273  fatal("swp: store failed\n");
1274  return;
1275  }
1276  reg(ic->arg[0]) = data;
1277 }
1278 Y(swp)
1279 X(swpb)
1280 {
1281  uint32_t addr = reg(ic->arg[2]), data;
1282  unsigned char d[1];
1283 
1284  /* Synchronize the program counter: */
1285  uint32_t low_pc = ((size_t)ic - (size_t)
1286  cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
1288  cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
1289 
1290  if (!cpu->memory_rw(cpu, cpu->mem, addr, d, sizeof(d), MEM_READ,
1291  CACHE_DATA)) {
1292  fatal("swp: load failed\n");
1293  return;
1294  }
1295  data = d[0];
1296  d[0] = reg(ic->arg[1]);
1297  if (!cpu->memory_rw(cpu, cpu->mem, addr, d, sizeof(d), MEM_WRITE,
1298  CACHE_DATA)) {
1299  fatal("swp: store failed\n");
1300  return;
1301  }
1302  reg(ic->arg[0]) = data;
1303 }
1304 Y(swpb)
1305 
1306 
1307 extern void (*arm_load_store_instr[1024])(struct cpu *,
1308  struct arm_instr_call *);
1309 X(store_w1_word_u1_p0_imm);
1310 X(store_w0_byte_u1_p0_imm);
1311 X(store_w0_word_u1_p0_imm);
1312 X(store_w0_word_u1_p1_imm);
1313 X(load_w0_word_u1_p0_imm);
1314 X(load_w0_word_u1_p1_imm);
1315 X(load_w1_word_u1_p0_imm);
1316 X(load_w0_byte_u1_p1_imm);
1317 X(load_w0_byte_u1_p1_reg);
1318 X(load_w1_byte_u1_p1_imm);
1319 
1320 extern void (*arm_load_store_instr_pc[1024])(struct cpu *,
1321  struct arm_instr_call *);
1322 
1323 extern void (*arm_load_store_instr_3[2048])(struct cpu *,
1324  struct arm_instr_call *);
1325 
1326 extern void (*arm_load_store_instr_3_pc[2048])(struct cpu *,
1327  struct arm_instr_call *);
1328 
1329 extern uint32_t (*arm_r[8192])(struct cpu *, struct arm_instr_call *);
1330 extern uint32_t arm_r_r3_t0_c0(struct cpu *cpu, struct arm_instr_call *ic);
1331 
1332 extern void (*arm_dpi_instr[2 * 2 * 2 * 16 * 16])(struct cpu *,
1333  struct arm_instr_call *);
1334 extern void (*arm_dpi_instr_regshort[2 * 16 * 16])(struct cpu *,
1335  struct arm_instr_call *);
1337 X(teqs);
1338 X(tsts);
1339 X(sub);
1340 X(add);
1341 X(subs);
1342 X(eor_regshort);
1343 X(cmps_regshort);
1344 
1345 
1346 #include "cpu_arm_instr_misc.cc"
1347 
1348 
1349 /*
1350  * Shared between regular ARM and the THUMB encoded 'pop'.
1351  */
1352 void arm_pop(struct cpu* cpu, uint32_t* np, int p_bit, int u_bit, int s_bit, int w_bit, uint32_t iw)
1353 {
1354  uint32_t addr = *np;
1355  unsigned char data[4];
1356  unsigned char *page;
1357  int i, return_flag = 0;
1358  uint32_t new_values[16];
1359 
1360  if (s_bit) {
1361  /* Load to USR registers: */
1362  if ((cpu->cd.arm.cpsr & ARM_FLAG_MODE) == ARM_MODE_USR32) {
1363  fatal("[ bdt_load: s-bit: in usermode? ]\n");
1364  s_bit = 0;
1365  }
1366  if (iw & 0x8000) {
1367  s_bit = 0;
1368  return_flag = 1;
1369  }
1370  }
1371 
1372  for (i=(u_bit? 0 : 15); i>=0 && i<=15; i+=(u_bit? 1 : -1)) {
1373  uint32_t value;
1374 
1375  if (!((iw >> i) & 1)) {
1376  /* Skip register i: */
1377  continue;
1378  }
1379 
1380  if (p_bit) {
1381  if (u_bit)
1382  addr += sizeof(uint32_t);
1383  else
1384  addr -= sizeof(uint32_t);
1385  }
1386 
1387  page = cpu->cd.arm.host_load[addr >> 12];
1388  if (page != NULL) {
1389  uint32_t *p32 = (uint32_t *) page;
1390  value = p32[(addr & 0xfff) >> 2];
1391  /* Change byte order of value if
1392  host and emulated endianness differ: */
1393 #ifdef HOST_LITTLE_ENDIAN
1394  if (cpu->byte_order == EMUL_BIG_ENDIAN)
1395 #else
1397 #endif
1398  value = ((value & 0xff) << 24) |
1399  ((value & 0xff00) << 8) |
1400  ((value & 0xff0000) >> 8) |
1401  ((value & 0xff000000) >> 24);
1402  } else {
1403  if (!cpu->memory_rw(cpu, cpu->mem, addr, data,
1404  sizeof(data), MEM_READ, CACHE_DATA)) {
1405  /* load failed */
1406  return;
1407  }
1408  if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
1409  value = data[0] +
1410  (data[1] << 8) + (data[2] << 16)
1411  + (data[3] << 24);
1412  } else {
1413  value = data[3] +
1414  (data[2] << 8) + (data[1] << 16)
1415  + (data[0] << 24);
1416  }
1417  }
1418 
1419  new_values[i] = value;
1420 
1421  if (!p_bit) {
1422  if (u_bit)
1423  addr += sizeof(uint32_t);
1424  else
1425  addr -= sizeof(uint32_t);
1426  }
1427  }
1428 
1429  for (i=(u_bit? 0 : 15); i>=0 && i<=15; i+=(u_bit? 1 : -1)) {
1430  if (!((iw >> i) & 1)) {
1431  /* Skip register i: */
1432  continue;
1433  }
1434 
1435  if (!s_bit) {
1436  cpu->cd.arm.r[i] = new_values[i];
1437  } else {
1438  switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) {
1439  case ARM_MODE_USR32:
1440  case ARM_MODE_SYS32:
1441  cpu->cd.arm.r[i] = new_values[i];
1442  break;
1443  case ARM_MODE_FIQ32:
1444  if (i >= 8 && i <= 14)
1445  cpu->cd.arm.default_r8_r14[i-8] =
1446  new_values[i];
1447  else
1448  cpu->cd.arm.r[i] = new_values[i];
1449  break;
1450  case ARM_MODE_SVC32:
1451  case ARM_MODE_ABT32:
1452  case ARM_MODE_UND32:
1453  case ARM_MODE_IRQ32:
1454  if (i >= 13 && i <= 14)
1455  cpu->cd.arm.default_r8_r14[i-8] =
1456  new_values[i];
1457  else
1458  cpu->cd.arm.r[i] = new_values[i];
1459  break;
1460  }
1461  }
1462  }
1463 
1464  if (w_bit)
1465  *np = addr;
1466 
1467  if (return_flag) {
1468  uint32_t new_cpsr;
1469  int switch_register_banks;
1470 
1471  switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) {
1472  case ARM_MODE_FIQ32:
1473  new_cpsr = cpu->cd.arm.spsr_fiq; break;
1474  case ARM_MODE_ABT32:
1475  new_cpsr = cpu->cd.arm.spsr_abt; break;
1476  case ARM_MODE_UND32:
1477  new_cpsr = cpu->cd.arm.spsr_und; break;
1478  case ARM_MODE_IRQ32:
1479  new_cpsr = cpu->cd.arm.spsr_irq; break;
1480  case ARM_MODE_SVC32:
1481  new_cpsr = cpu->cd.arm.spsr_svc; break;
1482  default:fatal("bdt_load: unimplemented mode %i\n",
1483  cpu->cd.arm.cpsr & ARM_FLAG_MODE);
1484  exit(1);
1485  }
1486 
1487  switch_register_banks = (cpu->cd.arm.cpsr & ARM_FLAG_MODE) !=
1488  (new_cpsr & ARM_FLAG_MODE);
1489 
1490  if (switch_register_banks)
1492 
1493  cpu->cd.arm.cpsr = new_cpsr;
1494  cpu->cd.arm.flags = cpu->cd.arm.cpsr >> 28;
1495 
1496  if (switch_register_banks)
1498  }
1499 
1500  /* NOTE: Special case: Loading the PC */
1501  if (iw & 0x8000) {
1502  cpu->pc = cpu->cd.arm.r[ARM_PC] & 0xfffffffc;
1503  if (cpu->machine->show_trace_tree)
1505  /* TODO: There is no need to update the
1506  pointers if this is a return to the
1507  same page! */
1508  /* Find the new physical page and update the
1509  translation pointers: */
1510  quick_pc_to_pointers_arm(cpu);
1511  }
1512 }
1513 
1514 
1515 /*
1516  * Shared between regular ARM and the THUMB encoded 'push'.
1517  */
1518 void arm_push(struct cpu* cpu, uint32_t* np, int p_bit, int u_bit, int s_bit, int w_bit, uint16_t regs)
1519 {
1520  int i;
1521  uint32_t value, addr = *np;
1522  unsigned char data[4];
1523  unsigned char *page;
1524 
1525  for (i=(u_bit? 0 : 15); i>=0 && i<=15; i+=(u_bit? 1 : -1)) {
1526  if (!((regs >> i) & 1)) {
1527  /* Skip register i: */
1528  continue;
1529  }
1530 
1531  value = cpu->cd.arm.r[i];
1532 
1533  if (s_bit) {
1534  switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) {
1535  case ARM_MODE_FIQ32:
1536  if (i >= 8 && i <= 14)
1537  value = cpu->cd.arm.default_r8_r14[i-8];
1538  break;
1539  case ARM_MODE_ABT32:
1540  case ARM_MODE_UND32:
1541  case ARM_MODE_IRQ32:
1542  case ARM_MODE_SVC32:
1543  if (i >= 13 && i <= 14)
1544  value = cpu->cd.arm.default_r8_r14[i-8];
1545  break;
1546  case ARM_MODE_USR32:
1547  case ARM_MODE_SYS32:
1548  break;
1549  }
1550  }
1551 
1552  /* NOTE/TODO: 8 vs 12 on some ARMs */
1553  if (i == ARM_PC)
1554  value = cpu->pc + 12;
1555 
1556  if (p_bit) {
1557  if (u_bit)
1558  addr += sizeof(uint32_t);
1559  else
1560  addr -= sizeof(uint32_t);
1561  }
1562 
1563  page = cpu->cd.arm.host_store[addr >> 12];
1564  if (page != NULL) {
1565  uint32_t *p32 = (uint32_t *) page;
1566  /* Change byte order of value if
1567  host and emulated endianness differ: */
1568 #ifdef HOST_LITTLE_ENDIAN
1569  if (cpu->byte_order == EMUL_BIG_ENDIAN)
1570 #else
1572 #endif
1573  value = ((value & 0xff) << 24) |
1574  ((value & 0xff00) << 8) |
1575  ((value & 0xff0000) >> 8) |
1576  ((value & 0xff000000) >> 24);
1577  p32[(addr & 0xfff) >> 2] = value;
1578  } else {
1579  if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
1580  data[0] = value;
1581  data[1] = value >> 8;
1582  data[2] = value >> 16;
1583  data[3] = value >> 24;
1584  } else {
1585  data[0] = value >> 24;
1586  data[1] = value >> 16;
1587  data[2] = value >> 8;
1588  data[3] = value;
1589  }
1590  if (!cpu->memory_rw(cpu, cpu->mem, addr, data,
1591  sizeof(data), MEM_WRITE, CACHE_DATA)) {
1592  /* store failed */
1593  return;
1594  }
1595  }
1596 
1597  if (!p_bit) {
1598  if (u_bit)
1599  addr += sizeof(uint32_t);
1600  else
1601  addr -= sizeof(uint32_t);
1602  }
1603  }
1604 
1605  if (w_bit)
1606  *np = addr;
1607 }
1608 
1609 
1610 /*
1611  * bdt_load: Block Data Transfer, Load
1612  *
1613  * arg[0] = pointer to uint32_t in host memory, pointing to the base register
1614  * arg[1] = 32-bit instruction word. Most bits are read from this.
1615  */
1617 {
1618  uint32_t *np = (uint32_t *)ic->arg[0];
1619  uint32_t low_pc;
1620  uint32_t iw = ic->arg[1]; /* xxxx100P USWLnnnn llllllll llllllll */
1621  int p_bit = iw & 0x01000000;
1622  int u_bit = iw & 0x00800000;
1623  int s_bit = iw & 0x00400000;
1624  int w_bit = iw & 0x00200000;
1625 
1626 #ifdef GATHER_BDT_STATISTICS
1627  if (!s_bit)
1628  update_bdt_statistics(iw);
1629 #endif
1630 
1631  /* Synchronize the program counter: */
1632  low_pc = ((size_t)ic - (size_t)
1633  cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
1635  cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
1636 
1637  arm_pop(cpu, np, p_bit, u_bit, s_bit, w_bit, (uint16_t)iw);
1638 }
1640 
1641 
1642 /*
1643  * bdt_store: Block Data Transfer, Store
1644  *
1645  * arg[0] = pointer to uint32_t in host memory, pointing to the base register
1646  * arg[1] = 32-bit instruction word. Most bits are read from this.
1647  */
1648 X(bdt_store)
1649 {
1650  uint32_t *np = (uint32_t *)ic->arg[0];
1651  uint32_t low_pc;
1652  uint32_t iw = ic->arg[1]; /* xxxx100P USWLnnnn llllllll llllllll */
1653  int p_bit = iw & 0x01000000;
1654  int u_bit = iw & 0x00800000;
1655  int s_bit = iw & 0x00400000;
1656  int w_bit = iw & 0x00200000;
1657 
1658 #ifdef GATHER_BDT_STATISTICS
1659  if (!s_bit)
1660  update_bdt_statistics(iw);
1661 #endif
1662 
1663  /* Synchronize the program counter: */
1664  low_pc = ((size_t)ic - (size_t)
1665  cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
1667  cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
1668 
1669  arm_push(cpu, np, p_bit, u_bit, s_bit, w_bit, (uint16_t)iw);
1670 }
1672 
1673 
1674 /*
1675  * Load Register Exclusive (ARM "load linked"):
1676  *
1677  * A Load Register Exclusive instruction initiates a RMW (read-modify-write)
1678  * sequence.
1679  *
1680  * A Store Register Exclusive instruction ends the sequence.
1681  *
1682  * arg[0] = ptr to rt
1683  * arg[1] = ptr to rn
1684  * arg[2] = int32_t imm offset
1685  */
1686 X(ldrex)
1687 {
1688  uint32_t addr = reg(ic->arg[1]) + (int32_t)ic->arg[2];
1689  int low_pc;
1690  uint8_t word[sizeof(uint32_t)];
1691 
1692  /* Synchronize the program counter: */
1693  low_pc = ((size_t)ic - (size_t)
1694  cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
1696  cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
1697 
1698  if (addr & (sizeof(word)-1)) {
1699  fatal("TODO: ldrex unaligned access: exception\n");
1700  exit(1);
1701  }
1702 
1703  if (!cpu->memory_rw(cpu, cpu->mem, addr, word,
1704  sizeof(word), MEM_READ, CACHE_DATA)) {
1705  /* An exception occurred. */
1706  return;
1707  }
1708 
1709  cpu->cd.arm.rmw = 1;
1710  cpu->cd.arm.rmw_addr = addr;
1711  cpu->cd.arm.rmw_len = sizeof(word);
1712 
1714  reg(ic->arg[0]) = word[0] + (word[1] << 8)
1715  + (word[2] << 16) + (word[3] << 24);
1716  else
1717  reg(ic->arg[0]) = word[3] + (word[2] << 8)
1718  + (word[1] << 16) + (word[0] << 24);
1719 }
1720 Y(ldrex)
1721 /*
1722  * Store Register Exclusive
1723  *
1724  * arg[0] = ptr to rd
1725  * arg[1] = ptr to rn
1726  * arg[2] = ptr to rt
1727  */
1728 X(strex)
1729 {
1730  uint32_t addr = reg(ic->arg[1]);
1731  uint64_t r = reg(ic->arg[2]);
1732  int low_pc, i;
1733  uint8_t word[sizeof(uint32_t)];
1734 
1735  /* Synchronize the program counter: */
1736  low_pc = ((size_t)ic - (size_t)
1737  cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
1739  cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
1740 
1741  if (addr & (sizeof(word)-1)) {
1742  fatal("TODO: strex unaligned access: exception\n");
1743  exit(1);
1744  }
1745 
1746  if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
1747  word[0]=r; word[1]=r>>8; word[2]=r>>16; word[3]=r>>24;
1748  } else {
1749  word[3]=r; word[2]=r>>8; word[1]=r>>16; word[0]=r>>24;
1750  }
1751 
1752  /* If rmw is 0, then the store failed. (This cache-line was written
1753  to by someone else.) */
1754  if (cpu->cd.arm.rmw == 0 || cpu->cd.arm.rmw_addr != addr
1755  || cpu->cd.arm.rmw_len != sizeof(word)) {
1756  reg(ic->arg[0]) = 1; // 1 = fail.
1757  cpu->cd.arm.rmw = 0;
1758  return;
1759  }
1760 
1761  if (!cpu->memory_rw(cpu, cpu->mem, addr, word,
1762  sizeof(word), MEM_WRITE, CACHE_DATA)) {
1763  /* An exception occurred. */
1764  return;
1765  }
1766 
1767  /* We succeeded. Let's invalidate everybody else's store to this
1768  cache line: */
1769  for (i=0; i<cpu->machine->ncpus; i++) {
1770  if (cpu->machine->cpus[i]->cd.arm.rmw) {
1771  uint64_t yaddr = addr, xaddr = cpu->machine->cpus[i]->
1772  cd.arm.rmw_addr;
1773 
1774  /* 8-2048 bytes, implementation dependent :-( */
1775  /* https://stackoverflow.com/questions/11383125/do-the-arm-instructions-ldrex-strex-have-to-operate-on-cache-aligned-data */
1776  uint64_t mask = 2047;
1777 
1778  xaddr &= mask;
1779  yaddr &= mask;
1780  if (xaddr == yaddr)
1781  cpu->machine->cpus[i]->cd.arm.rmw = 0;
1782  }
1783  }
1784 
1785  reg(ic->arg[0]) = 0; // 0 = success
1786  cpu->cd.arm.rmw = 0;
1787 }
1788 Y(strex)
1789 
1790 
1791 /* Various load/store multiple instructions: */
1792 extern uint32_t *multi_opcode[256];
1793 extern void (**multi_opcode_f[256])(struct cpu *, struct arm_instr_call *);
1794 X(multi_0x08b15018);
1795 X(multi_0x08ac000c__ge);
1796 X(multi_0x08a05018);
1797 
1798 
1799 /*****************************************************************************/
1800 
1801 
1802 /*
1803  * netbsd_memset:
1804  *
1805  * The core of a NetBSD/arm memset.
1806  *
1807  * f01bc420: e25XX080 subs rX,rX,#0x80
1808  * f01bc424: a8ac000c stmgeia ip!,{r2,r3} (16 of these)
1809  * ..
1810  * f01bc464: caffffed bgt 0xf01bc420 <memset+0x38>
1811  */
1813 {
1814  unsigned char *page;
1815  uint32_t addr;
1816 
1817  do {
1818  addr = cpu->cd.arm.r[ARM_IP];
1819 
1820  instr(subs)(cpu, ic);
1821 
1822  if (((cpu->cd.arm.flags & ARM_F_N)?1:0) !=
1823  ((cpu->cd.arm.flags & ARM_F_V)?1:0)) {
1824  cpu->n_translated_instrs += 16;
1825  /* Skip the store multiples: */
1826  cpu->cd.arm.next_ic = &ic[17];
1827  return;
1828  }
1829 
1830  /* Crossing a page boundary? Then continue non-combined. */
1831  if ((addr & 0xfff) + 128 > 0x1000)
1832  return;
1833 
1834  /* R2/R3 non-zero? Not allowed here. */
1835  if (cpu->cd.arm.r[2] != 0 || cpu->cd.arm.r[3] != 0)
1836  return;
1837 
1838  /* printf("addr = 0x%08x\n", addr); */
1839 
1840  page = cpu->cd.arm.host_store[addr >> 12];
1841  /* No page translation? Continue non-combined. */
1842  if (page == NULL)
1843  return;
1844 
1845  /* Clear: */
1846  memset(page + (addr & 0xfff), 0, 128);
1847  cpu->cd.arm.r[ARM_IP] = addr + 128;
1848  cpu->n_translated_instrs += 16;
1849 
1850  /* Branch back if greater: */
1851  cpu->n_translated_instrs += 1;
1852  } while (((cpu->cd.arm.flags & ARM_F_N)?1:0) ==
1853  ((cpu->cd.arm.flags & ARM_F_V)?1:0) &&
1854  !(cpu->cd.arm.flags & ARM_F_Z));
1855 
1856  /* Continue at the instruction after the bgt: */
1857  cpu->cd.arm.next_ic = &ic[18];
1858 }
1859 
1860 
1861 /*
1862  * netbsd_memcpy:
1863  *
1864  * The core of a NetBSD/arm memcpy.
1865  *
1866  * f01bc530: e8b15018 ldmia r1!,{r3,r4,ip,lr}
1867  * f01bc534: e8a05018 stmia r0!,{r3,r4,ip,lr}
1868  * f01bc538: e8b15018 ldmia r1!,{r3,r4,ip,lr}
1869  * f01bc53c: e8a05018 stmia r0!,{r3,r4,ip,lr}
1870  * f01bc540: e2522020 subs r2,r2,#0x20
1871  * f01bc544: aafffff9 bge 0xf01bc530
1872  */
1874 {
1875  unsigned char *page_0, *page_1;
1876  uint32_t addr_r0, addr_r1;
1877 
1878  do {
1879  addr_r0 = cpu->cd.arm.r[0];
1880  addr_r1 = cpu->cd.arm.r[1];
1881 
1882  /* printf("addr_r0 = %08x r1 = %08x\n", addr_r0, addr_r1); */
1883 
1884  /* Crossing a page boundary? Then continue non-combined. */
1885  if ((addr_r0 & 0xfff) + 32 > 0x1000 ||
1886  (addr_r1 & 0xfff) + 32 > 0x1000) {
1887  instr(multi_0x08b15018)(cpu, ic);
1888  return;
1889  }
1890 
1891  page_0 = cpu->cd.arm.host_store[addr_r0 >> 12];
1892  page_1 = cpu->cd.arm.host_store[addr_r1 >> 12];
1893 
1894  /* No page translations? Continue non-combined. */
1895  if (page_0 == NULL || page_1 == NULL) {
1896  instr(multi_0x08b15018)(cpu, ic);
1897  return;
1898  }
1899 
1900  memcpy(page_0 + (addr_r0 & 0xfff),
1901  page_1 + (addr_r1 & 0xfff), 32);
1902  cpu->cd.arm.r[0] = addr_r0 + 32;
1903  cpu->cd.arm.r[1] = addr_r1 + 32;
1904 
1905  cpu->n_translated_instrs += 4;
1906 
1907  instr(subs)(cpu, ic + 4);
1909 
1910  /* Loop while greater or equal: */
1912  } while (((cpu->cd.arm.flags & ARM_F_N)?1:0) ==
1913  ((cpu->cd.arm.flags & ARM_F_V)?1:0));
1914 
1915  /* Continue at the instruction after the bge: */
1916  cpu->cd.arm.next_ic = &ic[6];
1918 }
1919 
1920 
1921 /*
1922  * netbsd_cacheclean:
1923  *
1924  * The core of a NetBSD/arm cache clean routine, variant 1:
1925  *
1926  * f015f88c: e4902020 ldr r2,[r0],#32
1927  * f015f890: e2511020 subs r1,r1,#0x20
1928  * f015f894: 1afffffc bne 0xf015f88c
1929  * f015f898: ee070f9a mcr 15,0,r0,cr7,cr10,4
1930  */
1932 {
1933  uint32_t r1 = cpu->cd.arm.r[1];
1934  cpu->n_translated_instrs += ((r1 >> 5) * 3);
1935  cpu->cd.arm.r[0] += r1;
1936  cpu->cd.arm.r[1] = 0;
1937  cpu->cd.arm.next_ic = &ic[4];
1938 }
1939 
1940 
1941 /*
1942  * netbsd_cacheclean2:
1943  *
1944  * The core of a NetBSD/arm cache clean routine, variant 2:
1945  *
1946  * f015f93c: ee070f3a mcr 15,0,r0,cr7,cr10,1
1947  * f015f940: ee070f36 mcr 15,0,r0,cr7,cr6,1
1948  * f015f944: e2800020 add r0,r0,#0x20
1949  * f015f948: e2511020 subs r1,r1,#0x20
1950  * f015f94c: 8afffffa bhi 0xf015f93c
1951  */
1953 {
1954  cpu->n_translated_instrs += ((cpu->cd.arm.r[1] >> 5) * 5) - 1;
1955  cpu->cd.arm.next_ic = &ic[5];
1956 }
1957 
1958 
1959 /*
1960  * netbsd_scanc:
1961  *
1962  * f01bccbc: e5d13000 ldrb r3,[r1]
1963  * f01bccc0: e7d23003 ldrb r3,[r2,r3]
1964  * f01bccc4: e113000c tsts r3,ip
1965  */
1967 {
1968  unsigned char *page = cpu->cd.arm.host_load[cpu->cd.arm.r[1] >> 12];
1969  uint32_t t;
1970 
1971  if (page == NULL) {
1972  instr(load_w0_byte_u1_p1_imm)(cpu, ic);
1973  return;
1974  }
1975 
1976  t = page[cpu->cd.arm.r[1] & 0xfff];
1977  t += cpu->cd.arm.r[2];
1978  page = cpu->cd.arm.host_load[t >> 12];
1979 
1980  if (page == NULL) {
1981  instr(load_w0_byte_u1_p1_imm)(cpu, ic);
1982  return;
1983  }
1984 
1985  cpu->cd.arm.r[3] = page[t & 0xfff];
1986 
1987  t = cpu->cd.arm.r[3] & cpu->cd.arm.r[ARM_IP];
1988  cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N);
1989  if (t == 0)
1990  cpu->cd.arm.flags |= ARM_F_Z;
1991 
1992  cpu->n_translated_instrs += 2;
1993  cpu->cd.arm.next_ic = &ic[3];
1994 }
1995 
1996 
1997 /*
1998  * netbsd_idle:
1999  *
2000  * L: ldr rX,[rY]
2001  * teqs rX,#0
2002  * bne X (samepage)
2003  * teqs rZ,#0
2004  * beq L (samepage)
2005  * ....
2006  * X: somewhere else on the same page
2007  */
2008 X(netbsd_idle)
2009 {
2010  uint32_t rY = reg(ic[0].arg[0]);
2011  uint32_t rZ = reg(ic[3].arg[0]);
2012  uint32_t *p;
2013  uint32_t rX;
2014 
2015  p = (uint32_t *) cpu->cd.arm.host_load[rY >> 12];
2016  if (p == NULL) {
2017  instr(load_w0_word_u1_p1_imm)(cpu, ic);
2018  return;
2019  }
2020 
2021  rX = p[(rY & 0xfff) >> 2];
2022  /* No need to convert endianness, since it's only a 0-test. */
2023 
2024  /* This makes execution continue on the first teqs instruction,
2025  which is fine. */
2026  if (rX != 0) {
2027  instr(load_w0_word_u1_p1_imm)(cpu, ic);
2028  return;
2029  }
2030 
2031  if (rZ == 0) {
2032  static int x = 0;
2033 
2034  /* Synch the program counter. */
2035  uint32_t low_pc = ((size_t)ic - (size_t)
2036  cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
2037  cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1)
2039  cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
2040 
2041  /* Quasi-idle for a while: */
2042  cpu->has_been_idling = 1;
2043  if (cpu->machine->ncpus == 1 && (++x) == 100) {
2044  usleep(50);
2045  x = 0;
2046  }
2047 
2049  cpu->cd.arm.next_ic = &nothing_call;
2050  return;
2051  }
2052 
2053  cpu->cd.arm.next_ic = &ic[5];
2054 }
2055 
2056 
2057 /*
2058  * strlen:
2059  *
2060  * S: e5f03001 ldrb rY,[rX,#1]!
2061  * e3530000 cmps rY,#0
2062  * 1afffffc bne S
2063  */
2065 {
2066  unsigned int n_loops = 0;
2067  uint32_t rY, rX = reg(ic[0].arg[0]);
2068  unsigned char *p;
2069 
2070  do {
2071  rX ++;
2072  p = cpu->cd.arm.host_load[rX >> 12];
2073  if (p == NULL) {
2074  cpu->n_translated_instrs += (n_loops * 3);
2075  instr(load_w1_byte_u1_p1_imm)(cpu, ic);
2076  return;
2077  }
2078 
2079  rY = reg(ic[0].arg[2]) = p[rX & 0xfff]; /* load */
2080  reg(ic[0].arg[0]) = rX; /* writeback */
2081  n_loops ++;
2082 
2083  /* Compare rY to zero: */
2084  cpu->cd.arm.flags = ARM_F_C;
2085  if (rY == 0)
2086  cpu->cd.arm.flags |= ARM_F_Z;
2087  } while (rY != 0);
2088 
2089  cpu->n_translated_instrs += (n_loops * 3) - 1;
2090  cpu->cd.arm.next_ic = &ic[3];
2091 }
2092 
2093 
2094 /*
2095  * xchg:
2096  *
2097  * e02YX00X eor rX,rY,rX
2098  * e02XY00Y eor rY,rX,rY
2099  * e02YX00X eor rX,rY,rX
2100  */
2102 {
2103  uint32_t tmp = reg(ic[0].arg[0]);
2104  cpu->n_translated_instrs += 2;
2105  cpu->cd.arm.next_ic = &ic[3];
2106  reg(ic[0].arg[0]) = reg(ic[1].arg[0]);
2107  reg(ic[1].arg[0]) = tmp;
2108 }
2109 
2110 
2111 /*
2112  * netbsd_copyin:
2113  *
2114  * e4b0a004 ldrt sl,[r0],#4
2115  * e4b0b004 ldrt fp,[r0],#4
2116  * e4b06004 ldrt r6,[r0],#4
2117  * e4b07004 ldrt r7,[r0],#4
2118  * e4b08004 ldrt r8,[r0],#4
2119  * e4b09004 ldrt r9,[r0],#4
2120  */
2122 {
2123  uint32_t r0 = cpu->cd.arm.r[0], ofs = (r0 & 0xffc), index = r0 >> 12;
2124  unsigned char *p = cpu->cd.arm.host_load[index];
2125  uint32_t *p32 = (uint32_t *) p, *q32;
2126  int ok = cpu->cd.arm.is_userpage[index >> 5] & (1 << (index & 31));
2127 
2128  if (ofs > 0x1000 - 6*4 || !ok || p == NULL) {
2129  instr(load_w1_word_u1_p0_imm)(cpu, ic);
2130  return;
2131  }
2132  q32 = &cpu->cd.arm.r[6];
2133  ofs >>= 2;
2134  q32[0] = p32[ofs+2];
2135  q32[1] = p32[ofs+3];
2136  q32[2] = p32[ofs+4];
2137  q32[3] = p32[ofs+5];
2138  q32[4] = p32[ofs+0];
2139  q32[5] = p32[ofs+1];
2140  cpu->cd.arm.r[0] = r0 + 24;
2141  cpu->n_translated_instrs += 5;
2142  cpu->cd.arm.next_ic = &ic[6];
2143 }
2144 
2145 
2146 /*
2147  * netbsd_copyout:
2148  *
2149  * e4a18004 strt r8,[r1],#4
2150  * e4a19004 strt r9,[r1],#4
2151  * e4a1a004 strt sl,[r1],#4
2152  * e4a1b004 strt fp,[r1],#4
2153  * e4a16004 strt r6,[r1],#4
2154  * e4a17004 strt r7,[r1],#4
2155  */
2157 {
2158  uint32_t r1 = cpu->cd.arm.r[1], ofs = (r1 & 0xffc), index = r1 >> 12;
2159  unsigned char *p = cpu->cd.arm.host_store[index];
2160  uint32_t *p32 = (uint32_t *) p, *q32;
2161  int ok = cpu->cd.arm.is_userpage[index >> 5] & (1 << (index & 31));
2162 
2163  if (ofs > 0x1000 - 6*4 || !ok || p == NULL) {
2164  instr(store_w1_word_u1_p0_imm)(cpu, ic);
2165  return;
2166  }
2167  q32 = &cpu->cd.arm.r[6];
2168  ofs >>= 2;
2169  p32[ofs ] = q32[2];
2170  p32[ofs+1] = q32[3];
2171  p32[ofs+2] = q32[4];
2172  p32[ofs+3] = q32[5];
2173  p32[ofs+4] = q32[0];
2174  p32[ofs+5] = q32[1];
2175  cpu->cd.arm.r[1] = r1 + 24;
2176  cpu->n_translated_instrs += 5;
2177  cpu->cd.arm.next_ic = &ic[6];
2178 }
2179 
2180 
2181 /*
2182  * cmps by 0, followed by beq (inside the same page):
2183  */
2184 X(cmps0_beq_samepage)
2185 {
2186  uint32_t a = reg(ic->arg[0]);
2188  if (a == 0) {
2189  cpu->cd.arm.flags = ARM_F_Z | ARM_F_C;
2190  } else {
2191  /* Semi-ugly hack which sets the negative-bit if a < 0: */
2192  cpu->cd.arm.flags = ARM_F_C | ((a >> 28) & 8);
2193  }
2194  if (a == 0)
2195  cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0];
2196  else
2197  cpu->cd.arm.next_ic = &ic[2];
2198 }
2199 
2200 
2201 /*
2202  * cmps followed by beq (inside the same page):
2203  */
2204 X(cmps_beq_samepage)
2205 {
2206  uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a - b;
2208  cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0;
2209  if (((int32_t)a >= 0 && (int32_t)b < 0 && (int32_t)c < 0) ||
2210  ((int32_t)a < 0 && (int32_t)b >= 0 && (int32_t)c >= 0))
2211  cpu->cd.arm.flags |= ARM_F_V;
2212  if (c == 0) {
2213  cpu->cd.arm.flags |= ARM_F_Z;
2214  cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0];
2215  } else {
2216  cpu->cd.arm.next_ic = &ic[2];
2217  if (c & 0x80000000)
2218  cpu->cd.arm.flags |= ARM_F_N;
2219  }
2220 }
2221 
2222 
2223 /*
2224  * cmps followed by beq (not the same page):
2225  */
2226 X(cmps_0_beq)
2227 {
2228  uint32_t a = reg(ic->arg[0]);
2230  if (a == 0) {
2231  cpu->cd.arm.flags = ARM_F_Z | ARM_F_C;
2232  cpu->pc = (uint32_t)(((uint32_t)cpu->pc & 0xfffff000)
2233  + (int32_t)ic[1].arg[0]);
2234  quick_pc_to_pointers_arm(cpu);
2235  } else {
2236  /* Semi-ugly hack which sets the negative-bit if a < 0: */
2237  cpu->cd.arm.flags = ARM_F_C | ((a >> 28) & 8);
2238  cpu->cd.arm.next_ic = &ic[2];
2239  }
2240 }
2241 X(cmps_pos_beq)
2242 {
2243  uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a - b;
2245  cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0;
2246  if ((int32_t)a < 0 && (int32_t)c >= 0)
2247  cpu->cd.arm.flags |= ARM_F_V;
2248  if (c == 0) {
2249  cpu->cd.arm.flags |= ARM_F_Z;
2250  cpu->pc = (uint32_t)(((uint32_t)cpu->pc & 0xfffff000)
2251  + (int32_t)ic[1].arg[0]);
2252  quick_pc_to_pointers_arm(cpu);
2253  } else {
2254  cpu->cd.arm.next_ic = &ic[2];
2255  if (c & 0x80000000)
2256  cpu->cd.arm.flags |= ARM_F_N;
2257  }
2258 }
2259 X(cmps_neg_beq)
2260 {
2261  uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a - b;
2263  cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0;
2264  if ((int32_t)a >= 0 && (int32_t)c < 0)
2265  cpu->cd.arm.flags |= ARM_F_V;
2266  if (c == 0) {
2267  cpu->cd.arm.flags |= ARM_F_Z;
2268  cpu->pc = (uint32_t)(((uint32_t)cpu->pc & 0xfffff000)
2269  + (int32_t)ic[1].arg[0]);
2270  quick_pc_to_pointers_arm(cpu);
2271  } else {
2272  cpu->cd.arm.next_ic = &ic[2];
2273  if (c & 0x80000000)
2274  cpu->cd.arm.flags |= ARM_F_N;
2275  }
2276 }
2277 
2278 
2279 /*
2280  * cmps by 0, followed by bne (inside the same page):
2281  */
2282 X(cmps0_bne_samepage)
2283 {
2284  uint32_t a = reg(ic->arg[0]);
2286  if (a == 0) {
2287  cpu->cd.arm.flags = ARM_F_Z | ARM_F_C;
2288  } else {
2289  /* Semi-ugly hack which sets the negative-bit if a < 0: */
2290  cpu->cd.arm.flags = ARM_F_C | ((a >> 28) & 8);
2291  }
2292  if (a == 0)
2293  cpu->cd.arm.next_ic = &ic[2];
2294  else
2295  cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0];
2296 }
2297 
2298 
2299 /*
2300  * cmps followed by bne (inside the same page):
2301  */
2302 X(cmps_bne_samepage)
2303 {
2304  uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a - b;
2306  cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0;
2307  if (((int32_t)a >= 0 && (int32_t)b < 0 && (int32_t)c < 0) ||
2308  ((int32_t)a < 0 && (int32_t)b >= 0 && (int32_t)c >= 0))
2309  cpu->cd.arm.flags |= ARM_F_V;
2310  if (c == 0) {
2311  cpu->cd.arm.flags |= ARM_F_Z;
2312  cpu->cd.arm.next_ic = &ic[2];
2313  } else {
2314  if (c & 0x80000000)
2315  cpu->cd.arm.flags |= ARM_F_N;
2316  cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0];
2317  }
2318 }
2319 
2320 
2321 /*
2322  * cmps followed by bcc (inside the same page):
2323  */
2324 X(cmps_bcc_samepage)
2325 {
2326  uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a - b;
2328  cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0;
2329  if (c & 0x80000000)
2330  cpu->cd.arm.flags |= ARM_F_N;
2331  else if (c == 0)
2332  cpu->cd.arm.flags |= ARM_F_Z;
2333  if (((int32_t)a >= 0 && (int32_t)b < 0 && (int32_t)c < 0) ||
2334  ((int32_t)a < 0 && (int32_t)b >= 0 && (int32_t)c >= 0))
2335  cpu->cd.arm.flags |= ARM_F_V;
2336  if (a >= b)
2337  cpu->cd.arm.next_ic = &ic[2];
2338  else
2339  cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0];
2340 }
2341 
2342 
2343 /*
2344  * cmps (reg) followed by bcc (inside the same page):
2345  */
2346 X(cmps_reg_bcc_samepage)
2347 {
2348  uint32_t a = reg(ic->arg[0]), b = reg(ic->arg[1]), c = a - b;
2350  cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0;
2351  if (c & 0x80000000)
2352  cpu->cd.arm.flags |= ARM_F_N;
2353  else if (c == 0)
2354  cpu->cd.arm.flags |= ARM_F_Z;
2355  if (((int32_t)a >= 0 && (int32_t)b < 0 && (int32_t)c < 0) ||
2356  ((int32_t)a < 0 && (int32_t)b >= 0 && (int32_t)c >= 0))
2357  cpu->cd.arm.flags |= ARM_F_V;
2358  if (a >= b)
2359  cpu->cd.arm.next_ic = &ic[2];
2360  else
2361  cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0];
2362 }
2363 
2364 
2365 /*
2366  * cmps followed by bhi (inside the same page):
2367  */
2368 X(cmps_bhi_samepage)
2369 {
2370  uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a - b;
2372  cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0;
2373  if (c & 0x80000000)
2374  cpu->cd.arm.flags |= ARM_F_N;
2375  else if (c == 0)
2376  cpu->cd.arm.flags |= ARM_F_Z;
2377  if (((int32_t)a >= 0 && (int32_t)b < 0 && (int32_t)c < 0) ||
2378  ((int32_t)a < 0 && (int32_t)b >= 0 && (int32_t)c >= 0))
2379  cpu->cd.arm.flags |= ARM_F_V;
2380  if (a > b)
2381  cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0];
2382  else
2383  cpu->cd.arm.next_ic = &ic[2];
2384 }
2385 
2386 
2387 /*
2388  * cmps (reg) followed by bhi (inside the same page):
2389  */
2390 X(cmps_reg_bhi_samepage)
2391 {
2392  uint32_t a = reg(ic->arg[0]), b = reg(ic->arg[1]), c = a - b;
2394  cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0;
2395  if (c & 0x80000000)
2396  cpu->cd.arm.flags |= ARM_F_N;
2397  else if (c == 0)
2398  cpu->cd.arm.flags |= ARM_F_Z;
2399  if (((int32_t)a >= 0 && (int32_t)b < 0 && (int32_t)c < 0) ||
2400  ((int32_t)a < 0 && (int32_t)b >= 0 && (int32_t)c >= 0))
2401  cpu->cd.arm.flags |= ARM_F_V;
2402  if (a > b)
2403  cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0];
2404  else
2405  cpu->cd.arm.next_ic = &ic[2];
2406 }
2407 
2408 
2409 /*
2410  * cmps followed by bgt (inside the same page):
2411  */
2412 X(cmps_bgt_samepage)
2413 {
2414  uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a - b;
2416  cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0;
2417  if (c & 0x80000000)
2418  cpu->cd.arm.flags |= ARM_F_N;
2419  else if (c == 0)
2420  cpu->cd.arm.flags |= ARM_F_Z;
2421  if (((int32_t)a >= 0 && (int32_t)b < 0 && (int32_t)c < 0) ||
2422  ((int32_t)a < 0 && (int32_t)b >= 0 && (int32_t)c >= 0))
2423  cpu->cd.arm.flags |= ARM_F_V;
2424  if ((int32_t)a > (int32_t)b)
2425  cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0];
2426  else
2427  cpu->cd.arm.next_ic = &ic[2];
2428 }
2429 
2430 
2431 /*
2432  * cmps followed by ble (inside the same page):
2433  */
2434 X(cmps_ble_samepage)
2435 {
2436  uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a - b;
2438  cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0;
2439  if (c & 0x80000000)
2440  cpu->cd.arm.flags |= ARM_F_N;
2441  else if (c == 0)
2442  cpu->cd.arm.flags |= ARM_F_Z;
2443  if (((int32_t)a >= 0 && (int32_t)b < 0 && (int32_t)c < 0) ||
2444  ((int32_t)a < 0 && (int32_t)b >= 0 && (int32_t)c >= 0))
2445  cpu->cd.arm.flags |= ARM_F_V;
2446  if ((int32_t)a <= (int32_t)b)
2447  cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0];
2448  else
2449  cpu->cd.arm.next_ic = &ic[2];
2450 }
2451 
2452 
2453 /*
2454  * teqs followed by beq (inside the same page):
2455  */
2456 X(teqs_beq_samepage)
2457 {
2458  uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a ^ b;
2460  cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N);
2461  if (c == 0) {
2462  cpu->cd.arm.flags |= ARM_F_Z;
2463  cpu->cd.arm.next_ic = (struct arm_instr_call *)
2464  ic[1].arg[0];
2465  } else {
2466  if (c & 0x80000000)
2467  cpu->cd.arm.flags |= ARM_F_N;
2468  cpu->cd.arm.next_ic = &ic[2];
2469  }
2470 }
2471 
2472 
2473 /*
2474  * tsts followed by beq (inside the same page):
2475  * (arg[1] must not have its highest bit set))
2476  */
2477 X(tsts_lo_beq_samepage)
2478 {
2479  uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a & b;
2481  cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N);
2482  if (c == 0)
2483  cpu->cd.arm.flags |= ARM_F_Z;
2484  if (c == 0)
2485  cpu->cd.arm.next_ic = (struct arm_instr_call *)
2486  ic[1].arg[0];
2487  else
2488  cpu->cd.arm.next_ic = &ic[2];
2489 }
2490 
2491 
2492 /*
2493  * teqs followed by bne (inside the same page):
2494  */
2495 X(teqs_bne_samepage)
2496 {
2497  uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a ^ b;
2499  cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N);
2500  if (c == 0) {
2501  cpu->cd.arm.flags |= ARM_F_Z;
2502  } else {
2503  if (c & 0x80000000)
2504  cpu->cd.arm.flags |= ARM_F_N;
2505  }
2506  if (c == 0)
2507  cpu->cd.arm.next_ic = &ic[2];
2508  else
2509  cpu->cd.arm.next_ic = (struct arm_instr_call *)
2510  ic[1].arg[0];
2511 }
2512 
2513 
2514 /*
2515  * tsts followed by bne (inside the same page):
2516  * (arg[1] must not have its highest bit set))
2517  */
2518 X(tsts_lo_bne_samepage)
2519 {
2520  uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a & b;
2522  cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N);
2523  if (c == 0)
2524  cpu->cd.arm.flags |= ARM_F_Z;
2525  if (c == 0)
2526  cpu->cd.arm.next_ic = &ic[2];
2527  else
2528  cpu->cd.arm.next_ic = (struct arm_instr_call *)
2529  ic[1].arg[0];
2530 }
2531 
2532 
2533 /*****************************************************************************/
2534 
2535 
2536 X(end_of_page)
2537 {
2538  /* Update the PC: (offset 0, but on the next page) */
2541 
2542  /* Find the new physical page and update the translation pointers: */
2543  quick_pc_to_pointers_arm(cpu);
2544 
2545  /* end_of_page doesn't count as an executed instruction: */
2547 }
2548 
2549 
2550 /*****************************************************************************/
2551 
2552 
2553 /*
2554  * Combine: netbsd_memset():
2555  *
2556  * Check for the core of a NetBSD/arm memset; large memsets use a sequence
2557  * of 16 store-multiple instructions, each storing 2 registers at a time.
2558  */
2560  struct arm_instr_call *ic, int low_addr)
2561 {
2562 #ifdef HOST_LITTLE_ENDIAN
2563  int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2565 
2566  if (n_back >= 17) {
2567  int i;
2568  for (i=-16; i<=-1; i++)
2569  if (ic[i].f != instr(multi_0x08ac000c__ge))
2570  return;
2571  if (ic[-17].f == instr(subs) &&
2572  ic[-17].arg[0]==ic[-17].arg[2] && ic[-17].arg[1] == 128 &&
2573  ic[ 0].f == instr(b_samepage__gt) &&
2574  ic[ 0].arg[0] == (size_t)&ic[-17]) {
2575  ic[-17].f = instr(netbsd_memset);
2576  }
2577  }
2578 #endif
2579 }
2580 
2581 
2582 /*
2583  * Combine: netbsd_memcpy():
2584  *
2585  * Check for the core of a NetBSD/arm memcpy; large memcpys use a
2586  * sequence of ldmia instructions.
2587  */
2588 void COMBINE(netbsd_memcpy)(struct cpu *cpu, struct arm_instr_call *ic,
2589  int low_addr)
2590 {
2591 #ifdef HOST_LITTLE_ENDIAN
2592  int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2594 
2595  if (n_back >= 5) {
2596  if (ic[-5].f==instr(multi_0x08b15018) &&
2597  ic[-4].f==instr(multi_0x08a05018) &&
2598  ic[-3].f==instr(multi_0x08b15018) &&
2599  ic[-2].f==instr(multi_0x08a05018) &&
2600  ic[-1].f == instr(subs) &&
2601  ic[-1].arg[0]==ic[-1].arg[2] && ic[-1].arg[1] == 0x20 &&
2602  ic[ 0].f == instr(b_samepage__ge) &&
2603  ic[ 0].arg[0] == (size_t)&ic[-5]) {
2604  ic[-5].f = instr(netbsd_memcpy);
2605  }
2606  }
2607 #endif
2608 }
2609 
2610 
2611 /*
2612  * Combine: netbsd_cacheclean():
2613  *
2614  * Check for the core of a NetBSD/arm cache clean. (There are two variants.)
2615  */
2617  struct arm_instr_call *ic, int low_addr)
2618 {
2619  int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2621 
2622  if (n_back >= 3) {
2623  if (ic[-3].f==instr(load_w0_word_u1_p0_imm) &&
2624  ic[-2].f == instr(subs) &&
2625  ic[-2].arg[0]==ic[-2].arg[2] && ic[-2].arg[1] == 0x20 &&
2626  ic[-1].f == instr(b_samepage__ne) &&
2627  ic[-1].arg[0] == (size_t)&ic[-3]) {
2628  ic[-3].f = instr(netbsd_cacheclean);
2629  }
2630  }
2631 }
2632 
2633 
2634 /*
2635  * Combine: netbsd_cacheclean2():
2636  *
2637  * Check for the core of a NetBSD/arm cache clean. (Second variant.)
2638  */
2640  struct arm_instr_call *ic, int low_addr)
2641 {
2642  int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2644 
2645  if (n_back >= 4) {
2646  if (ic[-4].f == instr(mcr_mrc) && ic[-4].arg[0] == 0xee070f3a &&
2647  ic[-3].f == instr(mcr_mrc) && ic[-3].arg[0] == 0xee070f36 &&
2648  ic[-2].f == instr(add) &&
2649  ic[-2].arg[0]==ic[-2].arg[2] && ic[-2].arg[1] == 0x20 &&
2650  ic[-1].f == instr(subs) &&
2651  ic[-1].arg[0]==ic[-1].arg[2] && ic[-1].arg[1] == 0x20) {
2652  ic[-4].f = instr(netbsd_cacheclean2);
2653  }
2654  }
2655 }
2656 
2657 
2658 /*
2659  * Combine: netbsd_scanc():
2660  */
2661 void COMBINE(netbsd_scanc)(struct cpu *cpu,
2662  struct arm_instr_call *ic, int low_addr)
2663 {
2664  int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2666 
2667  if (n_back < 2)
2668  return;
2669 
2670  if (ic[-2].f == instr(load_w0_byte_u1_p1_imm) &&
2671  ic[-2].arg[0] == (size_t)(&cpu->cd.arm.r[1]) &&
2672  ic[-2].arg[1] == 0 &&
2673  ic[-2].arg[2] == (size_t)(&cpu->cd.arm.r[3]) &&
2674  ic[-1].f == instr(load_w0_byte_u1_p1_reg) &&
2675  ic[-1].arg[0] == (size_t)(&cpu->cd.arm.r[2]) &&
2676  ic[-1].arg[1] == (size_t)arm_r_r3_t0_c0 &&
2677  ic[-1].arg[2] == (size_t)(&cpu->cd.arm.r[3])) {
2678  ic[-2].f = instr(netbsd_scanc);
2679  }
2680 }
2681 
2682 
2683 /*
2684  * Combine: strlen():
2685  */
2686 void COMBINE(strlen)(struct cpu *cpu,
2687  struct arm_instr_call *ic, int low_addr)
2688 {
2689  int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2691 
2692  if (n_back < 2)
2693  return;
2694 
2695  if (ic[-2].f == instr(load_w1_byte_u1_p1_imm) &&
2696  ic[-2].arg[1] == 1 &&
2697  ic[-2].arg[2] == (size_t)(&cpu->cd.arm.r[3]) &&
2698  ic[-1].f == instr(cmps) &&
2699  ic[-1].arg[0] == (size_t)(&cpu->cd.arm.r[3]) &&
2700  ic[-1].arg[1] == 0) {
2701  ic[-2].f = instr(strlen);
2702  }
2703 }
2704 
2705 
2706 /*
2707  * Combine: xchg():
2708  */
2709 void COMBINE(xchg)(struct cpu *cpu,
2710  struct arm_instr_call *ic, int low_addr)
2711 {
2712  int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2714  size_t a, b;
2715 
2716  if (n_back < 2)
2717  return;
2718 
2719  a = ic[-2].arg[0]; b = ic[-1].arg[0];
2720 
2721  if (ic[-2].f == instr(eor_regshort) &&
2722  ic[-1].f == instr(eor_regshort) &&
2723  ic[-2].arg[0] == a && ic[-2].arg[1] == b && ic[-2].arg[2] == b &&
2724  ic[-1].arg[0] == b && ic[-1].arg[1] == a && ic[-1].arg[2] == a &&
2725  ic[ 0].arg[0] == a && ic[ 0].arg[1] == b && ic[ 0].arg[2] == b) {
2726  ic[-2].f = instr(xchg);
2727  }
2728 }
2729 
2730 
2731 /*
2732  * Combine: netbsd_copyin():
2733  */
2735  struct arm_instr_call *ic, int low_addr)
2736 {
2737 #ifdef HOST_LITTLE_ENDIAN
2738  int i, n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2740 
2741  if (n_back < 5)
2742  return;
2743 
2744  for (i=-5; i<0; i++) {
2745  if (ic[i].f != instr(load_w1_word_u1_p0_imm) ||
2746  ic[i].arg[0] != (size_t)(&cpu->cd.arm.r[0]) ||
2747  ic[i].arg[1] != 4)
2748  return;
2749  }
2750 
2751  if (ic[-5].arg[2] == (size_t)(&cpu->cd.arm.r[10]) &&
2752  ic[-4].arg[2] == (size_t)(&cpu->cd.arm.r[11]) &&
2753  ic[-3].arg[2] == (size_t)(&cpu->cd.arm.r[6]) &&
2754  ic[-2].arg[2] == (size_t)(&cpu->cd.arm.r[7]) &&
2755  ic[-1].arg[2] == (size_t)(&cpu->cd.arm.r[8])) {
2756  ic[-5].f = instr(netbsd_copyin);
2757  }
2758 #endif
2759 }
2760 
2761 
2762 /*
2763  * Combine: netbsd_copyout():
2764  */
2766  struct arm_instr_call *ic, int low_addr)
2767 {
2768 #ifdef HOST_LITTLE_ENDIAN
2769  int i, n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2771 
2772  if (n_back < 5)
2773  return;
2774 
2775  for (i=-5; i<0; i++) {
2776  if (ic[i].f != instr(store_w1_word_u1_p0_imm) ||
2777  ic[i].arg[0] != (size_t)(&cpu->cd.arm.r[1]) ||
2778  ic[i].arg[1] != 4)
2779  return;
2780  }
2781 
2782  if (ic[-5].arg[2] == (size_t)(&cpu->cd.arm.r[8]) &&
2783  ic[-4].arg[2] == (size_t)(&cpu->cd.arm.r[9]) &&
2784  ic[-3].arg[2] == (size_t)(&cpu->cd.arm.r[10]) &&
2785  ic[-2].arg[2] == (size_t)(&cpu->cd.arm.r[11]) &&
2786  ic[-1].arg[2] == (size_t)(&cpu->cd.arm.r[6])) {
2787  ic[-5].f = instr(netbsd_copyout);
2788  }
2789 #endif
2790 }
2791 
2792 
2793 /*
2794  * Combine: cmps + beq, etc:
2795  */
2796 void COMBINE(beq_etc)(struct cpu *cpu,
2797  struct arm_instr_call *ic, int low_addr)
2798 {
2799  int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2801  if (n_back < 1)
2802  return;
2803  if (ic[0].f == instr(b__eq)) {
2804  if (ic[-1].f == instr(cmps)) {
2805  if (ic[-1].arg[1] == 0)
2806  ic[-1].f = instr(cmps_0_beq);
2807  else if (ic[-1].arg[1] & 0x80000000)
2808  ic[-1].f = instr(cmps_neg_beq);
2809  else
2810  ic[-1].f = instr(cmps_pos_beq);
2811  }
2812  return;
2813  }
2814  if (ic[0].f == instr(b_samepage__eq)) {
2815  if (ic[-1].f == instr(cmps)) {
2816  if (ic[-1].arg[1] == 0)
2817  ic[-1].f = instr(cmps0_beq_samepage);
2818  else
2819  ic[-1].f = instr(cmps_beq_samepage);
2820  }
2821  if (ic[-1].f == instr(tsts) &&
2822  !(ic[-1].arg[1] & 0x80000000)) {
2823  ic[-1].f = instr(tsts_lo_beq_samepage);
2824  }
2825  if (n_back >= 4 &&
2826  ic[-4].f == instr(load_w0_word_u1_p1_imm) &&
2827  ic[-4].arg[0] != ic[-4].arg[2] &&
2828  ic[-4].arg[1] == 0 &&
2829  ic[-4].arg[2] == ic[-3].arg[0] &&
2830  /* Note: The teqs+bne is already combined! */
2831  ic[-3].f == instr(teqs_bne_samepage) &&
2832  ic[-3].arg[1] == 0 &&
2833  ic[-2].f == instr(b_samepage__ne) &&
2834  ic[-1].f == instr(teqs) &&
2835  ic[-1].arg[0] != ic[-4].arg[0] &&
2836  ic[-1].arg[1] == 0) {
2837  ic[-4].f = instr(netbsd_idle);
2838  }
2839  if (ic[-1].f == instr(teqs)) {
2840  ic[-1].f = instr(teqs_beq_samepage);
2841  }
2842  return;
2843  }
2844  if (ic[0].f == instr(b_samepage__ne)) {
2845  if (ic[-1].f == instr(cmps)) {
2846  if (ic[-1].arg[1] == 0)
2847  ic[-1].f = instr(cmps0_bne_samepage);
2848  else
2849  ic[-1].f = instr(cmps_bne_samepage);
2850  }
2851  if (ic[-1].f == instr(tsts) &&
2852  !(ic[-1].arg[1] & 0x80000000)) {
2853  ic[-1].f = instr(tsts_lo_bne_samepage);
2854  }
2855  if (ic[-1].f == instr(teqs)) {
2856  ic[-1].f = instr(teqs_bne_samepage);
2857  }
2858  return;
2859  }
2860  if (ic[0].f == instr(b_samepage__cc)) {
2861  if (ic[-1].f == instr(cmps)) {
2862  ic[-1].f = instr(cmps_bcc_samepage);
2863  }
2864  if (ic[-1].f == instr(cmps_regshort)) {
2865  ic[-1].f = instr(cmps_reg_bcc_samepage);
2866  }
2867  return;
2868  }
2869  if (ic[0].f == instr(b_samepage__hi)) {
2870  if (ic[-1].f == instr(cmps)) {
2871  ic[-1].f = instr(cmps_bhi_samepage);
2872  }
2873  if (ic[-1].f == instr(cmps_regshort)) {
2874  ic[-1].f = instr(cmps_reg_bhi_samepage);
2875  }
2876  return;
2877  }
2878  if (ic[0].f == instr(b_samepage__gt)) {
2879  if (ic[-1].f == instr(cmps)) {
2880  ic[-1].f = instr(cmps_bgt_samepage);
2881  }
2882  return;
2883  }
2884  if (ic[0].f == instr(b_samepage__le)) {
2885  if (ic[-1].f == instr(cmps)) {
2886  ic[-1].f = instr(cmps_ble_samepage);
2887  }
2888  return;
2889  }
2890 }
2891 
2892 
2893 /*****************************************************************************/
2894 
2895 
2896 static void arm_switch_clear(struct arm_instr_call *ic, int rd,
2897  int condition_code)
2898 {
2899  switch (rd) {
2900  case 0: ic->f = cond_instr(clear_r0); break;
2901  case 1: ic->f = cond_instr(clear_r1); break;
2902  case 2: ic->f = cond_instr(clear_r2); break;
2903  case 3: ic->f = cond_instr(clear_r3); break;
2904  case 4: ic->f = cond_instr(clear_r4); break;
2905  case 5: ic->f = cond_instr(clear_r5); break;
2906  case 6: ic->f = cond_instr(clear_r6); break;
2907  case 7: ic->f = cond_instr(clear_r7); break;
2908  case 8: ic->f = cond_instr(clear_r8); break;
2909  case 9: ic->f = cond_instr(clear_r9); break;
2910  case 10: ic->f = cond_instr(clear_r10); break;
2911  case 11: ic->f = cond_instr(clear_r11); break;
2912  case 12: ic->f = cond_instr(clear_r12); break;
2913  case 13: ic->f = cond_instr(clear_r13); break;
2914  case 14: ic->f = cond_instr(clear_r14); break;
2915  }
2916 }
2917 
2918 
2919 static void arm_switch_mov1(struct arm_instr_call *ic, int rd,
2920  int condition_code)
2921 {
2922  switch (rd) {
2923  case 0: ic->f = cond_instr(mov1_r0); break;
2924  case 1: ic->f = cond_instr(mov1_r1); break;
2925  case 2: ic->f = cond_instr(mov1_r2); break;
2926  case 3: ic->f = cond_instr(mov1_r3); break;
2927  case 4: ic->f = cond_instr(mov1_r4); break;
2928  case 5: ic->f = cond_instr(mov1_r5); break;
2929  case 6: ic->f = cond_instr(mov1_r6); break;
2930  case 7: ic->f = cond_instr(mov1_r7); break;
2931  case 8: ic->f = cond_instr(mov1_r8); break;
2932  case 9: ic->f = cond_instr(mov1_r9); break;
2933  case 10: ic->f = cond_instr(mov1_r10); break;
2934  case 11: ic->f = cond_instr(mov1_r11); break;
2935  case 12: ic->f = cond_instr(mov1_r12); break;
2936  case 13: ic->f = cond_instr(mov1_r13); break;
2937  case 14: ic->f = cond_instr(mov1_r14); break;
2938  }
2939 }
2940 
2941 
2942 static void arm_switch_add1(struct arm_instr_call *ic, int rd,
2943  int condition_code)
2944 {
2945  switch (rd) {
2946  case 0: ic->f = cond_instr(add1_r0); break;
2947  case 1: ic->f = cond_instr(add1_r1); break;
2948  case 2: ic->f = cond_instr(add1_r2); break;
2949  case 3: ic->f = cond_instr(add1_r3); break;
2950  case 4: ic->f = cond_instr(add1_r4); break;
2951  case 5: ic->f = cond_instr(add1_r5); break;
2952  case 6: ic->f = cond_instr(add1_r6); break;
2953  case 7: ic->f = cond_instr(add1_r7); break;
2954  case 8: ic->f = cond_instr(add1_r8); break;
2955  case 9: ic->f = cond_instr(add1_r9); break;
2956  case 10: ic->f = cond_instr(add1_r10); break;
2957  case 11: ic->f = cond_instr(add1_r11); break;
2958  case 12: ic->f = cond_instr(add1_r12); break;
2959  case 13: ic->f = cond_instr(add1_r13); break;
2960  case 14: ic->f = cond_instr(add1_r14); break;
2961  }
2962 }
2963 
2964 
2965 /*****************************************************************************/
2966 
2967 
2968 /*
2969  * arm_instr_to_be_translated():
2970  *
2971  * Translate an instruction word into an arm_instr_call. ic is filled in with
2972  * valid data for the translated instruction, or a "nothing" instruction if
2973  * there was a translation failure. The newly translated instruction is then
2974  * executed.
2975  */
2976 X(to_be_translated)
2977 {
2978  uint32_t addr, low_pc, iword, imm = 0;
2979  unsigned char *page;
2980  unsigned char ib[4];
2981  int condition_code, main_opcode, secondary_opcode, s_bit, rn, rd, r8;
2982  int p_bit, u_bit, w_bit, l_bit, regform, rm, any_pc_reg; // , c, t
2983  void (*samepage_function)(struct cpu *, struct arm_instr_call *);
2984 
2985  /* Figure out the address of the instruction: */
2986  low_pc = ((size_t)ic - (size_t)cpu->cd.arm.cur_ic_page)
2987  / sizeof(struct arm_instr_call);
2988  addr = cpu->pc & ~((ARM_IC_ENTRIES_PER_PAGE-1) <<
2990  addr += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
2991  cpu->pc = addr;
2992  addr &= ~((1 << ARM_INSTR_ALIGNMENT_SHIFT) - 1);
2993 
2994  /* Read the instruction word from memory: */
2995  page = cpu->cd.arm.host_load[addr >> 12];
2996 
2997  if (page != NULL) {
2998  /* fatal("TRANSLATION HIT! 0x%08x\n", addr); */
2999  memcpy(ib, page + (addr & 0xfff), sizeof(ib));
3000  } else {
3001  /* fatal("TRANSLATION MISS! 0x%08x\n", addr); */
3002  if (!cpu->memory_rw(cpu, cpu->mem, addr, &ib[0],
3003  sizeof(ib), MEM_READ, CACHE_INSTRUCTION)) {
3004  fatal("to_be_translated(): "
3005  "read failed: TODO\n");
3006  return;
3007  }
3008  }
3009 
3011  iword = ib[0] + (ib[1]<<8) + (ib[2]<<16) + (ib[3]<<24);
3012  else
3013  iword = ib[3] + (ib[2]<<8) + (ib[1]<<16) + (ib[0]<<24);
3014 
3015 
3016 #define DYNTRANS_TO_BE_TRANSLATED_HEAD
3017 #include "cpu_dyntrans.cc"
3018 #undef DYNTRANS_TO_BE_TRANSLATED_HEAD
3019 
3020 
3021  /* The idea of taking bits 27..24 was found here:
3022  http://armphetamine.sourceforge.net/oldinfo.html */
3023  condition_code = iword >> 28;
3024  main_opcode = (iword >> 24) & 15;
3025  secondary_opcode = (iword >> 21) & 15;
3026  u_bit = iword & 0x00800000;
3027  w_bit = iword & 0x00200000;
3028  s_bit = l_bit = iword & 0x00100000;
3029  rn = (iword >> 16) & 15;
3030  rd = (iword >> 12) & 15;
3031  r8 = (iword >> 8) & 15;
3032  // c = (iword >> 7) & 31;
3033  // t = (iword >> 4) & 7;
3034  rm = iword & 15;
3035 
3036  /*
3037  * Translate the instruction:
3038  */
3039 
3040  if ((iword >> 28) == 0xf) {
3041  /* The "never" condition is nowadays used for special encodings. */
3042  if ((iword & 0xfc70f000) == 0xf450f000) {
3043  /* Preload: TODO. Treat as NOP for now. */
3044  ic->f = instr(nop);
3045  goto okay;
3046  }
3047 
3048  if (iword == 0xf10c0040) {
3049  /* cpsid f. Treat as NOP for now. */
3050  ic->f = instr(nop);
3051  goto okay;
3052  }
3053 
3054  if (iword == 0xf10c0080) {
3055  /* cpsid i. Treat as NOP for now. */
3056  ic->f = instr(nop);
3057  goto okay;
3058  }
3059 
3060  if (iword == 0xf57ff04f) {
3061  /* dsb sy. Treat as NOP for now. */
3062  ic->f = instr(nop);
3063  goto okay;
3064  }
3065 
3066  if (iword == 0xf57ff05f) {
3067  /* dmb sy. Treat as NOP for now. */
3068  ic->f = instr(nop);
3069  goto okay;
3070  }
3071 
3072  if (iword == 0xf57ff06f) {
3073  /* isb sy. Treat as NOP for now. */
3074  ic->f = instr(nop);
3075  goto okay;
3076  }
3077 
3078  switch (main_opcode) {
3079  case 0xa:
3080  case 0xb:
3081  ic->f = instr(blx_imm);
3082 
3083  /* arg 1 = offset of current instruction */
3084  ic->arg[1] = addr & 0xffc;
3085 
3086  /* arg 0 = relative jump distance + 1 (to enable THUMB) */
3087  ic->arg[0] = (iword & 0x00ffffff) << 2;
3088  /* Sign-extend: */
3089  if (ic->arg[0] & 0x02000000)
3090  ic->arg[0] |= 0xfc000000;
3091  if (main_opcode == 0xb)
3092  ic->arg[0] += 2;
3093  ic->arg[0] = (int32_t)(ic->arg[0] + 8 + 1);
3094  break;
3095  default:
3096  goto bad;
3097  }
3098  goto okay;
3099  }
3100 
3101  switch (main_opcode) {
3102 
3103  case 0x0:
3104  case 0x1:
3105  case 0x2:
3106  case 0x3:
3107  /* Check special cases first: */
3108  if ((iword & 0x0ff00fff) == 0x01900f9f) {
3109  ic->arg[0] = (size_t)(&cpu->cd.arm.r[rd]);
3110  ic->arg[1] = (size_t)(&cpu->cd.arm.r[rn]);
3111  ic->arg[2] = 0;
3112 
3113  if (rd == ARM_PC || rn == ARM_PC) {
3114  if (!cpu->translation_readahead)
3115  fatal("ldrex with pc register: TODO\n");
3116  goto bad;
3117  }
3118 
3119  ic->f = cond_instr(ldrex);
3120  break;
3121  }
3122 
3123  if ((iword & 0x0ff00ff0) == 0x01800f90) {
3124  ic->arg[0] = (size_t)(&cpu->cd.arm.r[rd]);
3125  ic->arg[1] = (size_t)(&cpu->cd.arm.r[rn]);
3126  ic->arg[2] = (size_t)(&cpu->cd.arm.r[rm]);
3127 
3128  if (rd == ARM_PC || rm == ARM_PC || rn == ARM_PC ||
3129  rd == rm || rd == rn) {
3130  if (!cpu->translation_readahead)
3131  fatal("strex with bad register: TODO\n");
3132  goto bad;
3133  }
3134 
3135  ic->f = cond_instr(strex);
3136  break;
3137  }
3138 
3139  if ((iword & 0x0ff000f0) == 0x00600090) {
3140  ic->arg[0] = iword;
3141  ic->f = cond_instr(mls);
3142  break;
3143  }
3144 
3145  if ((iword & 0x0fc000f0) == 0x00000090) {
3146  /*
3147  * Multiplication:
3148  * xxxx0000 00ASdddd nnnnssss 1001mmmm (Rd,Rm,Rs[,Rn])
3149  */
3150  if (iword & 0x00200000) {
3151  if (s_bit)
3152  ic->f = cond_instr(mlas);
3153  else
3154  ic->f = cond_instr(mla);
3155  ic->arg[0] = iword;
3156  } else {
3157  if (s_bit)
3158  ic->f = cond_instr(muls);
3159  else
3160  ic->f = cond_instr(mul);
3161  /* NOTE: rn means rd in this case: */
3162  ic->arg[0] = (size_t)(&cpu->cd.arm.r[rn]);
3163  ic->arg[1] = (size_t)(&cpu->cd.arm.r[rm]);
3164  ic->arg[2] = (size_t)(&cpu->cd.arm.r[r8]);
3165  }
3166  break;
3167  }
3168  if ((iword & 0x0f8000f0) == 0x00800090) {
3169  /* Long multiplication: */
3170  if (s_bit) {
3171  if (!cpu->translation_readahead)
3172  fatal("TODO: sbit mull\n");
3173  goto bad;
3174  }
3175  ic->f = cond_instr(mull);
3176  ic->arg[0] = iword;
3177  break;
3178  }
3179  if ((iword & 0x0f900ff0) == 0x01000050) {
3180  if (!cpu->translation_readahead)
3181  fatal("TODO: q{,d}{add,sub}\n");
3182  goto bad;
3183  }
3184  if ((iword & 0x0ff000d0) == 0x01200010) {
3185  /* bx or blx */
3186  if (iword & 0x20)
3187  ic->f = cond_instr(blx_reg);
3188  else {
3189  if (cpu->machine->show_trace_tree &&
3190  rm == ARM_LR)
3191  ic->f = cond_instr(bx_trace);
3192  else
3193  ic->f = cond_instr(bx);
3194  }
3195  ic->arg[0] = (size_t)(&cpu->cd.arm.r[rm]);
3196  ic->arg[2] = (addr & 0xffc) + 4;
3197  break;
3198  }
3199  if ((iword & 0x0fb00ff0) == 0x1000090) {
3200  if (iword & 0x00400000)
3201  ic->f = cond_instr(swpb);
3202  else
3203  ic->f = cond_instr(swp);
3204  ic->arg[0] = (size_t)(&cpu->cd.arm.r[rd]);
3205  ic->arg[1] = (size_t)(&cpu->cd.arm.r[rm]);
3206  ic->arg[2] = (size_t)(&cpu->cd.arm.r[rn]);
3207  break;
3208  }
3209  if ((iword & 0x0fff0ff0) == 0x016f0f10) {
3210  ic->f = cond_instr(clz);
3211  ic->arg[0] = (size_t)(&cpu->cd.arm.r[rm]);
3212  ic->arg[1] = (size_t)(&cpu->cd.arm.r[rd]);
3213  break;
3214  }
3215  if ((iword & 0x0ff00090) == 0x01000080) {
3216  /* TODO: smlaXX */
3217  goto bad;
3218  }
3219  if ((iword & 0x0ff00090) == 0x01400080) {
3220  /* TODO: smlalY */
3221  goto bad;
3222  }
3223  if ((iword & 0x0ff000b0) == 0x01200080) {
3224  /* TODO: smlawY */
3225  goto bad;
3226  }
3227  if ((iword & 0x0ff0f090) == 0x01600080) {
3228  /* smulXY (16-bit * 16-bit => 32-bit) */
3229  switch (iword & 0x60) {
3230  case 0x00: ic->f = cond_instr(smulbb); break;
3231  case 0x20: ic->f = cond_instr(smultb); break;
3232  case 0x40: ic->f = cond_instr(smulbt); break;
3233  default: ic->f = cond_instr(smultt); break;
3234  }
3235  ic->arg[0] = (size_t)(&cpu->cd.arm.r[rm]);
3236  ic->arg[1] = (size_t)(&cpu->cd.arm.r[r8]);
3237  ic->arg[2] = (size_t)(&cpu->cd.arm.r[rn]); /* Rd */
3238  break;
3239  }
3240  if ((iword & 0x0ff0f0b0) == 0x012000a0) {
3241  /* TODO: smulwY */
3242  goto bad;
3243  }
3244  if ((iword & 0x0fb0fff0) == 0x0120f000 ||
3245  (iword & 0x0fb0f000) == 0x0320f000) {
3246  /* msr: move to [S|C]PSR from a register or
3247  immediate value */
3248  if (iword & 0x02000000) {
3249  if (iword & 0x00400000)
3250  ic->f = cond_instr(msr_imm_spsr);
3251  else
3252  ic->f = cond_instr(msr_imm);
3253  } else {
3254  if (rm == ARM_PC) {
3255  if (!cpu->translation_readahead)
3256  fatal("msr PC?\n");
3257  goto bad;
3258  }
3259  if (iword & 0x00400000)
3260  ic->f = cond_instr(msr_spsr);
3261  else
3262  ic->f = cond_instr(msr);
3263  }
3264  imm = iword & 0xff;
3265  while (r8-- > 0)
3266  imm = (imm >> 2) | ((imm & 3) << 30);
3267  ic->arg[0] = imm;
3268  ic->arg[2] = (size_t)(&cpu->cd.arm.r[rm]);
3269  {
3270  uint32_t arg1 = 0;
3271  if (iword & (1<<16)) arg1 |= 0x000000ff;
3272  if (iword & (1<<17)) arg1 |= 0x0000ff00;
3273  if (iword & (1<<18)) arg1 |= 0x00ff0000;
3274  if (iword & (1<<19)) arg1 |= 0xff000000;
3275  ic->arg[1] = arg1;
3276  if (arg1 == 0)
3277  ic->f = instr(nop);
3278  }
3279  break;
3280  }
3281  if ((iword & 0x0fbf0fff) == 0x010f0000) {
3282  /* mrs: move from CPSR/SPSR to a register: */
3283  if (rd == ARM_PC) {
3284  if (!cpu->translation_readahead)
3285  fatal("mrs PC?\n");
3286  goto bad;
3287  }
3288  if (iword & 0x00400000)
3289  ic->f = cond_instr(mrs_spsr);
3290  else
3291  ic->f = cond_instr(mrs);
3292  ic->arg[0] = (size_t)(&cpu->cd.arm.r[rd]);
3293  break;
3294  }
3295  if ((iword & 0x0e000090) == 0x00000090) {
3296  regform = !(iword & 0x00400000);
3297  imm = ((iword >> 4) & 0xf0) | (iword & 0xf);
3298  p_bit = main_opcode & 1;
3299  ic->arg[0] = (size_t)(&cpu->cd.arm.r[rn]);
3300  ic->arg[2] = (size_t)(&cpu->cd.arm.r[rd]);
3301  if (rd == ARM_PC || rn == ARM_PC) {
3303  condition_code + (l_bit? 16 : 0)
3304  + (iword & 0x40? 32 : 0)
3305  + (w_bit? 64 : 0)
3306  + (iword & 0x20? 128 : 0)
3307  + (u_bit? 256 : 0) + (p_bit? 512 : 0)
3308  + (regform? 1024 : 0)];
3309  if (rn == ARM_PC)
3310  ic->arg[0] = (size_t)
3311  (&cpu->cd.arm.tmp_pc);
3312  if (!l_bit && rd == ARM_PC)
3313  ic->arg[2] = (size_t)
3314  (&cpu->cd.arm.tmp_pc);
3315  } else
3317  condition_code + (l_bit? 16 : 0)
3318  + (iword & 0x40? 32 : 0)
3319  + (w_bit? 64 : 0)
3320  + (iword & 0x20? 128 : 0)
3321  + (u_bit? 256 : 0) + (p_bit? 512 : 0)
3322  + (regform? 1024 : 0)];
3323  if (regform)
3324  ic->arg[1] = (size_t)(void *)arm_r[iword & 0xf];
3325  else
3326  ic->arg[1] = imm;
3327  break;
3328  }
3329 
3330  if (iword & 0x80 && !(main_opcode & 2) && iword & 0x10) {
3331  if (!cpu->translation_readahead)
3332  fatal("reg form blah blah\n");
3333  goto bad;
3334  }
3335 
3336  /* "bkpt", ARMv5 and above */
3337  if ((iword & 0x0ff000f0) == 0x01200070) {
3338  ic->f = cond_instr(bkpt);
3339  ic->arg[0] = addr & 0xfff;
3340  break;
3341  }
3342 
3343  /* "mov pc,lr": */
3344  if ((iword & 0x0fffffff) == 0x01a0f00e) {
3345  if (cpu->machine->show_trace_tree)
3346  ic->f = cond_instr(ret_trace);
3347  else
3348  ic->f = cond_instr(ret);
3349  break;
3350  }
3351 
3352  /* "mov reg,reg" or "mov reg,pc": */
3353  if ((iword & 0x0fff0ff0) == 0x01a00000 && rd != ARM_PC) {
3354  if (rm != ARM_PC) {
3355  ic->f = cond_instr(mov_reg_reg);
3356  ic->arg[0] = (size_t)(&cpu->cd.arm.r[rm]);
3357  } else {
3358  ic->f = cond_instr(mov_reg_pc);
3359  ic->arg[0] = (addr & 0xfff) + 8;
3360  }
3361  ic->arg[1] = (size_t)(&cpu->cd.arm.r[rd]);
3362  break;
3363  }
3364 
3365  /* "mov reg,#0": */
3366  if ((iword & 0x0fff0fff) == 0x03a00000 && rd != ARM_PC) {
3367  arm_switch_clear(ic, rd, condition_code);
3368  break;
3369  }
3370 
3371  /* "mov reg,#1": */
3372  if ((iword & 0x0fff0fff) == 0x03a00001 && rd != ARM_PC) {
3373  arm_switch_mov1(ic, rd, condition_code);
3374  break;
3375  }
3376 
3377  /* "add reg,reg,#1": */
3378  if ((iword & 0x0ff00fff) == 0x02800001 && rd != ARM_PC
3379  && rn == rd) {
3380  arm_switch_add1(ic, rd, condition_code);
3381  break;
3382  }
3383 
3384  if ((iword & 0x0ff00000) == 0x03000000) {
3385  ic->arg[0] = (size_t)(&cpu->cd.arm.r[rn]);
3386  ic->arg[1] = (((iword & 0xf0000) >> 4) | (iword & 0xfff));
3387  ic->arg[2] = (size_t)(&cpu->cd.arm.r[rd]);
3388  ic->f = cond_instr(movw);
3389  if (rd == ARM_PC) {
3390  if (!cpu->translation_readahead)
3391  fatal("movw with rd = pc?\n");
3392  goto bad;
3393  }
3394  break;
3395  } else if ((iword & 0x0ff00000) == 0x03400000) {
3396  ic->arg[0] = (size_t)(&cpu->cd.arm.r[rn]);
3397  ic->arg[1] = (((iword & 0xf0000) >> 4) | (iword & 0xfff)) << 16;
3398  ic->arg[2] = (size_t)(&cpu->cd.arm.r[rd]);
3399  ic->f = cond_instr(movt);
3400  if (rd == ARM_PC) {
3401  if (!cpu->translation_readahead)
3402  fatal("movt with rd = pc?\n");
3403  goto bad;
3404  }
3405  break;
3406  }
3407 
3408  /*
3409  * Generic Data Processing Instructions:
3410  */
3411  if ((main_opcode & 2) == 0)
3412  regform = 1;
3413  else
3414  regform = 0;
3415 
3416  if (regform) {
3417  /* 0x1000 signifies Carry bit update on rotation,
3418  which is not necessary for add,adc,sub,sbc,
3419  rsb,rsc,cmp, or cmn, because they update the
3420  Carry bit manually anyway. */
3421  int q = 0x1000;
3422  if (s_bit == 0)
3423  q = 0;
3424  if ((secondary_opcode >= 2 && secondary_opcode <= 7)
3425  || secondary_opcode==0xa || secondary_opcode==0xb)
3426  q = 0;
3427  ic->arg[1] = (size_t)(void *)arm_r[(iword & 0xfff) + q];
3428  } else {
3429  int steps = r8;
3430 
3431  imm = iword & 0xff;
3432 
3433  while (r8-- > 0)
3434  imm = (imm >> 2) | ((imm & 3) << 30);
3435 
3436  if (steps != 0 && (imm != 0 && imm < 256)) {
3437  if (!cpu->translation_readahead)
3438  fatal("TODO: see cpu_arm_instr_dpi; non-zero steps but still under 256 is not implemented yet\n");
3439  goto bad;
3440  }
3441 
3442  ic->arg[1] = imm;
3443  }
3444 
3445  /* mvn #imm ==> mov #~imm */
3446  if (secondary_opcode == 0xf && !regform) {
3447  secondary_opcode = 0xd;
3448  ic->arg[1] = ~ic->arg[1];
3449  }
3450 
3451  ic->arg[0] = (size_t)(&cpu->cd.arm.r[rn]);
3452  ic->arg[2] = (size_t)(&cpu->cd.arm.r[rd]);
3453  any_pc_reg = 0;
3454  if (rn == ARM_PC || rd == ARM_PC)
3455  any_pc_reg = 1;
3456 
3457  if (!any_pc_reg && regform && (iword & 0xfff) < ARM_PC) {
3458  ic->arg[1] = (size_t)(&cpu->cd.arm.r[rm]);
3459  ic->f = arm_dpi_instr_regshort[condition_code +
3460  16 * secondary_opcode + (s_bit? 256 : 0)];
3461  } else
3462  ic->f = arm_dpi_instr[condition_code +
3463  16 * secondary_opcode + (s_bit? 256 : 0) +
3464  (any_pc_reg? 512 : 0) + (regform? 1024 : 0)];
3465 
3466  if (ic->f == instr(eor_regshort))
3467  cpu->cd.arm.combination_check = COMBINE(xchg);
3468  if (iword == 0xe113000c)
3469  cpu->cd.arm.combination_check = COMBINE(netbsd_scanc);
3470  break;
3471 
3472  case 0x4: /* Load and store... */
3473  case 0x5: /* xxxx010P UBWLnnnn ddddoooo oooooooo Immediate */
3474  case 0x6: /* xxxx011P UBWLnnnn ddddcccc ctt0mmmm Register */
3475  case 0x7:
3476  // Special non-loadstore encodings:
3477  if (main_opcode >= 6 && iword & 0x10) {
3478  if ((iword & 0x0fff0ff0) == 0x06bf0f30) {
3479  ic->f = cond_instr(rev);
3480  ic->arg[0] = (size_t)(&cpu->cd.arm.r[rd]);
3481  ic->arg[1] = (size_t)(&cpu->cd.arm.r[rm]);
3482  } else if ((iword & 0x0fff03f0) == 0x06bf0070) {
3483  ic->f = cond_instr(sxth);
3484  ic->arg[0] = (size_t)(&cpu->cd.arm.r[rd]);
3485  ic->arg[1] = (size_t)(&cpu->cd.arm.r[rm]);
3486  ic->arg[2] = ((iword & 0xc00) >> 10) << 3;
3487  } else if ((iword & 0x0fff03f0) == 0x06ef0070) {
3488  ic->f = cond_instr(uxtb);
3489  ic->arg[0] = (size_t)(&cpu->cd.arm.r[rd]);
3490  ic->arg[1] = (size_t)(&cpu->cd.arm.r[rm]);
3491  ic->arg[2] = ((iword & 0xc00) >> 10) << 3;
3492  } else if ((iword & 0x0ff003f0) == 0x06e00070) {
3493  ic->arg[0] = (size_t)(&cpu->cd.arm.r[rd]);
3494  ic->arg[1] = (size_t)(&cpu->cd.arm.r[rn]);
3495  ic->arg[2] = (size_t)(&cpu->cd.arm.r[rm]);
3496  ic->f = cond_instr(uxtab);
3497  if (iword & 0xc00) {
3498  if (!cpu->translation_readahead)
3499  fatal("unimplemented uxtab with rotate != 0\n");
3500  goto bad;
3501  }
3502  } else if ((iword & 0x0fff03f0) == 0x06ff0070) {
3503  ic->f = cond_instr(uxth);
3504  ic->arg[0] = (size_t)(&cpu->cd.arm.r[rd]);
3505  ic->arg[1] = (size_t)(&cpu->cd.arm.r[rm]);
3506  ic->arg[2] = ((iword & 0xc00) >> 10) << 3;
3507  } else if ((iword & 0x0ff003f0) == 0x06f00070) {
3508  ic->arg[0] = (size_t)(&cpu->cd.arm.r[rd]);
3509  ic->arg[1] = (size_t)(&cpu->cd.arm.r[rn]);
3510  ic->arg[2] = (size_t)(&cpu->cd.arm.r[rm]);
3511  ic->f = cond_instr(uxtah);
3512  if (iword & 0xc00) {
3513  if (!cpu->translation_readahead)
3514  fatal("unimplemented uxtah with rotate != 0\n");
3515  goto bad;
3516  }
3517  } else if ((iword & 0x0fe00070) == 0x07c00010) {
3518  ic->f = cond_instr(bfi);
3519  ic->arg[0] = (size_t)(&cpu->cd.arm.r[rd]);
3520  ic->arg[1] = (size_t)(&cpu->cd.arm.r[rm]);
3521  int lsb = (iword >> 7) & 31;
3522  int msb = (iword >> 16) & 31;
3523  ic->arg[2] = (msb << 16) + lsb;
3524  } else if ((iword & 0x0fe00070) == 0x07e00050) {
3525  ic->f = cond_instr(ubfx);
3526  ic->arg[0] = (size_t)(&cpu->cd.arm.r[rd]);
3527  ic->arg[1] = (size_t)(&cpu->cd.arm.r[rm]);
3528  int lsb = (iword >> 7) & 31;
3529  int width = 1 + ((iword >> 16) & 31);
3530  ic->arg[2] = (width << 16) + lsb;
3531  } else if ((iword & 0x0fe00070) == 0x07a00050) {
3532  ic->f = cond_instr(sbfx);
3533  ic->arg[0] = (size_t)(&cpu->cd.arm.r[rd]);
3534  ic->arg[1] = (size_t)(&cpu->cd.arm.r[rm]);
3535  int lsb = (iword >> 7) & 31;
3536  int width = 1 + ((iword >> 16) & 31);
3537  ic->arg[2] = (width << 16) + lsb;
3538  } else {
3539  if (!cpu->translation_readahead)
3540  fatal("unimplemented special non-loadstore encoding!\n");
3541  goto bad;
3542  }
3543  break;
3544  }
3545 
3546  ic->arg[0] = (size_t)(&cpu->cd.arm.r[rn]);
3547  ic->arg[2] = (size_t)(&cpu->cd.arm.r[rd]);
3548  if (rd == ARM_PC || rn == ARM_PC) {
3549  ic->f = arm_load_store_instr_pc[((iword >> 16)
3550  & 0x3f0) + condition_code];
3551  if (rn == ARM_PC)
3552  ic->arg[0] = (size_t)(&cpu->cd.arm.tmp_pc);
3553  if (!l_bit && rd == ARM_PC)
3554  ic->arg[2] = (size_t)(&cpu->cd.arm.tmp_pc);
3555  } else {
3556  ic->f = arm_load_store_instr[((iword >> 16) &
3557  0x3f0) + condition_code];
3558  }
3559  imm = iword & 0xfff;
3560  if (main_opcode < 6)
3561  ic->arg[1] = imm;
3562  else
3563  ic->arg[1] = (size_t)(void *)arm_r[iword & 0xfff];
3564  if ((iword & 0x0e000010) == 0x06000010) {
3565  /* GDB uses this for breakpoints. */
3566  ic->f = cond_instr(und);
3567  ic->arg[0] = addr & 0xfff;
3568  }
3569  /* Special case: pc-relative load within the same page: */
3570  if (rn == ARM_PC && rd != ARM_PC && main_opcode < 6 && l_bit) {
3571  unsigned char *p = page;
3572  int ofs = (addr & 0xfff) + 8, max = 0xffc;
3573  int b_bit = iword & 0x00400000;
3574  if (b_bit)
3575  max = 0xfff;
3576  if (u_bit)
3577  ofs += (iword & 0xfff);
3578  else
3579  ofs -= (iword & 0xfff);
3580  /* NOTE/TODO: This assumes 4KB pages,
3581  it will not work with 1KB pages. */
3582  if (ofs >= 0 && ofs <= max && p != NULL) {
3583  unsigned char cbuf[4];
3584  int len = b_bit? 1 : 4;
3585  uint32_t x, a = (addr & 0xfffff000) | ofs;
3586  /* ic->f = cond_instr(mov); */
3587  ic->f = arm_dpi_instr[condition_code + 16*0xd];
3588  ic->arg[2] = (size_t)(&cpu->cd.arm.r[rd]);
3589 
3590  memcpy(cbuf, p + (a & 0xfff), len);
3591 
3592  if (b_bit) {
3593  x = cbuf[0];
3594  } else {
3596  x = cbuf[0] + (cbuf[1]<<8) +
3597  (cbuf[2]<<16) + (cbuf[3]<<24);
3598  else
3599  x = cbuf[3] + (cbuf[2]<<8) +
3600  (cbuf[1]<<16) + (cbuf[0]<<24);
3601  }
3602 
3603  ic->arg[1] = x;
3604  }
3605  }
3606  if (iword == 0xe4b09004)
3607  cpu->cd.arm.combination_check = COMBINE(netbsd_copyin);
3608  if (iword == 0xe4a17004)
3609  cpu->cd.arm.combination_check = COMBINE(netbsd_copyout);
3610  break;
3611 
3612  case 0x8: /* Multiple load/store... (Block data transfer) */
3613  case 0x9: /* xxxx100P USWLnnnn llllllll llllllll */
3614  ic->arg[0] = (size_t)(&cpu->cd.arm.r[rn]);
3615  ic->arg[1] = (size_t)iword;
3616  /* Generic case: */
3617  if (l_bit)
3618  ic->f = cond_instr(bdt_load);
3619  else
3620  ic->f = cond_instr(bdt_store);
3621 #if defined(HOST_LITTLE_ENDIAN) && !defined(GATHER_BDT_STATISTICS)
3622  /*
3623  * Check for availability of optimized implementation:
3624  * xxxx100P USWLnnnn llllllll llllllll
3625  * ^ ^ ^ ^ ^ ^ ^ ^ (0x00950154)
3626  * These bits are used to select which list to scan, and then
3627  * the list is scanned linearly.
3628  *
3629  * The optimized functions do not support show_trace_tree,
3630  * but it's ok to use the unoptimized version in that case.
3631  */
3632  if (!cpu->machine->show_trace_tree) {
3633  int i = 0, j = iword;
3634  j = ((j & 0x00800000) >> 16) | ((j & 0x00100000) >> 14)
3635  | ((j & 0x00040000) >> 13) | ((j & 0x00010000) >> 12)
3636  | ((j & 0x00000100) >> 5) | ((j & 0x00000040) >> 4)
3637  | ((j & 0x00000010) >> 3) | ((j & 0x00000004) >> 2);
3638  while (multi_opcode[j][i] != 0) {
3639  if ((iword & 0x0fffffff) ==
3640  multi_opcode[j][i]) {
3641  ic->f = multi_opcode_f[j]
3642  [i*16 + condition_code];
3643  break;
3644  }
3645  i ++;
3646  }
3647  }
3648 #endif
3649  if (rn == ARM_PC) {
3650  if (!cpu->translation_readahead)
3651  fatal("TODO: bdt with PC as base\n");
3652  goto bad;
3653  }
3654  break;
3655 
3656  case 0xa: /* B: branch */
3657  case 0xb: /* BL: branch+link */
3658  if (main_opcode == 0x0a) {
3659  ic->f = cond_instr(b);
3660  samepage_function = cond_instr(b_samepage);
3661 
3662  /* Abort read-ahead on unconditional branches: */
3663  if (condition_code == 0xe &&
3666 
3667  if (iword == 0xcaffffed)
3668  cpu->cd.arm.combination_check =
3670  if (iword == 0xaafffff9)
3671  cpu->cd.arm.combination_check =
3673  } else {
3674  if (cpu->machine->show_trace_tree) {
3675  ic->f = cond_instr(bl_trace);
3676  samepage_function =
3677  cond_instr(bl_samepage_trace);
3678  } else {
3679  ic->f = cond_instr(bl);
3680  samepage_function = cond_instr(bl_samepage);
3681  }
3682  }
3683 
3684  /* arg 1 = offset of current instruction */
3685  /* arg 2 = offset of the following instruction */
3686  ic->arg[1] = addr & 0xffc;
3687  ic->arg[2] = (addr & 0xffc) + 4;
3688 
3689  ic->arg[0] = (iword & 0x00ffffff) << 2;
3690  /* Sign-extend: */
3691  if (ic->arg[0] & 0x02000000)
3692  ic->arg[0] |= 0xfc000000;
3693  /*
3694  * Branches are calculated as PC + 8 + offset.
3695  */
3696  ic->arg[0] = (int32_t)(ic->arg[0] + 8);
3697 
3698  /*
3699  * Special case: branch within the same page:
3700  *
3701  * arg[0] = addr of the arm_instr_call of the target
3702  * arg[1] = addr of the next arm_instr_call.
3703  */
3704  {
3705  uint32_t mask_within_page =
3706  ((ARM_IC_ENTRIES_PER_PAGE-1) <<
3708  ((1 << ARM_INSTR_ALIGNMENT_SHIFT) - 1);
3709  uint32_t old_pc = addr;
3710  uint32_t new_pc = old_pc + (int32_t)ic->arg[0];
3711  if ((old_pc & ~mask_within_page) ==
3712  (new_pc & ~mask_within_page)) {
3713  ic->f = samepage_function;
3714  ic->arg[0] = (size_t) (
3715  cpu->cd.arm.cur_ic_page +
3716  ((new_pc & mask_within_page) >>
3718  ic->arg[1] = (size_t) (
3719  cpu->cd.arm.cur_ic_page +
3720  (((addr & mask_within_page) + 4) >>
3722  } else if (main_opcode == 0x0a) {
3723  /* Special hack for a plain "b": */
3724  ic->arg[0] += ic->arg[1];
3725  }
3726  }
3727 
3728  if (main_opcode == 0xa && (condition_code <= 1
3729  || condition_code == 3 || condition_code == 8
3730  || condition_code == 12 || condition_code == 13))
3731  cpu->cd.arm.combination_check = COMBINE(beq_etc);
3732 
3733  if (iword == 0x1afffffc)
3734  cpu->cd.arm.combination_check = COMBINE(strlen);
3735 
3736  /* Hm. Does this really increase performance? */
3737  if (iword == 0x8afffffa)
3738  cpu->cd.arm.combination_check =
3740  break;
3741 
3742  case 0xc:
3743  case 0xd:
3744  /*
3745  * xxxx1100 0100nnnn ddddcccc oooommmm MCRR c,op,Rd,Rn,CRm
3746  * xxxx1100 0101nnnn ddddcccc oooommmm MRRC c,op,Rd,Rn,CRm
3747  */
3748  if ((iword & 0x0fe00fff) == 0x0c400000) {
3749  /* Special case: mar/mra DSP instructions */
3750  if (!cpu->translation_readahead)
3751  fatal("TODO: mar/mra DSP instructions!\n");
3752  /* Perhaps these are actually identical to MCRR/MRRC */
3753  goto bad;
3754  }
3755 
3756  if ((iword & 0x0fe00000) == 0x0c400000) {
3757  if (!cpu->translation_readahead)
3758  fatal("MCRR/MRRC: TODO\n");
3759  goto bad;
3760  }
3761 
3762  /*
3763  * TODO: LDC/STC
3764  *
3765  * For now, treat as Undefined instructions. This causes e.g.
3766  * Linux/ARM to emulate these instructions (floating point).
3767  */
3768 #if 1
3769  ic->f = cond_instr(und);
3770  ic->arg[0] = addr & 0xfff;
3771 #else
3772  if (!cpu->translation_readahead)
3773  fatal("LDC/STC: TODO\n");
3774  goto bad;
3775 #endif
3776  break;
3777 
3778  case 0xe:
3779  if ((iword & 0x0ff00ff0) == 0x0e200010) {
3780  /* Special case: mia* DSP instructions */
3781  /* See Intel's 27343601.pdf, page 16-20 */
3782  if (!cpu->translation_readahead)
3783  fatal("TODO: mia* DSP instructions!\n");
3784  goto bad;
3785  }
3786  if (iword & 0x10) {
3787  /* xxxx1110 oooLNNNN ddddpppp qqq1MMMM MCR/MRC */
3788  ic->arg[0] = iword;
3789  ic->f = cond_instr(mcr_mrc);
3790  } else {
3791  /* xxxx1110 oooonnnn ddddpppp qqq0mmmm CDP */
3792  ic->arg[0] = iword;
3793  ic->f = cond_instr(cdp);
3794  }
3795  if (iword == 0xee070f9a)
3796  cpu->cd.arm.combination_check =
3798  break;
3799 
3800  case 0xf:
3801  /* SWI: */
3802  /* Default handler: */
3803  ic->f = cond_instr(swi);
3804  ic->arg[0] = addr & 0xfff;
3805  if (iword == 0xef8c64eb) {
3806  /* Hack for rebooting a machine: */
3807  ic->f = instr(reboot);
3808  } else if (iword == 0xef8c64be) {
3809  /* Hack for openfirmware prom emulation: */
3810  ic->f = instr(openfirmware);
3811  }
3812  break;
3813 
3814  default:goto bad;
3815  }
3816 
3817 okay:
3818 
3819 #define DYNTRANS_TO_BE_TRANSLATED_TAIL
3820 #include "cpu_dyntrans.cc"
3821 #undef DYNTRANS_TO_BE_TRANSLATED_TAIL
3822 }
3823 
ARM_MODE_SVC32
#define ARM_MODE_SVC32
Definition: cpu_arm.h:111
data
u_short data
Definition: siireg.h:79
instr
#define instr(n)
Definition: tmp_alpha_head.cc:43
beq_etc
void COMBINE() beq_etc(struct cpu *cpu, struct arm_instr_call *ic, int low_addr)
Definition: cpu_arm_instr.cc:2796
cpu::has_been_idling
char has_been_idling
Definition: cpu.h:401
Y
#define Y(n)
Definition: cpu_arm_instr.cc:132
f
void f(int s, int func, int only_name)
Definition: generate_arm_r.c:45
arm_load_store_instr_3
void(* arm_load_store_instr_3[2048])(struct cpu *, struct arm_instr_call *)
Definition: tmp_arm_loadstore.cc:5915
ARM_EXCEPTION_PREF_ABT
#define ARM_EXCEPTION_PREF_ABT
Definition: cpu_arm.h:125
cpu_dyntrans.cc
cpu::running
uint8_t running
Definition: cpu.h:353
arm_cpu::tmp_pc
uint32_t tmp_pc
Definition: cpu_arm.h:164
machine::cpus
struct cpu ** cpus
Definition: machine.h:140
cpu_functioncall_trace_return
void cpu_functioncall_trace_return(struct cpu *cpu)
Definition: cpu.cc:284
cpu::n_translated_instrs
int n_translated_instrs
Definition: cpu.h:430
arm_cpu::default_r8_r14
uint32_t default_r8_r14[7]
Definition: cpu_arm.h:157
arm_r_r3_t0_c0
uint32_t arm_r_r3_t0_c0(struct cpu *cpu, struct arm_instr_call *ic)
Definition: tmp_arm_r0.cc:20
machine::show_trace_tree
int show_trace_tree
Definition: machine.h:164
ARM_MODE_SYS32
#define ARM_MODE_SYS32
Definition: cpu_arm.h:114
ARM_IC_ENTRIES_PER_PAGE
#define ARM_IC_ENTRIES_PER_PAGE
Definition: cpu_arm.h:80
if
addr & if(addr >=0x24 &&page !=NULL)
Definition: tmp_arm_multi.cc:56
arm_cdp
void arm_cdp(struct cpu *cpu, uint32_t iword)
Definition: cpu_arm.cc:2560
of_emul
int of_emul(struct cpu *cpu)
Definition: of.cc:1078
N_SAFE_DYNTRANS_LIMIT
#define N_SAFE_DYNTRANS_LIMIT
Definition: cpu.h:311
condition_gt
uint8_t condition_gt[16]
Definition: cpu_arm_instr.cc:130
MEM_READ
#define MEM_READ
Definition: memory.h:116
arm_pop
void arm_pop(struct cpu *cpu, uint32_t *np, int p_bit, int u_bit, int s_bit, int w_bit, uint32_t iw)
Definition: cpu_arm_instr.cc:1352
t
vmrs t
Definition: armreg.h:750
cpu::byte_order
uint8_t byte_order
Definition: cpu.h:347
EMUL_BIG_ENDIAN
#define EMUL_BIG_ENDIAN
Definition: misc.h:165
cpu_functioncall_trace
void cpu_functioncall_trace(struct cpu *cpu, uint64_t f)
Definition: cpu.cc:228
arm_cpu::cpsr
uint32_t cpsr
Definition: cpu_arm.h:175
ARM_MODE_ABT32
#define ARM_MODE_ABT32
Definition: cpu_arm.h:112
addr
uint32_t addr
Definition: tmp_arm_multi.cc:52
ARM_INSTR_ALIGNMENT_SHIFT
#define ARM_INSTR_ALIGNMENT_SHIFT
Definition: cpu_arm.h:79
cpu_arm_instr_misc.cc
cond_instr
#define cond_instr(n)
Definition: cpu_arm_instr.cc:199
MEM_WRITE
#define MEM_WRITE
Definition: memory.h:117
arm_instr_nop
void arm_instr_nop(struct cpu *, struct arm_instr_call *)
arm_r
uint32_t(* arm_r[8192])(struct cpu *, struct arm_instr_call *)
Definition: tmp_arm_r.cc:8204
ARM_MODE_FIQ32
#define ARM_MODE_FIQ32
Definition: cpu_arm.h:109
arm_cpu::flags
size_t flags
Definition: cpu_arm.h:174
arm_push
void arm_push(struct cpu *cpu, uint32_t *np, int p_bit, int u_bit, int s_bit, int w_bit, uint16_t regs)
Definition: cpu_arm_instr.cc:1518
ARM_IP
#define ARM_IP
Definition: cpu_arm.h:53
netbsd_cacheclean2
void COMBINE() netbsd_cacheclean2(struct cpu *cpu, struct arm_instr_call *ic, int low_addr)
Definition: cpu_arm_instr.cc:2639
arm_cpu::spsr_und
uint32_t spsr_und
Definition: cpu_arm.h:178
arm_dpi_instr_regshort
void(* arm_dpi_instr_regshort[2 *16 *16])(struct cpu *, struct arm_instr_call *)
Definition: tmp_arm_dpi.cc:7128
strlen
void COMBINE() strlen(struct cpu *cpu, struct arm_instr_call *ic, int low_addr)
Definition: cpu_arm_instr.cc:2686
fatal
void fatal(const char *fmt,...)
Definition: main.cc:152
arm_cpu::rmw_len
uint32_t rmw_len
Definition: cpu_arm.h:239
arm_cpu::spsr_irq
uint32_t spsr_irq
Definition: cpu_arm.h:179
xchg
void COMBINE() xchg(struct cpu *cpu, struct arm_instr_call *ic, int low_addr)
Definition: cpu_arm_instr.cc:2709
arm_cpu::rmw
int rmw
Definition: cpu_arm.h:238
netbsd_copyin
void COMBINE() netbsd_copyin(struct cpu *cpu, struct arm_instr_call *ic, int low_addr)
Definition: cpu_arm_instr.cc:2734
condition_hi
uint8_t condition_hi[16]
Definition: cpu_arm_instr.cc:128
cpu::cd
union cpu::@1 cd
arm_load_register_bank
void arm_load_register_bank(struct cpu *cpu)
Definition: cpu_arm.cc:561
page
page
Definition: tmp_arm_multi.cc:54
ic
struct arm_instr_call * ic
Definition: tmp_arm_multi.cc:50
CACHE_INSTRUCTION
#define CACHE_INSTRUCTION
Definition: memory.h:122
netbsd_memcpy
void COMBINE() netbsd_memcpy(struct cpu *cpu, struct arm_instr_call *ic, int low_addr)
Definition: cpu_arm_instr.cc:2588
ARM_EXCEPTION_UND
#define ARM_EXCEPTION_UND
Definition: cpu_arm.h:123
ARM_MODE_UND32
#define ARM_MODE_UND32
Definition: cpu_arm.h:113
ARM_MODE_USR32
#define ARM_MODE_USR32
Definition: cpu_arm.h:108
ARM_LR
#define ARM_LR
Definition: cpu_arm.h:55
arm_mcr_mrc
void arm_mcr_mrc(struct cpu *cpu, uint32_t iword)
Definition: cpu_arm.cc:2529
arm_cpu::spsr_abt
uint32_t spsr_abt
Definition: cpu_arm.h:177
CACHE_DATA
#define CACHE_DATA
Definition: memory.h:121
arm_cond_instr_b_samepage
void(* arm_cond_instr_b_samepage[16])(struct cpu *, struct arm_instr_call *)
Definition: cpu_arm_instr.cc:336
arm_cpu::r
uint32_t r[N_ARM_REGS]
Definition: cpu_arm.h:155
arm_save_register_bank
void arm_save_register_bank(struct cpu *cpu)
Definition: cpu_arm.cc:514
ARM_FLAG_T
#define ARM_FLAG_T
Definition: cpu_arm.h:101
arm_dpi_instr
void(* arm_dpi_instr[2 *2 *2 *16 *16])(struct cpu *, struct arm_instr_call *)
Definition: tmp_arm_dpi.cc:5075
arm_cpu::spsr_fiq
uint32_t spsr_fiq
Definition: cpu_arm.h:180
ARM_MODE_IRQ32
#define ARM_MODE_IRQ32
Definition: cpu_arm.h:110
ARM_PC
#define ARM_PC
Definition: cpu_arm.h:56
netbsd_cacheclean
void COMBINE() netbsd_cacheclean(struct cpu *cpu, struct arm_instr_call *ic, int low_addr)
Definition: cpu_arm_instr.cc:2616
cpu::mem
struct memory * mem
Definition: cpu.h:362
ARM_F_N
#define ARM_F_N
Definition: cpu_arm.h:86
EMUL_LITTLE_ENDIAN
#define EMUL_LITTLE_ENDIAN
Definition: misc.h:164
arm_cpu::rmw_addr
uint32_t rmw_addr
Definition: cpu_arm.h:240
cpu::machine
struct machine * machine
Definition: cpu.h:328
zeroed_alloc
void * zeroed_alloc(size_t s)
Definition: memory.cc:118
reg
#define reg(x)
Definition: tmp_alpha_tail.cc:53
bdt_store
else instr() bdt_store(cpu, ic)
ARM_FLAG_MODE
#define ARM_FLAG_MODE
Definition: cpu_arm.h:103
nop
void COMBINE() nop(struct cpu *cpu, struct mips_instr_call *ic, int low_addr)
Definition: cpu_mips_instr.cc:3365
ARM_F_Z
#define ARM_F_Z
Definition: cpu_arm.h:87
cpu::arm
struct arm_cpu arm
Definition: cpu.h:444
arm_exception
void arm_exception(struct cpu *cpu, int exception_nr)
Definition: cpu_arm.cc:608
arm_load_store_instr_3_pc
void(* arm_load_store_instr_3_pc[2048])(struct cpu *, struct arm_instr_call *)
Definition: tmp_arm_loadstore.cc:7968
arm_load_store_instr
void(* arm_load_store_instr[1024])(struct cpu *, struct arm_instr_call *)
Definition: tmp_arm_loadstore.cc:977
multi_opcode_f
void(** multi_opcode_f[256])(struct cpu *, struct arm_instr_call *)
Definition: tmp_arm_multi.cc:9510
multi_opcode
uint32_t * multi_opcode[256]
Definition: tmp_arm_multi.cc:9443
cpu::translation_readahead
int translation_readahead
Definition: cpu.h:427
cmps
char * cmps[N_CMPS]
Definition: generate_alpha_misc.c:35
arm_load_store_instr_pc
void(* arm_load_store_instr_pc[1024])(struct cpu *, struct arm_instr_call *)
Definition: tmp_arm_loadstore.cc:2006
X
X(invalid)
Definition: cpu_arm_instr.cc:208
cpu
Definition: cpu.h:326
arm_cpu::spsr_svc
uint32_t spsr_svc
Definition: cpu_arm.h:176
ARM_F_V
#define ARM_F_V
Definition: cpu_arm.h:89
COMBINE
#define COMBINE(n)
Definition: tmp_alpha_tail.cc:61
cpu::memory_rw
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:368
netbsd_copyout
void COMBINE() netbsd_copyout(struct cpu *cpu, struct arm_instr_call *ic, int low_addr)
Definition: cpu_arm_instr.cc:2765
arm_cpu::is_userpage
uint32_t is_userpage[N_VPH32_ENTRIES/32]
Definition: cpu_arm.h:252
cpu::pc
uint64_t pc
Definition: cpu.h:386
bdt_load
else instr() bdt_load(cpu, ic)
netbsd_memset
void COMBINE() netbsd_memset(struct cpu *cpu, struct arm_instr_call *ic, int low_addr)
Definition: cpu_arm_instr.cc:2559
netbsd_scanc
void COMBINE() netbsd_scanc(struct cpu *cpu, struct arm_instr_call *ic, int low_addr)
Definition: cpu_arm_instr.cc:2661
condition_ge
uint8_t condition_ge[16]
Definition: cpu_arm_instr.cc:129
ARM_F_C
#define ARM_F_C
Definition: cpu_arm.h:88
machine::ncpus
int ncpus
Definition: machine.h:139
ARM_EXCEPTION_SWI
#define ARM_EXCEPTION_SWI
Definition: cpu_arm.h:124

Generated on Tue Aug 25 2020 19:25:06 for GXemul by doxygen 1.8.18