1
0
mirror of https://github.com/pConst/basic_verilog.git synced 2025-01-14 06:42:54 +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,15 +52,19 @@ 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 = 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
INIT_FILE = ""
RAM_STYLE = "", // "block","register","M10K","logic",...
// optional initialization
INIT_FILE = "", // .HEX or .MEM file to initialize fifo contents
INIT_CNT = '0 // sets desired initial cnt[]
)( )(
input clk, input clk,
@ -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,23 +87,24 @@ 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 ),
.RAM_STYLE( RAM_STYLE ), // "block","register","M10K","logic",...
.INIT_FILE( INIT_FILE ) .INIT_FILE( INIT_FILE )
) data_ram ( ) data_ram (
.clka( clk ), .clka( clk ),
.addra( w_ptr[DEPTH_W-1:0] ), .addra( w_ptr[DEPTH_W-1:0] ),
.ena( w_req_f ), .ena( w_req_f ),
@ -104,53 +118,68 @@ true_dual_port_write_first_2_clock_ram #(
.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( 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
always_ff @(posedge clk) begin
if ( ~nrst ) begin if ( ~nrst ) begin
w_ptr[DEPTH_W-1:0] <= '0; w_ptr[DEPTH_W-1:0] <= '0;
r_ptr[DEPTH_W-1:0] <= '0; r_ptr[DEPTH_W-1:0] <= '0;
cnt[DEPTH_W-1:0] <= '0; cnt[DEPTH_W-1:0] <= '0;
end else begin end else begin
unique case ({w_req, r_req})
2'b00: ; // nothing
if( w_req_f ) begin 2'b01: begin // reading out
w_ptr[DEPTH_W-1:0] <= inc_ptr(w_ptr[DEPTH_W-1:0]); if( ~empty ) begin
end
if( r_req_f ) begin
r_ptr[DEPTH_W-1:0] <= inc_ptr(r_ptr[DEPTH_W-1:0]); 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; cnt[DEPTH_W-1:0] <= cnt[DEPTH_W-1:0] - 1'b1;
end end
end end
end
always_comb begin 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
always_comb begin
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 );
fail = ( empty && r_req ) || fail = ( empty && r_req ) ||
( full && w_req ); ( full && w_req );
end 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

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,49 +123,64 @@ 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
if( ~empty ) begin
for ( i = (DEPTH-1); i > 0; i=i-1 ) begin for ( i = (DEPTH-1); i > 0; i=i-1 ) begin
data[i-1] <= data[i]; data[i-1] <= data[i];
end end
cnt[DEPTH_W-1:0] <= cnt[DEPTH_W-1:0] - 1'b1; cnt[DEPTH_W-1:0] <= cnt[DEPTH_W-1:0] - 1'b1;
data_buf[DATA_W-1:0] <= data[0];
end
end end
2'b10: begin // writing in 2'b10: begin // writing in
if( ~full ) begin
data[cnt[DEPTH_W-1:0]] <= w_data[DATA_W-1:0]; data[cnt[DEPTH_W-1:0]] <= w_data[DATA_W-1:0];
cnt[DEPTH_W-1:0] <= cnt[DEPTH_W-1:0] + 1'b1; 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
if( empty ) begin
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 for ( i = (DEPTH-1); i > 0; i=i-1 ) begin
data[i-1] <= data[i]; data[i-1] <= data[i];
end end
data[cnt[DEPTH_W-1:0]-1] <= w_data[DATA_W-1:0]; cnt[DEPTH_W-1:0] <= cnt[DEPTH_W-1:0] - 1'b1;
// data counter does not change here 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
endcase end
//cnt[DEPTH_W-1:0] <= // data counter does not change here
// data buffer works only for normal fifo mode
if( r_req_f ) begin
data_buf[DATA_W-1:0] <= data[0]; data_buf[DATA_W-1:0] <= data[0];
end end
end end
endcase
end
end end
always_comb begin always_comb begin
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,14 +56,17 @@ 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
@ -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];
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 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; data <= '0;
cnt[DEPTH_W-1:0] <= '0;
w_ptr[DEPTH_W-1:0] <= '0; w_ptr[DEPTH_W-1:0] <= '0;
r_ptr[DEPTH_W-1:0] <= '0; r_ptr[DEPTH_W-1:0] <= '0;
cnt[DEPTH_W-1:0] <= '0;
end
end // initial
endgenerate
// data output buffer for normal fifo mode
logic [DATA_W-1:0] data_buf = '0;
always_ff @(posedge clk) begin
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
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
if( ~empty ) begin if( ~empty ) begin
r_ptr[DEPTH_W-1:0] <= inc_ptr(r_ptr[DEPTH_W-1:0]); 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; 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 end
2'b10: begin // writing in 2'b10: begin // writing in
if( ~full ) begin if( ~full ) begin
w_ptr[DEPTH_W-1:0] <= inc_ptr(w_ptr[DEPTH_W-1:0]); 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[w_ptr[DEPTH_W-1:0]] <= w_data[DATA_W-1:0];
cnt[DEPTH_W-1:0] <= cnt[DEPTH_W-1:0] + 1'b1; 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
if( ~empty ) begin 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]); 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[w_ptr[DEPTH_W-1:0]] <= w_data[DATA_W-1:0];
// data counter does not change here cnt[DEPTH_W-1:0] <= cnt[DEPTH_W-1:0] + 1'b1;
end end else if( full ) begin
endcase 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 buffer works only for normal fifo mode data_buf[DATA_W-1:0] <= data[r_ptr[DEPTH_W-1:0]];
if( r_req_f ) begin 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]]; data_buf[DATA_W-1:0] <= data[r_ptr[DEPTH_W-1:0]];
end end
end end
end endcase
end
end
always_comb begin
always_comb begin
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[r_ptr[DEPTH_W-1:0]]; // first-word fall-through mode r_data[DATA_W-1:0] = data[r_ptr[DEPTH_W-1: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 ) ||
( full && w_req ); ( full && w_req );
end 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 = ""
)( )(