mac: add packetizer/depacketizer (untested)
[litex.git] / liteeth / common.py
1 from collections import OrderedDict
2
3 from migen.fhdl.std import *
4 from migen.fhdl.std import *
5 from migen.genlib.resetsync import AsyncResetSynchronizer
6 from migen.genlib.record import *
7 from migen.genlib.fsm import FSM, NextState
8 from migen.genlib.misc import chooser
9 from migen.flow.actor import EndpointDescription
10 from migen.flow.actor import Sink, Source
11 from migen.actorlib.structuring import Converter, Pipeline
12 from migen.actorlib.fifo import SyncFIFO, AsyncFIFO
13 from migen.bank.description import *
14
15 eth_mtu = 1532
16 eth_preamble = 0xD555555555555555
17 buffer_depth = 2**log2_int(eth_mtu, need_pow2=False)
18
19 class HField():
20 def __init__(self, byte, offset, width):
21 self.byte = byte
22 self.offset = offset
23 self.width = width
24
25 mac_header_len = 14
26 mac_header = {
27 "destination_mac_address": HField(0, 0, 48),
28 "source_mac_address": HField(6, 0, 48),
29 "ethernet_type": HField(12, 0, 16)
30 }
31
32 arp_header_len = 28
33 arp_header = {
34 "hardware_type": HField( 0, 0, 16),
35 "protocol_type": HField( 2, 0, 16),
36 "hardware_address_length": HField( 4, 0, 8),
37 "protocol_address_length": HField( 5, 0, 8),
38 "operation": HField( 6, 0, 16),
39 "source_mac_address": HField( 8, 0, 48),
40 "source_ip_address": HField(14, 0, 32),
41 "destination_mac_address": HField(18, 0, 48),
42 "destination_ip_address": HField(24, 0, 32)
43 }
44
45 ipv4_header_len = 24
46 ipv4_header = {
47 "version": HField(0, 0, 4),
48 "ihl": HField(0, 4, 4),
49 "dscp": HField(1, 0, 6),
50 "ecn": HField(1, 6, 2),
51 "total_length": HField(2, 0, 16),
52 "identification": HField(4, 0, 16),
53 "flags": HField(6, 0, 3),
54 "fragment_offset": HField(6, 3, 13),
55 "time_to_live": HField(8, 0, 8),
56 "protocol": HField(9, 0, 8),
57 "header_checksum": HField(10, 0, 16),
58 "source_ip_address": HField(12, 0, 32),
59 "destination_ip_address": HField(16, 0, 32),
60 "options": HField(20, 0, 32)
61 }
62 udp_header_len = 8
63 udp_header = {
64 "source_port": HField( 0, 0, 16),
65 "destination_port": HField( 2, 0, 16),
66 "length": HField( 4, 0, 16),
67 "checksum": HField( 6, 0, 16)
68 }
69
70 # layouts
71 def _layout_from_header(header):
72 _layout = []
73 for k, v in sorted(header.items()):
74 _layout.append((k, v.width))
75 return _layout
76
77 def eth_phy_description(dw):
78 layout = [
79 ("data", dw),
80 ("last_be", dw//8),
81 ("error", dw//8)
82 ]
83 return EndpointDescription(layout, packetized=True)
84
85 def eth_mac_description(dw):
86 layout = _layout_from_header(mac_header) + [
87 ("data", dw),
88 ("last_be", dw//8),
89 ("error", dw//8)
90 ]
91 return EndpointDescription(layout, packetized=True)
92
93 def eth_arp_description(dw):
94 layout = _layout_from_header(arp_header) + [
95 ("data", dw),
96 ("error", dw//8)
97 ]
98 return EndpointDescription(layout, packetized=True)
99
100 def eth_ipv4_description(dw):
101 layout = _layout_from_header(ipv4_header) + [
102 ("data", dw),
103 ("error", dw//8)
104 ]
105 return EndpointDescription(layout, packetized=True)
106
107 def eth_udp_description(dw):
108 layout = _layout_from_header(udp_header) + [
109 ("data", dw),
110 ("error", dw//8)
111 ]
112 return EndpointDescription(layout, packetized=True)
113
114 # Generic modules
115 @DecorateModule(InsertReset)
116 @DecorateModule(InsertCE)
117 class Counter(Module):
118 def __init__(self, signal=None, **kwargs):
119 if signal is None:
120 self.value = Signal(**kwargs)
121 else:
122 self.value = signal
123 self.width = flen(self.value)
124 self.sync += self.value.eq(self.value+1)
125
126 @DecorateModule(InsertReset)
127 @DecorateModule(InsertCE)
128 class Timeout(Module):
129 def __init__(self, length):
130 self.reached = Signal()
131 ###
132 value = Signal(max=length)
133 self.sync += value.eq(value+1)
134 self.comb += self.reached.eq(value == length)
135
136 class BufferizeEndpoints(ModuleDecorator):
137 def __init__(self, submodule, *args):
138 ModuleDecorator.__init__(self, submodule)
139
140 endpoints = get_endpoints(submodule)
141 sinks = {}
142 sources = {}
143 for name, endpoint in endpoints.items():
144 if name in args or len(args) == 0:
145 if isinstance(endpoint, Sink):
146 sinks.update({name : endpoint})
147 elif isinstance(endpoint, Source):
148 sources.update({name : endpoint})
149
150 # add buffer on sinks
151 for name, sink in sinks.items():
152 buf = Buffer(sink.description)
153 self.submodules += buf
154 setattr(self, name, buf.d)
155 self.comb += Record.connect(buf.q, sink)
156
157 # add buffer on sources
158 for name, source in sources.items():
159 buf = Buffer(source.description)
160 self.submodules += buf
161 self.comb += Record.connect(source, buf.d)
162 setattr(self, name, buf.q)