Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Etherbone testing #106

Open
wants to merge 33 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
38ce533
test/model/phy.py: add dumping to .pcap file
michael-betz Dec 27, 2021
e8e0dbb
icmp.py: take icmp type field into account
michael-betz Dec 27, 2021
6bbf0b2
Merge branch 'master' of https://github.com/enjoy-digital/liteeth int…
michael-betz Dec 27, 2021
2a5dce3
icmp testing: demonstrate that non-ping ICMP packets are ignored
michael-betz Dec 27, 2021
c715316
Merge branch 'master' of https://github.com/enjoy-digital/liteeth
michael-betz Jan 15, 2022
bf2ef7e
Merge branch 'master' of https://github.com/enjoy-digital/liteeth
michael-betz Mar 30, 2022
fece437
test: fix ICMP header fields, add missing clockdomains
michael-betz Apr 3, 2022
c234798
test_icmp.py: fixed the testbench
michael-betz Apr 3, 2022
01dcdba
add ident and sequence parameters to ICMP stream
michael-betz Apr 3, 2022
b4519be
PacketStreamer: WIP, make it drive last_be correctly
michael-betz Apr 3, 2022
b0953ea
add .gtkw for ping debugging
michael-betz Apr 3, 2022
04a5565
Let PacketStreamer / Logger handle the word <--> byte conversion
michael-betz Apr 4, 2022
24d0b83
test_icmp: working ping testbench for 8, 32 and 64 bit datapath
michael-betz Apr 4, 2022
123a23d
fix PacketStreamer bug
michael-betz Apr 4, 2022
11fbea7
fix ci
michael-betz Apr 5, 2022
c83c7df
test_etherbone.py: fix the test and make it self checking
michael-betz Apr 17, 2022
4e2be2e
etherbone test with DW=32 succeeds
michael-betz Apr 17, 2022
bec83fd
Merge remote-tracking branch 'david/dev/liteethudprxfix' into yfl
michael-betz Apr 17, 2022
8c175c4
test_etherbone.py: writes seem to work with DW=64
michael-betz Apr 17, 2022
8e55e4f
packet.py: fix typo in Packetizer
michael-betz Apr 18, 2022
a2d0497
test_etherbone.py: make all tests pass with DW=64
michael-betz Apr 18, 2022
9de7d38
Merge branch 'master' into yfl
michael-betz Apr 18, 2022
d83430f
test_etherbone: test 8, 32 and 64 bit DW in CI
michael-betz Apr 18, 2022
b4ebc3b
test_etherbone.py: some polish
michael-betz Apr 19, 2022
57f357f
mode/phy.py: add stall detection
michael-betz Apr 19, 2022
e849638
test_etherbone: add stall-check
michael-betz Apr 19, 2022
09d59c0
mac/core.py: add FIFO to TxDatapath
michael-betz Apr 19, 2022
677c6bf
test_etherbone: check for infinite send loop
michael-betz Apr 21, 2022
1b6e241
Merge branch 'master' into yfl
michael-betz Apr 26, 2022
a151d97
test_etherbone.py: comments, remove antiUnderflow parameter
michael-betz Apr 26, 2022
c4689fa
clean-up for pull request
michael-betz Apr 26, 2022
250d9e0
Revert "mac/core.py: add FIFO to TxDatapath"
michael-betz Apr 26, 2022
00ed2c7
LiteEthMacCore: remove debug print
michael-betz Apr 26, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion liteeth/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,8 @@
"msgtype": HeaderField(0, 0, 8),
"code": HeaderField(1, 0, 8),
"checksum": HeaderField(2, 0, 16),
"quench": HeaderField(4, 0, 32)
"ident": HeaderField(4, 0, 16),
"sequence": HeaderField(6, 0, 16)
}
icmp_header = Header(icmp_header_fields, icmp_header_length, swap_field_bytes=True)

Expand Down
22 changes: 11 additions & 11 deletions liteeth/core/arp.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,9 +202,9 @@ def __init__(self, clk_freq, max_requests=8):
# table in the future to improve performance when packets are
# targeting multiple destinations.
update = Signal()
cached_valid = Signal()
cached_ip_address = Signal(32, reset_less=True)
cached_mac_address = Signal(48, reset_less=True)
self.cached_valid = Signal()
self.cached_ip_address = Signal(32, reset_less=True)
self.cached_mac_address = Signal(48, reset_less=True)
cached_timer = WaitTimer(clk_freq*10)
self.submodules += cached_timer

Expand Down Expand Up @@ -238,21 +238,21 @@ def __init__(self, clk_freq, max_requests=8):
)
self.sync += \
If(update,
cached_valid.eq(1),
cached_ip_address.eq(sink.ip_address),
cached_mac_address.eq(sink.mac_address),
self.cached_valid.eq(1),
self.cached_ip_address.eq(sink.ip_address),
self.cached_mac_address.eq(sink.mac_address),
).Else(
If(cached_timer.done,
cached_valid.eq(0)
self.cached_valid.eq(0)
)
)
self.comb += cached_timer.wait.eq(~update)
fsm.act("CHECK_TABLE",
If(cached_valid,
If(request_ip_address == cached_ip_address,
If(self.cached_valid,
If(request_ip_address == self.cached_ip_address,
request_ip_address_reset.eq(1),
NextState("PRESENT_RESPONSE"),
).Elif(request.ip_address == cached_ip_address,
).Elif(request.ip_address == self.cached_ip_address,
request.ready.eq(request.valid),
NextState("PRESENT_RESPONSE"),
).Else(
Expand Down Expand Up @@ -282,7 +282,7 @@ def __init__(self, clk_freq, max_requests=8):
request_counter_reset.eq(1),
request_pending_clr.eq(1)
),
response.mac_address.eq(cached_mac_address)
response.mac_address.eq(self.cached_mac_address)
]
fsm.act("PRESENT_RESPONSE",
response.valid.eq(1),
Expand Down
6 changes: 4 additions & 2 deletions liteeth/core/icmp.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ def __init__(self, ip_address, dw=8):
"msgtype",
"code",
"checksum",
"quench",
"ident",
"sequence",
"data",
"last_be"})

Expand Down Expand Up @@ -98,7 +99,8 @@ def __init__(self, ip_address, dw=8):
"msgtype",
"code",
"checksum",
"quench",
"ident",
"sequence",
"data",
"error",
"last_be"}),
Expand Down
12 changes: 11 additions & 1 deletion test/model/dumps.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ def verify_packet(packet, infos):
ping_request = format_dump("""
00 50 56 e0 14 49 00 0c 29 34 0b de 08 00 45 00
00 3c d7 43 00 00 80 01 2b 73 c0 a8 9e 8b ae 89
2a 4d 08 00 2a 5c 02 00 21 00 61 62 63 64 65 66
2a 4d 08 00 20 b4 02 00 21 00 61 62 63 64 65 66
67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76
77 61 62 63 64 65 66 67 68 69""")

Expand All @@ -104,3 +104,13 @@ def verify_packet(packet, infos):
77 61 62 63 64 65 66 67 68 69""")

ping_reply_infos = {}

# ICMP: Destination unreachable (Port unreachable)
icmp_unreachable_reply = format_dump("""
00 00 00 00 00 00 00 00 00 00 00 00 08 00 45 c0
00 3e 11 a7 00 00 40 01 6a 56 7f 00 00 01 7f 00
00 01 03 03 d8 18 00 00 00 00 45 00 00 22 a0 52
40 00 40 11 9c 76 7f 00 00 01 7f 00 00 01 de 05
04 d2 00 0e fe 21 68 65 6c 6c 6f 0a
""")

15 changes: 9 additions & 6 deletions test/model/etherbone.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,23 +31,26 @@ def __init__(self, udp, debug=False):

udp.set_etherbone_callback(self.callback)

def send(self, packet):
def send(self, packet, target_ip=0x12345678):
packet.encode()
if self.debug:
print_etherbone(">>>>>>>>")
print_etherbone(packet)
udp_packet = udp.UDPPacket(packet)
udp_packet = udp.UDPPacket(packet.bytes)
udp_packet.src_port = 0x1234 # FIXME
udp_packet.dst_port = 0x1234 # FIXME
udp_packet.length = len(packet)
udp_packet.length = len(packet.bytes) + udp_header_length
udp_packet.checksum = 0
self.udp.send(udp_packet)
self.udp.send(udp_packet, target_ip)

def receive(self):
def receive(self, timeout=None):
self.rx_packet = EtherbonePacket()
while not self.rx_packet.done:
i = 0
while not self.rx_packet.done and ((timeout is None) or (timeout >= i)):
i += 1
yield


def callback(self, packet):
packet = EtherbonePacket(packet)
packet.decode()
Expand Down
17 changes: 14 additions & 3 deletions test/model/icmp.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ def decode(self):
setattr(self, k, get_field_data(v, header))

def encode(self):
'''
insert header bytes in front of the payload bytes
'''
header = 0
for k, v in sorted(icmp_header.fields.items()):
value = merge_bytes(split_bytes(getattr(self, k),
Expand All @@ -41,6 +44,13 @@ def encode(self):
for d in split_bytes(header, icmp_header.length):
self.insert(0, d)

def insert_checksum(self):
self[2] = 0
self[3] = 0
c = ip.checksum(self)
self[2] = c & 0xff
self[3] = (c >> 8) & 0xff

def __repr__(self):
r = "--------\n"
for k in sorted(icmp_header.fields.keys()):
Expand All @@ -63,21 +73,22 @@ def __init__(self, ip, ip_address, debug=False):

self.ip.set_icmp_callback(self.callback)

def send(self, packet):
def send(self, packet, target_ip=0xFFFFFFFF):
packet.encode()
packet.insert_checksum()
if self.debug:
print_icmp(">>>>>>>>")
print_icmp(packet)
ip_packet = ip.IPPacket(packet)
ip_packet.version = 0x4
ip_packet.ihl = 0x5
ip_packet.total_length = len(packet) + ip_packet.ihl
ip_packet.total_length = len(packet) + 20
ip_packet.identification = 0
ip_packet.flags = 0
ip_packet.fragment_offset = 0
ip_packet.ttl = 0x80
ip_packet.sender_ip = self.ip_address
ip_packet.target_ip = 0x12345678 # XXX
ip_packet.target_ip = target_ip
ip_packet.checksum = 0
ip_packet.protocol = icmp_protocol
self.ip.send(ip_packet)
Expand Down
11 changes: 9 additions & 2 deletions test/model/ip.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,17 @@ def carry_around_add(a, b):


def checksum(msg):
'''
http://www.faqs.org/rfcs/rfc1071.html
'''
s = 0
for i in range(0, len(msg), 2):
w = msg[i] + (msg[i+1] << 8)
for i in range(len(msg) // 2):
w = msg[2 * i] + (msg[2 * i + 1] << 8)
s = carry_around_add(s, w)
# print(hex(w), hex(s))
if len(msg) % 2: # Add the single remaining byte
s = carry_around_add(s, msg[-1])
# print(hex(msg[-1]), hex(s))
return ~s & 0xffff


Expand Down
67 changes: 51 additions & 16 deletions test/model/phy.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
# Copyright (c) 2015-2019 Florent Kermarrec <[email protected]>
# SPDX-License-Identifier: BSD-2-Clause

from struct import pack
from litex.soc.interconnect.stream_sim import *

from liteeth.common import *
Expand All @@ -13,60 +14,94 @@
def print_phy(s):
print_with_prefix(s, "[PHY]")


# PHY Source ---------------------------------------------------------------------------------------

class PHYSource(PacketStreamer):
def __init__(self, dw):
PacketStreamer.__init__(self, eth_phy_description(dw))
def __init__(self, dw, assertStall):
PacketStreamer.__init__(self, eth_phy_description(dw), dw=dw, assertStall=assertStall)

# PHY Sink -----------------------------------------------------------------------------------------

class PHYSink(PacketLogger):
def __init__(self, dw):
PacketLogger.__init__(self, eth_phy_description(dw))
def __init__(self, dw, assertStall):
PacketLogger.__init__(self, eth_phy_description(dw), dw=dw, assertStall=assertStall)

# PHY ----------------------------------------------------------------------------------------------

LINKTYPE_ETHERNET = 1
LINKTYPE_RAW = 101
LINKTYPE_ETHERNET_MPACKET = 274

class PHY(Module):
def __init__(self, dw, debug=False):
def __init__(self, dw, debug=False, pcap_file=None, assertStall=False):
self.dw = dw
self.debug = debug

self.submodules.phy_source = PHYSource(dw)
self.submodules.phy_sink = PHYSink(dw)
self.submodules.phy_source = PHYSource(dw, assertStall)
self.submodules.phy_sink = PHYSink(dw, assertStall)

self.source = self.phy_source.source
self.sink = self.phy_sink.sink

self.mac_callback = None

self.cc = 0
self.pcap_file = pcap_file
if pcap_file is not None:
file_header = pack(
'IHHiIII',
0xa1b2c3d4,
2,
4,
0,
0,
65535,
LINKTYPE_ETHERNET_MPACKET
)
with open(pcap_file, 'wb') as f:
f.write(file_header)

def set_mac_callback(self, callback):
self.mac_callback = callback

def send(self, datas):
packet = Packet(datas)
n_bytes = len(datas)
if self.debug:
r = ">>>>>>>>\n"
r += "length " + str(len(datas)) + "\n"
r += "length " + str(n_bytes) + "\n"
for d in datas:
r += "{:02x}".format(d)
r += f'{d:02x} '
print_phy(r)
self.phy_source.send(packet)

if self.pcap_file is not None and n_bytes > 0:
with open(self.pcap_file, 'ab') as f:
f.write(pack('IIII', self.cc, 0, n_bytes, n_bytes))
f.write(bytes(datas))

self.phy_source.send(Packet(datas))

def receive(self):
yield from self.phy_sink.receive()
self.packet = p = self.phy_sink.packet # Each item is a byte
if self.debug:
r = "<<<<<<<<\n"
r += "length " + str(len(self.phy_sink.packet)) + "\n"
for d in self.phy_sink.packet:
r += "{:02x}".format(d)
r += "length " + str(len(p)) + "\n"
for d in p:
r += f'{d:02x} '
print_phy(r)
self.packet = self.phy_sink.packet

if self.pcap_file is not None:
ll = len(self.packet) # - 8
if ll > 0:
with open(self.pcap_file, 'ab') as f:
f.write(pack('IIII', self.cc, 0, ll, ll))
f.write(bytes(self.packet))


@passive
def generator(self):
while True:
yield from self.receive()
if self.mac_callback is not None:
self.mac_callback(self.packet)
self.cc += 1
6 changes: 3 additions & 3 deletions test/model/udp.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,21 +69,21 @@ def __init__(self, ip, ip_address, debug=False, loopback=False):
def set_etherbone_callback(self, callback):
self.etherbone_callback = callback

def send(self, packet):
def send(self, packet, target_ip=0x12345678):
packet.encode()
if self.debug:
print_udp(">>>>>>>>")
print_udp(packet)
ip_packet = ip.IPPacket(packet)
ip_packet.version = 0x4
ip_packet.ihl = 0x5
ip_packet.total_length = len(packet) + ip_packet.ihl
ip_packet.total_length = len(packet) + ip_packet.ihl * 4
ip_packet.identification = 0
ip_packet.flags = 0
ip_packet.fragment_offset = 0
ip_packet.ttl = 0x80
ip_packet.sender_ip = self.ip_address
ip_packet.target_ip = 0x12345678 # FIXME
ip_packet.target_ip = target_ip
ip_packet.checksum = 0
ip_packet.protocol = udp_protocol
self.ip.send(ip_packet)
Expand Down
Loading