Commit 95a3352a authored by Ralph Siemsen's avatar Ralph Siemsen Committed by Russell King

[NWFPE] Performance improvements [Part 1]

This is the first of a series of patches to NWFPE, which aim to bring
the performance improvements from the netwinder.org CVS tree into the
mainline ARM kernel.

This patch is merely a reformatting of the NWFPE sources.  All files
were processed with "indent -kr -i8 -ts8 -sob -l132 -ss" and a few
manual fixups. Exception: the softfloat files have not been touched.

This patch should be applied after the 5 patches previously published
by RMK on linux-arm-kernel have been applied.
parent 92c6da54
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.
2002-01-19 Russell King <rmk@arm.linux.org.uk>
* fpa11.h - Add documentation
......
......@@ -23,10 +23,9 @@
#include "softfloat.h"
#include "fpopcode.h"
union float64_components
{
float64 f64;
unsigned int i[2];
union float64_components {
float64 f64;
unsigned int i[2];
};
float64 float64_exp(float64 Fm);
......@@ -38,139 +37,125 @@ 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);
static float64 float64_rsf(float64 rFn, float64 rFm)
{
return float64_sub(rFm, rFn);
return float64_sub(rFm, rFn);
}
static float64 float64_rdv(float64 rFn, float64 rFm)
{
return float64_div(rFm, rFn);
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 (*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;
return rFm;
}
static float64 float64_mnf(float64 rFm)
{
union float64_components u;
union float64_components u;
u.f64 = rFm;
u.i[1] ^= 0x80000000;
u.f64 = rFm;
u.i[1] ^= 0x80000000;
return u.f64;
return u.f64;
}
static float64 float64_abs(float64 rFm)
{
union float64_components u;
union float64_components u;
u.f64 = rFm;
u.i[1] &= 0x7fffffff;
u.f64 = rFm;
u.i[1] &= 0x7fffffff;
return u.f64;
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,
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)
unsigned int DoubleCPDO(const unsigned int opcode, FPREG * rFd)
{
FPA11 *fpa11 = GET_FPA11();
float64 rFm;
unsigned int Fm, opc;
//printk("DoubleCPDO(0x%08x)\n",opcode);
Fm = getFm(opcode);
if (CONSTANT_FM(opcode))
{
rFm = getDoubleConstant(Fm);
}
else
{
switch (fpa11->fType[Fm])
{
case typeSingle:
rFm = float32_to_float64(fpa11->fpreg[Fm].fSingle);
break;
case typeDouble:
rFm = fpa11->fpreg[Fm].fDouble;
break;
default: return 0;
}
}
opc = opcode & MASK_ARITHMETIC_OPCODE;
if (!MONADIC_INSTRUCTION(opcode))
{
unsigned int Fn = getFn(opcode);
float64 rFn;
switch (fpa11->fType[Fn])
{
case typeSingle:
rFn = float32_to_float64(fpa11->fpreg[Fn].fSingle);
break;
case typeDouble:
rFn = fpa11->fpreg[Fn].fDouble;
break;
default: return 0;
}
if (dyadic_double[opc >> 20])
{
rFd->fDouble = dyadic_double[opc >> 20](rFn, rFm);
}
else
{
return 0;
}
}
else
{
if (monadic_double[opc >> 20])
{
rFd->fDouble = monadic_double[opc >> 20](rFm);
}
else
{
return 0;
}
}
return 1;
FPA11 *fpa11 = GET_FPA11();
float64 rFm;
unsigned int Fm, opc;
//printk("DoubleCPDO(0x%08x)\n",opcode);
Fm = getFm(opcode);
if (CONSTANT_FM(opcode)) {
rFm = getDoubleConstant(Fm);
} else {
switch (fpa11->fType[Fm]) {
case typeSingle:
rFm = float32_to_float64(fpa11->fpreg[Fm].fSingle);
break;
case typeDouble:
rFm = fpa11->fpreg[Fm].fDouble;
break;
default:
return 0;
}
}
opc = opcode & MASK_ARITHMETIC_OPCODE;
if (!MONADIC_INSTRUCTION(opcode)) {
unsigned int Fn = getFn(opcode);
float64 rFn;
switch (fpa11->fType[Fn]) {
case typeSingle:
rFn = float32_to_float64(fpa11->fpreg[Fn].fSingle);
break;
case typeDouble:
rFn = fpa11->fpreg[Fn].fDouble;
break;
default:
return 0;
}
if (dyadic_double[opc >> 20]) {
rFd->fDouble = dyadic_double[opc >> 20](rFn, rFm);
} else {
return 0;
}
} else {
if (monadic_double[opc >> 20]) {
rFd->fDouble = monadic_double[opc >> 20](rFm);
} else {
return 0;
}
}
return 1;
}
......@@ -32,139 +32,125 @@ 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);
static floatx80 floatx80_rsf(floatx80 rFn, floatx80 rFm)
{
return floatx80_sub(rFm, rFn);
return floatx80_sub(rFm, rFn);
}
static floatx80 floatx80_rdv(floatx80 rFn, floatx80 rFm)
{
return floatx80_div(rFm, rFn);
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 (*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;
return rFm;
}
static floatx80 floatx80_mnf(floatx80 rFm)
{
rFm.high ^= 0x8000;
return rFm;
rFm.high ^= 0x8000;
return rFm;
}
static floatx80 floatx80_abs(floatx80 rFm)
{
rFm.high &= 0x7fff;
return rFm;
rFm.high &= 0x7fff;
return rFm;
}
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,
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)
unsigned int ExtendedCPDO(const unsigned int opcode, FPREG * rFd)
{
FPA11 *fpa11 = GET_FPA11();
floatx80 rFm;
unsigned int Fm, opc;
//printk("ExtendedCPDO(0x%08x)\n",opcode);
Fm = getFm(opcode);
if (CONSTANT_FM(opcode))
{
rFm = getExtendedConstant(Fm);
}
else
{
switch (fpa11->fType[Fm])
{
case typeSingle:
rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle);
break;
case typeDouble:
rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble);
break;
case typeExtended:
rFm = fpa11->fpreg[Fm].fExtended;
break;
default: return 0;
}
}
opc = opcode & MASK_ARITHMETIC_OPCODE;
if (!MONADIC_INSTRUCTION(opcode))
{
unsigned int Fn = getFn(opcode);
floatx80 rFn;
switch (fpa11->fType[Fn])
{
case typeSingle:
rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle);
break;
case typeDouble:
rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble);
break;
case typeExtended:
rFn = fpa11->fpreg[Fn].fExtended;
break;
default: return 0;
}
if (dyadic_extended[opc >> 20])
{
rFd->fExtended = dyadic_extended[opc >> 20](rFn, rFm);
}
else
{
return 0;
}
}
else
{
if (monadic_extended[opc >> 20])
{
rFd->fExtended = monadic_extended[opc >> 20](rFm);
}
else
{
return 0;
}
}
return 1;
FPA11 *fpa11 = GET_FPA11();
floatx80 rFm;
unsigned int Fm, opc;
//printk("ExtendedCPDO(0x%08x)\n",opcode);
Fm = getFm(opcode);
if (CONSTANT_FM(opcode)) {
rFm = getExtendedConstant(Fm);
} else {
switch (fpa11->fType[Fm]) {
case typeSingle:
rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle);
break;
case typeDouble:
rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble);
break;
case typeExtended:
rFm = fpa11->fpreg[Fm].fExtended;
break;
default:
return 0;
}
}
opc = opcode & MASK_ARITHMETIC_OPCODE;
if (!MONADIC_INSTRUCTION(opcode)) {
unsigned int Fn = getFn(opcode);
floatx80 rFn;
switch (fpa11->fType[Fn]) {
case typeSingle:
rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle);
break;
case typeDouble:
rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble);
break;
case typeExtended:
rFn = fpa11->fpreg[Fn].fExtended;
break;
default:
return 0;
}
if (dyadic_extended[opc >> 20]) {
rFd->fExtended = dyadic_extended[opc >> 20](rFn, rFm);
} else {
return 0;
}
} else {
if (monadic_extended[opc >> 20]) {
rFd->fExtended = monadic_extended[opc >> 20](rFm);
} else {
return 0;
}
}
return 1;
}
......@@ -37,184 +37,177 @@ unsigned int EmulateCPRT(const unsigned int);
/* Reset the FPA11 chip. Called to initialize and reset the emulator. */
static void resetFPA11(void)
{
int i;
FPA11 *fpa11 = GET_FPA11();
/* initialize the register type array */
for (i=0;i<=7;i++)
{
fpa11->fType[i] = typeNone;
}
/* FPSR: set system id to FP_EMULATOR, set AC, clear all other bits */
fpa11->fpsr = FP_EMULATOR | BIT_AC;
/* FPCR: set SB, AB and DA bits, clear all others */
int i;
FPA11 *fpa11 = GET_FPA11();
/* initialize the register type array */
for (i = 0; i <= 7; i++) {
fpa11->fType[i] = typeNone;
}
/* FPSR: set system id to FP_EMULATOR, set AC, clear all other bits */
fpa11->fpsr = FP_EMULATOR | BIT_AC;
/* FPCR: set SB, AB and DA bits, clear all others */
#if MAINTAIN_FPCR
fpa11->fpcr = MASK_RESET;
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)
{
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;
}
FPA11 *fpa11 = GET_FPA11();
fpa11->fpcr &= ~MASK_ROUNDING_MODE;
#endif
switch (opcode & MASK_ROUNDING_MODE) {
default:
case ROUND_TO_NEAREST:
float_rounding_mode = float_round_nearest_even;
#if MAINTAIN_FPCR
fpa11->fpcr |= ROUND_TO_NEAREST;
#endif
break;
case ROUND_TO_PLUS_INFINITY:
float_rounding_mode = float_round_up;
#if MAINTAIN_FPCR
fpa11->fpcr |= ROUND_TO_PLUS_INFINITY;
#endif
break;
case ROUND_TO_MINUS_INFINITY:
float_rounding_mode = float_round_down;
#if MAINTAIN_FPCR
fpa11->fpcr |= ROUND_TO_MINUS_INFINITY;
#endif
break;
case ROUND_TO_ZERO:
float_rounding_mode = float_round_to_zero;
#if MAINTAIN_FPCR
fpa11->fpcr |= ROUND_TO_ZERO;
#endif
break;
}
}
void SetRoundingPrecision(const unsigned int opcode)
{
#if MAINTAIN_FPCR
FPA11 *fpa11 = GET_FPA11();
fpa11->fpcr &= ~MASK_ROUNDING_PRECISION;
#endif
switch (opcode & MASK_ROUNDING_PRECISION)
{
case ROUND_SINGLE:
floatx80_rounding_precision = 32;
#if MAINTAIN_FPCR
fpa11->fpcr |= ROUND_SINGLE;
#endif
break;
case ROUND_DOUBLE:
floatx80_rounding_precision = 64;
#if MAINTAIN_FPCR
fpa11->fpcr |= ROUND_DOUBLE;
#endif
break;
case ROUND_EXTENDED:
floatx80_rounding_precision = 80;
#if MAINTAIN_FPCR
fpa11->fpcr |= ROUND_EXTENDED;
#endif
break;
default: floatx80_rounding_precision = 80;
}
FPA11 *fpa11 = GET_FPA11();
fpa11->fpcr &= ~MASK_ROUNDING_PRECISION;
#endif
switch (opcode & MASK_ROUNDING_PRECISION) {
case ROUND_SINGLE:
floatx80_rounding_precision = 32;
#if MAINTAIN_FPCR
fpa11->fpcr |= ROUND_SINGLE;
#endif
break;
case ROUND_DOUBLE:
floatx80_rounding_precision = 64;
#if MAINTAIN_FPCR
fpa11->fpcr |= ROUND_DOUBLE;
#endif
break;
case ROUND_EXTENDED:
floatx80_rounding_precision = 80;
#if MAINTAIN_FPCR
fpa11->fpcr |= ROUND_EXTENDED;
#endif
break;
default:
floatx80_rounding_precision = 80;
}
}
void nwfpe_init(union fp_state *fp)
{
FPA11 *fpa11 = (FPA11 *)fp;
memset(fpa11, 0, sizeof(FPA11));
resetFPA11();
SetRoundingMode(ROUND_TO_NEAREST);
SetRoundingPrecision(ROUND_EXTENDED);
fpa11->initflag = 1;
FPA11 *fpa11 = (FPA11 *)fp;
memset(fpa11, 0, sizeof(FPA11));
resetFPA11();
SetRoundingMode(ROUND_TO_NEAREST);
SetRoundingPrecision(ROUND_EXTENDED);
fpa11->initflag = 1;
}
/* Emulate the instruction in the opcode. */
unsigned int EmulateAll(unsigned int opcode)
{
unsigned int nRc = 1, code;
code = opcode & 0x00000f00;
if (code == 0x00000100 || code == 0x00000200)
{
/* For coprocessor 1 or 2 (FPA11) */
code = opcode & 0x0e000000;
if (code == 0x0e000000)
{
if (opcode & 0x00000010)
{
/* Emulate conversion opcodes. */
/* Emulate register transfer opcodes. */
/* Emulate comparison opcodes. */
nRc = EmulateCPRT(opcode);
}
else
{
/* Emulate monadic arithmetic opcodes. */
/* Emulate dyadic arithmetic opcodes. */
nRc = EmulateCPDO(opcode);
}
}
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);
unsigned int nRc = 1, code;
code = opcode & 0x00000f00;
if (code == 0x00000100 || code == 0x00000200) {
/* For coprocessor 1 or 2 (FPA11) */
code = opcode & 0x0e000000;
if (code == 0x0e000000) {
if (opcode & 0x00000010) {
/* Emulate conversion opcodes. */
/* Emulate register transfer opcodes. */
/* Emulate comparison opcodes. */
nRc = EmulateCPRT(opcode);
} else {
/* Emulate monadic arithmetic opcodes. */
/* Emulate dyadic arithmetic opcodes. */
nRc = EmulateCPDO(opcode);
}
} 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;
}
}
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;
}
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;
}
}
#endif
......@@ -48,9 +48,9 @@ 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;
floatx80 fExtended;
float64 fDouble;
float32 fSingle;
} FPREG;
/*
......@@ -67,17 +67,17 @@ typedef union tagFPREG {
* not initialise.
*/
typedef struct tagFPA11 {
/* 0 */ FPREG fpreg[8]; /* 8 floating point registers */
/* 96 */ FPSR fpsr; /* floating point status register */
/* 100 */ FPCR fpcr; /* floating point control register */
/* 104 */ unsigned char fType[8]; /* type of floating point value held in
floating point registers. One of none
single, double or extended. */
/* 112 */ int initflag; /* this is special. The kernel guarantees
to set it to 0 when a thread is launched,
so we can use it to detect whether this
instance of the emulator needs to be
initialised. */
/* 0 */ FPREG fpreg[8]; /* 8 floating point registers */
/* 96 */ FPSR fpsr; /* floating point status register */
/* 100 */ FPCR fpcr; /* floating point control register */
/* 104 */ unsigned char fType[8]; /* type of floating point value held in
floating point registers. One of
none, single, double or extended. */
/* 112 */ int initflag; /* this is special. The kernel guarantees
to set it to 0 when a thread is launched,
so we can use it to detect whether this
instance of the emulator needs to be
initialised. */
} FPA11;
extern void SetRoundingMode(const unsigned int);
......
......@@ -24,28 +24,28 @@
/* Read and write floating point status register */
extern __inline__ unsigned int readFPSR(void)
{
FPA11 *fpa11 = GET_FPA11();
return(fpa11->fpsr);
FPA11 *fpa11 = GET_FPA11();
return (fpa11->fpsr);
}
extern __inline__ void writeFPSR(FPSR reg)
{
FPA11 *fpa11 = GET_FPA11();
/* the sysid byte in the status register is readonly */
fpa11->fpsr = (fpa11->fpsr & MASK_SYSID) | (reg & ~MASK_SYSID);
FPA11 *fpa11 = GET_FPA11();
/* the sysid byte in the status register is readonly */
fpa11->fpsr = (fpa11->fpsr & MASK_SYSID) | (reg & ~MASK_SYSID);
}
/* Read and write floating point control register */
extern __inline__ FPCR readFPCR(void)
{
FPA11 *fpa11 = GET_FPA11();
/* clear SB, AB and DA bits before returning FPCR */
return(fpa11->fpcr & ~MASK_RFC);
FPA11 *fpa11 = GET_FPA11();
/* clear SB, AB and DA bits before returning FPCR */
return (fpa11->fpcr & ~MASK_RFC);
}
extern __inline__ void writeFPCR(FPCR reg)
{
FPA11 *fpa11 = GET_FPA11();
fpa11->fpcr &= ~MASK_WFC; /* clear SB, AB and DA bits */
fpa11->fpcr |= (reg & MASK_WFC); /* write SB, AB and DA bits */
FPA11 *fpa11 = GET_FPA11();
fpa11->fpcr &= ~MASK_WFC; /* clear SB, AB and DA bits */
fpa11->fpcr |= (reg & MASK_WFC); /* write SB, AB and DA bits */
}
......@@ -22,98 +22,100 @@
#include "fpa11.h"
#include "fpopcode.h"
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 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();
FPREG *rFd;
unsigned int nType, nDest, nRc;
//printk("EmulateCPDO(0x%08x)\n",opcode);
/* Get the destination size. If not valid let Linux perform
an invalid instruction trap. */
nDest = getDestinationSize(opcode);
if (typeNone == nDest) return 0;
SetRoundingMode(opcode);
/* Compare the size of the operands in Fn and Fm.
Choose the largest size and perform operations in that size,
in order to make use of all the precision of the operands.
If Fm is a constant, we just grab a constant of a size
matching the size of the operand in Fn. */
if (MONADIC_INSTRUCTION(opcode))
nType = nDest;
else
nType = fpa11->fType[getFn(opcode)];
if (!CONSTANT_FM(opcode))
{
register unsigned int Fm = getFm(opcode);
if (nType < fpa11->fType[Fm])
{
nType = fpa11->fType[Fm];
}
}
rFd = &fpa11->fpreg[getFd(opcode)];
switch (nType)
{
case typeSingle : nRc = SingleCPDO(opcode, rFd); break;
case typeDouble : nRc = DoubleCPDO(opcode, rFd); break;
case typeExtended : nRc = ExtendedCPDO(opcode, rFd); break;
default : nRc = 0;
}
/* The CPDO functions used to always set the destination type
to be the same as their working size. */
if (nRc != 0)
{
/* If the operation succeeded, check to see if the result in the
destination register is the correct size. If not force it
to be. */
fpa11->fType[getFd(opcode)] = nDest;
if (nDest != nType)
{
switch (nDest)
{
case typeSingle:
{
if (typeDouble == nType)
rFd->fSingle = float64_to_float32(rFd->fDouble);
else
rFd->fSingle = floatx80_to_float32(rFd->fExtended);
}
break;
case typeDouble:
{
if (typeSingle == nType)
rFd->fDouble = float32_to_float64(rFd->fSingle);
else
rFd->fDouble = floatx80_to_float64(rFd->fExtended);
}
break;
case typeExtended:
{
if (typeSingle == nType)
rFd->fExtended = float32_to_floatx80(rFd->fSingle);
else
rFd->fExtended = float64_to_floatx80(rFd->fDouble);
}
break;
}
}
}
return nRc;
FPA11 *fpa11 = GET_FPA11();
FPREG *rFd;
unsigned int nType, nDest, nRc;
//printk("EmulateCPDO(0x%08x)\n",opcode);
/* Get the destination size. If not valid let Linux perform
an invalid instruction trap. */
nDest = getDestinationSize(opcode);
if (typeNone == nDest)
return 0;
SetRoundingMode(opcode);
/* Compare the size of the operands in Fn and Fm.
Choose the largest size and perform operations in that size,
in order to make use of all the precision of the operands.
If Fm is a constant, we just grab a constant of a size
matching the size of the operand in Fn. */
if (MONADIC_INSTRUCTION(opcode))
nType = nDest;
else
nType = fpa11->fType[getFn(opcode)];
if (!CONSTANT_FM(opcode)) {
register unsigned int Fm = getFm(opcode);
if (nType < fpa11->fType[Fm]) {
nType = fpa11->fType[Fm];
}
}
rFd = &fpa11->fpreg[getFd(opcode)];
switch (nType) {
case typeSingle:
nRc = SingleCPDO(opcode, rFd);
break;
case typeDouble:
nRc = DoubleCPDO(opcode, rFd);
break;
case typeExtended:
nRc = ExtendedCPDO(opcode, rFd);
break;
default:
nRc = 0;
}
/* The CPDO functions used to always set the destination type
to be the same as their working size. */
if (nRc != 0) {
/* If the operation succeeded, check to see if the result in the
destination register is the correct size. If not force it
to be. */
fpa11->fType[getFd(opcode)] = nDest;
if (nDest != nType) {
switch (nDest) {
case typeSingle:
{
if (typeDouble == nType)
rFd->fSingle = float64_to_float32(rFd->fDouble);
else
rFd->fSingle = floatx80_to_float32(rFd->fExtended);
}
break;
case typeDouble:
{
if (typeSingle == nType)
rFd->fDouble = float32_to_float64(rFd->fSingle);
else
rFd->fDouble = floatx80_to_float64(rFd->fExtended);
}
break;
case typeExtended:
{
if (typeSingle == nType)
rFd->fExtended = float32_to_floatx80(rFd->fSingle);
else
rFd->fExtended = float64_to_floatx80(rFd->fDouble);
}
break;
}
}
}
return nRc;
}
This diff is collapsed.
This diff is collapsed.
......@@ -63,63 +63,45 @@ void fp_setup(void);
extern void (*kern_fp_enter)(void);
extern void (*fp_init)(union fp_state *);
/* Original value of fp_enter from kernel before patched by fpe_init. */
/* Original value of fp_enter from kernel before patched by fpe_init. */
static void (*orig_fp_enter)(void);
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)) {
printk(KERN_ERR "nwfpe: bad structure size\n");
return -EINVAL;
}
if (sizeof(FPREG) != 12) {
printk(KERN_ERR "nwfpe: bad register size\n");
return -EINVAL;
}
#ifdef MODULE
if (!mod_member_present(&__this_module, can_unload))
return -EINVAL;
__this_module.can_unload = fpe_unload;
#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");
/* 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;
return 0;
if (sizeof(FPA11) > sizeof(union fp_state)) {
printk(KERN_ERR "nwfpe: bad structure size\n");
return -EINVAL;
}
if (sizeof(FPREG) != 12) {
printk(KERN_ERR "nwfpe: bad register size\n");
return -EINVAL;
}
if (fpe_type[0] && strcmp(fpe_type, "nwfpe"))
return 0;
/* Display title, version and copyright information. */
printk(KERN_WARNING "NetWinder Floating Point Emulator V0.95 "
"(c) 1998-1999 Rebel.com\n");
/* Save pointer to the old FP handler and then patch ourselves in */
orig_fp_enter = kern_fp_enter;
orig_fp_init = fp_init;
kern_fp_enter = nwfpe_enter;
fp_init = nwfpe_init;
return 0;
}
static void __exit fpe_exit(void)
{
/* Restore the values we saved earlier. */
kern_fp_enter = orig_fp_enter;
fp_init = orig_fp_init;
/* Restore the values we saved earlier. */
kern_fp_enter = orig_fp_enter;
fp_init = orig_fp_init;
}
/*
......@@ -144,41 +126,42 @@ cumulative exceptions flag byte are set and we return.
void float_raise(signed char flags)
{
register unsigned int fpsr, cumulativeTraps;
register unsigned int fpsr, cumulativeTraps;
#ifdef CONFIG_DEBUG_USER
printk(KERN_DEBUG "NWFPE: %s[%d] takes exception %08x at %p from %08x\n",
current->comm, current->pid, flags,
__builtin_return_address(0), GET_USERREG()[15]);
printk(KERN_DEBUG
"NWFPE: %s[%d] takes exception %08x at %p from %08x\n",
current->comm, current->pid, flags,
__builtin_return_address(0), GET_USERREG()[15]);
#endif
/* Keep SoftFloat exception flags up to date. */
float_exception_flags |= flags;
/* Read fpsr and initialize the cumulativeTraps. */
fpsr = readFPSR();
cumulativeTraps = 0;
/* For each type of exception, the cumulative trap exception bit is only
set if the corresponding trap enable bit is not set. */
if ((!(fpsr & BIT_IXE)) && (flags & BIT_IXC))
cumulativeTraps |= BIT_IXC;
if ((!(fpsr & BIT_UFE)) && (flags & BIT_UFC))
cumulativeTraps |= BIT_UFC;
if ((!(fpsr & BIT_OFE)) && (flags & BIT_OFC))
cumulativeTraps |= BIT_OFC;
if ((!(fpsr & BIT_DZE)) && (flags & BIT_DZC))
cumulativeTraps |= BIT_DZC;
if ((!(fpsr & BIT_IOE)) && (flags & BIT_IOC))
cumulativeTraps |= BIT_IOC;
/* Set the cumulative exceptions flags. */
if (cumulativeTraps)
writeFPSR(fpsr | cumulativeTraps);
/* Raise an exception if necessary. */
if (fpsr & (flags << 16))
fp_send_sig(SIGFPE, current, 1);
/* Keep SoftFloat exception flags up to date. */
float_exception_flags |= flags;
/* Read fpsr and initialize the cumulativeTraps. */
fpsr = readFPSR();
cumulativeTraps = 0;
/* For each type of exception, the cumulative trap exception bit is only
set if the corresponding trap enable bit is not set. */
if ((!(fpsr & BIT_IXE)) && (flags & BIT_IXC))
cumulativeTraps |= BIT_IXC;
if ((!(fpsr & BIT_UFE)) && (flags & BIT_UFC))
cumulativeTraps |= BIT_UFC;
if ((!(fpsr & BIT_OFE)) && (flags & BIT_OFC))
cumulativeTraps |= BIT_OFC;
if ((!(fpsr & BIT_DZE)) && (flags & BIT_DZC))
cumulativeTraps |= BIT_DZC;
if ((!(fpsr & BIT_IOE)) && (flags & BIT_IOC))
cumulativeTraps |= BIT_IOC;
/* Set the cumulative exceptions flags. */
if (cumulativeTraps)
writeFPSR(fpsr | cumulativeTraps);
/* Raise an exception if necessary. */
if (fpsr & (flags << 16))
fp_send_sig(SIGFPE, current, 1);
}
module_init(fpe_init);
......
......@@ -22,63 +22,64 @@
extern __inline__
unsigned int readRegister(const unsigned int nReg)
{
/* Note: The CPU thinks it has dealt with the current instruction. As
a result the program counter has been advanced to the next
instruction, and points 4 bytes beyond the actual instruction
that caused the invalid instruction trap to occur. We adjust
for this in this routine. LDF/STF instructions with Rn = PC
depend on the PC being correct, as they use PC+8 in their
address calculations. */
unsigned int *userRegisters = GET_USERREG();
unsigned int val = userRegisters[nReg];
if (REG_PC == nReg) val -= 4;
return val;
/* Note: The CPU thinks it has dealt with the current instruction.
As a result the program counter has been advanced to the next
instruction, and points 4 bytes beyond the actual instruction
that caused the invalid instruction trap to occur. We adjust
for this in this routine. LDF/STF instructions with Rn = PC
depend on the PC being correct, as they use PC+8 in their
address calculations. */
unsigned int *userRegisters = GET_USERREG();
unsigned int val = userRegisters[nReg];
if (REG_PC == nReg)
val -= 4;
return val;
}
extern __inline__
void writeRegister(const unsigned int nReg, const unsigned int val)
{
unsigned int *userRegisters = GET_USERREG();
userRegisters[nReg] = val;
unsigned int *userRegisters = GET_USERREG();
userRegisters[nReg] = val;
}
extern __inline__
unsigned int readCPSR(void)
{
return(readRegister(REG_CPSR));
return (readRegister(REG_CPSR));
}
extern __inline__
void writeCPSR(const unsigned int val)
{
writeRegister(REG_CPSR,val);
writeRegister(REG_CPSR, val);
}
extern __inline__
unsigned int readConditionCodes(void)
{
#ifdef __FPEM_TEST__
return(0);
return (0);
#else
return(readCPSR() & CC_MASK);
return (readCPSR() & CC_MASK);
#endif
}
extern __inline__
void writeConditionCodes(const unsigned int val)
{
unsigned int *userRegisters = GET_USERREG();
unsigned int rval;
/*
* Operate directly on userRegisters since
* the CPSR may be the PC register itself.
*/
rval = userRegisters[REG_CPSR] & ~CC_MASK;
userRegisters[REG_CPSR] = rval | (val & CC_MASK);
unsigned int *userRegisters = GET_USERREG();
unsigned int rval;
/*
* Operate directly on userRegisters since
* the CPSR may be the PC register itself.
*/
rval = userRegisters[REG_CPSR] & ~CC_MASK;
userRegisters[REG_CPSR] = rval | (val & CC_MASK);
}
extern __inline__
unsigned int readMemoryInt(unsigned int *pMem)
{
return *pMem;
return *pMem;
}
......@@ -27,122 +27,148 @@
#include "fpmodule.inl"
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 */
};
const float64 float64Constant[] = {
0x0000000000000000ULL, /* double 0.0 */
0x3ff0000000000000ULL, /* double 1.0 */
0x4000000000000000ULL, /* double 2.0 */
0x4008000000000000ULL, /* double 3.0 */
0x4010000000000000ULL, /* double 4.0 */
0x4014000000000000ULL, /* double 5.0 */
0x3fe0000000000000ULL, /* double 0.5 */
0x4024000000000000ULL /* double 10.0 */
};
0x0000000000000000ULL, /* double 0.0 */
0x3ff0000000000000ULL, /* double 1.0 */
0x4000000000000000ULL, /* double 2.0 */
0x4008000000000000ULL, /* double 3.0 */
0x4010000000000000ULL, /* double 4.0 */
0x4014000000000000ULL, /* double 5.0 */
0x3fe0000000000000ULL, /* double 0.5 */
0x4024000000000000ULL /* double 10.0 */
};
const float32 float32Constant[] = {
0x00000000, /* single 0.0 */
0x3f800000, /* single 1.0 */
0x40000000, /* single 2.0 */
0x40400000, /* single 3.0 */
0x40800000, /* single 4.0 */
0x40a00000, /* single 5.0 */
0x3f000000, /* single 0.5 */
0x41200000 /* single 10.0 */
};
0x00000000, /* single 0.0 */
0x3f800000, /* single 1.0 */
0x40000000, /* single 2.0 */
0x40400000, /* single 3.0 */
0x40800000, /* single 4.0 */
0x40a00000, /* single 5.0 */
0x3f000000, /* single 0.5 */
0x41200000 /* single 10.0 */
};
unsigned int getTransferLength(const unsigned int opcode)
{
unsigned int nRc;
switch (opcode & MASK_TRANSFER_LENGTH)
{
case 0x00000000: nRc = 1; break; /* single precision */
case 0x00008000: nRc = 2; break; /* double precision */
case 0x00400000: nRc = 3; break; /* extended precision */
default: nRc = 0;
}
return(nRc);
unsigned int 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 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 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);
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 */
static const unsigned short aCC[16] = {
0xF0F0, // EQ == Z set
0x0F0F, // NE
0xCCCC, // CS == C set
0x3333, // CC
0xFF00, // MI == N set
0x00FF, // PL
0xAAAA, // VS == V set
0x5555, // VC
0x0C0C, // HI == C set && Z clear
0xF3F3, // LS == C clear || Z set
0xAA55, // GE == (N==V)
0x55AA, // LT == (N!=V)
0x0A05, // GT == (!Z && (N==V))
0xF5FA, // LE == (Z || (N!=V))
0xFFFF, // AL always
0 // NV
0xF0F0, // EQ == Z set
0x0F0F, // NE
0xCCCC, // CS == C set
0x3333, // CC
0xFF00, // MI == N set
0x00FF, // PL
0xAAAA, // VS == V set
0x5555, // VC
0x0C0C, // HI == C set && Z clear
0xF3F3, // LS == C clear || Z set
0xAA55, // GE == (N==V)
0x55AA, // LT == (N!=V)
0x0A05, // GT == (!Z && (N==V))
0xF5FA, // LE == (Z || (N!=V))
0xFFFF, // AL always
0 // NV
};
unsigned int checkCondition(const unsigned int opcode, const unsigned int ccodes)
{
return (aCC[opcode>>28] >> (ccodes>>28)) & 1;
return (aCC[opcode >> 28] >> (ccodes >> 28)) & 1;
}
......@@ -186,7 +186,7 @@ TABLE 5
#define BIT_LOAD 0x00100000
/* masks for load/store */
#define MASK_CPDT 0x0c000000 /* data processing opcode */
#define MASK_CPDT 0x0c000000 /* data processing opcode */
#define MASK_OFFSET 0x000000ff
#define MASK_TRANSFER_LENGTH 0x00408000
#define MASK_REGISTER_COUNT MASK_TRANSFER_LENGTH
......@@ -236,7 +236,7 @@ TABLE 5
#define MONADIC_INSTRUCTION(opcode) ((opcode & BIT_MONADIC) != 0)
/* instruction identification masks */
#define MASK_CPDO 0x0e000000 /* arithmetic opcode */
#define MASK_CPDO 0x0e000000 /* arithmetic opcode */
#define MASK_ARITHMETIC_OPCODE 0x00f08000
#define MASK_DESTINATION_SIZE 0x00080080
......@@ -282,7 +282,7 @@ TABLE 5
===
*/
#define MASK_CPRT 0x0e000010 /* register transfer opcode */
#define MASK_CPRT 0x0e000010 /* register transfer opcode */
#define MASK_CPRT_CODE 0x00f00000
#define FLT_CODE 0x00000000
#define FIX_CODE 0x00100000
......@@ -368,21 +368,21 @@ TABLE 5
static inline const floatx80 getExtendedConstant(const unsigned int nIndex)
{
extern const floatx80 floatx80Constant[];
return floatx80Constant[nIndex];
}
extern const floatx80 floatx80Constant[];
return floatx80Constant[nIndex];
}
static inline const float64 getDoubleConstant(const unsigned int nIndex)
{
extern const float64 float64Constant[];
return float64Constant[nIndex];
}
extern const float64 float64Constant[];
return float64Constant[nIndex];
}
static inline const float32 getSingleConstant(const unsigned int nIndex)
{
extern const float32 float32Constant[];
return float32Constant[nIndex];
}
extern const float32 float32Constant[];
return float32Constant[nIndex];
}
extern unsigned int getRegisterCount(const unsigned int opcode);
extern unsigned int getDestinationSize(const unsigned int opcode);
......
......@@ -38,12 +38,12 @@ The FPCR is a 32 bit register consisting of bit flags.
------------
Note: the system id byte is read only */
typedef unsigned int FPSR; /* type for floating point status register */
typedef unsigned int FPCR; /* type for floating point control register */
typedef unsigned int FPSR; /* type for floating point status register */
typedef unsigned int FPCR; /* type for floating point control register */
#define MASK_SYSID 0xff000000
#define BIT_HARDWARE 0x80000000
#define FP_EMULATOR 0x01000000 /* System ID for emulator */
#define FP_EMULATOR 0x01000000 /* System ID for emulator */
#define FP_ACCELERATOR 0x81000000 /* System ID for FPA11 */
/* EXCEPTION TRAP ENABLE BYTE
......@@ -51,11 +51,11 @@ typedef unsigned int FPCR; /* type for floating point control register */
#define MASK_TRAP_ENABLE 0x00ff0000
#define MASK_TRAP_ENABLE_STRICT 0x001f0000
#define BIT_IXE 0x00100000 /* inexact exception enable */
#define BIT_UFE 0x00080000 /* underflow exception enable */
#define BIT_OFE 0x00040000 /* overflow exception enable */
#define BIT_DZE 0x00020000 /* divide by zero exception enable */
#define BIT_IOE 0x00010000 /* invalid operation exception enable */
#define BIT_IXE 0x00100000 /* inexact exception enable */
#define BIT_UFE 0x00080000 /* underflow exception enable */
#define BIT_OFE 0x00040000 /* overflow exception enable */
#define BIT_DZE 0x00020000 /* divide by zero exception enable */
#define BIT_IOE 0x00010000 /* invalid operation exception enable */
/* SYSTEM CONTROL BYTE
---------------------- */
......
......@@ -32,107 +32,91 @@ 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);
static float32 float32_rsf(float32 rFn, float32 rFm)
{
return float32_sub(rFm, rFn);
return float32_sub(rFm, rFn);
}
static float32 float32_rdv(float32 rFn, float32 rFm)
{
return float32_div(rFm, rFn);
return float32_div(rFm, rFn);
}
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 (*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)
{
return rFm;
return rFm;
}
static float32 float32_mnf(float32 rFm)
{
return rFm ^ 0x80000000;
return rFm ^ 0x80000000;
}
static float32 float32_abs(float32 rFm)
{
return rFm & 0x7fffffff;
return rFm & 0x7fffffff;
}
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,
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)
unsigned int SingleCPDO(const unsigned int opcode, FPREG * rFd)
{
FPA11 *fpa11 = GET_FPA11();
float32 rFm;
unsigned int Fm, opc;
Fm = getFm(opcode);
if (CONSTANT_FM(opcode))
{
rFm = getSingleConstant(Fm);
}
else if (fpa11->fType[Fm] == typeSingle)
{
rFm = fpa11->fpreg[Fm].fSingle;
}
else
{
return 0;
}
opc = opcode & MASK_ARITHMETIC_OPCODE;
if (!MONADIC_INSTRUCTION(opcode))
{
unsigned int Fn = getFn(opcode);
float32 rFn;
if (fpa11->fType[Fn] == typeSingle &&
dyadic_single[opc >> 20])
{
rFn = fpa11->fpreg[Fn].fSingle;
rFd->fSingle = dyadic_single[opc >> 20](rFn, rFm);
}
else
{
return 0;
}
}
else
{
if (monadic_single[opc >> 20])
{
rFd->fSingle = monadic_single[opc >> 20](rFm);
}
else
{
return 0;
}
}
return 1;
FPA11 *fpa11 = GET_FPA11();
float32 rFm;
unsigned int Fm, opc;
Fm = getFm(opcode);
if (CONSTANT_FM(opcode)) {
rFm = getSingleConstant(Fm);
} else if (fpa11->fType[Fm] == typeSingle) {
rFm = fpa11->fpreg[Fm].fSingle;
} else {
return 0;
}
opc = opcode & MASK_ARITHMETIC_OPCODE;
if (!MONADIC_INSTRUCTION(opcode)) {
unsigned int Fn = getFn(opcode);
float32 rFn;
if (fpa11->fType[Fn] == typeSingle && dyadic_single[opc >> 20]) {
rFn = fpa11->fpreg[Fn].fSingle;
rFd->fSingle = dyadic_single[opc >> 20](rFn, rFm);
} else {
return 0;
}
} else {
if (monadic_single[opc >> 20]) {
rFd->fSingle = monadic_single[opc >> 20](rFm);
} else {
return 0;
}
}
return 1;
}
......@@ -184,9 +184,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)
......
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