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

Использование нечистых функций в VHDL: повышение читаемости и поддерживаемости FSM

В VHDL нечистая функция (impure function) может обращаться к любому сигналу в своей лексической области видимости или изменять его, включая сигналы, не перечисленные в параметрах. Эта способность дает функции побочные эффекты — ее возвращаемое значение может варьироваться даже при одинаковых аргументах, и она может изменять внешние сигналы, не возвращаемые напрямую.

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

Примечание: Нечистые функции лучше объявлять внутри процесса. Объявление их на уровне архитектуры или пакета не дает преимущества, так как область видимости функции была бы ограничена сигналами, уже видимыми во время компиляции.

Когда и почему использовать нечистые функции

Типичные сценарии включают:

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

Синтаксис

Для объявления нечистой функции просто добавьте ключевое слово impure перед function:

 impure function CounterExpired(Minutes : integer := 0; Seconds : integer := 0) return boolean; 

Обратитесь к уроку по функциям для полных деталей синтаксиса.

Упражнение: Рефакторинг FSM с нечистой функцией

Ранее мы вычисляли задержки времени, используя чистую функцию CounterVal и вручную сбрасывали счетчик всякий раз, когда таймер истекал. Следующая нечистая функция консолидирует эту логику:

Тестбенч (T22_ImpureFunctionTb)

 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 -- Low clock frequency to accelerate 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 -- DUT instantiation 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); -- Clock generation Clk <= not Clk after ClockPeriod / 2; -- Testbench sequence process is begin wait until rising_edge(Clk); wait until rising_edge(Clk); -- Release reset nRst <= '1'; wait; end process; end architecture; 

Модуль светофоров (T22_TrafficLights)

 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 -- Pure function to compute clock cycles for a given time 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; -- FSM state definition type t_State is (NorthNext, StartNorth, North, StopNorth, WestNext, StartWest, West, StopWest); signal State : t_State; -- Counter for clock periods, up to one minute signal Counter : integer range 0 to ClockFrequencyHz * 60; begin process(Clk) is -- Impure function that reads and drives Counter 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 state and signals State <= NorthNext; Counter <= 0; NorthRed <= '1'; NorthYellow <= '0'; NorthGreen <= '0'; WestRed <= '1'; WestYellow <= '0'; WestGreen <= '0'; else -- Default outputs NorthRed <= '0'; NorthYellow <= '0'; NorthGreen <= '0'; WestRed <= '0'; WestYellow <= '0'; WestGreen <= '0'; Counter <= Counter + 1; case State is when NorthNext => NorthRed <= '1'; WestRed <= '1'; if CounterExpired(Seconds => 5) then State <= StartNorth; end if; when StartNorth => NorthRed <= '1'; NorthYellow <= '1'; WestRed <= '1'; if CounterExpired(Seconds => 5) then State <= North; end if; when North => NorthGreen <= '1'; WestRed <= '1'; if CounterExpired(Minutes => 1) then State <= StopNorth; end if; when StopNorth => NorthYellow <= '1'; WestRed <= '1'; if CounterExpired(Seconds => 5) then State <= WestNext; end if; when WestNext => NorthRed <= '1'; WestRed <= '1'; if CounterExpired(Seconds => 5) then State <= StartWest; end if; when StartWest => NorthRed <= '1'; WestRed <= '1'; WestYellow <= '1'; if CounterExpired(Seconds => 5) then State <= West; end if; when West => NorthRed <= '1'; WestGreen <= '1'; if CounterExpired(Minutes => 1) then State <= StopWest; end if; when StopWest => NorthRed <= '1'; WestYellow <= '1'; if CounterExpired(Seconds => 5) then State <= NorthNext; end if; end case; end if; end if; end process; end architecture; 

Анализ волновой формы

После ввода команды run 5 min в ModelSim симуляция показывает идентичное поведение оригинальному FSM — только код стал чище. Логика сброса счетчика теперь инкапсулирована в CounterExpired, уменьшая дублирование и потенциальные ошибки.

Использование нечистых функций в VHDL: повышение читаемости и поддерживаемости FSM

Анализ

Нечистая функция переносит сравнение и сброс счетчика из множества состояний FSM в единственную подпрограмму. Это изменение улучшает читаемость: CounterExpired(Seconds => 5) ясно передает намерение, тогда как Counter = CounterVal(Seconds => 5) более многословно.

Хотя нечистые функции могут скрывать побочные эффекты при чрезмерном использовании, сохранение их локальными для процесса гарантирует, что окружающий код остается детерминированным и легким для аудита. На практике они чаще используются в тестбенчах, где корректность важна, но риск тонких ошибок ниже, чем в синтезируемом RTL.

Использование нечистых функций в VHDL: повышение читаемости и поддерживаемости FSM

Ключевые выводы

Переходите к следующему уроку для изучения продвинутых техник VHDL.

VHDL

  1. Как молибден формирует современную промышленность: применение, преимущества и динамика поставок
  2. Создание списков строк в VHDL: лучшие практики и пример
  3. Корректное завершение симуляции VHDL-тестбенча
  4. Реализация PWM-контроллера в VHDL: проектирование, симуляция и FPGA-демо
  5. Генерация случайных чисел в VHDL: от Uniform к OSVVM
  6. Использование внутрипроцессных процедур для более чистого проектирования FSM на VHDL
  7. Освоение функций VHDL: практическое руководство по эффективному дизайну
  8. Использование realloc() в C: синтаксис, лучшие практики и пример
  9. Освоение функции free() в C: практическое руководство и пример
  10. Освоение техник шлифовального станка для режущих инструментов: практическое руководство