From 18a7d66b5e1b4639a0965042d0c132851410e62a Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 30 Jan 2015 00:03:16 +0100 Subject: [PATCH] add arp_tb and fixes (able to send a valid ARP request to the model) --- liteeth/arp/__init__.py | 42 ++++++++++++++++--------- liteeth/generic/depacketizer.py | 1 - liteeth/generic/packetizer.py | 24 ++++++++++----- liteeth/ip/__init__.py | 8 ++--- liteeth/mac/__init__.py | 9 +++--- liteeth/mac/core/__init__.py | 44 ++++++++++++++++----------- liteeth/test/Makefile | 3 ++ liteeth/test/arp_tb.py | 54 +++++++++++++++++++++++++++++++++ liteeth/test/model/arp.py | 26 ++++++++++------ liteeth/test/model/mac.py | 4 +-- liteeth/udp/__init__.py | 8 ++--- 11 files changed, 160 insertions(+), 63 deletions(-) create mode 100644 liteeth/test/arp_tb.py diff --git a/liteeth/arp/__init__.py b/liteeth/arp/__init__.py index 78a5535c..96d415c5 100644 --- a/liteeth/arp/__init__.py +++ b/liteeth/arp/__init__.py @@ -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", diff --git a/liteeth/generic/depacketizer.py b/liteeth/generic/depacketizer.py index ff7308a4..e4525a0c 100644 --- a/liteeth/generic/depacketizer.py +++ b/liteeth/generic/depacketizer.py @@ -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), diff --git a/liteeth/generic/packetizer.py b/liteeth/generic/packetizer.py index c10ff936..2aa161ef 100644 --- a/liteeth/generic/packetizer.py +++ b/liteeth/generic/packetizer.py @@ -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, diff --git a/liteeth/ip/__init__.py b/liteeth/ip/__init__.py index 3dbc7c01..55030397 100644 --- a/liteeth/ip/__init__.py +++ b/liteeth/ip/__init__.py @@ -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) diff --git a/liteeth/mac/__init__.py b/liteeth/mac/__init__.py index 510faa77..320f32b1 100644 --- a/liteeth/mac/__init__.py +++ b/liteeth/mac/__init__.py @@ -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 += [ diff --git a/liteeth/mac/core/__init__.py b/liteeth/mac/core/__init__.py index 2967e0b5..e8fa5a27 100644 --- a/liteeth/mac/core/__init__.py +++ b/liteeth/mac/core/__init__.py @@ -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 diff --git a/liteeth/test/Makefile b/liteeth/test/Makefile index 7d2283c8..f7cfac63 100644 --- a/liteeth/test/Makefile +++ b/liteeth/test/Makefile @@ -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 index 00000000..b4629c89 --- /dev/null +++ b/liteeth/test/arp_tb.py @@ -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) diff --git a/liteeth/test/model/arp.py b/liteeth/test/model/arp.py index ef4c2761..79ac98d0 100644 --- a/liteeth/test/model/arp.py +++ b/liteeth/test/model/arp.py @@ -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 diff --git a/liteeth/test/model/mac.py b/liteeth/test/model/mac.py index 26e4a13c..74273cb9 100644 --- a/liteeth/test/model/mac.py +++ b/liteeth/test/model/mac.py @@ -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: diff --git a/liteeth/udp/__init__.py b/liteeth/udp/__init__.py index 9f8b5daf..296abe6d 100644 --- a/liteeth/udp/__init__.py +++ b/liteeth/udp/__init__.py @@ -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) -- 2.30.2