mirror of
https://github.com/alexforencich/verilog-ethernet.git
synced 2025-01-14 06:43:18 +08:00
Add 10G Ethernet MAC/PHY combination modules and testbenches
This commit is contained in:
parent
5f6e7f721c
commit
ec38440d89
574
rtl/axis_baser_rx_64.v
Normal file
574
rtl/axis_baser_rx_64.v
Normal file
@ -0,0 +1,574 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2019 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
|
||||
|
||||
/*
|
||||
* AXI4-Stream 10GBASE-R frame receiver (10GBASE-R in, AXI out)
|
||||
*/
|
||||
module axis_baser_rx_64 #
|
||||
(
|
||||
parameter DATA_WIDTH = 64,
|
||||
parameter KEEP_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,
|
||||
|
||||
/*
|
||||
* AXI output
|
||||
*/
|
||||
output wire [DATA_WIDTH-1:0] m_axis_tdata,
|
||||
output wire [KEEP_WIDTH-1:0] m_axis_tkeep,
|
||||
output wire m_axis_tvalid,
|
||||
output wire m_axis_tlast,
|
||||
output wire m_axis_tuser,
|
||||
|
||||
/*
|
||||
* Status
|
||||
*/
|
||||
output wire start_packet_0,
|
||||
output wire start_packet_4,
|
||||
output wire error_bad_frame,
|
||||
output wire error_bad_fcs
|
||||
);
|
||||
|
||||
// bus width assertions
|
||||
initial begin
|
||||
if (DATA_WIDTH != 64) begin
|
||||
$error("Error: Interface width must be 64");
|
||||
$finish;
|
||||
end
|
||||
|
||||
if (KEEP_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]
|
||||
ETH_PRE = 8'h55,
|
||||
ETH_SFD = 8'hD5;
|
||||
|
||||
localparam [7:0]
|
||||
XGMII_IDLE = 8'h07,
|
||||
XGMII_START = 8'hfb,
|
||||
XGMII_TERM = 8'hfd,
|
||||
XGMII_ERROR = 8'hfe;
|
||||
|
||||
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
|
||||
|
||||
localparam [3:0]
|
||||
INPUT_TYPE_IDLE = 4'd0,
|
||||
INPUT_TYPE_ERROR = 4'd1,
|
||||
INPUT_TYPE_START_0 = 4'd2,
|
||||
INPUT_TYPE_START_4 = 4'd3,
|
||||
INPUT_TYPE_DATA = 4'd4,
|
||||
INPUT_TYPE_TERM_0 = 4'd8,
|
||||
INPUT_TYPE_TERM_1 = 4'd9,
|
||||
INPUT_TYPE_TERM_2 = 4'd10,
|
||||
INPUT_TYPE_TERM_3 = 4'd11,
|
||||
INPUT_TYPE_TERM_4 = 4'd12,
|
||||
INPUT_TYPE_TERM_5 = 4'd13,
|
||||
INPUT_TYPE_TERM_6 = 4'd14,
|
||||
INPUT_TYPE_TERM_7 = 4'd15;
|
||||
|
||||
localparam [2:0]
|
||||
STATE_IDLE = 3'd0,
|
||||
STATE_PAYLOAD = 3'd1,
|
||||
STATE_LAST = 3'd2;
|
||||
|
||||
reg [2:0] state_reg = STATE_IDLE, state_next;
|
||||
|
||||
// datapath control signals
|
||||
reg reset_crc;
|
||||
reg update_crc;
|
||||
|
||||
reg lanes_swapped = 1'b0;
|
||||
reg [31:0] swap_data = 32'd0;
|
||||
|
||||
reg delay_type_valid = 1'b0;
|
||||
reg [3:0] delay_type = INPUT_TYPE_IDLE;
|
||||
|
||||
reg [DATA_WIDTH-1:0] input_data_d0 = {DATA_WIDTH{1'b0}};
|
||||
reg [DATA_WIDTH-1:0] input_data_d1 = {DATA_WIDTH{1'b0}};
|
||||
reg [DATA_WIDTH-1:0] input_data_crc = {DATA_WIDTH{1'b0}};
|
||||
|
||||
reg [3:0] input_type_d0 = INPUT_TYPE_IDLE;
|
||||
reg [3:0] input_type_d1 = INPUT_TYPE_IDLE;
|
||||
|
||||
reg [DATA_WIDTH-1:0] m_axis_tdata_reg = {DATA_WIDTH{1'b0}}, m_axis_tdata_next;
|
||||
reg [KEEP_WIDTH-1:0] m_axis_tkeep_reg = {KEEP_WIDTH{1'b0}}, m_axis_tkeep_next;
|
||||
reg m_axis_tvalid_reg = 1'b0, m_axis_tvalid_next;
|
||||
reg m_axis_tlast_reg = 1'b0, m_axis_tlast_next;
|
||||
reg m_axis_tuser_reg = 1'b0, m_axis_tuser_next;
|
||||
|
||||
reg start_packet_0_reg = 1'b0;
|
||||
reg start_packet_4_reg = 1'b0;
|
||||
reg error_bad_frame_reg = 1'b0, error_bad_frame_next;
|
||||
reg error_bad_fcs_reg = 1'b0, error_bad_fcs_next;
|
||||
|
||||
reg [31:0] crc_state = 32'hFFFFFFFF;
|
||||
reg [31:0] crc_state3 = 32'hFFFFFFFF;
|
||||
|
||||
wire [31:0] crc_next0;
|
||||
wire [31:0] crc_next1;
|
||||
wire [31:0] crc_next2;
|
||||
wire [31:0] crc_next3;
|
||||
wire [31:0] crc_next7;
|
||||
|
||||
wire crc_valid0 = crc_next0 == ~32'h2144df1c;
|
||||
wire crc_valid1 = crc_next1 == ~32'h2144df1c;
|
||||
wire crc_valid2 = crc_next2 == ~32'h2144df1c;
|
||||
wire crc_valid3 = crc_next3 == ~32'h2144df1c;
|
||||
wire crc_valid7 = crc_next7 == ~32'h2144df1c;
|
||||
|
||||
reg crc_valid7_save = 1'b0;
|
||||
|
||||
assign m_axis_tdata = m_axis_tdata_reg;
|
||||
assign m_axis_tkeep = m_axis_tkeep_reg;
|
||||
assign m_axis_tvalid = m_axis_tvalid_reg;
|
||||
assign m_axis_tlast = m_axis_tlast_reg;
|
||||
assign m_axis_tuser = m_axis_tuser_reg;
|
||||
|
||||
assign start_packet_0 = start_packet_0_reg;
|
||||
assign start_packet_4 = start_packet_4_reg;
|
||||
assign error_bad_frame = error_bad_frame_reg;
|
||||
assign error_bad_fcs = error_bad_fcs_reg;
|
||||
|
||||
wire last_cycle = state_reg == STATE_LAST;
|
||||
|
||||
lfsr #(
|
||||
.LFSR_WIDTH(32),
|
||||
.LFSR_POLY(32'h4c11db7),
|
||||
.LFSR_CONFIG("GALOIS"),
|
||||
.LFSR_FEED_FORWARD(0),
|
||||
.REVERSE(1),
|
||||
.DATA_WIDTH(8),
|
||||
.STYLE("AUTO")
|
||||
)
|
||||
eth_crc_8 (
|
||||
.data_in(input_data_crc[7:0]),
|
||||
.state_in(last_cycle ? crc_state3 : crc_state),
|
||||
.data_out(),
|
||||
.state_out(crc_next0)
|
||||
);
|
||||
|
||||
lfsr #(
|
||||
.LFSR_WIDTH(32),
|
||||
.LFSR_POLY(32'h4c11db7),
|
||||
.LFSR_CONFIG("GALOIS"),
|
||||
.LFSR_FEED_FORWARD(0),
|
||||
.REVERSE(1),
|
||||
.DATA_WIDTH(16),
|
||||
.STYLE("AUTO")
|
||||
)
|
||||
eth_crc_16 (
|
||||
.data_in(input_data_crc[15:0]),
|
||||
.state_in(last_cycle ? crc_state3 : crc_state),
|
||||
.data_out(),
|
||||
.state_out(crc_next1)
|
||||
);
|
||||
|
||||
lfsr #(
|
||||
.LFSR_WIDTH(32),
|
||||
.LFSR_POLY(32'h4c11db7),
|
||||
.LFSR_CONFIG("GALOIS"),
|
||||
.LFSR_FEED_FORWARD(0),
|
||||
.REVERSE(1),
|
||||
.DATA_WIDTH(24),
|
||||
.STYLE("AUTO")
|
||||
)
|
||||
eth_crc_24 (
|
||||
.data_in(input_data_crc[23:0]),
|
||||
.state_in(last_cycle ? crc_state3 : crc_state),
|
||||
.data_out(),
|
||||
.state_out(crc_next2)
|
||||
);
|
||||
|
||||
lfsr #(
|
||||
.LFSR_WIDTH(32),
|
||||
.LFSR_POLY(32'h4c11db7),
|
||||
.LFSR_CONFIG("GALOIS"),
|
||||
.LFSR_FEED_FORWARD(0),
|
||||
.REVERSE(1),
|
||||
.DATA_WIDTH(32),
|
||||
.STYLE("AUTO")
|
||||
)
|
||||
eth_crc_32 (
|
||||
.data_in(input_data_crc[31:0]),
|
||||
.state_in(last_cycle ? crc_state3 : crc_state),
|
||||
.data_out(),
|
||||
.state_out(crc_next3)
|
||||
);
|
||||
|
||||
lfsr #(
|
||||
.LFSR_WIDTH(32),
|
||||
.LFSR_POLY(32'h4c11db7),
|
||||
.LFSR_CONFIG("GALOIS"),
|
||||
.LFSR_FEED_FORWARD(0),
|
||||
.REVERSE(1),
|
||||
.DATA_WIDTH(64),
|
||||
.STYLE("AUTO")
|
||||
)
|
||||
eth_crc_64 (
|
||||
.data_in(input_data_d0[63:0]),
|
||||
.state_in(crc_state),
|
||||
.data_out(),
|
||||
.state_out(crc_next7)
|
||||
);
|
||||
|
||||
always @* begin
|
||||
state_next = STATE_IDLE;
|
||||
|
||||
reset_crc = 1'b0;
|
||||
update_crc = 1'b0;
|
||||
|
||||
m_axis_tdata_next = input_data_d1;
|
||||
m_axis_tkeep_next = 8'd0;
|
||||
m_axis_tvalid_next = 1'b0;
|
||||
m_axis_tlast_next = 1'b0;
|
||||
m_axis_tuser_next = 1'b0;
|
||||
|
||||
error_bad_frame_next = 1'b0;
|
||||
error_bad_fcs_next = 1'b0;
|
||||
|
||||
case (state_reg)
|
||||
STATE_IDLE: begin
|
||||
// idle state - wait for packet
|
||||
reset_crc = 1'b1;
|
||||
|
||||
if (input_type_d1 == INPUT_TYPE_START_0) begin
|
||||
// start condition
|
||||
reset_crc = 1'b0;
|
||||
update_crc = 1'b1;
|
||||
state_next = STATE_PAYLOAD;
|
||||
end else begin
|
||||
state_next = STATE_IDLE;
|
||||
end
|
||||
end
|
||||
STATE_PAYLOAD: begin
|
||||
// read payload
|
||||
update_crc = 1'b1;
|
||||
|
||||
m_axis_tdata_next = input_data_d1;
|
||||
m_axis_tkeep_next = 8'hff;
|
||||
m_axis_tvalid_next = 1'b1;
|
||||
m_axis_tlast_next = 1'b0;
|
||||
m_axis_tuser_next = 1'b0;
|
||||
|
||||
if (input_type_d0 == INPUT_TYPE_DATA) begin
|
||||
state_next = STATE_PAYLOAD;
|
||||
end else if (input_type_d0[3]) begin
|
||||
// INPUT_TYPE_TERM_*
|
||||
if (input_type_d0 <= INPUT_TYPE_TERM_4) begin
|
||||
// end this cycle
|
||||
reset_crc = 1'b1;
|
||||
case (input_type_d0)
|
||||
INPUT_TYPE_TERM_0: m_axis_tkeep_next = 8'b00001111;
|
||||
INPUT_TYPE_TERM_1: m_axis_tkeep_next = 8'b00011111;
|
||||
INPUT_TYPE_TERM_2: m_axis_tkeep_next = 8'b00111111;
|
||||
INPUT_TYPE_TERM_3: m_axis_tkeep_next = 8'b01111111;
|
||||
INPUT_TYPE_TERM_4: m_axis_tkeep_next = 8'b11111111;
|
||||
endcase
|
||||
m_axis_tlast_next = 1'b1;
|
||||
if ((input_type_d0 == INPUT_TYPE_TERM_0 && crc_valid7_save) ||
|
||||
(input_type_d0 == INPUT_TYPE_TERM_1 && crc_valid0) ||
|
||||
(input_type_d0 == INPUT_TYPE_TERM_2 && crc_valid1) ||
|
||||
(input_type_d0 == INPUT_TYPE_TERM_3 && crc_valid2) ||
|
||||
(input_type_d0 == INPUT_TYPE_TERM_4 && crc_valid3)) begin
|
||||
// CRC valid
|
||||
end else begin
|
||||
m_axis_tuser_next = 1'b1;
|
||||
error_bad_frame_next = 1'b1;
|
||||
error_bad_fcs_next = 1'b1;
|
||||
end
|
||||
state_next = STATE_IDLE;
|
||||
end else begin
|
||||
// need extra cycle
|
||||
state_next = STATE_LAST;
|
||||
end
|
||||
end else begin
|
||||
// control or error characters in packet
|
||||
m_axis_tlast_next = 1'b1;
|
||||
m_axis_tuser_next = 1'b1;
|
||||
error_bad_frame_next = 1'b1;
|
||||
reset_crc = 1'b1;
|
||||
state_next = STATE_IDLE;
|
||||
end
|
||||
end
|
||||
STATE_LAST: begin
|
||||
// last cycle of packet
|
||||
m_axis_tdata_next = input_data_d1;
|
||||
m_axis_tkeep_next = 8'hff;
|
||||
m_axis_tvalid_next = 1'b1;
|
||||
m_axis_tlast_next = 1'b1;
|
||||
m_axis_tuser_next = 1'b0;
|
||||
|
||||
reset_crc = 1'b1;
|
||||
|
||||
case (input_type_d1)
|
||||
INPUT_TYPE_TERM_5: m_axis_tkeep_next = 8'b00000001;
|
||||
INPUT_TYPE_TERM_6: m_axis_tkeep_next = 8'b00000011;
|
||||
INPUT_TYPE_TERM_7: m_axis_tkeep_next = 8'b00000111;
|
||||
endcase
|
||||
|
||||
if ((input_type_d1 == INPUT_TYPE_TERM_5 && crc_valid0) ||
|
||||
(input_type_d1 == INPUT_TYPE_TERM_6 && crc_valid1) ||
|
||||
(input_type_d1 == INPUT_TYPE_TERM_7 && crc_valid2)) begin
|
||||
// CRC valid
|
||||
end else begin
|
||||
m_axis_tuser_next = 1'b1;
|
||||
error_bad_frame_next = 1'b1;
|
||||
error_bad_fcs_next = 1'b1;
|
||||
end
|
||||
|
||||
state_next = STATE_IDLE;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (rst) begin
|
||||
state_reg <= STATE_IDLE;
|
||||
|
||||
m_axis_tvalid_reg <= 1'b0;
|
||||
|
||||
start_packet_0_reg <= 1'b0;
|
||||
start_packet_4_reg <= 1'b0;
|
||||
error_bad_frame_reg <= 1'b0;
|
||||
error_bad_fcs_reg <= 1'b0;
|
||||
|
||||
crc_state <= 32'hFFFFFFFF;
|
||||
crc_state3 <= 32'hFFFFFFFF;
|
||||
crc_valid7_save <= 1'b0;
|
||||
|
||||
input_type_d0 <= INPUT_TYPE_IDLE;
|
||||
input_type_d1 <= INPUT_TYPE_IDLE;
|
||||
|
||||
lanes_swapped <= 1'b0;
|
||||
|
||||
delay_type_valid <= 1'b0;
|
||||
delay_type <= INPUT_TYPE_IDLE;
|
||||
end else begin
|
||||
state_reg <= state_next;
|
||||
|
||||
m_axis_tvalid_reg <= m_axis_tvalid_next;
|
||||
|
||||
start_packet_0_reg <= 1'b0;
|
||||
start_packet_4_reg <= 1'b0;
|
||||
error_bad_frame_reg <= error_bad_frame_next;
|
||||
error_bad_fcs_reg <= error_bad_fcs_next;
|
||||
|
||||
delay_type_valid <= 1'b0;
|
||||
|
||||
if (encoded_rx_hdr == SYNC_CTRL && encoded_rx_data[7:0] == BLOCK_TYPE_START_0) begin
|
||||
lanes_swapped <= 1'b0;
|
||||
start_packet_0_reg <= 1'b1;
|
||||
input_type_d0 <= INPUT_TYPE_START_0;
|
||||
end else if (encoded_rx_hdr == SYNC_CTRL && encoded_rx_data[7:0] == BLOCK_TYPE_START_4)begin
|
||||
lanes_swapped <= 1'b1;
|
||||
start_packet_4_reg <= 1'b1;
|
||||
delay_type_valid <= 1'b1;
|
||||
if (delay_type_valid) begin
|
||||
input_type_d0 <= delay_type;
|
||||
end else begin
|
||||
input_type_d0 <= INPUT_TYPE_IDLE;
|
||||
end
|
||||
end else if (lanes_swapped) begin
|
||||
if (delay_type_valid) begin
|
||||
input_type_d0 <= delay_type;
|
||||
end else if (encoded_rx_hdr == SYNC_DATA) begin
|
||||
input_type_d0 <= INPUT_TYPE_DATA;
|
||||
end else if (encoded_rx_hdr == SYNC_CTRL) begin
|
||||
case (encoded_rx_data[7:0])
|
||||
BLOCK_TYPE_TERM_0: input_type_d0 <= INPUT_TYPE_TERM_4;
|
||||
BLOCK_TYPE_TERM_1: input_type_d0 <= INPUT_TYPE_TERM_5;
|
||||
BLOCK_TYPE_TERM_2: input_type_d0 <= INPUT_TYPE_TERM_6;
|
||||
BLOCK_TYPE_TERM_3: input_type_d0 <= INPUT_TYPE_TERM_7;
|
||||
BLOCK_TYPE_TERM_4: begin
|
||||
delay_type_valid <= 1'b1;
|
||||
input_type_d0 <= INPUT_TYPE_DATA;
|
||||
end
|
||||
BLOCK_TYPE_TERM_5: begin
|
||||
delay_type_valid <= 1'b1;
|
||||
input_type_d0 <= INPUT_TYPE_DATA;
|
||||
end
|
||||
BLOCK_TYPE_TERM_6: begin
|
||||
delay_type_valid <= 1'b1;
|
||||
input_type_d0 <= INPUT_TYPE_DATA;
|
||||
end
|
||||
BLOCK_TYPE_TERM_7: begin
|
||||
delay_type_valid <= 1'b1;
|
||||
input_type_d0 <= INPUT_TYPE_DATA;
|
||||
end
|
||||
default: input_type_d0 <= INPUT_TYPE_ERROR;
|
||||
endcase
|
||||
end else begin
|
||||
input_type_d0 <= INPUT_TYPE_ERROR;
|
||||
end
|
||||
end else begin
|
||||
if (encoded_rx_hdr == SYNC_DATA) begin
|
||||
input_type_d0 <= INPUT_TYPE_DATA;
|
||||
end else if (encoded_rx_hdr == SYNC_CTRL) begin
|
||||
case (encoded_rx_data[7:0])
|
||||
BLOCK_TYPE_TERM_0: input_type_d0 <= INPUT_TYPE_TERM_0;
|
||||
BLOCK_TYPE_TERM_1: input_type_d0 <= INPUT_TYPE_TERM_1;
|
||||
BLOCK_TYPE_TERM_2: input_type_d0 <= INPUT_TYPE_TERM_2;
|
||||
BLOCK_TYPE_TERM_3: input_type_d0 <= INPUT_TYPE_TERM_3;
|
||||
BLOCK_TYPE_TERM_4: input_type_d0 <= INPUT_TYPE_TERM_4;
|
||||
BLOCK_TYPE_TERM_5: input_type_d0 <= INPUT_TYPE_TERM_5;
|
||||
BLOCK_TYPE_TERM_6: input_type_d0 <= INPUT_TYPE_TERM_6;
|
||||
BLOCK_TYPE_TERM_7: input_type_d0 <= INPUT_TYPE_TERM_7;
|
||||
default: input_type_d0 <= INPUT_TYPE_ERROR;
|
||||
endcase
|
||||
end else begin
|
||||
input_type_d0 <= INPUT_TYPE_ERROR;
|
||||
end
|
||||
end
|
||||
|
||||
input_type_d1 <= input_type_d0;
|
||||
|
||||
// datapath
|
||||
if (reset_crc) begin
|
||||
crc_state <= 32'hFFFFFFFF;
|
||||
crc_state3 <= 32'hFFFFFFFF;
|
||||
crc_valid7_save <= 1'b0;
|
||||
end else if (update_crc) begin
|
||||
crc_state <= crc_next7;
|
||||
crc_state3 <= crc_next3;
|
||||
crc_valid7_save <= crc_valid7;
|
||||
end
|
||||
end
|
||||
|
||||
m_axis_tdata_reg <= m_axis_tdata_next;
|
||||
m_axis_tkeep_reg <= m_axis_tkeep_next;
|
||||
m_axis_tlast_reg <= m_axis_tlast_next;
|
||||
m_axis_tuser_reg <= m_axis_tuser_next;
|
||||
|
||||
if (encoded_rx_hdr == SYNC_DATA) begin
|
||||
swap_data <= encoded_rx_data[63:32];
|
||||
end else begin
|
||||
swap_data <= {8'd0, encoded_rx_data[63:40]};
|
||||
end
|
||||
|
||||
if (encoded_rx_hdr == SYNC_CTRL && encoded_rx_data[7:0] == BLOCK_TYPE_START_0) begin
|
||||
input_data_d0 <= encoded_rx_data;
|
||||
input_data_crc <= encoded_rx_data;
|
||||
end else if (encoded_rx_hdr == SYNC_CTRL && encoded_rx_data[7:0] == BLOCK_TYPE_START_4)begin
|
||||
input_data_d0 <= {encoded_rx_data[31:0], swap_data};
|
||||
input_data_crc <= {encoded_rx_data[31:0], swap_data};
|
||||
end else if (lanes_swapped) begin
|
||||
if (encoded_rx_hdr == SYNC_DATA) begin
|
||||
input_data_d0 <= {encoded_rx_data[31:0], swap_data};
|
||||
input_data_crc <= {encoded_rx_data[31:0], swap_data};
|
||||
end else begin
|
||||
input_data_d0 <= {encoded_rx_data[39:8], swap_data};
|
||||
input_data_crc <= {encoded_rx_data[39:8], swap_data};
|
||||
end
|
||||
end else begin
|
||||
if (encoded_rx_hdr == SYNC_DATA) begin
|
||||
input_data_d0 <= encoded_rx_data;
|
||||
input_data_crc <= encoded_rx_data;
|
||||
end else begin
|
||||
input_data_d0 <= {8'd0, encoded_rx_data[63:8]};
|
||||
input_data_crc <= {8'd0, encoded_rx_data[63:8]};
|
||||
end
|
||||
end
|
||||
|
||||
if (state_next == STATE_LAST) begin
|
||||
input_data_crc[31:0] <= input_data_crc[63:32];
|
||||
end
|
||||
|
||||
input_data_d1 <= input_data_d0;
|
||||
|
||||
if (encoded_rx_hdr == SYNC_DATA) begin
|
||||
delay_type <= INPUT_TYPE_DATA;
|
||||
end else if (encoded_rx_hdr == SYNC_CTRL) begin
|
||||
case (encoded_rx_data[7:0])
|
||||
BLOCK_TYPE_START_4: delay_type <= INPUT_TYPE_START_0;
|
||||
BLOCK_TYPE_TERM_0: delay_type <= INPUT_TYPE_TERM_4;
|
||||
BLOCK_TYPE_TERM_1: delay_type <= INPUT_TYPE_TERM_5;
|
||||
BLOCK_TYPE_TERM_2: delay_type <= INPUT_TYPE_TERM_6;
|
||||
BLOCK_TYPE_TERM_3: delay_type <= INPUT_TYPE_TERM_7;
|
||||
BLOCK_TYPE_TERM_4: delay_type <= INPUT_TYPE_TERM_0;
|
||||
BLOCK_TYPE_TERM_5: delay_type <= INPUT_TYPE_TERM_1;
|
||||
BLOCK_TYPE_TERM_6: delay_type <= INPUT_TYPE_TERM_2;
|
||||
BLOCK_TYPE_TERM_7: delay_type <= INPUT_TYPE_TERM_3;
|
||||
default: delay_type <= INPUT_TYPE_ERROR;
|
||||
endcase
|
||||
end else begin
|
||||
delay_type <= INPUT_TYPE_ERROR;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
848
rtl/axis_baser_tx_64.v
Normal file
848
rtl/axis_baser_tx_64.v
Normal file
@ -0,0 +1,848 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2019 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
|
||||
|
||||
/*
|
||||
* AXI4-Stream 10GBASE-R frame transmitter (AXI in, 10GBASE-R out)
|
||||
*/
|
||||
module axis_baser_tx_64 #
|
||||
(
|
||||
parameter DATA_WIDTH = 64,
|
||||
parameter KEEP_WIDTH = (DATA_WIDTH/8),
|
||||
parameter HDR_WIDTH = 2,
|
||||
parameter ENABLE_PADDING = 1,
|
||||
parameter ENABLE_DIC = 1,
|
||||
parameter MIN_FRAME_LENGTH = 64
|
||||
)
|
||||
(
|
||||
input wire clk,
|
||||
input wire rst,
|
||||
|
||||
/*
|
||||
* AXI input
|
||||
*/
|
||||
input wire [DATA_WIDTH-1:0] s_axis_tdata,
|
||||
input wire [KEEP_WIDTH-1:0] s_axis_tkeep,
|
||||
input wire s_axis_tvalid,
|
||||
output wire s_axis_tready,
|
||||
input wire s_axis_tlast,
|
||||
input wire s_axis_tuser,
|
||||
|
||||
/*
|
||||
* 10GBASE-R encoded interface
|
||||
*/
|
||||
output wire [DATA_WIDTH-1:0] encoded_tx_data,
|
||||
output wire [HDR_WIDTH-1:0] encoded_tx_hdr,
|
||||
|
||||
/*
|
||||
* Configuration
|
||||
*/
|
||||
input wire [7:0] ifg_delay,
|
||||
|
||||
/*
|
||||
* Status
|
||||
*/
|
||||
output wire start_packet_0,
|
||||
output wire start_packet_4
|
||||
);
|
||||
|
||||
// bus width assertions
|
||||
initial begin
|
||||
if (DATA_WIDTH != 64) begin
|
||||
$error("Error: Interface width must be 64");
|
||||
$finish;
|
||||
end
|
||||
|
||||
if (KEEP_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 MIN_FL_NOCRC = MIN_FRAME_LENGTH-4;
|
||||
localparam MIN_FL_NOCRC_MS = MIN_FL_NOCRC & 16'hfff8;
|
||||
localparam MIN_FL_NOCRC_LS = MIN_FL_NOCRC & 16'h0007;
|
||||
|
||||
localparam [7:0]
|
||||
ETH_PRE = 8'h55,
|
||||
ETH_SFD = 8'hD5;
|
||||
|
||||
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
|
||||
|
||||
localparam [3:0]
|
||||
OUTPUT_TYPE_IDLE = 4'd0,
|
||||
OUTPUT_TYPE_ERROR = 4'd1,
|
||||
OUTPUT_TYPE_START_0 = 4'd2,
|
||||
OUTPUT_TYPE_START_4 = 4'd3,
|
||||
OUTPUT_TYPE_DATA = 4'd4,
|
||||
OUTPUT_TYPE_TERM_0 = 4'd8,
|
||||
OUTPUT_TYPE_TERM_1 = 4'd9,
|
||||
OUTPUT_TYPE_TERM_2 = 4'd10,
|
||||
OUTPUT_TYPE_TERM_3 = 4'd11,
|
||||
OUTPUT_TYPE_TERM_4 = 4'd12,
|
||||
OUTPUT_TYPE_TERM_5 = 4'd13,
|
||||
OUTPUT_TYPE_TERM_6 = 4'd14,
|
||||
OUTPUT_TYPE_TERM_7 = 4'd15;
|
||||
|
||||
localparam [2:0]
|
||||
STATE_IDLE = 3'd0,
|
||||
STATE_PAYLOAD = 3'd1,
|
||||
STATE_PAD = 3'd2,
|
||||
STATE_FCS_1 = 3'd3,
|
||||
STATE_FCS_2 = 3'd4,
|
||||
STATE_IFG = 3'd5,
|
||||
STATE_WAIT_END = 3'd6;
|
||||
|
||||
reg [2:0] state_reg = STATE_IDLE, state_next;
|
||||
|
||||
// datapath control signals
|
||||
reg reset_crc;
|
||||
reg update_crc;
|
||||
|
||||
reg swap_lanes;
|
||||
reg unswap_lanes;
|
||||
|
||||
reg lanes_swapped = 1'b0;
|
||||
reg [31:0] swap_data = 32'd0;
|
||||
|
||||
reg delay_type_valid = 1'b0;
|
||||
reg [3:0] delay_type = OUTPUT_TYPE_IDLE;
|
||||
|
||||
reg [DATA_WIDTH-1:0] s_axis_tdata_masked;
|
||||
|
||||
reg [DATA_WIDTH-1:0] s_tdata_reg = {DATA_WIDTH{1'b0}}, s_tdata_next;
|
||||
reg [7:0] s_tkeep_reg = 8'd0, s_tkeep_next;
|
||||
|
||||
reg [DATA_WIDTH-1:0] fcs_output_data_0;
|
||||
reg [DATA_WIDTH-1:0] fcs_output_data_1;
|
||||
reg [3:0] fcs_output_type_0;
|
||||
reg [3:0] fcs_output_type_1;
|
||||
|
||||
reg [7:0] ifg_offset;
|
||||
|
||||
reg extra_cycle;
|
||||
|
||||
reg [15:0] frame_ptr_reg = 16'd0, frame_ptr_next;
|
||||
|
||||
reg [7:0] ifg_count_reg = 8'd0, ifg_count_next;
|
||||
reg [1:0] deficit_idle_count_reg = 2'd0, deficit_idle_count_next;
|
||||
|
||||
reg s_axis_tready_reg = 1'b0, s_axis_tready_next;
|
||||
|
||||
reg [31:0] crc_state = 32'hFFFFFFFF;
|
||||
|
||||
wire [31:0] crc_next0;
|
||||
wire [31:0] crc_next1;
|
||||
wire [31:0] crc_next2;
|
||||
wire [31:0] crc_next3;
|
||||
wire [31:0] crc_next4;
|
||||
wire [31:0] crc_next5;
|
||||
wire [31:0] crc_next6;
|
||||
wire [31:0] crc_next7;
|
||||
|
||||
reg [DATA_WIDTH-1:0] encoded_tx_data_reg = {{8{CTRL_IDLE}}, BLOCK_TYPE_CTRL};
|
||||
reg [HDR_WIDTH-1:0] encoded_tx_hdr_reg = SYNC_CTRL;
|
||||
|
||||
reg [DATA_WIDTH-1:0] output_data_reg = {DATA_WIDTH{1'b0}}, output_data_next;
|
||||
reg [3:0] output_type_reg = OUTPUT_TYPE_IDLE, output_type_next;
|
||||
|
||||
reg start_packet_0_reg = 1'b0, start_packet_0_next;
|
||||
reg start_packet_4_reg = 1'b0, start_packet_4_next;
|
||||
|
||||
assign s_axis_tready = s_axis_tready_reg;
|
||||
|
||||
assign encoded_tx_data = encoded_tx_data_reg;
|
||||
assign encoded_tx_hdr = encoded_tx_hdr_reg;
|
||||
|
||||
assign start_packet_0 = start_packet_0_reg;
|
||||
assign start_packet_4 = start_packet_4_reg;
|
||||
|
||||
lfsr #(
|
||||
.LFSR_WIDTH(32),
|
||||
.LFSR_POLY(32'h4c11db7),
|
||||
.LFSR_CONFIG("GALOIS"),
|
||||
.LFSR_FEED_FORWARD(0),
|
||||
.REVERSE(1),
|
||||
.DATA_WIDTH(8),
|
||||
.STYLE("AUTO")
|
||||
)
|
||||
eth_crc_8 (
|
||||
.data_in(s_tdata_reg[7:0]),
|
||||
.state_in(crc_state),
|
||||
.data_out(),
|
||||
.state_out(crc_next0)
|
||||
);
|
||||
|
||||
lfsr #(
|
||||
.LFSR_WIDTH(32),
|
||||
.LFSR_POLY(32'h4c11db7),
|
||||
.LFSR_CONFIG("GALOIS"),
|
||||
.LFSR_FEED_FORWARD(0),
|
||||
.REVERSE(1),
|
||||
.DATA_WIDTH(16),
|
||||
.STYLE("AUTO")
|
||||
)
|
||||
eth_crc_16 (
|
||||
.data_in(s_tdata_reg[15:0]),
|
||||
.state_in(crc_state),
|
||||
.data_out(),
|
||||
.state_out(crc_next1)
|
||||
);
|
||||
|
||||
lfsr #(
|
||||
.LFSR_WIDTH(32),
|
||||
.LFSR_POLY(32'h4c11db7),
|
||||
.LFSR_CONFIG("GALOIS"),
|
||||
.LFSR_FEED_FORWARD(0),
|
||||
.REVERSE(1),
|
||||
.DATA_WIDTH(24),
|
||||
.STYLE("AUTO")
|
||||
)
|
||||
eth_crc_24 (
|
||||
.data_in(s_tdata_reg[23:0]),
|
||||
.state_in(crc_state),
|
||||
.data_out(),
|
||||
.state_out(crc_next2)
|
||||
);
|
||||
|
||||
lfsr #(
|
||||
.LFSR_WIDTH(32),
|
||||
.LFSR_POLY(32'h4c11db7),
|
||||
.LFSR_CONFIG("GALOIS"),
|
||||
.LFSR_FEED_FORWARD(0),
|
||||
.REVERSE(1),
|
||||
.DATA_WIDTH(32),
|
||||
.STYLE("AUTO")
|
||||
)
|
||||
eth_crc_32 (
|
||||
.data_in(s_tdata_reg[31:0]),
|
||||
.state_in(crc_state),
|
||||
.data_out(),
|
||||
.state_out(crc_next3)
|
||||
);
|
||||
|
||||
lfsr #(
|
||||
.LFSR_WIDTH(32),
|
||||
.LFSR_POLY(32'h4c11db7),
|
||||
.LFSR_CONFIG("GALOIS"),
|
||||
.LFSR_FEED_FORWARD(0),
|
||||
.REVERSE(1),
|
||||
.DATA_WIDTH(40),
|
||||
.STYLE("AUTO")
|
||||
)
|
||||
eth_crc_40 (
|
||||
.data_in(s_tdata_reg[39:0]),
|
||||
.state_in(crc_state),
|
||||
.data_out(),
|
||||
.state_out(crc_next4)
|
||||
);
|
||||
|
||||
lfsr #(
|
||||
.LFSR_WIDTH(32),
|
||||
.LFSR_POLY(32'h4c11db7),
|
||||
.LFSR_CONFIG("GALOIS"),
|
||||
.LFSR_FEED_FORWARD(0),
|
||||
.REVERSE(1),
|
||||
.DATA_WIDTH(48),
|
||||
.STYLE("AUTO")
|
||||
)
|
||||
eth_crc_48 (
|
||||
.data_in(s_tdata_reg[47:0]),
|
||||
.state_in(crc_state),
|
||||
.data_out(),
|
||||
.state_out(crc_next5)
|
||||
);
|
||||
|
||||
lfsr #(
|
||||
.LFSR_WIDTH(32),
|
||||
.LFSR_POLY(32'h4c11db7),
|
||||
.LFSR_CONFIG("GALOIS"),
|
||||
.LFSR_FEED_FORWARD(0),
|
||||
.REVERSE(1),
|
||||
.DATA_WIDTH(56),
|
||||
.STYLE("AUTO")
|
||||
)
|
||||
eth_crc_56 (
|
||||
.data_in(s_tdata_reg[55:0]),
|
||||
.state_in(crc_state),
|
||||
.data_out(),
|
||||
.state_out(crc_next6)
|
||||
);
|
||||
|
||||
lfsr #(
|
||||
.LFSR_WIDTH(32),
|
||||
.LFSR_POLY(32'h4c11db7),
|
||||
.LFSR_CONFIG("GALOIS"),
|
||||
.LFSR_FEED_FORWARD(0),
|
||||
.REVERSE(1),
|
||||
.DATA_WIDTH(64),
|
||||
.STYLE("AUTO")
|
||||
)
|
||||
eth_crc_64 (
|
||||
.data_in(s_tdata_reg[63:0]),
|
||||
.state_in(crc_state),
|
||||
.data_out(),
|
||||
.state_out(crc_next7)
|
||||
);
|
||||
|
||||
function [3:0] keep2count;
|
||||
input [7:0] k;
|
||||
casez (k)
|
||||
8'bzzzzzzz0: keep2count = 4'd0;
|
||||
8'bzzzzzz01: keep2count = 4'd1;
|
||||
8'bzzzzz011: keep2count = 4'd2;
|
||||
8'bzzzz0111: keep2count = 4'd3;
|
||||
8'bzzz01111: keep2count = 4'd4;
|
||||
8'bzz011111: keep2count = 4'd5;
|
||||
8'bz0111111: keep2count = 4'd6;
|
||||
8'b01111111: keep2count = 4'd7;
|
||||
8'b11111111: keep2count = 4'd8;
|
||||
endcase
|
||||
endfunction
|
||||
|
||||
// Mask input data
|
||||
integer j;
|
||||
|
||||
always @* begin
|
||||
for (j = 0; j < 8; j = j + 1) begin
|
||||
s_axis_tdata_masked[j*8 +: 8] = s_axis_tkeep[j] ? s_axis_tdata[j*8 +: 8] : 8'd0;
|
||||
end
|
||||
end
|
||||
|
||||
// FCS cycle calculation
|
||||
always @* begin
|
||||
casez (s_tkeep_reg)
|
||||
8'bzzzzzz01: begin
|
||||
fcs_output_data_0 = {24'd0, ~crc_next0[31:0], s_tdata_reg[7:0]};
|
||||
fcs_output_data_1 = 64'd0;
|
||||
fcs_output_type_0 = OUTPUT_TYPE_TERM_5;
|
||||
fcs_output_type_1 = OUTPUT_TYPE_IDLE;
|
||||
ifg_offset = 8'd3;
|
||||
extra_cycle = 1'b0;
|
||||
end
|
||||
8'bzzzzz011: begin
|
||||
fcs_output_data_0 = {16'd0, ~crc_next1[31:0], s_tdata_reg[15:0]};
|
||||
fcs_output_data_1 = 64'd0;
|
||||
fcs_output_type_0 = OUTPUT_TYPE_TERM_6;
|
||||
fcs_output_type_1 = OUTPUT_TYPE_IDLE;
|
||||
ifg_offset = 8'd2;
|
||||
extra_cycle = 1'b0;
|
||||
end
|
||||
8'bzzzz0111: begin
|
||||
fcs_output_data_0 = {8'd0, ~crc_next2[31:0], s_tdata_reg[23:0]};
|
||||
fcs_output_data_1 = 64'd0;
|
||||
fcs_output_type_0 = OUTPUT_TYPE_TERM_7;
|
||||
fcs_output_type_1 = OUTPUT_TYPE_IDLE;
|
||||
ifg_offset = 8'd1;
|
||||
extra_cycle = 1'b0;
|
||||
end
|
||||
8'bzzz01111: begin
|
||||
fcs_output_data_0 = {~crc_next3[31:0], s_tdata_reg[31:0]};
|
||||
fcs_output_data_1 = 64'd0;
|
||||
fcs_output_type_0 = OUTPUT_TYPE_DATA;
|
||||
fcs_output_type_1 = OUTPUT_TYPE_TERM_0;
|
||||
ifg_offset = 8'd8;
|
||||
extra_cycle = 1'b1;
|
||||
end
|
||||
8'bzz011111: begin
|
||||
fcs_output_data_0 = {~crc_next4[23:0], s_tdata_reg[39:0]};
|
||||
fcs_output_data_1 = {56'd0, ~crc_next4[31:24]};
|
||||
fcs_output_type_0 = OUTPUT_TYPE_DATA;
|
||||
fcs_output_type_1 = OUTPUT_TYPE_TERM_1;
|
||||
ifg_offset = 8'd7;
|
||||
extra_cycle = 1'b1;
|
||||
end
|
||||
8'bz0111111: begin
|
||||
fcs_output_data_0 = {~crc_next5[15:0], s_tdata_reg[47:0]};
|
||||
fcs_output_data_1 = {48'd0, ~crc_next5[31:16]};
|
||||
fcs_output_type_0 = OUTPUT_TYPE_DATA;
|
||||
fcs_output_type_1 = OUTPUT_TYPE_TERM_2;
|
||||
ifg_offset = 8'd6;
|
||||
extra_cycle = 1'b1;
|
||||
end
|
||||
8'b01111111: begin
|
||||
fcs_output_data_0 = {~crc_next6[7:0], s_tdata_reg[55:0]};
|
||||
fcs_output_data_1 = {40'd0, ~crc_next6[31:8]};
|
||||
fcs_output_type_0 = OUTPUT_TYPE_DATA;
|
||||
fcs_output_type_1 = OUTPUT_TYPE_TERM_3;
|
||||
ifg_offset = 8'd5;
|
||||
extra_cycle = 1'b1;
|
||||
end
|
||||
8'b11111111: begin
|
||||
fcs_output_data_0 = s_tdata_reg;
|
||||
fcs_output_data_1 = {32'd0, ~crc_next7[31:0]};
|
||||
fcs_output_type_0 = OUTPUT_TYPE_DATA;
|
||||
fcs_output_type_1 = OUTPUT_TYPE_TERM_4;
|
||||
ifg_offset = 8'd4;
|
||||
extra_cycle = 1'b1;
|
||||
end
|
||||
default: begin
|
||||
fcs_output_data_0 = 64'd0;
|
||||
fcs_output_data_1 = 64'd0;
|
||||
fcs_output_type_0 = OUTPUT_TYPE_ERROR;
|
||||
fcs_output_type_1 = OUTPUT_TYPE_ERROR;
|
||||
ifg_offset = 8'd0;
|
||||
extra_cycle = 1'b1;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
always @* begin
|
||||
state_next = STATE_IDLE;
|
||||
|
||||
reset_crc = 1'b0;
|
||||
update_crc = 1'b0;
|
||||
|
||||
swap_lanes = 1'b0;
|
||||
unswap_lanes = 1'b0;
|
||||
|
||||
frame_ptr_next = frame_ptr_reg;
|
||||
|
||||
ifg_count_next = ifg_count_reg;
|
||||
deficit_idle_count_next = deficit_idle_count_reg;
|
||||
|
||||
s_axis_tready_next = 1'b0;
|
||||
|
||||
s_tdata_next = s_tdata_reg;
|
||||
s_tkeep_next = s_tkeep_reg;
|
||||
|
||||
output_data_next = s_tdata_reg;
|
||||
output_type_next = OUTPUT_TYPE_IDLE;
|
||||
|
||||
start_packet_0_next = 1'b0;
|
||||
start_packet_4_next = 1'b0;
|
||||
|
||||
case (state_reg)
|
||||
STATE_IDLE: begin
|
||||
// idle state - wait for data
|
||||
frame_ptr_next = 16'd8;
|
||||
reset_crc = 1'b1;
|
||||
s_axis_tready_next = 1'b1;
|
||||
|
||||
output_data_next = s_tdata_reg;
|
||||
output_type_next = OUTPUT_TYPE_IDLE;
|
||||
|
||||
s_tdata_next = s_axis_tdata_masked;
|
||||
s_tkeep_next = s_axis_tkeep;
|
||||
|
||||
if (s_axis_tvalid) begin
|
||||
// XGMII start and preamble
|
||||
if (ifg_count_reg > 8'd0) begin
|
||||
// need to send more idles - swap lanes
|
||||
swap_lanes = 1'b1;
|
||||
start_packet_4_next = 1'b1;
|
||||
end else begin
|
||||
// no more idles - unswap
|
||||
unswap_lanes = 1'b1;
|
||||
start_packet_0_next = 1'b1;
|
||||
end
|
||||
output_data_next = {ETH_SFD, {7{ETH_PRE}}};
|
||||
output_type_next = OUTPUT_TYPE_START_0;
|
||||
s_axis_tready_next = 1'b1;
|
||||
state_next = STATE_PAYLOAD;
|
||||
end else begin
|
||||
ifg_count_next = 8'd0;
|
||||
deficit_idle_count_next = 2'd0;
|
||||
unswap_lanes = 1'b1;
|
||||
state_next = STATE_IDLE;
|
||||
end
|
||||
end
|
||||
STATE_PAYLOAD: begin
|
||||
// transfer payload
|
||||
update_crc = 1'b1;
|
||||
s_axis_tready_next = 1'b1;
|
||||
|
||||
frame_ptr_next = frame_ptr_reg + 16'd8;
|
||||
|
||||
output_data_next = s_tdata_reg;
|
||||
output_type_next = OUTPUT_TYPE_DATA;
|
||||
|
||||
s_tdata_next = s_axis_tdata_masked;
|
||||
s_tkeep_next = s_axis_tkeep;
|
||||
|
||||
if (s_axis_tvalid) begin
|
||||
if (s_axis_tlast) begin
|
||||
frame_ptr_next = frame_ptr_reg + keep2count(s_axis_tkeep);
|
||||
s_axis_tready_next = 1'b0;
|
||||
if (s_axis_tuser) begin
|
||||
output_type_next = OUTPUT_TYPE_ERROR;
|
||||
frame_ptr_next = 16'd0;
|
||||
ifg_count_next = 8'd8;
|
||||
state_next = STATE_IFG;
|
||||
end else begin
|
||||
s_axis_tready_next = 1'b0;
|
||||
|
||||
if (ENABLE_PADDING && (frame_ptr_reg < MIN_FL_NOCRC_MS || (frame_ptr_reg == MIN_FL_NOCRC_MS && keep2count(s_axis_tkeep) < MIN_FL_NOCRC_LS))) begin
|
||||
s_tkeep_next = 8'hff;
|
||||
frame_ptr_next = frame_ptr_reg + 16'd8;
|
||||
|
||||
if (frame_ptr_reg < (MIN_FL_NOCRC_LS > 0 ? MIN_FL_NOCRC_MS : MIN_FL_NOCRC_MS-8)) begin
|
||||
state_next = STATE_PAD;
|
||||
end else begin
|
||||
s_tkeep_next = 8'hff >> ((8-MIN_FL_NOCRC_LS) % 8);
|
||||
|
||||
state_next = STATE_FCS_1;
|
||||
end
|
||||
end else begin
|
||||
state_next = STATE_FCS_1;
|
||||
end
|
||||
end
|
||||
end else begin
|
||||
state_next = STATE_PAYLOAD;
|
||||
end
|
||||
end else begin
|
||||
// tvalid deassert, fail framec
|
||||
output_type_next = OUTPUT_TYPE_ERROR;
|
||||
frame_ptr_next = 16'd0;
|
||||
ifg_count_next = 8'd8;
|
||||
state_next = STATE_WAIT_END;
|
||||
end
|
||||
end
|
||||
STATE_PAD: begin
|
||||
// pad frame to MIN_FRAME_LENGTH
|
||||
s_axis_tready_next = 1'b0;
|
||||
|
||||
output_data_next = s_tdata_reg;
|
||||
output_type_next = OUTPUT_TYPE_DATA;
|
||||
|
||||
s_tdata_next = 64'd0;
|
||||
s_tkeep_next = 8'hff;
|
||||
|
||||
update_crc = 1'b1;
|
||||
frame_ptr_next = frame_ptr_reg + 16'd8;
|
||||
|
||||
if (frame_ptr_reg < (MIN_FL_NOCRC_LS > 0 ? MIN_FL_NOCRC_MS : MIN_FL_NOCRC_MS-8)) begin
|
||||
state_next = STATE_PAD;
|
||||
end else begin
|
||||
s_tkeep_next = 8'hff >> ((8-MIN_FL_NOCRC_LS) % 8);
|
||||
|
||||
state_next = STATE_FCS_1;
|
||||
end
|
||||
end
|
||||
STATE_FCS_1: begin
|
||||
// last cycle
|
||||
s_axis_tready_next = 1'b0;
|
||||
|
||||
output_data_next = fcs_output_data_0;
|
||||
output_type_next = fcs_output_type_0;
|
||||
|
||||
frame_ptr_next = 16'd0;
|
||||
|
||||
ifg_count_next = (ifg_delay > 8'd12 ? ifg_delay : 8'd12) - ifg_offset + (lanes_swapped ? 8'd4 : 8'd0) + deficit_idle_count_reg;
|
||||
if (extra_cycle) begin
|
||||
state_next = STATE_FCS_2;
|
||||
end else begin
|
||||
state_next = STATE_IFG;
|
||||
end
|
||||
end
|
||||
STATE_FCS_2: begin
|
||||
// last cycle
|
||||
s_axis_tready_next = 1'b0;
|
||||
|
||||
output_data_next = fcs_output_data_1;
|
||||
output_type_next = fcs_output_type_1;
|
||||
|
||||
reset_crc = 1'b1;
|
||||
frame_ptr_next = 16'd0;
|
||||
|
||||
if (ENABLE_DIC) begin
|
||||
if (ifg_count_next > 8'd7) begin
|
||||
state_next = STATE_IFG;
|
||||
end else begin
|
||||
if (ifg_count_next >= 8'd4) begin
|
||||
deficit_idle_count_next = ifg_count_next - 8'd4;
|
||||
end else begin
|
||||
deficit_idle_count_next = ifg_count_next;
|
||||
ifg_count_next = 8'd0;
|
||||
end
|
||||
s_axis_tready_next = 1'b1;
|
||||
state_next = STATE_IDLE;
|
||||
end
|
||||
end else begin
|
||||
if (ifg_count_next > 8'd4) begin
|
||||
state_next = STATE_IFG;
|
||||
end else begin
|
||||
s_axis_tready_next = 1'b1;
|
||||
state_next = STATE_IDLE;
|
||||
end
|
||||
end
|
||||
end
|
||||
STATE_IFG: begin
|
||||
// send IFG
|
||||
if (ifg_count_reg > 8'd8) begin
|
||||
ifg_count_next = ifg_count_reg - 8'd8;
|
||||
end else begin
|
||||
ifg_count_next = 8'd0;
|
||||
end
|
||||
|
||||
reset_crc = 1'b1;
|
||||
|
||||
if (ENABLE_DIC) begin
|
||||
if (ifg_count_next > 8'd7) begin
|
||||
state_next = STATE_IFG;
|
||||
end else begin
|
||||
if (ifg_count_next >= 8'd4) begin
|
||||
deficit_idle_count_next = ifg_count_next - 8'd4;
|
||||
end else begin
|
||||
deficit_idle_count_next = ifg_count_next;
|
||||
ifg_count_next = 8'd0;
|
||||
end
|
||||
s_axis_tready_next = 1'b1;
|
||||
state_next = STATE_IDLE;
|
||||
end
|
||||
end else begin
|
||||
if (ifg_count_next > 8'd4) begin
|
||||
state_next = STATE_IFG;
|
||||
end else begin
|
||||
s_axis_tready_next = 1'b1;
|
||||
state_next = STATE_IDLE;
|
||||
end
|
||||
end
|
||||
end
|
||||
STATE_WAIT_END: begin
|
||||
// wait for end of frame
|
||||
if (ifg_count_reg > 8'd8) begin
|
||||
ifg_count_next = ifg_count_reg - 8'd8;
|
||||
end else begin
|
||||
ifg_count_next = 8'd0;
|
||||
end
|
||||
|
||||
reset_crc = 1'b1;
|
||||
|
||||
if (s_axis_tvalid) begin
|
||||
if (s_axis_tlast) begin
|
||||
if (ENABLE_DIC) begin
|
||||
if (ifg_count_next > 8'd7) begin
|
||||
state_next = STATE_IFG;
|
||||
end else begin
|
||||
if (ifg_count_next >= 8'd4) begin
|
||||
deficit_idle_count_next = ifg_count_next - 8'd4;
|
||||
end else begin
|
||||
deficit_idle_count_next = ifg_count_next;
|
||||
ifg_count_next = 8'd0;
|
||||
end
|
||||
s_axis_tready_next = 1'b1;
|
||||
state_next = STATE_IDLE;
|
||||
end
|
||||
end else begin
|
||||
if (ifg_count_next > 8'd4) begin
|
||||
state_next = STATE_IFG;
|
||||
end else begin
|
||||
s_axis_tready_next = 1'b1;
|
||||
state_next = STATE_IDLE;
|
||||
end
|
||||
end
|
||||
end else begin
|
||||
state_next = STATE_WAIT_END;
|
||||
end
|
||||
end else begin
|
||||
state_next = STATE_WAIT_END;
|
||||
end
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (rst) begin
|
||||
state_reg <= STATE_IDLE;
|
||||
|
||||
frame_ptr_reg <= 16'd0;
|
||||
|
||||
ifg_count_reg <= 8'd0;
|
||||
deficit_idle_count_reg <= 2'd0;
|
||||
|
||||
s_axis_tready_reg <= 1'b0;
|
||||
|
||||
encoded_tx_data_reg <= {{8{CTRL_IDLE}}, BLOCK_TYPE_CTRL};
|
||||
encoded_tx_hdr_reg <= SYNC_CTRL;
|
||||
|
||||
output_data_reg <= {DATA_WIDTH{1'b0}};
|
||||
output_type_reg <= OUTPUT_TYPE_IDLE;
|
||||
|
||||
start_packet_0_reg <= 1'b0;
|
||||
start_packet_4_reg <= 1'b0;
|
||||
|
||||
crc_state <= 32'hFFFFFFFF;
|
||||
|
||||
lanes_swapped <= 1'b0;
|
||||
|
||||
delay_type_valid <= 1'b0;
|
||||
delay_type <= OUTPUT_TYPE_IDLE;
|
||||
end else begin
|
||||
state_reg <= state_next;
|
||||
|
||||
frame_ptr_reg <= frame_ptr_next;
|
||||
|
||||
ifg_count_reg <= ifg_count_next;
|
||||
deficit_idle_count_reg <= deficit_idle_count_next;
|
||||
|
||||
s_axis_tready_reg <= s_axis_tready_next;
|
||||
|
||||
start_packet_0_reg <= start_packet_0_next;
|
||||
start_packet_4_reg <= start_packet_4_next;
|
||||
|
||||
delay_type_valid <= 1'b0;
|
||||
|
||||
if (swap_lanes || (lanes_swapped && !unswap_lanes)) begin
|
||||
lanes_swapped <= 1'b1;
|
||||
output_data_reg <= {output_data_next[31:0], swap_data};
|
||||
if (delay_type_valid) begin
|
||||
output_type_reg <= delay_type;
|
||||
end else if (output_type_next == OUTPUT_TYPE_START_0) begin
|
||||
output_type_reg <= OUTPUT_TYPE_START_4;
|
||||
end else if (output_type_next[3]) begin
|
||||
// OUTPUT_TYPE_TERM_*
|
||||
if (output_type_next[2]) begin
|
||||
delay_type_valid <= 1'b1;
|
||||
output_type_reg <= OUTPUT_TYPE_DATA;
|
||||
end else begin
|
||||
output_type_reg <= output_type_next ^ 4'd4;
|
||||
end
|
||||
end else begin
|
||||
output_type_reg <= output_type_next;
|
||||
end
|
||||
end else begin
|
||||
lanes_swapped <= 1'b0;
|
||||
output_data_reg <= output_data_next;
|
||||
output_type_reg <= output_type_next;
|
||||
end
|
||||
|
||||
case (output_type_reg)
|
||||
OUTPUT_TYPE_IDLE: begin
|
||||
encoded_tx_data_reg <= {{8{CTRL_IDLE}}, BLOCK_TYPE_CTRL};
|
||||
encoded_tx_hdr_reg <= SYNC_CTRL;
|
||||
end
|
||||
OUTPUT_TYPE_ERROR: begin
|
||||
encoded_tx_data_reg <= {{8{CTRL_ERROR}}, BLOCK_TYPE_CTRL};
|
||||
encoded_tx_hdr_reg <= SYNC_CTRL;
|
||||
end
|
||||
OUTPUT_TYPE_START_0: begin
|
||||
encoded_tx_data_reg <= {output_data_reg[63:8], BLOCK_TYPE_START_0};
|
||||
encoded_tx_hdr_reg <= SYNC_CTRL;
|
||||
end
|
||||
OUTPUT_TYPE_START_4: begin
|
||||
encoded_tx_data_reg <= {output_data_reg[63:40], 4'd0, {4{CTRL_IDLE}}, BLOCK_TYPE_START_4};
|
||||
encoded_tx_hdr_reg <= SYNC_CTRL;
|
||||
end
|
||||
OUTPUT_TYPE_DATA: begin
|
||||
encoded_tx_data_reg <= output_data_reg;
|
||||
encoded_tx_hdr_reg <= SYNC_DATA;
|
||||
end
|
||||
OUTPUT_TYPE_TERM_0: begin
|
||||
encoded_tx_data_reg <= {{7{CTRL_IDLE}}, 7'd0, BLOCK_TYPE_TERM_0};
|
||||
encoded_tx_hdr_reg <= SYNC_CTRL;
|
||||
end
|
||||
OUTPUT_TYPE_TERM_1: begin
|
||||
encoded_tx_data_reg <= {{6{CTRL_IDLE}}, 6'd0, output_data_reg[7:0], BLOCK_TYPE_TERM_1};
|
||||
encoded_tx_hdr_reg <= SYNC_CTRL;
|
||||
end
|
||||
OUTPUT_TYPE_TERM_2: begin
|
||||
encoded_tx_data_reg <= {{5{CTRL_IDLE}}, 5'd0, output_data_reg[15:0], BLOCK_TYPE_TERM_2};
|
||||
encoded_tx_hdr_reg <= SYNC_CTRL;
|
||||
end
|
||||
OUTPUT_TYPE_TERM_3: begin
|
||||
encoded_tx_data_reg <= {{4{CTRL_IDLE}}, 4'd0, output_data_reg[23:0], BLOCK_TYPE_TERM_3};
|
||||
encoded_tx_hdr_reg <= SYNC_CTRL;
|
||||
end
|
||||
OUTPUT_TYPE_TERM_4: begin
|
||||
encoded_tx_data_reg <= {{3{CTRL_IDLE}}, 3'd0, output_data_reg[31:0], BLOCK_TYPE_TERM_4};
|
||||
encoded_tx_hdr_reg <= SYNC_CTRL;
|
||||
end
|
||||
OUTPUT_TYPE_TERM_5: begin
|
||||
encoded_tx_data_reg <= {{2{CTRL_IDLE}}, 2'd0, output_data_reg[39:0], BLOCK_TYPE_TERM_5};
|
||||
encoded_tx_hdr_reg <= SYNC_CTRL;
|
||||
end
|
||||
OUTPUT_TYPE_TERM_6: begin
|
||||
encoded_tx_data_reg <= {{1{CTRL_IDLE}}, 1'd0, output_data_reg[47:0], BLOCK_TYPE_TERM_6};
|
||||
encoded_tx_hdr_reg <= SYNC_CTRL;
|
||||
end
|
||||
OUTPUT_TYPE_TERM_7: begin
|
||||
encoded_tx_data_reg <= {output_data_reg[55:0], BLOCK_TYPE_TERM_7};
|
||||
encoded_tx_hdr_reg <= SYNC_CTRL;
|
||||
end
|
||||
default: begin
|
||||
encoded_tx_data_reg <= {{8{CTRL_ERROR}}, BLOCK_TYPE_CTRL};
|
||||
encoded_tx_hdr_reg <= SYNC_CTRL;
|
||||
end
|
||||
endcase
|
||||
|
||||
// datapath
|
||||
if (reset_crc) begin
|
||||
crc_state <= 32'hFFFFFFFF;
|
||||
end else if (update_crc) begin
|
||||
crc_state <= crc_next7;
|
||||
end
|
||||
end
|
||||
|
||||
s_tdata_reg <= s_tdata_next;
|
||||
s_tkeep_reg <= s_tkeep_next;
|
||||
|
||||
swap_data <= output_data_next[63:32];
|
||||
|
||||
delay_type <= output_type_next ^ 4'd4;
|
||||
end
|
||||
|
||||
endmodule
|
154
rtl/eth_mac_phy_10g.v
Normal file
154
rtl/eth_mac_phy_10g.v
Normal file
@ -0,0 +1,154 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2019 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
|
||||
|
||||
/*
|
||||
* 10G Ethernet MAC/PHY combination
|
||||
*/
|
||||
module eth_mac_phy_10g #
|
||||
(
|
||||
parameter DATA_WIDTH = 64,
|
||||
parameter KEEP_WIDTH = (DATA_WIDTH/8),
|
||||
parameter CTRL_WIDTH = (DATA_WIDTH/8),
|
||||
parameter HDR_WIDTH = (DATA_WIDTH/32),
|
||||
parameter ENABLE_PADDING = 1,
|
||||
parameter ENABLE_DIC = 1,
|
||||
parameter MIN_FRAME_LENGTH = 64,
|
||||
parameter BIT_REVERSE = 0,
|
||||
parameter SCRAMBLER_DISABLE = 0,
|
||||
parameter SLIP_COUNT_WIDTH = 3,
|
||||
parameter COUNT_125US = 125000/6.4
|
||||
)
|
||||
(
|
||||
input wire rx_clk,
|
||||
input wire rx_rst,
|
||||
input wire tx_clk,
|
||||
input wire tx_rst,
|
||||
|
||||
/*
|
||||
* AXI input
|
||||
*/
|
||||
input wire [DATA_WIDTH-1:0] tx_axis_tdata,
|
||||
input wire [KEEP_WIDTH-1:0] tx_axis_tkeep,
|
||||
input wire tx_axis_tvalid,
|
||||
output wire tx_axis_tready,
|
||||
input wire tx_axis_tlast,
|
||||
input wire tx_axis_tuser,
|
||||
|
||||
/*
|
||||
* AXI output
|
||||
*/
|
||||
output wire [DATA_WIDTH-1:0] rx_axis_tdata,
|
||||
output wire [KEEP_WIDTH-1:0] rx_axis_tkeep,
|
||||
output wire rx_axis_tvalid,
|
||||
output wire rx_axis_tlast,
|
||||
output wire rx_axis_tuser,
|
||||
|
||||
/*
|
||||
* SERDES interface
|
||||
*/
|
||||
output wire [DATA_WIDTH-1:0] serdes_tx_data,
|
||||
output wire [HDR_WIDTH-1:0] serdes_tx_hdr,
|
||||
input wire [DATA_WIDTH-1:0] serdes_rx_data,
|
||||
input wire [HDR_WIDTH-1:0] serdes_rx_hdr,
|
||||
output wire serdes_rx_bitslip,
|
||||
|
||||
/*
|
||||
* Status
|
||||
*/
|
||||
output wire tx_start_packet_0,
|
||||
output wire tx_start_packet_4,
|
||||
output wire rx_start_packet_0,
|
||||
output wire rx_start_packet_4,
|
||||
output wire rx_error_bad_frame,
|
||||
output wire rx_error_bad_fcs,
|
||||
output wire rx_block_lock,
|
||||
output wire rx_high_ber,
|
||||
|
||||
/*
|
||||
* Configuration
|
||||
*/
|
||||
input wire [7:0] ifg_delay
|
||||
);
|
||||
|
||||
eth_mac_phy_10g_rx #(
|
||||
.DATA_WIDTH(DATA_WIDTH),
|
||||
.KEEP_WIDTH(KEEP_WIDTH),
|
||||
.CTRL_WIDTH(CTRL_WIDTH),
|
||||
.HDR_WIDTH(HDR_WIDTH),
|
||||
.BIT_REVERSE(BIT_REVERSE),
|
||||
.SCRAMBLER_DISABLE(SCRAMBLER_DISABLE),
|
||||
.SLIP_COUNT_WIDTH(SLIP_COUNT_WIDTH),
|
||||
.COUNT_125US(COUNT_125US)
|
||||
)
|
||||
eth_mac_phy_10g_rx_inst (
|
||||
.clk(rx_clk),
|
||||
.rst(rx_rst),
|
||||
.m_axis_tdata(rx_axis_tdata),
|
||||
.m_axis_tkeep(rx_axis_tkeep),
|
||||
.m_axis_tvalid(rx_axis_tvalid),
|
||||
.m_axis_tlast(rx_axis_tlast),
|
||||
.m_axis_tuser(rx_axis_tuser),
|
||||
.serdes_rx_data(serdes_rx_data),
|
||||
.serdes_rx_hdr(serdes_rx_hdr),
|
||||
.serdes_rx_bitslip(serdes_rx_bitslip),
|
||||
.rx_start_packet_0(rx_start_packet_0),
|
||||
.rx_start_packet_4(rx_start_packet_4),
|
||||
.rx_error_bad_frame(rx_error_bad_frame),
|
||||
.rx_error_bad_fcs(rx_error_bad_fcs),
|
||||
.rx_block_lock(rx_block_lock),
|
||||
.rx_high_ber(rx_high_ber)
|
||||
);
|
||||
|
||||
eth_mac_phy_10g_tx #(
|
||||
.DATA_WIDTH(DATA_WIDTH),
|
||||
.KEEP_WIDTH(KEEP_WIDTH),
|
||||
.CTRL_WIDTH(CTRL_WIDTH),
|
||||
.HDR_WIDTH(HDR_WIDTH),
|
||||
.ENABLE_PADDING(ENABLE_PADDING),
|
||||
.ENABLE_DIC(ENABLE_DIC),
|
||||
.MIN_FRAME_LENGTH(MIN_FRAME_LENGTH),
|
||||
.BIT_REVERSE(BIT_REVERSE),
|
||||
.SCRAMBLER_DISABLE(SCRAMBLER_DISABLE)
|
||||
)
|
||||
eth_mac_phy_10g_tx_inst (
|
||||
.clk(tx_clk),
|
||||
.rst(tx_rst),
|
||||
.s_axis_tdata(tx_axis_tdata),
|
||||
.s_axis_tkeep(tx_axis_tkeep),
|
||||
.s_axis_tvalid(tx_axis_tvalid),
|
||||
.s_axis_tready(tx_axis_tready),
|
||||
.s_axis_tlast(tx_axis_tlast),
|
||||
.s_axis_tuser(tx_axis_tuser),
|
||||
.serdes_tx_data(serdes_tx_data),
|
||||
.serdes_tx_hdr(serdes_tx_hdr),
|
||||
.ifg_delay(ifg_delay),
|
||||
.tx_start_packet_0(tx_start_packet_0),
|
||||
.tx_start_packet_4(tx_start_packet_4)
|
||||
);
|
||||
|
||||
endmodule
|
295
rtl/eth_mac_phy_10g_fifo.v
Normal file
295
rtl/eth_mac_phy_10g_fifo.v
Normal file
@ -0,0 +1,295 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2019 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
|
||||
|
||||
/*
|
||||
* 10G Ethernet MAC/PHY combination with TX and RX FIFOs
|
||||
*/
|
||||
module eth_mac_phy_10g_fifo #
|
||||
(
|
||||
parameter DATA_WIDTH = 64,
|
||||
parameter KEEP_WIDTH = (DATA_WIDTH/8),
|
||||
parameter CTRL_WIDTH = (DATA_WIDTH/8),
|
||||
parameter HDR_WIDTH = (DATA_WIDTH/32),
|
||||
parameter ENABLE_PADDING = 1,
|
||||
parameter ENABLE_DIC = 1,
|
||||
parameter MIN_FRAME_LENGTH = 64,
|
||||
parameter BIT_REVERSE = 0,
|
||||
parameter SCRAMBLER_DISABLE = 0,
|
||||
parameter SLIP_COUNT_WIDTH = 3,
|
||||
parameter COUNT_125US = 125000/6.4,
|
||||
parameter TX_FIFO_ADDR_WIDTH = 12-$clog2(KEEP_WIDTH),
|
||||
parameter TX_FRAME_FIFO = 1,
|
||||
parameter TX_DROP_BAD_FRAME = TX_FRAME_FIFO,
|
||||
parameter TX_DROP_WHEN_FULL = 0,
|
||||
parameter RX_FIFO_ADDR_WIDTH = 12-$clog2(KEEP_WIDTH),
|
||||
parameter RX_FRAME_FIFO = 1,
|
||||
parameter RX_DROP_BAD_FRAME = RX_FRAME_FIFO,
|
||||
parameter RX_DROP_WHEN_FULL = RX_FRAME_FIFO
|
||||
)
|
||||
(
|
||||
input wire rx_clk,
|
||||
input wire rx_rst,
|
||||
input wire tx_clk,
|
||||
input wire tx_rst,
|
||||
input wire logic_clk,
|
||||
input wire logic_rst,
|
||||
|
||||
/*
|
||||
* AXI input
|
||||
*/
|
||||
input wire [DATA_WIDTH-1:0] tx_axis_tdata,
|
||||
input wire [KEEP_WIDTH-1:0] tx_axis_tkeep,
|
||||
input wire tx_axis_tvalid,
|
||||
output wire tx_axis_tready,
|
||||
input wire tx_axis_tlast,
|
||||
input wire tx_axis_tuser,
|
||||
|
||||
/*
|
||||
* AXI output
|
||||
*/
|
||||
output wire [DATA_WIDTH-1:0] rx_axis_tdata,
|
||||
output wire [KEEP_WIDTH-1:0] rx_axis_tkeep,
|
||||
output wire rx_axis_tvalid,
|
||||
input wire rx_axis_tready,
|
||||
output wire rx_axis_tlast,
|
||||
output wire rx_axis_tuser,
|
||||
|
||||
/*
|
||||
* SERDES interface
|
||||
*/
|
||||
output wire [DATA_WIDTH-1:0] serdes_tx_data,
|
||||
output wire [HDR_WIDTH-1:0] serdes_tx_hdr,
|
||||
input wire [DATA_WIDTH-1:0] serdes_rx_data,
|
||||
input wire [HDR_WIDTH-1:0] serdes_rx_hdr,
|
||||
output wire serdes_rx_bitslip,
|
||||
|
||||
/*
|
||||
* Status
|
||||
*/
|
||||
output wire tx_fifo_overflow,
|
||||
output wire tx_fifo_bad_frame,
|
||||
output wire tx_fifo_good_frame,
|
||||
output wire rx_error_bad_frame,
|
||||
output wire rx_error_bad_fcs,
|
||||
output wire rx_block_lock,
|
||||
output wire rx_high_ber,
|
||||
output wire rx_fifo_overflow,
|
||||
output wire rx_fifo_bad_frame,
|
||||
output wire rx_fifo_good_frame,
|
||||
|
||||
/*
|
||||
* Configuration
|
||||
*/
|
||||
input wire [7:0] ifg_delay
|
||||
);
|
||||
|
||||
wire [DATA_WIDTH-1:0] tx_fifo_axis_tdata;
|
||||
wire [KEEP_WIDTH-1:0] tx_fifo_axis_tkeep;
|
||||
wire tx_fifo_axis_tvalid;
|
||||
wire tx_fifo_axis_tready;
|
||||
wire tx_fifo_axis_tlast;
|
||||
wire tx_fifo_axis_tuser;
|
||||
|
||||
wire [DATA_WIDTH-1:0] rx_fifo_axis_tdata;
|
||||
wire [KEEP_WIDTH-1:0] rx_fifo_axis_tkeep;
|
||||
wire rx_fifo_axis_tvalid;
|
||||
wire rx_fifo_axis_tlast;
|
||||
wire rx_fifo_axis_tuser;
|
||||
|
||||
// synchronize MAC status signals into logic clock domain
|
||||
wire rx_error_bad_frame_int;
|
||||
wire rx_error_bad_fcs_int;
|
||||
|
||||
reg [3:0] rx_sync_reg_1 = 4'd0;
|
||||
reg [3:0] rx_sync_reg_2 = 4'd0;
|
||||
reg [3:0] rx_sync_reg_3 = 4'd0;
|
||||
reg [3:0] rx_sync_reg_4 = 4'd0;
|
||||
|
||||
assign rx_error_bad_frame = rx_sync_reg_3[0] ^ rx_sync_reg_4[0];
|
||||
assign rx_error_bad_fcs = rx_sync_reg_3[1] ^ rx_sync_reg_4[1];
|
||||
assign rx_block_lock = rx_sync_reg_3[2] ^ rx_sync_reg_4[2];
|
||||
assign rx_high_ber = rx_sync_reg_3[3] ^ rx_sync_reg_4[3];
|
||||
|
||||
always @(posedge rx_clk or posedge rx_rst) begin
|
||||
if (rx_rst) begin
|
||||
rx_sync_reg_1 <= 4'd0;
|
||||
end else begin
|
||||
rx_sync_reg_1 <= rx_sync_reg_1 ^ {rx_high_ber_int, rx_block_lock_int, rx_error_bad_frame_int, rx_error_bad_frame_int};
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge logic_clk or posedge logic_rst) begin
|
||||
if (logic_rst) begin
|
||||
rx_sync_reg_2 <= 4'd0;
|
||||
rx_sync_reg_3 <= 4'd0;
|
||||
rx_sync_reg_4 <= 4'd0;
|
||||
end else begin
|
||||
rx_sync_reg_2 <= rx_sync_reg_1;
|
||||
rx_sync_reg_3 <= rx_sync_reg_2;
|
||||
rx_sync_reg_4 <= rx_sync_reg_3;
|
||||
end
|
||||
end
|
||||
|
||||
eth_mac_phy_10g #(
|
||||
.DATA_WIDTH(DATA_WIDTH),
|
||||
.KEEP_WIDTH(KEEP_WIDTH),
|
||||
.CTRL_WIDTH(CTRL_WIDTH),
|
||||
.HDR_WIDTH(HDR_WIDTH),
|
||||
.ENABLE_PADDING(ENABLE_PADDING),
|
||||
.ENABLE_DIC(ENABLE_DIC),
|
||||
.MIN_FRAME_LENGTH(MIN_FRAME_LENGTH),
|
||||
.BIT_REVERSE(BIT_REVERSE),
|
||||
.SCRAMBLER_DISABLE(SCRAMBLER_DISABLE),
|
||||
.SLIP_COUNT_WIDTH(SLIP_COUNT_WIDTH),
|
||||
.COUNT_125US(COUNT_125US)
|
||||
)
|
||||
eth_mac_phy_10g_inst (
|
||||
.tx_clk(tx_clk),
|
||||
.tx_rst(tx_rst),
|
||||
.rx_clk(rx_clk),
|
||||
.rx_rst(rx_rst),
|
||||
.tx_axis_tdata(tx_fifo_axis_tdata),
|
||||
.tx_axis_tkeep(tx_fifo_axis_tkeep),
|
||||
.tx_axis_tvalid(tx_fifo_axis_tvalid),
|
||||
.tx_axis_tready(tx_fifo_axis_tready),
|
||||
.tx_axis_tlast(tx_fifo_axis_tlast),
|
||||
.tx_axis_tuser(tx_fifo_axis_tuser),
|
||||
.rx_axis_tdata(rx_fifo_axis_tdata),
|
||||
.rx_axis_tkeep(rx_fifo_axis_tkeep),
|
||||
.rx_axis_tvalid(rx_fifo_axis_tvalid),
|
||||
.rx_axis_tlast(rx_fifo_axis_tlast),
|
||||
.rx_axis_tuser(rx_fifo_axis_tuser),
|
||||
.serdes_tx_data(serdes_tx_data),
|
||||
.serdes_tx_hdr(serdes_tx_hdr),
|
||||
.serdes_rx_data(serdes_rx_data),
|
||||
.serdes_rx_hdr(serdes_rx_hdr),
|
||||
.serdes_rx_bitslip(serdes_rx_bitslip),
|
||||
.rx_error_bad_frame(rx_error_bad_frame_int),
|
||||
.rx_error_bad_fcs(rx_error_bad_fcs_int),
|
||||
.rx_block_lock(rx_block_lock_int),
|
||||
.rx_high_ber(rx_high_ber_int),
|
||||
.ifg_delay(ifg_delay)
|
||||
);
|
||||
|
||||
axis_async_fifo #(
|
||||
.ADDR_WIDTH(TX_FIFO_ADDR_WIDTH),
|
||||
.DATA_WIDTH(DATA_WIDTH),
|
||||
.KEEP_ENABLE(1),
|
||||
.KEEP_WIDTH(KEEP_WIDTH),
|
||||
.LAST_ENABLE(1),
|
||||
.ID_ENABLE(0),
|
||||
.DEST_ENABLE(0),
|
||||
.USER_ENABLE(1),
|
||||
.USER_WIDTH(1),
|
||||
.FRAME_FIFO(TX_FRAME_FIFO),
|
||||
.USER_BAD_FRAME_VALUE(1'b1),
|
||||
.USER_BAD_FRAME_MASK(1'b1),
|
||||
.DROP_BAD_FRAME(TX_DROP_BAD_FRAME),
|
||||
.DROP_WHEN_FULL(TX_DROP_WHEN_FULL)
|
||||
)
|
||||
tx_fifo (
|
||||
// Common reset
|
||||
.async_rst(logic_rst | tx_rst),
|
||||
// AXI input
|
||||
.s_clk(logic_clk),
|
||||
.s_axis_tdata(tx_axis_tdata),
|
||||
.s_axis_tkeep(tx_axis_tkeep),
|
||||
.s_axis_tvalid(tx_axis_tvalid),
|
||||
.s_axis_tready(tx_axis_tready),
|
||||
.s_axis_tlast(tx_axis_tlast),
|
||||
.s_axis_tid(0),
|
||||
.s_axis_tdest(0),
|
||||
.s_axis_tuser(tx_axis_tuser),
|
||||
// AXI output
|
||||
.m_clk(tx_clk),
|
||||
.m_axis_tdata(tx_fifo_axis_tdata),
|
||||
.m_axis_tkeep(tx_fifo_axis_tkeep),
|
||||
.m_axis_tvalid(tx_fifo_axis_tvalid),
|
||||
.m_axis_tready(tx_fifo_axis_tready),
|
||||
.m_axis_tlast(tx_fifo_axis_tlast),
|
||||
.m_axis_tid(),
|
||||
.m_axis_tdest(),
|
||||
.m_axis_tuser(tx_fifo_axis_tuser),
|
||||
// Status
|
||||
.s_status_overflow(tx_fifo_overflow),
|
||||
.s_status_bad_frame(tx_fifo_bad_frame),
|
||||
.s_status_good_frame(tx_fifo_good_frame),
|
||||
.m_status_overflow(),
|
||||
.m_status_bad_frame(),
|
||||
.m_status_good_frame()
|
||||
);
|
||||
|
||||
axis_async_fifo #(
|
||||
.ADDR_WIDTH(RX_FIFO_ADDR_WIDTH),
|
||||
.DATA_WIDTH(DATA_WIDTH),
|
||||
.KEEP_ENABLE(1),
|
||||
.KEEP_WIDTH(KEEP_WIDTH),
|
||||
.LAST_ENABLE(1),
|
||||
.ID_ENABLE(0),
|
||||
.DEST_ENABLE(0),
|
||||
.USER_ENABLE(1),
|
||||
.USER_WIDTH(1),
|
||||
.FRAME_FIFO(RX_FRAME_FIFO),
|
||||
.USER_BAD_FRAME_VALUE(1'b1),
|
||||
.USER_BAD_FRAME_MASK(1'b1),
|
||||
.DROP_BAD_FRAME(RX_DROP_BAD_FRAME),
|
||||
.DROP_WHEN_FULL(RX_DROP_WHEN_FULL)
|
||||
)
|
||||
rx_fifo (
|
||||
// Common reset
|
||||
.async_rst(rx_rst | logic_rst),
|
||||
// AXI input
|
||||
.s_clk(rx_clk),
|
||||
.s_axis_tdata(rx_fifo_axis_tdata),
|
||||
.s_axis_tkeep(rx_fifo_axis_tkeep),
|
||||
.s_axis_tvalid(rx_fifo_axis_tvalid),
|
||||
.s_axis_tready(),
|
||||
.s_axis_tlast(rx_fifo_axis_tlast),
|
||||
.s_axis_tid(0),
|
||||
.s_axis_tdest(0),
|
||||
.s_axis_tuser(rx_fifo_axis_tuser),
|
||||
// AXI output
|
||||
.m_clk(logic_clk),
|
||||
.m_axis_tdata(rx_axis_tdata),
|
||||
.m_axis_tkeep(rx_axis_tkeep),
|
||||
.m_axis_tvalid(rx_axis_tvalid),
|
||||
.m_axis_tready(rx_axis_tready),
|
||||
.m_axis_tlast(rx_axis_tlast),
|
||||
.m_axis_tid(),
|
||||
.m_axis_tdest(),
|
||||
.m_axis_tuser(rx_axis_tuser),
|
||||
// Status
|
||||
.s_status_overflow(),
|
||||
.s_status_bad_frame(),
|
||||
.s_status_good_frame(),
|
||||
.m_status_overflow(rx_fifo_overflow),
|
||||
.m_status_bad_frame(rx_fifo_bad_frame),
|
||||
.m_status_good_frame(rx_fifo_good_frame)
|
||||
);
|
||||
|
||||
endmodule
|
187
rtl/eth_mac_phy_10g_rx.v
Normal file
187
rtl/eth_mac_phy_10g_rx.v
Normal file
@ -0,0 +1,187 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2019 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
|
||||
|
||||
/*
|
||||
* 10G Ethernet MAC/PHY combination
|
||||
*/
|
||||
module eth_mac_phy_10g_rx #
|
||||
(
|
||||
parameter DATA_WIDTH = 64,
|
||||
parameter KEEP_WIDTH = (DATA_WIDTH/8),
|
||||
parameter CTRL_WIDTH = (DATA_WIDTH/8),
|
||||
parameter HDR_WIDTH = (DATA_WIDTH/32),
|
||||
parameter BIT_REVERSE = 0,
|
||||
parameter SCRAMBLER_DISABLE = 0,
|
||||
parameter SLIP_COUNT_WIDTH = 3,
|
||||
parameter COUNT_125US = 125000/6.4
|
||||
)
|
||||
(
|
||||
input wire clk,
|
||||
input wire rst,
|
||||
|
||||
/*
|
||||
* AXI output
|
||||
*/
|
||||
output wire [DATA_WIDTH-1:0] m_axis_tdata,
|
||||
output wire [KEEP_WIDTH-1:0] m_axis_tkeep,
|
||||
output wire m_axis_tvalid,
|
||||
output wire m_axis_tlast,
|
||||
output wire m_axis_tuser,
|
||||
|
||||
/*
|
||||
* SERDES interface
|
||||
*/
|
||||
input wire [DATA_WIDTH-1:0] serdes_rx_data,
|
||||
input wire [HDR_WIDTH-1:0] serdes_rx_hdr,
|
||||
output wire serdes_rx_bitslip,
|
||||
|
||||
/*
|
||||
* Status
|
||||
*/
|
||||
output wire rx_start_packet_0,
|
||||
output wire rx_start_packet_4,
|
||||
output wire rx_error_bad_frame,
|
||||
output wire rx_error_bad_fcs,
|
||||
output wire rx_block_lock,
|
||||
output wire rx_high_ber
|
||||
);
|
||||
|
||||
// bus width assertions
|
||||
initial begin
|
||||
if (DATA_WIDTH != 64) begin
|
||||
$error("Error: Interface width must be 64");
|
||||
$finish;
|
||||
end
|
||||
|
||||
if (KEEP_WIDTH * 8 != DATA_WIDTH || CTRL_WIDTH * 8 != DATA_WIDTH) begin
|
||||
$error("Error: Interface requires byte (8-bit) granularity");
|
||||
$finish;
|
||||
end
|
||||
|
||||
if (HDR_WIDTH * 32 != DATA_WIDTH) begin
|
||||
$error("Error: HDR_WIDTH must be equal to DATA_WIDTH/32");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
|
||||
wire [DATA_WIDTH-1:0] serdes_rx_data_int;
|
||||
wire [HDR_WIDTH-1:0] serdes_rx_hdr_int;
|
||||
|
||||
generate
|
||||
genvar n;
|
||||
|
||||
if (BIT_REVERSE) begin
|
||||
for (n = 0; n < DATA_WIDTH; n = n + 1) begin
|
||||
assign serdes_rx_data_int[n] = serdes_rx_data[DATA_WIDTH-n-1];
|
||||
end
|
||||
|
||||
for (n = 0; n < HDR_WIDTH; n = n + 1) begin
|
||||
assign serdes_rx_hdr_int[n] = serdes_rx_hdr[HDR_WIDTH-n-1];
|
||||
end
|
||||
end else begin
|
||||
assign serdes_rx_data_int = serdes_rx_data;
|
||||
assign serdes_rx_hdr_int = serdes_rx_hdr;
|
||||
end
|
||||
endgenerate
|
||||
|
||||
wire [DATA_WIDTH-1:0] descrambled_rx_data;
|
||||
|
||||
reg [DATA_WIDTH-1:0] encoded_rx_data_reg = {DATA_WIDTH{1'b0}};
|
||||
reg [HDR_WIDTH-1:0] encoded_rx_hdr_reg = {HDR_WIDTH{1'b0}};
|
||||
|
||||
reg [57:0] scrambler_state_reg = {58{1'b1}};
|
||||
wire [57:0] scrambler_state;
|
||||
|
||||
lfsr #(
|
||||
.LFSR_WIDTH(58),
|
||||
.LFSR_POLY(58'h8000000001),
|
||||
.LFSR_CONFIG("FIBONACCI"),
|
||||
.LFSR_FEED_FORWARD(1),
|
||||
.REVERSE(1),
|
||||
.DATA_WIDTH(DATA_WIDTH),
|
||||
.STYLE("AUTO")
|
||||
)
|
||||
descrambler_inst (
|
||||
.data_in(serdes_rx_data_int),
|
||||
.state_in(scrambler_state_reg),
|
||||
.data_out(descrambled_rx_data),
|
||||
.state_out(scrambler_state)
|
||||
);
|
||||
|
||||
always @(posedge clk) begin
|
||||
scrambler_state_reg <= scrambler_state;
|
||||
|
||||
encoded_rx_data_reg <= SCRAMBLER_DISABLE ? serdes_rx_data_int : descrambled_rx_data;
|
||||
encoded_rx_hdr_reg <= serdes_rx_hdr_int;
|
||||
end
|
||||
|
||||
axis_baser_rx_64 #(
|
||||
.DATA_WIDTH(DATA_WIDTH),
|
||||
.KEEP_WIDTH(KEEP_WIDTH),
|
||||
.HDR_WIDTH(HDR_WIDTH)
|
||||
)
|
||||
axis_baser_rx_inst (
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
.encoded_rx_data(encoded_rx_data_reg),
|
||||
.encoded_rx_hdr(encoded_rx_hdr_reg),
|
||||
.m_axis_tdata(m_axis_tdata),
|
||||
.m_axis_tkeep(m_axis_tkeep),
|
||||
.m_axis_tvalid(m_axis_tvalid),
|
||||
.m_axis_tlast(m_axis_tlast),
|
||||
.m_axis_tuser(m_axis_tuser),
|
||||
.start_packet_0(rx_start_packet_0),
|
||||
.start_packet_4(rx_start_packet_4),
|
||||
.error_bad_frame(rx_error_bad_frame),
|
||||
.error_bad_fcs(rx_error_bad_fcs)
|
||||
);
|
||||
|
||||
eth_phy_10g_rx_frame_sync #(
|
||||
.HDR_WIDTH(HDR_WIDTH),
|
||||
.SLIP_COUNT_WIDTH(SLIP_COUNT_WIDTH)
|
||||
)
|
||||
eth_phy_10g_rx_frame_sync_inst (
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
.serdes_rx_hdr(serdes_rx_hdr_int),
|
||||
.serdes_rx_bitslip(serdes_rx_bitslip),
|
||||
.rx_block_lock(rx_block_lock)
|
||||
);
|
||||
|
||||
eth_phy_10g_rx_ber_mon #(
|
||||
.HDR_WIDTH(HDR_WIDTH),
|
||||
.COUNT_125US(COUNT_125US)
|
||||
)
|
||||
eth_phy_10g_rx_ber_mon_inst (
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
.serdes_rx_hdr(serdes_rx_hdr_int),
|
||||
.rx_high_ber(rx_high_ber)
|
||||
);
|
||||
|
||||
endmodule
|
168
rtl/eth_mac_phy_10g_tx.v
Normal file
168
rtl/eth_mac_phy_10g_tx.v
Normal file
@ -0,0 +1,168 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2019 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
|
||||
|
||||
/*
|
||||
* 10G Ethernet MAC/PHY combination
|
||||
*/
|
||||
module eth_mac_phy_10g_tx #
|
||||
(
|
||||
parameter DATA_WIDTH = 64,
|
||||
parameter KEEP_WIDTH = (DATA_WIDTH/8),
|
||||
parameter CTRL_WIDTH = (DATA_WIDTH/8),
|
||||
parameter HDR_WIDTH = (DATA_WIDTH/32),
|
||||
parameter ENABLE_PADDING = 1,
|
||||
parameter ENABLE_DIC = 1,
|
||||
parameter MIN_FRAME_LENGTH = 64,
|
||||
parameter BIT_REVERSE = 0,
|
||||
parameter SCRAMBLER_DISABLE = 0
|
||||
)
|
||||
(
|
||||
input wire clk,
|
||||
input wire rst,
|
||||
|
||||
/*
|
||||
* AXI input
|
||||
*/
|
||||
input wire [DATA_WIDTH-1:0] s_axis_tdata,
|
||||
input wire [KEEP_WIDTH-1:0] s_axis_tkeep,
|
||||
input wire s_axis_tvalid,
|
||||
output wire s_axis_tready,
|
||||
input wire s_axis_tlast,
|
||||
input wire s_axis_tuser,
|
||||
|
||||
/*
|
||||
* SERDES interface
|
||||
*/
|
||||
output wire [DATA_WIDTH-1:0] serdes_tx_data,
|
||||
output wire [HDR_WIDTH-1:0] serdes_tx_hdr,
|
||||
|
||||
/*
|
||||
* Configuration
|
||||
*/
|
||||
input wire [7:0] ifg_delay,
|
||||
|
||||
/*
|
||||
* Status
|
||||
*/
|
||||
output wire tx_start_packet_0,
|
||||
output wire tx_start_packet_4
|
||||
);
|
||||
|
||||
// bus width assertions
|
||||
initial begin
|
||||
if (DATA_WIDTH != 64) begin
|
||||
$error("Error: Interface width must be 64");
|
||||
$finish;
|
||||
end
|
||||
|
||||
if (KEEP_WIDTH * 8 != DATA_WIDTH || CTRL_WIDTH * 8 != DATA_WIDTH) begin
|
||||
$error("Error: Interface requires byte (8-bit) granularity");
|
||||
$finish;
|
||||
end
|
||||
|
||||
if (HDR_WIDTH * 32 != DATA_WIDTH) begin
|
||||
$error("Error: HDR_WIDTH must be equal to DATA_WIDTH/32");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
|
||||
wire [DATA_WIDTH-1:0] encoded_tx_data;
|
||||
wire [HDR_WIDTH-1:0] encoded_tx_hdr;
|
||||
|
||||
axis_baser_tx_64 #(
|
||||
.DATA_WIDTH(DATA_WIDTH),
|
||||
.KEEP_WIDTH(KEEP_WIDTH),
|
||||
.HDR_WIDTH(HDR_WIDTH),
|
||||
.ENABLE_PADDING(ENABLE_PADDING),
|
||||
.ENABLE_DIC(ENABLE_DIC),
|
||||
.MIN_FRAME_LENGTH(MIN_FRAME_LENGTH)
|
||||
)
|
||||
axis_baser_tx_inst (
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
.s_axis_tdata(s_axis_tdata),
|
||||
.s_axis_tkeep(s_axis_tkeep),
|
||||
.s_axis_tvalid(s_axis_tvalid),
|
||||
.s_axis_tready(s_axis_tready),
|
||||
.s_axis_tlast(s_axis_tlast),
|
||||
.s_axis_tuser(s_axis_tuser),
|
||||
.encoded_tx_data(encoded_tx_data),
|
||||
.encoded_tx_hdr(encoded_tx_hdr),
|
||||
.ifg_delay(ifg_delay),
|
||||
.start_packet_0(tx_start_packet_0),
|
||||
.start_packet_4(tx_start_packet_4)
|
||||
);
|
||||
|
||||
reg [57:0] tx_scrambler_state_reg = {58{1'b1}};
|
||||
wire [57:0] tx_scrambler_state;
|
||||
wire [DATA_WIDTH-1:0] scrambled_data;
|
||||
|
||||
reg [DATA_WIDTH-1:0] serdes_tx_data_reg = {DATA_WIDTH{1'b0}};
|
||||
reg [HDR_WIDTH-1:0] serdes_tx_hdr_reg = {HDR_WIDTH{1'b0}};
|
||||
|
||||
generate
|
||||
genvar n;
|
||||
|
||||
if (BIT_REVERSE) begin
|
||||
for (n = 0; n < DATA_WIDTH; n = n + 1) begin
|
||||
assign serdes_tx_data[n] = serdes_tx_data_reg[DATA_WIDTH-n-1];
|
||||
end
|
||||
|
||||
for (n = 0; n < HDR_WIDTH; n = n + 1) begin
|
||||
assign serdes_tx_hdr[n] = serdes_tx_hdr_reg[HDR_WIDTH-n-1];
|
||||
end
|
||||
end else begin
|
||||
assign serdes_tx_data = serdes_tx_data_reg;
|
||||
assign serdes_tx_hdr = serdes_tx_hdr_reg;
|
||||
end
|
||||
endgenerate
|
||||
|
||||
lfsr #(
|
||||
.LFSR_WIDTH(58),
|
||||
.LFSR_POLY(58'h8000000001),
|
||||
.LFSR_CONFIG("FIBONACCI"),
|
||||
.LFSR_FEED_FORWARD(0),
|
||||
.REVERSE(1),
|
||||
.DATA_WIDTH(DATA_WIDTH),
|
||||
.STYLE("AUTO")
|
||||
)
|
||||
scrambler_inst (
|
||||
.data_in(encoded_tx_data),
|
||||
.state_in(tx_scrambler_state_reg),
|
||||
.data_out(scrambled_data),
|
||||
.state_out(tx_scrambler_state)
|
||||
);
|
||||
|
||||
always @(posedge clk) begin
|
||||
tx_scrambler_state_reg <= tx_scrambler_state;
|
||||
|
||||
serdes_tx_data_reg <= SCRAMBLER_DISABLE ? encoded_tx_data : scrambled_data;
|
||||
serdes_tx_hdr_reg <= encoded_tx_hdr;
|
||||
end
|
||||
|
||||
endmodule
|
438
tb/test_axis_baser_rx_64.py
Executable file
438
tb/test_axis_baser_rx_64.py
Executable file
@ -0,0 +1,438 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
|
||||
Copyright (c) 2019 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 baser_serdes_ep
|
||||
import xgmii_ep
|
||||
|
||||
module = 'axis_baser_rx_64'
|
||||
testbench = 'test_%s' % module
|
||||
|
||||
srcs = []
|
||||
|
||||
srcs.append("../rtl/%s.v" % module)
|
||||
srcs.append("../rtl/lfsr.v")
|
||||
srcs.append("%s.v" % testbench)
|
||||
|
||||
src = ' '.join(srcs)
|
||||
|
||||
build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
|
||||
|
||||
def bench():
|
||||
|
||||
# Parameters
|
||||
DATA_WIDTH = 64
|
||||
KEEP_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(1)[HDR_WIDTH:])
|
||||
|
||||
# Outputs
|
||||
m_axis_tdata = Signal(intbv(0)[DATA_WIDTH:])
|
||||
m_axis_tkeep = Signal(intbv(0)[KEEP_WIDTH:])
|
||||
m_axis_tvalid = Signal(bool(0))
|
||||
m_axis_tlast = Signal(bool(0))
|
||||
m_axis_tuser = Signal(bool(0))
|
||||
start_packet_0 = Signal(bool(0))
|
||||
start_packet_4 = Signal(bool(0))
|
||||
error_bad_frame = Signal(bool(0))
|
||||
error_bad_fcs = 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 = axis_ep.AXIStreamSink()
|
||||
|
||||
sink_logic = sink.create_logic(
|
||||
clk,
|
||||
rst,
|
||||
tdata=m_axis_tdata,
|
||||
tkeep=m_axis_tkeep,
|
||||
tvalid=m_axis_tvalid,
|
||||
tlast=m_axis_tlast,
|
||||
tuser=m_axis_tuser,
|
||||
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,
|
||||
encoded_rx_data=encoded_rx_data,
|
||||
encoded_rx_hdr=encoded_rx_hdr,
|
||||
m_axis_tdata=m_axis_tdata,
|
||||
m_axis_tkeep=m_axis_tkeep,
|
||||
m_axis_tvalid=m_axis_tvalid,
|
||||
m_axis_tlast=m_axis_tlast,
|
||||
m_axis_tuser=m_axis_tuser,
|
||||
start_packet_0=start_packet_0,
|
||||
start_packet_4=start_packet_4,
|
||||
error_bad_frame=error_bad_frame,
|
||||
error_bad_fcs=error_bad_fcs
|
||||
)
|
||||
|
||||
@always(delay(4))
|
||||
def clkgen():
|
||||
clk.next = not clk
|
||||
|
||||
error_bad_frame_asserted = Signal(bool(0))
|
||||
error_bad_fcs_asserted = Signal(bool(0))
|
||||
|
||||
@always(clk.posedge)
|
||||
def monitor():
|
||||
if (error_bad_frame):
|
||||
error_bad_frame_asserted.next = 1
|
||||
if (error_bad_fcs):
|
||||
error_bad_fcs_asserted.next = 1
|
||||
|
||||
@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(1,18))+list(range(64,82)):
|
||||
yield clk.posedge
|
||||
print("test 1: test packet, length %d" % payload_len)
|
||||
current_test.next = 1
|
||||
|
||||
test_frame = eth_ep.EthFrame()
|
||||
test_frame.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame.eth_src_mac = 0x5A5152535455
|
||||
test_frame.eth_type = 0x8000
|
||||
test_frame.payload = bytearray(range(payload_len))
|
||||
test_frame.update_fcs()
|
||||
|
||||
axis_frame = test_frame.build_axis_fcs()
|
||||
|
||||
xgmii_frame = xgmii_ep.XGMIIFrame(b'\x55\x55\x55\x55\x55\x55\x55\xD5'+bytearray(axis_frame))
|
||||
|
||||
source.send(xgmii_frame)
|
||||
|
||||
yield sink.wait()
|
||||
rx_frame = sink.recv()
|
||||
|
||||
eth_frame = eth_ep.EthFrame()
|
||||
eth_frame.parse_axis(rx_frame)
|
||||
eth_frame.update_fcs()
|
||||
|
||||
assert eth_frame == test_frame
|
||||
|
||||
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 = eth_ep.EthFrame()
|
||||
test_frame1.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame1.eth_src_mac = 0x5A5152535455
|
||||
test_frame1.eth_type = 0x8000
|
||||
test_frame1.payload = bytearray(range(payload_len))
|
||||
test_frame1.update_fcs()
|
||||
test_frame2 = eth_ep.EthFrame()
|
||||
test_frame2.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame2.eth_src_mac = 0x5A5152535455
|
||||
test_frame2.eth_type = 0x8000
|
||||
test_frame2.payload = bytearray(range(payload_len))
|
||||
test_frame2.update_fcs()
|
||||
|
||||
axis_frame1 = test_frame1.build_axis_fcs()
|
||||
axis_frame2 = test_frame2.build_axis_fcs()
|
||||
|
||||
xgmii_frame1 = xgmii_ep.XGMIIFrame(b'\x55\x55\x55\x55\x55\x55\x55\xD5'+bytearray(axis_frame1))
|
||||
xgmii_frame2 = xgmii_ep.XGMIIFrame(b'\x55\x55\x55\x55\x55\x55\x55\xD5'+bytearray(axis_frame2))
|
||||
|
||||
source.send(xgmii_frame1)
|
||||
source.send(xgmii_frame2)
|
||||
|
||||
yield sink.wait()
|
||||
rx_frame = sink.recv()
|
||||
|
||||
eth_frame = eth_ep.EthFrame()
|
||||
eth_frame.parse_axis(rx_frame)
|
||||
eth_frame.update_fcs()
|
||||
|
||||
assert eth_frame == test_frame1
|
||||
|
||||
yield sink.wait()
|
||||
rx_frame = sink.recv()
|
||||
|
||||
eth_frame = eth_ep.EthFrame()
|
||||
eth_frame.parse_axis(rx_frame)
|
||||
eth_frame.update_fcs()
|
||||
|
||||
assert eth_frame == test_frame2
|
||||
|
||||
assert sink.empty()
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 3: truncated frame, length %d" % payload_len)
|
||||
current_test.next = 3
|
||||
|
||||
test_frame1 = eth_ep.EthFrame()
|
||||
test_frame1.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame1.eth_src_mac = 0x5A5152535455
|
||||
test_frame1.eth_type = 0x8000
|
||||
test_frame1.payload = bytearray(range(payload_len))
|
||||
test_frame1.update_fcs()
|
||||
test_frame2 = eth_ep.EthFrame()
|
||||
test_frame2.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame2.eth_src_mac = 0x5A5152535455
|
||||
test_frame2.eth_type = 0x8000
|
||||
test_frame2.payload = bytearray(range(payload_len))
|
||||
test_frame2.update_fcs()
|
||||
|
||||
axis_frame1 = test_frame1.build_axis_fcs()
|
||||
axis_frame2 = test_frame2.build_axis_fcs()
|
||||
|
||||
axis_frame1.data = axis_frame1.data[:-1]
|
||||
|
||||
error_bad_frame_asserted.next = 0
|
||||
error_bad_fcs_asserted.next = 0
|
||||
|
||||
xgmii_frame1 = xgmii_ep.XGMIIFrame(b'\x55\x55\x55\x55\x55\x55\x55\xD5'+bytearray(axis_frame1))
|
||||
xgmii_frame2 = xgmii_ep.XGMIIFrame(b'\x55\x55\x55\x55\x55\x55\x55\xD5'+bytearray(axis_frame2))
|
||||
|
||||
source.send(xgmii_frame1)
|
||||
source.send(xgmii_frame2)
|
||||
|
||||
yield sink.wait()
|
||||
rx_frame = sink.recv()
|
||||
|
||||
assert error_bad_frame_asserted
|
||||
assert error_bad_fcs_asserted
|
||||
|
||||
assert rx_frame.user[-1]
|
||||
|
||||
yield sink.wait()
|
||||
rx_frame = sink.recv()
|
||||
|
||||
eth_frame = eth_ep.EthFrame()
|
||||
eth_frame.parse_axis(rx_frame)
|
||||
eth_frame.update_fcs()
|
||||
|
||||
assert eth_frame == test_frame2
|
||||
|
||||
assert sink.empty()
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 4: errored frame, length %d" % payload_len)
|
||||
current_test.next = 4
|
||||
|
||||
test_frame1 = eth_ep.EthFrame()
|
||||
test_frame1.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame1.eth_src_mac = 0x5A5152535455
|
||||
test_frame1.eth_type = 0x8000
|
||||
test_frame1.payload = bytearray(range(payload_len))
|
||||
test_frame1.update_fcs()
|
||||
test_frame2 = eth_ep.EthFrame()
|
||||
test_frame2.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame2.eth_src_mac = 0x5A5152535455
|
||||
test_frame2.eth_type = 0x8000
|
||||
test_frame2.payload = bytearray(range(payload_len))
|
||||
test_frame2.update_fcs()
|
||||
|
||||
axis_frame1 = test_frame1.build_axis_fcs()
|
||||
axis_frame2 = test_frame2.build_axis_fcs()
|
||||
|
||||
error_bad_frame_asserted.next = 0
|
||||
error_bad_fcs_asserted.next = 0
|
||||
|
||||
xgmii_frame1 = xgmii_ep.XGMIIFrame(b'\x55\x55\x55\x55\x55\x55\x55\xD5'+bytearray(axis_frame1))
|
||||
xgmii_frame2 = xgmii_ep.XGMIIFrame(b'\x55\x55\x55\x55\x55\x55\x55\xD5'+bytearray(axis_frame2))
|
||||
|
||||
xgmii_frame1.error = 1
|
||||
|
||||
source.send(xgmii_frame1)
|
||||
source.send(xgmii_frame2)
|
||||
|
||||
yield sink.wait()
|
||||
rx_frame = sink.recv()
|
||||
|
||||
assert error_bad_frame_asserted
|
||||
assert not error_bad_fcs_asserted
|
||||
|
||||
assert rx_frame.last_cycle_user
|
||||
|
||||
yield sink.wait()
|
||||
rx_frame = sink.recv()
|
||||
|
||||
eth_frame = eth_ep.EthFrame()
|
||||
eth_frame.parse_axis(rx_frame)
|
||||
eth_frame.update_fcs()
|
||||
|
||||
assert eth_frame == test_frame2
|
||||
|
||||
assert sink.empty()
|
||||
|
||||
yield delay(100)
|
||||
|
||||
for payload_len in list(range(46,54)):
|
||||
yield clk.posedge
|
||||
print("test 5: test stream, length %d" % payload_len)
|
||||
current_test.next = 5
|
||||
|
||||
for i in range(10):
|
||||
test_frame = eth_ep.EthFrame()
|
||||
test_frame.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame.eth_src_mac = 0x5A5152535455
|
||||
test_frame.eth_type = 0x8000
|
||||
test_frame.payload = bytearray(range(payload_len))
|
||||
test_frame.update_fcs()
|
||||
|
||||
axis_frame = test_frame.build_axis_fcs()
|
||||
|
||||
source.send(b'\x55\x55\x55\x55\x55\x55\x55\xD5'+bytearray(axis_frame))
|
||||
|
||||
for i in range(10):
|
||||
yield sink.wait()
|
||||
rx_frame = sink.recv()
|
||||
|
||||
eth_frame = eth_ep.EthFrame()
|
||||
eth_frame.parse_axis(rx_frame)
|
||||
eth_frame.update_fcs()
|
||||
|
||||
assert eth_frame == test_frame
|
||||
|
||||
yield delay(100)
|
||||
|
||||
for payload_len in list(range(46,54)):
|
||||
yield clk.posedge
|
||||
print("test 6: test stream with zero IFG, length %d" % payload_len)
|
||||
current_test.next = 6
|
||||
|
||||
source.ifg = 0
|
||||
|
||||
for i in range(10):
|
||||
test_frame = eth_ep.EthFrame()
|
||||
test_frame.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame.eth_src_mac = 0x5A5152535455
|
||||
test_frame.eth_type = 0x8000
|
||||
test_frame.payload = bytearray(range(payload_len))
|
||||
test_frame.update_fcs()
|
||||
|
||||
axis_frame = test_frame.build_axis_fcs()
|
||||
|
||||
source.send(b'\x55\x55\x55\x55\x55\x55\x55\xD5'+bytearray(axis_frame))
|
||||
|
||||
for i in range(10):
|
||||
yield sink.wait()
|
||||
rx_frame = sink.recv()
|
||||
|
||||
eth_frame = eth_ep.EthFrame()
|
||||
eth_frame.parse_axis(rx_frame)
|
||||
eth_frame.update_fcs()
|
||||
|
||||
assert eth_frame == test_frame
|
||||
|
||||
source.ifg = 12
|
||||
|
||||
yield delay(100)
|
||||
|
||||
for payload_len in list(range(46,54)):
|
||||
yield clk.posedge
|
||||
print("test 6: test stream with zero IFG and offset start, length %d" % payload_len)
|
||||
current_test.next = 6
|
||||
|
||||
source.ifg = 0
|
||||
source.force_offset_start = True
|
||||
|
||||
for i in range(10):
|
||||
test_frame = eth_ep.EthFrame()
|
||||
test_frame.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame.eth_src_mac = 0x5A5152535455
|
||||
test_frame.eth_type = 0x8000
|
||||
test_frame.payload = bytearray(range(payload_len))
|
||||
test_frame.update_fcs()
|
||||
|
||||
axis_frame = test_frame.build_axis_fcs()
|
||||
|
||||
source.send(b'\x55\x55\x55\x55\x55\x55\x55\xD5'+bytearray(axis_frame))
|
||||
|
||||
for i in range(10):
|
||||
yield sink.wait()
|
||||
rx_frame = sink.recv()
|
||||
|
||||
eth_frame = eth_ep.EthFrame()
|
||||
eth_frame.parse_axis(rx_frame)
|
||||
eth_frame.update_fcs()
|
||||
|
||||
assert eth_frame == test_frame
|
||||
|
||||
source.ifg = 12
|
||||
source.force_offset_start = False
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield delay(100)
|
||||
|
||||
raise StopSimulation
|
||||
|
||||
return instances()
|
||||
|
||||
def test_bench():
|
||||
sim = Simulation(bench())
|
||||
sim.run()
|
||||
|
||||
if __name__ == '__main__':
|
||||
print("Running test...")
|
||||
test_bench()
|
105
tb/test_axis_baser_rx_64.v
Normal file
105
tb/test_axis_baser_rx_64.v
Normal file
@ -0,0 +1,105 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2019 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 axis_baser_rx_64
|
||||
*/
|
||||
module test_axis_baser_rx_64;
|
||||
|
||||
// Parameters
|
||||
parameter DATA_WIDTH = 64;
|
||||
parameter KEEP_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 = 1;
|
||||
|
||||
// Outputs
|
||||
wire [DATA_WIDTH-1:0] m_axis_tdata;
|
||||
wire [KEEP_WIDTH-1:0] m_axis_tkeep;
|
||||
wire m_axis_tvalid;
|
||||
wire m_axis_tlast;
|
||||
wire m_axis_tuser;
|
||||
wire start_packet_0;
|
||||
wire start_packet_4;
|
||||
wire error_bad_frame;
|
||||
wire error_bad_fcs;
|
||||
|
||||
initial begin
|
||||
// myhdl integration
|
||||
$from_myhdl(
|
||||
clk,
|
||||
rst,
|
||||
current_test,
|
||||
encoded_rx_data,
|
||||
encoded_rx_hdr
|
||||
);
|
||||
$to_myhdl(
|
||||
m_axis_tdata,
|
||||
m_axis_tkeep,
|
||||
m_axis_tvalid,
|
||||
m_axis_tlast,
|
||||
m_axis_tuser,
|
||||
start_packet_0,
|
||||
start_packet_4,
|
||||
error_bad_frame,
|
||||
error_bad_fcs
|
||||
);
|
||||
|
||||
// dump file
|
||||
$dumpfile("test_axis_baser_rx_64.lxt");
|
||||
$dumpvars(0, test_axis_baser_rx_64);
|
||||
end
|
||||
|
||||
axis_baser_rx_64 #(
|
||||
.DATA_WIDTH(DATA_WIDTH),
|
||||
.KEEP_WIDTH(KEEP_WIDTH),
|
||||
.HDR_WIDTH(HDR_WIDTH)
|
||||
)
|
||||
UUT (
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
.encoded_rx_data(encoded_rx_data),
|
||||
.encoded_rx_hdr(encoded_rx_hdr),
|
||||
.m_axis_tdata(m_axis_tdata),
|
||||
.m_axis_tkeep(m_axis_tkeep),
|
||||
.m_axis_tvalid(m_axis_tvalid),
|
||||
.m_axis_tlast(m_axis_tlast),
|
||||
.m_axis_tuser(m_axis_tuser),
|
||||
.start_packet_0(start_packet_0),
|
||||
.start_packet_4(start_packet_4),
|
||||
.error_bad_frame(error_bad_frame),
|
||||
.error_bad_fcs(error_bad_fcs)
|
||||
);
|
||||
|
||||
endmodule
|
345
tb/test_axis_baser_tx_64.py
Executable file
345
tb/test_axis_baser_tx_64.py
Executable file
@ -0,0 +1,345 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
|
||||
Copyright (c) 2019 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 baser_serdes_ep
|
||||
|
||||
module = 'axis_baser_tx_64'
|
||||
testbench = 'test_%s' % module
|
||||
|
||||
srcs = []
|
||||
|
||||
srcs.append("../rtl/%s.v" % module)
|
||||
srcs.append("../rtl/lfsr.v")
|
||||
srcs.append("%s.v" % testbench)
|
||||
|
||||
src = ' '.join(srcs)
|
||||
|
||||
build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
|
||||
|
||||
def bench():
|
||||
|
||||
# Parameters
|
||||
DATA_WIDTH = 64
|
||||
KEEP_WIDTH = (DATA_WIDTH/8)
|
||||
HDR_WIDTH = 2
|
||||
ENABLE_PADDING = 1
|
||||
ENABLE_DIC = 1
|
||||
MIN_FRAME_LENGTH = 64
|
||||
|
||||
# Inputs
|
||||
clk = Signal(bool(0))
|
||||
rst = Signal(bool(0))
|
||||
current_test = Signal(intbv(0)[8:])
|
||||
|
||||
s_axis_tdata = Signal(intbv(0)[DATA_WIDTH:])
|
||||
s_axis_tkeep = Signal(intbv(0)[KEEP_WIDTH:])
|
||||
s_axis_tvalid = Signal(bool(0))
|
||||
s_axis_tlast = Signal(bool(0))
|
||||
s_axis_tuser = Signal(bool(0))
|
||||
ifg_delay = Signal(intbv(0)[8:])
|
||||
|
||||
# Outputs
|
||||
s_axis_tready = Signal(bool(0))
|
||||
encoded_tx_data = Signal(intbv(0)[DATA_WIDTH:])
|
||||
encoded_tx_hdr = Signal(intbv(1)[HDR_WIDTH:])
|
||||
start_packet_0 = Signal(bool(0))
|
||||
start_packet_4 = Signal(bool(0))
|
||||
|
||||
# sources and sinks
|
||||
source_pause = Signal(bool(0))
|
||||
|
||||
source = axis_ep.AXIStreamSource()
|
||||
|
||||
source_logic = source.create_logic(
|
||||
clk,
|
||||
rst,
|
||||
tdata=s_axis_tdata,
|
||||
tkeep=s_axis_tkeep,
|
||||
tvalid=s_axis_tvalid,
|
||||
tready=s_axis_tready,
|
||||
tlast=s_axis_tlast,
|
||||
tuser=s_axis_tuser,
|
||||
pause=source_pause,
|
||||
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,
|
||||
s_axis_tdata=s_axis_tdata,
|
||||
s_axis_tkeep=s_axis_tkeep,
|
||||
s_axis_tvalid=s_axis_tvalid,
|
||||
s_axis_tready=s_axis_tready,
|
||||
s_axis_tlast=s_axis_tlast,
|
||||
s_axis_tuser=s_axis_tuser,
|
||||
encoded_tx_data=encoded_tx_data,
|
||||
encoded_tx_hdr=encoded_tx_hdr,
|
||||
ifg_delay=ifg_delay,
|
||||
start_packet_0=start_packet_0,
|
||||
start_packet_4=start_packet_4,
|
||||
)
|
||||
|
||||
@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
|
||||
|
||||
ifg_delay.next = 12
|
||||
|
||||
# testbench stimulus
|
||||
|
||||
for payload_len in list(range(1,18))+list(range(40,58)):
|
||||
yield clk.posedge
|
||||
print("test 1: test packet, length %d" % payload_len)
|
||||
current_test.next = 1
|
||||
|
||||
test_frame = eth_ep.EthFrame()
|
||||
test_frame.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame.eth_src_mac = 0x5A5152535455
|
||||
test_frame.eth_type = 0x8000
|
||||
test_frame.payload = bytearray(range(payload_len))
|
||||
test_frame.update_fcs()
|
||||
|
||||
axis_frame = test_frame.build_axis()
|
||||
|
||||
source.send(axis_frame)
|
||||
|
||||
yield sink.wait()
|
||||
rx_frame = sink.recv()
|
||||
|
||||
assert rx_frame.data[0:8] == bytearray(b'\x55\x55\x55\x55\x55\x55\x55\xD5')
|
||||
|
||||
eth_frame = eth_ep.EthFrame()
|
||||
eth_frame.parse_axis_fcs(rx_frame.data[8:])
|
||||
|
||||
print(hex(eth_frame.eth_fcs))
|
||||
print(hex(eth_frame.calc_fcs()))
|
||||
|
||||
assert len(eth_frame.payload.data) == max(payload_len, 46)
|
||||
assert eth_frame.eth_fcs == eth_frame.calc_fcs()
|
||||
assert eth_frame.eth_dest_mac == test_frame.eth_dest_mac
|
||||
assert eth_frame.eth_src_mac == test_frame.eth_src_mac
|
||||
assert eth_frame.eth_type == test_frame.eth_type
|
||||
assert eth_frame.payload.data.index(test_frame.payload.data) == 0
|
||||
|
||||
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 = eth_ep.EthFrame()
|
||||
test_frame1.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame1.eth_src_mac = 0x5A5152535455
|
||||
test_frame1.eth_type = 0x8000
|
||||
test_frame1.payload = bytearray(range(payload_len))
|
||||
test_frame1.update_fcs()
|
||||
test_frame2 = eth_ep.EthFrame()
|
||||
test_frame2.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame2.eth_src_mac = 0x5A5152535455
|
||||
test_frame2.eth_type = 0x8000
|
||||
test_frame2.payload = bytearray(range(payload_len))
|
||||
test_frame2.update_fcs()
|
||||
|
||||
axis_frame1 = test_frame1.build_axis()
|
||||
axis_frame2 = test_frame2.build_axis()
|
||||
|
||||
source.send(axis_frame1)
|
||||
source.send(axis_frame2)
|
||||
|
||||
yield sink.wait()
|
||||
rx_frame = sink.recv()
|
||||
|
||||
assert rx_frame.data[0:8] == bytearray(b'\x55\x55\x55\x55\x55\x55\x55\xD5')
|
||||
|
||||
eth_frame = eth_ep.EthFrame()
|
||||
eth_frame.parse_axis_fcs(rx_frame.data[8:])
|
||||
|
||||
print(hex(eth_frame.eth_fcs))
|
||||
print(hex(eth_frame.calc_fcs()))
|
||||
|
||||
assert len(eth_frame.payload.data) == max(payload_len, 46)
|
||||
assert eth_frame.eth_fcs == eth_frame.calc_fcs()
|
||||
assert eth_frame.eth_dest_mac == test_frame1.eth_dest_mac
|
||||
assert eth_frame.eth_src_mac == test_frame1.eth_src_mac
|
||||
assert eth_frame.eth_type == test_frame1.eth_type
|
||||
assert eth_frame.payload.data.index(test_frame1.payload.data) == 0
|
||||
|
||||
yield sink.wait()
|
||||
rx_frame = sink.recv()
|
||||
|
||||
assert rx_frame.data[0:8] == bytearray(b'\x55\x55\x55\x55\x55\x55\x55\xD5')
|
||||
|
||||
eth_frame = eth_ep.EthFrame()
|
||||
eth_frame.parse_axis_fcs(rx_frame.data[8:])
|
||||
|
||||
print(hex(eth_frame.eth_fcs))
|
||||
print(hex(eth_frame.calc_fcs()))
|
||||
|
||||
assert len(eth_frame.payload.data) == max(payload_len, 46)
|
||||
assert eth_frame.eth_fcs == eth_frame.calc_fcs()
|
||||
assert eth_frame.eth_dest_mac == test_frame2.eth_dest_mac
|
||||
assert eth_frame.eth_src_mac == test_frame2.eth_src_mac
|
||||
assert eth_frame.eth_type == test_frame2.eth_type
|
||||
assert eth_frame.payload.data.index(test_frame2.payload.data) == 0
|
||||
|
||||
assert sink.empty()
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 3: tuser assert, length %d" % payload_len)
|
||||
current_test.next = 3
|
||||
|
||||
test_frame1 = eth_ep.EthFrame()
|
||||
test_frame1.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame1.eth_src_mac = 0x5A5152535455
|
||||
test_frame1.eth_type = 0x8000
|
||||
test_frame1.payload = bytearray(range(payload_len))
|
||||
test_frame1.update_fcs()
|
||||
test_frame2 = eth_ep.EthFrame()
|
||||
test_frame2.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame2.eth_src_mac = 0x5A5152535455
|
||||
test_frame2.eth_type = 0x8000
|
||||
test_frame2.payload = bytearray(range(payload_len))
|
||||
test_frame2.update_fcs()
|
||||
|
||||
axis_frame1 = test_frame1.build_axis()
|
||||
axis_frame2 = test_frame2.build_axis()
|
||||
|
||||
axis_frame1.last_cycle_user = 1
|
||||
|
||||
source.send(axis_frame1)
|
||||
source.send(axis_frame2)
|
||||
|
||||
yield sink.wait()
|
||||
rx_frame = sink.recv()
|
||||
|
||||
assert rx_frame.data[0:8] == bytearray(b'\x55\x55\x55\x55\x55\x55\x55\xD5')
|
||||
assert rx_frame.error[-1]
|
||||
|
||||
# bad packet
|
||||
|
||||
yield sink.wait()
|
||||
rx_frame = sink.recv()
|
||||
|
||||
assert rx_frame.data[0:8] == bytearray(b'\x55\x55\x55\x55\x55\x55\x55\xD5')
|
||||
|
||||
eth_frame = eth_ep.EthFrame()
|
||||
eth_frame.parse_axis_fcs(rx_frame.data[8:])
|
||||
|
||||
print(hex(eth_frame.eth_fcs))
|
||||
print(hex(eth_frame.calc_fcs()))
|
||||
|
||||
assert len(eth_frame.payload.data) == max(payload_len, 46)
|
||||
assert eth_frame.eth_fcs == eth_frame.calc_fcs()
|
||||
assert eth_frame.eth_dest_mac == test_frame2.eth_dest_mac
|
||||
assert eth_frame.eth_src_mac == test_frame2.eth_src_mac
|
||||
assert eth_frame.eth_type == test_frame2.eth_type
|
||||
assert eth_frame.payload.data.index(test_frame2.payload.data) == 0
|
||||
|
||||
assert sink.empty()
|
||||
|
||||
yield delay(100)
|
||||
|
||||
for payload_len in list(range(46,54)):
|
||||
yield clk.posedge
|
||||
print("test 4: test stream, length %d" % payload_len)
|
||||
current_test.next = 4
|
||||
|
||||
for i in range(10):
|
||||
test_frame = eth_ep.EthFrame()
|
||||
test_frame.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame.eth_src_mac = 0x5A5152535455
|
||||
test_frame.eth_type = 0x8000
|
||||
test_frame.payload = bytearray(range(payload_len))
|
||||
test_frame.update_fcs()
|
||||
|
||||
axis_frame = test_frame.build_axis()
|
||||
|
||||
source.send(axis_frame)
|
||||
|
||||
for i in range(10):
|
||||
yield sink.wait()
|
||||
rx_frame = sink.recv()
|
||||
|
||||
assert rx_frame.data[0:8] == bytearray(b'\x55\x55\x55\x55\x55\x55\x55\xD5')
|
||||
|
||||
eth_frame = eth_ep.EthFrame()
|
||||
eth_frame.parse_axis_fcs(rx_frame.data[8:])
|
||||
|
||||
assert len(eth_frame.payload.data) == max(payload_len, 46)
|
||||
assert eth_frame.eth_fcs == eth_frame.calc_fcs()
|
||||
assert eth_frame.eth_dest_mac == test_frame.eth_dest_mac
|
||||
assert eth_frame.eth_src_mac == test_frame.eth_src_mac
|
||||
assert eth_frame.eth_type == test_frame.eth_type
|
||||
assert eth_frame.payload.data.index(test_frame.payload.data) == 0
|
||||
|
||||
yield delay(100)
|
||||
|
||||
raise StopSimulation
|
||||
|
||||
return instances()
|
||||
|
||||
def test_bench():
|
||||
sim = Simulation(bench())
|
||||
sim.run()
|
||||
|
||||
if __name__ == '__main__':
|
||||
print("Running test...")
|
||||
test_bench()
|
111
tb/test_axis_baser_tx_64.v
Normal file
111
tb/test_axis_baser_tx_64.v
Normal file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2019 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 axis_baser_tx_64
|
||||
*/
|
||||
module test_axis_baser_tx_64;
|
||||
|
||||
// Parameters
|
||||
parameter DATA_WIDTH = 64;
|
||||
parameter KEEP_WIDTH = (DATA_WIDTH/8);
|
||||
parameter HDR_WIDTH = 2;
|
||||
parameter ENABLE_PADDING = 1;
|
||||
parameter ENABLE_DIC = 1;
|
||||
parameter MIN_FRAME_LENGTH = 64;
|
||||
|
||||
// Inputs
|
||||
reg clk = 0;
|
||||
reg rst = 0;
|
||||
reg [7:0] current_test = 0;
|
||||
|
||||
reg [DATA_WIDTH-1:0] s_axis_tdata = 0;
|
||||
reg [KEEP_WIDTH-1:0] s_axis_tkeep = 0;
|
||||
reg s_axis_tvalid = 0;
|
||||
reg s_axis_tlast = 0;
|
||||
reg s_axis_tuser = 0;
|
||||
reg [7:0] ifg_delay = 0;
|
||||
|
||||
// Outputs
|
||||
wire s_axis_tready;
|
||||
wire [DATA_WIDTH-1:0] encoded_tx_data;
|
||||
wire [HDR_WIDTH-1:0] encoded_tx_hdr;
|
||||
wire start_packet_0;
|
||||
wire start_packet_4;
|
||||
|
||||
initial begin
|
||||
// myhdl integration
|
||||
$from_myhdl(
|
||||
clk,
|
||||
rst,
|
||||
current_test,
|
||||
s_axis_tdata,
|
||||
s_axis_tkeep,
|
||||
s_axis_tvalid,
|
||||
s_axis_tlast,
|
||||
s_axis_tuser,
|
||||
ifg_delay
|
||||
);
|
||||
$to_myhdl(
|
||||
s_axis_tready,
|
||||
encoded_tx_data,
|
||||
encoded_tx_hdr,
|
||||
start_packet_0,
|
||||
start_packet_4
|
||||
);
|
||||
|
||||
// dump file
|
||||
$dumpfile("test_axis_baser_tx_64.lxt");
|
||||
$dumpvars(0, test_axis_baser_tx_64);
|
||||
end
|
||||
|
||||
axis_baser_tx_64 #(
|
||||
.DATA_WIDTH(DATA_WIDTH),
|
||||
.KEEP_WIDTH(KEEP_WIDTH),
|
||||
.HDR_WIDTH(HDR_WIDTH),
|
||||
.ENABLE_PADDING(ENABLE_PADDING),
|
||||
.ENABLE_DIC(ENABLE_DIC),
|
||||
.MIN_FRAME_LENGTH(MIN_FRAME_LENGTH)
|
||||
)
|
||||
UUT (
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
.s_axis_tdata(s_axis_tdata),
|
||||
.s_axis_tkeep(s_axis_tkeep),
|
||||
.s_axis_tvalid(s_axis_tvalid),
|
||||
.s_axis_tready(s_axis_tready),
|
||||
.s_axis_tlast(s_axis_tlast),
|
||||
.s_axis_tuser(s_axis_tuser),
|
||||
.encoded_tx_data(encoded_tx_data),
|
||||
.encoded_tx_hdr(encoded_tx_hdr),
|
||||
.ifg_delay(ifg_delay),
|
||||
.start_packet_0(start_packet_0),
|
||||
.start_packet_4(start_packet_4)
|
||||
);
|
||||
|
||||
endmodule
|
320
tb/test_eth_mac_phy_10g.py
Executable file
320
tb/test_eth_mac_phy_10g.py
Executable file
@ -0,0 +1,320 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
|
||||
Copyright (c) 2019 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 = 'eth_mac_phy_10g'
|
||||
testbench = 'test_%s' % module
|
||||
|
||||
srcs = []
|
||||
|
||||
srcs.append("../rtl/%s.v" % module)
|
||||
srcs.append("../rtl/axis_baser_tx_64.v")
|
||||
srcs.append("../rtl/axis_baser_rx_64.v")
|
||||
srcs.append("../rtl/eth_mac_phy_10g_rx.v")
|
||||
srcs.append("../rtl/eth_mac_phy_10g_tx.v")
|
||||
srcs.append("../rtl/eth_phy_10g_rx_ber_mon.v")
|
||||
srcs.append("../rtl/eth_phy_10g_rx_frame_sync.v")
|
||||
srcs.append("../rtl/lfsr.v")
|
||||
srcs.append("%s.v" % testbench)
|
||||
|
||||
src = ' '.join(srcs)
|
||||
|
||||
build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
|
||||
|
||||
def bench():
|
||||
|
||||
# Parameters
|
||||
DATA_WIDTH = 64
|
||||
KEEP_WIDTH = (DATA_WIDTH/8)
|
||||
CTRL_WIDTH = (DATA_WIDTH/8)
|
||||
HDR_WIDTH = (DATA_WIDTH/32)
|
||||
ENABLE_PADDING = 1
|
||||
ENABLE_DIC = 1
|
||||
MIN_FRAME_LENGTH = 64
|
||||
BIT_REVERSE = 0
|
||||
SCRAMBLER_DISABLE = 0
|
||||
SLIP_COUNT_WIDTH = 3
|
||||
COUNT_125US = 125000/6.4
|
||||
|
||||
# Inputs
|
||||
clk = Signal(bool(0))
|
||||
rst = Signal(bool(0))
|
||||
current_test = Signal(intbv(0)[8:])
|
||||
|
||||
rx_clk = Signal(bool(0))
|
||||
rx_rst = Signal(bool(0))
|
||||
tx_clk = Signal(bool(0))
|
||||
tx_rst = Signal(bool(0))
|
||||
tx_axis_tdata = Signal(intbv(0)[DATA_WIDTH:])
|
||||
tx_axis_tkeep = Signal(intbv(0)[KEEP_WIDTH:])
|
||||
tx_axis_tvalid = Signal(bool(0))
|
||||
tx_axis_tlast = Signal(bool(0))
|
||||
tx_axis_tuser = Signal(bool(0))
|
||||
serdes_rx_data = Signal(intbv(0)[DATA_WIDTH:])
|
||||
serdes_rx_hdr = Signal(intbv(1)[HDR_WIDTH:])
|
||||
ifg_delay = Signal(intbv(0)[8:])
|
||||
|
||||
serdes_rx_data_int = Signal(intbv(0)[DATA_WIDTH:])
|
||||
serdes_rx_hdr_int = Signal(intbv(1)[HDR_WIDTH:])
|
||||
|
||||
# Outputs
|
||||
tx_axis_tready = Signal(bool(0))
|
||||
rx_axis_tdata = Signal(intbv(0)[DATA_WIDTH:])
|
||||
rx_axis_tkeep = Signal(intbv(0)[KEEP_WIDTH:])
|
||||
rx_axis_tvalid = Signal(bool(0))
|
||||
rx_axis_tlast = Signal(bool(0))
|
||||
rx_axis_tuser = Signal(bool(0))
|
||||
serdes_tx_data = Signal(intbv(0)[DATA_WIDTH:])
|
||||
serdes_tx_hdr = Signal(intbv(1)[HDR_WIDTH:])
|
||||
serdes_rx_bitslip = Signal(bool(0))
|
||||
tx_start_packet_0 = Signal(bool(0))
|
||||
tx_start_packet_4 = Signal(bool(0))
|
||||
rx_start_packet_0 = Signal(bool(0))
|
||||
rx_start_packet_4 = Signal(bool(0))
|
||||
rx_error_bad_frame = Signal(bool(0))
|
||||
rx_error_bad_fcs = Signal(bool(0))
|
||||
rx_block_lock = Signal(bool(0))
|
||||
rx_high_ber = Signal(bool(0))
|
||||
|
||||
# sources and sinks
|
||||
axis_source_pause = Signal(bool(0))
|
||||
|
||||
serdes_source = baser_serdes_ep.BaseRSerdesSource()
|
||||
|
||||
serdes_source_logic = serdes_source.create_logic(
|
||||
rx_clk,
|
||||
tx_data=serdes_rx_data_int,
|
||||
tx_header=serdes_rx_hdr_int,
|
||||
name='serdes_source'
|
||||
)
|
||||
|
||||
serdes_sink = baser_serdes_ep.BaseRSerdesSink()
|
||||
|
||||
serdes_sink_logic = serdes_sink.create_logic(
|
||||
tx_clk,
|
||||
rx_data=serdes_tx_data,
|
||||
rx_header=serdes_tx_hdr,
|
||||
name='serdes_sink'
|
||||
)
|
||||
|
||||
axis_source = axis_ep.AXIStreamSource()
|
||||
|
||||
axis_source_logic = axis_source.create_logic(
|
||||
tx_clk,
|
||||
tx_rst,
|
||||
tdata=tx_axis_tdata,
|
||||
tkeep=tx_axis_tkeep,
|
||||
tvalid=tx_axis_tvalid,
|
||||
tready=tx_axis_tready,
|
||||
tlast=tx_axis_tlast,
|
||||
tuser=tx_axis_tuser,
|
||||
pause=axis_source_pause,
|
||||
name='axis_source'
|
||||
)
|
||||
|
||||
axis_sink = axis_ep.AXIStreamSink()
|
||||
|
||||
axis_sink_logic = axis_sink.create_logic(
|
||||
rx_clk,
|
||||
rx_rst,
|
||||
tdata=rx_axis_tdata,
|
||||
tkeep=rx_axis_tkeep,
|
||||
tvalid=rx_axis_tvalid,
|
||||
tlast=rx_axis_tlast,
|
||||
tuser=rx_axis_tuser,
|
||||
name='axis_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,
|
||||
rx_clk=rx_clk,
|
||||
rx_rst=rx_rst,
|
||||
tx_clk=tx_clk,
|
||||
tx_rst=tx_rst,
|
||||
tx_axis_tdata=tx_axis_tdata,
|
||||
tx_axis_tkeep=tx_axis_tkeep,
|
||||
tx_axis_tvalid=tx_axis_tvalid,
|
||||
tx_axis_tready=tx_axis_tready,
|
||||
tx_axis_tlast=tx_axis_tlast,
|
||||
tx_axis_tuser=tx_axis_tuser,
|
||||
rx_axis_tdata=rx_axis_tdata,
|
||||
rx_axis_tkeep=rx_axis_tkeep,
|
||||
rx_axis_tvalid=rx_axis_tvalid,
|
||||
rx_axis_tlast=rx_axis_tlast,
|
||||
rx_axis_tuser=rx_axis_tuser,
|
||||
serdes_tx_data=serdes_tx_data,
|
||||
serdes_tx_hdr=serdes_tx_hdr,
|
||||
serdes_rx_data=serdes_rx_data,
|
||||
serdes_rx_hdr=serdes_rx_hdr,
|
||||
serdes_rx_bitslip=serdes_rx_bitslip,
|
||||
tx_start_packet_0=tx_start_packet_0,
|
||||
tx_start_packet_4=tx_start_packet_4,
|
||||
rx_start_packet_0=rx_start_packet_0,
|
||||
rx_start_packet_4=rx_start_packet_4,
|
||||
rx_error_bad_frame=rx_error_bad_frame,
|
||||
rx_error_bad_fcs=rx_error_bad_fcs,
|
||||
rx_block_lock=rx_block_lock,
|
||||
rx_high_ber=rx_high_ber,
|
||||
ifg_delay=ifg_delay
|
||||
)
|
||||
|
||||
@always(delay(4))
|
||||
def clkgen():
|
||||
clk.next = not clk
|
||||
tx_clk.next = not tx_clk
|
||||
rx_clk.next = not rx_clk
|
||||
|
||||
load_bit_offset = []
|
||||
|
||||
@instance
|
||||
def shift_bits():
|
||||
bit_offset = 0
|
||||
last_data = 0
|
||||
|
||||
while True:
|
||||
yield clk.posedge
|
||||
|
||||
if load_bit_offset:
|
||||
bit_offset = load_bit_offset.pop(0)
|
||||
|
||||
if serdes_rx_bitslip:
|
||||
bit_offset += 1
|
||||
|
||||
bit_offset = bit_offset % 66
|
||||
|
||||
data = int(serdes_rx_data_int) << 2 | int(serdes_rx_hdr_int)
|
||||
|
||||
out_data = ((last_data | data << 66) >> 66-bit_offset) & 0x3ffffffffffffffff
|
||||
|
||||
last_data = data
|
||||
|
||||
serdes_rx_data.next = out_data >> 2
|
||||
serdes_rx_hdr.next = out_data & 3
|
||||
|
||||
@instance
|
||||
def check():
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
rst.next = 1
|
||||
tx_rst.next = 1
|
||||
rx_rst.next = 1
|
||||
yield clk.posedge
|
||||
rst.next = 0
|
||||
tx_rst.next = 0
|
||||
rx_rst.next = 0
|
||||
yield clk.posedge
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
|
||||
ifg_delay.next = 12
|
||||
|
||||
# testbench stimulus
|
||||
|
||||
yield clk.posedge
|
||||
print("test 1: test rx packet")
|
||||
current_test.next = 1
|
||||
|
||||
test_frame = eth_ep.EthFrame()
|
||||
test_frame.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame.eth_src_mac = 0x5A5152535455
|
||||
test_frame.eth_type = 0x8000
|
||||
test_frame.payload = bytearray(range(32))
|
||||
test_frame.update_fcs()
|
||||
|
||||
axis_frame = test_frame.build_axis_fcs()
|
||||
|
||||
serdes_source.send(b'\x55\x55\x55\x55\x55\x55\x55\xD5'+bytearray(axis_frame))
|
||||
|
||||
yield axis_sink.wait()
|
||||
rx_frame = axis_sink.recv()
|
||||
|
||||
eth_frame = eth_ep.EthFrame()
|
||||
eth_frame.parse_axis(rx_frame)
|
||||
eth_frame.update_fcs()
|
||||
|
||||
assert eth_frame == test_frame
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 2: test tx packet")
|
||||
current_test.next = 2
|
||||
|
||||
test_frame = eth_ep.EthFrame()
|
||||
test_frame.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame.eth_src_mac = 0x5A5152535455
|
||||
test_frame.eth_type = 0x8000
|
||||
test_frame.payload = bytearray(range(32))
|
||||
test_frame.update_fcs()
|
||||
|
||||
axis_frame = test_frame.build_axis()
|
||||
|
||||
axis_source.send(axis_frame)
|
||||
|
||||
yield serdes_sink.wait()
|
||||
rx_frame = serdes_sink.recv()
|
||||
|
||||
assert rx_frame.data[0:8] == bytearray(b'\x55\x55\x55\x55\x55\x55\x55\xD5')
|
||||
|
||||
eth_frame = eth_ep.EthFrame()
|
||||
eth_frame.parse_axis_fcs(rx_frame.data[8:])
|
||||
|
||||
print(hex(eth_frame.eth_fcs))
|
||||
print(hex(eth_frame.calc_fcs()))
|
||||
|
||||
assert len(eth_frame.payload.data) == 46
|
||||
assert eth_frame.eth_fcs == eth_frame.calc_fcs()
|
||||
assert eth_frame.eth_dest_mac == test_frame.eth_dest_mac
|
||||
assert eth_frame.eth_src_mac == test_frame.eth_src_mac
|
||||
assert eth_frame.eth_type == test_frame.eth_type
|
||||
assert eth_frame.payload.data.index(test_frame.payload.data) == 0
|
||||
|
||||
yield delay(100)
|
||||
|
||||
raise StopSimulation
|
||||
|
||||
return instances()
|
||||
|
||||
def test_bench():
|
||||
sim = Simulation(bench())
|
||||
sim.run()
|
||||
|
||||
if __name__ == '__main__':
|
||||
print("Running test...")
|
||||
test_bench()
|
173
tb/test_eth_mac_phy_10g.v
Normal file
173
tb/test_eth_mac_phy_10g.v
Normal file
@ -0,0 +1,173 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2019 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 eth_mac_phy_10g
|
||||
*/
|
||||
module test_eth_mac_phy_10g;
|
||||
|
||||
// Parameters
|
||||
parameter DATA_WIDTH = 64;
|
||||
parameter KEEP_WIDTH = (DATA_WIDTH/8);
|
||||
parameter CTRL_WIDTH = (DATA_WIDTH/8);
|
||||
parameter HDR_WIDTH = (DATA_WIDTH/32);
|
||||
parameter ENABLE_PADDING = 1;
|
||||
parameter ENABLE_DIC = 1;
|
||||
parameter MIN_FRAME_LENGTH = 64;
|
||||
parameter BIT_REVERSE = 0;
|
||||
parameter SCRAMBLER_DISABLE = 0;
|
||||
parameter SLIP_COUNT_WIDTH = 3;
|
||||
parameter COUNT_125US = 125000/6.4;
|
||||
|
||||
// Inputs
|
||||
reg clk = 0;
|
||||
reg rst = 0;
|
||||
reg [7:0] current_test = 0;
|
||||
|
||||
reg rx_clk = 0;
|
||||
reg rx_rst = 0;
|
||||
reg tx_clk = 0;
|
||||
reg tx_rst = 0;
|
||||
reg [DATA_WIDTH-1:0] tx_axis_tdata = 0;
|
||||
reg [KEEP_WIDTH-1:0] tx_axis_tkeep = 0;
|
||||
reg tx_axis_tvalid = 0;
|
||||
reg tx_axis_tlast = 0;
|
||||
reg tx_axis_tuser = 0;
|
||||
reg [DATA_WIDTH-1:0] serdes_rx_data = 0;
|
||||
reg [HDR_WIDTH-1:0] serdes_rx_hdr = 1;
|
||||
reg [7:0] ifg_delay = 0;
|
||||
|
||||
// Outputs
|
||||
wire tx_axis_tready;
|
||||
wire [DATA_WIDTH-1:0] rx_axis_tdata;
|
||||
wire [KEEP_WIDTH-1:0] rx_axis_tkeep;
|
||||
wire rx_axis_tvalid;
|
||||
wire rx_axis_tlast;
|
||||
wire rx_axis_tuser;
|
||||
wire [DATA_WIDTH-1:0] serdes_tx_data;
|
||||
wire [HDR_WIDTH-1:0] serdes_tx_hdr;
|
||||
wire serdes_rx_bitslip;
|
||||
wire tx_start_packet_0;
|
||||
wire tx_start_packet_4;
|
||||
wire rx_start_packet_0;
|
||||
wire rx_start_packet_4;
|
||||
wire rx_error_bad_frame;
|
||||
wire rx_error_bad_fcs;
|
||||
wire rx_block_lock;
|
||||
wire rx_high_ber;
|
||||
|
||||
initial begin
|
||||
// myhdl integration
|
||||
$from_myhdl(
|
||||
clk,
|
||||
rst,
|
||||
current_test,
|
||||
rx_clk,
|
||||
rx_rst,
|
||||
tx_clk,
|
||||
tx_rst,
|
||||
tx_axis_tdata,
|
||||
tx_axis_tkeep,
|
||||
tx_axis_tvalid,
|
||||
tx_axis_tlast,
|
||||
tx_axis_tuser,
|
||||
serdes_rx_data,
|
||||
serdes_rx_hdr,
|
||||
ifg_delay
|
||||
);
|
||||
$to_myhdl(
|
||||
tx_axis_tready,
|
||||
rx_axis_tdata,
|
||||
rx_axis_tkeep,
|
||||
rx_axis_tvalid,
|
||||
rx_axis_tlast,
|
||||
rx_axis_tuser,
|
||||
serdes_tx_data,
|
||||
serdes_tx_hdr,
|
||||
serdes_rx_bitslip,
|
||||
tx_start_packet_0,
|
||||
tx_start_packet_4,
|
||||
rx_start_packet_0,
|
||||
rx_start_packet_4,
|
||||
rx_error_bad_frame,
|
||||
rx_error_bad_fcs,
|
||||
rx_block_lock,
|
||||
rx_high_ber
|
||||
);
|
||||
|
||||
// dump file
|
||||
$dumpfile("test_eth_mac_phy_10g.lxt");
|
||||
$dumpvars(0, test_eth_mac_phy_10g);
|
||||
end
|
||||
|
||||
eth_mac_phy_10g #(
|
||||
.DATA_WIDTH(DATA_WIDTH),
|
||||
.KEEP_WIDTH(KEEP_WIDTH),
|
||||
.CTRL_WIDTH(CTRL_WIDTH),
|
||||
.HDR_WIDTH(HDR_WIDTH),
|
||||
.ENABLE_PADDING(ENABLE_PADDING),
|
||||
.ENABLE_DIC(ENABLE_DIC),
|
||||
.MIN_FRAME_LENGTH(MIN_FRAME_LENGTH),
|
||||
.BIT_REVERSE(BIT_REVERSE),
|
||||
.SCRAMBLER_DISABLE(SCRAMBLER_DISABLE),
|
||||
.SLIP_COUNT_WIDTH(SLIP_COUNT_WIDTH),
|
||||
.COUNT_125US(COUNT_125US)
|
||||
)
|
||||
UUT (
|
||||
.rx_clk(rx_clk),
|
||||
.rx_rst(rx_rst),
|
||||
.tx_clk(tx_clk),
|
||||
.tx_rst(tx_rst),
|
||||
.tx_axis_tdata(tx_axis_tdata),
|
||||
.tx_axis_tkeep(tx_axis_tkeep),
|
||||
.tx_axis_tvalid(tx_axis_tvalid),
|
||||
.tx_axis_tready(tx_axis_tready),
|
||||
.tx_axis_tlast(tx_axis_tlast),
|
||||
.tx_axis_tuser(tx_axis_tuser),
|
||||
.rx_axis_tdata(rx_axis_tdata),
|
||||
.rx_axis_tkeep(rx_axis_tkeep),
|
||||
.rx_axis_tvalid(rx_axis_tvalid),
|
||||
.rx_axis_tlast(rx_axis_tlast),
|
||||
.rx_axis_tuser(rx_axis_tuser),
|
||||
.serdes_tx_data(serdes_tx_data),
|
||||
.serdes_tx_hdr(serdes_tx_hdr),
|
||||
.serdes_rx_data(serdes_rx_data),
|
||||
.serdes_rx_hdr(serdes_rx_hdr),
|
||||
.serdes_rx_bitslip(serdes_rx_bitslip),
|
||||
.tx_start_packet_0(tx_start_packet_0),
|
||||
.tx_start_packet_4(tx_start_packet_4),
|
||||
.rx_start_packet_0(rx_start_packet_0),
|
||||
.rx_start_packet_4(rx_start_packet_4),
|
||||
.rx_error_bad_frame(rx_error_bad_frame),
|
||||
.rx_error_bad_fcs(rx_error_bad_fcs),
|
||||
.rx_block_lock(rx_block_lock),
|
||||
.rx_high_ber(rx_high_ber),
|
||||
.ifg_delay(ifg_delay)
|
||||
);
|
||||
|
||||
endmodule
|
344
tb/test_eth_mac_phy_10g_fifo.py
Executable file
344
tb/test_eth_mac_phy_10g_fifo.py
Executable file
@ -0,0 +1,344 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
|
||||
Copyright (c) 2019 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 = 'eth_mac_phy_10g_fifo'
|
||||
testbench = 'test_%s' % module
|
||||
|
||||
srcs = []
|
||||
|
||||
srcs.append("../rtl/%s.v" % module)
|
||||
srcs.append("../rtl/axis_baser_tx_64.v")
|
||||
srcs.append("../rtl/axis_baser_rx_64.v")
|
||||
srcs.append("../rtl/eth_mac_phy_10g.v")
|
||||
srcs.append("../rtl/eth_mac_phy_10g_rx.v")
|
||||
srcs.append("../rtl/eth_mac_phy_10g_tx.v")
|
||||
srcs.append("../rtl/eth_phy_10g_rx_ber_mon.v")
|
||||
srcs.append("../rtl/eth_phy_10g_rx_frame_sync.v")
|
||||
srcs.append("../rtl/lfsr.v")
|
||||
srcs.append("../lib/axis/rtl/axis_async_fifo.v")
|
||||
srcs.append("%s.v" % testbench)
|
||||
|
||||
src = ' '.join(srcs)
|
||||
|
||||
build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
|
||||
|
||||
def bench():
|
||||
|
||||
# Parameters
|
||||
DATA_WIDTH = 64
|
||||
KEEP_WIDTH = int(DATA_WIDTH/8)
|
||||
CTRL_WIDTH = int(DATA_WIDTH/8)
|
||||
HDR_WIDTH = int(DATA_WIDTH/32)
|
||||
ENABLE_PADDING = 1
|
||||
ENABLE_DIC = 1
|
||||
MIN_FRAME_LENGTH = 64
|
||||
BIT_REVERSE = 0
|
||||
SCRAMBLER_DISABLE = 0
|
||||
SLIP_COUNT_WIDTH = 3
|
||||
COUNT_125US = 125000/6.4
|
||||
TX_FIFO_ADDR_WIDTH = 12-(KEEP_WIDTH-1).bit_length()
|
||||
TX_FRAME_FIFO = 1
|
||||
TX_DROP_BAD_FRAME = TX_FRAME_FIFO
|
||||
TX_DROP_WHEN_FULL = 0
|
||||
RX_FIFO_ADDR_WIDTH = 12-(KEEP_WIDTH-1).bit_length()
|
||||
RX_FRAME_FIFO = 1
|
||||
RX_DROP_BAD_FRAME = RX_FRAME_FIFO
|
||||
RX_DROP_WHEN_FULL = RX_FRAME_FIFO
|
||||
|
||||
# Inputs
|
||||
clk = Signal(bool(0))
|
||||
rst = Signal(bool(0))
|
||||
current_test = Signal(intbv(0)[8:])
|
||||
|
||||
rx_clk = Signal(bool(0))
|
||||
rx_rst = Signal(bool(0))
|
||||
tx_clk = Signal(bool(0))
|
||||
tx_rst = Signal(bool(0))
|
||||
logic_clk = Signal(bool(0))
|
||||
logic_rst = Signal(bool(0))
|
||||
tx_axis_tdata = Signal(intbv(0)[DATA_WIDTH:])
|
||||
tx_axis_tkeep = Signal(intbv(0)[KEEP_WIDTH:])
|
||||
tx_axis_tvalid = Signal(bool(0))
|
||||
tx_axis_tlast = Signal(bool(0))
|
||||
tx_axis_tuser = Signal(bool(0))
|
||||
rx_axis_tready = Signal(bool(0))
|
||||
serdes_rx_data = Signal(intbv(0)[DATA_WIDTH:])
|
||||
serdes_rx_hdr = Signal(intbv(1)[HDR_WIDTH:])
|
||||
ifg_delay = Signal(intbv(0)[8:])
|
||||
|
||||
serdes_rx_data_int = Signal(intbv(0)[DATA_WIDTH:])
|
||||
serdes_rx_hdr_int = Signal(intbv(1)[HDR_WIDTH:])
|
||||
|
||||
# Outputs
|
||||
tx_axis_tready = Signal(bool(0))
|
||||
rx_axis_tdata = Signal(intbv(0)[DATA_WIDTH:])
|
||||
rx_axis_tkeep = Signal(intbv(0)[KEEP_WIDTH:])
|
||||
rx_axis_tvalid = Signal(bool(0))
|
||||
rx_axis_tlast = Signal(bool(0))
|
||||
rx_axis_tuser = Signal(bool(0))
|
||||
serdes_tx_data = Signal(intbv(0)[DATA_WIDTH:])
|
||||
serdes_tx_hdr = Signal(intbv(1)[HDR_WIDTH:])
|
||||
serdes_rx_bitslip = Signal(bool(0))
|
||||
tx_fifo_overflow = Signal(bool(0))
|
||||
tx_fifo_bad_frame = Signal(bool(0))
|
||||
tx_fifo_good_frame = Signal(bool(0))
|
||||
rx_error_bad_frame = Signal(bool(0))
|
||||
rx_error_bad_fcs = Signal(bool(0))
|
||||
rx_block_lock = Signal(bool(0))
|
||||
rx_high_ber = Signal(bool(0))
|
||||
rx_fifo_overflow = Signal(bool(0))
|
||||
rx_fifo_bad_frame = Signal(bool(0))
|
||||
rx_fifo_good_frame = Signal(bool(0))
|
||||
|
||||
# sources and sinks
|
||||
axis_source_pause = Signal(bool(0))
|
||||
|
||||
serdes_source = baser_serdes_ep.BaseRSerdesSource()
|
||||
|
||||
serdes_source_logic = serdes_source.create_logic(
|
||||
rx_clk,
|
||||
tx_data=serdes_rx_data_int,
|
||||
tx_header=serdes_rx_hdr_int,
|
||||
name='serdes_source'
|
||||
)
|
||||
|
||||
serdes_sink = baser_serdes_ep.BaseRSerdesSink()
|
||||
|
||||
serdes_sink_logic = serdes_sink.create_logic(
|
||||
tx_clk,
|
||||
rx_data=serdes_tx_data,
|
||||
rx_header=serdes_tx_hdr,
|
||||
name='serdes_sink'
|
||||
)
|
||||
|
||||
axis_source = axis_ep.AXIStreamSource()
|
||||
|
||||
axis_source_logic = axis_source.create_logic(
|
||||
logic_clk,
|
||||
logic_rst,
|
||||
tdata=tx_axis_tdata,
|
||||
tkeep=tx_axis_tkeep,
|
||||
tvalid=tx_axis_tvalid,
|
||||
tready=tx_axis_tready,
|
||||
tlast=tx_axis_tlast,
|
||||
tuser=tx_axis_tuser,
|
||||
pause=axis_source_pause,
|
||||
name='axis_source'
|
||||
)
|
||||
|
||||
axis_sink = axis_ep.AXIStreamSink()
|
||||
|
||||
axis_sink_logic = axis_sink.create_logic(
|
||||
logic_clk,
|
||||
logic_rst,
|
||||
tdata=rx_axis_tdata,
|
||||
tkeep=rx_axis_tkeep,
|
||||
tvalid=rx_axis_tvalid,
|
||||
tready=rx_axis_tready,
|
||||
tlast=rx_axis_tlast,
|
||||
tuser=rx_axis_tuser,
|
||||
name='axis_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,
|
||||
rx_clk=rx_clk,
|
||||
rx_rst=rx_rst,
|
||||
tx_clk=tx_clk,
|
||||
tx_rst=tx_rst,
|
||||
logic_clk=logic_clk,
|
||||
logic_rst=logic_rst,
|
||||
tx_axis_tdata=tx_axis_tdata,
|
||||
tx_axis_tkeep=tx_axis_tkeep,
|
||||
tx_axis_tvalid=tx_axis_tvalid,
|
||||
tx_axis_tready=tx_axis_tready,
|
||||
tx_axis_tlast=tx_axis_tlast,
|
||||
tx_axis_tuser=tx_axis_tuser,
|
||||
rx_axis_tdata=rx_axis_tdata,
|
||||
rx_axis_tkeep=rx_axis_tkeep,
|
||||
rx_axis_tvalid=rx_axis_tvalid,
|
||||
rx_axis_tready=rx_axis_tready,
|
||||
rx_axis_tlast=rx_axis_tlast,
|
||||
rx_axis_tuser=rx_axis_tuser,
|
||||
serdes_tx_data=serdes_tx_data,
|
||||
serdes_tx_hdr=serdes_tx_hdr,
|
||||
serdes_rx_data=serdes_rx_data,
|
||||
serdes_rx_hdr=serdes_rx_hdr,
|
||||
serdes_rx_bitslip=serdes_rx_bitslip,
|
||||
tx_fifo_overflow=tx_fifo_overflow,
|
||||
tx_fifo_bad_frame=tx_fifo_bad_frame,
|
||||
tx_fifo_good_frame=tx_fifo_good_frame,
|
||||
rx_error_bad_frame=rx_error_bad_frame,
|
||||
rx_error_bad_fcs=rx_error_bad_fcs,
|
||||
rx_block_lock=rx_block_lock,
|
||||
rx_high_ber=rx_high_ber,
|
||||
rx_fifo_overflow=rx_fifo_overflow,
|
||||
rx_fifo_bad_frame=rx_fifo_bad_frame,
|
||||
rx_fifo_good_frame=rx_fifo_good_frame,
|
||||
ifg_delay=ifg_delay
|
||||
)
|
||||
|
||||
@always(delay(4))
|
||||
def clkgen():
|
||||
clk.next = not clk
|
||||
tx_clk.next = not tx_clk
|
||||
rx_clk.next = not rx_clk
|
||||
logic_clk.next = not logic_clk
|
||||
|
||||
load_bit_offset = []
|
||||
|
||||
@instance
|
||||
def shift_bits():
|
||||
bit_offset = 0
|
||||
last_data = 0
|
||||
|
||||
while True:
|
||||
yield clk.posedge
|
||||
|
||||
if load_bit_offset:
|
||||
bit_offset = load_bit_offset.pop(0)
|
||||
|
||||
if serdes_rx_bitslip:
|
||||
bit_offset += 1
|
||||
|
||||
bit_offset = bit_offset % 66
|
||||
|
||||
data = int(serdes_rx_data_int) << 2 | int(serdes_rx_hdr_int)
|
||||
|
||||
out_data = ((last_data | data << 66) >> 66-bit_offset) & 0x3ffffffffffffffff
|
||||
|
||||
last_data = data
|
||||
|
||||
serdes_rx_data.next = out_data >> 2
|
||||
serdes_rx_hdr.next = out_data & 3
|
||||
|
||||
@instance
|
||||
def check():
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
rst.next = 1
|
||||
tx_rst.next = 1
|
||||
rx_rst.next = 1
|
||||
logic_rst.next = 1
|
||||
yield clk.posedge
|
||||
rst.next = 0
|
||||
tx_rst.next = 0
|
||||
rx_rst.next = 0
|
||||
logic_rst.next = 0
|
||||
yield clk.posedge
|
||||
yield delay(100)
|
||||
yield clk.posedge
|
||||
|
||||
ifg_delay.next = 12
|
||||
|
||||
# testbench stimulus
|
||||
|
||||
yield clk.posedge
|
||||
print("test 1: test rx packet")
|
||||
current_test.next = 1
|
||||
|
||||
test_frame = eth_ep.EthFrame()
|
||||
test_frame.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame.eth_src_mac = 0x5A5152535455
|
||||
test_frame.eth_type = 0x8000
|
||||
test_frame.payload = bytearray(range(32))
|
||||
test_frame.update_fcs()
|
||||
|
||||
axis_frame = test_frame.build_axis_fcs()
|
||||
|
||||
serdes_source.send(b'\x55\x55\x55\x55\x55\x55\x55\xD5'+bytearray(axis_frame))
|
||||
|
||||
yield axis_sink.wait()
|
||||
rx_frame = axis_sink.recv()
|
||||
|
||||
eth_frame = eth_ep.EthFrame()
|
||||
eth_frame.parse_axis(rx_frame)
|
||||
eth_frame.update_fcs()
|
||||
|
||||
assert eth_frame == test_frame
|
||||
|
||||
yield delay(100)
|
||||
|
||||
yield clk.posedge
|
||||
print("test 2: test tx packet")
|
||||
current_test.next = 2
|
||||
|
||||
test_frame = eth_ep.EthFrame()
|
||||
test_frame.eth_dest_mac = 0xDAD1D2D3D4D5
|
||||
test_frame.eth_src_mac = 0x5A5152535455
|
||||
test_frame.eth_type = 0x8000
|
||||
test_frame.payload = bytearray(range(32))
|
||||
test_frame.update_fcs()
|
||||
|
||||
axis_frame = test_frame.build_axis()
|
||||
|
||||
axis_source.send(axis_frame)
|
||||
|
||||
yield serdes_sink.wait()
|
||||
rx_frame = serdes_sink.recv()
|
||||
|
||||
assert rx_frame.data[0:8] == bytearray(b'\x55\x55\x55\x55\x55\x55\x55\xD5')
|
||||
|
||||
eth_frame = eth_ep.EthFrame()
|
||||
eth_frame.parse_axis_fcs(rx_frame.data[8:])
|
||||
|
||||
print(hex(eth_frame.eth_fcs))
|
||||
print(hex(eth_frame.calc_fcs()))
|
||||
|
||||
assert len(eth_frame.payload.data) == 46
|
||||
assert eth_frame.eth_fcs == eth_frame.calc_fcs()
|
||||
assert eth_frame.eth_dest_mac == test_frame.eth_dest_mac
|
||||
assert eth_frame.eth_src_mac == test_frame.eth_src_mac
|
||||
assert eth_frame.eth_type == test_frame.eth_type
|
||||
assert eth_frame.payload.data.index(test_frame.payload.data) == 0
|
||||
|
||||
yield delay(100)
|
||||
|
||||
raise StopSimulation
|
||||
|
||||
return instances()
|
||||
|
||||
def test_bench():
|
||||
sim = Simulation(bench())
|
||||
sim.run()
|
||||
|
||||
if __name__ == '__main__':
|
||||
print("Running test...")
|
||||
test_bench()
|
204
tb/test_eth_mac_phy_10g_fifo.v
Normal file
204
tb/test_eth_mac_phy_10g_fifo.v
Normal file
@ -0,0 +1,204 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2019 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 eth_mac_phy_10g_fifo
|
||||
*/
|
||||
module test_eth_mac_phy_10g_fifo;
|
||||
|
||||
// Parameters
|
||||
parameter DATA_WIDTH = 64;
|
||||
parameter KEEP_WIDTH = (DATA_WIDTH/8);
|
||||
parameter CTRL_WIDTH = (DATA_WIDTH/8);
|
||||
parameter HDR_WIDTH = (DATA_WIDTH/32);
|
||||
parameter ENABLE_PADDING = 1;
|
||||
parameter ENABLE_DIC = 1;
|
||||
parameter MIN_FRAME_LENGTH = 64;
|
||||
parameter BIT_REVERSE = 0;
|
||||
parameter SCRAMBLER_DISABLE = 0;
|
||||
parameter SLIP_COUNT_WIDTH = 3;
|
||||
parameter COUNT_125US = 125000/6.4;
|
||||
parameter TX_FIFO_ADDR_WIDTH = 12-$clog2(KEEP_WIDTH);
|
||||
parameter TX_FRAME_FIFO = 1;
|
||||
parameter TX_DROP_BAD_FRAME = TX_FRAME_FIFO;
|
||||
parameter TX_DROP_WHEN_FULL = 0;
|
||||
parameter RX_FIFO_ADDR_WIDTH = 12-$clog2(KEEP_WIDTH);
|
||||
parameter RX_FRAME_FIFO = 1;
|
||||
parameter RX_DROP_BAD_FRAME = RX_FRAME_FIFO;
|
||||
parameter RX_DROP_WHEN_FULL = RX_FRAME_FIFO;
|
||||
|
||||
// Inputs
|
||||
reg clk = 0;
|
||||
reg rst = 0;
|
||||
reg [7:0] current_test = 0;
|
||||
|
||||
reg rx_clk = 0;
|
||||
reg rx_rst = 0;
|
||||
reg tx_clk = 0;
|
||||
reg tx_rst = 0;
|
||||
reg logic_clk = 0;
|
||||
reg logic_rst = 0;
|
||||
reg [DATA_WIDTH-1:0] tx_axis_tdata = 0;
|
||||
reg [KEEP_WIDTH-1:0] tx_axis_tkeep = 0;
|
||||
reg tx_axis_tvalid = 0;
|
||||
reg tx_axis_tlast = 0;
|
||||
reg tx_axis_tuser = 0;
|
||||
reg rx_axis_tready = 0;
|
||||
reg [DATA_WIDTH-1:0] serdes_rx_data = 0;
|
||||
reg [HDR_WIDTH-1:0] serdes_rx_hdr = 1;
|
||||
reg [7:0] ifg_delay = 0;
|
||||
|
||||
// Outputs
|
||||
wire tx_axis_tready;
|
||||
wire [DATA_WIDTH-1:0] rx_axis_tdata;
|
||||
wire [KEEP_WIDTH-1:0] rx_axis_tkeep;
|
||||
wire rx_axis_tvalid;
|
||||
wire rx_axis_tlast;
|
||||
wire rx_axis_tuser;
|
||||
wire [DATA_WIDTH-1:0] serdes_tx_data;
|
||||
wire [HDR_WIDTH-1:0] serdes_tx_hdr;
|
||||
wire serdes_rx_bitslip;
|
||||
wire tx_fifo_overflow;
|
||||
wire tx_fifo_bad_frame;
|
||||
wire tx_fifo_good_frame;
|
||||
wire rx_error_bad_frame;
|
||||
wire rx_error_bad_fcs;
|
||||
wire rx_block_lock;
|
||||
wire rx_high_ber;
|
||||
wire rx_fifo_overflow;
|
||||
wire rx_fifo_bad_frame;
|
||||
wire rx_fifo_good_frame;
|
||||
|
||||
initial begin
|
||||
// myhdl integration
|
||||
$from_myhdl(
|
||||
clk,
|
||||
rst,
|
||||
current_test,
|
||||
rx_clk,
|
||||
rx_rst,
|
||||
tx_clk,
|
||||
tx_rst,
|
||||
logic_clk,
|
||||
logic_rst,
|
||||
tx_axis_tdata,
|
||||
tx_axis_tkeep,
|
||||
tx_axis_tvalid,
|
||||
tx_axis_tlast,
|
||||
tx_axis_tuser,
|
||||
rx_axis_tready,
|
||||
serdes_rx_data,
|
||||
serdes_rx_hdr,
|
||||
ifg_delay
|
||||
);
|
||||
$to_myhdl(
|
||||
tx_axis_tready,
|
||||
rx_axis_tdata,
|
||||
rx_axis_tkeep,
|
||||
rx_axis_tvalid,
|
||||
rx_axis_tlast,
|
||||
rx_axis_tuser,
|
||||
serdes_tx_data,
|
||||
serdes_tx_hdr,
|
||||
serdes_rx_bitslip,
|
||||
tx_fifo_overflow,
|
||||
tx_fifo_bad_frame,
|
||||
tx_fifo_good_frame,
|
||||
rx_error_bad_frame,
|
||||
rx_error_bad_fcs,
|
||||
rx_block_lock,
|
||||
rx_high_ber,
|
||||
rx_fifo_overflow,
|
||||
rx_fifo_bad_frame,
|
||||
rx_fifo_good_frame
|
||||
);
|
||||
|
||||
// dump file
|
||||
$dumpfile("test_eth_mac_phy_10g_fifo.lxt");
|
||||
$dumpvars(0, test_eth_mac_phy_10g_fifo);
|
||||
end
|
||||
|
||||
eth_mac_phy_10g_fifo #(
|
||||
.DATA_WIDTH(DATA_WIDTH),
|
||||
.KEEP_WIDTH(KEEP_WIDTH),
|
||||
.CTRL_WIDTH(CTRL_WIDTH),
|
||||
.HDR_WIDTH(HDR_WIDTH),
|
||||
.ENABLE_PADDING(ENABLE_PADDING),
|
||||
.ENABLE_DIC(ENABLE_DIC),
|
||||
.MIN_FRAME_LENGTH(MIN_FRAME_LENGTH),
|
||||
.BIT_REVERSE(BIT_REVERSE),
|
||||
.SCRAMBLER_DISABLE(SCRAMBLER_DISABLE),
|
||||
.SLIP_COUNT_WIDTH(SLIP_COUNT_WIDTH),
|
||||
.COUNT_125US(COUNT_125US),
|
||||
.TX_FIFO_ADDR_WIDTH(TX_FIFO_ADDR_WIDTH),
|
||||
.TX_FRAME_FIFO(TX_FRAME_FIFO),
|
||||
.TX_DROP_BAD_FRAME(TX_DROP_BAD_FRAME),
|
||||
.TX_DROP_WHEN_FULL(TX_DROP_WHEN_FULL),
|
||||
.RX_FIFO_ADDR_WIDTH(RX_FIFO_ADDR_WIDTH),
|
||||
.RX_FRAME_FIFO(RX_FRAME_FIFO),
|
||||
.RX_DROP_BAD_FRAME(RX_DROP_BAD_FRAME),
|
||||
.RX_DROP_WHEN_FULL(RX_DROP_WHEN_FULL)
|
||||
)
|
||||
UUT (
|
||||
.rx_clk(rx_clk),
|
||||
.rx_rst(rx_rst),
|
||||
.tx_clk(tx_clk),
|
||||
.tx_rst(tx_rst),
|
||||
.logic_clk(logic_clk),
|
||||
.logic_rst(logic_rst),
|
||||
.tx_axis_tdata(tx_axis_tdata),
|
||||
.tx_axis_tkeep(tx_axis_tkeep),
|
||||
.tx_axis_tvalid(tx_axis_tvalid),
|
||||
.tx_axis_tready(tx_axis_tready),
|
||||
.tx_axis_tlast(tx_axis_tlast),
|
||||
.tx_axis_tuser(tx_axis_tuser),
|
||||
.rx_axis_tdata(rx_axis_tdata),
|
||||
.rx_axis_tkeep(rx_axis_tkeep),
|
||||
.rx_axis_tvalid(rx_axis_tvalid),
|
||||
.rx_axis_tready(rx_axis_tready),
|
||||
.rx_axis_tlast(rx_axis_tlast),
|
||||
.rx_axis_tuser(rx_axis_tuser),
|
||||
.serdes_tx_data(serdes_tx_data),
|
||||
.serdes_tx_hdr(serdes_tx_hdr),
|
||||
.serdes_rx_data(serdes_rx_data),
|
||||
.serdes_rx_hdr(serdes_rx_hdr),
|
||||
.serdes_rx_bitslip(serdes_rx_bitslip),
|
||||
.tx_fifo_overflow(tx_fifo_overflow),
|
||||
.tx_fifo_bad_frame(tx_fifo_bad_frame),
|
||||
.tx_fifo_good_frame(tx_fifo_good_frame),
|
||||
.rx_error_bad_frame(rx_error_bad_frame),
|
||||
.rx_error_bad_fcs(rx_error_bad_fcs),
|
||||
.rx_block_lock(rx_block_lock),
|
||||
.rx_high_ber(rx_high_ber),
|
||||
.rx_fifo_overflow(rx_fifo_overflow),
|
||||
.rx_fifo_bad_frame(rx_fifo_bad_frame),
|
||||
.rx_fifo_good_frame(rx_fifo_good_frame),
|
||||
.ifg_delay(ifg_delay)
|
||||
);
|
||||
|
||||
endmodule
|
Loading…
x
Reference in New Issue
Block a user