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