?? math.c
字號:
/* * arch/s390/math-emu/math.c * * S390 version * Copyright (C) 1999-2001 IBM Deutschland Entwicklung GmbH, IBM Corporation * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), * * 'math.c' emulates IEEE instructions on a S390 processor * that does not have the IEEE fpu (all processors before G5). */#include <linux/config.h>#include <linux/types.h>#include <linux/sched.h>#include <linux/mm.h>#include <asm/uaccess.h>#include "sfp-util.h"#include <math-emu/soft-fp.h>#include <math-emu/single.h>#include <math-emu/double.h>#include <math-emu/quad.h>/* * I miss a macro to round a floating point number to the * nearest integer in the same floating point format. */#define _FP_TO_FPINT_ROUND(fs, wc, X) \ do { \ switch (X##_c) \ { \ case FP_CLS_NORMAL: \ if (X##_e > _FP_FRACBITS_##fs + _FP_EXPBIAS_##fs) \ { /* floating point number has no bits after the dot. */ \ } \ else if (X##_e <= _FP_FRACBITS_##fs + _FP_EXPBIAS_##fs && \ X##_e > _FP_EXPBIAS_##fs) \ { /* some bits before the dot, some after it. */ \ _FP_FRAC_SRS_##wc(X, _FP_WFRACBITS_##fs, \ X##_e - _FP_EXPBIAS_##fs \ + _FP_FRACBITS_##fs); \ _FP_ROUND(wc, X); \ _FP_FRAC_SLL_##wc(X, X##_e - _FP_EXPBIAS_##fs \ + _FP_FRACBITS_##fs); \ } \ else \ { /* all bits after the dot. */ \ FP_SET_EXCEPTION(FP_EX_INEXACT); \ X##_c = FP_CLS_ZERO; \ } \ break; \ case FP_CLS_NAN: \ case FP_CLS_INF: \ case FP_CLS_ZERO: \ break; \ } \ } while (0)#define FP_TO_FPINT_ROUND_S(X) _FP_TO_FPINT_ROUND(S,1,X)#define FP_TO_FPINT_ROUND_D(X) _FP_TO_FPINT_ROUND(D,2,X)#define FP_TO_FPINT_ROUND_Q(X) _FP_TO_FPINT_ROUND(Q,4,X)typedef union { long double ld; struct { __u64 high; __u64 low; } w;} mathemu_ldcv;#ifdef CONFIG_SYSCTLint sysctl_ieee_emulation_warnings=1;#endif#define mathemu_put_user(x, p) \ do { \ if (put_user((x),(p))) \ return SIGSEGV; \ } while (0)#define mathemu_get_user(x, p) \ do { \ if (get_user((x),(p))) \ return SIGSEGV; \ } while (0)#define mathemu_copy_from_user(d, s, n)\ do { \ if (copy_from_user((d),(s),(n)) == -EFAULT) \ return SIGSEGV; \ } while (0)#define mathemu_copy_to_user(d, s, n) \ do { \ if (copy_to_user((d),(s),(n)) == -EFAULT) \ return SIGSEGV; \ } while (0)static void display_emulation_not_implemented(struct pt_regs *regs, char *instr){ struct pt_regs *regs; __u16 *location; #if CONFIG_SYSCTL if(sysctl_ieee_emulation_warnings)#endif { location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc); printk("%s ieee fpu instruction not emulated " "process name: %s pid: %d \n", instr, current->comm, current->pid); printk("%s's PSW: %08lx %08lx\n", instr, (unsigned long) regs->psw.mask, (unsigned long) location); }}static inline void emu_set_CC (struct pt_regs *regs, int cc){ regs->psw.mask = (regs->psw.mask & 0xFFFFCFFF) | ((cc&3) << 12);}/* * Set the condition code in the user psw. * 0 : Result is zero * 1 : Result is less than zero * 2 : Result is greater than zero * 3 : Result is NaN or INF */static inline void emu_set_CC_cs(struct pt_regs *regs, int class, int sign){ switch (class) { case FP_CLS_NORMAL: case FP_CLS_INF: emu_set_CC(regs, sign ? 1 : 2); break; case FP_CLS_ZERO: emu_set_CC(regs, 0); break; case FP_CLS_NAN: emu_set_CC(regs, 3); break; }}/* Add long double */static int emu_axbr (struct pt_regs *regs, int rx, int ry) { FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_Q(QR); FP_DECL_EX; mathemu_ldcv cvt; int mode; mode = current->thread.fp_regs.fpc & 3; cvt.w.high = current->thread.fp_regs.fprs[rx].ui; cvt.w.low = current->thread.fp_regs.fprs[rx+2].ui; FP_UNPACK_QP(QA, &cvt.ld); cvt.w.high = current->thread.fp_regs.fprs[ry].ui; cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui; FP_UNPACK_QP(QB, &cvt.ld); FP_ADD_Q(QR, QA, QB); FP_PACK_QP(&cvt.ld, QR); current->thread.fp_regs.fprs[rx].ui = cvt.w.high; current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low; emu_set_CC_cs(regs, QR_c, QR_s); return _fex;}/* Add double */static int emu_adbr (struct pt_regs *regs, int rx, int ry) { FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR); FP_DECL_EX; int mode; mode = current->thread.fp_regs.fpc & 3; FP_UNPACK_DP(DA, ¤t->thread.fp_regs.fprs[rx].d); FP_UNPACK_DP(DB, ¤t->thread.fp_regs.fprs[ry].d); FP_ADD_D(DR, DA, DB); FP_PACK_DP(¤t->thread.fp_regs.fprs[rx].d, DR); emu_set_CC_cs(regs, DR_c, DR_s); return _fex;}/* Add double */static int emu_adb (struct pt_regs *regs, int rx, double *val) { FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR); FP_DECL_EX; int mode; mode = current->thread.fp_regs.fpc & 3; FP_UNPACK_DP(DA, ¤t->thread.fp_regs.fprs[rx].d); FP_UNPACK_DP(DB, val); FP_ADD_D(DR, DA, DB); FP_PACK_DP(¤t->thread.fp_regs.fprs[rx].d, DR); emu_set_CC_cs(regs, DR_c, DR_s); return _fex;}/* Add float */static int emu_aebr (struct pt_regs *regs, int rx, int ry) { FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR); FP_DECL_EX; int mode; mode = current->thread.fp_regs.fpc & 3; FP_UNPACK_SP(SA, ¤t->thread.fp_regs.fprs[rx].f); FP_UNPACK_SP(SB, ¤t->thread.fp_regs.fprs[ry].f); FP_ADD_S(SR, SA, SB); FP_PACK_SP(¤t->thread.fp_regs.fprs[rx].f, SR); emu_set_CC_cs(regs, SR_c, SR_s); return _fex;}/* Add float */static int emu_aeb (struct pt_regs *regs, int rx, float *val) { FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR); FP_DECL_EX; int mode; mode = current->thread.fp_regs.fpc & 3; FP_UNPACK_SP(SA, ¤t->thread.fp_regs.fprs[rx].f); FP_UNPACK_SP(SB, val); FP_ADD_S(SR, SA, SB); FP_PACK_SP(¤t->thread.fp_regs.fprs[rx].f, SR); emu_set_CC_cs(regs, SR_c, SR_s); return _fex;}/* Compare long double */static int emu_cxbr (struct pt_regs *regs, int rx, int ry) { FP_DECL_Q(QA); FP_DECL_Q(QB); mathemu_ldcv cvt; int IR; cvt.w.high = current->thread.fp_regs.fprs[rx].ui; cvt.w.low = current->thread.fp_regs.fprs[rx+2].ui; FP_UNPACK_RAW_QP(QA, &cvt.ld); cvt.w.high = current->thread.fp_regs.fprs[ry].ui; cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui; FP_UNPACK_RAW_QP(QB, &cvt.ld); FP_CMP_Q(IR, QA, QB, 3); /* * IR == -1 if DA < DB, IR == 0 if DA == DB, * IR == 1 if DA > DB and IR == 3 if unorderded */ emu_set_CC(regs, (IR == -1) ? 1 : (IR == 1) ? 2 : IR); return 0;}/* Compare double */static int emu_cdbr (struct pt_regs *regs, int rx, int ry) { FP_DECL_D(DA); FP_DECL_D(DB); int IR; FP_UNPACK_RAW_DP(DA, ¤t->thread.fp_regs.fprs[rx].d); FP_UNPACK_RAW_DP(DB, ¤t->thread.fp_regs.fprs[ry].d); FP_CMP_D(IR, DA, DB, 3); /* * IR == -1 if DA < DB, IR == 0 if DA == DB, * IR == 1 if DA > DB and IR == 3 if unorderded */ emu_set_CC(regs, (IR == -1) ? 1 : (IR == 1) ? 2 : IR); return 0;}/* Compare double */static int emu_cdb (struct pt_regs *regs, int rx, double *val) { FP_DECL_D(DA); FP_DECL_D(DB); int IR; FP_UNPACK_RAW_DP(DA, ¤t->thread.fp_regs.fprs[rx].d); FP_UNPACK_RAW_DP(DB, val); FP_CMP_D(IR, DA, DB, 3); /* * IR == -1 if DA < DB, IR == 0 if DA == DB, * IR == 1 if DA > DB and IR == 3 if unorderded */ emu_set_CC(regs, (IR == -1) ? 1 : (IR == 1) ? 2 : IR); return 0;}/* Compare float */static int emu_cebr (struct pt_regs *regs, int rx, int ry) { FP_DECL_S(SA); FP_DECL_S(SB); int IR; FP_UNPACK_RAW_SP(SA, ¤t->thread.fp_regs.fprs[rx].f); FP_UNPACK_RAW_SP(SB, ¤t->thread.fp_regs.fprs[ry].f); FP_CMP_S(IR, SA, SB, 3); /* * IR == -1 if DA < DB, IR == 0 if DA == DB, * IR == 1 if DA > DB and IR == 3 if unorderded */ emu_set_CC(regs, (IR == -1) ? 1 : (IR == 1) ? 2 : IR); return 0;}/* Compare float */static int emu_ceb (struct pt_regs *regs, int rx, float *val) { FP_DECL_S(SA); FP_DECL_S(SB); int IR; FP_UNPACK_RAW_SP(SA, ¤t->thread.fp_regs.fprs[rx].f); FP_UNPACK_RAW_SP(SB, val); FP_CMP_S(IR, SA, SB, 3); /* * IR == -1 if DA < DB, IR == 0 if DA == DB, * IR == 1 if DA > DB and IR == 3 if unorderded */ emu_set_CC(regs, (IR == -1) ? 1 : (IR == 1) ? 2 : IR); return 0;}/* Compare and signal long double */static int emu_kxbr (struct pt_regs *regs, int rx, int ry) { FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_EX; mathemu_ldcv cvt; int IR; cvt.w.high = current->thread.fp_regs.fprs[rx].ui; cvt.w.low = current->thread.fp_regs.fprs[rx+2].ui; FP_UNPACK_RAW_QP(QA, &cvt.ld); cvt.w.high = current->thread.fp_regs.fprs[ry].ui; cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui; FP_UNPACK_QP(QB, &cvt.ld); FP_CMP_Q(IR, QA, QB, 3); /* * IR == -1 if DA < DB, IR == 0 if DA == DB, * IR == 1 if DA > DB and IR == 3 if unorderded */ emu_set_CC(regs, (IR == -1) ? 1 : (IR == 1) ? 2 : IR); if (IR == 3) FP_SET_EXCEPTION (FP_EX_INVALID); return _fex;}/* Compare and signal double */static int emu_kdbr (struct pt_regs *regs, int rx, int ry) { FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_EX; int IR; FP_UNPACK_RAW_DP(DA, ¤t->thread.fp_regs.fprs[rx].d); FP_UNPACK_RAW_DP(DB, ¤t->thread.fp_regs.fprs[ry].d); FP_CMP_D(IR, DA, DB, 3); /* * IR == -1 if DA < DB, IR == 0 if DA == DB, * IR == 1 if DA > DB and IR == 3 if unorderded */ emu_set_CC(regs, (IR == -1) ? 1 : (IR == 1) ? 2 : IR); if (IR == 3) FP_SET_EXCEPTION (FP_EX_INVALID); return _fex;}/* Compare and signal double */static int emu_kdb (struct pt_regs *regs, int rx, double *val) { FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_EX; int IR; FP_UNPACK_RAW_DP(DA, ¤t->thread.fp_regs.fprs[rx].d); FP_UNPACK_RAW_DP(DB, val); FP_CMP_D(IR, DA, DB, 3); /* * IR == -1 if DA < DB, IR == 0 if DA == DB, * IR == 1 if DA > DB and IR == 3 if unorderded */ emu_set_CC(regs, (IR == -1) ? 1 : (IR == 1) ? 2 : IR); if (IR == 3) FP_SET_EXCEPTION (FP_EX_INVALID); return _fex;}/* Compare and signal float */static int emu_kebr (struct pt_regs *regs, int rx, int ry) { FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_EX; int IR; FP_UNPACK_RAW_SP(SA, ¤t->thread.fp_regs.fprs[rx].f); FP_UNPACK_RAW_SP(SB, ¤t->thread.fp_regs.fprs[ry].f); FP_CMP_S(IR, SA, SB, 3); /* * IR == -1 if DA < DB, IR == 0 if DA == DB, * IR == 1 if DA > DB and IR == 3 if unorderded */ emu_set_CC(regs, (IR == -1) ? 1 : (IR == 1) ? 2 : IR); if (IR == 3) FP_SET_EXCEPTION (FP_EX_INVALID); return _fex;}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -