diff -Nur linux-sharp-c860/arch/arm/nwfpe/ChangeLog linux-sharp-c860+nwfpe/arch/arm/nwfpe/ChangeLog --- linux-sharp-c860/arch/arm/nwfpe/ChangeLog 2002-08-26 14:45:38.000000000 +0900 +++ linux-sharp-c860+nwfpe/arch/arm/nwfpe/ChangeLog 2003-08-25 20:44:39.000000000 +0900 @@ -1,3 +1,11 @@ +2003-03-22 Ralph Siemsen + * Reformat all but softfloat files to get a consistent coding style. + Used "indent -kr -i8 -ts8 -sob -l132 -ss" and a few manual fixups. + * Removed dead code and fixed function protypes to match definitions. + * Consolidated use of (opcode && MASK_ARITHMETIC_OPCODE) >> 20. + * Make 80-bit precision a compile-time option. (1%) + * Only initialize FPE state once in repeat-FP situations. (6%) + 2002-01-19 Russell King * fpa11.h - Add documentation diff -Nur linux-sharp-c860/arch/arm/nwfpe/Makefile linux-sharp-c860+nwfpe/arch/arm/nwfpe/Makefile --- linux-sharp-c860/arch/arm/nwfpe/Makefile 2002-08-26 14:39:50.000000000 +0900 +++ linux-sharp-c860+nwfpe/arch/arm/nwfpe/Makefile 2003-08-25 20:44:39.000000000 +0900 @@ -18,7 +18,11 @@ nwfpe-objs := fpa11.o fpa11_cpdo.o fpa11_cpdt.o fpa11_cprt.o \ fpmodule.o fpopcode.o softfloat.o \ - single_cpdo.o double_cpdo.o extended_cpdo.o + single_cpdo.o double_cpdo.o + +ifeq ($(CONFIG_FPE_NWFPE_XP),y) +nwfpe-objs += extended_cpdo.o +endif ifeq ($(CONFIG_CPU_26),y) nwfpe-objs += entry26.o diff -Nur linux-sharp-c860/arch/arm/nwfpe/double_cpdo.c linux-sharp-c860+nwfpe/arch/arm/nwfpe/double_cpdo.c --- linux-sharp-c860/arch/arm/nwfpe/double_cpdo.c 2002-08-26 14:45:38.000000000 +0900 +++ linux-sharp-c860+nwfpe/arch/arm/nwfpe/double_cpdo.c 2003-08-25 20:44:39.000000000 +0900 @@ -23,6 +23,11 @@ #include "softfloat.h" #include "fpopcode.h" +union float64_components { + float64 f64; + unsigned int i[2]; +}; + float64 float64_exp(float64 Fm); float64 float64_ln(float64 Fm); float64 float64_sin(float64 rFm); @@ -32,257 +37,123 @@ float64 float64_log(float64 rFm); float64 float64_tan(float64 rFm); float64 float64_arccos(float64 rFm); -float64 float64_pow(float64 rFn,float64 rFm); -float64 float64_pol(float64 rFn,float64 rFm); +float64 float64_pow(float64 rFn, float64 rFm); +float64 float64_pol(float64 rFn, float64 rFm); -unsigned int DoubleCPDO(const unsigned int opcode) +static float64 float64_rsf(float64 rFn, float64 rFm) { - FPA11 *fpa11 = GET_FPA11(); - float64 rFm, rFn; - unsigned int Fd, Fm, Fn, nRc = 1; - - //printk("DoubleCPDO(0x%08x)\n",opcode); - - Fm = getFm(opcode); - if (CONSTANT_FM(opcode)) - { - rFm = getDoubleConstant(Fm); - } - else - { - switch (fpa11->fType[Fm]) - { - case typeSingle: - rFm = float32_to_float64(fpa11->fpreg[Fm].fSingle); - break; - - case typeDouble: - rFm = fpa11->fpreg[Fm].fDouble; - break; - - case typeExtended: - // !! patb - //printk("not implemented! why not?\n"); - //!! ScottB - // should never get here, if extended involved - // then other operand should be promoted then - // ExtendedCPDO called. - break; - - default: return 0; - } - } - - if (!MONADIC_INSTRUCTION(opcode)) - { - Fn = getFn(opcode); - switch (fpa11->fType[Fn]) - { - case typeSingle: - rFn = float32_to_float64(fpa11->fpreg[Fn].fSingle); - break; - - case typeDouble: - rFn = fpa11->fpreg[Fn].fDouble; - break; - - default: return 0; - } - } - - Fd = getFd(opcode); - /* !! this switch isn't optimized; better (opcode & MASK_ARITHMETIC_OPCODE)>>24, sort of */ - switch (opcode & MASK_ARITHMETIC_OPCODE) - { - /* dyadic opcodes */ - case ADF_CODE: - fpa11->fpreg[Fd].fDouble = float64_add(rFn,rFm); - break; - - case MUF_CODE: - case FML_CODE: - fpa11->fpreg[Fd].fDouble = float64_mul(rFn,rFm); - break; - - case SUF_CODE: - fpa11->fpreg[Fd].fDouble = float64_sub(rFn,rFm); - break; - - case RSF_CODE: - fpa11->fpreg[Fd].fDouble = float64_sub(rFm,rFn); - break; - - case DVF_CODE: - case FDV_CODE: - fpa11->fpreg[Fd].fDouble = float64_div(rFn,rFm); - break; - - case RDF_CODE: - case FRD_CODE: - fpa11->fpreg[Fd].fDouble = float64_div(rFm,rFn); - break; - -#if 0 - case POW_CODE: - fpa11->fpreg[Fd].fDouble = float64_pow(rFn,rFm); - break; - - case RPW_CODE: - fpa11->fpreg[Fd].fDouble = float64_pow(rFm,rFn); - break; -#endif - - case RMF_CODE: - fpa11->fpreg[Fd].fDouble = float64_rem(rFn,rFm); - break; - -#if 0 - case POL_CODE: - fpa11->fpreg[Fd].fDouble = float64_pol(rFn,rFm); - break; -#endif - - /* monadic opcodes */ - case MVF_CODE: - fpa11->fpreg[Fd].fDouble = rFm; - break; - - case MNF_CODE: - { - unsigned int *p = (unsigned int*)&rFm; - p[1] ^= 0x80000000; - fpa11->fpreg[Fd].fDouble = rFm; - } - break; - - case ABS_CODE: - { - unsigned int *p = (unsigned int*)&rFm; - p[1] &= 0x7fffffff; - fpa11->fpreg[Fd].fDouble = rFm; - } - break; - - case RND_CODE: - case URD_CODE: - fpa11->fpreg[Fd].fDouble = float64_round_to_int(rFm); - break; - - case SQT_CODE: - fpa11->fpreg[Fd].fDouble = float64_sqrt(rFm); - break; - -#if 0 - case LOG_CODE: - fpa11->fpreg[Fd].fDouble = float64_log(rFm); - break; - - case LGN_CODE: - fpa11->fpreg[Fd].fDouble = float64_ln(rFm); - break; - - case EXP_CODE: - fpa11->fpreg[Fd].fDouble = float64_exp(rFm); - break; - - case SIN_CODE: - fpa11->fpreg[Fd].fDouble = float64_sin(rFm); - break; - - case COS_CODE: - fpa11->fpreg[Fd].fDouble = float64_cos(rFm); - break; - - case TAN_CODE: - fpa11->fpreg[Fd].fDouble = float64_tan(rFm); - break; - - case ASN_CODE: - fpa11->fpreg[Fd].fDouble = float64_arcsin(rFm); - break; - - case ACS_CODE: - fpa11->fpreg[Fd].fDouble = float64_arccos(rFm); - break; - - case ATN_CODE: - fpa11->fpreg[Fd].fDouble = float64_arctan(rFm); - break; -#endif - - case NRM_CODE: - break; - - default: - { - nRc = 0; - } - } - - if (0 != nRc) fpa11->fType[Fd] = typeDouble; - return nRc; + return float64_sub(rFm, rFn); } -#if 0 -float64 float64_exp(float64 rFm) +static float64 float64_rdv(float64 rFn, float64 rFm) { - return rFm; -//series + return float64_div(rFm, rFn); } -float64 float64_ln(float64 rFm) -{ - return rFm; -//series -} +static float64 (*const dyadic_double[16])(float64 rFn, float64 rFm) = { + [ADF_CODE >> 20] = float64_add, + [MUF_CODE >> 20] = float64_mul, + [SUF_CODE >> 20] = float64_sub, + [RSF_CODE >> 20] = float64_rsf, + [DVF_CODE >> 20] = float64_div, + [RDF_CODE >> 20] = float64_rdv, + [RMF_CODE >> 20] = float64_rem, -float64 float64_sin(float64 rFm) -{ - return rFm; -//series -} + /* strictly, these opcodes should not be implemented */ + [FML_CODE >> 20] = float64_mul, + [FDV_CODE >> 20] = float64_div, + [FRD_CODE >> 20] = float64_rdv, +}; -float64 float64_cos(float64 rFm) +static float64 float64_mvf(float64 rFm) { - return rFm; - //series + return rFm; } -#if 0 -float64 float64_arcsin(float64 rFm) +static float64 float64_mnf(float64 rFm) { -//series -} + union float64_components u; -float64 float64_arctan(float64 rFm) -{ - //series -} -#endif + u.f64 = rFm; + u.i[1] ^= 0x80000000; -float64 float64_log(float64 rFm) -{ - return float64_div(float64_ln(rFm),getDoubleConstant(7)); + return u.f64; } -float64 float64_tan(float64 rFm) +static float64 float64_abs(float64 rFm) { - return float64_div(float64_sin(rFm),float64_cos(rFm)); -} + union float64_components u; -float64 float64_arccos(float64 rFm) -{ -return rFm; - //return float64_sub(halfPi,float64_arcsin(rFm)); -} + u.f64 = rFm; + u.i[1] &= 0x7fffffff; -float64 float64_pow(float64 rFn,float64 rFm) -{ - return float64_exp(float64_mul(rFm,float64_ln(rFn))); + return u.f64; } -float64 float64_pol(float64 rFn,float64 rFm) +static float64 (*const monadic_double[16])(float64 rFm) = { + [MVF_CODE >> 20] = float64_mvf, + [MNF_CODE >> 20] = float64_mnf, + [ABS_CODE >> 20] = float64_abs, + [RND_CODE >> 20] = float64_round_to_int, + [URD_CODE >> 20] = float64_round_to_int, + [SQT_CODE >> 20] = float64_sqrt, + [NRM_CODE >> 20] = float64_mvf, +}; + +unsigned int DoubleCPDO(const unsigned int opcode, FPREG * rFd) { - return float64_arctan(float64_div(rFn,rFm)); + FPA11 *fpa11 = GET_FPA11(); + float64 rFm; + unsigned int Fm, opc_mask_shift; + + Fm = getFm(opcode); + if (CONSTANT_FM(opcode)) { + rFm = getDoubleConstant(Fm); + } else { + switch (fpa11->fType[Fm]) { + case typeSingle: + rFm = float32_to_float64(fpa11->fpreg[Fm].fSingle); + break; + + case typeDouble: + rFm = fpa11->fpreg[Fm].fDouble; + break; + + default: + return 0; + } + } + + opc_mask_shift = (opcode & MASK_ARITHMETIC_OPCODE) >> 20; + if (!MONADIC_INSTRUCTION(opcode)) { + unsigned int Fn = getFn(opcode); + float64 rFn; + + switch (fpa11->fType[Fn]) { + case typeSingle: + rFn = float32_to_float64(fpa11->fpreg[Fn].fSingle); + break; + + case typeDouble: + rFn = fpa11->fpreg[Fn].fDouble; + break; + + default: + return 0; + } + + if (dyadic_double[opc_mask_shift]) { + rFd->fDouble = dyadic_double[opc_mask_shift](rFn, rFm); + } else { + return 0; + } + } else { + if (monadic_double[opc_mask_shift]) { + rFd->fDouble = monadic_double[opc_mask_shift](rFm); + } else { + return 0; + } + } + + return 1; } -#endif diff -Nur linux-sharp-c860/arch/arm/nwfpe/entry.S linux-sharp-c860+nwfpe/arch/arm/nwfpe/entry.S --- linux-sharp-c860/arch/arm/nwfpe/entry.S 2002-08-26 14:45:38.000000000 +0900 +++ linux-sharp-c860+nwfpe/arch/arm/nwfpe/entry.S 2003-08-25 20:44:39.000000000 +0900 @@ -70,39 +70,42 @@ .globl nwfpe_enter nwfpe_enter: - mov r4, lr @ save the failure-return addresses - mov sl, sp @ we access the registers via 'sl' - - ldr r5, [sp, #60] @ get contents of PC; - sub r8, r5, #4 -.Lx2: ldrt r0, [r8] @ get actual instruction into r0 + mov r4, lr @ save the failure-return addresses + ldr ip, [r10, #112] @ get init_flag + mov sl, sp @ we access the registers via 'sl' + + ldr r5, [sp, #60] @ get contents of PC; + cmp ip, #0 + bleq nwfpe_init_fpa + sub r8, r5, #4 +.Lx1: ldrt r0, [r8] @ get actual instruction into r0 emulate: - bl EmulateAll @ emulate the instruction - cmp r0, #0 @ was emulation successful - moveq pc, r4 @ no, return failure + bl EmulateAll @ emulate the instruction + cmp r0, #0 @ was emulation successful + moveq pc, r4 @ no, return failure next: -.Lx1: ldrt r6, [r5], #4 @ get the next instruction and +.Lx2: ldrt r6, [r5], #4 @ get the next instruction and @ increment PC - and r2, r6, #0x0F000000 @ test for FP insns - teq r2, #0x0C000000 - teqne r2, #0x0D000000 - teqne r2, #0x0E000000 - movne pc, r9 @ return ok if not a fp insn - - str r5, [sp, #60] @ update PC copy in regs - - mov r0, r6 @ save a copy - ldr r1, [sp, #64] @ fetch the condition codes - bl checkCondition @ check the condition - cmp r0, #0 @ r0 = 0 ==> condition failed - - @ if condition code failed to match, next insn - beq next @ get the next instruction; - - mov r0, r6 @ prepare for EmulateAll() - b emulate @ if r0 != 0, goto EmulateAll + and r2, r6, #0x0F000000 @ test for FP insns + teq r2, #0x0C000000 + teqne r2, #0x0D000000 + teqne r2, #0x0E000000 + movne pc, r9 @ return ok if not a fp insn + + str r5, [sp, #60] @ update PC copy in regs + + mov r0, r6 @ save a copy + ldr r1, [sp, #64] @ fetch the condition codes + bl checkCondition @ check the condition + cmp r0, #0 @ r0 = 0 ==> condition failed + + @ if condition code failed to match, next insn + beq next @ get the next instruction; + + mov r0, r6 @ prepare for EmulateAll() + b emulate @ if r0 != 0, goto EmulateAll @ We need to be prepared for the instructions at .Lx1 and .Lx2 @ to fault. Emit the appropriate exception gunk to fix things up. diff -Nur linux-sharp-c860/arch/arm/nwfpe/entry26.S linux-sharp-c860+nwfpe/arch/arm/nwfpe/entry26.S --- linux-sharp-c860/arch/arm/nwfpe/entry26.S 2002-08-26 14:45:38.000000000 +0900 +++ linux-sharp-c860+nwfpe/arch/arm/nwfpe/entry26.S 2003-08-25 20:44:39.000000000 +0900 @@ -95,7 +95,7 @@ @ if condition code failed to match, next insn beq next @ get the next instruction; - + mov r0, r6 @ prepare for EmulateAll() adr lr, 1b orr lr, lr, #3 diff -Nur linux-sharp-c860/arch/arm/nwfpe/extended_cpdo.c linux-sharp-c860+nwfpe/arch/arm/nwfpe/extended_cpdo.c --- linux-sharp-c860/arch/arm/nwfpe/extended_cpdo.c 2002-08-26 14:45:38.000000000 +0900 +++ linux-sharp-c860+nwfpe/arch/arm/nwfpe/extended_cpdo.c 2003-08-25 20:44:39.000000000 +0900 @@ -32,242 +32,123 @@ floatx80 floatx80_log(floatx80 rFm); floatx80 floatx80_tan(floatx80 rFm); floatx80 floatx80_arccos(floatx80 rFm); -floatx80 floatx80_pow(floatx80 rFn,floatx80 rFm); -floatx80 floatx80_pol(floatx80 rFn,floatx80 rFm); +floatx80 floatx80_pow(floatx80 rFn, floatx80 rFm); +floatx80 floatx80_pol(floatx80 rFn, floatx80 rFm); -unsigned int ExtendedCPDO(const unsigned int opcode) +static floatx80 floatx80_rsf(floatx80 rFn, floatx80 rFm) { - FPA11 *fpa11 = GET_FPA11(); - floatx80 rFm, rFn; - unsigned int Fd, Fm, Fn, nRc = 1; - - //printk("ExtendedCPDO(0x%08x)\n",opcode); - - Fm = getFm(opcode); - if (CONSTANT_FM(opcode)) - { - rFm = getExtendedConstant(Fm); - } - else - { - switch (fpa11->fType[Fm]) - { - case typeSingle: - rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle); - break; - - case typeDouble: - rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble); - break; - - case typeExtended: - rFm = fpa11->fpreg[Fm].fExtended; - break; - - default: return 0; - } - } - - if (!MONADIC_INSTRUCTION(opcode)) - { - Fn = getFn(opcode); - switch (fpa11->fType[Fn]) - { - case typeSingle: - rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle); - break; - - case typeDouble: - rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble); - break; - - case typeExtended: - rFn = fpa11->fpreg[Fn].fExtended; - break; - - default: return 0; - } - } - - Fd = getFd(opcode); - switch (opcode & MASK_ARITHMETIC_OPCODE) - { - /* dyadic opcodes */ - case ADF_CODE: - fpa11->fpreg[Fd].fExtended = floatx80_add(rFn,rFm); - break; - - case MUF_CODE: - case FML_CODE: - fpa11->fpreg[Fd].fExtended = floatx80_mul(rFn,rFm); - break; - - case SUF_CODE: - fpa11->fpreg[Fd].fExtended = floatx80_sub(rFn,rFm); - break; - - case RSF_CODE: - fpa11->fpreg[Fd].fExtended = floatx80_sub(rFm,rFn); - break; - - case DVF_CODE: - case FDV_CODE: - fpa11->fpreg[Fd].fExtended = floatx80_div(rFn,rFm); - break; - - case RDF_CODE: - case FRD_CODE: - fpa11->fpreg[Fd].fExtended = floatx80_div(rFm,rFn); - break; - -#if 0 - case POW_CODE: - fpa11->fpreg[Fd].fExtended = floatx80_pow(rFn,rFm); - break; - - case RPW_CODE: - fpa11->fpreg[Fd].fExtended = floatx80_pow(rFm,rFn); - break; -#endif - - case RMF_CODE: - fpa11->fpreg[Fd].fExtended = floatx80_rem(rFn,rFm); - break; - -#if 0 - case POL_CODE: - fpa11->fpreg[Fd].fExtended = floatx80_pol(rFn,rFm); - break; -#endif - - /* monadic opcodes */ - case MVF_CODE: - fpa11->fpreg[Fd].fExtended = rFm; - break; - - case MNF_CODE: - rFm.high ^= 0x8000; - fpa11->fpreg[Fd].fExtended = rFm; - break; - - case ABS_CODE: - rFm.high &= 0x7fff; - fpa11->fpreg[Fd].fExtended = rFm; - break; - - case RND_CODE: - case URD_CODE: - fpa11->fpreg[Fd].fExtended = floatx80_round_to_int(rFm); - break; - - case SQT_CODE: - fpa11->fpreg[Fd].fExtended = floatx80_sqrt(rFm); - break; - -#if 0 - case LOG_CODE: - fpa11->fpreg[Fd].fExtended = floatx80_log(rFm); - break; - - case LGN_CODE: - fpa11->fpreg[Fd].fExtended = floatx80_ln(rFm); - break; - - case EXP_CODE: - fpa11->fpreg[Fd].fExtended = floatx80_exp(rFm); - break; - - case SIN_CODE: - fpa11->fpreg[Fd].fExtended = floatx80_sin(rFm); - break; - - case COS_CODE: - fpa11->fpreg[Fd].fExtended = floatx80_cos(rFm); - break; - - case TAN_CODE: - fpa11->fpreg[Fd].fExtended = floatx80_tan(rFm); - break; - - case ASN_CODE: - fpa11->fpreg[Fd].fExtended = floatx80_arcsin(rFm); - break; - - case ACS_CODE: - fpa11->fpreg[Fd].fExtended = floatx80_arccos(rFm); - break; - - case ATN_CODE: - fpa11->fpreg[Fd].fExtended = floatx80_arctan(rFm); - break; -#endif - - case NRM_CODE: - break; - - default: - { - nRc = 0; - } - } - - if (0 != nRc) fpa11->fType[Fd] = typeExtended; - return nRc; + return floatx80_sub(rFm, rFn); } -#if 0 -floatx80 floatx80_exp(floatx80 Fm) +static floatx80 floatx80_rdv(floatx80 rFn, floatx80 rFm) { -//series + return floatx80_div(rFm, rFn); } -floatx80 floatx80_ln(floatx80 Fm) -{ -//series -} +static floatx80 (*const dyadic_extended[16])(floatx80 rFn, floatx80 rFm) = { + [ADF_CODE >> 20] = floatx80_add, + [MUF_CODE >> 20] = floatx80_mul, + [SUF_CODE >> 20] = floatx80_sub, + [RSF_CODE >> 20] = floatx80_rsf, + [DVF_CODE >> 20] = floatx80_div, + [RDF_CODE >> 20] = floatx80_rdv, + [RMF_CODE >> 20] = floatx80_rem, -floatx80 floatx80_sin(floatx80 rFm) -{ -//series -} + /* strictly, these opcodes should not be implemented */ + [FML_CODE >> 20] = floatx80_mul, + [FDV_CODE >> 20] = floatx80_div, + [FRD_CODE >> 20] = floatx80_rdv, +}; -floatx80 floatx80_cos(floatx80 rFm) +static floatx80 floatx80_mvf(floatx80 rFm) { -//series + return rFm; } -floatx80 floatx80_arcsin(floatx80 rFm) +static floatx80 floatx80_mnf(floatx80 rFm) { -//series + rFm.high ^= 0x8000; + return rFm; } -floatx80 floatx80_arctan(floatx80 rFm) +static floatx80 floatx80_abs(floatx80 rFm) { - //series + rFm.high &= 0x7fff; + return rFm; } -floatx80 floatx80_log(floatx80 rFm) -{ - return floatx80_div(floatx80_ln(rFm),getExtendedConstant(7)); -} +static floatx80 (*const monadic_extended[16])(floatx80 rFm) = { + [MVF_CODE >> 20] = floatx80_mvf, + [MNF_CODE >> 20] = floatx80_mnf, + [ABS_CODE >> 20] = floatx80_abs, + [RND_CODE >> 20] = floatx80_round_to_int, + [URD_CODE >> 20] = floatx80_round_to_int, + [SQT_CODE >> 20] = floatx80_sqrt, + [NRM_CODE >> 20] = floatx80_mvf, +}; -floatx80 floatx80_tan(floatx80 rFm) +unsigned int ExtendedCPDO(const unsigned int opcode, FPREG * rFd) { - return floatx80_div(floatx80_sin(rFm),floatx80_cos(rFm)); -} + FPA11 *fpa11 = GET_FPA11(); + floatx80 rFm; + unsigned int Fm, opc_mask_shift; -floatx80 floatx80_arccos(floatx80 rFm) -{ - //return floatx80_sub(halfPi,floatx80_arcsin(rFm)); -} + Fm = getFm(opcode); + if (CONSTANT_FM(opcode)) { + rFm = getExtendedConstant(Fm); + } else { + switch (fpa11->fType[Fm]) { + case typeSingle: + rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle); + break; -floatx80 floatx80_pow(floatx80 rFn,floatx80 rFm) -{ - return floatx80_exp(floatx80_mul(rFm,floatx80_ln(rFn))); -} + case typeDouble: + rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble); + break; -floatx80 floatx80_pol(floatx80 rFn,floatx80 rFm) -{ - return floatx80_arctan(floatx80_div(rFn,rFm)); + case typeExtended: + rFm = fpa11->fpreg[Fm].fExtended; + break; + + default: + return 0; + } + } + + opc_mask_shift = (opcode & MASK_ARITHMETIC_OPCODE) >> 20; + if (!MONADIC_INSTRUCTION(opcode)) { + unsigned int Fn = getFn(opcode); + floatx80 rFn; + + switch (fpa11->fType[Fn]) { + case typeSingle: + rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle); + break; + + case typeDouble: + rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble); + break; + + case typeExtended: + rFn = fpa11->fpreg[Fn].fExtended; + break; + + default: + return 0; + } + + if (dyadic_extended[opc_mask_shift]) { + rFd->fExtended = dyadic_extended[opc_mask_shift](rFn, rFm); + } else { + return 0; + } + } else { + if (monadic_extended[opc_mask_shift]) { + rFd->fExtended = monadic_extended[opc_mask_shift](rFm); + } else { + return 0; + } + } + + return 1; } -#endif diff -Nur linux-sharp-c860/arch/arm/nwfpe/fpa11.c linux-sharp-c860+nwfpe/arch/arm/nwfpe/fpa11.c --- linux-sharp-c860/arch/arm/nwfpe/fpa11.c 2002-08-26 14:45:38.000000000 +0900 +++ linux-sharp-c860+nwfpe/arch/arm/nwfpe/fpa11.c 2003-08-25 20:44:39.000000000 +0900 @@ -1,6 +1,7 @@ /* NetWinder Floating Point Emulator (c) Rebel.COM, 1998,1999 + (c) Philip Blundell, 2001 Direct questions, comments to Scott Bambrough @@ -20,7 +21,6 @@ */ #include "fpa11.h" - #include "fpopcode.h" #include "fpmodule.h" @@ -36,180 +36,96 @@ /* Reset the FPA11 chip. Called to initialize and reset the emulator. */ void resetFPA11(void) { - int i; - FPA11 *fpa11 = GET_FPA11(); - - /* initialize the register type array */ - for (i=0;i<=7;i++) - { - fpa11->fType[i] = typeNone; - } - - /* FPSR: set system id to FP_EMULATOR, set AC, clear all other bits */ - fpa11->fpsr = FP_EMULATOR | BIT_AC; - - /* FPCR: set SB, AB and DA bits, clear all others */ -#if MAINTAIN_FPCR - fpa11->fpcr = MASK_RESET; -#endif + int i; + FPA11 *fpa11 = GET_FPA11(); + + /* initialize the register type array */ + for (i = 0; i <= 7; i++) { + fpa11->fType[i] = typeNone; + } + + /* FPSR: set system id to FP_EMULATOR, set AC, clear all other bits */ + fpa11->fpsr = FP_EMULATOR | BIT_AC; } void SetRoundingMode(const unsigned int opcode) { -#if MAINTAIN_FPCR - FPA11 *fpa11 = GET_FPA11(); - fpa11->fpcr &= ~MASK_ROUNDING_MODE; -#endif - switch (opcode & MASK_ROUNDING_MODE) - { - default: - case ROUND_TO_NEAREST: - float_rounding_mode = float_round_nearest_even; -#if MAINTAIN_FPCR - fpa11->fpcr |= ROUND_TO_NEAREST; -#endif - break; - - case ROUND_TO_PLUS_INFINITY: - float_rounding_mode = float_round_up; -#if MAINTAIN_FPCR - fpa11->fpcr |= ROUND_TO_PLUS_INFINITY; -#endif - break; - - case ROUND_TO_MINUS_INFINITY: - float_rounding_mode = float_round_down; -#if MAINTAIN_FPCR - fpa11->fpcr |= ROUND_TO_MINUS_INFINITY; -#endif - break; - - case ROUND_TO_ZERO: - float_rounding_mode = float_round_to_zero; -#if MAINTAIN_FPCR - fpa11->fpcr |= ROUND_TO_ZERO; -#endif - break; - } + switch (opcode & MASK_ROUNDING_MODE) { + default: + case ROUND_TO_NEAREST: + float_rounding_mode = float_round_nearest_even; + break; + + case ROUND_TO_PLUS_INFINITY: + float_rounding_mode = float_round_up; + break; + + case ROUND_TO_MINUS_INFINITY: + float_rounding_mode = float_round_down; + break; + + case ROUND_TO_ZERO: + float_rounding_mode = float_round_to_zero; + break; + } } void SetRoundingPrecision(const unsigned int opcode) { -#if MAINTAIN_FPCR - FPA11 *fpa11 = GET_FPA11(); - fpa11->fpcr &= ~MASK_ROUNDING_PRECISION; -#endif - switch (opcode & MASK_ROUNDING_PRECISION) - { - case ROUND_SINGLE: - floatx80_rounding_precision = 32; -#if MAINTAIN_FPCR - fpa11->fpcr |= ROUND_SINGLE; -#endif - break; - - case ROUND_DOUBLE: - floatx80_rounding_precision = 64; -#if MAINTAIN_FPCR - fpa11->fpcr |= ROUND_DOUBLE; -#endif - break; - - case ROUND_EXTENDED: - floatx80_rounding_precision = 80; -#if MAINTAIN_FPCR - fpa11->fpcr |= ROUND_EXTENDED; -#endif - break; - - default: floatx80_rounding_precision = 80; - } +#ifdef CONFIG_FPE_NWFPE_XP + switch (opcode & MASK_ROUNDING_PRECISION) { + case ROUND_SINGLE: + floatx80_rounding_precision = 32; + break; + + case ROUND_DOUBLE: + floatx80_rounding_precision = 64; + break; + + case ROUND_EXTENDED: + floatx80_rounding_precision = 80; + break; + + default: + floatx80_rounding_precision = 80; + } +#endif } -/* Emulate the instruction in the opcode. */ -unsigned int EmulateAll(unsigned int opcode) +void nwfpe_init_fpa(void) { - unsigned int nRc = 0; - unsigned long flags; - FPA11 *fpa11; - save_flags(flags); sti(); - - fpa11 = GET_FPA11(); - - if (fpa11->initflag == 0) /* good place for __builtin_expect */ - { - resetFPA11(); - SetRoundingMode(ROUND_TO_NEAREST); - SetRoundingPrecision(ROUND_EXTENDED); - fpa11->initflag = 1; - } - - if (TEST_OPCODE(opcode,MASK_CPRT)) - { - /* Emulate conversion opcodes. */ - /* Emulate register transfer opcodes. */ - /* Emulate comparison opcodes. */ - nRc = EmulateCPRT(opcode); - } - else if (TEST_OPCODE(opcode,MASK_CPDO)) - { - /* Emulate monadic arithmetic opcodes. */ - /* Emulate dyadic arithmetic opcodes. */ - nRc = EmulateCPDO(opcode); - } - else if (TEST_OPCODE(opcode,MASK_CPDT)) - { - /* Emulate load/store opcodes. */ - /* Emulate load/store multiple opcodes. */ - nRc = EmulateCPDT(opcode); - } - else - { - /* Invalid instruction detected. Return FALSE. */ - nRc = 0; - } - - restore_flags(flags); - - return(nRc); + FPA11 *fpa11 = GET_FPA11(); +#ifdef NWFPE_DEBUG + printk("NWFPE: setting up state.\n"); +#endif + resetFPA11(); + SetRoundingMode(ROUND_TO_NEAREST); + SetRoundingPrecision(ROUND_EXTENDED); + fpa11->initflag = 1; } -#if 0 -unsigned int EmulateAll1(unsigned int opcode) +/* Emulate the instruction in the opcode. */ +unsigned int EmulateAll(const unsigned int opcode) { - switch ((opcode >> 24) & 0xf) - { - case 0xc: - case 0xd: - if ((opcode >> 20) & 0x1) - { - switch ((opcode >> 8) & 0xf) - { - case 0x1: return PerformLDF(opcode); break; - case 0x2: return PerformLFM(opcode); break; - default: return 0; - } - } - else - { - switch ((opcode >> 8) & 0xf) - { - case 0x1: return PerformSTF(opcode); break; - case 0x2: return PerformSFM(opcode); break; - default: return 0; - } - } - break; - - case 0xe: - if (opcode & 0x10) - return EmulateCPDO(opcode); - else - return EmulateCPRT(opcode); - break; - - default: return 0; - } -} +#ifdef NWFPE_DEBUG + printk("NWFPE: emulating opcode %08x\n", opcode); #endif + if (TEST_OPCODE(opcode, MASK_CPRT)) { + /* Emulate conversion opcodes. */ + /* Emulate register transfer opcodes. */ + /* Emulate comparison opcodes. */ + return EmulateCPRT(opcode); + } else if (TEST_OPCODE(opcode, MASK_CPDO)) { + /* Emulate monadic arithmetic opcodes. */ + /* Emulate dyadic arithmetic opcodes. */ + return EmulateCPDO(opcode); + } else if (TEST_OPCODE(opcode, MASK_CPDT)) { + /* Emulate load/store opcodes. */ + /* Emulate load/store multiple opcodes. */ + return EmulateCPDT(opcode); + } + + /* Invalid instruction detected. Return FALSE. */ + return 0; +} diff -Nur linux-sharp-c860/arch/arm/nwfpe/fpa11.h linux-sharp-c860+nwfpe/arch/arm/nwfpe/fpa11.h --- linux-sharp-c860/arch/arm/nwfpe/fpa11.h 2002-08-26 14:45:38.000000000 +0900 +++ linux-sharp-c860+nwfpe/arch/arm/nwfpe/fpa11.h 2003-08-25 20:44:39.000000000 +0900 @@ -38,6 +38,7 @@ /* includes */ #include "fpsr.h" /* FP control and status register definitions */ +#include "milieu.h" #include "softfloat.h" #define typeNone 0x00 @@ -49,9 +50,13 @@ * This must be no more and no less than 12 bytes. */ typedef union tagFPREG { - floatx80 fExtended; - float64 fDouble; - float32 fSingle; + float32 fSingle; + float64 fDouble; +#ifdef CONFIG_FPE_NWFPE_XP + floatx80 fExtended; +#else + int padding[3]; +#endif } FPREG; /* @@ -68,17 +73,17 @@ * not initialise. */ typedef struct tagFPA11 { -/* 0 */ FPREG fpreg[8]; /* 8 floating point registers */ -/* 96 */ FPSR fpsr; /* floating point status register */ -/* 100 */ FPCR fpcr; /* floating point control register */ -/* 104 */ unsigned char fType[8]; /* type of floating point value held in - floating point registers. One of none - single, double or extended. */ -/* 112 */ int initflag; /* this is special. The kernel guarantees - to set it to 0 when a thread is launched, - so we can use it to detect whether this - instance of the emulator needs to be - initialised. */ +/* 0 */ FPREG fpreg[8]; /* 8 floating point registers */ +/* 96 */ FPSR fpsr; /* floating point status register */ +/* 100 */ FPCR fpcr; /* floating point control register */ +/* 104 */ unsigned char fType[8]; /* type of floating point value held in + floating point registers. One of + none, single, double or extended. */ +/* 112 */ int initflag; /* this is special. The kernel guarantees + to set it to 0 when a thread is launched, + so we can use it to detect whether this + instance of the emulator needs to be + initialised. */ } FPA11; extern void resetFPA11(void); diff -Nur linux-sharp-c860/arch/arm/nwfpe/fpa11.inl linux-sharp-c860+nwfpe/arch/arm/nwfpe/fpa11.inl --- linux-sharp-c860/arch/arm/nwfpe/fpa11.inl 2002-08-26 14:39:50.000000000 +0900 +++ linux-sharp-c860+nwfpe/arch/arm/nwfpe/fpa11.inl 2003-08-25 20:44:39.000000000 +0900 @@ -24,28 +24,28 @@ /* Read and write floating point status register */ extern __inline__ unsigned int readFPSR(void) { - FPA11 *fpa11 = GET_FPA11(); - return(fpa11->fpsr); + FPA11 *fpa11 = GET_FPA11(); + return (fpa11->fpsr); } extern __inline__ void writeFPSR(FPSR reg) { - FPA11 *fpa11 = GET_FPA11(); - /* the sysid byte in the status register is readonly */ - fpa11->fpsr = (fpa11->fpsr & MASK_SYSID) | (reg & ~MASK_SYSID); + FPA11 *fpa11 = GET_FPA11(); + /* the sysid byte in the status register is readonly */ + fpa11->fpsr = (fpa11->fpsr & MASK_SYSID) | (reg & ~MASK_SYSID); } /* Read and write floating point control register */ extern __inline__ FPCR readFPCR(void) { - FPA11 *fpa11 = GET_FPA11(); - /* clear SB, AB and DA bits before returning FPCR */ - return(fpa11->fpcr & ~MASK_RFC); + FPA11 *fpa11 = GET_FPA11(); + /* clear SB, AB and DA bits before returning FPCR */ + return (fpa11->fpcr & ~MASK_RFC); } extern __inline__ void writeFPCR(FPCR reg) { - FPA11 *fpa11 = GET_FPA11(); - fpa11->fpcr &= ~MASK_WFC; /* clear SB, AB and DA bits */ - fpa11->fpcr |= (reg & MASK_WFC); /* write SB, AB and DA bits */ + FPA11 *fpa11 = GET_FPA11(); + fpa11->fpcr &= ~MASK_WFC; /* clear SB, AB and DA bits */ + fpa11->fpcr |= (reg & MASK_WFC); /* write SB, AB and DA bits */ } diff -Nur linux-sharp-c860/arch/arm/nwfpe/fpa11_cpdo.c linux-sharp-c860+nwfpe/arch/arm/nwfpe/fpa11_cpdo.c --- linux-sharp-c860/arch/arm/nwfpe/fpa11_cpdo.c 2002-08-26 14:39:50.000000000 +0900 +++ linux-sharp-c860+nwfpe/arch/arm/nwfpe/fpa11_cpdo.c 2003-08-25 20:44:39.000000000 +0900 @@ -1,6 +1,7 @@ /* NetWinder Floating Point Emulator (c) Rebel.COM, 1998,1999 + (c) Philip Blundell, 2001 Direct questions, comments to Scott Bambrough @@ -22,96 +23,109 @@ #include "fpa11.h" #include "fpopcode.h" -unsigned int SingleCPDO(const unsigned int opcode); -unsigned int DoubleCPDO(const unsigned int opcode); -unsigned int ExtendedCPDO(const unsigned int opcode); +unsigned int SingleCPDO(const unsigned int opcode, FPREG * rFd); +unsigned int DoubleCPDO(const unsigned int opcode, FPREG * rFd); +unsigned int ExtendedCPDO(const unsigned int opcode, FPREG * rFd); unsigned int EmulateCPDO(const unsigned int opcode) { - FPA11 *fpa11 = GET_FPA11(); - unsigned int Fd, nType, nDest, nRc = 1; - - //printk("EmulateCPDO(0x%08x)\n",opcode); - - /* Get the destination size. If not valid let Linux perform - an invalid instruction trap. */ - nDest = getDestinationSize(opcode); - if (typeNone == nDest) return 0; - - SetRoundingMode(opcode); - - /* Compare the size of the operands in Fn and Fm. - Choose the largest size and perform operations in that size, - in order to make use of all the precision of the operands. - If Fm is a constant, we just grab a constant of a size - matching the size of the operand in Fn. */ - if (MONADIC_INSTRUCTION(opcode)) - nType = nDest; - else - nType = fpa11->fType[getFn(opcode)]; - - if (!CONSTANT_FM(opcode)) - { - register unsigned int Fm = getFm(opcode); - if (nType < fpa11->fType[Fm]) - { - nType = fpa11->fType[Fm]; - } - } - - switch (nType) - { - case typeSingle : nRc = SingleCPDO(opcode); break; - case typeDouble : nRc = DoubleCPDO(opcode); break; - case typeExtended : nRc = ExtendedCPDO(opcode); break; - default : nRc = 0; - } - - /* If the operation succeeded, check to see if the result in the - destination register is the correct size. If not force it - to be. */ - Fd = getFd(opcode); - nType = fpa11->fType[Fd]; - if ((0 != nRc) && (nDest != nType)) - { - switch (nDest) - { - case typeSingle: - { - if (typeDouble == nType) - fpa11->fpreg[Fd].fSingle = - float64_to_float32(fpa11->fpreg[Fd].fDouble); - else - fpa11->fpreg[Fd].fSingle = - floatx80_to_float32(fpa11->fpreg[Fd].fExtended); - } - break; - - case typeDouble: - { - if (typeSingle == nType) - fpa11->fpreg[Fd].fDouble = - float32_to_float64(fpa11->fpreg[Fd].fSingle); - else - fpa11->fpreg[Fd].fDouble = - floatx80_to_float64(fpa11->fpreg[Fd].fExtended); - } - break; - - case typeExtended: - { - if (typeSingle == nType) - fpa11->fpreg[Fd].fExtended = - float32_to_floatx80(fpa11->fpreg[Fd].fSingle); - else - fpa11->fpreg[Fd].fExtended = - float64_to_floatx80(fpa11->fpreg[Fd].fDouble); - } - break; - } - - fpa11->fType[Fd] = nDest; - } - - return nRc; + FPA11 *fpa11 = GET_FPA11(); + FPREG *rFd; + unsigned int nType, nDest, nRc; + + /* Get the destination size. If not valid let Linux perform + an invalid instruction trap. */ + nDest = getDestinationSize(opcode); + if (typeNone == nDest) + return 0; + + SetRoundingMode(opcode); + + /* Compare the size of the operands in Fn and Fm. + Choose the largest size and perform operations in that size, + in order to make use of all the precision of the operands. + If Fm is a constant, we just grab a constant of a size + matching the size of the operand in Fn. */ + if (MONADIC_INSTRUCTION(opcode)) + nType = nDest; + else + nType = fpa11->fType[getFn(opcode)]; + + if (!CONSTANT_FM(opcode)) { + register unsigned int Fm = getFm(opcode); + if (nType < fpa11->fType[Fm]) { + nType = fpa11->fType[Fm]; + } + } + + rFd = &fpa11->fpreg[getFd(opcode)]; + + switch (nType) { + case typeSingle: + nRc = SingleCPDO(opcode, rFd); + break; + case typeDouble: + nRc = DoubleCPDO(opcode, rFd); + break; +#ifdef CONFIG_FPE_NWFPE_XP + case typeExtended: + nRc = ExtendedCPDO(opcode, rFd); + break; +#endif + default: + nRc = 0; + } + + /* The CPDO functions used to always set the destination type + to be the same as their working size. */ + + if (nRc != 0) { + /* If the operation succeeded, check to see if the result in the + destination register is the correct size. If not force it + to be. */ + + fpa11->fType[getFd(opcode)] = nDest; + +#ifdef CONFIG_FPE_NWFPE_XP + if (nDest != nType) { + switch (nDest) { + case typeSingle: + { + if (typeDouble == nType) + rFd->fSingle = float64_to_float32(rFd->fDouble); + else + rFd->fSingle = floatx80_to_float32(rFd->fExtended); + } + break; + + case typeDouble: + { + if (typeSingle == nType) + rFd->fDouble = float32_to_float64(rFd->fSingle); + else + rFd->fDouble = floatx80_to_float64(rFd->fExtended); + } + break; + + case typeExtended: + { + if (typeSingle == nType) + rFd->fExtended = float32_to_floatx80(rFd->fSingle); + else + rFd->fExtended = float64_to_floatx80(rFd->fDouble); + } + break; + } + } +#else + if (nDest != nType) { + if (nDest == typeSingle) + rFd->fSingle = float64_to_float32(rFd->fDouble); + else + rFd->fDouble = float32_to_float64(rFd->fSingle); + } +#endif + } + + return nRc; } diff -Nur linux-sharp-c860/arch/arm/nwfpe/fpa11_cpdt.c linux-sharp-c860+nwfpe/arch/arm/nwfpe/fpa11_cpdt.c --- linux-sharp-c860/arch/arm/nwfpe/fpa11_cpdt.c 2002-08-26 14:45:38.000000000 +0900 +++ linux-sharp-c860+nwfpe/arch/arm/nwfpe/fpa11_cpdt.c 2003-08-25 20:44:39.000000000 +0900 @@ -1,7 +1,7 @@ /* NetWinder Floating Point Emulator (c) Rebel.com, 1998-1999 - (c) Philip Blundell, 1998 + (c) Philip Blundell, 1998, 2001 Direct questions, comments to Scott Bambrough @@ -28,331 +28,347 @@ #include -static inline -void loadSingle(const unsigned int Fn,const unsigned int *pMem) +static inline void loadSingle(const unsigned int Fn, const unsigned int *pMem) { - FPA11 *fpa11 = GET_FPA11(); - fpa11->fType[Fn] = typeSingle; - get_user(fpa11->fpreg[Fn].fSingle, pMem); -} - -static inline -void loadDouble(const unsigned int Fn,const unsigned int *pMem) -{ - FPA11 *fpa11 = GET_FPA11(); - unsigned int *p; - p = (unsigned int*)&fpa11->fpreg[Fn].fDouble; - fpa11->fType[Fn] = typeDouble; - get_user(p[0], &pMem[1]); - get_user(p[1], &pMem[0]); /* sign & exponent */ -} - -static inline -void loadExtended(const unsigned int Fn,const unsigned int *pMem) -{ - FPA11 *fpa11 = GET_FPA11(); - unsigned int *p; - p = (unsigned int*)&fpa11->fpreg[Fn].fExtended; - fpa11->fType[Fn] = typeExtended; - get_user(p[0], &pMem[0]); /* sign & exponent */ - get_user(p[1], &pMem[2]); /* ls bits */ - get_user(p[2], &pMem[1]); /* ms bits */ -} - -static inline -void loadMultiple(const unsigned int Fn,const unsigned int *pMem) -{ - FPA11 *fpa11 = GET_FPA11(); - register unsigned int *p; - unsigned long x; - - p = (unsigned int*)&(fpa11->fpreg[Fn]); - get_user(x, &pMem[0]); - fpa11->fType[Fn] = (x >> 14) & 0x00000003; - - switch (fpa11->fType[Fn]) - { - case typeSingle: - case typeDouble: - { - get_user(p[0], &pMem[2]); /* Single */ - get_user(p[1], &pMem[1]); /* double msw */ - p[2] = 0; /* empty */ - } - break; - - case typeExtended: - { - get_user(p[1], &pMem[2]); - get_user(p[2], &pMem[1]); /* msw */ - p[0] = (x & 0x80003fff); - } - break; - } -} - -static inline -void storeSingle(const unsigned int Fn,unsigned int *pMem) -{ - FPA11 *fpa11 = GET_FPA11(); - float32 val; - register unsigned int *p = (unsigned int*)&val; - - switch (fpa11->fType[Fn]) - { - case typeDouble: - val = float64_to_float32(fpa11->fpreg[Fn].fDouble); - break; - - case typeExtended: - val = floatx80_to_float32(fpa11->fpreg[Fn].fExtended); - break; - - default: val = fpa11->fpreg[Fn].fSingle; - } - - put_user(p[0], pMem); -} - -static inline -void storeDouble(const unsigned int Fn,unsigned int *pMem) -{ - FPA11 *fpa11 = GET_FPA11(); - float64 val; - register unsigned int *p = (unsigned int*)&val; - - switch (fpa11->fType[Fn]) - { - case typeSingle: - val = float32_to_float64(fpa11->fpreg[Fn].fSingle); - break; - - case typeExtended: - val = floatx80_to_float64(fpa11->fpreg[Fn].fExtended); - break; - - default: val = fpa11->fpreg[Fn].fDouble; - } - put_user(p[1], &pMem[0]); /* msw */ - put_user(p[0], &pMem[1]); /* lsw */ -} - -static inline -void storeExtended(const unsigned int Fn,unsigned int *pMem) -{ - FPA11 *fpa11 = GET_FPA11(); - floatx80 val; - register unsigned int *p = (unsigned int*)&val; - - switch (fpa11->fType[Fn]) - { - case typeSingle: - val = float32_to_floatx80(fpa11->fpreg[Fn].fSingle); - break; - - case typeDouble: - val = float64_to_floatx80(fpa11->fpreg[Fn].fDouble); - break; - - default: val = fpa11->fpreg[Fn].fExtended; - } - - put_user(p[0], &pMem[0]); /* sign & exp */ - put_user(p[1], &pMem[2]); - put_user(p[2], &pMem[1]); /* msw */ -} - -static inline -void storeMultiple(const unsigned int Fn,unsigned int *pMem) -{ - FPA11 *fpa11 = GET_FPA11(); - register unsigned int nType, *p; - - p = (unsigned int*)&(fpa11->fpreg[Fn]); - nType = fpa11->fType[Fn]; - - switch (nType) - { - case typeSingle: - case typeDouble: - { - put_user(p[0], &pMem[2]); /* single */ - put_user(p[1], &pMem[1]); /* double msw */ - put_user(nType << 14, &pMem[0]); - } - break; - - case typeExtended: - { - put_user(p[2], &pMem[1]); /* msw */ - put_user(p[1], &pMem[2]); - put_user((p[0] & 0x80003fff) | (nType << 14), &pMem[0]); - } - break; - } + FPA11 *fpa11 = GET_FPA11(); + fpa11->fType[Fn] = typeSingle; + get_user(fpa11->fpreg[Fn].fSingle, pMem); } -unsigned int PerformLDF(const unsigned int opcode) +static inline void loadDouble(const unsigned int Fn, const unsigned int *pMem) +{ + FPA11 *fpa11 = GET_FPA11(); + unsigned int *p; + p = (unsigned int *) &fpa11->fpreg[Fn].fDouble; + fpa11->fType[Fn] = typeDouble; + get_user(p[0], &pMem[1]); + get_user(p[1], &pMem[0]); /* sign & exponent */ +} + +#ifdef CONFIG_FPE_NWFPE_XP +static inline void loadExtended(const unsigned int Fn, const unsigned int *pMem) +{ + FPA11 *fpa11 = GET_FPA11(); + unsigned int *p; + p = (unsigned int *) &fpa11->fpreg[Fn].fExtended; + fpa11->fType[Fn] = typeExtended; + get_user(p[0], &pMem[0]); /* sign & exponent */ + get_user(p[1], &pMem[2]); /* ls bits */ + get_user(p[2], &pMem[1]); /* ms bits */ +} +#endif + +static inline void loadMultiple(const unsigned int Fn, const unsigned int *pMem) +{ + FPA11 *fpa11 = GET_FPA11(); + register unsigned int *p; + unsigned long x; + + p = (unsigned int *) &(fpa11->fpreg[Fn]); + get_user(x, &pMem[0]); + fpa11->fType[Fn] = (x >> 14) & 0x00000003; + + switch (fpa11->fType[Fn]) { + case typeSingle: + case typeDouble: + { + get_user(p[0], &pMem[2]); /* Single */ + get_user(p[1], &pMem[1]); /* double msw */ + p[2] = 0; /* empty */ + } + break; + +#ifdef CONFIG_FPE_NWFPE_XP + case typeExtended: + { + get_user(p[1], &pMem[2]); + get_user(p[2], &pMem[1]); /* msw */ + p[0] = (x & 0x80003fff); + } + break; +#endif + } +} + +static inline void storeSingle(const unsigned int Fn, unsigned int *pMem) +{ + FPA11 *fpa11 = GET_FPA11(); + float32 val; + register unsigned int *p = (unsigned int *) &val; + + switch (fpa11->fType[Fn]) { + case typeDouble: + val = float64_to_float32(fpa11->fpreg[Fn].fDouble); + break; + +#ifdef CONFIG_FPE_NWFPE_XP + case typeExtended: + val = floatx80_to_float32(fpa11->fpreg[Fn].fExtended); + break; +#endif + + default: + val = fpa11->fpreg[Fn].fSingle; + } + + put_user(p[0], pMem); +} + +static inline void storeDouble(const unsigned int Fn, unsigned int *pMem) +{ + FPA11 *fpa11 = GET_FPA11(); + float64 val; + register unsigned int *p = (unsigned int *) &val; + + switch (fpa11->fType[Fn]) { + case typeSingle: + val = float32_to_float64(fpa11->fpreg[Fn].fSingle); + break; + +#ifdef CONFIG_FPE_NWFPE_XP + case typeExtended: + val = floatx80_to_float64(fpa11->fpreg[Fn].fExtended); + break; +#endif + + default: + val = fpa11->fpreg[Fn].fDouble; + } + put_user(p[1], &pMem[0]); /* msw */ + put_user(p[0], &pMem[1]); /* lsw */ +} + +#ifdef CONFIG_FPE_NWFPE_XP +static inline void storeExtended(const unsigned int Fn, unsigned int *pMem) +{ + FPA11 *fpa11 = GET_FPA11(); + floatx80 val; + register unsigned int *p = (unsigned int *) &val; + + switch (fpa11->fType[Fn]) { + case typeSingle: + val = float32_to_floatx80(fpa11->fpreg[Fn].fSingle); + break; + + case typeDouble: + val = float64_to_floatx80(fpa11->fpreg[Fn].fDouble); + break; + + default: + val = fpa11->fpreg[Fn].fExtended; + } + + put_user(p[0], &pMem[0]); /* sign & exp */ + put_user(p[1], &pMem[2]); + put_user(p[2], &pMem[1]); /* msw */ +} +#endif + +static inline void storeMultiple(const unsigned int Fn, unsigned int *pMem) { - unsigned int *pBase, *pAddress, *pFinal, nRc = 1, - write_back = WRITE_BACK(opcode); + FPA11 *fpa11 = GET_FPA11(); + register unsigned int nType, *p; + + p = (unsigned int *) &(fpa11->fpreg[Fn]); + nType = fpa11->fType[Fn]; + + switch (nType) { + case typeSingle: + case typeDouble: + { + put_user(p[0], &pMem[2]); /* single */ + put_user(p[1], &pMem[1]); /* double msw */ + put_user(nType << 14, &pMem[0]); + } + break; + +#ifdef CONFIG_FPE_NWFPE_XP + case typeExtended: + { + put_user(p[2], &pMem[1]); /* msw */ + put_user(p[1], &pMem[2]); + put_user((p[0] & 0x80003fff) | (nType << 14), &pMem[0]); + } + break; +#endif + } +} - //printk("PerformLDF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode)); +unsigned int PerformLDF(const unsigned int opcode) +{ + unsigned int *pBase, *pAddress, *pFinal, nRc = 1, + write_back = WRITE_BACK(opcode); - pBase = (unsigned int*)readRegister(getRn(opcode)); - if (REG_PC == getRn(opcode)) - { - pBase += 2; - write_back = 0; - } - - pFinal = pBase; - if (BIT_UP_SET(opcode)) - pFinal += getOffset(opcode); - else - pFinal -= getOffset(opcode); - - if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase; - - switch (opcode & MASK_TRANSFER_LENGTH) - { - case TRANSFER_SINGLE : loadSingle(getFd(opcode),pAddress); break; - case TRANSFER_DOUBLE : loadDouble(getFd(opcode),pAddress); break; - case TRANSFER_EXTENDED: loadExtended(getFd(opcode),pAddress); break; - default: nRc = 0; - } - - if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal); - return nRc; + pBase = (unsigned int *) readRegister(getRn(opcode)); + if (REG_PC == getRn(opcode)) { + pBase += 2; + write_back = 0; + } + + pFinal = pBase; + if (BIT_UP_SET(opcode)) + pFinal += getOffset(opcode); + else + pFinal -= getOffset(opcode); + + if (PREINDEXED(opcode)) + pAddress = pFinal; + else + pAddress = pBase; + + switch (opcode & MASK_TRANSFER_LENGTH) { + case TRANSFER_SINGLE: + loadSingle(getFd(opcode), pAddress); + break; + case TRANSFER_DOUBLE: + loadDouble(getFd(opcode), pAddress); + break; +#ifdef CONFIG_FPE_NWFPE_XP + case TRANSFER_EXTENDED: + loadExtended(getFd(opcode), pAddress); + break; +#endif + default: + nRc = 0; + } + + if (write_back) + writeRegister(getRn(opcode), (unsigned int) pFinal); + return nRc; } unsigned int PerformSTF(const unsigned int opcode) { - unsigned int *pBase, *pAddress, *pFinal, nRc = 1, - write_back = WRITE_BACK(opcode); - - //printk("PerformSTF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode)); - SetRoundingMode(ROUND_TO_NEAREST); - - pBase = (unsigned int*)readRegister(getRn(opcode)); - if (REG_PC == getRn(opcode)) - { - pBase += 2; - write_back = 0; - } - - pFinal = pBase; - if (BIT_UP_SET(opcode)) - pFinal += getOffset(opcode); - else - pFinal -= getOffset(opcode); - - if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase; - - switch (opcode & MASK_TRANSFER_LENGTH) - { - case TRANSFER_SINGLE : storeSingle(getFd(opcode),pAddress); break; - case TRANSFER_DOUBLE : storeDouble(getFd(opcode),pAddress); break; - case TRANSFER_EXTENDED: storeExtended(getFd(opcode),pAddress); break; - default: nRc = 0; - } - - if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal); - return nRc; + unsigned int *pBase, *pAddress, *pFinal, nRc = 1, + write_back = WRITE_BACK(opcode); + + SetRoundingMode(ROUND_TO_NEAREST); + + pBase = (unsigned int *) readRegister(getRn(opcode)); + if (REG_PC == getRn(opcode)) { + pBase += 2; + write_back = 0; + } + + pFinal = pBase; + if (BIT_UP_SET(opcode)) + pFinal += getOffset(opcode); + else + pFinal -= getOffset(opcode); + + if (PREINDEXED(opcode)) + pAddress = pFinal; + else + pAddress = pBase; + + switch (opcode & MASK_TRANSFER_LENGTH) { + case TRANSFER_SINGLE: + storeSingle(getFd(opcode), pAddress); + break; + case TRANSFER_DOUBLE: + storeDouble(getFd(opcode), pAddress); + break; +#ifdef CONFIG_FPE_NWFPE_XP + case TRANSFER_EXTENDED: + storeExtended(getFd(opcode), pAddress); + break; +#endif + default: + nRc = 0; + } + + if (write_back) + writeRegister(getRn(opcode), (unsigned int) pFinal); + return nRc; } unsigned int PerformLFM(const unsigned int opcode) { - unsigned int i, Fd, *pBase, *pAddress, *pFinal, - write_back = WRITE_BACK(opcode); - - pBase = (unsigned int*)readRegister(getRn(opcode)); - if (REG_PC == getRn(opcode)) - { - pBase += 2; - write_back = 0; - } - - pFinal = pBase; - if (BIT_UP_SET(opcode)) - pFinal += getOffset(opcode); - else - pFinal -= getOffset(opcode); - - if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase; - - Fd = getFd(opcode); - for (i=getRegisterCount(opcode);i>0;i--) - { - loadMultiple(Fd,pAddress); - pAddress += 3; Fd++; - if (Fd == 8) Fd = 0; - } + unsigned int i, Fd, *pBase, *pAddress, *pFinal, + write_back = WRITE_BACK(opcode); - if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal); - return 1; + pBase = (unsigned int *) readRegister(getRn(opcode)); + if (REG_PC == getRn(opcode)) { + pBase += 2; + write_back = 0; + } + + pFinal = pBase; + if (BIT_UP_SET(opcode)) + pFinal += getOffset(opcode); + else + pFinal -= getOffset(opcode); + + if (PREINDEXED(opcode)) + pAddress = pFinal; + else + pAddress = pBase; + + Fd = getFd(opcode); + for (i = getRegisterCount(opcode); i > 0; i--) { + loadMultiple(Fd, pAddress); + pAddress += 3; + Fd++; + if (Fd == 8) + Fd = 0; + } + + if (write_back) + writeRegister(getRn(opcode), (unsigned int) pFinal); + return 1; } unsigned int PerformSFM(const unsigned int opcode) { - unsigned int i, Fd, *pBase, *pAddress, *pFinal, - write_back = WRITE_BACK(opcode); - - pBase = (unsigned int*)readRegister(getRn(opcode)); - if (REG_PC == getRn(opcode)) - { - pBase += 2; - write_back = 0; - } - - pFinal = pBase; - if (BIT_UP_SET(opcode)) - pFinal += getOffset(opcode); - else - pFinal -= getOffset(opcode); - - if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase; - - Fd = getFd(opcode); - for (i=getRegisterCount(opcode);i>0;i--) - { - storeMultiple(Fd,pAddress); - pAddress += 3; Fd++; - if (Fd == 8) Fd = 0; - } + unsigned int i, Fd, *pBase, *pAddress, *pFinal, + write_back = WRITE_BACK(opcode); - if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal); - return 1; + pBase = (unsigned int *) readRegister(getRn(opcode)); + if (REG_PC == getRn(opcode)) { + pBase += 2; + write_back = 0; + } + + pFinal = pBase; + if (BIT_UP_SET(opcode)) + pFinal += getOffset(opcode); + else + pFinal -= getOffset(opcode); + + if (PREINDEXED(opcode)) + pAddress = pFinal; + else + pAddress = pBase; + + Fd = getFd(opcode); + for (i = getRegisterCount(opcode); i > 0; i--) { + storeMultiple(Fd, pAddress); + pAddress += 3; + Fd++; + if (Fd == 8) + Fd = 0; + } + + if (write_back) + writeRegister(getRn(opcode), (unsigned int) pFinal); + return 1; } -#if 1 unsigned int EmulateCPDT(const unsigned int opcode) { - unsigned int nRc = 0; + unsigned int nRc = 0; - //printk("EmulateCPDT(0x%08x)\n",opcode); - - if (LDF_OP(opcode)) - { - nRc = PerformLDF(opcode); - } - else if (LFM_OP(opcode)) - { - nRc = PerformLFM(opcode); - } - else if (STF_OP(opcode)) - { - nRc = PerformSTF(opcode); - } - else if (SFM_OP(opcode)) - { - nRc = PerformSFM(opcode); - } - else - { - nRc = 0; - } - - return nRc; + if (LDF_OP(opcode)) { + nRc = PerformLDF(opcode); + } else if (LFM_OP(opcode)) { + nRc = PerformLFM(opcode); + } else if (STF_OP(opcode)) { + nRc = PerformSTF(opcode); + } else if (SFM_OP(opcode)) { + nRc = PerformSFM(opcode); + } else { + nRc = 0; + } + + return nRc; } -#endif diff -Nur linux-sharp-c860/arch/arm/nwfpe/fpa11_cprt.c linux-sharp-c860+nwfpe/arch/arm/nwfpe/fpa11_cprt.c --- linux-sharp-c860/arch/arm/nwfpe/fpa11_cprt.c 2002-08-26 14:45:38.000000000 +0900 +++ linux-sharp-c860+nwfpe/arch/arm/nwfpe/fpa11_cprt.c 2003-08-25 20:44:39.000000000 +0900 @@ -1,7 +1,7 @@ /* NetWinder Floating Point Emulator (c) Rebel.COM, 1998,1999 - (c) Philip Blundell, 1999 + (c) Philip Blundell, 1999, 2001 Direct questions, comments to Scott Bambrough @@ -21,269 +21,348 @@ */ #include "fpa11.h" -#include "milieu.h" -#include "softfloat.h" #include "fpopcode.h" #include "fpa11.inl" #include "fpmodule.h" #include "fpmodule.inl" +#ifdef CONFIG_FPE_NWFPE_XP extern flag floatx80_is_nan(floatx80); -extern flag float64_is_nan( float64); -extern flag float32_is_nan( float32); +#endif +extern flag float64_is_nan(float64); +extern flag float32_is_nan(float32); void SetRoundingMode(const unsigned int opcode); unsigned int PerformFLT(const unsigned int opcode); unsigned int PerformFIX(const unsigned int opcode); -static unsigned int -PerformComparison(const unsigned int opcode); +static unsigned int PerformComparison(const unsigned int opcode); unsigned int EmulateCPRT(const unsigned int opcode) { - unsigned int nRc = 1; - - //printk("EmulateCPRT(0x%08x)\n",opcode); - if (opcode & 0x800000) - { - /* This is some variant of a comparison (PerformComparison will - sort out which one). Since most of the other CPRT - instructions are oddball cases of some sort or other it makes - sense to pull this out into a fast path. */ - return PerformComparison(opcode); - } - - /* Hint to GCC that we'd like a jump table rather than a load of CMPs */ - switch ((opcode & 0x700000) >> 20) - { - case FLT_CODE >> 20: nRc = PerformFLT(opcode); break; - case FIX_CODE >> 20: nRc = PerformFIX(opcode); break; - - case WFS_CODE >> 20: writeFPSR(readRegister(getRd(opcode))); break; - case RFS_CODE >> 20: writeRegister(getRd(opcode),readFPSR()); break; - -#if 0 /* We currently have no use for the FPCR, so there's no point - in emulating it. */ - case WFC_CODE >> 20: writeFPCR(readRegister(getRd(opcode))); - case RFC_CODE >> 20: writeRegister(getRd(opcode),readFPCR()); break; -#endif + if (opcode & 0x800000) { + /* This is some variant of a comparison (PerformComparison + will sort out which one). Since most of the other CPRT + instructions are oddball cases of some sort or other it + makes sense to pull this out into a fast path. */ + return PerformComparison(opcode); + } + + /* Hint to GCC that we'd like a jump table rather than a load of CMPs */ + switch ((opcode & 0x700000) >> 20) { + case FLT_CODE >> 20: + return PerformFLT(opcode); + break; + case FIX_CODE >> 20: + return PerformFIX(opcode); + break; + + case WFS_CODE >> 20: + writeFPSR(readRegister(getRd(opcode))); + break; + case RFS_CODE >> 20: + writeRegister(getRd(opcode), readFPSR()); + break; + + default: + return 0; + } - default: nRc = 0; - } - - return nRc; + return 1; } unsigned int PerformFLT(const unsigned int opcode) { - FPA11 *fpa11 = GET_FPA11(); - - unsigned int nRc = 1; - SetRoundingMode(opcode); - - switch (opcode & MASK_ROUNDING_PRECISION) - { - case ROUND_SINGLE: - { - fpa11->fType[getFn(opcode)] = typeSingle; - fpa11->fpreg[getFn(opcode)].fSingle = - int32_to_float32(readRegister(getRd(opcode))); - } - break; - - case ROUND_DOUBLE: - { - fpa11->fType[getFn(opcode)] = typeDouble; - fpa11->fpreg[getFn(opcode)].fDouble = - int32_to_float64(readRegister(getRd(opcode))); - } - break; - - case ROUND_EXTENDED: - { - fpa11->fType[getFn(opcode)] = typeExtended; - fpa11->fpreg[getFn(opcode)].fExtended = - int32_to_floatx80(readRegister(getRd(opcode))); - } - break; - - default: nRc = 0; - } - - return nRc; + FPA11 *fpa11 = GET_FPA11(); + SetRoundingMode(opcode); + SetRoundingPrecision(opcode); + + switch (opcode & MASK_ROUNDING_PRECISION) { + case ROUND_SINGLE: + { + fpa11->fType[getFn(opcode)] = typeSingle; + fpa11->fpreg[getFn(opcode)].fSingle = int32_to_float32(readRegister(getRd(opcode))); + } + break; + + case ROUND_DOUBLE: + { + fpa11->fType[getFn(opcode)] = typeDouble; + fpa11->fpreg[getFn(opcode)].fDouble = int32_to_float64(readRegister(getRd(opcode))); + } + break; + +#ifdef CONFIG_FPE_NWFPE_XP + case ROUND_EXTENDED: + { + fpa11->fType[getFn(opcode)] = typeExtended; + fpa11->fpreg[getFn(opcode)].fExtended = int32_to_floatx80(readRegister(getRd(opcode))); + } + break; +#endif + + default: + return 0; + } + + return 1; } unsigned int PerformFIX(const unsigned int opcode) { - FPA11 *fpa11 = GET_FPA11(); - unsigned int nRc = 1; - unsigned int Fn = getFm(opcode); - - SetRoundingMode(opcode); - - switch (fpa11->fType[Fn]) - { - case typeSingle: - { - writeRegister(getRd(opcode), - float32_to_int32(fpa11->fpreg[Fn].fSingle)); - } - break; - - case typeDouble: - { - writeRegister(getRd(opcode), - float64_to_int32(fpa11->fpreg[Fn].fDouble)); - } - break; - - case typeExtended: - { - writeRegister(getRd(opcode), - floatx80_to_int32(fpa11->fpreg[Fn].fExtended)); - } - break; - - default: nRc = 0; - } - - return nRc; -} + FPA11 *fpa11 = GET_FPA11(); + unsigned int Fn = getFm(opcode); - -static unsigned int __inline__ -PerformComparisonOperation(floatx80 Fn, floatx80 Fm) -{ - unsigned int flags = 0; + SetRoundingMode(opcode); - /* test for less than condition */ - if (floatx80_lt(Fn,Fm)) - { - flags |= CC_NEGATIVE; - } - - /* test for equal condition */ - if (floatx80_eq(Fn,Fm)) - { - flags |= CC_ZERO; - } - - /* test for greater than or equal condition */ - if (floatx80_lt(Fm,Fn)) - { - flags |= CC_CARRY; - } - - writeConditionCodes(flags); - return 1; + switch (fpa11->fType[Fn]) { + case typeSingle: + { + writeRegister(getRd(opcode), float32_to_int32(fpa11->fpreg[Fn].fSingle)); + } + break; + + case typeDouble: + { + writeRegister(getRd(opcode), float64_to_int32(fpa11->fpreg[Fn].fDouble)); + } + break; + +#ifdef CONFIG_FPE_NWFPE_XP + case typeExtended: + { + writeRegister(getRd(opcode), floatx80_to_int32(fpa11->fpreg[Fn].fExtended)); + } + break; +#endif + + default: + return 0; + } + + return 1; } /* This instruction sets the flags N, Z, C, V in the FPSR. */ - static unsigned int PerformComparison(const unsigned int opcode) { - FPA11 *fpa11 = GET_FPA11(); - unsigned int Fn, Fm; - floatx80 rFn, rFm; - int e_flag = opcode & 0x400000; /* 1 if CxFE */ - int n_flag = opcode & 0x200000; /* 1 if CNxx */ - unsigned int flags = 0; - - //printk("PerformComparison(0x%08x)\n",opcode); - - Fn = getFn(opcode); - Fm = getFm(opcode); - - /* Check for unordered condition and convert all operands to 80-bit - format. - ?? Might be some mileage in avoiding this conversion if possible. - Eg, if both operands are 32-bit, detect this and do a 32-bit - comparison (cheaper than an 80-bit one). */ - switch (fpa11->fType[Fn]) - { - case typeSingle: - //printk("single.\n"); - if (float32_is_nan(fpa11->fpreg[Fn].fSingle)) - goto unordered; - rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle); - break; - - case typeDouble: - //printk("double.\n"); - if (float64_is_nan(fpa11->fpreg[Fn].fDouble)) - goto unordered; - rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble); - break; - - case typeExtended: - //printk("extended.\n"); - if (floatx80_is_nan(fpa11->fpreg[Fn].fExtended)) - goto unordered; - rFn = fpa11->fpreg[Fn].fExtended; - break; - - default: return 0; - } - - if (CONSTANT_FM(opcode)) - { - //printk("Fm is a constant: #%d.\n",Fm); - rFm = getExtendedConstant(Fm); - if (floatx80_is_nan(rFm)) - goto unordered; - } - else - { - //printk("Fm = r%d which contains a ",Fm); - switch (fpa11->fType[Fm]) - { - case typeSingle: - //printk("single.\n"); - if (float32_is_nan(fpa11->fpreg[Fm].fSingle)) - goto unordered; - rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle); - break; - - case typeDouble: - //printk("double.\n"); - if (float64_is_nan(fpa11->fpreg[Fm].fDouble)) - goto unordered; - rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble); - break; - - case typeExtended: - //printk("extended.\n"); - if (floatx80_is_nan(fpa11->fpreg[Fm].fExtended)) - goto unordered; - rFm = fpa11->fpreg[Fm].fExtended; - break; - - default: return 0; - } - } - - if (n_flag) - { - rFm.high ^= 0x8000; - } - - return PerformComparisonOperation(rFn,rFm); - - unordered: - /* ?? The FPA data sheet is pretty vague about this, in particular - about whether the non-E comparisons can ever raise exceptions. - This implementation is based on a combination of what it says in - the data sheet, observation of how the Acorn emulator actually - behaves (and how programs expect it to) and guesswork. */ - flags |= CC_OVERFLOW; - flags &= ~(CC_ZERO | CC_NEGATIVE); + FPA11 *fpa11 = GET_FPA11(); + unsigned int Fn = getFn(opcode), Fm = getFm(opcode); + int e_flag = opcode & 0x400000; /* 1 if CxFE */ + int n_flag = opcode & 0x200000; /* 1 if CNxx */ + unsigned int flags = 0; + +#ifdef CONFIG_FPE_NWFPE_XP + floatx80 rFn, rFm; + + /* Check for unordered condition and convert all operands to 80-bit + format. + ?? Might be some mileage in avoiding this conversion if possible. + Eg, if both operands are 32-bit, detect this and do a 32-bit + comparison (cheaper than an 80-bit one). */ + switch (fpa11->fType[Fn]) { + case typeSingle: + //printk("single.\n"); + if (float32_is_nan(fpa11->fpreg[Fn].fSingle)) + goto unordered; + rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle); + break; + + case typeDouble: + //printk("double.\n"); + if (float64_is_nan(fpa11->fpreg[Fn].fDouble)) + goto unordered; + rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble); + break; + + case typeExtended: + //printk("extended.\n"); + if (floatx80_is_nan(fpa11->fpreg[Fn].fExtended)) + goto unordered; + rFn = fpa11->fpreg[Fn].fExtended; + break; + + default: + return 0; + } + + if (CONSTANT_FM(opcode)) { + //printk("Fm is a constant: #%d.\n",Fm); + rFm = getExtendedConstant(Fm); + if (floatx80_is_nan(rFm)) + goto unordered; + } else { + //printk("Fm = r%d which contains a ",Fm); + switch (fpa11->fType[Fm]) { + case typeSingle: + //printk("single.\n"); + if (float32_is_nan(fpa11->fpreg[Fm].fSingle)) + goto unordered; + rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle); + break; + + case typeDouble: + //printk("double.\n"); + if (float64_is_nan(fpa11->fpreg[Fm].fDouble)) + goto unordered; + rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble); + break; + + case typeExtended: + //printk("extended.\n"); + if (floatx80_is_nan(fpa11->fpreg[Fm].fExtended)) + goto unordered; + rFm = fpa11->fpreg[Fm].fExtended; + break; + + default: + return 0; + } + } + + if (n_flag) + rFm.high ^= 0x8000; + + /* test for less than condition */ + if (floatx80_lt(rFn, rFm)) + flags |= CC_NEGATIVE; + + /* test for equal condition */ + if (floatx80_eq(rFn, rFm)) + flags |= CC_ZERO; + + /* test for greater than or equal condition */ + if (floatx80_lt(rFm, rFn)) + flags |= CC_CARRY; + +#else + if (CONSTANT_FM(opcode)) { + /* Fm is a constant. Do the comparison in whatever precision + Fn happens to be stored in. */ + if (fpa11->fType[Fn] == typeSingle) { + float32 rFm = getSingleConstant(Fm); + float32 rFn = fpa11->fpreg[Fn].fSingle; + + if (float32_is_nan(rFn)) + goto unordered; + + if (n_flag) + rFm ^= 0x80000000; + + /* test for less than condition */ + if (float32_lt_nocheck(rFn, rFm)) + flags |= CC_NEGATIVE; + + /* test for equal condition */ + if (float32_eq_nocheck(rFn, rFm)) + flags |= CC_ZERO; + + /* test for greater than or equal condition */ + if (float32_lt_nocheck(rFm, rFn)) + flags |= CC_CARRY; + } else { + float64 rFm = getDoubleConstant(Fm); + float64 rFn = fpa11->fpreg[Fn].fDouble; + + if (float64_is_nan(rFn)) + goto unordered; + + if (n_flag) + rFm ^= 0x8000000000000000ULL; + + /* test for less than condition */ + if (float64_lt_nocheck(rFn, rFm)) + flags |= CC_NEGATIVE; + + /* test for equal condition */ + if (float64_eq_nocheck(rFn, rFm)) + flags |= CC_ZERO; + + /* test for greater than or equal condition */ + if (float64_lt_nocheck(rFm, rFn)) + flags |= CC_CARRY; + } + } else { + /* Both operands are in registers. */ + if (fpa11->fType[Fn] == typeSingle + && fpa11->fType[Fm] == typeSingle) { + float32 rFm = fpa11->fpreg[Fm].fSingle; + float32 rFn = fpa11->fpreg[Fn].fSingle; + + if (float32_is_nan(rFn) + || float32_is_nan(rFm)) + goto unordered; + + if (n_flag) + rFm ^= 0x80000000; + + /* test for less than condition */ + if (float32_lt_nocheck(rFn, rFm)) + flags |= CC_NEGATIVE; + + /* test for equal condition */ + if (float32_eq_nocheck(rFn, rFm)) + flags |= CC_ZERO; + + /* test for greater than or equal condition */ + if (float32_lt_nocheck(rFm, rFn)) + flags |= CC_CARRY; + } else { + /* Promote 32-bit operand to 64 bits. */ + float64 rFm, rFn; + + rFm = (fpa11->fType[Fm] == typeSingle) ? + float32_to_float64(fpa11->fpreg[Fm].fSingle) + : fpa11->fpreg[Fm].fDouble; + + rFn = (fpa11->fType[Fn] == typeSingle) ? + float32_to_float64(fpa11->fpreg[Fn].fSingle) + : fpa11->fpreg[Fn].fDouble; + + if (float64_is_nan(rFn) + || float64_is_nan(rFm)) + goto unordered; + + if (n_flag) + rFm ^= 0x8000000000000000ULL; + + /* test for less than condition */ + if (float64_lt_nocheck(rFn, rFm)) + flags |= CC_NEGATIVE; + + /* test for equal condition */ + if (float64_eq_nocheck(rFn, rFm)) + flags |= CC_ZERO; + + /* test for greater than or equal condition */ + if (float64_lt_nocheck(rFm, rFn)) + flags |= CC_CARRY; + } + } + +#endif + + writeConditionCodes(flags); + + return 1; + + unordered: + /* ?? The FPA data sheet is pretty vague about this, in particular + about whether the non-E comparisons can ever raise exceptions. + This implementation is based on a combination of what it says in + the data sheet, observation of how the Acorn emulator actually + behaves (and how programs expect it to) and guesswork. */ + flags |= CC_OVERFLOW; + flags &= ~(CC_ZERO | CC_NEGATIVE); - if (BIT_AC & readFPSR()) flags |= CC_CARRY; + if (BIT_AC & readFPSR()) + flags |= CC_CARRY; - if (e_flag) float_raise(float_flag_invalid); + if (e_flag) + float_raise(float_flag_invalid); - writeConditionCodes(flags); - return 1; + writeConditionCodes(flags); + return 1; } diff -Nur linux-sharp-c860/arch/arm/nwfpe/fpmodule.c linux-sharp-c860+nwfpe/arch/arm/nwfpe/fpmodule.c --- linux-sharp-c860/arch/arm/nwfpe/fpmodule.c 2002-08-26 14:45:38.000000000 +0900 +++ linux-sharp-c860+nwfpe/arch/arm/nwfpe/fpmodule.c 2003-08-25 20:44:39.000000000 +0900 @@ -41,13 +41,19 @@ #include "fpa11.inl" /* kernel symbols required for signal handling */ -typedef struct task_struct* PTASK; +typedef struct task_struct *PTASK; + +#ifdef CONFIG_FPE_NWFPE_XP +#define NWFPE_BITS "extended" +#else +#define NWFPE_BITS "double" +#endif #ifdef MODULE void fp_send_sig(unsigned long sig, PTASK p, int priv); #if LINUX_VERSION_CODE > 0x20115 MODULE_AUTHOR("Scott Bambrough "); -MODULE_DESCRIPTION("NWFPE floating point emulator"); +MODULE_DESCRIPTION("NWFPE floating point emulator (" NWFPE_BITS " precision)"); #endif #else @@ -63,7 +69,7 @@ /* external declarations for saved kernel symbols */ extern void (*kern_fp_enter)(void); -/* Original value of fp_enter from kernel before patched by fpe_init. */ +/* Original value of fp_enter from kernel before patched by fpe_init. */ static void (*orig_fp_enter)(void); /* forward declarations */ @@ -76,46 +82,45 @@ */ static int fpe_unload(void) { - return (kern_fp_enter == nwfpe_enter) ? 0 : 1; + return (kern_fp_enter == nwfpe_enter) ? 0 : 1; } #endif static int __init fpe_init(void) { - if (sizeof(FPA11) > sizeof(union fp_state)) { - printk(KERN_ERR "nwfpe: bad structure size\n"); - return -EINVAL; - } - - if (sizeof(FPREG) != 12) { - printk(KERN_ERR "nwfpe: bad register size\n"); - return -EINVAL; - } - + if (sizeof(FPA11) > sizeof(union fp_state)) { + printk(KERN_ERR "nwfpe: bad structure size\n"); + return -EINVAL; + } + + if (sizeof(FPREG) != 12) { + printk(KERN_ERR "nwfpe: bad register size\n"); + return -EINVAL; + } #ifdef MODULE - if (!mod_member_present(&__this_module, can_unload)) - return -EINVAL; - __this_module.can_unload = fpe_unload; + if (!mod_member_present(&__this_module, can_unload)) + return -EINVAL; + __this_module.can_unload = fpe_unload; #else - if (fpe_type[0] && strcmp(fpe_type, "nwfpe")) - return 0; + if (fpe_type[0] && strcmp(fpe_type, "nwfpe")) + return 0; #endif - /* Display title, version and copyright information. */ - printk(KERN_WARNING "NetWinder Floating Point Emulator V0.95 " - "(c) 1998-1999 Rebel.com\n"); - - /* Save pointer to the old FP handler and then patch ourselves in */ - orig_fp_enter = kern_fp_enter; - kern_fp_enter = nwfpe_enter; + /* Display title, version and copyright information. */ + printk(KERN_WARNING "NetWinder Floating Point Emulator V0.97 (" + NWFPE_BITS " precision)\n"); + + /* Save pointer to the old FP handler and then patch ourselves in */ + orig_fp_enter = kern_fp_enter; + kern_fp_enter = nwfpe_enter; - return 0; + return 0; } static void __exit fpe_exit(void) { - /* Restore the values we saved earlier. */ - kern_fp_enter = orig_fp_enter; + /* Restore the values we saved earlier. */ + kern_fp_enter = orig_fp_enter; } /* @@ -140,41 +145,42 @@ void float_raise(signed char flags) { - register unsigned int fpsr, cumulativeTraps; - + register unsigned int fpsr, cumulativeTraps; + #ifdef CONFIG_DEBUG_USER - printk(KERN_DEBUG "NWFPE: %s[%d] takes exception %08x at %p from %08x\n", - current->comm, current->pid, flags, - __builtin_return_address(0), GET_USERREG()[15]); -#endif - - /* Keep SoftFloat exception flags up to date. */ - float_exception_flags |= flags; - - /* Read fpsr and initialize the cumulativeTraps. */ - fpsr = readFPSR(); - cumulativeTraps = 0; - - /* For each type of exception, the cumulative trap exception bit is only - set if the corresponding trap enable bit is not set. */ - if ((!(fpsr & BIT_IXE)) && (flags & BIT_IXC)) - cumulativeTraps |= BIT_IXC; - if ((!(fpsr & BIT_UFE)) && (flags & BIT_UFC)) - cumulativeTraps |= BIT_UFC; - if ((!(fpsr & BIT_OFE)) && (flags & BIT_OFC)) - cumulativeTraps |= BIT_OFC; - if ((!(fpsr & BIT_DZE)) && (flags & BIT_DZC)) - cumulativeTraps |= BIT_DZC; - if ((!(fpsr & BIT_IOE)) && (flags & BIT_IOC)) - cumulativeTraps |= BIT_IOC; - - /* Set the cumulative exceptions flags. */ - if (cumulativeTraps) - writeFPSR(fpsr | cumulativeTraps); - - /* Raise an exception if necessary. */ - if (fpsr & (flags << 16)) - fp_send_sig(SIGFPE, current, 1); + printk(KERN_DEBUG + "NWFPE: %s[%d] takes exception %08x at %p from %08x\n", + current->comm, current->pid, flags, + __builtin_return_address(0), GET_USERREG()[15]); +#endif + + /* Keep SoftFloat exception flags up to date. */ + float_exception_flags |= flags; + + /* Read fpsr and initialize the cumulativeTraps. */ + fpsr = readFPSR(); + cumulativeTraps = 0; + + /* For each type of exception, the cumulative trap exception bit is only + set if the corresponding trap enable bit is not set. */ + if ((!(fpsr & BIT_IXE)) && (flags & BIT_IXC)) + cumulativeTraps |= BIT_IXC; + if ((!(fpsr & BIT_UFE)) && (flags & BIT_UFC)) + cumulativeTraps |= BIT_UFC; + if ((!(fpsr & BIT_OFE)) && (flags & BIT_OFC)) + cumulativeTraps |= BIT_OFC; + if ((!(fpsr & BIT_DZE)) && (flags & BIT_DZC)) + cumulativeTraps |= BIT_DZC; + if ((!(fpsr & BIT_IOE)) && (flags & BIT_IOC)) + cumulativeTraps |= BIT_IOC; + + /* Set the cumulative exceptions flags. */ + if (cumulativeTraps) + writeFPSR(fpsr | cumulativeTraps); + + /* Raise an exception if necessary. */ + if (fpsr & (flags << 16)) + fp_send_sig(SIGFPE, current, 1); } module_init(fpe_init); diff -Nur linux-sharp-c860/arch/arm/nwfpe/fpmodule.inl linux-sharp-c860+nwfpe/arch/arm/nwfpe/fpmodule.inl --- linux-sharp-c860/arch/arm/nwfpe/fpmodule.inl 2002-08-26 14:39:50.000000000 +0900 +++ linux-sharp-c860+nwfpe/arch/arm/nwfpe/fpmodule.inl 2003-08-25 20:44:39.000000000 +0900 @@ -22,63 +22,64 @@ extern __inline__ unsigned int readRegister(const unsigned int nReg) { - /* Note: The CPU thinks it has dealt with the current instruction. As - a result the program counter has been advanced to the next - instruction, and points 4 bytes beyond the actual instruction - that caused the invalid instruction trap to occur. We adjust - for this in this routine. LDF/STF instructions with Rn = PC - depend on the PC being correct, as they use PC+8 in their - address calculations. */ - unsigned int *userRegisters = GET_USERREG(); - unsigned int val = userRegisters[nReg]; - if (REG_PC == nReg) val -= 4; - return val; + /* Note: The CPU thinks it has dealt with the current instruction. + As a result the program counter has been advanced to the next + instruction, and points 4 bytes beyond the actual instruction + that caused the invalid instruction trap to occur. We adjust + for this in this routine. LDF/STF instructions with Rn = PC + depend on the PC being correct, as they use PC+8 in their + address calculations. */ + unsigned int *userRegisters = GET_USERREG(); + unsigned int val = userRegisters[nReg]; + if (REG_PC == nReg) + val -= 4; + return val; } extern __inline__ void writeRegister(const unsigned int nReg, const unsigned int val) { - unsigned int *userRegisters = GET_USERREG(); - userRegisters[nReg] = val; + unsigned int *userRegisters = GET_USERREG(); + userRegisters[nReg] = val; } extern __inline__ unsigned int readCPSR(void) { - return(readRegister(REG_CPSR)); + return (readRegister(REG_CPSR)); } extern __inline__ void writeCPSR(const unsigned int val) { - writeRegister(REG_CPSR,val); + writeRegister(REG_CPSR, val); } extern __inline__ unsigned int readConditionCodes(void) { #ifdef __FPEM_TEST__ - return(0); + return (0); #else - return(readCPSR() & CC_MASK); + return (readCPSR() & CC_MASK); #endif } extern __inline__ void writeConditionCodes(const unsigned int val) { - unsigned int *userRegisters = GET_USERREG(); - unsigned int rval; - /* - * Operate directly on userRegisters since - * the CPSR may be the PC register itself. - */ - rval = userRegisters[REG_CPSR] & ~CC_MASK; - userRegisters[REG_CPSR] = rval | (val & CC_MASK); + unsigned int *userRegisters = GET_USERREG(); + unsigned int rval; + /* + * Operate directly on userRegisters since + * the CPSR may be the PC register itself. + */ + rval = userRegisters[REG_CPSR] & ~CC_MASK; + userRegisters[REG_CPSR] = rval | (val & CC_MASK); } extern __inline__ unsigned int readMemoryInt(unsigned int *pMem) { - return *pMem; + return *pMem; } diff -Nur linux-sharp-c860/arch/arm/nwfpe/fpopcode.c linux-sharp-c860+nwfpe/arch/arm/nwfpe/fpopcode.c --- linux-sharp-c860/arch/arm/nwfpe/fpopcode.c 2002-08-26 14:45:38.000000000 +0900 +++ linux-sharp-c860+nwfpe/arch/arm/nwfpe/fpopcode.c 2003-08-25 20:44:39.000000000 +0900 @@ -26,123 +26,64 @@ #include "fpmodule.h" #include "fpmodule.inl" +#ifdef CONFIG_FPE_NWFPE_XP const floatx80 floatx80Constant[] = { - { 0x0000, 0x0000000000000000ULL}, /* extended 0.0 */ - { 0x3fff, 0x8000000000000000ULL}, /* extended 1.0 */ - { 0x4000, 0x8000000000000000ULL}, /* extended 2.0 */ - { 0x4000, 0xc000000000000000ULL}, /* extended 3.0 */ - { 0x4001, 0x8000000000000000ULL}, /* extended 4.0 */ - { 0x4001, 0xa000000000000000ULL}, /* extended 5.0 */ - { 0x3ffe, 0x8000000000000000ULL}, /* extended 0.5 */ - { 0x4002, 0xa000000000000000ULL} /* extended 10.0 */ -}; + {0x0000, 0x0000000000000000ULL}, /* extended 0.0 */ + {0x3fff, 0x8000000000000000ULL}, /* extended 1.0 */ + {0x4000, 0x8000000000000000ULL}, /* extended 2.0 */ + {0x4000, 0xc000000000000000ULL}, /* extended 3.0 */ + {0x4001, 0x8000000000000000ULL}, /* extended 4.0 */ + {0x4001, 0xa000000000000000ULL}, /* extended 5.0 */ + {0x3ffe, 0x8000000000000000ULL}, /* extended 0.5 */ + {0x4002, 0xa000000000000000ULL} /* extended 10.0 */ +}; +#endif const float64 float64Constant[] = { - 0x0000000000000000ULL, /* double 0.0 */ - 0x3ff0000000000000ULL, /* double 1.0 */ - 0x4000000000000000ULL, /* double 2.0 */ - 0x4008000000000000ULL, /* double 3.0 */ - 0x4010000000000000ULL, /* double 4.0 */ - 0x4014000000000000ULL, /* double 5.0 */ - 0x3fe0000000000000ULL, /* double 0.5 */ - 0x4024000000000000ULL /* double 10.0 */ -}; + 0x0000000000000000ULL, /* double 0.0 */ + 0x3ff0000000000000ULL, /* double 1.0 */ + 0x4000000000000000ULL, /* double 2.0 */ + 0x4008000000000000ULL, /* double 3.0 */ + 0x4010000000000000ULL, /* double 4.0 */ + 0x4014000000000000ULL, /* double 5.0 */ + 0x3fe0000000000000ULL, /* double 0.5 */ + 0x4024000000000000ULL /* double 10.0 */ +}; const float32 float32Constant[] = { - 0x00000000, /* single 0.0 */ - 0x3f800000, /* single 1.0 */ - 0x40000000, /* single 2.0 */ - 0x40400000, /* single 3.0 */ - 0x40800000, /* single 4.0 */ - 0x40a00000, /* single 5.0 */ - 0x3f000000, /* single 0.5 */ - 0x41200000 /* single 10.0 */ -}; - -unsigned int getTransferLength(const unsigned int opcode) -{ - unsigned int nRc; - - switch (opcode & MASK_TRANSFER_LENGTH) - { - case 0x00000000: nRc = 1; break; /* single precision */ - case 0x00008000: nRc = 2; break; /* double precision */ - case 0x00400000: nRc = 3; break; /* extended precision */ - default: nRc = 0; - } - - return(nRc); -} - -unsigned int getRegisterCount(const unsigned int opcode) -{ - unsigned int nRc; - - switch (opcode & MASK_REGISTER_COUNT) - { - case 0x00000000: nRc = 4; break; - case 0x00008000: nRc = 1; break; - case 0x00400000: nRc = 2; break; - case 0x00408000: nRc = 3; break; - default: nRc = 0; - } - - return(nRc); -} - -unsigned int getRoundingPrecision(const unsigned int opcode) -{ - unsigned int nRc; - - switch (opcode & MASK_ROUNDING_PRECISION) - { - case 0x00000000: nRc = 1; break; - case 0x00000080: nRc = 2; break; - case 0x00080000: nRc = 3; break; - default: nRc = 0; - } - - return(nRc); -} - -unsigned int getDestinationSize(const unsigned int opcode) -{ - unsigned int nRc; - - switch (opcode & MASK_DESTINATION_SIZE) - { - case 0x00000000: nRc = typeSingle; break; - case 0x00000080: nRc = typeDouble; break; - case 0x00080000: nRc = typeExtended; break; - default: nRc = typeNone; - } - - return(nRc); -} + 0x00000000, /* single 0.0 */ + 0x3f800000, /* single 1.0 */ + 0x40000000, /* single 2.0 */ + 0x40400000, /* single 3.0 */ + 0x40800000, /* single 4.0 */ + 0x40a00000, /* single 5.0 */ + 0x3f000000, /* single 0.5 */ + 0x41200000 /* single 10.0 */ +}; /* condition code lookup table index into the table is test code: EQ, NE, ... LT, GT, AL, NV bit position in short is condition code: NZCV */ static const unsigned short aCC[16] = { - 0xF0F0, // EQ == Z set - 0x0F0F, // NE - 0xCCCC, // CS == C set - 0x3333, // CC - 0xFF00, // MI == N set - 0x00FF, // PL - 0xAAAA, // VS == V set - 0x5555, // VC - 0x0C0C, // HI == C set && Z clear - 0xF3F3, // LS == C clear || Z set - 0xAA55, // GE == (N==V) - 0x55AA, // LT == (N!=V) - 0x0A05, // GT == (!Z && (N==V)) - 0xF5FA, // LE == (Z || (N!=V)) - 0xFFFF, // AL always - 0 // NV + 0xF0F0, // EQ == Z set + 0x0F0F, // NE + 0xCCCC, // CS == C set + 0x3333, // CC + 0xFF00, // MI == N set + 0x00FF, // PL + 0xAAAA, // VS == V set + 0x5555, // VC + 0x0C0C, // HI == C set && Z clear + 0xF3F3, // LS == C clear || Z set + 0xAA55, // GE == (N==V) + 0x55AA, // LT == (N!=V) + 0x0A05, // GT == (!Z && (N==V)) + 0xF5FA, // LE == (Z || (N!=V)) + 0xFFFF, // AL always + 0 // NV }; unsigned int checkCondition(const unsigned int opcode, const unsigned int ccodes) { - return (aCC[opcode>>28] >> (ccodes>>28)) & 1; + return (aCC[opcode >> 28] >> (ccodes >> 28)) & 1; } diff -Nur linux-sharp-c860/arch/arm/nwfpe/fpopcode.h linux-sharp-c860+nwfpe/arch/arm/nwfpe/fpopcode.h --- linux-sharp-c860/arch/arm/nwfpe/fpopcode.h 2002-08-26 14:39:50.000000000 +0900 +++ linux-sharp-c860+nwfpe/arch/arm/nwfpe/fpopcode.h 2003-08-25 20:44:39.000000000 +0900 @@ -1,6 +1,7 @@ /* NetWinder Floating Point Emulator (c) Rebel.COM, 1998,1999 + (c) Philip Blundell, 2001 Direct questions, comments to Scott Bambrough @@ -26,7 +27,7 @@ ARM Floating Point Instruction Classes | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |c o n d|1 1 0 P|U|u|W|L| Rn |v| Fd |0|0|0|1| o f f s e t | CPDT -|c o n d|1 1 0 P|U|w|W|L| Rn |x| Fd |0|0|0|1| o f f s e t | CPDT +|c o n d|1 1 0 P|U|w|W|L| Rn |x| Fd |0|0|1|0| o f f s e t | CPDT (copro 2) | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |c o n d|1 1 1 0|a|b|c|d|e| Fn |j| Fd |0|0|0|1|f|g|h|0|i| Fm | CPDO |c o n d|1 1 1 0|a|b|c|L|e| Fn | Rd |0|0|0|1|f|g|h|1|i| Fm | CPRT @@ -34,7 +35,7 @@ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | CPDT data transfer instructions - LDF, STF, LFM, SFM + LDF, STF, LFM (copro 2), SFM (copro 2) CPDO dyadic arithmetic instructions ADF, MUF, SUF, RSF, DVF, RDF, @@ -186,7 +187,7 @@ #define BIT_LOAD 0x00100000 /* masks for load/store */ -#define MASK_CPDT 0x0c000000 /* data processing opcode */ +#define MASK_CPDT 0x0c000000 /* data processing opcode */ #define MASK_OFFSET 0x000000ff #define MASK_TRANSFER_LENGTH 0x00408000 #define MASK_REGISTER_COUNT MASK_TRANSFER_LENGTH @@ -236,7 +237,7 @@ #define MONADIC_INSTRUCTION(opcode) ((opcode & BIT_MONADIC) != 0) /* instruction identification masks */ -#define MASK_CPDO 0x0e000000 /* arithmetic opcode */ +#define MASK_CPDO 0x0e000000 /* arithmetic opcode */ #define MASK_ARITHMETIC_OPCODE 0x00f08000 #define MASK_DESTINATION_SIZE 0x00080080 @@ -282,7 +283,7 @@ === */ -#define MASK_CPRT 0x0e000010 /* register transfer opcode */ +#define MASK_CPRT 0x0e000010 /* register transfer opcode */ #define MASK_CPRT_CODE 0x00f00000 #define FLT_CODE 0x00000000 #define FIX_CODE 0x00100000 @@ -366,25 +367,111 @@ /* Get the rounding mode from the opcode. */ #define getRoundingMode(opcode) ((opcode & MASK_ROUNDING_MODE) >> 5) +#ifdef CONFIG_FPE_NWFPE_XP static inline const floatx80 getExtendedConstant(const unsigned int nIndex) { - extern const floatx80 floatx80Constant[]; - return floatx80Constant[nIndex]; -} + extern const floatx80 floatx80Constant[]; + return floatx80Constant[nIndex]; +} +#endif static inline const float64 getDoubleConstant(const unsigned int nIndex) { - extern const float64 float64Constant[]; - return float64Constant[nIndex]; -} + extern const float64 float64Constant[]; + return float64Constant[nIndex]; +} static inline const float32 getSingleConstant(const unsigned int nIndex) { - extern const float32 float32Constant[]; - return float32Constant[nIndex]; -} + extern const float32 float32Constant[]; + return float32Constant[nIndex]; +} + +static inline unsigned int getTransferLength(const unsigned int opcode) +{ + unsigned int nRc; + + switch (opcode & MASK_TRANSFER_LENGTH) { + case 0x00000000: + nRc = 1; + break; /* single precision */ + case 0x00008000: + nRc = 2; + break; /* double precision */ + case 0x00400000: + nRc = 3; + break; /* extended precision */ + default: + nRc = 0; + } + + return (nRc); +} + +static inline unsigned int getRegisterCount(const unsigned int opcode) +{ + unsigned int nRc; + + switch (opcode & MASK_REGISTER_COUNT) { + case 0x00000000: + nRc = 4; + break; + case 0x00008000: + nRc = 1; + break; + case 0x00400000: + nRc = 2; + break; + case 0x00408000: + nRc = 3; + break; + default: + nRc = 0; + } + + return (nRc); +} + +static inline unsigned int getRoundingPrecision(const unsigned int opcode) +{ + unsigned int nRc; + + switch (opcode & MASK_ROUNDING_PRECISION) { + case 0x00000000: + nRc = 1; + break; + case 0x00000080: + nRc = 2; + break; + case 0x00080000: + nRc = 3; + break; + default: + nRc = 0; + } + + return (nRc); +} + +static inline unsigned int getDestinationSize(const unsigned int opcode) +{ + unsigned int nRc; + + switch (opcode & MASK_DESTINATION_SIZE) { + case 0x00000000: + nRc = typeSingle; + break; + case 0x00000080: + nRc = typeDouble; + break; + case 0x00080000: + nRc = typeExtended; + break; + default: + nRc = typeNone; + } -extern unsigned int getRegisterCount(const unsigned int opcode); -extern unsigned int getDestinationSize(const unsigned int opcode); + return (nRc); +} #endif diff -Nur linux-sharp-c860/arch/arm/nwfpe/fpsr.h linux-sharp-c860+nwfpe/arch/arm/nwfpe/fpsr.h --- linux-sharp-c860/arch/arm/nwfpe/fpsr.h 2002-08-26 14:39:50.000000000 +0900 +++ linux-sharp-c860+nwfpe/arch/arm/nwfpe/fpsr.h 2003-08-25 20:44:39.000000000 +0900 @@ -38,12 +38,12 @@ ------------ Note: the system id byte is read only */ -typedef unsigned int FPSR; /* type for floating point status register */ -typedef unsigned int FPCR; /* type for floating point control register */ +typedef unsigned int FPSR; /* type for floating point status register */ +typedef unsigned int FPCR; /* type for floating point control register */ #define MASK_SYSID 0xff000000 #define BIT_HARDWARE 0x80000000 -#define FP_EMULATOR 0x01000000 /* System ID for emulator */ +#define FP_EMULATOR 0x01000000 /* System ID for emulator */ #define FP_ACCELERATOR 0x81000000 /* System ID for FPA11 */ /* EXCEPTION TRAP ENABLE BYTE @@ -51,11 +51,11 @@ #define MASK_TRAP_ENABLE 0x00ff0000 #define MASK_TRAP_ENABLE_STRICT 0x001f0000 -#define BIT_IXE 0x00100000 /* inexact exception enable */ -#define BIT_UFE 0x00080000 /* underflow exception enable */ -#define BIT_OFE 0x00040000 /* overflow exception enable */ -#define BIT_DZE 0x00020000 /* divide by zero exception enable */ -#define BIT_IOE 0x00010000 /* invalid operation exception enable */ +#define BIT_IXE 0x00100000 /* inexact exception enable */ +#define BIT_UFE 0x00080000 /* underflow exception enable */ +#define BIT_OFE 0x00040000 /* overflow exception enable */ +#define BIT_DZE 0x00020000 /* divide by zero exception enable */ +#define BIT_IOE 0x00010000 /* invalid operation exception enable */ /* SYSTEM CONTROL BYTE ---------------------- */ diff -Nur linux-sharp-c860/arch/arm/nwfpe/single_cpdo.c linux-sharp-c860+nwfpe/arch/arm/nwfpe/single_cpdo.c --- linux-sharp-c860/arch/arm/nwfpe/single_cpdo.c 2002-08-26 14:45:38.000000000 +0900 +++ linux-sharp-c860+nwfpe/arch/arm/nwfpe/single_cpdo.c 2003-08-25 20:44:39.000000000 +0900 @@ -1,6 +1,7 @@ /* NetWinder Floating Point Emulator (c) Rebel.COM, 1998,1999 + (c) Philip Blundell, 2001 Direct questions, comments to Scott Bambrough @@ -32,224 +33,92 @@ float32 float32_log(float32 rFm); float32 float32_tan(float32 rFm); float32 float32_arccos(float32 rFm); -float32 float32_pow(float32 rFn,float32 rFm); -float32 float32_pol(float32 rFn,float32 rFm); +float32 float32_pow(float32 rFn, float32 rFm); +float32 float32_pol(float32 rFn, float32 rFm); -unsigned int SingleCPDO(const unsigned int opcode) +static float32 float32_rsf(float32 rFn, float32 rFm) { - FPA11 *fpa11 = GET_FPA11(); - float32 rFm, rFn; - unsigned int Fd, Fm, Fn, nRc = 1; - - Fm = getFm(opcode); - if (CONSTANT_FM(opcode)) - { - rFm = getSingleConstant(Fm); - } - else - { - switch (fpa11->fType[Fm]) - { - case typeSingle: - rFm = fpa11->fpreg[Fm].fSingle; - break; - - default: return 0; - } - } - - if (!MONADIC_INSTRUCTION(opcode)) - { - Fn = getFn(opcode); - switch (fpa11->fType[Fn]) - { - case typeSingle: - rFn = fpa11->fpreg[Fn].fSingle; - break; - - default: return 0; - } - } - - Fd = getFd(opcode); - switch (opcode & MASK_ARITHMETIC_OPCODE) - { - /* dyadic opcodes */ - case ADF_CODE: - fpa11->fpreg[Fd].fSingle = float32_add(rFn,rFm); - break; - - case MUF_CODE: - case FML_CODE: - fpa11->fpreg[Fd].fSingle = float32_mul(rFn,rFm); - break; - - case SUF_CODE: - fpa11->fpreg[Fd].fSingle = float32_sub(rFn,rFm); - break; - - case RSF_CODE: - fpa11->fpreg[Fd].fSingle = float32_sub(rFm,rFn); - break; - - case DVF_CODE: - case FDV_CODE: - fpa11->fpreg[Fd].fSingle = float32_div(rFn,rFm); - break; - - case RDF_CODE: - case FRD_CODE: - fpa11->fpreg[Fd].fSingle = float32_div(rFm,rFn); - break; - -#if 0 - case POW_CODE: - fpa11->fpreg[Fd].fSingle = float32_pow(rFn,rFm); - break; - - case RPW_CODE: - fpa11->fpreg[Fd].fSingle = float32_pow(rFm,rFn); - break; -#endif - - case RMF_CODE: - fpa11->fpreg[Fd].fSingle = float32_rem(rFn,rFm); - break; - -#if 0 - case POL_CODE: - fpa11->fpreg[Fd].fSingle = float32_pol(rFn,rFm); - break; -#endif - - /* monadic opcodes */ - case MVF_CODE: - fpa11->fpreg[Fd].fSingle = rFm; - break; - - case MNF_CODE: - rFm ^= 0x80000000; - fpa11->fpreg[Fd].fSingle = rFm; - break; - - case ABS_CODE: - rFm &= 0x7fffffff; - fpa11->fpreg[Fd].fSingle = rFm; - break; - - case RND_CODE: - case URD_CODE: - fpa11->fpreg[Fd].fSingle = float32_round_to_int(rFm); - break; - - case SQT_CODE: - fpa11->fpreg[Fd].fSingle = float32_sqrt(rFm); - break; - -#if 0 - case LOG_CODE: - fpa11->fpreg[Fd].fSingle = float32_log(rFm); - break; - - case LGN_CODE: - fpa11->fpreg[Fd].fSingle = float32_ln(rFm); - break; - - case EXP_CODE: - fpa11->fpreg[Fd].fSingle = float32_exp(rFm); - break; - - case SIN_CODE: - fpa11->fpreg[Fd].fSingle = float32_sin(rFm); - break; - - case COS_CODE: - fpa11->fpreg[Fd].fSingle = float32_cos(rFm); - break; - - case TAN_CODE: - fpa11->fpreg[Fd].fSingle = float32_tan(rFm); - break; - - case ASN_CODE: - fpa11->fpreg[Fd].fSingle = float32_arcsin(rFm); - break; - - case ACS_CODE: - fpa11->fpreg[Fd].fSingle = float32_arccos(rFm); - break; - - case ATN_CODE: - fpa11->fpreg[Fd].fSingle = float32_arctan(rFm); - break; -#endif - - case NRM_CODE: - break; - - default: - { - nRc = 0; - } - } - - if (0 != nRc) fpa11->fType[Fd] = typeSingle; - return nRc; + return float32_sub(rFm, rFn); } -#if 0 -float32 float32_exp(float32 Fm) +static float32 float32_rdv(float32 rFn, float32 rFm) { -//series + return float32_div(rFm, rFn); } -float32 float32_ln(float32 Fm) -{ -//series -} +static float32 (*const dyadic_single[16])(float32 rFn, float32 rFm) = { + [ADF_CODE >> 20] = float32_add, + [MUF_CODE >> 20] = float32_mul, + [SUF_CODE >> 20] = float32_sub, + [RSF_CODE >> 20] = float32_rsf, + [DVF_CODE >> 20] = float32_div, + [RDF_CODE >> 20] = float32_rdv, + [RMF_CODE >> 20] = float32_rem, -float32 float32_sin(float32 rFm) -{ -//series -} + [FML_CODE >> 20] = float32_mul, + [FDV_CODE >> 20] = float32_div, + [FRD_CODE >> 20] = float32_rdv, +}; -float32 float32_cos(float32 rFm) +static float32 float32_mvf(float32 rFm) { -//series + return rFm; } -float32 float32_arcsin(float32 rFm) +static float32 float32_mnf(float32 rFm) { -//series + return rFm ^ 0x80000000; } -float32 float32_arctan(float32 rFm) +static float32 float32_abs(float32 rFm) { - //series + return rFm & 0x7fffffff; } -float32 float32_arccos(float32 rFm) -{ - //return float32_sub(halfPi,float32_arcsin(rFm)); -} +static float32 (*const monadic_single[16])(float32 rFm) = { + [MVF_CODE >> 20] = float32_mvf, + [MNF_CODE >> 20] = float32_mnf, + [ABS_CODE >> 20] = float32_abs, + [RND_CODE >> 20] = float32_round_to_int, + [URD_CODE >> 20] = float32_round_to_int, + [SQT_CODE >> 20] = float32_sqrt, + [NRM_CODE >> 20] = float32_mvf, +}; -float32 float32_log(float32 rFm) +unsigned int SingleCPDO(const unsigned int opcode, FPREG * rFd) { - return float32_div(float32_ln(rFm),getSingleConstant(7)); -} + FPA11 *fpa11 = GET_FPA11(); + float32 rFm; + unsigned int Fm, opc_mask_shift; -float32 float32_tan(float32 rFm) -{ - return float32_div(float32_sin(rFm),float32_cos(rFm)); -} + Fm = getFm(opcode); + if (CONSTANT_FM(opcode)) { + rFm = getSingleConstant(Fm); + } else if (fpa11->fType[Fm] == typeSingle) { + rFm = fpa11->fpreg[Fm].fSingle; + } else { + return 0; + } -float32 float32_pow(float32 rFn,float32 rFm) -{ - return float32_exp(float32_mul(rFm,float32_ln(rFn))); -} + opc_mask_shift = (opcode & MASK_ARITHMETIC_OPCODE) >> 20; + if (!MONADIC_INSTRUCTION(opcode)) { + unsigned int Fn = getFn(opcode); + float32 rFn; -float32 float32_pol(float32 rFn,float32 rFm) -{ - return float32_arctan(float32_div(rFn,rFm)); + if (fpa11->fType[Fn] == typeSingle && + dyadic_single[opc_mask_shift]) { + rFn = fpa11->fpreg[Fn].fSingle; + rFd->fSingle = dyadic_single[opc_mask_shift](rFn, rFm); + } else { + return 0; + } + } else { + if (monadic_single[opc_mask_shift]) { + rFd->fSingle = monadic_single[opc_mask_shift](rFm); + } else { + return 0; + } + } + + return 1; } -#endif diff -Nur linux-sharp-c860/arch/arm/nwfpe/softfloat.c linux-sharp-c860+nwfpe/arch/arm/nwfpe/softfloat.c --- linux-sharp-c860/arch/arm/nwfpe/softfloat.c 2002-08-26 14:45:38.000000000 +0900 +++ linux-sharp-c860+nwfpe/arch/arm/nwfpe/softfloat.c 2003-08-25 20:44:39.000000000 +0900 @@ -29,8 +29,8 @@ */ #include "fpa11.h" -#include "milieu.h" -#include "softfloat.h" +//#include "milieu.h" +//#include "softfloat.h" /* ------------------------------------------------------------------------------- @@ -142,12 +142,14 @@ Returns the sign bit of the single-precision floating-point value `a'. ------------------------------------------------------------------------------- */ +#if 0 /* in softfloat.h */ INLINE flag extractFloat32Sign( float32 a ) { return a>>31; } +#endif /* ------------------------------------------------------------------------------- @@ -184,9 +186,9 @@ { #if 0 float32 f; - __asm__("@ packFloat32; - mov %0, %1, asl #31; - orr %0, %2, asl #23; + __asm__("@ packFloat32 \n\ + mov %0, %1, asl #31 \n\ + orr %0, %2, asl #23 \n\ orr %0, %3" : /* no outputs */ : "g" (f), "g" (zSign), "g" (zExp), "g" (zSig) @@ -321,12 +323,14 @@ Returns the sign bit of the double-precision floating-point value `a'. ------------------------------------------------------------------------------- */ +#if 0 /* in softfloat.h */ INLINE flag extractFloat64Sign( float64 a ) { return a>>63; } +#endif /* ------------------------------------------------------------------------------- diff -Nur linux-sharp-c860/arch/arm/nwfpe/softfloat.h linux-sharp-c860+nwfpe/arch/arm/nwfpe/softfloat.h --- linux-sharp-c860/arch/arm/nwfpe/softfloat.h 2002-08-26 14:45:38.000000000 +0900 +++ linux-sharp-c860+nwfpe/arch/arm/nwfpe/softfloat.h 2003-08-25 20:44:39.000000000 +0900 @@ -40,7 +40,9 @@ input or output the `floatx80' type will be defined. ------------------------------------------------------------------------------- */ +#ifdef CONFIG_FPE_NWFPE_XP #define FLOATX80 +#endif /* ------------------------------------------------------------------------------- @@ -229,4 +231,46 @@ #endif +static inline flag extractFloat32Sign(float32 a) +{ + return a >> 31; +} + +static inline flag float32_eq_nocheck(float32 a, float32 b) +{ + return (a == b) || ((bits32) ((a | b) << 1) == 0); +} + +static inline flag float32_lt_nocheck(float32 a, float32 b) +{ + flag aSign, bSign; + + aSign = extractFloat32Sign(a); + bSign = extractFloat32Sign(b); + if (aSign != bSign) + return aSign && ((bits32) ((a | b) << 1) != 0); + return (a != b) && (aSign ^ (a < b)); +} + +static inline flag extractFloat64Sign(float64 a) +{ + return a >> 63; +} + +static inline flag float64_eq_nocheck(float64 a, float64 b) +{ + return (a == b) || ((bits64) ((a | b) << 1) == 0); +} + +static inline flag float64_lt_nocheck(float64 a, float64 b) +{ + flag aSign, bSign; + + aSign = extractFloat64Sign(a); + bSign = extractFloat64Sign(b); + if (aSign != bSign) + return aSign && ((bits64) ((a | b) << 1) != 0); + return (a != b) && (aSign ^ (a < b)); +} + #endif