Hallo,
ich habe da eine 6 Bit Binärzahl, die will ich auf einer 2 stelligen
7-Segment-Anzeige im Dezimalsystem ausgeben. Dazu brauche ich eine
Modulo-10-Operation und eine Division durch 10. (4 Bit nach 7-Segment
habe ich schon)
Wie geht man das an auf einem XC9572 CPLD?
> Dazu brauche ich eine Modulo-10-Operation und eine Division durch 10.
Das ist nicht sooo trivial.
Vergiss mal die Division auf dem CPLD. So geht das nicht.
Hast du einen Takt?
Dann könntest du evtl. ein BCD-Schieberegister einsetzen:
http://www.lothar-miller.de/s9y/categories/44-BCD-Umwandlung
Aber auf einen CPLD wird das schnell eng :-/
Geht bei 6Bit eventuell noch mit nder LUT, aber das braucht auch einige
Logic Cells im CPLD. Division ist wie Lothar schon angemerkt hat nicht
Trivial. Außer eventuell durch 2er Potenzen
Das sieht gar nicht so schlecht aus.
EDIT:
Sogar einen ganzen 8 Bit Vektor kann man in diesem CPLD noch ohne
weiteres wandeln (Code von meiner HP, Link siehe oben). Die Produktterme
sind schön mächtig :-)
1
Macrocells Pterms Registers Pins Function Block Inputs
Der Byte zu 3xBCD Coder gefällt mir und erstaunt mich. Ich hätte einen
viel größeren Resourcenverbrauch erwartet. Aber so kann ich das direkt
gebrauchen und werds mal irgendwo einbauen.
Danke
TobiFlex
Ist doch klar, viele therme innerhalb des mux treten mehrfach auf,
werden aber nur einmal gebaut. Nimm Dir mal eine Sinustabelle, die in
LUTs gebaut wird und nicht im RAM liegt. Die hat nur die halbe Zahl der
LUTs die sie haben müsste, wenn alles parallel realisierrt wäre.
Man kann so ziemlich jede Funktion in VHDL formulieren und in LUTs
realisieren, wenn man sich ein script macht, welches VHDL automatisch
erzeugt. Ich mache das mit einer Accessdatenbank oder Excel unter
Nutzung von VBA und den DDS-Abfragen. Ich habe anbei mal ein VHDL und
eine Sample-Bank angefügt, die zeigen, wie das geht.
Man muss den Code dann nur noch minimal modifizieren, damit er
compiliert.
(erstes ELSIF in IF tauschen etc..)
Heraus kommt ein Quotient mit der Skalierung 256.
Über die Primärtabellen in der Datenbank kann man sogar die
Definitionsbereiche einschränken, um nur die möglichen Teiler zu
bekommen.
@Jürgen:
Für was benutzt du diesen Code?
Ich habe ihngerade mal in ise geladen. Die Synthese braucht eine knappe
Stunde, benutzt fast 3000 LUTs und läuft selbst in einem Virtex 4 nur
mit 70MHz - das klingt für mich nicht nach einer brauchbaren Lösung,
zumal im Code auch nur eine relativ willkürlich erscheinende Auswahl an
möglichen Input-Werten getroffen wird.
>@Jürgen:>Für was benutzt du diesen Code?
Der Code ist nur ein Beispiel, wie man das machen kann. Es ging mir
darum, zu zeigen, wie man mit der Hilfe der Datenbankfunktionen in
Access automatisch VHDL erzeugen lassen kann.
>Die Synthese braucht eine knappe Stunde
Habe das testsynthetisiert mit Quartus 9.0: <25 Min!
>benutzt fast 3000 LUTs
Das ist noch wenig :-)
Hast aber schon Recht: Es ist einseitiger Bau auf Geschwindigkeit auf
Kosten des Platzbedarfes! Das wird man nur machen, wenn es arg schnell
gehen muss, z.B. die schnelle Berechung innerhalb von Regelschleifen auf
Hochgeschwindigkeit, wo man keine grosse Latenz verkraften kann.
Konkret wird man in der Regel auch keinen Divider bauen, aber mit einem
Logarithmus, einem Sinus oder einer hyperbolischen Funktion böte sich
das schon an. Ich habe es auch schon mit einem Gaussalgorithmus gemacht:
4 Determinantenwerte werden flash berechnet und dann weiter verrechnet:
Mit dem Divider oben ginge das ganze sogar in 10 Takten. Real braucht
jede Determinante schon 15 und die gesamte Rechung über 100, wenn man es
voll sequenziell macht. (Der Divider hat auf der hohen Breite schon 6
Takte)
Aber je billiger die FPGAs werden und je mehr DSPs sie haben, desto mehr
wird sowas wichtig.
P.S. Die Einschränkung, die oben im Code enhalten ist, ist auch ein
Beispiel. Damit kann man aber sehr effektiv nur das aufbauen, was man
auch braucht! Nicht jede mathematische Funktion wird ja durch den
Definitionsbereich komplett angesteuert. Z.B. hatte ich mal eine
Wurzel-aus-Sinus-berechung aus einem Zwischenergebnis, das überhaupt nur
zwischen 257 und 3 x (k x 256 + n x 255) liegen konnte.
Wenn man sich das vorberechnet hat, fallen die Perioden des Sinus raus
und dank der 25%igen Auslastung des Definitionsbereichens nochmal 50%
der Wertmenge für die Wurzel. Das gab eine sehr übersichtliche Tabelle
:-)
Vor allem können die Terme, die entstehen, oftmals noch mit
vorangegangenen Berechungen zusammengefasst werden. Mit der Option
"Register - Retiming" macht das die Synthese sogar automatisch. Da fällt
vorne dann wider viel weg.
Jürgen Schuhmacher schrieb:
>>@Jürgen:>>Die Synthese braucht eine knappe Stunde> Habe das testsynthetisiert mit Quartus 9.0: <25 Min!
Gut, mein Rechner war nicht der schnellste, das kommt schon hin auf
einer aktuellen Maschine. Allerdings: Trotz komplexen Designs die viele
Verknüpfungen aufweisen und >50.000 LUTs verwenden hat bei mir noch
keine Synthese über 10 Minuten gedauert.
>>benutzt fast 3000 LUTs>> Das ist noch wenig :-)
Autsch.
> Hast aber schon Recht: Es ist einseitiger Bau auf Geschwindigkeit auf> Kosten des Platzbedarfes! Das wird man nur machen, wenn es arg schnell> gehen muss, z.B. die schnelle Berechung innerhalb von Regelschleifen auf> Hochgeschwindigkeit, wo man keine grosse Latenz verkraften kann.
Optimiert auf Geschwindigkeit ist das aber sicherlich nicht, z.B. kann
man einige einfache Fälle (hier: Divisionen durch 1,2,4,8) durchaus von
Hand optimieren.
Eine viel kleinere Lösung für dein Beispiel wäre: Ein ROM, der die
Ergebnisse von 1/n fuer alle 256 möglichen DIV enthält, mit 24bit
Genauigkeit und dahinter geschaltet ein Multiplizierer, der den Wert aus
dem ROM mit MUL multipliziert. Das sollte sicher eine höhere
Taktfrequenz erreichen, wenn auch mit einem Takt Latenz.
>Aber je billiger die FPGAs werden und je mehr DSPs sie haben, desto mehr>wird sowas wichtig.
Genau das ist in meinen Augen die falsche Einstellung - "Wir haben ja
genügend Leistung, also schreiben wir einfach irgendeinen Code ohne auf
Effizienz zu achten".
> z.B. kann man einige einfache Fälle (hier: Divisionen durch 1,2,4,8)> durchaus von Hand optimieren.
Die Fallunterscheidung kostet Programmierarbeit, die die Synthese
erledigt! Diese einfachen Fälle werden erkannt und wegoptimiert. In den
Fallen, in denen die Architektur das nicht zu lässt, kosten die
Fallunterscheidungen aber Rechenzeit, die der Vorgehensweise, alles in
einem Clock zu erledigen, zuwider läuft.
> Eine viel kleinere Lösung für dein Beispiel wäre: Ein ROM, der die> Ergebnisse von 1/n fuer alle 256 möglichen DIV enthält, mit 24bit> Genauigkeit und dahinter geschaltet ein Multiplizierer,
Genau das ist ja der Denkansatz und läuft auf genau dasselbe hinaus,
wenn das ROM und der Multiplizierer als LUT-array realisiert sind :-)
Aber:
1) Es braucht eine Auflösungsstufe mehr, wegen des Zwischenergebnisses -
bilde Dir mal die Tabelle für das 1/n
2) Man verliert entweder Laufzeit oder einen Takt, in jedem Fall ist es
langsamer (ich habe viel mit solchen Strukturen experientiert )
3) nur bei expliziter Darstellung können Terme mit Partiallösungen von
Ergebnissen vorher zusammengealtet werden, die im gleichen Takt
entstanden sind. (Man darf sowas nie isoliert sehen)
4) Die Definitionsmenge kann nicht so gut eingeschränkt werden
> Genau das ist in meinen Augen die falsche Einstellung> - "Wir haben ja genügend Leistung, also schreiben wir einfach> irgendeinen Code ohne auf Effizienz zu achten".
Grundsätzlich bin ich auf Deiner Seite, nur muss man das Argument
entsprechend anwenden: Normalerweise wird man gerade so schnell bauen,
wie nötig und damit Platz und Leistung sparen. Aber in meinem Beispiel
geht es wie gesagt um Tempolösungen!
Man muss sich ja immer überlegen, welche Randbedingung das FPGA gerade
hat und wenn es um das Platz, Geld- und Energisparen geht, ist der DSP
sowieos erstmal die bessere Wahl. Wenn aber ein FPGA zur Anwendung
kommt, dann gibt es meist zwei Gründe:
a) Es muss schneller sein, als DSPs es können und gepipelined sind
solche FPGA-Rechner x-mal schneller, man denke an viele Kanäle ...
b) Das FPGA ist aus anderen Gründen schon da und kann verwendet werden
oder es kann kostengünstig ein größeres implementiert werden
Beide Fälle habe ich regelmässig und wenn Fall 2 zutrifft und ich die
Möglichkeit habe, aufgrund der Leistungsreserven in das vorhandene FPGA
etwas Rechnung einbauen und damit den DSP wegfallen lassen zu können,
dann ist das zwingend die richtige Entscheidung, so vorzugehen.
... nud genau damit achte ich sehr genau auf (System-)effizienz :-)
Jürgen Schuhmacher schrieb:
>> Eine viel kleinere Lösung für dein Beispiel wäre: Ein ROM, der die>> Ergebnisse von 1/n fuer alle 256 möglichen DIV enthält, mit 24bit>> Genauigkeit und dahinter geschaltet ein Multiplizierer,>> Genau das ist ja der Denkansatz und läuft auf genau dasselbe hinaus,> wenn das ROM und der Multiplizierer als LUT-array realisiert sind :-)
Wer macht denn das? 1 BRAM und 2 Multiplizierer von vielen vs. 3k LUTs,
was bei vielen Bausteinen schon ueber 10% sind.
> 1) Es braucht eine Auflösungsstufe mehr, wegen des Zwischenergebnisses -> bilde Dir mal die Tabelle für das 1/n
Diese gibt es im Prinzip kostenlos dazu, ein memory Block hat ja gross
genug.
>> 2) Man verliert entweder Laufzeit oder einen Takt, in jedem Fall ist es> langsamer (ich habe viel mit solchen Strukturen experientiert )
Ich bin ziemlich sicher dass die "einfache" Loesung hier insgesamt
schneller ist. Sowohl ein ROM als auch ein 32x8 Multiplizierer laufen
mit ueber 140 MHz. Das ist bei zwei Takten schneller als die
"Brachialloesung"
>> 3) nur bei expliziter Darstellung können Terme mit Partiallösungen von> Ergebnissen vorher zusammengealtet werden, die im gleichen Takt> entstanden sind. (Man darf sowas nie isoliert sehen)>> 4) Die Definitionsmenge kann nicht so gut eingeschränkt werden
Das ist dann auch gar nicht noetig, weil es ohnehin keine Ressourcen
einspart.
> a) Es muss schneller sein, als DSPs es können und gepipelined sind> solche FPGA-Rechner x-mal schneller, man denke an viele Kanäle ...>> b) Das FPGA ist aus anderen Gründen schon da und kann verwendet werden> oder es kann kostengünstig ein größeres implementiert werden>> Beide Fälle habe ich regelmässig und wenn Fall 2 zutrifft und ich die> Möglichkeit habe, aufgrund der Leistungsreserven in das vorhandene FPGA> etwas Rechnung einbauen und damit den DSP wegfallen lassen zu können,> dann ist das zwingend die richtige Entscheidung, so vorzugehen.
Natuerlich, da sind wir einer Meinung. Allerdings halte ich es fuer
fragwuerdig, so massiv Hardware-Ressourcen zu verwenden und aeusserst
lange Synthesezeiten zu produzieren, nur um sich ein wenig
Entwicklungszeit zu sparen. Man muss sich ja auch ueberlegen, wieviel
Zeit verloren geht durch die 10fach laengere Zeit zwischen Quellcode und
Syntheseergebnis fuer Simulation oder Hardware.
> Man muss sich ja auch ueberlegen, wieviel Zeit verloren geht> durch die 10fach laengere Zeit zwischen Quellcode und> Syntheseergebnis fuer Simulation oder Hardware.
Seit wann kostet denn die Synthesezeit Geld? Von mir aus kann der
Rechner 4 Tage synthetisieren, wenn das Ergebnis besser ist und die
FPGAs schnell.
>Sowohl ein ROM als auch ein 32x8 Multiplizierer laufen mit ueber 140 MHz.
Das sind aber in Kette deutlich weniger, als die Hälfte wegen dem
Routing und das ROM liegt ja meistens im RAM und das hängt wo in der
Ecke! Da darf man sich mit dem Routing nicht vertun.
Aber mal im Ernst: Ihr beiden spendiert ein fettes ROM für eine simple
Division?
gagamel schrieb:
> Seit wann kostet denn die Synthesezeit Geld?
Sie kostet genau dann Geld, wenn man wegen einer (oftmals kleinen)
Änderung im Code eine lange Wartezeit hat oder einen Fehler erst nach
langer Synthesezeit im Report erkennt und beheben kann.
>>Sowohl ein ROM als auch ein 32x8 Multiplizierer laufen mit ueber 140 MHz.> Das sind aber in Kette deutlich weniger, als die Hälfte wegen dem> Routing und das ROM liegt ja meistens im RAM und das hängt wo in der> Ecke! Da darf man sich mit dem Routing nicht vertun.
Wenn ich den floorplan eines Virtex4 noch richtig im Kopf habe, sind die
Multiplier immer direkt neben BRAMs angeordnet und hart verdrahtet,
insofern sollte sich die Laufzeit zwischen den Modulen in Grenzen
halten. Außerdem kann man am Speicher dann auch die Ausgangs-FF
verwenden, damit sollten die 140MHz erreichbar sein - was dann trotz 2
Takten Latenz noch schneller ist als ein Takt bei 70 MHz.
> Aber mal im Ernst: Ihr beiden spendiert ein fettes ROM für eine simple> Division?
Normalerweise würde man das über eine Pipeline mit wenig Logik und
einigen Takten Latenz machen - wenn allerdings eine wirklich niedrige
Latenz gefordert ist, dann sind große Lookup-Tables in einem ROM
durchaus ein adäquates Mittel.
Was heisst denn bei Dri "hart" verdrahtet?
BRAMs sind sau langsam, wegen der MUXER und haben immer mindestens 1
Clock Latenz und brauchen sogar 2, wenn man auf Durchsatz kommen will.
gagamel schrieb:
> Was heisst denn bei Dri "hart" verdrahtet?
Mit hart meinte ich durch dedizierte Leitungen verbunden, nicht durch
normales Routing - damit habe ich mich aber geirrt:
Beim Virtex 4 trifft das nicht mehr zu, aber im Virtex 2 bestanden BRAM
und Multiplier aus einem festen Block, die miteinander verbunden waren.
> BRAMs sind sau langsam, wegen der MUXER und haben immer mindestens 1> Clock Latenz und brauchen sogar 2, wenn man auf Durchsatz kommen will.
Nun ja, laut Datenblatt 450 MHz im mittleren Speedgrade, 200 Mhz sind
noch ohne jedwede Design-Tricks locker nutzbar. Die FF am Ausgang, und
damit die 2 Takte Latenz, braucht man nur, wenn nach dem RAM noch
größere Logik folgt oder man sehr hohe Taktraten erreichen will.
Coole lösung mit der LUT!
Die LUT von oben kann man noch um die hälfte auf 32 Werte schrumpfen
weil div/mod 2 trivial ist und man dann nur für div/mod 5 ne tabelle
braucht.
Dann mit data(7 downto 1) in die tabelle und:
dig1 <= digits (2 downto 0) & data(0);
dig10 <= digits (6 downto 3);
Noch ne Frage. Die LUT mit konstantem Inhalt sollte man doch auch durch
ne for-schleife ersetzen können, die die entsprechenden Werte ausrechnet
und bei der Synthese ausgewertet wird - mit dem selben Ergebnis?
Ein std_logic ist kein integer, ergo kann man die nicht direkt zuweisen.
Mit numeric_std als library geht es so:
X_index <= to_integer(unsigned(Switch));
>library IEEE;>use IEEE.STD_LOGIC_1164.ALL;>use IEEE.STD_LOGIC_ARITH.ALL;>use IEEE.STD_LOGIC_UNSIGNED.ALL;>use IEEE.NUMERIC_STD.ALL;
Deine Wahl der Libaries ist nicht ganz gluecklich. Es reichen die erste
und die letzte.
>Frage mich, ob das Synthese-tool das evtl. selber erkennt und>entsprechend optimiert.
Jepp!
>Ich bin ziemlich sicher dass die "einfache" Loesung hier insgesamt>schneller ist
Definitiv in der Regel nicht, sonst würde ich ja die Wege nicht gehen:-)
>Aber mal im Ernst: Ihr beiden spendiert ein fettes ROM für eine simple>Division?
Wie ich bereits schrieb, ist das eigentliche Ziel der Vorgehensweise
nicht primär, einfache Multiplikationen (oder hier Divisionen) zu
ersetzen, die in den allermeisten Fällen schnell genug laufen werden,
sondern Funktionen zusammenzufassen, bzw so zu formulieren, dass sie
zusammenfassbar sind. Bei der ausdrücklichen Verwendung von RAM und MUL
ist das kaum der Fall.
Die Methode ist aber auch bei einfachen Berechnungen sehr effektiv, wie
z.B. das Beispiel "durch 10" zeigt (um das es hier mal ging :-)) und
nur, bei ausdrücklicher Formulierung der Terme, können die Verknüpfungen
mit anderen vorherstehenden Berechnungsergebnissen zusammengefasst und
vereinfacht werden. Ich habe das bei meinem Neuronennetzwerk gesehen, wo
eine Aneinanderreihung vieler Vergleiche, Elementarmultiplikationen (und
auch Divisionen) zunächst zu einem scheinbar gewaltigen Baum auftürmen,
hinterher jenachdem, was man in die Neuronen sonst noch reinstopft
wieder in sich zusammenfallen (samt der komplexen
Verschaltungsarchitektur).
Für einen Satz paralleler Audio-DSPs (im Wesentlichen Mischer und
einfache Filter) braucht Quartus im Übrigen 6-8h (je FPGA Derivat!).
>Ein std_logic ist kein integer, ergo kann man die nicht direkt zuweisen.>Mit numeric_std als library geht es so:>X_index <= to_integer(unsigned(Switch));>>library IEEE;>>use IEEE.STD_LOGIC_1164.ALL;>>use IEEE.STD_LOGIC_ARITH.ALL;>>use IEEE.STD_LOGIC_UNSIGNED.ALL;>>use IEEE.NUMERIC_STD.ALL;>Deine Wahl der Libaries ist nicht ganz gluecklich. Es reichen die erste>und die letzte.
Danke!
Als ich die beiden mittleren Libaries auskommentiert habe, ging es!
Warum? Wo lag da der Hund begraben?