udpip_tb: able to send valid UDP msg to model
[litex.git] / liteeth / core / ip.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.ack.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 packetizer.sink.data.eq(self.sink.data)
66 ]
67 sink = packetizer.source
68
69 checksum = LiteEthIPV4Checksum(skip_header=True)
70 self.submodules += checksum
71 self.comb += [
72 checksum.header.eq(packetizer.header),
73 packetizer.sink.header_checksum.eq(checksum.value)
74 ]
75
76 destination_mac_address = Signal(48)
77
78 fsm = FSM(reset_state="IDLE")
79 self.submodules += fsm
80 fsm.act("IDLE",
81 sink.ack.eq(1),
82 If(sink.stb & sink.sop,
83 sink.ack.eq(0),
84 NextState("SEND_MAC_ADDRESS_REQUEST")
85 )
86 )
87 fsm.act("SEND_MAC_ADDRESS_REQUEST",
88 arp_table.request.stb.eq(1),
89 arp_table.request.ip_address.eq(self.sink.ip_address),
90 If(arp_table.request.stb & arp_table.request.ack,
91 NextState("WAIT_MAC_ADDRESS_RESPONSE")
92 )
93 )
94 fsm.act("WAIT_MAC_ADDRESS_RESPONSE",
95 # XXX add timeout
96 If(arp_table.response.stb,
97 arp_table.response.ack.eq(1),
98 # XXX manage failed
99 NextState("SEND")
100 )
101 )
102 self.sync += If(arp_table.response.stb, destination_mac_address.eq(arp_table.response.mac_address))
103 fsm.act("SEND",
104 Record.connect(packetizer.source, self.source),
105 self.source.ethernet_type.eq(ethernet_type_ip),
106 self.source.destination_mac_address.eq(destination_mac_address),
107 self.source.source_mac_address.eq(mac_address),
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 checksum = LiteEthIPV4Checksum(skip_header=False)
125 self.submodules += checksum
126 self.comb += checksum.header.eq(depacketizer.header)
127
128 fsm = FSM(reset_state="IDLE")
129 self.submodules += fsm
130 fsm.act("IDLE",
131 sink.ack.eq(1),
132 If(sink.stb & sink.sop,
133 sink.ack.eq(0),
134 NextState("CHECK")
135 )
136 )
137 valid = Signal()
138 self.comb += valid.eq(
139 sink.stb &
140 (sink.destination_ip_address == ip_address) &
141 (sink.version == 0x4) &
142 (sink.ihl == 0x5) &
143 (checksum.value == 0)
144 )
145
146 fsm.act("CHECK",
147 If(valid,
148 NextState("PRESENT")
149 ).Else(
150 NextState("DROP")
151 )
152 ),
153 fsm.act("PRESENT",
154 source.stb.eq(sink.stb),
155 source.sop.eq(sink.sop),
156 source.eop.eq(sink.eop),
157 sink.ack.eq(source.ack),
158 source.length.eq(sink.total_length - (sink.ihl*4)),
159 source.protocol.eq(sink.protocol),
160 source.ip_address.eq(sink.destination_ip_address),
161 source.data.eq(sink.data),
162 source.error.eq(sink.error),
163 If(source.stb & source.eop & source.ack,
164 NextState("IDLE")
165 )
166 )
167 fsm.act("DROP",
168 sink.ack.eq(1),
169 If(source.stb & source.eop & source.ack,
170 NextState("IDLE")
171 )
172 )
173
174 class LiteEthIP(Module):
175 def __init__(self, mac, mac_address, ip_address, arp_table):
176 self.submodules.tx = LiteEthIPTX(mac_address, ip_address, arp_table)
177 self.submodules.rx = LiteEthIPRX(mac_address, ip_address)
178 mac_port = mac.crossbar.get_port(ethernet_type_ip)
179 self.comb += [
180 Record.connect(self.tx.source, mac_port.sink),
181 Record.connect(mac_port.source, self.rx.sink)
182 ]
183 self.sink, self.source = self.tx.sink, self.rx.source