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

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

  1. 몰리브덴은 어떻게 사용합니까?
  2. VHDL에서 문자열 목록을 만드는 방법
  3. VHDL 테스트벤치에서 시뮬레이션을 중지하는 방법
  4. VHDL에서 PWM 컨트롤러를 만드는 방법
  5. VHDL에서 난수를 생성하는 방법
  6. VHDL의 프로세스에서 프로시저를 사용하는 방법
  7. VHDL에서 함수를 사용하는 방법
  8. C 라이브러리의 realloc() 함수:어떻게 사용합니까? 구문 및 예
  9. C 라이브러리의 free() 함수:어떻게 사용합니까? 예제로 배우기
  10. 커터 그라인더 사용 방법