Hallo,
ich habe ein kleines Problem mit meinem VHDL-Code. Bin noch blutiger
Anfänger und ihr werdet wahrscheinlich die Hände über dem Kopf
zusammenschlagen, aber ich komm nicht drauf, woran es liegt.. Ich mache
einige Berechnungen mit Integer-Signalen. Anschließend werden diese in
einen std_logic_vector umgewandelt, um sie weiter verarbeiten zu können.
Der Code sieht so aus:
Das ist natürlich nicht der gesamte Code und ich hab ein paar
Deklarationen weggelassen, aber die machen auch keine Probleme.
Kommentiert man hinter IW1 in der Zeile
die beiden Arrays aus, läuft der Compiler durch. Lässt man sie drinnen,
so läuft der Compiler im Schritt "Analysis & Synthesis" bis 46% und
macht dann gar nichts mehr. Gleiches gilt für die Zeile
1
IW1<=2*IW1+diffarray(1)+diffarray(dcount+2);
Das Programm hängt sich allerdings nicht auf, man kann die Compilation
einfach beenden. Ich nutze Quartus II.
Vielen Dank schonmal für die Hilfe!
ni schrieb:> Datentypprobelm
Du hast hier kein Problem mit einem Datentypen, sondern eher ein
Implementierungsproblem.
> IW1 <= IW1 + diffarray(filter_zaehler)-diffarray(filter_zaehler+2);
Das ist ein Riesenmegamultiplexer, da kann man sich als Synthesizer
schon mal die Zähne ausbeißen...
Korrektur: zwei Riesenmegamultiplexer.
> Gleiches gilt für die Zeile IW1 <= 2*IW1 + diffarray(1) +> diffarray(dcount+2);
Korrektur: drei Riesenmegamultiplexer...
Du solltest dir unbedingt das Thema RAM-Blöcke mal genauer anschauen.
> Das ist natürlich nicht der gesamte Code
Ist dieser Prozessausschnitt getaktet?
Das war auch meine Vermutung, dass diese Berechnung einfach abartig groß
ist.
Wie kann man solche Berechnungen trotzdem durchführen? Ein Bekannter
meinte ich sollte die entsprechende megafunction benutzen. Würde das was
helfen? Dann wäre die Berechnung ja nicht mehr komplett in
kombinatorischer Logik aufgebaut?
Lothar M. schrieb:>> Das ist natürlich nicht der gesamte Code> Ist dieser Prozessausschnitt getaktet?
Ja. Er läuft mit 50 MHz.
ni schrieb:> Ein Bekannter meinte ich sollte die entsprechende megafunction benutzen.
Welche?
Letztlich muss das Array in ein RAM. Und ein RAM hat nur 1 oder 2 Ports
wo mit jeweils 1 Adresse auf 1 Wort pro Takt zugegriffen werden kann
(zudem kommt noch Latency ins Spiel, weil die Daten erst im nächsten
Takt verfügbar sind...).
Du musst also eigentlich die Schaltung mit Funktionsblöcken
(Adresszähler, Rechenwerk, zumindest aber dem RAM) auf ein Blatt Papier
aufzeichnen und das dann mit der HardwareBESCHREIBUNGssprache VHDLbeschreiben. Den Schritt mit der Malerei kannst du dir sparen, wenn du
dir die Schaltung vorstellen kannst, denn auch dann kannst du sie
beschreiben.
ni schrieb:> Ja. Er läuft mit 50 MHz.
Und wie schnell muss diese Berechnung abgearbeitet sein? Reicht es aus,
wenn du erst ein Wort liest, dann das nächste und dann rechnest? Oder
muss alles "gleichzeitig" gehen?
Welche megafunction ist eine gute Frage. Mit der Thematik habe ich mich
noch nicht weiter mit beschäftigt.
Lothar M. schrieb:> ni schrieb:>> Ja. Er läuft mit 50 MHz.> Und wie schnell muss diese Berechnung abgearbeitet sein? Reicht es aus,> wenn du erst ein Wort liest, dann das nächste und dann rechnest? Oder> muss alles "gleichzeitig" gehen?
Also das Array "diffarray" wird in einem vorherigen state durch einen
externen Datenstream gefüllt bzw. es wird mit der Differenz von je zwei
aufeinanderfolgenden Werten des Datenstreams gefüllt, um noch größere
Zahlen zu vermeiden. Das anschließende Aufsummieren
sollte möglichst schnell sein. Zielt deine Frage darauf ab, die Werte
des Arrays zuerst alle umzuspeichern und dann in einem Weiteren Schritt
aufzusummieren?
ni schrieb:> Das anschließende Aufsummieren
Mir erschließt sich da der Sinn der Subtraktion nicht ganz. Zwei Takte
später wird die doch durch die Addition neutralisiert...
> sollte möglichst schnell sein. Zielt deine Frage darauf ab...
Einfach eine Zeit zu erfahren, in der die 750 Operationen durchlaufen
sein müssen. Dann kann man sich eine Strategie ausdenken.
BTW: warum eine so "unbinäre" Zahl. Das ist ja fast, wie wenn dich wer
zwingt, im Siebenersystem zu rechnen...
BTW2: warum nur die Differenz abspeichern? Wie breit sind die Werte,
die da hereinkommen?
Lothar M. schrieb:> ni schrieb:>> Das anschließende Aufsummieren> Mir erschließt sich da der Sinn der Subtraktion nicht ganz. Zwei Takte> später wird die doch durch die Addition neutralisiert...
Jaein. Da stimmt natürlich, was du geschrieben hast. Das hängt
allerdings mit dem Algorithmus an sich zusammen. Einige der Werte müssen
herausfallen. Zusammen mit der Zählweise der if-Schleife (die ja nicht
einfach um 1 inkrementiert) und der vorhin erwähnten Differenzen ergibt
sich mein Filter. Da gibts sicherlich noch einiges an
Optimierungspotential, das ist mir klar.
Lothar M. schrieb:>> sollte möglichst schnell sein. Zielt deine Frage darauf ab...> Einfach eine Zeit zu erfahren, in der die 750 Operationen durchlaufen> sein müssen. Dann kann man sich eine Strategie ausdenken.
Ok. Das wäre als nächstes empirisch zu bestimmen (ja ich weiß, ist wie
mit der Henne und dem Ei). Die Größenordnung liegt bei etwa 15µs.
Lothar M. schrieb:> BTW: warum eine so "unbinäre" Zahl. Das ist ja fast, wie wenn dich wer> zwingt, im Siebenersystem zu rechnen...
Welche meinst du? Die sind ja alle etwas unschön;) Aber leider lässt
sich da auch nichts dran drehen. Die müssen für das Filter genau so
sein. Vllt. kann man später noch die Schleifen dahingehend ändern, dass
sie mit "schöneren" Werten läuft und anschließend eine entsprechende
Korrektur am Ergebnis vornehmen - fällt auch unter den Punkt
Optimierungsbedarf;)
Lothar M. schrieb:> BTW2: warum nur die Differenz abspeichern? Wie breit sind die Werte,> die da hereinkommen?
Das hat was mit dem Filter zu tun, wie oben geschrieben. Die kleineren
Werte sind nur ein willkommener Nebeneffekt. Im schlechtesten Fall kann
ein Element ohne Bildung der Differenz den Wert 92044800 erreichen.
ni schrieb:> Die Größenordnung liegt bei etwa 15µs.
50 * 15 gibt dann wieder die 750. Du kannst also dieses Array synchron
genau 1x durchlaufen.
> Das hängt allerdings mit dem Algorithmus an sich zusammen. Einige der> Werte müssen herausfallen.
Letztlich musst du aber nicht pro Takt 2x auf das RAM zugreifen, sondern
kannst diese "voreilenden" Subtraktionswerte ja einfach
zwischenspeichern für die Addition zwei Takte später.
> Im schlechtesten Fall kann ein Element ohne Bildung der Differenz den> Wert 92044800 erreichen.
Das passt doch problemlos in einen Integer...
Lothar M. schrieb:>> Das hängt allerdings mit dem Algorithmus an sich zusammen. Einige der>> Werte müssen herausfallen.> Letztlich musst du aber nicht pro Takt 2x auf das RAM zugreifen, sondern> kannst diese "voreilenden" Subtraktionswerte ja einfach> zwischenspeichern für die Addition zwei Takte später.
Ja das stimmt. Das werde ich auf jeden Fall noch einbauen. Allerdings
ist die Berechnung immer noch zu groß. Lässt man das voreilende Array
weg, klappt es auch nicht.
Lothar M. schrieb:>> Im schlechtesten Fall kann ein Element ohne Bildung der Differenz den>> Wert 92044800 erreichen.> Das passt doch problemlos in einen Integer...
Ja klar passt das in ein Integer. Ist auch nicht der primäre Zweck der
Differenzbildung.
ni schrieb:> Allerdings ist die Berechnung immer noch zu groß
Es ist nicht die Berechnung, sondern die Tatsache, dass das Array nach
der derzeitigen Beschreibung nicht als RAM implementiert werden kann.
Sieh dir mal im Handbuch zum Synthesizer an, wie der ein RAM beschrieben
haben möchte...
Lothar M. schrieb:> ni schrieb:> Allerdings ist die Berechnung immer noch zu groß>> Es ist nicht die Berechnung, sondern die Tatsache, dass das Array nach> der derzeitigen Beschreibung nicht als RAM implementiert werden kann.> Sieh dir mal im Handbuch zum Synthesizer an, wie der ein RAM beschrieben> haben möchte...
Achso daran liegt es. Dann werde ich mir mal das Handbuch zu dem Thema
anschauen. Könnte man das Array in kleinere Arrays aufteilen, die
einzeln als RAM implementiert werden können?
ni schrieb:> Könnte man das Array in kleinere Arrays aufteilen, die einzeln als RAM> implementiert werden können?
Sag ichs mal so: die Größe ist nicht das Problem...
Lothar M. schrieb:> ni schrieb:> Könnte man das Array in kleinere Arrays aufteilen, die einzeln als RAM> implementiert werden können?>> Sag ichs mal so: die Größe ist nicht das Problem...
Hm, dann hab ich es immer noch nicht durchschaut;)
Wenn nicht die Größe, was dann?
ni schrieb:> Wenn nicht die Größe, was dann?
Sieh dir das Datenblatt deines RAMs an. Und sieh dir an, wie viele Ports
das RAM hat. Und wie der Synthesizer so ein RAM beschrieben haben
möchte. So wie du es derzeit beschreiben hast, dürfte kein RAM
herauskommen, denn du möchtest auf 2 Ports gleichzeitig lesen und sicher
noch an einem dritten Port schreiben. Solche RAMs sind vorstellbar, aber
es gibt sie nicht so ohne Weiteres. Sie müssen aus mehreren RAM-Blöcken
zusammengebaut werden.
Mein Vorschlag: schreib einfach mal einen Dreizeiler, der ein RAM
implementiert. Hier habe ich sowas mal für Xilinx gemacht:
http://www.lothar-miller.de/s9y/archives/20-RAM.html#extended
Gut, weiter rumraten bringt ja nichts. Ich werde mal genau das tun, was
du geschrieben hast und mir das mit den RAMs mal genau durchlesen. Mal
schauen, ob ich es dann hinbekomme; )
So, ich habe mal Lothars RAM Beispiel nachprogrammiert. Wie das
funktioniert, ist mir jetzt relativ klar.
Bin mir jetzt nicht so ganz sicher über die Vorgehensweise zu meinem
Problem. Speichere ich jetzt erst das gesamte diffarray in ein
separates, von mir noch zu programmierendes, RAM und kann dann die
Berechnung genau so durchführen, wie in meinem Code zu sehen, nur halt
nicht mehr mit +diffarray(filter_zeahler), sondern mit +RAM(Adresse xy)
pseudocodemäßig?
@Lothar: deine Seite ist echt hilfreich!:)
ni schrieb:> So, ich habe mal Lothars RAM Beispiel nachprogrammiert.
Und im Ressourcenreport ein RAM gefunden?
> Speichere ich jetzt erst das gesamte diffarray in ein separates, von> mir noch zu programmierendes, RAM und kann dann die Berechnung genau so> durchführen, wie in meinem Code zu sehen, nur halt nicht mehr mit> +diffarray(filter_zeahler), sondern mit +RAM(Adresse xy) pseudocodemäßig?
Laut Radio Eriwna: Im Prinzip ja!
Das Ziel muss zuerst mal sein, dass aus diesem Array ein RAM wird. Und
danach musst du die Daten zum richtigen Zeitpunkt aus dem RAM
herausbringen. Und dort spuckt dir der Umstand in die Suppe, dass du an
so ein RAM die Adresse anlegen musst und dann am Takt zupfen, um die
Daten zu bekommen. Du bekommst also bei einem pro Takt hochzählenden
Adresszähler die Daten einen Takt später. Dieses Verhalten nennt sich
Latency.
> deine Seite ist echt hilfreich!:)
Viel Spass damit.
Lothar M. schrieb:> Laut Radio Eriwna: Im Prinzip ja!
Na das klingt doch schonmal ermutigend;D
Ich habe mir gestern Abend mal meine Vorgehensweise überlegt:
Das RAM muss 752 Zeilen haben mit einer Wortbreite von 28 Bit damit von
-920448800 bis 92044800 jeder Wert herein passt.
In dem state, in welchem ich das diffarray gefüllt habe, beschreibe ich
nun mein RAM mit den selben Daten und inkrementiere jedes Mal die
Schreibadresse - das ursprüngliche Array fällt weg. Meine statemaschine
ändert ihren Zustand mit dem 50MHz Taktsignal. Das heißt, dass ich für
das Speichern im RAM 752 Takte brauche, also etwa 15µs.
In dem state, in dem ich dann aufsummiere, hole ich mir wieder jeden
Takt ein Wort aus dem RAM und inkrementier die Leseadresse. Diesen Wert
addiere ich einfach auf meine ursprüngliche Variable IW1. Dauert also
auch nochmal 15µs.
Die Daten stehen ja immer erst einen Takt später zur Verfügung, was ja
nichts macht, dann werden sie halt erst im nächsten Takt zu IW1 addiert.
Ich muss dann nur die Schleifen jeweils ein Inkrement länger laufen
lassen, damit beim letzten Wert nicht nur die Adresse erhöht wird,
sondern auch Daten in oder aus dem RAM geholt werden.
Wahrscheinlich lässt sich das Zwischenspeichern im diffarray bzw jetzt
ja dann diffram sogar wegrationalisieren. Ich werde es aber erstmal so
machen. Die 30µs Verarbeitungszeit sind dann halt so. Gehen müsste es
trotzdem.
Klingt das halberwegs vernünftig?;)
ni schrieb:> Die 30µs Verarbeitungszeit sind dann halt so.
Wenn reicht... ;-)
Wenn du ein DPRAM hast, könntest du das Schreiben und Auswerten
parallelisieren. Allerdings musst du dann aufpassen, dass du beim Lesen
das Schreiben nicht überholst...
> Klingt das halberwegs vernünftig?;)
Das passt soweit. Die kleinen Problemchen, die sich dabei ergeben, musst
du eben aus dem Weg räumen.
Ein Denkanstoß:
Nachdem du es jetzt so machst, dass du offenbar erst 15µs lang "von vorn
nach hinten" ins RAM schreibst, und dann 15µs "von vorn nach hinten"
verarbeitest, warum verarbeitest du das Eingangssignal dann nicht direkt
"von vorn nach hinten" oder sogar dauernd durchlaufend "on the fly"?
Lothar M. schrieb:>> Klingt das halberwegs vernünftig?;)> Das passt soweit. Die kleinen Problemchen, die sich dabei ergeben, musst> du eben aus dem Weg räumen.
Ja auf "Compilieren" drücken und funktioniert, erwarte ich auch nicht;D
Lothar M. schrieb:> Nachdem du es jetzt so machst, dass du erst 15µs lang "von vorn nach> hinten" ins RAM schreibst, und dann 15µs "von vorn nach hinten"> verarbeitest, warum verarbeitest du das Eingangssignal dann nicht direkt> "von vorn nach hinten" oder sogar dauernd durchlaufend "on the fly"?
Das ist das, was ich mit wegrationalisieren meinte. Je länger ich meinen
Code angeschaut habe, desto klarer wird mir, dass es eigentlich ziemlich
umständlich ist, wie ich es mache. Aber dafür weiß ich jetzt, wie man
ein RAM benutzt, das ist doch auch was!;) Danke für deine Hilfe!
Hallo,
ich habe meinen VHDL-Code nun umgebaut. Ich bin mir allerdings nicht
ganz sicher, ob ich es richtig gemacht habe;)
Der Compiler bleibt nicht mehr während der Synthese stehen, dafür
braucht er aber gefühlt ewig, um einmal durchzulaufen, wobei den größten
Teil der Zeit der Fitter verbraucht. Wir reden hier von insgesamt etwa
11 Minuten Compilingzeit... Ohne die RAMs sinds 20 Sekunden.
Im Compilation-Report ist mir aufgefallen, dass beim Punkt "Total logic
elements" nun nicht mehr <1% sondern 68% stehen.
Der Compiler spuckt außerdem unter anderem die Info "Found 1 instances
of uninferred RAM logic" aus.
ni schrieb:> 11 Minuten Compilingzeit
je nach Größe des Systems kann das auch länger dauern. Bei mir laufen
auch Designs 2h durch Synthese+Implementierung, und das ist nicht mal
der Extremfall.
ni schrieb:> Der Compiler spuckt außerdem unter anderem die Info "Found 1 instances> of uninferred RAM logic" aus.
Tja - es ist eben doch nicht alles RAM, was glänzt ;).
Lies' Dir das Kapitel mit der RAM-Inferierung noch einmal durch.
Klakx schrieb:> ni schrieb:>> 11 Minuten Compilingzeit>> je nach Größe des Systems kann das auch länger dauern. Bei mir laufen> auch Designs 2h durch Synthese+Implementierung, und das ist nicht mal> der Extremfall.
Na dann bin ich ja noch gut bedient mit 11 Minuten;)
Wenn im Compilation Report die Anzahl der logischen Elemente gestiegen
ist, dann spricht das doch sehr dafür, dass ich distributed RAM und kein
Block-RAM gebastelt hab? Ich habe nicht explizit ein wait until o.ä. wie
in Lothars Beispiel zum RAM verwendet, da meine statemaschine sowieso
auf die steigende Flanke des Taktsignals reagiert.
ni schrieb:> Ich habe nicht explizit ein wait until o.ä. wie in Lothars Beispiel zum> RAM verwendet
Aber du hast den Abschnitt "Inferring RAM" o.ä. im Synthesizer Handbuch
gelesen und dich an die Beschreibung und die Beispiele dort gehalten?