From 187080228ca8db27e2ca048533878a6911ef7f1d Mon Sep 17 00:00:00 2001 From: Hans Baier Date: Mon, 8 May 2023 05:17:35 +0700 Subject: [PATCH] add qmtech_xc7l325t --- litex_boards/platforms/qmtech_xc7k325t.py | 159 ++++++++++++ litex_boards/targets/qmtech_xc7k325t.py | 281 ++++++++++++++++++++++ 2 files changed, 440 insertions(+) create mode 100644 litex_boards/platforms/qmtech_xc7k325t.py create mode 100755 litex_boards/targets/qmtech_xc7k325t.py diff --git a/litex_boards/platforms/qmtech_xc7k325t.py b/litex_boards/platforms/qmtech_xc7k325t.py new file mode 100644 index 0000000..ba2ffe6 --- /dev/null +++ b/litex_boards/platforms/qmtech_xc7k325t.py @@ -0,0 +1,159 @@ +# +# This file is part of LiteX-Boards. +# +# SPDX-License-Identifier: BSD-2-Clause + +from litex.build.generic_platform import Pins, Subsignal, IOStandard, Misc +from litex.build.xilinx import XilinxPlatform +from litex.build.openocd import OpenOCD + +# IOs ---------------------------------------------------------------------------------------------- + +_io = [ + # Clk / Rst + ("clk50", 0, Pins("F22"), IOStandard("LVCMOS33")), + + # SPIFlash + # S25FL256L + #("spiflash4x", 0, # clock needs to be accessed through STARTUPE2 + # Subsignal("cs_n", Pins("C23")), + # Subsignal("clk", Pins("C8")), + # Subsignal("dq", Pins("B24", "A25", "B22", "A22")), + # IOStandard("LVCMOS33") + #), + + # DDR3 SDRAM + # MT41J128M16JT-125K + ("ddram", 0, + Subsignal("a", Pins("AF5 AF2 AD6 AC6 AD4 AB6 AE2 Y5 AA4 AE6 AE3 AD5 AB4 Y6"), + IOStandard("SSTL15")), + Subsignal("ba", Pins("AD3 AE1 AE5"), IOStandard("SSTL15")), + Subsignal("ras_n", Pins("AC3"), IOStandard("SSTL15")), + Subsignal("cas_n", Pins("AC4"), IOStandard("SSTL15")), + Subsignal("we_n", Pins("AF4"), IOStandard("SSTL15")), + #Subsignal("cs_n", Pins("--"), IOStandard("SSTL15")), + Subsignal("dm", Pins("V1 V3"), IOStandard("SSTL15")), + Subsignal("dq", Pins( + "W1 V2 Y1 Y3 AC2 Y2 AB2 AA3", + "U1 V4 U6 W3 V6 U2 U7 U5"), + IOStandard("SSTL15")), # _T_DCI")), + + Subsignal("dqs_p", Pins("AB1 W6"), IOStandard("DIFF_SSTL15")), # _T_DCI")), + Subsignal("dqs_n", Pins("AC1 W5"), IOStandard("DIFF_SSTL15")), # _T_DCI")), + + Subsignal("clk_p", Pins("AA5"), IOStandard("DIFF_SSTL15")), + Subsignal("clk_n", Pins("AB5"), IOStandard("DIFF_SSTL15")), + + Subsignal("cke", Pins("AD1"), IOStandard("SSTL15")), + Subsignal("odt", Pins("AF3"), IOStandard("SSTL15")), + Subsignal("reset_n", Pins("W4"), IOStandard("LVCMOS15")), + Misc("SLEW=FAST"), + ), +] + +# The connectors are named after the daughterboard, not the core board +# because on the different core boards the names vary, but on the +# daughterboard they stay the same, which we need to connect the +# daughterboard peripherals to the core board. +# On this board J2 is U5 and J3 is U4 +_connectors = [ + ("J2", { + # odd row even row + 7: "A8", 8: "A9", + 9: "B9", 10: "C9", + 11: "A10", 12: "B10", + 13: "D10", 14: "E10", + 15: "B11", 16: "B12", + 17: "C11", 18: "C12", + 19: "A12", 20: "A13", + 21: "D13", 22: "D14", + 23: "A14", 24: "B14", + 25: "C13", 26: "C14", + 27: "A15", 28: "B15", + 29: "D16", 30: "D15", + 31: "B16", 32: "C16", + 33: "A17", 34: "B17", + 35: "D18", 36: "E18", + 37: "C18", 38: "C17", + 39: "A19", 40: "A18", + 41: "B19", 42: "C19", + 43: "A20", 44: "B20", + 45: "D20", 46: "D19", + 47: "A24", 48: "A23", + 49: "E22", 50: "E21", + 51: "D24", 52: "D23", + 53: "D25", 54: "E25", + 55: "E26", 56: "F25", + 57: "B26", 58: "B25", + 59: "C26", 60: "D26", + }), + ("J3", { + # odd row even row + 7: "AD21", 8: "AE21", + 9: "AE22", 10: "AF22", + 11: "AE23", 12: "AF23", + 13: "V21", 14: "W21", + 15: "Y22", 16: "AA22", + 17: "AF24", 18: "AF25", + 19: "AB21", 20: "AC21", + 21: "AB22", 22: "AC22", + 23: "AD23", 24: "AD24", + 25: "AC23", 26: "AC24", + 27: "AD25", 28: "AE25", + 29: "AA23", 30: "AB24", + 31: "AA25", 32: "AB25", + 33: "Y23", 34: "AA24", + 35: "AD26", 36: "AE26", + 37: "AB26", 38: "AC26", + 39: "W23", 40: "W24", + 41: "Y25", 42: "Y26", + 43: "W25", 44: "W26", + 45: "U26", 46: "V26", + 47: "V23", 48: "V24", + 49: "U24", 50: "U25", + 51: "T22", 52: "T23", + 53: "R22", 54: "R23", + 55: "R25", 56: "P25", + 57: "P23", 58: "N23", + 59: "N26", 60: "M26", + }) +] + +# Platform ----------------------------------------------------------------------------------------- + +class Platform(XilinxPlatform): + default_clk_name = "clk50" + default_clk_period = 1e9/50e6 + + core_resources = [ + ("onboard_led_1", 0, Pins("J26"), IOStandard("LVCMOS33")), + ("onboard_led_2", 0, Pins("H26"), IOStandard("LVCMOS33")), + ("cpu_reset", 0, Pins("AD21"), IOStandard("LVCMOS33")), + ] + + def __init__(self, toolchain="yosys+nexpnr", with_daughterboard=False): + device = "xc7k325tffg676-1" + io = _io + connectors = _connectors + + io += self.core_resources + + if with_daughterboard: + from litex_boards.platforms.qmtech_daughterboard import QMTechDaughterboard + daughterboard = QMTechDaughterboard(IOStandard("LVCMOS33")) + io += daughterboard.io + connectors += daughterboard.connectors + + XilinxPlatform.__init__(self, device, io, connectors, toolchain=toolchain) + + self.add_platform_command("set_property INTERNAL_VREF 0.750 [get_iobanks 34]") + self.add_platform_command("set_property INTERNAL_VREF 0.90 [get_iobanks 33]") + + def create_programmer(self): + bscan_spi = "bscan_spi_xc7k325t.bit" + return OpenOCD("openocd_xc7_ft2232.cfg", bscan_spi) + + + def do_finalize(self, fragment): + XilinxPlatform.do_finalize(self, fragment) + self.add_period_constraint(self.lookup_request("clk50", loose=True), 1e9/50e6) diff --git a/litex_boards/targets/qmtech_xc7k325t.py b/litex_boards/targets/qmtech_xc7k325t.py new file mode 100755 index 0000000..c89d1b6 --- /dev/null +++ b/litex_boards/targets/qmtech_xc7k325t.py @@ -0,0 +1,281 @@ +#!/usr/bin/env python3 + +# +# This file is part of LiteX-Boards. +# +# SPDX-License-Identifier: BSD-2-Clause + +import os +import argparse + +from migen import * + +from litex_boards.platforms import qmtech_xc7k325t +from litex.build.xilinx.vivado import vivado_build_args, vivado_build_argdict + +from litex.soc.cores.clock import * +from litex.soc.integration.soc import SoCRegion +from litex.soc.integration.soc_core import * +from litex.soc.integration.builder import * +from litex.soc.cores.video import VideoVGAPHY +from litex.soc.cores.led import LedChaser + +from litedram.modules import MT41J128M16 +from litedram.phy import s7ddrphy + +from liteeth.phy.mii import LiteEthPHYMII + +# SevenSeg ----------------------------------------------------------------------------------------- +from migen.genlib.misc import WaitTimer +from litex.soc.interconnect.csr import * + +class SevenSeg(Module, AutoCSR): + def __init__(self, segs, sels, sys_clk_freq, period=1e-2): + self.segs = segs + self.sels = sels + + n = len(sels) + self._out = CSRStorage(4*n, description="7 Seg LEDs Control.") + xdigits = Signal(4*n) + select = Signal(n) + count = Signal(max=n) + table = [ + 0x3f, 0x06, 0x5b, 0x4f, + 0x66, 0x6d, 0x7d, 0x07, + 0x7f, 0x6f, 0x77, 0x7c, + 0x39, 0x5e, 0x79, 0x71 + ] + abcdefg = Signal(8) + hexa = Signal(4) + cases = {} + for i in range(16): + cases[i] = abcdefg.eq(table[i]) + + self.comb += Case(hexa, cases) + + timer = WaitTimer(int(period*sys_clk_freq/(2*n))) + self.submodules += timer + self.comb += timer.wait.eq(~timer.done) + self.sync += If(timer.done, + If(count == n-1, + count.eq(0), + select.eq(1 << (n-1)), + xdigits.eq(self._out.storage) + ).Else( + count.eq(count + 1), + select.eq(select >> 1), + xdigits.eq(xdigits >> 4) + ) + ) + self.comb += [ + hexa.eq(xdigits[0:4]), + segs.eq(~abcdefg), + sels.eq(select) + ] + + +# CRG ---------------------------------------------------------------------------------------------- + +class _CRG(Module): + def __init__(self, platform, sys_clk_freq, with_ethernet, with_vga): + self.rst = Signal() + self.clock_domains.cd_sys = ClockDomain() + 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.clock_domains.cd_eth = ClockDomain() + if with_ethernet: + self.clock_domains.cd_eth = ClockDomain() + if with_vga: + self.clock_domains.cd_vga = ClockDomain(reset_less=True) + + # # # + + self.submodules.pll = pll = S7PLL(speedgrade=-1) + reset_button = platform.request("cpu_reset") + self.comb += pll.reset.eq(~reset_button | self.rst) + + pll.register_clkin(platform.request("clk50"), 50e6) + pll.create_clkout(self.cd_sys, 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) + if with_ethernet: + pll.create_clkout(self.cd_eth, 25e6) + if with_vga: + pll.create_clkout(self.cd_vga, 40e6) + + 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, toolchain="yosys+nextpnr", sys_clk_freq=int(100e6), with_daughterboard=False, + with_ethernet=False, with_etherbone=False, eth_ip="192.168.1.50", eth_dynamic_ip=False, + local_ip="", remote_ip="", + with_led_chaser=True, with_video_terminal=False, with_video_framebuffer=False, with_video_colorbars=False, + with_jtagbone=True, with_spi_flash=False, **kwargs): + platform = qmtech_xc7k325t.Platform(toolchain=toolchain, with_daughterboard=with_daughterboard) + + # SoCCore ---------------------------------------------------------------------------------- + print(f"{str(kwargs)}") + if (kwargs["uart_name"] == "serial") and (not with_daughterboard): + kwargs["uart_name"] = "gpio_serial" + + SoCCore.__init__(self, platform, sys_clk_freq, + ident = "LiteX SoC on QMTech XC7K325T" + (" + Daughterboard" if with_daughterboard else ""), + **kwargs) + + # CRG -------------------------------------------------------------------------------------- + self.submodules.crg = _CRG(platform, sys_clk_freq, with_ethernet or with_etherbone, with_video_terminal or with_video_framebuffer or with_video_colorbars) + + # DDR3 SDRAM ------------------------------------------------------------------------------- + if not self.integrated_main_ram_size: + from litedram.common import PHYPadsReducer + self.submodules.ddrphy = s7ddrphy.A7DDRPHY( + pads = PHYPadsReducer(platform.request("ddram", 0), [0, 1]), + memtype = "DDR3", + nphases = 4, + sys_clk_freq = sys_clk_freq) + self.add_sdram("sdram", + phy = self.ddrphy, + module = MT41J128M16(sys_clk_freq, "1:4"), + l2_cache_size = kwargs.get("l2_size", 8192) + ) + + # Ethernet / Etherbone --------------------------------------------------------------------- + if with_ethernet or with_etherbone: + self.submodules.ethphy = LiteEthPHYMII( + clock_pads = self.platform.request("eth_clocks"), + pads = self.platform.request("eth")) + if with_ethernet: + self.add_ethernet(phy=self.ethphy, dynamic_ip=eth_dynamic_ip) + if with_etherbone: + self.add_etherbone(phy=self.ethphy, ip_address=eth_ip) + # The daughterboard has the tx clock wired to a non-clock pin, so we can't help it + #self.platform.add_platform_command("set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets eth_clocks_tx_IBUF]") + self.add_constant("TARGET_BIOS_INIT", 1) + + if local_ip: + local_ip = local_ip.split(".") + self.add_constant("LOCALIP1", int(local_ip[0])) + self.add_constant("LOCALIP2", int(local_ip[1])) + self.add_constant("LOCALIP3", int(local_ip[2])) + self.add_constant("LOCALIP4", int(local_ip[3])) + + if remote_ip: + remote_ip = remote_ip.split(".") + self.add_constant("REMOTEIP1", int(remote_ip[0])) + self.add_constant("REMOTEIP2", int(remote_ip[1])) + self.add_constant("REMOTEIP3", int(remote_ip[2])) + self.add_constant("REMOTEIP4", int(remote_ip[3])) + + # Jtagbone --------------------------------------------------------------------------------- + if with_jtagbone: + self.add_jtagbone() + + # SPI Flash -------------------------------------------------------------------------------- + if with_spi_flash: + from litespi.modules import MT25QL128 + from litespi.opcodes import SpiNorFlashOpCodes as Codes + self.add_spi_flash(mode="4x", module=MT25QL128(Codes.READ_1_1_1), with_master=True) + + # Video ------------------------------------------------------------------------------------ + if with_video_terminal or with_video_framebuffer or with_video_colorbars: + self.submodules.videophy = VideoVGAPHY(platform.request("vga"), clock_domain="vga") + if with_video_terminal: + self.add_video_terminal(phy=self.videophy, timings="800x600@60Hz", clock_domain="vga") + if with_video_framebuffer: + self.add_video_framebuffer(phy=self.videophy, timings="800x600@60Hz", clock_domain="vga", format="rgb565") + if with_video_colorbars: + self.add_video_colorbars(phy=self.videophy, timings="800x600@60Hz", clock_domain="vga") + + # Leds ------------------------------------------------------------------------------------- + if with_led_chaser: + self.submodules.leds = LedChaser( + pads = platform.request_all("user_led"), + sys_clk_freq = sys_clk_freq) + + self.submodules.sevenseg = SevenSeg( + segs = platform.request_all("seven_seg"), + sels = platform.request_all("seven_seg_ctl"), + sys_clk_freq = sys_clk_freq) + + if not with_daughterboard and kwargs["uart_name"] == "serial": + kwargs["uart_name"] = "jtag_serial" + +# Build -------------------------------------------------------------------------------------------- + +def main(): + parser = argparse.ArgumentParser(description="LiteX SoC on QMTech XC7K325T") + parser.add_argument("--toolchain", default="yosys+nextpnr", help="FPGA toolchain (vivado, symbiflow or yosys+nextpnr).") + parser.add_argument("--build", action="store_true", help="Build bitstream.") + parser.add_argument("--load", action="store_true", help="Load bitstream.") + parser.add_argument("--sys-clk-freq", default=100e6, help="System clock frequency.") + parser.add_argument("--with-daughterboard", action="store_true", help="Board plugged into the QMTech daughterboard.") + ethopts = parser.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.") + parser.add_argument("--eth-ip", default="192.168.1.50", type=str, help="Ethernet/Etherbone IP address.") + parser.add_argument("--eth-dynamic-ip", action="store_true", help="Enable dynamic Ethernet IP addresses setting.") + parser.add_argument("--remote-ip", default="192.168.1.100", + help="Remote IP address of TFTP server.") + parser.add_argument("--local-ip", default="192.168.1.50", + help="Local IP address.") + sdopts = parser.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.") + parser.add_argument("--with-jtagbone", action="store_true", help="Enable Jtagbone support.") + parser.add_argument("--with-spi-flash", action="store_true", help="Enable SPI Flash (MMAPed).") + viopts = parser.add_mutually_exclusive_group() + viopts.add_argument("--with-video-terminal", action="store_true", help="Enable Video Terminal (VGA).") + viopts.add_argument("--with-video-framebuffer", action="store_true", help="Enable Video Framebuffer (VGA).") + viopts.add_argument("--with-video-colorbars", action="store_true", help="Enable Video Colorbars (VGA).") + builder_args(parser) + soc_core_args(parser) + vivado_build_args(parser) + args = parser.parse_args() + + soc = BaseSoC( + toolchain = args.toolchain, + sys_clk_freq = int(float(args.sys_clk_freq)), + with_daughterboard = args.with_daughterboard, + with_ethernet = args.with_ethernet, + with_etherbone = args.with_etherbone, + eth_ip = args.eth_ip, + eth_dynamic_ip = args.eth_dynamic_ip, + local_ip = args.local_ip, + remote_ip = args.remote_ip, + with_jtagbone = args.with_jtagbone, + with_spi_flash = args.with_spi_flash, + with_video_terminal = args.with_video_terminal, + with_video_framebuffer = args.with_video_framebuffer, + with_video_colorbars = args.with_video_colorbars, + **soc_core_argdict(args) + ) + + if args.with_spi_sdcard: + soc.add_spi_sdcard() + if args.with_sdcard: + soc.add_sdcard() + + builder = Builder(soc, **builder_argdict(args)) + if args.with_ethernet or args.with_etherbone: + os.makedirs(os.path.join(builder.software_dir, "include/generated"), + exist_ok=True) + write_to_file( + os.path.join(builder.software_dir, "include/generated", "target.h"), + "// Force 100Base-T speed\n" + "#define TARGET_ETHPHY_INIT_FUNC() mdio_write(0, 0, 0x2100)") + + builder_kwargs = vivado_build_argdict(args) if args.toolchain == "vivado" else {} + builder.build(**builder_kwargs, 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()