Hallo ihr Wissenden,
für die Initialiserung einer konstanten LUT habe ich eine
Initialiserungfunktion in VHDL geschrieben. Die Werte müssen mithilfe
vom Datentyp REAL berechnet werden. Das Ergebnis wird dann gerundet und
als SIGNED in der LUT gespeichert und synthetisiert.
Der Cast wird aktuell folgendermaßen durchgeführt:
romLUT(i) := to_signed(integer(round(temp)), romLUT(0)'length);
Das funktioniert natürlich nur, wenn die Zahl auch in den Zahlenbereich
von int32 passt, da integer in VHDL immer 32 bit haben, wenn ich das
richtig im Kopf habe.
Gibt es eine Möglichkeit die Tabelle auch für größere Bitbreiten in VHDL
zu berechnen oder komme ich um eine in MATLAB/Python/C berechnete
Tabelle die ich hard codiere nicht herum?
Da ich kein Freund von "Magic Numbers" bin, wäre es schön wenn der
Inhalt der Tabelle dort berechnet wird, sodass man beim Lesen des Codes
die Zusammenhänge versteht. Klar kann man das auch mit einem Kommentar
neben der Tabelle erreichen. Meist wird dann später aber nur die
Tabelle, aber nicht der Kommentar auf Stand gehalten (wir leben leider
nicht in einer idealen Welt).
Viele Grüße
Verwunderter
Verwunderter schrieb:> romLUT(i) := to_signed(integer(round(temp)), romLUT(0)'length);
Wenn ein 32-bit integer nicht reicht, dann nimmst Du eben zwei?
math_real bringt eine MOD-Funktion für REALs mit, mit dem Du das
Ergebnis deiner Berechnung in einen "High"- und einen "Low"-Integer
aufteilen kannst.
Nach der Konvertierung in signed klebst Du das Ergebnis wieder zusammen.
Verwunderter schrieb:> da integer in VHDL immer 32 bit haben, wenn ich das richtig im Kopf habe.
Sie haben "mindestens" 32 Bit. Und keiner der Synthesizerbauer hat es
geschafft, mehr als das Mindeste abzuliefern...
> Gibt es eine Möglichkeit die Tabelle auch für größere Bitbreiten in VHDL> zu berechnen
Wandle sie mit deiner eigenen Funktion direkt von real nach signed.
Markus F. schrieb:> math_real bringt eine MOD-Funktion für REALs mit
Wenn das angesichts der lausigen Genauigkeit einer real-Zahl nur nicht
in die Hosen geht.
Lothar M. schrieb:> Markus F. schrieb:>> math_real bringt eine MOD-Funktion für REALs mit> Wenn das angesichts der lausigen Genauigkeit einer real-Zahl nur nicht> in die Hosen geht.
Scheint mir eher nicht so relevant. Wenn ich das richtig sehe, will der
TO hier ja eigentlich nur die Nachkommastellen abschneiden.
Spricht erstmal etwas dagegen das so zu machen? Wo hat der Test
Schwachstellen?
Die Integer Werte für die ich die Funktion nutzen werde werden immer in
weniger als 50 Bit passen.
Viele Grüße
Verwunderter
Verwunderter schrieb:> Spricht erstmal etwas dagegen das so zu machen? Wo hat der Test> Schwachstellen?
Ja, so hätte ich mir das vorgestellt.
Das einzige Manko (hat aber nichts mit deiner Umsetzung zu tun) ist,
dass ghdl bei Iteration 32 schlapp macht (während modelsim prima alle 54
Durchläufe korrekt bewältigt). Interessant, das.
Test failed at: -90194313216 input: -9.0194313216e10 bits: 1111111111111111111111111110101000000000000000000000000000000000
Da hat sich ein Bit eingeschmuggelt, das da nicht hingehört
Sieht auf den ersten Blick so aus, als ob ghdl nur mit extended anstatt
mit double rechnen würde, die real range scheint aber etwas anderes zu
behaupten:
Markus F. schrieb:> Das einzige Manko (hat aber nichts mit deiner Umsetzung zu tun) ist,> dass ghdl bei Iteration 32 schlapp macht. Interessant, das.
Beim ISIM passiert das auch. Da muss man den Vektor optisch
"vergleichen". Der passt dann aber augenscheinlich über alle 64 Bits.
> (während modelsim prima alle 54 Durchläufe korrekt bewältigt)
Muss ich auch mal ausprobieren...
Markus F. schrieb:> Da hat sich ein Bit eingeschmuggelt, das da nicht hingehört> Sieht auf den ersten Blick so aus, als ob ghdl nur mit extended anstatt> mit double rechnen würde, die real range scheint aber etwas anderes zu> behaupten:real'left=-1.7976931348623157e308> real'right=1.7976931348623157e308> während modelsim "nur" das zu bieten hat:real'left=-1.000000e+308> real'right=1.000000e+308>> Da scheint mir noch ein Fehler in ghdl versteckt...
Hi Markus,
magst du das allenfalls als 'issue' im GHDL-Projekt einreichen? Wuerde
mich interessieren, was das Credo des 'VHDL-Standards' ist, und welche
von den vielen Simulatoren-Implementierungen es nun richtig macht.
Am wenigsten Kopfweh betr. grosse Zahlen hat mir bisher die Umsetzung
per Python bereitet (da sind die resultate nach 15 Jahren immer noch
konsistent), ansonsten kennt man die Ueberraschungen bei der Software
aus dem Hause X ja schon.
Martin S. schrieb:> magst du das allenfalls als 'issue' im GHDL-Projekt einreichen? Wuerde> mich interessieren, was das Credo des 'VHDL-Standards' ist, und welche> von den vielen Simulatoren-Implementierungen es nun richtig macht.
Würde ich, wenn der Fehler da läge.
Ich bin nämlich mittlerweile dahinter gekommen, dass der Fehler gar
nicht im ghdl (und entsprechend wahrscheinlich auch nicht in Lothar's
ISIM), sondern bei der (schlampigen, faulen, ...) IEEE liegt.
Uhhh. Gruselig.
ieee.math_real.round() ieee.math_real.floor() funktionieren nicht so,
wie man (und offensichtlich auch die ghdl und die ISIM-Entwickler) das
erwarten würde(n). Finden wird man das nur, wenn main in
math_real-impl.vhdl reinschaut, sonst scheint das nirgends klar
dokumentiert (ausser, dass die IEEE im 1076-2008 Standard sagt, die
math_real sei nicht Teil des Standards, sondern nur eine
Beispielimplementierung). Wie wir sind die o.g. Entwickler wohl davon
ausgegangen, dass die IEEE schon keinen Mist machen wird.
Weit gefehlt.
FLOOR() und ROUND() beginnen beide so:
1
...
2
constantLARGE:REAL:=REAL(INTEGER'HIGH);
3
variableRD:REAL;
4
5
begin
6
ifABS(X)>=LARGEthen
7
returnX;
8
endif;
Heisst: REALs, die betragsmässig grösser als integer'high sind, werden
nicht gerundet. Weder aufwärts noch runterwärts. Steht auch so in den
entsprechenden Kommentaren.
Verlässt man sich darauf, fällt man auf den Bauch...
Update: es ist nicht nur FLOOR() und ROUND(), die nicht wie erwartet
funktionieren, die offiziell und öffentlich verfügbare, bei ghdl
mitgelieferte OpenSource-Version von math_real ist schlicht komplett
kaputt (bzw. von gruseliger Präzision):
Modelsim bringt seine eigene math_real-Implementierung (native) mit,
deswegen funktioniert's da.
Aber es gibt Abhilfe:
Eigentlich nur für IEEE-Zahler gedacht, ist eine neuere (und deutlich
bessere) Implementierung von math_real trotzdem downloadbar:
https://standards.ieee.org/downloads.html
(1076.2-1996)
Ersetzt man math_real.vhdl und math_real-impl.vhdl, die bei ghdl
mitkommen durch die Dateien aus dem .zip-File (und zusätzlich die -
immer noch unpräzise Potenz durch entsprechende Konstanten), klappt's
auch mit ghdl (nachdem's bei Lothar mit ISIM auch nicht lief, würde ich
dort dasselbe erwarten?).
Hi Markus,
danke fuer diese wertvolle Erkenntnis. Koennte allenfalls die Loesung zu
einem jahrealten Raetsel betreffend ISIM gewesen sein. Hat damals keiner
untersuchen wollen. Ich glaube mich zu erinnern, dass es mit den
Lattice-Tools richtig gerechnet hat und deswegen die Libraries aus deren
Toolchain 'geborgt' wurden.
Leider ist das mit der Redistribution von IEEE-Libs im Rahmen der
Opensource immer so ein gordischer Knoten, vermutlich will sich auch
darum kaum einer aus der GHDL-Community damit herumschlagen.
ghdl hat ja das VHPIDIRECT interface, das calls aus dem VHDL code in
eine shared library erlaubt, kann also prinzipiell dasselbe, was
anscheinend auch Modelsim tut: ein eigenes math_real native Interface
realisieren.
Genau das habe ich eben mal "zusammengenagelt":
git@github.com:mfro0/math_real.git oder
https://github.com/mfro0/math_real.git
Man muss noch nicht mal eine eigene shared Library basteln, die ganzen
math_real Aufrufe mappen meist direkt auf eine C-Funktion, die es in der
libm.so (fast) genauso schon gibt. Der Code ist weitgehend ungetestet
(Überraschungen können und werden also durchaus noch drin stecken), aber
der Code in diesem Thread läuft jedenfalls jetzt fehlerfrei und
1
2**32 = 4294967296.000000000000000
liefert jetzt viele hübsche Nachkomma-Nullen.
Was sicherlich nicht funktioniert sind Testbenches, die sich darauf
verlassen, dass UNIFORM() eine bestimmte Zufallszahlen-Sequenz erzeugt -
das läuft jetzt mit rand() und srand() (wenn überhaupt, wie gesagt:
nicht getestet) und erzeugt mit Sicherheit was anderes.
Genutzt wird mein math_real, indem man die beiden Dateien math_real.vhdl
und math_real-impl.vhdl entweder in ein lokales Verzeichnis kopiert und
statt
1
useieee.math_real.all;
1
usework.math_real.all;
einbindet oder (wenn man ganz mutig ist) die beiden Dateien (und die
nach make erzeugten .o's) in der ghdl-Installation ersetzt.
Sorry, nur für Linux-User. Wie das mit Windows ginge, weiss ich nicht.