mirror of
https://github.com/KastnerRG/riffa.git
synced 2025-01-30 23:02:54 +08:00
312 lines
8.5 KiB
Verilog
312 lines
8.5 KiB
Verilog
// ----------------------------------------------------------------------
|
|
// Copyright (c) 2015, The Regents of the University of California All
|
|
// rights reserved.
|
|
//
|
|
// Redistribution and use in source and binary forms, with or without
|
|
// modification, are permitted provided that the following conditions are
|
|
// met:
|
|
//
|
|
// * Redistributions of source code must retain the above copyright
|
|
// notice, this list of conditions and the following disclaimer.
|
|
//
|
|
// * Redistributions in binary form must reproduce the above
|
|
// copyright notice, this list of conditions and the following
|
|
// disclaimer in the documentation and/or other materials provided
|
|
// with the distribution.
|
|
//
|
|
// * Neither the name of The Regents of the University of California
|
|
// nor the names of its contributors may be used to endorse or
|
|
// promote products derived from this software without specific
|
|
// prior written permission.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL REGENTS OF THE
|
|
// UNIVERSITY OF CALIFORNIA BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
|
// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
|
// TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
|
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
|
// DAMAGE.
|
|
// ----------------------------------------------------------------------
|
|
//----------------------------------------------------------------------------
|
|
// Filename: async_fifo.v
|
|
// Version: 1.00.a
|
|
// Verilog Standard: Verilog-2001
|
|
// Description: Asynchronous capable parameterized FIFO. As with all
|
|
// traditional FIFOs, the RD_DATA will be valid one cycle following a RD_EN
|
|
// assertion. RD_EMPTY will remain low until the cycle following the last RD_EN
|
|
// assertion. Note, that RD_EMPTY may actually be high on the same cycle that
|
|
// RD_DATA contains valid data.
|
|
// Author: Matt Jacobsen
|
|
// History: @mattj: Version 2.0
|
|
// Additional Comments: Based on design by CE Cummings in Simulation and
|
|
// Synthesis Techniques for Asynchronous FIFO Design with Asynchronous Pointer
|
|
// Comparisons
|
|
//-----------------------------------------------------------------------------
|
|
`timescale 1ns/1ns
|
|
module async_fifo #(
|
|
parameter C_WIDTH = 32, // Data bus width
|
|
parameter C_DEPTH = 1024, // Depth of the FIFO
|
|
// Local parameters
|
|
parameter C_REAL_DEPTH = 2**clog2(C_DEPTH),
|
|
parameter C_DEPTH_BITS = clog2(C_REAL_DEPTH),
|
|
parameter C_DEPTH_P1_BITS = clog2(C_REAL_DEPTH+1)
|
|
)
|
|
(
|
|
input RD_CLK, // Read clock
|
|
input RD_RST, // Read synchronous reset
|
|
input WR_CLK, // Write clock
|
|
input WR_RST, // Write synchronous reset
|
|
input [C_WIDTH-1:0] WR_DATA, // Write data input (WR_CLK)
|
|
input WR_EN, // Write enable, high active (WR_CLK)
|
|
output [C_WIDTH-1:0] RD_DATA, // Read data output (RD_CLK)
|
|
input RD_EN, // Read enable, high active (RD_CLK)
|
|
output WR_FULL, // Full condition (WR_CLK)
|
|
output RD_EMPTY // Empty condition (RD_CLK)
|
|
);
|
|
|
|
`include "functions.vh"
|
|
|
|
wire wCmpEmpty;
|
|
wire wCmpFull;
|
|
wire [C_DEPTH_BITS-1:0] wWrPtr;
|
|
wire [C_DEPTH_BITS-1:0] wRdPtr;
|
|
wire [C_DEPTH_BITS-1:0] wWrPtrP1;
|
|
wire [C_DEPTH_BITS-1:0] wRdPtrP1;
|
|
|
|
|
|
// Memory block (synthesis attributes applied to this module will
|
|
// determine the memory option).
|
|
ram_2clk_1w_1r #(.C_RAM_WIDTH(C_WIDTH), .C_RAM_DEPTH(C_REAL_DEPTH)) mem (
|
|
.CLKA(WR_CLK),
|
|
.ADDRA(wWrPtr),
|
|
.WEA(WR_EN & !WR_FULL),
|
|
.DINA(WR_DATA),
|
|
.CLKB(RD_CLK),
|
|
.ADDRB(wRdPtr),
|
|
.DOUTB(RD_DATA)
|
|
);
|
|
|
|
|
|
// Compare the pointers.
|
|
async_cmp #(.C_DEPTH_BITS(C_DEPTH_BITS)) asyncCompare (
|
|
.WR_RST(WR_RST),
|
|
.WR_CLK(WR_CLK),
|
|
.RD_RST(RD_RST),
|
|
.RD_CLK(RD_CLK),
|
|
.RD_VALID(RD_EN & !RD_EMPTY),
|
|
.WR_VALID(WR_EN & !WR_FULL),
|
|
.EMPTY(wCmpEmpty),
|
|
.FULL(wCmpFull),
|
|
.WR_PTR(wWrPtr),
|
|
.WR_PTR_P1(wWrPtrP1),
|
|
.RD_PTR(wRdPtr),
|
|
.RD_PTR_P1(wRdPtrP1)
|
|
);
|
|
|
|
|
|
// Calculate empty
|
|
rd_ptr_empty #(.C_DEPTH_BITS(C_DEPTH_BITS)) rdPtrEmpty (
|
|
.RD_EMPTY(RD_EMPTY),
|
|
.RD_PTR(wRdPtr),
|
|
.RD_PTR_P1(wRdPtrP1),
|
|
.CMP_EMPTY(wCmpEmpty),
|
|
.RD_EN(RD_EN),
|
|
.RD_CLK(RD_CLK),
|
|
.RD_RST(RD_RST)
|
|
);
|
|
|
|
|
|
// Calculate full
|
|
wr_ptr_full #(.C_DEPTH_BITS(C_DEPTH_BITS)) wrPtrFull (
|
|
.WR_CLK(WR_CLK),
|
|
.WR_RST(WR_RST),
|
|
.WR_EN(WR_EN),
|
|
.WR_FULL(WR_FULL),
|
|
.WR_PTR(wWrPtr),
|
|
.WR_PTR_P1(wWrPtrP1),
|
|
.CMP_FULL(wCmpFull)
|
|
);
|
|
|
|
endmodule
|
|
|
|
|
|
module async_cmp #(
|
|
parameter C_DEPTH_BITS = 4,
|
|
// Local parameters
|
|
parameter N = C_DEPTH_BITS-1
|
|
)
|
|
(
|
|
input WR_RST,
|
|
input WR_CLK,
|
|
input RD_RST,
|
|
input RD_CLK,
|
|
input RD_VALID,
|
|
input WR_VALID,
|
|
output EMPTY,
|
|
output FULL,
|
|
input [C_DEPTH_BITS-1:0] WR_PTR,
|
|
input [C_DEPTH_BITS-1:0] RD_PTR,
|
|
input [C_DEPTH_BITS-1:0] WR_PTR_P1,
|
|
input [C_DEPTH_BITS-1:0] RD_PTR_P1
|
|
);
|
|
|
|
reg rDir=0;
|
|
wire wDirSet = ( (WR_PTR[N]^RD_PTR[N-1]) & ~(WR_PTR[N-1]^RD_PTR[N]));
|
|
wire wDirClr = ((~(WR_PTR[N]^RD_PTR[N-1]) & (WR_PTR[N-1]^RD_PTR[N])) | WR_RST);
|
|
|
|
reg rRdValid=0;
|
|
reg rEmpty=1;
|
|
reg rFull=0;
|
|
wire wATBEmpty = ((WR_PTR == RD_PTR_P1) && (RD_VALID | rRdValid));
|
|
wire wATBFull = ((WR_PTR_P1 == RD_PTR) && WR_VALID);
|
|
wire wEmpty = ((WR_PTR == RD_PTR) && !rDir);
|
|
wire wFull = ((WR_PTR == RD_PTR) && rDir);
|
|
|
|
assign EMPTY = wATBEmpty || rEmpty;
|
|
assign FULL = wATBFull || rFull;
|
|
|
|
always @(posedge wDirSet or posedge wDirClr)
|
|
if (wDirClr)
|
|
rDir <= 1'b0;
|
|
else
|
|
rDir <= 1'b1;
|
|
|
|
always @(posedge RD_CLK) begin
|
|
rEmpty <= (RD_RST ? 1'd1 : wEmpty);
|
|
rRdValid <= (RD_RST ? 1'd0 : RD_VALID);
|
|
end
|
|
|
|
always @(posedge WR_CLK) begin
|
|
rFull <= (WR_RST ? 1'd0 : wFull);
|
|
end
|
|
|
|
endmodule
|
|
|
|
|
|
module rd_ptr_empty #(
|
|
parameter C_DEPTH_BITS = 4
|
|
)
|
|
(
|
|
input RD_CLK,
|
|
input RD_RST,
|
|
input RD_EN,
|
|
output RD_EMPTY,
|
|
output [C_DEPTH_BITS-1:0] RD_PTR,
|
|
output [C_DEPTH_BITS-1:0] RD_PTR_P1,
|
|
input CMP_EMPTY
|
|
);
|
|
|
|
reg rEmpty=1;
|
|
reg rEmpty2=1;
|
|
reg [C_DEPTH_BITS-1:0] rRdPtr=0;
|
|
reg [C_DEPTH_BITS-1:0] rRdPtrP1=0;
|
|
reg [C_DEPTH_BITS-1:0] rBin=0;
|
|
reg [C_DEPTH_BITS-1:0] rBinP1=1;
|
|
wire [C_DEPTH_BITS-1:0] wGrayNext;
|
|
wire [C_DEPTH_BITS-1:0] wGrayNextP1;
|
|
wire [C_DEPTH_BITS-1:0] wBinNext;
|
|
wire [C_DEPTH_BITS-1:0] wBinNextP1;
|
|
|
|
assign RD_EMPTY = rEmpty;
|
|
assign RD_PTR = rRdPtr;
|
|
assign RD_PTR_P1 = rRdPtrP1;
|
|
|
|
// Gray coded pointer
|
|
always @(posedge RD_CLK or posedge RD_RST) begin
|
|
if (RD_RST) begin
|
|
rBin <= #1 0;
|
|
rBinP1 <= #1 1;
|
|
rRdPtr <= #1 0;
|
|
rRdPtrP1 <= #1 0;
|
|
end
|
|
else begin
|
|
rBin <= #1 wBinNext;
|
|
rBinP1 <= #1 wBinNextP1;
|
|
rRdPtr <= #1 wGrayNext;
|
|
rRdPtrP1 <= #1 wGrayNextP1;
|
|
end
|
|
end
|
|
|
|
// Increment the binary count if not empty
|
|
assign wBinNext = (!rEmpty ? rBin + RD_EN : rBin);
|
|
assign wBinNextP1 = (!rEmpty ? rBinP1 + RD_EN : rBinP1);
|
|
assign wGrayNext = ((wBinNext>>1) ^ wBinNext); // binary-to-gray conversion
|
|
assign wGrayNextP1 = ((wBinNextP1>>1) ^ wBinNextP1); // binary-to-gray conversion
|
|
|
|
always @(posedge RD_CLK) begin
|
|
if (CMP_EMPTY)
|
|
{rEmpty, rEmpty2} <= #1 2'b11;
|
|
else
|
|
{rEmpty, rEmpty2} <= #1 {rEmpty2, CMP_EMPTY};
|
|
end
|
|
|
|
endmodule
|
|
|
|
|
|
module wr_ptr_full #(
|
|
parameter C_DEPTH_BITS = 4
|
|
)
|
|
(
|
|
input WR_CLK,
|
|
input WR_RST,
|
|
input WR_EN,
|
|
output WR_FULL,
|
|
output [C_DEPTH_BITS-1:0] WR_PTR,
|
|
output [C_DEPTH_BITS-1:0] WR_PTR_P1,
|
|
input CMP_FULL
|
|
);
|
|
|
|
reg rFull=0;
|
|
reg rFull2=0;
|
|
reg [C_DEPTH_BITS-1:0] rPtr=0;
|
|
reg [C_DEPTH_BITS-1:0] rPtrP1=0;
|
|
reg [C_DEPTH_BITS-1:0] rBin=0;
|
|
reg [C_DEPTH_BITS-1:0] rBinP1=1;
|
|
wire [C_DEPTH_BITS-1:0] wGrayNext;
|
|
wire [C_DEPTH_BITS-1:0] wGrayNextP1;
|
|
wire [C_DEPTH_BITS-1:0] wBinNext;
|
|
wire [C_DEPTH_BITS-1:0] wBinNextP1;
|
|
|
|
assign WR_FULL = rFull;
|
|
assign WR_PTR = rPtr;
|
|
assign WR_PTR_P1 = rPtrP1;
|
|
|
|
// Gray coded pointer
|
|
always @(posedge WR_CLK or posedge WR_RST) begin
|
|
if (WR_RST) begin
|
|
rBin <= #1 0;
|
|
rBinP1 <= #1 1;
|
|
rPtr <= #1 0;
|
|
rPtrP1 <= #1 0;
|
|
end
|
|
else begin
|
|
rBin <= #1 wBinNext;
|
|
rBinP1 <= #1 wBinNextP1;
|
|
rPtr <= #1 wGrayNext;
|
|
rPtrP1 <= #1 wGrayNextP1;
|
|
end
|
|
end
|
|
|
|
// Increment the binary count if not full
|
|
assign wBinNext = (!rFull ? rBin + WR_EN : rBin);
|
|
assign wBinNextP1 = (!rFull ? rBinP1 + WR_EN : rBinP1);
|
|
assign wGrayNext = ((wBinNext>>1) ^ wBinNext); // binary-to-gray conversion
|
|
assign wGrayNextP1 = ((wBinNextP1>>1) ^ wBinNextP1); // binary-to-gray conversion
|
|
|
|
always @(posedge WR_CLK) begin
|
|
if (WR_RST)
|
|
{rFull, rFull2} <= #1 2'b00;
|
|
else if (CMP_FULL)
|
|
{rFull, rFull2} <= #1 2'b11;
|
|
else
|
|
{rFull, rFull2} <= #1 {rFull2, CMP_FULL};
|
|
end
|
|
|
|
endmodule
|
|
|