diff --git a/delay.sv b/delay.sv index 43acecb..d1ffb7a 100644 --- a/delay.sv +++ b/delay.sv @@ -4,7 +4,7 @@ //------------------------------------------------------------------------------ // INFO ------------------------------------------------------------------------- -// Static Delay for arbitrary signal +// Static Delay for arbitrary signal, v2 // Another equivalent names for this module: // conveyor.sv // synchronizer.sv @@ -14,21 +14,26 @@ // // // CAUTION: delay module is widely used for synchronizing signals across clock -// domains. To automatically exclude input data paths from timing analisys -// set_false_path SDC constraint is integrated into this module. Applicable -// only to Intel/Altera Quartus IDE. Xilinx users still should write the -// constraints manually +// domains. When synchronizing, please exclude input data paths from timing +// analisys manually by writing appropriate set_false_path SDC constraint // +// Version 2 introduces "ALTERA_BLOCK_RAM" option to implement delays using +// block RAM. Quartus can make shifters on block RAM aautomatically +// using 'altshift_taps' internal module when "Auto Shift Register +// Replacement" option is ON /* --- INSTANTIATION TEMPLATE BEGIN --- delay #( - .LENGTH( 2 ) + .LENGTH( 2 ), + .WIDTH( 1 ), + .TYPE( "CELLS" ) ) S1 ( .clk( clk ), .nrst( 1'b1 ), .ena( 1'b1 ), + .in( ), .out( ) ); @@ -37,45 +42,110 @@ delay #( module delay #( parameter - LENGTH = 2 // delay/synchronizer chain length - // default length for synchronizer chain is 2 + LENGTH = 2, // delay/synchronizer chain length + WIDTH = 1, // signal width + TYPE = "CELLS", // "ALTERA_BLOCK_RAM" infers block ram fifo + // all other values infer registers + + CNTR_W = $clog2(LENGTH) )( input clk, input nrst, input ena, - input in, - output out + + input [WIDTH-1:0] in, + output [WIDTH-1:0] out ); generate if ( LENGTH == 0 ) begin - assign out = in; + + assign out[WIDTH-1:0] = in[WIDTH-1:0]; + end else if( LENGTH == 1 ) begin - logic data = 0; + logic [WIDTH-1:0] data = '0; always_ff @(posedge clk) begin - if (~nrst) begin - data <= 0; - end else if (ena) begin - data <= in; + if( ~nrst ) begin + data[WIDTH-1:0] <= '0; + end else if( ena ) begin + data[WIDTH-1:0] <= in[WIDTH-1:0]; end end - assign out = data; + assign out[WIDTH-1:0] = data[WIDTH-1:0]; end else begin + if( TYPE=="ALTERA_BLOCK_RAM" && LENGTH>=4 ) begin - logic [LENGTH:1] data = 0; - always_ff @(posedge clk) begin - if (~nrst) begin - data[LENGTH:1] <= 0; - end else if (ena) begin - data[LENGTH:1] <= {data[LENGTH-1:1],in}; + logic [CNTR_W-1:0] delay_cntr = '0; + + logic fifo_output_ena; + assign fifo_output_ena = (delay_cntr[CNTR_W-1:0] == LENGTH); + + always_ff @(posedge clk) begin + if( ~nrst ) begin + delay_cntr[CNTR_W-1:0] <= '0; + end else begin + if( ena && ~fifo_output_ena) begin + delay_cntr[CNTR_W-1:0] <= delay_cntr[CNTR_W-1:0] + 1'b1; + end + end end - end - assign out = data[LENGTH]; - end // if + logic [WIDTH-1:0] fifo_out; + scfifo #( + .LPM_WIDTH( WIDTH ), + .LPM_NUMWORDS( LENGTH ), // must be at least 4 + .LPM_WIDTHU( CNTR_W ), + .LPM_SHOWAHEAD( "ON" ), + .UNDERFLOW_CHECKING( "ON" ), + .OVERFLOW_CHECKING( "ON" ), + .ALMOST_FULL_VALUE( 0 ), + .ALMOST_EMPTY_VALUE( 0 ), + .ENABLE_ECC( "FALSE" ), + .ALLOW_RWCYCLE_WHEN_FULL( "ON" ), + .USE_EAB( "ON" ), + .MAXIMIZE_SPEED( 5 ), + .DEVICE_FAMILY( "Cyclone V" ) + ) internal_fifo ( + .clock( clk ), + .aclr( 1'b0 ), + .sclr( ~nrst ), + + .data( in[WIDTH-1:0] ), + .wrreq( ena ), + .rdreq( ena && fifo_output_ena ), + + .q( fifo_out[WIDTH-1:0] ), + .empty( ), + .full( ), + .almost_full( ), + .almost_empty( ), + .usedw( ), + .eccstatus( ) + ); + + assign out[WIDTH-1:0] = (fifo_output_ena)?(fifo_out[WIDTH-1:0]):('0); + + end else begin + + logic [LENGTH:1][WIDTH-1:0] data = '0; + always_ff @(posedge clk) begin + integer i; + if( ~nrst ) begin + data <= '0; + end else if( ena ) begin + for(i=LENGTH-1; i>0; i--) begin + data[i+1][WIDTH-1:0] <= data[i][WIDTH-1:0]; + end + data[1][WIDTH-1:0] <= in[WIDTH-1:0]; + end + end + assign out[WIDTH-1:0] = data[LENGTH][WIDTH-1:0]; + + end // if TYPE + end // if LENGTH endgenerate diff --git a/delay_tb.sv b/delay_tb.sv new file mode 100644 index 0000000..ddffeda --- /dev/null +++ b/delay_tb.sv @@ -0,0 +1,120 @@ +//------------------------------------------------------------------------------ +// delay_tb.sv +// Konstantin Pavlov, pavlovconst@gmail.com +//------------------------------------------------------------------------------ + +// INFO ------------------------------------------------------------------------ +// testbench for delay_tb.sv module + +`timescale 1ns / 1ps + +module delay_tb(); + +logic clk200; +initial begin + #0 clk200 = 1'b1; + forever + #2.5 clk200 = ~clk200; +end + +logic clk400; +initial begin + #0 clk400 = 1'b1; + forever + #1.25 clk400 = ~clk400; +end + +logic clk33; +initial begin + #0 clk33 = 1'b1; + forever + #15.151 clk33 = ~clk33; +end + +logic rst; +initial begin + #0 rst = 1'b0; + #10.2 rst = 1'b1; + #5 rst = 1'b0; +end + +logic nrst; +assign nrst = ~rst; + +logic rst_once; +initial begin + #0 rst_once = 1'b0; + #10.2 rst_once = 1'b1; + #5 rst_once = 1'b0; +end + +logic nrst_once; +assign nrst_once = ~rst_once; + +logic [31:0] DerivedClocks; +clk_divider #( + .WIDTH( 32 ) +) cd1 ( + .clk( clk200 ), + .nrst( nrst_once ), + .ena( 1'b1 ), + .out( DerivedClocks[31:0] ) +); + +logic [31:0] E_DerivedClocks; +edge_detect ed1[31:0] ( + .clk( {32{clk200}} ), + .nrst( {32{nrst_once}} ), + .in( DerivedClocks[31:0] ), + .rising( E_DerivedClocks[31:0] ), + .falling( ), + .both( ) +); + +logic [31:0] RandomNumber1; +c_rand rng1 ( + .clk( clk200 ), + .rst( 1'b0 ), + .reseed( rst_once ), + .seed_val( DerivedClocks[31:0] ^ (DerivedClocks[31:0] << 1) ), + .out( RandomNumber1[15:0] ) +); + +c_rand rng2 ( + .clk( clk200 ), + .rst( 1'b0 ), + .reseed( rst_once ), + .seed_val( DerivedClocks[31:0] ^ (DerivedClocks[31:0] << 2) ), + .out( RandomNumber1[31:16] ) +); + +// Module under test ========================================================== + +delay #( + .LENGTH( 10 ), + .WIDTH( 8 ) + //.TYPE( "CELLS" ) +) d1 ( + .clk( clk200 ), + .nrst( ~E_DerivedClocks[8] ), + .ena( 1'b1 ), + + .in( RandomNumber1[7:0] ), + .out( ) +); + +delay #( + .LENGTH( 10 ), + .WIDTH( 8 ), + .TYPE( "ALTERA_BLOCK_RAM" ) +) d2 ( + .clk( clk200 ), + .nrst( ~E_DerivedClocks[8] ), + .ena( 1'b1 ), + + .in( RandomNumber1[7:0] ), + .out( ) +); + + +endmodule