Source code for hdmi.cores.receiver.serdes_1_to_5

from myhdl import block, instance


@block
[docs]def serdes_1_to_5(use_phase_detector, data_in_p, data_in_n, rx_io_clock, rx_serdes_strobe, reset, g_clock, bit_slip, data_out, diff_term='TRUE', bit_slip_enable='TRUE', sim_tap_delay = 49): """ The block converts the serial data into a 5 bit parallel data. This block will be replaced with the xilinx primitives IODELAY2 and ISERDES2 during conversion. Args: use_phase_detector: The signal is used by the xilinx primitive data_in_p: The input differential data data_in_n: The input differential data rx_io_clock: The clock from the input side (serial data) rx_serdes_strobe: The signal is used by the xilinx primitive reset: The signal is used by the xilinx primitive g_clock: The clock on the output side (parallel data) bit_slip: The signal is used by the xilinx primitive data_out: The output parallel data (5-bit) diff_term: The parameter is used by the xilinx primitive bit_slip_enable: The parameter is used by the xilinx primitive sim_tap_delay: The parameter is used by the xilinx primitive Returns: myhdl.instances() : A list of myhdl instances. """ data = ['0' for _ in range(5)] @instance def deserialize(): while True: yield rx_io_clock.posedge data.append('1' if data_in_p else '0') data.pop(0) @instance def assign(): while True: yield g_clock.posedge data_out.next = int(''.join(data[::-1]), 2) return deserialize, assign
serdes_1_to_5.verilog_code = """ assign busy_data = busys ; assign cal_data_slave = cal_data_sint ; ///////////////////////////////////////////////// // // IDELAY Calibration FSM // ///////////////////////////////////////////////// always @ (posedge $g_clock or posedge $reset) begin if ($reset == 1'b1) begin state <= 0 ; cal_data_master <= 1'b0 ; cal_data_sint <= 1'b0 ; counter <= 9'h000 ; enable <= 1'b0 ; mux <= 1'h1 ; end else begin counter <= counter + 9'h001 ; if (counter[8] == 1'b1) begin counter <= 9'h000 ; end if (counter[5] == 1'b1) begin enable <= 1'b1 ; end if (state == 0 && enable == 1'b1) begin // Wait for IODELAY to be available cal_data_master <= 1'b0 ; cal_data_sint <= 1'b0 ; rst_data <= 1'b0 ; if (busy_data_d == 1'b0) begin state <= 1 ; end end else if (state == 1) begin // Issue calibrate command to both master and slave, needed for simulation, not for the silicon cal_data_master <= 1'b1 ; cal_data_sint <= 1'b1 ; if (busy_data_d == 1'b1) begin // and wait for command to be accepted state <= 2 ; end end else if (state == 2) begin // Now RST master and slave IODELAYs needed for simulation, not for the silicon cal_data_master <= 1'b0 ; cal_data_sint <= 1'b0 ; if (busy_data_d == 1'b0) begin rst_data <= 1'b1 ; state <= 3 ; end end else if (state == 3) begin // Wait for IODELAY to be available rst_data <= 1'b0 ; if (busy_data_d == 1'b0) begin state <= 4 ; end end else if (state == 4) begin // Wait for occasional enable if (counter[8] == 1'b1) begin state <= 5 ; end end else if (state == 5) begin // Calibrate slave only if (busy_data_d == 1'b0) begin cal_data_sint <= 1'b1 ; state <= 6 ; end end else if (state == 6) begin // Wait for command to be accepted cal_data_sint <= 1'b0 ; if (busy_data_d == 1'b1) begin state <= 7 ; end end else if (state == 7) begin // Wait for all IODELAYs to be available, ie CAL command finished cal_data_sint <= 1'b0 ; if (busy_data_d == 1'b0) begin state <= 4 ; end end end end always @ (posedge $g_clock or posedge $reset) // Per-bit phase detection state machine begin if ($reset == 1'b1) begin pdcounter <= 5'b1000 ; ce_data_inta <= 1'b0 ; flag <= 1'b0 ; // flag is there to only allow one inc or dec per cal (test) end else begin busy_data_d <= busy_data_or[1] ; if ($use_phase_detector == 1'b1) begin // decide whther pd is used incdec_data_d <= incdec_data_or[1] ; valid_data_d <= valid_data_or[1] ; if (ce_data_inta == 1'b1) begin ce_data = mux ; end else begin ce_data = 64'h0000000000000000 ; end if (state == 7) begin flag <= 1'b0 ; end else if (state != 4 || busy_data_d == 1'b1) begin // Reset filter if state machine issues a cal command or unit is busy pdcounter <= 5'b10000 ; ce_data_inta <= 1'b0 ; end else if (pdcounter == 5'b11111 && flag == 1'b0) begin // Filter has reached positive max - increment the tap count ce_data_inta <= 1'b1 ; inc_data_int <= 1'b1 ; pdcounter <= 5'b10000 ; flag <= 1'b1 ; end else if (pdcounter == 5'b00000 && flag == 1'b0) begin // Filter has reached negative max - decrement the tap count ce_data_inta <= 1'b1 ; inc_data_int <= 1'b0 ; pdcounter <= 5'b10000 ; flag <= 1'b1 ; end else if (valid_data_d == 1'b1) begin // increment filter ce_data_inta <= 1'b0 ; if (incdec_data_d == 1'b1 && pdcounter != 5'b11111) begin pdcounter <= pdcounter + 5'b00001 ; end else if (incdec_data_d == 1'b0 && pdcounter != 5'b00000) begin // decrement filter pdcounter <= pdcounter + 5'b11111 ; end end else begin ce_data_inta <= 1'b0 ; end end else begin ce_data = all_ce ; inc_data_int = debug_in[1] ; end end end assign inc_data = inc_data_int ; assign incdec_data_or[0] = 1'b0 ; // Input Mux - Initialise generate loop OR gates assign valid_data_or[0] = 1'b0 ; assign busy_data_or[0] = 1'b0 ; assign incdec_data_im = incdec_data & mux; // Input muxes assign incdec_data_or[1] = incdec_data_im | incdec_data_or; // AND gates to allow just one signal through at a tome assign valid_data_im = valid_data & mux; // followed by an OR assign valid_data_or[1] = valid_data_im | valid_data_or; // for the three inputs from each PD assign busy_data_or[1] = busy_data | busy_data_or; // The busy signals just need an OR gate assign all_ce = debug_in[0] ; IBUFDS #( .DIFF_TERM ("$diff_term")) data_in ( .I ($data_in_p), .IB ($data_in_n), .O (rx_data_in) ); // // Master IDELAY // IODELAY2 #( .DATA_RATE ("SDR"), .IDELAY_VALUE (0), .IDELAY2_VALUE (0), .IDELAY_MODE ("NORMAL" ), .ODELAY_VALUE (0), .IDELAY_TYPE ("DIFF_PHASE_DETECTOR"), .COUNTER_WRAPAROUND ("STAY_AT_LIMIT"), //("WRAPAROUND"), .DELAY_SRC ("IDATAIN"), .SERDES_MODE ("MASTER"), .SIM_TAPDELAY_VALUE ($sim_tap_delay) ) iodelay_m ( .IDATAIN (rx_data_in), // data from IBUFDS .TOUT (), // tri-state signal to IOB .DOUT (), // output data to IOB .T (1'b1), // tri-state control from OLOGIC/OSERDES2 .ODATAIN (1'b0), // data from OLOGIC/OSERDES2 .DATAOUT (ddly_m), // Output data 1 to ILOGIC/ISERDES2 .DATAOUT2 (), // Output data 2 to ILOGIC/ISERDES2 .IOCLK0 ($rx_io_clock), // High speed clock for calibration .IOCLK1 (1'b0), // High speed clock for calibration .CLK ($g_clock), // Fabric clock (GCLK) for control signals .CAL (cal_data_master), // Calibrate control signal .INC (inc_data), // Increment counter .CE (ce_data), // Clock Enable .RST (rst_data), // Reset delay line .BUSY () // output signal indicating sync circuit has finished / calibration has finished ); // // Slave IDELAY // IODELAY2 #( .DATA_RATE ("SDR"), .IDELAY_VALUE (0), .IDELAY2_VALUE (0), .IDELAY_MODE ("NORMAL" ), .ODELAY_VALUE (0), .IDELAY_TYPE ("DIFF_PHASE_DETECTOR"), .COUNTER_WRAPAROUND ("WRAPAROUND"), .DELAY_SRC ("IDATAIN"), .SERDES_MODE ("SLAVE"), .SIM_TAPDELAY_VALUE ($sim_tap_delay) ) iodelay_s ( .IDATAIN (rx_data_in), // data from IBUFDS .TOUT (), // tri-state signal to IOB .DOUT (), // output data to IOB .T (1'b1), // tri-state control from OLOGIC/OSERDES2 .ODATAIN (1'b0), // data from OLOGIC/OSERDES2 .DATAOUT (ddly_s), // Slave output data to ILOGIC/ISERDES2 .DATAOUT2 (), // .IOCLK0 ($rx_io_clock), // High speed IO clock for calibration .IOCLK1 (1'b0), .CLK ($g_clock), // Fabric clock (GCLK) for control signals .CAL (cal_data_slave), // Calibrate control signal .INC (inc_data), // Increment counter .CE (ce_data), // Clock Enable .RST (rst_data), // Reset delay line .BUSY (busys) // output signal indicating sync circuit has finished / calibration has finished ); // // Master ISERDES // ISERDES2 #( .DATA_WIDTH (5), .DATA_RATE ("SDR"), .BITSLIP_ENABLE ("$bit_slip_enable"), .SERDES_MODE ("MASTER"), .INTERFACE_TYPE ("RETIMED")) iserdes_m ( .D (ddly_m), .CE0 (1'b1), .CLK0 ($rx_io_clock), .CLK1 (1'b0), .IOCE ($rx_serdes_strobe), .RST ($reset), .CLKDIV ($g_clock), .SHIFTIN (pd_edge), .BITSLIP ($bit_slip), .FABRICOUT (), .Q4 ($data_out[4]), .Q3 ($data_out[3]), .Q2 ($data_out[2]), .Q1 ($data_out[1]), .DFB (), .CFB0 (), .CFB1 (), .VALID (valid_data), .INCDEC (incdec_data), .SHIFTOUT (cascade)); // // Slave ISERDES // ISERDES2 #( .DATA_WIDTH (5), .DATA_RATE ("SDR"), .BITSLIP_ENABLE ("$bit_slip_enable"), .SERDES_MODE ("SLAVE"), .INTERFACE_TYPE ("RETIMED") ) iserdes_s ( .D (ddly_s), .CE0 (1'b1), .CLK0 ($rx_io_clock), .CLK1 (1'b0), .IOCE ($rx_serdes_strobe), .RST ($reset), .CLKDIV ($g_clock), .SHIFTIN (cascade), .BITSLIP ($bit_slip), .FABRICOUT (), .Q4 ($data_out[0]), .Q3 (), .Q2 (), .Q1 (), .DFB (), .CFB0 (), .CFB1 (), .VALID (), .INCDEC (), .SHIFTOUT (pd_edge)); always @ (posedge $g_clock or posedge $reset) begin if ($reset) rxpdcntr <= 8'h7f; else if (ce_data) if (inc_data) rxpdcntr <= rxpdcntr + 1'b1; else rxpdcntr <= rxpdcntr - 1'b1; end """