如何在 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