Maker.io main logo

Assignment in Verilog - Part 20

2025-08-13 | By DWARAKAN RAMANATHAN

Introduction:

In Verilog design, efficient and good coding depends a lot on understanding how various types of signal assignments work. Being a hardware description language, unlike other software programming languages, Verilog defines hardware behavior, so the assignment type directly influences the synthesized hardware and simulated behavior. In this tutorial, we are going to discuss the three most important assignment categories in Verilog—continuous, procedural, and procedural continuous—along with examples and how and why to use each.

Continuous Assignments:

Continuous assignments are among the basic techniques employed to model combinational logic in Verilog. They are specified by means of the assign keyword and must be used to assign to wire-declared signals. They lie outside procedural blocks, such as always or initial, and the right-hand side of the assignment expression is continuously checked. That is, whenever an operand of the expression changes, the value on the left-hand side is refreshed immediately.

Something to keep in mind is that continuous assignments define data flow. The result of the expression is a combinational logic function of the inputs, and the output is driven continuously into the result. For instance, an AND gate can be expressed as:

Copy Code
assign y = a & b;

This definition means y is always the logical AND of a and b. There is no sequencing or timing, the output switches as soon as the inputs switch.

Continuous assignments are ideal for straightforward, direct logic expressions that don't include control flow statements like if, case, or for. They are synthesizable and translate well to hardware gates, so they are a first-choice way to implement simple combinational logic like decoders, multiplexers, and simple arithmetic operations.

Procedural Assignments

Procedural tasks are applied in always or initial blocks and have to be directed to reg-declared variables or similar data types (e.g., logic in SystemVerilog). Procedural blocks provide more sophisticated modeling with control flow structures like if-else, case, for, and while. Procedural blocks can be employed to model combinational logic and sequential logic, depending on the sensitivity list and the assignment type applied.

There exist two types of procedural assignments: blocking (=) and non-blocking (<=). Blocking assignments are done one at a time and are often used for modelling combinational logic. Non-blocking assignments are performed concurrently and are required for defining clocked, sequential logic such as registers and flip-flops.

For example, the following block declares a D flip-flop in a non-blocking assignment:

Copy Code
always @(posedge clk) begin
q <= d; 
end

This mode ensures that the value of d is passed on to q on the rising clock edge. Use of <= prevents race conditions created with blocking assignment in sequential logic and applies all the updates of the block all at once.

On the other hand, to define a combinational logic in procedural code, a blocking assignment within a combinational always block can be employed:

Copy Code
always @(*) begin
out = (sel)? a : b; 
finish

In this case, the ternary operation chooses between a and b depending on the value of sel and out is set appropriately.

Procedural assignments are flexible and are necessary whenever you must explain behavior that hinges on certain conditions or state. But caution needs to be exercised in applying the right kind of assignment so as not to induce simulation mismatches and to have synthesizability.

Procedural Continuous Assignments

Procedural continuous assignments is a less-used construct and are usually employed in testbench and simulation environments. They are comprised of assigning values to a reg using the assign and deassign or force and release keywords inside procedural blocks.

This sort of assignment provides for a reg variable to be driven continuously from within a procedural block, like assign is used on wire types. It must, however, be explicitly cleared using deassign or release once the assignment becomes invalid.

A sample usage would be:

Copy Code
initial begin
 y = a & b;
#10 deassign y; 
end

In simulation, this code makes y act like a wire being driven all the time by the value of a & b for 10 time units, and then the assignment is eliminated. These structures are synthesizable and are not to be utilized in RTL code. They are primarily utilized in testbenches to override signal values for a brief time or to introduce faults for verification.

Although not normally used in RTL design, knowledge of procedural continuous assignments is still valuable for the design of sophisticated test environments and simulation behavior debugging.

Choosing the Right Assignment Type

When choosing which type of assignment to use, you need to consider the context of the logic and your design objectives—simulation accuracy, synthesis compatibility, or testbench flexibility. A summary of use cases and considerations is presented below:

Continuous Assignments (assign): Best for simple combinational logic with direct relationships between inputs and outputs. Synthesizable and hardware friendly.

Procedural Assignments (blocking = and non-blocking <=): Appropriate for representing both combinational and sequential behavior via conditions and control structures. Blocking assignments are appropriate for combinational logic, but non-blocking assignments are required for sequential, clock-driven logic.

Procedural Continuous Assignments (assign within initial or always): For use in testbench, enabling dynamic signal control during simulation. Not synthesizable.

Misuse of assignment types may cause undesirable latch inference, flawed simulation results, or synthesis bugs. For example, not utilizing non-blocking assignments in sequential logic can result in race conditions in simulation that don't exist in real hardware.

Conclusion

A complete grasp of assignment semantics in Verilog is required to develop strong and efficient hardware description code. Continuous assignments are convenient and easy to read for straightforward logic. Procedural assignments offer the capability to define more complex behavior, especially for state machines and clock-driven logic. Procedural continuous assignments, although rarely used in synthesis, are important in testbench development.

By learning how to use the correct usage of these assignments, designers can have confidence that their Verilog code will work correctly in both simulation and actual hardware, without stumbling into common errors and with a smooth transition from code to silicon.

Have questions or comments? Continue the conversation on TechForum, DigiKey's online community and technical resource.