Search code examples
verilogsystem-verilogquestasim

SystemVerilog hierarchical reference in nonblocking assigment


I'm seeing strange behavior in my testbench where a nonblocking assignment is acting as a continuous assignment instead of outputting the RHS delayed by one cycle.

My testbench binds a module "cov" to the DUT at cpu.cache via bind cache cov cov_top, and inside the "cov" module I have this nonblocking assignment:

module cov
  import cachePkg::*;
(
  input logic clk,
  input logic rst
);
  clocking cclk @(posedge clk iff !rst); endclocking

  logic [1:0] LinkState_d1, LinkState_d2;
  always @(cclk) begin
    LinkState_d1 <= cache.cntrl.LinkState;
    LinkState_d2 <= LinkState_d1;
  end
endmodule

And the cache.cntrl.LinkState in the DUT is the output of a nonblocking assignment, so I would expect LinkState_d1 to simply follow LinkState from the DUT just delayed by one cycle. However in the waveform viewer I see LinkState_d1 is exactly matching LinkState as if it were a continuous assignment, here's the clock diagram of what I'm seeing in the waveform:

             __    __    __
clk       __|  |__|  |__|  |__
                   ________
LinkState    _____|
                   ________
LinkState_d1 _____|
                         __
LinkState_d2 ___________|

Is there something different that happens when we use a hierarchical reference in the RHS of a continuous assignment? Or is this just a simulator bug? I'm using questasim 2019.4


Solution

  • Your edited question is very different from the original. The problem is you are using different clocks. It has nothing to do with hierarchical references or that you are using an NBA statement in the module cov.

    The clocking block event cclk gets scheduled in the observed region, which is presumably after cache.cntrl.LinkState gets updated with its new value.

    You should not mix clocking blocks with signals from outside the clocking block. Either stop using the clocking block, or move everything inside it.

    logic [1:0] LinkState_d1, LinkState_d2;
    
    clocking cclk @(posedge clk iff !rst); 
      input LinkState = cache.cntrl.LinkState;
      inout LinkState_d1l
      output LinkState_d2;
    endclocking
    
      always @(cclk) begin
        cclk.LinkState_d1 <= cclk.LinkState;
        cclk.LinkState_d2 <= cclk.LinkState_d1;
      end
    endmodule