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