接着上一篇博客,正式开始进行System Verilog验证环境的搭建。依据MCDF的结构图,依次进行MCDF功能模块的验证。代码设计时我们将每一个功能模块里的验证内容都放在一个package中,提高代码的可读性。
- arb_pkg
由于Arbiter模块并没有与外部信号进行交互,其内部信号都已经划分至其余功能模块内,这里暂时先不对此模块进行验证,只会在测试案例中添加一些通道优先级的测试。 - chnl_pkg
channel模块的功能是向三个通道发送数据。
package chnl_pkg;
class chnl_trans;
constraint cstr{
};
//-------------------------------------------------
fuction chnl_trans clone();
endfunction
fuction string sprint();
endfunction
endcalss
class chnl_driver;
local string name;
local virtual chnl_intf intf;
mailbox#(chnl_trans)req_mb;
mailbox#(chnl_trans)rsq_mb;
//-------------------------------------------------
function new(string name = "");
endfunction
fuction viod set_interface(virtual chnl_inft intf)
endfunction
//-------------------------------------------------
task tun();
this.do_driver(();
endtask
class chnl_gennerator;
mailbox#(chnl_trans)req_mb;
mailbox#(chnl_trans)rsq_mb;
constraint cstr{
};
//-------------------------------------------------
function new(string name = "");
endfunction
task start();
repeat(ntrans) send_trans();
class chnl_monitor;
local string name;
local virtual chnl_intf intf;
mailbox#(mon_data_t)mon_mb;
//-------------------------------------------------
function new(string name = "");
endfunction
fuction viod set_interface(virtual chnl_inft intf)
endfunction
//-------------------------------------------------
task tun();
this.mon_trans();
endtask
class chnl_agent;
local string name;
chnl_driver driver;
chnl_monitor monitor;
local virtual chnl_intf intf;
//-------------------------------------------------
function new(string name = "");
endfunction
fuction viod set_interface(virtual chnl_inft intf)
endfunction
//-------------------------------------------------
task tun();
fork
driver.run();
monitor.run();
jion
endtask
endpackage
- fmt_pkg
formater模块的功能是模拟一个与设计相符的buffer。
package fmt_pkg;
class fmt_trans;
class fmt_driver;
class fmt_gennerator;
class fmt_monitor;
class fmt_agent;
endpackage
- reg_pkg
reg模块的功能是向寄存器发送读写数据。
package reg_pkg;
class reg_trans;
class reg_driver;
class reg_gennerator;
class reg_monitor;
class reg_agent;
endpackage
- rpt_pkg
report模块的功能是提供一些打印消息的函数,若使用UVM则无须此模块。 - mcdf_pkg
mcdf模块是验证环境的顶层模块,包括env的搭建与测试案例的编写。
package mcdf_pkg;
class mcdf_refmod;
local string name;
local virtual mcdf_intf intf;
mcdf_reg_t regd[3];
mailbox#(reg_trans)reg_mb;
mailbox#(mon_data_t)in_mb[3];
mailbox#(fmt_trans)out_mb[3];
//-------------------------------------------------
function new(string name = "");
endfunction
fuction viod set_interface(virtual chnl_inft intf)
endfunction
//-------------------------------------------------
task run();
fork
jion
endtask
class mcdf_checker;
local string name;
local virtual chnl_intf intf;
local virtual arb_intf intf;
local virtual mcdf_intf intf;
local mcdf_refmod refmod;
mcdf_reg_t regd[3];
mailbox#(mon_data_t)chnl_mbs[3];
mailbox#(fmt_trans)fmt_mb;
mailbox#(reg_trans)reg_mb;
mailbox#(fmt_trans)exp_mbs[3];
//-------------------------------------------------
function new(string name = "");
this.fmt_mb = new();
this.reg_mb = new();
this.fmt_mb = new();
foreach(this.chnl_mbs[i])this.chnl_mbs[i] = new();
//================================================
foreach(this.refmod.in_mbs[i])
this.chnl_mbs[i] = new();
this.chnl_mbs[i] = new();
this.refmod.reg_mb = this.reg_mb;
endfunction
fuction viod set_interface(virtual mcdf_inft mcdf_vif, virtual chnl_inft intf[3], virtual arb_inft arb_vif)
endfunction
//-------------------------------------------------
task run();
endtask
class mcdf_coverage;
local -----------------;
fuction viod set_interface(virtual mcdf_inft mcdf_vif, virtual chnl_inft intf[3], virtual arb_inft arb_vif, virtual reg_inft reg_vif, virtual fmt_inft fmt_vif)
endfunction
//-------------------------------------------------
covergroup cg_mcdf_reg_write_read;
addr: coverpoint reg_vif.mon_vk.cmd_addr{
}
endgroup
task run();
fork
this.do_reg_sample();
join
endtask
class mcdf_env;
chnl_agent chnl_agts[3];
reg_agent reg_agt;
fmt_agent fmt_agt;
mcdf_checker chker;
mcdf_coverage cvrg;
protected string name;
//-------------------------------------------------
function new(string name = "mcdf_env");
this.name = name;
this.chker = new();
foreach(chnl_agts[i]) begin
this.chnl_agts[i] = new($sformatf("chnl_agts[%0d]",i));
this.chnl_agts[i].monitor.mon_mb = this.chker.chnl_mbs[i];
end
this.reg_agt = new("reg_agt");
this.reg_agt.monitor.mon_mb = this.chker.reg_mb;
this.fmt_agt = new("fmt_agt");
this.fmt_agt.monitor.mon_mb = this.chker.fmt_mb;
this.cvrg = new();
endfunction
virtual function void do_report();
endfunction
//-------------------------------------------------
virtual task run();
this.do_config();
fork
this.chnl_agts[0].run();
this.chnl_agts[1].run();
this.chnl_agts[2].run();
this.reg_agt.run();
this.fmt_agt.run();
this.chker.run();
this.cvrg.run();
join
endtask
class mcdf_tc_base;
chnl_generator chnl_gens[3];
reg_generator reg_gen;
fmt_generator fmt_gen;
mcdf_env env;
protected string name;
//-------------------------------------------------
function new(string name = "mcdf_base_test");
this.name = name;
this.env = new("env");
foreach(this.chnl_gens[i]) begin
this.chnl_gens[i] = new();
this.env.chnl_agts[i].driver.req_mb = this.chnl_gens[i].req_mb;
this.env.chnl_agts[i].driver.rsp_mb = this.chnl_gens[i].rsp_mb;
end
this.reg_gen = new();
this.env.reg_agt.driver.req_mb = this.reg_gen.req_mb;
this.env.reg_agt.driver.rsp_mb = this.reg_gen.rsp_mb;
this.fmt_gen = new();
this.env.fmt_agt.driver.req_mb = this.fmt_gen.req_mb;
this.env.fmt_agt.driver.rsp_mb = this.fmt_gen.rsp_mb;
endfunction
virtual task run();
fork
env.run();
join_none
this.do_reg();
this.do_formatter();
endtask
class mcdf_data_consistence_basic_test extends mcdf_tc_base;
function new(string name = "mcdf_data_consistence_basic_test");
super.new(name);
endfunction
//-------------------------------------------------
task do_reg();
void'(this.diff_value(wr_val, rd_val, "SLV2_WR_REG"));
endtask
task do_formatter();
void'(fmt_gen.randomize() with {fifo == LONG_FIFO; bandwidth == HIGH_WIDTH;});
fmt_gen.start();
endtask
task do_data();
void'(chnl_gens[0].randomize() with {ntrans==100; ch_id==0; data_nidles==0; pkt_nidles==1; data_size==8; });
void'(chnl_gens[1].randomize() with {ntrans==100; ch_id==1; data_nidles==1; pkt_nidles==4; data_size==16;});
void'(chnl_gens[2].randomize() with {ntrans==100; ch_id==2; data_nidles==2; pkt_nidles==8; data_size==32;});
fork
chnl_gens[0].start();
chnl_gens[1].start();
chnl_gens[2].start();
join
#10us; // wait until all data haven been transfered through MCDF
endtask
endpackage
- tb
tb在最顶层的模块,负责例化dut与选择使用的测试案例。
interface chnl_intf(input clk, input rstn);
logic ---------------;
clocking drv_ck@(posedeg clk);
endclocking
clocking mon_ck@(posedeg clk);
endclocking
endinterface
interface reg_intf(input clk, input rstn);
logic ---------------;
clocking drv_ck@(posedeg clk);
endclocking
clocking mon_ck@(posedeg clk);
endclocking
endinterface
interface arb_intf(input clk, input rstn);
logic ---------------;
clocking mon_ck@(posedeg clk);
endclocking
endinterface
interface fmt_intf(input clk, input rstn);
logic ---------------;
clocking drv_ck@(posedeg clk);
endclocking
clocking mon_ck@(posedeg clk);
endclocking
endinterface
interface mcdf_intf(input clk, input rstn);
logic ---------------;
clocking mon_ck@(posedeg clk);
endclocking
endinterface
module top;
initial begin
if($value$plusargs("TESTNAME=%s", name)) begin
tests[name].set_interface(chnl0_if, chnl1_if, chnl2_if, reg_if, arb_if, fmt_if, mcdf_if);
tests[name].run();
end
endmodule
- MCDF 中任意一个功能模块的验证结构如下图所示。这里需要说明的是:将1/2号邮箱的连接放在测试案例中是为了在顶层操作方便,便于设计。
整个mcdf的验证流程如下图: