/* * ipv4.v * * Copyright (C) 2018, 2019 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: Receive State Machine and Logic for IPv4 * * * 0-7 8-15 16-23 24-31 * 0 Version/IHL TOS Total Length............. * 4 Identification...... Flags/Frag Off........... * 8 TTL Protocol Header Checksum.......... * 12 Source IP Address.................................... * 16 Dest IP Address...................................... * 20 Options / Padding.................................... * * * When pkt_start is detected, rx_data_m2 has the first byte */ `timescale 1ns /10ps module ipv4_rx ( input rstn, input clk, // control input phy_resetn, input phy_up, // packet data input pkt_start, // assert for each new frame to start state machines input rx_eop, // use as a synch reset input[7:0] rx_data_m1, input[7:0] rx_data_m2, input[7:0] rx_data_m3, // first byte of packet appears here simultaneous with pkt_start input[7:0] rx_data_m4, // flags output pkt_complete, output reg trigger_src_addr, output reg trigger_dst_addr, output reg keep ); /* Byte Address (when last byte of field is present on rx_data_m1 ) */ localparam IPV4_TOS=1, IPV4_LENGTH=3, IPV4_IP_ID=5, IPV4_PROTOCOL=9, IPV4_HDR_CKSUM=11, IPV4_SRC_ADDR=15, IPV4_DST_ADDR=19; localparam RX_ST_IDLE=4'h0, RX_ST_DATA=4'h1, RX_ST_DONE=4'h2, RX_ST_3=4'h3, RX_ST_4=4'h4, RX_ST_5=4'h5, RX_ST_6=4'h6, RX_ST_7=4'h7, RX_ST_8=4'h8, RX_ST_9=4'h9, RX_ST_A=4'ha, RX_ST_B=4'hb, RX_ST_C=4'hc, RX_ST_D=4'hd, RX_ST_E=4'he, RX_ST_F=4'hf; localparam IPV4_PROTO_ICMP = 1, IPV4_PROTO_IGMP = 2, IPV4_PROTO_TCP = 6, IPV4_PROTO_UDP = 17, IPV4_PROTO_ENCAP = 41, IPV4_PROTO_OSPF = 89, IPV4_PROTO_SCTP = 132; reg [3:0] rx_state; reg [10:0] rx_byte_cnt; reg [10:0] rx_pkt_length; reg [7:0] protocol; wire rx_error; /* * rx_state machine * capture an IPv4 Packet * */ always @(posedge clk, negedge rstn) if (!rstn) rx_state <= RX_ST_IDLE; else if ( rx_eop || !phy_resetn ) // EOP will reset state machine rx_state <= RX_ST_IDLE; else if ( phy_up ) case ( rx_state ) RX_ST_IDLE: if ( pkt_start ) // Found /S/ rx_state <= RX_ST_DATA; RX_ST_DATA: if (pkt_complete) rx_state <= RX_ST_DONE; RX_ST_DONE: rx_state <= RX_ST_IDLE; endcase else rx_state <= RX_ST_IDLE; /* rx_byte_cnt */ always @(posedge clk, negedge rstn) if (!rstn) rx_byte_cnt <= 0; else if ( rx_state == RX_ST_IDLE && !pkt_start ) // synch reset rx_byte_cnt <= 1; else if ( rx_state != RX_ST_IDLE || pkt_start ) rx_byte_cnt <= rx_byte_cnt + 1; /* protocol */ always @(posedge clk, negedge rstn) if ( !rstn ) protocol <= 0; else if ( rx_eop ) protocol <= 0; else if ( rx_byte_cnt == IPV4_PROTOCOL ) protocol <= rx_data_m1; /* rx_pkt_length */ always @(posedge clk, negedge rstn) if ( !rstn ) rx_pkt_length <= 11'h7ff; else if ( rx_eop ) rx_pkt_length <= 11'h7ff; else if ( rx_state == RX_ST_DATA && rx_byte_cnt == IPV4_LENGTH ) rx_pkt_length <= { rx_data_m2[2:0], rx_data_m1 }; /* * Packet Filter Trigger(s), assert the sample before the data appears * */ always @(posedge clk, negedge rstn) if (!rstn) trigger_src_addr <= 1'b0; else if ( rx_byte_cnt == IPV4_SRC_ADDR-1 ) trigger_src_addr <= 1'b1; else trigger_src_addr <= 1'b0; always @(posedge clk, negedge rstn) if (!rstn) trigger_dst_addr <= 1'b0; else if ( rx_byte_cnt == IPV4_DST_ADDR-1 ) trigger_dst_addr <= 1'b1; else trigger_dst_addr <= 1'b0; assign pkt_complete = ( rx_state >= RX_ST_DATA && rx_pkt_length == rx_byte_cnt+1 ) ? 1 : 0; assign rx_error = 0; endmodule