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);