Implementation of Queue to mimic mailbox in SV testbench

I am trying to implement a queue to replace the mailbox implementation (which is only FIFO) in a SV testbench structure. Currently I have :

  1. Environment - where I am initializing generator/driver/monitors/checkers. and the queue for holding the transactions:
class environment;

transaction gen2driv[$];   //This is to hold the transactions generated and also helps the driver pops the transaction
transaction mon2check[$];
...
.....
generator = new(gen2driv);
monitor = new(mon2check);
.....
endclass


class generator;

transaction trans;
transaction gen2driv[$];
function new(ref transaction gen2driv[$]);
this.gen2driv = gen2driv;
endfunction
...
...
trans = new();
gen2driv.push_back(trans);
...
..
endclass

class driver;

transaction trans;
transaction gen2driv[$];
function new(ref transaction gen2driv[$]);
this.gen2driv = gen2driv;
endfunction
...
...

transaction tr = gen2driv.pop_front(trans);
...
..
endclass

While executing the above code , the transaction is only pushing in. But when I display in the driver side - it complains that the size is 0.
Can someone please help in here ?

In reply to kb646bits:

You have three unconnected gen2driv queues. The generator::new just copies the queue as it exists when the constructor get called, and is probably empty. Same problem with driver::new().

What you need to do is encapsulate the queue in a class mymailbox, construct it in your environment, and pass a handle to that class into your generator and driver. And while you are at it, add put/get methods to your mymailbox.

This is exactly how you would connect up the built-in mailbox class.

In reply to dave_59:

Thanks Dave,

I have following questions to above :

  1. When you say unconnected gen2driv queues : you mean that - if in the generator, queue.push_back(transaction) is being implemented – the queue in the environment class will not be filled ?

  2. Is the queue definition correct? i.e. Here i am defining a queue of transaction class objects. So as per your suggestion :

class mymailbox;

transaction gen2driv[$];  //Is this definition correct ?

task push(transaction tr); . //Is this correct way of passing my transaction class objects
gen2driv.push_back(tr);
endtask

task transaction get();
transaction tr1 = gen2driv.pop_front();
return tr1;
endtask

endclass

Looking forward to your reply.

In reply to kb646bits:

  1. Yes.
  2. That will work mostly. However I suggest you parameterize the class just like the built-in mailbox class.
    A couple more suggestions. Use functions for methods that cannot block. Tasks can block, you the output has to be from an argument
    Your code should look like
class mymailbox #(type T);
 
   protected T Q[$]; //must use a method to access Q
 
   function void push(T tr); 
      Q.push_back(tr);
   endfunction
   
   task get(ref T tr);
      wait(Q.size()>0)
	tr = gen2driv.pop_front();
   endtask
endclass // mymailbox
class environment;
 
   mymailbox#(transaction)  gen2driv;
   transaction_driver driver;
   transaction_generator generator;
...
...
    
     gen2driv = new();
   driver = new(gen2driv);
   generator = new(gen2driv);
.....
endclass
 
 
class transaction_generator;
 
   transaction trans;
   mymailbox#(transaction) mailbox_h;
   
   function new(mymailbox#(transaction) mbx);
      mailbox_h = mbx;
   endfunction
   ...
...
   trans = new();
   maillbox_h.push(trans);
...
..
endclass
 
class transaction_driver;
 
   transaction trans;
   mymailbox#(transaction) mailbox_h;
   
   function new(mymailbox#(transaction) mbx);
      mailbox_h = mbx;
   endfunction

...
...
 
mailbox_h.get(trans);
...
..
endclass