liteeth/bench/arty_multi.py

254 lines
11 KiB
Python
Executable File

#!/usr/bin/env python3
#
# This file is part of LiteEth.
#
# Copyright (c) 2020 Florent Kermarrec <florent@enjoy-digital.fr>
# Copyright (c) 2022 Charles-Henri Mousset <ch.mousset@gmail.com>
# SPDX-License-Identifier: BSD-2-Clause
import os
import argparse
from migen import *
from litex_boards.platforms import digilent_arty
from litex.build.xilinx.vivado import vivado_build_args, vivado_build_argdict
from litex_boards.targets.digilent_arty import _CRG, BaseSoC
from litex.build.generic_platform import *
from litex.soc.cores.clock import *
from litex.soc.interconnect.csr import *
from litex.soc.integration.soc_core import *
from litex.soc.integration.builder import *
from liteeth.phy.mii import LiteEthPHYMII
from liteeth.phy.ethernet import LiteEthPHYETHERNET
from litescope import LiteScopeAnalyzer
# PMOD Raw 10BASET Ethernet ------------------------------------------------------------------------
#
# This testbench uses 2 differential pairs of the Arty-A7, and 4 outputs to bias the termination
# resistors.
# Two(2) 100 Ohms resistor (termination), four(4) 1kOhms (bias) resistors and four(4) capacitors are
# required to connect to the Ethernet port.
# Both the TX and RX pairs are wired identically.
# Using the 4 IOs as pullup/down are not strictly required (you can bias to GND/3V3 instead), but it
# makes wiring very convenient using only a piece of proto-PCB and SMD components.
#
# Ideally the capacitors should be replaced with suitable transformers, but for short
# wiring the capacitors usually work well.
#
# +───────PMOD Pinout───────+
# | 7 td_p_pd | td_p 1 |
# | 8 td_n_pu | td_n 2 |
# | 9 rd_p_pd | rd_p 3 |
# | 10 rd_n_pu | rd_n 4 |
# | 11 GND | GND 5 |
# | 12 3V3 | 3V3 6 |
# +────────────+────────────+
#
# ___
# td_p_pd──|___|───td_p────||────ORANGE/WHITE (RJ45 3)
# 1k0 | 1u
# ─
# | | 100
# ─
# ___ |
# td_n_pu──|___|───td_n────||────ORANGE (RJ45 6)
# 1k0 1u
#
#
# ___
# rd_p_pd──|___|───rd_p────||────GREEN/WHITE (RJ45 1)
# 1k0 | 1u
# ─
# | | 100
# ─
# ___ |
# rd_n_pu──|___|───rd_n────||────GREEN (RJ45 2)
# 1k0 1u
#
#
# Alternate wiring using a transformer (both channels are identical):
# ___
# rd_p_pd──|___|───rd_p─────, ,────GREEN/WHITE (RJ45 1)
# 1k0 | *_) || (_*
# ─ _) || (_
# | | 100 _) || (_
# ─ _) || (_
# ___ | _) || (_
# rd_n_pu──|___|───rd_n─────' '────GREEN (RJ45 2)
# 1k0
#
raw_eth = [
("raw_eth", 0,
Subsignal("td_p", Pins("pmodb:0"), IOStandard("LVCMOS33")),
Subsignal("td_n", Pins("pmodb:1"), IOStandard("LVCMOS33")),
Subsignal("rd_p", Pins("pmodb:2"), IOStandard("LVDS_25"), Misc("PULLDOWN")),
Subsignal("rd_n", Pins("pmodb:3"), IOStandard("LVDS_25"), Misc("PULLUP")),
Subsignal("td_p_pd", Pins("pmodb:4"), IOStandard("LVCMOS33")),
Subsignal("td_n_pu", Pins("pmodb:5"), IOStandard("LVCMOS33")),
Subsignal("rd_p_pd", Pins("pmodb:6"), IOStandard("LVCMOS33")),
Subsignal("rd_n_pu", Pins("pmodb:7"), IOStandard("LVCMOS33")),
),
]
# Bench SoC ----------------------------------------------------------------------------------------
class BenchSoC(BaseSoC):
def __init__(self, sys_clk_freq=int(50e6), with_raw_ethernet=True, **kwarg):
analyzer_signals = []
# BaseSoC ----------------------------------------------------------------------------------
super().__init__(**kwarg
)
self.platform.add_extension(raw_eth)
# Etherbone on 'raw' ethernet --------------------------------------------------------------
if with_raw_ethernet:
eth_raw_pads = self.platform.request("raw_eth")
self.crg.clock_domains.cd_eth_raw = ClockDomain()
self.crg.clock_domains.cd_eth_raw_tx = ClockDomain()
self.crg.clock_domains.cd_eth_raw_rx = ClockDomain()
self.comb += [
self.crg.cd_eth_raw_rx.clk.eq(self.crg.cd_eth_raw.clk),
self.crg.cd_eth_raw_tx.clk.eq(self.crg.cd_eth_raw.clk),
]
self.crg.pll.create_clkout(self.crg.cd_eth_raw, 40e6)
self.submodules.ethphy = ethphy = LiteEthPHYETHERNET(
pads = eth_raw_pads, refclk_cd="eth_raw",
with_hw_init_reset = False)
self.add_etherbone(name="etherbone", phy=self.ethphy, buffer_depth=255,
ip_address="192.168.2.51", phy_cd="eth_raw")
analyzer_signals += [
ethphy.rx.fsm,
ethphy.tx.fsm,
ethphy.rx.rx_i,
ethphy.tx.tx,
]
self.comb += [
eth_raw_pads.td_p_pd.eq(0),
eth_raw_pads.td_n_pu.eq(1),
eth_raw_pads.rd_p_pd.eq(0),
eth_raw_pads.rd_n_pu.eq(1),
]
# Analyzer ---------------------------------------------------------------------------------
ethcore = self.ethcore_etherbone
etherbone = self.etherbone
self.submodules.analyzer = LiteScopeAnalyzer(analyzer_signals + [
self.ethphy.sink,
self.ethphy.source,
# MAC.
ethcore.mac.core.sink.valid,
ethcore.mac.core.sink.ready,
ethcore.mac.core.source.valid,
ethcore.mac.core.source.payload,
ethcore.mac.core.source.ready,
# ARP.
ethcore.arp.rx.sink.valid,
ethcore.arp.rx.sink.ready,
ethcore.arp.tx.source.valid,
ethcore.arp.tx.source.ready,
# IP.
ethcore.ip.rx.sink.valid,
ethcore.ip.rx.sink.ready,
ethcore.ip.tx.source.valid,
ethcore.ip.tx.source.ready,
# UDP.
ethcore.udp.rx.sink.valid,
ethcore.udp.rx.sink.ready,
ethcore.udp.tx.source.valid,
ethcore.udp.tx.source.ready,
# Etherbone.
etherbone.packet.rx.sink.valid,
etherbone.packet.rx.sink.ready,
etherbone.packet.rx.fsm,
etherbone.packet.tx.source.valid,
etherbone.packet.tx.source.ready,
etherbone.packet.tx.fsm,
etherbone.record.receiver.fsm,
etherbone.record.sender.fsm
],
depth=1024 * 8, trigger_depth=256)
# Main ---------------------------------------------------------------------------------------------
def main():
from litex.soc.integration.soc import LiteXSoCArgumentParser
parser = LiteXSoCArgumentParser(description="LiteX SoC on Arty A7")
target_group = parser.add_argument_group(title="Target options")
target_group.add_argument("--toolchain", default="vivado", help="FPGA toolchain (vivado, symbiflow or yosys+nextpnr).")
target_group.add_argument("--build", action="store_true", help="Build design.")
target_group.add_argument("--load", action="store_true", help="Load bitstream.")
target_group.add_argument("--flash", action="store_true", help="Flash bitstream.")
target_group.add_argument("--variant", default="a7-35", help="Board variant (a7-35 or a7-100).")
target_group.add_argument("--sys-clk-freq", default=100e6, help="System clock frequency.")
ethopts = target_group.add_mutually_exclusive_group()
ethopts.add_argument("--with-ethernet", action="store_true", help="Enable Ethernet support.")
ethopts.add_argument("--with-etherbone", action="store_true", help="Enable Etherbone support.")
ethopts.add_argument("--raw-eth", action="store_true", help="use raw 10BASET ethernet on PMODA")
target_group.add_argument("--eth-ip", default="192.168.1.50", type=str, help="Ethernet/Etherbone IP address.")
target_group.add_argument("--eth-dynamic-ip", action="store_true", help="Enable dynamic Ethernet IP addresses setting.")
sdopts = target_group.add_mutually_exclusive_group()
sdopts.add_argument("--with-spi-sdcard", action="store_true", help="Enable SPI-mode SDCard support.")
sdopts.add_argument("--with-sdcard", action="store_true", help="Enable SDCard support.")
target_group.add_argument("--sdcard-adapter", type=str, help="SDCard PMOD adapter (digilent or numato).")
target_group.add_argument("--with-jtagbone", action="store_true", help="Enable JTAGbone support.")
target_group.add_argument("--with-spi-flash", action="store_true", help="Enable SPI Flash (MMAPed).")
target_group.add_argument("--with-pmod-gpio", action="store_true", help="Enable GPIOs through PMOD.") # FIXME: Temporary test.
builder_args(parser)
soc_core_args(parser)
vivado_build_args(parser)
args = parser.parse_args()
assert not (args.with_etherbone and args.eth_dynamic_ip)
soc = BenchSoC(
variant = args.variant,
toolchain = args.toolchain,
sys_clk_freq = int(float(args.sys_clk_freq)),
with_ethernet = args.with_ethernet,
with_etherbone = args.with_etherbone,
eth_ip = args.eth_ip,
eth_dynamic_ip = args.eth_dynamic_ip,
with_jtagbone = args.with_jtagbone,
with_spi_flash = args.with_spi_flash,
with_pmod_gpio = args.with_pmod_gpio,
with_raw_ethernet = args.raw_eth,
**soc_core_argdict(args)
)
if args.sdcard_adapter == "numato":
soc.platform.add_extension(digilent_arty._numato_sdcard_pmod_io)
else:
soc.platform.add_extension(digilent_arty._sdcard_pmod_io)
if args.with_spi_sdcard:
soc.add_spi_sdcard()
if args.with_sdcard:
soc.add_sdcard()
builder = Builder(soc, **builder_argdict(args))
builder_kwargs = vivado_build_argdict(args) if args.toolchain == "vivado" else {}
if args.build:
builder.build(**builder_kwargs)
if args.load:
prog = soc.platform.create_programmer()
prog.load_bitstream(builder.get_bitstream_filename(mode="sram"))
if args.flash:
prog = soc.platform.create_programmer()
prog.flash(0, builder.get_bitstream_filename(mode="flash"))
if __name__ == "__main__":
main()