[CU]reg model使用篇-uvm_reg_block常用操作
1. 寄存器模型的reset
(1) 每一个register model被继承到验证平台后,都必须进行reset操作,这样才能保证每个寄存器的值等于我们设置的初始值.
(2) register model并不会自动的进行reset操作,必须显式的调用reset函数进行复位操作.
1.1 uvm_reg_block的reset函数
1 function void uvm_reg_block::reset(string kind = "HARD"); 2 3 foreach (regs[rg_]) begin 4 uvm_reg rg = rg_; 5 rg.reset(kind); 6 end 7 8 foreach (blks[blk_]) begin 9 uvm_reg_block blk = blk_; 10 blk.reset(kind); 11 end 12 endfunction
1.2 uvm_reg的reset
(1) m_atomic本质上是一个semaphore,用于实现进程的同步; uvm_reg的new函数中会为其分配一个key;
1 function void uvm_reg::reset(string kind = "HARD"); 2 foreach (m_fields[i]) 3 m_fields[i].reset(kind); 4 // Put back a key in the semaphore if it is checked out 5 // in case a thread was killed during an operation 6 void'(m_atomic.try_get(1)); 7 m_atomic.put(1); 8 m_process = null; 9 Xset_busyX(0); 10 endfunction: reset
1.3 uvm_reg_field的reset
(1) m_reset中的记录是在uvm_reg_field的configure函数中通过调用set_reset函数插入的;
1 function void uvm_reg_field::reset(string kind = "HARD"); 2 3 if (!m_reset.exists(kind)) 4 return; 5 6 m_mirrored = m_reset[kind]; 7 m_desired = m_mirrored; 8 value = m_mirrored; 9 10 if (kind == "HARD") 11 m_written = 0; 12 13 endfunction: reset
1 function void uvm_reg_field::set_reset(uvm_reg_data_t value, 2 string kind = "HARD"); 3 m_reset[kind] = value & ((1<<m_size) - 1); 4 endfunction: set_reset
1 function void uvm_reg_field::configure(uvm_reg parent, 2 int unsigned size, 3 int unsigned lsb_pos, 4 string access, 5 bit volatile, 6 uvm_reg_data_t reset, 7 bit has_reset, 8 bit is_rand, 9 bit individually_accessible); 10 m_parent = parent; 11 if (size == 0) begin 12 `uvm_error("RegModel", 13 $sformatf("Field \"%s\" cannot have 0 bits", get_full_name())); 14 size = 1; 15 end 16 17 m_size = size; 18 m_volatile = volatile; 19 m_access = access.toupper(); 20 m_lsb = lsb_pos; 21 m_cover_on = UVM_NO_COVERAGE; 22 m_written = 0; 23 m_check = volatile ? UVM_NO_CHECK : UVM_CHECK; 24 m_individually_accessible = individually_accessible; 25 26 if (has_reset) 27 set_reset(reset); 28 else 29 uvm_resource_db#(bit)::set({"REG::", get_full_name()}, 30 "NO_REG_HW_RESET_TEST", 1); 31 32 m_parent.add_field(this); 33 34 if (!m_policy_names.exists(m_access)) begin 35 `uvm_error("RegModel", {"Access policy '",access, 36 "' for field '",get_full_name(),"' is not defined. Setting to RW"}) 37 m_access = "RW"; 38 end 39 40 if (size > m_max_size) 41 m_max_size = size; 42 43 // Ignore is_rand if the field is known not to be writeable 44 // i.e. not "RW", "WRC", "WRS", "WO", "W1", "WO1" 45 case (access) 46 "RO", "RC", "RS", "WC", "WS", 47 "W1C", "W1S", "W1T", "W0C", "W0S", "W0T", 48 "W1SRC", "W1CRS", "W0SRC", "W0CRS", "WSRC", "WCRS", 49 "WOC", "WOS": is_rand = 0; 50 endcase 51 52 if (!is_rand) 53 value.rand_mode(0); 54 55 m_field_registry[get_full_name()] = this; 56 endfunction: configure
2. get_root_blocks
(1) 得到所有的root blocks;
(2) 在使用get_root_blocks函数得到reg_block的指针后,使用cast将其转化为目标reg_block形式;
1 extern static function void get_root_blocks(ref uvm_reg_block blks[$]); 2 function void uvm_reg_block::get_root_blocks(ref uvm_reg_block blks[$]); 3 4 foreach (m_roots[blk]) begin 5 blks.push_back(blk); 6 end 7 8 endfunction: get_root_blocks
1 //示例 2 class case0_cfg_vseq extends uvm_sequence; 3 ... 4 virtual task body(); 5 uvm_status_e status; 6 uvm_reg_data_t value; 7 bit[31:0] counter; 8 uvm_reg_block blks[$]; 9 reg_model p_rm; 10 ... 11 12 uvm_reg_block::get_root_blocks(blks); 13 if(blks.size()==0) begin 14 `uvm_fatal(**) 15 end 16 else begin 17 if(!$cast(p_rm,blks[0])) begin 18 ** 19 end 20 p_rm.invert.read(status,value,UVM_FRONTDOOR); 21 ... 22 end 23 endtask 24 25 endclass
3. get_registers
(1) 得到在当前register_block里面例化的registers;
(2) 注意: register可能位于不同或多个address maps中,为了获取特定address map中的registers,需要使用uvm_reg_map::get_registers();
1 function void uvm_reg_block::get_registers(ref uvm_reg regs[$], 2 input uvm_hier_e hier=UVM_HIER); 3 foreach (this.regs[rg]) 4 regs.push_back(rg); 5 6 if (hier == UVM_HIER) 7 foreach (blks[blk_]) begin 8 uvm_reg_block blk = blk_; 9 blk.get_registers(regs); 10 end 11 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
1 function void uvm_reg_block::add_hdl_path(string path, string kind = "RTL"); 2 3 uvm_queue #(string) paths; 4 5 paths = hdl_paths_pool.get(kind); 6 7 paths.push_back(path); 8 9 endfunction
1 local uvm_object_string_pool #(uvm_queue #(string)) hdl_paths_pool; //uvm_reg_block内变量 2 //uvm_pool.svh 3 class uvm_pool #(type KEY=int, T=uvm_void) extends uvm_object; 4 ... 5 protected T pool[KEY]; 6 ... 7 endclass 8 9 class uvm_object_string_pool #(type T=uvm_object) extends uvm_pool #(string,T); 10 11 ... 12 virtual function T get (string key); 13 if (!pool.exists(key)) 14 pool[key] = new (key); 15 return pool[key]; 16 endfunction 17 ... 18 19 endclass
5. configure
1 function void uvm_reg_block::configure(uvm_reg_block parent=null, string hdl_path=""); 2 this.parent = parent; 3 if (parent != null) 4 this.parent.add_block(this); 5 add_hdl_path(hdl_path); 6 7 uvm_resource_db#(uvm_reg_block)::set("uvm_reg::*", get_full_name(), this); 8 endfunction
6. get_reg_by_name
1 function uvm_reg uvm_reg_block::get_reg_by_name(string name); 2 3 foreach (regs[rg_]) begin 4 uvm_reg rg = rg_; 5 if (rg.get_name() == name) 6 return rg; 7 end 8 9 foreach (blks[blk_]) begin 10 uvm_reg_block blk = blk_; 11 uvm_reg subregs[$]; 12 blk_.get_registers(subregs, UVM_HIER); 13 14 foreach (subregs[j]) 15 if (subregs[j].get_name() == name) 16 return subregs[j]; 17 end 18 19 `uvm_warning("RegModel", {"Unable to locate register '",name, 20 "' in block '",get_full_name(),"'"}) 21 return null; 22 23 endfunction: get_reg_by_name
7.get_parent
1 function void uvm_reg_block::configure(uvm_reg_block parent=null, string hdl_path=""); 2 this.parent = parent; 3 if (parent != null) 4 this.parent.add_block(this); 5 add_hdl_path(hdl_path); 6 7 uvm_resource_db#(uvm_reg_block)::set("uvm_reg::*", get_full_name(), this); 8 endfunction 9 10 function uvm_reg_block uvm_reg_block::get_parent(); 11 get_parent = this.parent; 12 endfunction: get_parent
8.update
1 task uvm_reg_block::update(output uvm_status_e status, 2 input uvm_path_e path = UVM_DEFAULT_PATH, 3 input uvm_sequence_base parent = null, 4 input int prior = -1, 5 input uvm_object extension = null, 6 input string fname = "", 7 input int lineno = 0); 8 status = UVM_IS_OK; 9 10 if (!needs_update()) begin 11 `uvm_info("RegModel", $sformatf("%s:%0d - RegModel block %s does not need updating", 12 fname, lineno, this.get_name()), UVM_HIGH); 13 return; 14 end 15 16 `uvm_info("RegModel", $sformatf("%s:%0d - Updating model block %s with %s path", 17 fname, lineno, this.get_name(), path.name ), UVM_HIGH); 18 19 foreach (regs[rg_]) begin 20 uvm_reg rg = rg_; 21 if (rg.needs_update()) begin 22 rg.update(status, path, null, parent, prior, extension); 23 if (status != UVM_IS_OK && status != UVM_HAS_X) begin; 24 `uvm_error("RegModel", $sformatf("Register \"%s\" could not be updated", 25 rg.get_full_name())); 26 return; 27 end 28 end 29 end 30 31 foreach (blks[blk_]) begin 32 uvm_reg_block blk = blk_; 33 blk.update(status,path,parent,prior,extension,fname,lineno); 34 end 35 endtask: update
9.write_reg_by_name
1 task uvm_reg_block::write_reg_by_name(output uvm_status_e status, 2 input string name, 3 input uvm_reg_data_t data, 4 input uvm_path_e path = UVM_DEFAULT_PATH, 5 input uvm_reg_map map = null, 6 input uvm_sequence_base parent = null, 7 input int prior = -1, 8 input uvm_object extension = null, 9 input string fname = "", 10 input int lineno = 0); 11 uvm_reg rg; 12 this.fname = fname; 13 this.lineno = lineno; 14 15 status = UVM_NOT_OK; 16 rg = this.get_reg_by_name(name); 17 if (rg != null) 18 rg.write(status, data, path, map, parent, prior, extension); 19 20 endtask: write_reg_by_name
10.read_reg_by_name
1 task uvm_reg_block::read_reg_by_name(output uvm_status_e status, 2 input string name, 3 output uvm_reg_data_t data, 4 input uvm_path_e path = UVM_DEFAULT_PATH, 5 input uvm_reg_map map = null, 6 input uvm_sequence_base parent = null, 7 input int prior = -1, 8 input uvm_object extension = null, 9 input string fname = "", 10 input int lineno = 0); 11 uvm_reg rg; 12 this.fname = fname; 13 this.lineno = lineno; 14 15 status = UVM_NOT_OK; 16 rg = this.get_reg_by_name(name); 17 if (rg != null) 18 rg.read(status, data, path, map, parent, prior, extension); 19 endtask: read_reg_by_name
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?