Synchronous fifo uvm testbench
Definition : Fifo (synchronous )
The Synchronous FIFO has a single clock port for both data-read and data-write operations, it means it is used for synchronising across two process when two process are running on same clock. One source writes to the FIFO and the other sources reads out the FIFO where it sees the order of data in exactly the same order.
DUT BLOCK
DUT DESIGN CODE
module FIFO (
clk,
reset,
put,
get,
data_in,
empty_bar,
full_bar,
data_out
);
parameter DEPTH = 8;
parameter WIDTH = 16;
parameter POINTER_WIDTH = 3;
input clk;
input reset;
input put;
input get;
input [WIDTH-1:0] data_in;
output empty_bar;
output full_bar;
output [WIDTH-1:0] data_out;
reg [POINTER_WIDTH:0] wr_ptr;
reg [POINTER_WIDTH:0] rd_ptr;
reg empty_bar;
reg full_bar;
reg [WIDTH-1:0] data_out;
reg [WIDTH-1:0] FIFO_3 [DEPTH-1:0];
wire [POINTER_WIDTH-1:0] wr_ptr_int;
wire [POINTER_WIDTH-1:0] rd_ptr_int;
wire full;
wire empty;
wire [POINTER_WIDTH:0] wr_rd;
wire put_e;
wire get_e;
assign wr_rd = wr_ptr – rd_ptr;
assign full = (wr_rd == 4’b1000);
assign empty = (wr_rd == 4’b0000);
assign put_e = (put && full == 1’b0);
assign get_e = (get && empty == 1’b0);
assign wr_ptr_int = wr_ptr[POINTER_WIDTH-1:0];
assign rd_ptr_int = rd_ptr[POINTER_WIDTH-1:0];
always @(posedge clk)
begin
if (reset)
begin
wr_ptr <= 3’b000;
rd_ptr <= 3’b000;
end else
begin
if (put_e)
begin
FIFO_3 [wr_ptr_int] <= data_in;
wr_ptr <= wr_ptr + 3’b001;
end
if (get_e)
begin
rd_ptr <= rd_ptr + 3’b001;
end
end
end
always @(rd_ptr_int)
begin
data_out <= FIFO_3 [rd_ptr_int-3’b001];
end
always @(empty or full)
begin
empty_bar <= ~empty;
full_bar <= ~full;
end
endmodule : FIFO
/*
TESTBENCH
*/
//Sequence item(basic txn)
//Data Txn
class data_transaction extends uvm_sequence_item;
rand logic [15 : 0] data_in;
rand logic put;
rand logic get;
function new(string name = “data_transaction”);
super.new(name);
endfunction
`uvm_object_utils_begin(data_transaction)
`uvm_field_int(data_in, UVM_ALL_ON)
`uvm_field_int(put, UVM_ALL_ON)
`uvm_field_int(get, UVM_ALL_ON)
`uvm_object_utils_end
endclass
//reset txn
class rst_transaction extends uvm_sequence_item;
logic rst;
function new(string name = “rst_transaction”);
super.new(name);
endfunction
`uvm_object_utils_begin(rst_transaction)
`uvm_field_int(rst, UVM_ALL_ON)
`uvm_object_utils_end
endclass
//Fifo Sequences
//Scenario 1
// write FIFO from empty to full -> read FIFO from full to empty
class FIFO_test_1_sequence extends uvm_sequence #(data_transaction);
`uvm_object_utils(FIFO_test_1_sequence)
data_transaction tr;
function new(string name = “data_seq_1”);
super.new(name);
endfunction
task body();
for (int i = 0; i < 20; i++) begin
tr = data_transaction::type_id::create(“tx_data_tr”);
start_item(tr);
if (i < 10) begin
if (!tr.randomize() with {tr.put == 1’b1; tr.get == 1’b0;}) begin
`uvm_error(“Sequence”, “Randomization failure for trasaction”)
end
end
else begin
if (!tr.randomize() with {tr.put == 1’b0; tr.get == 1’b1;}) begin
`uvm_error(“Sequence”, “Randomization failure for trasaction”)
end
end
finish_item(tr);
end
endtask
endclass : FIFO_test_1_sequence
// scenario 2
// Write FIFO from empty to half-full, and then read/write at the same time
class FIFO_test_2_sequence extends uvm_sequence #(data_transaction);
`uvm_object_utils(FIFO_test_2_sequence)
data_transaction tr;
function new(string name = “data_seq_1”);
super.new(name);
endfunction
task body();
for (int i = 0; i < 40; i++) begin
tr = data_transaction::type_id::create(“rd_tr”);
start_item(tr);
if (i < 4) begin
if (!tr.randomize() with {tr.put == 1’b1; tr.get == 1’b0;}) begin
`uvm_error(“Sequence”, “Randomization failure for trasaction”)
end
end
else begin
if (!tr.randomize() with {tr.put == 1’b1; tr.get == 1’b1;}) begin
`uvm_error(“Sequence”, “Randomization failure for trasaction”)
end
end
finish_item(tr);
end
endtask
endclass
//scenario 3
//reset
class FIFO_rst_sequence extends uvm_sequence #(rst_transaction);
`uvm_object_utils(FIFO_rst_sequence)
rst_transaction tr;
function new(string name = “rst_seq”);
super.new(name);
endfunction
task body();
tr = rst_transaction::type_id::create(“rst_tx_tr”);
start_item(tr);
tr.rst = 1’b1;
finish_item(tr);
tr = rst_transaction::type_id::create(“rst_tx_tr”);
start_item(tr);
tr.rst = 1’b0;
finish_item(tr);
endtask
endclass
//sequencer
//data sequencer
class data_sequencer extends uvm_sequencer #(data_transaction);
`uvm_component_utils(data_sequencer)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
endclass : data_sequencer
//reset sequencer
class rst_sequencer extends uvm_sequencer #(rst_transaction);
`uvm_component_utils(rst_sequencer)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
endclass : rst_sequencer
//virtual sequences
class top_vseq_base extends uvm_sequence #(uvm_sequence_item);
`uvm_object_utils(top_vseq_base)
rst_sequencer rst_sqr_h;
data_sequencer data_sqr_h;
function new(string name = “top_vseq_base”);
super.new(name);
endfunction
endclass
class vseq_rst_data extends top_vseq_base;
`uvm_object_utils(vseq_rst_data)
FIFO_test_1_sequence fifo_data_seq_h;
FIFO_rst_sequence fifo_rst_seq_h;
function new(string name = “vseq_rst_data”);
super.new(name);
endfunction
task body();
fifo_data_seq_h = FIFO_test_1_sequence::type_id::create(“fifo_data_seq_h”);
fifo_rst_seq_h = FIFO_rst_sequence::type_id::create(“fifo_rst_seq_h”);
fork
fifo_rst_seq_h.start(rst_sqr_h);
fifo_data_seq_h.start(data_sqr_h);
join
endtask
endclass : vseq_rst_data
//Fifo Driver
//data driver
class data_driver extends uvm_driver #(data_transaction);
`uvm_component_utils(data_driver)
virtual dut_if driver2dut;
data_transaction tr;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
if (!uvm_config_db #(virtual dut_if)::get(this, “”, “dut_if”, driver2dut))
`uvm_info(“DATA_DRIVER”, “uvm_config_db::get failed!”, UVM_HIGH)
endfunction
task reset_check();
forever begin
@(posedge driver2dut.clock);
if (driver2dut.reset) begin
driver2dut.put = 1’b0;
driver2dut.get = 1’b0;
end
end
endtask
task send_data();
forever begin
@(posedge driver2dut.clock);
if (!driver2dut.reset) begin
seq_item_port.get_next_item(tr);
#1
driver2dut.put = tr.put;
driver2dut.get = tr.get;
driver2dut.data_in = tr.data_in;
seq_item_port.item_done();
end
end
endtask
task run_phase(uvm_phase phase);
fork
reset_check();
send_data();
join
endtask
endclass : data_driver
//reset driver
class rst_driver extends uvm_driver #(rst_transaction);
`uvm_component_utils(rst_driver)
rst_transaction tr;
virtual dut_if driver2dut;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
if (!uvm_config_db #(virtual dut_if)::get(this, “”, “dut_if”, driver2dut))
`uvm_info(“RST_DRIVER”, “uvm_config_db::get failed!”, UVM_HIGH)
endfunction
task run_phase(uvm_phase phase);
seq_item_port.get_next_item(tr);
driver2dut.reset = tr.rst;
repeat (5) @(negedge driver2dut.clock);
seq_item_port.item_done();
/*
seq_item_port.get_next_item(tr);
driver2dut.reset = tr.rst;
seq_item_port.item_done();
endtask
*/
endclass : rst_driver
//monitor
// write monitor
class my_monitor_1 extends uvm_monitor;
`uvm_component_utils(my_monitor_1)
virtual dut_if dut2monitor1;
uvm_analysis_port #(data_transaction) ap;
data_transaction tr;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
ap = new(“monitor_1_ap”, this);
if (!uvm_config_db #(virtual dut_if)::get(this, “”, “dut_if”, dut2monitor1))
$display(“monitor_1 uvm_config_db::get failed”);
endfunction
task run_phase(uvm_phase phase);
forever
begin
@(posedge dut2monitor1.clock)
tr = data_transaction::type_id::create(“tr”);
if (!dut2monitor1.reset & dut2monitor1.full_bar & dut2monitor1.put)
begin
tr.data_in = dut2monitor1.data_in;
ap.write(tr);
end
end
endtask
endclass : my_monitor_1
// read monitor
class my_monitor_2 extends uvm_monitor;
`uvm_component_utils(my_monitor_2)
virtual dut_if dut2monitor2;
uvm_analysis_port #(data_transaction) ap;
data_transaction tr;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
ap = new(“monitor_2_ap”, this);
if (!uvm_config_db #(virtual dut_if)::get(this, “”, “dut_if”, dut2monitor2))
$display(“monitor_2 uvm_config_db::get failed”);
endfunction
task run_phase(uvm_phase phase);
forever
begin
@(posedge dut2monitor2.clock)
tr = data_transaction::type_id::create(“tr”);
if (!dut2monitor2.reset & dut2monitor2.empty_bar & dut2monitor2.get)
begin
#1
tr.data_in = dut2monitor2.data_out;
ap.write(tr);
end
end
endtask
endclass : my_monitor_2
//Agent
//data agent
class my_agent_1 extends uvm_component;
`uvm_component_utils(my_agent_1)
uvm_analysis_port #(data_transaction) ap;
data_driver data_driver_h;
data_sequencer data_sequencer_h;
my_monitor_1 monitor_1_h;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
data_driver_h = data_driver::type_id::create(“data_driver_h”, this);
data_sequencer_h = data_sequencer::type_id::create(“data_sequencer_h”, this);
monitor_1_h = my_monitor_1::type_id::create(“monitor_1_h”, this);
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
data_driver_h.seq_item_port.connect(data_sequencer_h.seq_item_export);
ap = monitor_1_h.ap;
endfunction
endclass : my_agent_1
//reset agent
class my_agent_2 extends uvm_component;
`uvm_component_utils(my_agent_2)
rst_driver rst_driver_h;
rst_sequencer rst_sequencer_h;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
rst_driver_h = rst_driver::type_id::create(“rst_driver_h”, this);
rst_sequencer_h = rst_sequencer::type_id::create(“rst_sequencer_h”, this);
endfunction
function void connect_phase(uvm_phase phase);
rst_driver_h.seq_item_port.connect(rst_sequencer_h.seq_item_export);
endfunction
endclass : my_agent_2
//read (reference data)
class my_agent_3 extends uvm_component;
`uvm_component_utils(my_agent_3)
uvm_analysis_port #(data_transaction) ap;
my_monitor_2 monitor_2_h;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
monitor_2_h = my_monitor_2::type_id::create(“monitor_2_h”, this);
endfunction
function void connect_phase(uvm_phase phase);
ap = monitor_2_h.ap;
endfunction
endclass : my_agent_3
//fifo environment
class my_environment extends uvm_env;
`uvm_component_utils(my_environment);
my_agent_1 agent_1_h;
my_agent_2 agent_2_h;
my_agent_3 agent_3_h;
my_scoreboard scoreboard_h;
uvm_tlm_analysis_fifo #(data_transaction) agt_1_scb_fifo;
uvm_tlm_analysis_fifo #(data_transaction) agt_2_scb_fifo;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
agent_1_h = my_agent_1::type_id::create(“agent_1_h”, this);
agent_2_h = my_agent_2::type_id::create(“agent_2_h”, this);
agent_3_h = my_agent_3::type_id::create(“agent_3_h”, this);
scoreboard_h = my_scoreboard::type_id::create(“scoreboard_h”, this);
agt_1_scb_fifo = new(“agt_1_scb_fifo”, this);
agt_2_scb_fifo = new(“agt_2_scb_fifo”, this);
endfunction
function void connect_phase(uvm_phase phase);
agent_1_h.ap.connect(agt_1_scb_fifo.analysis_export);
agent_3_h.ap.connect(agt_2_scb_fifo.analysis_export);
scoreboard_h.exp_port.connect(agt_1_scb_fifo.blocking_get_export);
scoreboard_h.act_port.connect(agt_2_scb_fifo.blocking_get_export);
endfunction
endclass : my_environment
//fifo checker
class my_scoreboard extends uvm_scoreboard;
`uvm_component_utils(my_scoreboard);
uvm_blocking_get_port #(data_transaction) exp_port;
uvm_blocking_get_port #(data_transaction) act_port;
data_transaction tr_act, tr_exp;
bit result;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
exp_port = new(“exp_port”, this);
act_port = new(“act_port”, this);
endfunction
task run_phase(uvm_phase phase);
forever
begin
exp_port.get(tr_exp);
act_port.get(tr_act);
result = tr_exp.compare(tr_act);
if (result)
$display(“Compare SUCCESSFULLY”);
else
`uvm_warning(“WARNING”, “Compare FAILED”)
$display(“The expected data is”);
tr_exp.print();
$display(“The actual data is”);
tr_act.print();
end
endtask
endclass : my_scoreboard
//fifo top
module top;
dut_if inf();
FIFO dut (
.clk(inf.clock),
.reset(inf.reset),
.put(inf.put),
.get(inf.get),
.full_bar(inf.full_bar),
.empty_bar(inf.empty_bar),
.data_in(inf.data_in),
.data_out(inf.data_out)
);
initial
begin
uvm_config_db #(virtual dut_if)::set(null, “uvm_test_top.env_h.agent_1_h.data_driver_h”, “dut_if”, inf);
uvm_config_db #(virtual dut_if)::set(null, “uvm_test_top.env_h.agent_2_h.rst_driver_h”, “dut_if”, inf);
uvm_config_db #(virtual dut_if)::set(null, “uvm_test_top.env_h.agent_1_h.monitor_1_h”, “dut_if”, inf);
uvm_config_db #(virtual dut_if)::set(null, “uvm_test_top.env_h.agent_3_h.monitor_2_h”, “dut_if”, inf);
run_test(“test_1”);
end
always
#5 inf.clock = !inf.clock;
initial
begin
inf.clock = 1’b1;
inf.reset = 1’b1;
repeat (3) @(posedge inf.clock);
#5
inf.reset = 1’b0;
end
endmodule : top
// fifo test
class top_test_base extends uvm_test;
`uvm_component_utils(top_test_base)
my_environment env_h;
function new(string name = “top_test_base”, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
env_h = my_environment::type_id::create(“env_h”, this);
endfunction
task init_vseq(top_vseq_base vseq);
vseq.data_sqr_h = env_h.agent_1_h.data_sequencer_h;
vseq.rst_sqr_h = env_h.agent_2_h.rst_sequencer_h;
endtask
endclass : top_test_base
class test_1 extends top_test_base;
`uvm_component_utils(test_1)
vseq_rst_data vseq_h;
function new(string name = “test_1”, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
vseq_h = vseq_rst_data::type_id::create(“vseq_h”);
endfunction
task run_phase(uvm_phase phase);
phase.raise_objection(this);
init_vseq(vseq_h);
vseq_h.start(null);
phase.drop_objection(this);
endtask
endclass : test_1