reset函数
目录
block reset:
function void uvm_reg_block::reset(string kind = "HARD");
foreach (regs[rg_]) begin
uvm_reg rg = rg_;
rg.reset(kind);
end
foreach (blks[blk_]) begin
uvm_reg_block blk = blk_;
blk.reset(kind);
end
endfunction
调用get_registers将regs从关联数组中拿到
function void uvm_reg_block::get_registers(ref uvm_reg regs[$],
input uvm_hier_e hier=UVM_HIER);
foreach (this.regs[rg])
regs.push_back(rg);
if (hier == UVM_HIER)
foreach (blks[blk_]) begin
uvm_reg_block blk = blk_;
blk.get_registers(regs);
end
endfunction: get_registers
regs关联数组由add_reg填充,blk的该函数由uvm_reg的configure调用,
function void uvm_reg_block::add_reg(uvm_reg rg);
if (this.is_locked()) begin
`uvm_error("RegModel", "Cannot add register to locked block model");
return;
end
if (this.regs.exists(rg)) begin
`uvm_error("RegModel", {"Register '",rg.get_name(),
"' has already been registered with block '",get_name(),"'"})
return;
end
regs[rg] = id++;
endfunction: add_reg
function void uvm_reg::configure (uvm_reg_block blk_parent,
uvm_reg_file regfile_parent=null,
string hdl_path = "");
m_parent = blk_parent;
m_parent.add_reg(this);
m_regfile_parent = regfile_parent;
if (hdl_path != "")
add_hdl_path_slice(hdl_path, -1, -1);
endfunction: configure
如果block已经通调用过lock函数那么则不能再add_reg,也不能对吧blk进行其余改变的操作
其中regs是关联数组,索引是rg(索引是句柄吗?),存放的是int类型数据
local int unsigned regs[uvm_reg];
reg reset
function void uvm_reg::reset(string kind = "HARD");
foreach (m_fields[i])
m_fields[i].reset(kind);
// Put back a key in the semaphore if it is checked out
// in case a thread was killed during an operation
void'(m_atomic.try_get(1));
m_atomic.put(1);
m_process = null;
Xset_busyX(0);
endfunction: reset
field reset
function void uvm_reg_field::reset(string kind = "HARD");
if (!m_reset.exists(kind))
return;
m_mirrored = m_reset[kind];
m_desired = m_mirrored;
value = m_mirrored;
if (kind == "HARD")
m_written = 0;
endfunction: reset
对于上面所说的string我们先看一下reset值是如何来的,对于field来说,reset值在configure时会进行传参,一般都会将has_reset配置为1,
function void uvm_reg_field::configure(uvm_reg parent,
int unsigned size,
int unsigned lsb_pos,
string access,
bit volatile,
uvm_reg_data_t reset,
bit has_reset,
bit is_rand,
bit individually_accessible);
if (has_reset)
set_reset(reset);
else
uvm_resource_db#(bit)::set({"REG::", get_full_name()},
"NO_REG_HW_RESET_TEST", 1);
那么m_reset关联数组索引默认情况下都为HARD,索引值为配置的reset值
function void uvm_reg_field::set_reset(uvm_reg_data_t value,
string kind = "HARD");
m_reset[kind] = value & ((1<<m_size) - 1);
endfunction: set_reset
现在在回头看reset函数,m_reset只有has_reset的情况下才会有值,否则会return,为该field的镜像值设置为reset值,期望值设置为镜像值,value也为镜像值,也就是说复位后,寄存器域的三个值都是复位值。对于非RW寄存器也会有复位值
uvm_resource_db
uvm_resource_db是一个参数化类,内建一个资源池,类型来自于uvm_resource_db的参数
typedef uvm_resource #(T) rsrc_t;
先看一下使用最频繁的set函数
static function void set(input string scope, input string name,
T val, input uvm_object accessor = null);
rsrc_t rsrc = new(name, scope);
rsrc.write(val, accessor);
rsrc.set();
if(uvm_resource_db_options::is_tracing())
m_show_msg("RSRCDB/SET", "Resource","set", scope, name, accessor, rsrc);
endfunction
set是静态函数,所以使用::可以直接调用
function void write(T t, uvm_object accessor = null);
if(is_read_only()) begin
uvm_report_error("resource", $sformatf("resource %s is read only -- cannot modify", get_name()));
return;
end
// Set the modified bit and record the transaction only if the value
// has actually changed.
if(val == t)
return;
record_write_access(accessor);
// set the value and set the dirty bit
val = t;
modified = 1;
endfunction
函数is_read_only来获得当前resource状态,read_only返回1,read_write返回0,该属性可以通过函数来配置。
如果写入的值没有发生改变return
record_write_access下次再看
set函数会继续调用rp的set
function void set();
uvm_resource_pool rp = uvm_resource_pool::get();
rp.set(this);
endfunction
rp的set
function void set (uvm_resource_base rsrc,
uvm_resource_types::override_t override = 0);
uvm_resource_types::rsrc_q_t rq;
string name;
uvm_resource_base type_handle;
// If resource handle is ~null~ then there is nothing to do.
if(rsrc == null)
return;
// insert into the name map. Resources with empty names are
// anonymous resources and are not entered into the name map
name = rsrc.get_name();
if(name != "") begin
if(rtab.exists(name))
rq = rtab[name];
else
rq = new();
// Insert the resource into the queue associated with its name.
// If we are doing a name override then insert it in the front of
// the queue, otherwise insert it in the back.
if(override & uvm_resource_types::NAME_OVERRIDE)
rq.push_front(rsrc);
else
rq.push_back(rsrc);
rtab[name] = rq;
end
// insert into the type map
type_handle = rsrc.get_type_handle();
if(ttab.exists(type_handle))
rq = ttab[type_handle];
else
rq = new();
// insert the resource into the queue associated with its type. If
// we are doing a type override then insert it in the front of the
// queue, otherwise insert it in the back of the queue.
if(override & uvm_resource_types::TYPE_OVERRIDE)
rq.push_front(rsrc);
else
rq.push_back(rsrc);
ttab[type_handle] = rq;
endfunction
对于rp来说内建了两个关联数组,rtab是以name索引,ttab是以类型索引
uvm_resource_types::rsrc_q_t rtab [string];
uvm_resource_types::rsrc_q_t ttab [uvm_resource_base];
以类型索引时,索引为type_handle,type_handle通过下面函数获得type
function uvm_resource_base get_type_handle();
return get_type();
endfunction
static function this_type get_type();
if(my_type == null)
my_type = new();
return my_type;
endfunction
学习一下get_by_name的实现,调用uvm_resource #(T) rsrc_t的get_by_name
static function rsrc_t get_by_name(string scope,
string name,
bit rpterr=1);
return rsrc_t::get_by_name(scope, name, rpterr);
endfunction
调用rp的get_by_name,应该是要在rp里找到对应的uvm_resource_base
static function this_type get_by_name(string scope,
string name,
bit rpterr = 1);
uvm_resource_pool rp = uvm_resource_pool::get();
uvm_resource_base rsrc_base;
this_type rsrc;
string msg;
rsrc_base = rp.get_by_name(scope, name, my_type, rpterr);
if(rsrc_base == null)
return null;
if(!$cast(rsrc, rsrc_base)) begin
if(rpterr) begin
$sformat(msg, "Resource with name %s in scope %s has incorrect type", name, scope);
`uvm_warning("RSRCTYPE", msg);
end
return null;
end
return rsrc;
endfunction
function uvm_resource_base get_by_name(string scope = "",
string name,
uvm_resource_base type_handle,
bit rpterr = 1);
uvm_resource_types::rsrc_q_t q;
uvm_resource_base rsrc;
q = lookup_name(scope, name, type_handle, rpterr);
if(q.size() == 0) begin
push_get_record(name, scope, null);
return null;
end
rsrc = get_highest_precedence(q);
push_get_record(name, scope, rsrc);
return rsrc;
endfunction