Code-Beispiel
FPU check
Lizenz: | Erster Autor: | Letzte Bearbeitung: |
LGPL | Volta | 26.11.2015 |
Nur 32 Bit
Wozu braucht man das?
Berechtigte Frage, eigentlich nur wenn man mit FPU-ASM-Befehlen experimentiert.
Was macht der FPU_check?
Er sichert in einem 512 Byte - Array relevante Daten der FPU ohne sie zu ändern.
Ausgewertet erhält man einen Überblick wie der konkrete Zustand der FPU ist.
FPU_check.bas :
' "FPU_check.bas" by Volta 16.01.2008
' Idee aus:
'- FPU-Helferlein
'- "Helle" Klaus Helbing, 12.08.2007, PB4.02
' http://www.purebasic.fr/german/viewtopic.php?t=13878
Union ext
As ULongInt fli(0 To 2-1)
As Double fd
End Union
Type fx_save Field = 2
As UShort FPUCW
As UShort FPUSW
As UByte Tag
As UByte resTag
As UShort Opcode
As ULongInt res0h
As ULongInt res1l
As ULongInt res1h
As ext FST(0 To 8-1)
As ULongInt res(0 To 44-1)
End Type
Dim Shared As fx_save xsave
Sub FPU_check ()
Asm
lea esi, [xsave]
fxsave [esi] '512 Byte in -> xsave sichern
fwait
fld tbyte Ptr[esi+32] 'ST(0)|MM0 -> xsave.FST(0).fd
fstp qword Ptr[esi+32]
fld tbyte Ptr[esi+48] 'ST(1)|MM1 -> xsave.FST(1).fd
fstp qword Ptr[esi+48]
fld tbyte Ptr[esi+64] 'usw
fstp qword Ptr[esi+64]
fld tbyte Ptr[esi+80]
fstp qword Ptr[esi+80]
fld tbyte Ptr[esi+96]
fstp qword Ptr[esi+96]
fld tbyte Ptr[esi+112]
fstp qword Ptr[esi+112]
fld tbyte Ptr[esi+128]
fstp qword Ptr[esi+128]
fld tbyte Ptr[esi+144] 'ST(7)|MM7 -> xsave.FST(7).fd
fstp qword Ptr[esi+144]
fwait
End Asm
Dim As Integer i,x
Dim As UByte b = 128
Print "------FPU_check------"
Print "FPU - Register"
Print "Controlword = ";Hex(xsave.FPUCW,4)
Print "Statusword = ";Hex(xsave.FPUSW,4)
x = (xsave.FPUSW And &h3800) Shr 11
For i = 0 To 7
If i = x Then
Print "TOS "; 'Top of stack
Else
Print " ";
End if
Print "ST(" & i & ") ";
If (xsave.Tag And b) Then
Print "Belegt ="; 'locked
Else
Print " Frei ="; 'free
End If
Print xsave.FST(i).fd
b\=2
Next
Print "----------------Ende-"
End Sub
Ausgabe:
------FPU_check------
FPU - Register
Controlword = 037F
Statusword = 0220
TOS ST(0) Frei = 0
ST(1) Frei = 0
ST(2) Frei = 0
ST(3) Frei = 0
ST(4) Frei = 0
ST(5) Frei = 1
ST(6) Frei = 6919435305.535846
ST(7) Frei = 6919435305.535846
----------------Ende-
Controlword, Statusword, TOS (Top of stack) und der Inhalt aller Register wird angezeigt.
Zusätzlich wird angezeigt ob die Register "Belegt" oder "Frei" sind, wichtig, da ein belegtes Register nicht überschrieben werden kann.
Die nachfolgende Funktion x_Pow(y) (=x^y) war der Anlass den FPU_check zu schreiben.
Sah elegant aus und arbeitete recht schnell aber nach mehrfachem Aufruf gab es nur noch falsche Ergebnisse.
Fehler_check.bas :
'Fehlertest mit FPU_check by Volta 16.01.2008
#Include "FPU_check.bas"
Function x_Pow(a As Double,b As Double) As Double
Asm
fld qword Ptr [b] 'st(0) = b
fld qword Ptr [a] 'st(0) = a ;st(1) = b
fyl2x 'st(0) = ln(a)*b
fst st(1) 'in st(1) kopieren
frndint 'st(0) runden = Integer-Anteil
fsub st(1),st(0) 'st(1) Vorkommaanteil auf 0 setzen
fld1 '1 laden
fscale 'temp:= 2 hoch Integer-Anteil
fld st(2) 'Nachkommaanteil laden
f2xm1 '2 hoch Nachkommaanteil -1
fld1 '1 laden
faddp st(1),st(0) '+1
fmulp st(1),st(0) '*temp
'fstp st(1)
'fstp st(1)
fstp qword Ptr [Function]
End Asm
End Function
Dim j As Integer
Dim As Double x=8.2123, n=-3.1,y
y=x^n
FPU_check
?y
Sleep
?
For j = 1 To 10
y=x_Pow (x,n)
FPU_check
?y
Sleep
Next j
Print "verdisch.."
Sleep
Es stellte sich heraus, dass nicht alle Werte vom Stack der FPU entfernt wurden und einige Register gesperrt blieben.
Macht der FBC auch solchen Unsinn?
'Test FBC mit FPU_check by Volta 16.01.2008
#Include "FPU_check.bas"
FPU_check
Sleep
Cls
Dim As Double x=3.2, y=4.76
x=x+y
FPU_check
Print x
Sleep
x=Sin(y)
FPU_check
Print x
Sleep
x=Sqr(y)
FPU_check
Print x
Sleep
x=Exp(y)
FPU_check
Print x
Sleep
x=x^y
FPU_check
Print x
Print "verdisch.."
Sleep
End
Nein, sauber programmiert!
Zusätzliche Informationen und Funktionen | |||||||
---|---|---|---|---|---|---|---|
|