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


von Igor (Gast)


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:
1
Signal naechster_zustand: STATE_TYPE;
2
Signal aktueller_zustand: STATE_TYPE:=Schlafen;
3
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); 
4
5
ZUSTAND_WEITERGEBEN:process (FLASH_CLK)
6
    begin
7
      if FLASH_RESET = '1' then
8
        aktueller_zustand<=Schlafen;--Grundzustand;
9
      elsif rising_edge(Flash_CLK) then
10
        aktueller_zustand <= naechster_zustand;
11
      end if;
12
  end process ZUSTAND_WEITERGEBEN;  
13
14
  Zustandsautomat:process (aktueller_zustand,ADD_VOLL,FLASH_ENABLE) 
15
  begin
16
  case aktueller_zustand is
17
    -----------------------------------------------------------
18
    when Schlafen       =>  BRAM_ADD_COUNT_ENABLE <='0';                     
19
                    BRAM_WEA        <= "0";  
20
                    BRAM_TAKT_20MHZ  <= '1';                  
21
                    ADD_COUNT_ENABLE   <= '0';       --  DIESER ZUSTAND LÄßT DEN SPEICHER NICHT AUSLESEN
22
                    ADD_ZERO       <= '0';       -- BIS DAS ENABLE SINGAL VOM EINGANG KOMMT, DANN
23
                    BYTE_SCHREIBEN    <= '0';      -- STARTET DER AUTOMAT LOS DEN FLASH SPEICHER AUSZU-
24
                    DATA_ENABLE_HI    <= '0';      -- LESEN
25
                    DATA_ENABLE_LOW  <= '0';      --
26
                    CE            <=  '0';      --
27
                    OE            <=  '0';      --
28
                    RP            <=  '0';      --        
29
                    if FLASH_ENABLE = '0' then      --
30
                    naechster_zustand <= Schlafen;  --  
31
                    else                    --
32
                    naechster_zustand <=Grundzustand;--
33
                    end if;                  --
34
    -----------------------------------------------------------
35
    when Grundzustand =>          
36
                    ADD_COUNT_ENABLE   <= '0';       --  HIER STARTET DER ZUSTANDSAUTOMAT WENN ER ZUM ERSTEN MAL 
37
                    ADD_ZERO       <= '1';        -- GESTARTET WIRD ODER WENN DIE FLASH ADDRESSE VOLL GELAUFEN
38
                    BRAM_ADD_COUNT_ENABLE <='0';                     
39
                    BRAM_WEA        <= "0";
40
                    BRAM_TAKT_20MHZ  <= '1';
41
                    if ADD_VOLL='1' then          -- IST. HIER WIRD DIE FALSH ADDRESSE WIEDER AUF NULL ZURÜCK-
42
                      BYTE_SCHREIBEN    <= '1';      -- GESETZT ODER FÄNGT MIT DER NULL AN.
43
                    else                    -- AUßERDEM WIRD HIER DURCH BYTE SCHREIBEN DATEN AUSGE-
44
                      BYTE_SCHREIBEN    <= '0';      -- GEBEN WENN 
45
                    end if;                  --
46
                    DATA_ENABLE_HI    <= '0';      -- 
47
                    DATA_ENABLE_LOW  <= '0';      --
48
                    CE            <=  '1';      --
49
                    OE            <=  '1';      --
50
                    RP            <=  '1';      --  
51
                    naechster_zustand <= Warten_0;  --
52
    -----------------------------------------------------------    
53
54
-----------------------------------------------------------                                      --  
55
    when Add_Zahlen =>    BRAM_ADD_COUNT_ENABLE <='0';                     
56
                    BRAM_WEA        <= "1";
57
                    BRAM_TAKT_20MHZ  <= '0';
58
                    ADD_COUNT_ENABLE   <= '1';       -- DIESER ZUSTAND ZÄHLT DIE ADDRESSE WEITER DA DIE FLASH    
59
                    ADD_ZERO       <= '0';       -- ADDRESSE NOCH NICHT VOLLGELAUFEN IST. BENÖTIGT WIRD 
60
                    BYTE_SCHREIBEN    <= '1';      -- DIESER ZUSTAND UM DEN CACHE SPEICHER VOM FALSH NEU ZU
61
                    DATA_ENABLE_HI    <= '0';      -- LADEN
62
                    DATA_ENABLE_LOW  <= '0';      --
63
                    CE            <=  '1';      --
64
                    OE            <=  '1';      --
65
                    RP            <=  '1';      --
66
                    naechster_zustand <= Warten_0;  --  
67
    -----------------------------------------------------------
68
69
70
71
72
73
when Warten_0   =>     BRAM_WEA        <= "1";
74
                    BRAM_ADD_COUNT_ENABLE <='1';   
75
                    BRAM_TAKT_20MHZ  <= '1';
76
                    
77
                    ADD_COUNT_ENABLE   <= '0';       
78
                    ADD_ZERO       <= '0';         
79
                    BYTE_SCHREIBEN    <= '0';
80
                    DATA_ENABLE_HI    <= '0';
81
                    DATA_ENABLE_LOW  <= '0';
82
                    CE            <=  '0';
83
                    OE            <=  '0';
84
                    RP            <=  '1';
85
                    naechster_zustand <= Warten_1;
86
87
88
89
90
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

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


Lesenswert?

> Meine Frage wie kann ich mich auf den Vorherigen Zustand beziehen,
Du merkst dir den vorigen Zustand einfach:
1
Signal voriger_zustand: STATE_TYPE;
2
Signal aktueller_zustand: STATE_TYPE:=Schlafen;
3
:
4
ZUSTAND_WEITERGEBEN:process (FLASH_CLK)
5
    begin
6
      if FLASH_RESET = '1' then
7
        aktueller_zustand<=Schlafen;--Grundzustand;
8
      elsif rising_edge(Flash_CLK) then
9
        aktueller_zustand <= naechster_zustand;
10
        voriger_zustand <= aktueller_zustand;
11
      end if;
12
  end process ZUSTAND_WEITERGEBEN;  
13
:

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

von Igor (Gast)


Lesenswert?

Hi,
Danke für den Tipp!! :)

So vielleicht ?
1
-------------------------------- ZUSTANDSAUTOMAT ----------------------------------------------
2
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); 
3
Signal naechster_zustand: STATE_TYPE;
4
Signal aktueller_zustand: STATE_TYPE:=Schlafen;
5
Signal alter_zustand    : STATE_TYPE;  
6
-----------------------------------------------------------------------------------------------
7
begin
8
9
  --------------- ENABLE SIGNALE--------------
10
            
11
  ---------------------------------------------
12
13
  ZUSTAND_WEITERGEBEN:process (FLASH_CLK,FLASH_RESET)
14
    begin
15
      if FLASH_RESET = '1' then
16
        aktueller_zustand<=Schlafen;--Grundzustand;
17
      elsif rising_edge(Flash_CLK) then
18
        aktueller_zustand <= naechster_zustand;
19
        alter_zustand  <= aktueller_zustand;
20
      end if;
21
  end process ZUSTAND_WEITERGEBEN;  
22
  ---------------------------------------------
23
  
24
  Zustandsautomat:process (aktueller_zustand,ADD_VOLL,FLASH_ENABLE,alter_zustand) 
25
  begin
26
  case aktueller_zustand is
27
    -----------------------------------------------------------
28
    when Schlafen       =>  BRAM_ADD_COUNT_ENABLE <='0';                     
29
                    BRAM_WEA        <= "0";  
30
                    BRAM_TAKT_20MHZ  <= '0';                  
31
                    ADD_COUNT_ENABLE   <= '0';       --  DIESER ZUSTAND LÄßT DEN SPEICHER NICHT AUSLESEN
32
                    ADD_ZERO       <= '0';       -- BIS DAS ENABLE SINGAL VOM EINGANG KOMMT, DANN
33
                    BYTE_SCHREIBEN    <= '0';      -- STARTET DER AUTOMAT LOS DEN FLASH SPEICHER AUSZU-
34
                    DATA_ENABLE_HI    <= '0';      -- LESEN
35
                    DATA_ENABLE_LOW  <= '0';      --
36
                    CE            <=  '0';      --
37
                    OE            <=  '0';      --
38
                    RP            <=  '0';      --        
39
                    if FLASH_ENABLE = '0' then      --
40
                    naechster_zustand <= Schlafen;  --  
41
                    else                    --
42
                    naechster_zustand <=Grundzustand;--
43
                    end if;                  --
44
    -----------------------------------------------------------
45
    when Grundzustand =>          
46
                    ADD_COUNT_ENABLE   <= '0';       --  HIER STARTET DER ZUSTANDSAUTOMAT WENN ER ZUM ERSTEN MAL 
47
                    ADD_ZERO       <= '1';        -- GESTARTET WIRD ODER WENN DIE FLASH ADDRESSE VOLL GELAUFEN
48
                    BRAM_ADD_COUNT_ENABLE <='0';                     
49
                    BRAM_WEA        <= "0";
50
                    BRAM_TAKT_20MHZ  <= '0';
51
                    if ADD_VOLL='1' then          -- IST. HIER WIRD DIE FALSH ADDRESSE WIEDER AUF NULL ZURÜCK-
52
                      BYTE_SCHREIBEN    <= '1';      -- GESETZT ODER FÄNGT MIT DER NULL AN.
53
                    else                    -- AUßERDEM WIRD HIER DURCH BYTE SCHREIBEN DATEN AUSGE-
54
                      BYTE_SCHREIBEN    <= '0';      -- GEBEN WENN 
55
                    end if;                  --
56
                    DATA_ENABLE_HI    <= '0';      -- 
57
                    DATA_ENABLE_LOW  <= '0';      --
58
                    CE            <=  '1';      --
59
                    OE            <=  '1';      --
60
                    RP            <=  '1';      --  
61
                    naechster_zustand <= Warten_0;  --
62
    -----------------------------------------------------------                                      --  
63
    when Add_Zahlen =>    BRAM_ADD_COUNT_ENABLE <='0';                     
64
                    BRAM_WEA        <= "1";
65
                    BRAM_TAKT_20MHZ  <= '1';
66
                    ADD_COUNT_ENABLE   <= '1';       -- DIESER ZUSTAND ZÄHLT DIE ADDRESSE WEITER DA DIE FLASH    
67
                    ADD_ZERO       <= '0';       -- ADDRESSE NOCH NICHT VOLLGELAUFEN IST. BENÖTIGT WIRD 
68
                    BYTE_SCHREIBEN    <= '1';      -- DIESER ZUSTAND UM DEN CACHE SPEICHER VOM FALSH NEU ZU
69
                    DATA_ENABLE_HI    <= '0';      -- LADEN
70
                    DATA_ENABLE_LOW  <= '0';      --
71
                    CE            <=  '1';      --
72
                    OE            <=  '1';      --
73
                    RP            <=  '1';      --
74
                    naechster_zustand <= Warten_0;  --  
75
    -----------------------------------------------------------
76
    
77
    when Warten_0   =>     if alter_zustand = Grundzustand then
78
                      BRAM_WEA        <= "0";
79
                      BRAM_ADD_COUNT_ENABLE <='0';
80
                      BRAM_TAKT_20MHZ  <= '1';
81
                    else
82
                      BRAM_WEA        <= "1";
83
                      BRAM_ADD_COUNT_ENABLE <='1';
84
                      BRAM_TAKT_20MHZ  <= '0';
85
                    end if;
86
                    
87
                    
88
                    ADD_COUNT_ENABLE   <= '0';       
89
                    ADD_ZERO       <= '0';         
90
                    BYTE_SCHREIBEN    <= '0';
91
                    DATA_ENABLE_HI    <= '0';
92
                    DATA_ENABLE_LOW  <= '0';
93
                    CE            <=  '0';
94
                    OE            <=  '0';
95
                    RP            <=  '1';
96
                    naechster_zustand <= Warten_1;

von Klaus F. (kfalser)


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.
1
ZUSTAND_WEITERGEBEN:process (FLASH_CLK,FLASH_RESET)
2
    begin
3
      if FLASH_RESET = '1' then
4
        aktueller_zustand<=Schlafen;--Grundzustand;
5
      elsif rising_edge(Flash_CLK) then
6
        aktueller_zustand <= naechster_zustand;
7
        case naechster_zustand is 
8
        when Grundzustand =>          
9
            BRAM_ADD_COUNT_ENABLE <='0';                     
10
            BRAM_WEA        <= "0";
11
            BRAM_TAKT_20MHZ  <= '0';
12
13
        when Warten_0   =>     
14
            if aktueller_zustand = Grundzustand then
15
               BRAM_WEA        <= "0";
16
               BRAM_ADD_COUNT_ENABLE <='0';
17
               BRAM_TAKT_20MHZ  <= '1';
18
            else
19
               BRAM_WEA        <= "1";
20
               BRAM_ADD_COUNT_ENABLE <='1';
21
               BRAM_TAKT_20MHZ  <= '0';
22
            end if;
23
         end case;
24
      end if;
25
  end process ZUSTAND_WEITERGEBEN;

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


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-oder-Zwei-Prozess-Schreibweise-fuer-FSM.html
Die hat auch noch andere Vorteile gegenüber der 2- oder gar 
3-Prozess-Schreibweise ;-)

von Klaus F. (kfalser)


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 ;-)

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


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 ;-)

von Igor (Gast)


Lesenswert?

puh... mein Kopf raucht... :)


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



Gruß

Igor

von Matthias G. (mgottke)


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.

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


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

von berndl (Gast)


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

von Matthias G. (mgottke)


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:
1
type state_t is (s_idle, s_work_irgendwas, s_read_ram_data, ...);
2
-- FMS geht die States in dem Beispiel nacheinander durch
3
4
-- Adressbildung bei 1-Prozess-Darstellung
5
build_ram_adress : process (current_state)
6
begin
7
   case current_state is
8
      ...
9
      s_work_irgendwas => ram_adress <= const_ram_adress; -- kein Bezug mehr zum Zustand s_read_ram_data erkennbar
10
      ...
11
   end case;
12
end process; 
13
14
-- Adressbildung bei 2-Prozess-Darstellung
15
build_ram_adress : process (next_state)
16
begin
17
   case next_state is
18
      ...
19
      s_read_ram_data => ram_adress <= const_ram_adress; -- da verstehe ich auch nach einem halben Jahr noch den Zusammenhang
20
      ...
21
   end case;
22
end process;

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.