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

Wider FIFO 구현한 내용입니다. #22

Open
wants to merge 5 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
114 changes: 114 additions & 0 deletions FIFO/Wider_FIFO/FIFO.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
module FIFO #(
parameter DEPTH_LG2 = 4,
parameter WRDATA_WIDTH = 16,
parameter RDDATA_WIDTH = 32,
parameter RST_MEM = 0 // 0: do not apply reset to the memory
)
(
input wire rst_n,

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

input wire rdclk,
input wire rden_i,
output wire [RDDATA_WIDTH-1:0] rdata_o,
output wire empty_o
);

localparam FIFO_DEPTH = (1<<DEPTH_LG2);
localparam WIDTH_RATIO = RDDATA_WIDTH/WRDATA_WIDTH;
localparam RATIO_LG2 = $clog2(WIDTH_RATIO);

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

reg [(DEPTH_LG2+RATIO_LG2):0] wrptr, wrptr_n;
reg full, full_n;

reg [RDDATA_WIDTH-1:0] rdata, rdata_n;
reg [DEPTH_LG2:0] rdptr, rdptr_n;
reg empty, empty_n;

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

always_ff @(posedge wrclk)
if (!rst_n) begin
wrptr <= {(DEPTH_LG2+RATIO_LG2){1'b0}};
full <= 1'b0;
end
else begin
wrptr <= wrptr_n;
full <= full_n;
end

always_ff @(posedge rdclk)
if (!rst_n) begin
rdptr <= {(DEPTH_LG2){1'b0}};
empty <= 1'b1; // empty after as reset
rdata <= rdata_n;
end
else begin
rdptr <= rdptr_n;
empty <= empty_n;
rdata <= rdata_n;
end

always_comb begin
wrptr_n = wrptr;
rdptr_n = rdptr;

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

if (rden_i) begin
rdata_n = mem[rdptr[DEPTH_LG2-1:0]];
rdptr_n = rdptr + 'd1;
end

if (!rden_i) begin
full_n = (wrptr_n[DEPTH_LG2+RATIO_LG2]!=rdptr_n[DEPTH_LG2])
&(wrptr_n[DEPTH_LG2+RATIO_LG2-1:RATIO_LG2] == rdptr_n[DEPTH_LG2-1:0]);
end

if (!wren_i) begin
empty_n = ((wrptr_n >> RATIO_LG2) == rdptr_n);
end
end

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

always @(posedge rdclk) begin
if (empty_o & rden_i) begin
$display("FIFO underflow");
@(posedge rdclk);
$finish;
end
end
// synthesis translate_on

assign empty_o = empty;
assign full_o = full;

assign rdata_o = rdata;

endmodule
171 changes: 171 additions & 0 deletions FIFO/Wider_FIFO/FIFO_TB.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
// A testbench for a FIFO
`timescale 1ns/10ps

module FIFO_TB;

localparam WRCLK_PERIOD = 10;
localparam RDCLK_PERIOD = 20;
localparam FIFO_DEPTH_LG2 = 4;
localparam WRDATA_WIDTH = 16;
localparam RDDATA_WIDTH = 32;

localparam TEST_DATA_CNT = 128;
localparam TEST_TIMEOUT = 100000;

//----------------------------------------------------------
// Clock and reset generation
//----------------------------------------------------------
logic wrclk, rdclk;
logic rst_n;

initial begin
wrclk = 1'b0;
forever
#(WRCLK_PERIOD/2) wrclk = ~wrclk;
end

initial begin
rdclk = 1'b0;
forever
#(RDCLK_PERIOD/2) rdclk = ~rdclk;
end

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

//----------------------------------------------------------
// Design-Under-Test (DUT)
//----------------------------------------------------------
wire full, empty;
logic wren, rden;
logic [WRDATA_WIDTH-1:0] wdata;
logic [RDDATA_WIDTH-1:0] rdata;
logic [WRDATA_WIDTH-1:0] wrtmp[2];

FIFO
#(
.DEPTH_LG2 (FIFO_DEPTH_LG2),
.WRDATA_WIDTH (WRDATA_WIDTH),
.RDDATA_WIDTH (RDDATA_WIDTH)
)
dut
(
.rst_n (rst_n),

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

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

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

// A scoreboard to hold expected data
mailbox data_sb = new(); // unlimited size
logic [RDDATA_WIDTH-1:0] expected_data;
logic [RDDATA_WIDTH-1:0] written_data;
logic read_flag = 1'b0;


// 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 wrclk);
#(WRCLK_PERIOD/2);
wren = 1'b0;
if (~full) begin
if (($random()%3)==0) begin // push with 33% probability
wren = 1'b1;
for (int i=0; i<RDDATA_WIDTH/WRDATA_WIDTH; i=i+1) begin
wdata = $urandom();
wrtmp[i] = wdata;
#WRCLK_PERIOD;
end
wren = 1'b0;
for (int i=0; i<RDDATA_WIDTH/WRDATA_WIDTH; i=i+1) begin
written_data[(i*WRDATA_WIDTH) +: WRDATA_WIDTH] = wrtmp[i];
end
data_sb.put(written_data);
$display($time, "ns, pushing %x", written_data);
end
end
end
wren = 1'b0;
end

// Pop driver/monitor
initial begin
rden = 1'b0;
@(posedge rst_n); // wait for the reset release

for (int i=0; i<TEST_DATA_CNT; i=i+1) begin
@(posedge rdclk);
#(RDCLK_PERIOD/2);

if (read_flag) begin
// compare against the rdata
if (expected_data===rdata) begin // "===" instead of "==" to compare against Xs
$display($time, "ns, peeking matching data: %x", rdata);
end
else begin
$fatal($time, "ns, data mismatch: %x (exp) %x (DUT)", expected_data, rdata);
end
read_flag = 1'b0;
end
rden = 1'b0;

if (~empty) begin
// step 1: check

// peek the expected data from the scoreboard
int peak_result;

peak_result = data_sb.try_peek(expected_data);
if (peak_result==0) begin
$fatal($time, "ns, the scoreboard is empty: %d", peak_result);
end
//
else begin
$display($time, "ns, peeking expected data: %x", expected_data);
end
//

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

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

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

endmodule
25 changes: 25 additions & 0 deletions FIFO/Wider_FIFO/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Wider FIFO

## Overview
Wider FIFO supports a narrow write port with a wide read port if the width ratio is valid. Valid width ratios are powers of 2 (e.g., 1, 2, and 4, etc.). For this FIFO, the read and write signals are synchronized to the rdclk and wrclk clocks, respectively.

## Parameters
- `DEPTH_LG2`: Specifies the depth of the FIFO as the number of log base 2.
- `WRDATA_WIDTH`: Specifies the bit-width of the write data in the FIFO.
- `RDDATA_WIDTH`: Specifies the bit-width of the read data in the FIFO.
- `RST_MEM`: Reset to the memory.

## Ports
- `rst_n`: Negative-edge-triggered reset.

- `wrclk`: Positive-edge-triggered clock. Use to synchronize the ports such as `wren_i`, `wdata_i`, and `full_o`.
- `wren_i`: Assert this signal to request for a write operation.
- `wdata_i`: Holds the data to be written in the FIFO when the `wren_i` signal is asserted.
- `full_o`: Do not perform write request operation when the FIFO is full.

- `rdclk`: Positive-edge-triggered clock. Use to synchronize the ports such as `rden_i`, `rdata_o`, `rdempty_o`, and `rdfull_o`.
- `rden_i`: Assert this signal to request for a read operation.
- `rdata_o`: Shows the data read from the read request operation.
- `empty_o`: Do not perform read request operation when the FIFO is empty.

(For Narrower and Wider FIFO, refer to https://www.intel.com/content/www/us/en/docs/programmable/683241/21-1/different-input-and-output-width.html)
Loading