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 "tcg.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)
raise_exception(CPUARMState * env,int tt)27 static void raise_exception(CPUARMState *env, int tt)
28 {
29 env->exception_index = tt;
30 cpu_loop_exit(env);
31 }
32 #endif
33
HELPER(neon_tbl)34 uint32_t HELPER(neon_tbl)(CPUARMState *env, 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 #undef env
57
58 #if !defined(CONFIG_USER_ONLY)
59
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) */
tlb_fill(CPUARMState * env,target_ulong addr,int is_write,int mmu_idx,uintptr_t retaddr)78 void tlb_fill(CPUARMState *env, target_ulong addr, int is_write, int mmu_idx,
79 uintptr_t retaddr)
80 {
81 int ret;
82
83 ret = cpu_arm_handle_mmu_fault(env, addr, is_write, mmu_idx);
84 if (unlikely(ret)) {
85 if (retaddr) {
86 /* now we have a real cpu fault */
87 cpu_restore_state(env, retaddr);
88 }
89 raise_exception(env, env->exception_index);
90 }
91 }
92
HELPER(set_cp)93 void HELPER(set_cp)(CPUARMState *env, uint32_t insn, uint32_t val)
94 {
95 int cp_num = (insn >> 8) & 0xf;
96 int cp_info = (insn >> 5) & 7;
97 int src = (insn >> 16) & 0xf;
98 int operand = insn & 0xf;
99
100 if (env->cp[cp_num].cp_write)
101 env->cp[cp_num].cp_write(env->cp[cp_num].opaque,
102 cp_info, src, operand, val, (void*)GETPC());
103 }
104
HELPER(get_cp)105 uint32_t HELPER(get_cp)(CPUARMState *env, uint32_t insn)
106 {
107 int cp_num = (insn >> 8) & 0xf;
108 int cp_info = (insn >> 5) & 7;
109 int dest = (insn >> 16) & 0xf;
110 int operand = insn & 0xf;
111
112 if (env->cp[cp_num].cp_read)
113 return env->cp[cp_num].cp_read(env->cp[cp_num].opaque,
114 cp_info, dest, operand, (void*)GETPC());
115 return 0;
116 }
117
118 #else
119
HELPER(set_cp)120 void HELPER(set_cp)(CPUARMState *env, uint32_t insn, uint32_t val)
121 {
122 int op1 = (insn >> 8) & 0xf;
123 cpu_abort(env, "cp%i insn %08x\n", op1, insn);
124 return;
125 }
126
HELPER(get_cp)127 uint32_t HELPER(get_cp)(CPUARMState *env, uint32_t insn)
128 {
129 int op1 = (insn >> 8) & 0xf;
130 cpu_abort(env, "cp%i insn %08x\n", op1, insn);
131 return 0;
132 }
133
134 #endif
135
HELPER(add_setq)136 uint32_t HELPER(add_setq)(CPUARMState *env, uint32_t a, uint32_t b)
137 {
138 uint32_t res = a + b;
139 if (((res ^ a) & SIGNBIT) && !((a ^ b) & SIGNBIT))
140 env->QF = 1;
141 return res;
142 }
143
HELPER(add_saturate)144 uint32_t HELPER(add_saturate)(CPUARMState *env, uint32_t a, uint32_t b)
145 {
146 uint32_t res = a + b;
147 if (((res ^ a) & SIGNBIT) && !((a ^ b) & SIGNBIT)) {
148 env->QF = 1;
149 res = ~(((int32_t)a >> 31) ^ SIGNBIT);
150 }
151 return res;
152 }
153
HELPER(sub_saturate)154 uint32_t HELPER(sub_saturate)(CPUARMState *env, uint32_t a, uint32_t b)
155 {
156 uint32_t res = a - b;
157 if (((res ^ a) & SIGNBIT) && ((a ^ b) & SIGNBIT)) {
158 env->QF = 1;
159 res = ~(((int32_t)a >> 31) ^ SIGNBIT);
160 }
161 return res;
162 }
163
HELPER(double_saturate)164 uint32_t HELPER(double_saturate)(CPUARMState *env, int32_t val)
165 {
166 uint32_t res;
167 if (val >= 0x40000000) {
168 res = ~SIGNBIT;
169 env->QF = 1;
170 } else if (val <= (int32_t)0xc0000000) {
171 res = SIGNBIT;
172 env->QF = 1;
173 } else {
174 res = val << 1;
175 }
176 return res;
177 }
178
HELPER(add_usaturate)179 uint32_t HELPER(add_usaturate)(CPUARMState *env, uint32_t a, uint32_t b)
180 {
181 uint32_t res = a + b;
182 if (res < a) {
183 env->QF = 1;
184 res = ~0;
185 }
186 return res;
187 }
188
HELPER(sub_usaturate)189 uint32_t HELPER(sub_usaturate)(CPUARMState *env, uint32_t a, uint32_t b)
190 {
191 uint32_t res = a - b;
192 if (res > a) {
193 env->QF = 1;
194 res = 0;
195 }
196 return res;
197 }
198
199 /* Signed saturation. */
do_ssat(CPUARMState * env,int32_t val,int shift)200 static inline uint32_t do_ssat(CPUARMState *env, int32_t val, int shift)
201 {
202 int32_t top;
203 uint32_t mask;
204
205 top = val >> shift;
206 mask = (1u << shift) - 1;
207 if (top > 0) {
208 env->QF = 1;
209 return mask;
210 } else if (top < -1) {
211 env->QF = 1;
212 return ~mask;
213 }
214 return val;
215 }
216
217 /* Unsigned saturation. */
do_usat(CPUARMState * env,int32_t val,int shift)218 static inline uint32_t do_usat(CPUARMState *env, int32_t val, int shift)
219 {
220 uint32_t max;
221
222 max = (1u << shift) - 1;
223 if (val < 0) {
224 env->QF = 1;
225 return 0;
226 } else if (val > max) {
227 env->QF = 1;
228 return max;
229 }
230 return val;
231 }
232
233 /* Signed saturate. */
HELPER(ssat)234 uint32_t HELPER(ssat)(CPUARMState *env, uint32_t x, uint32_t shift)
235 {
236 return do_ssat(env, x, shift);
237 }
238
239 /* Dual halfword signed saturate. */
HELPER(ssat16)240 uint32_t HELPER(ssat16)(CPUARMState *env, uint32_t x, uint32_t shift)
241 {
242 uint32_t res;
243
244 res = (uint16_t)do_ssat(env, (int16_t)x, shift);
245 res |= do_ssat(env, ((int32_t)x) >> 16, shift) << 16;
246 return res;
247 }
248
249 /* Unsigned saturate. */
HELPER(usat)250 uint32_t HELPER(usat)(CPUARMState *env, uint32_t x, uint32_t shift)
251 {
252 return do_usat(env, x, shift);
253 }
254
255 /* Dual halfword unsigned saturate. */
HELPER(usat16)256 uint32_t HELPER(usat16)(CPUARMState *env, uint32_t x, uint32_t shift)
257 {
258 uint32_t res;
259
260 res = (uint16_t)do_usat(env, (int16_t)x, shift);
261 res |= do_usat(env, ((int32_t)x) >> 16, shift) << 16;
262 return res;
263 }
264
HELPER(wfi)265 void HELPER(wfi)(CPUARMState *env)
266 {
267 env->exception_index = EXCP_HLT;
268 ENV_GET_CPU(env)->halted = 1;
269 cpu_loop_exit(env);
270 }
271
HELPER(exception)272 void HELPER(exception)(CPUARMState *env, uint32_t excp)
273 {
274 env->exception_index = excp;
275 cpu_loop_exit(env);
276 }
277
HELPER(cpsr_read)278 uint32_t HELPER(cpsr_read)(CPUARMState *env)
279 {
280 return cpsr_read(env) & ~CPSR_EXEC;
281 }
282
HELPER(cpsr_write)283 void HELPER(cpsr_write)(CPUARMState *env, uint32_t val, uint32_t mask)
284 {
285 cpsr_write(env, val, mask);
286 }
287
288 /* Access to user mode registers from privileged modes. */
HELPER(get_user_reg)289 uint32_t HELPER(get_user_reg)(CPUARMState *env, uint32_t regno)
290 {
291 uint32_t val;
292
293 if (regno == 13) {
294 val = env->banked_r13[0];
295 } else if (regno == 14) {
296 val = env->banked_r14[0];
297 } else if (regno >= 8
298 && (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) {
299 val = env->usr_regs[regno - 8];
300 } else {
301 val = env->regs[regno];
302 }
303 return val;
304 }
305
HELPER(set_user_reg)306 void HELPER(set_user_reg)(CPUARMState *env, uint32_t regno, uint32_t val)
307 {
308 if (regno == 13) {
309 env->banked_r13[0] = val;
310 } else if (regno == 14) {
311 env->banked_r14[0] = val;
312 } else if (regno >= 8
313 && (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) {
314 env->usr_regs[regno - 8] = val;
315 } else {
316 env->regs[regno] = val;
317 }
318 }
319
320 /* ??? Flag setting arithmetic is awkward because we need to do comparisons.
321 The only way to do that in TCG is a conditional branch, which clobbers
322 all our temporaries. For now implement these as helper functions. */
323
HELPER(add_cc)324 uint32_t HELPER (add_cc)(CPUARMState *env, uint32_t a, uint32_t b)
325 {
326 uint32_t result;
327 result = a + b;
328 env->NF = env->ZF = result;
329 env->CF = result < a;
330 env->VF = (a ^ b ^ -1) & (a ^ result);
331 return result;
332 }
333
HELPER(adc_cc)334 uint32_t HELPER(adc_cc)(CPUARMState *env, uint32_t a, uint32_t b)
335 {
336 uint32_t result;
337 if (!env->CF) {
338 result = a + b;
339 env->CF = result < a;
340 } else {
341 result = a + b + 1;
342 env->CF = result <= a;
343 }
344 env->VF = (a ^ b ^ -1) & (a ^ result);
345 env->NF = env->ZF = result;
346 return result;
347 }
348
HELPER(sub_cc)349 uint32_t HELPER(sub_cc)(CPUARMState *env, uint32_t a, uint32_t b)
350 {
351 uint32_t result;
352 result = a - b;
353 env->NF = env->ZF = result;
354 env->CF = a >= b;
355 env->VF = (a ^ b) & (a ^ result);
356 return result;
357 }
358
HELPER(sbc_cc)359 uint32_t HELPER(sbc_cc)(CPUARMState *env, uint32_t a, uint32_t b)
360 {
361 uint32_t result;
362 if (!env->CF) {
363 result = a - b - 1;
364 env->CF = a > b;
365 } else {
366 result = a - b;
367 env->CF = a >= b;
368 }
369 env->VF = (a ^ b) & (a ^ result);
370 env->NF = env->ZF = result;
371 return result;
372 }
373
374 /* Similarly for variable shift instructions. */
375
HELPER(shl)376 uint32_t HELPER(shl)(uint32_t x, uint32_t i)
377 {
378 int shift = i & 0xff;
379 if (shift >= 32)
380 return 0;
381 return x << shift;
382 }
383
HELPER(shr)384 uint32_t HELPER(shr)(uint32_t x, uint32_t i)
385 {
386 int shift = i & 0xff;
387 if (shift >= 32)
388 return 0;
389 return (uint32_t)x >> shift;
390 }
391
HELPER(sar)392 uint32_t HELPER(sar)(uint32_t x, uint32_t i)
393 {
394 int shift = i & 0xff;
395 if (shift >= 32)
396 shift = 31;
397 return (int32_t)x >> shift;
398 }
399
HELPER(shl_cc)400 uint32_t HELPER(shl_cc)(CPUARMState *env, uint32_t x, uint32_t i)
401 {
402 int shift = i & 0xff;
403 if (shift >= 32) {
404 if (shift == 32)
405 env->CF = x & 1;
406 else
407 env->CF = 0;
408 return 0;
409 } else if (shift != 0) {
410 env->CF = (x >> (32 - shift)) & 1;
411 return x << shift;
412 }
413 return x;
414 }
415
HELPER(shr_cc)416 uint32_t HELPER(shr_cc)(CPUARMState *env, uint32_t x, uint32_t i)
417 {
418 int shift = i & 0xff;
419 if (shift >= 32) {
420 if (shift == 32)
421 env->CF = (x >> 31) & 1;
422 else
423 env->CF = 0;
424 return 0;
425 } else if (shift != 0) {
426 env->CF = (x >> (shift - 1)) & 1;
427 return x >> shift;
428 }
429 return x;
430 }
431
HELPER(sar_cc)432 uint32_t HELPER(sar_cc)(CPUARMState *env, uint32_t x, uint32_t i)
433 {
434 int shift = i & 0xff;
435 if (shift >= 32) {
436 env->CF = (x >> 31) & 1;
437 return (int32_t)x >> 31;
438 } else if (shift != 0) {
439 env->CF = (x >> (shift - 1)) & 1;
440 return (int32_t)x >> shift;
441 }
442 return x;
443 }
444
HELPER(ror_cc)445 uint32_t HELPER(ror_cc)(CPUARMState *env, uint32_t x, uint32_t i)
446 {
447 int shift1, shift;
448 shift1 = i & 0xff;
449 shift = shift1 & 0x1f;
450 if (shift == 0) {
451 if (shift1 != 0)
452 env->CF = (x >> 31) & 1;
453 return x;
454 } else {
455 env->CF = (x >> (shift - 1)) & 1;
456 return ((uint32_t)x >> shift) | (x << (32 - shift));
457 }
458 }
459
HELPER(neon_vldst_all)460 void HELPER(neon_vldst_all)(CPUARMState *env, uint32_t insn)
461 {
462 #if defined(CONFIG_USER_ONLY)
463 #define LDB(addr) ldub(addr)
464 #define LDW(addr) lduw(addr)
465 #define LDL(addr) ldl(addr)
466 #define LDQ(addr) ldq(addr)
467 #define STB(addr, val) stb(addr, val)
468 #define STW(addr, val) stw(addr, val)
469 #define STL(addr, val) stl(addr, val)
470 #define STQ(addr, val) stq(addr, val)
471 #else
472 int user = cpu_mmu_index(env);
473 #define LDB(addr) helper_ldb_mmu(env, addr, user)
474 #define LDW(addr) helper_le_lduw_mmu(env, addr, user, GETPC())
475 #define LDL(addr) helper_le_ldul_mmu(env, addr, user, GETPC())
476 #define LDQ(addr) helper_le_ldq_mmu(env, addr, user, GETPC())
477 #define STB(addr, val) helper_stb_mmu(env, addr, val, user)
478 #define STW(addr, val) helper_le_stw_mmu(env, addr, val, user, GETPC())
479 #define STL(addr, val) helper_le_stl_mmu(env, addr, val, user, GETPC())
480 #define STQ(addr, val) helper_le_stq_mmu(env, addr, val, user, GETPC())
481 #endif
482 static const struct {
483 int nregs;
484 int interleave;
485 int spacing;
486 } neon_ls_element_type[11] = {
487 {4, 4, 1},
488 {4, 4, 2},
489 {4, 1, 1},
490 {4, 2, 1},
491 {3, 3, 1},
492 {3, 3, 2},
493 {3, 1, 1},
494 {1, 1, 1},
495 {2, 2, 1},
496 {2, 2, 2},
497 {2, 1, 1}
498 };
499
500 const int op = (insn >> 8) & 0xf;
501 const int size = (insn >> 6) & 3;
502 int rd = ((insn >> 12) & 0x0f) | ((insn >> 18) & 0x10);
503 const int rn = (insn >> 16) & 0xf;
504 const int load = (insn & (1 << 21)) != 0;
505 const int nregs = neon_ls_element_type[op].nregs;
506 const int interleave = neon_ls_element_type[op].interleave;
507 const int spacing = neon_ls_element_type[op].spacing;
508 uint32_t addr = env->regs[rn];
509 const int stride = (1 << size) * interleave;
510 int i, reg;
511 uint64_t tmp64;
512
513 for (reg = 0; reg < nregs; reg++) {
514 if (interleave > 2 || (interleave == 2 && nregs == 2)) {
515 addr = env->regs[rn] + (1 << size) * reg;
516 } else if (interleave == 2 && nregs == 4 && reg == 2) {
517 addr = env->regs[rn] + (1 << size);
518 }
519 switch (size) {
520 case 3:
521 if (load) {
522 env->vfp.regs[rd] = make_float64(LDQ(addr));
523 } else {
524 STQ(addr, float64_val(env->vfp.regs[rd]));
525 }
526 addr += stride;
527 break;
528 case 2:
529 if (load) {
530 tmp64 = (uint32_t)LDL(addr);
531 addr += stride;
532 tmp64 |= (uint64_t)LDL(addr) << 32;
533 addr += stride;
534 env->vfp.regs[rd] = make_float64(tmp64);
535 } else {
536 tmp64 = float64_val(env->vfp.regs[rd]);
537 STL(addr, tmp64);
538 addr += stride;
539 STL(addr, tmp64 >> 32);
540 addr += stride;
541 }
542 break;
543 case 1:
544 if (load) {
545 tmp64 = 0ull;
546 for (i = 0; i < 4; i++, addr += stride) {
547 tmp64 |= (uint64_t)LDW(addr) << (i * 16);
548 }
549 env->vfp.regs[rd] = make_float64(tmp64);
550 } else {
551 tmp64 = float64_val(env->vfp.regs[rd]);
552 for (i = 0; i < 4; i++, addr += stride, tmp64 >>= 16) {
553 STW(addr, tmp64);
554 }
555 }
556 break;
557 case 0:
558 if (load) {
559 tmp64 = 0ull;
560 for (i = 0; i < 8; i++, addr += stride) {
561 tmp64 |= (uint64_t)LDB(addr) << (i * 8);
562 }
563 env->vfp.regs[rd] = make_float64(tmp64);
564 } else {
565 tmp64 = float64_val(env->vfp.regs[rd]);
566 for (i = 0; i < 8; i++, addr += stride, tmp64 >>= 8) {
567 STB(addr, tmp64);
568 }
569 }
570 break;
571 }
572 rd += spacing;
573 }
574 #undef LDB
575 #undef LDW
576 #undef LDL
577 #undef LDQ
578 #undef STB
579 #undef STW
580 #undef STL
581 #undef STQ
582 }
583