Kampis Elektroecke

Entwurf eines Zustandsautomaten

In diesem Artikel zeige ich, wie ein einfacher Zustandsautomat in VHDL designed und implementiert werden kann. Nachdem die Schaltung entworfen wurde, wird sie in einer Testbench getestet und anschließend in ein FPGA exportiert.

Die zu entwerfende Schaltung soll sich gemäß dem dargestellten Zustandsdiagramms verhalten:

Nach einem Reset soll sich der Zustandsautomat automatisch im Zustand S0 befinden. Dieser Zustand wird so lange beibehalten, bis das Eingangssignal 012 anliegt. Liegt das Signal an, so wechselt der Zustandsautomat in den Zustand S1 und verbleibt dort so lange bis die nächste Übergangsbedingung erfüllt ist.

In dem Top-File des Zustandsautomaten definiere ich einen Typen namens State_Type und lege mit ihm fest wie viele Zustände mein Zustandsautomat besitzen soll:

type State_Type is (S0, S1, S2, S3);

Da der Zustandsautomat bis vier zählen soll, werden dem entsprechend vier verschiedene Zustände benötigt, wobei jeder Zustand einen Wert anzeigt. Anschließend erzeuge ich eine weitere Variable vom Typ State_Type, welche nachher den aktuellen Zustand des Zustandsautomaten beinhalten soll:

signal CurrentState : State_Type := S0;

Diese Variable wird außerdem direkt mit dem Startwert S0, sprich dem ersten Zustand, initialisiert.

Über eine Select-Case Abfrage wird der Ausgang bei jeder steigenden Taktflanke abhängig vom aktuellen Zustand und entsprechend der Definition geschaltet. Anschließend wechselt der Zustandsautomat in den nächsten Zustand.

process(Clock)
begin
    if(rising_edge(Clock)) then
        case CurrentState is
            when S0 =>  
                O <= "10";

                if(E = "01") then
                    CurrentState <= S1;
                else
                    CurrentState <= S0;
                end if;
            when S1 => 
                O <= "00";

                if(E = "10") then
                    CurrentState <= S2;
                else
                    CurrentState <= S1;
                end if;
            when S2 => 
                O <= "11";

                if(E = "11") then
                    CurrentState <= S3;
                else
                    CurrentState <= S2;
                end if;
            when S3 => 
                O <= "01";

                if(E = "00") then
                    CurrentState <= S0;
                else
                    CurrentState <= S3;
                end if;        
        end case;
    end if;
end process;

Die fertige Schaltung kann man am besten im Simulator testen. Bevor der Test aber losgeht muss eine Testbench erstellt werden, die das Testszenario für die Schaltung festlegt. Dazu wird als aller erstes dem Projekt eine neue Simulation Source hinzugefügt.

Das Schreiben der Testbench geschieht ebenfalls in VHDL. Dazu wird als erstes mit der Zeile

constant CLOCKPERIODE : TIME := 1 ms;

die Takfrequenz für das simulierte Taktsignal festgelegt. Im nächsten Schritt kann dann mit einem einzelnen Prozess der Systemtakt für die Simulation generiert werden:

process begin
    wait for (CLOCKPERIODE / 2);
    SimulationClock <= '1';
    wait for (CLOCKPERIODE / 2);
    SimulationClock <= '0';
end process;

Anschließend wird die zu testende Schaltung instantiiert:

architecture Top_TB_Arch of Top_TB is
    constant CLOCKPERIODE : TIME := 1 ms;

    signal SimulationClock  : STD_LOGIC := '0';
    signal E                : STD_LOGIC_VECTOR(1 downto 0) := (others => '0');
    signal O                : STD_LOGIC_VECTOR(1 downto 0) := (others => '0');

    component Top
        Port (  Clock   : in STD_LOGIC;
                E       : in STD_LOGIC_VECTOR(1 downto 0);
                O       : out STD_LOGIC_VECTOR(1 downto 0)
                );
    end component;

begin

    process begin
        wait for (CLOCKPERIODE / 2);
        SimulationClock <= '1';
        wait for (CLOCKPERIODE / 2);
        SimulationClock <= '0';
    end process;

    UUT: Top port map(  Clock => SimulationClock, 
                        E => E,
                        O => O
                        );

end Top_TB_Arch;

In dem Testszenario werden der Reihe nach alle Kombinationen des Eingangssignals an die Schaltung angelegt um das Verhalten analysieren zu können.

process begin
    E <= "01";
    wait for 50 ms;

    E <= "10";
    wait for 50 ms;

    E <= "11";
    wait for 50 ms;

    E <= "00";
    wait for 50 ms;
end process;

Damit wäre die Testbench komplett und die Simulation kann gestartet werden. Je nach Leistung des Rechners dauert die Simulation unterschiedlich lange (bei mir dauert sie z. B. gute 2 Minuten).

Anhand dieser Simulation können die Eingangs- und Ausgangszustände mit dem Soll verglichen werden um zu verifizieren ob die Schaltung korrekt arbeitet. 

Der Code für den Zustandsautomaten kann in meinem GitHub-Repository heruntergeladen werden.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert