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. :-)
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. :)
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.