VHDL
불순한 함수는 범위 내의 모든 신호를 읽거나 쓸 수 있으며 매개변수 목록에 없는 신호도 읽을 수 있습니다. 함수에 부작용이 있다고 말합니다. .
부작용이 의미하는 바는 함수가 동일한 매개변수로 호출될 때마다 동일한 값을 반환한다는 보장이 없다는 것입니다. 함수가 매개변수 목록에 없는 신호를 읽을 수 있는 경우 반환 값도 이러한 그림자 매개변수에 따라 달라질 수 있습니다. 또한 함수는 반환 값에서 할당되지 않은 외부 신호를 변경할 수 있습니다.
이 블로그 게시물은 기본 VHDL 자습서 시리즈의 일부입니다.
순수 함수를 선언할 수 있는 모든 곳에서 순수 함수를 선언할 수 있지만 프로세스 내에서만 사용하는 것이 좋습니다. 우리가 일반적으로 신호를 선언하는 아키텍처에서 선언되면 컴파일 타임에 신호가 해당 범위에 포함되지 않습니다. 따라서 순수 함수는 아키텍처 또는 패키지 내에서 선언될 때 순수 함수가 할 수 있는 것 이상을 수행할 수 없습니다.
불순한 함수를 사용하는 동기는 주로 코드를 깔끔하게 정리하는 것입니다. 단순히 매개변수 목록에 추가하는 것만으로 순수 함수로 모든 신호를 조작할 수 있지만 매개변수 목록이 너무 길어지면 단순화하기보다는 난독화될 것입니다.
불순한 함수를 선언하는 구문은 단순히 impure function을 작성하는 것입니다. function 대신 선언할 때. 일반 함수의 구문은 함수 자습서를 참조하십시오.
이전 자습서에서는 시간 지연 값을 계산하는 함수를 사용하여 유한 상태 기계(FSM) 코드를 단순화했습니다. 각 상태 변경을 지연할 시간을 지정하기 위해 Minutes 및 Seconds 매개변수를 제공했습니다.
CounterVal 함수 반환 true , 시간이 만료되어 다음 FSM 상태로 이동할 시간이었습니다. 같은 과정에서 Counter도 재설정해야 했습니다. 그렇지 않으면 함수는 다음 상태에서 작동하지 않습니다. 타이머가 이미 만료되었습니다.
Counter 신호는 항상 0로 설정됩니다. 함수가 true를 반환했을 때. CounterVal에서 이런 일이 발생했다면 더 좋지 않을까요? 상태 기계 코드의 여러 위치 대신 기능을 사용하시겠습니까?
이 비디오 자습서에서는 불순 함수를 사용하여 이전 자습서의 FSM 코드를 개선할 것입니다.
순수하지 않은 함수 testbench의 최종 코드 :
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
-- 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.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);
-- 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 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
-- Calculate the number of clock cycles in minutes/seconds
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;
-- 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
-- This impure function reads and drives the Counter signal
-- which is not on the parameter list.
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 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 CounterExpired(Seconds => 5) then
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 CounterExpired(Seconds => 5) then
State <= North;
end if;
-- Green in north/south direction
when North =>
NorthGreen <= '1';
WestRed <= '1';
-- If 1 minute has passed
if CounterExpired(Minutes => 1) then
State <= StopNorth;
end if;
-- Yellow in north/south direction
when StopNorth =>
NorthYellow <= '1';
WestRed <= '1';
-- If 5 seconds have passed
if CounterExpired(Seconds => 5) then
State <= WestNext;
end if;
-- Red in all directions
when WestNext =>
NorthRed <= '1';
WestRed <= '1';
-- If 5 seconds have passed
if CounterExpired(Seconds => 5) then
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 CounterExpired(Seconds => 5) then
State <= West;
end if;
-- Green in west/east direction
when West =>
NorthRed <= '1';
WestGreen <= '1';
-- If 1 minute has passed
if CounterExpired(Minutes => 1) then
State <= StopWest;
end if;
-- Yellow in west/east direction
when StopWest =>
NorthRed <= '1';
WestYellow <= '1';
-- If 5 seconds have passed
if CounterExpired(Seconds => 5) then
State <= NorthNext;
end if;
end case;
end if;
end if;
end process;
end architecture;
run 5 min을 입력한 후의 파형 ModelSim 콘솔의 명령:
파형에서 볼 수 있듯이 불순 함수를 추가한 후에도 모듈 출력은 변경되지 않은 상태로 유지됩니다. 로직은 전혀 변경하지 않고 코드만 변경했습니다.
Counter 평가 신호가 FSM 코드에서 새로운 불순 함수 CounterExpired로 이동되었습니다. . Counter <= 0; Counter 지우기 라인 신호도 불순 함수로 옮겨졌습니다.
그 결과 더 쉽게 유지 관리할 수 있는 더 읽기 쉬운 FSM 코드가 생성됩니다. 이것은 주관적이지만 나에게는 CounterExpired(Seconds => 5) Counter = CounterVal(Seconds => 5)보다 눈에 더 쉽습니다. .
불순한 기능을 얼마나 사용하느냐는 전적으로 귀하와 귀하의 서비스 비용을 지불하는 사람에게 달려 있습니다. 어떤 사람들은 하위 프로그램에 숨겨진 알고리즘의 모든 원인과 결과를 보기가 더 어려울 수 있으므로 주의해서 사용해야 한다고 생각합니다. 저와 같은 다른 사람들은 의도를 분명히 하면 코드를 읽기가 더 쉬워지므로 실제로 오류가 덜 발생한다고 생각합니다.
이러한 이유로 프로덕션 모듈보다 테스트벤치 코드에서 불순한 함수를 찾을 가능성이 더 큽니다. 테스트벤치는 일반적으로 테스트 중인 모듈보다 더 복잡하며 코드 정확성에 대한 요구 사항은 RTL 코드보다 덜 엄격합니다.
다음 튜토리얼로 이동 »
VHDL
이전 자습서에서 For-Loop를 사용하여 정수 범위를 반복하는 방법을 배웠습니다. 그러나 고정된 정수 범위보다 루프를 더 자세히 제어하려면 어떻게 해야 할까요? 이를 위해 While 루프를 사용할 수 있습니다. While 루프는 테스트하는 표현식이 true로 평가되는 한 계속해서 동봉된 코드를 반복합니다. . 따라서 While-Loop는 얼마나 많은 반복이 필요한지 미리 알 수 없는 상황에 적합합니다. 이 블로그 게시물은 기본 VHDL 자습서 시리즈의 일부입니다. While 루프의 구문은 다음과 같습니다. while <
이전 튜토리얼에서 wait for를 사용하여 시간을 지연시키는 방법을 배웠습니다. 성명. 프로세스 루프에 대해서도 배웠습니다. 이제 허용하면 프로세스 스레드가 프로세스 내에서 영원히 반복된다는 것을 알고 있습니다. 그러나 프로세스의 시작 부분에서 한 번만 무언가를 하고 싶다면 어떻게 해야 할까요? 그런 다음 끝에 다른 코드를 반복합니까? VHDL에서 가장 단순한 종류의 루프는 loop을 사용하여 생성할 수 있습니다. 성명서. 이 블로그 게시물은 기본 VHDL 자습서 시리즈의 일부입니다. 단순 루프의 구문은 다음과 같습니다.