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.1 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/timer.h" 24 #include "qemu/host-utils.h" 25 #include "exec/helper-proto.h" 26 27 void cpu_raise_exception_ra(CPUSPARCState *env, int tt, uintptr_t ra) 28 { 29 CPUState *cs = env_cpu(env); 30 31 cs->exception_index = tt; 32 cpu_loop_exit_restore(cs, ra); 33 } 34 35 void helper_raise_exception(CPUSPARCState *env, int tt) 36 { 37 CPUState *cs = env_cpu(env); 38 39 cs->exception_index = tt; 40 cpu_loop_exit(cs); 41 } 42 43 void helper_debug(CPUSPARCState *env) 44 { 45 CPUState *cs = env_cpu(env); 46 47 cs->exception_index = EXCP_DEBUG; 48 cpu_loop_exit(cs); 49 } 50 51 #ifdef TARGET_SPARC64 52 void 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 59 uint64_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 /* In user-mode, QEMU_CLOCK_VIRTUAL doesn't exist. 71 Just pass through the host cpu clock ticks. */ 72 return cpu_get_host_ticks(); 73 #endif 74 } 75 76 void helper_tick_set_limit(void *opaque, uint64_t limit) 77 { 78 #if !defined(CONFIG_USER_ONLY) 79 cpu_tick_set_limit(opaque, limit); 80 #endif 81 } 82 #endif 83 84 uint64_t helper_udiv(CPUSPARCState *env, target_ulong a, target_ulong b) 85 { 86 uint64_t a64 = (uint32_t)a | ((uint64_t)env->y << 32); 87 uint32_t b32 = b; 88 uint32_t r; 89 90 if (b32 == 0) { 91 cpu_raise_exception_ra(env, TT_DIV_ZERO, GETPC()); 92 } 93 94 a64 /= b32; 95 r = a64; 96 if (unlikely(a64 > UINT32_MAX)) { 97 return -1; /* r = UINT32_MAX, v = 1 */ 98 } 99 return r; 100 } 101 102 uint64_t helper_sdiv(CPUSPARCState *env, target_ulong a, target_ulong b) 103 { 104 int64_t a64 = (uint32_t)a | ((uint64_t)env->y << 32); 105 int32_t b32 = b; 106 int32_t r; 107 108 if (b32 == 0) { 109 cpu_raise_exception_ra(env, TT_DIV_ZERO, GETPC()); 110 } 111 112 if (unlikely(a64 == INT64_MIN)) { 113 /* 114 * Special case INT64_MIN / -1 is required to avoid trap on x86 host. 115 * However, with a dividend of INT64_MIN, there is no 32-bit divisor 116 * which can yield a 32-bit result: 117 * INT64_MIN / INT32_MIN = 0x1_0000_0000 118 * INT64_MIN / INT32_MAX = -0x1_0000_0002 119 * Therefore we know we must overflow and saturate. 120 */ 121 return (uint32_t)(b32 < 0 ? INT32_MAX : INT32_MIN) | (-1ull << 32); 122 } 123 124 a64 /= b; 125 r = a64; 126 if (unlikely(r != a64)) { 127 return (uint32_t)(a64 < 0 ? INT32_MIN : INT32_MAX) | (-1ull << 32); 128 } 129 return (uint32_t)r; 130 } 131 132 target_ulong helper_taddcctv(CPUSPARCState *env, target_ulong src1, 133 target_ulong src2) 134 { 135 target_ulong dst, v; 136 137 /* Tag overflow occurs if either input has bits 0 or 1 set. */ 138 if ((src1 | src2) & 3) { 139 goto tag_overflow; 140 } 141 142 dst = src1 + src2; 143 144 /* Tag overflow occurs if the addition overflows. */ 145 v = ~(src1 ^ src2) & (src1 ^ dst); 146 if (v & (1u << 31)) { 147 goto tag_overflow; 148 } 149 150 /* Only modify the CC after any exceptions have been generated. */ 151 env->cc_V = v; 152 env->cc_N = dst; 153 env->icc_Z = dst; 154 #ifdef TARGET_SPARC64 155 env->xcc_Z = dst; 156 env->icc_C = dst ^ src1 ^ src2; 157 env->xcc_C = dst < src1; 158 #else 159 env->icc_C = dst < src1; 160 #endif 161 162 return dst; 163 164 tag_overflow: 165 cpu_raise_exception_ra(env, TT_TOVF, GETPC()); 166 } 167 168 target_ulong helper_tsubcctv(CPUSPARCState *env, target_ulong src1, 169 target_ulong src2) 170 { 171 target_ulong dst, v; 172 173 /* Tag overflow occurs if either input has bits 0 or 1 set. */ 174 if ((src1 | src2) & 3) { 175 goto tag_overflow; 176 } 177 178 dst = src1 - src2; 179 180 /* Tag overflow occurs if the subtraction overflows. */ 181 v = (src1 ^ src2) & (src1 ^ dst); 182 if (v & (1u << 31)) { 183 goto tag_overflow; 184 } 185 186 /* Only modify the CC after any exceptions have been generated. */ 187 env->cc_V = v; 188 env->cc_N = dst; 189 env->icc_Z = dst; 190 #ifdef TARGET_SPARC64 191 env->xcc_Z = dst; 192 env->icc_C = dst ^ src1 ^ src2; 193 env->xcc_C = src1 < src2; 194 #else 195 env->icc_C = src1 < src2; 196 #endif 197 198 return dst; 199 200 tag_overflow: 201 cpu_raise_exception_ra(env, TT_TOVF, GETPC()); 202 } 203 204 #ifndef TARGET_SPARC64 205 void helper_power_down(CPUSPARCState *env) 206 { 207 CPUState *cs = env_cpu(env); 208 209 cs->halted = 1; 210 cs->exception_index = EXCP_HLT; 211 env->pc = env->npc; 212 env->npc = env->pc + 4; 213 cpu_loop_exit(cs); 214 } 215 #endif 216