当前位置: 首页 > article >正文

UVM response_handler和get_response机制

很多UVM用户平时更多的使用get_response()方式去获得uvm_driver的response,但get_response有些缺点:由于 get_response() 是一种阻塞方法,它会阻塞直到收到来自 UVM 驱动程序 (put_response()) 的响应。因此,如果我们使用 get_response() 方法实现并按此顺序将 start_item()、finish_item() 和 finally get_response() 放置在序列的 body() 方法中,这将导致非流水线序列实现,因为下一个序列项可以只有在 get_response() 方法收到前一个请求序列项的响应项后,才提供给 UVM 驱动程序。

为了实现背靠背的传输,我们可以使用response_handler()机制,它可以将sequence中发送request和处理response两个操作分开处理,尽量减少耦合。例子如下流程图。

 1. 如何使用response_handler

如果想要实现response_handler机制的话,第一步需要在要使用这个机制的sequence里使能它,即调用use_response_handler(1)函数把m_use_response_handler变量设置为1就行,m_use_response_handler是uvm_sequence_base类里的一个成员变量,默认值为0,也就是不打开。第二步需要override uvm_sequence_base类里的response_handler函数,实现自己对response任意处理的需求。它的原型为:

  // Function: response_handler
  // When the use_reponse_handler bit is set to 1, this virtual method is called
  // by the sequencer for each response that arrives for this sequence.
  virtual function void response_handler(uvm_sequence_item response);
    return;
  endfunction

response_handler对uvm_driver没有任何影响,也就是不可见,uvm_driver仍然用之前的put_response机制就行。

2. response_handler背后机制

sequence里的response_handler(xxx)函数在uvm_driver调用seq_item_export.put_response(rsp)的时会自动被调用执行,故此我们从seq_item_export.put_response(rsp)讲起。

uvm_driver调用put_response(rsp)时,会调用uvm_sequencer_param_base里的put_response(rsp)函数,这个函数的定义为:

 313行到326行就是对传参进来的rsp做一些检查。328行会根据rsp里携带的sequence_id去调用m_find_sequence函数在reg_sequences关联数组里找对应sequence的句柄,如果找到了就返回sequence句柄,没有找到的话,就直接返回null,并报告没有找到原始sequence的信息。通常我们返回的是非null的,因此会进入330行到337行。如何避免返回null,在我的另一篇博客中说了,有兴趣读者可以瞄一眼(UVM中使用put_response的一个注意点)。在332行,会判断m_use_response_handler变量的值,如果为1就执行333行sequence里的response_handler函数,如果为0就执行337行response_handler的put_response。可想而知,这是1个关键分叉点。我们分别介绍这两个方法。

2.1 sequence_ptr.response_handler(t)

sequence里的response_handler()函数我们在第一小节里也提到了,原型是个空函数,需要用到这个机制的用户自己去override它来实现需要的功能。

2.2 sequence_ptr.put_response(t)

在uvm_sequence_base类的put_response函数又会继续调用put_base_response函数,它们俩的代码为:

  virtual function void put_response (uvm_sequence_item response_item);
    put_base_response(response_item); // no error-checking
  endfunction
  virtual function void put_base_response(input uvm_sequence_item response);
    if ((response_queue_depth == -1) ||
        (response_queue.size() < response_queue_depth)) begin
      response_queue.push_back(response);
      return;
    end
    if (response_queue_error_report_disabled == 0) begin
      uvm_report_error(get_full_name(), "Response queue overflow, response was dropped", UVM_NONE);
    end
  endfunction

可以看出,在put_base_response函数里会将uvm_driver送过的rsp放到response_queue队列了,response_queue队列定义为:protected uvm_sequence_item response_queue[$]。另外说下response_queue_depth这个int类型变量,它的默认值为8,也就是response_queue队列默认只能放8个rsp,如果超过的话,会被直接忽视掉(用户可以打开response_queue_error_report_disabled来报错)。但如果用户想要让response_queue队列可以放更多的rsp呢?需要调用uvm_sequence_base里的set_response_queue_depth(xx)来设置新值,xx就是传进去的int类型数值。也可以调用get_response_queue_depth()来返回当前设置的值。

response_queue队列里的值会给get_reponse(xxx)使用。

3. get_response背后机制

在sequence中调用get_response(xxx)的时候,对调用uvm_sequence_base类里的get_base_response(xxx)方法。

  virtual task get_response(output RSP response, input int transaction_id = -1);
    uvm_sequence_item rsp;
    get_base_response( rsp, transaction_id);
    $cast(response,rsp);
  endtask

get_base_response(xxx)方法的代码如下:

 从以上代码可以看出,get_reponse(xxx)就是从response_queue队列里拿数据,response_queue里的数据是put_response在没有使能response_handler机制情况下放进去的。因此用户要注意一旦采用response_handler机制后,在当前sequence里一定不能用get_response,反则它会get不到response,一直block在get_base_response方法的991行。如果transaction_id为-1,也就是用户没有指定要得到特定transaction_id的response时,get_base_response会默认返回response_queue里的第一个response,类似于FIFO。如果transaction_id不为-1,那么get_base_response会在response_queue里检索,直到找到1个匹配对应transaction_id的response为止。


http://www.kler.cn/a/7495.html

相关文章:

  • LLM - 计算 多模态大语言模型 的参数量(Qwen2-VL、Llama-3.1) 教程
  • 动态规划-完全背包问题——518.零钱兑换II
  • cmake生成器表达式
  • 容器内的Jenkins使用docker部署服务,服务数据文件挂载问题
  • 树状数组+概率论,ABC380G - Another Shuffle Window
  • C#界面设计
  • 《C++开发技能树》004 语言类·指针和内存管理·glibc的内存实现ptmalloc
  • Vue3加载中(Spin)
  • 38--Django-项目实战-全栈开发-基于django+drf+vue+elementUI企业级项目开发流程-前台首页设计
  • 【vue】使用 el-upload+axis实现手动多文件上传的代码实现
  • 国内ChatGPt研发-中国chatGPT
  • VB execl函数 word文档 KBS
  • Canal增量数据订阅和消费——原理详解
  • ansible自动运维——看明白ansible.cfg配置文件
  • 【Linux】环境变量进程虚拟地址空间
  • MySQL 索引常见问题汇总,一次性梳理
  • React 组件的 children 数据使用
  • Android 10.0 系统framework发送悬浮通知的流程分析
  • 在CentOS 7 中安装Hive-1.2.2
  • 【一起撸个DL框架】1 绪论
  • FPGA纯verilog实现UDP通信,三速网自协商仲裁,动态ARP和Ping功能,提供工程源码和技术支持
  • 多线程-模拟抢红包,抽奖池
  • 设计模式-day03
  • ChatGPT给自己写的科普性文章,你们认为写的怎样
  • echarts tooltip文字太长换行
  • Java多线程与并发