84fd81773a6f7b9143cb64b9e68c25bd31596eed
[litex.git] / liteeth / ip / __init__.py
1 from liteeth.common import *
2 from liteeth.generic.depacketizer import LiteEthDepacketizer
3 from liteeth.generic.packetizer import LiteEthPacketizer
4
5 class LiteEthIPV4Depacketizer(LiteEthDepacketizer):
6 def __init__(self):
7 LiteEthDepacketizer.__init__(self,
8 eth_mac_description(8),
9 eth_ipv4_description(8),
10 ipv4_header,
11 ipv4_header_len)
12
13 class LiteEthIPV4Packetizer(LiteEthPacketizer):
14 def __init__(self):
15 LiteEthPacketizer.__init__(self,
16 eth_ipv4_description(8),
17 eth_mac_description(8),
18 ipv4_header,
19 ipv4_header_len)
20
21 class LiteEthIPV4Checksum(Module):
22 def __init__(self, skip_header=False):
23 self.header = Signal(ipv4_header_len*8)
24 self.value = Signal(16)
25
26 s = Signal(17)
27 r = Signal(17)
28 for i in range(ipv4_header_len//2):
29 if skip_header and i == 5:
30 pass
31 else:
32 s_next = Signal(17)
33 r_next = Signal(17)
34 self.comb += [
35 s_next.eq(r + self.header[i*16:(i+1)*16]),
36 r_next.eq(Cat(s_next[:16]+s_next[16], Signal()))
37 ]
38 s, r = s_next, r_next
39 self.comb += self.value.eq(~Cat(r[8:16], r[:8]))
40
41 class LiteEthIPTX(Module):
42 def __init__(self, mac_address, ip_address, arp_table):
43 self.sink = Sink(eth_ipv4_user_description(8))
44 self.source = Source(eth_mac_description(8))
45 ###
46 packetizer = LiteEthIPV4Packetizer()
47 self.submodules += packetizer
48 self.comb += [
49 packetizer.sink.stb.eq(self.sink.stb),
50 packetizer.sink.sop.eq(self.sink.sop),
51 packetizer.sink.eop.eq(self.sink.eop),
52 self.sink.eq(packetizer.sink.ack),
53 packetizer.sink.destination_ip_address.eq(ip_address),
54 packetizer.sink.protocol.eq(self.sink.protocol),
55 packetizer.sink.total_length.eq(self.sink.length + (0x5*4)),
56 packetizer.sink.version.eq(0x4), # ipv4
57 packetizer.sink.ihl.eq(0x5), # 20 bytes
58 packetizer.sink.dscp.eq(0),
59 packetizer.sink.ecn.eq(0),
60 packetizer.sink.identification.eq(0),
61 packetizer.sink.flags.eq(0),
62 packetizer.sink.fragment_offset.eq(0),
63 packetizer.sink.time_to_live.eq(0x80),
64 packetizer.sink.source_ip_address.eq(ip_address)
65 ]
66 sink = packetizer.source
67
68 checksum = LiteEthIPV4Checksum(skip_header=True)
69 self.submodules += checksum
70 self.comb += [
71 checksum.header.eq(packetizer.header),
72 packetizer.sink.header_checksum.eq(checksum.value)
73 ]
74
75 destination_mac_address = Signal(48)
76
77 fsm = FSM(reset_state="IDLE")
78 self.submodules += fsm
79 fsm.act("IDLE",
80 sink.ack.eq(1),
81 If(sink.stb & sink.sop,
82 sink.ack.eq(0),
83 NextState("SEND_MAC_ADDRESS_REQUEST")
84 )
85 )
86 fsm.act("SEND_MAC_ADDRESS_REQUEST",
87 arp_table.request.stb.eq(1),
88 arp_table.request.ip_address.eq(self.sink.ip_address),
89 If(arp_table.request.stb & arp_table.request.ack,
90 NextState("WAIT_MAC_ADDRESS_RESPONSE")
91 )
92 )
93 fsm.act("WAIT_MAC_ADDRESS_RESPONSE",
94 # XXX add timeout
95 If(arp_table.response.stb,
96 arp_table.response.ack.eq(1),
97 # XXX manage failed
98 NextState("SEND")
99 )
100 )
101 self.sync += If(arp_table.response.stb, destination_mac_address.eq(arp_table.response.mac_address))
102 fsm.act("SEND",
103 Record.connect(packetizer.source, self.source),
104 self.source.ethernet_type.eq(ethernet_type_ip),
105 self.source.destination_mac_address.eq(destination_mac_address),
106 self.source.source_mac_address.eq(mac_address),
107 # XXX compute check sum
108 If(self.source.stb & self.source.eop & self.source.ack,
109 # XXX manage failed
110 NextState("IDLE")
111 )
112 )
113
114 class LiteEthIPRX(Module):
115 def __init__(self, mac_address, ip_address):
116 self.sink = Sink(eth_mac_description(8))
117 self.source = source = Source(eth_ipv4_user_description(8))
118 ###
119 depacketizer = LiteEthIPV4Depacketizer()
120 self.submodules += depacketizer
121 self.comb += Record.connect(self.sink, depacketizer.sink)
122 sink = depacketizer.source
123
124 fsm = FSM(reset_state="IDLE")
125 self.submodules += fsm
126 fsm.act("IDLE",
127 sink.ack.eq(1),
128 If(sink.stb & sink.sop,
129 sink.ack.eq(0),
130 NextState("CHECK")
131 )
132 )
133 valid = Signal()
134 self.comb += valid.eq(1) # XXX FIXME
135 fsm.act("CHECK",
136 If(valid,
137 NextState("PRESENT")
138 ).Else(
139 NextState("DROP")
140 )
141 ),
142 fsm.act("PRESENT",
143 source.stb.eq(sink.stb),
144 source.sop.eq(sink.sop),
145 source.eop.eq(sink.eop),
146 sink.ack.eq(source.ack),
147 source.length.eq(sink.total_length - (sink.ihl*4)),
148 source.protocol.eq(sink.protocol),
149 source.ip_address.eq(sink.destination_ip_address),
150 source.data.eq(sink.data),
151 source.error.eq(sink.error),
152 If(source.stb & source.eop & source.ack,
153 NextState("IDLE")
154 )
155 )
156 fsm.act("DROP",
157 sink.ack.eq(1),
158 If(source.stb & source.eop & source.ack,
159 NextState("IDLE")
160 )
161 )
162
163 class LiteEthIP(Module):
164 def __init__(self, mac, mac_address, ip_address, arp_table):
165 self.submodules.tx = LiteEthIPTX(mac_address, ip_address, arp_table)
166 self.submodules.rx = LiteEthIPRX(mac_address, ip_address)
167 mac_port = mac.crossbar.get_port(ethernet_type_ip)
168 self.comb += [
169 Record.connect(self.tx.source, mac_port.sink),
170 Record.connect(mac_port.source, self.rx.sink)
171 ]
172 self.sink, self.source = self.tx.sink, self.rx.source