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 자습서 시리즈의 일부입니다. 단순 루프의 구문은 다음과 같습니다.