www.mikrocontroller.net

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


Autor: befro (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

type zustaende is ( START, a_SENDWERT_Z1, a_SENDWERT_Z2);
signal zustand, folgezustand: zustaende;

signal counter: STD_LOGIC_VECTOR( 7 downto 0 );

signal txflag: STD_LOGIC := '0';


begin
  z_speicher: process(clk)
  begin 
    if rising_edge(clk) then
      zustand <= folgezustand;
    end if;
  end process z_speicher;  

  ue_sn: process( RxData, zustand )
  begin
    case zustand is
      when START        =>   if RxData = "01100001" then -- 'a'=0x61
                          folgezustand <= a_SENDWERT_Z1;
                        else   folgezustand <= START;
                        end if;
        
      when a_SENDWERT_Z1   =>   counter <= counter +1 ;
                        txflag <= '0';
                        folgezustand <= a_SENDWERT_Z2;                   

      when a_SENDWERT_Z2  =>   txflag <='1';
                        if RxData = "01110011" then -- 's'=0x73; zurück in den Startzustand
                          folgezustand <= START;
                        else   folgezustand <= a_SENDWERT_Z2; -- im Zustand z2 bleiben
                        end if;
      when others        =>    folgezustand <= zustand; -- zustand nicht verändern                    

    end case;

  end process ue_sn;

  TxData <= counter;
  TxPulse <= txflag;

  
end Behavioral;

Kann mir jemand weiterhelfen?

Gruß,
befro

Autor: Olaf (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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:
:
:
  z_speicher: process(clk)
  begin 
    if rising_edge(clk) then
      zustand <= folgezustand;
      if (zustand = a_SENDWERT_Z1) then
        counter <= counter +1 ; -- das ist ein Zähler
      end if;
    end if;
  end process z_speicher;  
:
:


Die Simulation deines Codes funktioniert (scheinbar), weil die 
Sensitivity-List unvollständig ist. Auch ein gern gemachter Fehler bei 
der Mehrprozess-Schreibweise:
  ue_sn: process( RxData, zustand )
Richtig wäre:
  ue_sn: process( RxData, zustand, counter)

Ein Tipp:
Sieh dir mal die Einprozessschreibweise an, da passiert sowas nicht.

Autor: Klaus Falser (kfalser)
Datum:

Bewertung
0 lesenswert
nicht 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
  
  z_speicher: process(clk)
  begin 
    if rising_edge(clk) then
      zustand <= folgezustand;
      case folgezustand is     -- BITTE BEACHTEN
      when a_SENDWERT_Z1   =>   
          counter <= counter +1 ;
          txflag <= '0';
      when a_SENDWERT_Z2  =>   
          txflag <='1';
      when others        =>  
          null
      end case;
    end if;
  end process z_speicher;  

dann würde es funktionieren wie Du dir vorstellst.

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Andreas (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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...

Autor: befro (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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 :-/

Autor: Andreas (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: befro (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [vhdl]VHDL-Code[/vhdl]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.