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

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

Можно управлять внешними сигналами из процедуры. Пока сигнал находится в рамках процедуры, к нему можно получить доступ для чтения или записи, даже если он не указан в списке параметров.

Процедуры, объявленные в декларативной области архитектуры, не могут управлять никакими внешними сигналами. Это просто потому, что во время компиляции в его области видимости нет сигналов. С другой стороны, процедура, объявленная внутри процесса, будет иметь доступ ко всем сигналам, которые процесс может видеть.

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

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

Представьте себе процесс, реализующий сложный коммуникационный протокол. Было бы намного проще понять поток выполнения основного алгоритма, если бы некоторые операции были заменены вызовами процедур, такими как RequestToSend() или SendAutorizationHeader() . Вы бы знали, что делают эти строки, просто взглянув на имена процедур.

Упражнение

В предыдущем уроке мы упростили наш код конечного автомата (FSM), используя нечистую функцию. Мы ехали по Counter сигнал от нечистой функции, и мы использовали возвращаемое значение, чтобы определить, когда следует изменить состояние. Но что, если мы хотим переместить назначение State сигнал в функцию и игнорировать возвращаемое значение?

Невозможно вызвать функцию без присвоения возвращаемого значения чему-либо в VHDL. Если мы попытаемся сделать это, ModelSim выдаст ошибку компиляции: Нет допустимых записей для подпрограммы "CounterExpired".

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

В этом видеоруководстве мы упростим код FSM, используя процедуру, объявленную в процессе:

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

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

entity T23_ProcedureInProcessTb is
end entity;

architecture sim of T23_ProcedureInProcessTb 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.T23_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;

Окончательный код для модуля светофора :

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

entity T23_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 T23_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;

    -- Counter for counting clock periods, 1 minute max
    signal Counter : integer range 0 to ClockFrequencyHz * 60;

begin

    process(Clk) is

        -- Procedure for changing state after a given time
        procedure ChangeState(ToState : t_State;
                              Minutes : integer := 0;
                              Seconds : integer := 0) is
            variable TotalSeconds : integer;
            variable ClockCycles  : integer;
        begin
            TotalSeconds := Seconds + Minutes * 60;
            ClockCycles  := TotalSeconds * ClockFrequencyHz -1;
            if Counter = ClockCycles then
                Counter <= 0;
                State   <= ToState;
            end if;
        end procedure;

    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';
                        ChangeState(StartNorth, Seconds => 5);

                    -- Red and yellow in north/south direction
                    when StartNorth =>
                        NorthRed    <= '1';
                        NorthYellow <= '1';
                        WestRed     <= '1';
                        ChangeState(North, Seconds => 5);

                    -- Green in north/south direction
                    when North =>
                        NorthGreen <= '1';
                        WestRed    <= '1';
                        ChangeState(StopNorth, Minutes => 1);

                    -- Yellow in north/south direction
                    when StopNorth =>
                        NorthYellow <= '1';
                        WestRed     <= '1';
                        ChangeState(WestNext, Seconds => 5);

                    -- Red in all directions
                    when WestNext =>
                        NorthRed <= '1';
                        WestRed  <= '1';
                        ChangeState(StartWest, Seconds => 5);

                    -- Red and yellow in west/east direction
                    when StartWest =>
                        NorthRed   <= '1';
                        WestRed    <= '1';
                        WestYellow <= '1';
                        ChangeState(West, Seconds => 5);

                    -- Green in west/east direction
                    when West =>
                        NorthRed  <= '1';
                        WestGreen <= '1';
                        ChangeState(StopWest, Minutes => 1);

                    -- Yellow in west/east direction
                    when StopWest =>
                        NorthRed   <= '1';
                        WestYellow <= '1';
                        ChangeState(NorthNext, Seconds => 5);

                end case;

            end if;
        end if;
    end process;

end architecture;

Форма волны после ввода run 5 min команда в консоли ModelSim:

Анализ

Мы не изменили поведение модуля, и мы видим, что форма волны не изменилась.

По сравнению с кодом из руководства, в котором мы изначально создавали модуль светофора, код FSM теперь намного читабельнее. Вы можете легко следовать алгоритму, который он реализует, читая код. Наличие таймера и логики изменения состояния в одной процедуре выгодно, потому что это гарантирует, что они будут реализованы одинаково везде, где они используются.

Вывод


VHDL

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