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