"vscode:/vscode.git/clone" did not exist on "6a2beea4c6255ee0a66ddb6d3b059451f7976ac7"
Commit 738c1fef authored by Antoine Kaufmann's avatar Antoine Kaufmann
Browse files

add corundum and verilator build files

parent 7f925101
/*
Copyright (c) 2018 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* 10G Ethernet PHY frame sync
*/
module eth_phy_10g_rx_frame_sync #
(
parameter HDR_WIDTH = 2,
parameter SLIP_COUNT_WIDTH = 3
)
(
input wire clk,
input wire rst,
/*
* SERDES interface
*/
input wire [HDR_WIDTH-1:0] serdes_rx_hdr,
output wire serdes_rx_bitslip,
/*
* Status
*/
output wire rx_block_lock
);
// bus width assertions
initial begin
if (HDR_WIDTH != 2) begin
$error("Error: HDR_WIDTH must be 2");
$finish;
end
end
localparam [1:0]
SYNC_DATA = 2'b10,
SYNC_CTRL = 2'b01;
reg [5:0] sh_count_reg = 6'd0, sh_count_next;
reg [3:0] sh_invalid_count_reg = 4'd0, sh_invalid_count_next;
reg [SLIP_COUNT_WIDTH-1:0] slip_count_reg = 0, slip_count_next;
reg serdes_rx_bitslip_reg = 1'b0, serdes_rx_bitslip_next;
reg rx_block_lock_reg = 1'b0, rx_block_lock_next;
assign serdes_rx_bitslip = serdes_rx_bitslip_reg;
assign rx_block_lock = rx_block_lock_reg;
always @* begin
sh_count_next = sh_count_reg;
sh_invalid_count_next = sh_invalid_count_reg;
slip_count_next = slip_count_reg;
serdes_rx_bitslip_next = 1'b0;
rx_block_lock_next = rx_block_lock_reg;
if (slip_count_reg) begin
slip_count_next = slip_count_reg-1;
end else if (serdes_rx_hdr == SYNC_CTRL || serdes_rx_hdr == SYNC_DATA) begin
// valid header
sh_count_next = sh_count_reg + 1;
if (&sh_count_reg) begin
// valid count overflow, reset
sh_count_next = 0;
sh_invalid_count_next = 0;
if (!sh_invalid_count_reg) begin
rx_block_lock_next = 1'b1;
end
end
end else begin
// invalid header
sh_count_next = sh_count_reg + 1;
sh_invalid_count_next = sh_invalid_count_reg + 1;
if (!rx_block_lock_reg || &sh_invalid_count_reg) begin
// invalid count overflow, lost block lock
sh_count_next = 0;
sh_invalid_count_next = 0;
rx_block_lock_next = 1'b0;
serdes_rx_bitslip_next = 1'b1;
slip_count_next = {SLIP_COUNT_WIDTH{1'b1}};
end else if (&sh_count_reg) begin
// valid count overflow, reset
sh_count_next = 0;
sh_invalid_count_next = 0;
end
end
end
always @(posedge clk) begin
if (rst) begin
sh_count_reg <= 6'd0;
sh_invalid_count_reg <= 4'd0;
slip_count_reg <= 0;
rx_block_lock_reg <= 1'b0;
end else begin
sh_count_reg <= sh_count_next;
sh_invalid_count_reg <= sh_invalid_count_next;
slip_count_reg <= slip_count_next;
rx_block_lock_reg <= rx_block_lock_next;
end
serdes_rx_bitslip_reg <= serdes_rx_bitslip_next;
end
endmodule
/*
Copyright (c) 2018 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* 10G Ethernet PHY RX IF
*/
module eth_phy_10g_rx_if #
(
parameter DATA_WIDTH = 64,
parameter HDR_WIDTH = 2,
parameter BIT_REVERSE = 0,
parameter SCRAMBLER_DISABLE = 0,
parameter PRBS31_ENABLE = 0,
parameter SERDES_PIPELINE = 0,
parameter SLIP_COUNT_WIDTH = 3,
parameter COUNT_125US = 125000/6.4
)
(
input wire clk,
input wire rst,
/*
* 10GBASE-R encoded interface
*/
output wire [DATA_WIDTH-1:0] encoded_rx_data,
output wire [HDR_WIDTH-1:0] encoded_rx_hdr,
/*
* 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 [6:0] rx_error_count,
output wire rx_block_lock,
output wire rx_high_ber,
/*
* Configuration
*/
input wire rx_prbs31_enable
);
// bus width assertions
initial begin
if (DATA_WIDTH != 64) begin
$error("Error: Interface width must be 64");
$finish;
end
if (HDR_WIDTH != 2) begin
$error("Error: HDR_WIDTH must be 2");
$finish;
end
end
wire [DATA_WIDTH-1:0] serdes_rx_data_rev, serdes_rx_data_int;
wire [HDR_WIDTH-1:0] serdes_rx_hdr_rev, 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_rev[n] = serdes_rx_data[DATA_WIDTH-n-1];
end
for (n = 0; n < HDR_WIDTH; n = n + 1) begin
assign serdes_rx_hdr_rev[n] = serdes_rx_hdr[HDR_WIDTH-n-1];
end
end else begin
assign serdes_rx_data_rev = serdes_rx_data;
assign serdes_rx_hdr_rev = serdes_rx_hdr;
end
if (SERDES_PIPELINE > 0) begin
(* srl_style = "register" *)
reg [DATA_WIDTH-1:0] serdes_rx_data_pipe_reg[SERDES_PIPELINE-1:0];
(* srl_style = "register" *)
reg [HDR_WIDTH-1:0] serdes_rx_hdr_pipe_reg[SERDES_PIPELINE-1:0];
for (n = 0; n < SERDES_PIPELINE; n = n + 1) begin
initial begin
serdes_rx_data_pipe_reg[n] <= {DATA_WIDTH{1'b0}};
serdes_rx_hdr_pipe_reg[n] <= {HDR_WIDTH{1'b0}};
end
always @(posedge clk) begin
serdes_rx_data_pipe_reg[n] <= n == 0 ? serdes_rx_data_rev : serdes_rx_data_pipe_reg[n-1];
serdes_rx_hdr_pipe_reg[n] <= n == 0 ? serdes_rx_hdr_rev : serdes_rx_hdr_pipe_reg[n-1];
end
end
assign serdes_rx_data_int = serdes_rx_data_pipe_reg[SERDES_PIPELINE-1];
assign serdes_rx_hdr_int = serdes_rx_hdr_pipe_reg[SERDES_PIPELINE-1];
end else begin
assign serdes_rx_data_int = serdes_rx_data_rev;
assign serdes_rx_hdr_int = serdes_rx_hdr_rev;
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;
reg [30:0] prbs31_state_reg = 31'h7fffffff;
wire [30:0] prbs31_state;
wire [DATA_WIDTH+HDR_WIDTH-1:0] prbs31_data;
reg [6:0] rx_error_count_reg = 0;
reg [5:0] rx_error_count_1_reg = 0;
reg [5:0] rx_error_count_2_reg = 0;
reg [5:0] rx_error_count_1_temp = 0;
reg [5:0] rx_error_count_2_temp = 0;
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)
);
lfsr #(
.LFSR_WIDTH(31),
.LFSR_POLY(31'h10000001),
.LFSR_CONFIG("FIBONACCI"),
.LFSR_FEED_FORWARD(1),
.REVERSE(1),
.DATA_WIDTH(DATA_WIDTH+HDR_WIDTH),
.STYLE("AUTO")
)
prbs31_check_inst (
.data_in(~{serdes_rx_data_int, serdes_rx_hdr_int}),
.state_in(prbs31_state_reg),
.data_out(prbs31_data),
.state_out(prbs31_state)
);
integer i;
always @* begin
rx_error_count_1_temp = 0;
rx_error_count_2_temp = 0;
for (i = 0; i < DATA_WIDTH+HDR_WIDTH; i = i + 1) begin
if (i & 1) begin
rx_error_count_1_temp = rx_error_count_1_temp + prbs31_data[i];
end else begin
rx_error_count_2_temp = rx_error_count_2_temp + prbs31_data[i];
end
end
end
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;
if (PRBS31_ENABLE && rx_prbs31_enable) begin
prbs31_state_reg <= prbs31_state;
rx_error_count_1_reg <= rx_error_count_1_temp;
rx_error_count_2_reg <= rx_error_count_2_temp;
rx_error_count_reg <= rx_error_count_1_reg + rx_error_count_2_reg;
end
end
assign encoded_rx_data = encoded_rx_data_reg;
assign encoded_rx_hdr = encoded_rx_hdr_reg;
assign rx_error_count = rx_error_count_reg;
wire serdes_rx_bitslip_int;
assign serdes_rx_bitslip = serdes_rx_bitslip_int && !(PRBS31_ENABLE && rx_prbs31_enable);
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_int),
.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
/*
Copyright (c) 2018 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* 10G Ethernet PHY TX
*/
module eth_phy_10g_tx #
(
parameter DATA_WIDTH = 64,
parameter CTRL_WIDTH = (DATA_WIDTH/8),
parameter HDR_WIDTH = 2,
parameter BIT_REVERSE = 0,
parameter SCRAMBLER_DISABLE = 0,
parameter PRBS31_ENABLE = 0,
parameter SERDES_PIPELINE = 0
)
(
input wire clk,
input wire rst,
/*
* XGMII interface
*/
input wire [DATA_WIDTH-1:0] xgmii_txd,
input wire [CTRL_WIDTH-1:0] xgmii_txc,
/*
* SERDES interface
*/
output wire [DATA_WIDTH-1:0] serdes_tx_data,
output wire [HDR_WIDTH-1:0] serdes_tx_hdr,
/*
* Configuration
*/
input wire tx_prbs31_enable
);
// bus width assertions
initial begin
if (DATA_WIDTH != 64) begin
$error("Error: Interface width must be 64");
$finish;
end
if (CTRL_WIDTH * 8 != DATA_WIDTH) begin
$error("Error: Interface requires byte (8-bit) granularity");
$finish;
end
if (HDR_WIDTH != 2) begin
$error("Error: HDR_WIDTH must be 2");
$finish;
end
end
wire [DATA_WIDTH-1:0] encoded_tx_data;
wire [HDR_WIDTH-1:0] encoded_tx_hdr;
xgmii_baser_enc_64 #(
.DATA_WIDTH(DATA_WIDTH),
.CTRL_WIDTH(CTRL_WIDTH),
.HDR_WIDTH(HDR_WIDTH)
)
xgmii_baser_enc_inst (
.clk(clk),
.rst(rst),
.xgmii_txd(xgmii_txd),
.xgmii_txc(xgmii_txc),
.encoded_tx_data(encoded_tx_data),
.encoded_tx_hdr(encoded_tx_hdr)
);
eth_phy_10g_tx_if #(
.DATA_WIDTH(DATA_WIDTH),
.HDR_WIDTH(HDR_WIDTH),
.BIT_REVERSE(BIT_REVERSE),
.SCRAMBLER_DISABLE(SCRAMBLER_DISABLE),
.PRBS31_ENABLE(PRBS31_ENABLE),
.SERDES_PIPELINE(SERDES_PIPELINE)
)
eth_phy_10g_tx_if_inst (
.clk(clk),
.rst(rst),
.encoded_tx_data(encoded_tx_data),
.encoded_tx_hdr(encoded_tx_hdr),
.serdes_tx_data(serdes_tx_data),
.serdes_tx_hdr(serdes_tx_hdr),
.tx_prbs31_enable(tx_prbs31_enable)
);
endmodule
/*
Copyright (c) 2018 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* 10G Ethernet PHY TX IF
*/
module eth_phy_10g_tx_if #
(
parameter DATA_WIDTH = 64,
parameter HDR_WIDTH = 2,
parameter BIT_REVERSE = 0,
parameter SCRAMBLER_DISABLE = 0,
parameter PRBS31_ENABLE = 0,
parameter SERDES_PIPELINE = 0
)
(
input wire clk,
input wire rst,
/*
* 10GBASE-R encoded interface
*/
input wire [DATA_WIDTH-1:0] encoded_tx_data,
input wire [HDR_WIDTH-1:0] encoded_tx_hdr,
/*
* SERDES interface
*/
output wire [DATA_WIDTH-1:0] serdes_tx_data,
output wire [HDR_WIDTH-1:0] serdes_tx_hdr,
/*
* Configuration
*/
input wire tx_prbs31_enable
);
// bus width assertions
initial begin
if (DATA_WIDTH != 64) begin
$error("Error: Interface width must be 64");
$finish;
end
if (HDR_WIDTH != 2) begin
$error("Error: HDR_WIDTH must be 2");
$finish;
end
end
reg [57:0] scrambler_state_reg = {58{1'b1}};
wire [57:0] scrambler_state;
wire [DATA_WIDTH-1:0] scrambled_data;
reg [30:0] prbs31_state_reg = 31'h7fffffff;
wire [30:0] prbs31_state;
wire [DATA_WIDTH+HDR_WIDTH-1:0] prbs31_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}};
wire [DATA_WIDTH-1:0] serdes_tx_data_int;
wire [HDR_WIDTH-1:0] serdes_tx_hdr_int;
generate
genvar n;
if (BIT_REVERSE) begin
for (n = 0; n < DATA_WIDTH; n = n + 1) begin
assign serdes_tx_data_int[n] = serdes_tx_data_reg[DATA_WIDTH-n-1];
end
for (n = 0; n < HDR_WIDTH; n = n + 1) begin
assign serdes_tx_hdr_int[n] = serdes_tx_hdr_reg[HDR_WIDTH-n-1];
end
end else begin
assign serdes_tx_data_int = serdes_tx_data_reg;
assign serdes_tx_hdr_int = serdes_tx_hdr_reg;
end
if (SERDES_PIPELINE > 0) begin
(* srl_style = "register" *)
reg [DATA_WIDTH-1:0] serdes_tx_data_pipe_reg[SERDES_PIPELINE-1:0];
(* srl_style = "register" *)
reg [HDR_WIDTH-1:0] serdes_tx_hdr_pipe_reg[SERDES_PIPELINE-1:0];
for (n = 0; n < SERDES_PIPELINE; n = n + 1) begin
initial begin
serdes_tx_data_pipe_reg[n] <= {DATA_WIDTH{1'b0}};
serdes_tx_hdr_pipe_reg[n] <= {HDR_WIDTH{1'b0}};
end
always @(posedge clk) begin
serdes_tx_data_pipe_reg[n] <= n == 0 ? serdes_tx_data_int : serdes_tx_data_pipe_reg[n-1];
serdes_tx_hdr_pipe_reg[n] <= n == 0 ? serdes_tx_hdr_int : serdes_tx_hdr_pipe_reg[n-1];
end
end
assign serdes_tx_data = serdes_tx_data_pipe_reg[SERDES_PIPELINE-1];
assign serdes_tx_hdr = serdes_tx_hdr_pipe_reg[SERDES_PIPELINE-1];
end else begin
assign serdes_tx_data = serdes_tx_data_int;
assign serdes_tx_hdr = serdes_tx_hdr_int;
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(scrambler_state_reg),
.data_out(scrambled_data),
.state_out(scrambler_state)
);
lfsr #(
.LFSR_WIDTH(31),
.LFSR_POLY(31'h10000001),
.LFSR_CONFIG("FIBONACCI"),
.LFSR_FEED_FORWARD(0),
.REVERSE(1),
.DATA_WIDTH(DATA_WIDTH+HDR_WIDTH),
.STYLE("AUTO")
)
prbs31_gen_inst (
.data_in({DATA_WIDTH+HDR_WIDTH{1'b0}}),
.state_in(prbs31_state_reg),
.data_out(prbs31_data),
.state_out(prbs31_state)
);
always @(posedge clk) begin
scrambler_state_reg <= scrambler_state;
if (PRBS31_ENABLE && tx_prbs31_enable) begin
prbs31_state_reg <= prbs31_state;
serdes_tx_data_reg <= ~prbs31_data[DATA_WIDTH+HDR_WIDTH-1:HDR_WIDTH];
serdes_tx_hdr_reg <= ~prbs31_data[HDR_WIDTH-1:0];
end else begin
serdes_tx_data_reg <= SCRAMBLER_DISABLE ? encoded_tx_data : scrambled_data;
serdes_tx_hdr_reg <= encoded_tx_hdr;
end
end
endmodule
/*
Copyright (c) 2015-2018 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* GMII PHY interface
*/
module gmii_phy_if #
(
// target ("SIM", "GENERIC", "XILINX", "ALTERA")
parameter TARGET = "GENERIC",
// IODDR style ("IODDR", "IODDR2")
// Use IODDR for Virtex-4, Virtex-5, Virtex-6, 7 Series, Ultrascale
// Use IODDR2 for Spartan-6
parameter IODDR_STYLE = "IODDR2",
// Clock input style ("BUFG", "BUFR", "BUFIO", "BUFIO2")
// Use BUFR for Virtex-5, Virtex-6, 7-series
// Use BUFG for Ultrascale
// Use BUFIO2 for Spartan-6
parameter CLOCK_INPUT_STYLE = "BUFIO2"
)
(
input wire clk,
input wire rst,
/*
* GMII interface to MAC
*/
output wire mac_gmii_rx_clk,
output wire mac_gmii_rx_rst,
output wire [7:0] mac_gmii_rxd,
output wire mac_gmii_rx_dv,
output wire mac_gmii_rx_er,
output wire mac_gmii_tx_clk,
output wire mac_gmii_tx_rst,
input wire [7:0] mac_gmii_txd,
input wire mac_gmii_tx_en,
input wire mac_gmii_tx_er,
/*
* GMII interface to PHY
*/
input wire phy_gmii_rx_clk,
input wire [7:0] phy_gmii_rxd,
input wire phy_gmii_rx_dv,
input wire phy_gmii_rx_er,
input wire phy_mii_tx_clk,
output wire phy_gmii_tx_clk,
output wire [7:0] phy_gmii_txd,
output wire phy_gmii_tx_en,
output wire phy_gmii_tx_er,
/*
* Control
*/
input wire mii_select
);
ssio_sdr_in #
(
.TARGET(TARGET),
.CLOCK_INPUT_STYLE(CLOCK_INPUT_STYLE),
.WIDTH(10)
)
rx_ssio_sdr_inst (
.input_clk(phy_gmii_rx_clk),
.input_d({phy_gmii_rxd, phy_gmii_rx_dv, phy_gmii_rx_er}),
.output_clk(mac_gmii_rx_clk),
.output_q({mac_gmii_rxd, mac_gmii_rx_dv, mac_gmii_rx_er})
);
ssio_sdr_out #
(
.TARGET(TARGET),
.IODDR_STYLE(IODDR_STYLE),
.WIDTH(10)
)
tx_ssio_sdr_inst (
.clk(mac_gmii_tx_clk),
.input_d({mac_gmii_txd, mac_gmii_tx_en, mac_gmii_tx_er}),
.output_clk(phy_gmii_tx_clk),
.output_q({phy_gmii_txd, phy_gmii_tx_en, phy_gmii_tx_er})
);
generate
if (TARGET == "XILINX") begin
BUFGMUX
gmii_bufgmux_inst (
.I0(clk),
.I1(phy_mii_tx_clk),
.S(mii_select),
.O(mac_gmii_tx_clk)
);
end else begin
assign mac_gmii_tx_clk = mii_select ? phy_mii_tx_clk : clk;
end
endgenerate
// reset sync
reg [3:0] tx_rst_reg = 4'hf;
assign mac_gmii_tx_rst = tx_rst_reg[0];
always @(posedge mac_gmii_tx_clk or posedge rst) begin
if (rst) begin
tx_rst_reg <= 4'hf;
end else begin
tx_rst_reg <= {1'b0, tx_rst_reg[3:1]};
end
end
reg [3:0] rx_rst_reg = 4'hf;
assign mac_gmii_rx_rst = rx_rst_reg[0];
always @(posedge mac_gmii_rx_clk or posedge rst) begin
if (rst) begin
rx_rst_reg <= 4'hf;
end else begin
rx_rst_reg <= {1'b0, rx_rst_reg[3:1]};
end
end
endmodule
/*
Copyright (c) 2016-2018 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* Generic IDDR module
*/
module iddr #
(
// target ("SIM", "GENERIC", "XILINX", "ALTERA")
parameter TARGET = "GENERIC",
// IODDR style ("IODDR", "IODDR2")
// Use IODDR for Virtex-4, Virtex-5, Virtex-6, 7 Series, Ultrascale
// Use IODDR2 for Spartan-6
parameter IODDR_STYLE = "IODDR2",
// Width of register in bits
parameter WIDTH = 1
)
(
input wire clk,
input wire [WIDTH-1:0] d,
output wire [WIDTH-1:0] q1,
output wire [WIDTH-1:0] q2
);
/*
Provides a consistent input DDR flip flop across multiple FPGA families
_____ _____ _____ _____ ____
clk ____/ \_____/ \_____/ \_____/ \_____/
_ _____ _____ _____ _____ _____ _____ _____ _____ _____ _
d _X_D0__X_D1__X_D2__X_D3__X_D4__X_D5__X_D6__X_D7__X_D8__X_
_______ ___________ ___________ ___________ ___________ _
q1 _______X___________X____D0_____X____D2_____X____D4_____X_
_______ ___________ ___________ ___________ ___________ _
q2 _______X___________X____D1_____X____D3_____X____D5_____X_
*/
genvar n;
generate
if (TARGET == "XILINX") begin
for (n = 0; n < WIDTH; n = n + 1) begin : iddr
if (IODDR_STYLE == "IODDR") begin
IDDR #(
.DDR_CLK_EDGE("SAME_EDGE_PIPELINED"),
.SRTYPE("ASYNC")
)
iddr_inst (
.Q1(q1[n]),
.Q2(q2[n]),
.C(clk),
.CE(1'b1),
.D(d[n]),
.R(1'b0),
.S(1'b0)
);
end else if (IODDR_STYLE == "IODDR2") begin
IDDR2 #(
.DDR_ALIGNMENT("C0")
)
iddr_inst (
.Q0(q1[n]),
.Q1(q2[n]),
.C0(clk),
.C1(~clk),
.CE(1'b1),
.D(d[n]),
.R(1'b0),
.S(1'b0)
);
end
end
end else if (TARGET == "ALTERA") begin
wire [WIDTH-1:0] q1_int;
reg [WIDTH-1:0] q1_delay;
altddio_in #(
.WIDTH(WIDTH),
.POWER_UP_HIGH("OFF")
)
altddio_in_inst (
.aset(1'b0),
.datain(d),
.inclocken(1'b1),
.inclock(clk),
.aclr(1'b0),
.dataout_h(q1_int),
.dataout_l(q2)
);
always @(posedge clk) begin
q1_delay <= q1_int;
end
assign q1 = q1_delay;
end else begin
reg [WIDTH-1:0] d_reg_1 = {WIDTH{1'b0}};
reg [WIDTH-1:0] d_reg_2 = {WIDTH{1'b0}};
reg [WIDTH-1:0] q_reg_1 = {WIDTH{1'b0}};
reg [WIDTH-1:0] q_reg_2 = {WIDTH{1'b0}};
always @(posedge clk) begin
d_reg_1 <= d;
end
always @(negedge clk) begin
d_reg_2 <= d;
end
always @(posedge clk) begin
q_reg_1 <= d_reg_1;
q_reg_2 <= d_reg_2;
end
assign q1 = q_reg_1;
assign q2 = q_reg_2;
end
endgenerate
endmodule
/*
Copyright (c) 2014-2018 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* IPv4 block, ethernet frame interface
*/
module ip
(
input wire clk,
input wire rst,
/*
* Ethernet frame input
*/
input wire s_eth_hdr_valid,
output wire s_eth_hdr_ready,
input wire [47:0] s_eth_dest_mac,
input wire [47:0] s_eth_src_mac,
input wire [15:0] s_eth_type,
input wire [7:0] s_eth_payload_axis_tdata,
input wire s_eth_payload_axis_tvalid,
output wire s_eth_payload_axis_tready,
input wire s_eth_payload_axis_tlast,
input wire s_eth_payload_axis_tuser,
/*
* Ethernet frame output
*/
output wire m_eth_hdr_valid,
input wire m_eth_hdr_ready,
output wire [47:0] m_eth_dest_mac,
output wire [47:0] m_eth_src_mac,
output wire [15:0] m_eth_type,
output wire [7:0] m_eth_payload_axis_tdata,
output wire m_eth_payload_axis_tvalid,
input wire m_eth_payload_axis_tready,
output wire m_eth_payload_axis_tlast,
output wire m_eth_payload_axis_tuser,
/*
* ARP requests
*/
output wire arp_request_valid,
input wire arp_request_ready,
output wire [31:0] arp_request_ip,
input wire arp_response_valid,
output wire arp_response_ready,
input wire arp_response_error,
input wire [47:0] arp_response_mac,
/*
* IP input
*/
input wire s_ip_hdr_valid,
output wire s_ip_hdr_ready,
input wire [5:0] s_ip_dscp,
input wire [1:0] s_ip_ecn,
input wire [15:0] s_ip_length,
input wire [7:0] s_ip_ttl,
input wire [7:0] s_ip_protocol,
input wire [31:0] s_ip_source_ip,
input wire [31:0] s_ip_dest_ip,
input wire [7:0] s_ip_payload_axis_tdata,
input wire s_ip_payload_axis_tvalid,
output wire s_ip_payload_axis_tready,
input wire s_ip_payload_axis_tlast,
input wire s_ip_payload_axis_tuser,
/*
* IP output
*/
output wire m_ip_hdr_valid,
input wire m_ip_hdr_ready,
output wire [47:0] m_ip_eth_dest_mac,
output wire [47:0] m_ip_eth_src_mac,
output wire [15:0] m_ip_eth_type,
output wire [3:0] m_ip_version,
output wire [3:0] m_ip_ihl,
output wire [5:0] m_ip_dscp,
output wire [1:0] m_ip_ecn,
output wire [15:0] m_ip_length,
output wire [15:0] m_ip_identification,
output wire [2:0] m_ip_flags,
output wire [12:0] m_ip_fragment_offset,
output wire [7:0] m_ip_ttl,
output wire [7:0] m_ip_protocol,
output wire [15:0] m_ip_header_checksum,
output wire [31:0] m_ip_source_ip,
output wire [31:0] m_ip_dest_ip,
output wire [7:0] m_ip_payload_axis_tdata,
output wire m_ip_payload_axis_tvalid,
input wire m_ip_payload_axis_tready,
output wire m_ip_payload_axis_tlast,
output wire m_ip_payload_axis_tuser,
/*
* Status
*/
output wire rx_busy,
output wire tx_busy,
output wire rx_error_header_early_termination,
output wire rx_error_payload_early_termination,
output wire rx_error_invalid_header,
output wire rx_error_invalid_checksum,
output wire tx_error_payload_early_termination,
output wire tx_error_arp_failed,
/*
* Configuration
*/
input wire [47:0] local_mac,
input wire [31:0] local_ip
);
localparam [1:0]
STATE_IDLE = 2'd0,
STATE_ARP_QUERY = 2'd1,
STATE_WAIT_PACKET = 2'd2;
reg [1:0] state_reg = STATE_IDLE, state_next;
reg outgoing_ip_hdr_valid_reg = 1'b0, outgoing_ip_hdr_valid_next;
wire outgoing_ip_hdr_ready;
reg [47:0] outgoing_eth_dest_mac_reg = 48'h000000000000, outgoing_eth_dest_mac_next;
wire outgoing_ip_payload_axis_tready;
/*
* IP frame processing
*/
ip_eth_rx
ip_eth_rx_inst (
.clk(clk),
.rst(rst),
// Ethernet frame input
.s_eth_hdr_valid(s_eth_hdr_valid),
.s_eth_hdr_ready(s_eth_hdr_ready),
.s_eth_dest_mac(s_eth_dest_mac),
.s_eth_src_mac(s_eth_src_mac),
.s_eth_type(s_eth_type),
.s_eth_payload_axis_tdata(s_eth_payload_axis_tdata),
.s_eth_payload_axis_tvalid(s_eth_payload_axis_tvalid),
.s_eth_payload_axis_tready(s_eth_payload_axis_tready),
.s_eth_payload_axis_tlast(s_eth_payload_axis_tlast),
.s_eth_payload_axis_tuser(s_eth_payload_axis_tuser),
// IP frame output
.m_ip_hdr_valid(m_ip_hdr_valid),
.m_ip_hdr_ready(m_ip_hdr_ready),
.m_eth_dest_mac(m_ip_eth_dest_mac),
.m_eth_src_mac(m_ip_eth_src_mac),
.m_eth_type(m_ip_eth_type),
.m_ip_version(m_ip_version),
.m_ip_ihl(m_ip_ihl),
.m_ip_dscp(m_ip_dscp),
.m_ip_ecn(m_ip_ecn),
.m_ip_length(m_ip_length),
.m_ip_identification(m_ip_identification),
.m_ip_flags(m_ip_flags),
.m_ip_fragment_offset(m_ip_fragment_offset),
.m_ip_ttl(m_ip_ttl),
.m_ip_protocol(m_ip_protocol),
.m_ip_header_checksum(m_ip_header_checksum),
.m_ip_source_ip(m_ip_source_ip),
.m_ip_dest_ip(m_ip_dest_ip),
.m_ip_payload_axis_tdata(m_ip_payload_axis_tdata),
.m_ip_payload_axis_tvalid(m_ip_payload_axis_tvalid),
.m_ip_payload_axis_tready(m_ip_payload_axis_tready),
.m_ip_payload_axis_tlast(m_ip_payload_axis_tlast),
.m_ip_payload_axis_tuser(m_ip_payload_axis_tuser),
// Status signals
.busy(rx_busy),
.error_header_early_termination(rx_error_header_early_termination),
.error_payload_early_termination(rx_error_payload_early_termination),
.error_invalid_header(rx_error_invalid_header),
.error_invalid_checksum(rx_error_invalid_checksum)
);
ip_eth_tx
ip_eth_tx_inst (
.clk(clk),
.rst(rst),
// IP frame input
.s_ip_hdr_valid(outgoing_ip_hdr_valid_reg),
.s_ip_hdr_ready(outgoing_ip_hdr_ready),
.s_eth_dest_mac(outgoing_eth_dest_mac_reg),
.s_eth_src_mac(local_mac),
.s_eth_type(16'h0800),
.s_ip_dscp(s_ip_dscp),
.s_ip_ecn(s_ip_ecn),
.s_ip_length(s_ip_length),
.s_ip_identification(16'd0),
.s_ip_flags(3'b010),
.s_ip_fragment_offset(13'd0),
.s_ip_ttl(s_ip_ttl),
.s_ip_protocol(s_ip_protocol),
.s_ip_source_ip(s_ip_source_ip),
.s_ip_dest_ip(s_ip_dest_ip),
.s_ip_payload_axis_tdata(s_ip_payload_axis_tdata),
.s_ip_payload_axis_tvalid(s_ip_payload_axis_tvalid),
.s_ip_payload_axis_tready(outgoing_ip_payload_axis_tready),
.s_ip_payload_axis_tlast(s_ip_payload_axis_tlast),
.s_ip_payload_axis_tuser(s_ip_payload_axis_tuser),
// Ethernet frame output
.m_eth_hdr_valid(m_eth_hdr_valid),
.m_eth_hdr_ready(m_eth_hdr_ready),
.m_eth_dest_mac(m_eth_dest_mac),
.m_eth_src_mac(m_eth_src_mac),
.m_eth_type(m_eth_type),
.m_eth_payload_axis_tdata(m_eth_payload_axis_tdata),
.m_eth_payload_axis_tvalid(m_eth_payload_axis_tvalid),
.m_eth_payload_axis_tready(m_eth_payload_axis_tready),
.m_eth_payload_axis_tlast(m_eth_payload_axis_tlast),
.m_eth_payload_axis_tuser(m_eth_payload_axis_tuser),
// Status signals
.busy(tx_busy),
.error_payload_early_termination(tx_error_payload_early_termination)
);
reg s_ip_hdr_ready_reg = 1'b0, s_ip_hdr_ready_next;
reg arp_request_valid_reg = 1'b0, arp_request_valid_next;
reg arp_response_ready_reg = 1'b0, arp_response_ready_next;
reg drop_packet_reg = 1'b0, drop_packet_next;
assign s_ip_hdr_ready = s_ip_hdr_ready_reg;
assign s_ip_payload_axis_tready = outgoing_ip_payload_axis_tready || drop_packet_reg;
assign arp_request_valid = arp_request_valid_reg;
assign arp_request_ip = s_ip_dest_ip;
assign arp_response_ready = arp_response_ready_reg;
assign tx_error_arp_failed = arp_response_error;
always @* begin
state_next = STATE_IDLE;
arp_request_valid_next = arp_request_valid_reg && !arp_request_ready;
arp_response_ready_next = 1'b0;
drop_packet_next = 1'b0;
s_ip_hdr_ready_next = 1'b0;
outgoing_ip_hdr_valid_next = outgoing_ip_hdr_valid_reg && !outgoing_ip_hdr_ready;
outgoing_eth_dest_mac_next = outgoing_eth_dest_mac_reg;
case (state_reg)
STATE_IDLE: begin
// wait for outgoing packet
if (s_ip_hdr_valid) begin
// initiate ARP request
arp_request_valid_next = 1'b1;
arp_response_ready_next = 1'b1;
state_next = STATE_ARP_QUERY;
end else begin
state_next = STATE_IDLE;
end
end
STATE_ARP_QUERY: begin
arp_response_ready_next = 1'b1;
if (arp_response_valid) begin
// wait for ARP reponse
if (arp_response_error) begin
// did not get MAC address; drop packet
s_ip_hdr_ready_next = 1'b1;
drop_packet_next = 1'b1;
state_next = STATE_WAIT_PACKET;
end else begin
// got MAC address; send packet
s_ip_hdr_ready_next = 1'b1;
outgoing_ip_hdr_valid_next = 1'b1;
outgoing_eth_dest_mac_next = arp_response_mac;
state_next = STATE_WAIT_PACKET;
end
end else begin
state_next = STATE_ARP_QUERY;
end
end
STATE_WAIT_PACKET: begin
drop_packet_next = drop_packet_reg;
// wait for packet transfer to complete
if (s_ip_payload_axis_tlast && s_ip_payload_axis_tready && s_ip_payload_axis_tvalid) begin
state_next = STATE_IDLE;
end else begin
state_next = STATE_WAIT_PACKET;
end
end
endcase
end
always @(posedge clk) begin
if (rst) begin
state_reg <= STATE_IDLE;
arp_request_valid_reg <= 1'b0;
arp_response_ready_reg <= 1'b0;
drop_packet_reg <= 1'b0;
s_ip_hdr_ready_reg <= 1'b0;
outgoing_ip_hdr_valid_reg <= 1'b0;
end else begin
state_reg <= state_next;
arp_request_valid_reg <= arp_request_valid_next;
arp_response_ready_reg <= arp_response_ready_next;
drop_packet_reg <= drop_packet_next;
s_ip_hdr_ready_reg <= s_ip_hdr_ready_next;
outgoing_ip_hdr_valid_reg <= outgoing_ip_hdr_valid_next;
end
outgoing_eth_dest_mac_reg <= outgoing_eth_dest_mac_next;
end
endmodule
/*
Copyright (c) 2014-2018 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* IPv4 block, ethernet frame interface (64 bit datapath)
*/
module ip_64
(
input wire clk,
input wire rst,
/*
* Ethernet frame input
*/
input wire s_eth_hdr_valid,
output wire s_eth_hdr_ready,
input wire [47:0] s_eth_dest_mac,
input wire [47:0] s_eth_src_mac,
input wire [15:0] s_eth_type,
input wire [63:0] s_eth_payload_axis_tdata,
input wire [7:0] s_eth_payload_axis_tkeep,
input wire s_eth_payload_axis_tvalid,
output wire s_eth_payload_axis_tready,
input wire s_eth_payload_axis_tlast,
input wire s_eth_payload_axis_tuser,
/*
* Ethernet frame output
*/
output wire m_eth_hdr_valid,
input wire m_eth_hdr_ready,
output wire [47:0] m_eth_dest_mac,
output wire [47:0] m_eth_src_mac,
output wire [15:0] m_eth_type,
output wire [63:0] m_eth_payload_axis_tdata,
output wire [7:0] m_eth_payload_axis_tkeep,
output wire m_eth_payload_axis_tvalid,
input wire m_eth_payload_axis_tready,
output wire m_eth_payload_axis_tlast,
output wire m_eth_payload_axis_tuser,
/*
* ARP requests
*/
output wire arp_request_valid,
input wire arp_request_ready,
output wire [31:0] arp_request_ip,
input wire arp_response_valid,
output wire arp_response_ready,
input wire arp_response_error,
input wire [47:0] arp_response_mac,
/*
* IP input
*/
input wire s_ip_hdr_valid,
output wire s_ip_hdr_ready,
input wire [5:0] s_ip_dscp,
input wire [1:0] s_ip_ecn,
input wire [15:0] s_ip_length,
input wire [7:0] s_ip_ttl,
input wire [7:0] s_ip_protocol,
input wire [31:0] s_ip_source_ip,
input wire [31:0] s_ip_dest_ip,
input wire [63:0] s_ip_payload_axis_tdata,
input wire [7:0] s_ip_payload_axis_tkeep,
input wire s_ip_payload_axis_tvalid,
output wire s_ip_payload_axis_tready,
input wire s_ip_payload_axis_tlast,
input wire s_ip_payload_axis_tuser,
/*
* IP output
*/
output wire m_ip_hdr_valid,
input wire m_ip_hdr_ready,
output wire [47:0] m_ip_eth_dest_mac,
output wire [47:0] m_ip_eth_src_mac,
output wire [15:0] m_ip_eth_type,
output wire [3:0] m_ip_version,
output wire [3:0] m_ip_ihl,
output wire [5:0] m_ip_dscp,
output wire [1:0] m_ip_ecn,
output wire [15:0] m_ip_length,
output wire [15:0] m_ip_identification,
output wire [2:0] m_ip_flags,
output wire [12:0] m_ip_fragment_offset,
output wire [7:0] m_ip_ttl,
output wire [7:0] m_ip_protocol,
output wire [15:0] m_ip_header_checksum,
output wire [31:0] m_ip_source_ip,
output wire [31:0] m_ip_dest_ip,
output wire [63:0] m_ip_payload_axis_tdata,
output wire [7:0] m_ip_payload_axis_tkeep,
output wire m_ip_payload_axis_tvalid,
input wire m_ip_payload_axis_tready,
output wire m_ip_payload_axis_tlast,
output wire m_ip_payload_axis_tuser,
/*
* Status
*/
output wire rx_busy,
output wire tx_busy,
output wire rx_error_header_early_termination,
output wire rx_error_payload_early_termination,
output wire rx_error_invalid_header,
output wire rx_error_invalid_checksum,
output wire tx_error_payload_early_termination,
output wire tx_error_arp_failed,
/*
* Configuration
*/
input wire [47:0] local_mac,
input wire [31:0] local_ip
);
localparam [1:0]
STATE_IDLE = 2'd0,
STATE_ARP_QUERY = 2'd1,
STATE_WAIT_PACKET = 2'd2;
reg [1:0] state_reg = STATE_IDLE, state_next;
reg outgoing_ip_hdr_valid_reg = 1'b0, outgoing_ip_hdr_valid_next;
wire outgoing_ip_hdr_ready;
reg [47:0] outgoing_eth_dest_mac_reg = 48'h000000000000, outgoing_eth_dest_mac_next;
wire outgoing_ip_payload_axis_tready;
/*
* IP frame processing
*/
ip_eth_rx_64
ip_eth_rx_64_inst (
.clk(clk),
.rst(rst),
// Ethernet frame input
.s_eth_hdr_valid(s_eth_hdr_valid),
.s_eth_hdr_ready(s_eth_hdr_ready),
.s_eth_dest_mac(s_eth_dest_mac),
.s_eth_src_mac(s_eth_src_mac),
.s_eth_type(s_eth_type),
.s_eth_payload_axis_tdata(s_eth_payload_axis_tdata),
.s_eth_payload_axis_tkeep(s_eth_payload_axis_tkeep),
.s_eth_payload_axis_tvalid(s_eth_payload_axis_tvalid),
.s_eth_payload_axis_tready(s_eth_payload_axis_tready),
.s_eth_payload_axis_tlast(s_eth_payload_axis_tlast),
.s_eth_payload_axis_tuser(s_eth_payload_axis_tuser),
// IP frame output
.m_ip_hdr_valid(m_ip_hdr_valid),
.m_ip_hdr_ready(m_ip_hdr_ready),
.m_eth_dest_mac(m_ip_eth_dest_mac),
.m_eth_src_mac(m_ip_eth_src_mac),
.m_eth_type(m_ip_eth_type),
.m_ip_version(m_ip_version),
.m_ip_ihl(m_ip_ihl),
.m_ip_dscp(m_ip_dscp),
.m_ip_ecn(m_ip_ecn),
.m_ip_length(m_ip_length),
.m_ip_identification(m_ip_identification),
.m_ip_flags(m_ip_flags),
.m_ip_fragment_offset(m_ip_fragment_offset),
.m_ip_ttl(m_ip_ttl),
.m_ip_protocol(m_ip_protocol),
.m_ip_header_checksum(m_ip_header_checksum),
.m_ip_source_ip(m_ip_source_ip),
.m_ip_dest_ip(m_ip_dest_ip),
.m_ip_payload_axis_tdata(m_ip_payload_axis_tdata),
.m_ip_payload_axis_tkeep(m_ip_payload_axis_tkeep),
.m_ip_payload_axis_tvalid(m_ip_payload_axis_tvalid),
.m_ip_payload_axis_tready(m_ip_payload_axis_tready),
.m_ip_payload_axis_tlast(m_ip_payload_axis_tlast),
.m_ip_payload_axis_tuser(m_ip_payload_axis_tuser),
// Status signals
.busy(rx_busy),
.error_header_early_termination(rx_error_header_early_termination),
.error_payload_early_termination(rx_error_payload_early_termination),
.error_invalid_header(rx_error_invalid_header),
.error_invalid_checksum(rx_error_invalid_checksum)
);
ip_eth_tx_64
ip_eth_tx_64_inst (
.clk(clk),
.rst(rst),
// IP frame input
.s_ip_hdr_valid(outgoing_ip_hdr_valid_reg),
.s_ip_hdr_ready(outgoing_ip_hdr_ready),
.s_eth_dest_mac(outgoing_eth_dest_mac_reg),
.s_eth_src_mac(local_mac),
.s_eth_type(16'h0800),
.s_ip_dscp(s_ip_dscp),
.s_ip_ecn(s_ip_ecn),
.s_ip_length(s_ip_length),
.s_ip_identification(16'd0),
.s_ip_flags(3'b010),
.s_ip_fragment_offset(13'd0),
.s_ip_ttl(s_ip_ttl),
.s_ip_protocol(s_ip_protocol),
.s_ip_source_ip(s_ip_source_ip),
.s_ip_dest_ip(s_ip_dest_ip),
.s_ip_payload_axis_tdata(s_ip_payload_axis_tdata),
.s_ip_payload_axis_tkeep(s_ip_payload_axis_tkeep),
.s_ip_payload_axis_tvalid(s_ip_payload_axis_tvalid),
.s_ip_payload_axis_tready(outgoing_ip_payload_axis_tready),
.s_ip_payload_axis_tlast(s_ip_payload_axis_tlast),
.s_ip_payload_axis_tuser(s_ip_payload_axis_tuser),
// Ethernet frame output
.m_eth_hdr_valid(m_eth_hdr_valid),
.m_eth_hdr_ready(m_eth_hdr_ready),
.m_eth_dest_mac(m_eth_dest_mac),
.m_eth_src_mac(m_eth_src_mac),
.m_eth_type(m_eth_type),
.m_eth_payload_axis_tdata(m_eth_payload_axis_tdata),
.m_eth_payload_axis_tkeep(m_eth_payload_axis_tkeep),
.m_eth_payload_axis_tvalid(m_eth_payload_axis_tvalid),
.m_eth_payload_axis_tready(m_eth_payload_axis_tready),
.m_eth_payload_axis_tlast(m_eth_payload_axis_tlast),
.m_eth_payload_axis_tuser(m_eth_payload_axis_tuser),
// Status signals
.busy(tx_busy),
.error_payload_early_termination(tx_error_payload_early_termination)
);
reg s_ip_hdr_ready_reg = 1'b0, s_ip_hdr_ready_next;
reg arp_request_valid_reg = 1'b0, arp_request_valid_next;
reg arp_response_ready_reg = 1'b0, arp_response_ready_next;
reg drop_packet_reg = 1'b0, drop_packet_next;
assign s_ip_hdr_ready = s_ip_hdr_ready_reg;
assign s_ip_payload_axis_tready = outgoing_ip_payload_axis_tready || drop_packet_reg;
assign arp_request_valid = arp_request_valid_reg;
assign arp_request_ip = s_ip_dest_ip;
assign arp_response_ready = arp_response_ready_reg;
assign tx_error_arp_failed = arp_response_error;
always @* begin
state_next = STATE_IDLE;
arp_request_valid_next = arp_request_valid_reg && !arp_request_ready;
arp_response_ready_next = 1'b0;
drop_packet_next = 1'b0;
s_ip_hdr_ready_next = 1'b0;
outgoing_ip_hdr_valid_next = outgoing_ip_hdr_valid_reg && !outgoing_ip_hdr_ready;
outgoing_eth_dest_mac_next = outgoing_eth_dest_mac_reg;
case (state_reg)
STATE_IDLE: begin
// wait for outgoing packet
if (s_ip_hdr_valid) begin
// initiate ARP request
arp_request_valid_next = 1'b1;
arp_response_ready_next = 1'b1;
state_next = STATE_ARP_QUERY;
end else begin
state_next = STATE_IDLE;
end
end
STATE_ARP_QUERY: begin
arp_response_ready_next = 1'b1;
if (arp_response_valid) begin
// wait for ARP reponse
if (arp_response_error) begin
// did not get MAC address; drop packet
s_ip_hdr_ready_next = 1'b1;
drop_packet_next = 1'b1;
state_next = STATE_WAIT_PACKET;
end else begin
// got MAC address; send packet
s_ip_hdr_ready_next = 1'b1;
outgoing_ip_hdr_valid_next = 1'b1;
outgoing_eth_dest_mac_next = arp_response_mac;
state_next = STATE_WAIT_PACKET;
end
end else begin
state_next = STATE_ARP_QUERY;
end
end
STATE_WAIT_PACKET: begin
drop_packet_next = drop_packet_reg;
// wait for packet transfer to complete
if (s_ip_payload_axis_tlast && s_ip_payload_axis_tready && s_ip_payload_axis_tvalid) begin
state_next = STATE_IDLE;
end else begin
state_next = STATE_WAIT_PACKET;
end
end
endcase
end
always @(posedge clk) begin
if (rst) begin
state_reg <= STATE_IDLE;
arp_request_valid_reg <= 1'b0;
arp_response_ready_reg <= 1'b0;
drop_packet_reg <= 1'b0;
s_ip_hdr_ready_reg <= 1'b0;
outgoing_ip_hdr_valid_reg <= 1'b0;
end else begin
state_reg <= state_next;
arp_request_valid_reg <= arp_request_valid_next;
arp_response_ready_reg <= arp_response_ready_next;
drop_packet_reg <= drop_packet_next;
s_ip_hdr_ready_reg <= s_ip_hdr_ready_next;
outgoing_ip_hdr_valid_reg <= outgoing_ip_hdr_valid_next;
end
outgoing_eth_dest_mac_reg <= outgoing_eth_dest_mac_next;
end
endmodule
/*
Copyright (c) 2014-2018 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* IP arbitrated multiplexer
*/
module ip_arb_mux #
(
parameter S_COUNT = 4,
parameter DATA_WIDTH = 8,
parameter KEEP_ENABLE = (DATA_WIDTH>8),
parameter KEEP_WIDTH = (DATA_WIDTH/8),
parameter ID_ENABLE = 0,
parameter ID_WIDTH = 8,
parameter DEST_ENABLE = 0,
parameter DEST_WIDTH = 8,
parameter USER_ENABLE = 1,
parameter USER_WIDTH = 1,
// arbitration type: "PRIORITY" or "ROUND_ROBIN"
parameter ARB_TYPE = "PRIORITY",
// LSB priority: "LOW", "HIGH"
parameter LSB_PRIORITY = "HIGH"
)
(
input wire clk,
input wire rst,
/*
* IP frame inputs
*/
input wire [S_COUNT-1:0] s_ip_hdr_valid,
output wire [S_COUNT-1:0] s_ip_hdr_ready,
input wire [S_COUNT*48-1:0] s_eth_dest_mac,
input wire [S_COUNT*48-1:0] s_eth_src_mac,
input wire [S_COUNT*16-1:0] s_eth_type,
input wire [S_COUNT*4-1:0] s_ip_version,
input wire [S_COUNT*4-1:0] s_ip_ihl,
input wire [S_COUNT*6-1:0] s_ip_dscp,
input wire [S_COUNT*2-1:0] s_ip_ecn,
input wire [S_COUNT*16-1:0] s_ip_length,
input wire [S_COUNT*16-1:0] s_ip_identification,
input wire [S_COUNT*3-1:0] s_ip_flags,
input wire [S_COUNT*13-1:0] s_ip_fragment_offset,
input wire [S_COUNT*8-1:0] s_ip_ttl,
input wire [S_COUNT*8-1:0] s_ip_protocol,
input wire [S_COUNT*16-1:0] s_ip_header_checksum,
input wire [S_COUNT*32-1:0] s_ip_source_ip,
input wire [S_COUNT*32-1:0] s_ip_dest_ip,
input wire [S_COUNT*DATA_WIDTH-1:0] s_ip_payload_axis_tdata,
input wire [S_COUNT*KEEP_WIDTH-1:0] s_ip_payload_axis_tkeep,
input wire [S_COUNT-1:0] s_ip_payload_axis_tvalid,
output wire [S_COUNT-1:0] s_ip_payload_axis_tready,
input wire [S_COUNT-1:0] s_ip_payload_axis_tlast,
input wire [S_COUNT*ID_WIDTH-1:0] s_ip_payload_axis_tid,
input wire [S_COUNT*DEST_WIDTH-1:0] s_ip_payload_axis_tdest,
input wire [S_COUNT*USER_WIDTH-1:0] s_ip_payload_axis_tuser,
/*
* IP frame output
*/
output wire m_ip_hdr_valid,
input wire m_ip_hdr_ready,
output wire [47:0] m_eth_dest_mac,
output wire [47:0] m_eth_src_mac,
output wire [15:0] m_eth_type,
output wire [3:0] m_ip_version,
output wire [3:0] m_ip_ihl,
output wire [5:0] m_ip_dscp,
output wire [1:0] m_ip_ecn,
output wire [15:0] m_ip_length,
output wire [15:0] m_ip_identification,
output wire [2:0] m_ip_flags,
output wire [12:0] m_ip_fragment_offset,
output wire [7:0] m_ip_ttl,
output wire [7:0] m_ip_protocol,
output wire [15:0] m_ip_header_checksum,
output wire [31:0] m_ip_source_ip,
output wire [31:0] m_ip_dest_ip,
output wire [DATA_WIDTH-1:0] m_ip_payload_axis_tdata,
output wire [KEEP_WIDTH-1:0] m_ip_payload_axis_tkeep,
output wire m_ip_payload_axis_tvalid,
input wire m_ip_payload_axis_tready,
output wire m_ip_payload_axis_tlast,
output wire [ID_WIDTH-1:0] m_ip_payload_axis_tid,
output wire [DEST_WIDTH-1:0] m_ip_payload_axis_tdest,
output wire [USER_WIDTH-1:0] m_ip_payload_axis_tuser
);
parameter CL_S_COUNT = $clog2(S_COUNT);
reg frame_reg = 1'b0, frame_next;
reg s_ip_hdr_ready_mask_reg = 1'b0, s_ip_hdr_ready_mask_next;
reg m_ip_hdr_valid_reg = 1'b0, m_ip_hdr_valid_next;
reg [47:0] m_eth_dest_mac_reg = 48'd0, m_eth_dest_mac_next;
reg [47:0] m_eth_src_mac_reg = 48'd0, m_eth_src_mac_next;
reg [15:0] m_eth_type_reg = 16'd0, m_eth_type_next;
reg [3:0] m_ip_version_reg = 4'd0, m_ip_version_next;
reg [3:0] m_ip_ihl_reg = 4'd0, m_ip_ihl_next;
reg [5:0] m_ip_dscp_reg = 6'd0, m_ip_dscp_next;
reg [1:0] m_ip_ecn_reg = 2'd0, m_ip_ecn_next;
reg [15:0] m_ip_length_reg = 16'd0, m_ip_length_next;
reg [15:0] m_ip_identification_reg = 16'd0, m_ip_identification_next;
reg [2:0] m_ip_flags_reg = 3'd0, m_ip_flags_next;
reg [12:0] m_ip_fragment_offset_reg = 13'd0, m_ip_fragment_offset_next;
reg [7:0] m_ip_ttl_reg = 8'd0, m_ip_ttl_next;
reg [7:0] m_ip_protocol_reg = 8'd0, m_ip_protocol_next;
reg [15:0] m_ip_header_checksum_reg = 16'd0, m_ip_header_checksum_next;
reg [31:0] m_ip_source_ip_reg = 32'd0, m_ip_source_ip_next;
reg [31:0] m_ip_dest_ip_reg = 32'd0, m_ip_dest_ip_next;
wire [S_COUNT-1:0] request;
wire [S_COUNT-1:0] acknowledge;
wire [S_COUNT-1:0] grant;
wire grant_valid;
wire [CL_S_COUNT-1:0] grant_encoded;
// internal datapath
reg [DATA_WIDTH-1:0] m_ip_payload_axis_tdata_int;
reg [KEEP_WIDTH-1:0] m_ip_payload_axis_tkeep_int;
reg m_ip_payload_axis_tvalid_int;
reg m_ip_payload_axis_tready_int_reg = 1'b0;
reg m_ip_payload_axis_tlast_int;
reg [ID_WIDTH-1:0] m_ip_payload_axis_tid_int;
reg [DEST_WIDTH-1:0] m_ip_payload_axis_tdest_int;
reg [USER_WIDTH-1:0] m_ip_payload_axis_tuser_int;
wire m_ip_payload_axis_tready_int_early;
assign s_ip_hdr_ready = (!s_ip_hdr_ready_mask_reg && grant_valid) << grant_encoded;
assign s_ip_payload_axis_tready = (m_ip_payload_axis_tready_int_reg && grant_valid) << grant_encoded;
assign m_ip_hdr_valid = m_ip_hdr_valid_reg;
assign m_eth_dest_mac = m_eth_dest_mac_reg;
assign m_eth_src_mac = m_eth_src_mac_reg;
assign m_eth_type = m_eth_type_reg;
assign m_ip_version = m_ip_version_reg;
assign m_ip_ihl = m_ip_ihl_reg;
assign m_ip_dscp = m_ip_dscp_reg;
assign m_ip_ecn = m_ip_ecn_reg;
assign m_ip_length = m_ip_length_reg;
assign m_ip_identification = m_ip_identification_reg;
assign m_ip_flags = m_ip_flags_reg;
assign m_ip_fragment_offset = m_ip_fragment_offset_reg;
assign m_ip_ttl = m_ip_ttl_reg;
assign m_ip_protocol = m_ip_protocol_reg;
assign m_ip_header_checksum = m_ip_header_checksum_reg;
assign m_ip_source_ip = m_ip_source_ip_reg;
assign m_ip_dest_ip = m_ip_dest_ip_reg;
// mux for incoming packet
wire [DATA_WIDTH-1:0] current_s_tdata = s_ip_payload_axis_tdata[grant_encoded*DATA_WIDTH +: DATA_WIDTH];
wire [KEEP_WIDTH-1:0] current_s_tkeep = s_ip_payload_axis_tkeep[grant_encoded*KEEP_WIDTH +: KEEP_WIDTH];
wire current_s_tvalid = s_ip_payload_axis_tvalid[grant_encoded];
wire current_s_tready = s_ip_payload_axis_tready[grant_encoded];
wire current_s_tlast = s_ip_payload_axis_tlast[grant_encoded];
wire [ID_WIDTH-1:0] current_s_tid = s_ip_payload_axis_tid[grant_encoded*ID_WIDTH +: ID_WIDTH];
wire [DEST_WIDTH-1:0] current_s_tdest = s_ip_payload_axis_tdest[grant_encoded*DEST_WIDTH +: DEST_WIDTH];
wire [USER_WIDTH-1:0] current_s_tuser = s_ip_payload_axis_tuser[grant_encoded*USER_WIDTH +: USER_WIDTH];
// arbiter instance
arbiter #(
.PORTS(S_COUNT),
.TYPE(ARB_TYPE),
.BLOCK("ACKNOWLEDGE"),
.LSB_PRIORITY(LSB_PRIORITY)
)
arb_inst (
.clk(clk),
.rst(rst),
.request(request),
.acknowledge(acknowledge),
.grant(grant),
.grant_valid(grant_valid),
.grant_encoded(grant_encoded)
);
assign request = s_ip_hdr_valid & ~grant;
assign acknowledge = grant & s_ip_payload_axis_tvalid & s_ip_payload_axis_tready & s_ip_payload_axis_tlast;
always @* begin
frame_next = frame_reg;
s_ip_hdr_ready_mask_next = s_ip_hdr_ready_mask_reg;
m_ip_hdr_valid_next = m_ip_hdr_valid_reg && !m_ip_hdr_ready;
m_eth_dest_mac_next = m_eth_dest_mac_reg;
m_eth_src_mac_next = m_eth_src_mac_reg;
m_eth_type_next = m_eth_type_reg;
m_ip_version_next = m_ip_version_reg;
m_ip_ihl_next = m_ip_ihl_reg;
m_ip_dscp_next = m_ip_dscp_reg;
m_ip_ecn_next = m_ip_ecn_reg;
m_ip_length_next = m_ip_length_reg;
m_ip_identification_next = m_ip_identification_reg;
m_ip_flags_next = m_ip_flags_reg;
m_ip_fragment_offset_next = m_ip_fragment_offset_reg;
m_ip_ttl_next = m_ip_ttl_reg;
m_ip_protocol_next = m_ip_protocol_reg;
m_ip_header_checksum_next = m_ip_header_checksum_reg;
m_ip_source_ip_next = m_ip_source_ip_reg;
m_ip_dest_ip_next = m_ip_dest_ip_reg;
if (s_ip_payload_axis_tvalid[grant_encoded] && s_ip_payload_axis_tready[grant_encoded]) begin
// end of frame detection
if (s_ip_payload_axis_tlast[grant_encoded]) begin
frame_next = 1'b0;
s_ip_hdr_ready_mask_next = 1'b0;
end
end
if (!frame_reg && grant_valid) begin
// start of frame
frame_next = 1'b1;
s_ip_hdr_ready_mask_next = 1'b1;
m_ip_hdr_valid_next = 1'b1;
m_eth_dest_mac_next = s_eth_dest_mac[grant_encoded*48 +: 48];
m_eth_src_mac_next = s_eth_src_mac[grant_encoded*48 +: 48];
m_eth_type_next = s_eth_type[grant_encoded*16 +: 16];
m_ip_version_next = s_ip_version[grant_encoded*4 +: 4];
m_ip_ihl_next = s_ip_ihl[grant_encoded*4 +: 4];
m_ip_dscp_next = s_ip_dscp[grant_encoded*6 +: 6];
m_ip_ecn_next = s_ip_ecn[grant_encoded*2 +: 2];
m_ip_length_next = s_ip_length[grant_encoded*16 +: 16];
m_ip_identification_next = s_ip_identification[grant_encoded*16 +: 16];
m_ip_flags_next = s_ip_flags[grant_encoded*3 +: 3];
m_ip_fragment_offset_next = s_ip_fragment_offset[grant_encoded*13 +: 13];
m_ip_ttl_next = s_ip_ttl[grant_encoded*8 +: 8];
m_ip_protocol_next = s_ip_protocol[grant_encoded*8 +: 8];
m_ip_header_checksum_next = s_ip_header_checksum[grant_encoded*16 +: 16];
m_ip_source_ip_next = s_ip_source_ip[grant_encoded*32 +: 32];
m_ip_dest_ip_next = s_ip_dest_ip[grant_encoded*32 +: 32];
end
// pass through selected packet data
m_ip_payload_axis_tdata_int = current_s_tdata;
m_ip_payload_axis_tkeep_int = current_s_tkeep;
m_ip_payload_axis_tvalid_int = current_s_tvalid && m_ip_payload_axis_tready_int_reg && grant_valid;
m_ip_payload_axis_tlast_int = current_s_tlast;
m_ip_payload_axis_tid_int = current_s_tid;
m_ip_payload_axis_tdest_int = current_s_tdest;
m_ip_payload_axis_tuser_int = current_s_tuser;
end
always @(posedge clk) begin
if (rst) begin
frame_reg <= 1'b0;
s_ip_hdr_ready_mask_reg <= 1'b0;
m_ip_hdr_valid_reg <= 1'b0;
end else begin
frame_reg <= frame_next;
s_ip_hdr_ready_mask_reg <= s_ip_hdr_ready_mask_next;
m_ip_hdr_valid_reg <= m_ip_hdr_valid_next;
end
m_eth_dest_mac_reg <= m_eth_dest_mac_next;
m_eth_src_mac_reg <= m_eth_src_mac_next;
m_eth_type_reg <= m_eth_type_next;
m_ip_version_reg <= m_ip_version_next;
m_ip_ihl_reg <= m_ip_ihl_next;
m_ip_dscp_reg <= m_ip_dscp_next;
m_ip_ecn_reg <= m_ip_ecn_next;
m_ip_length_reg <= m_ip_length_next;
m_ip_identification_reg <= m_ip_identification_next;
m_ip_flags_reg <= m_ip_flags_next;
m_ip_fragment_offset_reg <= m_ip_fragment_offset_next;
m_ip_ttl_reg <= m_ip_ttl_next;
m_ip_protocol_reg <= m_ip_protocol_next;
m_ip_header_checksum_reg <= m_ip_header_checksum_next;
m_ip_source_ip_reg <= m_ip_source_ip_next;
m_ip_dest_ip_reg <= m_ip_dest_ip_next;
end
// output datapath logic
reg [DATA_WIDTH-1:0] m_ip_payload_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] m_ip_payload_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
reg m_ip_payload_axis_tvalid_reg = 1'b0, m_ip_payload_axis_tvalid_next;
reg m_ip_payload_axis_tlast_reg = 1'b0;
reg [ID_WIDTH-1:0] m_ip_payload_axis_tid_reg = {ID_WIDTH{1'b0}};
reg [DEST_WIDTH-1:0] m_ip_payload_axis_tdest_reg = {DEST_WIDTH{1'b0}};
reg [USER_WIDTH-1:0] m_ip_payload_axis_tuser_reg = {USER_WIDTH{1'b0}};
reg [DATA_WIDTH-1:0] temp_m_ip_payload_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] temp_m_ip_payload_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
reg temp_m_ip_payload_axis_tvalid_reg = 1'b0, temp_m_ip_payload_axis_tvalid_next;
reg temp_m_ip_payload_axis_tlast_reg = 1'b0;
reg [ID_WIDTH-1:0] temp_m_ip_payload_axis_tid_reg = {ID_WIDTH{1'b0}};
reg [DEST_WIDTH-1:0] temp_m_ip_payload_axis_tdest_reg = {DEST_WIDTH{1'b0}};
reg [USER_WIDTH-1:0] temp_m_ip_payload_axis_tuser_reg = {USER_WIDTH{1'b0}};
// datapath control
reg store_axis_int_to_output;
reg store_axis_int_to_temp;
reg store_ip_payload_axis_temp_to_output;
assign m_ip_payload_axis_tdata = m_ip_payload_axis_tdata_reg;
assign m_ip_payload_axis_tkeep = KEEP_ENABLE ? m_ip_payload_axis_tkeep_reg : {KEEP_WIDTH{1'b1}};
assign m_ip_payload_axis_tvalid = m_ip_payload_axis_tvalid_reg;
assign m_ip_payload_axis_tlast = m_ip_payload_axis_tlast_reg;
assign m_ip_payload_axis_tid = ID_ENABLE ? m_ip_payload_axis_tid_reg : {ID_WIDTH{1'b0}};
assign m_ip_payload_axis_tdest = DEST_ENABLE ? m_ip_payload_axis_tdest_reg : {DEST_WIDTH{1'b0}};
assign m_ip_payload_axis_tuser = USER_ENABLE ? m_ip_payload_axis_tuser_reg : {USER_WIDTH{1'b0}};
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
assign m_ip_payload_axis_tready_int_early = m_ip_payload_axis_tready || (!temp_m_ip_payload_axis_tvalid_reg && (!m_ip_payload_axis_tvalid_reg || !m_ip_payload_axis_tvalid_int));
always @* begin
// transfer sink ready state to source
m_ip_payload_axis_tvalid_next = m_ip_payload_axis_tvalid_reg;
temp_m_ip_payload_axis_tvalid_next = temp_m_ip_payload_axis_tvalid_reg;
store_axis_int_to_output = 1'b0;
store_axis_int_to_temp = 1'b0;
store_ip_payload_axis_temp_to_output = 1'b0;
if (m_ip_payload_axis_tready_int_reg) begin
// input is ready
if (m_ip_payload_axis_tready || !m_ip_payload_axis_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output
m_ip_payload_axis_tvalid_next = m_ip_payload_axis_tvalid_int;
store_axis_int_to_output = 1'b1;
end else begin
// output is not ready, store input in temp
temp_m_ip_payload_axis_tvalid_next = m_ip_payload_axis_tvalid_int;
store_axis_int_to_temp = 1'b1;
end
end else if (m_ip_payload_axis_tready) begin
// input is not ready, but output is ready
m_ip_payload_axis_tvalid_next = temp_m_ip_payload_axis_tvalid_reg;
temp_m_ip_payload_axis_tvalid_next = 1'b0;
store_ip_payload_axis_temp_to_output = 1'b1;
end
end
always @(posedge clk) begin
if (rst) begin
m_ip_payload_axis_tvalid_reg <= 1'b0;
m_ip_payload_axis_tready_int_reg <= 1'b0;
temp_m_ip_payload_axis_tvalid_reg <= 1'b0;
end else begin
m_ip_payload_axis_tvalid_reg <= m_ip_payload_axis_tvalid_next;
m_ip_payload_axis_tready_int_reg <= m_ip_payload_axis_tready_int_early;
temp_m_ip_payload_axis_tvalid_reg <= temp_m_ip_payload_axis_tvalid_next;
end
// datapath
if (store_axis_int_to_output) begin
m_ip_payload_axis_tdata_reg <= m_ip_payload_axis_tdata_int;
m_ip_payload_axis_tkeep_reg <= m_ip_payload_axis_tkeep_int;
m_ip_payload_axis_tlast_reg <= m_ip_payload_axis_tlast_int;
m_ip_payload_axis_tid_reg <= m_ip_payload_axis_tid_int;
m_ip_payload_axis_tdest_reg <= m_ip_payload_axis_tdest_int;
m_ip_payload_axis_tuser_reg <= m_ip_payload_axis_tuser_int;
end else if (store_ip_payload_axis_temp_to_output) begin
m_ip_payload_axis_tdata_reg <= temp_m_ip_payload_axis_tdata_reg;
m_ip_payload_axis_tkeep_reg <= temp_m_ip_payload_axis_tkeep_reg;
m_ip_payload_axis_tlast_reg <= temp_m_ip_payload_axis_tlast_reg;
m_ip_payload_axis_tid_reg <= temp_m_ip_payload_axis_tid_reg;
m_ip_payload_axis_tdest_reg <= temp_m_ip_payload_axis_tdest_reg;
m_ip_payload_axis_tuser_reg <= temp_m_ip_payload_axis_tuser_reg;
end
if (store_axis_int_to_temp) begin
temp_m_ip_payload_axis_tdata_reg <= m_ip_payload_axis_tdata_int;
temp_m_ip_payload_axis_tkeep_reg <= m_ip_payload_axis_tkeep_int;
temp_m_ip_payload_axis_tlast_reg <= m_ip_payload_axis_tlast_int;
temp_m_ip_payload_axis_tid_reg <= m_ip_payload_axis_tid_int;
temp_m_ip_payload_axis_tdest_reg <= m_ip_payload_axis_tdest_int;
temp_m_ip_payload_axis_tuser_reg <= m_ip_payload_axis_tuser_int;
end
end
endmodule
/*
Copyright (c) 2014-2018 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* IPv4 and ARP block, ethernet frame interface
*/
module ip_complete #(
parameter ARP_CACHE_ADDR_WIDTH = 9,
parameter ARP_REQUEST_RETRY_COUNT = 4,
parameter ARP_REQUEST_RETRY_INTERVAL = 125000000*2,
parameter ARP_REQUEST_TIMEOUT = 125000000*30
)
(
input wire clk,
input wire rst,
/*
* Ethernet frame input
*/
input wire s_eth_hdr_valid,
output wire s_eth_hdr_ready,
input wire [47:0] s_eth_dest_mac,
input wire [47:0] s_eth_src_mac,
input wire [15:0] s_eth_type,
input wire [7:0] s_eth_payload_axis_tdata,
input wire s_eth_payload_axis_tvalid,
output wire s_eth_payload_axis_tready,
input wire s_eth_payload_axis_tlast,
input wire s_eth_payload_axis_tuser,
/*
* Ethernet frame output
*/
output wire m_eth_hdr_valid,
input wire m_eth_hdr_ready,
output wire [47:0] m_eth_dest_mac,
output wire [47:0] m_eth_src_mac,
output wire [15:0] m_eth_type,
output wire [7:0] m_eth_payload_axis_tdata,
output wire m_eth_payload_axis_tvalid,
input wire m_eth_payload_axis_tready,
output wire m_eth_payload_axis_tlast,
output wire m_eth_payload_axis_tuser,
/*
* IP input
*/
input wire s_ip_hdr_valid,
output wire s_ip_hdr_ready,
input wire [5:0] s_ip_dscp,
input wire [1:0] s_ip_ecn,
input wire [15:0] s_ip_length,
input wire [7:0] s_ip_ttl,
input wire [7:0] s_ip_protocol,
input wire [31:0] s_ip_source_ip,
input wire [31:0] s_ip_dest_ip,
input wire [7:0] s_ip_payload_axis_tdata,
input wire s_ip_payload_axis_tvalid,
output wire s_ip_payload_axis_tready,
input wire s_ip_payload_axis_tlast,
input wire s_ip_payload_axis_tuser,
/*
* IP output
*/
output wire m_ip_hdr_valid,
input wire m_ip_hdr_ready,
output wire [47:0] m_ip_eth_dest_mac,
output wire [47:0] m_ip_eth_src_mac,
output wire [15:0] m_ip_eth_type,
output wire [3:0] m_ip_version,
output wire [3:0] m_ip_ihl,
output wire [5:0] m_ip_dscp,
output wire [1:0] m_ip_ecn,
output wire [15:0] m_ip_length,
output wire [15:0] m_ip_identification,
output wire [2:0] m_ip_flags,
output wire [12:0] m_ip_fragment_offset,
output wire [7:0] m_ip_ttl,
output wire [7:0] m_ip_protocol,
output wire [15:0] m_ip_header_checksum,
output wire [31:0] m_ip_source_ip,
output wire [31:0] m_ip_dest_ip,
output wire [7:0] m_ip_payload_axis_tdata,
output wire m_ip_payload_axis_tvalid,
input wire m_ip_payload_axis_tready,
output wire m_ip_payload_axis_tlast,
output wire m_ip_payload_axis_tuser,
/*
* Status
*/
output wire rx_busy,
output wire tx_busy,
output wire rx_error_header_early_termination,
output wire rx_error_payload_early_termination,
output wire rx_error_invalid_header,
output wire rx_error_invalid_checksum,
output wire tx_error_payload_early_termination,
output wire tx_error_arp_failed,
/*
* Configuration
*/
input wire [47:0] local_mac,
input wire [31:0] local_ip,
input wire [31:0] gateway_ip,
input wire [31:0] subnet_mask,
input wire clear_arp_cache
);
/*
This module integrates the IP and ARP modules for a complete IP stack
*/
wire arp_request_valid;
wire arp_request_ready;
wire [31:0] arp_request_ip;
wire arp_response_valid;
wire arp_response_ready;
wire arp_response_error;
wire [47:0] arp_response_mac;
wire ip_rx_eth_hdr_valid;
wire ip_rx_eth_hdr_ready;
wire [47:0] ip_rx_eth_dest_mac;
wire [47:0] ip_rx_eth_src_mac;
wire [15:0] ip_rx_eth_type;
wire [7:0] ip_rx_eth_payload_axis_tdata;
wire ip_rx_eth_payload_axis_tvalid;
wire ip_rx_eth_payload_axis_tready;
wire ip_rx_eth_payload_axis_tlast;
wire ip_rx_eth_payload_axis_tuser;
wire ip_tx_eth_hdr_valid;
wire ip_tx_eth_hdr_ready;
wire [47:0] ip_tx_eth_dest_mac;
wire [47:0] ip_tx_eth_src_mac;
wire [15:0] ip_tx_eth_type;
wire [7:0] ip_tx_eth_payload_axis_tdata;
wire ip_tx_eth_payload_axis_tvalid;
wire ip_tx_eth_payload_axis_tready;
wire ip_tx_eth_payload_axis_tlast;
wire ip_tx_eth_payload_axis_tuser;
wire arp_rx_eth_hdr_valid;
wire arp_rx_eth_hdr_ready;
wire [47:0] arp_rx_eth_dest_mac;
wire [47:0] arp_rx_eth_src_mac;
wire [15:0] arp_rx_eth_type;
wire [7:0] arp_rx_eth_payload_axis_tdata;
wire arp_rx_eth_payload_axis_tvalid;
wire arp_rx_eth_payload_axis_tready;
wire arp_rx_eth_payload_axis_tlast;
wire arp_rx_eth_payload_axis_tuser;
wire arp_tx_eth_hdr_valid;
wire arp_tx_eth_hdr_ready;
wire [47:0] arp_tx_eth_dest_mac;
wire [47:0] arp_tx_eth_src_mac;
wire [15:0] arp_tx_eth_type;
wire [7:0] arp_tx_eth_payload_axis_tdata;
wire arp_tx_eth_payload_axis_tvalid;
wire arp_tx_eth_payload_axis_tready;
wire arp_tx_eth_payload_axis_tlast;
wire arp_tx_eth_payload_axis_tuser;
/*
* Input classifier (eth_type)
*/
wire s_select_ip = (s_eth_type == 16'h0800);
wire s_select_arp = (s_eth_type == 16'h0806);
wire s_select_none = !(s_select_ip || s_select_arp);
reg s_select_ip_reg = 1'b0;
reg s_select_arp_reg = 1'b0;
reg s_select_none_reg = 1'b0;
always @(posedge clk) begin
if (rst) begin
s_select_ip_reg <= 1'b0;
s_select_arp_reg <= 1'b0;
s_select_none_reg <= 1'b0;
end else begin
if (s_eth_payload_axis_tvalid) begin
if ((!s_select_ip_reg && !s_select_arp_reg && !s_select_none_reg) ||
(s_eth_payload_axis_tvalid && s_eth_payload_axis_tready && s_eth_payload_axis_tlast)) begin
s_select_ip_reg <= s_select_ip;
s_select_arp_reg <= s_select_arp;
s_select_none_reg <= s_select_none;
end
end else begin
s_select_ip_reg <= 1'b0;
s_select_arp_reg <= 1'b0;
s_select_none_reg <= 1'b0;
end
end
end
assign ip_rx_eth_hdr_valid = s_select_ip && s_eth_hdr_valid;
assign ip_rx_eth_dest_mac = s_eth_dest_mac;
assign ip_rx_eth_src_mac = s_eth_src_mac;
assign ip_rx_eth_type = 16'h0800;
assign ip_rx_eth_payload_axis_tdata = s_eth_payload_axis_tdata;
assign ip_rx_eth_payload_axis_tvalid = s_select_ip_reg && s_eth_payload_axis_tvalid;
assign ip_rx_eth_payload_axis_tlast = s_eth_payload_axis_tlast;
assign ip_rx_eth_payload_axis_tuser = s_eth_payload_axis_tuser;
assign arp_rx_eth_hdr_valid = s_select_arp && s_eth_hdr_valid;
assign arp_rx_eth_dest_mac = s_eth_dest_mac;
assign arp_rx_eth_src_mac = s_eth_src_mac;
assign arp_rx_eth_type = 16'h0806;
assign arp_rx_eth_payload_axis_tdata = s_eth_payload_axis_tdata;
assign arp_rx_eth_payload_axis_tvalid = s_select_arp_reg && s_eth_payload_axis_tvalid;
assign arp_rx_eth_payload_axis_tlast = s_eth_payload_axis_tlast;
assign arp_rx_eth_payload_axis_tuser = s_eth_payload_axis_tuser;
assign s_eth_hdr_ready = (s_select_ip && ip_rx_eth_hdr_ready) ||
(s_select_arp && arp_rx_eth_hdr_ready) ||
(s_select_none);
assign s_eth_payload_axis_tready = (s_select_ip_reg && ip_rx_eth_payload_axis_tready) ||
(s_select_arp_reg && arp_rx_eth_payload_axis_tready) ||
s_select_none_reg;
/*
* Output arbiter
*/
eth_arb_mux #(
.S_COUNT(2),
.DATA_WIDTH(8),
.KEEP_ENABLE(0),
.ID_ENABLE(0),
.DEST_ENABLE(0),
.USER_ENABLE(1),
.USER_WIDTH(1),
.ARB_TYPE("PRIORITY"),
.LSB_PRIORITY("HIGH")
)
eth_arb_mux_inst (
.clk(clk),
.rst(rst),
// Ethernet frame inputs
.s_eth_hdr_valid({ip_tx_eth_hdr_valid, arp_tx_eth_hdr_valid}),
.s_eth_hdr_ready({ip_tx_eth_hdr_ready, arp_tx_eth_hdr_ready}),
.s_eth_dest_mac({ip_tx_eth_dest_mac, arp_tx_eth_dest_mac}),
.s_eth_src_mac({ip_tx_eth_src_mac, arp_tx_eth_src_mac}),
.s_eth_type({ip_tx_eth_type, arp_tx_eth_type}),
.s_eth_payload_axis_tdata({ip_tx_eth_payload_axis_tdata, arp_tx_eth_payload_axis_tdata}),
.s_eth_payload_axis_tkeep(0),
.s_eth_payload_axis_tvalid({ip_tx_eth_payload_axis_tvalid, arp_tx_eth_payload_axis_tvalid}),
.s_eth_payload_axis_tready({ip_tx_eth_payload_axis_tready, arp_tx_eth_payload_axis_tready}),
.s_eth_payload_axis_tlast({ip_tx_eth_payload_axis_tlast, arp_tx_eth_payload_axis_tlast}),
.s_eth_payload_axis_tid(0),
.s_eth_payload_axis_tdest(0),
.s_eth_payload_axis_tuser({ip_tx_eth_payload_axis_tuser, arp_tx_eth_payload_axis_tuser}),
// Ethernet frame output
.m_eth_hdr_valid(m_eth_hdr_valid),
.m_eth_hdr_ready(m_eth_hdr_ready),
.m_eth_dest_mac(m_eth_dest_mac),
.m_eth_src_mac(m_eth_src_mac),
.m_eth_type(m_eth_type),
.m_eth_payload_axis_tdata(m_eth_payload_axis_tdata),
.m_eth_payload_axis_tkeep(),
.m_eth_payload_axis_tvalid(m_eth_payload_axis_tvalid),
.m_eth_payload_axis_tready(m_eth_payload_axis_tready),
.m_eth_payload_axis_tlast(m_eth_payload_axis_tlast),
.m_eth_payload_axis_tid(),
.m_eth_payload_axis_tdest(),
.m_eth_payload_axis_tuser(m_eth_payload_axis_tuser)
);
/*
* IP module
*/
ip
ip_inst (
.clk(clk),
.rst(rst),
// Ethernet frame input
.s_eth_hdr_valid(ip_rx_eth_hdr_valid),
.s_eth_hdr_ready(ip_rx_eth_hdr_ready),
.s_eth_dest_mac(ip_rx_eth_dest_mac),
.s_eth_src_mac(ip_rx_eth_src_mac),
.s_eth_type(ip_rx_eth_type),
.s_eth_payload_axis_tdata(ip_rx_eth_payload_axis_tdata),
.s_eth_payload_axis_tvalid(ip_rx_eth_payload_axis_tvalid),
.s_eth_payload_axis_tready(ip_rx_eth_payload_axis_tready),
.s_eth_payload_axis_tlast(ip_rx_eth_payload_axis_tlast),
.s_eth_payload_axis_tuser(ip_rx_eth_payload_axis_tuser),
// Ethernet frame output
.m_eth_hdr_valid(ip_tx_eth_hdr_valid),
.m_eth_hdr_ready(ip_tx_eth_hdr_ready),
.m_eth_dest_mac(ip_tx_eth_dest_mac),
.m_eth_src_mac(ip_tx_eth_src_mac),
.m_eth_type(ip_tx_eth_type),
.m_eth_payload_axis_tdata(ip_tx_eth_payload_axis_tdata),
.m_eth_payload_axis_tvalid(ip_tx_eth_payload_axis_tvalid),
.m_eth_payload_axis_tready(ip_tx_eth_payload_axis_tready),
.m_eth_payload_axis_tlast(ip_tx_eth_payload_axis_tlast),
.m_eth_payload_axis_tuser(ip_tx_eth_payload_axis_tuser),
// IP frame output
.m_ip_hdr_valid(m_ip_hdr_valid),
.m_ip_hdr_ready(m_ip_hdr_ready),
.m_ip_eth_dest_mac(m_ip_eth_dest_mac),
.m_ip_eth_src_mac(m_ip_eth_src_mac),
.m_ip_eth_type(m_ip_eth_type),
.m_ip_version(m_ip_version),
.m_ip_ihl(m_ip_ihl),
.m_ip_dscp(m_ip_dscp),
.m_ip_ecn(m_ip_ecn),
.m_ip_length(m_ip_length),
.m_ip_identification(m_ip_identification),
.m_ip_flags(m_ip_flags),
.m_ip_fragment_offset(m_ip_fragment_offset),
.m_ip_ttl(m_ip_ttl),
.m_ip_protocol(m_ip_protocol),
.m_ip_header_checksum(m_ip_header_checksum),
.m_ip_source_ip(m_ip_source_ip),
.m_ip_dest_ip(m_ip_dest_ip),
.m_ip_payload_axis_tdata(m_ip_payload_axis_tdata),
.m_ip_payload_axis_tvalid(m_ip_payload_axis_tvalid),
.m_ip_payload_axis_tready(m_ip_payload_axis_tready),
.m_ip_payload_axis_tlast(m_ip_payload_axis_tlast),
.m_ip_payload_axis_tuser(m_ip_payload_axis_tuser),
// IP frame input
.s_ip_hdr_valid(s_ip_hdr_valid),
.s_ip_hdr_ready(s_ip_hdr_ready),
.s_ip_dscp(s_ip_dscp),
.s_ip_ecn(s_ip_ecn),
.s_ip_length(s_ip_length),
.s_ip_ttl(s_ip_ttl),
.s_ip_protocol(s_ip_protocol),
.s_ip_source_ip(s_ip_source_ip),
.s_ip_dest_ip(s_ip_dest_ip),
.s_ip_payload_axis_tdata(s_ip_payload_axis_tdata),
.s_ip_payload_axis_tvalid(s_ip_payload_axis_tvalid),
.s_ip_payload_axis_tready(s_ip_payload_axis_tready),
.s_ip_payload_axis_tlast(s_ip_payload_axis_tlast),
.s_ip_payload_axis_tuser(s_ip_payload_axis_tuser),
// ARP requests
.arp_request_valid(arp_request_valid),
.arp_request_ready(arp_request_ready),
.arp_request_ip(arp_request_ip),
.arp_response_valid(arp_response_valid),
.arp_response_ready(arp_response_ready),
.arp_response_error(arp_response_error),
.arp_response_mac(arp_response_mac),
// Status
.rx_busy(rx_busy),
.tx_busy(tx_busy),
.rx_error_header_early_termination(rx_error_header_early_termination),
.rx_error_payload_early_termination(rx_error_payload_early_termination),
.rx_error_invalid_header(rx_error_invalid_header),
.rx_error_invalid_checksum(rx_error_invalid_checksum),
.tx_error_payload_early_termination(tx_error_payload_early_termination),
.tx_error_arp_failed(tx_error_arp_failed),
// Configuration
.local_mac(local_mac),
.local_ip(local_ip)
);
/*
* ARP module
*/
arp #(
.CACHE_ADDR_WIDTH(ARP_CACHE_ADDR_WIDTH),
.REQUEST_RETRY_COUNT(ARP_REQUEST_RETRY_COUNT),
.REQUEST_RETRY_INTERVAL(ARP_REQUEST_RETRY_INTERVAL),
.REQUEST_TIMEOUT(ARP_REQUEST_TIMEOUT)
)
arp_inst (
.clk(clk),
.rst(rst),
// Ethernet frame input
.s_eth_hdr_valid(arp_rx_eth_hdr_valid),
.s_eth_hdr_ready(arp_rx_eth_hdr_ready),
.s_eth_dest_mac(arp_rx_eth_dest_mac),
.s_eth_src_mac(arp_rx_eth_src_mac),
.s_eth_type(arp_rx_eth_type),
.s_eth_payload_axis_tdata(arp_rx_eth_payload_axis_tdata),
.s_eth_payload_axis_tvalid(arp_rx_eth_payload_axis_tvalid),
.s_eth_payload_axis_tready(arp_rx_eth_payload_axis_tready),
.s_eth_payload_axis_tlast(arp_rx_eth_payload_axis_tlast),
.s_eth_payload_axis_tuser(arp_rx_eth_payload_axis_tuser),
// Ethernet frame output
.m_eth_hdr_valid(arp_tx_eth_hdr_valid),
.m_eth_hdr_ready(arp_tx_eth_hdr_ready),
.m_eth_dest_mac(arp_tx_eth_dest_mac),
.m_eth_src_mac(arp_tx_eth_src_mac),
.m_eth_type(arp_tx_eth_type),
.m_eth_payload_axis_tdata(arp_tx_eth_payload_axis_tdata),
.m_eth_payload_axis_tvalid(arp_tx_eth_payload_axis_tvalid),
.m_eth_payload_axis_tready(arp_tx_eth_payload_axis_tready),
.m_eth_payload_axis_tlast(arp_tx_eth_payload_axis_tlast),
.m_eth_payload_axis_tuser(arp_tx_eth_payload_axis_tuser),
// ARP requests
.arp_request_valid(arp_request_valid),
.arp_request_ready(arp_request_ready),
.arp_request_ip(arp_request_ip),
.arp_response_valid(arp_response_valid),
.arp_response_ready(arp_response_ready),
.arp_response_error(arp_response_error),
.arp_response_mac(arp_response_mac),
// Configuration
.local_mac(local_mac),
.local_ip(local_ip),
.gateway_ip(gateway_ip),
.subnet_mask(subnet_mask),
.clear_cache(clear_arp_cache)
);
endmodule
/*
Copyright (c) 2014-2018 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* IPv4 and ARP block, ethernet frame interface (64 bit datapath)
*/
module ip_complete_64 #(
parameter ARP_CACHE_ADDR_WIDTH = 9,
parameter ARP_REQUEST_RETRY_COUNT = 4,
parameter ARP_REQUEST_RETRY_INTERVAL = 156250000*2,
parameter ARP_REQUEST_TIMEOUT = 156250000*30
)
(
input wire clk,
input wire rst,
/*
* Ethernet frame input
*/
input wire s_eth_hdr_valid,
output wire s_eth_hdr_ready,
input wire [47:0] s_eth_dest_mac,
input wire [47:0] s_eth_src_mac,
input wire [15:0] s_eth_type,
input wire [63:0] s_eth_payload_axis_tdata,
input wire [7:0] s_eth_payload_axis_tkeep,
input wire s_eth_payload_axis_tvalid,
output wire s_eth_payload_axis_tready,
input wire s_eth_payload_axis_tlast,
input wire s_eth_payload_axis_tuser,
/*
* Ethernet frame output
*/
output wire m_eth_hdr_valid,
input wire m_eth_hdr_ready,
output wire [47:0] m_eth_dest_mac,
output wire [47:0] m_eth_src_mac,
output wire [15:0] m_eth_type,
output wire [63:0] m_eth_payload_axis_tdata,
output wire [7:0] m_eth_payload_axis_tkeep,
output wire m_eth_payload_axis_tvalid,
input wire m_eth_payload_axis_tready,
output wire m_eth_payload_axis_tlast,
output wire m_eth_payload_axis_tuser,
/*
* IP input
*/
input wire s_ip_hdr_valid,
output wire s_ip_hdr_ready,
input wire [5:0] s_ip_dscp,
input wire [1:0] s_ip_ecn,
input wire [15:0] s_ip_length,
input wire [7:0] s_ip_ttl,
input wire [7:0] s_ip_protocol,
input wire [31:0] s_ip_source_ip,
input wire [31:0] s_ip_dest_ip,
input wire [63:0] s_ip_payload_axis_tdata,
input wire [7:0] s_ip_payload_axis_tkeep,
input wire s_ip_payload_axis_tvalid,
output wire s_ip_payload_axis_tready,
input wire s_ip_payload_axis_tlast,
input wire s_ip_payload_axis_tuser,
/*
* IP output
*/
output wire m_ip_hdr_valid,
input wire m_ip_hdr_ready,
output wire [47:0] m_ip_eth_dest_mac,
output wire [47:0] m_ip_eth_src_mac,
output wire [15:0] m_ip_eth_type,
output wire [3:0] m_ip_version,
output wire [3:0] m_ip_ihl,
output wire [5:0] m_ip_dscp,
output wire [1:0] m_ip_ecn,
output wire [15:0] m_ip_length,
output wire [15:0] m_ip_identification,
output wire [2:0] m_ip_flags,
output wire [12:0] m_ip_fragment_offset,
output wire [7:0] m_ip_ttl,
output wire [7:0] m_ip_protocol,
output wire [15:0] m_ip_header_checksum,
output wire [31:0] m_ip_source_ip,
output wire [31:0] m_ip_dest_ip,
output wire [63:0] m_ip_payload_axis_tdata,
output wire [7:0] m_ip_payload_axis_tkeep,
output wire m_ip_payload_axis_tvalid,
input wire m_ip_payload_axis_tready,
output wire m_ip_payload_axis_tlast,
output wire m_ip_payload_axis_tuser,
/*
* Status
*/
output wire rx_busy,
output wire tx_busy,
output wire rx_error_header_early_termination,
output wire rx_error_payload_early_termination,
output wire rx_error_invalid_header,
output wire rx_error_invalid_checksum,
output wire tx_error_payload_early_termination,
output wire tx_error_arp_failed,
/*
* Configuration
*/
input wire [47:0] local_mac,
input wire [31:0] local_ip,
input wire [31:0] gateway_ip,
input wire [31:0] subnet_mask,
input wire clear_arp_cache
);
/*
This module integrates the IP and ARP modules for a complete IP stack
*/
wire arp_request_valid;
wire arp_request_ready;
wire [31:0] arp_request_ip;
wire arp_response_valid;
wire arp_response_ready;
wire arp_response_error;
wire [47:0] arp_response_mac;
wire ip_rx_eth_hdr_valid;
wire ip_rx_eth_hdr_ready;
wire [47:0] ip_rx_eth_dest_mac;
wire [47:0] ip_rx_eth_src_mac;
wire [15:0] ip_rx_eth_type;
wire [63:0] ip_rx_eth_payload_axis_tdata;
wire [7:0] ip_rx_eth_payload_axis_tkeep;
wire ip_rx_eth_payload_axis_tvalid;
wire ip_rx_eth_payload_axis_tready;
wire ip_rx_eth_payload_axis_tlast;
wire ip_rx_eth_payload_axis_tuser;
wire ip_tx_eth_hdr_valid;
wire ip_tx_eth_hdr_ready;
wire [47:0] ip_tx_eth_dest_mac;
wire [47:0] ip_tx_eth_src_mac;
wire [15:0] ip_tx_eth_type;
wire [63:0] ip_tx_eth_payload_axis_tdata;
wire [7:0] ip_tx_eth_payload_axis_tkeep;
wire ip_tx_eth_payload_axis_tvalid;
wire ip_tx_eth_payload_axis_tready;
wire ip_tx_eth_payload_axis_tlast;
wire ip_tx_eth_payload_axis_tuser;
wire arp_rx_eth_hdr_valid;
wire arp_rx_eth_hdr_ready;
wire [47:0] arp_rx_eth_dest_mac;
wire [47:0] arp_rx_eth_src_mac;
wire [15:0] arp_rx_eth_type;
wire [63:0] arp_rx_eth_payload_axis_tdata;
wire [7:0] arp_rx_eth_payload_axis_tkeep;
wire arp_rx_eth_payload_axis_tvalid;
wire arp_rx_eth_payload_axis_tready;
wire arp_rx_eth_payload_axis_tlast;
wire arp_rx_eth_payload_axis_tuser;
wire arp_tx_eth_hdr_valid;
wire arp_tx_eth_hdr_ready;
wire [47:0] arp_tx_eth_dest_mac;
wire [47:0] arp_tx_eth_src_mac;
wire [15:0] arp_tx_eth_type;
wire [63:0] arp_tx_eth_payload_axis_tdata;
wire [7:0] arp_tx_eth_payload_axis_tkeep;
wire arp_tx_eth_payload_axis_tvalid;
wire arp_tx_eth_payload_axis_tready;
wire arp_tx_eth_payload_axis_tlast;
wire arp_tx_eth_payload_axis_tuser;
/*
* Input classifier (eth_type)
*/
wire s_select_ip = (s_eth_type == 16'h0800);
wire s_select_arp = (s_eth_type == 16'h0806);
wire s_select_none = !(s_select_ip || s_select_arp);
reg s_select_ip_reg = 1'b0;
reg s_select_arp_reg = 1'b0;
reg s_select_none_reg = 1'b0;
always @(posedge clk) begin
if (rst) begin
s_select_ip_reg <= 1'b0;
s_select_arp_reg <= 1'b0;
s_select_none_reg <= 1'b0;
end else begin
if (s_eth_payload_axis_tvalid) begin
if ((!s_select_ip_reg && !s_select_arp_reg && !s_select_none_reg) ||
(s_eth_payload_axis_tvalid && s_eth_payload_axis_tready && s_eth_payload_axis_tlast)) begin
s_select_ip_reg <= s_select_ip;
s_select_arp_reg <= s_select_arp;
s_select_none_reg <= s_select_none;
end
end else begin
s_select_ip_reg <= 1'b0;
s_select_arp_reg <= 1'b0;
s_select_none_reg <= 1'b0;
end
end
end
assign ip_rx_eth_hdr_valid = s_select_ip && s_eth_hdr_valid;
assign ip_rx_eth_dest_mac = s_eth_dest_mac;
assign ip_rx_eth_src_mac = s_eth_src_mac;
assign ip_rx_eth_type = 16'h0800;
assign ip_rx_eth_payload_axis_tdata = s_eth_payload_axis_tdata;
assign ip_rx_eth_payload_axis_tkeep = s_eth_payload_axis_tkeep;
assign ip_rx_eth_payload_axis_tvalid = s_select_ip_reg && s_eth_payload_axis_tvalid;
assign ip_rx_eth_payload_axis_tlast = s_eth_payload_axis_tlast;
assign ip_rx_eth_payload_axis_tuser = s_eth_payload_axis_tuser;
assign arp_rx_eth_hdr_valid = s_select_arp && s_eth_hdr_valid;
assign arp_rx_eth_dest_mac = s_eth_dest_mac;
assign arp_rx_eth_src_mac = s_eth_src_mac;
assign arp_rx_eth_type = 16'h0806;
assign arp_rx_eth_payload_axis_tdata = s_eth_payload_axis_tdata;
assign arp_rx_eth_payload_axis_tkeep = s_eth_payload_axis_tkeep;
assign arp_rx_eth_payload_axis_tvalid = s_select_arp_reg && s_eth_payload_axis_tvalid;
assign arp_rx_eth_payload_axis_tlast = s_eth_payload_axis_tlast;
assign arp_rx_eth_payload_axis_tuser = s_eth_payload_axis_tuser;
assign s_eth_hdr_ready = (s_select_ip && ip_rx_eth_hdr_ready) ||
(s_select_arp && arp_rx_eth_hdr_ready) ||
(s_select_none);
assign s_eth_payload_axis_tready = (s_select_ip_reg && ip_rx_eth_payload_axis_tready) ||
(s_select_arp_reg && arp_rx_eth_payload_axis_tready) ||
s_select_none_reg;
/*
* Output arbiter
*/
eth_arb_mux #(
.S_COUNT(2),
.DATA_WIDTH(64),
.KEEP_ENABLE(1),
.ID_ENABLE(0),
.DEST_ENABLE(0),
.USER_ENABLE(1),
.USER_WIDTH(1),
.ARB_TYPE("PRIORITY"),
.LSB_PRIORITY("HIGH")
)
eth_arb_mux_inst (
.clk(clk),
.rst(rst),
// Ethernet frame inputs
.s_eth_hdr_valid({ip_tx_eth_hdr_valid, arp_tx_eth_hdr_valid}),
.s_eth_hdr_ready({ip_tx_eth_hdr_ready, arp_tx_eth_hdr_ready}),
.s_eth_dest_mac({ip_tx_eth_dest_mac, arp_tx_eth_dest_mac}),
.s_eth_src_mac({ip_tx_eth_src_mac, arp_tx_eth_src_mac}),
.s_eth_type({ip_tx_eth_type, arp_tx_eth_type}),
.s_eth_payload_axis_tdata({ip_tx_eth_payload_axis_tdata, arp_tx_eth_payload_axis_tdata}),
.s_eth_payload_axis_tkeep({ip_tx_eth_payload_axis_tkeep, arp_tx_eth_payload_axis_tkeep}),
.s_eth_payload_axis_tvalid({ip_tx_eth_payload_axis_tvalid, arp_tx_eth_payload_axis_tvalid}),
.s_eth_payload_axis_tready({ip_tx_eth_payload_axis_tready, arp_tx_eth_payload_axis_tready}),
.s_eth_payload_axis_tlast({ip_tx_eth_payload_axis_tlast, arp_tx_eth_payload_axis_tlast}),
.s_eth_payload_axis_tid(0),
.s_eth_payload_axis_tdest(0),
.s_eth_payload_axis_tuser({ip_tx_eth_payload_axis_tuser, arp_tx_eth_payload_axis_tuser}),
// Ethernet frame output
.m_eth_hdr_valid(m_eth_hdr_valid),
.m_eth_hdr_ready(m_eth_hdr_ready),
.m_eth_dest_mac(m_eth_dest_mac),
.m_eth_src_mac(m_eth_src_mac),
.m_eth_type(m_eth_type),
.m_eth_payload_axis_tdata(m_eth_payload_axis_tdata),
.m_eth_payload_axis_tkeep(m_eth_payload_axis_tkeep),
.m_eth_payload_axis_tvalid(m_eth_payload_axis_tvalid),
.m_eth_payload_axis_tready(m_eth_payload_axis_tready),
.m_eth_payload_axis_tlast(m_eth_payload_axis_tlast),
.m_eth_payload_axis_tid(),
.m_eth_payload_axis_tdest(),
.m_eth_payload_axis_tuser(m_eth_payload_axis_tuser)
);
/*
* IP module
*/
ip_64
ip_inst (
.clk(clk),
.rst(rst),
// Ethernet frame input
.s_eth_hdr_valid(ip_rx_eth_hdr_valid),
.s_eth_hdr_ready(ip_rx_eth_hdr_ready),
.s_eth_dest_mac(ip_rx_eth_dest_mac),
.s_eth_src_mac(ip_rx_eth_src_mac),
.s_eth_type(ip_rx_eth_type),
.s_eth_payload_axis_tdata(ip_rx_eth_payload_axis_tdata),
.s_eth_payload_axis_tkeep(ip_rx_eth_payload_axis_tkeep),
.s_eth_payload_axis_tvalid(ip_rx_eth_payload_axis_tvalid),
.s_eth_payload_axis_tready(ip_rx_eth_payload_axis_tready),
.s_eth_payload_axis_tlast(ip_rx_eth_payload_axis_tlast),
.s_eth_payload_axis_tuser(ip_rx_eth_payload_axis_tuser),
// Ethernet frame output
.m_eth_hdr_valid(ip_tx_eth_hdr_valid),
.m_eth_hdr_ready(ip_tx_eth_hdr_ready),
.m_eth_dest_mac(ip_tx_eth_dest_mac),
.m_eth_src_mac(ip_tx_eth_src_mac),
.m_eth_type(ip_tx_eth_type),
.m_eth_payload_axis_tdata(ip_tx_eth_payload_axis_tdata),
.m_eth_payload_axis_tkeep(ip_tx_eth_payload_axis_tkeep),
.m_eth_payload_axis_tvalid(ip_tx_eth_payload_axis_tvalid),
.m_eth_payload_axis_tready(ip_tx_eth_payload_axis_tready),
.m_eth_payload_axis_tlast(ip_tx_eth_payload_axis_tlast),
.m_eth_payload_axis_tuser(ip_tx_eth_payload_axis_tuser),
// IP frame output
.m_ip_hdr_valid(m_ip_hdr_valid),
.m_ip_hdr_ready(m_ip_hdr_ready),
.m_ip_eth_dest_mac(m_ip_eth_dest_mac),
.m_ip_eth_src_mac(m_ip_eth_src_mac),
.m_ip_eth_type(m_ip_eth_type),
.m_ip_version(m_ip_version),
.m_ip_ihl(m_ip_ihl),
.m_ip_dscp(m_ip_dscp),
.m_ip_ecn(m_ip_ecn),
.m_ip_length(m_ip_length),
.m_ip_identification(m_ip_identification),
.m_ip_flags(m_ip_flags),
.m_ip_fragment_offset(m_ip_fragment_offset),
.m_ip_ttl(m_ip_ttl),
.m_ip_protocol(m_ip_protocol),
.m_ip_header_checksum(m_ip_header_checksum),
.m_ip_source_ip(m_ip_source_ip),
.m_ip_dest_ip(m_ip_dest_ip),
.m_ip_payload_axis_tdata(m_ip_payload_axis_tdata),
.m_ip_payload_axis_tkeep(m_ip_payload_axis_tkeep),
.m_ip_payload_axis_tvalid(m_ip_payload_axis_tvalid),
.m_ip_payload_axis_tready(m_ip_payload_axis_tready),
.m_ip_payload_axis_tlast(m_ip_payload_axis_tlast),
.m_ip_payload_axis_tuser(m_ip_payload_axis_tuser),
// IP frame input
.s_ip_hdr_valid(s_ip_hdr_valid),
.s_ip_hdr_ready(s_ip_hdr_ready),
.s_ip_dscp(s_ip_dscp),
.s_ip_ecn(s_ip_ecn),
.s_ip_length(s_ip_length),
.s_ip_ttl(s_ip_ttl),
.s_ip_protocol(s_ip_protocol),
.s_ip_source_ip(s_ip_source_ip),
.s_ip_dest_ip(s_ip_dest_ip),
.s_ip_payload_axis_tdata(s_ip_payload_axis_tdata),
.s_ip_payload_axis_tkeep(s_ip_payload_axis_tkeep),
.s_ip_payload_axis_tvalid(s_ip_payload_axis_tvalid),
.s_ip_payload_axis_tready(s_ip_payload_axis_tready),
.s_ip_payload_axis_tlast(s_ip_payload_axis_tlast),
.s_ip_payload_axis_tuser(s_ip_payload_axis_tuser),
// ARP requests
.arp_request_valid(arp_request_valid),
.arp_request_ready(arp_request_ready),
.arp_request_ip(arp_request_ip),
.arp_response_valid(arp_response_valid),
.arp_response_ready(arp_response_ready),
.arp_response_error(arp_response_error),
.arp_response_mac(arp_response_mac),
// Status
.rx_busy(rx_busy),
.tx_busy(tx_busy),
.rx_error_header_early_termination(rx_error_header_early_termination),
.rx_error_payload_early_termination(rx_error_payload_early_termination),
.rx_error_invalid_header(rx_error_invalid_header),
.rx_error_invalid_checksum(rx_error_invalid_checksum),
.tx_error_payload_early_termination(tx_error_payload_early_termination),
.tx_error_arp_failed(tx_error_arp_failed),
// Configuration
.local_mac(local_mac),
.local_ip(local_ip)
);
/*
* ARP module
*/
arp #(
.DATA_WIDTH(64),
.KEEP_ENABLE(1),
.KEEP_WIDTH(8),
.CACHE_ADDR_WIDTH(ARP_CACHE_ADDR_WIDTH),
.REQUEST_RETRY_COUNT(ARP_REQUEST_RETRY_COUNT),
.REQUEST_RETRY_INTERVAL(ARP_REQUEST_RETRY_INTERVAL),
.REQUEST_TIMEOUT(ARP_REQUEST_TIMEOUT)
)
arp_inst (
.clk(clk),
.rst(rst),
// Ethernet frame input
.s_eth_hdr_valid(arp_rx_eth_hdr_valid),
.s_eth_hdr_ready(arp_rx_eth_hdr_ready),
.s_eth_dest_mac(arp_rx_eth_dest_mac),
.s_eth_src_mac(arp_rx_eth_src_mac),
.s_eth_type(arp_rx_eth_type),
.s_eth_payload_axis_tdata(arp_rx_eth_payload_axis_tdata),
.s_eth_payload_axis_tkeep(arp_rx_eth_payload_axis_tkeep),
.s_eth_payload_axis_tvalid(arp_rx_eth_payload_axis_tvalid),
.s_eth_payload_axis_tready(arp_rx_eth_payload_axis_tready),
.s_eth_payload_axis_tlast(arp_rx_eth_payload_axis_tlast),
.s_eth_payload_axis_tuser(arp_rx_eth_payload_axis_tuser),
// Ethernet frame output
.m_eth_hdr_valid(arp_tx_eth_hdr_valid),
.m_eth_hdr_ready(arp_tx_eth_hdr_ready),
.m_eth_dest_mac(arp_tx_eth_dest_mac),
.m_eth_src_mac(arp_tx_eth_src_mac),
.m_eth_type(arp_tx_eth_type),
.m_eth_payload_axis_tdata(arp_tx_eth_payload_axis_tdata),
.m_eth_payload_axis_tkeep(arp_tx_eth_payload_axis_tkeep),
.m_eth_payload_axis_tvalid(arp_tx_eth_payload_axis_tvalid),
.m_eth_payload_axis_tready(arp_tx_eth_payload_axis_tready),
.m_eth_payload_axis_tlast(arp_tx_eth_payload_axis_tlast),
.m_eth_payload_axis_tuser(arp_tx_eth_payload_axis_tuser),
// ARP requests
.arp_request_valid(arp_request_valid),
.arp_request_ready(arp_request_ready),
.arp_request_ip(arp_request_ip),
.arp_response_valid(arp_response_valid),
.arp_response_ready(arp_response_ready),
.arp_response_error(arp_response_error),
.arp_response_mac(arp_response_mac),
// Configuration
.local_mac(local_mac),
.local_ip(local_ip),
.gateway_ip(gateway_ip),
.subnet_mask(subnet_mask),
.clear_cache(clear_arp_cache)
);
endmodule
/*
Copyright (c) 2018 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* IP demultiplexer
*/
module ip_demux #
(
parameter M_COUNT = 4,
parameter DATA_WIDTH = 8,
parameter KEEP_ENABLE = (DATA_WIDTH>8),
parameter KEEP_WIDTH = (DATA_WIDTH/8),
parameter ID_ENABLE = 0,
parameter ID_WIDTH = 8,
parameter DEST_ENABLE = 0,
parameter DEST_WIDTH = 8,
parameter USER_ENABLE = 1,
parameter USER_WIDTH = 1
)
(
input wire clk,
input wire rst,
/*
* IP frame input
*/
input wire s_ip_hdr_valid,
output wire s_ip_hdr_ready,
input wire [47:0] s_eth_dest_mac,
input wire [47:0] s_eth_src_mac,
input wire [15:0] s_eth_type,
input wire [3:0] s_ip_version,
input wire [3:0] s_ip_ihl,
input wire [5:0] s_ip_dscp,
input wire [1:0] s_ip_ecn,
input wire [15:0] s_ip_length,
input wire [15:0] s_ip_identification,
input wire [2:0] s_ip_flags,
input wire [12:0] s_ip_fragment_offset,
input wire [7:0] s_ip_ttl,
input wire [7:0] s_ip_protocol,
input wire [15:0] s_ip_header_checksum,
input wire [31:0] s_ip_source_ip,
input wire [31:0] s_ip_dest_ip,
input wire [DATA_WIDTH-1:0] s_ip_payload_axis_tdata,
input wire [KEEP_WIDTH-1:0] s_ip_payload_axis_tkeep,
input wire s_ip_payload_axis_tvalid,
output wire s_ip_payload_axis_tready,
input wire s_ip_payload_axis_tlast,
input wire [ID_WIDTH-1:0] s_ip_payload_axis_tid,
input wire [DEST_WIDTH-1:0] s_ip_payload_axis_tdest,
input wire [USER_WIDTH-1:0] s_ip_payload_axis_tuser,
/*
* IP frame outputs
*/
output wire [M_COUNT-1:0] m_ip_hdr_valid,
input wire [M_COUNT-1:0] m_ip_hdr_ready,
output wire [M_COUNT*48-1:0] m_eth_dest_mac,
output wire [M_COUNT*48-1:0] m_eth_src_mac,
output wire [M_COUNT*16-1:0] m_eth_type,
output wire [M_COUNT*4-1:0] m_ip_version,
output wire [M_COUNT*4-1:0] m_ip_ihl,
output wire [M_COUNT*6-1:0] m_ip_dscp,
output wire [M_COUNT*2-1:0] m_ip_ecn,
output wire [M_COUNT*16-1:0] m_ip_length,
output wire [M_COUNT*16-1:0] m_ip_identification,
output wire [M_COUNT*3-1:0] m_ip_flags,
output wire [M_COUNT*13-1:0] m_ip_fragment_offset,
output wire [M_COUNT*8-1:0] m_ip_ttl,
output wire [M_COUNT*8-1:0] m_ip_protocol,
output wire [M_COUNT*16-1:0] m_ip_header_checksum,
output wire [M_COUNT*32-1:0] m_ip_source_ip,
output wire [M_COUNT*32-1:0] m_ip_dest_ip,
output wire [M_COUNT*DATA_WIDTH-1:0] m_ip_payload_axis_tdata,
output wire [M_COUNT*KEEP_WIDTH-1:0] m_ip_payload_axis_tkeep,
output wire [M_COUNT-1:0] m_ip_payload_axis_tvalid,
input wire [M_COUNT-1:0] m_ip_payload_axis_tready,
output wire [M_COUNT-1:0] m_ip_payload_axis_tlast,
output wire [M_COUNT*ID_WIDTH-1:0] m_ip_payload_axis_tid,
output wire [M_COUNT*DEST_WIDTH-1:0] m_ip_payload_axis_tdest,
output wire [M_COUNT*USER_WIDTH-1:0] m_ip_payload_axis_tuser,
/*
* Control
*/
input wire enable,
input wire drop,
input wire [$clog2(M_COUNT)-1:0] select
);
parameter CL_M_COUNT = $clog2(M_COUNT);
reg [CL_M_COUNT-1:0] select_reg = {CL_M_COUNT{1'b0}}, select_ctl, select_next;
reg drop_reg = 1'b0, drop_ctl, drop_next;
reg frame_reg = 1'b0, frame_ctl, frame_next;
reg s_ip_hdr_ready_reg = 1'b0, s_ip_hdr_ready_next;
reg s_ip_payload_axis_tready_reg = 1'b0, s_ip_payload_axis_tready_next;
reg [M_COUNT-1:0] m_ip_hdr_valid_reg = 0, m_ip_hdr_valid_next;
reg [47:0] m_eth_dest_mac_reg = 48'd0, m_eth_dest_mac_next;
reg [47:0] m_eth_src_mac_reg = 48'd0, m_eth_src_mac_next;
reg [15:0] m_eth_type_reg = 16'd0, m_eth_type_next;
reg [3:0] m_ip_version_reg = 4'd0, m_ip_version_next;
reg [3:0] m_ip_ihl_reg = 4'd0, m_ip_ihl_next;
reg [5:0] m_ip_dscp_reg = 6'd0, m_ip_dscp_next;
reg [1:0] m_ip_ecn_reg = 2'd0, m_ip_ecn_next;
reg [15:0] m_ip_length_reg = 16'd0, m_ip_length_next;
reg [15:0] m_ip_identification_reg = 16'd0, m_ip_identification_next;
reg [2:0] m_ip_flags_reg = 3'd0, m_ip_flags_next;
reg [12:0] m_ip_fragment_offset_reg = 13'd0, m_ip_fragment_offset_next;
reg [7:0] m_ip_ttl_reg = 8'd0, m_ip_ttl_next;
reg [7:0] m_ip_protocol_reg = 8'd0, m_ip_protocol_next;
reg [15:0] m_ip_header_checksum_reg = 16'd0, m_ip_header_checksum_next;
reg [31:0] m_ip_source_ip_reg = 32'd0, m_ip_source_ip_next;
reg [31:0] m_ip_dest_ip_reg = 32'd0, m_ip_dest_ip_next;
// internal datapath
reg [DATA_WIDTH-1:0] m_ip_payload_axis_tdata_int;
reg [KEEP_WIDTH-1:0] m_ip_payload_axis_tkeep_int;
reg [M_COUNT-1:0] m_ip_payload_axis_tvalid_int;
reg m_ip_payload_axis_tready_int_reg = 1'b0;
reg m_ip_payload_axis_tlast_int;
reg [ID_WIDTH-1:0] m_ip_payload_axis_tid_int;
reg [DEST_WIDTH-1:0] m_ip_payload_axis_tdest_int;
reg [USER_WIDTH-1:0] m_ip_payload_axis_tuser_int;
wire m_ip_payload_axis_tready_int_early;
assign s_ip_hdr_ready = s_ip_hdr_ready_reg && enable;
assign s_ip_payload_axis_tready = s_ip_payload_axis_tready_reg && enable;
assign m_ip_hdr_valid = m_ip_hdr_valid_reg;
assign m_eth_dest_mac = {M_COUNT{m_eth_dest_mac_reg}};
assign m_eth_src_mac = {M_COUNT{m_eth_src_mac_reg}};
assign m_eth_type = {M_COUNT{m_eth_type_reg}};
assign m_ip_version = {M_COUNT{m_ip_version_reg}};
assign m_ip_ihl = {M_COUNT{m_ip_ihl_reg}};
assign m_ip_dscp = {M_COUNT{m_ip_dscp_reg}};
assign m_ip_ecn = {M_COUNT{m_ip_ecn_reg}};
assign m_ip_length = {M_COUNT{m_ip_length_reg}};
assign m_ip_identification = {M_COUNT{m_ip_identification_reg}};
assign m_ip_flags = {M_COUNT{m_ip_flags_reg}};
assign m_ip_fragment_offset = {M_COUNT{m_ip_fragment_offset_reg}};
assign m_ip_ttl = {M_COUNT{m_ip_ttl_reg}};
assign m_ip_protocol = {M_COUNT{m_ip_protocol_reg}};
assign m_ip_header_checksum = {M_COUNT{m_ip_header_checksum_reg}};
assign m_ip_source_ip = {M_COUNT{m_ip_source_ip_reg}};
assign m_ip_dest_ip = {M_COUNT{m_ip_dest_ip_reg}};
integer i;
always @* begin
select_next = select_reg;
select_ctl = select_reg;
drop_next = drop_reg;
drop_ctl = drop_reg;
frame_next = frame_reg;
frame_ctl = frame_reg;
s_ip_hdr_ready_next = 1'b0;
s_ip_payload_axis_tready_next = 1'b0;
m_ip_hdr_valid_next = m_ip_hdr_valid_reg & ~m_ip_hdr_ready;
m_eth_dest_mac_next = m_eth_dest_mac_reg;
m_eth_src_mac_next = m_eth_src_mac_reg;
m_eth_type_next = m_eth_type_reg;
m_ip_version_next = m_ip_version_reg;
m_ip_ihl_next = m_ip_ihl_reg;
m_ip_dscp_next = m_ip_dscp_reg;
m_ip_ecn_next = m_ip_ecn_reg;
m_ip_length_next = m_ip_length_reg;
m_ip_identification_next = m_ip_identification_reg;
m_ip_flags_next = m_ip_flags_reg;
m_ip_fragment_offset_next = m_ip_fragment_offset_reg;
m_ip_ttl_next = m_ip_ttl_reg;
m_ip_protocol_next = m_ip_protocol_reg;
m_ip_header_checksum_next = m_ip_header_checksum_reg;
m_ip_source_ip_next = m_ip_source_ip_reg;
m_ip_dest_ip_next = m_ip_dest_ip_reg;
if (s_ip_payload_axis_tvalid && s_ip_payload_axis_tready) begin
// end of frame detection
if (s_ip_payload_axis_tlast) begin
frame_next = 1'b0;
drop_next = 1'b0;
end
end
if (!frame_reg && s_ip_hdr_valid && s_ip_hdr_ready) begin
// start of frame, grab select value
select_ctl = select;
drop_ctl = drop;
frame_ctl = 1'b1;
select_next = select_ctl;
drop_next = drop_ctl;
frame_next = frame_ctl;
s_ip_hdr_ready_next = 1'b0;
m_ip_hdr_valid_next = (!drop_ctl) << select_ctl;
m_eth_dest_mac_next = s_eth_dest_mac;
m_eth_src_mac_next = s_eth_src_mac;
m_eth_type_next = s_eth_type;
m_ip_version_next = s_ip_version;
m_ip_ihl_next = s_ip_ihl;
m_ip_dscp_next = s_ip_dscp;
m_ip_ecn_next = s_ip_ecn;
m_ip_length_next = s_ip_length;
m_ip_identification_next = s_ip_identification;
m_ip_flags_next = s_ip_flags;
m_ip_fragment_offset_next = s_ip_fragment_offset;
m_ip_ttl_next = s_ip_ttl;
m_ip_protocol_next = s_ip_protocol;
m_ip_header_checksum_next = s_ip_header_checksum;
m_ip_source_ip_next = s_ip_source_ip;
m_ip_dest_ip_next = s_ip_dest_ip;
end
s_ip_hdr_ready_next = !frame_next && !m_ip_hdr_valid_next;
s_ip_payload_axis_tready_next = (m_ip_payload_axis_tready_int_early || drop_ctl) && frame_ctl;
m_ip_payload_axis_tdata_int = s_ip_payload_axis_tdata;
m_ip_payload_axis_tkeep_int = s_ip_payload_axis_tkeep;
m_ip_payload_axis_tvalid_int = (s_ip_payload_axis_tvalid && s_ip_payload_axis_tready && !drop_ctl) << select_ctl;
m_ip_payload_axis_tlast_int = s_ip_payload_axis_tlast;
m_ip_payload_axis_tid_int = s_ip_payload_axis_tid;
m_ip_payload_axis_tdest_int = s_ip_payload_axis_tdest;
m_ip_payload_axis_tuser_int = s_ip_payload_axis_tuser;
end
always @(posedge clk) begin
if (rst) begin
select_reg <= 2'd0;
drop_reg <= 1'b0;
frame_reg <= 1'b0;
s_ip_hdr_ready_reg <= 1'b0;
s_ip_payload_axis_tready_reg <= 1'b0;
m_ip_hdr_valid_reg <= 0;
end else begin
select_reg <= select_next;
drop_reg <= drop_next;
frame_reg <= frame_next;
s_ip_hdr_ready_reg <= s_ip_hdr_ready_next;
s_ip_payload_axis_tready_reg <= s_ip_payload_axis_tready_next;
m_ip_hdr_valid_reg <= m_ip_hdr_valid_next;
end
m_eth_dest_mac_reg <= m_eth_dest_mac_next;
m_eth_src_mac_reg <= m_eth_src_mac_next;
m_eth_type_reg <= m_eth_type_next;
m_ip_version_reg <= m_ip_version_next;
m_ip_ihl_reg <= m_ip_ihl_next;
m_ip_dscp_reg <= m_ip_dscp_next;
m_ip_ecn_reg <= m_ip_ecn_next;
m_ip_length_reg <= m_ip_length_next;
m_ip_identification_reg <= m_ip_identification_next;
m_ip_flags_reg <= m_ip_flags_next;
m_ip_fragment_offset_reg <= m_ip_fragment_offset_next;
m_ip_ttl_reg <= m_ip_ttl_next;
m_ip_protocol_reg <= m_ip_protocol_next;
m_ip_header_checksum_reg <= m_ip_header_checksum_next;
m_ip_source_ip_reg <= m_ip_source_ip_next;
m_ip_dest_ip_reg <= m_ip_dest_ip_next;
end
// output datapath logic
reg [DATA_WIDTH-1:0] m_ip_payload_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] m_ip_payload_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
reg [M_COUNT-1:0] m_ip_payload_axis_tvalid_reg = {M_COUNT{1'b0}}, m_ip_payload_axis_tvalid_next;
reg m_ip_payload_axis_tlast_reg = 1'b0;
reg [ID_WIDTH-1:0] m_ip_payload_axis_tid_reg = {ID_WIDTH{1'b0}};
reg [DEST_WIDTH-1:0] m_ip_payload_axis_tdest_reg = {DEST_WIDTH{1'b0}};
reg [USER_WIDTH-1:0] m_ip_payload_axis_tuser_reg = {USER_WIDTH{1'b0}};
reg [DATA_WIDTH-1:0] temp_m_ip_payload_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] temp_m_ip_payload_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
reg [M_COUNT-1:0] temp_m_ip_payload_axis_tvalid_reg = {M_COUNT{1'b0}}, temp_m_ip_payload_axis_tvalid_next;
reg temp_m_ip_payload_axis_tlast_reg = 1'b0;
reg [ID_WIDTH-1:0] temp_m_ip_payload_axis_tid_reg = {ID_WIDTH{1'b0}};
reg [DEST_WIDTH-1:0] temp_m_ip_payload_axis_tdest_reg = {DEST_WIDTH{1'b0}};
reg [USER_WIDTH-1:0] temp_m_ip_payload_axis_tuser_reg = {USER_WIDTH{1'b0}};
// datapath control
reg store_axis_int_to_output;
reg store_axis_int_to_temp;
reg store_ip_payload_axis_temp_to_output;
assign m_ip_payload_axis_tdata = {M_COUNT{m_ip_payload_axis_tdata_reg}};
assign m_ip_payload_axis_tkeep = KEEP_ENABLE ? {M_COUNT{m_ip_payload_axis_tkeep_reg}} : {M_COUNT*KEEP_WIDTH{1'b1}};
assign m_ip_payload_axis_tvalid = m_ip_payload_axis_tvalid_reg;
assign m_ip_payload_axis_tlast = {M_COUNT{m_ip_payload_axis_tlast_reg}};
assign m_ip_payload_axis_tid = ID_ENABLE ? {M_COUNT{m_ip_payload_axis_tid_reg}} : {M_COUNT*ID_WIDTH{1'b0}};
assign m_ip_payload_axis_tdest = DEST_ENABLE ? {M_COUNT{m_ip_payload_axis_tdest_reg}} : {M_COUNT*DEST_WIDTH{1'b0}};
assign m_ip_payload_axis_tuser = USER_ENABLE ? {M_COUNT{m_ip_payload_axis_tuser_reg}} : {M_COUNT*USER_WIDTH{1'b0}};
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
assign m_ip_payload_axis_tready_int_early = (m_ip_payload_axis_tready & m_ip_payload_axis_tvalid) || (!temp_m_ip_payload_axis_tvalid_reg && (!m_ip_payload_axis_tvalid || !m_ip_payload_axis_tvalid_int));
always @* begin
// transfer sink ready state to source
m_ip_payload_axis_tvalid_next = m_ip_payload_axis_tvalid_reg;
temp_m_ip_payload_axis_tvalid_next = temp_m_ip_payload_axis_tvalid_reg;
store_axis_int_to_output = 1'b0;
store_axis_int_to_temp = 1'b0;
store_ip_payload_axis_temp_to_output = 1'b0;
if (m_ip_payload_axis_tready_int_reg) begin
// input is ready
if ((m_ip_payload_axis_tready & m_ip_payload_axis_tvalid) || !m_ip_payload_axis_tvalid) begin
// output is ready or currently not valid, transfer data to output
m_ip_payload_axis_tvalid_next = m_ip_payload_axis_tvalid_int;
store_axis_int_to_output = 1'b1;
end else begin
// output is not ready, store input in temp
temp_m_ip_payload_axis_tvalid_next = m_ip_payload_axis_tvalid_int;
store_axis_int_to_temp = 1'b1;
end
end else if (m_ip_payload_axis_tready & m_ip_payload_axis_tvalid) begin
// input is not ready, but output is ready
m_ip_payload_axis_tvalid_next = temp_m_ip_payload_axis_tvalid_reg;
temp_m_ip_payload_axis_tvalid_next = 1'b0;
store_ip_payload_axis_temp_to_output = 1'b1;
end
end
always @(posedge clk) begin
if (rst) begin
m_ip_payload_axis_tvalid_reg <= {M_COUNT{1'b0}};
m_ip_payload_axis_tready_int_reg <= 1'b0;
temp_m_ip_payload_axis_tvalid_reg <= 1'b0;
end else begin
m_ip_payload_axis_tvalid_reg <= m_ip_payload_axis_tvalid_next;
m_ip_payload_axis_tready_int_reg <= m_ip_payload_axis_tready_int_early;
temp_m_ip_payload_axis_tvalid_reg <= temp_m_ip_payload_axis_tvalid_next;
end
// datapath
if (store_axis_int_to_output) begin
m_ip_payload_axis_tdata_reg <= m_ip_payload_axis_tdata_int;
m_ip_payload_axis_tkeep_reg <= m_ip_payload_axis_tkeep_int;
m_ip_payload_axis_tlast_reg <= m_ip_payload_axis_tlast_int;
m_ip_payload_axis_tid_reg <= m_ip_payload_axis_tid_int;
m_ip_payload_axis_tdest_reg <= m_ip_payload_axis_tdest_int;
m_ip_payload_axis_tuser_reg <= m_ip_payload_axis_tuser_int;
end else if (store_ip_payload_axis_temp_to_output) begin
m_ip_payload_axis_tdata_reg <= temp_m_ip_payload_axis_tdata_reg;
m_ip_payload_axis_tkeep_reg <= temp_m_ip_payload_axis_tkeep_reg;
m_ip_payload_axis_tlast_reg <= temp_m_ip_payload_axis_tlast_reg;
m_ip_payload_axis_tid_reg <= temp_m_ip_payload_axis_tid_reg;
m_ip_payload_axis_tdest_reg <= temp_m_ip_payload_axis_tdest_reg;
m_ip_payload_axis_tuser_reg <= temp_m_ip_payload_axis_tuser_reg;
end
if (store_axis_int_to_temp) begin
temp_m_ip_payload_axis_tdata_reg <= m_ip_payload_axis_tdata_int;
temp_m_ip_payload_axis_tkeep_reg <= m_ip_payload_axis_tkeep_int;
temp_m_ip_payload_axis_tlast_reg <= m_ip_payload_axis_tlast_int;
temp_m_ip_payload_axis_tid_reg <= m_ip_payload_axis_tid_int;
temp_m_ip_payload_axis_tdest_reg <= m_ip_payload_axis_tdest_int;
temp_m_ip_payload_axis_tuser_reg <= m_ip_payload_axis_tuser_int;
end
end
endmodule
/*
Copyright (c) 2014-2018 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* IP ethernet frame receiver (Ethernet frame in, IP frame out)
*/
module ip_eth_rx
(
input wire clk,
input wire rst,
/*
* Ethernet frame input
*/
input wire s_eth_hdr_valid,
output wire s_eth_hdr_ready,
input wire [47:0] s_eth_dest_mac,
input wire [47:0] s_eth_src_mac,
input wire [15:0] s_eth_type,
input wire [7:0] s_eth_payload_axis_tdata,
input wire s_eth_payload_axis_tvalid,
output wire s_eth_payload_axis_tready,
input wire s_eth_payload_axis_tlast,
input wire s_eth_payload_axis_tuser,
/*
* IP frame output
*/
output wire m_ip_hdr_valid,
input wire m_ip_hdr_ready,
output wire [47:0] m_eth_dest_mac,
output wire [47:0] m_eth_src_mac,
output wire [15:0] m_eth_type,
output wire [3:0] m_ip_version,
output wire [3:0] m_ip_ihl,
output wire [5:0] m_ip_dscp,
output wire [1:0] m_ip_ecn,
output wire [15:0] m_ip_length,
output wire [15:0] m_ip_identification,
output wire [2:0] m_ip_flags,
output wire [12:0] m_ip_fragment_offset,
output wire [7:0] m_ip_ttl,
output wire [7:0] m_ip_protocol,
output wire [15:0] m_ip_header_checksum,
output wire [31:0] m_ip_source_ip,
output wire [31:0] m_ip_dest_ip,
output wire [7:0] m_ip_payload_axis_tdata,
output wire m_ip_payload_axis_tvalid,
input wire m_ip_payload_axis_tready,
output wire m_ip_payload_axis_tlast,
output wire m_ip_payload_axis_tuser,
/*
* Status signals
*/
output wire busy,
output wire error_header_early_termination,
output wire error_payload_early_termination,
output wire error_invalid_header,
output wire error_invalid_checksum
);
/*
IP Frame
Field Length
Destination MAC address 6 octets
Source MAC address 6 octets
Ethertype (0x0800) 2 octets
Version (4) 4 bits
IHL (5-15) 4 bits
DSCP (0) 6 bits
ECN (0) 2 bits
length 2 octets
identification (0?) 2 octets
flags (010) 3 bits
fragment offset (0) 13 bits
time to live (64?) 1 octet
protocol 1 octet
header checksum 2 octets
source IP 4 octets
destination IP 4 octets
options (IHL-5)*4 octets
payload length octets
This module receives an Ethernet frame with header fields in parallel and
payload on an AXI stream interface, decodes and strips the IP header fields,
then produces the header fields in parallel along with the IP payload in a
separate AXI stream.
*/
localparam [2:0]
STATE_IDLE = 3'd0,
STATE_READ_HEADER = 3'd1,
STATE_READ_PAYLOAD = 3'd2,
STATE_READ_PAYLOAD_LAST = 3'd3,
STATE_WAIT_LAST = 3'd4;
reg [2:0] state_reg = STATE_IDLE, state_next;
// datapath control signals
reg store_eth_hdr;
reg store_ip_version_ihl;
reg store_ip_dscp_ecn;
reg store_ip_length_0;
reg store_ip_length_1;
reg store_ip_identification_0;
reg store_ip_identification_1;
reg store_ip_flags_fragment_offset_0;
reg store_ip_flags_fragment_offset_1;
reg store_ip_ttl;
reg store_ip_protocol;
reg store_ip_header_checksum_0;
reg store_ip_header_checksum_1;
reg store_ip_source_ip_0;
reg store_ip_source_ip_1;
reg store_ip_source_ip_2;
reg store_ip_source_ip_3;
reg store_ip_dest_ip_0;
reg store_ip_dest_ip_1;
reg store_ip_dest_ip_2;
reg store_ip_dest_ip_3;
reg store_last_word;
reg [5:0] hdr_ptr_reg = 6'd0, hdr_ptr_next;
reg [15:0] word_count_reg = 16'd0, word_count_next;
reg [15:0] hdr_sum_reg = 16'd0, hdr_sum_next;
reg [7:0] last_word_data_reg = 8'd0;
reg s_eth_hdr_ready_reg = 1'b0, s_eth_hdr_ready_next;
reg s_eth_payload_axis_tready_reg = 1'b0, s_eth_payload_axis_tready_next;
reg m_ip_hdr_valid_reg = 1'b0, m_ip_hdr_valid_next;
reg [47:0] m_eth_dest_mac_reg = 48'd0;
reg [47:0] m_eth_src_mac_reg = 48'd0;
reg [15:0] m_eth_type_reg = 16'd0;
reg [3:0] m_ip_version_reg = 4'd0;
reg [3:0] m_ip_ihl_reg = 4'd0;
reg [5:0] m_ip_dscp_reg = 6'd0;
reg [1:0] m_ip_ecn_reg = 2'd0;
reg [15:0] m_ip_length_reg = 16'd0;
reg [15:0] m_ip_identification_reg = 16'd0;
reg [2:0] m_ip_flags_reg = 3'd0;
reg [12:0] m_ip_fragment_offset_reg = 13'd0;
reg [7:0] m_ip_ttl_reg = 8'd0;
reg [7:0] m_ip_protocol_reg = 8'd0;
reg [15:0] m_ip_header_checksum_reg = 16'd0;
reg [31:0] m_ip_source_ip_reg = 32'd0;
reg [31:0] m_ip_dest_ip_reg = 32'd0;
reg busy_reg = 1'b0;
reg error_header_early_termination_reg = 1'b0, error_header_early_termination_next;
reg error_payload_early_termination_reg = 1'b0, error_payload_early_termination_next;
reg error_invalid_header_reg = 1'b0, error_invalid_header_next;
reg error_invalid_checksum_reg = 1'b0, error_invalid_checksum_next;
// internal datapath
reg [7:0] m_ip_payload_axis_tdata_int;
reg m_ip_payload_axis_tvalid_int;
reg m_ip_payload_axis_tready_int_reg = 1'b0;
reg m_ip_payload_axis_tlast_int;
reg m_ip_payload_axis_tuser_int;
wire m_ip_payload_axis_tready_int_early;
assign s_eth_hdr_ready = s_eth_hdr_ready_reg;
assign s_eth_payload_axis_tready = s_eth_payload_axis_tready_reg;
assign m_ip_hdr_valid = m_ip_hdr_valid_reg;
assign m_eth_dest_mac = m_eth_dest_mac_reg;
assign m_eth_src_mac = m_eth_src_mac_reg;
assign m_eth_type = m_eth_type_reg;
assign m_ip_version = m_ip_version_reg;
assign m_ip_ihl = m_ip_ihl_reg;
assign m_ip_dscp = m_ip_dscp_reg;
assign m_ip_ecn = m_ip_ecn_reg;
assign m_ip_length = m_ip_length_reg;
assign m_ip_identification = m_ip_identification_reg;
assign m_ip_flags = m_ip_flags_reg;
assign m_ip_fragment_offset = m_ip_fragment_offset_reg;
assign m_ip_ttl = m_ip_ttl_reg;
assign m_ip_protocol = m_ip_protocol_reg;
assign m_ip_header_checksum = m_ip_header_checksum_reg;
assign m_ip_source_ip = m_ip_source_ip_reg;
assign m_ip_dest_ip = m_ip_dest_ip_reg;
assign busy = busy_reg;
assign error_header_early_termination = error_header_early_termination_reg;
assign error_payload_early_termination = error_payload_early_termination_reg;
assign error_invalid_header = error_invalid_header_reg;
assign error_invalid_checksum = error_invalid_checksum_reg;
function [15:0] add1c16b;
input [15:0] a, b;
reg [16:0] t;
begin
t = a+b;
add1c16b = t[15:0] + t[16];
end
endfunction
always @* begin
state_next = STATE_IDLE;
s_eth_hdr_ready_next = 1'b0;
s_eth_payload_axis_tready_next = 1'b0;
store_eth_hdr = 1'b0;
store_ip_version_ihl = 1'b0;
store_ip_dscp_ecn = 1'b0;
store_ip_length_0 = 1'b0;
store_ip_length_1 = 1'b0;
store_ip_identification_0 = 1'b0;
store_ip_identification_1 = 1'b0;
store_ip_flags_fragment_offset_0 = 1'b0;
store_ip_flags_fragment_offset_1 = 1'b0;
store_ip_ttl = 1'b0;
store_ip_protocol = 1'b0;
store_ip_header_checksum_0 = 1'b0;
store_ip_header_checksum_1 = 1'b0;
store_ip_source_ip_0 = 1'b0;
store_ip_source_ip_1 = 1'b0;
store_ip_source_ip_2 = 1'b0;
store_ip_source_ip_3 = 1'b0;
store_ip_dest_ip_0 = 1'b0;
store_ip_dest_ip_1 = 1'b0;
store_ip_dest_ip_2 = 1'b0;
store_ip_dest_ip_3 = 1'b0;
store_last_word = 1'b0;
hdr_ptr_next = hdr_ptr_reg;
word_count_next = word_count_reg;
hdr_sum_next = hdr_sum_reg;
m_ip_hdr_valid_next = m_ip_hdr_valid_reg && !m_ip_hdr_ready;
error_header_early_termination_next = 1'b0;
error_payload_early_termination_next = 1'b0;
error_invalid_header_next = 1'b0;
error_invalid_checksum_next = 1'b0;
m_ip_payload_axis_tdata_int = 8'd0;
m_ip_payload_axis_tvalid_int = 1'b0;
m_ip_payload_axis_tlast_int = 1'b0;
m_ip_payload_axis_tuser_int = 1'b0;
case (state_reg)
STATE_IDLE: begin
// idle state - wait for header
hdr_ptr_next = 16'd0;
hdr_sum_next = 16'd0;
s_eth_hdr_ready_next = !m_ip_hdr_valid_next;
if (s_eth_hdr_ready && s_eth_hdr_valid) begin
s_eth_hdr_ready_next = 1'b0;
s_eth_payload_axis_tready_next = 1'b1;
store_eth_hdr = 1'b1;
state_next = STATE_READ_HEADER;
end else begin
state_next = STATE_IDLE;
end
end
STATE_READ_HEADER: begin
// read header
s_eth_payload_axis_tready_next = 1'b1;
word_count_next = m_ip_length_reg - 5*4;
if (s_eth_payload_axis_tready && s_eth_payload_axis_tvalid) begin
// word transfer in - store it
hdr_ptr_next = hdr_ptr_reg + 6'd1;
state_next = STATE_READ_HEADER;
if (hdr_ptr_reg[0]) begin
hdr_sum_next = add1c16b(hdr_sum_reg, {8'd0, s_eth_payload_axis_tdata});
end else begin
hdr_sum_next = add1c16b(hdr_sum_reg, {s_eth_payload_axis_tdata, 8'd0});
end
case (hdr_ptr_reg)
6'h00: store_ip_version_ihl = 1'b1;
6'h01: store_ip_dscp_ecn = 1'b1;
6'h02: store_ip_length_1 = 1'b1;
6'h03: store_ip_length_0 = 1'b1;
6'h04: store_ip_identification_1 = 1'b1;
6'h05: store_ip_identification_0 = 1'b1;
6'h06: store_ip_flags_fragment_offset_1 = 1'b1;
6'h07: store_ip_flags_fragment_offset_0 = 1'b1;
6'h08: store_ip_ttl = 1'b1;
6'h09: store_ip_protocol = 1'b1;
6'h0A: store_ip_header_checksum_1 = 1'b1;
6'h0B: store_ip_header_checksum_0 = 1'b1;
6'h0C: store_ip_source_ip_3 = 1'b1;
6'h0D: store_ip_source_ip_2 = 1'b1;
6'h0E: store_ip_source_ip_1 = 1'b1;
6'h0F: store_ip_source_ip_0 = 1'b1;
6'h10: store_ip_dest_ip_3 = 1'b1;
6'h11: store_ip_dest_ip_2 = 1'b1;
6'h12: store_ip_dest_ip_1 = 1'b1;
6'h13: begin
store_ip_dest_ip_0 = 1'b1;
if (m_ip_version_reg != 4'd4 || m_ip_ihl_reg != 4'd5) begin
error_invalid_header_next = 1'b1;
state_next = STATE_WAIT_LAST;
end else if (hdr_sum_next != 16'hffff) begin
error_invalid_checksum_next = 1'b1;
state_next = STATE_WAIT_LAST;
end else begin
m_ip_hdr_valid_next = 1'b1;
s_eth_payload_axis_tready_next = m_ip_payload_axis_tready_int_early;
state_next = STATE_READ_PAYLOAD;
end
end
endcase
if (s_eth_payload_axis_tlast) begin
error_header_early_termination_next = 1'b1;
m_ip_hdr_valid_next = 1'b0;
s_eth_hdr_ready_next = !m_ip_hdr_valid_next;
s_eth_payload_axis_tready_next = 1'b0;
state_next = STATE_IDLE;
end
end else begin
state_next = STATE_READ_HEADER;
end
end
STATE_READ_PAYLOAD: begin
// read payload
s_eth_payload_axis_tready_next = m_ip_payload_axis_tready_int_early;
m_ip_payload_axis_tdata_int = s_eth_payload_axis_tdata;
m_ip_payload_axis_tvalid_int = s_eth_payload_axis_tvalid;
m_ip_payload_axis_tlast_int = s_eth_payload_axis_tlast;
m_ip_payload_axis_tuser_int = s_eth_payload_axis_tuser;
if (s_eth_payload_axis_tready && s_eth_payload_axis_tvalid) begin
// word transfer through
word_count_next = word_count_reg - 16'd1;
if (s_eth_payload_axis_tlast) begin
if (word_count_reg > 16'd1) begin
// end of frame, but length does not match
m_ip_payload_axis_tuser_int = 1'b1;
error_payload_early_termination_next = 1'b1;
end
s_eth_hdr_ready_next = !m_ip_hdr_valid_next;
s_eth_payload_axis_tready_next = 1'b0;
state_next = STATE_IDLE;
end else begin
if (word_count_reg == 16'd1) begin
store_last_word = 1'b1;
m_ip_payload_axis_tvalid_int = 1'b0;
state_next = STATE_READ_PAYLOAD_LAST;
end else begin
state_next = STATE_READ_PAYLOAD;
end
end
end else begin
state_next = STATE_READ_PAYLOAD;
end
end
STATE_READ_PAYLOAD_LAST: begin
// read and discard until end of frame
s_eth_payload_axis_tready_next = m_ip_payload_axis_tready_int_early;
m_ip_payload_axis_tdata_int = last_word_data_reg;
m_ip_payload_axis_tvalid_int = s_eth_payload_axis_tvalid && s_eth_payload_axis_tlast;
m_ip_payload_axis_tlast_int = s_eth_payload_axis_tlast;
m_ip_payload_axis_tuser_int = s_eth_payload_axis_tuser;
if (s_eth_payload_axis_tready && s_eth_payload_axis_tvalid) begin
if (s_eth_payload_axis_tlast) begin
s_eth_hdr_ready_next = !m_ip_hdr_valid_next;
s_eth_payload_axis_tready_next = 1'b0;
state_next = STATE_IDLE;
end else begin
state_next = STATE_READ_PAYLOAD_LAST;
end
end else begin
state_next = STATE_READ_PAYLOAD_LAST;
end
end
STATE_WAIT_LAST: begin
// read and discard until end of frame
s_eth_payload_axis_tready_next = 1'b1;
if (s_eth_payload_axis_tready && s_eth_payload_axis_tvalid) begin
if (s_eth_payload_axis_tlast) begin
s_eth_hdr_ready_next = !m_ip_hdr_valid_next;
s_eth_payload_axis_tready_next = 1'b0;
state_next = STATE_IDLE;
end else begin
state_next = STATE_WAIT_LAST;
end
end else begin
state_next = STATE_WAIT_LAST;
end
end
endcase
end
always @(posedge clk) begin
if (rst) begin
state_reg <= STATE_IDLE;
s_eth_hdr_ready_reg <= 1'b0;
s_eth_payload_axis_tready_reg <= 1'b0;
m_ip_hdr_valid_reg <= 1'b0;
busy_reg <= 1'b0;
error_header_early_termination_reg <= 1'b0;
error_payload_early_termination_reg <= 1'b0;
error_invalid_header_reg <= 1'b0;
error_invalid_checksum_reg <= 1'b0;
end else begin
state_reg <= state_next;
s_eth_hdr_ready_reg <= s_eth_hdr_ready_next;
s_eth_payload_axis_tready_reg <= s_eth_payload_axis_tready_next;
m_ip_hdr_valid_reg <= m_ip_hdr_valid_next;
error_header_early_termination_reg <= error_header_early_termination_next;
error_payload_early_termination_reg <= error_payload_early_termination_next;
error_invalid_header_reg <= error_invalid_header_next;
error_invalid_checksum_reg <= error_invalid_checksum_next;
busy_reg <= state_next != STATE_IDLE;
end
hdr_ptr_reg <= hdr_ptr_next;
word_count_reg <= word_count_next;
hdr_sum_reg <= hdr_sum_next;
// datapath
if (store_eth_hdr) begin
m_eth_dest_mac_reg <= s_eth_dest_mac;
m_eth_src_mac_reg <= s_eth_src_mac;
m_eth_type_reg <= s_eth_type;
end
if (store_last_word) begin
last_word_data_reg <= m_ip_payload_axis_tdata_int;
end
if (store_ip_version_ihl) {m_ip_version_reg, m_ip_ihl_reg} <= s_eth_payload_axis_tdata;
if (store_ip_dscp_ecn) {m_ip_dscp_reg, m_ip_ecn_reg} <= s_eth_payload_axis_tdata;
if (store_ip_length_0) m_ip_length_reg[ 7: 0] <= s_eth_payload_axis_tdata;
if (store_ip_length_1) m_ip_length_reg[15: 8] <= s_eth_payload_axis_tdata;
if (store_ip_identification_0) m_ip_identification_reg[ 7: 0] <= s_eth_payload_axis_tdata;
if (store_ip_identification_1) m_ip_identification_reg[15: 8] <= s_eth_payload_axis_tdata;
if (store_ip_flags_fragment_offset_0) m_ip_fragment_offset_reg[ 7:0] <= s_eth_payload_axis_tdata;
if (store_ip_flags_fragment_offset_1) {m_ip_flags_reg, m_ip_fragment_offset_reg[12:8]} <= s_eth_payload_axis_tdata;
if (store_ip_ttl) m_ip_ttl_reg <= s_eth_payload_axis_tdata;
if (store_ip_protocol) m_ip_protocol_reg <= s_eth_payload_axis_tdata;
if (store_ip_header_checksum_0) m_ip_header_checksum_reg[ 7: 0] <= s_eth_payload_axis_tdata;
if (store_ip_header_checksum_1) m_ip_header_checksum_reg[15: 8] <= s_eth_payload_axis_tdata;
if (store_ip_source_ip_0) m_ip_source_ip_reg[ 7: 0] <= s_eth_payload_axis_tdata;
if (store_ip_source_ip_1) m_ip_source_ip_reg[15: 8] <= s_eth_payload_axis_tdata;
if (store_ip_source_ip_2) m_ip_source_ip_reg[23:16] <= s_eth_payload_axis_tdata;
if (store_ip_source_ip_3) m_ip_source_ip_reg[31:24] <= s_eth_payload_axis_tdata;
if (store_ip_dest_ip_0) m_ip_dest_ip_reg[ 7: 0] <= s_eth_payload_axis_tdata;
if (store_ip_dest_ip_1) m_ip_dest_ip_reg[15: 8] <= s_eth_payload_axis_tdata;
if (store_ip_dest_ip_2) m_ip_dest_ip_reg[23:16] <= s_eth_payload_axis_tdata;
if (store_ip_dest_ip_3) m_ip_dest_ip_reg[31:24] <= s_eth_payload_axis_tdata;
end
// output datapath logic
reg [7:0] m_ip_payload_axis_tdata_reg = 8'd0;
reg m_ip_payload_axis_tvalid_reg = 1'b0, m_ip_payload_axis_tvalid_next;
reg m_ip_payload_axis_tlast_reg = 1'b0;
reg m_ip_payload_axis_tuser_reg = 1'b0;
reg [7:0] temp_m_ip_payload_axis_tdata_reg = 8'd0;
reg temp_m_ip_payload_axis_tvalid_reg = 1'b0, temp_m_ip_payload_axis_tvalid_next;
reg temp_m_ip_payload_axis_tlast_reg = 1'b0;
reg temp_m_ip_payload_axis_tuser_reg = 1'b0;
// datapath control
reg store_ip_payload_int_to_output;
reg store_ip_payload_int_to_temp;
reg store_ip_payload_axis_temp_to_output;
assign m_ip_payload_axis_tdata = m_ip_payload_axis_tdata_reg;
assign m_ip_payload_axis_tvalid = m_ip_payload_axis_tvalid_reg;
assign m_ip_payload_axis_tlast = m_ip_payload_axis_tlast_reg;
assign m_ip_payload_axis_tuser = m_ip_payload_axis_tuser_reg;
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
assign m_ip_payload_axis_tready_int_early = m_ip_payload_axis_tready || (!temp_m_ip_payload_axis_tvalid_reg && (!m_ip_payload_axis_tvalid_reg || !m_ip_payload_axis_tvalid_int));
always @* begin
// transfer sink ready state to source
m_ip_payload_axis_tvalid_next = m_ip_payload_axis_tvalid_reg;
temp_m_ip_payload_axis_tvalid_next = temp_m_ip_payload_axis_tvalid_reg;
store_ip_payload_int_to_output = 1'b0;
store_ip_payload_int_to_temp = 1'b0;
store_ip_payload_axis_temp_to_output = 1'b0;
if (m_ip_payload_axis_tready_int_reg) begin
// input is ready
if (m_ip_payload_axis_tready || !m_ip_payload_axis_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output
m_ip_payload_axis_tvalid_next = m_ip_payload_axis_tvalid_int;
store_ip_payload_int_to_output = 1'b1;
end else begin
// output is not ready, store input in temp
temp_m_ip_payload_axis_tvalid_next = m_ip_payload_axis_tvalid_int;
store_ip_payload_int_to_temp = 1'b1;
end
end else if (m_ip_payload_axis_tready) begin
// input is not ready, but output is ready
m_ip_payload_axis_tvalid_next = temp_m_ip_payload_axis_tvalid_reg;
temp_m_ip_payload_axis_tvalid_next = 1'b0;
store_ip_payload_axis_temp_to_output = 1'b1;
end
end
always @(posedge clk) begin
if (rst) begin
m_ip_payload_axis_tvalid_reg <= 1'b0;
m_ip_payload_axis_tready_int_reg <= 1'b0;
temp_m_ip_payload_axis_tvalid_reg <= 1'b0;
end else begin
m_ip_payload_axis_tvalid_reg <= m_ip_payload_axis_tvalid_next;
m_ip_payload_axis_tready_int_reg <= m_ip_payload_axis_tready_int_early;
temp_m_ip_payload_axis_tvalid_reg <= temp_m_ip_payload_axis_tvalid_next;
end
// datapath
if (store_ip_payload_int_to_output) begin
m_ip_payload_axis_tdata_reg <= m_ip_payload_axis_tdata_int;
m_ip_payload_axis_tlast_reg <= m_ip_payload_axis_tlast_int;
m_ip_payload_axis_tuser_reg <= m_ip_payload_axis_tuser_int;
end else if (store_ip_payload_axis_temp_to_output) begin
m_ip_payload_axis_tdata_reg <= temp_m_ip_payload_axis_tdata_reg;
m_ip_payload_axis_tlast_reg <= temp_m_ip_payload_axis_tlast_reg;
m_ip_payload_axis_tuser_reg <= temp_m_ip_payload_axis_tuser_reg;
end
if (store_ip_payload_int_to_temp) begin
temp_m_ip_payload_axis_tdata_reg <= m_ip_payload_axis_tdata_int;
temp_m_ip_payload_axis_tlast_reg <= m_ip_payload_axis_tlast_int;
temp_m_ip_payload_axis_tuser_reg <= m_ip_payload_axis_tuser_int;
end
end
endmodule
/*
Copyright (c) 2014-2018 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* IP ethernet frame receiver (Ethernet frame in, IP frame out, 64 bit datapath)
*/
module ip_eth_rx_64
(
input wire clk,
input wire rst,
/*
* Ethernet frame input
*/
input wire s_eth_hdr_valid,
output wire s_eth_hdr_ready,
input wire [47:0] s_eth_dest_mac,
input wire [47:0] s_eth_src_mac,
input wire [15:0] s_eth_type,
input wire [63:0] s_eth_payload_axis_tdata,
input wire [7:0] s_eth_payload_axis_tkeep,
input wire s_eth_payload_axis_tvalid,
output wire s_eth_payload_axis_tready,
input wire s_eth_payload_axis_tlast,
input wire s_eth_payload_axis_tuser,
/*
* IP frame output
*/
output wire m_ip_hdr_valid,
input wire m_ip_hdr_ready,
output wire [47:0] m_eth_dest_mac,
output wire [47:0] m_eth_src_mac,
output wire [15:0] m_eth_type,
output wire [3:0] m_ip_version,
output wire [3:0] m_ip_ihl,
output wire [5:0] m_ip_dscp,
output wire [1:0] m_ip_ecn,
output wire [15:0] m_ip_length,
output wire [15:0] m_ip_identification,
output wire [2:0] m_ip_flags,
output wire [12:0] m_ip_fragment_offset,
output wire [7:0] m_ip_ttl,
output wire [7:0] m_ip_protocol,
output wire [15:0] m_ip_header_checksum,
output wire [31:0] m_ip_source_ip,
output wire [31:0] m_ip_dest_ip,
output wire [63:0] m_ip_payload_axis_tdata,
output wire [7:0] m_ip_payload_axis_tkeep,
output wire m_ip_payload_axis_tvalid,
input wire m_ip_payload_axis_tready,
output wire m_ip_payload_axis_tlast,
output wire m_ip_payload_axis_tuser,
/*
* Status signals
*/
output wire busy,
output wire error_header_early_termination,
output wire error_payload_early_termination,
output wire error_invalid_header,
output wire error_invalid_checksum
);
/*
IP Frame
Field Length
Destination MAC address 6 octets
Source MAC address 6 octets
Ethertype (0x0800) 2 octets
Version (4) 4 bits
IHL (5-15) 4 bits
DSCP (0) 6 bits
ECN (0) 2 bits
length 2 octets
identification (0?) 2 octets
flags (010) 3 bits
fragment offset (0) 13 bits
time to live (64?) 1 octet
protocol 1 octet
header checksum 2 octets
source IP 4 octets
destination IP 4 octets
options (IHL-5)*4 octets
payload length octets
This module receives an Ethernet frame with header fields in parallel and
payload on an AXI stream interface, decodes and strips the IP header fields,
then produces the header fields in parallel along with the IP payload in a
separate AXI stream.
*/
localparam [2:0]
STATE_IDLE = 3'd0,
STATE_READ_HEADER = 3'd1,
STATE_READ_PAYLOAD = 3'd2,
STATE_READ_PAYLOAD_LAST = 3'd3,
STATE_WAIT_LAST = 3'd4;
reg [2:0] state_reg = STATE_IDLE, state_next;
// datapath control signals
reg store_eth_hdr;
reg store_hdr_word_0;
reg store_hdr_word_1;
reg store_hdr_word_2;
reg store_last_word;
reg flush_save;
reg transfer_in_save;
reg [5:0] hdr_ptr_reg = 6'd0, hdr_ptr_next;
reg [15:0] word_count_reg = 16'd0, word_count_next;
reg [16:0] hdr_sum_high_reg = 17'd0;
reg [16:0] hdr_sum_low_reg = 17'd0;
reg [19:0] hdr_sum_temp;
reg [19:0] hdr_sum_reg = 20'd0, hdr_sum_next;
reg check_hdr_reg = 1'b0, check_hdr_next;
reg [63:0] last_word_data_reg = 64'd0;
reg [7:0] last_word_keep_reg = 8'd0;
reg s_eth_hdr_ready_reg = 1'b0, s_eth_hdr_ready_next;
reg s_eth_payload_axis_tready_reg = 1'b0, s_eth_payload_axis_tready_next;
reg m_ip_hdr_valid_reg = 1'b0, m_ip_hdr_valid_next;
reg [47:0] m_eth_dest_mac_reg = 48'd0;
reg [47:0] m_eth_src_mac_reg = 48'd0;
reg [15:0] m_eth_type_reg = 16'd0;
reg [3:0] m_ip_version_reg = 4'd0;
reg [3:0] m_ip_ihl_reg = 4'd0;
reg [5:0] m_ip_dscp_reg = 6'd0;
reg [1:0] m_ip_ecn_reg = 2'd0;
reg [15:0] m_ip_length_reg = 16'd0;
reg [15:0] m_ip_identification_reg = 16'd0;
reg [2:0] m_ip_flags_reg = 3'd0;
reg [12:0] m_ip_fragment_offset_reg = 13'd0;
reg [7:0] m_ip_ttl_reg = 8'd0;
reg [7:0] m_ip_protocol_reg = 8'd0;
reg [15:0] m_ip_header_checksum_reg = 16'd0;
reg [31:0] m_ip_source_ip_reg = 32'd0;
reg [31:0] m_ip_dest_ip_reg = 32'd0;
reg busy_reg = 1'b0;
reg error_header_early_termination_reg = 1'b0, error_header_early_termination_next;
reg error_payload_early_termination_reg = 1'b0, error_payload_early_termination_next;
reg error_invalid_header_reg = 1'b0, error_invalid_header_next;
reg error_invalid_checksum_reg = 1'b0, error_invalid_checksum_next;
reg [63:0] save_eth_payload_axis_tdata_reg = 64'd0;
reg [7:0] save_eth_payload_axis_tkeep_reg = 8'd0;
reg save_eth_payload_axis_tlast_reg = 1'b0;
reg save_eth_payload_axis_tuser_reg = 1'b0;
reg [63:0] shift_eth_payload_axis_tdata;
reg [7:0] shift_eth_payload_axis_tkeep;
reg shift_eth_payload_axis_tvalid;
reg shift_eth_payload_axis_tlast;
reg shift_eth_payload_axis_tuser;
reg shift_eth_payload_s_tready;
reg shift_eth_payload_extra_cycle_reg = 1'b0;
// internal datapath
reg [63:0] m_ip_payload_axis_tdata_int;
reg [7:0] m_ip_payload_axis_tkeep_int;
reg m_ip_payload_axis_tvalid_int;
reg m_ip_payload_axis_tready_int_reg = 1'b0;
reg m_ip_payload_axis_tlast_int;
reg m_ip_payload_axis_tuser_int;
wire m_ip_payload_axis_tready_int_early;
assign s_eth_hdr_ready = s_eth_hdr_ready_reg;
assign s_eth_payload_axis_tready = s_eth_payload_axis_tready_reg;
assign m_ip_hdr_valid = m_ip_hdr_valid_reg;
assign m_eth_dest_mac = m_eth_dest_mac_reg;
assign m_eth_src_mac = m_eth_src_mac_reg;
assign m_eth_type = m_eth_type_reg;
assign m_ip_version = m_ip_version_reg;
assign m_ip_ihl = m_ip_ihl_reg;
assign m_ip_dscp = m_ip_dscp_reg;
assign m_ip_ecn = m_ip_ecn_reg;
assign m_ip_length = m_ip_length_reg;
assign m_ip_identification = m_ip_identification_reg;
assign m_ip_flags = m_ip_flags_reg;
assign m_ip_fragment_offset = m_ip_fragment_offset_reg;
assign m_ip_ttl = m_ip_ttl_reg;
assign m_ip_protocol = m_ip_protocol_reg;
assign m_ip_header_checksum = m_ip_header_checksum_reg;
assign m_ip_source_ip = m_ip_source_ip_reg;
assign m_ip_dest_ip = m_ip_dest_ip_reg;
assign busy = busy_reg;
assign error_header_early_termination = error_header_early_termination_reg;
assign error_payload_early_termination = error_payload_early_termination_reg;
assign error_invalid_header = error_invalid_header_reg;
assign error_invalid_checksum = error_invalid_checksum_reg;
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
function [7:0] count2keep;
input [3:0] k;
case (k)
4'd0: count2keep = 8'b00000000;
4'd1: count2keep = 8'b00000001;
4'd2: count2keep = 8'b00000011;
4'd3: count2keep = 8'b00000111;
4'd4: count2keep = 8'b00001111;
4'd5: count2keep = 8'b00011111;
4'd6: count2keep = 8'b00111111;
4'd7: count2keep = 8'b01111111;
4'd8: count2keep = 8'b11111111;
endcase
endfunction
always @* begin
shift_eth_payload_axis_tdata[31:0] = save_eth_payload_axis_tdata_reg[63:32];
shift_eth_payload_axis_tkeep[3:0] = save_eth_payload_axis_tkeep_reg[7:4];
if (shift_eth_payload_extra_cycle_reg) begin
shift_eth_payload_axis_tdata[63:32] = 32'd0;
shift_eth_payload_axis_tkeep[7:4] = 4'd0;
shift_eth_payload_axis_tvalid = 1'b1;
shift_eth_payload_axis_tlast = save_eth_payload_axis_tlast_reg;
shift_eth_payload_axis_tuser = save_eth_payload_axis_tuser_reg;
shift_eth_payload_s_tready = flush_save;
end else begin
shift_eth_payload_axis_tdata[63:32] = s_eth_payload_axis_tdata[31:0];
shift_eth_payload_axis_tkeep[7:4] = s_eth_payload_axis_tkeep[3:0];
shift_eth_payload_axis_tvalid = s_eth_payload_axis_tvalid;
shift_eth_payload_axis_tlast = (s_eth_payload_axis_tlast && (s_eth_payload_axis_tkeep[7:4] == 0));
shift_eth_payload_axis_tuser = (s_eth_payload_axis_tuser && (s_eth_payload_axis_tkeep[7:4] == 0));
shift_eth_payload_s_tready = !(s_eth_payload_axis_tlast && s_eth_payload_axis_tvalid && transfer_in_save);
end
end
always @* begin
state_next = STATE_IDLE;
flush_save = 1'b0;
transfer_in_save = 1'b0;
s_eth_hdr_ready_next = 1'b0;
s_eth_payload_axis_tready_next = 1'b0;
store_eth_hdr = 1'b0;
store_hdr_word_0 = 1'b0;
store_hdr_word_1 = 1'b0;
store_hdr_word_2 = 1'b0;
store_last_word = 1'b0;
hdr_ptr_next = hdr_ptr_reg;
word_count_next = word_count_reg;
hdr_sum_temp = 32'd0;
hdr_sum_next = hdr_sum_reg;
check_hdr_next = check_hdr_reg;
m_ip_hdr_valid_next = m_ip_hdr_valid_reg && !m_ip_hdr_ready;
error_header_early_termination_next = 1'b0;
error_payload_early_termination_next = 1'b0;
error_invalid_header_next = 1'b0;
error_invalid_checksum_next = 1'b0;
m_ip_payload_axis_tdata_int = 64'd0;
m_ip_payload_axis_tkeep_int = 8'd0;
m_ip_payload_axis_tvalid_int = 1'b0;
m_ip_payload_axis_tlast_int = 1'b0;
m_ip_payload_axis_tuser_int = 1'b0;
case (state_reg)
STATE_IDLE: begin
// idle state - wait for header
hdr_ptr_next = 6'd0;
hdr_sum_next = 32'd0;
flush_save = 1'b1;
s_eth_hdr_ready_next = !m_ip_hdr_valid_next;
if (s_eth_hdr_ready && s_eth_hdr_valid) begin
s_eth_hdr_ready_next = 1'b0;
s_eth_payload_axis_tready_next = 1'b1;
store_eth_hdr = 1'b1;
state_next = STATE_READ_HEADER;
end else begin
state_next = STATE_IDLE;
end
end
STATE_READ_HEADER: begin
// read header
s_eth_payload_axis_tready_next = shift_eth_payload_s_tready;
word_count_next = m_ip_length_reg - 5*4;
if (s_eth_payload_axis_tvalid) begin
// word transfer in - store it
hdr_ptr_next = hdr_ptr_reg + 6'd8;
transfer_in_save = 1'b1;
state_next = STATE_READ_HEADER;
case (hdr_ptr_reg)
6'h00: begin
store_hdr_word_0 = 1'b1;
end
6'h08: begin
store_hdr_word_1 = 1'b1;
hdr_sum_next = hdr_sum_high_reg + hdr_sum_low_reg;
end
6'h10: begin
store_hdr_word_2 = 1'b1;
hdr_sum_next = hdr_sum_reg + hdr_sum_high_reg + hdr_sum_low_reg;
// check header checksum on next cycle for improved timing
check_hdr_next = 1'b1;
if (m_ip_version_reg != 4'd4 || m_ip_ihl_reg != 4'd5) begin
error_invalid_header_next = 1'b1;
s_eth_payload_axis_tready_next = shift_eth_payload_s_tready;
state_next = STATE_WAIT_LAST;
end else begin
s_eth_payload_axis_tready_next = m_ip_payload_axis_tready_int_early && shift_eth_payload_s_tready;
state_next = STATE_READ_PAYLOAD;
end
end
endcase
if (shift_eth_payload_axis_tlast) begin
error_header_early_termination_next = 1'b1;
error_invalid_header_next = 1'b0;
error_invalid_checksum_next = 1'b0;
m_ip_hdr_valid_next = 1'b0;
s_eth_hdr_ready_next = !m_ip_hdr_valid_next;
s_eth_payload_axis_tready_next = 1'b0;
state_next = STATE_IDLE;
end
end else begin
state_next = STATE_READ_HEADER;
end
end
STATE_READ_PAYLOAD: begin
// read payload
s_eth_payload_axis_tready_next = m_ip_payload_axis_tready_int_early && shift_eth_payload_s_tready;
m_ip_payload_axis_tdata_int = shift_eth_payload_axis_tdata;
m_ip_payload_axis_tkeep_int = shift_eth_payload_axis_tkeep;
m_ip_payload_axis_tvalid_int = shift_eth_payload_axis_tvalid;
m_ip_payload_axis_tlast_int = shift_eth_payload_axis_tlast;
m_ip_payload_axis_tuser_int = shift_eth_payload_axis_tuser;
store_last_word = 1'b1;
if (m_ip_payload_axis_tready_int_reg && shift_eth_payload_axis_tvalid) begin
// word transfer through
word_count_next = word_count_reg - 16'd8;
transfer_in_save = 1'b1;
if (word_count_reg <= 8) begin
// have entire payload
m_ip_payload_axis_tkeep_int = shift_eth_payload_axis_tkeep & count2keep(word_count_reg);
if (shift_eth_payload_axis_tlast) begin
if (keep2count(shift_eth_payload_axis_tkeep) < word_count_reg[4:0]) begin
// end of frame, but length does not match
error_payload_early_termination_next = 1'b1;
m_ip_payload_axis_tuser_int = 1'b1;
end
s_eth_payload_axis_tready_next = 1'b0;
flush_save = 1'b1;
s_eth_hdr_ready_next = !m_ip_hdr_valid_reg && !check_hdr_reg;
state_next = STATE_IDLE;
end else begin
m_ip_payload_axis_tvalid_int = 1'b0;
state_next = STATE_READ_PAYLOAD_LAST;
end
end else begin
if (shift_eth_payload_axis_tlast) begin
// end of frame, but length does not match
error_payload_early_termination_next = 1'b1;
m_ip_payload_axis_tuser_int = 1'b1;
s_eth_payload_axis_tready_next = 1'b0;
flush_save = 1'b1;
s_eth_hdr_ready_next = !m_ip_hdr_valid_reg && !check_hdr_reg;
state_next = STATE_IDLE;
end else begin
state_next = STATE_READ_PAYLOAD;
end
end
end else begin
state_next = STATE_READ_PAYLOAD;
end
if (check_hdr_reg) begin
check_hdr_next = 1'b0;
hdr_sum_temp = hdr_sum_reg[15:0] + hdr_sum_reg[19:16] + hdr_sum_low_reg;
if (hdr_sum_temp != 19'h0ffff && hdr_sum_temp != 19'h1fffe) begin
// bad checksum
error_invalid_checksum_next = 1'b1;
m_ip_payload_axis_tvalid_int = 1'b0;
if (shift_eth_payload_axis_tlast && shift_eth_payload_axis_tvalid) begin
// only one payload cycle; return to idle now
s_eth_hdr_ready_next = !m_ip_hdr_valid_reg && !check_hdr_reg;
state_next = STATE_IDLE;
end else begin
// drop payload
s_eth_payload_axis_tready_next = shift_eth_payload_s_tready;
state_next = STATE_WAIT_LAST;
end
end else begin
// good checksum; transfer header
m_ip_hdr_valid_next = 1'b1;
end
end
end
STATE_READ_PAYLOAD_LAST: begin
// read and discard until end of frame
s_eth_payload_axis_tready_next = m_ip_payload_axis_tready_int_early && shift_eth_payload_s_tready;
m_ip_payload_axis_tdata_int = last_word_data_reg;
m_ip_payload_axis_tkeep_int = last_word_keep_reg;
m_ip_payload_axis_tvalid_int = shift_eth_payload_axis_tvalid && shift_eth_payload_axis_tlast;
m_ip_payload_axis_tlast_int = shift_eth_payload_axis_tlast;
m_ip_payload_axis_tuser_int = shift_eth_payload_axis_tuser;
if (m_ip_payload_axis_tready_int_reg && shift_eth_payload_axis_tvalid) begin
transfer_in_save = 1'b1;
if (shift_eth_payload_axis_tlast) begin
s_eth_payload_axis_tready_next = 1'b0;
flush_save = 1'b1;
s_eth_hdr_ready_next = !m_ip_hdr_valid_next;
state_next = STATE_IDLE;
end else begin
state_next = STATE_READ_PAYLOAD_LAST;
end
end else begin
state_next = STATE_READ_PAYLOAD_LAST;
end
end
STATE_WAIT_LAST: begin
// read and discard until end of frame
s_eth_payload_axis_tready_next = shift_eth_payload_s_tready;
if (shift_eth_payload_axis_tvalid) begin
transfer_in_save = 1'b1;
if (shift_eth_payload_axis_tlast) begin
s_eth_payload_axis_tready_next = 1'b0;
flush_save = 1'b1;
s_eth_hdr_ready_next = !m_ip_hdr_valid_next;
state_next = STATE_IDLE;
end else begin
state_next = STATE_WAIT_LAST;
end
end else begin
state_next = STATE_WAIT_LAST;
end
end
endcase
end
always @(posedge clk) begin
if (rst) begin
state_reg <= STATE_IDLE;
s_eth_hdr_ready_reg <= 1'b0;
s_eth_payload_axis_tready_reg <= 1'b0;
m_ip_hdr_valid_reg <= 1'b0;
save_eth_payload_axis_tlast_reg <= 1'b0;
shift_eth_payload_extra_cycle_reg <= 1'b0;
busy_reg <= 1'b0;
error_header_early_termination_reg <= 1'b0;
error_payload_early_termination_reg <= 1'b0;
error_invalid_header_reg <= 1'b0;
error_invalid_checksum_reg <= 1'b0;
end else begin
state_reg <= state_next;
s_eth_hdr_ready_reg <= s_eth_hdr_ready_next;
s_eth_payload_axis_tready_reg <= s_eth_payload_axis_tready_next;
m_ip_hdr_valid_reg <= m_ip_hdr_valid_next;
error_header_early_termination_reg <= error_header_early_termination_next;
error_payload_early_termination_reg <= error_payload_early_termination_next;
error_invalid_header_reg <= error_invalid_header_next;
error_invalid_checksum_reg <= error_invalid_checksum_next;
busy_reg <= state_next != STATE_IDLE;
// datapath
if (flush_save) begin
save_eth_payload_axis_tlast_reg <= 1'b0;
shift_eth_payload_extra_cycle_reg <= 1'b0;
end else if (transfer_in_save) begin
save_eth_payload_axis_tlast_reg <= s_eth_payload_axis_tlast;
shift_eth_payload_extra_cycle_reg <= s_eth_payload_axis_tlast && (s_eth_payload_axis_tkeep[7:4] != 0);
end
end
hdr_ptr_reg <= hdr_ptr_next;
word_count_reg <= word_count_next;
hdr_sum_reg <= hdr_sum_next;
check_hdr_reg <= check_hdr_next;
if (s_eth_payload_axis_tvalid) begin
hdr_sum_low_reg <= s_eth_payload_axis_tdata[15:0] + s_eth_payload_axis_tdata[31:16];
hdr_sum_high_reg <= s_eth_payload_axis_tdata[47:32] + s_eth_payload_axis_tdata[63:48];
end
// datapath
if (store_eth_hdr) begin
m_eth_dest_mac_reg <= s_eth_dest_mac;
m_eth_src_mac_reg <= s_eth_src_mac;
m_eth_type_reg <= s_eth_type;
end
if (store_last_word) begin
last_word_data_reg <= m_ip_payload_axis_tdata_int;
last_word_keep_reg <= m_ip_payload_axis_tkeep_int;
end
if (store_hdr_word_0) begin
{m_ip_version_reg, m_ip_ihl_reg} <= s_eth_payload_axis_tdata[ 7: 0];
{m_ip_dscp_reg, m_ip_ecn_reg} <= s_eth_payload_axis_tdata[15: 8];
m_ip_length_reg[15: 8] <= s_eth_payload_axis_tdata[23:16];
m_ip_length_reg[ 7: 0] <= s_eth_payload_axis_tdata[31:24];
m_ip_identification_reg[15: 8] <= s_eth_payload_axis_tdata[39:32];
m_ip_identification_reg[ 7: 0] <= s_eth_payload_axis_tdata[47:40];
{m_ip_flags_reg, m_ip_fragment_offset_reg[12:8]} <= s_eth_payload_axis_tdata[55:48];
m_ip_fragment_offset_reg[ 7:0] <= s_eth_payload_axis_tdata[63:56];
end
if (store_hdr_word_1) begin
m_ip_ttl_reg <= s_eth_payload_axis_tdata[ 7: 0];
m_ip_protocol_reg <= s_eth_payload_axis_tdata[15: 8];
m_ip_header_checksum_reg[15: 8] <= s_eth_payload_axis_tdata[23:16];
m_ip_header_checksum_reg[ 7: 0] <= s_eth_payload_axis_tdata[31:24];
m_ip_source_ip_reg[31:24] <= s_eth_payload_axis_tdata[39:32];
m_ip_source_ip_reg[23:16] <= s_eth_payload_axis_tdata[47:40];
m_ip_source_ip_reg[15: 8] <= s_eth_payload_axis_tdata[55:48];
m_ip_source_ip_reg[ 7: 0] <= s_eth_payload_axis_tdata[63:56];
end
if (store_hdr_word_2) begin
m_ip_dest_ip_reg[31:24] <= s_eth_payload_axis_tdata[ 7: 0];
m_ip_dest_ip_reg[23:16] <= s_eth_payload_axis_tdata[15: 8];
m_ip_dest_ip_reg[15: 8] <= s_eth_payload_axis_tdata[23:16];
m_ip_dest_ip_reg[ 7: 0] <= s_eth_payload_axis_tdata[31:24];
end
if (transfer_in_save) begin
save_eth_payload_axis_tdata_reg <= s_eth_payload_axis_tdata;
save_eth_payload_axis_tkeep_reg <= s_eth_payload_axis_tkeep;
save_eth_payload_axis_tuser_reg <= s_eth_payload_axis_tuser;
end
end
// output datapath logic
reg [63:0] m_ip_payload_axis_tdata_reg = 64'd0;
reg [7:0] m_ip_payload_axis_tkeep_reg = 8'd0;
reg m_ip_payload_axis_tvalid_reg = 1'b0, m_ip_payload_axis_tvalid_next;
reg m_ip_payload_axis_tlast_reg = 1'b0;
reg m_ip_payload_axis_tuser_reg = 1'b0;
reg [63:0] temp_m_ip_payload_axis_tdata_reg = 64'd0;
reg [7:0] temp_m_ip_payload_axis_tkeep_reg = 8'd0;
reg temp_m_ip_payload_axis_tvalid_reg = 1'b0, temp_m_ip_payload_axis_tvalid_next;
reg temp_m_ip_payload_axis_tlast_reg = 1'b0;
reg temp_m_ip_payload_axis_tuser_reg = 1'b0;
// datapath control
reg store_ip_payload_int_to_output;
reg store_ip_payload_int_to_temp;
reg store_ip_payload_axis_temp_to_output;
assign m_ip_payload_axis_tdata = m_ip_payload_axis_tdata_reg;
assign m_ip_payload_axis_tkeep = m_ip_payload_axis_tkeep_reg;
assign m_ip_payload_axis_tvalid = m_ip_payload_axis_tvalid_reg;
assign m_ip_payload_axis_tlast = m_ip_payload_axis_tlast_reg;
assign m_ip_payload_axis_tuser = m_ip_payload_axis_tuser_reg;
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
assign m_ip_payload_axis_tready_int_early = m_ip_payload_axis_tready || (!temp_m_ip_payload_axis_tvalid_reg && (!m_ip_payload_axis_tvalid_reg || !m_ip_payload_axis_tvalid_int));
always @* begin
// transfer sink ready state to source
m_ip_payload_axis_tvalid_next = m_ip_payload_axis_tvalid_reg;
temp_m_ip_payload_axis_tvalid_next = temp_m_ip_payload_axis_tvalid_reg;
store_ip_payload_int_to_output = 1'b0;
store_ip_payload_int_to_temp = 1'b0;
store_ip_payload_axis_temp_to_output = 1'b0;
if (m_ip_payload_axis_tready_int_reg) begin
// input is ready
if (m_ip_payload_axis_tready || !m_ip_payload_axis_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output
m_ip_payload_axis_tvalid_next = m_ip_payload_axis_tvalid_int;
store_ip_payload_int_to_output = 1'b1;
end else begin
// output is not ready, store input in temp
temp_m_ip_payload_axis_tvalid_next = m_ip_payload_axis_tvalid_int;
store_ip_payload_int_to_temp = 1'b1;
end
end else if (m_ip_payload_axis_tready) begin
// input is not ready, but output is ready
m_ip_payload_axis_tvalid_next = temp_m_ip_payload_axis_tvalid_reg;
temp_m_ip_payload_axis_tvalid_next = 1'b0;
store_ip_payload_axis_temp_to_output = 1'b1;
end
end
always @(posedge clk) begin
if (rst) begin
m_ip_payload_axis_tvalid_reg <= 1'b0;
m_ip_payload_axis_tready_int_reg <= 1'b0;
temp_m_ip_payload_axis_tvalid_reg <= 1'b0;
end else begin
m_ip_payload_axis_tvalid_reg <= m_ip_payload_axis_tvalid_next;
m_ip_payload_axis_tready_int_reg <= m_ip_payload_axis_tready_int_early;
temp_m_ip_payload_axis_tvalid_reg <= temp_m_ip_payload_axis_tvalid_next;
end
// datapath
if (store_ip_payload_int_to_output) begin
m_ip_payload_axis_tdata_reg <= m_ip_payload_axis_tdata_int;
m_ip_payload_axis_tkeep_reg <= m_ip_payload_axis_tkeep_int;
m_ip_payload_axis_tlast_reg <= m_ip_payload_axis_tlast_int;
m_ip_payload_axis_tuser_reg <= m_ip_payload_axis_tuser_int;
end else if (store_ip_payload_axis_temp_to_output) begin
m_ip_payload_axis_tdata_reg <= temp_m_ip_payload_axis_tdata_reg;
m_ip_payload_axis_tkeep_reg <= temp_m_ip_payload_axis_tkeep_reg;
m_ip_payload_axis_tlast_reg <= temp_m_ip_payload_axis_tlast_reg;
m_ip_payload_axis_tuser_reg <= temp_m_ip_payload_axis_tuser_reg;
end
if (store_ip_payload_int_to_temp) begin
temp_m_ip_payload_axis_tdata_reg <= m_ip_payload_axis_tdata_int;
temp_m_ip_payload_axis_tkeep_reg <= m_ip_payload_axis_tkeep_int;
temp_m_ip_payload_axis_tlast_reg <= m_ip_payload_axis_tlast_int;
temp_m_ip_payload_axis_tuser_reg <= m_ip_payload_axis_tuser_int;
end
end
endmodule
/*
Copyright (c) 2014-2018 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* IP ethernet frame transmitter (IP frame in, Ethernet frame out)
*/
module ip_eth_tx
(
input wire clk,
input wire rst,
/*
* IP frame input
*/
input wire s_ip_hdr_valid,
output wire s_ip_hdr_ready,
input wire [47:0] s_eth_dest_mac,
input wire [47:0] s_eth_src_mac,
input wire [15:0] s_eth_type,
input wire [5:0] s_ip_dscp,
input wire [1:0] s_ip_ecn,
input wire [15:0] s_ip_length,
input wire [15:0] s_ip_identification,
input wire [2:0] s_ip_flags,
input wire [12:0] s_ip_fragment_offset,
input wire [7:0] s_ip_ttl,
input wire [7:0] s_ip_protocol,
input wire [31:0] s_ip_source_ip,
input wire [31:0] s_ip_dest_ip,
input wire [7:0] s_ip_payload_axis_tdata,
input wire s_ip_payload_axis_tvalid,
output wire s_ip_payload_axis_tready,
input wire s_ip_payload_axis_tlast,
input wire s_ip_payload_axis_tuser,
/*
* Ethernet frame output
*/
output wire m_eth_hdr_valid,
input wire m_eth_hdr_ready,
output wire [47:0] m_eth_dest_mac,
output wire [47:0] m_eth_src_mac,
output wire [15:0] m_eth_type,
output wire [7:0] m_eth_payload_axis_tdata,
output wire m_eth_payload_axis_tvalid,
input wire m_eth_payload_axis_tready,
output wire m_eth_payload_axis_tlast,
output wire m_eth_payload_axis_tuser,
/*
* Status signals
*/
output wire busy,
output wire error_payload_early_termination
);
/*
IP Frame
Field Length
Destination MAC address 6 octets
Source MAC address 6 octets
Ethertype (0x0800) 2 octets
Version (4) 4 bits
IHL (5-15) 4 bits
DSCP (0) 6 bits
ECN (0) 2 bits
length 2 octets
identification (0?) 2 octets
flags (010) 3 bits
fragment offset (0) 13 bits
time to live (64?) 1 octet
protocol 1 octet
header checksum 2 octets
source IP 4 octets
destination IP 4 octets
options (IHL-5)*4 octets
payload length octets
This module receives an IP frame with header fields in parallel along with the
payload in an AXI stream, combines the header with the payload, passes through
the Ethernet headers, and transmits the complete Ethernet payload on an AXI
interface.
*/
localparam [2:0]
STATE_IDLE = 3'd0,
STATE_WRITE_HEADER = 3'd1,
STATE_WRITE_PAYLOAD = 3'd2,
STATE_WRITE_PAYLOAD_LAST = 3'd3,
STATE_WAIT_LAST = 3'd4;
reg [2:0] state_reg = STATE_IDLE, state_next;
// datapath control signals
reg store_ip_hdr;
reg store_last_word;
reg [5:0] hdr_ptr_reg = 6'd0, hdr_ptr_next;
reg [15:0] word_count_reg = 16'd0, word_count_next;
reg [15:0] hdr_sum_reg = 16'd0, hdr_sum_next;
reg [7:0] last_word_data_reg = 8'd0;
reg [5:0] ip_dscp_reg = 6'd0;
reg [1:0] ip_ecn_reg = 2'd0;
reg [15:0] ip_length_reg = 16'd0;
reg [15:0] ip_identification_reg = 16'd0;
reg [2:0] ip_flags_reg = 3'd0;
reg [12:0] ip_fragment_offset_reg = 13'd0;
reg [7:0] ip_ttl_reg = 8'd0;
reg [7:0] ip_protocol_reg = 8'd0;
reg [31:0] ip_source_ip_reg = 32'd0;
reg [31:0] ip_dest_ip_reg = 32'd0;
reg s_ip_hdr_ready_reg = 1'b0, s_ip_hdr_ready_next;
reg s_ip_payload_axis_tready_reg = 1'b0, s_ip_payload_axis_tready_next;
reg m_eth_hdr_valid_reg = 1'b0, m_eth_hdr_valid_next;
reg [47:0] m_eth_dest_mac_reg = 48'd0;
reg [47:0] m_eth_src_mac_reg = 48'd0;
reg [15:0] m_eth_type_reg = 16'd0;
reg busy_reg = 1'b0;
reg error_payload_early_termination_reg = 1'b0, error_payload_early_termination_next;
// internal datapath
reg [7:0] m_eth_payload_axis_tdata_int;
reg m_eth_payload_axis_tvalid_int;
reg m_eth_payload_axis_tready_int_reg = 1'b0;
reg m_eth_payload_axis_tlast_int;
reg m_eth_payload_axis_tuser_int;
wire m_eth_payload_axis_tready_int_early;
assign s_ip_hdr_ready = s_ip_hdr_ready_reg;
assign s_ip_payload_axis_tready = s_ip_payload_axis_tready_reg;
assign m_eth_hdr_valid = m_eth_hdr_valid_reg;
assign m_eth_dest_mac = m_eth_dest_mac_reg;
assign m_eth_src_mac = m_eth_src_mac_reg;
assign m_eth_type = m_eth_type_reg;
assign busy = busy_reg;
assign error_payload_early_termination = error_payload_early_termination_reg;
function [15:0] add1c16b;
input [15:0] a, b;
reg [16:0] t;
begin
t = a+b;
add1c16b = t[15:0] + t[16];
end
endfunction
always @* begin
state_next = STATE_IDLE;
s_ip_hdr_ready_next = 1'b0;
s_ip_payload_axis_tready_next = 1'b0;
store_ip_hdr = 1'b0;
store_last_word = 1'b0;
hdr_ptr_next = hdr_ptr_reg;
word_count_next = word_count_reg;
hdr_sum_next = hdr_sum_reg;
m_eth_hdr_valid_next = m_eth_hdr_valid_reg && !m_eth_hdr_ready;
error_payload_early_termination_next = 1'b0;
m_eth_payload_axis_tdata_int = 8'd0;
m_eth_payload_axis_tvalid_int = 1'b0;
m_eth_payload_axis_tlast_int = 1'b0;
m_eth_payload_axis_tuser_int = 1'b0;
case (state_reg)
STATE_IDLE: begin
// idle state - wait for data
hdr_ptr_next = 6'd0;
s_ip_hdr_ready_next = !m_eth_hdr_valid_next;
if (s_ip_hdr_ready && s_ip_hdr_valid) begin
store_ip_hdr = 1'b1;
s_ip_hdr_ready_next = 1'b0;
m_eth_hdr_valid_next = 1'b1;
if (m_eth_payload_axis_tready_int_reg) begin
m_eth_payload_axis_tvalid_int = 1'b1;
m_eth_payload_axis_tdata_int = {4'd4, 4'd5}; // ip_version, ip_ihl
hdr_ptr_next = 6'd1;
end
state_next = STATE_WRITE_HEADER;
end else begin
state_next = STATE_IDLE;
end
end
STATE_WRITE_HEADER: begin
// write header
word_count_next = ip_length_reg - 5*4;
if (m_eth_payload_axis_tready_int_reg) begin
hdr_ptr_next = hdr_ptr_reg + 6'd1;
m_eth_payload_axis_tvalid_int = 1;
state_next = STATE_WRITE_HEADER;
case (hdr_ptr_reg)
6'h00: begin
m_eth_payload_axis_tdata_int = {4'd4, 4'd5}; // ip_version, ip_ihl
end
6'h01: begin
m_eth_payload_axis_tdata_int = {ip_dscp_reg, ip_ecn_reg};
hdr_sum_next = {4'd4, 4'd5, ip_dscp_reg, ip_ecn_reg};
end
6'h02: begin
m_eth_payload_axis_tdata_int = ip_length_reg[15: 8];
hdr_sum_next = add1c16b(hdr_sum_reg, ip_length_reg);
end
6'h03: begin
m_eth_payload_axis_tdata_int = ip_length_reg[ 7: 0];
hdr_sum_next = add1c16b(hdr_sum_reg, ip_identification_reg);
end
6'h04: begin
m_eth_payload_axis_tdata_int = ip_identification_reg[15: 8];
hdr_sum_next = add1c16b(hdr_sum_reg, {ip_flags_reg, ip_fragment_offset_reg});
end
6'h05: begin
m_eth_payload_axis_tdata_int = ip_identification_reg[ 7: 0];
hdr_sum_next = add1c16b(hdr_sum_reg, {ip_ttl_reg, ip_protocol_reg});
end
6'h06: begin
m_eth_payload_axis_tdata_int = {ip_flags_reg, ip_fragment_offset_reg[12:8]};
hdr_sum_next = add1c16b(hdr_sum_reg, ip_source_ip_reg[31:16]);
end
6'h07: begin
m_eth_payload_axis_tdata_int = ip_fragment_offset_reg[ 7: 0];
hdr_sum_next = add1c16b(hdr_sum_reg, ip_source_ip_reg[15:0]);
end
6'h08: begin
m_eth_payload_axis_tdata_int = ip_ttl_reg;
hdr_sum_next = add1c16b(hdr_sum_reg, ip_dest_ip_reg[31:16]);
end
6'h09: begin
m_eth_payload_axis_tdata_int = ip_protocol_reg;
hdr_sum_next = add1c16b(hdr_sum_reg, ip_dest_ip_reg[15:0]);
end
6'h0A: m_eth_payload_axis_tdata_int = ~hdr_sum_reg[15: 8];
6'h0B: m_eth_payload_axis_tdata_int = ~hdr_sum_reg[ 7: 0];
6'h0C: m_eth_payload_axis_tdata_int = ip_source_ip_reg[31:24];
6'h0D: m_eth_payload_axis_tdata_int = ip_source_ip_reg[23:16];
6'h0E: m_eth_payload_axis_tdata_int = ip_source_ip_reg[15: 8];
6'h0F: m_eth_payload_axis_tdata_int = ip_source_ip_reg[ 7: 0];
6'h10: m_eth_payload_axis_tdata_int = ip_dest_ip_reg[31:24];
6'h11: m_eth_payload_axis_tdata_int = ip_dest_ip_reg[23:16];
6'h12: m_eth_payload_axis_tdata_int = ip_dest_ip_reg[15: 8];
6'h13: begin
m_eth_payload_axis_tdata_int = ip_dest_ip_reg[ 7: 0];
s_ip_payload_axis_tready_next = m_eth_payload_axis_tready_int_early;
state_next = STATE_WRITE_PAYLOAD;
end
endcase
end else begin
state_next = STATE_WRITE_HEADER;
end
end
STATE_WRITE_PAYLOAD: begin
// write payload
s_ip_payload_axis_tready_next = m_eth_payload_axis_tready_int_early;
m_eth_payload_axis_tdata_int = s_ip_payload_axis_tdata;
m_eth_payload_axis_tvalid_int = s_ip_payload_axis_tvalid;
m_eth_payload_axis_tlast_int = s_ip_payload_axis_tlast;
m_eth_payload_axis_tuser_int = s_ip_payload_axis_tuser;
if (s_ip_payload_axis_tready && s_ip_payload_axis_tvalid) begin
// word transfer through
word_count_next = word_count_reg - 6'd1;
if (s_ip_payload_axis_tlast) begin
if (word_count_reg != 16'd1) begin
// end of frame, but length does not match
m_eth_payload_axis_tuser_int = 1'b1;
error_payload_early_termination_next = 1'b1;
end
s_ip_hdr_ready_next = !m_eth_hdr_valid_next;
s_ip_payload_axis_tready_next = 1'b0;
state_next = STATE_IDLE;
end else begin
if (word_count_reg == 16'd1) begin
store_last_word = 1'b1;
m_eth_payload_axis_tvalid_int = 1'b0;
state_next = STATE_WRITE_PAYLOAD_LAST;
end else begin
state_next = STATE_WRITE_PAYLOAD;
end
end
end else begin
state_next = STATE_WRITE_PAYLOAD;
end
end
STATE_WRITE_PAYLOAD_LAST: begin
// read and discard until end of frame
s_ip_payload_axis_tready_next = m_eth_payload_axis_tready_int_early;
m_eth_payload_axis_tdata_int = last_word_data_reg;
m_eth_payload_axis_tvalid_int = s_ip_payload_axis_tvalid && s_ip_payload_axis_tlast;
m_eth_payload_axis_tlast_int = s_ip_payload_axis_tlast;
m_eth_payload_axis_tuser_int = s_ip_payload_axis_tuser;
if (s_ip_payload_axis_tready && s_ip_payload_axis_tvalid) begin
if (s_ip_payload_axis_tlast) begin
s_ip_hdr_ready_next = !m_eth_hdr_valid_next;
s_ip_payload_axis_tready_next = 1'b0;
state_next = STATE_IDLE;
end else begin
state_next = STATE_WRITE_PAYLOAD_LAST;
end
end else begin
state_next = STATE_WRITE_PAYLOAD_LAST;
end
end
STATE_WAIT_LAST: begin
// read and discard until end of frame
s_ip_payload_axis_tready_next = 1'b1;
if (s_ip_payload_axis_tready && s_ip_payload_axis_tvalid) begin
if (s_ip_payload_axis_tlast) begin
s_ip_hdr_ready_next = !m_eth_hdr_valid_next;
s_ip_payload_axis_tready_next = 1'b0;
state_next = STATE_IDLE;
end else begin
state_next = STATE_WAIT_LAST;
end
end else begin
state_next = STATE_WAIT_LAST;
end
end
endcase
end
always @(posedge clk) begin
if (rst) begin
state_reg <= STATE_IDLE;
s_ip_hdr_ready_reg <= 1'b0;
s_ip_payload_axis_tready_reg <= 1'b0;
m_eth_hdr_valid_reg <= 1'b0;
busy_reg <= 1'b0;
error_payload_early_termination_reg <= 1'b0;
end else begin
state_reg <= state_next;
s_ip_hdr_ready_reg <= s_ip_hdr_ready_next;
s_ip_payload_axis_tready_reg <= s_ip_payload_axis_tready_next;
m_eth_hdr_valid_reg <= m_eth_hdr_valid_next;
busy_reg <= state_next != STATE_IDLE;
error_payload_early_termination_reg <= error_payload_early_termination_next;
end
hdr_ptr_reg <= hdr_ptr_next;
word_count_reg <= word_count_next;
hdr_sum_reg <= hdr_sum_next;
// datapath
if (store_ip_hdr) begin
m_eth_dest_mac_reg <= s_eth_dest_mac;
m_eth_src_mac_reg <= s_eth_src_mac;
m_eth_type_reg <= s_eth_type;
ip_dscp_reg <= s_ip_dscp;
ip_ecn_reg <= s_ip_ecn;
ip_length_reg <= s_ip_length;
ip_identification_reg <= s_ip_identification;
ip_flags_reg <= s_ip_flags;
ip_fragment_offset_reg <= s_ip_fragment_offset;
ip_ttl_reg <= s_ip_ttl;
ip_protocol_reg <= s_ip_protocol;
ip_source_ip_reg <= s_ip_source_ip;
ip_dest_ip_reg <= s_ip_dest_ip;
end
if (store_last_word) begin
last_word_data_reg <= m_eth_payload_axis_tdata_int;
end
end
// output datapath logic
reg [7:0] m_eth_payload_axis_tdata_reg = 8'd0;
reg m_eth_payload_axis_tvalid_reg = 1'b0, m_eth_payload_axis_tvalid_next;
reg m_eth_payload_axis_tlast_reg = 1'b0;
reg m_eth_payload_axis_tuser_reg = 1'b0;
reg [7:0] temp_m_eth_payload_axis_tdata_reg = 8'd0;
reg temp_m_eth_payload_axis_tvalid_reg = 1'b0, temp_m_eth_payload_axis_tvalid_next;
reg temp_m_eth_payload_axis_tlast_reg = 1'b0;
reg temp_m_eth_payload_axis_tuser_reg = 1'b0;
// datapath control
reg store_eth_payload_int_to_output;
reg store_eth_payload_int_to_temp;
reg store_eth_payload_axis_temp_to_output;
assign m_eth_payload_axis_tdata = m_eth_payload_axis_tdata_reg;
assign m_eth_payload_axis_tvalid = m_eth_payload_axis_tvalid_reg;
assign m_eth_payload_axis_tlast = m_eth_payload_axis_tlast_reg;
assign m_eth_payload_axis_tuser = m_eth_payload_axis_tuser_reg;
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
assign m_eth_payload_axis_tready_int_early = m_eth_payload_axis_tready || (!temp_m_eth_payload_axis_tvalid_reg && (!m_eth_payload_axis_tvalid_reg || !m_eth_payload_axis_tvalid_int));
always @* begin
// transfer sink ready state to source
m_eth_payload_axis_tvalid_next = m_eth_payload_axis_tvalid_reg;
temp_m_eth_payload_axis_tvalid_next = temp_m_eth_payload_axis_tvalid_reg;
store_eth_payload_int_to_output = 1'b0;
store_eth_payload_int_to_temp = 1'b0;
store_eth_payload_axis_temp_to_output = 1'b0;
if (m_eth_payload_axis_tready_int_reg) begin
// input is ready
if (m_eth_payload_axis_tready || !m_eth_payload_axis_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output
m_eth_payload_axis_tvalid_next = m_eth_payload_axis_tvalid_int;
store_eth_payload_int_to_output = 1'b1;
end else begin
// output is not ready, store input in temp
temp_m_eth_payload_axis_tvalid_next = m_eth_payload_axis_tvalid_int;
store_eth_payload_int_to_temp = 1'b1;
end
end else if (m_eth_payload_axis_tready) begin
// input is not ready, but output is ready
m_eth_payload_axis_tvalid_next = temp_m_eth_payload_axis_tvalid_reg;
temp_m_eth_payload_axis_tvalid_next = 1'b0;
store_eth_payload_axis_temp_to_output = 1'b1;
end
end
always @(posedge clk) begin
if (rst) begin
m_eth_payload_axis_tvalid_reg <= 1'b0;
m_eth_payload_axis_tready_int_reg <= 1'b0;
temp_m_eth_payload_axis_tvalid_reg <= 1'b0;
end else begin
m_eth_payload_axis_tvalid_reg <= m_eth_payload_axis_tvalid_next;
m_eth_payload_axis_tready_int_reg <= m_eth_payload_axis_tready_int_early;
temp_m_eth_payload_axis_tvalid_reg <= temp_m_eth_payload_axis_tvalid_next;
end
// datapath
if (store_eth_payload_int_to_output) begin
m_eth_payload_axis_tdata_reg <= m_eth_payload_axis_tdata_int;
m_eth_payload_axis_tlast_reg <= m_eth_payload_axis_tlast_int;
m_eth_payload_axis_tuser_reg <= m_eth_payload_axis_tuser_int;
end else if (store_eth_payload_axis_temp_to_output) begin
m_eth_payload_axis_tdata_reg <= temp_m_eth_payload_axis_tdata_reg;
m_eth_payload_axis_tlast_reg <= temp_m_eth_payload_axis_tlast_reg;
m_eth_payload_axis_tuser_reg <= temp_m_eth_payload_axis_tuser_reg;
end
if (store_eth_payload_int_to_temp) begin
temp_m_eth_payload_axis_tdata_reg <= m_eth_payload_axis_tdata_int;
temp_m_eth_payload_axis_tlast_reg <= m_eth_payload_axis_tlast_int;
temp_m_eth_payload_axis_tuser_reg <= m_eth_payload_axis_tuser_int;
end
end
endmodule
/*
Copyright (c) 2014-2018 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* IP ethernet frame transmitter (IP frame in, Ethernet frame out, 64 bit datapath)
*/
module ip_eth_tx_64
(
input wire clk,
input wire rst,
/*
* IP frame input
*/
input wire s_ip_hdr_valid,
output wire s_ip_hdr_ready,
input wire [47:0] s_eth_dest_mac,
input wire [47:0] s_eth_src_mac,
input wire [15:0] s_eth_type,
input wire [5:0] s_ip_dscp,
input wire [1:0] s_ip_ecn,
input wire [15:0] s_ip_length,
input wire [15:0] s_ip_identification,
input wire [2:0] s_ip_flags,
input wire [12:0] s_ip_fragment_offset,
input wire [7:0] s_ip_ttl,
input wire [7:0] s_ip_protocol,
input wire [31:0] s_ip_source_ip,
input wire [31:0] s_ip_dest_ip,
input wire [63:0] s_ip_payload_axis_tdata,
input wire [7:0] s_ip_payload_axis_tkeep,
input wire s_ip_payload_axis_tvalid,
output wire s_ip_payload_axis_tready,
input wire s_ip_payload_axis_tlast,
input wire s_ip_payload_axis_tuser,
/*
* Ethernet frame output
*/
output wire m_eth_hdr_valid,
input wire m_eth_hdr_ready,
output wire [47:0] m_eth_dest_mac,
output wire [47:0] m_eth_src_mac,
output wire [15:0] m_eth_type,
output wire [63:0] m_eth_payload_axis_tdata,
output wire [7:0] m_eth_payload_axis_tkeep,
output wire m_eth_payload_axis_tvalid,
input wire m_eth_payload_axis_tready,
output wire m_eth_payload_axis_tlast,
output wire m_eth_payload_axis_tuser,
/*
* Status signals
*/
output wire busy,
output wire error_payload_early_termination
);
/*
IP Frame
Field Length
Destination MAC address 6 octets
Source MAC address 6 octets
Ethertype (0x0800) 2 octets
Version (4) 4 bits
IHL (5-15) 4 bits
DSCP (0) 6 bits
ECN (0) 2 bits
length 2 octets
identification (0?) 2 octets
flags (010) 3 bits
fragment offset (0) 13 bits
time to live (64?) 1 octet
protocol 1 octet
header checksum 2 octets
source IP 4 octets
destination IP 4 octets
options (IHL-5)*4 octets
payload length octets
This module receives an IP frame with header fields in parallel along with the
payload in an AXI stream, combines the header with the payload, passes through
the Ethernet headers, and transmits the complete Ethernet payload on an AXI
interface.
*/
localparam [2:0]
STATE_IDLE = 3'd0,
STATE_WRITE_HEADER = 3'd1,
STATE_WRITE_HEADER_LAST = 3'd2,
STATE_WRITE_PAYLOAD = 3'd3,
STATE_WRITE_PAYLOAD_LAST = 3'd4,
STATE_WAIT_LAST = 3'd5;
reg [2:0] state_reg = STATE_IDLE, state_next;
// datapath control signals
reg store_ip_hdr;
reg store_last_word;
reg [5:0] hdr_ptr_reg = 6'd0, hdr_ptr_next;
reg [15:0] word_count_reg = 16'd0, word_count_next;
reg flush_save;
reg transfer_in_save;
reg [19:0] hdr_sum_temp;
reg [19:0] hdr_sum_reg = 20'd0, hdr_sum_next;
reg [63:0] last_word_data_reg = 64'd0;
reg [7:0] last_word_keep_reg = 8'd0;
reg [5:0] ip_dscp_reg = 6'd0;
reg [1:0] ip_ecn_reg = 2'd0;
reg [15:0] ip_length_reg = 16'd0;
reg [15:0] ip_identification_reg = 16'd0;
reg [2:0] ip_flags_reg = 3'd0;
reg [12:0] ip_fragment_offset_reg = 13'd0;
reg [7:0] ip_ttl_reg = 8'd0;
reg [7:0] ip_protocol_reg = 8'd0;
reg [31:0] ip_source_ip_reg = 32'd0;
reg [31:0] ip_dest_ip_reg = 32'd0;
reg s_ip_hdr_ready_reg = 1'b0, s_ip_hdr_ready_next;
reg s_ip_payload_axis_tready_reg = 1'b0, s_ip_payload_axis_tready_next;
reg m_eth_hdr_valid_reg = 1'b0, m_eth_hdr_valid_next;
reg [47:0] m_eth_dest_mac_reg = 48'd0;
reg [47:0] m_eth_src_mac_reg = 48'd0;
reg [15:0] m_eth_type_reg = 16'd0;
reg busy_reg = 1'b0;
reg error_payload_early_termination_reg = 1'b0, error_payload_early_termination_next;
reg [63:0] save_ip_payload_axis_tdata_reg = 64'd0;
reg [7:0] save_ip_payload_axis_tkeep_reg = 8'd0;
reg save_ip_payload_axis_tlast_reg = 1'b0;
reg save_ip_payload_axis_tuser_reg = 1'b0;
reg [63:0] shift_ip_payload_axis_tdata;
reg [7:0] shift_ip_payload_axis_tkeep;
reg shift_ip_payload_axis_tvalid;
reg shift_ip_payload_axis_tlast;
reg shift_ip_payload_axis_tuser;
reg shift_ip_payload_s_tready;
reg shift_ip_payload_extra_cycle_reg = 1'b0;
// internal datapath
reg [63:0] m_eth_payload_axis_tdata_int;
reg [7:0] m_eth_payload_axis_tkeep_int;
reg m_eth_payload_axis_tvalid_int;
reg m_eth_payload_axis_tready_int_reg = 1'b0;
reg m_eth_payload_axis_tlast_int;
reg m_eth_payload_axis_tuser_int;
wire m_eth_payload_axis_tready_int_early;
assign s_ip_hdr_ready = s_ip_hdr_ready_reg;
assign s_ip_payload_axis_tready = s_ip_payload_axis_tready_reg;
assign m_eth_hdr_valid = m_eth_hdr_valid_reg;
assign m_eth_dest_mac = m_eth_dest_mac_reg;
assign m_eth_src_mac = m_eth_src_mac_reg;
assign m_eth_type = m_eth_type_reg;
assign busy = busy_reg;
assign error_payload_early_termination = error_payload_early_termination_reg;
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
function [7:0] count2keep;
input [3:0] k;
case (k)
4'd0: count2keep = 8'b00000000;
4'd1: count2keep = 8'b00000001;
4'd2: count2keep = 8'b00000011;
4'd3: count2keep = 8'b00000111;
4'd4: count2keep = 8'b00001111;
4'd5: count2keep = 8'b00011111;
4'd6: count2keep = 8'b00111111;
4'd7: count2keep = 8'b01111111;
4'd8: count2keep = 8'b11111111;
endcase
endfunction
always @* begin
shift_ip_payload_axis_tdata[31:0] = save_ip_payload_axis_tdata_reg[63:32];
shift_ip_payload_axis_tkeep[3:0] = save_ip_payload_axis_tkeep_reg[7:4];
if (shift_ip_payload_extra_cycle_reg) begin
shift_ip_payload_axis_tdata[63:32] = 32'd0;
shift_ip_payload_axis_tkeep[7:4] = 4'd0;
shift_ip_payload_axis_tvalid = 1'b1;
shift_ip_payload_axis_tlast = save_ip_payload_axis_tlast_reg;
shift_ip_payload_axis_tuser = save_ip_payload_axis_tuser_reg;
shift_ip_payload_s_tready = flush_save;
end else begin
shift_ip_payload_axis_tdata[63:32] = s_ip_payload_axis_tdata[31:0];
shift_ip_payload_axis_tkeep[7:4] = s_ip_payload_axis_tkeep[3:0];
shift_ip_payload_axis_tvalid = s_ip_payload_axis_tvalid;
shift_ip_payload_axis_tlast = (s_ip_payload_axis_tlast && (s_ip_payload_axis_tkeep[7:4] == 0));
shift_ip_payload_axis_tuser = (s_ip_payload_axis_tuser && (s_ip_payload_axis_tkeep[7:4] == 0));
shift_ip_payload_s_tready = !(s_ip_payload_axis_tlast && s_ip_payload_axis_tvalid && transfer_in_save) && !save_ip_payload_axis_tlast_reg;
end
end
always @* begin
state_next = STATE_IDLE;
s_ip_hdr_ready_next = 1'b0;
s_ip_payload_axis_tready_next = 1'b0;
store_ip_hdr = 1'b0;
store_last_word = 1'b0;
flush_save = 1'b0;
transfer_in_save = 1'b0;
hdr_ptr_next = hdr_ptr_reg;
word_count_next = word_count_reg;
hdr_sum_temp = 20'd0;
hdr_sum_next = hdr_sum_reg;
m_eth_hdr_valid_next = m_eth_hdr_valid_reg && !m_eth_hdr_ready;
error_payload_early_termination_next = 1'b0;
m_eth_payload_axis_tdata_int = 1'b0;
m_eth_payload_axis_tkeep_int = 1'b0;
m_eth_payload_axis_tvalid_int = 1'b0;
m_eth_payload_axis_tlast_int = 1'b0;
m_eth_payload_axis_tuser_int = 1'b0;
case (state_reg)
STATE_IDLE: begin
// idle state - wait for data
hdr_ptr_next = 6'd0;
flush_save = 1'b1;
s_ip_hdr_ready_next = !m_eth_hdr_valid_next;
if (s_ip_hdr_ready && s_ip_hdr_valid) begin
store_ip_hdr = 1'b1;
hdr_sum_next = {4'd4, 4'd5, s_ip_dscp, s_ip_ecn} +
s_ip_length +
s_ip_identification +
{s_ip_flags, s_ip_fragment_offset} +
{s_ip_ttl, s_ip_protocol} +
s_ip_source_ip[31:16] +
s_ip_source_ip[15: 0] +
s_ip_dest_ip[31:16] +
s_ip_dest_ip[15: 0];
s_ip_hdr_ready_next = 1'b0;
m_eth_hdr_valid_next = 1'b1;
if (m_eth_payload_axis_tready_int_reg) begin
m_eth_payload_axis_tvalid_int = 1'b1;
m_eth_payload_axis_tdata_int[ 7: 0] = {4'd4, 4'd5}; // ip_version, ip_ihl
m_eth_payload_axis_tdata_int[15: 8] = {s_ip_dscp, s_ip_ecn};
m_eth_payload_axis_tdata_int[23:16] = s_ip_length[15: 8];
m_eth_payload_axis_tdata_int[31:24] = s_ip_length[ 7: 0];
m_eth_payload_axis_tdata_int[39:32] = s_ip_identification[15: 8];
m_eth_payload_axis_tdata_int[47:40] = s_ip_identification[ 7: 0];
m_eth_payload_axis_tdata_int[55:48] = {s_ip_flags, s_ip_fragment_offset[12: 8]};
m_eth_payload_axis_tdata_int[63:56] = s_ip_fragment_offset[ 7: 0];
m_eth_payload_axis_tkeep_int = 8'hff;
hdr_ptr_next = 6'd8;
end
state_next = STATE_WRITE_HEADER;
end else begin
state_next = STATE_IDLE;
end
end
STATE_WRITE_HEADER: begin
// write header
word_count_next = ip_length_reg - 5*4 + 4;
if (m_eth_payload_axis_tready_int_reg) begin
hdr_ptr_next = hdr_ptr_reg + 6'd8;
m_eth_payload_axis_tvalid_int = 1'b1;
state_next = STATE_WRITE_HEADER;
case (hdr_ptr_reg)
6'h00: begin
m_eth_payload_axis_tdata_int[ 7: 0] = {4'd4, 4'd5}; // ip_version, ip_ihl
m_eth_payload_axis_tdata_int[15: 8] = {ip_dscp_reg, ip_ecn_reg};
m_eth_payload_axis_tdata_int[23:16] = ip_length_reg[15: 8];
m_eth_payload_axis_tdata_int[31:24] = ip_length_reg[ 7: 0];
m_eth_payload_axis_tdata_int[39:32] = ip_identification_reg[15: 8];
m_eth_payload_axis_tdata_int[47:40] = ip_identification_reg[ 7: 0];
m_eth_payload_axis_tdata_int[55:48] = {ip_flags_reg, ip_fragment_offset_reg[12: 8]};
m_eth_payload_axis_tdata_int[63:56] = ip_fragment_offset_reg[ 7: 0];
m_eth_payload_axis_tkeep_int = 8'hff;
end
6'h08: begin
hdr_sum_temp = hdr_sum_reg[15:0] + hdr_sum_reg[19:16];
hdr_sum_temp = hdr_sum_temp[15:0] + hdr_sum_temp[16];
m_eth_payload_axis_tdata_int[ 7: 0] = ip_ttl_reg;
m_eth_payload_axis_tdata_int[15: 8] = ip_protocol_reg;
m_eth_payload_axis_tdata_int[23:16] = ~hdr_sum_temp[15: 8];
m_eth_payload_axis_tdata_int[31:24] = ~hdr_sum_temp[ 7: 0];
m_eth_payload_axis_tdata_int[39:32] = ip_source_ip_reg[31:24];
m_eth_payload_axis_tdata_int[47:40] = ip_source_ip_reg[23:16];
m_eth_payload_axis_tdata_int[55:48] = ip_source_ip_reg[15: 8];
m_eth_payload_axis_tdata_int[63:56] = ip_source_ip_reg[ 7: 0];
m_eth_payload_axis_tkeep_int = 8'hff;
s_ip_payload_axis_tready_next = m_eth_payload_axis_tready_int_early;
state_next = STATE_WRITE_HEADER_LAST;
end
endcase
end else begin
state_next = STATE_WRITE_HEADER;
end
end
STATE_WRITE_HEADER_LAST: begin
// last header word requires first payload word; process accordingly
s_ip_payload_axis_tready_next = m_eth_payload_axis_tready_int_early && shift_ip_payload_s_tready;
if (s_ip_payload_axis_tready && s_ip_payload_axis_tvalid) begin
m_eth_payload_axis_tvalid_int = 1'b1;
transfer_in_save = 1'b1;
m_eth_payload_axis_tdata_int[ 7: 0] = ip_dest_ip_reg[31:24];
m_eth_payload_axis_tdata_int[15: 8] = ip_dest_ip_reg[23:16];
m_eth_payload_axis_tdata_int[23:16] = ip_dest_ip_reg[15: 8];
m_eth_payload_axis_tdata_int[31:24] = ip_dest_ip_reg[ 7: 0];
m_eth_payload_axis_tdata_int[39:32] = shift_ip_payload_axis_tdata[39:32];
m_eth_payload_axis_tdata_int[47:40] = shift_ip_payload_axis_tdata[47:40];
m_eth_payload_axis_tdata_int[55:48] = shift_ip_payload_axis_tdata[55:48];
m_eth_payload_axis_tdata_int[63:56] = shift_ip_payload_axis_tdata[63:56];
m_eth_payload_axis_tkeep_int = {shift_ip_payload_axis_tkeep[7:4], 4'hF};
m_eth_payload_axis_tlast_int = shift_ip_payload_axis_tlast;
m_eth_payload_axis_tuser_int = shift_ip_payload_axis_tuser;
word_count_next = word_count_reg - 16'd8;
if (keep2count(m_eth_payload_axis_tkeep_int) >= word_count_reg) begin
// have entire payload
m_eth_payload_axis_tkeep_int = count2keep(word_count_reg);
if (shift_ip_payload_axis_tlast) begin
s_ip_hdr_ready_next = !m_eth_hdr_valid_next;
s_ip_payload_axis_tready_next = 1'b0;
state_next = STATE_IDLE;
end else begin
store_last_word = 1'b1;
s_ip_payload_axis_tready_next = shift_ip_payload_s_tready;
m_eth_payload_axis_tvalid_int = 1'b0;
state_next = STATE_WRITE_PAYLOAD_LAST;
end
end else begin
if (shift_ip_payload_axis_tlast) begin
// end of frame, but length does not match
error_payload_early_termination_next = 1'b1;
s_ip_payload_axis_tready_next = shift_ip_payload_s_tready;
m_eth_payload_axis_tuser_int = 1'b1;
state_next = STATE_WAIT_LAST;
end else begin
state_next = STATE_WRITE_PAYLOAD;
end
end
end else begin
state_next = STATE_WRITE_HEADER_LAST;
end
end
STATE_WRITE_PAYLOAD: begin
// write payload
s_ip_payload_axis_tready_next = m_eth_payload_axis_tready_int_early && shift_ip_payload_s_tready;
m_eth_payload_axis_tdata_int = shift_ip_payload_axis_tdata;
m_eth_payload_axis_tkeep_int = shift_ip_payload_axis_tkeep;
m_eth_payload_axis_tvalid_int = shift_ip_payload_axis_tvalid;
m_eth_payload_axis_tlast_int = shift_ip_payload_axis_tlast;
m_eth_payload_axis_tuser_int = shift_ip_payload_axis_tuser;
store_last_word = 1'b1;
if (m_eth_payload_axis_tready_int_reg && shift_ip_payload_axis_tvalid) begin
// word transfer through
word_count_next = word_count_reg - 16'd8;
transfer_in_save = 1'b1;
if (word_count_reg <= 8) begin
// have entire payload
m_eth_payload_axis_tkeep_int = count2keep(word_count_reg);
if (shift_ip_payload_axis_tlast) begin
if (keep2count(shift_ip_payload_axis_tkeep) < word_count_reg[4:0]) begin
// end of frame, but length does not match
error_payload_early_termination_next = 1'b1;
m_eth_payload_axis_tuser_int = 1'b1;
end
s_ip_payload_axis_tready_next = 1'b0;
flush_save = 1'b1;
s_ip_hdr_ready_next = !m_eth_hdr_valid_next;
state_next = STATE_IDLE;
end else begin
m_eth_payload_axis_tvalid_int = 1'b0;
state_next = STATE_WRITE_PAYLOAD_LAST;
end
end else begin
if (shift_ip_payload_axis_tlast) begin
// end of frame, but length does not match
error_payload_early_termination_next = 1'b1;
m_eth_payload_axis_tuser_int = 1'b1;
s_ip_payload_axis_tready_next = 1'b0;
flush_save = 1'b1;
s_ip_hdr_ready_next = !m_eth_hdr_valid_next;
state_next = STATE_IDLE;
end else begin
state_next = STATE_WRITE_PAYLOAD;
end
end
end else begin
state_next = STATE_WRITE_PAYLOAD;
end
end
STATE_WRITE_PAYLOAD_LAST: begin
// read and discard until end of frame
s_ip_payload_axis_tready_next = m_eth_payload_axis_tready_int_early && shift_ip_payload_s_tready;
m_eth_payload_axis_tdata_int = last_word_data_reg;
m_eth_payload_axis_tkeep_int = last_word_keep_reg;
m_eth_payload_axis_tvalid_int = shift_ip_payload_axis_tvalid && shift_ip_payload_axis_tlast;
m_eth_payload_axis_tlast_int = shift_ip_payload_axis_tlast;
m_eth_payload_axis_tuser_int = shift_ip_payload_axis_tuser;
if (m_eth_payload_axis_tready_int_reg && shift_ip_payload_axis_tvalid) begin
transfer_in_save = 1'b1;
if (shift_ip_payload_axis_tlast) begin
s_ip_hdr_ready_next = !m_eth_hdr_valid_next;
s_ip_payload_axis_tready_next = 1'b0;
state_next = STATE_IDLE;
end else begin
state_next = STATE_WRITE_PAYLOAD_LAST;
end
end else begin
state_next = STATE_WRITE_PAYLOAD_LAST;
end
end
STATE_WAIT_LAST: begin
// read and discard until end of frame
s_ip_payload_axis_tready_next = shift_ip_payload_s_tready;
if (shift_ip_payload_axis_tvalid) begin
transfer_in_save = 1'b1;
if (shift_ip_payload_axis_tlast) begin
s_ip_hdr_ready_next = !m_eth_hdr_valid_next;
s_ip_payload_axis_tready_next = 1'b0;
state_next = STATE_IDLE;
end else begin
state_next = STATE_WAIT_LAST;
end
end else begin
state_next = STATE_WAIT_LAST;
end
end
endcase
end
always @(posedge clk) begin
if (rst) begin
state_reg <= STATE_IDLE;
s_ip_hdr_ready_reg <= 1'b0;
s_ip_payload_axis_tready_reg <= 1'b0;
m_eth_hdr_valid_reg <= 1'b0;
save_ip_payload_axis_tlast_reg <= 1'b0;
shift_ip_payload_extra_cycle_reg <= 1'b0;
busy_reg <= 1'b0;
error_payload_early_termination_reg <= 1'b0;
end else begin
state_reg <= state_next;
s_ip_hdr_ready_reg <= s_ip_hdr_ready_next;
s_ip_payload_axis_tready_reg <= s_ip_payload_axis_tready_next;
m_eth_hdr_valid_reg <= m_eth_hdr_valid_next;
busy_reg <= state_next != STATE_IDLE;
error_payload_early_termination_reg <= error_payload_early_termination_next;
if (flush_save) begin
save_ip_payload_axis_tlast_reg <= 1'b0;
shift_ip_payload_extra_cycle_reg <= 1'b0;
end else if (transfer_in_save) begin
save_ip_payload_axis_tlast_reg <= s_ip_payload_axis_tlast;
shift_ip_payload_extra_cycle_reg <= s_ip_payload_axis_tlast && (s_ip_payload_axis_tkeep[7:4] != 0);
end
end
hdr_ptr_reg <= hdr_ptr_next;
word_count_reg <= word_count_next;
hdr_sum_reg <= hdr_sum_next;
// datapath
if (store_ip_hdr) begin
m_eth_dest_mac_reg <= s_eth_dest_mac;
m_eth_src_mac_reg <= s_eth_src_mac;
m_eth_type_reg <= s_eth_type;
ip_dscp_reg <= s_ip_dscp;
ip_ecn_reg <= s_ip_ecn;
ip_length_reg <= s_ip_length;
ip_identification_reg <= s_ip_identification;
ip_flags_reg <= s_ip_flags;
ip_fragment_offset_reg <= s_ip_fragment_offset;
ip_ttl_reg <= s_ip_ttl;
ip_protocol_reg <= s_ip_protocol;
ip_source_ip_reg <= s_ip_source_ip;
ip_dest_ip_reg <= s_ip_dest_ip;
end
if (store_last_word) begin
last_word_data_reg <= m_eth_payload_axis_tdata_int;
last_word_keep_reg <= m_eth_payload_axis_tkeep_int;
end
if (transfer_in_save) begin
save_ip_payload_axis_tdata_reg <= s_ip_payload_axis_tdata;
save_ip_payload_axis_tkeep_reg <= s_ip_payload_axis_tkeep;
save_ip_payload_axis_tuser_reg <= s_ip_payload_axis_tuser;
end
end
// output datapath logic
reg [63:0] m_eth_payload_axis_tdata_reg = 64'd0;
reg [7:0] m_eth_payload_axis_tkeep_reg = 8'd0;
reg m_eth_payload_axis_tvalid_reg = 1'b0, m_eth_payload_axis_tvalid_next;
reg m_eth_payload_axis_tlast_reg = 1'b0;
reg m_eth_payload_axis_tuser_reg = 1'b0;
reg [63:0] temp_m_eth_payload_axis_tdata_reg = 64'd0;
reg [7:0] temp_m_eth_payload_axis_tkeep_reg = 8'd0;
reg temp_m_eth_payload_axis_tvalid_reg = 1'b0, temp_m_eth_payload_axis_tvalid_next;
reg temp_m_eth_payload_axis_tlast_reg = 1'b0;
reg temp_m_eth_payload_axis_tuser_reg = 1'b0;
// datapath control
reg store_eth_payload_int_to_output;
reg store_eth_payload_int_to_temp;
reg store_eth_payload_axis_temp_to_output;
assign m_eth_payload_axis_tdata = m_eth_payload_axis_tdata_reg;
assign m_eth_payload_axis_tkeep = m_eth_payload_axis_tkeep_reg;
assign m_eth_payload_axis_tvalid = m_eth_payload_axis_tvalid_reg;
assign m_eth_payload_axis_tlast = m_eth_payload_axis_tlast_reg;
assign m_eth_payload_axis_tuser = m_eth_payload_axis_tuser_reg;
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
assign m_eth_payload_axis_tready_int_early = m_eth_payload_axis_tready | (!temp_m_eth_payload_axis_tvalid_reg && (!m_eth_payload_axis_tvalid_reg | !m_eth_payload_axis_tvalid_int));
always @* begin
// transfer sink ready state to source
m_eth_payload_axis_tvalid_next = m_eth_payload_axis_tvalid_reg;
temp_m_eth_payload_axis_tvalid_next = temp_m_eth_payload_axis_tvalid_reg;
store_eth_payload_int_to_output = 1'b0;
store_eth_payload_int_to_temp = 1'b0;
store_eth_payload_axis_temp_to_output = 1'b0;
if (m_eth_payload_axis_tready_int_reg) begin
// input is ready
if (m_eth_payload_axis_tready | !m_eth_payload_axis_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output
m_eth_payload_axis_tvalid_next = m_eth_payload_axis_tvalid_int;
store_eth_payload_int_to_output = 1'b1;
end else begin
// output is not ready, store input in temp
temp_m_eth_payload_axis_tvalid_next = m_eth_payload_axis_tvalid_int;
store_eth_payload_int_to_temp = 1'b1;
end
end else if (m_eth_payload_axis_tready) begin
// input is not ready, but output is ready
m_eth_payload_axis_tvalid_next = temp_m_eth_payload_axis_tvalid_reg;
temp_m_eth_payload_axis_tvalid_next = 1'b0;
store_eth_payload_axis_temp_to_output = 1'b1;
end
end
always @(posedge clk) begin
if (rst) begin
m_eth_payload_axis_tvalid_reg <= 1'b0;
m_eth_payload_axis_tready_int_reg <= 1'b0;
temp_m_eth_payload_axis_tvalid_reg <= 1'b0;
end else begin
m_eth_payload_axis_tvalid_reg <= m_eth_payload_axis_tvalid_next;
m_eth_payload_axis_tready_int_reg <= m_eth_payload_axis_tready_int_early;
temp_m_eth_payload_axis_tvalid_reg <= temp_m_eth_payload_axis_tvalid_next;
end
// datapath
if (store_eth_payload_int_to_output) begin
m_eth_payload_axis_tdata_reg <= m_eth_payload_axis_tdata_int;
m_eth_payload_axis_tkeep_reg <= m_eth_payload_axis_tkeep_int;
m_eth_payload_axis_tlast_reg <= m_eth_payload_axis_tlast_int;
m_eth_payload_axis_tuser_reg <= m_eth_payload_axis_tuser_int;
end else if (store_eth_payload_axis_temp_to_output) begin
m_eth_payload_axis_tdata_reg <= temp_m_eth_payload_axis_tdata_reg;
m_eth_payload_axis_tkeep_reg <= temp_m_eth_payload_axis_tkeep_reg;
m_eth_payload_axis_tlast_reg <= temp_m_eth_payload_axis_tlast_reg;
m_eth_payload_axis_tuser_reg <= temp_m_eth_payload_axis_tuser_reg;
end
if (store_eth_payload_int_to_temp) begin
temp_m_eth_payload_axis_tdata_reg <= m_eth_payload_axis_tdata_int;
temp_m_eth_payload_axis_tkeep_reg <= m_eth_payload_axis_tkeep_int;
temp_m_eth_payload_axis_tlast_reg <= m_eth_payload_axis_tlast_int;
temp_m_eth_payload_axis_tuser_reg <= m_eth_payload_axis_tuser_int;
end
end
endmodule
/*
Copyright (c) 2014-2018 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* IP multiplexer
*/
module ip_mux #
(
parameter S_COUNT = 4,
parameter DATA_WIDTH = 8,
parameter KEEP_ENABLE = (DATA_WIDTH>8),
parameter KEEP_WIDTH = (DATA_WIDTH/8),
parameter ID_ENABLE = 0,
parameter ID_WIDTH = 8,
parameter DEST_ENABLE = 0,
parameter DEST_WIDTH = 8,
parameter USER_ENABLE = 1,
parameter USER_WIDTH = 1
)
(
input wire clk,
input wire rst,
/*
* IP frame inputs
*/
input wire [S_COUNT-1:0] s_ip_hdr_valid,
output wire [S_COUNT-1:0] s_ip_hdr_ready,
input wire [S_COUNT*48-1:0] s_eth_dest_mac,
input wire [S_COUNT*48-1:0] s_eth_src_mac,
input wire [S_COUNT*16-1:0] s_eth_type,
input wire [S_COUNT*4-1:0] s_ip_version,
input wire [S_COUNT*4-1:0] s_ip_ihl,
input wire [S_COUNT*6-1:0] s_ip_dscp,
input wire [S_COUNT*2-1:0] s_ip_ecn,
input wire [S_COUNT*16-1:0] s_ip_length,
input wire [S_COUNT*16-1:0] s_ip_identification,
input wire [S_COUNT*3-1:0] s_ip_flags,
input wire [S_COUNT*13-1:0] s_ip_fragment_offset,
input wire [S_COUNT*8-1:0] s_ip_ttl,
input wire [S_COUNT*8-1:0] s_ip_protocol,
input wire [S_COUNT*16-1:0] s_ip_header_checksum,
input wire [S_COUNT*32-1:0] s_ip_source_ip,
input wire [S_COUNT*32-1:0] s_ip_dest_ip,
input wire [S_COUNT*DATA_WIDTH-1:0] s_ip_payload_axis_tdata,
input wire [S_COUNT*KEEP_WIDTH-1:0] s_ip_payload_axis_tkeep,
input wire [S_COUNT-1:0] s_ip_payload_axis_tvalid,
output wire [S_COUNT-1:0] s_ip_payload_axis_tready,
input wire [S_COUNT-1:0] s_ip_payload_axis_tlast,
input wire [S_COUNT*ID_WIDTH-1:0] s_ip_payload_axis_tid,
input wire [S_COUNT*DEST_WIDTH-1:0] s_ip_payload_axis_tdest,
input wire [S_COUNT*USER_WIDTH-1:0] s_ip_payload_axis_tuser,
/*
* IP frame output
*/
output wire m_ip_hdr_valid,
input wire m_ip_hdr_ready,
output wire [47:0] m_eth_dest_mac,
output wire [47:0] m_eth_src_mac,
output wire [15:0] m_eth_type,
output wire [3:0] m_ip_version,
output wire [3:0] m_ip_ihl,
output wire [5:0] m_ip_dscp,
output wire [1:0] m_ip_ecn,
output wire [15:0] m_ip_length,
output wire [15:0] m_ip_identification,
output wire [2:0] m_ip_flags,
output wire [12:0] m_ip_fragment_offset,
output wire [7:0] m_ip_ttl,
output wire [7:0] m_ip_protocol,
output wire [15:0] m_ip_header_checksum,
output wire [31:0] m_ip_source_ip,
output wire [31:0] m_ip_dest_ip,
output wire [DATA_WIDTH-1:0] m_ip_payload_axis_tdata,
output wire [KEEP_WIDTH-1:0] m_ip_payload_axis_tkeep,
output wire m_ip_payload_axis_tvalid,
input wire m_ip_payload_axis_tready,
output wire m_ip_payload_axis_tlast,
output wire [ID_WIDTH-1:0] m_ip_payload_axis_tid,
output wire [DEST_WIDTH-1:0] m_ip_payload_axis_tdest,
output wire [USER_WIDTH-1:0] m_ip_payload_axis_tuser,
/*
* Control
*/
input wire enable,
input wire [$clog2(S_COUNT)-1:0] select
);
parameter CL_S_COUNT = $clog2(S_COUNT);
reg [CL_S_COUNT-1:0] select_reg = 2'd0, select_next;
reg frame_reg = 1'b0, frame_next;
reg [S_COUNT-1:0] s_ip_hdr_ready_reg = 0, s_ip_hdr_ready_next;
reg [S_COUNT-1:0] s_ip_payload_axis_tready_reg = 0, s_ip_payload_axis_tready_next;
reg m_ip_hdr_valid_reg = 1'b0, m_ip_hdr_valid_next;
reg [47:0] m_eth_dest_mac_reg = 48'd0, m_eth_dest_mac_next;
reg [47:0] m_eth_src_mac_reg = 48'd0, m_eth_src_mac_next;
reg [15:0] m_eth_type_reg = 16'd0, m_eth_type_next;
reg [3:0] m_ip_version_reg = 4'd0, m_ip_version_next;
reg [3:0] m_ip_ihl_reg = 4'd0, m_ip_ihl_next;
reg [5:0] m_ip_dscp_reg = 6'd0, m_ip_dscp_next;
reg [1:0] m_ip_ecn_reg = 2'd0, m_ip_ecn_next;
reg [15:0] m_ip_length_reg = 16'd0, m_ip_length_next;
reg [15:0] m_ip_identification_reg = 16'd0, m_ip_identification_next;
reg [2:0] m_ip_flags_reg = 3'd0, m_ip_flags_next;
reg [12:0] m_ip_fragment_offset_reg = 13'd0, m_ip_fragment_offset_next;
reg [7:0] m_ip_ttl_reg = 8'd0, m_ip_ttl_next;
reg [7:0] m_ip_protocol_reg = 8'd0, m_ip_protocol_next;
reg [15:0] m_ip_header_checksum_reg = 16'd0, m_ip_header_checksum_next;
reg [31:0] m_ip_source_ip_reg = 32'd0, m_ip_source_ip_next;
reg [31:0] m_ip_dest_ip_reg = 32'd0, m_ip_dest_ip_next;
// internal datapath
reg [DATA_WIDTH-1:0] m_ip_payload_axis_tdata_int;
reg [KEEP_WIDTH-1:0] m_ip_payload_axis_tkeep_int;
reg m_ip_payload_axis_tvalid_int;
reg m_ip_payload_axis_tready_int_reg = 1'b0;
reg m_ip_payload_axis_tlast_int;
reg [ID_WIDTH-1:0] m_ip_payload_axis_tid_int;
reg [DEST_WIDTH-1:0] m_ip_payload_axis_tdest_int;
reg [USER_WIDTH-1:0] m_ip_payload_axis_tuser_int;
wire m_ip_payload_axis_tready_int_early;
assign s_ip_hdr_ready = s_ip_hdr_ready_reg;
assign s_ip_payload_axis_tready = s_ip_payload_axis_tready_reg;
assign m_ip_hdr_valid = m_ip_hdr_valid_reg;
assign m_eth_dest_mac = m_eth_dest_mac_reg;
assign m_eth_src_mac = m_eth_src_mac_reg;
assign m_eth_type = m_eth_type_reg;
assign m_ip_version = m_ip_version_reg;
assign m_ip_ihl = m_ip_ihl_reg;
assign m_ip_dscp = m_ip_dscp_reg;
assign m_ip_ecn = m_ip_ecn_reg;
assign m_ip_length = m_ip_length_reg;
assign m_ip_identification = m_ip_identification_reg;
assign m_ip_flags = m_ip_flags_reg;
assign m_ip_fragment_offset = m_ip_fragment_offset_reg;
assign m_ip_ttl = m_ip_ttl_reg;
assign m_ip_protocol = m_ip_protocol_reg;
assign m_ip_header_checksum = m_ip_header_checksum_reg;
assign m_ip_source_ip = m_ip_source_ip_reg;
assign m_ip_dest_ip = m_ip_dest_ip_reg;
// mux for incoming packet
wire [DATA_WIDTH-1:0] current_s_tdata = s_ip_payload_axis_tdata[select_reg*DATA_WIDTH +: DATA_WIDTH];
wire [KEEP_WIDTH-1:0] current_s_tkeep = s_ip_payload_axis_tkeep[select_reg*KEEP_WIDTH +: KEEP_WIDTH];
wire current_s_tvalid = s_ip_payload_axis_tvalid[select_reg];
wire current_s_tready = s_ip_payload_axis_tready[select_reg];
wire current_s_tlast = s_ip_payload_axis_tlast[select_reg];
wire [ID_WIDTH-1:0] current_s_tid = s_ip_payload_axis_tid[select_reg*ID_WIDTH +: ID_WIDTH];
wire [DEST_WIDTH-1:0] current_s_tdest = s_ip_payload_axis_tdest[select_reg*DEST_WIDTH +: DEST_WIDTH];
wire [USER_WIDTH-1:0] current_s_tuser = s_ip_payload_axis_tuser[select_reg*USER_WIDTH +: USER_WIDTH];
always @* begin
select_next = select_reg;
frame_next = frame_reg;
s_ip_hdr_ready_next = 0;
s_ip_payload_axis_tready_next = 0;
m_ip_hdr_valid_next = m_ip_hdr_valid_reg && !m_ip_hdr_ready;
m_eth_dest_mac_next = m_eth_dest_mac_reg;
m_eth_src_mac_next = m_eth_src_mac_reg;
m_eth_type_next = m_eth_type_reg;
m_ip_version_next = m_ip_version_reg;
m_ip_ihl_next = m_ip_ihl_reg;
m_ip_dscp_next = m_ip_dscp_reg;
m_ip_ecn_next = m_ip_ecn_reg;
m_ip_length_next = m_ip_length_reg;
m_ip_identification_next = m_ip_identification_reg;
m_ip_flags_next = m_ip_flags_reg;
m_ip_fragment_offset_next = m_ip_fragment_offset_reg;
m_ip_ttl_next = m_ip_ttl_reg;
m_ip_protocol_next = m_ip_protocol_reg;
m_ip_header_checksum_next = m_ip_header_checksum_reg;
m_ip_source_ip_next = m_ip_source_ip_reg;
m_ip_dest_ip_next = m_ip_dest_ip_reg;
if (current_s_tvalid & current_s_tready) begin
// end of frame detection
if (current_s_tlast) begin
frame_next = 1'b0;
end
end
if (!frame_reg && enable && !m_ip_hdr_valid && (s_ip_hdr_valid & (1 << select))) begin
// start of frame, grab select value
frame_next = 1'b1;
select_next = select;
s_ip_hdr_ready_next = (1 << select);
m_ip_hdr_valid_next = 1'b1;
m_eth_dest_mac_next = s_eth_dest_mac[select*48 +: 48];
m_eth_src_mac_next = s_eth_src_mac[select*48 +: 48];
m_eth_type_next = s_eth_type[select*16 +: 16];
m_ip_version_next = s_ip_version[select*4 +: 4];
m_ip_ihl_next = s_ip_ihl[select*4 +: 4];
m_ip_dscp_next = s_ip_dscp[select*6 +: 6];
m_ip_ecn_next = s_ip_ecn[select*2 +: 2];
m_ip_length_next = s_ip_length[select*16 +: 16];
m_ip_identification_next = s_ip_identification[select*16 +: 16];
m_ip_flags_next = s_ip_flags[select*3 +: 3];
m_ip_fragment_offset_next = s_ip_fragment_offset[select*13 +: 13];
m_ip_ttl_next = s_ip_ttl[select*8 +: 8];
m_ip_protocol_next = s_ip_protocol[select*8 +: 8];
m_ip_header_checksum_next = s_ip_header_checksum[select*16 +: 16];
m_ip_source_ip_next = s_ip_source_ip[select*32 +: 32];
m_ip_dest_ip_next = s_ip_dest_ip[select*32 +: 32];
end
// generate ready signal on selected port
s_ip_payload_axis_tready_next = (m_ip_payload_axis_tready_int_early && frame_next) << select_next;
// pass through selected packet data
m_ip_payload_axis_tdata_int = current_s_tdata;
m_ip_payload_axis_tkeep_int = current_s_tkeep;
m_ip_payload_axis_tvalid_int = current_s_tvalid && current_s_tready && frame_reg;
m_ip_payload_axis_tlast_int = current_s_tlast;
m_ip_payload_axis_tid_int = current_s_tid;
m_ip_payload_axis_tdest_int = current_s_tdest;
m_ip_payload_axis_tuser_int = current_s_tuser;
end
always @(posedge clk) begin
if (rst) begin
select_reg <= 0;
frame_reg <= 1'b0;
s_ip_hdr_ready_reg <= 0;
s_ip_payload_axis_tready_reg <= 0;
m_ip_hdr_valid_reg <= 1'b0;
end else begin
select_reg <= select_next;
frame_reg <= frame_next;
s_ip_hdr_ready_reg <= s_ip_hdr_ready_next;
s_ip_payload_axis_tready_reg <= s_ip_payload_axis_tready_next;
m_ip_hdr_valid_reg <= m_ip_hdr_valid_next;
end
m_eth_dest_mac_reg <= m_eth_dest_mac_next;
m_eth_src_mac_reg <= m_eth_src_mac_next;
m_eth_type_reg <= m_eth_type_next;
m_ip_version_reg <= m_ip_version_next;
m_ip_ihl_reg <= m_ip_ihl_next;
m_ip_dscp_reg <= m_ip_dscp_next;
m_ip_ecn_reg <= m_ip_ecn_next;
m_ip_length_reg <= m_ip_length_next;
m_ip_identification_reg <= m_ip_identification_next;
m_ip_flags_reg <= m_ip_flags_next;
m_ip_fragment_offset_reg <= m_ip_fragment_offset_next;
m_ip_ttl_reg <= m_ip_ttl_next;
m_ip_protocol_reg <= m_ip_protocol_next;
m_ip_header_checksum_reg <= m_ip_header_checksum_next;
m_ip_source_ip_reg <= m_ip_source_ip_next;
m_ip_dest_ip_reg <= m_ip_dest_ip_next;
end
// output datapath logic
reg [DATA_WIDTH-1:0] m_ip_payload_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] m_ip_payload_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
reg m_ip_payload_axis_tvalid_reg = 1'b0, m_ip_payload_axis_tvalid_next;
reg m_ip_payload_axis_tlast_reg = 1'b0;
reg [ID_WIDTH-1:0] m_ip_payload_axis_tid_reg = {ID_WIDTH{1'b0}};
reg [DEST_WIDTH-1:0] m_ip_payload_axis_tdest_reg = {DEST_WIDTH{1'b0}};
reg [USER_WIDTH-1:0] m_ip_payload_axis_tuser_reg = {USER_WIDTH{1'b0}};
reg [DATA_WIDTH-1:0] temp_m_ip_payload_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] temp_m_ip_payload_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
reg temp_m_ip_payload_axis_tvalid_reg = 1'b0, temp_m_ip_payload_axis_tvalid_next;
reg temp_m_ip_payload_axis_tlast_reg = 1'b0;
reg [ID_WIDTH-1:0] temp_m_ip_payload_axis_tid_reg = {ID_WIDTH{1'b0}};
reg [DEST_WIDTH-1:0] temp_m_ip_payload_axis_tdest_reg = {DEST_WIDTH{1'b0}};
reg [USER_WIDTH-1:0] temp_m_ip_payload_axis_tuser_reg = {USER_WIDTH{1'b0}};
// datapath control
reg store_axis_int_to_output;
reg store_axis_int_to_temp;
reg store_axis_temp_to_output;
assign m_ip_payload_axis_tdata = m_ip_payload_axis_tdata_reg;
assign m_ip_payload_axis_tkeep = KEEP_ENABLE ? m_ip_payload_axis_tkeep_reg : {KEEP_WIDTH{1'b1}};
assign m_ip_payload_axis_tvalid = m_ip_payload_axis_tvalid_reg;
assign m_ip_payload_axis_tlast = m_ip_payload_axis_tlast_reg;
assign m_ip_payload_axis_tid = ID_ENABLE ? m_ip_payload_axis_tid_reg : {ID_WIDTH{1'b0}};
assign m_ip_payload_axis_tdest = DEST_ENABLE ? m_ip_payload_axis_tdest_reg : {DEST_WIDTH{1'b0}};
assign m_ip_payload_axis_tuser = USER_ENABLE ? m_ip_payload_axis_tuser_reg : {USER_WIDTH{1'b0}};
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
assign m_ip_payload_axis_tready_int_early = m_ip_payload_axis_tready || (!temp_m_ip_payload_axis_tvalid_reg && (!m_ip_payload_axis_tvalid_reg || !m_ip_payload_axis_tvalid_int));
always @* begin
// transfer sink ready state to source
m_ip_payload_axis_tvalid_next = m_ip_payload_axis_tvalid_reg;
temp_m_ip_payload_axis_tvalid_next = temp_m_ip_payload_axis_tvalid_reg;
store_axis_int_to_output = 1'b0;
store_axis_int_to_temp = 1'b0;
store_axis_temp_to_output = 1'b0;
if (m_ip_payload_axis_tready_int_reg) begin
// input is ready
if (m_ip_payload_axis_tready || !m_ip_payload_axis_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output
m_ip_payload_axis_tvalid_next = m_ip_payload_axis_tvalid_int;
store_axis_int_to_output = 1'b1;
end else begin
// output is not ready, store input in temp
temp_m_ip_payload_axis_tvalid_next = m_ip_payload_axis_tvalid_int;
store_axis_int_to_temp = 1'b1;
end
end else if (m_ip_payload_axis_tready) begin
// input is not ready, but output is ready
m_ip_payload_axis_tvalid_next = temp_m_ip_payload_axis_tvalid_reg;
temp_m_ip_payload_axis_tvalid_next = 1'b0;
store_axis_temp_to_output = 1'b1;
end
end
always @(posedge clk) begin
if (rst) begin
m_ip_payload_axis_tvalid_reg <= 1'b0;
m_ip_payload_axis_tready_int_reg <= 1'b0;
temp_m_ip_payload_axis_tvalid_reg <= 1'b0;
end else begin
m_ip_payload_axis_tvalid_reg <= m_ip_payload_axis_tvalid_next;
m_ip_payload_axis_tready_int_reg <= m_ip_payload_axis_tready_int_early;
temp_m_ip_payload_axis_tvalid_reg <= temp_m_ip_payload_axis_tvalid_next;
end
// datapath
if (store_axis_int_to_output) begin
m_ip_payload_axis_tdata_reg <= m_ip_payload_axis_tdata_int;
m_ip_payload_axis_tkeep_reg <= m_ip_payload_axis_tkeep_int;
m_ip_payload_axis_tlast_reg <= m_ip_payload_axis_tlast_int;
m_ip_payload_axis_tid_reg <= m_ip_payload_axis_tid_int;
m_ip_payload_axis_tdest_reg <= m_ip_payload_axis_tdest_int;
m_ip_payload_axis_tuser_reg <= m_ip_payload_axis_tuser_int;
end else if (store_axis_temp_to_output) begin
m_ip_payload_axis_tdata_reg <= temp_m_ip_payload_axis_tdata_reg;
m_ip_payload_axis_tkeep_reg <= temp_m_ip_payload_axis_tkeep_reg;
m_ip_payload_axis_tlast_reg <= temp_m_ip_payload_axis_tlast_reg;
m_ip_payload_axis_tid_reg <= temp_m_ip_payload_axis_tid_reg;
m_ip_payload_axis_tdest_reg <= temp_m_ip_payload_axis_tdest_reg;
m_ip_payload_axis_tuser_reg <= temp_m_ip_payload_axis_tuser_reg;
end
if (store_axis_int_to_temp) begin
temp_m_ip_payload_axis_tdata_reg <= m_ip_payload_axis_tdata_int;
temp_m_ip_payload_axis_tkeep_reg <= m_ip_payload_axis_tkeep_int;
temp_m_ip_payload_axis_tlast_reg <= m_ip_payload_axis_tlast_int;
temp_m_ip_payload_axis_tid_reg <= m_ip_payload_axis_tid_int;
temp_m_ip_payload_axis_tdest_reg <= m_ip_payload_axis_tdest_int;
temp_m_ip_payload_axis_tuser_reg <= m_ip_payload_axis_tuser_int;
end
end
endmodule
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment