You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

VHDL实现FIR滤波器前几时钟无输出及算术告警求助

分析与解决你的VHDL FIR滤波器问题

我来帮你拆解一下你遇到的两个核心问题——初始无输出和仿真告警,你的怀疑方向没错,确实和信号初始状态以及流水线结构有关:

一、仿真告警的根源:寄存器初始状态未知

你看到的'U'|'X'告警,本质是因为你的D触发器没有复位机制:

  • 在VHDL仿真中,未加复位的寄存器初始值默认是未知态X,而非你在顶层信号里定义的"0000"
  • 前几个时钟周期里,s1、s2、s3这些DFF输出都是X,参与乘法运算后自然会产生X态的结果,触发告警

二、前三个时钟周期无输出:流水线延迟特性

你的4抽头FIR滤波器是流水线结构:

  1. 输入x经过3级DFF移位(s1→s2→s3),需要3个时钟周期才能让所有抽头都获得有效输入
  2. 最后还有一级输出寄存器lDFF,又会多1个时钟周期的延迟
    所以前几个周期输出为初始值是流水线FIR的正常特性,并非bug

三、具体修改方案

1. 给DFF添加复位端口

先修改你的D触发器模块,加入同步低电平复位:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity DFF is
    Port ( 
        d      : in  STD_LOGIC_VECTOR(3 downto 0);
        clk    : in  STD_LOGIC;
        rst_n  : in  STD_LOGIC; -- 新增低电平复位
        q      : out STD_LOGIC_VECTOR(3 downto 0)
    );
end DFF;

architecture Behavioral of DFF is
begin
    process(clk, rst_n)
    begin
        if rst_n = '0' then
            q <= (others => '0'); -- 复位时置0
        elsif rising_edge(clk) then
            q <= d;
        end if;
    end process;
end Behavioral;

同理修改长位宽的lDFF模块:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity lDFF is
    Port ( 
        d      : in  STD_LOGIC_VECTOR(9 downto 0);
        clk    : in  STD_LOGIC;
        rst_n  : in  STD_LOGIC;
        q      : out STD_LOGIC_VECTOR(9 downto 0)
    );
end lDFF;

architecture Behavioral of lDFF is
begin
    process(clk, rst_n)
    begin
        if rst_n = '0' then
            q <= (others => '0');
        elsif rising_edge(clk) then
            q <= d;
        end if;
    end process;
end Behavioral;

2. 修改滤波器顶层文件

添加复位端口,连接到所有DFF,同时修复位宽扩展的溢出问题:

library IEEE; 
use IEEE.STD_LOGIC_1164.ALL; 
use ieee.std_logic_unsigned.all; 

entity filter is 
port ( 
    x       : in  STD_LOGIC_VECTOR(3 downto 0); 
    clk     : in  STD_LOGIC;
    rst_n   : in  STD_LOGIC; -- 新增复位端口
    y       : out STD_LOGIC_VECTOR(9 downto 0)
); 
end filter; 

architecture struct of filter is 
type array1 is array (0 to 3) of STD_LOGIC_VECTOR(3 downto 0); 
signal coef : array1 :=( "0001", "0011", "0010", "0001"); 
signal c0, c1, c2, c3: STD_LOGIC_VECTOR(7 downto 0):="00000000"; 
signal s0, s1, s2, s3: STD_LOGIC_VECTOR(3 downto 0) :="0000"; 
signal sum: STD_LOGIC_VECTOR(9 downto 0):="0000000000"; 

component DFF is 
Port ( 
    d      : in  STD_LOGIC_VECTOR(3 downto 0); 
    clk    : in  STD_LOGIC;
    rst_n  : in  STD_LOGIC;
    q      : out STD_LOGIC_VECTOR(3 downto 0)
); 
end component; 

component lDFF is 
Port ( 
    d      : in  STD_LOGIC_VECTOR(9 downto 0); 
    clk    : in  STD_LOGIC;
    rst_n  : in  STD_LOGIC;
    q      : out STD_LOGIC_VECTOR(9 downto 0)
); 
end component; 

begin 
s0 <= x; 
c0 <= x*coef(0); 

DFF1: DFF port map(
    d      => s0,
    clk    => clk,
    rst_n  => rst_n,
    q      => s1
); 
c1 <= s1*coef(1); 

DFF2: DFF port map(
    d      => s1,
    clk    => clk,
    rst_n  => rst_n,
    q      => s2
); 
c2 <= s2*coef(2); 

DFF3: DFF port map(
    d      => s2,
    clk    => clk,
    rst_n  => rst_n,
    q      => s3
); 
c3 <= s3*coef(3); 

-- 修复位宽扩展:先把每个8位结果扩展到10位再相加,避免溢出
sum <= ("00" & c0) + ("00" & c1) + ("00" & c2) + ("00" & c3);

lDFF1: lDFF port map(
    d      => sum,
    clk    => clk,
    rst_n  => rst_n,
    q      => y
); 
end struct;

3. 更新测试平台,添加复位激励

LIBRARY ieee; 
USE ieee.std_logic_1164.ALL; 
use ieee.std_logic_unsigned.all; 

ENTITY filter_tb IS 
END filter_tb; 

ARCHITECTURE behavior OF filter_tb IS 

COMPONENT filter 
PORT( 
    x       : IN  STD_LOGIC_VECTOR(3 downto 0); 
    clk     : IN  std_logic;
    rst_n   : IN  std_logic;
    y       : OUT STD_LOGIC_VECTOR(9 downto 0) 
); 
END COMPONENT; 

--Inputs 
signal x       : STD_LOGIC_VECTOR(3 downto 0) := (others => '0'); 
signal clk     : std_logic := '0';
signal rst_n   : std_logic := '0'; -- 初始拉低复位
--Outputs 
signal y       : STD_LOGIC_VECTOR(9 downto 0); 

-- Clock period definitions 
constant clk_period : time := 10 ns; 

BEGIN 

uut: filter PORT MAP ( 
    x       => x, 
    clk     => clk,
    rst_n   => rst_n,
    y       => y 
); 

clk_process :process 
begin 
    clk <= '0'; 
    wait for clk_period/2; 
    clk <= '1'; 
    wait for clk_period/2; 
end process; 

stim_proc1: process 
begin 
    -- 先复位2个时钟周期,确保所有寄存器初始化完成
    rst_n <= '0';
    wait for 2*clk_period;
    rst_n <= '1';
    
    x <= "0001"; 
    wait for clk_period; 
    x <= "0011"; 
    wait for clk_period; 
    x <= "0010"; 
    wait for clk_period; 
    x <= "0000"; -- 继续输入0,观察完整输出
    wait for 5*clk_period;
    wait;
end process; 

END;

四、修改后的效果

  1. 复位机制会让所有寄存器初始值为0,彻底消除X态告警
  2. 你会看到第4个时钟周期后,输出y开始出现包含完整4个输入值的滤波结果,符合流水线FIR的延迟特性

内容的提问来源于stack exchange,提问作者Bill

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 06:49:53