简体   繁体   中英

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):

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. One cycle after, it should assert req . It then waits until gnt is high and only deasserts req one cycle after.

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 . So either there's no delay or a few delays with maximum 5 cycles.

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). 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 . 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.

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. Use of a SV clocking block inside the interface is a standard solution. 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.

To help understand:

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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