ip: add skeleton
[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 arp_table_request_layout = [
118 ("ip_address", 32)
119 ]
120
121 arp_table_response_layout = [
122 ("failed", 1),
123 ("mac_address", 48)
124 ]
125
126 def eth_ipv4_description(dw):
127 layout = _layout_from_header(ipv4_header) + [
128 ("data", dw),
129 ("error", dw//8)
130 ]
131 return EndpointDescription(layout, packetized=True)
132
133 def eth_udp_description(dw):
134 layout = _layout_from_header(udp_header) + [
135 ("data", dw),
136 ("error", dw//8)
137 ]
138 return EndpointDescription(layout, packetized=True)
139
140 # Generic modules
141 @DecorateModule(InsertReset)
142 @DecorateModule(InsertCE)
143 class FlipFlop(Module):
144 def __init__(self, **kwargs):
145 self.d = Signal(**kwargs)
146 self.q = Signal(**kwargs)
147 self.sync += self.q.eq(self.d)
148
149 @DecorateModule(InsertReset)
150 @DecorateModule(InsertCE)
151 class Counter(Module):
152 def __init__(self, signal=None, **kwargs):
153 if signal is None:
154 self.value = Signal(**kwargs)
155 else:
156 self.value = signal
157 self.width = flen(self.value)
158 self.sync += self.value.eq(self.value+1)
159
160 @DecorateModule(InsertReset)
161 @DecorateModule(InsertCE)
162 class Timeout(Module):
163 def __init__(self, length):
164 self.reached = Signal()
165 ###
166 value = Signal(max=length)
167 self.sync += If(~self.reached, value.eq(value+1))
168 self.comb += self.reached.eq(value == (length-1))
169
170 class BufferizeEndpoints(ModuleDecorator):
171 def __init__(self, submodule, *args):
172 ModuleDecorator.__init__(self, submodule)
173
174 endpoints = get_endpoints(submodule)
175 sinks = {}
176 sources = {}
177 for name, endpoint in endpoints.items():
178 if name in args or len(args) == 0:
179 if isinstance(endpoint, Sink):
180 sinks.update({name : endpoint})
181 elif isinstance(endpoint, Source):
182 sources.update({name : endpoint})
183
184 # add buffer on sinks
185 for name, sink in sinks.items():
186 buf = Buffer(sink.description)
187 self.submodules += buf
188 setattr(self, name, buf.d)
189 self.comb += Record.connect(buf.q, sink)
190
191 # add buffer on sources
192 for name, source in sources.items():
193 buf = Buffer(source.description)
194 self.submodules += buf
195 self.comb += Record.connect(source, buf.d)
196 setattr(self, name, buf.q)
197