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