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);
[Link] = mbx;
tr = new();
endfunction;
task run();
repeat (count) begin
assert ([Link]) else $error("Randomization failed");
i++;
[Link](tr);
$display("[GEN] : Oper : %0d iteration : %0d", [Link], 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);
[Link] = mbx;
endfunction;
// Reset the DUT
task reset();
[Link] <= 1'b1;
[Link] <= 1'b0;
[Link] <= 1'b0;
fif.data_in <= 0;
repeat (5) @(posedge [Link]);
[Link] <= 1'b0;
$display("[DRV] : DUT Reset Done");
$display("------------------------------------------");
endtask
// Write data to the FIFO
task write();
@(posedge [Link]);
[Link] <= 1'b0;
[Link] <= 1'b0;
[Link] <= 1'b1;
fif.data_in <= $urandom_range(1, 10);
@(posedge [Link]);
[Link] <= 1'b0;
$display("[DRV] : DATA WRITE data : %0d", fif.data_in);
@(posedge [Link]);
endtask
// Read data from the FIFO
task read();
@(posedge [Link]);
[Link] <= 1'b0;
[Link] <= 1'b1;
[Link] <= 1'b0;
@(posedge [Link]);
[Link] <= 1'b0;
$display("[DRV] : DATA READ");
@(posedge [Link]);
endtask
// Apply random stimulus to the DUT
task run();
forever begin
[Link](datac);
if ([Link] == 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);
[Link] = mbx;
endfunction;
task run();
tr = new();
forever begin
repeat (2) @(posedge [Link]);
[Link] = [Link];
[Link] = [Link];
tr.data_in = fif.data_in;
[Link] = [Link];
[Link] = [Link];
@(posedge [Link]);
tr.data_out = fif.data_out;
[Link](tr);
$display("[MON] : Wr:%0d rd:%0d din:%0d dout:%0d full:%0d empty:%0d", [Link], [Link],
tr.data_in, tr.data_out, [Link], [Link]);
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);
[Link] = mbx;
endfunction;
task run();
forever begin
[Link](tr);
$display("[SCO] : Wr:%0d rd:%0d din:%0d dout:%0d full:%0d empty:%0d", [Link], [Link],
tr.data_in, tr.data_out, [Link], [Link]);
if ([Link] == 1'b1) begin
if ([Link] == 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 ([Link] == 1'b1) begin
if ([Link] == 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);
[Link] = fif;
[Link] = [Link];
[Link] = [Link];
[Link] = nextgs;
[Link] = nextgs;
endfunction
task pre_test();
[Link]();
endtask
task test();
fork
[Link]();
[Link]();
[Link]();
[Link]();
join_any
endtask
task post_test();
wait([Link]);
$display("---------------------------------------------");
$display("Error Count :%0d", [Link]);
$display("---------------------------------------------");
$finish();
endtask
task run();
pre_test();
test();
post_test();
endtask
endclass
///////////////////////////////////////////////////////
module tb;
fifo_if fif();
FIFO dut ([Link], [Link], [Link], [Link], fif.data_in, fif.data_out, [Link], [Link]);
initial begin
[Link] <= 0;
end
always #10 [Link] <= ~[Link];
environment env;
initial begin
env = new(fif);
[Link] = 10;
[Link]();
end
initial begin
$dumpfile("[Link]");
$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 [Link]);
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
[Link] = [Link]; // Copy the newd flag
[Link] = [Link]; // Copy the data input
[Link] = [Link]; // 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);
[Link] = mbx; // Initialize mailbox
tr = new(); // Create a new transaction
endfunction
task run();
repeat(count) begin
assert([Link]) else $error("[GEN] :Randomization Failed");
[Link]([Link]); // Put a copy of the transaction in the mailbox
$display("[GEN] : din : %0d", [Link]);
@(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);
[Link] = mbx; // Initialize mailboxes
[Link] = mbxds;
endfunction
task reset();
[Link] <= 1'b1; // Set reset signal
[Link] <= 1'b0; // Clear new data flag
[Link] <= 1'b0; // Clear data input
repeat(10) @(posedge [Link]);
[Link] <= 1'b0; // Clear reset signal
repeat(5) @(posedge [Link]);
$display("[DRV] : RESET DONE");
$display("-----------------------------------------");
endtask
task run();
forever begin
[Link](tr); // Get a transaction from the mailbox
[Link] <= 1'b1; // Set new data flag
[Link] <= [Link]; // Set data input
[Link]([Link]); // Put data in the mailbox for the monitor
@(posedge [Link]);
[Link] <= 1'b0; // Clear new data flag
@(posedge [Link]);
$display("[DRV] : DATA SENT TO DAC : %0d",[Link]);
@(posedge [Link]);
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);
[Link] = mbx; // Initialize the mailbox
endfunction
task run();
tr = new(); // Create a new transaction
forever begin
@(posedge [Link]);
@(posedge [Link]);
[Link] = [Link]; // Record data output
@(posedge [Link]);
$display("[MON] : DATA SENT : %0d", [Link]);
[Link]([Link]); // 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);
[Link] = mbxds; // Initialize mailboxes
[Link] = mbxms;
endfunction
task run();
forever begin
[Link](ds); // Get data from driver
[Link](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
[Link] = vif;
[Link] = [Link];
[Link] = [Link];
[Link] = nextgs; // Set synchronization events
[Link] = nextgs;
[Link] = nextgd;
[Link] = nextgd;
endfunction
task pre_test();
[Link](); // Perform driver reset
endtask
task test();
fork
[Link](); // Run generator
[Link](); // Run driver
[Link](); // Run monitor
[Link](); // Run scoreboard
join_any
endtask
task post_test();
wait([Link]); // 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([Link],[Link],[Link],[Link],[Link],[Link]);
initial begin
[Link] <= 0;
end
always #10 [Link] <= ~[Link];
environment env;
assign [Link] = [Link];
initial begin
env = new(vif);
[Link] = 4;
[Link]();
end
initial begin
$dumpfile("[Link]");
$dumpvars;
end
endmodule