/* * ipv4_tx.v * * Copyright 2025 Private Island Networks Inc. * Copyright 2018, 2019, 2020 Mind Chasers Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * function: Layer 3 (and 4) Support for Controller Transmit * * */ module ipv4_tx_c( input rstn, input phy_resetn, input clk, // Control Interface input cont_clk, // controller clock input cont_sel, input cont_we, input [7:0] cont_addr, input [15:0] cont_d_i, output reg [15:0] cont_d_o, // Line State input mode_100Mbit, input phy_up, // Switch I/F input [2:0] tx_mode, input [2:0] tx_src_sel, input [10:0] byte_cnt_i, // MAC Interface input fifo_re_i, output reg fifo_empty_o, output reg [8:0] fifo_d_o, // Debug output [7:0] gpio ); `define INCLUDED `include "ethernet_params.v" `include "rgmii_params.v" `undef INCLUDED localparam TX_CNT_OFFSET = 11'h15; // offset for start of IP Header in Ethernet frame localparam TX_CNT_CKSUM_START = TX_CNT_OFFSET + 10; wire ipv4_hdr_active; reg [10:0] tx_cnt; reg [17:0] ipv4_cksum; reg [15:0] ipv4_pkt_length; reg [15:0] udp_pkt_length; integer i; assign ipv4_hdr_active = (tx_mode == TX_MODE_XMT_CUSTOM && tx_src_sel == TX_SRC_SEL_UC); always @(posedge clk, negedge rstn) if ( !rstn ) tx_cnt <= 11'd0; else if (ipv4_hdr_active) tx_cnt <= tx_cnt + 1'b1; else tx_cnt <= 11'd0; always @(posedge clk, negedge rstn) if ( !rstn ) begin ipv4_pkt_length <= 16'd0; udp_pkt_length <= 16'd0; end else if (ipv4_hdr_active && tx_cnt == 11'd0) begin ipv4_pkt_length <= byte_cnt_i + SZ_IPV4_HEADER + SZ_UDP_HEADER; udp_pkt_length <= byte_cnt_i + SZ_UDP_HEADER; end always @(posedge clk, negedge rstn) if ( !rstn ) ipv4_cksum <= 18'd0; else if (!ipv4_hdr_active) ipv4_cksum <= 18'd0; else if (tx_cnt < 11'd20 && tx_cnt[0]) ipv4_cksum <= ipv4_cksum + (ipv4_hdr(tx_cnt-1)<<8) + ipv4_hdr(tx_cnt); // else if (tx_cnt == 11'd20) // ipv4_cksum <= ipv4_cksum + ipv4_pkt_length; else if (tx_cnt == 11'd21) ipv4_cksum <= {2'b00,ipv4_cksum[15:0]} + {16'h0000,ipv4_cksum[17:16]}; else if (tx_cnt == 11'd22) ipv4_cksum <= {2'b00, ~ipv4_cksum[15:0]}; // fifo_empty_o always @(posedge clk, negedge rstn) if ( !rstn ) fifo_empty_o <= 1'b1; else if (tx_cnt >= TX_CNT_OFFSET && tx_cnt < (TX_CNT_OFFSET + SZ_IPV4_HEADER + SZ_UDP_HEADER)) fifo_empty_o <= 1'b0; else fifo_empty_o <= 1'b1; // fifo_d_o always @(posedge clk, negedge rstn) if ( !rstn ) fifo_d_o <= 9'h000; else if (tx_cnt == TX_CNT_CKSUM_START) fifo_d_o <= ipv4_cksum[15:8]; else if (tx_cnt == TX_CNT_CKSUM_START+1) fifo_d_o <= ipv4_cksum[7:0]; else if (tx_cnt >= TX_CNT_OFFSET && tx_cnt < TX_CNT_OFFSET + SZ_IPV4_HEADER) fifo_d_o <= ipv4_hdr(tx_cnt-TX_CNT_OFFSET); else if (tx_cnt >= TX_CNT_OFFSET && tx_cnt < TX_CNT_OFFSET + SZ_IPV4_HEADER + SZ_UDP_HEADER) fifo_d_o <= udp_hdr(tx_cnt-(TX_CNT_OFFSET + SZ_IPV4_HEADER)); else fifo_d_o <= 9'h000; // generate the IPv4 header // Assuming the header is only 20 bytes, this is both efficient and flexible function automatic [7:0] ipv4_hdr; input [10:0] ad; case(ad) 0: ipv4_hdr = 8'h45; // Version 1: ipv4_hdr = 8'h00; // IHL 2: ipv4_hdr = ipv4_pkt_length[15:8]; // Total Length 3: ipv4_hdr = ipv4_pkt_length[7:0]; 4: ipv4_hdr = 8'h54; 5: ipv4_hdr = 8'hDB; 6: ipv4_hdr = 8'h40; 7: ipv4_hdr = 8'h00; 8: ipv4_hdr = 8'h40; // TTL 9: ipv4_hdr = 8'h11; // L4 Protocol (UDP=0x11) 10: ipv4_hdr = 8'h00; // Checksum 11: ipv4_hdr = 8'h00; 12: ipv4_hdr = 8'd192; // IP Source Address 13: ipv4_hdr = 8'd168; 14: ipv4_hdr = 8'd5; 15: ipv4_hdr = 8'd100; 16: ipv4_hdr = 8'd192; // IP Destination Address 17: ipv4_hdr = 8'd168; 18: ipv4_hdr = 8'd5; 19: ipv4_hdr = 8'd40; default: ipv4_hdr = 8'h00; endcase endfunction // generate the UDP header function automatic [7:0] udp_hdr; input [10:0] ad; case(ad) 0: udp_hdr = 8'h80; // SRC Port 1: udp_hdr = 8'h00; // 2: udp_hdr = 8'h80; // DST Port 3: udp_hdr = 8'h00; 4: udp_hdr = udp_pkt_length[15:8]; // Length 5: udp_hdr = udp_pkt_length[7:0]; 6: udp_hdr = 8'h00; //Checksum 7: udp_hdr = 8'h00; default: udp_hdr = 8'h00; endcase endfunction assign gpio[0] = |ipv4_cksum[7:0]; assign gpio[1] = |ipv4_cksum[15:8]; endmodule