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
// 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

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 ------------------------------------------------------------------------
// 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

View File

@ -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 ) ||

View File

@ -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 )

View File

@ -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

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
`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] ),

View File

@ -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 = ""
)(

View File

@ -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 = ""
)(