the UVM monitor can play not only a functional checker but also a performance checker which means, user can use it more quickly to find out where is their design bottleneck without waveform tracing. in this topic, we focused on how to use UVM monitor to point out the collected transactions had timing violation immediately when the simulation was running.
we write a UVM SystemVerilog "req happened until grant received" to our demo case.
// spawn sub procs(threads)
task run_phase(uvm_phase);
fork
sent_req();
sent_grant();
collected_req();
collected_grant();
check_performance();
check_protocol();
join
endtask : run_phase
// sent req
task sent_req();
forever begin
// random wait ....
repeat($urandom_range(8,16)) @(posedge m_vif.CLK);
// sent req
`delay(conf.half_cycle);
m_vif.REQ <= `TRUE;
@(posedge m_vif.CLK);
// wait until grant received
while(!m_vif.GRANT) @(posedge m_vif.CLK);
// free req
`delay(conf.half_cycle);
m_vif.REQ <= `FALSE;
@(posedge m_vif.CLK);
end
endtask : sent_req
// snet grant
task sent grant();
forever begin
// sent unvalid grant
`delay(conf.half_cycle);
m_vif.GRANT <= `FALSE;
@(posedge m_vif.CLK);
// wait until req received
while(!m_vif.REQ) @(posedge m_vif.CLK);
// random wait ...
repeat($urandom_range(8,16)) @(posedge m_vif.CLK);
// sent valid grant to free req
`delay(conf.half_cycle);
m_vif.GRANT <= `TRUE;
@(posedge m_vif.CLK);
end
endtask : sent grant
task collected_req();
forever begin
// @ neg edge check
@(negedge m_vif.CLK iff m_vif.REQ);
// assert only one fifo deep when req/grant case
assert(m_trx_q.size() < 1);
// collect trx
TRX m_trx = new();
m_trx.REQ = m_vif.REQ;
m_trx.TIME = $time;
m_trx_q.push_back(m_trx);
end
endtask : collected_req
task collected_grant();
forever begin
// @ neg edge cehck
@(negedge m_vif.CLK iff m_vif.GRANT);
//assert the queue size must be 1, means the req has been stored in the queue
assert(m_trx.q.size() == 1);
// free queue
m_trx_q.pop_front();
end
endtask : collected_grant
task check_performance();
forever begin
// at each pos edge check
@(posedge m_vif.CLK);
//assert queue
if (m_trx_q.size() == 1) begin
if ($time - m_trx_q[0].TIME > conf.min_offset) begin
`uvm_error(get_full_name(), {$psprintf("out of time %d"), conf.min_offset}, UVM_LOW)
end else begin
`uvm_error(get_full_name(), {$psprintf("req/grant seuence is not valid")}, UVM_LOW)
end
end
end
endtask