| |
网上找了一个例子,展示OVM中Component(例如scoreboard和monitor)相互传递transaction的机制。别看这短短60多行,不好理解。
virtual class port_base#(type T=int) ; // ¹¹ÔìÒ»¸ö³éÏóÀà
typedef port_base#(T) this_type;
this_type port_handle; // ÉêÃ÷Ò»¸ö¶ÔÏó¾ä±ú£¨Ö¸Õ룩
pure virtual task put_t(T trans); // ´¿Ð麯Êý£¬put_portºÍput_imp¶¼±ØÐëÒÔËüΪ»ùÀà
function void connect(this_type port); // connect½ö½öÊÇʵÏÖ¶ÔÏó¾ä±úµÄ¸³Öµ
port_handle = port;
endfunction // connect
endclass // port_base
class put_port#(type T=int) extends port_base#(T);
virtual task put_t(T trans);
port_handle.put_t(trans);
endtask // put_t
endclass // put_port
class put_imp#(type T=int, type IMP=int) extends port_base#(T);
local IMP m_imp; // imp±íʾ¾ßÌåʵÏÖput_t()º¯ÊýµÄ¶ÔÏó¾ä±ú¡£
function new(IMP imp);
m_imp = imp;
endfunction // new
virtual task put_t(T trans);
m_imp.put_t(trans); // µ÷ÓÃʵÏÖ¶ÔÏó¶ÔÓ¦µÄput_t()º¯Êý
endtask // put_t
endclass // put_imp
class producer;
put_port#(int) m_put_port;
function new();
m_put_port = new();
endfunction // new
task run();
for(int i=0; i<10; i++) begin // ˳Ðò²úÉú10¸öintÀàÐ͵Ätransaction.
m_put_port.put_t(i);
end
endtask // run
endclass // producer
class consumer;
put_imp#(int, consumer) m_put_export;
function new();
m_put_export = new(this); //½«consumer¾ä±ú´«µÝ¸øput_impÖÐimp±äÁ¿£¬´Ó¶øʵÏÖ½Ó¹Üput_t()×îÖÕʵÏÖ
endfunction // new
task put_t(int trans);
$display("[INFO]: Got the transaction:%d", trans);
endtask // put_t
endclass // consumer
module top;
producer p;
consumer c;
initial begin
p = new();
c = new();
p.m_put_port.connect(c.m_put_export); //ͨ¹ý¾ä±ú¸³Öµ½øÐÐÁ¬½Ó
p.run();
#10 $finish;
end
endmodule
关于此例解析:
producer对象里包含了一个put_port#(int) m_put_port;
consumer里包含了一个 put_imp#(int, consumer) m_put_export;
top中 p.m_put_port.connect(c.m_put_export); 执行的是port_base的方法,实现port_handle指向父类c.m_put_export
producer里run的 m_put_port.put_t(i)会调用put_port中的put_t方法,而其内容却是:
class put_port#(type T=int) extends port_base#(T);
virtual task put_t(T trans);
port_handle.put_t(trans);
endtask // put_t
endclass // put_port
而port_handle此时又已经指向了c.m_put_export,所以会调用put_imp中的put_t(SV里面多态是这样的规则:如果函数加了virtual关键字,那么就是根据当前指针指向哪个类的方法就调用哪个类的;):
virtual task put_t(T trans);
m_imp.put_t(trans);
endtask // put_t
从而最终实现调用consumer中的put_t方法
OOP基础补充:
SV里面多态是这样的规则:如果函数加了virtual关键字,那么就是根据当前指针指向哪个类的方法就调用哪个类的;
virtual class: 虚类只用来定义类的格式, 和成员的名字, 参数, 不能被实例化, 只能被重载, 用于在项目中定义一些标准的类, 例如driver类, 这样大家extend出来的driver的基本的格式都是一样的, 易读易理解. 在virtual class里的方法最好使用 pure virtual 修饰, 叫做纯虚方法, 也是用来定义方法的名字和参数列表的, 方便大家统一名字.
个人觉得SV for verification那本书上的mailbox方法很好用,这个OVM传递transaction的方法理解起来有点坑爹。