In reply to ben@SystemVerilog.us:
Thank you for the FIFO model you provided me, it is really clear and, despite not knowing that much of assertions because my supervisor told me to not use them, I believe I understood what the entire code is doing.
I was trying to create each components when my supervisor told me that things got way complicated than he expected so he basically provided me a verification plan which is this one:
!(file:///C:/Users/Trematerra/Downloads/889_786_1.png)
don’t know if you will be able to see it, but basically the Verification plan consists of: one Generator with one Transaction, two drivers (one for each side, write and read), at least 4/5 interfaces (one for write, one for read, one for the clock signals, one for the output flags and one for the internal signals such as pointers), two stimulus Monitor (always one for each side, write and read), one DUT Monitor shared by the two sides, a reference MODEL and a Scoreboard. Kinda tricky as TB architecture.
Anyway, until now I have came up with this code:
Transaction code:
class full_transaction;
typedef enum {RD, WR, RD_WR} situation;
rand situation cases;
rand bit rinc;
rand bit winc;
rand bit [7:0] wdata;
bit wfull;
bit rempty;
bit [7:0] rdata;
constraint read_only {cases == RD -> rinc==1; winc==0;}
constraint write_only {cases == WR -> rinc==0; winc==1;}
constraint both_operation {cases == RD_WR -> rinc==1; winc==1;}
//constraint write_full {}
function void print_all();
$display("rinc=");
endfunction
endclass
Generator code:
class full_generator;
//typedef enum {RD, WR, RD_WR, RD_EMPTY, WR_FULL} situation;
int num_transactions = 200;
full_transaction trans;
mailbox gen2wdriv;
mailbox gen2rdriv;
event gen_done;
//situation cases;
function new (mailbox gen2wdriv, event gen_done, mailbox gen2rdriv);
this.gen2wdriv = gen2wdriv;
this.gen2rdriv = gen2rdriv;
this.gen_done = gen_done;
endfunction
task main();
repeat (num_transactions) begin
trans = new();
if (!trans.randomize()) begin
$fatal(0,"Gen:: write_trans randomization failed.");
end
gen2wdriv.put(trans);
gen2rdriv.put(trans);
end
-> gen_done;
endtask
//if (!randomize.(cases) with {cases dist {RD:=2, WR:=2, RD_WR:=1, RD_EMPTY:=1, WR_FULL:=1};}) begin
//$fatal(0,"Gen:: write_trans randomization failed.");
endclass
Interfaces code:
interface write_if();
logic winc;
logic [7:0] wdata;
endinterface
interface read_if();
logic rinc;
logic [7:0] rdata;
endinterface
interface clk_if (input wclk, input rclk);
logic wrst_n;
logic rrst_n;
endinterface
interface flag_if();
logic wfull;
logic rempty;
endinterface
Driver, going to post only the write side:
class write_driver;
mailbox wgen2wdriv;
full_transaction trans;
virtual interface write_if w_vif;
virtual interface clk_if c_vif;
//constructor function
function new (virtual interface write_if w_vif, mailbox wgen2wdriv, virtual interface clk_if c_vif);
this.w_vif = w_vif;
this.wgen2wdriv = wgen2wdriv;
this.c_vif = c_vif;
endfunction
/*
task reset();
$display("Reset every interface signal");
wait (!c_vif.wrst_n);
w_vif.winc <=1'b0;
w_vif.wdata <=8'b0;
@(posedge c_vif.wclk);
wait (c_vif.wrst_n);
$display("Reset phase is over");
endtask */
//task to drive the signals from the driver to the interface
task drive();
$display("This task is used to drive the signals from the transaction to the involved interface");
@(posedge c_vif.wclk);
wait(wgen2wdriv.num()!=0);
trans = new();
wgen2wdriv.get(trans);
w_vif.wdata <= trans.wdata;
w_vif.winc <= trans.winc;
/* if (trans.winc && !w_vif.wfull) begin
$display ("The generator randomized winc equal to 1 so a new write operation can be passed");
w_vif.winc <= trans.winc;
w_vif.wdata<= trans.wdata;
end else begin
$display("Winc is equal to 0 so a write operation cannot be executed");
w_vif.winc<=1'b0;
end */
endtask
task write_full();
$display("This task is created to check what happens when the FIFO is FULL and the write enable is 1");
repeat(16) begin
@(posedge c_vif.wclk);
w_vif.winc<=1'b1;
w_vif.wdata <=$urandom(1);
end
endtask
task main();
while(!c_vif.wrst_n) begin
w_vif.winc <=1'b0;
w_vif.wdata<='0;
@(posedge c_vif.wclk);
end
forever begin
fork
begin
$display("Thread for the drive function");
drive();
end
begin
$display("Thread to check what happens when the FIFO is full");
write_full();
end
join_none
end
endtask
endclass
The idea was to generate a random transaction with some constraints to cover 3 different situations: RD, WR and RD/WR at the same time by using that typedef, while for the Write_FULL and the Read_EMPTY scenarios, since I know the depth of the FIFO, I have implemented the task Write_full which repeats itself 16 times so I know it will happen. Then in the task main I did fork/join_none with those two tasks. Hope it makes sense my plan…still thank you for your help