SV-路科-V0实验:lab4-使用类封装数据包

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


学习目标

1.将数据信息封装进入Packet类中
2.利用随机化(randomization)在packet类中随机产生源地址,目标地址和payload
3.创建两个packet对象(object),一个包用来在DUT输入端输入,另一个包用来和DUT输出的数据相参照
4.将compare()方法嵌入packet类,用来验证DUT工作的正确性

实验结构

提示:以下是本篇文章正文内容,下面内容仅供参考学习

一、任务步骤

任务一:创建一个数据包类(class)文件

1.创建Packet.sv
2.声明class Packet
3.在类class语句的前面和后面使用宏作为标记,防止多次编译
4.声明随机变量sa,da和随机队列payload[$];定义字符串string name用来区分不同的数据包对象
在这里插入图片描述

任务二:定义数据包的属性约束

在属性约束声明之后添加约束块限制sada 在0至15以内,**payload.size()**在2至4之内。
在这里插入图片描述

任务三:定义数据包类方法的雏形

声明:
外部方法new,传递参数string name,初始值为Packet;
外部方法compare,返回值为bit类型,传递参数class类Packet pkt2cmp和ref类型的字符串string msg
外部方法display用来放置打印语句,无返回值,传递参数为字符串string prefix,初始值为Accomplish
在这里插入图片描述

任务四:定义数据包类new()构建函数

对于Packet对象来说,大部分性质将会调用randomize()来进行设置,但是name这一性质需要在new()中初始化。
1.在Class()体的外部,实现new方法。确定通过**:😗*域这一接口,使function映射到Packet类中
2.函数内使用参数传入的字符串name赋值给指向这个类域里面的name
在这里插入图片描述

任务五:定义Packet的方法compare()

为了比较两个数据对象的内容,通常会在数据对象中去建立compare()方法。
1.将test.sv的compare()剪切到Packet.sv中去
2.参照上边把方法指明::域Packet中的compare()
3.修改参数列表需要添加一个参数即类Packet和它的句柄pkt2cmp
4.在compare()方法内部,参照类属性的pkt2cmp.payload来修改pkt2cmp_payload
在这里插入图片描述

任务六:定义数据包的方法display()

为了打印出Packet对象的内容以便调试,display的方法应该被定义在这个Packet类中
1.同上创建display()方法
2.打印内容:当前时间点当前对象的输入输出通道sa和da,传递队列payload内的数据内容
在这里插入图片描述

任务七:修改test.sv来使用Packet类

Packet类现在封装了数据包的信息,在test.sv中我们要做的是随机产生Packet的对象,然后在这些随机对象的基础上通过路由器发送和接受数据包。
1.在程序块内部导入Packet类使用includ语句即可
2.创建和构造两个数据包对象,pkt2send和pkt2cmp。
在这里插入图片描述

任务八:修改gen()任务以产生数据包对象

1.删除gen()内之前的代码
2.声明静态变量static int pkts_generated用来记录产生了多少个数据包对象
3.将pkt2sendname设置为一个唯一的字符串变量(使用一个可变变量pkts_generated作为这个字符串的一部分)
4.随机化数据包对象pkt2send。如果随机化失败,打印错误信息并终止仿真
5.使用随机化pkt2send使对象中的变量sa,da和payload值更新了,因此你需要将它们的值赋值给program域里的sa,da和payload。这样就将类中数据包信息与program联系起来了。这使得pkt2send对象的内容对程序的所有组件都可见。

  • 由原先在gen任务中直接产生数据包,改为在类中产生,然后通过类索引赋值传递给程序块。

在这里插入图片描述

任务九:修改recv()任务

这个任务是用来采样输出端的payload即task get_payload(),然后放入队列pkt2cmp_payload中的。
现在我们将这些步骤放入类Packet pkt2cmp中。这个类的对象会在后面检查和Packet pkt2send的对象的比较结果。

在recv()任务中,调用get_payload()之前需要进行以下操作:
1.创建一个静态int变量pkt_cnt来追踪数据包的数量。应该初始化为0

在调用get_payload()之后应该做一下操作:
1.连接pkt2cmp.da和全局变量da
2.连接pkt2cmp.payloadpkt2cmp_payload
3.和任务八-步骤3一样设置pkt2cmp.name,并将pkt_cnt作为字符串的一部分
在这里插入图片描述

任务十:修改check()任务

在check()任务中,我们将使用类Packet对象内的compare()方法来比较发送和接收的Packet对象内容是否一致。
并且为了方便调试错误,我们应该在数据包对象中使用display()方法。就是我们之前在类Packet定义的外部方法display().
1.将compare()放入类的对象中取代之前的compare。这一步我们之前做过了。
2.比较对象pkt2send和pkt2cmp。
3.当比较出现错误时,调用两个对象中的display()方法并传递相应的字符串,打印错误信息。
4.同样设置静态变量int pkts_checked用来记录检查次数。也可以使用之前定义的计数变量count
在这里插入图片描述

编译仿真:

编译报错

1.未声明约束块名称
在这里插入图片描述
在这里插入图片描述
2.pkt2cmp_payload未在类Packet中声明,即使在程序块中声明静态变量,类中也索引不到它。需要手动索引pkt2cmp对象中的payload
在这里插入图片描述
3.定义的外部方法忘记声明返回值,导致类找不到定义的外部方法
在这里插入图片描述
4.条件编译报错
ifndef 和 endif 要一起使用,如果丢失endif,会报错。
在这里插入图片描述
宏定义#define #ifndef #endif

仿真报错

打错字了。。仿真器没法解析变量
pkt2cmp和pkt_cnt
在这里插入图片描述

二、调试

1.随机化失败

条件给错了,少了一个!
在这里插入图片描述
在这里插入图片描述

2.数据包对象长度比较失败

第一个数据就比较失败了。输出端接收到的数据包有问题,查看波形发现输出端是有波形的。所以问题大概出在了recv()里面。
在这里插入图片描述
在这里插入图片描述
检查recv的代码发现,应该是之前get_payload的值传递给pkt2mp对象的payload,我写反了。pkt2mp对象是空的,pkt2cmp.payload自然是空的,da也反了,应该是全局变量da传递。
在这里插入图片描述
在这里插入图片描述

打印结果

在这里插入图片描述
在这里插入图片描述

波形结果

在这里插入图片描述


总结

`timescale 1ns/100ps  
program automatic test(router_io.TB rtr_io);
	`include "Packet.sv"
	bit [3:0] sa; //source address(input port)
	bit [3:0] da; //destination address (output port)
	logic [7:0] payload[$];
	int run_n_packets;
	logic [7:0] pkt2cmp_payload[$];
	Packet pkt2send = new("send-Packet");
	Packet pkt2cmp = new("recv-Packet");
	
    initial begin
      reset();
			run_n_packets = 5;
      repeat(run_n_packets) begin
      	gen();
      	fork
      		send();
      		recv();
      	join
      	check();
    	end
    	repeat(10) @(rtr_io.cb);
    end
    //signal reset_n draw low,frame_n and valid_n draw high.After 2ns reset_n draw high.
    //AND ues repeat statement to keep 15 cycles.
    task reset();
      rtr_io.reset_n = 1'b0;
      rtr_io.cb.frame_n <= '1;
      rtr_io.cb.valid_n <= '1;
      #2 rtr_io.cb.reset_n <= 1'b1;
      repeat(15) @(rtr_io.cb);
    endtask: reset
    
    task gen();
			static int pkts_generated = 0;
			pkt2send.name = $sformatf("send-Packet[%0d]",pkts_generated++);
			if(!pkt2send.randomize()) begin
				$display("object of handle pkt2send randomize fail");
				$finish;
				end
				sa = pkt2send.sa;
				da = pkt2send.da;
				payload = pkt2send.payload;
  	endtask: gen
  	
  	task send();
  		send_addrs();
  		send_pad();
  		send_payload();
  endtask
  
  	task send_addrs();
  	 
  		rtr_io.cb.frame_n[sa] <= 1'b0; //start to send packets
  		for(int i = 0; i<4; i++) begin
  			rtr_io.cb.din[sa] <= da[i];  //stage1:send address to din 
  		@(rtr_io.cb);
  		end
  endtask: send_addrs
  	
  	
  	task send_pad();
  		
  		rtr_io.cb.din[sa] <= 1'b1;
  		rtr_io.cb.valid_n[sa] <= 1'b1;
  		rtr_io.cb.frame_n[sa] <= 1'b0; //it is not necessary? Yes
  		repeat(5) @(rtr_io.cb);
  endtask: send_pad
  	
  	task send_payload();
  	static int id;
  	foreach(payload[id])
  	begin
  		for(int i = 0 ;i < 8 ;i++)begin
  				rtr_io.cb.din[sa] <= payload[id][i];
  				rtr_io.cb.valid_n[sa] <= 1'b0;
  				rtr_io.cb.frame_n[sa] <= (i == 7 && id == payload.size()-1) ? 1'b1:1'b0;
  				@(rtr_io.cb);
  				
  			end
  		$display("sa = [%0d] da = [%0d] ,send payload[%0d] is %0d ",sa,da,id,payload[id]);
  		end
  	rtr_io.cb.valid_n[sa] <= 1'b1;
  	
  endtask: send_payload
  
  task recv();
  	static int pkt_cnt = 0;
  	get_payload();
  	pkt2cmp.da = da;
  	pkt2cmp.payload = pkt2cmp_payload;
  	pkt2cmp.name = $sformatf("recv-Packet[%0d]",pkt_cnt++);
	endtask: recv
	
	task get_payload();
		logic [7:0] datum;
		
		pkt2cmp_payload.delete();
		fork
			begin		
				fork 
				 @(negedge rtr_io.cb.frameo_n[da]);
				 begin
				 	repeat(1000) @(rtr_io.cb);
			   	$display("\n%m\n[ERROR]%t Frame signal timed out!\n", $realtime);
			   	$finish;
			 	 end
				join_any
				disable fork;
			end
		join
		@(negedge rtr_io.cb.valido_n[da]);
		forever begin
	
			for(int i = 0; i < 8; i++)begin
					if(!rtr_io.cb.valido_n[da])
						datum[i] = rtr_io.cb.dout[da];
					if(rtr_io.cb.frameo_n[da])begin
					if(i==7)begin
						pkt2cmp_payload.push_back(datum);
						return;
					end
					else begin
							$display("%t \n[Error]:payload not a byte ",$realtime);
							$finish;
						end
					end
					@(rtr_io.cb);
				end
			pkt2cmp_payload.push_back(datum);
	end
	endtask: get_payload
	
	task check();
		string msg;
		static int count;
		
		if(!pkt2send.compare(pkt2cmp,msg))begin
		$display("%m\n%t [Error] Packet: #%0d \n %s",$realtime,count,msg);
		pkt2send.display("ERROR");
		pkt2cmp.display("ERROR");
		$finish;
	end
		else	
		$display("%m\n%t [Accomplish] Packet: #%0d \n %s",$realtime,count++,msg);
endtask
endprogram: test

`ifndef INC_PACKET_SV
`define INC_PACKET_SV //Use macros as a guard against multiple compilation before and after the class statements
class Packet;
	rand bit [3:0] sa, da;
	rand logic [7:0] payload[$];
			 string name;  //identify the individual object
	constraint constr {
		sa inside {[0:15]};
		da inside {[0:15]};
		payload.size() inside {[2:4]};
	}

		extern function new(string name = "Packet");
		extern function bit compare(Packet pkt2cmp, ref string msg);
		extern function void display(string prefix = "Note");
	endclass: Packet
	`endif

	function Packet::new(string name);
		this.name = name;

	endfunction: new
	
	function bit Packet::compare(Packet pkt2cmp, ref string msg );
			if(payload.size()!=pkt2cmp.payload.size()) begin
			compare = 0;
			msg = "Payload size mismatch:";
			msg = {msg , $sformatf("Cause of failure : payload.size()=%0d, pkt2cmp_payload.size()=%0d queues size is inconsistent",payload.size(),pkt2cmp.payload.size())};
		end
		else
			if(payload!=pkt2cmp.payload) begin
				compare = 0;
				msg = "Payload content mismatch:";
				msg = {msg ,$sformatf("Cause of failure : payload = %p pkt2cmp_payload = %p  queues data is inconsistent", payload,pkt2cmp.payload)};
			end
				else
				begin
					compare = 1;
					msg = "Two queues data compare succeslly";
				end
	endfunction

	function void Packet::display(string prefix);
 		$display("[%s]%t %s sa = %0d, da = %0d", prefix, $realtime, name, sa, da);
  	foreach(payload[i])
    $display("[%s]%t %s payload[%0d] = %0d", prefix, $realtime, name, i, payload[i]);
	endfunction
	
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值