The full code of my comparator looks like -
class mbu_in_order_comparator
#( type T = int,
type comp_type = uvm_built_in_comp #(T),
type convert = uvm_built_in_converter #(T),
type pair_type = uvm_built_in_pair #(T))
extends uvm_component;
typedef mbu_in_order_comparator #(T, comp_type, convert, pair_type) this_type;
`uvm_component_param_utils(this_type)
const static string type_name = "mbu_in_order_comparator #(T, comp_type, convert, pair_type)";
uvm_analysis_export #(T) before_export;
uvm_analysis_export #(T) after_export;
uvm_analysis_port #(pair_type) pair_ap;
// TLM Analysis FIFO's
uvm_tlm_analysis_fifo #(T) m_before_fifo;
uvm_tlm_analysis_fifo #(T) m_after_fifo;
int m_matches;
int m_mismatches;
function new(string name, uvm_component parent);
super.new(name, parent);
before_export = new("before_export", this);
after_export = new("after_export", this);
pair_ap = new("pair_ap", this);
m_before_fifo = new("before", this);
m_after_fifo = new("after", this);
m_matches = 0;
m_mismatches = 0;
endfunction
virtual function string get_type_name();
return type_name;
endfunction
virtual function void connect_phase(uvm_phase phase);
before_export.connect(m_before_fifo.analysis_export);
after_export.connect(m_after_fifo.analysis_export);
endfunction
virtual task run_phase(uvm_phase phase);
pair_type pair;
T b;
T a;
string s;
super.run_phase(phase);
forever begin
if ((!m_before_fifo.is_empty()) && (!m_after_fifo.is_empty())) begin
m_before_fifo.get(b);
m_after_fifo.get(a);
if (!comp_type::comp(b, a)) begin
$sformat(s, "%s differs from %s", convert::convert2string(a), convert::convert2string(b));
`uvm_error("Comparator Mismatch",$psprintf("Mismatching transaction - %s", s))
m_mismatches++;
end
else begin
s = convert::convert2string(b);
uvm_report_info("Comparator Match", s);
m_matches++;
end
// we make the assumption here that a transaction "sent for
// analysis" is safe from being edited by another process.
// Hence, it is safe not to clone a and b.
pair = new("after/before");
pair.first = a;
pair.second = b;
pair_ap.write(pair);
end
else begin
//#1;
wait ((m_before_fifo.size() != 0) && (m_after_fifo.size() != 0)) ;
end
end
endtask
// Function: flush
//
// This method sets m_matches and m_mismatches back to zero. The
// <uvm_tlm_fifo#(T)::flush> takes care of flushing the FIFOs.
virtual function void flush();
string s;
m_matches = 0;
m_mismatches = 0;
m_before_fifo.flush();
m_after_fifo.flush();
$sformat(s, "Size of\nm_before_fifo = %d\n m_after_fifo = %d", m_before_fifo.used(), m_after_fifo.used());
`uvm_info(get_type_name(), $psprintf("%s",s), UVM_NONE)
endfunction
function void report_phase(uvm_phase phase);
if ((m_before_fifo.size() != 0) && (m_after_fifo.size() != 0)) begin
`uvm_error(this.get_name(), $psprintf("[ERROR] BOTH Comparator FIFO's not empty at the end of test"))
end
else if ((m_before_fifo.size() != 0) && (m_after_fifo.size() == 0)) begin
`uvm_error(this.get_name(), $psprintf("[ERROR] m_before_fifo Comparator FIFO not empty at the end of test"))
end
else if ((m_before_fifo.size() == 0) && (m_after_fifo.size() != 0)) begin
`uvm_error(this.get_name(), $psprintf("[ERROR] m_after_fifo Comparator FIFO not empty at the end of test"))
end
`uvm_info(get_type_name(), $psprintf("MATCHES = %d MISMATCHES= %d",m_matches,m_mismatches), UVM_NONE)
endfunction : report_phase
endclass