10. SystemVerilog for synthesis

10.1. Introduction

In this chapter, we will convert some of the Verilog code into SystemVerilog code. Then, from next chapter, we will see various features of SystemVerilog.

Warning

  • We used Vivado for simulation of SystemVerilog codes, as free version of Modelsim (which is available with Quartus) can not simulate all the SystemVerilog features.

In Vivado, do following after making the changes in the code (otherwise changes may not be shown in the simulation),

  • Close the previous simulation
  • Then, right click on the ‘Run simulation->Reset Behaviour simulation’
  • Then, run the Behaviour-simulation again

10.2. Verilog, VHDL and SystemVerilog

Both Verilog and VHDL languages have their own advantages. Note that, the codes of this tutorial are implemented using VHDL in the other tutorial ‘FPGA designs with VHDL’ which is available on the website. If we compare the Verilog language with the VHDL language, we can observe the following things,

  • Verilog has a very limited set of keywords; but we can implement all the VHDL designs using Verilog.
  • Verilog codes are smaller as compare to VHDL codes.
  • VHDL is strongly typed language, therefore lots of conversions may require in it, which make the codes more complex than the Verilog codes. Also due to this reason, it may take more time to write the VHDL codes than the Verilog codes.
  • The general purpose ‘always’ block’ of Verilog needs to be used very carefully. It is the designer’s responsibility to use it correctly, as Verilog does not provide any option to check the rules. Any misuse of ‘always’ block will result in different ‘simulation’ and ‘synthesis’ results, which is very hard to debug. Whereas the behavior of VHDL is accurate, i.e. there is no ambiguity between the simulation and synthesize results.
  • The user-defined type (enumerated type) can not be defined in Verilog, which is a very handy tool in VHDL for designing the FSM.

The SystemVerilog language is the superset of Verilog and contains various features of other programming language i.e. C (structure, and typedef), C++ (class and object) and VHDL (enumerated data type, continue and break statements). Most importantly, it replaces the general purpose ‘always’ block with three different blocks i.e. ‘always_ff’, ‘always_comb’ and ‘always_latch’, which remove the Verilog’s ambiguity between simulation and synthesis results. Also, the compiler can catch the error if these new always-blocks are not implemented according to predefined rules. In this chapter, we will reimplement the some of the designs of previous chapters using SystemVerilog to learn and compare the SystemVerilog with Verilog.

Note

SystemVerilog is a vast language with several complex features. For example, it has the object oriented programming features (i.e. class and objects), interfaces and structures etc. Similar to other programming languages (e.g. C, C++ and Python), usage of these features requires proper planning and methodology, otherwise these features can harm more than their advantages.

In this tutorial, we have the following aims regarding the use of SystemVerilog to enhance the capabilities of Verilog language,

  • Use of new ‘always blocks’ of SystemVerilog to remove the ambiguities between the simulation and the synthesis results.
  • Use of ‘enumerated data type’ to write more readable and manageable FSM designs.
  • In this tutorial, we will not use the various important SystemVerilog features like packages, interface and structure etc. in the designs, which are related to managing the large designs and require proper planning for implementation.

10.3. ‘logic’ data type

In previous chapters, we saw that the ‘reg’ data type (i.e. variable type) can not used outside the ‘always’ block, whereas the ‘wire’ data type (i.e. net type) can not be used inside the ‘always’ block. This problem can be resolved by using the new data type provided by the SystemVerilog i.e. ‘logic’.

Note

Please note the following point regarding ‘logic’,

  • ‘logic’ and ‘reg’ can be used interchangeably.
  • Multiple drivers can not be assigned to ‘logic’ data type i.e. values to a variable can not be assigned through two different places.
  • Multiple-driver logic need to be implemented using net type e.g. ‘wire’, ‘wand’ and ‘wor’, which has the capability of resolving the multiple drivers. Since, we did not use the ‘wire’ to drive the multiple-driver logic in this tutorial, therefore ‘wire’ can also be replace by ‘logic’.
  • Listing 2.6 is reimplemented in Listing 10.1, where both ‘wire’ and ‘reg’ are replaced with ‘logic’ keyword.
Listing 10.1 Two bit comparator
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
// comparator2BitProcedure.sv
// Meher Krishna Patel 
// Date : 04-Sep-17

module comparator2BitProcedure
(   input logic[1:0] a, b,
    output logic eq
);
 
always @(a,b) begin
    if (a[0]==b[0] && a[1]==b[1]) 
        eq = 1;
    else
        eq = 0;
end

endmodule
    

10.4. Specialized ‘always’ blocks

In Section 4.2, we saw that a sequential design contains two parts i.e. ‘combination logic’ and ‘sequential logic’. The general purpose ‘always’ block is not intuitive enough to understand the type of logic implemented by it. Also, the synthesis tool has to spend the time to infer the type of logic the design intended to implement. Further, if we forgot to define all the outputs inside all the states of a combination logic, then a latch will be inferred and there is no way to detect this type of errors in Verilog. To remove these problems, three different types of ‘always’ blocks are introduced in SystemVerilog, i.e. ‘always_ff’, ‘always_comb’ and ‘always_latch’, which are discussed below,

10.4.1. ‘always_comb’

The ‘always_comb’ block represents that the block should be implemented by using ‘combinational logic’; and there is no need to define the sensitivity list for this block, as it will be done by the software itself. In this way SystemVerilog ensures that all the software tools will infer the same sensitivity list. The example of the ‘always_comb’ block is shown in Listing 10.2.

Listing 10.2 ‘always_comb’ example
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// always_comb_ex.sv

module always_comb_ex
(
    input logic a, b,
    output logic y, z
);

always_comb begin 
    if (a > b) begin 
        y = 1;
        z = 0;
    end
    else if (a < b) begin
        y = 0;
        z = 1;
    end
    else begin
        y = 1;
        z = 1;
    end
end 

endmodule 

Further, if the design can not be implemented by ‘pure combinational’ logic, then the compiler will generate the error as shown in Listing 10.3. In this listing, we commented the Line 18 and Lines 21-24. In this case, a latch will be inferred (see comments), therefore error will be reported as shown in Lines 8-9. Also, the information about the latch will be displayed by the software as shown in Lines 10-11.

Listing 10.3 Error for incomplete list of outputs in ‘always_comb’ block
 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
// always_comb_error_ex.sv
module always_comb_error_ex
(
    input logic a, b,
    output logic y, z
);

// Error (10166): SystemVerilog RTL Coding error at always_comb_error_ex.sv(13): always_comb 
// construct does not infer purely combinational logic
// Info (10041): Inferred latch for "z" at always_comb_error_ex.sv(17)
// Info (10041): Inferred latch for "y" at always_comb_error_ex.sv(17)
always_comb begin 
    if (a > b) begin 
        y = 1;
        z = 0;
    end
    else if (a < b) begin
        // y = 0;  // missing output will create latch
        z = 1;
    end
    // else begin   // missing 'else' block will create latch
        // y = 1;
        // z = 1;
    // end
end 

endmodule 

10.4.2. ‘always_latch’

In Listing 10.3, we saw that the implementation of the logic need a ‘latch’, therefore we can replace the ‘always_comb’ with ‘always_latch’ as done in Line of Listing 10.4 and the code will work fine. Similar to the ‘always_comb’, the ‘always_latch’ does not need the sensitive list.

Listing 10.4 ‘always_latch’ example
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// always_latch_ex.sv
module always_latch_ex
(
    input logic a, b,
    output logic y, z
);

always_latch begin 
    if (a > b) begin 
        y = 1;
        z = 0;
    end
    else if (a < b) begin
        // y = 0;  // missing output will create latch
        z = 1;
    end
    // else begin   // missing 'else' block will create latch
        // y = 1;
        // z = 1;
    // end
end 

endmodule 

Similarly, the Listing 10.2 was implemented using pure combination logic. If we change the ‘always_comb’ with ‘always_logic’ in that listing, then error will be reported as no ‘latch’ is required for this design as shown in Lines 8-9 of Listing 10.5.

Listing 10.5 Error for latch logic as the design can be implemented using pure combination logic
 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
// always_latch_error_ex.sv
module always_latch_error_ex
(
    input logic a, b,
    output logic y, z
);

// Error (10165): SystemVerilog RTL Coding error at always_latch_error_ex.sv(11): 
// always_latch construct does not infer latched logic
always_latch begin 
    if (a > b) begin 
        y = 1;
        z = 0;
    end
    else if (a < b) begin
        y = 0;  // missing output will create latch
        z = 1;
    end
    else begin   // missing 'else' block will create latch
        y = 1;
        z = 1;
    end
end 

endmodule 

10.4.3. ‘always_ff’

The ‘always_ff’ will result in ‘sequential logic’ as shown in Listing 10.6. Also, we need to define the sensitivity list for this block. Further, do not forget to use ‘posedge’ or ‘negedge’ in the sensitive list of the ‘always_ff’ block, otherwise the ‘D-FF’ will not be inferred.

Listing 10.6 Sequential logic
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
// always_ff_ex.sv

module always_ff_ex
(
    input logic clk, reset,
    output logic y, z
);

always_ff @(posedge clk, posedge reset) begin
    if (reset) begin
        y <= 0;
        z <= 0;
    end
    else begin
        y <= 1;
        z <= 1;
    end
end

endmodule 

10.5. User define types

Unlike VHDL, the Verilog does not have the userdefined variables, which is a very handy tool in VHDL. Hence, we need to define states-types and states as ‘localparam’ and ‘reg’ respectively, as shown in Listing 7.12. SystemVerilog adds two more functionalities, i.e. ‘enum’ and ‘typedef’, which can be used to define the ‘user-defined (i.e. typedef) enumerated (i.e. enum) type’. In this section, we will learn these two keywords with an example.

10.5.1. ‘typedef’

The keyword ‘typedef’ is similar to typedef-keyword in C. The ‘typedef’ is used to create the ‘user-defined datatype’, as shown in Listing 10.7.

Listing 10.7 ‘typedef’ example
typedef logic [31:0] new_bus; // create a new variable 'new_bus' of size 32
new_bus data_bus, address_bus; // two variables of new data type 'new_bus'

10.5.2. ‘enum’

The ‘enum’ is used to define the ‘abstract variable’ which can have a specific set of values, as shown below. Note that if the type is not defined in ‘enum’ then the type will be set as ‘integer’ by default, which may use extra memory unnecessarily. For example in Listing 10.8, the variable ‘num_word1’ has only 3 possible values, but it size is 32 bit (by default); therefore it is wise to define the type of enum as well, as done for the variable ‘new_word2’ in the listing.

Listing 10.8 ‘enum’ example
// default type is integer i.e. new_word1 will have the size of 32 bit
enum {one, two, three} num_word1; // variable num_word1 can have only three types of values
num_word1 = one; // assign one to num_word1

// size of new_word2 is 2-bits
enum logic [1:0] {seven, eight, nine} new_word2
new_word2 = seven

10.5.3. Example

In this tutorial, we will use the user-defined type for creating the states of the FSM. For this, we have to use both the keywords together, i.e. ‘typedef’ and ‘enum’ as shown in Listing 10.9. In this listing, the Listing 7.14 is reimplemented using SystemVerilog. The simulation result of the listing is the same as the Fig. Fig. 7.18.

Listing 10.9 FSM using ‘typedef’ and ‘enum’
 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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
// enum_typedef_example.sv

module enum_typedef_example
#( parameter 
        N = 4, // Number of bits to represent the time
        on_time = 3'd5,
        off_time = 3'd3
)
(
    input logic clk, reset,
    output logic s_wave
);

    
//    use below line for more than two states, and change
//    [1:0] to desired size e.g if state_t has 12 values then 
//    use [3:0] etc.
//    typedef enum logic[1:0] {onState, offState} state_t;
    typedef enum logic {onState, offState} state_t;
    state_t state_reg, state_next;

    logic [N-1:0] t = 0;
    
    always_ff @(posedge clk, posedge reset) begin 
        if (reset == 1'b1)
            state_reg <= offState; 
        else
            state_reg <= state_next;
    end
    
    always_ff @(posedge clk, posedge reset) begin 
        if (state_reg != state_next)
            t <= 0;
        else
            t <= t + 1;
    end

    always_comb begin
        case (state_reg)
            offState : begin
                s_wave = 1'b0; 
                if (t == off_time - 1) 
                    state_next = onState;
                else
                    state_next = offState; 
            end
            onState : begin
                s_wave = 1'b1; 
                if (t == on_time - 1)
                    state_next = offState;
                else
                    state_next = onState;
            end
        endcase
    end
endmodule 

10.6. Conclusion

In this chapter, we discussed of the synthesis-related-features of SystemVerilog which can be used to remove the risk of errors in Verilog. Further, we learn the user-defined types which makes the SystemVerilog codes more readable than the Verilog codes. Also, we learn the ‘logic’ datatype which can used in place of ‘reg’ and ‘wire’. Further, we did not use the various features of SystemVerilog like packages, interface and structure etc. in the designs, which are related to managing the large designs.