How to avoid race condition between driver and monitor

Hi,
I have made a small testbench eg. of half adder using classes. But there are some race condition, I have tried events, #delays, still the problem persists.


// DUT
module half_addr(
  input  logic a,
  input  logic b,
  output logic c,
  output logic s
  );

  assign { c, s} = a + b;

endmodule

//Transaction Class
class transaction;

  rand bit a;
  rand bit b;
       bit c;
       bit s;

  function void display(string name);
    $display("********************************");
    $display("***********%s*******************", name);
    $display(" Input  a = %0b, b = %0b ", a, b);
    $display(" Output s = %0b, c = %0b ", s, c);
    $display("********************************");
  endfunction

endclass

// Generator Class

class generator;

  mailbox gen2driv;
  transaction trans;
  event ev_done;

  int no_of_txn = 3;

  function new ( mailbox gen2driv );
    this.gen2driv = gen2driv;
  endfunction


  task main;
    for(int i = 0; i <= no_of_txn; i++) begin
      trans = new();
      if(!trans.randomize)
        $fatal(" Randomize failure ");
      else begin
        gen2driv.put(trans);
        trans.display(" Generator ");
        @(ev_done);
      end
    end
  endtask

endclass

//Driver
lass driver;

  mailbox gen2driv;
  virtual intf vif;
  transaction trans;
  event ev_done;

  int no_of_txn = 3;
  function new ( virtual intf vif, mailbox gen2driv);
    this.gen2driv = gen2driv;
    this.vif      = vif;
  endfunction


  task main;
    for( int i = 0; i <= no_of_txn; i++) begin
      gen2driv.get(trans);
      drive();
    end
  endtask

  task drive;
    #5;
    vif.a = trans.a;
    vif.b = trans.b;
    trans.display(" Driver ");
    -> ev_done;
  endtask
endclass

//Monitor
class monitor;

  virtual intf vif;
  mailbox mon2sbd;
  transaction trans;

  event ev_done;

  int no_of_txn = 3;
  function new ( virtual intf vif, mailbox mon2sbd);
    this.vif = vif;
    this.mon2sbd = mon2sbd;
  endfunction

  task main();

    for( int i = 0; i <= no_of_txn; i++) begin
      @(ev_done);
      trans = new;
      trans.a = vif.a;
      trans.b = vif.b;
      trans.s = vif.s;
      trans.c = vif.c;
      mon2sbd.put(trans);
      trans.display(" Monitor ");
    end
  endtask
endclass

//Scoreboard
class scoreboard;

  mailbox mon2sbd;
  transaction trans;
  int no_of_txn = 3;

  function new( mailbox mon2sbd );
    this.mon2sbd = mon2sbd;
  endfunction

  task main();
    for ( int i = 0; i <= no_of_txn; i++) begin
      mon2sbd.get(trans);
      trans.display(" Scoreboard ");
      if((trans.a ^ trans.b == trans.s) && ( trans.a & trans.b == trans.c))
        $display("[MATCHED]");
      else
        $display("[UNMATCHED]");
    end
  endtask;

endclass

// Environment
class environment;

  mailbox gen2driv;
  mailbox mon2sbd;

  event ev_done;

  generator  gen;
  driver     driv;
  monitor    mon;
  scoreboard sbd;

  virtual intf vif;

  function new( virtual intf vif);
    gen2driv = new();
    mon2sbd  = new();

    gen      = new(gen2driv);
    driv     = new(vif, gen2driv);
    mon      = new(vif, mon2sbd);
    sbd      = new(mon2sbd);
  endfunction

  task run;
    fork
      gen.main();
     driv.main();
      mon.main();
      sbd.main();
    join
  endtask


  task main;
    gen.ev_done  = ev_done;
    driv.ev_done = ev_done;
    mon.ev_done  = ev_done;
    run();
    $finish;
  endtask

endclass

//test
module test( intf intf_tb);
  environment env;

  initial begin
    env = new(intf_tb);
    env.main();
  end
endmodule

// tb top

module tb_top();

  intf intf_tb_top();

  test i_test(
    .intf_tb (intf_tb_top)
  );


  half_addr i_half_addr (
    .a(intf_tb_top.a),
    .b(intf_tb_top.b),
    .c(intf_tb_top.c),
    .s(intf_tb_top.s)
  );
endmodule

// Interface

interface intf;
  bit a;
  bit b;
  bit c;
  bit s;

endinterface

output
*********** Generator *******************
Input a = 0, b = 1
Output s = 0, c = 0



*********** Driver *******************
Input a = 0, b = 1
Output s = 0, c = 0



*********** Generator *******************
Input a = 1, b = 0
Output s = 0, c = 0



********** Monitor *******************
Input a = 0, b = 1
Output s = 1, c = 0



*********** Scoreboard *******************
Input a = 0, b = 1
Output s = 1, c = 0


[UNMATCHED]


*********** Driver *******************
Input a = 1, b = 0
Output s = 0, c = 0



*********** Generator *******************
Input a = 0, b = 0
Output s = 0, c = 0



*********** Monitor *******************
Input a = 1, b = 0
Output s = 1, c = 0



*********** Scoreboard *******************
Input a = 1, b = 0
Output s = 1, c = 0


[MATCHED]


*********** Driver *******************
Input a = 0, b = 0
Output s = 0, c = 0



*********** Generator *******************
Input a = 1, b = 0
Output s = 0, c = 0



*********** Monitor *******************
Input a = 0, b = 0
Output s = 0, c = 0



*********** Scoreboard *******************
Input a = 0, b = 0
Output s = 0, c = 0


[UNMATCHED]


*********** Driver *******************
Input a = 1, b = 0
Output s = 0, c = 0



*********** Monitor *******************
Input a = 1, b = 0
Output s = 1, c = 0



*********** Scoreboard *******************
Input a = 1, b = 0
Output s = 1, c = 0


[MATCHED]

Please help me in debugging.

Thanks,

Mukul

In reply to mukul1996:

Hi mukul,

Hope its not too late to reply…

module half_addr(
  input  bit a,
  input  bit b,
  output bit c,
  output bit s
  );
 
  assign s = a ^ b;
  assign c = a & b;
  
 
endmodule
 
interface intf;
  bit a;
  bit b;
  bit c;
  bit s;
 
endinterface

//Transaction Class
class transaction;
 
  rand bit a;
  rand bit b;
       bit c;
       bit s;
 
  function void display(string name);
    $display("********************************");
    $display("***********%s*******************", name);
    $display(" Input  a = %0b, b = %0b ", a, b);
    $display(" Output s = %0b, c = %0b ", s, c);
    $display("********************************");
  endfunction
 
endclass
 
// Generator Class
 
class generator;
 
  mailbox gen2driv;
  transaction trans;
  event ev_done;
  semaphore s;
 
  int no_of_txn = 10;
 
  function new ( mailbox gen2driv );
    this.gen2driv = gen2driv;
  endfunction
 
 
  task main;
    for(int i = 0; i <= no_of_txn; i++) begin
      trans = new();
      
      if(!trans.randomize)
        $fatal(" Randomize failure");
      else begin
        gen2driv.put(trans);
        @(ev_done);
        s.put(1);    // I added this semaphore because there will be a race between  
        trans.display(" Generator"); // generator and monitor @(ev_done)
        s.put(1);
       // s
      end
    end
  endtask
 
endclass
 
//Driver
class driver;
 
  mailbox gen2driv;
  virtual intf vif;
  transaction trans;
  event ev_done;
 
  int no_of_txn = 10;
  function new ( virtual intf vif, mailbox gen2driv);
    this.gen2driv = gen2driv;
    this.vif      = vif;
  endfunction
 
 
  task main;
    for( int i = 0; i <= no_of_txn; i++) begin
      gen2driv.get(trans);
      drive();
    end
  endtask
 
  task drive;
    #5;
    
   
    vif.a = trans.a;
    vif.b = trans.b;
    
    -> ev_done;
    #0;                          // added this #0 delays at components before 
    trans.display(" Driver ");   // transaction prints as there will be a race condition 
                                 // driver and generation printing function
  endtask
endclass
 
//Monitor
class monitor;
 
  virtual intf vif;
  mailbox mon2sbd;
  transaction trans;
 semaphore d;
  event ev_done;
 
  int no_of_txn = 10;
  function new ( virtual intf vif, mailbox mon2sbd);
    this.vif = vif;
    this.mon2sbd = mon2sbd;
  endfunction
 
  task main();
 
    for( int i = 0; i <= no_of_txn; i++) begin
      @(ev_done);
      d.get(2);
      trans = new;  
      trans.a = vif.a;
      trans.b = vif.b;
      #1;               // I have added his delay bacause to avoid ace between driver,  
      trans.s = vif.s;   // monitor and  monitor and half adder module
      trans.c = vif.c;
      mon2sbd.put(trans);
      
      trans.display(" Monitor ");
    end
  endtask
endclass
 
//Scoreboard
class scoreboard;
 
  mailbox mon2sbd;
  transaction trans;
  int no_of_txn = 10;
 
  function new( mailbox mon2sbd );
    this.mon2sbd = mon2sbd;
  endfunction
 
  task main();
    for ( int i = 0; i <= no_of_txn; i++) begin
    
      mon2sbd.get(trans);
      
      trans.display(" Scoreboard ");    
      if((trans.a ^ trans.b == trans.s) && ((trans.a & trans.b) == (trans.c))) //kindly check
        begin                                                             // this, without
          $display("[MATCHED]");                                    //bracket its not working
        end
          
      else
        begin
        $display("[UNMATCHED]");
        end
    end
  endtask
 
endclass
 
// Environment
class environment;
 
  mailbox gen2driv;
  mailbox mon2sbd;
 
  event ev_done;
 
  generator  gen;
  driver     driv;
  monitor    mon;
  scoreboard sbd;
 	
  
 
  function new( virtual intf vif);
    gen2driv = new();
    mon2sbd  = new();
 
    gen      = new(gen2driv);
    driv     = new(vif, gen2driv);
    mon      = new(vif, mon2sbd);
    sbd      = new(mon2sbd);
  endfunction
 
  task run;
    fork
      gen.main();
     driv.main();
      mon.main();
      sbd.main();
    join
  endtask
 
 
  task main;
    gen.ev_done  = ev_done;
    driv.ev_done = ev_done;
    mon.ev_done  = ev_done;
    run();
    $finish;
  endtask
 
endclass
 
//test
module test( intf intf_tb);
  environment env;
  semaphore sema;
  
  initial begin
    env = new(intf_tb);
    sema = new(2);
    env.gen.s = sema;
  env.mon.d = sema;
    env.main();
  end
endmodule
 
// tb top
 
module tb_top();
 
  intf intf_tb_top();
 
  test i_test(
    .intf_tb (intf_tb_top)
  );
 
 
  half_addr i_half_addr (
    .a(intf_tb_top.a),
    .b(intf_tb_top.b),
    .c(intf_tb_top.c),
    .s(intf_tb_top.s)
  );
  
 
  
endmodule

From next time please give description of your code in comments so that anyone can solve your issue