登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

Design IC

慢即是快,快即是慢

 
 
 

日志

 
 

uvm_blocking_put_port/uvm_blocking_put_imp实现的简单模型  

2011-01-13 18:44:02|  分类: SystemVerilog |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

UVM中TLM的使用非常方便,通过简单的connect()函数,就可以将两个不相关的对象紧紧联系在一起。为什么会如此简单,其背后的原理是什么呢?今天抽空分析了UVM的源代码,基本上了解了put_port/put_imp的实现机制。于是借用UVM的实现原理,我简单了编写了一个小程序,抛掉不必要的繁文缛节,基本上能够展示其背后的实现原理。

代码如下:

 1 /**
 2  * * tlm.sv 
 3  * * 说明: 通过简单的模型来阐述 UVM/OVM中TLM uvm_put_port
 4  * *        和uvm_port_imp直接连接的基本原理。直接编译运行即可。
 5  * * 作者:http://electron64.blog.163.com
 6  */
 7 virtual class port_base#(type T=int) ; // 构造一个抽象类
 8   typedef port_base#(T) this_type;
 9   protected this_type port_handle; // 申明一个对象句柄(指针)
10 
11   pure virtual task put_t(T trans); // 纯虚函数,put_port和put_imp都必须以它为基类
12 
13   function void connect(this_type port); // connect仅仅是实现对象句柄的赋值
14     port_handle = port;
15   endfunction // connect
16 
17 endclass // port_base
18 
19 class put_port#(type T=int) extends port_base#(T);
20   virtual task put_t(T trans);
21     port_handle.put_t(trans);
22   endtask // put_t
23 endclass // put_port
24 
25 class put_imp#(type T=int, type IMP=int) extends port_base#(T);
26   local IMP m_imp;  // imp表示具体实现put_t()函数的对象句柄。
27   function new(IMP imp);
28     m_imp = imp;
29   endfunction // new
30 
31   virtual task put_t(T trans);
32     m_imp.put_t(trans);  // 调用实现对象对应的put_t()函数
33   endtask // put_t
34 
35 endclass // put_imp
36 
37 class producer;
38   put_port#(int) m_put_port;
39   function new();
40     m_put_port = new();
41   endfunction // new
42 
43   task run();
44     for(int i=0; i<10; i++) begin  // 顺序产生10个int类型的transaction.
45       m_put_port.put_t(i);
46     end
47   endtask // run
48 endclass // producer
49 
50 class consumer;
51   put_imp#(int, consumer)  m_put_export;
52   function new();
53     m_put_export = new(this); //将consumer句柄传递给put_imp中imp变量,从而实现接管put_t()最终实现
54   endfunction // new
55 
56   task put_t(int trans);
57     $display("[INFO]: Got the transaction:%d", trans);
58   endtask // put_t
59 endclass // consumer
60 
61 module top;
62   producer p;
63   consumer c;
64   initial begin
65     p = new();
66     c = new();
67     p.m_put_port.connect(c.m_put_export);  //通过句柄赋值进行连接
68     p.run();
69     #10 $finish;
70   end
71 endmodule

     总共需要5个类,其中一个是抽象类(port_base),必须保证相互连接的两个对象port/export/imp都属于同一个基类,这样句柄赋值才能够类型一致。另外,要注意的是,为了调用consumer的真正put_t()的实现,需要借用put_imp这个桥梁,put_imp对象对put_t()的实现仅仅是调用其m_imp对象的put_t()(第31-33行),用这种方式实现了函数层次的传递。

    完成整个TLM put_port/put_imp用到了面向对象设计中的继承、组合、多态的技术。其中抽象类 port_base提供了一个数据接口port_handle,和两个任务接口:put_t()和connect(). put_t()表示需要进行连接的任务名称,connect()的目的是进行对象句柄赋值。第13-15行可以看出,connect()的实现非常简单。其中用到了systemverilog中对象的特性:参考http://electron64.blog.163.com/blog/static/106033970201092785450187/

类对象通过引用传递。其他Systemverilog类型通过值传递。

因此,port_handle看作一个指针,用它来指向最终想要的目标对象,通过调用目标对象的相应方法,就可以完成方法调用的层次化传递,完成TLM的功能。

    UVM中,实现了port_base, put_port, put_imp三个类,分别对应于uvm_port_base, uvm_blocking_put_port, uvm_blocking_put_imp,他们之间的UML关系示意图如下:

image

运行结果如下:


# [INFO]: Got the transaction:          0
# [INFO]: Got the transaction:          1
# [INFO]: Got the transaction:          2
# [INFO]: Got the transaction:          3
# [INFO]: Got the transaction:          4
# [INFO]: Got the transaction:          5
# [INFO]: Got the transaction:          6
# [INFO]: Got the transaction:          7
# [INFO]: Got the transaction:          8
# [INFO]: Got the transaction:          9
# ** Note: $finish    : tlm.sv(68)
#    Time: 10 ns  Iteration: 0  Instance: /top


  评论这张
 
阅读(1856)| 评论(0)

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018