So erstellen Sie einen endlichen Automaten in VHDL
Ein endlicher Automat (FSM) ist ein Mechanismus, dessen Ausgabe nicht nur vom aktuellen Zustand der Eingabe abhängt, sondern auch von vergangenen Eingabe- und Ausgabewerten.
Wann immer Sie einen zeitabhängigen Algorithmus in VHDL erstellen müssen oder wenn Sie vor dem Problem stehen, ein Computerprogramm in einem FPGA zu implementieren, kann dies normalerweise durch die Verwendung eines FSM gelöst werden.
Zustandsmaschinen in VHDL sind getaktete Prozesse, deren Ausgänge durch den Wert eines Zustandssignals gesteuert werden. Das Zustandssignal dient als interner Speicher dessen, was in der vorherigen Iteration passiert ist.
Dieser Blogpost ist Teil der Reihe Basic VHDL Tutorials.
Beachten Sie die Zustände der Ampeln an dieser Kreuzung:
Die Ampeln haben eine endliche Anzahl von Zuständen, denen wir identifizierbare Namen gegeben haben. Unsere beispielhafte Zustandsmaschine hat keine steuernden Eingaben, die Ausgabe ist der Zustand der Lichter in Nord/Süd- und West/Ost-Richtung. Es ist die verstrichene Zeit und der vorherige Zustand der Ausgänge, der diese Zustandsmaschine vorrückt.
Wir können Zustände in VHDL mit einem Aufzählungstyp darstellen . Dies sind Datentypen wie signed
oder unsigned
, aber anstelle von Ganzzahlen können wir eine benutzerdefinierte Liste möglicher Werte bereitstellen. Wenn Sie einen Blick in das Paket std_logic_1164 werfen, werden Sie tatsächlich feststellen, dass der std_ulogic
Typ ist nichts anderes als ein Aufzählungstyp mit den Werten 'U'
, 'X'
, '0'
, '1'
, 'Z'
, 'W'
, 'L'
, 'H'
, und '-'
als Aufzählungswerte aufgelistet.
Sobald wir unseren Aufzählungstyp haben, können wir ein Signal des neuen Typs deklarieren, das verwendet werden kann, um den aktuellen Zustand des FSM zu verfolgen.
Die Syntax zum Deklarieren eines Signals mit einem Aufzählungstyp in VHDL lautet:type <type_name> is (<state_name1>, <state_name2>, ...);
signal <signal_name> : <type_name>;
Unter Verwendung des Zustandssignals kann der Zustandsautomat dann in einem Prozess mit einer Case-Anweisung implementiert werden. Die Case-Anweisung enthält eine When-Anweisung für jeden der möglichen Zustände, was dazu führt, dass das Programm für jeden Zustand unterschiedliche Pfade einschlägt. Die When-Anweisung kann auch Code enthalten, der in diesem bestimmten Zustand ausgeführt werden soll. Der Status ändert sich dann typischerweise, wenn eine vordefinierte Bedingung erfüllt ist.
Dies ist eine Vorlage für eine Ein-Prozess-Zustandsmaschine:process(Clk) is
begin
if rising_edge(Clk) then
if nRst = '0' then
State <= <reset_state>;
else
case State is
when <state_name> =>
<set_outputs_for_this_state_here>
if <state_change_condition_is_true> then
State <= <next_state_name>;
end if;
...
end case;
end if;
end if;
end process;
Hinweis:
Es gibt mehrere Möglichkeiten, einen FSM in VHDL zu erstellen. Lesen Sie hier mehr über die verschiedenen Stile:
Ein-Prozess- vs. Zwei-Prozess- vs. Drei-Prozess-Zustandsmaschine
Übung
In diesem Video-Tutorial lernen wir, wie man einen endlichen Automaten in VHDL erstellt:
Der endgültige Code für die Zustandsmaschine Testbench :
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity T20_FiniteStateMachineTb is end entity; architecture sim of T20_FiniteStateMachineTb is -- We are using a low clock frequency to speed up the simulation constant ClockFrequencyHz : integer := 100; -- 100 Hz constant ClockPeriod : time := 1000 ms / ClockFrequencyHz; signal Clk : std_logic := '1'; signal nRst : std_logic := '0'; signal NorthRed : std_logic; signal NorthYellow : std_logic; signal NorthGreen : std_logic; signal WestRed : std_logic; signal WestYellow : std_logic; signal WestGreen : std_logic; begin -- The Device Under Test (DUT) i_TrafficLights : entity work.T20_TrafficLights(rtl) generic map(ClockFrequencyHz => ClockFrequencyHz) port map ( Clk => Clk, nRst => nRst, NorthRed => NorthRed, NorthYellow => NorthYellow, NorthGreen => NorthGreen, WestRed => WestRed, WestYellow => WestYellow, WestGreen => WestGreen); -- Process for generating clock Clk <= not Clk after ClockPeriod / 2; -- Testbench sequence process is begin wait until rising_edge(Clk); wait until rising_edge(Clk); -- Take the DUT out of reset nRst <= '1'; wait; end process; end architecture;
Der endgültige Code für das Modul der Zustandsmaschine :
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity T20_TrafficLights is generic(ClockFrequencyHz : integer); port( Clk : in std_logic; nRst : in std_logic; -- Negative reset NorthRed : out std_logic; NorthYellow : out std_logic; NorthGreen : out std_logic; WestRed : out std_logic; WestYellow : out std_logic; WestGreen : out std_logic); end entity; architecture rtl of T20_TrafficLights is -- Enumerated type declaration and state signal declaration type t_State is (NorthNext, StartNorth, North, StopNorth, WestNext, StartWest, West, StopWest); signal State : t_State; -- Counter for counting clock periods, 1 minute max signal Counter : integer range 0 to ClockFrequencyHz * 60; begin process(Clk) is begin if rising_edge(Clk) then if nRst = '0' then -- Reset values State <= NorthNext; Counter <= 0; NorthRed <= '1'; NorthYellow <= '0'; NorthGreen <= '0'; WestRed <= '1'; WestYellow <= '0'; WestGreen <= '0'; else -- Default values NorthRed <= '0'; NorthYellow <= '0'; NorthGreen <= '0'; WestRed <= '0'; WestYellow <= '0'; WestGreen <= '0'; Counter <= Counter + 1; case State is -- Red in all directions when NorthNext => NorthRed <= '1'; WestRed <= '1'; -- If 5 seconds have passed if Counter = ClockFrequencyHz * 5 -1 then Counter <= 0; State <= StartNorth; end if; -- Red and yellow in north/south direction when StartNorth => NorthRed <= '1'; NorthYellow <= '1'; WestRed <= '1'; -- If 5 seconds have passed if Counter = ClockFrequencyHz * 5 -1 then Counter <= 0; State <= North; end if; -- Green in north/south direction when North => NorthGreen <= '1'; WestRed <= '1'; -- If 1 minute has passed if Counter = ClockFrequencyHz * 60 -1 then Counter <= 0; State <= StopNorth; end if; -- Yellow in north/south direction when StopNorth => NorthYellow <= '1'; WestRed <= '1'; -- If 5 seconds have passed if Counter = ClockFrequencyHz * 5 -1 then Counter <= 0; State <= WestNext; end if; -- Red in all directions when WestNext => NorthRed <= '1'; WestRed <= '1'; -- If 5 seconds have passed if Counter = ClockFrequencyHz * 5 -1 then Counter <= 0; State <= StartWest; end if; -- Red and yellow in west/east direction when StartWest => NorthRed <= '1'; WestRed <= '1'; WestYellow <= '1'; -- If 5 seconds have passed if Counter = ClockFrequencyHz * 5 -1 then Counter <= 0; State <= West; end if; -- Green in west/east direction when West => NorthRed <= '1'; WestGreen <= '1'; -- If 1 minute has passed if Counter = ClockFrequencyHz * 60 -1 then Counter <= 0; State <= StopWest; end if; -- Yellow in west/east direction when StopWest => NorthRed <= '1'; WestYellow <= '1'; -- If 5 seconds have passed if Counter = ClockFrequencyHz * 5 -1 then Counter <= 0; State <= NorthNext; end if; end case; end if; end if; end process; end architecture;
Die Wellenform nachdem wir run 5 min
eingegeben haben Befehl in der ModelSim-Konsole:
Analyse
Wir haben einen Aufzählungstyp mit allen acht verschiedenen Zuständen unserer Ampeln deklariert. Dann haben wir einen state
deklariert Signal dieses neuen Typs, den wir geschaffen haben. Das bedeutet, dass das Signal nur einen der acht genannten Zustandswerte haben kann und keine anderen Werte.
Die FSM wurde unter Verwendung einer Case-Anweisung innerhalb eines getakteten Prozesses implementiert. Bei jeder steigenden Flanke der Uhr wacht der Prozess auf und der state
Signal ausgewertet. Der Code in genau einem der when
Choices (Zweige) dürfen ausgeführt werden, je nach aktuellem Status.
In unserem Code ist es der Wert von Counter
Signal, das Zustandsänderungen auslöst. Wenn der Zähler einen vordefinierten Wert erreicht, der 5 Sekunden oder 1 Minute darstellt, wird State
eine neue Zustandscodierung zugewiesen Signal. Wenn der Prozess dann bei der nächsten steigenden Flanke der Uhr aufwacht, nachdem der Zustandswert aktualisiert wurde, befindet sich die FSM in einem anderen Zustand.
Beachten Sie, dass wir '0'
nicht zuweisen zu jedem Signal in einem der when
Auswahlmöglichkeiten. Dies liegt daran, dass wir allen Ausgangssignalen einen Standardwert von '0'
gegeben haben zu Beginn des Prozesses. Sie erinnern sich vielleicht aus einem früheren Tutorial, dass der letzte Wert, der einem Signal zugewiesen wird, wirksam wird. Signalzuweisungen werden erst wirksam, nachdem der Prozess beendet ist. Wenn wir '0'
zuweisen zum Signal am Anfang des Prozesses und dann '1'
in einem der when
Auswahlmöglichkeiten erhält das Signal den Wert '1'
.
Wir können an der Wellenform erkennen, dass State
Signal durchläuft die acht Zustände. Die grünen Dauerzustände dauern eine Minute, das Wellenformbild wurde daher in North
geschnitten und West
Staaten.
Imbiss
- Algorithmen werden normalerweise als endliche Zustandsmaschinen (FSMs) implementiert
- Ein FSM kann durch die Verwendung einer case-Anweisung in einem getakteten Prozess implementiert werden
- FSM-Zustände können in einem Aufzählungstyp implementiert werden
Weiter zum nächsten Tutorial »
VHDL
- Finite-State-Maschine
- So stellen Sie die beste Leistung der Qt-Zustandsmaschine sicher
- So erstellen Sie eine Liste von Zeichenfolgen in VHDL
- So erstellen Sie eine Tcl-gesteuerte Testbench für ein VHDL-Code-Sperrmodul
- So stoppen Sie die Simulation in einer VHDL-Testbench
- So erstellen Sie einen PWM-Controller in VHDL
- So generieren Sie Zufallszahlen in VHDL
- So erstellen Sie eine selbstüberprüfende Testbench
- So erstellen Sie eine verknüpfte Liste in VHDL
- Wie erstellt OMNI CNC-Lasermaschinen personalisierte Weihnachtsgeschenke?