ARM TCG conversion 13/16.
[qemu] / 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, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 #include "exec.h"
21 #include "helpers.h"
22
23 void raise_exception(int tt)
24 {
25     env->exception_index = tt;
26     cpu_loop_exit();
27 }
28
29 /* thread support */
30
31 spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
32
33 void cpu_lock(void)
34 {
35     spin_lock(&global_cpu_lock);
36 }
37
38 void cpu_unlock(void)
39 {
40     spin_unlock(&global_cpu_lock);
41 }
42
43 uint32_t HELPER(neon_tbl)(uint32_t ireg, uint32_t def,
44                           uint32_t rn, uint32_t maxindex)
45 {
46     uint32_t val;
47     uint32_t tmp;
48     int index;
49     int shift;
50     uint64_t *table;
51     table = (uint64_t *)&env->vfp.regs[rn];
52     val = 0;
53     for (shift = 0; shift < 32; shift += 8) {
54         index = (ireg >> shift) & 0xff;
55         if (index < maxindex) {
56             tmp = (table[index >> 3] >> (index & 7)) & 0xff;
57             val |= tmp << shift;
58         } else {
59             val |= def & (0xff << shift);
60         }
61     }
62     return val;
63 }
64
65 #if !defined(CONFIG_USER_ONLY)
66
67 #define MMUSUFFIX _mmu
68 #ifdef __s390__
69 # define GETPC() ((void*)((unsigned long)__builtin_return_address(0) & 0x7fffffffUL))
70 #else
71 # define GETPC() (__builtin_return_address(0))
72 #endif
73
74 #define SHIFT 0
75 #include "softmmu_template.h"
76
77 #define SHIFT 1
78 #include "softmmu_template.h"
79
80 #define SHIFT 2
81 #include "softmmu_template.h"
82
83 #define SHIFT 3
84 #include "softmmu_template.h"
85
86 /* try to fill the TLB and return an exception if error. If retaddr is
87    NULL, it means that the function was called in C code (i.e. not
88    from generated code or from helper.c) */
89 /* XXX: fix it to restore all registers */
90 void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
91 {
92     TranslationBlock *tb;
93     CPUState *saved_env;
94     unsigned long pc;
95     int ret;
96
97     /* XXX: hack to restore env in all cases, even if not called from
98        generated code */
99     saved_env = env;
100     env = cpu_single_env;
101     ret = cpu_arm_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
102     if (__builtin_expect(ret, 0)) {
103         if (retaddr) {
104             /* now we have a real cpu fault */
105             pc = (unsigned long)retaddr;
106             tb = tb_find_pc(pc);
107             if (tb) {
108                 /* the PC is inside the translated code. It means that we have
109                    a virtual CPU fault */
110                 cpu_restore_state(tb, env, pc, NULL);
111             }
112         }
113         raise_exception(env->exception_index);
114     }
115     env = saved_env;
116 }
117 #endif
118
119 #define SIGNBIT (uint32_t)0x80000000
120 uint32_t HELPER(add_setq)(uint32_t a, uint32_t b)
121 {
122     uint32_t res = a + b;
123     if (((res ^ a) & SIGNBIT) && !((a ^ b) & SIGNBIT))
124         env->QF = 1;
125     return res;
126 }
127
128 uint32_t HELPER(add_saturate)(uint32_t a, uint32_t b)
129 {
130     uint32_t res = a + b;
131     if (((res ^ a) & SIGNBIT) && !((a ^ b) & SIGNBIT)) {
132         env->QF = 1;
133         res = ~(((int32_t)a >> 31) ^ SIGNBIT);
134     }
135     return res;
136 }
137
138 uint32_t HELPER(sub_saturate)(uint32_t a, uint32_t b)
139 {
140     uint32_t res = a - b;
141     if (((res ^ a) & SIGNBIT) && ((a ^ b) & SIGNBIT)) {
142         env->QF = 1;
143         res = ~(((int32_t)a >> 31) ^ SIGNBIT);
144     }
145     return res;
146 }
147
148 uint32_t HELPER(double_saturate)(int32_t val)
149 {
150     uint32_t res;
151     if (val >= 0x40000000) {
152         res = ~SIGNBIT;
153         env->QF = 1;
154     } else if (val <= (int32_t)0xc0000000) {
155         res = SIGNBIT;
156         env->QF = 1;
157     } else {
158         res = val << 1;
159     }
160     return res;
161 }
162
163 uint32_t HELPER(add_usaturate)(uint32_t a, uint32_t b)
164 {
165     uint32_t res = a + b;
166     if (res < a) {
167         env->QF = 1;
168         res = ~0;
169     }
170     return res;
171 }
172
173 uint32_t HELPER(sub_usaturate)(uint32_t a, uint32_t b)
174 {
175     uint32_t res = a - b;
176     if (res > a) {
177         env->QF = 1;
178         res = 0;
179     }
180     return res;
181 }
182
183 /* Signed saturation.  */
184 static inline uint32_t do_ssat(int32_t val, int shift)
185 {
186     int32_t top;
187     uint32_t mask;
188
189     shift = PARAM1;
190     top = val >> shift;
191     mask = (1u << shift) - 1;
192     if (top > 0) {
193         env->QF = 1;
194         return mask;
195     } else if (top < -1) {
196         env->QF = 1;
197         return ~mask;
198     }
199     return val;
200 }
201
202 /* Unsigned saturation.  */
203 static inline uint32_t do_usat(int32_t val, int shift)
204 {
205     uint32_t max;
206
207     shift = PARAM1;
208     max = (1u << shift) - 1;
209     if (val < 0) {
210         env->QF = 1;
211         return 0;
212     } else if (val > max) {
213         env->QF = 1;
214         return max;
215     }
216     return val;
217 }
218
219 /* Signed saturate.  */
220 uint32_t HELPER(ssat)(uint32_t x, uint32_t shift)
221 {
222     return do_ssat(x, shift);
223 }
224
225 /* Dual halfword signed saturate.  */
226 uint32_t HELPER(ssat16)(uint32_t x, uint32_t shift)
227 {
228     uint32_t res;
229
230     res = (uint16_t)do_ssat((int16_t)x, shift);
231     res |= do_ssat(((int32_t)x) >> 16, shift) << 16;
232     return res;
233 }
234
235 /* Unsigned saturate.  */
236 uint32_t HELPER(usat)(uint32_t x, uint32_t shift)
237 {
238     return do_usat(x, shift);
239 }
240
241 /* Dual halfword unsigned saturate.  */
242 uint32_t HELPER(usat16)(uint32_t x, uint32_t shift)
243 {
244     uint32_t res;
245
246     res = (uint16_t)do_usat((int16_t)x, shift);
247     res |= do_usat(((int32_t)x) >> 16, shift) << 16;
248     return res;
249 }
250
251 void HELPER(wfi)(void)
252 {
253     env->exception_index = EXCP_HLT;
254     env->halted = 1;
255     cpu_loop_exit();
256 }
257
258 void HELPER(exception)(uint32_t excp)
259 {
260     env->exception_index = excp;
261     cpu_loop_exit();
262 }
263
264 uint32_t HELPER(cpsr_read)(void)
265 {
266     return cpsr_read(env) & ~CPSR_EXEC;
267 }
268
269 void HELPER(cpsr_write)(uint32_t val, uint32_t mask)
270 {
271     cpsr_write(env, val, mask);
272 }
273
274 /* Access to user mode registers from privileged modes.  */
275 uint32_t HELPER(get_user_reg)(uint32_t regno)
276 {
277     uint32_t val;
278
279     if (regno == 13) {
280         val = env->banked_r13[0];
281     } else if (regno == 14) {
282         val = env->banked_r14[0];
283     } else if (regno >= 8
284                && (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) {
285         val = env->usr_regs[regno - 8];
286     } else {
287         val = env->regs[regno];
288     }
289     return val;
290 }
291
292 void HELPER(set_user_reg)(uint32_t regno, uint32_t val)
293 {
294     if (regno == 13) {
295         env->banked_r13[0] = val;
296     } else if (regno == 14) {
297         env->banked_r14[0] = val;
298     } else if (regno >= 8
299                && (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) {
300         env->usr_regs[regno - 8] = val;
301     } else {
302         env->regs[regno] = val;
303     }
304 }
305
306 /* ??? Flag setting arithmetic is awkward because we need to do comparisons.
307    The only way to do that in TCG is a conditional branch, which clobbers
308    all our temporaries.  For now implement these as helper functions.  */
309
310 uint32_t HELPER (add_cc)(uint32_t a, uint32_t b)
311 {
312     uint32_t result;
313     result = T0 + T1;
314     env->NZF = result;
315     env->CF = result < a;
316     env->VF = (a ^ b ^ -1) & (a ^ result);
317     return result;
318 }
319
320 uint32_t HELPER(adc_cc)(uint32_t a, uint32_t b)
321 {
322     uint32_t result;
323     if (!env->CF) {
324         result = a + b;
325         env->CF = result < a;
326     } else {
327         result = a + b + 1;
328         env->CF = result <= a;
329     }
330     env->VF = (a ^ b ^ -1) & (a ^ result);
331     env->NZF = result;
332     return result;
333 }
334
335 uint32_t HELPER(sub_cc)(uint32_t a, uint32_t b)
336 {
337     uint32_t result;
338     result = a - b;
339     env->NZF = result;
340     env->CF = a >= b;
341     env->VF = (a ^ b) & (a ^ result);
342     return result;
343 }
344
345 uint32_t HELPER(sbc_cc)(uint32_t a, uint32_t b)
346 {
347     uint32_t result;
348     if (!env->CF) {
349         result = a - b - 1;
350         env->CF = a > b;
351     } else {
352         result = a - b;
353         env->CF = a >= b;
354     }
355     env->VF = (a ^ b) & (a ^ result);
356     env->NZF = result;
357     return result;
358 }
359
360 /* Similarly for variable shift instructions.  */
361
362 uint32_t HELPER(shl)(uint32_t x, uint32_t i)
363 {
364     int shift = i & 0xff;
365     if (shift >= 32)
366         return 0;
367     return x << shift;
368 }
369
370 uint32_t HELPER(shr)(uint32_t x, uint32_t i)
371 {
372     int shift = i & 0xff;
373     if (shift >= 32)
374         return 0;
375     return (uint32_t)x >> shift;
376 }
377
378 uint32_t HELPER(sar)(uint32_t x, uint32_t i)
379 {
380     int shift = i & 0xff;
381     if (shift >= 32)
382         shift = 31;
383     return (int32_t)x >> shift;
384 }
385
386 uint32_t HELPER(ror)(uint32_t x, uint32_t i)
387 {
388     int shift = i & 0xff;
389     if (shift == 0)
390         return x;
391     return (x >> shift) | (x << (32 - shift));
392 }
393
394 uint32_t HELPER(shl_cc)(uint32_t x, uint32_t i)
395 {
396     int shift = i & 0xff;
397     if (shift >= 32) {
398         if (shift == 32)
399             env->CF = x & 1;
400         else
401             env->CF = 0;
402         return 0;
403     } else if (shift != 0) {
404         env->CF = (x >> (32 - shift)) & 1;
405         return x << shift;
406     }
407     return x;
408 }
409
410 uint32_t HELPER(shr_cc)(uint32_t x, uint32_t i)
411 {
412     int shift = i & 0xff;
413     if (shift >= 32) {
414         if (shift == 32)
415             env->CF = (x >> 31) & 1;
416         else
417             env->CF = 0;
418         return 0;
419     } else if (shift != 0) {
420         env->CF = (x >> (shift - 1)) & 1;
421         return x >> shift;
422     }
423     return x;
424 }
425
426 uint32_t HELPER(sar_cc)(uint32_t x, uint32_t i)
427 {
428     int shift = i & 0xff;
429     if (shift >= 32) {
430         env->CF = (x >> 31) & 1;
431         return (int32_t)x >> 31;
432     } else if (shift != 0) {
433         env->CF = (x >> (shift - 1)) & 1;
434         return (int32_t)x >> shift;
435     }
436     return x;
437 }
438
439 uint32_t HELPER(ror_cc)(uint32_t x, uint32_t i)
440 {
441     int shift1, shift;
442     shift1 = i & 0xff;
443     shift = shift1 & 0x1f;
444     if (shift == 0) {
445         if (shift1 != 0)
446             env->CF = (x >> 31) & 1;
447         return x;
448     } else {
449         env->CF = (x >> (shift - 1)) & 1;
450         return ((uint32_t)x >> shift) | (x << (32 - shift));
451     }
452 }
453