Module Name: src Committed By: rin Date: Sun Sep 4 13:14:57 UTC 2022
Modified Files: src/sys/arch/powerpc/fpu: fpu_compare.c fpu_emu.c fpu_emu.h fpu_implode.c Log Message: Fix logic for FI, FR, and FPRF fields of FPSCR. They are not sticky bits and updated by arithmetic and round insns at the same time. Comparison insns update only FPCC sub-field of FPRF. For other insns, these field are left untouched. Also, for single-precision insns, exception bits should be set by the first fpu_implode(), which rounds the value to float. To generate a diff of this commit: cvs rdiff -u -r1.5 -r1.6 src/sys/arch/powerpc/fpu/fpu_compare.c cvs rdiff -u -r1.49 -r1.50 src/sys/arch/powerpc/fpu/fpu_emu.c cvs rdiff -u -r1.8 -r1.9 src/sys/arch/powerpc/fpu/fpu_emu.h cvs rdiff -u -r1.20 -r1.21 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_compare.c diff -u src/sys/arch/powerpc/fpu/fpu_compare.c:1.5 src/sys/arch/powerpc/fpu/fpu_compare.c:1.6 --- src/sys/arch/powerpc/fpu/fpu_compare.c:1.5 Sat Jun 27 03:07:57 2020 +++ src/sys/arch/powerpc/fpu/fpu_compare.c Sun Sep 4 13:14:57 2022 @@ -1,4 +1,4 @@ -/* $NetBSD: fpu_compare.c,v 1.5 2020/06/27 03:07:57 rin Exp $ */ +/* $NetBSD: fpu_compare.c,v 1.6 2022/09/04 13:14:57 rin Exp $ */ /* * Copyright (c) 1992, 1993 @@ -48,7 +48,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: fpu_compare.c,v 1.5 2020/06/27 03:07:57 rin Exp $"); +__KERNEL_RCSID(0, "$NetBSD: fpu_compare.c,v 1.6 2022/09/04 13:14:57 rin Exp $"); #include <sys/types.h> @@ -79,6 +79,8 @@ fpu_compare(struct fpemu *fe, int ordere struct fpn *a, *b, *r; int cc; + fe->fe_fpscr &= ~FPSCR_FPCC; + a = &fe->fe_f1; b = &fe->fe_f2; r = &fe->fe_f3; Index: src/sys/arch/powerpc/fpu/fpu_emu.c diff -u src/sys/arch/powerpc/fpu/fpu_emu.c:1.49 src/sys/arch/powerpc/fpu/fpu_emu.c:1.50 --- src/sys/arch/powerpc/fpu/fpu_emu.c:1.49 Sat Sep 3 04:54:47 2022 +++ src/sys/arch/powerpc/fpu/fpu_emu.c Sun Sep 4 13:14:57 2022 @@ -1,4 +1,4 @@ -/* $NetBSD: fpu_emu.c,v 1.49 2022/09/03 04:54:47 rin Exp $ */ +/* $NetBSD: fpu_emu.c,v 1.50 2022/09/04 13:14:57 rin Exp $ */ /* * Copyright 2001 Wasabi Systems, Inc. @@ -76,7 +76,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: fpu_emu.c,v 1.49 2022/09/03 04:54:47 rin Exp $"); +__KERNEL_RCSID(0, "$NetBSD: fpu_emu.c,v 1.50 2022/09/04 13:14:57 rin Exp $"); #ifdef _KERNEL_OPT #include "opt_ddb.h" @@ -297,7 +297,7 @@ fpu_execute(struct trapframe *tf, struct int ra, rb, rc, rt, type, mask, fsr, cx, bf, setcr, cond; u_int bits; struct fpreg *fs; - int i, mtfsb1 = 0; + int i; /* Setup work. */ fp = NULL; @@ -499,7 +499,7 @@ fpu_execute(struct trapframe *tf, struct fpu_implode(fe, fp, FTYPE_SNG, &FR(rt)); fpu_explode(fe, fp = &fe->fe_f1, FTYPE_SNG, FR(rt)); - type = FTYPE_DBL | FTYPE_FPRF; + type = FTYPE_DBL | FTYPE_FPSCR; break; case OPC63_FCTIW: case OPC63_FCTIWZ: @@ -526,7 +526,6 @@ fpu_execute(struct trapframe *tf, struct case OPC63_MTFSB1: FPU_EMU_EVCNT_INCR(mtfsb1); DPRINTF(FPE_INSN, ("fpu_execute: MTFSB1\n")); - mtfsb1 = 1; fe->fe_cx = (1 << (31 - rt)) & ~(FPSCR_FEX | FPSCR_VX); break; @@ -627,7 +626,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, FR(rb)); - type = FTYPE_DBL | FTYPE_FPRF; + type = FTYPE_DBL | FTYPE_FPSCR; break; default: return (NOTFPU); @@ -763,12 +762,12 @@ 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 | FTYPE_FPRF, + fpu_implode(fe, fp, FTYPE_SNG | FTYPE_FPSCR, &FR(rt)); fpu_explode(fe, fp = &fe->fe_f1, FTYPE_SNG, FR(rt)); } else - type |= FTYPE_FPRF; + type |= FTYPE_FPSCR; } } else { return (NOTFPU); @@ -785,10 +784,6 @@ fpu_execute(struct trapframe *tf, struct cx = fe->fe_cx; fsr = fe->fe_fpscr & ~(FPSCR_FEX|FPSCR_VX); if (cx != 0) { - if (mtfsb1 == 0 && (cx & FPSCR_FPRF) != 0) { - /* Need to replace CC */ - fsr &= ~FPSCR_FPRF; - } fsr |= cx; DPRINTF(FPE_INSN, ("fpu_execute: cx %x, fsr %x\n", cx, fsr)); } Index: src/sys/arch/powerpc/fpu/fpu_emu.h diff -u src/sys/arch/powerpc/fpu/fpu_emu.h:1.8 src/sys/arch/powerpc/fpu/fpu_emu.h:1.9 --- src/sys/arch/powerpc/fpu/fpu_emu.h:1.8 Fri Sep 2 12:40:49 2022 +++ src/sys/arch/powerpc/fpu/fpu_emu.h Sun Sep 4 13:14:57 2022 @@ -1,4 +1,4 @@ -/* $NetBSD: fpu_emu.h,v 1.8 2022/09/02 12:40:49 rin Exp $ */ +/* $NetBSD: fpu_emu.h,v 1.9 2022/09/04 13:14:57 rin Exp $ */ /* * Copyright (c) 1992, 1993 @@ -141,8 +141,8 @@ struct fpn { #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) +#define FTYPE_FPSCR 0x10 +#define FTYPE_FLAG_MASK (FTYPE_RD_RZ | FTYPE_FPSCR) /* * Emulator state. Index: src/sys/arch/powerpc/fpu/fpu_implode.c diff -u src/sys/arch/powerpc/fpu/fpu_implode.c:1.20 src/sys/arch/powerpc/fpu/fpu_implode.c:1.21 --- src/sys/arch/powerpc/fpu/fpu_implode.c:1.20 Sun Sep 4 09:23:07 2022 +++ src/sys/arch/powerpc/fpu/fpu_implode.c Sun Sep 4 13:14:57 2022 @@ -1,4 +1,4 @@ -/* $NetBSD: fpu_implode.c,v 1.20 2022/09/04 09:23:07 rin Exp $ */ +/* $NetBSD: fpu_implode.c,v 1.21 2022/09/04 13:14:57 rin Exp $ */ /* * Copyright (c) 1992, 1993 @@ -46,7 +46,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: fpu_implode.c,v 1.20 2022/09/04 09:23:07 rin Exp $"); +__KERNEL_RCSID(0, "$NetBSD: fpu_implode.c,v 1.21 2022/09/04 13:14:57 rin Exp $"); #include <sys/types.h> #include <sys/systm.h> @@ -60,14 +60,14 @@ __KERNEL_RCSID(0, "$NetBSD: fpu_implode. #include <powerpc/fpu/fpu_emu.h> #include <powerpc/fpu/fpu_extern.h> -static int round(struct fpemu *, struct fpn *); +static int round(struct fpemu *, struct fpn *, int *); static int toinf(struct fpemu *, int); static int round_int(struct fpn *, int *, int, int, 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 *, bool); -static uint64_t fpu_ftod(struct fpemu *, struct fpn *, bool); +static u_int fpu_ftoi(struct fpemu *, struct fpn *, int *, int); +static uint64_t fpu_ftox(struct fpemu *, struct fpn *, int *, int); +static u_int fpu_ftos(struct fpemu *, struct fpn *, int *); +static uint64_t fpu_ftod(struct fpemu *, struct fpn *, int *); /* * Round a number (algorithm from Motorola MC68882 manual, modified for @@ -82,7 +82,7 @@ static uint64_t fpu_ftod(struct fpemu *, * responsibility to fix this if necessary. */ static int -round(struct fpemu *fe, struct fpn *fp) +round(struct fpemu *fe, struct fpn *fp, int *cx) { u_int m0, m1, m2, m3; int gr, s; @@ -104,7 +104,7 @@ round(struct fpemu *fe, struct fpn *fp) if ((gr | s) == 0) /* result is exact: no rounding needed */ goto rounddown; - fe->fe_cx |= FPSCR_XX|FPSCR_FI; /* inexact */ + *cx |= FPSCR_FI; /* inexact */ /* Go to rounddown to round down; break to round up. */ switch ((fe->fe_fpscr) & FPSCR_RN) { @@ -140,7 +140,7 @@ round(struct fpemu *fe, struct fpn *fp) } /* Bump low bit of mantissa, with carry. */ - fe->fe_cx |= FPSCR_FR; + *cx |= FPSCR_FR; FPU_ADDS(m3, m3, 1); FPU_ADDCS(m2, m2, 0); @@ -190,8 +190,6 @@ toinf(struct fpemu *fe, int sign) inf = sign; break; } - if (inf) - fe->fe_cx |= FPSCR_OX; return (inf); } @@ -206,7 +204,7 @@ round_int(struct fpn *fp, int *cx, int r if ((g | rs) == 0) return 0; /* exact */ - *cx |= FPSCR_XX | FPSCR_FI; + *cx |= FPSCR_FI; switch (rn) { case FSR_RD_RN: @@ -233,16 +231,15 @@ round_int(struct fpn *fp, int *cx, int r * fpn -> int (int value returned as return value). */ static u_int -fpu_ftoi(struct fpemu *fe, struct fpn *fp, int rn) +fpu_ftoi(struct fpemu *fe, struct fpn *fp, int *cx, int rn) { u_int i; - int sign, exp, cx; + int sign, exp, tmp_cx; sign = fp->fp_sign; - cx = 0; switch (fp->fp_class) { case FPC_SNAN: - fe->fe_cx |= FPSCR_VXSNAN; + *cx |= FPSCR_VXSNAN; /* FALLTHROUGH */ case FPC_QNAN: sign = 1; @@ -267,17 +264,18 @@ fpu_ftoi(struct fpemu *fe, struct fpn *f /* NB: the following includes exp < 0 cases */ (void)fpu_shr(fp, FP_NMANT - 32 - 1 - exp); i = fp->fp_mant[2]; - i += round_int(fp, &cx, rn, sign, i & 1); + tmp_cx = 0; + i += round_int(fp, &tmp_cx, rn, sign, i & 1); if (i >= ((u_int)0x80000000 + sign)) break; - fe->fe_cx |= cx; + *cx |= tmp_cx; return (sign ? -i : i); case FPC_INF: break; } /* overflow: replace any inexact exception with invalid */ - fe->fe_cx |= FPSCR_VXCVI; + *cx |= FPSCR_VXCVI; return (0x7fffffff + sign); } @@ -285,16 +283,15 @@ fpu_ftoi(struct fpemu *fe, struct fpn *f * fpn -> extended int (high bits of int value returned as return value). */ static uint64_t -fpu_ftox(struct fpemu *fe, struct fpn *fp, int rn) +fpu_ftox(struct fpemu *fe, struct fpn *fp, int *cx, int rn) { uint64_t i; - int sign, exp, cx; + int sign, exp, tmp_cx; sign = fp->fp_sign; - cx = 0; switch (fp->fp_class) { case FPC_SNAN: - fe->fe_cx |= FPSCR_VXSNAN; + *cx |= FPSCR_VXSNAN; /* FALLTHROUGH */ case FPC_QNAN: sign = 1; @@ -319,17 +316,18 @@ fpu_ftox(struct fpemu *fe, struct fpn *f /* NB: the following includes exp < 0 cases */ (void)fpu_shr(fp, FP_NMANT - 32 - 1 - exp); i = ((uint64_t)fp->fp_mant[1] << 32) | fp->fp_mant[2]; - i += round_int(fp, &cx, rn, sign, i & 1); + tmp_cx = 0; + i += round_int(fp, &tmp_cx, rn, sign, i & 1); if (i >= ((uint64_t)0x8000000000000000LL + sign)) break; - fe->fe_cx |= cx; + *cx |= tmp_cx; return (sign ? -i : i); case FPC_INF: break; } /* overflow: replace any inexact exception with invalid */ - fe->fe_cx |= FPSCR_VXCVI; + *cx |= FPSCR_VXCVI; return (0x7fffffffffffffffLL + sign); } @@ -340,7 +338,7 @@ fpu_ftox(struct fpemu *fe, struct fpn *f * We assume <= 29 bits in a single-precision fraction (1.f part). */ static u_int -fpu_ftos(struct fpemu *fe, struct fpn *fp, bool fprf) +fpu_ftos(struct fpemu *fe, struct fpn *fp, int *cx) { u_int sign = fp->fp_sign << 31; int exp; @@ -350,8 +348,7 @@ 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; + *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, @@ -362,16 +359,13 @@ fpu_ftos(struct fpemu *fe, struct fpn *f goto done; } if (ISINF(fp)) { - if (fprf) - fe->fe_cx |= FPRF_SIGN(sign) | FPSCR_FU; + *cx |= FPRF_SIGN(sign) | FPSCR_FU; return (sign | SNG_EXP(SNG_EXP_INFNAN)); } if (ISZERO(fp)) { - if (fprf) { - fe->fe_cx |= FPSCR_FE; - if (sign) - fe->fe_cx |= FPSCR_C; - } + *cx |= FPSCR_FE; + if (sign) + *cx |= FPSCR_C; return (sign); } @@ -399,16 +393,14 @@ 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 (fprf) - fe->fe_cx |= FPRF_SIGN(sign); + if (round(fe, fp, cx) && fp->fp_mant[3] == SNG_EXP(1)) { + *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) || + *cx |= FPSCR_C | FPRF_SIGN(sign); + if (((fe->fe_cx | *cx) & FPSCR_FI) || (fe->fe_fpscr & FPSCR_UX)) - fe->fe_cx |= FPSCR_UX; + *cx |= FPSCR_UX; return (sign | SNG_EXP(0) | fp->fp_mant[3]); } /* -FP_NG for g,r; -1 for implied 1; -SNG_FRACBITS for fraction */ @@ -417,21 +409,19 @@ fpu_ftos(struct fpemu *fe, struct fpn *f if ((fp->fp_mant[3] & SNG_EXP(1 << FP_NG)) == 0) panic("fpu_ftos"); #endif - if (round(fe, fp) && fp->fp_mant[3] == SNG_EXP(2)) + if (round(fe, fp, cx) && fp->fp_mant[3] == SNG_EXP(2)) exp++; if (exp >= SNG_EXP_INFNAN) { + *cx |= FPSCR_OX; /* overflow to inf or to max single */ if (toinf(fe, sign)) { - if (fprf) - fe->fe_cx |= FPRF_SIGN(sign) | FPSCR_FU; + *cx |= FPRF_SIGN(sign) | FPSCR_FU; return (sign | SNG_EXP(SNG_EXP_INFNAN)); } - if (fprf) - fe->fe_cx |= FPRF_SIGN(sign); + *cx |= FPRF_SIGN(sign); return (sign | SNG_EXP(SNG_EXP_INFNAN - 1) | SNG_MASK); } - if (fprf) - fe->fe_cx |= FPRF_SIGN(sign); + *cx |= FPRF_SIGN(sign); done: /* phew, made it */ return (sign | SNG_EXP(exp) | (fp->fp_mant[3] & SNG_MASK)); @@ -443,7 +433,7 @@ done: * This code mimics fpu_ftos; see it for comments. */ static uint64_t -fpu_ftod(struct fpemu *fe, struct fpn *fp, bool fprf) +fpu_ftod(struct fpemu *fe, struct fpn *fp, int *cx) { u_int sign = fp->fp_sign << 31; int exp; @@ -454,59 +444,51 @@ fpu_ftod(struct fpemu *fe, struct fpn *f #define LO_WORD(i) ((uint32_t)(i)) if (ISNAN(fp)) { - if (fprf) - fe->fe_cx |= FPSCR_C | FPSCR_FU; + *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; + *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; - } + *cx |= FPSCR_FE; + if (sign) + *cx |= FPSCR_C; zero: return HI_WORD(sign); } 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); + if (round(fe, fp, cx) && fp->fp_mant[2] == DBL_EXP(1)) { + *cx |= FPRF_SIGN(sign); return HI_WORD(sign | DBL_EXP(1) | 0); } - if (fprf) - fe->fe_cx |= FPSCR_C | FPRF_SIGN(sign); - if ((fe->fe_cx & FPSCR_FI) || + *cx |= FPSCR_C | FPRF_SIGN(sign); + if (((fe->fe_cx | *cx) & FPSCR_FI) || (fe->fe_fpscr & FPSCR_UX)) - fe->fe_cx |= FPSCR_UX; + *cx |= FPSCR_UX; exp = 0; goto done; } (void) fpu_shr(fp, FP_NMANT - FP_NG - 1 - DBL_FRACBITS); - if (round(fe, fp) && fp->fp_mant[2] == DBL_EXP(2)) + if (round(fe, fp, cx) && fp->fp_mant[2] == DBL_EXP(2)) exp++; if (exp >= DBL_EXP_INFNAN) { - fe->fe_cx |= FPSCR_OX; + *cx |= FPSCR_OX; + /* overflow to inf or to max double */ if (toinf(fe, sign)) { - if (fprf) - fe->fe_cx |= FPRF_SIGN(sign) | FPSCR_FU; + *cx |= FPRF_SIGN(sign) | FPSCR_FU; return HI_WORD(sign | DBL_EXP(DBL_EXP_INFNAN) | 0); } - if (fprf) - fe->fe_cx |= FPRF_SIGN(sign); + *cx |= FPRF_SIGN(sign); return HI_WORD(sign | DBL_EXP(DBL_EXP_INFNAN - 1) | DBL_MASK) | LO_WORD(~0); } - if (fprf) - fe->fe_cx |= FPRF_SIGN(sign); + *cx |= FPRF_SIGN(sign); done: return HI_WORD(sign | DBL_EXP(exp) | (fp->fp_mant[2] & DBL_MASK)) | LO_WORD(fp->fp_mant[3]); @@ -519,8 +501,8 @@ void fpu_implode(struct fpemu *fe, struct fpn *fp, int type, uint64_t *p) { u_int *hi, *lo; - int rn; - bool fprf; + int cx, rn; + bool fpscr; hi = (u_int *)p; lo = hi + 1; @@ -529,36 +511,44 @@ fpu_implode(struct fpemu *fe, struct fpn rn = FSR_RD_RZ; else rn = fe->fe_fpscr & FPSCR_RN; - fprf = type & FTYPE_FPRF; + fpscr = type & FTYPE_FPSCR; type &= ~FTYPE_FLAG_MASK; + cx = 0; switch (type) { case FTYPE_LNG: /* FPRF is undefined. */ - *p = fpu_ftox(fe, fp, rn); + *p = fpu_ftox(fe, fp, &cx, rn); DPRINTF(FPE_REG, ("fpu_implode: long %x %x\n", *hi, *lo)); break; case FTYPE_INT: /* FPRF is undefined. */ *hi = 0; - *lo = fpu_ftoi(fe, fp, rn); + *lo = fpu_ftoi(fe, fp, &cx, rn); DPRINTF(FPE_REG, ("fpu_implode: int %x\n", *lo)); break; case FTYPE_SNG: - *hi = fpu_ftos(fe, fp, fprf); + *hi = fpu_ftos(fe, fp, &cx); *lo = 0; DPRINTF(FPE_REG, ("fpu_implode: single %x\n", *hi)); break; case FTYPE_DBL: - *p = fpu_ftod(fe, fp, fprf); + *p = fpu_ftod(fe, fp, &cx); DPRINTF(FPE_REG, ("fpu_implode: double %x %x\n", *hi, *lo)); break; default: panic("fpu_implode: invalid type %d", type); } + + if (fpscr) { + fe->fe_fpscr &= ~(FPSCR_FR | FPSCR_FI | FPSCR_FPRF); + fe->fe_cx |= cx; + if (cx & FPSCR_FI) + fe->fe_cx |= FPSCR_XX; + } }