In reply to ben@SystemVerilog.us:
First of all, again, thank you for guiding me through this entire FIFO process. It is much appreciated because you are helping me more than expected so I am really grateful, just want you to know that.
Just want to update you about the fact that my supervisor told me that an asynchronous FIFO might be more complicated than expected so he decided to a first cut of the TB by imagining that is SYNCHRONOUS. So basically the two clocks are equal right now or at least that's how I am proceeding.
The code is still same I guess, one transaction provided to the generator which randomize the entire transaction feeding two drivers, one for each side.
1. I agree with you about having the clocks passed as arguments to the interface, that's basically what I planned to do at the beginning but unfortunately my supervisor made a Verification plan where, as I told you before, I have like 5 interfaces: Write_if, Read_if, Clock_if, OutputFlag_if and Internal_if (this last one should provide the WR_pointer and the RD_pointer to the DUT monitor)
2. I followed your advice and I have added an IDLE condition where I put winc=0 and rinc=0 when the variable situation (cases) happens to be equal to IDLE
3. In the write_driver class I am declaring the same mailbox basically (you made me notice the names were not matching) to get the transaction coming from the full_generator; like in the full_generator class I am putting the transaction, while in the write_driver class I am collecting it to pass the signals to the interfaces. (there should be a get operation). The call for the full_generator.main I thought it was not needed but maybe I can create a task that goes:
task drive ();
forever begin
main();
end
endtask
4. Since my supervisor told me to use two stimulus monitor to feed the Reference Model (I believe they are the ones that drives the winc, wdata and rinc to the reference Model) and one Results_monitor (it should be the DUT Monitor that provides the output to the Scoreboard), this is the code I came up with:
//Write_stimulus monitor that provides the inputs from the write_side (winc and wdata)
class write_stimulus_monitor;
mailbox wmon2mod;
//mailbox wmon2scb;
full_transaction trans_mod;
//write_transaction trans_scb;
virtual interface write_if w_vif;
virtual interface clk_if c_vif;
function new (mailbox wmon2mod, virtual interface clk_if c_vif, virtual interface write_if w_vif);
this.wmon2mod = wmon2mod;
//this.wmon2scb = wmon2scb;
this.w_vif = w_vif;
this.c_vif = c_vif;
endfunction
task main ();
forever begin
@(posedge c_vif.wclk);
trans_mod = new ();
//trans_scb = new ();
$display("By using mailboxes, the signals coming from the interfaces need to go to the monitors");
trans_mod.winc <= w_vif.winc;
trans_mod.wdata <= w_vif.wdata;
//$display("\t winc = %b, \twdata = %b", trans_mod.winc, trans_mod.wdata);
//trans_scb.wfull <=w_vif.wfull;
//$display("\t wfull = %b", trans_scb.wfull);
wmon2mod.put(trans_mod);
//wmon2scb.put(trans_scb);
end
endtask
endclass
//Stimulus monitor for the Read_side that provides the input to the Reference Model
class read_stimulus_monitor;
mailbox rmon2mod;
//mailbox rmon2scb;
virtual interface read_if r_vif;
virtual interface clk_if c_vif;
full_transaction trans_mod;
//read_transaction trans_scb;
function new (mailbox rmon2mod, virtual interface clk_if c_vif, virtual interface read_if r_vif);
this.rmon2mod = rmon2mod;
//this.rmon2scb = rmon2scb;
this.r_vif = r_vif;
this.c_vif = c_vif;
endfunction
task main();
forever begin
@(posedge c_vif.rclk);
trans_mod = new();
//trans_scb = new();
$display("let's pass the input signal from the interface to the monitor");
trans_mod.rinc = r_vif.rinc;
$display("\t rinc = %b", trans_mod.rinc);
//$display("Let's pass the outputs to the Scoreboard");
//trans_scb.rdata = r_vif.rdata;
//trans_scb.rempty = r_vif.rempty;
//$display("\t rdata = %b, rempty =%b", trans_scb.rdata, trans_scb.rempty);
rmon2mod.put(trans_mod);
//rmon2scb.put(trans_scb);
end
endtask
endclass
//Results monitor that get the outputs (flags and rdata) from the DUT through all the interfaces
class results_monitor;
virtual interface clk_if c_vif;
virtual interface flag_if f_vif;
virtual interface write_if w_vif;
virtual interface read_if r_vif;
virtual interface internal_if i_vif; //not sure if I need this 'cause it contains the pointers which I am not sure if I need to use them
mailbox resmon2scb;
full_transaction trans_scb;
function new (virtual interface read_if r_vif, virtual interface write_if w_vif, virtual interface flag_if f_vif,
virtual interface internal_if i_vif, virtual interface clk_if c_vif, mailbox resmon2scb);
this.r_vif = r_vif;
this.w_vif = w_vif;
this.f_vif = f_vif;
this.i_vif = i_vif;
this.c_vif = c_vif;
this.resmon2scb = resmon2scb;
endfunction
task main();
forever begin
@(posedge c_vif.wclk);
trans_scb = new ();
$display("This task is used to pass the DUT outputs to the results monitor");
trans_scb.rempty <= f_vif.rempty;
trans_scb.wfull <= f_vif.wfull;
trans_scb.rdata <= r_vif.rdata;
resmon2scb.put(trans_scb);
end
endtask
endclass
5. for the reference Model (is it your verifier? I think so but not sure though) I am using a queue because it seems to me the obvious thing to use in SV to replicate the FIFO behaviour
and this is the code I came up with:
class model #(parameter DSIZE =8, parameter ASIZE =4);
mailbox wmon2mod; //These two mailboxes are used to pass the transaction from the Stimulus monitor to the Model
mailbox rmon2mod; //So since it's about the stimulus monitors I am providing the winc, wdata and the rinc signals
mailbox mod2scb;//These two monitors are used to pass the outputs to the Scoreboard and then to the Coverage Collector
mailbox mod2cov;
full_transaction w_trans;
full_transaction r_trans;
localparam DEPTH = 1<<ASIZE; //Declaring the Depth of the FIFO by shifting 1 of four places
bit [DSIZE-1:0] fifo_queue[$:DEPTH-1]; //If it is declared right, this is a queue of 8 bit with a maximum dimension equal to 16
//Constructor Function
function new (mailbox wmon2mod, mailbox rmon2mod, mailbox mod2scb, mailbox mod2cov);
this.wmon2mod = wmon2mod;
this.rmon2mod = rmon2mod;
this.mod2scb = mod2scb;
this.mod2cov = mod2cov;
endfunction
task create_outputs();
wait(wmon2mod.num()!=0 && rmon2mod.num()!=0); //If the mailboxes containing the transactions that need to be passed
//to the Model are empty, I am not allowed to go ahead.
w_trans = new ();
r_trans = new ();
wmon2mod.get(w_trans);
rmon2mod.get(r_trans);
$display("Begin Model Operations");
//Write operation on the FIFO
if (w_trans.winc)begin //if the write_enable is equal to 1 begin the operation
if (fifo_queue.size == 16) begin //if the FIFO is full, raise the wfull flag
w_trans.wfull =1'b1;
end else begin
fifo_queue.push_back(w_trans.wdata); //if it's not FULL, then it is possible to write on the FIFO
end
end
if (r_trans.rinc) begin
if (fifo_queue.size == 0) begin
r_trans.rempty =1'b1;
end else begin
r_trans.rdata <= fifo_queue.pop_front();
end
end
/* if (w_trans.winc && !w_trans.wfull) begin
fifo_queue.push_back(w_trans.wdata);
end else if (r_trans.rinc) begin
r_trans.rdata =fifo_queue.pop_front();
end */
endtask
task main ();
forever begin
create_outputs();
end
endtask
endclass
I have some doubts about the Model because it's getting two transactions from two different stimulus_monitors and for this reason I am using inputs from the two transactions, (you can see how in the If I have used w_trans.winc and r_trans.rinc). But point is, I am not sure if this is okay 'cause I should probably feed then the two transactions to the Scoreboard with outputs updated as well.
I am sorry because now that I look at this, it can be really confusing, normally I would just follow a damn standard Verification Plan for the FIFO but my supervisor is really confusing me sometimes