eth_phy_10g_rx_if_code

// Language: Verilog 2001

  

`resetall

`timescale 1ns / 1ps

`default_nettype none

  

/*

 * 10G Ethernet PHY RX IF

 */

  

//! Modulo que controla los bloques del receptor con interfaz SERDES

module eth_phy_10g_rx_if #

(

    parameter DATA_WIDTH = 64,                                      //! Ancho de bus de datos

    parameter HDR_WIDTH = 2,                                        //! Ancho de bus de header

    parameter BIT_REVERSE = 0,                                      //! Flag para habilitar reversión de bits

    parameter SCRAMBLER_DISABLE = 0,                                //! Flag para habilitar scrambler

    parameter PRBS31_ENABLE = 0,                                    //! Flag para habilitar PRBS31

    parameter SERDES_PIPELINE = 0,                                  //! Flag para habilitar profundidad del pipeline

    parameter BITSLIP_HIGH_CYCLES = 1,                              //! Ciclos de bitslip alto

    parameter BITSLIP_LOW_CYCLES = 8,                               //! Ciclos de bitslip bajo

    parameter COUNT_125US = 125000/10                               //! Contador de 125 us

)

(

    input  wire                  clk,                               //! Señal del clock

    input  wire                  rst,                               //! Señal de reset

  

    /*

     *! 10GBASE-R encoded interface

     */

    output wire [DATA_WIDTH-1:0] encoded_rx_data,                   // Datos de salida codificados

    output wire [HDR_WIDTH-1:0]  encoded_rx_hdr,                    // Header de salida codificado

  

    /*

     *! SERDES interface

     */

    input  wire [DATA_WIDTH-1:0] serdes_rx_data,                    //! Entrada de bloques de datos interfaz serdes

    input  wire [HDR_WIDTH-1:0]  serdes_rx_hdr,                     //! Entrada del sync header interfaz serdes

    output wire                  serdes_rx_bitslip,                 //! Salida del bitslip

    output wire                  serdes_rx_reset_req,               //! Salida de solicitud de reinicio

  

    /*

     * Status

     */

    input  wire                  rx_bad_block,                      //! Flag de bloque con error

    input  wire                  rx_sequence_error,                 //! Flag de error de secuencia

    output wire [6:0]            rx_error_count,                    //! Contador de errores

    output wire                  rx_block_lock,                     //! Flag de bloque alineado

    output wire                  rx_high_ber,                       //! Flag de bit rate error alto

    output wire                  rx_status,                         //! Flag del estado del receptor

  

    /*

     * Configuration

     */

    input  wire                  cfg_rx_prbs31_enable               //! Entrada para habilitar la PRBS31

);

  

// Bus width assertions

initial begin

    if (DATA_WIDTH != 64) begin

        $error("Error: Interface width must be 64");

        $finish;

    end

  

    if (HDR_WIDTH != 2) begin

        $error("Error: HDR_WIDTH must be 2");

        $finish;

    end

end

  

wire [DATA_WIDTH-1:0] serdes_rx_data_rev, serdes_rx_data_int;                   //! Señales para procesar los datos del SERDES

wire [HDR_WIDTH-1:0]  serdes_rx_hdr_rev, serdes_rx_hdr_int;                     //! Señales para procesar el encabezado del SERDES

  

generate

    genvar n;

  

    if (BIT_REVERSE) begin                                                      //! Si BIT_REVERSE está activado, se invierten el orden de los bits de los datos y el encabezado en serdes_rx_data_int y serdes_rx_hdr_int

        for (n = 0; n < DATA_WIDTH; n = n + 1) begin

            assign serdes_rx_data_rev[n] = serdes_rx_data[DATA_WIDTH-n-1];

        end

  

        for (n = 0; n < HDR_WIDTH; n = n + 1) begin

            assign serdes_rx_hdr_rev[n] = serdes_rx_hdr[HDR_WIDTH-n-1];

        end

    end else begin

        assign serdes_rx_data_rev = serdes_rx_data;

        assign serdes_rx_hdr_rev = serdes_rx_hdr;

    end

  

    if (SERDES_PIPELINE > 0) begin                                              //! Si SERDES_PIPELINE > 0, implementa un pipeline en serie para serdes_rx_data y serdes_rx_hdr

        (* srl_style = "register" *)

        reg [DATA_WIDTH-1:0] serdes_rx_data_pipe_reg[SERDES_PIPELINE-1:0];      // crea tantos registros como profundidad tiene el pipeline

        (* srl_style = "register" *)

        reg [HDR_WIDTH-1:0]  serdes_rx_hdr_pipe_reg[SERDES_PIPELINE-1:0];

  

        for (n = 0; n < SERDES_PIPELINE; n = n + 1) begin

            initial begin

                serdes_rx_data_pipe_reg[n] <= {DATA_WIDTH{1'b0}};               // iniciamente coloca el valor de los registros en 0

                serdes_rx_hdr_pipe_reg[n] <= {HDR_WIDTH{1'b0}};

            end

  

            always @(posedge clk) begin

                serdes_rx_data_pipe_reg[n] <= n == 0 ? serdes_rx_data_rev : serdes_rx_data_pipe_reg[n-1]; //si n es igual a 0, a la data del pipeline le asigna data_rev, en caso contrario deja la misma

                //! Se asignan los datos por las diferentes etapas del pipeline

                serdes_rx_hdr_pipe_reg[n] <= n == 0 ? serdes_rx_hdr_rev : serdes_rx_hdr_pipe_reg[n-1];

            end

        end

  

        assign serdes_rx_data_int = serdes_rx_data_pipe_reg[SERDES_PIPELINE-1]; // la salida final es el utimo registro del pipeline del serdes

        assign serdes_rx_hdr_int = serdes_rx_hdr_pipe_reg[SERDES_PIPELINE-1];

    end else begin

        assign serdes_rx_data_int = serdes_rx_data_rev;

        assign serdes_rx_hdr_int = serdes_rx_hdr_rev;

    end

  

endgenerate

  

wire [DATA_WIDTH-1:0] descrambled_rx_data;                      //! Almacena los datos descifrados despues del proceso de descambler

  

reg [DATA_WIDTH-1:0] encoded_rx_data_reg = {DATA_WIDTH{1'b0}};  //! Registro para almacenar los datos codificados

reg [HDR_WIDTH-1:0] encoded_rx_hdr_reg = {HDR_WIDTH{1'b0}};     //! Registro para almacenar el encabezado codificado

  

reg [57:0] scrambler_state_reg = {58{1'b1}};                    //! Registro de estado del scrambler

wire [57:0] scrambler_state;                    

  

reg [30:0] prbs31_state_reg = 31'h7fffffff;                     //! Estado del generador de PRBS31

wire [30:0] prbs31_state;

wire [DATA_WIDTH+HDR_WIDTH-1:0] prbs31_data;                    //! Almacena los datos de salida del generador PRBS31

reg [DATA_WIDTH+HDR_WIDTH-1:0] prbs31_data_reg = 0;

  

//! Contadores de errores

reg [6:0] rx_error_count_reg = 0;  

reg [5:0] rx_error_count_1_reg = 0;

reg [5:0] rx_error_count_2_reg = 0;

reg [5:0] rx_error_count_1_temp = 0;

reg [5:0] rx_error_count_2_temp = 0;

  

//! Instancia un módulo LFSR (Linear Feedback Shift Register) llamado para el scrambler

lfsr #(

    .LFSR_WIDTH(58),

    .LFSR_POLY(58'h8000000001),

    .LFSR_CONFIG("FIBONACCI"),

    .LFSR_FEED_FORWARD(1),

    .REVERSE(1),

    .DATA_WIDTH(DATA_WIDTH),

    .STYLE("AUTO")

)

descrambler_inst (

    .data_in(serdes_rx_data_int),

    .state_in(scrambler_state_reg),

    .data_out(descrambled_rx_data),

    .state_out(scrambler_state)

);

  

//! Instancia un módulo LFSR (Linear Feedback Shift Register) para la generación de PRBS31

lfsr #(

    .LFSR_WIDTH(31),

    .LFSR_POLY(31'h10000001),

    .LFSR_CONFIG("FIBONACCI"),

    .LFSR_FEED_FORWARD(1),

    .REVERSE(1),

    .DATA_WIDTH(DATA_WIDTH+HDR_WIDTH),

    .STYLE("AUTO")

)

prbs31_check_inst (

    .data_in(~{serdes_rx_data_int, serdes_rx_hdr_int}),

    .state_in(prbs31_state_reg),

    .data_out(prbs31_data),

    .state_out(prbs31_state)

);

  

integer i;

  

always @* begin  //! Calcula el conteo de errores a partir de los datos del generador PRBS31, actualiza los registros de error_count

    rx_error_count_1_temp = 0;

    rx_error_count_2_temp = 0;

    for (i = 0; i < DATA_WIDTH+HDR_WIDTH; i = i + 1) begin

        if (i & 1) begin

            rx_error_count_1_temp = rx_error_count_1_temp + prbs31_data_reg[i]; // cuenta la cantidad de bits en alto cuando i es impar

        end else begin

            rx_error_count_2_temp = rx_error_count_2_temp + prbs31_data_reg[i]; // cuenta la cantidad de bits en alto cuando i es par

        end

    end

end

  

always @(posedge clk) begin //! En cada flanco positivo del clock se actualizan los registros y si PRBS31 está activado calcula el conteo de errores acumulativo

    scrambler_state_reg <= scrambler_state;

  

    encoded_rx_data_reg <= SCRAMBLER_DISABLE ? serdes_rx_data_int : descrambled_rx_data; // si no esta activado el scrambler, el registro tiene el valor de serdes, de lo contrario tiene el valos de los datos de descrambled

    encoded_rx_hdr_reg <= serdes_rx_hdr_int;

  

    if (PRBS31_ENABLE) begin

        if (cfg_rx_prbs31_enable) begin

            prbs31_state_reg <= prbs31_state;

            prbs31_data_reg <= prbs31_data;

        end else begin

            prbs31_data_reg <= 0;

        end

  

        rx_error_count_1_reg <= rx_error_count_1_temp; // coloca el error temp en el conteo de error

        rx_error_count_2_reg <= rx_error_count_2_temp;

        rx_error_count_reg <= rx_error_count_1_reg + rx_error_count_2_reg;

    end else begin

        rx_error_count_reg <= 0;

    end

end

  

assign encoded_rx_data = encoded_rx_data_reg; //! Se asignan registros a las salidas correspondientes

assign encoded_rx_hdr = encoded_rx_hdr_reg;

  

assign rx_error_count = rx_error_count_reg;

  

wire serdes_rx_bitslip_int;

wire serdes_rx_reset_req_int;

assign serdes_rx_bitslip = serdes_rx_bitslip_int && !(PRBS31_ENABLE && cfg_rx_prbs31_enable);

assign serdes_rx_reset_req = serdes_rx_reset_req_int && !(PRBS31_ENABLE && cfg_rx_prbs31_enable);

  

//! Instancia un módulo de sincronizacion del frame

eth_phy_10g_rx_frame_sync #(

    .HDR_WIDTH(HDR_WIDTH),

    .BITSLIP_HIGH_CYCLES(BITSLIP_HIGH_CYCLES),

    .BITSLIP_LOW_CYCLES(BITSLIP_LOW_CYCLES)

)

eth_phy_10g_rx_frame_sync_inst (

    .clk(clk),

    .rst(rst),

    .serdes_rx_hdr(serdes_rx_hdr_int),

    .serdes_rx_bitslip(serdes_rx_bitslip_int),

    .rx_block_lock(rx_block_lock)

);

  

//! Instancia un módulo para monitorear el BER

eth_phy_10g_rx_ber_mon #(

    .HDR_WIDTH(HDR_WIDTH),

    .COUNT_125US(COUNT_125US)

)

eth_phy_10g_rx_ber_mon_inst (

    .clk(clk),

    .rst(rst),

    .serdes_rx_hdr(serdes_rx_hdr_int),

    .rx_high_ber(rx_high_ber)

);

  

//! Instancia un modulo para monitoreo de los errores y estado del receptor

eth_phy_10g_rx_watchdog #(

    .HDR_WIDTH(HDR_WIDTH),

    .COUNT_125US(COUNT_125US)

)

eth_phy_10g_rx_watchdog_inst (

    .clk(clk),

    .rst(rst),

    .serdes_rx_hdr(serdes_rx_hdr_int),

    .serdes_rx_reset_req(serdes_rx_reset_req_int),

    .rx_bad_block(rx_bad_block),

    .rx_sequence_error(rx_sequence_error),

    .rx_block_lock(rx_block_lock),

    .rx_high_ber(rx_high_ber),

    .rx_status(rx_status)

);

  

endmodule

  

`resetall