mirror of
https://github.com/alexforencich/verilog-ethernet.git
synced 2025-01-14 06:43:18 +08:00
Add XGMII 10GBASE-R encoder and decoder modules and testbenches
This commit is contained in:
parent
c9752f24dd
commit
91553e6edf
325
rtl/xgmii_baser_dec_64.v
Normal file
325
rtl/xgmii_baser_dec_64.v
Normal file
@ -0,0 +1,325 @@
|
||||
/*
|
||||
|
||||
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
|
253
rtl/xgmii_baser_enc_64.v
Normal file
253
rtl/xgmii_baser_enc_64.v
Normal file
@ -0,0 +1,253 @@
|
||||
/*
|
||||
|
||||
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 encoder
|
||||
*/
|
||||
module xgmii_baser_enc_64 #
|
||||
(
|
||||
parameter DATA_WIDTH = 64,
|
||||
parameter CTRL_WIDTH = (DATA_WIDTH/8),
|
||||
parameter HDR_WIDTH = 2
|
||||
)
|
||||
(
|
||||
input wire clk,
|
||||
input wire rst,
|
||||
|
||||
/*
|
||||
* XGMII interface
|
||||
*/
|
||||
input wire [DATA_WIDTH-1:0] xgmii_txd,
|
||||
input wire [CTRL_WIDTH-1:0] xgmii_txc,
|
||||
|
||||
/*
|
||||
* 10GBASE-R encoded interface
|
||||
*/
|
||||
output wire [DATA_WIDTH-1:0] encoded_tx_data,
|
||||
output wire [HDR_WIDTH-1:0] encoded_tx_hdr
|
||||
);
|
||||
|
||||
// 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*7/8-1:0] encoded_ctrl;
|
||||
reg [CTRL_WIDTH-1:0] encode_err;
|
||||
|
||||
reg [DATA_WIDTH-1:0] encoded_tx_data_reg = {DATA_WIDTH{1'b0}}, encoded_tx_data_next;
|
||||
reg [HDR_WIDTH-1:0] encoded_tx_hdr_reg = {HDR_WIDTH{1'b0}}, encoded_tx_hdr_next;
|
||||
|
||||
assign encoded_tx_data = encoded_tx_data_reg;
|
||||
assign encoded_tx_hdr = encoded_tx_hdr_reg;
|
||||
|
||||
integer i;
|
||||
|
||||
always @* begin
|
||||
|
||||
|
||||
for (i = 0; i < CTRL_WIDTH; i = i + 1) begin
|
||||
if (xgmii_txc[i]) begin
|
||||
// control
|
||||
case (xgmii_txd[8*i +: 8])
|
||||
XGMII_IDLE: begin
|
||||
encoded_ctrl[7*i +: 7] = CTRL_IDLE;
|
||||
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
|
||||
encoded_tx_data_next = xgmii_txd;
|
||||
encoded_tx_hdr_next = SYNC_DATA;
|
||||
end else begin
|
||||
if (xgmii_txc[0] && xgmii_txd[7:0] == XGMII_START && !xgmii_txc[7:1]) begin
|
||||
// start in lane 0
|
||||
encoded_tx_data_next = {xgmii_txd[63:8], BLOCK_TYPE_START_0};
|
||||
end else if (xgmii_txc[4] && xgmii_txd[39:32] == XGMII_START && !xgmii_txc[7:5]) begin
|
||||
// start in lane 4
|
||||
if (xgmii_txc[0] && xgmii_txd[7:0] == XGMII_SEQ_OS && !xgmii_txc[3:1]) begin
|
||||
// ordered set in lane 0
|
||||
encoded_tx_data_next[35:0] = {O_SEQ_OS, xgmii_txd[31:8], BLOCK_TYPE_START_4};
|
||||
end else begin
|
||||
encoded_tx_data_next[35:0] = {encoded_ctrl[27:0], BLOCK_TYPE_START_4};
|
||||
end
|
||||
encoded_tx_data_next[63:36] = {xgmii_txd[63:40], 4'd0};
|
||||
end else if (xgmii_txc[0] && xgmii_txd[7:0] == XGMII_SEQ_OS && !xgmii_txc[3:1]) begin
|
||||
// ordered set in lane 0
|
||||
encoded_tx_data_next[35:8] = {O_SEQ_OS, xgmii_txd[31:8]};
|
||||
if (xgmii_txc[4] && xgmii_txd[39:32] == XGMII_SEQ_OS && !xgmii_txc[7:5]) begin
|
||||
// ordered set in lane 4
|
||||
encoded_tx_data_next[63:36] = {xgmii_txd[63:40], O_SEQ_OS};
|
||||
encoded_tx_data_next[7:0] = BLOCK_TYPE_OS_04;
|
||||
end else begin
|
||||
encoded_tx_data_next[63:36] = encoded_ctrl[55:28];
|
||||
encoded_tx_data_next[7:0] = BLOCK_TYPE_OS_0;
|
||||
end
|
||||
end else if (xgmii_txc[4] && xgmii_txd[39:32] == XGMII_SEQ_OS && !xgmii_txc[7:5]) begin
|
||||
// ordered set in lane 4
|
||||
encoded_tx_data_next = {xgmii_txd[63:40], O_SEQ_OS, 4'd0, encoded_ctrl[27:0], BLOCK_TYPE_OS_4};
|
||||
end else if (xgmii_txc[0] && 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};
|
||||
end else if (xgmii_txc[1] && xgmii_txd[15:8] == XGMII_TERM && !xgmii_txc[0]) begin
|
||||
// terminate in lane 1
|
||||
encoded_tx_data_next = {encoded_ctrl[55:14], 6'd0, xgmii_txd[7:0], BLOCK_TYPE_TERM_1};
|
||||
end else if (xgmii_txc[2] && xgmii_txd[23:16] == XGMII_TERM && !xgmii_txc[1:0]) begin
|
||||
// terminate in lane 2
|
||||
encoded_tx_data_next = {encoded_ctrl[55:21], 5'd0, xgmii_txd[15:0], BLOCK_TYPE_TERM_2};
|
||||
end else if (xgmii_txc[3] && xgmii_txd[31:24] == XGMII_TERM && !xgmii_txc[2:0]) begin
|
||||
// terminate in lane 3
|
||||
encoded_tx_data_next = {encoded_ctrl[55:28], 4'd0, xgmii_txd[23:0], BLOCK_TYPE_TERM_3};
|
||||
end else if (xgmii_txc[4] && xgmii_txd[39:32] == XGMII_TERM && !xgmii_txc[3:0]) begin
|
||||
// terminate in lane 4
|
||||
encoded_tx_data_next = {encoded_ctrl[55:35], 3'd0, xgmii_txd[31:0], BLOCK_TYPE_TERM_4};
|
||||
end else if (xgmii_txc[5] && xgmii_txd[47:40] == XGMII_TERM && !xgmii_txc[4:0]) begin
|
||||
// terminate in lane 5
|
||||
encoded_tx_data_next = {encoded_ctrl[55:42], 2'd0, xgmii_txd[39:0], BLOCK_TYPE_TERM_5};
|
||||
end else if (xgmii_txc[6] && xgmii_txd[55:48] == XGMII_TERM && !xgmii_txc[5:0]) begin
|
||||
// terminate in lane 6
|
||||
encoded_tx_data_next = {encoded_ctrl[55:49], 1'd0, xgmii_txd[47:0], BLOCK_TYPE_TERM_6};
|
||||
end else if (xgmii_txc[7] && xgmii_txd[63:56] == XGMII_TERM && !xgmii_txc[6:0]) begin
|
||||
// terminate in lane 7
|
||||
encoded_tx_data_next = {xgmii_txd[55:0], BLOCK_TYPE_TERM_7};
|
||||
end else begin
|
||||
// all control
|
||||
encoded_tx_data_next = {encoded_ctrl, BLOCK_TYPE_CTRL};
|
||||
end
|
||||
encoded_tx_hdr_next = SYNC_CTRL;
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk) begin
|
||||
encoded_tx_data_reg <= encoded_tx_data_next;
|
||||
encoded_tx_hdr_reg <= encoded_tx_hdr_next;
|
||||
end
|
||||
|
||||
endmodule
|
206
tb/test_xgmii_baser_dec_64.py
Executable file
206
tb/test_xgmii_baser_dec_64.py
Executable file
@ -0,0 +1,206 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
|
||||
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.
|
||||
|
||||
"""
|
||||
|
||||
from myhdl import *
|
||||
import os
|
||||
|
||||
import axis_ep
|
||||
import eth_ep
|
||||
import xgmii_ep
|
||||
import baser_serdes_ep
|
||||
|
||||
module = 'xgmii_baser_dec_64'
|
||||
testbench = 'test_%s' % module
|
||||
|
||||
srcs = []
|
||||
|
||||
srcs.append("../rtl/%s.v" % module)
|
||||
srcs.append("%s.v" % testbench)
|
||||
|
||||
src = ' '.join(srcs)
|
||||
|
||||
build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
|
||||
|
||||
def bench():
|
||||
|
||||
# Parameters
|
||||
DATA_WIDTH = 64
|
||||
CTRL_WIDTH = (DATA_WIDTH/8)
|
||||
HDR_WIDTH = 2
|
||||
|
||||
# Inputs
|
||||
clk = Signal(bool(0))
|
||||
rst = Signal(bool(0))
|
||||
current_test = Signal(intbv(0)[8:])
|
||||
|
||||
encoded_rx_data = Signal(intbv(0)[DATA_WIDTH:])
|
||||
encoded_rx_hdr = Signal(intbv(0)[HDR_WIDTH:])
|
||||
|
||||
# Outputs
|
||||
xgmii_rxd = Signal(intbv(0)[DATA_WIDTH:])
|
||||
xgmii_rxc = Signal(intbv(0)[CTRL_WIDTH:])
|
||||
rx_bad_block = Signal(bool(0))
|
||||
|
||||
# sources and sinks
|
||||
source = baser_serdes_ep.BaseRSerdesSource()
|
||||
|
||||
source_logic = source.create_logic(
|
||||
clk,
|
||||
tx_data=encoded_rx_data,
|
||||
tx_header=encoded_rx_hdr,
|
||||
scramble=False,
|
||||
name='source'
|
||||
)
|
||||
|
||||
sink = xgmii_ep.XGMIISink()
|
||||
|
||||
sink_logic = sink.create_logic(
|
||||
clk,
|
||||
rst,
|
||||
rxd=xgmii_rxd,
|
||||
rxc=xgmii_rxc,
|
||||
name='sink'
|
||||
)
|
||||
|
||||
# DUT
|
||||
if os.system(build_cmd):
|
||||
raise Exception("Error running build command")
|
||||
|
||||
dut = Cosimulation(
|
||||
"vvp -m myhdl %s.vvp -lxt2" % testbench,
|
||||
clk=clk,
|
||||
rst=rst,
|
||||
current_test=current_test,
|
||||
xgmii_rxd=xgmii_rxd,
|
||||
xgmii_rxc=xgmii_rxc,
|
||||
encoded_rx_data=encoded_rx_data,
|
||||
encoded_rx_hdr=encoded_rx_hdr,
|
||||
rx_bad_block=rx_bad_block
|
||||
)
|
||||
|
||||
@always(delay(4))
|
||||
def clkgen():
|
||||
clk.next = not clk
|
||||
|
||||
@instance
|
||||
def check():
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
rst.next = 1
|
||||
yield clk.posedge
|
||||
rst.next = 0
|
||||
yield clk.posedge
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
|
||||
# testbench stimulus
|
||||
|
||||
for payload_len in list(range(16,34)):
|
||||
yield clk.posedge
|
||||
print("test 1: test packet, length %d" % payload_len)
|
||||
current_test.next = 1
|
||||
|
||||
test_frame = bytearray(range(payload_len))
|
||||
|
||||
xgmii_frame = xgmii_ep.XGMIIFrame(b'\x55\x55\x55\x55\x55\x55\x55\xD5'+test_frame)
|
||||
|
||||
source.send(xgmii_frame)
|
||||
|
||||
yield sink.wait()
|
||||
rx_frame = sink.recv()
|
||||
|
||||
assert rx_frame.data == xgmii_frame.data
|
||||
|
||||
assert sink.empty()
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 2: back-to-back packets, length %d" % payload_len)
|
||||
current_test.next = 2
|
||||
|
||||
test_frame1 = bytearray(range(payload_len))
|
||||
test_frame2 = bytearray(range(payload_len))
|
||||
|
||||
xgmii_frame1 = xgmii_ep.XGMIIFrame(b'\x55\x55\x55\x55\x55\x55\x55\xD5'+test_frame1)
|
||||
xgmii_frame2 = xgmii_ep.XGMIIFrame(b'\x55\x55\x55\x55\x55\x55\x55\xD5'+test_frame2)
|
||||
|
||||
source.send(xgmii_frame1)
|
||||
source.send(xgmii_frame2)
|
||||
|
||||
yield sink.wait()
|
||||
rx_frame = sink.recv()
|
||||
|
||||
assert rx_frame.data == xgmii_frame1.data
|
||||
|
||||
yield sink.wait()
|
||||
rx_frame = sink.recv()
|
||||
|
||||
assert rx_frame.data == xgmii_frame2.data
|
||||
|
||||
assert sink.empty()
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 3: errored frame, length %d" % payload_len)
|
||||
current_test.next = 3
|
||||
|
||||
test_frame1 = bytearray(range(payload_len))
|
||||
test_frame2 = bytearray(range(payload_len))
|
||||
|
||||
xgmii_frame1 = xgmii_ep.XGMIIFrame(b'\x55\x55\x55\x55\x55\x55\x55\xD5'+test_frame1)
|
||||
xgmii_frame2 = xgmii_ep.XGMIIFrame(b'\x55\x55\x55\x55\x55\x55\x55\xD5'+test_frame2)
|
||||
|
||||
xgmii_frame1.error = 1
|
||||
|
||||
source.send(xgmii_frame1)
|
||||
source.send(xgmii_frame2)
|
||||
|
||||
yield sink.wait()
|
||||
rx_frame = sink.recv()
|
||||
|
||||
#assert rx_frame.data == xgmii_frame1.data
|
||||
|
||||
yield sink.wait()
|
||||
rx_frame = sink.recv()
|
||||
|
||||
assert rx_frame.data == xgmii_frame2.data
|
||||
|
||||
assert sink.empty()
|
||||
|
||||
yield delay(100)
|
||||
|
||||
raise StopSimulation
|
||||
|
||||
return instances()
|
||||
|
||||
def test_bench():
|
||||
sim = Simulation(bench())
|
||||
sim.run()
|
||||
|
||||
if __name__ == '__main__':
|
||||
print("Running test...")
|
||||
test_bench()
|
87
tb/test_xgmii_baser_dec_64.v
Normal file
87
tb/test_xgmii_baser_dec_64.v
Normal file
@ -0,0 +1,87 @@
|
||||
/*
|
||||
|
||||
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
|
||||
|
||||
/*
|
||||
* Testbench for xgmii_baser_dec_64
|
||||
*/
|
||||
module test_xgmii_baser_dec_64;
|
||||
|
||||
// Parameters
|
||||
parameter DATA_WIDTH = 64;
|
||||
parameter CTRL_WIDTH = (DATA_WIDTH/8);
|
||||
parameter HDR_WIDTH = 2;
|
||||
|
||||
// Inputs
|
||||
reg clk = 0;
|
||||
reg rst = 0;
|
||||
reg [7:0] current_test = 0;
|
||||
|
||||
reg [DATA_WIDTH-1:0] encoded_rx_data = 0;
|
||||
reg [HDR_WIDTH-1:0] encoded_rx_hdr = 0;
|
||||
|
||||
// Outputs
|
||||
wire [DATA_WIDTH-1:0] xgmii_rxd;
|
||||
wire [CTRL_WIDTH-1:0] xgmii_rxc;
|
||||
wire rx_bad_block;
|
||||
|
||||
initial begin
|
||||
// myhdl integration
|
||||
$from_myhdl(
|
||||
clk,
|
||||
rst,
|
||||
current_test,
|
||||
encoded_rx_data,
|
||||
encoded_rx_hdr
|
||||
);
|
||||
$to_myhdl(
|
||||
xgmii_rxd,
|
||||
xgmii_rxc,
|
||||
rx_bad_block
|
||||
);
|
||||
|
||||
// dump file
|
||||
$dumpfile("test_xgmii_baser_dec_64.lxt");
|
||||
$dumpvars(0, test_xgmii_baser_dec_64);
|
||||
end
|
||||
|
||||
xgmii_baser_dec_64 #(
|
||||
.DATA_WIDTH(DATA_WIDTH),
|
||||
.CTRL_WIDTH(CTRL_WIDTH),
|
||||
.HDR_WIDTH(HDR_WIDTH)
|
||||
)
|
||||
UUT (
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
.encoded_rx_data(encoded_rx_data),
|
||||
.encoded_rx_hdr(encoded_rx_hdr),
|
||||
.xgmii_rxd(xgmii_rxd),
|
||||
.xgmii_rxc(xgmii_rxc),
|
||||
.rx_bad_block(rx_bad_block)
|
||||
);
|
||||
|
||||
endmodule
|
204
tb/test_xgmii_baser_enc_64.py
Executable file
204
tb/test_xgmii_baser_enc_64.py
Executable file
@ -0,0 +1,204 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
|
||||
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.
|
||||
|
||||
"""
|
||||
|
||||
from myhdl import *
|
||||
import os
|
||||
|
||||
import axis_ep
|
||||
import eth_ep
|
||||
import xgmii_ep
|
||||
import baser_serdes_ep
|
||||
|
||||
module = 'xgmii_baser_enc_64'
|
||||
testbench = 'test_%s' % module
|
||||
|
||||
srcs = []
|
||||
|
||||
srcs.append("../rtl/%s.v" % module)
|
||||
srcs.append("%s.v" % testbench)
|
||||
|
||||
src = ' '.join(srcs)
|
||||
|
||||
build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
|
||||
|
||||
def bench():
|
||||
|
||||
# Parameters
|
||||
DATA_WIDTH = 64
|
||||
CTRL_WIDTH = (DATA_WIDTH/8)
|
||||
HDR_WIDTH = 2
|
||||
|
||||
# Inputs
|
||||
clk = Signal(bool(0))
|
||||
rst = Signal(bool(0))
|
||||
current_test = Signal(intbv(0)[8:])
|
||||
|
||||
xgmii_txd = Signal(intbv(0)[DATA_WIDTH:])
|
||||
xgmii_txc = Signal(intbv(0)[CTRL_WIDTH:])
|
||||
|
||||
# Outputs
|
||||
encoded_tx_data = Signal(intbv(0)[DATA_WIDTH:])
|
||||
encoded_tx_hdr = Signal(intbv(0)[HDR_WIDTH:])
|
||||
|
||||
# sources and sinks
|
||||
source = xgmii_ep.XGMIISource()
|
||||
|
||||
source_logic = source.create_logic(
|
||||
clk,
|
||||
rst,
|
||||
txd=xgmii_txd,
|
||||
txc=xgmii_txc,
|
||||
name='source'
|
||||
)
|
||||
|
||||
sink = baser_serdes_ep.BaseRSerdesSink()
|
||||
|
||||
sink_logic = sink.create_logic(
|
||||
clk,
|
||||
rx_data=encoded_tx_data,
|
||||
rx_header=encoded_tx_hdr,
|
||||
scramble=False,
|
||||
name='sink'
|
||||
)
|
||||
|
||||
# DUT
|
||||
if os.system(build_cmd):
|
||||
raise Exception("Error running build command")
|
||||
|
||||
dut = Cosimulation(
|
||||
"vvp -m myhdl %s.vvp -lxt2" % testbench,
|
||||
clk=clk,
|
||||
rst=rst,
|
||||
current_test=current_test,
|
||||
xgmii_txd=xgmii_txd,
|
||||
xgmii_txc=xgmii_txc,
|
||||
encoded_tx_data=encoded_tx_data,
|
||||
encoded_tx_hdr=encoded_tx_hdr
|
||||
)
|
||||
|
||||
@always(delay(4))
|
||||
def clkgen():
|
||||
clk.next = not clk
|
||||
|
||||
@instance
|
||||
def check():
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
rst.next = 1
|
||||
yield clk.posedge
|
||||
rst.next = 0
|
||||
yield clk.posedge
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
|
||||
# testbench stimulus
|
||||
|
||||
for payload_len in list(range(16,34)):
|
||||
yield clk.posedge
|
||||
print("test 1: test packet, length %d" % payload_len)
|
||||
current_test.next = 1
|
||||
|
||||
test_frame = bytearray(range(payload_len))
|
||||
|
||||
xgmii_frame = xgmii_ep.XGMIIFrame(b'\x55\x55\x55\x55\x55\x55\x55\xD5'+test_frame)
|
||||
|
||||
source.send(xgmii_frame)
|
||||
|
||||
yield sink.wait()
|
||||
rx_frame = sink.recv()
|
||||
|
||||
assert rx_frame.data == xgmii_frame.data
|
||||
|
||||
assert sink.empty()
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 2: back-to-back packets, length %d" % payload_len)
|
||||
current_test.next = 2
|
||||
|
||||
test_frame1 = bytearray(range(payload_len))
|
||||
test_frame2 = bytearray(range(payload_len))
|
||||
|
||||
xgmii_frame1 = xgmii_ep.XGMIIFrame(b'\x55\x55\x55\x55\x55\x55\x55\xD5'+test_frame1)
|
||||
xgmii_frame2 = xgmii_ep.XGMIIFrame(b'\x55\x55\x55\x55\x55\x55\x55\xD5'+test_frame2)
|
||||
|
||||
source.send(xgmii_frame1)
|
||||
source.send(xgmii_frame2)
|
||||
|
||||
yield sink.wait()
|
||||
rx_frame = sink.recv()
|
||||
|
||||
assert rx_frame.data == xgmii_frame1.data
|
||||
|
||||
yield sink.wait()
|
||||
rx_frame = sink.recv()
|
||||
|
||||
assert rx_frame.data == xgmii_frame2.data
|
||||
|
||||
assert sink.empty()
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 3: errored frame, length %d" % payload_len)
|
||||
current_test.next = 3
|
||||
|
||||
test_frame1 = bytearray(range(payload_len))
|
||||
test_frame2 = bytearray(range(payload_len))
|
||||
|
||||
xgmii_frame1 = xgmii_ep.XGMIIFrame(b'\x55\x55\x55\x55\x55\x55\x55\xD5'+test_frame1)
|
||||
xgmii_frame2 = xgmii_ep.XGMIIFrame(b'\x55\x55\x55\x55\x55\x55\x55\xD5'+test_frame2)
|
||||
|
||||
xgmii_frame1.error = 1
|
||||
|
||||
source.send(xgmii_frame1)
|
||||
source.send(xgmii_frame2)
|
||||
|
||||
yield sink.wait()
|
||||
rx_frame = sink.recv()
|
||||
|
||||
#assert rx_frame.data == xgmii_frame1.data
|
||||
|
||||
yield sink.wait()
|
||||
rx_frame = sink.recv()
|
||||
|
||||
assert rx_frame.data == xgmii_frame2.data
|
||||
|
||||
assert sink.empty()
|
||||
|
||||
yield delay(100)
|
||||
|
||||
raise StopSimulation
|
||||
|
||||
return instances()
|
||||
|
||||
def test_bench():
|
||||
sim = Simulation(bench())
|
||||
sim.run()
|
||||
|
||||
if __name__ == '__main__':
|
||||
print("Running test...")
|
||||
test_bench()
|
84
tb/test_xgmii_baser_enc_64.v
Normal file
84
tb/test_xgmii_baser_enc_64.v
Normal file
@ -0,0 +1,84 @@
|
||||
/*
|
||||
|
||||
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
|
||||
|
||||
/*
|
||||
* Testbench for xgmii_baser_enc_64
|
||||
*/
|
||||
module test_xgmii_baser_enc_64;
|
||||
|
||||
// Parameters
|
||||
parameter DATA_WIDTH = 64;
|
||||
parameter CTRL_WIDTH = (DATA_WIDTH/8);
|
||||
parameter HDR_WIDTH = 2;
|
||||
|
||||
// Inputs
|
||||
reg clk = 0;
|
||||
reg rst = 0;
|
||||
reg [7:0] current_test = 0;
|
||||
|
||||
reg [DATA_WIDTH-1:0] xgmii_txd = 0;
|
||||
reg [CTRL_WIDTH-1:0] xgmii_txc = 0;
|
||||
|
||||
// Outputs
|
||||
wire [DATA_WIDTH-1:0] encoded_tx_data;
|
||||
wire [HDR_WIDTH-1:0] encoded_tx_hdr;
|
||||
|
||||
initial begin
|
||||
// myhdl integration
|
||||
$from_myhdl(
|
||||
clk,
|
||||
rst,
|
||||
current_test,
|
||||
xgmii_txd,
|
||||
xgmii_txc
|
||||
);
|
||||
$to_myhdl(
|
||||
encoded_tx_data,
|
||||
encoded_tx_hdr
|
||||
);
|
||||
|
||||
// dump file
|
||||
$dumpfile("test_xgmii_baser_enc_64.lxt");
|
||||
$dumpvars(0, test_xgmii_baser_enc_64);
|
||||
end
|
||||
|
||||
xgmii_baser_enc_64 #(
|
||||
.DATA_WIDTH(DATA_WIDTH),
|
||||
.CTRL_WIDTH(CTRL_WIDTH),
|
||||
.HDR_WIDTH(HDR_WIDTH)
|
||||
)
|
||||
UUT (
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
.xgmii_txd(xgmii_txd),
|
||||
.xgmii_txc(xgmii_txc),
|
||||
.encoded_tx_data(encoded_tx_data),
|
||||
.encoded_tx_hdr(encoded_tx_hdr)
|
||||
);
|
||||
|
||||
endmodule
|
Loading…
x
Reference in New Issue
Block a user