From 75cadf845f3d2f5055f3f72c1430ee37b937492b Mon Sep 17 00:00:00 2001 From: Michael Mayers Date: Sat, 17 Jul 2021 22:03:17 -0600 Subject: [PATCH] add FPGA Boards 1. Digilent CMOD A7 https://reference.digilentinc.com/programmable-logic/cmod-a7/start 2. Digilent Nexys 4 https://reference.digilentinc.com/programmable-logic/nexys-4/start 3. MicroNova Mercury 2 https://www.micro-nova.com/mercury-2 --- litex_boards/platforms/digilent_cmod_a7.py | 80 ++++++ litex_boards/platforms/digilent_nexys4.py | 229 +++++++++++++++++ litex_boards/platforms/micronova_mercury2.py | 62 +++++ litex_boards/targets/digilent_cmod_a7.py | 174 +++++++++++++ litex_boards/targets/digilent_nexys4.py | 248 +++++++++++++++++++ litex_boards/targets/micronova_mercury2.py | 175 +++++++++++++ 6 files changed, 968 insertions(+) create mode 100644 litex_boards/platforms/digilent_cmod_a7.py create mode 100644 litex_boards/platforms/digilent_nexys4.py create mode 100644 litex_boards/platforms/micronova_mercury2.py create mode 100755 litex_boards/targets/digilent_cmod_a7.py create mode 100755 litex_boards/targets/digilent_nexys4.py create mode 100755 litex_boards/targets/micronova_mercury2.py diff --git a/litex_boards/platforms/digilent_cmod_a7.py b/litex_boards/platforms/digilent_cmod_a7.py new file mode 100644 index 0000000..9bd4deb --- /dev/null +++ b/litex_boards/platforms/digilent_cmod_a7.py @@ -0,0 +1,80 @@ +# +# This file is part of LiteX-Boards. +# +# Copyright (c) 2018 William D. Jones +# Copyright (c) 2020 Staf Verhaegen +# 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 + ("clk12", 0, Pins("L17"), IOStandard("LVCMOS33")), + + ## Buttons + ("cpu_reset", 0, Pins("A18"), IOStandard("LVCMOS33")), + ("user_btn", 0, Pins("B18"), IOStandard("LVCMOS33")), + + # Leds + ("user_led", 0, Pins("A17"), IOStandard("LVCMOS33")), + ("user_led", 1, Pins("C16"), IOStandard("LVCMOS33")), + + ("rgb_led", 0, + Subsignal("r", Pins("C17")), + Subsignal("g", Pins("B16")), + Subsignal("b", Pins("B17")), + IOStandard("LVCMOS33"), + ), + + # Serial + ("serial", 0, + Subsignal("tx", Pins("J18")), + Subsignal("rx", Pins("J17")), + IOStandard("LVCMOS33")), + + ("issiram", 0, + Subsignal( + "addr", + Pins("M18 M19 K17 N17 P17 P18 R18 W19", + "U19 V19 W18 T17 T18 U17 U18 V16", + "W16 W17 V15"), + IOStandard("LVCMOS33")), + Subsignal( + "data", + Pins("W15 W13 W14 U15 U16 V13 V14 U14"), + IOStandard("LVCMOS33")), + Subsignal("wen", Pins("R19"), IOStandard("LVCMOS33")), + Subsignal("cen", Pins("N19"), IOStandard("LVCMOS33")), + Misc("SLEW=FAST"), + ), + +] + +# Connectors --------------------------------------------------------------------------------------- +_connectors = [ +] + +# Platform ----------------------------------------------------------------------------------------- + +class Xc7A35t_Platform(XilinxPlatform): + def __init__(self, io, conns ): + XilinxPlatform.__init__(self, "xc7a35t-cpg236-1", io, conns, toolchain="vivado") + def do_finalize(self,fragment): + self.add_period_constraint(self.lookup_request("clk12", loose=True), self.default_clk_period) + +def get_platform(base_platform): + class the_platform(base_platform): + + def __init__(self): + self.default_clk_name = "clk12" + self.default_clk_period = 1e9/12e6 + base_platform.__init__(self,_io, _connectors) + + def do_finalize(self, fragment): + base_platform.do_finalize(self, fragment) + + return the_platform() \ No newline at end of file diff --git a/litex_boards/platforms/digilent_nexys4.py b/litex_boards/platforms/digilent_nexys4.py new file mode 100644 index 0000000..fa328e8 --- /dev/null +++ b/litex_boards/platforms/digilent_nexys4.py @@ -0,0 +1,229 @@ +# +# This file is part of LiteX-Boards. +# +# Copyright (c) 2018-2019 Florent Kermarrec +# SPDX-License-Identifier: BSD-2-Clause + +from litex.build.generic_platform import * +from litex.build.xilinx import XilinxPlatform, VivadoProgrammer +from litex.build.openocd import OpenOCD + +# IOs ---------------------------------------------------------------------------------------------- + +_io = [ + # Clk / Rst + ("clk100", 0, Pins("E3"), IOStandard("LVCMOS33")), + ("cpu_reset", 0, Pins("C12"), IOStandard("LVCMOS33")), + + # Leds + ("user_led", 0, Pins("T8"), IOStandard("LVCMOS33")), + ("user_led", 1, Pins("V9"), IOStandard("LVCMOS33")), + ("user_led", 2, Pins("R8"), IOStandard("LVCMOS33")), + ("user_led", 3, Pins("T6"), IOStandard("LVCMOS33")), + ("user_led", 4, Pins("T5"), IOStandard("LVCMOS33")), + ("user_led", 5, Pins("T4"), IOStandard("LVCMOS33")), + ("user_led", 6, Pins("U7"), IOStandard("LVCMOS33")), + ("user_led", 7, Pins("U6"), IOStandard("LVCMOS33")), + ("user_led", 8, Pins("V4"), IOStandard("LVCMOS33")), + ("user_led", 9, Pins("U3"), IOStandard("LVCMOS33")), + ("user_led", 10, Pins("V1"), IOStandard("LVCMOS33")), + ("user_led", 11, Pins("R1"), IOStandard("LVCMOS33")), + ("user_led", 12, Pins("P5"), IOStandard("LVCMOS33")), + ("user_led", 13, Pins("U1"), IOStandard("LVCMOS33")), + ("user_led", 14, Pins("R2"), IOStandard("LVCMOS33")), + ("user_led", 15, Pins("P2"), IOStandard("LVCMOS33")), + + # 7SEG DISPLAY + ("segled_an", 0, Pins("N6"), IOStandard("LVCMOS33")), + ("segled_an", 1, Pins("M6"), IOStandard("LVCMOS33")), + ("segled_an", 2, Pins("M3"), IOStandard("LVCMOS33")), + ("segled_an", 3, Pins("N5"), IOStandard("LVCMOS33")), + ("segled_an", 4, Pins("N2"), IOStandard("LVCMOS33")), + ("segled_an", 5, Pins("N4"), IOStandard("LVCMOS33")), + ("segled_an", 6, Pins("L1"), IOStandard("LVCMOS33")), + ("segled_an", 7, Pins("M1"), IOStandard("LVCMOS33")), + + ("segled_ca", 0, Pins("L3"), IOStandard("LVCMOS33")), + ("segled_cb", 0, Pins("N1"), IOStandard("LVCMOS33")), + ("segled_cc", 0, Pins("L5"), IOStandard("LVCMOS33")), + ("segled_cd", 0, Pins("L4"), IOStandard("LVCMOS33")), + ("segled_ce", 0, Pins("K3"), IOStandard("LVCMOS33")), + ("segled_cf", 0, Pins("M2"), IOStandard("LVCMOS33")), + ("segled_cg", 0, Pins("L6"), IOStandard("LVCMOS33")), + ("segled_dp", 0, Pins("M4"), IOStandard("LVCMOS33")), + + ("rgb_led", 0, + Subsignal("r", Pins("K6")), + Subsignal("g", Pins("H6")), + Subsignal("b", Pins("L16")), + IOStandard("LVCMOS33"), + ), + ("rgb_led", 1, + Subsignal("r", Pins("K5")), + Subsignal("g", Pins("F13")), + Subsignal("b", Pins("F6")), + IOStandard("LVCMOS33"), + ), + + # Switches + ("user_sw", 0, Pins("U9"), IOStandard("LVCMOS33")), + ("user_sw", 1, Pins("U8"), IOStandard("LVCMOS33")), + ("user_sw", 2, Pins("R7"), IOStandard("LVCMOS33")), + ("user_sw", 3, Pins("R6"), IOStandard("LVCMOS33")), + ("user_sw", 4, Pins("R5"), IOStandard("LVCMOS33")), + ("user_sw", 5, Pins("V7"), IOStandard("LVCMOS33")), + ("user_sw", 6, Pins("V6"), IOStandard("LVCMOS33")), + ("user_sw", 7, Pins("V5"), IOStandard("LVCMOS33")), + ("user_sw", 8, Pins("U4"), IOStandard("LVCMOS33")), + ("user_sw", 9, Pins("V2"), IOStandard("LVCMOS33")), + ("user_sw", 10, Pins("U2"), IOStandard("LVCMOS33")), + ("user_sw", 11, Pins("T3"), IOStandard("LVCMOS33")), + ("user_sw", 12, Pins("T1"), IOStandard("LVCMOS33")), + ("user_sw", 13, Pins("R3"), IOStandard("LVCMOS33")), + ("user_sw", 14, Pins("P3"), IOStandard("LVCMOS33")), + ("user_sw", 15, Pins("P4"), IOStandard("LVCMOS33")), + + # Buttons + ("user_btn", 0, Pins("T16"), IOStandard("LVCMOS33")), + ("user_btn", 1, Pins("R10"), IOStandard("LVCMOS33")), + ("user_btn", 2, Pins("F15"), IOStandard("LVCMOS33")), + ("user_btn", 3, Pins("V10"), IOStandard("LVCMOS33")), + ("user_btn", 4, Pins("E16"), IOStandard("LVCMOS33")), + + # Serial + ("serial", 0, + Subsignal("tx", Pins("D4")), + Subsignal("rx", Pins("C4")), + IOStandard("LVCMOS33"), + ), + + # SDCard + ("spisdcard", 0, + Subsignal("rst", Pins("E2")), + Subsignal("clk", Pins("B1")), + Subsignal("mosi", Pins("C1"), Misc("PULLUP True")), + Subsignal("cs_n", Pins("D2"), Misc("PULLUP True")), + Subsignal("miso", Pins("C2"), Misc("PULLUP True")), + Misc("SLEW=FAST"), + IOStandard("LVCMOS33"), + ), + ("sdcard", 0, + Subsignal("rst", Pins("E2"), Misc("PULLUP True")), + Subsignal("data", Pins("C2 E1 F1 D2"), Misc("PULLUP True")), + Subsignal("cmd", Pins("C1"), Misc("PULLUP True")), + Subsignal("clk", Pins("B1")), + Subsignal("cd", Pins("A1")), + Misc("SLEW=FAST"), + IOStandard("LVCMOS33"), + ), + + ("cellularram", 0, + Subsignal( + "addr", + Pins("J18 H17 H15 J17 H16 K15 K13 N15 V16 U14 V14 V12 P14 U16 R15 N14 N16 M13 V17 U17 T10 M16 U13"), + ), + Subsignal( + "data", + Pins("R12 T11 U12 R13 U18 R17 T18 R18 F18 G18 G17 M18 M17 P18 N17 P17"), + ), + Subsignal("oen", Pins("H14")), + Subsignal("wen", Pins("R11")), + Subsignal("clk", Pins("T15")), + Subsignal("adv", Pins("T13")), + Subsignal("wait", Pins("T14")), + Subsignal("cen", Pins("L18")), + Subsignal("ub", Pins("J13")), + Subsignal("lb", Pins("J15")), + Subsignal("cre", Pins("J14")), + Misc("SLEW=FAST"), + IOStandard("LVCMOS33"), + ), + + # RMII Ethernet + ("eth_clocks", 0, + Subsignal("ref_clk", Pins("D5")), + IOStandard("LVCMOS33"), + ), + + ("aud_pwm", 0, + Subsignal("pwm_out", Pins("A11")), + Subsignal("enable", Pins("D12")), + IOStandard("LVCMOS33"), + ), + + ("eth", 0, + Subsignal("rst_n", Pins("B3")), + Subsignal("rx_data", Pins("C11 D10")), + Subsignal("crs_dv", Pins("D9")), + Subsignal("tx_en", Pins("B9")), + Subsignal("tx_data", Pins("A10 A8")), + Subsignal("mdc", Pins("C9")), + Subsignal("mdio", Pins("A9")), + Subsignal("rx_er", Pins("C10")), + Subsignal("int_n", Pins("B8")), + IOStandard("LVCMOS33") + ), + + # VGA + ("vga", 0, + Subsignal("hsync_n", Pins("B11")), + Subsignal("vsync_n", Pins("B12")), + Subsignal("r", Pins("A4 C5 B4 A3")), + Subsignal("g", Pins("A6 B6 A5 C6")), + Subsignal("b", Pins("D7 C7 B7 D8")), + IOStandard("LVCMOS33") + ), +] + +# Connectors --------------------------------------------------------------------------------------- + +_connectors = [ + ("pmoda", "B13 F14 D17 E17 G13 C17 D18 E18"), + ("pmodb", "G14 P15 V11 V15 K16 R16 T9 U11"), + ("pmodc", "K2 E7 J3 J4 K1 E6 J2 G6"), + ("pmodd", "H4 H1 G1 G3 H2 G4 G2 F3"), + ("pmodxdac", "A13 A15 B16 B18 A14 A16 B17 A18"), +] + +# PMODS -------------------------------------------------------------------------------------------- + +def sdcard_pmod_io(pmod): + return [ + # SDCard PMOD: + # - https://store.digilentinc.com/pmod-microsd-microsd-card-slot/ + ("spisdcard", 0, + Subsignal("clk", Pins(f"{pmod}:3")), + Subsignal("mosi", Pins(f"{pmod}:1"), Misc("PULLUP True")), + Subsignal("cs_n", Pins(f"{pmod}:0"), Misc("PULLUP True")), + Subsignal("miso", Pins(f"{pmod}:2"), Misc("PULLUP True")), + Misc("SLEW=FAST"), + IOStandard("LVCMOS33"), + ), + ("sdcard", 0, + Subsignal("data", Pins(f"{pmod}:2 {pmod}:4 {pmod}:5 {pmod}:0"), Misc("PULLUP True")), + Subsignal("cmd", Pins(f"{pmod}:1"), Misc("PULLUP True")), + Subsignal("clk", Pins(f"{pmod}:3")), + Subsignal("cd", Pins(f"{pmod}:6")), + Misc("SLEW=FAST"), + IOStandard("LVCMOS33"), + ), +] +_sdcard_pmod_io = sdcard_pmod_io("pmodd") # SDCARD PMOD on JD. + +# Platform ----------------------------------------------------------------------------------------- + +class Platform(XilinxPlatform): + default_clk_name = "clk100" + default_clk_period = 1e9/100e6 + + def __init__(self): + XilinxPlatform.__init__(self, "xc7a100t-CSG324-1", _io, _connectors, toolchain="vivado") + self.add_platform_command("set_property INTERNAL_VREF 0.750 [get_iobanks 34]") + + def create_programmer(self): + return OpenOCD("openocd_xc7_ft2232.cfg", "bscan_spi_xc7a100t.bit") + + def do_finalize(self, fragment): + XilinxPlatform.do_finalize(self, fragment) + self.add_period_constraint(self.lookup_request("clk100", loose=True), 1e9/100e6) + self.add_period_constraint(self.lookup_request("eth_clocks:ref_clk", loose=True), 1e9/50e6) diff --git a/litex_boards/platforms/micronova_mercury2.py b/litex_boards/platforms/micronova_mercury2.py new file mode 100644 index 0000000..3c3a5dd --- /dev/null +++ b/litex_boards/platforms/micronova_mercury2.py @@ -0,0 +1,62 @@ +# +# This file is part of LiteX-Boards. +# +# Copyright (c) 2018 William D. Jones +# Copyright (c) 2020 Staf Verhaegen +# 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("N14"), IOStandard("LVCMOS33")), + + # Leds + ("user_led", 0, Pins("M1"), IOStandard("LVCMOS33")), + ("user_led", 1, Pins("A14"), IOStandard("LVCMOS33")), + ("user_led", 2, Pins("A13"), IOStandard("LVCMOS33")), + + # Serial + ("serial", 0, + Subsignal("tx", Pins("N11")), # BDBUS1 + Subsignal("rx", Pins("E11")), # BDBUS0 + IOStandard("LVCMOS33") + ), + + ("issiram", 0, + Subsignal("addr", Pins("M4 N3 N4 P3 M5 E5 D5 D3 B7 B4 J4 H4 H3 G4 E6 A7 A5 A4 C4"), IOStandard("LVCMOS33")), + Subsignal("data", Pins("L5 L3 L4 R2 F3 F4 E3 D6"), IOStandard("LVCMOS33")), + Subsignal("wen", Pins("R1"), IOStandard("LVCMOS33")), + Subsignal("cen", Pins("M6"), IOStandard("LVCMOS33")), + Misc("SLEW=FAST"), + ), +] + +# Connectors --------------------------------------------------------------------------------------- +_connectors = [ +] + +# Platform ----------------------------------------------------------------------------------------- + +class Xc7A35t_Platform(XilinxPlatform): + def __init__(self, io, conns ): + XilinxPlatform.__init__(self, "xc7a35tftg256-1", io, conns, toolchain="vivado") + def do_finalize(self,fragment): + self.add_period_constraint(self.lookup_request("clk50", loose=True), self.default_clk_period) + +def get_platform(base_platform): + class the_platform(base_platform): + + def __init__(self): + self.default_clk_name = "clk50" + self.default_clk_period = 1e9/50e6 + base_platform.__init__(self,_io, _connectors) + + def do_finalize(self, fragment): + base_platform.do_finalize(self, fragment) + + return the_platform() \ No newline at end of file diff --git a/litex_boards/targets/digilent_cmod_a7.py b/litex_boards/targets/digilent_cmod_a7.py new file mode 100755 index 0000000..9655e05 --- /dev/null +++ b/litex_boards/targets/digilent_cmod_a7.py @@ -0,0 +1,174 @@ +#!/usr/bin/env python3 + +# +# This file is part of LiteX-Boards. +# +# Copyright (c) 2020 Florent Kermarrec +# SPDX-License-Identifier: BSD-2-Clause + +import os +import sys +import argparse + +from migen import * + +from litex.build.io import CRG +from litex.build.xilinx.vivado import vivado_build_args, vivado_build_argdict + +from litex_boards.platforms import digilent_cmod_a7 + +#from litex.soc.cores.spi_flash import SpiFlash +from litex.soc.cores.clock import * +from litex.soc.integration.soc_core import * +from litex.soc.integration.soc import SoCRegion +from litex.soc.integration.builder import * +from litex.soc.cores.led import LedChaser +from litex.soc.interconnect import wishbone + +from litex.soc.integration.soc import colorer + +kB = 1024 +mB = 1024*kB + +class _CRG(Module): + def __init__(self, platform, sys_clk_freq): + self.rst = Signal() + self.cpu_reset = 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) + + # # # + + plls_clk12 = platform.request("clk12") + rst_n = platform.request("cpu_reset") + self.comb += self.cpu_reset.eq(rst_n) + + self.submodules.pll = pll = S7MMCM(speedgrade=-1) + self.comb += pll.reset.eq(self.cpu_reset | self.rst) + + pll.register_clkin(plls_clk12, 12e6) + 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) + + platform.add_false_path_constraints(self.cd_sys.clk, pll.clkin) # Ignore sys_clk to pll.clkin path created by SoC's rst. + +# AsyncSRAM ------------------------------------------------------------------------------------------ + +class AsyncSRAM(Module): + def __init__(self, platform, size): + addr_width = size//8 + data_width = 8 + self.bus = wishbone.Interface(data_width=data_width,adr_width=addr_width) + issiram = platform.request("issiram") + addr = issiram.addr + data = issiram.data + wen = issiram.wen + cen = issiram.cen + ######################## + tristate_data = TSTriple(data_width) + self.specials += tristate_data.get_tristate(data) + ######################## + chip_ena = self.bus.cyc & self.bus.stb & self.bus.sel[0] + write_ena = (chip_ena & self.bus.we) + ######################## + # external write enable, + # external chip enable, + # internal tristate write enable + ######################## + self.comb += [ + cen.eq(~chip_ena), + wen.eq(~write_ena), + tristate_data.oe.eq(write_ena) + ] + ######################## + # address and data + ######################## + self.comb += [ + addr.eq(self.bus.adr[:addr_width]), + self.bus.dat_r.eq(tristate_data.i[:data_width]), + tristate_data.o.eq(self.bus.dat_w[:data_width]) + ] + ######################## + # generate ack + ######################## + self.sync += [ + self.bus.ack.eq(self.bus.cyc & self.bus.stb & ~self.bus.ack), + ] + ######################## + +def addAsyncSram(soc, platform, name, origin, size): + ram_bus = wishbone.Interface(data_width=soc.bus.data_width) + ram = AsyncSRAM(platform,size) + soc.bus.add_slave(name, ram.bus, SoCRegion(origin=origin, size=size, mode="rw")) + soc.check_if_exists(name) + soc.logger.info("ISSIRAM {} {} {}.".format( + colorer(name), + colorer("added", color="green"), + soc.bus.regions[name])) + setattr(soc.submodules, name, ram) + +# BaseSoC ------------------------------------------------------------------------------------------ + +class BaseSoC(SoCCore): + def __init__(self, + variant="a7-35", + toolchain="vivado", + sys_clk_freq=int(100e6), + ident_version=True, + with_jtagbone=True, + with_mapped_flash=False, + **kwargs): + + xc7a35t_base = digilent_cmod_a7.Xc7A35t_Platform + platform = digilent_cmod_a7.get_platform(xc7a35t_base) + + # SoCCore ---------------------------------------------------------------------------------- + SoCCore.__init__(self, platform, sys_clk_freq, + ident = "LiteX SoC on Digilent CmodA7", + ident_version = True, + **kwargs) + + # CRG -------------------------------------------------------------------------------------- + + self.submodules.crg = _CRG(platform, sys_clk_freq) + + addAsyncSram(self,platform,"main_ram",0x40000000,512*1024) + + # 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 A7") + parser.add_argument("--toolchain", default="vivado", help="Toolchain use to build (default: vivado)") + 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="a7-35", help="Board variant: a7-35 (default) or a7-100") + parser.add_argument("--sys-clk-freq", default=48e6, help="System clock frequency (default: 48MHz)") + + builder_args(parser) + soc_core_args(parser) + vivado_build_args(parser) + args = parser.parse_args() + + soc = BaseSoC( + variant = args.variant, + toolchain = args.toolchain, + sys_clk_freq = int(float(args.sys_clk_freq)), + **soc_core_argdict(args) + ) + + builder_argd = builder_argdict(args) + + builder = Builder(soc, **builder_argd) + builder_kwargs = vivado_build_argdict(args) if args.toolchain == "vivado" else {} + builder.build(**builder_kwargs, run=args.build) + +if __name__ == "__main__": + main() diff --git a/litex_boards/targets/digilent_nexys4.py b/litex_boards/targets/digilent_nexys4.py new file mode 100755 index 0000000..af12e01 --- /dev/null +++ b/litex_boards/targets/digilent_nexys4.py @@ -0,0 +1,248 @@ +#!/usr/bin/env python3 + +# +# This file is part of LiteX-Boards. +# +# Copyright (c) 2020 Florent Kermarrec +# SPDX-License-Identifier: BSD-2-Clause + +import os +import sys +import argparse +import math + +from migen import * + +from litex.build.io import CRG + +from litex_boards.platforms import digilent_nexys4 + +#from litex.soc.cores.spi_flash import SpiFlash +from litex.soc.cores.clock import * +from litex.soc.integration.soc_core import * +from litex.soc.integration.soc import SoCRegion +from litex.soc.integration.builder import * +from litex.soc.cores.led import LedChaser +from litex.soc.interconnect import wishbone + +from litex.soc.integration.soc import colorer +from litex.soc.cores.video import VideoVGAPHY +from liteeth.phy.rmii import LiteEthPHYRMII + + +# 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_sys2x_dqs = ClockDomain(reset_less=True) + self.clock_domains.cd_idelay = ClockDomain() + self.clock_domains.cd_eth = ClockDomain() + self.clock_domains.cd_vga = ClockDomain(reset_less=True) + # # # + + self.submodules.pll = pll = S7MMCM(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_sys2x_dqs, 2*sys_clk_freq, phase=90) + pll.create_clkout(self.cd_idelay, 200e6) + pll.create_clkout(self.cd_eth, 50e6) + 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) + +# CellularRAM (https://media.digikey.com/PDF/Data%20Sheets/Micron%20Technology%20Inc%20PDFs/MT45W8MW16BGX.pdf) + +class CellularRAM(Module): + def __init__(self, soc, platform): + + sys_clk_freq = soc.sys_clk_freq + + addr_width = 23 + data_width = 16 + + delay_for_70ns = (70e-9) / (1.0/sys_clk_freq) + delay_for_70ns = int(math.ceil(delay_for_70ns))+1 + + #print("sys_clk_freq<%g> delay_for_70ns<%g>\n"%(sys_clk_freq,delay_for_70ns)) + + self.bus = wishbone.Interface(data_width=data_width,adr_width=addr_width) + + self.delaycounter = Signal(5) + + cellram = platform.request("cellularram") + addr = cellram.addr + data = cellram.data + wen = cellram.wen + oen = cellram.oen + cen = cellram.cen + clk = cellram.clk + cre = cellram.cre + adv = cellram.adv # address valid (low) + lb = cellram.lb + ub = cellram.ub + ######################## + tristate_data = TSTriple(data_width) + self.specials += tristate_data.get_tristate(data) + ######################## + i_rst = ResetSignal("sys") + fsm = FSM(reset_state="RESET") + fsm = ResetInserter()(fsm) + self.submodules.fsm = fsm + self.sync += fsm.reset.eq(i_rst) + ######################## + fsm.act("RESET", + NextState("INIT")) + ######################## + fsm.act("INIT", + NextValue(self.delaycounter,0), + NextValue(self.bus.ack,0), + NextValue(cen,1), + NextValue(adv,1), + NextValue(lb,1), + NextValue(ub,1), + NextValue(clk,0), + NextValue(cre,0), + NextValue(tristate_data.oe,0), + NextState("IDLE")) + ######################## + fsm.act("IDLE", + If(self.bus.stb & self.bus.cyc, + + NextValue(lb,~self.bus.sel[0]), + NextValue(ub,~self.bus.sel[1]), + + NextValue(self.delaycounter,0), + NextValue(cen,0), + NextValue(adv,0), + NextValue(addr,self.bus.adr[:addr_width]), + If(self.bus.we, + NextValue(wen,0), + NextValue(oen,1), + NextValue(tristate_data.oe,1), + NextValue(tristate_data.o,self.bus.dat_w[:data_width]), + NextState("WRITE") + ).Else( + NextValue(wen,1), + NextValue(oen,0), + NextValue(tristate_data.oe,0), + NextState("READ") + ) + ) + ) + ######################## + fsm.act("WRITE", + NextValue(self.delaycounter,self.delaycounter+1), + If(self.delaycounter==delay_for_70ns, + NextValue(self.bus.ack,1), + NextState("INIT")) + ) + ######################## + fsm.act("READ", + NextValue(self.delaycounter,self.delaycounter+1), + NextValue(self.bus.dat_r,tristate_data.i[:data_width]), + If(self.delaycounter==delay_for_70ns, + NextValue(self.bus.ack,1), + NextState("INIT")) + ) + ######################## + +def addCellularRAM(soc, platform, name, origin): + size = 16*1024*1024 + ram_bus = wishbone.Interface(data_width=soc.bus.data_width) + ram = CellularRAM(soc,platform) + soc.bus.add_slave(name, ram.bus, SoCRegion(origin=origin, size=size, mode="rw")) + soc.check_if_exists(name) + soc.logger.info("CELLULARRAM {} {} {}.".format( + colorer(name), + colorer("added", color="green"), + soc.bus.regions[name])) + setattr(soc.submodules, name, ram) + + +# BaseSoC ------------------------------------------------------------------------------------------ + +class BaseSoC(SoCCore): + def __init__(self, sys_clk_freq=int(75e6), with_ethernet=False, with_etherbone=False, with_video_terminal=False, with_video_framebuffer=False, **kwargs): + platform = digilent_nexys4.Platform() + + # SoCCore ----------------------------------_----------------------------------------------- + SoCCore.__init__(self, platform, sys_clk_freq, + ident = "LiteX SoC on Nexys4", + **kwargs) + + # CRG -------------------------------------------------------------------------------------- + self.submodules.crg = _CRG(platform, sys_clk_freq) + + # Cellular RAM ------------------------------------------------------------------------------- + addCellularRAM(self,platform,"main_ram",0x40000000) + + # Ethernet / Etherbone --------------------------------------------------------------------- + if with_ethernet or with_etherbone: + self.submodules.ethphy = LiteEthPHYRMII( + clock_pads = self.platform.request("eth_clocks"), + pads = self.platform.request("eth")) + if with_ethernet: + self.add_ethernet(phy=self.ethphy) + if with_etherbone: + self.add_etherbone(phy=self.ethphy) + + # Video ------------------------------------------------------------------------------------ + if with_video_terminal or with_video_framebuffer: + 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") + + # 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 Nexys4") + 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=75e6, help="System clock frequency (default: 75MHz)") + 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") + 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") + 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)") + builder_args(parser) + soc_core_args(parser) + args = parser.parse_args() + + soc = BaseSoC( + sys_clk_freq = int(float(args.sys_clk_freq)), + with_ethernet = args.with_ethernet, + with_etherbone = args.with_etherbone, + with_video_terminal = args.with_video_terminal, + with_video_framebuffer = args.with_video_framebuffer, + **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)) + builder.build(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() diff --git a/litex_boards/targets/micronova_mercury2.py b/litex_boards/targets/micronova_mercury2.py new file mode 100755 index 0000000..d426ec5 --- /dev/null +++ b/litex_boards/targets/micronova_mercury2.py @@ -0,0 +1,175 @@ +#!/usr/bin/env python3 + +# +# This file is part of LiteX-Boards. +# +# Copyright (c) 2020 Florent Kermarrec +# SPDX-License-Identifier: BSD-2-Clause + +import os +import sys +import argparse + +from migen import * + +from litex.build.io import CRG + +from litex_boards.platforms import micronova_mercury2 +from litex.build.xilinx.vivado import vivado_build_args, vivado_build_argdict + +#from litex.soc.cores.spi_flash import SpiFlash +from litex.soc.cores.clock import * +from litex.soc.integration.soc_core import * +from litex.soc.integration.soc import SoCRegion +from litex.soc.integration.builder import * +from litex.soc.cores.led import LedChaser +from litex.soc.interconnect import wishbone + +from litex.soc.integration.soc import colorer + +kB = 1024 +mB = 1024*kB + +class _CRG(Module): + def __init__(self, platform, sys_clk_freq): + 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) + + # # # + + #plls_reset = platform.request("cpu_reset") + plls_clk50 = platform.request("clk50") + + self.submodules.pll = pll = S7MMCM(speedgrade=-1) + self.comb += pll.reset.eq(self.rst) + pll.register_clkin(plls_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) + + platform.add_false_path_constraints(self.cd_sys.clk, pll.clkin) # Ignore sys_clk to pll.clkin path created by SoC's rst. + +# AsyncSRAM ------------------------------------------------------------------------------------------ + +class AsyncSRAM(Module): + def __init__(self, platform, size): + addr_width = size//8 + data_width = 8 + self.bus = wishbone.Interface(data_width=data_width,adr_width=addr_width) + issiram = platform.request("issiram") + addr = issiram.addr + data = issiram.data + wen = issiram.wen + cen = issiram.cen + ######################## + tristate_data = TSTriple(data_width) + self.specials += tristate_data.get_tristate(data) + ######################## + chip_ena = self.bus.cyc & self.bus.stb & self.bus.sel[0] + write_ena = (chip_ena & self.bus.we) + ######################## + # external write enable, + # external chip enable, + # internal tristate write enable + ######################## + self.comb += [ + cen.eq(~chip_ena), + wen.eq(~write_ena), + tristate_data.oe.eq(write_ena) + ] + ######################## + # address and data + ######################## + self.comb += [ + addr.eq(self.bus.adr[:addr_width]), + self.bus.dat_r.eq(tristate_data.i[:data_width]), + tristate_data.o.eq(self.bus.dat_w[:data_width]) + ] + ######################## + # generate ack + ######################## + self.sync += [ + self.bus.ack.eq(self.bus.cyc & self.bus.stb & ~self.bus.ack), + ] + ######################## + +def addAsyncSram(soc, platform, name, origin, size): + ram_bus = wishbone.Interface(data_width=soc.bus.data_width) + ram = AsyncSRAM(platform,size) + soc.bus.add_slave(name, ram.bus, SoCRegion(origin=origin, size=size, mode="rw")) + soc.check_if_exists(name) + soc.logger.info("ISSIRAM {} {} {}.".format( + colorer(name), + colorer("added", color="green"), + soc.bus.regions[name])) + setattr(soc.submodules, name, ram) + +# BaseSoC ------------------------------------------------------------------------------------------ + +class BaseSoC(SoCCore): + def __init__(self, + variant="a7-35", + toolchain="vivado", + sys_clk_freq=int(100e6), + ident_version=True, + with_jtagbone=True, + with_mapped_flash=False, + enable_leds = True, + **kwargs): + + xc7a35t_base = micronova_mercury2.Xc7A35t_Platform + platform = micronova_mercury2.get_platform(xc7a35t_base) + + # SoCCore ---------------------------------------------------------------------------------- + SoCCore.__init__(self, platform, sys_clk_freq, + ident = "LiteX SoC on MicroNova Mercury2", + ident_version = True, + **kwargs) + + # CRG -------------------------------------------------------------------------------------- + + self.submodules.crg = _CRG(platform, sys_clk_freq) + + addAsyncSram(self,platform,"main_ram",0x40000000,512*1024) + + #self.add_timer() + + # Leds ------------------------------------------------------------------------------------- + if enable_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 MicroNova Mercury2") + parser.add_argument("--toolchain", default="vivado", help="Toolchain use to build (default: vivado)") + 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="a7-35", help="Board variant: a7-35 (default) or a7-100") + parser.add_argument("--sys-clk-freq", default=50e6, help="System clock frequency (default: 50MHz)") + + builder_args(parser) + soc_core_args(parser) + vivado_build_args(parser) + args = parser.parse_args() + + soc = BaseSoC( + variant = args.variant, + toolchain = args.toolchain, + sys_clk_freq = int(float(args.sys_clk_freq)), + **soc_core_argdict(args) + ) + + builder_argd = builder_argdict(args) + + builder = Builder(soc, **builder_argd) + builder_kwargs = vivado_build_argdict(args) if args.toolchain == "vivado" else {} + builder.build(**builder_kwargs, run=args.build) + +if __name__ == "__main__": + main() +