Remove unused modules from Ethernet hierarchy

This commit is contained in:
Jonathan Richard Robert Kimmitt 2019-01-23 14:50:15 +00:00
parent 24d37830db
commit 1311a8da0b
27 changed files with 1 additions and 8693 deletions

View file

@ -1,416 +0,0 @@
/*
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
/*
* ARP block for IPv4, ethernet frame interface
*/
module arp #(
parameter CACHE_ADDR_WIDTH = 9,
parameter REQUEST_RETRY_COUNT = 4,
parameter REQUEST_RETRY_INTERVAL = 125000000*2,
parameter 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,
/*
* ARP requests
*/
input wire arp_request_valid,
output wire arp_request_ready,
input wire [31:0] arp_request_ip,
output wire arp_response_valid,
input wire arp_response_ready,
output wire arp_response_error,
output wire [47:0] arp_response_mac,
/*
* 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_cache
);
localparam [15:0]
ARP_OPER_ARP_REQUEST = 16'h0001,
ARP_OPER_ARP_REPLY = 16'h0002,
ARP_OPER_INARP_REQUEST = 16'h0008,
ARP_OPER_INARP_REPLY = 16'h0009;
wire incoming_frame_valid;
reg incoming_frame_ready;
wire [47:0] incoming_eth_dest_mac;
wire [47:0] incoming_eth_src_mac;
wire [15:0] incoming_eth_type;
wire [15:0] incoming_arp_htype;
wire [15:0] incoming_arp_ptype;
wire [7:0] incoming_arp_hlen;
wire [7:0] incoming_arp_plen;
wire [15:0] incoming_arp_oper;
wire [47:0] incoming_arp_sha;
wire [31:0] incoming_arp_spa;
wire [47:0] incoming_arp_tha;
wire [31:0] incoming_arp_tpa;
/*
* ARP frame processing
*/
arp_eth_rx
arp_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),
// ARP frame output
.m_frame_valid(incoming_frame_valid),
.m_frame_ready(incoming_frame_ready),
.m_eth_dest_mac(incoming_eth_dest_mac),
.m_eth_src_mac(incoming_eth_src_mac),
.m_eth_type(incoming_eth_type),
.m_arp_htype(incoming_arp_htype),
.m_arp_ptype(incoming_arp_ptype),
.m_arp_hlen(incoming_arp_hlen),
.m_arp_plen(incoming_arp_plen),
.m_arp_oper(incoming_arp_oper),
.m_arp_sha(incoming_arp_sha),
.m_arp_spa(incoming_arp_spa),
.m_arp_tha(incoming_arp_tha),
.m_arp_tpa(incoming_arp_tpa),
// Status signals
.busy(),
.error_header_early_termination(),
.error_invalid_header()
);
reg outgoing_frame_valid_reg = 1'b0, outgoing_frame_valid_next;
wire outgoing_frame_ready;
reg [47:0] outgoing_eth_dest_mac_reg = 48'd0, outgoing_eth_dest_mac_next;
reg [15:0] outgoing_arp_oper_reg = 16'd0, outgoing_arp_oper_next;
reg [47:0] outgoing_arp_tha_reg = 48'd0, outgoing_arp_tha_next;
reg [31:0] outgoing_arp_tpa_reg = 32'd0, outgoing_arp_tpa_next;
arp_eth_tx
arp_eth_tx_inst (
.clk(clk),
.rst(rst),
// ARP frame input
.s_frame_valid(outgoing_frame_valid_reg),
.s_frame_ready(outgoing_frame_ready),
.s_eth_dest_mac(outgoing_eth_dest_mac_reg),
.s_eth_src_mac(local_mac),
.s_eth_type(16'h0806),
.s_arp_htype(16'h0001),
.s_arp_ptype(16'h0800),
.s_arp_oper(outgoing_arp_oper_reg),
.s_arp_sha(local_mac),
.s_arp_spa(local_ip),
.s_arp_tha(outgoing_arp_tha_reg),
.s_arp_tpa(outgoing_arp_tpa_reg),
// 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()
);
reg cache_query_request_valid_reg = 1'b0, cache_query_request_valid_next;
reg [31:0] cache_query_request_ip_reg = 32'd0, cache_query_request_ip_next;
wire cache_query_response_valid;
wire cache_query_response_error;
wire [47:0] cache_query_response_mac;
reg cache_write_request_valid_reg = 1'b0, cache_write_request_valid_next;
reg [31:0] cache_write_request_ip_reg = 32'd0, cache_write_request_ip_next;
reg [47:0] cache_write_request_mac_reg = 48'd0, cache_write_request_mac_next;
/*
* ARP cache
*/
arp_cache #(
.CACHE_ADDR_WIDTH(CACHE_ADDR_WIDTH)
)
arp_cache_inst (
.clk(clk),
.rst(rst),
// Query cache
.query_request_valid(cache_query_request_valid_reg),
.query_request_ready(),
.query_request_ip(cache_query_request_ip_reg),
.query_response_valid(cache_query_response_valid),
.query_response_ready(1'b1),
.query_response_error(cache_query_response_error),
.query_response_mac(cache_query_response_mac),
// Write cache
.write_request_valid(cache_write_request_valid_reg),
.write_request_ready(),
.write_request_ip(cache_write_request_ip_reg),
.write_request_mac(cache_write_request_mac_reg),
// Configuration
.clear_cache(clear_cache)
);
reg arp_request_operation_reg = 1'b0, arp_request_operation_next;
reg arp_request_ready_reg = 1'b0, arp_request_ready_next;
reg [31:0] arp_request_ip_reg = 32'd0, arp_request_ip_next;
reg arp_response_valid_reg = 1'b0, arp_response_valid_next;
reg arp_response_error_reg = 1'b0, arp_response_error_next;
reg [47:0] arp_response_mac_reg = 48'd0, arp_response_mac_next;
reg [5:0] arp_request_retry_cnt_reg = 6'd0, arp_request_retry_cnt_next;
reg [35:0] arp_request_timer_reg = 36'd0, arp_request_timer_next;
assign arp_request_ready = arp_request_ready_reg;
assign arp_response_valid = arp_response_valid_reg;
assign arp_response_error = arp_response_error_reg;
assign arp_response_mac = arp_response_mac_reg;
always @* begin
incoming_frame_ready = 1'b0;
outgoing_frame_valid_next = outgoing_frame_valid_reg && !outgoing_frame_ready;
outgoing_eth_dest_mac_next = outgoing_eth_dest_mac_reg;
outgoing_arp_oper_next = outgoing_arp_oper_reg;
outgoing_arp_tha_next = outgoing_arp_tha_reg;
outgoing_arp_tpa_next = outgoing_arp_tpa_reg;
cache_query_request_valid_next = 1'b0;
cache_query_request_ip_next = cache_query_request_ip_reg;
cache_write_request_valid_next = 1'b0;
cache_write_request_mac_next = cache_write_request_mac_reg;
cache_write_request_ip_next = cache_write_request_ip_reg;
arp_request_ready_next = 1'b0;
arp_request_ip_next = arp_request_ip_reg;
arp_request_operation_next = arp_request_operation_reg;
arp_request_retry_cnt_next = arp_request_retry_cnt_reg;
arp_request_timer_next = arp_request_timer_reg;
arp_response_valid_next = arp_response_valid_reg && !arp_response_ready;
arp_response_error_next = 1'b0;
arp_response_mac_next = 48'd0;
// manage incoming frames
incoming_frame_ready = outgoing_frame_ready;
if (incoming_frame_valid && incoming_frame_ready) begin
if (incoming_eth_type == 16'h0806 && incoming_arp_htype == 16'h0001 && incoming_arp_ptype == 16'h0800) begin
// store sender addresses in cache
cache_write_request_valid_next = 1'b1;
cache_write_request_ip_next = incoming_arp_spa;
cache_write_request_mac_next = incoming_arp_sha;
if (incoming_arp_oper == ARP_OPER_ARP_REQUEST) begin
// ARP request
if (incoming_arp_tpa == local_ip) begin
// send reply frame to valid incoming request
outgoing_frame_valid_next = 1'b1;
outgoing_eth_dest_mac_next = incoming_eth_src_mac;
outgoing_arp_oper_next = ARP_OPER_ARP_REPLY;
outgoing_arp_tha_next = incoming_arp_sha;
outgoing_arp_tpa_next = incoming_arp_spa;
end
end else if (incoming_arp_oper == ARP_OPER_INARP_REPLY) begin
// INARP request
if (incoming_arp_tha == local_mac) begin
// send reply frame to valid incoming request
outgoing_frame_valid_next = 1'b1;
outgoing_eth_dest_mac_next = incoming_eth_src_mac;
outgoing_arp_oper_next = ARP_OPER_INARP_REPLY;
outgoing_arp_tha_next = incoming_arp_sha;
outgoing_arp_tpa_next = incoming_arp_spa;
end
end
end
end
// manage ARP lookup requests
if (arp_request_operation_reg) begin
arp_request_ready_next = 1'b0;
cache_query_request_valid_next = 1'b1;
arp_request_timer_next = arp_request_timer_reg - 1;
// if we got a response, it will go in the cache, so when the query succeds, we're done
if (cache_query_response_valid && !cache_query_response_error) begin
arp_request_operation_next = 1'b0;
cache_query_request_valid_next = 1'b0;
arp_response_valid_next = 1'b1;
arp_response_error_next = 1'b0;
arp_response_mac_next = cache_query_response_mac;
end
// timer timeout
if (arp_request_timer_reg == 0) begin
if (arp_request_retry_cnt_reg > 0) begin
// have more retries
// send ARP request frame
outgoing_frame_valid_next = 1'b1;
outgoing_eth_dest_mac_next = 48'hffffffffffff;
outgoing_arp_oper_next = ARP_OPER_ARP_REQUEST;
outgoing_arp_tha_next = 48'h000000000000;
outgoing_arp_tpa_next = arp_request_ip_reg;
arp_request_retry_cnt_next = arp_request_retry_cnt_reg - 1;
if (arp_request_retry_cnt_reg > 1) begin
arp_request_timer_next = REQUEST_RETRY_INTERVAL;
end else begin
arp_request_timer_next = REQUEST_TIMEOUT;
end
end else begin
// out of retries
arp_request_operation_next = 1'b0;
arp_response_valid_next = 1'b1;
arp_response_error_next = 1'b1;
cache_query_request_valid_next = 1'b0;
end
end
end else begin
arp_request_ready_next = !arp_response_valid_next;
if (cache_query_request_valid_reg) begin
cache_query_request_valid_next = 1'b1;
if (cache_query_response_valid) begin
if (cache_query_response_error) begin
arp_request_operation_next = 1'b1;
// send ARP request frame
outgoing_frame_valid_next = 1'b1;
outgoing_eth_dest_mac_next = 48'hffffffffffff;
outgoing_arp_oper_next = ARP_OPER_ARP_REQUEST;
outgoing_arp_tha_next = 48'h000000000000;
outgoing_arp_tpa_next = arp_request_ip_reg;
arp_request_retry_cnt_next = REQUEST_RETRY_COUNT-1;
arp_request_timer_next = REQUEST_RETRY_INTERVAL;
end else begin
cache_query_request_valid_next = 1'b0;
arp_response_valid_next = 1'b1;
arp_response_error_next = 1'b0;
arp_response_mac_next = cache_query_response_mac;
end
end
end else if (arp_request_valid && arp_request_ready) begin
if (~(arp_request_ip | subnet_mask) == 0) begin
// broadcast address
// (all bits in request IP set where subnet mask is clear)
arp_response_valid_next = 1'b1;
arp_response_error_next = 1'b0;
arp_response_mac_next = 48'hffffffffffff;
end else if (((arp_request_ip ^ gateway_ip) & subnet_mask) == 0) begin
// within subnet, look up IP directly
// (no bits differ between request IP and gateway IP where subnet mask is set)
cache_query_request_valid_next = 1'b1;
cache_query_request_ip_next = arp_request_ip;
arp_request_ip_next = arp_request_ip;
end else begin
// outside of subnet, so look up gateway address
cache_query_request_valid_next = 1'b1;
cache_query_request_ip_next = gateway_ip;
arp_request_ip_next = gateway_ip;
end
end
end
end
always @(posedge clk) begin
if (rst) begin
outgoing_frame_valid_reg <= 1'b0;
cache_query_request_valid_reg <= 1'b0;
cache_write_request_valid_reg <= 1'b0;
arp_request_ready_reg <= 1'b0;
arp_request_operation_reg <= 1'b0;
arp_request_retry_cnt_reg <= 6'd0;
arp_request_timer_reg <= 36'd0;
arp_response_valid_reg <= 1'b0;
end else begin
outgoing_frame_valid_reg <= outgoing_frame_valid_next;
cache_query_request_valid_reg <= cache_query_request_valid_next;
cache_write_request_valid_reg <= cache_write_request_valid_next;
arp_request_ready_reg <= arp_request_ready_next;
arp_request_operation_reg <= arp_request_operation_next;
arp_request_retry_cnt_reg <= arp_request_retry_cnt_next;
arp_request_timer_reg <= arp_request_timer_next;
arp_response_valid_reg <= arp_response_valid_next;
end
cache_query_request_ip_reg <= cache_query_request_ip_next;
outgoing_eth_dest_mac_reg <= outgoing_eth_dest_mac_next;
outgoing_arp_oper_reg <= outgoing_arp_oper_next;
outgoing_arp_tha_reg <= outgoing_arp_tha_next;
outgoing_arp_tpa_reg <= outgoing_arp_tpa_next;
cache_write_request_mac_reg <= cache_write_request_mac_next;
cache_write_request_ip_reg <= cache_write_request_ip_next;
arp_request_ip_reg <= arp_request_ip_next;
arp_response_error_reg <= arp_response_error_next;
arp_response_mac_reg <= arp_response_mac_next;
end
endmodule

View file

@ -1,218 +0,0 @@
/*
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
/*
* ARP cache
*/
module arp_cache #(
parameter CACHE_ADDR_WIDTH = 9
)
(
input wire clk,
input wire rst,
/*
* Cache query
*/
input wire query_request_valid,
output wire query_request_ready,
input wire [31:0] query_request_ip,
output wire query_response_valid,
input wire query_response_ready,
output wire query_response_error,
output wire [47:0] query_response_mac,
/*
* Cache write
*/
input wire write_request_valid,
output wire write_request_ready,
input wire [31:0] write_request_ip,
input wire [47:0] write_request_mac,
/*
* Configuration
*/
input wire clear_cache
);
reg mem_write = 0;
reg store_query = 0;
reg store_write = 0;
reg query_ip_valid_reg = 0, query_ip_valid_next;
reg [31:0] query_ip_reg = 0;
reg write_ip_valid_reg = 0, write_ip_valid_next;
reg [31:0] write_ip_reg = 0;
reg [47:0] write_mac_reg = 0;
reg [CACHE_ADDR_WIDTH-1:0] wr_ptr_reg = {CACHE_ADDR_WIDTH{1'b0}}, wr_ptr_next;
reg [CACHE_ADDR_WIDTH-1:0] rd_ptr_reg = {CACHE_ADDR_WIDTH{1'b0}}, rd_ptr_next;
reg valid_mem[(2**CACHE_ADDR_WIDTH)-1:0];
reg [31:0] ip_addr_mem[(2**CACHE_ADDR_WIDTH)-1:0];
reg [47:0] mac_addr_mem[(2**CACHE_ADDR_WIDTH)-1:0];
reg query_request_ready_reg = 0, query_request_ready_next;
reg query_response_valid_reg = 0, query_response_valid_next;
reg query_response_error_reg = 0, query_response_error_next;
reg [47:0] query_response_mac_reg = 0;
reg write_request_ready_reg = 0, write_request_ready_next;
wire [31:0] query_request_hash;
wire [31:0] write_request_hash;
assign query_request_ready = query_request_ready_reg;
assign query_response_valid = query_response_valid_reg;
assign query_response_error = query_response_error_reg;
assign query_response_mac = query_response_mac_reg;
assign write_request_ready = write_request_ready_reg;
rgmii_lfsr #(
.LFSR_WIDTH(32),
.LFSR_POLY(32'h4c11db7),
.LFSR_CONFIG("GALOIS"),
.LFSR_FEED_FORWARD(0),
.REVERSE(1),
.DATA_WIDTH(32),
.STYLE("AUTO")
)
rd_hash (
.data_in(query_request_ip),
.state_in(32'hffffffff),
.data_out(),
.state_out(query_request_hash)
);
rgmii_lfsr #(
.LFSR_WIDTH(32),
.LFSR_POLY(32'h4c11db7),
.LFSR_CONFIG("GALOIS"),
.LFSR_FEED_FORWARD(0),
.REVERSE(1),
.DATA_WIDTH(32),
.STYLE("AUTO")
)
wr_hash (
.data_in(write_request_ip),
.state_in(32'hffffffff),
.data_out(),
.state_out(write_request_hash)
);
always @* begin
mem_write = 1'b0;
store_query = 1'b0;
store_write = 1'b0;
wr_ptr_next = wr_ptr_reg;
rd_ptr_next = rd_ptr_reg;
query_ip_valid_next = query_ip_valid_reg;
query_request_ready_next = ~query_ip_valid_reg || ~query_request_valid || query_response_ready;
query_response_valid_next = query_response_valid_reg & ~query_response_ready;
query_response_error_next = query_response_error_reg;
if (query_ip_valid_reg && (~query_request_valid || query_response_ready)) begin
query_response_valid_next = 1;
query_ip_valid_next = 0;
if (valid_mem[rd_ptr_reg] && ip_addr_mem[rd_ptr_reg] == query_ip_reg) begin
query_response_error_next = 0;
end else begin
query_response_error_next = 1;
end
end
if (query_request_valid && query_request_ready && (~query_ip_valid_reg || ~query_request_valid || query_response_ready)) begin
store_query = 1;
query_ip_valid_next = 1;
rd_ptr_next = query_request_hash[CACHE_ADDR_WIDTH-1:0];
end
write_ip_valid_next = write_ip_valid_reg;
write_request_ready_next = 1'b1;
if (write_ip_valid_reg) begin
write_ip_valid_next = 0;
mem_write = 1;
end
if (write_request_valid && write_request_ready) begin
store_write = 1;
write_ip_valid_next = 1;
wr_ptr_next = write_request_hash[CACHE_ADDR_WIDTH-1:0];
end
end
always @(posedge clk) begin
if (rst) begin
query_ip_valid_reg <= 1'b0;
query_request_ready_reg <= 1'b0;
query_response_valid_reg <= 1'b0;
write_ip_valid_reg <= 1'b0;
write_request_ready_reg <= 1'b0;
end else begin
query_ip_valid_reg <= query_ip_valid_next;
query_request_ready_reg <= query_request_ready_next;
query_response_valid_reg <= query_response_valid_next;
write_ip_valid_reg <= write_ip_valid_next;
write_request_ready_reg <= write_request_ready_next;
end
query_response_error_reg <= query_response_error_next;
if (store_query) begin
query_ip_reg <= query_request_ip;
end
if (store_write) begin
write_ip_reg <= write_request_ip;
write_mac_reg <= write_request_mac;
end
wr_ptr_reg <= wr_ptr_next;
rd_ptr_reg <= rd_ptr_next;
query_response_mac_reg <= mac_addr_mem[rd_ptr_reg];
if (mem_write) begin
valid_mem[wr_ptr_reg] <= 1'b1;
ip_addr_mem[wr_ptr_reg] <= write_ip_reg;
mac_addr_mem[wr_ptr_reg] <= write_mac_reg;
end
end
endmodule

View file

@ -1,391 +0,0 @@
/*
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
/*
* ARP ethernet frame receiver (Ethernet frame in, ARP frame out)
*/
module arp_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,
/*
* ARP frame output
*/
output wire m_frame_valid,
input wire m_frame_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 [15:0] m_arp_htype,
output wire [15:0] m_arp_ptype,
output wire [7:0] m_arp_hlen,
output wire [7:0] m_arp_plen,
output wire [15:0] m_arp_oper,
output wire [47:0] m_arp_sha,
output wire [31:0] m_arp_spa,
output wire [47:0] m_arp_tha,
output wire [31:0] m_arp_tpa,
/*
* Status signals
*/
output wire busy,
output wire error_header_early_termination,
output wire error_invalid_header
);
/*
ARP Frame
Field Length
Destination MAC address 6 octets
Source MAC address 6 octets
Ethertype (0x0806) 2 octets
HTYPE (1) 2 octets
PTYPE (0x0800) 2 octets
HLEN (6) 1 octets
PLEN (4) 1 octets
OPER 2 octets
SHA Sender MAC 6 octets
SPA Sender IP 4 octets
THA Target MAC 6 octets
TPA Target IP 4 octets
This module receives an Ethernet frame with header fields in parallel and
payload on an AXI stream interface, decodes the ARP packet fields, and
produces the frame fields in parallel.
*/
localparam [2:0]
STATE_IDLE = 3'd0,
STATE_READ_HEADER = 3'd1,
STATE_WAIT_LAST = 3'd2;
reg [2:0] state_reg = STATE_IDLE, state_next;
// datapath control signals
reg store_eth_hdr;
reg store_arp_htype_0;
reg store_arp_htype_1;
reg store_arp_ptype_0;
reg store_arp_ptype_1;
reg store_arp_hlen;
reg store_arp_plen;
reg store_arp_oper_0;
reg store_arp_oper_1;
reg store_arp_sha_0;
reg store_arp_sha_1;
reg store_arp_sha_2;
reg store_arp_sha_3;
reg store_arp_sha_4;
reg store_arp_sha_5;
reg store_arp_spa_0;
reg store_arp_spa_1;
reg store_arp_spa_2;
reg store_arp_spa_3;
reg store_arp_tha_0;
reg store_arp_tha_1;
reg store_arp_tha_2;
reg store_arp_tha_3;
reg store_arp_tha_4;
reg store_arp_tha_5;
reg store_arp_tpa_0;
reg store_arp_tpa_1;
reg store_arp_tpa_2;
reg store_arp_tpa_3;
reg [7:0] frame_ptr_reg = 8'd0, frame_ptr_next;
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_frame_valid_reg = 1'b0, m_frame_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 [15:0] m_arp_htype_reg = 16'd0;
reg [15:0] m_arp_ptype_reg = 16'd0;
reg [7:0] m_arp_hlen_reg = 8'd0;
reg [7:0] m_arp_plen_reg = 8'd0;
reg [15:0] m_arp_oper_reg = 16'd0;
reg [47:0] m_arp_sha_reg = 48'd0;
reg [31:0] m_arp_spa_reg = 32'd0;
reg [47:0] m_arp_tha_reg = 48'd0;
reg [31:0] m_arp_tpa_reg = 32'd0;
reg busy_reg = 1'b0;
reg error_header_early_termination_reg = 1'b0, error_header_early_termination_next;
reg error_invalid_header_reg = 1'b0, error_invalid_header_next;
assign s_eth_hdr_ready = s_eth_hdr_ready_reg;
assign s_eth_payload_axis_tready = s_eth_payload_axis_tready_reg;
assign m_frame_valid = m_frame_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_arp_htype = m_arp_htype_reg;
assign m_arp_ptype = m_arp_ptype_reg;
assign m_arp_hlen = m_arp_hlen_reg;
assign m_arp_plen = m_arp_plen_reg;
assign m_arp_oper = m_arp_oper_reg;
assign m_arp_sha = m_arp_sha_reg;
assign m_arp_spa = m_arp_spa_reg;
assign m_arp_tha = m_arp_tha_reg;
assign m_arp_tpa = m_arp_tpa_reg;
assign busy = busy_reg;
assign error_header_early_termination = error_header_early_termination_reg;
assign error_invalid_header = error_invalid_header_reg;
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_arp_htype_0 = 1'b0;
store_arp_htype_1 = 1'b0;
store_arp_ptype_0 = 1'b0;
store_arp_ptype_1 = 1'b0;
store_arp_hlen = 1'b0;
store_arp_plen = 1'b0;
store_arp_oper_0 = 1'b0;
store_arp_oper_1 = 1'b0;
store_arp_sha_0 = 1'b0;
store_arp_sha_1 = 1'b0;
store_arp_sha_2 = 1'b0;
store_arp_sha_3 = 1'b0;
store_arp_sha_4 = 1'b0;
store_arp_sha_5 = 1'b0;
store_arp_spa_0 = 1'b0;
store_arp_spa_1 = 1'b0;
store_arp_spa_2 = 1'b0;
store_arp_spa_3 = 1'b0;
store_arp_tha_0 = 1'b0;
store_arp_tha_1 = 1'b0;
store_arp_tha_2 = 1'b0;
store_arp_tha_3 = 1'b0;
store_arp_tha_4 = 1'b0;
store_arp_tha_5 = 1'b0;
store_arp_tpa_0 = 1'b0;
store_arp_tpa_1 = 1'b0;
store_arp_tpa_2 = 1'b0;
store_arp_tpa_3 = 1'b0;
frame_ptr_next = frame_ptr_reg;
m_frame_valid_next = m_frame_valid_reg && !m_frame_ready;
error_header_early_termination_next = 1'b0;
error_invalid_header_next = 1'b0;
case (state_reg)
STATE_IDLE: begin
// idle state - wait for data
frame_ptr_next = 8'd0;
s_eth_hdr_ready_next = !m_frame_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 state
s_eth_payload_axis_tready_next = 1'b1;
if (s_eth_payload_axis_tvalid) begin
// word transfer in - store it
frame_ptr_next = frame_ptr_reg + 8'd1;
state_next = STATE_READ_HEADER;
case (frame_ptr_reg)
8'h00: store_arp_htype_1 = 1'b1;
8'h01: store_arp_htype_0 = 1'b1;
8'h02: store_arp_ptype_1 = 1'b1;
8'h03: store_arp_ptype_0 = 1'b1;
8'h04: store_arp_hlen = 1'b1;
8'h05: store_arp_plen = 1'b1;
8'h06: store_arp_oper_1 = 1'b1;
8'h07: store_arp_oper_0 = 1'b1;
8'h08: store_arp_sha_5 = 1'b1;
8'h09: store_arp_sha_4 = 1'b1;
8'h0A: store_arp_sha_3 = 1'b1;
8'h0B: store_arp_sha_2 = 1'b1;
8'h0C: store_arp_sha_1 = 1'b1;
8'h0D: store_arp_sha_0 = 1'b1;
8'h0E: store_arp_spa_3 = 1'b1;
8'h0F: store_arp_spa_2 = 1'b1;
8'h10: store_arp_spa_1 = 1'b1;
8'h11: store_arp_spa_0 = 1'b1;
8'h12: store_arp_tha_5 = 1'b1;
8'h13: store_arp_tha_4 = 1'b1;
8'h14: store_arp_tha_3 = 1'b1;
8'h15: store_arp_tha_2 = 1'b1;
8'h16: store_arp_tha_1 = 1'b1;
8'h17: store_arp_tha_0 = 1'b1;
8'h18: store_arp_tpa_3 = 1'b1;
8'h19: store_arp_tpa_2 = 1'b1;
8'h1A: store_arp_tpa_1 = 1'b1;
8'h1B: begin
store_arp_tpa_0 = 1'b1;
state_next = STATE_WAIT_LAST;
end
endcase
if (s_eth_payload_axis_tlast) begin
// end of frame
if (frame_ptr_reg != 8'h1B) begin
// don't have the whole header
error_header_early_termination_next = 1'b1;
end else if (m_arp_hlen != 4'd6 || m_arp_plen != 4'd4) begin
// lengths not valid
error_invalid_header_next = 1'b1;
end else begin
// otherwise, transfer tuser
m_frame_valid_next = !s_eth_payload_axis_tuser;
end
s_eth_hdr_ready_next = !m_frame_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_WAIT_LAST: begin
// wait for end of frame; read and discard
s_eth_payload_axis_tready_next = 1'b1;
if (s_eth_payload_axis_tvalid) begin
if (s_eth_payload_axis_tlast) begin
if (m_arp_hlen != 4'd6 || m_arp_plen != 4'd4) begin
// lengths not valid
error_invalid_header_next = 1'b1;
end else begin
// otherwise, transfer tuser
m_frame_valid_next = !s_eth_payload_axis_tuser;
end
s_eth_hdr_ready_next = !m_frame_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
// wait for end of frame; read and discard
state_next = STATE_WAIT_LAST;
end
end
endcase
end
always @(posedge clk) begin
if (rst) begin
state_reg <= STATE_IDLE;
frame_ptr_reg <= 8'd0;
s_eth_payload_axis_tready_reg <= 1'b0;
m_frame_valid_reg <= 1'b0;
busy_reg <= 1'b0;
error_header_early_termination_reg <= 1'b0;
error_invalid_header_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;
frame_ptr_reg <= frame_ptr_next;
m_frame_valid_reg <= m_frame_valid_next;
error_header_early_termination_reg <= error_header_early_termination_next;
error_invalid_header_reg <= error_invalid_header_next;
busy_reg <= state_next != STATE_IDLE;
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_arp_htype_0) m_arp_htype_reg[ 7: 0] <= s_eth_payload_axis_tdata;
if (store_arp_htype_1) m_arp_htype_reg[15: 8] <= s_eth_payload_axis_tdata;
if (store_arp_ptype_0) m_arp_ptype_reg[ 7: 0] <= s_eth_payload_axis_tdata;
if (store_arp_ptype_1) m_arp_ptype_reg[15: 8] <= s_eth_payload_axis_tdata;
if (store_arp_hlen) m_arp_hlen_reg <= s_eth_payload_axis_tdata;
if (store_arp_plen) m_arp_plen_reg <= s_eth_payload_axis_tdata;
if (store_arp_oper_0) m_arp_oper_reg[ 7: 0] <= s_eth_payload_axis_tdata;
if (store_arp_oper_1) m_arp_oper_reg[15: 8] <= s_eth_payload_axis_tdata;
if (store_arp_sha_0) m_arp_sha_reg[ 7: 0] <= s_eth_payload_axis_tdata;
if (store_arp_sha_1) m_arp_sha_reg[15: 8] <= s_eth_payload_axis_tdata;
if (store_arp_sha_2) m_arp_sha_reg[23:16] <= s_eth_payload_axis_tdata;
if (store_arp_sha_3) m_arp_sha_reg[31:24] <= s_eth_payload_axis_tdata;
if (store_arp_sha_4) m_arp_sha_reg[39:32] <= s_eth_payload_axis_tdata;
if (store_arp_sha_5) m_arp_sha_reg[47:40] <= s_eth_payload_axis_tdata;
if (store_arp_spa_0) m_arp_spa_reg[ 7: 0] <= s_eth_payload_axis_tdata;
if (store_arp_spa_1) m_arp_spa_reg[15: 8] <= s_eth_payload_axis_tdata;
if (store_arp_spa_2) m_arp_spa_reg[23:16] <= s_eth_payload_axis_tdata;
if (store_arp_spa_3) m_arp_spa_reg[31:24] <= s_eth_payload_axis_tdata;
if (store_arp_tha_0) m_arp_tha_reg[ 7: 0] <= s_eth_payload_axis_tdata;
if (store_arp_tha_1) m_arp_tha_reg[15: 8] <= s_eth_payload_axis_tdata;
if (store_arp_tha_2) m_arp_tha_reg[23:16] <= s_eth_payload_axis_tdata;
if (store_arp_tha_3) m_arp_tha_reg[31:24] <= s_eth_payload_axis_tdata;
if (store_arp_tha_4) m_arp_tha_reg[39:32] <= s_eth_payload_axis_tdata;
if (store_arp_tha_5) m_arp_tha_reg[47:40] <= s_eth_payload_axis_tdata;
if (store_arp_tpa_0) m_arp_tpa_reg[ 7: 0] <= s_eth_payload_axis_tdata;
if (store_arp_tpa_1) m_arp_tpa_reg[15: 8] <= s_eth_payload_axis_tdata;
if (store_arp_tpa_2) m_arp_tpa_reg[23:16] <= s_eth_payload_axis_tdata;
if (store_arp_tpa_3) m_arp_tpa_reg[31:24] <= s_eth_payload_axis_tdata;
end
endmodule

View file

@ -1,340 +0,0 @@
/*
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
/*
* ARP ethernet frame transmitter (ARP frame in, Ethernet frame out)
*/
module arp_eth_tx
(
input wire clk,
input wire rst,
/*
* ARP frame input
*/
input wire s_frame_valid,
output wire s_frame_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 [15:0] s_arp_htype,
input wire [15:0] s_arp_ptype,
input wire [15:0] s_arp_oper,
input wire [47:0] s_arp_sha,
input wire [31:0] s_arp_spa,
input wire [47:0] s_arp_tha,
input wire [31:0] s_arp_tpa,
/*
* 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
);
/*
ARP Frame
Field Length
Destination MAC address 6 octets
Source MAC address 6 octets
Ethertype (0x0806) 2 octets
HTYPE (1) 2 octets
PTYPE (0x0800) 2 octets
HLEN (6) 1 octets
PLEN (4) 1 octets
OPER 2 octets
SHA Sender MAC 6 octets
SPA Sender IP 4 octets
THA Target MAC 6 octets
TPA Target IP 4 octets
This module receives an ARP frame with header fields in parallel and
transmits the complete Ethernet payload on an AXI interface.
*/
localparam [1:0]
STATE_IDLE = 2'd0,
STATE_WRITE_HEADER = 2'd1;
reg [1:0] state_reg = STATE_IDLE, state_next;
// datapath control signals
reg store_frame;
reg [7:0] frame_ptr_reg = 8'd0, frame_ptr_next;
reg [15:0] arp_htype_reg = 16'd0;
reg [15:0] arp_ptype_reg = 16'd0;
reg [15:0] arp_oper_reg = 16'd0;
reg [47:0] arp_sha_reg = 48'd0;
reg [31:0] arp_spa_reg = 32'd0;
reg [47:0] arp_tha_reg = 48'd0;
reg [31:0] arp_tpa_reg = 32'd0;
reg s_frame_ready_reg = 1'b0, s_frame_ready_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;
// 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_frame_ready = s_frame_ready_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;
always @* begin
state_next = STATE_IDLE;
s_frame_ready_next = 1'b0;
store_frame = 1'b0;
frame_ptr_next = frame_ptr_reg;
m_eth_hdr_valid_next = m_eth_hdr_valid_reg && !m_eth_hdr_ready;
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
frame_ptr_next = 8'd0;
s_frame_ready_next = !m_eth_hdr_valid_next;
if (s_frame_ready && s_frame_valid) begin
store_frame = 1'b1;
s_frame_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 = s_arp_htype[15: 8];
frame_ptr_next = 8'd1;
end
state_next = STATE_WRITE_HEADER;
end else begin
state_next = STATE_IDLE;
end
end
STATE_WRITE_HEADER: begin
// read header state
if (m_eth_payload_axis_tready_int_reg) begin
// word transfer out
frame_ptr_next = frame_ptr_reg + 8'd1;
m_eth_payload_axis_tvalid_int = 1'b1;
state_next = STATE_WRITE_HEADER;
case (frame_ptr_reg)
8'h00: m_eth_payload_axis_tdata_int = arp_htype_reg[15: 8];
8'h01: m_eth_payload_axis_tdata_int = arp_htype_reg[ 7: 0];
8'h02: m_eth_payload_axis_tdata_int = arp_ptype_reg[15: 8];
8'h03: m_eth_payload_axis_tdata_int = arp_ptype_reg[ 7: 0];
8'h04: m_eth_payload_axis_tdata_int = 8'd6; // hlen
8'h05: m_eth_payload_axis_tdata_int = 8'd4; // plen
8'h06: m_eth_payload_axis_tdata_int = arp_oper_reg[15: 8];
8'h07: m_eth_payload_axis_tdata_int = arp_oper_reg[ 7: 0];
8'h08: m_eth_payload_axis_tdata_int = arp_sha_reg[47:40];
8'h09: m_eth_payload_axis_tdata_int = arp_sha_reg[39:32];
8'h0A: m_eth_payload_axis_tdata_int = arp_sha_reg[31:24];
8'h0B: m_eth_payload_axis_tdata_int = arp_sha_reg[23:16];
8'h0C: m_eth_payload_axis_tdata_int = arp_sha_reg[15: 8];
8'h0D: m_eth_payload_axis_tdata_int = arp_sha_reg[ 7: 0];
8'h0E: m_eth_payload_axis_tdata_int = arp_spa_reg[31:24];
8'h0F: m_eth_payload_axis_tdata_int = arp_spa_reg[23:16];
8'h10: m_eth_payload_axis_tdata_int = arp_spa_reg[15: 8];
8'h11: m_eth_payload_axis_tdata_int = arp_spa_reg[ 7: 0];
8'h12: m_eth_payload_axis_tdata_int = arp_tha_reg[47:40];
8'h13: m_eth_payload_axis_tdata_int = arp_tha_reg[39:32];
8'h14: m_eth_payload_axis_tdata_int = arp_tha_reg[31:24];
8'h15: m_eth_payload_axis_tdata_int = arp_tha_reg[23:16];
8'h16: m_eth_payload_axis_tdata_int = arp_tha_reg[15: 8];
8'h17: m_eth_payload_axis_tdata_int = arp_tha_reg[ 7: 0];
8'h18: m_eth_payload_axis_tdata_int = arp_tpa_reg[31:24];
8'h19: m_eth_payload_axis_tdata_int = arp_tpa_reg[23:16];
8'h1A: m_eth_payload_axis_tdata_int = arp_tpa_reg[15: 8];
8'h1B: begin
m_eth_payload_axis_tdata_int = arp_tpa_reg[ 7: 0];
m_eth_payload_axis_tlast_int = 1'b1;
s_frame_ready_next = !m_eth_hdr_valid_next;
state_next = STATE_IDLE;
end
endcase
end else begin
state_next = STATE_WRITE_HEADER;
end
end
endcase
end
always @(posedge clk) begin
if (rst) begin
state_reg <= STATE_IDLE;
frame_ptr_reg <= 8'd0;
s_frame_ready_reg <= 1'b0;
m_eth_hdr_valid_reg <= 1'b0;
busy_reg <= 1'b0;
end else begin
state_reg <= state_next;
frame_ptr_reg <= frame_ptr_next;
s_frame_ready_reg <= s_frame_ready_next;
m_eth_hdr_valid_reg <= m_eth_hdr_valid_next;
busy_reg <= state_next != STATE_IDLE;
end
if (store_frame) 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;
arp_htype_reg <= s_arp_htype;
arp_ptype_reg <= s_arp_ptype;
arp_oper_reg <= s_arp_oper;
arp_sha_reg <= s_arp_sha;
arp_spa_reg <= s_arp_spa;
arp_tha_reg <= s_arp_tha;
arp_tpa_reg <= s_arp_tpa;
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

View file

@ -1,453 +0,0 @@
/*
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
/*
* AXI4-Stream asynchronous FIFO
*/
module axis_async_fifo #
(
parameter ADDR_WIDTH = 12,
parameter DATA_WIDTH = 8,
parameter KEEP_ENABLE = (DATA_WIDTH>8),
parameter KEEP_WIDTH = (DATA_WIDTH/8),
parameter LAST_ENABLE = 1,
parameter ID_ENABLE = 0,
parameter ID_WIDTH = 8,
parameter DEST_ENABLE = 0,
parameter DEST_WIDTH = 8,
parameter USER_ENABLE = 1,
parameter USER_WIDTH = 1,
parameter FRAME_FIFO = 0,
parameter USER_BAD_FRAME_VALUE = 1'b1,
parameter USER_BAD_FRAME_MASK = 1'b1,
parameter DROP_BAD_FRAME = 0,
parameter DROP_WHEN_FULL = 0
)
(
/*
* Common asynchronous reset
*/
input wire async_rst,
/*
* AXI input
*/
input wire s_clk,
input wire [DATA_WIDTH-1:0] s_axis_tdata,
input wire [KEEP_WIDTH-1:0] s_axis_tkeep,
input wire s_axis_tvalid,
output wire s_axis_tready,
input wire s_axis_tlast,
input wire [ID_WIDTH-1:0] s_axis_tid,
input wire [DEST_WIDTH-1:0] s_axis_tdest,
input wire [USER_WIDTH-1:0] s_axis_tuser,
/*
* AXI output
*/
input wire m_clk,
output wire [DATA_WIDTH-1:0] m_axis_tdata,
output wire [KEEP_WIDTH-1:0] m_axis_tkeep,
output wire m_axis_tvalid,
input wire m_axis_tready,
output wire m_axis_tlast,
output wire [ID_WIDTH-1:0] m_axis_tid,
output wire [DEST_WIDTH-1:0] m_axis_tdest,
output wire [USER_WIDTH-1:0] m_axis_tuser,
/*
* Status
*/
output wire s_status_overflow,
output wire s_status_bad_frame,
output wire s_status_good_frame,
output wire m_status_overflow,
output wire m_status_bad_frame,
output wire m_status_good_frame
);
// check configuration
initial begin
if (FRAME_FIFO && !LAST_ENABLE) begin
$error("Error: FRAME_FIFO set requires LAST_ENABLE set");
$finish;
end
if (DROP_BAD_FRAME && !FRAME_FIFO) begin
$error("Error: DROP_BAD_FRAME set requires FRAME_FIFO set");
$finish;
end
if (DROP_WHEN_FULL && !FRAME_FIFO) begin
$error("Error: DROP_WHEN_FULL set requires FRAME_FIFO set");
$finish;
end
if (DROP_BAD_FRAME && (USER_BAD_FRAME_MASK & {USER_WIDTH{1'b1}}) == 0) begin
$error("Error: Invalid USER_BAD_FRAME_MASK value");
$finish;
end
end
localparam KEEP_OFFSET = DATA_WIDTH;
localparam LAST_OFFSET = KEEP_OFFSET + (KEEP_ENABLE ? KEEP_WIDTH : 0);
localparam ID_OFFSET = LAST_OFFSET + (LAST_ENABLE ? 1 : 0);
localparam DEST_OFFSET = ID_OFFSET + (ID_ENABLE ? ID_WIDTH : 0);
localparam USER_OFFSET = DEST_OFFSET + (DEST_ENABLE ? DEST_WIDTH : 0);
localparam WIDTH = USER_OFFSET + (USER_ENABLE ? USER_WIDTH : 0);
reg [ADDR_WIDTH:0] wr_ptr_reg = {ADDR_WIDTH+1{1'b0}}, wr_ptr_next;
reg [ADDR_WIDTH:0] wr_ptr_cur_reg = {ADDR_WIDTH+1{1'b0}}, wr_ptr_cur_next;
reg [ADDR_WIDTH:0] wr_ptr_gray_reg = {ADDR_WIDTH+1{1'b0}}, wr_ptr_gray_next;
reg [ADDR_WIDTH:0] wr_ptr_cur_gray_reg = {ADDR_WIDTH+1{1'b0}}, wr_ptr_cur_gray_next;
reg [ADDR_WIDTH:0] wr_addr_reg = {ADDR_WIDTH+1{1'b0}};
reg [ADDR_WIDTH:0] rd_ptr_reg = {ADDR_WIDTH+1{1'b0}}, rd_ptr_next;
reg [ADDR_WIDTH:0] rd_ptr_gray_reg = {ADDR_WIDTH+1{1'b0}}, rd_ptr_gray_next;
reg [ADDR_WIDTH:0] rd_addr_reg = {ADDR_WIDTH+1{1'b0}};
reg [ADDR_WIDTH:0] wr_ptr_gray_sync1_reg = {ADDR_WIDTH+1{1'b0}};
reg [ADDR_WIDTH:0] wr_ptr_gray_sync2_reg = {ADDR_WIDTH+1{1'b0}};
reg [ADDR_WIDTH:0] rd_ptr_gray_sync1_reg = {ADDR_WIDTH+1{1'b0}};
reg [ADDR_WIDTH:0] rd_ptr_gray_sync2_reg = {ADDR_WIDTH+1{1'b0}};
reg s_rst_sync1_reg = 1'b1;
reg s_rst_sync2_reg = 1'b1;
reg s_rst_sync3_reg = 1'b1;
reg m_rst_sync1_reg = 1'b1;
reg m_rst_sync2_reg = 1'b1;
reg m_rst_sync3_reg = 1'b1;
reg [WIDTH-1:0] mem[(2**ADDR_WIDTH)-1:0];
reg [WIDTH-1:0] mem_read_data_reg;
reg mem_read_data_valid_reg = 1'b0, mem_read_data_valid_next;
wire [WIDTH-1:0] s_axis;
reg [WIDTH-1:0] m_axis_reg;
reg m_axis_tvalid_reg = 1'b0, m_axis_tvalid_next;
// full when first TWO MSBs do NOT match, but rest matches
// (gray code equivalent of first MSB different but rest same)
wire full = ((wr_ptr_gray_reg[ADDR_WIDTH] != rd_ptr_gray_sync2_reg[ADDR_WIDTH]) &&
(wr_ptr_gray_reg[ADDR_WIDTH-1] != rd_ptr_gray_sync2_reg[ADDR_WIDTH-1]) &&
(wr_ptr_gray_reg[ADDR_WIDTH-2:0] == rd_ptr_gray_sync2_reg[ADDR_WIDTH-2:0]));
wire full_cur = ((wr_ptr_cur_gray_reg[ADDR_WIDTH] != rd_ptr_gray_sync2_reg[ADDR_WIDTH]) &&
(wr_ptr_cur_gray_reg[ADDR_WIDTH-1] != rd_ptr_gray_sync2_reg[ADDR_WIDTH-1]) &&
(wr_ptr_cur_gray_reg[ADDR_WIDTH-2:0] == rd_ptr_gray_sync2_reg[ADDR_WIDTH-2:0]));
// empty when pointers match exactly
wire empty = rd_ptr_gray_reg == wr_ptr_gray_sync2_reg;
// overflow within packet
wire full_wr = ((wr_ptr_reg[ADDR_WIDTH] != wr_ptr_cur_reg[ADDR_WIDTH]) &&
(wr_ptr_reg[ADDR_WIDTH-1:0] == wr_ptr_cur_reg[ADDR_WIDTH-1:0]));
// control signals
reg write;
reg read;
reg store_output;
reg drop_frame_reg = 1'b0, drop_frame_next;
reg overflow_reg = 1'b0, overflow_next;
reg bad_frame_reg = 1'b0, bad_frame_next;
reg good_frame_reg = 1'b0, good_frame_next;
reg overflow_sync1_reg = 1'b0;
reg overflow_sync2_reg = 1'b0;
reg overflow_sync3_reg = 1'b0;
reg overflow_sync4_reg = 1'b0;
reg bad_frame_sync1_reg = 1'b0;
reg bad_frame_sync2_reg = 1'b0;
reg bad_frame_sync3_reg = 1'b0;
reg bad_frame_sync4_reg = 1'b0;
reg good_frame_sync1_reg = 1'b0;
reg good_frame_sync2_reg = 1'b0;
reg good_frame_sync3_reg = 1'b0;
reg good_frame_sync4_reg = 1'b0;
assign s_axis_tready = (FRAME_FIFO ? (!full_cur || full_wr || DROP_WHEN_FULL) : !full) && !s_rst_sync3_reg;
generate
assign s_axis[DATA_WIDTH-1:0] = s_axis_tdata;
if (KEEP_ENABLE) assign s_axis[KEEP_OFFSET +: KEEP_WIDTH] = s_axis_tkeep;
if (LAST_ENABLE) assign s_axis[LAST_OFFSET] = s_axis_tlast;
if (ID_ENABLE) assign s_axis[ID_OFFSET +: ID_WIDTH] = s_axis_tid;
if (DEST_ENABLE) assign s_axis[DEST_OFFSET +: DEST_WIDTH] = s_axis_tdest;
if (USER_ENABLE) assign s_axis[USER_OFFSET +: USER_WIDTH] = s_axis_tuser;
endgenerate
assign m_axis_tvalid = m_axis_tvalid_reg;
assign m_axis_tdata = m_axis_reg[DATA_WIDTH-1:0];
assign m_axis_tkeep = KEEP_ENABLE ? m_axis_reg[KEEP_OFFSET +: KEEP_WIDTH] : {KEEP_WIDTH{1'b1}};
assign m_axis_tlast = LAST_ENABLE ? m_axis_reg[LAST_OFFSET] : 1'b1;
assign m_axis_tid = ID_ENABLE ? m_axis_reg[ID_OFFSET +: ID_WIDTH] : {ID_WIDTH{1'b0}};
assign m_axis_tdest = DEST_ENABLE ? m_axis_reg[DEST_OFFSET +: DEST_WIDTH] : {DEST_WIDTH{1'b0}};
assign m_axis_tuser = USER_ENABLE ? m_axis_reg[USER_OFFSET +: USER_WIDTH] : {USER_WIDTH{1'b0}};
assign s_status_overflow = overflow_reg;
assign s_status_bad_frame = bad_frame_reg;
assign s_status_good_frame = good_frame_reg;
assign m_status_overflow = overflow_sync3_reg ^ overflow_sync4_reg;
assign m_status_bad_frame = bad_frame_sync3_reg ^ bad_frame_sync4_reg;
assign m_status_good_frame = good_frame_sync3_reg ^ good_frame_sync4_reg;
// reset synchronization
always @(posedge s_clk or posedge async_rst) begin
if (async_rst) begin
s_rst_sync1_reg <= 1'b1;
s_rst_sync2_reg <= 1'b1;
s_rst_sync3_reg <= 1'b1;
end else begin
s_rst_sync1_reg <= 1'b0;
s_rst_sync2_reg <= s_rst_sync1_reg || m_rst_sync1_reg;
s_rst_sync3_reg <= s_rst_sync2_reg;
end
end
always @(posedge m_clk or posedge async_rst) begin
if (async_rst) begin
m_rst_sync1_reg <= 1'b1;
m_rst_sync2_reg <= 1'b1;
m_rst_sync3_reg <= 1'b1;
end else begin
m_rst_sync1_reg <= 1'b0;
m_rst_sync2_reg <= s_rst_sync1_reg || m_rst_sync1_reg;
m_rst_sync3_reg <= m_rst_sync2_reg;
end
end
// Write logic
always @* begin
write = 1'b0;
drop_frame_next = 1'b0;
overflow_next = 1'b0;
bad_frame_next = 1'b0;
good_frame_next = 1'b0;
wr_ptr_next = wr_ptr_reg;
wr_ptr_cur_next = wr_ptr_cur_reg;
wr_ptr_gray_next = wr_ptr_gray_reg;
wr_ptr_cur_gray_next = wr_ptr_cur_gray_reg;
if (s_axis_tready && s_axis_tvalid) begin
// transfer in
if (!FRAME_FIFO) begin
// normal FIFO mode
write = 1'b1;
wr_ptr_next = wr_ptr_reg + 1;
wr_ptr_gray_next = wr_ptr_next ^ (wr_ptr_next >> 1);
end else if (full_cur || full_wr || drop_frame_reg) begin
// full, packet overflow, or currently dropping frame
// drop frame
drop_frame_next = 1'b1;
if (s_axis_tlast) begin
// end of frame, reset write pointer
wr_ptr_cur_next = wr_ptr_reg;
wr_ptr_cur_gray_next = wr_ptr_cur_next ^ (wr_ptr_cur_next >> 1);
drop_frame_next = 1'b0;
overflow_next = 1'b1;
end
end else begin
write = 1'b1;
wr_ptr_cur_next = wr_ptr_cur_reg + 1;
wr_ptr_cur_gray_next = wr_ptr_cur_next ^ (wr_ptr_cur_next >> 1);
if (s_axis_tlast) begin
// end of frame
if (DROP_BAD_FRAME && (USER_BAD_FRAME_MASK & s_axis_tuser == USER_BAD_FRAME_VALUE)) begin
// bad packet, reset write pointer
wr_ptr_cur_next = wr_ptr_reg;
wr_ptr_cur_gray_next = wr_ptr_cur_next ^ (wr_ptr_cur_next >> 1);
bad_frame_next = 1'b1;
end else begin
// good packet, update write pointer
wr_ptr_next = wr_ptr_cur_reg + 1;
wr_ptr_gray_next = wr_ptr_next ^ (wr_ptr_next >> 1);
good_frame_next = 1'b1;
end
end
end
end
end
always @(posedge s_clk) begin
if (s_rst_sync3_reg) begin
wr_ptr_reg <= {ADDR_WIDTH+1{1'b0}};
wr_ptr_cur_reg <= {ADDR_WIDTH+1{1'b0}};
wr_ptr_gray_reg <= {ADDR_WIDTH+1{1'b0}};
wr_ptr_cur_gray_reg <= {ADDR_WIDTH+1{1'b0}};
drop_frame_reg <= 1'b0;
overflow_reg <= 1'b0;
bad_frame_reg <= 1'b0;
good_frame_reg <= 1'b0;
end else begin
wr_ptr_reg <= wr_ptr_next;
wr_ptr_cur_reg <= wr_ptr_cur_next;
wr_ptr_gray_reg <= wr_ptr_gray_next;
wr_ptr_cur_gray_reg <= wr_ptr_cur_gray_next;
drop_frame_reg <= drop_frame_next;
overflow_reg <= overflow_next;
bad_frame_reg <= bad_frame_next;
good_frame_reg <= good_frame_next;
end
if (FRAME_FIFO) begin
wr_addr_reg <= wr_ptr_cur_next;
end else begin
wr_addr_reg <= wr_ptr_next;
end
if (write) begin
mem[wr_addr_reg[ADDR_WIDTH-1:0]] <= s_axis;
end
end
// pointer synchronization
always @(posedge s_clk) begin
if (s_rst_sync3_reg) begin
rd_ptr_gray_sync1_reg <= {ADDR_WIDTH+1{1'b0}};
rd_ptr_gray_sync2_reg <= {ADDR_WIDTH+1{1'b0}};
end else begin
rd_ptr_gray_sync1_reg <= rd_ptr_gray_reg;
rd_ptr_gray_sync2_reg <= rd_ptr_gray_sync1_reg;
end
end
always @(posedge m_clk) begin
if (m_rst_sync3_reg) begin
wr_ptr_gray_sync1_reg <= {ADDR_WIDTH+1{1'b0}};
wr_ptr_gray_sync2_reg <= {ADDR_WIDTH+1{1'b0}};
end else begin
wr_ptr_gray_sync1_reg <= wr_ptr_gray_reg;
wr_ptr_gray_sync2_reg <= wr_ptr_gray_sync1_reg;
end
end
// status synchronization
always @(posedge s_clk) begin
if (s_rst_sync3_reg) begin
overflow_sync1_reg <= 1'b0;
bad_frame_sync1_reg <= 1'b0;
good_frame_sync1_reg <= 1'b0;
end else begin
overflow_sync1_reg <= overflow_sync1_reg ^ overflow_reg;
bad_frame_sync1_reg <= bad_frame_sync1_reg ^ bad_frame_reg;
good_frame_sync1_reg <= good_frame_sync1_reg ^ good_frame_reg;
end
end
always @(posedge m_clk) begin
if (m_rst_sync3_reg) begin
overflow_sync2_reg <= 1'b0;
overflow_sync3_reg <= 1'b0;
bad_frame_sync2_reg <= 1'b0;
bad_frame_sync3_reg <= 1'b0;
good_frame_sync2_reg <= 1'b0;
good_frame_sync3_reg <= 1'b0;
end else begin
overflow_sync2_reg <= overflow_sync1_reg;
overflow_sync3_reg <= overflow_sync2_reg;
overflow_sync4_reg <= overflow_sync3_reg;
bad_frame_sync2_reg <= bad_frame_sync1_reg;
bad_frame_sync3_reg <= bad_frame_sync2_reg;
bad_frame_sync4_reg <= bad_frame_sync3_reg;
good_frame_sync2_reg <= good_frame_sync1_reg;
good_frame_sync3_reg <= good_frame_sync2_reg;
good_frame_sync4_reg <= good_frame_sync3_reg;
end
end
// Read logic
always @* begin
read = 1'b0;
rd_ptr_next = rd_ptr_reg;
rd_ptr_gray_next = rd_ptr_gray_reg;
mem_read_data_valid_next = mem_read_data_valid_reg;
if (store_output || !mem_read_data_valid_reg) begin
// output data not valid OR currently being transferred
if (!empty) begin
// not empty, perform read
read = 1'b1;
mem_read_data_valid_next = 1'b1;
rd_ptr_next = rd_ptr_reg + 1;
rd_ptr_gray_next = rd_ptr_next ^ (rd_ptr_next >> 1);
end else begin
// empty, invalidate
mem_read_data_valid_next = 1'b0;
end
end
end
always @(posedge m_clk) begin
if (m_rst_sync3_reg) begin
rd_ptr_reg <= {ADDR_WIDTH+1{1'b0}};
rd_ptr_gray_reg <= {ADDR_WIDTH+1{1'b0}};
mem_read_data_valid_reg <= 1'b0;
end else begin
rd_ptr_reg <= rd_ptr_next;
rd_ptr_gray_reg <= rd_ptr_gray_next;
mem_read_data_valid_reg <= mem_read_data_valid_next;
end
rd_addr_reg <= rd_ptr_next;
if (read) begin
mem_read_data_reg <= mem[rd_addr_reg[ADDR_WIDTH-1:0]];
end
end
// Output register
always @* begin
store_output = 1'b0;
m_axis_tvalid_next = m_axis_tvalid_reg;
if (m_axis_tready || !m_axis_tvalid) begin
store_output = 1'b1;
m_axis_tvalid_next = mem_read_data_valid_reg;
end
end
always @(posedge m_clk) begin
if (m_rst_sync3_reg) begin
m_axis_tvalid_reg <= 1'b0;
end else begin
m_axis_tvalid_reg <= m_axis_tvalid_next;
end
if (store_output) begin
m_axis_reg <= mem_read_data_reg;
end
end
endmodule

View file

@ -1,316 +0,0 @@
/*
Copyright (c) 2013-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
/*
* AXI4-Stream FIFO
*/
module axis_fifo #
(
parameter ADDR_WIDTH = 12,
parameter DATA_WIDTH = 8,
parameter KEEP_ENABLE = (DATA_WIDTH>8),
parameter KEEP_WIDTH = (DATA_WIDTH/8),
parameter LAST_ENABLE = 1,
parameter ID_ENABLE = 0,
parameter ID_WIDTH = 8,
parameter DEST_ENABLE = 0,
parameter DEST_WIDTH = 8,
parameter USER_ENABLE = 1,
parameter USER_WIDTH = 1,
parameter FRAME_FIFO = 0,
parameter USER_BAD_FRAME_VALUE = 1'b1,
parameter USER_BAD_FRAME_MASK = 1'b1,
parameter DROP_BAD_FRAME = 0,
parameter DROP_WHEN_FULL = 0
)
(
input wire clk,
input wire rst,
/*
* AXI input
*/
input wire [DATA_WIDTH-1:0] s_axis_tdata,
input wire [KEEP_WIDTH-1:0] s_axis_tkeep,
input wire s_axis_tvalid,
output wire s_axis_tready,
input wire s_axis_tlast,
input wire [ID_WIDTH-1:0] s_axis_tid,
input wire [DEST_WIDTH-1:0] s_axis_tdest,
input wire [USER_WIDTH-1:0] s_axis_tuser,
/*
* AXI output
*/
output wire [DATA_WIDTH-1:0] m_axis_tdata,
output wire [KEEP_WIDTH-1:0] m_axis_tkeep,
output wire m_axis_tvalid,
input wire m_axis_tready,
output wire m_axis_tlast,
output wire [ID_WIDTH-1:0] m_axis_tid,
output wire [DEST_WIDTH-1:0] m_axis_tdest,
output wire [USER_WIDTH-1:0] m_axis_tuser,
/*
* Status
*/
output wire status_overflow,
output wire status_bad_frame,
output wire status_good_frame
);
// check configuration
initial begin
if (FRAME_FIFO && !LAST_ENABLE) begin
$error("Error: FRAME_FIFO set requires LAST_ENABLE set");
$finish;
end
if (DROP_BAD_FRAME && !FRAME_FIFO) begin
$error("Error: DROP_BAD_FRAME set requires FRAME_FIFO set");
$finish;
end
if (DROP_WHEN_FULL && !FRAME_FIFO) begin
$error("Error: DROP_WHEN_FULL set requires FRAME_FIFO set");
$finish;
end
if (DROP_BAD_FRAME && (USER_BAD_FRAME_MASK & {USER_WIDTH{1'b1}}) == 0) begin
$error("Error: Invalid USER_BAD_FRAME_MASK value");
$finish;
end
end
localparam KEEP_OFFSET = DATA_WIDTH;
localparam LAST_OFFSET = KEEP_OFFSET + (KEEP_ENABLE ? KEEP_WIDTH : 0);
localparam ID_OFFSET = LAST_OFFSET + (LAST_ENABLE ? 1 : 0);
localparam DEST_OFFSET = ID_OFFSET + (ID_ENABLE ? ID_WIDTH : 0);
localparam USER_OFFSET = DEST_OFFSET + (DEST_ENABLE ? DEST_WIDTH : 0);
localparam WIDTH = USER_OFFSET + (USER_ENABLE ? USER_WIDTH : 0);
reg [ADDR_WIDTH:0] wr_ptr_reg = {ADDR_WIDTH+1{1'b0}}, wr_ptr_next;
reg [ADDR_WIDTH:0] wr_ptr_cur_reg = {ADDR_WIDTH+1{1'b0}}, wr_ptr_cur_next;
reg [ADDR_WIDTH:0] wr_addr_reg = {ADDR_WIDTH+1{1'b0}};
reg [ADDR_WIDTH:0] rd_ptr_reg = {ADDR_WIDTH+1{1'b0}}, rd_ptr_next;
reg [ADDR_WIDTH:0] rd_addr_reg = {ADDR_WIDTH+1{1'b0}};
reg [WIDTH-1:0] mem[(2**ADDR_WIDTH)-1:0];
reg [WIDTH-1:0] mem_read_data_reg;
reg mem_read_data_valid_reg = 1'b0, mem_read_data_valid_next;
wire [WIDTH-1:0] s_axis;
reg [WIDTH-1:0] m_axis_reg;
reg m_axis_tvalid_reg = 1'b0, m_axis_tvalid_next;
// full when first MSB different but rest same
wire full = ((wr_ptr_reg[ADDR_WIDTH] != rd_ptr_reg[ADDR_WIDTH]) &&
(wr_ptr_reg[ADDR_WIDTH-1:0] == rd_ptr_reg[ADDR_WIDTH-1:0]));
wire full_cur = ((wr_ptr_cur_reg[ADDR_WIDTH] != rd_ptr_reg[ADDR_WIDTH]) &&
(wr_ptr_cur_reg[ADDR_WIDTH-1:0] == rd_ptr_reg[ADDR_WIDTH-1:0]));
// empty when pointers match exactly
wire empty = wr_ptr_reg == rd_ptr_reg;
// overflow within packet
wire full_wr = ((wr_ptr_reg[ADDR_WIDTH] != wr_ptr_cur_reg[ADDR_WIDTH]) &&
(wr_ptr_reg[ADDR_WIDTH-1:0] == wr_ptr_cur_reg[ADDR_WIDTH-1:0]));
// control signals
reg write;
reg read;
reg store_output;
reg drop_frame_reg = 1'b0, drop_frame_next;
reg overflow_reg = 1'b0, overflow_next;
reg bad_frame_reg = 1'b0, bad_frame_next;
reg good_frame_reg = 1'b0, good_frame_next;
assign s_axis_tready = FRAME_FIFO ? (!full_cur || full_wr || DROP_WHEN_FULL) : !full;
generate
assign s_axis[DATA_WIDTH-1:0] = s_axis_tdata;
if (KEEP_ENABLE) assign s_axis[KEEP_OFFSET +: KEEP_WIDTH] = s_axis_tkeep;
if (LAST_ENABLE) assign s_axis[LAST_OFFSET] = s_axis_tlast;
if (ID_ENABLE) assign s_axis[ID_OFFSET +: ID_WIDTH] = s_axis_tid;
if (DEST_ENABLE) assign s_axis[DEST_OFFSET +: DEST_WIDTH] = s_axis_tdest;
if (USER_ENABLE) assign s_axis[USER_OFFSET +: USER_WIDTH] = s_axis_tuser;
endgenerate
assign m_axis_tvalid = m_axis_tvalid_reg;
assign m_axis_tdata = m_axis_reg[DATA_WIDTH-1:0];
assign m_axis_tkeep = KEEP_ENABLE ? m_axis_reg[KEEP_OFFSET +: KEEP_WIDTH] : {KEEP_WIDTH{1'b1}};
assign m_axis_tlast = LAST_ENABLE ? m_axis_reg[LAST_OFFSET] : 1'b1;
assign m_axis_tid = ID_ENABLE ? m_axis_reg[ID_OFFSET +: ID_WIDTH] : {ID_WIDTH{1'b0}};
assign m_axis_tdest = DEST_ENABLE ? m_axis_reg[DEST_OFFSET +: DEST_WIDTH] : {DEST_WIDTH{1'b0}};
assign m_axis_tuser = USER_ENABLE ? m_axis_reg[USER_OFFSET +: USER_WIDTH] : {USER_WIDTH{1'b0}};
assign status_overflow = overflow_reg;
assign status_bad_frame = bad_frame_reg;
assign status_good_frame = good_frame_reg;
// Write logic
always @* begin
write = 1'b0;
drop_frame_next = 1'b0;
overflow_next = 1'b0;
bad_frame_next = 1'b0;
good_frame_next = 1'b0;
wr_ptr_next = wr_ptr_reg;
wr_ptr_cur_next = wr_ptr_cur_reg;
if (s_axis_tready && s_axis_tvalid) begin
// transfer in
if (!FRAME_FIFO) begin
// normal FIFO mode
write = 1'b1;
wr_ptr_next = wr_ptr_reg + 1;
end else if (full_cur || full_wr || drop_frame_reg) begin
// full, packet overflow, or currently dropping frame
// drop frame
drop_frame_next = 1'b1;
if (s_axis_tlast) begin
// end of frame, reset write pointer
wr_ptr_cur_next = wr_ptr_reg;
drop_frame_next = 1'b0;
overflow_next = 1'b1;
end
end else begin
write = 1'b1;
wr_ptr_cur_next = wr_ptr_cur_reg + 1;
if (s_axis_tlast) begin
// end of frame
if (DROP_BAD_FRAME && (USER_BAD_FRAME_MASK & s_axis_tuser == USER_BAD_FRAME_VALUE)) begin
// bad packet, reset write pointer
wr_ptr_cur_next = wr_ptr_reg;
bad_frame_next = 1'b1;
end else begin
// good packet, update write pointer
wr_ptr_next = wr_ptr_cur_reg + 1;
good_frame_next = 1'b1;
end
end
end
end
end
always @(posedge clk) begin
if (rst) begin
wr_ptr_reg <= {ADDR_WIDTH+1{1'b0}};
wr_ptr_cur_reg <= {ADDR_WIDTH+1{1'b0}};
drop_frame_reg <= 1'b0;
overflow_reg <= 1'b0;
bad_frame_reg <= 1'b0;
good_frame_reg <= 1'b0;
end else begin
wr_ptr_reg <= wr_ptr_next;
wr_ptr_cur_reg <= wr_ptr_cur_next;
drop_frame_reg <= drop_frame_next;
overflow_reg <= overflow_next;
bad_frame_reg <= bad_frame_next;
good_frame_reg <= good_frame_next;
end
if (FRAME_FIFO) begin
wr_addr_reg <= wr_ptr_cur_next;
end else begin
wr_addr_reg <= wr_ptr_next;
end
if (write) begin
mem[wr_addr_reg[ADDR_WIDTH-1:0]] <= s_axis;
end
end
// Read logic
always @* begin
read = 1'b0;
rd_ptr_next = rd_ptr_reg;
mem_read_data_valid_next = mem_read_data_valid_reg;
if (store_output || !mem_read_data_valid_reg) begin
// output data not valid OR currently being transferred
if (!empty) begin
// not empty, perform read
read = 1'b1;
mem_read_data_valid_next = 1'b1;
rd_ptr_next = rd_ptr_reg + 1;
end else begin
// empty, invalidate
mem_read_data_valid_next = 1'b0;
end
end
end
always @(posedge clk) begin
if (rst) begin
rd_ptr_reg <= {ADDR_WIDTH+1{1'b0}};
mem_read_data_valid_reg <= 1'b0;
end else begin
rd_ptr_reg <= rd_ptr_next;
mem_read_data_valid_reg <= mem_read_data_valid_next;
end
rd_addr_reg <= rd_ptr_next;
if (read) begin
mem_read_data_reg <= mem[rd_addr_reg[ADDR_WIDTH-1:0]];
end
end
// Output register
always @* begin
store_output = 1'b0;
m_axis_tvalid_next = m_axis_tvalid_reg;
if (m_axis_tready || !m_axis_tvalid) begin
store_output = 1'b1;
m_axis_tvalid_next = mem_read_data_valid_reg;
end
end
always @(posedge clk) begin
if (rst) begin
m_axis_tvalid_reg <= 1'b0;
end else begin
m_axis_tvalid_reg <= m_axis_tvalid_next;
end
if (store_output) begin
m_axis_reg <= mem_read_data_reg;
end
end
endmodule

View file

View file

@ -1,316 +0,0 @@
/*
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
/*
* Ethernet arbitrated multiplexer
*/
module eth_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,
/*
* Ethernet frame inputs
*/
input wire [S_COUNT-1:0] s_eth_hdr_valid,
output wire [S_COUNT-1:0] s_eth_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*DATA_WIDTH-1:0] s_eth_payload_axis_tdata,
input wire [S_COUNT*KEEP_WIDTH-1:0] s_eth_payload_axis_tkeep,
input wire [S_COUNT-1:0] s_eth_payload_axis_tvalid,
output wire [S_COUNT-1:0] s_eth_payload_axis_tready,
input wire [S_COUNT-1:0] s_eth_payload_axis_tlast,
input wire [S_COUNT*ID_WIDTH-1:0] s_eth_payload_axis_tid,
input wire [S_COUNT*DEST_WIDTH-1:0] s_eth_payload_axis_tdest,
input wire [S_COUNT*USER_WIDTH-1:0] 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 [DATA_WIDTH-1:0] m_eth_payload_axis_tdata,
output wire [KEEP_WIDTH-1: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 [ID_WIDTH-1:0] m_eth_payload_axis_tid,
output wire [DEST_WIDTH-1:0] m_eth_payload_axis_tdest,
output wire [USER_WIDTH-1:0] m_eth_payload_axis_tuser
);
parameter CL_S_COUNT = $clog2(S_COUNT);
reg frame_reg = 1'b0, frame_next;
reg s_eth_hdr_ready_mask_reg = 1'b0, s_eth_hdr_ready_mask_next;
reg m_eth_hdr_valid_reg = 1'b0, m_eth_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;
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_eth_payload_axis_tdata_int;
reg [KEEP_WIDTH-1: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 [ID_WIDTH-1:0] m_eth_payload_axis_tid_int;
reg [DEST_WIDTH-1:0] m_eth_payload_axis_tdest_int;
reg [USER_WIDTH-1:0] m_eth_payload_axis_tuser_int;
wire m_eth_payload_axis_tready_int_early;
assign s_eth_hdr_ready = (!s_eth_hdr_ready_mask_reg && grant_valid) << grant_encoded;
assign s_eth_payload_axis_tready = (m_eth_payload_axis_tready_int_reg && grant_valid) << grant_encoded;
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;
// mux for incoming packet
wire [DATA_WIDTH-1:0] current_s_tdata = s_eth_payload_axis_tdata[grant_encoded*DATA_WIDTH +: DATA_WIDTH];
wire [KEEP_WIDTH-1:0] current_s_tkeep = s_eth_payload_axis_tkeep[grant_encoded*KEEP_WIDTH +: KEEP_WIDTH];
wire current_s_tvalid = s_eth_payload_axis_tvalid[grant_encoded];
wire current_s_tready = s_eth_payload_axis_tready[grant_encoded];
wire current_s_tlast = s_eth_payload_axis_tlast[grant_encoded];
wire [ID_WIDTH-1:0] current_s_tid = s_eth_payload_axis_tid[grant_encoded*ID_WIDTH +: ID_WIDTH];
wire [DEST_WIDTH-1:0] current_s_tdest = s_eth_payload_axis_tdest[grant_encoded*DEST_WIDTH +: DEST_WIDTH];
wire [USER_WIDTH-1:0] current_s_tuser = s_eth_payload_axis_tuser[grant_encoded*USER_WIDTH +: USER_WIDTH];
// arbiter instance
rgmii_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)
);
generate
genvar n;
for (n = 0; n < S_COUNT; n = n + 1) begin
assign request[n] = s_eth_hdr_valid[n] && !grant[n];
assign acknowledge[n] = grant[n] && s_eth_payload_axis_tvalid[n] && s_eth_payload_axis_tready[n] && s_eth_payload_axis_tlast[n];
end
endgenerate
always @* begin
frame_next = frame_reg;
s_eth_hdr_ready_mask_next = s_eth_hdr_ready_mask_reg;
m_eth_hdr_valid_next = m_eth_hdr_valid_reg && !m_eth_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;
if (s_eth_payload_axis_tvalid[grant_encoded] && s_eth_payload_axis_tready[grant_encoded]) begin
// end of frame detection
if (s_eth_payload_axis_tlast[grant_encoded]) begin
frame_next = 1'b0;
s_eth_hdr_ready_mask_next = 1'b0;
end
end
if (!frame_reg && grant_valid) begin
// start of frame
frame_next = 1'b1;
s_eth_hdr_ready_mask_next = 1'b1;
m_eth_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];
end
// pass through selected packet data
m_eth_payload_axis_tdata_int = current_s_tdata;
m_eth_payload_axis_tkeep_int = current_s_tkeep;
m_eth_payload_axis_tvalid_int = current_s_tvalid && m_eth_payload_axis_tready_int_reg && grant_valid;
m_eth_payload_axis_tlast_int = current_s_tlast;
m_eth_payload_axis_tid_int = current_s_tid;
m_eth_payload_axis_tdest_int = current_s_tdest;
m_eth_payload_axis_tuser_int = current_s_tuser;
end
always @(posedge clk) begin
if (rst) begin
frame_reg <= 1'b0;
s_eth_hdr_ready_mask_reg <= 1'b0;
m_eth_hdr_valid_reg <= 1'b0;
end else begin
frame_reg <= frame_next;
s_eth_hdr_ready_mask_reg <= s_eth_hdr_ready_mask_next;
m_eth_hdr_valid_reg <= m_eth_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;
end
// output datapath logic
reg [DATA_WIDTH-1:0] m_eth_payload_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] m_eth_payload_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
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 [ID_WIDTH-1:0] m_eth_payload_axis_tid_reg = {ID_WIDTH{1'b0}};
reg [DEST_WIDTH-1:0] m_eth_payload_axis_tdest_reg = {DEST_WIDTH{1'b0}};
reg [USER_WIDTH-1:0] m_eth_payload_axis_tuser_reg = {USER_WIDTH{1'b0}};
reg [DATA_WIDTH-1:0] temp_m_eth_payload_axis_tdata_reg = {DATA_WIDTH{1'b0}};
reg [KEEP_WIDTH-1:0] temp_m_eth_payload_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
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 [ID_WIDTH-1:0] temp_m_eth_payload_axis_tid_reg = {ID_WIDTH{1'b0}};
reg [DEST_WIDTH-1:0] temp_m_eth_payload_axis_tdest_reg = {DEST_WIDTH{1'b0}};
reg [USER_WIDTH-1:0] temp_m_eth_payload_axis_tuser_reg = {USER_WIDTH{1'b0}};
// datapath control
reg store_axis_int_to_output;
reg store_axis_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 = KEEP_ENABLE ? m_eth_payload_axis_tkeep_reg : {KEEP_WIDTH{1'b1}};
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_tid = ID_ENABLE ? m_eth_payload_axis_tid_reg : {ID_WIDTH{1'b0}};
assign m_eth_payload_axis_tdest = DEST_ENABLE ? m_eth_payload_axis_tdest_reg : {DEST_WIDTH{1'b0}};
assign m_eth_payload_axis_tuser = USER_ENABLE ? m_eth_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_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_axis_int_to_output = 1'b0;
store_axis_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_axis_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_axis_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_axis_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_tid_reg <= m_eth_payload_axis_tid_int;
m_eth_payload_axis_tdest_reg <= m_eth_payload_axis_tdest_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_tid_reg <= temp_m_eth_payload_axis_tid_reg;
m_eth_payload_axis_tdest_reg <= temp_m_eth_payload_axis_tdest_reg;
m_eth_payload_axis_tuser_reg <= temp_m_eth_payload_axis_tuser_reg;
end
if (store_axis_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_tid_reg <= m_eth_payload_axis_tid_int;
temp_m_eth_payload_axis_tdest_reg <= m_eth_payload_axis_tdest_int;
temp_m_eth_payload_axis_tuser_reg <= m_eth_payload_axis_tuser_int;
end
end
endmodule

View file

@ -1,370 +0,0 @@
/*
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
/*
* AXI4-Stream ethernet frame receiver (AXI in, Ethernet frame out)
*/
module eth_axis_rx
(
input wire clk,
input wire rst,
/*
* AXI input
*/
input wire [7:0] s_axis_tdata,
input wire s_axis_tvalid,
output wire s_axis_tready,
input wire s_axis_tlast,
input wire s_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_header_early_termination
);
/*
Ethernet frame
Field Length
Destination MAC address 6 octets
Source MAC address 6 octets
Ethertype 2 octets
This module receives an Ethernet frame on an AXI stream interface, decodes
and strips the headers, then produces the header fields in parallel along
with the payload in a separate AXI stream.
*/
localparam [1:0]
STATE_IDLE = 2'd0,
STATE_READ_HEADER = 2'd1,
STATE_READ_PAYLOAD = 2'd2;
reg [1:0] state_reg = STATE_IDLE, state_next;
// datapath control signals
reg store_eth_dest_mac_0;
reg store_eth_dest_mac_1;
reg store_eth_dest_mac_2;
reg store_eth_dest_mac_3;
reg store_eth_dest_mac_4;
reg store_eth_dest_mac_5;
reg store_eth_src_mac_0;
reg store_eth_src_mac_1;
reg store_eth_src_mac_2;
reg store_eth_src_mac_3;
reg store_eth_src_mac_4;
reg store_eth_src_mac_5;
reg store_eth_type_0;
reg store_eth_type_1;
reg [7:0] frame_ptr_reg = 8'd0, frame_ptr_next;
reg s_axis_tready_reg = 1'b0, s_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_header_early_termination_reg = 1'b0, error_header_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_axis_tready = s_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_header_early_termination = error_header_early_termination_reg;
always @* begin
state_next = STATE_IDLE;
s_axis_tready_next = 1'b0;
store_eth_dest_mac_0 = 1'b0;
store_eth_dest_mac_1 = 1'b0;
store_eth_dest_mac_2 = 1'b0;
store_eth_dest_mac_3 = 1'b0;
store_eth_dest_mac_4 = 1'b0;
store_eth_dest_mac_5 = 1'b0;
store_eth_src_mac_0 = 1'b0;
store_eth_src_mac_1 = 1'b0;
store_eth_src_mac_2 = 1'b0;
store_eth_src_mac_3 = 1'b0;
store_eth_src_mac_4 = 1'b0;
store_eth_src_mac_5 = 1'b0;
store_eth_type_0 = 1'b0;
store_eth_type_1 = 1'b0;
frame_ptr_next = frame_ptr_reg;
m_eth_hdr_valid_next = m_eth_hdr_valid_reg && !m_eth_hdr_ready;
error_header_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
frame_ptr_next = 8'd0;
s_axis_tready_next = !m_eth_hdr_valid_reg;
if (s_axis_tready && s_axis_tvalid) begin
// got first word of packet
if (s_axis_tlast) begin
// tlast asserted on first word
error_header_early_termination_next = 1'b1;
state_next = STATE_IDLE;
end else begin
// move to read header state
frame_ptr_next = 1'b1;
store_eth_dest_mac_5 = 1'b1;
state_next = STATE_READ_HEADER;
end
end else begin
state_next = STATE_IDLE;
end
end
STATE_READ_HEADER: begin
// read header
s_axis_tready_next = 1'b1;
if (s_axis_tready && s_axis_tvalid) begin
// word transfer in - store it
frame_ptr_next = frame_ptr_reg + 8'd1;
state_next = STATE_READ_HEADER;
case (frame_ptr_reg)
8'h00: store_eth_dest_mac_5 = 1'b1;
8'h01: store_eth_dest_mac_4 = 1'b1;
8'h02: store_eth_dest_mac_3 = 1'b1;
8'h03: store_eth_dest_mac_2 = 1'b1;
8'h04: store_eth_dest_mac_1 = 1'b1;
8'h05: store_eth_dest_mac_0 = 1'b1;
8'h06: store_eth_src_mac_5 = 1'b1;
8'h07: store_eth_src_mac_4 = 1'b1;
8'h08: store_eth_src_mac_3 = 1'b1;
8'h09: store_eth_src_mac_2 = 1'b1;
8'h0A: store_eth_src_mac_1 = 1'b1;
8'h0B: store_eth_src_mac_0 = 1'b1;
8'h0C: store_eth_type_1 = 1'b1;
8'h0D: begin
store_eth_type_0 = 1'b1;
m_eth_hdr_valid_next = 1'b1;
s_axis_tready_next = m_eth_payload_axis_tready_int_early;
state_next = STATE_READ_PAYLOAD;
end
endcase
if (s_axis_tlast) begin
error_header_early_termination_next = 1'b1;
s_axis_tready_next = !m_eth_hdr_valid_reg;
state_next = STATE_IDLE;
end
end else begin
state_next = STATE_READ_HEADER;
end
end
STATE_READ_PAYLOAD: begin
// read payload
s_axis_tready_next = m_eth_payload_axis_tready_int_early;
m_eth_payload_axis_tdata_int = s_axis_tdata;
m_eth_payload_axis_tvalid_int = s_axis_tvalid;
m_eth_payload_axis_tlast_int = s_axis_tlast;
m_eth_payload_axis_tuser_int = s_axis_tuser;
if (s_axis_tready && s_axis_tvalid) begin
// word transfer through
if (s_axis_tlast) begin
s_axis_tready_next = !m_eth_hdr_valid_reg;
state_next = STATE_IDLE;
end else begin
state_next = STATE_READ_PAYLOAD;
end
end else begin
state_next = STATE_READ_PAYLOAD;
end
end
endcase
end
always @(posedge clk) begin
if (rst) begin
state_reg <= STATE_IDLE;
frame_ptr_reg <= 8'd0;
s_axis_tready_reg <= 1'b0;
m_eth_hdr_valid_reg <= 1'b0;
busy_reg <= 1'b0;
error_header_early_termination_reg <= 1'b0;
end else begin
state_reg <= state_next;
frame_ptr_reg <= frame_ptr_next;
s_axis_tready_reg <= s_axis_tready_next;
m_eth_hdr_valid_reg <= m_eth_hdr_valid_next;
error_header_early_termination_reg <= error_header_early_termination_next;
busy_reg <= state_next != STATE_IDLE;
end
// datapath
if (store_eth_dest_mac_0) m_eth_dest_mac_reg[ 7: 0] <= s_axis_tdata;
if (store_eth_dest_mac_1) m_eth_dest_mac_reg[15: 8] <= s_axis_tdata;
if (store_eth_dest_mac_2) m_eth_dest_mac_reg[23:16] <= s_axis_tdata;
if (store_eth_dest_mac_3) m_eth_dest_mac_reg[31:24] <= s_axis_tdata;
if (store_eth_dest_mac_4) m_eth_dest_mac_reg[39:32] <= s_axis_tdata;
if (store_eth_dest_mac_5) m_eth_dest_mac_reg[47:40] <= s_axis_tdata;
if (store_eth_src_mac_0) m_eth_src_mac_reg[ 7: 0] <= s_axis_tdata;
if (store_eth_src_mac_1) m_eth_src_mac_reg[15: 8] <= s_axis_tdata;
if (store_eth_src_mac_2) m_eth_src_mac_reg[23:16] <= s_axis_tdata;
if (store_eth_src_mac_3) m_eth_src_mac_reg[31:24] <= s_axis_tdata;
if (store_eth_src_mac_4) m_eth_src_mac_reg[39:32] <= s_axis_tdata;
if (store_eth_src_mac_5) m_eth_src_mac_reg[47:40] <= s_axis_tdata;
if (store_eth_type_0) m_eth_type_reg[ 7: 0] <= s_axis_tdata;
if (store_eth_type_1) m_eth_type_reg[15: 8] <= s_axis_tdata;
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

View file

@ -1,312 +0,0 @@
/*
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
/*
* AXI4-Stream ethernet frame transmitter (Ethernet frame in, AXI out)
*/
module eth_axis_tx
(
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,
/*
* AXI output
*/
output wire [7:0] m_axis_tdata,
output wire m_axis_tvalid,
input wire m_axis_tready,
output wire m_axis_tlast,
output wire m_axis_tuser,
/*
* Status signals
*/
output wire busy
);
/*
Ethernet frame
Field Length
Destination MAC address 6 octets
Source MAC address 6 octets
Ethertype 2 octets
This module receives an Ethernet frame with header fields in parallel along
with the payload in an AXI stream, combines the header with the payload, and
transmits the complete Ethernet frame on the output AXI stream interface.
*/
localparam [1:0]
STATE_IDLE = 2'd0,
STATE_WRITE_HEADER = 2'd1,
STATE_WRITE_PAYLOAD = 2'd2;
reg [1:0] state_reg = STATE_IDLE, state_next;
// datapath control signals
reg store_eth_hdr;
reg [7:0] frame_ptr_reg = 8'd0, frame_ptr_next;
reg [47:0] eth_dest_mac_reg = 48'd0;
reg [47:0] eth_src_mac_reg = 48'd0;
reg [15:0] eth_type_reg = 16'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 busy_reg = 1'b0;
// internal datapath
reg [7:0] m_axis_tdata_int;
reg m_axis_tvalid_int;
reg m_axis_tready_int_reg = 1'b0;
reg m_axis_tlast_int;
reg m_axis_tuser_int;
wire m_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 busy = busy_reg;
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;
frame_ptr_next = frame_ptr_reg;
m_axis_tdata_int = 8'd0;
m_axis_tvalid_int = 1'b0;
m_axis_tlast_int = 1'b0;
m_axis_tuser_int = 1'b0;
case (state_reg)
STATE_IDLE: begin
// idle state - wait for data
frame_ptr_next = 8'd0;
s_eth_hdr_ready_next = 1'b1;
if (s_eth_hdr_ready && s_eth_hdr_valid) begin
store_eth_hdr = 1'b1;
s_eth_hdr_ready_next = 1'b0;
if (m_axis_tready_int_reg) begin
m_axis_tvalid_int = 1'b1;
m_axis_tdata_int = s_eth_dest_mac[47:40];
frame_ptr_next = 1'b1;
end
state_next = STATE_WRITE_HEADER;
end else begin
state_next = STATE_IDLE;
end
end
STATE_WRITE_HEADER: begin
// write header
if (m_axis_tready_int_reg) begin
frame_ptr_next = frame_ptr_reg+1;
m_axis_tvalid_int = 1'b1;
state_next = STATE_WRITE_HEADER;
case (frame_ptr_reg)
8'h00: m_axis_tdata_int = eth_dest_mac_reg[47:40];
8'h01: m_axis_tdata_int = eth_dest_mac_reg[39:32];
8'h02: m_axis_tdata_int = eth_dest_mac_reg[31:24];
8'h03: m_axis_tdata_int = eth_dest_mac_reg[23:16];
8'h04: m_axis_tdata_int = eth_dest_mac_reg[15: 8];
8'h05: m_axis_tdata_int = eth_dest_mac_reg[ 7: 0];
8'h06: m_axis_tdata_int = eth_src_mac_reg[47:40];
8'h07: m_axis_tdata_int = eth_src_mac_reg[39:32];
8'h08: m_axis_tdata_int = eth_src_mac_reg[31:24];
8'h09: m_axis_tdata_int = eth_src_mac_reg[23:16];
8'h0A: m_axis_tdata_int = eth_src_mac_reg[15: 8];
8'h0B: m_axis_tdata_int = eth_src_mac_reg[ 7: 0];
8'h0C: m_axis_tdata_int = eth_type_reg[15: 8];
8'h0D: begin
m_axis_tdata_int = eth_type_reg[ 7: 0];
s_eth_payload_axis_tready_next = m_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_eth_payload_axis_tready_next = m_axis_tready_int_early;
m_axis_tdata_int = s_eth_payload_axis_tdata;
m_axis_tvalid_int = s_eth_payload_axis_tvalid;
m_axis_tlast_int = s_eth_payload_axis_tlast;
m_axis_tuser_int = s_eth_payload_axis_tuser;
if (s_eth_payload_axis_tready && s_eth_payload_axis_tvalid) begin
// word transfer through
if (s_eth_payload_axis_tlast) begin
s_eth_payload_axis_tready_next = 1'b0;
s_eth_hdr_ready_next = 1'b1;
state_next = STATE_IDLE;
end else begin
state_next = STATE_WRITE_PAYLOAD;
end
end else begin
state_next = STATE_WRITE_PAYLOAD;
end
end
endcase
end
always @(posedge clk) begin
if (rst) begin
state_reg <= STATE_IDLE;
frame_ptr_reg <= 8'd0;
s_eth_hdr_ready_reg <= 1'b0;
s_eth_payload_axis_tready_reg <= 1'b0;
busy_reg <= 1'b0;
end else begin
state_reg <= state_next;
frame_ptr_reg <= frame_ptr_next;
s_eth_hdr_ready_reg <= s_eth_hdr_ready_next;
s_eth_payload_axis_tready_reg <= s_eth_payload_axis_tready_next;
busy_reg <= state_next != STATE_IDLE;
end
// datapath
if (store_eth_hdr) begin
eth_dest_mac_reg <= s_eth_dest_mac;
eth_src_mac_reg <= s_eth_src_mac;
eth_type_reg <= s_eth_type;
end
end
// output datapath logic
reg [7:0] m_axis_tdata_reg = 8'd0;
reg m_axis_tvalid_reg = 1'b0, m_axis_tvalid_next;
reg m_axis_tlast_reg = 1'b0;
reg m_axis_tuser_reg = 1'b0;
reg [7:0] temp_m_axis_tdata_reg = 8'd0;
reg temp_m_axis_tvalid_reg = 1'b0, temp_m_axis_tvalid_next;
reg temp_m_axis_tlast_reg = 1'b0;
reg temp_m_axis_tuser_reg = 1'b0;
// datapath control
reg store_axis_int_to_output;
reg store_axis_int_to_temp;
reg store_axis_temp_to_output;
assign m_axis_tdata = m_axis_tdata_reg;
assign m_axis_tvalid = m_axis_tvalid_reg;
assign m_axis_tlast = m_axis_tlast_reg;
assign m_axis_tuser = m_axis_tuser_reg;
// 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_axis_tready_int_early = m_axis_tready || (!temp_m_axis_tvalid_reg && (!m_axis_tvalid_reg || !m_axis_tvalid_int));
always @* begin
// transfer sink ready state to source
m_axis_tvalid_next = m_axis_tvalid_reg;
temp_m_axis_tvalid_next = temp_m_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_axis_tready_int_reg) begin
// input is ready
if (m_axis_tready || !m_axis_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output
m_axis_tvalid_next = m_axis_tvalid_int;
store_axis_int_to_output = 1'b1;
end else begin
// output is not ready, store input in temp
temp_m_axis_tvalid_next = m_axis_tvalid_int;
store_axis_int_to_temp = 1'b1;
end
end else if (m_axis_tready) begin
// input is not ready, but output is ready
m_axis_tvalid_next = temp_m_axis_tvalid_reg;
temp_m_axis_tvalid_next = 1'b0;
store_axis_temp_to_output = 1'b1;
end
end
always @(posedge clk) begin
if (rst) begin
m_axis_tvalid_reg <= 1'b0;
m_axis_tready_int_reg <= 1'b0;
temp_m_axis_tvalid_reg <= 1'b0;
end else begin
m_axis_tvalid_reg <= m_axis_tvalid_next;
m_axis_tready_int_reg <= m_axis_tready_int_early;
temp_m_axis_tvalid_reg <= temp_m_axis_tvalid_next;
end
// datapath
if (store_axis_int_to_output) begin
m_axis_tdata_reg <= m_axis_tdata_int;
m_axis_tlast_reg <= m_axis_tlast_int;
m_axis_tuser_reg <= m_axis_tuser_int;
end else if (store_axis_temp_to_output) begin
m_axis_tdata_reg <= temp_m_axis_tdata_reg;
m_axis_tlast_reg <= temp_m_axis_tlast_reg;
m_axis_tuser_reg <= temp_m_axis_tuser_reg;
end
if (store_axis_int_to_temp) begin
temp_m_axis_tdata_reg <= m_axis_tdata_int;
temp_m_axis_tlast_reg <= m_axis_tlast_int;
temp_m_axis_tuser_reg <= m_axis_tuser_int;
end
end
endmodule

View file

@ -1,341 +0,0 @@
/*
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

View file

@ -1,407 +0,0 @@
/*
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
rgmii_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)
);
generate
genvar n;
for (n = 0; n < S_COUNT; n = n + 1) begin
assign request[n] = s_ip_hdr_valid[n] && !grant[n];
assign acknowledge[n] = grant[n] && s_ip_payload_axis_tvalid[n] && s_ip_payload_axis_tready[n] && s_ip_payload_axis_tlast[n];
end
endgenerate
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

View file

@ -1,440 +0,0 @@
/*
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

View file

@ -1,575 +0,0 @@
/*
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 [15:0] frame_ptr_reg = 16'd0, frame_ptr_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;
frame_ptr_next = frame_ptr_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
frame_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;
if (s_eth_payload_axis_tready && s_eth_payload_axis_tvalid) begin
// word transfer in - store it
frame_ptr_next = frame_ptr_reg + 16'd1;
state_next = STATE_READ_HEADER;
if (frame_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 (frame_ptr_reg)
8'h00: store_ip_version_ihl = 1'b1;
8'h01: store_ip_dscp_ecn = 1'b1;
8'h02: store_ip_length_1 = 1'b1;
8'h03: store_ip_length_0 = 1'b1;
8'h04: store_ip_identification_1 = 1'b1;
8'h05: store_ip_identification_0 = 1'b1;
8'h06: store_ip_flags_fragment_offset_1 = 1'b1;
8'h07: store_ip_flags_fragment_offset_0 = 1'b1;
8'h08: store_ip_ttl = 1'b1;
8'h09: store_ip_protocol = 1'b1;
8'h0A: store_ip_header_checksum_1 = 1'b1;
8'h0B: store_ip_header_checksum_0 = 1'b1;
8'h0C: store_ip_source_ip_3 = 1'b1;
8'h0D: store_ip_source_ip_2 = 1'b1;
8'h0E: store_ip_source_ip_1 = 1'b1;
8'h0F: store_ip_source_ip_0 = 1'b1;
8'h10: store_ip_dest_ip_3 = 1'b1;
8'h11: store_ip_dest_ip_2 = 1'b1;
8'h12: store_ip_dest_ip_1 = 1'b1;
8'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
frame_ptr_next = frame_ptr_reg + 16'd1;
if (s_eth_payload_axis_tlast) begin
if (frame_ptr_next != m_ip_length_reg) 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 (frame_ptr_next == m_ip_length_reg) 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;
frame_ptr_reg <= 16'd0;
hdr_sum_reg <= 16'd0;
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;
frame_ptr_reg <= frame_ptr_next;
hdr_sum_reg <= hdr_sum_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
// 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

View file

@ -1,494 +0,0 @@
/*
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 [15:0] frame_ptr_reg = 16'd0, frame_ptr_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;
frame_ptr_next = frame_ptr_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
frame_ptr_next = 16'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
frame_ptr_next = 16'd1;
end
state_next = STATE_WRITE_HEADER;
end else begin
state_next = STATE_IDLE;
end
end
STATE_WRITE_HEADER: begin
// write header
if (m_eth_payload_axis_tready_int_reg) begin
frame_ptr_next = frame_ptr_reg + 16'd1;
m_eth_payload_axis_tvalid_int = 1;
state_next = STATE_WRITE_HEADER;
case (frame_ptr_reg)
8'h00: begin
m_eth_payload_axis_tdata_int = {4'd4, 4'd5}; // ip_version, ip_ihl
end
8'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
8'h02: begin
m_eth_payload_axis_tdata_int = ip_length_reg[15: 8];
hdr_sum_next = add1c16b(hdr_sum_reg, ip_length_reg);
end
8'h03: begin
m_eth_payload_axis_tdata_int = ip_length_reg[ 7: 0];
hdr_sum_next = add1c16b(hdr_sum_reg, ip_identification_reg);
end
8'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
8'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
8'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
8'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
8'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
8'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
8'h0A: m_eth_payload_axis_tdata_int = ~hdr_sum_reg[15: 8];
8'h0B: m_eth_payload_axis_tdata_int = ~hdr_sum_reg[ 7: 0];
8'h0C: m_eth_payload_axis_tdata_int = ip_source_ip_reg[31:24];
8'h0D: m_eth_payload_axis_tdata_int = ip_source_ip_reg[23:16];
8'h0E: m_eth_payload_axis_tdata_int = ip_source_ip_reg[15: 8];
8'h0F: m_eth_payload_axis_tdata_int = ip_source_ip_reg[ 7: 0];
8'h10: m_eth_payload_axis_tdata_int = ip_dest_ip_reg[31:24];
8'h11: m_eth_payload_axis_tdata_int = ip_dest_ip_reg[23:16];
8'h12: m_eth_payload_axis_tdata_int = ip_dest_ip_reg[15: 8];
8'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
frame_ptr_next = frame_ptr_reg + 16'd1;
if (s_ip_payload_axis_tlast) begin
if (frame_ptr_next != ip_length_reg) 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 (frame_ptr_next == ip_length_reg) 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;
frame_ptr_reg <= 16'd0;
hdr_sum_reg <= 16'd0;
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;
frame_ptr_reg <= frame_ptr_next;
hdr_sum_reg <= hdr_sum_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
// 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

View file

@ -1,94 +0,0 @@
/*
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
/*
* Priority encoder module
*/
module priority_encoder #
(
parameter WIDTH = 4,
// LSB priority: "LOW", "HIGH"
parameter LSB_PRIORITY = "LOW"
)
(
input wire [WIDTH-1:0] input_unencoded,
output wire output_valid,
output wire [$clog2(WIDTH)-1:0] output_encoded,
output wire [WIDTH-1:0] output_unencoded
);
// power-of-two width
parameter W1 = 2**$clog2(WIDTH);
parameter W2 = W1/2;
generate
if (WIDTH == 2) begin
// two inputs - just an OR gate
assign output_valid = |input_unencoded;
if (LSB_PRIORITY == "LOW") begin
assign output_encoded = input_unencoded[1];
end else begin
assign output_encoded = ~input_unencoded[0];
end
end else begin
// more than two inputs - split into two parts and recurse
// also pad input to correct power-of-two width
wire [$clog2(W2)-1:0] out1, out2;
wire valid1, valid2;
priority_encoder #(
.WIDTH(W2),
.LSB_PRIORITY(LSB_PRIORITY)
)
priority_encoder_inst1 (
.input_unencoded(input_unencoded[W2-1:0]),
.output_valid(valid1),
.output_encoded(out1)
);
priority_encoder #(
.WIDTH(W2),
.LSB_PRIORITY(LSB_PRIORITY)
)
priority_encoder_inst2 (
.input_unencoded({{W1-WIDTH{1'b0}}, input_unencoded[WIDTH-1:W2]}),
.output_valid(valid2),
.output_encoded(out2)
);
// multiplexer to select part
assign output_valid = valid1 | valid2;
if (LSB_PRIORITY == "LOW") begin
assign output_encoded = valid2 ? {1'b1, out2} : {1'b0, out1};
end else begin
assign output_encoded = valid1 ? {1'b0, out1} : {1'b1, out2};
end
end
endgenerate
// unencoded output
assign output_unencoded = 1 << output_encoded;
endmodule

View file

@ -1,153 +0,0 @@
/*
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
/*
* Arbiter module
*/
module rgmii_arbiter #
(
parameter PORTS = 4,
// arbitration type: "PRIORITY" or "ROUND_ROBIN"
parameter TYPE = "PRIORITY",
// block type: "NONE", "REQUEST", "ACKNOWLEDGE"
parameter BLOCK = "NONE",
// LSB priority: "LOW", "HIGH"
parameter LSB_PRIORITY = "LOW"
)
(
input wire clk,
input wire rst,
input wire [PORTS-1:0] request,
input wire [PORTS-1:0] acknowledge,
output wire [PORTS-1:0] grant,
output wire grant_valid,
output wire [$clog2(PORTS)-1:0] grant_encoded
);
reg [PORTS-1:0] grant_reg = 0, grant_next;
reg grant_valid_reg = 0, grant_valid_next;
reg [$clog2(PORTS)-1:0] grant_encoded_reg = 0, grant_encoded_next;
assign grant_valid = grant_valid_reg;
assign grant = grant_reg;
assign grant_encoded = grant_encoded_reg;
wire request_valid;
wire [$clog2(PORTS)-1:0] request_index;
wire [PORTS-1:0] request_mask;
priority_encoder #(
.WIDTH(PORTS),
.LSB_PRIORITY(LSB_PRIORITY)
)
priority_encoder_inst (
.input_unencoded(request),
.output_valid(request_valid),
.output_encoded(request_index),
.output_unencoded(request_mask)
);
reg [PORTS-1:0] mask_reg = 0, mask_next;
wire masked_request_valid;
wire [$clog2(PORTS)-1:0] masked_request_index;
wire [PORTS-1:0] masked_request_mask;
priority_encoder #(
.WIDTH(PORTS),
.LSB_PRIORITY(LSB_PRIORITY)
)
priority_encoder_masked (
.input_unencoded(request & mask_reg),
.output_valid(masked_request_valid),
.output_encoded(masked_request_index),
.output_unencoded(masked_request_mask)
);
always @* begin
grant_next = 0;
grant_valid_next = 0;
grant_encoded_next = 0;
mask_next = mask_reg;
if (BLOCK == "REQUEST" && grant_reg & request) begin
// granted request still asserted; hold it
grant_valid_next = grant_valid_reg;
grant_next = grant_reg;
grant_encoded_next = grant_encoded_reg;
end else if (BLOCK == "ACKNOWLEDGE" && grant_valid && !(grant_reg & acknowledge)) begin
// granted request not yet acknowledged; hold it
grant_valid_next = grant_valid_reg;
grant_next = grant_reg;
grant_encoded_next = grant_encoded_reg;
end else if (request_valid) begin
if (TYPE == "PRIORITY") begin
grant_valid_next = 1;
grant_next = request_mask;
grant_encoded_next = request_index;
end else if (TYPE == "ROUND_ROBIN") begin
if (masked_request_valid) begin
grant_valid_next = 1;
grant_next = masked_request_mask;
grant_encoded_next = masked_request_index;
if (LSB_PRIORITY == "LOW") begin
mask_next = {PORTS{1'b1}} >> (PORTS - masked_request_index);
end else begin
mask_next = {PORTS{1'b1}} << (masked_request_index + 1);
end
end else begin
grant_valid_next = 1;
grant_next = request_mask;
grant_encoded_next = request_index;
if (LSB_PRIORITY == "LOW") begin
mask_next = {PORTS{1'b1}} >> (PORTS - request_index);
end else begin
mask_next = {PORTS{1'b1}} << (request_index + 1);
end
end
end
end
end
always @(posedge clk) begin
if (rst) begin
grant_reg <= 0;
grant_valid_reg <= 0;
grant_encoded_reg <= 0;
mask_reg <= 0;
end else begin
grant_reg <= grant_next;
grant_valid_reg <= grant_valid_next;
grant_encoded_reg <= grant_encoded_next;
mask_reg <= mask_next;
end
end
endmodule

View file

@ -1,195 +0,0 @@
// Copyright (c) 2015-2018 Princeton University
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of Princeton University nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY PRINCETON UNIVERSITY "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL PRINCETON UNIVERSITY BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Simplified RGMII <-> MII converter (boldly copied from OpenPiton)
// Specific to 7-series FPGA
module rgmii_to_mii_conv_xilinx (
// to PHY (RGMII)
output logic rgmii_phy_txc,
output logic rgmii_phy_txctl,
output logic [3:0] rgmii_phy_txd,
input logic rgmii_phy_rxc,
input logic rgmii_phy_rxctl,
input logic [3:0] rgmii_phy_rxd,
output logic rgmii_phy_rst_n,
inout wire rgmii_phy_mdio,
output logic rgmii_phy_mdc,
// from MAC (MII)
input logic mem_clk_i, // 200 MHz
input logic net_phy_rst_n,
input logic net_phy_tx_clk, // 25 MHz
input logic net_phy_tx_en,
input logic [3:0] net_phy_tx_data,
output logic net_phy_rx_clk,
output logic net_phy_dv,
output logic [3:0] net_phy_rx_data,
output logic net_phy_rx_er,
input logic net_mdio_i,
output logic net_mdio_o,
input logic net_mdio_t,
input logic net_phy_mdc
);
// -------------
// MDIO
// -------------
IOBUF mdio_io_iobuf (.I (net_mdio_i), .IO(rgmii_phy_mdio), .O (net_mdio_o), .T (net_mdio_t));
assign rgmii_phy_mdc = net_phy_mdc;
assign rgmii_phy_rst_n = net_phy_rst_n;
// -------------
// TX
// -------------
// net_phy_tx_clk: ___|------|______|------|______|------|______|
// rgmii_phy_txc: ---|______|------|______|------|______|------|
// net_phy_tx_en: -----_________________________________________
// rgmii_phy_txctl: _____--------------___________________________
// basically inverts the clock
ODDR net_phy_txc_oddr (
.C ( net_phy_tx_clk ), // 1-bit clock input (The CLK pin represents the clock input pin)
.CE ( 1'b1 ), // 1-bit clock enable input (CE represents the clock enable pin. When asserted Low,
.Q ( rgmii_phy_txc ), // 1-bit DDR output (ODDR register output)
// this port disables the output clock on port Q.)
.D1 ( 1'b0 ), // 1-bit data input (positive edge) (ODDR register inputs)
.D2 ( 1'b1 ), // 1-bit data input (negative edge) (ODDR register inputs)
// Synchronous/Asynchronous set/reset pin. Set/Reset is
// asserted High.
.R ( 1'b0 ), // 1-bit reset
.S ( 1'b0 ) // 1-bit set
);
// D-FF
FD net_phy_txctl_dff (
.C ( net_phy_tx_clk ),
.D ( net_phy_tx_en ),
.Q ( rgmii_phy_txctl )
);
for (genvar i = 0; i < 4; i++) begin : gen_net_phy_txd
FD net_phy_txd_dff (
.C ( net_phy_tx_clk ),
.D ( net_phy_tx_data[i] ),
.Q ( rgmii_phy_txd[i] )
);
end
// -------------
// RX
// -------------
logic net_phy_rxc_ibufg_out;
logic net_phy_rxc_delayed;
logic net_phy_rx_dv_f;
logic net_phy_rx_err_f;
logic net_phy_rx_dv_ff;
logic net_phy_rx_err_ff;
logic [3:0] net_phy_rxd_f;
logic [3:0] net_phy_rxd_ff;
IBUFG net_phy_rxc_ibufg (
.I ( rgmii_phy_rxc ),
.O ( net_phy_rxc_ibufg_out )
);
// Delay by RXC 31*78 (IDELAY_VALUE*tap_delay@200MHz) to put in RXD/RXCTL eye
(* IODELAY_GROUP = "NET_PHY_RXC" *)
IDELAYE2 #(
.CINVCTRL_SEL ( "FALSE" ), // Enable dynamic clock inversion (FALSE, TRUE)
.DELAY_SRC ( "IDATAIN" ), // Delay input (IDATAIN, DATAIN)
.HIGH_PERFORMANCE_MODE ( "FALSE" ), // Reduced jitter ("TRUE"), Reduced power ("FALSE")
.IDELAY_TYPE ( "FIXED" ), // FIXED, VARIABLE, VAR_LOAD, VAR_LOAD_PIPE
.IDELAY_VALUE ( 31 ), // Input delay tap setting (0-31)
.PIPE_SEL ( "FALSE" ), // Select pipelined mode, FALSE, TRUE
.REFCLK_FREQUENCY ( 200.0 ), // IDELAYCTRL clock input frequency in MHz (190.0-210.0, 290.0-310.0).
.SIGNAL_PATTERN ( "DATA" ) // DATA, CLOCK input signal
) i_idelaye2 (
.CNTVALUEOUT ( ), // 5-bit output: Counter value output
.DATAOUT ( net_phy_rxc_delayed ), // 1-bit output: Delayed data output
.C ( 1'b0 ), // 1-bit input: Clock input
.CE ( 1'b0 ), // 1-bit input: Active high enable increment/decrement input
.CINVCTRL ( ), // 1-bit input: Dynamic clock inversion input
.CNTVALUEIN ( 5'b0 ), // 5-bit input: Counter value input
.DATAIN ( 1'b0 ), // 1-bit input: Internal delay data input
.IDATAIN ( net_phy_rxc_ibufg_out ), // 1-bit input: Data input from the I/O
.INC ( 1'b0 ), // 1-bit input: Increment / Decrement tap delay input
.LD ( 1'b0 ), // 1-bit input: Load IDELAY_VALUE input
.LDPIPEEN ( 1'b0 ), // 1-bit input: Enable PIPELINE register to load data input
.REGRST ( 1'b0 ) // 1-bit input: Active-high reset tap-delay input
);
(* IODELAY_GROUP = "NET_PHY_RXC" *)
IDELAYCTRL i_idelayctrl (
.RDY ( ), // 1-bit output: Ready output
// 200-MHz for g2, clk_mmccm drives clocks through BUFG
.REFCLK ( mem_clk_i ), // 1-bit input: Reference clock input
.RST ( 1'b0 ) // 1-bit input: Active high reset input
);
BUFG BUFG_inst (
.I ( net_phy_rxc_delayed ),
.O ( net_phy_rx_clk )
);
// The RX_CTL signal carries RXDV (data valid) on the rising edge, and (RXDV xor RXER)
// on the falling edge.
// data valid is transmitted on positive edge
always_ff @(posedge net_phy_rx_clk) begin
if (~rgmii_phy_rst_n) begin
net_phy_rx_dv_f <= 1'b0;
end else begin
net_phy_rx_dv_f <= rgmii_phy_rxctl;
end
end
// data error is encoded on negative edge of rxctl
always_ff @(negedge net_phy_rx_clk) begin
if (~rgmii_phy_rst_n) begin
net_phy_rx_err_f <= 1'b0;
end else begin
net_phy_rx_err_f <= rgmii_phy_rxctl;
end
end
always_ff @(posedge net_phy_rx_clk) begin
if (~rgmii_phy_rst_n) begin
net_phy_rxd_f <= '0;
net_phy_rxd_ff <= '0;
net_phy_rx_dv_ff <= 1'b0;
net_phy_rx_err_ff <= 1'b0;
end else begin
net_phy_rxd_f <= rgmii_phy_rxd;
net_phy_rxd_ff <= net_phy_rxd_f;
net_phy_rx_dv_ff <= net_phy_rx_dv_f;
net_phy_rx_err_ff <= net_phy_rx_err_f;
end
end
assign net_phy_dv = net_phy_rx_dv_ff;
assign net_phy_rx_er = net_phy_rx_dv_ff ^ net_phy_rx_err_ff;
assign net_phy_rx_data = net_phy_rxd_ff;
endmodule

View file

@ -1,52 +0,0 @@
/*
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 1 ns / 1 ps
/*
* Synchronizes an active-high asynchronous reset signal to a given clock by
* using a pipeline of N registers.
*/
module sync_reset #(
parameter N=2 // depth of synchronizer
)(
input wire clk,
input wire rst,
output wire sync_reset_out
);
reg [N-1:0] sync_reg = {N{1'b1}};
assign sync_reset_out = sync_reg[N-1];
always @(posedge clk or posedge rst) begin
if (rst)
sync_reg <= {N{1'b1}};
else
sync_reg <= {sync_reg[N-2:0], 1'b0};
end
endmodule

View file

@ -1,413 +0,0 @@
/*
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
/*
* UDP block, IP interface
*/
module udp #
(
parameter CHECKSUM_GEN_ENABLE = 1,
parameter CHECKSUM_PAYLOAD_FIFO_ADDR_WIDTH = 11,
parameter CHECKSUM_HEADER_FIFO_ADDR_WIDTH = 3
)
(
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_ip_eth_dest_mac,
input wire [47:0] s_ip_eth_src_mac,
input wire [15:0] s_ip_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 [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 frame 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,
/*
* UDP frame input
*/
input wire s_udp_hdr_valid,
output wire s_udp_hdr_ready,
input wire [47:0] s_udp_eth_dest_mac,
input wire [47:0] s_udp_eth_src_mac,
input wire [15:0] s_udp_eth_type,
input wire [3:0] s_udp_ip_version,
input wire [3:0] s_udp_ip_ihl,
input wire [5:0] s_udp_ip_dscp,
input wire [1:0] s_udp_ip_ecn,
input wire [15:0] s_udp_ip_identification,
input wire [2:0] s_udp_ip_flags,
input wire [12:0] s_udp_ip_fragment_offset,
input wire [7:0] s_udp_ip_ttl,
input wire [15:0] s_udp_ip_header_checksum,
input wire [31:0] s_udp_ip_source_ip,
input wire [31:0] s_udp_ip_dest_ip,
input wire [15:0] s_udp_source_port,
input wire [15:0] s_udp_dest_port,
input wire [15:0] s_udp_length,
input wire [15:0] s_udp_checksum,
input wire [7:0] s_udp_payload_axis_tdata,
input wire s_udp_payload_axis_tvalid,
output wire s_udp_payload_axis_tready,
input wire s_udp_payload_axis_tlast,
input wire s_udp_payload_axis_tuser,
/*
* UDP frame output
*/
output wire m_udp_hdr_valid,
input wire m_udp_hdr_ready,
output wire [47:0] m_udp_eth_dest_mac,
output wire [47:0] m_udp_eth_src_mac,
output wire [15:0] m_udp_eth_type,
output wire [3:0] m_udp_ip_version,
output wire [3:0] m_udp_ip_ihl,
output wire [5:0] m_udp_ip_dscp,
output wire [1:0] m_udp_ip_ecn,
output wire [15:0] m_udp_ip_length,
output wire [15:0] m_udp_ip_identification,
output wire [2:0] m_udp_ip_flags,
output wire [12:0] m_udp_ip_fragment_offset,
output wire [7:0] m_udp_ip_ttl,
output wire [7:0] m_udp_ip_protocol,
output wire [15:0] m_udp_ip_header_checksum,
output wire [31:0] m_udp_ip_source_ip,
output wire [31:0] m_udp_ip_dest_ip,
output wire [15:0] m_udp_source_port,
output wire [15:0] m_udp_dest_port,
output wire [15:0] m_udp_length,
output wire [15:0] m_udp_checksum,
output wire [7:0] m_udp_payload_axis_tdata,
output wire m_udp_payload_axis_tvalid,
input wire m_udp_payload_axis_tready,
output wire m_udp_payload_axis_tlast,
output wire m_udp_payload_axis_tuser,
/*
* Status signals
*/
output wire rx_busy,
output wire tx_busy,
output wire rx_error_header_early_termination,
output wire rx_error_payload_early_termination,
output wire tx_error_payload_early_termination
);
wire tx_udp_hdr_valid;
wire tx_udp_hdr_ready;
wire [47:0] tx_udp_eth_dest_mac;
wire [47:0] tx_udp_eth_src_mac;
wire [15:0] tx_udp_eth_type;
wire [3:0] tx_udp_ip_version;
wire [3:0] tx_udp_ip_ihl;
wire [5:0] tx_udp_ip_dscp;
wire [1:0] tx_udp_ip_ecn;
wire [15:0] tx_udp_ip_identification;
wire [2:0] tx_udp_ip_flags;
wire [12:0] tx_udp_ip_fragment_offset;
wire [7:0] tx_udp_ip_ttl;
wire [15:0] tx_udp_ip_header_checksum;
wire [31:0] tx_udp_ip_source_ip;
wire [31:0] tx_udp_ip_dest_ip;
wire [15:0] tx_udp_source_port;
wire [15:0] tx_udp_dest_port;
wire [15:0] tx_udp_length;
wire [15:0] tx_udp_checksum;
wire [7:0] tx_udp_payload_axis_tdata;
wire tx_udp_payload_axis_tvalid;
wire tx_udp_payload_axis_tready;
wire tx_udp_payload_axis_tlast;
wire tx_udp_payload_axis_tuser;
udp_ip_rx
udp_ip_rx_inst (
.clk(clk),
.rst(rst),
// IP frame input
.s_ip_hdr_valid(s_ip_hdr_valid),
.s_ip_hdr_ready(s_ip_hdr_ready),
.s_eth_dest_mac(s_ip_eth_dest_mac),
.s_eth_src_mac(s_ip_eth_src_mac),
.s_eth_type(s_ip_eth_type),
.s_ip_version(s_ip_version),
.s_ip_ihl(s_ip_ihl),
.s_ip_dscp(s_ip_dscp),
.s_ip_ecn(s_ip_ecn),
.s_ip_length(s_ip_length),
.s_ip_identification(s_ip_identification),
.s_ip_flags(s_ip_flags),
.s_ip_fragment_offset(s_ip_fragment_offset),
.s_ip_ttl(s_ip_ttl),
.s_ip_protocol(s_ip_protocol),
.s_ip_header_checksum(s_ip_header_checksum),
.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),
// UDP frame output
.m_udp_hdr_valid(m_udp_hdr_valid),
.m_udp_hdr_ready(m_udp_hdr_ready),
.m_eth_dest_mac(m_udp_eth_dest_mac),
.m_eth_src_mac(m_udp_eth_src_mac),
.m_eth_type(m_udp_eth_type),
.m_ip_version(m_udp_ip_version),
.m_ip_ihl(m_udp_ip_ihl),
.m_ip_dscp(m_udp_ip_dscp),
.m_ip_ecn(m_udp_ip_ecn),
.m_ip_length(m_udp_ip_length),
.m_ip_identification(m_udp_ip_identification),
.m_ip_flags(m_udp_ip_flags),
.m_ip_fragment_offset(m_udp_ip_fragment_offset),
.m_ip_ttl(m_udp_ip_ttl),
.m_ip_protocol(m_udp_ip_protocol),
.m_ip_header_checksum(m_udp_ip_header_checksum),
.m_ip_source_ip(m_udp_ip_source_ip),
.m_ip_dest_ip(m_udp_ip_dest_ip),
.m_udp_source_port(m_udp_source_port),
.m_udp_dest_port(m_udp_dest_port),
.m_udp_length(m_udp_length),
.m_udp_checksum(m_udp_checksum),
.m_udp_payload_axis_tdata(m_udp_payload_axis_tdata),
.m_udp_payload_axis_tvalid(m_udp_payload_axis_tvalid),
.m_udp_payload_axis_tready(m_udp_payload_axis_tready),
.m_udp_payload_axis_tlast(m_udp_payload_axis_tlast),
.m_udp_payload_axis_tuser(m_udp_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)
);
generate
if (CHECKSUM_GEN_ENABLE) begin
udp_checksum_gen #(
.PAYLOAD_FIFO_ADDR_WIDTH(CHECKSUM_PAYLOAD_FIFO_ADDR_WIDTH),
.HEADER_FIFO_ADDR_WIDTH(CHECKSUM_HEADER_FIFO_ADDR_WIDTH)
)
udp_checksum_gen_inst (
.clk(clk),
.rst(rst),
// UDP frame input
.s_udp_hdr_valid(s_udp_hdr_valid),
.s_udp_hdr_ready(s_udp_hdr_ready),
.s_eth_dest_mac(s_udp_eth_dest_mac),
.s_eth_src_mac(s_udp_eth_src_mac),
.s_eth_type(s_udp_eth_type),
.s_ip_version(s_udp_ip_version),
.s_ip_ihl(s_udp_ip_ihl),
.s_ip_dscp(s_udp_ip_dscp),
.s_ip_ecn(s_udp_ip_ecn),
.s_ip_identification(s_udp_ip_identification),
.s_ip_flags(s_udp_ip_flags),
.s_ip_fragment_offset(s_udp_ip_fragment_offset),
.s_ip_ttl(s_udp_ip_ttl),
.s_ip_header_checksum(s_udp_ip_header_checksum),
.s_ip_source_ip(s_udp_ip_source_ip),
.s_ip_dest_ip(s_udp_ip_dest_ip),
.s_udp_source_port(s_udp_source_port),
.s_udp_dest_port(s_udp_dest_port),
.s_udp_payload_axis_tdata(s_udp_payload_axis_tdata),
.s_udp_payload_axis_tvalid(s_udp_payload_axis_tvalid),
.s_udp_payload_axis_tready(s_udp_payload_axis_tready),
.s_udp_payload_axis_tlast(s_udp_payload_axis_tlast),
.s_udp_payload_axis_tuser(s_udp_payload_axis_tuser),
// UDP frame output
.m_udp_hdr_valid(tx_udp_hdr_valid),
.m_udp_hdr_ready(tx_udp_hdr_ready),
.m_eth_dest_mac(tx_udp_eth_dest_mac),
.m_eth_src_mac(tx_udp_eth_src_mac),
.m_eth_type(tx_udp_eth_type),
.m_ip_version(tx_udp_ip_version),
.m_ip_ihl(tx_udp_ip_ihl),
.m_ip_dscp(tx_udp_ip_dscp),
.m_ip_ecn(tx_udp_ip_ecn),
.m_ip_length(),
.m_ip_identification(tx_udp_ip_identification),
.m_ip_flags(tx_udp_ip_flags),
.m_ip_fragment_offset(tx_udp_ip_fragment_offset),
.m_ip_ttl(tx_udp_ip_ttl),
.m_ip_protocol(),
.m_ip_header_checksum(tx_udp_ip_header_checksum),
.m_ip_source_ip(tx_udp_ip_source_ip),
.m_ip_dest_ip(tx_udp_ip_dest_ip),
.m_udp_source_port(tx_udp_source_port),
.m_udp_dest_port(tx_udp_dest_port),
.m_udp_length(tx_udp_length),
.m_udp_checksum(tx_udp_checksum),
.m_udp_payload_axis_tdata(tx_udp_payload_axis_tdata),
.m_udp_payload_axis_tvalid(tx_udp_payload_axis_tvalid),
.m_udp_payload_axis_tready(tx_udp_payload_axis_tready),
.m_udp_payload_axis_tlast(tx_udp_payload_axis_tlast),
.m_udp_payload_axis_tuser(tx_udp_payload_axis_tuser),
// Status signals
.busy()
);
end else begin
assign tx_udp_hdr_valid = s_udp_hdr_valid;
assign s_udp_hdr_ready = tx_udp_hdr_ready;
assign tx_udp_eth_dest_mac = s_udp_eth_dest_mac;
assign tx_udp_eth_src_mac = s_udp_eth_src_mac;
assign tx_udp_eth_type = s_udp_eth_type;
assign tx_udp_ip_version = s_udp_ip_version;
assign tx_udp_ip_ihl = s_udp_ip_ihl;
assign tx_udp_ip_dscp = s_udp_ip_dscp;
assign tx_udp_ip_ecn = s_udp_ip_ecn;
assign tx_udp_ip_identification = s_udp_ip_identification;
assign tx_udp_ip_flags = s_udp_ip_flags;
assign tx_udp_ip_fragment_offset = s_udp_ip_fragment_offset;
assign tx_udp_ip_ttl = s_udp_ip_ttl;
assign tx_udp_ip_header_checksum = s_udp_ip_header_checksum;
assign tx_udp_ip_source_ip = s_udp_ip_source_ip;
assign tx_udp_ip_dest_ip = s_udp_ip_dest_ip;
assign tx_udp_source_port = s_udp_source_port;
assign tx_udp_dest_port = s_udp_dest_port;
assign tx_udp_length = s_udp_length;
assign tx_udp_checksum = s_udp_checksum;
assign tx_udp_payload_axis_tdata = s_udp_payload_axis_tdata;
assign tx_udp_payload_axis_tvalid = s_udp_payload_axis_tvalid;
assign s_udp_payload_axis_tready = tx_udp_payload_axis_tready;
assign tx_udp_payload_axis_tlast = s_udp_payload_axis_tlast;
assign tx_udp_payload_axis_tuser = s_udp_payload_axis_tuser;
end
endgenerate
udp_ip_tx
udp_ip_tx_inst (
.clk(clk),
.rst(rst),
// UDP frame input
.s_udp_hdr_valid(tx_udp_hdr_valid),
.s_udp_hdr_ready(tx_udp_hdr_ready),
.s_eth_dest_mac(tx_udp_eth_dest_mac),
.s_eth_src_mac(tx_udp_eth_src_mac),
.s_eth_type(tx_udp_eth_type),
.s_ip_version(tx_udp_ip_version),
.s_ip_ihl(tx_udp_ip_ihl),
.s_ip_dscp(tx_udp_ip_dscp),
.s_ip_ecn(tx_udp_ip_ecn),
.s_ip_identification(tx_udp_ip_identification),
.s_ip_flags(tx_udp_ip_flags),
.s_ip_fragment_offset(tx_udp_ip_fragment_offset),
.s_ip_ttl(tx_udp_ip_ttl),
.s_ip_protocol(8'h11),
.s_ip_header_checksum(tx_udp_ip_header_checksum),
.s_ip_source_ip(tx_udp_ip_source_ip),
.s_ip_dest_ip(tx_udp_ip_dest_ip),
.s_udp_source_port(tx_udp_source_port),
.s_udp_dest_port(tx_udp_dest_port),
.s_udp_length(tx_udp_length),
.s_udp_checksum(tx_udp_checksum),
.s_udp_payload_axis_tdata(tx_udp_payload_axis_tdata),
.s_udp_payload_axis_tvalid(tx_udp_payload_axis_tvalid),
.s_udp_payload_axis_tready(tx_udp_payload_axis_tready),
.s_udp_payload_axis_tlast(tx_udp_payload_axis_tlast),
.s_udp_payload_axis_tuser(tx_udp_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(tx_busy),
.error_payload_early_termination(tx_error_payload_early_termination)
);
endmodule

View file

@ -1,555 +0,0 @@
/*
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
/*
* UDP checksum calculation module
*/
module udp_checksum_gen #
(
parameter PAYLOAD_FIFO_ADDR_WIDTH = 11,
parameter HEADER_FIFO_ADDR_WIDTH = 3
)
(
input wire clk,
input wire rst,
/*
* UDP frame input
*/
input wire s_udp_hdr_valid,
output wire s_udp_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_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 [15:0] s_ip_header_checksum,
input wire [31:0] s_ip_source_ip,
input wire [31:0] s_ip_dest_ip,
input wire [15:0] s_udp_source_port,
input wire [15:0] s_udp_dest_port,
input wire [7:0] s_udp_payload_axis_tdata,
input wire s_udp_payload_axis_tvalid,
output wire s_udp_payload_axis_tready,
input wire s_udp_payload_axis_tlast,
input wire s_udp_payload_axis_tuser,
/*
* UDP frame output
*/
output wire m_udp_hdr_valid,
input wire m_udp_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 [15:0] m_udp_source_port,
output wire [15:0] m_udp_dest_port,
output wire [15:0] m_udp_length,
output wire [15:0] m_udp_checksum,
output wire [7:0] m_udp_payload_axis_tdata,
output wire m_udp_payload_axis_tvalid,
input wire m_udp_payload_axis_tready,
output wire m_udp_payload_axis_tlast,
output wire m_udp_payload_axis_tuser,
/*
* Status signals
*/
output wire busy
);
/*
UDP 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
source port 2 octets
desination port 2 octets
length 2 octets
checksum 2 octets
payload length octets
This module receives a UDP frame with header fields in parallel and payload on
an AXI stream interface, calculates the length and checksum, then produces the
header fields in parallel along with the UDP payload in a separate AXI stream.
*/
localparam [2:0]
STATE_IDLE = 3'd0,
STATE_SUM_HEADER_1 = 3'd1,
STATE_SUM_HEADER_2 = 3'd2,
STATE_SUM_HEADER_3 = 3'd3,
STATE_SUM_PAYLOAD = 3'd4,
STATE_FINISH_SUM = 3'd5;
reg [2:0] state_reg = STATE_IDLE, state_next;
// datapath control signals
reg store_udp_hdr;
reg shift_payload_in;
reg [31:0] checksum_part;
reg [15:0] frame_ptr_reg = 16'd0, frame_ptr_next;
reg [31:0] checksum_reg = 32'd0, checksum_next;
reg [47:0] eth_dest_mac_reg = 48'd0;
reg [47:0] eth_src_mac_reg = 48'd0;
reg [15:0] eth_type_reg = 16'd0;
reg [3:0] ip_version_reg = 4'd0;
reg [3:0] ip_ihl_reg = 4'd0;
reg [5:0] ip_dscp_reg = 6'd0;
reg [1:0] ip_ecn_reg = 2'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 [15:0] ip_header_checksum_reg = 16'd0;
reg [31:0] ip_source_ip_reg = 32'd0;
reg [31:0] ip_dest_ip_reg = 32'd0;
reg [15:0] udp_source_port_reg = 16'd0;
reg [15:0] udp_dest_port_reg = 16'd0;
reg hdr_valid_reg = 0, hdr_valid_next;
reg s_udp_hdr_ready_reg = 1'b0, s_udp_hdr_ready_next;
reg s_udp_payload_axis_tready_reg = 1'b0, s_udp_payload_axis_tready_next;
reg busy_reg = 1'b0;
/*
* UDP Payload FIFO
*/
wire [7:0] s_udp_payload_fifo_tdata;
wire s_udp_payload_fifo_tvalid;
wire s_udp_payload_fifo_tready;
wire s_udp_payload_fifo_tlast;
wire s_udp_payload_fifo_tuser;
wire [7:0] m_udp_payload_fifo_tdata;
wire m_udp_payload_fifo_tvalid;
wire m_udp_payload_fifo_tready;
wire m_udp_payload_fifo_tlast;
wire m_udp_payload_fifo_tuser;
axis_fifo #(
.ADDR_WIDTH(PAYLOAD_FIFO_ADDR_WIDTH),
.DATA_WIDTH(8),
.KEEP_ENABLE(0),
.LAST_ENABLE(1),
.ID_ENABLE(0),
.DEST_ENABLE(0),
.USER_ENABLE(1),
.USER_WIDTH(1),
.FRAME_FIFO(0)
)
payload_fifo (
.clk(clk),
.rst(rst),
// AXI input
.s_axis_tdata(s_udp_payload_fifo_tdata),
.s_axis_tkeep(0),
.s_axis_tvalid(s_udp_payload_fifo_tvalid),
.s_axis_tready(s_udp_payload_fifo_tready),
.s_axis_tlast(s_udp_payload_fifo_tlast),
.s_axis_tid(0),
.s_axis_tdest(0),
.s_axis_tuser(s_udp_payload_fifo_tuser),
// AXI output
.m_axis_tdata(m_udp_payload_fifo_tdata),
.m_axis_tkeep(),
.m_axis_tvalid(m_udp_payload_fifo_tvalid),
.m_axis_tready(m_udp_payload_fifo_tready),
.m_axis_tlast(m_udp_payload_fifo_tlast),
.m_axis_tid(),
.m_axis_tdest(),
.m_axis_tuser(m_udp_payload_fifo_tuser),
// Status
.status_overflow(),
.status_bad_frame(),
.status_good_frame()
);
assign s_udp_payload_fifo_tdata = s_udp_payload_axis_tdata;
assign s_udp_payload_fifo_tvalid = s_udp_payload_axis_tvalid && shift_payload_in;
assign s_udp_payload_axis_tready = s_udp_payload_fifo_tready && shift_payload_in;
assign s_udp_payload_fifo_tlast = s_udp_payload_axis_tlast;
assign s_udp_payload_fifo_tuser = s_udp_payload_axis_tuser;
assign m_udp_payload_axis_tdata = m_udp_payload_fifo_tdata;
assign m_udp_payload_axis_tvalid = m_udp_payload_fifo_tvalid;
assign m_udp_payload_fifo_tready = m_udp_payload_axis_tready;
assign m_udp_payload_axis_tlast = m_udp_payload_fifo_tlast;
assign m_udp_payload_axis_tuser = m_udp_payload_fifo_tuser;
/*
* UDP Header FIFO
*/
reg [HEADER_FIFO_ADDR_WIDTH:0] header_fifo_wr_ptr_reg = {HEADER_FIFO_ADDR_WIDTH+1{1'b0}}, header_fifo_wr_ptr_next;
reg [HEADER_FIFO_ADDR_WIDTH:0] header_fifo_rd_ptr_reg = {HEADER_FIFO_ADDR_WIDTH+1{1'b0}}, header_fifo_rd_ptr_next;
reg [47:0] eth_dest_mac_mem[(2**HEADER_FIFO_ADDR_WIDTH)-1:0];
reg [47:0] eth_src_mac_mem[(2**HEADER_FIFO_ADDR_WIDTH)-1:0];
reg [15:0] eth_type_mem[(2**HEADER_FIFO_ADDR_WIDTH)-1:0];
reg [3:0] ip_version_mem[(2**HEADER_FIFO_ADDR_WIDTH)-1:0];
reg [3:0] ip_ihl_mem[(2**HEADER_FIFO_ADDR_WIDTH)-1:0];
reg [5:0] ip_dscp_mem[(2**HEADER_FIFO_ADDR_WIDTH)-1:0];
reg [1:0] ip_ecn_mem[(2**HEADER_FIFO_ADDR_WIDTH)-1:0];
reg [15:0] ip_identification_mem[(2**HEADER_FIFO_ADDR_WIDTH)-1:0];
reg [2:0] ip_flags_mem[(2**HEADER_FIFO_ADDR_WIDTH)-1:0];
reg [12:0] ip_fragment_offset_mem[(2**HEADER_FIFO_ADDR_WIDTH)-1:0];
reg [7:0] ip_ttl_mem[(2**HEADER_FIFO_ADDR_WIDTH)-1:0];
reg [15:0] ip_header_checksum_mem[(2**HEADER_FIFO_ADDR_WIDTH)-1:0];
reg [31:0] ip_source_ip_mem[(2**HEADER_FIFO_ADDR_WIDTH)-1:0];
reg [31:0] ip_dest_ip_mem[(2**HEADER_FIFO_ADDR_WIDTH)-1:0];
reg [15:0] udp_source_port_mem[(2**HEADER_FIFO_ADDR_WIDTH)-1:0];
reg [15:0] udp_dest_port_mem[(2**HEADER_FIFO_ADDR_WIDTH)-1:0];
reg [15:0] udp_length_mem[(2**HEADER_FIFO_ADDR_WIDTH)-1:0];
reg [15:0] udp_checksum_mem[(2**HEADER_FIFO_ADDR_WIDTH)-1:0];
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_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 [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 [15:0] m_udp_source_port_reg = 16'd0;
reg [15:0] m_udp_dest_port_reg = 16'd0;
reg [15:0] m_udp_length_reg = 16'd0;
reg [15:0] m_udp_checksum_reg = 16'd0;
reg m_udp_hdr_valid_reg = 1'b0, m_udp_hdr_valid_next;
// full when first MSB different but rest same
wire header_fifo_full = ((header_fifo_wr_ptr_reg[HEADER_FIFO_ADDR_WIDTH] != header_fifo_rd_ptr_reg[HEADER_FIFO_ADDR_WIDTH]) &&
(header_fifo_wr_ptr_reg[HEADER_FIFO_ADDR_WIDTH-1:0] == header_fifo_rd_ptr_reg[HEADER_FIFO_ADDR_WIDTH-1:0]));
// empty when pointers match exactly
wire header_fifo_empty = header_fifo_wr_ptr_reg == header_fifo_rd_ptr_reg;
// control signals
reg header_fifo_write;
reg header_fifo_read;
wire header_fifo_ready = !header_fifo_full;
assign m_udp_hdr_valid = m_udp_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_udp_length_reg + 16'd20;
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 = 8'h11;
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 m_udp_source_port = m_udp_source_port_reg;
assign m_udp_dest_port = m_udp_dest_port_reg;
assign m_udp_length = m_udp_length_reg;
assign m_udp_checksum = m_udp_checksum_reg;
// Write logic
always @* begin
header_fifo_write = 1'b0;
header_fifo_wr_ptr_next = header_fifo_wr_ptr_reg;
if (hdr_valid_reg) begin
// input data valid
if (~header_fifo_full) begin
// not full, perform write
header_fifo_write = 1'b1;
header_fifo_wr_ptr_next = header_fifo_wr_ptr_reg + 1;
end
end
end
always @(posedge clk) begin
if (rst) begin
header_fifo_wr_ptr_reg <= {HEADER_FIFO_ADDR_WIDTH+1{1'b0}};
end else begin
header_fifo_wr_ptr_reg <= header_fifo_wr_ptr_next;
end
if (header_fifo_write) begin
eth_dest_mac_mem[header_fifo_wr_ptr_reg[HEADER_FIFO_ADDR_WIDTH-1:0]] <= eth_dest_mac_reg;
eth_src_mac_mem[header_fifo_wr_ptr_reg[HEADER_FIFO_ADDR_WIDTH-1:0]] <= eth_src_mac_reg;
eth_type_mem[header_fifo_wr_ptr_reg[HEADER_FIFO_ADDR_WIDTH-1:0]] <= eth_type_reg;
ip_version_mem[header_fifo_wr_ptr_reg[HEADER_FIFO_ADDR_WIDTH-1:0]] <= ip_version_reg;
ip_ihl_mem[header_fifo_wr_ptr_reg[HEADER_FIFO_ADDR_WIDTH-1:0]] <= ip_ihl_reg;
ip_dscp_mem[header_fifo_wr_ptr_reg[HEADER_FIFO_ADDR_WIDTH-1:0]] <= ip_dscp_reg;
ip_ecn_mem[header_fifo_wr_ptr_reg[HEADER_FIFO_ADDR_WIDTH-1:0]] <= ip_ecn_reg;
ip_identification_mem[header_fifo_wr_ptr_reg[HEADER_FIFO_ADDR_WIDTH-1:0]] <= ip_identification_reg;
ip_flags_mem[header_fifo_wr_ptr_reg[HEADER_FIFO_ADDR_WIDTH-1:0]] <= ip_flags_reg;
ip_fragment_offset_mem[header_fifo_wr_ptr_reg[HEADER_FIFO_ADDR_WIDTH-1:0]] <= ip_fragment_offset_reg;
ip_ttl_mem[header_fifo_wr_ptr_reg[HEADER_FIFO_ADDR_WIDTH-1:0]] <= ip_ttl_reg;
ip_header_checksum_mem[header_fifo_wr_ptr_reg[HEADER_FIFO_ADDR_WIDTH-1:0]] <= ip_header_checksum_reg;
ip_source_ip_mem[header_fifo_wr_ptr_reg[HEADER_FIFO_ADDR_WIDTH-1:0]] <= ip_source_ip_reg;
ip_dest_ip_mem[header_fifo_wr_ptr_reg[HEADER_FIFO_ADDR_WIDTH-1:0]] <= ip_dest_ip_reg;
udp_source_port_mem[header_fifo_wr_ptr_reg[HEADER_FIFO_ADDR_WIDTH-1:0]] <= udp_source_port_reg;
udp_dest_port_mem[header_fifo_wr_ptr_reg[HEADER_FIFO_ADDR_WIDTH-1:0]] <= udp_dest_port_reg;
udp_length_mem[header_fifo_wr_ptr_reg[HEADER_FIFO_ADDR_WIDTH-1:0]] <= frame_ptr_reg;
udp_checksum_mem[header_fifo_wr_ptr_reg[HEADER_FIFO_ADDR_WIDTH-1:0]] <= checksum_reg[15:0];
end
end
// Read logic
always @* begin
header_fifo_read = 1'b0;
header_fifo_rd_ptr_next = header_fifo_rd_ptr_reg;
m_udp_hdr_valid_next = m_udp_hdr_valid_reg;
if (m_udp_hdr_ready || !m_udp_hdr_valid) begin
// output data not valid OR currently being transferred
if (!header_fifo_empty) begin
// not empty, perform read
header_fifo_read = 1'b1;
m_udp_hdr_valid_next = 1'b1;
header_fifo_rd_ptr_next = header_fifo_rd_ptr_reg + 1;
end else begin
// empty, invalidate
m_udp_hdr_valid_next = 1'b0;
end
end
end
always @(posedge clk) begin
if (rst) begin
header_fifo_rd_ptr_reg <= {HEADER_FIFO_ADDR_WIDTH+1{1'b0}};
m_udp_hdr_valid_reg <= 1'b0;
end else begin
header_fifo_rd_ptr_reg <= header_fifo_rd_ptr_next;
m_udp_hdr_valid_reg <= m_udp_hdr_valid_next;
end
if (header_fifo_read) begin
m_eth_dest_mac_reg <= eth_dest_mac_mem[header_fifo_rd_ptr_reg[HEADER_FIFO_ADDR_WIDTH-1:0]];
m_eth_src_mac_reg <= eth_src_mac_mem[header_fifo_rd_ptr_reg[HEADER_FIFO_ADDR_WIDTH-1:0]];
m_eth_type_reg <= eth_type_mem[header_fifo_rd_ptr_reg[HEADER_FIFO_ADDR_WIDTH-1:0]];
m_ip_version_reg <= ip_version_mem[header_fifo_rd_ptr_reg[HEADER_FIFO_ADDR_WIDTH-1:0]];
m_ip_ihl_reg <= ip_ihl_mem[header_fifo_rd_ptr_reg[HEADER_FIFO_ADDR_WIDTH-1:0]];
m_ip_dscp_reg <= ip_dscp_mem[header_fifo_rd_ptr_reg[HEADER_FIFO_ADDR_WIDTH-1:0]];
m_ip_ecn_reg <= ip_ecn_mem[header_fifo_rd_ptr_reg[HEADER_FIFO_ADDR_WIDTH-1:0]];
m_ip_identification_reg <= ip_identification_mem[header_fifo_rd_ptr_reg[HEADER_FIFO_ADDR_WIDTH-1:0]];
m_ip_flags_reg <= ip_flags_mem[header_fifo_rd_ptr_reg[HEADER_FIFO_ADDR_WIDTH-1:0]];
m_ip_fragment_offset_reg <= ip_fragment_offset_mem[header_fifo_rd_ptr_reg[HEADER_FIFO_ADDR_WIDTH-1:0]];
m_ip_ttl_reg <= ip_ttl_mem[header_fifo_rd_ptr_reg[HEADER_FIFO_ADDR_WIDTH-1:0]];
m_ip_header_checksum_reg <= ip_header_checksum_mem[header_fifo_rd_ptr_reg[HEADER_FIFO_ADDR_WIDTH-1:0]];
m_ip_source_ip_reg <= ip_source_ip_mem[header_fifo_rd_ptr_reg[HEADER_FIFO_ADDR_WIDTH-1:0]];
m_ip_dest_ip_reg <= ip_dest_ip_mem[header_fifo_rd_ptr_reg[HEADER_FIFO_ADDR_WIDTH-1:0]];
m_udp_source_port_reg <= udp_source_port_mem[header_fifo_rd_ptr_reg[HEADER_FIFO_ADDR_WIDTH-1:0]];
m_udp_dest_port_reg <= udp_dest_port_mem[header_fifo_rd_ptr_reg[HEADER_FIFO_ADDR_WIDTH-1:0]];
m_udp_length_reg <= udp_length_mem[header_fifo_rd_ptr_reg[HEADER_FIFO_ADDR_WIDTH-1:0]];
m_udp_checksum_reg <= udp_checksum_mem[header_fifo_rd_ptr_reg[HEADER_FIFO_ADDR_WIDTH-1:0]];
end
end
assign s_udp_hdr_ready = s_udp_hdr_ready_reg;
assign busy = busy_reg;
always @* begin
state_next = STATE_IDLE;
s_udp_hdr_ready_next = 1'b0;
s_udp_payload_axis_tready_next = 1'b0;
store_udp_hdr = 1'b0;
shift_payload_in = 1'b0;
frame_ptr_next = frame_ptr_reg;
checksum_next = checksum_reg;
hdr_valid_next = 1'b0;
case (state_reg)
STATE_IDLE: begin
// idle state
s_udp_hdr_ready_next = header_fifo_ready;
if (s_udp_hdr_ready && s_udp_hdr_valid) begin
store_udp_hdr = 1'b1;
frame_ptr_next = 0;
// 16'h0011 = zero padded type field
// 16'h0010 = header length times two
checksum_next = 16'h0011 + 16'h0010;
s_udp_hdr_ready_next = 1'b0;
state_next = STATE_SUM_HEADER_1;
end else begin
state_next = STATE_IDLE;
end
end
STATE_SUM_HEADER_1: begin
// sum pseudo header and header
checksum_next = checksum_reg + ip_source_ip_reg[31:16] + ip_source_ip_reg[15:0];
state_next = STATE_SUM_HEADER_2;
end
STATE_SUM_HEADER_2: begin
// sum pseudo header and header
checksum_next = checksum_reg + ip_dest_ip_reg[31:16] + ip_dest_ip_reg[15:0];
state_next = STATE_SUM_HEADER_3;
end
STATE_SUM_HEADER_3: begin
// sum pseudo header and header
checksum_next = checksum_reg + udp_source_port_reg + udp_dest_port_reg;
frame_ptr_next = 8;
state_next = STATE_SUM_PAYLOAD;
end
STATE_SUM_PAYLOAD: begin
// sum payload
shift_payload_in = 1'b1;
if (s_udp_payload_axis_tready && s_udp_payload_axis_tvalid) begin
// checksum computation for payload - alternately store and accumulate
// add 2 for length calculation (two length fields in pseudo header)
if (frame_ptr_reg[0]) begin
checksum_next = checksum_reg + {8'h00, s_udp_payload_axis_tdata} + 2;
end else begin
checksum_next = checksum_reg + {s_udp_payload_axis_tdata, 8'h00} + 2;
end
frame_ptr_next = frame_ptr_reg + 1;
if (s_udp_payload_axis_tlast) begin
state_next = STATE_FINISH_SUM;
end else begin
state_next = STATE_SUM_PAYLOAD;
end
end else begin
state_next = STATE_SUM_PAYLOAD;
end
end
STATE_FINISH_SUM: begin
// add MSW (twice!) for proper ones complement sum
checksum_part = checksum_reg[15:0] + checksum_reg[31:16];
checksum_next = ~(checksum_part[15:0] + checksum_part[16]);
hdr_valid_next = 1;
state_next = STATE_IDLE;
end
endcase
end
always @(posedge clk) begin
if (rst) begin
state_reg <= STATE_IDLE;
s_udp_hdr_ready_reg <= 1'b0;
s_udp_payload_axis_tready_reg <= 1'b0;
hdr_valid_reg <= 1'b0;
busy_reg <= 1'b0;
end else begin
state_reg <= state_next;
s_udp_hdr_ready_reg <= s_udp_hdr_ready_next;
s_udp_payload_axis_tready_reg <= s_udp_payload_axis_tready_next;
hdr_valid_reg <= hdr_valid_next;
busy_reg <= state_next != STATE_IDLE;
end
frame_ptr_reg <= frame_ptr_next;
checksum_reg <= checksum_next;
// datapath
if (store_udp_hdr) begin
eth_dest_mac_reg <= s_eth_dest_mac;
eth_src_mac_reg <= s_eth_src_mac;
eth_type_reg <= s_eth_type;
ip_version_reg <= s_ip_version;
ip_ihl_reg <= s_ip_ihl;
ip_dscp_reg <= s_ip_dscp;
ip_ecn_reg <= s_ip_ecn;
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_header_checksum_reg <= s_ip_header_checksum;
ip_source_ip_reg <= s_ip_source_ip;
ip_dest_ip_reg <= s_ip_dest_ip;
udp_source_port_reg <= s_udp_source_port;
udp_dest_port_reg <= s_udp_dest_port;
end
end
endmodule

View file

@ -1,637 +0,0 @@
/*
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 with UDP support, ethernet frame interface
*/
module udp_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,
parameter UDP_CHECKSUM_GEN_ENABLE = 1,
parameter UDP_CHECKSUM_PAYLOAD_FIFO_ADDR_WIDTH = 11,
parameter UDP_CHECKSUM_HEADER_FIFO_ADDR_WIDTH = 3
)
(
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,
/*
* UDP input
*/
input wire s_udp_hdr_valid,
output wire s_udp_hdr_ready,
input wire [5:0] s_udp_ip_dscp,
input wire [1:0] s_udp_ip_ecn,
input wire [7:0] s_udp_ip_ttl,
input wire [31:0] s_udp_ip_source_ip,
input wire [31:0] s_udp_ip_dest_ip,
input wire [15:0] s_udp_source_port,
input wire [15:0] s_udp_dest_port,
input wire [15:0] s_udp_length,
input wire [15:0] s_udp_checksum,
input wire [7:0] s_udp_payload_axis_tdata,
input wire s_udp_payload_axis_tvalid,
output wire s_udp_payload_axis_tready,
input wire s_udp_payload_axis_tlast,
input wire s_udp_payload_axis_tuser,
/*
* UDP output
*/
output wire m_udp_hdr_valid,
input wire m_udp_hdr_ready,
output wire [47:0] m_udp_eth_dest_mac,
output wire [47:0] m_udp_eth_src_mac,
output wire [15:0] m_udp_eth_type,
output wire [3:0] m_udp_ip_version,
output wire [3:0] m_udp_ip_ihl,
output wire [5:0] m_udp_ip_dscp,
output wire [1:0] m_udp_ip_ecn,
output wire [15:0] m_udp_ip_length,
output wire [15:0] m_udp_ip_identification,
output wire [2:0] m_udp_ip_flags,
output wire [12:0] m_udp_ip_fragment_offset,
output wire [7:0] m_udp_ip_ttl,
output wire [7:0] m_udp_ip_protocol,
output wire [15:0] m_udp_ip_header_checksum,
output wire [31:0] m_udp_ip_source_ip,
output wire [31:0] m_udp_ip_dest_ip,
output wire [15:0] m_udp_source_port,
output wire [15:0] m_udp_dest_port,
output wire [15:0] m_udp_length,
output wire [15:0] m_udp_checksum,
output wire [7:0] m_udp_payload_axis_tdata,
output wire m_udp_payload_axis_tvalid,
input wire m_udp_payload_axis_tready,
output wire m_udp_payload_axis_tlast,
output wire m_udp_payload_axis_tuser,
/*
* Status
*/
output wire ip_rx_busy,
output wire ip_tx_busy,
output wire udp_rx_busy,
output wire udp_tx_busy,
output wire ip_rx_error_header_early_termination,
output wire ip_rx_error_payload_early_termination,
output wire ip_rx_error_invalid_header,
output wire ip_rx_error_invalid_checksum,
output wire ip_tx_error_payload_early_termination,
output wire ip_tx_error_arp_failed,
output wire udp_rx_error_header_early_termination,
output wire udp_rx_error_payload_early_termination,
output wire udp_tx_error_payload_early_termination,
/*
* 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
);
wire ip_rx_ip_hdr_valid;
wire ip_rx_ip_hdr_ready;
wire [47:0] ip_rx_ip_eth_dest_mac;
wire [47:0] ip_rx_ip_eth_src_mac;
wire [15:0] ip_rx_ip_eth_type;
wire [3:0] ip_rx_ip_version;
wire [3:0] ip_rx_ip_ihl;
wire [5:0] ip_rx_ip_dscp;
wire [1:0] ip_rx_ip_ecn;
wire [15:0] ip_rx_ip_length;
wire [15:0] ip_rx_ip_identification;
wire [2:0] ip_rx_ip_flags;
wire [12:0] ip_rx_ip_fragment_offset;
wire [7:0] ip_rx_ip_ttl;
wire [7:0] ip_rx_ip_protocol;
wire [15:0] ip_rx_ip_header_checksum;
wire [31:0] ip_rx_ip_source_ip;
wire [31:0] ip_rx_ip_dest_ip;
wire [7:0] ip_rx_ip_payload_axis_tdata;
wire ip_rx_ip_payload_axis_tvalid;
wire ip_rx_ip_payload_axis_tlast;
wire ip_rx_ip_payload_axis_tuser;
wire ip_rx_ip_payload_axis_tready;
wire ip_tx_ip_hdr_valid;
wire ip_tx_ip_hdr_ready;
wire [5:0] ip_tx_ip_dscp;
wire [1:0] ip_tx_ip_ecn;
wire [15:0] ip_tx_ip_length;
wire [7:0] ip_tx_ip_ttl;
wire [7:0] ip_tx_ip_protocol;
wire [31:0] ip_tx_ip_source_ip;
wire [31:0] ip_tx_ip_dest_ip;
wire [7:0] ip_tx_ip_payload_axis_tdata;
wire ip_tx_ip_payload_axis_tvalid;
wire ip_tx_ip_payload_axis_tlast;
wire ip_tx_ip_payload_axis_tuser;
wire ip_tx_ip_payload_axis_tready;
wire udp_rx_ip_hdr_valid;
wire udp_rx_ip_hdr_ready;
wire [47:0] udp_rx_ip_eth_dest_mac;
wire [47:0] udp_rx_ip_eth_src_mac;
wire [15:0] udp_rx_ip_eth_type;
wire [3:0] udp_rx_ip_version;
wire [3:0] udp_rx_ip_ihl;
wire [5:0] udp_rx_ip_dscp;
wire [1:0] udp_rx_ip_ecn;
wire [15:0] udp_rx_ip_length;
wire [15:0] udp_rx_ip_identification;
wire [2:0] udp_rx_ip_flags;
wire [12:0] udp_rx_ip_fragment_offset;
wire [7:0] udp_rx_ip_ttl;
wire [7:0] udp_rx_ip_protocol;
wire [15:0] udp_rx_ip_header_checksum;
wire [31:0] udp_rx_ip_source_ip;
wire [31:0] udp_rx_ip_dest_ip;
wire [7:0] udp_rx_ip_payload_axis_tdata;
wire udp_rx_ip_payload_axis_tvalid;
wire udp_rx_ip_payload_axis_tlast;
wire udp_rx_ip_payload_axis_tuser;
wire udp_rx_ip_payload_axis_tready;
wire udp_tx_ip_hdr_valid;
wire udp_tx_ip_hdr_ready;
wire [5:0] udp_tx_ip_dscp;
wire [1:0] udp_tx_ip_ecn;
wire [15:0] udp_tx_ip_length;
wire [7:0] udp_tx_ip_ttl;
wire [7:0] udp_tx_ip_protocol;
wire [31:0] udp_tx_ip_source_ip;
wire [31:0] udp_tx_ip_dest_ip;
wire [7:0] udp_tx_ip_payload_axis_tdata;
wire udp_tx_ip_payload_axis_tvalid;
wire udp_tx_ip_payload_axis_tlast;
wire udp_tx_ip_payload_axis_tuser;
wire udp_tx_ip_payload_axis_tready;
/*
* Input classifier (ip_protocol)
*/
wire s_select_udp = (ip_rx_ip_protocol == 8'h11);
wire s_select_ip = !s_select_udp;
reg s_select_udp_reg = 1'b0;
reg s_select_ip_reg = 1'b0;
always @(posedge clk) begin
if (rst) begin
s_select_udp_reg <= 1'b0;
s_select_ip_reg <= 1'b0;
end else begin
if (ip_rx_ip_payload_axis_tvalid) begin
if ((!s_select_udp_reg && !s_select_ip_reg) ||
(ip_rx_ip_payload_axis_tvalid && ip_rx_ip_payload_axis_tready && ip_rx_ip_payload_axis_tlast)) begin
s_select_udp_reg <= s_select_udp;
s_select_ip_reg <= s_select_ip;
end
end else begin
s_select_udp_reg <= 1'b0;
s_select_ip_reg <= 1'b0;
end
end
end
// IP frame to UDP module
assign udp_rx_ip_hdr_valid = s_select_udp && ip_rx_ip_hdr_valid;
assign udp_rx_ip_eth_dest_mac = ip_rx_ip_eth_dest_mac;
assign udp_rx_ip_eth_src_mac = ip_rx_ip_eth_src_mac;
assign udp_rx_ip_eth_type = ip_rx_ip_eth_type;
assign udp_rx_ip_version = ip_rx_ip_version;
assign udp_rx_ip_ihl = ip_rx_ip_ihl;
assign udp_rx_ip_dscp = ip_rx_ip_dscp;
assign udp_rx_ip_ecn = ip_rx_ip_ecn;
assign udp_rx_ip_length = ip_rx_ip_length;
assign udp_rx_ip_identification = ip_rx_ip_identification;
assign udp_rx_ip_flags = ip_rx_ip_flags;
assign udp_rx_ip_fragment_offset = ip_rx_ip_fragment_offset;
assign udp_rx_ip_ttl = ip_rx_ip_ttl;
assign udp_rx_ip_protocol = 8'h11;
assign udp_rx_ip_header_checksum = ip_rx_ip_header_checksum;
assign udp_rx_ip_source_ip = ip_rx_ip_source_ip;
assign udp_rx_ip_dest_ip = ip_rx_ip_dest_ip;
assign udp_rx_ip_payload_axis_tdata = ip_rx_ip_payload_axis_tdata;
assign udp_rx_ip_payload_axis_tvalid = s_select_udp_reg && ip_rx_ip_payload_axis_tvalid;
assign udp_rx_ip_payload_axis_tlast = ip_rx_ip_payload_axis_tlast;
assign udp_rx_ip_payload_axis_tuser = ip_rx_ip_payload_axis_tuser;
// External IP frame output
assign m_ip_hdr_valid = s_select_ip && ip_rx_ip_hdr_valid;
assign m_ip_eth_dest_mac = ip_rx_ip_eth_dest_mac;
assign m_ip_eth_src_mac = ip_rx_ip_eth_src_mac;
assign m_ip_eth_type = ip_rx_ip_eth_type;
assign m_ip_version = ip_rx_ip_version;
assign m_ip_ihl = ip_rx_ip_ihl;
assign m_ip_dscp = ip_rx_ip_dscp;
assign m_ip_ecn = ip_rx_ip_ecn;
assign m_ip_length = ip_rx_ip_length;
assign m_ip_identification = ip_rx_ip_identification;
assign m_ip_flags = ip_rx_ip_flags;
assign m_ip_fragment_offset = ip_rx_ip_fragment_offset;
assign m_ip_ttl = ip_rx_ip_ttl;
assign m_ip_protocol = ip_rx_ip_protocol;
assign m_ip_header_checksum = ip_rx_ip_header_checksum;
assign m_ip_source_ip = ip_rx_ip_source_ip;
assign m_ip_dest_ip = ip_rx_ip_dest_ip;
assign m_ip_payload_axis_tdata = ip_rx_ip_payload_axis_tdata;
assign m_ip_payload_axis_tvalid = s_select_ip_reg && ip_rx_ip_payload_axis_tvalid;
assign m_ip_payload_axis_tlast = ip_rx_ip_payload_axis_tlast;
assign m_ip_payload_axis_tuser = ip_rx_ip_payload_axis_tuser;
assign ip_rx_ip_hdr_ready = (s_select_udp && udp_rx_ip_hdr_ready) ||
(s_select_ip && m_ip_hdr_ready);
assign ip_rx_ip_payload_axis_tready = (s_select_udp_reg && udp_rx_ip_payload_axis_tready) ||
(s_select_ip_reg && m_ip_payload_axis_tready);
/*
* Output arbiter
*/
ip_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")
)
ip_arb_mux_inst (
.clk(clk),
.rst(rst),
// IP frame inputs
.s_ip_hdr_valid({s_ip_hdr_valid, udp_tx_ip_hdr_valid}),
.s_ip_hdr_ready({s_ip_hdr_ready, udp_tx_ip_hdr_ready}),
.s_eth_dest_mac(0),
.s_eth_src_mac(0),
.s_eth_type(0),
.s_ip_version(0),
.s_ip_ihl(0),
.s_ip_dscp({s_ip_dscp, udp_tx_ip_dscp}),
.s_ip_ecn({s_ip_ecn, udp_tx_ip_ecn}),
.s_ip_length({s_ip_length, udp_tx_ip_length}),
.s_ip_identification(0),
.s_ip_flags(0),
.s_ip_fragment_offset(0),
.s_ip_ttl({s_ip_ttl, udp_tx_ip_ttl}),
.s_ip_protocol({s_ip_protocol, udp_tx_ip_protocol}),
.s_ip_header_checksum(0),
.s_ip_source_ip({s_ip_source_ip, udp_tx_ip_source_ip}),
.s_ip_dest_ip({s_ip_dest_ip, udp_tx_ip_dest_ip}),
.s_ip_payload_axis_tdata({s_ip_payload_axis_tdata, udp_tx_ip_payload_axis_tdata}),
.s_ip_payload_axis_tkeep(0),
.s_ip_payload_axis_tvalid({s_ip_payload_axis_tvalid, udp_tx_ip_payload_axis_tvalid}),
.s_ip_payload_axis_tready({s_ip_payload_axis_tready, udp_tx_ip_payload_axis_tready}),
.s_ip_payload_axis_tlast({s_ip_payload_axis_tlast, udp_tx_ip_payload_axis_tlast}),
.s_ip_payload_axis_tid(0),
.s_ip_payload_axis_tdest(0),
.s_ip_payload_axis_tuser({s_ip_payload_axis_tuser, udp_tx_ip_payload_axis_tuser}),
// IP frame output
.m_ip_hdr_valid(ip_tx_ip_hdr_valid),
.m_ip_hdr_ready(ip_tx_ip_hdr_ready),
.m_eth_dest_mac(),
.m_eth_src_mac(),
.m_eth_type(),
.m_ip_version(),
.m_ip_ihl(),
.m_ip_dscp(ip_tx_ip_dscp),
.m_ip_ecn(ip_tx_ip_ecn),
.m_ip_length(ip_tx_ip_length),
.m_ip_identification(),
.m_ip_flags(),
.m_ip_fragment_offset(),
.m_ip_ttl(ip_tx_ip_ttl),
.m_ip_protocol(ip_tx_ip_protocol),
.m_ip_header_checksum(),
.m_ip_source_ip(ip_tx_ip_source_ip),
.m_ip_dest_ip(ip_tx_ip_dest_ip),
.m_ip_payload_axis_tdata(ip_tx_ip_payload_axis_tdata),
.m_ip_payload_axis_tkeep(),
.m_ip_payload_axis_tvalid(ip_tx_ip_payload_axis_tvalid),
.m_ip_payload_axis_tready(ip_tx_ip_payload_axis_tready),
.m_ip_payload_axis_tlast(ip_tx_ip_payload_axis_tlast),
.m_ip_payload_axis_tid(),
.m_ip_payload_axis_tdest(),
.m_ip_payload_axis_tuser(ip_tx_ip_payload_axis_tuser)
);
/*
* IP stack
*/
ip_complete #(
.ARP_CACHE_ADDR_WIDTH(ARP_CACHE_ADDR_WIDTH),
.ARP_REQUEST_RETRY_COUNT(ARP_REQUEST_RETRY_COUNT),
.ARP_REQUEST_RETRY_INTERVAL(ARP_REQUEST_RETRY_INTERVAL),
.ARP_REQUEST_TIMEOUT(ARP_REQUEST_TIMEOUT)
)
ip_complete_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),
// 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),
// IP frame input
.s_ip_hdr_valid(ip_tx_ip_hdr_valid),
.s_ip_hdr_ready(ip_tx_ip_hdr_ready),
.s_ip_dscp(ip_tx_ip_dscp),
.s_ip_ecn(ip_tx_ip_ecn),
.s_ip_length(ip_tx_ip_length),
.s_ip_ttl(ip_tx_ip_ttl),
.s_ip_protocol(ip_tx_ip_protocol),
.s_ip_source_ip(ip_tx_ip_source_ip),
.s_ip_dest_ip(ip_tx_ip_dest_ip),
.s_ip_payload_axis_tdata(ip_tx_ip_payload_axis_tdata),
.s_ip_payload_axis_tvalid(ip_tx_ip_payload_axis_tvalid),
.s_ip_payload_axis_tready(ip_tx_ip_payload_axis_tready),
.s_ip_payload_axis_tlast(ip_tx_ip_payload_axis_tlast),
.s_ip_payload_axis_tuser(ip_tx_ip_payload_axis_tuser),
// IP frame output
.m_ip_hdr_valid(ip_rx_ip_hdr_valid),
.m_ip_hdr_ready(ip_rx_ip_hdr_ready),
.m_ip_eth_dest_mac(ip_rx_ip_eth_dest_mac),
.m_ip_eth_src_mac(ip_rx_ip_eth_src_mac),
.m_ip_eth_type(ip_rx_ip_eth_type),
.m_ip_version(ip_rx_ip_version),
.m_ip_ihl(ip_rx_ip_ihl),
.m_ip_dscp(ip_rx_ip_dscp),
.m_ip_ecn(ip_rx_ip_ecn),
.m_ip_length(ip_rx_ip_length),
.m_ip_identification(ip_rx_ip_identification),
.m_ip_flags(ip_rx_ip_flags),
.m_ip_fragment_offset(ip_rx_ip_fragment_offset),
.m_ip_ttl(ip_rx_ip_ttl),
.m_ip_protocol(ip_rx_ip_protocol),
.m_ip_header_checksum(ip_rx_ip_header_checksum),
.m_ip_source_ip(ip_rx_ip_source_ip),
.m_ip_dest_ip(ip_rx_ip_dest_ip),
.m_ip_payload_axis_tdata(ip_rx_ip_payload_axis_tdata),
.m_ip_payload_axis_tvalid(ip_rx_ip_payload_axis_tvalid),
.m_ip_payload_axis_tready(ip_rx_ip_payload_axis_tready),
.m_ip_payload_axis_tlast(ip_rx_ip_payload_axis_tlast),
.m_ip_payload_axis_tuser(ip_rx_ip_payload_axis_tuser),
// Status
.rx_busy(ip_rx_busy),
.tx_busy(ip_tx_busy),
.rx_error_header_early_termination(ip_rx_error_header_early_termination),
.rx_error_payload_early_termination(ip_rx_error_payload_early_termination),
.rx_error_invalid_header(ip_rx_error_invalid_header),
.rx_error_invalid_checksum(ip_rx_error_invalid_checksum),
.tx_error_payload_early_termination(ip_tx_error_payload_early_termination),
.tx_error_arp_failed(ip_tx_error_arp_failed),
// Configuration
.local_mac(local_mac),
.local_ip(local_ip),
.gateway_ip(gateway_ip),
.subnet_mask(subnet_mask),
.clear_arp_cache(clear_arp_cache)
);
/*
* UDP interface
*/
udp #(
.CHECKSUM_GEN_ENABLE(UDP_CHECKSUM_GEN_ENABLE),
.CHECKSUM_PAYLOAD_FIFO_ADDR_WIDTH(UDP_CHECKSUM_PAYLOAD_FIFO_ADDR_WIDTH),
.CHECKSUM_HEADER_FIFO_ADDR_WIDTH(UDP_CHECKSUM_HEADER_FIFO_ADDR_WIDTH)
)
udp_inst (
.clk(clk),
.rst(rst),
// IP frame input
.s_ip_hdr_valid(udp_rx_ip_hdr_valid),
.s_ip_hdr_ready(udp_rx_ip_hdr_ready),
.s_ip_eth_dest_mac(udp_rx_ip_eth_dest_mac),
.s_ip_eth_src_mac(udp_rx_ip_eth_src_mac),
.s_ip_eth_type(udp_rx_ip_eth_type),
.s_ip_version(udp_rx_ip_version),
.s_ip_ihl(udp_rx_ip_ihl),
.s_ip_dscp(udp_rx_ip_dscp),
.s_ip_ecn(udp_rx_ip_ecn),
.s_ip_length(udp_rx_ip_length),
.s_ip_identification(udp_rx_ip_identification),
.s_ip_flags(udp_rx_ip_flags),
.s_ip_fragment_offset(udp_rx_ip_fragment_offset),
.s_ip_ttl(udp_rx_ip_ttl),
.s_ip_protocol(udp_rx_ip_protocol),
.s_ip_header_checksum(udp_rx_ip_header_checksum),
.s_ip_source_ip(udp_rx_ip_source_ip),
.s_ip_dest_ip(udp_rx_ip_dest_ip),
.s_ip_payload_axis_tdata(udp_rx_ip_payload_axis_tdata),
.s_ip_payload_axis_tvalid(udp_rx_ip_payload_axis_tvalid),
.s_ip_payload_axis_tready(udp_rx_ip_payload_axis_tready),
.s_ip_payload_axis_tlast(udp_rx_ip_payload_axis_tlast),
.s_ip_payload_axis_tuser(udp_rx_ip_payload_axis_tuser),
// IP frame output
.m_ip_hdr_valid(udp_tx_ip_hdr_valid),
.m_ip_hdr_ready(udp_tx_ip_hdr_ready),
.m_ip_eth_dest_mac(),
.m_ip_eth_src_mac(),
.m_ip_eth_type(),
.m_ip_version(),
.m_ip_ihl(),
.m_ip_dscp(udp_tx_ip_dscp),
.m_ip_ecn(udp_tx_ip_ecn),
.m_ip_length(udp_tx_ip_length),
.m_ip_identification(),
.m_ip_flags(),
.m_ip_fragment_offset(),
.m_ip_ttl(udp_tx_ip_ttl),
.m_ip_protocol(udp_tx_ip_protocol),
.m_ip_header_checksum(),
.m_ip_source_ip(udp_tx_ip_source_ip),
.m_ip_dest_ip(udp_tx_ip_dest_ip),
.m_ip_payload_axis_tdata(udp_tx_ip_payload_axis_tdata),
.m_ip_payload_axis_tvalid(udp_tx_ip_payload_axis_tvalid),
.m_ip_payload_axis_tready(udp_tx_ip_payload_axis_tready),
.m_ip_payload_axis_tlast(udp_tx_ip_payload_axis_tlast),
.m_ip_payload_axis_tuser(udp_tx_ip_payload_axis_tuser),
// UDP frame input
.s_udp_hdr_valid(s_udp_hdr_valid),
.s_udp_hdr_ready(s_udp_hdr_ready),
.s_udp_eth_dest_mac(48'd0),
.s_udp_eth_src_mac(48'd0),
.s_udp_eth_type(16'd0),
.s_udp_ip_version(4'd0),
.s_udp_ip_ihl(4'd0),
.s_udp_ip_dscp(s_udp_ip_dscp),
.s_udp_ip_ecn(s_udp_ip_ecn),
.s_udp_ip_identification(16'd0),
.s_udp_ip_flags(3'd0),
.s_udp_ip_fragment_offset(13'd0),
.s_udp_ip_ttl(s_udp_ip_ttl),
.s_udp_ip_header_checksum(16'd0),
.s_udp_ip_source_ip(s_udp_ip_source_ip),
.s_udp_ip_dest_ip(s_udp_ip_dest_ip),
.s_udp_source_port(s_udp_source_port),
.s_udp_dest_port(s_udp_dest_port),
.s_udp_length(s_udp_length),
.s_udp_checksum(s_udp_checksum),
.s_udp_payload_axis_tdata(s_udp_payload_axis_tdata),
.s_udp_payload_axis_tvalid(s_udp_payload_axis_tvalid),
.s_udp_payload_axis_tready(s_udp_payload_axis_tready),
.s_udp_payload_axis_tlast(s_udp_payload_axis_tlast),
.s_udp_payload_axis_tuser(s_udp_payload_axis_tuser),
// UDP frame output
.m_udp_hdr_valid(m_udp_hdr_valid),
.m_udp_hdr_ready(m_udp_hdr_ready),
.m_udp_eth_dest_mac(m_udp_eth_dest_mac),
.m_udp_eth_src_mac(m_udp_eth_src_mac),
.m_udp_eth_type(m_udp_eth_type),
.m_udp_ip_version(m_udp_ip_version),
.m_udp_ip_ihl(m_udp_ip_ihl),
.m_udp_ip_dscp(m_udp_ip_dscp),
.m_udp_ip_ecn(m_udp_ip_ecn),
.m_udp_ip_length(m_udp_ip_length),
.m_udp_ip_identification(m_udp_ip_identification),
.m_udp_ip_flags(m_udp_ip_flags),
.m_udp_ip_fragment_offset(m_udp_ip_fragment_offset),
.m_udp_ip_ttl(m_udp_ip_ttl),
.m_udp_ip_protocol(m_udp_ip_protocol),
.m_udp_ip_header_checksum(m_udp_ip_header_checksum),
.m_udp_ip_source_ip(m_udp_ip_source_ip),
.m_udp_ip_dest_ip(m_udp_ip_dest_ip),
.m_udp_source_port(m_udp_source_port),
.m_udp_dest_port(m_udp_dest_port),
.m_udp_length(m_udp_length),
.m_udp_checksum(m_udp_checksum),
.m_udp_payload_axis_tdata(m_udp_payload_axis_tdata),
.m_udp_payload_axis_tvalid(m_udp_payload_axis_tvalid),
.m_udp_payload_axis_tready(m_udp_payload_axis_tready),
.m_udp_payload_axis_tlast(m_udp_payload_axis_tlast),
.m_udp_payload_axis_tuser(m_udp_payload_axis_tuser),
// Status
.rx_busy(udp_rx_busy),
.tx_busy(udp_tx_busy),
.rx_error_header_early_termination(udp_rx_error_header_early_termination),
.rx_error_payload_early_termination(udp_rx_error_payload_early_termination),
.tx_error_payload_early_termination(udp_tx_error_payload_early_termination)
);
endmodule

View file

@ -1,528 +0,0 @@
/*
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
/*
* UDP ethernet frame receiver (IP frame in, UDP frame out)
*/
module udp_ip_rx
(
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 [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,
/*
* UDP frame output
*/
output wire m_udp_hdr_valid,
input wire m_udp_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 [15:0] m_udp_source_port,
output wire [15:0] m_udp_dest_port,
output wire [15:0] m_udp_length,
output wire [15:0] m_udp_checksum,
output wire [7:0] m_udp_payload_axis_tdata,
output wire m_udp_payload_axis_tvalid,
input wire m_udp_payload_axis_tready,
output wire m_udp_payload_axis_tlast,
output wire m_udp_payload_axis_tuser,
/*
* Status signals
*/
output wire busy,
output wire error_header_early_termination,
output wire error_payload_early_termination
);
/*
UDP 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
source port 2 octets
desination port 2 octets
length 2 octets
checksum 2 octets
payload length octets
This module receives an IP frame with header fields in parallel and payload on
an AXI stream interface, decodes and strips the UDP header fields, then
produces the header fields in parallel along with the UDP 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_ip_hdr;
reg store_udp_source_port_0;
reg store_udp_source_port_1;
reg store_udp_dest_port_0;
reg store_udp_dest_port_1;
reg store_udp_length_0;
reg store_udp_length_1;
reg store_udp_checksum_0;
reg store_udp_checksum_1;
reg store_last_word;
reg [15:0] frame_ptr_reg = 16'd0, frame_ptr_next;
reg [7:0] last_word_data_reg = 8'd0;
reg m_udp_hdr_valid_reg = 1'b0, m_udp_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 [15:0] m_udp_source_port_reg = 16'd0;
reg [15:0] m_udp_dest_port_reg = 16'd0;
reg [15:0] m_udp_length_reg = 16'd0;
reg [15:0] m_udp_checksum_reg = 16'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 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;
// internal datapath
reg [7:0] m_udp_payload_axis_tdata_int;
reg m_udp_payload_axis_tvalid_int;
reg m_udp_payload_axis_tready_int_reg = 1'b0;
reg m_udp_payload_axis_tlast_int;
reg m_udp_payload_axis_tuser_int;
wire m_udp_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_udp_hdr_valid = m_udp_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 m_udp_source_port = m_udp_source_port_reg;
assign m_udp_dest_port = m_udp_dest_port_reg;
assign m_udp_length = m_udp_length_reg;
assign m_udp_checksum = m_udp_checksum_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;
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_udp_source_port_0 = 1'b0;
store_udp_source_port_1 = 1'b0;
store_udp_dest_port_0 = 1'b0;
store_udp_dest_port_1 = 1'b0;
store_udp_length_0 = 1'b0;
store_udp_length_1 = 1'b0;
store_udp_checksum_0 = 1'b0;
store_udp_checksum_1 = 1'b0;
store_last_word = 1'b0;
frame_ptr_next = frame_ptr_reg;
m_udp_hdr_valid_next = m_udp_hdr_valid_reg && !m_udp_hdr_ready;
error_header_early_termination_next = 1'b0;
error_payload_early_termination_next = 1'b0;
m_udp_payload_axis_tdata_int = 8'd0;
m_udp_payload_axis_tvalid_int = 1'b0;
m_udp_payload_axis_tlast_int = 1'b0;
m_udp_payload_axis_tuser_int = 1'b0;
case (state_reg)
STATE_IDLE: begin
// idle state - wait for header
frame_ptr_next = 16'd0;
s_ip_hdr_ready_next = !m_udp_hdr_valid_next;
if (s_ip_hdr_ready && s_ip_hdr_valid) begin
s_ip_hdr_ready_next = 1'b0;
s_ip_payload_axis_tready_next = 1'b1;
store_ip_hdr = 1'b1;
state_next = STATE_READ_HEADER;
end else begin
state_next = STATE_IDLE;
end
end
STATE_READ_HEADER: begin
// read header state
s_ip_payload_axis_tready_next = 1'b1;
if (s_ip_payload_axis_tready && s_ip_payload_axis_tvalid) begin
// word transfer in - store it
frame_ptr_next = frame_ptr_reg + 16'd1;
state_next = STATE_READ_HEADER;
case (frame_ptr_reg)
8'h00: store_udp_source_port_1 = 1'b1;
8'h01: store_udp_source_port_0 = 1'b1;
8'h02: store_udp_dest_port_1 = 1'b1;
8'h03: store_udp_dest_port_0 = 1'b1;
8'h04: store_udp_length_1 = 1'b1;
8'h05: store_udp_length_0 = 1'b1;
8'h06: store_udp_checksum_1 = 1'b1;
8'h07: begin
store_udp_checksum_0 = 1'b1;
m_udp_hdr_valid_next = 1'b1;
s_ip_payload_axis_tready_next = m_udp_payload_axis_tready_int_early;
state_next = STATE_READ_PAYLOAD;
end
endcase
if (s_ip_payload_axis_tlast) begin
error_header_early_termination_next = 1'b1;
m_udp_hdr_valid_next = 1'b0;
s_ip_hdr_ready_next = !m_udp_hdr_valid_next;
s_ip_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_ip_payload_axis_tready_next = m_udp_payload_axis_tready_int_early;
m_udp_payload_axis_tdata_int = s_ip_payload_axis_tdata;
m_udp_payload_axis_tvalid_int = s_ip_payload_axis_tvalid;
m_udp_payload_axis_tlast_int = s_ip_payload_axis_tlast;
m_udp_payload_axis_tuser_int = s_ip_payload_axis_tuser;
if (s_ip_payload_axis_tready && s_ip_payload_axis_tvalid) begin
// word transfer through
frame_ptr_next = frame_ptr_reg + 16'd1;
if (s_ip_payload_axis_tlast) begin
if (frame_ptr_next != m_udp_length_reg) begin
// end of frame, but length does not match
m_udp_payload_axis_tuser_int = 1'b1;
error_payload_early_termination_next = 1'b1;
end
s_ip_hdr_ready_next = !m_udp_hdr_valid_next;
s_ip_payload_axis_tready_next = 1'b0;
state_next = STATE_IDLE;
end else begin
if (frame_ptr_next == m_udp_length_reg) begin
store_last_word = 1'b1;
m_udp_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_ip_payload_axis_tready_next = m_udp_payload_axis_tready_int_early;
m_udp_payload_axis_tdata_int = last_word_data_reg;
m_udp_payload_axis_tvalid_int = s_ip_payload_axis_tvalid && s_ip_payload_axis_tlast;
m_udp_payload_axis_tlast_int = s_ip_payload_axis_tlast;
m_udp_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_udp_hdr_valid_next;
s_ip_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
// wait for end of frame; read and discard
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_udp_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;
frame_ptr_reg <= 16'd0;
s_ip_hdr_ready_reg <= 1'b0;
s_ip_payload_axis_tready_reg <= 1'b0;
m_udp_hdr_valid_reg <= 1'b0;
busy_reg <= 1'b0;
error_header_early_termination_reg <= 1'b0;
error_payload_early_termination_reg <= 1'b0;
end else begin
state_reg <= state_next;
frame_ptr_reg <= frame_ptr_next;
s_ip_hdr_ready_reg <= s_ip_hdr_ready_next;
s_ip_payload_axis_tready_reg <= s_ip_payload_axis_tready_next;
m_udp_hdr_valid_reg <= m_udp_hdr_valid_next;
error_header_early_termination_reg <= error_header_early_termination_next;
error_payload_early_termination_reg <= error_payload_early_termination_next;
busy_reg <= state_next != STATE_IDLE;
end
// 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;
m_ip_version_reg <= s_ip_version;
m_ip_ihl_reg <= s_ip_ihl;
m_ip_dscp_reg <= s_ip_dscp;
m_ip_ecn_reg <= s_ip_ecn;
m_ip_length_reg <= s_ip_length;
m_ip_identification_reg <= s_ip_identification;
m_ip_flags_reg <= s_ip_flags;
m_ip_fragment_offset_reg <= s_ip_fragment_offset;
m_ip_ttl_reg <= s_ip_ttl;
m_ip_protocol_reg <= s_ip_protocol;
m_ip_header_checksum_reg <= s_ip_header_checksum;
m_ip_source_ip_reg <= s_ip_source_ip;
m_ip_dest_ip_reg <= s_ip_dest_ip;
end
if (store_last_word) begin
last_word_data_reg <= m_udp_payload_axis_tdata_int;
end
if (store_udp_source_port_0) m_udp_source_port_reg[ 7: 0] <= s_ip_payload_axis_tdata;
if (store_udp_source_port_1) m_udp_source_port_reg[15: 8] <= s_ip_payload_axis_tdata;
if (store_udp_dest_port_0) m_udp_dest_port_reg[ 7: 0] <= s_ip_payload_axis_tdata;
if (store_udp_dest_port_1) m_udp_dest_port_reg[15: 8] <= s_ip_payload_axis_tdata;
if (store_udp_length_0) m_udp_length_reg[ 7: 0] <= s_ip_payload_axis_tdata;
if (store_udp_length_1) m_udp_length_reg[15: 8] <= s_ip_payload_axis_tdata;
if (store_udp_checksum_0) m_udp_checksum_reg[ 7: 0] <= s_ip_payload_axis_tdata;
if (store_udp_checksum_1) m_udp_checksum_reg[15: 8] <= s_ip_payload_axis_tdata;
end
// output datapath logic
reg [7:0] m_udp_payload_axis_tdata_reg = 8'd0;
reg m_udp_payload_axis_tvalid_reg = 1'b0, m_udp_payload_axis_tvalid_next;
reg m_udp_payload_axis_tlast_reg = 1'b0;
reg m_udp_payload_axis_tuser_reg = 1'b0;
reg [7:0] temp_m_udp_payload_axis_tdata_reg = 8'd0;
reg temp_m_udp_payload_axis_tvalid_reg = 1'b0, temp_m_udp_payload_axis_tvalid_next;
reg temp_m_udp_payload_axis_tlast_reg = 1'b0;
reg temp_m_udp_payload_axis_tuser_reg = 1'b0;
// datapath control
reg store_udp_payload_int_to_output;
reg store_udp_payload_int_to_temp;
reg store_udp_payload_axis_temp_to_output;
assign m_udp_payload_axis_tdata = m_udp_payload_axis_tdata_reg;
assign m_udp_payload_axis_tvalid = m_udp_payload_axis_tvalid_reg;
assign m_udp_payload_axis_tlast = m_udp_payload_axis_tlast_reg;
assign m_udp_payload_axis_tuser = m_udp_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_udp_payload_axis_tready_int_early = m_udp_payload_axis_tready || (!temp_m_udp_payload_axis_tvalid_reg && (!m_udp_payload_axis_tvalid_reg || !m_udp_payload_axis_tvalid_int));
always @* begin
// transfer sink ready state to source
m_udp_payload_axis_tvalid_next = m_udp_payload_axis_tvalid_reg;
temp_m_udp_payload_axis_tvalid_next = temp_m_udp_payload_axis_tvalid_reg;
store_udp_payload_int_to_output = 1'b0;
store_udp_payload_int_to_temp = 1'b0;
store_udp_payload_axis_temp_to_output = 1'b0;
if (m_udp_payload_axis_tready_int_reg) begin
// input is ready
if (m_udp_payload_axis_tready || !m_udp_payload_axis_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output
m_udp_payload_axis_tvalid_next = m_udp_payload_axis_tvalid_int;
store_udp_payload_int_to_output = 1'b1;
end else begin
// output is not ready, store input in temp
temp_m_udp_payload_axis_tvalid_next = m_udp_payload_axis_tvalid_int;
store_udp_payload_int_to_temp = 1'b1;
end
end else if (m_udp_payload_axis_tready) begin
// input is not ready, but output is ready
m_udp_payload_axis_tvalid_next = temp_m_udp_payload_axis_tvalid_reg;
temp_m_udp_payload_axis_tvalid_next = 1'b0;
store_udp_payload_axis_temp_to_output = 1'b1;
end
end
always @(posedge clk) begin
if (rst) begin
m_udp_payload_axis_tvalid_reg <= 1'b0;
m_udp_payload_axis_tready_int_reg <= 1'b0;
temp_m_udp_payload_axis_tvalid_reg <= 1'b0;
end else begin
m_udp_payload_axis_tvalid_reg <= m_udp_payload_axis_tvalid_next;
m_udp_payload_axis_tready_int_reg <= m_udp_payload_axis_tready_int_early;
temp_m_udp_payload_axis_tvalid_reg <= temp_m_udp_payload_axis_tvalid_next;
end
// datapath
if (store_udp_payload_int_to_output) begin
m_udp_payload_axis_tdata_reg <= m_udp_payload_axis_tdata_int;
m_udp_payload_axis_tlast_reg <= m_udp_payload_axis_tlast_int;
m_udp_payload_axis_tuser_reg <= m_udp_payload_axis_tuser_int;
end else if (store_udp_payload_axis_temp_to_output) begin
m_udp_payload_axis_tdata_reg <= temp_m_udp_payload_axis_tdata_reg;
m_udp_payload_axis_tlast_reg <= temp_m_udp_payload_axis_tlast_reg;
m_udp_payload_axis_tuser_reg <= temp_m_udp_payload_axis_tuser_reg;
end
if (store_udp_payload_int_to_temp) begin
temp_m_udp_payload_axis_tdata_reg <= m_udp_payload_axis_tdata_int;
temp_m_udp_payload_axis_tlast_reg <= m_udp_payload_axis_tlast_int;
temp_m_udp_payload_axis_tuser_reg <= m_udp_payload_axis_tuser_int;
end
end
endmodule

View file

@ -1,489 +0,0 @@
/*
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
/*
* UDP ethernet frame transmitter (UDP frame in, IP frame out)
*/
module udp_ip_tx
(
input wire clk,
input wire rst,
/*
* UDP frame input
*/
input wire s_udp_hdr_valid,
output wire s_udp_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_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 [15:0] s_udp_source_port,
input wire [15:0] s_udp_dest_port,
input wire [15:0] s_udp_length,
input wire [15:0] s_udp_checksum,
input wire [7:0] s_udp_payload_axis_tdata,
input wire s_udp_payload_axis_tvalid,
output wire s_udp_payload_axis_tready,
input wire s_udp_payload_axis_tlast,
input wire s_udp_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_payload_early_termination
);
/*
UDP 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
source port 2 octets
desination port 2 octets
length 2 octets
checksum 2 octets
payload length octets
This module receives a UDP frame with header fields in parallel along with the
payload in an AXI stream, combines the header with the payload, passes through
the IP headers, and transmits the complete IP 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_udp_hdr;
reg store_last_word;
reg [15:0] frame_ptr_reg = 16'd0, frame_ptr_next;
reg [7:0] last_word_data_reg = 8'd0;
reg [15:0] udp_source_port_reg = 16'd0;
reg [15:0] udp_dest_port_reg = 16'd0;
reg [15:0] udp_length_reg = 16'd0;
reg [15:0] udp_checksum_reg = 16'd0;
reg s_udp_hdr_ready_reg = 1'b0, s_udp_hdr_ready_next;
reg s_udp_payload_axis_tready_reg = 1'b0, s_udp_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_payload_early_termination_reg = 1'b0, error_payload_early_termination_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_udp_hdr_ready = s_udp_hdr_ready_reg;
assign s_udp_payload_axis_tready = s_udp_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_payload_early_termination = error_payload_early_termination_reg;
always @* begin
state_next = STATE_IDLE;
s_udp_hdr_ready_next = 1'b0;
s_udp_payload_axis_tready_next = 1'b0;
store_udp_hdr = 1'b0;
store_last_word = 1'b0;
frame_ptr_next = frame_ptr_reg;
m_ip_hdr_valid_next = m_ip_hdr_valid_reg && !m_ip_hdr_ready;
error_payload_early_termination_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 data
frame_ptr_next = 16'd0;
s_udp_hdr_ready_next = !m_ip_hdr_valid_next;
if (s_udp_hdr_ready && s_udp_hdr_valid) begin
store_udp_hdr = 1'b1;
s_udp_hdr_ready_next = 1'b0;
m_ip_hdr_valid_next = 1'b1;
if (m_ip_payload_axis_tready_int_reg) begin
m_ip_payload_axis_tvalid_int = 1'b1;
m_ip_payload_axis_tdata_int = s_udp_source_port[15: 8];
frame_ptr_next = 1'b1;
end
state_next = STATE_WRITE_HEADER;
end else begin
state_next = STATE_IDLE;
end
end
STATE_WRITE_HEADER: begin
// write header state
if (m_ip_payload_axis_tready_int_reg) begin
// word transfer out
frame_ptr_next = frame_ptr_reg + 16'd1;
m_ip_payload_axis_tvalid_int = 1'b1;
state_next = STATE_WRITE_HEADER;
case (frame_ptr_reg)
8'h00: m_ip_payload_axis_tdata_int = udp_source_port_reg[15: 8];
8'h01: m_ip_payload_axis_tdata_int = udp_source_port_reg[ 7: 0];
8'h02: m_ip_payload_axis_tdata_int = udp_dest_port_reg[15: 8];
8'h03: m_ip_payload_axis_tdata_int = udp_dest_port_reg[ 7: 0];
8'h04: m_ip_payload_axis_tdata_int = udp_length_reg[15: 8];
8'h05: m_ip_payload_axis_tdata_int = udp_length_reg[ 7: 0];
8'h06: m_ip_payload_axis_tdata_int = udp_checksum_reg[15: 8];
8'h07: begin
m_ip_payload_axis_tdata_int = udp_checksum_reg[ 7: 0];
s_udp_payload_axis_tready_next = m_ip_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_udp_payload_axis_tready_next = m_ip_payload_axis_tready_int_early;
m_ip_payload_axis_tdata_int = s_udp_payload_axis_tdata;
m_ip_payload_axis_tvalid_int = s_udp_payload_axis_tvalid;
m_ip_payload_axis_tlast_int = s_udp_payload_axis_tlast;
m_ip_payload_axis_tuser_int = s_udp_payload_axis_tuser;
if (s_udp_payload_axis_tready && s_udp_payload_axis_tvalid) begin
// word transfer through
frame_ptr_next = frame_ptr_reg + 16'd1;
if (s_udp_payload_axis_tlast) begin
if (frame_ptr_next != udp_length_reg) 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_udp_hdr_ready_next = !m_ip_hdr_valid_next;
s_udp_payload_axis_tready_next = 1'b0;
state_next = STATE_IDLE;
end else begin
if (frame_ptr_next == udp_length_reg) begin
store_last_word = 1'b1;
m_ip_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_udp_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_udp_payload_axis_tvalid && s_udp_payload_axis_tlast;
m_ip_payload_axis_tlast_int = s_udp_payload_axis_tlast;
m_ip_payload_axis_tuser_int = s_udp_payload_axis_tuser;
if (s_udp_payload_axis_tready && s_udp_payload_axis_tvalid) begin
if (s_udp_payload_axis_tlast) begin
s_udp_hdr_ready_next = !m_ip_hdr_valid_next;
s_udp_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
// wait for end of frame; read and discard
s_udp_payload_axis_tready_next = 1'b1;
if (s_udp_payload_axis_tvalid) begin
if (s_udp_payload_axis_tlast) begin
s_udp_hdr_ready_next = !m_ip_hdr_valid_next;
s_udp_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;
frame_ptr_reg <= 16'd0;
s_udp_hdr_ready_reg <= 1'b0;
s_udp_payload_axis_tready_reg <= 1'b0;
m_ip_hdr_valid_reg <= 1'b0;
busy_reg <= 1'b0;
error_payload_early_termination_reg <= 1'b0;
end else begin
state_reg <= state_next;
frame_ptr_reg <= frame_ptr_next;
s_udp_hdr_ready_reg <= s_udp_hdr_ready_next;
s_udp_payload_axis_tready_reg <= s_udp_payload_axis_tready_next;
m_ip_hdr_valid_reg <= m_ip_hdr_valid_next;
busy_reg <= state_next != STATE_IDLE;
error_payload_early_termination_reg <= error_payload_early_termination_next;
end
// datapath
if (store_udp_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;
m_ip_version_reg <= s_ip_version;
m_ip_ihl_reg <= s_ip_ihl;
m_ip_dscp_reg <= s_ip_dscp;
m_ip_ecn_reg <= s_ip_ecn;
m_ip_length_reg <= s_udp_length + 20;
m_ip_identification_reg <= s_ip_identification;
m_ip_flags_reg <= s_ip_flags;
m_ip_fragment_offset_reg <= s_ip_fragment_offset;
m_ip_ttl_reg <= s_ip_ttl;
m_ip_protocol_reg <= s_ip_protocol;
m_ip_header_checksum_reg <= s_ip_header_checksum;
m_ip_source_ip_reg <= s_ip_source_ip;
m_ip_dest_ip_reg <= s_ip_dest_ip;
udp_source_port_reg <= s_udp_source_port;
udp_dest_port_reg <= s_udp_dest_port;
udp_length_reg <= s_udp_length;
udp_checksum_reg <= s_udp_checksum;
end
if (store_last_word) begin
last_word_data_reg <= m_ip_payload_axis_tdata_int;
end
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

View file

@ -1,2 +0,0 @@
PROJECT:=xlnx_axi_ethernetlite
include ../common.mk

View file

@ -1,17 +0,0 @@
set partNumber $::env(XILINX_PART)
set boardName $::env(XILINX_BOARD)
set ipName xlnx_axi_ethernetlite
create_project $ipName . -part $partNumber
set_property board_part $boardName [current_project]
create_ip -name axi_ethernetlite -vendor xilinx.com -library ip -module_name $ipName
set_property -dict [list CONFIG.C_S_AXI_PROTOCOL {AXI4} CONFIG.AXI_ACLK_FREQ_MHZ {100}] [get_ips $ipName]
generate_target {instantiation_template} [get_files ./$ipName.srcs/sources_1/ip/$ipName/$ipName.xci]
generate_target all [get_files ./$ipName.srcs/sources_1/ip/$ipName/$ipName.xci]
create_ip_run [get_files -of_objects [get_fileset sources_1] ./$ipName.srcs/sources_1/ip/$ipName/$ipName.xci]
launch_run -jobs 8 ${ipName}_synth_1
wait_on_run ${ipName}_synth_1

View file

@ -480,175 +480,7 @@ module ariane_peripherals #(
// ---------------
// 4. Ethernet
// ---------------
if (InclEthernet) begin : gen_ethernet
wire mdio_i, mdio_o, mdio_t;
logic [3:0] s_axi_eth_awid;
logic [31:0] s_axi_eth_awaddr;
logic [7:0] s_axi_eth_awlen;
logic [2:0] s_axi_eth_awsize;
logic [1:0] s_axi_eth_awburst;
logic [3:0] s_axi_eth_awcache;
logic s_axi_eth_awvalid;
logic s_axi_eth_awready;
logic [31:0] s_axi_eth_wdata;
logic [3:0] s_axi_eth_wstrb;
logic s_axi_eth_wlast;
logic s_axi_eth_wvalid;
logic s_axi_eth_wready;
logic [3:0] s_axi_eth_bid;
logic [1:0] s_axi_eth_bresp;
logic s_axi_eth_bvalid;
logic s_axi_eth_bready;
logic [3:0] s_axi_eth_arid;
logic [31:0] s_axi_eth_araddr;
logic [7:0] s_axi_eth_arlen;
logic [2:0] s_axi_eth_arsize;
logic [1:0] s_axi_eth_arburst;
logic [3:0] s_axi_eth_arcache;
logic s_axi_eth_arvalid;
logic s_axi_eth_arready;
logic [3:0] s_axi_eth_rid;
logic [31:0] s_axi_eth_rdata;
logic [1:0] s_axi_eth_rresp;
logic s_axi_eth_rlast;
logic s_axi_eth_rvalid;
assign s_axi_eth_awid = '0;
assign s_axi_eth_arid = '0;
// system-bus is 64-bit, convert down to 32 bit
xlnx_axi_clock_converter i_xlnx_axi_clock_converter_ethernet (
.s_axi_aclk ( clk_i ),
.s_axi_aresetn ( rst_ni ),
.s_axi_awid ( ethernet.aw_id ),
.s_axi_awaddr ( ethernet.aw_addr[31:0] ),
.s_axi_awlen ( ethernet.aw_len ),
.s_axi_awsize ( ethernet.aw_size ),
.s_axi_awburst ( ethernet.aw_burst ),
.s_axi_awlock ( ethernet.aw_lock ),
.s_axi_awcache ( ethernet.aw_cache ),
.s_axi_awprot ( ethernet.aw_prot ),
.s_axi_awregion ( ethernet.aw_region ),
.s_axi_awqos ( ethernet.aw_qos ),
.s_axi_awvalid ( ethernet.aw_valid ),
.s_axi_awready ( ethernet.aw_ready ),
.s_axi_wdata ( ethernet.w_data ),
.s_axi_wstrb ( ethernet.w_strb ),
.s_axi_wlast ( ethernet.w_last ),
.s_axi_wvalid ( ethernet.w_valid ),
.s_axi_wready ( ethernet.w_ready ),
.s_axi_bid ( ethernet.b_id ),
.s_axi_bresp ( ethernet.b_resp ),
.s_axi_bvalid ( ethernet.b_valid ),
.s_axi_bready ( ethernet.b_ready ),
.s_axi_arid ( ethernet.ar_id ),
.s_axi_araddr ( ethernet.ar_addr[31:0] ),
.s_axi_arlen ( ethernet.ar_len ),
.s_axi_arsize ( ethernet.ar_size ),
.s_axi_arburst ( ethernet.ar_burst ),
.s_axi_arlock ( ethernet.ar_lock ),
.s_axi_arcache ( ethernet.ar_cache ),
.s_axi_arprot ( ethernet.ar_prot ),
.s_axi_arregion ( ethernet.ar_region ),
.s_axi_arqos ( ethernet.ar_qos ),
.s_axi_arvalid ( ethernet.ar_valid ),
.s_axi_arready ( ethernet.ar_ready ),
.s_axi_rid ( ethernet.r_id ),
.s_axi_rdata ( ethernet.r_data ),
.s_axi_rresp ( ethernet.r_resp ),
.s_axi_rlast ( ethernet.r_last ),
.s_axi_rvalid ( ethernet.r_valid ),
.s_axi_rready ( ethernet.r_ready ),
.m_axi_awaddr ( s_axi_eth_awaddr ),
.m_axi_awlen ( s_axi_eth_awlen ),
.m_axi_awsize ( s_axi_eth_awsize ),
.m_axi_awburst ( s_axi_eth_awburst ),
.m_axi_awlock ( ),
.m_axi_awcache ( s_axi_eth_awcache ),
.m_axi_awprot ( ),
.m_axi_awregion ( ),
.m_axi_awqos ( ),
.m_axi_awvalid ( s_axi_eth_awvalid ),
.m_axi_awready ( s_axi_eth_awready ),
.m_axi_wdata ( s_axi_eth_wdata ),
.m_axi_wstrb ( s_axi_eth_wstrb ),
.m_axi_wlast ( s_axi_eth_wlast ),
.m_axi_wvalid ( s_axi_eth_wvalid ),
.m_axi_wready ( s_axi_eth_wready ),
.m_axi_bresp ( s_axi_eth_bresp ),
.m_axi_bvalid ( s_axi_eth_bvalid ),
.m_axi_bready ( s_axi_eth_bready ),
.m_axi_araddr ( s_axi_eth_araddr ),
.m_axi_arlen ( s_axi_eth_arlen ),
.m_axi_arsize ( s_axi_eth_arsize ),
.m_axi_arburst ( s_axi_eth_arburst ),
.m_axi_arlock ( ),
.m_axi_arcache ( s_axi_eth_arcache ),
.m_axi_arprot ( ),
.m_axi_arregion ( ),
.m_axi_arqos ( ),
.m_axi_arvalid ( s_axi_eth_arvalid ),
.m_axi_arready ( s_axi_eth_arready ),
.m_axi_rdata ( s_axi_eth_rdata ),
.m_axi_rresp ( s_axi_eth_rresp ),
.m_axi_rlast ( s_axi_eth_rlast ),
.m_axi_rvalid ( s_axi_eth_rvalid ),
.m_axi_rready ( m_axi_rready )
);
xlnx_axi_ethernetlite i_xlnx_axi_ethernetlite (
.s_axi_aclk ( clk_i ),
.s_axi_aresetn ( rst_ni ),
.ip2intc_irpt ( irq_sources[0] ),
.s_axi_awid ( s_axi_eth_awid ),
.s_axi_awaddr ( s_axi_eth_awaddr[12:0] ),
.s_axi_awlen ( s_axi_eth_awlen ),
.s_axi_awsize ( s_axi_eth_awsize ),
.s_axi_awburst ( s_axi_eth_awburst ),
.s_axi_awcache ( s_axi_eth_awcache ),
.s_axi_awvalid ( s_axi_eth_awvalid ),
.s_axi_awready ( s_axi_eth_awready ),
.s_axi_wdata ( s_axi_eth_wdata ),
.s_axi_wstrb ( s_axi_eth_wstrb ),
.s_axi_wlast ( s_axi_eth_wlast ),
.s_axi_wvalid ( s_axi_eth_wvalid ),
.s_axi_wready ( s_axi_eth_wready ),
.s_axi_bid ( s_axi_eth_bid ),
.s_axi_bresp ( s_axi_eth_bresp ),
.s_axi_bvalid ( s_axi_eth_bvalid ),
.s_axi_bready ( s_axi_eth_bready ),
.s_axi_arid ( s_axi_eth_arid ),
.s_axi_araddr ( s_axi_eth_araddr[12:0] ),
.s_axi_arlen ( s_axi_eth_arlen ),
.s_axi_arsize ( s_axi_eth_arsize ),
.s_axi_arburst ( s_axi_eth_arburst ),
.s_axi_arcache ( s_axi_eth_arcache ),
.s_axi_arvalid ( s_axi_eth_arvalid ),
.s_axi_arready ( s_axi_eth_arready ),
.s_axi_rid ( s_axi_eth_rid ),
.s_axi_rdata ( s_axi_eth_rdata ),
.s_axi_rresp ( s_axi_eth_rresp ),
.s_axi_rlast ( s_axi_eth_rlast ),
.s_axi_rvalid ( s_axi_eth_rvalid ),
.s_axi_rready ( s_axi_eth_rready ),
.phy_tx_clk ( eth_txck ),
.phy_rx_clk ( eth_rxck ),
.phy_crs ( 1'b0 ),
.phy_dv ( eth_rxctl ),
.phy_rx_data ( eth_rxd ),
.phy_col ( 1'b0 ),
.phy_rx_er ( 1'b0 ),
.phy_rst_n ( eth_rst_n ),
.phy_tx_en ( eth_tx_en ),
.phy_tx_data ( eth_txd ),
.phy_mdio_i ( mdio_i ),
.phy_mdio_o ( mdio_o ),
.phy_mdio_t ( mdio_t ),
.phy_mdc ( eth_mdc )
);
IOBUF mdio_io_iobuf (.I (mdio_o), .IO(mdio), .O (mdio_i), .T (mdio_t));
end else begin
begin
assign irq_sources [2] = 1'b0;
assign ethernet.aw_ready = 1'b1;
assign ethernet.ar_ready = 1'b1;