# io_serdes.v ## Config register ### Config register write ``` // if both axi_awvalid_in=1 and axi_wvalid_in=1 then output axi_awready_out = 1 and axi_wready_out = 1 assign axi_awready_out = (axi_awvalid_in && axi_wvalid_in) ? 1 : 0; assign axi_wready_out = (axi_awvalid_in && axi_wvalid_in) ? 1 : 0; //write register always @(posedge axi_clk or negedge axi_reset_n) begin if ( !axi_reset_n ) begin rxen_ctl <= 0; txen_ctl <= 0; end else begin if ( axi_awvalid_in && axi_wvalid_in ) begin //when axi_awvalid_in=1 and axi_wvalid_in=1 means axi_awready_out=1 and axi_wready_out=1 if (axi_awaddr == 10'h000 && (axi_wstrb[0] == 1) ) begin //offset 0 rxen_ctl <= axi_wdata[0]; txen_ctl <= axi_wdata[1]; end else begin rxen_ctl <= rxen_ctl; txen_ctl <= txen_ctl; end end end end ``` ### Config register read ``` // io serdes always output axi_arready = 1 and don't care the axi_arvalid & axi_araddr // io serdes only support 2 register bits in offset 0. config read other address offset is reserved. assign axi_arready = 1; // io serdes always output axi_rvalid = 1 and axi_rdata = { 30'b0, txen_ctl, rxen_ctl } assign axi_rvalid = 1; assign axi_rdata = { 30'b0, txen_ctl, rxen_ctl }; ``` ### config read/write waveform ![](https://hackmd.io/_uploads/HkU6OFsFn.png) ## txclk ``` assign txclk = ioclk&txen; //use negedge to avoid glitch in txclk. ``` ## txen - txen use negedge to avoid glitch in txclk ``` reg txen; always @(negedge ioclk or negedge axis_rst_n) begin if ( !axis_rst_n ) begin txen <= 0; end else begin if ( (txen_ctl || rx_received_data) && phase_cnt == 3 ) // set txen=1 when timeout or rx_received_data==1 // if rx_received_data==1 before timeout, it means remote side txen is ealry then local side. // then we should set local site txen=1 to allow local site provide ready signal to remote side in tx path. // It is to avoid local site rx fifo full in axis switch. txen <= 1; else txen <= txen; end end ``` ### txclk waveform ![](https://hackmd.io/_uploads/B1xDkCsF2.png) ### txen_ctl before rx_received_data ![](https://hackmd.io/_uploads/rJdmD2RYh.png) ### txen_ctl after rx_received_data ![](https://hackmd.io/_uploads/BkvxDnRF2.png) ## TX Path - AS to IS ``` always @(posedge coreclk or negedge axis_rst_n) begin if ( !axis_rst_n || ~txen) 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 (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 as_is_tdata_buf <= as_is_tdata; as_is_tstrb_buf <= as_is_tstrb; as_is_tkeep_buf <= as_is_tkeep; as_is_tid_tuser_buf[3:2] <= as_is_tid; as_is_tid_tuser_buf[1:0] <= as_is_tuser; as_is_tlast_tvalid_tready_buf[2] <= as_is_tlast; as_is_tlast_tvalid_tready_buf[1] <= as_is_tvalid; as_is_tlast_tvalid_tready_buf[0] <= as_is_tready; end else begin as_is_tdata_buf <= as_is_tdata; as_is_tstrb_buf <= as_is_tstrb; as_is_tkeep_buf <= as_is_tkeep; as_is_tid_tuser_buf[3:2] <= as_is_tid; as_is_tid_tuser_buf[1:0] <= as_is_tuser; as_is_tlast_tvalid_tready_buf[2] <= as_is_tlast; as_is_tlast_tvalid_tready_buf[1] <= 0; // set as_is_tvalid =0 to remote side as_is_tlast_tvalid_tready_buf[0] <= as_is_tready; end end end ``` ### TX Path Wavefrom - first data transfer in bule line. ![](https://hackmd.io/_uploads/HkSIFzaYh.png) ## is_as_tready_out - avoid dead lock issue - // when txen==1 and still not recevies data from remote side then set is_as_tready_out=1 to avoid dead lock issue. ``` reg is_as_tready_out; assign is_as_tready = is_as_tready_out; always @(posedge coreclk or negedge axis_rst_n) begin if ( !axis_rst_n || !txen ) begin is_as_tready_out <= 0; //set is_as_tready_out=0 when txen == 0 end else begin if (rx_received_data == 0) is_as_tready_out <= 1; // when txen==1 and still not recevies data from remote side then set is_as_tready_out=1 to avoid dead lock issue. else is_as_tready_out <= is_as_tready_remote; // when txen == 1 and rx_received_data==1 (received data from remote side) then is_as_tready_out come from is_as_tready_remote (remote side) end end ``` ![](https://hackmd.io/_uploads/BkkJiMaFh.png) ## Serial_Data_Out_tdata ``` genvar j; generate for (j=0; j<8; j=j+1 ) begin assign Serial_Data_Out_tdata[j] = as_is_tdata_buf[j*4+tx_shift_phase_cnt] & txen ; end endgenerate ``` ![](https://hackmd.io/_uploads/BJyz2zpK3.png) ## RX Path - IS to AS ### rxen ``` always @(negedge ioclk or negedge axis_rst_n) begin if ( !axis_rst_n ) begin rxen <= 0; end else begin if (rxen_ctl) rxen <= 1; else rxen <= rxen; end end ``` ### fsic_io_serdes_rx ``` genvar i; generate for (i=0; i<8; i=i+1 ) begin fsic_io_serdes_rx #( .pRxFIFO_DEPTH(pRxFIFO_DEPTH), .pCLK_RATIO(pCLK_RATIO) ) fsic_io_serdes_rx_tdata( .axis_rst_n(axis_rst_n), .rxclk(rxclk), .rxen(rxen), .ioclk(ioclk), .coreclk(coreclk), .Serial_Data_in(Serial_Data_In_tdata[i]), .rxdata_out(is_as_tdata[i*4+3:i*4]) // .rxdata_out_valid(rxdata_out_valid) ); end endgenerate fsic_io_serdes_rx #( .pRxFIFO_DEPTH(pRxFIFO_DEPTH), .pCLK_RATIO(pCLK_RATIO) ) fsic_io_serdes_rx_tstrb( .axis_rst_n(axis_rst_n), .rxclk(rxclk), .rxen(rxen), .ioclk(ioclk), .coreclk(coreclk), .Serial_Data_in(Serial_Data_In_tstrb), .rxdata_out(is_as_tstrb) // .rxdata_out_valid(rxdata_out_valid) ); fsic_io_serdes_rx #( .pRxFIFO_DEPTH(pRxFIFO_DEPTH), .pCLK_RATIO(pCLK_RATIO) ) fsic_io_serdes_rx_tkeep( .axis_rst_n(axis_rst_n), .rxclk(rxclk), .rxen(rxen), .ioclk(ioclk), .coreclk(coreclk), .Serial_Data_in(Serial_Data_In_tkeep), .rxdata_out(is_as_tkeep) // .rxdata_out_valid(rxdata_out_valid) ); fsic_io_serdes_rx #( .pRxFIFO_DEPTH(pRxFIFO_DEPTH), .pCLK_RATIO(pCLK_RATIO) ) fsic_io_serdes_rx_tid_tuser( .axis_rst_n(axis_rst_n), .rxclk(rxclk), .rxen(rxen), .ioclk(ioclk), .coreclk(coreclk), .Serial_Data_in(Serial_Data_In_tid_tuser), .rxdata_out( {is_as_tid[1:0], is_as_tuser[1:0]}) // .rxdata_out_valid(rxdata_out_valid) ); wire rx_received_data; fsic_io_serdes_rx #( .pRxFIFO_DEPTH(pRxFIFO_DEPTH), .pCLK_RATIO(pCLK_RATIO) ) fsic_io_serdes_rx_fc( .axis_rst_n(axis_rst_n), .rxclk(rxclk), .rxen(rxen), .ioclk(ioclk), .coreclk(coreclk), .Serial_Data_in(Serial_Data_In_tlast_tvalid_tready), .rxdata_out( {is_as_tlast, is_as_tvalid, is_as_tready_remote}), // only connect [2:0] .rxdata_out_valid(rx_received_data) ); ``` - rx_received_data from rxdata_out_valid ## force FPGA de-assert as_is_tready to simulate defect Rx buffer <=7 (new code in https://github.com/bol-edu/fsic_fpga/commit/a87d4c9781aa4916eafa6cf12c511e7ada2ffb63) - Step 1. force FPGA de-assert as_is_tready to simulate defect Rx buffer <=7 - Step 2. SOC detect is_as_tready = 0 - Step 3. SOC output as_is_tlast_tvalid_tready_buf[1] = 0 - Step 4. FPGA still received 8 clocks of data after Step 1 ![](https://hackmd.io/_uploads/BydRuaoch.png)