Blueberry
Member |
Hi ADA-folks!
There has been some talk around here about the FPU emulation bugs in WinUAE. I thought they deserved their own thread, so I will start out by describing how I work around some of them...
The most serious bugs in the FPU emulation (that I have encountered) are in the float to int conversion, in the fmove.b/w/l fpn,<ea> instruction.
Here is how it works on a real Amiga:
If the float value is not an integer, it is rounded to the nearest integer. If it is exactly between two integers, the even one is chosen.
If the value is outside the range representable by the integer size of the instruction, it is set to the largest (if larger) or smallest (if smaller) value representable.
This resulting value is put into the target integer.
Now, here is how WinUAE does it:
If the value is not an integer, the decimals are chopped off, i.e. it is rounded towards zero.
If the value is outside the range representable by the target, it wraps around, i.e. for an n-bit integer, the lowest n bits of the exact integer value are taken.
Needless to say, this incorrect rounding and clamping causes lots of trouble.
So, here is how I deal with it: I always do float to int conversion using a macro, and then the macro expands to different code depending on the value of a WINUAE define (indicating whether I am assembling for testing on WinUAE). Here is what I have come up with:
f2i_clamp macro ; FPx,Dy,bottom,top,size
if WINUAE
move.w ccr,-(a7)
clr.\5 -(a7)
fmovem.x fp0/fp1,-(a7)
move.l d0,-(a7)
fmove \1,fp1
fblt .neg\@
fadd.s #0.5,fp1
bra.b .ok\@
.neg\@: fsub.s #0.5,fp1
.ok\@: fmove fp1,fp0
fcmp.d #\3,fp0
fbge .bottom\@
fmove.d #\3,fp0
.bottom\@: fcmp.d #\4,fp0
fble .top\@
fmove.d #\4,fp0
.top\@: fmove.\5 fp0,d0
fmove.\5 d0,fp0
fcmp fp0,fp1
fbne .nothalf\@
rol.\5 #1,d0
addq.\5 #1,d0
asr.\5 #1,d0
and.\5 #-2,d0
.nothalf\@: move.\5 d0,28(a7)
move.l (a7)+,d0
fmovem.x (a7)+,fp0/fp1
move.\5 (a7)+,\2
move.w (a7)+,ccr
else
fmove.\5 \1,\2
endc
endm
f2i.b macro ; FPx,Dy
f2i_clamp \1,\2,-128,127,b
endm
f2i.w macro ; FPx,Dy
f2i_clamp \1,\2,-32768,32767,w
endm
f2i.l macro ; FPx,Dy
f2i_clamp \1,\2,-2147483648,2147483647,l
endm
As far as I can see, it handles all input values and all forms of the instruction except pushing the value onto the stack. Onto the stack works if the condition code saving is removed, but then condition codes aren't right. Not obvious how to have both possibilities (without using a global variable).
Any comments? Something I have missed? Any smarter way to do it? ;-)
Of course, I ought to put this in a WinUAE bug report. Although last time I mentioned it, Toni didn't seem particularly keen to fix it. Thought is was more of a missing feature than an actual bug. Oh well...
Any other emulation bugs that people want to complain about? :-)
|
Blueberry
Member |
Damn you Toni! ;)
From the WinUAE 1.4.1 sources:
m68k_dreg (regs, reg) = (uae_u32)(((toint(value, -32768.0, 327676.0) & 0xffff) | (m68k_dreg (regs, reg) & ~0xffff)));
:-O
So, Cefa, you are absolutely right - your code gives the wrong result. More precisely, the upper-bound clamping for word-sized conversions is wrong when executed in interpreted mode. Byte and long conversions and all conversions in the JIT seem to be fine (note that the first few times some code is executed, it is interpreted, even when JIT is enabled).
I guess it is time for a little mail to Toni... Should be in time for the 1.4.2 release.
|