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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 15:29:49