]> Git Repo - qemu.git/blob - target-arm/op_helper.c
target-arm: Split out private-to-target functions into internals.h
[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 "helper.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 void HELPER(exception)(CPUARMState *env, uint32_t excp)
248 {
249     CPUState *cs = CPU(arm_env_get_cpu(env));
250
251     cs->exception_index = excp;
252     cpu_loop_exit(cs);
253 }
254
255 uint32_t HELPER(cpsr_read)(CPUARMState *env)
256 {
257     return cpsr_read(env) & ~CPSR_EXEC;
258 }
259
260 void HELPER(cpsr_write)(CPUARMState *env, uint32_t val, uint32_t mask)
261 {
262     cpsr_write(env, val, mask);
263 }
264
265 /* Access to user mode registers from privileged modes.  */
266 uint32_t HELPER(get_user_reg)(CPUARMState *env, uint32_t regno)
267 {
268     uint32_t val;
269
270     if (regno == 13) {
271         val = env->banked_r13[0];
272     } else if (regno == 14) {
273         val = env->banked_r14[0];
274     } else if (regno >= 8
275                && (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) {
276         val = env->usr_regs[regno - 8];
277     } else {
278         val = env->regs[regno];
279     }
280     return val;
281 }
282
283 void HELPER(set_user_reg)(CPUARMState *env, uint32_t regno, uint32_t val)
284 {
285     if (regno == 13) {
286         env->banked_r13[0] = val;
287     } else if (regno == 14) {
288         env->banked_r14[0] = val;
289     } else if (regno >= 8
290                && (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) {
291         env->usr_regs[regno - 8] = val;
292     } else {
293         env->regs[regno] = val;
294     }
295 }
296
297 void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip)
298 {
299     const ARMCPRegInfo *ri = rip;
300     switch (ri->accessfn(env, ri)) {
301     case CP_ACCESS_OK:
302         return;
303     case CP_ACCESS_TRAP:
304     case CP_ACCESS_TRAP_UNCATEGORIZED:
305         /* These cases will eventually need to generate different
306          * syndrome information.
307          */
308         break;
309     default:
310         g_assert_not_reached();
311     }
312     raise_exception(env, EXCP_UDEF);
313 }
314
315 void HELPER(set_cp_reg)(CPUARMState *env, void *rip, uint32_t value)
316 {
317     const ARMCPRegInfo *ri = rip;
318
319     ri->writefn(env, ri, value);
320 }
321
322 uint32_t HELPER(get_cp_reg)(CPUARMState *env, void *rip)
323 {
324     const ARMCPRegInfo *ri = rip;
325
326     return ri->readfn(env, ri);
327 }
328
329 void HELPER(set_cp_reg64)(CPUARMState *env, void *rip, uint64_t value)
330 {
331     const ARMCPRegInfo *ri = rip;
332
333     ri->writefn(env, ri, value);
334 }
335
336 uint64_t HELPER(get_cp_reg64)(CPUARMState *env, void *rip)
337 {
338     const ARMCPRegInfo *ri = rip;
339
340     return ri->readfn(env, ri);
341 }
342
343 void HELPER(msr_i_pstate)(CPUARMState *env, uint32_t op, uint32_t imm)
344 {
345     /* MSR_i to update PSTATE. This is OK from EL0 only if UMA is set.
346      * Note that SPSel is never OK from EL0; we rely on handle_msr_i()
347      * to catch that case at translate time.
348      */
349     if (arm_current_pl(env) == 0 && !(env->cp15.c1_sys & SCTLR_UMA)) {
350         raise_exception(env, EXCP_UDEF);
351     }
352
353     switch (op) {
354     case 0x05: /* SPSel */
355         env->pstate = deposit32(env->pstate, 0, 1, imm);
356         break;
357     case 0x1e: /* DAIFSet */
358         env->daif |= (imm << 6) & PSTATE_DAIF;
359         break;
360     case 0x1f: /* DAIFClear */
361         env->daif &= ~((imm << 6) & PSTATE_DAIF);
362         break;
363     default:
364         g_assert_not_reached();
365     }
366 }
367
368 /* ??? Flag setting arithmetic is awkward because we need to do comparisons.
369    The only way to do that in TCG is a conditional branch, which clobbers
370    all our temporaries.  For now implement these as helper functions.  */
371
372 /* Similarly for variable shift instructions.  */
373
374 uint32_t HELPER(shl_cc)(CPUARMState *env, uint32_t x, uint32_t i)
375 {
376     int shift = i & 0xff;
377     if (shift >= 32) {
378         if (shift == 32)
379             env->CF = x & 1;
380         else
381             env->CF = 0;
382         return 0;
383     } else if (shift != 0) {
384         env->CF = (x >> (32 - shift)) & 1;
385         return x << shift;
386     }
387     return x;
388 }
389
390 uint32_t HELPER(shr_cc)(CPUARMState *env, uint32_t x, uint32_t i)
391 {
392     int shift = i & 0xff;
393     if (shift >= 32) {
394         if (shift == 32)
395             env->CF = (x >> 31) & 1;
396         else
397             env->CF = 0;
398         return 0;
399     } else if (shift != 0) {
400         env->CF = (x >> (shift - 1)) & 1;
401         return x >> shift;
402     }
403     return x;
404 }
405
406 uint32_t HELPER(sar_cc)(CPUARMState *env, uint32_t x, uint32_t i)
407 {
408     int shift = i & 0xff;
409     if (shift >= 32) {
410         env->CF = (x >> 31) & 1;
411         return (int32_t)x >> 31;
412     } else if (shift != 0) {
413         env->CF = (x >> (shift - 1)) & 1;
414         return (int32_t)x >> shift;
415     }
416     return x;
417 }
418
419 uint32_t HELPER(ror_cc)(CPUARMState *env, uint32_t x, uint32_t i)
420 {
421     int shift1, shift;
422     shift1 = i & 0xff;
423     shift = shift1 & 0x1f;
424     if (shift == 0) {
425         if (shift1 != 0)
426             env->CF = (x >> 31) & 1;
427         return x;
428     } else {
429         env->CF = (x >> (shift - 1)) & 1;
430         return ((uint32_t)x >> shift) | (x << (32 - shift));
431     }
432 }
This page took 0.050344 seconds and 4 git commands to generate.