目录
任务一:创建一个数据包类(class)文件(用packet类来封装数据包的信息)
学习目标是:
1.将数据信息封装进入Packet类中
2.利用随机化(randomization)在packet类中随机产生源地址,目标地址和payload。
3.创建两个packet对象(object),一个包用来在DUT输入端输入,另一个包用来和DUT输出的数据相参照。
4.将compare()方法嵌入packet类,用来验证DUT工作的正确性。
任务一:创建一个数据包类(class)文件(用packet类来封装数据包的信息)
1.用编辑器打开Packet.sv文件。
2.声明一个Packet类的定义:
3.通过在类语句(statement)的前面和后面使用宏作为标记来防止多次编译。
4.在Packet类的体中,创建如下的属性:
(不同的数据包对象将会由 gen() 程序产生,我们需要区分这些不同的数据包对象,因此我们引入string name。)
任务二:定义数据包的属性约束
1.在属性声明之后,添加一个约束模块来限制sa和da在0至15之内,和payload.size()在2至4之内。
任务三:定义数据包类方法的雏形
1.在数据包类的体中,添加以下的方法声明:
注:表示类中的这些方法属于块外方法声明,它的内容在外部具体表示如:
function Packet::new(string name);
...
endfunction: new
function bit Packet::compare(Packet pkt2cmp, ref string message);
...
endfunction: compare
function void Packet::display(string prefix);
...
endfunction: display
任务四:定义数据包类new() 构造函数
new() 被用来初始化对象并为它开辟空间。对于这个Packet对象来说,大部分性质将会调用randomize() 来进行设置,但是 name 这一性质需要在构造函数(constructor)中初始化。
1.在Class()体的外部,创建new() 方法的具体内容。确定通过::这一接口,可以使这个构造函数回到开始的那个类中。
2.在构造函数内部
这个机制能让这个string到达packet class的所有其他方法中去。
任务五:定义Packet的方法compare()
为了自我验证,经常会去比较两个数据对象的内容。在数据对象中建立compare方法是一个很好的主意。
从test.v中剪切和粘贴compare() 到Packet类中。
参考上面用 :: 标记的的方式,完成compare() 方法。
修改argument列表来包含一个Packet handle:
4.在compare() 方法内部,参照这个类的性质来改写 pkt2cmp_payload。
function bit Packet::compare(Packet pkt2cmp, ref string message)
if(payload.size() != pkt2cmp_payload.size()) begin
message = "Payload size Mismatch:\n";
message = { message, $sformatf("payload.size() = %0d, pkt2cmp_payload.size() = %0d\n", payload.size(), pkt2cmp_payload.size()) };
return (0);
end
if(payload != pkt2cmp_payload) begin
message = "Payload Content Mismatch:\n";
message = { message, $sformatf("Packet Sent: %p\nPkt Received: %p", payload, pkt2cmp_payload) };
return (0);
end
message = "Successfully Compared";
return(1);
endfunction: compare
任务六:定义数据包的方法display()
能打印出一个数据包的内容,在debug过程中十分有用。为了让这一方式简化,一个display的方法应该被定义在这个Packet类中。这样就可以在控制台上打印出Packet对象的内容。
1.在类外,创建display()方法.
2.在方法内,打印你想输出的内容。
3.保存并关闭packet.sv文件。
任务七:修改test.sv来使用 Packet 类
这个packet类现在封装了路由器数据包的信息。
你将会产生随机Packet对象,接着会在这些随机数据包对象的基础上通过路由器发送和接受数据包。
1.用编辑器打开test.sv。
2.在program块内部,添加一个include语句,从而将Packet class包含进来。
3.创建和构造两个program全局数据包对象,pkt2send和pkt2cmp。
任务八:修改gen() 任务去产生数据包对象
1.在gen() 任务内,删掉所有已存在的代码。
2.声明一个静态int变量能够记录Generator产生了多少个数据包。
3.将 pkt2send 的 name 设置为一个唯一的字符串变量。
4.随机化数据包对象pkt2send。如果随机化失败,打印一条错误信息后停止程序并终止仿真。
5.更新所有program全局变量。(应用来自对象的数据)
这一步让pkt2send对象的内容对所有部件(component)是可见的。这些program的全局变量是一个暂时的解决方案。在下一个lab中,我们将删除这些变量,并将它们移植到testbench中不同部件的内部。
当你完成这些时,你的代码应该如下所示:
任务九:修改recv() 任务
在recv() 任务中,我们从路由器输出端取样payload时,需要将它们集合到一个数据包类中(pkt2cmp)。这个数据包对象将会被用来检查pkt2send对象。
在recv() 任务中:
在调用get_payload任务前要做以下的事情:
1.创建一个静态int型变量pkt_cnt来记录接收到的数据包的数量。
在调用get_payload之后要做的事情:
2. 连接pkt2cmp.da和程序全局变量da。
3. 连接pkt2cmp.payload和pkt2cmp_payload。
4. 为pkt2cmp对象设置一个唯一的name。
task recv();
static int pkt_cnt = 0;
get_payload();
pkt2cmp.da = da;
pkt2cmp.payload = pkt2cmp_payload;
pkt2cmp.name = $sformatf("rcvdPkt[%0d]", pkt_cnt++);
// 之前的写法:get_payload();
endtask: recv
任务十:修改check() 任务
在check() 任务中,你将把 compare() 放入Packet对象中去验证发送和接收到的内容是否正确。为了debug,你应该在这个packet对象中使用display() 方法。
1.将compare() 方法放入packet对象中,从而取代以前的compare() 。
(你想比较的两个对象是全局变量pkt2send和pkt2cmp)
2.当探查到错误时,使用display() 方法。
当完成操作后,这个check() 的程序应该如下所示:
task check();
// 之前的写法
// string message;
// static int pkts_checked = 0;
// if(!compare(message)) begin
// $display("\n%m\n[ERROR]%t Packet #%0d %s\n" , $realtime, pkts_checked, message);
// $finish;
// end
// $display("[NOTE]%t Packet #%0d %s", $realtime, pkts_checked++, message);
// 变成类之后的写法
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
$display("[NOTE]%t Packet #%0d %s", $realtime, pkts_checked++, message);
endtask: check
任务十一:检查和保存文件
-
确保你已经删除掉了test.sv文件中的compare() 程序。
-
保存和关闭test.v文件。
任务十二:编译和仿真(略)
总结:
对于gen() 产生发送数据 和 recv()采样数据的修改:我的理解是这样的
对于gen() 之后的任务中,需要用到 sa, da, payload, 故把 发送数据对象pkt2send的sa, da, payload 传给 全局变量
对于采样数据任务recv() 中调用的 get_payload() , 需要用到da, pkt2cmp_payload
故把这些,再传给 采样数据对象 pkt2cmp