Een onzuivere functie gebruiken in VHDL
Een onzuivere functie kan elk signaal binnen zijn bereik lezen of schrijven, ook signalen die niet op de parameterlijst staan. We zeggen dat de functie bijwerkingen . heeft .
Wat we bedoelen met bijwerkingen is dat het niet gegarandeerd is dat de functie elke keer dat deze wordt aangeroepen met dezelfde parameters dezelfde waarde retourneert. Als de functie signalen kan lezen die niet in de parameterlijst staan, kan de retourwaarde ook van deze schaduwparameters afhangen. De functie kan ook externe signalen wijzigen die niet zijn toegewezen aan de geretourneerde waarde.
Deze blogpost maakt deel uit van de serie Basic VHDL Tutorials.
Hoewel we overal onzuivere functies kunnen declareren waar we een normale, zuivere functie kunnen declareren, heeft het alleen zin om ze binnen processen te gebruiken. Wanneer gedeclareerd in de architectuur waar we normaal onze signalen declareren, zal geen van de signalen tijdens het compileren binnen het bereik vallen. Een onzuivere functie kan dus niet meer doen dan een zuivere functie wanneer deze wordt gedeclareerd in de architectuur of binnen een pakket.
De motivatie voor het gebruik van onzuivere functies is vooral het opschonen van de code. We zouden elk signaal met een pure functie kunnen manipuleren door het simpelweg toe te voegen aan de parameterlijst, maar als de parameterlijst te lang wordt, zou het eerder versluieren dan vereenvoudigen.
De syntaxis voor het declareren van een onzuivere functie is simpelweg het schrijven van impure function
in plaats van function
bij het declareren. Raadpleeg de functiehandleiding voor de syntaxis van een generieke functie.
Oefening
In de vorige zelfstudie hebben we onze finite-state machine (FSM) -code vereenvoudigd door een functie te gebruiken voor het berekenen van vertragingswaarden. We hebben de parameters Minuten en Seconden opgegeven om aan te geven hoe lang we elke statuswijziging wilden uitstellen.
Als de CounterVal
functie geretourneerd true
, de tijd was verstreken en het was tijd om naar de volgende FSM-status te gaan. In hetzelfde proces moesten we ook de Counter
. resetten signaal, anders zou de functie niet werken in de volgende staat. De timer zou al verlopen zijn.
De Counter
signaal zou altijd worden ingesteld op 0
wanneer de functie true retourneert. Zou het niet beter zijn als dit gebeurde in de CounterVal
functie in plaats van meerdere plaatsen in de machinecode van de staat?
In deze video-tutorial zullen we de FSM-code van de vorige tutorial verbeteren met behulp van een onzuivere functie:
De laatste code voor de onzuivere functie testbench :
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity T22_ImpureFunctionTb is end entity; architecture sim of T22_ImpureFunctionTb 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.T22_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 T22_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 T22_TrafficLights is -- 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; -- 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 -- This impure function reads and drives the Counter signal -- which is not on the parameter list. impure function CounterExpired(Minutes : integer := 0; Seconds : integer := 0) return boolean is begin if Counter = CounterVal(Minutes, Seconds) then Counter <= 0; return true; else return false; end if; end function; 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 CounterExpired(Seconds => 5) then 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 CounterExpired(Seconds => 5) then State <= North; end if; -- Green in north/south direction when North => NorthGreen <= '1'; WestRed <= '1'; -- If 1 minute has passed if CounterExpired(Minutes => 1) then State <= StopNorth; end if; -- Yellow in north/south direction when StopNorth => NorthYellow <= '1'; WestRed <= '1'; -- If 5 seconds have passed if CounterExpired(Seconds => 5) then State <= WestNext; end if; -- Red in all directions when WestNext => NorthRed <= '1'; WestRed <= '1'; -- If 5 seconds have passed if CounterExpired(Seconds => 5) then 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 CounterExpired(Seconds => 5) then State <= West; end if; -- Green in west/east direction when West => NorthRed <= '1'; WestGreen <= '1'; -- If 1 minute has passed if CounterExpired(Minutes => 1) then State <= StopWest; end if; -- Yellow in west/east direction when StopWest => NorthRed <= '1'; WestYellow <= '1'; -- If 5 seconds have passed if CounterExpired(Seconds => 5) then 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
Zoals we aan de golfvorm kunnen zien, blijft de module-uitvoer ongewijzigd nadat we de onzuivere functie hebben toegevoegd. We hebben de logica helemaal niet veranderd, alleen de code.
De evaluatie van de Counter
signaal is verplaatst van de FSM-code naar de nieuwe onzuivere functie CounterExpired
. De Counter <= 0;
regel voor het wissen van de Counter
signaal is ook verplaatst naar de onzuivere functie.
Het resultaat is een beter leesbare FSM-code die gemakkelijker te onderhouden is. Dit is subjectief, maar voor mij CounterExpired(Seconds => 5)
is gemakkelijker voor de ogen dan Counter = CounterVal(Seconds => 5)
.
Hoe ver u moet gaan met het gebruik van onzuivere functies, is geheel aan u en aan degene die voor uw diensten betaalt. Sommige mensen vinden dat ze met de nodige voorzichtigheid moeten worden gebruikt, omdat het moeilijker kan zijn om alle oorzaken en gevolgen te doorzien van een algoritme dat in een subprogramma is verborgen. Anderen, zoals ik, zijn van mening dat, zolang je je bedoelingen duidelijk maakt, de gemakkelijker te lezen code het eigenlijk minder foutgevoelig maakt.
Om deze reden is de kans groter dat u onzuivere functies aantreft in testbench-code dan in productiemodules. Testbanken zijn doorgaans complexer dan de module die ze testen, en de vereiste voor code correctheid is minder streng dan voor RTL-code.
Afhaalmaaltijden
- Onzuivere functies kunnen signalen lezen of aansturen die niet op de parameterlijst staan
- Het heeft alleen zin om onzuivere functies binnen een proces te declareren
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 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