2023.7.25 UVM学习和环境搭建

2024-03-23 05:10
文章标签 学习 25 搭建 环境 uvm 2023.7

本文主要是介绍2023.7.25 UVM学习和环境搭建,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

1.验证平台的组成

2. UVM验证平台搭建

1)UVM中driver的搭建

2)增加factory机制

3)增加object机制

4)增加virtual interface


1.验证平台的组成

在这里插入图片描述

         验证平台通常由DUT(Design Under Test)、driver、monitor、reference model、scoredboard组成。

driver:用于生成各种激励,施加给DUT,验证其功能。

monitor:用于收集DUT的输出,传递给scoredboard。

scoreboard:给出判断功能正确的标准。

reference model:验证平台同样进行正确的DUT过程,提供正确的值。同样由driver施加激励。

        在UVM中,引入了agent和sequence,因此实际的验证平台如上所示。

2. UVM验证平台搭建

        以下列的DUT为例。

module dut(clk,rxd,rx_dv,txd,tx_en);
input clk;tx_input rst_n;
input[7:0] rxd;
input rx_dv;
output[7:0] txd;
output tx_en;reg[7:0] txd;
reg tx_en;always @(pospedge clk) beginif(!rst_n) begintxd <= 8'b0;tx_en <= 1'b0;endelse begintxd <= rxd;tx_en <= rx_dv;end
end
endmodule

        该DUT通过rxd接收数据,通过txd发送出去。rx_dv是接受的数据有效指示,tx_en是发送的数据有效指示。

1)UVM中driver的搭建

验证平台中的所有组件都派生自UVM中的类。简单的driver如下所示。wdd

class my_driver extends uvm_driver;function new(string name = "my_driver", uvm_component parent = null);super.new(name,parent);endfunction//派生自uvm_component中的类的new函数需要传入两个参数,string类型的name和parent,uvm_driver派生自uvm_component,所以也需要该参数。extern virtual task main_phase(uvm_phase phase);//UVM由phase来管理验证平台的运行,phase统一以xxxx_phase命名,需要传入uvm_phase类型的phase参数,driver中的行为均在main_phase中实现。
endclasstask my_driver::main_phase(uvm_phase phase);top_tb.rxd <= 8'b0;top_tb.rx_dv <= 1'b0;while(!top_tb.rst_n)@(posedge  top_tb.clk);for(int i = 0; i < 256; i++) begin@(posedge  top_tb.clk);top_tb.rxd <= $urandom(0, 255);top_tb.rx_dv <= 1'b1;`uvm_info("my_driver", "data is drived", UVM_LOW)end@(posedge  top_tb.clk);top_tb.rx_dv <= 1'b0;
endtask

有了验证平台,接下来是顶层的调用。

`timescale 1ns/1ps
`include "uvm_macros.svh" //uvm中的文件,包含众多的宏定义,只需要包含一次import uvm_pkg::*; //只有导入了该库,才能识别uvm_driver等类名
`include "my_driver.sv"module top_tb;
reg clk;
reg rst_n;
reg[7:0] rxd;
reg rx_dv;
reg[7:0] txd;
reg tx_en;dut my_dut(...);//正常的端口连接initial beginmy_driver drv;drv = new("drv", null);drv.main_phase(null);$finish;
endinitial beginclk = 0;forever begin#100 clk = ~clk;end
endinitial beginrst_n = 0;#1000;rst_n = 1'b1;
end
endmodule

        仿真时的vcs命令中-f file.f中不需要再包含my_driver.sv,因为已经将其include进来,包含该sv文件会报错。同时需要添加-ntb_opts uvm命令将uvm库导入编译器。

vcs -full64 -LDFLAGS -wl,-no-as-needed -V -R +v2k -sverilog -debug_all -f file.f \
-ntb_opts uvm -timescale=1ns/1ps

2)增加factory机制

上述例子中虽然基于UVM平台,但实际上仅仅使用SV依然可以实现。UVM提供了类的实例化机制——factory。factory机制被集成在了一个宏中:uvm_component_utils。通过使用该机制,将该类登记在了UVM内部。如下所示:

class my_driver extends uvm_driver;`uvm_component_utils(my_driver); //增加factory宏机制function new(string name = "my_driver", uvm_component parent = null);super.new(name,parent);endfunctionextern virtual task main_phase(uvm_phase phase);
endclasstask my_driver::main_phase(uvm_phase phase);`uvm_info("my_driver", "main_phase is called", UVM_LOW);top_tb.rxd <= 8'b0;top_tb.rx_dv <= 1'b0;while(!top_tb.rst_n)@(posedge  top_tb.clk);for(int i = 0; i < 256; i++) begin@(posedge  top_tb.clk);top_tb.rxd <= $urandom(0, 255);top_tb.rx_dv <= 1'b1;`uvm_info("my_driver", "data is drived", UVM_LOW);end@(posedge  top_tb.clk);top_tb.rx_dv <= 1'b0;
endtask

        同时,顶层的tb文件不需要实例化该类。只需要使用run_tes()语句即可。

initial begin
//    my_driver drv;
//    drv = new("drv", null);
//    drv.main_phase(null);
//    $finish;run_test("my_driver");
end

执行该代码,会打印如下内容:

new is called
main_phase is called

uvm_component_utils根据类名可以实例化一个类。并自动调用main_phase任务。所有派生自uvm_component及其派生类都应该使用uvm_component_utils宏注册。但是该任务时不正确的。因为缺少object机制,会导致程序被提前终止。

3)增加object机制

        object可以简单理解为finish函数的替代者。raise_objection和drop_objection总是成对出现。UVM通过objection机制控制验证平台的开启和关闭。raise_objection必须在main_phase中第一个消耗仿真时间的语句之前被提起。如下所示。

class my_driver extends uvm_driver;`uvm_component_utils(my_driver); function new(string name = "my_driver", uvm_component parent = null);super.new(name,parent);endfunctionextern virtual task main_phase(uvm_phase phase);
endclasstask my_driver::main_phase(uvm_phase phase);phase.raise_objection(this); //提起objection`uvm_info("my_driver", "main_phase is called", UVM_LOW);top_tb.rxd <= 8'b0;top_tb.rx_dv <= 1'b0;while(!top_tb.rst_n)@(posedge  top_tb.clk);for(int i = 0; i < 256; i++) begin@(posedge  top_tb.clk);top_tb.rxd <= $urandom(0, 255);top_tb.rx_dv <= 1'b1;`uvm_info("my_driver", "data is drived", UVM_LOW);end@(posedge  top_tb.clk);top_tb.rx_dv <= 1'b0;phase.drop_objection(this); //撤销objection
endtask

4)增加virtual interface

        上面的例程中对于顶层的信号均采用绝对路径的方式赋值,如top_tb.rx_dv <= 1'b1。使用绝对路径大大减弱了验证平台的可移植性。例如clk信号的层次从top_tb变成了top.clk_inst.clk,那么所有带有clk的语句都需要大量的修改。

        通过interface可以定义接口,在DUT和验证平台直接搭起一座桥梁。如下所示:

interface my_if(input clk, input rst_n);logic[7:0] data;logic valid; 
endinterface

        在定义了接口之后,top_tb中的实例化可以变为:

`timescale 1ns/1ps
`include "uvm_macros.svh" import uvm_pkg::*; 
`include "my_driver.sv"module top_tb;
reg clk;
reg rst_n;my_if input_if(clk, rst_n);
my_if output_if(clk, rst_n);dut my_dut(.clk(clk),.rst_n(rst_n),.rxd(input_if.data),.rx_dv(input_if.valid),.txd(output_if.data),.tx_en(output_if.valid));initial beginrun_test("my_driver");
endinitial beginclk = 0;forever begin#100 clk = ~clk;end
endinitial beginrst_n = 0;#1000;rst_n = 1'b1;
end
endmodule

        需要注意的是,类中不能使用上述方式声明一个interface,只有在module、program中才可以,在类中声明可以使用virtual interface:

virtual my_if vif;

        在声明了vif后,就可以在main_phase中使用如下方式驱动信号:

task my_driver::main_phase(uvm_phase phase);phase.raise_objection(this); //提起objection`uvm_info("my_driver", "main_phase is called", UVM_LOW);vif.rxd <= 8'b0;vif.valid <= 1'b0;while(!vif.rst_n)@(posedge  vif.clk);for(int i = 0; i < 256; i++) begin@(posedge  vif.clk);vif.rx <= $urandom(0, 255);vif.valid <= 1'b1;`uvm_info("my_driver", "data is drived", UVM_LOW);end@(posedge vif.clk);vif.valid <= 1'b0;phase.drop_objection(this); //撤销objection
endtask

        这样虽然消除了代码中的绝对路径,但是如何把顶层代码top_tb中的input_if和my_driver中的vif对应起来呢?由于UVM通过run_test建立的my_driver实例脱离了层次结构,建立了新的层次结构。所以对于这种脱离了top_tb的层次结构,同时又要在top_tb中对其进行某些操作的实例,可以使用UVM中的config_db机制。config_db分两步,set和get,set设置传送的内容,get设置接收的内容。

        在top_tb中增加如下代码:

initial beginuvm_config_db# (virtual my_if)::set(null, "uvm_test_top", "vif", input_if);
end

        set函数中的第二个参数表示路径的索引,即实例化的类所在的层次,可以通过在类中增加如下语句查看:

$display("the full name of current component is %s", get_full_name());

        run_test创建的my_driver的实例为uvm_test_top。set函数的第三个参数是一个标识,需要和get中的第三个参数完全一样。第四个参数表示要将哪个interface通过config_tb传递给my_driver。

        在my_driver中,可以引入build_phase函数来规范配置。和main_phase一样,build_phase也是uvm中的内建phase。uvm启动后会自动执行,顺序在new之后,main之前。build_phase中主要通过config_db的set和get操作传递一些数据,以及实例化成员变量等。

        

virtual function void biuld_phase(uvm_phase phase);super.build_phase(phase);`uvm_info("my_driver", "build_phase is called", UVM_LOW);if(!uvm_config_db# (virtual my_if)::get(this, "", "vif", vif))`uvm_fatal("my_driver", "virtual interface must be set for vif!!!")
endfunciton

        最终的my_driver如下:

class my_driver extends uvm_driver;virtual my_if vif;`uvm_component_utils(my_driver); function new(string name = "my_driver", uvm_component parent = null);super.new(name,parent);endfunctionextern virtual task main_phase(uvm_phase phase);extern virtual function void build_phase(uvm_phase phase);
endclassfunction void build_phase(uvm_phase phase);super.build_phase(phase);`uvm_info("my_driver", "build_phase is called", UVM_LOW);if(!uvm_config_db# (virtual my_if)::get(this, "", "vif", vif))`uvm_fatal("my_driver", "virtual interface must be set for vif!!!")
endfuncitontask my_driver::main_phase(uvm_phase phase);phase.raise_objection(this); //提起objection`uvm_info("my_driver", "main_phase is called", UVM_LOW);vif.rxd <= 8'b0;vif.valid <= 1'b0;while(!vif.rst_n)@(posedge  vif.clk);for(int i = 0; i < 256; i++) begin@(posedge  vif.clk);vif.rx <= $urandom(0, 255);vif.valid <= 1'b1;`uvm_info("my_driver", "data is drived", UVM_LOW);end@(posedge vif.clk);vif.valid <= 1'b0;phase.drop_objection(this); //撤销objection
endtask

        get函数的第四个参数表示把得到的interface传递给哪个my_driver的成员变量。

        uvm_config_db# (virtual my_if)是一个参数化的类,其参数就是要寄信的类型。使用::是因为set和get都是静态函数。假如要像my_driver的var变量传递一个int类型的数据,那么可以使用如下方式:

initial beginuvm_config# (int)::set(null, "uvm_test_top", "var", 100);
end

        my_driver中是如下方式

class my_driver extends uvm_driver;int var;virtual function void build_phase(uvm_phase phase);super.build_phase(phase);`uvm_info("my_driver", "build_phase is called", UVM_LOW);if(!uvm_config_db# (virtual my_if)::get(this, "", "vif", vif))`uvm_fatal("my_driver", "virtual interface must be set for vif!!")if(!uvm_config_db# (int)::get(this, "", "var", var))`uvm_fatal("my_driver", "var must be set!!")endfuncion
endclass

        如果需要传递多个值,如下所示:

initial beginif(!uvm_config_db# (virtual my_if)::set(null, "uvm_test_top", "vif", input_if))if(!uvm_config_db# (virtual my_if)::set(null, "uvm_test_top", "vif2", output_if))
end
virtual my_if vif;
virtual my_if vif2;
virtual function void build_phase(uvm_phase phase);super.build_phase(phase);`uvm_info("my_driver", "build_phase is called", UVM_LOW);if(!uvm_config_db# (virtual my_if)::get(this, "", "vif", vif))`uvm_fatal("my_driver", "virtual interface must be set for vif!!!")if(!uvm_config_db# (virtual my_if)::get(this, "", "vif2", vif2))`uvm_fatal("my_driver", "virtual interface must be set for vif2!!!")
endfunciton

这篇关于2023.7.25 UVM学习和环境搭建的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/837228

相关文章

Android开发环境配置避坑指南

《Android开发环境配置避坑指南》本文主要介绍了Android开发环境配置过程中遇到的问题及解决方案,包括VPN注意事项、工具版本统一、Gerrit邮箱配置、Git拉取和提交代码、MergevsR... 目录网络环境:VPN 注意事项工具版本统一:android Studio & JDKGerrit的邮

IntelliJ IDEA 中配置 Spring MVC 环境的详细步骤及问题解决

《IntelliJIDEA中配置SpringMVC环境的详细步骤及问题解决》:本文主要介绍IntelliJIDEA中配置SpringMVC环境的详细步骤及问题解决,本文分步骤结合实例给大... 目录步骤 1:创建 Maven Web 项目步骤 2:添加 Spring MVC 依赖1、保存后执行2、将新的依赖

Java学习手册之Filter和Listener使用方法

《Java学习手册之Filter和Listener使用方法》:本文主要介绍Java学习手册之Filter和Listener使用方法的相关资料,Filter是一种拦截器,可以在请求到达Servl... 目录一、Filter(过滤器)1. Filter 的工作原理2. Filter 的配置与使用二、Listen

Python如何自动生成环境依赖包requirements

《Python如何自动生成环境依赖包requirements》:本文主要介绍Python如何自动生成环境依赖包requirements问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑... 目录生成当前 python 环境 安装的所有依赖包1、命令2、常见问题只生成当前 项目 的所有依赖包1、

Redis在windows环境下如何启动

《Redis在windows环境下如何启动》:本文主要介绍Redis在windows环境下如何启动的实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Redis在Windows环境下启动1.在redis的安装目录下2.输入·redis-server.exe

Pytest多环境切换的常见方法介绍

《Pytest多环境切换的常见方法介绍》Pytest作为自动化测试的主力框架,如何实现本地、测试、预发、生产环境的灵活切换,本文总结了通过pytest框架实现自由环境切换的几种方法,大家可以根据需要进... 目录1.pytest-base-url2.hooks函数3.yml和fixture结论你是否也遇到过

利用Python快速搭建Markdown笔记发布系统

《利用Python快速搭建Markdown笔记发布系统》这篇文章主要为大家详细介绍了使用Python生态的成熟工具,在30分钟内搭建一个支持Markdown渲染、分类标签、全文搜索的私有化知识发布系统... 目录引言:为什么要自建知识博客一、技术选型:极简主义开发栈二、系统架构设计三、核心代码实现(分步解析

浅谈配置MMCV环境,解决报错,版本不匹配问题

《浅谈配置MMCV环境,解决报错,版本不匹配问题》:本文主要介绍浅谈配置MMCV环境,解决报错,版本不匹配问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录配置MMCV环境,解决报错,版本不匹配错误示例正确示例总结配置MMCV环境,解决报错,版本不匹配在col

使用Python实现快速搭建本地HTTP服务器

《使用Python实现快速搭建本地HTTP服务器》:本文主要介绍如何使用Python快速搭建本地HTTP服务器,轻松实现一键HTTP文件共享,同时结合二维码技术,让访问更简单,感兴趣的小伙伴可以了... 目录1. 概述2. 快速搭建 HTTP 文件共享服务2.1 核心思路2.2 代码实现2.3 代码解读3.

MySQL双主搭建+keepalived高可用的实现

《MySQL双主搭建+keepalived高可用的实现》本文主要介绍了MySQL双主搭建+keepalived高可用的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,... 目录一、测试环境准备二、主从搭建1.创建复制用户2.创建复制关系3.开启复制,确认复制是否成功4.同