Verilog has four levels of modelling:
1) The switch level which includes MOS transistors modelled as switches. This is not discussed here.
2) The gate level. See “Gate-Level Modelling” on p. 3
3) The Data-Flow level. See Example 7 .4 on page 11
4) The Behavioral or procedural level described below.
Verilog procedural statements are used to model a design at a higher level of abstraction than the other levels. They provide powerful ways of doing complex designs. However small changes n coding methods can cause large changes in the hardware generated. Procedural statements can only be used in procedures.
Procedural Assignments
Procedural assignments are assignment statements used within Verilog procedures (always and initial blocks). Only reg variables and integers (and their bit/part-selects and concatenations) can be placed left of the “=” in procedures.
Delay in Assignment (not for synthesis)
In a delayed assignment â..t time units pass before the statement is executed and the left-hand assignment is made. With intra-assignment delay, the right side is evaluated immediately but there is a delay of â..t before the result is place in the left hand assignment. If another procedure changes a right-hand side signal during â..t, it does not effect the output. Delays are not supported by synthesis tools.
Syntax for Procedural Assignment variable = expression Delayed assignment #â..t variable = expression; Intra-assignment delay variable = #â..t expression; | ![]() |
Blocking Assignments
Procedural (blocking) assignments (=) are done sequentially in the order the statements are written. A second assignment is not started until the preceding one is complete.
SyntaxBlocking variable = expression; variable = #â..t expression; grab inputs now, deliver ans. later. #â..t variable = expression;grab inputs later, deliver ans later | ![]() ![]() |
Nonblocking (RTL) Assignments (see below for synthesis)
RTL (nonblocking) assignments (<=), which follow each other in the code, are done in parallel. The right hand side of nonblocking assignments is evaluated starting from the completion of the last blocking assignment or if none, the start of the procedure. The transfer to the left hand side is made according to the delays. A delay in a non-blocking statement will not delay the start of any subsequent statement blocking or non-blocking. A good habit is to use “<=” if the same variable appears on both sides of the equal sign.
For synthesis
• One must not mix “<=” or “=” in the same procedure.
• “<=” best mimics what physical flip-flops do; use it for “always @ (posedge clk ..) type procedures.
• “=” best corresponds to what c/c++ code would do; use it for combinational procedures.
Syntax Non-Blocking variable <= expression; variable <= #â..t expression; #â..t variable <= expression; | ![]() ![]() ![]() |
The following example shows interactions between blocking and non-blocking for simulation. Do not mix the two types in one procedure for synthesis.
SyntaxNon-Blocking variable <= expression; variable <= #â..t expression; ?#â..t variable <=expression;Blocking variable = expression; variable = #â..t expression; #â..t variable = expression; | ![]() |
begin … end
begin … end block statements are used to group several statements for use where one statement is syntactically allowed. Such places include functions, always and initial blocks, if, case and for statements. Blocks can optionally be named and can include register, integer and parameter declarations.
Syntax begin : block_name reg [msb:lsb] reg_variable_list; integer [msb:lsb] integer_list; parameter [msb:lsb] parameter_list; … statements … end | ![]() |
for Loops
Similar to for loops in C/C++, they are used to repeatedly execute a statement or block of statements. If the loop contains only one statement, the begin … end statements may be omitted.
Syntaxfor (count = value1; count />= value2; count = count +/- step) begin … statements … end | ![]() |
while Loops
The while loop repeatedly executes a statement or block of statements until the expression in the while statement evaluates to false. To avoid combinational feedback during synthesis, a while loop must be broken with an @(posedge/negedge clock) statement (Section 9.2). For simulation a delay inside the loop will suffice. If the loop contains only one statement, the begin … end statements may be omitted.
Syntax while (expression) begin … statements … end | ![]() |
forever Loops
The forever statement executes an infinite loop of a statement or block of statements. To avoid combinational feedback during synthesis, a forever loop must be broken with an @(posedge/negedge clock) statement . For simulation a delay inside the loop will suffice. If the loop contains only one statement, the begin … end statements may be omitted. It is
Syntax forever begin … statements … end | ![]() |
repeat Not synthesizable
The repeat statement executes a statement or block of statements a fixed number of times.
Syntax repeat (number_of_times) begin … statements … end | ![]() |
disable
Execution of a disable statement terminates a block and passes control to the next statement after the block. It is like the C break statement except it can terminate any loop, not just the one in which it appears.
Disable statements can only be used with named blocks.
Syntax disable block_name; | ![]() |
if … else if … else
The if … else if … else statements execute a statement or block of statements depending on the result of the expression following the if. If the conditional expressions in all the if’s evaluate to false, then the statements in the else block, if present, are executed.
There can be as many else if statements as required, but only one if block and one else block. If there is one statement in a block, then the begin .. end statements may be omitted.
Both the else if and else statements are optional. However if all possibilities are not specifically covered, synthesis
will generated extra latches.
Syntax if (expression) begin … statements … end else if (expression) begin … statements … end … more else if blocks … else begin … statements … end | ![]() |
case
The case statement allows a multipath branch based on comparing the expression with a list of case choices. Statements in the default block executes when none of the case choice comparisons are true (similar to the else block in the if … else if … else). If no comparisons , including delault, are true, synthesizers will generate unwanted latches.
Good practice says to make a habit of puting in a default whether you need it or not.
If the defaults are dont cares, define them as ‘x’ and the logic minimizer will treat them as don’t cares.
Case choices may be a simple constant or expression, or a comma-separated list of same.
Syntax case (expression) case_choice1: begin … statements … end case_choice2: begin … statements … end … more case choices blocks … default: begin … statements … end endcase | ![]() ![]() |
casex
In casex(a) the case choices constant “a” may contain z, x or ? which are used as don’t cares for comparison. With case the corresponding simulation variable would have to match a tri-state, unknown, or either signal. In short, case uses x to compare with an unknown signal. Casex uses x as a don’t care which can be used to minimize logic.
Syntax same as for case statement | ![]() |
casez
Casez is the same as casex except only ? and z (not x) are used in the case choice constants as don’t cares. Casez is favored over casex since in simulation, an inadvertent x signal, will not be matched by a 0 or 1 in the case choice.
Syntax same as for case statement | ![]() |