On Sat, 17 May 2025 at 13:02, <[email protected]> wrote: > > From: Helge Deller <[email protected]> > > Implement FP exception register #1 (lower 32-bits of 64-bit fr[0]). > A proper implementation is necessary to allow the Linux kernel in > system mode and the qemu linux-user to send proper si_code values > on SIGFPE signal. > > Always set the T-bit on taken exception, and merge over- and underflow > in system mode to just set overflow bit to mimic the behaviour I tested > on a physical machine.
It looks like this patch broke the setting of the Flag bits in the FPSR for non-trapped exceptions, which is https://gitlab.com/qemu-project/qemu/-/issues/3158 ... > diff --git a/target/hppa/fpu_helper.c b/target/hppa/fpu_helper.c > index a62d9d3083..294ce0a970 100644 > --- a/target/hppa/fpu_helper.c > +++ b/target/hppa/fpu_helper.c > @@ -95,7 +95,8 @@ static void update_fr0_op(CPUHPPAState *env, uintptr_t ra) > { > uint32_t soft_exp = get_float_exception_flags(&env->fp_status); > uint32_t hard_exp = 0; > - uint32_t shadow = env->fr0_shadow; > + uint32_t shadow = env->fr0_shadow & 0x3ffffff; We used to have 'shadow' contain all the existing Flag bits, but now we mask them out. So whenever we call this function we will zero out any previously set Flag bits. > + uint32_t fr1 = 0; > > if (likely(soft_exp == 0)) { > env->fr[0] = (uint64_t)shadow << 32; > @@ -108,9 +109,22 @@ static void update_fr0_op(CPUHPPAState *env, uintptr_t > ra) > hard_exp |= CONVERT_BIT(soft_exp, float_flag_overflow, > R_FPSR_ENA_O_MASK); > hard_exp |= CONVERT_BIT(soft_exp, float_flag_divbyzero, > R_FPSR_ENA_Z_MASK); > hard_exp |= CONVERT_BIT(soft_exp, float_flag_invalid, > R_FPSR_ENA_V_MASK); > - shadow |= hard_exp << (R_FPSR_FLAGS_SHIFT - R_FPSR_ENABLES_SHIFT); ...and we used to set the Flags bits for any exception that had happened, and now we don't. So setting Flags for non-trapped exceptions doesn't work. > + if (hard_exp & shadow) { > + shadow = FIELD_DP32(shadow, FPSR, T, 1); > + /* fill exception register #1, which is lower 32-bits of fr[0] */ > +#if !defined(CONFIG_USER_ONLY) > + if (hard_exp & (R_FPSR_ENA_O_MASK | R_FPSR_ENA_U_MASK)) { > + /* over- and underflow both set overflow flag only */ > + fr1 = FIELD_DP32(fr1, FPSR, C, 1); > + fr1 = FIELD_DP32(fr1, FPSR, FLG_O, 1); > + } else > +#endif > + { > + fr1 |= hard_exp << (R_FPSR_FLAGS_SHIFT - R_FPSR_ENABLES_SHIFT); > + } > + } > env->fr0_shadow = shadow; > - env->fr[0] = (uint64_t)shadow << 32; > + env->fr[0] = (uint64_t)shadow << 32 | fr1; > > if (hard_exp & shadow) { > hppa_dynamic_excp(env, EXCP_ASSIST, ra); > -- "Set all the Flag bits for non-trapping exceptions" seems straightforward. I can't see anywhere in the function which would care about the Flag bits in the 'shadow' variable, though, so I don't understand why you were masking out the Flag bits in this patch; so I'm not sure whether undoing that will break anything. (I don't have a setup to try the test program you give in this commit message.) This patch fixes the "don't trap" case: diff --git a/target/hppa/fpu_helper.c b/target/hppa/fpu_helper.c index 45353202fae..2d272730f60 100644 --- a/target/hppa/fpu_helper.c +++ b/target/hppa/fpu_helper.c @@ -94,7 +94,8 @@ static void update_fr0_op(CPUHPPAState *env, uintptr_t ra) { uint32_t soft_exp = get_float_exception_flags(&env->fp_status); uint32_t hard_exp = 0; - uint32_t shadow = env->fr0_shadow & 0x3ffffff; + uint32_t shadow = env->fr0_shadow; + uint32_t to_flag = 0; uint32_t fr1 = 0; if (likely(soft_exp == 0)) { @@ -122,6 +123,10 @@ static void update_fr0_op(CPUHPPAState *env, uintptr_t ra) fr1 |= hard_exp << (R_FPSR_FLAGS_SHIFT - R_FPSR_ENABLES_SHIFT); } } + /* Set the Flag bits for every exception that was not enabled */ + to_flag = hard_exp & ~shadow; + shadow |= to_flag << (R_FPSR_FLAGS_SHIFT - R_FPSR_ENABLES_SHIFT); + env->fr0_shadow = shadow; env->fr[0] = (uint64_t)shadow << 32 | fr1; If it looks OK I'll send it as a proper patch. -- PMM
