0% found this document useful (0 votes)
46 views

FIFO

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)
46 views

FIFO

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/ 31

FIFO

Design Code

module FIFO(input clk, rst, wr, rd,

input [7:0] din, output reg [7:0] dout,

output empty, full);

// Pointers for write and read operations

reg [3:0] wptr = 0, rptr = 0;

// Counter for tracking the number of elements in the FIFO

reg [4:0] cnt = 0;

// Memory array to store data

reg [7:0] mem [15:0];

always @(posedge clk)

begin

if (rst == 1'b1)

begin

// Reset the pointers and counter when the reset signal is asserted

wptr <= 0;

rptr <= 0;

cnt <= 0;

end

else if (wr && !full)


begin

// Write data to the FIFO if it's not full

mem[wptr] <= din;

wptr <= wptr + 1;

cnt <= cnt + 1;

end

else if (rd && !empty)

begin

// Read data from the FIFO if it's not empty

dout <= mem[rptr];

rptr <= rptr + 1;

cnt <= cnt - 1;

end

end

// Determine if the FIFO is empty or full

assign empty = (cnt == 0) ? 1'b1 : 1'b0;

assign full = (cnt == 16) ? 1'b1 : 1'b0;

endmodule

//////////////////////////////////////

// Define an interface for the FIFO

interface fifo_if;
logic clock, rd, wr; // Clock, read, and write signals

logic full, empty; // Flags indicating FIFO status

logic [7:0] data_in; // Data input

logic [7:0] data_out; // Data output

logic rst; // Reset signal

endinterface

TB code with comments

class transaction;

rand bit oper; // Randomized bit for operation control (1 or 0)

bit rd, wr; // Read and write control bits

bit [7:0] data_in; // 8-bit data input

bit full, empty; // Flags for full and empty status

bit [7:0] data_out; // 8-bit data output

constraint oper_ctrl {

oper dist {1 :/ 50 , 0 :/ 50}; // Constraint to randomize 'oper' with 50% probability of 1 and
50% probability of 0

endclass
///////////////////////////////////////////////////

class generator;

transaction tr; // Transaction object to generate and send

mailbox #(transaction) mbx; // Mailbox for communication

int count = 0; // Number of transactions to generate

int i = 0; // Iteration counter

event next; // Event to signal when to send the next transaction

event done; // Event to convey completion of requested number of transactions

function new(mailbox #(transaction) mbx);

this.mbx = mbx;

tr = new();

endfunction;

task run();

repeat (count) begin

assert (tr.randomize) else $error("Randomization failed");

i++;

mbx.put(tr);

$display("[GEN] : Oper : %0d iteration : %0d", tr.oper, i);

@(next);

end -> done;


endtask

endclass

////////////////////////////////////////////

class driver;

virtual fifo_if fif; // Virtual interface to the FIFO

mailbox #(transaction) mbx; // Mailbox for communication

transaction datac; // Transaction object for communication

function new(mailbox #(transaction) mbx);

this.mbx = mbx;

endfunction;

// Reset the DUT

task reset();

fif.rst <= 1'b1;

fif.rd <= 1'b0;

fif.wr <= 1'b0;

fif.data_in <= 0;

repeat (5) @(posedge fif.clock);

fif.rst <= 1'b0;

$display("[DRV] : DUT Reset Done");

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

// Write data to the FIFO

task write();

@(posedge fif.clock);

fif.rst <= 1'b0;

fif.rd <= 1'b0;

fif.wr <= 1'b1;

fif.data_in <= $urandom_range(1, 10);

@(posedge fif.clock);

fif.wr <= 1'b0;

$display("[DRV] : DATA WRITE data : %0d", fif.data_in);

@(posedge fif.clock);

endtask

// Read data from the FIFO

task read();

@(posedge fif.clock);

fif.rst <= 1'b0;

fif.rd <= 1'b1;

fif.wr <= 1'b0;

@(posedge fif.clock);

fif.rd <= 1'b0;

$display("[DRV] : DATA READ");

@(posedge fif.clock);
endtask

// Apply random stimulus to the DUT

task run();

forever begin

mbx.get(datac);

if (datac.oper == 1'b1)

write();

else

read();

end

endtask

endclass

///////////////////////////////////////////////////////

class monitor;

virtual fifo_if fif; // Virtual interface to the FIFO

mailbox #(transaction) mbx; // Mailbox for communication

transaction tr; // Transaction object for monitoring

function new(mailbox #(transaction) mbx);

this.mbx = mbx;
endfunction;

task run();

tr = new();

forever begin

repeat (2) @(posedge fif.clock);

tr.wr = fif.wr;

tr.rd = fif.rd;

tr.data_in = fif.data_in;

tr.full = fif.full;

tr.empty = fif.empty;

@(posedge fif.clock);

tr.data_out = fif.data_out;

mbx.put(tr);

$display("[MON] : Wr:%0d rd:%0d din:%0d dout:%0d full:%0d empty:%0d", tr.wr, tr.rd,


tr.data_in, tr.data_out, tr.full, tr.empty);

end

endtask

endclass

/////////////////////////////////////////////////////
class scoreboard;

mailbox #(transaction) mbx; // Mailbox for communication

transaction tr; // Transaction object for monitoring

event next;

bit [7:0] din[$]; // Array to store written data

bit [7:0] temp; // Temporary data storage

int err = 0; // Error count

function new(mailbox #(transaction) mbx);

this.mbx = mbx;

endfunction;

task run();

forever begin

mbx.get(tr);

$display("[SCO] : Wr:%0d rd:%0d din:%0d dout:%0d full:%0d empty:%0d", tr.wr, tr.rd,


tr.data_in, tr.data_out, tr.full, tr.empty);

if (tr.wr == 1'b1) begin

if (tr.full == 1'b0) begin

din.push_front(tr.data_in);

$display("[SCO] : DATA STORED IN QUEUE :%0d", tr.data_in);

end

else begin

$display("[SCO] : FIFO is full");


end

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

end

if (tr.rd == 1'b1) begin

if (tr.empty == 1'b0) begin

temp = din.pop_back();

if (tr.data_out == temp)

$display("[SCO] : DATA MATCH");

else begin

$error("[SCO] : DATA MISMATCH");

err++;

end

end

else begin

$display("[SCO] : FIFO IS EMPTY");

end

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

end

-> next;

end

endtask
endclass

///////////////////////////////////////////////////////

class environment;

generator gen;

driver drv;

monitor mon;

scoreboard sco;

mailbox #(transaction) gdmbx; // Generator + Driver mailbox

mailbox #(transaction) msmbx; // Monitor + Scoreboard mailbox

event nextgs;

virtual fifo_if fif;

function new(virtual fifo_if fif);

gdmbx = new();

gen = new(gdmbx);

drv = new(gdmbx);

msmbx = new();

mon = new(msmbx);

sco = new(msmbx);

this.fif = fif;

drv.fif = this.fif;
mon.fif = this.fif;

gen.next = nextgs;

sco.next = nextgs;

endfunction

task pre_test();

drv.reset();

endtask

task test();

fork

gen.run();

drv.run();

mon.run();

sco.run();

join_any

endtask

task post_test();

wait(gen.done.triggered);

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

$display("Error Count :%0d", sco.err);

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

$finish();

endtask
task run();

pre_test();

test();

post_test();

endtask

endclass

///////////////////////////////////////////////////////

module tb;

fifo_if fif();

FIFO dut (fif.clock, fif.rst, fif.wr, fif.rd, fif.data_in, fif.data_out, fif.empty, fif.full);

initial begin

fif.clock <= 0;

end

always #10 fif.clock <= ~fif.clock;

environment env;

initial begin
env = new(fif);

env.gen.count = 10;

env.run();

end

initial begin

$dumpfile("dump.vcd");

$dumpvars;

end

endmodule

SPI PROTOCOL

Design Code

module spi_master(

input clk, newd,rst,

input [11:0] din,

output reg sclk,cs,mosi

);

typedef enum bit [1:0] {idle = 2'b00, enable = 2'b01, send = 2'b10, comp = 2'b11 } state_type;

state_type state = idle;


int countc = 0;

int count = 0;

/////////////////////////generation of sclk

always@(posedge clk)

begin

if(rst == 1'b1) begin

countc <= 0;

sclk <= 1'b0;

end

else begin

if(countc < 10 )

countc <= countc + 1;

else

begin

countc <= 0;

sclk <= ~sclk;

end

end

end

//////////////////state machine

reg [11:0] temp;


always@(posedge sclk)

begin

if(rst == 1'b1) begin

cs <= 1'b1;

mosi <= 1'b0;

end

else begin

case(state)

idle:

begin

if(newd == 1'b1) begin

state <= send;

temp <= din;

cs <= 1'b0;

end

else begin

state <= idle;

temp <= 8'h00;

end

end

send : begin

if(count <= 11) begin

mosi <= temp[count]; /////sending lsb first


count <= count + 1;

end

else

begin

count <= 0;

state <= idle;

cs <= 1'b1;

mosi <= 1'b0;

end

end

default : state <= idle;

endcase

end

end

endmodule

///////////////////////////

module spi_slave (

input sclk, cs, mosi,

output [11:0] dout,

output reg done


);

typedef enum bit {detect_start = 1'b0, read_data = 1'b1} state_type;

state_type state = detect_start;

reg [11:0] temp = 12'h000;

int count = 0;

always@(posedge sclk)

begin

case(state)

detect_start:

begin

done <= 1'b0;

if(cs == 1'b0)

state <= read_data;

else

state <= detect_start;

end

read_data : begin

if(count <= 11)

begin

count <= count + 1;


temp <= { mosi, temp[11:1]};

end

else

begin

count <= 0;

done <= 1'b1;

state <= detect_start;

end

end

endcase

end

assign dout = temp;

endmodule

///////////////////////////////

module top (

input clk, rst, newd,

input [11:0] din,

output [11:0] dout,

output done
);

wire sclk, cs, mosi;

spi_master m1 (clk, newd, rst, din, sclk, cs, mosi);

spi_slave s1 (sclk, cs, mosi, dout, done);

endmodule

Verilog TB

`timescale 1ns / 1ps

//////////////////////////////////////////////////////////////////////////////////

module tb( );

reg clk = 0, rst = 0, newd = 0;

reg [11:0] din = 0;

wire [11:0] dout;

wire done;

always #10 clk = ~clk;

top dut (clk, rst, newd, din, dout, done);


initial begin

rst = 1;

repeat(5) @(posedge clk);

rst = 0;

for(int i = 0; i < 10; i++)

begin

newd = 1;

din = $urandom;

@(posedge dut.s1.sclk);

newd = 0;

@(posedge done);

end

end

endmodule

Testbench Code

////////////////Transaction Class

class transaction;

bit newd; // Flag for new transaction


rand bit [11:0] din; // Random 12-bit data input

bit [11:0] dout; // 12-bit data output

function transaction copy();

copy = new(); // Create a copy of the transaction

copy.newd = this.newd; // Copy the newd flag

copy.din = this.din; // Copy the data input

copy.dout = this.dout; // Copy the data output

endfunction

endclass

////////////////Generator Class

class generator;

transaction tr; // Transaction object

mailbox #(transaction) mbx; // Mailbox for transactions

event done; // Done event

int count = 0; // Transaction count

event drvnext; // Event to synchronize with driver

event sconext; // Event to synchronize with scoreboard

function new(mailbox #(transaction) mbx);

this.mbx = mbx; // Initialize mailbox

tr = new(); // Create a new transaction


endfunction

task run();

repeat(count) begin

assert(tr.randomize) else $error("[GEN] :Randomization Failed");

mbx.put(tr.copy); // Put a copy of the transaction in the mailbox

$display("[GEN] : din : %0d", tr.din);

@(sconext); // Wait for the scoreboard synchronization event

end

-> done; // Signal when done

endtask

endclass

////////////////Driver Class

class driver;

virtual spi_if vif; // Virtual interface

transaction tr; // Transaction object

mailbox #(transaction) mbx; // Mailbox for transactions

mailbox #(bit [11:0]) mbxds; // Mailbox for data output to monitor

event drvnext; // Event to synchronize with generator

bit [11:0] din; // Data input


function new(mailbox #(bit [11:0]) mbxds, mailbox #(transaction) mbx);

this.mbx = mbx; // Initialize mailboxes

this.mbxds = mbxds;

endfunction

task reset();

vif.rst <= 1'b1; // Set reset signal

vif.newd <= 1'b0; // Clear new data flag

vif.din <= 1'b0; // Clear data input

repeat(10) @(posedge vif.clk);

vif.rst <= 1'b0; // Clear reset signal

repeat(5) @(posedge vif.clk);

$display("[DRV] : RESET DONE");

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

endtask

task run();

forever begin

mbx.get(tr); // Get a transaction from the mailbox

vif.newd <= 1'b1; // Set new data flag

vif.din <= tr.din; // Set data input

mbxds.put(tr.din); // Put data in the mailbox for the monitor

@(posedge vif.sclk);

vif.newd <= 1'b0; // Clear new data flag


@(posedge vif.done);

$display("[DRV] : DATA SENT TO DAC : %0d",tr.din);

@(posedge vif.sclk);

end

endtask

endclass

////////////////Monitor Class

class monitor;

transaction tr; // Transaction object

mailbox #(bit [11:0]) mbx; // Mailbox for data output

virtual spi_if vif; // Virtual interface

function new(mailbox #(bit [11:0]) mbx);

this.mbx = mbx; // Initialize the mailbox

endfunction

task run();

tr = new(); // Create a new transaction

forever begin

@(posedge vif.sclk);

@(posedge vif.done);
tr.dout = vif.dout; // Record data output

@(posedge vif.sclk);

$display("[MON] : DATA SENT : %0d", tr.dout);

mbx.put(tr.dout); // Put data in the mailbox

end

endtask

endclass

////////////////Scoreboard Class

class scoreboard;

mailbox #(bit [11:0]) mbxds, mbxms; // Mailboxes for data from driver and monitor

bit [11:0] ds; // Data from driver

bit [11:0] ms; // Data from monitor

event sconext; // Event to synchronize with environment

function new(mailbox #(bit [11:0]) mbxds, mailbox #(bit [11:0]) mbxms);

this.mbxds = mbxds; // Initialize mailboxes

this.mbxms = mbxms;

endfunction

task run();

forever begin

mbxds.get(ds); // Get data from driver


mbxms.get(ms); // Get data from monitor

$display("[SCO] : DRV : %0d MON : %0d", ds, ms);

if(ds == ms)

$display("[SCO] : DATA MATCHED");

else

$display("[SCO] : DATA MISMATCHED");

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

->sconext; // Synchronize with the environment

end

endtask

endclass

////////////////Environment Class

class environment;

generator gen; // Generator object

driver drv; // Driver object

monitor mon; // Monitor object

scoreboard sco; // Scoreboard object

event nextgd; // Event for generator to driver communication

event nextgs; // Event for generator to scoreboard communication


mailbox #(transaction) mbxgd; // Mailbox for generator to driver communication

mailbox #(bit [11:0]) mbxds; // Mailbox for driver to monitor communication

mailbox #(bit [11:0]) mbxms; // Mailbox for monitor to scoreboard communication

virtual spi_if vif; // Virtual interface

function new(virtual spi_if vif);

mbxgd = new(); // Initialize mailboxes

mbxms = new();

mbxds = new();

gen = new(mbxgd); // Initialize generator

drv = new(mbxds,mbxgd); // Initialize driver

mon = new(mbxms); // Initialize monitor

sco = new(mbxds, mbxms); // Initialize scoreboard

this.vif = vif;

drv.vif = this.vif;

mon.vif = this.vif;

gen.sconext = nextgs; // Set synchronization events

sco.sconext = nextgs;

gen.drvnext = nextgd;
drv.drvnext = nextgd;

endfunction

task pre_test();

drv.reset(); // Perform driver reset

endtask

task test();

fork

gen.run(); // Run generator

drv.run(); // Run driver

mon.run(); // Run monitor

sco.run(); // Run scoreboard

join_any

endtask

task post_test();

wait(gen.done.triggered); // Wait for generator to finish

$finish();

endtask

task run();

pre_test();

test();

post_test();
endtask

endclass

////////////////Testbench Top

module tb;

spi_if vif(); // Virtual interface instance

top dut(vif.clk,vif.rst,vif.newd,vif.din,vif.dout,vif.done);

initial begin

vif.clk <= 0;

end

always #10 vif.clk <= ~vif.clk;

environment env;

assign vif.sclk = dut.m1.sclk;

initial begin

env = new(vif);

env.gen.count = 4;

env.run();

end
initial begin

$dumpfile("dump.vcd");

$dumpvars;

end

endmodule

You might also like