While I havent done much with clocking blocks, I can provide a basic understanding of their purpose and primary difference with the always block construct.
It is important to note these constructs are very different and solve very different problems. The always block is really the heart of Verilog and serves as the primary descriptor of logic and registers (Im kind of lumping together always @*
, always_comb
, always_latch
, always @(posedge clk)
and always_ff
all together because they all do a similar thing, though for different use cases and with several nuances). So, the always @(posedge clk)
is for describing registers or, more accurately, describing actions to be taken every time the given signal has a positive edge (just like FFs/registers behave in real circuits). Thus, when the clocking event happens, the code for that block executes.
Clocking blocks are used to generalize how the timing of events surrounding clock events should behave. In real circuits, you typically have hold time and setup time constraints for each FF in the design. These constraints dictate the limitation on clock frequency for circuits and are important to understand when it comes to designing hazard-free logic circuits. In simulation of HDL code however, recreating these timing paradigms can be annoying and not scalable, especially when dealing with synchronous interfaces between testbench code and design code. As such, SystemVerilog includes the clocking block construct as a way of providing testbenches with a method of easily defining the timing of such interfaces with a defined clock, builtin skew and constructs that allows stimulus in testbenches to be defined by the clock in a nicer way.
When you define a clocking block, you are defining a set of signals to be synchronized to the provided clock with defined skews, so then whenever you try to assign inputs or read from outputs, these signals are automatically skewed by the given amount (thus behaving a in more realistic way). Also, with clocking, you can use the ##
construct in stimulus and checking blocks to delay events by a certain number of clock cycles (true you can use @(posedge clk);
to do that, but the ##
syntax is much cleaner. Ultimately, clocking blocks allow you to build scalable testbenches that include timing information for synchronous interfaces (because the timing information is all in the clocking block). You can find a more complete explanation and examples of clocking blocks here:
https://www.doulos.com/knowhow/sysverilog/tutorial/clocking/
The important take-aways are these:
The difference between always @(posedge clk)
and clocking blocks is that the former is about describing registers and the latter is about describing the timing of a synchronous interface between a DUT and the testbench.
Thus, the direct comparison you make in your questions is not really appropriate. However to answer your questions directly:
Clocking blocks sample their inputs in the Postponed region of the timestep defined by the input skew (ie, skew time before the clocking event). As the default is 1step
, the sample is done in the Postponed region of the previous step before the clocking event (which is the same as the Preponed region of the current step in terms of value). The outputs are driven in the ReNBA region skew time steps after the clocking event (the default skew is 0, thus the output is driven in the ReNBA of the same timestep as the clocking event).
As clocking blocks are for defining a timing model (for synchronous lines) between a DUT and its testbench, they are indeed not snythesizable. They are a testbench construct, much like initial
(ignoring a few cases), final
, assertions and programs.
To learn more about clocking blocks, read Chapter 14 of IEEE1800-2012. 14.13 talks about input skew and 14.16 talks about output skew.