Een eindige-toestandsmachine maken in VHDL
Een eindige-toestandsmachine (FSM) is een mechanisme waarvan de uitvoer niet alleen afhankelijk is van de huidige status van de invoer, maar ook van eerdere invoer- en uitvoerwaarden.
Wanneer u een soort tijdsafhankelijk algoritme in VHDL moet maken, of als u wordt geconfronteerd met het probleem van het implementeren van een computerprogramma in een FPGA, kan dit meestal worden opgelost met behulp van een FSM.
State-machines in VHDL zijn geklokte processen waarvan de uitgangen worden bestuurd door de waarde van een statussignaal. Het statussignaal dient als een intern geheugen van wat er in de vorige iteratie is gebeurd.
Deze blogpost maakt deel uit van de serie Basic VHDL Tutorials.
Houd rekening met de toestand van de verkeerslichten op dit kruispunt:
De verkeerslichten hebben een eindig aantal toestanden, die we herkenbare namen hebben gegeven. Onze voorbeeldstatusmachine heeft geen controlerende inputs, de output is de status van de lichten in noord/zuid en west/oost richtingen. Het is de verstreken tijd en de vorige toestand van de uitgangen die deze toestandsmachine vooruithelpen.
We kunnen staten in VHDL weergeven met behulp van een opgesomd type . Dit zijn gegevenstypen, net als signed
of unsigned
, maar in plaats van gehele getallen kunnen we een aangepaste lijst met mogelijke waarden leveren. Als je in het std_logic_1164-pakket kijkt, zul je zien dat de std_ulogic
type is niets meer dan een opgesomd type met de waarden 'U'
, 'X'
, '0'
, '1'
, 'Z'
, 'W'
, 'L'
, 'H'
, en '-'
vermeld als opsommingswaarden.
Zodra we ons opgesomde type hebben, kunnen we een signaal van het nieuwe type declareren dat kan worden gebruikt om de huidige status van de FSM bij te houden.
De syntaxis voor het declareren van een signaal met een opgesomd type in VHDL is:type <type_name> is (<state_name1>, <state_name2>, ...);
signal <signal_name> : <type_name>;
Met behulp van het toestandssignaal kan de eindige-toestandsmachine vervolgens worden geïmplementeerd in een proces met een Case-statement. Het Case-statement bevat een When-statement voor elk van de mogelijke toestanden, waardoor het programma voor elke toestand een ander pad volgt. Het When-statement kan ook code bevatten die moet worden uitgevoerd in die specifieke staat. De status verandert dan meestal wanneer aan een vooraf gedefinieerde voorwaarde wordt voldaan.
Dit is een sjabloon voor een-proces-statusmachine: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;
Opmerking:
Er zijn verschillende manieren om een FSM in VHDL te maken. Lees hier meer over de verschillende stijlen:
Een-proces vs twee-process vs drie-process toestandsmachine
Oefening
In deze video-tutorial leren we hoe we een eindige-toestandsmachine in VHDL kunnen maken:
De definitieve code voor de toestandsmachine 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;
De laatste code voor de state machine module :
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;
De golfvorm nadat we de run 5 min
. hebben ingevoerd commando in de ModelSim-console:
Analyse
We hebben een opgesomd type aangegeven met alle acht verschillende toestanden van onze verkeerslichten. Vervolgens hebben we een state
. gedeclareerd signaal van dit nieuwe type dat we hebben gemaakt. Dit betekent dat het signaal slechts één van de acht genoemde statuswaarden kan hebben, en geen andere waarden.
De FSM is geïmplementeerd met behulp van een Case-statement binnen een geklokt proces. Op elke stijgende flank van de klok wordt het proces wakker en de state
signaal wordt beoordeeld. De code binnen precies één van de when
keuzes (takken) mogen worden uitgevoerd, afhankelijk van de huidige status.
In onze code is dit de waarde van de Counter
signaal dat toestandsveranderingen veroorzaakt. Wanneer de teller een vooraf gedefinieerde waarde bereikt, die 5 seconden of 1 minuut vertegenwoordigt, wordt een nieuwe statuscodering toegewezen aan de State
signaal. Wanneer het proces vervolgens ontwaakt op de volgende stijgende flank van de klok nadat de statuswaarde is bijgewerkt, bevindt de FSM zich in een andere status.
Merk op dat we '0'
. niet toewijzen op elk signaal in een van de when
keuzes. Dit komt omdat we alle uitgangssignalen een standaardwaarde van '0'
. hebben gegeven aan het begin van het proces. U herinnert zich misschien van een vorige tutorial dat het de laatste waarde is die wordt toegewezen aan een signaal dat effectief wordt. Signaaltoewijzingen worden pas van kracht nadat het proces is beëindigd. Als we '0'
. toewijzen naar het signaal aan het begin van het proces, en dan '1'
in een van de when
keuzes, het signaal krijgt de waarde '1'
.
We kunnen aan de golfvorm zien dat de State
signaal doorloopt de acht toestanden. De ononderbroken groene toestanden duren één minuut, het golfvormbeeld is daarom in de North
. gesneden en West
staten.
Afhaalmaaltijden
- Algoritmen worden meestal geïmplementeerd als finite-state machines (FSM's)
- Een FSM kan worden geïmplementeerd door een case-statement te gebruiken in een geklokt proces
- FSM-statussen kunnen worden geïmplementeerd in een opgesomd type
Ga naar de volgende tutorial »
VHDL
- Finite-state machine
- Hoe de beste Qt-statusmachineprestaties te garanderen
- Een lijst met strings maken in VHDL
- Hoe maak je een Tcl-gestuurde testbench voor een VHDL-codeslotmodule?
- Simulatie stoppen in een VHDL-testbench
- Een PWM-controller maken in VHDL
- Hoe willekeurige getallen te genereren in VHDL
- Hoe maak je een ringbuffer FIFO in VHDL
- Hoe maak je een zelfcontrolerende testbank aan
- Een gekoppelde lijst maken in VHDL
- Hoe OMNI CNC-lasermachine gepersonaliseerde kerstcadeaus maakt?