如何避免VHDL并发断言在输入变化时误触发?附全加器示例
解决VHDL并发断言频繁触发的问题
我太懂这种困扰了——并发断言会对表达式里所有信号的变化立刻做出响应,所以每次输入(X/Y/Cin)跳变时,哪怕只是过渡瞬间,它都会跑一遍检查,导致报告满天飞。针对你的全加器例子,我给你几个实用的解决思路:
方案1:把断言移到测试台,完全控制检查时机
最推荐的做法是把验证逻辑从DUT里剥离,放到测试台中,只在输入信号稳定后再执行断言检查。这样既能保持DUT的简洁(不混入验证代码),又能精准控制检查时机。
修改后的DUT(移除断言)
library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; entity Full_Adder is port( X, Y, Cin : in std_logic; sum, Cout : out std_logic); end Full_Adder; architecture bhv of Full_Adder is signal s_sum : std_logic:='0'; signal s_Cout : std_logic:='0'; begin s_sum <= (X xor Y) xor Cin; s_Cout <= (X and (Y or Cin)) or (Cin and Y); sum<=s_sum; Cout<=s_Cout; end bhv;
修改后的测试台(添加定时断言)
Library IEEE; USE IEEE.Std_logic_1164.all; entity tb_fulladder is end tb_fulladder; architecture behavioral of tb_fulladder is component Full_Adder port( X, Y, Cin : in std_logic; sum, Cout : out std_logic ); end component; signal A,B,Cin: std_logic:='0'; signal S,Cout: std_logic; begin structural_adder: Full_Adder port map ( X => A, Y => B, Cin => Cin, sum => S, Cout => Cout ); process begin -- 测试向量1 A <= '0'; B <= '0'; Cin <= '0'; wait for 100 ns; assert (S = ((A xor B) xor Cin)) report "Erreur de somme pour (0,0,0)" severity note; assert (Cout = ((A and (B or Cin)) or (Cin and B))) report "Erreur de retenue pour (0,0,0)" severity note; -- 测试向量2 A <= '0'; B <= '0'; Cin <= '1'; wait for 100 ns; assert (S = ((A xor B) xor Cin)) report "Erreur de somme pour (0,0,1)" severity note; assert (Cout = ((A and (B or Cin)) or (Cin and B))) report "Erreur de retenue pour (0,0,1)" severity note; -- 测试向量3 A <= '0'; B <= '1'; Cin <= '0'; wait for 100 ns; assert (S = ((A xor B) xor Cin)) report "Erreur de somme pour (0,1,0)" severity note; assert (Cout = ((A and (B or Cin)) or (Cin and B))) report "Erreur de retenue pour (0,1,0)" severity note; -- 测试向量4 A <= '0'; B <= '1'; Cin <= '1'; wait for 100 ns; assert (S = ((A xor B) xor Cin)) report "Erreur de somme pour (0,1,1)" severity note; assert (Cout = ((A and (B or Cin)) or (Cin and B))) report "Erreur de retenue pour (0,1,1)" severity note; -- 测试向量5 A <= '1'; B <= '0'; Cin <= '0'; wait for 100 ns; assert (S = ((A xor B) xor Cin)) report "Erreur de somme pour (1,0,0)" severity note; assert (Cout = ((A and (B or Cin)) or (Cin and B))) report "Erreur de retenue pour (1,0,0)" severity note; -- 测试向量6 A <= '1'; B <= '0'; Cin <= '1'; wait for 100 ns; assert (S = ((A xor B) xor Cin)) report "Erreur de somme pour (1,0,1)" severity note; assert (Cout = ((A and (B or Cin)) or (Cin and B))) report "Erreur de retenue pour (1,0,1)" severity note; -- 测试向量7 A <= '1'; B <= '1'; Cin <= '0'; wait for 100 ns; assert (S = ((A xor B) xor Cin)) report "Erreur de somme pour (1,1,0)" severity note; assert (Cout = ((A and (B or Cin)) or (Cin and B))) report "Erreur de retenue pour (1,1,0)" severity note; -- 测试向量8 A <= '1'; B <= '1'; Cin <= '1'; wait for 100 ns; assert (S = ((A xor B) xor Cin)) report "Erreur de somme pour (1,1,1)" severity note; assert (Cout = ((A and (B or Cin)) or (Cin and B))) report "Erreur de retenue pour (1,1,1)" severity note; wait; -- 终止测试进程 end process; end behavioral;
方案2:在DUT中添加触发信号,按需启用断言
如果必须在DUT中保留断言,可以新增一个check_enable输入信号,只有当该信号有效时,断言才会执行。测试台可以在输入稳定后拉高这个信号,触发检查。
修改后的DUT(带触发信号)
library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; entity Full_Adder is port( X, Y, Cin : in std_logic; check_enable : in std_logic; -- 新增断言触发信号 sum, Cout : out std_logic ); end Full_Adder; architecture bhv of Full_Adder is signal s_sum : std_logic:='0'; signal s_Cout : std_logic:='0'; begin s_sum <= (X xor Y) xor Cin; s_Cout <= (X and (Y or Cin)) or (Cin and Y); sum<=s_sum; Cout<=s_Cout; -- 仅当check_enable为'1'时执行断言检查 assert (check_enable = '0' or s_sum =((X xor Y) xor Cin)) report "Erreur de somme" severity note; assert (check_enable = '0' or s_Cout = ((X and (Y or Cin)) or (Cin and Y))) report "Erreur de retenue" severity note; end bhv;
修改后的测试台(控制触发信号)
Library IEEE; USE IEEE.Std_logic_1164.all; entity tb_fulladder is end tb_fulladder; architecture behavioral of tb_fulladder is component Full_Adder port( X, Y, Cin : in std_logic; check_enable : in std_logic; sum, Cout : out std_logic ); end component; signal A,B,Cin, check_en: std_logic:='0'; signal S,Cout: std_logic; begin structural_adder: Full_Adder port map ( X => A, Y => B, Cin => Cin, check_enable => check_en, sum => S, Cout => Cout ); process begin check_en <= '0'; -- 默认关闭断言检查 -- 测试向量1 A <= '0'; B <= '0'; Cin <= '0'; wait for 90 ns; check_en <= '1'; wait for 10 ns; -- 稳定后开启检查 check_en <= '0'; -- 测试向量2 A <= '0'; B <= '0'; Cin <= '1'; wait for 90 ns; check_en <= '1'; wait for 10 ns; check_en <= '0'; -- 剩余测试向量重复上述逻辑即可... wait; end process; end behavioral;
方案3:在DUT中延迟检查(适合组合逻辑)
对于纯组合逻辑,可以在断言前引入一个小延迟,确保输入变化后的过渡态消失后再执行检查。不过这种方法依赖于具体时序,灵活性较差:
-- 在DUT的架构中添加带延迟的进程 process(X, Y, Cin) begin wait for 1 ns; -- 等待信号稳定(时间需根据实际设计调整) assert (s_sum =((X xor Y) xor Cin)) report "Erreur de somme" severity note; assert (s_Cout = ((X and (Y or Cin)) or (Cin and Y))) report "Erreur de retenue" severity note; end process;
总结
优先推荐方案1,这种方式既能保证DUT的纯净性,又能完全掌控断言的触发时机,是验证领域的通用做法。如果必须在DUT中保留断言,方案2的触发信号方式更可靠,适合需要复用DUT的多场景测试。
内容的提问来源于stack exchange,提问作者Basil1402
相关产品推荐
相关产品推荐

