Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mulit-Reader FIFO #11

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
159 changes: 159 additions & 0 deletions FIFO/FIFO2/MULTI_FIFO/FIFO_TB.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
// A testbench for a FIFO
`timescale 1ns/10ps

module FIFO_TB;

localparam CLK_PERIOD = 10;
localparam FIFO_DEPTH_LG2 = 4;
localparam DATA_WIDTH = 32;

localparam READER_NUM = 2;

localparam TEST_DATA_CNT = 128;
localparam TEST_TIMEOUT = 100000;

//----------------------------------------------------------
// Clock and reset generation
//----------------------------------------------------------
logic clk;
logic rst_n;

initial begin
clk = 1'b0;
forever
#(CLK_PERIOD/2) clk = ~clk;
end

initial begin
rst_n = 1'b0;
repeat (3) @(posedge clk); // wait for 3 clocks
rst_n = 1'b1;
end

//----------------------------------------------------------
// Design-Under-Test (DUT)
//----------------------------------------------------------
wire full, empty[READER_NUM];
logic wren;
logic rden[READER_NUM];
logic [DATA_WIDTH-1:0] wdata;
logic [DATA_WIDTH-1:0] rdata[READER_NUM];

FIFO
#(
.DEPTH_LG2 (FIFO_DEPTH_LG2),
.DATA_WIDTH (DATA_WIDTH),
.READER_NUM (READER_NUM)
)
dut
(
.clk (clk),
.rst_n (rst_n),

.full_o (full),
.wren_i (wren),
.wdata_i (wdata),

.empty_o (empty),
.rden_i (rden),
.rdata_o (rdata)
);

//----------------------------------------------------------
// Driver, Monitor, and Scoreboard
//----------------------------------------------------------

// A scoreboard to hold expected data
mailbox data_sb[READER_NUM]; // unlimited size


initial begin
for (int i=0; i<READER_NUM; i++) begin
data_sb[i] = new();
end
end

// Push driver
initial begin
wren = 1'b0;
wdata = 'hX;
@(posedge rst_n); // wait for the reset release

for (int i=0; i<TEST_DATA_CNT; i=i+1) begin
@(posedge clk);
#1
wren = 1'b0;
if (~full) begin
if (($random()%3)==0) begin // push with 33% probability
wren = 1'b1;
wdata = $urandom();
data_sb[0].put(wdata); //reader 1
data_sb[1].put(wdata); //reader 2
$display($time, "ns, pushing %x", wdata);
end
end
end
wren = 1'b0;
end

// Pop driver/monitor
initial begin
rden[0] = 'b0;
rden[1] = 'b0;

@(posedge rst_n); // wait for the reset release

for (int i=0; i<TEST_DATA_CNT; i=i+1) begin
@(posedge clk);
#1
rden[0] = 'b0;
rden[1] = 'b0;

for (int i=0; i<READER_NUM; i++) begin
if (~empty[i]&~full) begin
// step 1: check

// peek the expected data from the scoreboard
int peak_result;
logic [DATA_WIDTH-1:0] expected_data[READER_NUM];

peak_result = data_sb[i].try_peek(expected_data[i]);
if (peak_result==0) begin
$fatal($time, "ns, the scoreboard is empty: %d", peak_result);
end


// compare against the rdata
if (expected_data[i]===rdata[i]) begin // "===" instead of "==" to compare against Xs
$display($time, "ns, peeking matching data(reader %d): %x", i, rdata[i]);
end
else begin
$fatal($time, "ns, data mismatch(reader %d): %x (exp) %x (DUT)", i, expected_data[i], rdata[i]);
end


// step 2: pop the entry
if (($random()%3)==0) begin // pop with 33% probability
rden[i] = 'b1;
// pop from the scoreboard -> discard
data_sb[i].get(expected_data[i]);
$display($time, "ns, popping matching data(reader %d): %x", i, rdata[i]);
end
end
end
end
rden[0] = 'b0;
rden[1] = 'b0;

repeat(10) @(posedge clk);
$finish;
end

// Time-out
initial begin
#TEST_TIMEOUT
$display("Simulation timed out!");
$fatal("Simulation timed out");
end

endmodule
123 changes: 123 additions & 0 deletions FIFO/FIFO2/MULTI_FIFO/Multi_FIFO.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
module FIFO #(
parameter DEPTH_LG2 = 4,
parameter DATA_WIDTH = 32,
parameter RST_MEM = 0, // 0: do not apply reset to the memory
parameter READER_NUM = 2
)
(
input wire clk,
input wire rst_n,

output wire full_o,
input wire wren_i,
input wire [DATA_WIDTH-1:0] wdata_i,

output wire empty_o[READER_NUM],
input wire rden_i[READER_NUM],
output wire [DATA_WIDTH-1:0] rdata_o[READER_NUM]
);

localparam FIFO_DEPTH = (1<<DEPTH_LG2);

reg [DATA_WIDTH-1:0] mem[FIFO_DEPTH];

reg full, full_n,
empty[READER_NUM],
empty_n[READER_NUM];
reg [DEPTH_LG2:0] wrptr, wrptr_n,
rdptr[READER_NUM],
rdptr_n[READER_NUM];


always_ff @(posedge clk)
if (!rst_n & RST_MEM) begin
for (int i=0; i<FIFO_DEPTH; i++) begin
mem[i] <= {DATA_WIDTH{1'b0}};
end
end
else begin
if (wren_i) begin
mem[wrptr[DEPTH_LG2-1:0]] <= wdata_i;
end
end

always_ff @(posedge clk)
if (!rst_n) begin
full <= 1'b0;
for (int i=0; i<READER_NUM; i++) begin
empty[i] <= 1'b1; // empty after as reset
end

wrptr <= {(DEPTH_LG2+1){1'b0}};
for (int i=0; i<READER_NUM; i++) begin
rdptr[i] <= {(DEPTH_LG2+1){1'b0}};
end

end
else begin
full <= full_n;
for (int i=0; i<READER_NUM; i++) begin
empty[i] <= empty_n[i]; // empty after as reset
end

wrptr <= wrptr_n;
for (int i=0; i<READER_NUM; i++) begin
rdptr[i] <= rdptr_n[i];
end
end

always_comb begin
wrptr_n = wrptr;
for (int i=0; i<READER_NUM; i++) begin
rdptr_n[i] = rdptr[i];
end

if (wren_i) begin
wrptr_n = wrptr + 'd1;
end

for (int i=0; i<READER_NUM; i++) begin
if (rden_i[i]) begin
rdptr_n[i] = rdptr[i] + 'd1;
end
end


for (int i=0; i<READER_NUM; i++) begin
empty_n[i] = (wrptr_n == rdptr_n[i]);
end
full_n = ((wrptr_n[DEPTH_LG2]!=rdptr_n[0][DEPTH_LG2])
&(wrptr_n[DEPTH_LG2-1:0]==rdptr_n[0][DEPTH_LG2-1:0]))||
((wrptr_n[DEPTH_LG2]!=rdptr_n[1][DEPTH_LG2])
&(wrptr_n[DEPTH_LG2-1:0]==rdptr_n[1][DEPTH_LG2-1:0]));

end

// synthesis translate_off
always @(posedge clk) begin
if (full_o & wren_i) begin
$display("FIFO overflow");
@(posedge clk);
$finish;
end
end

always @(posedge clk) begin
for (int i=0; i<READER_NUM; i++) begin
if (empty_o[i] & rden_i[i]) begin
$display("FIFO underflow(reader %d)", i);
@(posedge clk);
$finish;
end
end
end
// synthesis translate_on

assign full_o = full;
assign empty_o[0] = empty[0];
assign empty_o[1] = empty[1];
assign rdata_o[0] = mem[rdptr[0][DEPTH_LG2-1:0]];
assign rdata_o[1] = mem[rdptr[1][DEPTH_LG2-1:0]];


endmodule
Empty file added FIFO/FIFO2/MULTI_FIFO/README.md
Empty file.
2 changes: 2 additions & 0 deletions FIFO/FIFO2/MULTI_FIFO/filelist.f
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
FIFO_TV.sv
Multi_FIFO.sv
1 change: 1 addition & 0 deletions FIFO/FIFO2/MULTI_FIFO/run
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
vcs -full64 -kdb -debug_access+all -LDFLAGS -Wl,--no-as-needed -sverilog -f filelist.f