function new(string name = "fifo_transaction");
super.new(name);
endfunction
constraint valid_ops {
wr_en != rd_en;
}
endclass
// FIFO Sequence
class fifo_sequence extends uvm_sequence #(fifo_transaction);
`uvm_object_utils(fifo_sequence)
rand int num_transactions = 20;
fifo_transaction transactions[$];
function new(string name = "fifo_sequence");
super.new(name);
endfunction
task body();
// First fill the FIFO
for (int i = 0; i < 16; i++) begin
fifo_transaction tx;
`uvm_create(tx)
tx.wr_en = 1;
tx.rd_en = 0;
assert(tx.randomize());
transactions.push_back(tx);
`uvm_send(tx)
end
// Wait for FIFO to be full
#100;
// Then empty the FIFO
for (int i = 0; i < 16; i++) begin
fifo_transaction tx;
`uvm_create(tx)
tx.wr_en = 0;
tx.rd_en = 1;
tx.data = 0; // Data doesn't matter for reads
transactions.push_back(tx);
`uvm_send(tx)
end
endtask
endclass
// FIFO Driver
class fifo_driver extends uvm_driver #(fifo_transaction);
`uvm_component_utils(fifo_driver)
virtual fifo_if vif;
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 fifo_if)::get(this, "", "vif", vif)) begin
`uvm_fatal("NOVIF", "Virtual interface not set for driver")
end
endfunction
task run_phase(uvm_phase phase);
forever begin
fifo_transaction tx;
seq_item_port.get_next_item(tx);
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("ap", this);
if (!uvm_config_db#(virtual fifo_if)::get(this, "", "vif", vif)) begin
`uvm_fatal("NOVIF", "Virtual interface not set for monitor")
end
endfunction
task run_phase(uvm_phase phase);
forever begin
fifo_transaction tx = fifo_transaction::type_id::create("tx");
@(posedge vif.clk);
if (vif.wr_en && !vif.full) begin
tx.wr_en = 1;
tx.rd_en = 0;
tx.data = vif.data_in;
ap.write(tx);
end
if (vif.rd_en && !vif.empty) begin
tx = fifo_transaction::type_id::create("tx");
tx.wr_en = 0;
tx.rd_en = 1;
tx.data = vif.data_out;
ap.write(tx);
end
end
endtask
endclass
// FIFO Scoreboard
class fifo_scoreboard extends uvm_scoreboard;
`uvm_component_utils(fifo_scoreboard)
int write_count = 0;
int read_count = 0;
int match_count = 0;
int mismatch_count = 0;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
item_export = new("item_export", this);
endfunction
function void write(fifo_transaction tx);
if (tx.wr_en) begin
write_q.push_back(tx);
write_count++;
end
else if (tx.rd_en) begin
read_q.push_back(tx);
read_count++;
end
endfunction
function void report_phase(uvm_phase phase);
super.report_phase(phase);
// Compare write and read transactions
while (write_q.size() > 0 && read_q.size() > 0) begin
fifo_transaction write_tx = write_q.pop_front();
fifo_transaction read_tx = read_q.pop_front();
if (write_tx.data !== read_tx.data) begin
`uvm_error("SCOREBOARD", $sformatf("Data mismatch! Expected: 0x%0h, Actual: 0x%0h",
write_tx.data, read_tx.data))
mismatch_count++;
end
else begin
match_count++;
end
end
// Check for transaction count mismatch
if (write_count != read_count) begin
`uvm_error("SCOREBOARD", $sformatf("Transaction count mismatch! Writes: %0d, Reads: %0d",
write_count, read_count))
end
if (get_is_active() == UVM_ACTIVE) begin
driver = fifo_driver::type_id::create("driver", this);
sequencer = uvm_sequencer#(fifo_transaction)::type_id::create("sequencer", this);
end
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
if (get_is_active() == UVM_ACTIVE) begin
driver.seq_item_port.connect(sequencer.seq_item_export);
end
if (!uvm_config_db#(virtual fifo_if)::get(this, "", "vif", driver.vif)) begin
`uvm_fatal("NOVIF", "Virtual interface not set for driver")
end
if (!uvm_config_db#(virtual fifo_if)::get(this, "", "vif", monitor.vif)) begin
`uvm_fatal("NOVIF", "Virtual interface not set for monitor")
end
endfunction
endclass
// FIFO Environment
class fifo_env extends uvm_env;
`uvm_component_utils(fifo_env)
fifo_agent agent;
fifo_scoreboard scoreboard;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
// Clock generation
initial begin
clk = 0;
forever #5 clk = ~clk;
end
// Reset generation
initial begin
fif_if.rst_n = 0;
#20 fif_if.rst_n = 1;
end
// UVM test setup
initial begin
uvm_config_db#(virtual fifo_if)::set(null, "uvm_test_top.env*", "vif", fif_if);
run_test("basic_test");
end
// Final check
final begin
if (uvm_report_server::get_server().get_severity_count(UVM_FATAL) > 0) begin
$display("Simulation finished with UVM_FATAL errors");
$finish(2);
end
else if (uvm_report_server::get_server().get_severity_count(UVM_ERROR) > 0) begin
$display("Simulation finished with UVM_ERROR errors");
$finish(1);
end
else begin
$display("Test passed successfully");
$finish(0);
end
end
endmodule