qemu/target-arm/op_helper.c
<<
>>
Prefs
   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
  25static void raise_exception(CPUARMState *env, int tt)
  26{
  27    env->exception_index = tt;
  28    cpu_loop_exit(env);
  29}
  30
  31uint32_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) */
  74void 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
  90uint32_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
  98uint32_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
 108uint32_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
 118uint32_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
 133uint32_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
 143uint32_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.  */
 154static 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.  */
 172static 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.  */
 188uint32_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.  */
 194uint32_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.  */
 204uint32_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.  */
 210uint32_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
 219void HELPER(wfi)(CPUARMState *env)
 220{
 221    CPUState *cs = CPU(arm_env_get_cpu(env));
 222
 223    env->exception_index = EXCP_HLT;
 224    cs->halted = 1;
 225    cpu_loop_exit(env);
 226}
 227
 228void HELPER(exception)(CPUARMState *env, uint32_t excp)
 229{
 230    env->exception_index = excp;
 231    cpu_loop_exit(env);
 232}
 233
 234uint32_t HELPER(cpsr_read)(CPUARMState *env)
 235{
 236    return cpsr_read(env) & ~CPSR_EXEC;
 237}
 238
 239void HELPER(cpsr_write)(CPUARMState *env, uint32_t val, uint32_t mask)
 240{
 241    cpsr_write(env, val, mask);
 242}
 243
 244/* Access to user mode registers from privileged modes.  */
 245uint32_t HELPER(get_user_reg)(CPUARMState *env, uint32_t regno)
 246{
 247    uint32_t val;
 248
 249    if (regno == 13) {
 250        val = env->banked_r13[0];
 251    } else if (regno == 14) {
 252        val = env->banked_r14[0];
 253    } else if (regno >= 8
 254               && (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) {
 255        val = env->usr_regs[regno - 8];
 256    } else {
 257        val = env->regs[regno];
 258    }
 259    return val;
 260}
 261
 262void HELPER(set_user_reg)(CPUARMState *env, uint32_t regno, uint32_t val)
 263{
 264    if (regno == 13) {
 265        env->banked_r13[0] = val;
 266    } else if (regno == 14) {
 267        env->banked_r14[0] = val;
 268    } else if (regno >= 8
 269               && (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) {
 270        env->usr_regs[regno - 8] = val;
 271    } else {
 272        env->regs[regno] = val;
 273    }
 274}
 275
 276void HELPER(set_cp_reg)(CPUARMState *env, void *rip, uint32_t value)
 277{
 278    const ARMCPRegInfo *ri = rip;
 279    int excp = ri->writefn(env, ri, value);
 280    if (excp) {
 281        raise_exception(env, excp);
 282    }
 283}
 284
 285uint32_t HELPER(get_cp_reg)(CPUARMState *env, void *rip)
 286{
 287    const ARMCPRegInfo *ri = rip;
 288    uint64_t value;
 289    int excp = ri->readfn(env, ri, &value);
 290    if (excp) {
 291        raise_exception(env, excp);
 292    }
 293    return value;
 294}
 295
 296void HELPER(set_cp_reg64)(CPUARMState *env, void *rip, uint64_t value)
 297{
 298    const ARMCPRegInfo *ri = rip;
 299    int excp = ri->writefn(env, ri, value);
 300    if (excp) {
 301        raise_exception(env, excp);
 302    }
 303}
 304
 305uint64_t HELPER(get_cp_reg64)(CPUARMState *env, void *rip)
 306{
 307    const ARMCPRegInfo *ri = rip;
 308    uint64_t value;
 309    int excp = ri->readfn(env, ri, &value);
 310    if (excp) {
 311        raise_exception(env, excp);
 312    }
 313    return value;
 314}
 315
 316/* ??? Flag setting arithmetic is awkward because we need to do comparisons.
 317   The only way to do that in TCG is a conditional branch, which clobbers
 318   all our temporaries.  For now implement these as helper functions.  */
 319
 320/* Similarly for variable shift instructions.  */
 321
 322uint32_t HELPER(shl_cc)(CPUARMState *env, uint32_t x, uint32_t i)
 323{
 324    int shift = i & 0xff;
 325    if (shift >= 32) {
 326        if (shift == 32)
 327            env->CF = x & 1;
 328        else
 329            env->CF = 0;
 330        return 0;
 331    } else if (shift != 0) {
 332        env->CF = (x >> (32 - shift)) & 1;
 333        return x << shift;
 334    }
 335    return x;
 336}
 337
 338uint32_t HELPER(shr_cc)(CPUARMState *env, uint32_t x, uint32_t i)
 339{
 340    int shift = i & 0xff;
 341    if (shift >= 32) {
 342        if (shift == 32)
 343            env->CF = (x >> 31) & 1;
 344        else
 345            env->CF = 0;
 346        return 0;
 347    } else if (shift != 0) {
 348        env->CF = (x >> (shift - 1)) & 1;
 349        return x >> shift;
 350    }
 351    return x;
 352}
 353
 354uint32_t HELPER(sar_cc)(CPUARMState *env, uint32_t x, uint32_t i)
 355{
 356    int shift = i & 0xff;
 357    if (shift >= 32) {
 358        env->CF = (x >> 31) & 1;
 359        return (int32_t)x >> 31;
 360    } else if (shift != 0) {
 361        env->CF = (x >> (shift - 1)) & 1;
 362        return (int32_t)x >> shift;
 363    }
 364    return x;
 365}
 366
 367uint32_t HELPER(ror_cc)(CPUARMState *env, uint32_t x, uint32_t i)
 368{
 369    int shift1, shift;
 370    shift1 = i & 0xff;
 371    shift = shift1 & 0x1f;
 372    if (shift == 0) {
 373        if (shift1 != 0)
 374            env->CF = (x >> 31) & 1;
 375        return x;
 376    } else {
 377        env->CF = (x >> (shift - 1)) & 1;
 378        return ((uint32_t)x >> shift) | (x << (32 - shift));
 379    }
 380}
 381