Промышленное производство
Промышленный Интернет вещей | Промышленные материалы | Техническое обслуживание и ремонт оборудования | Промышленное программирование |
home  MfgRobots >> Промышленное производство >  >> Industrial programming >> VHDL

Как использовать процедуру в VHDL

Процедура — это тип подпрограммы в VHDL, которая помогает избежать повторения кода. Иногда возникает необходимость выполнить одинаковые операции в нескольких местах по всей конструкции. Хотя создание модуля может быть излишним для мелких операций, часто вам нужна процедура.

Процедуры могут быть объявлены в любой декларативной области. Объем процедуры будет ограничен тем, где она объявлена, архитектурой, пакетом или процессом. Всякий раз, когда вы вызываете процедуру, она будет вести себя так, как будто код процедуры был вставлен туда, откуда она была вызвана.

Процедура не возвращает значение, как функция, но вы можете вернуть значения, объявив out или inout сигналов в списке параметров.

Эта запись в блоге является частью серии учебных пособий по основам VHDL.

Основной синтаксис для создания процедуры:
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;

Список параметров процедуры определяет ее входы и выходы, что-то вроде мини-модуля. Это может быть сигнал или константа, но, в отличие от модуля, это может быть и переменная. Вы можете объявить объекты между ключевыми словами «is» и «begin», которые допустимы только внутри процедуры. Это могут быть константы, переменные, типы, подтипы и псевдонимы, но не сигналы.

В отличие от функций процедуры могут содержать операторы ожидания. Поэтому они часто используются в тестовых стендах, таких как простые BFM, для моделирования интерфейсов или для проверки выходных данных тестируемого устройства (DUT).

Упражнение

В предыдущем уроке мы создали модуль таймера, используя вложенные операторы If-Then-Else. Каждый уровень If-Then-Else внутри другого If-Then-Else усложняет дизайн, и он становится менее читаемым. На каждом уровне логики мы в основном выполняем одну и ту же операцию с другим набором сигналов. Разве нет лучшего способа сделать это?

В этом видеоуроке мы узнаем, как создать процедуру на VHDL:

Окончательный код процедуры 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;

Окончательный код для модуля таймера используя процедуру:

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;

Окно сигнала в ModelSim, увеличенное на временной шкале, где Minutes сигнал сворачивает:

Анализ

Из формы волны видно, что перенос сигналов по-прежнему работает, как и в предыдущем уроке. Это потому, что мы фактически не изменили функцию модуля, а только то, как она реализована.

Первый элемент в списке параметров для IncrementWrap процедура Counter сигнал. Он объявлен с использованием направления inout чтобы процедура могла как читать, так и устанавливать его значение.

Второй и третий элементы в списке параметров являются константами. Это означает, что введенные здесь значения будут отображаться как константы внутри. процедуры. WrapValue введите вместе с Enable input определяет, является ли Counter сигнал увеличивается или переносится.

Последний элемент в списке параметров — это переменная с направлением out. . Целью этого вывода является информирование вызывающей стороны о процедуре, в которую запакован счетчик. Мы используем его здесь как возвращаемое значение.

В основном процессе у нас есть четыре обращения к IncrementWrap процедура. Каждый из последующих вызовов использует Wrap переменная, чтобы включить подсчет. Это не сработало бы, если бы мы использовали сигнал вместо переменной, потому что значения сигнала обновляются только тогда, когда процесс переходит в спящий режим. Нам нужно, чтобы выходное значение из одного вызова процедуры использовалось в качестве входных данных для вызова в самой следующей строке. Таким образом, это должна быть переменная.

Вывод

Перейти к следующему руководству »


VHDL

  1. Оператор процедуры — пример VHDL
  2. Как мы используем молибден?
  3. Как создать список строк в VHDL
  4. Как остановить симуляцию в тестовом стенде VHDL
  5. Как создать ШИМ-контроллер на VHDL
  6. Как генерировать случайные числа в VHDL
  7. Как использовать процедуру в процессе в VHDL
  8. Как использовать нечистую функцию в VHDL
  9. Как использовать функцию в VHDL
  10. Как использовать шлифовальный станок