Industriële fabricage
Industrieel internet der dingen | Industriële materialen | Onderhoud en reparatie van apparatuur | Industriële programmering |
home  MfgRobots >> Industriële fabricage >  >> Industrial programming >> VHDL

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

  1. Hoe gebruiken we molybdeen?
  2. Een lijst met strings maken in VHDL
  3. Simulatie stoppen in een VHDL-testbench
  4. Een PWM-controller maken in VHDL
  5. Hoe willekeurige getallen te genereren in VHDL
  6. Een procedure gebruiken in een proces in VHDL
  7. Een functie gebruiken in VHDL
  8. Een eindige-toestandsmachine maken in VHDL
  9. realloc() Functie in C Library:Hoe te gebruiken? Syntaxis en voorbeeld
  10. free() Functie in C-bibliotheek:Hoe te gebruiken? Leer met voorbeeld
  11. Hoe een snijmolen te gebruiken