UVM学习知识点

UVM构建

    • include 和 import pkg区别
    • .sv .svh
    • hdl_top.sv和hvl_top.sv
    • 回顾uvm_config,以及自定义uvm_config
    • verilog:parameter、defparam与 localparam
    • test_base
      • build_phase
      • end_of_elaboration_phase
      • function void configure_agent
      • set_seqs
      • end_of_elaboration_phase
      • uvm_comfig_db#()set
    • env_config
      • do_cm_agent_cfg()
      • function cm_env_config get_config(uvm_component c)
    • cm_defines.svh
    • cm_cfg_pkg.svh
    • cm_ad_random_test
      • run_phase
    • hdl_top.sv
    • hvl_top
    • cm_env.svh
      • build
      • connect_phase
    • cm_env_pkg.svh
    • cm_virtual_sequencer
    • cm_agent
      • build
      • connect
    • cm_agent_config
    • cm_scoreboard
      • build
      • run
      • report_phase
    • cm _reference_model
    • driver
      • build
      • run
      • `get_config
      • driver 参数
    • cm_driver_bfm
    • cm_monitor
      • build
      • run
      • function
    • cm_monitor_bfm
    • cm_sequencer
    • Virtual Sequence & Virtual Sequencer
    • ?
      • 1
    • set 与 get 函数的参数

include 和 import pkg区别

1.作用
`include与C语言中类似,用于在一个文件中插入另一个文件;import用于在一个作用域中引入一个package(或其中的内容),使得这些内容在当前作用域中可以不添加其所在的package就能被识别。

2.用途
`include把一个文件平铺在插入的文件中,这个过程发生在编译前。

与verilog中类似,可以把宏定义的参数放在一个文件中,再使用`include插入所需的文件中,使代码更加整洁。

也可以将一个类写在一个头文件中,使用extern方法,在另一个文件中定义类中的方法,方便管理和加密,最后再将所有的文件统一`include到顶层,
而import发生在编译后,将已编译的package的作用域扩展到import的域中,例如文章开头的通过import引入uvm_pkg,从而使自己的验证环境可以使用UVM的特性和机制
在编程中,include 和 import 是两个常用的关键字,但它们在不同的编程语言和上下文中具有不同的含义和用法。

include:

include 是 C 和 C++ 编程语言中的预处理指令。它用于在源代码中包含外部文件的内容,通常用于包含头文件(header files)。
头文件通常包含函数声明、宏定义和数据结构的定义等内容,可以在多个源文件中共享和重用。
include 指令会在预处理阶段将被包含的文件的内容插入到当前文件中,相当于将文件内容复制粘贴到当前位置。
import:

import 是许多编程语言中用于导入外部模块或包的关键字,例如 Python、Java、JavaScript 等。
在不同的语言中,import 的用法和功能可能会有所不同。一般而言,它用于引入其他模块或包的定义,使得你可以在当前代码中使用这些定义。
在 UVM(Universal Verification Methodology)中,include 和 import 也有一些不同的用法和含义。
include 在 UVM 中:
在 UVM 中,include 通常用于包含 UVM 的库文件、基类和一些通用定义,例如 UVM 中的基类(uvm_object、uvm_component 等)和一些宏定义。
include 在 UVM 中用于将这些共享的定义引入到你的测试环境或测试用例中,以便你可以使用 UVM 提供的功能和方法。
import 在 UVM 中:
在 UVM 中,import 关键字用于引入 UVM 命名空间中的类或函数,以便在你的代码中可以直接使用它们的名称,而无需使用完整的命名空间路径。
UVM 使用了一系列的命名空间,例如 uvm_pkg 命名空间。通过 import 可以简化代码中对 UVM 类和方法的引用。
` include将文件中所有文本原样插入包含的文件中。这是一个预处理语句

`include在import之前执行。他的主要作用就是在package中平铺其他文件,从而在编译时能够将多个文件中定义的类置于这个包中,形成一种逻辑上的包含关系。

import不会复制文本内容。但是import可package中内容引入import语句所在的作用域,以帮助编译器能够识别被引用的类,并共享数据。

在我们的TB中,include通常分为以下几类:

1)package内的include文件:在package内,前面是import library,比如“import uvm_pkg:”,紧接着即使include文件,通常会把本目录下相关的文件都include进来,比如virtual sequence文件,testcase文件。

2)package外的include文件:这种用法在我们现在的环境中使用不多,目前最常用的是include interface文件,比如,在xxx_env_pkg文件的最开头,include “xxx_if.sv”

3)为了文件管理方法,将部分code写到一个单独的文件中,然后在主文件中直接include进来,相当于将多个文件合并成一个文件。比如,一个subsys要用到很多API,而这些API共有A, B,C三类,分别由3个人完成,则可以写成api_a.sv, api_b.sv, api_c.sv,在l0_basic_vseq.sv中,将这三个文件include进来。

https://blog.csdn.net/Andy_ICer/article/details/115679314

.sv .svh

.svh后缀的文件即systemverilog include文件,如其名,是为了include到其它文件里面去的文件。
.sv 文件与.svh文件没有本质区别。通常,需要被include 到package的文件定义为.svh类型, 其他的文件定义为.sv类型。
.svh后缀的文件即systemverilog include文件。
1、package内的类应该用include分隔为单独的文件。
2、按照编译顺序排列。
3、include中不应该还包含include。

hdl_top.sv和hvl_top.sv

hdl_top.sv 和 hvl_top.sv 是在硬件设计和硬件验证中经常使用的两个文件,分别用于硬件描述语言(HDL)的顶层设计和硬件验证语言(HVL)的顶层测试环境。

hdl_top.sv:
这个文件通常用于硬件描述语言(如 Verilog、VHDL)中的顶层设计。
在 hdl_top.sv 文件中,你会描述整个硬件系统的结构、功能和连接关系。这可能包括处理器、外设、数据通路等。
该文件会被综合工具用来生成实际的硬件电路。
hvl_top.sv:
这个文件通常用于硬件验证语言(如 SystemVerilog)中的顶层测试环境。
在 hvl_top.sv 文件中,你会创建和配置测试环境,生成测试用例,并驱动这些测试用例进行硬件验证。
这个文件会包括 UVM(Universal Verification Methodology)或其他验证方法学的相关代码,以及测试用例生成和管理的逻辑。
在典型的硬件验证流程中,hdl_top.sv 和 hvl_top.sv 两者协同工作。hdl_top.sv 描述了你要验证的硬件设计,而 hvl_top.sv 创建了测试环境,使用测试用例对 hdl_top.sv 中的设计进行验证。

回顾uvm_config,以及自定义uvm_config

class env_config extends uvm_object

verilog:parameter、defparam与 localparam

在 Verilog 语言中,parameter、defparam 和 localparam 都是用来定义常量的关键字,但它们有不同的用途和范围。下面我会为您解释它们的区别:

parameter:
parameter 用于在模块级别定义一个常量,该常量在编译时被确定,并可以在整个模块中使用。
它用于指定在模块实例化时需要传递的参数值,这些参数值可以在模块的内部使用。也可以用于定义宏、宏定义和一些常量值。
在模块中,parameter 常量可以直接使用,无需使用模块的实例名称来引用。

module MyModule #(parameter PARAM_VALUE = 8);
  // PARAM_VALUE is a parameter with default value 8
  // You can use PARAM_VALUE within this module
endmodule

defparam:
defparam 用于在模块实例化之外设置模块的参数值。
通常在模块实例化后,使用 defparam 可以修改模块实例的参数值。这样做可以避免在模块定义时传递参数,而在实例化时设置参数,从而更灵活地控制模块行为。
defparam 在一些情况下可能会影响代码的可读性,因此在实践中应该谨慎使用。


module Test;
  MyModule my_inst(); // Instantiate the module
endmodule

// Change the parameter value of my_inst using defparam
defparam my_inst.PARAM_VALUE = 10;

localparam:
localparam 用于在模块中定义一个局部常量,只能在该模块内部使用。
localparam 的值在编译时确定,但是它只在定义它的模块内部可见,无法在模块实例化时传递或在其他模块中使用。


module MyModule;
  localparam LOCAL_PARAM = 5; // A local parameter within the module
endmodule

总结:

parameter 用于定义模块内部的常量,可以在实例化时传递。
defparam 用于在模块实例化之外修改模块的参数值。
localparam 用于定义模块内部的局部常量,只在该模块内部可见。
1、最好运用模块在端口的声明方式,参数覆盖用参数值模块例化。

2、不要用defparam去修改在实体内声明的parameter,因为不可综合,用带参数值模块例化可以。

3、localparam参数可通过parameter赋值进行间接的修改,不能用其他方法修改。

两种声明方式混用时,vivado综合工具会把parameter变成local parameter,其他工具未知。

两种parameter声明方式混用的时候,defparam与参数值模块例化两种方法vivado均会报错,因为local parameter不可被直接改变。
单独使用parameter,无local的警告
https://zhuanlan.zhihu.com/p/420873197

test_base

例化
cm_env env
cm_env_config env_cfg
cm_agent_config agt_cfg
//methods
function void configure_cm_agent
//Standard methods
new
build_phase
set_seqs
function void end_of_elaboration_phase

build_phase

env_cfg
env
cm_agt_cfg
configure_cm_agent(agt_cfg)
get cm_mon_bfm,agt_cfg.mon_bfm
get cm_drv_bfm,agt_cfg.mon_bfm
env_cfg.agent_cfg = cm_agt_cfg
set (this, " * ",“cm_env_config”,env_cfg)
set (this, " * ",“cm_agent_config”,agt_cfg)

end_of_elaboration_phase

uvm_root::get().set_report_verbosity_level_hier(UVM_HIGH);
uvm_root::get().set_report_max_quit_count(10);

function void configure_agent

function void configure_cm_agent(agent_config cfg)
配置agt_configure
agt_cfg.active = …;

set_seqs

set_seqs(cm_base_virtual+sequence seq)
seq.cfg = env.cfg

end_of_elaboration_phase

在 UVM(Universal Verification Methodology)中,end_of_elaboration_phase 是一种阶段(phase),用于表示仿真环境中的一个特定时间点,通常用于进行一些最终的配置和准备工作,以便在仿真运行开始之前完成环境的设置。

具体来说,end_of_elaboration_phase 位于 UVM 测试基类 uvm_test 中的默认构造函数中,是 UVM 生命周期中的一个重要阶段。在这个阶段,测试环境的配置和连接已经完成,但还没有开始进行实际的仿真运行。

在 end_of_elaboration_phase 阶段,您可以执行以下操作:

完成环境的配置和连接:在此阶段,可以确认环境中的各个组件是否正确连接,并根据需要进行修复或调整。

设置参数和信号:您可以在此阶段设置各个组件的参数,包括一些与实际测试相关的参数。

收集信息和报告:您可以在此阶段生成一些初始化的报告,以便在仿真运行之前检查环境的状态和配置。

进行一些前期准备工作:例如,为测试用例生成随机种子、设置文件路径等。

需要注意的是,end_of_elaboration_phase 阶段是在 UVM 生命周期的早期阶段,仅用于环境的初始化和准备工作。在这之后,会进入 run_phase 阶段,开始进行实际的仿真运行。根据您的具体测试需求,您可以在 end_of_elaboration_phase 中执行适当的操作,以确保仿真环境在运行时处于正确的状态

这段代码是在 UVM(Universal Verification Methodology)中设置报告的详细程度和最大退出计数的操作。让我为您解释一下这两个函数的作用:

uvm_root::get().set_report_verbosity_level_hier(UVM_HIGH);:

这行代码设置了报告的详细程度(verbosity level)为 UVM_HIGH,这是一种 UVM 预定义的报告详细程度。
报告详细程度用于控制报告信息的显示级别。在高详细程度下,会显示更多的报告信息,包括警告和错误信息。
uvm_root::get() 返回 UVM 根实例,通过调用 set_report_verbosity_level_hier() 方法,您可以设置整个测试环境中所有组件的报告详细程度为 UVM_HIGH。
uvm_root::get().set_report_max_quit_count(10);:

这行代码设置了最大退出计数(max quit count)为 10。这是当发生错误时,仿真环境最多允许退出的次数。
如果测试中出现了一些严重错误,导致测试环境需要退出,但测试尚未结束,系统会尝试退出一定次数后继续进行,以便收集更多的错误信息。
该函数调用可以用于设置最大退出次数,以控制在错误情况下的退出行为。
这些函数调用的目的是在测试环境中配置报告行为和退出行为,以便更好地进行调试和错误定位。您可以根据需要选择不同的报告详细程度,并设置适当的最大退出计数,以符合您的测试需求。

uvm_comfig_db#()set

set第二个参数可以使用通配符*

get种一般第一个参数为this,则第二个参数可以是“”

env_config

localparam string s_my_config_id = “cm_env_config”
localparam string s_no_config_id =
localparam string s_my_config_type_error_id =

bit has_cm_function_coverage = 0;
bit has_cm_reg_scoreboard = 0;
//bit has_cm_scoreboard = 0;
//配置下属组件
cm_agent_config cm_agent_cfg
virtual cm_if vif
注册
extern static function cm_env_config get_config(uvm_component c)
new
do_cm_agent_cfg()

do_cm_agent_cfg()

cm_agent_cfg.name = ,,,;

赋值

function cm_env_config get_config(uvm_component c)

cm_env_config t;
get(c,“”, s_my_config_id ,t)
return t;

cm_defines.svh

cm_cfg_pkg.svh

cm_ad_random_test

注册
new
build_phase
task run_phase

run_phase

cm_ad_random_virt_seq random_ad_seq = create
phase.raise_objection(this,"cm_ad_random_test’);
random_ad_seq.start(env.m_vsqr);
#100ns;
phase.drop_objection(this,"cm_ad_random_test’);

hdl_top.sv

`timescale
logic clk
logic rstn
cm_if CM(clk, rstn)

//BFM interfaces
cm_monitor_bfm cm_mon_bfm
cm_driver_bfm cm_drv_bfm
//DUT
cm_math DUT(…
)

initial begin
import uvm_pkg::uvm_config_db;
set cm_mon_bfm
set cm_drv_bfm
end

initial begin
clk
end

initial begin
rstn
repeat(4)
rstn
end

hvl_top

`time
im uvm_pkg: ;
im cm_test_lib_pkg:: *

initial begin
//vcd
end

initial begin
run_test();
end

cm_env.svh

注册
//data members
cm_env_config m_env_cfg;
cm_agent m_agt;
cm_scoreboard m_scb;
cm_viryual_sequencer  m_vsqr;

new
build
connect_phase

build

//env_config
get (this, " * ","cm_env_config",m_env_cfg)
//agent_config
get (this, " * ","cm_agent_cfg",m_env_cfg.cm_agent_cfg)
m_agt = cm_agent::creat
if(m_env_cfg.has_cm_scoreboard)begin
m_scb = cm_scoreboard::type_id::creat(
set(this, "m_scb", "m_env_cfg", m_env_cfg);
//vsqr
set(this, "m_vsqr", "m_env_cfg", m_env_cfg);			//???
m_vsqr = cm_virtual_sequencer::type_id::creat(

connect_phase

if(m_env_has_complex_scoreboard)begin
magt.m_monitor.scb_ap.connect(m_scb.cm_imp.analysis_export);
end

m_vsqr.sqr = m_agt.m_sequencer

cm_env_pkg.svh

cm_virtual_sequencer

cm_sequencer sqr
cm_env_config cfg

virtual cm_vif vif

new
build
get (this, " * ",“cm_env_config”,cfg)
vif = cfg.vif

cm_agent

cm_gent_cofig m_cfg
m_monitor
m_sequencer
m_driver
m_subscriber

new
build
connect

build

get (this, " * ",“cm_agent_config”,m_cfg)

m_monitor = creat
m_monitor.m_cfg = m_cfg
set m_monitor

m_driver
m_driver.m_cfg = m_cfg
set m_driver

m_sequencer
set m_sequencer

m_subscriber

connect

scb_ap = m_monitor.scb_ap
m_driver.seq_item_port.connect(m_sequencer.seq_item_export)

m_monitor.sub_ap.connect(m_subscriber.analysis_export)

cm_agent_config

localparam string s_my_config_id = “cm_env_config”
localparam string s_no_config_id =
localparam string s_my_config_type_error_id =

virtual cm_monitor_bfm mon_bfm;
virtual cm_driver_bfm drv_bfm;

uvm_active_passive_enum active = UVM_ACTIVE;

bit has_cm_function_coverage = 1;
//bit has_cm_reg_scoreboard = 0;
rand bit has_scoreboard = 1;
好几个
field
//下面是个方法,set是在test_base.
function cm_agent_config get_config(uvn_component c)
cm_agent_config t;
get(c,“”, s_my_config_id ,t)
return t;

cm_scoreboard

cm_env_config cfg
uvm_tlm_analysis_fifo #(cm_seq_item) cm imp;

cm_reference_model complex_rm;
//data buffers
cm_seq_item tr_observed[ ] ; c m s e q i t e m t r e x p e c t e d [ ]; cm_seq_item tr_expected[ ];cmseqitemtrexpected[];

//cvoreboard var
new

build

new
new
get (this, " * ",“cm_env_config”,cfg)

run

cm_compare()

report_phase

cm _reference_model

//data_buffers
//statistics
//new

function void calculate()

driver

class cm_driver extends uvm_driver#(cm_seq.item,cm_seq_item);
virtual cm_driver_bfm m_bfm;
cm_agent_config m_cfg;
new
run
build

build

`get_config(cm_agent_config, m_cfg, “am_agent_config”)
m_bfm = m_cfg.drv_bfm

run

complex_seq_item req;
complex_seq_item rsp;
int psel_index;

m_bfm.m_cfg = m_cfg;

`get_config

`get_config(cm_agent_config, m_cfg, “am_agent_config”)
这段代码是使用 UVM(Universal Verification Methodology)中的 uvm_config_db 工具获取配置信息的示例。让我为您解释一下这段代码的含义:

get_config:这是 uvm_config_db 工具的一个方法,用于获取配置信息。

cm_agent_config:这是配置信息的目标对象的类型。在这个例子中,cm_agent_config 是一个类或数据结构,它定义了配置信息的格式。

m_cfg:这是一个变量,用于存储从配置数据库中获取的配置信息。根据代码,它似乎是一个类的实例。

“am_agent_config”:这是一个字符串,表示要获取的配置信息的名称。配置信息通常以字符串形式进行标识,以便在数据库中查找匹配的配置。

在上述代码中,get_config 方法的目的是从配置数据库中获取名为 “am_agent_config” 的配置信息,并将其存储在 m_cfg 变量中,该变量的类型是 cm_agent_config。

driver 参数

extends uvm_driver#(cm_seq.item, cm_seq_item):通过 extends 关键字,cm_driver 类继承自 uvm_driver 类,并在括号中使用泛型参数指定了序列项类型。具体来说:

uvm_driver#(cm_seq.item, cm_seq_item) 表示 cm_driver 是一个 uvm_driver 类的子类,其中 cm_seq.item 和 cm_seq_item 是泛型参数,分别表示输入序列项类型和输出序列项类型。

cm_driver_bfm

interface cm_driver_bfm(
cm_agent_config m_cfg
function ini_sigs
functio drive
)

cm_monitor

virtual cm_driver_bfm m_bfm;
cm_agent_config m_cfg;
uvm_analysis_port#(cm_seq_item) scb_ap;
uvm_analysis_port#(cm_seq_item) sub_ap;

new
run
build
report

build

`get_config(cm_agent_config, m_cfg, “cm_agent_config”)
m_bfm = m_cfg.mon_bfm
m_bfm.mnt = this;
new
new

run

m_bfm.run()

function

void cm_monitor::mnt.notofy_transaction(item);
scb_ap.write(item);
sub_ap.write(item);

cm_monitor_bfm

interface cm_monitor_bfm(
cm_monitor mnt
function ini_sigs
functio drive

task run();

mnt.notofy_transaction(item);

)

cm_sequencer

cm_agent_config cfg
new
build
reconfigure(cm_agent_config cfg)
get_cfg(ref cm_agent_config cfg_)

Virtual Sequence & Virtual Sequencer

https://zhuanlan.zhihu.com/p/369681031#%E4%BB%80%E4%B9%88%E6%97%B6%E5%80%99%E9%9C%80%E8%A6%81%E4%B8%80%E4%B8%AAvirtual%20Sequencer%EF%BC%9F

?

1

extern virtual function void configure_complex_agent(complex_agent_config cfg)

function void tesr_base::configure_complex_agent(complex_agent_config cfg);
agt_cfg.active = UVM_ACTIVE;

set 与 get 函数的参数

1.写信
在这里插入图片描述

1)第一个和第二个参数联合起来组成目标路径,与此路径符合的目标才能收信。

2)第一个参数必须为uvm_component 的实例的指针。

3)第二个参数是相对于此实例的路径。

2.收信

在这里插入图片描述

1)第一个参数必须为uvm_component 的实例的指针。

2)第二个参数是相对于此实例的路径。如果第一个设置为 this,第二个可以是空的字符串。
3)第三个参数必须和set中的严格一样。

3.在top_tb 中,set virtual interface 的第一个参数是null。UVM会自动把它替换成uvm_root::get(),即uvm_top。(uvm_root是全局的,get是静态的)

4.既然是第一个和第二个参数联合起来的,set 也可以是下面:
在这里插入图片描述

5 get也可以这样,比如driver的build_phase:
在这里插入图片描述

https://blog.csdn.net/tingtang13/article/details/46458869

你可能感兴趣的:(学习,UVM)