[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
【推荐】国内首个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吗?