eth_phy_10g_tx_if_code

/*

  

Copyright (c) 2018 Alex Forencich

  

Permission is hereby granted, free of charge, to any person obtaining a copy

of this software and associated documentation files (the "Software"), to deal

in the Software without restriction, including without limitation the rights

to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

copies of the Software, and to permit persons to whom the Software is

furnished to do so, subject to the following conditions:

  

The above copyright notice and this permission notice shall be included in

all copies or substantial portions of the Software.

  

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY

FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

THE SOFTWARE.

  

*/

  

// Language: Verilog 2001

  

`resetall

`timescale 1ns / 1ps

`default_nettype none

  

/*

 * 10G Ethernet PHY TX IF

 */

module eth_phy_10g_tx_if #

(

    parameter DATA_WIDTH = 64,                  //! Ancho de datos

    parameter CTRL_WIDTH = (DATA_WIDTH/8),      //! Ancho de control

    parameter HDR_WIDTH = 2,                    //! Ancho de header

    parameter BIT_REVERSE = 0,                  //! Flag que habilita la inversión de bits

    parameter SCRAMBLER_DISABLE = 0,            //! Flag que habilita el scrambler

    parameter PRBS31_ENABLE = 0,                //! Flag que habilita la generacion de patrones pseudoaleatorios PRBS31

    parameter SERDES_PIPELINE = 0               //! Flag que habilita el uso de pipeline en el SERDES

)

(

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

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

  

    /*

     * 10GBASE-R encoded interface

     */

    input  wire [DATA_WIDTH-1:0] encoded_tx_data,           //! Datos codificados para la transmisión

    input  wire [HDR_WIDTH-1:0]  encoded_tx_hdr,            //! Encabezados de los datos codificados

  

    /*

     * SERDES interface

     */

    output wire [DATA_WIDTH-1:0] serdes_tx_data,            //! Datos de salida para el SERDES

    output wire [HDR_WIDTH-1:0]  serdes_tx_hdr,             //! Encabezado de salida para el SERDES

  

    /*

     * Configuration

     */

    input  wire                  cfg_tx_prbs31_enable       //! Señal de habilitación para la generación de secuencias 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

  

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

wire [57:0] scrambler_state;                    //! Estado del scrambler.

wire [DATA_WIDTH-1:0] scrambled_data;           //! Datos obtenidos luego de aplicar el scrambling.

  

reg [30:0] prbs31_state_reg = 31'h7fffffff;     //! Registro para el estado del generador PRBS31. Lo inicializa en 31 unos

wire [30:0] prbs31_state;                       //! Estado del generador PRBS31.

wire [DATA_WIDTH+HDR_WIDTH-1:0] prbs31_data;    //! Datos generados por el generador PRBS31.

  

reg [DATA_WIDTH-1:0] serdes_tx_data_reg = {DATA_WIDTH{1'b0}};   //! Registro que almacena los datos que se enviarán al transmisor SERDES

reg [HDR_WIDTH-1:0] serdes_tx_hdr_reg = {HDR_WIDTH{1'b0}};      //! Registro que almacena el encabezado que se enviará al transmisor SERDES

  

wire [DATA_WIDTH-1:0] serdes_tx_data_int;                       //! Datos del transmisor SERDES

wire [HDR_WIDTH-1:0]  serdes_tx_hdr_int;                        //! Encabezado del transmisor SERDES    

  

generate

    genvar n;

  

    if (BIT_REVERSE) begin  // si BIT_REVERSE está activado, los datos y el encabezado se asignan de manera inversa a serdes_tx_data_int y serdes_tx_hdr_int

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

            assign serdes_tx_data_int[n] = serdes_tx_data_reg[DATA_WIDTH-n-1];

        end

  

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

            assign serdes_tx_hdr_int[n] = serdes_tx_hdr_reg[HDR_WIDTH-n-1];

        end

    end else begin

        assign serdes_tx_data_int = serdes_tx_data_reg;

        assign serdes_tx_hdr_int = serdes_tx_hdr_reg;

    end

  

    if (SERDES_PIPELINE > 0) begin  // si SERDES_PIPELINE > 0, implementa un pipeline en serue para serdes_Tx_data y serdes_tx_hdr

        (* srl_style = "register" *)

        reg [DATA_WIDTH-1:0] serdes_tx_data_pipe_reg[SERDES_PIPELINE-1:0];  // registros para almacenar los datos del pipeline de tamaño SERDES_PIPELINE.

        (* srl_style = "register" *)

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

  

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

            initial begin

                serdes_tx_data_pipe_reg[n] <= {DATA_WIDTH{1'b0}};       // inicializa los registros de pipeline en cero en el primer ciclo

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

            end

  

            always @(posedge clk) begin     // en el primer ciclo de reloj, el registro de pipeline toma el valor de serdes_tx_data_int, en los que sigue toma el valor del registro anterior

                serdes_tx_data_pipe_reg[n] <= n == 0 ? serdes_tx_data_int : serdes_tx_data_pipe_reg[n-1];

                serdes_tx_hdr_pipe_reg[n] <= n == 0 ? serdes_tx_hdr_int : serdes_tx_hdr_pipe_reg[n-1];

            end

        end

  

        assign serdes_tx_data = serdes_tx_data_pipe_reg[SERDES_PIPELINE-1]; // Asigna los valores del último registro del pipeline a los buses de salida serdes_tx_data y serdes_tx_hdr

        assign serdes_tx_hdr = serdes_tx_hdr_pipe_reg[SERDES_PIPELINE-1];

    end else begin

        assign serdes_tx_data = serdes_tx_data_int; // Si SERDES_PIPELINE es cero, los buses de salida se asignan directamente a serdes_tx_data_int y serdes_tx_hdr_int

        assign serdes_tx_hdr = serdes_tx_hdr_int;

    end

  

endgenerate

  

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

lfsr #(

    .LFSR_WIDTH(58),

    .LFSR_POLY(58'h8000000001),

    .LFSR_CONFIG("FIBONACCI"),

    .LFSR_FEED_FORWARD(0),

    .REVERSE(1),

    .DATA_WIDTH(DATA_WIDTH),

    .STYLE("AUTO")

)

scrambler_inst (

    .data_in(encoded_tx_data),

    .state_in(scrambler_state_reg),

    .data_out(scrambled_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(0),

    .REVERSE(1),

    .DATA_WIDTH(DATA_WIDTH+HDR_WIDTH),

    .STYLE("AUTO")

)

prbs31_gen_inst (

    .data_in({DATA_WIDTH+HDR_WIDTH{1'b0}}),

    .state_in(prbs31_state_reg),

    .data_out(prbs31_data),

    .state_out(prbs31_state)

);

  

//! Actualiza los registros en cada flanco positivo del clock

always @(posedge clk) begin

    scrambler_state_reg <= scrambler_state; // Actualiza el estado del LFSR scrambler_state_reg con el estado actual del módulo LFSR scrambler_state.

  

    if (PRBS31_ENABLE && cfg_tx_prbs31_enable) begin    // si PRBS31 esta habilitado, los datos que se envían son de PRBS31

        prbs31_state_reg <= prbs31_state;  

  

        serdes_tx_data_reg <= ~prbs31_data[DATA_WIDTH+HDR_WIDTH-1:HDR_WIDTH];   // le asigna a serdes_tx_data_reg la negación de bits de prbs31_data sin incluir el header

        serdes_tx_hdr_reg <= ~prbs31_data[HDR_WIDTH-1:0];           //

    end else begin                  // si PRBS31 no esta habilitado, los datos que se envían son de scramble o encoded si SCRAMBLER_DISABLE está en 1

        serdes_tx_data_reg <= SCRAMBLER_DISABLE ? encoded_tx_data : scrambled_data;

        serdes_tx_hdr_reg <= encoded_tx_hdr;

    end

end

  

endmodule

  

`resetall