Industrielle Fertigung
Industrielles Internet der Dinge | Industrielle Materialien | Gerätewartung und Reparatur | Industrielle Programmierung |
home  MfgRobots >> Industrielle Fertigung >  >> Industrial programming >> VHDL

So verwenden Sie eine Prozedur in VHDL

Eine Prozedur ist eine Art Unterprogramm in VHDL, das uns dabei helfen kann, die Wiederholung von Code zu vermeiden. Manchmal besteht die Notwendigkeit, identische Operationen an mehreren Stellen im Design durchzuführen. Während das Erstellen eines Moduls für kleinere Operationen übertrieben sein kann, ist eine Prozedur oft das, was Sie wollen.

Prozeduren können innerhalb jeder deklarativen Region deklariert werden. Der Geltungsbereich der Prozedur wird auf die deklarierte Architektur, das Paket oder den Prozess beschränkt. Wann immer Sie die Prozedur aufrufen, verhält sie sich so, als wäre der Code der Prozedur dort eingefügt worden, wo sie aufgerufen wurde.

Eine Prozedur gibt keinen Wert zurück wie eine Funktion, aber Sie können Werte zurückgeben, indem Sie out deklarieren oder inout Signale in der Parameterliste.

Dieser Blogpost ist Teil der Reihe Basic VHDL Tutorials.

Die grundlegende Syntax zum Erstellen einer Prozedur lautet:
procedure <procedure_name> (signal|variable|constant <name1> : in|out|inout <type>;
                            signal|variable|constant <name2> : in|out|inout <type>;
                            ... ) is
    <declarations_for_use_within_the_procedure>
begin
    <code_performed_by_the_procedure_here>
end procedure;

Die Parameterliste einer Prozedur definiert ihre Ein- und Ausgänge, ähnlich wie bei einem Mini-Modul. Es kann ein Signal oder eine Konstante sein, aber im Gegensatz zu einem Modul kann es auch eine Variable sein. Sie können Objekte zwischen den Schlüsselwörtern „is“ und „begin“ deklarieren, die nur innerhalb der Prozedur gültig sind. Dazu können Konstanten, Variablen, Typen, Untertypen und Aliase gehören, aber keine Signale.

Im Gegensatz zu Funktionen können Prozeduren Warteanweisungen enthalten. Daher werden sie häufig in Prüfständen wie einfache BFMs zur Simulation von Schnittstellen oder zur Überprüfung der Ausgabe des zu testenden Geräts (DUT) verwendet.

Übung

Im vorherigen Tutorial haben wir ein Timer-Modul mit verschachtelten If-Then-Else-Anweisungen erstellt. Jede Ebene von If-Then-Else innerhalb einer anderen If-Then-Else fügt dem Design Komplexität hinzu und es wird weniger lesbar. Auf jeder Logikebene führen wir im Grunde die gleiche Operation mit einem anderen Satz von Signalen durch. Gibt es dafür keinen besseren Weg?

In diesem Video-Tutorial lernen wir, wie man eine Prozedur in VHDL erstellt:

Der endgültige Code für die Prozedur testbench :

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity T19_ProcedureTb is
end entity;

architecture sim of T19_ProcedureTb is

    -- We're slowing down the clock to speed up simulation time
    constant ClockFrequencyHz : integer := 10; -- 10 Hz
    constant ClockPeriod : time := 1000 ms / ClockFrequencyHz;

    signal Clk     : std_logic := '1';
    signal nRst    : std_logic := '0';
    signal Seconds : integer;
    signal Minutes : integer;
    signal Hours   : integer;

begin

    -- The Device Under Test (DUT)
    i_Timer : entity work.T19_Timer(rtl)
    generic map(ClockFrequencyHz => ClockFrequencyHz)
    port map (
        Clk     => Clk,
        nRst    => nRst,
        Seconds => Seconds,
        Minutes => Minutes,
        Hours   => Hours);

    -- 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 Timer-Modul mit einer Prozedur:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity T19_Timer is
generic(ClockFrequencyHz : integer);
port(
    Clk     : in std_logic;
    nRst    : in std_logic; -- Negative reset
    Seconds : inout integer;
    Minutes : inout integer;
    Hours   : inout integer);
end entity;

architecture rtl of T19_Timer is

    -- Signal for counting clock periods
    signal Ticks : integer;

    procedure IncrementWrap(signal   Counter   : inout integer;
                            constant WrapValue : in    integer;
                            constant Enable    : in    boolean;
                            variable Wrapped   : out   boolean) is
    begin
        Wrapped := false;
        if Enable then
            if Counter = WrapValue - 1 then
                Wrapped := true;
                Counter <= 0;
            else
                Counter <= Counter + 1;
            end if;
        end if;
    end procedure;

begin

    process(Clk) is
        variable Wrap : boolean;
    begin
        if rising_edge(Clk) then

            -- If the negative reset signal is active
            if nRst = '0' then
                Ticks   <= 0;
                Seconds <= 0;
                Minutes <= 0;
                Hours   <= 0;
            else

                -- Cascade counters
                IncrementWrap(Ticks, ClockFrequencyHz, true, Wrap);
                IncrementWrap(Seconds,             60, Wrap, Wrap);
                IncrementWrap(Minutes,             60, Wrap, Wrap);
                IncrementWrap(Hours,               24, Wrap, Wrap);

            end if;
        end if;
    end process;

end architecture;

Das Wellenformfenster in ModelSim, vergrößert auf der Zeitachse, wo Minutes Signal wird umgebrochen:

Analyse

Wir können aus der Wellenform ersehen, dass das Wrapping von Signalen immer noch so funktioniert wie im vorherigen Tutorial. Das liegt daran, dass wir die Funktion des Moduls nicht wirklich geändert haben, sondern nur die Art und Weise, wie sie implementiert ist.

Das erste Element in der Parameterliste für IncrementWrap Prozedur ist die Counter Signal. Es wird mit der Richtung inout deklariert damit die Prozedur ihren Wert sowohl lesen als auch setzen kann.

Das zweite und dritte Element in der Parameterliste sind Konstanten. Das bedeutet, dass die Werte, die Sie hier eingeben, als Konstanten innerhalb erscheinen des Verfahrens. Die WrapValue zusammen mit dem Enable eingeben input bestimmt, ob der Counter Signal wird inkrementiert oder umgebrochen.

Das letzte Element in der Parameterliste ist eine Variable mit der Richtung out . Der Zweck dieser Ausgabe besteht darin, den Aufrufer über die Prozedur zu informieren, die der Zähler umbrochen hat. Wir verwenden es hier wie einen Rückgabewert.

Im Hauptprozess haben wir vier Aufrufe an die IncrementWrap Verfahren. Jeder der nachfolgenden Aufrufe verwendet den Wrap Variable, um die Zählung zu aktivieren. Es hätte nicht funktioniert, wenn wir anstelle einer Variablen ein Signal verwendet hätten, da Signalwerte nur aktualisiert werden, wenn ein Prozess schlafen geht. Wir brauchen den Ausgabewert eines Prozeduraufrufs, der als Eingabe für einen Aufruf in der nächsten Zeile verwendet werden soll. Es muss also eine Variable sein.

Imbiss

Weiter zum nächsten Tutorial »


VHDL

  1. Prozeduranweisung – VHDL-Beispiel
  2. Wie verwenden wir Molybdän?
  3. So erstellen Sie eine Liste von Zeichenfolgen in VHDL
  4. So stoppen Sie die Simulation in einer VHDL-Testbench
  5. So erstellen Sie einen PWM-Controller in VHDL
  6. So generieren Sie Zufallszahlen in VHDL
  7. So verwenden Sie eine Prozedur in einem Prozess in VHDL
  8. So verwenden Sie eine unreine Funktion in VHDL
  9. So verwenden Sie eine Funktion in VHDL
  10. So verwenden Sie einen Cutter Grinder