diff --git a/litex/boards/platforms/arty.py b/litex/boards/platforms/arty.py index 5d8254745..97d69fa02 100644 --- a/litex/boards/platforms/arty.py +++ b/litex/boards/platforms/arty.py @@ -323,8 +323,7 @@ class Platform(XilinxPlatform): self.toolchain.additional_commands = \ ["write_cfgmem -force -format bin -interface spix4 -size 16 " "-loadbit \"up 0x0 {build_name}.bit\" -file {build_name}.bin"] - if toolchain == "vivado": # FIXME - self.add_platform_command("set_property INTERNAL_VREF 0.675 [get_iobanks 34]") + self.add_platform_command("set_property INTERNAL_VREF 0.675 [get_iobanks 34]") def create_programmer(self): bscan_spi = "bscan_spi_xc7a100t.bit" if "xc7a100t" in self.device else "bscan_spi_xc7a35t.bit" @@ -333,5 +332,4 @@ class Platform(XilinxPlatform): def do_finalize(self, fragment): XilinxPlatform.do_finalize(self, fragment) from litex.build.xilinx import symbiflow - if not isinstance(self.toolchain, symbiflow.SymbiflowToolchain): # FIXME - self.add_period_constraint(self.lookup_request("clk100", loose=True), 1e9/100e6) + self.add_period_constraint(self.lookup_request("clk100", loose=True), 1e9/100e6) diff --git a/litex/boards/targets/arty.py b/litex/boards/targets/arty.py index 145283d9b..516ee4106 100755 --- a/litex/boards/targets/arty.py +++ b/litex/boards/targets/arty.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 - # # This file is part of LiteX. # @@ -29,7 +28,7 @@ from liteeth.phy.mii import LiteEthPHYMII # CRG ---------------------------------------------------------------------------------------------- class _CRG(Module): - def __init__(self, platform, sys_clk_freq, toolchain): + 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) @@ -39,54 +38,36 @@ class _CRG(Module): # # # - if toolchain == "vivado": - self.submodules.pll = pll = S7PLL(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_sys4x, 4*sys_clk_freq) - pll.create_clkout(self.cd_sys4x_dqs, 4*sys_clk_freq, phase=90) - pll.create_clkout(self.cd_idelay, 200e6) - pll.create_clkout(self.cd_eth, 25e6) + self.submodules.pll = pll = S7PLL(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_sys4x, 4*sys_clk_freq) + pll.create_clkout(self.cd_sys4x_dqs, 4*sys_clk_freq, phase=90) + pll.create_clkout(self.cd_idelay, 200e6) + pll.create_clkout(self.cd_eth, 25e6) - self.submodules.idelayctrl = S7IDELAYCTRL(self.cd_idelay) + self.submodules.idelayctrl = S7IDELAYCTRL(self.cd_idelay) - self.comb += platform.request("eth_ref_clk").eq(self.cd_eth.clk) - elif toolchain == "symbiflow": # FIXME - clk100_ibuf = Signal() - clk100_buf = Signal() - self.specials += Instance("IBUF", i_I=platform.request("clk100"), o_O=clk100_ibuf) - self.specials += Instance("BUFG", i_I=clk100_ibuf, o_O=clk100_buf) - - self.submodules.pll = pll = S7PLL(speedgrade=-1) - self.comb += pll.reset.eq(~platform.request("cpu_reset") | self.rst) - pll.register_clkin(clk100_buf, 100e6) - pll.create_clkout(self.cd_sys, sys_clk_freq) - - platform.add_period_constraint(clk100_buf, 1e9/100e6) - platform.add_period_constraint(self.cd_sys.clk, 1e9/sys_clk_freq) - platform.add_false_path_constraints(clk100_buf, self.cd_sys.clk) + self.comb += platform.request("eth_ref_clk").eq(self.cd_eth.clk) # BaseSoC ------------------------------------------------------------------------------------------ class BaseSoC(SoCCore): - def __init__(self, toolchain="vivado", sys_clk_freq=int(100e6), with_ethernet=False, with_etherbone=False, **kwargs): + def __init__(self, toolchain="vivado", sys_clk_freq=int(100e6), with_ethernet=False, with_etherbone=False, ident_version=True, **kwargs): platform = arty.Platform(toolchain=toolchain) # SoCCore ---------------------------------------------------------------------------------- - if toolchain == "symbiflow": - sys_clk_freq=int(60e6) - SoCCore.__init__(self, platform, sys_clk_freq, ident = "LiteX SoC on Arty A7", - ident_version = True, + ident_version = ident_version, **kwargs) # CRG -------------------------------------------------------------------------------------- - self.submodules.crg = _CRG(platform, sys_clk_freq, toolchain) + self.submodules.crg = _CRG(platform, sys_clk_freq) # DDR3 SDRAM ------------------------------------------------------------------------------- - if not self.integrated_main_ram_size and toolchain != "symbiflow": # FIXME + if not self.integrated_main_ram_size: self.submodules.ddrphy = s7ddrphy.A7DDRPHY(platform.request("ddram"), memtype = "DDR3", nphases = 4, @@ -123,14 +104,15 @@ class BaseSoC(SoCCore): def main(): parser = argparse.ArgumentParser(description="LiteX SoC on Arty A7") - parser.add_argument("--build", action="store_true", help="Build bitstream") - parser.add_argument("--load", action="store_true", help="Load bitstream") - parser.add_argument("--toolchain", default="vivado", help="FPGA toolchain: vivado (default) or symbiflow") - parser.add_argument("--sys-clk-freq", default=100e6, help="System clock frequency (default: 100MHz)") - parser.add_argument("--with-ethernet", action="store_true", help="Enable Ethernet support") - parser.add_argument("--with-etherbone", action="store_true", help="Enable Etherbone support") - parser.add_argument("--with-spi-sdcard", action="store_true", help="Enable SPI-mode SDCard support") - parser.add_argument("--with-sdcard", action="store_true", help="Enable SDCard support") + 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("--sys-clk-freq", default=100e6, help="System clock frequency (default: 100MHz)") + parser.add_argument("--with-ethernet", action="store_true", help="Enable Ethernet support") + parser.add_argument("--with-etherbone", action="store_true", help="Enable Etherbone support") + parser.add_argument("--with-spi-sdcard", action="store_true", help="Enable SPI-mode SDCard support") + parser.add_argument("--with-sdcard", action="store_true", help="Enable SDCard support") + parser.add_argument("--no-ident-version", action="store_false", help="Disable build time output") builder_args(parser) soc_sdram_args(parser) vivado_build_args(parser) @@ -138,10 +120,11 @@ def main(): assert not (args.with_ethernet and args.with_etherbone) soc = BaseSoC( - toolchain = args.toolchain, + toolchain = args.toolchain, sys_clk_freq = int(float(args.sys_clk_freq)), with_ethernet = args.with_ethernet, with_etherbone = args.with_etherbone, + ident_version = args.no_ident_version, **soc_sdram_argdict(args) ) assert not (args.with_spi_sdcard and args.with_sdcard) diff --git a/litex/build/xilinx/symbiflow.py b/litex/build/xilinx/symbiflow.py index b764a6cb3..118afb418 100644 --- a/litex/build/xilinx/symbiflow.py +++ b/litex/build/xilinx/symbiflow.py @@ -19,34 +19,12 @@ from migen.fhdl.specials import Instance from litex.build.generic_platform import * from litex.build.xilinx.vivado import _xdc_separator, _format_xdc, _build_xdc from litex.build import tools +from litex.build.xilinx import common def _unwrap(value): return value.value if isinstance(value, Constant) else value -# Constraints (.pcf) ------------------------------------------------------------------------------- - -def _build_pcf(named_sc): - r = _xdc_separator("Design constraints") - current_resname = "" - for sig, pins, _, resname in named_sc: - if current_resname != resname[0]: - if current_resname: - r += "\n" - current_resname = resname[0] - r += f"# {current_resname}\n" - if len(pins) > 1: - for i, p in enumerate(pins): - r += f"set_io {sig}[{i}] {Pins(p).identifiers[0]}\n" - elif pins: - r += f"set_io {sig} {Pins(pins[0]).identifiers[0]}\n" - return r - -# Constraints (.sdc) ------------------------------------------------------------------------------- - -def _build_sdc(named_pc): - return "\n".join(named_pc) if named_pc else "" - # Makefile ----------------------------------------------------------------------------------------- class _MakefileGenerator: @@ -95,12 +73,14 @@ class _MakefileGenerator: def _run_make(): + make_cmd = ["make"] + if which("symbiflow_synth") is None: msg = "Unable to find Symbiflow toolchain, please:\n" msg += "- Add Symbiflow toolchain to your $PATH." raise OSError(msg) - if tools.subprocess_call_filtered(shell + [script], common.colors) != 0: + if tools.subprocess_call_filtered(make_cmd, common.colors) != 0: raise OSError("Error occured during Symbiflow's script execution.") # SymbiflowToolchain ------------------------------------------------------------------------------- @@ -159,7 +139,6 @@ class SymbiflowToolchain: "", Var("VERILOG", [f for f,language,_ in platform.sources if language in ["verilog", "system_verilog"]]), Var("MEM_INIT", [f"{name}" for name in os.listdir() if name.endswith(".init")]), - Var("PCF", f"{build_name}.pcf"), Var("SDC", f"{build_name}.sdc"), Var("XDC", f"{build_name}.xdc"), Var("ARTIFACTS", [ @@ -176,8 +155,8 @@ class SymbiflowToolchain: Rule("$(TOP).net", ["$(TOP).eblif", "$(SDC)"], commands=[ "symbiflow_pack -e $(TOP).eblif -d $(DEVICE) -s $(SDC) > /dev/null" ]), - Rule("$(TOP).place", ["$(TOP).net", "$(PCF)"], commands=[ - "symbiflow_place -e $(TOP).eblif -d $(DEVICE) -p $(PCF) -n $(TOP).net -P $(PARTNAME) -s $(SDC) > /dev/null" + Rule("$(TOP).place", ["$(TOP).net"], commands=[ + "symbiflow_place -e $(TOP).eblif -d $(DEVICE) -n $(TOP).net -P $(PARTNAME) -s $(SDC) > /dev/null" ]), Rule("$(TOP).route", ["$(TOP).place"], commands=[ "symbiflow_route -e $(TOP).eblif -d $(DEVICE) -s $(SDC) > /dev/null" @@ -196,24 +175,14 @@ class SymbiflowToolchain: tools.write_to_file("Makefile", makefile.generate()) def _build_clock_constraints(self, platform): - for clk, (period, phase) in sorted(self.clocks.items(), key=lambda x: x[0].duid): - rising_edge = math.floor(period/360.0 * phase * 1e3)/1e3 - falling_edge = math.floor(((rising_edge + period/2) % period) * 1.e3)/1e3 - platform.add_platform_command(f"create_clock -period {period} {{clk}} -waveform {{{{{rising_edge} {falling_edge}}}}}", clk=clk) - for from_, to in sorted(self.false_paths, key=lambda x: (x[0].duid, x[1].duid)): - platform.add_platform_command("set_clock_groups -exclusive -group {{{from_}}} -group {{{to}}}", from_=from_, to=to) - # Make sure add_*_constraint cannot be used again - del self.clocks - del self.false_paths + platform.add_platform_command(_xdc_separator("Clock constraints")) + for clk, period in sorted(self.clocks.items(), key=lambda x: x[0].duid): + platform.add_platform_command( + "create_clock -period " + str(period) + + " {clk}", clk=clk) - # Yosys has limited support for real type. It requires that some values be multiplied - # by 1000 and passed as integers. For details, see: - # https://github.com/SymbiFlow/symbiflow-arch-defs/blob/master/xc/xc7/techmap/cells_map.v def _fix_instance(self, instance): - if instance.of == "PLLE2_ADV": - for item in instance.items: - if isinstance(item, Instance.Parameter) and re.fullmatch("CLKOUT[0-9]_(PHASE|DUTY_CYCLE)", item.name): - item.value = wrap(math.floor(_unwrap(item.value) * 1000)) + pass def build(self, platform, fragment, build_dir = "build", @@ -255,9 +224,7 @@ class SymbiflowToolchain: ) # Generate design constraints - tools.write_to_file(build_name + ".xdc", _build_xdc(named_sc, False)) - tools.write_to_file(build_name + ".pcf", _build_pcf(named_sc)) - tools.write_to_file(build_name + ".sdc", _build_sdc(named_pc)) + tools.write_to_file(build_name + ".xdc", _build_xdc(named_sc, named_pc)) if run: _run_make() @@ -266,25 +233,14 @@ class SymbiflowToolchain: return v_output.ns - def add_period_constraint(self, platform, clk, period, phase=0): + def add_period_constraint(self, platform, clk, period): clk.attr.add("keep") - phase = math.floor(phase % 360.0 * 1e3)/1e3 period = math.floor(period*1e3)/1e3 # round to lowest picosecond if clk in self.clocks: - if period != self.clocks[clk][0]: + if period != self.clocks[clk]: raise ValueError("Clock already constrained to {:.2f}ns, new constraint to {:.2f}ns" - .format(self.clocks[clk][0], period)) - if phase != self.clocks[clk][1]: - raise ValueError("Clock already constrained with phase {:.2f}deg, new phase {:.2f}deg" - .format(self.clocks[clk][1], phase)) - self.clocks[clk] = (period, phase) - - def add_false_path_constraint(self, platform, from_, to): - if (from_, to) in self.false_paths or (to, from_) in self.false_paths: - return - from_.attr.add("keep") - to.attr.add("keep") - self.false_paths.add((from_, to)) + .format(self.clocks[clk], period)) + self.clocks[clk] = period def symbiflow_build_args(parser):