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

VHDL四位同步递增计数器功能异常排查求助

VHDL四位同步递增计数器故障排查

问题现象

  • 测试台中若不给信号F设置初始值,F会显示为U;若设置初始值为0,F就一直保持0不变
  • 计数器预期功能:rst为低电平或计数到最大值1111时复位为0
  • 时钟波形显示正常,但F的值完全没有变化
  • 代码中暂未使用n信号,该信号不影响当前问题

原计数器代码

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use IEEE.NUMERIC_STD.ALL;

entity upcount is
    Port ( n : in STD_LOGIC_VECTOR (2 downto 1);
           clk : in STD_LOGIC;
           rst : in STD_LOGIC;
           F : out STD_LOGIC_VECTOR (3 downto 0));
end upcount;

architecture Behavioral of upcount is

signal temp : std_logic_vector(3 downto 0) := "0000";

begin
process(clk,rst,n)
begin
    if (rst = '0' or temp = "1111") then 
        temp <= "0000";
    elsif( falling_edge(clk) ) then
        temp <= temp + 1;
    end if;
end process;

f <= temp;

end Behavioral;

原测试台代码

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use IEEE.NUMERIC_STD.ALL;

entity upcount is
end upcount;

architecture Behavioral of upcount is

COMPONENT upcounter 
PORT (n : in std_logic_vector(2 downto 1); 
      clk, rst : in std_logic; 
      f : out std_logic_vector(3 downto 0));
END COMPONENT;

signal clk, rst : std_logic;
signal n : std_logic_vector(2 downto 1);
signal f : std_logic_vector(3 downto 0);

begin

UUT : upcounter PORT MAP (
n => n,
clk => clk, 
rst => rst,
f => f);

tb : PROCESS 
begin 
    RST <= '0';
    n <= "00";
    f <= "0000";

    CLK <= '1';
    wait for 20 ns;
    CLK <= '0';
    wait for 20 ns;
end process;
end behavioral;

问题排查与修复

1. 测试台致命错误:驱动输出信号F

测试台中直接对f <= "0000"赋值完全错误——F是被测模块(UUT)的输出端口,测试台只能读取它的数值,不能主动驱动。这个操作会导致仿真信号冲突,直接覆盖UUT的输出,所以F会一直保持0。

2. 计数器复位逻辑逻辑混乱

当前代码把rst='0'和temp="1111"放在同一个if分支,会导致两个问题:

  • 如果rst一直保持低电平,计数器永远无法计数(复位条件持续满足)
  • 计数到1111时,会立即复位,根本看不到1111的状态,也触发不了下一次递增

正确的逻辑应该把异步复位和同步计数分开,计数到最大值的复位要放在时钟沿判断内:

if rst = '0' then
    temp <= "0000"; -- 异步复位
elsif rising_edge(clk) then
    if temp = "1111" then
        temp <= "0000"; -- 计数到最大值后同步复位
    else
        temp <= temp + 1; -- 正常递增
    end if;
end if;

3. 测试台复位信号未释放

原测试台中rst一直是'0'(复位有效状态),计数器被持续复位,自然无法计数。需要在几个时钟周期后释放复位:

tb : PROCESS 
begin 
    RST <= '0'; -- 初始复位
    n <= "00";
    wait for 40 ns; -- 等一个完整时钟周期
    RST <= '1'; -- 释放复位,开始计数
    
    -- 循环生成时钟
    loop
        CLK <= '1';
        wait for 20 ns;
        CLK <= '0';
        wait for 20 ns;
    end loop;
end process;

4. 库文件冲突

代码同时导入了STD_LOGIC_ARITH/STD_LOGIC_UNSIGNED和NUMERIC_STD,这两个库的算术操作会冲突,建议只保留NUMERIC_STD,用unsigned类型处理计数逻辑,避免类型混乱。

5. 时钟沿选择建议

行业惯例一般用rising_edge(clk)作为触发沿,原代码用falling_edge容易和测试台的时钟逻辑混淆,建议统一成上升沿触发。

修复后的代码示例

修复后的计数器代码

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity upcount is
    Port ( 
        n : in STD_LOGIC_VECTOR (2 downto 1);
        clk : in STD_LOGIC;
        rst : in STD_LOGIC;
        F : out STD_LOGIC_VECTOR (3 downto 0)
    );
end upcount;

architecture Behavioral of upcount is
    signal temp : unsigned(3 downto 0) := "0000";
begin
    process(clk, rst)
    begin
        -- 异步低电平复位
        if rst = '0' then
            temp <= "0000";
        elsif rising_edge(clk) then
            -- 计数到最大值后复位,否则递增
            if temp = "1111" then
                temp <= "0000";
            else
                temp <= temp + 1;
            end if;
        end if;
    end process;

    F <= std_logic_vector(temp);
end Behavioral;

修复后的测试台代码

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

-- 注意修改测试台实体名,避免和被测模块重名
entity upcount_tb is
end upcount_tb;

architecture Behavioral of upcount_tb is
    COMPONENT upcount 
        PORT (
            n : in std_logic_vector(2 downto 1); 
            clk, rst : in std_logic; 
            f : out std_logic_vector(3 downto 0)
        );
    END COMPONENT;

    signal clk, rst : std_logic;
    signal n : std_logic_vector(2 downto 1);
    signal f : std_logic_vector(3 downto 0);

    constant CLK_PERIOD : time := 40 ns;
begin
    UUT : upcount PORT MAP (
        n => n,
        clk => clk, 
        rst => rst,
        f => f
    );

    -- 独立的时钟生成进程
    clk_gen : process
    begin
        clk <= '0';
        wait for CLK_PERIOD/2;
        clk <= '1';
        wait for CLK_PERIOD/2;
    end process;

    -- 测试激励进程
    tb_stimulus : process 
    begin 
        rst <= '0'; -- 初始复位
        n <= "00";
        wait for 2*CLK_PERIOD; -- 等待两个时钟周期
        rst <= '1'; -- 释放复位
        
        wait; -- 持续仿真
    end process;
end Behavioral;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 14:25:52