arp: rx and decoding OK
[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 def reverse_bytes(v):
81 n = math.ceil(flen(v)//8)
82 r = []
83 for i in reversed(range(n)):
84 r.append(v[i*8:min((i+1)*8, flen(v))])
85 return Cat(iter(r))
86
87 # layouts
88 def _layout_from_header(header):
89 _layout = []
90 for k, v in sorted(header.items()):
91 _layout.append((k, v.width))
92 return _layout
93
94 def eth_phy_description(dw):
95 layout = [
96 ("data", dw),
97 ("last_be", dw//8),
98 ("error", dw//8)
99 ]
100 return EndpointDescription(layout, packetized=True)
101
102 def eth_mac_description(dw):
103 layout = _layout_from_header(mac_header) + [
104 ("data", dw),
105 ("last_be", dw//8),
106 ("error", dw//8)
107 ]
108 return EndpointDescription(layout, packetized=True)
109
110 def eth_arp_description(dw):
111 layout = _layout_from_header(arp_header) + [
112 ("data", dw),
113 ("error", dw//8)
114 ]
115 return EndpointDescription(layout, packetized=True)
116
117 def eth_ipv4_description(dw):
118 layout = _layout_from_header(ipv4_header) + [
119 ("data", dw),
120 ("error", dw//8)
121 ]
122 return EndpointDescription(layout, packetized=True)
123
124 def eth_udp_description(dw):
125 layout = _layout_from_header(udp_header) + [
126 ("data", dw),
127 ("error", dw//8)
128 ]
129 return EndpointDescription(layout, packetized=True)
130
131 # Generic modules
132 @DecorateModule(InsertReset)
133 @DecorateModule(InsertCE)
134 class Counter(Module):
135 def __init__(self, signal=None, **kwargs):
136 if signal is None:
137 self.value = Signal(**kwargs)
138 else:
139 self.value = signal
140 self.width = flen(self.value)
141 self.sync += self.value.eq(self.value+1)
142
143 @DecorateModule(InsertReset)
144 @DecorateModule(InsertCE)
145 class Timeout(Module):
146 def __init__(self, length):
147 self.reached = Signal()
148 ###
149 value = Signal(max=length)
150 self.sync += value.eq(value+1)
151 self.comb += self.reached.eq(value == length)
152
153 class BufferizeEndpoints(ModuleDecorator):
154 def __init__(self, submodule, *args):
155 ModuleDecorator.__init__(self, submodule)
156
157 endpoints = get_endpoints(submodule)
158 sinks = {}
159 sources = {}
160 for name, endpoint in endpoints.items():
161 if name in args or len(args) == 0:
162 if isinstance(endpoint, Sink):
163 sinks.update({name : endpoint})
164 elif isinstance(endpoint, Source):
165 sources.update({name : endpoint})
166
167 # add buffer on sinks
168 for name, sink in sinks.items():
169 buf = Buffer(sink.description)
170 self.submodules += buf
171 setattr(self, name, buf.d)
172 self.comb += Record.connect(buf.q, sink)
173
174 # add buffer on sources
175 for name, source in sources.items():
176 buf = Buffer(source.description)
177 self.submodules += buf
178 self.comb += Record.connect(source, buf.d)
179 setattr(self, name, buf.q)
180