Hallo zusammen,
die Synthese meines Projekts in ISE wurde nun nach knapp 24h Stunden
durch mich abgebrochen. Um den Fehler zu finden wurde ein RAM-Modul
(siehe Code) auskommentiert und siehe da, die Synthese benötigt nur
wenige Minuten.
Ich habe nun herausgefunden, dass diese Verzögerungen in der Synthese
durch die Wahl des RAMs hervorgerufen wird
(http://stackoverflow.com/questions/20853824/synthesize-xst-in-xillinx-get-a-long-time).
Laut diesem Beitrag soll die Synthese eines Distributed-RAMs sehr lange
dauern. Meiner Meinung nach erzeuge ich allerdings einen Block-RAM (nach
http://www.lothar-miller.de/s9y/archives/20-RAM.html).
Zur Funktion des Moduls:
Bei aktivem WRITE_PIN werden die Daten für Realteil und Imaginärteil
taktweise eingelesen, bis der Speicher voll ist. Nach jedem Takt wird
dazu die Schreibadresse um 1 erhöht. Das Einlesen der 8 verschiedenen
Kanäle erfolgt sequenziell.
Bei aktivem READ_PIN werden die Daten für Realteil und Imaginärteil
taktweise ausgelesen. Nach jedem Takt wird dazu die Leseadresse um 1
erhöht. Das Auslesen der 8 verschiedenen Kanäle erfolgt parallel.
Zu den Definitionen:
1
subtypeRAM_INissfixed(8downto-8);
2
typeRAM_OUTisarray(integerrange<>)ofRAM_IN;
3
4
constantDATA_WD:integer:=12;
5
constantCHANNELS:integer:=8;
6
constantSAMPLES:natural:=1024;
Worin liegt hier mein Problem, dass die Synthese so lange dauert? Gibt
es Lösungsmöglichkeiten?
Was ich bereits versucht habe ist, den RAM-Style in den
Syntheseeinstellungen auf "Block" zu stellen, aber ohne Erfolg.
Vielen Dank schonmal und Grüße
Andy
Andy schrieb:> Meiner Meinung nach erzeuge ich allerdings einen Block-RAM
Niemals. Du hast ja nicht mal einen Takt im System!
Das ganze Ding ist ein Mega-Monster-Latch!
So wird kein Takt beschrieben, und der RST fehlt in der Sensitivliste
(eigentlich nocht viel mehr, aber das nur weil fehlerhafterweise der
Takt keiner ist...).
Weil 'event fehlt ist hier nirgends ein Takt:
1
if(RST='1')then
2
3
elsifCLK='1'andWRITE_PIN='1'then
4
5
elsifCLK='1'andREAD_PIN='1'andrdy_net='1'then
6
7
elsifCLK='1'andADR_R>SAMPLES*CHANNELS-1then
Das hier ist dann im selben Zusammehang noch eine gut versteckte
kombinatorische Schleife:
1
elsifCLK='1'...then
2
ADR_W:=ADR_W+1;
Siehe
http://www.lothar-miller.de/s9y/archives/42-Kombinatorische-Schleifen.html> Gibt es Lösungsmöglichkeiten?
Ja.
1. Simuliere das Design.
2. lies die Synthese-Warnungen und Meldungen. Wenn da was von
"incomplete sensitivity list" steht, dann ist die Simulation falsch.
Wenn da was von "latch" oder "combinatorial loop" steht, dann hast du
Murks im Design.
3. verwende KEINE speichernden Variablen (die sind hier zwar nicht der
Grund für den Fehler, aber sie verschleiern ihn zusätzlich).
4. mach die Fehler raus... ;-)
Man nehme Dr. Oetker, oder schlicht einen RAM aus dem Core Generator.
Dann muss die Synthese auch nicht raten. Wenn es nach 24h immer noch
nicht fertig war, ist das ein Bug in der Software, die hätte eigentlich
viel eher fertig sein müssen oder selber mit einem Fehler abbrechen
sollen.
Falk Brunner schrieb:> oder schlicht einen RAM aus dem Core Generator.
Oder man instatiiert das RAM manuell, dann kann man es sogar noch nach
Jahren und nach mehreren Updates pflegen und ändern.
> einen RAM aus dem Core Generator.
Auf jeden Fall aber hat man dann nur die Anschlüsse, die so ein RAM eben
hat, und kann z.B. nicht einfach parallel das ganze RAM woanders
hinkopieren.
@ Lothar Miller (lkmiller) (Moderator) Benutzerseite
>> oder schlicht einen RAM aus dem Core Generator.>Oder man instatiiert das RAM manuell, dann kann man es sogar noch nach>Jahren und nach mehreren Updates pflegen und ändern.
Das ist was für die alten Haudegen und Könner!
>> einen RAM aus dem Core Generator.>Auf jeden Fall aber hat man dann nur die Anschlüsse, die so ein RAM eben>hat, und kann z.B. nicht einfach parallel das ganze RAM woanders>hinkopieren.
Was? Gibts da kein memcpy() in VHDL?
Falk Brunner schrieb:> Man nehme Dr. Oetker, oder schlicht einen RAM aus dem Core> Generator.> Dann muss die Synthese auch nicht raten. Wenn es nach 24h immer noch> nicht fertig war, ist das ein Bug in der Software, die hätte eigentlich> viel eher fertig sein müssen oder selber mit einem Fehler abbrechen> sollen.
Naja, wenn ich die RAMs per VHDL beschreibe und mich an den XST User
Guide halte, ist die Synthese viel schneller als wenn ich erst den IP
Core erzeuge. Denn das dauert auch eine gefühlte Ewigkeit. Wenn man nur
lokal arbeitet und den Core als Netzliste immer da hat, OK, aber wir
bauen alle Designs aus den Quellen auf einem Server, da ist das ein
deutlicher Unterschied.
@ Christian R. (supachris)
>Naja, wenn ich die RAMs per VHDL beschreibe und mich an den XST User>Guide halte, ist die Synthese viel schneller als wenn ich erst den IP>Core erzeuge.
Jaja, Superchris ist superschnell. Mal sehen wie lange du brauchst, um
Dual Port, Write enable Eingänge und Read before Write Eigenschaften
etc. VHDL-gerecht zu beschreiben.
> Denn das dauert auch eine gefühlte Ewigkeit. Wenn man nur>lokal arbeitet und den Core als Netzliste immer da hat, OK, aber wir>bauen alle Designs aus den Quellen auf einem Server, da ist das ein>deutlicher Unterschied.
Ja und? Wenn der Core einmal generiert ist, wo ist das Problem?
Leute gibt . . .
Falk Brunner schrieb:> Mal sehen wie lange du brauchst, um> Dual Port, Write enable Eingänge und Read before Write Eigenschaften> etc. VHDL-gerecht zu beschreiben.>
und wenn jemand (ich z.B.) fast immer nur je einen dedizierten read und
write Port braucht, das ganze voll synchron laeuft und mir
read-before-write und Konsorten wurscht sind (weil ich z.B. in einem 1ms
Testsystem arbeite und mir Jitter (neuer oder alter Wert) da egal sind
oder ich es sogar ausschliessen kann)? Tja, dann kann ich dieses RAM in
X, in A, und in L unveraendert verwenden...
Und viel schneller simulieren tuts auch noch.
>> Ja und? Wenn der Core einmal generiert ist, wo ist das Problem?>
wenn ich die Plattform wechsle?
Und ausserdem habe ich persoenlich wenig Bock drauf, mich mit den
Core-Generatoren rumzuschlagen...
Falk Brunner schrieb:> Ja und? Wenn der Core einmal generiert ist, wo ist das Problem?
Man checkt halt nur im allergrößten Notfall Binärdateien ins SVN ein.
Und das VHDL macht man ein mal mit ein paar Generics und dann muss man
doch doch nicht immer tippen.
@berndl (Gast)
>wenn ich die Plattform wechsle?
Täglich! Auf dem Bahnhof!
>Und ausserdem habe ich persoenlich wenig Bock drauf, mich mit den>Core-Generatoren rumzuschlagen...
Dann geh angeln oder stricken. ;-)
Falk Brunner schrieb:> @berndl (Gast)>>>wenn ich die Plattform wechsle?>> Täglich! Auf dem Bahnhof!>>>Und ausserdem habe ich persoenlich wenig Bock drauf, mich mit den>>Core-Generatoren rumzuschlagen...>> Dann geh angeln oder stricken. ;-)
ist dir ne Laus ueber die Leber gelaufen?
(evtl. ein zickender Core-Generator? Duck und wech)
Falk Brunner schrieb:> Das ist was für die alten Haudegen und Könner!>>>> einen RAM aus dem Core Generator.>>Auf jeden Fall aber hat man dann nur die Anschlüsse, die so ein RAM eben>>hat, und kann z.B. nicht einfach parallel das ganze RAM woanders>>hinkopieren.>> Was? Gibts da kein memcpy() in VHDL?
O'Gott, memcpy() ist doch voll GOTO und voll unsicher. - Da gibt es
besseres:
So ein FPGA besteht doch aus konfigurierbaren Silizium -> kann man das
nicht zu ner passenden sandbox zusammenschieben ???
Christian R. schrieb:> Man checkt halt nur im allergrößten Notfall Binärdateien ins SVN ein.
Und vor allem: Wie checkt man die Mausklicks die man machen muss ins SVN
ein? Nee, lieber plain VHDL wenns geht...
berndl schrieb:> Christian R. schrieb:>> Man checkt halt nur im allergrößten Notfall Binärdateien ins SVN ein.>> Und vor allem: Wie checkt man die Mausklicks die man machen muss ins SVN> ein? Nee, lieber plain VHDL wenns geht...
Screenshoot von Coregen Masken sind gut für die Dokumentation von
"Mouseclicks". Weniger selbsterklärend sind die log von coregen - tut
aber auch seinen Zweck.
MfG,
Falk Brunner schrieb:> Was? Gibts da kein memcpy() in VHDL?
Klar, funktioniert sogar genauso wie in einer CPU: Mittels einer
State-Machine wird ein Eintrag eines RAMs X in ein anderes RAM Y
kopiert. Geht halt schneller als in einer CPU. Und wo liegt jetzt dein
Problem?
@ berndl (Gast)
>> Was? Gibts da kein memcpy() in VHDL?>Klar, funktioniert sogar genauso wie in einer CPU: Mittels einer>State-Machine wird ein Eintrag eines RAMs X in ein anderes RAM Y>kopiert. Geht halt schneller als in einer CPU. Und wo liegt jetzt dein>Problem?
Nirgendwo. Allerdings hast du eins. Dein Ironiedetektor ist kaputt ;-)
berndl schrieb:> Nee, lieber plain VHDL wenns geht...
Meien Rede. Klar, geht nicht immer, dann aber die Cores als xco Datei
oder xci von Vivado. Nur dauert das Bauen dann halt länger.
Falk Brunner schrieb:> Dein Ironiedetektor ist kaputt ;-)
ok, Entschuldigung, die Ironie hab' ich wirklich nicht gesehen. Ich
dachte echt, du meinst das ernst...
Christian R. schrieb:> berndl schrieb:>> Nee, lieber plain VHDL wenns geht...>> Meien Rede. Klar, geht nicht immer,
Vielleicht mal auflisten "wo es geht", "wo es geht aber nicht sinnvoll
ist "und "wo Coregen/Instanzierung Makros die bessere Wahl sind":
Inference aus VHDL-Array:
-alle SinglePort (SP) RAM/ROMS, ausser man will die ROM/RAM's nicht über
VHDL initialisieren (sondern aus *.ceo oder ähnlich)
--mgl. Ausnahme: SP-RAM mit BRAM Parity generierung
-alle DualPort (DP) RAM/ROMS mit gleicher datenbusbreite
--mgl. Ausnahme wie oben
Generierung aus Coregen:
-DP mit unterschiedlichen Datenbusbreiten
(geht zwar auch als plain-VHDL ist aber dann Synthese-tool spezifisch)
-FIFO's und sonstiger krams mit pointer-handling,underun/overrun
handling
-CIM
BTW: Bei Sicherheitskritischen Designs bspw Avionic ist inference nicht
gern gesehen. Um die Stör-Komplexität "Optimimierende Tools" zu
beherrschen, besteht man dort auf Instanzierte Makros.
MfG,
Da muss ich dir zustimmen, FIFOs und bus matching und/oder dual clock
fifos tu ich mir auch nicht in VHDL an, das können die bei Xilinx
besser. Aber single port und dual port mit gleicher Busbreite lässt sich
ja sehr einfach und lesbar beschreiben.
Lothar Miller schrieb:>> Gibt es Lösungsmöglichkeiten?> Ja.> 1. Simuliere das Design.> 2. lies die Synthese-Warnungen und Meldungen. Wenn da was von> "incomplete sensitivity list" steht, dann ist die Simulation falsch.> Wenn da was von "latch" oder "combinatorial loop" steht, dann hast du> Murks im Design.> 3. verwende KEINE speichernden Variablen (die sind hier zwar nicht der> Grund für den Fehler, aber sie verschleiern ihn zusätzlich).> 4. mach die Fehler raus... ;-)
Vielen Dank, ich habe das Modul entsprechend bearbeitet und es
funktioniert auch. Das ganze Prozedere hab ich auch für das restliche
Projekt durchgeführt und hab nun eine weitere Frage:
Code vorher:
ist korrekter. Aber wenn's der XST frisst, wird er es schon korrekt
umgesetzt haben.
Rein vom Übersichtlichkeit her würde ich die Adress-Generierung und den
Zugriff auf das RAM trennen.
Andy schrieb:> Wieso wird der Takt so stark verlangsamt?
Vorher war wie gesagt nirgendwo im geposteten Codeabschnitt irgendein
Takt involviert. Das war einfach ein Monsterlatch. Davon vermutlich die
Hälfte wegoptimiert...
> Wieso wird der Takt so stark verlangsamt?
Evtl. weil jetzt richtige und korrekte Hardware implementiert wird. Und
lass dich nicht täuschen: 170MHz sind schnell. Mach mal ein wenig was
dazu und deine Taktfrequenz wird schnell nch unten gehen...
> Maximale Taktfrequenz vorher: 295 MHz> Maximale Taktfrequenz nachher: 167 MHz
Wer sagt das? Besser gefragt: welcher Teil der Toolchain sagt das?
> Wieso wird der Takt so stark verlangsamt?
Der ungünstige und unnötige asynchrone Reset kann da seinen eigenen Teil
dazu beitragen:
Lothar Miller schrieb:> Wer sagt das? Besser gefragt: welcher Teil der Toolchain sagt das?
Diese Werte habe ich dem "Timing Summary" entnommen.
Ich habe die Beiträge nun so verstanden man soll generell (für
Stabilität, generell soll heißen für mich, dass es Sonderfälle gibt soll
nicht berücksichtigt werden) synchrone Resets verwenden, kann man das so
sagen?
Lothar Miller schrieb:> unnötige asynchrone Reset
Wieso ist der Reset unnötig, das konnte ich nicht nachvollziehen?
Ich habe jetzt auch mit Hilfe von
(https://www.mikrocontroller.net/articles/VHDL#Synthese) herausgefunden
was mein Fehler ist, ich habe einmal einen CLK=1 und einmal CLK=0
abgefragt... seit ich das geändert habe ist der Takt wieder bei max 295
MHz.
Die Abfrage auf CLK=0 habe ich gemacht, da der verwendete IP-Core die
Daten nicht synchron ausgibt, sie werden kurz nach der steigenden
Taktflanke ausgegeben. Kann ich die Daten einfach mit
(http://www.lothar-miller.de/s9y/archives/41-Einsynchronisieren-von-asynchronen-Signalen.html)
Andy schrieb:> Ich habe die Beiträge nun so verstanden man soll generell (für> Stabilität, generell soll heißen für mich, dass es Sonderfälle gibt soll> nicht berücksichtigt werden) synchrone Resets verwenden, kann man das so> sagen?
Für Xillinx ja. Für Altera gilt (zumindest für Cyclone), dass
asynchone Resets besser sind. Fazit: Du musst immer schauen, wie die
Hardwareelemente des FPGAs aussehen, das du nutzen möchtest.
Andy schrieb:> ich habe einmal einen CLK=1 und einmal CLK=0 abgefragt... seit ich das> geändert habe ist der Takt wieder bei max 295 MHz.
Du hattest eigentlich immer die 300MHz. Nur, weil du mal die fallende
und mal die steigende Flanke verwendet hast, hast du gleichzeitig die
Taktfrequenz auch verdoppelt, weil die beteiligten Flipflops nur die
halbe Periodendauer Ruhe haben.
Andy schrieb:> da der verwendete IP-Core die Daten nicht synchron ausgibt, sie werden> kurz nach der steigenden Taktflanke ausgegeben.
Das ist normal und die Grundlage jedes synchronen Design: es kommtnein
Takt, daraufhin herrscht arge Unruhe im FPGA, bis die Kombinatorik die
neuen Zustände ermittelt hat. Das muss rechtzeitig vor dem nächsten Takt
fertig sein, denn dann werden die Zustände in die Flipflops übernommen
und das Spiel beginnt von vorn.
Und genau so macht es der IP-Core: die Daten kommen ein paar ns nach dem
Takt am Ausgang an.
Olga schrieb:> Für Altera gilt (zumindest für Cyclone), dass asynchone Resets besser> sind.
Sie sind nicht besser im Sinn von stabiler, sondern sie machen das
Design schneller, weil Altera "nur" den asynchronen Modus der
Flipflops kann. Für Lattice gilt dad auch...
Das darf man jetzt aber nicht so locker dahersagen. Auch Altera
empfiehlt Sinnvollerweise, ein externes Resetsignal einzusynchonisieren.
Denn der gefährliche Augenblick ist auch bei Altera der, bei dem der
Reset inaktiv wird und das ganze Design loslaufen soll.
Und auf keinen Fall darf mit kombinatorischen Verknüpfungen auf den
Reset losgegangen werden. Sonst sorgen Glitches und Spikes für seltsames
Verhalten...
Fazit bleibt aber: für ein gutes Design muss man "seine" Hardware
kennen.
Olga schrieb:> Andy schrieb:>> Ich habe die Beiträge nun so verstanden man soll generell (für>> Stabilität, generell soll heißen für mich, dass es Sonderfälle gibt soll>> nicht berücksichtigt werden) synchrone Resets verwenden, kann man das so>> sagen?>> Für Xillinx ja. Für Altera gilt (zumindest für Cyclone), dass> asynchone Resets besser sind. Fazit: Du musst immer schauen, wie die> Hardwareelemente des FPGAs aussehen, das du nutzen möchtest.
Das Problem bei Xilinx ist das die beiden Setz/rücksetzeingänge der FF
entweder asynchron oder synchron benutzt werden können, aber nicht
beides gleichzeitig. Ein FF mit asynchronen Clear kann nur noch als D-FF
(evtl. auch T-FF) konfiguriert werden das heisst synchrones
Setzen/rücksetzen muß durch zusätzliche Logik vor dem D-Eingang
nachgebaut werden. Das macht das design langsamer und größer.
Die entsprechende AN findet man by Xilinx mit den Such begriff "Dont't
mix you drinks"
http://www.xilinx.com/support/documentation/white_papers/wp275.pdf S.5
Bei der Gelegenheit sollte man auch nachdenken, ob man den Reset an
diesem FF wirklich braucht. manchmal kann man komplett darauf verzichten
(Schieberegister) manchmal genügt der PowerUp Reset.
Die entsprechende AN findet man by Xilinx mit den Such begriff "Get
smart about reset":
http://www.xilinx.com/support/documentation/white_papers/wp272.pdf
MfG,