code clean up
[litex.git] / liteeth / core / arp / __init__.py
1 from liteeth.common import *
2 from liteeth.generic.depacketizer import LiteEthDepacketizer
3 from liteeth.generic.packetizer import LiteEthPacketizer
4
5 _arp_table_layout = [
6 ("reply", 1),
7 ("request", 1),
8 ("ip_address", 32),
9 ("mac_address", 48)
10 ]
11
12 class LiteEthARPDepacketizer(LiteEthDepacketizer):
13 def __init__(self):
14 LiteEthDepacketizer.__init__(self,
15 eth_mac_description(8),
16 eth_arp_description(8),
17 arp_header,
18 arp_header_len)
19
20 class LiteEthARPPacketizer(LiteEthPacketizer):
21 def __init__(self):
22 LiteEthPacketizer.__init__(self,
23 eth_arp_description(8),
24 eth_mac_description(8),
25 arp_header,
26 arp_header_len)
27
28 class LiteEthARPTX(Module):
29 def __init__(self, mac_address, ip_address):
30 self.sink = sink = Sink(_arp_table_layout)
31 self.source = source = Source(eth_mac_description(8))
32 ###
33 self.submodules.packetizer = packetizer = LiteEthARPPacketizer()
34
35 counter = Counter(max=max(arp_header_len, eth_min_len))
36 self.submodules += counter
37
38 self.submodules.fsm = fsm = FSM(reset_state="IDLE")
39 fsm.act("IDLE",
40 sink.ack.eq(1),
41 counter.reset.eq(1),
42 If(sink.stb,
43 sink.ack.eq(0),
44 NextState("SEND")
45 )
46 )
47 self.comb += [
48 packetizer.sink.sop.eq(counter.value == 0),
49 packetizer.sink.eop.eq(counter.value == max(arp_header_len, eth_min_len)-1),
50 packetizer.sink.hwtype.eq(arp_hwtype_ethernet),
51 packetizer.sink.proto.eq(arp_proto_ip),
52 packetizer.sink.hwsize.eq(6),
53 packetizer.sink.protosize.eq(4),
54 packetizer.sink.sender_mac.eq(mac_address),
55 packetizer.sink.sender_ip.eq(ip_address),
56 If(sink.reply,
57 packetizer.sink.opcode.eq(arp_opcode_reply),
58 packetizer.sink.target_mac.eq(sink.mac_address),
59 packetizer.sink.target_ip.eq(sink.ip_address)
60 ).Elif(sink.request,
61
62 packetizer.sink.opcode.eq(arp_opcode_request),
63 packetizer.sink.target_mac.eq(0xffffffffffff),
64 packetizer.sink.target_ip.eq(sink.ip_address)
65 )
66 ]
67 fsm.act("SEND",
68 packetizer.sink.stb.eq(1),
69 Record.connect(packetizer.source, source),
70 source.target_mac.eq(packetizer.sink.target_mac),
71 source.sender_mac.eq(mac_address),
72 source.ethernet_type.eq(ethernet_type_arp),
73 If(source.stb & source.ack,
74 counter.ce.eq(1),
75 If(source.eop,
76 sink.ack.eq(1),
77 NextState("IDLE")
78 )
79 )
80 )
81
82 class LiteEthARPRX(Module):
83 def __init__(self, mac_address, ip_address):
84 self.sink = sink = Sink(eth_mac_description(8))
85 self.source = source = Source(_arp_table_layout)
86 ###
87 self.submodules.depacketizer = depacketizer = LiteEthARPDepacketizer()
88 self.comb += Record.connect(sink, depacketizer.sink)
89
90 self.submodules.fsm = fsm = FSM(reset_state="IDLE")
91 fsm.act("IDLE",
92 depacketizer.source.ack.eq(1),
93 If(depacketizer.source.stb & depacketizer.source.sop,
94 depacketizer.source.ack.eq(0),
95 NextState("CHECK")
96 )
97 )
98 valid = Signal()
99 self.comb += valid.eq(
100 depacketizer.source.stb &
101 (depacketizer.source.hwtype == arp_hwtype_ethernet) &
102 (depacketizer.source.proto == arp_proto_ip) &
103 (depacketizer.source.hwsize == 6) &
104 (depacketizer.source.protosize == 4) &
105 (depacketizer.source.target_ip == ip_address)
106 )
107 reply = Signal()
108 request = Signal()
109 self.comb += Case(depacketizer.source.opcode, {
110 arp_opcode_request : [request.eq(1)],
111 arp_opcode_reply : [reply.eq(1)],
112 "default" : []
113 })
114 self.comb += [
115 source.ip_address.eq(depacketizer.source.sender_ip),
116 source.mac_address.eq(depacketizer.source.sender_mac)
117 ]
118 fsm.act("CHECK",
119 If(valid,
120 source.stb.eq(1),
121 source.reply.eq(reply),
122 source.request.eq(request)
123 ),
124 NextState("TERMINATE")
125 ),
126 fsm.act("TERMINATE",
127 depacketizer.source.ack.eq(1),
128 If(depacketizer.source.stb & depacketizer.source.eop,
129 NextState("IDLE")
130 )
131 )
132
133 class LiteEthARPTable(Module):
134 def __init__(self, clk_freq, max_requests=8):
135 self.sink = sink = Sink(_arp_table_layout) # from arp_rx
136 self.source = source = Source(_arp_table_layout) # to arp_tx
137
138 # Request/Response interface
139 self.request = request = Sink(arp_table_request_layout)
140 self.response = response = Source(arp_table_response_layout)
141 ###
142 request_timeout = Timeout(clk_freq//10)
143 request_counter = Counter(max=max_requests)
144 request_pending = FlipFlop()
145 request_ip_address = FlipFlop(32)
146 self.submodules += request_timeout, request_counter, request_pending, request_ip_address
147 self.comb += [
148 request_timeout.ce.eq(request_pending.q),
149 request_pending.d.eq(1),
150 request_ip_address.d.eq(request.ip_address)
151 ]
152
153 # Note: Store only 1 IP/MAC couple, can be improved with a real
154 # table in the future to improve performance when packets are
155 # targeting multiple destinations.
156 update = Signal()
157 cached_valid = Signal()
158 cached_ip_address = Signal(32)
159 cached_mac_address = Signal(48)
160 cached_timeout = Timeout(clk_freq*10)
161 self.submodules += cached_timeout
162
163 self.submodules.fsm = fsm = FSM(reset_state="IDLE")
164 fsm.act("IDLE",
165 # Note: for simplicicy, if APR table is busy response from arp_rx
166 # is lost. This is compensated by the protocol (retries)
167 If(sink.stb & sink.request,
168 NextState("SEND_REPLY")
169 ).Elif(sink.stb & sink.reply & request_pending.q,
170 NextState("UPDATE_TABLE"),
171 ).Elif(request_counter.value == max_requests-1,
172 NextState("PRESENT_RESPONSE")
173 ).Elif(request.stb | (request_pending.q & request_timeout.reached),
174 NextState("CHECK_TABLE")
175 )
176 )
177 fsm.act("SEND_REPLY",
178 source.stb.eq(1),
179 source.reply.eq(1),
180 source.ip_address.eq(sink.ip_address),
181 If(source.ack,
182 NextState("IDLE")
183 )
184 )
185 fsm.act("UPDATE_TABLE",
186 request_pending.reset.eq(1),
187 update.eq(1),
188 NextState("CHECK_TABLE")
189 )
190 self.sync += [
191 If(update,
192 cached_valid.eq(1),
193 cached_ip_address.eq(sink.ip_address),
194 cached_mac_address.eq(sink.mac_address),
195 cached_timeout.reset.eq(1)
196 ).Else(
197 cached_timeout.ce.eq(1),
198 If(cached_timeout.reached,
199 cached_valid.eq(0)
200 )
201 )
202 ]
203 found = Signal()
204 fsm.act("CHECK_TABLE",
205 If(cached_valid,
206 If(request_ip_address.q == cached_ip_address,
207 request_ip_address.reset.eq(1),
208 NextState("PRESENT_RESPONSE"),
209 ).Elif(request.ip_address == cached_ip_address,
210 request.ack.eq(request.stb),
211 NextState("PRESENT_RESPONSE"),
212 ).Else(
213 request_ip_address.ce.eq(request.stb),
214 NextState("SEND_REQUEST")
215 )
216 ).Else(
217 request_ip_address.ce.eq(request.stb),
218 NextState("SEND_REQUEST")
219 )
220 )
221 fsm.act("SEND_REQUEST",
222 source.stb.eq(1),
223 source.request.eq(1),
224 source.ip_address.eq(request_ip_address.q),
225 If(source.ack,
226 request_timeout.reset.eq(1),
227 request_counter.reset.eq(request.stb),
228 request_counter.ce.eq(1),
229 request_pending.ce.eq(1),
230 request.ack.eq(1),
231 NextState("IDLE")
232 )
233 )
234 self.comb += [
235 If(request_counter == max_requests-1,
236 response.failed.eq(1),
237 request_counter.reset.eq(1),
238 request_pending.reset.eq(1)
239 ),
240 response.mac_address.eq(cached_mac_address)
241 ]
242 fsm.act("PRESENT_RESPONSE",
243 response.stb.eq(1),
244 If(response.ack,
245 NextState("IDLE")
246 )
247 )
248
249 class LiteEthARP(Module):
250 def __init__(self, mac, mac_address, ip_address, clk_freq):
251 self.submodules.tx = tx = LiteEthARPTX(mac_address, ip_address)
252 self.submodules.rx = rx = LiteEthARPRX(mac_address, ip_address)
253 self.submodules.table = table = LiteEthARPTable(clk_freq)
254 self.comb += [
255 Record.connect(rx.source, table.sink),
256 Record.connect(table.source, tx.sink)
257 ]
258 mac_port = mac.crossbar.get_port(ethernet_type_arp)
259 self.comb += [
260 Record.connect(tx.source, mac_port.sink),
261 Record.connect(mac_port.source, rx.sink)
262 ]