Module Name:    src
Committed By:   rin
Date:           Thu Sep  1 06:08:16 UTC 2022

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

Log Message:
Set FPSCR[FPRF] for calculated result, for all instructions
that are documented to update this field.

Exceptions are fcti{w,d}{,z}; FPSCR[FPRF] becomes undefined,
according to Power ISA. We do not overwrite this field for
these insns at the moment.


To generate a diff of this commit:
cvs rdiff -u -r1.43 -r1.44 src/sys/arch/powerpc/fpu/fpu_emu.c
cvs rdiff -u -r1.6 -r1.7 src/sys/arch/powerpc/fpu/fpu_emu.h
cvs rdiff -u -r1.13 -r1.14 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.43 src/sys/arch/powerpc/fpu/fpu_emu.c:1.44
--- src/sys/arch/powerpc/fpu/fpu_emu.c:1.43	Tue Aug 30 11:09:34 2022
+++ src/sys/arch/powerpc/fpu/fpu_emu.c	Thu Sep  1 06:08:16 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: fpu_emu.c,v 1.43 2022/08/30 11:09:34 rin Exp $ */
+/*	$NetBSD: fpu_emu.c,v 1.44 2022/09/01 06:08:16 rin Exp $ */
 
 /*
  * Copyright 2001 Wasabi Systems, Inc.
@@ -76,7 +76,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: fpu_emu.c,v 1.43 2022/08/30 11:09:34 rin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: fpu_emu.c,v 1.44 2022/09/01 06:08:16 rin Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_ddb.h"
@@ -496,7 +496,7 @@ fpu_execute(struct trapframe *tf, struct
 				fpu_implode(fe, fp, FTYPE_SNG, 
 					(u_int *)&fs->fpreg[rt]);
 				fpu_explode(fe, fp = &fe->fe_f1, FTYPE_SNG, rt);
-				type = FTYPE_DBL;
+				type = FTYPE_DBL | FTYPE_FPRF;
 				break;
 			case	OPC63_FCTIW:
 			case	OPC63_FCTIWZ:
@@ -624,7 +624,7 @@ fpu_execute(struct trapframe *tf, struct
 				DPRINTF(FPE_INSN, ("fpu_execute: FCFID\n"));
 				type = FTYPE_LNG;
 				fpu_explode(fe, fp = &fe->fe_f1, type, rb);
-				type = FTYPE_DBL;
+				type = FTYPE_DBL | FTYPE_FPRF;
 				break;
 			default:
 				return (NOTFPU);
@@ -765,10 +765,11 @@ fpu_execute(struct trapframe *tf, struct
 
 			/* If the instruction was single precision, round */
 			if (!(instr.i_any.i_opcd & 0x4)) {
-				fpu_implode(fe, fp, FTYPE_SNG, 
+				fpu_implode(fe, fp, FTYPE_SNG | FTYPE_FPRF,
 					(u_int *)&fs->fpreg[rt]);
 				fpu_explode(fe, fp = &fe->fe_f1, FTYPE_SNG, rt);
-			}
+			} else
+				type |= FTYPE_FPRF;
 		}
 	} else {
 		return (NOTFPU);

Index: src/sys/arch/powerpc/fpu/fpu_emu.h
diff -u src/sys/arch/powerpc/fpu/fpu_emu.h:1.6 src/sys/arch/powerpc/fpu/fpu_emu.h:1.7
--- src/sys/arch/powerpc/fpu/fpu_emu.h:1.6	Tue Aug 30 11:09:34 2022
+++ src/sys/arch/powerpc/fpu/fpu_emu.h	Thu Sep  1 06:08:16 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: fpu_emu.h,v 1.6 2022/08/30 11:09:34 rin Exp $ */
+/*	$NetBSD: fpu_emu.h,v 1.7 2022/09/01 06:08:16 rin Exp $ */
 
 /*
  * Copyright (c) 1992, 1993
@@ -136,12 +136,13 @@ struct fpn {
 /*
  * FPU data types.
  */
-#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)
+#define	FTYPE_INT	0x00	/* data = 32-bit signed integer */
+#define	FTYPE_LNG	0x01	/* data = 64-bit signed long integer */
+#define	FTYPE_SNG	0x02	/* data = 32-bit float */
+#define	FTYPE_DBL	0x04	/* data = 64-bit double */
+#define	FTYPE_RD_RZ	0x08
+#define	FTYPE_FPRF	0x10
+#define	FTYPE_FLAG_MASK	(FTYPE_RD_RZ | FTYPE_FPRF)
 
 /*
  * Emulator state.

Index: src/sys/arch/powerpc/fpu/fpu_implode.c
diff -u src/sys/arch/powerpc/fpu/fpu_implode.c:1.13 src/sys/arch/powerpc/fpu/fpu_implode.c:1.14
--- src/sys/arch/powerpc/fpu/fpu_implode.c:1.13	Thu Sep  1 05:58:19 2022
+++ src/sys/arch/powerpc/fpu/fpu_implode.c	Thu Sep  1 06:08:16 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: fpu_implode.c,v 1.13 2022/09/01 05:58:19 rin Exp $ */
+/*	$NetBSD: fpu_implode.c,v 1.14 2022/09/01 06:08:16 rin Exp $ */
 
 /*
  * Copyright (c) 1992, 1993
@@ -46,7 +46,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: fpu_implode.c,v 1.13 2022/09/01 05:58:19 rin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: fpu_implode.c,v 1.14 2022/09/01 06:08:16 rin Exp $");
 
 #include <sys/types.h>
 #include <sys/systm.h>
@@ -66,8 +66,8 @@ static int round_int(struct fpn *, int *
 
 static u_int fpu_ftoi(struct fpemu *, struct fpn *, int);
 static uint64_t fpu_ftox(struct fpemu *, struct fpn *, int);
-static u_int fpu_ftos(struct fpemu *, struct fpn *);
-static u_int fpu_ftod(struct fpemu *, struct fpn *, u_int *);
+static u_int fpu_ftos(struct fpemu *, struct fpn *, bool);
+static u_int fpu_ftod(struct fpemu *, struct fpn *, u_int *, bool);
 
 /*
  * Round a number (algorithm from Motorola MC68882 manual, modified for
@@ -333,12 +333,14 @@ fpu_ftox(struct fpemu *fe, struct fpn *f
 	return (0x7fffffffffffffffLL + sign);
 }
 
+#define	FPRF_SIGN(sign)	((sign) ? FPSCR_FL : FPSCR_FG)
+
 /*
  * fpn -> single (32 bit single returned as return value).
  * We assume <= 29 bits in a single-precision fraction (1.f part).
  */
 static u_int
-fpu_ftos(struct fpemu *fe, struct fpn *fp)
+fpu_ftos(struct fpemu *fe, struct fpn *fp, bool fprf)
 {
 	u_int sign = fp->fp_sign << 31;
 	int exp;
@@ -348,6 +350,8 @@ fpu_ftos(struct fpemu *fe, struct fpn *f
 
 	/* Take care of non-numbers first. */
 	if (ISNAN(fp)) {
+		if (fprf)
+			fe->fe_cx |= FPSCR_C | FPSCR_FU;
 		/*
 		 * Preserve upper bits of NaN, per SPARC V8 appendix N.
 		 * Note that fp->fp_mant[0] has the quiet bit set,
@@ -357,10 +361,19 @@ fpu_ftos(struct fpemu *fe, struct fpn *f
 		exp = SNG_EXP_INFNAN;
 		goto done;
 	}
-	if (ISINF(fp))
+	if (ISINF(fp)) {
+		if (fprf)
+			fe->fe_cx |= FPRF_SIGN(sign) | FPSCR_FU;
 		return (sign | SNG_EXP(SNG_EXP_INFNAN));
-	if (ISZERO(fp))
+	}
+	if (ISZERO(fp)) {
+		if (fprf) {
+			fe->fe_cx |= FPSCR_FE;
+			if (sign)
+				fe->fe_cx |= FPSCR_C;
+		}
 		return (sign);
+	}
 
 	/*
 	 * Normals (including subnormals).  Drop all the fraction bits
@@ -386,8 +399,13 @@ fpu_ftos(struct fpemu *fe, struct fpn *f
 	if ((exp = fp->fp_exp + SNG_EXP_BIAS) <= 0) {	/* subnormal */
 		/* -NG for g,r; -SNG_FRACBITS-exp for fraction */
 		(void) fpu_shr(fp, FP_NMANT - FP_NG - SNG_FRACBITS - exp);
-		if (round(fe, fp) && fp->fp_mant[3] == SNG_EXP(1))
+		if (round(fe, fp) && fp->fp_mant[3] == SNG_EXP(1)) {
+			if (fprf)
+				fe->fe_cx |= FPRF_SIGN(sign);
 			return (sign | SNG_EXP(1) | 0);
+		}
+		if (fprf)
+			fe->fe_cx |= FPSCR_C | FPRF_SIGN(sign);
 		if ((fe->fe_cx & FPSCR_FI) ||
 		    (fe->fe_fpscr & FPSCR_UX))
 			fe->fe_cx |= FPSCR_UX;
@@ -403,10 +421,17 @@ fpu_ftos(struct fpemu *fe, struct fpn *f
 		exp++;
 	if (exp >= SNG_EXP_INFNAN) {
 		/* overflow to inf or to max single */
-		if (toinf(fe, sign))
+		if (toinf(fe, sign)) {
+			if (fprf)
+				fe->fe_cx |= FPRF_SIGN(sign) | FPSCR_FU;
 			return (sign | SNG_EXP(SNG_EXP_INFNAN));
+		}
+		if (fprf)
+			fe->fe_cx |= FPRF_SIGN(sign);
 		return (sign | SNG_EXP(SNG_EXP_INFNAN - 1) | SNG_MASK);
 	}
+	if (fprf)
+		fe->fe_cx |= FPRF_SIGN(sign);
 done:
 	/* phew, made it */
 	return (sign | SNG_EXP(exp) | (fp->fp_mant[3] & SNG_MASK));
@@ -419,7 +444,7 @@ done:
  * This code mimics fpu_ftos; see it for comments.
  */
 static u_int
-fpu_ftod(struct fpemu *fe, struct fpn *fp, u_int *res)
+fpu_ftod(struct fpemu *fe, struct fpn *fp, u_int *res, bool fprf)
 {
 	u_int sign = fp->fp_sign << 31;
 	int exp;
@@ -428,15 +453,24 @@ fpu_ftod(struct fpemu *fe, struct fpn *f
 #define	DBL_MASK	(DBL_EXP(1) - 1)
 
 	if (ISNAN(fp)) {
+		if (fprf)
+			fe->fe_cx |= FPSCR_C | FPSCR_FU;
 		(void) fpu_shr(fp, FP_NMANT - 1 - DBL_FRACBITS);
 		exp = DBL_EXP_INFNAN;
 		goto done;
 	}
 	if (ISINF(fp)) {
+		if (fprf)
+			fe->fe_cx |= FPRF_SIGN(sign) | FPSCR_FU;
 		sign |= DBL_EXP(DBL_EXP_INFNAN);
 		goto zero;
 	}
 	if (ISZERO(fp)) {
+		if (fprf) {
+			fe->fe_cx |= FPSCR_FE;
+			if (sign)
+				fe->fe_cx |= FPSCR_C;
+		}
 zero:		res[1] = 0;
 		return (sign);
 	}
@@ -444,9 +478,13 @@ zero:		res[1] = 0;
 	if ((exp = fp->fp_exp + DBL_EXP_BIAS) <= 0) {
 		(void) fpu_shr(fp, FP_NMANT - FP_NG - DBL_FRACBITS - exp);
 		if (round(fe, fp) && fp->fp_mant[2] == DBL_EXP(1)) {
+			if (fprf)
+				fe->fe_cx |= FPRF_SIGN(sign);
 			res[1] = 0;
 			return (sign | DBL_EXP(1) | 0);
 		}
+		if (fprf)
+			fe->fe_cx |= FPSCR_C | FPRF_SIGN(sign);
 		if ((fe->fe_cx & FPSCR_FI) ||
 		    (fe->fe_fpscr & FPSCR_UX))
 			fe->fe_cx |= FPSCR_UX;
@@ -459,12 +497,18 @@ zero:		res[1] = 0;
 	if (exp >= DBL_EXP_INFNAN) {
 		fe->fe_cx |= FPSCR_OX;
 		if (toinf(fe, sign)) {
+			if (fprf)
+				fe->fe_cx |= FPRF_SIGN(sign) | FPSCR_FU;
 			res[1] = 0;
 			return (sign | DBL_EXP(DBL_EXP_INFNAN) | 0);
 		}
+		if (fprf)
+			fe->fe_cx |= FPRF_SIGN(sign);
 		res[1] = ~0;
 		return (sign | DBL_EXP(DBL_EXP_INFNAN) | DBL_MASK);
 	}
+	if (fprf)
+		fe->fe_cx |= FPRF_SIGN(sign);
 done:
 	res[1] = fp->fp_mant[3];
 	return (sign | DBL_EXP(exp) | (fp->fp_mant[2] & DBL_MASK));
@@ -477,22 +521,26 @@ void
 fpu_implode(struct fpemu *fe, struct fpn *fp, int type, u_int *space)
 {
 	int rn;
+	bool fprf;
 
 	if (type & FTYPE_RD_RZ)
 		rn = FSR_RD_RZ;
 	else
 		rn = fe->fe_fpscr & FPSCR_RN;
-	type &= ~FTYPE_RD_MASK;
+	fprf = type & FTYPE_FPRF;
+	type &= ~FTYPE_FLAG_MASK;
 
 	switch (type) {
 
 	case FTYPE_LNG:
+		/* FPRF is undefined. */
 		*(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:
+		/* FPRF is undefined. */
 		space[0] = 0;
 		space[1] = fpu_ftoi(fe, fp, rn);
 		DPRINTF(FPE_REG, ("fpu_implode: int %x\n",
@@ -500,13 +548,13 @@ fpu_implode(struct fpemu *fe, struct fpn
 		break;
 
 	case FTYPE_SNG:
-		space[0] = fpu_ftos(fe, fp);
+		space[0] = fpu_ftos(fe, fp, fprf);
 		DPRINTF(FPE_REG, ("fpu_implode: single %x\n",
 			space[0]));
 		break;
 
 	case FTYPE_DBL:
-		space[0] = fpu_ftod(fe, fp, space);
+		space[0] = fpu_ftod(fe, fp, space, fprf);
 		DPRINTF(FPE_REG, ("fpu_implode: double %x %x\n",
 			space[0], space[1]));
 		break;		break;

Reply via email to