symbiflow: remove workarounds for symbiflow
Signed-off-by: Alessandro Comodi <acomodi@antmicro.com>
This commit is contained in:
parent
8e39060d26
commit
0431af729c
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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):
|
||||||
|
|
Loading…
Reference in New Issue