简体   繁体   English

采样和驱动信号的 SV/Verilog 时序

[英]SV/Verilog timing of sampling and driving signals

I have a class driver (coded in UVM) and a module sampler_n_dummy_gnt as follows (simplified for the purpose of this question):我有一个类驱动程序(用 UVM 编码)和一个模块 sampler_n_dummy_gnt 如下(为本问题的目的而简化):

class driver extends uvm_driver #(bus_trans);
    ...
    task run_phase();
        forever begin
            seq_item_port.get_next_item(bus_trans_h);
            drive_item(bus_trans_h);
            ...
        end
    ...
    endtask

    task drive_item();
        vif.sel = 1;
        vif.req = 0;
        @(posedge vif.clk);
        vif.req = 1;
        // #1; // this delay needed to prolong req for 1 clock
        if (vif.gnt == 1)
            @(posedge vif.clk);
        else begin
            while (vif.gnt == 0)
                @(posedge vif.clk);
            end
        end
        vif.req = 0;
    endtask
endclass
module sampler_n_dummy_gnt;
    logic clk, rstn;
    int rdelay;

    bus_interface vif(clk, rstn);

    always #10ns clk = ~clk;

    always @(posedge vif.req) begin
        rdelay = $urandom_range(0,5);
        if (rdelay != 0) begin
          for (int i=0; i<rdelay; i=i+1) begin
            vif.gnt = 0;
            @(posedge vif.clk);
          end
        end
        vif.gnt = 1;
    end
endmodule

Basically, the driver emulates a protocol that specifies that it should assert sel whenever there's a new transaction.基本上,驱动程序模拟一个协议,该协议指定它应该在有新事务时断言sel One cycle after, it should assert req .一个周期后,它应该断言req It then waits until gnt is high and only deasserts req one cycle after.然后它一直等到gnt为高电平,并且仅在一个周期后取消断言req

The sampler waits for the assertion of req and based on the randomly generated number waits for a certain number of clock cycles before it asserts gnt .采样器等待req的断言,并根据随机生成的数字在断言gnt之前等待一定数量的时钟周期。 So either there's no delay or a few delays with maximum 5 cycles.所以要么没有延迟,要么有一些延迟,最多 5 个周期。

The first transaction is OK until I run into the 2nd transaction.在我遇到第二笔交易之前,第一笔交易还可以。 At posedge of clock 7, the gnt deasserted and so req should remain high until it sees the gnt assert at clock 8. However, I never saw req assert anymore from clock 7 onwards (ie it stayed 0).在时钟 7 的位置, gnt被取消断言,因此req应该保持高电平,直到它在时钟 8 看到gnt断言。但是,从时钟 7 开始,我再也没有看到req断言(即它保持为 0)。 I suspected that at posedge of clock 7, it sees gnt = 1 but skipped the if-else condition and goes straight to drive req = 0 .我怀疑在时钟 7 的位置,它看到gnt = 1但跳过了if-else条件并直接驱动req = 0 So I have to add the line I commented above in order to get the expected scenario.所以我必须添加我在上面评论过的那一行,以获得预期的场景。 Could someone help explain why the delay is needed?有人可以帮助解释为什么需要延迟吗?

                (Expected)                               (Actual)
        1   2   3   4   5   6   7   8          1   2   3   4   5   6   7   8
       _   _   _   _   _   _   _   _          _   _   _   _   _   _   _   _  
clk  _| |_| |_| |_| |_| |_| |_| |_| |_      _| |_| |_| |_| |_| |_| |_| |_| |_
       _______________     ___________        _______________     ___________
sel  _|               |___|                 _|               |___|
           ___________         _______            ___________         
req  _____|           |_______|             _____|           |_______________   
                   ___________     ___                    ___________     ___
gnt  _____________|           |___|         _____________|           |___|

I'm assuming clk , vif.clk , vif.pclk are really all the same signal.我假设clkvif.clkvif.pclk实际上都是相同的信号。

Your code has a number of problems with dealing with synchronous signals.您的代码在处理同步信号方面存在许多问题。

  • You should only use one clock edge event, and never an edge of another signal unless you are dealing with asynchronous logic.除非您正在处理异步逻辑,否则您应该只使用一个时钟边沿事件,而不是另一个信号的边沿。
  • When making assignments to synchronous signals, always use nonblocking assignments <=对同步信号进行赋值时,始终使用非阻塞赋值<=
  • Make sure the first call to a task is synchronized to a clock edge确保对任务的第一次调用与时钟沿同步

Since you did not post the complete code, I can only make this a suggestion由于您没有发布完整的代码,我只能提出这个建议

class driver extends uvm_driver #(bus_trans);
    ...
    task run_phase();
       @(posedge vif.clk; // initial sync
       forever begin
            while (!seq_item_port.try_next_item(bus_trans_h)
               @(posedge vif.clk;
            drive_item(bus_trans_h);
            ...
        end
    ...
    endtask

    task drive_item();
        vif.sel <= 1;
        vif.req <= 0;
        @(posedge vif.clk);
        vif.req <= 1;
        @(posedge vif.clk iff vif.gnt);
        vif.req <= 0;
    endtask
endclass

There can be issues sampling and driving synchronous data from/to the SystemVerilog (SV) class domain.从 SystemVerilog (SV) 类域采样和驱动同步数据可能会出现问题。 Use of a SV clocking block inside the interface is a standard solution.在接口内部使用 SV 时钟块是标准解决方案。 Use of the clocking block requires understanding of the clocking block, clocking drive assignment and a clock event.使用时钟模块需要了解时钟模块、时钟驱动分配和时钟事件。 It also requires understanding of the sense of input and output from the interface point of view.它还需要从界面的角度来理解输入和输出的感觉。 The paper I listed shows some classic mistakes made when using clocking blocks (don't 'reach around' the CB.我列出的论文显示了使用时钟模块时犯的一些经典错误(不要“绕过”CB。

To help understand:为了帮助理解:

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM