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 "exec.h"
  20#include "helpers.h"
  21
  22#define SIGNBIT (uint32_t)0x80000000
  23#define SIGNBIT64 ((uint64_t)1 << 63)
  24
  25void raise_exception(int tt)
  26{
  27    env->exception_index = tt;
  28    cpu_loop_exit();
  29}
  30
  31/* thread support */
  32
  33static spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
  34
  35void cpu_lock(void)
  36{
  37    spin_lock(&global_cpu_lock);
  38}
  39
  40void cpu_unlock(void)
  41{
  42    spin_unlock(&global_cpu_lock);
  43}
  44
  45uint32_t HELPER(neon_tbl)(uint32_t ireg, uint32_t def,
  46                          uint32_t rn, uint32_t maxindex)
  47{
  48    uint32_t val;
  49    uint32_t tmp;
  50    int index;
  51    int shift;
  52    uint64_t *table;
  53    table = (uint64_t *)&env->vfp.regs[rn];
  54    val = 0;
  55    for (shift = 0; shift < 32; shift += 8) {
  56        index = (ireg >> shift) & 0xff;
  57        if (index < maxindex) {
  58            tmp = (table[index >> 3] >> ((index & 7) << 3)) & 0xff;
  59            val |= tmp << shift;
  60        } else {
  61            val |= def & (0xff << shift);
  62        }
  63    }
  64    return val;
  65}
  66
  67#if !defined(CONFIG_USER_ONLY)
  68
  69#define MMUSUFFIX _mmu
  70
  71#define SHIFT 0
  72#include "softmmu_template.h"
  73
  74#define SHIFT 1
  75#include "softmmu_template.h"
  76
  77#define SHIFT 2
  78#include "softmmu_template.h"
  79
  80#define SHIFT 3
  81#include "softmmu_template.h"
  82
  83/* try to fill the TLB and return an exception if error. If retaddr is
  84   NULL, it means that the function was called in C code (i.e. not
  85   from generated code or from helper.c) */
  86/* XXX: fix it to restore all registers */
  87void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
  88{
  89    TranslationBlock *tb;
  90    CPUState *saved_env;
  91    unsigned long pc;
  92    int ret;
  93
  94    /* XXX: hack to restore env in all cases, even if not called from
  95       generated code */
  96    saved_env = env;
  97    env = cpu_single_env;
  98    ret = cpu_arm_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
  99    if (unlikely(ret)) {
 100        if (retaddr) {
 101            /* now we have a real cpu fault */
 102            pc = (unsigned long)retaddr;
 103            tb = tb_find_pc(pc);
 104            if (tb) {
 105                /* the PC is inside the translated code. It means that we have
 106                   a virtual CPU fault */
 107                cpu_restore_state(tb, env, pc, NULL);
 108            }
 109        }
 110        raise_exception(env->exception_index);
 111    }
 112    env = saved_env;
 113}
 114#endif
 115
 116/* FIXME: Pass an axplicit pointer to QF to CPUState, and move saturating
 117   instructions into helper.c  */
 118uint32_t HELPER(add_setq)(uint32_t a, uint32_t b)
 119{
 120    uint32_t res = a + b;
 121    if (((res ^ a) & SIGNBIT) && !((a ^ b) & SIGNBIT))
 122        env->QF = 1;
 123    return res;
 124}
 125
 126uint32_t HELPER(add_saturate)(uint32_t a, uint32_t b)
 127{
 128    uint32_t res = a + b;
 129    if (((res ^ a) & SIGNBIT) && !((a ^ b) & SIGNBIT)) {
 130        env->QF = 1;
 131        res = ~(((int32_t)a >> 31) ^ SIGNBIT);
 132    }
 133    return res;
 134}
 135
 136uint32_t HELPER(sub_saturate)(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        res = ~(((int32_t)a >> 31) ^ SIGNBIT);
 142    }
 143    return res;
 144}
 145
 146uint32_t HELPER(double_saturate)(int32_t val)
 147{
 148    uint32_t res;
 149    if (val >= 0x40000000) {
 150        res = ~SIGNBIT;
 151        env->QF = 1;
 152    } else if (val <= (int32_t)0xc0000000) {
 153        res = SIGNBIT;
 154        env->QF = 1;
 155    } else {
 156        res = val << 1;
 157    }
 158    return res;
 159}
 160
 161uint32_t HELPER(add_usaturate)(uint32_t a, uint32_t b)
 162{
 163    uint32_t res = a + b;
 164    if (res < a) {
 165        env->QF = 1;
 166        res = ~0;
 167    }
 168    return res;
 169}
 170
 171uint32_t HELPER(sub_usaturate)(uint32_t a, uint32_t b)
 172{
 173    uint32_t res = a - b;
 174    if (res > a) {
 175        env->QF = 1;
 176        res = 0;
 177    }
 178    return res;
 179}
 180
 181/* Signed saturation.  */
 182static inline uint32_t do_ssat(int32_t val, int shift)
 183{
 184    int32_t top;
 185    uint32_t mask;
 186
 187    top = val >> shift;
 188    mask = (1u << shift) - 1;
 189    if (top > 0) {
 190        env->QF = 1;
 191        return mask;
 192    } else if (top < -1) {
 193        env->QF = 1;
 194        return ~mask;
 195    }
 196    return val;
 197}
 198
 199/* Unsigned saturation.  */
 200static inline uint32_t do_usat(int32_t val, int shift)
 201{
 202    uint32_t max;
 203
 204    max = (1u << shift) - 1;
 205    if (val < 0) {
 206        env->QF = 1;
 207        return 0;
 208    } else if (val > max) {
 209        env->QF = 1;
 210        return max;
 211    }
 212    return val;
 213}
 214
 215/* Signed saturate.  */
 216uint32_t HELPER(ssat)(uint32_t x, uint32_t shift)
 217{
 218    return do_ssat(x, shift);
 219}
 220
 221/* Dual halfword signed saturate.  */
 222uint32_t HELPER(ssat16)(uint32_t x, uint32_t shift)
 223{
 224    uint32_t res;
 225
 226    res = (uint16_t)do_ssat((int16_t)x, shift);
 227    res |= do_ssat(((int32_t)x) >> 16, shift) << 16;
 228    return res;
 229}
 230
 231/* Unsigned saturate.  */
 232uint32_t HELPER(usat)(uint32_t x, uint32_t shift)
 233{
 234    return do_usat(x, shift);
 235}
 236
 237/* Dual halfword unsigned saturate.  */
 238uint32_t HELPER(usat16)(uint32_t x, uint32_t shift)
 239{
 240    uint32_t res;
 241
 242    res = (uint16_t)do_usat((int16_t)x, shift);
 243    res |= do_usat(((int32_t)x) >> 16, shift) << 16;
 244    return res;
 245}
 246
 247void HELPER(wfi)(void)
 248{
 249    env->exception_index = EXCP_HLT;
 250    env->halted = 1;
 251    cpu_loop_exit();
 252}
 253
 254void HELPER(exception)(uint32_t excp)
 255{
 256    env->exception_index = excp;
 257    cpu_loop_exit();
 258}
 259
 260uint32_t HELPER(cpsr_read)(void)
 261{
 262    return cpsr_read(env) & ~CPSR_EXEC;
 263}
 264
 265void HELPER(cpsr_write)(uint32_t val, uint32_t mask)
 266{
 267    cpsr_write(env, val, mask);
 268}
 269
 270/* Access to user mode registers from privileged modes.  */
 271uint32_t HELPER(get_user_reg)(uint32_t regno)
 272{
 273    uint32_t val;
 274
 275    if (regno == 13) {
 276        val = env->banked_r13[0];
 277    } else if (regno == 14) {
 278        val = env->banked_r14[0];
 279    } else if (regno >= 8
 280               && (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) {
 281        val = env->usr_regs[regno - 8];
 282    } else {
 283        val = env->regs[regno];
 284    }
 285    return val;
 286}
 287
 288void HELPER(set_user_reg)(uint32_t regno, uint32_t val)
 289{
 290    if (regno == 13) {
 291        env->banked_r13[0] = val;
 292    } else if (regno == 14) {
 293        env->banked_r14[0] = val;
 294    } else if (regno >= 8
 295               && (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) {
 296        env->usr_regs[regno - 8] = val;
 297    } else {
 298        env->regs[regno] = val;
 299    }
 300}
 301
 302/* ??? Flag setting arithmetic is awkward because we need to do comparisons.
 303   The only way to do that in TCG is a conditional branch, which clobbers
 304   all our temporaries.  For now implement these as helper functions.  */
 305
 306uint32_t HELPER (add_cc)(uint32_t a, uint32_t b)
 307{
 308    uint32_t result;
 309    result = a + b;
 310    env->NF = env->ZF = result;
 311    env->CF = result < a;
 312    env->VF = (a ^ b ^ -1) & (a ^ result);
 313    return result;
 314}
 315
 316uint32_t HELPER(adc_cc)(uint32_t a, uint32_t b)
 317{
 318    uint32_t result;
 319    if (!env->CF) {
 320        result = a + b;
 321        env->CF = result < a;
 322    } else {
 323        result = a + b + 1;
 324        env->CF = result <= a;
 325    }
 326    env->VF = (a ^ b ^ -1) & (a ^ result);
 327    env->NF = env->ZF = result;
 328    return result;
 329}
 330
 331uint32_t HELPER(sub_cc)(uint32_t a, uint32_t b)
 332{
 333    uint32_t result;
 334    result = a - b;
 335    env->NF = env->ZF = result;
 336    env->CF = a >= b;
 337    env->VF = (a ^ b) & (a ^ result);
 338    return result;
 339}
 340
 341uint32_t HELPER(sbc_cc)(uint32_t a, uint32_t b)
 342{
 343    uint32_t result;
 344    if (!env->CF) {
 345        result = a - b - 1;
 346        env->CF = a > b;
 347    } else {
 348        result = a - b;
 349        env->CF = a >= b;
 350    }
 351    env->VF = (a ^ b) & (a ^ result);
 352    env->NF = env->ZF = result;
 353    return result;
 354}
 355
 356/* Similarly for variable shift instructions.  */
 357
 358uint32_t HELPER(shl)(uint32_t x, uint32_t i)
 359{
 360    int shift = i & 0xff;
 361    if (shift >= 32)
 362        return 0;
 363    return x << shift;
 364}
 365
 366uint32_t HELPER(shr)(uint32_t x, uint32_t i)
 367{
 368    int shift = i & 0xff;
 369    if (shift >= 32)
 370        return 0;
 371    return (uint32_t)x >> shift;
 372}
 373
 374uint32_t HELPER(sar)(uint32_t x, uint32_t i)
 375{
 376    int shift = i & 0xff;
 377    if (shift >= 32)
 378        shift = 31;
 379    return (int32_t)x >> shift;
 380}
 381
 382uint32_t HELPER(ror)(uint32_t x, uint32_t i)
 383{
 384    int shift = i & 0xff;
 385    if (shift == 0)
 386        return x;
 387    return (x >> shift) | (x << (32 - shift));
 388}
 389
 390uint32_t HELPER(shl_cc)(uint32_t x, uint32_t i)
 391{
 392    int shift = i & 0xff;
 393    if (shift >= 32) {
 394        if (shift == 32)
 395            env->CF = x & 1;
 396        else
 397            env->CF = 0;
 398        return 0;
 399    } else if (shift != 0) {
 400        env->CF = (x >> (32 - shift)) & 1;
 401        return x << shift;
 402    }
 403    return x;
 404}
 405
 406uint32_t HELPER(shr_cc)(uint32_t x, uint32_t i)
 407{
 408    int shift = i & 0xff;
 409    if (shift >= 32) {
 410        if (shift == 32)
 411            env->CF = (x >> 31) & 1;
 412        else
 413            env->CF = 0;
 414        return 0;
 415    } else if (shift != 0) {
 416        env->CF = (x >> (shift - 1)) & 1;
 417        return x >> shift;
 418    }
 419    return x;
 420}
 421
 422uint32_t HELPER(sar_cc)(uint32_t x, uint32_t i)
 423{
 424    int shift = i & 0xff;
 425    if (shift >= 32) {
 426        env->CF = (x >> 31) & 1;
 427        return (int32_t)x >> 31;
 428    } else if (shift != 0) {
 429        env->CF = (x >> (shift - 1)) & 1;
 430        return (int32_t)x >> shift;
 431    }
 432    return x;
 433}
 434
 435uint32_t HELPER(ror_cc)(uint32_t x, uint32_t i)
 436{
 437    int shift1, shift;
 438    shift1 = i & 0xff;
 439    shift = shift1 & 0x1f;
 440    if (shift == 0) {
 441        if (shift1 != 0)
 442            env->CF = (x >> 31) & 1;
 443        return x;
 444    } else {
 445        env->CF = (x >> (shift - 1)) & 1;
 446        return ((uint32_t)x >> shift) | (x << (32 - shift));
 447    }
 448}
 449
 450uint64_t HELPER(neon_add_saturate_s64)(uint64_t src1, uint64_t src2)
 451{
 452    uint64_t res;
 453
 454    res = src1 + src2;
 455    if (((res ^ src1) & SIGNBIT64) && !((src1 ^ src2) & SIGNBIT64)) {
 456        env->QF = 1;
 457        res = ((int64_t)src1 >> 63) ^ ~SIGNBIT64;
 458    }
 459    return res;
 460}
 461
 462uint64_t HELPER(neon_add_saturate_u64)(uint64_t src1, uint64_t src2)
 463{
 464    uint64_t res;
 465
 466    res = src1 + src2;
 467    if (res < src1) {
 468        env->QF = 1;
 469        res = ~(uint64_t)0;
 470    }
 471    return res;
 472}
 473
 474uint64_t HELPER(neon_sub_saturate_s64)(uint64_t src1, uint64_t src2)
 475{
 476    uint64_t res;
 477
 478    res = src1 - src2;
 479    if (((res ^ src1) & SIGNBIT64) && ((src1 ^ src2) & SIGNBIT64)) {
 480        env->QF = 1;
 481        res = ((int64_t)src1 >> 63) ^ ~SIGNBIT64;
 482    }
 483    return res;
 484}
 485
 486uint64_t HELPER(neon_sub_saturate_u64)(uint64_t src1, uint64_t src2)
 487{
 488    uint64_t res;
 489
 490    if (src1 < src2) {
 491        env->QF = 1;
 492        res = 0;
 493    } else {
 494        res = src1 - src2;
 495    }
 496    return res;
 497}
 498
 499/* These need to return a pair of value, so still use T0/T1.  */
 500/* Transpose.  Argument order is rather strange to avoid special casing
 501   the tranlation code.
 502   On input T0 = rm, T1 = rd.  On output T0 = rd, T1 = rm  */
 503void HELPER(neon_trn_u8)(void)
 504{
 505    uint32_t rd;
 506    uint32_t rm;
 507    rd = ((T0 & 0x00ff00ff) << 8) | (T1 & 0x00ff00ff);
 508    rm = ((T1 & 0xff00ff00) >> 8) | (T0 & 0xff00ff00);
 509    T0 = rd;
 510    T1 = rm;
 511}
 512
 513void HELPER(neon_trn_u16)(void)
 514{
 515    uint32_t rd;
 516    uint32_t rm;
 517    rd = (T0 << 16) | (T1 & 0xffff);
 518    rm = (T1 >> 16) | (T0 & 0xffff0000);
 519    T0 = rd;
 520    T1 = rm;
 521}
 522
 523/* Worker routines for zip and unzip.  */
 524void HELPER(neon_unzip_u8)(void)
 525{
 526    uint32_t rd;
 527    uint32_t rm;
 528    rd = (T0 & 0xff) | ((T0 >> 8) & 0xff00)
 529         | ((T1 << 16) & 0xff0000) | ((T1 << 8) & 0xff000000);
 530    rm = ((T0 >> 8) & 0xff) | ((T0 >> 16) & 0xff00)
 531         | ((T1 << 8) & 0xff0000) | (T1 & 0xff000000);
 532    T0 = rd;
 533    T1 = rm;
 534}
 535
 536void HELPER(neon_zip_u8)(void)
 537{
 538    uint32_t rd;
 539    uint32_t rm;
 540    rd = (T0 & 0xff) | ((T1 << 8) & 0xff00)
 541         | ((T0 << 16) & 0xff0000) | ((T1 << 24) & 0xff000000);
 542    rm = ((T0 >> 16) & 0xff) | ((T1 >> 8) & 0xff00)
 543         | ((T0 >> 8) & 0xff0000) | (T1 & 0xff000000);
 544    T0 = rd;
 545    T1 = rm;
 546}
 547
 548void HELPER(neon_zip_u16)(void)
 549{
 550    uint32_t tmp;
 551
 552    tmp = (T0 & 0xffff) | (T1 << 16);
 553    T1 = (T1 & 0xffff0000) | (T0 >> 16);
 554    T0 = tmp;
 555}
 556