Driving output clockvars on clocking block event

Hi ,
I was trying the following code ::


 bit [6:0]  ip  = 1 ;

  bit [7:0]  op ;

  clocking cb @(posedge clk);

    default input #1 output #2; 

    output  op  ;              

    input   ip  ;               

  endclocking

   bit clk ;
    
  always #5 clk = ~clk;
    
   mult_if inf( clk );
    
   `define  TB_IF   inf.cb

   initial begin
    
      //  Drive  Exactly  on  1st  posedge  of  clk  !!

       @( cb ) ;

       cb.op <= cb.ip + 1 ;

       $display(" Output  clockvars  \"op\"  driven %0d  at  TIME : %2t " , ( cb.ip + 1 ) , $time );

   end


   always @( op )  $display(" Raw  Signal  \"op\"  changed  to  %2d  at  T:%2t " , op , $time );

   initial  #20  $finish() ;


How is it that the raw signal ’ op ’ is driven on same clocking event relative to output skew of #2 units i.e at time: 7 units?

By the time @( cb ) unblocks the posedge of clock has already occurred , so my expectation was it would be driven at next posedge of clock ( relative to output skew )
i.e at time 17 units .

Instead of @( cb ) if I were to write #5 OR @( posedge clk ) , I observe the same output i.e always block is triggered at time 7 units

I expected the behavior would be similar to :
Driving between 2 clocking events results in the output clockvar being driven at the next clocking event

Eg : If I were to drive at time 10 units , the raw signal would actually be driven on next posedge of clock at time : 17 units

In reply to Have_A_Doubt:

A related topic: SV: The best way to drive interface wires is to use clocking blocks.
Quote:
1800-2012 14.3 Clocking block declaration

  • A clockvar whose clocking_direction is inout shall behave as if it were two clockvars, one input and one output, having the same name and the same clocking_signal.
  • Reading the value of such an inout clockvar shall be equivalent to reading the corresponding input clockvar.
  • Writing to such an inout clockvar shall be equivalent to writing to the corresponding output clockvar.
    // Complete code example
    LinkedIn

// Original question:

In reply to ben@SystemVerilog.us:

Hi Ben ,
Yes I do agree that using clocking blocks , net type can be driven procedurally through class type via a virtual interface .

However the confusion I have is regarding driving output clockvars on exactly the posedge of clk via any of the 3 ways above

Why is it being driven on same clocking event and not the next one since @( cb ) unblocks after posedge of clk occurs ( due to loopback from observed to active region )

I drive exactly on @( cb ) / @( posedge clk ) since my driver component would be


  seq_item_port.get_next_item( req );

  @( vif_intf.cb );

    vif_intf.output_clockvar  <=  req.property ;

    ...................

In reply to Have_A_Doubt:
In the model below, the input sampling and output delays are 2ns each.
ip=1 at 0ns, and 4 at 4ns. With a sampling of 2ns before the clocking event, ip is sampled at a value of 1 (and not the 4 that happened 1ns before the clock edge).
Simulation uses the value of ip at 2ns before the clock edge (i.e., the 1).
/* Output clockvars “op” driven 2 at TIME : 5

Raw Signal “op” changed to 2 at T: 7

The way
I see it, the @(cb) is the posedge clk; the difference between that and @(posedge clk) is the sampling time of the inputs and the drive time of the outputs.
With the @(posedge clk) the value used for the input is whatever that the inputs have in the active region. The outputs occur in the Obseved region in the same time step.
BTW, I encourage you to read my paper Understanding Assertion Processing Within a Time Step,
This is coming up in the Feb 27, 2023 Horizons.

Image cb203.png - Google Drive
Code Edit code - EDA Playground


module m;
  bit [6:0] ip = 1;
  bit [7:0] op, op1;
  bit clk;
  always #5 clk = !clk;

  clocking cb @(posedge clk);
    default input #2 output #2;
    output op;
    input ip;
  endclocking

  initial begin
    #4 ip=4;
    //  Drive  Exactly  on  1st  posedge  of  clk  !!
    @(cb) cb.op <= cb.ip + 1;
    $display(" Output  clockvars  \"op\"  driven %0d  at  TIME : %2t ", (cb.ip + 1), $time);
  end

  always @(op) $display(" Raw  Signal  \"op\"  changed  to  %2d  at  T:%2t ", op, $time);

  initial begin
    $dumpfile("dump.vcd");
    $dumpvars;
    #20 $finish();
  end
endmodule
/* Output  clockvars  "op"  driven 2  at  TIME :  5 
  #  Raw  Signal  "op"  changed  to   2  at  T: 7   */ 

Ben Cohen

In reply to ben@SystemVerilog.us:

I had missed out on the following lines from the LRM ::


Regardless of whether the synchronous drive takes effect on the current clocking event or at some future clocking event as a result of a cycle_delay, 
the corresponding signal shall be updated at a time after that clocking event as specified by the output skew.

This confirms that the raw signal is driven / updated at output skew units after the same clocking event i.e at time 7 units .