From: kaz K. <kk...@rr...> - 2001-08-01 13:27:23
|
Hi, I've talked about FCNVSD problem with Amir Hader. Amir Hadar <ami...@is...> wrote: > How do I use floating point emulation. The sh4-linux-gcc doesn't > recognize -msoft-float option. Is there an already made module that I > can linkup with my project that catches the SIGFPE and do the emulation? > What other workaround can do to support full denormelized floats and > doubles? There is no such module yet, as I know. The emulation itself isn't hard. Attached code is for the experimental emulation. But this isn't working code in the current kernel. Hacking kernel will be needed to implement such emulation in the kernel and I have no idea for other workaround. Of course, an awful workaround is to test float whether it's denormalized or not in userland and if it's denormalized, then construct valid double value by hand (as denormal_to_double () does), though nobody will do it. kaz -- static void denormal_to_double (struct pt_regs *regs, unsigned long x, int n) { unsigned long du, dl; int exp = 1023 - 126; if (x != 0 && (x & 0x7f800000) == 0) { du = (x & 0x80000000); while ((x & 0x00800000) == 0) { x <<= 1; exp--; } x &= 0x007fffff; du |= (exp << 20) | (x >> 3); dl = x << 29; regs->fpregs[n] = du; regs->fpregs[n+1] = dl; } } static int ieee_fpe_handler (struct pt_regs *regs) { unsigned short insn = *(unsigned short *) regs->pc; unsigned short finsn; unsigned long nextpc; int nib[4] = { (insn >> 12) & 0xf, (insn >> 8) & 0xf, (insn >> 4) & 0xf, insn & 0xf}; if (nib[0] == 0xb || (nib[0] == 0x4 && nib[2] == 0x0 && nib[3] == 0xb)) /* bsr & jsr */ regs->pr = regs->pc + 4; if (nib[0] == 0xa || nib[0] == 0xb) /* bra & bsr */ { nextpc = regs->pc + 4 + ((short) ((insn & 0xfff) << 4) >> 3); finsn = *(unsigned short *) (regs->pc + 2); } else if (nib[0] == 0x8 && nib[1] == 0xd) /* bt/s */ { if (regs->sr & 1) nextpc = regs->pc + 4 + ((char) (insn & 0xff) << 1); else nextpc = regs->pc + 4; finsn = *(unsigned short *) (regs->pc + 2); } else if (nib[0] == 0x8 && nib[1] == 0xf) /* bf/s */ { if (regs->sr & 1) nextpc = regs->pc + 4; else nextpc = regs->pc + 4 + ((char) (insn & 0xff) << 1); finsn = *(unsigned short *) (regs->pc + 2); } else if (nib[0] == 0x4 && nib[3] == 0xb && (nib[2] == 0x0 || nib[2] == 0x2)) /* jmp & jsr */ { nextpc = regs->regs[nib[1]]; finsn = *(unsigned short *) (regs->pc + 2); } else if (nib[0] == 0x0 && nib[3] == 0x3 && (nib[2] == 0x0 || nib[2] == 0x2)) /* braf & bsrf */ { nextpc = regs->pc + 4 + regs->regs[nib[1]]; finsn = *(unsigned short *) (regs->pc + 2); } else if (insn == 0x000b) /* rts */ { nextpc = regs->pr; finsn = *(unsigned short *) (regs->pc + 2); } else { nextpc = regs->pc + 2; finsn = insn; } if ((finsn & 0xf1ff) == 0xf0ad && (regs->fpscr & (1 << 17))) /* fcnvsd & FPU error */ { denormal_to_double (regs, regs->fpul, (finsn >> 8) & 0xf); regs->fpscr &= ~(FPSCR_CAUSE_MASK | FPSCR_FLAG_MASK); regs->pc = nextpc; return 1; } return 0; } |