连续分配看似不起作用

Jon*_*art 9 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'));
Run Code Online (Sandbox Code Playgroud)

这不起作用:

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;
Run Code Online (Sandbox Code Playgroud)

模拟


但这样做:

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;
Run Code Online (Sandbox Code Playgroud)

模拟

这个"解决方案"的问题是,所述第一元件中x_delayed,通过一个样品,它应该延迟是.(代码的其余部分x_delayed(0)应该是当前的样本).

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

是什么赋予了?


编辑:

问题基本上是,即使x_delayed(0)看起来并没有在内部驱动process,也是如此.

实施Brian Drummond的想法后,它完美地运作:

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;
Run Code Online (Sandbox Code Playgroud)

模拟


编辑2:

我采取了OllieB的建议来摆脱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;
Run Code Online (Sandbox Code Playgroud)

编辑3:

根据OllieB的下一个建议,事实证明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;
Run Code Online (Sandbox Code Playgroud)

Mor*_*mer 13

在第一种情况下,x_delayed(0)实际上有两个驱动程序,在进程外部,x_delayed(0) <= x在DELAY进程中是隐式的.

该过程中的驱动程序是VHDL标准概念(称为"最长静态前缀")的结果,在VHDL-2002标准(IEEE Std 1076-2002)部分"6.1 Names"中描述,以及具有循环变量的循环结构 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) <= x.

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

查看循环的原因之一是通过替换for ... loopwith 来手动推出循环:

x_delayed(1) <= x_delayed(1-1);
x_delayed(2) <= x_delayed(2-1);
...
x_delayed(NTAPS) <= x_delayed(NTAPS-1);
Run Code Online (Sandbox Code Playgroud)

对于将NTAPS作为通用的可配置模块,这当然不是一个可用的解决方案,但是可能有趣的是看到操作然后是直观预期的.

编辑:根据评论,在上述问题之后的"编辑"部分中列出了多个解决方案.具有变量的解决方案(如果需要,允许复杂表达式)如下所示.如果不需要复杂表达式,那么根据OllieB的建议,可以将赋值减少到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;
Run Code Online (Sandbox Code Playgroud)

  • 另一种方法是在进程内部使用`x_delayed(0)<='Z';`关闭时钟控制的进程驱动程序,以便外部连续驱动值正确解析.一点躲闪,但它应该工作...... (2认同)
  • @BrianDrummond:是否可以使用x_delayed(x_delayed'high downto 1)<= x_delayed(x_delayed'high-1 downto 0); 因为这是一个静态定义的名称? (2认同)