亿迅智能制造网
工业4.0先进制造技术信息网站!
首页 | 制造技术 | 制造设备 | 工业物联网 | 工业材料 | 设备保养维修 | 工业编程 |
home  MfgRobots >> 亿迅智能制造网 >  >> Industrial programming >> VHDL

如何在 VHDL 中使用函数

函数是 VHDL 中的子程序,可用于实现常用算法。一个函数接受零个或多个输入值,它总是返回一个值。除了返回值之外,函数与过程的不同之处在于它不能包含等待语句。这意味着函数总是消耗零仿真时间。

如果你熟悉其他编程语言的函数或方法,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;

pure/impure 关键字是可选的,但如果省略该关键字,它将默认为 pure。所有参数都被视为函数内部的常量。因此,它们无法更改。默认值是可选的,并且函数必须始终在 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 的持续时间 状态,它应该持续整整五秒钟。当 State 信号更改为 StartNorth , Counter 值为 0,并且仅在下一个时钟周期后更改。因此,如果我们最多计算 500 个时钟周期,则 StartNorth 状态实际上会持续 501 个周期。我们的测试台以 100 Hz 运行,500 个时钟周期正好是 5 秒。

外卖

转到下一个教程 »


VHDL

  1. 我们如何使用钼?
  2. 如何在 VHDL 中创建字符串列表
  3. 如何在 VHDL 测试平台中停止仿真
  4. 如何在 VHDL 中创建 PWM 控制器
  5. 如何在 VHDL 中生成随机数
  6. 如何在 VHDL 中的进程中使用过程
  7. 如何在 VHDL 中使用不纯函数
  8. 如何在 VHDL 中创建有限状态机
  9. 如何在 VHDL 中使用过程
  10. C 库中的 realloc() 函数:如何使用?语法和示例
  11. C 库中的 free() 函数:如何使用?通过示例学习
  12. 如何使用刀具磨床