import argparse import os from migen import * from migen.genlib.resetsync import AsyncResetSynchronizer from litex.build.io import DDROutput from litex.soc.cores.clock.gowin_gw1n import GW1NPLL 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.cores.spi import SPIBone from litex.soc.interconnect import wishbone import stellar_tang from litedram.modules import MT48LC4M16 # FIXME: use EtronTech reference. from litedram.phy import GENSDRPHY, HalfRateGENSDRPHY from litedram.init import get_sdram_phy_py_header kB = 1024 mB = 1024*kB # 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() # # # # CLK / RST clk27 = platform.request("clk27") rst_n = platform.request("user_btn", 0) # PLL self.submodules.pll = pll = GW1NPLL(devicename=platform.devicename, device=platform.device) self.comb += pll.reset.eq(~rst_n) pll.register_clkin(clk27, 27e6) pll.create_clkout(self.cd_sys2x, sys_clk_freq*2) # HCLKIN Input Clock input signal # RESETN Input Asynchronous reset signal, active-low # CALIB Input CALIB input signal, adjusting output clock # CLKOUT Output Clock output signa self.specials += Instance("CLKDIV", i_HCLKIN=ClockSignal("sys2x"), i_RESETN=~ResetSignal("sys2x"), i_CALIB=C(0), o_CLKOUT=ClockSignal("sys") ) # The PLL syncs the Reset signal to sys and sys2x, but in theory the # reset may not last long enough in the dest domain. self.specials += AsyncResetSynchronizer(self.cd_sys, ResetSignal("sys2x")) class BaseSoC(SoCCore): def __init__(self, sys_clk_freq=int(27e6), sdram_rate="1:1", debug=True, **kwargs): platform = stellar_tang.Platform() # We don't need no stinking soft-core CPU! kwargs["cpu_type"] = "None" kwargs["with_uart"] = False if not debug: kwargs["with_timer"] = False kwargs["bus_interconnect"] = "crossbar" # SoCCore ---------------------------------------------------------------------------------- SoCCore.__init__(self, platform, sys_clk_freq, ident = "LiteX SoC on stellar_board", **kwargs) # CRG -------------------------------------------------------------------------------------- self.submodules.crg = _CRG(platform, sys_clk_freq) # UARTBone --------------------------------------------------------------------------------- if debug: self.add_uartbone(baudrate=115200) # SDR SDRAM -------------------------------------------------------------------------------- if not self.integrated_main_ram_size: class SDRAMPads: def __init__(self): self.clk = platform.request("O_sdram_clk") self.cke = platform.request("O_sdram_cke") self.cs_n = platform.request("O_sdram_cs_n") self.cas_n = platform.request("O_sdram_cas_n") self.ras_n = platform.request("O_sdram_ras_n") self.we_n = platform.request("O_sdram_wen_n") self.dm = platform.request("O_sdram_dqm") self.a = platform.request("O_sdram_addr") self.ba = platform.request("O_sdram_ba") self.dq = platform.request("IO_sdram_dq") sdram_pads = SDRAMPads() #sdram_clk = ClockSignal("sys2x" if sdram_rate == "1:2" else "sys") # FIXME: use phase shift from PLL. sdram_clk = ClockSignal("sys") # FIXME: use phase shift from PLL. self.specials += DDROutput(0, 1, sdram_pads.clk, sdram_clk) sdrphy_cls = GENSDRPHY self.submodules.sdrphy = sdrphy_cls(sdram_pads, sys_clk_freq) self.add_sdram("sdram", phy = self.sdrphy, module = MT48LC4M16(sys_clk_freq, sdram_rate), # FIXME. l2_cache_size = 0, ) # SPIBone ---------------------------------------------------------------------------------- spi_pads = platform.request("spi") self.submodules.spibone = ClockDomainsRenamer({ "sys" : "sys2x" })(SPIBone(spi_pads)) spibone_1x = wishbone.Interface() self.comb += self.spibone.bus.connect(spibone_1x, omit={"ack"}) # Override for ACK to ensure that ACK lasts for 1 cycle in both the # slow domain and fast domain. prev_ack_1x = Signal() ack_2x = Signal() self.sync.sys += prev_ack_1x.eq(spibone_1x.ack) self.sync.sys2x += ack_2x.eq(~prev_ack_1x & spibone_1x.ack) self.comb += self.spibone.bus.ack.eq(ack_2x) self.bus.add_master(name="spibone", master=spibone_1x) # Leds ------------------------------------------------------------------------------------- if debug: self.submodules.leds = LedChaser( pads = platform.request_all("user_led"), sys_clk_freq = sys_clk_freq) # Build -------------------------------------------------------------------------------------------- def main(): from litex.soc.integration.soc import LiteXSoCArgumentParser parser = argparse.ArgumentParser(description="Project Stellar DRAM test core") target_group = parser.add_argument_group(title="Target options") target_group.add_argument("--build", action="store_true", help="Build bitstream.") target_group.add_argument("--load", action="store_true", help="Load bitstream.") target_group.add_argument("--flash", action="store_true", help="Flash Bitstream and BIOS.") target_group.add_argument("--prog-kit", default="openfpgaloader", help="Programmer select from Gowin/openFPGALoader.") target_group.add_argument("--debug", action="store_true", help="Add debugging peripherals and controllers.") builder_group = parser.add_argument_group(title="Builder options") builder_group.add_argument("--output-dir", default=None, help="Base Output directory.") args = parser.parse_args() soc = BaseSoC(debug = args.debug) builder = Builder(soc, compile_software=False, # All software is handled externally. output_dir = args.output_dir, ) builder.csr_csv = os.path.join(builder.output_dir, "csr.csv") # We don't know output_dir name until now. builder.build(run=args.build) with open(os.path.join(builder.output_dir, "sdr_init.py"), "w") as fp: fp.write(get_sdram_phy_py_header(soc.sdram.controller.settings.phy, soc.sdram.controller.settings.timing)) if args.load: prog = soc.platform.create_programmer(kit=args.prog_kit) prog.load_bitstream(builder.get_bitstream_filename(mode="sram")) if args.flash: prog = soc.platform.create_programmer() prog.flash(0, builder.get_bitstream_filename(mode="flash", ext=".fs")) # FIXME if __name__ == "__main__": main()