mirror of
https://github.com/pConst/basic_verilog.git
synced 2025-01-14 06:42:54 +08:00
292 lines
8.1 KiB
Systemverilog
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
|
|
|
|
|