Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/arch/powerpc/fpu stfs{,x}{,u}: Switch to conversion algo...
details: https://anonhg.NetBSD.org/src/rev/e4b1600ff732
branches: trunk
changeset: 370171:e4b1600ff732
user: rin <rin%NetBSD.org@localhost>
date: Tue Sep 20 12:12:42 2022 +0000
description:
stfs{,x}{,u}: Switch to conversion algorithm specified by Power ISA.
The ISA specifies algorithm for most bit patterns in double format, that
are not representable in float. I believe that sane people do not rely on
such a specification detail, but *REAL* programmers may utilize it ;)
Instead of complicating fpu_explode(), single-purpose helper function,
fpu_to_single(), is introduced. See comment therein for more details.
diffstat:
sys/arch/powerpc/fpu/fpu_emu.c | 84 ++++++++++++++++++++++++++++++++++-------
1 files changed, 69 insertions(+), 15 deletions(-)
diffs (121 lines):
diff -r 137b6f7daf59 -r e4b1600ff732 sys/arch/powerpc/fpu/fpu_emu.c
--- a/sys/arch/powerpc/fpu/fpu_emu.c Tue Sep 20 10:12:18 2022 +0000
+++ b/sys/arch/powerpc/fpu/fpu_emu.c Tue Sep 20 12:12:42 2022 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: fpu_emu.c,v 1.58 2022/09/15 14:25:28 rin Exp $ */
+/* $NetBSD: fpu_emu.c,v 1.59 2022/09/20 12:12:42 rin Exp $ */
/*
* Copyright 2001 Wasabi Systems, Inc.
@@ -76,7 +76,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: fpu_emu.c,v 1.58 2022/09/15 14:25:28 rin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: fpu_emu.c,v 1.59 2022/09/20 12:12:42 rin Exp $");
#ifdef _KERNEL_OPT
#include "opt_ddb.h"
@@ -283,6 +283,56 @@
}
/*
+ * fpu_to_single(): Helper function for stfs{,u}{,x}.
+ *
+ * Single-precision (float) data is internally represented in
+ * double-precision (double) format in floating-point registers (FRs).
+ * Even though double value cannot be translated into float format in
+ * general, Power ISA (2.0.3--3.1) specify conversion algorithm when
+ * stored to memory (see Sec. 4.6.3):
+ *
+ * - Extra fraction bits are truncated regardless of rounding mode.
+ * - When magnitude is larger than the maximum number in float format,
+ * bits 63--62 and 58--29 are mechanically copied into bits 31--0.
+ * - When magnitude is representable as denormalized number in float
+ * format, it is stored as normalized double value in FRs;
+ * denormalization is required in this case.
+ * - When magnitude is smaller than the minimum denormalized number in
+ * float format, the result is undefined. For G5 (790MP Rev 1.1),
+ * (sign | 0) seems to be stored. For G4 and prior, some ``random''
+ * garbage is stored in exponent. We mimic G5 for now.
+ */
+static uint32_t
+fpu_to_single(uint64_t reg)
+{
+ uint32_t sign, frac, word;
+ int exp, shift;
+
+ sign = (reg & __BIT(63)) >> 32;
+ exp = __SHIFTOUT(reg, __BITS(62, 52)) - 1023;
+ if (exp > -127 || (reg & ~__BIT(63)) == 0) {
+ /*
+ * No denormalization required: normalized, zero, inf, NaN,
+ * or numbers larger than MAXFLOAT (see comment above).
+ *
+ * Note that MSB and 7-LSBs in exponent are same for double
+ * and float formats in this case.
+ */
+ word = ((reg & __BIT(62)) >> 32) |
+ __SHIFTOUT(reg, __BITS(58, 52) | __BITS(51, 29));
+ } else if (exp <= -127 && exp >= -149) {
+ /* Denormalized. */
+ shift = - 126 - exp; /* 1 ... 23 */
+ frac = __SHIFTOUT(__BIT(52) | reg, __BITS(52, 29 + shift));
+ word = /* __SHIFTIN(0, __BITS(30, 23)) | */ frac;
+ } else {
+ /* Undefined. Mimic G5 for now. */
+ word = 0;
+ }
+ return sign | word;
+}
+
+/*
* Execute an FPU instruction (one that runs entirely in the FPU; not
* FBfcc or STF, for instance). On return, fe->fe_fs->fs_fsr will be
* modified to reflect the setting the hardware would have left.
@@ -411,28 +461,32 @@
if (store) {
/* Store */
+ uint32_t word;
+ const void *kaddr;
+
FPU_EMU_EVCNT_INCR(fpstore);
if (type != FTYPE_DBL) {
- uint64_t buf;
-
+ /*
+ * As Power ISA specifies conversion algorithm
+ * for store floating-point single insns, we
+ * cannot use fpu_explode() and _implode() here.
+ * See fpu_to_single() and comment therein for
+ * more details.
+ */
DPRINTF(FPE_INSN,
("fpu_execute: Store SNG at %p\n",
(void *)addr));
- fpu_explode(fe, fp = &fe->fe_f1, FTYPE_DBL,
- FR(rt));
- fpu_implode(fe, fp, type, &buf);
- if (copyout(&buf, (void *)addr, size)) {
- fe->fe_addr = addr;
- return (FAULT);
- }
+ word = fpu_to_single(FR(rt));
+ kaddr = &word;
} else {
DPRINTF(FPE_INSN,
("fpu_execute: Store DBL at %p\n",
(void *)addr));
- if (copyout(&FR(rt), (void *)addr, size)) {
- fe->fe_addr = addr;
- return (FAULT);
- }
+ kaddr = &FR(rt);
+ }
+ if (copyout(kaddr, (void *)addr, size)) {
+ fe->fe_addr = addr;
+ return (FAULT);
}
} else {
/* Load */
Home |
Main Index |
Thread Index |
Old Index