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?
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