---
# System prepended metadata

title: FPGA provide both coreclk and ioclk to FSIC_SOC - Hold time issue
tags: [fsic, transfer done, verilog]

---

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

