Task - Verilog's task

Task - Verilog's task

Previous articles recorded the use of functions such as function function: Function -- Verilog function . This time, record the function of using the task task task.

a thing for it

IIC save module needs to be used in the design, so there needs to be a corresponding master module in testbench, and a model that can read and write.

If Verilog is also used for comprehensive writing, it is somewhat trivial and requires strict control logic. Therefore, it is hoped that a function can actually carry out the read-write control timing operation of IIC.

The previous function only had function function, and the operation of the function was combinatorial logic, which could not meet the requirements of the temporal logic required this time, so the task function was selected.

Talk is cheap

The files of the entire IIC master model are as follows:

/**
 * Filename		:		iic_master_model.v
 * Date			:		Friday, May 21, 2021 4:50 PM
 *
 * Version		:		V 0.1
 * Author		:		ljacki@163.com
 * Modification history
 *				:		Friday, May 21, 2021 4:50 PM Create the demo
 *				:		Friday, May 28, 2021 2:37 PM Add the task of write pkg.
 */
`timescale 1ns / 100ps
`define		DEBUG_INFO	1'b0
`define		DELAY		2
module iic_master_model (
	// system
	input						clk,
	input						rst_n,
	input 						req,

	input 						rd_valid_i,
	input [7:0]					rd_data_i,

	output reg					start,
	output reg					stop,
	output reg [7:0]			dvice_id,
	output reg 					wr_en_o,
	output reg [7:0]			wr_data_o,

	output reg 					rd_en_o,
	output reg [7:0]			rd_addr_o

	);

parameter DEVICE_ID	= 7'h70;
parameter PKG_LEN	= 8'h10;

//  Declarations
reg [7:0] dout;

// initial

initial begin
	start = 1'b0;
	stop = 1'b0;		// The stop signal needs to be reset, otherwise req in the master will not assert
	dvice_id = 8'b0;
	wr_en_o = 1'b0;
	wr_data_o = 8'b0;
	rd_en_o = 1'b0;
	rd_addr_o = 8'h0;
	dout = 8'h0;
	if ( `DEBUG_INFO ) begin
		$display("\nINFO: IIC MASTER MODEL INSTANTIATED (%m)");
	end
end

task m_start;

	input wr_rd;	//1'b0: write, 1'b1:read;

	begin
		// @(posedge clk);
		#`DELAY
		start = 1'b1;
		dvice_id = {DEVICE_ID, wr_rd};

		@(posedge clk);
		#`DELAY
		start = 1'b0;
		dvice_id = 8'h0;

		// if ( wr_rd == 1'b0 ) begin
		// 	$display("status: %t master START WRITE,\tDEVICE ID : %X", $time, DEVICE_ID);
		// end else begin
		// 	$display("status: %t master START READ, \tDEVICE ID : %X", $time, DEVICE_ID);
		// end
	end
endtask


task m_wr_data;
	input [7:0] wr_addr;
	input [7:0] wr_data;
	input stop_flag;

	begin
		while(~req) @(posedge clk);
		#`DELAY
		wr_en_o = 1'b1;
		wr_data_o = wr_addr;

		@(posedge clk);
		#`DELAY
		wr_en_o = 1'b0;
		wr_data_o = 8'b0;

		if ( stop_flag) begin
			while(~req) @(posedge clk);
			#`DELAY
			stop = 1'b1;
			wr_en_o = 1'b1;
			wr_data_o = wr_data;

			@(posedge clk);
			#`DELAY
			stop = 1'b0;
			wr_en_o = 1'b0;
			wr_data_o = 8'b0;
		end else begin
			while(~req) @(posedge clk);
			#`DELAY
			stop = 1'b0;
			wr_en_o = 1'b1;
			wr_data_o = wr_data;

			@(posedge clk);
			#`DELAY
			stop = 1'b0;
			wr_en_o = 1'b0;
			wr_data_o = 8'b0;
		end

		if ( `DEBUG_INFO) begin
			$display("status: %t master WRITE ADDR:%X,\tDATA:%X\n", $time, wr_addr, wr_data);
		end
	end
endtask

task m_write;

	input [7:0] waddr;
	input [7:0] wdata;

	begin

		m_start(1'b0);

		m_wr_data(waddr, wdata, 1'b1);

		repeat(50) @(posedge clk);

		if ( `DEBUG_INFO) begin
			$display("status: %t master WRITE ADDR:%X,\tDATA:%X\n", $time, waddr, wdata);
		end
	end

endtask


task m_write_pkg;

	// input [7:0] len;
	input [8*PKG_LEN-1:0] addr;
	input [8*PKG_LEN-1:0] data;

	begin

		m_start(1'b0);

		m_wr_data(addr[(PKG_LEN-0)*8-1:(PKG_LEN-1)*8], data[(PKG_LEN-0)*8-1:(PKG_LEN-1)*8], 1'b0);
		m_wr_data(addr[(PKG_LEN-1)*8-1:(PKG_LEN-2)*8], data[(PKG_LEN-1)*8-1:(PKG_LEN-2)*8], 1'b0);
		m_wr_data(addr[(PKG_LEN-2)*8-1:(PKG_LEN-3)*8], data[(PKG_LEN-2)*8-1:(PKG_LEN-3)*8], 1'b0);
		m_wr_data(addr[(PKG_LEN-3)*8-1:(PKG_LEN-4)*8], data[(PKG_LEN-3)*8-1:(PKG_LEN-4)*8], 1'b1);

		repeat(50) @(posedge clk);
	end
endtask


task m_read;

	input [7:0] rd_addr;
	output [7:0] rd_dout;

	begin

		@(posedge clk);
		#`DELAY
		m_start(1'b0);

		while(~req) @(posedge clk);
		#`DELAY
		rd_en_o = 1'b1;
		rd_addr_o = rd_addr;

		@(posedge clk);
		#`DELAY
		rd_en_o = 1'b0;
		rd_addr_o = 8'h0;

		while(~req) @(posedge clk);
		#`DELAY
		m_start(1'b1);

		while(~rd_valid_i) @(posedge clk);
		#`DELAY
		rd_dout = rd_data_i;

		repeat(50) @(posedge clk);

		if ( `DEBUG_INFO ) begin
			$display("status: %t master READ ADDR:%X,\tDATA:%X\n", $time, rd_addr, rd_dout);
		end
	end
endtask


task m_cmp;

	input [7:0] addr;
	input [7:0] dexp;	// the expected data

	begin
		m_read(addr, dout);

		if ( dexp != dout ) begin
			$display("\t\t\tData compare error. Received %h, expected %h at time %t", dout, dexp, $time);
		end
	end

endtask

endmodule // the end of iic_master_model

Statement: the above timing needs to be used with iic master; According to the article, it is only used to explain the use of task tasks.

task introduction

A task is a program encapsulated between task and endtask.

It is executed by calling, and only when called. If a task is defined, but it is not called in the whole process, the task will not be executed.

Calling a task may require it to process some data and return the operation results, so the task in Verilog has input and output.

definition

task is defined as follows:

task<Task name>;              // <=  task task_id;           
  <Port and data type declaration statement> // <=    [declaration]       
  <Statement 1>                  // <=    procedural_statement
  <Statement 2>                  // <=    procedural_statement
   .....                   // <=
  <sentence n>                  // <=    procedural_statement
endtask                    // <=  endtask 						// <=  endtask

Among them, the keyword task and endtask mark the content between them as a task definition;

  • Task marks the beginning of a task definition structure;
  • task_id is the task name;
  • Optional declaration is a port declaration statement and a variable declaration statement. The task receives the input value and returns the output value through the port declared here;
  • procedural_statement is a process statement used to complete the task operation. If there is more than one process statement, it should be placed in the statement block;
  • endtask defines the structure end flag for the task.

task can start other tasks, and other tasks can start other tasks. There is no limit to the tasks that can be started. Control can return only after all tasks are completed. task can have no or multiple input-output type variables.

The Works of Liezi

The columns of a task are:

task find_max;      //The task definition structure starts with find_max
 input  [15:0] x,y; //Enter port description
 output [15:0] tmp; //Output port description

 if(x>y)            //Give the description statement of the task definition
   tmp = x;
 else
   tmp = y;

endtask

matters needing attention

Precautions for writing task are as follows:

  • The port name cannot be listed in the task statement in the first line;
  • The number of input, output and two-way ports of the task is not limited, or even there can be no input, output and two-way ports;
  • In the task, you can call other tasks or functions, or call yourself;
  • The disable abort statement can appear in the task definition to interrupt the executing task, but it cannot be integrated. When the task is interrupted, the program flow will return to the place where the task is called and continue to execute downward.

Call of task

The syntax of the task call statement is as follows:

task_id(Port 1, Port 2, port n);

Among them, task_id is the name of the task to be called. Port 1, port 2 and port n are parameter lists. The parameter list gives the data of the incoming task (entering the input of the task) and the variables that receive the returned results (receiving the returned results from the output of the task).

When calling task, you should pay attention to the following points:

  • Task call statements can only appear in procedure blocks;
  • The processing method of task call statement is consistent with that of an ordinary behavior description statement;
  • When the input and output users are called, the task call statement must contain a list of port names, and the order and type of signal ports must be consistent with the order and type in the task definition structure;
  • The output port of the task must correspond to the data variable of register type.
  • The integrable task can only realize combinatorial logic, that is, the time to call the integrable task is 0. Simulation oriented tasks can have timing control, such as multiple clock cycles or delay, and the call time of a task oriented to Fanzhen is not 0.

The above IIC master model can add test excitation to IIC bus and read bus data through simple read-write tasks:

	/**
	 * Read all the registers
	 */
	for (cnt = 8'h0; cnt <= 8'h57; cnt = cnt + 1'b1) begin
		m0.m_read(cnt, rd_dout);
	end

	/**
	 * Write all the registers once
	 */
	for (cnt = 8'h0; cnt <= 8'h57; cnt = cnt + 1'b1) begin
		m0.m_write(cnt, cnt);
	end

	/**
	 * Compare register values
	 */
	for (cnt = 8'h0; cnt <= 8'h57; cnt = cnt + 1'b1) begin
		m0.m_cmp(cnt, cnt);
	end

	/**
	 * For continuous writing, the parameter needs to be modified: PKG_LEN;
	 * PKG_LEN: Number of registers written continuously;
	 * addr: Continuous write register address splicing, MSB 8-bit priority write;
	 * data: Continuous write register value splicing, MSB 8-bit priority write;
	 * Need to modify m manually_ write_ The main content of PKG;
	 */
	m0.m_write_pkg( addr, data );

	// Short reset, register value reset;
	// sys_rst_n = 1'b0;
	// #500
	// sys_rst_n = 1'b1;
	// $display("\nstatus: %t reset again", $time);
	//
	// for (cnt = 8'h0; cnt <= 8'h57; cnt = cnt + 1'b1) begin
	// 	m0.m_read(cnt, rd_dout);
	// end

For CPU read-write timing and bus interface timing such as UART/SP/IIC/PC/USB, the early verification method provided some tasks for bus interaction, but now it has a proprietary name: BFM (Bus Function Model).

Differences between tasks and functions

Tasks and functions are two common execution call objects. The difference between them is:

Difference itemMission characteristicsFunction characteristics
1Tasks can have input, output and inout, and the number is unlimitedThe function has only input parameters and at least one input
2Tasks can include timing control (such as delay, etc.)Function cannot contain any delay, simulation time 0
3Tasks can be interrupted with disableFunction does not allow disable, wait statement
4Tasks can pass values through I/O portsThe function name is the name of the output variable and returns the value through the function
5Tasks can call other tasks and functionsFunctions can only call other functions, not tasks
6Tasks can dinginess their own simulation time unitsThe function can only share one simulation time unit with the main module
7The task can support multiple purposes and can calculate multiple result values. The result values can only be output through the called task output port or bus portThe function responds to the value of the input signal by a return value
8A wire type variable cannot be present in a function

Reference articles

On the usage of task in FPGA verilog

Verilog key analysis (3) (task & function) : static task and dynamic task are described in this article.

2021-6-26.

Keywords: Verilog FPGA Task

Added by mwmobley on Sun, 23 Jan 2022 11:24:03 +0200