Merge pull request #23 from enjoy-digital/versa_ecp5_udp_loopback

Versa ecp5 udp loopback example
This commit is contained in:
enjoy-digital 2019-11-20 09:44:15 +01:00 committed by GitHub
commit 5bf218a00b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 189 additions and 1 deletions

View File

@ -14,3 +14,4 @@ Copyright (c) 2015-2019 Florent Kermarrec <florent@enjoy-digital.fr>
Copyright (c) 2016-2017 Tim 'mithro' Ansell <mithro@mithis.com>
Copyright (c) 2015-2017 Sebastien Bourdeauducq <sb@m-labs.hk>
Copyright (c) 2017-2018 whitequark <whitequark@whitequark.org>
Copyright (c) 2019 Yehowshua <yimmanuel3@gatech.edu>

3
README
View File

@ -61,7 +61,8 @@ enjoy-digital.fr.
python3 setup.py develop
cd ..
3. TODO: add/describe examples
3. Check out /examples/versa_ecp5_udp_loopback for a good practical example of how to get
started with the Liteeth core solo in an FPGA.
[> Tests
--------

View File

@ -0,0 +1,33 @@
## Purpose
Example of UDP loopback with LiteETH IP/UDP hardware stack. The FPGA will echo back any UDP packet it
receives on the specified port (default=8000) to the sender.
You can also found a detailed tutorial [here](https://yehowshuaimmanuel.com/fpga/migen/ethernet_ecp5/).
## Usage
#!bash
./versa_ecp5.py
./versa_ecp5.py load
The IP address assigned to the FPGA in this example is ``192.168.1.50`` and the Host is expected to
be configured with ``192.168.1.100``. Since ``192.168.1.XXX`` is a common address in home networks, a
collisiton is quite possible and in this case, you will need to re-configure the FPGA and the python
scripts accordingly.
Once you are able to ping the FPGA board from your computer, you can run the sender and listener scripts
and should see the date/time UDP packets emitted by the sender looped back to the the listener:
#!bash
$python3 listener.py &
$python3 sender.py
2019-11-20 08:31:00
2019-11-20 08:31:01
2019-11-20 08:31:01
2019-11-20 08:31:02
2019-11-20 08:31:02
2019-11-20 08:31:03
2019-11-20 08:31:03
2019-11-20 08:31:04
2019-11-20 08:31:04
[...]

View File

@ -0,0 +1,16 @@
#!/usr/bin/env python3
# This file is Copyright (c) 2019 Yehowshua Immanuel <yimmanuel3@gatech.edu>
# License: BSD
import socket
UDP_IP = "192.168.1.50"
UDP_PORT = 8000
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind((UDP_IP, UDP_PORT))
while True:
data, addr = sock.recvfrom(1024)
print(data.decode("utf-8"))

View File

@ -0,0 +1,19 @@
#!/usr/bin/env python3
# This file is Copyright (c) 2019 Yehowshua Immanuel <yimmanuel3@gatech.edu>
# License: BSD
import socket
import time
import datetime
UDP_IP = "192.168.1.100"
UDP_PORT = 8000
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
while True:
t = datetime.datetime.fromtimestamp(time.time()).strftime("%Y-%m-%d %H:%M:%S")
print(t)
sock.sendto(t.encode('utf-8'), (UDP_IP, UDP_PORT))
time.sleep(0.5)

View File

@ -0,0 +1,118 @@
#!/usr/bin/env python3
# This file is Copyright (c) 2019 Yehowshua Immanuel <yimmanuel3@gatech.edu>
# This file is Copyright (c) 2019 Florent Kermarrec <florent@enjoy-digital.fr>
# License: BSD
import sys
from migen import *
from litex.build.generic_platform import *
from litex.boards.platforms import versa_ecp5
from litex.soc.cores.clock import *
from litex.soc.integration.soc_core import *
from litex.soc.integration.builder import *
from liteeth.common import *
from liteeth.phy.ecp5rgmii import LiteEthPHYRGMII
from liteeth.core import LiteEthUDPIPCore
# CRG ----------------------------------------------------------------------------------------------
class _CRG(Module):
def __init__(self, platform, sys_clk_freq):
self.clock_domains.cd_sys = ClockDomain()
# # #
self.cd_sys.clk.attr.add("keep")
# clk / rst
clk100 = platform.request("clk100")
platform.add_period_constraint(clk100, 1e9/100e6)
# pll
self.submodules.pll = pll = ECP5PLL()
pll.register_clkin(clk100, 100e6)
pll.create_clkout(self.cd_sys, sys_clk_freq)
# UDPLoopback ------------------------------------------------------------------------------------------
class UDPLoopback(SoCMini):
def __init__(self, platform):
sys_clk_freq = int(150e6)
SoCMini.__init__(self, platform, sys_clk_freq, ident="UDPLoopback", ident_version=True)
# CRG --------------------------------------------------------------------------------------
self.submodules.crg = _CRG(platform, sys_clk_freq)
# Ethernet ---------------------------------------------------------------------------------
# phy
self.submodules.eth_phy = LiteEthPHYRGMII(
clock_pads = platform.request("eth_clocks"),
pads = platform.request("eth"))
self.add_csr("eth_phy")
# core
self.submodules.eth_core = LiteEthUDPIPCore(
phy = self.eth_phy,
mac_address = 0x10e2d5000000,
ip_address = "192.168.1.50",
clk_freq = sys_clk_freq)
# add udp loopback on port 6000 with dw=8
self.add_udp_loopback(6000, 8, 128, "loopback_8")
# add udp loopback on port 8000 with dw=32
self.add_udp_loopback(8000, 32, 128, "loopback_32")
# timing constraints
self.eth_phy.crg.cd_eth_rx.clk.attr.add("keep")
self.eth_phy.crg.cd_eth_tx.clk.attr.add("keep")
self.platform.add_period_constraint(self.eth_phy.crg.cd_eth_rx.clk, 1e9/125e6)
self.platform.add_period_constraint(self.eth_phy.crg.cd_eth_tx.clk, 1e9/125e6)
def add_udp_loopback(self, port, dw, depth, name=None):
port = self.eth_core.udp.crossbar.get_port(port, dw)
buf = stream.SyncFIFO(eth_udp_user_description(dw), depth//(dw//8))
if name is None:
self.submodules += buf
else:
setattr(self.submodules, name, buf)
self.comb += Port.connect(port, buf)
# Load ---------------------------------------------------------------------------------------------
def load():
import os
f = open("ecp5-versa5g.cfg", "w")
f.write(
"""
interface ftdi
ftdi_vid_pid 0x0403 0x6010
ftdi_channel 0
ftdi_layout_init 0xfff8 0xfffb
reset_config none
adapter_khz 25000
jtag newtap ecp5 tap -irlen 8 -expected-id 0x81112043
""")
f.close()
os.system("openocd -f ecp5-versa5g.cfg -c \"transport select jtag; init; svf build/gateware/top.svf; exit\"")
# Build --------------------------------------------------------------------------------------------
def main():
if "load" in sys.argv[1:]:
load()
exit()
else:
platform = versa_ecp5.Platform(toolchain="trellis")
soc = UDPLoopback(platform)
builder = Builder(soc, output_dir="build", csr_csv="tools/csr.csv")
vns = builder.build()
if __name__ == "__main__":
main()