VHDL
함수는 자주 사용되는 알고리즘을 구현하는 데 사용할 수 있는 VHDL의 하위 프로그램입니다. 함수는 0개 이상의 입력 값을 사용하며 항상 값을 반환합니다. 반환 값 외에도 함수를 프로시저와 구분하는 것은 Wait 문을 포함할 수 없다는 것입니다. 이는 함수가 항상 시뮬레이션 시간을 0으로 소비한다는 것을 의미합니다.
다른 프로그래밍 언어의 함수나 메서드에 익숙하다면 VHDL 함수를 이해하기 쉬워야 합니다. VHDL에서는 반환 값을 생략하거나 void를 반환할 수 없으며, 함수는 항상 무언가를 반환해야 하고 반환 값은 무언가에 할당되어야 합니다.
이 블로그 게시물은 기본 VHDL 자습서 시리즈의 일부입니다.
VHDL에는 두 가지 유형의 함수가 있습니다. 순수 그리고 불순한 기능. 함수가 순수하다는 것은 외부 신호를 수정하거나 읽을 수 없다는 것을 의미합니다. 특정 인수를 사용하여 순수 함수를 호출하면 항상 동일한 값을 반환할 것임을 확신할 수 있습니다. 이 기능에는 부작용이 없습니다. .
VHDL에서 함수를 선언하는 구문은 다음과 같습니다.
[pure|impure] function <function_name> (<parameter1_name> : <parameter1_type> := <default_value>;
<parameter2_name> : <parameter2_type> := <default_value>;
... ) return <return_type> is
<constant_or_variable_declaration>
begin
<code_performed_by_the_function>
return <value>
end function;
순수/불순한 키워드는 선택 사항이지만 키워드가 생략되면 기본적으로 순수로 설정됩니다. 모든 매개변수는 함수 내에서 상수로 처리됩니다. 따라서 변경할 수 없습니다. 기본값은 선택 사항이며 함수는 항상 return
에서 종료되어야 합니다. 성명서.
함수에는 in
사이에 고유한 선언 영역이 있습니다. 및 begin
키워드. 여기에 선언된 상수, 신호 또는 변수는 함수 자체 내에서만 유효하며 함수에 대한 후속 호출을 통해 값을 유지하지 않습니다.
이 튜토리얼에서는 순수 함수에 초점을 맞출 것입니다. 순수 함수는 이 시리즈의 이후 튜토리얼에서 다룰 것입니다.
이전 자습서에서는 FSM(유한 상태 머신)을 사용하여 신호등 컨트롤러 모듈을 만들었습니다. 타이머 계산이 포함된 많은 줄을 한 상태에서 다른 상태로 복사하여 붙여넣고 하나의 상수만 약간 변경했습니다.
다음 함수를 사용하여 상태 기계어 코드를 단순화하는 방법을 알아보십시오.
testbench 기능의 최종 코드 :
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity T21_FunctionTb is end entity; architecture sim of T21_FunctionTb 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.T21_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 T21_TrafficLights is generic(ClockFrequencyHz : natural); 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 T21_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; -- 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; -- Counter for counting clock periods, 1 minute max signal Counter : integer range 0 to CounterVal(Minutes => 1) +1; begin process(Clk) is begin if rising_edge(Clk) then if nRst = '0' then -- Reset values NorthRed <= '1'; NorthYellow <= '0'; NorthGreen <= '0'; WestRed <= '1'; WestYellow <= '0'; WestGreen <= '0'; State <= NorthNext; Counter <= 0; else -- Default values NorthRed <= '0'; NorthYellow <= '0'; NorthGreen <= '0'; WestRed <= '0'; WestYellow <= '0'; WestGreen <= '0'; Counter <= Counter + 1; case State is -- Red light in all directions when NorthNext => NorthRed <= '1'; WestRed <= '1'; -- If 5 seconds have passed if Counter = CounterVal(Seconds => 5) then Counter <= 0; State <= StartNorth; end if; -- Yellow light in north/south directions when StartNorth => NorthRed <= '1'; NorthYellow <= '1'; WestRed <= '1'; -- If 5 seconds have passed if Counter = CounterVal(Seconds => 5) then Counter <= 0; State <= North; end if; -- Green light in north/south directions when North => NorthGreen <= '1'; WestRed <= '1'; -- If 1 minute has passed if Counter = CounterVal(Minutes => 1) then Counter <= 0; State <= StopNorth; end if; -- Red and yellow light in north/south direction when StopNorth => NorthYellow <= '1'; WestRed <= '1'; -- If 5 seconds have passed if Counter = CounterVal(Seconds => 5) then Counter <= 0; State <= WestNext; end if; -- Red light in all directions when WestNext => NorthRed <= '1'; WestRed <= '1'; -- If 5 seconds have passedf if Counter = CounterVal(Seconds => 5) then Counter <= 0; State <= StartWest; end if; -- Yellow light in west/east direction when StartWest => NorthRed <= '1'; WestRed <= '1'; WestYellow <= '1'; -- If 5 seconds have passed if Counter = CounterVal(Seconds => 5) then Counter <= 0; State <= West; end if; -- Green light in west/east direction when West => NorthRed <= '1'; WestGreen <= '1'; -- If 1 minute has passed if Counter = CounterVal(Minutes => 1) then Counter <= 0; State <= StopWest; end if; -- Red and yellow light in west/east direction when StopWest => NorthRed <= '1'; WestYellow <= '1'; -- If 5 seconds have passed if Counter = CounterVal(Seconds => 5) then Counter <= 0; State <= NorthNext; end if; end case; end if; end if; end process; end architecture;
run 5 min
를 입력한 후의 파형 ModelSim 콘솔의 명령:
StartNorth
로/부터 전환할 때 커서가 추가된 파형 상태:
이전 튜토리얼 if Counter = ClockFrequencyHz * 5 -1 then
의 타이머 계산을 대체했습니다. 새로운 CounterVal
호출로 우리가 만든 함수:if Counter = CounterVal(Seconds => 5) then
.
첫 번째 파형 스크린샷에서 모듈의 기능이 변경되지 않았음을 알 수 있습니다. 반복적인 작업에 함수를 사용하는 것은 좋은 디자인 방법입니다. 특히 Minutes
와 같은 용어가 포함된 더 읽기 쉬운 행으로 계산을 대체할 수 있는 경우 및 Seconds
.
함수를 사용하는 또 다른 이점은 한 줄씩 수행하는 대신 모든 타이머의 구현을 한 번에 변경할 수 있다는 것입니다. 예를 들어 return TotalSeconds * ClockFrequencyHz;
를 작성했다면 CounterVal
기능이 없으면 모든 타이머가 한 클럭 주기를 너무 오래 지속했을 것입니다. 그런 다음 이것을 return TotalSeconds * ClockFrequencyHz -1;
로 변경할 수 있습니다. CounterVal
기능을 사용하면 모든 타이머가 한 번에 고정됩니다.
마지막 파형 스크린샷을 살펴보면 CounterVal
에서 반환된 타이머 값에서 1을 빼야 하는 이유를 알 수 있습니다. 기능. 이 파형은 StartNorth
정확히 5초 동안 지속되어야 합니다. State
StartNorth
로 신호 변경 , Counter
값은 0이고 다음 클럭 사이클 이후에만 변경됩니다. 따라서 최대 500개의 클록 주기를 계산했다면 StartNorth
상태는 실제로 501주기 동안 지속되었을 것입니다. 100Hz에서 실행되는 테스트벤치에서 500클럭 사이클은 정확히 5초입니다.
wait
을 포함할 수 없습니다. 진술다음 튜토리얼로 이동 »
VHDL
이전 자습서에서 For-Loop를 사용하여 정수 범위를 반복하는 방법을 배웠습니다. 그러나 고정된 정수 범위보다 루프를 더 자세히 제어하려면 어떻게 해야 할까요? 이를 위해 While 루프를 사용할 수 있습니다. While 루프는 테스트하는 표현식이 true로 평가되는 한 계속해서 동봉된 코드를 반복합니다. . 따라서 While-Loop는 얼마나 많은 반복이 필요한지 미리 알 수 없는 상황에 적합합니다. 이 블로그 게시물은 기본 VHDL 자습서 시리즈의 일부입니다. While 루프의 구문은 다음과 같습니다. while <
이전 튜토리얼에서 wait for를 사용하여 시간을 지연시키는 방법을 배웠습니다. 성명. 프로세스 루프에 대해서도 배웠습니다. 이제 허용하면 프로세스 스레드가 프로세스 내에서 영원히 반복된다는 것을 알고 있습니다. 그러나 프로세스의 시작 부분에서 한 번만 무언가를 하고 싶다면 어떻게 해야 할까요? 그런 다음 끝에 다른 코드를 반복합니까? VHDL에서 가장 단순한 종류의 루프는 loop을 사용하여 생성할 수 있습니다. 성명서. 이 블로그 게시물은 기본 VHDL 자습서 시리즈의 일부입니다. 단순 루프의 구문은 다음과 같습니다.