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
You may say N here if you are going to load the Acorn FPEmulator
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
tristate "FastFPE math emulation (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>
* fpa11.h - Add documentation
......
......@@ -2,18 +2,12 @@
# Copyright (C) 1998, 1999, 2001 Philip Blundell
#
obj-y :=
obj-m :=
obj-n :=
obj-$(CONFIG_FPE_NWFPE) += nwfpe.o
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
nwfpe-y += fpa11.o fpa11_cpdo.o fpa11_cpdt.o \
fpa11_cprt.o fpmodule.o fpopcode.o \
softfloat.o single_cpdo.o double_cpdo.o
ifeq ($(CONFIG_CPU_26),y)
nwfpe-objs += entry26.o
else
nwfpe-objs += entry.o
endif
nwfpe-$(CONFIG_FPE_NWFPE_XP) += extended_cpdo.o
nwfpe-$(CONFIG_CPU_26) += entry26.o
nwfpe-$(CONFIG_CPU_32) += entry.o
......@@ -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,26 +37,80 @@ float64 float64_arctan(float64 rFm);
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;
return float64_sub(rFm, rFn);
}
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);
if (CONSTANT_FM(opcode))
{
if (CONSTANT_FM(opcode)) {
rFm = getDoubleConstant(Fm);
}
else
{
switch (fpa11->fType[Fm])
{
} else {
switch (fpa11->fType[Fm]) {
case typeSingle:
rFm = float32_to_float64(fpa11->fpreg[Fm].fSingle);
break;
......@@ -60,24 +119,17 @@ unsigned int DoubleCPDO(const unsigned int opcode)
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;
default:
return 0;
}
}
if (!MONADIC_INSTRUCTION(opcode))
{
Fn = getFn(opcode);
switch (fpa11->fType[Fn])
{
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;
......@@ -86,203 +138,22 @@ unsigned int DoubleCPDO(const unsigned int opcode)
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;
default:
return 0;
}
break;
case ABS_CODE:
{
unsigned int *p = (unsigned int*)&rFm;
p[1] &= 0x7fffffff;
fpa11->fpreg[Fd].fDouble = rFm;
if (dyadic_double[opc_mask_shift]) {
rFd->fDouble = dyadic_double[opc_mask_shift](rFn, rFm);
} else {
return 0;
}
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;
} else {
if (monadic_double[opc_mask_shift]) {
rFd->fDouble = monadic_double[opc_mask_shift](rFm);
} else {
return 0;
}
}
if (0 != nRc) fpa11->fType[Fd] = typeDouble;
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));
return 1;
}
#endif
......@@ -73,7 +73,7 @@ several floating point instructions. */
.globl nwfpe_enter
nwfpe_enter:
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;
emulate:
......
......@@ -66,7 +66,6 @@ several floating point instructions. */
.globl nwfpe_enter
nwfpe_enter:
mov sl, sp
ldr r5, [sp, #60] @ get contents of PC
bic r5, r5, #0xfc000003
ldr r0, [r5, #-4] @ get actual instruction into r0
......
......@@ -32,26 +32,72 @@ floatx80 floatx80_arctan(floatx80 rFm);
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;
return floatx80_sub(rFm, rFn);
}
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);
if (CONSTANT_FM(opcode))
{
if (CONSTANT_FM(opcode)) {
rFm = getExtendedConstant(Fm);
}
else
{
switch (fpa11->fType[Fm])
{
} else {
switch (fpa11->fType[Fm]) {
case typeSingle:
rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle);
break;
......@@ -64,15 +110,17 @@ unsigned int ExtendedCPDO(const unsigned int opcode)
rFm = fpa11->fpreg[Fm].fExtended;
break;
default: return 0;
default:
return 0;
}
}
if (!MONADIC_INSTRUCTION(opcode))
{
Fn = getFn(opcode);
switch (fpa11->fType[Fn])
{
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;
......@@ -85,189 +133,22 @@ unsigned int ExtendedCPDO(const unsigned int opcode)
rFn = fpa11->fpreg[Fn].fExtended;
break;
default: return 0;
}
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 (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;
}
}
if (0 != nRc) fpa11->fType[Fd] = typeExtended;
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));
return 1;
}
#endif
/*
NetWinder Floating Point Emulator
(c) Rebel.COM, 1998,1999
(c) Philip Blundell, 2001
Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
......@@ -41,95 +42,64 @@ static void resetFPA11(void)
FPA11 *fpa11 = GET_FPA11();
/* initialize the register type array */
for (i=0;i<=7;i++)
{
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
}
void SetRoundingMode(const unsigned int opcode)
{
#if MAINTAIN_FPCR
FPA11 *fpa11 = GET_FPA11();
fpa11->fpcr &= ~MASK_ROUNDING_MODE;
#endif
switch (opcode & MASK_ROUNDING_MODE)
{
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;
}
}
void SetRoundingPrecision(const unsigned int opcode)
{
#if MAINTAIN_FPCR
FPA11 *fpa11 = GET_FPA11();
fpa11->fpcr &= ~MASK_ROUNDING_PRECISION;
#endif
switch (opcode & MASK_ROUNDING_PRECISION)
{
#ifdef CONFIG_FPE_NWFPE_XP
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;
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;
#ifdef NWFPE_DEBUG
printk("NWFPE: setting up state.\n");
#endif
memset(fpa11, 0, sizeof(FPA11));
resetFPA11();
SetRoundingMode(ROUND_TO_NEAREST);
......@@ -140,81 +110,33 @@ void nwfpe_init(union fp_state *fp)
/* Emulate the instruction in the 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;
if (code == 0x00000100 || code == 0x00000200)
{
if (code == 0x00000100 || code == 0x00000200) {
/* For coprocessor 1 or 2 (FPA11) */
code = opcode & 0x0e000000;
if (code == 0x0e000000)
{
if (opcode & 0x00000010)
{
if (code == 0x0e000000) {
if (opcode & 0x00000010) {
/* Emulate conversion opcodes. */
/* Emulate register transfer opcodes. */
/* Emulate comparison opcodes. */
nRc = EmulateCPRT(opcode);
}
else
{
return EmulateCPRT(opcode);
} else {
/* Emulate monadic 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 multiple opcodes. */
nRc = 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;
}
return EmulateCPDT(opcode);
}
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");
/* includes */
#include "fpsr.h" /* FP control and status register definitions */
#include "milieu.h"
#include "softfloat.h"
#define typeNone 0x00
......@@ -48,9 +49,13 @@ register unsigned int *user_registers asm("sl");
* This must be no more and no less than 12 bytes.
*/
typedef union tagFPREG {
floatx80 fExtended;
float64 fDouble;
float32 fSingle;
float64 fDouble;
#ifdef CONFIG_FPE_NWFPE_XP
floatx80 fExtended;
#else
int padding[3];
#endif
} FPREG;
/*
......@@ -71,8 +76,8 @@ typedef struct tagFPA11 {
/* 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. */
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
......@@ -82,6 +87,6 @@ typedef struct tagFPA11 {
extern void SetRoundingMode(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
......@@ -25,7 +25,7 @@
extern __inline__ unsigned int readFPSR(void)
{
FPA11 *fpa11 = GET_FPA11();
return(fpa11->fpsr);
return (fpa11->fpsr);
}
extern __inline__ void writeFPSR(FPSR reg)
......@@ -40,7 +40,7 @@ extern __inline__ FPCR readFPCR(void)
{
FPA11 *fpa11 = GET_FPA11();
/* 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)
......
/*
NetWinder Floating Point Emulator
(c) Rebel.COM, 1998,1999
(c) Philip Blundell, 2001
Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
......@@ -22,21 +23,21 @@
#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);
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;
if (typeNone == nDest)
return 0;
SetRoundingMode(opcode);
......@@ -50,67 +51,80 @@ unsigned int EmulateCPDO(const unsigned int opcode)
else
nType = fpa11->fType[getFn(opcode)];
if (!CONSTANT_FM(opcode))
{
if (!CONSTANT_FM(opcode)) {
register unsigned int Fm = getFm(opcode);
if (nType < fpa11->fType[Fm])
{
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;
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. */
Fd = getFd(opcode);
nType = fpa11->fType[Fd];
if ((0 != nRc) && (nDest != nType))
{
switch (nDest)
{
fpa11->fType[getFd(opcode)] = nDest;
#ifdef CONFIG_FPE_NWFPE_XP
if (nDest != nType) {
switch (nDest) {
case typeSingle:
{
if (typeDouble == nType)
fpa11->fpreg[Fd].fSingle =
float64_to_float32(fpa11->fpreg[Fd].fDouble);
rFd->fSingle = float64_to_float32(rFd->fDouble);
else
fpa11->fpreg[Fd].fSingle =
floatx80_to_float32(fpa11->fpreg[Fd].fExtended);
rFd->fSingle = floatx80_to_float32(rFd->fExtended);
}
break;
case typeDouble:
{
if (typeSingle == nType)
fpa11->fpreg[Fd].fDouble =
float32_to_float64(fpa11->fpreg[Fd].fSingle);
rFd->fDouble = float32_to_float64(rFd->fSingle);
else
fpa11->fpreg[Fd].fDouble =
floatx80_to_float64(fpa11->fpreg[Fd].fExtended);
rFd->fDouble = floatx80_to_float64(rFd->fExtended);
}
break;
case typeExtended:
{
if (typeSingle == nType)
fpa11->fpreg[Fd].fExtended =
float32_to_floatx80(fpa11->fpreg[Fd].fSingle);
rFd->fExtended = float32_to_floatx80(rFd->fSingle);
else
fpa11->fpreg[Fd].fExtended =
float64_to_floatx80(fpa11->fpreg[Fd].fDouble);
rFd->fExtended = float64_to_floatx80(rFd->fDouble);
}
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;
......
/*
NetWinder Floating Point Emulator
(c) Rebel.com, 1998-1999
(c) Philip Blundell, 1998
(c) Philip Blundell, 1998, 2001
Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
......@@ -28,50 +28,47 @@
#include <asm/uaccess.h>
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)
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;
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)
#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;
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)
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]);
p = (unsigned int *) &(fpa11->fpreg[Fn]);
get_user(x, &pMem[0]);
fpa11->fType[Fn] = (x >> 14) & 0x00000003;
switch (fpa11->fType[Fn])
{
switch (fpa11->fType[Fn]) {
case typeSingle:
case typeDouble:
{
......@@ -81,6 +78,7 @@ void loadMultiple(const unsigned int Fn,const unsigned int *pMem)
}
break;
#ifdef CONFIG_FPE_NWFPE_XP
case typeExtended:
{
get_user(p[1], &pMem[2]);
......@@ -88,74 +86,73 @@ void loadMultiple(const unsigned int Fn,const unsigned int *pMem)
p[0] = (x & 0x80003fff);
}
break;
#endif
}
}
static inline
void storeSingle(const unsigned int Fn,unsigned int *pMem)
static inline void storeSingle(const unsigned int Fn, unsigned int *pMem)
{
FPA11 *fpa11 = GET_FPA11();
union
{
union {
float32 f;
unsigned int i[1];
} val;
switch (fpa11->fType[Fn])
{
switch (fpa11->fType[Fn]) {
case typeDouble:
val.f = float64_to_float32(fpa11->fpreg[Fn].fDouble);
break;
#ifdef CONFIG_FPE_NWFPE_XP
case typeExtended:
val.f = floatx80_to_float32(fpa11->fpreg[Fn].fExtended);
break;
#endif
default: val.f = fpa11->fpreg[Fn].fSingle;
default:
val.f = fpa11->fpreg[Fn].fSingle;
}
put_user(val.i[0], pMem);
}
static inline
void storeDouble(const unsigned int Fn,unsigned int *pMem)
static inline void storeDouble(const unsigned int Fn, unsigned int *pMem)
{
FPA11 *fpa11 = GET_FPA11();
union
{
union {
float64 f;
unsigned int i[2];
} val;
switch (fpa11->fType[Fn])
{
switch (fpa11->fType[Fn]) {
case typeSingle:
val.f = float32_to_float64(fpa11->fpreg[Fn].fSingle);
break;
#ifdef CONFIG_FPE_NWFPE_XP
case typeExtended:
val.f = floatx80_to_float64(fpa11->fpreg[Fn].fExtended);
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[0], &pMem[1]); /* lsw */
}
static inline
void storeExtended(const unsigned int Fn,unsigned int *pMem)
#ifdef CONFIG_FPE_NWFPE_XP
static inline void storeExtended(const unsigned int Fn, unsigned int *pMem)
{
FPA11 *fpa11 = GET_FPA11();
union
{
union {
floatx80 f;
unsigned int i[3];
} val;
switch (fpa11->fType[Fn])
{
switch (fpa11->fType[Fn]) {
case typeSingle:
val.f = float32_to_floatx80(fpa11->fpreg[Fn].fSingle);
break;
......@@ -164,25 +161,25 @@ void storeExtended(const unsigned int Fn,unsigned int *pMem)
val.f = float64_to_floatx80(fpa11->fpreg[Fn].fDouble);
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[1], &pMem[2]);
put_user(val.i[2], &pMem[1]); /* msw */
}
#endif
static inline
void storeMultiple(const unsigned int Fn,unsigned int *pMem)
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]);
p = (unsigned int *) &(fpa11->fpreg[Fn]);
nType = fpa11->fType[Fn];
switch (nType)
{
switch (nType) {
case typeSingle:
case typeDouble:
{
......@@ -192,6 +189,7 @@ void storeMultiple(const unsigned int Fn,unsigned int *pMem)
}
break;
#ifdef CONFIG_FPE_NWFPE_XP
case typeExtended:
{
put_user(p[2], &pMem[1]); /* msw */
......@@ -199,6 +197,7 @@ void storeMultiple(const unsigned int Fn,unsigned int *pMem)
put_user((p[0] & 0x80003fff) | (nType << 14), &pMem[0]);
}
break;
#endif
}
}
......@@ -207,11 +206,8 @@ unsigned int PerformLDF(const unsigned int opcode)
unsigned int *pBase, *pAddress, *pFinal, nRc = 1,
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;
write_back = 0;
}
......@@ -222,17 +218,29 @@ unsigned int PerformLDF(const unsigned int opcode)
else
pFinal -= getOffset(opcode);
if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase;
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;
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);
if (write_back)
writeRegister(getRn(opcode), (unsigned int) pFinal);
return nRc;
}
......@@ -241,12 +249,10 @@ 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 = (unsigned int *) readRegister(getRn(opcode));
if (REG_PC == getRn(opcode)) {
pBase += 2;
write_back = 0;
}
......@@ -257,17 +263,29 @@ unsigned int PerformSTF(const unsigned int opcode)
else
pFinal -= getOffset(opcode);
if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase;
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;
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);
if (write_back)
writeRegister(getRn(opcode), (unsigned int) pFinal);
return nRc;
}
......@@ -276,9 +294,8 @@ 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 = (unsigned int *) readRegister(getRn(opcode));
if (REG_PC == getRn(opcode)) {
pBase += 2;
write_back = 0;
}
......@@ -289,17 +306,22 @@ unsigned int PerformLFM(const unsigned int opcode)
else
pFinal -= getOffset(opcode);
if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase;
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;
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);
if (write_back)
writeRegister(getRn(opcode), (unsigned int) pFinal);
return 1;
}
......@@ -308,9 +330,8 @@ 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 = (unsigned int *) readRegister(getRn(opcode));
if (REG_PC == getRn(opcode)) {
pBase += 2;
write_back = 0;
}
......@@ -321,48 +342,40 @@ unsigned int PerformSFM(const unsigned int opcode)
else
pFinal -= getOffset(opcode);
if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase;
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;
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);
if (write_back)
writeRegister(getRn(opcode), (unsigned int) pFinal);
return 1;
}
#if 1
unsigned int EmulateCPDT(const unsigned int opcode)
{
unsigned int nRc = 0;
//printk("EmulateCPDT(0x%08x)\n",opcode);
if (LDF_OP(opcode))
{
if (LDF_OP(opcode)) {
nRc = PerformLDF(opcode);
}
else if (LFM_OP(opcode))
{
} else if (LFM_OP(opcode)) {
nRc = PerformLFM(opcode);
}
else if (STF_OP(opcode))
{
} else if (STF_OP(opcode)) {
nRc = PerformSTF(opcode);
}
else if (SFM_OP(opcode))
{
} else if (SFM_OP(opcode)) {
nRc = PerformSFM(opcode);
}
else
{
} else {
nRc = 0;
}
return nRc;
}
#endif
/*
NetWinder Floating Point Emulator
(c) Rebel.COM, 1998,1999
(c) Philip Blundell, 1999
(c) Philip Blundell, 1999, 2001
Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
......@@ -21,188 +21,148 @@
*/
#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. */
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;
switch ((opcode & 0x700000) >> 20) {
case FLT_CODE >> 20:
return PerformFLT(opcode);
break;
case FIX_CODE >> 20:
return PerformFIX(opcode);
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
case WFS_CODE >> 20:
writeFPSR(readRegister(getRd(opcode)));
break;
case RFS_CODE >> 20:
writeRegister(getRd(opcode), readFPSR());
break;
default: nRc = 0;
default:
return 0;
}
return nRc;
return 1;
}
unsigned int PerformFLT(const unsigned int opcode)
{
FPA11 *fpa11 = GET_FPA11();
unsigned int nRc = 1;
SetRoundingMode(opcode);
SetRoundingPrecision(opcode);
switch (opcode & MASK_ROUNDING_PRECISION)
{
switch (opcode & MASK_ROUNDING_PRECISION) {
case ROUND_SINGLE:
{
fpa11->fType[getFn(opcode)] = typeSingle;
fpa11->fpreg[getFn(opcode)].fSingle =
int32_to_float32(readRegister(getRd(opcode)));
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)));
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)));
fpa11->fpreg[getFn(opcode)].fExtended = int32_to_floatx80(readRegister(getRd(opcode)));
}
break;
#endif
default: nRc = 0;
default:
return 0;
}
return nRc;
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])
{
switch (fpa11->fType[Fn]) {
case typeSingle:
{
writeRegister(getRd(opcode),
float32_to_int32(fpa11->fpreg[Fn].fSingle));
writeRegister(getRd(opcode), float32_to_int32(fpa11->fpreg[Fn].fSingle));
}
break;
case typeDouble:
{
writeRegister(getRd(opcode),
float64_to_int32(fpa11->fpreg[Fn].fDouble));
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));
writeRegister(getRd(opcode), floatx80_to_int32(fpa11->fpreg[Fn].fExtended));
}
break;
#endif
default: nRc = 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;
default:
return 0;
}
writeConditionCodes(flags);
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;
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;
//printk("PerformComparison(0x%08x)\n",opcode);
Fn = getFn(opcode);
Fm = getFm(opcode);
#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])
{
switch (fpa11->fType[Fn]) {
case typeSingle:
//printk("single.\n");
if (float32_is_nan(fpa11->fpreg[Fn].fSingle))
......@@ -224,21 +184,18 @@ static unsigned int PerformComparison(const unsigned int opcode)
rFn = fpa11->fpreg[Fn].fExtended;
break;
default: return 0;
default:
return 0;
}
if (CONSTANT_FM(opcode))
{
if (CONSTANT_FM(opcode)) {
//printk("Fm is a constant: #%d.\n",Fm);
rFm = getExtendedConstant(Fm);
if (floatx80_is_nan(rFm))
goto unordered;
}
else
{
} else {
//printk("Fm = r%d which contains a ",Fm);
switch (fpa11->fType[Fm])
{
switch (fpa11->fType[Fm]) {
case typeSingle:
//printk("single.\n");
if (float32_is_nan(fpa11->fpreg[Fm].fSingle))
......@@ -260,16 +217,136 @@ static unsigned int PerformComparison(const unsigned int opcode)
rFm = fpa11->fpreg[Fm].fExtended;
break;
default: return 0;
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
return PerformComparisonOperation(rFn,rFm);
writeConditionCodes(flags);
return 1;
unordered:
/* ?? The FPA data sheet is pretty vague about this, in particular
......@@ -280,9 +357,11 @@ static unsigned int PerformComparison(const unsigned int opcode)
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;
......
......@@ -42,11 +42,17 @@
#include "fpa11.inl"
/* kernel symbols required for signal handling */
#ifdef CONFIG_FPE_NWFPE_XP
#define NWFPE_BITS "extended"
#else
#define NWFPE_BITS "double"
#endif
#ifdef MODULE
void fp_send_sig(unsigned long sig, struct task_struct *p, int priv);
#if LINUX_VERSION_CODE > 0x20115
MODULE_AUTHOR("Scott Bambrough <scottb@rebel.com>");
MODULE_DESCRIPTION("NWFPE floating point emulator");
MODULE_DESCRIPTION("NWFPE floating point emulator (" NWFPE_BITS " precision)");
#endif
#else
......@@ -70,17 +76,6 @@ static void (*orig_fp_init)(union fp_state *);
/* forward declarations */
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)
{
if (sizeof(FPA11) > sizeof(union fp_state)) {
......@@ -92,25 +87,18 @@ static int __init fpe_init(void)
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;
#else
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");
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;
orig_fp_init = fp_init;
kern_fp_enter = nwfpe_enter;
fp_init = nwfpe_init;
fp_init = nwfpe_init_fpa;
return 0;
}
......@@ -147,7 +135,8 @@ void float_raise(signed char flags)
register unsigned int fpsr, cumulativeTraps;
#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,
__builtin_return_address(0), GET_USERREG()[15]);
#endif
......
......@@ -22,8 +22,8 @@
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
/* 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
......@@ -31,7 +31,8 @@ unsigned int readRegister(const unsigned int nReg)
address calculations. */
unsigned int *userRegisters = GET_USERREG();
unsigned int val = userRegisters[nReg];
if (REG_PC == nReg) val -= 4;
if (REG_PC == nReg)
val -= 4;
return val;
}
......@@ -45,22 +46,22 @@ void writeRegister(const unsigned int nReg, const unsigned int 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
}
......
......@@ -26,16 +26,18 @@
#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 */
......@@ -59,67 +61,6 @@ const float32 float32Constant[] = {
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
index into the table is test code: EQ, NE, ... LT, GT, AL, NV
bit position in short is condition code: NZCV */
......@@ -144,5 +85,5 @@ static const unsigned short aCC[16] = {
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
(c) Rebel.COM, 1998,1999
(c) Philip Blundell, 2001
Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
......@@ -366,11 +367,13 @@ TABLE 5
/* 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];
}
#endif
static inline const float64 getDoubleConstant(const unsigned int nIndex)
{
......@@ -384,7 +387,91 @@ static inline const float32 getSingleConstant(const unsigned int nIndex)
return float32Constant[nIndex];
}
extern unsigned int getRegisterCount(const unsigned int opcode);
extern unsigned int getDestinationSize(const unsigned int opcode);
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;
}
return (nRc);
}
#endif
/*
NetWinder Floating Point Emulator
(c) Rebel.COM, 1998,1999
(c) Philip Blundell, 2001
Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
......@@ -32,224 +33,92 @@ float32 float32_arctan(float32 rFm);
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;
}
#if 0
float32 float32_exp(float32 Fm)
{
//series
return float32_sub(rFm, rFn);
}
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
}
float32 float32_arccos(float32 rFm)
{
//return float32_sub(halfPi,float32_arcsin(rFm));
}
FPA11 *fpa11 = GET_FPA11();
float32 rFm;
unsigned int Fm, opc_mask_shift;
float32 float32_log(float32 rFm)
{
return float32_div(float32_ln(rFm),getSingleConstant(7));
}
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_tan(float32 rFm)
{
return float32_div(float32_sin(rFm),float32_cos(rFm));
}
opc_mask_shift = (opcode & MASK_ARITHMETIC_OPCODE) >> 20;
if (!MONADIC_INSTRUCTION(opcode)) {
unsigned int Fn = getFn(opcode);
float32 rFn;
float32 float32_pow(float32 rFn,float32 rFm)
{
return float32_exp(float32_mul(rFm,float32_ln(rFn)));
}
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;
}
}
float32 float32_pol(float32 rFn,float32 rFm)
{
return float32_arctan(float32_div(rFn,rFm));
return 1;
}
#endif
......@@ -29,8 +29,8 @@ this code that are retained.
*/
#include "fpa11.h"
#include "milieu.h"
#include "softfloat.h"
//#include "milieu.h"
//#include "softfloat.h"
/*
-------------------------------------------------------------------------------
......@@ -142,12 +142,14 @@ INLINE int16 extractFloat32Exp( float32 a )
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 @@ INLINE float32 packFloat32( flag zSign, int16 zExp, bits32 zSig )
{
#if 0
float32 f;
__asm__("@ packFloat32; \n\
mov %0, %1, asl #31; \n\
orr %0, %2, asl #23; \n\
__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 @@ INLINE int16 extractFloat64Exp( float64 a )
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
/*
-------------------------------------------------------------------------------
......
......@@ -40,7 +40,9 @@ floating-point format `floatx80'. If this macro is not defined, the
input or output the `floatx80' type will be defined.
-------------------------------------------------------------------------------
*/
#ifdef CONFIG_FPE_NWFPE_XP
#define FLOATX80
#endif
/*
-------------------------------------------------------------------------------
......@@ -229,4 +231,46 @@ char floatx80_is_signaling_nan( floatx80 );
#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
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