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 "exec/exec-all.h"
  23#include "qemu/host-utils.h"
  24#include "exec/helper-proto.h"
  25#include "sysemu/sysemu.h"
  26
  27void cpu_raise_exception_ra(CPUSPARCState *env, int tt, uintptr_t ra)
  28{
  29    CPUState *cs = CPU(sparc_env_get_cpu(env));
  30
  31    cs->exception_index = tt;
  32    cpu_loop_exit_restore(cs, ra);
  33}
  34
  35void helper_raise_exception(CPUSPARCState *env, int tt)
  36{
  37    CPUState *cs = CPU(sparc_env_get_cpu(env));
  38
  39    cs->exception_index = tt;
  40    cpu_loop_exit(cs);
  41}
  42
  43void helper_debug(CPUSPARCState *env)
  44{
  45    CPUState *cs = CPU(sparc_env_get_cpu(env));
  46
  47    cs->exception_index = EXCP_DEBUG;
  48    cpu_loop_exit(cs);
  49}
  50
  51#ifdef TARGET_SPARC64
  52void helper_tick_set_count(void *opaque, uint64_t count)
  53{
  54#if !defined(CONFIG_USER_ONLY)
  55    cpu_tick_set_count(opaque, count);
  56#endif
  57}
  58
  59uint64_t helper_tick_get_count(CPUSPARCState *env, void *opaque, int mem_idx)
  60{
  61#if !defined(CONFIG_USER_ONLY)
  62    CPUTimer *timer = opaque;
  63
  64    if (timer->npt && mem_idx < MMU_KERNEL_IDX) {
  65        cpu_raise_exception_ra(env, TT_PRIV_INSN, GETPC());
  66    }
  67
  68    return cpu_tick_get_count(timer);
  69#else
  70    return 0;
  71#endif
  72}
  73
  74void helper_tick_set_limit(void *opaque, uint64_t limit)
  75{
  76#if !defined(CONFIG_USER_ONLY)
  77    cpu_tick_set_limit(opaque, limit);
  78#endif
  79}
  80#endif
  81
  82static target_ulong do_udiv(CPUSPARCState *env, target_ulong a,
  83                            target_ulong b, int cc, uintptr_t ra)
  84{
  85    int overflow = 0;
  86    uint64_t x0;
  87    uint32_t x1;
  88
  89    x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32);
  90    x1 = (b & 0xffffffff);
  91
  92    if (x1 == 0) {
  93        cpu_raise_exception_ra(env, TT_DIV_ZERO, ra);
  94    }
  95
  96    x0 = x0 / x1;
  97    if (x0 > UINT32_MAX) {
  98        x0 = UINT32_MAX;
  99        overflow = 1;
 100    }
 101
 102    if (cc) {
 103        env->cc_dst = x0;
 104        env->cc_src2 = overflow;
 105        env->cc_op = CC_OP_DIV;
 106    }
 107    return x0;
 108}
 109
 110target_ulong helper_udiv(CPUSPARCState *env, target_ulong a, target_ulong b)
 111{
 112    return do_udiv(env, a, b, 0, GETPC());
 113}
 114
 115target_ulong helper_udiv_cc(CPUSPARCState *env, target_ulong a, target_ulong b)
 116{
 117    return do_udiv(env, a, b, 1, GETPC());
 118}
 119
 120static target_ulong do_sdiv(CPUSPARCState *env, target_ulong a,
 121                            target_ulong b, int cc, uintptr_t ra)
 122{
 123    int overflow = 0;
 124    int64_t x0;
 125    int32_t x1;
 126
 127    x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32);
 128    x1 = (b & 0xffffffff);
 129
 130    if (x1 == 0) {
 131        cpu_raise_exception_ra(env, TT_DIV_ZERO, ra);
 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 do_sdiv(env, a, b, 0, GETPC());
 154}
 155
 156target_ulong helper_sdiv_cc(CPUSPARCState *env, target_ulong a, target_ulong b)
 157{
 158    return do_sdiv(env, a, b, 1, GETPC());
 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        cpu_raise_exception_ra(env, TT_DIV_ZERO, GETPC());
 167    } else if (b == -1) {
 168        /* Avoid overflow trap with i386 divide insn.  */
 169        return -a;
 170    } else {
 171        return a / b;
 172    }
 173}
 174
 175uint64_t helper_udivx(CPUSPARCState *env, uint64_t a, uint64_t b)
 176{
 177    if (b == 0) {
 178        /* Raise divide by zero trap.  */
 179        cpu_raise_exception_ra(env, TT_DIV_ZERO, GETPC());
 180    }
 181    return a / b;
 182}
 183#endif
 184
 185target_ulong helper_taddcctv(CPUSPARCState *env, target_ulong src1,
 186                             target_ulong src2)
 187{
 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_raise_exception_ra(env, TT_TOVF, GETPC());
 211}
 212
 213target_ulong helper_tsubcctv(CPUSPARCState *env, target_ulong src1,
 214                             target_ulong src2)
 215{
 216    target_ulong dst;
 217
 218    /* Tag overflow occurs if either input has bits 0 or 1 set.  */
 219    if ((src1 | src2) & 3) {
 220        goto tag_overflow;
 221    }
 222
 223    dst = src1 - src2;
 224
 225    /* Tag overflow occurs if the subtraction overflows.  */
 226    if ((src1 ^ src2) & (src1 ^ dst) & (1u << 31)) {
 227        goto tag_overflow;
 228    }
 229
 230    /* Only modify the CC after any exceptions have been generated.  */
 231    env->cc_op = CC_OP_TSUBTV;
 232    env->cc_src = src1;
 233    env->cc_src2 = src2;
 234    env->cc_dst = dst;
 235    return dst;
 236
 237 tag_overflow:
 238    cpu_raise_exception_ra(env, TT_TOVF, GETPC());
 239}
 240
 241#ifndef TARGET_SPARC64
 242void helper_power_down(CPUSPARCState *env)
 243{
 244    CPUState *cs = CPU(sparc_env_get_cpu(env));
 245
 246    cs->halted = 1;
 247    cs->exception_index = EXCP_HLT;
 248    env->pc = env->npc;
 249    env->npc = env->pc + 4;
 250    cpu_loop_exit(cs);
 251}
 252#endif
 253