Forum: FPGA, VHDL & Co. Endlicher Automat hängt


von Patric v. (vloewis)


Lesenswert?

Hallo,
ich stehe da irgendwie auf dem Schlauch. Folgender VHDL Code

entity ResetGenerator is
    Port ( RESET_IN : in  STD_LOGIC;
           CLK_IN : in  STD_LOGIC;
           STATE_OUT: out std_logic_vector(1 downto 0);
           RESET_OUT : out  STD_LOGIC);
end ResetGenerator;

architecture Behavioral of ResetGenerator is

signal state: bit_vector(1 downto 0);

begin
  process(state, RESET_IN, CLK_IN)
  begin
    if rising_edge(CLK_IN) then
      case state is
  when "00" =>
    state <= "00";
    RESET_OUT <= '0';
    if RESET_IN = '1' then
      state <= "01";
      RESET_OUT <= '1';
    end if;
  when "01" =>
    state <= "11";
    RESET_OUT <= '1';
  when "11" =>
    state <= "10";
    RESET_OUT <= '0';
  when "10" =>
    state <= "10";
    RESET_OUT <= '0';
    if RESET_IN = '0' then
      state <= "00";
      RESET_OUT <= '0';
    end if;
  when others =>
    state <= "00";
      end case;
    end if;
  end process;
  STATE_OUT <= to_stdlogicvector(state);
end Behavioral;

Soll ein RESET_IN Signal entgegennehmen, für zwei CLK_IN Zyklen eine
'1' auf das Ausgangssignal RESET_OUT legen und danach warten, bis das
Eingangssignal wieder auf Null geht, damit das ganze wieder von vorn
beginnen kann.
Board ist ein Spartan 3AN Prototypenboard von DIGILENT, ich benutze ISE
13.2.
CLK_IN ist der 50MHz Quarz, RESET_IN einer der Taster.
RESET_OUT, STATE_OUT und auch der Taster sind auf LEDs gelegt,
das RESET_OUT-Signal wird zusätzlich noch mit einem Oszi überprüft.

Wenn ich jetzt das ganze ausprobiere:
Taste gedrückt: LED für Taste an, STATE_OUT ist "10"
Taste losgelassen: LED für Taste aus, STATE_OUT ist "00"
Es wird beim Drücken der Taste ein 40ns Impuls erzeugt.
So weit so gut...
Tippe ich jetzt mehrfach auf den Taster hängt das ganze nach kurzer 
Zeit.
Wenn es hängt:
Taste gedrückt: LED für Taste an, STATE_OUT ist _"00"_
Taste losgelassen: LED für Taste aus, STATE_OUT ist "00"
Es wird beim Drücken der Taste KEIN 40ns Impuls erzeugt.

Wie kann das sein? Was habe ich da nicht begriffen?

Gruß, Patric

von Klaus T. (gauchi)


Lesenswert?

so kann man das besser lesen
1
entity ResetGenerator is
2
    Port ( RESET_IN : in  STD_LOGIC;
3
           CLK_IN : in  STD_LOGIC;
4
           STATE_OUT: out std_logic_vector(1 downto 0);
5
           RESET_OUT : out  STD_LOGIC);
6
end ResetGenerator;
7
8
architecture Behavioral of ResetGenerator is
9
10
signal state: bit_vector(1 downto 0);
11
12
begin
13
  process(state, RESET_IN, CLK_IN)
14
  begin
15
    if rising_edge(CLK_IN) then
16
      case state is
17
        when "00" =>
18
          state <= "00";
19
          RESET_OUT <= '0';
20
          if RESET_IN = '1' then
21
            state <= "01";
22
            RESET_OUT <= '1';
23
          end if;
24
        when "01" =>
25
          state <= "11";
26
          RESET_OUT <= '1';
27
        when "11" =>
28
          state <= "10";
29
          RESET_OUT <= '0';
30
        when "10" =>
31
          state <= "10";
32
          RESET_OUT <= '0';
33
          if RESET_IN = '0' then
34
            state <= "00";
35
            RESET_OUT <= '0';
36
          end if;
37
        when others =>
38
          state <= "00";
39
      end case;
40
    end if;
41
  end process;
42
  STATE_OUT <= to_stdlogicvector(state);
43
end Behavioral;

keine fundierten Tipps, aber:

1. hast du das ganze mal simuliert?
2. die Fehlerbeschreibung klingt, als ob du irgendwo Probleme mit einem 
prellenden Taster hättest

von Patric v. (vloewis)


Lesenswert?

Ok, wie geht das mit der Lesbarkeit?

Und Danke erstmal für die Antwort.

zu 1. nein ich habe es nicht simuliert (kenne mich da mit den Tools 
(noch)
nicht so ganz aus.

zu 2. Müsste es nicht egal sein, ob der Taster prellt? Das Ding hängt
komplett. Selbst wenn der Taster irgendwo prellt müsste sich das ganze 
doch
wieder fangen, da es keinen Zustand gibt, der als Sackgasse in Frage 
kommt?
Der Taster funktioniert laut LED und die 50MHz sind auch weiterhin da
(Oszi geprüft).

von hmmmm (Gast)


Lesenswert?

Gibts bei der Synthese irgendwelche Warnungen?

von Patric v. (vloewis)


Lesenswert?

Warnungen:
Ja, jede Menge, die aber nichts mit dem entsprechenden Fetzen Hardware
zu tun haben. Nur für den ResetGenerator beschwert sich das Tool über 
den
default case (zu recht) und schmeisst ihn weg.

Ich habe das Ganze noch eben mal mit einem globalen asynchronen Reset
versehen (weiterer Taster). Es dauert gefühlt 5* so lang bis das Ganze 
hängt.
Aber es lässt sich wieder zum Leben erwecken indem man state auf "00" 
zwingt
und RESET_OUT auf '0'.

Kann ein bit_vector noch andere Zustände annehmen als "00" "01" "11" 
"10"?

Derzeitiger Code:
1
entity ResetGenerator is
2
    Port ( RESET_IN : in  STD_LOGIC;
3
         RESET: in STD_LOGIC;
4
           CLK_IN : in  STD_LOGIC;
5
        STATE_OUT: out std_logic_vector(1 downto 0);
6
           RESET_OUT : out  STD_LOGIC);
7
end ResetGenerator;
8
9
architecture Behavioral of ResetGenerator is
10
11
signal state: bit_vector(1 downto 0);
12
13
begin
14
  process(RESET, state, RESET_IN, CLK_IN)
15
  begin
16
    if RESET = '1' then
17
      state <= "00";
18
      RESET_OUT <= '0';
19
    else
20
      if rising_edge(CLK_IN) then
21
        case state is
22
          when "00" => 
23
            state <= "00";
24
            RESET_OUT <= '0';
25
            if RESET_IN = '1' then
26
              state <= "01";
27
              RESET_OUT <= '1';
28
            end if;
29
          when "01" =>
30
            state <= "11";
31
            RESET_OUT <= '1';
32
          when "11" =>
33
            state <= "10";
34
            RESET_OUT <= '0';
35
          when "10" =>
36
            state <= "10";
37
            RESET_OUT <= '0';
38
            if RESET_IN = '0' then
39
              state <= "00";
40
              RESET_OUT <= '0';
41
            end if;
42
          when others =>
43
            state <= "00";
44
        end case;
45
      end if;
46
    end if;
47
  end process;    
48
  STATE_OUT <= to_stdlogicvector(state);
49
end Behavioral;

Toll die Formatierung funktioniert ziemlich gut :)

von Achim S. (Gast)


Lesenswert?

Hallo Patric,

> Kann ein bit_vector noch andere Zustände annehmen als "00" "01" "11"
> "10"?

Nein, der bit_vector(1 downto 0) kennt keine anderen Werte.

Aber dein Synthesetool erkennt, dass du eine Statemachine baust, und es 
kann die interne Codierung der States anders wählen, als du im VHDL-Code 
angibst. Die Ausgänge müssen mit den Werten im Code übereinstimmen, aber 
die internen Zustände können eine andere Codierung aufweisen. Du kannst 
in der ISE die Codierung der SM vorgeben. Evtl ist dort eine Codierung 
wie "one hot" eingestellt, dann werden deine vier Zustände mit 4 
Flipflops codiert, und dann kann es verbotene Zustände geben, in denen 
sich die SM aufhängt.

Reset_in ein ansynchrones Signal von außen, das du zunächst 
einsynchronisieren musst. Andernfalls kann es passieren, dass Reset_in 
genau bei einer Taktflanke schaltet. Ein Teil der Logik wertet noch den 
alten Wert von Reset_in aus, ein anderer Teil sieht schon den neuen 
Wert, und insgesamt erhältst du ein verbotenes Ergebnis (SM hängt sich 
auf).

viele Grüße

Achim S.

von Achim S. (Gast)


Lesenswert?

Na, jetzt hab ich auch den passenden Link dazu gefunden :-)

http://www.lothar-miller.de/s9y/categories/35-Einsynchronisieren

von Patric v. (vloewis)


Lesenswert?

Danke Achim!

Also die Antwort auf meine Frage mit den Zuständen des bit_vectors wäre 
dann ein nein, aber das Synthesetool weiss es besser?
Ich dachte ich hätte das RESET_IN Signal über die Statemachine 
einsynchronisiert. Nun gut dann werde ich mir morgen mal ISE genauer 
ansehen, oder kannst Du mir sagen wo ich Einfluss auf die SM-Generation 
nehmen kann?

Ach Quartus war irgendwie einfacher :)

Aber das werde ich mir mal genauer zu Gemüte führen, ich habe schon an 
meinem Verstand gezweifelt. Immerhin ist es ja schon ein Gray-Code.

von user (Gast)


Lesenswert?

also statemachinen kann man auch so angeben

type state_type is (idle, zustand1, zustand2, zustand3);
signal state : state_type;

von Achim S. (Gast)


Angehängte Dateien:

Lesenswert?

> Nun gut dann werde ich mir morgen mal ISE genauer
> ansehen, oder kannst Du mir sagen wo ich Einfluss auf die SM-Generation
> nehmen kann?

auf dem Rechner hier habe ich nur die 10.1 installiert. Dort kannst du 
die Einstellung über einen Rechtsklick auf Synthesize XST -> Properties 
-> HDL Options einstellen. In anderen Versionen muss es nicht genau so 
heißen, aber ähnlich.

> Ich dachte ich hätte das RESET_IN Signal über die Statemachine
> einsynchronisiert.

Nö: du wertest das Signal zwar nur bei der steigenden Taktflanke aus, 
aber das Signals kann sich genau zu diesem Zeitpunkt ändern. Um es 
einzusynchronisieren musst du es mit der steigenden Taktflanke einem 
internen Signal zuweisen. Und dieses interne Signal nutzt du dann (mit 
einem Takt Verzögerung) zur Steuerung der SM.

Wenn sich dann das externe Signal genau bei der Taktflanke ändert, 
erhält das interne Signal den neuen Wert entweder gleich oder erst einen 
Takt später, aber es hat auf jeden Fall kurz nach der Taktflanke einen 
eindeutigen Wert. Und alle Teile der Logik der SM sehen den identischen, 
eindeutigen Wert und schalten mit dem nächsten Takt "in die selbe 
Richtung".

viele Grüße

Achim S.

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


Lesenswert?

Achim S. schrieb:
> Nö: du wertest das Signal zwar nur bei der steigenden Taktflanke aus,
> aber das Signals kann sich genau zu diesem Zeitpunkt ändern.
Und noch nicht mal das ist das Problem. Das kommt nämlich gleich danach: 
nicht alle Flipflops der FSM sehen den selben Pegel. Das ist der 
eigentliche Knackpunkt.
1
  process(RESET, state, RESET_IN, CLK_IN)
2
  begin
3
    if RESET = '1' then
4
      state <= "00";
5
      RESET_OUT <= '0';
6
    else
7
      if rising_edge(CLK_IN) then
Diese Sensitivliste ist überbestimmt. Da muss der Simulator zu viel tun, 
denn er wird unnötigerweise bei einer Änderung von state und RESET_IN zu 
einer Neuberechnung genötigt!


Patric vL schrieb:
> Ach Quartus war irgendwie einfacher :)
Das hat nichts mit Quartus zu tun. Auch Altera kocht da mit dem selben 
Wasser: unterschiedliche Laufzeiten von asynchronen Signalen, die direkt 
in eine FSM gehen, führen per Definition zu Fehlern.

> Nun gut dann werde ich mir morgen mal ISE genauer ansehen, oder kannst
> Du mir sagen wo ich Einfluss auf die SM-Generation nehmen kann?
Als Faustformel: wenn du durch eine geänderte FSM-Implementierung ein 
anderes Verhalten der FSM bekommst, dann hast du mit an Sicherheit 
grenzender Wahrscheinlichkeit einen Designfehler, der irgendwas mit 
Laufzeiten und/oder der Verdrahtung zu tun hat.

Patric vL schrieb:
> Ich habe das Ganze noch eben mal mit einem globalen asynchronen Reset
> versehen (weiterer Taster). Es dauert gefühlt 5* so lang bis das Ganze
> hängt.
Wie gesagt: andere Verdrahtung, anderes Verhalten.
Ursache: nicht einsynchronisierter Eingang, der direkt in die FSM geht.

Ein asynchroner Reset, wieder mal...
1
  process(RESET, state, RESET_IN, CLK_IN)
2
  begin
3
    if RESET = '1' then
Dazu den Klassiker im Beitrag "Xilinx und die Resets"
Und das lesenswerte WP272 von Xilinx.

von Patric v. (vloewis)


Lesenswert?

Hallo Achim S.,
hallo Lothar M.,

zu dem Punkt Synthesetool erkennt Statemachine:
Beim Schematic sind tatsächlich 4 FlipFlops zu erkennen. Ich durchschaue
das Schematic nicht ganz, aber es sieht nach einer OneHot-Codierung aus.
Beim Menuepunkt "FSM Encoding Algorithm" war "Auto" eingetragen.
Ich habe das RESET-Signal erstmal wieder rausgenommen (war eh nur um zu
prüfen, ob man einen augenscheinlichen "00" state auf "00" resetten 
kann)
und ich habe "FSM Encoding Algorithm" auf "None" gesetzt damit 
funktioniert
der folgende Code:
1
process(CLK_IN)
2
  begin
3
    if rising_edge(CLK_IN) then
4
      case state is
5
        when "00" => 
6
          state <= "00";
7
          RESET_OUT <= '0';
8
          if RESET_IN = '1' then
9
            state <= "01";
10
            RESET_OUT <= '1';
11
          end if;
12
        when "01" =>
13
          state <= "11";
14
          RESET_OUT <= '1';
15
        when "11" =>
16
          state <= "10";
17
          RESET_OUT <= '0';
18
        when "10" =>
19
          state <= "10";
20
          RESET_OUT <= '0';
21
          if RESET_IN = '0' then
22
            state <= "00";
23
            RESET_OUT <= '0';
24
          end if;
25
        when others => 
26
          state <= "00";
27
      end case;
28
    end if;
29
  end process;
zumindest habe ich nach 5min Finger wundtippen keinen Hänger gehabt (ich
weiss, dass dies kein Beweis ist).

zum Punkt einsynchronisieren des RESET_IN Signales:
Ich habe in einem zweiten process das RESET_IN Signal mit CLK_IN 
synchronisiert und dabei das Signal synced_reset generiert und dieses
statt RESET_IN verwendet. Code:
1
process (CLK_IN)
2
  begin
3
    if rising_edge(CLK_IN) then
4
      synced_reset <= RESET_IN;
5
    end if;
6
  end process;
7
8
  process(CLK_IN)
9
  begin
10
    if rising_edge(CLK_IN) then
11
      case state is
12
        when "00" => 
13
          state <= "00";
14
          RESET_OUT <= '0';
15
          if synced_reset = '1' then
16
            state <= "01";
17
            RESET_OUT <= '1';
18
          end if;
19
        when "01" =>
20
          state <= "11";
21
          RESET_OUT <= '1';
22
        when "11" =>
23
          state <= "10";
24
          RESET_OUT <= '0';
25
        when "10" =>
26
          state <= "10";
27
          RESET_OUT <= '0';
28
          if synced_reset = '0' then
29
            state <= "00";
30
            RESET_OUT <= '0';
31
          end if;
32
        when others => 
33
          state <= "00";
34
      end case;
35
    end if;
36
  end process;

"FSM Encoding Algorithm" wurde wieder auf "Auto" gesetzt. Im Schematic
konnte ich jetzt keine OneHot-Codierung finden. Daher habe ich
"FSM Encoding Algorithm" auf "OneHot" gesetzt ich konnte aber immer noch
keine OneHot-Codierung im Schematic finden. Die "Auto" und "OneHot"
Versionen habe ich getestet (diesmal mit Funktionsgenerator) und auch
diesmal hängt nichts.

Fazit:
An sich war die Gray-Codierung nicht falsch, aber das Synthesetool
hat eine OneHot-Codierung daraus gemacht und die knirscht, weil das 
RESET_IN-Signal dadurch nicht (mehr?) synchronisiert war.

Ich danke Euch, ich war nämlich kurz davor meinen Verstand zu verlieren,
abgesehen davon fallen mir spontan drei Stellen ein, bei denen diese
Art Fehler auch noch dazwischen funkt.

Gruß, Patric

von Achim S. (Gast)


Lesenswert?

bitteschön, und schön dass es jetzt klappt.

> An sich war die Gray-Codierung nicht falsch, aber das Synthesetool
> hat eine OneHot-Codierung daraus gemacht und die knirscht, weil das
> RESET_IN-Signal dadurch nicht (mehr?) synchronisiert war.

Ich würde eher formulieren: das Reset_in ist seiner Natur nach ein 
asynchrones Signal, und du musst erst ein synchrones Signal daraus 
machen.

In der One-hot SM führt das asynchrone Eingangssignal zu Fehlern bis hin 
zum Aufhängen. In deiner Gray-codierten SM, bei der alle Zustände 
genutzt werden, führt das asynchrone Eingangssignal "nur" zu einem 
falschen Durchlaufen der States (der Ausgangspuls kann z.B. mal zu kurz 
oder zu lang werden), aber nicht zum Aufhängen der SM. Das ist zwar 
schon mal eine Verbesserung, und bei flüchtigem Darübersehen fallen 
verbleibende Fehler vielleicht nicht mal auf. Aber die richtige Lösung 
besteht allein darin, das Signal einzusynchronisieren.

viele Grüße

Achim S.

von franke (Gast)


Lesenswert?

und ich würde Dir dringend dazu raten deine FSM wie oben beschrieben zu 
definieren und dem Synthesetool die Entscheidung der Codierung zu 
überlassen

>type state_type is (idle, zustand1, zustand2, zustand3);
>signal state : state_type;

da kann man dem state nämlich gleich noch einwenig Info mit geben, wie 
"idle", "reset_active", "wait_for_reset_low" oder ähnlich ;-)

Gruß

von martin (Gast)


Lesenswert?

Kann es ein dass alle INterpretationen falsch waren und
der Code


 state <= "00";
    RESET_OUT <= '0';
    if RESET_IN = '1' then
      state <= "01";
      RESET_OUT <= '1';
    end if;


einfach Mist ist?

Könnte das Problem  des Hängens nicht besser mit



    if RESET_IN = '1' then
      state <= "01";
      RESET_OUT <= '1';
   else
     state <= "00";
      RESET_OUT <= '0';
    end if;


gefixt werden?


Zwei verschiedene Zuweisungen  auf 'state' , welche soll
denn bitteschön gelten?  MIt 'else' eindeutig

von Patric v. (vloewis)


Lesenswert?

@Martin

Soweit ich das verstanden habe wird bei der Synthese
1
    RESET_OUT <= '0';
2
    if RESET_IN = '1' then
3
      state <= "01";
4
      RESET_OUT <= '1';
5
    end if;
Der Anweisungsblock von oben nach unten interpretiert und der letzte
Zustand "gilt". Das macht den Code lesbarer, weil man oben quasi
erstmal den Default-Zustand definieren kann und unten auf die
Einzelfälle eingehen kann.
In einem meiner Bücher wurde das als guter Stil propagiert.

von Duke Scarring (Gast)


Lesenswert?

martin schrieb:
> Zwei verschiedene Zuweisungen  auf 'state' , welche soll
> denn bitteschön gelten?
Solange wie die bei VHDL im Prozess stehen, gewinnt die letzte 
Zuweisung.

> MIt 'else' eindeutig
Ja, aber: Es wird gern vergessen alle Signale, die ein Prozess treibt, 
in jedem möglichen Zweig zu setzten (zumindest bei komplexeren Sachen). 
Daher ist es nicht verkehrt erstmal allen Signalen einen default-Wert 
zuzuweisen und den dann ggf. zu "überschreiben".

Duke

von Patric v. (vloewis)


Lesenswert?

@Achim S.

Spontan hätte ich ja gesagt, dass, da beim Gray-Code ja immer nur ein
Bit kippt alles in Ordnung sein sollte, aber nach längerem Meditieren
kommen mir Zweifel.

Ich habe dass jetzt noch mal mit Funktionsgenerator, "None",
Gray-Codierung und ohne Synchronisierung durchlaufen lassen, mit Oszi
auf Nachleuchten unendlich und siehe da: manche Impulse sind nur 20ns
lang. Also es scheint ein "Durchrutschen" von "00" auf "11" zu geben.
Ich ziehe mein Fazit zurück :( War zugegebenermassen nur ein Versuch
wenigstens ein wenig Recht zu haben ;)
ABER meine Gray-Version würde wenigstens nicht hängenbleiben (jaja
ich weiss unsauber ist unsauber).

@martin (Gast)
Lesbarkeit ist immer gut. Würde denn eine solche Codierung auch
hängenbleiben können? Die bit_vector[2]-Gray-Version hat ja durch
die Synthese als OneHot zusätzliche "illegale" States erzeugt, die sich
mit when others nicht abfangen liessen, weil es semantisch vollständig
auscodiert war.

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


Lesenswert?

martin schrieb:
> Zwei verschiedene Zuweisungen  auf 'state' , welche soll
> denn bitteschön gelten?
Wie üblich beim Prozess: die letzte Zuweisung an ein Signal gewinnt...
Der "Zwischenzustand" existiert in diesm Fall gar nicht. Nehmen wir mal 
diese (etwas unsinnige und umständliche) Beschreibung:
1
process (clk) begin
2
   if rising_edge(clk) then
3
       Ausgang <= '0';
4
       if Eingang='1' then
5
          Ausgang <= '1';
6
       end if;
7
   end if;
8
end process;
Frage:
Was macht bei einer Taktflanke der Ausgang, wenn der Eingang '1' ist?
Antwort:
Der Ausgang ist fest auf '1'. Da gibt es keine auch noch so kurzen 
Spikes nach '0', obwohl da eine Defaultzuweisung (Ausgang <= '0') steht.

Patric vL schrieb:
> ABER meine Gray-Version würde wenigstens nicht hängenbleiben (jaja
> ich weiss unsauber ist unsauber).
Glück gehabt, denn du hast alle Zustände verwendet.
Wenn das jetzt aber nicht sowas simples wäre, sondern eine FSM, die z.B. 
einen Getränkeautomaten steuert, dann käme z.B. der Kaffee und dann wäre 
Ende. Oder es käme nur ein Becher, oder kein Pulver...

EDIT:
Zweiter! Duke hatte das mit dem "gewinnen" schon erwähnt... ;-)

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.