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