Revision 4373f3ce target-arm/helper.c
b/target-arm/helper.c | ||
---|---|---|
2167 | 2167 |
return (a & mask) | (b & ~mask); |
2168 | 2168 |
} |
2169 | 2169 |
|
2170 |
|
|
2171 |
/* VFP support. We follow the convention used for VFP instrunctions: |
|
2172 |
Single precition routines have a "s" suffix, double precision a |
|
2173 |
"d" suffix. */ |
|
2174 |
|
|
2175 |
/* Convert host exception flags to vfp form. */ |
|
2176 |
static inline int vfp_exceptbits_from_host(int host_bits) |
|
2177 |
{ |
|
2178 |
int target_bits = 0; |
|
2179 |
|
|
2180 |
if (host_bits & float_flag_invalid) |
|
2181 |
target_bits |= 1; |
|
2182 |
if (host_bits & float_flag_divbyzero) |
|
2183 |
target_bits |= 2; |
|
2184 |
if (host_bits & float_flag_overflow) |
|
2185 |
target_bits |= 4; |
|
2186 |
if (host_bits & float_flag_underflow) |
|
2187 |
target_bits |= 8; |
|
2188 |
if (host_bits & float_flag_inexact) |
|
2189 |
target_bits |= 0x10; |
|
2190 |
return target_bits; |
|
2191 |
} |
|
2192 |
|
|
2193 |
uint32_t HELPER(vfp_get_fpscr)(CPUState *env) |
|
2194 |
{ |
|
2195 |
int i; |
|
2196 |
uint32_t fpscr; |
|
2197 |
|
|
2198 |
fpscr = (env->vfp.xregs[ARM_VFP_FPSCR] & 0xffc8ffff) |
|
2199 |
| (env->vfp.vec_len << 16) |
|
2200 |
| (env->vfp.vec_stride << 20); |
|
2201 |
i = get_float_exception_flags(&env->vfp.fp_status); |
|
2202 |
fpscr |= vfp_exceptbits_from_host(i); |
|
2203 |
return fpscr; |
|
2204 |
} |
|
2205 |
|
|
2206 |
/* Convert vfp exception flags to target form. */ |
|
2207 |
static inline int vfp_exceptbits_to_host(int target_bits) |
|
2208 |
{ |
|
2209 |
int host_bits = 0; |
|
2210 |
|
|
2211 |
if (target_bits & 1) |
|
2212 |
host_bits |= float_flag_invalid; |
|
2213 |
if (target_bits & 2) |
|
2214 |
host_bits |= float_flag_divbyzero; |
|
2215 |
if (target_bits & 4) |
|
2216 |
host_bits |= float_flag_overflow; |
|
2217 |
if (target_bits & 8) |
|
2218 |
host_bits |= float_flag_underflow; |
|
2219 |
if (target_bits & 0x10) |
|
2220 |
host_bits |= float_flag_inexact; |
|
2221 |
return host_bits; |
|
2222 |
} |
|
2223 |
|
|
2224 |
void HELPER(vfp_set_fpscr)(CPUState *env, uint32_t val) |
|
2225 |
{ |
|
2226 |
int i; |
|
2227 |
uint32_t changed; |
|
2228 |
|
|
2229 |
changed = env->vfp.xregs[ARM_VFP_FPSCR]; |
|
2230 |
env->vfp.xregs[ARM_VFP_FPSCR] = (val & 0xffc8ffff); |
|
2231 |
env->vfp.vec_len = (val >> 16) & 7; |
|
2232 |
env->vfp.vec_stride = (val >> 20) & 3; |
|
2233 |
|
|
2234 |
changed ^= val; |
|
2235 |
if (changed & (3 << 22)) { |
|
2236 |
i = (val >> 22) & 3; |
|
2237 |
switch (i) { |
|
2238 |
case 0: |
|
2239 |
i = float_round_nearest_even; |
|
2240 |
break; |
|
2241 |
case 1: |
|
2242 |
i = float_round_up; |
|
2243 |
break; |
|
2244 |
case 2: |
|
2245 |
i = float_round_down; |
|
2246 |
break; |
|
2247 |
case 3: |
|
2248 |
i = float_round_to_zero; |
|
2249 |
break; |
|
2250 |
} |
|
2251 |
set_float_rounding_mode(i, &env->vfp.fp_status); |
|
2252 |
} |
|
2253 |
|
|
2254 |
i = vfp_exceptbits_to_host((val >> 8) & 0x1f); |
|
2255 |
set_float_exception_flags(i, &env->vfp.fp_status); |
|
2256 |
/* XXX: FZ and DN are not implemented. */ |
|
2257 |
} |
|
2258 |
|
|
2259 |
#define VFP_HELPER(name, p) HELPER(glue(glue(vfp_,name),p)) |
|
2260 |
|
|
2261 |
#define VFP_BINOP(name) \ |
|
2262 |
float32 VFP_HELPER(name, s)(float32 a, float32 b, CPUState *env) \ |
|
2263 |
{ \ |
|
2264 |
return float32_ ## name (a, b, &env->vfp.fp_status); \ |
|
2265 |
} \ |
|
2266 |
float64 VFP_HELPER(name, d)(float64 a, float64 b, CPUState *env) \ |
|
2267 |
{ \ |
|
2268 |
return float64_ ## name (a, b, &env->vfp.fp_status); \ |
|
2269 |
} |
|
2270 |
VFP_BINOP(add) |
|
2271 |
VFP_BINOP(sub) |
|
2272 |
VFP_BINOP(mul) |
|
2273 |
VFP_BINOP(div) |
|
2274 |
#undef VFP_BINOP |
|
2275 |
|
|
2276 |
float32 VFP_HELPER(neg, s)(float32 a) |
|
2277 |
{ |
|
2278 |
return float32_chs(a); |
|
2279 |
} |
|
2280 |
|
|
2281 |
float64 VFP_HELPER(neg, d)(float64 a) |
|
2282 |
{ |
|
2283 |
return float32_chs(a); |
|
2284 |
} |
|
2285 |
|
|
2286 |
float32 VFP_HELPER(abs, s)(float32 a) |
|
2287 |
{ |
|
2288 |
return float32_abs(a); |
|
2289 |
} |
|
2290 |
|
|
2291 |
float64 VFP_HELPER(abs, d)(float64 a) |
|
2292 |
{ |
|
2293 |
return float32_abs(a); |
|
2294 |
} |
|
2295 |
|
|
2296 |
float32 VFP_HELPER(sqrt, s)(float32 a, CPUState *env) |
|
2297 |
{ |
|
2298 |
return float32_sqrt(a, &env->vfp.fp_status); |
|
2299 |
} |
|
2300 |
|
|
2301 |
float64 VFP_HELPER(sqrt, d)(float64 a, CPUState *env) |
|
2302 |
{ |
|
2303 |
return float64_sqrt(a, &env->vfp.fp_status); |
|
2304 |
} |
|
2305 |
|
|
2306 |
/* XXX: check quiet/signaling case */ |
|
2307 |
#define DO_VFP_cmp(p, type) \ |
|
2308 |
void VFP_HELPER(cmp, p)(type a, type b, CPUState *env) \ |
|
2309 |
{ \ |
|
2310 |
uint32_t flags; \ |
|
2311 |
switch(type ## _compare_quiet(a, b, &env->vfp.fp_status)) { \ |
|
2312 |
case 0: flags = 0x6; break; \ |
|
2313 |
case -1: flags = 0x8; break; \ |
|
2314 |
case 1: flags = 0x2; break; \ |
|
2315 |
default: case 2: flags = 0x3; break; \ |
|
2316 |
} \ |
|
2317 |
env->vfp.xregs[ARM_VFP_FPSCR] = (flags << 28) \ |
|
2318 |
| (env->vfp.xregs[ARM_VFP_FPSCR] & 0x0fffffff); \ |
|
2319 |
} \ |
|
2320 |
void VFP_HELPER(cmpe, p)(type a, type b, CPUState *env) \ |
|
2321 |
{ \ |
|
2322 |
uint32_t flags; \ |
|
2323 |
switch(type ## _compare(a, b, &env->vfp.fp_status)) { \ |
|
2324 |
case 0: flags = 0x6; break; \ |
|
2325 |
case -1: flags = 0x8; break; \ |
|
2326 |
case 1: flags = 0x2; break; \ |
|
2327 |
default: case 2: flags = 0x3; break; \ |
|
2328 |
} \ |
|
2329 |
env->vfp.xregs[ARM_VFP_FPSCR] = (flags << 28) \ |
|
2330 |
| (env->vfp.xregs[ARM_VFP_FPSCR] & 0x0fffffff); \ |
|
2331 |
} |
|
2332 |
DO_VFP_cmp(s, float32) |
|
2333 |
DO_VFP_cmp(d, float64) |
|
2334 |
#undef DO_VFP_cmp |
|
2335 |
|
|
2336 |
/* Helper routines to perform bitwise copies between float and int. */ |
|
2337 |
static inline float32 vfp_itos(uint32_t i) |
|
2338 |
{ |
|
2339 |
union { |
|
2340 |
uint32_t i; |
|
2341 |
float32 s; |
|
2342 |
} v; |
|
2343 |
|
|
2344 |
v.i = i; |
|
2345 |
return v.s; |
|
2346 |
} |
|
2347 |
|
|
2348 |
static inline uint32_t vfp_stoi(float32 s) |
|
2349 |
{ |
|
2350 |
union { |
|
2351 |
uint32_t i; |
|
2352 |
float32 s; |
|
2353 |
} v; |
|
2354 |
|
|
2355 |
v.s = s; |
|
2356 |
return v.i; |
|
2357 |
} |
|
2358 |
|
|
2359 |
static inline float64 vfp_itod(uint64_t i) |
|
2360 |
{ |
|
2361 |
union { |
|
2362 |
uint64_t i; |
|
2363 |
float64 d; |
|
2364 |
} v; |
|
2365 |
|
|
2366 |
v.i = i; |
|
2367 |
return v.d; |
|
2368 |
} |
|
2369 |
|
|
2370 |
static inline uint64_t vfp_dtoi(float64 d) |
|
2371 |
{ |
|
2372 |
union { |
|
2373 |
uint64_t i; |
|
2374 |
float64 d; |
|
2375 |
} v; |
|
2376 |
|
|
2377 |
v.d = d; |
|
2378 |
return v.i; |
|
2379 |
} |
|
2380 |
|
|
2381 |
/* Integer to float conversion. */ |
|
2382 |
float32 VFP_HELPER(uito, s)(float32 x, CPUState *env) |
|
2383 |
{ |
|
2384 |
return uint32_to_float32(vfp_stoi(x), &env->vfp.fp_status); |
|
2385 |
} |
|
2386 |
|
|
2387 |
float64 VFP_HELPER(uito, d)(float32 x, CPUState *env) |
|
2388 |
{ |
|
2389 |
return uint32_to_float64(vfp_stoi(x), &env->vfp.fp_status); |
|
2390 |
} |
|
2391 |
|
|
2392 |
float32 VFP_HELPER(sito, s)(float32 x, CPUState *env) |
|
2393 |
{ |
|
2394 |
return int32_to_float32(vfp_stoi(x), &env->vfp.fp_status); |
|
2395 |
} |
|
2396 |
|
|
2397 |
float64 VFP_HELPER(sito, d)(float32 x, CPUState *env) |
|
2398 |
{ |
|
2399 |
return int32_to_float64(vfp_stoi(x), &env->vfp.fp_status); |
|
2400 |
} |
|
2401 |
|
|
2402 |
/* Float to integer conversion. */ |
|
2403 |
float32 VFP_HELPER(toui, s)(float32 x, CPUState *env) |
|
2404 |
{ |
|
2405 |
return vfp_itos(float32_to_uint32(x, &env->vfp.fp_status)); |
|
2406 |
} |
|
2407 |
|
|
2408 |
float32 VFP_HELPER(toui, d)(float64 x, CPUState *env) |
|
2409 |
{ |
|
2410 |
return vfp_itos(float64_to_uint32(x, &env->vfp.fp_status)); |
|
2411 |
} |
|
2412 |
|
|
2413 |
float32 VFP_HELPER(tosi, s)(float32 x, CPUState *env) |
|
2414 |
{ |
|
2415 |
return vfp_itos(float32_to_int32(x, &env->vfp.fp_status)); |
|
2416 |
} |
|
2417 |
|
|
2418 |
float32 VFP_HELPER(tosi, d)(float64 x, CPUState *env) |
|
2419 |
{ |
|
2420 |
return vfp_itos(float64_to_int32(x, &env->vfp.fp_status)); |
|
2421 |
} |
|
2422 |
|
|
2423 |
float32 VFP_HELPER(touiz, s)(float32 x, CPUState *env) |
|
2424 |
{ |
|
2425 |
return vfp_itos(float32_to_uint32_round_to_zero(x, &env->vfp.fp_status)); |
|
2426 |
} |
|
2427 |
|
|
2428 |
float32 VFP_HELPER(touiz, d)(float64 x, CPUState *env) |
|
2429 |
{ |
|
2430 |
return vfp_itos(float64_to_uint32_round_to_zero(x, &env->vfp.fp_status)); |
|
2431 |
} |
|
2432 |
|
|
2433 |
float32 VFP_HELPER(tosiz, s)(float32 x, CPUState *env) |
|
2434 |
{ |
|
2435 |
return vfp_itos(float32_to_int32_round_to_zero(x, &env->vfp.fp_status)); |
|
2436 |
} |
|
2437 |
|
|
2438 |
float32 VFP_HELPER(tosiz, d)(float64 x, CPUState *env) |
|
2439 |
{ |
|
2440 |
return vfp_itos(float64_to_int32_round_to_zero(x, &env->vfp.fp_status)); |
|
2441 |
} |
|
2442 |
|
|
2443 |
/* floating point conversion */ |
|
2444 |
float64 VFP_HELPER(fcvtd, s)(float32 x, CPUState *env) |
|
2445 |
{ |
|
2446 |
return float32_to_float64(x, &env->vfp.fp_status); |
|
2447 |
} |
|
2448 |
|
|
2449 |
float32 VFP_HELPER(fcvts, d)(float64 x, CPUState *env) |
|
2450 |
{ |
|
2451 |
return float64_to_float32(x, &env->vfp.fp_status); |
|
2452 |
} |
|
2453 |
|
|
2454 |
/* VFP3 fixed point conversion. */ |
|
2455 |
#define VFP_CONV_FIX(name, p, ftype, itype, sign) \ |
|
2456 |
ftype VFP_HELPER(name##to, p)(ftype x, uint32_t shift, CPUState *env) \ |
|
2457 |
{ \ |
|
2458 |
ftype tmp; \ |
|
2459 |
tmp = sign##int32_to_##ftype ((itype)vfp_##p##toi(x), \ |
|
2460 |
&env->vfp.fp_status); \ |
|
2461 |
return ftype##_scalbn(tmp, shift, &env->vfp.fp_status); \ |
|
2462 |
} \ |
|
2463 |
ftype VFP_HELPER(to##name, p)(ftype x, uint32_t shift, CPUState *env) \ |
|
2464 |
{ \ |
|
2465 |
ftype tmp; \ |
|
2466 |
tmp = ftype##_scalbn(x, shift, &env->vfp.fp_status); \ |
|
2467 |
return vfp_ito##p((itype)ftype##_to_##sign##int32_round_to_zero(tmp, \ |
|
2468 |
&env->vfp.fp_status)); \ |
|
2469 |
} |
|
2470 |
|
|
2471 |
VFP_CONV_FIX(sh, d, float64, int16, ) |
|
2472 |
VFP_CONV_FIX(sl, d, float64, int32, ) |
|
2473 |
VFP_CONV_FIX(uh, d, float64, uint16, u) |
|
2474 |
VFP_CONV_FIX(ul, d, float64, uint32, u) |
|
2475 |
VFP_CONV_FIX(sh, s, float32, int16, ) |
|
2476 |
VFP_CONV_FIX(sl, s, float32, int32, ) |
|
2477 |
VFP_CONV_FIX(uh, s, float32, uint16, u) |
|
2478 |
VFP_CONV_FIX(ul, s, float32, uint32, u) |
|
2479 |
#undef VFP_CONV_FIX |
|
2480 |
|
|
2481 |
float32 HELPER(recps_f32)(float32 a, float32 b, CPUState *env) |
|
2482 |
{ |
|
2483 |
float_status *s = &env->vfp.fp_status; |
|
2484 |
float32 two = int32_to_float32(2, s); |
|
2485 |
return float32_sub(two, float32_mul(a, b, s), s); |
|
2486 |
} |
|
2487 |
|
|
2488 |
float32 HELPER(rsqrts_f32)(float32 a, float32 b, CPUState *env) |
|
2489 |
{ |
|
2490 |
float_status *s = &env->vfp.fp_status; |
|
2491 |
float32 three = int32_to_float32(3, s); |
|
2492 |
return float32_sub(three, float32_mul(a, b, s), s); |
|
2493 |
} |
|
2494 |
|
|
2495 |
/* TODO: The architecture specifies the value that the estimate functions |
|
2496 |
should return. We return the exact reciprocal/root instead. */ |
|
2497 |
float32 HELPER(recpe_f32)(float32 a, CPUState *env) |
|
2498 |
{ |
|
2499 |
float_status *s = &env->vfp.fp_status; |
|
2500 |
float32 one = int32_to_float32(1, s); |
|
2501 |
return float32_div(one, a, s); |
|
2502 |
} |
|
2503 |
|
|
2504 |
float32 HELPER(rsqrte_f32)(float32 a, CPUState *env) |
|
2505 |
{ |
|
2506 |
float_status *s = &env->vfp.fp_status; |
|
2507 |
float32 one = int32_to_float32(1, s); |
|
2508 |
return float32_div(one, float32_sqrt(a, s), s); |
|
2509 |
} |
|
2510 |
|
|
2511 |
uint32_t HELPER(recpe_u32)(uint32_t a, CPUState *env) |
|
2512 |
{ |
|
2513 |
float_status *s = &env->vfp.fp_status; |
|
2514 |
float32 tmp; |
|
2515 |
tmp = int32_to_float32(a, s); |
|
2516 |
tmp = float32_scalbn(tmp, -32, s); |
|
2517 |
tmp = helper_recpe_f32(tmp, env); |
|
2518 |
tmp = float32_scalbn(tmp, 31, s); |
|
2519 |
return float32_to_int32(tmp, s); |
|
2520 |
} |
|
2521 |
|
|
2522 |
uint32_t HELPER(rsqrte_u32)(uint32_t a, CPUState *env) |
|
2523 |
{ |
|
2524 |
float_status *s = &env->vfp.fp_status; |
|
2525 |
float32 tmp; |
|
2526 |
tmp = int32_to_float32(a, s); |
|
2527 |
tmp = float32_scalbn(tmp, -32, s); |
|
2528 |
tmp = helper_rsqrte_f32(tmp, env); |
|
2529 |
tmp = float32_scalbn(tmp, 31, s); |
|
2530 |
return float32_to_int32(tmp, s); |
|
2531 |
} |
|
2532 |
|
Also available in: Unified diff