前言
最近在研究uvm环境的仿真结束机制,准备在现有的objection机制基础上补充看门狗操作。而看门狗操作中,scoreboard喂狗是重要的一环,因此这次先实现一下通用型顺序比对的scoreboard组件编写。
scoreboard
在之前的 【python脚本】用于生成简单握手接口与自测环境的gen_uvm_agent脚本 工程中,我针对每一个agent都生成了对应的scb,这实际是没有必要的,绝大多数的transaction都可以共用一套scb,只需要把对应的数据类型传入即可,暂且将其中的顺序比对公用scb命名为prj_scoreboard。
class prj_scoreboard #(type REQ=uvm_sequence_item) extends uvm_scoreboard;
REQ expect_q[$];
REQ actual_q[$];
uvm_blocking_get_port #(REQ) exp_port;
uvm_blocking_get_port #(REQ) act_port;
static event feed_watchdog;
extern function new(string name, uvm_component parent = null);
extern virtual function void build_phase(uvm_phase phase);
extern virtual task run_phase(uvm_phase phase);
`uvm_component_param_utils(prj_scoreboard#(REQ))
endclass: prj_scoreboard
prj_scoreboard必然是继承自uvm_scoreboard,不过要做公用的那必然要将内部比对的数据类型作为参数传入,因此使用REQ作为传参类型,内部的queue声明和port声明都以REQ作为数据类型。feed_watchdog是全局可见的event,后续所有例化的prj_scoreboard均触发这一个event就可以了,没有必要在环境中@每一个scb的比对事件,因为所有的scb比对事件均要触发喂狗,因此大家喂一个就可以了。
`uvm_component_param_utils(prj_scoreboard#(REQ))这一行卡了时间(毕竟我自学成才o(╥﹏╥)o),虽然能够确定要使用param型的注册,但是应该如何注册呢,我先后试用了
`uvm_component_utils(prj_scoreboard)
`uvm_component_param_utils(prj_scoreboard#(type REQ=uvm_sequence_item))
`uvm_component_param_utils(prj_scoreboard#(uvm_sequence_item))
然后发现要么编译不过,要么后面create时有问题。然后问了大神应该怎么写,大神一语点醒梦中人:参数型的class传了不同的参数就是完全不同的class,因此注册时要明确当前的参数,而在内部注册时,参数就是REQ,后面声明时REQ传参指向谁那么注册的类就是谁。所以这里的factory注册方式直接就是:
`uvm_component_param_utils(prj_scoreboard#(REQ))
内部的方法,new和build_phase都没有什么多说的,比对行为放在了run_phase中,因为scb是被动型的组件,不需要raise objection,一直工作就可以了。
function prj_scoreboard::new(string name, uvm_component parent = null);
super.new(name, parent);
endfunction: new
function void prj_scoreboard::build_phase(uvm_phase phase);
super.build_phase(phase);
exp_port = new("exp_port", this);
act_port = new("act_port", this);
endfunction: build_phase
task prj_scoreboard::run_phase(uvm_phase phase);
super.run_phase(phase);
fork
while(1)begin
REQ get_expect;
exp_port.get(get_expect);
expect_q.push_back(get_expect);
end
while(1)begin
REQ get_actual;
act_port.get(get_actual);
actual_q.push_back(get_actual);
end
while(1)begin
REQ get_expect;
REQ get_actual;
bit result;
if(actual_q.size() > 0)begin
get_actual = actual_q.pop_front();
-> feed_watchdog;
if(expect_q.size() > 0) begin
get_expect = expect_q.pop_front();
result = get_actual.compare(get_expect);
if(result) begin
`uvm_info("prj_scoreboard", "Compare SUCCESSFULLY", UVM_LOW);
end
else begin
`uvm_error("prj_scoreboard", "Compare FAILED");
$display("RM:");
get_expect.print();
$display("RTL:");
get_actual.print();
end
end
else begin
`uvm_error("prj_scoreboard", "Received from DUT, while Expect Queue is empty");
get_actual.print();
end
end
else begin
#1;
end
end
join_none
endtask: run_phase