Verilog Description Styles
Introduction to Description Styles
There are two different styles of description:
-
- Data Flow
- Continuous assignment, using assignment statements.
-
- Behavioral
- Procedural assignment, using procedural statements similar to a program in a high-level language.
- Blocking
- Non-blocking
Data Flow Style: Continuous Assignment (assign)
Characteristics of assign
- Identified by the keyword
assign. - Forms a static binding between:
- The
netbeing assigned on the left-hand side (LHS). - The expression on the right-hand side (RHS), which may consist of both
netandregistertype variables.
- The
- The assignment is continuously active.
- Almost exclusively used to model combinational circuits.
- Some points to note:
- A Verilog module can contain any number of
assignstatements. - Typically, the
assignstatements are followed by procedural descriptions. - The
assignstatements are used to model behavioral descriptions.
- A Verilog module can contain any number of
Modeling Combinational Logic with assign
Generating a MUX with a Variable Index
- Point to note:
- Whenever there is an array reference on the RHS with a variable index, a MUX is generated by the synthesis tool.
- If the index is a constant, just a wire will be generated.
- Example:
assign out = data[2];
- Example:
- The use of a non-constant index in an expression on the RHS generates a MUX.
- Example:
module generate_MUX (data, select, out); input [15:0] data; input [3:0] select; output out; assign out = data[select]; endmodule
Generating a MUX with the Conditional Operator
- Point to note:
- Whenever a conditional is encountered in the RHS of an expression, a 2-to-1 MUX is generated.
- In the example below, since the variables
a,b, andfare vectors, an array of 2-to-1 MUX-es are generated.
- Example:
module generate_set_of_MUX (a, b, f, sel); input [0:3] a, b; input sel; output [0:3] f; assign f = sel ? a : b; endmodule - Question: What hardware will be generated by the following?
assign f = (a==0) ? (c+d) : (c-d);- Answer: The expression generates an adder and a subtractor whose outputs feed into a 2x1 MUX. The MUX’s select line is controlled by the output of a comparator that checks if
a==0.
Generating a Decoder with a Variable Index
- A non-constant index in an expression on the LHS generates a decoder.
- Point to note:
- A constant index in the expression on the LHS will not generate a decoder.
- Example:
assign out[5] = in; - This will simply generate a wire connection.
- Example:
- As a rule of thumb, whenever the synthesis tool detects a variable index in the LHS, a decoder is generated.
- A constant index in the expression on the LHS will not generate a decoder.
- Example:
module generate_decoder (out, in, select); input in; input [0:1] select; output [0:3] out; assign out[select] = in; endmodule
Modeling Sequential Logic with assign
D-Type Latch
- This is an example to describe a sequential logic element using an
assignstatement. - Example:
module level_sensitive_latch (D, Q, En); input D, En; output Q; assign Q = En ? D : Q; endmodule - Truth Table:
- En | D | Qn
- 0 | x | Qn-1
- 1 | 0 | 0
- 1 | 1 | 1
S-R Latch
- Modeling a simple S-R latch. The circuit consists of two cross-coupled NAND gates.
- Example:
module sr_latch (Q, Qbar, S, R); input S, R; output Q, Qbar; assign Q = ~(R & Qbar); assign Qbar = ~(S & Q); endmodule - Testbench and Simulation:
- A testbench can be created to apply stimulus to the S and R inputs.
- Simulation Output:
0 S=0, R=1, Q=0, Qbar=1 5 S=1, R=1, Q=0, Qbar=1 10 S=1, R=0, Q=1, Qbar=0 15 S=1, R=1, Q=1, Qbar=0 20 S=0, R=0, Q=1, Qbar=1 and then the simulator hangs
Behavioral Style: Procedural Assignment
Procedural Blocks (initial and always)
- Two kinds of procedural blocks are supported in Verilog:
- The
initialblock- Executed once at the beginning of simulation.
- Used only in test benches; cannot be used in synthesis.
- The
alwaysblock- A continuous loop that never terminates.
- The
- The procedural block defines:
- A region of code containing sequential statements.
- The statements execute in the order they are written.
The initial Block
- All statements inside an
initialstatement constitute aninitial block. - Statements are grouped inside a
begin...endstructure for multiple statements. - The statements start at time 0, and execute only once.
- If there are multiple
initialblocks, all the blocks will start to execute concurrently at time 0. - The
initialblock is typically used to write test benches for simulation:- Specifies the stimulus to be applied to the design-under-test (DUT).
- Specifies how the DUT outputs are to be displayed / handled.
- Specifies the file where the waveform information is to be dumped.
The always Block
- All behavioral statements inside an
alwaysstatement constitute analways block. - Multiple statements are grouped using
begin...end. - An
alwaysstatement starts at time 0 and executes the statements inside the block repeatedly, and never stops. - It is used to model a block of activity that is repeated indefinitely in a digital circuit.
- Basic syntax of
alwaysblock:always @(event_expression) begin sequential_statement_1; sequential_statement_2; ... sequential_statement_n; end - A module can contain any number of
alwaysblocks, all of which execute concurrently. - The
@(event_expression)part is required for both combinational and sequential circuit descriptions.
Rules and Statements within Procedural Blocks
Sequential Statements
- In Verilog, one or more sequential statements can be present inside an
initialoralwaysblock.- The statements are executed sequentially.
- Multiple assignment statements inside a
begin...endblock may either execute sequentially or concurrently depending upon on the type of assignment.
- Two types of assignment statements: blocking (
a = b + c;) or non-blocking (a <= b + c;).
Variable Assignment Rules
- Only
regtype variable can be assigned within aninitialoralwaysblock. - Basic reason:
- The sequential
alwaysblock executes only when the event expression triggers. - At other times the block is doing nothing.
- An object being assigned to must therefore remember the last value assigned (not continuously driven).
- So, only
regtype variables can be assigned within thealwaysblock.
- The sequential
- Any kind of variable may appear in the event expression (reg, wire, etc.).
Sequential Control Statements
if ... else: Conditional branching with optionalelse ifandelseclauses.case: Multiway branching (case,casez,casex). Can replace a complexif...elsestructure. The expression is compared to alternatives in order. Adefaultstatement can be used.whileloop: Executes a statement while an expression is true.forloop: Consists of an initial condition, a terminating condition check, and a procedural assignment to change the control variable.repeatloop: Executes a loop a fixed number of times. The expression is evaluated only once at the start.foreverloop: Executes forever until$finishis encountered. Equivalent to awhileloop for which the expression is always true.
Timing and Event Control
# (time_value): Makes a block suspend fortime_valueunits of time.@ (event_expression): Makes a block suspend untilevent_expressiontriggers.- The event can be any one of the following:
- a) Change of a signal value.
- b) Positive or negative edge occurring on signal (
posedgeornegedge). - c) List of above-mentioned events, separated by
oror comma.
- A
posedgeis any transition from{0, x, z}to 1, and from0to{z, x}. - A
negedgeis any transition from{1, x, z}to 0, and from1to{z, x}. - Examples of event expressions:
@ (in):inchanges.@ (a or b or c)or@ (a, b, c): any ofa,b,cchanges.@ (posedge clk): positive edge ofclk.@ (posedge clk or negedge reset): positive edge ofclkor negative edge ofreset.@ (*): any variable changes.
Latch Inference in Combinational Logic
- When a
casestatement is incompletely decoded, the synthesis tool will infer the need for a latch to hold the residual output when the select bits take the unspecified values. - This also applies to an
ifstatement without a finalelseclause. - It is up to the designer to code the design in such a way that latch can be avoided where possible.
- To avoid latch inference, either provide a
defaultassignment in the branching statement or assign a default value to the variable at the start of the procedural block.
Examples of Procedural Assignments
- Up-down Counter (synchronous clear):
module counter (mode, clr, ld, d_in, clk, count); input mode, clr, ld, clk; input [0:7] d_in; output reg [0:7] count; always @(posedge clk) if (ld) count <= d_in; else if (clr) count <= 0; else if (mode) count <= count + 1; else count <= count - 1; endmodule - Parameterized Design: An N-bit Counter:
- Use the keyword
parameterto make a design general for any number of bits. - Parameter values are substituted before simulation or synthesis.
module counter (clear, clock, count); parameter N = 7; input clear, clock; output reg [0:N] count; always @(negedge clock) if (clear) count <= 0; else count <= count + 1; endmodule - Use the keyword
- Using more than one clock in a module:
module multiple_clk (clk1, clk2, a, b, c, f1, f2); input clk1, clk2, a, b, c; output reg f1, f2; always @(posedge clk1) f1 <= a & b; always @(negedge clk2) f2 <= b ^ c; endmodule - Using multiple edges of the same clock:
module multi_edge_clk (a, b, c, d, f, clk); input clk; input [7:0] a,b,c,d; output reg [7:0] f; always @(posedge clk) c <= a + b; always @(negedge clk) f <= c - d; endmodule- Two operations are carried out every clock cycle.
cis assigned at the rising edge,fis assigned at the falling edge.
- Two operations are carried out every clock cycle.
Blocking vs. Non-Blocking Assignments
Introduction
- We shall illustrate some examples that show how the modeling style influences the simulator or synthesizer to capture the behavior of the modeled circuit.
- This is a very important concept required to be clearly understood by the designer.
- Even a slight error in modeling can result in a drastically different circuit.
- Highly recommended: For any confusion, write a Verilog code, simulate it and analyze the output(s).
Procedural Assignment Types
- Procedural assignment statements can be used to update variables of types
reg,integer,real, ortime. - The value assigned to a variable remains unchanged until another procedural assignment statement assigns a new value.
- This is different from continuous assignment (using
assign) that results in the expression on the RHS to continuously drive thenettype variable on the left. - Two types of procedural assignment statements:
- a) Blocking (denoted by
=) - b) Non-blocking (denoted by
<=)
- a) Blocking (denoted by
- The left-hand side can be a register type variable, a bit select, a part select, or a concatenation.
- The right-hand side can be any expression that evaluates to a value.
- Procedural assignments can only appear within procedural blocks (
initialoralways).
Blocking Assignment (=)
- General syntax:
variable_name = [delay_or_event_control] expression; - The
=operator is used to specify blocking assignment. - Blocking assignment statements are executed in the order they are specified in a procedural block.
- The target of an assignment gets updated before the next sequential statement in the block is executed.
- They do not block execution of statements in other procedural blocks.
- This is the recommended style for modeling combinational logic.
Non-Blocking Assignment (<=)
- General syntax:
variable_name <= [delay_or_event_control] expression; - The
<=operator is used to specify non-blocking assignment. - Non-blocking assignment statements allow scheduling of assignments without blocking execution of statements that follow within the procedural block.
- The assignment to the target gets scheduled for the end of the simulation cycle.
- Statements subsequent to the instruction under consideration are not blocked by the assignment.
- Allows concurrent procedural assignment, suitable for sequential logic.
Modeling Guidelines and Rules
- It is recommended that blocking and non-blocking assignments are not mixed in the same
alwaysblock. This is not good design practice. - Verilog synthesizer ignores the delays specified in a procedural assignment statement. This may lead to functional mismatch between the design model and the synthesized netlist.
- A variable cannot appear as the target of both a blocking and a non-blocking assignment.
Comparative Examples
Swapping Values
- Trying to swap using blocking assignment:
always @(posedge clk) begin a=b; b=a; end- This is incorrect. Both
aandbwill be getting the value previously stored inb.
- Swapping values of ‘a’ and ‘b’:
- With Blocking assignments:
always @(posedge clk) a=b; always @(posedge clk) b=a;- Either
a=bwill execute beforeb=a, or vice versa, depending on simulator implementation. Both registers will get the same value. This is a race condition.
- Either
- With Non-blocking assignments:
always @(posedge clk) a<=b; always @(posedge clk) b<=a;- Here the variables are correctly swapped. All RHS variables are read first, and assigned to LHS variables at the positive clock edge.
- With Blocking assignments:
Shift Register Modeling
- Example 3:
- Correct blocking version:
always @(posedge clock) begin q2 = q1; q1 = a; end - Correct non-blocking version:
always @(posedge clock) begin q1 <= a; q2 <= q1; end
- Correct blocking version:
- Example 4 (Correct): Using separate non-blocking
alwaysblocks correctly models a shift register.always @(posedge clock) q2 <= q1; always @(posedge clock) q1 <= a; - Example 5 (Incorrect): Using separate blocking
alwaysblocks creates a race condition, and the outputq2will be indeterminate.always @(posedge clock) q1 = a; always @(posedge clock) q2 = q1; - Example 6 (Correct): Modeling a 4-bit shift register with blocking assignments requires careful ordering.
// Correct order for blocking always @(posedge clock or negedge clear) begin if (!clear) ... else begin E = D; D = C; C = B; B = A; end end - Example 6a (Incorrect): Reversing the order of blocking assignments is incorrect.
// Incorrect order for blocking else begin B = A; C = B; D = C; E = D; end- The effect of the assignment
B=Ais immediate. The updated value is used inC=B, and so on. The four statements are equivalent to a single statement that assignsAtoE.
- The effect of the assignment
- Example 6b (Correct): This is the recommended style for modeling sequential circuits, using non-blocking assignments.
- The statements can appear in any order. The chances of errors are less.
- The right-hand side expressions are evaluated in parallel, so that order of the statements is not important.
always @(posedge clock or negedge clear) begin if (!clear) ... else begin E <= D; D <= C; C <= B; B <= A; end end
Ring Counter Modeling
- A ring counter is a circular shift register.
- Incorrect with Blocking assignments:
// Incorrect code else begin count = count << 1; count[0] = count[7]; end- This solution is wrong.
count[7]will get overwritten in the first statement. Rotation of the bits will not happen.
- This solution is wrong.
- Correct with Non-blocking assignments (Modified version 1):
// Correct code else begin count <= count << 1; count[0] <= count[7]; end- Since non-blocking assignments are used, rotation will take place correctly.
- Correct with Blocking assignment (Modified version 2):
// Correct code using concatenation else count = {count[6:0], count[7]};- This is a correct way of modeling using blocking assignment.
Generate Blocks
Introduction to generate
generatestatements allow Verilog code to be generated dynamically before the simulation or synthesis begins.- Very convenient to create parameterized module descriptions. Example: N-bit ripple carry adder for arbitrary value of N.
- Requires the keywords
generateandendgenerate. - Generate instantiations can be carried out for various Verilog blocks: Modules, user-defined primitives, gates, continuous assignments,
initialandalwaysblocks, etc. - Generated instances have unique identifier names and can be referenced hierarchically.
genvar Variables
- Special
genvarvariables:- The keyword
genvarcan be used to declare variables that are used only in the evaluation of a generate block. - These variables do not exist during simulation or synthesis.
- The value of a
genvarcan be defined only in a generate loop. - Every generate loop is assigned a name, so that variables inside the generate loop can be referenced hierarchically.
- The keyword
Examples of Generate Blocks
Example 1: Design of a Parameterized Bitwise XOR
module xor_bitwise (f, a, b);
parameter N = 16;
output [N-1:0] f;
input [N-1:0] a, b;
genvar p;
generate
for (p=0; p<N; p=p+1)
begin: xorlp
xor XG (f[p], a[p], b[p]);
end
endgenerate
endmodule
- In the bitwise xor example, the name
xorlpwas given to the generate loop. - The relative hierarchical names of the xor gates will be:
xorlp[0].XG, xorlp[1].XG, ..., xorlp[15].XG.
Example 2: Design of N-bit Ripple Carry Adder
- We can use
generateto dynamically create N copies of a full adder and connect them to make an N-bit ripple-carry adder. - Full Adder Module:
module full_adder (a, b, c, sum, cout); input a, b, c; output, sum, cout; wire t1, t2, t3; xor G1 (t1, a, b); xor G2 (sum, t1, c); and G3 (t2, a, b); and G4 (t3, t1, c); or G5 (cout, t2, t3); endmodule - RCA Module using
generate:module RCA (carry_out, sum, a, b, carry_in); parameter N = 8; input [N-1:0] a, b; input carry_in; output [N-1:0] sum; output carry_out; wire [N:0] carry; assign carry[0] = carry_in; assign carry_out = carry[N]; genvar i; generate for (i=0; i<N; i++) begin: fa_loop // This implicitly instantiates a full adder wire t1, t2, t3; xor G1 (t1, a[i], b[i]); xor G2 (sum[i], t1, carry[i]); and G3 (t2, a[i], b[i]); and G4 (t3, t1, carry[i]); or G5 (carry[i+1], t2, t3); end endgenerate endmodule - Some of the relative hierarchical instance names that are generated are:
fa_loop[0].G1,fa_loop[1].G1,fa_loop[7].G1, etc. - Some of the nets (
wires) that are generated are:fa_loop[0].t1,fa_loop[1].t2,fa_loop[0].t3, etc.