首页 > 其他 > 详细

Verilog -- testbench的initial块中阻塞与非阻塞赋值问题

时间:2020-03-24 21:35:42      阅读:366      评论:0      收藏:0      [点我收藏+]

Verilog testbench的initial块中阻塞与非阻塞赋值问题

问题描述

在testbench的编写中经常要做的就是在initial块中对一些信号变化进行描述。
比如希望信号start在仿真开始后第10个周期上升沿置为高电平。
对于仿真时钟一般都会这么写:

 always #1 clk = ~clk;
  • 如果初始化clk = 0,那么实际上start应该在 #21;start=1; 也就是十个半周期后置高。
  • 如果初始化clk = 1,那么实际上start应该在 #20;start=1; 也就是准确的十个周期后置高。

这种写法实际上不符合实际电路中的运行规则
如果start在上层模块是通过其他FF给出的,则这样的写法往往会导致数据提前一拍,因为#20;start=1;的写法是跟时钟上升沿无关的,因此在该处时钟上升沿实际上和start的值同时改变,而我们知道,实际上FF的原理是一般都是基于正负latch,其采样和保持都需要一定的延时(clk-Q),所以用clk去驱动FF时,FF的Q端数据一般都是在上升沿之后的一段延时后才改变。
这也是为什么verilog中要使用“<=”阻塞赋值的一个因素,因为阻塞赋值契合了实际电路中的这一特性,如果该FF之后又级联了一个FF,则在这个clk上升沿,如果不考虑时钟skew,那么后面级联的FF实际上采样到的数据还是前级FF赋值之前的数值,阻塞赋值可以保证这一特性。

所以在tb里initial块中一般使用

@ (posedge clk);
 start<=1;

这种写法来保证阻塞的特性,也就是在时钟上升沿之后reg值才变化。
下面是一段测试程序,以便更好的理解两者的差别:

module test();
  reg clk;
  reg req0;
  reg req1;
  reg test_sig;
  always #1 clk = ~clk;
  initial begin
  clk = 0;
  req0 = 0;
  req1 = 0;
  test_sig = 0;
  #10;
  @ (posedge clk);
  req0 <= 1;
  req1 <= req0;
  repeat (1) @ (posedge clk)
  req0 <= 1;
  req1 <= req0;

  #10;
  req0 = 0;
  req1 = req0;
 end
always@(posedge clk) begin
    if(req0==1) test_sig <= 1;
    else test_sig <= 0;
end

initial begin
    $fsdbDumpvars();
    $fsdbDumpMDA();
    $dumpvars();
    #100 $finish;
 end
endmodule 

技术分享图片

其中,test_sig依赖req0的值。可以发现,当使用@ (posedge clk);配合“<="赋值时,test_sig的值在req0变化的下一周期才改变,req1也是如此,符合时序电路的规范。而下面使用"#"延时和非阻塞赋值的语句则导致test_sig、req1跟着req0的值同时改变。

Verilog -- testbench的initial块中阻塞与非阻塞赋值问题

原文:https://www.cnblogs.com/lyc-seu/p/12562107.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!