SystemVerilog Testbench Lab4: oop encapsulatio

OOP encapsulation意为面向对象封装。Lab4做的事情就是将packet信息——sa、da和payload封装成一个Packet类,在generator中创建随机的Packet对象。

Packet class

在我看到的很多sv文件中,都会使用宏定义来防止多次编译。

`ifndef INC_PACKET_SV
`define INC_PACKET_SV
class Packet;
	rand bit[3:0] sa, da;
	rand logic[7:0] payload[$];
	string name;
	// property constraints
	constraint Limit{sa inside {[0:15]};
					 da inside {[0:15]};
					 payload.size() inside {[2:4]};
	}
	// class method prototypes
	extern function new(string name="Packet");
	extern function bit compare(Packet pkt2cmp, ref string message);
	extern function void display(string prefix="NOTE");
endclass: Packet
`endif
  • rand修饰符:修饰的变量会在限定范围内随机取一个值,且每个值被取到的概率是一致的。比如sa的取值是0到15之间的一个数,每个数被取到的概率都是1/16。
    • 只要类的数据类型是rand或randc(周期性随机),且一旦这个类的实例化对象调用了randomzie()方法,rand/randc类型的数据将会被随机化。randomize()的返回值是1或者0,分别表示随机成功或者失败。
    • constraint语句块对随机数据进行约束,随机表达式(>、=、<等操作符,一个表达式只能出现一个操作符!)、inside操作符、dist操作符、条件表达式(if-else语句)等。参考link
  • extern关键字:在类内带extern关键字进行声明,类外定义时用“::”需指明类作用域。
  • name是每个Packet类的ID,用于区分不同的Packet对象,对debug有很大帮助。

Class method

类外定义3个method,分别用于对象初始化、对象比较和结果打印。

new method
function Packet::new(string name);
	this.name = name;
endfunction: new
  • new()方法用于初始化对象。类的对象在定义时仅为一个Null的句柄,直到用new()初始化后才变为非空。
  • 个人理解:name赋值给this指针,该指针指向的其他属性也将拥有姓名,形象点说就是同一个类对象拥有同一个姓,同一个类对象的不同属性拥有不同的名。this指针限定了类的本地变量参数和方法,用在非静态方法中。
compare method
function Packet::compare(Packet pkt2cmp, ref string message);
	if( !(payload.size() == pkt2cmp.payload.size()) ) begin
		message = "Packet Size Mismatch:\n";
		message = {meaasge, $sformatf("payload.size = %0d, pkt2cmp.payload.size = %0d", payload.size(), pkt2cmp.payload.size())};
		return(0);
	end
	if( payload == pkt2cmp.payload );
	else begin
		message = "Packet Content Mismatch:\n";
		message = {meaasge, $sformatf("Packet Sent: %p\nPacket Recevied: %p", payload, pkt2cmp.payload)}; 
		return(0);
	end
	meassage = "Successfully Compared!";
	return(1);
endfucntion: compare
  • 第一个参数是Packet类的pkt2cmp,即一个创建好的Packet对象。与Lab3的compare()相比,只是在参数列表中加了一个类对象,以及将pkt2cmp_payload替换成对象的属性pkt2cmp.payload
display method
function Packet::display(string prefix);
	$display("[%s]%t %s sa=%0d, da=%0d", prefix, $realtime, name, sa, da);
	foreach(payload[index])
		$display("[%s]%t %s payload[%0d]=%0d", prefix, $realtime, name, index, payload[index]);
endfunction: display
  • display方法用于打印payload情况,包含地址和内容。既可以打印发送端的payload情况,也可以打印接收端的payload情况,取决于是pkt2send还是pkt2cmp调用这个method。

Modify test.sv

global variables
`include Packet.sv
bit   [3:0] sa,da;
logic [7:0] payload[$];			// expected packet data array
logic [7:0] pkt2cmp_payload[$]; // actual packet data array
Packet	 pkt2send = new();		// expected packet object
Packet	 pkt2cmp = new();		// actual packet object
  • 在原有全局变量的基础上增加两个Packet的类对象,并include类文件。如果类定义错误或者找不到该类文件的话,编译时将提示类名无效:XXX is not a valid type
gen task
task gen();
	pkt2send.payload.delete();
	static int pkts_generated = 0;
	pkt2send.name = $sformatf("Packett[%0d]", pkts_generated++);
	if( !pkt2send.randomize() ) begin
		$display("\n%m\n[ERROR]%t Packet Randomization Failed!", $realtime);
		$finish;
	end
	sa = pkt2send.sa;
	da = pkt2send.da;
	payload = pkt2send.payload;
endtask: gen
  • pkt2send对象调用randomize()方法时,sa、da、payload的值会在约束范围内被随机化。
  • pkt2send的property赋值给全局变量sa、da、payload,使得pkt2send的属性在类外也可见。send()任务可以使用全局变量da、payload来发送数据,本Lab中的send()任务与前一个Lab完全相同。
recv task
task recv();
	static int pkt_cnt = 0;
	get_payload();
	pkt2cmp.da = da;
	pkt2cmp.payload = pkt2cmp_payload;
	pkt2cmp.name = $sformatf("rcvdPkt[%0d]", pkt_cnt++);
endtask: recv
  • get_payload()任务与前一个Lab相同,仅仅是将pkt2cmp_payload作为payload属性赋值给了类对象pkt2cmp
  • 注意:static变量通常在声明时初始化(在最开始的位置),否则编译报错提示:System verilog keyword ‘static’ is not expected to be used in this context
check task
task check();
	string message;
	static int pkts_checked = 0;
	if(!pkt2send.compare(pkt2cmp, message)) begin
		$display("\n%m\n[ERROR]%t Packet[#%0d] %s\n", $realtime, pkts_checked, message);
		pkt2send.display("ERROR");
		pkt2cmp.display("ERROR");
		$finish;
	end
	else 
		$display("[NOTE]%t Packet[#%0d] %s\n", $realtime, pkts_checked, message);
endtask: check
  • 调用compare()函数时,由于ref关键字使得传递的实际是message的地址,在函调用结束后message中的字符内容的改变不会被丢弃。
  • 疑问:若是pkt2cmp调用display方法,其sa属性在test program中并未被赋值,那将会打印出什么?

Conclusion

面向对象封装的中涉及到很多术语,在此先对已经出现的做一个小结,【】中给出已经出现的例子。

  • class——类:包含变量、函数、任务的基本构建块。【Packet】
  • object——对象:类的一个实例。【pkt2send、pkt2cmp】
  • handle——句柄:即指向对象的指针。【pkt2send、pkt2cmp】
  • method——方法:类中操作变量的程序块。【compare、display】
  • prototype——原型:程序定义,包含程序名、参数列表、返回类型。【extern function xxx】

更多归纳参考link

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值