SystemVerilog Testbench Lab2: sending packets

Lab1介绍了DUT的基本情况,学习了基本的验证流和基础的验证框架。Lab2在此基础上对test program进行功能的拓展,新增发送数据包的任务;其他模块保持不变。

Test Program

test generator

简单来说,这部分的功能就是产生激励,需要明确两点:一是数据输入和输出的端口,二是待传输的数据内容。因而,首先定义如下的全局变量,其次将地址和数据赋给全局变量。

	bit[3:0] sa;	// source port
	bit[3:0] da;	// destination port
	logic[7:0] payload[$];	// packet data array
  • payload是一个队列queue,队列中存储的数据类型是8位的logic数据。
    • 队列结合了链表和数组的优点,可在任何地方添加或删除元素,并通过index实现对任一元素的访问
    • 声明时使用美元符号[$],队列的存储空间无限大,理论上为物理内存的最大空间,从0$
    • 不需要使用new[ ]来创建空间,一开始的空间为0,使用队列的方法可以实现元素的增减
    • 队列自带的方法有:insert、delete、push_front、push_back、pop_front、pop_back(通过push_backpop_front的结合来可以实现FIFO的用法)
	task gen();		// specifying input and output ports and packet data 
		sa = 3;
		da = 7;
		payload.delete();
		repeat($urandom_range(2,4))
			payload.push_back($urandom);
	endtask: gen
  • 队列方法:参考link
    • payload.delete()方法:删除整个queue;若在括号中指定index,则删除该元素。
    • payload.push_back()方法:在队尾插入元素,括号里为待插入的元素。
  • 随机化系统函数:参考link
    • $urandom_range(): 返回指定范围内的无符号随机整数
    • $urandom:返回32bit无符号数。payload是8bit,32bit无符号数高位截断,取低8位赋值给payload。参考link

transactor & device driver

这里的transactor,无其他具体的动作,只是调用device driver完成事务;device driver才是直接与硬件交互的模块。根据DUT发送数据的时序来看,完成一次事务需要发送address、padding bits、payload。
DUT时序

send transactor
	task send();	// test transactor
		send_address();
		send_pad();
		send_payload();
	endtask: send
send drivers
	task send_address();	// device driver 1
		rtr_io.cb.frame_n[sa] <= 1'b0;
		for(int i=0; i<4; i++) begin
			rtr_io.cb.din[sa] <= da[i];
			@(rtr_io.cb);	// dont forget clock !!!
		end
	endtask: send_address

	task send_pad();		// device driver 2
		rtr_io.cb.frame_n[sa] <= 1'b0;
		rtr_io.cb.valid_n[sa] <= 1'b1;
		rtr_io.cb.din[sa] <= 1'b1;
		repeat(5) @(rtr_io.cb);
	endtask: send_pad

	task send_payload();	// device driver 3
		rtr_io.frame_n[sa] <= 1'b0;
		rtr_io.valid_n[sa] <= 1'b0;
		for(int index=0; index<payload.size(); index++) begin	// -> foreach(payload[index])
			for(int i=8; i<8; i++) begin
				rtr_io.cb.din[sa] <= payload[index][i];
				rtr_io.cb.valid_n[sa] <= 1'b0;
				rtr_io.cb.frame_n[sa] <= (index == payload.size - 1) && (i==7);
				@(rtr_io.cb);	// dont forget clock !!!
			end
		end
		rtr_io.cb.valid_n[sa] <= 1'b1;
	endtask: send_payload		
  • 特别注意时钟推进的位置!要特别注意如何把时钟拨快。如果在一个子程序中,你在退出子程序时推进时钟,然后在另一个子程序中,你在进入子程序时推进时钟,可能会导致错误的计时。观察@(rtr_io.cb)的位置发现,这三个diver都在退出子程序之时推进时钟。

task integration

在initial过程块中调用上述task,即可完成Lab2中测试平台的搭建。

	initial begin
		run_for_n_packets = 21;	// dont forget define it as "int"
		reset();
		repeat(run_for_n_packets) begin
			gen();
			send();
		end
		repeat(10) @(rtr_io.cb);
	end
  • send()后增加10个额外的时钟周期,目的是便于观察最后一轮发送的输出数据;不加的话,不便于观察而已,不影响结果。

一些疑惑

  • 创建队列元素之前为何要先使用delete()方法将整个队列清空?
  • 因为test中重复发送packets多次,在新一轮的发送之前必须将旧的内容清除,创建新的待发送数据。假设只发送一次,不清空队列不会产生影响。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值