亿迅智能制造网
工业4.0先进制造技术信息网站!
首页 | 制造技术 | 制造设备 | 工业物联网 | 工业材料 | 设备保养维修 | 工业编程 |
home  MfgRobots >> 亿迅智能制造网 >  >> Industrial programming >> VHDL

使用VHDL不纯函数提升FSM可读性与可维护性

在VHDL中,不纯函数可访问或修改其词法作用域内的任何信号,包括未列为参数的信号。此能力赋予函数副作用——即使提供相同参数,返回值也可能不同,且可能改变未直接返回的外部信号。

纯函数限于确定性行为,而不纯函数通过将重复或有副作用的任务移入单个命名良好的子程序,对清理复杂状态机逻辑极具价值。

注意: 不纯函数最好声明在进程内。在架构或包层级声明无优势,因函数作用域将限于编译时已在作用域内的信号。

何时及为何使用不纯函数

典型场景包括:

使用不纯函数在保持核心状态机逻辑可读的同时,仍保留设计所需的副作用行为。

语法

声明不纯函数,只需在function前加impure关键字:

 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; 

波形洞察

在ModelSim中发出run 5 min命令后,仿真显示与原始FSM完全相同的行为——仅代码变得更整洁。计数器复位逻辑现封装在CounterExpired中,减少重复和潜在错误。

使用VHDL不纯函数提升FSM可读性与可维护性

分析

不纯函数将计数器比较和复位从多个FSM状态转移到单一子程序。此变更提升可读性:CounterExpired(Seconds => 5)清晰表达意图,而Counter = CounterVal(Seconds => 5)更冗长。

虽不纯函数若滥用可能掩盖副作用,但将其局限在进程内确保周围代码保持确定性且易于审计。实践中,它们更常用于测试平台,因正确性重要但微妙bug风险低于可综合RTL。

使用VHDL不纯函数提升FSM可读性与可维护性

关键要点

进入下一教程探索高级VHDL技术。

VHDL

  1. 刀具磨床实战技法指南:从入门到精通
  2. 钼如何塑造现代工业:用途、优势与供应动态
  3. C 语言 realloc() 完全指南:语法、最佳实践与实战案例
  4. C 语言 free() 函数实战指南:正确释放动态内存、防泄漏与避坑全解析
  5. VHDL 字符串列表创建:最佳实践与示例
  6. 优雅结束 VHDL 测试平台仿真
  7. VHDL 实现 PWM 控制器:设计、仿真与 FPGA 演示
  8. VHDL 生成随机数:从均匀分布到 OSVVM
  9. 利用进程内过程简化VHDL状态机设计
  10. 掌握VHDL函数:高效设计实战指南
  11. 用VHDL设计有限状态机:红绿灯实战范例
  12. 在VHDL中使用过程:用可复用代码简化设计