Hallo, bei einer State Machine sollten ja den Ausgangssignalen immer Defaultwerte zugewiesen werden, damit das Signal nicht in jedem case zugewiesen werden muss. In der Uni habe ich gelernt als Default immer Null zu verwenden. In der Praxis sehe ich jedoch häufig, dass dem Ausgangssignal der "vorherige" Wert, also dessen Register zugewiesen wird. Den Vorteil sehe ich bei der zweiten Variante darin, das z. B. ein Counter oder ein Zustandsregister ihren Wert über mehrere Takte beibehalten. Nachteil ist, das z. B. ein "write enable" Signal nicht vergessen werden darf in den nachfolgenden Zuständen wieder zurückzusetzen. Ich verwende daher immer eine Kombination aus beiden: Defaultwert entspricht dem alten Wert und nur Schreibsignale setze ich auf Null. Meine Frage ist daher, welche Variante ist besser? Was verwendet ihr und warum? Ist es für die Synthese besser, wenn man den alten Wert als Default verwendet und nicht Null? Danke! Heiner
Hallo! "DIE" Antwort wird es auf deine Frage vermutlich nicht geben. Signale können kombinatorisch aus dem State gebildet werden. Dann brauchen sie auf jeden Fall einen "Default"-Wert, da sonst ein Latch entsteht. Sind die Signale registered, ist es vermutlich eher philosophischer Natur, was man bevorzugt. Ich halte es immer so: Wenn ein Signal nur in einem State oder für einen Takt einen bestimmten Wert annehmen soll, dann mache ich das über einen Default-Wert. Soll das Signal über mehrere Takte oder States anliegen, dann setze ich das Signal im State X und setzte es im State Y zurück.
Meine Konterfrage lautet hier: verwendest du die Ein- oder die Zwei-Prozess Schreibweise? Denn in der Zwei-Prozess Schreibweise darf im kombinatorischen Teil nie der "vorherige" Wert zugewiesen werden. Das gäbe ein Latch...
> Meine Konterfrage lautet hier: verwendest du die Ein- oder die > Zwei-Prozess Schreibweise? Man sollte nicht vergessen, dass es neben diesen beiden älteren Schreibweisen auch noch die etwas neuere Schreibweise mit einem Prozess für die State Übergänge und dem kombinarorischem Teil außerhalb eines Prozesses gibt. Beispiel:
1 | foo <= "101 when state = idle else |
2 | "010" when state = ramrd else |
3 | "011" when state = ramwr else |
4 | "110"; |
Das ist am übersichtlichen, wenn es darum geht zu sehen, welcher Ausgang in welchem state welchen Wert hat und man vergisst auch nie den default Wert. :-)
Das finde ich eigentlich auch am Übersichtlichsten, danke für den Tipp!
Schlumpf schrieb: > Wenn ein Signal nur in einem State oder für einen Takt einen bestimmten > Wert annehmen soll, dann mache ich das über einen Default-Wert. > Soll das Signal über mehrere Takte oder States anliegen, dann setze ich > das Signal im State X und setzte es im State Y zurück. Also so wie ich es auch mache. ;-) Lothar Miller schrieb: > Meine Konterfrage lautet hier: verwendest du die Ein- oder die > Zwei-Prozess Schreibweise? Ich habe einen kombinatorischen und einen sequentiellen Prozess. Im kombinatorischen Prozess weise ich dem kombinatorischen Signal das zughörige registrierte Signal zu. Lina schrieb: > Man sollte nicht vergessen, dass es neben diesen beiden älteren > Schreibweisen auch noch die etwas neuere Schreibweise mit einem Prozess > für die State Übergänge und dem kombinarorischem Teil außerhalb eines > Prozesses gibt. Auch eine interessante Idee, aber ich denke meine State Machines würden dadurch unübersichtlicher werden...
>Man sollte nicht vergessen, dass es neben diesen beiden älteren >Schreibweisen auch noch die etwas neuere Schreibweise mit einem Prozess >für die State Übergänge und dem kombinarorischem Teil außerhalb eines >Prozesses gibt. >Beispiel: >
1 | >foo <= "101 when state = idle else |
2 | > "010" when state = ramrd else |
3 | > "011" when state = ramwr else |
4 | > "110"; |
Was hat das mit "neuerer Schreibweise" zu tun? Du weist hier einfach einem Signal (foo) kombinatorisch einen Wert zu, abhängig vom aktuellen Zustand. Das hat nichts mit dem Unterschied zwischen der Ein- und Zweiprozessvariante von Zustandsautomaten zu tun.
Jope schrieb: > Was hat das mit "neuerer Schreibweise" zu tun? In der ein- und zwei-Prozess Schreibweise ist die Kombinatorik in einem Prozess. Dies ist imho unnötig, da man nur für sequentielle Logik Prozesse wirklich braucht. Hier ist dies nicht der Fall, daher neue/andere Schreibweise. Ich hoffe, dass beantwortet deine Frage.
Lina schrieb: > Dies ist imho unnötig, da man nur für sequentielle Logik > Prozesse wirklich braucht. Da hast du natürlich recht. Aber es ist ja auch kein Problem, seine Kombinatorik in einen Prozess zu "packen". Mir gefällt es besser, wenn ich auf einen Blick sehe, was in einen State passiert. In deiner Schreibweise sieht man auf einen Blick, welche Werte ein Signal zu welchem Zeitpunkt annimmt... Ob man dann seine Signalzuweisungen nach States "sortiert" dargestellt hat, oder, wie in deiner Schreibweise, nach Signalnamen, ist vermutlich einfach nur Geschmackssache.
Lina schrieb: > Jope schrieb: >> Was hat das mit "neuerer Schreibweise" zu tun? > > In der ein- und zwei-Prozess Schreibweise ist die Kombinatorik in einem > Prozess. Dies ist imho unnötig, da man nur für sequentielle Logik > Prozesse wirklich braucht. Hier ist dies nicht der Fall, daher > neue/andere Schreibweise. Das klingt als ob man das proces konstrukt vermeiden sollte, warum?
> Ob man dann seine Signalzuweisungen nach States "sortiert" dargestellt > hat, oder, wie in deiner Schreibweise, nach Signalnamen, ist vermutlich > einfach nur Geschmackssache. In der Tat. ;) > Das klingt als ob man das proces konstrukt vermeiden sollte, warum? Wie das "imho" schon andeutet, ist das alles nur meine persönliche und keinesfalls allgemeingültige Meinung. ;) Prozesse erinnern meiner Meinung nach einfach zu sehr an prozedurale Programmiersprachen, was VHDL ja nun mal nicht ist. Daher finde ich, dass meine Schreibweise besser zu programmierbarer Logik passt. :) (In Testbenches oder anderen Dingen, die nicht synthetisiert werden sollen ist das natürlich was anderes.)
Karl Könner schrieb: > Das klingt als ob man das proces konstrukt vermeiden sollte, warum? in dem gezeigten Fall sparst du dir die sensitivity Liste, ein riesengrosser Vorteil. Und ein Latch ist auch wesentlich besser zu erkennen bzw. zu vermeiden im Vergleich mit einem kombinatorischen process(....). Und die Bildschirme werden ja auch immer breiter, es bleibt ganz gut lesbar...
>Ich hoffe, dass beantwortet deine Frage
Nein, da sie rhetorisch war.
Das was Du hier machst, hat nichts mit dem Unterschied zwischen Ein- und
Zweiprozessvarianten zu tun.
Dieser Unterschied bezieht sich nämlich nur darauf, ob ich:
1. Das "state"-Register in einen getakteten Prozess packe, zusammen mit
den Zustandsübergangslogik;
2. Oder aber die Zustandsübergangslogik in einen ungetakteten Prozess
auslagere und in einem separaten, getakteten Prozess das
"state"-Register update.
Die Ausgangssignale, die mit den jeweiligen Zustände gekoppelt sind,
kann ich dann kombinatorisch erzeugen (innerhalb und außerhalb von
Prozessen). Ich mache das auch wie Du wenn es geht außerhalb.
Achso, okay. Zwei-Prozess-Schreibweise impliziert für mich, dass die Kombinatorik in einem zweiten Prozess ist. ;) Da dies bei mir (und offenbar auch bei dir) nicht der Fall ist, meinte ich, dass es eine andere Schreibweise ist. Tut mir leid, dass wir uns da missverstanden haben. :)
PS: die Zustandsüberganslogik kann man natürlich auch wunderbar außerhalb eines Prozessen machen, wenn man möchte:
1 | next_state <= idl when reset = '0' else |
2 | rdy when (state = idl or state = done) and tready = '1' else |
3 | send_addr when state = rdy and rx_done = '1' else |
4 | send_data when state = send_addr else |
5 | done when state = send_data else |
6 | state; |
Ist aber natürlich Geschmackssache und jedem selbst überlassen. ;)
Lina schrieb: > PS: die Zustandsüberganslogik kann man natürlich auch wunderbar > außerhalb eines Prozessen machen, wenn man möchte: > >
1 | next_state <= idl when reset = '0' else |
2 | > rdy when (state = idl or state = done) and tready = '1' |
3 | > else |
4 | > send_addr when state = rdy and rx_done = '1' else |
5 | > send_data when state = send_addr else |
6 | > done when state = send_data else |
7 | > state; |
> > Ist aber natürlich Geschmackssache und jedem selbst überlassen. ;) Wird halt bei große und komplexen FSMs sehr schnell sehr unübersichtlich. Da hat die Schreibweise mit Process & CASE deutlich Vorteile. Man sieht direkt, was in einem State passiert, welche Ausgangssignale gesetz werden, welche State-Übergänge möchlich sind. Alles auf eine Blick erkenntlich. Ein FSM ist ja meistens die zentralle Kontrollinstanz und kontroliert die (Ausgangs-)Signale, daher finde ich die zentralle Zuweisung der Signale genau in dem State Case am effektivsten. Nimm man an deine FSM kontrolliert 50 Signale, da darf man sich dann aus 50 einzelnen Zuweisungen den State raussuchen. Mal davon abgesehen, dass obige Schreibweise ganz schnell sehr hässlich aussieht, wenn es von einem State nicht nur einen Übergang gibt, sondern viele. Rein von der Logik betrachtet beschreibt dein Code übrigens einen Priority-Encoder, d.h. viele hintereinander geschaltete Multiplexer, d.h. längere Signallaufzeiten und eine höheren Logikverbrauch.Ein CASE Statement beschreibt lediglich einen MUX. Das büglen heute jedoch alle (FPGA-) Synthesizer glatt, intern wird ein CASE synthetisiert. Gruss, JD
Das kannst du so pauschal nicht sagen. Ein Case Statement ist nur dann übersichtlich, wenn der Verlauf der FSM recht gradlinig ist und es von einem State nur wenige Verzweigungen gibt. Reagiert deine FSM jedoch auf Events wird ein Case Statement sehr groß, weil man für jeden State einzeln eine if Anfrage auf das Event schreiben muss, was in Viel doppeltem Code resultiert. In meiner Schreibweise wäre es nur eine Zeile. Aus der Sicht des FPGAs ist beides nur syntaktischer Zucker. Am Ende kommen LUTs bei heraus.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.