// Language: Verilog 2001
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* XGMII 10GBASE-R encoder
*/
module xgmii_baser_enc_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
/*
* XGMII interface
*/
input wire [DATA_WIDTH-1:0] xgmii_txd, //! Datos de entrada XGMII
input wire [CTRL_WIDTH-1:0] xgmii_txc, //! Señales de control XGMII
/*
* 10GBASE-R encoded interface
*/
output wire [DATA_WIDTH-1:0] encoded_tx_data, //! Datos codificados
output wire [HDR_WIDTH-1:0] encoded_tx_hdr, //! Encabezado codificado
/*
* Status
*/
output wire tx_bad_block //! Flag que indica si hay un bloque de transmision defectuoso
);
// 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*7/8-1:0] encoded_ctrl; //! Registro para almacenar control codificado
reg [CTRL_WIDTH-1:0] encode_err; //! Registro para almacenar errores en codificacion
reg [DATA_WIDTH-1:0] encoded_tx_data_reg = {DATA_WIDTH{1'b0}}, encoded_tx_data_next; //! Registro para almacenar los datos de salida codificado.
reg [HDR_WIDTH-1:0] encoded_tx_hdr_reg = {HDR_WIDTH{1'b0}}, encoded_tx_hdr_next; //! Registro para almacenar el header de salida codificado.
reg tx_bad_block_reg = 1'b0, tx_bad_block_next; //! Registro para indicar si hay un bloque de transmisión defectuoso.
assign encoded_tx_data = encoded_tx_data_reg; // conecta la salida codificada de datps al exterior del modulo
assign encoded_tx_hdr = encoded_tx_hdr_reg; // conecta la salida del header codificado al exterior del modulo
assign tx_bad_block = tx_bad_block_reg; // señal externa que indica si hay un bloque de transmision defectuoso
integer i;
//! Codifica los datos según el caso correspondientes y los respectos codigos para cada caso
always @* begin
tx_bad_block_next = 1'b0; // se inicializa en 0 la señal que indica si el siguiente bloque es defectuoso
for (i = 0; i < CTRL_WIDTH; i = i + 1) begin
if (xgmii_txc[i]) begin
// control
case (xgmii_txd[8*i +: 8]) // evalua el tipo de control segun el codigo de control
XGMII_IDLE: begin
encoded_ctrl[7*i +: 7] = CTRL_IDLE;
encode_err[i] = 1'b0;
end
XGMII_LPI: begin
encoded_ctrl[7*i +: 7] = CTRL_LPI;
encode_err[i] = 1'b0;
end
XGMII_ERROR: begin
encoded_ctrl[7*i +: 7] = CTRL_ERROR;
encode_err[i] = 1'b0;
end
XGMII_RES_0: begin
encoded_ctrl[7*i +: 7] = CTRL_RES_0;
encode_err[i] = 1'b0;
end
XGMII_RES_1: begin
encoded_ctrl[7*i +: 7] = CTRL_RES_1;
encode_err[i] = 1'b0;
end
XGMII_RES_2: begin
encoded_ctrl[7*i +: 7] = CTRL_RES_2;
encode_err[i] = 1'b0;
end
XGMII_RES_3: begin
encoded_ctrl[7*i +: 7] = CTRL_RES_3;
encode_err[i] = 1'b0;
end
XGMII_RES_4: begin
encoded_ctrl[7*i +: 7] = CTRL_RES_4;
encode_err[i] = 1'b0;
end
XGMII_RES_5: begin
encoded_ctrl[7*i +: 7] = CTRL_RES_5;
encode_err[i] = 1'b0;
end
default: begin
encoded_ctrl[7*i +: 7] = CTRL_ERROR;
encode_err[i] = 1'b1;
end
endcase
end else begin
// data (always invalid as control)
encoded_ctrl[7*i +: 7] = CTRL_ERROR;
encode_err[i] = 1'b1;
end
end
if (xgmii_txc == 8'h00) begin // todos los bits de control estan en cero
encoded_tx_data_next = xgmii_txd; // se pasa xgmii_txd al siguiente ciclo de reloj
encoded_tx_hdr_next = SYNC_DATA; // se establece que el encabezado es de tipo data
tx_bad_block_next = 1'b0; // no hay ningun bloque malo en esta secuencia de datos
end else begin // al menos uno de los bits de control no está en cero
if (xgmii_txc == 8'h1f && xgmii_txd[39:32] == XGMII_SEQ_OS) begin // si el tipo de control es XGMII_SEQ_OS
// ordered set in lane 4
encoded_tx_data_next = {xgmii_txd[63:40], O_SEQ_OS, encoded_ctrl[27:0], BLOCK_TYPE_OS_4};
tx_bad_block_next = encode_err[3:0] != 0;
end else if (xgmii_txc == 8'h1f && xgmii_txd[39:32] == XGMII_START) begin
// start in lane 4
encoded_tx_data_next = {xgmii_txd[63:40], 4'd0, encoded_ctrl[27:0], BLOCK_TYPE_START_4};
tx_bad_block_next = encode_err[3:0] != 0;
end else if (xgmii_txc == 8'h11 && xgmii_txd[7:0] == XGMII_SEQ_OS && xgmii_txd[39:32] == XGMII_START) begin
// ordered set in lane 0, start in lane 4
encoded_tx_data_next = {xgmii_txd[63:40], 4'd0, O_SEQ_OS, xgmii_txd[31:8], BLOCK_TYPE_OS_START};
tx_bad_block_next = 1'b0;
end else if (xgmii_txc == 8'h11 && xgmii_txd[7:0] == XGMII_SEQ_OS && xgmii_txd[39:32] == XGMII_SEQ_OS) begin
// ordered set in lane 0 and lane 4
encoded_tx_data_next = {xgmii_txd[63:40], O_SEQ_OS, O_SEQ_OS, xgmii_txd[31:8], BLOCK_TYPE_OS_04};
tx_bad_block_next = 1'b0;
end else if (xgmii_txc == 8'h01 && xgmii_txd[7:0] == XGMII_START) begin
// start in lane 0
encoded_tx_data_next = {xgmii_txd[63:8], BLOCK_TYPE_START_0};
tx_bad_block_next = 1'b0;
end else if (xgmii_txc == 8'hf1 && xgmii_txd[7:0] == XGMII_SEQ_OS) begin
// ordered set in lane 0
encoded_tx_data_next = {encoded_ctrl[55:28], O_SEQ_OS, xgmii_txd[31:8], BLOCK_TYPE_OS_0};
tx_bad_block_next = encode_err[7:4] != 0;
end else if (xgmii_txc == 8'hff && xgmii_txd[7:0] == XGMII_TERM) begin
// terminate in lane 0
encoded_tx_data_next = {encoded_ctrl[55:7], 7'd0, BLOCK_TYPE_TERM_0};
tx_bad_block_next = encode_err[7:1] != 0;
end else if (xgmii_txc == 8'hfe && xgmii_txd[15:8] == XGMII_TERM) begin
// terminate in lane 1
encoded_tx_data_next = {encoded_ctrl[55:14], 6'd0, xgmii_txd[7:0], BLOCK_TYPE_TERM_1};
tx_bad_block_next = encode_err[7:2] != 0;
end else if (xgmii_txc == 8'hfc && xgmii_txd[23:16] == XGMII_TERM) begin
// terminate in lane 2
encoded_tx_data_next = {encoded_ctrl[55:21], 5'd0, xgmii_txd[15:0], BLOCK_TYPE_TERM_2};
tx_bad_block_next = encode_err[7:3] != 0;
end else if (xgmii_txc == 8'hf8 && xgmii_txd[31:24] == XGMII_TERM) begin
// terminate in lane 3
encoded_tx_data_next = {encoded_ctrl[55:28], 4'd0, xgmii_txd[23:0], BLOCK_TYPE_TERM_3};
tx_bad_block_next = encode_err[7:4] != 0;
end else if (xgmii_txc == 8'hf0 && xgmii_txd[39:32] == XGMII_TERM) begin
// terminate in lane 4
encoded_tx_data_next = {encoded_ctrl[55:35], 3'd0, xgmii_txd[31:0], BLOCK_TYPE_TERM_4};
tx_bad_block_next = encode_err[7:5] != 0;
end else if (xgmii_txc == 8'he0 && xgmii_txd[47:40] == XGMII_TERM) begin
// terminate in lane 5
encoded_tx_data_next = {encoded_ctrl[55:42], 2'd0, xgmii_txd[39:0], BLOCK_TYPE_TERM_5};
tx_bad_block_next = encode_err[7:6] != 0;
end else if (xgmii_txc == 8'hc0 && xgmii_txd[55:48] == XGMII_TERM) begin
// terminate in lane 6
encoded_tx_data_next = {encoded_ctrl[55:49], 1'd0, xgmii_txd[47:0], BLOCK_TYPE_TERM_6};
tx_bad_block_next = encode_err[7] != 0;
end else if (xgmii_txc == 8'h80 && xgmii_txd[63:56] == XGMII_TERM) begin
// terminate in lane 7
encoded_tx_data_next = {xgmii_txd[55:0], BLOCK_TYPE_TERM_7};
tx_bad_block_next = 1'b0;
end else if (xgmii_txc == 8'hff) begin
// all control
encoded_tx_data_next = {encoded_ctrl, BLOCK_TYPE_CTRL};
tx_bad_block_next = encode_err != 0;
end else begin
// no corresponding block format
encoded_tx_data_next = {{8{CTRL_ERROR}}, BLOCK_TYPE_CTRL};
tx_bad_block_next = 1'b1;
end
encoded_tx_hdr_next = SYNC_CTRL; // se establece que el encabezado es de tipo CONTROL
end
end
always @(posedge clk) begin //! En cada flanco positivo del clock se actualizan los registros con sus respectivos valores calculados en el bloque anterior
encoded_tx_data_reg <= encoded_tx_data_next;
encoded_tx_hdr_reg <= encoded_tx_hdr_next;
tx_bad_block_reg <= tx_bad_block_next;
end
endmodule
`resetall