mirror of
https://github.com/corundum/corundum.git
synced 2025-01-16 08:12:53 +08:00
326 lines
11 KiB
Coq
326 lines
11 KiB
Coq
|
/*
|
||
|
|
||
|
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
|
||
|
|
||
|
`timescale 1ns / 1ps
|
||
|
|
||
|
/*
|
||
|
* XGMII 10GBASE-R decoder
|
||
|
*/
|
||
|
module xgmii_baser_dec_64 #
|
||
|
(
|
||
|
parameter DATA_WIDTH = 64,
|
||
|
parameter CTRL_WIDTH = (DATA_WIDTH/8),
|
||
|
parameter HDR_WIDTH = 2
|
||
|
)
|
||
|
(
|
||
|
input wire clk,
|
||
|
input wire rst,
|
||
|
|
||
|
/*
|
||
|
* 10GBASE-R encoded input
|
||
|
*/
|
||
|
input wire [DATA_WIDTH-1:0] encoded_rx_data,
|
||
|
input wire [HDR_WIDTH-1:0] encoded_rx_hdr,
|
||
|
|
||
|
/*
|
||
|
* XGMII interface
|
||
|
*/
|
||
|
output wire [DATA_WIDTH-1:0] xgmii_rxd,
|
||
|
output wire [CTRL_WIDTH-1:0] xgmii_rxc,
|
||
|
|
||
|
/*
|
||
|
* Status
|
||
|
*/
|
||
|
output wire rx_bad_block
|
||
|
);
|
||
|
|
||
|
// 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]
|
||
|
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
|
||
|
|
||
|
reg [DATA_WIDTH-1:0] decoded_ctrl;
|
||
|
reg [CTRL_WIDTH-1:0] decode_err;
|
||
|
|
||
|
reg [DATA_WIDTH-1:0] xgmii_rxd_reg = {DATA_WIDTH{1'b0}}, xgmii_rxd_next;
|
||
|
reg [CTRL_WIDTH-1:0] xgmii_rxc_reg = {CTRL_WIDTH{1'b0}}, xgmii_rxc_next;
|
||
|
|
||
|
reg rx_bad_block_reg = 1'b0, rx_bad_block_next;
|
||
|
|
||
|
assign xgmii_rxd = xgmii_rxd_reg;
|
||
|
assign xgmii_rxc = xgmii_rxc_reg;
|
||
|
|
||
|
assign rx_bad_block = rx_bad_block_reg;
|
||
|
|
||
|
integer i;
|
||
|
|
||
|
always @* begin
|
||
|
xgmii_rxd_next = {8{XGMII_ERROR}};
|
||
|
xgmii_rxc_next = 8'hff;
|
||
|
rx_bad_block_next = 1'b0;
|
||
|
|
||
|
for (i = 0; i < CTRL_WIDTH; i = i + 1) begin
|
||
|
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_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 (encoded_rx_hdr == SYNC_DATA) begin
|
||
|
xgmii_rxd_next = encoded_rx_data;
|
||
|
xgmii_rxc_next = 8'h00;
|
||
|
end else if (encoded_rx_hdr == SYNC_CTRL) begin
|
||
|
case (encoded_rx_data[7:0])
|
||
|
BLOCK_TYPE_CTRL: begin
|
||
|
// C7 C6 C5 C4 C3 C2 C1 C0 BT
|
||
|
xgmii_rxd_next = decoded_ctrl;
|
||
|
xgmii_rxc_next = 8'hff;
|
||
|
end
|
||
|
BLOCK_TYPE_OS_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;
|
||
|
if (encoded_rx_data[39:36] == O_SEQ_OS) begin
|
||
|
xgmii_rxd_next[63:32] = {encoded_rx_data[63:40], XGMII_SEQ_OS};
|
||
|
xgmii_rxc_next[7:4] = 4'h1;
|
||
|
end else begin
|
||
|
xgmii_rxd_next[63:32] = {4{XGMII_ERROR}};
|
||
|
xgmii_rxc_next[7:4] = 4'hf;
|
||
|
end
|
||
|
end
|
||
|
BLOCK_TYPE_START_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;
|
||
|
end
|
||
|
BLOCK_TYPE_OS_START: begin
|
||
|
// D7 D6 D5 O0 D3 D2 D1 BT
|
||
|
if (encoded_rx_data[35:32] == O_SEQ_OS) begin
|
||
|
xgmii_rxd_next[31:0] = {encoded_rx_data[31:8], XGMII_SEQ_OS};
|
||
|
xgmii_rxc_next[3:0] = 4'h1;
|
||
|
end else begin
|
||
|
xgmii_rxd_next[31:0] = {4{XGMII_ERROR}};
|
||
|
xgmii_rxc_next[3:0] = 4'hf;
|
||
|
end
|
||
|
xgmii_rxd_next[63:32] = {encoded_rx_data[63:40], XGMII_START};
|
||
|
xgmii_rxc_next[7:4] = 4'h1;
|
||
|
end
|
||
|
BLOCK_TYPE_OS_04: begin
|
||
|
// D7 D6 D5 O4 O0 D3 D2 D1 BT
|
||
|
if (encoded_rx_data[35:32] == O_SEQ_OS) begin
|
||
|
xgmii_rxd_next[31:0] = {encoded_rx_data[31:8], XGMII_SEQ_OS};
|
||
|
xgmii_rxc_next[3:0] = 4'h1;
|
||
|
end else begin
|
||
|
xgmii_rxd_next[31:0] = {4{XGMII_ERROR}};
|
||
|
xgmii_rxc_next[3:0] = 4'hf;
|
||
|
end
|
||
|
if (encoded_rx_data[39:36] == O_SEQ_OS) begin
|
||
|
xgmii_rxd_next[63:32] = {encoded_rx_data[63:40], XGMII_SEQ_OS};
|
||
|
xgmii_rxc_next[7:4] = 4'h1;
|
||
|
end else begin
|
||
|
xgmii_rxd_next[63:32] = {4{XGMII_ERROR}};
|
||
|
xgmii_rxc_next[7:4] = 4'hf;
|
||
|
end
|
||
|
end
|
||
|
BLOCK_TYPE_START_0: begin
|
||
|
// D7 D6 D5 D4 D3 D2 D1 BT
|
||
|
xgmii_rxd_next = {encoded_rx_data[63:8], XGMII_START};
|
||
|
xgmii_rxc_next = 8'h01;
|
||
|
end
|
||
|
BLOCK_TYPE_OS_0: begin
|
||
|
// C7 C6 C5 C4 O0 D3 D2 D1 BT
|
||
|
if (encoded_rx_data[35:32] == O_SEQ_OS) begin
|
||
|
xgmii_rxd_next[31:0] = {encoded_rx_data[31:8], XGMII_SEQ_OS};
|
||
|
xgmii_rxc_next[3:0] = 4'h1;
|
||
|
end else begin
|
||
|
xgmii_rxd_next[31:0] = {4{XGMII_ERROR}};
|
||
|
xgmii_rxc_next[3:0] = 4'hf;
|
||
|
end
|
||
|
xgmii_rxd_next[63:32] = decoded_ctrl[63:32];
|
||
|
xgmii_rxc_next[7:4] = 4'hf;
|
||
|
end
|
||
|
BLOCK_TYPE_TERM_0: begin
|
||
|
// C7 C6 C5 C4 C3 C2 C1 BT
|
||
|
xgmii_rxd_next = {decoded_ctrl[63:8], XGMII_TERM};
|
||
|
xgmii_rxc_next = 8'hff;
|
||
|
end
|
||
|
BLOCK_TYPE_TERM_1: 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;
|
||
|
end
|
||
|
BLOCK_TYPE_TERM_2: 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;
|
||
|
end
|
||
|
BLOCK_TYPE_TERM_3: 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;
|
||
|
end
|
||
|
BLOCK_TYPE_TERM_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;
|
||
|
end
|
||
|
BLOCK_TYPE_TERM_5: 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;
|
||
|
end
|
||
|
BLOCK_TYPE_TERM_6: 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;
|
||
|
end
|
||
|
BLOCK_TYPE_TERM_7: begin
|
||
|
// D6 D5 D4 D3 D2 D1 D0 BT
|
||
|
xgmii_rxd_next = {XGMII_TERM, encoded_rx_data[63:8]};
|
||
|
xgmii_rxc_next = 8'h80;
|
||
|
end
|
||
|
default: begin
|
||
|
// 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
|
||
|
// 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
|
||
|
xgmii_rxd_reg <= xgmii_rxd_next;
|
||
|
xgmii_rxc_reg <= xgmii_rxc_next;
|
||
|
|
||
|
rx_bad_block_reg <= rx_bad_block_next;
|
||
|
end
|
||
|
|
||
|
endmodule
|