zoukankan      html  css  js  c++  java
  • UVM 片断

    Q: UVM中有些component使用new()函数来创建,有些则是使用build_phase中的create()来创建,这两种方法有什么区别?分别应用在哪些场景?

    A:new()函数是sv的语法,而create是UVM提供的方法,只有使用create才能实现factory的override,所以我们在创建component的时候一定要使用create。(对于uvm_object也是一样的)。

    TB的补充:补充一下Zhongjie的说明,我的个人意见:

    所有场景都推荐用create(),如果不能支持create(),则一定不是component。

    常见的sequence和sequence_item都用create()。

    UVM中有些“散件”确实不怎么用create(),比如uvm_event,我们会new()。

    我的补充:TLM也不支持factory功能,所以用new()来construct。

    Q: 上次讨论会提到尽量不要在component的build_phase中使用super.build_phase(phase),因为这个函数会使得component进入build_phase时对验证环境中的 config_db pool 进行检索,试图将所有 set 到这个 component 的元素都自动 get 到,这样做非常消耗系统计算资源,而且可能隐去了很多 get 代码段,这样并不利于理解、 debug 和代码的交接。

    举伪代码说明我的疑问:

    介绍一下代码,代码2中的 driver_err 是代码1中 my_driver 的子类,相比于父类的 A 和 B,driver_err 比父类多了两个需要 get 的变量 C 和 D。因为 driver_err 是扩展来的子类,我们不希望它把父类的 A 和 B 显示的写出来(包括它们的赋值操作:get)。代码3和代码4是driver_err的另外两种不同写法。

    问题来了:

    那么,如果在如代码2定义driver_err的时候,省略了super.build_phase(),driver_err 显然能够继承到父类的变量A和B,可重点是,driver_err 能够get到A和B的值吗(父类的build_phase中的get操作能够被子类继承吗?)

    如果不能的话,我们将子类的 super.build_phase() 写出来可以让driver_err获得A和B的值吗(如代码3

    还是说,我们仍然省略super.build_phase(),但是在 driver_err 的 build_phase 中将 get(A) 和 get(B) 再写一遍(如代码4

     1 //代码1
     2 class my_driver extends uvm_driver#(...);
     3   int A, B;
     4   virtual function void build_phase(...);
     5     ::get(A);
     6     ::get(B);
     7   endfunction
     8 endclass
     9 
    10 //代码2
    11 class driver_err extends my_driver;
    12   int C, D;
    13   virtual function void build_phase(...);
    14     ::get(C);
    15     ::get(D);
    16   endfunction
    17 endclass
    18 
    19 //代码3
    20 class driver_err extends my_driver;
    21   int C, D;
    22   virtual function void build_phase(...); 
    23     super.build_phase(..);
    24     ::get(C);
    25     ::get(D);
    26   endfunction
    27 endclass
    28 
    29 //代码4
    30 class driver_err extends my_driver;
    31   int C, D;
    32   virtual function void build_phase(...);
    33     ::get(A);
    34     ::get(B); 
    35     ::get(C);
    36     ::get(D);
    37   endfunction
    38 endclass
    View Code

    A

    Q:省略get语句的三个条件(但省略get语句会给debug带来一些麻烦)

    A: 第一,my_driver必须使用uvm_component_utils宏注册;(here my_driver is just for example)

        第二,pre_num必须使用uvm_field_in宏注册,且在build_phase调用super.build_phase();(pre_num is a property of driver)

        第三,在调用set函数的时候,set函数的第三个参数必须与要get函数中变量的名字相一致。

    P: UVM对于寄信人优先级的判定是根据set函数中的第一个参数!

    P: config_db的层级是由第一个参数决定的!

    P: 当同一层的同种类Class中多数实例的同一个参数的值是相同的话,可以把它的set放在super.build_phase()中去进行,如果有个别实例需要新的不同的参数值,可以在它自己的build_phase()中进行重新set,因为这两种情况的set的发信人级别一样(发信人优先原则不起作用),而个性实例的set行为在super.build_phase()之后,按照时间优先的原则,所以个性实例会得到自己的参数值。

    P: 非直线设置set,有一定风险,未知的component build_phase顺序。

    P: 非直线获取get,可以有效减少对同一个参数的多次set到不同component,减小出错的可能,易于维护。

    P: check_config_usage()一般在connect_phase来检测之前的config_db::set语句是否都被get到。

    P: UVM命令行中config数值(以int为例)。 +uvm_set_config_int="uvm_test_top.env.i_agt.drv,pre_num,'h8"

    Q: TLM2.0 比 TLM1.0 好在哪些方面?

    A

    Q: TLM中所传递的transaction是handle还是值?是否利用了bluePrint模式?

    A

    P: analysis_port跨level,如mon,agt,scb,最好用的方式:在agt中声明一个ap(analysis_port)但是不实例化它,而是直接把它指向mon.ap。这样在env中可以将agent的ap直接连到scoreboard的imp,实际上就是将monitor中的ap连接到了scoreboard中的imp。

    P: UVM_component必须在build_phase中实例化,uvm_object可以在任何phase实例化。

    P: 所有不消耗仿真时间的phase(function_phase)都是自下而上(空间上)启动(是启动!)的。这里启动是什么意思?

    P: 同一层级测component实例化是按照字典顺序执行的。

    P: phase是一个level更高的概念,不是针对单个component的,比如所有的component的post_build_phase都是同时开始的(等最后开始的那个)。

    Q: run_time_phase 中的 main_phase 不可以被 run_phase 中的objection block住?(已知,run_phase会被run_time_phase中(如main_phase)的objection block住)

    A: 不会

    P: 如果想要一个phase中的代码run起来,只需要在该phase中的任何一个component中加入raise_objection即可。

    P: UVM推荐只在root sequence中控制objection。

    Q: 如果phase中没有raise_objection,系统是否等待drain_time再进入下一个phase?

    A: 这个问题没意思啊

    P: domain只能隔离run-time phase。

    P: 一般在connect_phase中调用set_domain()来讲某个component及其全部子孙放入新的domain。

    P: 虽然一个phase中没有任何raise_objection,但是UVM(实际仿真器中的表现)还是会留一个NBA迭代的时间给大家运行。所以比如$display这种不消耗时间的操作还是会被执行。

    P: 在一个相对顶端的位置上raise_objection是一种比较易于理解和debug的做法。

    P: nested sequence和它的sub sequence所拥有的item应该是同一类型(同种transaction)。

    Q: Jingyong 讲要用`uvm_create()创建sub sequence和item才能通过get_full_name()得到正确的”inst_path"。为什么?

    A: 参考P200 in UVM实战

    P: 对sequence设定优先级本质上就是对内部的transaction设定优先级。

    Q: 在sequence中定义rand类型变量以向产生的transaction传递约束时,变量名字一定要和transaction中相应字段的名字不同!请问可以使用加this.前缀的方式解决问题吗?问题来源于UVM实战184页底端。

    A

    P: 嵌套sequence的前提是,在套里面的所有sequence产生的transaction都可以被同一个sequencer接受,也就是transaction的类型是该sequencer所指定的transaction类型或者它的派生类型。

    Q: `uvm_declare_p_sequencer()这个Macro是干什么用的?

    A: P186-188 in UVM实战。这个宏1: 实例化my_sequencer p_sequencer;2: $cast(p_sequencer, m_sequencer) 在"pre_body()之前"; 这里m_sequencer是属于每个sequence的成员变量啦。这样做将sequence所指定的sequencer的指针赋给了p_sequencer,比如,可以在sequence的body之中访问sequencer的成员变量:p_sequencer.value

    Q: 连接agent中的imonitor到scoreboard中的uvm_comparator,的TLM路径?

    A

    P: UVM中的factory机制不支持参数化的类的默认参数,在实例化的时候必须要将省略的参数加上。

    Q: analysis_port 和 其他TLM port的区别和联系?

    A: analysis_port是广播性质的,而TLM port类似于点对点的。一般analysis_port常用在scoreboard与monitor(agent)的通信中。

    P: 在sequence中定义rand类型变量以向产生的transaction传递约束时,变量的名字一定要与transaction中相应的字段的名字不同。因为编译器会误把他们都当成my_transaction中的变量,而使约束无效。

    P: virtual sequence 和 virtual sequencer 在创建时不需要制定transaction类型。

    P: Jinyong 建议启动root sequence时,使用先create然后config_db#(uvm_sequence_base)的方式(最后一个参数不需要::get_type()或::type_id::get()),不推荐使用config_db#(uvm_object_wrapper)的方式,因为后者会在后台进行create,但是产生出来的name可能会很复杂,不利于在factory中使用。(handle name 和 instance name)(logical hierarchy tree 和 composition hierarchy)

    Q: 在设置default_sequence时候,::get_type() 和 ::type_id::get()有什么区别?顺便总结一下将sequence指定到sequencer的方法。

    A:在util宏里有如下定义,所以是一样的啦。

    typedef uvm_object_registery #(T, S) type_id;
    static function type_id get_type();
       return type_id::get();
    endfunction
    • 1、uvm_config_db #(uvm_sequence_base)::set(this, "*.seqr.main_phase", "default_sequence", seq_inst); 
      • // 先要创建sequence! 这样sequence的名字就是我们决定的了。
      • // 但是由于上条原因,在我们利用factory去override这个sequence的时候,要注意把override语句写在create之前,否则无法实现override。因为UVM在create的时候才会检查是否有override需求被登记进来,如果override语句写在create之后就为时已晚了。
    • 2、uvm_config_db #(uvm_object_wrapper)::set(this, "*.seqr.main_phase", "default_sequence", seq::type_id::get()); 
      • // 缺点在于我们直接把一个sequence类指定到sequencer的default_sequence,所以这个sequence是在后台被UVMcreate的,它的实例名字是在后台被UVM创建并命名的,名字可能会很奇怪。所以在使用inst override的时候可能会出现问题。
      • // 优点在于我们不大可能犯上一种方式中容易出现的错误,即:把override语句在到create之后。因为这种方法里面没有显示的create,它由UVM在后台打理。
    • 3、uvm_config_db #(uvm_object_wrapper)::set(this, "*.seqr.main_phase", "default_sequence", seq::get_type()); 
      • // 跟上一种方法完全一致。

          --------上、下几种方法的区别在于:下面的方法多用在指定child sequence时使用,而上面的方法多用在指定root sequence时使用--------

    • 4、seq.start(seqr); 
    • 5、`uvm_do_on(seq, seqr); //`uvm_do()系列宏

    Q: 将东西set到sequence中的方法?

      A: set到sequence所在的sequencer。

    P: The nested sequence's pre_body() and post_body will not be executed. and nested sequence will not have access to starting_phase. 所以将objection放在pre_start和post_start中,当这个sequence被嵌套在其他sequence中时,它的objection操作将失效,管理objection就会比较方便。

    常用的objection操作方式:下面代码。 另外:objection 的 raise/drop 不应该出现在 component 的run_phase 或者 main_phase!!!

    task pre_start;
    //task
    pre_body();不推荐使用因为pre/post_body并不一定会存在, 却绝于开关:my_seq.start(seqr, parent_seq=null, priority=-1, call_pre_post=1)   if(starting_phase != null) starting_phase.raise_objection(this); endtask ...... task post_start; if(starting_phase != null) starting_phase.drop_objection(this); endtask

    Q: sequence 中的 starting_phase 是什么东西?

    A: 在uvm_sequence这个基类中有一个变量名为starting_phase,它的类型为uvm_phase,sequencer在启动default_phase时,会自动进行如下操作:

    task my_sequencer::main_phase(uvm_phase phase);

    ...

      seq.starting_phase = phase;

      seq,start(this);

    ...

    endtask

    因 此,可以在sequence中利用starting_phase进行提起和撤销objection。当sequence沦为child sequence时,objection的操作权自动被剥夺了,因为child sequence不会拥有starting_phase。以上是uvm1.1中的starting_phase的特性,uvm1.2有所优化。

    源码中:if non-null, specifies the phase in which this sequence was started.

    在sequence body中尽量都写上:

    if(starting_phase != 1) begin
      starting_phase.raise_objection();
    end
    ...
    
    if(starting_phase != 1) begin
      starting_phase.drop_objection();
    end

    Q: ::build_phase(uvm_phase phase)中的参数有什么用?

    A: UVM在后台维护的东东

    Q: Synopsis lab5中的 analysis_port的创建是在IMonitor的build_phase中通过analysis_port.new()完成的,为什么不用type_id::create()?

    A: LAB comment: TLM ports in UVM does'nt have factory support. You can not construct it with UVM create() method. 

    P: 在VCS中可以打开transaction模式,DVE中可以将各个transaction放在wave中去检查。下面是脚本命令的例子。

    #compile_time
    vcs -sverilog -ntb_ops uvm-1.1 -l comp.log -debug_all -timescale="1ns/100ps"  rtl.sv test.sv +define+UVM_TR_RECORD -lca
    
    #run_time
    ./simv -l simv.log +ntb_random_seed=1 +UVM_TESTNAME=test_base +UVM_VERBOSITY=UVM_MEDIUM +UVM_TR_RECORD +UVM_LOG_RECORD dve -vpd vcdplus.vpd &

    P: objection 的 drain_time 设定:

    virtual task body();
      if (starting_phase != null) begin
        uvm_objection objection = starting_phase.get_objection();//Get objection handle
        objection.set_drain_time(this, 1us);//set drain time
        starting_phase.raise_objection(this);//放在pre_body()中更合适。
      end
    ...

    Q: UVM如何知道driver是否需要返回一个rsp?

    A

    Q: 在env的build_phase中,先create了agent,然后才config_db set agent 的is_active(UVM_ACTIVE 和 UVM_NEGTIVE)。而在agent的build_phase中通常是先判断is_active的值再进行相应的内部component的create。env中build_phase的写法是不是顺序不对?

    A: function build_phase的执行顺序是由上而下的,agent的build_phase在env的build_phase之后执行。而系统在进行env的build_phase时,调用的时agent的new()函数,并不会调用agent的build_phase(),不需要对is_active进行判断。

    P: 初学UVM时,我的一个误区是,以为在UVM中一个component的build_phase函数中所包含的sub component的create命令,是在执行sub_component的build_phase函数。实际上,UVM中一个component在build_phase中执行sub_component的create时调用了sub_component的new()函数,在自己的build_phase执行完毕之后,系统才会执行sub_component的build_phase(依据build_phase的由上而下的执行顺序)。

    Q: 如何通过call_back来实现不同的测试,以driver为例。

    A:

    • class driver_callback: 在driver class同文件中建立一个class driver_callback extends uvm_callback;声明两个纯虚任务 pre_send 和 post_send;
    1 class driver_callback extends uvm_callback;
    2   function new(string name = "driver_callback");
    3     super.new(name);
    4   endfunction
    5   virtual task pre_send(driver drv, packet tr); endtask;
    6   virtual task post_send(driver drv, packet tr); endtask;
    7 endclass
    •  class driver: 在class driver中注册callback,使用`uvm_register_cb(driver,driver_callback);在class driver合适的地方中插入`uvm_do_callback(driver, driver_callback, pre_send(this, reg)) 任务; 
    class driver extends uvm_driver #(packet);
      `uvm_register_cb(driver, driver_callback)
      ...
       task run_phase(uvm_phase phase);
         forever begin
           seq_item_port.get_next_item(req);
           `uvm_do_callbacks(driver, driver_callback, pre_send(this, req));
           send(req);
           `uvm_do_callbacks(driver, driver_callback, post_send(this, req));
         end
      endtask
    endclass
    •  class driver_err_callback: extends from driver_callback, override the task pre_send() and other methods if needed;
    class driver_err_callback extends driver_callback;
      virtual task pre_send(driver drv, packet tr);
        xxx
      endtask
    endclass
    •  class err_test: create callback objects(driver_err_cb); initialize callback objects; register callback objects; 
    class err_test extends test_base;
    driver_err_callback drv_err_cb;
    ...
    virtual function connect_phase(uvm_phase phase);
      ...
      drv_err_cb = new();
      uvm_callbacks #(driver, driver_callback)::add(env.drv, drv_err,cb);
    endfunction
    endclass

    P: sequence library 使用要点

    • 为了增强可重用性,把sequence library打包在package里面。可以把transaction的类也放在同一package中。
    • 从uvm_sequence_library派生时要注明所产生的transaction的类型;
    • 其new函数中要调用init_sequence_library(),否则其内部候选的sequence队列为空;
    • 要调用`uvm_sequence_library_utils(name)注册;
    • 在sequence定义时使用宏uvm_add_to_seq_lib来将其加入到某个library中;
    • 在env(或其它)中指定default sequence为这个sequence library;
    • 可以通过uvm_sequence_library_cfg extends uvm_object来改变sequence library的默认工作方式;
      • uvm_sequence_libraty_cfg可在new()的过程中进行参数配置:seq_cfg = new(string name= " ", uvm_sequence_lib_mode = UVM_SEQ_LIB_RAND, int unsigned min=1, int unsigned max=10);
      • test中利用uvm_config_db #(uvm_sequence_library_cfg)::set(this, "*.seqr.main_phase", "default_sequence.config", seq_cfg)来进行Library的配置;

    Q: sequence library带来的方便之处?

      A

    P: Virtual Sequence使用要点:

    • 和virtual sequencer配套使用,register it to a virtual sequencer component.
    • 在body()中使用`uvm_do_on(seq, p_sequencer.sqr)来把sub sequence分配到对应的sequencer。
    • virtual_sequence的函数new中的,`uvm_update_sequence_lib干什么用的
    • 在virtual_sequencer的build_phase中,将child sequencers进行disable。通过set 空的 sequence 作为 default sequence:
    • uvm_config_db#(uvm_object_wrapper)::set(this, "*.agt.sqr.main_phase", noop_sequence::get_type());
    • 在virtual_sequencer的connect_phase中,将child sequencers连接到virtual_sequencer:
    • v_sqr.bfm0_sqr = agt0.bfm_sqr;
      v_sqr.bfm1_sqr = agt1.bfm_sqr;
    Q: set_inst_override("env.comp", "component", "new_comp");这种替换语句,一般放在被替换部件的上层的上层的build_phase中进行?比如driver的替换命令一般放在test_case层的build_phase中进行?如果确实有这样的惯例,有什么背后的原因吗?
    A:Jinyu说override一定要在create之前。因为UVM只会在create的时刻才会检查该component是否有登记过需要被override,如果override语句在create之后就没有意义了。
     
    Q: UVM中自带req成员的class有哪些?
      A
    P: TLM中普通uvm_tlm_port和uvm_tlm_fifo区别在于,普通的uvm_tlm_port会block进程,而uvm_tlm_fifo允许producer和consumer工作在各自独立的进程中
     
    P: uvm_tlm_port的函数get()是task,而uvm_analysis_port的write()必须是void function。Why?
      A:
    Q: 关于item和child sequence执行的语句总结:《论 sequence_item 和 sequence 的”发射“方式》
      A: sequence_item的发射方式。这里将sequence_item简称为tr。
     1 //No.1 `uvm_do系列宏
     2 
     3 //`uvm_do系列宏其实封装了下面的动作.
     4 tr = new("tr");
     5 start_item(tr); //在这一句话之前要先new(); //会等待driver进行xxx_port.get_next_item(tr);
     6   assert(tr.randomize() with {tr.pload.size() == 200;});//这个位置可根据需求进行 randomize;
     7 finish_item(tr);  //会等待req接受对象driver进行xxxx_port.item_done();
     8 //`uvm_do系列宏其实封装了上面面的动作.同样还有`uvm_do_on_pri_with()可供取舍.
     9 
    10 //No.2.1 `uvm_create 和 `uvm_send系列宏
    11 
    12 `uvm_create(tr) //相当于tr = new("tr");
    13 assert(tr.randomize()); //在这里可以对tr做很多事情
    14 `uvm_send(tr) //同样还有`uvm_send_pri(tr, 100)
    15 
    16 //No.2.2 `uvm_create 和 `uvm_rand_send系列宏
    17 
    18 `uvm_create(tr) //相当于new()
    19 `uvm_rand_send(tr) 
    20 //同样还有`uvm_rand_send_pri(tr, 100)
    21 //同样还有`uvm_rand_send_with(tr, {})
    22 //同样还有`uvm_rand_send_pri_with(tr, 100, {})
    23
    24 //No.3 start_item()和 finish_item()使用方法可见No.1
    24
    25 //No.4 pre_do mid_do post_do
    25
    25 ... \
    25 ... || start_item() \
    26 pre_do(bit is_item); // \
    27 ... || `uvm_do* 系列宏
    28 mid_do(); \ //
    29 ... || finish_item() //
    30 post_do(); //

    A: sequence的发射方法。待完善

    1. start_item() 和 finish_item() 不能用于sequence。
    2. sequence.start(sequencer handle);
    3. !!!  Strongly Recommend :Use `uvm_create(sub_seq)  to a  create child sequence, Keep the ‘inst_path’ align with logical parent-child relationsAlso use `uvm_create(item)  to create a sequence_item.

    Q:  reference_model需要的数据从哪里拿?
      UVM或者SV 的 bench 中,经常需要需要把发到DUT的数据抄送到reference_model,把从DUT返回的数据送到scoreboard。往往是driver负责总线的写读,monitor负责监视,这些数据可以从monitor拿,也可以直接让driver提供。应该如何选择呢?依据有哪些?
      A: 我以为,如果只是传递数据的话,从driver提供给reference_model和scoreboard就可以了。但是如果需要做总线上时序的判断之类的操作,使用monitor更合适。

    Q: RAL 相关的做业,有哪些是我部门需要编制代码的?

      A: 暂时参考Wenping的视频

    P: RAL使用要点:

    • 1.手工编写或者利用CODA(spec)产生 .ralf 文件,说明寄存器的内容、偏移地址等信息。
      2.利用ralgen程序借助.ralf文件生成regmodel.sv(定义了所有的reg和field,并放在一个uvm_reg_block的子类中)。
      3.编写adapter,主要是两个函数 reg2bus 和 bus2reg,实现 bus_agent 所需的 sequence_item 格式数据和 regmodel 的 uvm_reg_bus_op 格式的转换。
      4.在env声明 regmodel 和 adapter。
      5.在env中的build_phase() 中实例化 regmodel,  adapter.
           regmodel.configure(); //设定parent block和hdl_path
           regmodel.build(); //实例化内部寄存器
           regmodel.lock_model(); //锁定之后,不能再加入(add)新的map, reg, block, mem.
           regmodel.reset(); //内部寄存器值变为复位值,否则都是零
      6.在env中将reg_model连接到 adaper 和 bus_agent.sequencer。
        regmodel.default_map.set_sequencer(sequencer, adapter);
      7.regmodel.default_map.set_auto_predict(1);//通过default_map的任何bus读写操作都将更新mirror中的值。

    P: 使用ral时,采用的双层agent结构。agent、adapter在bench分层中的作用。
      在UVM的bench中,当使用register model的时候,底层的bus agent由于服务于adapter的缘故,必须处于协议层,也就是只服务于简单的读写操作。这时agent中的sequencer和driver的绑定的item type只能是协议中一个transaction对应的item type(这里的item是指uvm_sequence_item)。而在抽象级别更高的上层,我们在准备stimulus的时候,显然需要构造抽象级别更高的item以实现随机化等操作。所以上层的sequence所绑定的item type是高抽象级别的,可能包含了很多bus transaction相关的数据和参数。这样的话,由于sequence和sequencer绑定item类型的不同,不可以将sequence给set到sequencer的某个phase中去,这样导致了sequence实际上无法工作。为了解决这个问题,我们需要在高抽象层中构建新的agent,这个agent中的sequencer和driver都应该是高抽象级别的。那么显然,register_model变成了高抽象和低抽象层之间的分界,高抽象级别中的driver会调用register_model的读写函数,而register_model则通过adapter向低抽象层的sequencer发送协议级的item。总结一下,这样的bench结构出现了两层agent,高层agent负责对接高抽象级的sequence,低层的agent负责对接register_model和adapter并完成对bus的读写。这样写的好处是,底层的agent,包括sequencer、driver、monitor,只和bus的协议相关,agent可以很方便的打包被复用!符合科学的作业方法。

    Q: 在使用RAL时,编译器报错说“UVM_FRONT_DOOR”未被声明怎么办?

      A:UVM_FRONT_DOOR,是不是因为少了某个语句,虽然这个语句里面将front_door路径赋值为null。

    Q: uvm_mem是什么?(我在mem vip中看到“Programming interface full compatible to uvm_mem”,故有此问。)
      A: 是在uvm_reg_block下面的存储器的模拟类,可用来读写数据。由于uvm_mem通常占用较大空间,所以不被mirror支持。若想获得存储空间,必须先申请region。申请的方式有两种,可查阅class reference获知。

    Q: uvm_reg_sequence是什么?
      A:

    Q: uvm_comparer是什么?
      A:

    P: cd3_scoreboard使用要点(partial):

    • scoreboard -> streams + cfg_object + tlm_ports
    • parameters: order, number of streams and ports,
    • customized methods:  transfer(n port items to m stream items)
    • 比较顺序有多种(in_order;with_losses...),需要自定义的comparer的话,请override三个(sb,stream,cfg中的)user_compare()之一,且将cfg.order进行设定。
      • 若要设定相同类型的多个stream,只需要在单一stream的scoreboard的typedef基础上多写一个int参数就好。
          typedef cd3_scoreboard#(tr_item, 3) 3_stream_sb;
    • 若要设定支持不同数据类型的stream,则在定义scoreboard时的参数中使用共同父类。这样两边的export可以接收不同的衍生数据类型。

    P: cd3_abstract_mem的使用方法。

    • include 文件,package。
    • 实例化,并设置cfg。
    • 申请空间,使用mem.mam.reserve_region() or mem_mam.request_region()。
    • 记得release不需要的region。
    • 使用提供的adapter来进行读写操作。(通常是协议级别的操作,所以一般是DUT通过agent来操作adapter来读写memory。)
    • 使用cfg object来进行存储器属性的配置。

    Q: 在RAL file中定义register的field,比如一个32bit的寄存器,只有4个LSB和1个MSB是有意义的,那么该如何定义field才能明确两个field各自占用的地址?才能保证reg.write()能够将设定值准确配置到DUT的register相应的bit上?
      需要将32bit的每个bit都放在field里面吗?
      A: 肯定没必要把每个bit都定义出来,因为已经为有效的bit定义了宽度和偏移地址。

    Q: 可以定义参数化的函数和任务吗?例如 task type_trans(input bit[n] in, output T out )#(type T= int[n]);
      A: SV 语法不支持。

    Q: 一个uvm_component中是否可以存在多个analysis_imp?如果存在多个imp,如何在这个component中定义imp对应的method,总不能定义好多个write()吧?
      A:

      1. 非常有可能出现,而且经常出现。比如bench中的一个component会收集多个其他component的数据,这就需要这个component中有多个analysis_imp。
      2. 需要定义很多个write_xxx函数,通过后缀_xxx区别,步骤如下:
        1. 在这个component的class外部,写上
          `uvm_analysis_imp_decl(_from_agent1)
          `uvm_analysis_imp_decl(_from_agent2)
          这样就声明了两个analysis imp port的class,注意后缀,这个后缀就是write函数的后缀,两个analysis_imp分别调用的。
        2. 在这个component的class内部声明两个analysis_imp的handle
          uvm_analysis_imp_from_agent1#(transaction_type1) agent1_imp;
          uvm_analysis_imp_form_agent2#(transaction_type2) agent2_imp;
        3. 在这个component内部实现两个函数
          function void write_from_agent1(transaction_type1);
          function void write_from_agent2(transaction_type2);
          两个函数分别对应于两个analysis_imp的write函数。
        4. 在build_phase中new这两个analysis_imp
          agent1_imp = new("agent1_imp", this);
          agent2_imp = new("agent2_imp", this);
        5. 在env中链接(比如component名叫parser)
          agent1.ap.connect(parser.agent1_imp);
          agent2.ap.connect(parser.agent2_imp)

    Q:  HW中有一些寄存器,只有个别位是有效的,比如一个32bit的寄存器reg,其中只有reg[0]代表R或W操作,其余31bit没有意义。也就是说寄存器reg中只有1个有意义的field,其大小为1位。那么,我们在RALF文件中定义寄存器的时候,如何处理那些没有意义的bit? 
      A: 忽略它们,因为在定义field的时候会有参数bits代表长度,参数offset代表位地址偏移。这两个参数足够将所有有意义的field标示出来。所以问题中的情况的话,只需要将offset设置成0,将bits设置成1,即可。

    Q: SV中event和UVM_EVENT的异同?(可以作为分享会内容)使用方法可参考帖子:http://www.cnblogs.com/sunmaoduo/p/4958014.html
      UVM: Once an event has been triggered, it will be remain “on” until the event is reset。
      UVM: wait_trigger类似于SV中的“@”;wait_ptrigger类似于SV中的“wait”。
      UVM: wait_trigger_data和wait_ptrigger_data都是在以上基础上获得了event夹带的数据。
      UVM: virtual function void trigger ( uvm_object data = null ) 函数激发了事件,而且将数据data附带给这个事件。
        但是,这个data的数据类型是uvm_object,这该如何是好?

     P: Henry说过的bench design的3个要点

    1. 会不会遗漏bug
    2. reuseble
    3. maintainable

    P: uvm_object的对象的new只需要name,不需要parent。uvm_component则需要parent,因为uvm_component有着hierarchy的概念。

    Q: RAL中的field的成员变量value和成员方法get_mirrored_value有什么区别?

    • value:Mirrored field value.  This value can be sampled in a functional coverage model or constrained when randomized.
    • get_mirrored_value:Return the mirrored value of the field. It does not actually read the value of the field in the design, only the mirrored value in the abstraction class. If the field is write-only, the desired/mirrored value is the value last written and assumed to reside in the bits implementing it.  Although a physical read operation would something different, the returned value is the actual content.

      A:在使用中貌似没什么区别,都返回了Mirror中的值。

    Q: 多维数组不可以使用field注册?

    P: 在package中的class无法进行hierarchy信号的访问。

    P: .sv是在命令行中去指定的,.svh是用来被其它人引用的。只允许在.sv中import或者include文件。

    P: 在object中可以直接访问到类中的枚举变量的内部值。
      如:tr.direction = transaction::READ

    Q: 下面段落的含义,有关于RAL中Memory的read的offset,什么是memory的region?哪里有提到这个概念?

    The read() method is used to read from a memory location, the address of the location is the offset within the memory
    region, rather than the absolute memory address. This allows stimulus accessing memory to be relocatable, and therefore
    reuseable.
      A:其实region是uvm_mem中的存储空间,需要用函数来申请,有了region的mem才能够真正用来读写数据。read函数的offset指的是region中的相对地址偏移量,并不是map中的绝对地址。

    Q: uvm_config_db的set和get是不是应该分别放在build_phase和connect_phase中比较好,这样可以确保set的东西可以被get到?
      A:不是的,UVM中build_phase的执行顺序是自树根到树梢的,已经提供了天然的时间先后顺序。部门推荐的做法是将他们放在build_phase中。

    P: 在使用scoreboard的vip时候,可以通过将streams定义成针对父类的,从而实现利用多条stream比对不同类型数据的功能。(这里不同类型的数据有一个共同的父类,其实这很简单,吧父类设置成uvm_sequence_item就行了。)

    P: 在隐性uvm_config_db#(T)::get()时,get的动作放生在super.build_phase()中,UVM负责后台执行。如果所传递的数据类型是UVM自带数据类型之外的,就使用UVM自带的父类作为T。比如:uvm_config_db#(uvm_object)::set(this,"","",xxx);

  • 相关阅读:
    TOJ5272: 逆矩阵
    TOJ4537: n阶行列式
    gym101532 2017 JUST Programming Contest 4.0
    Float(浮动)
    块级元素与行级元素
    MyBatis-Oracle生成主键,嵌套对象中的List增加
    MyBatis嵌套对象中的List查询
    dbcp properties
    Idea菜单字体大小调整
    DOM4J
  • 原文地址:https://www.cnblogs.com/sunmaoduo/p/4679924.html
Copyright © 2011-2022 走看看