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

Как создать конечный автомат на VHDL

Конечный автомат (FSM) — это механизм, выходные данные которого зависят не только от текущего состояния ввода, но и от прошлых входных и выходных значений.

Всякий раз, когда вам нужно создать какой-то зависящий от времени алгоритм на VHDL или если вы сталкиваетесь с проблемой реализации компьютерной программы на FPGA, ее обычно можно решить с помощью FSM.

Конечные автоматы в VHDL — это синхронизируемые процессы, выходы которых контролируются значением сигнала состояния. Сигнал состояния служит внутренней памятью о том, что произошло в предыдущей итерации.

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

Рассмотрим состояния светофоров на этом перекрестке:

Светофоры имеют конечное число состояний, которым мы дали идентифицируемые имена. В нашем примере конечный автомат не имеет управляющих входов, выходом является состояние огней в направлениях север/юг и запад/восток. Это прошедшее время и предыдущее состояние выходов, которые продвигают этот конечный автомат.

Мы можем представить состояния в VHDL, используя нумерованный тип . Это такие же типы данных, как и signed. или unsigned , но вместо целых чисел мы можем предоставить собственный список возможных значений. На самом деле, если вы посмотрите на пакет std_logic_1164, вы обнаружите, что std_ulogic type — это не что иное, как перечисляемый тип со значениями 'U' , 'X' , '0' , '1' , 'Z' , 'W' , 'L' , 'H' и '-' перечислены как значения перечисления.

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

Синтаксис объявления сигнала перечислимого типа в VHDL:
type <type_name> is (<state_name1>, <state_name2>, ...);
signal <signal_name> : <type_name>;

Затем, используя сигнал состояния, можно реализовать конечный автомат в процессе с оператором Case. Оператор Case содержит оператор When для каждого из возможных состояний, заставляя программу выбирать разные пути для каждого состояния. Оператор When также может содержать код, который должен быть выполнен в этом конкретном состоянии. Затем состояние обычно изменяется при выполнении предопределенного условия.

Это шаблон для конечного автомата с одним процессом:
process(Clk) is
begin
    if rising_edge(Clk) then
        if nRst = '0' then
            State <= <reset_state>;
        else
            case State is
                when <state_name> =>
                    <set_outputs_for_this_state_here>
                    if <state_change_condition_is_true> then
                        State <= <next_state_name>;
                    end if;
                ...
            end case;
        end if;
    end if;
end process;

Примечание.
Существует несколько способов создания FSM в VHDL. Подробнее о различных стилях читайте здесь:
Конечный автомат с одним, двумя и тремя процессами

Упражнение

В этом видеоуроке мы научимся создавать конечный автомат на VHDL:

Окончательный код конечного автомата testbench :

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

entity T20_FiniteStateMachineTb is
end entity;

architecture sim of T20_FiniteStateMachineTb 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.T20_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 T20_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 T20_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
    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 Counter = ClockFrequencyHz * 5 -1 then
                            Counter <= 0;
                            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 Counter = ClockFrequencyHz * 5 -1 then
                            Counter <= 0;
                            State   <= North;
                        end if;

                    -- Green in north/south direction
                    when North =>
                        NorthGreen <= '1';
                        WestRed    <= '1';
                        -- If 1 minute has passed
                        if Counter = ClockFrequencyHz * 60 -1 then
                            Counter <= 0;
                            State   <= StopNorth;
                        end if;

                    -- Yellow in north/south direction
                    when StopNorth =>
                        NorthYellow <= '1';
                        WestRed     <= '1';
                        -- If 5 seconds have passed
                        if Counter = ClockFrequencyHz * 5 -1 then
                            Counter <= 0;
                            State   <= WestNext;
                        end if;

                    -- Red in all directions
                    when WestNext =>
                        NorthRed <= '1';
                        WestRed  <= '1';
                        -- If 5 seconds have passed
                        if Counter = ClockFrequencyHz * 5 -1 then
                            Counter <= 0;
                            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 Counter = ClockFrequencyHz * 5 -1 then
                            Counter <= 0;
                            State   <= West;
                        end if;

                    -- Green in west/east direction
                    when West =>
                        NorthRed  <= '1';
                        WestGreen <= '1';
                        -- If 1 minute has passed
                        if Counter = ClockFrequencyHz * 60 -1 then
                            Counter <= 0;
                            State   <= StopWest;
                        end if;

                    -- Yellow in west/east direction
                    when StopWest =>
                        NorthRed   <= '1';
                        WestYellow <= '1';
                        -- If 5 seconds have passed
                        if Counter = ClockFrequencyHz * 5 -1 then
                            Counter <= 0;
                            State   <= NorthNext;
                        end if;

                end case;

            end if;
        end if;
    end process;

end architecture;

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

Анализ

Мы объявили перечисляемый тип со всеми восемью различными состояниями наших светофоров. Затем мы объявили state сигнал этого нового типа, который мы создали. Это означает, что сигнал может иметь только одно из восьми именованных значений состояния и никаких других значений.

FSM был реализован с использованием оператора Case внутри синхронизируемого процесса. При каждом переднем фронте тактового сигнала процесс просыпается, и state сигнал оценивается. Код ровно в одном из when варианты (ветки) разрешено запускать в зависимости от текущего состояния.

В нашем коде это значение Counter сигнал, запускающий изменение состояния. Когда счетчик достигает предопределенного значения, представляющего 5 секунд или 1 минуту, State присваивается новое кодирование состояния. сигнал. Затем, когда процесс просыпается по следующему переднему фронту тактового сигнала после обновления значения состояния, FSM находится в другом состоянии.

Обратите внимание, что мы не назначаем '0' на любой сигнал в любом из when выбор. Это потому, что мы присвоили всем выходным сигналам значение по умолчанию '0'. в начале процесса. Возможно, вы помните из предыдущего урока, что последнее значение, присвоенное сигналу, становится эффективным. Назначение сигналов вступает в силу только после завершения процесса. Если мы назначим '0' к сигналу в начале процесса, а затем '1' в одном из when вариантов, сигнал получит значение '1' .

Из формы волны видно, что State сигнал циклически проходит через восемь состояний. Постоянные зеленые состояния длятся одну минуту, поэтому изображение сигнала было вырезано в North и West состояния.

Вывод

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


VHDL

  1. Конечный автомат
  2. Как обеспечить максимальную производительность конечного автомата Qt
  3. Как создать список строк в VHDL
  4. Как создать управляемый Tcl тестовый стенд для модуля кодовой блокировки VHDL
  5. Как остановить симуляцию в тестовом стенде VHDL
  6. Как создать ШИМ-контроллер на VHDL
  7. Как генерировать случайные числа в VHDL
  8. Как создать самопроверяющийся тестовый стенд
  9. Как создать связанный список в VHDL
  10. Как лазерный станок с ЧПУ OMNI создает персонализированные рождественские подарки?