symbiflow: remove workarounds for symbiflow

Signed-off-by: Alessandro Comodi <acomodi@antmicro.com>
This commit is contained in:
Alessandro Comodi 2020-11-23 09:25:22 +01:00
parent 8e39060d26
commit 0431af729c
3 changed files with 45 additions and 108 deletions

View File

@ -323,7 +323,6 @@ class Platform(XilinxPlatform):
self.toolchain.additional_commands = \ self.toolchain.additional_commands = \
["write_cfgmem -force -format bin -interface spix4 -size 16 " ["write_cfgmem -force -format bin -interface spix4 -size 16 "
"-loadbit \"up 0x0 {build_name}.bit\" -file {build_name}.bin"] "-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): def create_programmer(self):
@ -333,5 +332,4 @@ class Platform(XilinxPlatform):
def do_finalize(self, fragment): def do_finalize(self, fragment):
XilinxPlatform.do_finalize(self, fragment) XilinxPlatform.do_finalize(self, fragment)
from litex.build.xilinx import symbiflow 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)

View File

@ -1,5 +1,4 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# #
# This file is part of LiteX. # This file is part of LiteX.
# #
@ -29,7 +28,7 @@ from liteeth.phy.mii import LiteEthPHYMII
# CRG ---------------------------------------------------------------------------------------------- # CRG ----------------------------------------------------------------------------------------------
class _CRG(Module): class _CRG(Module):
def __init__(self, platform, sys_clk_freq, toolchain): def __init__(self, platform, sys_clk_freq):
self.rst = Signal() self.rst = Signal()
self.clock_domains.cd_sys = ClockDomain() self.clock_domains.cd_sys = ClockDomain()
self.clock_domains.cd_sys4x = ClockDomain(reset_less=True) self.clock_domains.cd_sys4x = ClockDomain(reset_less=True)
@ -39,7 +38,6 @@ class _CRG(Module):
# # # # # #
if toolchain == "vivado":
self.submodules.pll = pll = S7PLL(speedgrade=-1) self.submodules.pll = pll = S7PLL(speedgrade=-1)
self.comb += pll.reset.eq(~platform.request("cpu_reset") | self.rst) self.comb += pll.reset.eq(~platform.request("cpu_reset") | self.rst)
pll.register_clkin(platform.request("clk100"), 100e6) pll.register_clkin(platform.request("clk100"), 100e6)
@ -52,41 +50,24 @@ class _CRG(Module):
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) 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)
# BaseSoC ------------------------------------------------------------------------------------------ # BaseSoC ------------------------------------------------------------------------------------------
class BaseSoC(SoCCore): 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) platform = arty.Platform(toolchain=toolchain)
# SoCCore ---------------------------------------------------------------------------------- # SoCCore ----------------------------------------------------------------------------------
if toolchain == "symbiflow":
sys_clk_freq=int(60e6)
SoCCore.__init__(self, platform, sys_clk_freq, SoCCore.__init__(self, platform, sys_clk_freq,
ident = "LiteX SoC on Arty A7", ident = "LiteX SoC on Arty A7",
ident_version = True, ident_version = ident_version,
**kwargs) **kwargs)
# CRG -------------------------------------------------------------------------------------- # CRG --------------------------------------------------------------------------------------
self.submodules.crg = _CRG(platform, sys_clk_freq, toolchain) self.submodules.crg = _CRG(platform, sys_clk_freq)
# DDR3 SDRAM ------------------------------------------------------------------------------- # 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"), self.submodules.ddrphy = s7ddrphy.A7DDRPHY(platform.request("ddram"),
memtype = "DDR3", memtype = "DDR3",
nphases = 4, nphases = 4,
@ -123,14 +104,15 @@ class BaseSoC(SoCCore):
def main(): def main():
parser = argparse.ArgumentParser(description="LiteX SoC on Arty A7") parser = argparse.ArgumentParser(description="LiteX SoC on Arty A7")
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("--build", action="store_true", help="Build bitstream")
parser.add_argument("--load", action="store_true", help="Load 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("--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-ethernet", action="store_true", help="Enable Ethernet support")
parser.add_argument("--with-etherbone", action="store_true", help="Enable Etherbone 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-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("--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) builder_args(parser)
soc_sdram_args(parser) soc_sdram_args(parser)
vivado_build_args(parser) vivado_build_args(parser)
@ -142,6 +124,7 @@ def main():
sys_clk_freq = int(float(args.sys_clk_freq)), sys_clk_freq = int(float(args.sys_clk_freq)),
with_ethernet = args.with_ethernet, with_ethernet = args.with_ethernet,
with_etherbone = args.with_etherbone, with_etherbone = args.with_etherbone,
ident_version = args.no_ident_version,
**soc_sdram_argdict(args) **soc_sdram_argdict(args)
) )
assert not (args.with_spi_sdcard and args.with_sdcard) assert not (args.with_spi_sdcard and args.with_sdcard)

View File

@ -19,34 +19,12 @@ from migen.fhdl.specials import Instance
from litex.build.generic_platform import * from litex.build.generic_platform import *
from litex.build.xilinx.vivado import _xdc_separator, _format_xdc, _build_xdc from litex.build.xilinx.vivado import _xdc_separator, _format_xdc, _build_xdc
from litex.build import tools from litex.build import tools
from litex.build.xilinx import common
def _unwrap(value): def _unwrap(value):
return value.value if isinstance(value, Constant) else 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 ----------------------------------------------------------------------------------------- # Makefile -----------------------------------------------------------------------------------------
class _MakefileGenerator: class _MakefileGenerator:
@ -95,12 +73,14 @@ class _MakefileGenerator:
def _run_make(): def _run_make():
make_cmd = ["make"]
if which("symbiflow_synth") is None: if which("symbiflow_synth") is None:
msg = "Unable to find Symbiflow toolchain, please:\n" msg = "Unable to find Symbiflow toolchain, please:\n"
msg += "- Add Symbiflow toolchain to your $PATH." msg += "- Add Symbiflow toolchain to your $PATH."
raise OSError(msg) 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.") raise OSError("Error occured during Symbiflow's script execution.")
# SymbiflowToolchain ------------------------------------------------------------------------------- # SymbiflowToolchain -------------------------------------------------------------------------------
@ -159,7 +139,6 @@ class SymbiflowToolchain:
"", "",
Var("VERILOG", [f for f,language,_ in platform.sources if language in ["verilog", "system_verilog"]]), 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("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("SDC", f"{build_name}.sdc"),
Var("XDC", f"{build_name}.xdc"), Var("XDC", f"{build_name}.xdc"),
Var("ARTIFACTS", [ Var("ARTIFACTS", [
@ -176,8 +155,8 @@ class SymbiflowToolchain:
Rule("$(TOP).net", ["$(TOP).eblif", "$(SDC)"], commands=[ Rule("$(TOP).net", ["$(TOP).eblif", "$(SDC)"], commands=[
"symbiflow_pack -e $(TOP).eblif -d $(DEVICE) -s $(SDC) > /dev/null" "symbiflow_pack -e $(TOP).eblif -d $(DEVICE) -s $(SDC) > /dev/null"
]), ]),
Rule("$(TOP).place", ["$(TOP).net", "$(PCF)"], commands=[ Rule("$(TOP).place", ["$(TOP).net"], commands=[
"symbiflow_place -e $(TOP).eblif -d $(DEVICE) -p $(PCF) -n $(TOP).net -P $(PARTNAME) -s $(SDC) > /dev/null" "symbiflow_place -e $(TOP).eblif -d $(DEVICE) -n $(TOP).net -P $(PARTNAME) -s $(SDC) > /dev/null"
]), ]),
Rule("$(TOP).route", ["$(TOP).place"], commands=[ Rule("$(TOP).route", ["$(TOP).place"], commands=[
"symbiflow_route -e $(TOP).eblif -d $(DEVICE) -s $(SDC) > /dev/null" "symbiflow_route -e $(TOP).eblif -d $(DEVICE) -s $(SDC) > /dev/null"
@ -196,24 +175,14 @@ class SymbiflowToolchain:
tools.write_to_file("Makefile", makefile.generate()) tools.write_to_file("Makefile", makefile.generate())
def _build_clock_constraints(self, platform): def _build_clock_constraints(self, platform):
for clk, (period, phase) in sorted(self.clocks.items(), key=lambda x: x[0].duid): platform.add_platform_command(_xdc_separator("Clock constraints"))
rising_edge = math.floor(period/360.0 * phase * 1e3)/1e3 for clk, period in sorted(self.clocks.items(), key=lambda x: x[0].duid):
falling_edge = math.floor(((rising_edge + period/2) % period) * 1.e3)/1e3 platform.add_platform_command(
platform.add_platform_command(f"create_clock -period {period} {{clk}} -waveform {{{{{rising_edge} {falling_edge}}}}}", clk=clk) "create_clock -period " + str(period) +
for from_, to in sorted(self.false_paths, key=lambda x: (x[0].duid, x[1].duid)): " {clk}", clk=clk)
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
# 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): def _fix_instance(self, instance):
if instance.of == "PLLE2_ADV": pass
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))
def build(self, platform, fragment, def build(self, platform, fragment,
build_dir = "build", build_dir = "build",
@ -255,9 +224,7 @@ class SymbiflowToolchain:
) )
# Generate design constraints # Generate design constraints
tools.write_to_file(build_name + ".xdc", _build_xdc(named_sc, False)) tools.write_to_file(build_name + ".xdc", _build_xdc(named_sc, named_pc))
tools.write_to_file(build_name + ".pcf", _build_pcf(named_sc))
tools.write_to_file(build_name + ".sdc", _build_sdc(named_pc))
if run: if run:
_run_make() _run_make()
@ -266,25 +233,14 @@ class SymbiflowToolchain:
return v_output.ns 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") clk.attr.add("keep")
phase = math.floor(phase % 360.0 * 1e3)/1e3
period = math.floor(period*1e3)/1e3 # round to lowest picosecond period = math.floor(period*1e3)/1e3 # round to lowest picosecond
if clk in self.clocks: 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" raise ValueError("Clock already constrained to {:.2f}ns, new constraint to {:.2f}ns"
.format(self.clocks[clk][0], period)) .format(self.clocks[clk], period))
if phase != self.clocks[clk][1]: self.clocks[clk] = period
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))
def symbiflow_build_args(parser): def symbiflow_build_args(parser):