SYNOPSYS—SystemVerilog入门实验2
文章目录
前言
该实验的目的为:从DUT的输入端口(端口3)发送1包数据,并由DUT的输出端口(端口7)进行输出。
一、实验思路
- 如何产生这个数据包?
- 发送的数据包格式与内容是什么?
二、实验步骤
针对上述描述的两条思路,首先要思考的是如何去产生数据包。有些时候,数据在传输的过程中,不一定时时刻刻都会使用到,为了更加易于我们对数据的掌控,在FPGA中我们会使用Verilog来设计FIFO、寄存器等来暂时存储数据。而在SV中,充当这部分角色的则是队列、数组等。
1.声明与调用gen()
在这里,我们使用 队列 来暂时存放数据包,由于实验中规定数据包从端口3进入至DUT,从端口7输出,因此需将端口3作为源地址(Source Address),端口7作为目的地址(Destination Address),在实验1 test.sv的基础上继续敲入代码如下:
program automatic test(router_io.TB router_io);
//---one--
bit [3:0] sa ;//源地址
bit [3:0] da ;//目的地址
logic [7:0] payload[$] ;//数据包(队列)
initial begin
//----创建一个vcd+dump文件来产生可见波形
// $vcdpluson;
reset();
//---two---
gen();
send();
end
task reset();
router_io.reset_n = 1'b0 ;
router_io.cb.frame_n <= '1 ;
router_io.cb.valid_n <= '1 ;
#2 router_io.cb.reset_n <= 1'b1 ;
repeat(15) @(router_io.cb);
//change
router_io.cb.frame_n <= 1'b0 ;
endtask: reset
//---three---
task gen();
endtask: gen
endprogram: test
代码分析: one 声明三个全局变量 two 声明须在initial块中(send已提前声明,在后续会用到) three 调用采用task endtask的格式
task gen();
//---one---
sa = 3;
da = 7;
//---four---
payload.delete();
//---two---
repeat($urandom_range(2,4))
//---three---
payload.push_back($urandom);
endtask: gen
代码分析: 在task gen()的任务体中,根据实验要求 one 设置源地址为3,目的地址为7, two 随机将2~4(包括2与4)范围内的数 three 依次从队列的末尾填充至队列中,four 需要注意的是在进行队列操作前,须要将队列进行清空操作,防止原有队列中的数据影响后续实验结果。
2.声明与调用send()
紧接着,我们要思考发送的数据包格式是什么?数据包中的数据包含哪些内容?数据包与其他相关的输入信号的时序关系是什么?这些问题的答案,在开展验证前设计师会提供给我们,如果没有按照DUT规定的时序关系(即验证环境的输出)去发送激励,DUT将无法正常对数据进行接收。
1) 读懂时序图
上图中 din[sa] 为DUT的数据信号(输入):首先发4位地址(先低位后高位),之后等待5个时钟周期(上图中pad所示),最后发n位数据(先低位后高位);valid_n[sa] 为DUT的数据有效信号(输入/低有效),在数据信号发送最低位地址时,该信号既可为0又可为1,在数据开始等待5个时钟周期时,该信号置为1,在数据信号开始发送最低位数据时,该信号由高(1)变低(0),当数据全部发送完毕时,该信号又由低(0)变高(1);frame_n[sa] 为DUT的帧标志信号(输入/低有效),在数据信号开始发送最低位地址时,该信号由高(1)变低(0),并一直持续至数据的次高位时,该信号由低(0)变高(1)。
2) 用“代码”描述“时序图”
task send();
//---one---
send_addrs();
//---two---
send_pad();
//---three---
send_payload();
endtask: send
代码分析: 我们调用send()进一步封装了三个子任务:send_addr()、send_pad()、send_payload(),它们分别对应时序图中的 one address、 two pad、three data。
task send_addrs();
//---one---
router_io.cb.frame_n[sa] <= 1'b0;
//---two---
for(int i=0; i<4; i++)begin
router_io.cb.din[sa] <= da[i];
//---three---
@(router_io.cb);
end
endtask: send_addrs
代码分析: 针对 task send_addrs() 而言,我们应在第一个红色箭头处将各个信号的变化用代码描述出来。 one 此刻 frame_n[sa] 信号由高电平(1)跳转为低电平(0),其中高电平即为初始状态,在实验1中的task reset()中已描述。two 由于 valid_n[sa] 既可为1又可为0,故延续初始状态即可,此处不予重复描述;由于数据中的地址A0-A4首先按照先发低位后发高位的顺序依次发送至DUT的输入信号din[sa],因此用for()begin…end循环体来描述这四位的发送顺序,其中 three 需注意每位地址均是在每个时钟周期的上升沿进行发送。
task send_pad();
//---one---
router_io.cb.frame_n[sa] <= 1'b0;
//---two---
router_io.cb.valid_n[sa] <= 1'b1;
//---three---
router_io.cb.din[sa] <= 1'b1;
//---four---
repeat(5) @(router_io.cb);
endtask: send_pad
代码分析: 针对 task send_pad() 而言,我们应在第二个红色箭头处将各个信号的变化用代码描述出来。 one 此时 frame_n[sa] 依旧延续低电平的状态;two valid_n[sa] 此时真正意义上变为高电平; three din[sa] 在发送完四位地址后,电平变为高电平;在第三个红色箭头的时刻到来时,第二个红色箭头距离该箭头的时间间隔为5个时钟周期,因此使用repeat(5)语句将时钟重复5个周期。
task send_payload();
//---one---
foreach(payload[index])begin
for(int i=0; i<8; i++)begin
router_io.cb.din[sa] <= payload[index][i];
//---two---
router_io.cb.valid_n[sa] <= 1'b0;
//---three---
router_io.cb.frame_n[sa] <= (index == (payload.size()-1))&&(i == 7);
@(router_io.cb);
end
end
//---four---
router_io.cb.valid_n[sa] <= 1'b1;
endtask: send_payload
代码分析: 针对 task send_payload() 而言,我们应在第三个红色箭头处将各个信号的变化用代码描述出来。one din[sa] 此时应将数据按照先发低位后发高位的顺序发送,并且每8位拼成1字节,payload[index]中的index代表字节索引值,范围为0 ~ N-1,(例如payload[0][3]则代表队列中第1个字节的第4位数据),因此payload[index][i]能将所有字节的中的所有位全部覆盖,需要注意的是,index在队列中不需要声明,默认从0开始累加; two 此时valid_n[sa] 由高电平变为低电平; three 此时frame_n[sa] 应在准备发送最后1个字节的最后1位时,将低电平变为高电平(1):可以这样理解------如果字节索引值等于最后一个字节的数值且最后1字节里的位数等于最后一位时,将frame_n[sa] 变为高电平。(提示:数据包中有5个字节的数据(payload.size() = 5),index的范围为0~4,则payload.size() -1 = 5-1 = 4)
三、知识点:随机变量赋值
在task gen()的任务体中,我们将sa设置为3,da设置为7。若想将sa与da设置为随机变量,则不妨使用如下语句:
sa = $random;
da = $random;
//---或者---
sa = $urandom;
da = $urandom;
除此之外,若想将sa与da在随机时进行约束,例如,将sa设置为在5 ~ 10(包括5与10)之间的随机数,da设置为10 ~ 15(包括10与15)之间的随机数,则可以编写如下代码:
sa = $urandom_range(5,10);
da = $urandom_range(10,15);
四、总结
该部分实验主要将红色框内的大致结构(数据的产生与发送)搭建了起来,后续的实验会继续在此基础上进完善以及剩余环境的构造,感谢大家支持。