Merge pull request #704 from antmicro/fix-symbiflow-workarounds
symbiflow: remove workarounds
This commit is contained in:
commit
9b3414746c
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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):
|
||||
|
|
Loading…
Reference in New Issue