[CU]reg model使用篇-uvm_reg常用操作part3(XatomicX/read/write(frontdoor/backdoor))

1. XatomicX

(1) 当要访问互斥的资源时,即只允许一个进程访问,其他进程必须在此进行访问完成之后才能访问,可以使用XatomicX(1) + access the resource +XatomicX(0)实现;

(2) read, write, poke, peek, mirror等操作中,都用类似的方法保证同一时间只有一个进程对互斥资源进行访问;

注1: register model可以由多个线程并行访问,但是register model内部会串行处理这些进程,这样做是为了确保当同一个register field被访问时,其隐式更新的镜像值可预测;

注2: 每一个register内都有一个旗语m_atomic来确保它同时只能被一个进程访问; 如果一个线程在执行过程中,被显式杀掉, 有必要调用uvm_reg::reset()释放掉它所占用的key;

注3:在实际仿真过程中,发现采用寄存器后门读一个uvm_reg_field时,没有立即返回读取值,而是隔了很久,就是因为在XatomicX中获取旗语时hang住;hang住的原因是在另一处调用了前门操作对该uvm_reg_field所在uvm_reg的另一个uvm_reg_field进行写操作;

复制代码
 1 local semaphore         m_atomic;
 2 local process           m_process;
 3 
 4 function void uvm_reg::reset(string kind = "HARD");
 5    foreach (m_fields[i])
 6       m_fields[i].reset(kind);
 7    // Put back a key in the semaphore if it is checked out
 8    // in case a thread was killed during an operation
 9    void'(m_atomic.try_get(1));
10    m_atomic.put(1);
11    m_process = null;
12    Xset_busyX(0);
13 endfunction: reset
14 
15 task uvm_reg::XatomicX(bit on);
16    process m_reg_process;
17    m_reg_process=process::self();
18 
19    if (on) begin
20      if (m_reg_process == m_process)
21        return;
22      m_atomic.get(1);
23      m_process = m_reg_process; 
24    end
25    else begin
26       // Maybe a key was put back in by a spurious call to reset()
27       void'(m_atomic.try_get(1));
28       m_atomic.put(1);
29       m_process = null;
30    end
31 endtask: XatomicX
复制代码

2. read/write (frontdoor)

1 regmodel.register.read(status,value,UVM_FRONTDOOR,.parent(this));
2 regmodel.register.write(status,value,UVM_FRONTDOOR,.parent(this));

2.1 read/write (frontdoor)操作的影响

(1) 当使用front-door(path=BFM), 一个或多个实际的transaction会发往DUT进行register的读写;

(2) 无论通过前门访问还是后门访问的方式从DUT中读取或写入寄存器的值,在操作完成后,寄存器模型都会根据读写的结果更新期望值和镜像值(其实是有前提条件的,对于后门访问,会自动更新镜像值和期望值; 对于前门访问,更新镜像值和期望值有两种方法: (a) auto_predict功能需要打开,即在env中调用uvm_reg_map.set_auto_predict(1),然后调用do-predict函数更新寄存器模型的mirror值; (b)关闭auto_predict功能,使用uvm_reg_predictor进行更新);

(3) 如果寄存器map到多个uvm_address_map,在调用uvm_reg的write/read task进行前门访问时,需要指定uvm_reg_map参数;

2.2 write (frontdoor)的源码

(1) uvm_reg::write

(1.1) FRONTDOOR write操作最终会转换为uvm_reg_map的do_write任务;

(1.2) uvm_reg_map的do_write任务会查看系统是否设置了adapter,如果没有设置,就直接启动sequence, 让sequencer发送uvm_reg_item类型的transaction;如果设置了,那就调用do_bus_write任务.

(1.3) uvm_reg_map的do_write完成后,如果auto predict功能打开了, uvm_reg的do_write会根据写入的值更新register model中寄存器的值;

复制代码
 1 task uvm_reg::write(output uvm_status_e      status,
 2                     input  uvm_reg_data_t    value,
 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 
11    // create an abstract transaction for this operation
12    uvm_reg_item rw;
13 
14    XatomicX(1);
15 
16    set(value);
17 
18    rw = uvm_reg_item::type_id::create("write_item",,get_full_name());
19    rw.element      = this;
20    rw.element_kind = UVM_REG;
21    rw.kind         = UVM_WRITE;
22    rw.value[0]     = value;
23    rw.path         = path;
24    rw.map          = map;
25    rw.parent       = parent;
26    rw.prior        = prior;
27    rw.extension    = extension;
28    rw.fname        = fname;
29    rw.lineno       = lineno;
30 
31    do_write(rw);
32 
33    status = rw.status;
34 
35    XatomicX(0);
36 
37 endtask
复制代码

(2) uvm_reg::do_write

复制代码
 1 task uvm_reg::do_write (uvm_reg_item rw);
 2 
 3    uvm_reg_cb_iter  cbs = new(this);
 4    uvm_reg_map_info map_info;
 5    uvm_reg_data_t   value; 
 6 
 7    m_fname  = rw.fname;
 8    m_lineno = rw.lineno;
 9 
10    if (!Xcheck_accessX(rw,map_info,"write()"))
11      return;
12 
13    XatomicX(1);
14 
15    m_write_in_progress = 1'b1;
16 
17    rw.value[0] &= ((1 << m_n_bits)-1);
18    value = rw.value[0];
19 
20    rw.status = UVM_IS_OK;
21 
22    // PRE-WRITE CBS - FIELDS
23    begin : pre_write_callbacks
24       ...
25    end
26    rw.element = this;
27    rw.element_kind = UVM_REG;
28    rw.value[0] = value;
29 
30    // PRE-WRITE CBS - REG
31    pre_write(rw);
32    for (uvm_reg_cbs cb=cbs.first(); cb!=null; cb=cbs.next())
33       cb.pre_write(rw);
34 
35    if (rw.status != UVM_IS_OK) begin
36      m_write_in_progress = 1'b0;
37 
38      XatomicX(0);
39          
40      return;
41    end
42          
43    // EXECUTE WRITE...
44    case (rw.path)
45       
46       // ...VIA USER BACKDOOR
47       UVM_BACKDOOR: begin
48         ...
49       end
50 
51       UVM_FRONTDOOR: begin
52 
53          uvm_reg_map system_map = rw.local_map.get_root_map();
54 
55          m_is_busy = 1;
56 
57          // ...VIA USER FRONTDOOR
58          if (map_info.frontdoor != null) begin
59             uvm_reg_frontdoor fd = map_info.frontdoor;
60             fd.rw_info = rw;
61             if (fd.sequencer == null)
62               fd.sequencer = system_map.get_sequencer();
63             fd.start(fd.sequencer, rw.parent);
64          end
65 
66          // ...VIA BUILT-IN FRONTDOOR
67          else begin : built_in_frontdoor
68 
69             rw.local_map.do_write(rw);
70 
71          end
72 
73          m_is_busy = 0;
74 
75          if (system_map.get_auto_predict()) begin
76             uvm_status_e status;
77             if (rw.status != UVM_NOT_OK) begin
78                sample(value, -1, 0, rw.map);
79                m_parent.XsampleX(map_info.offset, 0, rw.map);
80             end
81 
82             status = rw.status; // do_predict will override rw.status, so we save it here
83             do_predict(rw, UVM_PREDICT_WRITE);
84             rw.status = status;
85          end
86       end
87       
88    endcase
89 
90    ...
91    XatomicX(0);
92 
93 endtask: do_write
复制代码

(3) uvm_reg_map.do_write

(3.1) 24到26行把要写的item通过sequencer发送出去,27行调用rw.end_event的wait_on;

(3.2) sequence.finish_item task中会调用sequencer.end_tr,而sequencer.end_tr会在driver调用item_done后结束;

(3.3) sequencer.end_tr内会触发end_event事件;

复制代码
 1 task uvm_reg_map::do_write(uvm_reg_item rw);
 2 
 3   uvm_sequence_base tmp_parent_seq;
 4   uvm_reg_map system_map = get_root_map();
 5   uvm_reg_adapter adapter = system_map.get_adapter();
 6   uvm_sequencer_base sequencer = system_map.get_sequencer();
 7 
 8   if (adapter != null && adapter.parent_sequence != null) begin
 9     uvm_object o;
10     uvm_sequence_base seq;
11     o = adapter.parent_sequence.clone();
12     assert($cast(seq,o));
13     seq.set_parent_sequence(rw.parent);
14     rw.parent = seq;
15     tmp_parent_seq = seq;
16   end
17 
18   if (rw.parent == null) begin
19      rw.parent = new("default_parent_seq");
20      tmp_parent_seq = rw.parent;
21   end
22 
23   if (adapter == null) begin
24     rw.set_sequencer(sequencer);
25     rw.parent.start_item(rw,rw.prior);
26     rw.parent.finish_item(rw);
27     rw.end_event.wait_on();
28   end
29   else begin
30     do_bus_write(rw, sequencer, adapter);
31   end
32 
33   if (tmp_parent_seq != null)
34     sequencer.m_sequence_exiting(tmp_parent_seq);
35 
36 endtask
复制代码

2.3 read (frontdoor)源码

复制代码
 1 task uvm_reg::read(output uvm_status_e      status,
 2                    output uvm_reg_data_t    value,
 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    XatomicX(1);
11    XreadX(status, value, path, map, parent, prior, extension, fname, lineno);
12    XatomicX(0);
13 endtask: read
复制代码
复制代码
 1 task uvm_reg::XreadX(output uvm_status_e      status,
 2                      output uvm_reg_data_t    value,
 3                      input  uvm_path_e        path,
 4                      input  uvm_reg_map       map,
 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    
11    // create an abstract transaction for this operation
12    uvm_reg_item rw;
13    rw = uvm_reg_item::type_id::create("read_item",,get_full_name());
14    rw.element      = this;
15    rw.element_kind = UVM_REG;
16    rw.kind         = UVM_READ;
17    rw.value[0]     = 0;
18    rw.path         = path;
19    rw.map          = map;
20    rw.parent       = parent;
21    rw.prior        = prior;
22    rw.extension    = extension;
23    rw.fname        = fname;
24    rw.lineno       = lineno;
25 
26    do_read(rw);
27 
28    status = rw.status;
29    value = rw.value[0];
30 
31 endtask: XreadX
复制代码

3. read/write (backdoor)

 

(1) 当使用back-door(path=BACKDOOR)时, 会通过uvm_hdl_read/uvm_hdl_deposit函数获取或修改DUT register值,而不会通过物理上的interface;

(2) 但是back-door的访问方式会尽量模拟前门访问的行为,比如如果对一个只读寄存器进行后门写操作,由于要模拟DUT的只读行为,所以是写不进去的;

(3) 无论通过前门访问还是后门访问的方式,从DUT中读取或写入寄存器的值,在操作完成后,寄存器模型都会根据读写的结果更新期望值和镜像值(对于前门访问而言,前提条件是system_map.get_auto_predict为1);

 

 

 

 

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

导航

统计

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