Forum: FPGA, VHDL & Co. warning beim Implementieren einer State Machine


von befro (Gast)


Lesenswert?

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.
1
type zustaende is ( START, a_SENDWERT_Z1, a_SENDWERT_Z2);
2
signal zustand, folgezustand: zustaende;
3
4
signal counter: STD_LOGIC_VECTOR( 7 downto 0 );
5
6
signal txflag: STD_LOGIC := '0';
7
8
9
begin
10
  z_speicher: process(clk)
11
  begin 
12
    if rising_edge(clk) then
13
      zustand <= folgezustand;
14
    end if;
15
  end process z_speicher;  
16
17
  ue_sn: process( RxData, zustand )
18
  begin
19
    case zustand is
20
      when START        =>   if RxData = "01100001" then -- 'a'=0x61
21
                          folgezustand <= a_SENDWERT_Z1;
22
                        else   folgezustand <= START;
23
                        end if;
24
        
25
      when a_SENDWERT_Z1   =>   counter <= counter +1 ;
26
                        txflag <= '0';
27
                        folgezustand <= a_SENDWERT_Z2;                   
28
29
      when a_SENDWERT_Z2  =>   txflag <='1';
30
                        if RxData = "01110011" then -- 's'=0x73; zurück in den Startzustand
31
                          folgezustand <= START;
32
                        else   folgezustand <= a_SENDWERT_Z2; -- im Zustand z2 bleiben
33
                        end if;
34
      when others        =>    folgezustand <= zustand; -- zustand nicht verändern                    
35
36
    end case;
37
38
  end process ue_sn;
39
40
  TxData <= counter;
41
  TxPulse <= txflag;
42
43
  
44
end Behavioral;

Kann mir jemand weiterhelfen?

Gruß,
befro

von Olaf (Gast)


Lesenswert?

> 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

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

> 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
    if rising_edge(clk) then
6
      zustand <= folgezustand;
7
      if (zustand = a_SENDWERT_Z1) then
8
        counter <= counter +1 ; -- das ist ein Zähler
9
      end if;
10
    end if;
11
  end process z_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.

von Klaus F. (kfalser)


Lesenswert?

> 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
    if rising_edge(clk) then
5
      zustand <= folgezustand;
6
      case folgezustand is     -- BITTE BEACHTEN
7
      when a_SENDWERT_Z1   =>   
8
          counter <= counter +1 ;
9
          txflag <= '0';
10
      when a_SENDWERT_Z2  =>   
11
          txflag <='1';
12
      when others        =>  
13
          null
14
      end case;
15
    end if;
16
  end process z_speicher;

dann würde es funktionieren wie Du dir vorstellst.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

> 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

von Andreas (Gast)


Lesenswert?

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

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Angehängte Dateien:

Lesenswert?

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

von befro (Gast)


Lesenswert?

>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

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

> 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 :-/

von Andreas (Gast)


Lesenswert?

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.

von befro (Gast)


Lesenswert?

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?

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

> Gibt es irgendwo eine gute Beschreibung/Beispiel für
> eine State Machine mit einem Prozess?
Alle meine VHDL-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.

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
Noch kein Account? Hier anmelden.