Clocking Block Problem

Hi,

I coded an I2C memory, there is some deficits but without clocking block it works well. (Without Clocking Block

I added clocking block with posedge. (I gave scl from outside for some reasons but it is not important.)
Tests passed but there is a different situation in wave form. State changes before than expected. WITH Clocking Block

Driver Part


  task reset();
    @(`TOP_IF);
    `TOP_IF.rst 	<= 1'b1;
    `TOP_IF.newd	<= 1'b0;
    `TOP_IF.wr	 	<= 1'b0;
    `TOP_IF.wdata	<= 0;
    `TOP_IF.addr 	<= 0;
    repeat (3) @(`TOP_IF);
    `TOP_IF.rst 	<= 1'b0;
    `uvm_info("DRV", "DRV: Reset Detected", UVM_NONE)
  endtask
  
  virtual task run_phase(uvm_phase phase);
    reset();
    `TOP_IF.rst 	<= 1'b0;
    forever begin
      seq_item_port.get_next_item(tr);
      if(tr.wr)
        begin  
          @(`TOP_IF);
          `TOP_IF.newd	<= 1'b1;
          `TOP_IF.wr  	<= tr.wr;
          `TOP_IF.wdata <= tr.wdata;
          `TOP_IF.addr  <= tr.addr;  
          @(`TOP_IF); ///@(posedge vif.scl_ref); 
          `TOP_IF.newd	<= 1'b0;
          @(`TOP_IF);//@(posedge vif.scl_ref); 
          wait(`TOP_IF.done);// where pos done state is new_data
          `uvm_info("DRV", $sformatf("DRV: WRITE ---> tr.wr: %0d --- tr.addr: %0d --- tr.wdata: %0d",  tr.wr, tr.addr, tr.wdata), UVM_NONE)   
          end
      else
        begin
          @(`TOP_IF);
          `TOP_IF.newd	<= 1'b1;
          `TOP_IF.wr  	<= tr.wr;
          //vif.wdata <= tr.wdata;
          `TOP_IF.addr  <= tr.addr;
          @(`TOP_IF);//@(posedge vif.scl_ref);
          `TOP_IF.newd	<= 1'b0;
          @(`TOP_IF);//@(posedge vif.scl_ref); 
          tr.rdata = `TOP_IF.rdata;
          `uvm_info("DRV", $sformatf("DRV: %0d. READ ---> tr.wr: %0d --- tr.addr: %0d --- tr.rdata: %0d",  count_read, tr.wr, tr.addr, tr.rdata), UVM_NONE)
          count_read = count_read + 1;         
        end
      seq_item_port.item_done();
    end
  endtask

Unexpected State


  always@(posedge scl_ref, posedge rst)
    begin
      if(rst)
        begin
          rdata			<= 0;
          done			<= 1'b0;
          sdat			<= 1'b1; // sdat and sclt is '1' in default
          sclt			<= 1'b1; // sdat and sclt is '1' in default
          sda_en		<= 1'b1; // sda_en		  is '1' in default
          ack_en        <= 1'b0; // ack_en		  is '1' in default
          ackt          <= 1'b0;
          addrt			<= 0;
          wdata_reg		<= 0;
          rdata_reg		<= 0;
        end
      else
        begin
          $monitor("[%0t] monitor for scl_ref posedge: newd == %0b -- 1'b1 and state will be 'wstart' in the next clock. ", $time(), newd);
          //$monitor("[%0t] monitor for scl_ref posedge: state == %0d", $time(), state);
          case(state)
            new_data: begin
              rdata			<= 0;
              done			<= 1'b0;
              sdat			<= 1'b1; // sdat and sclt is '1' in default
              sclt			<= 1'b1; // sdat and sclt is '1' in default
              sda_en		<= 1'b1; // sda_en		  is '1' in default
              ack_en        <= 1'b0; // ack_en		  is '1' in default
              ackt          <= 1'b0;
              addrt			<= 0;
              wdata_reg		<= 0;
              rdata_reg		<= 0;
              
              if(newd == 1'b1)  // ----------> It changes unexpectedly. 
                begin
                  state <= wstart;
                  $display("[%0t] newd == %0b -- 1'b1 and state will be 'wstart' in the next clock. ", $time(), newd);
                  //$monitor("[%0t] monitor: newd == %0b -- 1'b1 and state will be 'wstart' in the next clock. ", $time(), newd);
                  //$strobe("[%0t] strobe: newd == %0b -- 1'b1 and state will be 'wstart' in the next clock. ", $time(), newd);
                end
              else
                begin
                  state <= new_data;
                end
            end

I supposed state=2 should be 1 clock later since it is dependent on becoming of newd == 1’b1 with @(posedge scl_ref)

I tried different simulators on EDAPLAYGROUND and I used Xilinx 2022.

I used like @(clocking CB) in order not to violate something.

This is my interface at the bottom of design.


interface i2c_if;
  logic clk;
  logic scl_ref;
  logic rst;
  logic newd;
  logic wr;   
  logic [7:0] wdata;
  logic [6:0] addr;
  logic [7:0] rdata;
  logic  done;
  
  clocking top_cb @(posedge scl_ref); // according to testbench
    default input #1step output #3ns;
    output rst;
    output newd;
    output wr;
    output wdata;
    output addr;
    input  rdata;
    input  done;    
  endclocking 
  
  clocking mon_cb @(posedge scl_ref); // according to monitor
    default input #1step;  // --------------------------------> Monitor should only have an input skew, NO output skew;
    input rst;
    input newd;
    input wr;
    input wdata;
    input addr;
    input rdata;
    input done;    
  endclocking
  
  modport top_mp(clocking top_cb);
  modport mon_mp(clocking mon_cb);
    
endinterface


Can anybody explain why?

In reply to hcglu:

I don’t have enough time to look into your example in enough detail, maybe someone else does.

A couple of things that stand out that may or may not be your problem. One of the guidelines I recommend is, if you do use clocking block events, that should be the only event controls used. Do not use wait() statements or other time consuming constructs. That means using try_next_item() instead of get_next item.

forever begin
      @(`TOP_IF) if(seq_item_port.try_next_item(tr) ) begin
         ...


       @(`TOP_IF iff(`TOP_IF.done) )
      ...
     end

I do want to ask why you are adding clocking blocks when your test bench is already working without them?

In reply to hcglu:

You are running different sequences in your examples. You have to align your code that the results are becoming comparable.

In reply to dave_59:

Thank you Dave.

I just tried to learn Clocking Blocks by using.

Maybe I couldn’t explained.

Please look this screenshot: Screenshoot

(Master works with slc_ref) As You’ve seen, master part waits newd == 1’b1 to change its state to wstart. I use clocking block with posedge whose output skew is #3 to make easier to see. As shown in timing of newd and state, newd becomes 1 at 183000 and it is visible at 220000 ns for master. Master should go to state wstart after that but it is already in state wstart. How can it be possible? Master cannot see newd = 1 at 180000 so it shouldn’t have gone to state wstart. I would accept to see state go to wstart at 240000.

Is is clear now? I am very confused. I tried it with different simulators on EDP and I also used Xilinx 2022 version.

Thanks, It would be great to understand the reason. :)

In reply to chr_sue:

I changed to make them same. However, as you can see on my next comment it is not about it. If you’re available, can you check with screen shoot given on the next comment?

In reply to hcglu:

Your drivers are still not the same. Please double-check.