连续分配似乎不起作用 [英] Continuous assignment seemingly not working

查看:31
本文介绍了连续分配似乎不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

type slv32_array 是 std_logic_vector(31 downto 0) 的数组(自然范围<>);...信号 x_delayed : slv32_array(0 to NTAPS-1) := (others => (others => '0'));

这不起作用:

x_delayed(0) <= x;-- 连续赋值延迟:进程(samp_clk)开始如果rising_edge(samp_clk) 那么for i in 1 到 NTAPS-1 循环x_delayed(i) <= x_delayed(i-1);结束循环;万一;-- 上升沿(samp_clk)结束过程;

<小时>

但这确实是:

延迟:进程(samp_clk)开始如果rising_edge(samp_clk) 那么x_delayed(0) <= x;-- 注册输入for i in 1 到 NTAPS-1 循环x_delayed(i) <= x_delayed(i-1);结束循环;万一;-- 上升沿(samp_clk)结束过程;

这个解决方案"的问题在于 x_delayed 中的第一个元素延迟了一个样本,它应该.(其余代码期望 x_delayed(0) 成为 当前 示例).

我使用的是 Xilinx ISE 13.2,使用 ISim 进行仿真,但也证实了使用 ModelSim 进行仿真.

什么给?

<小时>

问题本质上是,即使 x_delayed(0) 似乎没有在 process 内部被驱动,来摆脱for 循环.我不得不改变它,因为我的 x_delayed 是从 (0 到 NTAPS-1) 索引的,但我们最终得到了这个漂亮的小过程:

x_delayed(0) <= x;延迟:进程(samp_clk)开始x_delayed(0) <= (others => 'Z');如果rising_edge(samp_clk) 那么x_delayed(1 to x_delayed'high) <= x_delayed(0 to x_delayed'high-1);万一;-- 上升沿(samp_clk)结束过程;

<小时>

编辑 3:

按照OllieB 的下一个建议,它变成了在他之前的更改之后,x_delayed(0) <= (others => 'Z') 是不必要的.以下工作正常:

x_delayed(0) <= x;延迟:进程(samp_clk)开始如果rising_edge(samp_clk) 那么x_delayed(1 to x_delayed'high) <= x_delayed(0 to x_delayed'high-1);万一;结束过程;

解决方案

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

进程内的驱动程序是 VHDL 标准概念的结果称为最长静态前缀",在 VHDL-2002 标准(IEEE Std1076-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) <= 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 的可配置模块来说,这当然不是一个可用的解决方案,因为一个通用的,但看到操作然后是作为直觉预期.

编辑:根据评论,在上述问题之后的编辑"部分列出了多个解决方案.下面显示了一个带有变量的解决方案,如果需要,它允许使用复杂的表达式.如果不需要复杂的表达式,则按照 OllieB 的建议 可以减少对 x_delayed(1 to x_delayed_dir'high) <= x_delayed(0 to x_delayed_dir'high-1) 的赋值:

x_delayed(0) <= x;延迟:进程(samp_clk)变量 x_delayed_v : slv32_array(1 to NTAPS-1);开始如果rising_edge(samp_clk) 那么for i in 1 到 NTAPS-1 循环x_delayed_v(i) := x_delayed(i-1);-- 更复杂的操作也是可能的结束循环;x_delayed(1 to x_delayed_dir'high) <= x_delayed_v;万一;-- 上升沿(samp_clk)结束过程;

I'm working on a FIR filter, specifically the delay line. x_delayed is initialized to all zeros.

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'));

This does not work:

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;


But this does:

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;

The problem with this "solution" is that the first element in x_delayed is delayed by one sample, which it should not be. (The rest of the code expects x_delayed(0) to be the current sample).

I'm using Xilinx ISE 13.2, simulating with ISim, but this was also confirmed simulating with ModelSim.

What gives?


Edit:

The problem was essentially that, even though x_delayed(0) didn't appear to be driven inside the process, it was.

After implementing Brian Drummond's idea it works perfectly:

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;


Edit 2:

I took OllieB's suggestion for getting rid of the for loop. I had to change it, since my x_delayed is indexed from (0 to NTAPS-1), but we end up with this nice looking little process:

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;


Edit 3:

Following OllieB's next suggestion, it turns out the x_delayed(0) <= (others => 'Z') was unnecessary, following his previous change. The following works just fine:

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;

解决方案

In the first case, the x_delayed(0) actually has two drivers, out outside the process, being x_delayed(0) <= x, and an implicit one inside the DELAY process.

The driver inside the process is a consequence of a VHDL standard concept called "longest static prefix", described in VHDL-2002 standard (IEEE Std 1076-2002) section "6.1 Names", and the loop construction with a loop variable i, whereby the longest static prefix for x_delayed(i) is x_delayed.

The VHDL standard then further describes drives for processes in section "12.6.1 Drivers", which says "... There is a single driver for a given scalar signal S in a process statement, provided that there is at least one signal assignment statement in that process statement and that the longest static prefix of the target signal of that signal assignment statement denotes S ...".

So as a (probably surprising) consequence the x_delayed(0) has a driver in the DELAY process, which drives all std_logic elements to 'U' since unassigned, whereby the std_logic resolution function causes the resulting value to be 'U', no matter what value is driven by the external x_delayed(0) <= x.

But in the case of your code, there seems to be more to it, since there actually are some "0" values in the simulation output for x_delayed(0), for what I can see from the figures. However, it is hard to dig further into this when I do not have the entire code.

One way to see that the loop is the reason, is to manually roll out the loop by replacing the for ... loop with:

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

This is of course not a usable solution for configurable modules with NTAPS as a generic, but it may be interesting to see that the operation then is as intuitively expected.

EDIT: Multiple solutions are listed in "edit" sections after the question above, based on comments. A solution with variable, which allows for complex expressions if required, is shown below. If complex expression is not required, then as per OllieB's suggestion it is possible to reduce the assign to 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;

这篇关于连续分配似乎不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆