Hallo
Ich habe ein VHDL Modul, welches nicht von mir stammt, aber sehr gut
funktioniert.
Dieses kann ich mit ISE12 problemlos übersetzen, möchte dies aber wegen
der 5V Kompatibilität auf einen Spartan 2 FPGA portieren.
Der Spartan2 wird aber nur bis ISE10.1 unterstützt, beim Übersetzen
kommt eine Fehlermeldung:
"Operator <DIVIDE> must have constant operands or first operand must be
power of 2"
für folgende zwei Zeilen:
Hallo Tom,
die Division lässt sich nicht einfach synthetisieren.
Das musst du zu Fuß machen.
Such mal hier im Forum, da findest du genügend Bespiele für so etwas.
Grüße, Jens
Durch eine Zweierpotenz teilen ist einfach, da kannst du die LSBs
wegschneiden, aber dein CHAR_Y_SIZE hat den Wert 24, das ist keine
Zweierpotenz.
Das sollte also bauen wenn du statt 24 dort auch 16 oder 32
reinschreibst.
Aber auch mit 24 geht das.
/ (CHAR_Y_SIZE/8) teilt also durch 3.
und
/CHAR_Y_SIZE teilt durch 24.
Weil man im FPGA aber gut multiplizieren kann, kann man aus der Division
eine Multiplikation mit anschließender Division durch eine Zweierpotenz
machen. Geteilt durch 3 ist doch mal 1/3. Und geteilt durch 24 ist mal
1/24. Du brauchst also jetzt einen Bruch der möglichst nahe an 1/3 liegt
und dessen Nenner eine Zweierpotenz ist.
Ganz einfach, wir erweitern 1/3 mit 256/3 (ca. 85) und bekommen den
Bruch 85/256.
Und schon kannst du statt
cgAddr <= charData & std_logic_vector(to_unsigned(countV /
(CHAR_Y_SIZE/8), 3));
das hier schreiben:
cgAddr <= charData & std_logic_vector(to_unsigned(countV*85/256, 3));
Mit 1/24 geht das ähnlich:
Erweitern mit 256/24 (ca. 11) und raus kommt die Zeile
ramAddr <= std_logic_vector(to_unsigned(countH/CHAR_X_SIZE +
countV*11/256 * CHAR_PER_LINE, 11));
Ja, das ist natürlich ungenau. Aber dann spendiere dem Bruch eben mehr
Stellen. Statt mit 256/3 oder 256/24, also ungenau 85 und 11 zu
erweitern, kannst du auch mit 2**16/3 und 2**16/24 erweitern, also mit
den Zahlen 21845 und 2730 und bekommst die Zeilen:
cgAddr <= charData & std_logic_vector(to_unsigned(countV*21845/2**16,
3));
ramAddr <= std_logic_vector(to_unsigned(countH/CHAR_X_SIZE +
countV*2730/2**16 * CHAR_PER_LINE, 11));
Tom schrieb:> "Operator <DIVIDE> must have constant operands or first operand must be> power of 2"> für folgende zwei Zeilen:
Der Parameter "DIVIDE" taucht in diesen Zeilen gar nicht auf (?)
Bitte (-: Ich habe hier auch nur weitergegeben was mir einst Lothar
erklärt hat. Das ist eine sehr elegante Methode wie man im FPGA durch
eine Konstante teilt die keine Zweierpotenz ist.
Gustl B. schrieb:> Ich habe hier auch nur weitergegeben was mir einst Lothar> erklärt hat. Das ist eine sehr elegante Methode
Das ist aber jetzt nicht so ganz neu, oder? ;-)
Und es geht auch nicht für unbekannte Zahlen.
> Ganz einfach, wir erweitern 1/3 mit 256/3 (ca. 85) und bekommen den> Bruch 85/256.
Das ist aber jetzt nicht euer Ernst, oder?
Reto schrieb:> Gustl B. schrieb:>> Ich habe hier auch nur weitergegeben was mir einst Lothar>> erklärt hat. Das ist eine sehr elegante Methode> Das ist aber jetzt nicht so ganz neu, oder? ;-)
Es ist eine Multiplikation mit dem (skalierten) Kehrwert. Die
Multiplikation mit dem Reziprokwert lernt man in der Schule bei der
Division von Brüchen, das Skalieren ergibt sich aus der Notwendigkeit,
mit Integerzahlen >1 arbeiten zu müssen.
Aus r = x/y wird also r = x * 1/y. Schon ist aus der nicht
synthetisierbaren Division eine Multiplikation geworden, für die sogar
spezielle Komponenten auf dem FPGA vorhanden sind. Und wenn y konstant
ist, dann ist auch 1/y konstant und kann bereits vom Synthesizer
berechnet werden.
Weil aber 1/y bei Integerzahlen ein Wert kleiner 1 ist, muss 1/y noch
erweitert werden, z.B. mit 1024 (= 10 Bit).
Das ergibt also r = (1*1024)/(y*1024) und das lässt sich umstellen zu
r = (1024/y) / 1024.
Das / 1024 erledigt man in Software durch einen Rechtsshift, damit
werden die 10 LSB "abgeschnitten". Auf der Hadrware kann das der
Synthesizer einfach durch "Nichtwerwenden" der 10 LSB machen. Diese
Division durch ein 2er-Komplement braucht also keinerlei Ressourcen,
deshalb schreibt Xilinx ja auch "operand must be power of 2".
Gustl B. schrieb:> einstReto schrieb:> Das ist aber jetzt nicht so ganz neu
Natürlich nicht.
Reto schrieb:> Und es geht auch nicht für unbekannte Zahlen.Gustl B. schrieb:> Das ist eine sehr elegante Methode wie man im FPGA durch> eine Konstante teilt die keine Zweierpotenz ist.Reto schrieb:>> Ganz einfach, wir erweitern 1/3 mit 256/3 (ca. 85) und bekommen den>> Bruch 85/256.> Das ist aber jetzt nicht euer Ernst, oder?
Doch. Wenn dir das zu ungenau ist, dann mach es eben genauer. 1/3 kannst
du auch mit 2**16/3 erweitern und bekommst den Bruch 21845/65536. Das
ist dann 0.3333282471 und schon nahe dran an den echten 1/3. Dafür musst
du dann aber auch mit 21845 multiplizieren, das sind 15 Bits. Bei 85/256
bekommt man 0,32075, muss aber auch nur mit 85 multiplizieren, das sind
7 Bits. Man kann also je nach gewünschter Genauigkeit oder
Geschwindigkeit selber wählen was man haben will.
Gustl B. schrieb:> Bei 85/256 bekommt man 0,32075, muss aber auch nur mit 85> multiplizieren, das sind 7 Bits.
Und noch besser: bei geschickter Wahl dieses "Multiplikators" kann der
in Additionen und Subtraktionen zerlegt werden.
Bei x*85 ist es jetzt mit x*(64+16+4+1) recht aufwendig, aber eine
Multiplikation mit z.B. x*69 wäre über x*(64+4+1) nur eine Addition von
x&"000000" + x&"00" + x
Und bei x*57 könnte man via x*(64-8+1) so rechnen: x&"000000" - x&"000"
+ x
Damit ist für diese Division durch eine Konstante dann auch kein
Multiplizierer mehr nötig.
Lothar M. schrieb:> Bei x*85 ist es jetzt mit x*(64+16+4+1) recht aufwendig, aber eine> Multiplikation mit z.B. x*69 wäre über x*(64+4+1) nur eine Addition von> x&"000000" + x&"00" + x
Kann man auch gleich addieren:
Messtechnikprofi schrieb:> downto 256
Das ist aber schon ein pfundiger Vektor. Verwechselt du da
Zweiwerpotenzen mit Bitpositionen?
Aber richtig:
Für so eine Division muss man nicht mal mit Teilvektoren rechnen,
sondern man kann einfach durch die entsprechende Zweierpotenz teilen:
1
y = x/3
2
-->
3
y = x/4 + x/16 + X/64 + x/256 = x/3,01
4
oder noch was dazu:
5
y = x/4 + x/16 + X/64 + x/256 + x/1024 = x/3,003
und das ist bezogen auf den Aufwand hinreichend genau... ;-)
Lothar M. schrieb:> Für so eine Division muss man nicht mal mit Teilvektoren rechnen,> sondern man kann einfach durch die entsprechende Zweierpotenz teilen:
Dann muss man aber mit dem Runden aufpassen! Das Addieren auf höherer
Genauigkeit ist zu bevorzugen. Ich hatte dazu auch vor Jahren mal eine
Tabelle gepostet, wie man solche Divisionen zusammensetzen kann, um sie
auf DSPs zu rechnen. Das geht dort hinreichend genau. Man kann es auch
in VHDL generisch aufziehen, wenn man statistisch rundet und für eine
begrenzte Zahl an Divisoren auch in einen FPGA gießen, der dann sehr
effizient dividiert. BTDT
Bei der Verfügbarkeit von MULs in heutigen FPGAs ist das allerdings
inzwischen ein untergeordnetes Thema.
Und dann gibt es auch einen Punkt, ab dem ein vollständiger
Differenzierer auf Basis eines Heron kleiner und schneller ist, weil er
nur einen MUL braucht.