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