Module Name:    src
Committed By:   rin
Date:           Wed Dec 28 10:52:30 UTC 2016

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

Log Message:
PR port-powerpc/51368: powerpc FPU emulation fails for single precision
floating point arithmetic

For single precision instruction, calculate first in double precision,
and then round it. With this fix, single precision arithmetic gets sane
on ibm4xx and booke.

Taken from FreeBSD commit r258250:
  https://svnweb.freebsd.org/base?view=revision&revision=258250

Ok matt and simonb.


To generate a diff of this commit:
cvs rdiff -u -r1.18 -r1.19 src/sys/arch/powerpc/fpu/fpu_emu.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.18 src/sys/arch/powerpc/fpu/fpu_emu.c:1.19
--- src/sys/arch/powerpc/fpu/fpu_emu.c:1.18	Thu Dec 15 11:32:03 2016
+++ src/sys/arch/powerpc/fpu/fpu_emu.c	Wed Dec 28 10:52:30 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: fpu_emu.c,v 1.18 2016/12/15 11:32:03 rin Exp $ */
+/*	$NetBSD: fpu_emu.c,v 1.19 2016/12/28 10:52:30 rin Exp $ */
 
 /*
  * Copyright 2001 Wasabi Systems, Inc.
@@ -76,7 +76,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: fpu_emu.c,v 1.18 2016/12/15 11:32:03 rin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: fpu_emu.c,v 1.19 2016/12/28 10:52:30 rin Exp $");
 
 #include "opt_ddb.h"
 
@@ -626,9 +626,11 @@ fpu_execute(struct trapframe *tf, struct
 			rb = instr.i_a.i_frb;
 			rc = instr.i_a.i_frc;
 
-			type = FTYPE_SNG;
-			if (instr.i_any.i_opcd & 0x4)
-				type = FTYPE_DBL;
+			/*
+			 * All arithmetic operations work on registers, which
+			 * are stored as doubles.
+			 */
+			type = FTYPE_DBL;
 			switch ((unsigned int)instr.i_a.i_xo) {
 			case	OPC59_FDIVS:
 				FPU_EMU_EVCNT_INCR(fdiv);
@@ -745,6 +747,13 @@ fpu_execute(struct trapframe *tf, struct
 				return (NOTFPU);
 				break;
 			}
+
+			/* If the instruction was single precision, round */
+			if (!(instr.i_any.i_opcd & 0x4)) {
+				fpu_implode(fe, fp, FTYPE_SNG, 
+					(u_int *)&fs->fpreg[rt]);
+				fpu_explode(fe, fp = &fe->fe_f1, FTYPE_SNG, rt);
+			}
 		}
 	} else {
 		return (NOTFPU);

Reply via email to