1
0
mirror of https://github.com/pConst/basic_verilog.git synced 2025-01-28 07:02:55 +08:00

Done fifo initialization

This commit is contained in:
Konstantin Pavlov 2022-04-25 01:06:34 +03:00
parent 66ff427e1e
commit a6aa3c3893
10 changed files with 452 additions and 243 deletions

View File

@ -1,5 +1,6 @@
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// fifo_single_clock_ram.sv // fifo_single_clock_ram.sv
// published as part of https://github.com/pConst/basic_verilog
// Konstantin Pavlov, pavlovconst@gmail.com // Konstantin Pavlov, pavlovconst@gmail.com
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -15,15 +16,23 @@
// - configurable depth and data width // - configurable depth and data width
// - only "normal" mode is supported here, no FWFT mode // - only "normal" mode is supported here, no FWFT mode
// - protected against overflow and underflow // - protected against overflow and underflow
// - simultaneous read and write operations supported BUT:
// only read will happen if simultaneous rw from full fifo
// only write will happen if simultaneous rw from empty fifo
// Always honor empty and full flags!
// - provides fifo contents initialization (!) // - provides fifo contents initialization (!)
// // - CAUTION! block RAMs do NOT support fifo contents REinitialization after reset
/* --- INSTANTIATION TEMPLATE BEGIN --- /* --- INSTANTIATION TEMPLATE BEGIN ---
fifo_single_clock_ram #( fifo_single_clock_ram #(
.DEPTH( 8 ), .DEPTH( 8 ),
.DATA_W( 32 ) .DATA_W( 32 ),
// optional initialization
.INIT_FILE( "fifo_single_clock_ram_init.mem" ),
.INIT_CNT( 10 )
) FF1 ( ) FF1 (
.clk( clk ), .clk( clk ),
.nrst( 1'b1 ), .nrst( 1'b1 ),
@ -43,19 +52,23 @@ fifo_single_clock_ram #(
module fifo_single_clock_ram #( parameter module fifo_single_clock_ram #( parameter
//FWFT_MODE = "TRUE", // "TRUE" - first word fall-trrough" mode FWFT_MODE = "TRUE", // "TRUE" - first word fall-trrough" mode
// "FALSE" - normal fifo mode // "FALSE" - normal fifo mode
DEPTH = 8, // max elements count == DEPTH, DEPTH MUST be power of 2
DEPTH_W = clogb2(DEPTH)+1, // elements counter width, extra bit to store
// "fifo full" state, see cnt[] variable comments
DEPTH = 8, // max elements count == DEPTH, DEPTH MUST be power of 2 DATA_W = 32, // data field width
DEPTH_W = $clog2(DEPTH)+1, // elements counter width, extra bit to store
// "fifo full" state, see cnt[] variable comments
DATA_W = 32, // data field width RAM_STYLE = "", // "block","register","M10K","logic",...
INIT_FILE = ""
// optional initialization
INIT_FILE = "", // .HEX or .MEM file to initialize fifo contents
INIT_CNT = '0 // sets desired initial cnt[]
)( )(
input clk, input clk,
input nrst, // inverted reset input nrst, // inverted reset
// input port // input port
input w_req, input w_req,
@ -66,7 +79,7 @@ module fifo_single_clock_ram #( parameter
output [DATA_W-1:0] r_data, output [DATA_W-1:0] r_data,
// helper ports // helper ports
output logic [DEPTH_W-1:0] cnt = '0, output logic [DEPTH_W-1:0] cnt = INIT_CNT[DEPTH_W-1:0],
output logic empty, output logic empty,
output logic full, output logic full,
@ -74,83 +87,99 @@ module fifo_single_clock_ram #( parameter
); );
// read and write pointers // read and write pointers
logic [DEPTH_W-1:0] w_ptr = '0; logic [DEPTH_W-1:0] w_ptr = INIT_CNT[DEPTH_W-1:0];
logic [DEPTH_W-1:0] r_ptr = '0; logic [DEPTH_W-1:0] r_ptr = '0;
// filtered requests // filtered requests
logic w_req_f; logic w_req_f;
assign w_req_f = w_req && ~full; assign w_req_f = w_req && ~full;
logic r_req_f; logic r_req_f;
assign r_req_f = r_req && ~empty; assign r_req_f = r_req && ~empty;
true_dual_port_write_first_2_clock_ram #( true_dual_port_write_first_2_clock_ram #(
.RAM_WIDTH( DATA_W ), .RAM_WIDTH( DATA_W ),
.RAM_DEPTH( DEPTH ), .RAM_DEPTH( DEPTH ),
.INIT_FILE( INIT_FILE ) .RAM_STYLE( RAM_STYLE ), // "block","register","M10K","logic",...
) data_ram ( .INIT_FILE( INIT_FILE )
.clka( clk ), ) data_ram (
.addra( w_ptr[DEPTH_W-1:0] ), .clka( clk ),
.ena( w_req_f ), .addra( w_ptr[DEPTH_W-1:0] ),
.wea( 1'b1 ), .ena( w_req_f ),
.dina( w_data[DATA_W-1:0] ), .wea( 1'b1 ),
.douta( ), .dina( w_data[DATA_W-1:0] ),
.douta( ),
.clkb( clk ), .clkb( clk ),
.addrb( r_ptr[DEPTH_W-1:0] ), .addrb( r_ptr[DEPTH_W-1:0] ),
.enb( r_req_f ), .enb( r_req_f ),
.web( 1'b0 ), .web( 1'b0 ),
.dinb( '0 ), .dinb( '0 ),
.doutb( r_data[DATA_W-1:0] ) .doutb( r_data[DATA_W-1:0] )
); );
function [DEPTH_W-1:0] inc_ptr ( always_ff @(posedge clk) begin
input [DEPTH_W-1:0] ptr if ( ~nrst ) begin
); w_ptr[DEPTH_W-1:0] <= '0;
r_ptr[DEPTH_W-1:0] <= '0;
if( ptr[DEPTH_W-1:0] == DEPTH-1 ) begin cnt[DEPTH_W-1:0] <= '0;
inc_ptr[DEPTH_W-1:0] = '0; end else begin
end else begin unique case ({w_req, r_req})
inc_ptr[DEPTH_W-1:0] = ptr[DEPTH_W-1:0] + 1'b1; 2'b00: ; // nothing
2'b01: begin // reading out
if( ~empty ) begin
r_ptr[DEPTH_W-1:0] <= inc_ptr(r_ptr[DEPTH_W-1:0]);
cnt[DEPTH_W-1:0] <= cnt[DEPTH_W-1:0] - 1'b1;
end
end
2'b10: begin // writing in
if( ~full ) begin
w_ptr[DEPTH_W-1:0] <= inc_ptr(w_ptr[DEPTH_W-1:0]);
cnt[DEPTH_W-1:0] <= cnt[DEPTH_W-1:0] + 1'b1;
end
end
2'b11: begin // simultaneously reading and writing
if( empty ) begin
w_ptr[DEPTH_W-1:0] <= inc_ptr(w_ptr[DEPTH_W-1:0]);
cnt[DEPTH_W-1:0] <= cnt[DEPTH_W-1:0] + 1'b1;
end else if( full ) begin
r_ptr[DEPTH_W-1:0] <= inc_ptr(r_ptr[DEPTH_W-1:0]);
cnt[DEPTH_W-1:0] <= cnt[DEPTH_W-1:0] - 1'b1;
end else begin
w_ptr[DEPTH_W-1:0] <= inc_ptr(w_ptr[DEPTH_W-1:0]);
r_ptr[DEPTH_W-1:0] <= inc_ptr(r_ptr[DEPTH_W-1:0]);
//cnt[DEPTH_W-1:0] <= // data counter does not change here
end
end
endcase
end
end end
endfunction
always_comb begin
empty = ( cnt[DEPTH_W-1:0] == '0 );
full = ( cnt[DEPTH_W-1:0] == DEPTH );
always_ff @(posedge clk) begin fail = ( empty && r_req ) ||
if ( ~nrst ) begin ( full && w_req );
w_ptr[DEPTH_W-1:0] <= '0;
r_ptr[DEPTH_W-1:0] <= '0;
cnt[DEPTH_W-1:0] <= '0;
end else begin
if( w_req_f ) begin
w_ptr[DEPTH_W-1:0] <= inc_ptr(w_ptr[DEPTH_W-1:0]);
end
if( r_req_f ) begin
r_ptr[DEPTH_W-1:0] <= inc_ptr(r_ptr[DEPTH_W-1:0]);
end
if( w_req_f && ~r_req_f ) begin
cnt[DEPTH_W-1:0] <= cnt[DEPTH_W-1:0] + 1'b1;
end else if( ~w_req_f && r_req_f ) begin
cnt[DEPTH_W-1:0] <= cnt[DEPTH_W-1:0] - 1'b1;
end
end end
end
always_comb begin function [DEPTH_W-1:0] inc_ptr (
empty = ( cnt[DEPTH_W-1:0] == '0 ); input [DEPTH_W-1:0] ptr
full = ( cnt[DEPTH_W-1:0] == DEPTH ); );
if( ptr[DEPTH_W-1:0] == DEPTH-1 ) begin
inc_ptr[DEPTH_W-1:0] = '0;
end else begin
inc_ptr[DEPTH_W-1:0] = ptr[DEPTH_W-1:0] + 1'b1;
end
endfunction
fail = ( empty && r_req ) || `include "clogb2.svh"
( full && w_req );
end
endmodule endmodule

32
fifo_single_clock_ram_init.mem Executable file
View File

@ -0,0 +1,32 @@
ABCD
A001
A002
A003
A004
A005
A006
A007
A008
A009
A00A
A00B
A00C
A00D
A00E
A00F
A001
A002
A001
A002
A001
A002
A001
A002
A001
A002
A001
A002
A001
A002
A001
A002

View File

@ -4,7 +4,7 @@
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// INFO ------------------------------------------------------------------------ // INFO ------------------------------------------------------------------------
// testbench for fifo_single_clock_reg_ram.sv module // testbench for fifo_single_clock_ram.sv module
// //
`timescale 1ns / 1ps `timescale 1ns / 1ps
@ -89,15 +89,19 @@ end
// Module under test ========================================================== // Module under test ==========================================================
// comment or uncomment to test FWFT and normal fifo modes // comment or uncomment to test FWFT and normal fifo modes
//`define TEST_FWFT yes //`define TEST_FWFT yes
// comment or uncomment to sweep-test or random test // comment or uncomment to sweep-test or random test
`define TEST_SWEEP yes //`define TEST_SWEEP yes
// comment or uncomment to use bare scfifo or quartus wizard-generated wrappers // comment or uncomment to use bare scfifo or quartus wizard-generated wrappers
//`define BARE_SCFIFO yes //`define BARE_SCFIFO yes
// initialization is not supported for Altera fifo
//`define TEST_INIT yes
logic full1, empty1; logic full1, empty1;
logic full1_d1, empty1_d1; logic full1_d1, empty1_d1;
@ -124,11 +128,29 @@ end
logic [3:0] cnt1; logic [3:0] cnt1;
logic [15:0] data_out1; logic [15:0] data_out1;
fifo_single_clock_ram #( fifo_single_clock_ram #(
`ifdef TEST_FWFT
.FWFT_MODE( "TRUE" ),
`else
.FWFT_MODE( "FALSE" ),
`endif
.DEPTH( 8 ), .DEPTH( 8 ),
.DATA_W( 16 ) .DATA_W( 16 ),
.RAM_STYLE( "logic" )
`ifdef TEST_INIT
,
// optional initialization
.INIT_FILE( "fifo_single_clock_ram_init.mem" ),
.INIT_CNT( 10 )
`endif
) FF1 ( ) FF1 (
.clk( clk200 ), .clk( clk200 ),
`ifdef TEST_INIT
.nrst( 1'b1 ),
`else
.nrst( nrst_once ), .nrst( nrst_once ),
`endif
`ifdef TEST_SWEEP `ifdef TEST_SWEEP
.w_req( ~direction1 && &RandomNumber1[10] ), .w_req( ~direction1 && &RandomNumber1[10] ),
@ -177,8 +199,9 @@ end
//============================================================================== //==============================================================================
logic [15:0] data_out2; logic [15:0] data_out2;
`ifdef BARE_SCFIFO
DCFIFO #( SCFIFO #(
.LPM_WIDTH( 16 ), .LPM_WIDTH( 16 ),
.LPM_NUMWORDS( 8 ), .LPM_NUMWORDS( 8 ),
.LPM_WIDTHU( $clog2(8) ), /// CEIL(LOG2(LPM_NUMWORDS)), .LPM_WIDTHU( $clog2(8) ), /// CEIL(LOG2(LPM_NUMWORDS)),
@ -190,23 +213,12 @@ logic [15:0] data_out2;
`endif `endif
.UNDERFLOW_CHECKING( "ON" ), .UNDERFLOW_CHECKING( "ON" ),
.OVERFLOW_CHECKING( "ON" ), .OVERFLOW_CHECKING( "ON" ),
.ALLOW_RWCYCLE_WHEN_FULL( "ON" ),
.ADD_RAM_OUTPUT_REGISTER( "OFF" ), .ADD_RAM_OUTPUT_REGISTER( "OFF" ),
.ENABLE_ECC( "FALSE" ),
// output delay to the usedw[] outputs .ALMOST_FULL_VALUE( 0 ),
.DELAY_RDUSEDW( 1 ), // one clock cycle by default .ALMOST_EMPTY_VALUE( 0 ),
.DELAY_WRUSEDW( 1 ), .ENABLE_ECC( "FALSE" )
// Pipe length used for synchronization and metastability resolving
// If the rdclk and wrclk are unrelated, most often used values range from 2 to 4
// If they are syncronized to one another, 0 might be used
.RDSYNC_DELAYPIPE( 3 ), // from the wrclk to the rdclk subsystem
.WRSYNC_DELAYPIPE( 3 ), // from the rdclk to the wrclk subsystem
.CLOCKS_ARE_SYNCHRONIZED( "TRUE" ), // Are the clocks sufficiently synchronized (or clock multiples of each other with no pashe shift)
// such that the synchronization and pipeline registers may be elliminated
.ADD_USEDW_MSB_BIT( "ON" ),
.WRITE_ACLR_SYNCH( "OFF" ),
.READ_ACLR_SYNCH( "OFF" )
//.USE_EAB( "ON" ), //.USE_EAB( "ON" ),
//.MAXIMIZE_SPEED( 5 ), //.MAXIMIZE_SPEED( 5 ),
@ -214,35 +226,63 @@ logic [15:0] data_out2;
//.OPTIMIZE_FOR_SPEED( 5 ), //.OPTIMIZE_FOR_SPEED( 5 ),
//.CBXI_PARAMETER( "NOTHING" ) //.CBXI_PARAMETER( "NOTHING" )
) FF2 ( ) FF2 (
.clock( clk200 ),
.aclr( 1'b0 ), .aclr( 1'b0 ),
.sclr( ~nrst_once ),
.wrclk( clk200 ),
`ifdef TEST_SWEEP `ifdef TEST_SWEEP
.wrreq( ~direction1 && &RandomNumber1[10] ), .wrreq( ~direction1 && &RandomNumber1[10] ),
.data( RandomNumber1[15:0] ), .data( RandomNumber1[15:0] ),
`else
.wrreq( &RandomNumber1[10:9] ),
.data( RandomNumber1[15:0] ),
`endif
.wrempty( ),
.wrfull( ),
.wrusedw( ),
.rdclk( clk200 ),
`ifdef TEST_SWEEP
.rdreq( direction1 && &RandomNumber1[10] ), .rdreq( direction1 && &RandomNumber1[10] ),
.q( data_out2[15:0] ), .q( data_out2[15:0] ),
`else `else
.wrreq( &RandomNumber1[10:9] ),
.data( RandomNumber1[15:0] ),
.rdreq( &RandomNumber1[8:7] ), .rdreq( &RandomNumber1[8:7] ),
.q( data_out2[15:0] ), .q( data_out2[15:0] ),
`endif `endif
.rdempty( empty2 ),
.rdfull( full2 ), .empty( empty2 ),
.rdusedw( ), .full( full2 ),
.almost_empty( ),
.almost_full( ),
.usedw( ),
.eccstatus( ) .eccstatus( )
); );
`else
`ifdef TEST_FWFT
altera_fifo FF2 (
`else
altera_fifo_normal FF2 (
`endif
.clock ( clk200 ),
`ifdef TEST_SWEEP
.wrreq( ~direction1 && &RandomNumber1[10] ),
.data( RandomNumber1[15:0] ),
.rdreq( direction1 && &RandomNumber1[10] ),
.q( data_out2[15:0] ),
`else
.wrreq( &RandomNumber1[10:9] ),
.data( RandomNumber1[15:0] ),
.rdreq( &RandomNumber1[8:7] ),
.q( data_out2[15:0] ),
`endif
.empty ( empty2 ),
.full ( full2 ),
.usedw ( )
);
`endif
//============================================================================== //==============================================================================
@ -273,5 +313,9 @@ always_ff @(posedge clk200) begin
end end
end end
// this condition is being processed differently by altera`s scfifo and
// the custom fifo implementation
logic test_cond;
assign test_cond = empty1 && &RandomNumber1[10:9] && &RandomNumber1[8:7];
endmodule endmodule

View File

@ -16,9 +16,10 @@
// - configurable depth and data width // - configurable depth and data width
// - one write- and one read- port in "FWFT" or "normal" mode // - one write- and one read- port in "FWFT" or "normal" mode
// - protected against overflow and underflow // - protected against overflow and underflow
// - simultaneous read and write operations supported if not full and not empty // - simultaneous read and write operations supported BUT:
// - only read operation is performed when (full && r_req && w_req) // only read will happen if simultaneous rw from full fifo
// - only write operation is performed when (empty && r_req && w_req) // only write will happen if simultaneous rw from empty fifo
// Always honor empty and full flags!
// - (new!) optional fifo contents initialization // - (new!) optional fifo contents initialization
// //
// See also "lifo.sv" module for similar LIFO buffer implementation // See also "lifo.sv" module for similar LIFO buffer implementation
@ -110,15 +111,6 @@ module fifo_single_clock_reg_v1 #( parameter
// cnt[] vector always holds fifo elements count // cnt[] vector always holds fifo elements count
// data[cnt[]] points to the first empty fifo slot // data[cnt[]] points to the first empty fifo slot
// when fifo is full data[cnt[]] points "outside" of data[] // when fifo is full data[cnt[]] points "outside" of data[]
// filtered requests
logic w_req_f;
assign w_req_f = w_req && ~full;
logic r_req_f;
assign r_req_f = r_req && ~empty;
always_ff @(posedge clk) begin always_ff @(posedge clk) begin
integer i; integer i;
if ( ~nrst ) begin if ( ~nrst ) begin
@ -131,34 +123,49 @@ module fifo_single_clock_reg_v1 #( parameter
end end
data_buf[DATA_W-1:0] <= '0; data_buf[DATA_W-1:0] <= '0;
end else begin end else begin
unique case ({w_req_f, r_req_f}) unique case ({w_req, r_req})
2'b00: ; // nothing 2'b00: ; // nothing
2'b01: begin // reading out 2'b01: begin // reading out
for ( i = (DEPTH-1); i > 0; i=i-1 ) begin if( ~empty ) begin
data[i-1] <= data[i]; for ( i = (DEPTH-1); i > 0; i=i-1 ) begin
data[i-1] <= data[i];
end
cnt[DEPTH_W-1:0] <= cnt[DEPTH_W-1:0] - 1'b1;
data_buf[DATA_W-1:0] <= data[0];
end end
cnt[DEPTH_W-1:0] <= cnt[DEPTH_W-1:0] - 1'b1;
end end
2'b10: begin // writing in 2'b10: begin // writing in
data[cnt[DEPTH_W-1:0]] <= w_data[DATA_W-1:0]; if( ~full ) begin
cnt[DEPTH_W-1:0] <= cnt[DEPTH_W-1:0] + 1'b1; data[cnt[DEPTH_W-1:0]] <= w_data[DATA_W-1:0];
cnt[DEPTH_W-1:0] <= cnt[DEPTH_W-1:0] + 1'b1;
end
end end
2'b11: begin // simultaneously reading and writing 2'b11: begin // simultaneously reading and writing
for ( i = (DEPTH-1); i > 0; i=i-1 ) begin if( empty ) begin
data[i-1] <= data[i]; data[cnt[DEPTH_W-1:0]] <= w_data[DATA_W-1:0];
cnt[DEPTH_W-1:0] <= cnt[DEPTH_W-1:0] + 1'b1;
end else if( full ) begin
for ( i = (DEPTH-1); i > 0; i=i-1 ) begin
data[i-1] <= data[i];
end
cnt[DEPTH_W-1:0] <= cnt[DEPTH_W-1:0] - 1'b1;
data_buf[DATA_W-1:0] <= data[0];
end else begin
for ( i = (DEPTH-1); i > 0; i=i-1 ) begin
if( i == cnt[DEPTH_W-1:0] ) begin
data[i-1] <= w_data[DATA_W-1:0];
end else begin
data[i-1] <= data[i];
end
end
//cnt[DEPTH_W-1:0] <= // data counter does not change here
data_buf[DATA_W-1:0] <= data[0];
end end
data[cnt[DEPTH_W-1:0]-1] <= w_data[DATA_W-1:0];
// data counter does not change here
end end
endcase endcase
// data buffer works only for normal fifo mode
if( r_req_f ) begin
data_buf[DATA_W-1:0] <= data[0];
end
end end
end end
@ -166,14 +173,14 @@ module fifo_single_clock_reg_v1 #( parameter
empty = ( cnt[DEPTH_W-1:0] == '0 ); empty = ( cnt[DEPTH_W-1:0] == '0 );
full = ( cnt[DEPTH_W-1:0] == DEPTH ); full = ( cnt[DEPTH_W-1:0] == DEPTH );
if( FWFT_MODE == "TRUE" ) begin if( FWFT_MODE == "TRUE" ) begin // first-word fall-through mode
if( ~empty ) begin if( ~empty ) begin
r_data[DATA_W-1:0] = data[0]; // first-word fall-through mode r_data[DATA_W-1:0] = data[0];
end else begin end else begin
r_data[DATA_W-1:0] = '0; r_data[DATA_W-1:0] = '0;
end end
end else begin end else begin // normal mode
r_data[DATA_W-1:0] = data_buf[DATA_W-1:0]; // normal mode r_data[DATA_W-1:0] = data_buf[DATA_W-1:0];
end end
fail = ( empty && r_req ) || fail = ( empty && r_req ) ||

View File

@ -100,7 +100,7 @@ end
//`define BARE_SCFIFO yes //`define BARE_SCFIFO yes
// initialization is not supported for Altera fifo // initialization is not supported for Altera fifo
`define TEST_INIT yes //`define TEST_INIT yes
logic full1, empty1; logic full1, empty1;
logic full1_d1, empty1_d1; logic full1_d1, empty1_d1;
@ -134,9 +134,10 @@ fifo_single_clock_reg_v1 #(
.FWFT_MODE( "FALSE" ), .FWFT_MODE( "FALSE" ),
`endif `endif
.DEPTH( 8 ), .DEPTH( 8 ),
.DATA_W( 16 ), .DATA_W( 16 )
`ifdef TEST_INIT `ifdef TEST_INIT
,
// optional initialization // optional initialization
.USE_INIT_FILE( "TRUE" ), .USE_INIT_FILE( "TRUE" ),
.INIT_CNT( 10 ) .INIT_CNT( 10 )

View File

@ -1,19 +1,26 @@
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// fifo_single_clock_reg_v2.sv // fifo_single_clock_reg_v2.sv
// published as part of https://github.com/pConst/basic_verilog
// Konstantin Pavlov, pavlovconst@gmail.com // Konstantin Pavlov, pavlovconst@gmail.com
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// INFO ------------------------------------------------------------------------ // INFO ------------------------------------------------------------------------
// Single-clock FIFO buffer implementation, also known as "queue" // Single-clock FIFO buffer implementation, also known as "queue"
// //
// I`ve made two variants of fifo_single_clock_reg module - v1 and v2
// Both variants are valid, both operate identically from an outside observer`s
// view. Only internal r/w pointers operation is different.
//
// Features: // Features:
// - single clock operation // - single clock operation
// - configurable depth and data width // - configurable depth and data width
// - one write- and one read- port in "FWFT" or "normal" mode // - one write- and one read- port in "FWFT" or "normal" mode
// - protected against overflow and underflow // - protected against overflow and underflow
// - simultaneous read and write operations supported if not full and not empty // - simultaneous read and write operations supported BUT:
// - only read operation is performed when (full && r_req && w_req) // only read will happen if simultaneous rw from full fifo
// - only write operation is performed when (empty && r_req && w_req) // only write will happen if simultaneous rw from empty fifo
// Always honor empty and full flags!
// - (new!) optional fifo contents initialization
// //
// See also "lifo.sv" module for similar LIFO buffer implementation // See also "lifo.sv" module for similar LIFO buffer implementation
@ -23,7 +30,11 @@
fifo_single_clock_reg_v2 #( fifo_single_clock_reg_v2 #(
.FWFT_MODE( "TRUE" ), .FWFT_MODE( "TRUE" ),
.DEPTH( 8 ), .DEPTH( 8 ),
.DATA_W( 32 ) .DATA_W( 32 ),
// optional initialization
.INIT_FILE( "fifo_single_clock_reg_v2_init.svh" ),
.INIT_CNT( 10 )
) FF1 ( ) FF1 (
.clk( clk ), .clk( clk ),
.nrst( 1'b1 ), .nrst( 1'b1 ),
@ -45,16 +56,19 @@ module fifo_single_clock_reg_v2 #( parameter
FWFT_MODE = "TRUE", // "TRUE" - first word fall-trrough" mode FWFT_MODE = "TRUE", // "TRUE" - first word fall-trrough" mode
// "FALSE" - normal fifo mode // "FALSE" - normal fifo mode
DEPTH = 8, // max elements count == DEPTH, DEPTH MUST be power of 2 DEPTH = 8, // max elements count == DEPTH, DEPTH MUST be power of 2
DEPTH_W = $clog2(DEPTH)+1, // elements counter width, extra bit to store DEPTH_W = clogb2(DEPTH)+1, // elements counter width, extra bit to store
// "fifo full" state, see cnt[] variable comments // "fifo full" state, see cnt[] variable comments
DATA_W = 32 // data field width DATA_W = 32, // data field width
)(
// optional initialization
USE_INIT_FILE = "FALSE", // "TRUE" - uses special filethat provides init data
// "FALSE" - initializes with '0
INIT_CNT = '0 // sets desired initial cnt[]
)(
input clk, input clk,
input nrst, // inverted reset input nrst, // inverted reset
// input port // input port
input w_req, input w_req,
@ -65,111 +79,131 @@ module fifo_single_clock_reg_v2 #( parameter
output logic [DATA_W-1:0] r_data, output logic [DATA_W-1:0] r_data,
// helper ports // helper ports
output logic [DEPTH_W-1:0] cnt = '0, output logic [DEPTH_W-1:0] cnt,
output logic empty, output logic empty,
output logic full, output logic full,
output logic fail output logic fail
); );
// fifo data, extra element to keep pointer positions always valid, // fifo data
// even when fifo is empty or full logic [DEPTH-1:0][DATA_W-1:0] data;
logic [DEPTH-1:0][DATA_W-1:0] data = '0;
// read and write pointers // read and write pointers
logic [DEPTH_W-1:0] w_ptr = '0; logic [DEPTH_W-1:0] w_ptr;
logic [DEPTH_W-1:0] r_ptr = '0; logic [DEPTH_W-1:0] r_ptr;
// data output buffer for normal fifo mode // fofo initialization
logic [DATA_W-1:0] data_buf = '0; // Modelsim gives suppressable error here
// "(vlog-7061) Variable 'data' driven in an always_ff block, may not be driven by any other process"
generate
// filtered requests initial begin
logic w_req_f; if( USE_INIT_FILE ) begin
assign w_req_f = w_req && ~full; `include "fifo_single_clock_reg_v2_init.svh"
w_ptr[DEPTH_W-1:0] <= INIT_CNT[DEPTH_W-1:0];
logic r_req_f; r_ptr[DEPTH_W-1:0] <= '0;
assign r_req_f = r_req && ~empty; cnt[DEPTH_W-1:0] <= INIT_CNT[DEPTH_W-1:0];
end else begin
data <= '0;
function [DEPTH_W-1:0] inc_ptr ( w_ptr[DEPTH_W-1:0] <= '0;
input [DEPTH_W-1:0] ptr r_ptr[DEPTH_W-1:0] <= '0;
); cnt[DEPTH_W-1:0] <= '0;
if( ptr[DEPTH_W-1:0] == DEPTH-1 ) begin
inc_ptr[DEPTH_W-1:0] = '0;
end else begin
inc_ptr[DEPTH_W-1:0] = ptr[DEPTH_W-1:0] + 1'b1;
end
endfunction
integer i;
always_ff @(posedge clk) begin
if ( ~nrst ) begin
data <= '0;
cnt[DEPTH_W-1:0] <= '0;
w_ptr[DEPTH_W-1:0] <= '0;
r_ptr[DEPTH_W-1:0] <= '0;
data_buf[DATA_W-1:0] <= '0;
end else begin
unique case ({w_req_f, r_req_f})
2'b00: ; // nothing
2'b01: begin // reading out
if( ~empty ) begin
r_ptr[DEPTH_W-1:0] <= inc_ptr(r_ptr[DEPTH_W-1:0]);
end
cnt[DEPTH_W-1:0] <= cnt[DEPTH_W-1:0] - 1'b1;
end end
end // initial
endgenerate
2'b10: begin // writing in
if( ~full ) begin // data output buffer for normal fifo mode
w_ptr[DEPTH_W-1:0] <= inc_ptr(w_ptr[DEPTH_W-1:0]); logic [DATA_W-1:0] data_buf = '0;
end
data[w_ptr[DEPTH_W-1:0]] <= w_data[DATA_W-1:0]; always_ff @(posedge clk) begin
cnt[DEPTH_W-1:0] <= cnt[DEPTH_W-1:0] + 1'b1; integer i;
if ( ~nrst ) begin
if( USE_INIT_FILE ) begin
`include "fifo_single_clock_reg_v2_init.svh"
w_ptr[DEPTH_W-1:0] <= INIT_CNT[DEPTH_W-1:0];
r_ptr[DEPTH_W-1:0] <= '0;
cnt[DEPTH_W-1:0] <= INIT_CNT[DEPTH_W-1:0];
end else begin
data <= '0;
w_ptr[DEPTH_W-1:0] <= '0;
r_ptr[DEPTH_W-1:0] <= '0;
cnt[DEPTH_W-1:0] <= '0;
end end
data_buf[DATA_W-1:0] <= '0;
2'b11: begin // simultaneously reading and writing
if( ~empty ) begin
r_ptr[DEPTH_W-1:0] <= inc_ptr(r_ptr[DEPTH_W-1:0]);
end
if( ~full ) begin
w_ptr[DEPTH_W-1:0] <= inc_ptr(w_ptr[DEPTH_W-1:0]);
end
data[w_ptr[DEPTH_W-1:0]] <= w_data[DATA_W-1:0];
// data counter does not change here
end
endcase
// data buffer works only for normal fifo mode
if( r_req_f ) begin
data_buf[DATA_W-1:0] <= data[r_ptr[DEPTH_W-1:0]];
end
end
end
always_comb begin
empty = ( cnt[DEPTH_W-1:0] == '0 );
full = ( cnt[DEPTH_W-1:0] == DEPTH );
if( FWFT_MODE == "TRUE" ) begin
if (~empty) begin
r_data[DATA_W-1:0] = data[r_ptr[DEPTH_W-1:0]]; // first-word fall-through mode
end else begin end else begin
r_data[DATA_W-1:0] = '0; unique case ({w_req, r_req})
2'b00: ; // nothing
2'b01: begin // reading out
if( ~empty ) begin
r_ptr[DEPTH_W-1:0] <= inc_ptr(r_ptr[DEPTH_W-1:0]);
cnt[DEPTH_W-1:0] <= cnt[DEPTH_W-1:0] - 1'b1;
data_buf[DATA_W-1:0] <= data[r_ptr[DEPTH_W-1:0]];
end
end
2'b10: begin // writing in
if( ~full ) begin
w_ptr[DEPTH_W-1:0] <= inc_ptr(w_ptr[DEPTH_W-1:0]);
data[w_ptr[DEPTH_W-1:0]] <= w_data[DATA_W-1:0];
cnt[DEPTH_W-1:0] <= cnt[DEPTH_W-1:0] + 1'b1;
end
end
2'b11: begin // simultaneously reading and writing
if( empty ) begin
w_ptr[DEPTH_W-1:0] <= inc_ptr(w_ptr[DEPTH_W-1:0]);
data[w_ptr[DEPTH_W-1:0]] <= w_data[DATA_W-1:0];
cnt[DEPTH_W-1:0] <= cnt[DEPTH_W-1:0] + 1'b1;
end else if( full ) begin
r_ptr[DEPTH_W-1:0] <= inc_ptr(r_ptr[DEPTH_W-1:0]);
cnt[DEPTH_W-1:0] <= cnt[DEPTH_W-1:0] - 1'b1;
data_buf[DATA_W-1:0] <= data[r_ptr[DEPTH_W-1:0]];
end else begin
w_ptr[DEPTH_W-1:0] <= inc_ptr(w_ptr[DEPTH_W-1:0]);
data[w_ptr[DEPTH_W-1:0]] <= w_data[DATA_W-1:0];
//cnt[DEPTH_W-1:0] <= // data counter does not change here
r_ptr[DEPTH_W-1:0] <= inc_ptr(r_ptr[DEPTH_W-1:0]);
//cnt[DEPTH_W-1:0] <= // data counter does not change here
data_buf[DATA_W-1:0] <= data[r_ptr[DEPTH_W-1:0]];
end
end
endcase
end end
end else begin
r_data[DATA_W-1:0] = data_buf[DATA_W-1:0]; // normal mode
end end
fail = ( empty && r_req ) || always_comb begin
( full && w_req ); empty = ( cnt[DEPTH_W-1:0] == '0 );
end full = ( cnt[DEPTH_W-1:0] == DEPTH );
if( FWFT_MODE == "TRUE" ) begin // first-word fall-through mode
if( ~empty ) begin
r_data[DATA_W-1:0] = data[r_ptr[DEPTH_W-1:0]];
end else begin
r_data[DATA_W-1:0] = '0;
end
end else begin // normal mode
r_data[DATA_W-1:0] = data_buf[DATA_W-1:0];
end
fail = ( empty && r_req ) ||
( full && w_req );
end
function [DEPTH_W-1:0] inc_ptr (
input [DEPTH_W-1:0] ptr
);
if( ptr[DEPTH_W-1:0] == DEPTH-1 ) begin
inc_ptr[DEPTH_W-1:0] = '0;
end else begin
inc_ptr[DEPTH_W-1:0] = ptr[DEPTH_W-1:0] + 1'b1;
end
endfunction
`include "clogb2.svh"
endmodule endmodule

View File

@ -0,0 +1,43 @@
//------------------------------------------------------------------------------
// fifo_single_clock_reg_v2_init.svh
// published as part of https://github.com/pConst/basic_verilog
// Konstantin Pavlov, pavlovconst@gmail.com
//------------------------------------------------------------------------------
// INFO ------------------------------------------------------------------------
// Initialization statements example for fifo_single_clock_reg_v2 fifo
//
data[0] <= 32'hAAAA;
data[1] <= 32'h0001;
data[2] <= 32'h0002;
data[3] <= 32'h0003;
data[4] <= 32'h0004;
data[5] <= 32'h0005;
data[6] <= 32'h0006;
data[7] <= 32'h0007;
data[8] <= 32'hBBBB;
data[9] <= 32'h0001;
data[10] <= 32'h0002;
data[11] <= 32'h0003;
data[12] <= 32'h0004;
data[13] <= 32'h0005;
data[14] <= 32'h0006;
data[15] <= 32'h0007;
data[16] <= 32'hCCCC;
data[17] <= 32'h0001;
data[18] <= 32'h0002;
data[19] <= 32'h0003;
data[20] <= 32'h0004;
data[21] <= 32'h0005;
data[22] <= 32'h0006;
data[23] <= 32'h0007;
data[24] <= 32'hDDDD;
data[25] <= 32'h0001;
data[26] <= 32'h0002;
data[27] <= 32'h0003;
data[28] <= 32'h0004;
data[29] <= 32'h0005;
data[30] <= 32'h0006;
data[31] <= 32'h0007;

View File

@ -91,7 +91,7 @@ end
// comment or uncomment to test FWFT and normal fifo modes // comment or uncomment to test FWFT and normal fifo modes
`define TEST_FWFT yes //`define TEST_FWFT yes
// comment or uncomment to sweep-test or random test // comment or uncomment to sweep-test or random test
//`define TEST_SWEEP yes //`define TEST_SWEEP yes
@ -99,6 +99,9 @@ end
// comment or uncomment to use bare scfifo or quartus wizard-generated wrappers // comment or uncomment to use bare scfifo or quartus wizard-generated wrappers
//`define BARE_SCFIFO yes //`define BARE_SCFIFO yes
// initialization is not supported for Altera fifo
//`define TEST_INIT yes
logic full1, empty1; logic full1, empty1;
logic full1_d1, empty1_d1; logic full1_d1, empty1_d1;
@ -132,9 +135,20 @@ fifo_single_clock_reg_v2 #(
`endif `endif
.DEPTH( 8 ), .DEPTH( 8 ),
.DATA_W( 16 ) .DATA_W( 16 )
`ifdef TEST_INIT
,
// optional initialization
.USE_INIT_FILE( "TRUE" ),
.INIT_CNT( 10 )
`endif
) FF1 ( ) FF1 (
.clk( clk200 ), .clk( clk200 ),
`ifdef TEST_INIT
.nrst( 1'b1 ),
`else
.nrst( nrst_once ), .nrst( nrst_once ),
`endif
`ifdef TEST_SWEEP `ifdef TEST_SWEEP
.w_req( ~direction1 && &RandomNumber1[10] ), .w_req( ~direction1 && &RandomNumber1[10] ),

View File

@ -15,8 +15,8 @@
true_dual_port_write_first_2_clock_ram #( true_dual_port_write_first_2_clock_ram #(
.RAM_WIDTH( DATA_W ), .RAM_WIDTH( DATA_W ),
.RAM_DEPTH( DEPTH ), .RAM_DEPTH( DEPTH ),
.RAM_STYLE( "init.mem" ), // "block","register","M10K","logic",... .RAM_STYLE( "block" ), // "block","register","M10K","logic",...
.INIT_FILE( "" ) .INIT_FILE( "init.mem" )
) DR1 ( ) DR1 (
.clka( w_clk ), .clka( w_clk ),
.addra( w_ptr[DEPTH_W-1:0] ), .addra( w_ptr[DEPTH_W-1:0] ),
@ -39,6 +39,8 @@ true_dual_port_write_first_2_clock_ram #(
module true_dual_port_write_first_2_clock_ram #( parameter module true_dual_port_write_first_2_clock_ram #( parameter
RAM_WIDTH = 16, RAM_WIDTH = 16,
RAM_DEPTH = 8, RAM_DEPTH = 8,
// optional initialization parameters
RAM_STYLE = "", RAM_STYLE = "",
INIT_FILE = "" INIT_FILE = ""
)( )(

View File

@ -1,5 +1,6 @@
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// true_single_port_write_first_ram.sv // true_single_port_write_first_ram.sv
// published as part of https://github.com/pConst/basic_verilog
// Konstantin Pavlov, pavlovconst@gmail.com // Konstantin Pavlov, pavlovconst@gmail.com
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -31,6 +32,8 @@ true_single_port_write_first_ram #(
module true_single_port_write_first_ram #( parameter module true_single_port_write_first_ram #( parameter
RAM_WIDTH = 16, RAM_WIDTH = 16,
RAM_DEPTH = 8, RAM_DEPTH = 8,
// optional initialization parameters
RAM_STYLE = "", RAM_STYLE = "",
INIT_FILE = "" INIT_FILE = ""
)( )(