xgmii_baser_dec_64_code

// Language: Verilog 2001

  

`resetall

`timescale 1ns / 1ps

`default_nettype none

  

/*

 * XGMII 10GBASE-R decoder

 */

module xgmii_baser_dec_64 #

(

    parameter DATA_WIDTH = 64,              //! Ancho de datos

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

    parameter HDR_WIDTH = 2                 //! Ancho de header

)

(

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

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

  

    /*

     * 10GBASE-R encoded input

     */

    input  wire [DATA_WIDTH-1:0] encoded_rx_data,   //! Datos de entrada codificados

    input  wire [HDR_WIDTH-1:0]  encoded_rx_hdr,    //! Encabezado de entrada codificado

  

    /*

     * XGMII interface

     */

    output wire [DATA_WIDTH-1:0] xgmii_rxd,     //! Salida de datos para XGMII

    output wire [CTRL_WIDTH-1:0] xgmii_rxc,     //! Salida de control para XGMII

  

    /*

     * Status

     */

    output wire                  rx_bad_block,      //! Salida de estado para indicar bloques invalidos

    output wire                  rx_sequence_error  //! Salida de estado para indicar errores de secuencia

);

  

// bus width assertions

initial begin

    if (DATA_WIDTH != 64) begin

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

        $finish;

    end

  

    if (CTRL_WIDTH * 8 != DATA_WIDTH) begin

        $error("Error: Interface requires byte (8-bit) granularity");

        $finish;

    end

  

    if (HDR_WIDTH != 2) begin

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

        $finish;

    end

end

  

localparam [7:0]        // Codigos de control XGMII (tabla 49-1, pagina 11)

    XGMII_IDLE   = 8'h07,   //! XGMII Control Code para caracter de control idle

    XGMII_LPI    = 8'h06,   //! XGMII Control Code para caracter de control LPI

    XGMII_START  = 8'hfb,   //! XGMII Control Code para caracter de control start

    XGMII_TERM   = 8'hfd,   //! XGMII Control Code para caracter de control terminate

    XGMII_ERROR  = 8'hfe,   //! XGMII Control Code para caracter de control error

    XGMII_SEQ_OS = 8'h9c,   //! XGMII Control Code para caracter de control Sequence ordered set

    XGMII_RES_0  = 8'h1c,   //! XGMII Control Code para caracter de control reserved0

    XGMII_RES_1  = 8'h3c,   //! XGMII Control Code para caracter de control reserved1

    XGMII_RES_2  = 8'h7c,   //! XGMII Control Code para caracter de control reserved2

    XGMII_RES_3  = 8'hbc,   //! XGMII Control Code para caracter de control reserved3

    XGMII_RES_4  = 8'hdc,   //! XGMII Control Code para caracter de control reserved4

    XGMII_RES_5  = 8'hf7,   //! XGMII Control Code para caracter de control reserved5

    XGMII_SIG_OS = 8'h5c;   //! XGMII Control Code para caracter de control Signal ordered set

  

localparam [6:0]        // Codigos de Control 10GBASE-R (tabla 49-1, pagina 11)

    CTRL_IDLE  = 7'h00,     //! 10GBASE-R Control Code para caracter de control idle

    CTRL_LPI   = 7'h06,     //! 10GBASE-R Control Code para caracter de control LPI

    CTRL_ERROR = 7'h1e,     //! 10GBASE-R Control Code para caracter de control error

    CTRL_RES_0 = 7'h2d,     //! 10GBASE-R Control Code para caracter de control reserved0

    CTRL_RES_1 = 7'h33,     //! 10GBASE-R Control Code para caracter de control reserved1

    CTRL_RES_2 = 7'h4b,     //! 10GBASE-R Control Code para caracter de control reserved2

    CTRL_RES_3 = 7'h55,     //! 10GBASE-R Control Code para caracter de control reserved3

    CTRL_RES_4 = 7'h66,     //! 10GBASE-R Control Code para caracter de control reserved4

    CTRL_RES_5 = 7'h78;     //! 10GBASE-R Control Code para caracter de control reserved5

  

localparam [3:0]        // Codigo O 10GBASE-R (tabla 49-1, pagina 11)

    O_SEQ_OS = 4'h0,        //! 10GBASE-R O Code para caracter de control Sequence ordered set

    O_SIG_OS = 4'hf;        //! 10GBASE-R O Code para caracter de control Signal ordered set

  

localparam [1:0]

    SYNC_DATA = 2'b10,      //! Header de Sincronizacion para bloque de datos

    SYNC_CTRL = 2'b01;      //! Header de Sincronizacion para bloque de control

  

localparam [7:0]    // block formarts 64b/66b (figura 49-7, pagina 10)

    BLOCK_TYPE_CTRL     = 8'h1e, //! C7 C6 C5 C4 C3 C2 C1 C0 BT

    BLOCK_TYPE_OS_4     = 8'h2d, //! D7 D6 D5 O4 C3 C2 C1 C0 BT

    BLOCK_TYPE_START_4  = 8'h33, //! D7 D6 D5    C3 C2 C1 C0 BT

    BLOCK_TYPE_OS_START = 8'h66, //! D7 D6 D5    O0 D3 D2 D1 BT

    BLOCK_TYPE_OS_04    = 8'h55, //! D7 D6 D5 O4 O0 D3 D2 D1 BT

    BLOCK_TYPE_START_0  = 8'h78, //! D7 D6 D5 D4 D3 D2 D1    BT

    BLOCK_TYPE_OS_0     = 8'h4b, //! C7 C6 C5 C4 O0 D3 D2 D1 BT

    BLOCK_TYPE_TERM_0   = 8'h87, //! C7 C6 C5 C4 C3 C2 C1    BT

    BLOCK_TYPE_TERM_1   = 8'h99, //! C7 C6 C5 C4 C3 C2    D0 BT

    BLOCK_TYPE_TERM_2   = 8'haa, //! C7 C6 C5 C4 C3    D1 D0 BT

    BLOCK_TYPE_TERM_3   = 8'hb4, //! C7 C6 C5 C4    D2 D1 D0 BT

    BLOCK_TYPE_TERM_4   = 8'hcc, //! C7 C6 C5    D3 D2 D1 D0 BT

    BLOCK_TYPE_TERM_5   = 8'hd2, //! C7 C6    D4 D3 D2 D1 D0 BT

    BLOCK_TYPE_TERM_6   = 8'he1, //! C7    D5 D4 D3 D2 D1 D0 BT

    BLOCK_TYPE_TERM_7   = 8'hff; //!    D6 D5 D4 D3 D2 D1 D0 BT

  

reg [DATA_WIDTH-1:0] decoded_ctrl;  //! Registro para almacenar control decodificado

reg [CTRL_WIDTH-1:0] decode_err;    //! Registro para almacenar errores en decodificacion

  

reg [DATA_WIDTH-1:0] xgmii_rxd_reg = {DATA_WIDTH{1'b0}}, xgmii_rxd_next;    //! Registro para almacenar la salida de datos de XGMII

reg [CTRL_WIDTH-1:0] xgmii_rxc_reg = {CTRL_WIDTH{1'b0}}, xgmii_rxc_next;    //! Registro para almacenar la salida de control de XGMII

  

reg rx_bad_block_reg = 1'b0, rx_bad_block_next;             //! Registro para almacenar el estado de bloques incorrectos

reg rx_sequence_error_reg = 1'b0, rx_sequence_error_next;   //! Registro para almacenar el estado de errores de secuencia

reg frame_reg = 1'b0, frame_next;                           //! Registro para indicar el inicio de un nuevo marco de datos

  

assign xgmii_rxd = xgmii_rxd_reg;  

assign xgmii_rxc = xgmii_rxc_reg;

  

assign rx_bad_block = rx_bad_block_reg;

assign rx_sequence_error = rx_sequence_error_reg;

  

integer i;

  

//! Recibe los datos y los decodifica segun el caso que corresponda y los diferentes codigos para los diferentes estados

always @* begin

    xgmii_rxd_next = {8{XGMII_ERROR}};      // el siguiente valor de salida de datos es 8 veces XGMII_ERROR (error en la transmision)

    xgmii_rxc_next = 8'hff;         // el siguiente valor de salida de control es FF (valor de control predeterminado o invalido)

    rx_bad_block_next = 1'b0;           // inicializa el registro de estado de error a 0

    rx_sequence_error_next = 1'b0;      // inicializa el registro de error de secuencia en 0

    frame_next = frame_reg;         // asigna el siguiente frame al actual frame

  

    for (i = 0; i < CTRL_WIDTH; i = i + 1) begin    // se iteran sobre los bytes de encoded_rx_data para decodificar el control correspondiente para cada byte

        case (encoded_rx_data[7*i+8 +: 7])

            CTRL_IDLE: begin

                decoded_ctrl[8*i +: 8] = XGMII_IDLE;

                decode_err[i] = 1'b0;

            end

            CTRL_LPI: begin

                decoded_ctrl[8*i +: 8] = XGMII_LPI;

                decode_err[i] = 1'b0;

            end

            CTRL_ERROR: begin

                decoded_ctrl[8*i +: 8] = XGMII_ERROR;

                decode_err[i] = 1'b0;

            end

            CTRL_RES_0: begin

                decoded_ctrl[8*i +: 8] = XGMII_RES_0;

                decode_err[i] = 1'b0;

            end

            CTRL_RES_1: begin

                decoded_ctrl[8*i +: 8] = XGMII_RES_1;

                decode_err[i] = 1'b0;

            end

            CTRL_RES_2: begin

                decoded_ctrl[8*i +: 8] = XGMII_RES_2;

                decode_err[i] = 1'b0;

            end

            CTRL_RES_3: begin

                decoded_ctrl[8*i +: 8] = XGMII_RES_3;

                decode_err[i] = 1'b0;

            end

            CTRL_RES_4: begin

                decoded_ctrl[8*i +: 8] = XGMII_RES_4;

                decode_err[i] = 1'b0;

            end

            CTRL_RES_5: begin

                decoded_ctrl[8*i +: 8] = XGMII_RES_5;

                decode_err[i] = 1'b0;

            end

            default: begin

                decoded_ctrl[8*i +: 8] = XGMII_ERROR;

                decode_err[i] = 1'b1;

            end

        endcase

    end

  

    // use only four bits of block type for reduced fanin

    if (encoded_rx_hdr[0] == 0) begin       // si el bit mas significativo del encabezado es cero, se trata de un bloque de datos

        xgmii_rxd_next = encoded_rx_data;   // se actualiza xgmii_rxd

        xgmii_rxc_next = 8'h00;         // se reinicia xgmii_rxc

        rx_bad_block_next = 1'b0;       // se reomocoa rx_bad_block

    end else begin              // si el bit mas significativo del encabezado no es cero, se trata de un bloque de control

        case (encoded_rx_data[7:4])     // se determina el tipo de bloque de control y se realiza la decodificacion correspondiente

            BLOCK_TYPE_CTRL[7:4]: begin

                // C7 C6 C5 C4 C3 C2 C1 C0 BT

                xgmii_rxd_next = decoded_ctrl;

                xgmii_rxc_next = 8'hff;

                rx_bad_block_next = decode_err != 0;

            end

            BLOCK_TYPE_OS_4[7:4]: begin

                // D7 D6 D5 O4 C3 C2 C1 C0 BT

                xgmii_rxd_next[31:0] = decoded_ctrl[31:0];

                xgmii_rxc_next[3:0] = 4'hf;

                xgmii_rxd_next[63:40] = encoded_rx_data[63:40];

                xgmii_rxc_next[7:4] = 4'h1;

                if (encoded_rx_data[39:36] == O_SEQ_OS) begin

                    xgmii_rxd_next[39:32] = XGMII_SEQ_OS;

                    rx_bad_block_next = decode_err[3:0] != 0;

                end else begin

                    xgmii_rxd_next[39:32] = XGMII_ERROR;

                    rx_bad_block_next = 1'b1;

                end

            end

            BLOCK_TYPE_START_4[7:4]: begin

                // D7 D6 D5    C3 C2 C1 C0 BT

                xgmii_rxd_next = {encoded_rx_data[63:40], XGMII_START, decoded_ctrl[31:0]};

                xgmii_rxc_next = 8'h1f;

                rx_bad_block_next = decode_err[3:0] != 0;

                rx_sequence_error_next = frame_reg;

                frame_next = 1'b1;

            end

            BLOCK_TYPE_OS_START[7:4]: begin

                // D7 D6 D5    O0 D3 D2 D1 BT

                xgmii_rxd_next[31:8] = encoded_rx_data[31:8];

                xgmii_rxc_next[3:0] = 4'hf;

                if (encoded_rx_data[35:32] == O_SEQ_OS) begin

                    xgmii_rxd_next[7:0] = XGMII_SEQ_OS;

                    rx_bad_block_next = 1'b0;

                end else begin

                    xgmii_rxd_next[7:0] = XGMII_ERROR;

                    rx_bad_block_next = 1'b1;

                end

                xgmii_rxd_next[63:32] = {encoded_rx_data[63:40], XGMII_START};

                xgmii_rxc_next[7:4] = 4'h1;

                rx_sequence_error_next = frame_reg;

                frame_next = 1'b1;

            end

            BLOCK_TYPE_OS_04[7:4]: begin

                // D7 D6 D5 O4 O0 D3 D2 D1 BT

                rx_bad_block_next = 1'b0;

                xgmii_rxd_next[31:8] = encoded_rx_data[31:8];

                xgmii_rxc_next[3:0] = 4'h1;

                if (encoded_rx_data[35:32] == O_SEQ_OS) begin

                    xgmii_rxd_next[7:0] = XGMII_SEQ_OS;

                end else begin

                    xgmii_rxd_next[7:0] = XGMII_ERROR;

                    rx_bad_block_next = 1'b1;

                end

                xgmii_rxd_next[63:40] = encoded_rx_data[63:40];

                xgmii_rxc_next[7:4] = 4'h1;

                if (encoded_rx_data[39:36] == O_SEQ_OS) begin

                    xgmii_rxd_next[39:32] = XGMII_SEQ_OS;

                end else begin

                    xgmii_rxd_next[39:32] = XGMII_ERROR;

                    rx_bad_block_next = 1'b1;

                end

            end

            BLOCK_TYPE_START_0[7:4]: begin

                // D7 D6 D5 D4 D3 D2 D1    BT

                xgmii_rxd_next = {encoded_rx_data[63:8], XGMII_START};

                xgmii_rxc_next = 8'h01;

                rx_bad_block_next = 1'b0;

                rx_sequence_error_next = frame_reg;

                frame_next = 1'b1;

            end

            BLOCK_TYPE_OS_0[7:4]: begin

                // C7 C6 C5 C4 O0 D3 D2 D1 BT

                xgmii_rxd_next[31:8] = encoded_rx_data[31:8];

                xgmii_rxc_next[3:0] = 4'h1;

                if (encoded_rx_data[35:32] == O_SEQ_OS) begin

                    xgmii_rxd_next[7:0] = XGMII_SEQ_OS;

                    rx_bad_block_next = decode_err[7:4] != 0;

                end else begin

                    xgmii_rxd_next[7:0] = XGMII_ERROR;

                    rx_bad_block_next = 1'b1;

                end

                xgmii_rxd_next[63:32] = decoded_ctrl[63:32];

                xgmii_rxc_next[7:4] = 4'hf;

            end

            BLOCK_TYPE_TERM_0[7:4]: begin

                // C7 C6 C5 C4 C3 C2 C1    BT

                xgmii_rxd_next = {decoded_ctrl[63:8], XGMII_TERM};

                xgmii_rxc_next = 8'hff;

                rx_bad_block_next = decode_err[7:1] != 0;

                rx_sequence_error_next = !frame_reg;

                frame_next = 1'b0;

            end

            BLOCK_TYPE_TERM_1[7:4]: begin

                // C7 C6 C5 C4 C3 C2    D0 BT

                xgmii_rxd_next = {decoded_ctrl[63:16], XGMII_TERM, encoded_rx_data[15:8]};

                xgmii_rxc_next = 8'hfe;

                rx_bad_block_next = decode_err[7:2] != 0;

                rx_sequence_error_next = !frame_reg;

                frame_next = 1'b0;

            end

            BLOCK_TYPE_TERM_2[7:4]: begin

                // C7 C6 C5 C4 C3    D1 D0 BT

                xgmii_rxd_next = {decoded_ctrl[63:24], XGMII_TERM, encoded_rx_data[23:8]};

                xgmii_rxc_next = 8'hfc;

                rx_bad_block_next = decode_err[7:3] != 0;

                rx_sequence_error_next = !frame_reg;

                frame_next = 1'b0;

            end

            BLOCK_TYPE_TERM_3[7:4]: begin

                // C7 C6 C5 C4    D2 D1 D0 BT

                xgmii_rxd_next = {decoded_ctrl[63:32], XGMII_TERM, encoded_rx_data[31:8]};

                xgmii_rxc_next = 8'hf8;

                rx_bad_block_next = decode_err[7:4] != 0;

                rx_sequence_error_next = !frame_reg;

                frame_next = 1'b0;

            end

            BLOCK_TYPE_TERM_4[7:4]: begin

                // C7 C6 C5    D3 D2 D1 D0 BT

                xgmii_rxd_next = {decoded_ctrl[63:40], XGMII_TERM, encoded_rx_data[39:8]};

                xgmii_rxc_next = 8'hf0;

                rx_bad_block_next = decode_err[7:5] != 0;

                rx_sequence_error_next = !frame_reg;

                frame_next = 1'b0;

            end

            BLOCK_TYPE_TERM_5[7:4]: begin

                // C7 C6    D4 D3 D2 D1 D0 BT

                xgmii_rxd_next = {decoded_ctrl[63:48], XGMII_TERM, encoded_rx_data[47:8]};

                xgmii_rxc_next = 8'he0;

                rx_bad_block_next = decode_err[7:6] != 0;

                rx_sequence_error_next = !frame_reg;

                frame_next = 1'b0;

            end

            BLOCK_TYPE_TERM_6[7:4]: begin

                // C7    D5 D4 D3 D2 D1 D0 BT

                xgmii_rxd_next = {decoded_ctrl[63:56], XGMII_TERM, encoded_rx_data[55:8]};

                xgmii_rxc_next = 8'hc0;

                rx_bad_block_next = decode_err[7] != 0;

                rx_sequence_error_next = !frame_reg;

                frame_next = 1'b0;

            end

            BLOCK_TYPE_TERM_7[7:4]: begin

                //    D6 D5 D4 D3 D2 D1 D0 BT

                xgmii_rxd_next = {XGMII_TERM, encoded_rx_data[63:8]};

                xgmii_rxc_next = 8'h80;

                rx_bad_block_next = 1'b0;

                rx_sequence_error_next = !frame_reg;

                frame_next = 1'b0;

            end

            default: begin              // en caso que no corresponda con ningun tipo de bloque, el bloque es invalido y se asignan valores predeterminados de error

                // invalid block type

                xgmii_rxd_next = {8{XGMII_ERROR}};

                xgmii_rxc_next = 8'hff;

                rx_bad_block_next = 1'b1;

            end

        endcase

    end

  

    // check all block type bits to detect bad encodings, se realiza una verificacion de los bits de tipo de bloque para detectar codificaciones incorrectas

    if (encoded_rx_hdr == SYNC_DATA) begin      // si el encabezado es de datos (no hace nada)

    end else if (encoded_rx_hdr == SYNC_CTRL) begin // si el encabezado es de control

        case (encoded_rx_data[7:0])         // case de los bits que representan el tipo de bloques

            BLOCK_TYPE_CTRL: begin end          // si coincide con cualquiera de los tipos de bloques predefinidos sale del case indicando que no hay error en el tipo de bloque

            BLOCK_TYPE_OS_4: begin end

            BLOCK_TYPE_START_4: begin end

            BLOCK_TYPE_OS_START: begin end

            BLOCK_TYPE_OS_04: begin end

            BLOCK_TYPE_START_0: begin end

            BLOCK_TYPE_OS_0: begin end

            BLOCK_TYPE_TERM_0: begin end

            BLOCK_TYPE_TERM_1: begin end

            BLOCK_TYPE_TERM_2: begin end

            BLOCK_TYPE_TERM_3: begin end

            BLOCK_TYPE_TERM_4: begin end

            BLOCK_TYPE_TERM_5: begin end

            BLOCK_TYPE_TERM_6: begin end

            BLOCK_TYPE_TERM_7: begin end

            default: begin              // si no coincide con ninguno de los tipos de bloques predefinidos indica error

                // invalid block type

                xgmii_rxd_next = {8{XGMII_ERROR}};

                xgmii_rxc_next = 8'hff;

                rx_bad_block_next = 1'b1;

            end

        endcase

    end else begin                  // si el encabezado no es ni de datos ni de control tambien se indica error

        // invalid header

        xgmii_rxd_next = {8{XGMII_ERROR}};

        xgmii_rxc_next = 8'hff;

        rx_bad_block_next = 1'b1;

    end

end

  

always @(posedge clk) begin     //! En cada flanco positivo de clock se actualizan los registros y se verifica si hubo un reset

    xgmii_rxd_reg <= xgmii_rxd_next;

    xgmii_rxc_reg <= xgmii_rxc_next;

  

    rx_bad_block_reg <= rx_bad_block_next;

    rx_sequence_error_reg <= rx_sequence_error_next;

    frame_reg <= frame_next;

  

    if (rst) begin

        frame_reg <= 1'b0;

    end

end

  

endmodule

  

`resetall