【问题标题】:Continuous assignment seemingly not working连续分配似乎不起作用
【发布时间】:2013-08-15 07:16:58
【问题描述】:

我正在研究 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;


但这确实:

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;

这个“解决方案”的问题是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;


编辑 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) &lt;= (others =&gt; '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;

【问题讨论】:

  • x_delayed 是一个寄存器库(或者看起来如此)。您打算如何在没有进程的情况下将值输入寄存器?顺便说一句,在 std_logic 中使用 std_logic_vector(x 是 std_logic_vector 还是整数?所有负值是什么?)不是给你一些警告吗?
  • 您能指定 x 和 x_delayed 的类型吗?从您粘贴的内容来看,您似乎正在将 x(31 downto 0) 分配给 x_delayed(0)。 x 是如何定义的?
  • 啊,我明白了:x_delayed 是一个 x 类型的数组。从代码中问题并没有立即显现出来。您能否具体说明您正在使用哪些工具?
  • 抱歉,我试图精简问题,但遗漏了一些重要部分。这里的一切都是std_logic_vector(31 downto 0)。我正在使用赛灵思 ISE。
  • 再一次,我手头没有标准,但我相信这是因为 x_delayed 的移位版本是本地静态切片名称,而索引版本使用变量作为其索引,所以不是本地静态的。

标签: vhdl


【解决方案1】:

在第一种情况下,x_delayed(0) 实际上有两个驱动程序,在外部 进程,为x_delayed(0) &lt;= x,并在 DELAY 中隐含一个 过程。

进程内的驱动程序是 VHDL 标准概念的结果 称为“最长静态前缀”,在 VHDL-2002 标准(IEEE Std 1076-2002) 部分“6.1 名称”,以及带有循环变量的循环构造 i,其中x_delayed(i) 的最长静态前缀是x_delayed

VHDL 标准随后在章节中进一步描述了进程的驱动器 “12.6.1 驱动程序”,它表示“......给定标量有一个驱动程序 过程语句中的信号 S,前提是至少有一个信号 那个进程语句中的赋值语句和那个最长的静态 该信号分配语句的目标信号的前缀表示 S ..."。

所以作为一个(可能令人惊讶的)结果,x_delayed(0) 有一个驱动程序 DELAY 进程,它将所有 std_logic 元素驱动为“U”,因为未分配, 从而 std_logic 解析函数导致结果值为“U”, 无论外部x_delayed(0) &lt;= x驱动什么值。

但就您的代码而言,似乎还有更多内容,因为在x_delayed(0) 的模拟输出中实际上有一些“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 的可配置模块,这当然不是一个可用的解决方案 一个通用的,但有趣的是看到操作然后是 直观地预期。

编辑:根据 cmets,在上述问题之后的“编辑”部分中列出了多个解决方案。下面显示了一个带有变量的解决方案,如果需要,它允许复杂的表达式。如果不需要复杂的表达式,那么根据OllieB's suggestion 可以减少分配到x_delayed(1 to x_delayed_dir'high) &lt;= 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;

【讨论】:

  • 另一种方法是在进程内部关闭带有x_delayed(0) &lt;= 'Z';的时钟进程驱动程序,以便正确解析外部连续驱动值。有点麻烦,但它应该可以工作......
  • @Brian Drummond:你认为综合工具能正确处理这个问题吗?
  • 相当肯定 XST 会解决它; Synplicity可能不会。它也可能取决于工具版本;他们不断变化;通常是为了更好。只有一种方法可以确定...
  • 是的,知道x_delayed(0) 正在进程内部驱动,这令人惊讶!我在另一个例子中也注意到了这一点,并且非常困惑。你写的很详细,谢谢!我很惊讶 XST 没有抱怨多个驱动程序。
  • @BrianDrummond: 是否可以使用 x_delayed(x_delayed'high downto 1)
【解决方案2】:

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

【讨论】:

  • "为 x_delayed 中的所有元素创建驱动程序,无论循环迭代器的范围如何" - 确实!我没有意识到这一点。
【解决方案3】:

你有问题的原因是逻辑认为你有两个东西同时分配给同一个信号 - 继续分配和寄存器分配循环。 与注册实现保持一致。

编辑
如果您有 modelsim,您可以使用“trace x”选项并查看它的来源。
可能是其他模拟器也有这个功能,但是对于modelsim我确定它可以工作

【讨论】:

  • 我没有看到两个东西在任何地方分配相同的信号。该循环将 1 分配给 NTAPS-1,而 0 则从 x 输入分配。
  • 我不是反对你的人。但是现在其他人已经解释得更详细了,我看你是对的,x_delayed(0)确实实际上有两个驱动程序。我投票赞成你补偿:-)
  • @JonathonReinhart 谢谢:)。老实说,在我回答你几个小时后,我们在工作中遇到了一个非常相似的问题,我立即想到了这个问题,但最终结果证明是 QC 测试平台将所有问题都推到了“X” :)
【解决方案4】:

在你不工作的例子中 x_delayed(0)

相当于

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

所以只有当 x 改变时,进程才会分配 x_delayed(0)。因为这是一个信号分配,所以 x_delayed(0) 不会立即改变,它会在一个增量周期后改变。因此,当进程DELAYS被调用时,x_delayed(0)的赋值还没有发生!

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

x_delayed(0) := x;

【讨论】:

  • 即使有从xx_delayed(0) 的增量延迟,x_delayed(0) 也不应该是未定义的,所以这个解释听起来不正确。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-03
  • 2020-12-30
  • 1970-01-01
  • 1970-01-01
  • 2018-06-07
  • 1970-01-01
相关资源
最近更新 更多