2 from collections
import OrderedDict
4 from migen
.fhdl
.std
import *
5 from migen
.fhdl
.decorators
import ModuleDecorator
6 from migen
.genlib
.resetsync
import AsyncResetSynchronizer
7 from migen
.genlib
.record
import *
8 from migen
.genlib
.fsm
import FSM
, NextState
9 from migen
.genlib
.misc
import chooser
10 from migen
.flow
.actor
import *
11 from migen
.flow
.plumbing
import Buffer
12 from migen
.actorlib
.structuring
import Converter
, Pipeline
13 from migen
.actorlib
.fifo
import SyncFIFO
, AsyncFIFO
14 from migen
.bank
.description
import *
18 eth_interpacket_gap
= 12
19 eth_preamble
= 0xD555555555555555
20 buffer_depth
= 2**log2_int(eth_mtu
, need_pow2
=False)
23 def __init__(self
, byte
, offset
, width
):
28 ethernet_type_ip
= 0x800
29 ethernet_type_arp
= 0x806
33 "target_mac": HField(0, 0, 48),
34 "sender_mac": HField(6, 0, 48),
35 "ethernet_type": HField(12, 0, 16)
38 arp_hwtype_ethernet
= 0x0001
40 arp_opcode_request
= 0x0001
41 arp_opcode_reply
= 0x0002
45 "hwtype": HField( 0, 0, 16),
46 "proto": HField( 2, 0, 16),
47 "hwsize": HField( 4, 0, 8),
48 "protosize": HField( 5, 0, 8),
49 "opcode": HField( 6, 0, 16),
50 "sender_mac": HField( 8, 0, 48),
51 "sender_ip": HField(14, 0, 32),
52 "target_mac": HField(18, 0, 48),
53 "target_ip": HField(24, 0, 32)
58 "ihl": HField(0, 0, 4),
59 "version": HField(0, 4, 4),
60 "total_length": HField(2, 0, 16),
61 "identification": HField(4, 0, 16),
62 "ttl": HField(8, 0, 8),
63 "protocol": HField(9, 0, 8),
64 "checksum": HField(10, 0, 16),
65 "sender_ip": HField(12, 0, 32),
66 "target_ip": HField(16, 0, 32)
71 "msgtype": HField( 0, 0, 8),
72 "code": HField( 1, 0, 8),
73 "checksum": HField( 2, 0, 16),
74 "quench": HField( 4, 0, 32)
80 "src_port": HField( 0, 0, 16),
81 "dst_port": HField( 2, 0, 16),
82 "length": HField( 4, 0, 16),
83 "checksum": HField( 6, 0, 16)
88 etherbone_magic
= 0x4e6f
90 etherbone_packet_header_len
= 8
91 etherbone_packet_header
= {
92 "magic": HField( 0, 0, 16),
94 "version": HField( 2, 4, 4),
95 "nr": HField( 2, 2, 1),
96 "pr": HField( 2, 1, 1),
97 "pf": HField( 2, 0, 1),
99 "addr_size": HField( 3, 4, 4),
100 "port_size": HField( 3, 0, 4)
103 etherbone_record_header_len
= 4
104 etherbone_record_header
= {
105 "bca": HField( 0, 0, 1),
106 "rca": HField( 0, 1, 1),
107 "rff": HField( 0, 2, 1),
108 "cyc": HField( 0, 4, 1),
109 "wca": HField( 0, 5, 1),
110 "wff": HField( 0, 6, 1),
112 "byte_enable": HField( 1, 0, 8),
114 "wcount": HField( 2, 0, 8),
116 "rcount": HField( 3, 0, 8)
119 def reverse_bytes(v
):
120 n
= math
.ceil(flen(v
)/8)
122 for i
in reversed(range(n
)):
123 r
.append(v
[i
*8:min((i
+1)*8, flen(v
))])
127 def _layout_from_header(header
):
129 for k
, v
in sorted(header
.items()):
130 _layout
.append((k
, v
.width
))
133 def _remove_from_layout(layout
, *args
):
144 def eth_raw_description(dw
):
149 return EndpointDescription(payload_layout
, packetized
=True)
151 def eth_phy_description(dw
):
157 return EndpointDescription(payload_layout
, packetized
=True)
159 def eth_mac_description(dw
):
160 payload_layout
= _layout_from_header(mac_header
) + [
165 return EndpointDescription(payload_layout
, packetized
=True)
167 def eth_arp_description(dw
):
172 param_layout
= _layout_from_header(arp_header
)
173 return EndpointDescription(payload_layout
, param_layout
, packetized
=True)
175 arp_table_request_layout
= [
179 arp_table_response_layout
= [
184 def eth_ipv4_description(dw
):
189 param_layout
= _layout_from_header(ipv4_header
)
190 return EndpointDescription(payload_layout
, param_layout
, packetized
=True)
192 def eth_ipv4_user_description(dw
):
202 return EndpointDescription(payload_layout
, param_layout
, packetized
=True)
206 for e
in s
.split("."):
211 def eth_icmp_description(dw
):
216 param_layout
= _layout_from_header(icmp_header
)
217 return EndpointDescription(payload_layout
, param_layout
, packetized
=True)
219 def eth_icmp_user_description(dw
):
224 param_layout
= _layout_from_header(icmp_header
) + [
228 return EndpointDescription(payload_layout
, param_layout
, packetized
=True)
230 def eth_udp_description(dw
):
235 param_layout
= _layout_from_header(udp_header
)
236 return EndpointDescription(payload_layout
, param_layout
, packetized
=True)
238 def eth_udp_user_description(dw
):
249 return EndpointDescription(payload_layout
, param_layout
, packetized
=True)
251 def eth_etherbone_packet_description(dw
):
256 param_layout
= _layout_from_header(etherbone_packet_header
)
257 return EndpointDescription(payload_layout
, param_layout
, packetized
=True)
259 def eth_etherbone_packet_user_description(dw
):
264 param_layout
= _layout_from_header(etherbone_packet_header
)
265 param_layout
= _remove_from_layout(param_layout
, "magic", "portsize", "addrsize", "version")
266 param_layout
+= eth_udp_user_description(dw
).param_layout
267 return EndpointDescription(payload_layout
, param_layout
, packetized
=True)
269 def eth_etherbone_record_description(dw
):
274 param_layout
= _layout_from_header(etherbone_record_header
)
275 return EndpointDescription(payload_layout
, param_layout
, packetized
=True)
277 def eth_etherbone_mmap_description(dw
):
287 return EndpointDescription(payload_layout
, param_layout
, packetized
=True)
291 def connect(self
, port
):
293 Record
.connect(self
.source
, port
.sink
),
294 Record
.connect(port
.source
, self
.sink
)
299 @DecorateModule(InsertReset
)
300 @DecorateModule(InsertCE
)
301 class FlipFlop(Module
):
302 def __init__(self
, *args
, **kwargs
):
303 self
.d
= Signal(*args
, **kwargs
)
304 self
.q
= Signal(*args
, **kwargs
)
305 self
.sync
+= self
.q
.eq(self
.d
)
307 @DecorateModule(InsertReset
)
308 @DecorateModule(InsertCE
)
309 class Counter(Module
):
310 def __init__(self
, signal
=None, **kwargs
):
312 self
.value
= Signal(**kwargs
)
315 self
.width
= flen(self
.value
)
316 self
.sync
+= self
.value
.eq(self
.value
+1)
318 @DecorateModule(InsertReset
)
319 @DecorateModule(InsertCE
)
320 class Timeout(Module
):
321 def __init__(self
, length
):
322 self
.reached
= Signal()
324 value
= Signal(max=length
)
325 self
.sync
+= If(~self
.reached
, value
.eq(value
+1))
326 self
.comb
+= self
.reached
.eq(value
== (length
-1))
328 class BufferizeEndpoints(ModuleDecorator
):
329 def __init__(self
, submodule
, *args
):
330 ModuleDecorator
.__init
__(self
, submodule
)
332 endpoints
= get_endpoints(submodule
)
335 for name
, endpoint
in endpoints
.items():
336 if name
in args
or len(args
) == 0:
337 if isinstance(endpoint
, Sink
):
338 sinks
.update({name
: endpoint
})
339 elif isinstance(endpoint
, Source
):
340 sources
.update({name
: endpoint
})
342 # add buffer on sinks
343 for name
, sink
in sinks
.items():
344 buf
= Buffer(sink
.description
)
345 self
.submodules
+= buf
346 setattr(self
, name
, buf
.d
)
347 self
.comb
+= Record
.connect(buf
.q
, sink
)
349 # add buffer on sources
350 for name
, source
in sources
.items():
351 buf
= Buffer(source
.description
)
352 self
.submodules
+= buf
353 self
.comb
+= Record
.connect(source
, buf
.d
)
354 setattr(self
, name
, buf
.q
)
356 class EndpointPacketStatus(Module
):
357 def __init__(self
, endpoint
):
358 self
.start
= Signal()
360 self
.ongoing
= Signal()
364 self
.start
.eq(endpoint
.stb
& endpoint
.sop
& endpoint
.ack
),
365 self
.done
.eq(endpoint
.stb
& endpoint
.eop
& endpoint
.ack
)
373 self
.comb
+= self
.ongoing
.eq((self
.start | ongoing
) & ~self
.done
)
375 class PacketBuffer(Module
):
376 def __init__(self
, description
, data_depth
, cmd_depth
=4, almost_full
=None):
377 self
.sink
= sink
= Sink(description
)
378 self
.source
= source
= Source(description
)
381 sink_status
= EndpointPacketStatus(self
.sink
)
382 source_status
= EndpointPacketStatus(self
.source
)
383 self
.submodules
+= sink_status
, source_status
385 # store incoming packets
387 def cmd_description():
388 layout
= [("error", 1)]
389 return EndpointDescription(layout
)
390 cmd_fifo
= SyncFIFO(cmd_description(), cmd_depth
)
391 self
.submodules
+= cmd_fifo
392 self
.comb
+= cmd_fifo
.sink
.stb
.eq(sink_status
.done
)
393 if hasattr(sink
, "error"):
394 self
.comb
+= cmd_fifo
.sink
.error
.eq(sink
.error
)
397 data_fifo
= SyncFIFO(description
, data_depth
, buffered
=True)
398 self
.submodules
+= data_fifo
400 Record
.connect(self
.sink
, data_fifo
.sink
),
401 data_fifo
.sink
.stb
.eq(self
.sink
.stb
& cmd_fifo
.sink
.ack
),
402 self
.sink
.ack
.eq(data_fifo
.sink
.ack
& cmd_fifo
.sink
.ack
),
406 self
.fsm
= fsm
= FSM(reset_state
="IDLE")
407 self
.submodules
+= fsm
409 If(cmd_fifo
.source
.stb
,
410 NextState("SEEK_SOP")
414 If(~data_fifo
.source
.sop
,
415 data_fifo
.source
.ack
.eq(1)
420 if hasattr(source
, "error"):
421 source_error
= self
.source
.error
423 source_error
= Signal()
426 Record
.connect(data_fifo
.source
, self
.source
),
427 source_error
.eq(cmd_fifo
.source
.error
),
428 If(source_status
.done
,
429 cmd_fifo
.source
.ack
.eq(1),
434 # compute almost full
435 if almost_full
is not None:
436 self
.almost_full
= Signal()
437 self
.comb
+= self
.almost_full
.eq(data_fifo
.fifo
.level
> almost_full
)