Revision 4373f3ce target-arm/op_helper.c
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; |
Also available in: Unified diff