sv实验2
验证框架
1.接口的使用
1.1-1.2
interface chnl_intf(input clk, input rstn); logic [31:0] ch_data; logic ch_valid; logic ch_ready; logic [ 5:0] ch_margin; clocking drv_ck @(posedge clk); default input #1ns output #1ns; output ch_data, ch_valid; input ch_ready, ch_margin; endclocking endinterface module chnl_initiator(chnl_intf intf); string name; int idle_cycles = 1; function automatic void set_idle_cycles(int n); idle_cycles = n; endfunction function automatic void set_name(string s); name = s; endfunction task automatic chnl_write(input logic[31:0] data); @(posedge intf.clk); // USER TODO 1.1 // Please use the clocking drv_ck of chnl_intf to drive data intf.drv_ck.ch_valid <= 1; intf.drv_ck.ch_data <= data; //intf.ch_valid <= 1; //intf.ch_data <= data; @(negedge intf.clk); wait(intf.ch_ready === 'b1); $display("%t channel initiator [%s] sent data %x", $time, name, data); // USER TODO 1.2 // Apply variable idle_cycles and decide how many idle cycles to be // inserted between two sequential data repeat(idle_cycles) chnl_idle(); endtask task automatic chnl_idle(); @(posedge intf.clk); // USER TODO 1.1 // Please use the clocking drv_ck of chnl_intf to drive data intf.drv_ck.ch_valid <= 0; intf.drv_ck.ch_data <= 0; //intf.ch_valid <= 0; //intf.ch_data <= 0; endtask endmodule
加入时钟延迟后,valid和data与clk存在1ns的延迟,方便分析波形。
在initiator模块中引入set_idle_cycles函数灵活设置空闲周期。
仿真的结束
2.1-2.2
task automatic burst_test(); // verification component initializationi chnl0_gen.initialize(0); chnl1_gen.initialize(1); chnl2_gen.initialize(2); chnl0_init.set_name("chnl0_init"); chnl1_init.set_name("chnl1_init"); chnl2_init.set_name("chnl2_init"); chnl0_init.set_idle_cycles(0); chnl1_init.set_idle_cycles(0); chnl2_init.set_idle_cycles(0); $display("burst_test initialized components"); wait (rstn === 1'b1); repeat(5) @(posedge clk); $display("burst_test started testing DUT"); // Please check the SV book for fork-join basic knowledge // and get understood it is for parallel thread running fork repeat(500) chnl0_init.chnl_write(chnl0_gen.get_data()); repeat(500) chnl1_init.chnl_write(chnl1_gen.get_data()); repeat(500) chnl2_init.chnl_write(chnl2_gen.get_data()); join $display("burst_test finished testing DUT"); endtask
task automatic fifo_full_test(); // verification component initializationi chnl0_gen.initialize(0); chnl1_gen.initialize(1); chnl2_gen.initialize(2); chnl0_init.set_name("chnl0_init"); chnl1_init.set_name("chnl1_init"); chnl2_init.set_name("chnl2_init"); chnl0_init.set_idle_cycles($urandom_range(1, 3)); chnl1_init.set_idle_cycles($urandom_range(1, 3)); chnl2_init.set_idle_cycles($urandom_range(1, 3)); $display("fifo_full_test initialized components"); wait (rstn === 1'b1); repeat(5) @(posedge clk); $display("fifo_full_test started testing DUT"); // Please check the SV book for fork-join basic knowledge // and get understood it is for parallel thread running fork repeat(100) chnl0_init.chnl_write(chnl0_gen.get_data()); repeat(100) chnl1_init.chnl_write(chnl1_gen.get_data()); repeat(100) chnl2_init.chnl_write(chnl2_gen.get_data()); join_none fork wait(chnl0_init.intf.ch_margin == 0); wait(chnl1_init.intf.ch_margin == 0); wait(chnl2_init.intf.ch_margin == 0); join $display("fifo_full_test finished testing DUT"); endtask
1.SV中数据的生命周期分为动态(automatic)和静态(static)。class中成员和方法默认为automatic,program、module、interface、package中函数和任务和变量默认为静态的。
在讨论静态变量和动态变量之前,我们先说全局变量和局部变量的概念。
局部变量的生命周期同其所在域,例如function/task中的变量,在方法调用结束后,这些变量的也将消失,所以它们是动态生命周期;
全局变量是从仿真开始到结束一直存在的,例如module中的变量默认情况下全部为全局变量,这也可以理解为module中的变量是硬件电路中实际存在的信号和连接,所以它们是静态生命周期
此处module中的方法默认为静态,所以需要加上automatica
2.fork-join中的线程会同时进行,且全部执行完毕后顺序执行下面的语句。fork-join_none中的线程会同时进行,但不会等待其执行完毕,会直接执行下面的语句。
3.类的例化和类的成员
3.1-3.2
initial begin // USER TODO 3.1 // instantiate the components chn0/1/2_init chnl0/1/2_gen chnl0_init = new("chnl0_init"); chnl1_init = new("chnl1_init"); chnl2_init = new("chnl2_init"); chnl0_gen = new(0); chnl1_gen = new(1); chnl2_gen = new(2); // USER TODO 3.2 // assign the interface handle to each chnl_initiator objects chnl0_init.set_interface(chnl0_if); chnl1_init.set_interface(chnl1_if); chnl2_init.set_interface(chnl2_if); // USER TODO 3.3 // START TESTs $display("*****************all of tests have been finished********************"); basic_test(); burst_test(); fifo_full_test(); $finish(); end
4.包的定义和类的继承
4.1
import chnl_pkg::*;
4.2
class chnl_root_test; chnl_agent agent[3]; protected string name; function new(int ntrans = 100, string name = "chnl_root_test"); foreach(agent[i]) begin this.agent[i] = new($sformatf("chnl_agent%0d",i), i, ntrans); end this.name = name; $display("%s instantiate objects", this.name); endfunction task run(); $display("%s started testing DUT", this.name); fork agent[0].run(); agent[1].run(); agent[2].run(); join $display("%s waiting DUT transfering all of data", this.name); fork wait(agent[0].vif.ch_margin == 'h20); wait(agent[1].vif.ch_margin == 'h20); wait(agent[2].vif.ch_margin == 'h20); join $display("%s: 3 channel fifos have transferred all data", this.name); $display("%s finished testing DUT", this.name); endtask function void set_interface(virtual chnl_intf ch0_vif, virtual chnl_intf ch1_vif, virtual chnl_intf ch2_vif); agent[0].set_interface(ch0_vif); agent[1].set_interface(ch1_vif); agent[2].set_interface(ch2_vif); endfunction endclass // each channel send data with idle_cycles inside [1:3] // each channel send out 200 data // then to finish the test class chnl_basic_test extends chnl_root_test; function new(int ntrans = 200, string name = "chnl_basic_test"); super.new(ntrans, name); foreach(agent[i]) begin this.agent[i].init.set_idle_cycles($urandom_range(1, 3)); end $display("%s configured objects", this.name); endfunction endclass: chnl_basic_test // USER TODO 4.2 // Refer to chnl_basic_test, and extend another 2 tests // chnl_burst_test, chnl_fifo_full_test // each channel send data with idle_cycles == 0 // each channel send out 500 data // then to finish the test class chnl_burst_test extends chnl_root_test; //USER TODO function new(int ntrans = 500, string name = "chnl_burst_test"); super.new(ntrans, name); foreach(agent[i]) begin this.agent[i].init.set_idle_cycles(0); end $display("%s configured objects", this.name); endfunction endclass: chnl_burst_test class chnl_fifo_full_test extends chnl_root_test; // USER TODO function new(int ntrans = 1_000_000, string name = "chnl_fifo_full_test"); super.new(ntrans, name); foreach(agent[i]) begin this.agent[i].init.set_idle_cycles(0); end $display("%s configured objects", this.name); endfunction task run(); $display("%s started testing DUT", this.name); fork: fork_all_run agent[0].run(); agent[1].run(); agent[2].run(); join_none $display("%s: 3 agents running now", this.name); $display("%s: waiting 3 channel fifos to be full", this.name); fork wait(agent[0].vif.ch_margin == 0); wait(agent[1].vif.ch_margin == 0); wait(agent[2].vif.ch_margin == 0); join $display("%s: 3 channel fifos have reached full", this.name); $display("%s: stop 3 agents running", this.name); disable fork_all_run; $display("%s: set and ensure all agents' initiator are idle state", this.name); fork agent[0].init.chnl_idle(); agent[1].init.chnl_idle(); agent[2].init.chnl_idle(); join $display("%s waiting DUT transfering all of data", this.name); fork wait(agent[0].vif.ch_margin == 'h20); wait(agent[1].vif.ch_margin == 'h20); wait(agent[2].vif.ch_margin == 'h20); join $display("%s: 3 channel fifos have transferred all data", this.name); $display("%s finished testing DUT", this.name); endtask endclass: chnl_fifo_full_test
4.3-4.4-4.5
例化3个test;传递接口;调用test
initial begin basic_test = new(); burst_test = new(); fifo_full_test = new(); // USER TODO 4.4 // assign the interface handle to each chnl_initiator objects basic_test.set_interface(chnl0_if, chnl1_if, chnl2_if); burst_test.set_interface(chnl0_if, chnl1_if, chnl2_if); fifo_full_test.set_interface(chnl0_if, chnl1_if, chnl2_if); // USER TODO 4.5 // START TESTs @(posedge rstn); repeat(10) @(posedge clk); basic_test.run(); burst_test.run(); fifo_full_test.run(); $display("*****************all of tests have been finished********************"); $finish(); end
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· .NET Core 中如何实现缓存的预热?
· 三行代码完成国际化适配,妙~啊~
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?