[CU]reg model使用篇-uvm_reg常用操作part1(randomize, update, get, set, mirror, predict, reset, get_reset, get_parent, get_mirrored_value)

1. randomize

注1:uvm1_2中uvm_reg类内没有该函数,uvm_reg_field内有该函数;

1.1 randomize的影响

(1) randomize操作会改变register field的期望值(uvm_reg_field的post_randomize函数内,会将期望值设置为随机的结果),镜像值不会改变;

1 function void uvm_reg_field::post_randomize();
2    m_desired = value;
3 endfunction: post_randomize

(2) 如果在randomize后,跟着调用update,会将期望值写入DUT;

1.2 randomize的使用

(1) 在向uvm_reg中加入uvm_reg_field时,将加入的uvm_reg_field定义为rand类型;

(2) 在将uvm_reg加入到uvm_reg_block中时,将uvm_reg定义为rand类型;

(3) 如果要使某个uvm_reg_field能够随机化,只是将其定义为rand类型并不够; 在将uvm_reg_field加入uvm_reg时,要调用其configure函数并设置合适的参数;此外,uvm_reg_field还需是合适的类型,如RW, WRC, WRS等;

(4) 可以在uvm_reg_field, uvm_reg等中为randomize定义约束;

2. update

2.1 update操作的影响

(1) update操作会检查寄存器的期望值和镜像值是否一致(调用needs_update进行检查);

(2) 如果期望值(可以调用set()或者randomize()函数进行改变)和镜像值不同,调用update函数,期望值会通过write函数被配置到DUT中(可以指定使用FRONTDOOR还是BACKDOOR),同时镜像值也会更新;

1 my_reg1.myfield2.set(0x11);
2 my_reg1.myfield3.set(1);
3 my_reg1.update();

2.2 update源码

复制代码
 1 //uvm_reg_field.svh
 2 function bit uvm_reg_field::needs_update();
 3    needs_update = (m_mirrored != m_desired) | m_volatile;
 4 endfunction: needs_update
 5 
 6 //uvm_reg.svh
 7 function bit uvm_reg::needs_update();
 8    needs_update = 0;
 9    foreach (m_fields[i]) begin
10       if (m_fields[i].needs_update()) begin
11          return 1;
12       end
13    end
14 endfunction: needs_update
15 
16 task uvm_reg::update(output uvm_status_e      status,
17                      input  uvm_path_e        path = UVM_DEFAULT_PATH,
18                      input  uvm_reg_map       map = null,
19                      input  uvm_sequence_base parent = null,
20                      input  int               prior = -1,
21                      input  uvm_object        extension = null,
22                      input  string            fname = "",
23                      input  int               lineno = 0);
24    uvm_reg_data_t upd;
25 
26    status = UVM_IS_OK;
27 
28    if (!needs_update()) return;
29 
30    // Concatenate the write-to-update values from each field
31    // Fields are stored in LSB or MSB order
32    upd = 0;
33    foreach (m_fields[i])
34       upd |= m_fields[i].XupdateX() << m_fields[i].get_lsb_pos();
35 
36    write(status, upd, path, map, parent, prior, extension, fname, lineno);
37 endtask: update
复制代码

3. get & set

(1) 获取(get)或修改(set)期望值(不是硬件实际值);set操作会更新期望值,但是镜像值不会改变;

(2) 如果在set后,跟着调用update,会将期望值写入DUT;

复制代码
 1 //uvm_reg.svh
 2 function void uvm_reg::set(uvm_reg_data_t  value,
 3                            string          fname = "",
 4                            int             lineno = 0);
 5    // Split the value into the individual fields
 6    m_fname = fname;
 7    m_lineno = lineno;
 8 
 9    foreach (m_fields[i])
10       m_fields[i].set((value >> m_fields[i].get_lsb_pos()) &
11                        ((1 << m_fields[i].get_n_bits()) - 1));
12 endfunction: set
13 
14 //uvm_reg_field.svh
15 function void uvm_reg_field::set(uvm_reg_data_t  value,
16                                  string          fname = "",
17                                  int             lineno = 0);
18    uvm_reg_data_t mask = ('b1 << m_size)-1;
19 
20    m_fname = fname;
21    m_lineno = lineno;
22    if (value >> m_size) begin
23       `uvm_warning("RegModel",
24          $sformatf("Specified value (0x%h) greater than field \"%s\" size (%0d bits)",
25              value, get_name(), m_size));
26       value &= mask;
27    end
28 
29    if (m_parent.is_busy()) begin
30       `uvm_warning("UVM/FLD/SET/BSY",
31                    $sformatf("Setting the value of field \"%s\" while containing register \"%s\" is being accessed may result in loss of desired field value. A race condition between threads concurrently accessing the register model is the likely cause of the problem.",
32                              get_name(), m_parent.get_full_name()))
33    end
34 
35    case (m_access)
36       "RO":    m_desired = m_desired;
37       "RW":    m_desired = value;
38       "RC":    m_desired = m_desired;
39       "RS":    m_desired = m_desired;
40       "WC":    m_desired = '0;
41       "WS":    m_desired = mask;
42       "WRC":   m_desired = value;
43       "WRS":   m_desired = value;
44       "WSRC":  m_desired = mask;
45       "WCRS":  m_desired = '0;
46       "W1C":   m_desired = m_desired & (~value);
47       "W1S":   m_desired = m_desired | value;
48       "W1T":   m_desired = m_desired ^ value;
49       "W0C":   m_desired = m_desired & value;
50       "W0S":   m_desired = m_desired | (~value & mask);
51       "W0T":   m_desired = m_desired ^ (~value & mask);
52       "W1SRC": m_desired = m_desired | value;
53       "W1CRS": m_desired = m_desired & (~value);
54       "W0SRC": m_desired = m_desired | (~value & mask);
55       "W0CRS": m_desired = m_desired & value;
56       "WO":    m_desired = value;
57       "WOC":   m_desired = '0;
58       "WOS":   m_desired = mask;
59       "W1":    m_desired = (m_written) ? m_desired : value;
60       "WO1":   m_desired = (m_written) ? m_desired : value;
61       default: m_desired = value;
62    endcase
63    this.value = m_desired;
64 endfunction: set
复制代码
复制代码
 1 //uvm_reg.svh
 2 function uvm_reg_data_t  uvm_reg::get(string  fname = "",
 3                                       int     lineno = 0);
 4    // Concatenate the value of the individual fields
 5    // to form the register value
 6    m_fname = fname;
 7    m_lineno = lineno;
 8 
 9    get = 0;
10    
11    foreach (m_fields[i])
12       get |= m_fields[i].get() << m_fields[i].get_lsb_pos();
13 endfunction: get
14 
15 //uvm_reg_field.svh
16 function uvm_reg_data_t  uvm_reg_field::get(string  fname = "",
17                                             int     lineno = 0);
18    m_fname = fname;
19    m_lineno = lineno;
20    get = m_desired;
21 endfunction: get
复制代码

4. mirror

4.1 mirror操作的影响

(1) mirror方法会调用read()函数,读取DUT(读取的方式可以选择BACKDOOR或者FRONTDOOR),然后根据read的返回值,更新镜像值和期望值;

(2) mirror方法的两种应用场景:

一是在仿真中不断的调用它,使得到整个寄存器模型的镜像值与DUT中寄存器的值保持一致,此时check选项是关闭的(即如果mirror操作发现DUT中寄存器的值和寄存器模型中的镜像值不一致,那么在更新寄存器模型之前不给出错误提示);

二是在仿真即将结束时,检查DUT中寄存器的值与寄存器模型中DUT的镜像值是否一致,这种情况下,check选项是打开的;

4.2 mirror源码

(1) mirror操作中会根据check参数的情况,来决定是否把mirror前的寄存器值保存下来; 如果设置了UVM_CHECK,后面会对mirror前后的寄存器值进行比较;

(2) 注:下文的源代码比较旧,新版中exp=get_mirrored_value,而不是exp=get();

复制代码
 1 task uvm_reg::mirror(output uvm_status_e       status,
 2                      input  uvm_check_e        check = UVM_NO_CHECK,
 3                      input  uvm_path_e         path = UVM_DEFAULT_PATH,
 4                      input  uvm_reg_map        map = null,
 5                      input  uvm_sequence_base  parent = null,
 6                      input  int                prior = -1,
 7                      input  uvm_object         extension = null,
 8                      input  string             fname = "",
 9                      input  int                lineno = 0);
10    uvm_reg_data_t  v;
11    uvm_reg_data_t  exp;
12    uvm_reg_backdoor bkdr = get_backdoor();
13 
14    XatomicX(1);
15    m_fname = fname;
16    m_lineno = lineno;
17 
18 
19    if (path == UVM_DEFAULT_PATH)
20      path = m_parent.get_default_path();
21 
22    if (path == UVM_BACKDOOR && (bkdr != null || has_hdl_path()))
23      map = uvm_reg_map::backdoor();
24    else
25      map = get_local_map(map, "read()");
26 
27    if (map == null)
28      return;
29    
30    // Remember what we think the value is before it gets updated
31    if (check == UVM_CHECK)
32      exp = get_mirrored_value();
33 
34    XreadX(status, v, path, map, parent, prior, extension, fname, lineno);
35 
36    if (status == UVM_NOT_OK) begin
37       XatomicX(0);
38       return;
39    end
40 
41    if (check == UVM_CHECK) void'(do_check(exp, v, map));
42 
43    XatomicX(0);
44 endtask: mirror
复制代码

5. predict

5.1 predict操作的影响

(1) 可以实现人为地更新镜像值和期望值为要设置的值,但是同时又不对DUT进行任何操作;这种情况下,需要采用kind的默认值,即UVM_PREDICT_DIRECT;

5.2 predict操作的使用

(1) read/peek和write/poke操作对DUT完成读写后,也会调用此函数,只是它们给出的参数是UVM_PREDICT_READ和UVM_PREDICT_WRITE(使用这两个参数的区别? 详见uvm_reg_field的do_predict函数);

(2) 在显式预测中,predictor内会调用uvm_predict函数进行镜像值的更新;

5.3 predict源码

复制代码
 1 function bit uvm_reg::predict (uvm_reg_data_t    value,
 2                                uvm_reg_byte_en_t be = -1,
 3                                uvm_predict_e     kind = UVM_PREDICT_DIRECT,
 4                                uvm_path_e        path = UVM_FRONTDOOR,
 5                                uvm_reg_map       map = null,
 6                                string            fname = "",
 7                                int               lineno = 0);
 8   uvm_reg_item rw = new;
 9   rw.value[0] = value;
10   rw.path = path;
11   rw.map = map;
12   rw.fname = fname;
13   rw.lineno = lineno;
14   do_predict(rw, kind, be);
15   predict = (rw.status == UVM_NOT_OK) ? 0 : 1;
16 endfunction: predict
复制代码

6. reset

复制代码
 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) reset方法将寄存器的期望值和镜像值设置为预定义的register reset值;

(2) 当硬件发生reset时,会将内部寄存器值复位,寄存器模型在捕捉到复位事件时,需要调用register model.reset保证硬件和register model的一致性;

(3) 硬件复位后,用户可以通过读取寄存器模型的复位值(与寄存器描述文件一致),与前门访问获取的寄存器复位值进行比较,以此判断硬件各个寄存器的复位值是否按照寄存器描述去实现。

复制代码
1 @(negedge p_sequencer.vif.rstn);
2 rgm.reset();
3 reg.chnl0_ctrl_reg.reset();
4 reg.chnl0_ctrl_reg.pkt_len.reset();
5 
6 rstval=rgm.chnl0_ctrl_reg.get_reset();
7 rgm.chnl0_ctrl_reg.read(status,data,UVM_BACKDOOR,.parent(this));
8 if(rstval!=data) 
9     `uvm_error("RSTERR","reset value read is not the desired reset value")
复制代码

7. get_reset

(1) get_reset方法返回register或者register field预定义的reset值;

(2) get_reset通常和read/mirror共同使用,用于检查register是否被正确的reset;

8.get_parent

复制代码
 1 function uvm_reg_block uvm_reg::get_parent();
 2   return get_block();
 3 endfunction
 4 
 5 function uvm_reg_block uvm_reg::get_block();
 6    get_block = m_parent;
 7 endfunction
 8 
 9 function void uvm_reg::configure (uvm_reg_block blk_parent,
10                                   uvm_reg_file regfile_parent=null,
11                                   string hdl_path = "");
12    if (blk_parent == null) begin
13      `uvm_error("UVM/REG/CFG/NOBLK", {"uvm_reg::configure() called without a parent block for instance \"", get_name(), "\" of register type \"", get_type_name(), "\"."})
14      return;
15    end
16 
17    m_parent = blk_parent;
18    m_regfile_parent = regfile_parent;
19    m_parent.add_reg(this);
20    if (hdl_path != "")
21      add_hdl_path_slice(hdl_path, -1, -1);
22 
23    m_reg_registry[get_full_name()] = this;
24 endfunction: configure
复制代码

9.get_mirrored_value

复制代码
 1 function uvm_reg_data_t  uvm_reg::get_mirrored_value(string  fname = "",
 2                                       int     lineno = 0);
 3    // Concatenate the value of the individual fields
 4    // to form the register value
 5    m_fname = fname;
 6    m_lineno = lineno;
 7 
 8    get_mirrored_value = 0;
 9    
10    foreach (m_fields[i])
11       get_mirrored_value |= m_fields[i].get_mirrored_value() << m_fields[i].get_lsb_pos();
12 endfunction: get_mirrored_value
复制代码

 

posted on   知北游。。  阅读(3399)  评论(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

导航

统计

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