路科验证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 begin
        seq_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);
      end
    endtask
  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);
    endfunction
  endclass: reg_sequencer

二、底层sequence的提取

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

  //extract chnl_data_sequence from the reg_generator
  class 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);
    endfunction

    task body();
      send_trans();
    endtask

    // generate transaction and put into local mailbox
    task 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);
    endtask

    function 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)
    endfunction
  endclass: 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);
    endfunction
  endclass: 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);
    endfunction
  endclass: 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);
    endfunction
  endclass: read_reg_sequence 
  // register agent
  class reg_agent extends uvm_agent;
    reg_driver driver;
    reg_monitor monitor;
    // declare the sequencer
    reg_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);
    endfunction

    function 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 sequencer
      sequencer = reg_sequencer::type_id::create("sequencer", this);
    endfunction

    function void connect_phase(uvm_phase phase);
      super.connect_phase(phase);
      //connect the driver and the sequencer
      driver.seq_item_port.connect(sequencer.seq_item_export);
    endfunction

    function void set_interface(virtual reg_intf vif);
      this.vif = vif;
      driver.set_interface(vif);
      monitor.set_interface(vif);
    endfunction
  endclass

三、移除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);
    endfunction

    function void build_phase(uvm_phase phase);
      super.build_phase(phase);
      // get virtual interface from top TB
      if(!uvm_config_db#(virtual chnl_intf)::get(this,"","ch0_vif", ch0_vif)) begin
        `uvm_fatal("GETVIF","cannot get vif handle from config DB")
      end
      if(!uvm_config_db#(virtual chnl_intf)::get(this,"","ch1_vif", ch1_vif)) begin
        `uvm_fatal("GETVIF","cannot get vif handle from config DB")
      end
      if(!uvm_config_db#(virtual chnl_intf)::get(this,"","ch2_vif", ch2_vif)) begin
        `uvm_fatal("GETVIF","cannot get vif handle from config DB")
      end
      if(!uvm_config_db#(virtual reg_intf)::get(this,"","reg_vif", reg_vif)) begin
        `uvm_fatal("GETVIF","cannot get vif handle from config DB")
      end
      if(!uvm_config_db#(virtual arb_intf)::get(this,"","arb_vif", arb_vif)) begin
        `uvm_fatal("GETVIF","cannot get vif handle from config DB")
      end
      if(!uvm_config_db#(virtual fmt_intf)::get(this,"","fmt_vif", fmt_vif)) begin
        `uvm_fatal("GETVIF","cannot get vif handle from config DB")
      end
      if(!uvm_config_db#(virtual mcdf_intf)::get(this,"","mcdf_vif", mcdf_vif)) begin
        `uvm_fatal("GETVIF","cannot get vif handle from config DB")
      end

      this.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);
    endfunction

    function void connect_phase(uvm_phase phase);
      super.connect_phase(phase);
      // After get virtual interface from config_db, and then set them to
      // child components
      this.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]) begin
        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.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;
      */
    endfunction

    function 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);
    endfunction

    task run_phase(uvm_phase phase);
      // NOTE:: raise objection to prevent simulation stopping
      phase.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 stopping
      phase.drop_objection(this);
    endtask

    // do register configuration
    virtual task do_reg();
    endtask

    // do external formatter down stream slave configuration
    virtual task do_formatter();
    endtask

    // do data transition from 3 channel slaves
    virtual task do_data();
    endtask

    virtual 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

    virtual 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;
      end
      else begin
        `uvm_info("[CMPSUC]", $sformatf("SUCCESS! %s val1 %8x == val2 %8x", id, val1, val2), UVM_LOW)
        return 1;
      end
    endfunction

    // 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();
    endtask

    virtual 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();
    endtask

    virtual 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
  endclass: 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 stopping
      phase.raise_objection(this);

      this.run_top_virtual_sequence();

      // NOTE:: drop objection to request simulation stopping
      phase.drop_objection(this);
    endtask

    virtual task run_top_virtual_sequence();
      // User to implement this task in the child tests
    endtask
    //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();
    endtask

    virtual 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();
    endtask

    virtual 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);
    endfunction
  endclass
  // MCDF top environment
  class 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 handle
    mcdf_virtual_sequencer virt_sqr;

    `uvm_component_utils(mcdf_env)

    function new (string name = "mcdf_env", uvm_component parent);
      super.new(name, parent);
    endfunction

    function void build_phase(uvm_phase phase);
      super.build_phase(phase);
      this.chker = mcdf_checker::type_id::create("chker", this);
      foreach(chnl_agts[i]) begin
        this.chnl_agts[i] = chnl_agent::type_id::create($sformatf("chnl_agts[%0d]",i), this);
      end
      this.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 sequencer
      virt_sqr = mcdf_virtual_sequencer::type_id::create("virt_sqr", this);
    endfunction

    function 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 agents
      virt_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;
    endfunction
  endclass: 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 clarification
    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);
    endfunction

    function void build_phase(uvm_phase phase);
      super.build_phase(phase);
      // get virtual interface from top TB
      if(!uvm_config_db#(virtual chnl_intf)::get(this,"","ch0_vif", ch0_vif)) begin
        `uvm_fatal("GETVIF","cannot get vif handle from config DB")
      end
      if(!uvm_config_db#(virtual chnl_intf)::get(this,"","ch1_vif", ch1_vif)) begin
        `uvm_fatal("GETVIF","cannot get vif handle from config DB")
      end
      if(!uvm_config_db#(virtual chnl_intf)::get(this,"","ch2_vif", ch2_vif)) begin
        `uvm_fatal("GETVIF","cannot get vif handle from config DB")
      end
      if(!uvm_config_db#(virtual reg_intf)::get(this,"","reg_vif", reg_vif)) begin
        `uvm_fatal("GETVIF","cannot get vif handle from config DB")
      end
      if(!uvm_config_db#(virtual arb_intf)::get(this,"","arb_vif", arb_vif)) begin
        `uvm_fatal("GETVIF","cannot get vif handle from config DB")
      end
      if(!uvm_config_db#(virtual fmt_intf)::get(this,"","fmt_vif", fmt_vif)) begin
        `uvm_fatal("GETVIF","cannot get vif handle from config DB")
      end
      if(!uvm_config_db#(virtual mcdf_intf)::get(this,"","mcdf_vif", mcdf_vif)) begin
        `uvm_fatal("GETVIF","cannot get vif handle from config DB")
      end

      this.env = mcdf_env::type_id::create("env", this);
      // remove the generators' instantiation 
    endfunction

    function void connect_phase(uvm_phase phase);
      super.connect_phase(phase);
      // After get virtual interface from config_db, and then set them to
      // child components
      this.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
    endfunction

    function 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);
    endfunction

    task run_phase(uvm_phase phase);
      // NOTE:: raise objection to prevent simulation stopping
      phase.raise_objection(this);

      this.run_top_virtual_sequence();

      // NOTE:: drop objection to request simulation stopping
      phase.drop_objection(this);
    endtask

    virtual task run_top_virtual_sequence();
      // User to implement this task in the child tests
    endtask

    virtual 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);
    endfunction

    virtual 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 configuration
    virtual task do_reg();
      //User to implment the task in the child virtual sequence
    endtask

    // do external formatter down stream slave configuration
    virtual task do_formatter();
      //User to implment the task in the child virtual sequence
    endtask

    // do data transition from 3 channel slaves
    virtual task do_data();
      //User to implment the task in the child virtual sequence
    endtask

    virtual 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;
      end
      else begin
        `uvm_info("[CMPSUC]", $sformatf("SUCCESS! %s val1 %8x == val2 %8x", id, val1, val2), UVM_LOW)
        return 1;
      end
    endfunction
  endclass

七、重构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);
    endfunction
    task do_reg();
      bit[31:0] wr_val, rd_val;
      // slv0 with len=8,  prio=0, en=1
      wr_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=1
      wr_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=1
      wr_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)
    endtask
    task do_formatter();
      `uvm_do_on_with(fmt_config_seq, p_sequencer.fmt_sqr, {fifo == LONG_FIFO; bandwidth == HIGH_WIDTH;})
    endtask
    task 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 MCDF
    endtask
  endclass: 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);
    endfunction

    task run_top_virtual_sequence();
      mcdf_data_consistence_basic_virtual_sequence top_seq = new();
      top_seq.start(env.virt_sqr);
    endtask
  endclass: mcdf_data_consistence_basic_test

你可能感兴趣的:(硬件工程)