写在前文:我胡汉三又来更新csdn了。今年的秋招真的一言难尽啊。。。面了好多公司,可惜本人是个社恐,一跟面试官聊天就啥也不会了。。。到现在还是0 offer。。。哎,后面的阶段就准备去做几个fpga的项目实在不行卷fpga岗不去卷ic岗了。。。
好了,现在说一下本次更新的主要内容:
- 更新底层的driver,monitor代码,优化了一些之前的逻辑,提高代码可读性。
- 更新了refermodule,scoreboard
更新后的driver代码:
`ifndef FIFO_DRIVER__SV
`define FIFO_DRIVER__SV
`include "fifo_transaction.sv"
class fifo_driver extends uvm_driver#(fifo_transaction);
virtual fifo_if vif;
`uvm_component_utils(fifo_driver)
function new(string name = "fifo_driver",uvm_component parent = null);
super.new(name,parent);
endfunction
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
`uvm_info("fifo_driver","build_phase is called",UVM_LOW)
if(!uvm_config_db#(virtual fifo_if)::get(this,"","vif",vif))
`uvm_fatal("fifo_driver","vif must be set")
endfunction
extern task main_phase(uvm_phase phase);
extern task drive_one_pkt(fifo_transaction);
endclass
task fifo_driver::main_phase(uvm_phase phase);
`uvm_info("fifo_driver","main_phase is called",UVM_LOW)
while(1) begin
@(posedge vif.wclk);
if(!vif.wfull && vif.wreset_b == 1) begin
seq_item_port.get_next_item(req);
drive_one_pkt(req);
//`uvm_info("fifo_driver",$sformatf("drive one data:%d at %d",vif.wdata,$time),UVM_LOW)
seq_item_port.item_done();
end
else begin
vif.wdata <= vif.wdata;
end
end
endtask
task fifo_driver::drive_one_pkt(fifo_transaction tr);
bit[31:0] data_q;
data_q = tr.data;
vif.wdata = data_q ;
endtask
`endif
更新后的monitor代码:
`ifndef FIFO_MONITOR__SV
`define FIFO_MONITOR__SV
`include "fifo_transaction.sv"
class fifo_monitor extends uvm_monitor;
`uvm_component_utils(fifo_monitor)
virtual fifo_if vif;
uvm_analysis_port#(fifo_transaction) ap;
function new(string name = "fifo_monitor",uvm_component parent = null);
super.new(name,parent);
endfunction
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
`uvm_info("fifo_monitor","build_phase is called",UVM_LOW)
if(!uvm_config_db#(virtual fifo_if)::get(this,"","vif",vif))
`uvm_fatal("fifo_monitor","vif must be set")
ap = new("ap",this);
endfunction
extern task main_phase(uvm_phase phase);
extern task collect_one_pkt(fifo_transaction);
endclass
task fifo_monitor::main_phase(uvm_phase phase);
fifo_transaction tr;
/* repeat(100) begin
tr = new("tr");
collect_one_pkt(tr);
end */
while(1) begin
@(posedge vif.wclk);
#0.001;
if(!vif.wfull && vif.wreset_b == 1) begin
tr = new("tr");
collect_one_pkt(tr);
#0.004;
ap.write(tr);
end
end
endtask
task fifo_monitor::collect_one_pkt(fifo_transaction tr);
bit[31:0] data_q;
data_q = vif.wdata ;
tr.data = data_q ;
//tr.my_print();
endtask
//---------------------------------------------------------
class fifo_monitor_out extends uvm_monitor;
`uvm_component_utils(fifo_monitor_out)
virtual fifo_if vif;
uvm_analysis_port#(fifo_transaction) ap;
function new(string name = "fifo_monitor_out",uvm_component parent = null);
super.new(name,parent);
endfunction
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
`uvm_info("fifo_monitor_out","build_phase is called",UVM_LOW)
if(!uvm_config_db#(virtual fifo_if)::get(this,"","vif",vif))
`uvm_fatal("fifo_monitor_out","vif must be set")
ap = new("ap",this);
endfunction
extern task main_phase(uvm_phase phase);
extern task collect_one_pkt(fifo_transaction);
endclass
task fifo_monitor_out::main_phase(uvm_phase phase);
fifo_transaction tr;
/* repeat(100) begin
tr = new("tr");
collect_one_pkt(tr);
end */
while(1) begin
@(posedge vif.rclk);
#0.001;
if(!vif.rempty && vif.rreset_b == 1) begin
tr = new("tr");
collect_one_pkt(tr);
ap.write(tr);
end
end
endtask
task fifo_monitor_out::collect_one_pkt(fifo_transaction tr);
bit[31:0] data_q;
data_q = vif.rdata ;
tr.data = data_q ;
//tr.print();
endtask
`endif
对于driver的更新主要是由于之前的逻辑很混乱,有很多的逻辑判断是重复无效的。这次变得简洁一点。
对于monitor的更新是之前直接输出vif.rdata,现在采用接受fifo_transaction的方式来收集数据。
fifo_refermodule
`ifndef FIFO_REFERMODULE__SV
`define FIFO_REFERMODULE__SV
`include "uvm_macros.svh"
import uvm_pkg::*;
`include "fifo_transaction.sv"
class fifo_refermodule extends uvm_component;
`uvm_component_utils(fifo_refermodule)
uvm_blocking_get_port#(fifo_transaction) port;
uvm_analysis_port#(fifo_transaction) ap ;
function new(string name = "fifo_refermodule",uvm_component parent = null);
super.new(name,parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
port = new("port",this);
ap = new("ap",this);
endfunction
virtual task main_phase(uvm_phase phase);
fifo_transaction tr ;
fifo_transaction tr_out ;
super.main_phase(phase);
while(1)begin
port.get(tr);
tr_out = new("tr_out");
tr_out.copy(tr);
//tr_out.mdl_print();
#0.001;
ap.write(tr_out);
end
endtask
endclass
`endif
refermodule的代码逻辑比较简单,从输入agent中,接收到一个data,然后复制到一个新的tr中,直接发送给scoreboard当作期望值
fifo_scoreboard
`ifndef FIFO_SCOREBOARD__SV
`define FIFO_SCOREBOARD__SV
`include "uvm_macros.svh"
import uvm_pkg::*;
`include "fifo_transaction.sv"
class fifo_scoreboard extends uvm_scoreboard;
`uvm_component_utils(fifo_scoreboard)
uvm_blocking_get_port#(fifo_transaction) exp_port;
uvm_blocking_get_port#(fifo_transaction) act_port;
fifo_transaction expect_quene[$];
function new(string name = "fifo_scoreboard",uvm_component parent = null);
super.new(name,parent);
endfunction
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
exp_port = new("exp_port",this);
act_port = new("act_port",this);
endfunction
virtual task main_phase(uvm_phase phase);
fifo_transaction get_expect,get_actual,tmp_exp;
bit result;
super.main_phase(phase);
fork
while(1) begin
exp_port.get(get_expect);
expect_quene.push_back(get_expect);
end
while(1) begin
//exp_port.get(get_expect);
//expect_quene.push_back(get_expect);
act_port.get(get_actual);
//`uvm_info("fifo_scoreboard",$sformatf("get actual is %d at %d",get_actual.data,$time),UVM_LOW)
if(expect_quene.size() && get_actual.data > 0) begin
tmp_exp = expect_quene.pop_front();
result = get_actual.compare(tmp_exp);
if(result)
`uvm_info("fifo_scoreboard","compare successful!",UVM_LOW)
else begin
`uvm_info("fifo_scoreboard","compare falled!",UVM_LOW)
$display("the expect data is:");
tmp_exp.my_print();
$display("the actual data is:");
get_actual.my_print();
end
end // expect_quene.size > 0
else begin
`uvm_error("fifo_scoreboard","expect_quene is empty!")
$display("the actual data is:");
//tmp_act.my_print();
end
end
join
endtask
endclass
`endif
scoreboard的作用是接收refermodule的数据作为期望值,接收输出agent的值作为实际值,进行比较,为1则输出successful,否则输出fall。这里有一个注意的点是我的dut在reset之后,rdata有一个初始的值0,所以我加入了一个判断条件get_actual.data > 0 ,但这样的问题是假如后续传输值有0 会产生判断错误。这个bug还没修。。。
逻辑比较简单,这里面主要用到的知识还是tlm通信的内容。
我才用了这几个类型的port:
analysis port
blocking get port
tlm_fifo port
我个人是把tlm_fifo当作一个万能转接头。如果你用analys或者bg port 需要写一个write函数。用tlm_fifo口的话代码看着也整洁,还省事。
analysis主要是作为一个广播口,不需要考虑阻塞非阻塞,也没有put get操作,只有一个write函数。用起来很方便。
当然直接用put get 端口也能连,我测试过是可以用的,效果也不错。根据个人爱好以及实际使用需求来更改即可。
然后别的东西也有一些小的改动就不全部放了,有需要的可以去我的gitee上自取。
最后的最后,后续看情况会更新一个covergroup吧~
祝各位秋招顺利~