SystemVerilog adds the clocking block that identifies clock signals, and captures the timing and synchronization requirements of the blocks being modeled. A clocking block assembles signals that are synchronous to a particular clock, and makes their timing explicit. The clocking block is a key element in a cycle-based methodology, which enables users to write testbenches at a higher level of abstraction. Simulation is faster with cycle based methodology.
Depending on the environment, a testbench can contain one or more clocking blocks, each containing its own clock plus an arbitrary number of signals. These operations are as follows:
- Synchronous events
- Input sampling
- Synchronous drives
clocking cb @(posedge clk);
default input #10ns output #2ns;
input negedge data;
In the above example, the first line declares a clocking block called cb that is to be clocked on the positive edge of the signal clk. The second line specifies that by default all signals in the clocking block shall use a 10ns input skew and a 2ns output skew by default. The next line adds three output signals to the clocking block: read, enable and addr. The fourth line adds the signal data to the clocking block as input. Fourth line also contains negedge which overrides the skew ,so that data is sampled on the negedge of the clk.
If an input skew is specified then the signal is sampled at skew time units before the clock event. If output skew is specified, then output (or inout) signals are driven skew time units after the corresponding clock event. A skew must be a constant expression, and can be specified as a parameter.
Skew can be specified in 3 ways.
- #d : The skew is d time units. The time unit depends on the timescale of the block.
- #dns : The skew is d nano seconds.
- #1step : Sampling is done in the preponed region of current time stamp.
If skew is not specified, default input skew is 1step and output skew is 0.
Specifying a clocking block using a SystemVerilog interface can significantly reduce the amount of code needed to connect the TestBench without race condition. Clocking blocks add an extra level of signal hierarchy while accessing signals.
Interface declaration with clocking block:
interface intf (input clk);
logic read, enable,
logic [7:0] addr,data;
clocking cb @(posedge clock); // clocking block for testbench
default input #10ns output #2ns;
modport dut (input read,enable,addr,output data);
modport tb (clocking cb); // synchronous testbench modport
module testbench(intf.tb tb_if);
tb_if.cb.read <= 1; //writing to synchronous signal read
The ## operator can be used to delay execution by a specified number of clocking events, or clock cycles. What constitutes a cycle is determined by the default clocking in effect of module, interface, or program.
##3; // wait 3 cycles
##1 tb_if.addr <= 8'h00;// waits for 1 cycle and then writes address.
Using clocking blocks,cycle delays syntax gets reduced.
Insted of writing
repeat(3) @(posedge clock); sync_block.a <= 1;
##3 sync_block.a <= 1;
To schedule the assignment after 3 clocks,Just use,
sync_block.a <= ##3 1;
To simply wait for 3 clock cycles,
##3; can be used.
But there may be more than one clocking block is defined in a project.
##3 waits for 3 clocks cycles,of the block which is defined as default.
default clocking sync_block @(posedge clock);