SYNOPSYS—SystemVerilog入门实验4-2
前言
在结束了实验4-1,接下来我们还需完成以下目标来结束整个实验4:
- 生成随机的数据包对象发送至DUT;
- 接收来自DUT发送出来的数据包;
- 对比相对于DUT输入与输出的数据包。
一、在Lab3的基础上修改
复制Lab3下的test.sv至Lab4下,并打开。
1. 修改 gen ()
将Lab3中的 task gen()
内的部分全部删除
i. 增加 `include
为了将 Packet.sv
包含进 test.sv
中,在这里需使用 `include 语句,该语句具体语法戳此链接。
`timescale 1ns/100ps
program automatic test(router_io.TB rtr_io);
//******add 1******
`include "Packet.sv"
//******add 1******
int run_for_n_packets; // number of packets to test
bit[3:0] sa; // source address
bit[3:0] da; // destination address
logic[7:0] payload[$]; // expected packet data array
initial begin
run_for_n_packets = 2000;
reset();
repeat(run_for_n_packets) begin
gen();
fork
send();
recv();
join
check();
end
repeat(10) @(rtr_io.cb);
end
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
endprogram: test
ii. 声明静态变量 pkts_generated
其主要作用是记录DUT的输入端口共接收了多少组数据包。
`timescale 1ns/100ps
program automatic test(router_io.TB rtr_io);
//******add 1******
`include "Packet.sv"
//******add 1******
int run_for_n_packets; // number of packets to test
bit[3:0] sa; // source address
bit[3:0] da; // destination address
logic[7:0] payload[$]; // expected packet data array
initial begin
run_for_n_packets = 2000;
reset();
repeat(run_for_n_packets) begin
gen();
fork
send();
recv();
join
check();
end
repeat(10) @(rtr_io.cb);
end
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();
//******add 2******
static int pkts_generated = 0;
//******add 2******
endtask: gen
endprogram: test
iii. 定义 发送至DUT(输入变量)的数据包的名称 pkt2send
在定义名称前,应首先声明一个句柄并为其开辟空间!不由想到:输入变量可以定义一个packet,那么输出变量是否也可以定义。这里的输出变量要经过数据比较器 (checker) 与输入变量进行比对,那么就不妨定义为pkt2cmp即可。
`timescale 1ns/100ps
program automatic test(router_io.TB rtr_io);
//******add 1******
`include "Packet.sv"
//******add 1******
int run_for_n_packets; // number of packets to test
bit[3:0] sa; // source address
bit[3:0] da; // destination address
logic[7:0] payload[$]; // expected packet data array
//******add 4******
Packet pkt2send = new();
Packet pkt2cmp = new();
//******add 4******
initial begin
run_for_n_packets = 2000;
reset();
repeat(run_for_n_packets) begin
gen();
fork
send();
recv();
join
check();
end
repeat(10) @(rtr_io.cb);
end
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();
//******add 2******
static int pkts_generated = 0;
//******add 2******
//******add 3******
pkt2send.name = $sformatf("Packet[%0d]", pkts_generated++);
//******add 3******
endtask: gen
endprogram: test
在这里需使用 $sformatf 内建函数,该函数具体语法戳此链接。
iv. 设置随机化失败即退出语句
`timescale 1ns/100ps
program automatic test(router_io.TB rtr_io);
//******add 1******
`include "Packet.sv"
//******add 1******
int run_for_n_packets; // number of packets to test
bit[3:0] sa; // source address
bit[3:0] da; // destination address
logic[7:0] payload[$]; // expected packet data array
//******add 4******
Packet pkt2send = new();
Packet pkt2cmp = new();
//******add 4******
initial begin
run_for_n_packets = 2000;
reset();
repeat(run_for_n_packets) begin
gen();
fork
send();
recv();
join
check();
end
repeat(10) @(rtr_io.cb);
end
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();
//******add 2******
static int pkts_generated = 0;
//******add 2******
//******add 3******
pkt2send.name = $sformatf("Packet[%0d]", pkts_generated++);
//******add 3******
//******add 5******
if(!pkt2send.randomize()) begin
$display("\n%m\n [ERROR] %t: Randomize Error!!", $realtime);
$finish;
end
//******add 5******
endtask: gen
endprogram: test
在这里需使用 $display 、 $finish 内建函数,该函数具体语法戳此链接。
v. 信号sa、da、队列payload实现同步
大家是否还记得Lab3中关于数据发送 task send()
内的语句块:根据DUT接收的时序,我们将模拟该时序把数据串行地发送进DUT,而这些数据都需要由外部的激励产生,在这里外部的激励即为 Packet.sv
,因此我们需将 Packet.sv
生成的随机数据更新至 test.sv
中。
`timescale 1ns/100ps
program automatic test(router_io.TB rtr_io);
//******add 1******
`include "Packet.sv"
//******add 1******
int run_for_n_packets; // number of packets to test
bit[3:0] sa; // source address
bit[3:0] da; // destination address
logic[7:0] payload[$]; // expected packet data array
//******add 4******
Packet pkt2send = new();
Packet pkt2cmp = new();
//******add 4******
initial begin
run_for_n_packets = 2000;
reset();
repeat(run_for_n_packets) begin
gen();
fork
send();
recv();
join
check();
end
repeat(10) @(rtr_io.cb);
end
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();
//******add 2******
static int pkts_generated = 0;
//******add 2******
//******add 3******
pkt2send.name = $sformatf("Packet[%0d]", pkts_generated++);
//******add 3******
//******add 5******
if(!pkt2send.randomize()) begin
$display("\n%m\n [ERROR] %t: Randomize Error!!", $realtime);
$finish;
end
//******add 5******
//******add 6******
sa = pkt2send.sa;
da = pkt2send.da;
payload = pkt2send.payload;
//******add 6******
endtask: gen
endprogram: test
至此,task gen()
已更新完毕。
2. 修改 recv ()
i. 声明静态变量 pkt_cnt
其主要作用是记录DUT的输出端口共发出了多少组数据包。
task recv();
//******add 1******
static int pkt_cnt = 0;
//******add 1******
get_payload();
endtask: recv
ii. 定义 DUT发送(输出变量)的数据包名称 pkt2cmp
task recv();
//******add 1******
static int pkt_cnt = 0;
//******add 1******
get_payload();
//******add 2******
pkt2cmp.name = $sformatf("rcvdPkt[%0d]", pkt_cnt++);
//******add 2******
endtask: recv
iii. 信号da、队列payload实现同步
在数据比较时,若对比失败,我们希望能够明确DUT发送出来的队列payload是通过哪个通道传递的,这样对于定位问题会起到积极的作用。
task recv();
//******add 1******
static int pkt_cnt = 0;
//******add 1******
get_payload();
//******add 2******
pkt2cmp.name = $sformatf("rcvdPkt[%0d]", pkt_cnt++);
//******add 2******
//******add 3******
pkt2cmp.da = da;
pkt2cmp.payload = pkt2cmp_payload;
//******add 3******
endtask: recv
至此,task recv()
已更新完毕。
3. 修改 check ()
将Lab3中的 function bit compare()
内的部分全部删除。
i. 修 if (…) …begin 中的判断条件
在 task check()
任务中,我们把 function bit compare
放入Packet对象中,目的使验证发送和接收的数据是否正确。为了debug,我们需将错误的具体信息均进行打印。
需要说明的是,!pkt2send.compare(pkt2cmp, message)
是根据 Packet.sv
中 function bit Packet::compare
的返回值进行判断的,当数据错误返回0,反之返回1。
task check();
string message;
static int pkts_checked = 0;
//******add 1******
if (!pkt2send.compare(pkt2cmp, message)) begin
$display("\n%m\n[ERROR]%t Packet #%0d %s\n", $realtime, pkts_checked, message);
pkt2send.display();
pkt2cmp.display();
//******add 1******
$finish;
end
$display("[NOTE]%t Packet #%0d %s", $realtime, pkts_checked++, message);
endtask: check
至此,task check()
已更新完毕。
将test.sv文件保存并关闭,随即启动仿真即可。
二、总结
该部分实验主要将红色箭头指向的三部分进行了环境完善,至此,一个进一步优化的验证环境搭建完毕,感谢大家支持。