]> Git Repo - qemu.git/blob - target-arm/op_helper.c
Merge remote-tracking branch 'mst/tags/for_anthony' 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 "dyngen-exec.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)
27 static void raise_exception(int tt)
28 {
29     env->exception_index = tt;
30     cpu_loop_exit(env);
31 }
32 #endif
33
34 uint32_t HELPER(neon_tbl)(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 #if !defined(CONFIG_USER_ONLY)
57
58 #include "softmmu_exec.h"
59
60 #define MMUSUFFIX _mmu
61
62 #define SHIFT 0
63 #include "softmmu_template.h"
64
65 #define SHIFT 1
66 #include "softmmu_template.h"
67
68 #define SHIFT 2
69 #include "softmmu_template.h"
70
71 #define SHIFT 3
72 #include "softmmu_template.h"
73
74 /* try to fill the TLB and return an exception if error. If retaddr is
75    NULL, it means that the function was called in C code (i.e. not
76    from generated code or from helper.c) */
77 /* XXX: fix it to restore all registers */
78 void tlb_fill(CPUARMState *env1, target_ulong addr, int is_write, int mmu_idx,
79               uintptr_t retaddr)
80 {
81     TranslationBlock *tb;
82     CPUARMState *saved_env;
83     int ret;
84
85     saved_env = env;
86     env = env1;
87     ret = cpu_arm_handle_mmu_fault(env, addr, is_write, mmu_idx);
88     if (unlikely(ret)) {
89         if (retaddr) {
90             /* now we have a real cpu fault */
91             tb = tb_find_pc(retaddr);
92             if (tb) {
93                 /* the PC is inside the translated code. It means that we have
94                    a virtual CPU fault */
95                 cpu_restore_state(tb, env, retaddr);
96             }
97         }
98         raise_exception(env->exception_index);
99     }
100     env = saved_env;
101 }
102 #endif
103
104 /* FIXME: Pass an axplicit pointer to QF to CPUARMState, and move saturating
105    instructions into helper.c  */
106 uint32_t HELPER(add_setq)(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     return res;
112 }
113
114 uint32_t HELPER(add_saturate)(uint32_t a, uint32_t b)
115 {
116     uint32_t res = a + b;
117     if (((res ^ a) & SIGNBIT) && !((a ^ b) & SIGNBIT)) {
118         env->QF = 1;
119         res = ~(((int32_t)a >> 31) ^ SIGNBIT);
120     }
121     return res;
122 }
123
124 uint32_t HELPER(sub_saturate)(uint32_t a, uint32_t b)
125 {
126     uint32_t res = a - b;
127     if (((res ^ a) & SIGNBIT) && ((a ^ b) & SIGNBIT)) {
128         env->QF = 1;
129         res = ~(((int32_t)a >> 31) ^ SIGNBIT);
130     }
131     return res;
132 }
133
134 uint32_t HELPER(double_saturate)(int32_t val)
135 {
136     uint32_t res;
137     if (val >= 0x40000000) {
138         res = ~SIGNBIT;
139         env->QF = 1;
140     } else if (val <= (int32_t)0xc0000000) {
141         res = SIGNBIT;
142         env->QF = 1;
143     } else {
144         res = val << 1;
145     }
146     return res;
147 }
148
149 uint32_t HELPER(add_usaturate)(uint32_t a, uint32_t b)
150 {
151     uint32_t res = a + b;
152     if (res < a) {
153         env->QF = 1;
154         res = ~0;
155     }
156     return res;
157 }
158
159 uint32_t HELPER(sub_usaturate)(uint32_t a, uint32_t b)
160 {
161     uint32_t res = a - b;
162     if (res > a) {
163         env->QF = 1;
164         res = 0;
165     }
166     return res;
167 }
168
169 /* Signed saturation.  */
170 static inline uint32_t do_ssat(int32_t val, int shift)
171 {
172     int32_t top;
173     uint32_t mask;
174
175     top = val >> shift;
176     mask = (1u << shift) - 1;
177     if (top > 0) {
178         env->QF = 1;
179         return mask;
180     } else if (top < -1) {
181         env->QF = 1;
182         return ~mask;
183     }
184     return val;
185 }
186
187 /* Unsigned saturation.  */
188 static inline uint32_t do_usat(int32_t val, int shift)
189 {
190     uint32_t max;
191
192     max = (1u << shift) - 1;
193     if (val < 0) {
194         env->QF = 1;
195         return 0;
196     } else if (val > max) {
197         env->QF = 1;
198         return max;
199     }
200     return val;
201 }
202
203 /* Signed saturate.  */
204 uint32_t HELPER(ssat)(uint32_t x, uint32_t shift)
205 {
206     return do_ssat(x, shift);
207 }
208
209 /* Dual halfword signed saturate.  */
210 uint32_t HELPER(ssat16)(uint32_t x, uint32_t shift)
211 {
212     uint32_t res;
213
214     res = (uint16_t)do_ssat((int16_t)x, shift);
215     res |= do_ssat(((int32_t)x) >> 16, shift) << 16;
216     return res;
217 }
218
219 /* Unsigned saturate.  */
220 uint32_t HELPER(usat)(uint32_t x, uint32_t shift)
221 {
222     return do_usat(x, shift);
223 }
224
225 /* Dual halfword unsigned saturate.  */
226 uint32_t HELPER(usat16)(uint32_t x, uint32_t shift)
227 {
228     uint32_t res;
229
230     res = (uint16_t)do_usat((int16_t)x, shift);
231     res |= do_usat(((int32_t)x) >> 16, shift) << 16;
232     return res;
233 }
234
235 void HELPER(wfi)(void)
236 {
237     env->exception_index = EXCP_HLT;
238     env->halted = 1;
239     cpu_loop_exit(env);
240 }
241
242 void HELPER(exception)(uint32_t excp)
243 {
244     env->exception_index = excp;
245     cpu_loop_exit(env);
246 }
247
248 uint32_t HELPER(cpsr_read)(void)
249 {
250     return cpsr_read(env) & ~CPSR_EXEC;
251 }
252
253 void HELPER(cpsr_write)(uint32_t val, uint32_t mask)
254 {
255     cpsr_write(env, val, mask);
256 }
257
258 /* Access to user mode registers from privileged modes.  */
259 uint32_t HELPER(get_user_reg)(uint32_t regno)
260 {
261     uint32_t val;
262
263     if (regno == 13) {
264         val = env->banked_r13[0];
265     } else if (regno == 14) {
266         val = env->banked_r14[0];
267     } else if (regno >= 8
268                && (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) {
269         val = env->usr_regs[regno - 8];
270     } else {
271         val = env->regs[regno];
272     }
273     return val;
274 }
275
276 void HELPER(set_user_reg)(uint32_t regno, uint32_t val)
277 {
278     if (regno == 13) {
279         env->banked_r13[0] = val;
280     } else if (regno == 14) {
281         env->banked_r14[0] = val;
282     } else if (regno >= 8
283                && (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) {
284         env->usr_regs[regno - 8] = val;
285     } else {
286         env->regs[regno] = val;
287     }
288 }
289
290 /* ??? Flag setting arithmetic is awkward because we need to do comparisons.
291    The only way to do that in TCG is a conditional branch, which clobbers
292    all our temporaries.  For now implement these as helper functions.  */
293
294 uint32_t HELPER (add_cc)(uint32_t a, uint32_t b)
295 {
296     uint32_t result;
297     result = a + b;
298     env->NF = env->ZF = result;
299     env->CF = result < a;
300     env->VF = (a ^ b ^ -1) & (a ^ result);
301     return result;
302 }
303
304 uint32_t HELPER(adc_cc)(uint32_t a, uint32_t b)
305 {
306     uint32_t result;
307     if (!env->CF) {
308         result = a + b;
309         env->CF = result < a;
310     } else {
311         result = a + b + 1;
312         env->CF = result <= a;
313     }
314     env->VF = (a ^ b ^ -1) & (a ^ result);
315     env->NF = env->ZF = result;
316     return result;
317 }
318
319 uint32_t HELPER(sub_cc)(uint32_t a, uint32_t b)
320 {
321     uint32_t result;
322     result = a - b;
323     env->NF = env->ZF = result;
324     env->CF = a >= b;
325     env->VF = (a ^ b) & (a ^ result);
326     return result;
327 }
328
329 uint32_t HELPER(sbc_cc)(uint32_t a, uint32_t b)
330 {
331     uint32_t result;
332     if (!env->CF) {
333         result = a - b - 1;
334         env->CF = a > b;
335     } else {
336         result = a - b;
337         env->CF = a >= b;
338     }
339     env->VF = (a ^ b) & (a ^ result);
340     env->NF = env->ZF = result;
341     return result;
342 }
343
344 /* Similarly for variable shift instructions.  */
345
346 uint32_t HELPER(shl)(uint32_t x, uint32_t i)
347 {
348     int shift = i & 0xff;
349     if (shift >= 32)
350         return 0;
351     return x << shift;
352 }
353
354 uint32_t HELPER(shr)(uint32_t x, uint32_t i)
355 {
356     int shift = i & 0xff;
357     if (shift >= 32)
358         return 0;
359     return (uint32_t)x >> shift;
360 }
361
362 uint32_t HELPER(sar)(uint32_t x, uint32_t i)
363 {
364     int shift = i & 0xff;
365     if (shift >= 32)
366         shift = 31;
367     return (int32_t)x >> shift;
368 }
369
370 uint32_t HELPER(shl_cc)(uint32_t x, uint32_t i)
371 {
372     int shift = i & 0xff;
373     if (shift >= 32) {
374         if (shift == 32)
375             env->CF = x & 1;
376         else
377             env->CF = 0;
378         return 0;
379     } else if (shift != 0) {
380         env->CF = (x >> (32 - shift)) & 1;
381         return x << shift;
382     }
383     return x;
384 }
385
386 uint32_t HELPER(shr_cc)(uint32_t x, uint32_t i)
387 {
388     int shift = i & 0xff;
389     if (shift >= 32) {
390         if (shift == 32)
391             env->CF = (x >> 31) & 1;
392         else
393             env->CF = 0;
394         return 0;
395     } else if (shift != 0) {
396         env->CF = (x >> (shift - 1)) & 1;
397         return x >> shift;
398     }
399     return x;
400 }
401
402 uint32_t HELPER(sar_cc)(uint32_t x, uint32_t i)
403 {
404     int shift = i & 0xff;
405     if (shift >= 32) {
406         env->CF = (x >> 31) & 1;
407         return (int32_t)x >> 31;
408     } else if (shift != 0) {
409         env->CF = (x >> (shift - 1)) & 1;
410         return (int32_t)x >> shift;
411     }
412     return x;
413 }
414
415 uint32_t HELPER(ror_cc)(uint32_t x, uint32_t i)
416 {
417     int shift1, shift;
418     shift1 = i & 0xff;
419     shift = shift1 & 0x1f;
420     if (shift == 0) {
421         if (shift1 != 0)
422             env->CF = (x >> 31) & 1;
423         return x;
424     } else {
425         env->CF = (x >> (shift - 1)) & 1;
426         return ((uint32_t)x >> shift) | (x << (32 - shift));
427     }
428 }
This page took 0.050287 seconds and 4 git commands to generate.