SV Chapter 2 data types

Posted by Marchingknight11 on Sun, 23 Jan 2022 11:30:21 +0100

2.8 select storage array type

This paper introduces some criteria for selecting storage types based on flexibility, memory usage, speed and sorting requirements.

2.8.1 flexibility

  • If the index of an array is a continuous nonnegative integer, a fixed width or dynamic array should be used.
  • If the fixed width array has been selected when the array is compiled, and the array width is not known until the program runs, select the dynamic array
  • As long as the type matches, any length of queue can be passed to the subroutine
  • Array indexes are irregular, sparse distributed indexes generated by random values or addresses, and associative arrays should be selected for content-based addressing.

2.8.2 memory usage

  • Using dual state type can reduce the storage consumption during simulation
  • Associative arrays should be used to model memory on the megabyte scale

2.8.3 speed

  • It is also considered to select the array type according to the number of memory accesses per clock cycle
  • Fixed width and dynamic arrays are continuous storage space, and the time to access any location is the same
  • The read and write speed of the queue is basically the same as that of fixed width or dynamic array. Queues are accessed quickly at the beginning and end, but they need to be moved in the middle, which takes linear time
  • Associative array access needs to calculate hash table and tree, and the access speed is the slowest

2.8.4 sorting

  • SV can sort any type of one-dimensional array (fixed width, dynamic, associative array and queue), and select the array type according to the frequency of adding elements to the array
  • If all elements are added at one time, select fixed width or dynamic array, and you only need to sort the array once. If the array is added one by one, select the queue.
  • If the values of the array are discontinuous and different from each other, consider using the associative array and the element value Province as the index. Use the exist() function to check and delete.

2.8.5 select the optimal data structure

The following are suggestions for selecting common data structures:

  • Network array package. Features: fixed length, sequential access. For fixed or variable length packets, fixed width and dynamic array are adopted respectively
  • An integrator that holds the desired values. Features: the length is unknown before simulation, accessed by value, and the length changes frequently. General selection queue
  • Ordered structure. Features: if the data is output in a predictable order, a queue is used. If the output order is uncertain, an associative array is used
  • Model large capacity memory with more than one million entries. If you do not need to use all the storage space, you can use associative arrays to achieve sparse storage.
  • The command name or opcode in the file. Features: convert string to fixed value. Read the string from the file, and then use the command name as the string index to find the command name or opcode in the associative array.
    On the basis of OOP, it also involves an array of handles to objects

2.9 creating new data types using typedef

typedef statements can be used to create new data types. For example, an arithmetic logic unit ALU is required to be configured at compile time to accommodate operands with different bit widths such as 8 bits, 16 bits, 24 bits or 32 bits. In Verilog, you can define a macro for the bit width and type of operands respectively.

// Old Verilog style
`define OPSIZE 8
`defeine OPREG reg[' OPSIZE-1:0]

'OPREG op_a,op_b;

In the above case, there is no new type of innovation, but only text replacement. In SV, the following code can be used to create a new type. Convention: all custom user types have the suffix "_t".

// New SV style
parameter OPSIZE = 8;
typedef reg[OPSIZE-1:0] opreg_t;

opreg_t op_a,op_b;

Generally speaking, if the data bit width does not match, the value will be expanded or truncated. SV allows replication between these basic types without warning.
**parameter and typedef statements can be put into a package so that they can be shared by the whole design and test platform.

typedef bit[31:0] unit ;	//32-bit two state unsigned number
typedef int unsigned unit;	// Definition of equivalence

// Declare an array of this type
typedef int fixed_array5[5];
fixed_array5 f5;

initial begin
	foreach (f5[i])
		f5[i]=i;
end

2.10 create user-defined structure

One of Verilog's biggest defects is that it has no data structure. In SV, the keyword struct can be used to create, but struct has few functions. It is better to use classes directly on the test platform.
Just as Verilog modules include both data (signals) and code (always/initial code blocks and subroutines), classes contain data and programs for debugging and reuse. However, struct just organizes data together and lacks data manipulation methods.
However, because struct is a collection of data, it can be integrated. If you want to model a complex data type in the design code, such as pixels, you can put it in struct. The structure can be transferred through the module port. But if you want to generate random data with constraints, you should use classes.

2.10.1 create a new type using struct

Function: combine several variables into a structure.

struct {bit[7:0] r,g,b} pixel;
// The above statement just creates a pixel variable directly. If you want to share it in the port and program, you must create a new type.
typedef stuct {bit[7:0] r,g,b} pixel_s;	// Use the suffix "_s" in struct to represent a custom type.

2.10.1 initialize the structure

Assign multiple values to a structure in a declaration or procedure assignment statement.

initial begin
	typedef struct{
				int a; 
				byte b;
				int d;
				}	my_struct_s;
	my_struct_s st = '{32'haaaa_aaaad,
				 8'hbb,
				 16'hcccc,
				 32'hdddd_dddd
				};
	$display("str = %x %x %x %x",st.a,st.b,st.c,st.d);	// The structure variable calls the data in it
end

2.10.3 consortium union

Compared with the structure, the union section saves bytes, but a more complex data structure must be created and maintained.

2.10.4 consolidation structure

typedef struct packed {bit[7:0] r,g,b;} pixel_p_s;
pixel_p_s my_pixel;
  • If the structure is operated frequently, for example, the entire structure needs to be copied frequently, the efficiency of using the merged structure will be higher.
  • However, if the operation is often directed at individual members within the structure rather than the whole, the structure should not be merged.

2.11 type conversion

The variety of data types in SV means that they need to be converted before them.
If the bit distribution of the source variable and the target variable are exactly the same, such as integer and enumeration types, they can be assigned to each other directly.
If the bit distribution is different, such as byte array and word array, you need to rearrange the bit distribution using the stream operator

2.11.1 static conversion

The static conversion operation does not check the converted value.
When converting, specify the target type and put single quotation marks before the expression to be converted.

int i;
real r;

i =int '(10-0.1);	// Conversion is not mandatory
r = real(42);	// Conversion is not mandatory

2.11.2 dynamic conversion

The dynamic conversion function $cast allows you to check for out of bounds values.

2.1.3 flow operator

The stream operators < < and > > are used to the right of the assignment expression, followed by an expression, structure or array.
The stream operator is used to package the subsequent data into a bitstream. Operator > > turns data from left to right into a stream, while < < turns data from right to left into a stream.

initial begin
	int h;
	bit[7:0]b,g[4], j[4] = '{8'ha,8'hb,8'hc,'8hd};
	bit[7:0]q,r,s,t;
	
	h={>>{j}};	// 0a0b0c0d- pack arrays into integers
	h={<<{j}};	// b030d050 bit reverse order
	h={<<byte{j}};	// 0d0c0b0a byte flashback
	g={<<byte {j}};	// 0d,0c,0b,9a split into arrays
	b={<<{8'b0011_0101}};	// 1010_ 1100 bit flashback
	b={<<4{8'b0011_0101}};	// 0101_ 0011 half byte flashback
	{>>{q,r,s,t}} = j ;	// Spread j into four byte variables
	h={>>{t,s,r,q}};	// Concentrate bytes on hli

end

Many connectors {} can be used to do the same, but the flow operator is simpler and easier to read
Example: use the flow operator to convert the queue

initial begin
	bit[15:0] wg[$]= {16'h1234,16'h5678};
	bit[7:0] bg[$];
	
	// Convert a word array to a byte array
	bq={>>{wg}};	// 12 34 56 78
	
	// Convert byte array to word array
	bq = {8'h98,8'h76,8'h54,8'h32};
	wq={>>{bq}};	// 98 76 54 32

end

**Subscript [256] in array declaration is equivalent to [0:255] instead of [255:0]**
Stream operations can be used to package or split structures (such as ATM cells) into byte arrays.
Example: use the stream operator to convert a structure into a dynamic byte array, and then the byte array is converted into a structure in turn.

initial begin
	typedef struct{ int a;
				   byte b;
				  shortint c;
				  int d;
				} my_struct_s;

	my_struct_s st = '{32'haaaa_aaaa,
					8'hbb,
					16'hcccc,
					32'hdddd_dddd};
	
	byte b[];
	// Convert structure to byte array
	b={>>{st}};	//{aa aa aa aa bb cc cc dd dd dd dd};
	// Convert byte array to structure
	b='{8'h11,8'h22,8'h33,8'h44,8'h55,8'h66,8'h77,8'h88,8'h99,8'haa,8'hbb};
	st = {>>{b}};	// st=11223344,55,6677,8899aabb
end

2.12 enumeration types

Use a text macro before enumerating types. Macros are too scoped and visible to the debugger.

  • Enumeration creates a type that is limited to a collection of specific names, such as opcodes in instructions or state names in state machines.
  • Another way to define constants is to use parameters. However, parameters need to define each value separately, and enumeration types can automatically assign different values to each name in the list.
    The simplest enumeration type declaration: a list of constant names and one or more variables
enum {RED,BLUE,GREEN} color;

// Enumeration type
// Create a data type representing 0,1,2
typedef enum{INIT,DECODE,IDLE} fsmstate_e;	
fsmstate_e pstate,nstate;	// Declare custom type variables

initial begin
	case(paste)
		IDLE: nstate =INIT;	// Data assignment
		INIT: nstate = DECODE;
		default: nstate =IDLE;
	endcase
	
	$display("Next state is %s",
			nstate.name();	// Displays the symbol name of the status
			)
end

**The suffix "_e" indicates the enumeration type

2.12.1 defining enumeration values

The enumeration value defaults to an integer incremented from 0.

typedef enum{INIT,DECODE=2,IDLE} fsmtype_e;	

2.12.2 subroutines of enumeration type

SV traverses functions of enumeration types:

  • first() ;last(); next(); next(N); prev(); prev(N);
    Use the do... while loop to iterate through all values.
// Traverse all enumeration members
typedef enum{RED, BLUE, GREEN} color_e;
color_e color;
color =color.first();

do
	begin
		$display("color =%0d/%s", color,color.name);
		color =color.next();
	end
while(color!=color.first());

2.12.3 conversion of enumeration type

The default type of enumeration type is dual state int. SV does not allow non display type conversion.

typedef enum{RED, BLUE,GREEN} COLOR_E;
COLOR_E color,c2;
int c;

initial begin
	color =BLUE;
	c= color;
	c++;
	if(! $cast(color,c))
		$display("Cast failed for c=%0d",c);
	$display("Color is %0d /%s",color,color.name);
	c++
	c2=COLOR_E'(c);	/
	$display("c2 is %0d /%s",c2,c2.name);
end

2.13 constants – const

2.14 string

The string type in SV can be used to store variable length strings.
Example: string method

string s;

initial begin
	s="IEEE";
	$display(s.getc(0));
	$display(s.tolower());
	
	s.putc(s.len()-1,"-");
	s={s,"P1800"};
	
	$display(s.substr(2,5));

	//  Create a temporary string,
	my_log($psprintf("%s %5d",s,42));
	
end

task my_log(string message);
	// Print the information into the log
	$display("@%0t: %s",$time,message);
endtask

2.15 expression bit width

2.16 summary

SV provides many new data types and structures, which makes it possible to write test platforms on OOP at a higher level of abstraction.

  • Queues are ideal for creating scoreboards, adding or deleting data frequently
  • Dynamic arrays allow you to specify the array width when the program is running
  • Associative arrays are used for sparse storage
  • Enumeration types create a list of constants, making the code easy to read and write.

Topics: systemverilog