[CU]reg model构建篇-uvm_reg_adapter(与前门访问相关)

资料来源

(1) 浅谈UVM register adapter机制 (qq.com)

(2) 《UVM cookbook》

注1:该篇文章会涉及到uvm_reg_bus_op转换为uvm_sequence_item以及uvm_sequence_item发送的细节;

注2:前门访问寄存器方式1- 使用reg model以前门方式访问寄存器时,需要adapter的参与(实现uvm_reg_item到bus_transaction的转换);

注3:前门访问寄存器方式2-直接通过bus_agent(包括bus_sequencer, bus_driver等), bus sequence, bus transaction进行;这种方式绕开了reg model;

1. uvm_reg_adapter的作用

(1) uvm_reg_adapter对于前门操作而言必不可少;

注1:将reg model集成到testbench的先决条件是:  a)register model已经准备好;   b)uvm_reg_adapter类准备好;

(2) 《uvm cookbook》中对uvm_reg_adapter作用的描述比较好,如下:

There are two parts to the register adaption layer, the first part implements the sequence based stimulus layering(即reg2bus转换) and the second part implements the analysis based update of the register model using a predictor component(即bus2reg转换);

2. uvm_reg_bus_op

复制代码
 1 typedef struct {
 2 
 3   uvm_access_e kind;
 4   uvm_reg_addr_t addr;
 5   uvm_reg_data_t data;
 6   int n_bits;
 7   uvm_reg_byte_en_t byte_en;
 8   uvm_status_e status;
 9 
10 } uvm_reg_bus_op;
复制代码

3. uvm_reg_adapter派生类的实现

复制代码
 1 virtual class uvm_reg_adapter extends uvm_object;
 2 
 3   function new(string name="");
 4     super.new(name);
 5   endfunction
 6 
 7   bit supports_byte_enable;
 8   bit provides_responses; 
 9   uvm_sequence_base parent_sequence; 
10 
11   pure virtual function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw);
12   pure virtual function void bus2reg(uvm_sequence_item bus_item,ref uvm_reg_bus_op rw);
13 
14   local uvm_reg_item m_item;
15 
16   virtual function uvm_reg_item get_item();
17     return m_item;
18   endfunction
19   
20   virtual function void m_set_item(uvm_reg_item item);
21     m_item = item;
22   endfunction
23 endclass
复制代码

(1)定义reg2bus函数,将寄存器模型通过sequence发出的uvm_reg_bus_op型变量(register model使用的通用transaction)转换成bus_sequencer能够接受的形式(与协议相关的transaction);

(2) 定义bus2reg函数,将从总线上收集来的transaction转换成寄存器模型能够接受的形式,以便寄存器模型能够更新相应的寄存器的值.

(3) supports_byte_enable成员变量:如果bus协议支持byte enable,需要在adapter的new函数中将supports_byte_enable配为0;

(4) provides_responses成员变量:如果agent driver返回一个单独的response item(比如通过put(response)或者item_done(response)),那么provides_response就会被用于register model层决定是否wait response; provides_response被设置为1的情况下,如果driver没有回复response,会发生异常情况(详见《uvm cookbook》);

复制代码
 1 //示例1
 2 
 3 class my_adapter extends uvm_reg_adapter;
 4     `uvm_object_utils(my_adapter)
 5     string tID=get_type_name();
 6 
 7     function new(string name="my_adapter");
 8         super.new(name);
 9     endfunction
10 
11     //uvm_reg_bus_op->bus_transaction
12     function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw);
13         bus_transaction tr;
14         tr=new("tr");
15         tr.addr=rw.addr;
16         tr.bus_op=(rw.kind==UVM_READ)?BUS_RD:BUS_WR;
17 
18         if(tr.bus_op==BUS_WR) tr.wr_data=rw.data;
19         return tr;
20     endfunction
21 
22     //bus_transaction->uvm_reg_bus_op
23     function void bus2reg(uvm_sequence_item bus_item, ref uvm_reg_bus_op rw);
24         bus_transaction tr;
25         if(!$cast(tr,bus_item)) begin
26             `uvm_fatal(tID,"Provided bus_item is not of the correct type, expecting bus_trans action")
27             return;
28         end
29 
30         rw.kind=(tr.bus_op==BUS_RD)?UVM_READ:UVM_WRITE;
31         rw.addr=tr.addr;
32         rw.byte_en='h3;
33         rw.data=(tr.bus_op==BUS_RD)?tr.rd_data:tr.wr_data;
34         rw.status=UVM_IS_OK;
35     endfunction
36 endclass
复制代码
复制代码
 1 //示例2
 2 class reg2apb_adapter extends uvm_reg_adapter;
 3     `uvm_object_utils(reg2apb_adapter)
 4 
 5     function new(string name="reg2apb_adapter");
 6         super.new(name);
 7     endfunction
 8 
 9     virtual function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw);
10         apb_rw apb=apb_rw::type_id::create("apb_rw");
11         apb.kind=(rw.kind==UVM_READ)?apb_rw::READ : apb_rw::WRITE;
12         apb.addr=rw.addr;
13         apb.data=rw.data;
14         return apb;
15     endfunction
16 
17     virtual fuction void bus2reg(uvm_sequence_item bus_item, ref uvm_reg_bus_op rw);
18         apb_rw apb;
19         if(!$cast(apb, bus_item)) begin
20             `uvm_fatal("NOT_APB_TYPE","provided bus_item is not of the correct type")
21             return;
22         end
23 
24         rw.kind=apb.kind?UVM_READ:UVM_WRITE;
25         rw.addr=apb.addr;
26         rw.data=apb.data;
27         rw.status=UVM_IS_OK;
28     endfunction
29 endclass
30 
31 class block_env extends uvm_env;
32     block_reg_model regmodel;
33     subblk_env subblk;
34 
35     virtual function void connect_phase(uvm_phase phase);
36         ...
37         if(regmodel.get_parent==null) begin
38             reg2apb_adapter reg2apb=reg2apb_adapter::type_id::create("reg2apb",get_full_name());
39             ...
40         end
41     endfunction
42 
43 endclass
复制代码
复制代码
 1 //示例3
 2 
 3 class vga_ral_adapter extends uvm_reg_adapter;
 4     `uvm_object_utils(vga_ral_adapter)
 5 
 6     function new(string name="");
 7         super.new(name);
 8     endfunction
 9 
10     virtual function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw);
11         wb_transaction w_trans;
12         w_trans=wb_transaction::type_id::create("w_trans");
13         w_trans.address=rw.addr;
14         w_trans.sel=4'hf;
15         w_trans.data=rw.data;
16         w_trans.kind=(rw.kind==UVM_READ)?wb_transaction::READ:wb_transaction::WRITE;
17         
18         return w_trans;
19     endfunction
20 
21     virtual function void bus2reg(uvm_sequence_item bus_item, ref uvm_reg_bus_op rw);
22         wb_transaction trans;
23         if(!$cast(trans,bus_item)) begin
24             `uvm_fatal("BUS2REF", "Wrong type received")
25         end
26 
27         rw.addr=trans.address;
28         rw.data=trans.data;
29         rw.kind=(trans.kind==wb_transaction::READ)?UVM_READ:UVM_WRITE;
30         rw.status=UVM_IS_OK;
31     endfunction
32 endclass 
复制代码

4. uvm_reg_adapter的具体工作过程(前门访问)

(1) 通过reg_model write/read task发寄存器读写命令;

1 uvm_status_e status;
2 bit[31:0] rdata;
3 
4 env.reg_model.XXXX_REG.write(status, 32'haaaa_ffff);
5 env.reg_model.XXXX_REG.read(status, rdata);

(2)在uvm_reg::write(*) task内,会调用uvm_reg::do_write(uvm_reg_item rw) task,并最终调用uvm_reg_item.local_map.do_write task,即uvm_reg_map.do_write;

(3)在uvm_reg_map的do_write task中,会先为uvm_reg_item.parent赋值,然后调用uvm_reg_map::do_bus_write task;

复制代码
 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
复制代码

(4)在uvm_reg_map::do_bus_write task中,会调用uvm_reg_adapter.reg2bus将uvm_reg_bus_op转换为uvm_sequence_item;

(5)为uvm_seq_item设置相应的sequencer(该sequencer为uvm_reg_map的sequencer),并调用uvm_reg_item.parent.start_item(uvm_seq_item)进行trans的发送;

注1:uvm_reg与uvm_reg_map的联系是通过uvm_reg_map.add_reg建立的;uvm_reg_map::add_reg函数会调用uvm_reg.add_map(this);uvm_reg.add_map(this)会将this指向的uvm_reg_map作为uvm_reg的关联数组m_maps的索引);

复制代码
 1 function void uvm_reg_map::add_reg(uvm_reg rg, 
 2                                    uvm_reg_addr_t offset,
 3                                    string rights = "RW",
 4                                    bit unmapped=0,
 5                                    uvm_reg_frontdoor frontdoor=null);
 6 
 7    if (m_regs_info.exists(rg)) begin
 8       `uvm_error("RegModel", {"Register '",rg.get_name(),
 9                  "' has already been added to map '",get_name(),"'"})
10       return;
11    end
12 
13    if (rg.get_parent() != get_parent()) begin
14       `uvm_error("RegModel",
15          {"Register '",rg.get_full_name(),"' may not be added to address map '",
16           get_full_name(),"' : they are not in the same block"})
17       return;
18    end
19    
20    rg.add_map(this);
21 
22    begin
23    uvm_reg_map_info info = new;
24    info.offset   = offset;
25    info.rights   = rights;
26    info.unmapped = unmapped;
27    info.frontdoor = frontdoor;
28    m_regs_info[rg] = info;
29    end
30 endfunction
复制代码
1 function void uvm_reg::add_map(uvm_reg_map map);
2   m_maps[map] = 1;
3 endfunction

注2:uvm_reg_item与uvm_reg_map的联系是怎么建立的? uvm_reg_item.local_map是在uvm_reg::do_write调用的Xcheck_accessX内获取的; uvm_reg_item.map是在uvm_reg::write等函数内获取的);

复制代码
 1 function bit uvm_reg::Xcheck_accessX (input uvm_reg_item rw,
 2                                       output uvm_reg_map_info map_info,
 3                                       input string caller);
 4 
 5 
 6    if (rw.path == UVM_DEFAULT_PATH)
 7      rw.path = m_parent.get_default_path();
 8 
 9    if (rw.path == UVM_BACKDOOR) begin
10       if (get_backdoor() == null && !has_hdl_path()) begin
11          `uvm_warning("RegModel",
12             {"No backdoor access available for register '",get_full_name(),
13             "' . Using frontdoor instead."})
14          rw.path = UVM_FRONTDOOR;
15       end
16       else
17         rw.map = uvm_reg_map::backdoor();
18    end
19 
20 
21    if (rw.path != UVM_BACKDOOR) begin
22 
23      rw.local_map = get_local_map(rw.map,caller);
24 
25      if (rw.local_map == null) begin
26         `uvm_error(get_type_name(), 
27            {"No transactor available to physically access register on map '",
28             rw.map.get_full_name(),"'"})
29         rw.status = UVM_NOT_OK;
30         return 0;
31      end
32 
33      map_info = rw.local_map.get_reg_map_info(this);
34 
35      if (map_info.frontdoor == null && map_info.unmapped) begin
36           `uvm_error("RegModel", {"Register '",get_full_name(),
37              "' unmapped in map '",
38              (rw.map==null)? rw.local_map.get_full_name():rw.map.get_full_name(),
39              "' and does not have a user-defined frontdoor"})
40           rw.status = UVM_NOT_OK;
41           return 0;
42      end
43 
44      if (rw.map == null)
45        rw.map = rw.local_map;
46    end
47    return 1;
48 endfunction
复制代码

5. uvm_reg_adapter与bus_seqr及uvm_reg_map的联系

(1)通过调用regmodel.reg_map的set_sequencer(sequencer, adapter)函数使用reg adapter;

1 //示例1
2 default_map.set_sequencer(env.bus_agt.sqr,reg_sqr_adapter);
1 //示例2
2 virtual function void connect_phase(uvm_phase phase);
3     super.connect_phase(phase);
4     reg_adapter adapter;
5     adapter=reg_adapter::type_id::create("adapter",this);
6     regmodel.default_map.set_sequence(m_agent.seqr,adapter);
7 endfunction

 

 

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

编辑推荐:
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
< 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

导航

统计

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