• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  ARM helper routines
3  *
4  *  Copyright (c) 2005-2007 CodeSourcery, LLC
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18  */
19 #include "cpu.h"
20 #include "tcg.h"
21 #include "helper.h"
22 
23 #define SIGNBIT (uint32_t)0x80000000
24 #define SIGNBIT64 ((uint64_t)1 << 63)
25 
26 #if !defined(CONFIG_USER_ONLY)
raise_exception(CPUARMState * env,int tt)27 static void raise_exception(CPUARMState *env, int tt)
28 {
29     env->exception_index = tt;
30     cpu_loop_exit(env);
31 }
32 #endif
33 
HELPER(neon_tbl)34 uint32_t HELPER(neon_tbl)(CPUARMState *env, uint32_t ireg, uint32_t def,
35                           uint32_t rn, uint32_t maxindex)
36 {
37     uint32_t val;
38     uint32_t tmp;
39     int index;
40     int shift;
41     uint64_t *table;
42     table = (uint64_t *)&env->vfp.regs[rn];
43     val = 0;
44     for (shift = 0; shift < 32; shift += 8) {
45         index = (ireg >> shift) & 0xff;
46         if (index < maxindex) {
47             tmp = (table[index >> 3] >> ((index & 7) << 3)) & 0xff;
48             val |= tmp << shift;
49         } else {
50             val |= def & (0xff << shift);
51         }
52     }
53     return val;
54 }
55 
56 #undef env
57 
58 #if !defined(CONFIG_USER_ONLY)
59 
60 
61 #define MMUSUFFIX _mmu
62 
63 #define SHIFT 0
64 #include "exec/softmmu_template.h"
65 
66 #define SHIFT 1
67 #include "exec/softmmu_template.h"
68 
69 #define SHIFT 2
70 #include "exec/softmmu_template.h"
71 
72 #define SHIFT 3
73 #include "exec/softmmu_template.h"
74 
75 /* try to fill the TLB and return an exception if error. If retaddr is
76    NULL, it means that the function was called in C code (i.e. not
77    from generated code or from helper.c) */
tlb_fill(CPUARMState * env,target_ulong addr,int is_write,int mmu_idx,uintptr_t retaddr)78 void tlb_fill(CPUARMState *env, target_ulong addr, int is_write, int mmu_idx,
79               uintptr_t retaddr)
80 {
81     int ret;
82 
83     ret = cpu_arm_handle_mmu_fault(env, addr, is_write, mmu_idx);
84     if (unlikely(ret)) {
85         if (retaddr) {
86             /* now we have a real cpu fault */
87             cpu_restore_state(env, retaddr);
88         }
89         raise_exception(env, env->exception_index);
90     }
91 }
92 
HELPER(set_cp)93 void HELPER(set_cp)(CPUARMState *env, uint32_t insn, uint32_t val)
94 {
95     int cp_num = (insn >> 8) & 0xf;
96     int cp_info = (insn >> 5) & 7;
97     int src = (insn >> 16) & 0xf;
98     int operand = insn & 0xf;
99 
100     if (env->cp[cp_num].cp_write)
101         env->cp[cp_num].cp_write(env->cp[cp_num].opaque,
102                                  cp_info, src, operand, val, (void*)GETPC());
103         }
104 
HELPER(get_cp)105 uint32_t HELPER(get_cp)(CPUARMState *env, uint32_t insn)
106 {
107     int cp_num = (insn >> 8) & 0xf;
108     int cp_info = (insn >> 5) & 7;
109     int dest = (insn >> 16) & 0xf;
110     int operand = insn & 0xf;
111 
112     if (env->cp[cp_num].cp_read)
113         return env->cp[cp_num].cp_read(env->cp[cp_num].opaque,
114                                        cp_info, dest, operand, (void*)GETPC());
115         return 0;
116 }
117 
118 #else
119 
HELPER(set_cp)120 void HELPER(set_cp)(CPUARMState *env, uint32_t insn, uint32_t val)
121 {
122     int op1 = (insn >> 8) & 0xf;
123     cpu_abort(env, "cp%i insn %08x\n", op1, insn);
124     return;
125 }
126 
HELPER(get_cp)127 uint32_t HELPER(get_cp)(CPUARMState *env, uint32_t insn)
128 {
129     int op1 = (insn >> 8) & 0xf;
130     cpu_abort(env, "cp%i insn %08x\n", op1, insn);
131     return 0;
132 }
133 
134 #endif
135 
HELPER(add_setq)136 uint32_t HELPER(add_setq)(CPUARMState *env, uint32_t a, uint32_t b)
137 {
138     uint32_t res = a + b;
139     if (((res ^ a) & SIGNBIT) && !((a ^ b) & SIGNBIT))
140         env->QF = 1;
141     return res;
142 }
143 
HELPER(add_saturate)144 uint32_t HELPER(add_saturate)(CPUARMState *env, uint32_t a, uint32_t b)
145 {
146     uint32_t res = a + b;
147     if (((res ^ a) & SIGNBIT) && !((a ^ b) & SIGNBIT)) {
148         env->QF = 1;
149         res = ~(((int32_t)a >> 31) ^ SIGNBIT);
150     }
151     return res;
152 }
153 
HELPER(sub_saturate)154 uint32_t HELPER(sub_saturate)(CPUARMState *env, uint32_t a, uint32_t b)
155 {
156     uint32_t res = a - b;
157     if (((res ^ a) & SIGNBIT) && ((a ^ b) & SIGNBIT)) {
158         env->QF = 1;
159         res = ~(((int32_t)a >> 31) ^ SIGNBIT);
160     }
161     return res;
162 }
163 
HELPER(double_saturate)164 uint32_t HELPER(double_saturate)(CPUARMState *env, int32_t val)
165 {
166     uint32_t res;
167     if (val >= 0x40000000) {
168         res = ~SIGNBIT;
169         env->QF = 1;
170     } else if (val <= (int32_t)0xc0000000) {
171         res = SIGNBIT;
172         env->QF = 1;
173     } else {
174         res = val << 1;
175     }
176     return res;
177 }
178 
HELPER(add_usaturate)179 uint32_t HELPER(add_usaturate)(CPUARMState *env, uint32_t a, uint32_t b)
180 {
181     uint32_t res = a + b;
182     if (res < a) {
183         env->QF = 1;
184         res = ~0;
185     }
186     return res;
187 }
188 
HELPER(sub_usaturate)189 uint32_t HELPER(sub_usaturate)(CPUARMState *env, uint32_t a, uint32_t b)
190 {
191     uint32_t res = a - b;
192     if (res > a) {
193         env->QF = 1;
194         res = 0;
195     }
196     return res;
197 }
198 
199 /* Signed saturation.  */
do_ssat(CPUARMState * env,int32_t val,int shift)200 static inline uint32_t do_ssat(CPUARMState *env, int32_t val, int shift)
201 {
202     int32_t top;
203     uint32_t mask;
204 
205     top = val >> shift;
206     mask = (1u << shift) - 1;
207     if (top > 0) {
208         env->QF = 1;
209         return mask;
210     } else if (top < -1) {
211         env->QF = 1;
212         return ~mask;
213     }
214     return val;
215 }
216 
217 /* Unsigned saturation.  */
do_usat(CPUARMState * env,int32_t val,int shift)218 static inline uint32_t do_usat(CPUARMState *env, int32_t val, int shift)
219 {
220     uint32_t max;
221 
222     max = (1u << shift) - 1;
223     if (val < 0) {
224         env->QF = 1;
225         return 0;
226     } else if (val > max) {
227         env->QF = 1;
228         return max;
229     }
230     return val;
231 }
232 
233 /* Signed saturate.  */
HELPER(ssat)234 uint32_t HELPER(ssat)(CPUARMState *env, uint32_t x, uint32_t shift)
235 {
236     return do_ssat(env, x, shift);
237 }
238 
239 /* Dual halfword signed saturate.  */
HELPER(ssat16)240 uint32_t HELPER(ssat16)(CPUARMState *env, uint32_t x, uint32_t shift)
241 {
242     uint32_t res;
243 
244     res = (uint16_t)do_ssat(env, (int16_t)x, shift);
245     res |= do_ssat(env, ((int32_t)x) >> 16, shift) << 16;
246     return res;
247 }
248 
249 /* Unsigned saturate.  */
HELPER(usat)250 uint32_t HELPER(usat)(CPUARMState *env, uint32_t x, uint32_t shift)
251 {
252     return do_usat(env, x, shift);
253 }
254 
255 /* Dual halfword unsigned saturate.  */
HELPER(usat16)256 uint32_t HELPER(usat16)(CPUARMState *env, uint32_t x, uint32_t shift)
257 {
258     uint32_t res;
259 
260     res = (uint16_t)do_usat(env, (int16_t)x, shift);
261     res |= do_usat(env, ((int32_t)x) >> 16, shift) << 16;
262     return res;
263 }
264 
HELPER(wfi)265 void HELPER(wfi)(CPUARMState *env)
266 {
267     env->exception_index = EXCP_HLT;
268     ENV_GET_CPU(env)->halted = 1;
269     cpu_loop_exit(env);
270 }
271 
HELPER(exception)272 void HELPER(exception)(CPUARMState *env, uint32_t excp)
273 {
274     env->exception_index = excp;
275     cpu_loop_exit(env);
276 }
277 
HELPER(cpsr_read)278 uint32_t HELPER(cpsr_read)(CPUARMState *env)
279 {
280     return cpsr_read(env) & ~CPSR_EXEC;
281 }
282 
HELPER(cpsr_write)283 void HELPER(cpsr_write)(CPUARMState *env, uint32_t val, uint32_t mask)
284 {
285     cpsr_write(env, val, mask);
286 }
287 
288 /* Access to user mode registers from privileged modes.  */
HELPER(get_user_reg)289 uint32_t HELPER(get_user_reg)(CPUARMState *env, uint32_t regno)
290 {
291     uint32_t val;
292 
293     if (regno == 13) {
294         val = env->banked_r13[0];
295     } else if (regno == 14) {
296         val = env->banked_r14[0];
297     } else if (regno >= 8
298                && (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) {
299         val = env->usr_regs[regno - 8];
300     } else {
301         val = env->regs[regno];
302     }
303     return val;
304 }
305 
HELPER(set_user_reg)306 void HELPER(set_user_reg)(CPUARMState *env, uint32_t regno, uint32_t val)
307 {
308     if (regno == 13) {
309         env->banked_r13[0] = val;
310     } else if (regno == 14) {
311         env->banked_r14[0] = val;
312     } else if (regno >= 8
313                && (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) {
314         env->usr_regs[regno - 8] = val;
315     } else {
316         env->regs[regno] = val;
317     }
318 }
319 
320 /* ??? Flag setting arithmetic is awkward because we need to do comparisons.
321    The only way to do that in TCG is a conditional branch, which clobbers
322    all our temporaries.  For now implement these as helper functions.  */
323 
HELPER(add_cc)324 uint32_t HELPER (add_cc)(CPUARMState *env, uint32_t a, uint32_t b)
325 {
326     uint32_t result;
327     result = a + b;
328     env->NF = env->ZF = result;
329     env->CF = result < a;
330     env->VF = (a ^ b ^ -1) & (a ^ result);
331     return result;
332 }
333 
HELPER(adc_cc)334 uint32_t HELPER(adc_cc)(CPUARMState *env, uint32_t a, uint32_t b)
335 {
336     uint32_t result;
337     if (!env->CF) {
338         result = a + b;
339         env->CF = result < a;
340     } else {
341         result = a + b + 1;
342         env->CF = result <= a;
343     }
344     env->VF = (a ^ b ^ -1) & (a ^ result);
345     env->NF = env->ZF = result;
346     return result;
347 }
348 
HELPER(sub_cc)349 uint32_t HELPER(sub_cc)(CPUARMState *env, uint32_t a, uint32_t b)
350 {
351     uint32_t result;
352     result = a - b;
353     env->NF = env->ZF = result;
354     env->CF = a >= b;
355     env->VF = (a ^ b) & (a ^ result);
356     return result;
357 }
358 
HELPER(sbc_cc)359 uint32_t HELPER(sbc_cc)(CPUARMState *env, uint32_t a, uint32_t b)
360 {
361     uint32_t result;
362     if (!env->CF) {
363         result = a - b - 1;
364         env->CF = a > b;
365     } else {
366         result = a - b;
367         env->CF = a >= b;
368     }
369     env->VF = (a ^ b) & (a ^ result);
370     env->NF = env->ZF = result;
371     return result;
372 }
373 
374 /* Similarly for variable shift instructions.  */
375 
HELPER(shl)376 uint32_t HELPER(shl)(uint32_t x, uint32_t i)
377 {
378     int shift = i & 0xff;
379     if (shift >= 32)
380         return 0;
381     return x << shift;
382 }
383 
HELPER(shr)384 uint32_t HELPER(shr)(uint32_t x, uint32_t i)
385 {
386     int shift = i & 0xff;
387     if (shift >= 32)
388         return 0;
389     return (uint32_t)x >> shift;
390 }
391 
HELPER(sar)392 uint32_t HELPER(sar)(uint32_t x, uint32_t i)
393 {
394     int shift = i & 0xff;
395     if (shift >= 32)
396         shift = 31;
397     return (int32_t)x >> shift;
398 }
399 
HELPER(shl_cc)400 uint32_t HELPER(shl_cc)(CPUARMState *env, uint32_t x, uint32_t i)
401 {
402     int shift = i & 0xff;
403     if (shift >= 32) {
404         if (shift == 32)
405             env->CF = x & 1;
406         else
407             env->CF = 0;
408         return 0;
409     } else if (shift != 0) {
410         env->CF = (x >> (32 - shift)) & 1;
411         return x << shift;
412     }
413     return x;
414 }
415 
HELPER(shr_cc)416 uint32_t HELPER(shr_cc)(CPUARMState *env, uint32_t x, uint32_t i)
417 {
418     int shift = i & 0xff;
419     if (shift >= 32) {
420         if (shift == 32)
421             env->CF = (x >> 31) & 1;
422         else
423             env->CF = 0;
424         return 0;
425     } else if (shift != 0) {
426         env->CF = (x >> (shift - 1)) & 1;
427         return x >> shift;
428     }
429     return x;
430 }
431 
HELPER(sar_cc)432 uint32_t HELPER(sar_cc)(CPUARMState *env, uint32_t x, uint32_t i)
433 {
434     int shift = i & 0xff;
435     if (shift >= 32) {
436         env->CF = (x >> 31) & 1;
437         return (int32_t)x >> 31;
438     } else if (shift != 0) {
439         env->CF = (x >> (shift - 1)) & 1;
440         return (int32_t)x >> shift;
441     }
442     return x;
443 }
444 
HELPER(ror_cc)445 uint32_t HELPER(ror_cc)(CPUARMState *env, uint32_t x, uint32_t i)
446 {
447     int shift1, shift;
448     shift1 = i & 0xff;
449     shift = shift1 & 0x1f;
450     if (shift == 0) {
451         if (shift1 != 0)
452             env->CF = (x >> 31) & 1;
453         return x;
454     } else {
455         env->CF = (x >> (shift - 1)) & 1;
456         return ((uint32_t)x >> shift) | (x << (32 - shift));
457     }
458 }
459 
HELPER(neon_vldst_all)460 void HELPER(neon_vldst_all)(CPUARMState *env, uint32_t insn)
461 {
462 #if defined(CONFIG_USER_ONLY)
463 #define LDB(addr) ldub(addr)
464 #define LDW(addr) lduw(addr)
465 #define LDL(addr) ldl(addr)
466 #define LDQ(addr) ldq(addr)
467 #define STB(addr, val) stb(addr, val)
468 #define STW(addr, val) stw(addr, val)
469 #define STL(addr, val) stl(addr, val)
470 #define STQ(addr, val) stq(addr, val)
471 #else
472     int user = cpu_mmu_index(env);
473 #define LDB(addr) helper_ldb_mmu(env, addr, user)
474 #define LDW(addr) helper_le_lduw_mmu(env, addr, user, GETPC())
475 #define LDL(addr) helper_le_ldul_mmu(env, addr, user, GETPC())
476 #define LDQ(addr) helper_le_ldq_mmu(env, addr, user, GETPC())
477 #define STB(addr, val) helper_stb_mmu(env, addr, val, user)
478 #define STW(addr, val) helper_le_stw_mmu(env, addr, val, user, GETPC())
479 #define STL(addr, val) helper_le_stl_mmu(env, addr, val, user, GETPC())
480 #define STQ(addr, val) helper_le_stq_mmu(env, addr, val, user, GETPC())
481 #endif
482     static const struct {
483         int nregs;
484         int interleave;
485         int spacing;
486     } neon_ls_element_type[11] = {
487         {4, 4, 1},
488         {4, 4, 2},
489         {4, 1, 1},
490         {4, 2, 1},
491         {3, 3, 1},
492         {3, 3, 2},
493         {3, 1, 1},
494         {1, 1, 1},
495         {2, 2, 1},
496         {2, 2, 2},
497         {2, 1, 1}
498     };
499 
500     const int op = (insn >> 8) & 0xf;
501     const int size = (insn >> 6) & 3;
502     int rd = ((insn >> 12) & 0x0f) | ((insn >> 18) & 0x10);
503     const int rn = (insn >> 16) & 0xf;
504     const int load = (insn & (1 << 21)) != 0;
505     const int nregs = neon_ls_element_type[op].nregs;
506     const int interleave = neon_ls_element_type[op].interleave;
507     const int spacing = neon_ls_element_type[op].spacing;
508     uint32_t addr = env->regs[rn];
509     const int stride = (1 << size) * interleave;
510     int i, reg;
511     uint64_t tmp64;
512 
513     for (reg = 0; reg < nregs; reg++) {
514         if (interleave > 2 || (interleave == 2 && nregs == 2)) {
515             addr = env->regs[rn] + (1 << size) * reg;
516         } else if (interleave == 2 && nregs == 4 && reg == 2) {
517             addr = env->regs[rn] + (1 << size);
518         }
519         switch (size) {
520             case 3:
521                 if (load) {
522                     env->vfp.regs[rd] = make_float64(LDQ(addr));
523                 } else {
524                     STQ(addr, float64_val(env->vfp.regs[rd]));
525                 }
526                 addr += stride;
527                 break;
528             case 2:
529                 if (load) {
530                     tmp64 = (uint32_t)LDL(addr);
531                     addr += stride;
532                     tmp64 |= (uint64_t)LDL(addr) << 32;
533                     addr += stride;
534                     env->vfp.regs[rd] = make_float64(tmp64);
535                 } else {
536                     tmp64 = float64_val(env->vfp.regs[rd]);
537                     STL(addr, tmp64);
538                     addr += stride;
539                     STL(addr, tmp64 >> 32);
540                     addr += stride;
541                 }
542                 break;
543             case 1:
544                 if (load) {
545                     tmp64 = 0ull;
546                     for (i = 0; i < 4; i++, addr += stride) {
547                         tmp64 |= (uint64_t)LDW(addr) << (i * 16);
548                     }
549                     env->vfp.regs[rd] = make_float64(tmp64);
550                 } else {
551                     tmp64 = float64_val(env->vfp.regs[rd]);
552                     for (i = 0; i < 4; i++, addr += stride, tmp64 >>= 16) {
553                         STW(addr, tmp64);
554                     }
555                 }
556                 break;
557             case 0:
558                 if (load) {
559                     tmp64 = 0ull;
560                     for (i = 0; i < 8; i++, addr += stride) {
561                         tmp64 |= (uint64_t)LDB(addr) << (i * 8);
562                     }
563                     env->vfp.regs[rd] = make_float64(tmp64);
564                 } else {
565                     tmp64 = float64_val(env->vfp.regs[rd]);
566                     for (i = 0; i < 8; i++, addr += stride, tmp64 >>= 8) {
567                         STB(addr, tmp64);
568                     }
569                 }
570                 break;
571         }
572         rd += spacing;
573     }
574 #undef LDB
575 #undef LDW
576 #undef LDL
577 #undef LDQ
578 #undef STB
579 #undef STW
580 #undef STL
581 #undef STQ
582 }
583