qemu/target-sparc/helper.c
<<
>>
Prefs
   1/*
   2 *  Misc Sparc helpers
   3 *
   4 *  Copyright (c) 2003-2005 Fabrice Bellard
   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
  20#include "cpu.h"
  21#include "qemu/host-utils.h"
  22#include "exec/helper-proto.h"
  23#include "sysemu/sysemu.h"
  24
  25void helper_raise_exception(CPUSPARCState *env, int tt)
  26{
  27    CPUState *cs = CPU(sparc_env_get_cpu(env));
  28
  29    cs->exception_index = tt;
  30    cpu_loop_exit(cs);
  31}
  32
  33void helper_debug(CPUSPARCState *env)
  34{
  35    CPUState *cs = CPU(sparc_env_get_cpu(env));
  36
  37    cs->exception_index = EXCP_DEBUG;
  38    cpu_loop_exit(cs);
  39}
  40
  41#ifdef TARGET_SPARC64
  42target_ulong helper_popc(target_ulong val)
  43{
  44    return ctpop64(val);
  45}
  46
  47void helper_tick_set_count(void *opaque, uint64_t count)
  48{
  49#if !defined(CONFIG_USER_ONLY)
  50    cpu_tick_set_count(opaque, count);
  51#endif
  52}
  53
  54uint64_t helper_tick_get_count(void *opaque)
  55{
  56#if !defined(CONFIG_USER_ONLY)
  57    return cpu_tick_get_count(opaque);
  58#else
  59    return 0;
  60#endif
  61}
  62
  63void helper_tick_set_limit(void *opaque, uint64_t limit)
  64{
  65#if !defined(CONFIG_USER_ONLY)
  66    cpu_tick_set_limit(opaque, limit);
  67#endif
  68}
  69#endif
  70
  71static target_ulong helper_udiv_common(CPUSPARCState *env, target_ulong a,
  72                                       target_ulong b, int cc)
  73{
  74    SPARCCPU *cpu = sparc_env_get_cpu(env);
  75    int overflow = 0;
  76    uint64_t x0;
  77    uint32_t x1;
  78
  79    x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32);
  80    x1 = (b & 0xffffffff);
  81
  82    if (x1 == 0) {
  83        cpu_restore_state(CPU(cpu), GETPC());
  84        helper_raise_exception(env, TT_DIV_ZERO);
  85    }
  86
  87    x0 = x0 / x1;
  88    if (x0 > UINT32_MAX) {
  89        x0 = UINT32_MAX;
  90        overflow = 1;
  91    }
  92
  93    if (cc) {
  94        env->cc_dst = x0;
  95        env->cc_src2 = overflow;
  96        env->cc_op = CC_OP_DIV;
  97    }
  98    return x0;
  99}
 100
 101target_ulong helper_udiv(CPUSPARCState *env, target_ulong a, target_ulong b)
 102{
 103    return helper_udiv_common(env, a, b, 0);
 104}
 105
 106target_ulong helper_udiv_cc(CPUSPARCState *env, target_ulong a, target_ulong b)
 107{
 108    return helper_udiv_common(env, a, b, 1);
 109}
 110
 111static target_ulong helper_sdiv_common(CPUSPARCState *env, target_ulong a,
 112                                       target_ulong b, int cc)
 113{
 114    SPARCCPU *cpu = sparc_env_get_cpu(env);
 115    int overflow = 0;
 116    int64_t x0;
 117    int32_t x1;
 118
 119    x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32);
 120    x1 = (b & 0xffffffff);
 121
 122    if (x1 == 0) {
 123        cpu_restore_state(CPU(cpu), GETPC());
 124        helper_raise_exception(env, TT_DIV_ZERO);
 125    } else if (x1 == -1 && x0 == INT64_MIN) {
 126        x0 = INT32_MAX;
 127        overflow = 1;
 128    } else {
 129        x0 = x0 / x1;
 130        if ((int32_t) x0 != x0) {
 131            x0 = x0 < 0 ? INT32_MIN : INT32_MAX;
 132            overflow = 1;
 133        }
 134    }
 135
 136    if (cc) {
 137        env->cc_dst = x0;
 138        env->cc_src2 = overflow;
 139        env->cc_op = CC_OP_DIV;
 140    }
 141    return x0;
 142}
 143
 144target_ulong helper_sdiv(CPUSPARCState *env, target_ulong a, target_ulong b)
 145{
 146    return helper_sdiv_common(env, a, b, 0);
 147}
 148
 149target_ulong helper_sdiv_cc(CPUSPARCState *env, target_ulong a, target_ulong b)
 150{
 151    return helper_sdiv_common(env, a, b, 1);
 152}
 153
 154#ifdef TARGET_SPARC64
 155int64_t helper_sdivx(CPUSPARCState *env, int64_t a, int64_t b)
 156{
 157    if (b == 0) {
 158        /* Raise divide by zero trap.  */
 159        SPARCCPU *cpu = sparc_env_get_cpu(env);
 160
 161        cpu_restore_state(CPU(cpu), GETPC());
 162        helper_raise_exception(env, TT_DIV_ZERO);
 163    } else if (b == -1) {
 164        /* Avoid overflow trap with i386 divide insn.  */
 165        return -a;
 166    } else {
 167        return a / b;
 168    }
 169}
 170
 171uint64_t helper_udivx(CPUSPARCState *env, uint64_t a, uint64_t b)
 172{
 173    if (b == 0) {
 174        /* Raise divide by zero trap.  */
 175        SPARCCPU *cpu = sparc_env_get_cpu(env);
 176
 177        cpu_restore_state(CPU(cpu), GETPC());
 178        helper_raise_exception(env, TT_DIV_ZERO);
 179    }
 180    return a / b;
 181}
 182#endif
 183
 184target_ulong helper_taddcctv(CPUSPARCState *env, target_ulong src1,
 185                             target_ulong src2)
 186{
 187    SPARCCPU *cpu = sparc_env_get_cpu(env);
 188    target_ulong dst;
 189
 190    /* Tag overflow occurs if either input has bits 0 or 1 set.  */
 191    if ((src1 | src2) & 3) {
 192        goto tag_overflow;
 193    }
 194
 195    dst = src1 + src2;
 196
 197    /* Tag overflow occurs if the addition overflows.  */
 198    if (~(src1 ^ src2) & (src1 ^ dst) & (1u << 31)) {
 199        goto tag_overflow;
 200    }
 201
 202    /* Only modify the CC after any exceptions have been generated.  */
 203    env->cc_op = CC_OP_TADDTV;
 204    env->cc_src = src1;
 205    env->cc_src2 = src2;
 206    env->cc_dst = dst;
 207    return dst;
 208
 209 tag_overflow:
 210    cpu_restore_state(CPU(cpu), GETPC());
 211    helper_raise_exception(env, TT_TOVF);
 212}
 213
 214target_ulong helper_tsubcctv(CPUSPARCState *env, target_ulong src1,
 215                             target_ulong src2)
 216{
 217    SPARCCPU *cpu = sparc_env_get_cpu(env);
 218    target_ulong dst;
 219
 220    /* Tag overflow occurs if either input has bits 0 or 1 set.  */
 221    if ((src1 | src2) & 3) {
 222        goto tag_overflow;
 223    }
 224
 225    dst = src1 - src2;
 226
 227    /* Tag overflow occurs if the subtraction overflows.  */
 228    if ((src1 ^ src2) & (src1 ^ dst) & (1u << 31)) {
 229        goto tag_overflow;
 230    }
 231
 232    /* Only modify the CC after any exceptions have been generated.  */
 233    env->cc_op = CC_OP_TSUBTV;
 234    env->cc_src = src1;
 235    env->cc_src2 = src2;
 236    env->cc_dst = dst;
 237    return dst;
 238
 239 tag_overflow:
 240    cpu_restore_state(CPU(cpu), GETPC());
 241    helper_raise_exception(env, TT_TOVF);
 242}
 243
 244#ifndef TARGET_SPARC64
 245void helper_power_down(CPUSPARCState *env)
 246{
 247    CPUState *cs = CPU(sparc_env_get_cpu(env));
 248
 249    cs->halted = 1;
 250    cs->exception_index = EXCP_HLT;
 251    env->pc = env->npc;
 252    env->npc = env->pc + 4;
 253    cpu_loop_exit(cs);
 254}
 255#endif
 256