SV Chapter 3 procedure statements and subroutines

Posted by bitman on Sun, 23 Jan 2022 17:52:16 +0100


In fact, when writing design or verification, the code basically unloads tasks or functions. This chapter mainly introduces the improvement of SV like C language - processing parameter cases.

3.1 procedure statement

  • Loop variables are defined in the for loop, and the scope is limited to the inside of the loop to avoid some code vulnerabilities.
  • Auto increment / decrement
  • An identifier can be used in a begin/fork statement and the same label can be placed in its corresponding end or join statement.
    Example:
initial begin:example
	integer array[10],sum,j;
	// Declare i in a for statement
	for(int i=0;i<10;i++ )
		array[i]=i;
	
	// Add the elements of the array
	sum = array[9];
	j=8;
	do	
		sum+=array[j];	// while Loop 
	while(j--);
	$display("Sum=%4d",sum);	// %4d - specify width
end: example
// continue and break functions can also be added to the loop.

initial begin
	bit[127:0] cmd;
	int file,c;
	
	file = $fopen("commands.txt",'r');
	while(!$feof(file)) begin
		c = $fscanf(file,"%s",cmd);
		case(cmd)
			"": continue;		//Empty line, terminate this cycle
			"done": breakļ¼›// Terminate and jump out of loop
			....
		endcase
	end
	$fclose(file);

end

3.2 tasks, functions and void functions

In Verilog, there is an obvious difference between any and functions. The biggest difference is that the task can consume time, and the function cannot have delay statements such as #100 or blocking statements such as @ (pose clock) and wait(ready), nor can it call the task. The function must have a return value and must be used (basically used in assignment statements).
In SV, if there is a task that does not consume time, it should be defined as void() function, which can be called by functions and tasks at this time.
Example: void function for debugging

function void print_state(...);
	$display("@%0t:state=%s",$time,cur_state.name());
endfunction
// Some emulators allow the return value to be ignored when void is not applicable.

3.3 task and function overview

A slight improvement: subprograms without parameters do not need empty parentheses when they are defined or called.

3.3.1 remove begin... end from the subroutine

It is optional in SV and must be carried for multi line subroutines in Verilog.

// Without begin end
task multiple_lines;
	$display("First line");
	$display("Second line");
	
endtask:multiple_lines

3.4 subroutine parameters

The improvement in SV makes the declaration of parameters more convenient, and extends the transmission mode of parameters.
Verilog directly replicates the passed parameters, and the parameter passing method in SV - ref is reference rather than copy.

// Using ref between multiple threads
task bus_read(input logic[31:0] addr,
			   ref logic [31:0] data);

	// Request bus and drive address
	bus.request =1'b1;
	@(posedge bus.grant) 	bus.addr = addr;
	
	// Waiting for data from memory
	@(posedge bus.enable) 	data = bus.data;

	// Release the bus and wait for permission
	bus.request = 1'b0;
	@(posedge bus.grant);
endtask

logic[31:0] addr,data;
initial 
	fork
		bus_read(addr,data);
		thread2:begin
			@data;	// Triggered when data changes
			$display("Read %h from bus",data);
		end	

	join

3.4.4 default values of parameters

Set a default value for the parameter in SV. If the parameter is not specified during the call, the default value is used.

function void print_checksum(ref bit[31:0] a[],
							input bit[31:0] low=0,
							input int high =-1);
		bit[31:0] checksum =0;
		if(high==-1 || high>=a.size())
			high = a.size()-1;
		for(int i=low;i<high;i++)
			checksum+=a[i];
		$display ("The array checksum is %0d",checksum);
endfunction
// Call using parameter defaults
print_checksum(a);	// Checksum of all elements in a[0:size-1]
print_checksum(a,2,4);	// Checksum of all elements in a[2:4]
print_checksum(a,1);	// Start with 1

print _checksum(a, ,2);	//Checksum of all elements in a[0:2]
print_checksum();	// Compilation error: a has no default value
// Use - 1 (or any other out of bounds value) as your default value to determine whether the specified value is given during the call

3.4.5 parameter transfer by name

In SV language, the parameters of any or function are sometimes called port "port", just like the interface of the module.

// Parameter passing by name
task many(input int a=1,b=2,c=3,d=4);
	$display("%0d %0d %0d %0d",a,b,c,d);
	
endtask

initial begin
	many(6,7,8,9);	//a,b,c,d
	many();	// Use Default 
	many(.c(5));	// Specify only c
	many(,6,.d(8));	// Mixed mode

end

3.4.6 clearly indicate the direction of all parameters

task sticky(ref int array[50],
			input int a,b);	// Clearly specify the direction

3.5 return of subroutine

In Verilog, it is the last statement after executing the subroutine, and the program will return to the code of the subroutine. In addition, the function returns a value assigned to a variable with the same name as the function. Add a return statement to SV. It will return when it encounters a return.

3.5.1 return an array from a function

Only one simple value can be returned in Verilog, such as bit, integer or vector.
In SV, the function returns an array in many ways.

//The first is to define an array type and then use it in the declaration of the function
typedef int fixed_array5[5];	// Define a new array type
fixed_array5 f5;	

function fixed_array5 init(int start)
	foreach(init[i])
		init[i] = i+start;

endfuncton

initial begin
	f5 = init(5);
	foreach(f5[[i]])
		$display("f5[%0d] =%0d", i,f5[i]);
end	

// When creating an array, the array value is assigned, which wastes space
// Second: use reference
function void  init(ref int f[5], input int start);
	foreach(f[i])
		f[i] = i+start;
endfunction

int fa[5];
initial begin
	init(fa,5);
	foreach(fa[i])
		$display("fa[%0d] = %0d",fa[i]);
end
// The third method: encapsulate the array into a class, and then return the handle of the object

3.6 local data storage

Verilog hardware language allocates data statically, especially subroutines and local variables are placed in fixed positions. The C preloading equation is stored based on the stack area.
In the latest version of Verilog, you can specify that tasks, functions and modules use automatic storage - stack area, forcing the emulator to use stack area. In SV, module and program blocks use the keyword automatic to use the stack area.
Example: a task for monitoring when data is written to memory

program aumomatic test;
	task wait_for_mem(input [31:0] addr, expect_data, output success);
		while(bus.addr!=addr)
			@(bus.addr);
			success = (bus.data ==expect_data);
	endtask
.......
endprogram

3.6.2 initialization of variables

Example: after monitoring the bus for five cycles, create a local variable and assign the value of the current address bus to it as the initial value

program automatic initialization;	
	task check_bus;
		repeat(5) @(posedge clock);
		if(bus_cmd ='READ) begin
			//When to local_addr initial value
			logic[7:0] local_addr =addr<<2;	
			$display("Local Addr=%h",local_addr);
		end
	endtask

endprogram

3.7 time value

The new structure in SV helps to indicate the time value in the system

3.7.1 time unit and accuracy

Statement: ` timescale time unit / time precision

3.7.2 time parameters

Delay after formatting with $timeformat() and% t specifier

3.7.3 time and variables

This specific encounter will be more understandable. Now I'm confused.

  • $time: the return value is an integer rounded according to the time precision requirements of the module, without decimal part.
  • The return value of $realtime is a complete real number with a decimal part.

3.8 summary

The programming structure in SV, that is, the new characteristics of any and functions, makes it closer to the characteristics of C + +, which is convenient to write the test platform.
Compared with C + +, SV has its own special structure, timing control, simple thread control and four state logic.

Topics: systemverilog