@@ -113,11 +113,12 @@ static void vfp_set_fpsr_to_host(CPUARMState *env, uint32_t val)
113113 set_float_exception_flags (0 , & env -> vfp .standard_fp_status_f16 );
114114}
115115
116- static void vfp_set_fpcr_to_host (CPUARMState * env , uint32_t val )
116+ static void vfp_set_fpcr_to_host (CPUARMState * env , uint32_t val , uint32_t mask )
117117{
118118 uint64_t changed = env -> vfp .fpcr ;
119119
120120 changed ^= val ;
121+ changed &= mask ;
121122 if (changed & (3 << 22 )) {
122123 int i = (val >> 22 ) & 3 ;
123124 switch (i ) {
@@ -167,7 +168,7 @@ static void vfp_set_fpsr_to_host(CPUARMState *env, uint32_t val)
167168{
168169}
169170
170- static void vfp_set_fpcr_to_host (CPUARMState * env , uint32_t val )
171+ static void vfp_set_fpcr_to_host (CPUARMState * env , uint32_t val , uint32_t mask )
171172{
172173}
173174
@@ -239,31 +240,38 @@ void vfp_set_fpsr(CPUARMState *env, uint32_t val)
239240 env -> vfp .fpsr = val ;
240241}
241242
242- void vfp_set_fpcr (CPUARMState * env , uint32_t val )
243+ static void vfp_set_fpcr_masked (CPUARMState * env , uint32_t val , uint32_t mask )
243244{
245+ /*
246+ * We only set FPCR bits defined by mask, and leave the others alone.
247+ * We assume the mask is sensible (e.g. doesn't try to set only
248+ * part of a field)
249+ */
244250 ARMCPU * cpu = env_archcpu (env );
245251
246252 /* When ARMv8.2-FP16 is not supported, FZ16 is RES0. */
247253 if (!cpu_isar_feature (any_fp16 , cpu )) {
248254 val &= ~FPCR_FZ16 ;
249255 }
250256
251- vfp_set_fpcr_to_host (env , val );
252-
253- if (!arm_feature (env , ARM_FEATURE_M )) {
254- /*
255- * Short-vector length and stride; on M-profile these bits
256- * are used for different purposes.
257- * We can't make this conditional be "if MVFR0.FPShVec != 0",
258- * because in v7A no-short-vector-support cores still had to
259- * allow Stride/Len to be written with the only effect that
260- * some insns are required to UNDEF if the guest sets them.
261- */
262- env -> vfp .vec_len = extract32 (val , 16 , 3 );
263- env -> vfp .vec_stride = extract32 (val , 20 , 2 );
264- } else if (cpu_isar_feature (aa32_mve , cpu )) {
265- env -> v7m .ltpsize = extract32 (val , FPCR_LTPSIZE_SHIFT ,
266- FPCR_LTPSIZE_LENGTH );
257+ vfp_set_fpcr_to_host (env , val , mask );
258+
259+ if (mask & (FPCR_LEN_MASK | FPCR_STRIDE_MASK )) {
260+ if (!arm_feature (env , ARM_FEATURE_M )) {
261+ /*
262+ * Short-vector length and stride; on M-profile these bits
263+ * are used for different purposes.
264+ * We can't make this conditional be "if MVFR0.FPShVec != 0",
265+ * because in v7A no-short-vector-support cores still had to
266+ * allow Stride/Len to be written with the only effect that
267+ * some insns are required to UNDEF if the guest sets them.
268+ */
269+ env -> vfp .vec_len = extract32 (val , 16 , 3 );
270+ env -> vfp .vec_stride = extract32 (val , 20 , 2 );
271+ } else if (cpu_isar_feature (aa32_mve , cpu )) {
272+ env -> v7m .ltpsize = extract32 (val , FPCR_LTPSIZE_SHIFT ,
273+ FPCR_LTPSIZE_LENGTH );
274+ }
267275 }
268276
269277 /*
@@ -276,12 +284,18 @@ void vfp_set_fpcr(CPUARMState *env, uint32_t val)
276284 * bits.
277285 */
278286 val &= FPCR_AHP | FPCR_DN | FPCR_FZ | FPCR_RMODE_MASK | FPCR_FZ16 ;
279- env -> vfp .fpcr = val ;
287+ env -> vfp .fpcr &= ~mask ;
288+ env -> vfp .fpcr |= val ;
289+ }
290+
291+ void vfp_set_fpcr (CPUARMState * env , uint32_t val )
292+ {
293+ vfp_set_fpcr_masked (env , val , MAKE_64BIT_MASK (0 , 32 ));
280294}
281295
282296void HELPER (vfp_set_fpscr )(CPUARMState * env , uint32_t val )
283297{
284- vfp_set_fpcr (env , val & FPSCR_FPCR_MASK );
298+ vfp_set_fpcr_masked (env , val , FPSCR_FPCR_MASK );
285299 vfp_set_fpsr (env , val & FPSCR_FPSR_MASK );
286300}
287301
0 commit comments