Created
June 11, 2021 07:36
-
-
Save enjoy-digital/785baeb1845f67e72617f3d94460438e to your computer and use it in GitHub Desktop.
Add Ethernet to your SoC with cheap Lan8720 RMII "PMOD"
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
# | |
# This file is part of LiteX-Boards. | |
# | |
# Copyright (c) 2015-2019 Florent Kermarrec <[email protected]>, | |
# Copyright (c) 2020 Staf Verhaegen <[email protected]> | |
# SPDX-License-Identifier: BSD-2-Clause | |
import os | |
import argparse | |
from migen import * | |
from litex_boards.platforms import arty_s7 | |
from litex.build.xilinx.vivado import vivado_build_args, vivado_build_argdict | |
from litex.soc.cores.clock import * | |
from litex.soc.integration.soc_core import * | |
from litex.soc.integration.builder import * | |
from litex.soc.cores.led import LedChaser | |
from litedram.modules import MT41K128M16 | |
from litedram.phy import s7ddrphy | |
# CRG ---------------------------------------------------------------------------------------------- | |
class _CRG(Module): | |
def __init__(self, platform, sys_clk_freq): | |
self.rst = Signal() | |
self.clock_domains.cd_sys = ClockDomain() | |
self.clock_domains.cd_sys2x = ClockDomain(reset_less=True) | |
self.clock_domains.cd_sys4x = ClockDomain(reset_less=True) | |
self.clock_domains.cd_sys4x_dqs = ClockDomain(reset_less=True) | |
self.clock_domains.cd_idelay = ClockDomain() | |
# # # | |
self.submodules.pll = pll = S7PLL(speedgrade=-1) | |
self.comb += pll.reset.eq(~platform.request("cpu_reset") | self.rst) | |
pll.register_clkin(platform.request("clk100"), 100e6) | |
pll.create_clkout(self.cd_sys, sys_clk_freq) | |
pll.create_clkout(self.cd_sys2x, 2*sys_clk_freq) | |
pll.create_clkout(self.cd_sys4x, 4*sys_clk_freq) | |
pll.create_clkout(self.cd_sys4x_dqs, 4*sys_clk_freq, phase=90) | |
pll.create_clkout(self.cd_idelay, 200e6) | |
platform.add_false_path_constraints(self.cd_sys.clk, pll.clkin) # Ignore sys_clk to pll.clkin path created by SoC's rst. | |
self.submodules.idelayctrl = S7IDELAYCTRL(self.cd_idelay) | |
# BaseSoC ------------------------------------------------------------------------------------------ | |
class BaseSoC(SoCCore): | |
def __init__(self, variant="s7-50", sys_clk_freq=int(100e6), **kwargs): | |
platform = arty_s7.Platform(variant=variant) | |
# SoCCore ---------------------------------------------------------------------------------- | |
SoCCore.__init__(self, platform, sys_clk_freq, | |
ident = "LiteX SoC on Arty S7", | |
ident_version = True, | |
**kwargs) | |
# CRG -------------------------------------------------------------------------------------- | |
self.submodules.crg = _CRG(platform, sys_clk_freq) | |
# DDR3 SDRAM ------------------------------------------------------------------------------- | |
if not self.integrated_main_ram_size: | |
self.submodules.ddrphy = s7ddrphy.A7DDRPHY(platform.request("ddram"), | |
memtype = "DDR3", | |
nphases = 4, | |
sys_clk_freq = sys_clk_freq) | |
self.add_sdram("sdram", | |
phy = self.ddrphy, | |
module = MT41K128M16(sys_clk_freq, "1:4"), | |
l2_cache_size = kwargs.get("l2_size", 8192) | |
) | |
# Ethernet --------------------------------------------------------------------------------- | |
# Add IOs to Board's platform. | |
from litex.build.generic_platform import Pins, Subsignal, IOStandard | |
def eth_lan8720_rmii_pmod_io(pmod): | |
# Lan8020 RMII PHY "PMOD": To be used as a PMOD, MDIO should be disconnected and TX1 | |
# connected to PMOD8 IO. | |
return [ | |
("eth_clocks", 0, | |
Subsignal("ref_clk", Pins(f"{pmod}:6")), | |
IOStandard("LVCMOS33"), | |
), | |
("eth", 0, | |
Subsignal("rx_data", Pins(f"{pmod}:5 {pmod}:1")), | |
Subsignal("crs_dv", Pins(f"{pmod}:2")), | |
Subsignal("tx_en", Pins(f"{pmod}:4")), | |
Subsignal("tx_data", Pins(f"{pmod}:0 {pmod}:7")), | |
IOStandard("LVCMOS33") | |
), | |
] | |
platform.add_extension(eth_lan8720_rmii_pmod_io("pmodb")) | |
# Create RMII Ethernet PHY. | |
from liteeth.phy.rmii import LiteEthPHYRMII | |
self.submodules.ethphy = LiteEthPHYRMII( | |
clock_pads = platform.request("eth_clocks"), | |
pads = platform.request("eth"), | |
refclk_cd = None) | |
# Add Ethernet MAC and connect it to the Soft-CPU. | |
#self.add_ethernet(phy=self.ethphy) | |
# Add Etherbone and connect if to the SoC. | |
self.add_etherbone(phy=self.ethphy) | |
# Leds ------------------------------------------------------------------------------------- | |
self.submodules.leds = LedChaser( | |
pads = platform.request_all("user_led"), | |
sys_clk_freq = sys_clk_freq) | |
# Build -------------------------------------------------------------------------------------------- | |
def main(): | |
parser = argparse.ArgumentParser(description="LiteX SoC on Arty S7") | |
parser.add_argument("--build", action="store_true", help="Build bitstream") | |
parser.add_argument("--load", action="store_true", help="Load bitstream") | |
parser.add_argument("--variant", default="s7-50", help="Board variant: s7-50 (default) or s7-25") | |
parser.add_argument("--sys-clk-freq", default=100e6, help="System clock frequency (default: 100MHz)") | |
builder_args(parser) | |
soc_core_args(parser) | |
vivado_build_args(parser) | |
args = parser.parse_args() | |
soc = BaseSoC( | |
variant = args.variant, | |
sys_clk_freq = int(float(args.sys_clk_freq)), | |
**soc_core_argdict(args) | |
) | |
builder = Builder(soc, **builder_argdict(args)) | |
builder.build(**vivado_build_argdict(args), run=args.build) | |
if args.load: | |
prog = soc.platform.create_programmer() | |
prog.load_bitstream(os.path.join(builder.gateware_dir, soc.build_name + ".bit")) | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment