Hallo Zusammen,
nachdem mir neulich hier schon geholfen wurde und das Projekt
vorrangeschritten ist, gibt es die nächste Aufgabe für die Profis
hier;-)
Randbedingungen:
- FPGA-Neuling...
- Board: De0 Nano Terasic
- Ziel:
Phasenversatz zwischen zwei Rechtecksignalen (4 MHz) mit hoher
Geschwindigkeit bestimmen und "Position" als Quadratursignal ausgaben.
Dabei müssen die Überlaufe wenn der Phasenversatz von Minimal->Maximal
(Rückwärts) bzw. Maximal->Minimal springt berücksichtigt werden um ein
durchgehendes Positionssignal zu erlangen. Ausgaberate des
Quadratursignals sollte 250kHz betragen.
- Aufbau des Programs:
Modul "referenzcounter" zählt die Clockzyklen mit 200MHz zwischen zwei
steigenden Flanken des Referenzsignals. Hier ergibt sich der Zählwert 50
pro Periode, da über 16 Werte aufsummiert wird folgt referenzcounts= 800
Modul "flankentimer" zählt die Clockzyklen zwischen steigender Flanke
vom Referenz-Signal bis zur steigenden Flanke des Angle-Signals. Hier
ergibt sich ein Wert zwischen 0 und 50 für das Signal
flankentimercounts.
Hierbei wird auch das invertierte Angle-Signal verwendet um in Realität
an den Überläufen eine saubere Auswertung zu erhalten.
Modul "eval_flankentimer" summiert wieder 16 Messungen des
flankentimer-Moduls zusammen und gibt den Wert aus. Dabei wird wieder
der positive und negative Überlauf berücksichtigt und die Zählrichtung
bestimmt.
Modul "fastclock_pll_200mhz" ist eine 200MHz Pll aus dem
Megafunction-Wizard um die 200MHz für die Phasenversatzbestimmung zu
erzeugen.
- Problem:
In der Simulation der Testbench sieht das auch alles ganz nett aus. Es
sind sicher noch ein paar unsaubere Abläufe (Startphase, ...) drin aber
es macht was es soll. Nun wollte ich dieses aber mal auf das Board
spielen und erste reale Versuche machen. Hierbei hagelt es aber
Timing-Fehler ("Worst-Case Timing Paths Slack -1.500", "Timing
requirements not met!") Sicher für die Profis auch nachvollziehbar weil
in meinem sdc-File momentan nur folgendes steht:
Auf der Suche nach einer Lösung hatte ich schon diverse Versionen mit
zusätzlichen Zeilen in dem sdc-File um irgendwelche Timing-Constraints
zu erstellen. Leider, trotz diverser Tutorials und Literatur, ohne
Erfolg. Die grundsätzliche Problematik und Notwendigkeit für was die
Timing-Constraints sind ist mir klar. Nur die praktische Umsetzung
klappt leider nicht.
Jetzt wäre es natürlich super, wenn mir mal jemand einen Startpunkt (am
besten mit ein paar Zeilen fürs sdc-File) gibt, wie ich solche Pfade
Richtig mit Constraints versehe. Den rest versuche ich dann gerne
selber.
Das Modul wäre zur Erzeugung des Quadratursignals ist noch gar nicht
aktiviert. Dieses funktioniert in der Simulation auch, in Realität auf
dem Board geht dann natürlich noch weniger.
Im Anhang mal die Testbench sowie die Dateien aus dem normalen
Quartus-Projekt für das Board.
Sollte es sonst noch Anmerkungen geben, gerne her damit. Als Grundlage
bitte einen vhdl/FPGA Anfänger sehen.
Viele Grüße,
Fabian
Flyget schrieb:> Modul "referenzcounter"> Modul "flankentimer"
Kann ich leider auf dem Handy mangels Entpacker nicht ansehen...
> Hierbei hagelt es aber Timing-Fehler ("Worst-Case Timing Paths Slack> -1.500", "Timing requirements not met!") Sicher für die Profis auch> nachvollziehbar weil in meinem sdc-File momentan nur folgendes steht:
Wenn schon allein eine Taktangabe mit 20MHz Probleme macht, dann bringen
hier weitere Constraints nichts mehr (die würden das "Problem" ja
bestenfalls noch verschärfen). Meine vermutung: du hast hier vermutlich
irgendein Problem bei der Datenübergabe zwischen verschiendenen
Taktdomänen. Oder das Design ist prinzipiell zu langsam (weil zu
umständlich).
> Aufbau des Programs: Modul "referenzcounter" zählt die Clockzyklen mit> 200MHz zwischen zwei steigenden Flanken des Referenzsignals
Um ein Design (oder einen Teil daraus) mit 200MHz laufen zu lassen, muss
man schon mal ab&an etwas Gehirnschmalz investieren. Denn auch wenn man
es angesichts der GHz-Angaben aus der PC-Ecke meinen könnte: 200MHz sind
recht sportlich.
Nur mal so gefragt: was passiert, wenn du in deinem Design einen anderen
Speedgrade einstellst?
Ohne Details angeschaut zu haben:
in counter_between_rising_edges.vhd
steht in Zeile 48
wait until rising_edge(clk);
Soll das synthetisiert werden?
Flyget schrieb:> Modul "referenzcounter" zählt die Clockzyklen mit 200MHz zwischen zwei
Das fehlt im Rar-Archiv
Schlumpf schrieb:> in counter_between_rising_edges.vhd>> steht in Zeile 48>> wait until rising_edge(clk);>> Soll das synthetisiert werden?
Vermutlich schon. Und wenn das die einzige 'wait until'-Anweisung im
Prozess ist, funktioniert das auch bei allen mit bekannten
(Xilinx/Intel/Lattice) Synthesetools problemlos.
Für mehrere 'wait untils' hat Lothar hier mal einen Test gemacht:
http://www.lothar-miller.de/s9y/archives/47-wait-im-Prozess.html
Duke
Auch wenn es funktioniert und bestimmt nicht die Ursache des Problems
ist, würde ich so ein Konstrukt trotzdem nicht verwenden.
Flyget:
Kannst du mal den Pfad angeben, der das Timing nicht schafft?
Hui, vielen Dank für die schnellen Antworten
@ Schlumpf
Das Modul "referenzcounter" besteht aus der entity
counter_between_rising_edges. Sorry, mein Fehler, ich ändere das gleich
oben noch ab.
Das mit dem "wait until rising_edge(clk);" is natürlich hier ebenfalls
Käse und ein Prozess ohne Sensitivitätsliste auch. Habe das gleich mal
noch angepasst. Vmtl. hätte ich früher in die Weihnachtsferien müssen...
@ Lothar
Hier mal noch der Code der beiden Module fürs Handy. Is aber von meiner
Seite nicht so eilig, dass es auf dem Handy gelesen werden muss;-)
Modul Referenzcounter (counter_between_rising_edges):
ifcounts_ref_angle_inv_internal>12andcounts_ref_angle_inv_internal<38then-- and (counts_ref_angle_internal > 38 or counts_ref_angle_internal < 12) then
if(new_data='1')then-- Ausgabewert ändern wenn fallende Flanke am timer signal (zählung gestoppt)
176
177
-- zähler stoppen
178
timer_signal<='0';
179
timer_inv_signal<='0';
180
181
-- zählwert ausgeben
182
counts_out<=counts_summation;
183
184
-- new_data Flag setzen
185
new_data_out<='1';
186
187
-- Zähler zurücksetzen
188
counts_ref_angle_internal<=1;
189
counts_ref_angle_inv_internal<=1;
190
191
new_data<='0';
192
193
else
194
195
new_data_out<='0';
196
197
198
endif;
199
200
201
202
203
else
204
205
--resetbedingung
206
207
208
209
210
endif;
211
212
213
endif;
214
endprocess;
215
endbehave;
Zum Thema Taktdomänen habe ich den pragmatischen Ansatz verfolgt: Wenn
ich alles mit den 200MHz laufen lasse, muss ich mich hierrum nicht
kümmern. Möglicherweise der falsche Ansatz als Anfänger.
Die 200MHz ergeben sich um eine gewisse Auflösung zu erhalten. In
Realität sieht das ganze folgendermaßen aus. Die 4MHZ Rechtecksignale
ergeben sich aus 4MHz Sinussignalen die nach einer kapazitiven,
kontaktlosen Übertragung in Rechtecke gewandelt werden. Der Überlauf an
diesen Signalen entsteht bei einem Winkel von 10°. Um eine Auflösung von
später ~0,1° auf dem Quadratursignal zu erhalten sind die 50 Zählwerte
die sich aus den 200MHz ergeben und eine Aufsummation von 16 Messwerten
gedacht. Die Anzahl der aufsummierten Werte soll später mal noch
angepasst werden, das war jetzt einfachmal der erste Schuss.
Wenn man, wie ich, von AVRs kommt, sind die 200MHz auch schon schnell.
Aber für diese Anwendung müsste doch eigentlich eine Realisierung im
FPGA am sinnvollsten sein. Die Abtastung und Verarbeitung ist in einem
DSP sicherlich auch nicht so ohne weiteres hingeschrieben. Aber noch bin
ich zuversichtlich, dass die 200MHz im FPGA mit eure Hilfe machbar
sind;-)
Den Speedgrade müsste meines Wissens nach schon bei C6 sein, schneller
gibts ja glaube ich eh nicht. Oder täusche ich mich hier. Ich habe im
Quartus das De0 Nano Board ausgewählt.
Beste Grüße und vielen Dank,
Fabian
Flyget schrieb:> Wenn> ich alles mit den 200MHz laufen lasse, muss ich mich hierrum nicht> kümmern. Möglicherweise der falsche Ansatz als Anfänger.
Das ist genau der richtige Ansatz für Anfänger ;-)
Denn jeder Taktübergang erfodert Hirnschmalz und constraining.
Wenn du alles mit dieser schnellen Taktrate laufen lässt, darf die
Logiktiefe zwischen zwei Registern nicht zu groß werden.
Daher die Frage, welche Pfade denn kritisch sind.
Eventuell kann man eine Logik auf "aufbrechen" und in zwei Takten
abarbeiten..
Also mit einem Zwischenregister.
Was synthetisiert es dir denn bei den integer-Signalen für eine Breite?
Brauchst du diese Breite? Ansonsten mal einen range bei den integern
angeben, dann werden die Addierer kürzer und damit evtl. die kritischen
Pfade.
Flyget schrieb:> @ Lothar> Hier mal noch der Code der beiden Module fürs Handy.
Schon mal ein Anfang. Aber einfacher wäre es tatsächlich, wie in der
Bedeinungsanleitung nur die VHDL-Dateien (als *.vhd oder *.vhdl)
anzuhängen:
1
Antwort schreiben
2
Wichtige Regeln - erst lesen, dann posten!
3
4
Groß- und Kleinschreibung verwenden
5
Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang
> Um eine Auflösung von später ~0,1° auf dem Quadratursignal zu erhalten> sind die 50 Zählwerte die sich aus den 200MHz ergeben und eine> Aufsummation von 16 Messwerten gedacht.
Da sind niemals irgendwo 32 Bit Zählerbreite nötig...
Und deshalb ist es nicht gut, einfach nur unconstrained Integer zu
nehmen und dem Synthesizer das "Kürzen" zu überlassen. Denn ein 32 Bit
breiter Zähler mit Bedingungen ist wesentlich langsamer als ein 16 oder
gar nur 8 Bit breiter Zähler (Stichwort: Carry-Chain).
Zudem kannst nur du wissen, welcher Bereich tatsächlich sinnvoll ist.
Und nur wenn du einen sinnvollen Bereich angibst, kann der Simulator
einen Überlauf anmeckern.
@ Schlumpf
Das klingt doch schonmal gut.
Jetzt habe ich soeben nochmal rumgespielt (Kommentare eingefügt, alte
übriggebliebene und ungenutzte Signale entfernt, ...) und nochmals auf
Kompilieren geklickt. Und Quartus hat mal wieder eine überraschung für
mich... diesmal keine Timing-Fehler. Bisher hat der Kompilieren-Button
in Quartus noch einen mystischen Hauch an sich... ich hatte es schon
öfters dass sich bei quasi unverändertem Code plötzlich andere
Ergebnisse/Warnings/Fehler ergeben. Gefühlt nimmt der Kompiler manchmal
nicht die aktuellen Dateien...
In der Version in den rar-Archiven gibt es also wohl doch kein Problem
im Timing. Ich füge euch noch die zwei fehlenden Module, "Berechnung
Quadratursignal" und "Quadraturausgabe" hinzu, damit sollten dann (nach
letztem Kompilierstand...) auf jedenfall die Timingfehler auftreten.
Habe nur heute keinen Zugriff mehr, daher wird das erst morgen früh was.
Ursprünglich dachte ich, ich gebe euch das Konstrukt aus Modulen wo
erstmals Fehler im Timing auftreten...
Das mit dem Zwischenregister hatte ich auch mal als Lösung versucht,
aber auch ohne Erfolg.
Wie gesagt, morgen mehr, dann kann ich auch die kritischen Pfade im
Timing benennen!
Vielen Dank trotzdem schonmal an alle beteiligten hier, super Service!
P.S. leider kann ich den ersten Beitrag als Gast nicht editieren. Ich
melde mich wohl demnächst doch an.
Flyget schrieb:> Bisher hat der Kompilieren-Button> in Quartus noch einen mystischen Hauch an sich... ich hatte es schon> öfters dass sich bei quasi unverändertem Code plötzlich andere> Ergebnisse/Warnings/Fehler ergeben. Gefühlt nimmt der Kompiler manchmal> nicht die aktuellen Dateien...
Das ist völlig normal. Wenn man auch nur einen Hauch ändert, kommt u.U.
ein deutlich verändertes Timing raus.
Hier:
https://fpgawiki.intel.com/uploads/e/e6/FittingAlgorithms_and_SeedSweeps.pdf
ist ein Dokument, daß das Verhalten m.E. ziemlich gut erklärt.
Schlumpf schrieb:> wait until rising_edge(clk);>> Soll das synthetisiert werden?
Eine Synthesesoftware, die das nicht kann, würd' ich wegschmeissen.
Und den dazugehörigen Käfer gleich mit.
Markus F. schrieb:> Eine Synthesesoftware, die das nicht kann, würd' ich wegschmeissen.> Und den dazugehörigen Käfer gleich mit.
Synthetisierbar ja, aber völlig unübliche Praxis.
Für mich wäre es kein Grund Tool samt Chips zu entsorgen, wenn es das
nicht kann. Denn ich würde nicht auf die Idee kommen, ein wait Statement
in synthetisierbarem Code zu verwenden. Vorallem, weil es dafür keinen
triftigen Grund gibt, das zu tun.
Aber kann jeder halten, wie er will.
Schlumpf schrieb:> Synthetisierbar ja, aber völlig unübliche Praxis.
In meiner Filterblase schon.
> Vorallem, weil es dafür keinen> triftigen Grund gibt, das zu tun.
+ der Code wird lesbarer, weil eine Einrückungsebene wegfällt
+ die Sensitivitätsliste fällt weg (wird automatisch richtig gemacht)
+ man kann nicht aus Versehen asynchrone Logik in den Prozess einbauen
Duke
Na ja, genauso kann man genug Gründe aufzählen, das nicht zu verwenden..
Aber wie ich ja sagte:
Kann jeder machen, wie er es will.
Und wenn man den Code so anschaut, der auf der Welt existiert, dann
tendieren wohl nur die wenigsten dazu, es über ein Wait-Statement zu
machen.
Duke Scarring schrieb:> Schlumpf schrieb:>> Synthetisierbar ja, aber völlig unübliche Praxis.> In meiner Filterblase schon.
Ich mach das (wenn möglich) auch nur noch so. Und Kombinatorik am
liebsten nebenläufig. Dann stimmt die Sensitivliste auch automatisch.
> + der Code wird lesbarer, weil eine Einrückungsebene wegfällt
Der Code wird auch für "Laien" (aka. "Programmierer") lesbar. Denn wenn
da als erste Zeile ein "wait until rising_edge(clk);" steht, dann steht
explizit da, was die Sensitivliste implizit macht.
Die Professoren meiner betreuten Studenten und
Abschlussarbeitschriebenden akzeptieren die "Eleganz" dieses Ansatzes
dann auch irgendwann. Steht halt immer noch nicht in den verwendeten
Büchern...
Blöd ist nur, dass manche FPGAs nach "den alten Schriften" entwickelt
sind und keinen synchronen Set/Reset haben. Da muss man dann ggfs. zur
Geschwindigkeitsoptimierung wieder "old school" mäßig mit asynchronem
Reset arbeiten, und dann geht das mit dem "wait until" leider nicht
mehr...
Schlumpf schrieb:> Aber kann jeder halten, wie er will.
So ist es. Es gibt ja auch noch Leute, die zwei Prozesse für FSM
verwenden... ;-)
Schlumpf schrieb:> Kann jeder machen, wie er es will.
Richtig.
> Und wenn man den Code so anschaut, der auf der Welt existiert, dann> tendieren wohl nur die wenigsten dazu, es über ein Wait-Statement zu> machen.
Naja, das habe ich früher (tm) auch gedacht: Code der im Netz verbreitet
ist, muß gut sein.
Stimmt aber nicht. Im Netz ist auch std_logic_arith noch weit
verbreitet.
Oder asynchrone Resets. Oder "clk'event and clk ='1'". Oder von mir aus
auch std_logic_vector statt std_ulogic_vector.
Es mag für alles Gründe gegeben haben es zu verwenden.
Dummerweise haben meisten Leute, die es wirklich drauf haben besseres zu
tun, als ihr Wissen zu teilen. Das sieht man an z.B. den vielen
mittelmäßigen Fachbüchern zum Thema Computer.
Man muß m.E. mal über alle Fallstricke gestolpert sein, um die
(zugegeben manchmal recht kleinen) Vorteile der einen oder anderen
Schreibweise zu erkennen.
Für mich ist inzwischen die oberste Priorität: einfach lesbaren Code zu
scheiben (nach der Funktionalität).
Kompliziert wird es dann von ganz alleine.
Duke
Lothar M. schrieb:> Der Code wird auch für "Laien" (aka. "Programmierer") lesbar.
Genau für die Leute, die nicht verstehen, dass sie keinen sequenziellen
Programmcode vor sich haben, sondern eine Beschreibung einer Hardware.
Genau für die Leute, die du immer korrigierst, wenn sie das Wort
"Programm" in den Mund nehmen.
Damit glauben sie erst recht, es würde an der Stelle "gewartet"..
Duke Scarring schrieb:> + der Code wird lesbarer, weil eine Einrückungsebene wegfällt
Einrückungen halte ich für ein ganz gutes Mittel um Code lesbarer zu
machen
> + die Sensitivitätsliste fällt weg (wird automatisch richtig gemacht)
Das ist in der Tat ein wirklich gutes Argument
> Für mich ist inzwischen die oberste Priorität: einfach lesbaren Code zu> scheiben (nach der Funktionalität).
Für mich ist oberste Priorität einfach lesbaren Code zu schreiben (nach
der daraus resultierenden Hardware)
Aber vielleicht bin ich da echt ein wenig old-school..
So, hier nun der versprochene neue Satz an Dateien. Wieder die Testbench
und die Board-Dateien. Die Einzeldateien sind die Boarddateien ungezipt.
Momentan kommen nur Fehler im "Slow 1200mV 85C Model". Hierbei ist unter
Worst-Case Timing Paths der Pfad von counts_ref_angle_internal ->
counts_summation als Problem gelistet. Der Slack für diesen Pfad liegt
im negativen Bereich...
Zur Erklärung:
Modul eval_quadratur_output ermittelt eine 16Bit Zahl
"signal_to_count_current_out" aus dem Maximalwert der aufsummierten
Einzelmessungen (Maximalwert 784 ergibt den Wert 32512). Diese 16Bit
Zahl wird im Modul "quadratur_output" verwendet um die zwei passenden
Bits auf die Quadratursignal-Ausgänge zu legen. Die Bits 8 und 9
entsprechen dem Wert 256. Somit wird der maximale Zählbereich von 784
durch 128 geteilt und ich erreiche die Genauigkeit von unter 0,1°
Winkelsignal auf dem Quadraturausgang.
Klingt vllt kompliziert aber war ein halbwegs plausibler Weg für mich um
keine hässlichen Divisionen, Floatingzahlen, ... oder ähnliches
verwenden zu müssen.
Noch ne allgemeine Frage:
wie deklariere ich sauber ein "constant integer" mit der range
Zuweisung. Oder passen die Tools Konstanten automatisch in ihrer
Bitbreite an, da sich diese ja nicht ändern.
Schlumpf schrieb:> Einrückungen halte ich für ein ganz gutes Mittel um Code lesbarer zu machen
Wenn eine Einrückebene weniger nötig ist, ist der Code für mich fast
automatisch lesbarer.
> Lothar M. schrieb:>> Der Code wird auch für "Laien" (aka. "Programmierer") lesbar.> Genau für die Leute, die nicht verstehen, dass sie keinen sequenziellen> Programmcode vor sich haben, sondern eine Beschreibung einer Hardware.
Ja, aber sie verstehen dann eben trotzdem, was da passiert.
> Genau für die Leute, die du immer korrigierst, wenn sie das Wort> "Programm" in den Mund nehmen.
Das wird auch weiterhin so sein.
Ich habs zwischendurch mal versucht, eine VHDL-Beschreibung (auf
vielfache Anregung hier aus dem Forum) "Programm" zu nennen. Das hat
mich wirr gemacht. Und zwischendurch musste ich zum Erklären, was da
passiert, doch wieder "Beschreibung" sagen. Diese wechselweise
Verwendung und die Gleichstellung von "Programm" und "Beschreibung" hat
dann die anderen wirr gemacht.
> Damit glauben sie erst recht, es würde an der Stelle "gewartet".
Wird ja doch auch...
> Aber vielleicht bin ich da echt ein wenig old-school..
Hauptsache, die Chose läuft.
Lothar M. schrieb:> Verwendung und die Gleichstellung von "Programm" und "Beschreibung" hat> dann die anderen wirr gemacht.
Geht mir nicht anders..
Und am Ende muss jeder für sich seinen Style finden, in dem er den
Überblick behält.
Lothar M. schrieb:> Hauptsache, die Chose läuft.
Exakt :-)
Weil mir das grade wieder aufgefallen ist, die Unconstrained Paths würde
ich ja auch gerne beheben... aber auch daran bin ich gescheitert.
Prinzipiell ist mir das Timing dieser Ein- und Ausgänge relativ egal, da
diese nicht synchron mit einem anderen Bauteil laufen müssen.
Gibts hier noch Tipps was man in so einem Fall standardmäßig für Angaben
im sdc-file macht?
Die Kombinatorik zum Generieren der "counts_summation" Register ist
recht mächtig. Hier wird "counts_ref_angle_internal" an mehreren Stellen
auf größer und kleiner x verglich und damit werden die Pfade zwischen
den Registern sehr groß
Eventuell kannst du Hilfsregsister einbauen.
z.B.
Ein Register, welches gesetzt wird, wenn
counts_ref_angle_internal > 12 and counts_ref_angle_internal < 40
Und eines, wenn
counts_ref_angle_internal > 12 and counts_ref_angle_internal < 26
Weiterhin immer von counts_ref_angle_internal eine Kopie in ein Register
anlegen.
Und dann die aktualisierung von counts_summation in Abhängigkeit des
Zustandes der Hilfsregister aus der Kopie von counts_ref_angle_internal
bilden
Das Ergebnis von counts_summation steht dann immer einen Takt später zur
Verfügung, als in deinem Code, aber wenn das kein Problem darstellt,
wäre das vielleicht eine Lösung.
Ich hoffe, ich hab so auf die Schnelle jetzt nichst Gravierendes
übersehen
Danke Schlumpf für deine Hinweise!
Ich habe mal versucht diese umzusetzen, und es tauchen jetzt auch keine
Timing-Fehler mehr für dieses Modul auf. Dafür genügend in
"eval_flankentimer". Aber auch hier verwende ich viele If-Bedingungen um
die Überläufe abzufangen. Vllt is es aber auch nur die Magie des
Kompilierenknopfes*g*
Wäre super, wenn du vllt kurz über mein verbessertes "flankentimer"
Modul schauen könntest, ob ich deine Hinweise so richtig umgesetzt habe.
Wenn ja würde ich das gleiche beim "eval_flankentimer" probieren.
Und bei Gelegenheit wäre es super wenn ihr mir hier noch Hinweise zu den
Unconstrained Paths sowie der Deklaration einer Konstanten geben
könntet.
Hab grad gesehen, da is noch ein Logikfehler im Modul flankentimer,
deshalb bricht die Simulation ab. Ich verbessere das noch und lade es
hoch sobald das Internet wieder funktioniert.
Hallo Lothar,
wissen würde ich das nicht unbedingt nennen. Ich bin eher davon
ausgegangen, dass er das als "Zahl" castet. Sauberer wäre sicherlich
wenn ich folgendes schreibe, oder?
1
ifref_input='1'andref_old_state='0'then
Das eigentliche "warum" würde ich aber natürlich gerne hören
Flyget schrieb:> ob ich deine Hinweise so richtig umgesetzt habe.
Nicht ganz.
Du hast mehrere Vergleicher, wo du counts_ref_angle_(inv)_internal mit
diversen Werten vergleichst.
Je nachdem, ob "true" oder "false" führst du bestimmte Zuweisungen aus.
Speichere das Ergebnis der Vergleicher in Register und führe dann die
Zusweisungen in Abhängigkeit dieser Ergebnisregister aus.
Da dann aber die Zuweisung einen Takt später erfolgt, musst du ggf auch
counts_ref_angle_(inv)_internal bei der Zuweisung auf counts_summation
um einen Takt verzögern (also über ein Zischenregister führen)
Hm ok, ich mache mich nochmal ans Werk. Bisher bin ich auch eher dem
Ansatz gefolgt, dass ich möglichst wenig Signale verwende, um es dem
Tool einfacher zu machen die Wege passend zu Routen.
Nur nochmal zum Verständnis bezüglich Registern. Wenn ich folgendes
schreibe:
Fabian N. schrieb:> Ich bin eher davon ausgegangen
Das ist die denkbar schlechteste Variante.
> Sauberer wäre sicherlich wenn ich folgendes schreibe, oder?> if ref_input = '1' and ref_old_state = '0' then
So mache ich das. Dann muss man auch nicht nachsehen, ob da irgendwie
zwei Zähler miteinander verglichen werden. Das war das Erste, was ich
getan habe...
> Das eigentliche "warum" würde ich aber natürlich gerne hören
Sieh dir mal an, wie std_logic definiert ist: das ist ein Aufzählungstyp
mit 9 möglichen Werten. Und die '0' steht links von der '1':
Und der Operator < ist für Integerzahlen und Aufzählungstypen definiert.
das "linkeste" Element ist das niederwertigste. Im Fall des
Aufzaählungstyps std_logic ist also das 'U' das "kleinste" Element und
'1' it größer als '0'. Aber 'L' (eine "schwache" '0') ist größer als
'1'... :-O
Siehe das LRM Kapitel 7.2, dort auf Seite 98 Zeile 128:
https://edg.uchicago.edu/~tang/VHDLref.pdfFabian N. schrieb:> Ist register2 ein Zwischenregister, oder?
Ein Signale (oder Variablen) die getaktet werden, werden als
Flipflops/Register ausgeführt.
@Lothar: super, vielen Dank für die Infos. Eigentlich ist deine
Schreibweise auch offensichtlicher beim lesen, wird übernommen.
@Schlumpf
ich hab mich nochmal an das Modul flankentimer gemacht. Und zumindest im
Report nach dem Kompilieren und im RTL-Viewer erhalte ich jetzt deutlich
weniger Logikelemente:
Vorher:
Total combinational functions: 65
Dedicated logic registers: 47
Jetzt:
Total combinational functions: 35
Dedicated logic registers: 31
Gleiches werde ich nun auch mit dem nächsten Modul, eval_flankentimer,
versuchen.
Flyget schrieb:> Gibts hier noch Tipps was man in so einem Fall standardmäßig für Angaben> im sdc-file macht?
Wenn Du sicher weißt, das das Timing eines bestimmten Signals in jedem
Fall unkritisch (bzw. sinnlos, weil das Signal ein asynchrones ist) ist,
kannst Du sowohl der Synthese als auch der Timing-Analyse das Leben
leichter machen, indem Du dafür einen false_path definierst:
1
set_false_path-toLEDS[*]
Das Signal wird dann bzgl. Timing (sowohl vom Fitter als auch bei der
Timing-Analyse) ignoriert.
Fabian N. schrieb:> Nur nochmal zum Verständnis bezüglich Registern. Wenn ich folgendes> schreibe:
Genau.. wobei Zwischenregister jetzt nicht ein standardisierter Begriff
ist.
Die Idee ist einfach folgende:
---- Register --- Loooooooooooooooooooooogik --- Register ----
durch
---- Register --- Logik --- Register --- Logik --- Register ----
zu ersetzen.
Die Laufzeit durch Logik ist kürzer als durch Loooooooogik und damit
wird das Setup-Zeit-Problem entspannt.
Allerdings steht das Ergebnis um einen Takt verzögert zur Verfügung.
Man kann auch, wie Markus beschrieben hat, den Pfad ganz aus der der
Betrachtung nehmen oder, über ein multicycle Constraint eine längere
Zeit "erlauben".
Der Vorteil mit dem Zwischenregister ist allerdings, dass das
Constraining einfacher ist. Man muss nicht selektiv einzelne Pfade
(Ausnahmen) betrachten.
Zu deiner Frage wegen den unconstrained Paths:
Das sind die Pfade zwischen den Ausgangs- bzw Eingangsregistern zu den
Pins des FPGA.
Wenn dir egal ist, wie lange das Signal dafür benötigt (Weil du z.B.
außerhalb des FPGA nicht synchron zum FPGA-Takt arbeitest), dann kannst
du die z.B. als false_path constrainen.
@ Markus, vielen Dank, das werde ich probieren. Jetzt im Moment is es
auch nicht so wichtig, bin nur immer ein Fan davon, wenn die Warnungen
weg sind.
Jetzt habe ich aber schon wieder die nächste Sache... Wenn ich
Kompiliere und den RTL-Viewer anschaue, sehe ich alle meine Module. Wenn
ich den Post-Mapping-Viewer aufmache fehlen mir die Module
eval_quadratur_output und quadratur_output. Scheinbar hält er die für
überflüssig? Ne Idee wie man dieses Verhalten beseitigt?
Fabian N. schrieb:> bin nur immer ein Fan davon, wenn die Warnungen> weg sind.
Na ja..
Warnungen sind dazu da, dich vor etwas zu warnen.
Man kann sie ignorieren und darf sich dann aber nicht wundern, wenn das
FPGA nicht so tut, wie in der Simulation.
Wenn du ein Setup Zeit Problem reportet bekommst, dann machst du mit
einem false_path constraint auf diesen Pfad nur folgendes:
Du sagst dem Tool: "Scheiss auf das Signal.. es interessiert mich
nicht".
Die Timingverletzung bleibt aber natürlich bestehen. Sie wird nur
ignoriert.
Sowas kann man also nur dann machen, wenn man sich 100% sicher ist, dass
diese Timing-Verletzung nicht problematisch für das Systemverhalten
wird.
Man sich also anderweitig abgefangen hat.
Und das sehe ich in deinem Fall nicht als gegeben.
So war das jetzt nicht gemeint;-) Ich meinte eher möglichst viele
Warnungen/Hinweise befolgen/lösen, sodass Sie deswegen nicht mehr
auftauchen.
In dem aktuellen Fall könnte ich ja aber für die LED's das auf jedenfall
mal machen, da mich das ja nicht kümmert ob die ein paar ns später oder
früher leuchtet, oder?
Und auch spätern wenn ich z.B. das Quadratursignal mit einem nicht
synchronisierten DSP erfasse, sollte es ja kein Problem ergeben den
Quadraturausgang als set_false_path zu setzen, oder sehe ich das falsch?
EDIT: vergesst meine Frage nach den nicht mehr vorhandenen Modulen...
ich hatte den Reset manuell gesetzt und deswegen waren die Module ohne
Funktion...
Fabian N. schrieb:> Ne Idee wie man dieses Verhalten beseitigt?
Liegt der Ausgang des Moduls auf einem Pin?
Fabian N. schrieb:> In dem aktuellen Fall könnte ich ja aber für die LED's das auf jedenfall> mal machen ....
Ja genau.
man muss sich halt im Klaren sein, was man tut
@Schlumpf
Ja, die Ausgänge liegen auf Pins. Ich hatte aber gerade meinen letzten
Beitrag editiert, da ich festgestellt hatte, das ich den Reset der
beiden Quadraturmodule gesetzt hatte und diese keine Funktion hatte.
Daher hat Quartus die vermutlich gleich ganz wegoptimiert.
Momentan (!) kompiliert er alle Module durch ohne Timingfehler Juhuu
Ich werde jetzt mal weitermachen, funktionalität Prüfen und wenn wieder
was auftritt hier nochmal fragen.
Vielen lieben Dank auf jedenfall schonmal an alle die sich hier so zügig
und hilfsbereit geäußert haben!
Jetzt hab ich es auch gesehen..
Alles klar :-)
Fabian N. schrieb:> Momentan (!) kompiliert er alle Module durch ohne Timingfehler Juhuu
Und wie viel "Reserve" hast du beim schlechtesten Pfad? Also positiven
Slack?
Fabian N. schrieb:> Was wäre denn so ein Zielwert?
Schön wäre natürlich ein wenig mehr, aber das passt so schon.
Kann auch gut sein, dass ohne Probleme noch mehr möglich wäre, aber der
Router keine Notwendigkeit sieht, das besser zu machen, weil es ja
reicht.
Schlumpf schrieb:> Kann auch gut sein, dass ohne Probleme noch mehr möglich wäre, aber der> Router keine Notwendigkeit sieht, das besser zu machen, weil es ja> reicht.
... das hängt von den Fitter-Einstellungen ("Fitter Effort") ab.
Da gibt es "Auto Fit" (hört auf, sobald die timing requirements bzw. die
"Auto Fit Effort Desired Slack Margin" - unter "Advanced Fitter
Settings") erfüllt sind, "Standard Fit" (optimierte timing margin) und
"Fast Fit" ("hingeschlampert").
Schlumpf schrieb:> Warnungen sind dazu da, dich vor etwas zu warnen.> Man kann sie ignorieren und darf sich dann aber nicht wundern,> wenn das FPGA nicht so tut, wie in der Simulation.
Viel nerviger ist, dass man viele Warnungen nicht sinnvoll (d.h. ohne
massiven Aufwand) beheben kann. Zum Beispiel die Warnungen, dass
bestimmte Eingangssignale konstant sind oder dass bestimmte
Ausgangssignale nicht verwendet werden. Bei einer größeren
Array-Struktur sind das gerne mal einige hundert Warnungen... die alle
nur den Rand betreffen.
Dafür würde ich im Code gerne ein allgemeines "ja ich weiß" ranschreiben
können, um das Rauschen im Log zu reduzieren. In der GUI kann man das
einstellen, aber die nutze ich nicht.