| |
Scoreboards
Overview
记分板的工作是确定DUT是否正常运行。 记分板通常是要编写的测试平台中最困难的部分,但它可以概括为两部分:第一步是确定正确的功能究竟是什么。 一旦预测到正确的功能,记分板就可以评估在DUT上观察到的实际结果是否与预测结果相匹配。 最佳记分板架构是将预测task与评估task分开。 通过允许替换预测器和评估模型,并遵循关注点分离的最佳实践,这为您提供了最大的重用灵活性。
【此处需插一幅图】
在存在单个预测事务流和单个实际事务流的情况下,记分板可以使用简单的比较器执行评估。 最常见的比较器是有序和无序比较器。
Comparing Transactions Assuming In-Order Arrival
【此处需插一幅图】
有序比较器假定匹配的事务将以预期和实际流的相同顺序出现。 它从预期和实际方面获取事务并对其进行评估。 事务将独立到达,因此评估必须是阻塞的,直到两个事务都到达存在。 在这种情况下,一个简单的实现方法是在比较器中嵌入两个analysis FIFO,并在run()task中执行同步和评估。 评估可以像调用事务的compare()方法一样简单,也可以更复杂,因为为了评估正确的行为,比较并不一定意味着相等。
class comparator_inorder extends uvm_component;
`uvm_component_utils(comparator_inorder)
uvm_analysis_export #(alu_txn) before_export;
uvm_analysis_export #(alu_txn) after_export;
uvm_tlm_analysis_fifo #(alu_txn) before_fifo, after_fifo;
int m_matches, m_mismatches;
function new( string name , uvm_component parent) ;
super.new( name , parent );
m_matches = 0;
m_mismatches = 0;
endfunction
function void build_phase( uvm_phase phase );
before_fifo = new("before_fifo", this);
after_fifo = new("after_fifo", this);
before_export = new("before_export", this);
after_export = new("after_export", this);
endfunction
function void connect_phase( uvm_phase phase );
before_export.connect(before_fifo.analysis_export);
after_export.connect(after_fifo.analysis_export);
endfunction
task run_phase( uvm_phase phase );
string s;
alu_txn before_txn, after_txn;
forever begin
before_fifo.get(before_txn);
after_fifo.get(after_txn);
if (!before_txn.compare(after_txn)) begin
$sformat(s, "%s does not match %s", before_txn.convert2string(), after_txn.convert2string());
uvm_report_error("Comparator Mismatch",s);
m_mismatches++;
end else begin
m_matches++;
end
end
endtask
function void report_phase( uvm_phase phase );
uvm_report_info("Inorder Comparator", $sformatf("Matches: %0d", m_matches));
uvm_report_info("Inorder Comparator", $sformatf("Mismatches: %0d", m_mismatches));
endfunction
endclass
Comparing transactions out-of-order
【此处需插一幅图】
无序比较器不假设匹配事务将以预期和实际方面的相同顺序出现。 因此,需要存储不匹配的事务,直到匹配的事务出现在另一个的事务流上。对于大多数无序比较器,使用关联数组进行存储。该示例比较器具有通过analysis exports到达的两个输入流。比较器的实现是对称的,因此export名称没有任何实际重要性。此示例使用嵌入式fifos来实现analysis write()函数,但由于事务要么存储到关联数组中,要么在到达时进行评估,这个示例可以使用analysis imps和writ()函数轻松编写。
由于需要确定两个事务是否匹配并且是否应该进行比较,因此该示例要求事务实现index_id()函数,该函数返回用作关联数组的键的值。如果关联数组中已存在具有此键的条目,则表示事务先前从另一个流到达,并且事务将进行比较。如果不存在key,则将此事务添加到关联数组。
此示例还有一个附加功能,即它不会假定index_id()值在给定流上始终是唯一的。在这种情况下,属于同一事务流的多个未完成事务具有相同索引值,它们存储在队列中,并且队列是关联数组的值部分。当来自其他事务流的匹配到达时,将按FIFO顺序进行比较。
class ooo_comparator
#(type T = int,
type IDX = int)
extends uvm_component;
typedef ooo_comparator #(T, IDX) this_type;
`uvm_component_param_utils(this_type)
typedef T q_of_T[$];
typedef IDX q_of_IDX[$];
uvm_analysis_export #(T) before_axp, after_axp;
protected uvm_tlm_analysis_fifo #(T) before_fifo, after_fifo;
bit before_queued = 0;
bit after_queued = 0;
protected int m_matches, m_mismatches;
protected q_of_T received_data[IDX];
protected int rcv_count[IDX];
protected process before_proc = null;
protected process after_proc = null;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase( uvm_phase phase );
before_axp = new("before_axp", this);
after_axp = new("after_axp", this);
before_fifo = new("before", this);
after_fifo = new("after", this);
endfunction
function void connect_phase( uvm_phase phase );
before_axp.connect(before_fifo.analysis_export);
after_axp.connect(after_fifo.analysis_export);
endfunction : connect
// The component forks two concurrent instantiations of this task
// Each instantiation monitors an input analysis fifo
protected task get_data(ref uvm_tlm_analysis_fifo #(T) txn_fifo, ref process proc, input bit is_before);
T txn_data, txn_existing;
IDX idx;
string rs;
q_of_T tmpq;
bit need_to_compare;
forever begin
proc = process::self();
// Get the transaction object, block if no transaction available
txn_fifo.get(txn_data);
idx = txn_data.index_id();
// Check to see if there is an existing object to compare
need_to_compare = (rcv_count.exists(idx) &&
((is_before && rcv_count[idx] > 0) ||
(!is_before && rcv_count[idx] < 0)));
if (need_to_compare) begin
// Compare objects using compare() method of transaction
tmpq = received_data[idx];
txn_existing = tmpq.pop_front();
received_data[idx] = tmpq;
if (txn_data.compare(txn_existing))
m_matches++;
else
m_mismatches++;
end
else begin
// If no compare happened, add the new entry
if (received_data.exists(idx))
tmpq = received_data[idx];
else
tmpq = {};
tmpq.push_back(txn_data);
received_data[idx] = tmpq;
end
// Update the index count
if (is_before)
if (rcv_count.exists(idx)) begin
rcv_count[idx]--;
end
else
rcv_count[idx] = -1;
else
if (rcv_count.exists(idx)) begin
rcv_count[idx]++;
end
else
rcv_count[idx] = 1;
// If index count is balanced, remove entry from the arrays
if (rcv_count[idx] == 0) begin
received_data.delete(idx);
rcv_count.delete(idx);
end
end // forever
endtask
virtual function int get_matches();
return m_matches;
endfunction : get_matches
virtual function int get_mismatches();
return m_mismatches;
endfunction : get_mismatches
virtual function int get_total_missing();
int num_missing;
foreach (rcv_count[i]) begin
num_missing += (rcv_count[i] < 0 ? -rcv_count[i] : rcv_count[i]);
end
return num_missing;
endfunction : get_total_missing
virtual function q_of_IDX get_missing_indexes();
q_of_IDX rv = rcv_count.find_index() with (item != 0);
return rv;
endfunction : get_missing_indexes;
virtual function int get_missing_index_count(IDX i);
// If count is < 0, more "before" txns were received
// If count is > 0, more "after" txns were received
if (rcv_count.exists(i))
return rcv_count[i];
else
return 0;
endfunction : get_missing_index_count;
task run_phase( uvm_phase phase );
fork
get_data(before_fifo, before_proc, 1);
get_data(after_fifo, after_proc, 0);
join
endtask : run_phase
virtual function void kill();
before_proc.kill();
after_proc.kill();
endfunction
endclass : ooo_comparator
Advanced Scenarios
在更高级的场景中,可以存在来自多个DUT接口的多个预期事务流和实际事务流。在这种情况下,简单的比较器是不够的,并且记分板的评估部分的实现更复杂并且特定于DUT。
Reporting and Recording
评估结果是布尔值,记分板应使用该值来报告和记录故障。通常,成功的评估不会单独报告,但可以记录以供后边的总结报告使用。
(在http://verificationacademy.com/uvm-ovm上在线下载源代码示例)。