Clocking Blocks:

Clocking blocks are used to trigger or provide sample events to the DUT. Clocking block captures a protocol & are usually defined in an Interface. In certain instances Clocking block protocol can Trigger an event that happens after certain conditions are met. For E.g Trigger counter after Request or Valid is seen. It can also create certain clocking events that are on different clock and are not readily available or logic that has not been coded yet. Clocking blocks provide a way to add asynchronous triggering events without need of explicit clocks & thus avoiding Race conditions in Program or Testbench.

interface example_i(input logic clk);

logic request, grant, stall;

clocking cb_i (@posedge clk);
  input grant, stall;
  output request ##1 grant;
  property check : (~stall & grant) |=> request;


program test(example_i interf_i);

Prop_1: assert property (interf_i.cb_i.check);

initial begin
  @(posedge clk)
  dut.request = interf_i.cb_i.request;


Clocking blocks cannot be defined inside Tasks, Functions or Packages and the Scope of the Clocking Block is Static i.e limited to Interface , Program or Module in which its defined.

Input sampling can be done by using clocking block name itself or by using sample signals inside it to get the desired skew.

clocking legal_bus_read @(posedge clk);
  input negedge bus_avail;
  output request_valid ##2 bus_avail;

// In a program or Testbench Module

initial begin

  wait (legal_bus_read.request_valid == 1);