ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

日常记录(46)寄存器模型、工厂、回调

2022-01-23 19:01:48  阅读:288  来源: 互联网

标签:name 46 value uvm 寄存器 phase new reg 日常


寄存器模型

前门访问

通过协议进行数据正规访问

定义seq

class reg_access_sequence extends uvm_sequence#(bus_transaction);
   string tID = get_type_name();

   bit[15:0] addr;
   bit[15:0] rdata;
   bit[15:0] wdata;
   bit       is_wr;

   `uvm_object_utils(reg_access_sequence)
   function new(string name = "reg_access_sequence");
      super.new(name);
   endfunction

   virtual task body();
      bus_transaction tr;
      tr = new("tr");
      tr.addr = this.addr;
      tr.wr_data = this.wdata;
      tr.bus_op = (is_wr ? BUS_WR : BUS_RD);
      `uvm_info(tID, $sformatf("begin to access register: is_wr = %0d, addr = %0h", is_wr, addr), UVM_MEDIUM)
      `uvm_send(tr)
      `uvm_info(tID, "successfull access register", UVM_MEDIUM)
      this.rdata = tr.rd_data;
   endtask
endclass

在寄存器模型

main_phase中进行数据获取

class my_model extends uvm_component;
   
   uvm_blocking_get_port #(my_transaction)  port;
   uvm_analysis_port #(my_transaction)  ap;

   bus_sequencer p_sqr;
   extern function new(string name, uvm_component parent);
   extern function void build_phase(uvm_phase phase);
   extern virtual  task main_phase(uvm_phase phase);
   extern virtual  function void invert_tr(my_transaction tr);

   `uvm_component_utils(my_model)
endclass 

function my_model::new(string name, uvm_component parent);
   super.new(name, parent);
endfunction 

function void my_model::build_phase(uvm_phase phase);
   super.build_phase(phase);
   port = new("port", this);
   ap = new("ap", this);
endfunction

function void my_model::invert_tr(my_transaction tr);
    tr.dmac = tr.dmac ^ 48'hFFFF_FFFF_FFFF;
    tr.smac = tr.smac ^ 48'hFFFF_FFFF_FFFF;
    tr.ether_type = tr.ether_type ^ 16'hFFFF;
    tr.crc = tr.crc ^ 32'hFFFF_FFFF;
    for(int i = 0; i < tr.pload.size; i++)
      tr.pload[i] = tr.pload[i] ^ 8'hFF;
endfunction

task my_model::main_phase(uvm_phase phase);
   my_transaction tr;
   my_transaction new_tr;
   reg_access_sequence reg_seq;
   super.main_phase(phase);
   reg_seq = new("reg_seq");
   reg_seq.addr = 16'h9;
   reg_seq.is_wr = 0;
   reg_seq.start(p_sqr);
   while(1) begin
      port.get(tr);
      new_tr = new("new_tr");
      new_tr.copy(tr);
      //`uvm_info("my_model", "get one transaction, copy and print it:", UVM_LOW)
      //new_tr.print();
      if(reg_seq.rdata)
         invert_tr(new_tr);
      ap.write(new_tr);
   end
endtask

后门手动数据访问

使用interface

interface backdoor_if(input clk, input rst_n);

   function void poke_counter(input bit[31:0] value);
      top_tb.my_dut.counter = value;
   endfunction

   function void peek_counter(output bit[31:0] value);
      value = top_tb.my_dut.counter;
   endfunction
endinterface

poke预置数据

在my_case0中声明并调用

class my_case0 extends base_test;

   virtual backdoor_if vif;
   function new(string name = "my_case0", uvm_component parent = null);
      super.new(name,parent);
   endfunction 
   extern virtual function void build_phase(uvm_phase phase); 
   extern virtual task configure_phase(uvm_phase phase); 
   `uvm_component_utils(my_case0)
endclass

function void my_case0::build_phase(uvm_phase phase);
   super.build_phase(phase);

   uvm_config_db#(uvm_object_wrapper)::set(this, 
                                           "v_sqr.main_phase", 
                                           "default_sequence", 
                                           case0_vseq::type_id::get());
   void'(uvm_config_db#(virtual backdoor_if)::get(this, "", "vif", vif));
endfunction

task my_case0::configure_phase(uvm_phase phase);
   phase.raise_objection(this);
   @(posedge vif.rst_n);
   vif.poke_counter(32'hFFFD);
   phase.drop_objection(this);
endtask

  

后门接口数据访问

定义好reg_block(寄存器模型)

其中包括了三个寄存器模型,然后分别定义了他们的地址和配置等。

class reg_invert extends uvm_reg;

    rand uvm_reg_field reg_data;

    virtual function void build();
        reg_data = uvm_reg_field::type_id::create("reg_data");
        // parameter: parent, size, lsb_pos, access, volatile, reset value, has_reset, is_rand, individually accessible
        reg_data.configure(this, 1, 0, "RW", 1, 0, 1, 1, 0);
    endfunction

    `uvm_object_utils(reg_invert)

    function new(input string name="reg_invert");
        //parameter: name, size, has_coverage
        super.new(name, 16, UVM_NO_COVERAGE);
    endfunction
endclass

class reg_counter_low extends uvm_reg;

    rand uvm_reg_field reg_data;

    virtual function void build();
        reg_data = uvm_reg_field::type_id::create("reg_data");
        // parameter: parent, size, lsb_pos, access, volatile, reset value, has_reset, is_rand, individually accessible
        reg_data.configure(this, 16, 0, "W1C", 1, 0, 1, 1, 0);
    endfunction

    `uvm_object_utils(reg_counter_low)

    function new(input string name="reg_counter_low");
        //parameter: name, size, has_coverage
        super.new(name, 16, UVM_NO_COVERAGE);
    endfunction
endclass

class reg_counter_high extends uvm_reg;

    rand uvm_reg_field reg_data;

    virtual function void build();
        reg_data = uvm_reg_field::type_id::create("reg_data");
        // parameter: parent, size, lsb_pos, access, volatile, reset value, has_reset, is_rand, individually accessible
        reg_data.configure(this, 16, 0, "W1C", 1, 0, 1, 1, 0);
    endfunction

    `uvm_object_utils(reg_counter_high)

    function new(input string name="reg_counter_high");
        //parameter: name, size, has_coverage
        super.new(name, 16, UVM_NO_COVERAGE);
    endfunction
endclass

class reg_model extends uvm_reg_block;
   rand reg_invert invert;
   rand reg_counter_high counter_high;
   rand reg_counter_low counter_low;

   virtual function void build();
      default_map = create_map("default_map", 0, 2, UVM_BIG_ENDIAN, 0);

      invert = reg_invert::type_id::create("invert", , get_full_name());
      invert.configure(this, null, "invert");
      invert.build();
      default_map.add_reg(invert, 'h9, "RW");
      counter_high = reg_counter_high::type_id::create("counter_high", , get_full_name());
      counter_high.configure(this, null, "counter[31:16]");
      counter_high.build();
      default_map.add_reg(counter_high, 'h5, "RW");
      counter_low = reg_counter_low::type_id::create("counter_low", , get_full_name());
      counter_low.configure(this, null, "counter[15:0]");
      counter_low.build();
      default_map.add_reg(counter_low, 'h6, "RW");
   endfunction

   `uvm_object_utils(reg_model)

    function new(input string name="reg_model");
        super.new(name, UVM_NO_COVERAGE);
    endfunction 

endclass

my_vsqr

class my_vsqr extends uvm_sequencer;
  
   my_sequencer  p_my_sqr;
   bus_sequencer p_bus_sqr;
   reg_model     p_rm;

   function new(string name, uvm_component parent);
      super.new(name, parent);
   endfunction 
   
   `uvm_component_utils(my_vsqr)
endclass 

然后在seq中(my_case0)

使用p_sequencer的方式调用内部uvm的peek和poke

class case0_cfg_vseq extends uvm_sequence;

   `uvm_object_utils(case0_cfg_vseq)
   `uvm_declare_p_sequencer(my_vsqr)
   
   function  new(string name= "case0_cfg_vseq");
      super.new(name);
   endfunction 
   
   virtual task body();
      uvm_status_e   status;
      uvm_reg_data_t value;
      bit[31:0] counter;
      if(starting_phase != null) 
         starting_phase.raise_objection(this);
      p_sequencer.p_rm.invert.read(status, value, UVM_FRONTDOOR);
      `uvm_info("case0_cfg_vseq", $sformatf("invert's initial value is %0h", value), UVM_LOW)
      p_sequencer.p_rm.invert.write(status, 1, UVM_FRONTDOOR);
      p_sequencer.p_rm.invert.read(status, value, UVM_FRONTDOOR);
      `uvm_info("case0_cfg_vseq", $sformatf("after set, invert's value is %0h", value), UVM_LOW)
      p_sequencer.p_rm.counter_low.read(status, value, UVM_FRONTDOOR);
      counter[15:0] = value[15:0];
      p_sequencer.p_rm.counter_high.read(status, value, UVM_FRONTDOOR);
      counter[31:16] = value[15:0];
      `uvm_info("case0_cfg_vseq", $sformatf("counter's initial value(FRONTDOOR) is %0h", counter), UVM_LOW)
      p_sequencer.p_rm.counter_low.poke(status, 16'hFFFD);
      p_sequencer.p_rm.counter_low.read(status, value, UVM_FRONTDOOR);
      counter[15:0] = value[15:0];
      p_sequencer.p_rm.counter_high.read(status, value, UVM_FRONTDOOR);
      counter[31:16] = value[15:0];
      `uvm_info("case0_cfg_vseq", $sformatf("after poke, counter's value(FRONTDOOR) is %0h", counter), UVM_LOW)
      p_sequencer.p_rm.counter_low.peek(status, value);
      counter[15:0] = value[15:0];
      p_sequencer.p_rm.counter_high.peek(status, value);
      counter[31:16] = value[15:0];
      `uvm_info("case0_cfg_vseq", $sformatf("after poke, counter's value(BACKDOOR) is %0h", counter), UVM_LOW)
      if(starting_phase != null) 
         starting_phase.drop_objection(this);
   endtask

endclass

  

层次化的寄存器模型

可能较为通用,首先底层是reg,中层是结合不同reg的blk,上层是综合的blk

class reg_invert extends uvm_reg;

    rand uvm_reg_field reg_data;

    virtual function void build();
        reg_data = uvm_reg_field::type_id::create("reg_data");
        // parameter: parent, size, lsb_pos, access, volatile, reset value, has_reset, is_rand, individually accessible
        reg_data.configure(this, 1, 0, "RW", 1, 0, 1, 1, 0);
    endfunction

    `uvm_object_utils(reg_invert)

    function new(input string name="reg_invert");
        //parameter: name, size, has_coverage
        super.new(name, 16, UVM_NO_COVERAGE);
    endfunction
endclass

class reg_depth extends uvm_reg;

    rand uvm_reg_field reg_data;

    virtual function void build();
        reg_data = uvm_reg_field::type_id::create("reg_data");
        // parameter: parent, size, lsb_pos, access, volatile, reset value, has_reset, is_rand, individually accessible
        reg_data.configure(this, 16, 0, "RW", 1, 0, 1, 1, 0);
    endfunction

    `uvm_object_utils(reg_depth)

    function new(input string name="reg_depth");
        //parameter: name, size, has_coverage
        super.new(name, 16, UVM_NO_COVERAGE);
    endfunction
endclass

class reg_vlan extends uvm_reg;

    rand uvm_reg_field reg_data;

    virtual function void build();
        reg_data = uvm_reg_field::type_id::create("reg_data");
        // parameter: parent, size, lsb_pos, access, volatile, reset value, has_reset, is_rand, individually accessible
        reg_data.configure(this, 10, 0, "RW", 1, 0, 1, 1, 0);
    endfunction

    `uvm_object_utils(reg_vlan)

    function new(input string name="reg_vlan");
        //parameter: name, size, has_coverage
        super.new(name, 16, UVM_NO_COVERAGE);
    endfunction
endclass

class global_blk extends uvm_reg_block;
   rand reg_invert invert;
   
   virtual function void build();
      default_map = create_map("default_map", 0, 2, UVM_BIG_ENDIAN, 0);

      invert = reg_invert::type_id::create("invert", , get_full_name());
      invert.configure(this, null, "");
      invert.build();
      default_map.add_reg(invert, 'h9, "RW");
   endfunction

    `uvm_object_utils(global_blk)

    function new(input string name="global_blk");
        super.new(name, UVM_NO_COVERAGE);
    endfunction 
   
endclass

class buf_blk extends uvm_reg_block;
   rand reg_depth depth;
   
   virtual function void build();
      default_map = create_map("default_map", 0, 2, UVM_BIG_ENDIAN, 0);

      depth = reg_depth::type_id::create("depth", , get_full_name());
      depth.configure(this, null, "");
      depth.build();
      default_map.add_reg(depth, 'h3, "RW");
   endfunction

    `uvm_object_utils(buf_blk)

    function new(input string name="buf_blk");
        super.new(name, UVM_NO_COVERAGE);
    endfunction 
   
endclass

class mac_blk extends uvm_reg_block;
   rand reg_vlan vlan;
   
   virtual function void build();
      default_map = create_map("default_map", 0, 2, UVM_BIG_ENDIAN, 0);

      vlan = reg_vlan::type_id::create("vlan", , get_full_name());
      vlan.configure(this, null, "");
      vlan.build();
      default_map.add_reg(vlan, 'h40, "RW");
   endfunction

    `uvm_object_utils(mac_blk)

    function new(input string name="mac_blk");
        super.new(name, UVM_NO_COVERAGE);
    endfunction 
   
endclass

class reg_model extends uvm_reg_block;

   rand global_blk gb_ins;
   rand buf_blk    bb_ins;
   rand mac_blk    mb_ins;

   virtual function void build();
      default_map = create_map("default_map", 0, 2, UVM_BIG_ENDIAN, 0);
      gb_ins = global_blk::type_id::create("gb_ins");
      gb_ins.configure(this, "");
      gb_ins.build();
      gb_ins.lock_model();
      default_map.add_submap(gb_ins.default_map, 16'h0);

      bb_ins = buf_blk::type_id::create("bb_ins");
      bb_ins.configure(this, "");
      bb_ins.build();
      bb_ins.lock_model();
      default_map.add_submap(bb_ins.default_map, 16'h1000);

      mb_ins = mac_blk::type_id::create("mb_ins");
      mb_ins.configure(this, "");
      mb_ins.build();
      mb_ins.lock_model();
      default_map.add_submap(mb_ins.default_map, 16'h2000);

   endfunction

   `uvm_object_utils(reg_model)

    function new(input string name="reg_model");
        super.new(name, UVM_NO_COVERAGE);
    endfunction 

endclass

reg_file

管理blk。

reg_invert、reg_depth、reg_vlan、reg_regA、reg_regB是寄存器,

regfile是寄存器文件,global_blk包括reg_invert,buf_blk包括reg_depth,mac_blk包括两个regfile,

reg_regA,reg_regB,reg_vlan,并将regA和regB的configure过程使用对应的file取代

class reg_invert extends uvm_reg;

    rand uvm_reg_field reg_data;

    virtual function void build();
        reg_data = uvm_reg_field::type_id::create("reg_data");
        // parameter: parent, size, lsb_pos, access, volatile, reset value, has_reset, is_rand, individually accessible
        reg_data.configure(this, 1, 0, "RW", 1, 0, 1, 1, 0);
    endfunction

    `uvm_object_utils(reg_invert)

    function new(input string name="reg_invert");
        //parameter: name, size, has_coverage
        super.new(name, 16, UVM_NO_COVERAGE);
    endfunction
endclass

class reg_depth extends uvm_reg;

    rand uvm_reg_field reg_data;

    virtual function void build();
        reg_data = uvm_reg_field::type_id::create("reg_data");
        // parameter: parent, size, lsb_pos, access, volatile, reset value, has_reset, is_rand, individually accessible
        reg_data.configure(this, 16, 0, "RW", 1, 0, 1, 1, 0);
    endfunction

    `uvm_object_utils(reg_depth)

    function new(input string name="reg_depth");
        //parameter: name, size, has_coverage
        super.new(name, 16, UVM_NO_COVERAGE);
    endfunction
endclass

class reg_vlan extends uvm_reg;

    rand uvm_reg_field reg_data;

    virtual function void build();
        reg_data = uvm_reg_field::type_id::create("reg_data");
        // parameter: parent, size, lsb_pos, access, volatile, reset value, has_reset, is_rand, individually accessible
        reg_data.configure(this, 10, 0, "RW", 1, 0, 1, 1, 0);
    endfunction

    `uvm_object_utils(reg_vlan)

    function new(input string name="reg_vlan");
        //parameter: name, size, has_coverage
        super.new(name, 16, UVM_NO_COVERAGE);
    endfunction
endclass

class reg_regA extends uvm_reg;

    rand uvm_reg_field reg_data;

    virtual function void build();
        reg_data = uvm_reg_field::type_id::create("reg_data");
        // parameter: parent, size, lsb_pos, access, volatile, reset value, has_reset, is_rand, individually accessible
        reg_data.configure(this, 10, 0, "RW", 1, 0, 1, 1, 0);
    endfunction

    `uvm_object_utils(reg_regA)

    function new(input string name="reg_regA");
        //parameter: name, size, has_coverage
        super.new(name, 16, UVM_NO_COVERAGE);
    endfunction
endclass

class reg_regB extends uvm_reg;

    rand uvm_reg_field reg_data;

    virtual function void build();
        reg_data = uvm_reg_field::type_id::create("reg_data");
        // parameter: parent, size, lsb_pos, access, volatile, reset value, has_reset, is_rand, individually accessible
        reg_data.configure(this, 10, 0, "RW", 1, 0, 1, 1, 0);
    endfunction

    `uvm_object_utils(reg_regB)

    function new(input string name="reg_regB");
        //parameter: name, size, has_coverage
        super.new(name, 16, UVM_NO_COVERAGE);
    endfunction
endclass

class regfile extends uvm_reg_file;
   function new(string name = "regfile");
      super.new(name);
   endfunction

   `uvm_object_utils(regfile)
endclass

class global_blk extends uvm_reg_block;
   rand reg_invert invert;
   
   virtual function void build();
      default_map = create_map("default_map", 0, 2, UVM_BIG_ENDIAN, 0);

      invert = reg_invert::type_id::create("invert", , get_full_name());
      invert.configure(this, null, "invert");
      invert.build();
      default_map.add_reg(invert, 'h9, "RW");
   endfunction

    `uvm_object_utils(global_blk)

    function new(input string name="global_blk");
        super.new(name, UVM_NO_COVERAGE);
    endfunction 
   
endclass

class buf_blk extends uvm_reg_block;
   rand reg_depth depth;
   
   virtual function void build();
      default_map = create_map("default_map", 0, 2, UVM_BIG_ENDIAN, 0);

      depth = reg_depth::type_id::create("depth", , get_full_name());
      depth.configure(this, null, "depth");
      depth.build();
      default_map.add_reg(depth, 'h3, "RW");
   endfunction

    `uvm_object_utils(buf_blk)

    function new(input string name="buf_blk");
        super.new(name, UVM_NO_COVERAGE);
    endfunction 
   
endclass

class mac_blk extends uvm_reg_block;

   rand regfile file_a;
   rand regfile file_b;
   rand reg_regA regA;
   rand reg_regB regB;
   rand reg_vlan vlan;
   
   virtual function void build();
      default_map = create_map("default_map", 0, 2, UVM_BIG_ENDIAN, 0);

      file_a = regfile::type_id::create("file_a", , get_full_name());
      file_a.configure(this, null, "fileA");
      file_b = regfile::type_id::create("file_b", , get_full_name());
      file_b.configure(this, null, "fileB");
      
      regA = reg_regA::type_id::create("regA", , get_full_name());
      regA.configure(this, file_a, "regA");
      regA.build();
      default_map.add_reg(regA, 'h31, "RW");
      
      regB = reg_regB::type_id::create("regB", , get_full_name());
      regB.configure(this, file_b, "regB");
      regB.build();
      default_map.add_reg(regB, 'h32, "RW");
      
      vlan = reg_vlan::type_id::create("vlan", , get_full_name());
      vlan.configure(this, null, "vlan");
      vlan.build();
      default_map.add_reg(vlan, 'h40, "RW");
   endfunction

    `uvm_object_utils(mac_blk)

    function new(input string name="mac_blk");
        super.new(name, UVM_NO_COVERAGE);
    endfunction 
   
endclass

class reg_model extends uvm_reg_block;

   rand global_blk gb_ins;
   rand buf_blk    bb_ins;
   rand mac_blk    mb_ins;

   virtual function void build();
      default_map = create_map("default_map", 0, 2, UVM_BIG_ENDIAN, 0);
      gb_ins = global_blk::type_id::create("gb_ins");
      gb_ins.configure(this, "global_reg");
      gb_ins.build();
      gb_ins.lock_model();
      default_map.add_submap(gb_ins.default_map, 16'h0);

      bb_ins = buf_blk::type_id::create("bb_ins");
      bb_ins.configure(this, "buf_reg");
      bb_ins.build();
      bb_ins.lock_model();
      default_map.add_submap(bb_ins.default_map, 16'h1000);

      mb_ins = mac_blk::type_id::create("mb_ins");
      mb_ins.configure(this, "mac_reg");
      mb_ins.build();
      mb_ins.lock_model();
      default_map.add_submap(mb_ins.default_map, 16'h2000);

   endfunction

   `uvm_object_utils(reg_model)

    function new(input string name="reg_model");
        super.new(name, UVM_NO_COVERAGE);
    endfunction 

endclass

寄存器的不同域

在reg_model中,定义一个reg,其中3个field。

class three_field_reg extends uvm_reg;
    rand uvm_reg_field fieldA;
    rand uvm_reg_field fieldB;
    rand uvm_reg_field fieldC;

    virtual function void build();
        fieldA = uvm_reg_field::type_id::create("fieldA");
        fieldB = uvm_reg_field::type_id::create("fieldB");
        fieldC = uvm_reg_field::type_id::create("fieldC");
    endfunction
    
   `uvm_object_utils(three_field_reg)

    function new(input string name="three_field_reg");
        //parameter: name, size, has_coverage
        super.new(name, 16, UVM_NO_COVERAGE);
    endfunction
endclass

使用blk括起来,tf_reg,注意修改了基地址位和偏移位。

add_hdl_path_slice设置相对路径

class mac_blk extends uvm_reg_block;

   rand reg_vlan vlan;
   rand three_field_reg tf_reg;
   
   virtual function void build();
      default_map = create_map("default_map", 0, 2, UVM_BIG_ENDIAN, 0);

      vlan = reg_vlan::type_id::create("vlan", , get_full_name());
      vlan.configure(this, null, "vlan");
      vlan.build();
      default_map.add_reg(vlan, 'h40, "RW");
      
      tf_reg = three_field_reg::type_id::create("tf_reg", , get_full_name());
      tf_reg.configure(this, null, "");
      tf_reg.build();
      tf_reg.fieldA.configure(tf_reg, 2, 0, "RW", 1, 0, 1, 1, 1);
      tf_reg.add_hdl_path_slice("fieldA", 0, 2);
      tf_reg.fieldB.configure(tf_reg, 3, 2, "RW", 1, 0, 1, 1, 1);
      tf_reg.add_hdl_path_slice("fieldA", 2, 3);
      tf_reg.fieldC.configure(tf_reg, 4, 5, "RW", 1, 0, 1, 1, 1);
      tf_reg.add_hdl_path_slice("fieldA", 5, 4);
      default_map.add_reg(tf_reg, 'h41, "RW");
   endfunction

    `uvm_object_utils(mac_blk)

    function new(input string name="mac_blk");
        super.new(name, UVM_NO_COVERAGE);
    endfunction 
   
endclass

寄存器占据多个地址位(数据宽度大于总线宽度)

这里的数据宽度32

class reg_counter extends uvm_reg;

    rand uvm_reg_field reg_data;

    virtual function void build();
        reg_data = uvm_reg_field::type_id::create("reg_data");
        // parameter: parent, size, lsb_pos, access, volatile, reset value, has_reset, is_rand, individually accessible
        reg_data.configure(this, 32, 0, "W1C", 1, 0, 1, 1, 0);
    endfunction

    `uvm_object_utils(reg_counter)

    function new(input string name="reg_counter");
        //parameter: name, size, has_coverage
        super.new(name, 32, UVM_NO_COVERAGE);
    endfunction
endclass

default_map中定义了2byte,总线宽度16位,

class reg_model extends uvm_reg_block;
   rand reg_invert invert;
   rand reg_counter counter;

   virtual function void build();
      default_map = create_map("default_map", 0, 2, UVM_BIG_ENDIAN, 0);

      invert = reg_invert::type_id::create("invert", , get_full_name());
      invert.configure(this, null, "invert");
      invert.build();
      default_map.add_reg(invert, 'h9, "RW");
      
      counter= reg_counter::type_id::create("counter", , get_full_name());
      counter.configure(this, null, "counter");
      counter.build();
      default_map.add_reg(counter, 'h5, "RW");
   endfunction

   `uvm_object_utils(reg_model)

    function new(input string name="reg_model");
        super.new(name, UVM_NO_COVERAGE);
    endfunction 

endclass

在my_case0中,和原来读取方式相同(read、poke等)

存储器

和寄存器(uvm_reg)不同,为uvm_mem。在reg_model中进行了定义。

其中的default添加mem后,可用于前门访问(read、write)。不加入也具有后门访问(peek、poke)。

这里定义的1024个单元,每个单位宽度16。若定义512个单元长度为32,则最大偏移仍然为512,寄存器模型会默认读写两次。

class my_memory extends uvm_mem;
   function new(string name="my_memory");
      super.new(name, 1024, 16);
   endfunction

   `uvm_object_utils(my_memory)
endclass

class reg_model extends uvm_reg_block;
   rand reg_invert invert;
   rand reg_counter counter;
   rand my_memory mm;

   virtual function void build();
      default_map = create_map("default_map", 0, 2, UVM_BIG_ENDIAN, 0);

      invert = reg_invert::type_id::create("invert", , get_full_name());
      invert.configure(this, null, "invert");
      invert.build();
      default_map.add_reg(invert, 'h9, "RW");
      
      counter= reg_counter::type_id::create("counter", , get_full_name());
      counter.configure(this, null, "counter");
      counter.build();
      default_map.add_reg(counter, 'h5, "RW");

      mm = my_memory::type_id::create("mm", , get_full_name());
      mm.configure(this, "stat_blk.ram1024x16_inst.array");
      default_map.add_mem(mm, 'h100);
   endfunction

   `uvm_object_utils(reg_model)

    function new(input string name="reg_model");
        super.new(name, UVM_NO_COVERAGE);
    endfunction 

endclass

期望值与镜像值

最大可能地和DUT保持同步,为DUT的镜像值。(获取性质)

期望值是DUT需要变成的值,使用set对期望值进行设置,使用update将期望值更新到DUT中。(写入性质)

以下是get和set用于期望值,镜像值不变。update将期望值不同于镜像值时,将期望值写入DUT,更新镜像值。

get_mirrored_value用于镜像值。peek从后面获取DUT实际值。read、write、peek、poke会更新期望值和镜像值,使得二者相等。

class case0_cfg_vseq extends uvm_sequence;

   `uvm_object_utils(case0_cfg_vseq)
   `uvm_declare_p_sequencer(my_vsqr)
   
   function  new(string name= "case0_cfg_vseq");
      super.new(name);
   endfunction 
   
   virtual task body();
      uvm_status_e   status;
      uvm_reg_data_t value;
      if(starting_phase != null) 
         starting_phase.raise_objection(this);
      p_sequencer.p_rm.invert.read(status, value, UVM_FRONTDOOR);
      p_sequencer.p_rm.invert.set(16'h1);
      value = p_sequencer.p_rm.invert.get();
      `uvm_info("case0_cfg_vseq", $sformatf("invert's desired value is %0h", value), UVM_LOW)
      value = p_sequencer.p_rm.invert.get_mirrored_value();
      `uvm_info("case0_cfg_vseq", $sformatf("invert's mirrored value is %0h", value), UVM_LOW)
      p_sequencer.p_rm.invert.update(status, UVM_FRONTDOOR);
      value = p_sequencer.p_rm.invert.get();
      `uvm_info("case0_cfg_vseq", $sformatf("invert's desired value is %0h", value), UVM_LOW)
      value = p_sequencer.p_rm.invert.get_mirrored_value();
      `uvm_info("case0_cfg_vseq", $sformatf("invert's mirrored value is %0h", value), UVM_LOW)
      p_sequencer.p_rm.invert.peek(status, value);
      `uvm_info("case0_cfg_vseq", $sformatf("invert's actual value is %0h", value), UVM_LOW)
      if(starting_phase != null) 
         starting_phase.drop_objection(this);
   endtask

endclass

检查后门访问路径

定义了uvm_reg_mem_hdl_paths_seq,然后设定了model为被测的寄存器模型。由于不需要sqr,因此start给null。

当无法读取,会给错误提示。

class case0_cfg_vseq extends uvm_sequence;

   `uvm_object_utils(case0_cfg_vseq)
   `uvm_declare_p_sequencer(my_vsqr)
   
   function  new(string name= "case0_cfg_vseq");
      super.new(name);
   endfunction 
   
   virtual task body();
      uvm_status_e   status;
      uvm_reg_data_t value;
      uvm_reg_mem_hdl_paths_seq ckseq;
      if(starting_phase != null) 
         starting_phase.raise_objection(this);
      ckseq = new("ckseq");
      ckseq.model = p_sequencer.p_rm;
      ckseq.start(null);
      if(starting_phase != null) 
         starting_phase.drop_objection(this);
   endtask

endclass

检查寄存器模型复位值与DUT的默认值是否相同

DUT初始化后为默认值,寄存器初始化后为0,调用reset后为复位值。

DUT的数据是通过寄存器进行前后门访问获取的。

的uvm_reg_hw_reset_seq为检查过程。

class case0_cfg_vseq extends uvm_sequence;

   `uvm_object_utils(case0_cfg_vseq)
   `uvm_declare_p_sequencer(my_vsqr)
   
   function  new(string name= "case0_cfg_vseq");
      super.new(name);
   endfunction 
   
   virtual task body();
      uvm_reg_hw_reset_seq ckseq;
      if(starting_phase != null) 
         starting_phase.raise_objection(this);
      ckseq = new("ckseq");
      ckseq.model = p_sequencer.p_rm;
      ckseq.start(null);
      if(starting_phase != null) 
         starting_phase.drop_objection(this);
   endtask

endclass

uvm_config_db从uvm_resource_db中派生,后者可以设置不检查的寄存器值(2选1)

function void my_case0::build_phase(uvm_phase phase);
   super.build_phase(phase);

   uvm_config_db#(uvm_object_wrapper)::set(this, 
                                           "v_sqr.configure_phase", 
                                           "default_sequence", 
                                           case0_cfg_vseq::type_id::get());
   uvm_config_db#(uvm_object_wrapper)::set(this, 
                                           "v_sqr.main_phase", 
                                           "default_sequence", 
                                           case0_vseq::type_id::get());
   uvm_resource_db#(bit)::set({"REG::",rm.invert.get_full_name(),".*"},
                              "NO_REG_TESTS", 1, this);
   uvm_resource_db#(bit)::set({"REG::",rm.invert.get_full_name(),".*"},
                              "NO_REG_HW_RESET_TEST", 1, this);

endfunction

检查读写功能

使用前门访问写,后门访问读。然后反之,检查读写功能。

uvm_reg_access_seq。等

class case0_cfg_vseq extends uvm_sequence;

   `uvm_object_utils(case0_cfg_vseq)
   `uvm_declare_p_sequencer(my_vsqr)
   
   function  new(string name= "case0_cfg_vseq");
      super.new(name);
   endfunction 
   
   virtual task body();
      uvm_reg_access_seq ckseq;
      uvm_mem_access_seq ckseq2;
      if(starting_phase != null) 
         starting_phase.raise_objection(this);
      ckseq = new("ckseq");
      ckseq.model = p_sequencer.p_rm;
      ckseq.start(null);
      ckseq2 = new("ckseq2");
      ckseq2.model = p_sequencer.p_rm;
      ckseq2.start(null);
      if(starting_phase != null) 
         starting_phase.drop_objection(this);
   endtask

endclass

使用uvm_resource_db可以跳过寄存器、存储器的检查(2选1,3选1)

function void my_case0::build_phase(uvm_phase phase);
   super.build_phase(phase);

   uvm_config_db#(uvm_object_wrapper)::set(this, 
                                           "v_sqr.configure_phase", 
                                           "default_sequence", 
                                           case0_cfg_vseq::type_id::get());
   uvm_config_db#(uvm_object_wrapper)::set(this, 
                                           "v_sqr.main_phase", 
                                           "default_sequence", 
                                           case0_vseq::type_id::get());
   //set for reg access sequence
   uvm_resource_db#(bit)::set({"REG::",rm.invert.get_full_name(),".*"},
                              "NO_REG_TESTS", 1, this);
   uvm_resource_db#(bit)::set({"REG::",rm.invert.get_full_name(),".*"},
                              "NO_REG_ACCESS_TEST", 1, this);
   
   //set for mem access sequence
   uvm_resource_db#(bit)::set({"REG::",rm.get_full_name(),".*"},
                              "NO_REG_TESTS", 1, this);
   uvm_resource_db#(bit)::set({"REG::",rm.get_full_name(),".*"},
                              "NO_MEM_TESTS", 1, this);
   uvm_resource_db#(bit)::set({"REG::",rm.invert.get_full_name(),".*"},
                              "NO_MEM_ACCESS_TEST", 1, this);

endfunction

预测器与自动预测

自动预测功能使用,

set_auto_predict,1打开,0关闭。用于driver读取数据返回后,更新期望值与镜像值。

function void base_test::connect_phase(uvm_phase phase);
   super.connect_phase(phase);
   v_sqr.p_my_sqr = env.i_agt.sqr;
   v_sqr.p_bus_sqr = env.bus_agt.sqr;
   v_sqr.p_rm = this.rm;
   rm.default_map.set_sequencer(env.bus_agt.sqr, reg_sqr_adapter);
   rm.default_map.set_auto_predict(1);
endfunction

也可手动定义预测器

定义预测器的同时也需要一个新的适配器。mon_reg_adapter。

然后连接1.default_map,2.adapter,3.bus_in。数据从agt到predictor到adapter到reg_model.

class base_test extends uvm_test;

   my_env         env;
   my_vsqr        v_sqr;
   reg_model      rm;
   my_adapter     reg_sqr_adapter;
   my_adapter     mon_reg_adapter;

   uvm_reg_predictor#(bus_transaction) reg_predictor;
   
   function new(string name = "base_test", uvm_component parent = null);
      super.new(name,parent);
   endfunction
   
   extern virtual function void build_phase(uvm_phase phase);
   extern virtual function void connect_phase(uvm_phase phase);
   extern virtual function void report_phase(uvm_phase phase);
   `uvm_component_utils(base_test)
endclass

function void base_test::build_phase(uvm_phase phase);
   super.build_phase(phase);
   env  =  my_env::type_id::create("env", this); 
   v_sqr =  my_vsqr::type_id::create("v_sqr", this);
   rm = reg_model::type_id::create("rm", this);
   rm.configure(null, "");
   rm.build();
   rm.lock_model();
   rm.reset();
   reg_sqr_adapter = new("reg_sqr_adapter");
   mon_reg_adapter = new("mon_reg_adapter");
   reg_predictor = new("reg_predictor", this);
   env.p_rm = this.rm;
endfunction

function void base_test::connect_phase(uvm_phase phase);
   super.connect_phase(phase);
   v_sqr.p_my_sqr = env.i_agt.sqr;
   v_sqr.p_bus_sqr = env.bus_agt.sqr;
   v_sqr.p_rm = this.rm;
   rm.default_map.set_sequencer(env.bus_agt.sqr, reg_sqr_adapter);
   rm.default_map.set_auto_predict(1);
   reg_predictor.map = rm.default_map;
   reg_predictor.adapter = mon_reg_adapter;
   env.bus_agt.ap.connect(reg_predictor.bus_in);
endfunction

function void base_test::report_phase(uvm_phase phase);
   uvm_report_server server;
   int err_num;
   super.report_phase(phase);

   server = get_report_server();
   err_num = server.get_severity_count(UVM_ERROR);

   if (err_num != 0) begin
      $display("TEST CASE FAILED");
   end
   else begin
      $display("TEST CASE PASSED");
   end
endfunction

DUT数据更新到寄存器模型

使用mirror函数

class case0_vseq extends uvm_sequence;

   `uvm_object_utils(case0_vseq)
   `uvm_declare_p_sequencer(my_vsqr)
   
   function  new(string name= "case0_vseq");
      super.new(name);
   endfunction 
   
   virtual task body();
      case0_sequence dseq;
      uvm_status_e   status;
      uvm_reg_data_t value;
      if(starting_phase != null) 
         starting_phase.raise_objection(this);
      #10000;
      dseq = case0_sequence::type_id::create("dseq");
      dseq.start(p_sequencer.p_my_sqr);
      #100000;
      p_sequencer.p_rm.counter.mirror(status, UVM_CHECK, UVM_FRONTDOOR); 

      p_sequencer.p_rm.counter.peek(status, value);
      `uvm_info("case0_vseq", $sformatf("counter's value is %0h", value), UVM_LOW)
      if(starting_phase != null) 
         starting_phase.drop_objection(this);
   endtask

endclass

人为更新寄存器模型镜像值,但不改变DUT值

task my_model::main_phase(uvm_phase phase);
   my_transaction tr;
   my_transaction new_tr;
   uvm_status_e status;
   uvm_reg_data_t value;
   int length;
   bit[31:0] counter;
   super.main_phase(phase);
   p_rm.invert.read(status, value, UVM_FRONTDOOR);
   while(1) begin
      port.get(tr);
      new_tr = new("new_tr");
      new_tr.copy(tr);
      //`uvm_info("my_model", "get one transaction, copy and print it:", UVM_LOW)
      //new_tr.print();
      if(value)
         invert_tr(new_tr);
      counter = p_rm.counter.get();
      length = new_tr.pload.size() + 18;
      counter = counter + length;
      p_rm.counter.predict(counter); 
      ap.write(new_tr);
   end
endtask

获取顶层blk

uvm_reg_block::get_root_blocks

class case0_cfg_vseq extends uvm_sequence;

   `uvm_object_utils(case0_cfg_vseq)
   `uvm_declare_p_sequencer(my_vsqr)
   
   function  new(string name= "case0_cfg_vseq");
      super.new(name);
   endfunction 
   
   virtual task body();
      uvm_status_e   status;
      uvm_reg_data_t value;
      bit[31:0] counter;
      uvm_reg_block blks[$];
      reg_model p_rm;
      if(starting_phase != null) 
         starting_phase.raise_objection(this);
      uvm_reg_block::get_root_blocks(blks);
      if(blks.size() == 0)
          `uvm_fatal("case0_cfg_vseq", "can't find root blocks")
      else begin
         if(!$cast(p_rm, blks[0]))
             `uvm_fatal("case0_cfg_vseq", "can't cast to reg_model")
      end
          
      p_rm.invert.read(status, value, UVM_FRONTDOOR);
      `uvm_info("case0_cfg_vseq", $sformatf("invert's initial value is %0h", value), UVM_LOW)
      p_rm.invert.write(status, 1, UVM_FRONTDOOR);
      p_rm.invert.read(status, value, UVM_FRONTDOOR);
      `uvm_info("case0_cfg_vseq", $sformatf("after set, invert's value is %0h", value), UVM_LOW)
      p_rm.counter.read(status, value, UVM_FRONTDOOR);
      counter = value;
      `uvm_info("case0_cfg_vseq", $sformatf("counter's initial value(FRONTDOOR) is %0h", counter), UVM_LOW)
      p_rm.counter.poke(status, 32'hFFFD);
      p_rm.counter.read(status, value, UVM_FRONTDOOR);
      counter = value;
      `uvm_info("case0_cfg_vseq", $sformatf("after poke, counter's value(FRONTDOOR) is %0h", counter), UVM_LOW)
      p_rm.counter.peek(status, value);
      counter = value;
      `uvm_info("case0_cfg_vseq", $sformatf("after poke, counter's value(BACKDOOR) is %0h", counter), UVM_LOW)
      if(starting_phase != null) 
         starting_phase.drop_objection(this);
   endtask

endclass

通过地址获取指针

p_sequencer.p_rm.default_map.get_reg_by_offset(addr)

class case0_cfg_vseq extends uvm_sequence;

   `uvm_object_utils(case0_cfg_vseq)
   `uvm_declare_p_sequencer(my_vsqr)
   
   function  new(string name= "case0_cfg_vseq");
      super.new(name);
   endfunction 
   
   virtual task read_reg(input bit[15:0] addr, output bit[15:0] value);
      uvm_status_e   status;
      uvm_reg target;
      uvm_reg_data_t data;
      uvm_reg_addr_t addrs[];
      target = p_sequencer.p_rm.default_map.get_reg_by_offset(addr);
      if(target == null) 
         `uvm_error("case0_cfg_vseq", $sformatf("can't find reg in register model with address: 'h%0h", addr))
      target.read(status, data, UVM_FRONTDOOR);
      void'(target.get_addresses(null,addrs));
      if(addrs.size() == 1)
         value = data[15:0]; 
      else begin
         int index;
         for(int i = 0; i < addrs.size(); i++) begin
            if(addrs[i] == addr) begin
               data = data >> (16*(addrs.size() - i));
               value = data[15:0];
               break;
            end
         end
      end 
   endtask

   virtual task body();
      uvm_status_e   status;
      uvm_reg_data_t value;

      if(starting_phase != null) 
         starting_phase.raise_objection(this);
      p_sequencer.p_rm.gb_ins.invert.read(status, value, UVM_FRONTDOOR);
      `uvm_info("case0_cfg_vseq", $sformatf("invert's initial value is %0h", value), UVM_LOW)
      p_sequencer.p_rm.gb_ins.invert.write(status, 1, UVM_FRONTDOOR);
      p_sequencer.p_rm.gb_ins.invert.read(status, value, UVM_FRONTDOOR);
      `uvm_info("case0_cfg_vseq", $sformatf("after set, invert's value is %0h", value), UVM_LOW)
      p_sequencer.p_rm.bb_ins.depth.read(status, value, UVM_FRONTDOOR);
      `uvm_info("case0_cfg_vseq", $sformatf("not existed reg depth's read value is %0h", value), UVM_LOW)
      read_reg('h0005, value);
      `uvm_info("case0_cfg_vseq", $sformatf("'h0005's value is %0h", value), UVM_LOW)
      read_reg('h0006, value);
      `uvm_info("case0_cfg_vseq", $sformatf("'h0006's value is %0h", value), UVM_LOW)
      if(starting_phase != null) 
         starting_phase.drop_objection(this);
   endtask

endclass

Factory机制

重载

任务、函数、约束支持重载。而重载可通过factory实现。

factory的重载当检测到定义过的重载记录后, 使用新的类型代替旧的类型。

重载的类型

set_type_override_by_type,根据类型对全局类型进行重载。

function void my_case0::build_phase(uvm_phase phase);
   bird bird_inst;
   parrot parrot_inst;
   super.build_phase(phase);
   
   set_type_override_by_type(bird::get_type(), parrot::get_type());
   
   bird_inst = bird::type_id::create("bird_inst");
   parrot_inst = parrot::type_id::create("parrot_inst");
   print_hungry(bird_inst);
   print_hungry(parrot_inst);
endfunction

set_inst_override_by_type限定了重载的范围

set_inst_override则使用字符串即可完成重载,同样set_type_override。

class my_case0 extends base_test;

   function new(string name = "my_case0", uvm_component parent = null);
      super.new(name,parent);
   endfunction 
   extern virtual function void build_phase(uvm_phase phase); 
   `uvm_component_utils(my_case0)
endclass


function void my_case0::build_phase(uvm_phase phase);
   super.build_phase(phase);

   //set_inst_override_by_type("env.o_agt.mon", my_monitor::get_type(), new_monitor::get_type());
   //set_inst_override("env.o_agt.mon", "my_monitor", "new_monitor");
   uvm_config_db#(uvm_object_wrapper)::set(this, 
                                           "env.i_agt.sqr.main_phase", 
                                           "default_sequence", 
                                           case0_sequence::type_id::get());
endfunction

以上4个函数用于component中,在top的initial中,使用另外不同的4个函数用于重载(名字部分重复,使用factory.进行调用)

set_type_override_by_type

set_type_override_by_name

set_inst_override_by_type

set_inst_override_by_name

连续重载、替换重载

连续,

需要父子关系

在连续重载的中间过程可以没有父子关系,但是无法实例化这些中间的类型,因为没有完整的父子关系。但是可以实例化开头的类型。头和尾之间必有父子关系。

function void my_case0::build_phase(uvm_phase phase);
   bird bird_inst;
   parrot parrot_inst;
   super.build_phase(phase);
   
   set_type_override_by_type(bird::get_type(), parrot::get_type());
   set_type_override_by_type(parrot::get_type(), big_parrot::get_type());
   
   bird_inst = bird::type_id::create("bird_inst");
   parrot_inst = parrot::type_id::create("parrot_inst");
   print_hungry(bird_inst);
   print_hungry(parrot_inst);
endfunction

替换,

后面替换前面的重载定义

function void my_case0::build_phase(uvm_phase phase);
   bird bird_inst;
   parrot parrot_inst;
   super.build_phase(phase);
   
   set_type_override_by_type(bird::get_type(), parrot::get_type());
   set_type_override_by_type(bird::get_type(), sparrow::get_type(), 0);
   
   bird_inst = bird::type_id::create("bird_inst");
   parrot_inst = parrot::type_id::create("parrot_inst");
   print_hungry(bird_inst);
   print_hungry(parrot_inst);
endfunctionz

输出重载信息

cmop的print_override_info与factory.debug_create_by_type效果相同。

另外的print为0,打印重载信息,为1打印增加用户定义到factory的类,为2增加了包括定义到factory的类。

print_topology则是打印系统top结构。(build实现的拓扑)

function void my_case0::connect_phase(uvm_phase phase);
   super.connect_phase(phase);
   //env.o_agt.mon.print_override_info("my_monitor");
   //factory.debug_create_by_type(my_monitor::get_type(), "uvm_test_top.env.o_agt.mon");
   //factory.print(2);
   //uvm_top.print_topology();
   uvm_top.print();
endfunction

  

回调机制

这里的回调往往是指代post,pre之类的自动执行函数。

定义回调类和池子

池子中实例化类的pre_tran会被自动调用(在do_callbacks中声明)

class A extends uvm_callback;
   virtual task pre_tran(my_driver drv, ref my_transaction tr);
   endtask
endclass

typedef uvm_callbacks#(my_driver, A) A_pool;

连接到drv

task my_driver::main_phase(uvm_phase phase);
   vif.data <= 8'b0;
   vif.valid <= 1'b0;
   while(!vif.rst_n)
      @(posedge vif.clk);
   while(1) begin
      seq_item_port.get_next_item(req);
      `uvm_do_callbacks(my_driver, A, pre_tran(this, req))
      drive_one_pkt(req);
      seq_item_port.item_done();
   end
endtask

在使用过程中,从A派生出callback,然后放入池子中。A需要重载callback

class my_callback extends A;

   virtual task pre_tran(my_driver drv, ref my_transaction tr);
      `uvm_info("my_callback", "this is pre_tran task", UVM_MEDIUM)
   endtask

   `uvm_object_utils(my_callback)
endclass

 

function void my_case0::connect_phase(uvm_phase phase);
   my_callback my_cb;
   super.connect_phase(phase);

   my_cb = my_callback::type_id::create("my_cb");
   A_pool::add(env.i_agt.drv, my_cb);
endfunction

回调继承

两处:1.继承后并使用set_super_type,2.do_callback过程使用父类,其它相同。

typedef class A;

class my_driver extends uvm_driver#(my_transaction);

   virtual my_if vif;

   `uvm_component_utils(my_driver)
   `uvm_register_cb(my_driver, A)
   function new(string name = "my_driver", uvm_component parent = null);
      super.new(name, parent);
   endfunction

   virtual function void build_phase(uvm_phase phase);
      super.build_phase(phase);
      if(!uvm_config_db#(virtual my_if)::get(this, "", "vif", vif))
         `uvm_fatal("my_driver", "virtual interface must be set for vif!!!")
   endfunction

   extern task main_phase(uvm_phase phase);
   extern task drive_one_pkt(my_transaction tr);
endclass

task my_driver::main_phase(uvm_phase phase);
   vif.data <= 8'b0;
   vif.valid <= 1'b0;
   while(!vif.rst_n)
      @(posedge vif.clk);
   while(1) begin
      seq_item_port.get_next_item(req);
      `uvm_do_callbacks(my_driver, A, pre_tran(this, req))
      drive_one_pkt(req);
      seq_item_port.item_done();
   end
endtask

task my_driver::drive_one_pkt(my_transaction tr);
   byte unsigned     data_q[];
   int  data_size;
   
   data_size = tr.pack_bytes(data_q) / 8; 
   //`uvm_info("my_driver", "begin to drive one pkt", UVM_LOW);
   repeat(3) @(posedge vif.clk);
   for ( int i = 0; i < data_size; i++ ) begin
      @(posedge vif.clk);
      vif.valid <= 1'b1;
      vif.data <= data_q[i]; 
   end

   @(posedge vif.clk);
   vif.valid <= 1'b0;
   //`uvm_info("my_driver", "end drive one pkt", UVM_LOW);
endtask

class new_driver extends my_driver;
   `uvm_component_utils(new_driver)
   `uvm_set_super_type(new_driver, my_driver)
   function new(string name = "new_driver", uvm_component parent = null);
      super.new(name, parent);
   endfunction
   
   extern task main_phase(uvm_phase phase);
endclass

task new_driver::main_phase(uvm_phase phase);
   vif.data <= 8'b0;
   vif.valid <= 1'b0;
   while(!vif.rst_n)
      @(posedge vif.clk);
   while(1) begin
      seq_item_port.get_next_item(req);
      `uvm_info("new_driver", "this is new driver", UVM_MEDIUM)
      `uvm_do_callbacks(my_driver, A, pre_tran(this, req))
      drive_one_pkt(req);
      seq_item_port.item_done();
   end
endtask

  

另外就是关于参数化类,以及代码重用机制。这部分更需要一个框架以后才理解。

 

标签:name,46,value,uvm,寄存器,phase,new,reg,日常
来源: https://www.cnblogs.com/bai2022/p/15837019.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有