前言
在芯片的前端debug阶段中我遇到了下面的几个困扰:
1.当有新增、修改端口时,由于和验证或是前后级模块沟通不及时,导致有空接高阻,而导致的X态会在很远的出口才会被发现,定位成本虽然不大但是反复几次后我已经是很烦了;
于是乎我就一直在想,不仅环境要检查代码,代码也要检查环境;
2.代码中的信号在仿真过程中的某一时刻可能已经出现异常跳变(比如说cnt减翻了但是功能上段时间没影响)但是在很靠后的时间点才累计致错,定位成本很高;
同样,不仅环境要检查代码,代码也要检查环境,接口上如果约束好了axlen的取值是0、1、3,环境或者其他模块楞发了一个2怎么办,那我也不是没干过这种事;
3.代码的结束检查,承载方式一般是设计和验证确认哪些信号需要检查,或者以文档或者表格承载,我感觉这其中的沟通成本和设计-文档-验证-代码的过程可以节约下;
根据我眼观耳闻的一些经验值,其认为以上的问题都可以通过快速生成断言来解决的,所以最近一段时间闲下来我就在考虑应该怎么做。
几行代码示例
其实仔细想下,把代码的注释用起来是个很好的习惯,毕竟注释也是代码的一部分;
output reg data_out_vld ; //ASSERT: chk_xz
output reg [DATA_WIDTH-1:0] data_out ; //ASSERT: chk_xz while data_out_vld; == [0~100,200,300] while data_out_vld; END == [0]
reg data_out_vld_ff1 ; //ASSERT: chk_xz
reg [DATA_WIDTH-1:0] data_out_ff1 ; //ASSERT: != [5~]
reg [DATA_WIDTH-1:0] num ; //ASSERT: chk_xz
reg [DATA_WIDTH-1:0] cnt ; //ASSERT: == [0~(num-1)]; END = [1]
对于以上的信号代码注释,设计了这样的规则:
1.ASSERT为关键词,表示这个注释是为了生成断言;
2.分号“;”作为分隔,前后两个是不同的断言;
3.chk_xz作为检查X态和高阻的关键词,当有when时,取其后的条件作为前置算子;
4. == []作为反正过程中的信号合理取值范围检查关键词,!= []同理,== [5~]含义就是取值范围>=5;
5.END == []或者END != []就是结束检查关键字,用来检查个计数器状态机FIFO空满啥的肯定好使,不过这个也是最难实现的,因为RTL无法感知环境的结束状态,我想了很久很可能需要动验证环境或者借助宏来实现;
OK,以上即是我拟定的一个初步的规则;
几行断言示例
由浅入深删繁就简,对于X态、Z态的检查其实是最容易也最简单的,其实只要写好模板,直接抓取信号替换进去就可以了:
`ifdef ASSERT_ON
wire assert_clk = clk;
wire assert_rst_n = rst_n;
reg after_rst = 1'b0;
always @(posedge assert_clk) if(assert_rst_n == 1'b0) ##10; after_rst <= 1'b1;
property chk_xz(info);
@(posedge assert_clk) disable iff(~after_rst)
~$isunkown(info);
endproperty
property chk_xz_valid(valid, info);
@(posedge assert_clk) disable iff(~after_rst)
valid |-> ~$isunkown(info);
endproperty
assert property chk_xz(data_out_vld_ff1) else $error("%m %s is error", "data_out_vld_ff1");
assert property chk_xz_valid(data_out_vld, data_out) else $error("%m %s is error when %s", "data_out", "data_out_vld");
`endif //ASSERT_ON
因此我觉得我应该从这里入手,逐步构建一个快速断言体系,快速注释断言一键刷新断言;
经过详细得到拆分步骤,第一步实际上还是解析RTL中的信号定义,主要把一下几个信息解析出来:port/type/width/name/note
第0回·完