这里是引用
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.youkuaiyun.com/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);
?11
function void configure_agent
function void configure_cm_agent(agent_config cfg)
配置agt_configure
agt_cfg.active = …;
agt cfg.active = UVM ACTIVE;
agt cfg.has functional coverage = 1;
agt cfg.has scoreboard = 1;
agt cfg.total random = 1;
agt cfg.random times all = 100;
agt cfg.random times each = 10;
agt cfg.enable put response = 1;
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
//opccode
parameter ADD = 4’d0;
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_if
一些接口信号比如溢出输入输出
property vld_valid;
‘’’
;;;
task wait_rstn_release();
@(posedge rstn);
endtask
cm_driver_bfm
接口信号比如溢出输入输出
`include “uvm_macros.svh”
import uvm_pkg::;
import cm_agt_pkg::;
cm_agent_config m_cfg;
function void ini_sigs();
初始化接口信号
task drive (cm_seq_item seq);
repeat(seq.delay)
@(posedge clk);
i_vld <= 1;
sat <= seq.sat
@(posedge clk);
?
cm_monitor_bfm
接口信号比如溢出输入输出
import cm_agt_pkg:😗;
cm_monitor mnt;
task run();
cm_seq_item item, cloned_item;
item = ::creat(“item”);
forever begin
@(posedge i_vld);
item.sat = sat;
…
@(posedge i_vld);
@(posedge i_vld);
item.o_vld = o_vld;
…
mnt.notify_transation(item);
end
endtask: run
cm_seq_item
rand logic [31:0] mul1;
接口信号数据
rand int delay;
bit error;
constriaint input_range {
opcode inside{[0:12]};
}
constriaint delay_bounds {
delay inside{[1:20]};
}
function
new
void do_copy(uvm_object rhs);
bit do_compare(uvm_object rhs, uvm_comparer comparer);
string conver2string();
void do_print(uvm_printer printer);
void do_record(uvm_recorder recoeder);
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
function driver
)
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
bit manage_objection = 1;
uvm_report_objection report = this;
protected bit isrunning;
cm_agent_config cfg
uvm_component_utils_begin(cm_sequenser)
uvm_field_objection(cfg, UVM_ALL_ON)
`uvm_component_utils_end
new
build
reconfigure(cm_agent_config cfg)
get_cfg(ref cm_agent_config cfg_)
virtual_if vif
build
string method_name = "build_phase"
begin
if(cfg == null) begin
if (get (,,,cfg) && (cfg!=null) begin
`uvm_info(method_name, "get configure ok", UVM_LOW)
`uvm_info("TEST123 ",$sformatf(get configure random_total %d ", cfg.total_random UVM_LOW)
if(!($cast(this.cfg, cfg.clone()))) begin
`uvm_fatal
end
end else begin
`uvm_fatal(
end
end
end
function void cm_sequencer::reconfigure(cm_agent_config cfg);
if (!($cast(this.cfg, cfg.clone()))) begin
`uvm_error(“reconfigure”, “Failed attempting to assign ‘cfg’ argument to sequencer 'cfg’field.”)
end
endfunction
function cm_sequencer::get_cfg(ref cm_agent_config cfg_);
cfg_ = cfg;
`uvm_info("TEST123 ",$sformatf(get configure random_total %d ", cfg.total_random UVM_LOW)
cm_add_random_virt_seq
注册
new
virtual task body();
super.body();
`uvm_do_on(add_seq_r, p_sequencer.sqr)
endtask
cm_base_virtual_sequence
virtual cm_if vif;
cm_env env;
cm_env_config cfg;
cm_random_seq random_seq;
cm_add_random_seq add_seq_r;
…
`uvm_declare_p_sequencer(cm_virtual_sequencer)
new
task body();
vif = p_sequencer.vif;
cfg= p_sequencer.cfg;
void‘($cast(env, p_sequencer.m_parent));
virtual class cm_base_sequence extend uvm_sequencr #(cm_seq_item)
//opcode control
rand logic add = -1;
…
//input control
rand logic [31:0] mul = 0;
…
//timing control
rand int delay = 5;
cm_agent_config cfg;
`uvm_declare_p_sequencer(cm_virtual_sequencer)
new
virtual task body();
p_sequncer.get_cfg(cfg);
endtask
cm_add_random_seq
注册
cm_seq_item req, rsp;
new
virtual task body();
super.body();
add = cfg.random_tinmes_each;
for(int i = 0 ; i <32'hffffffff; i++) begin
`uvm_do_with(req, {
opcode ==0;
add1== i;
add2== i;
acc1==i;
acc2==i;
})
end
`uvm_do_with(req, {local::cmac >0 -> opcode ==11;
acc1 == 2})
```