In Verilog, assigning values to variables and nets is a fundamental concept that helps define the behavior of circuits. Assignments in Verilog can be broken down into three main categories:
- Procedural Assignment
- Continuous Assignment
- Procedural Continuous Assignment
Each type of assignment plays a unique role in how signals and variables are handled in Verilog, allowing you to design more efficient digital systems. Let’s dive deeper into each type and their usage.
Legal LHS (Left-Hand Side) Values for Verilog Assignments
An assignment in Verilog consists of two parts: the Right-Hand Side (RHS) and the Left-Hand Side (LHS). The RHS is the expression that evaluates to a value, while the LHS is the variable or net that will receive the value from the RHS.
Here is a table summarizing valid LHS values for each assignment type:
Assignment Type | Legal LHS Values |
---|---|
Procedural | – Variables (scalar or vector) – Bit-select or part-select of a vector – Memory word – Concatenation of variables |
Continuous | – Net (scalar or vector) – Bit-select or part-select of a vector net – Concatenation of bit-selects and part-selects |
Procedural Continuous | – Net or variable (scalar or vector) – Bit-select or part-select of a vector net |
Verilog Assignment Examples
Let’s look at some practical Verilog examples to understand how assignments work.
module tb;
reg clk;
wire a, b, c, d, e, f;
reg z, y;
// Procedural Assignment: Toggling the clock signal
always #10 clk = ~clk;
// Continuous Assignment: Assign constant value to y
assign y = 1;
// Continuous Assignment: Logic expression for f
assign f = (a | b) ^ (d & e);
// Procedural Assignment: Adding values during positive clock edge
always @ (posedge clk) begin
z <= a + b + c + d;
end
// Initializing variables at the start of the simulation
initial begin
a <= 0; b <= 0; c <= 0; d <= 0; e <= 0;
clk <= 0;
end
endmodule
Procedural Assignment
Procedural assignments occur within procedural blocks such as always
, initial
, tasks, and functions. These assignments place values onto variables and maintain those values until a new assignment occurs.
Key Points:
- The variable holds the assigned value until another assignment happens.
- Procedural assignments are triggered during simulation, and you can control the flow using control statements like
if-else
,case
, and loops.
Example:
reg [7:0] data;
integer count;
real period;
initial begin
data = 8'h3e; // Initial assignment
period = 4.23;
count = 0;
end
always @ (posedge clk) begin
count++; // Increment count on every positive clock edge
end
Variable Declaration Assignment
You can assign a value to a variable at the time of declaration. This assignment works similarly to procedural assignments but has no duration — the value holds until the next assignment.
Note: Arrays cannot be initialized directly during declaration.
Example:
module my_block;
reg [31:0] data = 32'hdead_cafe; // Initial assignment at declaration
initial begin
#20 data = 32'h1234_5678; // At time 20, 'data' changes to 1234_5678
end
endmodule
If the variable is initialized during the declaration, the order of evaluation may not be predictable. It can have either of the two initial values.
module my_block;
reg [7:0] addr = 8'h05;
initial begin
addr = 8'hee; // This will update addr to 8'hee
end
endmodule
Continuous Assignment
Continuous assignments assign values to nets and occur whenever there is a change in the RHS expression. This is often used to model combinational logic without specifying the underlying gates. The value on the LHS will continuously update based on the evaluation of the RHS.
Example:
// Example of an AND gate using continuous assignment
wire a, b, c;
assign a = b & c; // 'a' will always be the result of b AND c
Whenever the values of b
or c
change, the expression on the RHS is re-evaluated, and a
gets updated.
Net Declaration Assignment
In Verilog, nets (e.g., wire
) can also be initialized at the time of declaration. However, nets can only have one continuous assignment.
Example:
wire penable = 1; // Assigning value 1 to the 'penable' wire during declaration
Procedural Continuous Assignment
These assignments are used within procedural blocks but allow continuous updates to nets or variables. There are two types of procedural continuous assignments:
- assign … deassign
- force … release
1. assign ... deassign
The assign
statement assigns a value to a variable, and deassign
removes this value, leaving the variable unchanged until a new value is assigned procedurally.
Example:
reg q;
initial begin
assign q = 0; // Assign 0 to q
#10 deassign q; // Remove the assignment after 10 time units
end
2. force ... release
The force
statement allows you to override all other assignments to a variable or net, and release
removes the force.
Example:
reg o, a, b;
initial begin
force o = a & b; // Force o to be the result of a AND b
// Other code
release o; // Release the force on o
end
This can be applied to both nets and variables. However, the LHS cannot be a bit-select, part-select of an array, or a variable array reference.
Conclusion
Verilog assignments are crucial for defining the behavior of digital circuits. Understanding the different types of assignments—procedural, continuous, and procedural continuous—helps you build efficient and reliable designs. By carefully choosing the correct assignment type, you can ensure that your circuits behave as expected, whether you are working with variables or nets.
Always keep in mind that the LHS of an assignment must be appropriate for the assignment type, and procedural assignments will hold their values until a new assignment occurs. Continuous assignments are ideal for combinational logic, while procedural continuous assignments allow you to override or release values as needed.