산업 제조
산업용 사물 인터넷 | 산업자재 | 장비 유지 보수 및 수리 | 산업 프로그래밍 |
home  MfgRobots >> 산업 제조 >  >> Industrial programming >> VHDL

VHDL 비순수 함수 활용: FSM 가독성과 유지보수성 높이기

VHDL에서 비순수 함수(impure function)는 파라미터 리스트에 없는 시그널을 포함해 자신의 어휘적 범위 내 모든 시그널에 접근하거나 수정할 수 있습니다. 이 능력으로 함수에 부작용(side effects)이 생기는데, 같은 인수를 줘도 반환값이 달라질 수 있고 직접 반환하지 않는 외부 시그널을 변경할 수도 있습니다.

순수 함수는 결정론적 동작에 한정되지만, 비순수 함수는 복잡한 상태 머신 로직을 정리할 때 반복적이거나 부작용이 있는 작업을 단일하고 잘 명명된 서브프로그램으로 옮기는 데 매우 유용합니다.

참고: 비순수 함수는 프로세스 내부에서 선언하는 게 가장 좋습니다. 아키텍처나 패키지 레벨에서 선언하면 컴파일 시점에 이미 범위 내에 있는 시그널로만 한정되므로 이점이 없습니다.

비순수 함수 사용 시기와 이유

대표적 시나리오:

비순수 함수를 쓰면 핵심 상태 머신 로직을 가독성 좋게 유지하면서 설계에 필요한 부작용 동작을 보존할 수 있습니다.

문법

비순수 함수를 선언하려면 function 앞에 impure 키워드를 붙이면 됩니다:

 impure function CounterExpired(Minutes : integer := 0; Seconds : integer := 0) return boolean; 

전체 문법은 함수 튜토리얼을 참조하세요.

실습: 비순수 함수로 FSM 리팩토링

이전에는 순수 함수 CounterVal로 시간 지연을 계산하고 타이머 만료 시 수동으로 카운터를 리셋했습니다. 다음 비순수 함수가 이 로직을 통합합니다:

테스트벤치 (T22_ImpureFunctionTb)

 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 -- 시뮬레이션 가속용 저주파 클록 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 -- 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); -- 클록 생성 Clk <= not Clk after ClockPeriod / 2; -- 테스트벤치 시퀀스 process is begin wait until rising_edge(Clk); wait until rising_edge(Clk); -- 리셋 해제 nRst <= '1'; wait; end process; end architecture; 

신호등 모듈 (T22_TrafficLights)

 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 -- 주어진 시간에 대한 클록 사이클 수 계산 순수 함수 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; -- FSM 상태 정의 type t_State is (NorthNext, StartNorth, North, StopNorth, WestNext, StartWest, West, StopWest); signal State : t_State; -- 클록 주기 카운터, 최대 1분 signal Counter : integer range 0 to ClockFrequencyHz * 60; begin process(Clk) is -- Counter를 읽고 구동하는 비순수 함수 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 -- 상태와 시그널 리셋 State <= NorthNext; Counter <= 0; NorthRed <= '1'; NorthYellow <= '0'; NorthGreen <= '0'; WestRed <= '1'; WestYellow <= '0'; WestGreen <= '0'; else -- 기본 출력 NorthRed <= '0'; NorthYellow <= '0'; NorthGreen <= '0'; WestRed <= '0'; WestYellow <= '0'; WestGreen <= '0'; Counter <= Counter + 1; case State is when NorthNext => NorthRed <= '1'; WestRed <= '1'; if CounterExpired(Seconds => 5) then State <= StartNorth; end if; when StartNorth => NorthRed <= '1'; NorthYellow <= '1'; WestRed <= '1'; if CounterExpired(Seconds => 5) then State <= North; end if; when North => NorthGreen <= '1'; WestRed <= '1'; if CounterExpired(Minutes => 1) then State <= StopNorth; end if; when StopNorth => NorthYellow <= '1'; WestRed <= '1'; if CounterExpired(Seconds => 5) then State <= WestNext; end if; when WestNext => NorthRed <= '1'; WestRed <= '1'; if CounterExpired(Seconds => 5) then State <= StartWest; end if; when StartWest => NorthRed <= '1'; WestRed <= '1'; WestYellow <= '1'; if CounterExpired(Seconds => 5) then State <= West; end if; when West => NorthRed <= '1'; WestGreen <= '1'; if CounterExpired(Minutes => 1) then State <= StopWest; end if; when StopWest => NorthRed <= '1'; WestYellow <= '1'; if CounterExpired(Seconds => 5) then State <= NorthNext; end if; end case; end if; end if; end process; end architecture; 

파형 통찰

ModelSim에서 run 5 min 명령 실행 후 시뮬레이션은 원래 FSM과 동일한 동작을 보입니다. 코드만 더 깔끔해졌습니다. 카운터 리셋 로직이 CounterExpired 안에 캡슐화되어 중복과 잠재적 에러가 줄었습니다.

VHDL 비순수 함수 활용: FSM 가독성과 유지보수성 높이기

분석

비순수 함수는 여러 FSM 상태에 흩어진 카운터 비교와 리셋을 단일 서브프로그램으로 옮겼습니다. CounterExpired(Seconds => 5)는 의도를 명확히 전달하지만 Counter = CounterVal(Seconds => 5)는 더 장황합니다.

비순수 함수를 남용하면 부작용이 가려질 수 있지만, 프로세스 지역으로 한정하면 주변 코드는 결정론적이고 감사하기 쉽습니다. 실제로는 합성 가능한 RTL보다 테스트벤치에서 더 자주 쓰이는데, 정확성이 중요하지만 미묘한 버그 위험이 낮기 때문입니다.

VHDL 비순수 함수 활용: FSM 가독성과 유지보수성 높이기

핵심 요약

다음 튜토리얼로 넘어가 고급 VHDL 기법을 탐구하세요.

VHDL

  1. 몰리브덴이 현대 산업을 형성하는 방식: 용도, 이점, 공급 역학
  2. VHDL 문자열 리스트 구현: 모범 사례와 예제
  3. VHDL 테스트벤치 시뮬레이션 우아하게 종료하기
  4. VHDL PWM 컨트롤러 구현: 설계, 시뮬레이션, FPGA 데모
  5. VHDL 난수 생성: 균일 분포부터 OSVVM까지
  6. 프로세스 내 프로시저로 VHDL FSM 설계 깔끔하게 만들기
  7. VHDL 함수 마스터하기: 효율적 설계를 위한 실전 가이드
  8. C언어 realloc() 활용법: 문법, 모범 사례, 실전 예제
  9. C언어 free() 함수 마스터하기: 실전 가이드와 예제
  10. 커터 그라인더(Cutter Grinder) 마스터하기: 실전 기술 가이드