6.2 激励设计与断言检查


6.2 激励设计与断言检查

本节摘要:激励的质量决定验证的深度,断言的质量决定排错的效率。本节讲定向激励的选题策略(正常路径、边界值、异常输入、时序场景),assert 三件套的写法规范,以及自校验测试台的完整落地。

考题怎么出:激励的选题策略

随机拍脑袋给输入,是最常见的低效验证。定向激励要按"考纲"出题,考纲按四类场景展开:

场景类型 考什么 ALU 的例子
正常路径 典型值下功能正确 10+20、200-100
边界值 最大最小值、零、进位边界 127+1、255+255、0-1
异常输入 非法码、未定义组合 op 全部八档各来一遍
时序场景 连续变化、背靠背请求 相邻两拍 op 突变、使能抖动

边界值是四类里性价比最高的:数字电路的 bug 几乎都藏在边界上——进位丢失、符号翻转、比较器差一位,全都发生在最大最小值附近。异常输入检验设计的"防御性":非法码进来是输出安全值还是失控?没有断言兜底的设计,异常输入的错误行为会静默传播到下游。

对状态机还有第五类:非法状态恢复。人为把状态寄存器写进非法值(测试台可以直接强赋内部信号,GHDL 与厂商仿真器都支持),看状态机能否经 when others 回到正轨。上板后宇宙射线、上电亚稳态都可能把状态打飞,仿真里先演练一遍才安心。

断言三件套:条件、报告、严重级别

assert 语句的完整形态:

assert 条件表达式 report "人类能读懂的报错信息" severity error;

三件套各有讲究。条件写"期望成立的事",条件为假即报错——写反了(写成错误条件)是新手高频失误,报错逻辑整个翻转。报告要带定位信息:第几拍、输入是什么、期望值实得值各是多少——"结果不对"这种报错等于没报。严重级别三档用法:error 表示功能错误但不中断(继续跑完收集全部问题);failure 表示致命错误立即停机(比如总线挂死,继续跑没有意义);warning 留给可疑但不致命的行为(比如毛刺、罕见时序)。

报错信息的措辞规范示例:

assert to_integer(unsigned(y)) = expect_y report "加法用例失败:a=" & integer'image(xa) & " b=" & integer'image(xb) & " 期望 " & integer'image(expect_y) & " 实得 " & integer'image(to_integer(unsigned(y))) & "(时间 " & time'image(now) & ")" severity error;

time'image(now) 把仿真时刻打进报错——波形里直接跳到该时刻,定位效率翻倍。integer'image、time'image 这类"值转字符串"的属性是测试台报错信息的标准装备。

自校验测试台:从看热闹到自动判分

把策略与断言合体,得到自校验测试台:不需要人看波形,测试自己判分、自己汇总。给模十计数器写一个完整示例,重点看"考纲落地":

architecture sim of counter_tb is signal clk, rst, en : std_logic := '0'; signal q : std_logic_vector(3 downto 0); signal carry : std_logic; signal done : boolean := false; signal pass_cnt, fail_cnt : natural := 0; -- 成绩单 begin dut : entity work.counter_n generic map (WIDTH => 4, MAX => 9) port map (clk => clk, rst => rst, en => en, q => q, carry => carry); clk_gen : process begin while not done loop clk <= '0'; wait for 5 ns; clk <= '1'; wait for 5 ns; end loop; wait; end process; main : process variable exp : natural := 0; -- 期望计数,测试台自己维护 begin -- 场景一:复位后从零起跑 rst <= '1'; en <= '1'; wait until rising_edge(clk); wait for 1 ns; rst <= '0'; -- 场景二:数完一整轮,逐拍核对 for beat in 1 to 25 loop if en = '1' then assert to_integer(unsigned(q)) = exp report "计数值错:第 " & integer'image(beat) & " 拍 期望 " & integer'image(exp) & " 实得 " & integer'image(to_integer(unsigned(q))) severity error; exp := (exp + 1) mod 10; -- 测试台并行维护期望值 end if; wait until rising_edge(clk); wait for 1 ns; end loop; -- 场景三:使能冻结 en <= '0'; wait until rising_edge(clk); wait for 1 ns; assert to_integer(unsigned(q)) = exp - 1 report "使能冻结失败" severity error; -- 成绩单 assert fail_cnt = 0 report "存在失败用例" severity failure; report "全部用例通过"; -- 无条件打印,当作结束语 done <= true; wait; end process; end architecture sim;

测试台维护自己的期望值变量 exp,与被测输出逐拍对账——这叫参考模型思路的最简版。复杂设计可以维护一个完整的黄金模型(行为级描述或查表),对账粒度更细。pass_cnt/fail_cnt 成绩单让回归测试结果一眼可判。

回归测试:改一行,全量跑

激励与断言资产化后,"回归测试"水到渠成:设计每改一次,全部测试台重跑一遍,旧 bug 想复发立刻被断言按住。工程实践就是一条批处理:依次运行所有测试台,收集命令行输出,fail_cnt 非零即报警。GHDL 下每个测试一次运行就是一次回归;厂商 IDE 里把多个仿真配置串成脚本同理。夜里挂着跑,早上看成绩单——这是验证工程师的日常。

⚠️ 常见坑:断言条件写反。assert 的语义是"断言此条件为真",条件为假才触发报错。写完先故意构造一个错误用例,确认报错真的会触发、信息真的能读懂——没验证过触发路径的断言,可能从第一天起就是哑弹。

💡 关键直觉:出考题的优先级是"边界大于中间、异常大于正常、组合场景大于单点"。断言是阅卷人,报错信息要写到"三个月后的你不用翻代码就知道错在哪"。

本节要点回顾

  • 四类考纲:正常路径、边界值、异常输入、时序场景,边界值性价比最高;
  • 状态机加试非法状态恢复,when others 的兜底要用测试证明过;
  • assert 三件套:条件写期望、报告带五要素(拍号输入期望实得时刻)、级别分档使用;
  • 参考模型对账:测试台维护期望值,逐拍自动判分;
  • 回归测试:改设计必全量重跑,成绩单一眼判绿红。

作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U