4. Procedural assignments

4.1. Introduction

In Chapter 2, a 2-bit comparator is designed using ‘procedural assignments’. In that chapter, ‘if’ keyword was used in the ‘always’ statement block. This chapter presents some more such keywords which can be used in procedural assignments.

4.2. Combinational circuit and sequential circuit

Digital design can be broadly categorized in two ways i.e. combinational designs and sequential designs. It is very important to understand the differences between these two designs and see the relation between these designs with various elements of Verilog.

  • Combinational designs : Combinational designs are the designs in which the output of the system depends on present value of the inputs only. Since, the outputs depends on current inputs only, therefore ‘no memory’ is required for these designs. Further, memories are nothing but the ‘flip flops’ in the digital designs, therefore there is no need of ‘flip flops’ in combination designs. In the other words, only ‘logic gates (i.e. and, not and xor etc.)’ are required to implement the combinational designs.
  • Sequential designs : Sequential designs are the designs in which the output depends on current inputs and previous states of the system. Since output depends on previous states, therefore ‘memories’ are required for these systems. Hence, in the sequential designs the ‘flip flops’ are needed along with the logic gates.
../_images/combSeqBlock.jpg

Fig. 4.1 Block diagram of ‘combinational’ and ‘sequential’ designs

4.3. Concurrent statements and sequential statements

In Listing 2.3, we saw that the concurrent statements execute in parallel, i.e. the order of the statement does not matter. Whereas Listing 2.6 shows the example of ‘sequential statements’ where the statements execute one by one. Following are the relationship between ‘statements’ and ‘design-type’,

  • Please note that ‘sequential statements’ and ‘sequential designs’ are two different things. Do not mix these together.
  • Combinational designs can be implemented using both ‘sequential statements’ and ‘concurrent statements’.
  • Sequential designs can be implemented using ‘sequential statements’ only.
  • Sequential statements can be defined inside ‘always’ block only. Further, these blocks executes concurrently e.g. if we have more than one always block then these block will execute in parallel, but statements inside each block will execute sequentially.
  • Sequential designs are implemented using various constructs e.g. ‘if’, ‘case’ and ‘for’ etc., which are discussed in this chapter.
  • Conditional operator (?:) can be used for combinational designs.

Note

Remember : (see the words ‘design’, ‘logic’ and ‘statement’ carefully)

  • Only ‘logic gates (i.e. and, not and xor etc.)’ are required to implement the combinational designs.
  • Both ‘logic gates’ and ‘flip flops’ are required for implementing the sequential designs.
  • Lastly, the ‘sequential design’ contains both ‘combinational logics’ and ‘sequential logics’, but the combinational logic can be implement using ‘sequential statements’ only as shown in Fig. 4.1; whereas the ‘combination logic’ in the combinational designs can be implemented using both ‘concurrent’ and ‘sequential’ statements.

4.4. ‘always’ block

All the statements inside the always block execute sequentially. Further, if the module contains more than one always block, then all the always blocks execute in parallel, i.e. always blocks are the concurrent blocks.

Note

Note that, we can write the complete design using sequential programming (similar to C, C++ and Python codes). But that may result in very complex hardware design, or to a design which can not be synthesized at all. The best way of designing is to make small units using ‘continuous assignment statements’ and ‘procedural assignment statements’, and then use the structural modeling style to create the large system.

4.5. Blocking and Non-blocking assignment

There are two kinds of assignments which can be used inside the always block i.e. blocking and non-blocking assignments. The ‘=’ sign is used in blocking assignment; whereas the ‘<=’ is used for non-blocking assignment as shown in Listing 4.1 and Listing 4.2. Both the listings are exactly same expect the assignment signs at lines 13-14. Due to different in assignment signs, the design generated by these listings are different as shown in Fig. 4.2 and Fig. 4.3, which are explained below.

Explanation Listing 4.1

In line 10, value of input port ‘x’ is assigned to output ‘z’. Since, the value of ‘z’ is equal to ‘x’, therefore line 11 will be equivalent to ‘z = x + y’; due to this reason, the design is generated as ‘and’ gate with inputs ‘x’ and ‘y’ as shown in Fig. 4.2.

Listing 4.1 Blocking assignment, Fig. 4.2
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// blockAssignment.v

module blockAssignment(
    input wire x, y, 
    output reg z
);

always @(x,y)  
begin
    z = x;  // since z = x
    z = z & y;  // therefore, z = x + y;
end
endmodule
../_images/blockAssignment.jpg

Fig. 4.2 Blocking assignment, Listing 4.1

../_images/nonblockAssignment.jpg

Fig. 4.3 Non-blocking assignment, Listing 4.2

Explanation Listing 4.2:

In non-blocking assignment, updated values inside the block are not used for assignment.} In line 10, value of input port ‘x’ is assigned to the ‘z’. Since updated value inside the block are not used in non-blocking assignment, therefore in line 11, ‘z = z & y;’, the old value of ‘z’ will be used for assignments (instead of z=x); hence a feedback path is used in Fig. 4.3. Also, ‘x’ has no effect on the design as it is updating ‘z’ inside the block, which will not be used by non-blocking assignment; hence ‘x’ is not connected (i.e. connected to ground) in the design as shown in Fig. 4.3.

Listing 4.2 Non-blocking assignment, Fig. 4.3
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// nonblockAssignment.v

module nonblockAssignment(
    input wire x, y, 
    output reg z
    );

always @(x,y)  
begin
    z <= x; // z_new = x
    z <= z & y; // z_new = z_entry + y (not z = z_new + y)
end
endmodule

Note

The block and non-blocking assignments can not be used together for a signal. For example, the below assignment will generate error as both ‘blocking’ and ‘non-blocking’ assignments are used for ‘z’,

z = x; // blocking assignment
z <= z & y; // non-blocking assignment

4.6. Guidelines for using ‘always’ block

The general purpose ‘always’ block of Verilog can be misused very easily. And the misuse of this block will result in different ‘simulation’ and ‘synthesis’ results. In this section, the general guidelines are provided for using the ‘always’ block in different conditions.

Further, we can use the specilialized ‘always’ blocks of SystemVerilog to avoid the ambiguities in synthesis and simulation results, which are discussed in Section 10.4.

Note

Note that, the ‘always’ block is used for ‘synthesis (i.e. with sensitive list)’ as well as ‘simulation (i.e. with and without sensitive list)’, which have different set of semantic rules. If we do not follow the below guidelines in the designs, then simulation and synthesis tools will infer different set of rules, which will result in differences in synthesis and simulation results.

Further, SystemVerilog has specialized ‘always blocks’ for different types of designs (see Section 10.4), which can catch the errors when the designs are not created according to below rules.

4.6.1. ‘always’ block for ‘combinational designs’

Follow the below rules for combinational designs,

  • Do not use the ‘posedge’ and ‘negedge’ in sensitive list.
  • Sensitive list should contain all the signals which are read inside the block.
  • No variable should be updated outside the ‘always’ block.
  • Use blocking assignment (i.e. = ) for assigning values.
  • All the variables should be updated for all the possible input conditions i.e. if-else and case statements should include all the possible conditions; and all the variables must be updated inside all the conditions.

4.6.2. ‘always’ block for ‘latched designs’

Follow the below rules for latched designs,

  • Do not use the ‘posedge’ and ‘negedge’ in sensitive list.
  • Sensitive list should contain all the signals which are read inside the block.
  • No variable should be updated outside the ‘always’ block.
  • Use blocking assignment (i.e. = ) for assigning values.
  • At least one the variables should not be updated for some of the possible input conditions.

4.6.3. ‘always’ block for ‘sequential designs’

Follow the below rules for sequential designs,

  • Use either ‘posedge’ or ‘negedge’ (not both) in sensitive list for all the elements.
  • No variable should be updated outside the ‘always’ block.
  • Use non-blocking assignment (i.e. <= ) for assigning values.

4.7. If-else statement

In this section, a 4x1 multiplexed is designed using If-else statement. We already see the working of ‘if’ statement in the Chapter 2. In lines 11-24 of Listing 4.3, ‘else if’ and ‘else’ are added to ‘if’ statement. Note that, If-else block can contain multiple ‘else if’ statements between one ‘if’ and one ‘else’ statement. Further, ‘begin - end’ is added in line 12-15 of Listing 4.3, which is used to define multiple statements inside ‘if’, ‘else if’ or ‘else’ block. Fig. 4.5 shows the waveform generated by Modelsim for Listing 4.3.

Note that, we are generating the exact designs as the VHDL tutorials, therefore line 22-23 are used. Also, we can remove the line 22-23, and change line 20 with ‘else’, which will also work correctly.

../_images/ifEx.jpg

Fig. 4.4 Multiplexer using if statement, Listing 4.3

Listing 4.3 Multiplexer using if statement
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// ifEx.v

module ifEx(
    input wire[1:0] s,
    input wire i0, i1, i2, i3, 
    output reg y
);

always @(s)
begin
    if (s==2'b00)
        begin //begin-end is required for more than one statements
            y = i0;
            // more statements
        end
    else if (s==2'b01)
            y = i1;
    else if (s==2'b10)
            y = i2;
    else if (s==2'b11)
            y = i3;
    else
        y = y; // no change
end

endmodule
../_images/ifExWave.jpg

Fig. 4.5 Waveforms of Listing 4.3 and Listing 4.4

4.8. Case statement

Case statement is shown in lines 11-16 of Listing 4.4. ‘s’ is used in case statement at line 11; whose value is checked using ‘when’ keyword at lines 12 and 13 etc. The value of the output y depends on the value of ‘s’ e.g. if ‘s’ is ‘1’, then line 12 will be true, hence value of ‘i1’ will be assigned to ‘y’. Note that, we can use ‘integer’ notation (line 12) as well as ‘binary’ notation (line 13) in ‘case’ and ‘if’ statements. Design generated by Listing 4.4 is shown in Fig. 4.6.

Listing 4.4 Multiplexer using case statement
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
// caseEx.v

module caseEx(
    input wire[1:0] s,
    input wire i0, i1, i2, i3, 
    output reg y
);

always @(s)
begin
    case (s)
        0 : y = i0;
        2'b01 : y = i1;
        2 : y = i2;
        3 : y = i3; 
    endcase
end
endmodule
../_images/caseEx.jpg

Fig. 4.6 Multiplexer using case statement, Listing 4.4

We need not to define all the possible cases in the ‘case-statement’, the ‘default’ keyword can be used to provide the output for undefined-cases as shown in Listing 4.5. Here, only two cases are defined i.e. 7 and 3; for the rest of the cases, the default value (i.e. i2) will be sent to the output.

Listing 4.5 Case-statement with default values
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// caseEx2.v

module caseEx2(
    input wire[2:0] s,
    input wire [1:0] i0, i1, i2,
    output reg [1:0] y
);

always @(s)
begin
    case (s)
        7 : y = i0; // 7
        3 : y = i1; // 3
        default : y = i2; // 0, 1, 3, 4, 5
    endcase
end
endmodule

4.9. Problem with Loops

Verilog provides two loop statements i.e. ‘for’ loop and ‘while’ loop’. These loops are very different from software loops. Suppose ‘for i = 1 to N’ is a loop’, then, in software ‘i’ will be assigned one value at time i.e. first i=1, then next cycle i=2 and so on. Whereas in Verilog, N logics will be implement for this loop, which will execute in parallel. Also, in software, ‘N’ cycles are required to complete the loop, whereas in Verilog the loop will execute in one cycle.

Note

As loops implement the design-units multiple times, therefore design may become large and sometimes can not be synthesized as well. If we do not want to execute everything in one cycle (which is almost always the case), then loops can be replaced by ‘case’ statements and ‘conditional’ statements as shown in section Section 4.10. Further, due to these reasons, we do not use loops in the design, and hence these are not discussed in the tutorial.

4.10. Loop using ‘if’ statement

In Listing 4.6, a loop is created using ‘if’ statement, which counts the number upto input ‘x’.

Explanation Listing 4.6

In the listing, two ‘always’ blocks are used i.e. at lines 20 and 33. The process at line 20 checks whether the signal ‘count’ value is ‘less or equal’ to input x (line 22), and sets the currentState to ‘continueState’; otherwise if count is greater than the input x, then currentState is set to ‘stopState’.

Then next ‘always’ statement (line 33), increase the ‘count’ by 1, if currentState is ‘continueState’; otherwise count is set to 0 for stopState. Finally count is displayed at the output through line 41. In this way, we can implement the loops using the ‘always’ statements.

Fig. 4.7 shows the loop generated by the listing with parameter N=1. Further, Fig. 4.8 shows the count-waveforms generated by the listing with parameter N = 3.

Warning

Sensitivity list is still not correct in the Listing 4.6 e.g. we do not put the ‘x’ in the sensitive list at Line 20 which is used inside the ‘always’ block. Further, the ‘clk’ is unnecessarily used at Line 33.

Although the results are correct, but such practice leads to undetectable errors in large designs. We will see the correct style of coding in Chapter 7.

Listing 4.6 Loop using ‘if’ statement
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// ifLoop.v (-- This code is for simulation purpose only)
// ideally positive or negative clock edge must be used; which will be discussed later.
module ifLoop
    #(
        parameter N = 3, 
                  M = 2 //not used
    )
    (
    input wire clk,
    input wire[N:0] x, 
    output wire[N:0] z
    );
localparam 
    continueState = 1'b0,
    stopState = 1'b1;

reg currentState;
reg [N:0] count = 0; 

always @(clk, currentState, count)
begin
    if(count<=x)
        currentState = continueState;
    else
        currentState = stopState;
end

// simulation and synthesis difference in verilog: 
// if count is added to sensitivity list i.e. always @(clk, currentState, count) 
// then always block must create an infinite loop (see exaplation)
// but this simulator will work fine for this case
// such error can not be detected in verilog.
always @(clk, currentState) 
begin
    if(currentState==continueState)
        count = count+1;
    else
        count = 0;
end

assign z = count;
endmodule
../_images/ifLoop.jpg

Fig. 4.7 Loop using ‘if’ statement, Listing 4.6 with N = 1

../_images/ifLoopWave.jpg

Fig. 4.8 Loop using ‘if’ statement, Listing 4.6 with N = 3

Note

Sensitivity list of the always block should be implemented carefully. For example, if we add ‘count’ in the sensitivity list at line 33 of Listing Listing 4.6, then the always block will execute infinite times. This will occur because the always block execute whenever there is any event in the signals in the sensitivity list; therefore any change in ‘count’ will execute the block, and then this block will change the ‘count’ value through line 36. Since ‘count’ value is changed, therefore always block will execute again, and the loop will never exit.

Another problem is that, above error can not be detected during simulation phase, i.e. simulation will show the correct results. Such errors are very difficult to find in Verilog. Further, such errors can be identified in VHDL code, as shown in VHDL tutorials. To avoid such errors in Verilog, please follow the guidelines for using the ‘always’ block as described in Section 4.6.

4.11. Conclusion

In this chapter, various statements for procedural assignments are discussed. Problem with loops are discussed and finally loop is implemented using ‘if’ statement. Lastly, it is shown that, Verilog designs can have differences in simulation results and implementation results.