[CU]reg model构建篇-uvm_reg
参考资料:
(1) https://verificationacademy.com/verification-methodology-reference/uvm/src/reg/uvm_reg.svh
(2) 《Practical UVM Step by Step with IEEE》
1. uvm_reg意义
(1) uvm_reg和DUT中每个register对应,其宽度一般和总线位宽一致,里面可以包含多个uvm_reg_field;
2. uvm_reg源码
1 virtual class uvm_reg extends uvm_object; 2 3 local bit m_locked; 4 //m_parent表示此uvm_reg所在的uvm_reg_block; 5 local uvm_reg_block m_parent; 6 //m_regfile_parent表示此uvm_reg所在的uvm_reg_file的指针; 7 local uvm_reg_file m_regfile_parent; 8 //m_n_bits表示此寄存器的位数; 9 local int unsigned m_n_bits; 10 //m_n_used_bits表示此寄存器用了多少位; 11 local int unsigned m_n_used_bits; 12 //m_maps表示此寄存器所在uvm_reg_map信息; 13 //m_maps是一个关联数组,表示一个寄存器可以与多个uvm_reg_map对应; 14 protected bit m_maps[uvm_reg_map]; 15 //m_fields关联数组中记录了加入此uvm_reg中的所有uvm_reg_field的指针; 16 protected uvm_reg_field m_fields[$]; // Fields in LSB to MSB order 17 ... 18 local static int unsigned m_max_size; 19 //m_hdl_paths_pool用于存储此寄存器的backdoor操作时用到的路径信息; 20 local uvm_object_string_pool #(uvm_queue #(uvm_hdl_path_concat)) m_hdl_paths_pool; 21 22 ... 23 endclass
3. user-defined uvm_reg的构建步骤
3.1 类与成员变量的声明
(1) 可以在类中定义covergroup, sample的function等,在component中采样(具体实现??);
(2) 声明uvm_reg_field成员变量,对于reserved uvm_reg_field可以不用声明为rand类型,其他uvm_reg_field声明为rand类型;
注1:注意仍然需要使用factory机制进行注册;
注2:为什么需要将uvm_reg_field声明为rand类型?? 寄存器随机化是为了考虑日常不可预期的场景,模拟无法预期的硬件配置场景,可以测试到边界情况;
3.2 new函数的实现
1 function uvm_reg::new(string name="", int unsigned n_bits, int has_coverage); 2 super.new(name); 3 if (n_bits == 0) begin 4 `uvm_error("RegModel", $sformatf("Register \"%s\" cannot have 0 bits", get_name())); 5 n_bits = 1; 6 end 7 m_n_bits = n_bits; 8 m_has_cover = has_coverage; 9 m_atomic = new(1); 10 m_n_used_bits = 0; 11 m_locked = 0; 12 m_is_busy = 0; 13 m_is_locked_by_field = 1'b0; 14 m_hdl_paths_pool = new("hdl_paths"); 15 16 if (n_bits > m_max_size) 17 m_max_size = n_bits; 18 19 endfunction: new
(1) 要将寄存器宽度作为参数传递给super.new函数;
(2) uvm_reg new函数参数的含义:
参数2含义:寄存器宽度,指的是寄存器中总共的位数,一般与系统总线宽度一致;
参数3含义:用以设置寄存器是否参与加入覆盖率;
3.3 virtual build函数的实现
(1) 采用factory机制方式对uvm_reg_field进行例化;
(2) 调用uvm_reg_field的configure函数;
3.4 uvm_reg示例
1 //示例1 2 class reg_invert extends uvm_reg; 3 `uvm_object_utils(reg_invert) 4 5 rand uvm_reg_field reg_data; 6 7 function new(input string name="reg_invert"); 8 //paramter: name,size,has_coverage 9 super.new(name,16,UVM_NO_COVERAGE); 10 endfunction 11 12 virtual function void build(); 13 reg_data=uvm_reg_field::type_id::create("reg_data"); 14 //parameter:parent,size,lsb_pos,access,volatile,reset value,has_reset,is_rand 15 reg_data.configure(this,1,0,"RW",1,0,1,1,0); 16 endfunction 17 endclass
1 //示例2 2 class cfs_dut_reg_ctrl extends uvm_reg; 3 `uvm_object_utils(cfs_dut_reg_ctrl) 4 5 rand uvm_reg_field reserved; 6 rand uvm_reg_field enable; 7 8 function new(string name="cfs_dut_reg_config"); 9 super.new(**); 10 endfunction 11 12 virtual function void build(); 13 reserved=uvm_reg_field::type_id::create("reserved"); 14 reserved.configure(**); 15 enable=uvm_reg_field::type_id::create("enable"); 16 enable.configure(**); 17 endfunction 18 19 endclass
1 //示例3 2 // typedef enum uvm_reg_cvr_t { 3 // UVM_NO_COVERAGE = 'h0000, 4 // UVM_CVR_REG_BITS = 'h0001, 5 // UVM_CVR_ADDR_MAP = 'h0002, 6 // UVM_CVR_FIELD_VALS = 'h0004, 7 // UVM_CVR_ALL = -1 8 // } uvm_coverage_model_e; 9 10 class my_reg_type extends uvm_reg; 11 `uvm_object_utils(my_reg_type) 12 13 rand uvm_reg_field F1; 14 rand uvm_reg_field F2[3]; 15 16 protected uvm_reg_data_t m_current; 17 protected uvm_reg_data_t m_data; 18 protected bit m_is_read; 19 20 covergroup cg1(); 21 ... 22 endgroup 23 24 function new(string name="my_reg_type"); 25 super.new(.name(name), .n_bits(32), .has_coverage(UVM_NO_COVERAGE)); 26 if(has_coverage(UVM_CVR_REG_BITS)) cg1=new(); 27 endfunction 28 29 virtual function build(); 30 this.F1=uvm_reg_field::type_id::create(.name("F1"),.parent(null),.contxt(get_full_name())); 31 this.F1.configure(this,...); 32 endfunction 33 34 virtual function void sample(uvm_reg_data_t data, 35 uvm_reg_data_r byte_en, 36 bit is_read, 37 uvm_reg_map map 38 ); 39 if(get_coverage(UVM_CVR_REG_BITS)) begin 40 m_current=get(); 41 m_data=data; 42 m_is_read=is_read; 43 cg1.sample(); 44 end 45 endfunction 46 endclass
4. uvm_reg的函数及作用
4.1 uvm_reg的configure函数及源码(在uvm_reg_block的build函数内调用)
(1) 通过调用uvm_reg的configure函数,在configure函数内调用m_parent.add_reg函数,将uvm_reg加入到uvm_reg_block中;
(2) 一般地,假如整个寄存器中只有一个字段的话,会在调用这个寄存器的configure函数时,指定此寄存器的hdl路径,这个路径本质上是其中的uvm_reg_field的路径; 但是当一个寄存器中有多个uvm_reg_field时,由于每个field都有各自的路径,即有多个路径,而在configure函数中只能指定一个参数,这种情况下,就需要手工调用add_hdl_path_slice函数;
1 function void uvm_reg::configure (uvm_reg_block blk_parent, 2 uvm_reg_file regfile_parent=null, 3 string hdl_path = ""); 4 if (blk_parent == null) begin 5 `uvm_error("UVM/REG/CFG/NOBLK", {"uvm_reg::configure() called without a parent block for instance \"", get_name(), "\" of register type \"", get_type_name(), "\"."}) 6 return; 7 end 8 9 m_parent = blk_parent; 10 m_regfile_parent = regfile_parent; 11 m_parent.add_reg(this); 12 if (hdl_path != "") 13 add_hdl_path_slice(hdl_path, -1, -1); 14 15 m_reg_registry[get_full_name()] = this; 16 endfunction: configure
4.2 uvm_reg的add_hdl_path_slice函数(在uvm_reg_block的build函数内调用)
1 function void uvm_reg::add_hdl_path_slice(string name, 2 int offset, 3 int size, 4 bit first = 0, 5 string kind = "RTL"); 6 uvm_queue #(uvm_hdl_path_concat) paths = m_hdl_paths_pool.get(kind); 7 uvm_hdl_path_concat concat; 8 9 if (first || paths.size() == 0) begin 10 concat = new(); 11 paths.push_back(concat); 12 end 13 else 14 concat = paths.get(paths.size()-1); 15 16 concat.add_path(name, offset, size); 17 endfunction
1 local uvm_object_string_pool #(uvm_queue #(uvm_hdl_path_concat)) m_hdl_paths_pool; 2 3 class uvm_pool #(type KEY=int, T=uvm_void) extends uvm_object; 4 5 const static string type_name = "uvm_pool"; 6 7 typedef uvm_pool #(KEY,T) this_type; 8 9 static protected this_type m_global_pool; 10 protected T pool[KEY]; 11 ... 12 13 endclass 14 15 class uvm_object_string_pool #(type T=uvm_object) extends uvm_pool #(string,T); 16 ... 17 virtual function T get (string key); 18 if (!pool.exists(key)) 19 pool[key] = new (key); 20 return pool[key]; 21 endfunction 22 ... 23 endclass
(1) m_hdl_paths_pool.get("kind")函数会返回uvm_pool中索引为kind的一条记录;一般来说,在调用add_hdl_path_slice时,最后一个参数kind不会传入任何值, 所以索引为默认值”RTL”,记录的内容是一个队列;
1 class uvm_hdl_path_concat; 2 3 // Variable: slices 4 // Array of individual slices, 5 // stored in most-to-least significant order 6 uvm_hdl_path_slice slices[]; 7 8 // Function: set 9 // Initialize the concatenation using an array literal 10 function void set(uvm_hdl_path_slice t[]); 11 slices = t; 12 endfunction 13 14 // Function: add_slice 15 // Append the specified ~slice~ literal to the path concatenation 16 function void add_slice(uvm_hdl_path_slice slice); 17 slices = new [slices.size()+1] (slices); 18 slices[slices.size()-1] = slice; 19 endfunction 20 21 // Function: add_path 22 // Append the specified ~path~ to the path concatenation, 23 // for the specified number of bits at the specified ~offset~. 24 function void add_path(string path, 25 int unsigned offset = -1, 26 int unsigned size = -1); 27 uvm_hdl_path_slice t; 28 t.offset = offset; 29 t.path = path; 30 t.size = size; 31 32 add_slice(t); 33 endfunction 34 35 endclass
(2) add_hdl_path_slice的效果是向m_hdl_paths_pool中索引为”RTL”的记录对应的队列中的最后一条记录的uvm_hdl_path_concat的实例的动态数组中插入一条记录-uvm_hdl_path_slice;
4.3 uvm_reg的add_map函数
4.4 uvm_reg的get_rights函数
1 function string uvm_reg::get_rights(uvm_reg_map map = null); 2 3 uvm_reg_map_info info; 4 5 map = get_local_map(map,"get_rights()"); 6 7 if (map == null) 8 return "RW"; 9 10 info = map.get_reg_map_info(this); 11 return info.rights; 12 13 endfunction
5. uvm_reg的使用
(1) 在reg_block或reg_file的build函数内实例化(uvm_mem同样);
(2) 在reg_block内调用uvm_reg的configure函数;
(3) uvm_reg的build函数不会自动执行,需要在reg_block的build函数内手动调用;
【推荐】国内首个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吗?