# Hold time issue the FPGA provide both coreclk and ioclk to FSIC_SOC, the skew of coreclk and ioclk maybe impact by FPGA output timining -> PCB -> FSIC_SOC input timing. ![](https://hackmd.io/_uploads/ryTxPIwnn.png) ## Rx Path hold time issue when ioclok before coreclk in fsic_io_serdes_rx, it may cause hold time issue in rx_shift_reg to rx_sync_fifo. use negdege ioclk to improve the hold time, but it sacrifice the setup time. ### Using posedge ioclk with hold time issue in Rx ``` always @(posedge ioclk or negedge axis_rst_n) begin rx_sync_fifo <= 0; rx_sync_fifo_valid <= 0; end else begin if (rx_start && rx_shift_reg_valid) begin rx_sync_fifo <= rx_shift_reg; rx_sync_fifo_valid <= 1; end else begin rx_sync_fifo <= rx_sync_fifo; rx_sync_fifo_valid <= rx_sync_fifo_valid; end end end ``` #### when soc_ioclk before soc_coreclk 1ns - found hold time issue - AS should get data = 0, but it get 1 in below waveform ![](https://hackmd.io/_uploads/r10Jdw9on.png) #### when soc_ioclk and soc_coreclk no skew - AS get data = 0, it is correct ![](https://hackmd.io/_uploads/r1uyuDcsn.png) #### when soc_ioclk after soc_coreclk 1ns - AS get data = 0, it is correct ![](https://hackmd.io/_uploads/S1Oa_Pcsn.png) ### Using negedge ioclk to fix hold time issue in Rx ``` always @(negedge ioclk or negedge axis_rst_n) begin rx_sync_fifo <= 0; rx_sync_fifo_valid <= 0; end else begin if (rx_start && rx_shift_reg_valid) begin rx_sync_fifo <= rx_shift_reg; rx_sync_fifo_valid <= 1; end else begin rx_sync_fifo <= rx_sync_fifo; rx_sync_fifo_valid <= rx_sync_fifo_valid; end end end ``` #### using negedge ioclk waveform ##### when soc_ioclk before soc_coreclk 1ns - issue fixed by negedge ioclk ![](https://hackmd.io/_uploads/ByOqkXRih.png) ## Tx Path hold time issue there are 2 hold time issue in tx path 1. phase_cnt issue 2. Serial_Data_Out_tdata issue ### phase_cnt issue in TX #### when soc_ioclk and soc_coreclk no skew - the waveform is ok ![](https://hackmd.io/_uploads/Hka6CDqin.png) #### when soc_ioclk after soc_coreclk 1ns - metastable issue when sample core_clk_toggle - phase_cnt result changed issue. ![](https://hackmd.io/_uploads/H15P6w5jh.png) ### Serial_Data_Out_tdata result issue in TX #### when soc_ioclk and soc_coreclk no skew ![](https://hackmd.io/_uploads/B1FZV_con.png) #### when soc_ioclk after soc_coreclk 1ns - data with giltch time issue caused by phase_cnt . ![](https://hackmd.io/_uploads/SJSlIO9j3.png) ### Soultion in TX ### avoid metastable issue in sample core_clk_toggle ``` reg pre_core_clk_toggle; reg sync_core_clk_toggle; always @(posedge ioclk or negedge axis_rst_n) begin if ( !axis_rst_n ) begin pre_core_clk_toggle <= 0; sync_core_clk_toggle <= 0; end else begin pre_core_clk_toggle <= core_clk_toggle; sync_core_clk_toggle <= pre_core_clk_toggle; //avoid metastable issue. end end always @(posedge ioclk or negedge axis_rst_n) begin if ( !axis_rst_n ) begin clk_seq <= 0; end else begin clk_seq[pCLK_RATIO-1:1] <= clk_seq[pCLK_RATIO-2:0]; clk_seq[0] <= sync_core_clk_toggle; end end ``` ### change phase_cnt ``` always @(posedge ioclk or negedge axis_rst_n) begin if ( !axis_rst_n) begin phase_cnt <= 0; end else begin if ( (clk_seq == 4'h3) || (clk_seq == 4'hc) ) phase_cnt <= 0; else phase_cnt <= phase_cnt + 1; end end ``` ![](https://hackmd.io/_uploads/BkMeHz0o3.png) ## use negedge to sample as_is_tdata - no metasable issue when using negedge to sample as_is_tdata ![](https://hackmd.io/_uploads/rJKxSJRi2.png) ``` reg [pDATA_WIDTH-1:0] pre_as_is_tdata_buf; reg [(pDATA_WIDTH/8)-1:0] pre_as_is_tstrb_buf; reg [(pDATA_WIDTH/8)-1:0] pre_as_is_tkeep_buf; reg [(pDATA_WIDTH/8)-1:0] pre_as_is_tid_tuser_buf; reg [(pDATA_WIDTH/8)-1:0] pre_as_is_tlast_tvalid_tready_buf; always @(negedge coreclk or negedge axis_rst_n) begin pre_as_is_tdata_buf <= as_is_tdata; pre_as_is_tstrb_buf <= as_is_tstrb; pre_as_is_tkeep_buf <= as_is_tkeep; pre_as_is_tid_tuser_buf[3:2] <= as_is_tid; pre_as_is_tid_tuser_buf[1:0] <= as_is_tuser; pre_as_is_tlast_tvalid_tready_buf[2] <= as_is_tlast; pre_as_is_tlast_tvalid_tready_buf[1] <= as_is_tvalid; pre_as_is_tlast_tvalid_tready_buf[0] <= as_is_tready; if ( !axis_rst_n || ~txen) begin pre_as_is_tdata_buf <= 0; pre_as_is_tstrb_buf <= 0; pre_as_is_tkeep_buf <= 0; pre_as_is_tid_tuser_buf <= 0; pre_as_is_tlast_tvalid_tready_buf <= 0; end else begin if (is_as_tready && as_is_tvalid) begin //data transfer from Axis siwtch to io serdes when is_as_tready=1 and as_is_tvalid=1 pre_as_is_tlast_tvalid_tready_buf[1] <= as_is_tvalid; end else begin pre_as_is_tlast_tvalid_tready_buf[1] <= 0; // set as_is_tvalid =0 to remote side end end end ``` ## update as_is_*_buf when phase_cnt == 3 ``` reg [pDATA_WIDTH-1:0] as_is_tdata_buf; reg [(pDATA_WIDTH/8)-1:0] as_is_tstrb_buf; reg [(pDATA_WIDTH/8)-1:0] as_is_tkeep_buf; reg [(pDATA_WIDTH/8)-1:0] as_is_tid_tuser_buf; reg [(pDATA_WIDTH/8)-1:0] as_is_tlast_tvalid_tready_buf; always @(posedge ioclk or negedge axis_rst_n) begin if ( !axis_rst_n ) begin as_is_tdata_buf <= 0; as_is_tstrb_buf <= 0; as_is_tkeep_buf <= 0; as_is_tid_tuser_buf <= 0; as_is_tlast_tvalid_tready_buf <= 0; end else begin if (phase_cnt == 3) begin //update as_is_*_buf when phase_cnt == 3 as_is_tdata_buf <= pre_as_is_tdata_buf; as_is_tstrb_buf <= pre_as_is_tstrb_buf; as_is_tkeep_buf <= pre_as_is_tkeep_buf; as_is_tid_tuser_buf <= pre_as_is_tid_tuser_buf; as_is_tlast_tvalid_tready_buf <= pre_as_is_tlast_tvalid_tready_buf; end end end ``` ## when soc_ioclk and soc_coreclk no skew ![](https://hackmd.io/_uploads/BkMeHz0o3.png) ## when soc_ioclk before soc_coreclk 1ns ![](https://hackmd.io/_uploads/SJY78fRon.png) ## when soc_ioclk after soc_coreclk 1ns - fix hold time issue ![](https://hackmd.io/_uploads/ByjF8fCo2.png)