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 Fix fcti{w,d}{,z}.



details:   https://anonhg.NetBSD.org/src/rev/b9c1e25d3dde
branches:  trunk
changeset: 369753:b9c1e25d3dde
user:      rin <rin%NetBSD.org@localhost>
date:      Tue Aug 30 11:09:34 2022 +0000

description:
Fix fcti{w,d}{,z}.

- Treat 64-bit integer correctly for fctid{,z}.
- Respect round mode specified by FPSCR[RN].

XXX
- Set FPSCR[FR] and [FI] appropriately.
- Also set FPSCR[FPRF]?
- fctid{,z} traps on powerpc32 (confirmed on 603e and G4).

diffstat:

 sys/arch/powerpc/fpu/fpu_emu.c     |   8 ++-
 sys/arch/powerpc/fpu/fpu_emu.h     |  12 +++--
 sys/arch/powerpc/fpu/fpu_extern.h  |   6 +-
 sys/arch/powerpc/fpu/fpu_implode.c |  77 +++++++++++++++++++++++++++++--------
 4 files changed, 76 insertions(+), 27 deletions(-)

diffs (231 lines):

diff -r e2f46e5013c7 -r b9c1e25d3dde sys/arch/powerpc/fpu/fpu_emu.c
--- a/sys/arch/powerpc/fpu/fpu_emu.c    Tue Aug 30 11:05:59 2022 +0000
+++ b/sys/arch/powerpc/fpu/fpu_emu.c    Tue Aug 30 11:09:34 2022 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: fpu_emu.c,v 1.42 2022/08/30 10:59:43 rin Exp $ */
+/*     $NetBSD: fpu_emu.c,v 1.43 2022/08/30 11:09:34 rin Exp $ */
 
 /*
  * Copyright 2001 Wasabi Systems, Inc.
@@ -76,7 +76,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: fpu_emu.c,v 1.42 2022/08/30 10:59:43 rin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: fpu_emu.c,v 1.43 2022/08/30 11:09:34 rin Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_ddb.h"
@@ -504,6 +504,8 @@
                                DPRINTF(FPE_INSN, ("fpu_execute: FCTIW\n"));
                                fpu_explode(fe, fp = &fe->fe_f1, type, rb);
                                type = FTYPE_INT;
+                               if (instr.i_x.i_xo == OPC63_FCTIWZ)
+                                       type |= FTYPE_RD_RZ;
                                break;
                        case    OPC63_FCMPO:
                                FPU_EMU_EVCNT_INCR(fcmpo);
@@ -614,6 +616,8 @@
                                DPRINTF(FPE_INSN, ("fpu_execute: FCTID\n"));
                                fpu_explode(fe, fp = &fe->fe_f1, type, rb);
                                type = FTYPE_LNG;
+                               if (instr.i_x.i_xo == OPC63_FCTIDZ)
+                                       type |= FTYPE_RD_RZ;
                                break;
                        case    OPC63_FCFID:
                                FPU_EMU_EVCNT_INCR(fcfid);
diff -r e2f46e5013c7 -r b9c1e25d3dde sys/arch/powerpc/fpu/fpu_emu.h
--- a/sys/arch/powerpc/fpu/fpu_emu.h    Tue Aug 30 11:05:59 2022 +0000
+++ b/sys/arch/powerpc/fpu/fpu_emu.h    Tue Aug 30 11:09:34 2022 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: fpu_emu.h,v 1.5 2022/08/30 11:05:59 rin Exp $ */
+/*     $NetBSD: fpu_emu.h,v 1.6 2022/08/30 11:09:34 rin Exp $ */
 
 /*
  * Copyright (c) 1992, 1993
@@ -136,10 +136,12 @@
 /*
  * FPU data types.
  */
-#define        FTYPE_LNG       -1      /* data = 64-bit signed long integer */
-#define        FTYPE_INT       0       /* data = 32-bit signed integer */
-#define        FTYPE_SNG       1       /* data = 32-bit float */
-#define        FTYPE_DBL       2       /* data = 64-bit double */
+#define        FTYPE_INT       0x0     /* data = 32-bit signed integer */
+#define        FTYPE_LNG       0x1     /* data = 64-bit signed long integer */
+#define        FTYPE_SNG       0x2     /* data = 32-bit float */
+#define        FTYPE_DBL       0x4     /* data = 64-bit double */
+#define        FTYPE_RD_RZ     0x8
+#define        FTYPE_RD_MASK   (FTYPE_RD_RZ)
 
 /*
  * Emulator state.
diff -r e2f46e5013c7 -r b9c1e25d3dde sys/arch/powerpc/fpu/fpu_extern.h
--- a/sys/arch/powerpc/fpu/fpu_extern.h Tue Aug 30 11:05:59 2022 +0000
+++ b/sys/arch/powerpc/fpu/fpu_extern.h Tue Aug 30 11:09:34 2022 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: fpu_extern.h,v 1.6 2022/08/28 22:22:41 rin Exp $       */
+/*     $NetBSD: fpu_extern.h,v 1.7 2022/08/30 11:09:34 rin Exp $       */
 
 /*-
  * Copyright (c) 1995 The NetBSD Foundation, Inc.
@@ -63,8 +63,8 @@
 void fpu_explode(struct fpemu *, struct fpn *, int, int);
 
 /* fpu_implode.c */
-u_int fpu_ftoi(struct fpemu *, struct fpn *);
-u_int fpu_ftox(struct fpemu *, struct fpn *, u_int *);
+u_int fpu_ftoi(struct fpemu *, struct fpn *, int);
+uint64_t fpu_ftox(struct fpemu *, struct fpn *, int);
 u_int fpu_ftos(struct fpemu *, struct fpn *);
 u_int fpu_ftod(struct fpemu *, struct fpn *, u_int *);
 void fpu_implode(struct fpemu *, struct fpn *, int, u_int *);
diff -r e2f46e5013c7 -r b9c1e25d3dde sys/arch/powerpc/fpu/fpu_implode.c
--- a/sys/arch/powerpc/fpu/fpu_implode.c        Tue Aug 30 11:05:59 2022 +0000
+++ b/sys/arch/powerpc/fpu/fpu_implode.c        Tue Aug 30 11:09:34 2022 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: fpu_implode.c,v 1.9 2022/08/30 11:00:49 rin Exp $ */
+/*     $NetBSD: fpu_implode.c,v 1.10 2022/08/30 11:09:34 rin Exp $ */
 
 /*
  * Copyright (c) 1992, 1993
@@ -46,7 +46,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: fpu_implode.c,v 1.9 2022/08/30 11:00:49 rin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: fpu_implode.c,v 1.10 2022/08/30 11:09:34 rin Exp $");
 
 #include <sys/types.h>
 #include <sys/systm.h>
@@ -191,15 +191,12 @@
 
 /*
  * fpn -> int (int value returned as return value).
- *
- * N.B.: this conversion always rounds towards zero (this is a peculiarity
- * of the SPARC instruction set).
  */
 u_int
-fpu_ftoi(struct fpemu *fe, struct fpn *fp)
+fpu_ftoi(struct fpemu *fe, struct fpn *fp, int rn)
 {
        u_int i;
-       int sign, exp;
+       int sign, exp, g, rs;
 
        sign = fp->fp_sign;
        switch (fp->fp_class) {
@@ -221,9 +218,29 @@
                if ((exp = fp->fp_exp) >= 32)
                        break;
                /* NB: the following includes exp < 0 cases */
-               if (fpu_shr(fp, FP_NMANT - 1 - exp) != 0)
+               if (fpu_shr(fp, FP_NMANT - 32 - 1 - exp) != 0)
                        fe->fe_cx |= FPSCR_UX;
-               i = fp->fp_mant[3];
+               i = fp->fp_mant[2];
+
+               g  =  fp->fp_mant[3] & 0x80000000;
+               rs = (fp->fp_mant[3] & 0x7fffffff) | fp->fp_sticky;
+               switch (rn) {
+               case FSR_RD_RN:
+                       if (g && (rs | (i & 1)))
+                               i++;
+                       break;
+               case FSR_RD_RZ:
+                       break;
+               case FSR_RD_RP:
+                       if (!sign && (g | rs))
+                               i++;
+                       break;
+               case FSR_RD_RM:
+                       if (sign && (g | rs))
+                               i++;
+                       break;
+               }
+
                if (i >= ((u_int)0x80000000 + sign))
                        break;
                return (sign ? -i : i);
@@ -242,17 +259,16 @@
  * N.B.: this conversion always rounds towards zero (this is a peculiarity
  * of the SPARC instruction set).
  */
-u_int
-fpu_ftox(struct fpemu *fe, struct fpn *fp, u_int *res)
+uint64_t
+fpu_ftox(struct fpemu *fe, struct fpn *fp, int rn)
 {
        uint64_t i;
-       int sign, exp;
+       int sign, exp, g, rs;
 
        sign = fp->fp_sign;
        switch (fp->fp_class) {
 
        case FPC_ZERO:
-               res[1] = 0;
                return (0);
 
        case FPC_NUM:
@@ -269,9 +285,29 @@
                if ((exp = fp->fp_exp) >= 64)
                        break;
                /* NB: the following includes exp < 0 cases */
-               if (fpu_shr(fp, FP_NMANT - 1 - exp) != 0)
+               if (fpu_shr(fp, FP_NMANT - 32 - 1 - exp) != 0)
                        fe->fe_cx |= FPSCR_UX;
-               i = ((uint64_t)fp->fp_mant[2]<<32)|fp->fp_mant[3];
+               i = ((uint64_t)fp->fp_mant[1] << 32) | fp->fp_mant[2];
+
+               g  =  fp->fp_mant[3] & 0x80000000;
+               rs = (fp->fp_mant[3] & 0x7fffffff) | fp->fp_sticky;
+               switch (rn) {
+               case FSR_RD_RN:
+                       if (g && (rs | (i & 1)))
+                               i++;
+                       break;
+               case FSR_RD_RZ:
+                       break;
+               case FSR_RD_RP:
+                       if (!sign && (g | rs))
+                               i++;
+                       break;
+               case FSR_RD_RM:
+                       if (sign && (g | rs))
+                               i++;
+                       break;
+               }
+
                if (i >= ((uint64_t)0x8000000000000000LL + sign))
                        break;
                return (sign ? -i : i);
@@ -427,18 +463,25 @@
 void
 fpu_implode(struct fpemu *fe, struct fpn *fp, int type, u_int *space)
 {
+       int rn;
+
+       if (type & FTYPE_RD_RZ)
+               rn = FSR_RD_RZ;
+       else
+               rn = fe->fe_fpscr & FPSCR_RN;
+       type &= ~FTYPE_RD_MASK;
 
        switch (type) {
 
        case FTYPE_LNG:
-               space[0] = fpu_ftox(fe, fp, space);
+               *(uint64_t *)space = fpu_ftox(fe, fp, rn);
                DPRINTF(FPE_REG, ("fpu_implode: long %x %x\n",
                        space[0], space[1]));
                break;
 
        case FTYPE_INT:
                space[0] = 0;
-               space[1] = fpu_ftoi(fe, fp);
+               space[1] = fpu_ftoi(fe, fp, rn);
                DPRINTF(FPE_REG, ("fpu_implode: int %x\n",
                        space[1]));
                break;



Home | Main Index | Thread Index | Old Index