diff --git a/litex/boards/platforms/ulx3s.py b/litex/boards/platforms/ulx3s.py index 319596d29..c17ce3318 100644 --- a/litex/boards/platforms/ulx3s.py +++ b/litex/boards/platforms/ulx3s.py @@ -34,10 +34,14 @@ _io = [ Subsignal("cke", Pins("F20")), Subsignal("ba", Pins("P19 N20")), Subsignal("dm", Pins("U19 E20")), - IOStandard("LVCMOS33") + IOStandard("LVCMOS33"), Misc("SLEWRATE=FAST") ), ("wifi_gpio0", 0, Pins("L2"), IOStandard("LVCMOS33")), + + ("ext0p", 0, Pins("B11"), IOStandard("LVCMOS33")), + ("ext1p", 0, Pins("A10"), IOStandard("LVCMOS33")), + ] diff --git a/litex/boards/platforms/versaecp55g_sdram.py b/litex/boards/platforms/versaecp55g_sdram.py new file mode 100644 index 000000000..ceec31341 --- /dev/null +++ b/litex/boards/platforms/versaecp55g_sdram.py @@ -0,0 +1,152 @@ +# This file is Copyright (c) 2017 Serge 'q3k' Bazanski +# License: BSD + +from litex.build.generic_platform import * +from litex.build.lattice import LatticePlatform +from litex.build.lattice.programmer import LatticeProgrammer + + +_io = [ + ("clk100", 0, Pins("P3"), IOStandard("LVDS")), + ("rst_n", 0, Pins("T1"), IOStandard("LVCMOS33")), + + ("user_led", 0, Pins("E16"), IOStandard("LVCMOS25")), + ("user_led", 1, Pins("D17"), IOStandard("LVCMOS25")), + ("user_led", 2, Pins("D18"), IOStandard("LVCMOS25")), + ("user_led", 3, Pins("E18"), IOStandard("LVCMOS25")), + ("user_led", 4, Pins("F17"), IOStandard("LVCMOS25")), + ("user_led", 5, Pins("F18"), IOStandard("LVCMOS25")), + ("user_led", 6, Pins("E17"), IOStandard("LVCMOS25")), + ("user_led", 7, Pins("F16"), IOStandard("LVCMOS25")), + + ("user_dip_btn", 0, Pins("H2"), IOStandard("LVCMOS15")), + ("user_dip_btn", 1, Pins("K3"), IOStandard("LVCMOS15")), + ("user_dip_btn", 2, Pins("G3"), IOStandard("LVCMOS15")), + ("user_dip_btn", 3, Pins("F2"), IOStandard("LVCMOS15")), + ("user_dip_btn", 4, Pins("J18"), IOStandard("LVCMOS25")), + ("user_dip_btn", 5, Pins("K18"), IOStandard("LVCMOS25")), + ("user_dip_btn", 6, Pins("K19"), IOStandard("LVCMOS25")), + ("user_dip_btn", 7, Pins("K20"), IOStandard("LVCMOS25")), + + ("serial", 0, + Subsignal("rx", Pins("C11"), IOStandard("LVCMOS33")), + Subsignal("tx", Pins("A11"), IOStandard("LVCMOS33")), + ), + + ("sdram_clock", 0, Pins("E14"), IOStandard("LVCMOS33")), + ("sdram", 0, + Subsignal("a", Pins("C6 E15 A16 B16 D15 C15 B15 E12 D12 B10 C7 A9 C10")), + Subsignal("dq", Pins("B19 B12 B9 E6 D6 E7 D7 B11 C14 A14 E13 D13 C13 B13 A13 A12")), + Subsignal("we_n", Pins("E9")), + Subsignal("ras_n", Pins("B8")), + Subsignal("cas_n", Pins("D9")), + Subsignal("cs_n", Pins("C8")), + Subsignal("cke", Pins("D11")), + Subsignal("ba", Pins("D8 E8")), + Subsignal("dm", Pins("B6 D14")), + IOStandard("LVCMOS33"), Misc("SLEWRATE=FAST") + ), + + ("eth_clocks", 0, + Subsignal("tx", Pins("P19")), + Subsignal("rx", Pins("L20")), + IOStandard("LVCMOS25") + ), + ("eth", 0, + Subsignal("rst_n", Pins("U17")), + Subsignal("mdio", Pins("U18")), + Subsignal("mdc", Pins("T18")), + Subsignal("rx_ctl", Pins("U19")), + Subsignal("rx_data", Pins("T20 U20 T19 R18")), + Subsignal("tx_ctl", Pins("R20")), + Subsignal("tx_data", Pins("N19 N20 P18 P20")), + IOStandard("LVCMOS25") + ), + + ("eth_clocks", 1, + Subsignal("tx", Pins("C20")), + Subsignal("rx", Pins("J19")), + IOStandard("LVCMOS25") + ), + ("eth", 1, + Subsignal("rst_n", Pins("F20")), + Subsignal("mdio", Pins("H20")), + Subsignal("mdc", Pins("G19")), + Subsignal("rx_ctl", Pins("F19")), + Subsignal("rx_data", Pins("G18 G16 H18 H17")), + Subsignal("tx_ctl", Pins("E19")), + Subsignal("tx_data", Pins("J17 J16 D19 D20")), + IOStandard("LVCMOS25") + ), +] + + +class Platform(LatticePlatform): + default_clk_name = "clk100" + default_clk_period = 10 + + def __init__(self, **kwargs): + LatticePlatform.__init__(self, "LFE5UM5G-45F-8BG381C", _io, **kwargs) + + def do_finalize(self, fragment): + LatticePlatform.do_finalize(self, fragment) + try: + self.add_period_constraint(self.lookup_request("eth_clocks", 0).rx, 8.0) + except ConstraintError: + pass + try: + self.add_period_constraint(self.lookup_request("eth_clocks", 1).rx, 8.0) + except ConstraintError: + pass + + def create_programmer(self): + _xcf_template = """ + + + + + + JTAG + + + 1 + Lattice + ECP5UM5G + LFE5UM5G-45F + 0x81112043 + {bitstream_file} + Fast Program + + + + 2 + Lattice + ispCLOCK + ispPAC-CLK5406D + 0x00191043 + Erase,Program,Verify + + 8 + 11111111 + 1 + 0 + + + + + SEQUENTIAL + ENTIRED CHAIN + No Override + TLR + TLR + + + + USB2 + FTUSB-0 + LATTICE ECP5_5G VERSA BOARD A Location 0000 Serial Lattice ECP5_5G VERSA Board A + + +""" + + return LatticeProgrammer(_xcf_template) diff --git a/litex/boards/targets/ulx3s.py b/litex/boards/targets/ulx3s.py index 8ff3777cf..21f057fda 100755 --- a/litex/boards/targets/ulx3s.py +++ b/litex/boards/targets/ulx3s.py @@ -26,38 +26,65 @@ class _CRG(Module): rst = platform.request("rst") # sys_clk - self.comb += self.cd_sys.clk.eq(clk25) # FIXME: AsyncResetSynchronizer needs FD1S3BX support. #self.specials += AsyncResetSynchronizer(self.cd_sys, rst) self.comb += self.cd_sys.rst.eq(rst) + self.comb += self.cd_sys_ps.rst.eq(rst) - # sys_clk phase shifted (for sdram) - sdram_ps_clk = self.cd_sys.clk - # FIXME: phase shift with luts, needs PLL support. - sdram_ps_luts = 5 - for i in range(sdram_ps_luts): - new_sdram_ps_clk = Signal() - self.specials += Instance("LUT4", - p_INIT=2, - i_A=sdram_ps_clk, - i_B=0, - i_C=0, - i_D=0, - o_Z=new_sdram_ps_clk) - sdram_ps_clk = new_sdram_ps_clk + sys_clk = Signal() + sdram_ps_clk = Signal() + + self.specials += Instance( + "EHXPLLL", + i_CLKI=clk25, + i_CLKFB=sys_clk, + i_PHASESEL1=0, + i_PHASESEL0=0, + i_PHASEDIR=0, + i_PHASESTEP=0, + i_PHASELOADREG=0, + i_STDBY=0, + i_PLLWAKESYNC=0, + i_RST=0, + i_ENCLKOP=0, + i_ENCLKOS=0, + o_CLKOP=sys_clk, + o_CLKOS=sdram_ps_clk, + p_CLKOS_FPHASE=2, + p_CLKOS_CPHASE=15, + p_CLKOP_FPHASE=0, + p_CLKOP_CPHASE=12, + p_PLL_LOCK_MODE=0, + p_OUTDIVIDER_MUXB="DIVB", + p_CLKOS_ENABLE="ENABLED", + p_CLKOP_ENABLE="ENABLED", + p_CLKOS_DIV=13, + p_CLKOP_DIV=13, + p_CLKFB_DIV=2, + p_CLKI_DIV=1, + p_FEEDBK_PATH="CLKOP", + attr=[("ICP_CURRENT", "6"), ("LPF_RESISTOR", "16"), ("MFG_ENABLE_FILTEROPAMP", "1"), ("MFG_GMCREF_SEL", "2")] + ) + + self.comb += self.cd_sys.clk.eq(sys_clk) self.comb += self.cd_sys_ps.clk.eq(sdram_ps_clk) sdram_clock = platform.request("sdram_clock") - self.comb += sdram_clock.eq(sdram_ps_clk) + self.comb += sdram_clock.eq(sys_clk) # Stop ESP32 from resetting FPGA wifi_gpio0 = platform.request("wifi_gpio0") self.comb += wifi_gpio0.eq(1) + ext0p = platform.request("ext0p") + self.comb += ext0p.eq(sdram_ps_clk) + ext1p = platform.request("ext1p") + self.comb += ext1p.eq(self.cd_sys.clk) + class BaseSoC(SoCSDRAM): def __init__(self, **kwargs): platform = ulx3s.Platform(toolchain="prjtrellis") - sys_clk_freq = int(25e6) + sys_clk_freq = int(50e6) SoCSDRAM.__init__(self, platform, clk_freq=sys_clk_freq, l2_size=32, integrated_rom_size=0x8000, diff --git a/litex/boards/targets/versaecp55g_sdram.py b/litex/boards/targets/versaecp55g_sdram.py new file mode 100755 index 000000000..c279f8efa --- /dev/null +++ b/litex/boards/targets/versaecp55g_sdram.py @@ -0,0 +1,113 @@ +#!/usr/bin/env python3 + +import argparse + +from migen import * +from migen.genlib.resetsync import AsyncResetSynchronizer + +from litex.boards.platforms import versaecp55g_sdram + +from litex.soc.integration.soc_sdram import * +from litex.soc.integration.builder import * + +from litedram.modules import AS4C32M16 +from litedram.phy import GENSDRPHY + + +class _CRG(Module): + def __init__(self, platform): + self.clock_domains.cd_sys = ClockDomain() + self.clock_domains.cd_sys_ps = ClockDomain() + + # # # + + clk100 = platform.request("clk100") + rst_n = platform.request("rst_n") + + rst = Signal() + self.comb += rst.eq(~rst_n) + + # sys_clk + # FIXME: AsyncResetSynchronizer needs FD1S3BX support. + #self.specials += AsyncResetSynchronizer(self.cd_sys, rst) + self.comb += self.cd_sys.rst.eq(rst) + self.comb += self.cd_sys_ps.rst.eq(rst) + + sys_clk = Signal() + sdram_ps_clk = Signal() + lock = Signal() + + self.specials += Instance( + "EHXPLLL", + i_CLKI=clk100, + i_CLKFB=sys_clk, + i_PHASESEL1=0, + i_PHASESEL0=0, + i_PHASEDIR=0, + i_PHASESTEP=0, + i_PHASELOADREG=0, + i_STDBY=0, + i_PLLWAKESYNC=0, + i_RST=0, + i_ENCLKOP=0, + i_ENCLKOS=0, + o_CLKOP=sys_clk, + o_CLKOS=sdram_ps_clk, + o_LOCK=lock, + p_CLKOS_FPHASE=0, + p_CLKOS_CPHASE=17, + p_CLKOP_FPHASE=0, + p_CLKOP_CPHASE=11, + p_PLL_LOCK_MODE=0, + p_OUTDIVIDER_MUXB="DIVB", + p_OUTDIVIDER_MUXA="DIVA", + p_CLKOS_ENABLE="ENABLED", + p_CLKOP_ENABLE="ENABLED", + p_CLKOS_DIV=12, + p_CLKOP_DIV=12, + p_CLKFB_DIV=1, + p_CLKI_DIV=2, + p_FEEDBK_PATH="CLKOP", + attr=[("ICP_CURRENT", "12"), ("LPF_RESISTOR", "8"), ("MFG_ENABLE_FILTEROPAMP", "1"), ("MFG_GMCREF_SEL", "2")] + ) + + self.comb += self.cd_sys.clk.eq(sys_clk) + self.comb += self.cd_sys_ps.clk.eq(sdram_ps_clk) + sdram_clock = platform.request("sdram_clock") + self.comb += sdram_clock.eq(sdram_ps_clk) + led0 = platform.request("user_led", 0) + self.comb += led0.eq(~lock) + + +class BaseSoC(SoCSDRAM): + def __init__(self, **kwargs): + platform = versaecp55g_sdram.Platform(toolchain="prjtrellis") + sys_clk_freq = int(50e6) + SoCSDRAM.__init__(self, platform, clk_freq=sys_clk_freq, + l2_size=32, + integrated_rom_size=0x8000, + **kwargs) + + self.submodules.crg = _CRG(platform) + + if not self.integrated_main_ram_size: + self.submodules.sdrphy = GENSDRPHY(platform.request("sdram")) + sdram_module = AS4C32M16(sys_clk_freq, "1:1") + self.register_sdram(self.sdrphy, + sdram_module.geom_settings, + sdram_module.timing_settings) + + +def main(): + parser = argparse.ArgumentParser(description="LiteX SoC port to the ECP5 Versa board with SDRAM hat") + 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() diff --git a/litex/build/lattice/prjtrellis.py b/litex/build/lattice/prjtrellis.py index ec983505f..79df493a7 100644 --- a/litex/build/lattice/prjtrellis.py +++ b/litex/build/lattice/prjtrellis.py @@ -33,7 +33,7 @@ def _format_constraint(c): elif isinstance(c, IOStandard): return ("IOBUF PORT ", " IO_TYPE=" + c.name) elif isinstance(c, Misc): - return c.misc + return ("IOBUF PORT ", " " + c.misc) def _format_lpf(signame, pin, others, resname):