TLM事务级建模

概述

TLM:Transaction Level Modeling(事务级建模),它是一个独立于语言的一个标准,常用于系统建模,加速软硬件协同开发。在芯片开发中,常配合system C使用来进行系统设计。最新的标准是OCSI TLM 2.0。

TLM的端口整理

端口的按照类型可以划分为三种:

port:经常作为initiator的发起端,也凭借port,initiator才可以访问target中实现的TLM通信方法;

export:作为initiator和target中间层次的端口;

imp:只能是作为target接收request的末端,它无法作为中间层次的端口,imp无法向其他端口发送conne连接;

port和export体现的是一种控制流,port是控制的发起者,export是被动接收者。

PORT、 EXPORT、 IMP三者的优先级顺序为PORT > EXPORT >  IMP, PORT的优先级最高,IMP的优先级最低。TLM通信连接只能从高优先级向低优先级发起,也就意味着port可以连接port、export或者imp;export可以连接export或者imp;imp只能作为数据传送的终点,无法扩展连接

PORT、 EXPORT、 IMP每一种下面都包含15种,主要区分为:

  1. 阻塞和非阻塞之分
  2. 哪种通信数据流传输方式,put、get、peek、transport( request-response操作)等。

put:从initiator向target发送数据

get:从initiator向target获取数据

peek:peek和get在数据流和控制流上相似,区别在于get任务被调用时, FIFO内部缓存中会少一个transaction, 而peek被调用时, FIFO会把transaction复制一份发送出去

PORT、 EXPORT、 IMP在使用上是一一对应的,如果使用了uvm_blocking_put_port#(T)作为initiator则port一定要使用uvm_blocking_put_export#(T);imp一定要使用uvm_blocking_put_imp#(T);

 

portexportimp
uvm_blocking_put_port#(T);uvm_blocking_put_export#(T);uvm_blocking_put_imp#(T);
uvm_nonblocking_put_port#(T);uvm_nonblocking_put_export#(T);uvm_nonblocking_put_imp#(T);
uvm_put_port#(T);uvm_put_export#(T);uvm_put_imp#(T);
uvm_blocking_get_port#(T);uvm_blocking_get_export#(T);uvm_blocking_get_imp#(T);
uvm_nonblocking_get_port#(T);uvm_nonblocking_get_export#(T);uvm_nonblocking_get_imp#(T);
uvm_get_port#(T);uvm_get_export#(T);uvm_get_export#(T);
uvm_blocking_peek_port#(T);uvm_blocking_peek_export#(T);uvm_blocking_peek_imp#(T);
uvm_nonblocking_peek_port#(T);uvm_nonblocking_peek_export#(T);uvm_nonblocking_peek_imp#(T);
uvm_peek_port#(T);uvm_peek_export#(T);uvm_peek_imp#(T);
uvm_blocking_get_peek_port#(T);uvm_blocking_get_peek_export#(T);uvm_blocking_get_peek_imp#(T);
uvm_nonblocking_get_peek_port#(T);uvm_nonblocking_get_peek_export#(T);uvm_nonblocking_get_peek_imp#(T);
uvm_get_peek_port#(T);uvm_get_peek_export#(T);uvm_get_peek_imp#(T);
uvm_blocking_transport_port#(REQ, RSP);uvm_blocking_transport_export#(REQ, RSP);uvm_blocking_transport_imp#(REQ, RSP);
uvm_nonblocking_transport_port#(REQ, RSP);uvm_nonblocking_transport_export#(REQ, RSP);uvm_nonblocking_transport_imp#(REQ, RSP);
uvm_transport_port#(REQ, RSP);uvm_transport_export#(REQ, RSP);uvm_transport_imp#(REQ, RSP);

 

                                                                                                     

与上述三种task对应的nonblocking非阻塞的方法分别是:

try_put//返回值默认为1或0

can_put//回调方法,在调用try_xxx()方法时自动调用

try_get

can_get

try_peek

can_peek

这六个函数与其对应的task的区别在于,它们必须立即返回,如果try_xxx函数可以发送或者获取数据,那么函数还应该返回1,如果执行失败则应该返回0。或者通过can_xxx函数先试探target是否可以接收数据,通过返回值,再通过try_xxx函数发送,提高数据发送的成功率 ;

put_export:用户可以通过该端口调用put()、try_put()、can_put()。

put_ap:调用了put方法写入的数据同时也会通过该端口的write()函数送出。

get_peek_export:用户可以通过该端口调用get()、try_get()、can_get()、peek()、try_peek()、can_peek()。

get_ap:调用了get和peek方法读出的数据也会通过该端口的write()函数送出。

analysis_port和analysis_export

除了port、export和imp三种端口,还有两种特殊端口analysis_port和analysis_export。analysis_port和analysis_export没有阻塞和非阻塞之分,在通信中他们是一对多的,相当于广播的方式,一个analysis_port或者analysis_export可以连接多个imp,imp的类型必须是uvm_analysis_imp。analysis_port和analysis_export来说, 只有一种操作: write。 在analysis_imp所在的component, 必须定义一个名字为write的函数。

如果在一个component中存在多个imp,使用时每个imp都需要有一个write函数,这种可以通过uvm_analysis_imp_decl来解决,指定write函数的后缀,这样在调用write函数时会自动调用write_后缀的函数。

 

`ifndef MY_SCOREBOARD__SV
`define MY_SCOREBOARD__SV

`uvm_analysis_imp_decl(_model0)
`uvm_analysis_imp_decl(_model1)
`uvm_analysis_imp_decl(_model2)

class my_scoreboard extends uvm_scoreboard;
   my_transaction  expect_queue[$];
   uvm_analysis_imp_monitor#(my_transaction, my_scoreboard) monitor_imp;
   uvm_analysis_imp_model0#(my_transaction, my_scoreboard) model0_imp;
   uvm_analysis_imp_model1#(my_transaction, my_scoreboard) model1_imp;
   uvm_analysis_imp_model2#(my_transaction, my_scoreboard) model2_imp;

   `uvm_component_utils(my_scoreboard)

   extern function new(string name, uvm_component parent = null);
   extern virtual function void build_phase(uvm_phase phase);
   extern virtual task main_phase(uvm_phase phase);
   extern function void write_monitor(my_transaction tr);
   extern function void write_model0(my_transaction tr);
   extern function void write_model1(my_transaction tr);
   extern function void write_model2(my_transaction tr);

endclass 

function my_scoreboard::new(string name, uvm_component parent = null);
   super.new(name, parent);
endfunction 

function void my_scoreboard::build_phase(uvm_phase phase);
   super.build_phase(phase);
   monitor_imp = new("monitor_imp", this);
   model0_imp = new("model0_imp", this);
   model1_imp = new("model1_imp", this);
   model2_imp = new("model2_imp", this);

endfunction 

function void my_scoreboard::write_model0(my_transaction tr);
   expect_queue.push_back(tr);
endfunction

function void my_scoreboard::write_model1(my_transaction tr);
   expect_queue.push_back(tr);
endfunction

function void my_scoreboard::write_model2(my_transaction tr);
   expect_queue.push_back(tr);
endfunction


function void my_scoreboard::write_monitor(my_transaction tr);
   my_transaction  tmp_tran;
   bit result;
   if(expect_queue.size() > 0) begin
      tmp_tran = expect_queue.pop_front();
      result = tr.compare(tmp_tran);
      if(result) begin 
         `uvm_info("my_scoreboard", "Compare SUCCESSFULLY", UVM_LOW);
      end
      else begin
         `uvm_error("my_scoreboard", "Compare FAILED");
         $display("the expect pkt is");
         tmp_tran.print();
         $display("the actual pkt is");
         tr.print();
      end
   end
   else begin
      `uvm_error("my_scoreboard", "Received from DUT, while Expect Queue is empty");
      $display("the unexpected pkt is");
      tr.print();
   end 

endfunction

task my_scoreboard::main_phase(uvm_phase phase);
endtask
`endif

fifo 

uvm_tlm_fifo和uvm_tlm_analysis_fifo两种,区别在于uvm_tlm_analysis_fifo存在一个analysis_export端口, 并且有一个write函数, 而uvm_tlm_fifo没有。

fifo的本质实际上是集成了两个imp完成的通信。

fifo上存在相当多的端口供给我们连接,function new(string name, uvm_component parent = null, int size = 1);可通过指定size的大小指定fifo的缓存深度,如果size=0表示无限大小。


 

posted @ 2021-04-05 14:12  验证cc  阅读(758)  评论(0编辑  收藏  举报