系统框图:
总体上看,实验2 转到实验3,把更多的验证环境好而组建都放置到package里面,chnl_trans的内容丰富了很多,变得更复杂了。实验二里面的chnl_trans是在generator里面完成赋值的,实验三赋值、随机化则是自己完成的
信箱:
旗语: 主要是可以实现对同一资源的访问控制,semaphore是SV内建的类,因此需要句柄,方法包含new(),get(),put(),try_get()。旗语想当一个篮子,想要获取资源必须从篮子里面获取一把后者多把钥匙,获取完资源后必须把钥匙放回篮子里面去。另外一个线程想要获取资源的话,必须等待篮子里面拥有足够多的钥匙才可以,否则会是一直阻塞的状态。
断言: 断言分为立即断言和并发断言,断言属性类似于if语句中的条件表达式,用于检查表达式中的值是否为真。
主要是数据空闲周期和包数据周期,data.size被限制在[4:8],data_nidles 限制在[0:2],pkt_nidle限制在[3:5]
data.size inside {[4:8]};/*...................................*/constraint cstr{data.size inside {[4:8]};foreach(data[i]) data[i] == 'hC000_0000 + (this.ch_id<<24) + (this.pkt_id<<8) + i;soft ch_id == 0;soft pkt_id == 0;data_nidles inside {[0:2]};pkt_nidles inside {[3:5]};};/*...................................*/task chnl_write(input chnl_trans t);foreach(t.data[i]) begin@(posedge intf.clk);intf.drv_ck.ch_valid <= 1;intf.drv_ck.ch_data <= t.data[i];wait(intf.ch_ready === 'b1);$display("%0t channel initiator [%s] sent data %x", $time, name, t.data[i]);repeat(t.data_nidles) chnl_idle();endrepeat(t.pkt_nidles) chnl_idle();endtask
仿真结束:原本在 chnl_root_test 类中用来结束仿真的$finish()变迁到 generator 中。
agent部分不再控制发送数据的多少,只是控制运行generate和initiator,发送ntrans的数量在generate里面控制,initiator里面因为forever的存在是一直运行的。如果放在165行代码的位置,会提前结束,发送完一次数据就会结束仿真。
165处会有个breakpoint,生成的对象只有1184个,$finish 在这个位置中,程序会提早结束,因为fork jion_any中有一个程序结束就会导致程序直接结束。
解决方法:initiator是不会结束的,所以需要使用generate来结束控制agent结束,从而使得整个结束掉。所以在chnl_root_test中在三个agent运行结束以后finish
Could we put c.obj_id = this.obj_id here? and why?
obj_id是一个local静态变量,处于一个独立了的空间,句柄C和this都是通过访问静态变量来获得obj_id的值,相当于是自己给自己赋值,所以有没有这句话是一样的。
restart之后两个数据是一样的,因为默认产生随机数的种子是相同的。运行仿真器命令vsim -novopt -solvefaildebug -sv_seed 0 work.tb1结果也是一样的,运行vsim -novopt -solvefaildebug -sv seed random work.tb1,结果不一样。
obj. id 值是1200,每次new一次就会自增一次,chnl_basic_test中的ntrans有200个数据,initiator中会存在一次克隆,相当于乘2,3个agent,相当于乘3。200*2*3=1200;一个agent里面最多三个对象存在,三个agent里面最多九个。 function new();this.obj_id++;endfunction
mailbox部分:
generate首先生成一个req然后放到req_mb里面,然后传递给initiator,initiator会条用clone产生一个rsp,使得rsp.rsp=1,再放到rsp_mb里面。然generate还会从rsp_mb里面拿回一个rsp的句柄。在initiator里面并没有例化这两个信箱,所以req_mb和rsp_mb都是句柄,句柄都是指向generator里面,在agent里面赋值句柄,把generator两个不悬空的句柄赋值给initiator中悬空的句柄
实现不同的test,需要对generator里面作出不同的控制,控制对象就是chnl_trans。可以达到在顶层里面控制chnl_trans的效果。在chnl_root_test里面声明initiator和generator的句柄,然后利用信箱进行连接。
function new(string name = "chnl_root_test");foreach(agent[i]) beginthis.agent[i] = new($sformatf("chnl_agent%0d",i));[i] = new();this.agent[i].q_mb = [i].req_mb;this.agent[i].init.rsq_mb = [i].rsq_mb; endthis.name = name;$display("%s instantiate objects", this.name);endfunction
参考gen[0]书写gen[1] 、gen[2]
virtual function void do_config();super.do_config();assert(gen[0].randomize() with {ntrans==100; data_nidles==0; pkt_nidles==1; data_size==8;})else $fatal("[RNDFAIL] gen[0] randomization failure!");assert(gen[1].randomize() with {ntrans==50; data_nidles inside {[1:2]}; pkt_nidles inside {[3:5]}; data_size==6;})else $fatal("[RNDFAIL] gen[1] randomization failure!");assert(gen[2].randomize() with {ntrans==80; data_nidles inside {[0:1]}; pkt_nidles inside {[1:2]}; data_size==32;})else $fatal("[RNDFAIL] gen[2] randomization failure!");
分别对chnl_burst_test和chnl_fifo_ fullt_test中的config进行配置
仿真的参数传递选择测试的种类:对比tb1和tb3
//更改测试的话,需要重新更改代码,重新编译import chnl_pkg1::*;chnl_intf chnl0_if(.*);chnl_intf chnl1_if(.*);chnl_intf chnl2_if(.*);chnl_basic_test basic_test;chnl_burst_test burst_test;chnl_fifo_full_test fifo_full_test;initial begin basic_test = new();basic_test.set_interface(chnl0_if, chnl1_if, chnl2_if);basic_test.run(); end
结合系统框图 ,根据脚本命令选择测试类型,如果没有声明的话则会自动选择basic_test测试
import chnl_pkg2::*;chnl_intf chnl0_if(.*);chnl_intf chnl1_if(.*);chnl_intf chnl2_if(.*);chnl_basic_test basic_test;chnl_burst_test burst_test;chnl_fifo_full_test fifo_full_test;chnl_root_test tests[string];string name;initial begin basic_test = new();burst_test = new();fifo_full_test = new();tests["chnl_basic_test"] = basic_test;tests["chnl_burst_test"] = burst_test;tests["chnl_fifo_full_test"] = fifo_full_test;if($value$plusargs("TESTNAME=%s", name)) ists(name)) begintests[name].set_interface(chnl0_if, chnl1_if, chnl2_if);tests[name].run();endelse begin$fatal($sformatf("[ERRTEST], test name %s is invalid, please specify a valid name!", name));endendelse begin$display("NO runtime optiont TEST=[testname] is configured, and run default test chnl_basic_test");tests["chnl_basic_test"].set_interface(chnl0_if, chnl1_if, chnl2_if);tests["chnl_basic_test"].run(); endend
endmodule
增加了组件monitor和checker。
在 chnl_monitor 类和 mcdt_monitor 类各自的 mon_trans()方法中需要采集正确的数据,将它们写入 mailbox 缓存,同时将捕捉的数据也打印出来,便于我们的调试。 就是通过接口把各自的mon_trans数据分别送进邮箱。 task mon_trans();mon_data_t m;forever begin@(posedge intf.clk iff (_ck.ch_valid==='b1 && _ck.ch_ready==='b1));m.data = _ck.ch_data;mon_mb.put(m);$display("%0t %s monitored channle data %8x", $time, this.name, m.data);endendtaskendclass
task mon_trans();mon_data_t m;forever begin@(posedge intf.clk _ck.mcdt_val==='b1);m.data = _ck.mcdt_data;m.id = _ck.mcdt_id;mon_mb.put(m);$display("%0t %s monitored mcdt data %8x and id %0d", $time, this.name, m.data, m.id);endendtaskendclass
在 chnl_agent 中,参考如何例化的 initiator 对象,也对 chnl_monitor 对象开始例化、传递虚接口和使其运行。
例化initiator对象还是通过new函数,参考initiator写法,分别进行例化和接口传递和运行
class chnl_agent;local string name;chnl_initiator init;chnl_monitor mon;virtual chnl_intf vif;function new(string name = "chnl_agent");this.name = name;this.init = new({name, ".init"}); = new({name, ".mon"});endfunctionfunction void set_interface(virtual chnl_intf vif);this.vif = vif;init.set_interface(vif);mon.set_interface(vif);endfunctiontask run();forkinit.run();mon.run();joinendtaskendclass: chnl_agent
在 chnl_checker 的任务 do_compare()中, 同学需要从 checker 自己的数据缓存mailbox 中分别取得一个输出端的采集数据和一个输入端的采集数据,继而将它们的内容进行比较。
输出是mcdt输出的数据,输入是三个channel输入的数据,也就是三个agent,对于输出跟哪个agent的数据比较则是根据数据的ID来判断。
task do_compare();mon_data_t im, om;forever (om);case(om.id)0: in_mbs[0].get(im);1: in_mbs[1].get(im);2: in_mbs[2].get(im);default: $fatal("id %0d is not available", om.id);endcaseif(om.data != im.data) _count++;$error("[CMPFAIL] Compared failed! mcdt out data %8x ch_id %0d is not equal with channel in data %8x", om.data, om.id, im.data);endelse begin$display("[CMPSUCD] Compared succeeded! mcdt out data %8x ch_id %0d is equal with channel in data %8x", om.data, om.id, im.data);p_count++;endendtaskendclass
在顶层环境 chnl_root_test 中。同学们先要对 mcdt_monitor 和 chnl_checker 进行例化。传递虚接口,并且将 chnl_monitor. mcdt_monitor 的邮箱句柄分别指向chnl_checker 中的邮箱实例。别忘了,在例化和连接之后要运行
class chnl_root_test;chnl_generator gen[3];chnl_agent agents[3];mcdt_monitor mcdt_mon;chnl_checker chker;protected string name;event gen_stop_e;function new(string name = "chnl_root_test");this.name = name;this.chker = new();foreach(agents[i]) beginthis.agents[i] = new($sformatf("chnl_agent%0d",i));[i] = new();this.agents[i].q_mb = [i].req_mb;this.agents[i].init.rsp_mb = [i].rsp_mb;this.agents[i]._mb = this.chker.in_mbs[i];dt_mon = new();_mb = this.chker.out_mb;$display("%s instantiated and connected objects", this.name);endfunction
为什么约束值都是-1,-1可以使得随机化的初始条件不成立,实现随机化中递进的层层控制。local::ch_id指类chnl_generator的变量,而ch_id指当前req的变量,local::只在randomize里出现。
class chnl_generator;rand int pkt_id = -1;rand int ch_id = -1;rand int data_nidles = -1;rand int pkt_nidles = -1;rand int data_size = -1;rand int ntrans = 10;
task send_trans();chnl_trans req, rsp;req = new();assert(req.randomize with {local::ch_id >= 0 -> ch_id == local::ch_id; local::pkt_id >= 0 -> pkt_id == local::pkt_id;local::data_nidles >= 0 -> data_nidles == local::data_nidles;local::pkt_nidles >= 0 -> pkt_nidles == local::pkt_nidles;local::data_size >0 -> data.size() == local::data_size; })else $fatal("[RNDFAIL] channel packet randomization failure!");
运行之前,首先配置我们的generate,然后运行agent,在运行generate,generate在运行之前的随机化发生在do_config里面
virtual task run();$display($sformatf("*****************%s started********************", this.name));this.do_config();forkagent[0].run();agent[1].run();agent[2].run();join_noneforkgen[0].run();gen[1].run();gen[2].run();join$display($sformatf("*****************%s finished********************", this.name));// USER TODO 1.3// Please move the $finish statement from the test run task to generator// You woudl put it anywhere you like inside generator to stop test when// all transactions have been transfered$finish();endtask
参考:路科验证MCDF_svlab3笔记_Hardworking_IC_boy的博客-CSDN博客_路科验证
本文发布于:2024-02-01 13:07:58,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170676407836812.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |