From 4c966114f87dda4af485f6b6adac4fbd2d3d6fe3 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 19 Nov 2018 09:40:16 +0100 Subject: [PATCH] build/microsemi/libero_soc: add timing constraints support --- litex/build/microsemi/libero_soc.py | 48 ++++++++++++++++++++++++++--- litex/build/microsemi/platform.py | 9 +++++- 2 files changed, 52 insertions(+), 5 deletions(-) diff --git a/litex/build/microsemi/libero_soc.py b/litex/build/microsemi/libero_soc.py index 32fa40939..6e561c4d6 100644 --- a/litex/build/microsemi/libero_soc.py +++ b/litex/build/microsemi/libero_soc.py @@ -87,7 +87,7 @@ def _build_tcl(platform, sources, build_dir, build_name): "-adv_options {VCCI_2.5_VOLTR:EXT}", "-adv_options {VCCI_3.3_VOLTR:EXT}", "-adv_options {VOLTR:EXT} " - ])) + ])) # add files for filename, language, library in sources: @@ -102,7 +102,7 @@ def _build_tcl(platform, sources, build_dir, build_name): if file.endswith(".init"): tcl.append("file copy -- {} impl/synthesis".format(file)) - # import constraints + # import io constraints tcl.append("import_files -io_pdc {{{}}}".format(build_name + ".pdc")) tcl.append(" ".join(["organize_tool_files", "-tool {PLACEROUTE}", @@ -111,6 +111,15 @@ def _build_tcl(platform, sources, build_dir, build_name): "-input_type {constraint}" ])) + # import timing constraints + tcl.append("import_files -convert_EDN_to_HDL 0 -sdc {{{}}}".format(build_name + ".sdc")) + tcl.append(" ".join(["organize_tool_files", + "-tool {VERIFYTIMING}", + "-file impl/constraint/{}.sdc".format(build_name), + "-module {}".format(build_name), + "-input_type {constraint}" + ])) + # build flow tcl.append("run_tool -name {CONSTRAINT_MANAGEMENT}") tcl.append("run_tool -name {SYNTHESIZE}") @@ -129,6 +138,24 @@ def _build_tcl(platform, sources, build_dir, build_name): tools.write_to_file(build_name + ".tcl", "\n".join(tcl)) +def _build_sdc(vns, clocks, false_paths, build_name): + sdc = [] + + for clk, period in sorted(clocks.items(), key=lambda x: x[0].duid): + sdc.append( + "create_clock -name {clk} -period " + str(period) + + " [get_nets {clk}]".format(clk=vns.get_name(clk))) + for from_, to in sorted(false_paths, + key=lambda x: (x[0].duid, x[1].duid)): + sdc.append( + "set_clock_groups " + "-group [get_clocks -include_generated_clocks -of [get_nets {from_}]] " + "-group [get_clocks -include_generated_clocks -of [get_nets {to}]] " + "-asynchronous".format(from_=from_, to=to)) + + # generate sdc + tools.write_to_file(build_name + ".sdc", "\n".join(sdc)) + def _build_script(build_name, device, toolchain_path, ver=None): if sys.platform in ("win32", "cygwin"): script_ext = ".bat" @@ -170,6 +197,10 @@ class MicrosemiLiberoSoCPolarfireToolchain: special_overrides = common.microsemi_polarfire_special_overrides + def __init__(self): + self.clocks = dict() + self.false_paths = set() + def build(self, platform, fragment, build_dir="build", build_name="top", toolchain_path=None, run=False, **kwargs): os.makedirs(build_dir, exist_ok=True) @@ -190,9 +221,12 @@ class MicrosemiLiberoSoCPolarfireToolchain: # generate design script (tcl) _build_tcl(platform, platform.sources, build_dir, build_name) - # generate design constraints (pdc) + # generate design io constraints (pdc) _build_pdc(named_sc, named_pc, build_name) + # generate design timing constraints (sdc) + _build_sdc(top_output.ns, self.clocks, self.false_paths, build_name) + # generate build script script = _build_script(build_name, platform.device, toolchain_path) @@ -205,4 +239,10 @@ class MicrosemiLiberoSoCPolarfireToolchain: return top_output.ns def add_period_constraint(self, platform, clk, period): - print("TODO: add_period_constraint") \ No newline at end of file + if clk in self.clocks: + raise ValueError("A period constraint already exists") + self.clocks[clk] = period + + def add_false_path_constraint(self, platform, from_, to): + if (to, from_) not in self.false_paths: + self.false_paths.add((from_, to)) diff --git a/litex/build/microsemi/platform.py b/litex/build/microsemi/platform.py index 6ecb8e923..db6392884 100644 --- a/litex/build/microsemi/platform.py +++ b/litex/build/microsemi/platform.py @@ -13,7 +13,7 @@ class MicrosemiPlatform(GenericPlatform): raise ValueError("Unknown toolchain") def get_verilog(self, *args, special_overrides=dict(), **kwargs): - so = dict() # No common overrides between ECP and ice40. + so = dict() so.update(self.toolchain.special_overrides) so.update(special_overrides) return GenericPlatform.get_verilog(self, *args, special_overrides=so, @@ -27,3 +27,10 @@ class MicrosemiPlatform(GenericPlatform): if hasattr(clk, "p"): clk = clk.p self.toolchain.add_period_constraint(self, clk, period) + + def add_false_path_constraint(self, from_, to): + if hasattr(from_, "p"): + from_ = from_.p + if hasattr(to, "p"): + to = to.p + self.toolchain.add_false_path_constraint(self, from_, to)