Files
taxi/src/eth/rtl/taxi_xgmii_baser_dec.sv
Alex Forencich 5f814e7da8 Clean up always blocks
Signed-off-by: Alex Forencich <alex@alexforencich.com>
2025-11-07 01:51:18 -08:00

464 lines
16 KiB
Systemverilog

// SPDX-License-Identifier: CERN-OHL-S-2.0
/*
Copyright (c) 2018-2025 FPGA Ninja, LLC
Authors:
- Alex Forencich
*/
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* XGMII 10GBASE-R decoder
*/
module taxi_xgmii_baser_dec #
(
parameter DATA_W = 64,
parameter CTRL_W = (DATA_W/8),
parameter HDR_W = 2,
parameter logic GBX_IF_EN = 1'b0
)
(
input wire logic clk,
input wire logic rst,
/*
* 10GBASE-R encoded input
*/
input wire logic [DATA_W-1:0] encoded_rx_data,
input wire logic encoded_rx_data_valid = 1'b1,
input wire logic [HDR_W-1:0] encoded_rx_hdr,
input wire logic encoded_rx_hdr_valid = 1'b1,
/*
* XGMII interface
*/
output wire logic [DATA_W-1:0] xgmii_rxd,
output wire logic [CTRL_W-1:0] xgmii_rxc,
output wire logic xgmii_rx_valid,
/*
* Status
*/
output wire logic rx_bad_block,
output wire logic rx_sequence_error
);
localparam DATA_W_INT = 64;
localparam CTRL_W_INT = 8;
localparam SEG_CNT = DATA_W_INT / DATA_W;
// check configuration
if (DATA_W != 32 && DATA_W != 64)
$fatal(0, "Error: Interface width must be 32 or 64");
if (CTRL_W * 8 != DATA_W)
$fatal(0, "Error: Interface requires byte (8-bit) granularity");
if (HDR_W != 2)
$fatal(0, "Error: HDR_W must be 2");
localparam [7:0]
XGMII_IDLE = 8'h07,
XGMII_LPI = 8'h06,
XGMII_START = 8'hfb,
XGMII_TERM = 8'hfd,
XGMII_ERROR = 8'hfe,
XGMII_SEQ_OS = 8'h9c,
XGMII_RES_0 = 8'h1c,
XGMII_RES_1 = 8'h3c,
XGMII_RES_2 = 8'h7c,
XGMII_RES_3 = 8'hbc,
XGMII_RES_4 = 8'hdc,
XGMII_RES_5 = 8'hf7,
XGMII_SIG_OS = 8'h5c;
localparam [6:0]
CTRL_IDLE = 7'h00,
CTRL_LPI = 7'h06,
CTRL_ERROR = 7'h1e,
CTRL_RES_0 = 7'h2d,
CTRL_RES_1 = 7'h33,
CTRL_RES_2 = 7'h4b,
CTRL_RES_3 = 7'h55,
CTRL_RES_4 = 7'h66,
CTRL_RES_5 = 7'h78;
localparam [3:0]
O_SEQ_OS = 4'h0,
O_SIG_OS = 4'hf;
localparam [1:0]
SYNC_DATA = 2'b10,
SYNC_CTRL = 2'b01;
localparam [7:0]
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
wire [DATA_W_INT-1:0] encoded_rx_data_int;
wire encoded_rx_data_valid_int;
wire [HDR_W-1:0] encoded_rx_hdr_int;
logic [DATA_W_INT-1:0] decoded_ctrl;
logic [CTRL_W_INT-1:0] decode_err;
logic [DATA_W_INT-1:0] xgmii_rxd_reg = '0, xgmii_rxd_next;
logic [CTRL_W_INT-1:0] xgmii_rxc_reg = '0, xgmii_rxc_next;
logic [SEG_CNT-1:0] xgmii_rx_valid_reg = '0, xgmii_rx_valid_next;
logic rx_bad_block_reg = 1'b0, rx_bad_block_next;
logic rx_sequence_error_reg = 1'b0, rx_sequence_error_next;
logic frame_reg = 1'b0, frame_next;
assign xgmii_rxd = xgmii_rxd_reg[DATA_W-1:0];
assign xgmii_rxc = xgmii_rxc_reg[CTRL_W-1:0];
assign xgmii_rx_valid = GBX_IF_EN ? xgmii_rx_valid_reg[0] : 1'b1;
assign rx_bad_block = rx_bad_block_reg;
assign rx_sequence_error = rx_sequence_error_reg;
if (DATA_W == 64) begin : repack_in
assign encoded_rx_data_int = encoded_rx_data;
assign encoded_rx_data_valid_int = GBX_IF_EN ? encoded_rx_data_valid : 1'b1;
assign encoded_rx_hdr_int = encoded_rx_hdr;
end else begin : repack_in
logic [DATA_W_INT-DATA_W-1:0] encoded_rx_data_reg = '0;
logic encoded_rx_data_valid_reg = '0;
logic [HDR_W-1:0] encoded_rx_hdr_reg = '0;
assign encoded_rx_data_int = {encoded_rx_data, encoded_rx_data_reg};
assign encoded_rx_data_valid_int = encoded_rx_data_valid_reg && (GBX_IF_EN ? encoded_rx_data_valid : 1'b1);
assign encoded_rx_hdr_int = encoded_rx_hdr_reg;
always_ff @(posedge clk) begin
if (!GBX_IF_EN || encoded_rx_data_valid) begin
encoded_rx_data_reg <= encoded_rx_data;
encoded_rx_data_valid_reg <= encoded_rx_hdr_valid;
if (encoded_rx_hdr_valid) begin
encoded_rx_hdr_reg <= encoded_rx_hdr;
end
end
if (rst) begin
encoded_rx_data_valid_reg <= '0;
end
end
end
always_comb begin
xgmii_rxd_next = {CTRL_W_INT{XGMII_ERROR}};
xgmii_rxc_next = '1;
xgmii_rx_valid_next = '0;
rx_bad_block_next = 1'b0;
rx_sequence_error_next = 1'b0;
frame_next = frame_reg;
for (integer i = 0; i < CTRL_W_INT; i = i + 1) begin
case (encoded_rx_data_int[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
if (SEG_CNT > 1) begin
// repack output
// disable broken verilator linter (unreachable code by parameter value)
// verilator lint_off WIDTH
// verilator lint_off SELRANGE
xgmii_rxd_next = {{CTRL_W{XGMII_ERROR}}, xgmii_rxd_reg[DATA_W_INT-1:DATA_W]};
xgmii_rxc_next = {{CTRL_W{1'b1}}, xgmii_rxc_reg[CTRL_W_INT-1:CTRL_W]};
xgmii_rx_valid_next = {1'b0, xgmii_rx_valid_reg[SEG_CNT-1:1]};
// verilator lint_on WIDTH
// verilator lint_on SELRANGE
end
if (!encoded_rx_data_valid_int) begin
// wait for data
end else if (encoded_rx_hdr_int[0] == 0) begin
// data block
xgmii_rxd_next = encoded_rx_data_int;
xgmii_rxc_next = 8'h00;
xgmii_rx_valid_next = '1;
rx_bad_block_next = 1'b0;
end else begin
// control block
// use only four bits of block type for reduced fanin
xgmii_rx_valid_next = '1;
case (encoded_rx_data_int[7:4])
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_int[63:40];
xgmii_rxc_next[7:4] = 4'h1;
if (encoded_rx_data_int[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_int[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_int[31:8];
xgmii_rxc_next[3:0] = 4'h1;
if (encoded_rx_data_int[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_int[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_int[31:8];
xgmii_rxc_next[3:0] = 4'h1;
if (encoded_rx_data_int[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_int[63:40];
xgmii_rxc_next[7:4] = 4'h1;
if (encoded_rx_data_int[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_int[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_int[31:8];
xgmii_rxc_next[3:0] = 4'h1;
if (encoded_rx_data_int[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_int[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_int[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_int[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_int[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_int[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_int[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_int[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
// invalid block type
xgmii_rxd_next = {CTRL_W_INT{XGMII_ERROR}};
xgmii_rxc_next = '1;
rx_bad_block_next = 1'b1;
end
endcase
end
// check all block type bits to detect bad encodings
if (!encoded_rx_data_valid_int) begin
// wait for block
end else if (encoded_rx_hdr_int == SYNC_DATA) begin
// data - nothing encoded
end else if (encoded_rx_hdr_int == SYNC_CTRL) begin
// control - check for bad block types
case (encoded_rx_data_int[7:0])
BLOCK_TYPE_CTRL: begin end
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
// invalid block type
xgmii_rxd_next = {CTRL_W_INT{XGMII_ERROR}};
xgmii_rxc_next = '1;
rx_bad_block_next = 1'b1;
end
endcase
end else begin
// invalid header
xgmii_rxd_next = {CTRL_W_INT{XGMII_ERROR}};
xgmii_rxc_next = '1;
rx_bad_block_next = 1'b1;
end
end
always_ff @(posedge clk) begin
xgmii_rxd_reg <= xgmii_rxd_next;
xgmii_rxc_reg <= xgmii_rxc_next;
xgmii_rx_valid_reg <= xgmii_rx_valid_next;
rx_bad_block_reg <= rx_bad_block_next;
rx_sequence_error_reg <= rx_sequence_error_next;
frame_reg <= frame_next;
if (rst) begin
xgmii_rx_valid_reg <= '0;
frame_reg <= 1'b0;
end
end
endmodule
`resetall