Scoreboard with expected and actual data arriving at the same time

I have a scoreboard which has been working fine comparing actual data with expected data, but now the RTL has changed so that for one instance there is no clock delay between the data streams. Consequently both data are sampled at the same time. So there is a race and the comparator may fail when the expected data has not got onto the queue before the actual data arrives.
Is there a recommended method to ensure the data is pushed into a queue before it is compared?

What I did in such a situation is the following:

  1. Create a TLM FIFO for your expected stream.
  2. Push items from the expected stream into the FIFO
  3. When getting an actual, fork out a process that gets from this FIFO and compare the two items.

Some code:


class my_comp extends uvm_component;
  uvm_analysis_fifo exp_fifo;
  local int checks_pending;  

  // ...
  // analysis imps, constructor, etc.

  function void write_expected(some_item item);
    if (!exp_fifo.try_put(item))
      `uvm_fatal("FIFOERR", "I should always be able to put in the FIFO")
  endfunction

  function void write_actual(some_item item);
    fork
      check_item(item);
    join_none
  endfunction

  task check_item(some_item item);
    some_item exp_item;
    checks_pending++;
    exp_fifo.get(exp_item);
    // compare item to exp_item
    checks_pending--;
  endtask

  function void check_phase(uvm_phase phase);
    if (checks_pending)
      `uvm_error(...)

    if (!exp_fifo.is_empty())
      `uvm_error(...)
  endtask
endclass

A separate process is forked when an actual item comes that waits for the expected item to reach the queue. If it’s already there it won’t need to block. A key thing to ensure is that there are no outstanding checks at the end of the simulation.

I’m not sure if it’s optimal, but it works.

In reply to Tudor Timi:

Forking off a new thread every time you have a new received item can be dangerous. What happens if you receive two items via write_actual() and there are two parallel threads competing over the same exp_fifo?

I would use two fifos (one for received and one for actual), and have the run_phase() pull from each and do the comparison. Take a look at this article from the UVM Cookbook.

Also, look at the uvm_in_order_comparator class.

In reply to cgales:

Thanks for those suggestions. It turned out it was easier in my environment to add a new comparator with two fifos as cgales suggested.