Search code examples
system-veriloguvm

Changing clocking block clock polarity on the fly


I am creating UVM VIP which is able to switch its clock polarity. Clocking block is used in the interface. For example, a monitor should sample the data using posedge or negedge of incoming clock depending on UVM configuration - and this polarity change can happen on the fly.

This can be implemented as follows:

// In the interface, two clocking blocks are defined
// one for posedge (passive_cb), one for negedge (passive_cbn).

task wait_clock_event();
   if (cfg.pol == 0) @vif.passive_cb;
   else @vif.passive_cbn;
endtask

task sample_data();
  if (cfg.pol == 0) pkt.data = vif.passive_cb.data;
  else pkt.data = vif.passive_cbn.data;
endtask

task run();
  wait_clock_event();
  sample_data();
endtask

This seems to work but waste code lines and prone to error.

Is there any better solution?


Solution

  • Assuming the monitor has exclusive access to the clocking block, you could consider modifying clocking event in the interface with the iff qualifier.

    bit pol;
    clocking passive_cb @(posedge clk iff !pol, negedge clk iff pol);
      input data;
    endclocking
    

    There is a potential race condition if pol changes in the same timestep as the target clock polarity.

    Your monitor code would then include a set function and other tasks can be simplified to us only one clocking block.

    function void set_vifcb_pol();
      vif.pol = cfg.pol;
    endfunction
    
    task wait_clock_event();
      @vif.passive_cb;
    endtask
    
    task sample_data();
      pkt.data = vif.passive_cb.data;
    endtask
    
    task run();
      set_vifcb_pol();
      wait_clock_event();
      sample_data();
    endtask