VHDL实现FIR滤波器前几时钟无输出及算术告警求助
分析与解决你的VHDL FIR滤波器问题
我来帮你拆解一下你遇到的两个核心问题——初始无输出和仿真告警,你的怀疑方向没错,确实和信号初始状态以及流水线结构有关:
一、仿真告警的根源:寄存器初始状态未知
你看到的'U'|'X'告警,本质是因为你的D触发器没有复位机制:
- 在VHDL仿真中,未加复位的寄存器初始值默认是未知态
X,而非你在顶层信号里定义的"0000" - 前几个时钟周期里,
s1、s2、s3这些DFF输出都是X,参与乘法运算后自然会产生X态的结果,触发告警
二、前三个时钟周期无输出:流水线延迟特性
你的4抽头FIR滤波器是流水线结构:
- 输入
x经过3级DFF移位(s1→s2→s3),需要3个时钟周期才能让所有抽头都获得有效输入 - 最后还有一级输出寄存器
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;
四、修改后的效果
- 复位机制会让所有寄存器初始值为0,彻底消除
X态告警 - 你会看到第4个时钟周期后,输出
y开始出现包含完整4个输入值的滤波结果,符合流水线FIR的延迟特性
内容的提问来源于stack exchange,提问作者Bill
相关产品推荐
相关产品推荐

