1 /* 2 * Helpers for vax floating point instructions. 3 * 4 * Copyright (c) 2007 Jocelyn Mayer 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 "exec/helper-proto.h" 24 #include "fpu/softfloat.h" 25 26 #define FP_STATUS (env->fp_status) 27 28 29 /* F floating (VAX) */ 30 static uint64_t float32_to_f(float32 fa) 31 { 32 uint64_t r, exp, mant, sig; 33 CPU_FloatU a; 34 35 a.f = fa; 36 sig = ((uint64_t)a.l & 0x80000000) << 32; 37 exp = (a.l >> 23) & 0xff; 38 mant = ((uint64_t)a.l & 0x007fffff) << 29; 39 40 if (exp == 255) { 41 /* NaN or infinity */ 42 r = 1; /* VAX dirty zero */ 43 } else if (exp == 0) { 44 if (mant == 0) { 45 /* Zero */ 46 r = 0; 47 } else { 48 /* Denormalized */ 49 r = sig | ((exp + 1) << 52) | mant; 50 } 51 } else { 52 if (exp >= 253) { 53 /* Overflow */ 54 r = 1; /* VAX dirty zero */ 55 } else { 56 r = sig | ((exp + 2) << 52); 57 } 58 } 59 60 return r; 61 } 62 63 static float32 f_to_float32(CPUAlphaState *env, uintptr_t retaddr, uint64_t a) 64 { 65 uint32_t exp, mant_sig; 66 CPU_FloatU r; 67 68 exp = ((a >> 55) & 0x80) | ((a >> 52) & 0x7f); 69 mant_sig = ((a >> 32) & 0x80000000) | ((a >> 29) & 0x007fffff); 70 71 if (unlikely(!exp && mant_sig)) { 72 /* Reserved operands / Dirty zero */ 73 dynamic_excp(env, retaddr, EXCP_OPCDEC, 0); 74 } 75 76 if (exp < 3) { 77 /* Underflow */ 78 r.l = 0; 79 } else { 80 r.l = ((exp - 2) << 23) | mant_sig; 81 } 82 83 return r.f; 84 } 85 86 uint32_t helper_f_to_memory(uint64_t a) 87 { 88 uint32_t r; 89 r = (a & 0x00001fffe0000000ull) >> 13; 90 r |= (a & 0x07ffe00000000000ull) >> 45; 91 r |= (a & 0xc000000000000000ull) >> 48; 92 return r; 93 } 94 95 uint64_t helper_memory_to_f(uint32_t a) 96 { 97 uint64_t r; 98 r = ((uint64_t)(a & 0x0000c000)) << 48; 99 r |= ((uint64_t)(a & 0x003fffff)) << 45; 100 r |= ((uint64_t)(a & 0xffff0000)) << 13; 101 if (!(a & 0x00004000)) { 102 r |= 0x7ll << 59; 103 } 104 return r; 105 } 106 107 /* ??? Emulating VAX arithmetic with IEEE arithmetic is wrong. We should 108 either implement VAX arithmetic properly or just signal invalid opcode. */ 109 110 uint64_t helper_addf(CPUAlphaState *env, uint64_t a, uint64_t b) 111 { 112 float32 fa, fb, fr; 113 114 fa = f_to_float32(env, GETPC(), a); 115 fb = f_to_float32(env, GETPC(), b); 116 fr = float32_add(fa, fb, &FP_STATUS); 117 return float32_to_f(fr); 118 } 119 120 uint64_t helper_subf(CPUAlphaState *env, uint64_t a, uint64_t b) 121 { 122 float32 fa, fb, fr; 123 124 fa = f_to_float32(env, GETPC(), a); 125 fb = f_to_float32(env, GETPC(), b); 126 fr = float32_sub(fa, fb, &FP_STATUS); 127 return float32_to_f(fr); 128 } 129 130 uint64_t helper_mulf(CPUAlphaState *env, uint64_t a, uint64_t b) 131 { 132 float32 fa, fb, fr; 133 134 fa = f_to_float32(env, GETPC(), a); 135 fb = f_to_float32(env, GETPC(), b); 136 fr = float32_mul(fa, fb, &FP_STATUS); 137 return float32_to_f(fr); 138 } 139 140 uint64_t helper_divf(CPUAlphaState *env, uint64_t a, uint64_t b) 141 { 142 float32 fa, fb, fr; 143 144 fa = f_to_float32(env, GETPC(), a); 145 fb = f_to_float32(env, GETPC(), b); 146 fr = float32_div(fa, fb, &FP_STATUS); 147 return float32_to_f(fr); 148 } 149 150 uint64_t helper_sqrtf(CPUAlphaState *env, uint64_t t) 151 { 152 float32 ft, fr; 153 154 ft = f_to_float32(env, GETPC(), t); 155 fr = float32_sqrt(ft, &FP_STATUS); 156 return float32_to_f(fr); 157 } 158 159 160 /* G floating (VAX) */ 161 static uint64_t float64_to_g(float64 fa) 162 { 163 uint64_t r, exp, mant, sig; 164 CPU_DoubleU a; 165 166 a.d = fa; 167 sig = a.ll & 0x8000000000000000ull; 168 exp = (a.ll >> 52) & 0x7ff; 169 mant = a.ll & 0x000fffffffffffffull; 170 171 if (exp == 2047) { 172 /* NaN or infinity */ 173 r = 1; /* VAX dirty zero */ 174 } else if (exp == 0) { 175 if (mant == 0) { 176 /* Zero */ 177 r = 0; 178 } else { 179 /* Denormalized */ 180 r = sig | ((exp + 1) << 52) | mant; 181 } 182 } else { 183 if (exp >= 2045) { 184 /* Overflow */ 185 r = 1; /* VAX dirty zero */ 186 } else { 187 r = sig | ((exp + 2) << 52); 188 } 189 } 190 191 return r; 192 } 193 194 static float64 g_to_float64(CPUAlphaState *env, uintptr_t retaddr, uint64_t a) 195 { 196 uint64_t exp, mant_sig; 197 CPU_DoubleU r; 198 199 exp = (a >> 52) & 0x7ff; 200 mant_sig = a & 0x800fffffffffffffull; 201 202 if (!exp && mant_sig) { 203 /* Reserved operands / Dirty zero */ 204 dynamic_excp(env, retaddr, EXCP_OPCDEC, 0); 205 } 206 207 if (exp < 3) { 208 /* Underflow */ 209 r.ll = 0; 210 } else { 211 r.ll = ((exp - 2) << 52) | mant_sig; 212 } 213 214 return r.d; 215 } 216 217 uint64_t helper_g_to_memory(uint64_t a) 218 { 219 uint64_t r; 220 r = (a & 0x000000000000ffffull) << 48; 221 r |= (a & 0x00000000ffff0000ull) << 16; 222 r |= (a & 0x0000ffff00000000ull) >> 16; 223 r |= (a & 0xffff000000000000ull) >> 48; 224 return r; 225 } 226 227 uint64_t helper_memory_to_g(uint64_t a) 228 { 229 uint64_t r; 230 r = (a & 0x000000000000ffffull) << 48; 231 r |= (a & 0x00000000ffff0000ull) << 16; 232 r |= (a & 0x0000ffff00000000ull) >> 16; 233 r |= (a & 0xffff000000000000ull) >> 48; 234 return r; 235 } 236 237 uint64_t helper_addg(CPUAlphaState *env, uint64_t a, uint64_t b) 238 { 239 float64 fa, fb, fr; 240 241 fa = g_to_float64(env, GETPC(), a); 242 fb = g_to_float64(env, GETPC(), b); 243 fr = float64_add(fa, fb, &FP_STATUS); 244 return float64_to_g(fr); 245 } 246 247 uint64_t helper_subg(CPUAlphaState *env, uint64_t a, uint64_t b) 248 { 249 float64 fa, fb, fr; 250 251 fa = g_to_float64(env, GETPC(), a); 252 fb = g_to_float64(env, GETPC(), b); 253 fr = float64_sub(fa, fb, &FP_STATUS); 254 return float64_to_g(fr); 255 } 256 257 uint64_t helper_mulg(CPUAlphaState *env, uint64_t a, uint64_t b) 258 { 259 float64 fa, fb, fr; 260 261 fa = g_to_float64(env, GETPC(), a); 262 fb = g_to_float64(env, GETPC(), b); 263 fr = float64_mul(fa, fb, &FP_STATUS); 264 return float64_to_g(fr); 265 } 266 267 uint64_t helper_divg(CPUAlphaState *env, uint64_t a, uint64_t b) 268 { 269 float64 fa, fb, fr; 270 271 fa = g_to_float64(env, GETPC(), a); 272 fb = g_to_float64(env, GETPC(), b); 273 fr = float64_div(fa, fb, &FP_STATUS); 274 return float64_to_g(fr); 275 } 276 277 uint64_t helper_sqrtg(CPUAlphaState *env, uint64_t a) 278 { 279 float64 fa, fr; 280 281 fa = g_to_float64(env, GETPC(), a); 282 fr = float64_sqrt(fa, &FP_STATUS); 283 return float64_to_g(fr); 284 } 285 286 uint64_t helper_cmpgeq(CPUAlphaState *env, uint64_t a, uint64_t b) 287 { 288 float64 fa, fb; 289 290 fa = g_to_float64(env, GETPC(), a); 291 fb = g_to_float64(env, GETPC(), b); 292 293 if (float64_eq_quiet(fa, fb, &FP_STATUS)) { 294 return 0x4000000000000000ULL; 295 } else { 296 return 0; 297 } 298 } 299 300 uint64_t helper_cmpgle(CPUAlphaState *env, uint64_t a, uint64_t b) 301 { 302 float64 fa, fb; 303 304 fa = g_to_float64(env, GETPC(), a); 305 fb = g_to_float64(env, GETPC(), b); 306 307 if (float64_le(fa, fb, &FP_STATUS)) { 308 return 0x4000000000000000ULL; 309 } else { 310 return 0; 311 } 312 } 313 314 uint64_t helper_cmpglt(CPUAlphaState *env, uint64_t a, uint64_t b) 315 { 316 float64 fa, fb; 317 318 fa = g_to_float64(env, GETPC(), a); 319 fb = g_to_float64(env, GETPC(), b); 320 321 if (float64_lt(fa, fb, &FP_STATUS)) { 322 return 0x4000000000000000ULL; 323 } else { 324 return 0; 325 } 326 } 327 328 uint64_t helper_cvtqf(CPUAlphaState *env, uint64_t a) 329 { 330 float32 fr = int64_to_float32(a, &FP_STATUS); 331 return float32_to_f(fr); 332 } 333 334 uint64_t helper_cvtgf(CPUAlphaState *env, uint64_t a) 335 { 336 float64 fa; 337 float32 fr; 338 339 fa = g_to_float64(env, GETPC(), a); 340 fr = float64_to_float32(fa, &FP_STATUS); 341 return float32_to_f(fr); 342 } 343 344 uint64_t helper_cvtgq(CPUAlphaState *env, uint64_t a) 345 { 346 float64 fa = g_to_float64(env, GETPC(), a); 347 return float64_to_int64_round_to_zero(fa, &FP_STATUS); 348 } 349 350 uint64_t helper_cvtqg(CPUAlphaState *env, uint64_t a) 351 { 352 float64 fr; 353 fr = int64_to_float64(a, &FP_STATUS); 354 return float64_to_g(fr); 355 } 356