]> Git Repo - qemu.git/blob - target-arm/op_helper.c
Merge remote-tracking branch 'remotes/afaerber/tags/qom-devices-for-peter' into staging
[qemu.git] / target-arm / op_helper.c
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 "exec/helper-proto.h"
21 #include "internals.h"
22
23 #define SIGNBIT (uint32_t)0x80000000
24 #define SIGNBIT64 ((uint64_t)1 << 63)
25
26 static void raise_exception(CPUARMState *env, int tt)
27 {
28     ARMCPU *cpu = arm_env_get_cpu(env);
29     CPUState *cs = CPU(cpu);
30
31     cs->exception_index = tt;
32     cpu_loop_exit(cs);
33 }
34
35 uint32_t HELPER(neon_tbl)(CPUARMState *env, uint32_t ireg, uint32_t def,
36                           uint32_t rn, uint32_t maxindex)
37 {
38     uint32_t val;
39     uint32_t tmp;
40     int index;
41     int shift;
42     uint64_t *table;
43     table = (uint64_t *)&env->vfp.regs[rn];
44     val = 0;
45     for (shift = 0; shift < 32; shift += 8) {
46         index = (ireg >> shift) & 0xff;
47         if (index < maxindex) {
48             tmp = (table[index >> 3] >> ((index & 7) << 3)) & 0xff;
49             val |= tmp << shift;
50         } else {
51             val |= def & (0xff << shift);
52         }
53     }
54     return val;
55 }
56
57 #if !defined(CONFIG_USER_ONLY)
58
59 #include "exec/softmmu_exec.h"
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)
78  */
79 void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx,
80               uintptr_t retaddr)
81 {
82     int ret;
83
84     ret = arm_cpu_handle_mmu_fault(cs, addr, is_write, mmu_idx);
85     if (unlikely(ret)) {
86         ARMCPU *cpu = ARM_CPU(cs);
87         CPUARMState *env = &cpu->env;
88
89         if (retaddr) {
90             /* now we have a real cpu fault */
91             cpu_restore_state(cs, retaddr);
92         }
93         raise_exception(env, cs->exception_index);
94     }
95 }
96 #endif
97
98 uint32_t HELPER(add_setq)(CPUARMState *env, uint32_t a, uint32_t b)
99 {
100     uint32_t res = a + b;
101     if (((res ^ a) & SIGNBIT) && !((a ^ b) & SIGNBIT))
102         env->QF = 1;
103     return res;
104 }
105
106 uint32_t HELPER(add_saturate)(CPUARMState *env, uint32_t a, uint32_t b)
107 {
108     uint32_t res = a + b;
109     if (((res ^ a) & SIGNBIT) && !((a ^ b) & SIGNBIT)) {
110         env->QF = 1;
111         res = ~(((int32_t)a >> 31) ^ SIGNBIT);
112     }
113     return res;
114 }
115
116 uint32_t HELPER(sub_saturate)(CPUARMState *env, uint32_t a, uint32_t b)
117 {
118     uint32_t res = a - b;
119     if (((res ^ a) & SIGNBIT) && ((a ^ b) & SIGNBIT)) {
120         env->QF = 1;
121         res = ~(((int32_t)a >> 31) ^ SIGNBIT);
122     }
123     return res;
124 }
125
126 uint32_t HELPER(double_saturate)(CPUARMState *env, int32_t val)
127 {
128     uint32_t res;
129     if (val >= 0x40000000) {
130         res = ~SIGNBIT;
131         env->QF = 1;
132     } else if (val <= (int32_t)0xc0000000) {
133         res = SIGNBIT;
134         env->QF = 1;
135     } else {
136         res = val << 1;
137     }
138     return res;
139 }
140
141 uint32_t HELPER(add_usaturate)(CPUARMState *env, uint32_t a, uint32_t b)
142 {
143     uint32_t res = a + b;
144     if (res < a) {
145         env->QF = 1;
146         res = ~0;
147     }
148     return res;
149 }
150
151 uint32_t HELPER(sub_usaturate)(CPUARMState *env, uint32_t a, uint32_t b)
152 {
153     uint32_t res = a - b;
154     if (res > a) {
155         env->QF = 1;
156         res = 0;
157     }
158     return res;
159 }
160
161 /* Signed saturation.  */
162 static inline uint32_t do_ssat(CPUARMState *env, int32_t val, int shift)
163 {
164     int32_t top;
165     uint32_t mask;
166
167     top = val >> shift;
168     mask = (1u << shift) - 1;
169     if (top > 0) {
170         env->QF = 1;
171         return mask;
172     } else if (top < -1) {
173         env->QF = 1;
174         return ~mask;
175     }
176     return val;
177 }
178
179 /* Unsigned saturation.  */
180 static inline uint32_t do_usat(CPUARMState *env, int32_t val, int shift)
181 {
182     uint32_t max;
183
184     max = (1u << shift) - 1;
185     if (val < 0) {
186         env->QF = 1;
187         return 0;
188     } else if (val > max) {
189         env->QF = 1;
190         return max;
191     }
192     return val;
193 }
194
195 /* Signed saturate.  */
196 uint32_t HELPER(ssat)(CPUARMState *env, uint32_t x, uint32_t shift)
197 {
198     return do_ssat(env, x, shift);
199 }
200
201 /* Dual halfword signed saturate.  */
202 uint32_t HELPER(ssat16)(CPUARMState *env, uint32_t x, uint32_t shift)
203 {
204     uint32_t res;
205
206     res = (uint16_t)do_ssat(env, (int16_t)x, shift);
207     res |= do_ssat(env, ((int32_t)x) >> 16, shift) << 16;
208     return res;
209 }
210
211 /* Unsigned saturate.  */
212 uint32_t HELPER(usat)(CPUARMState *env, uint32_t x, uint32_t shift)
213 {
214     return do_usat(env, x, shift);
215 }
216
217 /* Dual halfword unsigned saturate.  */
218 uint32_t HELPER(usat16)(CPUARMState *env, uint32_t x, uint32_t shift)
219 {
220     uint32_t res;
221
222     res = (uint16_t)do_usat(env, (int16_t)x, shift);
223     res |= do_usat(env, ((int32_t)x) >> 16, shift) << 16;
224     return res;
225 }
226
227 void HELPER(wfi)(CPUARMState *env)
228 {
229     CPUState *cs = CPU(arm_env_get_cpu(env));
230
231     cs->exception_index = EXCP_HLT;
232     cs->halted = 1;
233     cpu_loop_exit(cs);
234 }
235
236 void HELPER(wfe)(CPUARMState *env)
237 {
238     CPUState *cs = CPU(arm_env_get_cpu(env));
239
240     /* Don't actually halt the CPU, just yield back to top
241      * level loop
242      */
243     cs->exception_index = EXCP_YIELD;
244     cpu_loop_exit(cs);
245 }
246
247 /* Raise an internal-to-QEMU exception. This is limited to only
248  * those EXCP values which are special cases for QEMU to interrupt
249  * execution and not to be used for exceptions which are passed to
250  * the guest (those must all have syndrome information and thus should
251  * use exception_with_syndrome).
252  */
253 void HELPER(exception_internal)(CPUARMState *env, uint32_t excp)
254 {
255     CPUState *cs = CPU(arm_env_get_cpu(env));
256
257     assert(excp_is_internal(excp));
258     cs->exception_index = excp;
259     cpu_loop_exit(cs);
260 }
261
262 /* Raise an exception with the specified syndrome register value */
263 void HELPER(exception_with_syndrome)(CPUARMState *env, uint32_t excp,
264                                      uint32_t syndrome)
265 {
266     CPUState *cs = CPU(arm_env_get_cpu(env));
267
268     assert(!excp_is_internal(excp));
269     cs->exception_index = excp;
270     env->exception.syndrome = syndrome;
271     cpu_loop_exit(cs);
272 }
273
274 uint32_t HELPER(cpsr_read)(CPUARMState *env)
275 {
276     return cpsr_read(env) & ~CPSR_EXEC;
277 }
278
279 void HELPER(cpsr_write)(CPUARMState *env, uint32_t val, uint32_t mask)
280 {
281     cpsr_write(env, val, mask);
282 }
283
284 /* Access to user mode registers from privileged modes.  */
285 uint32_t HELPER(get_user_reg)(CPUARMState *env, uint32_t regno)
286 {
287     uint32_t val;
288
289     if (regno == 13) {
290         val = env->banked_r13[0];
291     } else if (regno == 14) {
292         val = env->banked_r14[0];
293     } else if (regno >= 8
294                && (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) {
295         val = env->usr_regs[regno - 8];
296     } else {
297         val = env->regs[regno];
298     }
299     return val;
300 }
301
302 void HELPER(set_user_reg)(CPUARMState *env, uint32_t regno, uint32_t val)
303 {
304     if (regno == 13) {
305         env->banked_r13[0] = val;
306     } else if (regno == 14) {
307         env->banked_r14[0] = val;
308     } else if (regno >= 8
309                && (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) {
310         env->usr_regs[regno - 8] = val;
311     } else {
312         env->regs[regno] = val;
313     }
314 }
315
316 void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip, uint32_t syndrome)
317 {
318     const ARMCPRegInfo *ri = rip;
319     switch (ri->accessfn(env, ri)) {
320     case CP_ACCESS_OK:
321         return;
322     case CP_ACCESS_TRAP:
323         env->exception.syndrome = syndrome;
324         break;
325     case CP_ACCESS_TRAP_UNCATEGORIZED:
326         env->exception.syndrome = syn_uncategorized();
327         break;
328     default:
329         g_assert_not_reached();
330     }
331     raise_exception(env, EXCP_UDEF);
332 }
333
334 void HELPER(set_cp_reg)(CPUARMState *env, void *rip, uint32_t value)
335 {
336     const ARMCPRegInfo *ri = rip;
337
338     ri->writefn(env, ri, value);
339 }
340
341 uint32_t HELPER(get_cp_reg)(CPUARMState *env, void *rip)
342 {
343     const ARMCPRegInfo *ri = rip;
344
345     return ri->readfn(env, ri);
346 }
347
348 void HELPER(set_cp_reg64)(CPUARMState *env, void *rip, uint64_t value)
349 {
350     const ARMCPRegInfo *ri = rip;
351
352     ri->writefn(env, ri, value);
353 }
354
355 uint64_t HELPER(get_cp_reg64)(CPUARMState *env, void *rip)
356 {
357     const ARMCPRegInfo *ri = rip;
358
359     return ri->readfn(env, ri);
360 }
361
362 void HELPER(msr_i_pstate)(CPUARMState *env, uint32_t op, uint32_t imm)
363 {
364     /* MSR_i to update PSTATE. This is OK from EL0 only if UMA is set.
365      * Note that SPSel is never OK from EL0; we rely on handle_msr_i()
366      * to catch that case at translate time.
367      */
368     if (arm_current_pl(env) == 0 && !(env->cp15.c1_sys & SCTLR_UMA)) {
369         raise_exception(env, EXCP_UDEF);
370     }
371
372     switch (op) {
373     case 0x05: /* SPSel */
374         update_spsel(env, imm);
375         break;
376     case 0x1e: /* DAIFSet */
377         env->daif |= (imm << 6) & PSTATE_DAIF;
378         break;
379     case 0x1f: /* DAIFClear */
380         env->daif &= ~((imm << 6) & PSTATE_DAIF);
381         break;
382     default:
383         g_assert_not_reached();
384     }
385 }
386
387 void HELPER(exception_return)(CPUARMState *env)
388 {
389     int cur_el = arm_current_pl(env);
390     unsigned int spsr_idx = aarch64_banked_spsr_index(cur_el);
391     uint32_t spsr = env->banked_spsr[spsr_idx];
392     int new_el, i;
393
394     if (env->pstate & PSTATE_SP) {
395         env->sp_el[cur_el] = env->xregs[31];
396     } else {
397         env->sp_el[0] = env->xregs[31];
398     }
399
400     env->exclusive_addr = -1;
401
402     if (spsr & PSTATE_nRW) {
403         /* TODO: We currently assume EL1/2/3 are running in AArch64.  */
404         env->aarch64 = 0;
405         new_el = 0;
406         env->uncached_cpsr = 0x10;
407         cpsr_write(env, spsr, ~0);
408         for (i = 0; i < 15; i++) {
409             env->regs[i] = env->xregs[i];
410         }
411
412         env->regs[15] = env->elr_el[1] & ~0x1;
413     } else {
414         new_el = extract32(spsr, 2, 2);
415         if (new_el > cur_el
416             || (new_el == 2 && !arm_feature(env, ARM_FEATURE_EL2))) {
417             /* Disallow return to an EL which is unimplemented or higher
418              * than the current one.
419              */
420             goto illegal_return;
421         }
422         if (extract32(spsr, 1, 1)) {
423             /* Return with reserved M[1] bit set */
424             goto illegal_return;
425         }
426         if (new_el == 0 && (spsr & PSTATE_SP)) {
427             /* Return to EL0 with M[0] bit set */
428             goto illegal_return;
429         }
430         env->aarch64 = 1;
431         pstate_write(env, spsr);
432         env->xregs[31] = env->sp_el[new_el];
433         env->pc = env->elr_el[cur_el];
434     }
435
436     return;
437
438 illegal_return:
439     /* Illegal return events of various kinds have architecturally
440      * mandated behaviour:
441      * restore NZCV and DAIF from SPSR_ELx
442      * set PSTATE.IL
443      * restore PC from ELR_ELx
444      * no change to exception level, execution state or stack pointer
445      */
446     env->pstate |= PSTATE_IL;
447     env->pc = env->elr_el[cur_el];
448     spsr &= PSTATE_NZCV | PSTATE_DAIF;
449     spsr |= pstate_read(env) & ~(PSTATE_NZCV | PSTATE_DAIF);
450     pstate_write(env, spsr);
451 }
452
453 /* ??? Flag setting arithmetic is awkward because we need to do comparisons.
454    The only way to do that in TCG is a conditional branch, which clobbers
455    all our temporaries.  For now implement these as helper functions.  */
456
457 /* Similarly for variable shift instructions.  */
458
459 uint32_t HELPER(shl_cc)(CPUARMState *env, uint32_t x, uint32_t i)
460 {
461     int shift = i & 0xff;
462     if (shift >= 32) {
463         if (shift == 32)
464             env->CF = x & 1;
465         else
466             env->CF = 0;
467         return 0;
468     } else if (shift != 0) {
469         env->CF = (x >> (32 - shift)) & 1;
470         return x << shift;
471     }
472     return x;
473 }
474
475 uint32_t HELPER(shr_cc)(CPUARMState *env, uint32_t x, uint32_t i)
476 {
477     int shift = i & 0xff;
478     if (shift >= 32) {
479         if (shift == 32)
480             env->CF = (x >> 31) & 1;
481         else
482             env->CF = 0;
483         return 0;
484     } else if (shift != 0) {
485         env->CF = (x >> (shift - 1)) & 1;
486         return x >> shift;
487     }
488     return x;
489 }
490
491 uint32_t HELPER(sar_cc)(CPUARMState *env, uint32_t x, uint32_t i)
492 {
493     int shift = i & 0xff;
494     if (shift >= 32) {
495         env->CF = (x >> 31) & 1;
496         return (int32_t)x >> 31;
497     } else if (shift != 0) {
498         env->CF = (x >> (shift - 1)) & 1;
499         return (int32_t)x >> shift;
500     }
501     return x;
502 }
503
504 uint32_t HELPER(ror_cc)(CPUARMState *env, uint32_t x, uint32_t i)
505 {
506     int shift1, shift;
507     shift1 = i & 0xff;
508     shift = shift1 & 0x1f;
509     if (shift == 0) {
510         if (shift1 != 0)
511             env->CF = (x >> 31) & 1;
512         return x;
513     } else {
514         env->CF = (x >> (shift - 1)) & 1;
515         return ((uint32_t)x >> shift) | (x << (32 - shift));
516     }
517 }
This page took 0.052045 seconds and 4 git commands to generate.