uvm misc note

295 阅读2分钟

知识点

uvm知识点

1. 如果在item中对某个field约束是0-10范围内;在seq中randomize(),这个field会是一个0-10之间的数值;但是在seq randomize之后对该field赋值100,则实际发出去的item 该field 为100;

2. task中参数赋值例子

item中field定义

 
  `uvm_object_utils_begin(pkt_item)
    `uvm_field_enum(cmd_type,cmd, UVM_ALL_ON)
    `uvm_field_int(w_data, UVM_ALL_ON)
    `uvm_field_int(rd_data, UVM_ALL_ON)
    `uvm_field_int(addr, UVM_ALL_ON)
  `uvm_object_utils_end
  constraint addr_type_cons {addr>0; addr<10;}

在seq中定义task

task reg_wr(
	bit[31:0] addr=32'h00000000,
	bit[31:0] w_data=32'h11223344,
    cmd_type  cmd=MEM_WR
);
 //call other task
endtask

// call reg_wr
reg_wr(.addr(32'h00000004),w_data(100))
//不用列出所有的port, 没有列出的port使用task定义时候的default值

3. 约束的重载

如果在一个item的约束中对addr 约束范围0-10; 在其子类item中 对addr约束范围>100;(两者有冲突),则实现对约束的重载。例子可以参考uvm实战8.1.2

4.uvm_teste_top在uvm_root中实例化,具体完成过程看uvm_root.sv代码

$cast(uvm_test_top, factory.create_component_by_name(test_name, "", "uvm_test_top", null));

task uvm_root::run_test(string test_name="");

  uvm_factory factory= uvm_factory::get();
  bit testname_plusarg;
  int test_name_count;
  string test_names[$];
  string msg;
  uvm_component uvm_test_top;

  process phase_runner_proc; // store thread forked below for final cleanup

  testname_plusarg = 0;

  // Set up the process that decouples the thread that drops objections from
  // the process that processes drop/all_dropped objections. Thus, if the
  // original calling thread (the "dropper") gets killed, it does not affect
  // drain-time and propagation of the drop up the hierarchy.
  // Needs to be done in run_test since it needs to be in an
  // initial block to fork a process.
  uvm_objection::m_init_objections();

`ifndef UVM_NO_DPI

  // Retrieve the test names provided on the command line.  Command line
  // overrides the argument.
  test_name_count = clp.get_arg_values("+UVM_TESTNAME=", test_names);

  // If at least one, use first in queue.
  if (test_name_count > 0) begin
    test_name = test_names[0];
    testname_plusarg = 1;
  end

  // If multiple, provided the warning giving the number, which one will be
  // used and the complete list.
  if (test_name_count > 1) begin
    string test_list;
    string sep;
    for (int i = 0; i < test_names.size(); i++) begin
      if (i != 0)
        sep = ", ";
      test_list = {test_list, sep, test_names[i]};
    end
    uvm_report_warning("MULTTST", 
      $sformatf("Multiple (%0d) +UVM_TESTNAME arguments provided on the command line.  '%s' will be used.  Provided list: %s.", test_name_count, test_name, test_list), UVM_NONE);
  end

`else

     // plusarg overrides argument
  if ($value$plusargs("UVM_TESTNAME=%s", test_name)) begin
    `uvm_info("NO_DPI_TSTNAME", "UVM_NO_DPI defined--getting UVM_TESTNAME directly, without DPI", UVM_NONE)
    testname_plusarg = 1;
  end

`endif

  // if test now defined, create it using common factory
  if (test_name != "") begin
    if(m_children.exists("uvm_test_top")) begin
      uvm_report_fatal("TTINST",
          "An uvm_test_top already exists via a previous call to run_test", UVM_NONE);
      #0; // forces shutdown because $finish is forked
    end
    //使用factory创建uvm_test_top,实例名是test_name;
    $cast(uvm_test_top, factory.create_component_by_name(test_name,
          "", "uvm_test_top", null));  
    if (uvm_test_top == null) begin
      msg = testname_plusarg ? {"command line +UVM_TESTNAME=",test_name} : 
                               {"call to run_test(",test_name,")"};
      uvm_report_fatal("INVTST",
          {"Requested test from ",msg, " not found." }, UVM_NONE);
    end
  end

  if (m_children.num() == 0) begin
    uvm_report_fatal("NOCOMP",
          {"No components instantiated. You must either instantiate",
           " at least one component before calling run_test or use",
           " run_test to do so. To run a test using run_test,",
           " use +UVM_TESTNAME or supply the test name in",
           " the argument to run_test(). Exiting simulation."}, UVM_NONE);
    return;
  end

  begin
  	if(test_name=="") 
  		uvm_report_info("RNTST", "Running test ...", UVM_LOW); 
  	else if (test_name == uvm_test_top.get_type_name())
  		uvm_report_info("RNTST", {"Running test ",test_name,"..."}, UVM_LOW); 
  	else
  		uvm_report_info("RNTST", {"Running test ",uvm_test_top.get_type_name()," (via factory override for test \"",test_name,"\")..."}, UVM_LOW);
  end
  
  // phase runner, isolated from calling process
  fork begin
    // spawn the phase runner task
    phase_runner_proc = process::self();
    uvm_phase::m_run_phases();
  end
  join_none
  #0; // let the phase runner start
  
  wait (m_phase_all_done == 1);
  
  // clean up after ourselves
  phase_runner_proc.kill();

  report_summarize();

  if (finish_on_completion)
    $finish;

endtask

5. sv中调用function或者task可以不带();但是java要求function在没有参数的时候也要写();所以在sv中好的习惯是function或者task名字后带();这样可以明确的知道这个是一个call function

6. 几种打印方法

  • uvm_report_info
uvm_report_info(get_type_name(),$psprintf("rq_attr = %0h",rq_attr));
REPORT_TAG = $sformatf("RST_AGENT_DRV[%0s]",cfg.id);

uvm_report_fatal(REPORT_TAG,"Unsupported cmd_type in sequence item");
uvm_report_fatal(REPORT_TAG, {"rst_agent_cfg must be set for: ", get_full_name(), ".cfg"});

if (cfg.use_rst_in) begin
    uvm_report_error(REPORT_TAG,$sformatf(
      "Reset %s is configured to use rst_in as its control, so it should not receive a sequence item, but one was just sent. Ignoring sequence item.\n",cfg.id));
  • display
$display("hello");
$display("data =%h", data);
$fatal("Failed to get BFM");
  • uvm_info
    `uvm_info(get_type_name(),"ckseq",UVM_LOW)
 `uvm_fatal("REG/NULL_ITEM","bus2reg: bus_item argument is null") 

    if (!$cast(gp,bus_item)) begin
      `uvm_error("WRONG_TYPE","Provided bus_item is not of type uvm_tlm_gp")

`uvm_info(get_type_name(),
         $sformatf("Writing 'h%0h at 'h%0h via map \"%s\"...",
              data, addrs[i], rw.map.get_full_name()), UVM_FULL);

`uvm_info(“TRACE”,$sformatf("%m"),UVM_HIGH)

`uvm_info(“TRACE”,$sformatf(“port_id value of %0d”,port_id),UVM_HIGH)

`uvm_info(“TRACE”,{"\n",req.sprint()},UVM_HIGH)

7. 函数及其参数赋值

  • 函数的形参必须给默认值default;
  • assign_value(.dmac(11)); 如果在call function的时候,没有给某个形参赋值,则函数内部使用该形参得默认值,smac是default 0 赋值给tr
task assign_value(bit [47:0] dmac=0,
		                 bit [47:0] smac=0);
      my_transaction tr;
		 $display("seq begin"); 
      if(starting_phase != null) 
         starting_phase.raise_objection(this);
      repeat (10) begin
		    // $display("seq begin loop "); 
         tr = new("tr");
				assert(tr.randomize() with {tr.pload.size==200;});
				tr.dmac=dmac;  //赋值
				tr.smac=smac;
			
         start_item(tr);
		    // $display("seq begin loop3 "); 
         finish_item(tr);
		    // $display("seq begin loop4 "); 
				uvm_report_info(get_type_name(),$psprintf("tr.dmac = %0h",tr.dmac));
				uvm_report_info(get_type_name(),$psprintf("tr.smac = %0h",tr.smac));
      end
		 $display("seq begin end "); 
      #100;
      if(starting_phase != null) 
         starting_phase.drop_objection(this);
      
	 
	 endtask

8. 静态的方法和成员可以使用声明句柄的方式来调用;也可以直接使用类来调用;

class lion_cage;
 //  protected static lion cage[$];
	 protected static animal cage[$];
   static function void cage_lion(animal l);
      cage.push_back(l);
   endfunction : cage_lion
   static function void list_lions();
      $display("Lions in cage"); 
      foreach (cage[i])
        $display(cage[i].get_name());
   endfunction : list_lions
endclass : lion_cage

//在top中使用 
lion_cage lc;
		   
lion_h  = new(2,  "Kimba");
lc.cage_lion(lion_h);
lc.list_lion();

9. uvm实战中,register model要点

  • 可以在reference model中发起reg的read/write操作
  • 可以在sequence中发起这个操作,reference model/sequence都是调用register model的 read/write操作,
  • 不论是在reference model还是sequence中,都是通过句柄访问register model
  • register model一般在base_test中定义;
  • 然后通过句柄传到env的reference model中;
  • sequence中调用register model 可以通过先把句柄传入seuqncer中,然后通过p_sequencer访问
  • sequence中调用register model 也可以通过uvm_config_db 的方法把register model 传进来;
    class bus_base_seq extends uvm_sequence #(pcie_cpl_item);
class bus_base_seq extends uvm_sequence #(pcie_cpl_item);
  `uvm_object_utils(bus_base_seq)
  `uvm_declare_p_sequencer(pcie_cpl_sequencer)
 
  global_pkt_config my_pkt_config;
  // Register model:
  reg_top_block reg_rm;
  pcie_cpl_item rsp;
  // Properties used by the various register access methods:
  rand uvm_reg_data_t data; // For passing data
  uvm_status_e status;      // Returning access status
  
  function new(string name = "bus_base_seq");
    super.new(name);
  endfunction

  // Getting a handle to the register model
  task body;
  //uvm_config_db  得到register model
    if(!uvm_config_db #(reg_top_block)::get(null, get_full_name(), "reg_top_block", reg_rm)) begin
      `uvm_error("body", "Could not find reg_top_block")
    end
endclass

10. transaction是继承uvm_sequence_item,uvm_sequence_item 继承uvm_transaction; 如果transaction中定义的域加入field_automation机制,则不用自己重写do_copy/do_compare/convert2string等函数;但是自己重写这些函数对于调试更加方便;

11. get_type_name()/get_name()/get_full_name()

get_type_names是类的名字;
get_name是对象的名字;
driver driver_h;
在driver中
`uvm_info(get_type_name(),get_name(),UVM_LOW)
driver[get_type_name] driver_h[get_name];

uvm_test_top.env_h.driver_h(get_full_name())
对于sequence

# UVM_INFO tb_classes/fibonacci_sequence.svh(28) @ 0: uvm_test_top.env_h.sequencer_h@@fibonacci [fibonacci_sequence] #####
# UVM_INFO tb_classes/fibonacci_sequence.svh(29) @ 0: uvm_test_top.env_h.sequencer_h@@fibonacci [fibonacci_sequence] fibonacci(get_type_name/ get_name)
# UVM_INFO tb_classes/fibonacci_sequence.svh(30) @ 0: uvm_test_top.env_h.sequencer_h@@fibonacci [fibonacci_sequence] uvm_test_top.env_h.sequencer_h.fibonacci(get_full_name)

另外一种用法

`uvm_info(get_full_name(),uvm_component_h.get_type_name(),UVM_LOW)
`uvm_info(get_full_name(),uvm_component_h.get_full_name(),UVM_LOW)

12. sequence中一般不建议加入@ #等消耗时间的操作;