From a6aa3c38935b804ecd06327cc0179bf8b37f54ef Mon Sep 17 00:00:00 2001 From: Konstantin Pavlov Date: Mon, 25 Apr 2022 01:06:34 +0300 Subject: [PATCH] Done fifo initialization --- fifo_single_clock_ram.sv | 179 ++++++++++------- fifo_single_clock_ram_init.mem | 32 +++ fifo_single_clock_ram_tb.sv | 108 +++++++--- fifo_single_clock_reg_v1.sv | 69 ++++--- fifo_single_clock_reg_v1_tb.sv | 5 +- fifo_single_clock_reg_v2.sv | 234 +++++++++++++--------- fifo_single_clock_reg_v2_init.svh | 43 ++++ fifo_single_clock_reg_v2_tb.sv | 16 +- true_dual_port_write_first_2_clock_ram.sv | 6 +- true_single_port_write_first_ram.sv | 3 + 10 files changed, 452 insertions(+), 243 deletions(-) create mode 100755 fifo_single_clock_ram_init.mem create mode 100755 fifo_single_clock_reg_v2_init.svh diff --git a/fifo_single_clock_ram.sv b/fifo_single_clock_ram.sv index 8a00a0e..25203bb 100755 --- a/fifo_single_clock_ram.sv +++ b/fifo_single_clock_ram.sv @@ -1,5 +1,6 @@ //------------------------------------------------------------------------------ // fifo_single_clock_ram.sv +// published as part of https://github.com/pConst/basic_verilog // Konstantin Pavlov, pavlovconst@gmail.com //------------------------------------------------------------------------------ @@ -15,15 +16,23 @@ // - configurable depth and data width // - only "normal" mode is supported here, no FWFT mode // - 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 (!) -// +// - CAUTION! block RAMs do NOT support fifo contents REinitialization after reset /* --- INSTANTIATION TEMPLATE BEGIN --- fifo_single_clock_ram #( .DEPTH( 8 ), - .DATA_W( 32 ) + .DATA_W( 32 ), + + // optional initialization + .INIT_FILE( "fifo_single_clock_ram_init.mem" ), + .INIT_CNT( 10 ) ) FF1 ( .clk( clk ), .nrst( 1'b1 ), @@ -43,19 +52,23 @@ fifo_single_clock_ram #( module fifo_single_clock_ram #( parameter - //FWFT_MODE = "TRUE", // "TRUE" - first word fall-trrough" mode - // "FALSE" - normal fifo mode + FWFT_MODE = "TRUE", // "TRUE" - first word fall-trrough" 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 - 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 - 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 nrst, // inverted reset + input nrst, // inverted reset // input port input w_req, @@ -66,7 +79,7 @@ module fifo_single_clock_ram #( parameter output [DATA_W-1:0] r_data, // 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 full, @@ -74,83 +87,99 @@ module fifo_single_clock_ram #( parameter ); -// read and write pointers -logic [DEPTH_W-1:0] w_ptr = '0; -logic [DEPTH_W-1:0] r_ptr = '0; + // read and write pointers + logic [DEPTH_W-1:0] w_ptr = INIT_CNT[DEPTH_W-1:0]; + logic [DEPTH_W-1:0] r_ptr = '0; -// filtered requests -logic w_req_f; -assign w_req_f = w_req && ~full; + // filtered requests + logic w_req_f; + assign w_req_f = w_req && ~full; -logic r_req_f; -assign r_req_f = r_req && ~empty; + logic r_req_f; + assign r_req_f = r_req && ~empty; -true_dual_port_write_first_2_clock_ram #( - .RAM_WIDTH( DATA_W ), - .RAM_DEPTH( DEPTH ), - .INIT_FILE( INIT_FILE ) -) data_ram ( - .clka( clk ), - .addra( w_ptr[DEPTH_W-1:0] ), - .ena( w_req_f ), - .wea( 1'b1 ), - .dina( w_data[DATA_W-1:0] ), - .douta( ), + true_dual_port_write_first_2_clock_ram #( + .RAM_WIDTH( DATA_W ), + .RAM_DEPTH( DEPTH ), + .RAM_STYLE( RAM_STYLE ), // "block","register","M10K","logic",... + .INIT_FILE( INIT_FILE ) + ) data_ram ( + .clka( clk ), + .addra( w_ptr[DEPTH_W-1:0] ), + .ena( w_req_f ), + .wea( 1'b1 ), + .dina( w_data[DATA_W-1:0] ), + .douta( ), - .clkb( clk ), - .addrb( r_ptr[DEPTH_W-1:0] ), - .enb( r_req_f ), - .web( 1'b0 ), - .dinb( '0 ), - .doutb( r_data[DATA_W-1:0] ) -); + .clkb( clk ), + .addrb( r_ptr[DEPTH_W-1:0] ), + .enb( r_req_f ), + .web( 1'b0 ), + .dinb( '0 ), + .doutb( r_data[DATA_W-1:0] ) + ); -function [DEPTH_W-1:0] inc_ptr ( - input [DEPTH_W-1:0] ptr -); + always_ff @(posedge clk) begin + 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 - inc_ptr[DEPTH_W-1:0] = '0; - end else begin - inc_ptr[DEPTH_W-1:0] = ptr[DEPTH_W-1:0] + 1'b1; + cnt[DEPTH_W-1:0] <= '0; + end else begin + 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; + 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 -endfunction + always_comb begin + empty = ( cnt[DEPTH_W-1:0] == '0 ); + full = ( cnt[DEPTH_W-1:0] == DEPTH ); -always_ff @(posedge clk) begin - if ( ~nrst ) begin - 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 - + fail = ( empty && r_req ) || + ( full && w_req ); end -end -always_comb begin - empty = ( cnt[DEPTH_W-1:0] == '0 ); - full = ( cnt[DEPTH_W-1:0] == DEPTH ); + 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 - fail = ( empty && r_req ) || - ( full && w_req ); -end + `include "clogb2.svh" endmodule - diff --git a/fifo_single_clock_ram_init.mem b/fifo_single_clock_ram_init.mem new file mode 100755 index 0000000..7ab3f67 --- /dev/null +++ b/fifo_single_clock_ram_init.mem @@ -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 \ No newline at end of file diff --git a/fifo_single_clock_ram_tb.sv b/fifo_single_clock_ram_tb.sv index a241e49..b407b3b 100755 --- a/fifo_single_clock_ram_tb.sv +++ b/fifo_single_clock_ram_tb.sv @@ -4,7 +4,7 @@ //------------------------------------------------------------------------------ // INFO ------------------------------------------------------------------------ -// testbench for fifo_single_clock_reg_ram.sv module +// testbench for fifo_single_clock_ram.sv module // `timescale 1ns / 1ps @@ -89,15 +89,19 @@ end // Module under test ========================================================== + // comment or uncomment to test FWFT and normal fifo modes //`define TEST_FWFT yes // 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 //`define BARE_SCFIFO yes +// initialization is not supported for Altera fifo +//`define TEST_INIT yes + logic full1, empty1; logic full1_d1, empty1_d1; @@ -124,11 +128,29 @@ end logic [3:0] cnt1; logic [15:0] data_out1; fifo_single_clock_ram #( +`ifdef TEST_FWFT + .FWFT_MODE( "TRUE" ), +`else + .FWFT_MODE( "FALSE" ), +`endif .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 ( .clk( clk200 ), +`ifdef TEST_INIT + .nrst( 1'b1 ), +`else .nrst( nrst_once ), +`endif `ifdef TEST_SWEEP .w_req( ~direction1 && &RandomNumber1[10] ), @@ -177,8 +199,9 @@ end //============================================================================== logic [15:0] data_out2; +`ifdef BARE_SCFIFO - DCFIFO #( + SCFIFO #( .LPM_WIDTH( 16 ), .LPM_NUMWORDS( 8 ), .LPM_WIDTHU( $clog2(8) ), /// CEIL(LOG2(LPM_NUMWORDS)), @@ -190,23 +213,12 @@ logic [15:0] data_out2; `endif .UNDERFLOW_CHECKING( "ON" ), .OVERFLOW_CHECKING( "ON" ), - + .ALLOW_RWCYCLE_WHEN_FULL( "ON" ), .ADD_RAM_OUTPUT_REGISTER( "OFF" ), - .ENABLE_ECC( "FALSE" ), - // output delay to the usedw[] outputs - .DELAY_RDUSEDW( 1 ), // one clock cycle by default - .DELAY_WRUSEDW( 1 ), - // 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" ) + .ALMOST_FULL_VALUE( 0 ), + .ALMOST_EMPTY_VALUE( 0 ), + .ENABLE_ECC( "FALSE" ) //.USE_EAB( "ON" ), //.MAXIMIZE_SPEED( 5 ), @@ -214,35 +226,63 @@ logic [15:0] data_out2; //.OPTIMIZE_FOR_SPEED( 5 ), //.CBXI_PARAMETER( "NOTHING" ) ) FF2 ( + .clock( clk200 ), .aclr( 1'b0 ), + .sclr( ~nrst_once ), - .wrclk( clk200 ), `ifdef TEST_SWEEP .wrreq( ~direction1 && &RandomNumber1[10] ), .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] ), .q( data_out2[15:0] ), `else + .wrreq( &RandomNumber1[10:9] ), + .data( RandomNumber1[15:0] ), + .rdreq( &RandomNumber1[8:7] ), .q( data_out2[15:0] ), `endif - .rdempty( empty2 ), - .rdfull( full2 ), - .rdusedw( ), + + .empty( empty2 ), + .full( full2 ), + + .almost_empty( ), + .almost_full( ), + .usedw( ), .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 +// 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 diff --git a/fifo_single_clock_reg_v1.sv b/fifo_single_clock_reg_v1.sv index a502c73..80232db 100644 --- a/fifo_single_clock_reg_v1.sv +++ b/fifo_single_clock_reg_v1.sv @@ -16,9 +16,10 @@ // - configurable depth and data width // - one write- and one read- port in "FWFT" or "normal" mode // - protected against overflow and underflow -// - simultaneous read and write operations supported if not full and not empty -// - only read operation is performed when (full && r_req && w_req) -// - only write operation is performed when (empty && r_req && w_req) +// - 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! // - (new!) optional fifo contents initialization // // 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 // data[cnt[]] points to the first empty fifo slot // 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 integer i; if ( ~nrst ) begin @@ -131,34 +123,49 @@ module fifo_single_clock_reg_v1 #( parameter end data_buf[DATA_W-1:0] <= '0; end else begin - unique case ({w_req_f, r_req_f}) + unique case ({w_req, r_req}) 2'b00: ; // nothing 2'b01: begin // reading out - for ( i = (DEPTH-1); i > 0; i=i-1 ) begin - data[i-1] <= data[i]; + if( ~empty ) 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 - cnt[DEPTH_W-1:0] <= cnt[DEPTH_W-1:0] - 1'b1; end 2'b10: begin // writing in - data[cnt[DEPTH_W-1:0]] <= w_data[DATA_W-1:0]; - cnt[DEPTH_W-1:0] <= cnt[DEPTH_W-1:0] + 1'b1; + if( ~full ) 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 end 2'b11: begin // simultaneously reading and writing - for ( i = (DEPTH-1); i > 0; i=i-1 ) begin - data[i-1] <= data[i]; + 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 + 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 - data[cnt[DEPTH_W-1:0]-1] <= 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[0]; - end end end @@ -166,14 +173,14 @@ module fifo_single_clock_reg_v1 #( parameter empty = ( cnt[DEPTH_W-1:0] == '0 ); 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 - r_data[DATA_W-1:0] = data[0]; // first-word fall-through mode + r_data[DATA_W-1:0] = data[0]; end else begin r_data[DATA_W-1:0] = '0; end - end else begin - r_data[DATA_W-1:0] = data_buf[DATA_W-1:0]; // normal mode + end else begin // normal mode + r_data[DATA_W-1:0] = data_buf[DATA_W-1:0]; end fail = ( empty && r_req ) || diff --git a/fifo_single_clock_reg_v1_tb.sv b/fifo_single_clock_reg_v1_tb.sv index 8bae977..f5de1bc 100644 --- a/fifo_single_clock_reg_v1_tb.sv +++ b/fifo_single_clock_reg_v1_tb.sv @@ -100,7 +100,7 @@ end //`define BARE_SCFIFO yes // initialization is not supported for Altera fifo -`define TEST_INIT yes +//`define TEST_INIT yes logic full1, empty1; logic full1_d1, empty1_d1; @@ -134,9 +134,10 @@ fifo_single_clock_reg_v1 #( .FWFT_MODE( "FALSE" ), `endif .DEPTH( 8 ), - .DATA_W( 16 ), + .DATA_W( 16 ) `ifdef TEST_INIT + , // optional initialization .USE_INIT_FILE( "TRUE" ), .INIT_CNT( 10 ) diff --git a/fifo_single_clock_reg_v2.sv b/fifo_single_clock_reg_v2.sv index 7879f8c..09e89d7 100644 --- a/fifo_single_clock_reg_v2.sv +++ b/fifo_single_clock_reg_v2.sv @@ -1,19 +1,26 @@ //------------------------------------------------------------------------------ // fifo_single_clock_reg_v2.sv +// published as part of https://github.com/pConst/basic_verilog // Konstantin Pavlov, pavlovconst@gmail.com //------------------------------------------------------------------------------ // INFO ------------------------------------------------------------------------ // 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: // - single clock operation // - configurable depth and data width // - one write- and one read- port in "FWFT" or "normal" mode // - protected against overflow and underflow -// - simultaneous read and write operations supported if not full and not empty -// - only read operation is performed when (full && r_req && w_req) -// - only write operation is performed when (empty && r_req && w_req) +// - 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! +// - (new!) optional fifo contents initialization // // See also "lifo.sv" module for similar LIFO buffer implementation @@ -23,7 +30,11 @@ fifo_single_clock_reg_v2 #( .FWFT_MODE( "TRUE" ), .DEPTH( 8 ), - .DATA_W( 32 ) + .DATA_W( 32 ), + + // optional initialization + .INIT_FILE( "fifo_single_clock_reg_v2_init.svh" ), + .INIT_CNT( 10 ) ) FF1 ( .clk( clk ), .nrst( 1'b1 ), @@ -45,16 +56,19 @@ module fifo_single_clock_reg_v2 #( parameter FWFT_MODE = "TRUE", // "TRUE" - first word fall-trrough" mode // "FALSE" - normal fifo mode - 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 - 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 nrst, // inverted reset + input nrst, // inverted reset // input port input w_req, @@ -65,111 +79,131 @@ module fifo_single_clock_reg_v2 #( parameter output logic [DATA_W-1:0] r_data, // helper ports - output logic [DEPTH_W-1:0] cnt = '0, + output logic [DEPTH_W-1:0] cnt, output logic empty, output logic full, output logic fail ); -// fifo data, extra element to keep pointer positions always valid, -// even when fifo is empty or full -logic [DEPTH-1:0][DATA_W-1:0] data = '0; + // fifo data + logic [DEPTH-1:0][DATA_W-1:0] data; -// read and write pointers -logic [DEPTH_W-1:0] w_ptr = '0; -logic [DEPTH_W-1:0] r_ptr = '0; + // read and write pointers + logic [DEPTH_W-1:0] w_ptr; + logic [DEPTH_W-1:0] r_ptr; -// data output buffer for normal fifo mode -logic [DATA_W-1:0] data_buf = '0; - - -// filtered requests -logic w_req_f; -assign w_req_f = w_req && ~full; - -logic r_req_f; -assign r_req_f = r_req && ~empty; - - -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 - - -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; + // fofo initialization + // Modelsim gives suppressable error here + // "(vlog-7061) Variable 'data' driven in an always_ff block, may not be driven by any other process" + generate + initial 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 // initial + endgenerate - 2'b10: begin // writing in - 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]; - cnt[DEPTH_W-1:0] <= cnt[DEPTH_W-1:0] + 1'b1; + + // 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 - - 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 + data_buf[DATA_W-1:0] <= '0; 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 else begin - r_data[DATA_W-1:0] = data_buf[DATA_W-1:0]; // normal mode end - fail = ( empty && r_req ) || - ( full && w_req ); -end + always_comb begin + empty = ( cnt[DEPTH_W-1:0] == '0 ); + 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 diff --git a/fifo_single_clock_reg_v2_init.svh b/fifo_single_clock_reg_v2_init.svh new file mode 100755 index 0000000..f1e2220 --- /dev/null +++ b/fifo_single_clock_reg_v2_init.svh @@ -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; + diff --git a/fifo_single_clock_reg_v2_tb.sv b/fifo_single_clock_reg_v2_tb.sv index d520b42..870f57d 100644 --- a/fifo_single_clock_reg_v2_tb.sv +++ b/fifo_single_clock_reg_v2_tb.sv @@ -91,7 +91,7 @@ end // 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 //`define TEST_SWEEP yes @@ -99,6 +99,9 @@ end // comment or uncomment to use bare scfifo or quartus wizard-generated wrappers //`define BARE_SCFIFO yes +// initialization is not supported for Altera fifo +//`define TEST_INIT yes + logic full1, empty1; logic full1_d1, empty1_d1; @@ -132,9 +135,20 @@ fifo_single_clock_reg_v2 #( `endif .DEPTH( 8 ), .DATA_W( 16 ) + +`ifdef TEST_INIT + , + // optional initialization + .USE_INIT_FILE( "TRUE" ), + .INIT_CNT( 10 ) +`endif ) FF1 ( .clk( clk200 ), +`ifdef TEST_INIT + .nrst( 1'b1 ), +`else .nrst( nrst_once ), +`endif `ifdef TEST_SWEEP .w_req( ~direction1 && &RandomNumber1[10] ), diff --git a/true_dual_port_write_first_2_clock_ram.sv b/true_dual_port_write_first_2_clock_ram.sv index 42bc42b..baa52d9 100755 --- a/true_dual_port_write_first_2_clock_ram.sv +++ b/true_dual_port_write_first_2_clock_ram.sv @@ -15,8 +15,8 @@ true_dual_port_write_first_2_clock_ram #( .RAM_WIDTH( DATA_W ), .RAM_DEPTH( DEPTH ), - .RAM_STYLE( "init.mem" ), // "block","register","M10K","logic",... - .INIT_FILE( "" ) + .RAM_STYLE( "block" ), // "block","register","M10K","logic",... + .INIT_FILE( "init.mem" ) ) DR1 ( .clka( w_clk ), .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 RAM_WIDTH = 16, RAM_DEPTH = 8, + + // optional initialization parameters RAM_STYLE = "", INIT_FILE = "" )( diff --git a/true_single_port_write_first_ram.sv b/true_single_port_write_first_ram.sv index 1071802..c0b1ae1 100755 --- a/true_single_port_write_first_ram.sv +++ b/true_single_port_write_first_ram.sv @@ -1,5 +1,6 @@ //------------------------------------------------------------------------------ // true_single_port_write_first_ram.sv +// published as part of https://github.com/pConst/basic_verilog // Konstantin Pavlov, pavlovconst@gmail.com //------------------------------------------------------------------------------ @@ -31,6 +32,8 @@ true_single_port_write_first_ram #( module true_single_port_write_first_ram #( parameter RAM_WIDTH = 16, RAM_DEPTH = 8, + + // optional initialization parameters RAM_STYLE = "", INIT_FILE = "" )(