RM的输出被scoreboard接收,用于和DUT的输出作比较。
1. my_transaction的传输
1. my_model是从i_agent中获取my_transaction,并将其传递给my_scoreboard
这两个组件之间的传输通常用TLM(Transaction Level Modeling,事务级别传输)来实现tranction的通信。
1.1如何发送数据?
使用uvm_analysis_port
在my_monitor中定义如下变量:
uvm_analysis_port # (my_transaction) ap;
~ uvm_analysis_port是一个参数化的类,其参数就是analysis_port需要传递的数据的类型,在这里就是my_transaction。
~ 声明了ap后,需要在monitor的build_phase中将其例化:
virtual function void build_phase(uvm_phase phase);
ap = new("ap",this);
~ 在main_phase中,当收集完一个transaction后,需要将其写入ap中,(write是uvm_analysis_port中的一个内建函数。
task my_monitor::main_phase(uvm_phase phase);
my_transaction tr;
while(1) begin
tr=new("tr");
collect_one_pkt(tr);
ap.write(tr);
end
endtask
1.2 如何接收数据?
使用uvm_blocking_get-port
在my_monitor中定义如下变量:
uvm_blocking_get_port # (my_transaction) port;
在build_phase中将其例化,通过 task port.get来得到从i_agent的monitor中发出的transaction。
至此,完成了在my_monitor和my_model中的定义及各自端口的实现,但接下来还需要在my_env中使用fifo将两个端口联系起来。
1.3 将两个端口联系起来的fifo
在my_env中定义一个fifo,并在build_phase中将其例化:
uvm_tlm_analysis_fifo #(my_transaction) agt_mdl_fifo;
agt_mdl_fifo = new("agt_mdl_fifo",this);
fifo的类型是uvm_tlm_analysis_fifo
下一步,在connect_phase中将fifo分别与my_monitor中的analysis_port和my_model中的blocking_get_port相连:
function void my_env::connect_phase(uvm_phase phase);
super.connect_phase(phase);
i_agt.ap.connect(agt_mdl_fifo.analysis_export);
mdl.port.connect(agt_mdl_fifo.blocking_get_export);
endfunction
为什么需要fifo呢?
因为analysis_port是非阻塞性质的,ap.write函数调用完成后马上返回,不会等待数据被接收之后再返回,假如当write函数调用时,blocking_get_port正忙于其他事情,没有准备好接收新的数据,那此时被write函数写入的my_transaction就需要一个暂存的位置,就是fifo。
2. Scoreboard
2.1 如何接收数据?
my_scoreboard要比较的数据, 一是来源于reference model ,通过exp_port获取;另一是来源于o_agent的monitor,通过act_port获取。
在main_phase中通过fork建立起两个进程,一个进程处理exp_port的数据,收到数据后把数据放入expect_queue中;另外一个进程处理act_port的数据,(DUT的输出数据),当收集到这些数据后,从expect_queue中弹出之前从exp_port收到的数据,并调用my_transaction的my_compare函数。 采用这种比较方式的前提是exp_port要比act_port先收到数据。RM是基于高级语言的处理,一般不需要延时,DUT处理数据需要延时,所以一般可以保证exp_port的数据比act_port的数据先到。
3. field_automation
使用uvm_object_utils_begin和uvm_object_utils_end实现my_transaction的factory注册,在这两个宏之间,使用uvm_field宏注册所有字段。此后,就可以直接调用copy compare print等函数。
另外一大好处:简化了driver和monitor,将my_driver的drv_one_pkt任务和my_monitor的collect_one_pkt任务代码很长,调用pack_bytes将tr中的所有字段变成byte流放入data_q中。