1
0
mirror of https://github.com/pConst/basic_verilog.git synced 2025-01-14 06:42:54 +08:00
basic_verilog/preview_fifo.sv

292 lines
8.1 KiB
Systemverilog

//------------------------------------------------------------------------------
// preview_fifo.sv
// Konstantin Pavlov, pavlovconst@gmail.com
//------------------------------------------------------------------------------
// INFO ------------------------------------------------------------------------
// Preview FIFO, v2
//
// The module performs just like an ordinany FIFO in show-ahead mode.
// The diffenence is that 0, 1 or 2 words may be written at once.
// Also, 0, 1 or 2 words may be requested at once.
// This gives an opportunity for the reader to "preview" up to 2 future
// fifo words without actually fetching it yet.
//
/* --- INSTANTIATION TEMPLATE BEGIN ---
preview_fifo #(
.WIDTH( 16 ),
.DEPTH( 16 ) // must be at least 8
) pf (
.clk( clk ),
.nrst( nrst ),
// input port
.wrreq( ), // 3 bit one-hot
.id0( ), // first word
.id1( ), // secong word
// output port
.rdreq( ), // 3 bit one-hot
.od0( ), // first word
.od1( ), // second word
.empty( [1:0] ), // 2'b00, 2'b10 or 2'b11
.full( [1:0] ), // 2'b11, 2'b01 or 2'b00
.usedw( [USED_W:0] ) // attention to the width!
);
--- INSTANTIATION TEMPLATE END ---*/
module preview_fifo #( parameter
WIDTH = 32,
DEPTH = 16, // must be at least 8
USED_W = $clog2(DEPTH)
)(
input clk,
input nrst,
// input port
input [2:0] wrreq, // 3'b001 - no write
// 3'b010 - write one word
// 3'b100 - write two words at once
input [WIDTH-1:0] id0, // preceding data word
input [WIDTH-1:0] id1, // subsequent data word
// both data words are written simultaneously
// output port
input [2:0] rdreq, // 3'b001 - no read
// 3'b010 - read one word
// 3'b100 - read two words at once
output logic [WIDTH-1:0] od0, // first data word (preceding)
output logic [WIDTH-1:0] od1, // seconfd dadta word (subsequent)
output [1:0] empty, // when FIFO has just one word -
// any of thse bits will be active
// when FIFO has no words -
// both of these flags will be active
output [1:0] full, // "full" flags, logic is similar to "empty"
output logic[USED_W:0] usedw // word count, attention to the additional
// MSB for holding word count when full
);
// *_ptr=0 means that next read or write shoul happen with FIFO0
// *_ptr=1 means that next read or write shoul happen with FIFO1
logic wr_ptr = 1'b0;
logic rd_ptr = 1'b0;
logic [1:0] f_wrreq;
logic [1:0][WIDTH-1:0] f_wrdata;
logic [1:0] f_rdreq;
logic [1:0][WIDTH-1:0] f_rddata;
// underflow and owerflow protection flags
logic w0_valid, w1_valid, w2_valid;
logic r0_valid, r1_valid, r2_valid;
always_comb begin
w0_valid <= ~full[0];
w1_valid <= ~full[1];
w2_valid <= ~|full[1:0]; // write two words is valid
r0_valid <= ~empty[0];
r1_valid <= ~empty[1];
r2_valid <= ~|empty[1:0]; // read two words is valid
end
// writing internal FIFOs ======================================================
always_comb begin
case( wrreq[2:0] )
3'b010: begin // writing one word
if( wr_ptr ) begin
f_wrreq[0] <= 1'b0;
if( w1_valid ) begin // protecting from overflow
f_wrreq[1] <= 1'b1;
end else begin
f_wrreq[1] <= 1'b0;
end
end else begin
if( w0_valid ) begin // protecting from overflow
f_wrreq[0] <= 1'b1;
end else begin
f_wrreq[0] <= 1'b0;
end
f_wrreq[1] <= 1'b0;
end // wr_ptr
end
3'b100: begin // writing two words
if( w2_valid ) begin // protecting from overflow
f_wrreq[0] <= 1'b1;
f_wrreq[1] <= 1'b1;
end else begin
f_wrreq[0] <= 1'b0;
f_wrreq[1] <= 1'b0;
end
end
default: begin // supports valid "3'b001" case and all invalid cases
f_wrreq[0] <= 1'b0;
f_wrreq[1] <= 1'b0;
end
endcase
if( wr_ptr ) begin
f_wrdata[0][WIDTH-1:0] <= id1[WIDTH-1:0];
f_wrdata[1][WIDTH-1:0] <= id0[WIDTH-1:0];
end else begin
f_wrdata[0][WIDTH-1:0] <= id0[WIDTH-1:0];
f_wrdata[1][WIDTH-1:0] <= id1[WIDTH-1:0];
end
end
always_ff @(posedge clk) begin
if( ~nrst ) begin
wr_ptr = 1'b0;
end else begin
if( wr_ptr ) begin
if( wrreq[2:0] == 3'b010 && w1_valid ) begin
wr_ptr = ~wr_ptr;
end
end else begin
if( wrreq[2:0] == 3'b010 && w0_valid ) begin
wr_ptr = ~wr_ptr;
end
end
end // nrst
end
// reading internal FIFOs ======================================================
always_comb begin
case( rdreq[2:0] )
3'b010: begin
if( rd_ptr ) begin
f_rdreq[0] <= 1'b0;
if( r1_valid ) begin // protecting from underflow
f_rdreq[1] <= 1'b1;
end else begin
f_rdreq[1] <= 1'b0;
end
end else begin
if( r0_valid ) begin // protecting from underflow
f_rdreq[0] <= 1'b1;
end else begin
f_rdreq[0] <= 1'b0;
end
f_rdreq[1] <= 1'b0;
end
end
3'b100: begin
if( r2_valid ) begin // protecting from underflow
f_rdreq[0] <= 1'b1;
f_rdreq[1] <= 1'b1;
end else begin
f_rdreq[0] <= 1'b0;
f_rdreq[1] <= 1'b0;
end
end
default: begin
f_rdreq[0] <= 1'b0;
f_rdreq[1] <= 1'b0;
end
endcase
if( rd_ptr ) begin
od0[WIDTH-1:0] <= f_rddata[1][WIDTH-1:0];
od1[WIDTH-1:0] <= f_rddata[0][WIDTH-1:0];
end else begin
od0[WIDTH-1:0] <= f_rddata[0][WIDTH-1:0];
od1[WIDTH-1:0] <= f_rddata[1][WIDTH-1:0];
end
end
always_ff @(posedge clk) begin
if( ~nrst ) begin
rd_ptr = 1'b0;
end else begin
if( rd_ptr ) begin
if( rdreq[2:0] == 3'b010 && r1_valid ) begin
rd_ptr = ~rd_ptr;
end
end else begin
if( rdreq[2:0] == 3'b010 && r0_valid ) begin
rd_ptr = ~rd_ptr;
end
end
end // nrst
end
// internal FIFOs itself =======================================================
logic [1:0][USED_W-2:0] f_usedw_i;
logic [1:0][USED_W-1:0] f_usedw;
scfifo #(
.LPM_WIDTH( WIDTH ),
.LPM_NUMWORDS( DEPTH/2 ), // must be at least 4
.LPM_WIDTHU( USED_W-1 ),
.LPM_SHOWAHEAD( "ON" ),
.UNDERFLOW_CHECKING( "ON" ),
.OVERFLOW_CHECKING( "ON" ),
.ENABLE_ECC( "FALSE" ),
.ALLOW_RWCYCLE_WHEN_FULL( "ON" ),
.USE_EAB( "ON" )
) internal_fifo0 (
.clock( clk ),
.aclr( 1'b0 ),
.sclr( ~nrst ),
.data( f_wrdata[0][WIDTH-1:0] ),
.wrreq( f_wrreq[0] ),
.rdreq( f_rdreq[0] ),
.q( f_rddata[0][WIDTH-1:0] ),
.empty( empty[0] ),
.full( full[0] ),
.usedw( f_usedw_i[0][USED_W-2:0] )
);
scfifo #(
.LPM_WIDTH( WIDTH ),
.LPM_NUMWORDS( DEPTH/2 ), // must be at least 4
.LPM_WIDTHU( USED_W-1 ),
.LPM_SHOWAHEAD( "ON" ),
.UNDERFLOW_CHECKING( "ON" ),
.OVERFLOW_CHECKING( "ON" ),
.ENABLE_ECC( "FALSE" ),
.ALLOW_RWCYCLE_WHEN_FULL( "ON" ),
.USE_EAB( "ON" )
) internal_fifo1 (
.clock( clk ),
.aclr( 1'b0 ),
.sclr( ~nrst ),
.data( f_wrdata[1][WIDTH-1:0] ),
.wrreq( f_wrreq[1] ),
.rdreq( f_rdreq[1] ),
.q( f_rddata[1][WIDTH-1:0] ),
.empty( empty[1] ),
.full( full[1] ),
.usedw( f_usedw_i[1][USED_W-2:0] )
);
always_comb begin
f_usedw[0][USED_W-1:0] = ( full[0] )?
( 1<<(USED_W-1) ):
( {1'b0,f_usedw_i[0][USED_W-2:0]} );
f_usedw[1][USED_W-1:0] = ( full[1] )?
( 1<<(USED_W-1) ):
( {1'b0,f_usedw_i[1][USED_W-2:0]} );
usedw[USED_W:0] = f_usedw[0][USED_W-1:0] + f_usedw[1][USED_W-1:0];
end
endmodule