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
相关产品推荐
相关产品推荐

