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