ARM TCG conversion 10/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 void helper_neon_tbl(int rn, int maxindex)
44 {
45     uint32_t val;
46     uint32_t mask;
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     mask = 0;
54     for (shift = 0; shift < 32; shift += 8) {
55         index = (T1 >> shift) & 0xff;
56         if (index <= maxindex) {
57             tmp = (table[index >> 3] >> (index & 7)) & 0xff;
58             val |= tmp << shift;
59         } else {
60             val |= T0 & (0xff << shift);
61         }
62     }
63     T0 = val;
64 }
65
66 #if !defined(CONFIG_USER_ONLY)
67
68 #define MMUSUFFIX _mmu
69 #ifdef __s390__
70 # define GETPC() ((void*)((unsigned long)__builtin_return_address(0) & 0x7fffffffUL))
71 #else
72 # define GETPC() (__builtin_return_address(0))
73 #endif
74
75 #define SHIFT 0
76 #include "softmmu_template.h"
77
78 #define SHIFT 1
79 #include "softmmu_template.h"
80
81 #define SHIFT 2
82 #include "softmmu_template.h"
83
84 #define SHIFT 3
85 #include "softmmu_template.h"
86
87 /* try to fill the TLB and return an exception if error. If retaddr is
88    NULL, it means that the function was called in C code (i.e. not
89    from generated code or from helper.c) */
90 /* XXX: fix it to restore all registers */
91 void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
92 {
93     TranslationBlock *tb;
94     CPUState *saved_env;
95     unsigned long pc;
96     int ret;
97
98     /* XXX: hack to restore env in all cases, even if not called from
99        generated code */
100     saved_env = env;
101     env = cpu_single_env;
102     ret = cpu_arm_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
103     if (__builtin_expect(ret, 0)) {
104         if (retaddr) {
105             /* now we have a real cpu fault */
106             pc = (unsigned long)retaddr;
107             tb = tb_find_pc(pc);
108             if (tb) {
109                 /* the PC is inside the translated code. It means that we have
110                    a virtual CPU fault */
111                 cpu_restore_state(tb, env, pc, NULL);
112             }
113         }
114         raise_exception(env->exception_index);
115     }
116     env = saved_env;
117 }
118 #endif
119
120 #define SIGNBIT (uint32_t)0x80000000
121 uint32_t HELPER(add_setq)(uint32_t a, uint32_t b)
122 {
123     uint32_t res = a + b;
124     if (((res ^ a) & SIGNBIT) && !((a ^ b) & SIGNBIT))
125         env->QF = 1;
126     return res;
127 }
128
129 uint32_t HELPER(add_saturate)(uint32_t a, uint32_t b)
130 {
131     uint32_t res = a + b;
132     if (((res ^ a) & SIGNBIT) && !((a ^ b) & SIGNBIT)) {
133         env->QF = 1;
134         res = ~(((int32_t)a >> 31) ^ SIGNBIT);
135     }
136     return res;
137 }
138
139 uint32_t HELPER(sub_saturate)(uint32_t a, uint32_t b)
140 {
141     uint32_t res = a - b;
142     if (((res ^ a) & SIGNBIT) && ((a ^ b) & SIGNBIT)) {
143         env->QF = 1;
144         res = ~(((int32_t)a >> 31) ^ SIGNBIT);
145     }
146     return res;
147 }
148
149 uint32_t HELPER(double_saturate)(int32_t val)
150 {
151     uint32_t res;
152     if (val >= 0x40000000) {
153         res = ~SIGNBIT;
154         env->QF = 1;
155     } else if (val <= (int32_t)0xc0000000) {
156         res = SIGNBIT;
157         env->QF = 1;
158     } else {
159         res = val << 1;
160     }
161     return res;
162 }
163
164 uint32_t HELPER(add_usaturate)(uint32_t a, uint32_t b)
165 {
166     uint32_t res = a + b;
167     if (res < a) {
168         env->QF = 1;
169         res = ~0;
170     }
171     return res;
172 }
173
174 uint32_t HELPER(sub_usaturate)(uint32_t a, uint32_t b)
175 {
176     uint32_t res = a - b;
177     if (res > a) {
178         env->QF = 1;
179         res = 0;
180     }
181     return res;
182 }
183
184 /* Signed saturation.  */
185 static inline uint32_t do_ssat(int32_t val, int shift)
186 {
187     int32_t top;
188     uint32_t mask;
189
190     shift = PARAM1;
191     top = val >> shift;
192     mask = (1u << shift) - 1;
193     if (top > 0) {
194         env->QF = 1;
195         return mask;
196     } else if (top < -1) {
197         env->QF = 1;
198         return ~mask;
199     }
200     return val;
201 }
202
203 /* Unsigned saturation.  */
204 static inline uint32_t do_usat(int32_t val, int shift)
205 {
206     uint32_t max;
207
208     shift = PARAM1;
209     max = (1u << shift) - 1;
210     if (val < 0) {
211         env->QF = 1;
212         return 0;
213     } else if (val > max) {
214         env->QF = 1;
215         return max;
216     }
217     return val;
218 }
219
220 /* Signed saturate.  */
221 uint32_t HELPER(ssat)(uint32_t x, uint32_t shift)
222 {
223     return do_ssat(x, shift);
224 }
225
226 /* Dual halfword signed saturate.  */
227 uint32_t HELPER(ssat16)(uint32_t x, uint32_t shift)
228 {
229     uint32_t res;
230
231     res = (uint16_t)do_ssat((int16_t)x, shift);
232     res |= do_ssat(((int32_t)x) >> 16, shift) << 16;
233     return res;
234 }
235
236 /* Unsigned saturate.  */
237 uint32_t HELPER(usat)(uint32_t x, uint32_t shift)
238 {
239     return do_usat(x, shift);
240 }
241
242 /* Dual halfword unsigned saturate.  */
243 uint32_t HELPER(usat16)(uint32_t x, uint32_t shift)
244 {
245     uint32_t res;
246
247     res = (uint16_t)do_usat((int16_t)x, shift);
248     res |= do_usat(((int32_t)x) >> 16, shift) << 16;
249     return res;
250 }
251
252 void HELPER(wfi)(void)
253 {
254     env->exception_index = EXCP_HLT;
255     env->halted = 1;
256     cpu_loop_exit();
257 }
258
259 void HELPER(exception)(uint32_t excp)
260 {
261     env->exception_index = excp;
262     cpu_loop_exit();
263 }
264
265 uint32_t HELPER(cpsr_read)(void)
266 {
267     return cpsr_read(env) & ~CPSR_EXEC;
268 }
269
270 void HELPER(cpsr_write)(uint32_t val, uint32_t mask)
271 {
272     cpsr_write(env, val, mask);
273 }
274
275 /* Access to user mode registers from privileged modes.  */
276 uint32_t HELPER(get_user_reg)(uint32_t regno)
277 {
278     uint32_t val;
279
280     if (regno == 13) {
281         val = env->banked_r13[0];
282     } else if (regno == 14) {
283         val = env->banked_r14[0];
284     } else if (regno >= 8
285                && (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) {
286         val = env->usr_regs[regno - 8];
287     } else {
288         val = env->regs[regno];
289     }
290     return val;
291 }
292
293 void HELPER(set_user_reg)(uint32_t regno, uint32_t val)
294 {
295     if (regno == 13) {
296         env->banked_r13[0] = val;
297     } else if (regno == 14) {
298         env->banked_r14[0] = val;
299     } else if (regno >= 8
300                && (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) {
301         env->usr_regs[regno - 8] = val;
302     } else {
303         env->regs[regno] = val;
304     }
305 }
306