我正在研究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)
似乎没有被驱逐到process
,it 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) <= (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;
答案 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;