Module Name:    src
Committed By:   rin
Date:           Tue Aug 30 11:09:34 UTC 2022

Modified Files:
        src/sys/arch/powerpc/fpu: fpu_emu.c fpu_emu.h fpu_extern.h
            fpu_implode.c

Log Message:
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).


To generate a diff of this commit:
cvs rdiff -u -r1.42 -r1.43 src/sys/arch/powerpc/fpu/fpu_emu.c
cvs rdiff -u -r1.5 -r1.6 src/sys/arch/powerpc/fpu/fpu_emu.h
cvs rdiff -u -r1.6 -r1.7 src/sys/arch/powerpc/fpu/fpu_extern.h
cvs rdiff -u -r1.9 -r1.10 src/sys/arch/powerpc/fpu/fpu_implode.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/powerpc/fpu/fpu_emu.c
diff -u src/sys/arch/powerpc/fpu/fpu_emu.c:1.42 src/sys/arch/powerpc/fpu/fpu_emu.c:1.43
--- src/sys/arch/powerpc/fpu/fpu_emu.c:1.42	Tue Aug 30 10:59:43 2022
+++ src/sys/arch/powerpc/fpu/fpu_emu.c	Tue Aug 30 11:09:34 2022
@@ -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 @@ fpu_execute(struct trapframe *tf, struct
 				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 @@ fpu_execute(struct trapframe *tf, struct
 				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);

Index: src/sys/arch/powerpc/fpu/fpu_emu.h
diff -u src/sys/arch/powerpc/fpu/fpu_emu.h:1.5 src/sys/arch/powerpc/fpu/fpu_emu.h:1.6
--- src/sys/arch/powerpc/fpu/fpu_emu.h:1.5	Tue Aug 30 11:05:59 2022
+++ src/sys/arch/powerpc/fpu/fpu_emu.h	Tue Aug 30 11:09:34 2022
@@ -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 @@ struct fpn {
 /*
  * 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.

Index: src/sys/arch/powerpc/fpu/fpu_extern.h
diff -u src/sys/arch/powerpc/fpu/fpu_extern.h:1.6 src/sys/arch/powerpc/fpu/fpu_extern.h:1.7
--- src/sys/arch/powerpc/fpu/fpu_extern.h:1.6	Sun Aug 28 22:22:41 2022
+++ src/sys/arch/powerpc/fpu/fpu_extern.h	Tue Aug 30 11:09:34 2022
@@ -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 @@ int fpu_dtof(struct fpn *, u_int, u_int)
 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 *);

Index: src/sys/arch/powerpc/fpu/fpu_implode.c
diff -u src/sys/arch/powerpc/fpu/fpu_implode.c:1.9 src/sys/arch/powerpc/fpu/fpu_implode.c:1.10
--- src/sys/arch/powerpc/fpu/fpu_implode.c:1.9	Tue Aug 30 11:00:49 2022
+++ src/sys/arch/powerpc/fpu/fpu_implode.c	Tue Aug 30 11:09:34 2022
@@ -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 @@ toinf(struct fpemu *fe, int sign)
 
 /*
  * 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 @@ fpu_ftoi(struct fpemu *fe, struct fpn *f
 		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 @@ fpu_ftoi(struct fpemu *fe, struct fpn *f
  * 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 @@ fpu_ftox(struct fpemu *fe, struct fpn *f
 		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 @@ done:
 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;

Reply via email to