From d002059e0b2fe055ea6769dea857b1918b25b120 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Boczar?= Date: Mon, 2 Mar 2020 15:36:43 +0100 Subject: [PATCH] add Enclustra Mercury XU5 board --- litex_boards/platforms/mercury_xu5.py | 143 ++++++++++++++++++++++++++ litex_boards/targets/mercury_xu5.py | 111 ++++++++++++++++++++ 2 files changed, 254 insertions(+) create mode 100644 litex_boards/platforms/mercury_xu5.py create mode 100755 litex_boards/targets/mercury_xu5.py diff --git a/litex_boards/platforms/mercury_xu5.py b/litex_boards/platforms/mercury_xu5.py new file mode 100644 index 0000000..d32647f --- /dev/null +++ b/litex_boards/platforms/mercury_xu5.py @@ -0,0 +1,143 @@ +from litex.build.generic_platform import * +from litex.build.xilinx import XilinxPlatform, VivadoProgrammer + +# IOs ---------------------------------------------------------------------------------------------- + +_io = [ + ('clk100', 0, + Subsignal('n', Pins('AD4'), IOStandard('DIFF_SSTL12_DCI')), + Subsignal('p', Pins('AD5'), IOStandard('DIFF_SSTL12_DCI')), + ), + + ('clk100_gtr', 0, + Subsignal('p', Pins('C21'), IOStandard('DIFF_SSTL12')), + Subsignal('n', Pins('C22'), IOStandard('DIFF_SSTL12')), + ), + + ('clk27_gtr', 0, + Subsignal('p', Pins('A21'), IOStandard('DIFF_SSTL12')), + Subsignal('n', Pins('A22'), IOStandard('DIFF_SSTL12')), + ), + + ('clk33', 0, Pins('AD4'), IOStandard('SSTL12')), + + ('cpu_reset', 0, Pins('N19'), IOStandard('LVCMOS33')), + + ('user_led', 0, Pins('H2'), IOStandard('LVCMOS18')), + ('user_led', 1, Pins('P9'), IOStandard('LVCMOS18')), + ('user_led', 2, Pins('K5'), IOStandard('LVCMOS18')), + + ('serial', 0, + Subsignal('rx', Pins('AA10')), # Module connector A: A60 (Meccury PE1: "IO B" connector 32) + Subsignal('tx', Pins('AA11')), # Module connector A: A58 (Meccury PE1: "IO B" connector 31) + IOStandard('LVCMOS33'), + ), + + ('ddram', 0, # TODO: remove Misc with default settings + Subsignal('a', Pins( + 'AC4 AC3 AB4 AB3 AB2 AC2 AB1 AC1', + 'AB5 AG4 AH4 AG3 AH3 AE3'), IOStandard('SSTL12_DCI'), + Misc('OUTPUT_IMPEDANCE=RDRV_40_40'), + Misc('DATA_RATE=DDR'), + ), + Subsignal('we_n', Pins('AF3'), IOStandard('SSTL12_DCI'), # A14 + Misc('OUTPUT_IMPEDANCE=RDRV_40_40'), + Misc('DATA_RATE=DDR'), + ), + Subsignal('cas_n', Pins('AE2'), IOStandard('SSTL12_DCI'), # A15 + Misc('OUTPUT_IMPEDANCE=RDRV_40_40'), + Misc('DATA_RATE=DDR'), + ), + Subsignal('ras_n', Pins('AF2'), IOStandard('SSTL12_DCI'), # A16 + Misc('OUTPUT_IMPEDANCE=RDRV_40_40'), + Misc('DATA_RATE=DDR'), + ), + Subsignal('ba', Pins('AH1 AF1'), IOStandard('SSTL12_DCI'), + Misc('OUTPUT_IMPEDANCE=RDRV_40_40'), + Misc('DATA_RATE=DDR'), + ), + # Subsignal('bg', Pins('AG1 AD9'), IOStandard('SSTL12_DCI'), + Subsignal('bg', Pins('AG1'), IOStandard('SSTL12_DCI'), + Misc('OUTPUT_IMPEDANCE=RDRV_40_40'), + Misc('DATA_RATE=DDR'), + ), + Subsignal('cs_n', Pins('AH9'), IOStandard('SSTL12_DCI'), + Misc('OUTPUT_IMPEDANCE=RDRV_40_40'), + Misc('DATA_RATE=SDR'), + ), + Subsignal('act_n', Pins('AH2'), IOStandard('SSTL12_DCI'), + Misc('OUTPUT_IMPEDANCE=RDRV_40_40'), + Misc('DATA_RATE=DDR'), + ), + Subsignal('dm', Pins('AC9 AG9'), IOStandard('POD12_DCI'), + Misc('OUTPUT_IMPEDANCE=RDRV_40_40'), + # Misc('EQUALIZATION=EQ_LEVEL2'), + Misc('DATA_RATE=DDR'), + ), + Subsignal('dq', Pins( + 'AB6 AC6 AE9 AE8 AB8 AC8 AB7 AC7', + 'AE5 AF5 AF8 AG8 AH8 AH7 AF7 AF6'), IOStandard('POD12_DCI'), + Misc('PRE_EMPHASIS=RDRV_240'), + Misc('EQUALIZATION=EQ_LEVEL2'), + Misc('OUTPUT_IMPEDANCE=RDRV_40_40'), + Misc('DATA_RATE=DDR'), + Misc('ODT=RTT_40'), + ), + Subsignal('dqs_p', Pins('AD7 AG6'), IOStandard('DIFF_POD12_DCI'), + Misc('PRE_EMPHASIS=RDRV_240'), + Misc('EQUALIZATION=EQ_LEVEL2'), + Misc('OUTPUT_IMPEDANCE=RDRV_40_40'), + Misc('DATA_RATE=DDR'), + Misc('ODT=RTT_40'), + ), + Subsignal('dqs_n', Pins('AE7 AG5'), IOStandard('DIFF_POD12_DCI'), + Misc('PRE_EMPHASIS=RDRV_240'), + Misc('EQUALIZATION=EQ_LEVEL2'), + Misc('OUTPUT_IMPEDANCE=RDRV_40_40'), + Misc('DATA_RATE=DDR'), + Misc('ODT=RTT_40'), + ), + Subsignal('clk_p', Pins('AD2'), IOStandard('DIFF_SSTL12_DCI'), + Misc('OUTPUT_IMPEDANCE=RDRV_40_40'), + Misc('DATA_RATE=DDR'), + ), + Subsignal('clk_n', Pins('AD1'), IOStandard('DIFF_SSTL12_DCI'), + Misc('OUTPUT_IMPEDANCE=RDRV_40_40'), + Misc('DATA_RATE=DDR'), + ), + Subsignal('cke', Pins('AH6'), IOStandard('SSTL12_DCI'), + Misc('OUTPUT_IMPEDANCE=RDRV_40_40'), + Misc('DATA_RATE=DDR'), + ), + Subsignal('odt', Pins('AE4'), IOStandard('SSTL12_DCI'), + Misc('OUTPUT_IMPEDANCE=RDRV_40_40'), + Misc('DATA_RATE=DDR'), + ), + Subsignal('reset_n', Pins('G4'), IOStandard('LVCMOS18'), + Misc('DRIVE=8'), + ), + Misc('SLEW=FAST'), + ), +] + +# Connectors --------------------------------------------------------------------------------------- + +_connectors = [] + +# Platform ----------------------------------------------------------------------------------------- + +class Platform(XilinxPlatform): + default_clk_name = 'clk100' + default_clk_period = 1e9/100e6 + + def __init__(self): + XilinxPlatform.__init__(self, 'xczu2eg-sfvc784-1-i', _io, _connectors, toolchain='vivado') + + def create_programmer(self): + return VivadoProgrammer() + + def do_finalize(self, fragment): + XilinxPlatform.do_finalize(self, fragment) + self.add_platform_command('set_property BITSTREAM.CONFIG.OVERTEMPSHUTDOWN ENABLE [current_design]') + self.add_platform_command('set_property BITSTREAM.CONFIG.UNUSEDPIN PULLNONE [current_design]') + self.add_platform_command('set_property INTERNAL_VREF 0.600 [get_iobanks 64]') diff --git a/litex_boards/targets/mercury_xu5.py b/litex_boards/targets/mercury_xu5.py new file mode 100755 index 0000000..49e9453 --- /dev/null +++ b/litex_boards/targets/mercury_xu5.py @@ -0,0 +1,111 @@ +#!/usr/bin/env python3 + +import argparse + +from migen import * +from migen.genlib.io import CRG + +from litex_boards.platforms import mercury_xu5 + +from litex.soc.cores.clock import * +from litex.soc.integration.soc_sdram import * +from litex.soc.integration.builder import * + +from litedram.modules import MT40A256M16 +from litedram.phy import usddrphy + +# CRG ---------------------------------------------------------------------------------------------- + +class _CRG(Module): + def __init__(self, platform, sys_clk_freq): + self.clock_domains.cd_sys = ClockDomain() + self.clock_domains.cd_sys4x = ClockDomain(reset_less=True) + self.clock_domains.cd_pll4x = ClockDomain(reset_less=True) + self.clock_domains.cd_clk400 = ClockDomain() + self.clock_domains.cd_ic = ClockDomain() + + self.submodules.pll = pll = USMMCM(speedgrade=-1) + pll.register_clkin(platform.request("clk100"), 100e6) + + pll.create_clkout(self.cd_pll4x, sys_clk_freq*4, buf=None, with_reset=False) + pll.create_clkout(self.cd_clk400, 400e6, with_reset=False) + + self.specials += [ + Instance("BUFGCE_DIV", name="main_bufgce_div", + p_BUFGCE_DIVIDE=4, + i_CE=1, i_I=self.cd_pll4x.clk, o_O=self.cd_sys.clk), + Instance("BUFGCE", name="main_bufgce", + i_CE=1, i_I=self.cd_pll4x.clk, o_O=self.cd_sys4x.clk), + AsyncResetSynchronizer(self.cd_clk400, ~pll.locked), + ] + + ic_reset_counter = Signal(max=64, reset=63) + ic_reset = Signal(reset=1) + self.sync.clk400 += \ + If(ic_reset_counter != 0, + ic_reset_counter.eq(ic_reset_counter - 1) + ).Else( + ic_reset.eq(0) + ) + ic_rdy = Signal() + ic_rdy_counter = Signal(max=64, reset=63) + self.cd_sys.rst.reset = 1 + self.comb += self.cd_ic.clk.eq(self.cd_sys.clk) + self.sync.ic += [ + If(ic_rdy, + If(ic_rdy_counter != 0, + ic_rdy_counter.eq(ic_rdy_counter - 1) + ).Else( + self.cd_sys.rst.eq(0) + ) + ) + ] + self.specials += [ + Instance("IDELAYCTRL", p_SIM_DEVICE="ULTRASCALE", + i_REFCLK=ClockSignal("clk400"), i_RST=ic_reset, + o_RDY=ic_rdy), + AsyncResetSynchronizer(self.cd_ic, ic_reset) + ] + +# BaseSoC ------------------------------------------------------------------------------------------ + +class BaseSoC(SoCSDRAM): + def __init__(self, sys_clk_freq=int(100e6), **kwargs): + platform = mercury_xu5.Platform() + + # SoCSDRAM --------------------------------------------------------------------------------- + SoCSDRAM.__init__(self, platform, clk_freq=sys_clk_freq, **kwargs) + + # CRG -------------------------------------------------------------------------------------- + self.submodules.crg = _CRG(platform, sys_clk_freq) + + # DDR4 SDRAM ------------------------------------------------------------------------------- + if not self.integrated_main_ram_size: + self.submodules.ddrphy = usddrphy.USDDRPHY(platform.request("ddram"), + memtype = "DDR4", + sim_device = "ULTRASCALE_PLUS", + iodelay_clk_freq = 400e6, + cmd_latency = 1, + sys_clk_freq = sys_clk_freq) + self.add_csr("ddrphy") + self.add_constant("USDDRPHY", None) + sdram_module = MT40A256M16(sys_clk_freq, "1:4") + self.register_sdram(self.ddrphy, + geom_settings = sdram_module.geom_settings, + timing_settings = sdram_module.timing_settings) + +# Build -------------------------------------------------------------------------------------------- + +def main(): + parser = argparse.ArgumentParser(description="LiteX SoC on Enclustra's Mercury XU5") + builder_args(parser) + soc_sdram_args(parser) + args = parser.parse_args() + + soc = BaseSoC(**soc_sdram_argdict(args)) + builder = Builder(soc, **builder_argdict(args)) + builder.build() + + +if __name__ == "__main__": + main()