Keywords: deassign, force, release

Procedural continuous assignment is a type of procedural assignment. This assignment statement can replace all other assignments to wire or reg, overwriting the current value of variables of type wire or reg.

Unlike procedural assignment, the expression of a procedural continuous assignment can be continuously driven into variables of type wire or reg. That is, when a procedural continuous assignment takes effect, any change in an operand of the right-hand expression will cause the procedural continuous assignment statement to re-execute.

There are mainly two types of procedural continuous assignment: assign-deassign and force-release.

assign, deassign

assign (procedural assignment operation) and deassign (cancel procedural assignment operation) represent the first type of procedural continuous assignment statement. The assignment target can only be a register or register array, not a wire type variable.

During the assignment process, the register is continuously assigned, and the value in the register is retained until it is reassigned.

For example, a D flip-flop with a reset terminal can be described with the following code:

Example

module dff_normal(
    input       rstn,
    input       clk,
    input       D,
    output reg  Q
 );

    always @(posedge clk or negedge rstn) begin
        if(!rstn) begin   //Q = 0 after reset effective
            Q <= 1'b0 ;
        end
        else begin
            Q <= D ;       //Q = D at posedge of clock
        end
    end

endmodule  

In the following, rewrite it with assign and deassign to accomplish the same functionality.

That is, when the reset signal is 0, the Q terminal is assigned by the assign statement and always outputs 0.

When the reset signal is 1, the Q terminal is de-assigned by the deassign statement and is reassigned at the rising edge of the clock.

Example

module dff_assign(
    input       rstn,
    input       clk,
    input       D,
    output reg  Q
 );
 
    always @(posedge clk) begin
        Q <= D ;       //Q = D at posedge of clock
    end
 
    always @(negedge rstn) begin
        if(!rstn) begin
            assign Q = 1'b0 ; //change Q value when reset effective
        end
        else begin        //cancel the Q value overlay,
            deassign Q ;  //and Q remains 0-value until the coming of clock posedge
        end
    end
 
endmodule

force, release

force (force assignment operation) and release (release forced assignment) represent the second type of procedural continuous assignment statement.

The usage and effects are similar to assign and deassign, but the assignment target can be either a reg type variable or a wire type variable.

Because it is an unconditional forced assignment, it is generally used in interactive debugging processes and should not be used in design modules.

When force is applied to a register, the current value of the register is overwritten; at release, the register value will continue to retain the value from the forced assignment. After that, the register value can be changed by the original procedural assignment statements.

When force is applied to a net, the net value is also forcibly assigned. However, once the net variable is released, its value immediately becomes the original driven value.

To intuitively observe the difference of forced assignment between the two types of variables, use the counter counter10 from the first section as the design module, and the testbench is designed as follows.

Example

`timescale 1ns/1ns
 
module test ;
    reg          rstn ;
    reg          clk ;
    reg [3:0]    cnt ;
    wire         cout ;
 
    counter10     u_counter (
        .rstn    (rstn),
        .clk     (clk),
        .cnt     (cnt),
        .cout    (cout));
 
    initial begin
        clk       = 0 ;
        rstn      = 0 ;
        #10 ;
        rstn      = 1'b1 ;
        wait (test.u_counter.cnt_temp == 4'd4) ;
        @(negedge clk) ;
        force     test.u_counter.cnt_temp = 4'd6 ;
        force     test.u_counter.cout     = 1'b1 ;
        #40 ;
        @(negedge clk) ;
        release   test.u_counter.cnt_temp ;
        release   test.u_counter.cout ;
    end
 
    initial begin
        clk = 0 ;
        forever #10 clk = ~ clk ;
    end
 
    //finish the simulation
    always begin
        #1000;
        if ($time >= 1000) $finish ;
    end
 
endmodule // test

The simulation results are as follows.

As can be seen from the figure, when cnt_temp equals 4 (80ns), cnt_temp is forced to 6, and cout is forced to 1.

At release (120ns), cnt_temp is a register type, still retaining its original value unchanged; only when the clock rising edge performs addition assignment on it, the value becomes 7.

At 120ns, however, since cout is a net type variable, its value cannot be saved. In the original counter10 model, there is a driving statement:assign cout = (cnt_temp==4'd9), so the cout value becomes 0.

Source Code Download

Download