add arp_tb and fixes (able to send a valid ARP request to the model)
authorFlorent Kermarrec <florent@enjoy-digital.fr>
Thu, 29 Jan 2015 23:03:16 +0000 (00:03 +0100)
committerFlorent Kermarrec <florent@enjoy-digital.fr>
Thu, 29 Jan 2015 23:03:16 +0000 (00:03 +0100)
liteeth/arp/__init__.py
liteeth/generic/depacketizer.py
liteeth/generic/packetizer.py
liteeth/ip/__init__.py
liteeth/mac/__init__.py
liteeth/mac/core/__init__.py
liteeth/test/Makefile
liteeth/test/arp_tb.py [new file with mode: 0644]
liteeth/test/model/arp.py
liteeth/test/model/mac.py
liteeth/udp/__init__.py

index 78a5535c0023d6829035b81315ea695a098bbf6b..96d415c51ec2203e12aa4d58ea262da08538d90a 100644 (file)
@@ -17,15 +17,15 @@ class LiteEthARPDepacketizer(LiteEthDepacketizer):
                        eth_mac_description(8),
                        eth_arp_description(8),
                        arp_header,
-                       arp_header_length)
+                       arp_header_len)
 
-class LiteEthARPPacketizer(LiteEthDepacketizer):
+class LiteEthARPPacketizer(LiteEthPacketizer):
        def __init__(self):
-               LiteEthDepacketizer.__init__(self,
+               LiteEthPacketizer.__init__(self,
                        eth_arp_description(8),
                        eth_mac_description(8),
                        arp_header,
-                       arp_header_length)
+                       arp_header_len)
 
 class LiteSATACommandTX(Module):
        def __init__(self, transport):
@@ -37,15 +37,20 @@ class LiteEthARPTX(Module):
                self.sink = sink = Sink(_arp_table_description())
                self.source = Source(eth_mac_description(8))
                ###
-               packetiser = LiteEthARPPacketizer()
+               packetizer = LiteEthARPPacketizer()
                self.submodules += packetizer
                source = packetizer.sink
 
+               counter = Counter(max=arp_packet_length)
+               self.submodules += counter
+
                fsm = FSM(reset_state="IDLE")
                self.submodules += fsm
                fsm.act("IDLE",
                        sink.ack.eq(1),
-                       If(sink.stb & sink.sop,
+                       counter.reset.eq(1),
+                       If(sink.stb,
+                               sink.ack.eq(0),
                                NextState("SEND")
                        )
                )
@@ -66,11 +71,20 @@ class LiteEthARPTX(Module):
                                source.destination_ip_address.eq(sink.ip_address)
                        )
                ]
-               fsm.act("SEND_REQUEST",
+               fsm.act("SEND",
                        source.stb.eq(1),
+                       source.sop.eq(counter.value == 0),
+                       source.eop.eq(counter.value == arp_packet_length-1),
                        Record.connect(packetizer.source, self.source),
-                       If(self.source.stb & self.source.eop & self.source.ack,
-                               NextState("IDLE")
+                       self.source.destination_mac_address.eq(source.destination_mac_address),
+                       self.source.source_mac_address.eq(mac_address),
+                       self.source.ethernet_type.eq(ethernet_type_arp),
+                       If(self.source.stb & self.source.ack,
+                               sink.ack.eq(1),
+                               counter.ce.eq(1),
+                               If(self.source.eop,
+                                       NextState("IDLE")
+                               )
                        )
                )
 
@@ -79,7 +93,7 @@ class LiteEthARPRX(Module):
                self.sink = Sink(eth_mac_description(8))
                self.source = source = Source(_arp_table_description())
                ###
-               depacketiser = LiteEthARPDepacketizer()
+               depacketizer = LiteEthARPDepacketizer()
                self.submodules += depacketizer
                self.comb += Record.connect(self.sink, depacketizer.sink)
                sink = depacketizer.source
@@ -118,11 +132,11 @@ class LiteEthARPRX(Module):
                                source.reply.eq(reply),
                                source.request.eq(request)
                        ),
-                       NextState.eq("TERMINATE")
+                       NextState("TERMINATE")
                ),
                fsm.act("TERMINATE",
                        sink.ack.eq(1),
-                       If(sink.stb & sink.source.eop & sink.source.ack,
+                       If(sink.stb & sink.eop,
                                NextState("IDLE")
                        )
                )
@@ -173,9 +187,9 @@ class LiteEthARPTable(Module):
                fsm.act("CHECK_TABLE",
                        # XXX add a kind of CAM?
                        If(found,
-                               NexState.eq("PRESENT_RESPONSE")
+                               NextState("PRESENT_RESPONSE")
                        ).Else(
-                               NextState.eq("SEND_REQUEST")
+                               NextState("SEND_REQUEST")
                        )
                )
                fsm.act("SEND_REQUEST",
index ff7308a47a2cc52831d58053aaa464cf99afb908..e4525a0c5bfeeba8cb007f8475a8d9bc996c833b 100644 (file)
@@ -46,7 +46,6 @@ class LiteEthDepacketizer(Module):
                                source.sop.eq(0)
                        )
                self.comb += [
-                       source.sop.eq(sop),
                        source.eop.eq(sink.eop),
                        source.data.eq(sink.data),
                        source.error.eq(sink.error),
index c10ff9366a521dbc61e37c4ba2e94599aa40c97a..2aa161ef4426850922cfc8bcdf36c44cf4f4808a 100644 (file)
@@ -1,11 +1,19 @@
 from liteeth.common import *
+import math
+
+def reverse_bytes(v):
+       n = math.ceil(flen(v)//8)
+       r = []
+       for i in reversed(range(n)):
+               r.append(v[i*8:min((i+1)*8, flen(v))])
+       return Cat(iter(r))
 
 def _encode_header(h_dict, h_signal, obj):
        r = []
        for k, v in sorted(h_dict.items()):
-               start = v.word*32+v.offset
+               start = v.byte*8+v.offset
                end = start+v.width
-               r.append(h_signal[start:end].eq(getattr(obj, k)))
+               r.append(h_signal[start:end].eq(reverse_bytes(getattr(obj, k))))
        return r
 
 class LiteEthPacketizer(Module):
@@ -20,7 +28,7 @@ class LiteEthPacketizer(Module):
                counter = Counter(max=header_length)
                self.submodules += counter
 
-               self.comb += header.eq(_encode_header(header_type, header, sink))
+               self.comb += _encode_header(header_type, header, sink)
                self.sync += [
                        If(load,
                                header_reg.eq(header)
@@ -34,14 +42,15 @@ class LiteEthPacketizer(Module):
 
                fsm.act("IDLE",
                        sink.ack.eq(1),
+                       counter.reset.eq(1),
                        If(sink.stb & sink.sop,
-                               load.eq(1),
                                sink.ack.eq(0),
                                source.stb.eq(1),
                                source.sop.eq(1),
                                source.eop.eq(0),
                                source.data.eq(header[:8]),
                                If(source.stb & source.ack,
+                                       load.eq(1),
                                        NextState("SEND_HEADER"),
                                )
                        )
@@ -52,8 +61,9 @@ class LiteEthPacketizer(Module):
                        source.eop.eq(sink.eop),
                        source.data.eq(header_reg[8:16]),
                        If(source.stb & source.ack,
-                               sink.ack.eq(1),
-                               If(counter == header_length-2,
+                               shift.eq(1),
+                               counter.ce.eq(1),
+                               If(counter.value == header_length-2,
                                        NextState("COPY")
                                )
                        )
@@ -61,7 +71,7 @@ class LiteEthPacketizer(Module):
                fsm.act("COPY",
                        source.stb.eq(sink.stb),
                        source.sop.eq(0),
-                       source.eop.eq(sink_eop),
+                       source.eop.eq(sink.eop),
                        source.data.eq(sink.data),
                        source.error.eq(sink.error),
                        If(source.stb & source.ack,
index 3dbc7c016d4bce13ec184f5b2b3aed08c6e45e64..55030397be42804db84ea0ec4852ab01e2ba7f5e 100644 (file)
@@ -8,12 +8,12 @@ class LiteEthIPV4Depacketizer(LiteEthDepacketizer):
                        eth_mac_description(8),
                        eth_ipv4_description(8),
                        ipv4_header,
-                       ipv4_header_length)
+                       ipv4_header_len)
 
-class LiteEthIPV4Packetizer(LiteEthDepacketizer):
+class LiteEthIPV4Packetizer(LiteEthPacketizer):
        def __init__(self):
-               LiteEthDepacketizer.__init__(self,
+               LiteEthPacketizer.__init__(self,
                        eth_ipv4_description(8),
                        eth_mac_description(8),
                        ipv4_header,
-                       ipv4_header_length)
+                       ipv4_header_len)
index 510faa77a4b9bce44b4d2c1b3780b71ff7925adf..320f32b106863cf13001dcf51715e09a3cd19ae2 100644 (file)
@@ -10,15 +10,15 @@ class LiteEthMACDepacketizer(LiteEthDepacketizer):
                        eth_phy_description(8),
                        eth_mac_description(8),
                        mac_header,
-                       mac_header_length)
+                       mac_header_len)
 
-class LiteEthMACPacketizer(LiteEthDepacketizer):
+class LiteEthMACPacketizer(LiteEthPacketizer):
        def __init__(self):
-               LiteEthDepacketizer.__init__(self,
+               LiteEthPacketizer.__init__(self,
                        eth_mac_description(8),
                        eth_phy_description(8),
                        mac_header,
-                       mac_header_length)
+                       mac_header_len)
 
 class LiteEthMAC(Module, AutoCSR):
        def __init__(self, phy, dw, interface="mac", endianness="be",
@@ -34,6 +34,7 @@ class LiteEthMAC(Module, AutoCSR):
                                Record.connect(self.core.source, depacketizer.sink)
                        ]
                        self.sink, self.source = packetizer.sink, depacketizer.source
+                       pass
                elif interface == "wishbone":
                        self.submodules.interface = wishbone.LiteEthMACWishboneInterface(dw, 2, 2)
                        self.comb += [
index 2967e0b58869fa27a97443832a4033d2b8a1c1af..e8fa5a27768b988954487e32cb79028b3b4e2ff1 100644 (file)
@@ -6,6 +6,10 @@ class LiteEthMACCore(Module, AutoCSR):
        def __init__(self, phy, dw, endianness="be", with_hw_preamble_crc=True):
                if dw < phy.dw:
                        raise ValueError("Core data width({}) must be larger than PHY data width({})".format(dw, phy.dw))
+
+               rx_pipeline = [phy]
+               tx_pipeline = [phy]
+
                # Preamble / CRC (optional)
                if with_hw_preamble_crc:
                        self._hw_preamble_crc = CSRStatus(reset=1)
@@ -21,18 +25,25 @@ class LiteEthMACCore(Module, AutoCSR):
                        self.submodules += RenameClockDomains(crc32_inserter, "eth_tx")
                        self.submodules += RenameClockDomains(crc32_checker, "eth_rx")
 
-               # Delimiters
-               tx_last_be = last_be.LiteEthMACTXLastBE(phy.dw)
-               rx_last_be = last_be.LiteEthMACRXLastBE(phy.dw)
-               self.submodules += RenameClockDomains(tx_last_be, "eth_tx")
-               self.submodules += RenameClockDomains(rx_last_be, "eth_rx")
+                       tx_pipeline += [preamble_inserter, crc32_inserter]
+                       rx_pipeline += [preamble_checker, crc32_checker]
+
+               if dw != phy.dw:
+                       # Delimiters
+                       tx_last_be = last_be.LiteEthMACTXLastBE(phy.dw)
+                       rx_last_be = last_be.LiteEthMACRXLastBE(phy.dw)
+                       self.submodules += RenameClockDomains(tx_last_be, "eth_tx")
+                       self.submodules += RenameClockDomains(rx_last_be, "eth_rx")
 
-               # Converters
-               reverse = endianness == "be"
-               tx_converter = Converter(eth_phy_description(dw), eth_phy_description(phy.dw), reverse=reverse)
-               rx_converter = Converter(eth_phy_description(phy.dw), eth_phy_description(dw), reverse=reverse)
-               self.submodules += RenameClockDomains(tx_converter, "eth_tx")
-               self.submodules += RenameClockDomains(rx_converter, "eth_rx")
+                       # Converters
+                       reverse = endianness == "be"
+                       tx_converter = Converter(eth_phy_description(dw), eth_phy_description(phy.dw), reverse=reverse)
+                       rx_converter = Converter(eth_phy_description(phy.dw), eth_phy_description(dw), reverse=reverse)
+                       self.submodules += RenameClockDomains(tx_converter, "eth_tx")
+                       self.submodules += RenameClockDomains(rx_converter, "eth_rx")
+
+                       tx_pipeline += [tx_last_be, tx_converter]
+                       rx_pipeline += [rx_last_be, rx_converter]
 
                # Cross Domain Crossing
                tx_cdc = AsyncFIFO(eth_phy_description(dw), 4)
@@ -40,14 +51,11 @@ class LiteEthMACCore(Module, AutoCSR):
                self.submodules +=  RenameClockDomains(tx_cdc, {"write": "sys", "read": "eth_tx"})
                self.submodules +=  RenameClockDomains(rx_cdc, {"write": "eth_rx", "read": "sys"})
 
+               tx_pipeline += [tx_cdc]
+               rx_pipeline += [rx_cdc]
+
                # Graph
-               if with_hw_preamble_crc:
-                       rx_pipeline = [phy, preamble_checker, crc32_checker, rx_last_be, rx_converter, rx_cdc]
-                       tx_pipeline = [tx_cdc, tx_converter, tx_last_be, crc32_inserter, preamble_inserter, phy]
-               else:
-                       rx_pipeline = [phy, rx_last_be, rx_converter, rx_cdc]
-                       tx_pipeline = [tx_cdc, tx_converter, tx_last_be, phy]
+               self.submodules.tx_pipeline = Pipeline(*reversed(tx_pipeline))
                self.submodules.rx_pipeline = Pipeline(*rx_pipeline)
-               self.submodules.tx_pipeline = Pipeline(*tx_pipeline)
 
                self.sink, self.source = self.tx_pipeline.sink, self.rx_pipeline.source
index 7d2283c85059be2957ff7c514c372909ded09e3d..f7cfac6310dd64a839f1492164f8131d492afa1f 100644 (file)
@@ -12,3 +12,6 @@ mac_core_tb:
 
 mac_wishbone_tb:
        $(CMD) mac_wishbone_tb.py
+
+arp_tb:
+       $(CMD) arp_tb.py
diff --git a/liteeth/test/arp_tb.py b/liteeth/test/arp_tb.py
new file mode 100644 (file)
index 0000000..b4629c8
--- /dev/null
@@ -0,0 +1,54 @@
+from migen.fhdl.std import *
+from migen.bus import wishbone
+from migen.bus.transactions import *
+from migen.sim.generic import run_simulation
+
+from liteeth.common import *
+from liteeth.mac import LiteEthMAC
+from liteeth.arp import LiteEthARP
+
+from liteeth.test.common import *
+from liteeth.test.model import phy, mac, arp
+
+ip_address = 0x12345678
+mac_address = 0x12345678abcd
+
+class TB(Module):
+       def __init__(self):
+               self.submodules.phy_model = phy.PHY(8, debug=True)
+               self.submodules.mac_model = mac.MAC(self.phy_model, debug=True, loopback=False)
+               self.submodules.arp_model = arp.ARP(self.mac_model, mac_address, ip_address, debug=True)
+
+               self.submodules.core = LiteEthMAC(phy=self.phy_model, dw=8, with_hw_preamble_crc=True)
+               self.submodules.arp = LiteEthARP(mac_address, ip_address)
+
+               # use sys_clk for each clock_domain
+               self.clock_domains.cd_eth_rx = ClockDomain()
+               self.clock_domains.cd_eth_tx = ClockDomain()
+               self.comb += [
+                       self.cd_eth_rx.clk.eq(ClockSignal()),
+                       self.cd_eth_rx.rst.eq(ResetSignal()),
+                       self.cd_eth_tx.clk.eq(ClockSignal()),
+                       self.cd_eth_tx.rst.eq(ResetSignal()),
+               ]
+
+               self.comb += [
+                       Record.connect(self.arp.source, self.core.sink),
+                       Record.connect(self.core.source, self.arp.sink)
+               ]
+
+       def gen_simulation(self, selfp):
+               selfp.cd_eth_rx.rst = 1
+               selfp.cd_eth_tx.rst = 1
+               yield
+               selfp.cd_eth_rx.rst = 0
+               selfp.cd_eth_tx.rst = 0
+
+               for i in range(100):
+                       yield
+
+               selfp.arp.table.request.ip_address = 0x12345678
+               selfp.arp.table.request.stb = 1
+
+if __name__ == "__main__":
+       run_simulation(TB(), ncycles=256, vcd_name="my.vcd", keep_files=True)
index ef4c27618de2c22e17706a4aad8f560da43ced86..79ac98d0a036df1d0d6dd11ce91107237dec31ee 100644 (file)
@@ -4,6 +4,8 @@ from liteeth.common import *
 from liteeth.mac.common import *
 from liteeth.test.common import *
 
+from liteeth.test.model import mac
+
 def print_arp(s):
        print_with_prefix(s, "[ARP]")
 
@@ -39,10 +41,10 @@ class ARPPacket(Packet):
                return r
 
 class ARP(Module):
-       def  __init__(self, mac, ip_address, mac_address, debug=False):
+       def  __init__(self, mac, mac_address, ip_address, debug=False):
                self.mac = mac
+               self.mac_address = mac_address
                self.ip_address = ip_address
-               self.mac_address = mac_addres
                self.debug = debug
                self.tx_packets = []
                self.tx_packet = ARPPacket()
@@ -53,22 +55,26 @@ class ARP(Module):
                self.mac.set_arp_callback(self.callback)
 
        def send(self, packet):
+               packet.encode()
                if self.debug:
                        print_arp(">>>>>>>>")
                        print_arp(packet)
-               packet.encode()
-               self.mac.send(MACPacket(packet))
+               mac_packet = mac.MACPacket(packet)
+               mac_packet.destination_mac_address = packet.destination_mac_address
+               mac_packet.source_mac_address = packet.source_mac_address
+               mac_packet.ethernet_type = ethernet_type_arp
+               self.mac.send(mac_packet)
 
        def callback(self, packet):
-               packet = ARPPacket(datas)
+               packet = ARPPacket(packet)
                packet.decode()
                if self.debug:
                        print_arp("<<<<<<<<")
                        print_arp(packet)
-               self.process_packet()
+               self.process(packet)
 
        def process(self, packet):
-               if len(packet) != arp_packet_length-arp_header_length:
+               if len(packet) != arp_packet_length-arp_header_len:
                        raise ValueError
                if packet.hardware_type != arp_hwtype_ethernet:
                        raise ValueError
@@ -85,9 +91,10 @@ class ARP(Module):
        
        def process_request(self, request):
                if request.destination_ip_address == self.ip_address:
-                       reply = ARPPacket([0]*(arp_packet_length-arp_header_length))
+                       reply = ARPPacket([0]*(arp_packet_length-arp_header_len))
                        reply.hardware_type = arp_hwtype_ethernet
                        reply.protocol_type = arp_proto_ip
+                       reply.operation = arp_opcode_reply
                        reply.hardware_address_length = 6
                        reply.protocol_address_length = 4
                        reply.source_mac_address = self.mac_address
@@ -100,9 +107,10 @@ class ARP(Module):
                self.table[reply.source_ip_address] = reply.source_mac_address
 
        def request(self, ip_address):
-               request = ARPPacket([0]*(arp_packet_length-arp_header_length))
+               request = ARPPacket([0]*(arp_packet_length-arp_header_len))
                request.hardware_type = arp_hwtype_ethernet
                request.protocol_type = arp_proto_ip
+               request.operation = arp_opcode_request
                request.hardware_address_length = 6
                request.protocol_address_length = 4
                request.source_mac_address = self.mac_address
index 26e4a13ca1d8ed34614c18429633622ec7a8b8c3..74273cb95df9d0531b3a707f57a11b66bdc26d32 100644 (file)
@@ -118,10 +118,10 @@ class MAC(Module):
                if self.loopback:
                        self.send(packet)
                else:
-                       if self.ethernet_type == ethernet_type_ip:
+                       if packet.ethernet_type == ethernet_type_ip:
                                if self.ip_callback is not None:
                                        self.ip_callback(packet)
-                       elif self.ethernet_type == ethernet_type_arp:
+                       elif packet.ethernet_type == ethernet_type_arp:
                                if self.arp_callback is not None:
                                        self.arp_callback(packet)
                        else:
index 9f8b5dafc4f777df842a9e43d37f27d550028531..296abe6d960a873580f77f8bfff9c0a1b018bb69 100644 (file)
@@ -8,12 +8,12 @@ class LiteEthUDPDepacketizer(LiteEthDepacketizer):
                        eth_ipv4_description(8),
                        eth_udp_description(8),
                        udp_header,
-                       udp_header_length)
+                       udp_header_len)
 
-class LiteEthUDPPacketizer(LiteEthDepacketizer):
+class LiteEthUDPPacketizer(LiteEthPacketizer):
        def __init__(self):
-               LiteEthDepacketizer.__init__(self,
+               LiteEthPacketizer.__init__(self,
                        eth_udp_description(8),
                        eth_ipv4_description(8),
                        udp_header,
-                       udp_header_length)
+                       udp_header_len)