---
# System prepended metadata

title: FSIC IO SERDES code review - io_serdes.v
tags: [fsic, code trace, transfer done, verilog]

---

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