An enumerated type defines a set of named values. In the following example, light_* is an enumerated variable that can store one of the three possible values (0, 1, 2). By default, the first name in the enumerated list gets the value 0 and the following names get incremental values like 1 and 2.

  
  
	enum          {RED, YELLOW, GREEN}         light_1;         // int type; RED = 0, YELLOW = 1, GREEN = 2
	enum bit[1:0] {RED, YELLOW, GREEN}         light_2;         // bit type; RED = 0, YELLOW = 1, GREEN = 2

  

The user can assign any integer value for any of the enumerated names. If any name does not have an assigned value, then it automatically takes the incremented value of the previous name.

  
  
	enum          {RED=3, YELLOW, GREEN}       light_3;         // RED = 3, YELLOW = 4, GREEN = 5
	enum          {RED = 4, YELLOW = 9, GREEN} light_4;         // RED = 4, YELLOW = 9, GREEN = 10 (automatically assigned)
	enum          {RED = 2, YELLOW, GREEN = 3} light_5;         // Error : YELLOW and GREEN are both assigned 3
	
	enum bit[0:0] {RED, YELLOW, GREEN} light_6;                 // Error: minimum 2 bits are required

  

What is a SystemVerilog string ?

The string data-type is an ordered collection of characters. The length of a string variable is the number of characters in the collection which can have dynamic length and vary during the course of a simulation. A string variable does not represent a string in the same way as a string literal. No truncation occurs when using the string variable.

Syntax

  
  
	string  variable_name [= initial_value];

  

variable_name is a valid identifier and the optional initial_value can be a string literal, the value "" for an empty string, or a string data type expression. If an initial value is not specified at the time of declaration, then the variable defaults to "", an empty string literal.

In the previous article, an overview of the major data types were given. In this session, we'll look at 4-state and 2-state variables and two new data types called logic and bit.

4-state data types

Types that can have unknown (X) and high-impedance (Z) value in addition to zero (0) and one (1) are called 4-state types. Note that reg can only be driven in procedural blocks like always and initial while wire data types can only be driven in assign statements. SystemVerilog introduces a new 4-state data type called logic that can be driven in both procedural blocks and continuous assign statements. But, a signal with more than one driver needs to be declared a net-type such as wire so that SystemVerilog can resolve the final value.

logic

  
  
module tb;
	logic [3:0]  my_data; 		// Declare a 4-bit logic type variable
	logic        en; 			// Declare a 1-bit logic type variable
	
	initial begin
    	$display ("my_data=0x%0h en=%0b", my_data, en);    	// Default value of logic type is X
		my_data = 4'hB; 									// logic datatype can be driven in initial/always blocks
      	$display ("my_data=0x%0h en=%0b", my_data, en); 	 
      	#1;
      	$display ("my_data=0x%0h en=%0b", my_data, en);
	end
  
  	assign en = my_data[0]; 								// logic datatype can also be driven via assign statements
endmodule

  
Simulation Log
ncsim> run
my_data=0xx en=x
my_data=0xb en=x
my_data=0xb en=1
ncsim: *W,RNQUIE: Simulation is complete.

2-state data types

In a typical verification testbench, there are many cases where we don't really need all the four values (0, 1, x, z) like for example when modeling a network packet with a header that specifies the length of the packet.Length is usually a number, but not X and Z. SystemVerilog adds many new 2-state data types that can only store and have a value of either 0 or 1. This will aid in faster simulation, take less memory and are preferred in some design styles.

When a 4-state value is converted to a 2-state value, any unknown or high-impedance bits shall be converted to zeros.

The most important 2-state data type is bit which is used most often in testbenches. A variable of type bit can be either 0 or 1 which represents a single bit. A range from MSB to LSB should be provided to make it represent and store multiple bits

bit

  
  
module tb;
  bit       var_a;       // Declare a 1 bit variable of type "bit"
  bit [3:0] var_b;       // Declare a 4 bit variable of type "bit"
  
  logic [3:0] x_val;     // Declare a 4 bit variable of type "logic"
  
  initial begin
  
    // Initial value of "bit" data type is 0
    $display ("Initial value var_a=%0b var_b=0x%0h", var_a, var_b);
    
    // Assign new values and display the variable to see that it gets the new values
    var_a = 1;
    var_b = 4'hF;
    $display ("New values    var_a=%0b var_b=0x%0h", var_a, var_b);
    
    // If a "bit" type variable is assigned with a value greater than it can hold
    // the left most bits are truncated. In this case, var_b can hold only 4 bits
    // and hence 'h481 gets truncated leaving var_b with only 'ha;
    var_b = 16'h481a;
    $display ("Truncated value: var_b=0x%0h", var_b);
    
    // If a logic type or any 4-state variable assigns its value to a "bit" type 
    // variable, then X and Z get converted to zero
    var_b = 4'b01zx;
    $display ("var_b = %b", var_b);
  end
endmodule

  
Simulation Log
ncsim> run
Initial value var_a=0 var_b=0x0
New values    var_a=1 var_b=0xf
Truncated value: var_b=0xa
var_b = 0100
ncsim: *W,RNQUIE: Simulation is complete.

The bins construct allows the creation of a separate bin for each value in the given range of possible values of a coverage point variable.

Usage

  
  
	
	coverpoint mode {
		// Manually create a separate bin for each value
		bins zero = {0};
		bins one  = {1};
		
		// Allow SystemVerilog to automatically create separate bins for each value
		// Values from 0 to maximum possible value is split into separate bins
		bins range[] = {[0:$]};
		
		// Create automatic bins for both the given ranges
		bins c[] = { [2:3], [5:7]};
		
		// Use fixed number of automatic bins. Entire range is broken up into 4 bins
		bins range[4] = {[0:$]};
		
		// If the number of bins cannot be equally divided for the given range, then 
		// the last bin will include remaining items; Here there are 13 values to be
		// distributed into 4 bins which yields:
		// [1,2,3] [4,5,6] [7,8,9] [10, 1, 3, 6]
		bins range[4] = {[1:10], 1, 3, 6};
		
		// A single bin to store all other values that don't belong to any other bin
		bins others = default;
	}

  

Examples

  
  
module tb;
  bit [2:0] mode;
  
  // This covergroup does not get sample automatically because
  // the sample event is missing in declaration
  covergroup cg;
    coverpoint mode {
    	bins one = {1};
    	bins five = {5};
    }
  endgroup
  
  // Stimulus : Simply randomize mode to have different values and
  // manually sample each time
  initial begin
    cg cg_inst = new();
    for (int i = 0; i < 5; i++) begin
	  #10 mode = $random;
      $display ("[%0t] mode = 0x%0h", $time, mode);
      cg_inst.sample();
    end
    $display ("Coverage = %0.2f %%", cg_inst.get_inst_coverage());
  end
 
endmodule

  
Simulation Log
ncsim> run
[10] mode = 0x4
[20] mode = 0x1
[30] mode = 0x1
[40] mode = 0x3
[50] mode = 0x5
Coverage = 100.00 %
ncsim: *W,RNQUIE: Simulation is complete.

Automatic Bins

  
  
  covergroup cg;
    coverpoint mode {
      
      // Declares a separate bin for each values -> Here there will 8 bins
      bins range[] = {[0:$]};
    }
  endgroup

  

4 out of the total possible 8 values have been sampled and hence coverage is 50%.

Simulation Log
ncsim> run
[10] mode = 0x4
[20] mode = 0x1
[30] mode = 0x1
[40] mode = 0x3
[50] mode = 0x5
Coverage = 50.00 %
ncsim: *W,RNQUIE: Simulation is complete.

Fixed Number of automatic bins

  
  
  covergroup cg;
    coverpoint mode {
      
      // Declares 4 bins for the total range of 8 values
      // So bin0->[0:1] bin1->[2:3] bin2->[4:5] bin3->[6:7]
      bins range[4] = {[0:$]};
    }
  endgroup

  

mode never got a value of 6 or 7 and hence bin3 does not get hit. But all the other bins are hit and hence coverage is 75%.

Simulation Log
ncsim> run
[10] mode = 0x4
[20] mode = 0x1
[30] mode = 0x1
[40] mode = 0x3
[50] mode = 0x5
Coverage = 75.00 %
ncsim: *W,RNQUIE: Simulation is complete.

Split fixed number of bins between a given range

  
  
  covergroup cg;
    coverpoint mode {
      
      // Defines 3 bins 
      // Two bins for values from 1:4, and one bin for value 7
      // bin1->[1,2] bin2->[3,4], bin3->7
      bins range[3] = {[1:4], 7};
    }
  endgroup

  

Only 2/3 of the bins were hit and hence coverage is at 66.67%. To be specific, bin1 and bin2 were hit because mode was sampled to have 1 and [3,4] respectively.

Simulation Log
ncsim> run
[10] mode = 0x4
[20] mode = 0x1
[30] mode = 0x1
[40] mode = 0x3
[50] mode = 0x5
Coverage = 66.67 %
ncsim: *W,RNQUIE: Simulation is complete.

Signals of type wire or a similar wire like data type requires the continuous assignment of a value. For example, consider an electrical wire used to connect pieces on a breadboard. As long as the +5V battery is applied to one end of the wire, the component connected to the other end of the wire will get the required voltage.

breadboard-circuit

In Verilog, this concept is realized by the assign statement where any wire or other similar wire like data-types can be driven continuously with a value. The value can either be a constant or an expression comprising of a group of signals.