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