Commit 58ada350 authored by Russell King's avatar Russell King

Merge flint.arm.linux.org.uk:/usr/src/linux-bk-2.5/linux-2.5-nwfpe

into flint.arm.linux.org.uk:/usr/src/linux-bk-2.5/linux-2.5-rmk
parents 8a0aa9f7 180699eb
...@@ -628,6 +628,18 @@ config FPE_NWFPE ...@@ -628,6 +628,18 @@ config FPE_NWFPE
You may say N here if you are going to load the Acorn FPEmulator You may say N here if you are going to load the Acorn FPEmulator
early in the bootup. early in the bootup.
config FPE_NWFPE_XP
bool "Support extended precision"
depends on FPE_NWFPE
help
Say Y to include 80-bit support in the kernel floating-point
emulator. Otherwise, only 32 and 64-bit support is compiled in.
Note that gcc does not generate 80-bit operations by default,
so in most cases this option only enlarges the size of the
floating point emulator without any good reason.
You almost surely want to say N here.
config FPE_FASTFPE config FPE_FASTFPE
tristate "FastFPE math emulation (EXPERIMENTAL)" tristate "FastFPE math emulation (EXPERIMENTAL)"
depends on !CPU_26 && !CPU_32v3 && EXPERIMENTAL depends on !CPU_26 && !CPU_32v3 && EXPERIMENTAL
......
2003-03-22 Ralph Siemsen <ralphs@netwinder.org>
* 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 <rmk@arm.linux.org.uk> 2002-01-19 Russell King <rmk@arm.linux.org.uk>
* fpa11.h - Add documentation * fpa11.h - Add documentation
......
...@@ -2,18 +2,12 @@ ...@@ -2,18 +2,12 @@
# Copyright (C) 1998, 1999, 2001 Philip Blundell # Copyright (C) 1998, 1999, 2001 Philip Blundell
# #
obj-y :=
obj-m :=
obj-n :=
obj-$(CONFIG_FPE_NWFPE) += nwfpe.o obj-$(CONFIG_FPE_NWFPE) += nwfpe.o
nwfpe-objs := fpa11.o fpa11_cpdo.o fpa11_cpdt.o fpa11_cprt.o \ nwfpe-y += fpa11.o fpa11_cpdo.o fpa11_cpdt.o \
fpmodule.o fpopcode.o softfloat.o \ fpa11_cprt.o fpmodule.o fpopcode.o \
single_cpdo.o double_cpdo.o extended_cpdo.o softfloat.o single_cpdo.o double_cpdo.o
ifeq ($(CONFIG_CPU_26),y) nwfpe-$(CONFIG_FPE_NWFPE_XP) += extended_cpdo.o
nwfpe-objs += entry26.o nwfpe-$(CONFIG_CPU_26) += entry26.o
else nwfpe-$(CONFIG_CPU_32) += entry.o
nwfpe-objs += entry.o
endif
...@@ -23,6 +23,11 @@ ...@@ -23,6 +23,11 @@
#include "softfloat.h" #include "softfloat.h"
#include "fpopcode.h" #include "fpopcode.h"
union float64_components {
float64 f64;
unsigned int i[2];
};
float64 float64_exp(float64 Fm); float64 float64_exp(float64 Fm);
float64 float64_ln(float64 Fm); float64 float64_ln(float64 Fm);
float64 float64_sin(float64 rFm); float64 float64_sin(float64 rFm);
...@@ -32,26 +37,80 @@ float64 float64_arctan(float64 rFm); ...@@ -32,26 +37,80 @@ float64 float64_arctan(float64 rFm);
float64 float64_log(float64 rFm); float64 float64_log(float64 rFm);
float64 float64_tan(float64 rFm); float64 float64_tan(float64 rFm);
float64 float64_arccos(float64 rFm); float64 float64_arccos(float64 rFm);
float64 float64_pow(float64 rFn,float64 rFm); float64 float64_pow(float64 rFn, float64 rFm);
float64 float64_pol(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(); return float64_sub(rFm, rFn);
float64 rFm, rFn; }
unsigned int Fd, Fm, Fn, nRc = 1;
static float64 float64_rdv(float64 rFn, float64 rFm)
{
return float64_div(rFm, rFn);
}
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,
/* strictly, these opcodes should not be implemented */
[FML_CODE >> 20] = float64_mul,
[FDV_CODE >> 20] = float64_div,
[FRD_CODE >> 20] = float64_rdv,
};
static float64 float64_mvf(float64 rFm)
{
return rFm;
}
static float64 float64_mnf(float64 rFm)
{
union float64_components u;
u.f64 = rFm;
u.i[1] ^= 0x80000000;
return u.f64;
}
//printk("DoubleCPDO(0x%08x)\n",opcode); static float64 float64_abs(float64 rFm)
{
union float64_components u;
u.f64 = rFm;
u.i[1] &= 0x7fffffff;
return u.f64;
}
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)
{
FPA11 *fpa11 = GET_FPA11();
float64 rFm;
unsigned int Fm, opc_mask_shift;
Fm = getFm(opcode); Fm = getFm(opcode);
if (CONSTANT_FM(opcode)) if (CONSTANT_FM(opcode)) {
{
rFm = getDoubleConstant(Fm); rFm = getDoubleConstant(Fm);
} } else {
else switch (fpa11->fType[Fm]) {
{
switch (fpa11->fType[Fm])
{
case typeSingle: case typeSingle:
rFm = float32_to_float64(fpa11->fpreg[Fm].fSingle); rFm = float32_to_float64(fpa11->fpreg[Fm].fSingle);
break; break;
...@@ -60,24 +119,17 @@ unsigned int DoubleCPDO(const unsigned int opcode) ...@@ -60,24 +119,17 @@ unsigned int DoubleCPDO(const unsigned int opcode)
rFm = fpa11->fpreg[Fm].fDouble; rFm = fpa11->fpreg[Fm].fDouble;
break; break;
case typeExtended: default:
// !! patb return 0;
//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)) opc_mask_shift = (opcode & MASK_ARITHMETIC_OPCODE) >> 20;
{ if (!MONADIC_INSTRUCTION(opcode)) {
Fn = getFn(opcode); unsigned int Fn = getFn(opcode);
switch (fpa11->fType[Fn]) float64 rFn;
{
switch (fpa11->fType[Fn]) {
case typeSingle: case typeSingle:
rFn = float32_to_float64(fpa11->fpreg[Fn].fSingle); rFn = float32_to_float64(fpa11->fpreg[Fn].fSingle);
break; break;
...@@ -86,203 +138,22 @@ unsigned int DoubleCPDO(const unsigned int opcode) ...@@ -86,203 +138,22 @@ unsigned int DoubleCPDO(const unsigned int opcode)
rFn = fpa11->fpreg[Fn].fDouble; rFn = fpa11->fpreg[Fn].fDouble;
break; break;
default: return 0; 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: if (dyadic_double[opc_mask_shift]) {
{ rFd->fDouble = dyadic_double[opc_mask_shift](rFn, rFm);
unsigned int *p = (unsigned int*)&rFm; } else {
p[1] &= 0x7fffffff; return 0;
fpa11->fpreg[Fd].fDouble = rFm;
} }
break; } else {
if (monadic_double[opc_mask_shift]) {
case RND_CODE: rFd->fDouble = monadic_double[opc_mask_shift](rFm);
case URD_CODE: } else {
fpa11->fpreg[Fd].fDouble = float64_round_to_int(rFm); return 0;
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 1;
return nRc;
}
#if 0
float64 float64_exp(float64 rFm)
{
return rFm;
//series
}
float64 float64_ln(float64 rFm)
{
return rFm;
//series
}
float64 float64_sin(float64 rFm)
{
return rFm;
//series
}
float64 float64_cos(float64 rFm)
{
return rFm;
//series
}
#if 0
float64 float64_arcsin(float64 rFm)
{
//series
}
float64 float64_arctan(float64 rFm)
{
//series
}
#endif
float64 float64_log(float64 rFm)
{
return float64_div(float64_ln(rFm),getDoubleConstant(7));
}
float64 float64_tan(float64 rFm)
{
return float64_div(float64_sin(rFm),float64_cos(rFm));
}
float64 float64_arccos(float64 rFm)
{
return rFm;
//return float64_sub(halfPi,float64_arcsin(rFm));
}
float64 float64_pow(float64 rFn,float64 rFm)
{
return float64_exp(float64_mul(rFm,float64_ln(rFn)));
}
float64 float64_pol(float64 rFn,float64 rFm)
{
return float64_arctan(float64_div(rFn,rFm));
} }
#endif
...@@ -73,7 +73,7 @@ several floating point instructions. */ ...@@ -73,7 +73,7 @@ several floating point instructions. */
.globl nwfpe_enter .globl nwfpe_enter
nwfpe_enter: nwfpe_enter:
mov r4, lr @ save the failure-return addresses mov r4, lr @ save the failure-return addresses
mov sl, sp mov sl, sp @ we access the registers via 'sl'
ldr r5, [sp, #60] @ get contents of PC; ldr r5, [sp, #60] @ get contents of PC;
emulate: emulate:
......
...@@ -66,7 +66,6 @@ several floating point instructions. */ ...@@ -66,7 +66,6 @@ several floating point instructions. */
.globl nwfpe_enter .globl nwfpe_enter
nwfpe_enter: nwfpe_enter:
mov sl, sp mov sl, sp
ldr r5, [sp, #60] @ get contents of PC ldr r5, [sp, #60] @ get contents of PC
bic r5, r5, #0xfc000003 bic r5, r5, #0xfc000003
ldr r0, [r5, #-4] @ get actual instruction into r0 ldr r0, [r5, #-4] @ get actual instruction into r0
......
...@@ -32,26 +32,72 @@ floatx80 floatx80_arctan(floatx80 rFm); ...@@ -32,26 +32,72 @@ floatx80 floatx80_arctan(floatx80 rFm);
floatx80 floatx80_log(floatx80 rFm); floatx80 floatx80_log(floatx80 rFm);
floatx80 floatx80_tan(floatx80 rFm); floatx80 floatx80_tan(floatx80 rFm);
floatx80 floatx80_arccos(floatx80 rFm); floatx80 floatx80_arccos(floatx80 rFm);
floatx80 floatx80_pow(floatx80 rFn,floatx80 rFm); floatx80 floatx80_pow(floatx80 rFn, floatx80 rFm);
floatx80 floatx80_pol(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(); return floatx80_sub(rFm, rFn);
floatx80 rFm, rFn; }
unsigned int Fd, Fm, Fn, nRc = 1;
static floatx80 floatx80_rdv(floatx80 rFn, floatx80 rFm)
{
return floatx80_div(rFm, rFn);
}
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,
/* strictly, these opcodes should not be implemented */
[FML_CODE >> 20] = floatx80_mul,
[FDV_CODE >> 20] = floatx80_div,
[FRD_CODE >> 20] = floatx80_rdv,
};
static floatx80 floatx80_mvf(floatx80 rFm)
{
return rFm;
}
static floatx80 floatx80_mnf(floatx80 rFm)
{
rFm.high ^= 0x8000;
return rFm;
}
static floatx80 floatx80_abs(floatx80 rFm)
{
rFm.high &= 0x7fff;
return rFm;
}
//printk("ExtendedCPDO(0x%08x)\n",opcode); 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,
};
unsigned int ExtendedCPDO(const unsigned int opcode, FPREG * rFd)
{
FPA11 *fpa11 = GET_FPA11();
floatx80 rFm;
unsigned int Fm, opc_mask_shift;
Fm = getFm(opcode); Fm = getFm(opcode);
if (CONSTANT_FM(opcode)) if (CONSTANT_FM(opcode)) {
{
rFm = getExtendedConstant(Fm); rFm = getExtendedConstant(Fm);
} } else {
else switch (fpa11->fType[Fm]) {
{
switch (fpa11->fType[Fm])
{
case typeSingle: case typeSingle:
rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle); rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle);
break; break;
...@@ -64,15 +110,17 @@ unsigned int ExtendedCPDO(const unsigned int opcode) ...@@ -64,15 +110,17 @@ unsigned int ExtendedCPDO(const unsigned int opcode)
rFm = fpa11->fpreg[Fm].fExtended; rFm = fpa11->fpreg[Fm].fExtended;
break; break;
default: return 0; default:
return 0;
} }
} }
if (!MONADIC_INSTRUCTION(opcode)) opc_mask_shift = (opcode & MASK_ARITHMETIC_OPCODE) >> 20;
{ if (!MONADIC_INSTRUCTION(opcode)) {
Fn = getFn(opcode); unsigned int Fn = getFn(opcode);
switch (fpa11->fType[Fn]) floatx80 rFn;
{
switch (fpa11->fType[Fn]) {
case typeSingle: case typeSingle:
rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle); rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle);
break; break;
...@@ -85,189 +133,22 @@ unsigned int ExtendedCPDO(const unsigned int opcode) ...@@ -85,189 +133,22 @@ unsigned int ExtendedCPDO(const unsigned int opcode)
rFn = fpa11->fpreg[Fn].fExtended; rFn = fpa11->fpreg[Fn].fExtended;
break; break;
default: return 0; default:
} return 0;
} }
Fd = getFd(opcode); if (dyadic_extended[opc_mask_shift]) {
switch (opcode & MASK_ARITHMETIC_OPCODE) rFd->fExtended = dyadic_extended[opc_mask_shift](rFn, rFm);
{ } else {
/* dyadic opcodes */ return 0;
case ADF_CODE: }
fpa11->fpreg[Fd].fExtended = floatx80_add(rFn,rFm); } else {
break; if (monadic_extended[opc_mask_shift]) {
rFd->fExtended = monadic_extended[opc_mask_shift](rFm);
case MUF_CODE: } else {
case FML_CODE: return 0;
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 1;
return nRc;
}
#if 0
floatx80 floatx80_exp(floatx80 Fm)
{
//series
}
floatx80 floatx80_ln(floatx80 Fm)
{
//series
}
floatx80 floatx80_sin(floatx80 rFm)
{
//series
}
floatx80 floatx80_cos(floatx80 rFm)
{
//series
}
floatx80 floatx80_arcsin(floatx80 rFm)
{
//series
}
floatx80 floatx80_arctan(floatx80 rFm)
{
//series
}
floatx80 floatx80_log(floatx80 rFm)
{
return floatx80_div(floatx80_ln(rFm),getExtendedConstant(7));
}
floatx80 floatx80_tan(floatx80 rFm)
{
return floatx80_div(floatx80_sin(rFm),floatx80_cos(rFm));
}
floatx80 floatx80_arccos(floatx80 rFm)
{
//return floatx80_sub(halfPi,floatx80_arcsin(rFm));
}
floatx80 floatx80_pow(floatx80 rFn,floatx80 rFm)
{
return floatx80_exp(floatx80_mul(rFm,floatx80_ln(rFn)));
}
floatx80 floatx80_pol(floatx80 rFn,floatx80 rFm)
{
return floatx80_arctan(floatx80_div(rFn,rFm));
} }
#endif
/* /*
NetWinder Floating Point Emulator NetWinder Floating Point Emulator
(c) Rebel.COM, 1998,1999 (c) Rebel.COM, 1998,1999
(c) Philip Blundell, 2001
Direct questions, comments to Scott Bambrough <scottb@netwinder.org> Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
...@@ -41,95 +42,64 @@ static void resetFPA11(void) ...@@ -41,95 +42,64 @@ static void resetFPA11(void)
FPA11 *fpa11 = GET_FPA11(); FPA11 *fpa11 = GET_FPA11();
/* initialize the register type array */ /* initialize the register type array */
for (i=0;i<=7;i++) for (i = 0; i <= 7; i++) {
{
fpa11->fType[i] = typeNone; fpa11->fType[i] = typeNone;
} }
/* FPSR: set system id to FP_EMULATOR, set AC, clear all other bits */ /* FPSR: set system id to FP_EMULATOR, set AC, clear all other bits */
fpa11->fpsr = FP_EMULATOR | BIT_AC; fpa11->fpsr = FP_EMULATOR | BIT_AC;
/* FPCR: set SB, AB and DA bits, clear all others */
#if MAINTAIN_FPCR
fpa11->fpcr = MASK_RESET;
#endif
} }
void SetRoundingMode(const unsigned int opcode) void SetRoundingMode(const unsigned int opcode)
{ {
#if MAINTAIN_FPCR switch (opcode & MASK_ROUNDING_MODE) {
FPA11 *fpa11 = GET_FPA11();
fpa11->fpcr &= ~MASK_ROUNDING_MODE;
#endif
switch (opcode & MASK_ROUNDING_MODE)
{
default: default:
case ROUND_TO_NEAREST: case ROUND_TO_NEAREST:
float_rounding_mode = float_round_nearest_even; float_rounding_mode = float_round_nearest_even;
#if MAINTAIN_FPCR
fpa11->fpcr |= ROUND_TO_NEAREST;
#endif
break; break;
case ROUND_TO_PLUS_INFINITY: case ROUND_TO_PLUS_INFINITY:
float_rounding_mode = float_round_up; float_rounding_mode = float_round_up;
#if MAINTAIN_FPCR
fpa11->fpcr |= ROUND_TO_PLUS_INFINITY;
#endif
break; break;
case ROUND_TO_MINUS_INFINITY: case ROUND_TO_MINUS_INFINITY:
float_rounding_mode = float_round_down; float_rounding_mode = float_round_down;
#if MAINTAIN_FPCR
fpa11->fpcr |= ROUND_TO_MINUS_INFINITY;
#endif
break; break;
case ROUND_TO_ZERO: case ROUND_TO_ZERO:
float_rounding_mode = float_round_to_zero; float_rounding_mode = float_round_to_zero;
#if MAINTAIN_FPCR
fpa11->fpcr |= ROUND_TO_ZERO;
#endif
break; break;
} }
} }
void SetRoundingPrecision(const unsigned int opcode) void SetRoundingPrecision(const unsigned int opcode)
{ {
#if MAINTAIN_FPCR #ifdef CONFIG_FPE_NWFPE_XP
FPA11 *fpa11 = GET_FPA11(); switch (opcode & MASK_ROUNDING_PRECISION) {
fpa11->fpcr &= ~MASK_ROUNDING_PRECISION;
#endif
switch (opcode & MASK_ROUNDING_PRECISION)
{
case ROUND_SINGLE: case ROUND_SINGLE:
floatx80_rounding_precision = 32; floatx80_rounding_precision = 32;
#if MAINTAIN_FPCR
fpa11->fpcr |= ROUND_SINGLE;
#endif
break; break;
case ROUND_DOUBLE: case ROUND_DOUBLE:
floatx80_rounding_precision = 64; floatx80_rounding_precision = 64;
#if MAINTAIN_FPCR
fpa11->fpcr |= ROUND_DOUBLE;
#endif
break; break;
case ROUND_EXTENDED: case ROUND_EXTENDED:
floatx80_rounding_precision = 80; floatx80_rounding_precision = 80;
#if MAINTAIN_FPCR
fpa11->fpcr |= ROUND_EXTENDED;
#endif
break; break;
default: floatx80_rounding_precision = 80; default:
floatx80_rounding_precision = 80;
} }
#endif
} }
void nwfpe_init(union fp_state *fp) void nwfpe_init_fpa(union fp_state *fp)
{ {
FPA11 *fpa11 = (FPA11 *)fp; FPA11 *fpa11 = (FPA11 *)fp;
#ifdef NWFPE_DEBUG
printk("NWFPE: setting up state.\n");
#endif
memset(fpa11, 0, sizeof(FPA11)); memset(fpa11, 0, sizeof(FPA11));
resetFPA11(); resetFPA11();
SetRoundingMode(ROUND_TO_NEAREST); SetRoundingMode(ROUND_TO_NEAREST);
...@@ -140,81 +110,33 @@ void nwfpe_init(union fp_state *fp) ...@@ -140,81 +110,33 @@ void nwfpe_init(union fp_state *fp)
/* Emulate the instruction in the opcode. */ /* Emulate the instruction in the opcode. */
unsigned int EmulateAll(unsigned int opcode) unsigned int EmulateAll(unsigned int opcode)
{ {
unsigned int nRc = 1, code; unsigned int code;
#ifdef NWFPE_DEBUG
printk("NWFPE: emulating opcode %08x\n", opcode);
#endif
code = opcode & 0x00000f00; code = opcode & 0x00000f00;
if (code == 0x00000100 || code == 0x00000200) if (code == 0x00000100 || code == 0x00000200) {
{
/* For coprocessor 1 or 2 (FPA11) */ /* For coprocessor 1 or 2 (FPA11) */
code = opcode & 0x0e000000; code = opcode & 0x0e000000;
if (code == 0x0e000000) if (code == 0x0e000000) {
{ if (opcode & 0x00000010) {
if (opcode & 0x00000010)
{
/* Emulate conversion opcodes. */ /* Emulate conversion opcodes. */
/* Emulate register transfer opcodes. */ /* Emulate register transfer opcodes. */
/* Emulate comparison opcodes. */ /* Emulate comparison opcodes. */
nRc = EmulateCPRT(opcode); return EmulateCPRT(opcode);
} } else {
else
{
/* Emulate monadic arithmetic opcodes. */ /* Emulate monadic arithmetic opcodes. */
/* Emulate dyadic arithmetic opcodes. */ /* Emulate dyadic arithmetic opcodes. */
nRc = EmulateCPDO(opcode); return EmulateCPDO(opcode);
}
} }
else if (code == 0x0c000000) } else if (code == 0x0c000000) {
{
/* Emulate load/store opcodes. */ /* Emulate load/store opcodes. */
/* Emulate load/store multiple opcodes. */ /* Emulate load/store multiple opcodes. */
nRc = EmulateCPDT(opcode); return EmulateCPDT(opcode);
}
else
{
/* Invalid instruction detected. Return FALSE. */
nRc = 0;
}
}
return(nRc);
}
#if 0
unsigned int EmulateAll1(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; /* Invalid instruction detected. Return FALSE. */
} return 0;
} }
#endif
...@@ -37,6 +37,7 @@ register unsigned int *user_registers asm("sl"); ...@@ -37,6 +37,7 @@ register unsigned int *user_registers asm("sl");
/* includes */ /* includes */
#include "fpsr.h" /* FP control and status register definitions */ #include "fpsr.h" /* FP control and status register definitions */
#include "milieu.h"
#include "softfloat.h" #include "softfloat.h"
#define typeNone 0x00 #define typeNone 0x00
...@@ -48,9 +49,13 @@ register unsigned int *user_registers asm("sl"); ...@@ -48,9 +49,13 @@ register unsigned int *user_registers asm("sl");
* This must be no more and no less than 12 bytes. * This must be no more and no less than 12 bytes.
*/ */
typedef union tagFPREG { 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; } FPREG;
/* /*
...@@ -71,8 +76,8 @@ typedef struct tagFPA11 { ...@@ -71,8 +76,8 @@ typedef struct tagFPA11 {
/* 96 */ FPSR fpsr; /* floating point status register */ /* 96 */ FPSR fpsr; /* floating point status register */
/* 100 */ FPCR fpcr; /* floating point control register */ /* 100 */ FPCR fpcr; /* floating point control register */
/* 104 */ unsigned char fType[8]; /* type of floating point value held in /* 104 */ unsigned char fType[8]; /* type of floating point value held in
floating point registers. One of none floating point registers. One of
single, double or extended. */ none, single, double or extended. */
/* 112 */ int initflag; /* this is special. The kernel guarantees /* 112 */ int initflag; /* this is special. The kernel guarantees
to set it to 0 when a thread is launched, to set it to 0 when a thread is launched,
so we can use it to detect whether this so we can use it to detect whether this
...@@ -82,6 +87,6 @@ typedef struct tagFPA11 { ...@@ -82,6 +87,6 @@ typedef struct tagFPA11 {
extern void SetRoundingMode(const unsigned int); extern void SetRoundingMode(const unsigned int);
extern void SetRoundingPrecision(const unsigned int); extern void SetRoundingPrecision(const unsigned int);
extern void nwfpe_init(union fp_state *fp); extern void nwfpe_init_fpa(union fp_state *fp);
#endif #endif
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
extern __inline__ unsigned int readFPSR(void) extern __inline__ unsigned int readFPSR(void)
{ {
FPA11 *fpa11 = GET_FPA11(); FPA11 *fpa11 = GET_FPA11();
return(fpa11->fpsr); return (fpa11->fpsr);
} }
extern __inline__ void writeFPSR(FPSR reg) extern __inline__ void writeFPSR(FPSR reg)
...@@ -40,7 +40,7 @@ extern __inline__ FPCR readFPCR(void) ...@@ -40,7 +40,7 @@ extern __inline__ FPCR readFPCR(void)
{ {
FPA11 *fpa11 = GET_FPA11(); FPA11 *fpa11 = GET_FPA11();
/* clear SB, AB and DA bits before returning FPCR */ /* clear SB, AB and DA bits before returning FPCR */
return(fpa11->fpcr & ~MASK_RFC); return (fpa11->fpcr & ~MASK_RFC);
} }
extern __inline__ void writeFPCR(FPCR reg) extern __inline__ void writeFPCR(FPCR reg)
......
/* /*
NetWinder Floating Point Emulator NetWinder Floating Point Emulator
(c) Rebel.COM, 1998,1999 (c) Rebel.COM, 1998,1999
(c) Philip Blundell, 2001
Direct questions, comments to Scott Bambrough <scottb@netwinder.org> Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
...@@ -22,21 +23,21 @@ ...@@ -22,21 +23,21 @@
#include "fpa11.h" #include "fpa11.h"
#include "fpopcode.h" #include "fpopcode.h"
unsigned int SingleCPDO(const unsigned int opcode); unsigned int SingleCPDO(const unsigned int opcode, FPREG * rFd);
unsigned int DoubleCPDO(const unsigned int opcode); unsigned int DoubleCPDO(const unsigned int opcode, FPREG * rFd);
unsigned int ExtendedCPDO(const unsigned int opcode); unsigned int ExtendedCPDO(const unsigned int opcode, FPREG * rFd);
unsigned int EmulateCPDO(const unsigned int opcode) unsigned int EmulateCPDO(const unsigned int opcode)
{ {
FPA11 *fpa11 = GET_FPA11(); FPA11 *fpa11 = GET_FPA11();
unsigned int Fd, nType, nDest, nRc = 1; FPREG *rFd;
unsigned int nType, nDest, nRc;
//printk("EmulateCPDO(0x%08x)\n",opcode);
/* Get the destination size. If not valid let Linux perform /* Get the destination size. If not valid let Linux perform
an invalid instruction trap. */ an invalid instruction trap. */
nDest = getDestinationSize(opcode); nDest = getDestinationSize(opcode);
if (typeNone == nDest) return 0; if (typeNone == nDest)
return 0;
SetRoundingMode(opcode); SetRoundingMode(opcode);
...@@ -50,67 +51,80 @@ unsigned int EmulateCPDO(const unsigned int opcode) ...@@ -50,67 +51,80 @@ unsigned int EmulateCPDO(const unsigned int opcode)
else else
nType = fpa11->fType[getFn(opcode)]; nType = fpa11->fType[getFn(opcode)];
if (!CONSTANT_FM(opcode)) if (!CONSTANT_FM(opcode)) {
{
register unsigned int Fm = getFm(opcode); register unsigned int Fm = getFm(opcode);
if (nType < fpa11->fType[Fm]) if (nType < fpa11->fType[Fm]) {
{
nType = fpa11->fType[Fm]; nType = fpa11->fType[Fm];
} }
} }
switch (nType) rFd = &fpa11->fpreg[getFd(opcode)];
{
case typeSingle : nRc = SingleCPDO(opcode); break; switch (nType) {
case typeDouble : nRc = DoubleCPDO(opcode); break; case typeSingle:
case typeExtended : nRc = ExtendedCPDO(opcode); break; nRc = SingleCPDO(opcode, rFd);
default : nRc = 0; 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 /* If the operation succeeded, check to see if the result in the
destination register is the correct size. If not force it destination register is the correct size. If not force it
to be. */ to be. */
Fd = getFd(opcode);
nType = fpa11->fType[Fd]; fpa11->fType[getFd(opcode)] = nDest;
if ((0 != nRc) && (nDest != nType))
{ #ifdef CONFIG_FPE_NWFPE_XP
switch (nDest) if (nDest != nType) {
{ switch (nDest) {
case typeSingle: case typeSingle:
{ {
if (typeDouble == nType) if (typeDouble == nType)
fpa11->fpreg[Fd].fSingle = rFd->fSingle = float64_to_float32(rFd->fDouble);
float64_to_float32(fpa11->fpreg[Fd].fDouble);
else else
fpa11->fpreg[Fd].fSingle = rFd->fSingle = floatx80_to_float32(rFd->fExtended);
floatx80_to_float32(fpa11->fpreg[Fd].fExtended);
} }
break; break;
case typeDouble: case typeDouble:
{ {
if (typeSingle == nType) if (typeSingle == nType)
fpa11->fpreg[Fd].fDouble = rFd->fDouble = float32_to_float64(rFd->fSingle);
float32_to_float64(fpa11->fpreg[Fd].fSingle);
else else
fpa11->fpreg[Fd].fDouble = rFd->fDouble = floatx80_to_float64(rFd->fExtended);
floatx80_to_float64(fpa11->fpreg[Fd].fExtended);
} }
break; break;
case typeExtended: case typeExtended:
{ {
if (typeSingle == nType) if (typeSingle == nType)
fpa11->fpreg[Fd].fExtended = rFd->fExtended = float32_to_floatx80(rFd->fSingle);
float32_to_floatx80(fpa11->fpreg[Fd].fSingle);
else else
fpa11->fpreg[Fd].fExtended = rFd->fExtended = float64_to_floatx80(rFd->fDouble);
float64_to_floatx80(fpa11->fpreg[Fd].fDouble);
} }
break; break;
} }
}
fpa11->fType[Fd] = nDest; #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; return nRc;
......
/* /*
NetWinder Floating Point Emulator NetWinder Floating Point Emulator
(c) Rebel.com, 1998-1999 (c) Rebel.com, 1998-1999
(c) Philip Blundell, 1998 (c) Philip Blundell, 1998, 2001
Direct questions, comments to Scott Bambrough <scottb@netwinder.org> Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
...@@ -28,50 +28,47 @@ ...@@ -28,50 +28,47 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
static inline static inline void loadSingle(const unsigned int Fn, const unsigned int *pMem)
void loadSingle(const unsigned int Fn,const unsigned int *pMem)
{ {
FPA11 *fpa11 = GET_FPA11(); FPA11 *fpa11 = GET_FPA11();
fpa11->fType[Fn] = typeSingle; fpa11->fType[Fn] = typeSingle;
get_user(fpa11->fpreg[Fn].fSingle, pMem); get_user(fpa11->fpreg[Fn].fSingle, pMem);
} }
static inline static inline void loadDouble(const unsigned int Fn, const unsigned int *pMem)
void loadDouble(const unsigned int Fn,const unsigned int *pMem)
{ {
FPA11 *fpa11 = GET_FPA11(); FPA11 *fpa11 = GET_FPA11();
unsigned int *p; unsigned int *p;
p = (unsigned int*)&fpa11->fpreg[Fn].fDouble; p = (unsigned int *) &fpa11->fpreg[Fn].fDouble;
fpa11->fType[Fn] = typeDouble; fpa11->fType[Fn] = typeDouble;
get_user(p[0], &pMem[1]); get_user(p[0], &pMem[1]);
get_user(p[1], &pMem[0]); /* sign & exponent */ get_user(p[1], &pMem[0]); /* sign & exponent */
} }
static inline #ifdef CONFIG_FPE_NWFPE_XP
void loadExtended(const unsigned int Fn,const unsigned int *pMem) static inline void loadExtended(const unsigned int Fn, const unsigned int *pMem)
{ {
FPA11 *fpa11 = GET_FPA11(); FPA11 *fpa11 = GET_FPA11();
unsigned int *p; unsigned int *p;
p = (unsigned int*)&fpa11->fpreg[Fn].fExtended; p = (unsigned int *) &fpa11->fpreg[Fn].fExtended;
fpa11->fType[Fn] = typeExtended; fpa11->fType[Fn] = typeExtended;
get_user(p[0], &pMem[0]); /* sign & exponent */ get_user(p[0], &pMem[0]); /* sign & exponent */
get_user(p[1], &pMem[2]); /* ls bits */ get_user(p[1], &pMem[2]); /* ls bits */
get_user(p[2], &pMem[1]); /* ms bits */ get_user(p[2], &pMem[1]); /* ms bits */
} }
#endif
static inline static inline void loadMultiple(const unsigned int Fn, const unsigned int *pMem)
void loadMultiple(const unsigned int Fn,const unsigned int *pMem)
{ {
FPA11 *fpa11 = GET_FPA11(); FPA11 *fpa11 = GET_FPA11();
register unsigned int *p; register unsigned int *p;
unsigned long x; unsigned long x;
p = (unsigned int*)&(fpa11->fpreg[Fn]); p = (unsigned int *) &(fpa11->fpreg[Fn]);
get_user(x, &pMem[0]); get_user(x, &pMem[0]);
fpa11->fType[Fn] = (x >> 14) & 0x00000003; fpa11->fType[Fn] = (x >> 14) & 0x00000003;
switch (fpa11->fType[Fn]) switch (fpa11->fType[Fn]) {
{
case typeSingle: case typeSingle:
case typeDouble: case typeDouble:
{ {
...@@ -81,6 +78,7 @@ void loadMultiple(const unsigned int Fn,const unsigned int *pMem) ...@@ -81,6 +78,7 @@ void loadMultiple(const unsigned int Fn,const unsigned int *pMem)
} }
break; break;
#ifdef CONFIG_FPE_NWFPE_XP
case typeExtended: case typeExtended:
{ {
get_user(p[1], &pMem[2]); get_user(p[1], &pMem[2]);
...@@ -88,74 +86,73 @@ void loadMultiple(const unsigned int Fn,const unsigned int *pMem) ...@@ -88,74 +86,73 @@ void loadMultiple(const unsigned int Fn,const unsigned int *pMem)
p[0] = (x & 0x80003fff); p[0] = (x & 0x80003fff);
} }
break; break;
#endif
} }
} }
static inline static inline void storeSingle(const unsigned int Fn, unsigned int *pMem)
void storeSingle(const unsigned int Fn,unsigned int *pMem)
{ {
FPA11 *fpa11 = GET_FPA11(); FPA11 *fpa11 = GET_FPA11();
union union {
{
float32 f; float32 f;
unsigned int i[1]; unsigned int i[1];
} val; } val;
switch (fpa11->fType[Fn]) switch (fpa11->fType[Fn]) {
{
case typeDouble: case typeDouble:
val.f = float64_to_float32(fpa11->fpreg[Fn].fDouble); val.f = float64_to_float32(fpa11->fpreg[Fn].fDouble);
break; break;
#ifdef CONFIG_FPE_NWFPE_XP
case typeExtended: case typeExtended:
val.f = floatx80_to_float32(fpa11->fpreg[Fn].fExtended); val.f = floatx80_to_float32(fpa11->fpreg[Fn].fExtended);
break; break;
#endif
default: val.f = fpa11->fpreg[Fn].fSingle; default:
val.f = fpa11->fpreg[Fn].fSingle;
} }
put_user(val.i[0], pMem); put_user(val.i[0], pMem);
} }
static inline static inline void storeDouble(const unsigned int Fn, unsigned int *pMem)
void storeDouble(const unsigned int Fn,unsigned int *pMem)
{ {
FPA11 *fpa11 = GET_FPA11(); FPA11 *fpa11 = GET_FPA11();
union union {
{
float64 f; float64 f;
unsigned int i[2]; unsigned int i[2];
} val; } val;
switch (fpa11->fType[Fn]) switch (fpa11->fType[Fn]) {
{
case typeSingle: case typeSingle:
val.f = float32_to_float64(fpa11->fpreg[Fn].fSingle); val.f = float32_to_float64(fpa11->fpreg[Fn].fSingle);
break; break;
#ifdef CONFIG_FPE_NWFPE_XP
case typeExtended: case typeExtended:
val.f = floatx80_to_float64(fpa11->fpreg[Fn].fExtended); val.f = floatx80_to_float64(fpa11->fpreg[Fn].fExtended);
break; break;
#endif
default: val.f = fpa11->fpreg[Fn].fDouble; default:
val.f = fpa11->fpreg[Fn].fDouble;
} }
put_user(val.i[1], &pMem[0]); /* msw */ put_user(val.i[1], &pMem[0]); /* msw */
put_user(val.i[0], &pMem[1]); /* lsw */ put_user(val.i[0], &pMem[1]); /* lsw */
} }
static inline #ifdef CONFIG_FPE_NWFPE_XP
void storeExtended(const unsigned int Fn,unsigned int *pMem) static inline void storeExtended(const unsigned int Fn, unsigned int *pMem)
{ {
FPA11 *fpa11 = GET_FPA11(); FPA11 *fpa11 = GET_FPA11();
union union {
{
floatx80 f; floatx80 f;
unsigned int i[3]; unsigned int i[3];
} val; } val;
switch (fpa11->fType[Fn]) switch (fpa11->fType[Fn]) {
{
case typeSingle: case typeSingle:
val.f = float32_to_floatx80(fpa11->fpreg[Fn].fSingle); val.f = float32_to_floatx80(fpa11->fpreg[Fn].fSingle);
break; break;
...@@ -164,25 +161,25 @@ void storeExtended(const unsigned int Fn,unsigned int *pMem) ...@@ -164,25 +161,25 @@ void storeExtended(const unsigned int Fn,unsigned int *pMem)
val.f = float64_to_floatx80(fpa11->fpreg[Fn].fDouble); val.f = float64_to_floatx80(fpa11->fpreg[Fn].fDouble);
break; break;
default: val.f = fpa11->fpreg[Fn].fExtended; default:
val.f = fpa11->fpreg[Fn].fExtended;
} }
put_user(val.i[0], &pMem[0]); /* sign & exp */ put_user(val.i[0], &pMem[0]); /* sign & exp */
put_user(val.i[1], &pMem[2]); put_user(val.i[1], &pMem[2]);
put_user(val.i[2], &pMem[1]); /* msw */ put_user(val.i[2], &pMem[1]); /* msw */
} }
#endif
static inline static inline void storeMultiple(const unsigned int Fn, unsigned int *pMem)
void storeMultiple(const unsigned int Fn,unsigned int *pMem)
{ {
FPA11 *fpa11 = GET_FPA11(); FPA11 *fpa11 = GET_FPA11();
register unsigned int nType, *p; register unsigned int nType, *p;
p = (unsigned int*)&(fpa11->fpreg[Fn]); p = (unsigned int *) &(fpa11->fpreg[Fn]);
nType = fpa11->fType[Fn]; nType = fpa11->fType[Fn];
switch (nType) switch (nType) {
{
case typeSingle: case typeSingle:
case typeDouble: case typeDouble:
{ {
...@@ -192,6 +189,7 @@ void storeMultiple(const unsigned int Fn,unsigned int *pMem) ...@@ -192,6 +189,7 @@ void storeMultiple(const unsigned int Fn,unsigned int *pMem)
} }
break; break;
#ifdef CONFIG_FPE_NWFPE_XP
case typeExtended: case typeExtended:
{ {
put_user(p[2], &pMem[1]); /* msw */ put_user(p[2], &pMem[1]); /* msw */
...@@ -199,6 +197,7 @@ void storeMultiple(const unsigned int Fn,unsigned int *pMem) ...@@ -199,6 +197,7 @@ void storeMultiple(const unsigned int Fn,unsigned int *pMem)
put_user((p[0] & 0x80003fff) | (nType << 14), &pMem[0]); put_user((p[0] & 0x80003fff) | (nType << 14), &pMem[0]);
} }
break; break;
#endif
} }
} }
...@@ -207,11 +206,8 @@ unsigned int PerformLDF(const unsigned int opcode) ...@@ -207,11 +206,8 @@ unsigned int PerformLDF(const unsigned int opcode)
unsigned int *pBase, *pAddress, *pFinal, nRc = 1, unsigned int *pBase, *pAddress, *pFinal, nRc = 1,
write_back = WRITE_BACK(opcode); write_back = WRITE_BACK(opcode);
//printk("PerformLDF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode)); pBase = (unsigned int *) readRegister(getRn(opcode));
if (REG_PC == getRn(opcode)) {
pBase = (unsigned int*)readRegister(getRn(opcode));
if (REG_PC == getRn(opcode))
{
pBase += 2; pBase += 2;
write_back = 0; write_back = 0;
} }
...@@ -222,17 +218,29 @@ unsigned int PerformLDF(const unsigned int opcode) ...@@ -222,17 +218,29 @@ unsigned int PerformLDF(const unsigned int opcode)
else else
pFinal -= getOffset(opcode); pFinal -= getOffset(opcode);
if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase; if (PREINDEXED(opcode))
pAddress = pFinal;
else
pAddress = pBase;
switch (opcode & MASK_TRANSFER_LENGTH) switch (opcode & MASK_TRANSFER_LENGTH) {
{ case TRANSFER_SINGLE:
case TRANSFER_SINGLE : loadSingle(getFd(opcode),pAddress); break; loadSingle(getFd(opcode), pAddress);
case TRANSFER_DOUBLE : loadDouble(getFd(opcode),pAddress); break; break;
case TRANSFER_EXTENDED: loadExtended(getFd(opcode),pAddress); break; case TRANSFER_DOUBLE:
default: nRc = 0; 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); if (write_back)
writeRegister(getRn(opcode), (unsigned int) pFinal);
return nRc; return nRc;
} }
...@@ -241,12 +249,10 @@ unsigned int PerformSTF(const unsigned int opcode) ...@@ -241,12 +249,10 @@ unsigned int PerformSTF(const unsigned int opcode)
unsigned int *pBase, *pAddress, *pFinal, nRc = 1, unsigned int *pBase, *pAddress, *pFinal, nRc = 1,
write_back = WRITE_BACK(opcode); write_back = WRITE_BACK(opcode);
//printk("PerformSTF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode));
SetRoundingMode(ROUND_TO_NEAREST); SetRoundingMode(ROUND_TO_NEAREST);
pBase = (unsigned int*)readRegister(getRn(opcode)); pBase = (unsigned int *) readRegister(getRn(opcode));
if (REG_PC == getRn(opcode)) if (REG_PC == getRn(opcode)) {
{
pBase += 2; pBase += 2;
write_back = 0; write_back = 0;
} }
...@@ -257,17 +263,29 @@ unsigned int PerformSTF(const unsigned int opcode) ...@@ -257,17 +263,29 @@ unsigned int PerformSTF(const unsigned int opcode)
else else
pFinal -= getOffset(opcode); pFinal -= getOffset(opcode);
if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase; if (PREINDEXED(opcode))
pAddress = pFinal;
else
pAddress = pBase;
switch (opcode & MASK_TRANSFER_LENGTH) switch (opcode & MASK_TRANSFER_LENGTH) {
{ case TRANSFER_SINGLE:
case TRANSFER_SINGLE : storeSingle(getFd(opcode),pAddress); break; storeSingle(getFd(opcode), pAddress);
case TRANSFER_DOUBLE : storeDouble(getFd(opcode),pAddress); break; break;
case TRANSFER_EXTENDED: storeExtended(getFd(opcode),pAddress); break; case TRANSFER_DOUBLE:
default: nRc = 0; 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); if (write_back)
writeRegister(getRn(opcode), (unsigned int) pFinal);
return nRc; return nRc;
} }
...@@ -276,9 +294,8 @@ unsigned int PerformLFM(const unsigned int opcode) ...@@ -276,9 +294,8 @@ unsigned int PerformLFM(const unsigned int opcode)
unsigned int i, Fd, *pBase, *pAddress, *pFinal, unsigned int i, Fd, *pBase, *pAddress, *pFinal,
write_back = WRITE_BACK(opcode); write_back = WRITE_BACK(opcode);
pBase = (unsigned int*)readRegister(getRn(opcode)); pBase = (unsigned int *) readRegister(getRn(opcode));
if (REG_PC == getRn(opcode)) if (REG_PC == getRn(opcode)) {
{
pBase += 2; pBase += 2;
write_back = 0; write_back = 0;
} }
...@@ -289,17 +306,22 @@ unsigned int PerformLFM(const unsigned int opcode) ...@@ -289,17 +306,22 @@ unsigned int PerformLFM(const unsigned int opcode)
else else
pFinal -= getOffset(opcode); pFinal -= getOffset(opcode);
if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase; if (PREINDEXED(opcode))
pAddress = pFinal;
else
pAddress = pBase;
Fd = getFd(opcode); Fd = getFd(opcode);
for (i=getRegisterCount(opcode);i>0;i--) for (i = getRegisterCount(opcode); i > 0; i--) {
{ loadMultiple(Fd, pAddress);
loadMultiple(Fd,pAddress); pAddress += 3;
pAddress += 3; Fd++; Fd++;
if (Fd == 8) Fd = 0; if (Fd == 8)
Fd = 0;
} }
if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal); if (write_back)
writeRegister(getRn(opcode), (unsigned int) pFinal);
return 1; return 1;
} }
...@@ -308,9 +330,8 @@ unsigned int PerformSFM(const unsigned int opcode) ...@@ -308,9 +330,8 @@ unsigned int PerformSFM(const unsigned int opcode)
unsigned int i, Fd, *pBase, *pAddress, *pFinal, unsigned int i, Fd, *pBase, *pAddress, *pFinal,
write_back = WRITE_BACK(opcode); write_back = WRITE_BACK(opcode);
pBase = (unsigned int*)readRegister(getRn(opcode)); pBase = (unsigned int *) readRegister(getRn(opcode));
if (REG_PC == getRn(opcode)) if (REG_PC == getRn(opcode)) {
{
pBase += 2; pBase += 2;
write_back = 0; write_back = 0;
} }
...@@ -321,48 +342,40 @@ unsigned int PerformSFM(const unsigned int opcode) ...@@ -321,48 +342,40 @@ unsigned int PerformSFM(const unsigned int opcode)
else else
pFinal -= getOffset(opcode); pFinal -= getOffset(opcode);
if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase; if (PREINDEXED(opcode))
pAddress = pFinal;
else
pAddress = pBase;
Fd = getFd(opcode); Fd = getFd(opcode);
for (i=getRegisterCount(opcode);i>0;i--) for (i = getRegisterCount(opcode); i > 0; i--) {
{ storeMultiple(Fd, pAddress);
storeMultiple(Fd,pAddress); pAddress += 3;
pAddress += 3; Fd++; Fd++;
if (Fd == 8) Fd = 0; if (Fd == 8)
Fd = 0;
} }
if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal); if (write_back)
writeRegister(getRn(opcode), (unsigned int) pFinal);
return 1; return 1;
} }
#if 1
unsigned int EmulateCPDT(const unsigned int opcode) 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)) {
if (LDF_OP(opcode))
{
nRc = PerformLDF(opcode); nRc = PerformLDF(opcode);
} } else if (LFM_OP(opcode)) {
else if (LFM_OP(opcode))
{
nRc = PerformLFM(opcode); nRc = PerformLFM(opcode);
} } else if (STF_OP(opcode)) {
else if (STF_OP(opcode))
{
nRc = PerformSTF(opcode); nRc = PerformSTF(opcode);
} } else if (SFM_OP(opcode)) {
else if (SFM_OP(opcode))
{
nRc = PerformSFM(opcode); nRc = PerformSFM(opcode);
} } else {
else
{
nRc = 0; nRc = 0;
} }
return nRc; return nRc;
} }
#endif
/* /*
NetWinder Floating Point Emulator NetWinder Floating Point Emulator
(c) Rebel.COM, 1998,1999 (c) Rebel.COM, 1998,1999
(c) Philip Blundell, 1999 (c) Philip Blundell, 1999, 2001
Direct questions, comments to Scott Bambrough <scottb@netwinder.org> Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
...@@ -21,188 +21,148 @@ ...@@ -21,188 +21,148 @@
*/ */
#include "fpa11.h" #include "fpa11.h"
#include "milieu.h"
#include "softfloat.h"
#include "fpopcode.h" #include "fpopcode.h"
#include "fpa11.inl" #include "fpa11.inl"
#include "fpmodule.h" #include "fpmodule.h"
#include "fpmodule.inl" #include "fpmodule.inl"
#ifdef CONFIG_FPE_NWFPE_XP
extern flag floatx80_is_nan(floatx80); extern flag floatx80_is_nan(floatx80);
extern flag float64_is_nan( float64); #endif
extern flag float32_is_nan( float32); extern flag float64_is_nan(float64);
extern flag float32_is_nan(float32);
void SetRoundingMode(const unsigned int opcode); void SetRoundingMode(const unsigned int opcode);
unsigned int PerformFLT(const unsigned int opcode); unsigned int PerformFLT(const unsigned int opcode);
unsigned int PerformFIX(const unsigned int opcode); unsigned int PerformFIX(const unsigned int opcode);
static unsigned int static unsigned int PerformComparison(const unsigned int opcode);
PerformComparison(const unsigned int opcode);
unsigned int EmulateCPRT(const unsigned int opcode) unsigned int EmulateCPRT(const unsigned int opcode)
{ {
unsigned int nRc = 1;
//printk("EmulateCPRT(0x%08x)\n",opcode);
if (opcode & 0x800000) if (opcode & 0x800000) {
{ /* This is some variant of a comparison (PerformComparison
/* This is some variant of a comparison (PerformComparison will will sort out which one). Since most of the other CPRT
sort out which one). Since most of the other CPRT instructions are oddball cases of some sort or other it
instructions are oddball cases of some sort or other it makes makes sense to pull this out into a fast path. */
sense to pull this out into a fast path. */
return PerformComparison(opcode); return PerformComparison(opcode);
} }
/* Hint to GCC that we'd like a jump table rather than a load of CMPs */ /* Hint to GCC that we'd like a jump table rather than a load of CMPs */
switch ((opcode & 0x700000) >> 20) switch ((opcode & 0x700000) >> 20) {
{ case FLT_CODE >> 20:
case FLT_CODE >> 20: nRc = PerformFLT(opcode); break; return PerformFLT(opcode);
case FIX_CODE >> 20: nRc = PerformFIX(opcode); break; break;
case FIX_CODE >> 20:
case WFS_CODE >> 20: writeFPSR(readRegister(getRd(opcode))); break; return PerformFIX(opcode);
case RFS_CODE >> 20: writeRegister(getRd(opcode),readFPSR()); break; break;
#if 0 /* We currently have no use for the FPCR, so there's no point case WFS_CODE >> 20:
in emulating it. */ writeFPSR(readRegister(getRd(opcode)));
case WFC_CODE >> 20: writeFPCR(readRegister(getRd(opcode))); break;
case RFC_CODE >> 20: writeRegister(getRd(opcode),readFPCR()); break; case RFS_CODE >> 20:
#endif writeRegister(getRd(opcode), readFPSR());
break;
default: nRc = 0; default:
return 0;
} }
return nRc; return 1;
} }
unsigned int PerformFLT(const unsigned int opcode) unsigned int PerformFLT(const unsigned int opcode)
{ {
FPA11 *fpa11 = GET_FPA11(); FPA11 *fpa11 = GET_FPA11();
unsigned int nRc = 1;
SetRoundingMode(opcode); SetRoundingMode(opcode);
SetRoundingPrecision(opcode);
switch (opcode & MASK_ROUNDING_PRECISION) switch (opcode & MASK_ROUNDING_PRECISION) {
{
case ROUND_SINGLE: case ROUND_SINGLE:
{ {
fpa11->fType[getFn(opcode)] = typeSingle; fpa11->fType[getFn(opcode)] = typeSingle;
fpa11->fpreg[getFn(opcode)].fSingle = fpa11->fpreg[getFn(opcode)].fSingle = int32_to_float32(readRegister(getRd(opcode)));
int32_to_float32(readRegister(getRd(opcode)));
} }
break; break;
case ROUND_DOUBLE: case ROUND_DOUBLE:
{ {
fpa11->fType[getFn(opcode)] = typeDouble; fpa11->fType[getFn(opcode)] = typeDouble;
fpa11->fpreg[getFn(opcode)].fDouble = fpa11->fpreg[getFn(opcode)].fDouble = int32_to_float64(readRegister(getRd(opcode)));
int32_to_float64(readRegister(getRd(opcode)));
} }
break; break;
#ifdef CONFIG_FPE_NWFPE_XP
case ROUND_EXTENDED: case ROUND_EXTENDED:
{ {
fpa11->fType[getFn(opcode)] = typeExtended; fpa11->fType[getFn(opcode)] = typeExtended;
fpa11->fpreg[getFn(opcode)].fExtended = fpa11->fpreg[getFn(opcode)].fExtended = int32_to_floatx80(readRegister(getRd(opcode)));
int32_to_floatx80(readRegister(getRd(opcode)));
} }
break; break;
#endif
default: nRc = 0; default:
return 0;
} }
return nRc; return 1;
} }
unsigned int PerformFIX(const unsigned int opcode) unsigned int PerformFIX(const unsigned int opcode)
{ {
FPA11 *fpa11 = GET_FPA11(); FPA11 *fpa11 = GET_FPA11();
unsigned int nRc = 1;
unsigned int Fn = getFm(opcode); unsigned int Fn = getFm(opcode);
SetRoundingMode(opcode); SetRoundingMode(opcode);
switch (fpa11->fType[Fn]) switch (fpa11->fType[Fn]) {
{
case typeSingle: case typeSingle:
{ {
writeRegister(getRd(opcode), writeRegister(getRd(opcode), float32_to_int32(fpa11->fpreg[Fn].fSingle));
float32_to_int32(fpa11->fpreg[Fn].fSingle));
} }
break; break;
case typeDouble: case typeDouble:
{ {
writeRegister(getRd(opcode), writeRegister(getRd(opcode), float64_to_int32(fpa11->fpreg[Fn].fDouble));
float64_to_int32(fpa11->fpreg[Fn].fDouble));
} }
break; break;
#ifdef CONFIG_FPE_NWFPE_XP
case typeExtended: case typeExtended:
{ {
writeRegister(getRd(opcode), writeRegister(getRd(opcode), floatx80_to_int32(fpa11->fpreg[Fn].fExtended));
floatx80_to_int32(fpa11->fpreg[Fn].fExtended));
} }
break; break;
#endif
default: nRc = 0; default:
} return 0;
return nRc;
}
static unsigned int __inline__
PerformComparisonOperation(floatx80 Fn, floatx80 Fm)
{
unsigned int flags = 0;
/* 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; return 1;
} }
/* This instruction sets the flags N, Z, C, V in the FPSR. */ /* This instruction sets the flags N, Z, C, V in the FPSR. */
static unsigned int PerformComparison(const unsigned int opcode) static unsigned int PerformComparison(const unsigned int opcode)
{ {
FPA11 *fpa11 = GET_FPA11(); FPA11 *fpa11 = GET_FPA11();
unsigned int Fn, Fm; unsigned int Fn = getFn(opcode), Fm = getFm(opcode);
floatx80 rFn, rFm;
int e_flag = opcode & 0x400000; /* 1 if CxFE */ int e_flag = opcode & 0x400000; /* 1 if CxFE */
int n_flag = opcode & 0x200000; /* 1 if CNxx */ int n_flag = opcode & 0x200000; /* 1 if CNxx */
unsigned int flags = 0; unsigned int flags = 0;
//printk("PerformComparison(0x%08x)\n",opcode); #ifdef CONFIG_FPE_NWFPE_XP
floatx80 rFn, rFm;
Fn = getFn(opcode);
Fm = getFm(opcode);
/* Check for unordered condition and convert all operands to 80-bit /* Check for unordered condition and convert all operands to 80-bit
format. format.
?? Might be some mileage in avoiding this conversion if possible. ?? Might be some mileage in avoiding this conversion if possible.
Eg, if both operands are 32-bit, detect this and do a 32-bit Eg, if both operands are 32-bit, detect this and do a 32-bit
comparison (cheaper than an 80-bit one). */ comparison (cheaper than an 80-bit one). */
switch (fpa11->fType[Fn]) switch (fpa11->fType[Fn]) {
{
case typeSingle: case typeSingle:
//printk("single.\n"); //printk("single.\n");
if (float32_is_nan(fpa11->fpreg[Fn].fSingle)) if (float32_is_nan(fpa11->fpreg[Fn].fSingle))
...@@ -224,21 +184,18 @@ static unsigned int PerformComparison(const unsigned int opcode) ...@@ -224,21 +184,18 @@ static unsigned int PerformComparison(const unsigned int opcode)
rFn = fpa11->fpreg[Fn].fExtended; rFn = fpa11->fpreg[Fn].fExtended;
break; break;
default: return 0; default:
return 0;
} }
if (CONSTANT_FM(opcode)) if (CONSTANT_FM(opcode)) {
{
//printk("Fm is a constant: #%d.\n",Fm); //printk("Fm is a constant: #%d.\n",Fm);
rFm = getExtendedConstant(Fm); rFm = getExtendedConstant(Fm);
if (floatx80_is_nan(rFm)) if (floatx80_is_nan(rFm))
goto unordered; goto unordered;
} } else {
else
{
//printk("Fm = r%d which contains a ",Fm); //printk("Fm = r%d which contains a ",Fm);
switch (fpa11->fType[Fm]) switch (fpa11->fType[Fm]) {
{
case typeSingle: case typeSingle:
//printk("single.\n"); //printk("single.\n");
if (float32_is_nan(fpa11->fpreg[Fm].fSingle)) if (float32_is_nan(fpa11->fpreg[Fm].fSingle))
...@@ -260,16 +217,136 @@ static unsigned int PerformComparison(const unsigned int opcode) ...@@ -260,16 +217,136 @@ static unsigned int PerformComparison(const unsigned int opcode)
rFm = fpa11->fpreg[Fm].fExtended; rFm = fpa11->fpreg[Fm].fExtended;
break; break;
default: return 0; default:
return 0;
} }
} }
if (n_flag) if (n_flag)
{
rFm.high ^= 0x8000; 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
return PerformComparisonOperation(rFn,rFm); writeConditionCodes(flags);
return 1;
unordered: unordered:
/* ?? The FPA data sheet is pretty vague about this, in particular /* ?? The FPA data sheet is pretty vague about this, in particular
...@@ -280,9 +357,11 @@ static unsigned int PerformComparison(const unsigned int opcode) ...@@ -280,9 +357,11 @@ static unsigned int PerformComparison(const unsigned int opcode)
flags |= CC_OVERFLOW; flags |= CC_OVERFLOW;
flags &= ~(CC_ZERO | CC_NEGATIVE); 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); writeConditionCodes(flags);
return 1; return 1;
......
...@@ -42,11 +42,17 @@ ...@@ -42,11 +42,17 @@
#include "fpa11.inl" #include "fpa11.inl"
/* kernel symbols required for signal handling */ /* kernel symbols required for signal handling */
#ifdef CONFIG_FPE_NWFPE_XP
#define NWFPE_BITS "extended"
#else
#define NWFPE_BITS "double"
#endif
#ifdef MODULE #ifdef MODULE
void fp_send_sig(unsigned long sig, struct task_struct *p, int priv); void fp_send_sig(unsigned long sig, struct task_struct *p, int priv);
#if LINUX_VERSION_CODE > 0x20115 #if LINUX_VERSION_CODE > 0x20115
MODULE_AUTHOR("Scott Bambrough <scottb@rebel.com>"); MODULE_AUTHOR("Scott Bambrough <scottb@rebel.com>");
MODULE_DESCRIPTION("NWFPE floating point emulator"); MODULE_DESCRIPTION("NWFPE floating point emulator (" NWFPE_BITS " precision)");
#endif #endif
#else #else
...@@ -70,17 +76,6 @@ static void (*orig_fp_init)(union fp_state *); ...@@ -70,17 +76,6 @@ static void (*orig_fp_init)(union fp_state *);
/* forward declarations */ /* forward declarations */
extern void nwfpe_enter(void); extern void nwfpe_enter(void);
#ifdef MODULE
/*
* Return 0 if we can be unloaded. This can only happen if
* kern_fp_enter is still pointing at nwfpe_enter
*/
static int fpe_unload(void)
{
return (kern_fp_enter == nwfpe_enter) ? 0 : 1;
}
#endif
static int __init fpe_init(void) static int __init fpe_init(void)
{ {
if (sizeof(FPA11) > sizeof(union fp_state)) { if (sizeof(FPA11) > sizeof(union fp_state)) {
...@@ -92,25 +87,18 @@ static int __init fpe_init(void) ...@@ -92,25 +87,18 @@ static int __init fpe_init(void)
printk(KERN_ERR "nwfpe: bad register size\n"); printk(KERN_ERR "nwfpe: bad register size\n");
return -EINVAL; return -EINVAL;
} }
#ifdef MODULE
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")) if (fpe_type[0] && strcmp(fpe_type, "nwfpe"))
return 0; return 0;
#endif
/* Display title, version and copyright information. */ /* Display title, version and copyright information. */
printk(KERN_WARNING "NetWinder Floating Point Emulator V0.95 " printk(KERN_WARNING "NetWinder Floating Point Emulator V0.97 ("
"(c) 1998-1999 Rebel.com\n"); NWFPE_BITS " precision)\n");
/* Save pointer to the old FP handler and then patch ourselves in */ /* Save pointer to the old FP handler and then patch ourselves in */
orig_fp_enter = kern_fp_enter; orig_fp_enter = kern_fp_enter;
orig_fp_init = fp_init; orig_fp_init = fp_init;
kern_fp_enter = nwfpe_enter; kern_fp_enter = nwfpe_enter;
fp_init = nwfpe_init; fp_init = nwfpe_init_fpa;
return 0; return 0;
} }
...@@ -147,7 +135,8 @@ void float_raise(signed char flags) ...@@ -147,7 +135,8 @@ void float_raise(signed char flags)
register unsigned int fpsr, cumulativeTraps; register unsigned int fpsr, cumulativeTraps;
#ifdef CONFIG_DEBUG_USER #ifdef CONFIG_DEBUG_USER
printk(KERN_DEBUG "NWFPE: %s[%d] takes exception %08x at %p from %08x\n", printk(KERN_DEBUG
"NWFPE: %s[%d] takes exception %08x at %p from %08x\n",
current->comm, current->pid, flags, current->comm, current->pid, flags,
__builtin_return_address(0), GET_USERREG()[15]); __builtin_return_address(0), GET_USERREG()[15]);
#endif #endif
......
...@@ -22,8 +22,8 @@ ...@@ -22,8 +22,8 @@
extern __inline__ extern __inline__
unsigned int readRegister(const unsigned int nReg) unsigned int readRegister(const unsigned int nReg)
{ {
/* Note: The CPU thinks it has dealt with the current instruction. As /* Note: The CPU thinks it has dealt with the current instruction.
a result the program counter has been advanced to the next As a result the program counter has been advanced to the next
instruction, and points 4 bytes beyond the actual instruction instruction, and points 4 bytes beyond the actual instruction
that caused the invalid instruction trap to occur. We adjust that caused the invalid instruction trap to occur. We adjust
for this in this routine. LDF/STF instructions with Rn = PC for this in this routine. LDF/STF instructions with Rn = PC
...@@ -31,7 +31,8 @@ unsigned int readRegister(const unsigned int nReg) ...@@ -31,7 +31,8 @@ unsigned int readRegister(const unsigned int nReg)
address calculations. */ address calculations. */
unsigned int *userRegisters = GET_USERREG(); unsigned int *userRegisters = GET_USERREG();
unsigned int val = userRegisters[nReg]; unsigned int val = userRegisters[nReg];
if (REG_PC == nReg) val -= 4; if (REG_PC == nReg)
val -= 4;
return val; return val;
} }
...@@ -45,22 +46,22 @@ void writeRegister(const unsigned int nReg, const unsigned int val) ...@@ -45,22 +46,22 @@ void writeRegister(const unsigned int nReg, const unsigned int val)
extern __inline__ extern __inline__
unsigned int readCPSR(void) unsigned int readCPSR(void)
{ {
return(readRegister(REG_CPSR)); return (readRegister(REG_CPSR));
} }
extern __inline__ extern __inline__
void writeCPSR(const unsigned int val) void writeCPSR(const unsigned int val)
{ {
writeRegister(REG_CPSR,val); writeRegister(REG_CPSR, val);
} }
extern __inline__ extern __inline__
unsigned int readConditionCodes(void) unsigned int readConditionCodes(void)
{ {
#ifdef __FPEM_TEST__ #ifdef __FPEM_TEST__
return(0); return (0);
#else #else
return(readCPSR() & CC_MASK); return (readCPSR() & CC_MASK);
#endif #endif
} }
......
...@@ -26,16 +26,18 @@ ...@@ -26,16 +26,18 @@
#include "fpmodule.h" #include "fpmodule.h"
#include "fpmodule.inl" #include "fpmodule.inl"
#ifdef CONFIG_FPE_NWFPE_XP
const floatx80 floatx80Constant[] = { const floatx80 floatx80Constant[] = {
{ 0x0000, 0x0000000000000000ULL}, /* extended 0.0 */ {0x0000, 0x0000000000000000ULL}, /* extended 0.0 */
{ 0x3fff, 0x8000000000000000ULL}, /* extended 1.0 */ {0x3fff, 0x8000000000000000ULL}, /* extended 1.0 */
{ 0x4000, 0x8000000000000000ULL}, /* extended 2.0 */ {0x4000, 0x8000000000000000ULL}, /* extended 2.0 */
{ 0x4000, 0xc000000000000000ULL}, /* extended 3.0 */ {0x4000, 0xc000000000000000ULL}, /* extended 3.0 */
{ 0x4001, 0x8000000000000000ULL}, /* extended 4.0 */ {0x4001, 0x8000000000000000ULL}, /* extended 4.0 */
{ 0x4001, 0xa000000000000000ULL}, /* extended 5.0 */ {0x4001, 0xa000000000000000ULL}, /* extended 5.0 */
{ 0x3ffe, 0x8000000000000000ULL}, /* extended 0.5 */ {0x3ffe, 0x8000000000000000ULL}, /* extended 0.5 */
{ 0x4002, 0xa000000000000000ULL} /* extended 10.0 */ {0x4002, 0xa000000000000000ULL} /* extended 10.0 */
}; };
#endif
const float64 float64Constant[] = { const float64 float64Constant[] = {
0x0000000000000000ULL, /* double 0.0 */ 0x0000000000000000ULL, /* double 0.0 */
...@@ -59,67 +61,6 @@ const float32 float32Constant[] = { ...@@ -59,67 +61,6 @@ const float32 float32Constant[] = {
0x41200000 /* single 10.0 */ 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);
}
/* condition code lookup table /* condition code lookup table
index into the table is test code: EQ, NE, ... LT, GT, AL, NV index into the table is test code: EQ, NE, ... LT, GT, AL, NV
bit position in short is condition code: NZCV */ bit position in short is condition code: NZCV */
...@@ -144,5 +85,5 @@ static const unsigned short aCC[16] = { ...@@ -144,5 +85,5 @@ static const unsigned short aCC[16] = {
unsigned int checkCondition(const unsigned int opcode, const unsigned int ccodes) 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;
} }
/* /*
NetWinder Floating Point Emulator NetWinder Floating Point Emulator
(c) Rebel.COM, 1998,1999 (c) Rebel.COM, 1998,1999
(c) Philip Blundell, 2001
Direct questions, comments to Scott Bambrough <scottb@netwinder.org> Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
...@@ -366,11 +367,13 @@ TABLE 5 ...@@ -366,11 +367,13 @@ TABLE 5
/* Get the rounding mode from the opcode. */ /* Get the rounding mode from the opcode. */
#define getRoundingMode(opcode) ((opcode & MASK_ROUNDING_MODE) >> 5) #define getRoundingMode(opcode) ((opcode & MASK_ROUNDING_MODE) >> 5)
#ifdef CONFIG_FPE_NWFPE_XP
static inline const floatx80 getExtendedConstant(const unsigned int nIndex) static inline const floatx80 getExtendedConstant(const unsigned int nIndex)
{ {
extern const floatx80 floatx80Constant[]; extern const floatx80 floatx80Constant[];
return floatx80Constant[nIndex]; return floatx80Constant[nIndex];
} }
#endif
static inline const float64 getDoubleConstant(const unsigned int nIndex) static inline const float64 getDoubleConstant(const unsigned int nIndex)
{ {
...@@ -384,7 +387,91 @@ static inline const float32 getSingleConstant(const unsigned int nIndex) ...@@ -384,7 +387,91 @@ static inline const float32 getSingleConstant(const unsigned int nIndex)
return float32Constant[nIndex]; return float32Constant[nIndex];
} }
extern unsigned int getRegisterCount(const unsigned int opcode); static inline unsigned int getTransferLength(const unsigned int opcode)
extern unsigned int getDestinationSize(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;
}
return (nRc);
}
#endif #endif
/* /*
NetWinder Floating Point Emulator NetWinder Floating Point Emulator
(c) Rebel.COM, 1998,1999 (c) Rebel.COM, 1998,1999
(c) Philip Blundell, 2001
Direct questions, comments to Scott Bambrough <scottb@netwinder.org> Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
...@@ -32,224 +33,92 @@ float32 float32_arctan(float32 rFm); ...@@ -32,224 +33,92 @@ float32 float32_arctan(float32 rFm);
float32 float32_log(float32 rFm); float32 float32_log(float32 rFm);
float32 float32_tan(float32 rFm); float32 float32_tan(float32 rFm);
float32 float32_arccos(float32 rFm); float32 float32_arccos(float32 rFm);
float32 float32_pow(float32 rFn,float32 rFm); float32 float32_pow(float32 rFn, float32 rFm);
float32 float32_pol(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(); return float32_sub(rFm, rFn);
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;
}
#if 0
float32 float32_exp(float32 Fm)
{
//series
} }
float32 float32_ln(float32 Fm) static float32 float32_rdv(float32 rFn, float32 rFm)
{ {
//series return float32_div(rFm, rFn);
} }
float32 float32_sin(float32 rFm) 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,
[FML_CODE >> 20] = float32_mul,
[FDV_CODE >> 20] = float32_div,
[FRD_CODE >> 20] = float32_rdv,
};
static float32 float32_mvf(float32 rFm)
{ {
//series return rFm;
} }
float32 float32_cos(float32 rFm) static float32 float32_mnf(float32 rFm)
{ {
//series return rFm ^ 0x80000000;
} }
float32 float32_arcsin(float32 rFm) static float32 float32_abs(float32 rFm)
{ {
//series return rFm & 0x7fffffff;
} }
float32 float32_arctan(float32 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,
};
unsigned int SingleCPDO(const unsigned int opcode, FPREG * rFd)
{ {
//series FPA11 *fpa11 = GET_FPA11();
} float32 rFm;
unsigned int Fm, opc_mask_shift;
float32 float32_arccos(float32 rFm)
{
//return float32_sub(halfPi,float32_arcsin(rFm));
}
float32 float32_log(float32 rFm) Fm = getFm(opcode);
{ if (CONSTANT_FM(opcode)) {
return float32_div(float32_ln(rFm),getSingleConstant(7)); rFm = getSingleConstant(Fm);
} } else if (fpa11->fType[Fm] == typeSingle) {
rFm = fpa11->fpreg[Fm].fSingle;
} else {
return 0;
}
float32 float32_tan(float32 rFm) opc_mask_shift = (opcode & MASK_ARITHMETIC_OPCODE) >> 20;
{ if (!MONADIC_INSTRUCTION(opcode)) {
return float32_div(float32_sin(rFm),float32_cos(rFm)); unsigned int Fn = getFn(opcode);
} float32 rFn;
float32 float32_pow(float32 rFn,float32 rFm) if (fpa11->fType[Fn] == typeSingle &&
{ dyadic_single[opc_mask_shift]) {
return float32_exp(float32_mul(rFm,float32_ln(rFn))); 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;
}
}
float32 float32_pol(float32 rFn,float32 rFm) return 1;
{
return float32_arctan(float32_div(rFn,rFm));
} }
#endif
...@@ -29,8 +29,8 @@ this code that are retained. ...@@ -29,8 +29,8 @@ this code that are retained.
*/ */
#include "fpa11.h" #include "fpa11.h"
#include "milieu.h" //#include "milieu.h"
#include "softfloat.h" //#include "softfloat.h"
/* /*
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
...@@ -142,12 +142,14 @@ INLINE int16 extractFloat32Exp( float32 a ) ...@@ -142,12 +142,14 @@ INLINE int16 extractFloat32Exp( float32 a )
Returns the sign bit of the single-precision floating-point value `a'. Returns the sign bit of the single-precision floating-point value `a'.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
*/ */
#if 0 /* in softfloat.h */
INLINE flag extractFloat32Sign( float32 a ) INLINE flag extractFloat32Sign( float32 a )
{ {
return a>>31; return a>>31;
} }
#endif
/* /*
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
...@@ -184,9 +186,9 @@ INLINE float32 packFloat32( flag zSign, int16 zExp, bits32 zSig ) ...@@ -184,9 +186,9 @@ INLINE float32 packFloat32( flag zSign, int16 zExp, bits32 zSig )
{ {
#if 0 #if 0
float32 f; float32 f;
__asm__("@ packFloat32; \n\ __asm__("@ packFloat32 \n\
mov %0, %1, asl #31; \n\ mov %0, %1, asl #31 \n\
orr %0, %2, asl #23; \n\ orr %0, %2, asl #23 \n\
orr %0, %3" orr %0, %3"
: /* no outputs */ : /* no outputs */
: "g" (f), "g" (zSign), "g" (zExp), "g" (zSig) : "g" (f), "g" (zSign), "g" (zExp), "g" (zSig)
...@@ -321,12 +323,14 @@ INLINE int16 extractFloat64Exp( float64 a ) ...@@ -321,12 +323,14 @@ INLINE int16 extractFloat64Exp( float64 a )
Returns the sign bit of the double-precision floating-point value `a'. Returns the sign bit of the double-precision floating-point value `a'.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
*/ */
#if 0 /* in softfloat.h */
INLINE flag extractFloat64Sign( float64 a ) INLINE flag extractFloat64Sign( float64 a )
{ {
return a>>63; return a>>63;
} }
#endif
/* /*
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
......
...@@ -40,7 +40,9 @@ floating-point format `floatx80'. If this macro is not defined, the ...@@ -40,7 +40,9 @@ floating-point format `floatx80'. If this macro is not defined, the
input or output the `floatx80' type will be defined. input or output the `floatx80' type will be defined.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
*/ */
#ifdef CONFIG_FPE_NWFPE_XP
#define FLOATX80 #define FLOATX80
#endif
/* /*
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
...@@ -229,4 +231,46 @@ char floatx80_is_signaling_nan( floatx80 ); ...@@ -229,4 +231,46 @@ char floatx80_is_signaling_nan( floatx80 );
#endif #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 #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment