diff options
Diffstat (limited to 'arch/alpha/math-emu/fp-emul.c')
-rw-r--r-- | arch/alpha/math-emu/fp-emul.c | 122 |
1 files changed, 25 insertions, 97 deletions
diff --git a/arch/alpha/math-emu/fp-emul.c b/arch/alpha/math-emu/fp-emul.c index f1ff5a2be..543044019 100644 --- a/arch/alpha/math-emu/fp-emul.c +++ b/arch/alpha/math-emu/fp-emul.c @@ -1,5 +1,5 @@ +#include <linux/module.h> #include <linux/types.h> - #include <linux/kernel.h> #include <linux/sched.h> @@ -52,111 +52,33 @@ #define MISC_TRAPB 0x0000 #define MISC_EXCB 0x0400 +extern unsigned long alpha_read_fp_reg (unsigned long reg); +extern void alpha_write_fp_reg (unsigned long reg, unsigned long val); + -extern unsigned long rdfpcr (void); -extern void wrfpcr (unsigned long); +#ifdef MODULE +MODULE_DESCRIPTION("FP Software completion module"); -unsigned long -alpha_read_fp_reg (unsigned long reg) +extern long (*alpha_fp_emul_imprecise)(struct pt_regs *, unsigned long); +static long (*save_emul)(struct pt_regs *, unsigned long); +long do_alpha_fp_emul_imprecise(struct pt_regs *, unsigned long); + +int init_module(void) { - unsigned long r; - - switch (reg) { - case 0: asm ("stt $f0,%0" : "m="(r)); break; - case 1: asm ("stt $f1,%0" : "m="(r)); break; - case 2: asm ("stt $f2,%0" : "m="(r)); break; - case 3: asm ("stt $f3,%0" : "m="(r)); break; - case 4: asm ("stt $f4,%0" : "m="(r)); break; - case 5: asm ("stt $f5,%0" : "m="(r)); break; - case 6: asm ("stt $f6,%0" : "m="(r)); break; - case 7: asm ("stt $f7,%0" : "m="(r)); break; - case 8: asm ("stt $f8,%0" : "m="(r)); break; - case 9: asm ("stt $f9,%0" : "m="(r)); break; - case 10: asm ("stt $f10,%0" : "m="(r)); break; - case 11: asm ("stt $f11,%0" : "m="(r)); break; - case 12: asm ("stt $f12,%0" : "m="(r)); break; - case 13: asm ("stt $f13,%0" : "m="(r)); break; - case 14: asm ("stt $f14,%0" : "m="(r)); break; - case 15: asm ("stt $f15,%0" : "m="(r)); break; - case 16: asm ("stt $f16,%0" : "m="(r)); break; - case 17: asm ("stt $f17,%0" : "m="(r)); break; - case 18: asm ("stt $f18,%0" : "m="(r)); break; - case 19: asm ("stt $f19,%0" : "m="(r)); break; - case 20: asm ("stt $f20,%0" : "m="(r)); break; - case 21: asm ("stt $f21,%0" : "m="(r)); break; - case 22: asm ("stt $f22,%0" : "m="(r)); break; - case 23: asm ("stt $f23,%0" : "m="(r)); break; - case 24: asm ("stt $f24,%0" : "m="(r)); break; - case 25: asm ("stt $f25,%0" : "m="(r)); break; - case 26: asm ("stt $f26,%0" : "m="(r)); break; - case 27: asm ("stt $f27,%0" : "m="(r)); break; - case 28: asm ("stt $f28,%0" : "m="(r)); break; - case 29: asm ("stt $f29,%0" : "m="(r)); break; - case 30: asm ("stt $f30,%0" : "m="(r)); break; - case 31: asm ("stt $f31,%0" : "m="(r)); break; - default: - break; - } - return r; + save_emul = alpha_fp_emul_imprecise; + alpha_fp_emul_imprecise = do_alpha_fp_emul_imprecise; + return 0; } - -#if 0 -/* - * This is IMHO the better way of implementing LDT(). But it - * has the disadvantage that gcc 2.7.0 refuses to compile it - * (invalid operand constraints), so instead, we use the uglier - * macro below. - */ -# define LDT(reg,val) \ - asm volatile ("ldt $f"#reg",%0" :: "m"(val)); -#else -# define LDT(reg,val) \ - asm volatile ("ldt $f"#reg",0(%0)" :: "r"(&val)); -#endif - -void -alpha_write_fp_reg (unsigned long reg, unsigned long val) +void cleanup_module(void) { - switch (reg) { - case 0: LDT( 0, val); break; - case 1: LDT( 1, val); break; - case 2: LDT( 2, val); break; - case 3: LDT( 3, val); break; - case 4: LDT( 4, val); break; - case 5: LDT( 5, val); break; - case 6: LDT( 6, val); break; - case 7: LDT( 7, val); break; - case 8: LDT( 8, val); break; - case 9: LDT( 9, val); break; - case 10: LDT(10, val); break; - case 11: LDT(11, val); break; - case 12: LDT(12, val); break; - case 13: LDT(13, val); break; - case 14: LDT(14, val); break; - case 15: LDT(15, val); break; - case 16: LDT(16, val); break; - case 17: LDT(17, val); break; - case 18: LDT(18, val); break; - case 19: LDT(19, val); break; - case 20: LDT(20, val); break; - case 21: LDT(21, val); break; - case 22: LDT(22, val); break; - case 23: LDT(23, val); break; - case 24: LDT(24, val); break; - case 25: LDT(25, val); break; - case 26: LDT(26, val); break; - case 27: LDT(27, val); break; - case 28: LDT(28, val); break; - case 29: LDT(29, val); break; - case 30: LDT(30, val); break; - case 31: LDT(31, val); break; - default: - break; - } + alpha_fp_emul_imprecise = save_emul; } +#define alpha_fp_emul_imprecise do_alpha_fp_emul_imprecise + +#endif /* MODULE */ /* * Emulate the floating point instruction at address PC. Returns 0 if @@ -334,6 +256,8 @@ alpha_fp_emul_imprecise (struct pt_regs *regs, unsigned long write_mask) unsigned long trigger_pc = regs->pc - 4; unsigned long insn, opcode, rc; + MOD_INC_USE_COUNT; + /* * Turn off the bits corresponding to registers that are the * target of instructions that set bits in the exception @@ -354,12 +278,14 @@ alpha_fp_emul_imprecise (struct pt_regs *regs, unsigned long write_mask) case OPC_PAL: case OPC_JSR: case 0x30 ... 0x3f: /* branches */ + MOD_DEC_USE_COUNT; return 0; case OPC_MISC: switch (insn & 0xffff) { case MISC_TRAPB: case MISC_EXCB: + MOD_DEC_USE_COUNT; return 0; default: @@ -386,11 +312,13 @@ alpha_fp_emul_imprecise (struct pt_regs *regs, unsigned long write_mask) { /* re-execute insns in trap-shadow: */ regs->pc = trigger_pc + 4; + MOD_DEC_USE_COUNT; return 1; } break; } trigger_pc -= 4; } + MOD_DEC_USE_COUNT; return 0; } |