blob: fe40358c9690c9fbe1d0e8622d2a586d7b866c9a [file] [log] [blame]
bellardb7bcbe92005-02-22 19:27:29 +00001/*
2 * ARM helper routines
ths5fafdf22007-09-16 21:08:06 +00003 *
pbrook9ee6e8b2007-11-11 00:04:49 +00004 * Copyright (c) 2005-2007 CodeSourcery, LLC
bellardb7bcbe92005-02-22 19:27:29 +00005 *
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
Blue Swirl8167ee82009-07-16 20:47:01 +000017 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
bellardb7bcbe92005-02-22 19:27:29 +000018 */
Blue Swirl3e457172011-07-13 12:44:15 +000019#include "cpu.h"
Richard Henderson2ef61752014-04-07 22:31:41 -070020#include "exec/helper-proto.h"
Peter Maydellccd38082014-04-15 19:18:37 +010021#include "internals.h"
Paolo Bonzinif08b6172014-03-28 19:42:10 +010022#include "exec/cpu_ldst.h"
bellardb7bcbe92005-02-22 19:27:29 +000023
pbrookad694712008-03-31 03:48:30 +000024#define SIGNBIT (uint32_t)0x80000000
25#define SIGNBIT64 ((uint64_t)1 << 63)
26
Blue Swirl1ce94f82012-09-04 20:08:34 +000027static void raise_exception(CPUARMState *env, int tt)
bellardb7bcbe92005-02-22 19:27:29 +000028{
Andreas Färber27103422013-08-26 08:31:06 +020029 ARMCPU *cpu = arm_env_get_cpu(env);
30 CPUState *cs = CPU(cpu);
31
32 cs->exception_index = tt;
Andreas Färber5638d182013-08-27 17:52:12 +020033 cpu_loop_exit(cs);
bellardb7bcbe92005-02-22 19:27:29 +000034}
35
Blue Swirl9ef39272012-09-04 20:19:15 +000036uint32_t HELPER(neon_tbl)(CPUARMState *env, uint32_t ireg, uint32_t def,
pbrook8f8e3aa2008-03-31 03:48:01 +000037 uint32_t rn, uint32_t maxindex)
pbrook9ee6e8b2007-11-11 00:04:49 +000038{
39 uint32_t val;
pbrook9ee6e8b2007-11-11 00:04:49 +000040 uint32_t tmp;
41 int index;
42 int shift;
43 uint64_t *table;
44 table = (uint64_t *)&env->vfp.regs[rn];
45 val = 0;
pbrook9ee6e8b2007-11-11 00:04:49 +000046 for (shift = 0; shift < 32; shift += 8) {
pbrook8f8e3aa2008-03-31 03:48:01 +000047 index = (ireg >> shift) & 0xff;
48 if (index < maxindex) {
pbrook3018f252008-09-22 00:52:42 +000049 tmp = (table[index >> 3] >> ((index & 7) << 3)) & 0xff;
pbrook9ee6e8b2007-11-11 00:04:49 +000050 val |= tmp << shift;
51 } else {
pbrook8f8e3aa2008-03-31 03:48:01 +000052 val |= def & (0xff << shift);
pbrook9ee6e8b2007-11-11 00:04:49 +000053 }
54 }
pbrook8f8e3aa2008-03-31 03:48:01 +000055 return val;
pbrook9ee6e8b2007-11-11 00:04:49 +000056}
57
bellardb5ff1b32005-11-26 10:38:39 +000058#if !defined(CONFIG_USER_ONLY)
59
bellardb5ff1b32005-11-26 10:38:39 +000060/* try to fill the TLB and return an exception if error. If retaddr is
Andreas Färberd5a11fe2013-08-27 00:28:06 +020061 * NULL, it means that the function was called in C code (i.e. not
62 * from generated code or from helper.c)
63 */
64void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx,
Blue Swirl20503962012-04-09 14:20:20 +000065 uintptr_t retaddr)
bellardb5ff1b32005-11-26 10:38:39 +000066{
bellardb5ff1b32005-11-26 10:38:39 +000067 int ret;
68
Andreas Färber27103422013-08-26 08:31:06 +020069 ret = arm_cpu_handle_mmu_fault(cs, addr, is_write, mmu_idx);
ths551bd272008-07-03 17:57:36 +000070 if (unlikely(ret)) {
Andreas Färberd5a11fe2013-08-27 00:28:06 +020071 ARMCPU *cpu = ARM_CPU(cs);
72 CPUARMState *env = &cpu->env;
73
bellardb5ff1b32005-11-26 10:38:39 +000074 if (retaddr) {
75 /* now we have a real cpu fault */
Andreas Färber3f38f302013-09-01 16:51:34 +020076 cpu_restore_state(cs, retaddr);
bellardb5ff1b32005-11-26 10:38:39 +000077 }
Andreas Färber27103422013-08-26 08:31:06 +020078 raise_exception(env, cs->exception_index);
bellardb5ff1b32005-11-26 10:38:39 +000079 }
bellardb5ff1b32005-11-26 10:38:39 +000080}
bellardb5ff1b32005-11-26 10:38:39 +000081#endif
pbrook1497c962008-03-31 03:45:50 +000082
Blue Swirl9ef39272012-09-04 20:19:15 +000083uint32_t HELPER(add_setq)(CPUARMState *env, uint32_t a, uint32_t b)
pbrook1497c962008-03-31 03:45:50 +000084{
85 uint32_t res = a + b;
86 if (((res ^ a) & SIGNBIT) && !((a ^ b) & SIGNBIT))
87 env->QF = 1;
88 return res;
89}
90
Blue Swirl9ef39272012-09-04 20:19:15 +000091uint32_t HELPER(add_saturate)(CPUARMState *env, uint32_t a, uint32_t b)
pbrook1497c962008-03-31 03:45:50 +000092{
93 uint32_t res = a + b;
94 if (((res ^ a) & SIGNBIT) && !((a ^ b) & SIGNBIT)) {
95 env->QF = 1;
96 res = ~(((int32_t)a >> 31) ^ SIGNBIT);
97 }
98 return res;
99}
100
Blue Swirl9ef39272012-09-04 20:19:15 +0000101uint32_t HELPER(sub_saturate)(CPUARMState *env, uint32_t a, uint32_t b)
pbrook1497c962008-03-31 03:45:50 +0000102{
103 uint32_t res = a - b;
104 if (((res ^ a) & SIGNBIT) && ((a ^ b) & SIGNBIT)) {
105 env->QF = 1;
106 res = ~(((int32_t)a >> 31) ^ SIGNBIT);
107 }
108 return res;
109}
110
Blue Swirl9ef39272012-09-04 20:19:15 +0000111uint32_t HELPER(double_saturate)(CPUARMState *env, int32_t val)
pbrook1497c962008-03-31 03:45:50 +0000112{
113 uint32_t res;
114 if (val >= 0x40000000) {
115 res = ~SIGNBIT;
116 env->QF = 1;
117 } else if (val <= (int32_t)0xc0000000) {
118 res = SIGNBIT;
119 env->QF = 1;
120 } else {
121 res = val << 1;
122 }
123 return res;
124}
125
Blue Swirl9ef39272012-09-04 20:19:15 +0000126uint32_t HELPER(add_usaturate)(CPUARMState *env, uint32_t a, uint32_t b)
pbrook1497c962008-03-31 03:45:50 +0000127{
128 uint32_t res = a + b;
129 if (res < a) {
130 env->QF = 1;
131 res = ~0;
132 }
133 return res;
134}
135
Blue Swirl9ef39272012-09-04 20:19:15 +0000136uint32_t HELPER(sub_usaturate)(CPUARMState *env, uint32_t a, uint32_t b)
pbrook1497c962008-03-31 03:45:50 +0000137{
138 uint32_t res = a - b;
139 if (res > a) {
140 env->QF = 1;
141 res = 0;
142 }
143 return res;
144}
145
pbrook6ddbc6e2008-03-31 03:46:33 +0000146/* Signed saturation. */
Blue Swirl9ef39272012-09-04 20:19:15 +0000147static inline uint32_t do_ssat(CPUARMState *env, int32_t val, int shift)
pbrook6ddbc6e2008-03-31 03:46:33 +0000148{
149 int32_t top;
150 uint32_t mask;
151
pbrook6ddbc6e2008-03-31 03:46:33 +0000152 top = val >> shift;
153 mask = (1u << shift) - 1;
154 if (top > 0) {
155 env->QF = 1;
156 return mask;
157 } else if (top < -1) {
158 env->QF = 1;
159 return ~mask;
160 }
161 return val;
162}
163
164/* Unsigned saturation. */
Blue Swirl9ef39272012-09-04 20:19:15 +0000165static inline uint32_t do_usat(CPUARMState *env, int32_t val, int shift)
pbrook6ddbc6e2008-03-31 03:46:33 +0000166{
167 uint32_t max;
168
pbrook6ddbc6e2008-03-31 03:46:33 +0000169 max = (1u << shift) - 1;
170 if (val < 0) {
171 env->QF = 1;
172 return 0;
173 } else if (val > max) {
174 env->QF = 1;
175 return max;
176 }
177 return val;
178}
179
180/* Signed saturate. */
Blue Swirl9ef39272012-09-04 20:19:15 +0000181uint32_t HELPER(ssat)(CPUARMState *env, uint32_t x, uint32_t shift)
pbrook6ddbc6e2008-03-31 03:46:33 +0000182{
Blue Swirl9ef39272012-09-04 20:19:15 +0000183 return do_ssat(env, x, shift);
pbrook6ddbc6e2008-03-31 03:46:33 +0000184}
185
186/* Dual halfword signed saturate. */
Blue Swirl9ef39272012-09-04 20:19:15 +0000187uint32_t HELPER(ssat16)(CPUARMState *env, uint32_t x, uint32_t shift)
pbrook6ddbc6e2008-03-31 03:46:33 +0000188{
189 uint32_t res;
190
Blue Swirl9ef39272012-09-04 20:19:15 +0000191 res = (uint16_t)do_ssat(env, (int16_t)x, shift);
192 res |= do_ssat(env, ((int32_t)x) >> 16, shift) << 16;
pbrook6ddbc6e2008-03-31 03:46:33 +0000193 return res;
194}
195
196/* Unsigned saturate. */
Blue Swirl9ef39272012-09-04 20:19:15 +0000197uint32_t HELPER(usat)(CPUARMState *env, uint32_t x, uint32_t shift)
pbrook6ddbc6e2008-03-31 03:46:33 +0000198{
Blue Swirl9ef39272012-09-04 20:19:15 +0000199 return do_usat(env, x, shift);
pbrook6ddbc6e2008-03-31 03:46:33 +0000200}
201
202/* Dual halfword unsigned saturate. */
Blue Swirl9ef39272012-09-04 20:19:15 +0000203uint32_t HELPER(usat16)(CPUARMState *env, uint32_t x, uint32_t shift)
pbrook6ddbc6e2008-03-31 03:46:33 +0000204{
205 uint32_t res;
206
Blue Swirl9ef39272012-09-04 20:19:15 +0000207 res = (uint16_t)do_usat(env, (int16_t)x, shift);
208 res |= do_usat(env, ((int32_t)x) >> 16, shift) << 16;
pbrook6ddbc6e2008-03-31 03:46:33 +0000209 return res;
210}
pbrookd9ba4832008-03-31 03:46:50 +0000211
Blue Swirl1ce94f82012-09-04 20:08:34 +0000212void HELPER(wfi)(CPUARMState *env)
pbrookd9ba4832008-03-31 03:46:50 +0000213{
Andreas Färber259186a2013-01-17 18:51:17 +0100214 CPUState *cs = CPU(arm_env_get_cpu(env));
215
Andreas Färber27103422013-08-26 08:31:06 +0200216 cs->exception_index = EXCP_HLT;
Andreas Färber259186a2013-01-17 18:51:17 +0100217 cs->halted = 1;
Andreas Färber5638d182013-08-27 17:52:12 +0200218 cpu_loop_exit(cs);
pbrookd9ba4832008-03-31 03:46:50 +0000219}
220
Peter Maydell72c1d3a2014-03-10 14:56:30 +0000221void HELPER(wfe)(CPUARMState *env)
222{
Andreas Färber27103422013-08-26 08:31:06 +0200223 CPUState *cs = CPU(arm_env_get_cpu(env));
224
Peter Maydell72c1d3a2014-03-10 14:56:30 +0000225 /* Don't actually halt the CPU, just yield back to top
226 * level loop
227 */
Andreas Färber27103422013-08-26 08:31:06 +0200228 cs->exception_index = EXCP_YIELD;
Andreas Färber5638d182013-08-27 17:52:12 +0200229 cpu_loop_exit(cs);
Peter Maydell72c1d3a2014-03-10 14:56:30 +0000230}
231
Peter Maydelld4a2dc62014-04-15 19:18:38 +0100232/* Raise an internal-to-QEMU exception. This is limited to only
233 * those EXCP values which are special cases for QEMU to interrupt
234 * execution and not to be used for exceptions which are passed to
235 * the guest (those must all have syndrome information and thus should
236 * use exception_with_syndrome).
237 */
238void HELPER(exception_internal)(CPUARMState *env, uint32_t excp)
pbrookd9ba4832008-03-31 03:46:50 +0000239{
Andreas Färber27103422013-08-26 08:31:06 +0200240 CPUState *cs = CPU(arm_env_get_cpu(env));
241
Peter Maydelld4a2dc62014-04-15 19:18:38 +0100242 assert(excp_is_internal(excp));
Andreas Färber27103422013-08-26 08:31:06 +0200243 cs->exception_index = excp;
Andreas Färber5638d182013-08-27 17:52:12 +0200244 cpu_loop_exit(cs);
pbrookd9ba4832008-03-31 03:46:50 +0000245}
246
Peter Maydelld4a2dc62014-04-15 19:18:38 +0100247/* Raise an exception with the specified syndrome register value */
248void HELPER(exception_with_syndrome)(CPUARMState *env, uint32_t excp,
249 uint32_t syndrome)
250{
251 CPUState *cs = CPU(arm_env_get_cpu(env));
252
253 assert(!excp_is_internal(excp));
254 cs->exception_index = excp;
255 env->exception.syndrome = syndrome;
256 cpu_loop_exit(cs);
257}
258
Blue Swirl9ef39272012-09-04 20:19:15 +0000259uint32_t HELPER(cpsr_read)(CPUARMState *env)
pbrookd9ba4832008-03-31 03:46:50 +0000260{
Peter Maydell4051e122014-08-19 18:56:26 +0100261 return cpsr_read(env) & ~(CPSR_EXEC | CPSR_RESERVED);
pbrookd9ba4832008-03-31 03:46:50 +0000262}
263
Blue Swirl1ce94f82012-09-04 20:08:34 +0000264void HELPER(cpsr_write)(CPUARMState *env, uint32_t val, uint32_t mask)
pbrookd9ba4832008-03-31 03:46:50 +0000265{
266 cpsr_write(env, val, mask);
267}
pbrookb0109802008-03-31 03:47:03 +0000268
269/* Access to user mode registers from privileged modes. */
Blue Swirl9ef39272012-09-04 20:19:15 +0000270uint32_t HELPER(get_user_reg)(CPUARMState *env, uint32_t regno)
pbrookb0109802008-03-31 03:47:03 +0000271{
272 uint32_t val;
273
274 if (regno == 13) {
275 val = env->banked_r13[0];
276 } else if (regno == 14) {
277 val = env->banked_r14[0];
278 } else if (regno >= 8
279 && (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) {
280 val = env->usr_regs[regno - 8];
281 } else {
282 val = env->regs[regno];
283 }
284 return val;
285}
286
Blue Swirl1ce94f82012-09-04 20:08:34 +0000287void HELPER(set_user_reg)(CPUARMState *env, uint32_t regno, uint32_t val)
pbrookb0109802008-03-31 03:47:03 +0000288{
289 if (regno == 13) {
290 env->banked_r13[0] = val;
291 } else if (regno == 14) {
292 env->banked_r14[0] = val;
293 } else if (regno >= 8
294 && (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) {
295 env->usr_regs[regno - 8] = val;
296 } else {
297 env->regs[regno] = val;
298 }
299}
300
Peter Maydell8bcbf372014-04-15 19:18:38 +0100301void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip, uint32_t syndrome)
Peter Maydellf59df3f2014-02-20 10:35:52 +0000302{
303 const ARMCPRegInfo *ri = rip;
304 switch (ri->accessfn(env, ri)) {
305 case CP_ACCESS_OK:
306 return;
307 case CP_ACCESS_TRAP:
Peter Maydell8bcbf372014-04-15 19:18:38 +0100308 env->exception.syndrome = syndrome;
309 break;
Peter Maydellf59df3f2014-02-20 10:35:52 +0000310 case CP_ACCESS_TRAP_UNCATEGORIZED:
Peter Maydell8bcbf372014-04-15 19:18:38 +0100311 env->exception.syndrome = syn_uncategorized();
Peter Maydellf59df3f2014-02-20 10:35:52 +0000312 break;
313 default:
314 g_assert_not_reached();
315 }
316 raise_exception(env, EXCP_UDEF);
317}
318
Peter Maydell4b6a83f2012-06-20 11:57:06 +0000319void HELPER(set_cp_reg)(CPUARMState *env, void *rip, uint32_t value)
320{
321 const ARMCPRegInfo *ri = rip;
Peter Maydellc4241c72014-02-20 10:35:54 +0000322
323 ri->writefn(env, ri, value);
Peter Maydell4b6a83f2012-06-20 11:57:06 +0000324}
325
326uint32_t HELPER(get_cp_reg)(CPUARMState *env, void *rip)
327{
328 const ARMCPRegInfo *ri = rip;
Peter Maydellc4241c72014-02-20 10:35:54 +0000329
330 return ri->readfn(env, ri);
Peter Maydell4b6a83f2012-06-20 11:57:06 +0000331}
332
333void HELPER(set_cp_reg64)(CPUARMState *env, void *rip, uint64_t value)
334{
335 const ARMCPRegInfo *ri = rip;
Peter Maydellc4241c72014-02-20 10:35:54 +0000336
337 ri->writefn(env, ri, value);
Peter Maydell4b6a83f2012-06-20 11:57:06 +0000338}
339
340uint64_t HELPER(get_cp_reg64)(CPUARMState *env, void *rip)
341{
342 const ARMCPRegInfo *ri = rip;
Peter Maydellc4241c72014-02-20 10:35:54 +0000343
344 return ri->readfn(env, ri);
Peter Maydell4b6a83f2012-06-20 11:57:06 +0000345}
346
Peter Maydell9cfa0b42014-02-26 17:20:06 +0000347void HELPER(msr_i_pstate)(CPUARMState *env, uint32_t op, uint32_t imm)
348{
349 /* MSR_i to update PSTATE. This is OK from EL0 only if UMA is set.
350 * Note that SPSel is never OK from EL0; we rely on handle_msr_i()
351 * to catch that case at translate time.
352 */
353 if (arm_current_pl(env) == 0 && !(env->cp15.c1_sys & SCTLR_UMA)) {
354 raise_exception(env, EXCP_UDEF);
355 }
356
357 switch (op) {
358 case 0x05: /* SPSel */
Peter Maydellf502cfc2014-04-15 19:18:43 +0100359 update_spsel(env, imm);
Peter Maydell9cfa0b42014-02-26 17:20:06 +0000360 break;
361 case 0x1e: /* DAIFSet */
362 env->daif |= (imm << 6) & PSTATE_DAIF;
363 break;
364 case 0x1f: /* DAIFClear */
365 env->daif &= ~((imm << 6) & PSTATE_DAIF);
366 break;
367 default:
368 g_assert_not_reached();
369 }
370}
371
Peter Maydell7ea47fe2014-08-19 18:56:26 +0100372void HELPER(clear_pstate_ss)(CPUARMState *env)
373{
374 env->pstate &= ~PSTATE_SS;
375}
376
Rob Herring52e60cd2014-04-15 19:18:44 +0100377void HELPER(exception_return)(CPUARMState *env)
378{
Edgar E. Iglesiasdb6c3cd2014-05-27 17:09:54 +0100379 int cur_el = arm_current_pl(env);
380 unsigned int spsr_idx = aarch64_banked_spsr_index(cur_el);
Edgar E. Iglesias2a923c42014-05-27 17:09:52 +0100381 uint32_t spsr = env->banked_spsr[spsr_idx];
Rob Herring52e60cd2014-04-15 19:18:44 +0100382 int new_el, i;
383
Edgar E. Iglesias9208b962014-08-04 14:41:54 +0100384 aarch64_save_sp(env, cur_el);
Rob Herring52e60cd2014-04-15 19:18:44 +0100385
386 env->exclusive_addr = -1;
387
Peter Maydell3a298202014-08-19 18:56:26 +0100388 /* We must squash the PSTATE.SS bit to zero unless both of the
389 * following hold:
390 * 1. debug exceptions are currently disabled
391 * 2. singlestep will be active in the EL we return to
392 * We check 1 here and 2 after we've done the pstate/cpsr write() to
393 * transition to the EL we're going to.
394 */
395 if (arm_generate_debug_exceptions(env)) {
396 spsr &= ~PSTATE_SS;
397 }
398
Rob Herring52e60cd2014-04-15 19:18:44 +0100399 if (spsr & PSTATE_nRW) {
Edgar E. Iglesiasdb6c3cd2014-05-27 17:09:54 +0100400 /* TODO: We currently assume EL1/2/3 are running in AArch64. */
Rob Herring52e60cd2014-04-15 19:18:44 +0100401 env->aarch64 = 0;
402 new_el = 0;
403 env->uncached_cpsr = 0x10;
404 cpsr_write(env, spsr, ~0);
Peter Maydell3a298202014-08-19 18:56:26 +0100405 if (!arm_singlestep_active(env)) {
406 env->uncached_cpsr &= ~PSTATE_SS;
407 }
Rob Herring52e60cd2014-04-15 19:18:44 +0100408 for (i = 0; i < 15; i++) {
409 env->regs[i] = env->xregs[i];
410 }
411
Edgar E. Iglesias6947f052014-05-27 17:09:51 +0100412 env->regs[15] = env->elr_el[1] & ~0x1;
Rob Herring52e60cd2014-04-15 19:18:44 +0100413 } else {
414 new_el = extract32(spsr, 2, 2);
Edgar E. Iglesias7ab6c102014-05-27 17:09:53 +0100415 if (new_el > cur_el
416 || (new_el == 2 && !arm_feature(env, ARM_FEATURE_EL2))) {
417 /* Disallow return to an EL which is unimplemented or higher
418 * than the current one.
419 */
Rob Herring52e60cd2014-04-15 19:18:44 +0100420 goto illegal_return;
421 }
422 if (extract32(spsr, 1, 1)) {
423 /* Return with reserved M[1] bit set */
424 goto illegal_return;
425 }
426 if (new_el == 0 && (spsr & PSTATE_SP)) {
Edgar E. Iglesias37f08062014-05-01 15:24:46 +0100427 /* Return to EL0 with M[0] bit set */
Rob Herring52e60cd2014-04-15 19:18:44 +0100428 goto illegal_return;
429 }
430 env->aarch64 = 1;
431 pstate_write(env, spsr);
Peter Maydell3a298202014-08-19 18:56:26 +0100432 if (!arm_singlestep_active(env)) {
433 env->pstate &= ~PSTATE_SS;
434 }
Edgar E. Iglesias98ea5612014-08-04 14:41:54 +0100435 aarch64_restore_sp(env, new_el);
Edgar E. Iglesiasdb6c3cd2014-05-27 17:09:54 +0100436 env->pc = env->elr_el[cur_el];
Rob Herring52e60cd2014-04-15 19:18:44 +0100437 }
438
439 return;
440
441illegal_return:
442 /* Illegal return events of various kinds have architecturally
443 * mandated behaviour:
444 * restore NZCV and DAIF from SPSR_ELx
445 * set PSTATE.IL
446 * restore PC from ELR_ELx
447 * no change to exception level, execution state or stack pointer
448 */
449 env->pstate |= PSTATE_IL;
Edgar E. Iglesiasdb6c3cd2014-05-27 17:09:54 +0100450 env->pc = env->elr_el[cur_el];
Rob Herring52e60cd2014-04-15 19:18:44 +0100451 spsr &= PSTATE_NZCV | PSTATE_DAIF;
452 spsr |= pstate_read(env) & ~(PSTATE_NZCV | PSTATE_DAIF);
453 pstate_write(env, spsr);
Peter Maydell3a298202014-08-19 18:56:26 +0100454 if (!arm_singlestep_active(env)) {
455 env->pstate &= ~PSTATE_SS;
456 }
Rob Herring52e60cd2014-04-15 19:18:44 +0100457}
458
pbrook8984bd22008-03-31 03:47:48 +0000459/* ??? Flag setting arithmetic is awkward because we need to do comparisons.
460 The only way to do that in TCG is a conditional branch, which clobbers
461 all our temporaries. For now implement these as helper functions. */
462
pbrook8984bd22008-03-31 03:47:48 +0000463/* Similarly for variable shift instructions. */
464
Blue Swirl9ef39272012-09-04 20:19:15 +0000465uint32_t HELPER(shl_cc)(CPUARMState *env, uint32_t x, uint32_t i)
pbrook8984bd22008-03-31 03:47:48 +0000466{
467 int shift = i & 0xff;
468 if (shift >= 32) {
469 if (shift == 32)
470 env->CF = x & 1;
471 else
472 env->CF = 0;
473 return 0;
474 } else if (shift != 0) {
475 env->CF = (x >> (32 - shift)) & 1;
476 return x << shift;
477 }
478 return x;
479}
480
Blue Swirl9ef39272012-09-04 20:19:15 +0000481uint32_t HELPER(shr_cc)(CPUARMState *env, uint32_t x, uint32_t i)
pbrook8984bd22008-03-31 03:47:48 +0000482{
483 int shift = i & 0xff;
484 if (shift >= 32) {
485 if (shift == 32)
486 env->CF = (x >> 31) & 1;
487 else
488 env->CF = 0;
489 return 0;
490 } else if (shift != 0) {
491 env->CF = (x >> (shift - 1)) & 1;
492 return x >> shift;
493 }
494 return x;
495}
496
Blue Swirl9ef39272012-09-04 20:19:15 +0000497uint32_t HELPER(sar_cc)(CPUARMState *env, uint32_t x, uint32_t i)
pbrook8984bd22008-03-31 03:47:48 +0000498{
499 int shift = i & 0xff;
500 if (shift >= 32) {
501 env->CF = (x >> 31) & 1;
502 return (int32_t)x >> 31;
503 } else if (shift != 0) {
504 env->CF = (x >> (shift - 1)) & 1;
505 return (int32_t)x >> shift;
506 }
507 return x;
508}
509
Blue Swirl9ef39272012-09-04 20:19:15 +0000510uint32_t HELPER(ror_cc)(CPUARMState *env, uint32_t x, uint32_t i)
pbrook8984bd22008-03-31 03:47:48 +0000511{
512 int shift1, shift;
513 shift1 = i & 0xff;
514 shift = shift1 & 0x1f;
515 if (shift == 0) {
516 if (shift1 != 0)
517 env->CF = (x >> 31) & 1;
518 return x;
519 } else {
520 env->CF = (x >> (shift - 1)) & 1;
521 return ((uint32_t)x >> shift) | (x << (32 - shift));
522 }
523}