【问题标题】:VHDL - variable vs. signal behaviour in queueVHDL - 队列中的变量与信号行为
【发布时间】:2014-02-09 00:58:42
【问题描述】:

在一门关于可配置嵌入式系统的大学课程中(在 ZYNQ-7010 上),我们最近实现了一个(简单的)低通图像过滤器,它将一维高斯核 (0.25*[1 2 1]) 应用于数据来自块 RAM。

我们决定缓存(即排队)三个像素,然后在数据输出过程中对它们进行在线操作。我们的第一种方法是设置三个流程变量,并让它们在一个

pixel[k-2] := pixel[k-1];
pixel[k-1] := pixel[k];
pixel[k]   := RAM(address);

时尚;以下为全流程:

process (clk25)
    -- queue
    variable pixelMinus2  : std_logic_vector(11 downto 0) := (others => '0');
    variable pixelMinus1  : std_logic_vector(11 downto 0) := (others => '0');
    variable pixelCurrent : std_logic_vector(11 downto 0) := (others => '0');

    -- temporaries
    variable r : unsigned(3 downto 0);
    variable g : unsigned(3 downto 0);
    variable b : unsigned(3 downto 0);
begin
    if clk25'event and clk25 = '1' then
        pixelMinus2  := pixelMinus1;
        pixelMinus1  := pixelCurrent;
        pixelCurrent := RAM(to_integer(UNSIGNED(addrb)));

        IF slv_reg0(3) = '0' THEN 
            -- bypass filter for debugging
            dob <= pixelCurrent;
        ELSE
            -- colors are 4 bit each in a 12 bit vector
            -- division by 4 is done by right shifting by 2
            r := (
                          ("00" & unsigned(pixelMinus2(11 downto 10)))
                        + ("00" & unsigned(pixelMinus1(11 downto 10)))
                        + ("00" & unsigned(pixelMinus1(11 downto 10)))
                        + ("00" & unsigned(pixelCurrent(11 downto 10)))
                    );

            g :=  (
                          ("00" & unsigned(pixelMinus2(7 downto 6)))
                        + ("00" & unsigned(pixelMinus1(7 downto 6)))
                        + ("00" & unsigned(pixelMinus1(7 downto 6)))
                        + ("00" & unsigned(pixelCurrent(7 downto 6)))
                    );

            b :=  (
                          ("00" & unsigned(pixelMinus2(3 downto 2)))
                        + ("00" & unsigned(pixelMinus1(3 downto 2)))
                        + ("00" & unsigned(pixelMinus1(3 downto 2)))
                        + ("00" & unsigned(pixelCurrent(3 downto 2)))
                    );

            dob <= std_logic_vector(r) & std_logic_vector(g) & std_logic_vector(b);
        END IF;
    end if;
end process;

然而事实证明这是非常错误的;综合需要很长时间,并导致 LUT 使用量估计为设备能力的 130%。

我们后来将实现更改为使用信号而不是变量,这解决了所有问题;硬件表现符合预期,LUT 使用率下降到一定百分比。

我的问题是使用变量时出现问题的原因是什么,因为根据我们的理解,它应该是这样工作的。

【问题讨论】:

    标签: vhdl fpga hdl synthesis


    【解决方案1】:

    信号作为进程间通信的手段,具有精心设计的赋值语义以避免竞争条件和危险。有关血腥细节,请参阅 this Q&Athis link to "VHDL's crown jewel"

    因此当你分配pixelCurrent(信号)

    pixelCurrent <= RAM(to_integer(UNSIGNED(addrb)));
    

    直到进程挂起(对于 RTL 代码通常是在进程退出并在敏感度列表中时),分配才会发生,并且在该进程下一次在if rising_edge(clk25) 唤醒之前,结果在此进程中不可用。所以这会创建一个流水线寄存器。

    VHDL 进程中的变量的作用类似于任何其他命令式语言(C 等)中的进程中的变量 - 一旦更新,它们的新值立即可用。

    因此如下:

    pixelCurrent := RAM(to_integer(UNSIGNED(addrb)));
    
    IF slv_reg0(3) = '0' THEN 
        -- bypass filter for debugging
        dob <= pixelCurrent;
    

    将 pixelCurrent 的新值传播到流程的其余部分,生成一个巨大的设计,试图在单个时钟周期内完成所有事情。

    有两种解决方案:我的首选是将信号用于流水线寄存器,因为您可以以最自然的方式describe the pipeline(第一阶段在前)。

    第二个解决方案,使用变量作为流水线寄存器 - 讽刺的是你已经部分采用了这个解决方案 -

    pixelMinus2  := pixelMinus1;
    pixelMinus1  := pixelCurrent;
    pixelCurrent := RAM(to_integer(UNSIGNED(addrb)));
    

    是描述管道 BACKWARDS 以便对变量的赋值是在最后一次使用它的值之后进行的。

    只需将这三个赋值移到大 IF slv_reg0(3) 之后,您的变量版本就可以工作了。

    验证两种方法生成相同的硬件后,选择您认为可以实现最清晰(最容易理解)设计的方法。

    【讨论】:

      【解决方案2】:

      当一个变量在进程中用于pixelCurrent时,则值为 更新并立即可用,其中信号的值尚未准备好 直到下一个周期。

      所以当一个变量被使用时,这行代码实现了一个带异步的 RAM 基于addrb阅读:

      pixelCurrent := RAM(to_integer(UNSIGNED(addrb)));
      

      分配给信号将实现具有同步读取的 RAM,其中 从 RAM 中读取的值直到下一个周期才可用。

      典型的 FPGA 技术具有用于同步 RAM 的专用硬件 读取,但具有异步的 RAM 是用组合逻辑制成的(查找 表/LUT)。

      因此在使用变量时会出现大量的 LUT pixelCurrent 是因为综合工具尝试将 RAM 映射到 异步读入 LUT,通常需要大量 LUT 并使生成的 RAM 非常慢。

      在流水线设计中,异步 RAM 读取听起来不像 必需,因此如果pixelCurrent 是一个信号,则使用同步 RAM 并且综合工具会将 RAM 映射到内部 RAM 硬件块,其中 代码如下:

      pixelMinus2  := pixelMinus1;
      pixelMinus1  := pixelCurrent;
      pixelCurrent <= RAM(to_integer(UNSIGNED(addrb)));
      

      【讨论】:

        猜你喜欢
        • 2013-03-07
        • 2012-10-18
        • 2010-10-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-03-01
        • 1970-01-01
        相关资源
        最近更新 更多