mirror of
https://github.com/openhwgroup/cva6.git
synced 2025-04-20 12:17:19 -04:00
Remove unused modules from Ethernet hierarchy
This commit is contained in:
parent
24d37830db
commit
1311a8da0b
27 changed files with 1 additions and 8693 deletions
416
fpga/src/arp.sv
416
fpga/src/arp.sv
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
341
fpga/src/ip.sv
341
fpga/src/ip.sv
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
413
fpga/src/udp.sv
413
fpga/src/udp.sv
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -1,2 +0,0 @@
|
|||
PROJECT:=xlnx_axi_ethernetlite
|
||||
include ../common.mk
|
|
@ -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
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue