reg model使用篇-uvm_reg_block常用操作
1. 寄存器模型的reset
(1) 每一个register model被继承到验证平台后,都必须进行reset操作,这样才能保证每个寄存器的值等于我们设置的初始值.
(2) register model并不会自动的进行reset操作,必须显式的调用reset函数进行复位操作.
1.1 uvm_reg_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
1.2 uvm_reg的reset
(1) m_atomic本质上是一个semaphore,用于实现进程的同步; uvm_reg的new函数中会为其分配一个key;
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
1.3 uvm_reg_field的reset
(1) m_reset中的记录是在uvm_reg_field的configure函数中通过调用set_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
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
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);
m_parent = parent;
if (size == 0) begin
`uvm_error("RegModel",
$sformatf("Field \"%s\" cannot have 0 bits", get_full_name()));
size = 1;
end
m_size = size;
m_volatile = volatile;
m_access = access.toupper();
m_lsb = lsb_pos;
m_cover_on = UVM_NO_COVERAGE;
m_written = 0;
m_check = volatile ? UVM_NO_CHECK : UVM_CHECK;
m_individually_accessible = 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_parent.add_field(this);
if (!m_policy_names.exists(m_access)) begin
`uvm_error("RegModel", {"Access policy '",access,
"' for field '",get_full_name(),"' is not defined. Setting to RW"})
m_access = "RW";
end
if (size > m_max_size)
m_max_size = size;
// Ignore is_rand if the field is known not to be writeable
// i.e. not "RW", "WRC", "WRS", "WO", "W1", "WO1"
case (access)
"RO", "RC", "RS", "WC", "WS",
"W1C", "W1S", "W1T", "W0C", "W0S", "W0T",
"W1SRC", "W1CRS", "W0SRC", "W0CRS", "WSRC", "WCRS",
"WOC", "WOS": is_rand = 0;
endcase
if (!is_rand)
value.rand_mode(0);
m_field_registry[get_full_name()] = this;
endfunction: configure
2. get_root_blocks
(1) 得到所有的root blocks;
(2) 在使用get_root_blocks函数得到reg_block的指针后,使用cast将其转化为目标reg_block形式;
extern static function void get_root_blocks(ref uvm_reg_block blks[$]);
function void uvm_reg_block::get_root_blocks(ref uvm_reg_block blks[$]);
foreach (m_roots[blk]) begin
blks.push_back(blk);
end
endfunction: get_root_blocks
//示例
class case0_cfg_vseq extends uvm_sequence;
...
virtual task body();
uvm_status_e status;
uvm_reg_data_t value;
bit[31:0] counter;
uvm_reg_block blks[$];
reg_model p_rm;
...
uvm_reg_block::get_root_blocks(blks);
if(blks.size()==0) begin
`uvm_fatal(**)
end
else begin
if(!$cast(p_rm,blks[0])) begin
**
end
p_rm.invert.read(status,value,UVM_FRONTDOOR);
...
end
endtask
endclass
3. get_registers
(1) 得到在当前register_block里面例化的registers;
(2) 注意: register可能位于不同或多个address maps中,为了获取特定address map中的registers,需要使用uvm_reg_map::get_registers();
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
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
4. add_hdl_path
function void uvm_reg_block::add_hdl_path(string path, string kind = "RTL");
uvm_queue #(string) paths;
paths = hdl_paths_pool.get(kind);
paths.push_back(path);
endfunction
local uvm_object_string_pool #(uvm_queue #(string)) hdl_paths_pool; //uvm_reg_block内变量
//uvm_pool.svh
class uvm_pool #(type KEY=int, T=uvm_void) extends uvm_object;
...
protected T pool[KEY];
...
endclass
class uvm_object_string_pool #(type T=uvm_object) extends uvm_pool #(string,T);
...
virtual function T get (string key);
if (!pool.exists(key))
pool[key] = new (key);
return pool[key];
endfunction
...
endclass
5. configure
function void uvm_reg_block::configure(uvm_reg_block parent=null, string hdl_path="");
this.parent = parent;
if (parent != null)
this.parent.add_block(this);
add_hdl_path(hdl_path);
uvm_resource_db#(uvm_reg_block)::set("uvm_reg::*", get_full_name(), this);
endfunction
6. get_reg_by_name
function uvm_reg uvm_reg_block::get_reg_by_name(string name);
foreach (regs[rg_]) begin
uvm_reg rg = rg_;
if (rg.get_name() == name)
return rg;
end
foreach (blks[blk_]) begin
uvm_reg_block blk = blk_;
uvm_reg subregs[$];
blk_.get_registers(subregs, UVM_HIER);
foreach (subregs[j])
if (subregs[j].get_name() == name)
return subregs[j];
end
`uvm_warning("RegModel", {"Unable to locate register '",name,
"' in block '",get_full_name(),"'"})
return null;
endfunction: get_reg_by_name
7.get_parent
function void uvm_reg_block::configure(uvm_reg_block parent=null, string hdl_path="");
this.parent = parent;
if (parent != null)
this.parent.add_block(this);
add_hdl_path(hdl_path);
uvm_resource_db#(uvm_reg_block)::set("uvm_reg::*", get_full_name(), this);
endfunction
function uvm_reg_block uvm_reg_block::get_parent();
get_parent = this.parent;
endfunction: get_parent
8.update
task uvm_reg_block::update(output uvm_status_e status,
input uvm_path_e path = UVM_DEFAULT_PATH,
input uvm_sequence_base parent = null,
input int prior = -1,
input uvm_object extension = null,
input string fname = "",
input int lineno = 0);
status = UVM_IS_OK;
if (!needs_update()) begin
`uvm_info("RegModel", $sformatf("%s:%0d - RegModel block %s does not need updating",
fname, lineno, this.get_name()), UVM_HIGH);
return;
end
`uvm_info("RegModel", $sformatf("%s:%0d - Updating model block %s with %s path",
fname, lineno, this.get_name(), path.name ), UVM_HIGH);
foreach (regs[rg_]) begin
uvm_reg rg = rg_;
if (rg.needs_update()) begin
rg.update(status, path, null, parent, prior, extension);
if (status != UVM_IS_OK && status != UVM_HAS_X) begin;
`uvm_error("RegModel", $sformatf("Register \"%s\" could not be updated",
rg.get_full_name()));
return;
end
end
end
foreach (blks[blk_]) begin
uvm_reg_block blk = blk_;
blk.update(status,path,parent,prior,extension,fname,lineno);
end
endtask: update
9.write_reg_by_name
task uvm_reg_block::write_reg_by_name(output uvm_status_e status,
input string name,
input uvm_reg_data_t data,
input uvm_path_e path = UVM_DEFAULT_PATH,
input uvm_reg_map map = null,
input uvm_sequence_base parent = null,
input int prior = -1,
input uvm_object extension = null,
input string fname = "",
input int lineno = 0);
uvm_reg rg;
this.fname = fname;
this.lineno = lineno;
status = UVM_NOT_OK;
rg = this.get_reg_by_name(name);
if (rg != null)
rg.write(status, data, path, map, parent, prior, extension);
endtask: write_reg_by_name
10.read_reg_by_name
task uvm_reg_block::read_reg_by_name(output uvm_status_e status,
input string name,
output uvm_reg_data_t data,
input uvm_path_e path = UVM_DEFAULT_PATH,
input uvm_reg_map map = null,
input uvm_sequence_base parent = null,
input int prior = -1,
input uvm_object extension = null,
input string fname = "",
input int lineno = 0);
uvm_reg rg;
this.fname = fname;
this.lineno = lineno;
status = UVM_NOT_OK;
rg = this.get_reg_by_name(name);
if (rg != null)
rg.read(status, data, path, map, parent, prior, extension);
endtask: read_reg_by_name

浙公网安备 33010602011771号