Subject: floating point on Nevada cpu

From: Pete Popov <[email-masked]>
Date: Wed, 24 Jan 2001 18:28:54 -0800

This simple test fails on a Nevada (5231) cpu:

int main()
{
    float x1,x2,x3;

    x1 = 7.5;
    x2 = 2.0;
    x3 = x1/x2;
    printf("x3 = %f\n", x3);
}

Has anyone else used floating point with 52xx processors?

Pete

---

From: Justin Carlson <[email-masked]>
Date: Wed, 24 Jan 2001 18:33:05 -0800

> This simple test fails on a Nevada (5231) cpu:

Ummm...care to tell *how* it fails?

-Justin

---

From: Pete Popov <[email-masked]>
Date: Wed, 24 Jan 2001 18:52:16 -0800

> Ummm...care to tell *how* it fails?

Here it is:

sh-2.03# ./fl
x3 = 0.000000

I'm running a test9 based kernel, but the same kernel compiled for my
Indigo2 produces the right result.  Also, the uptime commands complains
with:

Unknown HZ value! (2147483647) Assume 100.

At the console, I get "Setting flush to zero for uptime."  So, I took a
look at arch/mips/kernel/traps.c and the kernel retries the instruction
with denormalized instructions flushed to zero. However, the 5200
signals an unimplemented operation even if the FS bit is set. 

In any case, the first simple test doesn't run into the "flush to zero"
problem but the result is still bad.

Pete

---

From: Pete Popov <[email-masked]>
Date: Wed, 24 Jan 2001 19:05:56 -0800

> Ummm...care to tell *how* it fails?

Looks like there's something more basic that fails here.  This:

#include <stdio.h>
int main()
{
    float x1,x2,x3,x4,x5;

    x1 = 7.5;
    x2 = 2.0;
    x3 = x1/x2;
    x4 = x1*x2;
    x5 = x1-x2;
    printf("x1 %f x2 %f x3 %f x4 %f x5 %f\n", x1, x2, x3, x4, x5);
}

produces this:

sh-2.03# ./fl 
x1 0.000000 x2 0.000000 x3 0.000000 x4 0.000000 x5 0.000000

Pete

---

From: Justin Carlson <[email-masked]>
Date: Wed, 24 Jan 2001 18:57:04 -0800

On Wed, 24 Jan 2001, you wrote:
> Indigo2 produces the right result.  

Hmmm...the only thing here that should involve kernel support is the lazy FPU
register saving.   I'm not terribly familiar with that portion of the kernel,
but it should take an unimplemented instruction trap on the first fpu op, set
up a flag for saving FP state on context switches, enable the FPU, then let the
program run.  From what I *have* seen of that code, it's shared between many
processors; doesn't seem like a likely candidate for such a simple problem.

If you compile that code snippet and optimize it with gcc, you actually won't
invoke any fpu ops, as gcc is smart enough to precalculate the result, and
just load that before jumping to printf().

How are you compiling the code?  And are you compiling it the same way on both
platforms?  Do you have fpu emulation enabled on a kernel that doesn't need it? 

These are the potential problems that jump to mind...

-Justin

---

From: Justin Carlson <[email-masked]>
Date: Wed, 24 Jan 2001 19:16:04 -0800

> x1 0.000000 x2 0.000000 x3 0.000000 x4 0.000000 x5 0.000000

Try this:

int main()
{
	printf("%f\n", (float)3.14159);
}

If *that* fails, check your libraries and make sure the calling conventions,
etc. match what you think they should be...

-Justin

---

From: Steve Johnson <[email-masked]>
Date: Thu, 25 Jan 2001 07:54:53 -0700

Pete,

    We had a problem in user-space apps all showing 0 for floating-point
results because we hadn't set the ST0_FR bit to 0, and we had a mis-match
between user libraries (MIPS3k-compatible) and the floating point registers.
We noticed the problem when we couldn't run "ps" or "rm" correctly and tracked
it down from some old postings by Ralf and friends.  Maybe this is your
problem, too?

    I added this to our setup call:

    set_cp0_status(ST0_FR, 0);

    Steve

---

From: Pete Popov <[email-masked]>
Date: Thu, 25 Jan 2001 10:02:10 -0800

Steve,

>     set_cp0_status(ST0_FR, 0);

Problem solved before I finished my first cup of coffee. Thanks!

I bet this problem will show up here and there depending on how the boot
code sets cp0.  Seems like adding the above line in a mips generic init
routine would be a good thing.

Pete

---

From: Ralf Baechle <[email-masked]>
Date: Thu, 25 Jan 2001 09:26:01 -0800

> 	printf("%f\n", (float)3.14159);

Note that above cast is useless; in C all floats are implicitly converted
to doubles for passing to a varargs function.

  Ralf

---

From: Justin Carlson <[email-masked]>
Date: Thu, 25 Jan 2001 12:01:05 -0800

> to doubles for passing to a varargs function.

Yah, I remembered this after I sent it.  I sometimes get confused with K&R
rules on promotion vs. ANSI, and forgot the varargs handling...

>All MIPS FPUs need it; the architecture specification leaves it to the
>implementor of a CPU which parts of the FP architecture are implemented
>in hardware if at all; the missing parts have to be replaced in
>software.

And here I was remembering the i386 FPU configuration options.  Just spewing
all sorts if incorrect information today!  <sigh>

Thanks for the corrections,
-Justin

---

From: Ralf Baechle <[email-masked]>
Date: Thu, 25 Jan 2001 14:12:31 -0800

> Has anyone else used floating point with 52xx processors?

Cobalt Qube since '97.  It's working :-)

  Ralf

---

From: Carsten Langgaard <[email-masked]>
Date: Fri, 26 Jan 2001 08:53:25 +0100

I have been run on a QED RM5261 for quite some time now.
Notice that even it got a FPU, you need to enable the FP emulator to be
fully IEEE compliant.

/Carsten

--
_    _ ____  ___   Carsten Langgaard   Mailto:[email-masked]
|\  /|||___)(___   MIPS Denmark        Direct: +45 4486 5527
| \/ |||    ____)  Lautrupvang 4B      Switch: +45 4486 5555
  TECHNOLOGIES     2750 Ballerup       Fax...: +45 4486 5556
                   Denmark             http://www.mips.com

---

From: "Kevin D. Kissell" <[email-masked]>
Date: Fri, 26 Jan 2001 11:14:38 +0100

> routine would be a good thing.

I had essentially the same problem at MIPS a year or two ago,
and I could have *sworn* that my fix, which ORed ST0_FR into
the initial Status register value set in the startup assembly code,
had made it into the standard distributions.  It's at about line 530
of head.S, where a term is added to make the instruction

li t1,~(ST0_CU1|ST0_CU2|ST0_CU3|ST0_KX|ST0_SX|ST0_FR)

I spent days thinking it was a mipsel library problem,
because it only turned up when I tried exercising a
little-endian version of the same kernel that worked
sell big-endian on the Indy.  But of course it was all
due to the mipsel system having a boot-prom that
cleverly enabled all the FP registers for me...

            Kevin K.

---

From: Steve Johnson <[email-masked]>
Date: Fri, 26 Jan 2001 06:01:12 -0700

> cleverly enabled all the FP registers for me...

Kevin,

    Your/Flo's/Ralf's thread in the MIPS Linux archives from last January was
what clued me into the ST0_FR setting in the first place.  Ralf gave arguments
why he wouldn't take your change at that time, which is why that line isn't in
the 2.4.x kernel.

    Steve

---

From: "Kevin D. Kissell" <[email-masked]>
Date: Fri, 26 Jan 2001 14:57:08 +0100

> why he wouldn't take your change at that time, which is why that line
isn't in

Yeah, and I still think they are piss-poor arguments.  ;-)

I still do not see much virtue in saying that one has a binary
kernel that supports either FR=0 or FR=1, *provided*
that the entire userland from init inward is built with the same
"polarity" *and* that the boot monitor is  guaranteed to have
set FR the right way before launching the kernel.  FR=0 (o32)
and FR=1 (n32, n64) binaries should be distinguishable at
exec() time, and the FR bit set appropriately at
that time.  Making assumptions  about what the bootloader
or bootprom has done is just plain foolish, IMHO.

            Kevin K.

---

From: Ralf Baechle <[email-masked]>
Date: Sat, 27 Jan 2001 11:16:38 -0800

> li t1,~(ST0_CU1|ST0_CU2|ST0_CU3|ST0_KX|ST0_SX|ST0_FR)

It's not in the CVS 2.2 kernel.  I've added this patch to my kernel and
will commit it when I'm online again.

  Ralf