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

Generated on Sun Sep 30 2018 16:05:18 for GXemul by doxygen 1.8.13