Hallo Zusammen,
bei der Umsetzung einer Zustandsmaschine mit 3 Zuständen habe ich
folgendes Problem:
In einem Zustand soll ein 8 Bit Zähler um 1 erhöht werden. Der Compiler
gibt ein Warning aus, dass er dafür ein gesondertes Latch anlegen müsste
und dieses wohl irgendwie asynchron sei und damit problematisch.
Mir ist völlig unklar wieso. Sollte man nicht einfach die eine Zeile für
die Erhöhung des Zählerwertes in die case-Anweisung für die Zustände
schreiben können?
WARNING:Xst:737 - Found 8-bit latch for signal <counter>. Latches may be
generated from incomplete case or if statements. We do not recommend the
use of latches in FPGA/CPLD designs, as they may lead to timing
problems.
> Mir ist völlig unklar wieso.
Das liegt daran das du vermutlich gewohnt bist in einer
normalen Programmiersprache normale Prozessoren zu programmieren
und jetzt glaubst dieses Wissen uebertragen zu koennen weil die
Sprachen sich so aehnlich sehen.
Das ist leider ein grosser Fehler. Du musst dir darueber im klaren
das du jetzt kein Programm erzeugst das nacheinander ablaeuft und
irgendwelchen Dinge macht wenn es meint sie machen zu muessen.
Wenn die Synthesesoftware ein Latch anlegt dann ist das immer da. Auch
wenn auch es garnicht benoetigt wird. Also sozusagen wie eine globale
Variable. Aber es kommt noch schlimmer. Wenn es irgenwelche
Abhaengigkeiten von ihrem Zustand gibt dann werden die auch immer
ausgefuehrt. Und das sollte nun aber idealerweise syncron geschehen weil
es sonst passieren kann das in deinem Programm^WLogic irgendwelche
Pegelwechsel geschehen die du nicht beabsichtigst.
Ich weiss auch eigener <aechz> betrueblicher Erfahrung das es durchaus
moeglich ist eine Logic zu beschreiben die als Programm perfekt und
logisch aussieht, in der Simulation gut aussieht und in der Praxis
ueberhaubt nicht funktioniert. Es ist wirklich wichtig das man beim
betrachten eines solchen Progammes versteht was der Compiler daraus
machen wird.
Olaf
> counter <= counter +1 ;
Sowas darfst du (natürlich) nur in einem getakteten Prozess machen.
Das traditionelle Problem mit der Mehrprozess-Schreibweise.
So wie du es beschreibst, würde der Zähler beliebig schnell zählen,
solange der Zustand a_SENDWERT_Z1 aktiv ist. Das ist eine
kombinatorische Schleife.
Einen getakteten Zähler würdest du so bekommen:
1
:
2
:
3
z_speicher:process(clk)
4
begin
5
ifrising_edge(clk)then
6
zustand<=folgezustand;
7
if(zustand=a_SENDWERT_Z1)then
8
counter<=counter+1;-- das ist ein Zähler
9
endif;
10
endif;
11
endprocessz_speicher;
12
:
13
:
Die Simulation deines Codes funktioniert (scheinbar), weil die
Sensitivity-List unvollständig ist. Auch ein gern gemachter Fehler bei
der Mehrprozess-Schreibweise:
1
ue_sn:process(RxData,zustand)
Richtig wäre:
1
ue_sn:process(RxData,zustand,counter)
Ein Tipp:
Sieh dir mal die Einprozessschreibweise an, da passiert sowas nicht.
> So wie du es beschreibst, würde der Zähler beliebig schnell zählen,
Nein, nicht unbedingt, da der Prozess nur bei einer Zustandswechsel von
RXData und zustand "gestartet" wird. Das Signal Zustand zumindest ändert
sich nur mit dem Takt, ergo auch der Zähler.
Wenn man das Zählen in den synchronen Prozess verschiebt
1
2
z_speicher:process(clk)
3
begin
4
ifrising_edge(clk)then
5
zustand<=folgezustand;
6
casefolgezustandis-- BITTE BEACHTEN
7
whena_SENDWERT_Z1=>
8
counter<=counter+1;
9
txflag<='0';
10
whena_SENDWERT_Z2=>
11
txflag<='1';
12
whenothers=>
13
null
14
endcase;
15
endif;
16
endprocessz_speicher;
dann würde es funktionieren wie Du dir vorstellst.
> Nein, nicht unbedingt, da der Prozess nur bei einer Zustandswechsel von> RXData und zustand "gestartet" wird.
In der Simulation schon, aber in der realen Hardware wird ein
(Zähler-)Latch gebaut, das mit zustand=a_SENDWERT_Z1 aktiviert wird und
in diesem Zustand so schnell wie möglich hochgezählt wird.
Auf diese Art (unvollständige Sensitivity-List) sieht zwar die
Simulation richtig aus, die real implementierte Hardware verhält sich
anders :-o
Hallo befro,
ich glaube mal Du hast etwas anderes beschrieben, als Du eigentlich
haben möchtest:
mal in Text:
wenn Zustand a_SENDWERT_Z1 erreicht ist, zähle den vector counter so
schnell hoch wie die Technologie es hergibt...
Ich befürchte fast Du wolltest das im Zustand a_SENDWERT_Z1 der Wert bei
jedem steigenden Clock um 1 erhöht wird?
Dann musst Du das auch so schreiben, so wie Du es geschrieben hast,
bleibt der Synthese nichts anderes über als ein Latch zu bauen ( der
Wert soll ja bei allen Zustaender ausser a_sendwert_z1 den aktuellen
Wert behalten. Da Du aber keinen Clock für den Zähler definiert hast...
Die Gefahr entstammt hier der Zwei-Prozess Methode...
Gruss
Andreas
> Da Du aber keinen Clock für den Zähler definiert hast...
Ich habe das Ganze mal implementiert und im Bild sieht man jetzt rechts
oben schön das Latch, das vom Zustands-FF enabled wird.
Solange der entsprechende Zustand aktiv ist wird der Ausgang des Latches
um 1 incrementiert (der Addierer) und dann wieder in das Latch
eingespeist. Weil der Zustand noch immer aktiv (und damit das Latch
transparent) ist, erscheint dieses Ergebnis schnellstmöglich am Ausgang
des Latchs und das Spiel geht von vorne los...
>Ich befürchte fast Du wolltest das im Zustand a_SENDWERT_Z1 der Wert bei>jedem steigenden Clock um 1 erhöht wird?
Ja genau, immer wenn der Übergang in den Zustand a_SENDWERT_Z1 passiert,
soll der Counter um 1 erhöht werden.
>wenn Zustand a_SENDWERT_Z1 erreicht ist, zähle den vector counter so>schnell hoch wie die Technologie es hergibt...
Das wundert mich ein wenig. Im Prozess "z_speicher" wird der Zustand
"upgedated". Dieser Prozess wird mit dem vollen Systemtakt ( in meinem
Fall 16MHz ) getaktet. Der Zustand a_SENDWERT_Z1 sollte nur einen Takt
lang aktiv sein, weil dieser Zustand sofort in den Zustand
a_SENDWERT_Z2 übergeht. Deshalb bin ich davon ausgegangen, dass der
Zähler nur um 1 erhöht wird.
Lothar: wie kann man eigentlich den VHDL-Code in ISE in einen Schaltplan
umwandeln?
Gruß,
befro
> Lothar: wie kann man eigentlich den VHDL-Code in ISE in einen Schaltplan> umwandeln?
Das ist der RTL-Viewer
Processes --> Synthesize --> View RTL Schematic
> Der Zustand a_SENDWERT_Z1 sollte nur einen Takt lang aktiv sein,
Ist er auch, aber während dieses Taktes hat die Kombinatorik Zeit
hochzuzählen, und die zählt schnell :-/
Hallo Lothar,
"Das wundert mich ein wenig. Im Prozess "z_speicher" wird der Zustand
"upgedated". Dieser Prozess wird mit dem vollen Systemtakt ( in meinem
Fall 16MHz ) getaktet. Der Zustand a_SENDWERT_Z1 sollte nur einen Takt
lang aktiv sein, weil dieser Zustand sofort in den Zustand
a_SENDWERT_Z2 übergeht. Deshalb bin ich davon ausgegangen, dass der
Zähler nur um 1 erhöht wird."
Wie einer der Vorschreiber geschrieben hat, neigen Synthesetools dazu (
vermeindlich vom Schreiberling vergessene Sensitivity Signale zu
ergänzen). In deinem Falle wird stillschweigend der counter ergänzt und
dann läuft das Ding kombinatorisch, auf der Hardware ist das Verhalten
und die Zaehlgeschwindigkeit nicht vorhersehbar.
Besten Dank an euch für die Hilfe, jetzt läuft der Code bestens :-)
Zwar will die Erkenntnis noch nicht so richtig in's Blut übergehen, aber
ich werde sie noch ein wenig auf mich wirken lassen.
Oben wird beschrieben, dass mit einem Ein-Prozessmodell so was nicht
passieren sollte. Gibt es irgendwo eine gute Beschreibung/Beispiel für
eine State Machine mit einem Prozess?
> Gibt es irgendwo eine gute Beschreibung/Beispiel für> eine State Machine mit einem Prozess?
Alle meineVHDL-Quellen ;-)
Im Buch VHDL-Synthese von Reichardt/Schwarz ist eine schöne
Gegenüberstellung der verschiedenen Schreibweisen. Auch der Rest vom
Buch ist (besonders für Anfänger) sehr gut.