diff --git a/fifo_single_clock_reg_v1.sv b/fifo_single_clock_reg_v1.sv index 509e239..a502c73 100644 --- a/fifo_single_clock_reg_v1.sv +++ b/fifo_single_clock_reg_v1.sv @@ -1,11 +1,16 @@ //------------------------------------------------------------------------------ // fifo_single_clock_reg_v1.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 @@ -14,6 +19,7 @@ // - 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) +// - (new!) optional fifo contents initialization // // See also "lifo.sv" module for similar LIFO buffer implementation @@ -23,7 +29,11 @@ fifo_single_clock_reg_v1 #( .FWFT_MODE( "TRUE" ), .DEPTH( 8 ), - .DATA_W( 32 ) + .DATA_W( 32 ), + + // optional initialization + .INIT_FILE( "fifo_single_clock_reg_v1_init.svh" ), + .INIT_CNT( 10 ) ) FF1 ( .clk( clk ), .nrst( 1'b1 ), @@ -45,16 +55,19 @@ module fifo_single_clock_reg_v1 #( 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,86 +78,108 @@ module fifo_single_clock_reg_v1 #( 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 -logic [DEPTH-1:0][DATA_W-1:0] data = '0; + // fifo data + logic [DEPTH-1:0][DATA_W-1:0] data; -// data output buffer for normal fifo mode -logic [DATA_W-1:0] data_buf = '0; - -// 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; - - -integer i; -always_ff @(posedge clk) begin - if ( ~nrst ) begin - data <= '0; - cnt[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 - for ( i = (DEPTH-1); i > 0; i-- ) begin - data[i-1] <= data[i]; - 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_v1_init.svh" + cnt[DEPTH_W-1:0] <= INIT_CNT[DEPTH_W-1:0]; + end else begin + data <= '0; + cnt[DEPTH_W-1:0] <= '0; end + end // initial + endgenerate - 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; + + // data output buffer for normal fifo mode + logic [DATA_W-1:0] data_buf = '0; + + // 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 + if( USE_INIT_FILE ) begin + `include "fifo_single_clock_reg_v1_init.svh" + cnt[DEPTH_W-1:0] <= INIT_CNT[DEPTH_W-1:0]; + end else begin + data <= '0; + cnt[DEPTH_W-1:0] <= '0; end - - 2'b11: begin // simultaneously reading and writing - for ( i = (DEPTH-1); i > 0; i-- ) begin - data[i-1] <= data[i]; - 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 - - -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[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_f, r_req_f}) + 2'b00: ; // nothing + + 2'b01: begin // reading out + 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; + 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; + end + + 2'b11: begin // simultaneously reading and writing + for ( i = (DEPTH-1); i > 0; i=i-1 ) begin + data[i-1] <= data[i]; + 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 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 + if( ~empty ) begin + r_data[DATA_W-1:0] = data[0]; // first-word fall-through mode + 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 + + fail = ( empty && r_req ) || + ( full && w_req ); + end + + `include "clogb2.svh" endmodule diff --git a/fifo_single_clock_reg_v1_init.svh b/fifo_single_clock_reg_v1_init.svh new file mode 100755 index 0000000..f81419a --- /dev/null +++ b/fifo_single_clock_reg_v1_init.svh @@ -0,0 +1,43 @@ +//------------------------------------------------------------------------------ +// fifo_single_clock_reg_v1_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_v1 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_v1_tb.sv b/fifo_single_clock_reg_v1_tb.sv index 427f08e..8bae977 100644 --- a/fifo_single_clock_reg_v1_tb.sv +++ b/fifo_single_clock_reg_v1_tb.sv @@ -94,11 +94,14 @@ end //`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; @@ -131,10 +134,20 @@ 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 ) +`endif ) FF1 ( .clk( clk200 ), +`ifdef TEST_INIT + .nrst( 1'b1 ), +`else .nrst( nrst_once ), +`endif `ifdef TEST_SWEEP .w_req( ~direction1 && &RandomNumber1[10] ),