作者:liuleyi | 来源:互联网 | 2023-09-24 14:09
背景 DUT和tb之间的port口的数量较多,很容易犯错,可以将interface看成一根巨大的线缆,然后线缆里面包括了许多传输线,连接不同的设备。
interface的定义和使用 需要注意的:
如果是使用logic clk,会出现logic的默认值是x,如果后续的tb没有对clk进行赋值,则他可能会出现一直是x的状态。把if的clk设为bit的话默认为0。 interface arb_if ( input bit clk) ; logic[ 1 : 0 ] grant, request; logic grant_valid; logic rst; endinterfacemodule arb ( arb_if arbif) ; ... always@( posedge arbif. clk or posedge arbi. rst) ;
连接top和子模块
module top; bit clk; always # 5 clk = ~ clk; arb_if arbif ( clk) ; arb a ( arbif) ; test t ( arbif) ; endmodule
如果都没有使用interface的话
moduel top; bit clk; always #5 clk= ~ clk; arb_if arbif ( clk) ; test_arbif t1 ( . grant ( grant) , . request ( request) , . rst ( rst) , . clk ( clk) ) ; arb_port u0_arbport ( . grant ( grant) , . request ( request) , . rst ( rst) , . clk ( clk) ) ; endmodule
modport 之前的interface是没有指出方向的,我们可以在interface里面通过modport指出方向,并且
interface arb_if ( input bit clk) ; logic[ 1 : 0 ] grant, request; logic rst; modport TEST ( output request, rst, input grant, clk) ; modport DUT ( input request, rst, clk, output grant) ; modport MONITOR ( input request, grant, rst, clk) ; endinterface
modport使用
module arb ( arb_if. DUT arbif) ; ... endmodulemodule TEST ( arb_if. TEST arbif) ; ... endmodulemodule monitor ( arb_if. MONITOR arbif) ; ... endmodule
module和interface区别
interface不能例化module的,module可以例化interface; 不能将module里面portlist含有另一个module的,可以含有interface 如果function、task的端口声明中声明为ref,那么function、task必须是automatic! 在program或者module中,function、task默认都是static 激励时序 竞争与冒险 组合逻辑中可能会传输不同的路径,有先后顺序,然后到达输出门的时间不同,这个现象是竞争;产生毛刺现象(冒险);后仿真比较容易看到延迟,打开dtelt-cycle,可以看到; #0 能强制让b进程晚于a进程,避免竞争冒险的,一般会在验证环境中,
delta cycle 实际具体的电路中&#xff0c;会有一定的延迟时间&#xff0c;但是我们是无法得知是多少的&#xff0c;所以我们在仿真过程中会人为地在模拟过程中的时钟电路驱动添加一个无限小的时间delta cycle 的延迟。 如果仿真器进行一个run 0 &#xff0c;就可以运行一个delta cycle。 在时钟有效沿之后才进行有效采样&#xff0c;也就是说我们想得到我们想要的数&#xff0c;我们需要在时间有效沿后一点点 位置进行采样。 module top_tb; bit clk1, clk2; bit rst; logic [ 1 : 0 ] data; initial beginforever #1 clk1 &#61; ~ clk1; end always &#64;( clk1) beginclk2 <&#61; clk1; end initial begin#2 rst &#61; 1 &#39;b0; #4 rst &#61; 1 &#39;b1; #10 $stop; endalways &#64;( posedge clk1 or negedge rst) beginif ( ! rst) data <&#61; 2 &#39;b00; else data <&#61; data&#43; 2 &#39;b01; end always &#64;( posedge clk1) begin$display ( "clk1 &#64;%t : data is %h" , $time, data) ; end always &#64;( posedge clk2) begin$display ( "clk2 &#64;%t : data is %h" , $time, data) ; end endmodule
这里使用verdi进行仿真&#xff0c;在./simv &#43;fsdb&#43;delta
才能使用view-expand delta ,怎么使用verdi进行看delta 如果设计和测试同时对同一个信号进行访问&#xff0c;例如&#xff1a;tb正在初始化某一变量&#xff0c;而RTL同时也要读这个变量&#xff0c;读回来的是初始化前的值。
timing region 在Verilog进行仿真时&#xff0c;在一个timeslot里面的语句是按照一定事件顺序执行的&#xff1b;
Active Events&#xff1a;1&#xff09;blocking assignments&#xff1b;2&#xff09;nonblocking assignment RHS计算&#xff1b;3&#xff09;连续赋值&#xff1b;4&#xff09;$display command execution&#xff1b; Inactive Events&#xff1a;#0 blocking assignment Nonblocking Events:nonblocking assignment RHS更新到左边的赋值过程&#xff1b; Monitor Event:1)$monitor;2) $strobe sig1<&#61; sig2& sig3; $display ( sig1) ; $monitor ( sig1) ;
为避免仿真和设计竞争问题(race condition)&#xff0c;systemverilog中引入了program的概念。 关于timing region的说明
经常有说往前采值&#xff0c;就是说的是往preponed区进行采值&#xff0c;当前的preponed区的值也就是上一个timeslot的postponed值&#xff1b; Observed区是触发clocking block&#xff0c;同时的并行断言也是这里进行的&#xff1b; 一般后面的sv的区&#xff0c;是通过program区进行的&#xff0c;其中名字就是Verilog里面的前面加上一个re&#xff1b; program为了区分验证环境和设计环境&#xff0c;它不能包含任何的层次结构&#xff0c;也就是他不能包含module、interface、program&#xff1b; 但是在UVM里面没什么人使用program了&#xff0c;都是会使用class&#xff0c;在program里面能够做的事情在module里面都可以进行。 program里面不能使用always&#xff1a;
tb中程序一般会遵循初始化-驱动激励信号-获取DUT对激励的反馈&#xff0c;直到结束&#xff0c;当最后一个initial模块结束后&#xff0c;这个仿真就结束了&#xff0c;就像执行$finish一样。 always语句是没有结束&#xff0c;需要$exit来指定才能接受。 如果需要一个类似always块的功能&#xff0c;可以使用“initial forever”来完成相同的事&#xff0c;所以initial forever可以在tb中可以使用。 program需要注意的 &#xff1a;
program中不能例化其他program和module 不能出现interface和always&#xff0c;可以使用initial forever替代always program内部可以发起多个initial块 program中内部定义的变量最好采用阻塞赋值&#xff0c;当然采用非阻塞仿真器也不会产生error&#xff0c;驱动外部信号则应该采用非阻塞赋值 program中的initial块和module中的initial块执行位置不同&#xff0c;前者在reactive&#xff0c;后者在active块中执行。 program中存在的多个initial块中&#xff0c;如果有一个initial采用了退出系统函数$exit&#xff08;&#xff09;&#xff0c;则会结束该program&#xff0c;而不仅仅是该initial块。 program和module的相似和不同
module里可以定义program&#xff0c;而program里不能定义module; module里不能调用program里定义的task,function&#xff0c;而program可以调用module里定义的task和function&#xff1b; program里不能例化module,interface,其它program,也不能包含always块·。 最主要的区别是program是在inactive时域执行的&#xff0c;而module在active时域执行的&#xff0c;所以program在module后执行&#xff0c;可以解决竞争冒险现象 clocking block systemverilog通过clocking的来实现这个采样和驱动过程
interface tb_itf ( input bit clk) ; parameter setup_time &#61; 3 ; parameter hold_time &#61; 2 ; logic [ 1 : 0 ] dat_in, dat_out; clocking cb&#64;( posedge clk) ; default input #setup_time output #hold_time; output dat_in; input dat_out; endclockingmodport TEST ( clocking cb) ; modport DUT ( input dat_in, output dat_out) ; endinterfacemodule duv ( tb_itf. DUT itf) ; initial beginitf. dat_out &#61; 2 &#39;b01; #19 itf. dat_out &#61; 2 &#39;b11; #7 itf. dat_out &#61; 2 &#39;b10; #14 itf. dat_out &#61; 2 &#39;b01; end endmodulemodule test ( tb_itf. TEST itf) ; initial beginitf. cb. dat_in <&#61; 2 &#39;b00; #9 itf. cb. dat_in <&#61; 2 &#39;b11; #13 itf. cb. dat_in <&#61; 2 &#39;b11; #16 itf. cb. dat_in <&#61; 2 &#39;b11; #14 itf. cb. dat_in <&#61; 2 &#39;b11; #50 $finish; end endmodule
进行top模块连接
module top_tb; bit clk, rst; initial beginclk &#61; 1 &#39;b1; forever #5 clk &#61; ~ clk; end tb_itf itf ( clk) ; duv dut ( itf) ; test tb ( itf) ; $monitor ( "&#64;%0t dat_in &#61; %d" , $time, itf. cb. dat_in) ; $monitor ( "&#64;%0t dat_out &#61; %d" , $time, itf. cb. dat_out) ; endmodule