Overview Features Coding ApolloOS Performance Forum Downloads Products Order Contact

Welcome to the Apollo Forum

This forum is for people interested in the APOLLO CPU.
Please read the forum usage manual.
Please visit our Apollo-Discord Server for support.



All TopicsNewsPerformanceGamesDemosApolloVampireAROSWorkbenchATARIReleases
Documentation about the Vampire hardware

Is This a Bug In the Fpu?

Stephen A.

Posts 24
19 Jun 2018 12:53


i'm not sure if this is a bug in the fpu or not. it might just be lazy programming on my part, but i thought it might be worth mentioning...

i'm trying to debug why the vampire fpu breaks some software that i've written in E and i ran across this anomaly. take this code for instance:

code wrote:

PROC main()
  DEF x, y, z, s[16]:STRING
  x:=8
  y:=6
  z:=!x/y
-> z:=!(x!)/(y!)
  WriteF('\tZ\t= \s\n', RealF(s, z, 8))
ENDPROC

when the vampire fpu is disabled, z returns the correct result -> 1.3333333

when the vampire fpu is enabled, z returns incorrectly -> 1.0000000

also, z returns the correct result with the furia accelerator (with fpu)

however, if you replace line 5 in the above code (z:=!x/y) with the commented line 6 (z:=!(x!)/(y!)) z returns the correct result with both the vampire fpu enabled or disabled.

i'm curious why both versions of the above z equations work with the furia fpu (or fpu in winuae), but only the commented line 6 version of the equation works with the vampire?


Vojin Vidanovic
(Needs Verification)
Posts 1916/ 1
19 Jun 2018 14:30


Seems there are few bugs to squash. Current v2 FPU is reduced precision and with some instructions softcoded, which might give some bad results.

Its explained FPU is ment just "to run software not for science"
EXTERNAL LINK 
I am not sure if this bug was previously reported, some were.

It might improve in future (bugfixing) keeping its limits.

Real and full ApolloFPU comes with v4 Vampires



Gunnar von Boehn
(Apollo Team Member)
Posts 6214
19 Jun 2018 14:34


The Vampire-2 FPGA has a certain size.
This size does not allow fitting the full precision FPU.
 
Therefore the FPU in the Vamp V2 is reduced to make it fit.
Like typical GAME consoles like SONY Playstation 1 / 2 /3 also
use a FPU with "game precision".
 
In 99% of the cases this reduce precision is no problem
and games, demos will just run and look the same.
 
Also your 3D animation e.g with CINEMA 4D or Lighwave renderings look the same.
But there might be rare cases where this is visible.

If you want to spend the extra $ for a FPU with more precision then getting the V4 is what you want.
 
Regarding your question.
I do not know E, and do not know what the difference in your instruction is.
  (z:=!(x!)/(y!))
 
  Can you explain it?
 
 
 
 
 


Stephen A.

Posts 24
19 Jun 2018 16:35


thanks for the info/replies, i'll try to explain the difference...

i'll reference this page: EXTERNAL LINK 
from that link: "The first time a ! occurs in an expression the value of the expression so far is converted to floating-point and all the operators and variables after this point are considered floating-point."

the way that i interpret that statement above, this instruction: z:=!x/y implies z:=8.0/6.0

whereas this instruction: z:=!(x!)/(y!) is just a more explicit or verbose way of writing the same thing... convert both x and y to float (8.0, 6.0), then divide them.

if this is a bug in the fpu and it can be fixed, then thats great. if not, i understand... but i guess it would lead me to ask a couple of questions:

in the 2.9 core its not possible to disable the fpu. will it be possible to disable it again in future cores (ie, 3.0)?

if it will not be possible to disable the fpu in future cores, then will earlier cores (2.8) be updated with current registration numbers so that hdmi works in color?

thanx!


Gunnar von Boehn
(Apollo Team Member)
Posts 6214
19 Jun 2018 17:54


Stephen A. wrote:

  the way that i interpret that statement above, this instruction: z:=!x/y implies z:=8.0/6.0

can you show the created ASM for this?


Stephen A.

Posts 24
19 Jun 2018 20:01


i don't know assembly and the E compiler doesn't have an option to compile assembly source...

but i can provide binaries that can maybe be disassembled.

i've put them here: EXTERNAL LINK 
i've put both versions of the code i posted.

whats included:

xy -> binary of !x/y that doesn't work with the vampire fpu
xy.e -> source
xy.out -> disassembled binary? E has a utility called showhunk that has a disasm option. i'm assuming its a disassembler of some kind

xy2 -> binary of z:=!(x!)/(y!)
xy2.e -> source
xy2.out -> disassembled?

i hope that helps!


Louis Dias
(Needs Verification)
Posts 55/ 1
19 Jun 2018 21:47


I believe the ! casts something as a float and something like a # could be used to cast as an integer or a $ for a string.

Hence, your X/Y (integer divide assumed) results as 1 then is cast to a float with the ! at the beginning.  It's an order of operations effect.


Samuel Devulder

Posts 248
19 Jun 2018 23:30


Yeah, it looks like
1) on the vamp 8/6 is interpreted as an int division (result is 1) which is later transformed as 1.0 (float "one") by the "!" operator.
2) on the furia !8/6 is interpreted as (!8) first resulting in 8.0 (8 as float) which is later divided by the integer 6, resulting in float 1.33333..
To sum up apparently it seem that !x/y is interpreted
1) as !(x/y) on the vamp, and
2) as (!x)/y on the furia.

I doubt this is FPU related. Operator precedence is typically governed by integer operation. To confirm I tried to look at the disasm code provided in the link. Unfortunately the disassembler didn't know of FPU opcodes, resulting in unreadable disassembly. :-(

To know which from interpretation 1) or 2) is good, the knowled of an E expert about operator precedence might be valuable. May be it is the Furia result which is wrong.


Samuel Devulder

Posts 248
19 Jun 2018 23:34


Yeah, it looks like
    1) on the vamp 8/6 is interpreted as an int division (result is 1) which is later transformed as 1.0 (float "one") by the "!" operator.
    2) on the furia !8/6 is interpreted as (!8) first resulting in 8.0 (8 as float) which is later divided by the integer 6, resulting in float 1.33333..
 
To sum up apparently it seem that !x/y is interpreted
    1) as !(x/y) on the vamp (division has precedence), and
    2) as (!x)/y on the furia (conversion to float has precedence).
   
I doubt this is FPU related. Operator precedence is typically governed by integer operations, but the test with fpu enabled/disabled seem to indicate the code behaves differently whenever the fpu is in action or not. To confirm I tried to look at the disasm code provided in the link. Unfortunately the disassembler didn't know of FPU opcodes, resulting in unreadable disassembly. :-(
   
   
Notice that this is all assuming that "!" is a real operator with a real definite precedence. This assumption might be completely wrong since in the code "!" is both used as a prefix (in !x/y) or as a postfix (in (x!)/(y!)).
 
([edit] sorry for the duplicate answer.. I can't delete the previous one :( )


Stephen A.

Posts 24
19 Jun 2018 23:43


Samuel Devulder wrote:

  Yeah, it looks like...

May be it is the Furia result which is wrong.
 


 
  all of that makes good sense :)
 
  it should probably also be noted that !x/y on a stock 68k with no accelerator or fpu results in the proper result 1.33333...


Samuel Devulder

Posts 248
20 Jun 2018 07:44


Actually the key-feature is that the very same exe works differently on the vamp depending on fpu being active or not. I really wonder how the E compiler encode the operation and how it is affected by fpu being real or emulated by system-libraries.


Andrew Copland

Posts 113
20 Jun 2018 11:18


Stephen A. wrote:

Samuel Devulder wrote:

  Yeah, it looks like...
 
 
  May be it is the Furia result which is wrong.
 

 
  all of that makes good sense :)
 
  it should probably also be noted that !x/y on a stock 68k with no accelerator or fpu results in the proper result 1.33333...

I doubt that the Furia is wrong, if using the 68882 then it is canonically correct for existing software.

In C an equivalent group of forced precedence tests might be something like:

int x=8, y=6;
float result_idivi = (float)(x / y);
float result_fdivi = (float)(((float)x) / y);
float result_idivf = (float)(x / ((float)y));
float result_fdivf = (float)(((float)x) / ((float)y));

That way you can test the differences across a range of ordering operations.

posts 12