引言
UVMC引入特定的内存共享方法,可以在UVM Systemverilog 与SystemC 模块之间传递记名的半全局变量,在使用方式上类似UVM build-in提供的config_db方法,可以传递字符串,整形数据(byte/int/bit-- char/int/long)和对象结构,在传递对象时需要对packet 结构打包成字符流
一 . config api函数
在UVM layer层的config 函数与惯例一致,需要通过泛型指定传递的数据类型,对于UVMC 所在的SystemC layer,有set/get 各3个传递函数,用于传递字符串,整型数据 及对象结构
- UVMC 的set 方法用于在指定层次的上下文中创建或更新字段配置,主要通过三种函数来实现
uvmc_set_config_object("uvm_tlm_generic_payload","e.prod","","trans", tr);
uvmc_set_config_string ("e.prod", "", "message", "Hello from SystemC!");
uvmc_set_config_int ("e.prod", "", "start_addr", 0x1234);
这些函数建立配置设置,将它们存储为资源数据库中的资源条目,以便以后通过get_config调用进行查找。它们不会直接影响目标字段的值。当组件层次结构在UVM的构建阶段构建时,组件就会出现并建立它们的上下文。一旦知道了它的上下文,每个组件就可以调用get_config来检索应用于它的任何配置设置。配置参数的名称由field_name参数指定,
当UVM处于build_phase时,与任何其他阶段相比,set方法的语义是不同的。如果在构建阶段进行了set调用,则上下文确定数据库中的优先级。来自层次结构中较高级别(例如,mytop.test1)的set调用优先于来自较低级别(例如,mytop.test1.env.agent)的对同一字段的set调用。在相同层次结构级别上进行的Set调用具有相同的优先级,因此每个Set调用都会覆盖前一个Set调用的字段值
在build_phase之后,所有set调用都具有相同的优先级,而与它们的层次上下文无关。每个set调用都会覆盖前一个调用的值
set api 函数的传参说明:
以使用`uvmc_set_config_object`传递对象为例:共有5个参数 a. `type_name` : UVM Connect将利用工厂来分配这种类型的对象,并将序列化的值解包到其中。不支持参数化类 b. `context` : 组件的层次结构路径,或指定uvm_top的空字符串。可以使用通配符(*和?)指定多个组件,例如“top.env.*.driver”还可以通过将contxt括在前斜杠中来指定POSIX扩展正则表达式,例如。`“惠普/ b /”`。默认 值:"` (uvm_top)` c. `inst_name` : 相对于指定的上下文,正在配置的对象的实例路径。可以包含通配符还是正则表达式, 即目的层次,可以留空,视为全局空间参数的广播 d. `filed_name` : 配置参数的名称。通常,此名称与用于保存目标上下文中配置的值的变量相同或类似 e. ` value` : 值必须具有为其定义的`uvmc_convert
`专门化。使用转换器方便宏是可以接受的,以满足这一要求 对于
uvmc_set_config_string
和uvmc_set_config_int
已经指明传参类型的函数,则只需要四个参数,省略type_name
- UVMC 的get 方法用于获取指定层次上下文的配置字段值。
如果成功,则返回true;如果无法在给定上下文中找到配置设置,则返回false。如果为假,则值引用未修改. get方法主要通过三种函数来实现
`uvmc_get_config_object("uvm_tlm_generic_payload","e","prod","trans", tr2);`
`uvmc_get_config_string ("e", "prod", "message", str);`
`uvmc_get_config_int ("e.prod", "", "start_addr", saddr);`
上下文指定搜索在该层次结构级别或更高级别上创建的字段的配置设置作为起始点, 即get config可以搜搜哦是指定层次更高的级别。inst_name
是相对于上下文的显式实例名,如果上下文是配置设置应用于的完整上下文,则可能是空字符串,上下文和inst_name
字符串必须是简单字符串——没有通配符或正则表达式
get api 函数的传参说明:
type_name
: 仅供uvmc_get_config_object。指定要检索的等效对象的类型名SV。UVM Connect将检查从配置数据库检索到的对象是否与此类型名匹配。如果匹配,对象将被序列化(打包)并跨语言边界返回。在这一边,对象数据被解压缩到通过值参数引用传递的对象中。不支持参数化类。
context
: 正在代表其检索指定配置的组件的层次结构路径。不允许通配符或正则表达式。上下文必须与现有组件的层次结构名称完全匹配,或者是指定uvm_top的空字符串 ,对象区域inst_name
: 相对于指定的上下文,正在配置的对象的实例路径,目标域filed_name
: 配置参数的名称。通常,此名称与用于保存目标上下文中配置的值的变量名称一致value
: 配置参数的值。整数值目前不能超过64位。对象值必须具有为其定义的uvmc_convert
专门化。使用转换器方便宏是可以接受的,以满足这一要求。SV中的等价类必须基于uvm_object
并在UVM工厂注册,即包含一个`' uvm_object_utils '`
二. UVM 打包器与转换器说明:
在uvm systemVerilog testbench 一侧可用于传递的对象必须派生自uvm_object
类,并实现其中的do_pack
和do_unpack
回调函数,由于序列化需要使用factory方法,所以封包类必须使用uvm_object_utils
注册
示例如下:
class prod_cfg extends uvm_object;
`uvm_object_utils(prod_cfg);
function new(string name="producer_config_inst");
super.new(name);
endfunction
int min_addr = 'h00;
int max_addr = 'hff;
int min_data_len = 10;
int max_data_len = 80;
int max_trans = 5;
virtual function void do_pack(uvm_packer packer);
`uvm_pack_int(min_addr)
`uvm_pack_int(max_addr)
`uvm_pack_int(min_data_len)
`uvm_pack_int(max_data_len)
`uvm_pack_int(max_trans)
endfunction
virtual function void do_unpack(uvm_packer packer);
`uvm_unpack_int(min_addr)
`uvm_unpack_int(max_addr)
`uvm_unpack_int(min_data_len)
`uvm_unpack_int(max_data_len)
`uvm_unpack_int(max_trans)
endfunction
function string convert2string();
return $sformatf("min_addr:%h max_addr:%h min_data_len:%0d max_data_len:%0d max_trans:%0d",
min_addr, max_addr, min_data_len, max_data_len,max_trans);
endfunction
endclass
do_pack
和do_unpack
的的序列化打包,注意使用uvm_packer
作为形参接口,注意在打包中需要使用uvm_pack/unpakc_int , uvm_pack/unpack_enum
将成员变量做封装处理
在示例中,congvet2string
属于非强制必须实现函数
在systemC layer中,为了准确讲从sv传递而来的packet做反序列化,需要构造一个成员类型与sv object一致的对象类作为反序列化转换的标准类型,实例如下
class prod_cfg {
public:
int min_addr;
int max_addr;
int min_data_len;
int max_data_len;
int max_trans;
};
UVMC_UTILS_5(prod_cfg,min_addr,max_addr,
min_data_len,max_data_len,max_trans)
需要注意的是,UVMC_UTILS_N
这个标准宏,其为给定的对象类型生成专用的打包,解包,打印功能
主要有如下两种宏:UVMC_UTILS_
)
UVMC_UTILS_EXT_
)
第一种宏中N 代表将要打包的对象中的变量数量,TYPE
为对象类型,后面变量为需要打包的变量,第二种宏则表示为增量打包,其中TYPE
为对象原型,BASE
为已有对象,后续为增量打包的变量,其中N为增量打包的变量数量
三, 完整的UVMC和UVM之间通过config传递变量和对象的实例
#include "uvmc.h"
#include "uvmc_macros.h"
using namespace uvmc;
class prod_cfg {
public:
int min_addr;
int max_addr;
int min_data_len;
int max_data_len;
int max_trans;
};
UVMC_UTILS_5(prod_cfg,min_addr,max_addr,
min_data_len,max_data_len,max_trans)
// (end inline source)
#include
#include
#include "systemc.h"
#include "tlm.h"
#include "uvmc.h"
using namespace std;
using namespace sc_core;
using namespace tlm;
using namespace uvmc;
#include "consumer.cpp"
SC_MODULE(top)
{
consumer cons;
SC_CTOR(top) : cons("consumer") {
SC_THREAD(show_uvm_config);
uvmc_connect(cons.in,"foo");
uvmc_connect(cons.analysis_out,"bar");
}
void show_uvm_config();
};
// (end inline source)
void top::show_uvm_config()
{
string s = "Greetings from SystemC";
uint64 i = 2;
prod_cfg cfg;
cfg.min_addr=0x100;
cfg.max_addr=0x10f;
cfg.min_data_len=1;
cfg.max_data_len=8;
cfg.max_trans=2;
wait(SC_ZERO_TIME);
UVMC_INFO("TOP/SET_CFG",
"Calling set_config_* to SV-side instance 'e.prod'",
UVM_MEDIUM,"");
uvmc_set_config_int ("e.prod", "", "some_int", i);
uvmc_set_config_string ("", "e.prod", "some_string", s.c_str());
uvmc_set_config_object ("prod_cfg", "e", "prod", "config", cfg);
// Wait until the build phase. The SV side will have used get_config
// to retreive our settings
uvmc_wait_for_phase("build", UVM_PHASE_ENDED);
i=0;
s="";
cfg.min_addr=0;
cfg.max_addr=0;
UVMC_INFO("TOP/GET_CFG", \
"Calling get_config_* from SV-side context 'e.prod'", \
UVM_MEDIUM,"");
// Get and check our int, string, and object configuration
if (uvmc_get_config_int ("e.prod", "", "some_int", i))
cout << "get_config_int : some_int=" << hex << i << endl;
else
UVMC_ERROR("GET_CFG_INT_FAIL", "get_config_int failed",name());
if (uvmc_get_config_string ("e.prod", "", "some_string", s))
cout << "get_config_string: some_string=" << s << endl;
else
UVMC_ERROR("GET_CFG_STR_FAIL", "get_config_string failed",name());
if (uvmc_get_config_object ("prod_cfg", "e.prod", "", "config", cfg))
cout << "get_config_object: config = " << cfg << endl;
else
UVMC_ERROR("GET_CFG_OBJ_FAIL", "get_config_object failed",name());
}
int sc_main(int argc, char* argv[])
{
top t("t");
sc_start();
return 0;
}
在UVM 层的打包操作为:
function void check_config();
int i;
string str;
uvm_object obj;
if (!uvm_config_db #(uvm_bitstream_t)::get(this,"","some_int",i))
`uvm_error("NO_INT_CONFIG",{"No configuration for field 'some_int'",
" found at context '",get_full_name(),"'"})
else
`uvm_info("INT_CONFIG",
$sformatf("Config for field 'some_int' at context '%s' has value %0h",
get_full_name(),i),UVM_NONE)
if (!uvm_config_db #(string)::get(this,"","some_string",str))
`uvm_error("NO_STRING_CONFIG",{"No configuration for field 'some_string'",
" found at context '",get_full_name(),"'"})
else
`uvm_info("STRING_CONFIG",
{"Config for field 'message' at context '", get_full_name(),
"' has value '", str,"'"},UVM_NONE)
if (!uvm_config_db #(uvm_object)::get(this,"","config",obj))
`uvm_error("NO_OBJECT_CONFIG",{"No configuration for field 'config'",
" found at context '",get_full_name(),"'"})
else begin
prod_cfg c;
if (!$cast(c,obj))
`uvm_error("BAD_CONFIG_TYPE",
{"Object set for configuration field 'config' at context '",
get_full_name(),"' is not a prod_cfg type"})
else begin
cfg = c;
`uvm_info("OBJECT_CONFIG",
{"Config for field 'config' at context '",get_full_name(),
"' has value '", cfg.convert2string(),"'"},UVM_NONE)
end
end
endfunction
需要注意的是,由于在打包传递的过程中,存在序列化和反序列化的过程,因此对于在uvm sv中get到该变量需要首先用uvm_object 类型的句柄指向传递而来的反序列化对象,并使用动态cast将其转化为目标对象类型,以防止内存共享过程中数据流传递的错误。