Hallo Leute,
ich habe eine Frage zu kombinatorischen Prozessen.
Sehen wir uns diese State machine an:
1
STATE_MEM : process( clk , reset )
2
begin
3
if reset = ’1’ then
4
state <= "00";
5
else if rising_edge(clk) then
6
if(enable = '1') then
7
state <= next_state;
8
end if;
9
end if;
10
11
end process
12
13
14
15
TRANSITION_LOGIC : process( state , i )
16
begin
17
next_state <= state ;
18
19
case( state) is
20
when "00" =>
21
if i = ’1’ then
22
next_state <= "01";
23
else
24
next_state <= "00";
25
end if;
26
when "01" =>
27
if i = ’1’ then
28
next_state <= "10";
29
else
30
next_state <= "00";
31
end if;
32
when "10" =>
33
if i = ’1’ then
34
next_state <= "10";
35
else
36
next_state <= "00";
37
end if;
38
when others =>
39
next_state <= "00";
40
end case;
41
end process;
Es heisst doch, dass in einem rein kombinatorischen Prozess Signale
nicht gespeichert werden. Weil diese ja nicht getaktet sind und somit
keine Flip Flops erzeugt werden.
Wenn wir jetzt den Prozess "TRANSITION_LOGIC" betrachten. Dann wird ja
"next_state" auf einen Wert gesetzt falls sich "state" oder "i" ändert.
Danach wird bei der nächsten steigenden Flanke dem "state" der WErt von
"next_state" zugewiesen. Aber sollte zu diesem Zeitpunkt der Wert vom
"next_state" nicht wieder weg sein? Weil dieser ja nicht gespeichert
wird...?
Danke schon mal im Vorraus
Chris
Aus Softwaresicht, also im Sinne der Simulation, wird das natürlich sehr
wohl gespeichert und auch die Synthese speichert sich diese Information.
Aber das, was dabei herauskommt, enthält keinen Speicher mehr, in dem
Variablen oder "temporäre Signale" noch irgendwie sichtbar wären, weil
diese eben nur Hilfskonstrukte beim Bauen sind. Deren Information muss
sich in irgendeiner Form in Signale abbilden, die in einen echten
Speicher münden.
Und:
Nur, was aufgrund der Verknüpfungen mit IOs oder internen
"Energiespeichern" tatsächlich benötigt wird, führt auch zu einer
Hardware und nur die kann (muss nicht) einen Wert speichern. Ein solcher
state wäre z.B. auch in Hardware dann nicht mehr in dieser Form
sichtbar, wenn die Bits, die ihn codieren, nicht vollständig benötigt
werden.
Ich betone nochmals, dass VHDL eine Bauanleitung für eine Schaltung ist.
Wenn dort drin steht, dass der Erbauer sich was merken soll oder eine
Schleife machen soll um mehrfach etwas zu bauen, heißt das noch lange
nicht, dass die Schaltung die er erbaut, sich später auch was merken
muss oder Schleifen vollzieht.
In dem Prozess TRANSITION_LOGIC ist next_state zu meine identisch mit
state, dann aber wieder nicht. Da muss man sich entscheiden. Dann tritt
auch die Frage gar nicht auf.
Es scheint mir, als wenn Du ein "Programm" schreiben willst. Aber, wie
unser allseits beliebter Lothar immer sagt: Du beschreibst Hardware.
Chris schrieb:> Aber sollte zu diesem Zeitpunkt der Wert vom> "next_state" nicht wieder weg sein?
Transistion_logic muss tatsächlich nichts speichern. Dieser Prozess
beschreibt eine einfache kombinatorische Logik (ein Schaltnetz), die aus
den aktuellen Werten von state und von i den Wert von next_state
berechnet. next_state ändert sich immer dann, wenn einer der Eingänge
(state, i) sich ändert.
Wichtig ist, dass der Wert von next_state dann stabil ist, wenn er
benötigt wird. Das ist jeweils bei der positiven Taktflanke (wenn
next_state nach state übernommen werden soll). Das ist aber
gewährleistet, wenn sich die Werte von state und i einige ns vor der
Taktflanke nicht mehr ändern.
Wenn die Taktflanke kommt ändert sich state, und in der Folge schaltet
auch next_state um. Aber das ist ok, weil der abzuspeichernde Wert von
next_state ja schon bei der Taktflanke nach state übernommen wurde und
erst wieder bei der nächsten Taktflanke interessiert. Wennd die
Taktfrequenz nicht zu hoch ist macht state als Eingang hier also keine
Probleme, weil sich state und next_state nur kurz nach der Taktflanke
ändern - aber erst beid er nächsten Taktflanke wieder von Interesse sind
- und bis dahin ist next_state wieder stabil.
Bei i ist die Sache potentiell anders, weil wir in deinem Code-Schnipsel
nicht sehen, wann genau i sich ändern kann. Wenn i sich zu beliebigen
Zeitpunkten ändern kann, dann wird deine Statemachine tatsächlich nicht
zuverlässig funktionieren. Es kann dann passieren, dass i sich gerade
kurz vor einer Taktflanke ändert, und der Wert von next_state bei der
Taktflanke noch nicht vollständig auf den neuen gültigen Wert
umgeschaltet ist. Dann machte deine Statemachine falsche oder
undefinierte State-Übergänge.
Aber wenn i selbst auch aus einem Flip-Flop stammt, das mit dem selben
Takt arbeitet wie deine Statemachine, dann passt wieder alles. Dann
liegt der Wert von i lange genug an um die Durchlaufzeiten der
Übergangslogik abzuwarten. Dann hat next_state vor der nächsten Flanke
wieder zuverlässig auf den neuen Folgezustand umgeschaltet.
Das ist auch der Grund, warum externe Signale (die keinen definierten
Setup-Hold-Zeiten relativ zu clk haben) erst einsynchronisiert werden
müssen, ehe sie in deiner synchronen Statemachine ausgewertet werden
dürfen.
Chris schrieb:> Es heisst doch, dass in einem rein kombinatorischen Prozess Signale> nicht gespeichert werden.
Du hast da aus den Aussagen etwas falsch extrahiert.
In eine kombinatorischen Prozess werden keine getakteten
Speicherelemente (aka. Flipflops) beschrieben. Bestenfalls ein Latch
kannst du da basteln (meist ungewollt und zufällig).
Ein kombinatorischer Prozess beschreibt (genauso wie eine ungetaktete
nebenläufige Anweisung) einfach eine Schaltung, die aus Eingangswerten
Ergebnisse berechnet.
Udn diese Ergebnisse werden natürlich nicht gespeichert, sondern ändern
sich mit jeder Änderung des Eingangswertes.
Aber wie Theor schon sagt, was ich immer sage:
Stell dir eine Hardware vor und beschreibe sie dann mit der
HardwareBESCHREIBUNGssprache VH-D-L. Es geht mit Garantie schief, wenn
du dir solche Eselsbrücken wie "kombinatorische Prozesse speichern
nichts" merkst und basierend auf diesem "Extrakt" drauflos
programmierst...
Chris schrieb:
FSM:
Z(t+1) <= f(Z(t),X(t))
y(t) <= f(Z(t),X(t))
Letzte Gleichung ist rein kombinatorisch, die erstere beinhaltet
kombinatorik und Speicher. eine Zustands-Speicherung, also die Abbildung
von Z(t) auf Z(t+1) wird durch FF ("getakteter Prozess) realisiert,
alles andere durch kombinatorik.
https://www3.informatik.uni-erlangen.de/DE/Lehre/VHDL-RA/SS2014/folien/09-fsm.pdf
Such dir einfach mal die Blockbilder einer FSM aus einem gescheiten
Lehrbuch raus, dann sollte der Unterschied zwichen "Speicher" und
"Variablenspeicherung" klarer werden.
Man muss dem TO zugute halten, dass diese Sache in VHDL auch recht
verwirrend ist. Die Semantik eines Prozesses besagt, dass der Rumpf nur
ausgewertet wird, wenn sich eines der Signale aus der Sens-Liste ändert.
Aber was ist, wenn sich keines der Signale ändert? Bleiben die Ergbnisse
aus dem Prozess erhalten (aka Speicherung), oder sind sie anschließend
undefiniert? Beides ist im obigen Beispiel falsch, weil es sich um reine
Kombinatorik handelt, die kontinuierlich ausgewertet wird und nicht nur
bei Änderung eines Signals.
Deswegen hat reine Kombinatorik streg genommen eigentlich auch nichts in
einem Prozess zu suchen. Es wäre besser, sie als plattes concurrent
statement ohne Prozess drumherum hinzuschreiben. Leider verbietet VHDL
die Benutzung von IF und CASE außerhalb von Prozessen, und das ganze mit
WHEN oder als Boole'sche Gleichungen aufzuschreiben ist umständlich und
fehleranfällig. Deswegen nimmt man halt doch einen Prozess.
Vielleicht sollte man noch erwähnen, dass die ganze Sache mit der
Sensitivitätsliste ein Zugeständnis an den Simulator ist. Der Simulator
speichert die Zustände kombinatorischer Signale intern natürlich
irgendwo ab, und muss sie daher auch nur dann neu berechnen, wenn sich
die Operanden ändern (heißt deswegen Event Driven Simulation). Durch sie
Sens-Liste sagt man dem Simulator, wann er seine internen Zustände neu
berechnen muss. Das ganze darf aber nicht darüber hinweg täuschen, dass
das Konstrukt eine reine Gatteranordnung ohne Speicherelemente
beschreibt.
In SystemVerilog ist das übrigens besser gelöst: Es gibt dort den
always_comb-Block, in dem der Benutzer reine Kombinatorik reinschreiben
und dabei alle Sprachkonstrukte von SystemVerilog verwenden kann. Die
Sensitivitätsliste baut sich der Compiler selbst, daher kann man auch
kein Signal vergessen und versehentlich ein Latch erzeugen.
Vancouver schrieb:> Man muss dem TO zugute halten, dass diese Sache in VHDL auch recht> verwirrend ist. Die Semantik eines Prozesses besagt, dass der Rumpf nur> ausgewertet wird, wenn sich eines der Signale aus der Sens-Liste ändert.> Aber was ist, wenn sich keines der Signale ändert? Bleiben die Ergbnisse> aus dem Prozess erhalten (aka Speicherung), oder sind sie anschließend> undefiniert? Beides ist im obigen Beispiel falsch, weil es sich um reine> Kombinatorik handelt, die kontinuierlich ausgewertet wird und nicht nur> bei Änderung eines Signals.> [...]
Hm. Naja. Ich mag falsch liegen, aber mir kommt dieses Argument doch so
vor, als wenn es aus der nicht ganz beiseite geschobenen Sichtweise der
imperativen Programmierung her rührt.
Ich denke es ist nicht wirklich zutreffend, in beiden Fällen (der
Beschreibung eines Flip-Flops und der Kombinatorik) von "Speicherung" zu
sprechen. Um den Kontrast etwas deutlicher zu machen könnte man eher von
Speicherung im Gegensatz zu "Beständigkeit" (das ist nur ein Vorschlag)
sprechen. Ich stimme allerdings zu, dass, was ich eben Beschreibung
genannt habe, in VHDL eine auch mir, etwas "gekünstelte" Semantik
beinhaltet - eine ein wenig abseitige Interpretation.
Sie wird eigentlich erst klar, wenn man sich dazu, die reale Schaltung
denkt. Dann nämlich kommt man an den Punkt, an dem eine von einer Flanke
abhängige "Weiterleitung" und "Beständigkeit" eigentlich nur mit einem
FF möglich ist. Andererseits ergibt eine Kombinatorik eine zeitlich
verzögerte "Beständigkeit".
Um klar zumachen, was ich unter "Beständigkeit" hier verstehen will,
eine Skizze eines Und-Gatters:
x1 +---+
----+ | y
| & +--->
----+ |
x2 +---+
In VHDL also etwa: "y y= x1 and x2".
Ein einfacherer, sogar trivialer, Fall ist:
x x
----------->
Etwas, das in VHDL zur Semantik gehört und nicht ausdrücklich
hingeschrieben werden muss.
Die Frage des TO ist sinngemäss, ob denn nicht y "verschwunden" ist,
wenn der UND-Prozess ein weiteres Mal durchlaufen wird. Zitat: "Er wird
ja nicht gespeichert". Die Fehlinterpretation ist dem
VHDL-Fortgeschrittenen klar, denn er weiss, dass er eine
Kombinatorik-SCHALTUNG beschrieben hat, die ständig die
Und-Verknüpfung von x1 und x2 bildet und damit ist das Resultat y
ständig vorhanden, obwohl es nicht gespeichert wird - nicht in dem
Sinne, wie es mit einem Flip-Flop geschieht.
Damit ist diese Frage eigentlich geklärt. (Womit ich nicht sagen will,
dass man darüber nicht noch weiter reden kann).
In meinem ersten Beitrag hier, habe ich mich auf etwas anderes bezogen,
In Schaltung übersetzt, sieht TRANSITION_LOGIC etwa so aus:
+-------------------+
state | |
----->+-----+------?--+ | next_state
| | ^ +---+------->
| V | |
| +--+--+ | |
i | | | | |
----->+--+ f +->-+ |
| | | |
| +-----+ |
+-------------------+
In dieser Beschreibung steckt ein Widerspruch. Und zwar nicht weil
eine Rückkopplung beschrieben wird - das wird es nämlich nicht. Sondern
weil next_state zum einen identisch mit state sein soll, andererseits
aber, mit dem Resultat (der hier mit f angedeuteten) kombinatorischen
Funktion (der case-Teil des Prozesses).
Der TO wollte anscheinend eine Rückkopplung beschreiben, in der
Annahme, er realisiere damit eine Speicherung. Diese Deutung seines
VHDL-Textes ist aber nur bei einer imperativen Interpretation, also
Zeile-für-Zeile, sinnvoll. So aber kann VHDL eben nicht verstanden
werden. Das ist nicht seine Semantik.
Hier spielt auch die so oft wiederholte Warnung vor asynchroner Logik
eine Rolle, denke ich. Sie wird bei Erklärungen und in Lerntexten schon
so weit stillschweigend vorausgesetzt, dass sie möglicherweise dem einen
oder anderen gar nicht mehr erklärt wird. Ja, vielleicht hat sie der
"Lehrer" schon so weit verinnerlicht, dass er die lediglich von den
Konsequenzen erzählt und dem Schüler das unklare Gefühl bleibt, da fehle
etwas an der Erklärung. Ich vermute wenigstens, dass diese Tatsache für
den TO ein Teil seines Verständnisproblems ist.
Dabei ist es, wie schon oft demonstriert, durchaus möglich asynchrone
Logik zu beschreiben und auch zu synthetisieren. Es handelt sich
lediglich um eine Regel, die das arbeiten vereinfachen soll, nicht
um ein technisches Hindernis im eigentlichen Sinn. (Ich denke, ich sage
nur, was den VHDL-Fortgeschrittenen ohnehin klar ist).
Jedenfalls ist aber eine Rückführung von Signalen keine Speicherung.
Vielmehr ein Fall von (der von mir so genannten) "Beständigkeit" von
Signalen. Bei einer Rückführung tritt deswegen ein gewisser
"Speichereffekt" ein, weil die Laufzeit eine Rolle spielt. Die Frage ist
dann nur, ob nachfolgende Logik auf diesen "Zustand" schnell genug
reagieren kann.
Püh. Ein langer Text. Ich hoffe er ist sinnvoll und hilft jemandem.
Viel Erfolg.
Theor schrieb:> könnte man eher von> Speicherung im Gegensatz zu "Beständigkeit" (das ist nur ein Vorschlag)> sprechen.
Speicherung ist zugegeben unglücklich gewählt. Entscheidend ist, dass
der Wert erhalten bleibt.
> Der TO wollte anscheinend eine Rückkopplung beschreiben, in der> Annahme, er realisiere damit eine Speicherung.
Der Code des TO beschreibt einen völlig korrekten Zustandsautomaten,
soweit ich das sehe, und der enthält eine Rückkopplung. Die Speicherung
kommt aber nicht durch die Rückkopplung zustande, sondern durch den
getakteten ersten Prozess. Die Frage des TO war, warum im ungetakteten
zweiten Prozess nicht auch eine Speicherung stattfindet.
> In dieser Beschreibung steckt ein Widerspruch.> Sondern> weil next_state zum einen identisch mit state sein soll, andererseits> aber, mit dem Resultat (der hier mit f angedeuteten) kombinatorischen> Funktion (der case-Teil des Prozesses).
Nein, das ist kein Widerspruch. Innerhalb eines Prozesses werden die
Anweisungen sequenziell (wie bei einem imperativen Programm)
ausgewertet. (Genauer formuliert: Es wird bei der Synthese eine
Schaltung erzeugt, die das gleiche Ergebnis liefert wie der sequenziell
ausgeführte Code im Prozess). Die mehrmalige Zuweisung von next_state
ist korrekt, der zuletzt zugewiesene Wert "gewinnt". Next_state wird nur
dann identisch mit state, wenn keiner der Case-Branches zutrifft, was
aber im Beipiel niemals der Fall ist, weil die Case-Bedingungen
vollständig auscodiert sind und immer eine zutrifft. Man könnte die
Zeile next_state <= state also weglassen in diesem Fall, aber falsch ist
sie nicht.
Vancouver schrieb:> Man könnte die Zeile next_state <= state also weglassen
Auch wenn sie hier überflüssig ist, sollte man diese
Default-Zuweisungen immer am Anfang eines komb. Prozesses
schreiben (z.B. in der Zwei-Prozess-Schreibweise). Damit
sind Latches ausgeschlossen.