> 文章列表 > 路科验证UVM入门与进阶详解实验4

路科验证UVM入门与进阶详解实验4

路科验证UVM入门与进阶详解实验4

在UVM实验3中,实现了monitor、reference modelchecker之间的通信是通过TLM端口或者TLM FIFO来完成,相较于之前的mailbox句柄连接,更加容易定制,使得组件的独立性提高。

本次实验需要实现的是:

  1. 将产生的transaction并且发送至driver的generator组件,拆分为sequence与sequencer。
  2. 在拆分的基础上,实现底层的sequence。
  3. 完成sequencer与driver的连接和通信工作。
  4. 构建顶层的virtual sequencer。
  5. 将原有的mcdf_base_test拆分为mcdf_base_virtual_sequence与mcdf_base_best,前者发挥产生序列的工作,后者只完成挂载的工作。
  6. 将原有的mcdf_data_consistence_basic_test和mcdf_full_random_test继续拆分为对应的virtual sequence和轻量化的顶层test。

通过实验4,可以将generator、driver与test的关系最终移植为sequence、sequencer、driver和test的关系。

一、driver与sequence的改建

移除原有在各个driver中的mailbox句柄,以及在do_driver()任务中使用mailbox句柄通信方式,转而用uvm_driver::seq_item_port进行通信,同时定义对应的uvm_sequencer

	//移除各个`driver`中的`mailbox`句柄//mailbox #(reg_trans) req_mb;//mailbox #(reg_trans) rsp_mb;task do_drive();reg_trans req, rsp;@(posedge intf.rstn);forever beginseq_item_port.get_next_item(req);this.reg_write(req);void'($cast(rsp, req.clone()));rsp.rsp = 1;rsp.set_sequence_id(req.get_sequence_id());seq_item_port.item_done(rsp);endendtask
  class reg_sequencer extends uvm_sequencer #(reg_trans);`uvm_component_utils(reg_sequencer)function new (string name = "reg_sequencer", uvm_component parent);super.new(name, parent);endfunctionendclass: reg_sequencer

二、底层sequence的提取

将原来在各个generator中发送transaction的任务,提取为各个对应的底层sequence。在各个agent中声明、创建对应的sequencer,并且将其与driver通过TLM port连接起来。

  //extract chnl_data_sequence from the reg_generatorclass reg_base_sequence extends uvm_sequence #(reg_trans);rand bit[7:0] addr = -1;rand bit[1:0] cmd = -1;rand bit[31:0] data = -1;constraint cstr{soft addr == -1;soft cmd == -1;soft data == -1;}`uvm_object_utils_begin(reg_base_sequence)`uvm_field_int(addr, UVM_ALL_ON)`uvm_field_int(cmd, UVM_ALL_ON)`uvm_field_int(data, UVM_ALL_ON)`uvm_object_utils_end`uvm_declare_p_sequencer(reg_sequencer)function new (string name = "reg_base_sequence");super.new(name);endfunctiontask body();send_trans();endtask// generate transaction and put into local mailboxtask send_trans();reg_trans req, rsp;`uvm_do_with(req, {local::addr >= 0 -> addr == local::addr;local::cmd >= 0 -> cmd == local::cmd;local::data >= 0 -> data == local::data;})`uvm_info(get_type_name(), req.sprint(), UVM_HIGH)get_response(rsp);`uvm_info(get_type_name(), rsp.sprint(), UVM_HIGH)if(req.cmd == `READ) this.data = rsp.data;assert(rsp.rsp)else $error("[RSPERR] %0t error response received!", $time);endtaskfunction void post_randomize();string s;s = {s, "AFTER RANDOMIZATION \\n"};s = {s, "=======================================\\n"};s = {s, "reg_base_sequence object content is as below: \\n"};s = {s, super.sprint()};s = {s, "=======================================\\n"};`uvm_info(get_type_name(), s, UVM_HIGH)endfunctionendclass: reg_base_sequence
  class idle_reg_sequence extends reg_base_sequence;constraint cstr{addr == 0;cmd == `IDLE;data == 0;}`uvm_object_utils(idle_reg_sequence)function new (string name = "idle_reg_sequence");super.new(name);endfunctionendclass: idle_reg_sequence
  class write_reg_sequence extends reg_base_sequence;constraint cstr{cmd == `WRITE;}`uvm_object_utils(write_reg_sequence)function new (string name = "write_reg_sequence");super.new(name);endfunctionendclass: write_reg_sequence
  class read_reg_sequence extends reg_base_sequence;constraint cstr{cmd == `READ;}`uvm_object_utils(read_reg_sequence)function new (string name = "read_reg_sequence");super.new(name);endfunctionendclass: read_reg_sequence 
  // register agentclass reg_agent extends uvm_agent;reg_driver driver;reg_monitor monitor;// declare the sequencerreg_sequencer sequencer;local virtual reg_intf vif;`uvm_component_utils(reg_agent)function new(string name = "reg_agent", uvm_component parent);super.new(name, parent);endfunctionfunction void build_phase(uvm_phase phase);super.build_phase(phase);driver = reg_driver::type_id::create("driver", this);monitor = reg_monitor::type_id::create("monitor", this);// instantiate the sequencersequencer = reg_sequencer::type_id::create("sequencer", this);endfunctionfunction void connect_phase(uvm_phase phase);super.connect_phase(phase);//connect the driver and the sequencerdriver.seq_item_port.connect(sequencer.seq_item_export);endfunctionfunction void set_interface(virtual reg_intf vif);this.vif = vif;driver.set_interface(vif);monitor.set_interface(vif);endfunctionendclass

三、移除generator的踪迹

mcdf_base_test中移除generator的声明、创建以及和driver之间的连接。

  class mcdf_base_test extends uvm_test;//remove the generators' handle clarification//chnl_generator chnl_gens[3];//reg_generator reg_gen;//fmt_generator fmt_gen;mcdf_env env;virtual chnl_intf ch0_vif ;virtual chnl_intf ch1_vif ;virtual chnl_intf ch2_vif ;virtual reg_intf reg_vif  ;virtual arb_intf arb_vif  ;virtual fmt_intf fmt_vif  ;virtual mcdf_intf mcdf_vif;`uvm_component_utils(mcdf_base_test)function new(string name = "mcdf_base_test", uvm_component parent);super.new(name, parent);endfunctionfunction void build_phase(uvm_phase phase);super.build_phase(phase);// get virtual interface from top TBif(!uvm_config_db#(virtual chnl_intf)::get(this,"","ch0_vif", ch0_vif)) begin`uvm_fatal("GETVIF","cannot get vif handle from config DB")endif(!uvm_config_db#(virtual chnl_intf)::get(this,"","ch1_vif", ch1_vif)) begin`uvm_fatal("GETVIF","cannot get vif handle from config DB")endif(!uvm_config_db#(virtual chnl_intf)::get(this,"","ch2_vif", ch2_vif)) begin`uvm_fatal("GETVIF","cannot get vif handle from config DB")endif(!uvm_config_db#(virtual reg_intf)::get(this,"","reg_vif", reg_vif)) begin`uvm_fatal("GETVIF","cannot get vif handle from config DB")endif(!uvm_config_db#(virtual arb_intf)::get(this,"","arb_vif", arb_vif)) begin`uvm_fatal("GETVIF","cannot get vif handle from config DB")endif(!uvm_config_db#(virtual fmt_intf)::get(this,"","fmt_vif", fmt_vif)) begin`uvm_fatal("GETVIF","cannot get vif handle from config DB")endif(!uvm_config_db#(virtual mcdf_intf)::get(this,"","mcdf_vif", mcdf_vif)) begin`uvm_fatal("GETVIF","cannot get vif handle from config DB")endthis.env = mcdf_env::type_id::create("env", this);//remove the generators' instantiation //foreach(this.chnl_gens[i]) begin//  this.chnl_gens[i] = chnl_generator::type_id::create($sformatf("chnl_gens[%0d]",i), this);//end//this.reg_gen = reg_generator::type_id::create("reg_gen", this);//this.fmt_gen = fmt_generator::type_id::create("fmt_gen", this);endfunctionfunction void connect_phase(uvm_phase phase);super.connect_phase(phase);// After get virtual interface from config_db, and then set them to// child componentsthis.set_interface(ch0_vif, ch1_vif, ch2_vif, reg_vif, arb_vif, fmt_vif, mcdf_vif);// remove the cross-hierarchy handle connection between drivers//and generators since they are now connected inside the agents by the//TLM ports connection between the sequencer and the driver/*foreach(this.chnl_gens[i]) beginthis.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;endthis.env.reg_agt.driver.req_mb = this.reg_gen.req_mb;this.env.reg_agt.driver.rsp_mb = this.reg_gen.rsp_mb;this.env.fmt_agt.driver.req_mb = this.fmt_gen.req_mb;this.env.fmt_agt.driver.rsp_mb = this.fmt_gen.rsp_mb;*/endfunctionfunction void end_of_elaboration_phase(uvm_phase phase);super.end_of_elaboration_phase(phase);uvm_root::get().set_report_verbosity_level_hier(UVM_HIGH);uvm_root::get().set_report_max_quit_count(1);uvm_root::get().set_timeout(10ms);endfunctiontask run_phase(uvm_phase phase);// NOTE:: raise objection to prevent simulation stoppingphase.raise_objection(this);`uvm_info(get_type_name(), "=====================STARTED=====================", UVM_LOW)this.do_reg();this.do_formatter();this.do_data();`uvm_info(get_type_name(), "=====================FINISHED=====================", UVM_LOW)// NOTE:: drop objection to request simulation stoppingphase.drop_objection(this);endtask// do register configurationvirtual task do_reg();endtask// do external formatter down stream slave configurationvirtual task do_formatter();endtask// do data transition from 3 channel slavesvirtual task do_data();endtaskvirtual function void set_interface(virtual chnl_intf ch0_vif ,virtual chnl_intf ch1_vif ,virtual chnl_intf ch2_vif ,virtual reg_intf reg_vif,virtual arb_intf arb_vif,virtual fmt_intf fmt_vif,virtual mcdf_intf mcdf_vif);this.env.chnl_agts[0].set_interface(ch0_vif);this.env.chnl_agts[1].set_interface(ch1_vif);this.env.chnl_agts[2].set_interface(ch2_vif);this.env.reg_agt.set_interface(reg_vif);this.env.fmt_agt.set_interface(fmt_vif);this.env.chker.set_interface(mcdf_vif, '{ch0_vif, ch1_vif, ch2_vif}, arb_vif);this.env.cvrg.set_interface('{ch0_vif, ch1_vif, ch2_vif}, reg_vif, arb_vif, fmt_vif, mcdf_vif);endfunctionvirtual function bit diff_value(int val1, int val2, string id = "value_compare");if(val1 != val2) begin`uvm_error("[CMPERR]", $sformatf("ERROR! %s val1 %8x != val2 %8x", id, val1, val2)) return 0;endelse begin`uvm_info("[CMPSUC]", $sformatf("SUCCESS! %s val1 %8x == val2 %8x", id, val1, val2), UVM_LOW)return 1;endendfunction// remove the tasks and they are implemented already by register//sequences//  -idle_reg()//  -write_reg()//  -read_reg()virtual task idle_reg();void'(reg_gen.randomize() with {cmd == `IDLE; addr == 0; data == 0;});reg_gen.start();endtaskvirtual task write_reg(bit[7:0] addr, bit[31:0] data);void'(reg_gen.randomize() with {cmd == `WRITE; addr == local::addr; data == local::data;});reg_gen.start();endtaskvirtual task read_reg(bit[7:0] addr, output bit[31:0] data);void'(reg_gen.randomize() with {cmd == `READ; addr == local::addr;});reg_gen.start();data = reg_gen.data;endtaskendclass: mcdf_base_test

四、移除uvm_base_test的transaction发送方法。

将已经被从uvm_base_test移植到reg_pkg中的方法idle_reg()、write_reg()和read_reg()从uvm_base_test中移除。初次uvm_base_test变为了容器的性质,在他内部主要由mcdf_env、mcdf_config配置对象以及被用来挂载的顶层sequence构成。

    task run_phase(uvm_phase phase);// NOTE:: raise objection to prevent simulation stoppingphase.raise_objection(this);this.run_top_virtual_sequence();// NOTE:: drop objection to request simulation stoppingphase.drop_objection(this);endtaskvirtual task run_top_virtual_sequence();// User to implement this task in the child testsendtask
    //remove the tasks and they are implemented already by register//sequences//  -idle_reg()//  -write_reg()//  -read_reg()/*virtual task idle_reg();void'(reg_gen.randomize() with {cmd == `IDLE; addr == 0; data == 0;});reg_gen.start();endtaskvirtual task write_reg(bit[7:0] addr, bit[31:0] data);void'(reg_gen.randomize() with {cmd == `WRITE; addr == local::addr; data == local::data;});reg_gen.start();endtaskvirtual task read_reg(bit[7:0] addr, output bit[31:0] data);void'(reg_gen.randomize() with {cmd == `READ; addr == local::addr;});reg_gen.start();data = reg_gen.data;endtask*/

 五、添加顶层的virtual sequencer

由于MCDF验证环境中存在多个底层的sequencer和sequence,因此这就需要有顶层的virtual sequencer与virtual sequence统一调度。在定义了mcdf_virtual_sequencer之后,在mcdf_env中声明、例化,并且完成其与底层sequencer的句柄连接。

  class mcdf_virtual_sequencer extends uvm_sequencer;reg_sequencer reg_sqr;fmt_sequencer fmt_sqr;chnl_sequencer chnl_sqrs[3];`uvm_component_utils(mcdf_virtual_sequencer)function new (string name = "mcdf_virtual_sequencer", uvm_component parent);super.new(name, parent);endfunctionendclass
  // MCDF top environmentclass mcdf_env extends uvm_env;chnl_agent chnl_agts[3];reg_agent reg_agt;fmt_agent fmt_agt;mcdf_checker chker;mcdf_coverage cvrg;// declare the virtual sequencer handlemcdf_virtual_sequencer virt_sqr;`uvm_component_utils(mcdf_env)function new (string name = "mcdf_env", uvm_component parent);super.new(name, parent);endfunctionfunction void build_phase(uvm_phase phase);super.build_phase(phase);this.chker = mcdf_checker::type_id::create("chker", this);foreach(chnl_agts[i]) beginthis.chnl_agts[i] = chnl_agent::type_id::create($sformatf("chnl_agts[%0d]",i), this);endthis.reg_agt = reg_agent::type_id::create("reg_agt", this);this.fmt_agt = fmt_agent::type_id::create("fmt_agt", this);this.cvrg = mcdf_coverage::type_id::create("cvrg", this);//  instantiate the virtual sequencervirt_sqr = mcdf_virtual_sequencer::type_id::create("virt_sqr", this);endfunctionfunction void connect_phase(uvm_phase phase);super.connect_phase(phase);chnl_agts[0].monitor.mon_bp_port.connect(chker.chnl0_bp_imp);chnl_agts[1].monitor.mon_bp_port.connect(chker.chnl1_bp_imp);chnl_agts[2].monitor.mon_bp_port.connect(chker.chnl2_bp_imp);reg_agt.monitor.mon_bp_port.connect(chker.reg_bp_imp);fmt_agt.monitor.mon_bp_port.connect(chker.fmt_bp_imp);//  connect the sequencer handles of the virtual sequencer to//those dedicated sequencer objects inside the agentsvirt_sqr.reg_sqr = reg_agt.sequencer;virt_sqr.fmt_sqr = fmt_agt.sequencer;foreach(virt_sqr.chnl_sqrs[i]) virt_sqr.chnl_sqrs[i] = chnl_agts[i].sequencer;endfunctionendclass: mcdf_env

 六、重构mcdf_base_test

原有的mcdf_base_test除了承担其容器的功能,还在其run_phase阶段中实现了sequence的分阶段发送功能。在添加了顶层的virtual sequencer之后,需要将所有发送序列的顺序和组织等内容均移植到mcdf_base_virtual_sequence,因此需要将mcdf_base_test::run_phase()发送序列的功能移植到定义的mcdf_base_virtual_sequence一侧,而在移植后,mcdf_base_test::run_phase()只需要挂载对应的顶层virtual sequence即可。

  // MCDF base test 容器作用class mcdf_base_test extends uvm_test;// remove the generators' handle clarificationmcdf_env env;virtual chnl_intf ch0_vif ;virtual chnl_intf ch1_vif ;virtual chnl_intf ch2_vif ;virtual reg_intf reg_vif  ;virtual arb_intf arb_vif  ;virtual fmt_intf fmt_vif  ;virtual mcdf_intf mcdf_vif;`uvm_component_utils(mcdf_base_test)function new(string name = "mcdf_base_test", uvm_component parent);super.new(name, parent);endfunctionfunction void build_phase(uvm_phase phase);super.build_phase(phase);// get virtual interface from top TBif(!uvm_config_db#(virtual chnl_intf)::get(this,"","ch0_vif", ch0_vif)) begin`uvm_fatal("GETVIF","cannot get vif handle from config DB")endif(!uvm_config_db#(virtual chnl_intf)::get(this,"","ch1_vif", ch1_vif)) begin`uvm_fatal("GETVIF","cannot get vif handle from config DB")endif(!uvm_config_db#(virtual chnl_intf)::get(this,"","ch2_vif", ch2_vif)) begin`uvm_fatal("GETVIF","cannot get vif handle from config DB")endif(!uvm_config_db#(virtual reg_intf)::get(this,"","reg_vif", reg_vif)) begin`uvm_fatal("GETVIF","cannot get vif handle from config DB")endif(!uvm_config_db#(virtual arb_intf)::get(this,"","arb_vif", arb_vif)) begin`uvm_fatal("GETVIF","cannot get vif handle from config DB")endif(!uvm_config_db#(virtual fmt_intf)::get(this,"","fmt_vif", fmt_vif)) begin`uvm_fatal("GETVIF","cannot get vif handle from config DB")endif(!uvm_config_db#(virtual mcdf_intf)::get(this,"","mcdf_vif", mcdf_vif)) begin`uvm_fatal("GETVIF","cannot get vif handle from config DB")endthis.env = mcdf_env::type_id::create("env", this);// remove the generators' instantiation endfunctionfunction void connect_phase(uvm_phase phase);super.connect_phase(phase);// After get virtual interface from config_db, and then set them to// child componentsthis.set_interface(ch0_vif, ch1_vif, ch2_vif, reg_vif, arb_vif, fmt_vif, mcdf_vif);// remove the cross-hierarchy handle connection between drivers//and generators since they are now connected inside the agents by the//TLM ports connection between the sequencer and the driverendfunctionfunction void end_of_elaboration_phase(uvm_phase phase);super.end_of_elaboration_phase(phase);uvm_root::get().set_report_verbosity_level_hier(UVM_HIGH);uvm_root::get().set_report_max_quit_count(1);uvm_root::get().set_timeout(10ms);endfunctiontask run_phase(uvm_phase phase);// NOTE:: raise objection to prevent simulation stoppingphase.raise_objection(this);this.run_top_virtual_sequence();// NOTE:: drop objection to request simulation stoppingphase.drop_objection(this);endtaskvirtual task run_top_virtual_sequence();// User to implement this task in the child testsendtaskvirtual function void set_interface(virtual chnl_intf ch0_vif ,virtual chnl_intf ch1_vif ,virtual chnl_intf ch2_vif ,virtual reg_intf reg_vif,virtual arb_intf arb_vif,virtual fmt_intf fmt_vif,virtual mcdf_intf mcdf_vif);this.env.chnl_agts[0].set_interface(ch0_vif);this.env.chnl_agts[1].set_interface(ch1_vif);this.env.chnl_agts[2].set_interface(ch2_vif);this.env.reg_agt.set_interface(reg_vif);this.env.fmt_agt.set_interface(fmt_vif);this.env.chker.set_interface(mcdf_vif, '{ch0_vif, ch1_vif, ch2_vif}, arb_vif);this.env.cvrg.set_interface('{ch0_vif, ch1_vif, ch2_vif}, reg_vif, arb_vif, fmt_vif, mcdf_vif);endfunction// remove the tasks and they are implemented already by register//sequences//  -idle_reg()//  -write_reg()//  -read_reg()endclass: mcdf_base_test
  class mcdf_base_virtual_sequence extends uvm_sequence;idle_reg_sequence idle_reg_seq;write_reg_sequence write_reg_seq;read_reg_sequence read_reg_seq;chnl_data_sequence chnl_data_seq;fmt_config_sequence fmt_config_seq;`uvm_object_utils(mcdf_base_virtual_sequence)`uvm_declare_p_sequencer(mcdf_virtual_sequencer)function new (string name = "mcdf_base_virtual_sequence");super.new(name);endfunctionvirtual task body();`uvm_info(get_type_name(), "=====================STARTED=====================", UVM_LOW)this.do_reg();this.do_formatter();this.do_data();`uvm_info(get_type_name(), "=====================FINISHED=====================", UVM_LOW)endtask// do register configurationvirtual task do_reg();//User to implment the task in the child virtual sequenceendtask// do external formatter down stream slave configurationvirtual task do_formatter();//User to implment the task in the child virtual sequenceendtask// do data transition from 3 channel slavesvirtual task do_data();//User to implment the task in the child virtual sequenceendtaskvirtual function bit diff_value(int val1, int val2, string id = "value_compare");if(val1 != val2) begin`uvm_error("[CMPERR]", $sformatf("ERROR! %s val1 %8x != val2 %8x", id, val1, val2)) return 0;endelse begin`uvm_info("[CMPSUC]", $sformatf("SUCCESS! %s val1 %8x == val2 %8x", id, val1, val2), UVM_LOW)return 1;endendfunctionendclass

七、重构mcdf_data_consistence_basic_test

将其产生和发送transaction的任务,都移植到mcdf_data_consistence_basic_virtual_sequence,而进一步减轻mcdf_data_consistence_basic_test的代码量。测试的动态场景往往都是由virtual sequence统一组织的,而test层往往之后做run_phase前的一些验证环境的配置。

  class mcdf_data_consistence_basic_virtual_sequence extends mcdf_base_virtual_sequence;`uvm_object_utils(mcdf_data_consistence_basic_virtual_sequence)function new (string name = "mcdf_data_consistence_basic_virtual_sequence");super.new(name);endfunctiontask do_reg();bit[31:0] wr_val, rd_val;// slv0 with len=8,  prio=0, en=1wr_val = (1<<3)+(0<<1)+1;`uvm_do_on_with(write_reg_seq, p_sequencer.reg_sqr, {addr == `SLV0_RW_ADDR; data == wr_val;})`uvm_do_on_with(read_reg_seq, p_sequencer.reg_sqr, {addr == `SLV0_RW_ADDR;})rd_val = read_reg_seq.data;void'(this.diff_value(wr_val, rd_val, "SLV0_WR_REG"));// slv1 with len=16, prio=1, en=1wr_val = (2<<3)+(1<<1)+1;`uvm_do_on_with(write_reg_seq, p_sequencer.reg_sqr, {addr == `SLV1_RW_ADDR; data == wr_val;})`uvm_do_on_with(read_reg_seq, p_sequencer.reg_sqr, {addr == `SLV1_RW_ADDR;})rd_val = read_reg_seq.data;void'(this.diff_value(wr_val, rd_val, "SLV1_WR_REG"));// slv2 with len=32, prio=2, en=1wr_val = (3<<3)+(2<<1)+1;`uvm_do_on_with(write_reg_seq, p_sequencer.reg_sqr, {addr == `SLV2_RW_ADDR; data == wr_val;})`uvm_do_on_with(read_reg_seq, p_sequencer.reg_sqr, {addr == `SLV2_RW_ADDR;})rd_val = read_reg_seq.data;void'(this.diff_value(wr_val, rd_val, "SLV2_WR_REG"));// send IDLE command`uvm_do_on(idle_reg_seq, p_sequencer.reg_sqr)endtasktask do_formatter();`uvm_do_on_with(fmt_config_seq, p_sequencer.fmt_sqr, {fifo == LONG_FIFO; bandwidth == HIGH_WIDTH;})endtasktask do_data();fork`uvm_do_on_with(chnl_data_seq, p_sequencer.chnl_sqrs[0], {ntrans==100; ch_id==0; data_nidles==0; pkt_nidles==1; data_size==8; })`uvm_do_on_with(chnl_data_seq, p_sequencer.chnl_sqrs[1], {ntrans==100; ch_id==1; data_nidles==1; pkt_nidles==4; data_size==16;})`uvm_do_on_with(chnl_data_seq, p_sequencer.chnl_sqrs[2], {ntrans==100; ch_id==2; data_nidles==2; pkt_nidles==8; data_size==32;})join#10us; // wait until all data haven been transfered through MCDFendtaskendclass: mcdf_data_consistence_basic_virtual_sequence
  class mcdf_data_consistence_basic_test extends mcdf_base_test;`uvm_component_utils(mcdf_data_consistence_basic_test)function new(string name = "mcdf_data_consistence_basic_test", uvm_component parent);super.new(name, parent);endfunctiontask run_top_virtual_sequence();mcdf_data_consistence_basic_virtual_sequence top_seq = new();top_seq.start(env.virt_sqr);endtaskendclass: mcdf_data_consistence_basic_test