1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
|
/*
* 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
|