Hallo zusammen,
ich spiele mit dem ARM-Assembler unter DAVE4 für einen Cortex M4f.
Ich versuche mit VMOV eine Konstante zu laden, dabei stoße ich auf
folgendes Problem:
VMOV.F32 s1, #0.25 // funktioniert!
VMOV.F32 s1, #0.26 // funktioniert nicht!
Ich denke, dass es daran liegt, dass sich 0.26 nicht genau mit einem F32
nachbilden lässt.
Gibt es einen Trick, mit dem man dem Assembler mitteilt, dass der die
nächstmögliche F32-Darstellung der Zahl verwendet?
Ich habe das Manual so interpretiert, dass er das auch ohne zusätzliche
Anweisung machen würde, tut er aber wohl nicht...
Also habe ich habe nach einer Art Rundungsderektive gesucht, bin aber
nur auf die gleiche Frage gestoßen.
Wie ist der Trick hierfür?
Gruß Stephan
Stephan schrieb:> Ich denke, dass es daran liegt, dass sich 0.26 nicht genau mit einem F32> nachbilden lässt.
Kleine Pingeligkeit: Es lässt sich überhaupt nicht mit
Binär-Floating-Point darstellen, egal wie viele Bits ;-) Ist so wie 1/3
sich nicht mit Dezimalzahlen darstellen lässt, egal wie viele...
Also, lautet die Analyse so:
1. Die Zahl ist in den Beschränkungen des Assemblers nicht als Float
darstellbar. +/– n * 2–r,where n and r are integers, 16 <= n <= 31, 0 <=
r <= 7
2. Der C-Preprozessor ist zwar verwendbar, kann aber nicht mit Floats
umgehen. Daraus folgt, dass es auch kein Macro geben kann, dass diese
Rundung durchführt.
Das ist also vermutlich unter "funktioniert nicht" zu verstehen.
Man könnte also allenfalls (das ist nur so eine Idee) der Nachkommateil
als Integer darstellen und damit was basteln. D.h. aus 0.26 die Zahl 26
machen und dem Macro noch den Faktor mitgeben (also 100).
Die nächstliegenden Zweierpotenzen sind 64 und 128 - für 0.01; den Teil
der 1/100 entsprich.
1/64 = 0.0156
1/128 = 0.00781
Die Differenz zu 0.01 ist bei 1/128 geringer. Also nimmt man das.
Voilà.
Die Bemerkung, dass, sich sowas auszudenken im wesentlichen dem
enspricht, was man "programmieren" nennt, erspare ich mir.
Dr. Sommer schrieb:> Stephan schrieb:>> Ich denke, dass es daran liegt, dass sich 0.26 nicht genau mit einem F32>> nachbilden lässt.> Kleine Pingeligkeit: Es lässt sich überhaupt nicht mit> Binär-Floating-Point darstellen, egal wie viele Bits ;-) Ist so wie 1/3> sich nicht mit Dezimalzahlen darstellen lässt, egal wie viele...
Widerspruch: 1/4, 1/2, 1.0 u.v.m. lassen sich sowohl im Dezimalsystem
als auch im IEEE-Float32-Format mit einer endlichen Anzahl an Stellen
exakt abbilden. :-)
Das Problem ist, dass der Assembler die Befehlszeile nicht akzeptiert
und den Fehler "garbage following instruction" wirft.
Im ARM-Infocenter für den ARM Compiler habe ich die Fußnote
"Any number that can be expressed as +/-n * 2-r, where n and r are
integers, 16 <= n <= 31, 0 <= r <= 7." gefunden.
Das bestätigt schonmal die Annahme bzgl. der Ursache...
Gibt es bei den GCC keine Hilfsfunktion, die die (fehlerträchtige)
Konvertierung/Rundung einer Zahl in eine vom Assembler akzeptierte
Hex/Bin-Darstellung übernimmt?
Der GCC-C-Compiler muss das bei "float32_t K = 0.26" schließlich auch
vornehmen.
Stephan
"Die Bemerkung, dass, sich sowas auszudenken im wesentlichen dem
enspricht, was man "programmieren" nennt, erspare ich mir."
Du tust gut daran! Davon auszugehen, dass für ein Standardprobleme, die
sehr fehlerträchtig sein können, die Lösung nicht bereits in dem
verwendeten Werkzeug vorhanden ist, führt oft zu massiven Fehlern und
stellt einen nicht unerheblichen Zeitaufwand dar.
Stephan schrieb:> "Die Bemerkung, dass, sich sowas auszudenken im wesentlichen dem> enspricht, was man "programmieren" nennt, erspare ich mir.">> Du tust gut daran! Davon auszugehen, dass für ein Standardprobleme, die> sehr fehlerträchtig sein können, die Lösung nicht bereits in dem> verwendeten Werkzeug vorhanden ist, führt oft zu massiven Fehlern und> stellt einen nicht unerheblichen Zeitaufwand dar.
Ja, ja, Meister. Du hast nur gefragt, weil Du Langeweile hattest. Schon
klar.
Für alle, die diesen Beitrag irgendwann mal ausgraben:
Const_1: .float 0.26
...
VLDR.32 s1, Const_1
Hier wird der Wert der Konstante zwar aus dem Speicher geladen und nicht
als Immediate, dafür bleibt der Quellcode gut lesbar; man muss nicht mit
den Hex-Darstellungen der Floats hantieren.
http://infocenter.arm.com/help/topic/com.arm.doc.dui0553a/CHDICEDI.html
Der Assembler des ARM-Toolchains für NEON kennt eine gleichnamige
Pseudo-Anweisung
VLDR.32 s0,=const
die (falls möglich) in eine einzelne VMOV-Anweisung übersetzt wird.
http://infocenter.arm.com/help/topic/com.arm.doc.dui0489f/CIHGGHHA.html
Der GCC-Assembler von DAVE4 scheint dies nicht zu tun. Unabhägig vom
Wert der Konstanten wurde bei mir
VLDR.32 s0,=const (Quelltext)
stets in
vldr s0, [r0]
übersetzt.
Evtl. hilft es jemand...
Gruß Stephan
Danke Stefan,
vor vielen Jahren habe ich die FPU auch zum ersten mal eingesetzt und
muste auch feststellen, dass nicht jede Zahl als direkte Angabe
funktioniert.
Mann muss nur in der Dokumentation bei ARM nachlesen, dann sieht man
sofort, das es sehr eingeschränkt ist.
Also bleibt nur das laden eines Prozessorregister in ein FPU-Register
oder die elegantere Art, die Stefan zeigt übrig. Das indirekte laden
PC+rel ist durchaus sehr gut.
Nur nicht vergessen, irgendwo müssen die Daten dann auch im ROM sein.
deshalb am Ende der Routine noch ein .LTORG setzen, ab da werden dann
die Daten gespeichert.
Übrigens finde ich die FPU sehr gelungen, auch für DSP übrigens spitze
zu verwenden.
Werde mal diese Woche die FPU eines CM7 von ST mit 64 Bit ausprobieren.
Mal sehen wie schnell die ist?
Gruß Sascha
FPU in Assembler ist einfach wie ein Gedicht....