Guest User

litepcie_with_spi_and_gpio

a guest
Nov 9th, 2021
169
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 15.29 KB | None | 0 0
  1. #!/usr/bin/env python3
  2.  
  3. #
  4. # This file is part of LitePCIe.
  5. #
  6. # Copyright (c) 2019-2020 Florent Kermarrec <[email protected]>
  7. # Copyright (c) 2020 Antmicro <www.antmicro.com>
  8. # SPDX-License-Identifier: BSD-2-Clause
  9.  
  10. """
  11. LitePCIe standalone core generator
  12.  
  13. LitePCIe aims to be directly used as a python package when the SoC is created using LiteX. However,
  14. for some use cases it could be interesting to generate a standalone verilog file of the core:
  15. - integration of the core in a SoC using a more traditional flow.
  16. - need to version/package the core.
  17. - avoid Migen/LiteX dependencies.
  18. - etc...
  19.  
  20. The standalone core is generated from a YAML configuration file that allows the user to generate
  21. easily a custom configuration of the core.
  22.  
  23. Current version of the generator is limited to:
  24. - Xilinx 7-Series.
  25. - Xilinx Ultrascale.
  26. - Altera Cyclone V.
  27. """
  28.  
  29. import yaml
  30. import argparse
  31. import subprocess
  32.  
  33. from migen import *
  34. from migen.genlib.resetsync import AsyncResetSynchronizer
  35. from migen.genlib.misc import WaitTimer
  36.  
  37. from litex.soc.cores.clock import *
  38. from litex.soc.interconnect.csr import *
  39. from litex.soc.interconnect import wishbone
  40. from litex.soc.interconnect.axi import *
  41. from litex.soc.integration.soc_core import *
  42. from litex.soc.integration.builder import *
  43.  
  44. # PCIe pecific imports
  45. from litepcie.core import LitePCIeEndpoint, LitePCIeMSI, LitePCIeMSIMultiVector, LitePCIeMSIX
  46. from litepcie.frontend.dma import LitePCIeDMA
  47. from litepcie.frontend.wishbone import LitePCIeWishboneMaster, LitePCIeWishboneSlave
  48. from litepcie.frontend.axi import LitePCIeAXISlave
  49. from litepcie.software import generate_litepcie_software_headers
  50.  
  51. # SPI flash specific imports
  52. from litex.soc.cores.gpio import GPIOOut
  53. from litex.soc.cores.spi_flash import S7SPIFlash
  54.  
  55. # ICAP specific imports
  56. from litex.soc.cores.icap import ICAP
  57.  
  58. from litex.build.generic_platform import *
  59.  
  60. # IOs/Interfaces -----------------------------------------------------------------------------------
  61.  
  62. def get_clkin_ios():
  63.     return [
  64.         # clk / rst
  65.         ("clk", 0, Pins(1)),
  66.         ("rst", 0, Pins(1))
  67.     ]
  68.  
  69. def get_clkout_ios():
  70.     return [
  71.         # clk / rst
  72.         ("clk125", 0, Pins(1)),
  73.         ("rst125", 0, Pins(1))
  74.     ]
  75.  
  76. def get_pcie_ios(phy_lanes=4):
  77.     return [
  78.         ("pcie", 0,
  79.             Subsignal("rst_n", Pins(1)),
  80.             Subsignal("clk_p", Pins(1)),
  81.             Subsignal("clk_n", Pins(1)),
  82.             Subsignal("rx_p",  Pins(phy_lanes)),
  83.             Subsignal("rx_n",  Pins(phy_lanes)),
  84.             Subsignal("tx_p",  Pins(phy_lanes)),
  85.             Subsignal("tx_n",  Pins(phy_lanes)),
  86.         ),
  87.     ]
  88.  
  89. def get_axi_dma_ios(_id, dw):
  90.     return [
  91.         ("dma{}_writer_axi".format(_id), 0,
  92.             Subsignal("tvalid", Pins(1)),
  93.             Subsignal("tready", Pins(1)),
  94.             Subsignal("tlast",  Pins(1)),
  95.             Subsignal("tdata",  Pins(dw)),
  96.             Subsignal("tuser",  Pins(1)), # first
  97.         ),
  98.         ("dma{}_reader_axi".format(_id), 0,
  99.             Subsignal("tvalid", Pins(1)),
  100.             Subsignal("tready", Pins(1)),
  101.             Subsignal("tlast",  Pins(1)),
  102.             Subsignal("tdata",  Pins(dw)),
  103.             Subsignal("tuser",  Pins(1)), # first
  104.         ),
  105.     ]
  106.  
  107. def get_msi_irqs_ios(width=16):
  108.     return [("msi_irqs", 0, Pins(width))]
  109.  
  110. # CRG ----------------------------------------------------------------------------------------------
  111.  
  112. class LitePCIeCRG(Module):
  113.     def __init__(self, platform, sys_clk_freq, clk_external):
  114.         self.clock_domains.cd_sys = ClockDomain()
  115.  
  116.         # # #
  117.  
  118.         if clk_external:
  119.             platform.add_extension(get_clkin_ios())
  120.             self.comb += self.cd_sys.clk.eq(platform.request("clk"))
  121.             self.specials += AsyncResetSynchronizer(self.cd_sys, platform.request("rst"))
  122.         else:
  123.             platform.add_extension(get_clkout_ios())
  124.             self.comb += self.cd_sys.clk.eq(ClockSignal("pcie"))
  125.             self.comb += self.cd_sys.rst.eq(ResetSignal("pcie"))
  126.             self.comb += platform.request("clk125").eq(ClockSignal("pcie"))
  127.             self.comb += platform.request("rst125").eq(ResetSignal("pcie"))
  128.  
  129. # Core ---------------------------------------------------------------------------------------------
  130.  
  131. class LitePCIeCore(SoCMini):
  132.     SoCMini.mem_map["csr"] = 0x00000000
  133.     SoCMini.csr_map = {
  134.         "ctrl":           0,
  135.         "crg" :           1,
  136.         "pcie_phy":       2,
  137.         "pcie_msi":       3,
  138.         "pcie_msi_table": 4,
  139.     }
  140.     def __init__(self, platform, core_config):
  141.         platform.add_extension(get_pcie_ios(core_config["phy_lanes"]))
  142.         for i in range(core_config["dma_channels"]):
  143.             platform.add_extension(get_axi_dma_ios(i, core_config["phy_data_width"]))
  144.         platform.add_extension(get_msi_irqs_ios(width=core_config["msi_irqs"]))
  145.         sys_clk_freq = float(core_config.get("clk_freq", 125e6))
  146.  
  147.         # SoCMini ----------------------------------------------------------------------------------
  148.         SoCMini.__init__(self, platform, clk_freq=sys_clk_freq,
  149.             csr_data_width = 32,
  150.             csr_ordering   = core_config.get("csr_ordering", "big"),
  151.             ident          = "LitePCIe standalone core",
  152.             ident_version  = True
  153.         )
  154.  
  155.         # CRG --------------------------------------------------------------------------------------
  156.         clk_external = core_config.get("clk_external", False)
  157.         self.submodules.crg = LitePCIeCRG(platform, sys_clk_freq, clk_external)
  158.  
  159.         # PCIe PHY ---------------------------------------------------------------------------------
  160.         self.submodules.pcie_phy = core_config["phy"](platform, platform.request("pcie"),
  161.             pcie_data_width = core_config.get("phy_pcie_data_width", 64),
  162.             data_width      = core_config["phy_data_width"],
  163.             bar0_size       = core_config["phy_bar0_size"])
  164.  
  165.         # PCIe Endpoint ----------------------------------------------------------------------------
  166.         self.submodules.pcie_endpoint = LitePCIeEndpoint(self.pcie_phy,
  167.             endianness           = self.pcie_phy.endianness,
  168.             max_pending_requests = core_config.get("ep_max_pending_requests", 4))
  169.  
  170.         # PCIe Wishbone Master ---------------------------------------------------------------------
  171.         pcie_wishbone_master = LitePCIeWishboneMaster(self.pcie_endpoint,
  172.             qword_aligned = self.pcie_phy.qword_aligned)
  173.         self.submodules += pcie_wishbone_master
  174.         self.add_wb_master(pcie_wishbone_master.wishbone)
  175.  
  176.         # PCIe MMAP Master -------------------------------------------------------------------------
  177.         if core_config.get("mmap", False):
  178.             mmap_base        = core_config["mmap_base"]
  179.             mmap_size        = core_config["mmap_size"]
  180.             mmap_translation = core_config.get("mmap_translation", 0x00000000)
  181.             wb = wishbone.Interface(data_width=32)
  182.             self.mem_map["mmap"] = mmap_base
  183.             self.add_wb_slave(mmap_base, wb, mmap_size)
  184.             self.add_memory_region("mmap", mmap_base, mmap_size, type="io")
  185.             axi = AXILiteInterface(data_width=32, address_width=32)
  186.             wb2axi = Wishbone2AXILite(wb, axi, base_address=-mmap_translation)
  187.             self.submodules += wb2axi
  188.             platform.add_extension(axi.get_ios("mmap_axi_lite"))
  189.             axi_pads = platform.request("mmap_axi_lite")
  190.             self.comb += axi.connect_to_pads(axi_pads, mode="master")
  191.  
  192.         # PCIe MMAP Slave --------------------------------------------------------------------------
  193.         if core_config.get("mmap_slave", False):
  194.             # AXI-Full
  195.             if core_config.get("mmap_slave_axi_full", False):
  196.                 pcie_axi_slave = LitePCIeAXISlave(self.pcie_endpoint, data_width=128)
  197.                 self.submodules += pcie_axi_slave
  198.                 platform.add_extension(pcie_axi_slave.axi.get_ios("mmap_slave_axi"))
  199.                 axi_pads = platform.request("mmap_slave_axi")
  200.                 self.comb += pcie_axi_slave.axi.connect_to_pads(axi_pads, mode="slave")
  201.             # AXI-Lite
  202.             else:
  203.                 platform.add_extension(axi.get_ios("mmap_slave_axi_lite"))
  204.                 axi_pads = platform.request("mmap_slave_axi_lite")
  205.                 wb = wishbone.Interface(data_width=32)
  206.                 axi = AXILiteInterface(data_width=32, address_width=32)
  207.                 self.comb += axi.connect_to_pads(axi_pads, mode="slave")
  208.                 axi2wb = AXILite2Wishbone(axi, wb)
  209.                 self.submodules += axi2wb
  210.                 pcie_wishbone_slave = LitePCIeWishboneSlave(self.pcie_endpoint,
  211.                     qword_aligned=self.pcie_phy.qword_aligned)
  212.                 self.submodules += pcie_wishbone_slave
  213.                 self.comb += wb.connect(pcie_wishbone_slave.wishbone)
  214.  
  215.         # PCIe DMA ---------------------------------------------------------------------------------
  216.         pcie_dmas = []
  217.         self.add_constant("DMA_CHANNELS", core_config["dma_channels"])
  218.         for i in range(core_config["dma_channels"]):
  219.             pcie_dma = LitePCIeDMA(self.pcie_phy, self.pcie_endpoint,
  220.                 with_buffering    = core_config["dma_buffering"] != 0,
  221.                 buffering_depth   = core_config["dma_buffering"],
  222.                 with_loopback     = core_config["dma_loopback"],
  223.                 with_synchronizer = core_config["dma_synchronizer"],
  224.                 with_monitor      = core_config["dma_monitor"])
  225.             pcie_dma = stream.BufferizeEndpoints({"sink"   : stream.DIR_SINK})(pcie_dma)
  226.             pcie_dma = stream.BufferizeEndpoints({"source" : stream.DIR_SOURCE})(pcie_dma)
  227.             setattr(self.submodules, "pcie_dma" + str(i), pcie_dma)
  228.             self.add_csr("pcie_dma{}".format(i))
  229.             dma_writer_ios = platform.request("dma{}_writer_axi".format(i))
  230.             dma_reader_ios = platform.request("dma{}_reader_axi".format(i))
  231.             self.comb += [
  232.                 # Writer IOs
  233.                 pcie_dma.sink.valid.eq(dma_writer_ios.tvalid),
  234.                 dma_writer_ios.tready.eq(pcie_dma.sink.ready),
  235.                 pcie_dma.sink.last.eq(dma_writer_ios.tlast),
  236.                 pcie_dma.sink.data.eq(dma_writer_ios.tdata),
  237.                 pcie_dma.sink.first.eq(dma_writer_ios.tuser),
  238.  
  239.                 # Reader IOs
  240.                 dma_reader_ios.tvalid.eq(pcie_dma.source.valid),
  241.                 pcie_dma.source.ready.eq(dma_reader_ios.tready),
  242.                 dma_reader_ios.tlast.eq(pcie_dma.source.last),
  243.                 dma_reader_ios.tdata.eq(pcie_dma.source.data),
  244.                 dma_reader_ios.tuser.eq(pcie_dma.source.first),
  245.             ]
  246.  
  247.         # PCIe MSI ---------------------------------------------------------------------------------
  248.         if core_config.get("msi_x", False):
  249.             assert core_config["msi_irqs"] <= 32
  250.             self.submodules.pcie_msi = LitePCIeMSIX(self.pcie_endpoint, width=64)
  251.             self.comb += self.pcie_msi.irqs[32:32+core_config["msi_irqs"]].eq(platform.request("msi_irqs"))
  252.         else:
  253.             assert core_config["msi_irqs"] <= 16
  254.             if core_config.get("msi_multivector", False):
  255.                 self.submodules.pcie_msi = LitePCIeMSIMultiVector(width=32)
  256.             else:
  257.                 self.submodules.pcie_msi = LitePCIeMSI(width=32)
  258.             self.comb += self.pcie_msi.source.connect(self.pcie_phy.msi)
  259.             self.comb += self.pcie_msi.irqs[16:16+core_config["msi_irqs"]].eq(platform.request("msi_irqs"))
  260.         self.interrupts = {}
  261.         for i in range(core_config["dma_channels"]):
  262.             self.interrupts["pcie_dma" + str(i) + "_writer"] = getattr(self, "pcie_dma" + str(i)).writer.irq
  263.             self.interrupts["pcie_dma" + str(i) + "_reader"] = getattr(self, "pcie_dma" + str(i)).reader.irq
  264.         for i, (k, v) in enumerate(sorted(self.interrupts.items())):
  265.             self.comb += self.pcie_msi.irqs[i].eq(v)
  266.             self.add_constant(k.upper() + "_INTERRUPT", i)
  267.         assert len(self.interrupts.keys()) <= 16
  268.  
  269.         # ICAP (For FPGA reload over PCIe).
  270.         self.submodules.icap = ICAP()
  271.         self.icap.add_reload()
  272.         self.icap.add_timing_constraints(platform, sys_clk_freq, self.crg.cd_sys.clk)
  273.  
  274.         # Flash (For SPIFlash update over PCIe). FIXME: Should probably be updated to use SpiFlashSingle/SpiFlashDualQuad (so MMAPed and do the update with bit-bangin>
  275.         self.submodules.flash_cs_n = GPIOOut(platform.request("flash_cs_n"))
  276.         self.submodules.flash      = S7SPIFlash(platform.request("flash"), sys_clk_freq, 25e6)
  277.  
  278.     def generate_documentation(self, build_name, **kwargs):
  279.         from litex.soc.doc import generate_docs
  280.         generate_docs(self, "documentation".format(build_name),
  281.             project_name = "LitePCIe standalone core",
  282.             author       = "Enjoy-Digital")
  283.         os.system("sphinx-build -M html documentation/ documentation/_build".format(build_name, build_name))
  284.  
  285. # Build --------------------------------------------------------------------------------------------
  286.  
  287. def main():
  288.     parser = argparse.ArgumentParser(description="LitePCIe standalone core generator")
  289.     parser.add_argument("config", help="YAML config file")
  290.     parser.add_argument("--doc",  action="store_true", help="Build documentation")
  291.     args = parser.parse_args()
  292.     core_config = yaml.load(open(args.config).read(), Loader=yaml.Loader)
  293.  
  294.     # Convert YAML elements to Python/LiteX --------------------------------------------------------
  295.     for k, v in core_config.items():
  296.         replaces = {"False": False, "True": True, "None": None}
  297.         for r in replaces.keys():
  298.             if v == r:
  299.                 core_config[k] = replaces[r]
  300.  
  301.     # Generate core --------------------------------------------------------------------------------
  302.     if core_config["phy"]  == "C5PCIEPHY":
  303.         from litex.build.altera import AlteraPlatform
  304.         from litepcie.phy.c5pciephy import C5PCIEPHY
  305.         platform = AlteraPlatform("", io=[])
  306.         core_config["phy"] = C5PCIEPHY
  307.     elif core_config["phy"] == "S7PCIEPHY":
  308.         from litex.build.xilinx import XilinxPlatform
  309.         from litepcie.phy.s7pciephy import S7PCIEPHY
  310.         platform = XilinxPlatform(core_config["phy_device"], io=[], toolchain="vivado")
  311.         core_config["phy"] = S7PCIEPHY
  312.     elif core_config["phy"] == "USPCIEPHY":
  313.         from litex.build.xilinx import XilinxPlatform
  314.         from litepcie.phy.uspciephy import USPCIEPHY
  315.         platform = XilinxPlatform(core_config["phy_device"], io=[], toolchain="vivado")
  316.         core_config["phy"] = USPCIEPHY
  317.     elif core_config["phy"] == "USPPCIEPHY":
  318.         from litex.build.xilinx import XilinxPlatform
  319.         from litepcie.phy.usppciephy import USPPCIEPHY
  320.         platform = XilinxPlatform(core_config["phy_device"], io=[], toolchain="vivado")
  321.         core_config["phy"] = USPPCIEPHY
  322.     else:
  323.         raise ValueError("Unsupported PCIe PHY: {}".format(core_config["phy"]))
  324.     soc      = LitePCIeCore(platform, core_config)
  325.     builder  = Builder(soc, output_dir="build", compile_gateware=False)
  326.     builder.build(build_name="litepcie_core", regular_comb=True)
  327.     generate_litepcie_software_headers(soc, "./")
  328.  
  329.     if args.doc:
  330.         soc.generate_documentation("litepcie_core")
  331.  
  332. if __name__ == "__main__":
  333.     main()
  334.  
Advertisement
Add Comment
Please, Sign In to add comment