Clarifications in clauses 15 and 16, clocking blocks and programs

In 15.10, ADD the following blue text:

15.10 Cycle delay

…

 

What constitutes a cycle is determined by the default clocking in effect (see 15.11). If no default clocking has been specified for the current module, interface, or program then the compiler shall issue an error.

 

Example:

 

    ## 5; // wait 5 cycles (clocking events) using the default clocking

    ## (j + 1); // wait j+1 cycles (clocking events) using the default clocking

 

If a ## cycle delay operator is executed at a simulation time that does not correspond to a default clocking event (perhaps due to the use of a # delay control or an asynchronous @ event control), the processing of the cycle delay is postponed until the time of the next default clocking event.   Thus a ##1 cycle delay shall always be guaranteed to wait at least one full clock cycle.

 

In 15.12, ADD the following blue text:

15.12 Input sampling

All clocking block inputs (input or inout) are sampled at the corresponding clocking event. If the input skew is not an explicit #0, then the value sampled corresponds to the signal value at the Postponed region of the time step skew time-units prior to the clocking event (see Figure 15-1 in 15.3). If the input skew is an explicit #0, then the value sampled corresponds to the signal value in the Observed region.

 

If the input skew is an explicit #0, several additional considerations shall govern input sampling. First, the value sampled corresponds to the signal value in the Observed region.  Next, if the clocking event occurs due to activity on a design object (net or variable), the sampled value shall be updated and available for reading before any program code starts execution in the reactive region. Finally, if the clocking event occurs due to activity on a program object, there is a race condition between the update of the clocking block input's value and the execution of program code that reads that value.

 

 

In 15.14, ADD the following blue text and DELETE the following red strikethrough text:

15.14 Synchronous drives

…

Clocking block outputs (output or inout) are used to drive values onto their corresponding signals, but at a specified time. That is, the corresponding signal changes value at the indicated clocking event as modified by the output skew.

 

Clocking block outputs are scheduled to propagate back into the design after the reactive and re-inactive regions of a given time unit have completed their iterations and contain no more events. (See Figure 9-1) After these regions have been processed, all possible synchronous drives will have executed. For zero skew clocking block outputs with no cycle delay, the new values will be scheduled in the NBA region of the current time unit. For clocking block outputs with non-zero skew or non-zero cycle delay, the corresponding signal shall be scheduled to change value in the NBA region of a future time unit.

 

The syntax to specify a synchronous drive is similar to an assignment:

…

 

Examples:

    bus.data[3:0] <= 4’h5; // drive data in the NBA region of the current cycle

    ##1 bus.data <= 8’hz;  // wait 1 (bus) cycle and then drive data

    ##2; bus.data <= 2;    // wait 2 default clocking cycles, then drive data

    bus.data <= ##2 r;     // remember the value of r and then drive

                           // data 2 (bus) cycles later

 

Regardless of when the drive statement executes (due to event_count delays), the driven value is assigned to the corresponding signal only at the time specified by the output skew.

 

It is possible (though not conventional) for a drive statement to execute asynchronously at a time that does not correspond to its associated clocking event. Such drive statements shall be processed as if they had executed at the time of the next clocking event. Any values read on the right hand side of the drive statement are read immediately, but the processing of the statement is delayed until the time of the next clocking event. This has implications on synchronous drive resolution (See 15.14.2)  and ## cycle delay scheduling.

 

It shall be an error if a synchronous drive uses the intra-assignment NBA syntax form with the conventional # delay control operator.

…

15.14.1 Drives and nonblocking assignments

Synchronous signal drives are processed as nonblocking assignments.

While the NBA operator is used in the synchronous drive syntax, it is worth noting that these assignments are different than classic Verilog NBA variable assignments. The intention of using this operator is to remind readers of certain similarities shared by synchronous drives and nonblocking assignments. One main similarity is that design variables and wires connected to clocking block outputs and inouts are driven in the NBA region.

 

Another key NBA-like feature of inout clocking block variables and synchronous drives is that a drive does not change the clocking block input. This is because reading the input always yields the last sampled value, and not the driven value.

 

A key difference between synchronous drives and class NBA assignments is that transport delay is not performed by synchronous drives (except in the presence of the intra-assignment cycle delay operator). Another key difference is drive value resolution, discussed in the next section.

15.14.2 Drive value resolution

…

The driven value of nibble is 4’b0xx1, regardless of whether nibble is a reg or a wire.

 

If a given clocking output is driven by more than one assignment in the same time unit, but the assignments are scheduled to mature at different future times due to the use of cycle delay, then no drive value resolution shall be performed. The drives shall be applied with classic Verilog NBA transport delay semantics in this case.

 

If a given clocking output is driven asynchronously at different time units within the same clock cycle, then drive value resolution is performed as if all such assignments were made at the same time unit in which the next clocking event occurs.

 

When the same variable is an output from multiple clocking blocks, the last drive determines the value of the variable. This allows a single module to model multi-rate devices, such as a DDR memory, using a different

clocking block to model each active edge. For example:

…

In 16.2, add the following blue text:

16.2 The program construct

…

 

Type and data declarations within the program are local to the program scope and have static lifetime. Variables declared within the scope of a program are called program variables. Program variables, including variable ports, can only be assigned using blocking assignments, continuous assignments, or as output arguments of tasks or functions. Non-program variables can only be assigned using nonblocking assignments. Using nonblocking assignments with program variables or blocking assignments with design (non-program) variables shall be an error. References to program variables from outside any program block shall be an error.

 

16.2.1 Operation of program port connections in the absence of clocking blocks

 

The interaction of clocking blocks with program ports is described in Clause 15.  Clocking blocks are an important component in establishing race-free behavior between designs and testbenches. However, it is possible to construct a program that contains no clocking blocks. Such programs are more prone to races when interacting with design code. This subclause defines the interaction of program ports with design code in the absence of clocking blocks.

 

Program ports are program-scope objects. As such, program variable ports are subject to the blocking assignment restrictions described in 16.2. Another property of program ports is that they are always connected to design objects (wires and variables), since programs can only be instantiated in design scopes.

 

In the absence of clocking blocks, the concept of NBA-like drives across the program/design boundary no longer applies (except in the case of an NBA assignment via hierarchical reference).  Rather, variables on the other side of a port connection may be updated right away, in the current scheduling region.  The same applies to the driving and resolution of wires on the other side of a port connection.

 

Constructs that are sensitive to such cross-region updates and drives, however, shall be scheduled in the scheduling region that corresponds to their declarative scope.  Thus if a program input variable port is updated in the active region, any continuous assignment that uses that input variable on its right hand side shall be scheduled for evaluation in the reactive region. Similarly, if program code drives an inout wire port with a new value, the change on that port is immediately driven  into the connected design scope.  The wire is fully resolved and propagated in the reactive region. However, any design constructs that are sensitive to changes on the wire shall be scheduled for evaluation in the active region. Any program constructs that are sensitive to changes on the wire shall be scheduled in the current reactive or re-inactive regions.

 

Consider the following example design, which contains both design constructs and program constructs:

 

    module m;

        reg r;

        wire dw1, dw2;

 

        initial begin

            r = 0;

            #10 r = 1;

        end

 

        assign dw1 = r;

 

        p p_i(dw2, dw1);

 

        always @(dw2)

            $display("dw2 is %b", dw2);

    endmodule

 

    program p(output pw2, input pw1);

        assign pw2 = pw1;

    endprogram

 

In this design, the flow of data originates in reg r and terminates in the execution of the always construct. Due to the presence of program p, it is necessary for simulators to perform multiple iterations of the big scheduling loop in Figure 9-1. This is because the assign statement in program p shall not be executed until the reactive region.  And then when it executes and triggers activity on the always construct in module m, that always construct is not allowed to execute until the active region in the next iteration of the big loop.