连续分配看似不起作用

时间:2013-08-15 07:16:59

标签: vhdl

我正在研究FIR滤波器,特别是延迟线。 x_delayed初始化为全零。

type slv32_array is array(natural range <>) of std_logic_vector(31 downto 0);
...
signal x_delayed : slv32_array(0 to NTAPS-1) := (others => (others => '0'));

这不起作用:

x_delayed(0) <= x;             -- Continuous assignment

DELAYS : process(samp_clk)
begin
    if rising_edge(samp_clk) then
        for i in 1 to NTAPS-1 loop
            x_delayed(i) <= x_delayed(i-1);
        end loop;
    end if; -- rising_edge(samp_clk)
end process;

Simulation


但这样做:

DELAYS : process(samp_clk)
begin
    if rising_edge(samp_clk) then
        x_delayed(0) <= x;           -- Registering input
        for i in 1 to NTAPS-1 loop
            x_delayed(i) <= x_delayed(i-1);
        end loop;
    end if; -- rising_edge(samp_clk)
end process;

Simulation

这个“解决方案”的问题是x_delayed中的第一个元素被延迟了一个样本,它应该。 (代码的其余部分希望x_delayed(0)成为当前样本。)

我正在使用Xilinx ISE 13.2,使用ISim进行模拟,但这也证实了使用ModelSim进行模拟。

是什么给出的?


修改

问题基本上是,即使x_delayed(0)似乎没有被驱逐到processit was

实施Brian Drummond's idea后,它完美无缺:

x_delayed(0) <= x;

-- Synchronous delay cycles.
DELAYS : process(samp_clk)
begin
    -- Disable the clocked driver, allowing the continuous driver above to function correctly.
    -- https://stackoverflow.com/questions/18247955/#comment26779546_18248941
    x_delayed(0) <= (others => 'Z');        

    if rising_edge(samp_clk) then
        for i in 1 to NTAPS-1 loop
            x_delayed(i) <= x_delayed(i-1);
        end loop;
    end if; -- rising_edge(samp_clk)
end process;

Simulation


编辑2:

我用OllieB's suggestion来摆脱for循环。我必须更改它,因为我的x_delayed已从(0 to NTAPS-1)编入索引,但我们最终得到了这个漂亮的小程序:

x_delayed(0) <= x;

DELAYS : process(samp_clk)
begin
    x_delayed(0) <= (others => 'Z');
    if rising_edge(samp_clk) then
        x_delayed(1 to x_delayed'high) <= x_delayed(0 to x_delayed'high-1);
    end if; -- rising_edge(samp_clk)
end process;

编辑3:

OllieB's next suggestion之后,事实证明x_delayed(0) <= (others => 'Z')在他之前的更改之后是不必要的。以下工作正常:

x_delayed(0) <= x;

DELAYS : process(samp_clk)
begin    
    if rising_edge(samp_clk) then
        x_delayed(1 to x_delayed'high) <= x_delayed(0 to x_delayed'high-1);
    end if;
end process;

4 个答案:

答案 0 :(得分:12)

在第一种情况下,x_delayed(0)实际上有两个驱动程序,在外面 进程,x_delayed(0) <= x,以及DELAY内的隐式进程 过程

流程中的驱动程序是VHDL标准概念的结果 被称为&#34;最长的静态前缀&#34;,在VHDL-2002标准(IEEE Std 1076-2002)section&#34; 6.1 Names&#34;,以及带有循环变量的循环结构 i,其中x_delayed(i)的最长静态前缀为x_delayed

VHDL标准然后进一步描述了部分过程的驱动器 &#34; 12.6.1驱动程序&#34;,表示&#34; ...给定标量有一个驱动程序 如果存在至少一个信号,则在过程语句中的信号S. 该进程语句中的赋值语句和最长的静态 该信号赋值语句的目标信号的前缀表示S ...&#34;。

因此x_delayed(0)有一个(可能是令人惊讶的)后果 DELAY进程,它将所有std_logic元素驱动到&#39; U&#39;从未分配, 由此std_logic解析函数导致结果值为&#39; U&#39; 无论外部x_delayed(0) <= x驱动什么值。

但是对于你的代码,它似乎还有更多,因为实际上有一些&#34; 0&#34;我可以从图中看到x_delayed(0)的模拟输出中的值。但是,当我没有完整的代码时,很难深入研究。

一种看待循环的原因,就是手动推出循环 将for ... loop替换为:

x_delayed(1) <= x_delayed(1-1);
x_delayed(2) <= x_delayed(2-1);
...
x_delayed(NTAPS) <= x_delayed(NTAPS-1);

对于具有NTAPS的可配置模块,这当然不是一个可用的解决方案 一般,但可能有趣的是看到操作然后是 直觉上预期。

编辑:&#34;编辑&#34;中列出了多种解决方案。根据评论,在上述问题之后的部分。具有变量的解决方案(如果需要,允许复杂表达式)如下所示。如果不需要复杂表达式,那么根据OllieB's suggestion可以将赋值减少到x_delayed(1 to x_delayed_dir'high) <= x_delayed(0 to x_delayed_dir'high-1)

x_delayed(0) <= x;
DELAYS : process(samp_clk)
  variable x_delayed_v : slv32_array(1 to NTAPS-1);
begin
  if rising_edge(samp_clk) then
    for i in 1 to NTAPS-1 loop
      x_delayed_v(i) := x_delayed(i-1);  -- More complex operations are also possible
    end loop;
    x_delayed(1 to x_delayed_dir'high) <= x_delayed_v;
  end if;  -- rising_edge(samp_clk)
end process;

答案 1 :(得分:1)

在详细说明期间,无论循环迭代器的范围如何,都会为x_delayed中的所有元素创建驱动程序。因此,x_delayed(0)有两个与之关联的驱动程序。 Std_Logic和Std_Logic_Vector是resoved类型(即,当多个驱动程序与这些类型的信号关联时,已解析的函数将通过查找std包中的表来确定信号的值。请参阅 VHDL编码样式和方法论了解更多详情。

答案 2 :(得分:0)

你遇到问题的原因是逻辑认为你有两件事同时分配到同一个信号 - 连续分配和寄存器分配循环。 与寄存器实施保持一致。

修改
如果你有modelsim,你可以使用'trace x'选项并查看它的来源。
可能是另一个模拟器也有这个功能,但对于modelsim我肯定它有效

答案 3 :(得分:0)

在你不工作的例子中     x_delayed(0)&lt; = x;

非常容易

process(x)
begin
   x_delayed(0) <= x;
end process;

因此,只有当x发生变化时,该过程才会分配x_delayed(0)。因为这是一个信号对齐,x_delayed(0)不会立即改变,它会在一个delta周期后改变。因此,当调用进程DELAYS时,x_delayed(0)的赋值尚未发生!

如果可以,请在流程中为x_delayed使用变量。

x_delayed(0) := x;