uvm源码解读-sequence,sequencer,driver三者之间的握手关系1

news2024/11/26 1:58:10

1.start item

1.start_item();
 sequencer.wait_for_grant(prior);
 this.pre_do(1);

需要指出,这里明确说明了wait_for_grant和send_request之间不能有任何延迟,所以在mid_do这个任务里千万不能有任何延迟。 

task uvm_sequencer_base::wait_for_grant(uvm_sequence_base sequence_ptr,
                                        int item_priority = -1,
                                        bit lock_request = 0);
  uvm_sequence_request req_s;
  int my_seq_id;

  if (sequence_ptr == null)
    uvm_report_fatal("uvm_sequencer",
       "wait_for_grant passed null sequence_ptr", UVM_NONE);

  my_seq_id = m_register_sequence(sequence_ptr);
  
  // If lock_request is asserted, then issue a lock.  Don't wait for the response, since
  // there is a request immediately following the lock request
  if (lock_request == 1) begin
    req_s = new();
    req_s.grant = 0;
    req_s.sequence_id = my_seq_id;
    req_s.request = SEQ_TYPE_LOCK;
    req_s.sequence_ptr = sequence_ptr;
    req_s.request_id = g_request_id++;
    req_s.process_id = process::self();
    arb_sequence_q.push_back(req_s);
  end
      
  // Push the request onto the queue
  req_s = new();
  req_s.grant = 0;
  req_s.request = SEQ_TYPE_REQ;
  req_s.sequence_id = my_seq_id;
  req_s.item_priority = item_priority;
  req_s.sequence_ptr = sequence_ptr;
  req_s.request_id = g_request_id++;
  req_s.process_id = process::self();
  arb_sequence_q.push_back(req_s);
  m_update_lists();

  // Wait until this entry is granted
  // Continue to point to the element, since location in queue will change
  m_wait_for_arbitration_completed(req_s.request_id);

  // The wait_for_grant_semaphore is used only to check that send_request
  // is only called after wait_for_grant.  This is not a complete check, since
  // requests might be done in parallel, but it will catch basic errors
  req_s.sequence_ptr.m_wait_for_grant_semaphore++;//这个变量会用在send_request那里,发了一个减少一个,这里得到一个grant加一个

endtask

需要注意几点:

(1)uvm_sequence_base,相当于一个seq或者item的合集

(2) uvm_sequence_request

class uvm_sequence_request;
  bit        grant;
  int        sequence_id;
  int        request_id;
  int        item_priority;
  process    process_id;
  uvm_sequencer_base::seq_req_t  request;
  uvm_sequence_base sequence_ptr;
endclass

(3)m_register_sequence,这个任务核心就是输出sequence_ptr的id,同时将sequence_ptr记录到自己定义的动态数组reg_sequence中

function int uvm_sequencer_base::m_register_sequence(uvm_sequence_base sequence_ptr);

  if (sequence_ptr.m_get_sqr_sequence_id(m_sequencer_id, 1) > 0)
    return sequence_ptr.get_sequence_id();
  
  sequence_ptr.m_set_sqr_sequence_id(m_sequencer_id, g_sequence_id++);
  reg_sequences[sequence_ptr.get_sequence_id()] = sequence_ptr;
  return sequence_ptr.get_sequence_id();
endfunction

-------------------------------------------------------------------------------
m_get_sqr_sequence_id主要做的内容就是:定义了一个存放id的动态数组m_sqr_seq_ids,如果这个动态数组中存在输入的id,同时需要更新这个id,那就将这个id更新到对应item中
 function int m_get_sqr_sequence_id(int sequencer_id, bit update_sequence_id);
    if (m_sqr_seq_ids.exists(sequencer_id)) begin
      if (update_sequence_id == 1) begin
        set_sequence_id(m_sqr_seq_ids[sequencer_id]);
      end
      return m_sqr_seq_ids[sequencer_id];
    end

    if (update_sequence_id == 1)
      set_sequence_id(-1);

    return -1;
  endfunction
------------------------------------------------------------------------------------
function void set_sequence_id(int id);//uvm_sequence_item中的任务
    m_sequence_id = id;//这个m_sequence_id是item的id
  endfunction
------------------------------------------------------------------------------------

 function int get_sequence_id();//get_sequence_id是uvm_sequence_item中的任务
    return (m_sequence_id);//就是返回当前item的id
  endfunction
------------------------------------------------------------------------------------
 reg_sequences是定义的uvm_sequence_base的动态数组-> 
 protected uvm_sequence_base   reg_sequences[int];
------------------------------------------------------------------------------------

 (4)

protected uvm_sequence_request arb_sequence_q[$];

(5)

function void uvm_sequencer_base::m_update_lists();
  m_lock_arb_size++;
endfunction

 (6)注意这里有几个变量,第一个变量是lock_arb_size,第二个变量是m_lock_arb_size变量,m_lock_arb_size这个变量在每次进行m_update_lists()任务的时候会加一次,在一开始的时候会将这两个值相当,随后去等执行m_update_lists()任务。注意这里的arb_completed,原型是  protected bit  arb_completed[int]; 删除这个index相当于从仲裁的q(arb_completed)将仲裁完毕的id删除。

task uvm_sequencer_base::m_wait_for_arbitration_completed(int request_id);
  int lock_arb_size;
  
  // Search the list of arb_wait_q, see if this item is done
  forever 
    begin
      lock_arb_size  = m_lock_arb_size;
      
      if (arb_completed.exists(request_id)) begin
        arb_completed.delete(request_id);
        return;
      end
      wait (lock_arb_size != m_lock_arb_size);
    end
endtask

2.finish_item

finish_item();
(1)this.mid_do(item);
(2)sequencer.send_request(item);
(3)sequencer.wait_for_item_done();
(4)this.post_do(item);

注意,实际上会存在三个fifo,一个fifo是 uvm_tlm_fifo #(REQ) m_req_fifo;另两个是

 REQ m_last_req_buffer[$];
  RSP m_last_rsp_buffer[$];

uvm_send实际上是不断的往m_req_fifo去放入内容。

function void uvm_sequencer_param_base::send_request(uvm_sequence_base sequence_ptr,
                                                     uvm_sequence_item t,
                                                     bit rerandomize = 0);
  REQ param_t;

  if (sequence_ptr == null) begin
    uvm_report_fatal("SNDREQ", "Send request sequence_ptr is null", UVM_NONE);
  end//没有的化报fatal

  if (sequence_ptr.m_wait_for_grant_semaphore < 1) begin
    uvm_report_fatal("SNDREQ", "Send request called without wait_for_grant", UVM_NONE);
  end//注意,在上面wait_for_grant任务中得到一个grant就会加一个,这里减少
  sequence_ptr.m_wait_for_grant_semaphore--;
  
  if ($cast(param_t, t)) begin
    if (rerandomize == 1) begin//如果给了随机的选项,需要进行随机
      if (!param_t.randomize()) begin
        uvm_report_warning("SQRSNDREQ", "Failed to rerandomize sequence item in send_request");
      end
    end
    if (param_t.get_transaction_id() == -1) begin
      param_t.set_transaction_id(sequence_ptr.m_next_transaction_id++);
    end
    m_last_req_push_front(param_t);//往别的q里去推
  end else begin
    uvm_report_fatal(get_name(),$sformatf("send_request failed to cast sequence item"), UVM_NONE);
  end

  param_t.set_sequence_id(sequence_ptr.m_get_sqr_sequence_id(m_sequencer_id, 1));
  t.set_sequencer(this);
  if (m_req_fifo.try_put(param_t) != 1) begin
    uvm_report_fatal(get_full_name(), "Concurrent calls to get_next_item() not supported. Consider using a semaphore to ensure that concurrent processes take turns in the driver", UVM_NONE);
  end

  m_num_reqs_sent++;//记录send了多少内容
  // Grant any locks as soon as possible
  grant_queued_locks();
endfunction

grant_queued_locks()任务有点复杂,没看完,留个坑

注意这个任务 ,前期会一直往m_last_req_buffer里push,注意这里是从前推入。这个q是uvm_sequencer_param_base类中定义的q,他的类型采用了参数化的类REQ,定义方式如下:

REQ m_last_req_buffer[$];

function void uvm_sequencer_param_base::m_last_req_push_front(REQ item);
  if(!m_num_last_reqs)
    return;
 
  if(m_last_req_buffer.size() == m_num_last_reqs)
    void'(m_last_req_buffer.pop_back());

  this.m_last_req_buffer.push_front(item);
endfunction

 其中m_num_last_reqs这个变量是通过set_num_last_reqs任务实现的,也就是说m_last_req_buffer的buf含量最大是1024个。

function void uvm_sequencer_param_base::set_num_last_reqs(int unsigned max);
  if(max > 1024) begin
    uvm_report_warning("HSTOB", 
      $sformatf("Invalid last size; 1024 is the maximum and will be used"));
    max = 1024;
  end

  //shrink the buffer if necessary
  while((m_last_req_buffer.size() != 0) && (m_last_req_buffer.size() > max))
    void'(m_last_req_buffer.pop_back());

  m_num_last_reqs = max;
  num_last_items = max;

endfunction

这里就有个问题了,可以看到,实际上源码 并没有用m_last_req_buffer,而是用的是m_req_fifo,那这个buffer到底是做什么用的呢?其实查阅uvm手册可以发现,针对m_last_req_buffer的相关任务大多是以API的形式存在,所以个人理解还是封装了一下以便上层可以根据API实现更为负载的sequencer。

下面介绍结构和m_last_req_buffer/m_last_rsp_buffer相关的方法,可以在sequencer中实现。

(1)last_req,返回最后一个req,虽然叫last_req,但是实际可以返回任何顺序的。

function REQ last_req(int unsigned n = 0);
    if(n > m_num_last_reqs) begin
      uvm_report_warning("HSTOB",
        $sformatf("Invalid last access (%0d), the max history is %0d", n,
        m_num_last_reqs));
      return null;
    end
    if(n == m_last_req_buffer.size())
      return null;
  
    return m_last_req_buffer[n];
endfunction

get_num_last_reqs,相当于返回m_last_req_buffer的size

function int unsigned uvm_sequencer_param_base::get_num_last_reqs();
  return m_num_last_reqs;
endfunction

 set_num_last_reqs,约束m_last_req_buffer的size,多的部分会被pop出去。

function void uvm_sequencer_param_base::set_num_last_reqs(int unsigned max);
  if(max > 1024) begin
    uvm_report_warning("HSTOB", 
      $sformatf("Invalid last size; 1024 is the maximum and will be used"));
    max = 1024;
  end

  //shrink the buffer if necessary
  while((m_last_req_buffer.size() != 0) && (m_last_req_buffer.size() > max))
    void'(m_last_req_buffer.pop_back());

  m_num_last_reqs = max;
  num_last_items = max;

endfunction

 m_last_rsp_buffer的方法和上面类似,但是方法名称有所不同,分别是last_rsp();set_num_last_rsps();get_num_last_rsps();

 

function int uvm_sequencer_param_base::get_num_rsps_received();
  return m_num_rsps_received;//相当于m_last_rsp_buffer的size
endfunction

wait_for_item_done针对这个sequence_ptr,如果没有定义了transaction_id,那么仅仅需要等sequence_id,如果定义了的化,还需要多等一个 transaction_id。

task uvm_sequencer_base::wait_for_item_done(uvm_sequence_base sequence_ptr,
                                            int transaction_id);
  int sequence_id;

  sequence_id = sequence_ptr.m_get_sqr_sequence_id(m_sequencer_id, 1);
  m_wait_for_item_sequence_id = -1;
  m_wait_for_item_transaction_id = -1;

  if (transaction_id == -1)
    wait (m_wait_for_item_sequence_id == sequence_id);
  else
    wait ((m_wait_for_item_sequence_id == sequence_id &&
           m_wait_for_item_transaction_id == transaction_id));
endtask

 3.uvm_do做了上面的两部分:

4.driver

需要注意的是,get_next_item是从前面说的m_req_fifo里去拿

未完。。。。 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1023868.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MySQL进阶篇2-索引的创建和使用

索引 mkdir mysql tar -xvf mysqlxxxxx.tar -c myql cd mysql rpm -ivh .....rpm yum install openssl-develsystemctl start mysqldgerp temporary password /var/log/mysqld.logmysql -u root -p mysql> show variables like validate_password.% set global validate_…

maven本地安装jar包

在实际开发中&#xff0c;有些jar包不能通过公共库下载&#xff0c;只能本地安装。可以按照以下步骤操作&#xff1a; 1、安装命令&#xff1a; mvn install:install-file -DgroupIdcom.chinacreator.sm -DartifactIdfbm-sm-common -Dversion0.0.1 -Dpackagingjar -Dfile../n…

基于Java+SpringBoot+Vue+协同过滤算法的电影推荐系统(亮点:智能推荐、协同过滤算法、在线支付、视频观看)

协同过滤算法的电影推荐系统 一、前言二、我的优势2.1 自己的网站2.2 自己的小程序&#xff08;小蔡coding&#xff09;2.3 有保障的售后2.4 福利 三、开发环境与技术3.1 MySQL数据库3.2 Vue前端技术3.3 Spring Boot框架3.4 微信小程序 四、功能设计4.1 主要功能描述 五、系统实…

微服务学习(七):docker安装Mysql

微服务学习&#xff08;七&#xff09;&#xff1a;docker安装Mysql 1、拉取镜像 docker pull mysql2、查看安装的镜像 docker images3、安装mysql docker run -p 3306:3306 --name mysql \ -v /mydata/mysql/log:/var/log/mysql \ -v /mydata/mysql/data:/var/lib/mysql \…

【HarmonyOS】元服务卡片router实现跳转到指定页面

【关键字】 元服务卡片、router跳转不同页面 【写在前面】 本篇文章主要介绍开发元服务卡片时&#xff0c;如何实现从卡片中点击事件跳转到指定的应用内页面功能。此处以JS UI开发服务卡片为例&#xff0c;JS卡片支持组件设置action&#xff0c;包括router事件和message事件&…

Python配置与测试利器:Hydra + pytest的完美结合

简介&#xff1a;Hydra 和 pytest 可以一起使用&#xff0c;基于 Hydra Pytest 的应用可以轻松地管理复杂配置&#xff0c;并编写参数化的单元测试&#xff0c;使得Python开发和测试将变得更为高效。 安装&#xff1a; pip install hydra-core pytest案例源码&#xff1a;my…

系统架构设计师(第二版)学习笔记----软件工程

【原文链接】系统架构设计师&#xff08;第二版&#xff09;学习笔记----软件工程 文章目录 一、软件工程1.1 软件危机的表现1.2 软件工程的内容 二、软件过程模型2.1 软件的声明周期2.2 瀑布模型2.3 瀑布模型的缺点2.4 原型模型2.5 原型模型开发阶段2.6 开发原型的途径2.7 螺旋…

【音视频】ffplay源码解析-PacketQueue队列

包队列架构位置 对应结构体源码 MyAVPacketList typedef struct MyAVPacketList {AVPacket pkt; //解封装后的数据struct MyAVPacketList *next; //下一个节点int serial; //播放序列 } MyAVPacketList;PacketQueue typedef struct PacketQueue {MyAVPacketList …

纯js实现html指定页面导出word

因为最近做了范文网站需要&#xff0c;所以要下载为word文档&#xff0c;如果php进行处理&#xff0c;很吃后台服务器&#xff0c;所以想用前端进行实现。查询github发现&#xff0c;确实有这方面的插件。 js导出word文档所需要的两个插件&#xff1a; FileSaver.js jquery.w…

企业备份解决方案:保护您的企业虚拟机安全!

在目前这个高度数据化的信息时代中&#xff0c;企业对数据的依赖程度更高&#xff0c;以便进行高效的运营和理智的决策。然而&#xff0c;硬件的故障、自然的灾害以及网络的攻击等无法预料的情况&#xff0c;可能会带来大规模的数据丢失&#xff0c;进而造成经济的损失&#xf…

vscode 编译工程问题总结

1.安装NuGet Package出错 The “path” argument must be of type string or an instance of Buffer of URL Received undefined 解决方法&#xff1a; 账号登录&#xff0c;重启vscode &#xff08;1&#xff09;找到登录 &#xff08;2&#xff09;选择一个登录方式登录 …

打造本地紧密链接的开源社区——KCC@长沙开源读书会openKylin爱好者沙龙圆满举办...

2023年9月9日&#xff0c;由开源社联合 openKylin 社区举办的 KCC长沙开源读书会&openKylin 爱好者沙龙&#xff0c;在长沙圆满举办。这是 KCC长沙首次正式进入公众视野&#xff0c;开展开源交流活动&#xff0c;也是 openKylin 社区长沙首场线下沙龙。长沙地区及其周边的众…

目标分类笔记(二): 利用PaddleClas的框架来完成多标签分类任务(从数据准备到训练测试部署的完整流程)

文章目录 一、演示多分类效果二、PaddleClas介绍三、代码获取四、数据集获取五、环境搭建六、数据格式分析七、模型训练7.1 其他训练指标 八、模型预测九、模型评估十、PaddleClas相关博客 一、演示多分类效果 二、PaddleClas介绍 PaddleClas主要构件&#xff1a; PP-ShiTu&a…

测试与FastAPI应用数据之间的差异

【squids.cn】 全网zui低价RDS&#xff0c;免费的迁移工具DBMotion、数据库备份工具DBTwin、SQL开发工具等 当使用两个不同的异步会话来测试FastAPI应用程序与数据库的连接时&#xff0c;可能会出现以下错误&#xff1a; 在测试中&#xff0c;在数据库中创建了一个对象&#x…

指针笔试题讲解-----让指针简单易懂(2)

目录 回顾上篇重点 &#xff1a; 一.笔试题 ( 1 ) 二.笔试题 ( 2 ) 科普进制知识点 (1) 二进制 (2) 八进制 (3)十六进制 三.笔试题&#xff08; 3 &#xff09; 四.笔试题&#xff08; 4 &#xff09; 五.笔试题&#xff08; 5 &#xff09; 六.笔试题&#xff08; …

Word中的图片保存后变模糊怎么解决

目录 1.介绍 2.原因 3.解决方案 Word是由微软公司开发的一款文字处理软件&#xff0c;它是Microsoft Office套件的一部分。Word提供了丰富的功能和工具&#xff0c;使用户能够创建、编辑和格式化文档。它支持各种文本处理任务&#xff0c;包括编写信函、报告、论文、简历等。…

C# Onnx Yolov8 Detect Poker 扑克牌识别

效果 项目 代码 using Microsoft.ML.OnnxRuntime; using Microsoft.ML.OnnxRuntime.Tensors; using OpenCvSharp; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System…

OVS-DPDK学习

安装教程&#xff1a; https://docs.openvswitch.org/en/latest/intro/install/dpdk/ https://docs.openvswitch.org/en/latest/howto/dpdk/ overview和应用 https://www.intel.com/content/www/us/en/developer/articles/technical/open-vswitch-with-dpdk-overview.html OVS…

【网络安全】黑客自学笔记

1️⃣前言 &#x1f680;作为一个合格的网络安全工程师&#xff0c;应该做到攻守兼备&#xff0c;毕竟知己知彼&#xff0c;才能百战百胜。 计算机各领域的知识水平决定你渗透水平的上限&#x1f680; 【1】比如&#xff1a;你编程水平高&#xff0c;那你在代码审计的时候就会比…

【Map篇】HashTable详解

目录 成员变量属性构造函数put()remove()get()总结: HashTable的优点?HashTable 是一种基于哈希函数的数据结构。它将每个键Key映射到一个唯一的索引Index,通过这个索引来快速访问数据。底层是一个数组,数组中的每个元素称为桶(bucket)。 当我们需要访问某个元素时,首先会对…