diff --git a/litex_boards/platforms/digilent_atlys.py b/litex_boards/platforms/digilent_atlys.py new file mode 100644 index 0000000..af73fc1 --- /dev/null +++ b/litex_boards/platforms/digilent_atlys.py @@ -0,0 +1,235 @@ +# +# This file is part of LiteX-Boards. +# +# Copyright (c) 2015-2021 HDMI2USB/LiteX developers +# SPDX-License-Identifier: BSD-2-Clause + +from litex.build.generic_platform import * +from litex.build.xilinx import XilinxPlatform + +# IOs ---------------------------------------------------------------------------------------------- + +_io = [ + # Clk/Rst + ("clk100", 0, Pins("L15"), IOStandard("LVCMOS33")), + ("cpu_reset", 0, Pins("T15"), IOStandard("LVCMOS33")), + + # Serial + ("serial", 0, + Subsignal("rx", Pins("A16"), IOStandard("LVCMOS33")), + Subsignal("tx", Pins("B16"), IOStandard("LVCMOS33")), + ), + + # FX2 + ("fx2", 0, + Subsignal("ifclk", Pins("C10")), + Subsignal("data", Pins("A2 D6 C6 B3 A3 B4 A4 C5")), + Subsignal("addr", Pins("A14 B14"), Misc("DRIVE=12")), + Subsignal("flaga", Pins("B9"), Misc("DRIVE=12")), + Subsignal("flagb", Pins("A9"), Misc("DRIVE=12")), + Subsignal("flagc", Pins("C15"), Misc("DRIVE=12")), + Subsignal("rd_n", Pins("F13"), Misc("DRIVE=12")), + Subsignal("wr_n", Pins("E13")), + Subsignal("oe_n", Pins("A15"), Misc("DRIVE=12")), + Subsignal("cs_n", Pins("B2")), + Subsignal("pktend_n", Pins("C4"), Misc("DRIVE=12")), + IOStandard("LVCMOS33") + ), + + # SPI Flash + ("spiflash4x", 0, + Subsignal("cs_n", Pins("V3")), + Subsignal("clk", Pins("R15")), + Subsignal("dq", Pins("T13", "R13", "T14", "V14")), + IOStandard("LVCMOS33"), + Misc("SLEW=FAST"), + ), + + # Leds + ("user_led", 0, Pins("U18"), IOStandard("LVCMOS33")), + ("user_led", 1, Pins("M14"), IOStandard("LVCMOS33")), + ("user_led", 2, Pins("N14"), IOStandard("LVCMOS33")), + ("user_led", 3, Pins("L14"), IOStandard("LVCMOS33")), + ("user_led", 4, Pins("M13"), IOStandard("LVCMOS33")), + ("user_led", 5, Pins("D4"), IOStandard("LVCMOS33")), + ("user_led", 6, Pins("P16"), IOStandard("LVCMOS33")), + ("user_led", 7, Pins("N12"), IOStandard("LVCMOS33")), + + # Buttons + ("user_btn", 0, Pins("N4"), IOStandard("LVCMOS18")), # North button + ("user_btn", 1, Pins("P4"), IOStandard("LVCMOS18")), # East button + ("user_btn", 2, Pins("P3"), IOStandard("LVCMOS18")), # South button + ("user_btn", 3, Pins("F6"), IOStandard("LVCMOS18")), # West button + ("user_btn", 4, Pins("F5"), IOStandard("LVCMOS18")), # Center button + + # Switches. + ("user_sw", 0, Pins("A10"), IOStandard("LVCMOS33")), + ("user_sw", 1, Pins("D14"), IOStandard("LVCMOS33")), + ("user_sw", 2, Pins("C14"), IOStandard("LVCMOS33")), + ("user_sw", 3, Pins("P15"), IOStandard("LVCMOS33")), + ("user_sw", 4, Pins("P12"), IOStandard("LVCMOS33")), + ("user_sw", 5, Pins("R5"), IOStandard("LVCMOS33")), + ("user_sw", 6, Pins("T5"), IOStandard("LVCMOS33")), + ("user_sw", 7, Pins("E4"), IOStandard("LVCMOS18")), + + # GMII/MII Ethernet + ("eth_clocks", 0, + Subsignal("tx", Pins("K16")), + Subsignal("gtx", Pins("L12")), + Subsignal("rx", Pins("K15")), + IOStandard("LVCMOS33") + ), + ("eth", 0, + Subsignal("rst_n", Pins("G13")), + Subsignal("int_n", Pins("L16")), + Subsignal("mdio", Pins("N17")), + Subsignal("mdc", Pins("F16")), + Subsignal("rx_dv", Pins("F17")), + Subsignal("rx_er", Pins("F18")), + Subsignal("rx_data", Pins("G16 H14 E16 F15 F14 E18 D18 D17")), + Subsignal("tx_en", Pins("H15")), + Subsignal("tx_er", Pins("G18")), + Subsignal("tx_data", Pins("H16 H13 K14 K13 J13 G14 H12 K12")), + Subsignal("col", Pins("C17")), + Subsignal("crs", Pins("C18")), + IOStandard("LVCMOS33") + ), + + # DDR2 SDRAM. + ("ddram_clock", 0, + Subsignal("p", Pins("G3")), + Subsignal("n", Pins("G1")), + IOStandard("DIFF_SSTL18_II"), Misc("IN_TERM=NONE") + ), + ("ddram", 0, + Subsignal("cke", Pins("H7"), IOStandard("SSTL18_II")), + Subsignal("ras_n", Pins("L5"), IOStandard("SSTL18_II")), + Subsignal("cas_n", Pins("K5"), IOStandard("SSTL18_II")), + Subsignal("we_n", Pins("E3"), IOStandard("SSTL18_II")), + Subsignal("ba", Pins("F2 F1 E1"), IOStandard("SSTL18_II")), + Subsignal("a", Pins( + "J7 J6 H5 L7 F3 H4 H3 H6", + "D2 D1 F4 D3 G6"), + IOStandard("SSTL18_II")), + Subsignal("dq", Pins( + "L2 L1 K2 K1 H2 H1 J3 J1", + "M3 M1 N2 N1 T2 T1 U2 U1"), + IOStandard("SSTL18_II")), + Subsignal("dqs", Pins("P2 L4"), IOStandard("DIFF_SSTL18_II")), + Subsignal("dqs_n", Pins("P1 L3"), IOStandard("DIFF_SSTL18_II")), + Subsignal("dm", Pins("K4 K3"), IOStandard("SSTL18_II")), + Subsignal("odt", Pins("K6"), IOStandard("SSTL18_II")) + ), + + # HDMI Out 0 + ("hdmi_out", 0, + Subsignal("clk_p", Pins("B6"), IOStandard("TMDS_33")), + Subsignal("clk_n", Pins("A6"), IOStandard("TMDS_33")), + Subsignal("data0_p", Pins("D8"), IOStandard("TMDS_33")), + Subsignal("data0_n", Pins("C8"), IOStandard("TMDS_33")), + Subsignal("data1_p", Pins("C7"), IOStandard("TMDS_33")), + Subsignal("data1_n", Pins("A7"), IOStandard("TMDS_33")), + Subsignal("data2_p", Pins("B8"), IOStandard("TMDS_33")), + Subsignal("data2_n", Pins("A8"), IOStandard("TMDS_33")), + Subsignal("scl", Pins("D9"), IOStandard("I2C")), + Subsignal("sda", Pins("C9"), IOStandard("I2C")), + ), + + # HDMI In 0 + ("hdmi_in", 0, + Subsignal("clk_p", Pins("D11")), + Subsignal("clk_n", Pins("C11")), + Subsignal("data0_p", Pins("G9")), + Subsignal("data0_n", Pins("F9")), + Subsignal("data1_p", Pins("B11")), + Subsignal("data1_n", Pins("A11")), + Subsignal("data2_p", Pins("B12")), + Subsignal("data2_n", Pins("A12")), + Subsignal("scl", Pins("C13"), IOStandard("LVCMOS33")), + Subsignal("sda", Pins("A13"), IOStandard("LVCMOS33")), + ), + + # HDMI In 1 + ("hdmi_in", 1, + Subsignal("clk_p", Pins("H17")), + Subsignal("clk_n", Pins("H18")), + Subsignal("data0_p", Pins("K17")), + Subsignal("data0_n", Pins("K18")), + Subsignal("data1_p", Pins("L17")), + Subsignal("data1_n", Pins("L18")), + Subsignal("data2_p", Pins("J16")), + Subsignal("data2_n", Pins("J18")), + Subsignal("scl", Pins("M16"), IOStandard("LVCMOS33")), + Subsignal("sda", Pins("M18"), IOStandard("LVCMOS33")), + ), +] + +# Connectors --------------------------------------------------------------------------------------- + +_connectors = [ + ("VHDCI", + { + "EXP-IO1_P" : "U16", + "EXP-IO2_P" : "U15", + "EXP-IO3_P" : "U13", + "EXP-IO4_P" : "M11", + "EXP-IO5_P" : "R11", + "EXP-IO6_P" : "T12", + "EXP-IO7_P" : "N10", + "EXP-IO8_P" : "M10", + "EXP-IO9_P" : "U11", + "EXP-IO10_P" : "R10", + "EXP-IO11_P" : "U10", + "EXP-IO12_P" : "R8", + "EXP-IO13_P" : "M8", + "EXP-IO14_P" : "U8", + "EXP-IO15_P" : "U7", + "EXP-IO16_P" : "N7", + "EXP-IO17_P" : "T6", + "EXP-IO18_P" : "R7", + "EXP-IO19_P" : "N6", + "EXP-IO20_P" : "U5", + "EXP-IO1_N" : "V16", + "EXP-IO2_N" : "V15", + "EXP-IO3_N" : "V13", + "EXP-IO4_N" : "N11", + "EXP-IO5_N" : "T11", + "EXP-IO6_N" : "V12", + "EXP-IO7_N" : "P11", + "EXP-IO8_N" : "N9", + "EXP-IO9_N" : "V11", + "EXP-IO10_N" : "T10", + "EXP-IO11_N" : "V10", + "EXP-IO12_N" : "T8", + "EXP-IO13_N" : "N8", + "EXP-IO14_N" : "V8", + "EXP-IO15_N" : "V7", + "EXP-IO16_N" : "P8", + "EXP-IO17_N" : "V6", + "EXP-IO18_N" : "T7", + "EXP-IO19_N" : "P7", + "EXP-IO20_N" : "V5", + } + ), +] + +# Platform ----------------------------------------------------------------------------------------- + +class Platform(XilinxPlatform): + default_clk_name = "clk100" + default_clk_period = 1e9/100e6 + + def __init__(self,): + XilinxPlatform.__init__(self, "xc6slx45-csg324-3", _io, _connectors) + self.add_platform_command("""CONFIG VCCAUX="3.3";""") + + def create_programmer(self): + return iMPACT() + + 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("hdmi_in:clk_p", 0, loose=True), 1e9/74.25e6) + self.add_period_constraint(self.lookup_request("hdmi_in:clk_p", 1, loose=True), 1e9/74.25e6) + self.add_period_constraint(self.lookup_request("eth_clocks:rx", loose=True), 1e9/25e6) + self.add_period_constraint(self.lookup_request("fx2:ifclk", loose=True), 1e9/100e6) diff --git a/litex_boards/targets/digilent_atlys.py b/litex_boards/targets/digilent_atlys.py new file mode 100755 index 0000000..f14e8dc --- /dev/null +++ b/litex_boards/targets/digilent_atlys.py @@ -0,0 +1,232 @@ +#!/usr/bin/env python3 + +# +# This file is part of LiteX-Boards. +# +# Copyright (c) 2015 Robert Jordens +# Copyright (c) 2015 Sebastien Bourdeauducq +# Copyright (c) 2015 Yann Sionneau +# Copyright (c) 2016-2017 Tim 'mithro' Ansell +# Copyright (c) 2019 Florent Kermarrec +# SPDX-License-Identifier: BSD-2-Clause + +import os +import argparse + +from fractions import Fraction + +from migen import * +from migen.genlib.resetsync import AsyncResetSynchronizer + +from litex_boards.platforms import atlys + +from litex.soc.integration.soc_core import * +from litex.soc.integration.builder import * +from litex.soc.cores.led import LedChaser + +from litedram.modules import MT47H64M16 +from litedram.phy import s6ddrphy + +# CRG ---------------------------------------------------------------------------------------------- + +class _CRG(Module): + def __init__(self, platform, sys_clk_freq): + self.clock_domains.cd_sys = ClockDomain() + self.clock_domains.cd_sdram_half = ClockDomain() + self.clock_domains.cd_sdram_full_wr = ClockDomain() + self.clock_domains.cd_sdram_full_rd = ClockDomain() + + self.reset = Signal() + + # # # + + # Input clock ------------------------------------------------------------------------------ + clk100_freq = int(100e6) + clk100 = platform.request("clk100") + clk100b = Signal() + self.specials += Instance("BUFIO2", + p_DIVIDE=1, p_DIVIDE_BYPASS="TRUE", + p_I_INVERT="FALSE", + i_I=clk100, o_DIVCLK=clk100b) + + # PLL -------------------------------------------------------------------------------------- + pll_lckd = Signal() + pll_fb = Signal() + pll_sdram_full = Signal() + pll_sdram_half_a = Signal() + pll_sdram_half_b = Signal() + pll_unused = Signal() + pll_sys = Signal() + pll_periph = Signal() + + f0 = clk100_freq + f = Fraction(int(sys_clk_freq), int(f0)) + n, m = f.denominator, f.numerator + assert f0 / n * m == sys_clk_freq + p = 8 + + self.specials.pll = Instance( + "PLL_ADV", + name="crg_pll_adv", + p_SIM_DEVICE="SPARTAN6", p_BANDWIDTH="OPTIMIZED", p_COMPENSATION="INTERNAL", + p_REF_JITTER=.01, + i_DADDR=0, i_DCLK=0, i_DEN=0, i_DI=0, i_DWE=0, i_RST=0, i_REL=0, + p_DIVCLK_DIVIDE=1, + # Input Clocks (100MHz) + i_CLKIN1=clk100b, + p_CLKIN1_PERIOD=1e9/f0, + i_CLKIN2=0, + p_CLKIN2_PERIOD=0., + i_CLKINSEL=1, + # Feedback + i_CLKFBIN=pll_fb, o_CLKFBOUT=pll_fb, o_LOCKED=pll_lckd, + p_CLK_FEEDBACK="CLKFBOUT", + p_CLKFBOUT_MULT=m*p//n, p_CLKFBOUT_PHASE=0., + # (300MHz) sdram wr rd + o_CLKOUT0=pll_sdram_full, p_CLKOUT0_DUTY_CYCLE=.5, + p_CLKOUT0_PHASE=0., p_CLKOUT0_DIVIDE=p//4, + # unused? + o_CLKOUT1=pll_unused, p_CLKOUT1_DUTY_CYCLE=.5, + p_CLKOUT1_PHASE=0., p_CLKOUT1_DIVIDE=15, + # (150MHz) sdram_half - sdram dqs adr ctrl + o_CLKOUT2=pll_sdram_half_a, p_CLKOUT2_DUTY_CYCLE=.5, + p_CLKOUT2_PHASE=270., p_CLKOUT2_DIVIDE=p//2, + # (150Mhz) off-chip ddr + o_CLKOUT3=pll_sdram_half_b, p_CLKOUT3_DUTY_CYCLE=.5, + p_CLKOUT3_PHASE=250., p_CLKOUT3_DIVIDE=p//2, + # ( 50MHz) periph + o_CLKOUT4=pll_periph, p_CLKOUT4_DUTY_CYCLE=.5, + p_CLKOUT4_PHASE=0., p_CLKOUT4_DIVIDE=20, + # ( 75MHz) sysclk + o_CLKOUT5=pll_sys, p_CLKOUT5_DUTY_CYCLE=.5, + p_CLKOUT5_PHASE=0., p_CLKOUT5_DIVIDE=p//1, + ) + + # Power on reset + reset = ~platform.request("cpu_reset") | self.reset + self.clock_domains.cd_por = ClockDomain() + por = Signal(max=1 << 11, reset=(1 << 11) - 1) + self.sync.por += If(por != 0, por.eq(por - 1)) + self.specials += AsyncResetSynchronizer(self.cd_por, reset) + + # System clock + self.specials += Instance("BUFG", i_I=pll_sys, o_O=self.cd_sys.clk) + self.comb += self.cd_por.clk.eq(self.cd_sys.clk) + self.specials += AsyncResetSynchronizer(self.cd_sys, ~pll_lckd | (por > 0)) + + # SDRAM clocks ----------------------------------------------------------------------------- + self.clk4x_wr_strb = Signal() + self.clk4x_rd_strb = Signal() + + # SDRAM full clock + self.specials += Instance("BUFPLL", name="sdram_full_bufpll", + p_DIVIDE = 4, + i_PLLIN = pll_sdram_full, i_GCLK=self.cd_sys.clk, + i_LOCKED = pll_lckd, + o_IOCLK = self.cd_sdram_full_wr.clk, + o_SERDESSTROBE = self.clk4x_wr_strb) + self.comb += [ + self.cd_sdram_full_rd.clk.eq(self.cd_sdram_full_wr.clk), + self.clk4x_rd_strb.eq(self.clk4x_wr_strb), + ] + # SDRAM_half clock + self.specials += Instance("BUFG", name="sdram_half_a_bufpll", + i_I=pll_sdram_half_a, o_O=self.cd_sdram_half.clk) + clk_sdram_half_shifted = Signal() + self.specials += Instance("BUFG", name="sdram_half_b_bufpll", + i_I=pll_sdram_half_b, o_O=clk_sdram_half_shifted) + + output_clk = Signal() + clk = platform.request("ddram_clock") + self.specials += Instance("ODDR2", p_DDR_ALIGNMENT="NONE", + p_INIT=0, p_SRTYPE="SYNC", + i_D0=1, i_D1=0, i_S=0, i_R=0, i_CE=1, + i_C0=clk_sdram_half_shifted, + i_C1=~clk_sdram_half_shifted, + o_Q=output_clk) + self.specials += Instance("OBUFDS", i_I=output_clk, o_O=clk.p, o_OB=clk.n) + +# BaseSoC ------------------------------------------------------------------------------------------ + +class BaseSoC(SoCCore): + def __init__(self, with_ethernet=True, with_etherbone=False, eth_phy=0, **kwargs): + sys_clk_freq = int(75e6) + platform = atlys.Platform() + + # SoCCore ---------------------------------------------------------------------------------- + SoCCore.__init__(self, platform, sys_clk_freq, + ident = "LiteX SoC on Atlys", + ident_version = True, + **kwargs) + + # CRG -------------------------------------------------------------------------------------- + self.submodules.crg = _CRG(platform, sys_clk_freq) + self.platform.add_period_constraint(self.crg.cd_sys.clk, 1e9/sys_clk_freq) + + # DDR2 SDRAM ------------------------------------------------------------------------------- + if not self.integrated_main_ram_size: + self.submodules.ddrphy = s6ddrphy.S6HalfRateDDRPHY(platform.request("ddram"), + memtype = "DDR2", + rd_bitslip = 0, + wr_bitslip = 4, + dqs_ddr_alignment = "C0") + self.comb += [ + self.ddrphy.clk4x_wr_strb.eq(self.crg.clk4x_wr_strb), + self.ddrphy.clk4x_rd_strb.eq(self.crg.clk4x_rd_strb), + ] + self.add_sdram("sdram", + phy = self.ddrphy, + module = MT47H64M16(sys_clk_freq, "1:2"), + l2_cache_size = kwargs.get("l2_size", 8192), + ) + + # Ethernet / Etherbone --------------------------------------------------------------------- + if with_ethernet or with_etherbone: + from liteeth.phy import LiteEthPHYGMIIMII + self.submodules.ethphy = LiteEthPHYGMIIMII( + clock_pads = self.platform.request("eth_clocks", eth_phy), + pads = self.platform.request("eth", eth_phy), + clk_freq = int(self.sys_clk_freq)) + if with_ethernet: + self.add_ethernet(phy=self.ethphy) + if with_etherbone: + self.add_etherbone(phy=self.ethphy) + self.ethphy.crg.cd_eth_rx.clk.attr.add("keep") + self.ethphy.crg.cd_eth_tx.clk.attr.add("keep") + self.platform.add_platform_command(""" +NET "{eth_clocks_rx}" CLOCK_DEDICATED_ROUTE = FALSE; +NET "{eth_clocks_tx}" CLOCK_DEDICATED_ROUTE = FALSE; +""", + eth_clocks_rx=platform.lookup_request("eth_clocks").rx, + eth_clocks_tx=platform.lookup_request("eth_clocks").tx, + ) + + # Leds ------------------------------------------------------------------------------------- + self.submodules.leds = LedChaser( + pads = platform.request_all("user_led"), + sys_clk_freq = sys_clk_freq) + self.add_csr("leds") + +# Build -------------------------------------------------------------------------------------------- + +def main(): + parser = argparse.ArgumentParser(description="LiteX SoC on Atlys") + parser.add_argument("--build", action="store_true", help="Build bitstream") + parser.add_argument("--load", action="store_true", help="Load bitstream") + parser.add_argument("--with-ethernet", action="store_true", help="Enable Ethernet support") + parser.add_argument("--with-etherbone", action="store_true", help="Enable Etherbone support") + + builder_args(parser) + soc_core_args(parser) + args = parser.parse_args() + + soc = BaseSoC(**soc_core_argdict(args)) + 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()