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    env->exception_index = EXCP_HLT;
 222    env->halted = 1;
 223    cpu_loop_exit(env);
 224}
 225
 226void HELPER(exception)(CPUARMState *env, uint32_t excp)
 227{
 228    env->exception_index = excp;
 229    cpu_loop_exit(env);
 230}
 231
 232uint32_t HELPER(cpsr_read)(CPUARMState *env)
 233{
 234    return cpsr_read(env) & ~CPSR_EXEC;
 235}
 236
 237void HELPER(cpsr_write)(CPUARMState *env, uint32_t val, uint32_t mask)
 238{
 239    cpsr_write(env, val, mask);
 240}
 241
 242/* Access to user mode registers from privileged modes.  */
 243uint32_t HELPER(get_user_reg)(CPUARMState *env, uint32_t regno)
 244{
 245    uint32_t val;
 246
 247    if (regno == 13) {
 248        val = env->banked_r13[0];
 249    } else if (regno == 14) {
 250        val = env->banked_r14[0];
 251    } else if (regno >= 8
 252               && (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) {
 253        val = env->usr_regs[regno - 8];
 254    } else {
 255        val = env->regs[regno];
 256    }
 257    return val;
 258}
 259
 260void HELPER(set_user_reg)(CPUARMState *env, uint32_t regno, uint32_t val)
 261{
 262    if (regno == 13) {
 263        env->banked_r13[0] = val;
 264    } else if (regno == 14) {
 265        env->banked_r14[0] = val;
 266    } else if (regno >= 8
 267               && (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) {
 268        env->usr_regs[regno - 8] = val;
 269    } else {
 270        env->regs[regno] = val;
 271    }
 272}
 273
 274void HELPER(set_cp_reg)(CPUARMState *env, void *rip, uint32_t value)
 275{
 276    const ARMCPRegInfo *ri = rip;
 277    int excp = ri->writefn(env, ri, value);
 278    if (excp) {
 279        raise_exception(env, excp);
 280    }
 281}
 282
 283uint32_t HELPER(get_cp_reg)(CPUARMState *env, void *rip)
 284{
 285    const ARMCPRegInfo *ri = rip;
 286    uint64_t value;
 287    int excp = ri->readfn(env, ri, &value);
 288    if (excp) {
 289        raise_exception(env, excp);
 290    }
 291    return value;
 292}
 293
 294void HELPER(set_cp_reg64)(CPUARMState *env, void *rip, uint64_t value)
 295{
 296    const ARMCPRegInfo *ri = rip;
 297    int excp = ri->writefn(env, ri, value);
 298    if (excp) {
 299        raise_exception(env, excp);
 300    }
 301}
 302
 303uint64_t HELPER(get_cp_reg64)(CPUARMState *env, void *rip)
 304{
 305    const ARMCPRegInfo *ri = rip;
 306    uint64_t value;
 307    int excp = ri->readfn(env, ri, &value);
 308    if (excp) {
 309        raise_exception(env, excp);
 310    }
 311    return value;
 312}
 313
 314/* ??? Flag setting arithmetic is awkward because we need to do comparisons.
 315   The only way to do that in TCG is a conditional branch, which clobbers
 316   all our temporaries.  For now implement these as helper functions.  */
 317
 318uint32_t HELPER(adc_cc)(CPUARMState *env, uint32_t a, uint32_t b)
 319{
 320    uint32_t result;
 321    if (!env->CF) {
 322        result = a + b;
 323        env->CF = result < a;
 324    } else {
 325        result = a + b + 1;
 326        env->CF = result <= a;
 327    }
 328    env->VF = (a ^ b ^ -1) & (a ^ result);
 329    env->NF = env->ZF = result;
 330    return result;
 331}
 332
 333uint32_t HELPER(sbc_cc)(CPUARMState *env, uint32_t a, uint32_t b)
 334{
 335    uint32_t result;
 336    if (!env->CF) {
 337        result = a - b - 1;
 338        env->CF = a > b;
 339    } else {
 340        result = a - b;
 341        env->CF = a >= b;
 342    }
 343    env->VF = (a ^ b) & (a ^ result);
 344    env->NF = env->ZF = result;
 345    return result;
 346}
 347
 348/* Similarly for variable shift instructions.  */
 349
 350uint32_t HELPER(shl_cc)(CPUARMState *env, uint32_t x, uint32_t i)
 351{
 352    int shift = i & 0xff;
 353    if (shift >= 32) {
 354        if (shift == 32)
 355            env->CF = x & 1;
 356        else
 357            env->CF = 0;
 358        return 0;
 359    } else if (shift != 0) {
 360        env->CF = (x >> (32 - shift)) & 1;
 361        return x << shift;
 362    }
 363    return x;
 364}
 365
 366uint32_t HELPER(shr_cc)(CPUARMState *env, uint32_t x, uint32_t i)
 367{
 368    int shift = i & 0xff;
 369    if (shift >= 32) {
 370        if (shift == 32)
 371            env->CF = (x >> 31) & 1;
 372        else
 373            env->CF = 0;
 374        return 0;
 375    } else if (shift != 0) {
 376        env->CF = (x >> (shift - 1)) & 1;
 377        return x >> shift;
 378    }
 379    return x;
 380}
 381
 382uint32_t HELPER(sar_cc)(CPUARMState *env, uint32_t x, uint32_t i)
 383{
 384    int shift = i & 0xff;
 385    if (shift >= 32) {
 386        env->CF = (x >> 31) & 1;
 387        return (int32_t)x >> 31;
 388    } else if (shift != 0) {
 389        env->CF = (x >> (shift - 1)) & 1;
 390        return (int32_t)x >> shift;
 391    }
 392    return x;
 393}
 394
 395uint32_t HELPER(ror_cc)(CPUARMState *env, uint32_t x, uint32_t i)
 396{
 397    int shift1, shift;
 398    shift1 = i & 0xff;
 399    shift = shift1 & 0x1f;
 400    if (shift == 0) {
 401        if (shift1 != 0)
 402            env->CF = (x >> 31) & 1;
 403        return x;
 404    } else {
 405        env->CF = (x >> (shift - 1)) & 1;
 406        return ((uint32_t)x >> shift) | (x << (32 - shift));
 407    }
 408}
 409