Hallo zusammen,
ich habe eine Frage zur Komplexität von Prozessen. Damit meine ich wie
viel Funktionalität in einem Prozess sein sollte.
Ein kleines, sehr vereinfachtes Beispiel. Ich habe zwei Prozesse. Der
erste Prozess ist ein einfacher Zähler. Der zweite Prozess generiert ein
Valid Signal, wenn der Zählerwert Null ist.
1
counter_process:process(clk50mhz,reset_n)
2
begin
3
ifreset_n='0'then
4
r_counter<=(others=>'0');
5
elsifrising_edge(clk50mhz)then
6
r_counter<=r_counter+1;
7
endif;
8
endprocess;
9
10
valid_process:process(clk50mhz,reset_n)
11
begin
12
ifreset_n='0'then
13
r_valid<='0';
14
elsifrising_edge(clk50mhz)then
15
ifr_counter=0then
16
r_valid<='1';
17
else
18
r_valid<='0';
19
endif;
20
endif;
21
endprocess;
Man kann das Beispiel in zwei Prozessen schreiben oder auch in einem.
Meine Frage ist, gibt es ein Best Practice für die Komplexität eines
Prozesses? Also schreibt man alles was passt in einem Prozess oder
bricht man die Funktion auf kleine Prozesse runter? Wie handhabt ihr
das?
Hat die Entscheidung sogar Auswirkungen auf den Fitter? Könnte er im
Worst Case den Zähler links unten und das Valid Signal rechts oben
platzieren?
Ich hoffe, ihr versteht worauf ich hinaus möchte.
Liebe Grüße
Jan
Jan K. schrieb:> Meine Frage ist, gibt es ein Best Practice für die Komplexität eines> Prozesses? Also schreibt man alles was passt in einem Prozess oder> bricht man die Funktion auf kleine Prozesse runter? Wie handhabt ihr> das?
Da werden dich wieder zig Fachleute mit unterschiedlichen Meinungen
zudroehnen - also, ein Klassiker: Bild' Dir deine eigene Meinung.
Stichworte:
- Gaisler-Ansatz bei FSMs (state of the art)
- Simulator-Aspekte, je nach Simulator kann es einen Unterschied
(Geschwindigkeit) machen, wie man die Prozesse gestaltet
- Logik: Macht es Sinn, eine Verzoegerung (siehe r_counter gegen
r_valid) explizit oder implizit 'hinzuschreiben'
Deswegen nur mein Credo: Lesbarkeit. Bei einer Pipeline wuerde ich die
einzelnen Prozess-Stufen ('stages') kennzeichnen. Beim Debuggen von
langen schlecht lesbaren process'es verbraet man am meisten Zeit.
Jan K. schrieb:> Hat die Entscheidung sogar Auswirkungen auf den Fitter? Könnte er im> Worst Case den Zähler links unten und das Valid Signal rechts oben> platzieren?
Nee, ein solch unzulaengliches Synthesetool hab' ich noch nicht gesehen
:-)
Also wenn reset_n = '0' dann wird auch der counter auf 0 gesetzt.
Und im zweiten Prozess wird r_valid <= '0'; gesetzt wenn reset_n = '0'
ist, aber if r_counter = 0 then r_valid <= '1'; ? Aber das ist doch auch
dann der Fall wenn reset_n = '0'.
Verstehe nicht, was du da machen möchtest.
Für mich sieht das so aus, als möchtest du nach einem Reset eine Zeit
warten und dann erst dein valid setzen.
Ich mache das so:
Martin S. schrieb:> Stichworte:> - Gaisler-Ansatz bei FSMs (state of the art)
Echt jetzt? Das mit dem Hin- und Herkopieren auf lokale Variablen? Damit
man VHDL wie in Software programmieren kann?
> - Logik: Macht es Sinn, eine Verzoegerung (siehe r_counter gegen> r_valid) explizit oder implizit 'hinzuschreiben'
Niemals "Pseudoverzögerungen" in synthetisierbaren Code! Das kann z.B.
in einer kombinatorischen Schleife urige Effekte geben, wo der Simulator
nie drauf kommt...
> Jan K. schrieb:>> Hat die Entscheidung sogar Auswirkungen auf den Fitter? Könnte er im>> Worst Case den Zähler links unten und das Valid Signal rechts oben>> platzieren?> Nee, ein solch unzulaengliches Synthesetool hab' ich noch nicht gesehen
Wenn man dem Placer (einen Fitter braucht es für CPLDs) keine Vorgaben
in den Constraints macht, dann fängt er einfach irgendwo an und packt
das Zeug vom Synthesizer der Reihe nach irgendwohin. Und wenn der
Synthesizer auf dumme Ideen kommt, dann kann das schon passieren.
Und dass der Synthesizer auf dumme Ideen kommen kann, kann man sich
schon daraus ableiten, was er aus gleichen Beschreibungen macht, die nur
anders formatiert sind. Siehe das Beispiel dort zum Schluss:
http://www.lothar-miller.de/s9y/archives/52-Kompakte-Flankenerkennung.html> ein Klassiker: Bild' Dir deine eigene Meinung.
So ist es. Sieh dir Code von anderen an. Übernimm den Stil, den du am
besten lesen kannst.
Vielen Dank für Eure Antworten.
Gustl B. schrieb:> Also wenn reset_n = '0' dann wird auch der counter auf 0 gesetzt.>> Und im zweiten Prozess wird r_valid <= '0'; gesetzt wenn reset_n = '0'> ist, aber if r_counter = 0 then r_valid <= '1'; ? Aber das ist doch auch> dann der Fall wenn reset_n = '0'.>> Verstehe nicht, was du da machen möchtest.
Das war ein einfachen Beispiel welches ich mir aus den Fingern gesogen
habe. Dass es nicht praktisch sinnvoll ist, weiß ich auch. Mir ging es
nur darum meine Frage zu verdeutlichen.
Lothar M. schrieb:> Martin S. schrieb:>> Stichworte:>> - Gaisler-Ansatz bei FSMs (state of the art)> Echt jetzt? Das mit dem Hin- und Herkopieren auf lokale Variablen? Damit> man VHDL wie in Software programmieren kann?
Wir machen hier alles im Gaisler Stil aber ohne dieses
Variablen-gedöhns. Das war mir beim ersten lesen seines Papers schon
irgendwie suspekt.
Man kann so sehr aufgeräumte Beschreibungen machen (hier gibt es
natürlich auch Gebenbeispiele...). Richtig angewendet, werden auch nur
die FFs erzeugt die gewünscht sind, die anderen werden zu
Latches/Kombinatorische Schlaufen, die dann Reported werden (Auch hier
gibt es leider Gegenbeispiele wo Latches ausgeliefert wurden).
Christoph Z. schrieb:> Wir machen hier alles im Gaisler Stil aber ohne dieses Variablen-gedöhns.
Gerade das ist doch aber das Neue daran: dass Variabeln Wertänderungen
sofort übernehmen und deshalb keine Probleme mit Latency auftreten
können.
Denn dass man Signale über Records in Module einschleust, damit die
leitchter erweiterbar/änderbar sind, das gibts ja schon lange.
Lothar M. schrieb:> Denn dass man Signale über Records in Module einschleust, damit die> leitchter erweiterbar/änderbar sind, das gibts ja schon lange.
Aber ausser das Paper von Jiri Gaissler kenne ich keine Quelle, die das
mit Beispielen dokumentiert. Alle Lehrbücher, die ich kenne, hören
vorher auf und die Codes die bis dahin gesehen hatte, verwendeten das
nicht (bzw. Stile die ich nie selber anwenden will).
Für mich war damals Jiris Paper ein Augenöffner, wie man VHDL eigentlich
nutzen kann. Bei den Programmierern gibt es da ja diverse Bücher über
Design Patterns, Advanced concepts in... etc. So etwas vermisse ich für
VHDL.
Bleibt mir halt das uC Forum :-)
Lothar M. schrieb:> Echt jetzt? Das mit dem Hin- und Herkopieren auf lokale Variablen? Damit> man VHDL wie in Software programmieren kann?
Macht in komplexen Designs (CPUs) durchaus Sinn und die Sache einiges.
lesbarer. Bloss nicht wieder das alte Fass aufmachen, das wurde hier
schon zigfach durchgekaut.
Grade der Gaisler-Ansatz kann auch die Ausfuehrungszeit der Simulation
optimieren.
Lothar M. schrieb:> Niemals "Pseudoverzögerungen" in synthetisierbaren Code! Das kann z.B.> in einer kombinatorischen Schleife urige Effekte geben, wo der Simulator> nie drauf kommt...
Ich meine einen clock delay..
Das gehoert dann auch wieder ins Thema Variable vs. Signal.
Haeufiger Denkfehler: Vergleich gegen ein Signal, was erst im naechsten
Takt valide ist. Sehr muehsam, das durch einen schlecht strukturierten
Code zu tracen (ohne Simulator).
Lothar M. schrieb:> Wenn man dem Placer (einen Fitter braucht es für CPLDs) keine Vorgaben> in den Constraints macht, dann fängt er einfach irgendwo an und packt> das Zeug vom Synthesizer der Reihe nach irgendwohin. Und wenn der> Synthesizer auf dumme Ideen kommt, dann kann das schon passieren.>> Und dass der Synthesizer auf dumme Ideen kommen kann, kann man sich> schon daraus ableiten, was er aus gleichen Beschreibungen macht, die nur> anders formatiert sind. Siehe das Beispiel dort zum Schluss:
Wie gesagt, solche Synthesizer habe ich lange nicht mehr gesehen, da
wird optimiert, dass kein Mensch mehr durchblickt.
Und der Technology-Mapper packt typischerweise das Zeug so, dass es PNR
nicht unnoetig aufm Quadranten verteilt. Bei so einem simplen
process-Beispiel sowieso nicht.
Jan K. schrieb:> Meine Frage ist, gibt es ein Best Practice für die Komplexität eines> Prozesses? Also schreibt man alles was passt in einem Prozess oder> bricht man die Funktion auf kleine Prozesse runter? Wie handhabt ihr> das?
Es gibt 'Best practice' für Prozesse, die drehen sich aber nicht um so
ein Pillepalle wie max. Zeilanzahl für process body. Die Grundregel,
schreibe alles in einem Prozess was zu der Hardware-Komponente gehört.
Also bei einem run-once-counter alles in einem, bei einer FSM, shiftreg,
speicherblock,...
Dann sollte man sich auf wenige sensitivity-listen beschränken, bspw.
nur getaktetet Prozesse mit synchronen reset, keine kombinatorischen
Prozesse.
Man kann auch kombinatorische Prozesse verwenden, das ist IMHO aber
fehlerträchtig.
Die sensitivity-listen müssen vollständig sein, dürfen aber keine
ungenutzten Signal enthalten.
Für FSM bevorzuge ich die Ein-prozess Variante, wobei das
Ausgangsnetzwerk auch schon mal ausserhalb dieses prozesses stehen kann
(falls das signal ohne FF benötigt wird).
Bei Counter in Prozessen habe ich noch nicht den goldenen Mittelweg
gefunden, also bspw. wait-cycle-counter im extra prozess oder im FSM
prozess; ich tendiere diesen counter in den selben Prozess zu setzen.
Und nicht vergessen, wenn etwas zu lang oder zu unübersichtlich zu weren
droht, kann man immer comments einschieben um zu erklären an welcher
Stelle im Hardwaregestrüpp man sich gerade befindet, und was hier
gemacht werden soll.