/[gxemul]/trunk/src/cpus/cpu_arm_instr.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Diff of /trunk/src/cpus/cpu_arm_instr.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 14 by dpavlin, Mon Oct 8 16:18:51 2007 UTC revision 44 by dpavlin, Mon Oct 8 16:22:56 2007 UTC
# Line 1  Line 1 
1  /*  /*
2   *  Copyright (C) 2005  Anders Gavare.  All rights reserved.   *  Copyright (C) 2005-2007  Anders Gavare.  All rights reserved.
3   *   *
4   *  Redistribution and use in source and binary forms, with or without   *  Redistribution and use in source and binary forms, with or without
5   *  modification, are permitted provided that the following conditions are met:   *  modification, are permitted provided that the following conditions are met:
# Line 25  Line 25 
25   *  SUCH DAMAGE.   *  SUCH DAMAGE.
26   *   *
27   *   *
28   *  $Id: cpu_arm_instr.c,v 1.26 2005/10/07 22:10:51 debug Exp $   *  $Id: cpu_arm_instr.c,v 1.77 2007/06/28 13:36:46 debug Exp $
29   *   *
30   *  ARM instructions.   *  ARM instructions.
31   *   *
# Line 33  Line 33 
33   *  (If no instruction was executed, then it should be decreased. If, say, 4   *  (If no instruction was executed, then it should be decreased. If, say, 4
34   *  instructions were combined into one function and executed, then it should   *  instructions were combined into one function and executed, then it should
35   *  be increased by 3.)   *  be increased by 3.)
36     *
37     *  Note: cpu->pc is prefered over r[ARM_PC]. r[ARM_PC] is only used in a
38     *        few places, and should always be kept in synch with the real
39     *        program counter.
40     */
41    
42    
43    /*  #define GATHER_BDT_STATISTICS  */
44    
45    
46    #ifdef GATHER_BDT_STATISTICS
47    /*
48     *  update_bdt_statistics():
49     *
50     *  Gathers statistics about load/store multiple instructions.
51     *
52     *  NOTE/TODO: Perhaps it would be more memory efficient to swap the high
53     *  and low parts of the instruction word, so that the lllllll bits become
54     *  the high bits; this would cause fewer host pages to be used. Anyway, the
55     *  current implementation works on hosts with lots of RAM.
56     *
57     *  The resulting file, bdt_statistics.txt, should then be processed like
58     *  this to give a new cpu_arm_multi.txt:
59     *
60     *  uniq -c bdt_statistics.txt|sort -nr|head -256|cut -f 2 > cpu_arm_multi.txt
61   */   */
62    static void update_bdt_statistics(uint32_t iw)
63    {
64            static FILE *f = NULL;
65            static long long *counts;
66            static char *counts_used;
67            static long long n = 0;
68    
69            if (f == NULL) {
70                    size_t s = (1 << 24) * sizeof(long long);
71                    f = fopen("bdt_statistics.txt", "w");
72                    if (f == NULL) {
73                            fprintf(stderr, "update_bdt_statistics(): :-(\n");
74                            exit(1);
75                    }
76                    counts = zeroed_alloc(s);
77                    counts_used = zeroed_alloc(65536);
78            }
79    
80            /*  Drop the s-bit: xxxx100P USWLnnnn llllllll llllllll  */
81            iw = ((iw & 0x01800000) >> 1) | (iw & 0x003fffff);
82    
83            counts_used[iw & 0xffff] = 1;
84            counts[iw] ++;
85    
86            n ++;
87            if ((n % 500000) == 0) {
88                    int i;
89                    long long j;
90                    fatal("[ update_bdt_statistics(): n = %lli ]\n", (long long) n);
91                    fseek(f, 0, SEEK_SET);
92                    for (i=0; i<0x1000000; i++)
93                            if (counts_used[i & 0xffff] && counts[i] != 0) {
94                                    /*  Recreate the opcode:  */
95                                    uint32_t opcode = ((i & 0x00c00000) << 1)
96                                        | (i & 0x003fffff) | 0x08000000;
97                                    for (j=0; j<counts[i]; j++)
98                                            fprintf(f, "0x%08x\n", opcode);
99                            }
100                    fflush(f);
101            }
102    }
103    #endif
104    
105    
106    /*****************************************************************************/
107    
108    
109  /*  /*
# Line 51  Line 121 
121   *  condition code. (The NV condition code is not included, and the AL code   *  condition code. (The NV condition code is not included, and the AL code
122   *  uses the main foo function.)  Y also defines an array with pointers to   *  uses the main foo function.)  Y also defines an array with pointers to
123   *  all of these functions.   *  all of these functions.
124     *
125     *  If the compiler is good enough (i.e. allows long enough code sequences
126     *  to be inlined), then the Y functions will be compiled as full (inlined)
127     *  functions, otherwise they will simply call the X function.
128   */   */
129    
130    uint8_t condition_hi[16] = { 0,0,1,1, 0,0,0,0, 0,0,1,1, 0,0,0,0 };
131    uint8_t condition_ge[16] = { 1,0,1,0, 1,0,1,0, 0,1,0,1, 0,1,0,1 };
132    uint8_t condition_gt[16] = { 1,0,1,0, 0,0,0,0, 0,1,0,1, 0,0,0,0 };
133    
134  #define Y(n) void arm_instr_ ## n ## __eq(struct cpu *cpu,              \  #define Y(n) void arm_instr_ ## n ## __eq(struct cpu *cpu,              \
135                          struct arm_instr_call *ic)                      \                          struct arm_instr_call *ic)                      \
136          {  if (cpu->cd.arm.cpsr & ARM_FLAG_Z)                           \          {  if (cpu->cd.arm.flags & ARM_F_Z)                             \
137                  arm_instr_ ## n (cpu, ic);              }               \                  arm_instr_ ## n (cpu, ic);              }               \
138          void arm_instr_ ## n ## __ne(struct cpu *cpu,                   \          void arm_instr_ ## n ## __ne(struct cpu *cpu,                   \
139                          struct arm_instr_call *ic)                      \                          struct arm_instr_call *ic)                      \
140          {  if (!(cpu->cd.arm.cpsr & ARM_FLAG_Z))                        \          {  if (!(cpu->cd.arm.flags & ARM_F_Z))                          \
141                  arm_instr_ ## n (cpu, ic);              }               \                  arm_instr_ ## n (cpu, ic);              }               \
142          void arm_instr_ ## n ## __cs(struct cpu *cpu,                   \          void arm_instr_ ## n ## __cs(struct cpu *cpu,                   \
143                          struct arm_instr_call *ic)                      \                          struct arm_instr_call *ic)                      \
144          {  if (cpu->cd.arm.cpsr & ARM_FLAG_C)                           \          {  if (cpu->cd.arm.flags & ARM_F_C)                             \
145                  arm_instr_ ## n (cpu, ic);              }               \                  arm_instr_ ## n (cpu, ic);              }               \
146          void arm_instr_ ## n ## __cc(struct cpu *cpu,                   \          void arm_instr_ ## n ## __cc(struct cpu *cpu,                   \
147                          struct arm_instr_call *ic)                      \                          struct arm_instr_call *ic)                      \
148          {  if (!(cpu->cd.arm.cpsr & ARM_FLAG_C))                        \          {  if (!(cpu->cd.arm.flags & ARM_F_C))                          \
149                  arm_instr_ ## n (cpu, ic);              }               \                  arm_instr_ ## n (cpu, ic);              }               \
150          void arm_instr_ ## n ## __mi(struct cpu *cpu,                   \          void arm_instr_ ## n ## __mi(struct cpu *cpu,                   \
151                          struct arm_instr_call *ic)                      \                          struct arm_instr_call *ic)                      \
152          {  if (cpu->cd.arm.cpsr & ARM_FLAG_N)                           \          {  if (cpu->cd.arm.flags & ARM_F_N)                             \
153                  arm_instr_ ## n (cpu, ic);              }               \                  arm_instr_ ## n (cpu, ic);              }               \
154          void arm_instr_ ## n ## __pl(struct cpu *cpu,                   \          void arm_instr_ ## n ## __pl(struct cpu *cpu,                   \
155                          struct arm_instr_call *ic)                      \                          struct arm_instr_call *ic)                      \
156          {  if (!(cpu->cd.arm.cpsr & ARM_FLAG_N))                        \          {  if (!(cpu->cd.arm.flags & ARM_F_N))                          \
157                  arm_instr_ ## n (cpu, ic);              }               \                  arm_instr_ ## n (cpu, ic);              }               \
158          void arm_instr_ ## n ## __vs(struct cpu *cpu,                   \          void arm_instr_ ## n ## __vs(struct cpu *cpu,                   \
159                          struct arm_instr_call *ic)                      \                          struct arm_instr_call *ic)                      \
160          {  if (cpu->cd.arm.cpsr & ARM_FLAG_V)                           \          {  if (cpu->cd.arm.flags & ARM_F_V)                             \
161                  arm_instr_ ## n (cpu, ic);              }               \                  arm_instr_ ## n (cpu, ic);              }               \
162          void arm_instr_ ## n ## __vc(struct cpu *cpu,                   \          void arm_instr_ ## n ## __vc(struct cpu *cpu,                   \
163                          struct arm_instr_call *ic)                      \                          struct arm_instr_call *ic)                      \
164          {  if (!(cpu->cd.arm.cpsr & ARM_FLAG_V))                        \          {  if (!(cpu->cd.arm.flags & ARM_F_V))                          \
165                  arm_instr_ ## n (cpu, ic);              }               \                  arm_instr_ ## n (cpu, ic);              }               \
166          void arm_instr_ ## n ## __hi(struct cpu *cpu,                   \          void arm_instr_ ## n ## __hi(struct cpu *cpu,                   \
167                          struct arm_instr_call *ic)                      \                          struct arm_instr_call *ic)                      \
168          {  if (cpu->cd.arm.cpsr & ARM_FLAG_C &&                         \          {  if (condition_hi[cpu->cd.arm.flags])                         \
                 !(cpu->cd.arm.cpsr & ARM_FLAG_Z))                       \  
169                  arm_instr_ ## n (cpu, ic);              }               \                  arm_instr_ ## n (cpu, ic);              }               \
170          void arm_instr_ ## n ## __ls(struct cpu *cpu,                   \          void arm_instr_ ## n ## __ls(struct cpu *cpu,                   \
171                          struct arm_instr_call *ic)                      \                          struct arm_instr_call *ic)                      \
172          {  if (cpu->cd.arm.cpsr & ARM_FLAG_Z ||                         \          {  if (!condition_hi[cpu->cd.arm.flags])                        \
                 !(cpu->cd.arm.cpsr & ARM_FLAG_C))                       \  
173                  arm_instr_ ## n (cpu, ic);              }               \                  arm_instr_ ## n (cpu, ic);              }               \
174          void arm_instr_ ## n ## __ge(struct cpu *cpu,                   \          void arm_instr_ ## n ## __ge(struct cpu *cpu,                   \
175                          struct arm_instr_call *ic)                      \                          struct arm_instr_call *ic)                      \
176          {  if (((cpu->cd.arm.cpsr & ARM_FLAG_N)?1:0) ==                 \          {  if (condition_ge[cpu->cd.arm.flags])                         \
                 ((cpu->cd.arm.cpsr & ARM_FLAG_V)?1:0))                  \  
177                  arm_instr_ ## n (cpu, ic);              }               \                  arm_instr_ ## n (cpu, ic);              }               \
178          void arm_instr_ ## n ## __lt(struct cpu *cpu,                   \          void arm_instr_ ## n ## __lt(struct cpu *cpu,                   \
179                          struct arm_instr_call *ic)                      \                          struct arm_instr_call *ic)                      \
180          {  if (((cpu->cd.arm.cpsr & ARM_FLAG_N)?1:0) !=                 \          {  if (!condition_ge[cpu->cd.arm.flags])                        \
                 ((cpu->cd.arm.cpsr & ARM_FLAG_V)?1:0))                  \  
181                  arm_instr_ ## n (cpu, ic);              }               \                  arm_instr_ ## n (cpu, ic);              }               \
182          void arm_instr_ ## n ## __gt(struct cpu *cpu,                   \          void arm_instr_ ## n ## __gt(struct cpu *cpu,                   \
183                          struct arm_instr_call *ic)                      \                          struct arm_instr_call *ic)                      \
184          {  if (((cpu->cd.arm.cpsr & ARM_FLAG_N)?1:0) ==                 \          {  if (condition_gt[cpu->cd.arm.flags])                         \
                 ((cpu->cd.arm.cpsr & ARM_FLAG_V)?1:0) &&                \  
                 !(cpu->cd.arm.cpsr & ARM_FLAG_Z))                       \  
185                  arm_instr_ ## n (cpu, ic);              }               \                  arm_instr_ ## n (cpu, ic);              }               \
186          void arm_instr_ ## n ## __le(struct cpu *cpu,                   \          void arm_instr_ ## n ## __le(struct cpu *cpu,                   \
187                          struct arm_instr_call *ic)                      \                          struct arm_instr_call *ic)                      \
188          {  if (((cpu->cd.arm.cpsr & ARM_FLAG_N)?1:0) !=                 \          {  if (!condition_gt[cpu->cd.arm.flags])                        \
                 ((cpu->cd.arm.cpsr & ARM_FLAG_V)?1:0) ||                \  
                 (cpu->cd.arm.cpsr & ARM_FLAG_Z))                        \  
189                  arm_instr_ ## n (cpu, ic);              }               \                  arm_instr_ ## n (cpu, ic);              }               \
190          void (*arm_cond_instr_ ## n  [16])(struct cpu *,                \          void (*arm_cond_instr_ ## n  [16])(struct cpu *,                \
191                          struct arm_instr_call *) = {                    \                          struct arm_instr_call *) = {                    \
# Line 133  Line 203 
203    
204  /*****************************************************************************/  /*****************************************************************************/
205    
 /*  
  *  update_c is set if the C flag should be updated with the last shifted/  
  *  rotated bit.  
  */  
 uint32_t R(struct cpu *cpu, struct arm_instr_call *ic,  
         uint32_t iword, int update_c)  
 {  
         int rm = iword & 15, lastbit, t, c;  
         uint32_t tmp = cpu->cd.arm.r[rm];  
   
         if ((iword & 0xff0)==0 && rm != ARM_PC)  
                 return tmp;  
   
         t = (iword >> 4) & 7;  
         c = (iword >> 7) & 31;  
         lastbit = 0;  
   
         if (rm == ARM_PC) {  
                 /*  Calculate tmp from this instruction's PC + 8  */  
                 uint32_t low_pc = ((size_t)ic - (size_t)  
                     cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);  
                 tmp &= ~((ARM_IC_ENTRIES_PER_PAGE-1) <<  
                     ARM_INSTR_ALIGNMENT_SHIFT);  
                 tmp += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);  
                 tmp += 8;  
         }  
   
         if ((iword & 0xff0)==0 && rm == ARM_PC)  
                 return tmp;  
   
         if ((t & 1) && (c >> 1) == ARM_PC) {  
                 fatal("TODO: R: rc = PC\n");  
                 exit(1);  
         }  
   
         switch (t) {  
         case 0: /*  lsl #c  (c = 0..31)  */  
                 if (update_c) {  
                         if (c == 0)  
                                 update_c = 0;  
                         else  
                                 lastbit = (tmp << (c-1)) & 0x80000000;  
                 }  
                 tmp <<= c;  
                 break;  
         case 1: /*  lsl Rc  */  
                 c = cpu->cd.arm.r[c >> 1] & 255;  
                 if (c >= 32)  
                         c = 33;  
                 if (update_c) {  
                         if (c == 0)  
                                 update_c = 0;  
                         else  
                                 lastbit = ((uint64_t)tmp << (c-1)) & 0x80000000;  
                 }  
                 tmp = (uint64_t)tmp << c;  
                 break;  
         case 2: /*  lsr #c  (c = 1..32)  */  
                 if (c == 0)  
                         c = 32;  
                 if (update_c) {  
                         lastbit = ((uint64_t)tmp >> (c-1)) & 1;  
                 }  
                 tmp = (uint64_t)tmp >> c;  
                 break;  
         case 3: /*  lsr Rc  */  
                 c = cpu->cd.arm.r[c >> 1] & 255;  
                 if (c >= 32)  
                         c = 33;  
                 if (update_c) {  
                         if (c == 0)  
                                 update_c = 0;  
                         else  
                                 lastbit = ((uint64_t)tmp >> (c-1)) & 1;  
                 }  
                 tmp = (uint64_t)tmp >> c;  
                 break;  
         case 4: /*  asr #c  (c = 1..32)  */  
                 if (c == 0)  
                         c = 32;  
                 if (update_c) {  
                         lastbit = ((int64_t)(int32_t)tmp >> (c-1)) & 1;  
                 }  
                 tmp = (int64_t)(int32_t)tmp >> c;  
                 break;  
         case 5: /*  asr Rc  */  
                 c = cpu->cd.arm.r[c >> 1] & 255;  
                 if (c >= 32)  
                         c = 33;  
                 if (update_c) {  
                         if (c == 0)  
                                 update_c = 0;  
                         else  
                                 lastbit = ((int64_t)(int32_t)tmp >> (c-1)) & 1;  
                 }  
                 tmp = (int64_t)(int32_t)tmp >> c;  
                 break;  
         case 6: /*  ror 1..31  */  
                 if (c == 0) {  
                         fatal("TODO: rrx\n");  
                         exit(1);  
                 }  
                 if (update_c)  
                         lastbit = ((int64_t)(int32_t)tmp >> (c-1)) & 1;  
                 tmp = (uint64_t)(((uint64_t)tmp << 32) | tmp) >> c;  
                 break;  
         case 7: /*  ror Rc  */  
                 c = cpu->cd.arm.r[c >> 1] & 255;  
                 if (update_c) {  
                         if (c == 0)  
                                 update_c = 0;  
                         else {  
                                 c &= 31;  
                                 if (c == 0)  
                                         lastbit = tmp & 0x80000000;  
                                 else  
                                         lastbit = ((int64_t)(int32_t)tmp  
                                             >> (c-1)) & 1;  
                                 tmp = (uint64_t)(((uint64_t)tmp << 32)  
                                     | tmp) >> c;  
                         }  
                 }  
                 break;  
         }  
         if (update_c) {  
                 cpu->cd.arm.cpsr &= ~ARM_FLAG_C;  
                 if (lastbit)  
                         cpu->cd.arm.cpsr |= ARM_FLAG_C;  
         }  
         return tmp;  
 }  
   
   
 /*****************************************************************************/  
   
206    
207  /*  /*
  *  nop:  Do nothing.  
208   *  invalid:  Invalid instructions end up here.   *  invalid:  Invalid instructions end up here.
209   */   */
 X(nop) { }  
210  X(invalid) {  X(invalid) {
211          uint32_t low_pc;          uint32_t low_pc;
212          low_pc = ((size_t)ic - (size_t)          low_pc = ((size_t)ic - (size_t)
213              cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);              cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
214          cpu->cd.arm.r[ARM_PC] &= ~((ARM_IC_ENTRIES_PER_PAGE-1)          cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1)
215              << ARM_INSTR_ALIGNMENT_SHIFT);              << ARM_INSTR_ALIGNMENT_SHIFT);
216          cpu->cd.arm.r[ARM_PC] += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);          cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
         cpu->pc = cpu->cd.arm.r[ARM_PC];  
217    
218          fatal("Invalid ARM instruction: pc=0x%08x\n", (int)cpu->pc);          fatal("FATAL ERROR: An internal error occured in the ARM"
219                " dyntrans code. Please contact the author with detailed"
220                " repro steps on how to trigger this bug. pc = 0x%08"PRIx32"\n",
221                (uint32_t)cpu->pc);
222    
         cpu->running = 0;  
         cpu->running_translated = 0;  
         cpu->n_translated_instrs --;  
223          cpu->cd.arm.next_ic = &nothing_call;          cpu->cd.arm.next_ic = &nothing_call;
224  }  }
225    
226    
227  /*  /*
228     *  nop:  Do nothing.
229     */
230    X(nop)
231    {
232    }
233    
234    
235    /*
236   *  b:  Branch (to a different translated page)   *  b:  Branch (to a different translated page)
237   *   *
238   *  arg[0] = relative offset   *  arg[0] = relative offset from start of page
239   */   */
240  X(b)  X(b)
241  {  {
242          uint32_t low_pc;          cpu->pc = (uint32_t)((cpu->pc & 0xfffff000) + (int32_t)ic->arg[0]);
   
         /*  Calculate new PC from this instruction + arg[0]  */  
         low_pc = ((size_t)ic - (size_t)  
             cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);  
         cpu->cd.arm.r[ARM_PC] &= ~((ARM_IC_ENTRIES_PER_PAGE-1)  
             << ARM_INSTR_ALIGNMENT_SHIFT);  
         cpu->cd.arm.r[ARM_PC] += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);  
         cpu->cd.arm.r[ARM_PC] += (int32_t)ic->arg[0];  
         cpu->pc = cpu->cd.arm.r[ARM_PC];  
243    
244          /*  Find the new physical page and update the translation pointers:  */          /*  Find the new physical page and update the translation pointers:  */
245          arm_pc_to_pointers(cpu);          quick_pc_to_pointers(cpu);
246  }  }
247  Y(b)  Y(b)
248    
# Line 320  Y(b) Line 251  Y(b)
251   *  b_samepage:  Branch (to within the same translated page)   *  b_samepage:  Branch (to within the same translated page)
252   *   *
253   *  arg[0] = pointer to new arm_instr_call   *  arg[0] = pointer to new arm_instr_call
254     *  arg[1] = pointer to the next instruction.
255     *
256     *  NOTE: This instruction is manually inlined.
257   */   */
258  X(b_samepage)  X(b_samepage) {
 {  
259          cpu->cd.arm.next_ic = (struct arm_instr_call *) ic->arg[0];          cpu->cd.arm.next_ic = (struct arm_instr_call *) ic->arg[0];
260  }  }
261  Y(b_samepage)  X(b_samepage__eq) {
262            cpu->cd.arm.next_ic = (struct arm_instr_call *)
263                ic->arg[cpu->cd.arm.flags & ARM_F_Z? 0 : 1];
264    }
265    X(b_samepage__ne) {
266            cpu->cd.arm.next_ic = (struct arm_instr_call *)
267                ic->arg[cpu->cd.arm.flags & ARM_F_Z? 1 : 0];
268    }
269    X(b_samepage__cs) {
270            cpu->cd.arm.next_ic = (struct arm_instr_call *)
271                ic->arg[cpu->cd.arm.flags & ARM_F_C? 0 : 1];
272    }
273    X(b_samepage__cc) {
274            cpu->cd.arm.next_ic = (struct arm_instr_call *)
275                ic->arg[cpu->cd.arm.flags & ARM_F_C? 1 : 0];
276    }
277    X(b_samepage__mi) {
278            cpu->cd.arm.next_ic = (struct arm_instr_call *)
279                ic->arg[cpu->cd.arm.flags & ARM_F_N? 0 : 1];
280    }
281    X(b_samepage__pl) {
282            cpu->cd.arm.next_ic = (struct arm_instr_call *)
283                ic->arg[cpu->cd.arm.flags & ARM_F_N? 1 : 0];
284    }
285    X(b_samepage__vs) {
286            cpu->cd.arm.next_ic = (struct arm_instr_call *)
287                ic->arg[cpu->cd.arm.flags & ARM_F_V? 0 : 1];
288    }
289    X(b_samepage__vc) {
290            cpu->cd.arm.next_ic = (struct arm_instr_call *)
291                ic->arg[cpu->cd.arm.flags & ARM_F_V? 1 : 0];
292    }
293    X(b_samepage__hi) {
294            cpu->cd.arm.next_ic = (condition_hi[cpu->cd.arm.flags])?
295                (struct arm_instr_call *) ic->arg[0] :
296                (struct arm_instr_call *) ic->arg[1];
297    }
298    X(b_samepage__ls) {
299            cpu->cd.arm.next_ic = (struct arm_instr_call *)
300                ic->arg[condition_hi[cpu->cd.arm.flags]];
301    }
302    X(b_samepage__ge) {
303            cpu->cd.arm.next_ic = (condition_ge[cpu->cd.arm.flags])?
304                (struct arm_instr_call *) ic->arg[0] :
305                (struct arm_instr_call *) ic->arg[1];
306    }
307    X(b_samepage__lt) {
308            cpu->cd.arm.next_ic = (struct arm_instr_call *)
309                ic->arg[condition_ge[cpu->cd.arm.flags]];
310    }
311    X(b_samepage__gt) {
312            cpu->cd.arm.next_ic = (condition_gt[cpu->cd.arm.flags])?
313                (struct arm_instr_call *) ic->arg[0] :
314                (struct arm_instr_call *) ic->arg[1];
315    }
316    X(b_samepage__le) {
317            cpu->cd.arm.next_ic = (struct arm_instr_call *)
318                ic->arg[condition_gt[cpu->cd.arm.flags]];
319    }
320    void (*arm_cond_instr_b_samepage[16])(struct cpu *,
321            struct arm_instr_call *) = {
322            arm_instr_b_samepage__eq, arm_instr_b_samepage__ne,
323            arm_instr_b_samepage__cs, arm_instr_b_samepage__cc,
324            arm_instr_b_samepage__mi, arm_instr_b_samepage__pl,
325            arm_instr_b_samepage__vs, arm_instr_b_samepage__vc,
326            arm_instr_b_samepage__hi, arm_instr_b_samepage__ls,
327            arm_instr_b_samepage__ge, arm_instr_b_samepage__lt,
328            arm_instr_b_samepage__gt, arm_instr_b_samepage__le,
329            arm_instr_b_samepage, arm_instr_nop };
330    
331    
332  /*  /*
# Line 335  Y(b_samepage) Line 336  Y(b_samepage)
336   */   */
337  X(bx)  X(bx)
338  {  {
339          cpu->pc = cpu->cd.arm.r[ARM_PC] = reg(ic->arg[0]);          cpu->pc = reg(ic->arg[0]);
340          if (cpu->pc & 1) {          if (cpu->pc & 1) {
341                  fatal("thumb: TODO\n");                  fatal("thumb: TODO\n");
342                  exit(1);                  exit(1);
# Line 343  X(bx) Line 344  X(bx)
344          cpu->pc &= ~3;          cpu->pc &= ~3;
345    
346          /*  Find the new physical page and update the translation pointers:  */          /*  Find the new physical page and update the translation pointers:  */
347          arm_pc_to_pointers(cpu);          quick_pc_to_pointers(cpu);
348  }  }
349  Y(bx)  Y(bx)
350    
# Line 355  Y(bx) Line 356  Y(bx)
356   */   */
357  X(bx_trace)  X(bx_trace)
358  {  {
359          cpu->pc = cpu->cd.arm.r[ARM_PC] = cpu->cd.arm.r[ARM_LR];          cpu->pc = cpu->cd.arm.r[ARM_LR];
360          if (cpu->pc & 1) {          if (cpu->pc & 1) {
361                  fatal("thumb: TODO\n");                  fatal("thumb: TODO\n");
362                  exit(1);                  exit(1);
# Line 365  X(bx_trace) Line 366  X(bx_trace)
366          cpu_functioncall_trace_return(cpu);          cpu_functioncall_trace_return(cpu);
367    
368          /*  Find the new physical page and update the translation pointers:  */          /*  Find the new physical page and update the translation pointers:  */
369          arm_pc_to_pointers(cpu);          quick_pc_to_pointers(cpu);
370  }  }
371  Y(bx_trace)  Y(bx_trace)
372    
# Line 377  Y(bx_trace) Line 378  Y(bx_trace)
378   */   */
379  X(bl)  X(bl)
380  {  {
381          uint32_t lr, low_pc;          uint32_t pc = ((uint32_t)cpu->pc & 0xfffff000) + (int32_t)ic->arg[1];
382            cpu->cd.arm.r[ARM_LR] = pc + 4;
         /*  Figure out what the return (link) address will be:  */  
         low_pc = ((size_t)cpu->cd.arm.next_ic - (size_t)  
             cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);  
         lr = cpu->cd.arm.r[ARM_PC];  
         lr &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);  
         lr += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);  
   
         /*  Link:  */  
         cpu->cd.arm.r[ARM_LR] = lr;  
383    
384          /*  Calculate new PC from this instruction + arg[0]  */          /*  Calculate new PC from this instruction + arg[0]  */
385          cpu->pc = cpu->cd.arm.r[ARM_PC] = lr - 4 + (int32_t)ic->arg[0];          cpu->pc = pc + (int32_t)ic->arg[0];
386    
387          /*  Find the new physical page and update the translation pointers:  */          /*  Find the new physical page and update the translation pointers:  */
388          arm_pc_to_pointers(cpu);          quick_pc_to_pointers(cpu);
389  }  }
390  Y(bl)  Y(bl)
391    
# Line 405  Y(bl) Line 397  Y(bl)
397   */   */
398  X(blx)  X(blx)
399  {  {
400          uint32_t lr, low_pc;          uint32_t lr = ((uint32_t)cpu->pc & 0xfffff000) + (int32_t)ic->arg[2];
   
         /*  Figure out what the return (link) address will be:  */  
         low_pc = ((size_t)cpu->cd.arm.next_ic - (size_t)  
             cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);  
         lr = cpu->cd.arm.r[ARM_PC];  
         lr &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);  
         lr += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);  
   
         /*  Link:  */  
401          cpu->cd.arm.r[ARM_LR] = lr;          cpu->cd.arm.r[ARM_LR] = lr;
402            cpu->pc = reg(ic->arg[0]);
         cpu->pc = cpu->cd.arm.r[ARM_PC] = reg(ic->arg[0]);  
403          if (cpu->pc & 1) {          if (cpu->pc & 1) {
404                  fatal("thumb: TODO\n");                  fatal("thumb: TODO\n");
405                  exit(1);                  exit(1);
# Line 425  X(blx) Line 407  X(blx)
407          cpu->pc &= ~3;          cpu->pc &= ~3;
408    
409          /*  Find the new physical page and update the translation pointers:  */          /*  Find the new physical page and update the translation pointers:  */
410          arm_pc_to_pointers(cpu);          quick_pc_to_pointers(cpu);
411  }  }
412  Y(blx)  Y(blx)
413    
# Line 437  Y(blx) Line 419  Y(blx)
419   */   */
420  X(bl_trace)  X(bl_trace)
421  {  {
422          uint32_t lr, low_pc;          uint32_t pc = ((uint32_t)cpu->pc & 0xfffff000) + (int32_t)ic->arg[1];
423            cpu->cd.arm.r[ARM_LR] = pc + 4;
         /*  Figure out what the return (link) address will be:  */  
         low_pc = ((size_t)cpu->cd.arm.next_ic - (size_t)  
             cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);  
         lr = cpu->cd.arm.r[ARM_PC];  
         lr &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);  
         lr += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);  
   
         /*  Link:  */  
         cpu->cd.arm.r[ARM_LR] = lr;  
424    
425          /*  Calculate new PC from this instruction + arg[0]  */          /*  Calculate new PC from this instruction + arg[0]  */
426          cpu->pc = cpu->cd.arm.r[ARM_PC] = lr - 4 + (int32_t)ic->arg[0];          cpu->pc = pc + (int32_t)ic->arg[0];
427    
428          cpu_functioncall_trace(cpu, cpu->pc);          cpu_functioncall_trace(cpu, cpu->pc);
429    
430          /*  Find the new physical page and update the translation pointers:  */          /*  Find the new physical page and update the translation pointers:  */
431          arm_pc_to_pointers(cpu);          quick_pc_to_pointers(cpu);
432  }  }
433  Y(bl_trace)  Y(bl_trace)
434    
# Line 467  Y(bl_trace) Line 440  Y(bl_trace)
440   */   */
441  X(bl_samepage)  X(bl_samepage)
442  {  {
443          uint32_t lr, low_pc;          cpu->cd.arm.r[ARM_LR] =
444                ((uint32_t)cpu->pc & 0xfffff000) + (int32_t)ic->arg[2];
         /*  Figure out what the return (link) address will be:  */  
         low_pc = ((size_t)cpu->cd.arm.next_ic - (size_t)  
             cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);  
         lr = cpu->cd.arm.r[ARM_PC];  
         lr &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);  
         lr += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);  
   
         /*  Link:  */  
         cpu->cd.arm.r[ARM_LR] = lr;  
   
         /*  Branch:  */  
445          cpu->cd.arm.next_ic = (struct arm_instr_call *) ic->arg[0];          cpu->cd.arm.next_ic = (struct arm_instr_call *) ic->arg[0];
446  }  }
447  Y(bl_samepage)  Y(bl_samepage)
# Line 492  Y(bl_samepage) Line 454  Y(bl_samepage)
454   */   */
455  X(bl_samepage_trace)  X(bl_samepage_trace)
456  {  {
457          uint32_t tmp_pc, lr, low_pc;          uint32_t low_pc, lr = (cpu->pc & 0xfffff000) + ic->arg[2];
   
         /*  Figure out what the return (link) address will be:  */  
         low_pc = ((size_t)cpu->cd.arm.next_ic - (size_t)  
             cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);  
         lr = cpu->cd.arm.r[ARM_PC];  
         lr &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);  
         lr += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);  
458    
459          /*  Link:  */          /*  Link and branch:  */
460          cpu->cd.arm.r[ARM_LR] = lr;          cpu->cd.arm.r[ARM_LR] = lr;
   
         /*  Branch:  */  
461          cpu->cd.arm.next_ic = (struct arm_instr_call *) ic->arg[0];          cpu->cd.arm.next_ic = (struct arm_instr_call *) ic->arg[0];
462    
463            /*  Synchronize the program counter:  */
464          low_pc = ((size_t)cpu->cd.arm.next_ic - (size_t)          low_pc = ((size_t)cpu->cd.arm.next_ic - (size_t)
465              cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);              cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
466          tmp_pc = cpu->cd.arm.r[ARM_PC];          cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1)
         tmp_pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1)  
467              << ARM_INSTR_ALIGNMENT_SHIFT);              << ARM_INSTR_ALIGNMENT_SHIFT);
468          tmp_pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);          cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
469          cpu_functioncall_trace(cpu, tmp_pc);  
470            /*  ... and show trace:  */
471            cpu_functioncall_trace(cpu, cpu->pc);
472  }  }
473  Y(bl_samepage_trace)  Y(bl_samepage_trace)
474    
475    
476  /*  /*
477     *  clz: Count leading zeroes.
478     *
479     *  arg[0] = ptr to rm
480     *  arg[1] = ptr to rd
481     */
482    X(clz)
483    {
484            uint32_t rm = reg(ic->arg[0]);
485            int i = 32, n = 0, j;
486            while (i>0) {
487                    if (rm & 0xff000000) {
488                            for (j=0; j<8; j++) {
489                                    if (rm & 0x80000000)
490                                            break;
491                                    n ++;
492                                    rm <<= 1;
493                            }
494                            break;
495                    } else {
496                            rm <<= 8;
497                            i -= 8;
498                            n += 8;
499                    }
500            }
501            reg(ic->arg[1]) = n;
502    }
503    Y(clz)
504    
505    
506    /*
507   *  mul: Multiplication   *  mul: Multiplication
508   *   *
509   *  arg[0] = ptr to rd   *  arg[0] = ptr to rd
# Line 532  X(mul) Line 517  X(mul)
517  Y(mul)  Y(mul)
518  X(muls)  X(muls)
519  {  {
520          uint32_t result = reg(ic->arg[1]) * reg(ic->arg[2]);          uint32_t result;
521          cpu->cd.arm.cpsr &= ~(ARM_FLAG_Z | ARM_FLAG_N);          result = reg(ic->arg[1]) * reg(ic->arg[2]);
522            cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N);
523          if (result == 0)          if (result == 0)
524                  cpu->cd.arm.cpsr |= ARM_FLAG_Z;                  cpu->cd.arm.flags |= ARM_F_Z;
525          if (result & 0x80000000)          if (result & 0x80000000)
526                  cpu->cd.arm.cpsr |= ARM_FLAG_N;                  cpu->cd.arm.flags |= ARM_F_N;
527          reg(ic->arg[0]) = result;          reg(ic->arg[0]) = result;
528  }  }
529  Y(muls)  Y(muls)
# Line 552  X(mla) Line 538  X(mla)
538  {  {
539          /*  xxxx0000 00ASdddd nnnnssss 1001mmmm (Rd,Rm,Rs[,Rn])  */          /*  xxxx0000 00ASdddd nnnnssss 1001mmmm (Rd,Rm,Rs[,Rn])  */
540          uint32_t iw = ic->arg[0];          uint32_t iw = ic->arg[0];
541          int rd = (iw >> 16) & 15, rn = (iw >> 12) & 15,          int rd, rs, rn, rm;
542              rs = (iw >> 8) & 15,  rm = iw & 15;          rd = (iw >> 16) & 15; rn = (iw >> 12) & 15,
543            rs = (iw >> 8) & 15;  rm = iw & 15;
544          cpu->cd.arm.r[rd] = cpu->cd.arm.r[rm] * cpu->cd.arm.r[rs]          cpu->cd.arm.r[rd] = cpu->cd.arm.r[rm] * cpu->cd.arm.r[rs]
545              + cpu->cd.arm.r[rn];              + cpu->cd.arm.r[rn];
546  }  }
# Line 562  X(mlas) Line 549  X(mlas)
549  {  {
550          /*  xxxx0000 00ASdddd nnnnssss 1001mmmm (Rd,Rm,Rs[,Rn])  */          /*  xxxx0000 00ASdddd nnnnssss 1001mmmm (Rd,Rm,Rs[,Rn])  */
551          uint32_t iw = ic->arg[0];          uint32_t iw = ic->arg[0];
552          int rd = (iw >> 16) & 15, rn = (iw >> 12) & 15,          int rd, rs, rn, rm;
553              rs = (iw >> 8) & 15,  rm = iw & 15;          rd = (iw >> 16) & 15; rn = (iw >> 12) & 15,
554            rs = (iw >> 8) & 15;  rm = iw & 15;
555          cpu->cd.arm.r[rd] = cpu->cd.arm.r[rm] * cpu->cd.arm.r[rs]          cpu->cd.arm.r[rd] = cpu->cd.arm.r[rm] * cpu->cd.arm.r[rs]
556              + cpu->cd.arm.r[rn];              + cpu->cd.arm.r[rn];
557          cpu->cd.arm.cpsr &= ~(ARM_FLAG_Z | ARM_FLAG_N);          cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N);
558          if (cpu->cd.arm.r[rd] == 0)          if (cpu->cd.arm.r[rd] == 0)
559                  cpu->cd.arm.cpsr |= ARM_FLAG_Z;                  cpu->cd.arm.flags |= ARM_F_Z;
560          if (cpu->cd.arm.r[rd] & 0x80000000)          if (cpu->cd.arm.r[rd] & 0x80000000)
561                  cpu->cd.arm.cpsr |= ARM_FLAG_N;                  cpu->cd.arm.flags |= ARM_F_N;
562  }  }
563  Y(mlas)  Y(mlas)
564    
# Line 583  Y(mlas) Line 571  Y(mlas)
571  X(mull)  X(mull)
572  {  {
573          /*  xxxx0000 1UAShhhh llllssss 1001mmmm  */          /*  xxxx0000 1UAShhhh llllssss 1001mmmm  */
574          uint32_t iw = ic->arg[0];          uint32_t iw; uint64_t tmp; int u_bit, a_bit;
575          int u_bit = (iw >> 22) & 1, a_bit = (iw >> 21) & 1;          iw = ic->arg[0];
576          uint64_t tmp = cpu->cd.arm.r[iw & 15];          u_bit = iw & 0x00400000; a_bit = iw & 0x00200000;
577            tmp = cpu->cd.arm.r[iw & 15];
578          if (u_bit)          if (u_bit)
579                  tmp = (int64_t)(int32_t)tmp                  tmp = (int64_t)(int32_t)tmp
580                      * (int64_t)(int32_t)cpu->cd.arm.r[(iw >> 8) & 15];                      * (int64_t)(int32_t)cpu->cd.arm.r[(iw >> 8) & 15];
# Line 606  Y(mull) Line 595  Y(mull)
595    
596    
597  /*  /*
598     *  smulXY:  16-bit * 16-bit multiplication (32-bit result)
599     *
600     *  arg[0] = ptr to rm
601     *  arg[1] = ptr to rs
602     *  arg[2] = ptr to rd
603     */
604    X(smulbb)
605    {
606            reg(ic->arg[2]) = (int32_t)(int16_t)reg(ic->arg[0]) *
607                (int32_t)(int16_t)reg(ic->arg[1]);
608    }
609    Y(smulbb)
610    X(smultb)
611    {
612            reg(ic->arg[2]) = (int32_t)(int16_t)(reg(ic->arg[0]) >> 16) *
613                (int32_t)(int16_t)reg(ic->arg[1]);
614    }
615    Y(smultb)
616    X(smulbt)
617    {
618            reg(ic->arg[2]) = (int32_t)(int16_t)reg(ic->arg[0]) *
619                (int32_t)(int16_t)(reg(ic->arg[1]) >> 16);
620    }
621    Y(smulbt)
622    X(smultt)
623    {
624            reg(ic->arg[2]) = (int32_t)(int16_t)(reg(ic->arg[0]) >> 16) *
625                (int32_t)(int16_t)(reg(ic->arg[1]) >> 16);
626    }
627    Y(smultt)
628    
629    
630    /*
631   *  mov_reg_reg:  Move a register to another.   *  mov_reg_reg:  Move a register to another.
632   *   *
633   *  arg[0] = ptr to source register   *  arg[0] = ptr to source register
# Line 619  Y(mov_reg_reg) Line 641  Y(mov_reg_reg)
641    
642    
643  /*  /*
644     *  mov_reg_pc:  Move the PC register to a normal register.
645     *
646     *  arg[0] = offset compared to start of current page + 8
647     *  arg[1] = ptr to destination register
648     */
649    X(mov_reg_pc)
650    {
651            reg(ic->arg[1]) = ((uint32_t)cpu->pc&0xfffff000) + (int32_t)ic->arg[0];
652    }
653    Y(mov_reg_pc)
654    
655    
656    /*
657   *  ret_trace:  "mov pc,lr" with trace enabled   *  ret_trace:  "mov pc,lr" with trace enabled
658     *  ret:  "mov pc,lr" without trace enabled
659   *   *
660   *  arg[0] = ignored   *  arg[0] = ignored
661   */   */
662  X(ret_trace)  X(ret_trace)
663  {  {
664          uint32_t old_pc = cpu->cd.arm.r[ARM_PC];          uint32_t old_pc, mask_within_page;
665          uint32_t mask_within_page = ((ARM_IC_ENTRIES_PER_PAGE-1)          old_pc = cpu->pc;
666            mask_within_page = ((ARM_IC_ENTRIES_PER_PAGE-1)
667              << ARM_INSTR_ALIGNMENT_SHIFT) |              << ARM_INSTR_ALIGNMENT_SHIFT) |
668              ((1 << ARM_INSTR_ALIGNMENT_SHIFT) - 1);              ((1 << ARM_INSTR_ALIGNMENT_SHIFT) - 1);
669    
670          /*  Update the PC register:  */          /*  Update the PC register:  */
671          cpu->pc = cpu->cd.arm.r[ARM_PC] = cpu->cd.arm.r[ARM_LR];          cpu->pc = cpu->cd.arm.r[ARM_LR];
672    
673          cpu_functioncall_trace_return(cpu);          cpu_functioncall_trace_return(cpu);
674    
# Line 644  X(ret_trace) Line 681  X(ret_trace)
681                      ((cpu->pc & mask_within_page) >> ARM_INSTR_ALIGNMENT_SHIFT);                      ((cpu->pc & mask_within_page) >> ARM_INSTR_ALIGNMENT_SHIFT);
682          } else {          } else {
683                  /*  Find the new physical page and update pointers:  */                  /*  Find the new physical page and update pointers:  */
684                  arm_pc_to_pointers(cpu);                  quick_pc_to_pointers(cpu);
685          }          }
686  }  }
687  Y(ret_trace)  Y(ret_trace)
688    X(ret)
689    {
690            cpu->pc = cpu->cd.arm.r[ARM_LR];
691            quick_pc_to_pointers(cpu);
692    }
693    Y(ret)
694    
695    
696  /*  /*
# Line 668  X(msr_imm) Line 711  X(msr_imm)
711              (ic->arg[0] & ARM_FLAG_MODE));              (ic->arg[0] & ARM_FLAG_MODE));
712          uint32_t new_value = ic->arg[0];          uint32_t new_value = ic->arg[0];
713    
714            cpu->cd.arm.cpsr &= 0x0fffffff;
715            cpu->cd.arm.cpsr |= (cpu->cd.arm.flags << 28);
716    
717          if (switch_register_banks)          if (switch_register_banks)
718                  arm_save_register_bank(cpu);                  arm_save_register_bank(cpu);
719    
720          cpu->cd.arm.cpsr &= ~mask;          cpu->cd.arm.cpsr &= ~mask;
721          cpu->cd.arm.cpsr |= (new_value & mask);          cpu->cd.arm.cpsr |= (new_value & mask);
722    
723            cpu->cd.arm.flags = cpu->cd.arm.cpsr >> 28;
724    
725          if (switch_register_banks)          if (switch_register_banks)
726                  arm_load_register_bank(cpu);                  arm_load_register_bank(cpu);
727  }  }
# Line 715  X(msr_imm_spsr) Line 763  X(msr_imm_spsr)
763          /*  Synchronize the program counter:  */          /*  Synchronize the program counter:  */
764          uint32_t old_pc, low_pc = ((size_t)ic - (size_t)          uint32_t old_pc, low_pc = ((size_t)ic - (size_t)
765              cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);              cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
766          cpu->cd.arm.r[ARM_PC] &= ~((ARM_IC_ENTRIES_PER_PAGE-1)          cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
767              << ARM_INSTR_ALIGNMENT_SHIFT);          cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
768          cpu->cd.arm.r[ARM_PC] += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);          old_pc = cpu->pc;
769          old_pc = cpu->pc = cpu->cd.arm.r[ARM_PC];          printf("msr_spsr: old pc = 0x%08"PRIx32"\n", old_pc);
 printf("msr_spsr: old pc = 0x%08x\n", old_pc);  
770  }  }
771                  exit(1);                  exit(1);
772          }          }
# Line 740  Y(msr_spsr) Line 787  Y(msr_spsr)
787   */   */
788  X(mrs)  X(mrs)
789  {  {
790            cpu->cd.arm.cpsr &= 0x0fffffff;
791            cpu->cd.arm.cpsr |= (cpu->cd.arm.flags << 28);
792          reg(ic->arg[0]) = cpu->cd.arm.cpsr;          reg(ic->arg[0]) = cpu->cd.arm.cpsr;
793  }  }
794  Y(mrs)  Y(mrs)
795    
796    
797  /*  /*
798   *  mrs: Move from status/flag register to a normal register.   *  mrs: Move from saved status/flag register to a normal register.
799   *   *
800   *  arg[0] = pointer to rd   *  arg[0] = pointer to rd
801   */   */
# Line 775  Y(mrs_spsr) Line 824  Y(mrs_spsr)
824   *  arg[0] = copy of the instruction word   *  arg[0] = copy of the instruction word
825   */   */
826  X(mcr_mrc) {  X(mcr_mrc) {
827          uint32_t low_pc;          uint32_t low_pc = ((size_t)ic - (size_t)
         low_pc = ((size_t)ic - (size_t)  
828              cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);              cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
829          cpu->cd.arm.r[ARM_PC] &= ~((ARM_IC_ENTRIES_PER_PAGE-1)          cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
830              << ARM_INSTR_ALIGNMENT_SHIFT);          cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
         cpu->cd.arm.r[ARM_PC] += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);  
         cpu->pc = cpu->cd.arm.r[ARM_PC];  
831          arm_mcr_mrc(cpu, ic->arg[0]);          arm_mcr_mrc(cpu, ic->arg[0]);
832  }  }
833  Y(mcr_mrc)  Y(mcr_mrc)
834  X(cdp) {  X(cdp) {
835          uint32_t low_pc;          uint32_t low_pc = ((size_t)ic - (size_t)
         low_pc = ((size_t)ic - (size_t)  
836              cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);              cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
837          cpu->cd.arm.r[ARM_PC] &= ~((ARM_IC_ENTRIES_PER_PAGE-1)          cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
838              << ARM_INSTR_ALIGNMENT_SHIFT);          cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
         cpu->cd.arm.r[ARM_PC] += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);  
         cpu->pc = cpu->cd.arm.r[ARM_PC];  
839          arm_cdp(cpu, ic->arg[0]);          arm_cdp(cpu, ic->arg[0]);
840  }  }
841  Y(cdp)  Y(cdp)
# Line 803  Y(cdp) Line 846  Y(cdp)
846   */   */
847  X(openfirmware)  X(openfirmware)
848  {  {
849            /*  TODO: sync pc?  */
850          of_emul(cpu);          of_emul(cpu);
851          cpu->pc = cpu->cd.arm.r[ARM_PC] = cpu->cd.arm.r[ARM_LR];          cpu->pc = cpu->cd.arm.r[ARM_LR];
852          if (cpu->machine->show_trace_tree)          if (cpu->machine->show_trace_tree)
853                  cpu_functioncall_trace_return(cpu);                  cpu_functioncall_trace_return(cpu);
854          arm_pc_to_pointers(cpu);          quick_pc_to_pointers(cpu);
855    }
856    
857    
858    /*
859     *  reboot:
860     */
861    X(reboot)
862    {
863            cpu->running = 0;
864            cpu->n_translated_instrs --;
865            cpu->cd.arm.next_ic = &nothing_call;
866  }  }
867    
868    
# Line 821  X(swi_useremul) Line 876  X(swi_useremul)
876          /*  Synchronize the program counter:  */          /*  Synchronize the program counter:  */
877          uint32_t old_pc, low_pc = ((size_t)ic - (size_t)          uint32_t old_pc, low_pc = ((size_t)ic - (size_t)
878              cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);              cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
879          cpu->cd.arm.r[ARM_PC] &= ~((ARM_IC_ENTRIES_PER_PAGE-1)          cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1)
880              << ARM_INSTR_ALIGNMENT_SHIFT);              << ARM_INSTR_ALIGNMENT_SHIFT);
881          cpu->cd.arm.r[ARM_PC] += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);          cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
882          old_pc = cpu->pc = cpu->cd.arm.r[ARM_PC];          old_pc = cpu->pc;
883    
884          useremul_syscall(cpu, ic->arg[0]);          useremul_syscall(cpu, ic->arg[0]);
885    
886          if (!cpu->running) {          if (!cpu->running) {
                 cpu->running_translated = 0;  
887                  cpu->n_translated_instrs --;                  cpu->n_translated_instrs --;
888                  cpu->cd.arm.next_ic = &nothing_call;                  cpu->cd.arm.next_ic = &nothing_call;
889          } else if (cpu->pc != old_pc) {          } else if (cpu->pc != old_pc) {
890                  /*  PC was changed by the SWI call. Find the new physical                  /*  PC was changed by the SWI call. Find the new physical
891                      page and update the translation pointers:  */                      page and update the translation pointers:  */
892                  arm_pc_to_pointers(cpu);                  quick_pc_to_pointers(cpu);
893          }          }
894  }  }
895  Y(swi_useremul)  Y(swi_useremul)
# Line 846  Y(swi_useremul) Line 900  Y(swi_useremul)
900   */   */
901  X(swi)  X(swi)
902  {  {
903          /*  Synchronize the program counter:  */          /*  Synchronize the program counter first:  */
904          uint32_t low_pc = ((size_t)ic - (size_t)          cpu->pc &= 0xfffff000;
905              cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);          cpu->pc += ic->arg[0];
         cpu->cd.arm.r[ARM_PC] &= ~((ARM_IC_ENTRIES_PER_PAGE-1)  
             << ARM_INSTR_ALIGNMENT_SHIFT);  
         cpu->cd.arm.r[ARM_PC] += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);  
         cpu->pc = cpu->cd.arm.r[ARM_PC];  
   
906          arm_exception(cpu, ARM_EXCEPTION_SWI);          arm_exception(cpu, ARM_EXCEPTION_SWI);
907  }  }
908  Y(swi)  Y(swi)
909    
910    
911  /*  /*
912     *  und:  Undefined instruction.
913     */
914    X(und)
915    {
916            /*  Synchronize the program counter first:  */
917            cpu->pc &= 0xfffff000;
918            cpu->pc += ic->arg[0];
919            arm_exception(cpu, ARM_EXCEPTION_UND);
920    }
921    Y(und)
922    
923    
924    /*
925   *  swp, swpb:  Swap (word or byte).   *  swp, swpb:  Swap (word or byte).
926   *   *
927   *  arg[0] = ptr to rd   *  arg[0] = ptr to rd
# Line 870  X(swp) Line 932  X(swp)
932  {  {
933          uint32_t addr = reg(ic->arg[2]), data, data2;          uint32_t addr = reg(ic->arg[2]), data, data2;
934          unsigned char d[4];          unsigned char d[4];
935    
936          /*  Synchronize the program counter:  */          /*  Synchronize the program counter:  */
937          uint32_t low_pc = ((size_t)ic - (size_t)          uint32_t low_pc = ((size_t)ic - (size_t)
938              cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);              cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
939          cpu->cd.arm.r[ARM_PC] &= ~((ARM_IC_ENTRIES_PER_PAGE-1)          cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
940              << ARM_INSTR_ALIGNMENT_SHIFT);          cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
         cpu->cd.arm.r[ARM_PC] += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);  
         cpu->pc = cpu->cd.arm.r[ARM_PC];  
941    
942          if (!cpu->memory_rw(cpu, cpu->mem, addr, d, sizeof(d), MEM_READ,          if (!cpu->memory_rw(cpu, cpu->mem, addr, d, sizeof(d), MEM_READ,
943              CACHE_DATA)) {              CACHE_DATA)) {
# Line 898  X(swpb) Line 959  X(swpb)
959  {  {
960          uint32_t addr = reg(ic->arg[2]), data;          uint32_t addr = reg(ic->arg[2]), data;
961          unsigned char d[1];          unsigned char d[1];
962    
963          /*  Synchronize the program counter:  */          /*  Synchronize the program counter:  */
964          uint32_t low_pc = ((size_t)ic - (size_t)          uint32_t low_pc = ((size_t)ic - (size_t)
965              cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);              cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
966          cpu->cd.arm.r[ARM_PC] &= ~((ARM_IC_ENTRIES_PER_PAGE-1)          cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
967              << ARM_INSTR_ALIGNMENT_SHIFT);          cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
         cpu->cd.arm.r[ARM_PC] += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);  
         cpu->pc = cpu->cd.arm.r[ARM_PC];  
968    
969          if (!cpu->memory_rw(cpu, cpu->mem, addr, d, sizeof(d), MEM_READ,          if (!cpu->memory_rw(cpu, cpu->mem, addr, d, sizeof(d), MEM_READ,
970              CACHE_DATA)) {              CACHE_DATA)) {
# Line 925  Y(swpb) Line 985  Y(swpb)
985    
986  extern void (*arm_load_store_instr[1024])(struct cpu *,  extern void (*arm_load_store_instr[1024])(struct cpu *,
987          struct arm_instr_call *);          struct arm_instr_call *);
988    X(store_w1_word_u1_p0_imm);
989  X(store_w0_byte_u1_p0_imm);  X(store_w0_byte_u1_p0_imm);
990  X(store_w0_word_u1_p0_imm);  X(store_w0_word_u1_p0_imm);
991    X(store_w0_word_u1_p1_imm);
992    X(load_w0_word_u1_p0_imm);
993    X(load_w0_word_u1_p1_imm);
994    X(load_w1_word_u1_p0_imm);
995    X(load_w0_byte_u1_p1_imm);
996    X(load_w0_byte_u1_p1_reg);
997    X(load_w1_byte_u1_p1_imm);
998    
999  extern void (*arm_load_store_instr_pc[1024])(struct cpu *,  extern void (*arm_load_store_instr_pc[1024])(struct cpu *,
1000          struct arm_instr_call *);          struct arm_instr_call *);
# Line 937  extern void (*arm_load_store_instr_3[204 Line 1005  extern void (*arm_load_store_instr_3[204
1005  extern void (*arm_load_store_instr_3_pc[2048])(struct cpu *,  extern void (*arm_load_store_instr_3_pc[2048])(struct cpu *,
1006          struct arm_instr_call *);          struct arm_instr_call *);
1007    
1008    extern uint32_t (*arm_r[8192])(struct cpu *, struct arm_instr_call *);
1009    extern void arm_r_r3_t0_c0(void);
1010    
1011  extern void (*arm_dpi_instr[2 * 2 * 2 * 16 * 16])(struct cpu *,  extern void (*arm_dpi_instr[2 * 2 * 2 * 16 * 16])(struct cpu *,
1012          struct arm_instr_call *);          struct arm_instr_call *);
1013    extern void (*arm_dpi_instr_regshort[2 * 16 * 16])(struct cpu *,
1014            struct arm_instr_call *);
1015  X(cmps);  X(cmps);
1016    X(teqs);
1017    X(tsts);
1018  X(sub);  X(sub);
1019    X(add);
1020  X(subs);  X(subs);
1021    X(eor_regshort);
1022    X(cmps_regshort);
1023    
1024    
1025    #include "cpu_arm_instr_misc.c"
1026    
1027    
1028  /*  /*
1029   *  bdt_load:  Block Data Transfer, Load   *  bdt_load:  Block Data Transfer, Load
# Line 962  X(bdt_load) Line 1042  X(bdt_load)
1042          int u_bit = iw & 0x00800000;          int u_bit = iw & 0x00800000;
1043          int s_bit = iw & 0x00400000;          int s_bit = iw & 0x00400000;
1044          int w_bit = iw & 0x00200000;          int w_bit = iw & 0x00200000;
1045          int i, return_flag = 0, saved_mode = 0;          int i, return_flag = 0;
1046          uint32_t new_values[16];          uint32_t new_values[16];
1047    
1048    #ifdef GATHER_BDT_STATISTICS
1049            if (!s_bit)
1050                    update_bdt_statistics(iw);
1051    #endif
1052    
1053          /*  Synchronize the program counter:  */          /*  Synchronize the program counter:  */
1054          low_pc = ((size_t)ic - (size_t)          low_pc = ((size_t)ic - (size_t)
1055              cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);              cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
1056          cpu->cd.arm.r[ARM_PC] &= ~((ARM_IC_ENTRIES_PER_PAGE-1) <<          cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
1057              ARM_INSTR_ALIGNMENT_SHIFT);          cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
         cpu->cd.arm.r[ARM_PC] += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);  
         cpu->pc = cpu->cd.arm.r[ARM_PC];  
1058    
1059          if (s_bit) {          if (s_bit) {
1060                  /*  Load USR registers:  */                  /*  Load to USR registers:  */
1061                  if ((cpu->cd.arm.cpsr & ARM_FLAG_MODE) == ARM_MODE_USR32) {                  if ((cpu->cd.arm.cpsr & ARM_FLAG_MODE) == ARM_MODE_USR32) {
1062                          fatal("[ bdt_load: s-bit: in usermode? ]\n");                          fatal("[ bdt_load: s-bit: in usermode? ]\n");
1063                          s_bit = 0;                          s_bit = 0;
1064                  } else if (iw & 0x8000) {                  }
1065                    if (iw & 0x8000) {
1066                          s_bit = 0;                          s_bit = 0;
1067                          return_flag = 1;                          return_flag = 1;
                 } else {  
                         /*  Which saved mode to restore to:  */  
                         uint32_t spsr;  
                         switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) {  
                         case ARM_MODE_FIQ32:  
                                 spsr = cpu->cd.arm.spsr_fiq; break;  
                         case ARM_MODE_ABT32:  
                                 spsr = cpu->cd.arm.spsr_abt; break;  
                         case ARM_MODE_UND32:  
                                 spsr = cpu->cd.arm.spsr_und; break;  
                         case ARM_MODE_IRQ32:  
                                 spsr = cpu->cd.arm.spsr_irq; break;  
                         case ARM_MODE_SVC32:  
                                 spsr = cpu->cd.arm.spsr_svc; break;  
                         default:fatal("bdt_load (1): unimplemented mode %i\n",  
                                     cpu->cd.arm.cpsr & ARM_FLAG_MODE);  
                                 exit(1);  
                         }  
                         saved_mode = spsr & ARM_FLAG_MODE;  
1068                  }                  }
1069          }          }
1070    
# Line 1069  X(bdt_load) Line 1134  X(bdt_load)
1134                  if (!s_bit) {                  if (!s_bit) {
1135                          cpu->cd.arm.r[i] = new_values[i];                          cpu->cd.arm.r[i] = new_values[i];
1136                  } else {                  } else {
1137                          switch (saved_mode) {                          switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) {
1138                          case ARM_MODE_USR32:                          case ARM_MODE_USR32:
1139                          case ARM_MODE_SYS32:                          case ARM_MODE_SYS32:
1140                                  if (i >= 8 && i <= 14)                                  cpu->cd.arm.r[i] = new_values[i];
                                         cpu->cd.arm.default_r8_r14[i-8] =  
                                             new_values[i];  
                                 else  
                                         cpu->cd.arm.r[i] = new_values[i];  
1141                                  break;                                  break;
1142                          case ARM_MODE_FIQ32:                          case ARM_MODE_FIQ32:
1143                                  if (i >= 8 && i <= 14)                                  if (i >= 8 && i <= 14)
1144                                          cpu->cd.arm.fiq_r8_r14[i-8] =                                          cpu->cd.arm.default_r8_r14[i-8] =
                                             new_values[i];  
                                 else  
                                         cpu->cd.arm.r[i] = new_values[i];  
                                 break;  
                         case ARM_MODE_IRQ32:  
                                 if (i >= 13 && i <= 14)  
                                         cpu->cd.arm.irq_r13_r14[i-13] =  
1145                                              new_values[i];                                              new_values[i];
1146                                  else                                  else
1147                                          cpu->cd.arm.r[i] = new_values[i];                                          cpu->cd.arm.r[i] = new_values[i];
1148                                  break;                                  break;
1149                          case ARM_MODE_SVC32:                          case ARM_MODE_SVC32:
                                 if (i >= 13 && i <= 14)  
                                         cpu->cd.arm.svc_r13_r14[i-13] =  
                                             new_values[i];  
                                 else  
                                         cpu->cd.arm.r[i] = new_values[i];  
                                 break;  
1150                          case ARM_MODE_ABT32:                          case ARM_MODE_ABT32:
                                 if (i >= 13 && i <= 14)  
                                         cpu->cd.arm.abt_r13_r14[i-13] =  
                                             new_values[i];  
                                 else  
                                         cpu->cd.arm.r[i] = new_values[i];  
                                 break;  
1151                          case ARM_MODE_UND32:                          case ARM_MODE_UND32:
1152                            case ARM_MODE_IRQ32:
1153                                  if (i >= 13 && i <= 14)                                  if (i >= 13 && i <= 14)
1154                                          cpu->cd.arm.und_r13_r14[i-13] =                                          cpu->cd.arm.default_r8_r14[i-8] =
1155                                              new_values[i];                                              new_values[i];
1156                                  else                                  else
1157                                          cpu->cd.arm.r[i] = new_values[i];                                          cpu->cd.arm.r[i] = new_values[i];
# Line 1147  X(bdt_load) Line 1190  X(bdt_load)
1190                          arm_save_register_bank(cpu);                          arm_save_register_bank(cpu);
1191    
1192                  cpu->cd.arm.cpsr = new_cpsr;                  cpu->cd.arm.cpsr = new_cpsr;
1193                    cpu->cd.arm.flags = cpu->cd.arm.cpsr >> 28;
1194    
1195                  if (switch_register_banks)                  if (switch_register_banks)
1196                          arm_load_register_bank(cpu);                          arm_load_register_bank(cpu);
# Line 1154  X(bdt_load) Line 1198  X(bdt_load)
1198    
1199          /*  NOTE: Special case: Loading the PC  */          /*  NOTE: Special case: Loading the PC  */
1200          if (iw & 0x8000) {          if (iw & 0x8000) {
1201                  cpu->cd.arm.r[ARM_PC] &= ~3;                  cpu->pc = cpu->cd.arm.r[ARM_PC] & 0xfffffffc;
                 cpu->pc = cpu->cd.arm.r[ARM_PC];  
1202                  if (cpu->machine->show_trace_tree)                  if (cpu->machine->show_trace_tree)
1203                          cpu_functioncall_trace_return(cpu);                          cpu_functioncall_trace_return(cpu);
1204                  /*  TODO: There is no need to update the                  /*  TODO: There is no need to update the
# Line 1163  X(bdt_load) Line 1206  X(bdt_load)
1206                      same page!  */                      same page!  */
1207                  /*  Find the new physical page and update the                  /*  Find the new physical page and update the
1208                      translation pointers:  */                      translation pointers:  */
1209                  arm_pc_to_pointers(cpu);                  quick_pc_to_pointers(cpu);
1210          }          }
1211  }  }
1212  Y(bdt_load)  Y(bdt_load)
# Line 1186  X(bdt_store) Line 1229  X(bdt_store)
1229          int u_bit = iw & 0x00800000;          int u_bit = iw & 0x00800000;
1230          int s_bit = iw & 0x00400000;          int s_bit = iw & 0x00400000;
1231          int w_bit = iw & 0x00200000;          int w_bit = iw & 0x00200000;
1232          int i, saved_mode = 0;          int i;
1233    
1234          if (s_bit) {  #ifdef GATHER_BDT_STATISTICS
1235                  /*  Store USR (or saved) registers:  */          if (!s_bit)
1236                  uint32_t spsr;                  update_bdt_statistics(iw);
1237                  switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) {  #endif
                 case ARM_MODE_FIQ32:  
                         spsr = cpu->cd.arm.spsr_fiq; break;  
                 case ARM_MODE_ABT32:  
                         spsr = cpu->cd.arm.spsr_abt; break;  
                 case ARM_MODE_UND32:  
                         spsr = cpu->cd.arm.spsr_und; break;  
                 case ARM_MODE_IRQ32:  
                         spsr = cpu->cd.arm.spsr_irq; break;  
                 case ARM_MODE_SVC32:  
                         spsr = cpu->cd.arm.spsr_svc; break;  
                 default:fatal("bdt_store: unimplemented mode %i\n",  
                             cpu->cd.arm.cpsr & ARM_FLAG_MODE);  
                         exit(1);  
                 }  
                 saved_mode = spsr & ARM_FLAG_MODE;  
         }  
1238    
1239          /*  Synchronize the program counter:  */          /*  Synchronize the program counter:  */
1240          low_pc = ((size_t)ic - (size_t)          low_pc = ((size_t)ic - (size_t)
1241              cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);              cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
1242          cpu->cd.arm.r[ARM_PC] &= ~((ARM_IC_ENTRIES_PER_PAGE-1) <<          cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
1243              ARM_INSTR_ALIGNMENT_SHIFT);          cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
         cpu->cd.arm.r[ARM_PC] += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);  
         cpu->pc = cpu->cd.arm.r[ARM_PC];  
1244    
1245          for (i=(u_bit? 0 : 15); i>=0 && i<=15; i+=(u_bit? 1 : -1)) {          for (i=(u_bit? 0 : 15); i>=0 && i<=15; i+=(u_bit? 1 : -1)) {
1246                  if (!((iw >> i) & 1)) {                  if (!((iw >> i) & 1)) {
# Line 1226  X(bdt_store) Line 1251  X(bdt_store)
1251                  value = cpu->cd.arm.r[i];                  value = cpu->cd.arm.r[i];
1252    
1253                  if (s_bit) {                  if (s_bit) {
1254                          switch (saved_mode) {                          switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) {
1255                          case ARM_MODE_FIQ32:                          case ARM_MODE_FIQ32:
1256                                  if (i >= 8 && i <= 14)                                  if (i >= 8 && i <= 14)
1257                                          value = cpu->cd.arm.fiq_r8_r14[i-8];                                          value = cpu->cd.arm.default_r8_r14[i-8];
1258                                  break;                                  break;
1259                          case ARM_MODE_ABT32:                          case ARM_MODE_ABT32:
                                 if (i >= 13 && i <= 14)  
                                         value = cpu->cd.arm.abt_r13_r14[i-13];  
                                 break;  
1260                          case ARM_MODE_UND32:                          case ARM_MODE_UND32:
                                 if (i >= 13 && i <= 14)  
                                         value = cpu->cd.arm.und_r13_r14[i-13];  
                                 break;  
1261                          case ARM_MODE_IRQ32:                          case ARM_MODE_IRQ32:
                                 if (i >= 13 && i <= 14)  
                                         value = cpu->cd.arm.irq_r13_r14[i-13];  
                                 break;  
1262                          case ARM_MODE_SVC32:                          case ARM_MODE_SVC32:
1263                                  if (i >= 13 && i <= 14)                                  if (i >= 13 && i <= 14)
1264                                          value = cpu->cd.arm.svc_r13_r14[i-13];                                          value = cpu->cd.arm.default_r8_r14[i-8];
1265                                  break;                                  break;
1266                          case ARM_MODE_USR32:                          case ARM_MODE_USR32:
1267                          case ARM_MODE_SYS32:                          case ARM_MODE_SYS32:
                                 if (i >= 8 && i <= 14)  
                                         value = cpu->cd.arm.default_r8_r14[i-8];  
1268                                  break;                                  break;
1269                          }                          }
1270                  }                  }
1271    
1272                    /*  NOTE/TODO: 8 vs 12 on some ARMs  */
1273                  if (i == ARM_PC)                  if (i == ARM_PC)
1274                          value += 12;    /*  NOTE/TODO: 8 on some ARMs  */                          value = cpu->pc + 12;
1275    
1276                  if (p_bit) {                  if (p_bit) {
1277                          if (u_bit)                          if (u_bit)
# Line 1313  X(bdt_store) Line 1328  X(bdt_store)
1328  Y(bdt_store)  Y(bdt_store)
1329    
1330    
1331    /*  Various load/store multiple instructions:  */
1332    extern uint32_t *multi_opcode[256];
1333    extern void (**multi_opcode_f[256])(struct cpu *, struct arm_instr_call *);
1334    X(multi_0x08b15018);
1335    X(multi_0x08ac000c__ge);
1336    X(multi_0x08a05018);
1337    
1338    
1339  /*****************************************************************************/  /*****************************************************************************/
1340    
1341    
1342  /*  /*
1343   *  fill_loop_test:   *  netbsd_memset:
  *  
  *  A byte-fill loop. Fills at most one page at a time. If the page was not  
  *  in the host_store table, then the original sequence (beginning with  
  *  cmps rZ,#0) is executed instead.  
1344   *   *
1345   *  L: cmps rZ,#0               ic[0]   *  The core of a NetBSD/arm memset.
  *     strb rX,[rY],#1          ic[1]  
  *     sub  rZ,rZ,#1            ic[2]  
  *     bgt  L                   ic[3]  
1346   *   *
1347   *  A maximum of 4 pages are filled before returning.   *  f01bc420:  e25XX080     subs    rX,rX,#0x80
1348     *  f01bc424:  a8ac000c     stmgeia ip!,{r2,r3}   (16 of these)
1349     *  ..
1350     *  f01bc464:  caffffed     bgt     0xf01bc420      <memset+0x38>
1351   */   */
1352  X(fill_loop_test)  X(netbsd_memset)
1353  {  {
         int max_pages_left = 4;  
         uint32_t addr, a, n, ofs, maxlen;  
         uint32_t *rzp = (uint32_t *)(size_t)ic[0].arg[0];  
1354          unsigned char *page;          unsigned char *page;
1355            uint32_t addr;
1356    
1357            do {
1358                    addr = cpu->cd.arm.r[ARM_IP];
1359    
1360                    instr(subs)(cpu, ic);
1361    
1362                    if (((cpu->cd.arm.flags & ARM_F_N)?1:0) !=
1363                        ((cpu->cd.arm.flags & ARM_F_V)?1:0)) {
1364                            cpu->n_translated_instrs += 16;
1365                            /*  Skip the store multiples:  */
1366                            cpu->cd.arm.next_ic = &ic[17];
1367                            return;
1368                    }
1369    
1370                    /*  Crossing a page boundary? Then continue non-combined.  */
1371                    if ((addr & 0xfff) + 128 > 0x1000)
1372                            return;
1373    
1374                    /*  R2/R3 non-zero? Not allowed here.  */
1375                    if (cpu->cd.arm.r[2] != 0 || cpu->cd.arm.r[3] != 0)
1376                            return;
1377    
1378                    /*  printf("addr = 0x%08x\n", addr);  */
1379    
1380                    page = cpu->cd.arm.host_store[addr >> 12];
1381                    /*  No page translation? Continue non-combined.  */
1382                    if (page == NULL)
1383                            return;
1384    
1385                    /*  Clear:  */
1386                    memset(page + (addr & 0xfff), 0, 128);
1387                    cpu->cd.arm.r[ARM_IP] = addr + 128;
1388                    cpu->n_translated_instrs += 16;
1389    
1390                    /*  Branch back if greater:  */
1391                    cpu->n_translated_instrs += 1;
1392            } while (((cpu->cd.arm.flags & ARM_F_N)?1:0) ==
1393                ((cpu->cd.arm.flags & ARM_F_V)?1:0) &&
1394                !(cpu->cd.arm.flags & ARM_F_Z));
1395    
1396            /*  Continue at the instruction after the bgt:  */
1397            cpu->cd.arm.next_ic = &ic[18];
1398    }
1399    
1400    
1401    /*
1402     *  netbsd_memcpy:
1403     *
1404     *  The core of a NetBSD/arm memcpy.
1405     *
1406     *  f01bc530:  e8b15018     ldmia   r1!,{r3,r4,ip,lr}
1407     *  f01bc534:  e8a05018     stmia   r0!,{r3,r4,ip,lr}
1408     *  f01bc538:  e8b15018     ldmia   r1!,{r3,r4,ip,lr}
1409     *  f01bc53c:  e8a05018     stmia   r0!,{r3,r4,ip,lr}
1410     *  f01bc540:  e2522020     subs    r2,r2,#0x20
1411     *  f01bc544:  aafffff9     bge     0xf01bc530
1412     */
1413    X(netbsd_memcpy)
1414    {
1415            unsigned char *page_0, *page_1;
1416            uint32_t addr_r0, addr_r1;
1417    
1418            do {
1419                    addr_r0 = cpu->cd.arm.r[0];
1420                    addr_r1 = cpu->cd.arm.r[1];
1421    
1422                    /*  printf("addr_r0 = %08x  r1 = %08x\n", addr_r0, addr_r1);  */
1423    
1424                    /*  Crossing a page boundary? Then continue non-combined.  */
1425                    if ((addr_r0 & 0xfff) + 32 > 0x1000 ||
1426                        (addr_r1 & 0xfff) + 32 > 0x1000) {
1427                            instr(multi_0x08b15018)(cpu, ic);
1428                            return;
1429                    }
1430    
1431                    page_0 = cpu->cd.arm.host_store[addr_r0 >> 12];
1432                    page_1 = cpu->cd.arm.host_store[addr_r1 >> 12];
1433    
1434                    /*  No page translations? Continue non-combined.  */
1435                    if (page_0 == NULL || page_1 == NULL) {
1436                            instr(multi_0x08b15018)(cpu, ic);
1437                            return;
1438                    }
1439    
1440                    memcpy(page_0 + (addr_r0 & 0xfff),
1441                        page_1 + (addr_r1 & 0xfff), 32);
1442                    cpu->cd.arm.r[0] = addr_r0 + 32;
1443                    cpu->cd.arm.r[1] = addr_r1 + 32;
1444    
1445                    cpu->n_translated_instrs += 4;
1446    
1447                    instr(subs)(cpu, ic + 4);
1448                    cpu->n_translated_instrs ++;
1449    
1450                    /*  Loop while greater or equal:  */
1451                    cpu->n_translated_instrs ++;
1452            } while (((cpu->cd.arm.flags & ARM_F_N)?1:0) ==
1453                ((cpu->cd.arm.flags & ARM_F_V)?1:0));
1454    
1455            /*  Continue at the instruction after the bge:  */
1456            cpu->cd.arm.next_ic = &ic[6];
1457            cpu->n_translated_instrs --;
1458    }
1459    
1460    
1461    /*
1462     *  netbsd_cacheclean:
1463     *
1464     *  The core of a NetBSD/arm cache clean routine, variant 1:
1465     *
1466     *  f015f88c:  e4902020     ldr     r2,[r0],#32
1467     *  f015f890:  e2511020     subs    r1,r1,#0x20
1468     *  f015f894:  1afffffc     bne     0xf015f88c
1469     *  f015f898:  ee070f9a     mcr     15,0,r0,cr7,cr10,4
1470     */
1471    X(netbsd_cacheclean)
1472    {
1473            uint32_t r1 = cpu->cd.arm.r[1];
1474            cpu->n_translated_instrs += ((r1 >> 5) * 3);
1475            cpu->cd.arm.r[0] += r1;
1476            cpu->cd.arm.r[1] = 0;
1477            cpu->cd.arm.next_ic = &ic[4];
1478    }
1479    
1480    
1481    /*
1482     *  netbsd_cacheclean2:
1483     *
1484     *  The core of a NetBSD/arm cache clean routine, variant 2:
1485     *
1486     *  f015f93c:  ee070f3a     mcr     15,0,r0,cr7,cr10,1
1487     *  f015f940:  ee070f36     mcr     15,0,r0,cr7,cr6,1
1488     *  f015f944:  e2800020     add     r0,r0,#0x20
1489     *  f015f948:  e2511020     subs    r1,r1,#0x20
1490     *  f015f94c:  8afffffa     bhi     0xf015f93c
1491     */
1492    X(netbsd_cacheclean2)
1493    {
1494            cpu->n_translated_instrs += ((cpu->cd.arm.r[1] >> 5) * 5) - 1;
1495            cpu->cd.arm.next_ic = &ic[5];
1496    }
1497    
1498    
1499    /*
1500     *  netbsd_scanc:
1501     *
1502     *  f01bccbc:  e5d13000     ldrb    r3,[r1]
1503     *  f01bccc0:  e7d23003     ldrb    r3,[r2,r3]
1504     *  f01bccc4:  e113000c     tsts    r3,ip
1505     */
1506    X(netbsd_scanc)
1507    {
1508            unsigned char *page = cpu->cd.arm.host_load[cpu->cd.arm.r[1] >> 12];
1509            uint32_t t;
1510    
 restart_loop:  
         addr = reg(ic[1].arg[0]);  
         page = cpu->cd.arm.host_store[addr >> 12];  
1511          if (page == NULL) {          if (page == NULL) {
1512                  instr(cmps)(cpu, ic);                  instr(load_w0_byte_u1_p1_imm)(cpu, ic);
1513                  return;                  return;
1514          }          }
1515    
1516          n = reg(rzp) + 1;          t = page[cpu->cd.arm.r[1] & 0xfff];
1517          ofs = addr & 0xfff;          t += cpu->cd.arm.r[2];
1518          maxlen = 4096 - ofs;          page = cpu->cd.arm.host_load[t >> 12];
         if (n > maxlen)  
                 n = maxlen;  
1519    
1520          /*  printf("x = %x, n = %i\n", reg(ic[1].arg[2]), n);  */          if (page == NULL) {
1521          memset(page + ofs, reg(ic[1].arg[2]), n);                  instr(load_w0_byte_u1_p1_imm)(cpu, ic);
1522                    return;
1523            }
1524    
1525          reg(ic[1].arg[0]) = addr + n;          cpu->cd.arm.r[3] = page[t & 0xfff];
1526    
1527          reg(rzp) -= n;          t = cpu->cd.arm.r[3] & cpu->cd.arm.r[ARM_IP];
1528          cpu->n_translated_instrs += (4 * n);          cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N);
1529            if (t == 0)
1530                    cpu->cd.arm.flags |= ARM_F_Z;
1531    
1532          a = reg(rzp);          cpu->n_translated_instrs += 2;
1533            cpu->cd.arm.next_ic = &ic[3];
1534    }
1535    
         cpu->cd.arm.cpsr &=  
             ~(ARM_FLAG_Z | ARM_FLAG_N | ARM_FLAG_V | ARM_FLAG_C);  
         if (a != 0)  
                 cpu->cd.arm.cpsr |= ARM_FLAG_C;  
         else  
                 cpu->cd.arm.cpsr |= ARM_FLAG_Z;  
         if ((int32_t)a < 0)  
                 cpu->cd.arm.cpsr |= ARM_FLAG_N;  
1536    
1537          if (max_pages_left-- > 0 && (int32_t)a > 0)  /*
1538                  goto restart_loop;   *  netbsd_idle:
1539     *
1540     *  L:  ldr     rX,[rY]
1541     *      teqs    rX,#0
1542     *      bne     X (samepage)
1543     *      teqs    rZ,#0
1544     *      beq     L (samepage)
1545     *      ....
1546     *      X:  somewhere else on the same page
1547     */
1548    X(netbsd_idle)
1549    {
1550            uint32_t rY = reg(ic[0].arg[0]);
1551            uint32_t rZ = reg(ic[3].arg[0]);
1552            uint32_t *p;
1553            uint32_t rX;
1554    
1555          cpu->n_translated_instrs --;          p = (uint32_t *) cpu->cd.arm.host_load[rY >> 12];
1556            if (p == NULL) {
1557                    instr(load_w0_word_u1_p1_imm)(cpu, ic);
1558                    return;
1559            }
1560    
1561          if ((int32_t)a > 0)          rX = p[(rY & 0xfff) >> 2];
1562                  cpu->cd.arm.next_ic = ic;          /*  No need to convert endianness, since it's only a 0-test.  */
1563          else  
1564                  cpu->cd.arm.next_ic = &ic[4];          /*  This makes execution continue on the first teqs instruction,
1565                which is fine.  */
1566            if (rX != 0) {
1567                    instr(load_w0_word_u1_p1_imm)(cpu, ic);
1568                    return;
1569            }
1570    
1571            if (rZ == 0) {
1572                    static int x = 0;
1573    
1574                    /*  Synch the program counter.  */
1575                    uint32_t low_pc = ((size_t)ic - (size_t)
1576                        cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
1577                    cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1)
1578                        << ARM_INSTR_ALIGNMENT_SHIFT);
1579                    cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
1580    
1581                    /*  Quasi-idle for a while:  */
1582                    cpu->has_been_idling = 1;
1583                    if (cpu->machine->ncpus == 1 && (++x) == 100) {
1584                            usleep(50);
1585                            x = 0;
1586                    }
1587    
1588                    cpu->n_translated_instrs += N_SAFE_DYNTRANS_LIMIT / 6;
1589                    cpu->cd.arm.next_ic = &nothing_call;
1590                    return;
1591            }
1592    
1593            cpu->cd.arm.next_ic = &ic[5];
1594  }  }
1595    
1596    
1597  /*  /*
1598   *  fill_loop_test2:   *  strlen:
1599   *   *
1600   *  A word-fill loop. Fills at most one page at a time. If the page was not   *  S: e5f03001   ldrb  rY,[rX,#1]!
1601   *  in the host_store table, then the original sequence (beginning with   *     e3530000   cmps  rY,#0
1602   *  cmps rZ,#0) is executed instead.   *     1afffffc   bne   S
1603     */
1604    X(strlen)
1605    {
1606            unsigned int n_loops = 0;
1607            uint32_t rY, rX = reg(ic[0].arg[0]);
1608            unsigned char *p;
1609    
1610            do {
1611                    rX ++;
1612                    p = cpu->cd.arm.host_load[rX >> 12];
1613                    if (p == NULL) {
1614                            cpu->n_translated_instrs += (n_loops * 3);
1615                            instr(load_w1_byte_u1_p1_imm)(cpu, ic);
1616                            return;
1617                    }
1618    
1619                    rY = reg(ic[0].arg[2]) = p[rX & 0xfff]; /*  load  */
1620                    reg(ic[0].arg[0]) = rX;                 /*  writeback  */
1621                    n_loops ++;
1622    
1623                    /*  Compare rY to zero:  */
1624                    cpu->cd.arm.flags = ARM_F_C;
1625                    if (rY == 0)
1626                            cpu->cd.arm.flags |= ARM_F_Z;
1627            } while (rY != 0);
1628    
1629            cpu->n_translated_instrs += (n_loops * 3) - 1;
1630            cpu->cd.arm.next_ic = &ic[3];
1631    }
1632    
1633    
1634    /*
1635     *  xchg:
1636   *   *
1637   *      L: str     rX,[rY],#4           ic[0]   *  e02YX00X     eor     rX,rY,rX
1638   *         subs    rZ,rZ,#4             ic[1]   *  e02XY00Y     eor     rY,rX,rY
1639   *         bgt     L                    ic[2]   *  e02YX00X     eor     rX,rY,rX
1640     */
1641    X(xchg)
1642    {
1643            uint32_t tmp = reg(ic[0].arg[0]);
1644            cpu->n_translated_instrs += 2;
1645            cpu->cd.arm.next_ic = &ic[3];
1646            reg(ic[0].arg[0]) = reg(ic[1].arg[0]);
1647            reg(ic[1].arg[0]) = tmp;
1648    }
1649    
1650    
1651    /*
1652     *  netbsd_copyin:
1653   *   *
1654   *  A maximum of 5 pages are filled before returning.   *  e4b0a004     ldrt    sl,[r0],#4
1655     *  e4b0b004     ldrt    fp,[r0],#4
1656     *  e4b06004     ldrt    r6,[r0],#4
1657     *  e4b07004     ldrt    r7,[r0],#4
1658     *  e4b08004     ldrt    r8,[r0],#4
1659     *  e4b09004     ldrt    r9,[r0],#4
1660   */   */
1661  X(fill_loop_test2)  X(netbsd_copyin)
1662  {  {
1663          int max_pages_left = 5;          uint32_t r0 = cpu->cd.arm.r[0], ofs = (r0 & 0xffc), index = r0 >> 12;
1664          unsigned char x1,x2,x3,x4;          unsigned char *p = cpu->cd.arm.host_load[index];
1665          uint32_t addr, a, n, x, ofs, maxlen;          uint32_t *p32 = (uint32_t *) p, *q32;
1666          uint32_t *rzp = (uint32_t *)(size_t)ic[1].arg[0];          int ok = cpu->cd.arm.is_userpage[index >> 5] & (1 << (index & 31));
         unsigned char *page;  
1667    
1668          x = reg(ic[0].arg[2]);          if (ofs > 0x1000 - 6*4 || !ok || p == NULL) {
1669          x1 = x; x2 = x >> 8; x3 = x >> 16; x4 = x >> 24;                  instr(load_w1_word_u1_p0_imm)(cpu, ic);
         if (x1 != x2 || x1 != x3 || x1 != x4) {  
                 instr(store_w0_word_u1_p0_imm)(cpu, ic);  
1670                  return;                  return;
1671          }          }
1672            q32 = &cpu->cd.arm.r[6];
1673            ofs >>= 2;
1674            q32[0] = p32[ofs+2];
1675            q32[1] = p32[ofs+3];
1676            q32[2] = p32[ofs+4];
1677            q32[3] = p32[ofs+5];
1678            q32[4] = p32[ofs+0];
1679            q32[5] = p32[ofs+1];
1680            cpu->cd.arm.r[0] = r0 + 24;
1681            cpu->n_translated_instrs += 5;
1682            cpu->cd.arm.next_ic = &ic[6];
1683    }
1684    
1685    
1686    /*
1687     *  netbsd_copyout:
1688     *
1689     *  e4a18004     strt    r8,[r1],#4
1690     *  e4a19004     strt    r9,[r1],#4
1691     *  e4a1a004     strt    sl,[r1],#4
1692     *  e4a1b004     strt    fp,[r1],#4
1693     *  e4a16004     strt    r6,[r1],#4
1694     *  e4a17004     strt    r7,[r1],#4
1695     */
1696    X(netbsd_copyout)
1697    {
1698            uint32_t r1 = cpu->cd.arm.r[1], ofs = (r1 & 0xffc), index = r1 >> 12;
1699            unsigned char *p = cpu->cd.arm.host_store[index];
1700            uint32_t *p32 = (uint32_t *) p, *q32;
1701            int ok = cpu->cd.arm.is_userpage[index >> 5] & (1 << (index & 31));
1702    
1703  restart_loop:          if (ofs > 0x1000 - 6*4 || !ok || p == NULL) {
1704          addr = reg(ic[0].arg[0]);                  instr(store_w1_word_u1_p0_imm)(cpu, ic);
         page = cpu->cd.arm.host_store[addr >> 12];  
         if (page == NULL || (addr & 3) != 0) {  
                 instr(store_w0_word_u1_p0_imm)(cpu, ic);  
1705                  return;                  return;
1706          }          }
1707            q32 = &cpu->cd.arm.r[6];
1708            ofs >>= 2;
1709            p32[ofs  ] = q32[2];
1710            p32[ofs+1] = q32[3];
1711            p32[ofs+2] = q32[4];
1712            p32[ofs+3] = q32[5];
1713            p32[ofs+4] = q32[0];
1714            p32[ofs+5] = q32[1];
1715            cpu->cd.arm.r[1] = r1 + 24;
1716            cpu->n_translated_instrs += 5;
1717            cpu->cd.arm.next_ic = &ic[6];
1718    }
1719    
1720    
1721          /*  printf("addr = 0x%08x, page = %p\n", addr, page);  /*
1722              printf("*rzp = 0x%08x\n", reg(rzp));  */   *  cmps by 0, followed by beq (inside the same page):
1723     */
1724    X(cmps0_beq_samepage)
1725    {
1726            uint32_t a = reg(ic->arg[0]);
1727            cpu->n_translated_instrs ++;
1728            if (a == 0) {
1729                    cpu->cd.arm.flags = ARM_F_Z | ARM_F_C;
1730            } else {
1731                    /*  Semi-ugly hack which sets the negative-bit if a < 0:  */
1732                    cpu->cd.arm.flags = ARM_F_C | ((a >> 28) & 8);
1733            }
1734            if (a == 0)
1735                    cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0];
1736            else
1737                    cpu->cd.arm.next_ic = &ic[2];
1738    }
1739    
         n = reg(rzp) / 4;  
         if (n == 0)  
                 n++;  
         /*  n = nr of _words_  */  
         ofs = addr & 0xfff;  
         maxlen = 4096 - ofs;  
         if (n*4 > maxlen)  
                 n = maxlen / 4;  
1740    
1741          /*  printf("x = %x, n = %i\n", x1, n);  */  /*
1742          memset(page + ofs, x1, n * 4);   *  cmps followed by beq (inside the same page):
1743     */
1744    X(cmps_beq_samepage)
1745    {
1746            uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a - b;
1747            cpu->n_translated_instrs ++;
1748            cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0;
1749            if (((int32_t)a >= 0 && (int32_t)b < 0 && (int32_t)c < 0) ||
1750                ((int32_t)a < 0 && (int32_t)b >= 0 && (int32_t)c >= 0))
1751                    cpu->cd.arm.flags |= ARM_F_V;
1752            if (c == 0) {
1753                    cpu->cd.arm.flags |= ARM_F_Z;
1754                    cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0];
1755            } else {
1756                    cpu->cd.arm.next_ic = &ic[2];
1757                    if (c & 0x80000000)
1758                            cpu->cd.arm.flags |= ARM_F_N;
1759            }
1760    }
1761    
         reg(ic[0].arg[0]) = addr + n * 4;  
1762    
1763          reg(rzp) -= (n * 4);  /*
1764          cpu->n_translated_instrs += (3 * n);   *  cmps followed by beq (not the same page):
1765     */
1766    X(cmps_0_beq)
1767    {
1768            uint32_t a = reg(ic->arg[0]);
1769            cpu->n_translated_instrs ++;
1770            if (a == 0) {
1771                    cpu->cd.arm.flags = ARM_F_Z | ARM_F_C;
1772                    cpu->pc = (uint32_t)(((uint32_t)cpu->pc & 0xfffff000)
1773                        + (int32_t)ic[1].arg[0]);
1774                    quick_pc_to_pointers(cpu);
1775            } else {
1776                    /*  Semi-ugly hack which sets the negative-bit if a < 0:  */
1777                    cpu->cd.arm.flags = ARM_F_C | ((a >> 28) & 8);
1778                    cpu->cd.arm.next_ic = &ic[2];
1779            }
1780    }
1781    X(cmps_pos_beq)
1782    {
1783            uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a - b;
1784            cpu->n_translated_instrs ++;
1785            cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0;
1786            if ((int32_t)a < 0 && (int32_t)c >= 0)
1787                    cpu->cd.arm.flags |= ARM_F_V;
1788            if (c == 0) {
1789                    cpu->cd.arm.flags |= ARM_F_Z;
1790                    cpu->pc = (uint32_t)(((uint32_t)cpu->pc & 0xfffff000)
1791                        + (int32_t)ic[1].arg[0]);
1792                    quick_pc_to_pointers(cpu);
1793            } else {
1794                    cpu->cd.arm.next_ic = &ic[2];
1795                    if (c & 0x80000000)
1796                            cpu->cd.arm.flags |= ARM_F_N;
1797            }
1798    }
1799    X(cmps_neg_beq)
1800    {
1801            uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a - b;
1802            cpu->n_translated_instrs ++;
1803            cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0;
1804            if ((int32_t)a >= 0 && (int32_t)c < 0)
1805                    cpu->cd.arm.flags |= ARM_F_V;
1806            if (c == 0) {
1807                    cpu->cd.arm.flags |= ARM_F_Z;
1808                    cpu->pc = (uint32_t)(((uint32_t)cpu->pc & 0xfffff000)
1809                        + (int32_t)ic[1].arg[0]);
1810                    quick_pc_to_pointers(cpu);
1811            } else {
1812                    cpu->cd.arm.next_ic = &ic[2];
1813                    if (c & 0x80000000)
1814                            cpu->cd.arm.flags |= ARM_F_N;
1815            }
1816    }
1817    
         a = reg(rzp);  
1818    
1819          cpu->cd.arm.cpsr &=  /*
1820              ~(ARM_FLAG_Z | ARM_FLAG_N | ARM_FLAG_V | ARM_FLAG_C);   *  cmps by 0, followed by bne (inside the same page):
1821          if (a != 0)   */
1822                  cpu->cd.arm.cpsr |= ARM_FLAG_C;  X(cmps0_bne_samepage)
1823    {
1824            uint32_t a = reg(ic->arg[0]);
1825            cpu->n_translated_instrs ++;
1826            if (a == 0) {
1827                    cpu->cd.arm.flags = ARM_F_Z | ARM_F_C;
1828            } else {
1829                    /*  Semi-ugly hack which sets the negative-bit if a < 0:  */
1830                    cpu->cd.arm.flags = ARM_F_C | ((a >> 28) & 8);
1831            }
1832            if (a == 0)
1833                    cpu->cd.arm.next_ic = &ic[2];
1834          else          else
1835                  cpu->cd.arm.cpsr |= ARM_FLAG_Z;                  cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0];
1836          if ((int32_t)a < 0)  }
                 cpu->cd.arm.cpsr |= ARM_FLAG_N;  
1837    
         if (max_pages_left-- > 0 && (int32_t)a > 0)  
                 goto restart_loop;  
1838    
1839          cpu->n_translated_instrs --;  /*
1840     *  cmps followed by bne (inside the same page):
1841     */
1842    X(cmps_bne_samepage)
1843    {
1844            uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a - b;
1845            cpu->n_translated_instrs ++;
1846            cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0;
1847            if (((int32_t)a >= 0 && (int32_t)b < 0 && (int32_t)c < 0) ||
1848                ((int32_t)a < 0 && (int32_t)b >= 0 && (int32_t)c >= 0))
1849                    cpu->cd.arm.flags |= ARM_F_V;
1850            if (c == 0) {
1851                    cpu->cd.arm.flags |= ARM_F_Z;
1852                    cpu->cd.arm.next_ic = &ic[2];
1853            } else {
1854                    if (c & 0x80000000)
1855                            cpu->cd.arm.flags |= ARM_F_N;
1856                    cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0];
1857            }
1858    }
1859    
1860    
1861    /*
1862     *  cmps followed by bcc (inside the same page):
1863     */
1864    X(cmps_bcc_samepage)
1865    {
1866            uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a - b;
1867            cpu->n_translated_instrs ++;
1868            cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0;
1869            if (c & 0x80000000)
1870                    cpu->cd.arm.flags |= ARM_F_N;
1871            else if (c == 0)
1872                    cpu->cd.arm.flags |= ARM_F_Z;
1873            if (((int32_t)a >= 0 && (int32_t)b < 0 && (int32_t)c < 0) ||
1874                ((int32_t)a < 0 && (int32_t)b >= 0 && (int32_t)c >= 0))
1875                    cpu->cd.arm.flags |= ARM_F_V;
1876            if (a >= b)
1877                    cpu->cd.arm.next_ic = &ic[2];
1878            else
1879                    cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0];
1880    }
1881    
1882    
1883    /*
1884     *  cmps (reg) followed by bcc (inside the same page):
1885     */
1886    X(cmps_reg_bcc_samepage)
1887    {
1888            uint32_t a = reg(ic->arg[0]), b = reg(ic->arg[1]), c = a - b;
1889            cpu->n_translated_instrs ++;
1890            cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0;
1891            if (c & 0x80000000)
1892                    cpu->cd.arm.flags |= ARM_F_N;
1893            else if (c == 0)
1894                    cpu->cd.arm.flags |= ARM_F_Z;
1895            if (((int32_t)a >= 0 && (int32_t)b < 0 && (int32_t)c < 0) ||
1896                ((int32_t)a < 0 && (int32_t)b >= 0 && (int32_t)c >= 0))
1897                    cpu->cd.arm.flags |= ARM_F_V;
1898            if (a >= b)
1899                    cpu->cd.arm.next_ic = &ic[2];
1900            else
1901                    cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0];
1902    }
1903    
1904    
1905    /*
1906     *  cmps followed by bhi (inside the same page):
1907     */
1908    X(cmps_bhi_samepage)
1909    {
1910            uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a - b;
1911            cpu->n_translated_instrs ++;
1912            cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0;
1913            if (c & 0x80000000)
1914                    cpu->cd.arm.flags |= ARM_F_N;
1915            else if (c == 0)
1916                    cpu->cd.arm.flags |= ARM_F_Z;
1917            if (((int32_t)a >= 0 && (int32_t)b < 0 && (int32_t)c < 0) ||
1918                ((int32_t)a < 0 && (int32_t)b >= 0 && (int32_t)c >= 0))
1919                    cpu->cd.arm.flags |= ARM_F_V;
1920            if (a > b)
1921                    cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0];
1922            else
1923                    cpu->cd.arm.next_ic = &ic[2];
1924    }
1925    
1926    
1927    /*
1928     *  cmps (reg) followed by bhi (inside the same page):
1929     */
1930    X(cmps_reg_bhi_samepage)
1931    {
1932            uint32_t a = reg(ic->arg[0]), b = reg(ic->arg[1]), c = a - b;
1933            cpu->n_translated_instrs ++;
1934            cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0;
1935            if (c & 0x80000000)
1936                    cpu->cd.arm.flags |= ARM_F_N;
1937            else if (c == 0)
1938                    cpu->cd.arm.flags |= ARM_F_Z;
1939            if (((int32_t)a >= 0 && (int32_t)b < 0 && (int32_t)c < 0) ||
1940                ((int32_t)a < 0 && (int32_t)b >= 0 && (int32_t)c >= 0))
1941                    cpu->cd.arm.flags |= ARM_F_V;
1942            if (a > b)
1943                    cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0];
1944            else
1945                    cpu->cd.arm.next_ic = &ic[2];
1946    }
1947    
1948    
1949    /*
1950     *  cmps followed by bgt (inside the same page):
1951     */
1952    X(cmps_bgt_samepage)
1953    {
1954            uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a - b;
1955            cpu->n_translated_instrs ++;
1956            cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0;
1957            if (c & 0x80000000)
1958                    cpu->cd.arm.flags |= ARM_F_N;
1959            else if (c == 0)
1960                    cpu->cd.arm.flags |= ARM_F_Z;
1961            if (((int32_t)a >= 0 && (int32_t)b < 0 && (int32_t)c < 0) ||
1962                ((int32_t)a < 0 && (int32_t)b >= 0 && (int32_t)c >= 0))
1963                    cpu->cd.arm.flags |= ARM_F_V;
1964            if ((int32_t)a > (int32_t)b)
1965                    cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0];
1966            else
1967                    cpu->cd.arm.next_ic = &ic[2];
1968    }
1969    
1970    
1971          if ((int32_t)a > 0)  /*
1972                  cpu->cd.arm.next_ic = ic;   *  cmps followed by ble (inside the same page):
1973     */
1974    X(cmps_ble_samepage)
1975    {
1976            uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a - b;
1977            cpu->n_translated_instrs ++;
1978            cpu->cd.arm.flags = ((uint32_t)a >= (uint32_t)b)? ARM_F_C : 0;
1979            if (c & 0x80000000)
1980                    cpu->cd.arm.flags |= ARM_F_N;
1981            else if (c == 0)
1982                    cpu->cd.arm.flags |= ARM_F_Z;
1983            if (((int32_t)a >= 0 && (int32_t)b < 0 && (int32_t)c < 0) ||
1984                ((int32_t)a < 0 && (int32_t)b >= 0 && (int32_t)c >= 0))
1985                    cpu->cd.arm.flags |= ARM_F_V;
1986            if ((int32_t)a <= (int32_t)b)
1987                    cpu->cd.arm.next_ic = (struct arm_instr_call *) ic[1].arg[0];
1988            else
1989                    cpu->cd.arm.next_ic = &ic[2];
1990    }
1991    
1992    
1993    /*
1994     *  teqs followed by beq (inside the same page):
1995     */
1996    X(teqs_beq_samepage)
1997    {
1998            uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a ^ b;
1999            cpu->n_translated_instrs ++;
2000            cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N);
2001            if (c == 0) {
2002                    cpu->cd.arm.flags |= ARM_F_Z;
2003                    cpu->cd.arm.next_ic = (struct arm_instr_call *)
2004                        ic[1].arg[0];
2005            } else {
2006                    if (c & 0x80000000)
2007                            cpu->cd.arm.flags |= ARM_F_N;
2008                    cpu->cd.arm.next_ic = &ic[2];
2009            }
2010    }
2011    
2012    
2013    /*
2014     *  tsts followed by beq (inside the same page):
2015     *  (arg[1] must not have its highest bit set))
2016     */
2017    X(tsts_lo_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            if (c == 0)
2025                    cpu->cd.arm.next_ic = (struct arm_instr_call *)
2026                        ic[1].arg[0];
2027            else
2028                    cpu->cd.arm.next_ic = &ic[2];
2029    }
2030    
2031    
2032    /*
2033     *  teqs followed by bne (inside the same page):
2034     */
2035    X(teqs_bne_samepage)
2036    {
2037            uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a ^ b;
2038            cpu->n_translated_instrs ++;
2039            cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N);
2040            if (c == 0) {
2041                    cpu->cd.arm.flags |= ARM_F_Z;
2042            } else {
2043                    if (c & 0x80000000)
2044                            cpu->cd.arm.flags |= ARM_F_N;
2045            }
2046            if (c == 0)
2047                    cpu->cd.arm.next_ic = &ic[2];
2048            else
2049                    cpu->cd.arm.next_ic = (struct arm_instr_call *)
2050                        ic[1].arg[0];
2051    }
2052    
2053    
2054    /*
2055     *  tsts followed by bne (inside the same page):
2056     *  (arg[1] must not have its highest bit set))
2057     */
2058    X(tsts_lo_bne_samepage)
2059    {
2060            uint32_t a = reg(ic->arg[0]), b = ic->arg[1], c = a & b;
2061            cpu->n_translated_instrs ++;
2062            cpu->cd.arm.flags &= ~(ARM_F_Z | ARM_F_N);
2063            if (c == 0)
2064                    cpu->cd.arm.flags |= ARM_F_Z;
2065            if (c == 0)
2066                    cpu->cd.arm.next_ic = &ic[2];
2067          else          else
2068                  cpu->cd.arm.next_ic = &ic[3];                  cpu->cd.arm.next_ic = (struct arm_instr_call *)
2069                        ic[1].arg[0];
2070  }  }
2071    
2072    
# Line 1467  restart_loop: Line 2076  restart_loop:
2076  X(end_of_page)  X(end_of_page)
2077  {  {
2078          /*  Update the PC:  (offset 0, but on the next page)  */          /*  Update the PC:  (offset 0, but on the next page)  */
2079          cpu->cd.arm.r[ARM_PC] &= ~((ARM_IC_ENTRIES_PER_PAGE-1)          cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT);
2080              << ARM_INSTR_ALIGNMENT_SHIFT);          cpu->pc += (ARM_IC_ENTRIES_PER_PAGE << ARM_INSTR_ALIGNMENT_SHIFT);
         cpu->cd.arm.r[ARM_PC] += (ARM_IC_ENTRIES_PER_PAGE  
             << ARM_INSTR_ALIGNMENT_SHIFT);  
         cpu->pc = cpu->cd.arm.r[ARM_PC];  
2081    
2082          /*  Find the new physical page and update the translation pointers:  */          /*  Find the new physical page and update the translation pointers:  */
2083          arm_pc_to_pointers(cpu);          quick_pc_to_pointers(cpu);
2084    
2085          /*  end_of_page doesn't count as an executed instruction:  */          /*  end_of_page doesn't count as an executed instruction:  */
2086          cpu->n_translated_instrs --;          cpu->n_translated_instrs --;
# Line 1485  X(end_of_page) Line 2091  X(end_of_page)
2091    
2092    
2093  /*  /*
2094   *  arm_combine_instructions():   *  Combine: netbsd_memset():
2095   *   *
2096   *  Combine two or more instructions, if possible, into a single function call.   *  Check for the core of a NetBSD/arm memset; large memsets use a sequence
2097     *  of 16 store-multiple instructions, each storing 2 registers at a time.
2098   */   */
2099  void arm_combine_instructions(struct cpu *cpu, struct arm_instr_call *ic,  void COMBINE(netbsd_memset)(struct cpu *cpu,
2100          uint32_t addr)          struct arm_instr_call *ic, int low_addr)
2101  {  {
2102          int n_back;  #ifdef HOST_LITTLE_ENDIAN
2103          n_back = (addr >> ARM_INSTR_ALIGNMENT_SHIFT)          int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2104              & (ARM_IC_ENTRIES_PER_PAGE-1);              & (ARM_IC_ENTRIES_PER_PAGE-1);
2105    
2106          if (n_back >= 2) {          if (n_back >= 17) {
2107                  if (ic[-2].f == instr(store_w0_word_u1_p0_imm) &&                  int i;
2108                      ic[-2].arg[1] == 4 &&                  for (i=-16; i<=-1; i++)
2109                      ic[-1].f == instr(subs) &&                          if (ic[i].f != instr(multi_0x08ac000c__ge))
2110                      ic[-1].arg[0] == ic[-1].arg[2] && ic[-1].arg[1] == 4 &&                                  return;
2111                    if (ic[-17].f == instr(subs) &&
2112                        ic[-17].arg[0]==ic[-17].arg[2] && ic[-17].arg[1] == 128 &&
2113                      ic[ 0].f == instr(b_samepage__gt) &&                      ic[ 0].f == instr(b_samepage__gt) &&
2114                      ic[ 0].arg[0] == (size_t)&ic[-2]) {                      ic[ 0].arg[0] == (size_t)&ic[-17]) {
2115                          ic[-2].f = instr(fill_loop_test2);                          ic[-17].f = instr(netbsd_memset);
                         combined;  
2116                  }                  }
2117          }          }
2118    #endif
2119    }
2120    
2121    
2122    /*
2123     *  Combine: netbsd_memcpy():
2124     *
2125     *  Check for the core of a NetBSD/arm memcpy; large memcpys use a
2126     *  sequence of ldmia instructions.
2127     */
2128    void COMBINE(netbsd_memcpy)(struct cpu *cpu, struct arm_instr_call *ic,
2129            int low_addr)
2130    {
2131    #ifdef HOST_LITTLE_ENDIAN
2132            int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2133                & (ARM_IC_ENTRIES_PER_PAGE-1);
2134    
2135            if (n_back >= 5) {
2136                    if (ic[-5].f==instr(multi_0x08b15018) &&
2137                        ic[-4].f==instr(multi_0x08a05018) &&
2138                        ic[-3].f==instr(multi_0x08b15018) &&
2139                        ic[-2].f==instr(multi_0x08a05018) &&
2140                        ic[-1].f == instr(subs) &&
2141                        ic[-1].arg[0]==ic[-1].arg[2] && ic[-1].arg[1] == 0x20 &&
2142                        ic[ 0].f == instr(b_samepage__ge) &&
2143                        ic[ 0].arg[0] == (size_t)&ic[-5]) {
2144                            ic[-5].f = instr(netbsd_memcpy);
2145                    }
2146            }
2147    #endif
2148    }
2149    
2150    
2151    /*
2152     *  Combine: netbsd_cacheclean():
2153     *
2154     *  Check for the core of a NetBSD/arm cache clean. (There are two variants.)
2155     */
2156    void COMBINE(netbsd_cacheclean)(struct cpu *cpu,
2157            struct arm_instr_call *ic, int low_addr)
2158    {
2159            int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2160                & (ARM_IC_ENTRIES_PER_PAGE-1);
2161    
2162          if (n_back >= 3) {          if (n_back >= 3) {
2163                  if (ic[-3].f == instr(cmps) &&                  if (ic[-3].f==instr(load_w0_word_u1_p0_imm) &&
2164                      ic[-3].arg[0] == ic[-1].arg[0] &&                      ic[-2].f == instr(subs) &&
2165                        ic[-2].arg[0]==ic[-2].arg[2] && ic[-2].arg[1] == 0x20 &&
2166                        ic[-1].f == instr(b_samepage__ne) &&
2167                        ic[-1].arg[0] == (size_t)&ic[-3]) {
2168                            ic[-3].f = instr(netbsd_cacheclean);
2169                    }
2170            }
2171    }
2172    
2173    
2174    /*
2175     *  Combine: netbsd_cacheclean2():
2176     *
2177     *  Check for the core of a NetBSD/arm cache clean. (Second variant.)
2178     */
2179    void COMBINE(netbsd_cacheclean2)(struct cpu *cpu,
2180            struct arm_instr_call *ic, int low_addr)
2181    {
2182            int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2183                & (ARM_IC_ENTRIES_PER_PAGE-1);
2184    
2185            if (n_back >= 4) {
2186                    if (ic[-4].f == instr(mcr_mrc) && ic[-4].arg[0] == 0xee070f3a &&
2187                        ic[-3].f == instr(mcr_mrc) && ic[-3].arg[0] == 0xee070f36 &&
2188                        ic[-2].f == instr(add) &&
2189                        ic[-2].arg[0]==ic[-2].arg[2] && ic[-2].arg[1] == 0x20 &&
2190                        ic[-1].f == instr(subs) &&
2191                        ic[-1].arg[0]==ic[-1].arg[2] && ic[-1].arg[1] == 0x20) {
2192                            ic[-4].f = instr(netbsd_cacheclean2);
2193                    }
2194            }
2195    }
2196    
2197    
2198    /*
2199     *  Combine: netbsd_scanc():
2200     */
2201    void COMBINE(netbsd_scanc)(struct cpu *cpu,
2202            struct arm_instr_call *ic, int low_addr)
2203    {
2204            int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2205                & (ARM_IC_ENTRIES_PER_PAGE-1);
2206    
2207            if (n_back < 2)
2208                    return;
2209    
2210            if (ic[-2].f == instr(load_w0_byte_u1_p1_imm) &&
2211                ic[-2].arg[0] == (size_t)(&cpu->cd.arm.r[1]) &&
2212                ic[-2].arg[1] == 0 &&
2213                ic[-2].arg[2] == (size_t)(&cpu->cd.arm.r[3]) &&
2214                ic[-1].f == instr(load_w0_byte_u1_p1_reg) &&
2215                ic[-1].arg[0] == (size_t)(&cpu->cd.arm.r[2]) &&
2216                ic[-1].arg[1] == (size_t)arm_r_r3_t0_c0 &&
2217                ic[-1].arg[2] == (size_t)(&cpu->cd.arm.r[3])) {
2218                    ic[-2].f = instr(netbsd_scanc);
2219            }
2220    }
2221    
2222    
2223    /*
2224     *  Combine: strlen():
2225     */
2226    void COMBINE(strlen)(struct cpu *cpu,
2227            struct arm_instr_call *ic, int low_addr)
2228    {
2229            int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2230                & (ARM_IC_ENTRIES_PER_PAGE-1);
2231    
2232            if (n_back < 2)
2233                    return;
2234    
2235            if (ic[-2].f == instr(load_w1_byte_u1_p1_imm) &&
2236                ic[-2].arg[1] == 1 &&
2237                ic[-2].arg[2] == (size_t)(&cpu->cd.arm.r[3]) &&
2238                ic[-1].f == instr(cmps) &&
2239                ic[-1].arg[0] == (size_t)(&cpu->cd.arm.r[3]) &&
2240                ic[-1].arg[1] == 0) {
2241                    ic[-2].f = instr(strlen);
2242            }
2243    }
2244    
2245    
2246    /*
2247     *  Combine: xchg():
2248     */
2249    void COMBINE(xchg)(struct cpu *cpu,
2250            struct arm_instr_call *ic, int low_addr)
2251    {
2252            int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2253                & (ARM_IC_ENTRIES_PER_PAGE-1);
2254            size_t a, b;
2255    
2256            if (n_back < 2)
2257                    return;
2258    
2259            a = ic[-2].arg[0]; b = ic[-1].arg[0];
2260    
2261            if (ic[-2].f == instr(eor_regshort) &&
2262                ic[-1].f == instr(eor_regshort) &&
2263                ic[-2].arg[0] == a && ic[-2].arg[1] == b && ic[-2].arg[2] == b &&
2264                ic[-1].arg[0] == b && ic[-1].arg[1] == a && ic[-1].arg[2] == a &&
2265                ic[ 0].arg[0] == a && ic[ 0].arg[1] == b && ic[ 0].arg[2] == b) {
2266                    ic[-2].f = instr(xchg);
2267            }
2268    }
2269    
2270    
2271    /*
2272     *  Combine: netbsd_copyin():
2273     */
2274    void COMBINE(netbsd_copyin)(struct cpu *cpu,
2275            struct arm_instr_call *ic, int low_addr)
2276    {
2277    #ifdef HOST_LITTLE_ENDIAN
2278            int i, n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2279                & (ARM_IC_ENTRIES_PER_PAGE-1);
2280    
2281            if (n_back < 5)
2282                    return;
2283    
2284            for (i=-5; i<0; i++) {
2285                    if (ic[i].f != instr(load_w1_word_u1_p0_imm) ||
2286                        ic[i].arg[0] != (size_t)(&cpu->cd.arm.r[0]) ||
2287                        ic[i].arg[1] != 4)
2288                            return;
2289            }
2290    
2291            if (ic[-5].arg[2] == (size_t)(&cpu->cd.arm.r[10]) &&
2292                ic[-4].arg[2] == (size_t)(&cpu->cd.arm.r[11]) &&
2293                ic[-3].arg[2] == (size_t)(&cpu->cd.arm.r[6]) &&
2294                ic[-2].arg[2] == (size_t)(&cpu->cd.arm.r[7]) &&
2295                ic[-1].arg[2] == (size_t)(&cpu->cd.arm.r[8])) {
2296                    ic[-5].f = instr(netbsd_copyin);
2297            }
2298    #endif
2299    }
2300    
2301    
2302    /*
2303     *  Combine: netbsd_copyout():
2304     */
2305    void COMBINE(netbsd_copyout)(struct cpu *cpu,
2306            struct arm_instr_call *ic, int low_addr)
2307    {
2308    #ifdef HOST_LITTLE_ENDIAN
2309            int i, n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2310                & (ARM_IC_ENTRIES_PER_PAGE-1);
2311    
2312            if (n_back < 5)
2313                    return;
2314    
2315            for (i=-5; i<0; i++) {
2316                    if (ic[i].f != instr(store_w1_word_u1_p0_imm) ||
2317                        ic[i].arg[0] != (size_t)(&cpu->cd.arm.r[1]) ||
2318                        ic[i].arg[1] != 4)
2319                            return;
2320            }
2321    
2322            if (ic[-5].arg[2] == (size_t)(&cpu->cd.arm.r[8]) &&
2323                ic[-4].arg[2] == (size_t)(&cpu->cd.arm.r[9]) &&
2324                ic[-3].arg[2] == (size_t)(&cpu->cd.arm.r[10]) &&
2325                ic[-2].arg[2] == (size_t)(&cpu->cd.arm.r[11]) &&
2326                ic[-1].arg[2] == (size_t)(&cpu->cd.arm.r[6])) {
2327                    ic[-5].f = instr(netbsd_copyout);
2328            }
2329    #endif
2330    }
2331    
2332    
2333    /*
2334     *  Combine: cmps + beq, etc:
2335     */
2336    void COMBINE(beq_etc)(struct cpu *cpu,
2337            struct arm_instr_call *ic, int low_addr)
2338    {
2339            int n_back = (low_addr >> ARM_INSTR_ALIGNMENT_SHIFT)
2340                & (ARM_IC_ENTRIES_PER_PAGE-1);
2341            if (n_back < 1)
2342                    return;
2343            if (ic[0].f == instr(b__eq)) {
2344                    if (ic[-1].f == instr(cmps)) {
2345                            if (ic[-1].arg[1] == 0)
2346                                    ic[-1].f = instr(cmps_0_beq);
2347                            else if (ic[-1].arg[1] & 0x80000000)
2348                                    ic[-1].f = instr(cmps_neg_beq);
2349                            else
2350                                    ic[-1].f = instr(cmps_pos_beq);
2351                    }
2352                    return;
2353            }
2354            if (ic[0].f == instr(b_samepage__eq)) {
2355                    if (ic[-1].f == instr(cmps)) {
2356                            if (ic[-1].arg[1] == 0)
2357                                    ic[-1].f = instr(cmps0_beq_samepage);
2358                            else
2359                                    ic[-1].f = instr(cmps_beq_samepage);
2360                    }
2361                    if (ic[-1].f == instr(tsts) &&
2362                        !(ic[-1].arg[1] & 0x80000000)) {
2363                            ic[-1].f = instr(tsts_lo_beq_samepage);
2364                    }
2365                    if (n_back >= 4 &&
2366                        ic[-4].f == instr(load_w0_word_u1_p1_imm) &&
2367                        ic[-4].arg[0] != ic[-4].arg[2] &&
2368                        ic[-4].arg[1] == 0 &&
2369                        ic[-4].arg[2] == ic[-3].arg[0] &&
2370                        /*  Note: The teqs+bne is already combined!  */
2371                        ic[-3].f == instr(teqs_bne_samepage) &&
2372                      ic[-3].arg[1] == 0 &&                      ic[-3].arg[1] == 0 &&
2373                      ic[-2].f == instr(store_w0_byte_u1_p0_imm) &&                      ic[-2].f == instr(b_samepage__ne) &&
2374                      ic[-2].arg[1] == 1 &&                      ic[-1].f == instr(teqs) &&
2375                      ic[-1].f == instr(sub) &&                      ic[-1].arg[0] != ic[-4].arg[0] &&
2376                      ic[-1].arg[0] == ic[-1].arg[2] && ic[-1].arg[1] == 1 &&                      ic[-1].arg[1] == 0) {
2377                      ic[ 0].f == instr(b_samepage__gt) &&                          ic[-4].f = instr(netbsd_idle);
2378                      ic[ 0].arg[0] == (size_t)&ic[-3]) {                  }
2379                          ic[-3].f = instr(fill_loop_test);                  if (ic[-1].f == instr(teqs)) {
2380                          combined;                          ic[-1].f = instr(teqs_beq_samepage);
2381                  }                  }
2382                    return;
2383            }
2384            if (ic[0].f == instr(b_samepage__ne)) {
2385                    if (ic[-1].f == instr(cmps)) {
2386                            if (ic[-1].arg[1] == 0)
2387                                    ic[-1].f = instr(cmps0_bne_samepage);
2388                            else
2389                                    ic[-1].f = instr(cmps_bne_samepage);
2390                    }
2391                    if (ic[-1].f == instr(tsts) &&
2392                        !(ic[-1].arg[1] & 0x80000000)) {
2393                            ic[-1].f = instr(tsts_lo_bne_samepage);
2394                    }
2395                    if (ic[-1].f == instr(teqs)) {
2396                            ic[-1].f = instr(teqs_bne_samepage);
2397                    }
2398                    return;
2399            }
2400            if (ic[0].f == instr(b_samepage__cc)) {
2401                    if (ic[-1].f == instr(cmps)) {
2402                            ic[-1].f = instr(cmps_bcc_samepage);
2403                    }
2404                    if (ic[-1].f == instr(cmps_regshort)) {
2405                            ic[-1].f = instr(cmps_reg_bcc_samepage);
2406                    }
2407                    return;
2408            }
2409            if (ic[0].f == instr(b_samepage__hi)) {
2410                    if (ic[-1].f == instr(cmps)) {
2411                            ic[-1].f = instr(cmps_bhi_samepage);
2412                    }
2413                    if (ic[-1].f == instr(cmps_regshort)) {
2414                            ic[-1].f = instr(cmps_reg_bhi_samepage);
2415                    }
2416                    return;
2417            }
2418            if (ic[0].f == instr(b_samepage__gt)) {
2419                    if (ic[-1].f == instr(cmps)) {
2420                            ic[-1].f = instr(cmps_bgt_samepage);
2421                    }
2422                    return;
2423          }          }
2424            if (ic[0].f == instr(b_samepage__le)) {
2425                    if (ic[-1].f == instr(cmps)) {
2426                            ic[-1].f = instr(cmps_ble_samepage);
2427                    }
2428                    return;
2429            }
2430    }
2431    
2432    
2433          /*  TODO: Combine forward as well  */  /*****************************************************************************/
2434    
2435    
2436    static void arm_switch_clear(struct arm_instr_call *ic, int rd,
2437            int condition_code)
2438    {
2439            switch (rd) {
2440            case  0: ic->f = cond_instr(clear_r0); break;
2441            case  1: ic->f = cond_instr(clear_r1); break;
2442            case  2: ic->f = cond_instr(clear_r2); break;
2443            case  3: ic->f = cond_instr(clear_r3); break;
2444            case  4: ic->f = cond_instr(clear_r4); break;
2445            case  5: ic->f = cond_instr(clear_r5); break;
2446            case  6: ic->f = cond_instr(clear_r6); break;
2447            case  7: ic->f = cond_instr(clear_r7); break;
2448            case  8: ic->f = cond_instr(clear_r8); break;
2449            case  9: ic->f = cond_instr(clear_r9); break;
2450            case 10: ic->f = cond_instr(clear_r10); break;
2451            case 11: ic->f = cond_instr(clear_r11); break;
2452            case 12: ic->f = cond_instr(clear_r12); break;
2453            case 13: ic->f = cond_instr(clear_r13); break;
2454            case 14: ic->f = cond_instr(clear_r14); break;
2455            }
2456    }
2457    
2458    
2459    static void arm_switch_mov1(struct arm_instr_call *ic, int rd,
2460            int condition_code)
2461    {
2462            switch (rd) {
2463            case  0: ic->f = cond_instr(mov1_r0); break;
2464            case  1: ic->f = cond_instr(mov1_r1); break;
2465            case  2: ic->f = cond_instr(mov1_r2); break;
2466            case  3: ic->f = cond_instr(mov1_r3); break;
2467            case  4: ic->f = cond_instr(mov1_r4); break;
2468            case  5: ic->f = cond_instr(mov1_r5); break;
2469            case  6: ic->f = cond_instr(mov1_r6); break;
2470            case  7: ic->f = cond_instr(mov1_r7); break;
2471            case  8: ic->f = cond_instr(mov1_r8); break;
2472            case  9: ic->f = cond_instr(mov1_r9); break;
2473            case 10: ic->f = cond_instr(mov1_r10); break;
2474            case 11: ic->f = cond_instr(mov1_r11); break;
2475            case 12: ic->f = cond_instr(mov1_r12); break;
2476            case 13: ic->f = cond_instr(mov1_r13); break;
2477            case 14: ic->f = cond_instr(mov1_r14); break;
2478            }
2479    }
2480    
2481    
2482    static void arm_switch_add1(struct arm_instr_call *ic, int rd,
2483            int condition_code)
2484    {
2485            switch (rd) {
2486            case  0: ic->f = cond_instr(add1_r0); break;
2487            case  1: ic->f = cond_instr(add1_r1); break;
2488            case  2: ic->f = cond_instr(add1_r2); break;
2489            case  3: ic->f = cond_instr(add1_r3); break;
2490            case  4: ic->f = cond_instr(add1_r4); break;
2491            case  5: ic->f = cond_instr(add1_r5); break;
2492            case  6: ic->f = cond_instr(add1_r6); break;
2493            case  7: ic->f = cond_instr(add1_r7); break;
2494            case  8: ic->f = cond_instr(add1_r8); break;
2495            case  9: ic->f = cond_instr(add1_r9); break;
2496            case 10: ic->f = cond_instr(add1_r10); break;
2497            case 11: ic->f = cond_instr(add1_r11); break;
2498            case 12: ic->f = cond_instr(add1_r12); break;
2499            case 13: ic->f = cond_instr(add1_r13); break;
2500            case 14: ic->f = cond_instr(add1_r14); break;
2501            }
2502  }  }
2503    
2504    
# Line 1544  X(to_be_translated) Line 2519  X(to_be_translated)
2519          unsigned char *page;          unsigned char *page;
2520          unsigned char ib[4];          unsigned char ib[4];
2521          int condition_code, main_opcode, secondary_opcode, s_bit, rn, rd, r8;          int condition_code, main_opcode, secondary_opcode, s_bit, rn, rd, r8;
2522          int p_bit, u_bit, b_bit, w_bit, l_bit, regform, rm, c, t;          int p_bit, u_bit, w_bit, l_bit, regform, rm, c, t, any_pc_reg;
         int any_pc_reg;  
2523          void (*samepage_function)(struct cpu *, struct arm_instr_call *);          void (*samepage_function)(struct cpu *, struct arm_instr_call *);
2524    
2525          /*  Figure out the address of the instruction:  */          /*  Figure out the address of the instruction:  */
2526          low_pc = ((size_t)ic - (size_t)cpu->cd.arm.cur_ic_page)          low_pc = ((size_t)ic - (size_t)cpu->cd.arm.cur_ic_page)
2527              / sizeof(struct arm_instr_call);              / sizeof(struct arm_instr_call);
2528          addr = cpu->cd.arm.r[ARM_PC] & ~((ARM_IC_ENTRIES_PER_PAGE-1) <<          addr = cpu->pc & ~((ARM_IC_ENTRIES_PER_PAGE-1) <<
2529              ARM_INSTR_ALIGNMENT_SHIFT);              ARM_INSTR_ALIGNMENT_SHIFT);
2530          addr += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);          addr += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT);
2531          cpu->pc = cpu->cd.arm.r[ARM_PC] = addr;          cpu->pc = addr;
2532          addr &= ~((1 << ARM_INSTR_ALIGNMENT_SHIFT) - 1);          addr &= ~((1 << ARM_INSTR_ALIGNMENT_SHIFT) - 1);
2533    
2534          /*  Read the instruction word from memory:  */          /*  Read the instruction word from memory:  */
2535          page = cpu->cd.arm.host_load[addr >> 12];          page = cpu->cd.arm.host_load[addr >> 12];
2536    
2537          if (page != NULL) {          if (page != NULL) {
2538                  /*  fatal("TRANSLATION HIT!\n");  */                  /*  fatal("TRANSLATION HIT! 0x%08x\n", addr);  */
2539                  memcpy(ib, page + (addr & 0xfff), sizeof(ib));                  memcpy(ib, page + (addr & 0xfff), sizeof(ib));
2540          } else {          } else {
2541                  /*  fatal("TRANSLATION MISS!\n");  */                  /*  fatal("TRANSLATION MISS! 0x%08x\n", addr);  */
2542                  if (!cpu->memory_rw(cpu, cpu->mem, addr, &ib[0],                  if (!cpu->memory_rw(cpu, cpu->mem, addr, &ib[0],
2543                      sizeof(ib), MEM_READ, CACHE_INSTRUCTION)) {                      sizeof(ib), MEM_READ, CACHE_INSTRUCTION)) {
2544                          fatal("to_be_translated(): "                          fatal("to_be_translated(): "
2545                              "read failed: TODO\n");                              "read failed: TODO\n");
2546                          goto bad;                          return;
2547                  }                  }
2548          }          }
2549    
# Line 1588  X(to_be_translated) Line 2563  X(to_be_translated)
2563          condition_code = iword >> 28;          condition_code = iword >> 28;
2564          main_opcode = (iword >> 24) & 15;          main_opcode = (iword >> 24) & 15;
2565          secondary_opcode = (iword >> 21) & 15;          secondary_opcode = (iword >> 21) & 15;
2566          u_bit = (iword >> 23) & 1;          u_bit = iword & 0x00800000;
2567          b_bit = (iword >> 22) & 1;          w_bit = iword & 0x00200000;
2568          w_bit = (iword >> 21) & 1;          s_bit = l_bit = iword & 0x00100000;
         s_bit = l_bit = (iword >> 20) & 1;  
2569          rn    = (iword >> 16) & 15;          rn    = (iword >> 16) & 15;
2570          rd    = (iword >> 12) & 15;          rd    = (iword >> 12) & 15;
2571          r8    = (iword >> 8) & 15;          r8    = (iword >> 8) & 15;
# Line 1606  X(to_be_translated) Line 2580  X(to_be_translated)
2580                          goto okay;                          goto okay;
2581                  }                  }
2582    
2583                  fatal("TODO: ARM condition code 0x%x\n",                  if (!cpu->translation_readahead)
2584                      condition_code);                          fatal("TODO: ARM condition code 0x%x\n",
2585                                condition_code);
2586                  goto bad;                  goto bad;
2587          }          }
2588    
# Line 1649  X(to_be_translated) Line 2624  X(to_be_translated)
2624                  if ((iword & 0x0f8000f0) == 0x00800090) {                  if ((iword & 0x0f8000f0) == 0x00800090) {
2625                          /*  Long multiplication:  */                          /*  Long multiplication:  */
2626                          if (s_bit) {                          if (s_bit) {
2627                                  fatal("TODO: sbit mull\n");                                  if (!cpu->translation_readahead)
2628                                            fatal("TODO: sbit mull\n");
2629                                  goto bad;                                  goto bad;
2630                          }                          }
2631                          ic->f = cond_instr(mull);                          ic->f = cond_instr(mull);
2632                          ic->arg[0] = iword;                          ic->arg[0] = iword;
2633                          break;                          break;
2634                  }                  }
2635                    if ((iword & 0x0f900ff0) == 0x01000050) {
2636                            if (!cpu->translation_readahead)
2637                                    fatal("TODO: q{,d}{add,sub}\n");
2638                            goto bad;
2639                    }
2640                  if ((iword & 0x0ff000d0) == 0x01200010) {                  if ((iword & 0x0ff000d0) == 0x01200010) {
2641                          /*  bx or blx  */                          /*  bx or blx  */
2642                          if (iword & 0x20)                          if (iword & 0x20)
# Line 1680  X(to_be_translated) Line 2661  X(to_be_translated)
2661                          ic->arg[2] = (size_t)(&cpu->cd.arm.r[rn]);                          ic->arg[2] = (size_t)(&cpu->cd.arm.r[rn]);
2662                          break;                          break;
2663                  }                  }
2664                    if ((iword & 0x0fff0ff0) == 0x016f0f10) {
2665                            ic->f = cond_instr(clz);
2666                            ic->arg[0] = (size_t)(&cpu->cd.arm.r[rm]);
2667                            ic->arg[1] = (size_t)(&cpu->cd.arm.r[rd]);
2668                            break;
2669                    }
2670                    if ((iword & 0x0ff00090) == 0x01000080) {
2671                            /*  TODO: smlaXX  */
2672                            goto bad;
2673                    }
2674                    if ((iword & 0x0ff00090) == 0x01400080) {
2675                            /*  TODO: smlalY  */
2676                            goto bad;
2677                    }
2678                    if ((iword & 0x0ff000b0) == 0x01200080) {
2679                            /*  TODO: smlawY  */
2680                            goto bad;
2681                    }
2682                    if ((iword & 0x0ff0f090) == 0x01600080) {
2683                            /*  smulXY (16-bit * 16-bit => 32-bit)  */
2684                            switch (iword & 0x60) {
2685                            case 0x00: ic->f = cond_instr(smulbb); break;
2686                            case 0x20: ic->f = cond_instr(smultb); break;
2687                            case 0x40: ic->f = cond_instr(smulbt); break;
2688                            default:   ic->f = cond_instr(smultt); break;
2689                            }
2690                            ic->arg[0] = (size_t)(&cpu->cd.arm.r[rm]);
2691                            ic->arg[1] = (size_t)(&cpu->cd.arm.r[r8]);
2692                            ic->arg[2] = (size_t)(&cpu->cd.arm.r[rn]); /*  Rd  */
2693                            break;
2694                    }
2695                    if ((iword & 0x0ff0f0b0) == 0x012000a0) {
2696                            /*  TODO: smulwY  */
2697                            goto bad;
2698                    }
2699                  if ((iword & 0x0fb0fff0) == 0x0120f000 ||                  if ((iword & 0x0fb0fff0) == 0x0120f000 ||
2700                      (iword & 0x0fb0f000) == 0x0320f000) {                      (iword & 0x0fb0f000) == 0x0320f000) {
2701                          /*  msr: move to [S|C]PSR from a register or                          /*  msr: move to [S|C]PSR from a register or
2702                              immediate value  */                              immediate value  */
                         if (rm == ARM_PC) {  
                                 fatal("msr PC?\n");  
                                 goto bad;  
                         }  
2703                          if (iword & 0x02000000) {                          if (iword & 0x02000000) {
2704                                  if (iword & 0x00400000)                                  if (iword & 0x00400000)
2705                                          ic->f = cond_instr(msr_imm_spsr);                                          ic->f = cond_instr(msr_imm_spsr);
2706                                  else                                  else
2707                                          ic->f = cond_instr(msr_imm);                                          ic->f = cond_instr(msr_imm);
2708                          } else {                          } else {
2709                                    if (rm == ARM_PC) {
2710                                            if (!cpu->translation_readahead)
2711                                                    fatal("msr PC?\n");
2712                                            goto bad;
2713                                    }
2714                                  if (iword & 0x00400000)                                  if (iword & 0x00400000)
2715                                          ic->f = cond_instr(msr_spsr);                                          ic->f = cond_instr(msr_spsr);
2716                                  else                                  else
# Line 1708  X(to_be_translated) Line 2725  X(to_be_translated)
2725                          case 1: ic->arg[1] = 0x000000ff; break;                          case 1: ic->arg[1] = 0x000000ff; break;
2726                          case 8: ic->arg[1] = 0xff000000; break;                          case 8: ic->arg[1] = 0xff000000; break;
2727                          case 9: ic->arg[1] = 0xff0000ff; break;                          case 9: ic->arg[1] = 0xff0000ff; break;
2728                          default:fatal("unimpl a: msr regform\n");                          default:if (!cpu->translation_readahead)
2729                                            fatal("unimpl a: msr regform\n");
2730                                  goto bad;                                  goto bad;
2731                          }                          }
2732                          break;                          break;
# Line 1716  X(to_be_translated) Line 2734  X(to_be_translated)
2734                  if ((iword & 0x0fbf0fff) == 0x010f0000) {                  if ((iword & 0x0fbf0fff) == 0x010f0000) {
2735                          /*  mrs: move from CPSR/SPSR to a register:  */                          /*  mrs: move from CPSR/SPSR to a register:  */
2736                          if (rd == ARM_PC) {                          if (rd == ARM_PC) {
2737                                  fatal("mrs PC?\n");                                  if (!cpu->translation_readahead)
2738                                            fatal("mrs PC?\n");
2739                                  goto bad;                                  goto bad;
2740                          }                          }
2741                          if (iword & 0x00400000)                          if (iword & 0x00400000)
# Line 1755  X(to_be_translated) Line 2774  X(to_be_translated)
2774                                      + (u_bit? 256 : 0) + (p_bit? 512 : 0)                                      + (u_bit? 256 : 0) + (p_bit? 512 : 0)
2775                                      + (regform? 1024 : 0)];                                      + (regform? 1024 : 0)];
2776                          if (regform)                          if (regform)
2777                                  ic->arg[1] = iword & 0xf;                                  ic->arg[1] = (size_t)(void *)arm_r[iword & 0xf];
2778                          else                          else
2779                                  ic->arg[1] = imm;                                  ic->arg[1] = imm;
2780                          break;                          break;
2781                  }                  }
2782    
2783                  if (iword & 0x80 && !(main_opcode & 2) && iword & 0x10) {                  if (iword & 0x80 && !(main_opcode & 2) && iword & 0x10) {
2784                          fatal("reg form blah blah\n");                          if (!cpu->translation_readahead)
2785                                    fatal("reg form blah blah\n");
2786                          goto bad;                          goto bad;
2787                  }                  }
2788    
2789                  /*  "mov pc,lr" with trace enabled:  */                  /*  "mov pc,lr":  */
2790                  if ((iword & 0x0fffffff) == 0x01a0f00e &&                  if ((iword & 0x0fffffff) == 0x01a0f00e) {
2791                      cpu->machine->show_trace_tree) {                          if (cpu->machine->show_trace_tree)
2792                          ic->f = cond_instr(ret_trace);                                  ic->f = cond_instr(ret_trace);
2793                            else
2794                                    ic->f = cond_instr(ret);
2795                          break;                          break;
2796                  }                  }
2797    
2798                  /*  "mov reg,reg":  */                  /*  "mov reg,reg" or "mov reg,pc":  */
2799                  if ((iword & 0x0fff0ff0) == 0x01a00000 &&                  if ((iword & 0x0fff0ff0) == 0x01a00000 && rd != ARM_PC) {
2800                      (iword&15) != ARM_PC && rd != ARM_PC) {                          if (rm != ARM_PC) {
2801                          ic->f = cond_instr(mov_reg_reg);                                  ic->f = cond_instr(mov_reg_reg);
2802                          ic->arg[0] = (size_t)(&cpu->cd.arm.r[iword & 15]);                                  ic->arg[0] = (size_t)(&cpu->cd.arm.r[rm]);
2803                            } else {
2804                                    ic->f = cond_instr(mov_reg_pc);
2805                                    ic->arg[0] = (addr & 0xfff) + 8;
2806                            }
2807                          ic->arg[1] = (size_t)(&cpu->cd.arm.r[rd]);                          ic->arg[1] = (size_t)(&cpu->cd.arm.r[rd]);
2808                          break;                          break;
2809                  }                  }
2810    
2811                    /*  "mov reg,#0":  */
2812                    if ((iword & 0x0fff0fff) == 0x03a00000 && rd != ARM_PC) {
2813                            arm_switch_clear(ic, rd, condition_code);
2814                            break;
2815                    }
2816    
2817                    /*  "mov reg,#1":  */
2818                    if ((iword & 0x0fff0fff) == 0x03a00001 && rd != ARM_PC) {
2819                            arm_switch_mov1(ic, rd, condition_code);
2820                            break;
2821                    }
2822    
2823                    /*  "add reg,reg,#1":  */
2824                    if ((iword & 0x0ff00fff) == 0x02800001 && rd != ARM_PC
2825                        && rn == rd) {
2826                            arm_switch_add1(ic, rd, condition_code);
2827                            break;
2828                    }
2829    
2830                  /*                  /*
2831                   *  Generic Data Processing Instructions:                   *  Generic Data Processing Instructions:
2832                   */                   */
# Line 1790  X(to_be_translated) Line 2835  X(to_be_translated)
2835                  else                  else
2836                          regform = 0;                          regform = 0;
2837    
2838                  if (regform)                  if (regform) {
2839                          ic->arg[1] = iword;                          /*  0x1000 signifies Carry bit update on rotation,
2840                  else {                              which is not necessary for add,adc,sub,sbc,
2841                                rsb,rsc,cmp, or cmn, because they update the
2842                                Carry bit manually anyway.  */
2843                            int q = 0x1000;
2844                            if (s_bit == 0)
2845                                    q = 0;
2846                            if ((secondary_opcode >= 2 && secondary_opcode <= 7)
2847                                || secondary_opcode==0xa || secondary_opcode==0xb)
2848                                    q = 0;
2849                            ic->arg[1] = (size_t)(void *)arm_r[(iword & 0xfff) + q];
2850                    } else {
2851                          imm = iword & 0xff;                          imm = iword & 0xff;
2852                          while (r8-- > 0)                          while (r8-- > 0)
2853                                  imm = (imm >> 2) | ((imm & 3) << 30);                                  imm = (imm >> 2) | ((imm & 3) << 30);
2854                          ic->arg[1] = imm;                          ic->arg[1] = imm;
2855                  }                  }
2856    
2857                    /*  mvn #imm ==> mov #~imm  */
2858                    if (secondary_opcode == 0xf && !regform) {
2859                            secondary_opcode = 0xd;
2860                            ic->arg[1] = ~ic->arg[1];
2861                    }
2862    
2863                  ic->arg[0] = (size_t)(&cpu->cd.arm.r[rn]);                  ic->arg[0] = (size_t)(&cpu->cd.arm.r[rn]);
2864                  ic->arg[2] = (size_t)(&cpu->cd.arm.r[rd]);                  ic->arg[2] = (size_t)(&cpu->cd.arm.r[rd]);
2865                  any_pc_reg = 0;                  any_pc_reg = 0;
2866                  if (rn == ARM_PC || rd == ARM_PC)                  if (rn == ARM_PC || rd == ARM_PC)
2867                          any_pc_reg = 1;                          any_pc_reg = 1;
2868    
2869                  ic->f = arm_dpi_instr[condition_code +                  if (!any_pc_reg && regform && (iword & 0xfff) < ARM_PC) {
2870                      16 * secondary_opcode + (s_bit? 256 : 0) +                          ic->arg[1] = (size_t)(&cpu->cd.arm.r[rm]);
2871                      (any_pc_reg? 512 : 0) + (regform? 1024 : 0)];                          ic->f = arm_dpi_instr_regshort[condition_code +
2872                                16 * secondary_opcode + (s_bit? 256 : 0)];
2873                    } else
2874                            ic->f = arm_dpi_instr[condition_code +
2875                                16 * secondary_opcode + (s_bit? 256 : 0) +
2876                                (any_pc_reg? 512 : 0) + (regform? 1024 : 0)];
2877    
2878                    if (ic->f == instr(eor_regshort))
2879                            cpu->cd.arm.combination_check = COMBINE(xchg);
2880                    if (iword == 0xe113000c)
2881                            cpu->cd.arm.combination_check = COMBINE(netbsd_scanc);
2882                  break;                  break;
2883    
2884          case 0x4:       /*  Load and store...  */          case 0x4:       /*  Load and store...  */
# Line 1831  X(to_be_translated) Line 2902  X(to_be_translated)
2902                  if (main_opcode < 6)                  if (main_opcode < 6)
2903                          ic->arg[1] = imm;                          ic->arg[1] = imm;
2904                  else                  else
2905                          ic->arg[1] = iword;                          ic->arg[1] = (size_t)(void *)arm_r[iword & 0xfff];
2906                  if ((iword & 0x0e000010) == 0x06000010) {                  if ((iword & 0x0e000010) == 0x06000010) {
2907                          fatal("Not a Load/store TODO\n");                          if (!cpu->translation_readahead)
2908                                    fatal("Not a Load/store TODO\n");
2909                          goto bad;                          goto bad;
2910                  }                  }
2911                    /*  Special case: pc-relative load within the same page:  */
2912                    if (rn == ARM_PC && rd != ARM_PC && main_opcode < 6) {
2913                            int ofs = (addr & 0xfff) + 8, max = 0xffc;
2914                            int b_bit = iword & 0x00400000;
2915                            if (b_bit)
2916                                    max = 0xfff;
2917                            if (u_bit)
2918                                    ofs += (iword & 0xfff);
2919                            else
2920                                    ofs -= (iword & 0xfff);
2921                            /*  NOTE/TODO: This assumes 4KB pages,
2922                                it will not work with 1KB pages.  */
2923                            if (ofs >= 0 && ofs <= max) {
2924                                    unsigned char *p;
2925                                    unsigned char c[4];
2926                                    int len = b_bit? 1 : 4;
2927                                    uint32_t x, a = (addr & 0xfffff000) | ofs;
2928                                    /*  ic->f = cond_instr(mov);  */
2929                                    ic->f = arm_dpi_instr[condition_code + 16*0xd];
2930                                    ic->arg[2] = (size_t)(&cpu->cd.arm.r[rd]);
2931                                    p = page;
2932                                    if (p != NULL) {
2933                                            memcpy(c, p + (a & 0xfff), len);
2934                                    } else {
2935                                            fatal("Hm? Internal error in "
2936                                                "cpu_arm_instr.c!\n");
2937                                            goto bad;
2938                                    }
2939                                    if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
2940                                            x = c[0] + (c[1]<<8) +
2941                                                (c[2]<<16) + (c[3]<<24);
2942                                    else
2943                                            x = c[3] + (c[2]<<8) +
2944                                                (c[1]<<16) + (c[0]<<24);
2945                                    if (b_bit)
2946                                            x = c[0];
2947                                    ic->arg[1] = x;
2948                            }
2949                    }
2950                    if (iword == 0xe4b09004)
2951                            cpu->cd.arm.combination_check = COMBINE(netbsd_copyin);
2952                    if (iword == 0xe4a17004)
2953                            cpu->cd.arm.combination_check = COMBINE(netbsd_copyout);
2954                  break;                  break;
2955    
2956          case 0x8:       /*  Multiple load/store...  (Block data transfer)  */          case 0x8:       /*  Multiple load/store...  (Block data transfer)  */
2957          case 0x9:       /*  xxxx100P USWLnnnn llllllll llllllll  */          case 0x9:       /*  xxxx100P USWLnnnn llllllll llllllll  */
2958                    ic->arg[0] = (size_t)(&cpu->cd.arm.r[rn]);
2959                    ic->arg[1] = (size_t)iword;
2960                    /*  Generic case:  */
2961                  if (l_bit)                  if (l_bit)
2962                          ic->f = cond_instr(bdt_load);                          ic->f = cond_instr(bdt_load);
2963                  else                  else
2964                          ic->f = cond_instr(bdt_store);                          ic->f = cond_instr(bdt_store);
2965                  ic->arg[0] = (size_t)(&cpu->cd.arm.r[rn]);  #if defined(HOST_LITTLE_ENDIAN) && !defined(GATHER_BDT_STATISTICS)
2966                  ic->arg[1] = (size_t)iword;                  /*
2967                     *  Check for availability of optimized implementation:
2968                     *  xxxx100P USWLnnnn llllllll llllllll
2969                     *           ^  ^ ^ ^        ^  ^ ^ ^   (0x00950154)
2970                     *  These bits are used to select which list to scan, and then
2971                     *  the list is scanned linearly.
2972                     *
2973                     *  The optimized functions do not support show_trace_tree,
2974                     *  but it's ok to use the unoptimized version in that case.
2975                     */
2976                    if (!cpu->machine->show_trace_tree) {
2977                            int i = 0, j = iword;
2978                            j = ((j & 0x00800000) >> 16) | ((j & 0x00100000) >> 14)
2979                              | ((j & 0x00040000) >> 13) | ((j & 0x00010000) >> 12)
2980                              | ((j & 0x00000100) >>  5) | ((j & 0x00000040) >>  4)
2981                              | ((j & 0x00000010) >>  3) | ((j & 0x00000004) >>  2);
2982                            while (multi_opcode[j][i] != 0) {
2983                                    if ((iword & 0x0fffffff) ==
2984                                        multi_opcode[j][i]) {
2985                                            ic->f = multi_opcode_f[j]
2986                                                [i*16 + condition_code];
2987                                            break;
2988                                    }
2989                                    i ++;
2990                            }
2991                    }
2992    #endif
2993                  if (rn == ARM_PC) {                  if (rn == ARM_PC) {
2994                          fatal("TODO: bdt with PC as base\n");                          if (!cpu->translation_readahead)
2995                                    fatal("TODO: bdt with PC as base\n");
2996                          goto bad;                          goto bad;
2997                  }                  }
2998                  break;                  break;
# Line 1857  X(to_be_translated) Line 3002  X(to_be_translated)
3002                  if (main_opcode == 0x0a) {                  if (main_opcode == 0x0a) {
3003                          ic->f = cond_instr(b);                          ic->f = cond_instr(b);
3004                          samepage_function = cond_instr(b_samepage);                          samepage_function = cond_instr(b_samepage);
3005    
3006                            /*  Abort read-ahead on unconditional branches:  */
3007                            if (condition_code == 0xe &&
3008                                cpu->translation_readahead > 1)
3009                                    cpu->translation_readahead = 1;
3010    
3011                            if (iword == 0xcaffffed)
3012                                    cpu->cd.arm.combination_check =
3013                                        COMBINE(netbsd_memset);
3014                            if (iword == 0xaafffff9)
3015                                    cpu->cd.arm.combination_check =
3016                                        COMBINE(netbsd_memcpy);
3017                  } else {                  } else {
3018                          if (cpu->machine->show_trace_tree) {                          if (cpu->machine->show_trace_tree) {
3019                                  ic->f = cond_instr(bl_trace);                                  ic->f = cond_instr(bl_trace);
# Line 1868  X(to_be_translated) Line 3025  X(to_be_translated)
3025                          }                          }
3026                  }                  }
3027    
3028                    /*  arg 1 = offset of current instruction  */
3029                    /*  arg 2 = offset of the following instruction  */
3030                    ic->arg[1] = addr & 0xffc;
3031                    ic->arg[2] = (addr & 0xffc) + 4;
3032    
3033                  ic->arg[0] = (iword & 0x00ffffff) << 2;                  ic->arg[0] = (iword & 0x00ffffff) << 2;
3034                  /*  Sign-extend:  */                  /*  Sign-extend:  */
3035                  if (ic->arg[0] & 0x02000000)                  if (ic->arg[0] & 0x02000000)
# Line 1877  X(to_be_translated) Line 3039  X(to_be_translated)
3039                   */                   */
3040                  ic->arg[0] = (int32_t)(ic->arg[0] + 8);                  ic->arg[0] = (int32_t)(ic->arg[0] + 8);
3041    
3042                  /*  Special case: branch within the same page:  */                  /*
3043                     *  Special case: branch within the same page:
3044                     *
3045                     *  arg[0] = addr of the arm_instr_call of the target
3046                     *  arg[1] = addr of the next arm_instr_call.
3047                     */
3048                  {                  {
3049                          uint32_t mask_within_page =                          uint32_t mask_within_page =
3050                              ((ARM_IC_ENTRIES_PER_PAGE-1) <<                              ((ARM_IC_ENTRIES_PER_PAGE-1) <<
# Line 1892  X(to_be_translated) Line 3059  X(to_be_translated)
3059                                      cpu->cd.arm.cur_ic_page +                                      cpu->cd.arm.cur_ic_page +
3060                                      ((new_pc & mask_within_page) >>                                      ((new_pc & mask_within_page) >>
3061                                      ARM_INSTR_ALIGNMENT_SHIFT));                                      ARM_INSTR_ALIGNMENT_SHIFT));
3062                                    ic->arg[1] = (size_t) (
3063                                        cpu->cd.arm.cur_ic_page +
3064                                        (((addr & mask_within_page) + 4) >>
3065                                        ARM_INSTR_ALIGNMENT_SHIFT));
3066                            } else if (main_opcode == 0x0a) {
3067                                    /*  Special hack for a plain "b":  */
3068                                    ic->arg[0] += ic->arg[1];
3069                          }                          }
3070                  }                  }
3071    
3072                    if (main_opcode == 0xa && (condition_code <= 1
3073                        || condition_code == 3 || condition_code == 8
3074                        || condition_code == 12 || condition_code == 13))
3075                            cpu->cd.arm.combination_check = COMBINE(beq_etc);
3076    
3077                    if (iword == 0x1afffffc)
3078                            cpu->cd.arm.combination_check = COMBINE(strlen);
3079    
3080                    /*  Hm. Does this really increase performance?  */
3081                    if (iword == 0x8afffffa)
3082                            cpu->cd.arm.combination_check =
3083                                COMBINE(netbsd_cacheclean2);
3084                    break;
3085    
3086            case 0xc:
3087            case 0xd:
3088                    /*
3089                     *  xxxx1100 0100nnnn ddddcccc oooommmm    MCRR c,op,Rd,Rn,CRm
3090                     *  xxxx1100 0101nnnn ddddcccc oooommmm    MRRC c,op,Rd,Rn,CRm
3091                     */
3092                    if ((iword & 0x0fe00fff) == 0x0c400000) {
3093                            /*  Special case: mar/mra DSP instructions  */
3094                            if (!cpu->translation_readahead)
3095                                    fatal("TODO: mar/mra DSP instructions!\n");
3096                            /*  Perhaps these are actually identical to MCRR/MRRC */
3097                            goto bad;
3098                    }
3099    
3100                    if ((iword & 0x0fe00000) == 0x0c400000) {
3101                            if (!cpu->translation_readahead)
3102                                    fatal("MCRR/MRRC: TODO\n");
3103                            goto bad;
3104                    }
3105    
3106                    /*
3107                     *  TODO: LDC/STC
3108                     *
3109                     *  For now, treat as Undefined instructions. This causes e.g.
3110                     *  Linux/ARM to emulate these instructions (floating point).
3111                     */
3112    #if 0
3113                    ic->f = cond_instr(und);
3114                    ic->arg[0] = addr & 0xfff;
3115    #else
3116                    if (!cpu->translation_readahead)
3117                            fatal("LDC/STC: TODO\n");
3118                    goto bad;
3119    #endif
3120                  break;                  break;
3121    
3122          case 0xe:          case 0xe:
3123                    if ((iword & 0x0ff00ff0) == 0x0e200010) {
3124                            /*  Special case: mia* DSP instructions  */
3125                            /*  See Intel's 27343601.pdf, page 16-20  */
3126                            if (!cpu->translation_readahead)
3127                                    fatal("TODO: mia* DSP instructions!\n");
3128                            goto bad;
3129                    }
3130                  if (iword & 0x10) {                  if (iword & 0x10) {
3131                          /*  xxxx1110 oooLNNNN ddddpppp qqq1MMMM  MCR/MRC  */                          /*  xxxx1110 oooLNNNN ddddpppp qqq1MMMM  MCR/MRC  */
3132                          ic->arg[0] = iword;                          ic->arg[0] = iword;
# Line 1906  X(to_be_translated) Line 3136  X(to_be_translated)
3136                          ic->arg[0] = iword;                          ic->arg[0] = iword;
3137                          ic->f = cond_instr(cdp);                          ic->f = cond_instr(cdp);
3138                  }                  }
3139                    if (iword == 0xee070f9a)
3140                            cpu->cd.arm.combination_check =
3141                                COMBINE(netbsd_cacheclean);
3142                  break;                  break;
3143    
3144          case 0xf:          case 0xf:
3145                  /*  SWI:  */                  /*  SWI:  */
3146                  /*  Default handler:  */                  /*  Default handler:  */
3147                  ic->f = cond_instr(swi);                  ic->f = cond_instr(swi);
3148                  if (iword == 0xef8c64be) {                  ic->arg[0] = addr & 0xfff;
3149                    if (iword == 0xef8c64eb) {
3150                            /*  Hack for rebooting a machine:  */
3151                            ic->f = instr(reboot);
3152                    } else if (iword == 0xef8c64be) {
3153                          /*  Hack for openfirmware prom emulation:  */                          /*  Hack for openfirmware prom emulation:  */
3154                          ic->f = instr(openfirmware);                          ic->f = instr(openfirmware);
3155                  } else if (cpu->machine->userland_emul != NULL) {                  } else if (cpu->machine->userland_emul != NULL) {
# Line 1920  X(to_be_translated) Line 3157  X(to_be_translated)
3157                                  ic->arg[0] = iword & 0x00ffffff;                                  ic->arg[0] = iword & 0x00ffffff;
3158                                  ic->f = cond_instr(swi_useremul);                                  ic->f = cond_instr(swi_useremul);
3159                          } else {                          } else {
3160                                  fatal("Bad userland SWI?\n");                                  if (!cpu->translation_readahead)
3161                                            fatal("Bad userland SWI?\n");
3162                                  goto bad;                                  goto bad;
3163                          }                          }
3164                  }                  }

Legend:
Removed from v.14  
changed lines
  Added in v.44

  ViewVC Help
Powered by ViewVC 1.1.26