VHDL寄存器与增量器电路仿真异常:信号显示X的问题排查
问题分析:闭环PC电路仿真出现未知值(X)的原因及修复
问题描述
我设计了一套由寄存器和增量器组成的闭环电路,二者互为输入,预期每个时钟上升沿PC值增加4。对应的VHDL代码如下:
library IEEE; use IEEE.STD_LOGIC_1164.all; entity Register1 is port ( CLK : in STD_LOGIC; d : in STD_LOGIC_VECTOR(31 downto 0); q : out STD_LOGIC_VECTOR(31 downto 0) ); end; architecture Behavioral of Register1 is begin process (CLK) begin if rising_edge(CLK) then q <= d; end if; end process; end; library IEEE; use IEEE.STD_LOGIC_1164.all; use IEEE.NUMERIC_STD.all; entity Incrementer is port ( din : in STD_LOGIC_VECTOR(31 downto 0); dout : out STD_LOGIC_VECTOR(31 downto 0) ); end; architecture DataFLow of Incrementer is begin dout <= STD_LOGIC_VECTOR(UNSIGNED(din) + 4); end; library IEEE; use IEEE.STD_LOGIC_1164.ALL; entity Test is end Test; architecture Struct of Test is component Register1 is port ( CLK : in STD_LOGIC; d : in STD_LOGIC_VECTOR(31 downto 0); q : out STD_LOGIC_VECTOR(31 downto 0) ); end component; component Incrementer is port ( din : in STD_LOGIC_VECTOR(31 downto 0); dout : out STD_LOGIC_VECTOR(31 downto 0) ); end component; signal CLK : STD_LOGIC := '0'; signal PCN : STD_LOGIC_VECTOR(31 downto 0) := (others => '0'); signal PC : STD_LOGIC_VECTOR(31 downto 0) := (others => '0'); constant CLK_period: TIME := 10 ns; begin -- The concurent clock signal CLK <= not CLK after CLK_period/2; PCreg: Register1 port map ( CLK, d => PCN, q => PC ); Incr1: Incrementer port map ( din => PC, dout => PCN ); -- The stimulus process verify: process begin wait for 80 ns; end process; end;
但在Vivado仿真器中,相关信号PC、PCN均显示为“X”,请问我哪里出错了?
错误原因
核心问题是寄存器无确定初始值导致的未知态循环:
- 你的
Register1没有复位逻辑或内部初始值,仿真时寄存器输出q默认是未知态X,即使Testbench里给PC信号赋了初始0,也会被寄存器的未知输出覆盖。 - 未知态
X输入到增量器后,计算UNSIGNED(X)+4的结果还是X,这个X又被寄存器在时钟沿锁存,形成永久的未知态循环,永远无法跳出。
修复方案
方案1:添加异步复位(硬件仿真通用)
给寄存器添加异步复位信号,复位时强制输出确定初始值,从根源打破未知态循环,这也是硬件设计的标准做法:
修改后的Register1代码:
library IEEE; use IEEE.STD_LOGIC_1164.all; entity Register1 is port ( CLK : in STD_LOGIC; RST_N : in STD_LOGIC; -- 低有效异步复位 d : in STD_LOGIC_VECTOR(31 downto 0); q : out STD_LOGIC_VECTOR(31 downto 0) ); end; architecture Behavioral of Register1 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;
同步修改Testbench,添加复位信号并触发初始复位:
architecture Struct of Test is component Register1 is port ( CLK : in STD_LOGIC; RST_N : in STD_LOGIC; d : in STD_LOGIC_VECTOR(31 downto 0); q : out STD_LOGIC_VECTOR(31 downto 0) ); end component; component Incrementer is port ( din : in STD_LOGIC_VECTOR(31 downto 0); dout : out STD_LOGIC_VECTOR(31 downto 0) ); end component; signal CLK : STD_LOGIC := '0'; signal RST_N : STD_LOGIC := '0'; -- 初始复位有效 signal PCN : STD_LOGIC_VECTOR(31 downto 0); signal PC : STD_LOGIC_VECTOR(31 downto 0); constant CLK_period: TIME := 10 ns; begin CLK <= not CLK after CLK_period/2; -- 复位信号:仿真开始后1个时钟周期释放复位 process begin RST_N <= '0'; wait for CLK_period; RST_N <= '1'; wait; end process; PCreg: Register1 port map ( CLK => CLK, RST_N => RST_N, d => PCN, q => PC ); Incr1: Incrementer port map ( din => PC, dout => PCN ); verify: process begin wait for 80 ns; end process; end;
方案2:给寄存器内部信号赋初始值(仅仿真有效)
如果不需要硬件复位逻辑,仅为了快速验证仿真,可以给寄存器内部存储信号添加初始值(注意:该方法仅适用于仿真,硬件中不支持):
architecture Behavioral of Register1 is signal reg_data : STD_LOGIC_VECTOR(31 downto 0) := (others => '0'); -- 初始化为0 begin process (CLK) begin if rising_edge(CLK) then reg_data <= d; end if; end process; q <= reg_data; end;
验证效果
修复后仿真时:
- 复位释放(或仿真启动)后,第一个时钟上升沿PC会被赋值为4(PCN由0+4得到)
- 后续每个时钟上升沿,PC依次变为8、12、16...完全符合每个时钟沿加4的预期。
内容的提问来源于stack exchange,提问作者Nick
相关产品推荐
相关产品推荐

