Verilog Assignments
In Verilog, there are various ways for assignment, due to the concurrent nature of the Verilog code. Also, to represent the combinational and sequential digital circuits, Verilog provides different ways for assignment which helps to model the hardware accurately.
As we know, Verilog has net
and reg
data types, which represent a wire
and flip flop
respectively. From hardware point of view, wires are driven continuously once the circuit is switched on, thus for every point of time wire will take the value which is fed into as it cannot retain any previous value. To represent this behaviour, Verilog provides continuous assignment. This will assign certain value to the wire at every time step.
Similarly, flip flops, are not driven continuously, rather it is driven at some clock edge or any other event, as flip flops retain the value until it is changed. This is the expected behaviour in sequential circuits. To represent this behaviour, Verilog provides procedural assignment, in which the assignment will be done only if certain event is triggered. Let’s see these assignments in detail.
Continuous Assignment
As discussed earlier this assignment is generally used for net
data types. assign
keyword is used for continuous assignment and is used directly inside the module, i.e., procedural blocks are not required for this type of assignment.
Procedural Assignment
Procedural assignments are used with flip flops, i.e., for sequential circuits. Thus, it can be used to drive only variables and not any net
data type. Also, this type of assignment can only be used inside a procedural block, i.e., initial
or always
.
Procedural assignment can further be divided into 2 types:
- Blocking Assignment
- Non-blocking Assignments
Blocking Assignment
This type of assignment is the same as we see in all the programming language. As the name suggests, program flow will be blocked until the assignment is complete. This assignment is done using the help of =
operator, which is also known as blocking assignment operator. Blocking assignment is executed in the Active region of the event semantics. As we know, the active region does not guarantee the order of execution, thus this type of assignment is prone to race conditions as discussed in previous article.
Non-blocking Assignment
This type of assignment, as name suggests, does not block the flow of program. The RHS of the assignment operation is calculated but it is not assigned to LHS. All the non-blocking assignments are executed at the end of the time-step in NBA region of event semantics and the LHS gets assigned with the calculated RHS. NBAs are done using <=
operator which is also known as non-blocking assignment operator. As this assignment is done in NBA region, it helps prevent race around condition. We will see how this prevents race around condition with example later in this article.
module assignment_demo;
reg [3:0] a;
wire [3:0] b;
// continous assignment
assign b = a;
// assign a = 4'd6; // Not Valid
// continous assignment
initial begin
$monitor("At [%0t], value of a = %0d & b = %0d",$time, a, b);
a = 4'd3;
#10 a = 4'd8; // blocking assignment
#10 a <= 4'd2;// non blocking assignment
// b = 4'ds8; // Not Valid
end
endmodule
Procedural Continuous Assignment
This is a continuous assignment which is used inside the procedural blocks. This is mainly used when we want to override the value of a variable or net. These types of assignments can be achieved using
assign
-deassign
keywordforce
-release
keyword.
Assign deassign keywords
These are used to override the value of a variable until the variable is de-assigned using deassign
keyword. After de-assignment, the value of the variable will remain the same until it is re-assigned using procedural or procedural continuous assignment.
These can be used only used when LHS is a variable or concatenation of variable.
In below example, the value of a
is continuously incremented in the first initial block. In the second initial block, at t=17, the value of a is overridden using assign
keyword, and thus the value of a
is not getting incremented. Once deassign
is used at t=27, the value of a
starts getting incremented.
module assign_deassign;
reg [3:0] a;
initial begin
a = 4'd0;
$monitor("At [%0t], value of a = %0d", $time, a);
repeat(10) begin
$display("Incrementing a");
a = a + 1;
// $display("At [%0t], value of a = %0d", $time, a);
#5;
end
end
initial begin
#17;
$display("At [%0t], Overriding a with assign", $time);
assign a = 4'he;
#10
$display("At [%0t], Deassigning a", $time);
deassign a;
end
endmodule
Output
The value of
a
is not getting printed once the value ofa
is overridden, as$monitor
prints only when the value of the variable changes. As assign does not let the value change, thus value ofa
is not getting printed even aftera
is incremented.
# Incrementing a
# At [0], value of a = 1
# Incrementing a
# At [5], value of a = 2
# Incrementing a
# At [10], value of a = 3
# Incrementing a
# At [15], value of a = 4
# At [17], Overriding a with assign
# At [17], value of a = 14
# Incrementing a
# Incrementing a
# At [27], Deassigning a
# Incrementing a
# At [30], value of a = 15
# Incrementing a
# At [35], value of a = 0
# Incrementing a
# At [40], value of a = 1
# Incrementing a
# At [45], value of a = 2
Force release keyword
These are same as that of assign-deassign
statement but it can be used for both nets and variables. The LHS can be a bit-select, part-select of net but cannot be an array or a bit or part select of variables. These will override all other assignments until released.
In below example, b
is continuously assigned ~a
, i.e., inverse of a. In first initial block value of a
is incremented and the value of b
also changes. In second initial block, at t=15 value of a is overridden using force
keyword. Value of b
changes with response to a
. At t=25 value of b[2:1]
is overridden with force
keyword, and thus now only the first and last bit of b can change. At t=35 variable a
is released, and value of a can be changed, but net b
is still not released, so only the first and the last bit of b
changes with change in a
. At t=45 net b
is also released and now all bits of b
is changed with change in a
.
module force_release;
wire [3:0] b;
reg [3:0] a;
assign b = ~a;
initial begin
a = 0;
$monitor("At [%0t], a = %b, b = %b", $time, a, b);
repeat(12) begin
a = a + 1;
#5;
end
end
initial begin
#15;
$display("Overriding value of variable a by force");
force a = 4'b1111;
#10;
$display("Overriding value of part-select of net b by force");
force b[2:1] = 2'b10;
#10
$display("Releasing a");
release a;
#10
$display("Releasing b");
release b;
end
endmodule
Output
# At [0], a = 0001, b = 1110
# At [5], a = 0010, b = 1101
# At [10], a = 0011, b = 1100
# Overriding value of variable a by force
# At [15], a = 1111, b = 0000
# Overriding value of part-select of net b by force
# At [25], a = 1111, b = 0100
# Releasing a
# At [35], a = 0000, b = 1101
# At [40], a = 0001, b = 1100
# Releasing b
# At [45], a = 0010, b = 1101
# At [50], a = 0011, b = 1100
# At [55], a = 0100, b = 1011
Prevention of race around condition
Race around condition, which was discussed in earlier article, can be prevented by using a non-blocking assignment. As we know in non-blocking assignment, the LHS is assigned in the non-blocking region of event semantics, which comes after the active regions, thus the value is determinate as all the calculations have been already done. Let’s understand this with an example.
Example
In the 1st code, at the positive edge of clk
, variable a
is assigned a value whereas at the same time b
is reading of value of a
. As order of execution in active region is not guaranteed in Verilog, thus it can lead to a race around condition.
Whereas in 2nd code, as non-blocking assignment is used, thus 1
will not be assigned immediately to a
. Now when, b
access the variable a
it will always read the previous value stored, in this case 0
. Thus, b
will be assigned with 0
and a
will be assigned with 1
at the send of the time step. Also note that for b
to attain the value of a
, it takes 2 cycles, thus at t=30, b
= 1
1st code - having race around condition
module race_around;
reg a;
reg b;
reg clk;
initial begin
a = 0;
b = 0;
clk = 0;
$monitor("At [%0t] a = %b, b = %b", $time,a ,b);
#50 $finish;
end
always #10 clk = ~clk;
always @(posedge clk) begin
a = 1;
end
always @(posedge clk) begin
b = a;
end
endmodule
Output
# At [0] a = 0, b = 0
# At [10] a = 1, b = 1
Try this code in EDA Playground2nd code - solution for race condition
module race_around_sol;
reg a;
reg b;
reg clk;
initial begin
a = 0;
b = 0;
clk = 0;
$monitor("At [%0t] a = %b, b = %b", $time,a ,b);
#50 $finish;
end
always #10 clk = ~clk;
always @(posedge clk) begin
a <= 1;
end
always @(posedge clk) begin
b <= a;
end
endmodule
Output
# At [0] a = 0, b = 0
# At [10] a = 1, b = 0
# At [30] a = 1, b = 1
Try this code in EDA Playground