How do you ensure no race condition occurs?

How do you ensure no race condition occurs?

Let’s take the example below. In that example, I’m trying to count the number of clock cycles between the negedge of sent_sdin.
So the possible problem here is to have a race condition of the assignment of variable in_between_negedge.


fork
// Detect send_sdin negedge
forever begin
  @(negedge sigs.sentMon.sent_sdin);
  `uvm_info("sent_monitor", $sformatf("sent_sdin first negedge!"), UVM_MEDIUM);
  in_between_negedge = 1;
        
  @(negedge sigs.sentMon.sent_sdin);
  `uvm_info("sent_monitor", $sformatf("sent_sdin second negedge!"),UVM_MEDIUM);

  in_between_negedge = 0;
end

forever begin
  wait(in_between_negedge);

  // Race condition may happen here. When negedge of sent_sdin comes, the while-loop may
  // not be able to get a 0 value for in_between_negedge. So cnt_pulse will become 1 greater
  // than the correct value.
  while(in_between_negedge) begin
    @(posedge sigs.ecu_clk);
    ++cnt_pulse;
  end
end
join_any

Here’s the interface where sent_sdin is located. I don’t clocking block.


interface sent_if (input ecu_clk);
  logic                   rstb;
  logic                   sent_en;
  logic                   sent_sdin;
  logic                   sent_sdout_hi;
  logic                   sent_sdout_lo;
  logic                   sent_rx_enb;
  logic                   sent_tx_enb; 
endinterface

In reply to Reuben:

It would help if you could explain how sigs.sentMon.sent_sdin is defined and how it changes value.

In reply to dave_59:

Oh ok. I think I’ll just edit it. Actually those signals are form the monitor.

In reply to Reuben:

The driver drives sent_sdin after seeing the posedge of clk.

In reply to Reuben:

Actually this is just a theoretical situation. I don’t really have that code. I’m just worrying that if I implement it then it might have race condition so I’m looking for a way to avoid it.

The recommendation here is to write code that is synchronous to only one clock edge, do not use mixtures of different signal edges and wait statements. Only use

@(posedge sigs.ecu_clk); or @(posedge sigs.ecu_clk iff (signal == value));

The signals that you sample must be written with non-blocking assignments, just like RTL designers would do to avoid race conditions, or you can use clocking blocks to sample the signals. Once you start using clocking blocks, you should only use the clocking block event to synchronize your code.

In reply to dave_59:

Okay. Thanks. I think that’s a better way of coding.
I’m not using clocking blocks that’s why race conditions are so frequent.
Hmm… Seems I need to do a lot of changes in my testbench. =)