第四课
Debugging simulation mismatches
if (data == 3)是判断语句,而误写成 if(data = 3)就会先把值赋给data,再判断data是否为3,因此判断语句永远为真。
用(3 == data)可以避免误操作,只要少一个等号就会报错。
- 本章学习内容
- 使用+race选项对竞争冒险现象生成报告 e.g.对一个数据同时进行读和写
- 使用$vcdplusdeltacycleon(并不是特别常用)定位产生竞争冒险的代码
- 使用vcddiff和vcat对vpd文件进行比较(其实生成的文件并不方便查看,更多的是直接用两个波形文件进行对比)
- Causes of simulation mismatches
- 不同的仿真工具仿出来的结果不一样
- 不同版本的仿真器结果不一样
- RTL级和门级电路仿真结果不一样——代码不完善或者综合过程中出现了问题
- Races
下面是竞争的一个例子:
module race;reg a;initial begina = 0; #10 a = 1;endinitial begin#10 if(a) $display("May not print"); //读写操作发生了竞争,每个仿真器的结果可能不一样end
endmodule
解决方法:1.人为错开读取的时间 2.使用非阻塞语句
零时刻的竞争
initial beginreset = 0;clock = 0;forever #50 clock = ~clock;
endalways @(negedge reset) begin$display ("May or may not display at time zero.");
出现了两个问题:1.零时刻reset从不定态变化到0,是否算下降沿?2.如果算下降沿,那么零时刻的下降沿是否在always语句的判断范围之内?
解决方法:1.将下降沿的时间错开 2.初始值赋为1,则零时刻就不会有下降沿
- Coding Rules of Thumb
- 同步模块当中只含有非阻塞语句
- 组合逻辑电路和初始化语句只含有阻塞语句,用always语句描述组合逻辑语句的时候尽量用always@(*)
- 不要有多驱动源,一个变量只在一个always模块里面赋值,或只在一个assign里面赋值;只有在SoC顶层的双向口才会出现多驱动源。
Use vcdiff to show differences in simulation;use vcat to display VCD file values in readable format.
也可以用+race选项显示竞争冒险事件:
vcs -R +race test.v
- 实例
gvim中 :set nu 命令可以显示行号
一共有两种方式实现两级DFF:
//dff_tb.v 两级DFF`timescale 1ns/1nsmodule dff_exp(input wire clk_i,input wire rst_l_i,input wire d,output reg q);reg q1;//第一种实现方式 `ifdef DFFSTYLE1 always @(posedge clk_i, negedge rst_l_i) beginif (!rst_l_i)q1 <= 1'b0;elseq1 <= d;endalways @(posedge clk_i, negedge rst_l_i) beginif(!rst_l_i)q <= 1'b0;elseq <= q1;end`endif//第二种实现方式`ifdef DFFSTYLE2always @(posedge clk_i, negedge rst_l_i) beginif (!rst_l_i)q1 = 1'b0;elseq1 = d;endalways @(posedge clk_i, negedge rst_l_i) beginif(!rst_l_i)q = 1'b0;elseq = q1;end`endifendmodule
这两种方式仿真的结果是有区别的(第二种会出现错误),但是综合出来的结果是一样的。
接下来进行第三第四种实现方式的仿真:
//第三种实现方式 `ifdef DFFSTYLE3 always @(posedge clk_i, negedge rst_l_i) beginif (!rst_l_i) beginq1 <= 1'b0;q <= 1'b0;endelse beginq1 <= d;q <= q1;endend`endif//第四种实现方式`ifdef DFFSTYLE4always @(posedge clk_i, negedge rst_l_i) beginif (!rst_l_i) beginq1 = 1'b0;q = 1'b0;endelse beginq1 = d;q = q1;endend`endif
第三个电路的仿真结果是正确的:
第四个电路的仿真结果是错误的:
第三种写法综合结果是正确的,第四种则出现了错误(只有一个DFF)。
第五种第六种分别是在第三种第四种的基础上,对两个赋值的顺序进行调换。例如从q1<=d;q<=q1变成q<=q1;q1<d;
第五种第六种仿真结果都是正确的(虽然第六个使用的是阻塞语句),并且两种综合结果也都是正确的。
总结:代码中很小的差别可能会造成仿真和综合极大的不同。
mismatch要注意两点:仿真结果是否不同,综合结果是否不同。