Re: Unexpected behaviour when catching SIGFPE on FPU-less system

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, May 4, 2010 at 5:16 AM, Kevin D. Kissell <kevink@xxxxxxxxxxxxx> wrote:
> Shane McDonald wrote:
>> When I'm inside my handler, I see the FCSR register has the value 0x8420,
>> indicating that the Z bit is set in each of the Cause, Enables, and Flags
>> fields.  When longjmp() is called, it tries to write the old FCSR value
>> of 0x400 (just the Z bit of the Enables field).  In the emulation code,
>> at lines 392 - 394 of file cp1emu.c, is the code:
>>
>>     if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) {
>>             return SIGFPE;
>>     }
>>
>> Given the original FCSR value of 0x8420 and the new value to set
>> of 0x400, the Z bit of the Cause field is still set, and as a result, the
>> above code causes the SIGFPE exception to be thrown.
>>
> That's not how I read the code.  If ctx->fcr31 is 0x400, then the result
> of the AND should be zero.

Sorry, I should have been more clear.

In the following chunk of code from cp1emu.c:

                case ctc_op:{
                        /* copregister rd <- rt */
                        u32 value;

                        if (MIPSInst_RT(ir) == 0)
                                value = 0;
                        else
                                value = xcp->regs[MIPSInst_RT(ir)];

                        /* we only have one writable control reg
                         */
                        if (MIPSInst_RD(ir) == FPCREG_CSR) {
#ifdef CSRTRACE
                                printk("%p gpr[%d]->csr=%08x\n",
                                        (void *) (xcp->cp0_epc),
                                        MIPSInst_RT(ir), value);
#endif
                                value &= (FPU_CSR_FLUSH |
FPU_CSR_ALL_E | FPU_CSR_ALL_S | 0x03);
                                ctx->fcr31 &= ~(FPU_CSR_FLUSH |
FPU_CSR_ALL_E | FPU_CSR_ALL_S | 0x03);
                                /* convert to ieee library modes */
                                ctx->fcr31 |= (value & ~0x3) |
ieee_rm[value & 0x3];
                        }
                        if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) {
                                return SIGFPE;
                        }
                        break;

value gets set to an initial value of 0x400, and ctx->fcr31
comes in with an initial value of 0x8420.
By the time we hit the if statement around the return SIGFPE, ctx->fcr31
has been set to 0x8400, not the 0x400 I implied.

Nevertheless, that's not the problem.  You've given me some good pointers
for where to begin searching for the problem.

If anyone out there has a verification suite they can run on the emulator,
that would be much appreciated!

Shane


[Index of Archives]     [Linux MIPS Home]     [LKML Archive]     [Linux ARM Kernel]     [Linux ARM]     [Linux]     [Git]     [Yosemite News]     [Linux SCSI]     [Linux Hams]

  Powered by Linux