###### 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
2. 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
```
