0% found this document useful (0 votes)
47 views15 pages

Fifo Uvm

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
47 views15 pages

Fifo Uvm

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 15

VerifiCATION

WITH
FIFO Design
The FIFO (First-In, First-Out) design is a memory-based circuit that stores data in the
order it is received and outputs it in the same order. It has two pointers: one for writing
data in and one for reading data out. The FIFO uses a clock to synchronize these
operations and includes signals to indicate when it is full or empty. A reset signal can
clear the memory and reset the pointers. This design helps manage data flow smoothly,
especially when transferring data between different parts of a system.

FIFO Design Specifications

Specification Details
- data_in: 8-bit input data signal
- clock: 1-bit clock signal
Inputs - reset: 1-bit reset signal (active high)
- wn: 1-bit write enable signal
- rn: 1-bit read enable signal
- data_out: 8-bit output data signal
Outputs - full: 1-bit flag indicating FIFO is full
- empty: 1-bit flag indicating FIFO is empty
- wptr: 3-bit write pointer
Internal
- rptr: 3-bit read pointer
Signals
- memory: 8-entry array of 8-bit registers (FIFO storage)
- Reset: On a high reset signal, all entries in the FIFO memory are
cleared, wptr and rptr are reset to 0, and data_out is set to 0.
- Write Operation: When wn is high and full is low, data_in is
written into the FIFO at the position indicated by wptr. The wptr is
then incremented.
- Read Operation: When rn is high and empty is low, data from the
Behavior FIFO at the position indicated by rptr is output through data_out.
The rptr is then incremented.
- Full Condition: The FIFO is considered full when wptr[2:1] ==
rptr[2:1] and wptr[0] != rptr[0]. When full, no further write
operations are allowed.
- Empty Condition: The FIFO is considered empty when wptr ==
rptr. When empty, no further read operations are allowed.
Synchronous with the clock signal. Operations are triggered on the
Clocking
positive edge of clock.
Memory 8 entries (indexed by 3-bit pointers)
Depth
Data Width 8 bits per entry
- Buffering: Temporarily stores data to handle timing differences
between producer and consumer modules.
Use Cases
- Queue Management: Manages data flow in a first-in, first-out
manner.

Testbench Architecture
Design.V

module FIFO (
output reg [7:0] data_out,
output full, empty,
input [7:0] data_in,
input clock, reset, wn, rn
);
reg [2:0] wptr, rptr;
reg [7:0] memory [7:0];

// Initialize FIFO memory and pointers


always @(posedge clock or posedge reset) begin
if (reset) begin
// Reset memory and pointers
integer i;
for (i = 0; i < 8; i = i + 1)
memory[i] <= 0;
data_out <= 0;
wptr <= 0;
rptr <= 0;
end
else begin
// Write operation
if (wn && !full) begin
memory[wptr] <= data_in;
wptr <= wptr + 1;
end

// Read operation
if (rn && !empty) begin
data_out <= memory[rptr];
rptr <= rptr + 1;
end
end
end

// FIFO full condition


// assign full = ((wptr[2:1] == rptr[2:1]) && (wptr[0] != rptr[0]));
// assign full= (wptr==15 && !rn && wn);
assign full = ((wptr+1'b1) == rptr);
// FIFO empty condition
assign empty = (wptr == rptr);

endmodule
Interface

interface fifo_if(input logic clock,reset);


logic wn;
logic rn;
logic[7:0] data_in;
logic[7:0] data_out;
logic empty;
logic full;

clocking driver_cb@(posedge clock);


default input #1 output #1;

output wn;
output rn;
output data_in;
input full;
input empty;
input data_out;
endclocking

clocking monitor_cb@(posedge clock);


default input #1 output #1;

input wn;
input rn;
input data_in;
input full;
input empty;
input data_out;
endclocking

modport DRIVER(clocking driver_cb, input clock, reset);


modport MONITOR(clocking monitor_cb, input clock, reset);

endinterface
Sequence Item

class seq_item extends uvm_sequence_item;

rand logic [7:0] data_in;


rand bit wn;
rand bit rn;
bit empty;
bit full;
bit reset;
logic [7:0] data_out;

function new(string name="seq_item");


super.new(name);
endfunction

`uvm_object_utils_begin(seq_item)
`uvm_field_int(data_in,UVM_ALL_ON)
`uvm_field_int(wn,UVM_ALL_ON)
`uvm_field_int(rn,UVM_ALL_ON)
`uvm_field_int(full,UVM_ALL_ON)
`uvm_field_int(data_out,UVM_ALL_ON)
`uvm_object_utils_end

constraint C{rn != wn;};


constraint D{ data_in inside {[0:50]};};

function string convert2string();


return $psprintf("\n wn= %0d \n rn=%0d \n FULL= %0d \n EMPTY=%0d \n
DATA_IN= %0d", wn,rn,full,empty,data_in);
endfunction

endclass

Sequence

class base_seq extends uvm_sequence#(seq_item);


`uvm_object_utils(base_seq)

function new(string name="base_seq");


super.new(name);
endfunction

virtual task body();


`uvm_info(get_type_name(), $sformatf("******** Generate 16 Write REQs
********"), UVM_LOW)
repeat(16) begin
req = seq_item::type_id::create("req");
start_item(req);
assert(req.randomize() with {wn == 1;});
finish_item(req);
end
`uvm_info(get_type_name(), $sformatf("******** Generate 16 Read REQs
********"), UVM_LOW)
repeat(16) begin
req = seq_item::type_id::create("req");
start_item(req);
assert(req.randomize() with {rn == 1;});
finish_item(req);
end
`uvm_info(get_type_name(), $sformatf("******** Generate 20 Random REQs
********"), UVM_LOW)
repeat(20) begin
req = seq_item::type_id::create("req");
start_item(req);
assert(req.randomize());
finish_item(req);
end
endtask

endclass

Sequencer

class sequencer extends uvm_sequencer#(seq_item);


`uvm_component_utils(sequencer)

function new(string name="sequencer", uvm_component parent=null);


super.new(name, parent);
endfunction

function void build_phase(uvm_phase phase);


super.build_phase(phase);
endfunction

endclass
Driver

class driver extends uvm_driver#(seq_item);


`uvm_component_utils(driver)

// Virtual interface to connect to the FIFO


virtual fifo_if vif;

function new(string name="driver", uvm_component parent=null);


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))
`uvm_fatal(get_type_name(), "Virtual interface not set on top level");
endfunction

virtual task run_phase(uvm_phase phase);

forever begin
seq_item req;
seq_item_port.get_next_item(req);

if (req.wn == 1)
main_write(req.data_in);
else if (req.rn == 1)
main_read();

seq_item_port.item_done();
end
endtask

virtual task main_write(input [7:0] din);


@(posedge vif.clock); // Ensure you have the correct clock signal
vif.wn <= 1'b1;
vif.data_in <= din;

`uvm_info("DRIVER", $psprintf("DRIVER data: \nwn= %0d \nDATA_IN= %0d",


vif.wn, vif.data_in), UVM_LOW);

// Wait for the FIFO to process the data


@(posedge vif.clock); // Ensure the signal is properly synchronized with
the clock
vif.wn <= 1'b0;
endtask

virtual task main_read();


@(posedge vif.clock); // Ensure you have the correct clock signal
vif.rn <= 1'b1;

// Wait for the read operation to complete


@(posedge vif.clock); // Ensure the signal is properly synchronized with
the clock
// Log the output data after it has been read
`uvm_info("DRIVER", $psprintf("DRIVER data: \nrn= %0d \nDATA_OUT= %0d",
vif.rn, vif.data_out), UVM_LOW);

vif.rn <= 1'b0;


endtask

endclass

Monitor

class monitor extends uvm_monitor;


`uvm_component_utils(monitor)

// Analysis port for sending monitored items to the scoreboard or other


components
uvm_analysis_port #(seq_item) item_collect_port;

virtual fifo_if vif;

seq_item mon_item;

function new(string name="monitor", uvm_component parent=null);


super.new(name, parent);
item_collect_port = new("item_collect_port", this);
endfunction

function void build_phase(uvm_phase phase);


super.build_phase(phase);
if (!uvm_config_db#(virtual fifo_if)::get(this, "", "vif", vif))
`uvm_fatal(get_type_name(), "Virtual interface not set on top level");
endfunction

virtual task run_phase(uvm_phase phase);


// Create an instance of seq_item to use for monitoring
mon_item = seq_item::type_id::create("mon_item");

forever begin
@(posedge vif.clock);

// Log relevant signals and update mon_item


if (vif.wn == 1) begin
mon_item.data_in = vif.data_in;
mon_item.wn = 1'b1;
mon_item.rn = 1'b0;
mon_item.full = vif.full;

`uvm_info("MONITOR", $psprintf("Monitoring data: \nwn= %0d \nFULL=


%0d \nDATA_IN= %0d",
mon_item.wn, mon_item.full,
mon_item.data_in), UVM_LOW);
end
else if (vif.rn == 1) begin
mon_item.data_out = vif.data_out;
mon_item.rn = 1'b1;
mon_item.wn = 1'b0;
mon_item.empty = vif.empty;

`uvm_info("MONITOR", $psprintf("Monitoring data: \nrn= %0d \nEMPTY=


%0d \nDATA_OUT= %0d",
mon_item.rn, mon_item.empty,
mon_item.data_out), UVM_LOW);

item_collect_port.write(mon_item);
end
end
endtask
endclass

Agent

class agent extends uvm_agent;


`uvm_component_utils(agent)

sequencer seqr;
driver drv;
monitor mon;

function new(string name="agent", uvm_component parent);


super.new(name, parent);
endfunction

function void build_phase(uvm_phase phase);


super.build_phase(phase);

if(get_is_active==UVM_ACTIVE)
begin
drv=driver::type_id::create("drv",this);
seqr=sequencer::type_id::create("seqr",this);
end

mon=monitor::type_id::create("mon",this);
endfunction

function void connect_phase(uvm_phase phase);


super.connect_phase(phase);

if(get_is_active == UVM_ACTIVE)
begin
drv.seq_item_port.connect(seqr.seq_item_export);
end
endfunction

endclass
Environment

class env extends uvm_env;


`uvm_component_utils(env)

agent agt;
scoreboard sb;

function new(string name="agent", uvm_component parent=null);


super.new(name,parent);
endfunction

function void build_phase(uvm_phase phase);


super.build_phase(phase);

agt=agent::type_id::create("env",this);
sb=scoreboard::type_id::create("sb",this);
endfunction

function void connect_phase(uvm_phase phase);


super.connect_phase(phase);

agt.mon.item_collect_port.connect(sb.item_collect_export);
endfunction

endclass

Scoreboard

class scoreboard extends uvm_scoreboard;


`uvm_component_utils(scoreboard)

uvm_analysis_imp #(seq_item, scoreboard) item_collect_export;

int expected_data_queue[$];

// Declare the covergroup and the sequence item used for coverage
seq_item cov_data_pkt;
covergroup fifo_coverage;

option.per_instance = 1; // Enable per-instance coverage

// Coverage of data_in signal


DATA_IN : coverpoint cov_data_pkt.data_in {
bins MAX = {[0:255]};
}

// Coverage of write enable signal (wn)


WRITE_CMD : coverpoint cov_data_pkt.wn {
bins write_dut = {0, 1};
}

// Coverage of Read enable signal (rn)


READ_CMD : coverpoint cov_data_pkt.rn {
bins write_dut = {0, 1};
}

// Coverage of empty signal (empty)


EMPTY_CMD : coverpoint cov_data_pkt.empty {
bins read_dut = {0, 1};
}

// Coverage of full signal (full)


FULL_CMD : coverpoint cov_data_pkt.full {
bins write_dut = {0, 1};
}

// Add cross-coverage if needed


READxWRITE : cross WRITE_CMD, DATA_IN;

endgroup : fifo_coverage

function new(string name="scoreboard", uvm_component parent=null);


super.new(name, parent);
item_collect_export = new("item_collect_export", this);

// Initialize the covergroup


fifo_coverage = new();
endfunction

function void build_phase(uvm_phase phase);


super.build_phase(phase);
endfunction

function void write(seq_item req);


$display("-------------------------------------------");

// Assign the transaction to the coverage packet


cov_data_pkt = req;

// Sample the covergroup with the current transaction


fifo_coverage.sample();

// Push the incoming data_in into the queue


expected_data_queue.push_back(req.data_in);

// Handle the latency, e.g., 2-cycle delay


if (expected_data_queue.size() >= 2) begin
int expected_data = expected_data_queue.pop_front();

// Compare the received output with the expected value


if (req.rn == 1'b1 && req.data_out == expected_data) begin
`uvm_info(get_type_name(), $sformatf("MATCH : DATA_IN=%0d,
DATA_OUT=%0d", expected_data, req.data_out), UVM_LOW);
end else if (req.rn == 1'b1) begin
`uvm_error(get_type_name(), $sformatf("NOT MATCH : Expected=%0d,
Got=%0d", expected_data, req.data_out));
end
end

$display("-------------------------------------------------");
$display("Overall Coverage: %0.2f%%",
$get_coverage());
$display("Coverage of covergroup 'FIFO_coverage': %0.2f%%",
fifo_coverage.get_coverage());
$display("Coverage of coverpoint 'DATA_IN' = %0f",
fifo_coverage.DATA_IN.get_coverage());
$display("Coverage of coverpoint 'WRITE_CMD' = %0f",
fifo_coverage.WRITE_CMD.get_coverage());
$display("Coverage of coverpoint 'READ_CMD' = %0f",
fifo_coverage.READ_CMD.get_coverage());
$display("Coverage of coverpoint 'EMPTY_CMD' = %0f",
fifo_coverage.EMPTY_CMD.get_coverage());
$display("Coverage of coverpoint 'FULL_CMD' = %0f",
fifo_coverage.FULL_CMD.get_coverage());

$display("-------------------------------------------------");

$display("-------------------------------------------");
endfunction
endclass

Test

class base_test extends uvm_test;


`uvm_component_utils(base_test)

env env_o;
base_seq bseq;

function new(string name="base_test", uvm_component parent=null);


super.new(name,parent);
endfunction

function void build_phase(uvm_phase phase);


super.build_phase(phase);

env_o=env::type_id::create("env_o",this);
bseq=base_seq::type_id::create("bseq",this);
endfunction

task run_phase(uvm_phase phase);


phase.raise_objection(this);
bseq.start(env_o.agt.seqr);
#30;
phase.drop_objection(this);
endtask

function void end_of_elaboration_phase (uvm_phase phase);


uvm_top.print_topology ();
endfunction

endclass

Testbench Top

import uvm_pkg::*;
`include "uvm_macros.svh"
`include "interface.sv"
`include "package.sv"

module tb_top;
bit clock;
bit reset;

always #5 clock=~clock;

initial
begin
clock=0;
reset=1;
#10 reset=0;
end

fifo_if vif(clock,reset);

FIFO DUT (
.data_out(vif.data_out),
.full(vif.full),
.empty(vif.empty),
.clock(vif.clock),
.reset(vif.reset),
.wn(vif.wn),
.rn(vif.rn),
.data_in(vif.data_in)
);

initial
begin
uvm_config_db #(virtual fifo_if)::set(uvm_root::get(),"*","vif",vif);
$dumpvars;
end

initial
begin
run_test("base_test");
end
endmodule
Package

import uvm_pkg::*;

`include "seq_item.sv"
`include "base_seq.sv"
`include "sequencer.sv"
`include "driver.sv"
`include "monitor.sv"
`include "scoreboard.sv"
`include "agent.sv"
`include "env.sv"
`include "base_test.sv"

You might also like