电力电子转战数字IC20220817day62——uvm入门实验4

目录

实验目标 

存在问题 

 实验任务

1.1移除driver中的mailbox句柄和do_drive()中用mailbox句柄通信的方式,用driver自带的seq_item_port通信;定义对应的uvm_sequencer

1.2将generator中发送trans的任务改为底层sequence。将mcdf_base_test中的idle_reg()和write_reg()和read_reg()提取改为seq

1.3在agent中声明、例化sequencer,并TLM连接到driver

1.4去掉generator在mcdf_base_test中的声明+例化+连接到driver

1.5去掉1.2中已经提取为seq的三个task

1.6实现MCDF顶层的virtual sequencer

1.7连接virtual sequencer和底层sequencer的句柄

1.8将所有发送序列的顺序和组织等内容移植到mcdf_base_virtual_sequence,需要将mcdf_base_test::run_phase()发送序列的功能移植到mcdf_base_virtual_sequence;mcdf_base_test::run_phase()只需要挂载对应的顶层sequence

1.9将原本test中产生和发送trans的任务提取到mcdf_data_consistence_basic_virtual_sequence中


实验目标 

存在问题 

主要是关于sequence和sequencer的,见之前的笔记,没有太多改变。

 实验任务

1.1移除driver中的mailbox句柄和do_drive()中用mailbox句柄通信的方式,用driver自带的seq_item_port通信;定义对应的uvm_sequencer

首先是去掉mailbox的定义

  class chnl_driver extends uvm_driver #(chnl_trans);
    local virtual chnl_intf intf;
   // mailbox #(chnl_trans) req_mb;
   // mailbox #(chnl_trans) rsp_mb;

在do_drive()中将原来用mailbox通信的方式改为PORT通信。通过driver的seq_item_port端口调用get_next_item(req)获取req,由sequence的函数set_sequence_id设置id,所用id为req这个item调用get_sequence_id得到的;最后返回rsp。

    task do_drive();
      chnl_trans req, rsp;
      @(posedge intf.rstn);
      forever begin
//        this.req_mb.get(req);
        this.chnl_write(req);
        void'($cast(rsp, req.clone()));
        rsp.rsp = 1;
//        this.rsp_mb.put(rsp);
      end
    endtask

    task do_drive();
      chnl_trans req, rsp;
      @(posedge intf.rstn);
      forever begin
        //TODO-1.1 Use seq_item_port to get request item
        seq_item_port.get_next_item(req);
        this.chnl_write(req);
        void'($cast(rsp, req.clone()));
        rsp.rsp = 1;
        //TODO-1.1 Use seq_item_port to put response item
        rsp.set_sequence_id(req.get_sequence_id());
        seq_item_port.item_done(rsp);
      end
    endtask

定义sequencer,只需要注册和new函数即可,注意是参数类的要加参数#()

  class chnl_sequencer extends uvm_sequencer #(chnl_trans);
    `uvm_component_utils(chnl_sequencer)
    function new (string name = "chnl_sequencer", uvm_component parent);
      super.new(name, parent);
    endfunction
  endclass: chnl_sequencer

在fmt_pkg和reg_pkg中的操作完全相同。

1.2将generator中发送trans的任务改为底层sequence。将mcdf_base_test中的idle_reg()和write_reg()和read_reg()提取改为seq

改造generator:不需要mailbox;由于变成sequence,start任务变成body()任务;将原来assert with做随机化约束变成`uvm_do_with;将mailbox通信改为seq通信;注意也是个参数类#()

  class chnl_data_sequence extends uvm_sequence #(chnl_trans);
    rand int pkt_id = 0;
    rand int ch_id = -1;
    rand int data_nidles = -1;
    rand int pkt_nidles = -1;
    rand int data_size = -1;
    rand int ntrans = 10;
    `uvm_object_utils_begin(chnl_data_sequence)
      `uvm_field_int(pkt_id, UVM_ALL_ON)
      `uvm_field_int(ch_id, UVM_ALL_ON)
      `uvm_field_int(data_nidles, UVM_ALL_ON)
      `uvm_field_int(pkt_nidles, UVM_ALL_ON)
      `uvm_field_int(data_size, UVM_ALL_ON)
      `uvm_field_int(ntrans, UVM_ALL_ON)
    `uvm_object_utils_end
    `uvm_declare_p_sequencer(chnl_sequencer)
    function new (string name = "chnl_data_sequence");
      super.new(name);
    endfunction

    task body();
      repeat(ntrans) send_trans();
    endtask

    task send_trans();
      chnl_trans req, rsp;
      `uvm_do_with(req, {local::ch_id >= 0 -> ch_id == local::ch_id; 
                         local::pkt_id >= 0 -> pkt_id == local::pkt_id;
                         local::data_nidles >= 0 -> data_nidles == local::data_nidles;
                         local::pkt_nidles >= 0 -> pkt_nidles == local::pkt_nidles;
                         local::data_size >0 -> data.size() == local::data_size; 
                         })
      this.pkt_id++;
      `uvm_info(get_type_name(), req.sprint(), UVM_HIGH)
      get_response(rsp);
      `uvm_info(get_type_name(), rsp.sprint(), UVM_HIGH)
      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, "chnl_data_sequence object content is as below: \n"};
      s = {s, super.sprint()};
      s = {s, "=======================================\n"};
      `uvm_info(get_type_name(), s, UVM_HIGH)
    endfunction
  endclass: chnl_data_sequence

在fmt_pkg和reg_pkg中的操作完全相同。

//原来在mcdf_base_test中的三个虚任务
    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

//被替换成reg_pkg中的三个sequence,分别做约束,注册恶,new函数

  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 

1.3在agent中声明、例化sequencer,并TLM连接到driver

  class chnl_agent extends uvm_agent;
    chnl_driver driver;
    chnl_monitor monitor;
    //声明sequencer
    chnl_sequencer sequencer;
    local virtual chnl_intf vif;

    `uvm_component_utils(chnl_agent)

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

    function void build_phase(uvm_phase phase);
      super.build_phase(phase);
      driver = chnl_driver::type_id::create("driver", this);
      monitor = chnl_monitor::type_id::create("monitor", this);
      //例化sequencer
      sequencer = chnl_sequencer::type_id::create("sequencer", this);
    endfunction

    function void connect_phase(uvm_phase phase);
      super.connect_phase(phase);
      //连接driver和sequencer
      driver.seq_item_port.connect(sequencer.seq_item_export);
    endfunction

    function void set_interface(virtual chnl_intf vif);
      this.vif = vif;
      driver.set_interface(vif);
      monitor.set_interface(vif);
    endfunction
  endclass: chnl_agent

在fmt_pkg和reg_pkg中的操作完全相同。

1.4去掉generator在mcdf_base_test中的声明+例化+连接到driver

1.5去掉1.2中已经提取为seq的三个task

1.6实现MCDF顶层的virtual sequencer

virtual sequencer包含所有底层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

1.7连接virtual sequencer和底层sequencer的句柄

  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;
    //声明
    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);
      //例化
      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);
      //和底层的sequencer连接起来
      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

1.8将所有发送序列的顺序和组织等内容移植到mcdf_base_virtual_sequence,需要将mcdf_base_test::run_phase()发送序列的功能移植到mcdf_base_virtual_sequence;mcdf_base_test::run_phase()只需要挂载对应的顶层sequence

就是对应virtual sequencer的顶层virtual sequence。

  class mcdf_base_virtual_sequence extends uvm_sequence;
//对应virtual sequencer的顶层virtual 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();
    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 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_base_test::run_phase()中只需要运行对应的虚方法

    task run_phase(uvm_phase phase);
      phase.raise_objection(this);
      this.run_top_virtual_sequence();
      phase.drop_objection(this);
    endtask

    virtual task run_top_virtual_sequence();
    endtask

在不同的test中用继承的字方法来自定义所需要的的seq

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


    task run_top_virtual_sequence();
      mcdf_full_random_virtual_sequence top_seq = new();
      top_seq.start(env.virt_sqr);
    endtask

1.9将原本test中产生和发送trans的任务提取到mcdf_data_consistence_basic_virtual_sequence中

  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

原本在test中的处理trans的三个任务早已在1.2中被提取为sequence(idle_reg_seq,write_reg_seq,read_reg_seq )

现在的test只剩下注册,new函数,运行顶层virtual seq的任务了

  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

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值