mikrocontroller.net

Forum: FPGA, VHDL & Co. Zustandsautomat,vorherriger Zustand


Autor: Igor (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich habe eine Verständnissfrage und hoffe das mir die jemand beantworten 
könnte. Ich habe ein Flashscontroller geschrieben der auch funzt, wollte 
es jetzt erweitern und bin auf ein Problem gestoßen.

Ich habe einen Zustandsautomat hier ein Ausschnitt:
Signal naechster_zustand: STATE_TYPE;
Signal aktueller_zustand: STATE_TYPE:=Schlafen;
type STATE_TYPE is (Grundzustand,Add_Zahlen,Warten_0,Warten_1,Warten_2,Lesen_0,Anlegen_1,Lesen_1,Anlegen_2,Lesen_2,Anlegen_3,Lesen_3,Anlegen_4,Lesen_4,Anlegen_5,Lesen_5,Anlegen_6,Lesen_6,Anlegen_7,Lesen_7,Schlafen); 

ZUSTAND_WEITERGEBEN:process (FLASH_CLK)
    begin
      if FLASH_RESET = '1' then
        aktueller_zustand<=Schlafen;--Grundzustand;
      elsif rising_edge(Flash_CLK) then
        aktueller_zustand <= naechster_zustand;
      end if;
  end process ZUSTAND_WEITERGEBEN;  

  Zustandsautomat:process (aktueller_zustand,ADD_VOLL,FLASH_ENABLE) 
  begin
  case aktueller_zustand is
    -----------------------------------------------------------
    when Schlafen       =>  BRAM_ADD_COUNT_ENABLE <='0';                     
                    BRAM_WEA        <= "0";  
                    BRAM_TAKT_20MHZ  <= '1';                  
                    ADD_COUNT_ENABLE   <= '0';       --  DIESER ZUSTAND LÄßT DEN SPEICHER NICHT AUSLESEN
                    ADD_ZERO       <= '0';       -- BIS DAS ENABLE SINGAL VOM EINGANG KOMMT, DANN
                    BYTE_SCHREIBEN    <= '0';      -- STARTET DER AUTOMAT LOS DEN FLASH SPEICHER AUSZU-
                    DATA_ENABLE_HI    <= '0';      -- LESEN
                    DATA_ENABLE_LOW  <= '0';      --
                    CE            <=  '0';      --
                    OE            <=  '0';      --
                    RP            <=  '0';      --        
                    if FLASH_ENABLE = '0' then      --
                    naechster_zustand <= Schlafen;  --  
                    else                    --
                    naechster_zustand <=Grundzustand;--
                    end if;                  --
    -----------------------------------------------------------
    when Grundzustand =>          
                    ADD_COUNT_ENABLE   <= '0';       --  HIER STARTET DER ZUSTANDSAUTOMAT WENN ER ZUM ERSTEN MAL 
                    ADD_ZERO       <= '1';        -- GESTARTET WIRD ODER WENN DIE FLASH ADDRESSE VOLL GELAUFEN
                    BRAM_ADD_COUNT_ENABLE <='0';                     
                    BRAM_WEA        <= "0";
                    BRAM_TAKT_20MHZ  <= '1';
                    if ADD_VOLL='1' then          -- IST. HIER WIRD DIE FALSH ADDRESSE WIEDER AUF NULL ZURÜCK-
                      BYTE_SCHREIBEN    <= '1';      -- GESETZT ODER FÄNGT MIT DER NULL AN.
                    else                    -- AUßERDEM WIRD HIER DURCH BYTE SCHREIBEN DATEN AUSGE-
                      BYTE_SCHREIBEN    <= '0';      -- GEBEN WENN 
                    end if;                  --
                    DATA_ENABLE_HI    <= '0';      -- 
                    DATA_ENABLE_LOW  <= '0';      --
                    CE            <=  '1';      --
                    OE            <=  '1';      --
                    RP            <=  '1';      --  
                    naechster_zustand <= Warten_0;  --
    -----------------------------------------------------------    

-----------------------------------------------------------                                      --  
    when Add_Zahlen =>    BRAM_ADD_COUNT_ENABLE <='0';                     
                    BRAM_WEA        <= "1";
                    BRAM_TAKT_20MHZ  <= '0';
                    ADD_COUNT_ENABLE   <= '1';       -- DIESER ZUSTAND ZÄHLT DIE ADDRESSE WEITER DA DIE FLASH    
                    ADD_ZERO       <= '0';       -- ADDRESSE NOCH NICHT VOLLGELAUFEN IST. BENÖTIGT WIRD 
                    BYTE_SCHREIBEN    <= '1';      -- DIESER ZUSTAND UM DEN CACHE SPEICHER VOM FALSH NEU ZU
                    DATA_ENABLE_HI    <= '0';      -- LADEN
                    DATA_ENABLE_LOW  <= '0';      --
                    CE            <=  '1';      --
                    OE            <=  '1';      --
                    RP            <=  '1';      --
                    naechster_zustand <= Warten_0;  --  
    -----------------------------------------------------------





when Warten_0   =>     BRAM_WEA        <= "1";
                    BRAM_ADD_COUNT_ENABLE <='1';   
                    BRAM_TAKT_20MHZ  <= '1';
                    
                    ADD_COUNT_ENABLE   <= '0';       
                    ADD_ZERO       <= '0';         
                    BYTE_SCHREIBEN    <= '0';
                    DATA_ENABLE_HI    <= '0';
                    DATA_ENABLE_LOW  <= '0';
                    CE            <=  '0';
                    OE            <=  '0';
                    RP            <=  '1';
                    naechster_zustand <= Warten_1;




usw.....................................



Meine Frage wie kann ich mich auf den Vorherigen Zustand beziehen, bzw. 
was müsste ich tun um im Zustand Warten_0 zu schauen ob ich vom 
Grundzustand oder vom Add_Zahlen Zustand gekommen bin?



Gruß

Igor

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

Bewertung
0 lesenswert
nicht lesenswert
> Meine Frage wie kann ich mich auf den Vorherigen Zustand beziehen,
Du merkst dir den vorigen Zustand einfach:
Signal voriger_zustand: STATE_TYPE;
Signal aktueller_zustand: STATE_TYPE:=Schlafen;
:
ZUSTAND_WEITERGEBEN:process (FLASH_CLK)
    begin
      if FLASH_RESET = '1' then
        aktueller_zustand<=Schlafen;--Grundzustand;
      elsif rising_edge(Flash_CLK) then
        aktueller_zustand <= naechster_zustand;
        voriger_zustand <= aktueller_zustand;
      end if;
  end process ZUSTAND_WEITERGEBEN;  
:

Und dann noch das Übliche: deine Simulation ist falsch, weil die 
Sensitivliste unvollständig ist.
ZUSTAND_WEITERGEBEN:process (FLASH_CLK) -- hier fehlt FLASH_RESET
    begin
      if FLASH_RESET = '1' then

Autor: Igor (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,
Danke für den Tipp!! :)

So vielleicht ?

-------------------------------- ZUSTANDSAUTOMAT ----------------------------------------------
type STATE_TYPE is (Grundzustand,Add_Zahlen,Warten_0,Warten_1,Warten_2,Lesen_0,Anlegen_1,Lesen_1,Anlegen_2,Lesen_2,Anlegen_3,Lesen_3,Anlegen_4,Lesen_4,Anlegen_5,Lesen_5,Anlegen_6,Lesen_6,Anlegen_7,Lesen_7,Schlafen); 
Signal naechster_zustand: STATE_TYPE;
Signal aktueller_zustand: STATE_TYPE:=Schlafen;
Signal alter_zustand    : STATE_TYPE;  
-----------------------------------------------------------------------------------------------
begin

  --------------- ENABLE SIGNALE--------------
            
  ---------------------------------------------

  ZUSTAND_WEITERGEBEN:process (FLASH_CLK,FLASH_RESET)
    begin
      if FLASH_RESET = '1' then
        aktueller_zustand<=Schlafen;--Grundzustand;
      elsif rising_edge(Flash_CLK) then
        aktueller_zustand <= naechster_zustand;
        alter_zustand  <= aktueller_zustand;
      end if;
  end process ZUSTAND_WEITERGEBEN;  
  ---------------------------------------------
  
  Zustandsautomat:process (aktueller_zustand,ADD_VOLL,FLASH_ENABLE,alter_zustand) 
  begin
  case aktueller_zustand is
    -----------------------------------------------------------
    when Schlafen       =>  BRAM_ADD_COUNT_ENABLE <='0';                     
                    BRAM_WEA        <= "0";  
                    BRAM_TAKT_20MHZ  <= '0';                  
                    ADD_COUNT_ENABLE   <= '0';       --  DIESER ZUSTAND LÄßT DEN SPEICHER NICHT AUSLESEN
                    ADD_ZERO       <= '0';       -- BIS DAS ENABLE SINGAL VOM EINGANG KOMMT, DANN
                    BYTE_SCHREIBEN    <= '0';      -- STARTET DER AUTOMAT LOS DEN FLASH SPEICHER AUSZU-
                    DATA_ENABLE_HI    <= '0';      -- LESEN
                    DATA_ENABLE_LOW  <= '0';      --
                    CE            <=  '0';      --
                    OE            <=  '0';      --
                    RP            <=  '0';      --        
                    if FLASH_ENABLE = '0' then      --
                    naechster_zustand <= Schlafen;  --  
                    else                    --
                    naechster_zustand <=Grundzustand;--
                    end if;                  --
    -----------------------------------------------------------
    when Grundzustand =>          
                    ADD_COUNT_ENABLE   <= '0';       --  HIER STARTET DER ZUSTANDSAUTOMAT WENN ER ZUM ERSTEN MAL 
                    ADD_ZERO       <= '1';        -- GESTARTET WIRD ODER WENN DIE FLASH ADDRESSE VOLL GELAUFEN
                    BRAM_ADD_COUNT_ENABLE <='0';                     
                    BRAM_WEA        <= "0";
                    BRAM_TAKT_20MHZ  <= '0';
                    if ADD_VOLL='1' then          -- IST. HIER WIRD DIE FALSH ADDRESSE WIEDER AUF NULL ZURÜCK-
                      BYTE_SCHREIBEN    <= '1';      -- GESETZT ODER FÄNGT MIT DER NULL AN.
                    else                    -- AUßERDEM WIRD HIER DURCH BYTE SCHREIBEN DATEN AUSGE-
                      BYTE_SCHREIBEN    <= '0';      -- GEBEN WENN 
                    end if;                  --
                    DATA_ENABLE_HI    <= '0';      -- 
                    DATA_ENABLE_LOW  <= '0';      --
                    CE            <=  '1';      --
                    OE            <=  '1';      --
                    RP            <=  '1';      --  
                    naechster_zustand <= Warten_0;  --
    -----------------------------------------------------------                                      --  
    when Add_Zahlen =>    BRAM_ADD_COUNT_ENABLE <='0';                     
                    BRAM_WEA        <= "1";
                    BRAM_TAKT_20MHZ  <= '1';
                    ADD_COUNT_ENABLE   <= '1';       -- DIESER ZUSTAND ZÄHLT DIE ADDRESSE WEITER DA DIE FLASH    
                    ADD_ZERO       <= '0';       -- ADDRESSE NOCH NICHT VOLLGELAUFEN IST. BENÖTIGT WIRD 
                    BYTE_SCHREIBEN    <= '1';      -- DIESER ZUSTAND UM DEN CACHE SPEICHER VOM FALSH NEU ZU
                    DATA_ENABLE_HI    <= '0';      -- LADEN
                    DATA_ENABLE_LOW  <= '0';      --
                    CE            <=  '1';      --
                    OE            <=  '1';      --
                    RP            <=  '1';      --
                    naechster_zustand <= Warten_0;  --  
    -----------------------------------------------------------
    
    when Warten_0   =>     if alter_zustand = Grundzustand then
                      BRAM_WEA        <= "0";
                      BRAM_ADD_COUNT_ENABLE <='0';
                      BRAM_TAKT_20MHZ  <= '1';
                    else
                      BRAM_WEA        <= "1";
                      BRAM_ADD_COUNT_ENABLE <='1';
                      BRAM_TAKT_20MHZ  <= '0';
                    end if;
                    
                    
                    ADD_COUNT_ENABLE   <= '0';       
                    ADD_ZERO       <= '0';         
                    BYTE_SCHREIBEN    <= '0';
                    DATA_ENABLE_HI    <= '0';
                    DATA_ENABLE_LOW  <= '0';
                    CE            <=  '0';
                    OE            <=  '0';
                    RP            <=  '1';
                    naechster_zustand <= Warten_1;


Autor: Klaus Falser (kfalser)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bei deiner FSM werden die Ausgangssignale Kombinatorisch erzeugt.
Das kann Glitsches geben, was eventuell stört wenn die Signale nach 
außen gehen.

Du kannst die Signale auch in den getakteten Prozess hineinziehen, dann 
fällt auch das Zwischensignal mit dem alten Zustand weg.
ZUSTAND_WEITERGEBEN:process (FLASH_CLK,FLASH_RESET)
    begin
      if FLASH_RESET = '1' then
        aktueller_zustand<=Schlafen;--Grundzustand;
      elsif rising_edge(Flash_CLK) then
        aktueller_zustand <= naechster_zustand;
        case naechster_zustand is 
        when Grundzustand =>          
            BRAM_ADD_COUNT_ENABLE <='0';                     
            BRAM_WEA        <= "0";
            BRAM_TAKT_20MHZ  <= '0';

        when Warten_0   =>     
            if aktueller_zustand = Grundzustand then
               BRAM_WEA        <= "0";
               BRAM_ADD_COUNT_ENABLE <='0';
               BRAM_TAKT_20MHZ  <= '1';
            else
               BRAM_WEA        <= "1";
               BRAM_ADD_COUNT_ENABLE <='1';
               BRAM_TAKT_20MHZ  <= '0';
            end if;
         end case;
      end if;
  end process ZUSTAND_WEITERGEBEN;  

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

Bewertung
0 lesenswert
nicht lesenswert
Klaus Falser schrieb:
> Du kannst die Signale auch in den getakteten Prozess hineinziehen
Der logische nächste Schritt wäre dann die 1-Prozess-Schreibweise:
http://www.lothar-miller.de/s9y/archives/43-Ein-od...
Die hat auch noch andere Vorteile gegenüber der 2- oder gar 
3-Prozess-Schreibweise ;-)

Autor: Klaus Falser (kfalser)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Lothar Miller schrieb:
> Der logische nächste Schritt wäre dann die 1-Prozess-Schreibweise
> ..
> Die hat auch noch andere Vorteile gegenüber der 2- oder gar
> 3-Prozess-Schreibweise ;-)
.. und den Nachteil, dass die Ausgangssignale zum State jeweils 1 Takt 
verzögert sind ;-)

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

Bewertung
0 lesenswert
nicht lesenswert
> .. und den Nachteil, dass die Ausgangssignale zum State jeweils 1 Takt
> verzögert sind ;-)
Naja, das was in der SM auscodiert ist, wird vor dem Takt ausgewertet 
und mit der Taktflanke aktualisiert (wie bei FFs halt so üblich). So 
kommt ein 2-Prozess-Denker natürlich schlagartig an 1 Takt Latency...

> .. und den Nachteil, dass die Ausgangssignale zum State jeweils 1 Takt
> verzögert sind ;-)
Dafür aber garantiert glitchfrei ;-)

Autor: Igor (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
puh... mein Kopf raucht... :)


Danke euch, funktioniert aber trotzdem und in gibt auch keine Probleme.



Gruß

Igor

Autor: Matthias G. (mgottke)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Lothar Miller

Die 2-Prozess-Schreibweise hat aber noch einen anderen Vorteil. Man kann 
den Next_State nutzen um z.B. RAM-Blöcke zu adressieren. So kann man 
schon im nächsten Schritt auf dessen Daten zugreifen ohne einen 
Wartetakt zu benötigen. Das beschleunigt das ganze in zeitkritischen 
Applikationen.

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

Bewertung
0 lesenswert
nicht lesenswert
> So kann man schon im nächsten Schritt auf dessen Daten zugreifen
> ohne einen Wartetakt zu benötigen.
Für mich wird andersrum ein Schuh draus: In der 1 Prozess-Schreibweise 
bereite ich schon bei der Zustandstransition (also genau eine Taktflanke 
früher) die Adresse vor.

> Das beschleunigt das ganze in zeitkritischen Applikationen.
Wenn ich 3 Taktzyklen Zeit habe, um etwas zu tun, dann sind das 3 Takte, 
ob ichs mit 2 oder 1 Prozess beschreibe...

Ich bin kein Gegner der 2-Pozess-Schreibweise, mir fällt nur die 
1-Prozess-Darstellung leichter... ;-)

Autor: berndl (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mir faellt eigentlich immer nur ein Fall ein, in dem die 
Mehrprozessschreibweise Vorteile hat:

- Deine FSM Ablaufsteuerung ist relativ einfach, aber die notwendige HW 
pro State ist recht kompliziert oder komplex. Ein eigener Prozess kann 
dann die komplizierte oder komplexe Logik etwas 'entwirren' und 
verstaendlicher machen.

Beispiel: Eine FSM die mehr oder weniger geradeaus laeuft, aber z.B. 
viele verschiedene Opcodes bzw. Funktionen hat. Dann kann es manchmal 
sehr angenehm sein, wenn du die eigentliche Logik auf eine 
Bildschirmseite bringst. Auch wenn du dafuer z.B. Decoder mehrfach 
hinschreiben musst. Die Mehrfachdekoder werden i.A. sowieso 
rausoptimiert, also kein Problem mit der Laufzeit. Aber bei Aenderungen 
bist du halt immer an mehreren Stellen im Code unterwegs. Und da 
vergisst man bei komplexeren Sachen gerne mal eine Stelle... Und ja, man 
kann bei solchen verschachtelten Sachen auch in 1-Prozess Schreibweise 
durch umschreiben (andere Reihenfolge der 'case' Statements) eine 
zumindest optische Vereinfachung erreichen. Solange es die Tools 
packen......

Autor: Matthias G. (mgottke)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Ich bin kein Gegner der 2-Pozess-Schreibweise, mir fällt nur die
> 1-Prozess-Darstellung leichter... ;-)
Meist nutze ich die 2-Prozess-Darstellung. Der größte Nachteil dabei ist 
sicherlich alles konsisten zu halten. Vor allem die Sensitivitylist kann 
schon mal sehr unübersichtlich werden und bedarf großer Disziplin in der 
Pflege.

> ... In der 1 Prozess-Schreibweise
> bereite ich schon bei der Zustandstransition (also genau eine Taktflanke
> früher) die Adresse vor.
Keine Frage. Geht wunderbar. Um beim Beispiel zu bleiben: So lange die 
Adressbildung innerhalb des FSM-Prozesses abgehandelt wird, ist das dann 
noch leserlich. Kleine Statemachines sind sicherlich in der 1 
Prozess-Schreibweise übersichtlicher. Sobald aber eine gewisse 
Komplexität überschritten wird und die Adressbildung in einem anderen 
Prozess landet wird es sehr unübersichtlich. Beispiel:
type state_t is (s_idle, s_work_irgendwas, s_read_ram_data, ...);
-- FMS geht die States in dem Beispiel nacheinander durch

-- Adressbildung bei 1-Prozess-Darstellung
build_ram_adress : process (current_state)
begin
   case current_state is
      ...
      s_work_irgendwas => ram_adress <= const_ram_adress; -- kein Bezug mehr zum Zustand s_read_ram_data erkennbar
      ...
   end case;
end process; 

-- Adressbildung bei 2-Prozess-Darstellung
build_ram_adress : process (next_state)
begin
   case next_state is
      ...
      s_read_ram_data => ram_adress <= const_ram_adress; -- da verstehe ich auch nach einem halben Jahr noch den Zusammenhang
      ...
   end case;
end process;  

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.