Try   HackMD
tags: caraval-fpga

add delay in verilog

issue 1 (root cause is relative to inertial delay and update in below)

I found the waveform in delay 13ns is incorrect.

assign #13 Serial_Data_Out_by_assign_13ns = Serial_Data_Out;

issue 2 Serial_Data_Out_delay with glitch

I also implement a module name dly_line to simulation the behavior for delay.

  • I found the input source impact the result.
    • When I input ioclk then the result is ok.
    • When I input Serial_Data_Out then the result in Serial_Data_Out_delay with glitch.

issue 3 (root cuase is the same as issue 1)

There are another issue in assign with delay

 	assign #3 ioclk_by_assign_3ns = ioclk;
 	assign #8 ioclk_by_assign_8ns = ioclk;
 	assign #13 ioclk_by_assign_13ns = ioclk;
  • ioclk_by_assign_3ns is ok
  • ioclk_by_assign_8ns is incorrect
  • ioclk_by_assign_13ns is incorrect

result

below net result is not meet my expectation. Why???

  • Serial_Data_Out_by_assign_13ns
  • ioclk_by_assign_8ns
  • ioclk_by_assign_13ns
  • Serial_Data_Out_delay

code - fsic_io_serdes_m2.v

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 05/26/2023 05:10:17 PM
// Design Name: 
// Module Name: sfic_io_serdes
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////

//for ioserdes method 2


module fsic_io_serdes_tx_m2#(
		parameter TxFIFO_DEPTH = 4,
		parameter CLK_RATIO =4
	) (
		input 	rst,
		output 	txclk,
		input 	ioclk,
		input 	coreclk,
		output 	Serial_Data_Out,
		input 	[CLK_RATIO-1:0] txdata_in
	);
	
	reg	tx_en;
	reg	[7:0] tx_en_phase_cnt;	

    always @(negedge ioclk)  begin
        if (rst ) begin
            tx_en_phase_cnt <= 0;
        end
        else begin
				tx_en_phase_cnt <= tx_en_phase_cnt+1;
        end
    end	

	
    always @(negedge ioclk)  begin
        if (rst ) begin
            tx_en <= 0;
        end
        else begin
			if (tx_en_phase_cnt > 82)	
				tx_en <= 1;
			else
				tx_en <= tx_en;
        end
    end	

	reg [$clog2(CLK_RATIO)-1:0] tx_shift_phase_cnt;


    always @(posedge ioclk)  begin
        if (rst ) begin
            tx_shift_phase_cnt <= 3;
        end
        else begin
			if (tx_en)
				tx_shift_phase_cnt <= tx_shift_phase_cnt + 1;
			else
				tx_shift_phase_cnt <= tx_shift_phase_cnt;
        end
    end	

	assign Serial_Data_Out= txdata_in[tx_shift_phase_cnt] & tx_en ;
	assign txclk = ioclk&tx_en;		//use negedge to avoid glitch in txclk.
	
endmodule	


	

code - delay_line.v

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 06/06/2023 03:37:37 PM
// Design Name: 
// Module Name: delay_line
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module dly_line #(
        parameter SHIFT_DEPTH = 13
    )
    (
        input dlyclk,
        input dly_in,
        input rst,
        output dly_out
    );
    
    reg [SHIFT_DEPTH-1:0] ShiftReg;
    

    assign    dly_out =  ShiftReg[SHIFT_DEPTH-1];
    always @(posedge dlyclk) begin
        if (rst) begin
            ShiftReg <= 0;
        end 
        else begin
            ShiftReg[0] <= dly_in;
            ShiftReg[SHIFT_DEPTH-1:1] <= ShiftReg[SHIFT_DEPTH-2:0];
        end
        
    end 
endmodule

testbench

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 06/06/2023 03:38:53 PM
// Design Name: 
// Module Name: tb
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module tb#(
        parameter SHIFT_DEPTH = 13,
		parameter RxFIFO_DEPTH = 4,
		parameter CLK_RATIO = 4 
	)
	(

    );
	reg rst;
	reg ioclk;
	reg dlyclk;	
	reg coreclk_tx;
 	reg [CLK_RATIO-1:0] txdata_in;
 	
 	assign #3 Serial_Data_Out_by_assign_3ns = Serial_Data_Out;
 	assign #8 Serial_Data_Out_by_assign_8ns = Serial_Data_Out;
 	assign #13 Serial_Data_Out_by_assign_13ns = Serial_Data_Out;

 	assign #3 ioclk_by_assign_3ns = ioclk;
 	assign #8 ioclk_by_assign_8ns = ioclk;
 	assign #13 ioclk_by_assign_13ns = ioclk;


    fsic_io_serdes_tx_m2  #(
		.RxFIFO_DEPTH(RxFIFO_DEPTH),
		.CLK_RATIO(CLK_RATIO) 
    )		
    fsic_io_serdes_tx_m2_1(
    	.rst(rst),
    	.txclk(txclk),
    	.ioclk(ioclk),
    	.coreclk(coreclk_tx),
    	.Serial_Data_Out(Serial_Data_Out),
    	.txdata_in(txdata_in)
    );
    

    
    dly_line  #(
		.SHIFT_DEPTH(10) 
    )	
    dly_line_ioclk(
    	.rst(rst),
    	.dlyclk(dlyclk),
    	.dly_in(ioclk),
    	.dly_out(ioclk_delay)
    );

    dly_line  #(
		.SHIFT_DEPTH(10) 
    )	
    dly_line_Serial_Data_Out(
    	.rst(rst),
    	.dlyclk(dlyclk),
    	.dly_in(Serial_Data_Out),
    	.dly_out(Serial_Data_Out_delay)
    );

	reg[7:0]idx;
	
    initial begin
        rst = 1;
        dlyclk = 1;
        ioclk = 1;
        coreclk_tx = 1;

        #20;
		rst = 0;
		txdata_in = 0;

        #820;

        for(idx=0; idx<32; idx=idx+1)begin
    		#40
	        txdata_in = idx;
        end

		#200;

		$finish;
		
    end
    

    always #20 coreclk_tx = ~coreclk_tx;
    always #5 ioclk = ~ioclk;
    always #0.5 dlyclk = ~dlyclk;    

        
endmodule

root cause

issue 1: assign delay time issue

  • only delay 1ns to 5ns is correct, when delay time > 5ns then result is incorrect.
 	assign #1 ioclk_by_assign_1ns = ioclk;
 	assign #2 ioclk_by_assign_2ns = ioclk;
 	assign #3 ioclk_by_assign_3ns = ioclk;
 	assign #4 ioclk_by_assign_4ns = ioclk;
 	assign #5 ioclk_by_assign_5ns = ioclk;
 	assign #6 ioclk_by_assign_6ns = ioclk;
 	assign #7 ioclk_by_assign_7ns = ioclk;
 	assign #8 ioclk_by_assign_8ns = ioclk;
 	assign #9 ioclk_by_assign_9ns = ioclk;
 	assign #10 ioclk_by_assign_10ns = ioclk;
 	assign #11 ioclk_by_assign_11ns = ioclk;
 	assign #12 ioclk_by_assign_12ns = ioclk;
 	assign #13 ioclk_by_assign_13ns = ioclk;
 	assign #14 ioclk_by_assign_14ns = ioclk;
 	assign #15 ioclk_by_assign_15ns = ioclk;
 	assign #16 ioclk_by_assign_16ns = ioclk;
 	assign #17 ioclk_by_assign_17ns = ioclk;
 	assign #18 ioclk_by_assign_18ns = ioclk;
 	assign #19 ioclk_by_assign_19ns = ioclk;
 	assign #20 ioclk_by_assign_20ns = ioclk;

root cause of issue 1

  • the ioclok pulse width is 5ns then verilog filter the pulse when in Inertial delay models(default)

reference
http://twins.ee.nctu.edu.tw/courses/ip_core_04/resource_pdf/cummings_final.pdf

solution

  1. use 2 or more stages to assign delay time.
 	assign #1 ioclk_by_assign_1ns = ioclk;
 	assign #2 ioclk_by_assign_2ns = ioclk;
 	assign #3 ioclk_by_assign_3ns = ioclk;
 	assign #4 ioclk_by_assign_4ns = ioclk;
 	assign #5 ioclk_by_assign_5ns = ioclk;
 	assign #5 ioclk_by_assign_6ns = ioclk_by_assign_1ns;
 	assign #5 ioclk_by_assign_7ns = ioclk_by_assign_2ns;
 	assign #5 ioclk_by_assign_8ns = ioclk_by_assign_3ns;
 	assign #5 ioclk_by_assign_9ns = ioclk_by_assign_4ns;
 	assign #5 ioclk_by_assign_10ns = ioclk_by_assign_5ns;

Or

  1. use transport delay model(I don't know how to do in verilog), I do a lot of serach but not found example in vivado.

reference
https://www.xilinx.com/support/documents/sw_manuals/xilinx2022_1/ug900-vivado-logic-simulation.pdf

root cause issue 2: Serial_Data_Out_delay with glitch

update testbench code then pass

code with issue

        for(idx=0; idx<32; idx=idx+1)begin
    		#40
	        txdata_in = idx;
        end

method 1 : using @(posedge coreclk_tx);

        for(idx=0; idx<32; idx=idx+1)begin
    		@(posedge coreclk_tx);  //using @(posedge coreclk_tx)
    		//#40;
	        txdata_in = idx;
        end

method 2 : using Non-block assigment

        for(idx=0; idx<32; idx=idx+1)begin
    		#40;
	        txdata_in <= idx;        //using Non-block assigment
        end

method 3 : both method 1 and method 2

        for(idx=0; idx<32; idx=idx+1)begin
    		@(posedge coreclk_tx);    //using @(posedge coreclk_tx)
    		//#40;
	        txdata_in <= idx;    //using Non-block assigment
        end