Skip to content

SV 的激励时序:解决竞争冒险现象

SystemVerilog Stimulus Timing & Race-Hazard Mitigation

  • SystemVerilog

竞争冒险现象

  • **竞争:**在电路中到达某一个输出端时间的先后可能有差距的这种现象就叫竞争

  • **冒险:**由竞争所产生的瞬时输出错误(毛刺)现象

在一个timeslot(时间片/上升沿)中会顺序执行很多的语句,即层次化事件队列,以下例子中在此刻的timeslot中就会产生冒险,因为此时不清楚a到底等于0还是a+1

always_ff @(posedge clk) begin
a = 0;
a = a + 1;
b = a;

理解’#‘延迟

   a = b;
#0 c = a;  //后执行
  • #0 只能对两条语句进限定
  • #1 是错误的,因为这样就不在一个timeslot(层次化事件队列)中,没有从根本上解决问题

实际上SV中很少使用#,因为在不同的DUT中时间精度不尽相同

clocking block

虽然在verilog中可使用非阻塞赋值(<=)来避免这一现象,但在SV中一般不再使用非阻塞赋值和增加延迟#的方法来避免竞争冒险现象,而是使用时钟块clocking block

ps:非阻塞赋值右边值先更新,然后再赋值

  • 理解clocking block:想象成一个精确控制信号何时“进⼊”和“离开”模块的闸⻔。严格控制每辆⻋在特定时间 (时钟信号的特定边沿) 通过
  • inputoutput 的定义是从测试平台(testbench)的视角出发的,所以和tb对输入输出的定义保持一致
interface arbiter_interface(input bit clk);
logic [1:0] grant,request;
logic       grant_valid;
logic       rst;

//input and output are defined from a tb perspective
clocking cb @(posedge clk); // Declares a clock module cb
        input grant, grant_valid, clk;
        output request;
endclocking

modport DUT_arbiter (input request, clk, rst,  //注意clk在tb和dut中都是input
                     output grant, grant_valid);
    modport tb_arbiter (clocking cb,  //调用cb,只需在tb中调用
                     output rst);
modport monitor(input request, grant_valid, cb.grant, rst, clk);
endinterface

tb代码中调用clocking

module tb_arbiter(arbiter_interface.tb_arbiter arbif);

            initial begin
                @(arbif.cb) arbif.cb.request <= 2'b01;//在时钟的上升沿(posedge)触发时执行,将request信号设置为2'b01
                    $display("@%0t : Drove req=01",$time);
                    repeat(2) @(arbif.cb)    //在时钟的上升沿触发时,重复执行后续的代码两次。
                    if(arbif.cb.grant != 2'b01)
                    $display("@%0t : grant != 2'b01",$time);
            end
endmodule

DUT中可以这样调用

clocking cb @(posedge clk);
     input start, write, addr, data;
endclocking

always @(posedge clk) begin
        if (cb.start && cb.write)
            mem[cb.addr] = cb.data;
end