• uvm_declare_p_sequencer获取sequencer原理


    在看张强白皮书P189中对uvm_declare_p_sequencer的描述时有一个疑问,就是为什么通过sequencer的类名就能获取到sequencer,然后自己下来查了一下,理了一下关系才明白。

    首先就是uvm_declare_p_sequencer这个宏,看了一下定义的地方,在uvm_sequence_defines.svh中:

    1. `define uvm_declare_p_sequencer(SEQUENCER) \
    2. SEQUENCER p_sequencer;\
    3. virtual function void m_set_p_sequencer();\
    4. super.m_set_p_sequencer(); \
    5. if( !$cast(p_sequencer, m_sequencer)) \
    6. `uvm_fatal("DCLPSQ", \
    7. $sformatf("%m %s Error casting p_sequencer, please verify that this sequence/sequence item is intended to execute on this type of sequencer", get_full_name())) \
    8. endfunction

    书上一样,就是把m_sequencer转成了p_sequencer,这个m_set_p_sequencer函数是在uvm_sequence_item里面,最开始是空的,宏定义进行了扩展,具体细节往下。

    1. //原始m_set_p_sequencer函数
    2. virtual function void m_set_p_sequencer();
    3. return;
    4. endfunction
    5. class uvm_sequence_item extends uvm_transaction;
    6. local int m_sequence_id = -1;
    7. protected bit m_use_sequence_info;
    8. protected int m_depth = -1;
    9. protected uvm_sequencer_base m_sequencer;
    10. protected uvm_sequence_base m_parent_sequence;
    11. static bit issued1,issued2;
    12. bit print_sequence_info;

    m_sequencer是在uvm_sequence_item里定义的,类型是uvm_sequencer_base,和书上一样。

    1. virtual function void set_sequencer(uvm_sequencer_base sequencer);
    2. m_sequencer = sequencer;
    3. m_set_p_sequencer();
    4. endfunction

    m_sequencer是在uvm_sequence_item的set_sequencer里赋值的,然后我们继续找这个函数。

    1. function void set_item_context(uvm_sequence_base parent_seq,
    2. uvm_sequencer_base sequencer = null);
    3. set_use_sequence_info(1);
    4. if (parent_seq != null) set_parent_sequence(parent_seq);
    5. if (sequencer == null && m_parent_sequence != null) sequencer = m_parent_sequence.get_sequencer();
    6. set_sequencer(sequencer);
    7. if (m_parent_sequence != null) set_depth(m_parent_sequence.get_depth() + 1);
    8. reseed();
    9. endfunction

    set_sequencer是在uvm_sequence_item的set_item_context里调用,可以看见前面两个函数的参数都有一个sequencer,我们继续找这个是从哪来的。

    1. virtual task start (uvm_sequencer_base sequencer,
    2. uvm_sequence_base parent_sequence = null,
    3. int this_priority = -1,
    4. bit call_pre_post = 1);
    5. set_item_context(parent_sequence, sequencer);
    6. if (!(m_sequence_state inside {CREATED,STOPPED,FINISHED})) begin
    7. uvm_report_fatal("SEQ_NOT_DONE",
    8. {"Sequence ", get_full_name(), " already started"},UVM_NONE);
    9. end
    10. .....

    可以看到,在uvm_sequence_base里面,start启动了这个函数,并且传了一个sequencer进去,这个sequencer是在sequence启动的时候指定的那个sequencer,这下就明白了,实际上被cast的m_sequencer传入的参数就是我们启动时候指定的sequencer。

    总结一下,sequence不管是显式还是隐式启动,都会调用start函数指定需要在哪个sequencer上启动,指定的是实例化后的sequencer的对象,然后将sequencer传给set_item_context,set_item_context再传给set_sequencer,最后赋给m_sequencer,然后通过cast将m_sequencer转换到p_sequencer。

  • 相关阅读:
    HTML5学习笔记(一)
    算法题:21合并两个有序链表
    lv8 嵌入式开发-网络编程开发 17 套接字属性设置
    数据读取与保存Sequence文件_大数据培训
    Flutter 跨平台框架中的 Widgets,你了解多少?
    windows和ubuntu下c++编译的库文件获取运行时自身所在路径的异同
    Tkinter:窗口控件配置
    【LeetCode】300.最长递增子序列
    【面试题】作用域和闭包
    JS 堆栈&内存快照& tracre跟踪
  • 原文地址:https://blog.csdn.net/Kizuna_AI/article/details/132720563