[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函数内手动调用;

 

 

posted on   知北游。。  阅读(1446)  评论(0编辑  收藏  举报

编辑推荐:
· .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吗?
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

导航

统计

点击右上角即可分享
微信分享提示