【UVM学习笔记】更加灵活的UVM—通信

系列文章目录

【UVM学习笔记】UVM基础—一文告诉你UVM的组成部分
【UVM学习笔记】UVM中的“类”


文章目录

  • 系列文章目录
  • 前言
  • 一、TLM是什么?
  • 二、put操作
    • 2.1、建立PORT和EXPORT的连接
    • 2.2 IMP组件
  • 三、get操作
  • 四、transport端口
  • 五、nonblocking端口
  • 六、analysis端口
  • 七、monitor与scoreboard之间的通信
  • 八、使用FIFO通信
  • 总结


前言

该专题用于记录学习UVM芯片验证的过程,主要学习书籍为经典的《UVM实战》,同时也会去进行一些UVM的项目联系。


一、TLM是什么?

TLM是Transaction Level Modeling(事务级建模)的缩写。所谓transaction level是相对DUT中各个模块之间信号线级别的通信来说的。
TLM通常有三种模式:

  1. put操作,通信的发起者A把一个transaction发送给B。在这个过程中,A称为“发起者”,而B称为“目标”。A具有的端口(用方框表示)称为PORT,而B的端口(用圆圈表示)称为EXPORT。这个过程中,数据流是从A流向B的。
  2. get操作。在这个过程中,A依然是“发起者”,B依然是“目标”,A上的端口依然是PORT,而B上的端口依然是EXPORT。这个过程中,数据流是从B流向A的。PORT和EXPORT体现的是控制流而不是数据流。

在这里插入图片描述

  1. transport操作,transport操作相当于一次put操作加一次get操作,这两次操作的“发起者”都是A,目标都是B。在这个过程中,数据流先从A流向B,再从B流向A。在现实世界中, 相当于是A向B提交了一个请求(request),而B返回给A一个应答(response)。

在这里插入图片描述

二、put操作

2.1、建立PORT和EXPORT的连接

UVM中使用connect函数来建立连接关系。如A要和B通信(A是发起者),那么可以这么写:A.port.connect(B.export)。下面是A的代码部分:

class A extends uvm_component;`uvm_component_utils(A)uvm_blocking_put_port#(my_transaction) A_port;function new(string name, uvm_component parent);super.new(name, parent);endfunctionextern function void build_phase(uvm_phase phase);extern virtual  task main_phase(uvm_phase phase);
endclassfunction void A::build_phase(uvm_phase phase);super.build_phase(phase);A_port = new("A_port", this);
endfunctiontask A::main_phase(uvm_phase phase);
endtask

然后得到B的代码:

class B extends uvm_component;`uvm_component_utils(B)uvm_blocking_put_export#(my_transaction) B_export;function new(string name, uvm_component parent);super.new(name, parent);endfunctionextern function void build_phase(uvm_phase phase);extern virtual  task main_phase(uvm_phase phase);
endclassfunction void B::build_phase(uvm_phase phase);super.build_phase(phase);B_export = new("B_export", this);
endfunctiontask B::main_phase(uvm_phase phase);
endtask

然后在env将两者进行链接

class my_env extends uvm_env;A   A_inst;B   B_inst;function new(string name = "my_env", uvm_component parent);super.new(name, parent);endfunctionvirtual function void build_phase(uvm_phase phase);super.build_phase(phase);A_inst = A::type_id::create("A_inst", this);B_inst = B::type_id::create("B_inst", this);endfunctionextern virtual function void connect_phase(uvm_phase phase);`uvm_component_utils(my_env)
endclassfunction void my_env::connect_phase(uvm_phase phase);super.connect_phase(phase);A_inst.A_port.connect(B_inst.B_export);
endfunction

2.2 IMP组件

除了TLM中定义的PORT与EXPORT外,UVM中加入了第三种端口:IMP,起作用相当于在EXPORT后进行接受操作。
添加IMP后,A的代码变为:

task A::main_phase(uvm_phase phase);my_transaction tr;repeat(10) begin#10;tr = new("tr");assert(tr.randomize());A_port.put(tr);end
endtask

在B中需要改动的要多一点:

class B extends uvm_component;`uvm_component_utils(B)uvm_blocking_put_export#(my_transaction) B_export;uvm_blocking_put_imp#(my_transaction, B) B_imp;function new(string name, uvm_component parent);super.new(name, parent);endfunctionextern function void build_phase(uvm_phase phase);extern function void connect_phase(uvm_phase phase);extern function void put(my_transaction tr);extern virtual  task main_phase(uvm_phase phase);
endclassfunction void B::build_phase(uvm_phase phase);super.build_phase(phase);B_export = new("B_export", this);B_imp = new("B_imp", this);
endfunctionfunction void B::connect_phase(uvm_phase phase);super.connect_phase(phase);B_export.connect(B_imp);
endfunctionfunction void B::put(my_transaction tr);`uvm_info("B", "receive a transaction", UVM_LOW) tr.print();
endfunction

在上述连接关系中,IMP是作为连接的终点。在UVM中,只有IMP才能作为连接关系的终点。如果是PORT或者EXPORT作为终点,则会报错。

三、get操作

get系列端口与put系列端口在某些方面完全相反。在这种连接关系中,数据流依然是从A到B,但是A由动作发起者变成了动作接收者,而B由动作接收者变成了动作发起者。
在这里插入图片描述
B_port的类型为uvm_blocking_get_port,A_export的类型为uvm_blocking_get_export,A_imp的类型为uvm_blocking_get_imp。A的代码为:

class A extends uvm_component;`uvm_component_utils(A)uvm_blocking_get_export#(my_transaction) A_export;uvm_blocking_get_imp#(my_transaction, A) A_imp;my_transaction tr_q[$];function new(string name, uvm_component parent);super.new(name, parent);endfunctionextern function void build_phase(uvm_phase phase);extern function void connect_phase(uvm_phase phase);extern virtual  task get(output my_transaction tr);extern virtual  task main_phase(uvm_phase phase);
endclassfunction void A::build_phase(uvm_phase phase);super.build_phase(phase);A_export = new("A_export", this);A_imp = new("A_imp", this);
endfunctionfunction void A::connect_phase(uvm_phase phase);super.connect_phase(phase);A_export.connect(A_imp); 
endfunctiontask A::get(output my_transaction tr);while(tr_q.size() == 0) #2;tr = tr_q.pop_front();
endtasktask A::main_phase(uvm_phase phase);my_transaction tr;repeat(10) begin#10;tr = new("tr");tr_q.push_back(tr); end
endtask

在A的get任务中,每隔2个时间单位检查tr_q中是否有数据,如果有则发送出去。当B在其main_phase调用get任务时,会最终执行A的get任务。在A的connect_phase,需要把A_export和A_imp连接起来。下面是B的部分:

class B extends uvm_component;`uvm_component_utils(B)uvm_blocking_get_port#(my_transaction) B_port;function new(string name, uvm_component parent);super.new(name, parent);endfunctionextern function void build_phase(uvm_phase phase);extern virtual  task main_phase(uvm_phase phase);
endclassfunction void B::build_phase(uvm_phase phase);super.build_phase(phase);B_port = new("B_port", this);
endfunctiontask B::main_phase(uvm_phase phase);my_transaction tr;while(1) beginB_port.get(tr);`uvm_info("B", "get a transaction", UVM_LOW) tr.print();end
endtask

在这些连接关系中,需要谨记的是连接的终点必须是一个IMP。

四、transport端口

在这里插入图片描述
A代码如下所示:

task A::main_phase(uvm_phase phase);my_transaction tr;my_transaction rsp;repeat(10) begin#10;tr = new("tr");assert(tr.randomize());A_transport.transport(tr, rsp);`uvm_info("A", "received rsp", UVM_MEDIUM)rsp.print();end
endtask

B中需要定义一个类型为uvm_blocking_transport_imp的IMP:

class B extends uvm_component;`uvm_component_utils(B)uvm_blocking_transport_imp#(my_transaction, my_transaction, B) B_imp;function new(string name, uvm_component parent);super.new(name, parent);endfunctionextern function void build_phase(uvm_phase phase);extern task transport(my_transaction req, output my_transaction rsp);
endclassfunction void B::build_phase(uvm_phase phase);super.build_phase(phase);B_imp = new("B_imp", this);
endfunctiontask B::transport(my_transaction req, output my_transaction rsp);`uvm_info("B", "receive a transaction", UVM_LOW) req.print();//do something according to req#5;rsp = new("rsp");
endtask

env中的代码是:

function void my_env::connect_phase(uvm_phase phase);super.connect_phase(phase);A_inst.A_transport.connect(B_inst.B_imp);
endfunction

在A中调用transport任务,并把生成的transaction作为第一个参数。B中的transaport任务接收到这笔transaction,根据这笔transaction做某些操作,并把操作的结果作为transport的第二个参数发送出去。A根据接收到的rsp来决定后面的行为。

五、nonblocking端口

task A::main_phase(uvm_phase phase);my_transaction tr;repeat(10) begintr = new("tr");assert(tr.randomize());while(!A_port.can_put()) #10;void'(A_port.try_put(tr));end
endtask

由于端口变为了非阻塞的,所以在送出transaction之前需要调用can_put函数来确认是否能够执行put操作。can_put最终会调用B中的can_put:

六、analysis端口

UVM中还有两种特殊的端口:analysis_port和analysis_export。该端口有两点需要注意的地方:

  • 一个analysis_port(analysis_export)可以连接多个IMP,analysis_port(analysis_export)与IMP 之间的通信是一对多的通信。analysis_port(analysis_export)更像是一个广播。
  • put与get系列端口都有阻塞和非阻塞的区分。但是对于analysis_port和analysis_export来说,没有阻塞和非阻塞的概念。

一个analysis_port可以和多个IMP相连接进行通信,但是IMP的类型必须是uvm_analysis_imp,否则会报错。
在这里插入图片描述
下面是A的代码:

class A extends uvm_component;`uvm_component_utils(A)uvm_analysis_port#(my_transaction) A_ap;function new(string name, uvm_component parent);super.new(name, parent);endfunctionextern function void build_phase(uvm_phase phase);extern virtual  task main_phase(uvm_phase phase);
endclassfunction void A::build_phase(uvm_phase phase);super.build_phase(phase);A_ap = new("A_ap", this);
endfunctiontask A::main_phase(uvm_phase phase);my_transaction tr;repeat(10) begin#10;tr = new("tr");assert(tr.randomize());A_ap.write(tr);end
endtask

A的代码很简单,只是简单地定义一个analysis_port,并在main_phase中每隔10个时间单位写入一个transaction。
B的代码为:

function void B::write(my_transaction tr);`uvm_info("B", "receive a transaction", UVM_LOW) tr.print();
endfunction

在env中通过下面方式进行连接:

function void my_env::connect_phase(uvm_phase phase);super.connect_phase(phase);A_inst.A_ap.connect(B_inst.B_imp);A_inst.A_ap.connect(C_inst.C_imp);
endfunction

上面只是一个analysis_port与IMP相连的例子。analysis_export和IMP也可以这样相连接,只需将上面例子中的uvm_analysis_port改为uvm_analysis_export就可以。

七、monitor与scoreboard之间的通信

和上一个一样,在两段分别进行定义,monitor的代码为:

task my_monitor::main_phase(uvm_phase phase);my_transaction tr;while(1) begintr = new("tr");collect_one_pkt(tr);ap.write(tr);end
endtask

scoreboard的代码为:

function void my_scoreboard::write_monitor(my_transaction tr);my_transaction  tmp_tran;bit result;if(expect_queue.size() > 0) begintmp_tran = expect_queue.pop_front();result = tr.compare(tmp_tran);if(result) begin `uvm_info("my_scoreboard", "Compare SUCCESSFULLY", UVM_LOW);endelse begin`uvm_error("my_scoreboard", "Compare FAILED");$display("the expect pkt is");tmp_tran.print();$display("the actual pkt is");tr.print();endendelse begin`uvm_error("my_scoreboard", "Received from DUT, while Expect Queue is empty");$display("the unexpected pkt is");tr.print();end
endfunction

之后在env中可以使用connect连接。
由于monitor与scoreboard在UVM树中并不是平等的兄妹关系,这里选择下面的连接方式:
在agent中声明一个ap,但是不实例化它,让其指向monitor中的ap。在env中可以直接连接agent的ap到scoreboard的imp:

agent:
class my_agent extends uvm_agent ; uvm_analysis_port #(my_transaction) ap; ...  function void my_agent::connect_phase(uvm_phase phase); ap = mon.ap; ...  endfunction 
endclass 
env:
function void my_env::connect_phase(uvm_phase phase); o_agt.ap.connect(scb.scb_imp); ...  
endfunction

在上面的例子中,scoreboard只接收一路数据。但在现实情况中,scoreboard除了接收monitor的数据之外,还要接收reference model的数据。相应的scoreboard就要再添加一个 uvm_analysis_imp的IMP。此时问题就出现了,由于接收到的两路数据应该做不同的处理,所以这个新的IMP也要有一个write任务与其对应。但是write只有一个,怎么办?
可以使用宏定义的方法:

`uvm_analysis_imp_decl(_monitor)
`uvm_analysis_imp_decl(_model)
class my_scoreboard extends uvm_scoreboard;my_transaction  expect_queue[$];uvm_analysis_imp_monitor#(my_transaction, my_scoreboard) monitor_imp; uvm_analysis_imp_model#(my_transaction, my_scoreboard) model_imp;`uvm_component_utils(my_scoreboard)extern function new(string name, uvm_component parent = null);extern virtual function void build_phase(uvm_phase phase);extern virtual task main_phase(uvm_phase phase);
endclass 

上述代码通过宏uvm_analysis_imp_decl声明了两个后缀_monitor和_model。
当与monitor_imp相连接的analysis_port执行write函数时,会自动调用write_monitor函数,而与model_imp相连接的analysis_port执行write 函数时,会自动调用write_model函数。

八、使用FIFO通信

使用fifo的方法能够让两个端口都能实现主动的接收,因此下面的例子便是利用FIFO来实现monitor和scoreboard的通信。
FIFO的本质是一块缓存加两个IMP。在monitor与FIFO的连接关系中,monitor中依然是analysis_port,FIFO中是uvm_analysis_imp,数据流和控制流的方向相同。在scoreboard与FIFO的连接关系中,scoreboard中使用blocking_get_port端口:

class my_scoreboard extends uvm_scoreboard;my_transaction  expect_queue[$];uvm_blocking_get_port #(my_transaction)  exp_port[16];uvm_blocking_get_port #(my_transaction)  act_port;`uvm_component_utils(my_scoreboard)extern function new(string name, uvm_component parent = null);extern virtual function void build_phase(uvm_phase phase);extern virtual task main_phase(uvm_phase phase);
endclass 

而FIFO中使用的是一个get端口的IMP。在这种连接关系中,控制流是从scoreboard到FIFO,而数据流是从FIFO到scoreboard。

在env中连接方式如下:

function void my_env::connect_phase(uvm_phase phase);super.connect_phase(phase);i_agt.ap.connect(agt_mdl_fifo.analysis_export);mdl.port.connect(agt_mdl_fifo.blocking_get_export);for(int i = 0; i < 16; i++) beginmdl.ap[i].connect(mdl_scb_fifo[i].analysis_export);scb.exp_port[i].connect(mdl_scb_fifo[i].blocking_get_export);endo_agt.ap.connect(agt_scb_fifo.analysis_export);scb.act_port.connect(agt_scb_fifo.blocking_get_export); 
endfunction

FIFO中有两个IMP,但是在上面的连接关系中,FIFO中却是EXPORT,这是为什么呢?实际上,FIFO中的analysis_export和blocking_get_export虽然名字中有关键字export,但是其类型却是IMP。UVM为了掩饰IMP的存在,在它们的命名中加入了export关键字。
但事实上,FIFO上的端口并不局限于上述两个,一个FIFO中有众多的端口。端口列表如下:

总结

总结来说,这一章主要讲了数据在UVM中的传递方式,学习这一章可以更好的编写灵活性更高的UVM代码。

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

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

相关文章

uni-app项目上传至gitee方法详细教程

1. 准备工作 1.1 安装 Git 下载并安装 Git&#xff1a;前往 Git 官网&#xff0c;根据操作系统下载安装包。 配置用户名和邮箱&#xff08;需与 Gitee 账号一致&#xff09;&#xff1a; git config --global user.name "你的Gitee用户名" git config --global use…

走向多模态AI之路(三):多模态 AI 的挑战与未来

目录 前言一、多模态 AI 真的成熟了吗&#xff1f;二、多模态 AI 的主要挑战2.1 计算资源消耗&#xff1a;模型复杂度带来的成本问题2.2 数据标注困难&#xff1a;跨模态数据集的挑战2.3 对齐和融合的难点2.4 泛化能力与鲁棒性2.5 伦理与隐私问题 三、研究方向与未来发展3.1 轻…

STM32单片机入门学习——第12节: [5-2]对射式红外传感器计次旋转编码器计次

写这个文章是用来学习的,记录一下我的学习过程。希望我能一直坚持下去,我只是一个小白,只是想好好学习,我知道这会很难&#xff0c;但我还是想去做&#xff01; 本文写于&#xff1a;2025.04.03 STM32开发板学习——第12节: [5-2]对射式红外传感器计次&旋转编码器计次 前言…

汇编学习之《jcc指令》

JCC&#xff08;Jump on Condition Code&#xff09;指的是条件跳转指令&#xff0c;c中的就是if-else, while, for 等分支循环条件判断的逻辑。它包括很多指令集&#xff0c;各自都不太一样&#xff0c;接下来我尽量将每一个指令的c 源码和汇编代码结合起来看&#xff0c;加深…

深度解析算法之滑动窗口

12滑动窗口—将 x 减到 0 的最小操作数 题目传送门 题目描述&#xff1a; 给你一个整数数组 nums 和一个整数 x 。每一次操作时&#xff0c;你应当移除数组 nums 最左边或最右边的元素&#xff0c;然后从 x 中减去该元素的值。请注意&#xff0c;需要 修改 数组以供接下来的操…

[MySQL初阶]MySQL表的操作

MySQL表的操作 1. 创建表2. 查看表结构3. 修改表&#xff08;修改表的属性而非表的数据&#xff09;4. 删除表 1. 创建表 语法&#xff1a; CREATE TABLE table_name (field1 datatype,field2 datatype,field3 datatype ) character set 字符集 collate 校验规则 engine 存储…

sqlalchemy详细介绍以及使用方法

SQLAlchemy是一个Python的ORM&#xff08;对象关系映射&#xff09;工具&#xff0c;它允许开发者使用Python代码来操作数据库而不必直接编写SQL语句。SQLAlchemy提供了一种抽象层&#xff0c;使开发者可以通过简单的Python对象来表示数据库表和记录&#xff0c;从而实现对数据…

图解AUTOSAR_SWS_LINDriver

AUTOSAR LIN驱动详解文档 基于AUTOSAR标准的本地互联网络(LIN)驱动程序技术规范解析 目录 1. 概述 1.1 AUTOSAR LIN驱动简介1.2 LIN协议基础2. LIN驱动架构 2.1 类图结构2.2 状态机设计3. LIN帧结构 3.1 基本帧组成3.2 PID结构4. LIN驱动配置 4.1 主要配置参数4.2 配置结构5. L…

《网络管理》实践环节03:snmp服务器上对网络设备和服务器进行初步监控

兰生幽谷&#xff0c;不为莫服而不芳&#xff1b; 君子行义&#xff0c;不为莫知而止休。 应用拓扑图 3.0准备工作 所有Linux服务器上&#xff08;服务器和Agent端&#xff09;安装下列工具 yum -y install net-snmp net-snmp-utils 保证所有的HCL网络设备和服务器相互间能…

2025年内外网文件交换系统排名分析

在时代&#xff0c;企业的日常运营离不开内外网文件的交换。然而&#xff0c;传统的文件传输方式难以满足企业对多方面的要求。以下是一些备受关注的内外网文件交换系统及其排名分析。 第一名&#xff1a;阳途内外网文件交换系统 阳途内外网文件交换系统是一款专为解决内外网…

【Centos】centos7内核升级-亲测有效

相关资源 通过网盘分享的文件&#xff1a;脚本升级 链接: https://pan.baidu.com/s/1yrCnflT-xWhAPVQRx8_YUg?pwd52xy 提取码: 52xy –来自百度网盘超级会员v5的分享 使用教程 将脚本文件上传到服务器的一个目录 执行更新命令 yum install -y linux-firmware执行脚本即可 …

Qt进阶开发:QDirModel的使用

文章目录 一、QDirModel的基本介绍二、QDirModel的基本使用2.1 在 QTreeView 中显示文件系统2.2 在 QListView 显示当前目录2.3 在 QTableView 中使用 三、QDirModel的常用API1. 构造 & 目录操作1.1 创建 QDirModel1.2 设置根目录 2. 过滤 & 排序2.1 过滤文件类型2.2 设…

牛客 除2问题

除2&#xff01; 贪心堆 让偶数入堆 注意点&#xff1a; 1.判断堆是否为空再进行操作 2. 为了防止超时&#xff0c;我们采取先求和的方式&#xff0c;后面调整之后再减掉&#xff0c;可以节省一次遍历的时间。 3.注意数据范围&#xff0c;要用long long #include<iost…

#MySQL 语句大全(完整实用教程)

&#x1f4cc; MySQL 语句大全&#xff08;完整实用教程&#xff09; &#x1f4cc; 1. 数据库操作 ✅ 创建数据库 CREATE DATABASE mydb; -- 创建名为 mydb 的数据库✅ 使用数据库 USE mydb; -- 选择数据库✅ 删除数据库 DROP DATABASE mydb; -- 删除数据库&#xff08…

万字重谈C++——类和对象篇

什么是类&#xff1f; 在编程中&#xff0c;类是用来创建对象的模板。可以把类看作一个蓝图&#xff0c;它定义了对象的属性&#xff08;特征&#xff09;和方法&#xff08;行为&#xff09;。例如&#xff0c;如果我们有一个“学生”的类&#xff0c;它可能包含学生的名字、…

18认识Qt坐标系

平面直角坐标系(笛卡尔坐标系) 数学上的坐标系 右手坐标系 计算机中的坐标系 左手坐标系 坐标系的原点(0,0) 就是屏幕的左上角 /窗口的左上角 给 Qt 的某个控件,设置位置,就需要指定坐标.对于这个控件来说, 坐标系原点就是相对于父窗口/控件的. QPushButton 的父元素/父控件/父…

量子计算与人工智能的结合:未来科技的双重革命

引言 在过去几十年里&#xff0c;人工智能&#xff08;AI&#xff09;和计算能力的提升一直是推动科技进步的重要力量。然而&#xff0c;随着深度学习和大规模数据处理的发展&#xff0c;传统计算架构的算力瓶颈逐渐显现&#xff0c;人工智能的训练和推理效率受到了限制。在此背…

SEO长尾词优化策略精要

内容概要 长尾关键词优化是SEO策略中实现精准流量捕获的核心环节。本文从定位方法、搜索意图分析、词库构建三个维度切入&#xff0c;系统阐述如何通过数据化工具筛选高转化潜力词&#xff0c;并结合用户行为路径优化内容架构。具体而言&#xff0c;内容将覆盖关键词挖掘工具的…

基于大模型的主动脉瓣病变预测及治疗方案研究报告

目录 一、引言 1.1 研究背景 1.2 研究目的 1.3 研究意义 二、大模型预测主动脉瓣病变原理 2.1 大模型介绍 2.2 数据收集与处理 2.3 模型训练与优化 三、术前预测与评估 3.1 主动脉瓣病变类型及程度预测 3.2 患者整体状况评估 3.3 手术风险预测 四、术中应用与监测…

进程和内存管理

目录 一.进程的基本信息 1.1进程的定义 1.2进程的特征 1.3进程的组成 1.4线程产生的背景 1.5线程的定义 1.6进程与线程的区别 1.7进程的类别 1.8进程的优先级 1.8.1进程优先级的概念 1.8.2PRI和NI 1.9僵尸进程 1.9.1僵尸进程的定义 1.9.2僵尸进程产生的原因 1.9…