NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

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



>Number:         51368
>Category:       port-powerpc
>Synopsis:       powerpc FPU emulation fails for single precision floating point arithmetic
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    port-powerpc-maintainer
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Wed Jul 27 15:10:01 +0000 2016
>Originator:     Rin Okuyama
>Release:        HEAD
>Organization:
Faculty of Science and Technology, Keio University
>Environment:
NetBSD obs266 7.99.34 NetBSD 7.99.34 (OPENBLOCKS266) #1: Wed Jul 27 22:09:26 JST 2016  rin@XXX:XXX evbppc
>Description:
FPU emulation of powerpc fails for single precision floating point
arithmetic. On a machine without FPU (e.g., ibm4xx like
evbppc/OPENBLOCKS266),

====================
  % cat fp.c
  #include <stdio.h>
  int main(){
          double dx = 1.0, dy = 2.0;
          float  sx = 1.0, sy = 2.0;
          printf("DP: %f / %f = %f\n", dx, dy, dx / dy);
          printf("SP: %f / %f = %f\n", sx, sy, sx / sy);
          return 0;
  }
  % cc fp.c && ./a.out
  DP: 1.000000 / 2.000000 = 0.500000
  SP: 1.000000 / 2.000000 = 0.003906
====================

This failure triggers corrupted display output of X clients, e.g., xterm
or oclock, where single precision calculation is utilized.
>How-To-Repeat:
Described above.
>Fix:
FreeBSD also uses FPU emulation codes derived from ours, and they fixed
this bug by commit r258250:

====================
  https://svnweb.freebsd.org/base?view=revision&revision=258250

  Make single precision floating point arithmetic actually work -- I think
  it never did -- and fix an obvious missing line. Floating point emulation
  on Book-E still needs some work but this gets it basically functional on
  soft-FPU systems (hard FPU for Book-E is not yet implemented).

  MFC after:	1 week
====================

With this fix, X clients as well as the test above works fine.

====================
--- src/sys/arch/powerpc/fpu/fpu_emu.c.orig	2016-07-27 10:04:00.737524067 +0900
+++ src/sys/arch/powerpc/fpu/fpu_emu.c	2016-07-27 10:03:44.803486129 +0900
@@ -626,9 +626,11 @@
 			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 @@
 				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);
--- src/sys/arch/powerpc/fpu/fpu_explode.c.orig	2016-07-27 10:00:01.060507066 +0900
+++ src/sys/arch/powerpc/fpu/fpu_explode.c	2016-07-27 10:00:12.431852649 +0900
@@ -235,6 +235,7 @@
 		s = fpu_dtof(fp, s, space[1]);
 		break;
 
+	default:
 		panic("fpu_explode");
 		panic("fpu_explode: invalid type %d", type);
 	}
====================



Home | Main Index | Thread Index | Old Index