Een functie gebruiken in VHDL
Functies zijn subprogramma's in VHDL die kunnen worden gebruikt voor het implementeren van veelgebruikte algoritmen. Een functie heeft nul of meer invoerwaarden en retourneert altijd een waarde. Wat een functie behalve de retourwaarde onderscheidt van een procedure, is dat deze geen Wait-statements kan bevatten. Dit betekent dat functies altijd nul simulatietijd verbruiken.
Als u bekend bent met functies of methoden uit andere programmeertalen, moeten VHDL-functies gemakkelijk te begrijpen zijn. In VHDL kunnen we de returnwaarde of return void niet weglaten, een functie moet altijd iets teruggeven en de returnwaarde moet ergens aan worden toegewezen.
Deze blogpost maakt deel uit van de serie Basic VHDL Tutorials.
In VHDL zijn er twee soorten functies, puur en onzuiver functies. Dat een functie puur is, betekent dat het niet is toegestaan om een extern signaal te wijzigen of uit te lezen. We kunnen er zeker van zijn dat wanneer we een pure functie aanroepen met bepaalde argumenten, deze altijd dezelfde waarde zal retourneren. We zeggen dat de functie geen bijwerkingen heeft .
De syntaxis voor het declareren van een functie in VHDL is:
[pure|impure] function <function_name> (<parameter1_name> : <parameter1_type> := <default_value>;
<parameter2_name> : <parameter2_type> := <default_value>;
... ) return <return_type> is
<constant_or_variable_declaration>
begin
<code_performed_by_the_function>
return <value>
end function;
Het trefwoord pure/onzuiver is optioneel, hoewel het standaard wordt ingesteld op pure als het trefwoord wordt weggelaten. Alle parameters worden behandeld als constanten binnen de functie. Ze kunnen dus niet worden gewijzigd. De standaardwaarden zijn optioneel en de functie moet altijd eindigen op een return
verklaring.
Functies hebben hun eigen declaratieve regio tussen de in
en begin
trefwoorden. Hier gedeclareerde constanten, signalen of variabelen zijn alleen geldig binnen de functie zelf, en ze behouden hun waarden niet bij latere aanroepen van de functie.
Oefening
In deze tutorial gaan we ons concentreren op de pure functie, onzuivere functies komen aan bod in een latere tutorial in deze serie.
In de vorige zelfstudie hebben we een verkeerslichtcontroller-module gemaakt met behulp van een eindige-toestandsmachine (FSM). We hebben veel van de regels met timerberekeningen van de ene toestand naar de andere gekopieerd en geplakt, waarbij we slechts één constante lichtjes hebben gewijzigd.
Ontdek hoe u de toestandsmachinecode kunt vereenvoudigen door een functie te gebruiken:
De definitieve code voor de functie testbench :
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity T21_FunctionTb is end entity; architecture sim of T21_FunctionTb 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.T21_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 definitieve code voor de verkeerslichten module :
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity T21_TrafficLights is generic(ClockFrequencyHz : natural); 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 T21_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; -- Calculate the number of clock cycles in minutes/seconds function CounterVal(Minutes : integer := 0; Seconds : integer := 0) return integer is variable TotalSeconds : integer; begin TotalSeconds := Seconds + Minutes * 60; return TotalSeconds * ClockFrequencyHz -1; end function; -- Counter for counting clock periods, 1 minute max signal Counter : integer range 0 to CounterVal(Minutes => 1) +1; begin process(Clk) is begin if rising_edge(Clk) then if nRst = '0' then -- Reset values NorthRed <= '1'; NorthYellow <= '0'; NorthGreen <= '0'; WestRed <= '1'; WestYellow <= '0'; WestGreen <= '0'; State <= NorthNext; Counter <= 0; else -- Default values NorthRed <= '0'; NorthYellow <= '0'; NorthGreen <= '0'; WestRed <= '0'; WestYellow <= '0'; WestGreen <= '0'; Counter <= Counter + 1; case State is -- Red light in all directions when NorthNext => NorthRed <= '1'; WestRed <= '1'; -- If 5 seconds have passed if Counter = CounterVal(Seconds => 5) then Counter <= 0; State <= StartNorth; end if; -- Yellow light in north/south directions when StartNorth => NorthRed <= '1'; NorthYellow <= '1'; WestRed <= '1'; -- If 5 seconds have passed if Counter = CounterVal(Seconds => 5) then Counter <= 0; State <= North; end if; -- Green light in north/south directions when North => NorthGreen <= '1'; WestRed <= '1'; -- If 1 minute has passed if Counter = CounterVal(Minutes => 1) then Counter <= 0; State <= StopNorth; end if; -- Red and yellow light in north/south direction when StopNorth => NorthYellow <= '1'; WestRed <= '1'; -- If 5 seconds have passed if Counter = CounterVal(Seconds => 5) then Counter <= 0; State <= WestNext; end if; -- Red light in all directions when WestNext => NorthRed <= '1'; WestRed <= '1'; -- If 5 seconds have passedf if Counter = CounterVal(Seconds => 5) then Counter <= 0; State <= StartWest; end if; -- Yellow light in west/east direction when StartWest => NorthRed <= '1'; WestRed <= '1'; WestYellow <= '1'; -- If 5 seconds have passed if Counter = CounterVal(Seconds => 5) then Counter <= 0; State <= West; end if; -- Green light in west/east direction when West => NorthRed <= '1'; WestGreen <= '1'; -- If 1 minute has passed if Counter = CounterVal(Minutes => 1) then Counter <= 0; State <= StopWest; end if; -- Red and yellow light in west/east direction when StopWest => NorthRed <= '1'; WestYellow <= '1'; -- If 5 seconds have passed if Counter = CounterVal(Seconds => 5) 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:
De golfvorm met cursors toegevoegd bij de overgangen van en naar de StartNorth
staat:
Analyse
We hebben de timerberekeningen uit de vorige tutorial vervangen if Counter = ClockFrequencyHz * 5 -1 then
met een oproep naar de nieuwe CounterVal
functie die we hebben gemaakt:if Counter = CounterVal(Seconds => 5) then
.
We kunnen aan de eerste golfvorm-screenshot zien dat de functie van de module ongewijzigd is. Het gebruik van functies voor repetitieve taken is een goede ontwerppraktijk. Vooral als je berekeningen kunt vervangen door beter leesbare regels met termen als Minutes
en Seconds
.
Een ander voordeel van het gebruik van functies is dat we de implementatie van alle timers tegelijk kunnen wijzigen, in plaats van dit regel voor regel te doen. Als we bijvoorbeeld return TotalSeconds * ClockFrequencyHz;
. hadden geschreven in de CounterVal
functie, zouden alle timers een klokcyclus te lang hebben geduurd. We kunnen dit dan veranderen in return TotalSeconds * ClockFrequencyHz -1;
in de CounterVal
functie, en alle timers zouden in één keer worden vastgesteld.
Als we de laatste schermafbeelding van de golfvorm bekijken, kunnen we zien waarom we 1 moeten aftrekken van de timerwaarde die wordt geretourneerd uit de CounterVal
functie. Deze golfvorm onderzoekt de duur van de StartNorth
staat, zou het precies vijf seconden moeten duren. Wanneer de State
signaal verandert in StartNorth
, de Counter
waarde is 0 en verandert pas na de volgende klokcyclus. Dus als we tot 500 klokcycli hadden geteld, zou de StartNorth
toestand zou eigenlijk 501 cycli hebben geduurd. Met onze testbank op 100 Hz, zijn 500 klokcycli precies vijf seconden.
Afhaalmaaltijden
- Functies kunnen nul of meer parameters hebben, maar ze retourneren altijd een waarde
- Functies mogen geen
wait
. bevatten uitspraken - Pure functies kunnen geen bijwerkingen hebben, terwijl onzuivere functies dat wel kunnen.
Ga naar de volgende tutorial »
VHDL
- Hoe gebruiken we molybdeen?
- Een lijst met strings maken in VHDL
- Simulatie stoppen in een VHDL-testbench
- Een PWM-controller maken in VHDL
- Hoe willekeurige getallen te genereren in VHDL
- Een procedure gebruiken in een proces in VHDL
- Een onzuivere functie gebruiken in VHDL
- Een eindige-toestandsmachine maken in VHDL
- realloc() Functie in C Library:Hoe te gebruiken? Syntaxis en voorbeeld
- free() Functie in C-bibliotheek:Hoe te gebruiken? Leer met voorbeeld
- Hoe een snijmolen te gebruiken