IEEE Standard for SystemVerilog—Chapter 25.7 Tasks and functions in interfaces

news/2024/5/19 17:25:51 标签: systemverilog

        子例程(任务和函数)可以在接口中定义,也可以在连接的一个或多个模块中定义。这允许更抽象的建模级别。例如,“读”和“写”可以定义为任务,而不需要引用任何连线,主模块只能调用这些任务。在modport中,这些任务被声明为导入任务( import tasks)。
        函数原型指定参数的类型和方向,以及在其他地方定义的函数的返回值。类似地,任务原型指定了在其他地方定义的任务的参数的类型和方向。在modport中,导入和导出构造可以使用子例程原型,也可以只使用标识符。唯一的例外是当使用modport从另一个模块导入子例程时,以及当使用默认参数值或按名称绑定参数时,在这种情况下,应使用完整的原型。
        原型中参数的数量和类型应与子程序声明中的参数类型相匹配。6.22.1中介绍了类型匹配的规则。如果子程序调用中需要默认参数值,则应在原型中指定。如果参数在原型和声明中都指定了默认值,则指定的值不必相同,但使用的默认值应为原型中指定的值。原型中的正式参数名称应是可选的,除非使用默认参数值或按名称绑定的参数,或者声明了额外的未封装维度。原型中的形式参数名称应与声明中的形式变量名称相同
        如果一个模块连接到包含导出子例程的modport,而该模块没有定义该子例程,则会发生elaboration错误。类似地,如果modport包含导出的子例程原型,而模块中定义的子例程与该原型不完全匹配,则会发生elaboration错误。
        如果在模块中使用层次名称定义子例程,则它们也应在接口中声明为extern或在modport中声明为export
        任务(而非函数)可以在实例化两次的模块中定义,例如,由同一CPU驱动的两个存储器。接口中的extern forkjoin声明允许这样的多个任务定义。

25.7.1 Example of using tasks in interface


interface simple_bus (input logic clk); // Define the interface
	logic req, gnt;
	logic [7:0] addr, data;
	logic [1:0] mode;
	logic start, rdy;
	
task masterRead(input logic [7:0] raddr); // masterRead method
	// ...
endtask: masterRead

task slaveRead; // slaveRead method
	// ...
endtask: slaveRead

endinterface: simple_bus


module memMod(interface a); // Uses any interface
	logic avail;
	always @(posedge a.clk) // the clk signal from the interface
		a.gnt <= a.req & avail // the gnt and req signals in the interface
	always @(a.start)
		a.slaveRead;
endmodule

module cpuMod(interface b);
	enum {read, write} instr;
	logic [7:0] raddr;
	always @(posedge b.clk)
		if (instr == read)
			b.masterRead(raddr); // call the Interface method
			...
endmodule

module top;
	logic clk = 0;
	simple_bus sb_intf(clk); // Instantiate the interface
	memMod mem(sb_intf);
	cpuMod cpu(sb_intf);
endmodule

25.7.2 Example of using tasks in modports

        这个接口示例展示了如何在完整的读/写接口中使用modports来控制信号方向和任务访问。

interface simple_bus (input logic clk); // Define the interface
	logic req, gnt;
	logic [7:0] addr, data;
	logic [1:0] mode;
	logic start, rdy;
	
	
modport slave (input req, addr, mode, start, clk,
	output gnt, rdy,
	ref data,
	import slaveRead,
	slaveWrite);
	
	
	// import into module that uses the modport
modport master(input gnt, rdy, clk,
	output req, addr, mode, start,
	ref data,
	import masterRead,
	masterWrite);
	
	
 // import into module that uses the modport
task masterRead(input logic [7:0] raddr); // masterRead method
	// ...
endtask

task slaveRead; // slaveRead method
	// ...
endtask

task masterWrite(input logic [7:0] waddr);
	//...
endtask

task slaveWrite;
	//...
endtask

endinterface: simple_bus


module memMod(interface a); // Uses just the interface
	logic avail;
always @(posedge a.clk) // the clk signal from the interface
	a.gnt <= a.req & avail; // the gnt and req signals in the interface
	
always @(a.start)
	if (a.mode[0] == 1'b0)
		a.slaveRead;
	else
		a.slaveWrite;
endmodule


module cpuMod(interface b);
	enum {read, write} instr;
	logic [7:0] raddr = $random();
always @(posedge b.clk)
	if (instr == read)
		b.masterRead(raddr); // call the Interface method
			// ...
	else
		b.masterWrite(raddr);
endmodule

module omniMod( interface b);
	//...
endmodule: omniMod

module top;
	logic clk = 0;
	simple_bus sb_intf(clk); // Instantiate the interface
	memMod mem(sb_intf.slave); // only has access to the slave tasks
	cpuMod cpu(sb_intf.master); // only has access to the master tasks
	omniMod omni(sb_intf); // has access to all master and slave tasks
endmodule

25.7.3 Example of exporting tasks and functions

        这个接口示例展示了如何在一个模块中定义任务,并在另一个模块调用它们,使用modports来控制任务访问。


interface simple_bus (input logic clk); // Define the interface
	logic req, gnt;
	logic [7:0] addr, data;
	logic [1:0] mode;
	logic start, rdy;

	modport slave( input req, addr, mode, start, clk,
		output gnt, rdy,
		ref data,
		export Read,
			Write);
 
 // export from module that uses the modport
	modport master(input gnt, rdy, clk,
		output req, addr, mode, start,
		ref data,
	import task Read(input logic [7:0] raddr),
	
	
task Write(input logic [7:0] waddr));
	// import requires the full task prototype
endinterface: simple_bus


module memMod(interface a); // Uses just the interface keyword
	logic avail;
	
	task a.Read; // Read method
		avail = 0;
		...
		avail = 1;
	endtask
	
	task a.Write;
		avail = 0;
		...
		avail = 1;
		endtask
endmodule

module cpuMod(interface b);
	enum {read, write} instr;
	logic [7:0] raddr;
	always @(posedge b.clk)
		if (instr == read)
			b.Read(raddr); // call the slave method via the interface
			...
		else
		b.Write(raddr);
	endmodule
	
module top;
	logic clk = 0;
	simple_bus sb_intf(clk); // Instantiate the interface
	memMod mem(sb_intf.slave); // exports the Read and Write tasks
	cpuMod cpu(sb_intf.master); // imports the Read and Write tasks
endmodule

25.7.4 Example of multiple task exports

        多个模块导出(export)相同的任务名称通常是错误的。然而,相同modport类型的几个实例可以连接到一个接口,例如前面示例中的内存模块。为了让它们仍然可以导出它们的读写任务,这些任务应该在接口中使用extern forkjoin关键字声明。对extern forkjoin任务countslaves()的调用;在以下示例中,行为如下:

fork
    top.mem1.a.countslaves;
    top.mem2.a.countslaves;
join

        对于读取任务,只有一个模块应该主动响应任务调用,例如,包含适当地址的模块。其他模块中的任务应返回而不产生任何效果。只有这样,活动任务才能写入结果变量。与任务不同,不允许多次导出函数,因为它们总是写入结果
禁用对外部forkjoin任务的影响如下:
        --如果通过接口实例引用任务,则应禁用所有任务调用
        --如果任务是通过模块实例引用的,则只应禁用对该模块实例的任务调用
        --如果一个接口包含一个外部forkjoin任务,并且没有连接到该接口的模块定义该任务,那么对该任务的任何调用都将报告运行时错误,并立即返回而不产生任何影响。这个接口示例展示了如何在多个模块中定义任务,并使用extern forkjoin在另一个模块中调用它们。多任务导出机制还可以用于统计连接到每个接口实例的特定modport的实例。

interface simple_bus (input logic clk); // Define the interface
	logic req, gnt;
	logic [7:0] addr, data;
	logic [1:0] mode;
	logic start, rdy;
	int slaves = 0;
	
	// tasks executed concurrently as a fork-join block
	extern forkjoin task countSlaves();
	extern forkjoin task Read (input logic [7:0] raddr);
	extern forkjoin task Write (input logic [7:0] waddr);
	
modport slave (input req,addr, mode, start, clk,
	output gnt, rdy,
	ref data, slaves,
	export Read, Write, countSlaves);
	// export from module that uses the modport
	
modport master ( input gnt, rdy, clk,
	output req, addr, mode, start,
	ref data,
	import task Read(input logic [7:0] raddr),
	task Write(input logic [7:0] waddr));
	// import requires the full task prototype
	
	initial begin
		slaves = 0;
		countSlaves;
		$display ("number of slaves = %d", slaves);
		end
endinterface: simple_bus

module memMod #(parameter int minaddr=0, maxaddr=0;) (interface a);
	logic avail = 1;
	logic [7:0] mem[255:0];
	task a.countSlaves();
		a.slaves++;
	endtask

	task a.Read(input logic [7:0] raddr); // Read method
		if (raddr >= minaddr && raddr <= maxaddr) begin
			avail = 0;
			#10 a.data = mem[raddr];
			avail = 1;
		end
	endtask
	
task a.Write(input logic [7:0] waddr); // Write method
	if (waddr >= minaddr && waddr <= maxaddr) begin
		avail = 0;
		#10 mem[waddr] = a.data;
		avail = 1;
	end
	endtask
endmodule

module cpuMod(interface b);
	typedef enum {read, write} instr;
	instr inst;
	logic [7:0] raddr;
	integer seed;
	always @(posedge b.clk) begin
			inst = instr'($dist_uniform(seed, 0, 1));
			raddr = $dist_uniform(seed, 0, 3);
		if (inst == read) begin
		$display("%t begin read %h @ %h", $time, b.data, raddr);
		callr:b.Read(raddr);
		$display("%t end read %h @ %h", $time, b.data, raddr);
end

else begin
	$display("%t begin write %h @ %h", $time, b.data, raddr);
	b.data = raddr;
	callw:b.Write(raddr);
	$display("%t end write %h @ %h", $time, b.data, raddr);
end
end
endmodule

module top;
	logic clk = 0;
	function void interrupt();
		disable mem1.a.Read; // task via module instance
		disable sb_intf.Write; // task via interface instance
		if (mem1.avail == 0) $display ("mem1 was interrupted");
		if (mem2.avail == 0) $display ("mem2 was interrupted");
	endfunction

always #5 clk++;
	initial begin
		#28 interrupt();
		#10 interrupt();
		#100 $finish;
	end
	
	simple_bus sb_intf(clk);
	memMod #(0, 127) mem1(sb_intf.slave);
	memMod #(128, 255) mem2(sb_intf.slave);
	cpuMod cpu(sb_intf.master);
endmodule

25.8 Parameterized interfaces

        接口定义可以以与模块定义相同的方式利用参数和参数重新定义。以下示例显示如何在接口定义中使用参数。

interface simple_bus #(AWIDTH = 8, DWIDTH = 8)
	(input logic clk); // Define the interface
	logic req, gnt;
	logic [AWIDTH-1:0] addr;
	logic [DWIDTH-1:0] data;
	logic [1:0] mode;
	logic start, rdy;
	modport slave( input req, addr, mode, start, clk,
		output gnt, rdy,
		ref data,
		import task slaveRead,
	task slaveWrite);
	
	// import into module that uses the modport
	modport master(input gnt, rdy, clk,
		output req, addr, mode, start,
		ref data,
		import task masterRead(input logic [AWIDTH-1:0] raddr),
		task masterWrite(input logic [AWIDTH-1:0] waddr));

// import requires the full task prototype
task masterRead(input logic [AWIDTH-1:0] raddr); // masterRead method
	...
endtask

task slaveRead; // slaveRead method
	...
endtask

task masterWrite(input logic [AWIDTH-1:0] waddr);
	...
endtask

task slaveWrite;
	...
endtask

endinterface: simple_bus


module memMod(interface a); // Uses just the interface keyword
	logic avail;
	always @(posedge a.clk) // the clk signal from the interface
		a.gnt <= a.req & avail; //the gnt and req signals in the interface
	always @(a.start)
		if (a.mode[0] == 1'b0)
			a.slaveRead;
		else
			a.slaveWrite;
endmodule

module cpuMod(interface b);
	enum {read, write} instr;
	logic [7:0] raddr;
	always @(posedge b.clk)
		if (instr == read)
			b.masterRead(raddr); // call the Interface method
			// ...
		else
			b.masterWrite(raddr);
endmodule

module top;
	logic clk = 0;
	simple_bus sb_intf(clk); // Instantiate default interface
	simple_bus #(.DWIDTH(16)) wide_intf(clk); // Interface with 16-bit data
	initial repeat(10) #10 clk++;
		memMod mem(sb_intf.slave); // only has access to the slaveRead task
		cpuMod cpu(sb_intf.master); // only has access to the masterRead task
		memMod memW(wide_intf.slave); // 16-bit wide memory
		cpuMod cpuW(wide_intf.master); // 16-bit wide cpu
endmodule





 


http://www.niftyadmin.cn/n/5133451.html

相关文章

队列概念|循环队列的实现

前言 今天我们将学习循环队列实现&#xff0c;我们首先介绍队列的概念和结构&#xff0c;之后一步步讲解循环队列由来与实现。 一、队列的概念与结构 1、队列的概念 队列&#xff1a; 只允许在一端进行插入数据操作&#xff0c;在另一端进行删除数据操作的特殊线性表。队列是…

C#__简单了解XML文档

/* XML(可扩展标记语言)&#xff1a;用于传输和存储数据 XML文档&#xff1a;树结构&#xff1b;包含根元素 XML元素&#xff1a;从开始标签到结束标签的部分 XML语法规则&#xff1a; 1、所有XML元素都必须有结束标签 …

centos7 部署 Flink

1. 准备 安装的前提是虚拟机里已安装了jdk 去官网下载 Flink 所有版本下载地址&#xff1a;https://archive.apache.org/dist/flink/ 找到下图的安装包&#xff0c;下载即可 下载完后&#xff0c;将其上传至虚拟机的某个地方&#xff0c;本人将其放在 /home/flink/ 下 解压…

微信小程序vue+uniapp旅游景点门票预订系统 名胜风景推荐系统

与此同时越来越多的旅游公司建立了自己的基于微信小程序的名胜风景推荐平台&#xff0c;管理员通过网站可以添加用户、景点分类、景点信息、在线预订、最新推荐&#xff0c;用户可以对景点信息进行在线预订&#xff0c;以及开展电子商务等。互联网的世界里蕴藏无限生机&#xf…

TensorRT量化实战课YOLOv7量化:YOLOv7-PTQ量化(一)

目录 前言1. YOLOv7-PTQ量化流程2. 准备工作3. 插入QDQ节点3.1 自动插入QDQ节点3.2 手动插入QDQ节点 前言 手写 AI 推出的全新 TensorRT 模型量化实战课程&#xff0c;链接。记录下个人学习笔记&#xff0c;仅供自己参考。 该实战课程主要基于手写 AI 的 Latte 老师所出的 Tens…

业务设计——用户敏感信息展示脱敏及其反脱敏

业务需求 将用户敏感信息脱敏展示到前端是出于保护用户隐私和信息安全的考虑。 敏感信息包括但不限于手机号码、身份证号、银行卡号等&#xff0c;这些信息泄露可能导致用户个人信息的滥用、身份盗用等严重问题。脱敏是一种常用的保护用户隐私的方式&#xff0c;它的目的是减少…

GAMP源码阅读(中)伪距单点定位 SPP

原始 Markdown文档、Visio流程图、XMind思维导图见&#xff1a;https://github.com/LiZhengXiao99/Navigation-Learning 文章目录 一、SPP 解算1、spp()&#xff1a;单点定位主入口函数2、estpos()3、estpose_()4、valsol()&#xff1a;GDOP和卡方检验结果有效性 二、卫星位置钟…

FL Studio21.2.0.3421最新汉化破解版中文解锁下载完整版本

音乐在人们心中的地位日益增高&#xff0c;近几年音乐选秀的节目更是层出不穷&#xff0c;喜爱音乐&#xff0c;创作音乐的朋友们也是越来越多&#xff0c;音乐的类型有很多&#xff0c;好比古典&#xff0c;流行&#xff0c;摇滚等等。对新手友好程度基本上在首位&#xff0c;…