Hallo an das Forum,
ich arbeite mich gerade in das Thema FPGA und VHDL ein und bin jetzt
soweit um FSM zu konstruieren. Dazu habe ich einen Grundsatzfrage.
Worin unterscheiden sich die verschiedenen Prozess Modelle:
Ein-Prozess-Modell
Zwei-Prozess-Modell
Drei-Prozess-Modell
Gruß Andre
Bis auf den Fall, wo man die asynchrone Funktionalität eines
Mealy-Automaten braucht, ist die Wahl der Beschreibungsart etwas, wo
sich beliebig viele Flamewars führen lassen...
Im Endeffekt gehts nur darum, wie man die theoretische
Automatenbeschreibung mit den beiden Lookuptabellen
(Eingang,Zustand)->(Zustand) und (Eingang, Zustand)->(Ausgang) und der
eigentlichen Zustandsspeicherung tau (aka Register/FF) verteilt oder
zusammenfasst.
Da kann man dann zB. beliebig lange drüber streiten, ob es gut ist,
Zustandsübergänge und Ausgangszuweisungen in einem Prozess
zusammenzufassen, weil man da evtl. ein paar Fälle in den Verzweigungen
übersieht. Oder ob das asynchrone Ausdekodieren der Ausgänge
Timingprobleme machen kann oder nicht. Oder dass alles ausser der
Einprozess-Variante eine Sch...-Schreibarbeit ist, die noch mehr Fehler
provoziert. etc. pp.
Jedes Lehrbuch und jeder Codingstyle hat da andere Ansichten.
Ich nehm meistens die Einprozess-Variante ;)
Ein-Prozess-Modell
Alles ist in einem Prozess beschrieben:
Der aktuelle Zustand und der Folgezustand. Alle Signale sind speichernd
(kein Problem weil es im FPGA so viele Speicher-FFs gibt), deshalb
lassen sich Zähler einfach innerhalb der FSM codieren. Am Anfang holpert
es mit der Denkweise manchmal und man hat einen Takt Latency an der
Backe.
Zwei-Prozess-Modell
Es gibt einen getakteten Speicher-Prozess und einen Prozess mit der
Weiterschaltlogik. Für Anfänger eine gute Möglichkeit, die
kombinatorische Schleife kennenzulernen:
http://www.lothar-miller.de/s9y/categories/36-Kombinatorische-Schleife
Drei-Prozess-Modell
Siehe vorher, nur werden jetzt auch noch die Ausgangssignale irgendwie
kombinatorisch (evtl. auch noch mit den Eingängen verknüpft) erzeugt.
Vor der Einarbeitung sollte das Erlernen stehen, und da kann ich bei
VHDL das Buch "VHDL-Synthese" von Reichardt und Schwarz empfehlen. Dort
ist auch das mit den drei Modellen erklärt.
Ich meine das mal als Empfehlung von Xilinx gesehen zu haben. Ein Grund
war glaube ich auch, dass beim Coding mit 2 oder 3 Prozessen die
Ausgangssignale nicht zwangsweise registriert werden. Hier wird unter
"Basic HDL Coding Techniques - Part 2" auch Multi-Prozess-Coding
empfohlen, weil das angeblich Ressource-Sharing verhindert (Unterpunkt
State-Machine-Design):
http://www.xilinx.com/training/free-video-courses.htm#FPGA
Auch im Buch "RTL hardware Design Using VHDL" von Pong Chu wird das
Multi-Segment-Coding propagiert.
Lothar Miller schrieb:> Wer sagt das? Quellennachweis? Erfahrungen?
Der einzig funktionelle Unterschied der Methoden ist das asynchrone
Ausdekodieren der Ausgänge, alles andere führt nach dem Flachkopfen auf
dasselbe Ergebnis. Bei den vielen FFs in einem FPGA sehe ich auch
erstmal keinen Sinn darin, FFs sparen zu wollen.
Und mit dem bidirektionalen Register-Balancing vom xst (und sicherlich
auch anderen Synthesetools) ist es eh ziemlich egal, wo das/die FF
schliesslich steht/stehen, es wird eh dupliziert/reduziert an die
optimale Timingposition geschoben... Sicher, Sonderfälle wird man immer
finden können, wo irgendwas schlechter geht, aber so im allgemeinen ist
mir noch nichts negatives untergekommen.
> ... und man hat einen Takt Latency an der Backe.
Wieso das?
Ich setze hier die Ausgänge direkt mit dem neuen State:
1
whens1=>if(A='1')then
2
B<='1';
3
C<='0';
4
state<=s2;
5
endif;
Eine direkte Zuweisung der Ausgänge innerhalb der States gibt es nur im
Initial-State.
Ansonsten werden die nur beim Zustandswechsel zugewiesen und dann im FF
gespeichert.
Grüße,
Thomas
> Wieso das?
Weil du quasi immer aus dem aktuellen Signal mit einem Takt Verzögerung
das Folgesignal generierst. Bei deinem Beispiel passiert da nichts.
Interessant wird es, wenn du 2 synchrone Prozesse mit jeweils 1 FSM
hast, von denen der eine Prozess auf den anderen wartet. Z.B. eine
Haupt-FSM, die eine RS232-FSM antriggert. Dann erreicht die RS232-FSM
das Ende, signalisiert dies, und die Haupt-FSM reagiert mit einem Takt
Verzögerung.
Ich werde mir mal die nächsten Tage ein Beispiel zum Thema aus den
Fingern saucgen... ;-)
Das wäre echt nett, wirklich verstanden habe ich das jetzt noch nicht.
Ich habe hier ein Design, bei dem es sehr auf die Durchlaufzeit ankommt,
alle paar ns sind da schon ein echter Gewinn.
Anfangs hatte ich die Ausgänge in jedem State zugewiesen, bevor es in
die Weiterschaltlogik ging:
1
whens1=>B<='0';
2
C<='1';
3
if(A='1')then
4
state<=s2;
5
endif;
Durch die oben beschriebene Modifikation habe ich einen Takt gewonnen,
was bei 155Mhz immerhin schon gut 6ns ausmacht.
Meine Kollegen aus der Hardwareentwicklung sagen zwar das sei Scheiße,
weil angeblich jeder Ausgang bei jedem Prozessdurchlauf aktiv gesetzt
werden soll, aber funktionieren tuts trotzdem.
Gott sei dank bin ich in einer anderen Abteilung und muss mich nicht an
deren Guidelines halten...
> Meine Kollegen aus der Hardwareentwicklung sagen zwar das sei Scheiße,> weil angeblich jeder Ausgang bei jedem Prozessdurchlauf aktiv gesetzt> werden soll, aber funktionieren tuts trotzdem.
Ist der Prozess getaktet oder nicht? Falls nicht (tippe ich mal), ist es
in der Tat Müll, falls es nicht am Anfang eine Default-Zuweisung auf
alle Ausgänge gibt. Ohne baust du nette Latches, die ein FPGA gar nicht
mag und die auch nicht unbedingt zuverlässig funktionieren müssen. Und
das hat nichts mit Geschmacks-Guidelines zu tun sondern mit "never
ever".
Und so nebenbei: Wenn du einen ganzen Takt gewinnst, hast du im Design
des Automaten vorher was falsch gemacht und evtl. neue Probleme
geschaffen bzw. nicht erkannt. Die Unterschiede Mealy vs. Moore gibt es
nicht umsonst, auch im Sinne von "geschenkt".
> Ist der Prozess getaktet oder nicht? Falls nicht (tippe ich mal)
Natürlich ist der Prozess getaktet, es handelt sich um eine
Ein-Prozess-FSM:
1
processbegin
2
waituntilrising_edge(clk);
3
casestateis
4
...
> Und so nebenbei: Wenn du einen ganzen Takt gewinnst, hast du im Design> des Automaten vorher was falsch gemacht und evtl. neue Probleme> geschaffen bzw. nicht erkannt
Das glaube ich nicht.
Es lief vorher problemlos, und jetzt auch.
Nur halt mit einem Takt schnellerer Durchlaufzeit.
Also nicht einfach irgendwie, sondern genau so wie ich es geplant habe.
Aber oben ist ja die Modifikation für den Taktgewinn komplett erklärt.
Wenn du da begründete Zweifel am Design hast würde mich das sehr
interessieren.
Unsere Hardwareentwicklung kann es nämlich leider nicht begründen.
Sie sagen halt einfach, das geht so nicht, weil sie immer gelernt haben,
dass in jedem State erst mal alle Ausgänge zugewiesen werden müssen.
Aber es gibt da auch noch andere Konflikte, die ich mit denen Austrage,
so funktioniert das mit dem "wait until rising_edge(clk);" nämlich
angeblich auch nicht.
Außerdem muss ja jeder Prozess einen Reset haben weil direkte
Signalzuweisungen bei der Initialisierung (signal state : state_type :=
s0;) geht natürlich gar nicht.
Und dann habe ich auch kein "when others" in der FSM, weil alle
definierten States bereits abgehandelt werden. => Ganz böse!!
@ Thomas
>>> Ich werde mir mal die nächsten Tage ein Beispiel zum Thema aus den>>> Fingern saugen... ;-)>> Das wäre echt nett, wirklich verstanden habe ich das jetzt noch nicht.
Da war ich dann schon am Grübeln, aber DU selber hast das beste Beispiel
abgeliefert. Nur hast du es anders umschrieben:
> Durch die oben beschriebene Modifikation habe ich einen Takt gewonnen,> was bei 155Mhz immerhin schon gut 6ns ausmacht.
Das heißt eigentlich nur: wenn das Design jetzt immer noch funktioniert,
dann hattest du vorher irgendwo Latency mit drin...
Ein Takt Latency auf den Signalen B und C:
1
whens1=>if(A='1')then
2
B<='1';
3
C<='0';
4
state<=s2;
5
endif;
Nach Überdenken des Prozesses:
1
whens1=>B<='0';
2
C<='1';
3
if(A='1')then
4
state<=s2;
5
endif;
Und das passiert dir nur, weil der gesamte Prozess getaktet ist. Denn
wenn aus irgendeinem Grund sofort nach dem letzten Takt A='1' ist, dann
werden erst nach dam folgenden Takt B und C gesetzt.
Wenn du diese Codeausschnitte in einem kombinatorischen Prozess hättest,
kämen B und C in beiden Fällen praktisch gleichzeitig, wenn A='1'
wäre...
Zeichne dir das mal auf ein Blatt Papier, dann wird es klar.
BTW: die Abhilfe wäre, schon in der if-Abfrage, in der auf Zustand s1
weitergeschaltet wird, diese Abfrage nach A='1' mit einzubauen.
Wenn man den 1 Takt Latency umgehen will und die 3 Prozess Methode
verwendet, kann man auch eine Look-Ahead-Moore FSM bauen. Hier wird zwar
die kombinatorische Logik etwas größer, weil das Signal aus der
kominatorischen Next-State-Logik kommt und nicht mehr aus dem
State-Register, aber man spart 1 Takt Latenz. Das einzige was man ggü.
der Standard Xilinx Moore FSM Template ändert ist, dass die Output-Logik
auf
1
next_state
statt auf
1
state
sensitiv ist - unten habe ich das Xilinx Template modifiziert,
natürlich ohne Gewähr ;)
1
SYNC_PROC:process(<clock>)
2
begin
3
if(<clock>'eventand<clock>='1')then
4
if(<reset>='1')then
5
state<=st1_<name_state>;
6
<output><='0';
7
else
8
state<=next_state;
9
<output><=<output>_i;
10
-- assign other outputs to internal signals
11
endif;
12
endif;
13
endprocess;
14
15
--LOOK-AHEAD MOORE State-Machine - Outputs based on NEXT_STATE only
16
LOOK_AHEAD_OUTPUT_DECODE:process(NEXT_STATE)
17
begin
18
--insert statements to decode internal output signals
Danke, Lothar.
Jetzt habe ich verstanden was du meinst.
Klar, durch den getakteten Prozess hatte ich vorher zwei Zyklen
Verzögerung und durch die Modifikation einen gewonnen.
Wenn ich jetzt die Eingänge in einem weiteren Prozess asynchron mit den
Zuständen verknüpfen würde, dann würde ich auch noch den letzten Zyklus
einsparen.
Ob es mir das aber wert ist, dadurch wird der Code ganz schön
unübersichtlich...
Aber noch eine Frage zu Einsynchronisieren.
Wenn ich das richtig verstehe, dann ist das 1. FF dafür zuständig, dass
ein asynchrones Signal nicht gleichzeitig auf mehrere FFs geroutet wird
und dort durch unterschiedliche Signallaufzeiten unterschiedliche Pegel
verursacht.
Falls das asynchrone Signal das erste FF durch Timingverletzungen in
einen metastabilen Zustand versetzt hat, wird dieser durch das zweite FF
abgefangen.
Wenn ich allerdings mit 155MHz takte, dann liegen zwischen zwei Takten
gut 6ns. In dieser Zeit sollte doch heutzutage jedes FF wieder einen
stabilen Zustand erreicht haben? Kann ich mir in diesem Fall das zweite
FF sparen?
Thomas schrieb:> Wenn ich das richtig verstehe, dann ist das 1. FF dafür zuständig, dass> ein asynchrones Signal nicht gleichzeitig auf mehrere FFs geroutet wird> und dort durch unterschiedliche Signallaufzeiten unterschiedliche Pegel> verursacht.
Richtig. Das ist der Hauptgrund fürs Eintakten. Die daraus
resultierenden Effekte werden aber oft der Metastabilität in die Schuhe
geschoben...
Metastabilität an sich sollte eigentlich entsprechend den aktuellen
Aussagen von FPGA Herstellern erst ab 500MHz spürbare Auswirkungen haben
können.
> Kann ich mir in diesem Fall das zweite FF sparen?Wahrscheinlich schon...
Metastabilität und die ganzen Mechanismen hinter der Metastabilität sind
eine Frage von Wahrscheinlichkeiten. Wenn du ein 2. FF dahinterschaltest
kannst du irgenwelche Störeffekte durch Metastabilität während deiner
Lebenszeit mit ziemlicher Sicherheit ausschliessen... ;-)
Prima, das sind gute Nachrichten!
Mit diesen beiden Optimierungen kann ich die psychologisch wichtige
100ns Verzögerung des Gesamtsystems (inkl. externe Bauteile) knacken,
und komme sogar auf knapp unter 90ns.
Dafür nehme ich auch die unübersichtliche Implementierung der FSM Kauf.
Hallo Leute!
Ich habe die Optimierungen jetzt mal implementiert.
Funktionierte schon in der Simulation einwandfrei.
Aber der wirkliche Hammer zeigte sich erst nach der Synthese.
Nicht nur, dass ich zwei Takte spare, der kann jetzt auch noch deutlich
schneller takten.
Zunächst hatte ich ein eigenes 2-Prozess FSM Konstrukt aus synchroner
Weiterschaltlogik + asynchroner Ausgangsschaltung.
Das hat schon mal 12% gebracht.
Dann habe ich nochmal nur für Spaß Anguels drei-Prozess Methode
implementiert...
100% schneller! Das sind jetzt 380MHz!
Wahnsinn, mir ist schon ganz schwindelig vom Geschwindigkeitsrausch.
So hat der FPGA quasi keinen Einfluss mehr auch die Gesamtdurchlaufzeit
des Systems.
Aber eigentlich ist es klar, dass er schneller Takten kann, wenn man die
ganze Logik aus den getakteten Prozessen raus schmeißt.
Nur wirklich sauber finde ich das jetzt nicht mehr.
Jedenfalls bin ich gerade (um diese Uhrzeit) nicht mehr in der Lage
nachzuvollziehen, was da alles passieren kann.
Nachtrag:
Wenn ich in der kombinatorischen Weiterschaltlogik alle Bedingungen
komplett ausformuliere wie man es in der VHDL Schulung lernt, dann
schafft er nur noch 230MHz:
1
whenS1=>if(A='1')then
2
next_state<=S2;
3
else
4
next_state<=S1;
5
endif;
Muss ich den Else-Zweig wirklich haben? Die Simulation zeigt da
jedenfalls keinen Unterschied.
Eigentlich sollte doch auch die Synthese identische Ergebnisse liefern,
wenn der Optimierer perfekt währe, oder?
Thomas schrieb:>> Nachtrag:> Wenn ich in der kombinatorischen Weiterschaltlogik alle Bedingungen> komplett ausformuliere wie man es in der VHDL Schulung lernt, dann> schafft er nur noch 230MHz:>
1
>whenS1=>if(A='1')then
2
>next_state<=S2;
3
>else
4
>next_state<=S1;
5
>endif;
6
>
> Muss ich den Else-Zweig wirklich haben? Die Simulation zeigt da> jedenfalls keinen Unterschied.
Wenn du es nicht komplett auskodierst hast du halt ein Latch.
> 100% schneller! Das sind jetzt 380MHz!
Das würde mir sehr zu Denken geben... :-/
> Aber eigentlich ist es klar, dass er schneller Takten kann, wenn man die> ganze Logik aus den getakteten Prozessen raus schmeißt.> Nur wirklich sauber finde ich das jetzt nicht mehr.
Ja klar, denn du schaust ja "nur" auf die Taktfrequenz. Für ein reales
FPGA-Design hast du aber auch Verzögerungen in den IO-Puffern. Die
tauchen in der Berechnung der maximalen Taktfrequenz nicht auf. Und
natürlich genausowenig in der Vehaltenssimulation...
> Muss ich den Else-Zweig wirklich haben?
Da wäre jetzt der gesamte Code mal interessant...
Thomas schrieb:> Dann habe ich nochmal nur für Spaß Anguels drei-Prozess Methode> implementiert...> 100% schneller! Das sind jetzt 380MHz!> Wahnsinn, mir ist schon ganz schwindelig vom Geschwindigkeitsrausch.> So hat der FPGA quasi keinen Einfluss mehr auch die Gesamtdurchlaufzeit> des Systems.>> Aber eigentlich ist es klar, dass er schneller Takten kann, wenn man die> ganze Logik aus den getakteten Prozessen raus schmeißt.> Nur wirklich sauber finde ich das jetzt nicht mehr.> Jedenfalls bin ich gerade (um diese Uhrzeit) nicht mehr in der Lage> nachzuvollziehen, was da alles passieren kann.
Ich habe mir die Methode nicht selbst ausgedacht, sondern in Pong Chus
RTL HW Design gesehen. Ich zitiere ihn mal:
"A more systematic approach to Moore output buffering is to use a
look-ahead output circuit. The basic idea is to buffer the next output
value to cancel the one-clock delay introduced by the output buffer. In
most systems, we don't know a signal's next or future value. However,
in an FSM, the next value of the state register is generated by
next-state logic and is always available."
"To cancel the effect of the delay, we can feed the output buffer with
the next output value. After being delayed by one clock cycle, the next
output value becomes the current output value, which is the desired
output. Obtaining the next output is very straightforward. Recall that
the current output is a function of the current state, which is the
output of the state register. The next output should be a function of
the next state, which is the output of next-state logic. To obtain the
next output, we need
only disconnect the input of the output logic from the state_reg signal
and reconnect it to the state_next signal."
"The look-ahead buffer is a very effective scheme for buffering Moore
output. It provides a glitch-free output signal and reduces Tco to Tcq.
Furthermore, this scheme has no effect on the next-state logic or state
assignment and needs only minimal modification over the original code."
IMHO is der einzige Nachteil dieser Methode, dass der kritische Pfad zu
lang wird, wenn die Next-State Logik kompliziert ist, was aber bei
kleinen FSMs nicht der Fall ist. Das beste an der Methode ist aber, dass
man den 1 Takt Latenz umgeht.
Grüße,
Anguel
D. I. schrieb:>> Muss ich den Else-Zweig wirklich haben? Die Simulation zeigt da>> jedenfalls keinen Unterschied.>> Wenn du es nicht komplett auskodierst hast du halt ein Latch.
Wenn das ganze innerhalb eines getakteten Prozesses passiert, entsteht
IMHO kein Latch, für alle nicht zugewiesen next_state müsste man sich
eigentlich next_state <= next_state denken.
Anguel S. schrieb:> Wenn das ganze innerhalb eines getakteten Prozesses passiert, entsteht> IMHO kein Latch
Es passiert aber nicht im getakteten Teil! Zitat:
Thomas schrieb:> Wenn ich in der kombinatorischen Weiterschaltlogik alle Bedingungen> komplett ausformuliere ...
Es handelt sich also offenbar um die 2-Prozess-Schreibweise. Und wenn
dort in der Wieterschlatlogik nicht jeder Zustandspfad abgeschlossen
ist, dann gibt es ein Latch. Verhindert wird das im oberen Beispiel
(Beitrag "Re: Automaten(FSM) und die verschiedenen Prozess Modelle") durch die
Defaultzuweisung:
1
next_state<=state;--default is to stay in current state
> müsste man sich eigentlich next_state <= next_state denken.
Nur kann das der Synthesizer nicht wissen (und denken tut der schon
überhaupt nicht) und ergo macht er daraus ein Latch.
BTW: next_state <= next_state
Das ist die explizite Beschreibung für ein Latch, wenn kein Takt
beteiligt ist.
D. I. schrieb:>> when S1 => if (A = '1') then>> next_state <= S2;>> else>> next_state <= S1;>> end if;>>
so, wenn der else Zweig drinn bleibt, gibt das ja auch kein Latch
sondern halt 'nur' einen weiteren Mux-Eingang. Und das erklaert auch,
warum sein Design ohne 'else', also mit Latch, ein anderes Timing
liefert.
Es ist ein Latch.
Aber genau das will ich doch auch.
Im Anhang findet ihr den Code der FSM.
Das Latch kann ich einfach beseitigen, wenn ich entweder wie oben
beschrieben mittels "else" alle Bedingungen komplett ausformuliere, oder
einfach als erste Zeile in dem Prozess ein "next_state <= state"
schreibe.
Aber dann lässt sich das Design "nur" noch mit 230MHz takten, statt mit
380.
Das ist ist immer noch schnell genug, aber ich würde gerne verstehen
welche Probleme ich mir damit einfange.
Der Compiler schmeißt mit dem Latch jedenfalls eine "gated clock"
Warnung.
Die Simulation ist identisch.
Praktisch kann ich es leider im Moment nicht testen.
Grüße,
Thomas
Thomas schrieb:> Es ist ein Latch.> Aber genau das will ich doch auch.
du hast, wenn ich das richtig sehe, nicht ein Latch sondern mindestens 4
(next_state) sowie weitere 8 (led)
...
> Der Compiler schmeißt mit dem Latch jedenfalls eine "gated clock"> Warnung.> Die Simulation ist identisch.
identisch zu was? ...
> Praktisch kann ich es leider im Moment nicht testen.
...wenn du es nicht real testen kannst
> sowie weitere 8 (led)
warum sollten die leds Latche sein? Ich sehe da keins.
> identisch zu was? ...
Zu der Version ohne Latch, wie am Anfang meines Posts beschrieben.