From 322cc5d45bb9a7df96857de1fc48e6212a1ab07c Mon Sep 17 00:00:00 2001 From: Charles-Henri Mousset Date: Sat, 29 Apr 2023 18:32:02 +0200 Subject: [PATCH] [init] added colorlight i9+ based on XC7A50 FPGA --- litex_boards/platforms/colorlight_i9plus.py | 132 ++++++++++++++ litex_boards/targets/colorlight_i9plus.py | 186 ++++++++++++++++++++ 2 files changed, 318 insertions(+) create mode 100644 litex_boards/platforms/colorlight_i9plus.py create mode 100755 litex_boards/targets/colorlight_i9plus.py diff --git a/litex_boards/platforms/colorlight_i9plus.py b/litex_boards/platforms/colorlight_i9plus.py new file mode 100644 index 0000000..6b2e814 --- /dev/null +++ b/litex_boards/platforms/colorlight_i9plus.py @@ -0,0 +1,132 @@ +# +# This file is part of LiteX-Boards. +# +# Copyright (c) 2023 Charles-Henri Mousset +# SPDX-License-Identifier: BSD-2-Clause + +from litex.build.generic_platform import * +from litex.build.xilinx import Xilinx7SeriesPlatform +from litex.build.openocd import OpenOCD + +# IOs ---------------------------------------------------------------------------------------------- + +_io = [ + ("clk25", 0, Pins("K4"), IOStandard("LVCMOS33")), + ("user_led", 0, Pins("A18"), IOStandard("LVCMOS33")), + + # RGMII Ethernet (B50612D) + ("eth_clocks", 0, # U5 is SDIO phy #0 + Subsignal("tx", Pins("A1")), + Subsignal("rx", Pins("H4")), + IOStandard("LVCMOS33") + ), + ("eth", 0, + Subsignal("rst_n", Pins("H2")), + Subsignal("mdio", Pins("G2")), + Subsignal("mdc", Pins("G1")), + Subsignal("rx_ctl", Pins("F1")), + Subsignal("rx_data", Pins("E3 E2 E1 F3")), + Subsignal("tx_ctl", Pins("D1")), + Subsignal("tx_data", Pins("B2 B1 C2 D2")), + IOStandard("LVCMOS33") + ), + ("eth_clocks", 1, # U9 is SDIO phy #1 + Subsignal("tx", Pins("M6")), + Subsignal("rx", Pins("L3")), + IOStandard("LVCMOS33") + ), + ("eth", 1, + Subsignal("rst_n", Pins("H2")), + Subsignal("mdio", Pins("G2")), + Subsignal("mdc", Pins("G1")), + Subsignal("rx_ctl", Pins("R1")), + Subsignal("rx_data", Pins("N2 N3 P1 P2")), + Subsignal("tx_ctl", Pins("N5")), + Subsignal("tx_data", Pins("M5 M2 N4 P4")), + IOStandard("LVCMOS33") + ), + # M12L64322A + ("sdram_clock", 0, Pins("E14"), IOStandard("LVCMOS33")), + ("sdram", 0, + Subsignal("a", Pins( + "C20 C19 C13 F13 G13 G15 " + "F14 F18 E13 E18 C14 A13")), # address pin A11 routed but NC on M12L64322A + Subsignal("dq", Pins( + "F21 E22 F20 E21 F19 D22 E19 D21 " + "K21 L21 K22 M21 L20 M22 N20 M20 " + "B18 D20 A19 A21 A20 B21 C22 B22 " + "G21 G22 H20 H22 J20 J22 G20 J21 " + )), + Subsignal("we_n", Pins("D17")), + Subsignal("ras_n", Pins("A14")), + Subsignal("cas_n", Pins("D14")), + #Subsignal("cs_n", Pins("")), # gnd + #Subsignal("cke", Pins("")), # 3v3 + Subsignal("ba", Pins("D19 B13")), + #Subsignal("dm", Pins("")), # gnd + IOStandard("LVCMOS33"), + Misc("SLEWRATE=FAST") + ), +] + +# Connectors --------------------------------------------------------------------------------------- + +_connectors = [ + ("dimm", + "- " + "GND 5V GND 5V GND 5V GND 5V GND 5V " # 1-10 + "GND 5V NC NC ETH1_1P ETH2_1P ETH1_1N ETH2_1N NC NC " # 11-20 + "ETH1_2N ETH2_2N ETH1_2P ETH2_2P NC NC ETH1_3P ETH2_3P ETH1_3N ETH2_3N " # 21-30 + "NC NC ETH1_4N ETH2_4N ETH1_4P ETH2_4P NC NC GND GND " # 31-40 + "R2 P5 P6 T6 R6 U7 T1 U6 T3 U5 " # 41-50 + "T4 V5 T4 U1 GND GND U2 H3 U3 J1 " # 51-60 + "V2 K1 V3 L1 W1 M1 Y1 J2 AA1 K2 " # 61-70 + "AB1 K3 W2 G3 Y2 J4 AB2 G4 AA3 F4 " # 71-80 + "AB3 L4 Y3 R3 W4 M3 AA4 V4 Y4 R4 " # 81-90 + "AB5 T5 AA5 J5 Y6 J6 AB6 W5 AA6 L5 " # 91-100 + "Y7 L6 AB7 W6 GND GND GND GND AA8 V7 " # 101-110 + "AB8 N13 Y8 N14 W7 P15 Y9 P16 V8 R16 " # 111-120 + "W9 N17 V9 V17 R14 P17 P14 U17 W17 T18 " # 121-130 + "Y18 R17 AA18 U18 W19 R18 AB18 N18 Y19 R19 " # 131-140 + "AA19 N19 V18 N15 V19 M16 AB20 M15 AA20 L15 " # 141-150 + "AA21 L16 AB21 K14 Y21 N22 GND GND AB22 J14 " # 151-160 + "W20 J15 Y22 J19 W21 H13 W22 H14 V20 H17 " # 161-170 + "V22 H15 U21 G18 U20 G17 T20 G16 P19 F16 " # 171-180 + "P20 F15 M18 E17 L19 E16 J17 D16 K18 D15 " # 181-190 + "K19 C18 K16 C17 H18 B20 H19 B17 NC NC" # 191-200 + ) +] + + +def pmod_uart(port="P2"): + if port == "P2": + return [ + ("serial", 0, + Subsignal("tx", Pins("dimm:41")), + Subsignal("rx", Pins("dimm:51")), + IOStandard("LVCMOS33")) + ] + else: + raise ValueError(f"port {port} not in ['P2']") + +# Platform ----------------------------------------------------------------------------------------- + +class Platform(Xilinx7SeriesPlatform): + default_clk_name = "clk25" + default_clk_period = 1e9/25e6 + + def __init__(self, toolchain="vivado"): + Xilinx7SeriesPlatform.__init__(self, "xc7a50tfgg484-1", _io, _connectors, toolchain=toolchain) + self.toolchain.bitstream_commands = \ + ["set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 4 [current_design]"] + self.toolchain.additional_commands = \ + ["write_cfgmem -force -format bin -interface spix4 -size 16 " + "-loadbit \"up 0x0 {build_name}.bit\" -file {build_name}.bin"] + + + def create_programmer(self, cfg="openocd_xc7_ft2232.cfg"): + return OpenOCD(cfg, "bscan_spi_xc7a50t.bit") + + def do_finalize(self, fragment): + Xilinx7SeriesPlatform.do_finalize(self, fragment) + self.add_period_constraint(self.lookup_request(self.default_clk_name, loose=True), self.default_clk_period) diff --git a/litex_boards/targets/colorlight_i9plus.py b/litex_boards/targets/colorlight_i9plus.py new file mode 100755 index 0000000..aae6119 --- /dev/null +++ b/litex_boards/targets/colorlight_i9plus.py @@ -0,0 +1,186 @@ +#!/usr/bin/env python3 + +# +# This file is part of LiteX-Boards. +# +# Copyright (c) 2015-2019 Florent Kermarrec +# Copyright (c) 2020 Antmicro +# Copyright (c) 2022 Victor Suarez Rovere +# Copyright (c) 2023 Charles-Henri Mousset +# SPDX-License-Identifier: BSD-2-Clause + + +from migen import * + +from litex.gen import * + +from litex.build.io import DDROutput + +from litex_boards.platforms import colorlight_i9plus + +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.led import LedChaser +from litex.soc.cores.dna import DNA + +from litedram.modules import M12L64322A +from litedram.phy import GENSDRPHY + +from liteeth.phy.s7rgmii import LiteEthPHYRGMII + +# CRG ---------------------------------------------------------------------------------------------- + +class _CRG(LiteXModule): + def __init__(self, platform, sys_clk_freq, with_dram=True, with_ethernet=True): + self.rst = Signal() + self.cd_sys = ClockDomain() + self.cd_idelay = ClockDomain() + if with_dram: + self.cd_sys_ps = ClockDomain() + + # # # + + # Clk/Rst. + clk25 = platform.request("clk25") + + # PLL. + self.pll = pll = S7PLL(speedgrade=-1) + self.comb += pll.reset.eq(self.rst) + pll.register_clkin(clk25, 25e6) + pll.create_clkout(self.cd_sys, sys_clk_freq) + 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. + if with_dram: + pll.create_clkout(self.cd_sys_ps, sys_clk_freq, phase=90) # untested + # SDRAM clock + sdram_clk = ClockSignal("sys_ps") + self.specials += DDROutput(1, 0, platform.request("sdram_clock"), sdram_clk) + + self.idelayctrl = S7IDELAYCTRL(self.cd_idelay) + + +# BaseSoC ------------------------------------------------------------------------------------------ + +class BaseSoC(SoCCore): + def __init__(self, toolchain="vivado", sys_clk_freq=100e6, + with_dna = False, + with_pmod_uart = False, + with_ethernet = False, + with_etherbone = False, + eth_port = 0, + eth_ip = "192.168.1.50", + eth_dynamic_ip = False, + with_led_chaser = True, + with_jtagbone = True, + with_spi_flash = False, + **kwargs): + platform = colorlight_i9plus.Platform(toolchain=toolchain) + + # PMOD: uart on P2 (top) ------------------------------------------------------------------- + if with_pmod_uart: + platform.add_extension(colorlight_i9plus.pmod_uart()) + + # CRG -------------------------------------------------------------------------------------- + with_dram = (kwargs.get("integrated_main_ram_size", 0) == 0) + self.crg = _CRG(platform, sys_clk_freq, with_dram) + + # SoCCore ---------------------------------------------------------------------------------- + SoCCore.__init__(self, platform, sys_clk_freq, ident="LiteX SoC on Arty A7", **kwargs) + + # DNA -------------------------------------------------------------------------------------- + if with_dna: + self.dna = DNA() + self.dna.add_timing_constraints(platform, sys_clk_freq, self.crg.cd_sys.clk) + + # SDRAM ------------------------------------------------------------------------------------ + if not self.integrated_main_ram_size: + sdrphy_cls = GENSDRPHY + self.sdrphy = sdrphy_cls(platform.request("sdram")) + self.add_sdram("sdram", + phy = self.sdrphy, + module = M12L64322A(sys_clk_freq, "1:1"), + l2_cache_size = kwargs.get("l2_size", 8192) + ) + + + # Ethernet / Etherbone --------------------------------------------------------------------- + if with_ethernet or with_etherbone: + self.ethphy = LiteEthPHYRGMII( + clock_pads = self.platform.request("eth_clocks", eth_port), + pads = self.platform.request("eth", eth_port), + tx_delay = 0) + 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) + + # Jtagbone --------------------------------------------------------------------------------- + if with_jtagbone: + self.add_jtagbone() + + # SPI Flash -------------------------------------------------------------------------------- + if with_spi_flash: + from litespi.modules import MX25L12833F + from litespi.opcodes import SpiNorFlashOpCodes as Codes + self.add_spi_flash(mode="4x", module=MX25L12833F(Codes.READ_1_1_4), rate="1:2", with_master=True) + + # Leds ------------------------------------------------------------------------------------- + if with_led_chaser: + self.leds = LedChaser( + pads = platform.request_all("user_led"), + sys_clk_freq = sys_clk_freq, + ) + + +# Build -------------------------------------------------------------------------------------------- + +def main(): + from litex.build.parser import LiteXArgumentParser + parser = LiteXArgumentParser(platform=colorlight_i9plus.Platform, description="LiteX SoC on Arty A7.") + parser.add_target_argument("--flash", action="store_true", help="Flash bitstream.") + parser.add_target_argument("--sys-clk-freq", default=100e6, type=float, help="System clock frequency.") + parser.add_target_argument("--with-dna", action="store_true", help="Enable 7-Series DNA.") + parser.add_target_argument("--with-pmod-uart", action="store_true", help="Enable uart on P2 (top) PMOD") + ethopts = parser.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.") + parser.add_target_argument("--eth-port", default=0, type=int, help="Ethernet port to use (0/1)") + parser.add_target_argument("--eth-ip", default="192.168.1.50", help="Ethernet/Etherbone IP address.") + parser.add_target_argument("--eth-dynamic-ip", action="store_true", help="Enable dynamic Ethernet IP addresses setting.") + parser.add_target_argument("--with-jtagbone", action="store_true", help="Enable JTAGbone support.") + parser.add_target_argument("--with-spi-flash", action="store_true", help="Enable SPI Flash (MMAPed).") + args = parser.parse_args() + + assert not (args.with_etherbone and args.eth_dynamic_ip) + + soc = BaseSoC( + toolchain = args.toolchain, + sys_clk_freq = args.sys_clk_freq, + with_dna = args.with_dna, + with_pmod_uart = args.with_pmod_uart, + with_ethernet = args.with_ethernet, + with_etherbone = args.with_etherbone, + eth_port = args.eth_port, + eth_ip = args.eth_ip, + eth_dynamic_ip = args.eth_dynamic_ip, + with_jtagbone = args.with_jtagbone, + with_spi_flash = args.with_spi_flash, + **parser.soc_argdict + ) + + builder = Builder(soc, **parser.builder_argdict) + if args.build: + builder.build(**parser.toolchain_argdict) + + if args.load: + prog = soc.platform.create_programmer(cfg="prog/openocd_xc7_ft2232.cfg") + prog.load_bitstream(builder.get_bitstream_filename(mode="sram")) + + if args.flash: + prog = soc.platform.create_programmer(cfg="prog/openocd_xc7_ft2232.cfg") + prog.flash(0, builder.get_bitstream_filename(mode="flash")) + +if __name__ == "__main__": + main()