1*fcf5ef2aSThomas Huth /* 2*fcf5ef2aSThomas Huth * Misc Sparc helpers 3*fcf5ef2aSThomas Huth * 4*fcf5ef2aSThomas Huth * Copyright (c) 2003-2005 Fabrice Bellard 5*fcf5ef2aSThomas Huth * 6*fcf5ef2aSThomas Huth * This library is free software; you can redistribute it and/or 7*fcf5ef2aSThomas Huth * modify it under the terms of the GNU Lesser General Public 8*fcf5ef2aSThomas Huth * License as published by the Free Software Foundation; either 9*fcf5ef2aSThomas Huth * version 2 of the License, or (at your option) any later version. 10*fcf5ef2aSThomas Huth * 11*fcf5ef2aSThomas Huth * This library is distributed in the hope that it will be useful, 12*fcf5ef2aSThomas Huth * but WITHOUT ANY WARRANTY; without even the implied warranty of 13*fcf5ef2aSThomas Huth * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14*fcf5ef2aSThomas Huth * Lesser General Public License for more details. 15*fcf5ef2aSThomas Huth * 16*fcf5ef2aSThomas Huth * You should have received a copy of the GNU Lesser General Public 17*fcf5ef2aSThomas Huth * License along with this library; if not, see <http://www.gnu.org/licenses/>. 18*fcf5ef2aSThomas Huth */ 19*fcf5ef2aSThomas Huth 20*fcf5ef2aSThomas Huth #include "qemu/osdep.h" 21*fcf5ef2aSThomas Huth #include "cpu.h" 22*fcf5ef2aSThomas Huth #include "exec/exec-all.h" 23*fcf5ef2aSThomas Huth #include "qemu/host-utils.h" 24*fcf5ef2aSThomas Huth #include "exec/helper-proto.h" 25*fcf5ef2aSThomas Huth #include "sysemu/sysemu.h" 26*fcf5ef2aSThomas Huth 27*fcf5ef2aSThomas Huth void cpu_raise_exception_ra(CPUSPARCState *env, int tt, uintptr_t ra) 28*fcf5ef2aSThomas Huth { 29*fcf5ef2aSThomas Huth CPUState *cs = CPU(sparc_env_get_cpu(env)); 30*fcf5ef2aSThomas Huth 31*fcf5ef2aSThomas Huth cs->exception_index = tt; 32*fcf5ef2aSThomas Huth cpu_loop_exit_restore(cs, ra); 33*fcf5ef2aSThomas Huth } 34*fcf5ef2aSThomas Huth 35*fcf5ef2aSThomas Huth void helper_raise_exception(CPUSPARCState *env, int tt) 36*fcf5ef2aSThomas Huth { 37*fcf5ef2aSThomas Huth CPUState *cs = CPU(sparc_env_get_cpu(env)); 38*fcf5ef2aSThomas Huth 39*fcf5ef2aSThomas Huth cs->exception_index = tt; 40*fcf5ef2aSThomas Huth cpu_loop_exit(cs); 41*fcf5ef2aSThomas Huth } 42*fcf5ef2aSThomas Huth 43*fcf5ef2aSThomas Huth void helper_debug(CPUSPARCState *env) 44*fcf5ef2aSThomas Huth { 45*fcf5ef2aSThomas Huth CPUState *cs = CPU(sparc_env_get_cpu(env)); 46*fcf5ef2aSThomas Huth 47*fcf5ef2aSThomas Huth cs->exception_index = EXCP_DEBUG; 48*fcf5ef2aSThomas Huth cpu_loop_exit(cs); 49*fcf5ef2aSThomas Huth } 50*fcf5ef2aSThomas Huth 51*fcf5ef2aSThomas Huth #ifdef TARGET_SPARC64 52*fcf5ef2aSThomas Huth target_ulong helper_popc(target_ulong val) 53*fcf5ef2aSThomas Huth { 54*fcf5ef2aSThomas Huth return ctpop64(val); 55*fcf5ef2aSThomas Huth } 56*fcf5ef2aSThomas Huth 57*fcf5ef2aSThomas Huth void helper_tick_set_count(void *opaque, uint64_t count) 58*fcf5ef2aSThomas Huth { 59*fcf5ef2aSThomas Huth #if !defined(CONFIG_USER_ONLY) 60*fcf5ef2aSThomas Huth cpu_tick_set_count(opaque, count); 61*fcf5ef2aSThomas Huth #endif 62*fcf5ef2aSThomas Huth } 63*fcf5ef2aSThomas Huth 64*fcf5ef2aSThomas Huth uint64_t helper_tick_get_count(CPUSPARCState *env, void *opaque, int mem_idx) 65*fcf5ef2aSThomas Huth { 66*fcf5ef2aSThomas Huth #if !defined(CONFIG_USER_ONLY) 67*fcf5ef2aSThomas Huth CPUTimer *timer = opaque; 68*fcf5ef2aSThomas Huth 69*fcf5ef2aSThomas Huth if (timer->npt && mem_idx < MMU_KERNEL_IDX) { 70*fcf5ef2aSThomas Huth cpu_raise_exception_ra(env, TT_PRIV_INSN, GETPC()); 71*fcf5ef2aSThomas Huth } 72*fcf5ef2aSThomas Huth 73*fcf5ef2aSThomas Huth return cpu_tick_get_count(timer); 74*fcf5ef2aSThomas Huth #else 75*fcf5ef2aSThomas Huth return 0; 76*fcf5ef2aSThomas Huth #endif 77*fcf5ef2aSThomas Huth } 78*fcf5ef2aSThomas Huth 79*fcf5ef2aSThomas Huth void helper_tick_set_limit(void *opaque, uint64_t limit) 80*fcf5ef2aSThomas Huth { 81*fcf5ef2aSThomas Huth #if !defined(CONFIG_USER_ONLY) 82*fcf5ef2aSThomas Huth cpu_tick_set_limit(opaque, limit); 83*fcf5ef2aSThomas Huth #endif 84*fcf5ef2aSThomas Huth } 85*fcf5ef2aSThomas Huth #endif 86*fcf5ef2aSThomas Huth 87*fcf5ef2aSThomas Huth static target_ulong do_udiv(CPUSPARCState *env, target_ulong a, 88*fcf5ef2aSThomas Huth target_ulong b, int cc, uintptr_t ra) 89*fcf5ef2aSThomas Huth { 90*fcf5ef2aSThomas Huth int overflow = 0; 91*fcf5ef2aSThomas Huth uint64_t x0; 92*fcf5ef2aSThomas Huth uint32_t x1; 93*fcf5ef2aSThomas Huth 94*fcf5ef2aSThomas Huth x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32); 95*fcf5ef2aSThomas Huth x1 = (b & 0xffffffff); 96*fcf5ef2aSThomas Huth 97*fcf5ef2aSThomas Huth if (x1 == 0) { 98*fcf5ef2aSThomas Huth cpu_raise_exception_ra(env, TT_DIV_ZERO, ra); 99*fcf5ef2aSThomas Huth } 100*fcf5ef2aSThomas Huth 101*fcf5ef2aSThomas Huth x0 = x0 / x1; 102*fcf5ef2aSThomas Huth if (x0 > UINT32_MAX) { 103*fcf5ef2aSThomas Huth x0 = UINT32_MAX; 104*fcf5ef2aSThomas Huth overflow = 1; 105*fcf5ef2aSThomas Huth } 106*fcf5ef2aSThomas Huth 107*fcf5ef2aSThomas Huth if (cc) { 108*fcf5ef2aSThomas Huth env->cc_dst = x0; 109*fcf5ef2aSThomas Huth env->cc_src2 = overflow; 110*fcf5ef2aSThomas Huth env->cc_op = CC_OP_DIV; 111*fcf5ef2aSThomas Huth } 112*fcf5ef2aSThomas Huth return x0; 113*fcf5ef2aSThomas Huth } 114*fcf5ef2aSThomas Huth 115*fcf5ef2aSThomas Huth target_ulong helper_udiv(CPUSPARCState *env, target_ulong a, target_ulong b) 116*fcf5ef2aSThomas Huth { 117*fcf5ef2aSThomas Huth return do_udiv(env, a, b, 0, GETPC()); 118*fcf5ef2aSThomas Huth } 119*fcf5ef2aSThomas Huth 120*fcf5ef2aSThomas Huth target_ulong helper_udiv_cc(CPUSPARCState *env, target_ulong a, target_ulong b) 121*fcf5ef2aSThomas Huth { 122*fcf5ef2aSThomas Huth return do_udiv(env, a, b, 1, GETPC()); 123*fcf5ef2aSThomas Huth } 124*fcf5ef2aSThomas Huth 125*fcf5ef2aSThomas Huth static target_ulong do_sdiv(CPUSPARCState *env, target_ulong a, 126*fcf5ef2aSThomas Huth target_ulong b, int cc, uintptr_t ra) 127*fcf5ef2aSThomas Huth { 128*fcf5ef2aSThomas Huth int overflow = 0; 129*fcf5ef2aSThomas Huth int64_t x0; 130*fcf5ef2aSThomas Huth int32_t x1; 131*fcf5ef2aSThomas Huth 132*fcf5ef2aSThomas Huth x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32); 133*fcf5ef2aSThomas Huth x1 = (b & 0xffffffff); 134*fcf5ef2aSThomas Huth 135*fcf5ef2aSThomas Huth if (x1 == 0) { 136*fcf5ef2aSThomas Huth cpu_raise_exception_ra(env, TT_DIV_ZERO, ra); 137*fcf5ef2aSThomas Huth } else if (x1 == -1 && x0 == INT64_MIN) { 138*fcf5ef2aSThomas Huth x0 = INT32_MAX; 139*fcf5ef2aSThomas Huth overflow = 1; 140*fcf5ef2aSThomas Huth } else { 141*fcf5ef2aSThomas Huth x0 = x0 / x1; 142*fcf5ef2aSThomas Huth if ((int32_t) x0 != x0) { 143*fcf5ef2aSThomas Huth x0 = x0 < 0 ? INT32_MIN : INT32_MAX; 144*fcf5ef2aSThomas Huth overflow = 1; 145*fcf5ef2aSThomas Huth } 146*fcf5ef2aSThomas Huth } 147*fcf5ef2aSThomas Huth 148*fcf5ef2aSThomas Huth if (cc) { 149*fcf5ef2aSThomas Huth env->cc_dst = x0; 150*fcf5ef2aSThomas Huth env->cc_src2 = overflow; 151*fcf5ef2aSThomas Huth env->cc_op = CC_OP_DIV; 152*fcf5ef2aSThomas Huth } 153*fcf5ef2aSThomas Huth return x0; 154*fcf5ef2aSThomas Huth } 155*fcf5ef2aSThomas Huth 156*fcf5ef2aSThomas Huth target_ulong helper_sdiv(CPUSPARCState *env, target_ulong a, target_ulong b) 157*fcf5ef2aSThomas Huth { 158*fcf5ef2aSThomas Huth return do_sdiv(env, a, b, 0, GETPC()); 159*fcf5ef2aSThomas Huth } 160*fcf5ef2aSThomas Huth 161*fcf5ef2aSThomas Huth target_ulong helper_sdiv_cc(CPUSPARCState *env, target_ulong a, target_ulong b) 162*fcf5ef2aSThomas Huth { 163*fcf5ef2aSThomas Huth return do_sdiv(env, a, b, 1, GETPC()); 164*fcf5ef2aSThomas Huth } 165*fcf5ef2aSThomas Huth 166*fcf5ef2aSThomas Huth #ifdef TARGET_SPARC64 167*fcf5ef2aSThomas Huth int64_t helper_sdivx(CPUSPARCState *env, int64_t a, int64_t b) 168*fcf5ef2aSThomas Huth { 169*fcf5ef2aSThomas Huth if (b == 0) { 170*fcf5ef2aSThomas Huth /* Raise divide by zero trap. */ 171*fcf5ef2aSThomas Huth cpu_raise_exception_ra(env, TT_DIV_ZERO, GETPC()); 172*fcf5ef2aSThomas Huth } else if (b == -1) { 173*fcf5ef2aSThomas Huth /* Avoid overflow trap with i386 divide insn. */ 174*fcf5ef2aSThomas Huth return -a; 175*fcf5ef2aSThomas Huth } else { 176*fcf5ef2aSThomas Huth return a / b; 177*fcf5ef2aSThomas Huth } 178*fcf5ef2aSThomas Huth } 179*fcf5ef2aSThomas Huth 180*fcf5ef2aSThomas Huth uint64_t helper_udivx(CPUSPARCState *env, uint64_t a, uint64_t b) 181*fcf5ef2aSThomas Huth { 182*fcf5ef2aSThomas Huth if (b == 0) { 183*fcf5ef2aSThomas Huth /* Raise divide by zero trap. */ 184*fcf5ef2aSThomas Huth cpu_raise_exception_ra(env, TT_DIV_ZERO, GETPC()); 185*fcf5ef2aSThomas Huth } 186*fcf5ef2aSThomas Huth return a / b; 187*fcf5ef2aSThomas Huth } 188*fcf5ef2aSThomas Huth #endif 189*fcf5ef2aSThomas Huth 190*fcf5ef2aSThomas Huth target_ulong helper_taddcctv(CPUSPARCState *env, target_ulong src1, 191*fcf5ef2aSThomas Huth target_ulong src2) 192*fcf5ef2aSThomas Huth { 193*fcf5ef2aSThomas Huth target_ulong dst; 194*fcf5ef2aSThomas Huth 195*fcf5ef2aSThomas Huth /* Tag overflow occurs if either input has bits 0 or 1 set. */ 196*fcf5ef2aSThomas Huth if ((src1 | src2) & 3) { 197*fcf5ef2aSThomas Huth goto tag_overflow; 198*fcf5ef2aSThomas Huth } 199*fcf5ef2aSThomas Huth 200*fcf5ef2aSThomas Huth dst = src1 + src2; 201*fcf5ef2aSThomas Huth 202*fcf5ef2aSThomas Huth /* Tag overflow occurs if the addition overflows. */ 203*fcf5ef2aSThomas Huth if (~(src1 ^ src2) & (src1 ^ dst) & (1u << 31)) { 204*fcf5ef2aSThomas Huth goto tag_overflow; 205*fcf5ef2aSThomas Huth } 206*fcf5ef2aSThomas Huth 207*fcf5ef2aSThomas Huth /* Only modify the CC after any exceptions have been generated. */ 208*fcf5ef2aSThomas Huth env->cc_op = CC_OP_TADDTV; 209*fcf5ef2aSThomas Huth env->cc_src = src1; 210*fcf5ef2aSThomas Huth env->cc_src2 = src2; 211*fcf5ef2aSThomas Huth env->cc_dst = dst; 212*fcf5ef2aSThomas Huth return dst; 213*fcf5ef2aSThomas Huth 214*fcf5ef2aSThomas Huth tag_overflow: 215*fcf5ef2aSThomas Huth cpu_raise_exception_ra(env, TT_TOVF, GETPC()); 216*fcf5ef2aSThomas Huth } 217*fcf5ef2aSThomas Huth 218*fcf5ef2aSThomas Huth target_ulong helper_tsubcctv(CPUSPARCState *env, target_ulong src1, 219*fcf5ef2aSThomas Huth target_ulong src2) 220*fcf5ef2aSThomas Huth { 221*fcf5ef2aSThomas Huth target_ulong dst; 222*fcf5ef2aSThomas Huth 223*fcf5ef2aSThomas Huth /* Tag overflow occurs if either input has bits 0 or 1 set. */ 224*fcf5ef2aSThomas Huth if ((src1 | src2) & 3) { 225*fcf5ef2aSThomas Huth goto tag_overflow; 226*fcf5ef2aSThomas Huth } 227*fcf5ef2aSThomas Huth 228*fcf5ef2aSThomas Huth dst = src1 - src2; 229*fcf5ef2aSThomas Huth 230*fcf5ef2aSThomas Huth /* Tag overflow occurs if the subtraction overflows. */ 231*fcf5ef2aSThomas Huth if ((src1 ^ src2) & (src1 ^ dst) & (1u << 31)) { 232*fcf5ef2aSThomas Huth goto tag_overflow; 233*fcf5ef2aSThomas Huth } 234*fcf5ef2aSThomas Huth 235*fcf5ef2aSThomas Huth /* Only modify the CC after any exceptions have been generated. */ 236*fcf5ef2aSThomas Huth env->cc_op = CC_OP_TSUBTV; 237*fcf5ef2aSThomas Huth env->cc_src = src1; 238*fcf5ef2aSThomas Huth env->cc_src2 = src2; 239*fcf5ef2aSThomas Huth env->cc_dst = dst; 240*fcf5ef2aSThomas Huth return dst; 241*fcf5ef2aSThomas Huth 242*fcf5ef2aSThomas Huth tag_overflow: 243*fcf5ef2aSThomas Huth cpu_raise_exception_ra(env, TT_TOVF, GETPC()); 244*fcf5ef2aSThomas Huth } 245*fcf5ef2aSThomas Huth 246*fcf5ef2aSThomas Huth #ifndef TARGET_SPARC64 247*fcf5ef2aSThomas Huth void helper_power_down(CPUSPARCState *env) 248*fcf5ef2aSThomas Huth { 249*fcf5ef2aSThomas Huth CPUState *cs = CPU(sparc_env_get_cpu(env)); 250*fcf5ef2aSThomas Huth 251*fcf5ef2aSThomas Huth cs->halted = 1; 252*fcf5ef2aSThomas Huth cs->exception_index = EXCP_HLT; 253*fcf5ef2aSThomas Huth env->pc = env->npc; 254*fcf5ef2aSThomas Huth env->npc = env->pc + 4; 255*fcf5ef2aSThomas Huth cpu_loop_exit(cs); 256*fcf5ef2aSThomas Huth } 257*fcf5ef2aSThomas Huth #endif 258