1 from liteeth
.common
import *
2 from liteeth
.generic
.depacketizer
import LiteEthDepacketizer
3 from liteeth
.generic
.packetizer
import LiteEthPacketizer
12 class LiteEthARPDepacketizer(LiteEthDepacketizer
):
14 LiteEthDepacketizer
.__init
__(self
,
15 eth_mac_description(8),
16 eth_arp_description(8),
20 class LiteEthARPPacketizer(LiteEthPacketizer
):
22 LiteEthPacketizer
.__init
__(self
,
23 eth_arp_description(8),
24 eth_mac_description(8),
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))
33 self
.submodules
.packetizer
= packetizer
= LiteEthARPPacketizer()
35 counter
= Counter(max=max(arp_header_len
, eth_min_len
))
36 self
.submodules
+= counter
38 self
.submodules
.fsm
= fsm
= FSM(reset_state
="IDLE")
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
),
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
)
62 packetizer
.sink
.opcode
.eq(arp_opcode_request
),
63 packetizer
.sink
.target_mac
.eq(0xffffffffffff),
64 packetizer
.sink
.target_ip
.eq(sink
.ip_address
)
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
,
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
)
87 self
.submodules
.depacketizer
= depacketizer
= LiteEthARPDepacketizer()
88 self
.comb
+= Record
.connect(sink
, depacketizer
.sink
)
90 self
.submodules
.fsm
= fsm
= FSM(reset_state
="IDLE")
92 depacketizer
.source
.ack
.eq(1),
93 If(depacketizer
.source
.stb
& depacketizer
.source
.sop
,
94 depacketizer
.source
.ack
.eq(0),
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
)
109 self
.comb
+= Case(depacketizer
.source
.opcode
, {
110 arp_opcode_request
: [request
.eq(1)],
111 arp_opcode_reply
: [reply
.eq(1)],
115 source
.ip_address
.eq(depacketizer
.source
.sender_ip
),
116 source
.mac_address
.eq(depacketizer
.source
.sender_mac
)
121 source
.reply
.eq(reply
),
122 source
.request
.eq(request
)
124 NextState("TERMINATE")
127 depacketizer
.source
.ack
.eq(1),
128 If(depacketizer
.source
.stb
& depacketizer
.source
.eop
,
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
138 # Request/Response interface
139 self
.request
= request
= Sink(arp_table_request_layout
)
140 self
.response
= response
= Source(arp_table_response_layout
)
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
148 request_timeout
.ce
.eq(request_pending
.q
),
149 request_pending
.d
.eq(1),
150 request_ip_address
.d
.eq(request
.ip_address
)
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.
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
163 self
.submodules
.fsm
= fsm
= FSM(reset_state
="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")
177 fsm
.act("SEND_REPLY",
180 source
.ip_address
.eq(sink
.ip_address
),
185 fsm
.act("UPDATE_TABLE",
186 request_pending
.reset
.eq(1),
188 NextState("CHECK_TABLE")
193 cached_ip_address
.eq(sink
.ip_address
),
194 cached_mac_address
.eq(sink
.mac_address
),
195 cached_timeout
.reset
.eq(1)
197 cached_timeout
.ce
.eq(1),
198 If(cached_timeout
.reached
,
204 fsm
.act("CHECK_TABLE",
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"),
213 request_ip_address
.ce
.eq(request
.stb
),
214 NextState("SEND_REQUEST")
217 request_ip_address
.ce
.eq(request
.stb
),
218 NextState("SEND_REQUEST")
221 fsm
.act("SEND_REQUEST",
223 source
.request
.eq(1),
224 source
.ip_address
.eq(request_ip_address
.q
),
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),
235 If(request_counter
== max_requests
-1,
236 response
.failed
.eq(1),
237 request_counter
.reset
.eq(1),
238 request_pending
.reset
.eq(1)
240 response
.mac_address
.eq(cached_mac_address
)
242 fsm
.act("PRESENT_RESPONSE",
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
)
255 Record
.connect(rx
.source
, table
.sink
),
256 Record
.connect(table
.source
, tx
.sink
)
258 mac_port
= mac
.crossbar
.get_port(ethernet_type_arp
)
260 Record
.connect(tx
.source
, mac_port
.sink
),
261 Record
.connect(mac_port
.source
, rx
.sink
)