Revision 4373f3ce
b/target-arm/cpu.h | ||
---|---|---|
168 | 168 |
int vec_len; |
169 | 169 |
int vec_stride; |
170 | 170 |
|
171 |
/* Temporary variables if we don't have spare fp regs. */ |
|
172 |
float32 tmp0s, tmp1s; |
|
173 |
float64 tmp0d, tmp1d; |
|
174 | 171 |
/* scratch space when Tn are not sufficient. */ |
175 | 172 |
uint32_t scratch[8]; |
176 | 173 |
|
b/target-arm/exec.h | ||
---|---|---|
25 | 25 |
register uint32_t T1 asm(AREG2); |
26 | 26 |
register uint32_t T2 asm(AREG3); |
27 | 27 |
|
28 |
/* TODO: Put these in FP regs on targets that have such things. */ |
|
29 |
/* It is ok for FT0s and FT0d to overlap. Likewise FT1s and FT1d. */ |
|
30 |
#define FT0s env->vfp.tmp0s |
|
31 |
#define FT1s env->vfp.tmp1s |
|
32 |
#define FT0d env->vfp.tmp0d |
|
33 |
#define FT1d env->vfp.tmp1d |
|
34 |
|
|
35 | 28 |
#define M0 env->iwmmxt.val |
36 | 29 |
|
37 | 30 |
#include "cpu.h" |
... | ... | |
83 | 76 |
|
84 | 77 |
void raise_exception(int); |
85 | 78 |
|
86 |
void do_vfp_abss(void); |
|
87 |
void do_vfp_absd(void); |
|
88 |
void do_vfp_negs(void); |
|
89 |
void do_vfp_negd(void); |
|
90 |
void do_vfp_sqrts(void); |
|
91 |
void do_vfp_sqrtd(void); |
|
92 |
void do_vfp_cmps(void); |
|
93 |
void do_vfp_cmpd(void); |
|
94 |
void do_vfp_cmpes(void); |
|
95 |
void do_vfp_cmped(void); |
|
96 |
void do_vfp_set_fpscr(void); |
|
97 |
void do_vfp_get_fpscr(void); |
|
98 |
float32 helper_recps_f32(float32, float32); |
|
99 |
float32 helper_rsqrts_f32(float32, float32); |
|
100 |
uint32_t helper_recpe_u32(uint32_t); |
|
101 |
uint32_t helper_rsqrte_u32(uint32_t); |
|
102 |
float32 helper_recpe_f32(float32); |
|
103 |
float32 helper_rsqrte_f32(float32); |
|
104 | 79 |
void helper_neon_tbl(int rn, int maxindex); |
105 | 80 |
uint32_t helper_neon_mul_p8(uint32_t op1, uint32_t op2); |
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 |
|
b/target-arm/helpers.h | ||
---|---|---|
122 | 122 |
DEF_HELPER_1_1(get_user_reg, uint32_t, (uint32_t)) |
123 | 123 |
DEF_HELPER_0_2(set_user_reg, void, (uint32_t, uint32_t)) |
124 | 124 |
|
125 |
DEF_HELPER_1_1(vfp_get_fpscr, uint32_t, (CPUState *)) |
|
126 |
DEF_HELPER_0_2(vfp_set_fpscr, void, (CPUState *, uint32_t)) |
|
127 |
|
|
128 |
DEF_HELPER_1_3(vfp_adds, float32, (float32, float32, CPUState *)) |
|
129 |
DEF_HELPER_1_3(vfp_addd, float64, (float64, float64, CPUState *)) |
|
130 |
DEF_HELPER_1_3(vfp_subs, float32, (float32, float32, CPUState *)) |
|
131 |
DEF_HELPER_1_3(vfp_subd, float64, (float64, float64, CPUState *)) |
|
132 |
DEF_HELPER_1_3(vfp_muls, float32, (float32, float32, CPUState *)) |
|
133 |
DEF_HELPER_1_3(vfp_muld, float64, (float64, float64, CPUState *)) |
|
134 |
DEF_HELPER_1_3(vfp_divs, float32, (float32, float32, CPUState *)) |
|
135 |
DEF_HELPER_1_3(vfp_divd, float64, (float64, float64, CPUState *)) |
|
136 |
DEF_HELPER_1_1(vfp_negs, float32, (float32)) |
|
137 |
DEF_HELPER_1_1(vfp_negd, float64, (float64)) |
|
138 |
DEF_HELPER_1_1(vfp_abss, float32, (float32)) |
|
139 |
DEF_HELPER_1_1(vfp_absd, float64, (float64)) |
|
140 |
DEF_HELPER_1_2(vfp_sqrts, float32, (float32, CPUState *)) |
|
141 |
DEF_HELPER_1_2(vfp_sqrtd, float64, (float64, CPUState *)) |
|
142 |
DEF_HELPER_0_3(vfp_cmps, void, (float32, float32, CPUState *)) |
|
143 |
DEF_HELPER_0_3(vfp_cmpd, void, (float64, float64, CPUState *)) |
|
144 |
DEF_HELPER_0_3(vfp_cmpes, void, (float32, float32, CPUState *)) |
|
145 |
DEF_HELPER_0_3(vfp_cmped, void, (float64, float64, CPUState *)) |
|
146 |
|
|
147 |
DEF_HELPER_1_2(vfp_fcvtds, float64, (float32, CPUState *)) |
|
148 |
DEF_HELPER_1_2(vfp_fcvtsd, float32, (float64, CPUState *)) |
|
149 |
|
|
150 |
DEF_HELPER_1_2(vfp_uitos, float32, (float32, CPUState *)) |
|
151 |
DEF_HELPER_1_2(vfp_uitod, float64, (float32, CPUState *)) |
|
152 |
DEF_HELPER_1_2(vfp_sitos, float32, (float32, CPUState *)) |
|
153 |
DEF_HELPER_1_2(vfp_sitod, float64, (float32, CPUState *)) |
|
154 |
|
|
155 |
DEF_HELPER_1_2(vfp_touis, float32, (float32, CPUState *)) |
|
156 |
DEF_HELPER_1_2(vfp_touid, float32, (float64, CPUState *)) |
|
157 |
DEF_HELPER_1_2(vfp_touizs, float32, (float32, CPUState *)) |
|
158 |
DEF_HELPER_1_2(vfp_touizd, float32, (float64, CPUState *)) |
|
159 |
DEF_HELPER_1_2(vfp_tosis, float32, (float32, CPUState *)) |
|
160 |
DEF_HELPER_1_2(vfp_tosid, float32, (float64, CPUState *)) |
|
161 |
DEF_HELPER_1_2(vfp_tosizs, float32, (float32, CPUState *)) |
|
162 |
DEF_HELPER_1_2(vfp_tosizd, float32, (float64, CPUState *)) |
|
163 |
|
|
164 |
DEF_HELPER_1_3(vfp_toshs, float32, (float32, uint32_t, CPUState *)) |
|
165 |
DEF_HELPER_1_3(vfp_tosls, float32, (float32, uint32_t, CPUState *)) |
|
166 |
DEF_HELPER_1_3(vfp_touhs, float32, (float32, uint32_t, CPUState *)) |
|
167 |
DEF_HELPER_1_3(vfp_touls, float32, (float32, uint32_t, CPUState *)) |
|
168 |
DEF_HELPER_1_3(vfp_toshd, float64, (float64, uint32_t, CPUState *)) |
|
169 |
DEF_HELPER_1_3(vfp_tosld, float64, (float64, uint32_t, CPUState *)) |
|
170 |
DEF_HELPER_1_3(vfp_touhd, float64, (float64, uint32_t, CPUState *)) |
|
171 |
DEF_HELPER_1_3(vfp_tould, float64, (float64, uint32_t, CPUState *)) |
|
172 |
DEF_HELPER_1_3(vfp_shtos, float32, (float32, uint32_t, CPUState *)) |
|
173 |
DEF_HELPER_1_3(vfp_sltos, float32, (float32, uint32_t, CPUState *)) |
|
174 |
DEF_HELPER_1_3(vfp_uhtos, float32, (float32, uint32_t, CPUState *)) |
|
175 |
DEF_HELPER_1_3(vfp_ultos, float32, (float32, uint32_t, CPUState *)) |
|
176 |
DEF_HELPER_1_3(vfp_shtod, float64, (float64, uint32_t, CPUState *)) |
|
177 |
DEF_HELPER_1_3(vfp_sltod, float64, (float64, uint32_t, CPUState *)) |
|
178 |
DEF_HELPER_1_3(vfp_uhtod, float64, (float64, uint32_t, CPUState *)) |
|
179 |
DEF_HELPER_1_3(vfp_ultod, float64, (float64, uint32_t, CPUState *)) |
|
180 |
|
|
181 |
DEF_HELPER_1_3(recps_f32, float32, (float32, float32, CPUState *)) |
|
182 |
DEF_HELPER_1_3(rsqrts_f32, float32, (float32, float32, CPUState *)) |
|
183 |
DEF_HELPER_1_2(recpe_f32, float32, (float32, CPUState *)) |
|
184 |
DEF_HELPER_1_2(rsqrte_f32, float32, (float32, CPUState *)) |
|
185 |
DEF_HELPER_1_2(recpe_u32, uint32_t, (uint32_t, CPUState *)) |
|
186 |
DEF_HELPER_1_2(rsqrte_u32, uint32_t, (uint32_t, CPUState *)) |
|
187 |
|
|
125 | 188 |
#undef DEF_HELPER |
126 | 189 |
#undef DEF_HELPER_0_0 |
127 | 190 |
#undef DEF_HELPER_0_1 |
b/target-arm/op.c | ||
---|---|---|
252 | 252 |
FORCE_RET(); |
253 | 253 |
} |
254 | 254 |
|
255 |
/* VFP support. We follow the convention used for VFP instrunctions: |
|
256 |
Single precition routines have a "s" suffix, double precision a |
|
257 |
"d" suffix. */ |
|
258 |
|
|
259 |
#define VFP_OP(name, p) void OPPROTO op_vfp_##name##p(void) |
|
260 |
|
|
261 |
#define VFP_BINOP(name) \ |
|
262 |
VFP_OP(name, s) \ |
|
263 |
{ \ |
|
264 |
FT0s = float32_ ## name (FT0s, FT1s, &env->vfp.fp_status); \ |
|
265 |
} \ |
|
266 |
VFP_OP(name, d) \ |
|
267 |
{ \ |
|
268 |
FT0d = float64_ ## name (FT0d, FT1d, &env->vfp.fp_status); \ |
|
269 |
} |
|
270 |
VFP_BINOP(add) |
|
271 |
VFP_BINOP(sub) |
|
272 |
VFP_BINOP(mul) |
|
273 |
VFP_BINOP(div) |
|
274 |
#undef VFP_BINOP |
|
275 |
|
|
276 |
#define VFP_HELPER(name) \ |
|
277 |
VFP_OP(name, s) \ |
|
278 |
{ \ |
|
279 |
do_vfp_##name##s(); \ |
|
280 |
} \ |
|
281 |
VFP_OP(name, d) \ |
|
282 |
{ \ |
|
283 |
do_vfp_##name##d(); \ |
|
284 |
} |
|
285 |
VFP_HELPER(abs) |
|
286 |
VFP_HELPER(sqrt) |
|
287 |
VFP_HELPER(cmp) |
|
288 |
VFP_HELPER(cmpe) |
|
289 |
#undef VFP_HELPER |
|
290 |
|
|
291 |
/* XXX: Will this do the right thing for NANs. Should invert the signbit |
|
292 |
without looking at the rest of the value. */ |
|
293 |
VFP_OP(neg, s) |
|
294 |
{ |
|
295 |
FT0s = float32_chs(FT0s); |
|
296 |
} |
|
297 |
|
|
298 |
VFP_OP(neg, d) |
|
299 |
{ |
|
300 |
FT0d = float64_chs(FT0d); |
|
301 |
} |
|
302 |
|
|
303 |
VFP_OP(F1_ld0, s) |
|
304 |
{ |
|
305 |
union { |
|
306 |
uint32_t i; |
|
307 |
float32 s; |
|
308 |
} v; |
|
309 |
v.i = 0; |
|
310 |
FT1s = v.s; |
|
311 |
} |
|
312 |
|
|
313 |
VFP_OP(F1_ld0, d) |
|
314 |
{ |
|
315 |
union { |
|
316 |
uint64_t i; |
|
317 |
float64 d; |
|
318 |
} v; |
|
319 |
v.i = 0; |
|
320 |
FT1d = v.d; |
|
321 |
} |
|
322 |
|
|
323 |
/* Helper routines to perform bitwise copies between float and int. */ |
|
324 |
static inline float32 vfp_itos(uint32_t i) |
|
325 |
{ |
|
326 |
union { |
|
327 |
uint32_t i; |
|
328 |
float32 s; |
|
329 |
} v; |
|
330 |
|
|
331 |
v.i = i; |
|
332 |
return v.s; |
|
333 |
} |
|
334 |
|
|
335 |
static inline uint32_t vfp_stoi(float32 s) |
|
336 |
{ |
|
337 |
union { |
|
338 |
uint32_t i; |
|
339 |
float32 s; |
|
340 |
} v; |
|
341 |
|
|
342 |
v.s = s; |
|
343 |
return v.i; |
|
344 |
} |
|
345 |
|
|
346 |
static inline float64 vfp_itod(uint64_t i) |
|
347 |
{ |
|
348 |
union { |
|
349 |
uint64_t i; |
|
350 |
float64 d; |
|
351 |
} v; |
|
352 |
|
|
353 |
v.i = i; |
|
354 |
return v.d; |
|
355 |
} |
|
356 |
|
|
357 |
static inline uint64_t vfp_dtoi(float64 d) |
|
358 |
{ |
|
359 |
union { |
|
360 |
uint64_t i; |
|
361 |
float64 d; |
|
362 |
} v; |
|
363 |
|
|
364 |
v.d = d; |
|
365 |
return v.i; |
|
366 |
} |
|
367 |
|
|
368 |
/* Integer to float conversion. */ |
|
369 |
VFP_OP(uito, s) |
|
370 |
{ |
|
371 |
FT0s = uint32_to_float32(vfp_stoi(FT0s), &env->vfp.fp_status); |
|
372 |
} |
|
373 |
|
|
374 |
VFP_OP(uito, d) |
|
375 |
{ |
|
376 |
FT0d = uint32_to_float64(vfp_stoi(FT0s), &env->vfp.fp_status); |
|
377 |
} |
|
378 |
|
|
379 |
VFP_OP(sito, s) |
|
380 |
{ |
|
381 |
FT0s = int32_to_float32(vfp_stoi(FT0s), &env->vfp.fp_status); |
|
382 |
} |
|
383 |
|
|
384 |
VFP_OP(sito, d) |
|
385 |
{ |
|
386 |
FT0d = int32_to_float64(vfp_stoi(FT0s), &env->vfp.fp_status); |
|
387 |
} |
|
388 |
|
|
389 |
/* Float to integer conversion. */ |
|
390 |
VFP_OP(toui, s) |
|
391 |
{ |
|
392 |
FT0s = vfp_itos(float32_to_uint32(FT0s, &env->vfp.fp_status)); |
|
393 |
} |
|
394 |
|
|
395 |
VFP_OP(toui, d) |
|
396 |
{ |
|
397 |
FT0s = vfp_itos(float64_to_uint32(FT0d, &env->vfp.fp_status)); |
|
398 |
} |
|
399 |
|
|
400 |
VFP_OP(tosi, s) |
|
401 |
{ |
|
402 |
FT0s = vfp_itos(float32_to_int32(FT0s, &env->vfp.fp_status)); |
|
403 |
} |
|
404 |
|
|
405 |
VFP_OP(tosi, d) |
|
406 |
{ |
|
407 |
FT0s = vfp_itos(float64_to_int32(FT0d, &env->vfp.fp_status)); |
|
408 |
} |
|
409 |
|
|
410 |
/* TODO: Set rounding mode properly. */ |
|
411 |
VFP_OP(touiz, s) |
|
412 |
{ |
|
413 |
FT0s = vfp_itos(float32_to_uint32_round_to_zero(FT0s, &env->vfp.fp_status)); |
|
414 |
} |
|
415 |
|
|
416 |
VFP_OP(touiz, d) |
|
417 |
{ |
|
418 |
FT0s = vfp_itos(float64_to_uint32_round_to_zero(FT0d, &env->vfp.fp_status)); |
|
419 |
} |
|
420 |
|
|
421 |
VFP_OP(tosiz, s) |
|
422 |
{ |
|
423 |
FT0s = vfp_itos(float32_to_int32_round_to_zero(FT0s, &env->vfp.fp_status)); |
|
424 |
} |
|
425 |
|
|
426 |
VFP_OP(tosiz, d) |
|
427 |
{ |
|
428 |
FT0s = vfp_itos(float64_to_int32_round_to_zero(FT0d, &env->vfp.fp_status)); |
|
429 |
} |
|
430 |
|
|
431 |
/* floating point conversion */ |
|
432 |
VFP_OP(fcvtd, s) |
|
433 |
{ |
|
434 |
FT0d = float32_to_float64(FT0s, &env->vfp.fp_status); |
|
435 |
} |
|
436 |
|
|
437 |
VFP_OP(fcvts, d) |
|
438 |
{ |
|
439 |
FT0s = float64_to_float32(FT0d, &env->vfp.fp_status); |
|
440 |
} |
|
441 |
|
|
442 |
/* VFP3 fixed point conversion. */ |
|
443 |
#define VFP_CONV_FIX(name, p, ftype, itype, sign) \ |
|
444 |
VFP_OP(name##to, p) \ |
|
445 |
{ \ |
|
446 |
ftype tmp; \ |
|
447 |
tmp = sign##int32_to_##ftype ((itype)vfp_##p##toi(FT0##p), \ |
|
448 |
&env->vfp.fp_status); \ |
|
449 |
FT0##p = ftype##_scalbn(tmp, PARAM1, &env->vfp.fp_status); \ |
|
450 |
} \ |
|
451 |
VFP_OP(to##name, p) \ |
|
452 |
{ \ |
|
453 |
ftype tmp; \ |
|
454 |
tmp = ftype##_scalbn(FT0##p, PARAM1, &env->vfp.fp_status); \ |
|
455 |
FT0##p = vfp_ito##p((itype)ftype##_to_##sign##int32_round_to_zero(tmp, \ |
|
456 |
&env->vfp.fp_status)); \ |
|
457 |
} |
|
458 |
|
|
459 |
VFP_CONV_FIX(sh, d, float64, int16, ) |
|
460 |
VFP_CONV_FIX(sl, d, float64, int32, ) |
|
461 |
VFP_CONV_FIX(uh, d, float64, uint16, u) |
|
462 |
VFP_CONV_FIX(ul, d, float64, uint32, u) |
|
463 |
VFP_CONV_FIX(sh, s, float32, int16, ) |
|
464 |
VFP_CONV_FIX(sl, s, float32, int32, ) |
|
465 |
VFP_CONV_FIX(uh, s, float32, uint16, u) |
|
466 |
VFP_CONV_FIX(ul, s, float32, uint32, u) |
|
467 |
|
|
468 |
/* Get and Put values from registers. */ |
|
469 |
VFP_OP(getreg_F0, d) |
|
470 |
{ |
|
471 |
FT0d = *(float64 *)((char *) env + PARAM1); |
|
472 |
} |
|
473 |
|
|
474 |
VFP_OP(getreg_F0, s) |
|
475 |
{ |
|
476 |
FT0s = *(float32 *)((char *) env + PARAM1); |
|
477 |
} |
|
478 |
|
|
479 |
VFP_OP(getreg_F1, d) |
|
480 |
{ |
|
481 |
FT1d = *(float64 *)((char *) env + PARAM1); |
|
482 |
} |
|
483 |
|
|
484 |
VFP_OP(getreg_F1, s) |
|
485 |
{ |
|
486 |
FT1s = *(float32 *)((char *) env + PARAM1); |
|
487 |
} |
|
488 |
|
|
489 |
VFP_OP(setreg_F0, d) |
|
490 |
{ |
|
491 |
*(float64 *)((char *) env + PARAM1) = FT0d; |
|
492 |
} |
|
493 |
|
|
494 |
VFP_OP(setreg_F0, s) |
|
495 |
{ |
|
496 |
*(float32 *)((char *) env + PARAM1) = FT0s; |
|
497 |
} |
|
498 |
|
|
499 |
void OPPROTO op_vfp_movl_T0_fpscr(void) |
|
500 |
{ |
|
501 |
do_vfp_get_fpscr (); |
|
502 |
} |
|
503 |
|
|
504 |
void OPPROTO op_vfp_movl_T0_fpscr_flags(void) |
|
505 |
{ |
|
506 |
T0 = env->vfp.xregs[ARM_VFP_FPSCR] & (0xf << 28); |
|
507 |
} |
|
508 |
|
|
509 |
void OPPROTO op_vfp_movl_fpscr_T0(void) |
|
510 |
{ |
|
511 |
do_vfp_set_fpscr(); |
|
512 |
} |
|
513 |
|
|
514 |
void OPPROTO op_vfp_movl_T0_xreg(void) |
|
515 |
{ |
|
516 |
T0 = env->vfp.xregs[PARAM1]; |
|
517 |
} |
|
518 |
|
|
519 |
void OPPROTO op_vfp_movl_xreg_T0(void) |
|
520 |
{ |
|
521 |
env->vfp.xregs[PARAM1] = T0; |
|
522 |
} |
|
523 |
|
|
524 |
/* Move between FT0s to T0 */ |
|
525 |
void OPPROTO op_vfp_mrs(void) |
|
526 |
{ |
|
527 |
T0 = vfp_stoi(FT0s); |
|
528 |
} |
|
529 |
|
|
530 |
void OPPROTO op_vfp_msr(void) |
|
531 |
{ |
|
532 |
FT0s = vfp_itos(T0); |
|
533 |
} |
|
534 |
|
|
535 |
/* Move between FT0d and {T0,T1} */ |
|
536 |
void OPPROTO op_vfp_mrrd(void) |
|
537 |
{ |
|
538 |
CPU_DoubleU u; |
|
539 |
|
|
540 |
u.d = FT0d; |
|
541 |
T0 = u.l.lower; |
|
542 |
T1 = u.l.upper; |
|
543 |
} |
|
544 |
|
|
545 |
void OPPROTO op_vfp_mdrr(void) |
|
546 |
{ |
|
547 |
CPU_DoubleU u; |
|
548 |
|
|
549 |
u.l.lower = T0; |
|
550 |
u.l.upper = T1; |
|
551 |
FT0d = u.d; |
|
552 |
} |
|
553 |
|
|
554 |
/* Load immediate. PARAM1 is the 32 most significant bits of the value. */ |
|
555 |
void OPPROTO op_vfp_fconstd(void) |
|
556 |
{ |
|
557 |
CPU_DoubleU u; |
|
558 |
u.l.upper = PARAM1; |
|
559 |
u.l.lower = 0; |
|
560 |
FT0d = u.d; |
|
561 |
} |
|
562 |
|
|
563 |
void OPPROTO op_vfp_fconsts(void) |
|
564 |
{ |
|
565 |
FT0s = vfp_itos(PARAM1); |
|
566 |
} |
|
567 |
|
|
568 | 255 |
void OPPROTO op_movl_cp_T0(void) |
569 | 256 |
{ |
570 | 257 |
helper_set_cp(env, PARAM1, T0); |
b/target-arm/op_helper.c | ||
---|---|---|
40 | 40 |
spin_unlock(&global_cpu_lock); |
41 | 41 |
} |
42 | 42 |
|
43 |
/* VFP support. */ |
|
44 |
|
|
45 |
void do_vfp_abss(void) |
|
46 |
{ |
|
47 |
FT0s = float32_abs(FT0s); |
|
48 |
} |
|
49 |
|
|
50 |
void do_vfp_absd(void) |
|
51 |
{ |
|
52 |
FT0d = float64_abs(FT0d); |
|
53 |
} |
|
54 |
|
|
55 |
void do_vfp_sqrts(void) |
|
56 |
{ |
|
57 |
FT0s = float32_sqrt(FT0s, &env->vfp.fp_status); |
|
58 |
} |
|
59 |
|
|
60 |
void do_vfp_sqrtd(void) |
|
61 |
{ |
|
62 |
FT0d = float64_sqrt(FT0d, &env->vfp.fp_status); |
|
63 |
} |
|
64 |
|
|
65 |
/* XXX: check quiet/signaling case */ |
|
66 |
#define DO_VFP_cmp(p, size) \ |
|
67 |
void do_vfp_cmp##p(void) \ |
|
68 |
{ \ |
|
69 |
uint32_t flags; \ |
|
70 |
switch(float ## size ## _compare_quiet(FT0##p, FT1##p, &env->vfp.fp_status)) {\ |
|
71 |
case 0: flags = 0x6; break;\ |
|
72 |
case -1: flags = 0x8; break;\ |
|
73 |
case 1: flags = 0x2; break;\ |
|
74 |
default: case 2: flags = 0x3; break;\ |
|
75 |
}\ |
|
76 |
env->vfp.xregs[ARM_VFP_FPSCR] = (flags << 28)\ |
|
77 |
| (env->vfp.xregs[ARM_VFP_FPSCR] & 0x0fffffff); \ |
|
78 |
FORCE_RET(); \ |
|
79 |
}\ |
|
80 |
\ |
|
81 |
void do_vfp_cmpe##p(void) \ |
|
82 |
{ \ |
|
83 |
uint32_t flags; \ |
|
84 |
switch(float ## size ## _compare(FT0##p, FT1##p, &env->vfp.fp_status)) {\ |
|
85 |
case 0: flags = 0x6; break;\ |
|
86 |
case -1: flags = 0x8; break;\ |
|
87 |
case 1: flags = 0x2; break;\ |
|
88 |
default: case 2: flags = 0x3; break;\ |
|
89 |
}\ |
|
90 |
env->vfp.xregs[ARM_VFP_FPSCR] = (flags << 28)\ |
|
91 |
| (env->vfp.xregs[ARM_VFP_FPSCR] & 0x0fffffff); \ |
|
92 |
FORCE_RET(); \ |
|
93 |
} |
|
94 |
DO_VFP_cmp(s, 32) |
|
95 |
DO_VFP_cmp(d, 64) |
|
96 |
#undef DO_VFP_cmp |
|
97 |
|
|
98 |
/* Convert host exception flags to vfp form. */ |
|
99 |
static inline int vfp_exceptbits_from_host(int host_bits) |
|
100 |
{ |
|
101 |
int target_bits = 0; |
|
102 |
|
|
103 |
if (host_bits & float_flag_invalid) |
|
104 |
target_bits |= 1; |
|
105 |
if (host_bits & float_flag_divbyzero) |
|
106 |
target_bits |= 2; |
|
107 |
if (host_bits & float_flag_overflow) |
|
108 |
target_bits |= 4; |
|
109 |
if (host_bits & float_flag_underflow) |
|
110 |
target_bits |= 8; |
|
111 |
if (host_bits & float_flag_inexact) |
|
112 |
target_bits |= 0x10; |
|
113 |
return target_bits; |
|
114 |
} |
|
115 |
|
|
116 |
/* Convert vfp exception flags to target form. */ |
|
117 |
static inline int vfp_exceptbits_to_host(int target_bits) |
|
118 |
{ |
|
119 |
int host_bits = 0; |
|
120 |
|
|
121 |
if (target_bits & 1) |
|
122 |
host_bits |= float_flag_invalid; |
|
123 |
if (target_bits & 2) |
|
124 |
host_bits |= float_flag_divbyzero; |
|
125 |
if (target_bits & 4) |
|
126 |
host_bits |= float_flag_overflow; |
|
127 |
if (target_bits & 8) |
|
128 |
host_bits |= float_flag_underflow; |
|
129 |
if (target_bits & 0x10) |
|
130 |
host_bits |= float_flag_inexact; |
|
131 |
return host_bits; |
|
132 |
} |
|
133 |
|
|
134 |
void do_vfp_set_fpscr(void) |
|
135 |
{ |
|
136 |
int i; |
|
137 |
uint32_t changed; |
|
138 |
|
|
139 |
changed = env->vfp.xregs[ARM_VFP_FPSCR]; |
|
140 |
env->vfp.xregs[ARM_VFP_FPSCR] = (T0 & 0xffc8ffff); |
|
141 |
env->vfp.vec_len = (T0 >> 16) & 7; |
|
142 |
env->vfp.vec_stride = (T0 >> 20) & 3; |
|
143 |
|
|
144 |
changed ^= T0; |
|
145 |
if (changed & (3 << 22)) { |
|
146 |
i = (T0 >> 22) & 3; |
|
147 |
switch (i) { |
|
148 |
case 0: |
|
149 |
i = float_round_nearest_even; |
|
150 |
break; |
|
151 |
case 1: |
|
152 |
i = float_round_up; |
|
153 |
break; |
|
154 |
case 2: |
|
155 |
i = float_round_down; |
|
156 |
break; |
|
157 |
case 3: |
|
158 |
i = float_round_to_zero; |
|
159 |
break; |
|
160 |
} |
|
161 |
set_float_rounding_mode(i, &env->vfp.fp_status); |
|
162 |
} |
|
163 |
|
|
164 |
i = vfp_exceptbits_to_host((T0 >> 8) & 0x1f); |
|
165 |
set_float_exception_flags(i, &env->vfp.fp_status); |
|
166 |
/* XXX: FZ and DN are not implemented. */ |
|
167 |
} |
|
168 |
|
|
169 |
void do_vfp_get_fpscr(void) |
|
170 |
{ |
|
171 |
int i; |
|
172 |
|
|
173 |
T0 = (env->vfp.xregs[ARM_VFP_FPSCR] & 0xffc8ffff) | (env->vfp.vec_len << 16) |
|
174 |
| (env->vfp.vec_stride << 20); |
|
175 |
i = get_float_exception_flags(&env->vfp.fp_status); |
|
176 |
T0 |= vfp_exceptbits_from_host(i); |
|
177 |
} |
|
178 |
|
|
179 |
float32 helper_recps_f32(float32 a, float32 b) |
|
180 |
{ |
|
181 |
float_status *s = &env->vfp.fp_status; |
|
182 |
float32 two = int32_to_float32(2, s); |
|
183 |
return float32_sub(two, float32_mul(a, b, s), s); |
|
184 |
} |
|
185 |
|
|
186 |
float32 helper_rsqrts_f32(float32 a, float32 b) |
|
187 |
{ |
|
188 |
float_status *s = &env->vfp.fp_status; |
|
189 |
float32 three = int32_to_float32(3, s); |
|
190 |
return float32_sub(three, float32_mul(a, b, s), s); |
|
191 |
} |
|
192 |
|
|
193 |
/* TODO: The architecture specifies the value that the estimate functions |
|
194 |
should return. We return the exact reciprocal/root instead. */ |
|
195 |
float32 helper_recpe_f32(float32 a) |
|
196 |
{ |
|
197 |
float_status *s = &env->vfp.fp_status; |
|
198 |
float32 one = int32_to_float32(1, s); |
|
199 |
return float32_div(one, a, s); |
|
200 |
} |
|
201 |
|
|
202 |
float32 helper_rsqrte_f32(float32 a) |
|
203 |
{ |
|
204 |
float_status *s = &env->vfp.fp_status; |
|
205 |
float32 one = int32_to_float32(1, s); |
|
206 |
return float32_div(one, float32_sqrt(a, s), s); |
|
207 |
} |
|
208 |
|
|
209 |
uint32_t helper_recpe_u32(uint32_t a) |
|
210 |
{ |
|
211 |
float_status *s = &env->vfp.fp_status; |
|
212 |
float32 tmp; |
|
213 |
tmp = int32_to_float32(a, s); |
|
214 |
tmp = float32_scalbn(tmp, -32, s); |
|
215 |
tmp = helper_recpe_f32(tmp); |
|
216 |
tmp = float32_scalbn(tmp, 31, s); |
|
217 |
return float32_to_int32(tmp, s); |
|
218 |
} |
|
219 |
|
|
220 |
uint32_t helper_rsqrte_u32(uint32_t a) |
|
221 |
{ |
|
222 |
float_status *s = &env->vfp.fp_status; |
|
223 |
float32 tmp; |
|
224 |
tmp = int32_to_float32(a, s); |
|
225 |
tmp = float32_scalbn(tmp, -32, s); |
|
226 |
tmp = helper_rsqrte_f32(tmp); |
|
227 |
tmp = float32_scalbn(tmp, 31, s); |
|
228 |
return float32_to_int32(tmp, s); |
|
229 |
} |
|
230 |
|
|
231 | 43 |
void helper_neon_tbl(int rn, int maxindex) |
232 | 44 |
{ |
233 | 45 |
uint32_t val; |
b/target-arm/op_mem.h | ||
---|---|---|
77 | 77 |
FORCE_RET(); |
78 | 78 |
} |
79 | 79 |
|
80 |
/* Floating point load/store. Address is in T1 */ |
|
81 |
#define VFP_MEM_OP(p, w) \ |
|
82 |
void OPPROTO glue(op_vfp_ld##p,MEMSUFFIX)(void) \ |
|
83 |
{ \ |
|
84 |
FT0##p = glue(ldf##w,MEMSUFFIX)(T1); \ |
|
85 |
FORCE_RET(); \ |
|
86 |
} \ |
|
87 |
void OPPROTO glue(op_vfp_st##p,MEMSUFFIX)(void) \ |
|
88 |
{ \ |
|
89 |
glue(stf##w,MEMSUFFIX)(T1, FT0##p); \ |
|
90 |
FORCE_RET(); \ |
|
91 |
} |
|
92 |
|
|
93 |
VFP_MEM_OP(s,l) |
|
94 |
VFP_MEM_OP(d,q) |
|
95 |
|
|
96 |
#undef VFP_MEM_OP |
|
97 |
|
|
98 | 80 |
/* iwMMXt load/store. Address is in T1 */ |
99 | 81 |
#define MMX_MEM_OP(name, ldname) \ |
100 | 82 |
void OPPROTO glue(op_iwmmxt_ld##name,MEMSUFFIX)(void) \ |
b/target-arm/op_neon.h | ||
---|---|---|
14 | 14 |
#define NFS &env->vfp.fp_status |
15 | 15 |
#define NEON_OP(name) void OPPROTO op_neon_##name (void) |
16 | 16 |
|
17 |
/* Helper routines to perform bitwise copies between float and int. */ |
|
18 |
static inline float32 vfp_itos(uint32_t i) |
|
19 |
{ |
|
20 |
union { |
|
21 |
uint32_t i; |
|
22 |
float32 s; |
|
23 |
} v; |
|
24 |
|
|
25 |
v.i = i; |
|
26 |
return v.s; |
|
27 |
} |
|
28 |
|
|
29 |
static inline uint32_t vfp_stoi(float32 s) |
|
30 |
{ |
|
31 |
union { |
|
32 |
uint32_t i; |
|
33 |
float32 s; |
|
34 |
} v; |
|
35 |
|
|
36 |
v.s = s; |
|
37 |
return v.i; |
|
38 |
} |
|
39 |
|
|
17 | 40 |
NEON_OP(getreg_T0) |
18 | 41 |
{ |
19 | 42 |
T0 = *(uint32_t *)((char *) env + PARAM1); |
... | ... | |
754 | 777 |
#undef NEON_FN |
755 | 778 |
#undef NEON_QDMULH32 |
756 | 779 |
|
757 |
NEON_OP(recps_f32) |
|
758 |
{ |
|
759 |
T0 = vfp_stoi(helper_recps_f32(vfp_itos(T0), vfp_itos(T1))); |
|
760 |
FORCE_RET(); |
|
761 |
} |
|
762 |
|
|
763 |
NEON_OP(rsqrts_f32) |
|
764 |
{ |
|
765 |
T0 = vfp_stoi(helper_rsqrts_f32(vfp_itos(T0), vfp_itos(T1))); |
|
766 |
FORCE_RET(); |
|
767 |
} |
|
768 |
|
|
769 | 780 |
/* Floating point comparisons produce an integer result. */ |
770 | 781 |
#define NEON_VOP_FCMP(name, cmp) \ |
771 | 782 |
NEON_OP(name) \ |
... | ... | |
1702 | 1713 |
FORCE_RET(); |
1703 | 1714 |
} |
1704 | 1715 |
|
1705 |
/* Reciprocal/root estimate. */ |
|
1706 |
NEON_OP(recpe_u32) |
|
1707 |
{ |
|
1708 |
T0 = helper_recpe_u32(T0); |
|
1709 |
} |
|
1710 |
|
|
1711 |
NEON_OP(rsqrte_u32) |
|
1712 |
{ |
|
1713 |
T0 = helper_rsqrte_u32(T0); |
|
1714 |
} |
|
1715 |
|
|
1716 |
NEON_OP(recpe_f32) |
|
1717 |
{ |
|
1718 |
FT0s = helper_recpe_f32(FT0s); |
|
1719 |
} |
|
1720 |
|
|
1721 |
NEON_OP(rsqrte_f32) |
|
1722 |
{ |
|
1723 |
FT0s = helper_rsqrte_f32(FT0s); |
|
1724 |
} |
|
1725 |
|
|
1726 | 1716 |
/* Table lookup. This accessed the register file directly. */ |
1727 | 1717 |
NEON_OP(tbl) |
1728 | 1718 |
{ |
b/target-arm/translate.c | ||
---|---|---|
79 | 79 |
static TCGv cpu_env; |
80 | 80 |
/* FIXME: These should be removed. */ |
81 | 81 |
static TCGv cpu_T[3]; |
82 |
static TCGv cpu_F0s, cpu_F1s, cpu_F0d, cpu_F1d; |
|
82 | 83 |
|
83 | 84 |
/* initialize TCG globals. */ |
84 | 85 |
void arm_translate_init(void) |
... | ... | |
959 | 960 |
} |
960 | 961 |
} |
961 | 962 |
|
962 |
#define VFP_OP(name) \
|
|
963 |
static inline void gen_vfp_##name(int dp) \ |
|
964 |
{ \ |
|
965 |
if (dp) \ |
|
966 |
gen_op_vfp_##name##d(); \
|
|
967 |
else \ |
|
968 |
gen_op_vfp_##name##s(); \
|
|
963 |
#define VFP_OP2(name) \
|
|
964 |
static inline void gen_vfp_##name(int dp) \
|
|
965 |
{ \
|
|
966 |
if (dp) \
|
|
967 |
gen_helper_vfp_##name##d(cpu_F0d, cpu_F0d, cpu_F1d, cpu_env); \
|
|
968 |
else \
|
|
969 |
gen_helper_vfp_##name##s(cpu_F0s, cpu_F0s, cpu_F1s, cpu_env); \
|
|
969 | 970 |
} |
970 | 971 |
|
971 |
#define VFP_OP1(name) \ |
|
972 |
#define VFP_OP1i(name) \
|
|
972 | 973 |
static inline void gen_vfp_##name(int dp, int arg) \ |
973 | 974 |
{ \ |
974 | 975 |
if (dp) \ |
... | ... | |
977 | 978 |
gen_op_vfp_##name##s(arg); \ |
978 | 979 |
} |
979 | 980 |
|
980 |
VFP_OP(add) |
|
981 |
VFP_OP(sub) |
|
982 |
VFP_OP(mul) |
|
983 |
VFP_OP(div) |
|
984 |
VFP_OP(neg) |
|
985 |
VFP_OP(abs) |
|
986 |
VFP_OP(sqrt) |
|
987 |
VFP_OP(cmp) |
|
988 |
VFP_OP(cmpe) |
|
989 |
VFP_OP(F1_ld0) |
|
990 |
VFP_OP(uito) |
|
991 |
VFP_OP(sito) |
|
992 |
VFP_OP(toui) |
|
993 |
VFP_OP(touiz) |
|
994 |
VFP_OP(tosi) |
|
995 |
VFP_OP(tosiz) |
|
996 |
VFP_OP1(tosh) |
|
997 |
VFP_OP1(tosl) |
|
998 |
VFP_OP1(touh) |
|
999 |
VFP_OP1(toul) |
|
1000 |
VFP_OP1(shto) |
|
1001 |
VFP_OP1(slto) |
|
1002 |
VFP_OP1(uhto) |
|
1003 |
VFP_OP1(ulto) |
|
1004 |
|
|
1005 |
#undef VFP_OP |
|
1006 |
|
|
1007 |
static inline void gen_vfp_fconst(int dp, uint32_t val) |
|
981 |
VFP_OP2(add) |
|
982 |
VFP_OP2(sub) |
|
983 |
VFP_OP2(mul) |
|
984 |
VFP_OP2(div) |
|
985 |
|
|
986 |
#undef VFP_OP2 |
|
987 |
|
|
988 |
static inline void gen_vfp_abs(int dp) |
|
989 |
{ |
|
990 |
if (dp) |
|
991 |
gen_helper_vfp_absd(cpu_F0d, cpu_F0d); |
|
992 |
else |
|
993 |
gen_helper_vfp_abss(cpu_F0s, cpu_F0s); |
|
994 |
} |
|
995 |
|
|
996 |
static inline void gen_vfp_neg(int dp) |
|
997 |
{ |
|
998 |
if (dp) |
|
999 |
gen_helper_vfp_negd(cpu_F0d, cpu_F0d); |
|
1000 |
else |
|
1001 |
gen_helper_vfp_negs(cpu_F0s, cpu_F0s); |
|
1002 |
} |
|
1003 |
|
|
1004 |
static inline void gen_vfp_sqrt(int dp) |
|
1005 |
{ |
|
1006 |
if (dp) |
|
1007 |
gen_helper_vfp_sqrtd(cpu_F0d, cpu_F0d, cpu_env); |
|
1008 |
else |
|
1009 |
gen_helper_vfp_sqrts(cpu_F0s, cpu_F0s, cpu_env); |
|
1010 |
} |
|
1011 |
|
|
1012 |
static inline void gen_vfp_cmp(int dp) |
|
1013 |
{ |
|
1014 |
if (dp) |
|
1015 |
gen_helper_vfp_cmpd(cpu_F0d, cpu_F1d, cpu_env); |
|
1016 |
else |
|
1017 |
gen_helper_vfp_cmps(cpu_F0s, cpu_F1s, cpu_env); |
|
1018 |
} |
|
1019 |
|
|
1020 |
static inline void gen_vfp_cmpe(int dp) |
|
1021 |
{ |
|
1022 |
if (dp) |
|
1023 |
gen_helper_vfp_cmped(cpu_F0d, cpu_F1d, cpu_env); |
|
1024 |
else |
|
1025 |
gen_helper_vfp_cmpes(cpu_F0s, cpu_F1s, cpu_env); |
|
1026 |
} |
|
1027 |
|
|
1028 |
static inline void gen_vfp_F1_ld0(int dp) |
|
1029 |
{ |
|
1030 |
if (dp) |
|
1031 |
tcg_gen_movi_i64(cpu_F0d, 0); |
|
1032 |
else |
|
1033 |
tcg_gen_movi_i32(cpu_F0s, 0); |
|
1034 |
} |
|
1035 |
|
|
1036 |
static inline void gen_vfp_uito(int dp) |
|
1037 |
{ |
|
1038 |
if (dp) |
|
1039 |
gen_helper_vfp_uitod(cpu_F0d, cpu_F0s, cpu_env); |
|
1040 |
else |
|
1041 |
gen_helper_vfp_uitos(cpu_F0s, cpu_F0s, cpu_env); |
|
1042 |
} |
|
1043 |
|
|
1044 |
static inline void gen_vfp_sito(int dp) |
|
1045 |
{ |
|
1046 |
if (dp) |
|
1047 |
gen_helper_vfp_uitod(cpu_F0d, cpu_F0s, cpu_env); |
|
1048 |
else |
|
1049 |
gen_helper_vfp_uitos(cpu_F0s, cpu_F0s, cpu_env); |
|
1050 |
} |
|
1051 |
|
|
1052 |
static inline void gen_vfp_toui(int dp) |
|
1053 |
{ |
|
1054 |
if (dp) |
|
1055 |
gen_helper_vfp_touid(cpu_F0s, cpu_F0d, cpu_env); |
|
1056 |
else |
|
1057 |
gen_helper_vfp_touis(cpu_F0s, cpu_F0s, cpu_env); |
|
1058 |
} |
|
1059 |
|
|
1060 |
static inline void gen_vfp_touiz(int dp) |
|
1061 |
{ |
|
1062 |
if (dp) |
|
1063 |
gen_helper_vfp_touizd(cpu_F0s, cpu_F0d, cpu_env); |
|
1064 |
else |
|
1065 |
gen_helper_vfp_touizs(cpu_F0s, cpu_F0s, cpu_env); |
|
1066 |
} |
|
1067 |
|
|
1068 |
static inline void gen_vfp_tosi(int dp) |
|
1069 |
{ |
|
1070 |
if (dp) |
|
1071 |
gen_helper_vfp_tosid(cpu_F0s, cpu_F0d, cpu_env); |
|
1072 |
else |
|
1073 |
gen_helper_vfp_tosis(cpu_F0s, cpu_F0s, cpu_env); |
|
1074 |
} |
|
1075 |
|
|
1076 |
static inline void gen_vfp_tosiz(int dp) |
|
1008 | 1077 |
{ |
1009 | 1078 |
if (dp) |
1010 |
gen_op_vfp_fconstd(val);
|
|
1079 |
gen_helper_vfp_tosizd(cpu_F0s, cpu_F0d, cpu_env);
|
|
1011 | 1080 |
else |
1012 |
gen_op_vfp_fconsts(val); |
|
1081 |
gen_helper_vfp_tosizs(cpu_F0s, cpu_F0s, cpu_env); |
|
1082 |
} |
|
1083 |
|
|
1084 |
#define VFP_GEN_FIX(name) \ |
|
1085 |
static inline void gen_vfp_##name(int dp, int shift) \ |
|
1086 |
{ \ |
|
1087 |
if (dp) \ |
|
1088 |
gen_helper_vfp_##name##d(cpu_F0d, cpu_F0d, tcg_const_i32(shift), cpu_env);\ |
|
1089 |
else \ |
|
1090 |
gen_helper_vfp_##name##s(cpu_F0s, cpu_F0s, tcg_const_i32(shift), cpu_env);\ |
|
1013 | 1091 |
} |
1092 |
VFP_GEN_FIX(tosh) |
|
1093 |
VFP_GEN_FIX(tosl) |
|
1094 |
VFP_GEN_FIX(touh) |
|
1095 |
VFP_GEN_FIX(toul) |
|
1096 |
VFP_GEN_FIX(shto) |
|
1097 |
VFP_GEN_FIX(slto) |
|
1098 |
VFP_GEN_FIX(uhto) |
|
1099 |
VFP_GEN_FIX(ulto) |
|
1100 |
#undef VFP_GEN_FIX |
|
1014 | 1101 |
|
1015 | 1102 |
static inline void gen_vfp_ld(DisasContext *s, int dp) |
1016 | 1103 |
{ |
1017 | 1104 |
if (dp) |
1018 |
gen_ldst(vfp_ldd, s);
|
|
1105 |
tcg_gen_qemu_ld64(cpu_F0d, cpu_T[1], IS_USER(s));
|
|
1019 | 1106 |
else |
1020 |
gen_ldst(vfp_lds, s);
|
|
1107 |
tcg_gen_qemu_ld32u(cpu_F0s, cpu_T[1], IS_USER(s));
|
|
1021 | 1108 |
} |
1022 | 1109 |
|
1023 | 1110 |
static inline void gen_vfp_st(DisasContext *s, int dp) |
1024 | 1111 |
{ |
1025 | 1112 |
if (dp) |
1026 |
gen_ldst(vfp_std, s);
|
|
1113 |
tcg_gen_qemu_st64(cpu_F0d, cpu_T[1], IS_USER(s));
|
|
1027 | 1114 |
else |
1028 |
gen_ldst(vfp_sts, s);
|
|
1115 |
tcg_gen_qemu_st32(cpu_F0s, cpu_T[1], IS_USER(s));
|
|
1029 | 1116 |
} |
1030 | 1117 |
|
1031 | 1118 |
static inline long |
... | ... | |
1055 | 1142 |
#define NEON_GET_REG(T, reg, n) gen_op_neon_getreg_##T(neon_reg_offset(reg, n)) |
1056 | 1143 |
#define NEON_SET_REG(T, reg, n) gen_op_neon_setreg_##T(neon_reg_offset(reg, n)) |
1057 | 1144 |
|
1145 |
#define tcg_gen_ld_f32 tcg_gen_ld_i32 |
|
1146 |
#define tcg_gen_ld_f64 tcg_gen_ld_i64 |
|
1147 |
#define tcg_gen_st_f32 tcg_gen_st_i32 |
|
1148 |
#define tcg_gen_st_f64 tcg_gen_st_i64 |
|
1149 |
|
|
1058 | 1150 |
static inline void gen_mov_F0_vreg(int dp, int reg) |
1059 | 1151 |
{ |
1060 | 1152 |
if (dp) |
1061 |
gen_op_vfp_getreg_F0d(vfp_reg_offset(dp, reg));
|
|
1153 |
tcg_gen_ld_f64(cpu_F0d, cpu_env, vfp_reg_offset(dp, reg));
|
|
1062 | 1154 |
else |
1063 |
gen_op_vfp_getreg_F0s(vfp_reg_offset(dp, reg));
|
|
1155 |
tcg_gen_ld_f32(cpu_F0s, cpu_env, vfp_reg_offset(dp, reg));
|
|
1064 | 1156 |
} |
1065 | 1157 |
|
1066 | 1158 |
static inline void gen_mov_F1_vreg(int dp, int reg) |
1067 | 1159 |
{ |
1068 | 1160 |
if (dp) |
1069 |
gen_op_vfp_getreg_F1d(vfp_reg_offset(dp, reg));
|
|
1161 |
tcg_gen_ld_f64(cpu_F1d, cpu_env, vfp_reg_offset(dp, reg));
|
|
1070 | 1162 |
else |
1071 |
gen_op_vfp_getreg_F1s(vfp_reg_offset(dp, reg));
|
|
1163 |
tcg_gen_ld_f32(cpu_F1s, cpu_env, vfp_reg_offset(dp, reg));
|
|
1072 | 1164 |
} |
1073 | 1165 |
|
1074 | 1166 |
static inline void gen_mov_vreg_F0(int dp, int reg) |
1075 | 1167 |
{ |
1076 | 1168 |
if (dp) |
1077 |
gen_op_vfp_setreg_F0d(vfp_reg_offset(dp, reg));
|
|
1169 |
tcg_gen_st_f64(cpu_F0d, cpu_env, vfp_reg_offset(dp, reg));
|
|
1078 | 1170 |
else |
1079 |
gen_op_vfp_setreg_F0s(vfp_reg_offset(dp, reg));
|
|
1171 |
tcg_gen_st_f32(cpu_F0s, cpu_env, vfp_reg_offset(dp, reg));
|
|
1080 | 1172 |
} |
1081 | 1173 |
|
1082 | 1174 |
#define ARM_CP_RW_BIT (1 << 20) |
... | ... | |
2262 | 2354 |
#define VFP_SREG_M(insn) VFP_SREG(insn, 0, 5) |
2263 | 2355 |
#define VFP_DREG_M(reg, insn) VFP_DREG(reg, insn, 0, 5) |
2264 | 2356 |
|
2357 |
/* Move between integer and VFP cores. */ |
|
2358 |
static TCGv gen_vfp_mrs(void) |
|
2359 |
{ |
|
2360 |
TCGv tmp = new_tmp(); |
|
2361 |
tcg_gen_mov_i32(tmp, cpu_F0s); |
|
2362 |
return tmp; |
|
2363 |
} |
|
2364 |
|
|
2365 |
static void gen_vfp_msr(TCGv tmp) |
|
2366 |
{ |
|
2367 |
tcg_gen_mov_i32(cpu_F0s, tmp); |
|
2368 |
dead_tmp(tmp); |
|
2369 |
} |
|
2370 |
|
|
2265 | 2371 |
static inline int |
2266 | 2372 |
vfp_enabled(CPUState * env) |
2267 | 2373 |
{ |
... | ... | |
2274 | 2380 |
{ |
2275 | 2381 |
uint32_t rd, rn, rm, op, i, n, offset, delta_d, delta_m, bank_mask; |
2276 | 2382 |
int dp, veclen; |
2383 |
TCGv tmp; |
|
2277 | 2384 |
|
2278 | 2385 |
if (!arm_feature(env, ARM_FEATURE_VFP)) |
2279 | 2386 |
return 1; |
... | ... | |
2396 | 2503 |
|
2397 | 2504 |
switch (rn) { |
2398 | 2505 |
case ARM_VFP_FPSID: |
2399 |
/* VFP2 allows access for FSID from userspace.
|
|
2506 |
/* VFP2 allows access to FSID from userspace.
|
|
2400 | 2507 |
VFP3 restricts all id registers to privileged |
2401 | 2508 |
accesses. */ |
2402 | 2509 |
if (IS_USER(s) |
2403 | 2510 |
&& arm_feature(env, ARM_FEATURE_VFP3)) |
2404 | 2511 |
return 1; |
2405 |
gen_op_vfp_movl_T0_xreg(rn);
|
|
2512 |
tmp = load_cpu_field(vfp.xregs[rn]);
|
|
2406 | 2513 |
break; |
2407 | 2514 |
case ARM_VFP_FPEXC: |
2408 | 2515 |
if (IS_USER(s)) |
2409 | 2516 |
return 1; |
2410 |
gen_op_vfp_movl_T0_xreg(rn);
|
|
2517 |
tmp = load_cpu_field(vfp.xregs[rn]);
|
|
2411 | 2518 |
break; |
2412 | 2519 |
case ARM_VFP_FPINST: |
2413 | 2520 |
case ARM_VFP_FPINST2: |
... | ... | |
2415 | 2522 |
if (IS_USER(s) |
2416 | 2523 |
|| arm_feature(env, ARM_FEATURE_VFP3)) |
2417 | 2524 |
return 1; |
2418 |
gen_op_vfp_movl_T0_xreg(rn);
|
|
2525 |
tmp = load_cpu_field(vfp.xregs[rn]);
|
|
2419 | 2526 |
break; |
2420 | 2527 |
case ARM_VFP_FPSCR: |
2421 |
if (rd == 15) |
|
2422 |
gen_op_vfp_movl_T0_fpscr_flags(); |
|
2423 |
else |
|
2424 |
gen_op_vfp_movl_T0_fpscr(); |
|
2528 |
if (rd == 15) { |
|
2529 |
tmp = load_cpu_field(vfp.xregs[ARM_VFP_FPSCR]); |
|
2530 |
tcg_gen_andi_i32(tmp, tmp, 0xf0000000); |
|
2531 |
} else { |
|
2532 |
tmp = new_tmp(); |
|
2533 |
gen_helper_vfp_get_fpscr(tmp, cpu_env); |
|
2534 |
} |
|
2425 | 2535 |
break; |
2426 | 2536 |
case ARM_VFP_MVFR0: |
2427 | 2537 |
case ARM_VFP_MVFR1: |
2428 | 2538 |
if (IS_USER(s) |
2429 | 2539 |
|| !arm_feature(env, ARM_FEATURE_VFP3)) |
2430 | 2540 |
return 1; |
2431 |
gen_op_vfp_movl_T0_xreg(rn);
|
|
2541 |
tmp = load_cpu_field(vfp.xregs[rn]);
|
|
2432 | 2542 |
break; |
2433 | 2543 |
default: |
2434 | 2544 |
return 1; |
2435 | 2545 |
} |
2436 | 2546 |
} else { |
2437 | 2547 |
gen_mov_F0_vreg(0, rn); |
2438 |
gen_op_vfp_mrs();
|
|
2548 |
tmp = gen_vfp_mrs();
|
|
2439 | 2549 |
} |
2440 | 2550 |
if (rd == 15) { |
2441 | 2551 |
/* Set the 4 flag bits in the CPSR. */ |
2442 |
gen_set_nzcv(cpu_T[0]); |
|
2443 |
} else |
|
2444 |
gen_movl_reg_T0(s, rd); |
|
2552 |
gen_set_nzcv(tmp); |
|
2553 |
dead_tmp(tmp); |
|
2554 |
} else { |
|
2555 |
store_reg(s, rd, tmp); |
|
2556 |
} |
|
2445 | 2557 |
} else { |
2446 | 2558 |
/* arm->vfp */ |
2447 |
gen_movl_T0_reg(s, rd);
|
|
2559 |
tmp = load_reg(s, rd);
|
|
2448 | 2560 |
if (insn & (1 << 21)) { |
2449 | 2561 |
rn >>= 1; |
2450 | 2562 |
/* system register */ |
... | ... | |
2455 | 2567 |
/* Writes are ignored. */ |
Also available in: Unified diff