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

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

#### when soc_ioclk and soc_coreclk no skew
- AS get data = 0, it is correct

#### when soc_ioclk after soc_coreclk 1ns
- AS get data = 0, it is correct

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

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

#### when soc_ioclk after soc_coreclk 1ns
- metastable issue when sample core_clk_toggle
- phase_cnt result changed issue.

### Serial_Data_Out_tdata result issue in TX
#### when soc_ioclk and soc_coreclk no skew

#### when soc_ioclk after soc_coreclk 1ns
- data with giltch time issue caused by phase_cnt .

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

## use negedge to sample as_is_tdata
- no metasable issue when using negedge to sample as_is_tdata

```
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

## when soc_ioclk before soc_coreclk 1ns

## when soc_ioclk after soc_coreclk 1ns
- fix hold time issue
