From 6fe42a80c2aca3255f30e56fb11d04806f4b59ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20Harboe?= Date: Fri, 30 Oct 2026 10:32:25 +0100 Subject: [PATCH 1/5] args: a grammar for a command's arguments, with unit tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A _ARGS variable holds edits to the arguments ORFS passes to an OpenROAD command, written with the command's own options: -option value, -flag, ~-option to delete, on/off to run the command or not, each scoped to a stage (cts:) or one call (grt.wns:) when needed. PLATFORM_ARGS holds a platform's defaults, each edit naming its command. Layers merge lowest first: the flow's arguments, PLATFORM_ARGS, deprecated variables, _ARGS. args_grammar.bzl is written in the subset of Python that is also Starlark, so a Bazel build can load() it to check the grammar at analysis and give each stage only its own edits. args.py runs it for the stage scripts and checks every variable before a stage starts. test_args.py tests both. Co-Authored-By: Claude Opus 5.5 Signed-off-by: Øyvind Harboe --- flow/scripts/args.py | 230 +++++++++++++++++++ flow/scripts/args_grammar.bzl | 341 ++++++++++++++++++++++++++++ flow/test/test_args.py | 415 ++++++++++++++++++++++++++++++++++ 3 files changed, 986 insertions(+) create mode 100644 flow/scripts/args.py create mode 100644 flow/scripts/args_grammar.bzl create mode 100644 flow/test/test_args.py diff --git a/flow/scripts/args.py b/flow/scripts/args.py new file mode 100644 index 0000000000..95c20bc95d --- /dev/null +++ b/flow/scripts/args.py @@ -0,0 +1,230 @@ +#!/usr/bin/env python3 +"""Command arguments for the stage scripts: docs/user/CommandArguments.md. + +The stage scripts call this with $PYTHON_EXE, so that the handling of +arguments is in Python with unit tests (flow/test/test_args.py) instead of +in Tcl. The grammar itself is in args_grammar.bzl, which a Bazel build +load()s too. + + args.py check STAGE + Checks every _ARGS and PLATFORM_ARGS, and warns about each + deprecated variable STAGE reads that is set. Run before a stage + erases its non-stage variables. + + args.py runs COMMAND CALL RUN + Prints 1 or 0: whether the call runs. RUN is the flow's choice. + + args.py resolve COMMAND CALL RUN N FLOW... M DEPRECATED... [LEGACY] + Prints 1 or 0, whether the call runs, then the arguments it gets, + one per line, and names the call in the log. CALL is stage.name. FLOW is the command line the flow + passes when no _ARGS is set, deprecated variables included, + DEPRECATED the part of it that deprecated variables add: they rank + above PLATFORM_ARGS. LEGACY names a variable that replaces the + flow's arguments when it holds a plain command line; LEGACY:N keeps + the first N words of FLOW. +""" + +import json +import os +import sys + +DIR = os.path.dirname(os.path.realpath(__file__)) + + +class ArgsError(Exception): + pass + + +def _fail(msg): + raise ArgsError(msg) + + +def load_grammar(): + """args_grammar.bzl as a Python module, with Starlark's fail().""" + scope = {"fail": _fail} + with open(os.path.join(DIR, "args_grammar.bzl")) as f: + exec(compile(f.read(), "args_grammar.bzl", "exec"), scope) + return scope + + +G = load_grammar() + + +def tcl_split(text): + """Splits a value the way Tcl's {*} splits a list.""" + words = [] + i = 0 + n = len(text) + while i < n: + while i < n and text[i].isspace(): + i += 1 + if i >= n: + break + if text[i] == "{": + depth = 1 + j = i + 1 + while j < n and depth: + if text[j] == "{": + depth += 1 + elif text[j] == "}": + depth -= 1 + j += 1 + if depth: + raise ArgsError("unbalanced '{' in: " + text) + words.append(text[i + 1 : j - 1]) + i = j + elif text[i] == '"': + j = text.find('"', i + 1) + if j < 0: + raise ArgsError("unbalanced '\"' in: " + text) + words.append(text[i + 1 : j]) + i = j + 1 + else: + j = i + while j < n and not text[j].isspace(): + j += 1 + words.append(text[i:j]) + i = j + return words + + +def edits_of(env, name, platform=False): + return G["parse_args"](name, env.get(name, ""), G["STAGES"], platform) + + +def is_command_line(edits): + """True when a value uses nothing a plain command line can't say.""" + return all(e["op"] in ("set", "flag") and not e["stage"] for e in edits) + + +def check(env, stage, variables): + """Returns warnings; raises ArgsError on the first syntax error.""" + for command in sorted(G["COMMANDS"]): + edits_of(env, G["args_variable"](command)) + for e in edits_of(env, "PLATFORM_ARGS", platform=True): + if e["command"] not in G["COMMANDS"]: + raise ArgsError( + "PLATFORM_ARGS: '{}' is not a command with arguments here ({})".format( + e["command"], ", ".join(sorted(G["COMMANDS"])) + ) + ) + warnings = [] + for name in sorted(variables): + meta = variables[name] + if not meta.get("deprecated") or name not in env or env[name] == "": + continue + if str(meta.get("default", "")) == env[name]: + continue + stages = meta.get("stages", []) + if stages and "All stages" not in stages and stage not in stages: + continue + replacement = meta["replacement"] + if isinstance(replacement, dict): + if env[name] not in replacement: + continue + replacement = replacement[env[name]] + else: + replacement = replacement.format(value=G["quote_value"](env[name])) + warnings.append( + "{}={} is deprecated: write {}".format(name, env[name], replacement) + ) + return warnings + + +def resolve(env, command, stage, call, run, flow, deprecated, legacy=None, defaults={}): + """What one call of a command gets: [run, args, notes]. + + defaults are the variables.yaml defaults: a _ARGS at its + default is the flow's own choice, and its edits get no note. + """ + variable = G["args_variable"](command) + flow_edits = G["args_layer"](flow) + # A deprecated variable's option ranks above PLATFORM_ARGS where it + # survives in the flow's command line, as it does today; where the flow + # passes the option again after it, the flow's value wins, as today. + passed = G["resolve"]([["", flow_edits]], command, stage, call, True)["args"] + survives = dict(zip(passed, passed[1:] + [None])) + deprecated = [ + e + for e in G["args_layer"](deprecated) + if e["option"] in survives + and (e["value"] is None or survives[e["option"]] == e["value"]) + ] + layers = [ + ["the flow", flow_edits], + ["PLATFORM_ARGS", edits_of(env, "PLATFORM_ARGS", platform=True)], + ["deprecated variables", deprecated], + [variable, edits_of(env, variable)], + ] + r = G["resolve"](layers, command, stage, call, run) + notes = [ + "[{}.{}] {}: {} ({})".format(stage, call, command, G["format_args"]([e]), layer) + for layer, e in r["changes"] + if layer == "PLATFORM_ARGS" + or (layer == variable and env.get(variable) != defaults.get(variable)) + ] + legacy, _, fixed = (legacy or "").partition(":") + if legacy and env.get(legacy) and is_command_line(layers[3][1]): + old = flow[: int(fixed or 0)] + tcl_split(env[legacy]) + if old != r["args"]: + gone = [w for w in r["args"] if w.startswith("-") and w not in old] + notes = [ + "{} replaces the flow's arguments to {}; it will edit them" + " instead, so to keep this command line add {}".format( + legacy, command, " ".join("~" + w for w in gone) + ) + ] + return [r["run"], old, notes] + return [r["run"], r["args"], notes] + + +def _counted(argv): + n = int(argv[0]) + return argv[1 : 1 + n], argv[1 + n :] + + +def main(argv, env): + with open(os.path.join(DIR, "variables.json")) as f: + variables = json.load(f) + if argv[:1] == ["check"] and len(argv) == 2: + for w in check(env, argv[1], variables): + print("[WARNING] " + w, file=sys.stderr) + return 0 + if argv[:1] == ["resolve"] and len(argv) >= 6: + command, where, run = argv[1:4] + stage, _, call = where.partition(".") + flow, rest = _counted(argv[4:]) + deprecated, rest = _counted(rest) + legacy = rest[0] if rest else None + defaults = { + k: str(v["default"]) for k, v in variables.items() if "default" in v + } + run, args, notes = resolve( + env, command, stage, call, run == "1", flow, deprecated, legacy, defaults + ) + # The call's name goes in the log in front of the command, so a user + # can copy it into a scope. + for note in notes or ["[{}] {}".format(where, command)]: + print(note, file=sys.stderr) + print("1" if run else "0") + for w in args: + print(w) + return 0 + if argv[:1] == ["runs"] and len(argv) == 4: + command, where, run = argv[1:4] + stage, _, call = where.partition(".") + run, _, notes = resolve(env, command, stage, call, run == "1", [], []) + for note in notes: + print(note, file=sys.stderr) + print("1" if run else "0") + return 0 + print(__doc__, file=sys.stderr) + return 2 + + +if __name__ == "__main__": + try: + sys.exit(main(sys.argv[1:], os.environ)) + except ArgsError as e: + print("[ERROR] " + str(e), file=sys.stderr) + sys.exit(1) diff --git a/flow/scripts/args_grammar.bzl b/flow/scripts/args_grammar.bzl new file mode 100644 index 0000000000..5db80eb7a0 --- /dev/null +++ b/flow/scripts/args_grammar.bzl @@ -0,0 +1,341 @@ +"""The _ARGS grammar: edits to the arguments ORFS passes to a command. + +See docs/user/CommandArguments.md for the user's view. In short: + + -option value set the value + -flag add the flag + ~-option delete the option, and its value if it has one + on / off run the command / do not run it + stage: in front of an edit: only in that stage + stage.call: in front of an edit: only at that call + command: in front of an edit: the command it is for; only in + PLATFORM_ARGS, where every edit names one + {a b} or "a b" a value with spaces in it, as in Tcl + +Layers merge lowest first. For each option the highest layer that mentions +it decides; within a layer a call edit beats a stage edit, a stage edit +beats an unscoped one, and later beats earlier. + +This file is Python and Starlark both: ORFS runs it as Python (args.py), +and a Bazel build load()s it to check the grammar at analysis and to give +each stage only its own edits. Keep it in the common subset: no while, +recursion, classes, exceptions, sets, f-strings or iteration over a string, +and nothing at the top level but assignments and defs. Errors go through +fail(), a Starlark builtin that args.py provides when it runs this file. +""" + +# The commands a _ARGS variable can edit, each read in the stages +# that run it. The variable's name is the command's in upper case. +COMMANDS = { + "balance_row_usage": ["place"], + "buffer_ports": ["place"], + "clock_tree_synthesis": ["cts"], + "cluster_flops": ["place"], + "detailed_placement": ["place", "cts", "grt"], + "detailed_route": ["route"], + "global_placement": ["place"], + "global_route": ["grt"], + "improve_placement": ["place"], + "place_pins": ["place"], + "repair_antennas": ["grt", "route"], + "repair_design": ["place", "grt"], + "repair_tie_fanout": ["floorplan"], + "repair_timing": ["floorplan", "place", "cts", "grt"], + "report_metrics": ["synth", "floorplan", "place", "cts", "grt", "route", "final"], + "rtl_macro_placer": ["floorplan"], +} + +# The stages a scope can name, in flow order. +STAGES = ["synth", "floorplan", "place", "cts", "grt", "route", "final"] + +def args_variable(command): + return command.upper() + "_ARGS" + +_IDENT_START ="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_" +_IDENT_REST = _IDENT_START + "0123456789" +_SPACE = " \t\n\r" + +def _is_ident(s): + if not s or s[0] not in _IDENT_START: + return False + for i in range(1, len(s)): + if s[i] not in _IDENT_REST: + return False + return True + +def _is_option(token): + # -name, not -5 or -0.5: a negative number is a value. + return len(token) > 1 and token[0] == "-" and _is_ident(token[1:]) + +_CLOSE = {"{": "}", "\"": "\""} + +def _tokenize(name, text): + """Splits on whitespace into (word, quoted) pairs. + + {...} or "..." around a value makes it one word, as in Tcl. + """ + tokens = [] + current = "" + braced = False + close = "" + for i in range(len(text)): + c = text[i] + if close: + if c == close: + close = "" + elif c == "{" or (c == "\"" and close == "}"): + fail("{}: '{}' inside a quoted value at character {}; a value is quoted once".format(name, c, i)) + else: + current += c + elif c in _CLOSE: + if current: + fail("{}: '{}' inside a word at character {}; quotes go around a whole value".format(name, c, i)) + close = _CLOSE[c] + braced = True + elif c == "}": + fail("{}: '}}' with no '{{' before it, at character {}".format(name, i)) + elif c in _SPACE: + if current or braced: + tokens.append((current, braced)) + current = "" + braced = False + else: + if braced: + fail("{}: text right after a quoted value at character {}; put a space after it".format(name, i)) + current += c + if close: + fail("{}: '{}' is never closed".format(name, "{" if close == "}" else "\"")) + if current or braced: + tokens.append((current, braced)) + return tokens + +def _is_edit_word(word): + return word in ("on", "off") or _is_option(word) or (word.startswith("~") and len(word) > 1) + +def _split_scope(name, token, platform, stages): + """Returns [command, stage, call, edit] for a scoped token, else None.""" + parts = token.split(":") + if len(parts) == 1 or not _is_edit_word(parts[-1]): + # No edit after the last colon, so no scope: a value such as a:b. + return None + edit = parts[-1] + scopes = parts[:-1] + command = "" + if platform: + if not _is_ident(scopes[0]) or scopes[0] in stages: + fail("{}: '{}' must start with the command it is for, as in clock_tree_synthesis:{}".format(name, token, edit)) + command = scopes[0] + scopes = scopes[1:] + if len(scopes) > 1: + fail("{}: '{}' has too many scopes; write {}stage:edit or {}stage.call:edit".format( + name, + token, + "command:" if platform else "", + "command:" if platform else "", + )) + stage = "" + call = "" + if scopes: + where = scopes[0].split(".") + if len(where) > 2: + fail("{}: '{}': a scope is a stage or stage.call".format(name, token)) + stage = where[0] + if stage not in stages: + fail("{}: '{}': '{}' is not a stage ({}){}".format( + name, + token, + stage, + ", ".join(stages), + "" if platform else "; only PLATFORM_ARGS names a command", + )) + if len(where) == 2: + call = where[1] + if not _is_ident(call): + fail("{}: '{}': '{}' is not a call name".format(name, token, call)) + return [command, stage, call, edit] + +def parse_args(name, text, stages, platform = False): + """Parses a variable's value into a list of edits. + + Args: + name: the variable's name, for error messages. + text: the variable's value. + stages: the stage names a scope may use. + platform: True for PLATFORM_ARGS, where every edit names its command. + + Returns: + A list of dicts with keys command, stage, call, op ("set", "flag", + "delete", "on" or "off"), option and value. Fails on a syntax error. + """ + edits = [] + pending = None + for token, braced in _tokenize(name, text): + scoped = None + if not braced: + scoped = _split_scope(name, token, platform, stages) + if scoped != None: + command, stage, call, word = scoped + else: + command, stage, call, word = "", "", "", token + if braced or (scoped == None and not _is_edit_word(word)): + if pending == None: + fail("{}: '{}' is a value with no option before it; a value with spaces goes in braces".format(name, token)) + pending["op"] = "set" + pending["value"] = token + pending = None + continue + if platform and not command: + fail("{}: '{}' must start with the command it is for, as in clock_tree_synthesis:{}".format(name, token, token)) + pending = None + e = {"command": command, "stage": stage, "call": call, "op": "", "option": "", "value": None} + if word in ("on", "off"): + e["op"] = word + elif word.startswith("~"): + if not _is_option(word[1:]): + fail("{}: '{}': '~' deletes an option, as in ~-repair_clock_nets".format(name, token)) + e["op"] = "delete" + e["option"] = word[1:] + else: + e["op"] = "flag" + e["option"] = word + pending = e + edits.append(e) + return edits + +def quote_value(value): + """A value as the grammar writes it, in braces when it needs them.""" + if value == "" or value in ("on", "off") or value.startswith("~") or _is_option(value) or ":" in value: + return "{" + value + "}" + for i in range(len(value)): + if value[i] in _SPACE or value[i] in "{}": + return "{" + value + "}" + return value + +def format_args(edits, platform = False): + """Writes edits back in the grammar: the inverse of parse_args().""" + words = [] + for e in edits: + prefix = "" + if platform: + prefix = e["command"] + ":" + if e["stage"]: + prefix += e["stage"] + if e["call"]: + prefix += "." + e["call"] + prefix += ":" + if e["op"] in ("on", "off"): + words.append(prefix + e["op"]) + elif e["op"] == "delete": + words.append(prefix + "~" + e["option"]) + else: + words.append(prefix + e["option"]) + if e["op"] == "set": + words.append(quote_value(e["value"])) + return " ".join(words) + +def stage_args(name, text, stage, stages, platform = False): + """The part of a variable's value that can matter in one stage. + + An unscoped edit matters in every stage, a scoped one only in its own, + so a build that keys each stage on its inputs can give each stage this + and leave the other stages' keys alone. + """ + if stage not in stages: + fail("{}: '{}' is not a stage ({})".format(name, stage, ", ".join(stages))) + edits = parse_args(name, text, stages, platform) + return format_args([e for e in edits if e["stage"] in ("", stage)], platform) + +def args_layer(words): + """A list of words, as a command line takes them, as a layer of edits.""" + edits = [] + pending = None + for w in words: + if pending != None and not _is_option(w): + pending["op"] = "set" + pending["value"] = w + pending = None + continue + if not _is_option(w): + fail("'{}' is a value with no option before it in {}".format(w, " ".join(words))) + e = {"command": "", "stage": "", "call": "", "op": "flag", "option": w, "value": None} + edits.append(e) + pending = e + return edits + +def _specificity(e): + if e["call"]: + return 2 + if e["stage"]: + return 1 + return 0 + +def resolve(layers, command, stage, call, run = True): + """Merges layers of edits into what one call of a command gets. + + Args: + layers: a list of [name, edits] pairs, lowest priority first, with + edits as parse_args() or args_layer() returns them. An edit that + names a command applies only to that command. + command: the command being called. + stage: the stage it is called in. + call: the call's name within the stage. + run: whether the command runs when no layer says on or off. + + Returns: + A dict: "run", a bool; "args", the words to pass, in the order the + options were first set; "changes", a list of [layer, edit] for each + edit that changed what the layers below it gave. + """ + values = {} + kinds = {} + order = [] + changes = [] + for layer in layers: + layer_name = layer[0] + edits = layer[1] + applicable = [] + for i in range(len(edits)): + e = edits[i] + if e["command"] and e["command"] != command: + continue + if e["stage"] and e["stage"] != stage: + continue + if e["call"] and e["call"] != call: + continue + applicable.append([_specificity(e), i, e]) + for _, _, e in sorted(applicable, key = lambda t: (t[0], t[1])): + op = e["op"] + if op in ("on", "off"): + if run != (op == "on"): + changes.append([layer_name, e]) + run = op == "on" + continue + option = e["option"] + if op == "delete": + if option in values: + changes.append([layer_name, e]) + values.pop(option) + order.remove(option) + continue + kind = "flag" if op == "flag" else "value" + if option in kinds and kinds[option] != kind: + fail("{}: {} {} {} here, and {} below".format( + layer_name, + command, + option, + "takes no value" if kind == "flag" else "takes a value", + "a value" if kind == "flag" else "no value", + )) + kinds[option] = kind + if option not in values: + order.append(option) + elif values[option] == e["value"]: + continue + changes.append([layer_name, e]) + values[option] = e["value"] + words = [] + for option in order: + words.append(option) + if values[option] != None: + words.append(values[option]) + return {"run": run, "args": words, "changes": changes} diff --git a/flow/test/test_args.py b/flow/test/test_args.py new file mode 100644 index 0000000000..d40415577c --- /dev/null +++ b/flow/test/test_args.py @@ -0,0 +1,415 @@ +#!/usr/bin/env python3 +"""Unit tests for command arguments: scripts/args.py and args_grammar.bzl.""" + +import os +import sys +import unittest + +sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "scripts")) + +import args # noqa: E402 + +G = args.G +STAGES = G["STAGES"] + + +def parse(text, platform=False): + return G["parse_args"]("X_ARGS", text, STAGES, platform) + + +def fmt(text, platform=False): + return G["format_args"](parse(text, platform), platform) + + +def run(env, command="repair_timing", stage="grt", call="main", flow=(), dep=()): + return args.resolve(env, command, stage, call, True, list(flow), list(dep)) + + +class Parse(unittest.TestCase): + def test_set_flag_delete(self): + e = parse("-a 1 -b ~-c") + self.assertEqual( + [(x["op"], x["option"], x["value"]) for x in e], + [("set", "-a", "1"), ("flag", "-b", None), ("delete", "-c", None)], + ) + + def test_negative_number_is_a_value(self): + self.assertEqual(parse("-margin -0.5")[0]["value"], "-0.5") + + def test_quoted_values(self): + self.assertEqual(parse("-a {20 20}")[0]["value"], "20 20") + self.assertEqual(parse('-a "x y"')[0]["value"], "x y") + self.assertEqual(parse("-a {}")[0]["value"], "") + + def test_on_off_and_scopes(self): + e = parse("off cts:on grt.wns:-x 1 floorplan:~-y") + self.assertEqual( + [(x["op"], x["stage"], x["call"]) for x in e], + [("off", "", ""), ("on", "cts", ""), ("set", "grt", "wns")] + + [("delete", "floorplan", "")], + ) + + def test_colon_in_a_value_is_no_scope(self): + self.assertEqual(parse("-file a:b")[0]["value"], "a:b") + + def test_platform_names_the_command(self): + e = parse("rtl_macro_placer:-halo_width 5 repair_timing:grt:off", True) + self.assertEqual( + [(x["command"], x["stage"], x["op"]) for x in e], + [("rtl_macro_placer", "", "set"), ("repair_timing", "grt", "off")], + ) + + def test_round_trip(self): + for text in [ + "-a 1 -b ~-c on cts:off grt.wns:-x {1 2}", + "-file {a:b} -name {-x} -v {on}", + ]: + self.assertEqual(fmt(fmt(text)), fmt(text)) + self.assertEqual(parse(fmt(text)), parse(text)) + text = "repair_timing:grt:-x 1 clock_tree_synthesis:~-y" + self.assertEqual(parse(fmt(text, True), True), parse(text, True)) + + +class SyntaxErrors(unittest.TestCase): + def check(self, text, message, platform=False): + with self.assertRaises(args.ArgsError) as cm: + parse(text, platform) + self.assertIn(message, str(cm.exception)) + + def test_value_without_option(self): + self.check("30", "value with no option") + self.check("-a 1 2", "'2' is a value with no option") + + def test_quotes(self): + self.check("-a {1", "never closed") + self.check("-a 1}", "with no '{'") + self.check("-a {{1}}", "quoted once") + self.check("-a x{1}", "inside a word") + self.check("-a {1}x", "right after a quoted value") + + def test_scopes(self): + self.check("plce:-a 1", "'plce' is not a stage") + self.check("grt.a.b:-x", "a stage or stage.call") + self.check("cts:grt:-x", "too many scopes") + self.check("~x", "'~' deletes an option") + + def test_platform(self): + self.check("-x 1", "must start with the command", True) + self.check("cts:-x 1", "must start with the command", True) + + +class StageArgs(unittest.TestCase): + def test_only_this_stage(self): + text = "-a 1 cts:-b 2 grt.wns:off" + self.assertEqual(G["stage_args"]("X", text, "cts", STAGES), "-a 1 cts:-b 2") + self.assertEqual(G["stage_args"]("X", text, "grt", STAGES), "-a 1 grt.wns:off") + self.assertEqual(G["stage_args"]("X", text, "place", STAGES), "-a 1") + + +class Resolve(unittest.TestCase): + def test_nothing_set_gives_the_flow_unchanged(self): + flow = ["-setup_margin", "0.1", "-setup", "-sequence", "a,b", "-skip_last_gasp"] + self.assertEqual( + run({}, flow=flow, dep=["-setup_margin", "0.1"]), [True, flow, []] + ) + + def test_override_in_place_add_and_delete(self): + env = {"REPAIR_TIMING_ARGS": "-sequence vt_swap -hold ~-skip_last_gasp"} + r = run(env, flow=["-setup", "-sequence", "a", "-skip_last_gasp"]) + self.assertEqual(r[1], ["-setup", "-sequence", "vt_swap", "-hold"]) + + def test_deleting_an_option_not_passed_is_no_error(self): + self.assertEqual( + run({"REPAIR_TIMING_ARGS": "~-hold"}, flow=["-setup"])[1], ["-setup"] + ) + + def test_layers_highest_wins(self): + env = { + "PLATFORM_ARGS": "repair_timing:-x 2 repair_timing:-y 2", + "REPAIR_TIMING_ARGS": "-y 3", + } + r = run(env, flow=["-x", "0"]) + self.assertEqual(r[1], ["-x", "2", "-y", "3"]) + + def test_deprecated_beats_platform(self): + env = {"PLATFORM_ARGS": "repair_timing:-x 2"} + self.assertEqual(run(env, flow=["-x", "1"], dep=["-x", "1"])[1], ["-x", "1"]) + self.assertEqual(run(env, flow=["-x", "0"])[1], ["-x", "2"]) + + def test_flow_passing_an_option_again_beats_the_deprecated_one(self): + flow = ["-sequence", "a", "-setup", "-sequence", "b"] + self.assertEqual( + run({}, flow=flow, dep=["-sequence", "a"])[1], ["-sequence", "b", "-setup"] + ) + env = {"PLATFORM_ARGS": "repair_timing:-sequence c"} + self.assertEqual( + run(env, flow=flow, dep=["-sequence", "a"])[1], ["-sequence", "c", "-setup"] + ) + + def test_specificity_within_a_layer(self): + env = {"REPAIR_TIMING_ARGS": "grt.main:-x 3 grt:-x 2 -x 1"} + self.assertEqual(run(env)[1], ["-x", "3"]) + self.assertEqual(run(env, call="wns")[1], ["-x", "2"]) + self.assertEqual(run(env, stage="cts")[1], ["-x", "1"]) + + def test_a_higher_layer_beats_a_more_specific_lower_one(self): + env = { + "PLATFORM_ARGS": "repair_timing:grt.main:-x 1", + "REPAIR_TIMING_ARGS": "-x 2", + } + self.assertEqual(run(env)[1], ["-x", "2"]) + + def test_on_off(self): + env = {"REPAIR_TIMING_ARGS": "off cts:on"} + self.assertFalse(run(env)[0]) + self.assertTrue(run(env, stage="cts")[0]) + self.assertFalse( + args.resolve({}, "report_metrics", "cts", "x", False, [], [])[0] + ) + + def test_platform_edit_for_another_command_is_ignored(self): + env = {"PLATFORM_ARGS": "clock_tree_synthesis:-x 1"} + self.assertEqual(run(env)[1], []) + + def test_flag_and_value_conflict(self): + with self.assertRaises(args.ArgsError) as cm: + run({"REPAIR_TIMING_ARGS": "-x"}, flow=["-x", "1"]) + self.assertIn("takes no value here", str(cm.exception)) + + def test_no_note_for_an_edit_that_changes_nothing(self): + self.assertEqual( + run({"REPAIR_TIMING_ARGS": "-x 1 on"}, flow=["-x", "1"])[2], [] + ) + + def test_no_note_for_a_variable_at_its_default(self): + env = {"GLOBAL_ROUTE_ARGS": "-verbose"} + r = args.resolve( + env, + "global_route", + "grt", + "main", + True, + [], + [], + None, + {"GLOBAL_ROUTE_ARGS": "-verbose"}, + ) + self.assertEqual(r[1:], [["-verbose"], []]) + + def test_notes_name_the_call_and_layer(self): + notes = run({"REPAIR_TIMING_ARGS": "-x 1"})[2] + self.assertEqual(notes, ["[grt.main] repair_timing: -x 1 (REPAIR_TIMING_ARGS)"]) + + +class Legacy(unittest.TestCase): + FIXED = ["-output_drc", "drc.rpt"] + FLOW = FIXED + ["-verbose", "1", "-drc_report_iter_step", "5"] + + def resolve(self, value): + env = {"DETAILED_ROUTE_ARGS": value} + return args.resolve( + env, + "detailed_route", + "route", + "main", + True, + self.FLOW, + [], + "DETAILED_ROUTE_ARGS:2", + ) + + def test_a_command_line_that_reads_the_same_either_way(self): + r = self.resolve("-verbose 1 -drc_report_iter_step 5 -droute_end_iter 3") + self.assertEqual(r[1], self.FLOW + ["-droute_end_iter", "3"]) + self.assertEqual( + r[2], + ["[route.main] detailed_route: -droute_end_iter 3 (DETAILED_ROUTE_ARGS)"], + ) + + def test_a_command_line_still_replaces(self): + r = self.resolve("-droute_end_iter 3") + self.assertEqual(r[1], self.FIXED + ["-droute_end_iter", "3"]) + self.assertIn("add ~-verbose ~-drc_report_iter_step", r[2][0]) + + def test_edits_edit(self): + r = self.resolve("~-verbose") + self.assertEqual(r[1], self.FIXED + ["-drc_report_iter_step", "5"]) + + def test_tcl_split(self): + self.assertEqual( + args.tcl_split(' -a {b c} "d e" f '), ["-a", "b c", "d e", "f"] + ) + self.assertEqual(args.tcl_split("-a {b {c}}"), ["-a", "b {c}"]) + + +class Check(unittest.TestCase): + VARS = { + "CTS_CLUSTER_SIZE": { + "deprecated": 1, + "stages": ["cts"], + "replacement": "CLOCK_TREE_SYNTHESIS_ARGS = -sink_clustering_size {value}", + }, + "SKIP_CTS_REPAIR_TIMING": { + "deprecated": 1, + "default": 0, + "stages": ["cts"], + "replacement": {"1": "REPAIR_TIMING_ARGS = cts:off"}, + }, + "RTLMP_MIN_CHANNEL_SIZE": { + "deprecated": 1, + "stages": ["floorplan"], + "replacement": "RTL_MACRO_PLACER_ARGS = -min_channel_size {value}", + }, + } + + def test_a_value_with_spaces_is_braced(self): + self.assertEqual( + args.check({"RTLMP_MIN_CHANNEL_SIZE": "20 20"}, "floorplan", self.VARS), + [ + "RTLMP_MIN_CHANNEL_SIZE=20 20 is deprecated: write " + "RTL_MACRO_PLACER_ARGS = -min_channel_size {20 20}" + ], + ) + + def test_warns_only_when_set_in_its_stage_and_not_default(self): + env = {"CTS_CLUSTER_SIZE": "30", "SKIP_CTS_REPAIR_TIMING": "0"} + self.assertEqual( + args.check(env, "cts", self.VARS), + [ + "CTS_CLUSTER_SIZE=30 is deprecated: write " + "CLOCK_TREE_SYNTHESIS_ARGS = -sink_clustering_size 30" + ], + ) + self.assertEqual(args.check(env, "grt", self.VARS), []) + env["SKIP_CTS_REPAIR_TIMING"] = "1" + self.assertEqual(len(args.check(env, "cts", self.VARS)), 2) + + def test_syntax_error_in_any_command(self): + with self.assertRaises(args.ArgsError): + args.check({"CLOCK_TREE_SYNTHESIS_ARGS": "-a {"}, "synth", {}) + + def test_platform_args_unknown_command(self): + with self.assertRaises(args.ArgsError) as cm: + args.check({"PLATFORM_ARGS": "nope:-x 1"}, "synth", {}) + self.assertIn("'nope' is not a command", str(cm.exception)) + + +class StarlarkSubset(unittest.TestCase): + """args_grammar.bzl stays in the subset of Python that is also Starlark. + + ORFS has no Bazel, so this is the check that a change to the grammar + still loads in a Bazel build. It rejects the constructs Starlark lacks; + a Bazel build that load()s the file is the final word. + """ + + BANNED = { + "While": "while loops", + "Try": "exceptions", + "Raise": "exceptions", + "ClassDef": "classes", + "JoinedStr": "f-strings", + "Set": "sets", + "SetComp": "sets", + "Yield": "generators", + "YieldFrom": "generators", + "GeneratorExp": "generators", + "Global": "global", + "Nonlocal": "nonlocal", + "Import": "import", + "ImportFrom": "import", + "With": "with", + "AsyncFunctionDef": "async", + "Await": "async", + "Starred": "star expressions outside calls", + "Is": "is / is not", + "IsNot": "is / is not", + } + + def test_only_the_common_subset(self): + import ast + + path = os.path.join(args.DIR, "args_grammar.bzl") + tree = ast.parse(open(path).read()) + for node in tree.body: + ok = isinstance(node, (ast.FunctionDef, ast.Assign)) or ( + isinstance(node, ast.Expr) and isinstance(node.value, ast.Constant) + ) + self.assertTrue( + ok, + "line {}: only defs and assignments at the top level".format( + node.lineno + ), + ) + defs = {n.name for n in tree.body if isinstance(n, ast.FunctionDef)} + for node in ast.walk(tree): + name = type(node).__name__ + if name in self.BANNED: + self.fail( + "line {}: {} is not Starlark".format( + getattr(node, "lineno", "?"), self.BANNED[name] + ) + ) + if isinstance(node, ast.FunctionDef): + calls = { + c.func.id + for c in ast.walk(node) + if isinstance(c, ast.Call) and isinstance(c.func, ast.Name) + } + if node.name in calls: + self.fail("{} recurses; Starlark doesn't".format(node.name)) + if isinstance(node, (ast.For, ast.comprehension)) and isinstance( + node.iter, ast.Name + ): + # Starlark can't iterate a string; the grammar indexes them instead. + self.assertNotIn( + node.iter.id, + ("text", "s", "token", "value", "word"), + "line {}: iterating a string".format(node.iter.lineno), + ) + self.assertTrue(defs) + + +class Main(unittest.TestCase): + def capture(self, argv, env): + import contextlib + import io + + out, err = io.StringIO(), io.StringIO() + with contextlib.redirect_stdout(out), contextlib.redirect_stderr(err): + args.main(argv, env) + return out.getvalue().splitlines(), err.getvalue().splitlines() + + def test_resolve_names_the_call(self): + out, err = self.capture( + ["resolve", "repair_timing", "grt.wns", "1", "0", "0"], {} + ) + self.assertEqual((out, err), (["1"], ["[grt.wns] repair_timing"])) + + def test_runs(self): + env = {"REPORT_METRICS_ARGS": "grt:off"} + self.assertEqual( + self.capture(["runs", "report_metrics", "grt.x", "1"], env)[0], ["0"] + ) + self.assertEqual( + self.capture(["runs", "report_metrics", "cts.x", "1"], env), (["1"], []) + ) + + def test_resolve_protocol(self): + out = [] + old = sys.stdout + try: + import io + + sys.stdout = io.StringIO() + args.main( + ["resolve", "repair_timing", "cts.main", "1", "2", "-a", "b c", "0"], + {"REPAIR_TIMING_ARGS": "cts:-d"}, + ) + out = sys.stdout.getvalue().splitlines() + finally: + sys.stdout = old + self.assertEqual(out, ["1", "-a", "b c", "-d"]) + + +if __name__ == "__main__": + unittest.main() From 06c3bb3e833d7754c5c96811fbb252ac1b906663 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20Harboe?= Date: Fri, 30 Oct 2026 10:32:25 +0100 Subject: [PATCH 2/5] flow: pass every wrapped command's arguments through the grammar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every command a stage script runs with arguments a user could change, 16 in all, takes them from command_args and command_runs in util.tcl, which call args.py with $PYTHON_EXE so the merge has unit tests. Each call has a name, stage.call, that an edit can be scoped to. Nothing changes for a design that sets no new variable: the flow's arguments, deprecated variables included, are the command line as before. erase_non_stage_variables checks every _ARGS and PLATFORM_ARGS first, so a syntax error stops the stage before it runs. variables.yaml gains a _ARGS for each command that had none, and PLATFORM_ARGS. The 63 variables that passed one option to one command, or switched one step on or off, are marked deprecated with the line that replaces them: they keep working, and a stage that reads one warns with that line. CTS_ARGS and RTLMP_ARGS still replace the flow's arguments, and so does DETAILED_ROUTE_ARGS while it holds a plain command line. Co-Authored-By: Claude Opus 5.5 Signed-off-by: Øyvind Harboe --- docs/user/FlowVariables.md | 173 +++++++++------ flow/scripts/cts.tcl | 36 ++- flow/scripts/detail_place.tcl | 19 +- flow/scripts/detail_route.tcl | 63 +++--- flow/scripts/floorplan.tcl | 33 +-- flow/scripts/generate-variables-docs.py | 9 + flow/scripts/global_place.tcl | 26 +-- flow/scripts/global_place_skip_io.tcl | 14 +- flow/scripts/global_route.tcl | 69 +++--- flow/scripts/io_placement.tcl | 6 +- flow/scripts/macro_place_util.tcl | 49 ++-- flow/scripts/report_metrics.tcl | 8 +- flow/scripts/resize.tcl | 6 +- flow/scripts/util.tcl | 80 ++++--- flow/scripts/variables.json | 265 +++++++++++++++++++++- flow/scripts/variables.yaml | 282 +++++++++++++++++++++++- flow/test/test_args.py | 33 +++ 17 files changed, 889 insertions(+), 282 deletions(-) diff --git a/docs/user/FlowVariables.md b/docs/user/FlowVariables.md index 7ea1adf6aa..388c1f7d6a 100644 --- a/docs/user/FlowVariables.md +++ b/docs/user/FlowVariables.md @@ -104,48 +104,51 @@ configuration file. | ADDITIONAL_SITES| Passed as -additional_sites to initialize_floorplan.| | | ASAP7_USE_VT| A space separated list of VT options to use with the ASAP7 standard cell library: RVT, LVT, SLVT.| RVT| | AUTO_MEMORIES| Experimental. When set to 1, memories that yosys infers in the RTL (`$mem_v2` cells, module boundary only) are detected pre-synthesis, inventoried in `$(RESULTS_DIR)/memories.json`, and — when idiomatic as an SRAM macro — given generated .lib/.lef views under `$(RESULTS_DIR)/memories/`. Synthesis blackboxes those modules and all later stages read the generated views, so an existing design gets macro-based results without a memory compiler. Supported for the asap7 platform only. See docs/user/AutoMemories.md.| 0| -| BALANCE_ROWS| Balance rows during placement.| 0| +| BALANCE_ROWS (deprecated)| Balance rows during placement. Instead of BALANCE_ROWS=1, write `BALANCE_ROW_USAGE_ARGS = on`.| 0| +| BALANCE_ROW_USAGE_ARGS| Edits to the arguments the flow passes to `balance_row_usage`, in the grammar of docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, `on`/`off`, each optionally scoped `stage:` or `stage.call:`.| | | BLOCKS| Blocks used as hard macros in a hierarchical flow. Do note that you have to specify block-specific inputs file in the directory mentioned by Makefile.| | -| BUFFER_PORTS_ARGS| Specify arguments to the buffer_ports call during placement. Only used if DONT_BUFFER_PORTS=0.| | +| BUFFER_PORTS_ARGS| Edits to the arguments the flow passes to `buffer_ports`, in the grammar of docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, `on`/`off`, each optionally scoped `stage:` or `stage.call:`.| | | CACHED_REPORTS| List of pre-existing report files to copy into the reports directory before synthesis. Used when reusing prior synthesis results with SYNTH_NETLIST_FILES.| | -| CAP_MARGIN| Specifies a capacitance margin when fixing max capacitance violations. This option allows you to overfix.| | +| CAP_MARGIN (deprecated)| Specifies a capacitance margin when fixing max capacitance violations. This option allows you to overfix. Instead, write `REPAIR_DESIGN_ARGS = -cap_margin `.| | | CDL_FILE| CDL master netlist file used as the -masters argument to write_cdl for generating Circuit Description Language output.| | | CDL_FILES| Insert additional Circuit Description Language (`.cdl`) netlist files.| | | CELL_PAD_IN_SITES_DETAIL_PLACEMENT| Cell padding on both sides in site widths to ease routability in detail placement.| 0| | CELL_PAD_IN_SITES_GLOBAL_PLACEMENT| Cell padding on both sides in site widths to ease routability during global placement.| 0| | CLKGATE_MAP_FILE| Optional mapping file supplied to Yosys to map clock gating cells| | -| CLUSTER_FLOPS| Enable clustering of flip-flops into multi-bit flip-flops, if the platform PDK includes multi-bit flip-flops| 0| -| CLUSTER_FLOPS_ARGS| Additional arguments passed to the cluster_flops command. Only used when CLUSTER_FLOPS is set.| | +| CLOCK_TREE_SYNTHESIS_ARGS| Edits to the arguments the flow passes to `clock_tree_synthesis`, in the grammar of docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, `on`/`off`, each optionally scoped `stage:` or `stage.call:`.| | +| CLUSTER_FLOPS (deprecated)| Enable clustering of flip-flops into multi-bit flip-flops, if the platform PDK includes multi-bit flip-flops Instead of CLUSTER_FLOPS=1, write `CLUSTER_FLOPS_ARGS = on`.| 0| +| CLUSTER_FLOPS_ARGS| Edits to the arguments the flow passes to `cluster_flops`, in the grammar of docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, `on`/`off`, each optionally scoped `stage:` or `stage.call:`.| | | CORE_AREA| The core area specified as a list of lower-left and upper-right corners in microns (X1 Y1 X2 Y2).| | | CORE_ASPECT_RATIO| The core aspect ratio (height / width). This variable is only used when `CORE_UTILIZATION` is set.| 1.0| | CORE_MARGIN| The margin between the core area and die area, specified in microns. Allowed values are either one value for all margins or a set of four values, one for each margin. The order of the four values are: `{bottom top left right}`. This variable is only used when `CORE_UTILIZATION` is set.| 1.0| | CORE_UTILIZATION| The core utilization percentage (0-100).| | | CORNER| PVT corner library selection. Only available for ASAP7 and GF180 PDKs.| | | CORNERS| List of timing corner names for multi-corner analysis (e.g. "slow fast"). When set, liberty files are loaded per corner using uppercase _LIB_FILES environment variables (e.g. corner "slow" reads SLOW_LIB_FILES) and timing models are generated per corner.| | -| CTS_ARGS| Override `clock_tree_synthesis` arguments.| | -| CTS_BUF_DISTANCE| Distance (in microns) between buffers.| | -| CTS_BUF_LIST| List of cells used to construct the clock tree. Overrides buffer inference.| | -| CTS_CLUSTER_DIAMETER| Maximum diameter (in microns) of sink cluster.| | -| CTS_CLUSTER_SIZE| Maximum number of sinks per cluster.| | -| CTS_LIB_NAME| Name of the Liberty library to use in selecting the clock buffers.| | +| CTS_ARGS (deprecated)| Override `clock_tree_synthesis` arguments. Instead, write `CLOCK_TREE_SYNTHESIS_ARGS, with only what differs from the flow's arguments`.| | +| CTS_BUF_DISTANCE (deprecated)| Distance (in microns) between buffers. Instead, write `CLOCK_TREE_SYNTHESIS_ARGS = -distance_between_buffers `.| | +| CTS_BUF_LIST (deprecated)| List of cells used to construct the clock tree. Overrides buffer inference. Instead, write `CLOCK_TREE_SYNTHESIS_ARGS = -buf_list `.| | +| CTS_CLUSTER_DIAMETER (deprecated)| Maximum diameter (in microns) of sink cluster. Instead, write `CLOCK_TREE_SYNTHESIS_ARGS = -sink_clustering_max_diameter `.| | +| CTS_CLUSTER_SIZE (deprecated)| Maximum number of sinks per cluster. Instead, write `CLOCK_TREE_SYNTHESIS_ARGS = -sink_clustering_size `.| | +| CTS_LIB_NAME (deprecated)| Name of the Liberty library to use in selecting the clock buffers. Instead, write `CLOCK_TREE_SYNTHESIS_ARGS = -library `.| | | CTS_SNAPSHOTS| Create ODB/SDC files at different stages of CTS.| 0| | DESIGN_NAME| The name of the top-level module of the design.| | | DESIGN_NICKNAME| DESIGN_NICKNAME just changes the directory name that ORFS outputs to be DESIGN_NICKNAME instead of DESIGN_NAME in case DESIGN_NAME is unwieldy or conflicts with a different design.| | -| DETAILED_METRICS| If set, then calls report_metrics prior to repair operations in the CTS and global route stages| 0| -| DETAILED_ROUTE_ARGS| Add additional arguments for debugging purposes during detail route.| | -| DETAILED_ROUTE_END_ITERATION| Maximum number of iterations.| 64| -| DETAIL_PLACEMENT_ARGS| Specify arguments to every detailed_placement call: the one in placement and the re-legalizations after clock tree synthesis, after repair in CTS and after the repairs in global route. A legalizer chosen here (-use_diamond_legalizer, -max_displacement) is therefore the one every stage uses.| | +| DETAILED_METRICS (deprecated)| If set, then calls report_metrics prior to repair operations in the CTS and global route stages Instead of DETAILED_METRICS=1, write `REPORT_METRICS_ARGS = cts:on grt:on`.| 0| +| DETAILED_PLACEMENT_ARGS| Edits to the arguments the flow passes to `detailed_placement`, in the grammar of docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, `on`/`off`, each optionally scoped `stage:` or `stage.call:`.| | +| DETAILED_ROUTE_ARGS| Edits to the arguments the flow passes to `detailed_route`, in the grammar of docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, `on`/`off`, each optionally scoped `stage:` or `stage.call:`. Until it is removed, a value that is a plain command line, with no `~`, `on`, `off` or scope, replaces the flow's arguments, as it always has.| | +| DETAILED_ROUTE_END_ITERATION (deprecated)| Maximum number of iterations. Instead, write `DETAILED_ROUTE_ARGS = -droute_end_iter `.| 64| +| DETAIL_PLACEMENT_ARGS (deprecated)| Specify arguments to every detailed_placement call: the one in placement and the re-legalizations after clock tree synthesis, after repair in CTS and after the repairs in global route. A legalizer chosen here (-use_diamond_legalizer, -max_displacement) is therefore the one every stage uses. Instead, write `DETAILED_PLACEMENT_ARGS = `.| | | DFF_LIB_FILE| Single Liberty file for flip-flop technology mapping (dfflibmap) during synthesis. Takes precedence over DFF_MAP_FILE when set.| | | DFF_MAP_FILE| Optional mapping file supplied to Yosys to map D flip-flops| | | DIE_AREA| The die area specified as a list of lower-left and upper-right corners in microns (X1 Y1 X2 Y2).| | -| DISABLE_VIA_GEN| Passed as -disable_via_gen to detailed_route.| | -| DONT_BUFFER_PORTS| Do not buffer input/output ports during floorplanning.| 0| +| DISABLE_VIA_GEN (deprecated)| Passed as -disable_via_gen to detailed_route. Instead of DISABLE_VIA_GEN=1, write `DETAILED_ROUTE_ARGS = -disable_via_gen`.| | +| DONT_BUFFER_PORTS (deprecated)| Do not buffer input/output ports during floorplanning. Instead of DONT_BUFFER_PORTS=1, write `BUFFER_PORTS_ARGS = off`.| 0| | DONT_USE_CELLS| Dont use cells eases pin access in detailed routing.| | -| DPO_MAX_DISPLACEMENT| Specifies how far an instance can be moved when optimizing.| 5 1| +| DPO_MAX_DISPLACEMENT (deprecated)| Specifies how far an instance can be moved when optimizing. Instead, write `IMPROVE_PLACEMENT_ARGS = -max_displacement `.| 5 1| | EARLY_SIZING_CAP_RATIO| Ratio between the input pin capacitance and the output pin load during initial gate sizing.| | -| ENABLE_DPO| Enable detail placement with improve_placement feature.| 1| -| ENABLE_PLACE_REPAIR_TIMING| Run repair_timing during the placement resize stage using placement parasitics. Disabled by default; pre-CTS setup/hold repair is skipped unless this is set to 1.| 0| -| ENABLE_RESISTANCE_AWARE| Passed as -resistance_aware to global_route.| | +| ENABLE_DPO (deprecated)| Enable detail placement with improve_placement feature. Instead of ENABLE_DPO=0, write `IMPROVE_PLACEMENT_ARGS = off`.| 1| +| ENABLE_PLACE_REPAIR_TIMING (deprecated)| Run repair_timing during the placement resize stage using placement parasitics. Disabled by default; pre-CTS setup/hold repair is skipped unless this is set to 1. Instead of ENABLE_PLACE_REPAIR_TIMING=1, write `REPAIR_TIMING_ARGS = place:on`.| 0| +| ENABLE_RESISTANCE_AWARE (deprecated)| Passed as -resistance_aware to global_route. Instead of ENABLE_RESISTANCE_AWARE=1, write `GLOBAL_ROUTE_ARGS = -resistance_aware`.| | | FASTROUTE_TCL| Specifies a Tcl script with commands to run before FastRoute.| | | FILL_CELLS| Fill cells are used to fill empty sites. If not set or empty, fill cell insertion is skipped.| | | FILL_CONFIG| JSON rule file for metal fill during chip finishing.| | @@ -156,18 +159,19 @@ configuration file. | GDS_ALLOW_EMPTY| Single regular expression of module names of macros that have no .gds file| | | GDS_FILES| Path to platform GDS files.| | | GENERATE_ARTIFACTS_ON_FAILURE| For instance Bazel needs artifacts (.odb and .rpt files) on a failure to allow the user to save hours on re-running the failed step locally, but when working with a Makefile flow, it is more natural to fail the step and leave the user to manually inspect the logs and artifacts directly via the file system. Set to 1 to change the behavior to generate artifacts upon failure to e.g. do a global route. The exit code will still be non-zero on all other failures that aren't covered by the "useful to inspect the artifacts on failure" use-case. Example: just like detailed routing, a global route that fails with congestion, is not a build failure(as in exit code non-zero), it is a successful(as in zero exit code) global route that produce reports detailing the problem. Detailed route will not proceed, if there is global routing congestion This allows build systems, such as bazel, to create artifacts for global and detailed route, even if the operation had problems, without having know about the semantics between global and detailed route. Considering that global and detailed route can run for a long time and use a lot of memory, this allows inspecting results on a laptop for a build that ran on a server.| 0| -| GLOBAL_PLACEMENT_ARGS| Use additional tuning parameters during global placement other than default args defined in global_place.tcl.| | -| GLOBAL_ROUTE_ARGS| Replaces default arguments for global route. The -congestion_iterations default is set by the flow (30 for FastRoute, 10 for CUGR); add -congestion_iterations here to override it.| -congestion_report_iter_step 5 -verbose| +| GLOBAL_PLACEMENT_ARGS| Edits to the arguments the flow passes to `global_placement`, in the grammar of docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, `on`/`off`, each optionally scoped `stage:` or `stage.call:`.| | +| GLOBAL_ROUTE_ARGS| Edits to the arguments the flow passes to `global_route`, in the grammar of docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, `on`/`off`, each optionally scoped `stage:` or `stage.call:`. Edits the first global_route; the incremental ones after repair take -allow_congestion from it.| -congestion_report_iter_step 5 -verbose| | GLOBAL_ROUTE_USE_CUGR| Passed as -use_cugr to global_route. Uses CUGR as the global routing solver instead of the default FastRoute solver. NOTE: CUGR is not ready for production.| 0| | GND_NETS_VOLTAGES| Used for IR Drop calculation.| | | GPL_KEEP_OVERFLOW| Passed as -keep_resize_below_overflow to global_placement. Only used when GPL_TIMING_DRIVEN is enabled.| | | GPL_PLACE_IOS| Place IO pins together with the cells in global placement (-place_ios).| 0| -| GPL_RANDOM_SEED| Specifies a random seed for global placement. Useful for perturbation studies.| | -| GPL_ROUTABILITY_DRIVEN| Specifies whether the placer should use routability driven placement.| 1| +| GPL_RANDOM_SEED (deprecated)| Specifies a random seed for global placement. Useful for perturbation studies. Instead, write `GLOBAL_PLACEMENT_ARGS = -random_seed `.| | +| GPL_ROUTABILITY_DRIVEN (deprecated)| Specifies whether the placer should use routability driven placement. Instead of GPL_ROUTABILITY_DRIVEN=0, write `GLOBAL_PLACEMENT_ARGS = ~-routability_driven`.| 1| | GPL_TIMING_DRIVEN| Specifies whether the placer should use timing driven placement.| 1| | GRT_SEED| Specifies a random seed for global routing. Useful for perturbation studies.| | | GUI_TIMING| Load timing information when opening GUI. For large designs, this can be quite time consuming. Useful to disable when investigating non-timing aspects like floorplan, placement, routing, etc.| 1| -| HOLD_SLACK_MARGIN| Specifies a time margin for the slack when fixing hold violations. This option allows you to overfix or underfix (negative value, terminate retiming before 0 or positive slack). floorplan.tcl uses min of HOLD_SLACK_MARGIN and 0 (default hold slack margin). This avoids overrepair in floorplan for hold by default, but allows skipping hold repair using a negative HOLD_SLACK_MARGIN. Exiting timing repair early is useful in exploration where the .sdc has a fixed clock period at the design's target clock period and where HOLD/SETUP_SLACK_MARGIN is used to avoid overrepair (extremely long running times) when exploring different parameter settings. When an ideal clock is used, that is before CTS, a clock insertion delay of 0 is used in timing paths. This creates a mismatch between macros that have a .lib file from after CTS, when the clock is propagated. To mitigate this, OpenSTA will use subtract the clock insertion delay of macros when calculating timing with ideal clock. Provided that min_clock_tree_path and max_clock_tree_path are in the .lib file, which is the case for macros built with OpenROAD. This is less accurate than if OpenROAD had created a placeholder clock tree for timing estimation purposes prior to CTS. There will inevitably be inaccuracies in the timing calculation prior to CTS. Use a slack margin that is low enough, even negative, to avoid overrepair. Inaccuracies in the timing prior to CTS can also lead to underrepair, but there no obvious and simple way to avoid underrapir in these cases. Overrepair can lead to excessive runtimes in repair or too much buffering being added, which can present itself as congestion of hold cells or buffer cells. Another use of SETUP/HOLD_SLACK_MARGIN is design parameter exploration when trying to find the minimum clock period for a design. The SDC_FILE for a design can be quite complicated and instead of modifying the clock period in the SDC_FILE, which can be non-trivial, the clock period can be fixed at the target frequency and the SETUP/HOLD_SLACK_MARGIN can be swept to find a plausible current minimum clock period.| 0| +| HOLD_SLACK_MARGIN (deprecated)| Specifies a time margin for the slack when fixing hold violations. This option allows you to overfix or underfix (negative value, terminate retiming before 0 or positive slack). floorplan.tcl uses min of HOLD_SLACK_MARGIN and 0 (default hold slack margin). This avoids overrepair in floorplan for hold by default, but allows skipping hold repair using a negative HOLD_SLACK_MARGIN. Exiting timing repair early is useful in exploration where the .sdc has a fixed clock period at the design's target clock period and where HOLD/SETUP_SLACK_MARGIN is used to avoid overrepair (extremely long running times) when exploring different parameter settings. When an ideal clock is used, that is before CTS, a clock insertion delay of 0 is used in timing paths. This creates a mismatch between macros that have a .lib file from after CTS, when the clock is propagated. To mitigate this, OpenSTA will use subtract the clock insertion delay of macros when calculating timing with ideal clock. Provided that min_clock_tree_path and max_clock_tree_path are in the .lib file, which is the case for macros built with OpenROAD. This is less accurate than if OpenROAD had created a placeholder clock tree for timing estimation purposes prior to CTS. There will inevitably be inaccuracies in the timing calculation prior to CTS. Use a slack margin that is low enough, even negative, to avoid overrepair. Inaccuracies in the timing prior to CTS can also lead to underrepair, but there no obvious and simple way to avoid underrapir in these cases. Overrepair can lead to excessive runtimes in repair or too much buffering being added, which can present itself as congestion of hold cells or buffer cells. Another use of SETUP/HOLD_SLACK_MARGIN is design parameter exploration when trying to find the minimum clock period for a design. The SDC_FILE for a design can be quite complicated and instead of modifying the clock period in the SDC_FILE, which can be non-trivial, the clock period can be fixed at the target frequency and the SETUP/HOLD_SLACK_MARGIN can be swept to find a plausible current minimum clock period. Instead, write `REPAIR_TIMING_ARGS = -hold_margin `.| 0| +| IMPROVE_PLACEMENT_ARGS| Edits to the arguments the flow passes to `improve_placement`, in the grammar of docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, `on`/`off`, each optionally scoped `stage:` or `stage.call:`.| | | INFER_CLKGATES| Enables Yosys clock gate inference. By default, it uses the Liberty cell definitions to determine clock gating cell. The selection can be overridden using the POS_CLKGATE_AND_PORTS and/or NEG_CLKGATE_AND_PORTS variables.| 0| | IO_CONSTRAINTS| File path to the IO constraints .tcl file. Also used for manual placement.| | | IO_PLACER_H| A list of metal layers on which the I/O pins are placed horizontally (top and bottom of the die).| | @@ -189,7 +193,7 @@ configuration file. | MATCH_CELL_FOOTPRINT| Enforce sizing operations to only swap cells that have the same layout boundary.| 0| | MAX_PLACE_STEP_COEF| Sets the maximum phi coefficient (pcof_max / µ_k Upper Bound) for global placement optimization. This parameter controls the step size upper bound in the RePlAce Nesterov optimization algorithm. Higher values allow more aggressive optimization but may risk divergence. Valid range: 1.00-1.20| 1.05| | MAX_REPAIR_ANTENNAS_ITER_DRT| Defines the maximum number of iterations post-detailed routing repair antennas will run.| 5| -| MAX_REPAIR_ANTENNAS_ITER_GRT| Defines the maximum number of iterations post global routing repair antennas will run.| 5| +| MAX_REPAIR_ANTENNAS_ITER_GRT (deprecated)| Defines the maximum number of iterations post global routing repair antennas will run. Instead, write `REPAIR_ANTENNAS_ARGS = grt:-iterations `.| 5| | MAX_ROUTING_LAYER| The highest metal layer name to be used in routing.| | | MIN_BUF_CELL_AND_PORTS| Used to insert a buffer cell to pass through wires. Used in synthesis.| | | MIN_CLK_ROUTING_LAYER| The lowest metal layer name to be used for clock-net routing in global routing. Used in flow/platforms/*/fastroute.tcl as the lower bound of `set_routing_layers -clock`. Typically higher than MIN_ROUTING_LAYER so clock nets prefer the upper, lower-RC layers. No `stages:` list because floorplan.tcl also `source`s the platform fastroute.tcl.| | @@ -199,14 +203,15 @@ configuration file. | NUM_CORES| Passed to `openroad -threads $(NUM_CORES)`, defaults to numbers of cores in system as determined by system specific code in Makefile, `nproc` is tried first. OpenROAD does not limit itself to this number of cores across OpenROAD running instances, which can lead to overprovisioning in contexts such as bazel-orfs where there could be many routing, or place jobs running at the same time.| | | OPENROAD_HIERARCHICAL| Feature toggle to enable to run OpenROAD in hierarchical mode, otherwise considered flat. Will eventually be the default and this option will be retired.| 0| | OPT_POST_GRT_WNS| Optimize WNS after global routing by additional repair_timing that uses VT swap and wire rerouting only to minimize placement and routing disturbance| 1| -| OR_K| Passed as -or_k to detailed routing.| | -| OR_SEED| Passed as -or_seed to detailed routing.| | +| OR_K (deprecated)| Passed as -or_k to detailed routing. Instead, write `DETAILED_ROUTE_ARGS = -or_k `.| | +| OR_SEED (deprecated)| Passed as -or_seed to detailed routing. Instead, write `DETAILED_ROUTE_ARGS = -or_seed `.| | | PDN_TCL| File path which has a set of power grid policies used by pdn to be applied to the design, such as layers to use, stripe width and spacing to generate the actual metal straps.| | | PLACE_DENSITY| The desired average placement density of cells: 1.0 = dense, 0.0 = widely spread. The intended effort is also communicated by this parameter. Use a low value for faster builds and higher value for better quality of results. If a too low value is used, the placer will not be able to place all cells and a recommended minimum placement density can be found in the logs. A too high value can lead to excessive runtimes, even timeouts and subtle failures in the flow after placement, such as in CTS or global routing when timing repair fails. The default is platform specific.| | | PLACE_DENSITY_LB_ADDON| Check the lower boundary of the PLACE_DENSITY and add PLACE_DENSITY_LB_ADDON if it exists.| | -| PLACE_PINS_ARGS| Arguments to place_pins| | +| PLACE_PINS_ARGS| Edits to the arguments the flow passes to `place_pins`, in the grammar of docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, `on`/`off`, each optionally scoped `stage:` or `stage.call:`.| | | PLACE_SITE| Placement site for core cells defined in the technology LEF file.| | | PLATFORM| Specifies process design kit or technology node to be used.| | +| PLATFORM_ARGS| A platform's defaults for command arguments, in the grammar of docs/user/CommandArguments.md, each edit starting with the command it is for, as in `rtl_macro_placer:-halo_width 5`. They rank above the flow's own arguments and below a design's _ARGS.| | | PLATFORM_TCL| Specifies a Tcl script with commands to run before loading design.| | | POST_CTS_TCL| Specifies a Tcl script with commands to run after CTS is completed.| | | POST_DENSITY_FILL_TCL| Specifies a Tcl script with commands to run after density fill.| | @@ -247,30 +252,36 @@ configuration file. | RCX_RULES| RC Extraction rules file path.| | | RECOVER_POWER| Specifies how many percent of paths with positive slacks can be slowed for power savings [0-100].| 0| | REMOVE_CELLS_FOR_LEC| String patterns directly passed to write_verilog -remove_cells <> for lec checks.| | -| REPAIR_PDN_VIA_LAYER| Remove power grid vias which generate DRC violations after detailed routing.| | +| REPAIR_ANTENNAS_ARGS| Edits to the arguments the flow passes to `repair_antennas`, in the grammar of docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, `on`/`off`, each optionally scoped `stage:` or `stage.call:`.| | +| REPAIR_DESIGN_ARGS| Edits to the arguments the flow passes to `repair_design`, in the grammar of docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, `on`/`off`, each optionally scoped `stage:` or `stage.call:`.| | +| REPAIR_PDN_VIA_LAYER (deprecated)| Remove power grid vias which generate DRC violations after detailed routing. Instead, write `DETAILED_ROUTE_ARGS = -repair_pdn_vias `.| | +| REPAIR_TIE_FANOUT_ARGS| Edits to the arguments the flow passes to `repair_tie_fanout`, in the grammar of docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, `on`/`off`, each optionally scoped `stage:` or `stage.call:`.| | +| REPAIR_TIMING_ARGS| Edits to the arguments the flow passes to `repair_timing`, in the grammar of docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, `on`/`off`, each optionally scoped `stage:` or `stage.call:`.| | | REPORT_CLOCK_SKEW| Report clock skew as part of reporting metrics, starting at CTS, before which there is no clock skew. This metric can be quite time-consuming, so it can be useful to disable.| 1| | REPORT_ENDPOINT_SLACK| If set to 1, write the setup and hold slack of every timing endpoint at the end of every flow step (e.g. 3_3_place_gp) to $REPORTS_DIR/_endpoint_slack.json. These snapshots can be compared across steps with flow/util/endpointSlack.py. See docs/contrib/EndpointSlackTracking.md.| 0| +| REPORT_METRICS_ARGS| Edits to the arguments the flow passes to `report_metrics`, in the grammar of docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, `on`/`off`, each optionally scoped `stage:` or `stage.call:`.| | | ROUTING_LAYER_ADJUSTMENT| Adjusts routing layer capacities to manage congestion and improve detailed routing. High values ease detailed routing but risk excessive detours and long global routing times, while low values reduce global routing failure but can complicate detailed routing. The global routing running time normally reduces dramatically (entirely design specific, but going from hours to minutes has been observed) when the value is low (such as 0.10). Sometimes, global routing will succeed with lower values and fail with higher values. Exploring results with different values can help shed light on the problem. Start with a too low value, such as 0.10, and bisect to value that works by doing multiple global routing runs. As a last resort, `make global_route_issue` and using the tools/OpenROAD/etc/whittle.py can be useful to debug global routing errors. If there is something specific that is impossible to route, such as a clock line over a macro, global routing will terminate with DRC errors routes that could have been routed were it not for the specific impossible routes. whittle.py should weed out the possible routes and leave a minimal failing case that pinpoints the problem.| 0.5| -| RTLMP_AREA_WT| Weight for the area of the current floorplan.| 0.1| -| RTLMP_ARGS| Overrides all other RTL macro placer arguments.| | -| RTLMP_BOUNDARY_WT| Weight for the boundary or how far the hard macro clusters are from boundaries.| 50.0| -| RTLMP_FENCE_LX| Defines the lower left X coordinate for the global fence bounding box in microns.| 0.0| -| RTLMP_FENCE_LY| Defines the lower left Y coordinate for the global fence bounding box in microns.| 0.0| -| RTLMP_FENCE_UX| Defines the upper right X coordinate for the global fence bounding box in microns.| 0.0| -| RTLMP_FENCE_UY| Defines the upper right Y coordinate for the global fence bounding box in microns.| 0.0| -| RTLMP_KEEP_CLUSTERING| Set to 1 to store the RTL macro placer's clustering hierarchy in the ODB as nested dbGroups.| 0| -| RTLMP_MAX_INST| Maximum number of standard cells in a cluster. If unset, rtl_macro_placer will calculate a value based on the design attributes.| | -| RTLMP_MAX_LEVEL| Maximum depth of the physical hierarchy tree.| 2| -| RTLMP_MAX_MACRO| Maximum number of macros in a cluster. If unset, rtl_macro_placer will calculate a value based on the design attributes.| | -| RTLMP_MIN_AR| Specifies the minimum aspect ratio (height/width).| 0.33| -| RTLMP_MIN_CHANNEL_SIZE| Minimum channel width and height between macros (microns), given as one value for both, or two values "width height".| | -| RTLMP_MIN_INST| Minimum number of standard cells in a cluster. If unset, rtl_macro_placer will calculate a value based on the design attributes.| | -| RTLMP_MIN_MACRO| Minimum number of macros in a cluster. If unset, rtl_macro_placer will calculate a value based on the design attributes.| | -| RTLMP_NOTCH_WT| Weight for the notch, or the existence of dead space that cannot be used for placement and routing.| 50.0| -| RTLMP_OUTLINE_WT| Weight for violating the fixed outline constraint, meaning that all clusters should be placed within the shape of their parent cluster.| 100.0| -| RTLMP_PIN_AWARE_CHANNELS| Set to 1 to trim macro channels based on the pin locations of macros, instead of using full channels. Requires RTLMP_MIN_CHANNEL_SIZE to also be set. Defaults to 1 whenever RTLMP_MIN_CHANNEL_SIZE is set and this variable is not explicitly set to 0.| 1| -| RTLMP_RPT_DIR| Path to the directory where reports are saved.| | -| RTLMP_WIRELENGTH_WT| Weight for half-perimiter wirelength.| 100.0| +| RTLMP_AREA_WT (deprecated)| Weight for the area of the current floorplan. Instead, write `RTL_MACRO_PLACER_ARGS = -area_weight `.| 0.1| +| RTLMP_ARGS (deprecated)| Overrides all other RTL macro placer arguments. Instead, write `RTL_MACRO_PLACER_ARGS, with only what differs from the flow's arguments`.| | +| RTLMP_BOUNDARY_WT (deprecated)| Weight for the boundary or how far the hard macro clusters are from boundaries. Instead, write `RTL_MACRO_PLACER_ARGS = -boundary_weight `.| 50.0| +| RTLMP_FENCE_LX (deprecated)| Defines the lower left X coordinate for the global fence bounding box in microns. Instead, write `RTL_MACRO_PLACER_ARGS = -fence_lx `.| 0.0| +| RTLMP_FENCE_LY (deprecated)| Defines the lower left Y coordinate for the global fence bounding box in microns. Instead, write `RTL_MACRO_PLACER_ARGS = -fence_ly `.| 0.0| +| RTLMP_FENCE_UX (deprecated)| Defines the upper right X coordinate for the global fence bounding box in microns. Instead, write `RTL_MACRO_PLACER_ARGS = -fence_ux `.| 0.0| +| RTLMP_FENCE_UY (deprecated)| Defines the upper right Y coordinate for the global fence bounding box in microns. Instead, write `RTL_MACRO_PLACER_ARGS = -fence_uy `.| 0.0| +| RTLMP_KEEP_CLUSTERING (deprecated)| Set to 1 to store the RTL macro placer's clustering hierarchy in the ODB as nested dbGroups. Instead of RTLMP_KEEP_CLUSTERING=1, write `RTL_MACRO_PLACER_ARGS = -keep_clustering_data`.| 0| +| RTLMP_MAX_INST (deprecated)| Maximum number of standard cells in a cluster. If unset, rtl_macro_placer will calculate a value based on the design attributes. Instead, write `RTL_MACRO_PLACER_ARGS = -max_num_inst `.| | +| RTLMP_MAX_LEVEL (deprecated)| Maximum depth of the physical hierarchy tree. Instead, write `RTL_MACRO_PLACER_ARGS = -max_num_level `.| 2| +| RTLMP_MAX_MACRO (deprecated)| Maximum number of macros in a cluster. If unset, rtl_macro_placer will calculate a value based on the design attributes. Instead, write `RTL_MACRO_PLACER_ARGS = -max_num_macro `.| | +| RTLMP_MIN_AR (deprecated)| Specifies the minimum aspect ratio (height/width). Instead, write `RTL_MACRO_PLACER_ARGS = -min_ar `.| 0.33| +| RTLMP_MIN_CHANNEL_SIZE (deprecated)| Minimum channel width and height between macros (microns), given as one value for both, or two values "width height". Instead, write `RTL_MACRO_PLACER_ARGS = -min_channel_size `.| | +| RTLMP_MIN_INST (deprecated)| Minimum number of standard cells in a cluster. If unset, rtl_macro_placer will calculate a value based on the design attributes. Instead, write `RTL_MACRO_PLACER_ARGS = -min_num_inst `.| | +| RTLMP_MIN_MACRO (deprecated)| Minimum number of macros in a cluster. If unset, rtl_macro_placer will calculate a value based on the design attributes. Instead, write `RTL_MACRO_PLACER_ARGS = -min_num_macro `.| | +| RTLMP_NOTCH_WT (deprecated)| Weight for the notch, or the existence of dead space that cannot be used for placement and routing. Instead, write `RTL_MACRO_PLACER_ARGS = -notch_weight `.| 50.0| +| RTLMP_OUTLINE_WT (deprecated)| Weight for violating the fixed outline constraint, meaning that all clusters should be placed within the shape of their parent cluster. Instead, write `RTL_MACRO_PLACER_ARGS = -outline_weight `.| 100.0| +| RTLMP_PIN_AWARE_CHANNELS (deprecated)| Set to 1 to trim macro channels based on the pin locations of macros, instead of using full channels. Requires RTLMP_MIN_CHANNEL_SIZE to also be set. Defaults to 1 whenever RTLMP_MIN_CHANNEL_SIZE is set and this variable is not explicitly set to 0. Instead of RTLMP_PIN_AWARE_CHANNELS=0, write `RTL_MACRO_PLACER_ARGS = ~-pin_aware_channels`.| 1| +| RTLMP_RPT_DIR (deprecated)| Path to the directory where reports are saved. Instead, write `RTL_MACRO_PLACER_ARGS = -report_directory `.| | +| RTLMP_WIRELENGTH_WT (deprecated)| Weight for half-perimiter wirelength. Instead, write `RTL_MACRO_PLACER_ARGS = -wirelength_weight `.| 100.0| +| RTL_MACRO_PLACER_ARGS| Edits to the arguments the flow passes to `rtl_macro_placer`, in the grammar of docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, `on`/`off`, each optionally scoped `stage:` or `stage.call:`.| | | RUN_LOG_NAME_STEM| Stem of the log file name, the log file will be named `$(LOG_DIR)/$(RUN_LOG_NAME_STEM).log`.| run| | RUN_SCRIPT| Path to script to run from `make run`, python or tcl script detected by .py or .tcl extension.| | | SAIF_FILE| Specifies the Switching Activity Interchange Format (SAIF) file containing pin activities and duty cycles for use in power calculation.| | @@ -278,24 +289,24 @@ configuration file. | SDC_FILE| The path to design constraint (SDC) file.| | | SEAL_GDS| Seal macro to place around the design.| | | SEC_CHECK| Perform a sequential equivalence check between the initial synthesis netlist and final netlist with the Kepler Formal PDR engine. If this fails, report an issue to OpenROAD.| 0| -| SETUP_MOVE_SEQUENCE| Passed as -sequence to repair_timing. This should be a string of move keywords separated by commas.| | -| SETUP_REPAIR_PHASES| Passed as -phases to repair_timing. This should be a string of setup repair phase names separated by spaces. Set to PARALLEL_EVAL to repair setup timing with the experimental parallel evaluation policy. When unset, repair_timing runs its default phases.| | -| SETUP_SLACK_MARGIN| Specifies a time margin for the slack when fixing setup violations. This option allows you to overfix or underfix(negative value, terminate retiming before 0 or positive slack). See HOLD_SLACK_MARGIN for more details.| 0| -| SKIP_ANTENNA_REPAIR| Skips antenna repair entirely.| 0| -| SKIP_ANTENNA_REPAIR_POST_DRT| Skips antenna repair post-detailed routing.| 0| -| SKIP_BUFFER_REMOVAL| Passed as -skip_buffer_removal to repair_timing. Do not remove buffers as a transform to fix timing violations (default: allow buffer removal).| | -| SKIP_CRIT_VT_SWAP| Do not perform VT swap on critical cells to improve QoR (default: do critical VT swap). This is an additional VT swap on critical cells that remain near the end of setup fixing. If SKIP_VT_SWAP is set to 1, this also disables critical cell VT swap.| | -| SKIP_CTS_REPAIR_TIMING| Skipping CTS repair, which can take a long time, can be useful in architectural exploration or when getting CI up and running.| 0| +| SETUP_MOVE_SEQUENCE (deprecated)| Passed as -sequence to repair_timing. This should be a string of move keywords separated by commas. Instead, write `REPAIR_TIMING_ARGS = -sequence `.| | +| SETUP_REPAIR_PHASES (deprecated)| Passed as -phases to repair_timing. This should be a string of setup repair phase names separated by spaces. Set to PARALLEL_EVAL to repair setup timing with the experimental parallel evaluation policy. When unset, repair_timing runs its default phases. Instead, write `REPAIR_TIMING_ARGS = -phases `.| | +| SETUP_SLACK_MARGIN (deprecated)| Specifies a time margin for the slack when fixing setup violations. This option allows you to overfix or underfix(negative value, terminate retiming before 0 or positive slack). See HOLD_SLACK_MARGIN for more details. Instead, write `REPAIR_TIMING_ARGS = -setup_margin `.| 0| +| SKIP_ANTENNA_REPAIR (deprecated)| Skips antenna repair entirely. Instead of SKIP_ANTENNA_REPAIR=1, write `REPAIR_ANTENNAS_ARGS = grt:off`.| 0| +| SKIP_ANTENNA_REPAIR_POST_DRT (deprecated)| Skips antenna repair post-detailed routing. Instead of SKIP_ANTENNA_REPAIR_POST_DRT=1, write `REPAIR_ANTENNAS_ARGS = route:off`.| 0| +| SKIP_BUFFER_REMOVAL (deprecated)| Passed as -skip_buffer_removal to repair_timing. Do not remove buffers as a transform to fix timing violations (default: allow buffer removal). Instead of SKIP_BUFFER_REMOVAL=1, write `REPAIR_TIMING_ARGS = -skip_buffer_removal`.| | +| SKIP_CRIT_VT_SWAP (deprecated)| Do not perform VT swap on critical cells to improve QoR (default: do critical VT swap). This is an additional VT swap on critical cells that remain near the end of setup fixing. If SKIP_VT_SWAP is set to 1, this also disables critical cell VT swap. Instead of SKIP_CRIT_VT_SWAP=1, write `REPAIR_TIMING_ARGS = -skip_crit_vt_swap`.| | +| SKIP_CTS_REPAIR_TIMING (deprecated)| Skipping CTS repair, which can take a long time, can be useful in architectural exploration or when getting CI up and running. Instead of SKIP_CTS_REPAIR_TIMING=1, write `REPAIR_TIMING_ARGS = cts:off`.| 0| | SKIP_DETAILED_ROUTE| Skips detailed route.| 0| -| SKIP_FLOORPLAN_REPAIR_TIMING| Skipping floorplan repair which sometimes does too much optimization too early.| 0| -| SKIP_GATE_CLONING| Do not use gate cloning transform to fix timing violations (default: use gate cloning).| | +| SKIP_FLOORPLAN_REPAIR_TIMING (deprecated)| Skipping floorplan repair which sometimes does too much optimization too early. Instead of SKIP_FLOORPLAN_REPAIR_TIMING=1, write `REPAIR_TIMING_ARGS = floorplan:off`.| 0| +| SKIP_GATE_CLONING (deprecated)| Do not use gate cloning transform to fix timing violations (default: use gate cloning). Instead of SKIP_GATE_CLONING=1, write `REPAIR_TIMING_ARGS = -skip_gate_cloning`.| | | SKIP_INCREMENTAL_REPAIR| Skip incremental repair in global route.| 0| -| SKIP_LAST_GASP| Do not use last gasp optimization to fix timing violations (default: use gate last gasp).| | -| SKIP_PIN_SWAP| Do not use pin swapping as a transform to fix timing violations (default: use pin swapping).| | -| SKIP_REPAIR_TIE_FANOUT| Skip repair_tie_fanout at floorplan step.| 0| -| SKIP_REPORT_METRICS| If set to 1, then metrics, report_metrics does nothing. Useful to speed up builds.| 0| -| SKIP_VT_SWAP| Do not perform VT swap to improve QoR (default: do VT swap).| | -| SLEW_MARGIN| Specifies a slew margin when fixing max slew violations. This option allows you to overfix.| | +| SKIP_LAST_GASP (deprecated)| Do not use last gasp optimization to fix timing violations (default: use gate last gasp). Instead of SKIP_LAST_GASP=1, write `REPAIR_TIMING_ARGS = -skip_last_gasp`.| | +| SKIP_PIN_SWAP (deprecated)| Do not use pin swapping as a transform to fix timing violations (default: use pin swapping). Instead of SKIP_PIN_SWAP=1, write `REPAIR_TIMING_ARGS = -skip_pin_swap`.| | +| SKIP_REPAIR_TIE_FANOUT (deprecated)| Skip repair_tie_fanout at floorplan step. Instead of SKIP_REPAIR_TIE_FANOUT=1, write `REPAIR_TIE_FANOUT_ARGS = off`.| 0| +| SKIP_REPORT_METRICS (deprecated)| If set to 1, then metrics, report_metrics does nothing. Useful to speed up builds. Instead of SKIP_REPORT_METRICS=1, write `REPORT_METRICS_ARGS = off`.| 0| +| SKIP_VT_SWAP (deprecated)| Do not perform VT swap to improve QoR (default: do VT swap). Instead of SKIP_VT_SWAP=1, write `REPAIR_TIMING_ARGS = -skip_vt_swap`.| | +| SLEW_MARGIN (deprecated)| Specifies a slew margin when fixing max slew violations. This option allows you to overfix. Instead, write `REPAIR_DESIGN_ARGS = -slew_margin `.| | | SWAP_ARITH_OPERATORS| Improve timing QoR by swapping ALU and MULT arithmetic operators.| 0| | SYNTH_ARGS| Optional synthesis variables for yosys.| | | SYNTH_BLACKBOXES| List of cells treated as a black box by Yosys. With Bazel, this can be used to run synthesis in parallel for the large modules of the design. Non-existant modules are ignored silently, useful when listing modules statically, even if modules come and go dynamically.| | @@ -329,8 +340,8 @@ configuration file. | TECH_LEF| A technology LEF file of the PDK that includes all relevant information regarding metal layers, vias, and spacing requirements.| | | TIEHI_CELL_AND_PORT| Tie high cells used in Yosys synthesis to replace a logical 1 in the Netlist.| | | TIELO_CELL_AND_PORT| Tie low cells used in Yosys synthesis to replace a logical 0 in the Netlist.| | -| TIE_SEPARATION| Distance separating tie high/low instances from the load.| 0| -| TNS_END_PERCENT| Default TNS_END_PERCENT value for post CTS timing repair. Try fixing all violating endpoints by default (reduce to 5% for runtime). Specifies how many percent of violating paths to fix [0-100]. Worst path will always be fixed.| 100| +| TIE_SEPARATION (deprecated)| Distance separating tie high/low instances from the load. Instead, write `REPAIR_TIE_FANOUT_ARGS = -separation `.| 0| +| TNS_END_PERCENT (deprecated)| Default TNS_END_PERCENT value for post CTS timing repair. Try fixing all violating endpoints by default (reduce to 5% for runtime). Specifies how many percent of violating paths to fix [0-100]. Worst path will always be fixed. Instead, write `REPAIR_TIMING_ARGS = -repair_tns `.| 100| | UNSET_ABC9_BOX_CELLS| List of cells to unset the abc9_box attribute on| | | USE_FILL| Whether to perform metal density filling.| 0| | VCD_FILE| Specifies the Value Change Dump (VCD) file containing pin activities and duty cycles for use in power calculation.| | @@ -365,6 +376,7 @@ configuration file. - [POS_CLKGATE_AND_PORTS](#POS_CLKGATE_AND_PORTS) - [PRE_SYNTH_TCL](#PRE_SYNTH_TCL) - [REPORT_ENDPOINT_SLACK](#REPORT_ENDPOINT_SLACK) +- [REPORT_METRICS_ARGS](#REPORT_METRICS_ARGS) - [SDC_FILE](#SDC_FILE) - [SEC_CHECK](#SEC_CHECK) - [SKIP_REPORT_METRICS](#SKIP_REPORT_METRICS) @@ -438,7 +450,10 @@ configuration file. - [PRE_MACRO_PLACE_TCL](#PRE_MACRO_PLACE_TCL) - [PRE_PDN_TCL](#PRE_PDN_TCL) - [PRE_TAPCELL_TCL](#PRE_TAPCELL_TCL) +- [REPAIR_TIE_FANOUT_ARGS](#REPAIR_TIE_FANOUT_ARGS) +- [REPAIR_TIMING_ARGS](#REPAIR_TIMING_ARGS) - [REPORT_ENDPOINT_SLACK](#REPORT_ENDPOINT_SLACK) +- [REPORT_METRICS_ARGS](#REPORT_METRICS_ARGS) - [ROUTING_LAYER_ADJUSTMENT](#ROUTING_LAYER_ADJUSTMENT) - [RTLMP_AREA_WT](#RTLMP_AREA_WT) - [RTLMP_ARGS](#RTLMP_ARGS) @@ -460,6 +475,7 @@ configuration file. - [RTLMP_PIN_AWARE_CHANNELS](#RTLMP_PIN_AWARE_CHANNELS) - [RTLMP_RPT_DIR](#RTLMP_RPT_DIR) - [RTLMP_WIRELENGTH_WT](#RTLMP_WIRELENGTH_WT) +- [RTL_MACRO_PLACER_ARGS](#RTL_MACRO_PLACER_ARGS) - [SETUP_MOVE_SEQUENCE](#SETUP_MOVE_SEQUENCE) - [SETUP_REPAIR_PHASES](#SETUP_REPAIR_PHASES) - [SETUP_SLACK_MARGIN](#SETUP_SLACK_MARGIN) @@ -481,11 +497,13 @@ configuration file. ## place variables - [BALANCE_ROWS](#BALANCE_ROWS) +- [BALANCE_ROW_USAGE_ARGS](#BALANCE_ROW_USAGE_ARGS) - [BUFFER_PORTS_ARGS](#BUFFER_PORTS_ARGS) - [CELL_PAD_IN_SITES_DETAIL_PLACEMENT](#CELL_PAD_IN_SITES_DETAIL_PLACEMENT) - [CELL_PAD_IN_SITES_GLOBAL_PLACEMENT](#CELL_PAD_IN_SITES_GLOBAL_PLACEMENT) - [CLUSTER_FLOPS](#CLUSTER_FLOPS) - [CLUSTER_FLOPS_ARGS](#CLUSTER_FLOPS_ARGS) +- [DETAILED_PLACEMENT_ARGS](#DETAILED_PLACEMENT_ARGS) - [DETAIL_PLACEMENT_ARGS](#DETAIL_PLACEMENT_ARGS) - [DONT_BUFFER_PORTS](#DONT_BUFFER_PORTS) - [DPO_MAX_DISPLACEMENT](#DPO_MAX_DISPLACEMENT) @@ -499,6 +517,7 @@ configuration file. - [GPL_RANDOM_SEED](#GPL_RANDOM_SEED) - [GPL_ROUTABILITY_DRIVEN](#GPL_ROUTABILITY_DRIVEN) - [GPL_TIMING_DRIVEN](#GPL_TIMING_DRIVEN) +- [IMPROVE_PLACEMENT_ARGS](#IMPROVE_PLACEMENT_ARGS) - [IO_PLACER_H](#IO_PLACER_H) - [IO_PLACER_V](#IO_PLACER_V) - [MATCH_CELL_FOOTPRINT](#MATCH_CELL_FOOTPRINT) @@ -519,7 +538,10 @@ configuration file. - [PRE_GLOBAL_PLACE_TCL](#PRE_GLOBAL_PLACE_TCL) - [PRE_IO_PLACEMENT_TCL](#PRE_IO_PLACEMENT_TCL) - [PRE_RESIZE_TCL](#PRE_RESIZE_TCL) +- [REPAIR_DESIGN_ARGS](#REPAIR_DESIGN_ARGS) +- [REPAIR_TIMING_ARGS](#REPAIR_TIMING_ARGS) - [REPORT_ENDPOINT_SLACK](#REPORT_ENDPOINT_SLACK) +- [REPORT_METRICS_ARGS](#REPORT_METRICS_ARGS) - [ROUTING_LAYER_ADJUSTMENT](#ROUTING_LAYER_ADJUSTMENT) - [SETUP_REPAIR_PHASES](#SETUP_REPAIR_PHASES) - [SKIP_REPORT_METRICS](#SKIP_REPORT_METRICS) @@ -528,6 +550,7 @@ configuration file. ## cts variables - [CELL_PAD_IN_SITES_DETAIL_PLACEMENT](#CELL_PAD_IN_SITES_DETAIL_PLACEMENT) +- [CLOCK_TREE_SYNTHESIS_ARGS](#CLOCK_TREE_SYNTHESIS_ARGS) - [CTS_ARGS](#CTS_ARGS) - [CTS_BUF_DISTANCE](#CTS_BUF_DISTANCE) - [CTS_BUF_LIST](#CTS_BUF_LIST) @@ -536,6 +559,7 @@ configuration file. - [CTS_LIB_NAME](#CTS_LIB_NAME) - [CTS_SNAPSHOTS](#CTS_SNAPSHOTS) - [DETAILED_METRICS](#DETAILED_METRICS) +- [DETAILED_PLACEMENT_ARGS](#DETAILED_PLACEMENT_ARGS) - [DETAIL_PLACEMENT_ARGS](#DETAIL_PLACEMENT_ARGS) - [HOLD_SLACK_MARGIN](#HOLD_SLACK_MARGIN) - [LEC_AUX_VERILOG_FILES](#LEC_AUX_VERILOG_FILES) @@ -543,8 +567,10 @@ configuration file. - [MATCH_CELL_FOOTPRINT](#MATCH_CELL_FOOTPRINT) - [POST_CTS_TCL](#POST_CTS_TCL) - [PRE_CTS_TCL](#PRE_CTS_TCL) +- [REPAIR_TIMING_ARGS](#REPAIR_TIMING_ARGS) - [REPORT_CLOCK_SKEW](#REPORT_CLOCK_SKEW) - [REPORT_ENDPOINT_SLACK](#REPORT_ENDPOINT_SLACK) +- [REPORT_METRICS_ARGS](#REPORT_METRICS_ARGS) - [SETUP_MOVE_SEQUENCE](#SETUP_MOVE_SEQUENCE) - [SETUP_REPAIR_PHASES](#SETUP_REPAIR_PHASES) - [SETUP_SLACK_MARGIN](#SETUP_SLACK_MARGIN) @@ -562,6 +588,7 @@ configuration file. - [CELL_PAD_IN_SITES_DETAIL_PLACEMENT](#CELL_PAD_IN_SITES_DETAIL_PLACEMENT) - [DETAILED_METRICS](#DETAILED_METRICS) +- [DETAILED_PLACEMENT_ARGS](#DETAILED_PLACEMENT_ARGS) - [DETAIL_PLACEMENT_ARGS](#DETAIL_PLACEMENT_ARGS) - [ENABLE_RESISTANCE_AWARE](#ENABLE_RESISTANCE_AWARE) - [GLOBAL_ROUTE_ARGS](#GLOBAL_ROUTE_ARGS) @@ -574,8 +601,12 @@ configuration file. - [OPT_POST_GRT_WNS](#OPT_POST_GRT_WNS) - [POST_GLOBAL_ROUTE_TCL](#POST_GLOBAL_ROUTE_TCL) - [PRE_GLOBAL_ROUTE_TCL](#PRE_GLOBAL_ROUTE_TCL) +- [REPAIR_ANTENNAS_ARGS](#REPAIR_ANTENNAS_ARGS) +- [REPAIR_DESIGN_ARGS](#REPAIR_DESIGN_ARGS) +- [REPAIR_TIMING_ARGS](#REPAIR_TIMING_ARGS) - [REPORT_CLOCK_SKEW](#REPORT_CLOCK_SKEW) - [REPORT_ENDPOINT_SLACK](#REPORT_ENDPOINT_SLACK) +- [REPORT_METRICS_ARGS](#REPORT_METRICS_ARGS) - [ROUTING_LAYER_ADJUSTMENT](#ROUTING_LAYER_ADJUSTMENT) - [SETUP_MOVE_SEQUENCE](#SETUP_MOVE_SEQUENCE) - [SETUP_REPAIR_PHASES](#SETUP_REPAIR_PHASES) @@ -609,8 +640,10 @@ configuration file. - [POST_FILLCELL_TCL](#POST_FILLCELL_TCL) - [PRE_DETAIL_ROUTE_TCL](#PRE_DETAIL_ROUTE_TCL) - [PRE_FILLCELL_TCL](#PRE_FILLCELL_TCL) +- [REPAIR_ANTENNAS_ARGS](#REPAIR_ANTENNAS_ARGS) - [REPORT_CLOCK_SKEW](#REPORT_CLOCK_SKEW) - [REPORT_ENDPOINT_SLACK](#REPORT_ENDPOINT_SLACK) +- [REPORT_METRICS_ARGS](#REPORT_METRICS_ARGS) - [ROUTING_LAYER_ADJUSTMENT](#ROUTING_LAYER_ADJUSTMENT) - [SKIP_ANTENNA_REPAIR_POST_DRT](#SKIP_ANTENNA_REPAIR_POST_DRT) - [SKIP_DETAILED_ROUTE](#SKIP_DETAILED_ROUTE) @@ -635,6 +668,7 @@ configuration file. - [PWR_NETS_VOLTAGES](#PWR_NETS_VOLTAGES) - [REPORT_CLOCK_SKEW](#REPORT_CLOCK_SKEW) - [REPORT_ENDPOINT_SLACK](#REPORT_ENDPOINT_SLACK) +- [REPORT_METRICS_ARGS](#REPORT_METRICS_ARGS) - [ROUTING_LAYER_ADJUSTMENT](#ROUTING_LAYER_ADJUSTMENT) - [SEC_CHECK](#SEC_CHECK) - [SKIP_DETAILED_ROUTE](#SKIP_DETAILED_ROUTE) @@ -647,6 +681,7 @@ configuration file. - [KEEP_VARS](#KEEP_VARS) - [NUM_CORES](#NUM_CORES) - [OPENROAD_HIERARCHICAL](#OPENROAD_HIERARCHICAL) +- [PLATFORM_ARGS](#PLATFORM_ARGS) - [SWAP_ARITH_OPERATORS](#SWAP_ARITH_OPERATORS) - [SYNTH_WRAPPED_OPERATORS](#SYNTH_WRAPPED_OPERATORS) - [WRITE_ODB_AND_SDC_EACH_STAGE](#WRITE_ODB_AND_SDC_EACH_STAGE) diff --git a/flow/scripts/cts.tcl b/flow/scripts/cts.tcl index e90c6f0698..19462c6901 100644 --- a/flow/scripts/cts.tcl +++ b/flow/scripts/cts.tcl @@ -16,37 +16,35 @@ proc save_progress { stage } { } # Run CTS -set cts_args [list \ - -sink_clustering_enable \ - -repair_clock_nets] - -append_env_var cts_args CTS_BUF_DISTANCE -distance_between_buffers 1 -append_env_var cts_args CTS_CLUSTER_SIZE -sink_clustering_size 1 -append_env_var cts_args CTS_CLUSTER_DIAMETER -sink_clustering_max_diameter 1 -append_env_var cts_args CTS_BUF_LIST -buf_list 1 -append_env_var cts_args CTS_LIB_NAME -library 1 - - +set deprecated {} +append_env_var deprecated CTS_BUF_DISTANCE -distance_between_buffers 1 +append_env_var deprecated CTS_CLUSTER_SIZE -sink_clustering_size 1 +append_env_var deprecated CTS_CLUSTER_DIAMETER -sink_clustering_max_diameter 1 +append_env_var deprecated CTS_BUF_LIST -buf_list 1 +append_env_var deprecated CTS_LIB_NAME -library 1 +set cts_args [list -sink_clustering_enable -repair_clock_nets {*}$deprecated] + +# CTS_ARGS, deprecated, replaces the flow's arguments. if { [env_var_exists_and_non_empty CTS_ARGS] } { set cts_args $::env(CTS_ARGS) + set deprecated $cts_args } set_dont_use $::env(DONT_USE_CELLS) -log_cmd clock_tree_synthesis {*}$cts_args +log_cmd clock_tree_synthesis \ + {*}[command_args clock_tree_synthesis cts.main $cts_args $deprecated] utl::push_metrics_stage "cts__{}__pre_repair_timing" log_cmd estimate_parasitics -placement -if { $::env(DETAILED_METRICS) } { - report_metrics 4 "cts pre-repair-timing" -} +report_metrics 4 "cts pre-repair-timing" true true $::env(DETAILED_METRICS) utl::pop_metrics_stage set_placement_padding -global \ -left $::env(CELL_PAD_IN_SITES_DETAIL_PLACEMENT) \ -right $::env(CELL_PAD_IN_SITES_DETAIL_PLACEMENT) -set result [catch { detailed_placement_helper -quiet } msg] +set result [catch { detailed_placement_helper cts.main -quiet } msg] if { $result != 0 } { save_progress 4_1_error error "Detailed placement failed in CTS: $msg" @@ -58,20 +56,20 @@ if { $::env(CTS_SNAPSHOTS) } { save_progress 4_1_pre_repair_setup_hold } -if { !$::env(SKIP_CTS_REPAIR_TIMING) } { +if { [command_runs repair_timing cts.main [expr { !$::env(SKIP_CTS_REPAIR_TIMING) }]] } { set lec_enabled [lec_check_enabled] if { $lec_enabled } { write_lec_verilog 4_before_rsz_lec.v } - repair_timing_helper + repair_timing_helper cts.main if { $lec_enabled } { write_lec_verilog 4_after_rsz_lec.v run_lec_test 4_rsz 4_before_rsz_lec.v 4_after_rsz_lec.v } - set result [catch { detailed_placement_helper -quiet } msg] + set result [catch { detailed_placement_helper cts.repair_timing -quiet } msg] if { $result != 0 } { save_progress 4_1_error error "Detailed placement failed in CTS: $msg" diff --git a/flow/scripts/detail_place.tcl b/flow/scripts/detail_place.tcl index 20aee94c3a..e0949dfdad 100644 --- a/flow/scripts/detail_place.tcl +++ b/flow/scripts/detail_place.tcl @@ -6,21 +6,20 @@ source_step_tcl PRE DETAIL_PLACE proc do_dpl { } { # Only for use with hybrid rows - if { $::env(BALANCE_ROWS) } { - balance_row_usage + if { [command_runs balance_row_usage place.main $::env(BALANCE_ROWS)] } { + balance_row_usage {*}[command_args balance_row_usage place.main {}] } set_placement_padding -global \ -left $::env(CELL_PAD_IN_SITES_DETAIL_PLACEMENT) \ -right $::env(CELL_PAD_IN_SITES_DETAIL_PLACEMENT) - detailed_placement_helper - - if { $::env(ENABLE_DPO) } { - if { [env_var_exists_and_non_empty DPO_MAX_DISPLACEMENT] } { - log_cmd improve_placement -max_displacement $::env(DPO_MAX_DISPLACEMENT) - } else { - log_cmd improve_placement - } + detailed_placement_helper place.main + + if { [command_runs improve_placement place.main $::env(ENABLE_DPO)] } { + set deprecated {} + append_env_var deprecated DPO_MAX_DISPLACEMENT -max_displacement 1 + log_cmd improve_placement \ + {*}[command_args improve_placement place.main $deprecated $deprecated] } log_cmd optimize_mirroring diff --git a/flow/scripts/detail_route.tcl b/flow/scripts/detail_route.tcl index 538e8476e0..a5403d4587 100644 --- a/flow/scripts/detail_route.tcl +++ b/flow/scripts/detail_route.tcl @@ -11,56 +11,53 @@ if { !$::env(SKIP_DETAILED_ROUTE) } { erase_non_stage_variables route set_propagated_clock [all_clocks] + set deprecated "" + append_env_var deprecated OR_SEED -or_seed 1 + append_env_var deprecated OR_K -or_k 1 + append_env_var deprecated DISABLE_VIA_GEN -disable_via_gen 0 + append_env_var deprecated REPAIR_PDN_VIA_LAYER -repair_pdn_vias 1 + append_env_var deprecated DETAILED_ROUTE_END_ITERATION -droute_end_iter 1 + set additional_args "" append_env_var additional_args dbProcessNode -db_process_node 1 - append_env_var additional_args OR_SEED -or_seed 1 - append_env_var additional_args OR_K -or_k 1 append_env_var additional_args VIA_IN_PIN_MIN_LAYER -via_in_pin_bottom_layer 1 append_env_var additional_args VIA_IN_PIN_MAX_LAYER -via_in_pin_top_layer 1 - append_env_var additional_args DISABLE_VIA_GEN -disable_via_gen 0 - append_env_var additional_args REPAIR_PDN_VIA_LAYER -repair_pdn_vias 1 - append_env_var additional_args DETAILED_ROUTE_END_ITERATION -droute_end_iter 1 - - append additional_args " -verbose 1" - # DETAILED_ROUTE_ARGS is used when debugging detailed, route, e.g. append - # "-droute_end_iter 5" to look at routing violations after only 5 iterations, - # speeding up iterations on a problem where detailed routing doesn't converge - # or converges slower than expected. + # Save out a progress report a few iterations after the first two: the + # first couple of iterations produce very large .drc reports without + # interesting information for the user. This gives progress information + # soon without having to go spelunking in Tcl or modify configuration + # scripts, while not having to wait too long or generating large useless + # reports. # - # If DETAILED_ROUTE_ARGS is not specified, save out progress report a - # few iterations after the first two iterations. The first couple of - # iterations would produce very large .drc reports without interesting - # information for the user. - # - # The idea is to have a policy that gives progress information soon without - # having to go spelunking in Tcl or modify configuration scripts, while - # not having to wait too long or generating large useless reports. - - set arguments [expr { - [env_var_exists_and_non_empty DETAILED_ROUTE_ARGS] ? $::env(DETAILED_ROUTE_ARGS) : - [concat $additional_args {-drc_report_iter_step 5}] - }] - - set all_args [concat [list \ - -output_drc $::env(REPORTS_DIR)/5_route_drc.rpt \ - -output_maze $::env(RESULTS_DIR)/maze.log] \ - $arguments] + # DETAILED_ROUTE_ARGS is used when debugging detailed route, e.g. + # "-droute_end_iter 5" to look at routing violations after only 5 + # iterations, speeding up iterations on a problem where detailed routing + # doesn't converge or converges slower than expected. A plain command line + # in it still replaces these arguments, as it always has; the first two + # options, the report and log files, stay. + set fixed [list -output_drc $::env(REPORTS_DIR)/5_route_drc.rpt \ + -output_maze $::env(RESULTS_DIR)/maze.log] + set all_args [command_args detailed_route route.main \ + [list {*}$fixed {*}$additional_args {*}$deprecated -verbose 1 -drc_report_iter_step 5] \ + $deprecated DETAILED_ROUTE_ARGS:[llength $fixed]] log_cmd detailed_route {*}$all_args - if { + set run [expr { !$::env(SKIP_ANTENNA_REPAIR_POST_DRT) && [env_var_exists_and_non_empty MAX_REPAIR_ANTENNAS_ITER_DRT] - } { + }] + if { [command_runs repair_antennas route.main $run] } { + set antenna_args [command_args repair_antennas route.main {}] set repair_antennas_iters 1 - if { [repair_antennas] } { + if { [repair_antennas {*}$antenna_args] } { detailed_route {*}$all_args } while { [check_antennas] && $repair_antennas_iters < $::env(MAX_REPAIR_ANTENNAS_ITER_DRT) } { - repair_antennas + repair_antennas {*}$antenna_args detailed_route {*}$all_args incr repair_antennas_iters } diff --git a/flow/scripts/floorplan.tcl b/flow/scripts/floorplan.tcl index 67b5b16564..354f50ca8b 100644 --- a/flow/scripts/floorplan.tcl +++ b/flow/scripts/floorplan.tcl @@ -129,20 +129,19 @@ log_cmd set_dont_use $::env(DONT_USE_CELLS) # unchanged. The move was reverted; only eliminate_dead_logic stayed in # synth_odb.tcl because it is a pure netlist transform that doesn't # depend on placement or routing-layer context. -if { !$::env(SKIP_REPAIR_TIE_FANOUT) } { - # This needs to come before any call to remove_buffers. You could have one - # tie driving multiple buffers that drive multiple outputs. - # Repair tie lo fanout - set tielo_cell_name [lindex $::env(TIELO_CELL_AND_PORT) 0] - set tielo_lib_name [get_name [get_property [lindex [get_lib_cell $tielo_cell_name] 0] library]] - set tielo_pin $tielo_lib_name/$tielo_cell_name/[lindex $::env(TIELO_CELL_AND_PORT) 1] - log_cmd repair_tie_fanout -separation $::env(TIE_SEPARATION) $tielo_pin - - # Repair tie hi fanout - set tiehi_cell_name [lindex $::env(TIEHI_CELL_AND_PORT) 0] - set tiehi_lib_name [get_name [get_property [lindex [get_lib_cell $tiehi_cell_name] 0] library]] - set tiehi_pin $tiehi_lib_name/$tiehi_cell_name/[lindex $::env(TIEHI_CELL_AND_PORT) 1] - log_cmd repair_tie_fanout -separation $::env(TIE_SEPARATION) $tiehi_pin +# This needs to come before any call to remove_buffers. You could have one +# tie driving multiple buffers that drive multiple outputs. +set run [expr { !$::env(SKIP_REPAIR_TIE_FANOUT) }] +foreach {call cell_and_port} [list tielo $::env(TIELO_CELL_AND_PORT) \ + tiehi $::env(TIEHI_CELL_AND_PORT)] { + if { [command_runs repair_tie_fanout floorplan.$call $run] } { + set cell_name [lindex $cell_and_port 0] + set lib_name [get_name [get_property [lindex [get_lib_cell $cell_name] 0] library]] + set deprecated [list -separation $::env(TIE_SEPARATION)] + log_cmd repair_tie_fanout \ + {*}[command_args repair_tie_fanout floorplan.$call $deprecated $deprecated] \ + $lib_name/$cell_name/[lindex $cell_and_port 1] + } } if { [env_var_equals SWAP_ARITH_OPERATORS 1] } { @@ -151,9 +150,11 @@ if { [env_var_equals SWAP_ARITH_OPERATORS 1] } { log_cmd replace_arith_modules } -if { !$::env(SKIP_FLOORPLAN_REPAIR_TIMING) } { +set run [expr { !$::env(SKIP_FLOORPLAN_REPAIR_TIMING) }] +if { [command_runs repair_timing floorplan.main $run] } { # Skip clone & split - repair_timing_helper -setup -skip_last_gasp -sequence "unbuffer,sizeup,swap,vt_swap" + repair_timing_helper floorplan.main -setup -skip_last_gasp \ + -sequence "unbuffer,sizeup,swap,vt_swap" } puts "Default units for flow" diff --git a/flow/scripts/generate-variables-docs.py b/flow/scripts/generate-variables-docs.py index c236f86b2c..9907c730de 100755 --- a/flow/scripts/generate-variables-docs.py +++ b/flow/scripts/generate-variables-docs.py @@ -33,6 +33,15 @@ for key in sorted(data): value = data[key] description = value.get("description", "").replace("\n", " ").strip() + replacement = value.get("replacement") + if isinstance(replacement, dict): + description += ( + " Instead of " + + ", ".join(f"{key}={v}, write `{r}`" for v, r in replacement.items()) + + "." + ) + elif replacement: + description += " Instead, write `" + replacement.format(value="") + "`." table_rows += ( f'| {key}' + f'{" (deprecated)" if value.get("deprecated", 0) == 1 else ""}' diff --git a/flow/scripts/global_place.tcl b/flow/scripts/global_place.tcl index 6a2d583d26..58acd9a13f 100644 --- a/flow/scripts/global_place.tcl +++ b/flow/scripts/global_place.tcl @@ -15,18 +15,17 @@ if { $::env(GPL_TIMING_DRIVEN) } { # to not buffer IO ports, set environment variable # DONT_BUFFER_PORT = 1 if { ![env_var_exists_and_non_empty FOOTPRINT] } { - if { !$::env(DONT_BUFFER_PORTS) } { + if { [command_runs buffer_ports place.main [expr { !$::env(DONT_BUFFER_PORTS) }]] } { puts "Perform port buffering..." - buffer_ports {*}[env_var_or_empty BUFFER_PORTS_ARGS] + buffer_ports {*}[command_args buffer_ports place.main {}] } } -set global_placement_args {} - # Parameters for routability mode in global placement -append_env_var global_placement_args GPL_ROUTABILITY_DRIVEN -routability_driven 0 - -append_env_var global_placement_args GPL_RANDOM_SEED -random_seed 1 +set deprecated {} +append_env_var deprecated GPL_ROUTABILITY_DRIVEN -routability_driven 0 +append_env_var deprecated GPL_RANDOM_SEED -random_seed 1 +set global_placement_args $deprecated # Parameters for timing driven mode in global placement if { $::env(GPL_TIMING_DRIVEN) } { @@ -57,18 +56,17 @@ if { $place_ios } { lappend global_placement_args -place_ios } -proc do_placement { global_placement_args } { +proc do_placement { global_placement_args deprecated } { set all_args [concat [list -density [place_density_with_lb_addon] \ -pad_left $::env(CELL_PAD_IN_SITES_GLOBAL_PLACEMENT) \ -pad_right $::env(CELL_PAD_IN_SITES_GLOBAL_PLACEMENT)] \ $global_placement_args] - lappend all_args {*}[env_var_or_empty GLOBAL_PLACEMENT_ARGS] - - log_cmd global_placement {*}$all_args + log_cmd global_placement \ + {*}[command_args global_placement place.main $all_args $deprecated] } -set result [catch { do_placement $global_placement_args } errMsg] +set result [catch { do_placement $global_placement_args $deprecated } errMsg] if { $place_ios } { log_cmd reset_place_config } @@ -79,8 +77,8 @@ if { $result != 0 } { log_cmd estimate_parasitics -placement -if { $::env(CLUSTER_FLOPS) } { - log_cmd cluster_flops {*}[env_var_or_empty CLUSTER_FLOPS_ARGS] +if { [command_runs cluster_flops place.main $::env(CLUSTER_FLOPS)] } { + log_cmd cluster_flops {*}[command_args cluster_flops place.main {}] log_cmd estimate_parasitics -placement } diff --git a/flow/scripts/global_place_skip_io.tcl b/flow/scripts/global_place_skip_io.tcl index 96195d486e..12aea7db8e 100644 --- a/flow/scripts/global_place_skip_io.tcl +++ b/flow/scripts/global_place_skip_io.tcl @@ -13,14 +13,14 @@ if { [env_var_exists_and_non_empty FLOORPLAN_DEF] } { } elseif { [all_pins_placed] } { puts "All pins are placed. Skipping global placement without IOs" } else { - set global_placement_args {} - append_env_var global_placement_args GPL_RANDOM_SEED -random_seed 1 - - log_cmd global_placement -skip_io -density [place_density_with_lb_addon] \ + set deprecated {} + append_env_var deprecated GPL_RANDOM_SEED -random_seed 1 + set flow [list -skip_io -density [place_density_with_lb_addon] \ -pad_left $::env(CELL_PAD_IN_SITES_GLOBAL_PLACEMENT) \ - -pad_right $::env(CELL_PAD_IN_SITES_GLOBAL_PLACEMENT) \ - {*}[env_var_or_empty GLOBAL_PLACEMENT_ARGS] \ - {*}$global_placement_args + -pad_right $::env(CELL_PAD_IN_SITES_GLOBAL_PLACEMENT) {*}$deprecated] + + log_cmd global_placement \ + {*}[command_args global_placement place.skip_io $flow $deprecated] } source_step_tcl POST GLOBAL_PLACE_SKIP_IO diff --git a/flow/scripts/global_route.tcl b/flow/scripts/global_route.tcl index fb9d41945f..61cbe3385c 100644 --- a/flow/scripts/global_route.tcl +++ b/flow/scripts/global_route.tcl @@ -14,12 +14,21 @@ proc global_route_helper { } { set use_cugr "" append_env_var use_cugr GLOBAL_ROUTE_USE_CUGR -use_cugr 0 + # CUGR runs a full 3D maze pass per iteration; use a tighter default. + set cong_iters [list -congestion_iterations 30] + if { $use_cugr ne "" } { + set cong_iters [list -congestion_iterations 10] + } + set flow [list -congestion_report_file $::global_route_congestion_report \ + {*}$cong_iters {*}$res_aware {*}$use_cugr] + set grt_args [command_args global_route grt.main $flow $res_aware] + # The flow's choice to accept congestion, from GLOBAL_ROUTE_ARGS, passed # to every incremental reroute and to repair_antennas: each call decides # for itself, and one without -allow_congestion reroutes a congested route # harder and then fails on it. set allow_congestion "" - if { [lsearch -exact $::env(GLOBAL_ROUTE_ARGS) -allow_congestion] >= 0 } { + if { [lsearch -exact $grt_args -allow_congestion] >= 0 } { set allow_congestion -allow_congestion } @@ -45,18 +54,9 @@ proc global_route_helper { } { return 1 } - proc do_global_route { res_aware use_cugr } { + proc do_global_route { grt_args } { set_grt_seed - # CUGR runs a full 3D maze pass per iteration; use a tighter default. - set cong_iters "-congestion_iterations 30" - if { $use_cugr ne "" } { - set cong_iters "-congestion_iterations 10" - } - set all_args [concat [list \ - -congestion_report_file $::global_route_congestion_report] \ - $cong_iters $::env(GLOBAL_ROUTE_ARGS) {*}$res_aware {*}$use_cugr] - - return [run_global_route_and_catch_failures {*}$all_args] + return [run_global_route_and_catch_failures {*}$grt_args] } set additional_args "" append_env_var additional_args dbProcessNode -db_process_node 1 @@ -65,7 +65,7 @@ proc global_route_helper { } { log_cmd pin_access {*}$additional_args - if { ![do_global_route $res_aware $use_cugr] } { + if { ![do_global_route $grt_args] } { return } @@ -81,20 +81,16 @@ proc global_route_helper { } { } if { !$::env(SKIP_INCREMENTAL_REPAIR) } { - if { $::env(DETAILED_METRICS) } { - report_metrics 5 "global route pre repair design" - } + report_metrics 5 "global route pre repair design" true true $::env(DETAILED_METRICS) # Repair design using global route parasitics - repair_design_helper - if { $::env(DETAILED_METRICS) } { - report_metrics 5 "global route post repair design" - } + repair_design_helper grt.main + report_metrics 5 "global route post repair design" true true $::env(DETAILED_METRICS) # Running DPL to fix overlapped instances # Run to get modified net by DPL log_cmd global_route -start_incremental {*}$allow_congestion - detailed_placement_helper -quiet + detailed_placement_helper grt.repair_design -quiet # Route only the modified net by DPL if { ![run_global_route_and_catch_failures -end_incremental {*}$res_aware \ @@ -108,14 +104,12 @@ proc global_route_helper { } { puts "Repair setup and hold violations..." log_cmd estimate_parasitics -global_routing - repair_timing_helper + repair_timing_helper grt.main - if { $::env(DETAILED_METRICS) } { - report_metrics 5 "global route post repair timing" - } + report_metrics 5 "global route post repair timing" true true $::env(DETAILED_METRICS) log_cmd global_route -start_incremental {*}$allow_congestion - detailed_placement_helper -quiet + detailed_placement_helper grt.repair_timing -quiet log_cmd check_placement -placeable -verbose # Route only the modified net by DPL if { @@ -134,14 +128,16 @@ proc global_route_helper { } { if { [env_var_exists_and_non_empty MATCH_CELL_FOOTPRINT] } { lappend repair_timing_args -match_cell_footprint } + set deprecated {} if { $::env(SETUP_SLACK_MARGIN) != 0 } { - lappend repair_timing_args -setup_margin $::env(SETUP_SLACK_MARGIN) + lappend deprecated -setup_margin $::env(SETUP_SLACK_MARGIN) } - log_cmd repair_timing {*}$repair_timing_args + lappend repair_timing_args {*}$deprecated + log_cmd repair_timing \ + {*}[command_args repair_timing grt.wns $repair_timing_args $deprecated] - if { $::env(DETAILED_METRICS) } { - report_metrics 5 "global route post repair timing_opt_wns" - } + report_metrics 5 "global route post repair timing_opt_wns" true true \ + $::env(DETAILED_METRICS) } } @@ -158,13 +154,16 @@ proc global_route_helper { } { } } - if { + set run [expr { !$::env(SKIP_ANTENNA_REPAIR) && [env_var_exists_and_non_empty MAX_REPAIR_ANTENNAS_ITER_GRT] - } { + }] + if { [command_runs repair_antennas grt.main $run] } { puts "Repair antennas..." - repair_antennas -iterations $::env(MAX_REPAIR_ANTENNAS_ITER_GRT) \ - {*}$allow_congestion + set deprecated {} + append_env_var deprecated MAX_REPAIR_ANTENNAS_ITER_GRT -iterations 1 + repair_antennas {*}[command_args repair_antennas grt.main \ + [list {*}$deprecated {*}$allow_congestion] $deprecated] # repair antennas calls DPL internally log_cmd check_placement -placeable -verbose check_antennas -report_file $::env(REPORTS_DIR)/grt_antennas.log diff --git a/flow/scripts/io_placement.tcl b/flow/scripts/io_placement.tcl index ad4d7809e2..0315613994 100644 --- a/flow/scripts/io_placement.tcl +++ b/flow/scripts/io_placement.tcl @@ -4,10 +4,8 @@ erase_non_stage_variables place if { !$::env(GPL_PLACE_IOS) && ![pins_fixed_in_floorplan] } { load_design 3_1_place_gp_skip_io.odb 2_floorplan.sdc source_step_tcl PRE IO_PLACEMENT - log_cmd place_pins \ - -hor_layers $::env(IO_PLACER_H) \ - -ver_layers $::env(IO_PLACER_V) \ - {*}[env_var_or_empty PLACE_PINS_ARGS] + set flow [list -hor_layers $::env(IO_PLACER_H) -ver_layers $::env(IO_PLACER_V)] + log_cmd place_pins {*}[command_args place_pins place.main $flow] report_design_area orfs_write_db $::env(RESULTS_DIR)/3_2_place_iop.odb diff --git a/flow/scripts/macro_place_util.tcl b/flow/scripts/macro_place_util.tcl index b613835974..653aa98ef6 100644 --- a/flow/scripts/macro_place_util.tcl +++ b/flow/scripts/macro_place_util.tcl @@ -30,42 +30,43 @@ if { [find_macros] != "" } { log_cmd source $::env(MACRO_PLACEMENT_TCL) } - set additional_rtlmp_args "" - append_env_var additional_rtlmp_args RTLMP_MAX_LEVEL -max_num_level 1 - append_env_var additional_rtlmp_args RTLMP_MAX_INST -max_num_inst 1 - append_env_var additional_rtlmp_args RTLMP_MIN_INST -min_num_inst 1 - append_env_var additional_rtlmp_args RTLMP_MAX_MACRO -max_num_macro 1 - append_env_var additional_rtlmp_args RTLMP_MIN_MACRO -min_num_macro 1 + set deprecated {} + append_env_var deprecated RTLMP_MAX_LEVEL -max_num_level 1 + append_env_var deprecated RTLMP_MAX_INST -max_num_inst 1 + append_env_var deprecated RTLMP_MIN_INST -min_num_inst 1 + append_env_var deprecated RTLMP_MAX_MACRO -max_num_macro 1 + append_env_var deprecated RTLMP_MIN_MACRO -min_num_macro 1 if { ![env_var_exists_and_non_empty RTLMP_MIN_CHANNEL_SIZE] } { set ::env(RTLMP_PIN_AWARE_CHANNELS) 0 } - append_env_var additional_rtlmp_args RTLMP_MIN_CHANNEL_SIZE -min_channel_size 1 - append_env_var additional_rtlmp_args RTLMP_PIN_AWARE_CHANNELS \ + append_env_var deprecated RTLMP_MIN_CHANNEL_SIZE -min_channel_size 1 + append_env_var deprecated RTLMP_PIN_AWARE_CHANNELS \ -pin_aware_channels 0 - append_env_var additional_rtlmp_args RTLMP_MIN_AR -min_ar 1 - append_env_var additional_rtlmp_args RTLMP_AREA_WT -area_weight 1 - append_env_var additional_rtlmp_args RTLMP_WIRELENGTH_WT -wirelength_weight 1 - append_env_var additional_rtlmp_args RTLMP_OUTLINE_WT -outline_weight 1 - append_env_var additional_rtlmp_args RTLMP_BOUNDARY_WT -boundary_weight 1 - append_env_var additional_rtlmp_args RTLMP_NOTCH_WT -notch_weight 1 - append_env_var additional_rtlmp_args RTLMP_RPT_DIR -report_directory 1 - append_env_var additional_rtlmp_args RTLMP_KEEP_CLUSTERING \ + append_env_var deprecated RTLMP_MIN_AR -min_ar 1 + append_env_var deprecated RTLMP_AREA_WT -area_weight 1 + append_env_var deprecated RTLMP_WIRELENGTH_WT -wirelength_weight 1 + append_env_var deprecated RTLMP_OUTLINE_WT -outline_weight 1 + append_env_var deprecated RTLMP_BOUNDARY_WT -boundary_weight 1 + append_env_var deprecated RTLMP_NOTCH_WT -notch_weight 1 + append_env_var deprecated RTLMP_RPT_DIR -report_directory 1 + append_env_var deprecated RTLMP_KEEP_CLUSTERING \ -keep_clustering_data 0 - append_env_var additional_rtlmp_args RTLMP_FENCE_LX -fence_lx 1 - append_env_var additional_rtlmp_args RTLMP_FENCE_LY -fence_ly 1 - append_env_var additional_rtlmp_args RTLMP_FENCE_UX -fence_ux 1 - append_env_var additional_rtlmp_args RTLMP_FENCE_UY -fence_uy 1 + append_env_var deprecated RTLMP_FENCE_LX -fence_lx 1 + append_env_var deprecated RTLMP_FENCE_LY -fence_ly 1 + append_env_var deprecated RTLMP_FENCE_UX -fence_ux 1 + append_env_var deprecated RTLMP_FENCE_UY -fence_uy 1 - append additional_rtlmp_args " -target_util [place_density_with_lb_addon]" - - set all_args $additional_rtlmp_args + set all_args [list {*}$deprecated -target_util [place_density_with_lb_addon]] + # RTLMP_ARGS, deprecated, replaces the flow's arguments. if { [env_var_exists_and_non_empty RTLMP_ARGS] } { set all_args $::env(RTLMP_ARGS) + set deprecated $all_args } - log_cmd rtl_macro_placer {*}$all_args + log_cmd rtl_macro_placer \ + {*}[command_args rtl_macro_placer floorplan.main $all_args $deprecated] } else { puts "No macros found: Skipping macro_placement" } diff --git a/flow/scripts/report_metrics.tcl b/flow/scripts/report_metrics.tcl index ed6f2ec6ef..64ead8986a 100644 --- a/flow/scripts/report_metrics.tcl +++ b/flow/scripts/report_metrics.tcl @@ -30,8 +30,12 @@ proc get_power_file_scope_args { } { return $args } -proc report_metrics { stage when { include_erc true } { include_clock_skew true } } { - if { $::env(SKIP_REPORT_METRICS) } { +# The call is named after the report, as in cts.cts_final for +# report_metrics 4 "cts final"; run is the flow's choice to report here. +proc report_metrics { stage when { include_erc true } { include_clock_skew true } { run 1 } } { + set call [lindex {- synth floorplan place cts grt final} $stage] + append call . [regsub -all {[^a-z0-9]+} [string tolower $when] _] + if { ![command_runs report_metrics $call [expr { $run && !$::env(SKIP_REPORT_METRICS) }]] } { return } puts "Report metrics stage $stage, $when..." diff --git a/flow/scripts/resize.tcl b/flow/scripts/resize.tcl index e46ac4b328..c8ef820008 100644 --- a/flow/scripts/resize.tcl +++ b/flow/scripts/resize.tcl @@ -23,14 +23,14 @@ if { [env_var_equals SWAP_ARITH_OPERATORS 1] } { log_cmd global_placement -incremental -density $density } -repair_design_helper +repair_design_helper place.main -if { $::env(ENABLE_PLACE_REPAIR_TIMING) } { +if { [command_runs repair_timing place.main $::env(ENABLE_PLACE_REPAIR_TIMING)] } { # Repair timing using placement parasitics. puts "Repair setup and hold violations..." log_cmd estimate_parasitics -placement - repair_timing_helper + repair_timing_helper place.main } # post report diff --git a/flow/scripts/util.tcl b/flow/scripts/util.tcl index 065e4e5895..939ac9dc83 100644 --- a/flow/scripts/util.tcl +++ b/flow/scripts/util.tcl @@ -27,40 +27,63 @@ proc log_cmd { cmd args } { return $result } -proc repair_timing_helper { args } { - set additional_args {} - append_env_var additional_args SETUP_SLACK_MARGIN -setup_margin 1 - append_env_var additional_args HOLD_SLACK_MARGIN -hold_margin 1 - append_env_var additional_args SETUP_MOVE_SEQUENCE -sequence 1 - append_env_var additional_args SETUP_REPAIR_PHASES -phases 1 - append_env_var additional_args TNS_END_PERCENT -repair_tns 1 - append_env_var additional_args SKIP_PIN_SWAP -skip_pin_swap 0 - append_env_var additional_args SKIP_GATE_CLONING -skip_gate_cloning 0 - append_env_var additional_args SKIP_BUFFER_REMOVAL -skip_buffer_removal 0 - append_env_var additional_args SKIP_LAST_GASP -skip_last_gasp 0 - append_env_var additional_args SKIP_VT_SWAP -skip_vt_swap 0 - append_env_var additional_args SKIP_CRIT_VT_SWAP -skip_crit_vt_swap 0 - append_env_var additional_args MATCH_CELL_FOOTPRINT -match_cell_footprint 0 - lappend additional_args {*}$args -verbose +# Arguments to one call of a command: the flow's, edited by PLATFORM_ARGS and +# the command's _ARGS (docs/user/CommandArguments.md). args.py +# merges them, so the merge has unit tests (flow/test/test_args.py). call is +# stage.name, as a user scopes an edit to it. flow is the command line the +# flow passes, deprecated variables included; deprecated is the part of it +# deprecated variables add. +proc command_args { cmd call flow { deprecated {} } { legacy {} } } { + set out [exec $::env(PYTHON_EXE) $::env(SCRIPTS_DIR)/args.py resolve \ + $cmd $call 1 [llength $flow] {*}$flow [llength $deprecated] {*}$deprecated \ + {*}$legacy 2>@ stderr] + return [lrange [split $out \n] 1 end] +} + +# Whether a call runs: run is the flow's choice, and on or off in +# PLATFORM_ARGS or _ARGS changes it. +proc command_runs { cmd call run } { + return [exec $::env(PYTHON_EXE) $::env(SCRIPTS_DIR)/args.py runs $cmd $call $run 2>@ stderr] +} - log_cmd repair_timing {*}$additional_args +proc repair_timing_helper { call args } { + set deprecated {} + append_env_var deprecated SETUP_SLACK_MARGIN -setup_margin 1 + append_env_var deprecated HOLD_SLACK_MARGIN -hold_margin 1 + append_env_var deprecated SETUP_MOVE_SEQUENCE -sequence 1 + append_env_var deprecated SETUP_REPAIR_PHASES -phases 1 + append_env_var deprecated TNS_END_PERCENT -repair_tns 1 + append_env_var deprecated SKIP_PIN_SWAP -skip_pin_swap 0 + append_env_var deprecated SKIP_GATE_CLONING -skip_gate_cloning 0 + append_env_var deprecated SKIP_BUFFER_REMOVAL -skip_buffer_removal 0 + append_env_var deprecated SKIP_LAST_GASP -skip_last_gasp 0 + append_env_var deprecated SKIP_VT_SWAP -skip_vt_swap 0 + append_env_var deprecated SKIP_CRIT_VT_SWAP -skip_crit_vt_swap 0 + set flow $deprecated + append_env_var flow MATCH_CELL_FOOTPRINT -match_cell_footprint 0 + lappend flow {*}$args -verbose + + log_cmd repair_timing {*}[command_args repair_timing $call $flow $deprecated] } # Every detailed_placement in the flow goes through here, so the design's -# DETAIL_PLACEMENT_ARGS (the legalizer and its window, say) apply to the +# DETAILED_PLACEMENT_ARGS (the legalizer and its window, say) apply to the # placement stage and to every re-legalization after it alike. -proc detailed_placement_helper { args } { - log_cmd detailed_placement {*}[env_var_or_empty DETAIL_PLACEMENT_ARGS] {*}$args +proc detailed_placement_helper { call args } { + set deprecated [env_var_or_empty DETAIL_PLACEMENT_ARGS] + log_cmd detailed_placement \ + {*}[command_args detailed_placement $call [concat $deprecated $args] $deprecated] } -proc repair_design_helper { } { +proc repair_design_helper { call } { puts "Perform buffer insertion and gate resizing..." - set additional_args "-verbose" - append_env_var additional_args CAP_MARGIN -cap_margin 1 - append_env_var additional_args SLEW_MARGIN -slew_margin 1 - append_env_var additional_args MATCH_CELL_FOOTPRINT -match_cell_footprint 0 - log_cmd repair_design {*}$additional_args + set deprecated {} + append_env_var deprecated CAP_MARGIN -cap_margin 1 + append_env_var deprecated SLEW_MARGIN -slew_margin 1 + set flow [list -verbose {*}$deprecated] + append_env_var flow MATCH_CELL_FOOTPRINT -match_cell_footprint 0 + log_cmd repair_design {*}[command_args repair_design $call $flow $deprecated] } proc recover_power_helper { } { @@ -75,7 +98,7 @@ proc recover_power_helper { } { set additional_args "-verbose" append_env_var additional_args RECOVER_POWER -recover_power 1 append_env_var additional_args MATCH_CELL_FOOTPRINT -match_cell_footprint 0 - log_cmd repair_timing {*}$additional_args + log_cmd repair_timing {*}[command_args repair_timing grt.recover_power $additional_args] report_tns report_wns report_power @@ -167,7 +190,7 @@ proc place_pins_args_to_place_config { } { set config_args [list \ -io_pin_hor_layers $::env(IO_PLACER_H) \ -io_pin_ver_layers $::env(IO_PLACER_V)] - set pins_args [env_var_or_empty PLACE_PINS_ARGS] + set pins_args [command_args place_pins place.main {}] for { set i 0 } { $i < [llength $pins_args] } { incr i } { set arg [lindex $pins_args $i] switch -- $arg { @@ -207,6 +230,9 @@ proc find_macros { } { } proc erase_non_stage_variables { stage_name } { + # Every _ARGS is checked before the stage reads one, and the + # deprecated variables this stage reads are named with their replacement. + exec $::env(PYTHON_EXE) $::env(SCRIPTS_DIR)/args.py check $stage_name 2>@ stderr if { $::env(KEEP_VARS) } { return } diff --git a/flow/scripts/variables.json b/flow/scripts/variables.json index d1e156a808..84bfa0156f 100644 --- a/flow/scripts/variables.json +++ b/flow/scripts/variables.json @@ -76,7 +76,17 @@ }, "BALANCE_ROWS": { "default": 0, + "deprecated": 1, "description": "Balance rows during placement.\n", + "replacement": { + "1": "BALANCE_ROW_USAGE_ARGS = on" + }, + "stages": [ + "place" + ] + }, + "BALANCE_ROW_USAGE_ARGS": { + "description": "Edits to the arguments the flow passes to `balance_row_usage`, in the grammar of docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, `on`/`off`, each optionally scoped `stage:` or `stage.call:`.\n", "stages": [ "place" ] @@ -85,7 +95,7 @@ "description": "Blocks used as hard macros in a hierarchical flow. Do note that you have to specify block-specific inputs file in the directory mentioned by Makefile.\n" }, "BUFFER_PORTS_ARGS": { - "description": "Specify arguments to the buffer_ports call during placement. Only used if DONT_BUFFER_PORTS=0.\n", + "description": "Edits to the arguments the flow passes to `buffer_ports`, in the grammar of docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, `on`/`off`, each optionally scoped `stage:` or `stage.call:`.\n", "stages": [ "place" ] @@ -97,7 +107,9 @@ ] }, "CAP_MARGIN": { + "deprecated": 1, "description": "Specifies a capacitance margin when fixing max capacitance violations. This option allows you to overfix.\n", + "replacement": "REPAIR_DESIGN_ARGS = -cap_margin {value}", "tunable": 1 }, "CDL_FILE": { @@ -137,16 +149,26 @@ "synth" ] }, + "CLOCK_TREE_SYNTHESIS_ARGS": { + "description": "Edits to the arguments the flow passes to `clock_tree_synthesis`, in the grammar of docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, `on`/`off`, each optionally scoped `stage:` or `stage.call:`.\n", + "stages": [ + "cts" + ] + }, "CLUSTER_FLOPS": { "default": 0, + "deprecated": 1, "description": "Enable clustering of flip-flops into multi-bit flip-flops, if the platform PDK includes multi-bit flip-flops\n", + "replacement": { + "1": "CLUSTER_FLOPS_ARGS = on" + }, "stages": [ "place" ] }, "CLUSTER_FLOPS_ARGS": { "default": "", - "description": "Additional arguments passed to the cluster_flops command. Only used when CLUSTER_FLOPS is set.\n", + "description": "Edits to the arguments the flow passes to `cluster_flops`, in the grammar of docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, `on`/`off`, each optionally scoped `stage:` or `stage.call:`.\n", "stages": [ "place" ] @@ -194,13 +216,17 @@ ] }, "CTS_ARGS": { + "deprecated": 1, "description": "Override `clock_tree_synthesis` arguments.\n", + "replacement": "CLOCK_TREE_SYNTHESIS_ARGS, with only what differs from the flow's arguments", "stages": [ "cts" ] }, "CTS_BUF_DISTANCE": { + "deprecated": 1, "description": "Distance (in microns) between buffers.\n", + "replacement": "CLOCK_TREE_SYNTHESIS_ARGS = -distance_between_buffers {value}", "stages": [ "cts" ], @@ -208,13 +234,17 @@ "type": "float" }, "CTS_BUF_LIST": { + "deprecated": 1, "description": "List of cells used to construct the clock tree. Overrides buffer inference.\n", + "replacement": "CLOCK_TREE_SYNTHESIS_ARGS = -buf_list {value}", "stages": [ "cts" ] }, "CTS_CLUSTER_DIAMETER": { + "deprecated": 1, "description": "Maximum diameter (in microns) of sink cluster.\n", + "replacement": "CLOCK_TREE_SYNTHESIS_ARGS = -sink_clustering_max_diameter {value}", "stages": [ "cts" ], @@ -222,7 +252,9 @@ "type": "float" }, "CTS_CLUSTER_SIZE": { + "deprecated": 1, "description": "Maximum number of sinks per cluster.\n", + "replacement": "CLOCK_TREE_SYNTHESIS_ARGS = -sink_clustering_size {value}", "stages": [ "cts" ], @@ -230,7 +262,9 @@ "type": "int" }, "CTS_LIB_NAME": { + "deprecated": 1, "description": "Name of the Liberty library to use in selecting the clock buffers.\n", + "replacement": "CLOCK_TREE_SYNTHESIS_ARGS = -library {value}", "stages": [ "cts" ] @@ -251,27 +285,43 @@ }, "DETAILED_METRICS": { "default": 0, + "deprecated": 1, "description": "If set, then calls report_metrics prior to repair operations in the CTS and global route stages\n", + "replacement": { + "1": "REPORT_METRICS_ARGS = cts:on grt:on" + }, "stages": [ "cts", "grt" ] }, + "DETAILED_PLACEMENT_ARGS": { + "description": "Edits to the arguments the flow passes to `detailed_placement`, in the grammar of docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, `on`/`off`, each optionally scoped `stage:` or `stage.call:`.\n", + "stages": [ + "place", + "cts", + "grt" + ] + }, "DETAILED_ROUTE_ARGS": { - "description": "Add additional arguments for debugging purposes during detail route.\n", + "description": "Edits to the arguments the flow passes to `detailed_route`, in the grammar of docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, `on`/`off`, each optionally scoped `stage:` or `stage.call:`. Until it is removed, a value that is a plain command line, with no `~`, `on`, `off` or scope, replaces the flow's arguments, as it always has.\n", "stages": [ "route" ] }, "DETAILED_ROUTE_END_ITERATION": { "default": 64, + "deprecated": 1, "description": "Maximum number of iterations.\n", + "replacement": "DETAILED_ROUTE_ARGS = -droute_end_iter {value}", "stages": [ "route" ] }, "DETAIL_PLACEMENT_ARGS": { + "deprecated": 1, "description": "Specify arguments to every detailed_placement call: the one in placement and the re-legalizations after clock tree synthesis, after repair in CTS and after the repairs in global route. A legalizer chosen here (-use_diamond_legalizer, -max_displacement) is therefore the one every stage uses.\n", + "replacement": "DETAILED_PLACEMENT_ARGS = {value}", "stages": [ "place", "cts", @@ -298,14 +348,22 @@ "tunable": 1 }, "DISABLE_VIA_GEN": { + "deprecated": 1, "description": "Passed as -disable_via_gen to detailed_route.\n", + "replacement": { + "1": "DETAILED_ROUTE_ARGS = -disable_via_gen" + }, "stages": [ "route" ] }, "DONT_BUFFER_PORTS": { "default": 0, + "deprecated": 1, "description": "Do not buffer input/output ports during floorplanning.\n", + "replacement": { + "1": "BUFFER_PORTS_ARGS = off" + }, "stages": [ "place" ] @@ -315,7 +373,9 @@ }, "DPO_MAX_DISPLACEMENT": { "default": "5 1", + "deprecated": 1, "description": "Specifies how far an instance can be moved when optimizing.\n", + "replacement": "IMPROVE_PLACEMENT_ARGS = -max_displacement {value}", "stages": [ "place" ] @@ -328,20 +388,32 @@ }, "ENABLE_DPO": { "default": 1, + "deprecated": 1, "description": "Enable detail placement with improve_placement feature.\n", + "replacement": { + "0": "IMPROVE_PLACEMENT_ARGS = off" + }, "stages": [ "place" ] }, "ENABLE_PLACE_REPAIR_TIMING": { "default": 0, + "deprecated": 1, "description": "Run repair_timing during the placement resize stage using placement parasitics. Disabled by default; pre-CTS setup/hold repair is skipped unless this is set to 1.\n", + "replacement": { + "1": "REPAIR_TIMING_ARGS = place:on" + }, "stages": [ "place" ] }, "ENABLE_RESISTANCE_AWARE": { + "deprecated": 1, "description": "Passed as -resistance_aware to global_route.\n", + "replacement": { + "1": "GLOBAL_ROUTE_ARGS = -resistance_aware" + }, "stages": [ "grt" ] @@ -395,14 +467,14 @@ "description": "For instance Bazel needs artifacts (.odb and .rpt files) on a failure to allow the user to save hours on re-running the failed step locally, but when working with a Makefile flow, it is more natural to fail the step and leave the user to manually inspect the logs and artifacts directly via the file system. Set to 1 to change the behavior to generate artifacts upon failure to e.g. do a global route. The exit code will still be non-zero on all other failures that aren't covered by the \"useful to inspect the artifacts on failure\" use-case. Example: just like detailed routing, a global route that fails with congestion, is not a build failure(as in exit code non-zero), it is a successful(as in zero exit code) global route that produce reports detailing the problem. Detailed route will not proceed, if there is global routing congestion This allows build systems, such as bazel, to create artifacts for global and detailed route, even if the operation had problems, without having know about the semantics between global and detailed route. Considering that global and detailed route can run for a long time and use a lot of memory, this allows inspecting results on a laptop for a build that ran on a server.\n" }, "GLOBAL_PLACEMENT_ARGS": { - "description": "Use additional tuning parameters during global placement other than default args defined in global_place.tcl.\n", + "description": "Edits to the arguments the flow passes to `global_placement`, in the grammar of docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, `on`/`off`, each optionally scoped `stage:` or `stage.call:`.\n", "stages": [ "place" ] }, "GLOBAL_ROUTE_ARGS": { "default": "-congestion_report_iter_step 5 -verbose", - "description": "Replaces default arguments for global route. The -congestion_iterations default is set by the flow (30 for FastRoute, 10 for CUGR); add -congestion_iterations here to override it.\n", + "description": "Edits to the arguments the flow passes to `global_route`, in the grammar of docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, `on`/`off`, each optionally scoped `stage:` or `stage.call:`. Edits the first global_route; the incremental ones after repair take -allow_congestion from it.\n", "stages": [ "grt" ] @@ -434,14 +506,20 @@ ] }, "GPL_RANDOM_SEED": { + "deprecated": 1, "description": "Specifies a random seed for global placement. Useful for perturbation studies.\n", + "replacement": "GLOBAL_PLACEMENT_ARGS = -random_seed {value}", "stages": [ "place" ] }, "GPL_ROUTABILITY_DRIVEN": { "default": 1, + "deprecated": 1, "description": "Specifies whether the placer should use routability driven placement.\n", + "replacement": { + "0": "GLOBAL_PLACEMENT_ARGS = ~-routability_driven" + }, "stages": [ "place" ] @@ -467,13 +545,21 @@ }, "HOLD_SLACK_MARGIN": { "default": 0, + "deprecated": 1, "description": "Specifies a time margin for the slack when fixing hold violations. This option allows you to overfix or underfix (negative value, terminate retiming before 0 or positive slack). floorplan.tcl uses min of HOLD_SLACK_MARGIN and 0 (default hold slack margin). This avoids overrepair in floorplan for hold by default, but allows skipping hold repair using a negative HOLD_SLACK_MARGIN. Exiting timing repair early is useful in exploration where the .sdc has a fixed clock period at the design's target clock period and where HOLD/SETUP_SLACK_MARGIN is used to avoid overrepair (extremely long running times) when exploring different parameter settings. When an ideal clock is used, that is before CTS, a clock insertion delay of 0 is used in timing paths. This creates a mismatch between macros that have a .lib file from after CTS, when the clock is propagated. To mitigate this, OpenSTA will use subtract the clock insertion delay of macros when calculating timing with ideal clock. Provided that min_clock_tree_path and max_clock_tree_path are in the .lib file, which is the case for macros built with OpenROAD. This is less accurate than if OpenROAD had created a placeholder clock tree for timing estimation purposes prior to CTS. There will inevitably be inaccuracies in the timing calculation prior to CTS. Use a slack margin that is low enough, even negative, to avoid overrepair. Inaccuracies in the timing prior to CTS can also lead to underrepair, but there no obvious and simple way to avoid underrapir in these cases. Overrepair can lead to excessive runtimes in repair or too much buffering being added, which can present itself as congestion of hold cells or buffer cells. Another use of SETUP/HOLD_SLACK_MARGIN is design parameter exploration when trying to find the minimum clock period for a design. The SDC_FILE for a design can be quite complicated and instead of modifying the clock period in the SDC_FILE, which can be non-trivial, the clock period can be fixed at the target frequency and the SETUP/HOLD_SLACK_MARGIN can be swept to find a plausible current minimum clock period.\n", + "replacement": "REPAIR_TIMING_ARGS = -hold_margin {value}", "stages": [ "cts", "floorplan", "grt" ] }, + "IMPROVE_PLACEMENT_ARGS": { + "description": "Edits to the arguments the flow passes to `improve_placement`, in the grammar of docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, `on`/`off`, each optionally scoped `stage:` or `stage.call:`.\n", + "stages": [ + "place" + ] + }, "INFER_CLKGATES": { "default": 0, "description": "Enables Yosys clock gate inference. By default, it uses the Liberty cell definitions to determine clock gating cell. The selection can be overridden using the POS_CLKGATE_AND_PORTS and/or NEG_CLKGATE_AND_PORTS variables.\n", @@ -604,7 +690,9 @@ }, "MAX_REPAIR_ANTENNAS_ITER_GRT": { "default": 5, + "deprecated": 1, "description": "Defines the maximum number of iterations post global routing repair antennas will run.\n", + "replacement": "REPAIR_ANTENNAS_ARGS = grt:-iterations {value}", "stages": [ "grt" ] @@ -675,13 +763,17 @@ ] }, "OR_K": { + "deprecated": 1, "description": "Passed as -or_k to detailed routing.\n", + "replacement": "DETAILED_ROUTE_ARGS = -or_k {value}", "stages": [ "route" ] }, "OR_SEED": { + "deprecated": 1, "description": "Passed as -or_seed to detailed routing.\n", + "replacement": "DETAILED_ROUTE_ARGS = -or_seed {value}", "stages": [ "route" ] @@ -709,7 +801,7 @@ "type": "float" }, "PLACE_PINS_ARGS": { - "description": "Arguments to place_pins\n", + "description": "Edits to the arguments the flow passes to `place_pins`, in the grammar of docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, `on`/`off`, each optionally scoped `stage:` or `stage.call:`.\n", "stages": [ "place" ] @@ -726,6 +818,12 @@ "description": "Specifies process design kit or technology node to be used.\n", "required": true }, + "PLATFORM_ARGS": { + "description": "A platform's defaults for command arguments, in the grammar of docs/user/CommandArguments.md, each edit starting with the command it is for, as in `rtl_macro_placer:-halo_width 5`. They rank above the flow's own arguments and below a design's _ARGS.\n", + "stages": [ + "All stages" + ] + }, "PLATFORM_TCL": { "description": "Specifies a Tcl script with commands to run before loading design.\n" }, @@ -951,8 +1049,39 @@ "description": "String patterns directly passed to write_verilog -remove_cells <> for lec checks.\n", "type": "string" }, + "REPAIR_ANTENNAS_ARGS": { + "description": "Edits to the arguments the flow passes to `repair_antennas`, in the grammar of docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, `on`/`off`, each optionally scoped `stage:` or `stage.call:`.\n", + "stages": [ + "grt", + "route" + ] + }, + "REPAIR_DESIGN_ARGS": { + "description": "Edits to the arguments the flow passes to `repair_design`, in the grammar of docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, `on`/`off`, each optionally scoped `stage:` or `stage.call:`.\n", + "stages": [ + "place", + "grt" + ] + }, "REPAIR_PDN_VIA_LAYER": { - "description": "Remove power grid vias which generate DRC violations after detailed routing.\n" + "deprecated": 1, + "description": "Remove power grid vias which generate DRC violations after detailed routing.\n", + "replacement": "DETAILED_ROUTE_ARGS = -repair_pdn_vias {value}" + }, + "REPAIR_TIE_FANOUT_ARGS": { + "description": "Edits to the arguments the flow passes to `repair_tie_fanout`, in the grammar of docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, `on`/`off`, each optionally scoped `stage:` or `stage.call:`.\n", + "stages": [ + "floorplan" + ] + }, + "REPAIR_TIMING_ARGS": { + "description": "Edits to the arguments the flow passes to `repair_timing`, in the grammar of docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, `on`/`off`, each optionally scoped `stage:` or `stage.call:`.\n", + "stages": [ + "floorplan", + "place", + "cts", + "grt" + ] }, "REPORT_CLOCK_SKEW": { "default": 1, @@ -977,6 +1106,18 @@ "final" ] }, + "REPORT_METRICS_ARGS": { + "description": "Edits to the arguments the flow passes to `report_metrics`, in the grammar of docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, `on`/`off`, each optionally scoped `stage:` or `stage.call:`.\n", + "stages": [ + "synth", + "floorplan", + "place", + "cts", + "grt", + "route", + "final" + ] + }, "ROUTING_LAYER_ADJUSTMENT": { "default": 0.5, "description": "Adjusts routing layer capacities to manage congestion and improve detailed routing. High values ease detailed routing but risk excessive detours and long global routing times, while low values reduce global routing failure but can complicate detailed routing. The global routing running time normally reduces dramatically (entirely design specific, but going from hours to minutes has been observed) when the value is low (such as 0.10). Sometimes, global routing will succeed with lower values and fail with higher values. Exploring results with different values can help shed light on the problem. Start with a too low value, such as 0.10, and bisect to value that works by doing multiple global routing runs. As a last resort, `make global_route_issue` and using the tools/OpenROAD/etc/whittle.py can be useful to debug global routing errors. If there is something specific that is impossible to route, such as a clock line over a macro, global routing will terminate with DRC errors routes that could have been routed were it not for the specific impossible routes. whittle.py should weed out the possible routes and leave a minimal failing case that pinpoints the problem.\n", @@ -990,133 +1131,183 @@ }, "RTLMP_AREA_WT": { "default": 0.1, + "deprecated": 1, "description": "Weight for the area of the current floorplan.\n", + "replacement": "RTL_MACRO_PLACER_ARGS = -area_weight {value}", "stages": [ "floorplan" ] }, "RTLMP_ARGS": { + "deprecated": 1, "description": "Overrides all other RTL macro placer arguments.\n", + "replacement": "RTL_MACRO_PLACER_ARGS, with only what differs from the flow's arguments", "stages": [ "floorplan" ] }, "RTLMP_BOUNDARY_WT": { "default": 50.0, + "deprecated": 1, "description": "Weight for the boundary or how far the hard macro clusters are from boundaries.\n", + "replacement": "RTL_MACRO_PLACER_ARGS = -boundary_weight {value}", "stages": [ "floorplan" ] }, "RTLMP_FENCE_LX": { "default": 0.0, + "deprecated": 1, "description": "Defines the lower left X coordinate for the global fence bounding box in microns.\n", + "replacement": "RTL_MACRO_PLACER_ARGS = -fence_lx {value}", "stages": [ "floorplan" ] }, "RTLMP_FENCE_LY": { "default": 0.0, + "deprecated": 1, "description": "Defines the lower left Y coordinate for the global fence bounding box in microns.\n", + "replacement": "RTL_MACRO_PLACER_ARGS = -fence_ly {value}", "stages": [ "floorplan" ] }, "RTLMP_FENCE_UX": { "default": 0.0, + "deprecated": 1, "description": "Defines the upper right X coordinate for the global fence bounding box in microns.\n", + "replacement": "RTL_MACRO_PLACER_ARGS = -fence_ux {value}", "stages": [ "floorplan" ] }, "RTLMP_FENCE_UY": { "default": 0.0, + "deprecated": 1, "description": "Defines the upper right Y coordinate for the global fence bounding box in microns.\n", + "replacement": "RTL_MACRO_PLACER_ARGS = -fence_uy {value}", "stages": [ "floorplan" ] }, "RTLMP_KEEP_CLUSTERING": { "default": 0, + "deprecated": 1, "description": "Set to 1 to store the RTL macro placer's clustering hierarchy in the ODB as nested dbGroups.\n", + "replacement": { + "1": "RTL_MACRO_PLACER_ARGS = -keep_clustering_data" + }, "stages": [ "floorplan" ] }, "RTLMP_MAX_INST": { + "deprecated": 1, "description": "Maximum number of standard cells in a cluster. If unset, rtl_macro_placer will calculate a value based on the design attributes.\n", + "replacement": "RTL_MACRO_PLACER_ARGS = -max_num_inst {value}", "stages": [ "floorplan" ] }, "RTLMP_MAX_LEVEL": { "default": 2, + "deprecated": 1, "description": "Maximum depth of the physical hierarchy tree.\n", + "replacement": "RTL_MACRO_PLACER_ARGS = -max_num_level {value}", "stages": [ "floorplan" ] }, "RTLMP_MAX_MACRO": { + "deprecated": 1, "description": "Maximum number of macros in a cluster. If unset, rtl_macro_placer will calculate a value based on the design attributes.\n", + "replacement": "RTL_MACRO_PLACER_ARGS = -max_num_macro {value}", "stages": [ "floorplan" ] }, "RTLMP_MIN_AR": { "default": 0.33, + "deprecated": 1, "description": "Specifies the minimum aspect ratio (height/width).\n", + "replacement": "RTL_MACRO_PLACER_ARGS = -min_ar {value}", "stages": [ "floorplan" ] }, "RTLMP_MIN_CHANNEL_SIZE": { + "deprecated": 1, "description": "Minimum channel width and height between macros (microns), given as one value for both, or two values \"width height\".\n", + "replacement": "RTL_MACRO_PLACER_ARGS = -min_channel_size {value}", "stages": [ "floorplan" ] }, "RTLMP_MIN_INST": { + "deprecated": 1, "description": "Minimum number of standard cells in a cluster. If unset, rtl_macro_placer will calculate a value based on the design attributes.\n", + "replacement": "RTL_MACRO_PLACER_ARGS = -min_num_inst {value}", "stages": [ "floorplan" ] }, "RTLMP_MIN_MACRO": { + "deprecated": 1, "description": "Minimum number of macros in a cluster. If unset, rtl_macro_placer will calculate a value based on the design attributes.\n", + "replacement": "RTL_MACRO_PLACER_ARGS = -min_num_macro {value}", "stages": [ "floorplan" ] }, "RTLMP_NOTCH_WT": { "default": 50.0, + "deprecated": 1, "description": "Weight for the notch, or the existence of dead space that cannot be used for placement and routing.\n", + "replacement": "RTL_MACRO_PLACER_ARGS = -notch_weight {value}", "stages": [ "floorplan" ] }, "RTLMP_OUTLINE_WT": { "default": 100.0, + "deprecated": 1, "description": "Weight for violating the fixed outline constraint, meaning that all clusters should be placed within the shape of their parent cluster.\n", + "replacement": "RTL_MACRO_PLACER_ARGS = -outline_weight {value}", "stages": [ "floorplan" ] }, "RTLMP_PIN_AWARE_CHANNELS": { "default": 1, + "deprecated": 1, "description": "Set to 1 to trim macro channels based on the pin locations of macros, instead of using full channels. Requires RTLMP_MIN_CHANNEL_SIZE to also be set. Defaults to 1 whenever RTLMP_MIN_CHANNEL_SIZE is set and this variable is not explicitly set to 0.\n", + "replacement": { + "0": "RTL_MACRO_PLACER_ARGS = ~-pin_aware_channels" + }, "stages": [ "floorplan" ] }, "RTLMP_RPT_DIR": { + "deprecated": 1, "description": "Path to the directory where reports are saved.\n", + "replacement": "RTL_MACRO_PLACER_ARGS = -report_directory {value}", "stages": [ "floorplan" ] }, "RTLMP_WIRELENGTH_WT": { "default": 100.0, + "deprecated": 1, "description": "Weight for half-perimiter wirelength.\n", + "replacement": "RTL_MACRO_PLACER_ARGS = -wirelength_weight {value}", + "stages": [ + "floorplan" + ] + }, + "RTL_MACRO_PLACER_ARGS": { + "description": "Edits to the arguments the flow passes to `rtl_macro_placer`, in the grammar of docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, `on`/`off`, each optionally scoped `stage:` or `stage.call:`.\n", "stages": [ "floorplan" ] @@ -1154,7 +1345,9 @@ ] }, "SETUP_MOVE_SEQUENCE": { + "deprecated": 1, "description": "Passed as -sequence to repair_timing. This should be a string of move keywords separated by commas.\n", + "replacement": "REPAIR_TIMING_ARGS = -sequence {value}", "stages": [ "cts", "floorplan", @@ -1162,7 +1355,9 @@ ] }, "SETUP_REPAIR_PHASES": { + "deprecated": 1, "description": "Passed as -phases to repair_timing. This should be a string of setup repair phase names separated by spaces. Set to PARALLEL_EVAL to repair setup timing with the experimental parallel evaluation policy. When unset, repair_timing runs its default phases.\n", + "replacement": "REPAIR_TIMING_ARGS = -phases {value}", "stages": [ "cts", "floorplan", @@ -1172,7 +1367,9 @@ }, "SETUP_SLACK_MARGIN": { "default": 0, + "deprecated": 1, "description": "Specifies a time margin for the slack when fixing setup violations.\nThis option allows you to overfix or underfix(negative value, terminate\nretiming before 0 or positive slack).\nSee HOLD_SLACK_MARGIN for more details.\n", + "replacement": "REPAIR_TIMING_ARGS = -setup_margin {value}", "stages": [ "cts", "floorplan", @@ -1182,20 +1379,32 @@ }, "SKIP_ANTENNA_REPAIR": { "default": 0, + "deprecated": 1, "description": "Skips antenna repair entirely.\n", + "replacement": { + "1": "REPAIR_ANTENNAS_ARGS = grt:off" + }, "stages": [ "grt" ] }, "SKIP_ANTENNA_REPAIR_POST_DRT": { "default": 0, + "deprecated": 1, "description": "Skips antenna repair post-detailed routing.\n", + "replacement": { + "1": "REPAIR_ANTENNAS_ARGS = route:off" + }, "stages": [ "route" ] }, "SKIP_BUFFER_REMOVAL": { + "deprecated": 1, "description": "Passed as -skip_buffer_removal to repair_timing. Do not remove buffers as a transform to fix timing violations (default: allow buffer removal).\n", + "replacement": { + "1": "REPAIR_TIMING_ARGS = -skip_buffer_removal" + }, "stages": [ "cts", "floorplan", @@ -1203,7 +1412,11 @@ ] }, "SKIP_CRIT_VT_SWAP": { + "deprecated": 1, "description": "Do not perform VT swap on critical cells to improve QoR (default: do critical VT swap). This is an additional VT swap on critical cells that remain near the end of setup fixing. If SKIP_VT_SWAP is set to 1, this also disables critical cell VT swap.\n", + "replacement": { + "1": "REPAIR_TIMING_ARGS = -skip_crit_vt_swap" + }, "stages": [ "cts", "floorplan", @@ -1212,7 +1425,11 @@ }, "SKIP_CTS_REPAIR_TIMING": { "default": 0, + "deprecated": 1, "description": "Skipping CTS repair, which can take a long time, can be useful in architectural exploration or when getting CI up and running.\n", + "replacement": { + "1": "REPAIR_TIMING_ARGS = cts:off" + }, "stages": [ "cts" ] @@ -1227,13 +1444,21 @@ }, "SKIP_FLOORPLAN_REPAIR_TIMING": { "default": 0, + "deprecated": 1, "description": "Skipping floorplan repair which sometimes does too much optimization too early.\n", + "replacement": { + "1": "REPAIR_TIMING_ARGS = floorplan:off" + }, "stages": [ "floorplan" ] }, "SKIP_GATE_CLONING": { + "deprecated": 1, "description": "Do not use gate cloning transform to fix timing violations (default: use gate cloning).\n", + "replacement": { + "1": "REPAIR_TIMING_ARGS = -skip_gate_cloning" + }, "stages": [ "cts", "floorplan", @@ -1248,7 +1473,11 @@ ] }, "SKIP_LAST_GASP": { + "deprecated": 1, "description": "Do not use last gasp optimization to fix timing violations (default: use gate last gasp).\n", + "replacement": { + "1": "REPAIR_TIMING_ARGS = -skip_last_gasp" + }, "stages": [ "cts", "floorplan", @@ -1256,7 +1485,11 @@ ] }, "SKIP_PIN_SWAP": { + "deprecated": 1, "description": "Do not use pin swapping as a transform to fix timing violations (default: use pin swapping).\n", + "replacement": { + "1": "REPAIR_TIMING_ARGS = -skip_pin_swap" + }, "stages": [ "cts", "floorplan", @@ -1265,14 +1498,22 @@ }, "SKIP_REPAIR_TIE_FANOUT": { "default": 0, + "deprecated": 1, "description": "Skip repair_tie_fanout at floorplan step.\n", + "replacement": { + "1": "REPAIR_TIE_FANOUT_ARGS = off" + }, "stages": [ "floorplan" ] }, "SKIP_REPORT_METRICS": { "default": 0, + "deprecated": 1, "description": "If set to 1, then metrics, report_metrics does nothing. Useful to speed up builds.\n", + "replacement": { + "1": "REPORT_METRICS_ARGS = off" + }, "stages": [ "synth", "floorplan", @@ -1284,7 +1525,11 @@ ] }, "SKIP_VT_SWAP": { + "deprecated": 1, "description": "Do not perform VT swap to improve QoR (default: do VT swap).\n", + "replacement": { + "1": "REPAIR_TIMING_ARGS = -skip_vt_swap" + }, "stages": [ "cts", "floorplan", @@ -1292,7 +1537,9 @@ ] }, "SLEW_MARGIN": { + "deprecated": 1, "description": "Specifies a slew margin when fixing max slew violations. This option allows you to overfix.\n", + "replacement": "REPAIR_DESIGN_ARGS = -slew_margin {value}", "tunable": 1 }, "SWAP_ARITH_OPERATORS": { @@ -1510,14 +1757,18 @@ }, "TIE_SEPARATION": { "default": 0, + "deprecated": 1, "description": "Distance separating tie high/low instances from the load.\n", + "replacement": "REPAIR_TIE_FANOUT_ARGS = -separation {value}", "stages": [ "floorplan" ] }, "TNS_END_PERCENT": { "default": 100, + "deprecated": 1, "description": "Default TNS_END_PERCENT value for post CTS timing repair. Try fixing all violating endpoints by default (reduce to 5% for runtime). Specifies how many percent of violating paths to fix [0-100]. Worst path will always be fixed.\n", + "replacement": "REPAIR_TIMING_ARGS = -repair_tns {value}", "stages": [ "place", "cts", diff --git a/flow/scripts/variables.yaml b/flow/scripts/variables.yaml index 1af977b0e6..1638910669 100644 --- a/flow/scripts/variables.yaml +++ b/flow/scripts/variables.yaml @@ -34,6 +34,8 @@ TNS_END_PERCENT: - cts - floorplan - grt + deprecated: 1 + replacement: REPAIR_TIMING_ARGS = -repair_tns {value} ROUTING_LAYER_ADJUSTMENT: default: 0.5 description: > @@ -84,6 +86,9 @@ DETAILED_METRICS: stages: - cts - grt + deprecated: 1 + replacement: + '1': REPORT_METRICS_ARGS = cts:on grt:on CORE_UTILIZATION: description: | The core utilization percentage (0-100). @@ -139,6 +144,9 @@ SKIP_REPORT_METRICS: - route - final default: 0 + deprecated: 1 + replacement: + '1': REPORT_METRICS_ARGS = off PROCESS: description: | Technology node or process in use. @@ -467,6 +475,8 @@ TIE_SEPARATION: stages: - floorplan default: 0 + deprecated: 1 + replacement: REPAIR_TIE_FANOUT_ARGS = -separation {value} UNSET_ABC9_BOX_CELLS: description: | List of cells to unset the abc9_box attribute on @@ -541,9 +551,14 @@ DONT_BUFFER_PORTS: stages: - place default: 0 + deprecated: 1 + replacement: + '1': BUFFER_PORTS_ARGS = off BUFFER_PORTS_ARGS: description: > - Specify arguments to the buffer_ports call during placement. Only used if DONT_BUFFER_PORTS=0. + Edits to the arguments the flow passes to `buffer_ports`, in the grammar of + docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, + `on`/`off`, each optionally scoped `stage:` or `stage.call:`. stages: - place BALANCE_ROWS: @@ -552,6 +567,9 @@ BALANCE_ROWS: stages: - place default: 0 + deprecated: 1 + replacement: + '1': BALANCE_ROW_USAGE_ARGS = on ADDITIONAL_SITES: description: > Passed as -additional_sites to initialize_floorplan. @@ -661,6 +679,8 @@ DETAIL_PLACEMENT_ARGS: - place - cts - grt + deprecated: 1 + replacement: DETAILED_PLACEMENT_ARGS = {value} CELL_PAD_IN_SITES_DETAIL_PLACEMENT: description: > Cell padding on both sides in site widths to ease routability in detail @@ -674,8 +694,10 @@ CELL_PAD_IN_SITES_DETAIL_PLACEMENT: type: int tunable: 1 PLACE_PINS_ARGS: - description: | - Arguments to place_pins + description: > + Edits to the arguments the flow passes to `place_pins`, in the grammar of + docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, + `on`/`off`, each optionally scoped `stage:` or `stage.call:`. stages: - place PLACE_DENSITY: @@ -704,10 +726,13 @@ PLACE_DENSITY_LB_ADDON: REPAIR_PDN_VIA_LAYER: description: | Remove power grid vias which generate DRC violations after detailed routing. + deprecated: 1 + replacement: DETAILED_ROUTE_ARGS = -repair_pdn_vias {value} GLOBAL_PLACEMENT_ARGS: description: > - Use additional tuning parameters during global placement other than default - args defined in global_place.tcl. + Edits to the arguments the flow passes to `global_placement`, in the grammar of + docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, + `on`/`off`, each optionally scoped `stage:` or `stage.call:`. stages: - place ENABLE_DPO: @@ -716,17 +741,24 @@ ENABLE_DPO: default: 1 stages: - place + deprecated: 1 + replacement: + '0': IMPROVE_PLACEMENT_ARGS = off DPO_MAX_DISPLACEMENT: description: | Specifies how far an instance can be moved when optimizing. default: 5 1 stages: - place + deprecated: 1 + replacement: IMPROVE_PLACEMENT_ARGS = -max_displacement {value} GPL_RANDOM_SEED: description: | Specifies a random seed for global placement. Useful for perturbation studies. stages: - place + deprecated: 1 + replacement: GLOBAL_PLACEMENT_ARGS = -random_seed {value} GPL_TIMING_DRIVEN: description: | Specifies whether the placer should use timing driven placement. @@ -739,6 +771,9 @@ GPL_ROUTABILITY_DRIVEN: stages: - place default: 1 + deprecated: 1 + replacement: + '0': GLOBAL_PLACEMENT_ARGS = ~-routability_driven GPL_PLACE_IOS: description: | Place IO pins together with the cells in global placement (-place_ios). @@ -780,16 +815,22 @@ CAP_MARGIN: Specifies a capacitance margin when fixing max capacitance violations. This option allows you to overfix. tunable: 1 + deprecated: 1 + replacement: REPAIR_DESIGN_ARGS = -cap_margin {value} SLEW_MARGIN: description: > Specifies a slew margin when fixing max slew violations. This option allows you to overfix. tunable: 1 + deprecated: 1 + replacement: REPAIR_DESIGN_ARGS = -slew_margin {value} CTS_ARGS: description: | Override `clock_tree_synthesis` arguments. stages: - cts + deprecated: 1 + replacement: CLOCK_TREE_SYNTHESIS_ARGS, with only what differs from the flow's arguments CTS_SNAPSHOTS: description: | Create ODB/SDC files at different stages of CTS. @@ -838,6 +879,8 @@ HOLD_SLACK_MARGIN: - floorplan - grt default: 0 + deprecated: 1 + replacement: REPAIR_TIMING_ARGS = -hold_margin {value} SETUP_SLACK_MARGIN: description: | Specifies a time margin for the slack when fixing setup violations. @@ -850,6 +893,8 @@ SETUP_SLACK_MARGIN: - grt default: 0 tunable: 1 + deprecated: 1 + replacement: REPAIR_TIMING_ARGS = -setup_margin {value} SETUP_MOVE_SEQUENCE: description: > Passed as -sequence to repair_timing. This should be a string of move @@ -858,6 +903,8 @@ SETUP_MOVE_SEQUENCE: - cts - floorplan - grt + deprecated: 1 + replacement: REPAIR_TIMING_ARGS = -sequence {value} SETUP_REPAIR_PHASES: description: > Passed as -phases to repair_timing. This should be a string of setup @@ -869,6 +916,8 @@ SETUP_REPAIR_PHASES: - floorplan - grt - place + deprecated: 1 + replacement: REPAIR_TIMING_ARGS = -phases {value} SKIP_GATE_CLONING: description: > Do not use gate cloning transform to fix timing violations (default: use @@ -877,6 +926,9 @@ SKIP_GATE_CLONING: - cts - floorplan - grt + deprecated: 1 + replacement: + '1': REPAIR_TIMING_ARGS = -skip_gate_cloning SKIP_LAST_GASP: description: > Do not use last gasp optimization to fix timing violations (default: use @@ -885,6 +937,9 @@ SKIP_LAST_GASP: - cts - floorplan - grt + deprecated: 1 + replacement: + '1': REPAIR_TIMING_ARGS = -skip_last_gasp SKIP_BUFFER_REMOVAL: description: > Passed as -skip_buffer_removal to repair_timing. Do not remove buffers @@ -893,6 +948,9 @@ SKIP_BUFFER_REMOVAL: - cts - floorplan - grt + deprecated: 1 + replacement: + '1': REPAIR_TIMING_ARGS = -skip_buffer_removal SKIP_PIN_SWAP: description: > Do not use pin swapping as a transform to fix timing violations (default: @@ -901,6 +959,9 @@ SKIP_PIN_SWAP: - cts - floorplan - grt + deprecated: 1 + replacement: + '1': REPAIR_TIMING_ARGS = -skip_pin_swap SKIP_VT_SWAP: description: > Do not perform VT swap to improve QoR (default: do VT swap). @@ -908,6 +969,9 @@ SKIP_VT_SWAP: - cts - floorplan - grt + deprecated: 1 + replacement: + '1': REPAIR_TIMING_ARGS = -skip_vt_swap SKIP_CRIT_VT_SWAP: description: > Do not perform VT swap on critical cells to improve QoR (default: do critical @@ -919,6 +983,9 @@ SKIP_CRIT_VT_SWAP: - cts - floorplan - grt + deprecated: 1 + replacement: + '1': REPAIR_TIMING_ARGS = -skip_crit_vt_swap SKIP_CTS_REPAIR_TIMING: description: > Skipping CTS repair, which can take a long time, can be useful in @@ -926,6 +993,9 @@ SKIP_CTS_REPAIR_TIMING: stages: - cts default: 0 + deprecated: 1 + replacement: + '1': REPAIR_TIMING_ARGS = cts:off SKIP_FLOORPLAN_REPAIR_TIMING: description: > Skipping floorplan repair which sometimes does too much optimization @@ -933,6 +1003,9 @@ SKIP_FLOORPLAN_REPAIR_TIMING: stages: - floorplan default: 0 + deprecated: 1 + replacement: + '1': REPAIR_TIMING_ARGS = floorplan:off ENABLE_PLACE_REPAIR_TIMING: description: > Run repair_timing during the placement resize stage using placement @@ -941,12 +1014,18 @@ ENABLE_PLACE_REPAIR_TIMING: stages: - place default: 0 + deprecated: 1 + replacement: + '1': REPAIR_TIMING_ARGS = place:on SKIP_REPAIR_TIE_FANOUT: description: > Skip repair_tie_fanout at floorplan step. stages: - floorplan default: 0 + deprecated: 1 + replacement: + '1': REPAIR_TIE_FANOUT_ARGS = off MIN_ROUTING_LAYER: description: | The lowest metal layer name to be used in routing. @@ -985,8 +1064,13 @@ VIA_IN_PIN_MAX_LAYER: - grt - route DETAILED_ROUTE_ARGS: - description: | - Add additional arguments for debugging purposes during detail route. + description: > + Edits to the arguments the flow passes to `detailed_route`, in the grammar of + docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, + `on`/`off`, each optionally scoped `stage:` or `stage.call:`. + Until it is removed, a value that is a plain command line, with + no `~`, `on`, `off` or scope, replaces the flow's arguments, as + it always has. stages: - route DISABLE_VIA_GEN: @@ -994,22 +1078,31 @@ DISABLE_VIA_GEN: Passed as -disable_via_gen to detailed_route. stages: - route + deprecated: 1 + replacement: + '1': DETAILED_ROUTE_ARGS = -disable_via_gen DETAILED_ROUTE_END_ITERATION: description: > Maximum number of iterations. default: 64 stages: - route + deprecated: 1 + replacement: DETAILED_ROUTE_ARGS = -droute_end_iter {value} OR_K: description: > Passed as -or_k to detailed routing. stages: - route + deprecated: 1 + replacement: DETAILED_ROUTE_ARGS = -or_k {value} OR_SEED: description: > Passed as -or_seed to detailed routing. stages: - route + deprecated: 1 + replacement: DETAILED_ROUTE_ARGS = -or_seed {value} RCX_RULES: description: | RC Extraction rules file path. @@ -1201,11 +1294,15 @@ CTS_BUF_DISTANCE: - cts tunable: 1 type: float + deprecated: 1 + replacement: CLOCK_TREE_SYNTHESIS_ARGS = -distance_between_buffers {value} CTS_BUF_LIST: description: | List of cells used to construct the clock tree. Overrides buffer inference. stages: - cts + deprecated: 1 + replacement: CLOCK_TREE_SYNTHESIS_ARGS = -buf_list {value} CLUSTER_FLOPS: description: > Enable clustering of flip-flops into multi-bit flip-flops, if the platform @@ -1213,10 +1310,14 @@ CLUSTER_FLOPS: stages: - place default: 0 + deprecated: 1 + replacement: + '1': CLUSTER_FLOPS_ARGS = on CLUSTER_FLOPS_ARGS: description: > - Additional arguments passed to the cluster_flops command. - Only used when CLUSTER_FLOPS is set. + Edits to the arguments the flow passes to `cluster_flops`, in the grammar of + docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, + `on`/`off`, each optionally scoped `stage:` or `stage.call:`. stages: - place default: "" @@ -1227,6 +1328,8 @@ CTS_CLUSTER_DIAMETER: - cts tunable: 1 type: float + deprecated: 1 + replacement: CLOCK_TREE_SYNTHESIS_ARGS = -sink_clustering_max_diameter {value} CTS_CLUSTER_SIZE: description: > Maximum number of sinks per cluster. @@ -1234,11 +1337,15 @@ CTS_CLUSTER_SIZE: - cts tunable: 1 type: int + deprecated: 1 + replacement: CLOCK_TREE_SYNTHESIS_ARGS = -sink_clustering_size {value} CTS_LIB_NAME: description: | Name of the Liberty library to use in selecting the clock buffers. stages: - cts + deprecated: 1 + replacement: CLOCK_TREE_SYNTHESIS_ARGS = -library {value} POST_CTS_TCL: description: | Specifies a Tcl script with commands to run after CTS is completed. @@ -1416,9 +1523,11 @@ PRE_GLOBAL_ROUTE_TCL: - grt GLOBAL_ROUTE_ARGS: description: > - Replaces default arguments for global route. The -congestion_iterations - default is set by the flow (30 for FastRoute, 10 for CUGR); add - -congestion_iterations here to override it. + Edits to the arguments the flow passes to `global_route`, in the grammar of + docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, + `on`/`off`, each optionally scoped `stage:` or `stage.call:`. + Edits the first global_route; the incremental ones after repair + take -allow_congestion from it. stages: - grt default: -congestion_report_iter_step 5 -verbose @@ -1435,6 +1544,9 @@ ENABLE_RESISTANCE_AWARE: Passed as -resistance_aware to global_route. stages: - grt + deprecated: 1 + replacement: + '1': GLOBAL_ROUTE_ARGS = -resistance_aware MATCH_CELL_FOOTPRINT: description: > Enforce sizing operations to only swap cells that have the same layout @@ -1451,36 +1563,48 @@ RTLMP_MAX_LEVEL: default: 2 stages: - floorplan + deprecated: 1 + replacement: RTL_MACRO_PLACER_ARGS = -max_num_level {value} RTLMP_MAX_INST: description: > Maximum number of standard cells in a cluster. If unset, rtl_macro_placer will calculate a value based on the design attributes. stages: - floorplan + deprecated: 1 + replacement: RTL_MACRO_PLACER_ARGS = -max_num_inst {value} RTLMP_MIN_INST: description: > Minimum number of standard cells in a cluster. If unset, rtl_macro_placer will calculate a value based on the design attributes. stages: - floorplan + deprecated: 1 + replacement: RTL_MACRO_PLACER_ARGS = -min_num_inst {value} RTLMP_MAX_MACRO: description: > Maximum number of macros in a cluster. If unset, rtl_macro_placer will calculate a value based on the design attributes. stages: - floorplan + deprecated: 1 + replacement: RTL_MACRO_PLACER_ARGS = -max_num_macro {value} RTLMP_MIN_MACRO: description: > Minimum number of macros in a cluster. If unset, rtl_macro_placer will calculate a value based on the design attributes. stages: - floorplan + deprecated: 1 + replacement: RTL_MACRO_PLACER_ARGS = -min_num_macro {value} RTLMP_MIN_CHANNEL_SIZE: description: > Minimum channel width and height between macros (microns), given as one value for both, or two values "width height". stages: - floorplan + deprecated: 1 + replacement: RTL_MACRO_PLACER_ARGS = -min_channel_size {value} RTLMP_PIN_AWARE_CHANNELS: description: > Set to 1 to trim macro channels based on the pin locations of macros, @@ -1490,24 +1614,33 @@ RTLMP_PIN_AWARE_CHANNELS: default: 1 stages: - floorplan + deprecated: 1 + replacement: + '0': RTL_MACRO_PLACER_ARGS = ~-pin_aware_channels RTLMP_MIN_AR: description: > Specifies the minimum aspect ratio (height/width). default: 0.33 stages: - floorplan + deprecated: 1 + replacement: RTL_MACRO_PLACER_ARGS = -min_ar {value} RTLMP_AREA_WT: description: > Weight for the area of the current floorplan. default: 0.1 stages: - floorplan + deprecated: 1 + replacement: RTL_MACRO_PLACER_ARGS = -area_weight {value} RTLMP_WIRELENGTH_WT: description: > Weight for half-perimiter wirelength. default: 100.0 stages: - floorplan + deprecated: 1 + replacement: RTL_MACRO_PLACER_ARGS = -wirelength_weight {value} RTLMP_OUTLINE_WT: description: > Weight for violating the fixed outline constraint, meaning that all @@ -1515,6 +1648,8 @@ RTLMP_OUTLINE_WT: default: 100.00 stages: - floorplan + deprecated: 1 + replacement: RTL_MACRO_PLACER_ARGS = -outline_weight {value} RTLMP_BOUNDARY_WT: description: > Weight for the boundary or how far the hard macro clusters are from @@ -1522,6 +1657,8 @@ RTLMP_BOUNDARY_WT: default: 50.0 stages: - floorplan + deprecated: 1 + replacement: RTL_MACRO_PLACER_ARGS = -boundary_weight {value} RTLMP_NOTCH_WT: description: > Weight for the notch, or the existence of dead space that cannot be used @@ -1529,11 +1666,15 @@ RTLMP_NOTCH_WT: default: 50.0 stages: - floorplan + deprecated: 1 + replacement: RTL_MACRO_PLACER_ARGS = -notch_weight {value} RTLMP_RPT_DIR: description: > Path to the directory where reports are saved. stages: - floorplan + deprecated: 1 + replacement: RTL_MACRO_PLACER_ARGS = -report_directory {value} RTLMP_FENCE_LX: description: > Defines the lower left X coordinate for the global fence bounding box in @@ -1541,6 +1682,8 @@ RTLMP_FENCE_LX: default: 0.0 stages: - floorplan + deprecated: 1 + replacement: RTL_MACRO_PLACER_ARGS = -fence_lx {value} RTLMP_FENCE_LY: description: > Defines the lower left Y coordinate for the global fence bounding box in @@ -1548,6 +1691,8 @@ RTLMP_FENCE_LY: default: 0.0 stages: - floorplan + deprecated: 1 + replacement: RTL_MACRO_PLACER_ARGS = -fence_ly {value} RTLMP_FENCE_UX: description: > Defines the upper right X coordinate for the global fence bounding box in @@ -1555,6 +1700,8 @@ RTLMP_FENCE_UX: default: 0.0 stages: - floorplan + deprecated: 1 + replacement: RTL_MACRO_PLACER_ARGS = -fence_ux {value} RTLMP_FENCE_UY: description: > Defines the upper right Y coordinate for the global fence bounding box in @@ -1562,11 +1709,15 @@ RTLMP_FENCE_UY: default: 0.0 stages: - floorplan + deprecated: 1 + replacement: RTL_MACRO_PLACER_ARGS = -fence_uy {value} RTLMP_ARGS: description: > Overrides all other RTL macro placer arguments. stages: - floorplan + deprecated: 1 + replacement: RTL_MACRO_PLACER_ARGS, with only what differs from the flow's arguments RTLMP_KEEP_CLUSTERING: description: > Set to 1 to store the RTL macro placer's clustering hierarchy in the ODB as @@ -1574,6 +1725,9 @@ RTLMP_KEEP_CLUSTERING: default: 0 stages: - floorplan + deprecated: 1 + replacement: + '1': RTL_MACRO_PLACER_ARGS = -keep_clustering_data GDS_ALLOW_EMPTY: description: > Single regular expression of module names of macros that have no .gds file @@ -1614,12 +1768,18 @@ SKIP_ANTENNA_REPAIR_POST_DRT: Skips antenna repair post-detailed routing. stages: - route + deprecated: 1 + replacement: + '1': REPAIR_ANTENNAS_ARGS = route:off SKIP_ANTENNA_REPAIR: default: 0 description: > Skips antenna repair entirely. stages: - grt + deprecated: 1 + replacement: + '1': REPAIR_ANTENNAS_ARGS = grt:off SKIP_DETAILED_ROUTE: default: 0 description: > @@ -1641,6 +1801,8 @@ MAX_REPAIR_ANTENNAS_ITER_GRT: antennas will run. stages: - grt + deprecated: 1 + replacement: REPAIR_ANTENNAS_ARGS = grt:-iterations {value} OPENROAD_HIERARCHICAL: description: > Feature toggle to enable to run OpenROAD in hierarchical mode, @@ -1757,3 +1919,99 @@ VCD_FILE: Specifies the Value Change Dump (VCD) file containing pin activities and duty cycles for use in power calculation. type: string +BALANCE_ROW_USAGE_ARGS: + description: > + Edits to the arguments the flow passes to `balance_row_usage`, in the grammar + of + docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, + `on`/`off`, each optionally scoped `stage:` or `stage.call:`. + stages: + - place +CLOCK_TREE_SYNTHESIS_ARGS: + description: > + Edits to the arguments the flow passes to `clock_tree_synthesis`, in the grammar + of + docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, + `on`/`off`, each optionally scoped `stage:` or `stage.call:`. + stages: + - cts +DETAILED_PLACEMENT_ARGS: + description: > + Edits to the arguments the flow passes to `detailed_placement`, in the grammar + of + docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, + `on`/`off`, each optionally scoped `stage:` or `stage.call:`. + stages: + - place + - cts + - grt +IMPROVE_PLACEMENT_ARGS: + description: > + Edits to the arguments the flow passes to `improve_placement`, in the grammar + of + docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, + `on`/`off`, each optionally scoped `stage:` or `stage.call:`. + stages: + - place +REPAIR_ANTENNAS_ARGS: + description: > + Edits to the arguments the flow passes to `repair_antennas`, in the grammar of + docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, + `on`/`off`, each optionally scoped `stage:` or `stage.call:`. + stages: + - grt + - route +REPAIR_DESIGN_ARGS: + description: > + Edits to the arguments the flow passes to `repair_design`, in the grammar of + docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, + `on`/`off`, each optionally scoped `stage:` or `stage.call:`. + stages: + - place + - grt +REPAIR_TIE_FANOUT_ARGS: + description: > + Edits to the arguments the flow passes to `repair_tie_fanout`, in the grammar + of + docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, + `on`/`off`, each optionally scoped `stage:` or `stage.call:`. + stages: + - floorplan +REPAIR_TIMING_ARGS: + description: > + Edits to the arguments the flow passes to `repair_timing`, in the grammar of + docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, + `on`/`off`, each optionally scoped `stage:` or `stage.call:`. + stages: + - floorplan + - place + - cts + - grt +REPORT_METRICS_ARGS: + description: > + Edits to the arguments the flow passes to `report_metrics`, in the grammar of + docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, + `on`/`off`, each optionally scoped `stage:` or `stage.call:`. + stages: + - synth + - floorplan + - place + - cts + - grt + - route + - final +RTL_MACRO_PLACER_ARGS: + description: > + Edits to the arguments the flow passes to `rtl_macro_placer`, in the grammar of + docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, + `on`/`off`, each optionally scoped `stage:` or `stage.call:`. + stages: + - floorplan +PLATFORM_ARGS: + description: > + A platform's defaults for command arguments, in the grammar of + docs/user/CommandArguments.md, each edit starting with the command it + is for, as in `rtl_macro_placer:-halo_width 5`. They rank above the + flow's own arguments and below a design's _ARGS. + stages: + - All stages diff --git a/flow/test/test_args.py b/flow/test/test_args.py index d40415577c..5e0bd7640c 100644 --- a/flow/test/test_args.py +++ b/flow/test/test_args.py @@ -294,6 +294,39 @@ def test_platform_args_unknown_command(self): self.assertIn("'nope' is not a command", str(cm.exception)) +class VariablesYaml(unittest.TestCase): + """variables.json, generated from variables.yaml, agrees with the code.""" + + @classmethod + def setUpClass(cls): + import json + + with open(os.path.join(args.DIR, "variables.json")) as f: + cls.variables = json.load(f) + + def test_every_command_has_its_variable_and_stages(self): + for command, stages in G["COMMANDS"].items(): + meta = self.variables[G["args_variable"](command)] + self.assertEqual(sorted(meta["stages"]), sorted(stages), command) + + def test_every_replacement_parses(self): + names = {G["args_variable"](c) for c in G["COMMANDS"]} + for name, meta in self.variables.items(): + if not meta.get("deprecated") or "replacement" not in meta: + continue + replacement = meta["replacement"] + texts = ( + replacement.values() if isinstance(replacement, dict) else [replacement] + ) + for text in texts: + variable, _, value = text.partition(" = ") + variable = variable.split(",")[0] + self.assertIn(variable, names, name) + if value: + # A bare {value} is a whole command line: the old variable's. + parse(value.format(value="-x 1" if value == "{value}" else "1")) + + class StarlarkSubset(unittest.TestCase): """args_grammar.bzl stays in the subset of Python that is also Starlark. From 8237e16256071ef00f36b98b487b05b76a761182 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20Harboe?= Date: Fri, 30 Oct 2026 10:32:25 +0100 Subject: [PATCH 3/5] docs: Command Arguments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit How to change the arguments ORFS passes to an OpenROAD command: the grammar, the layers and how Make picks each one's value, use cases from a design, a platform, a flow variant, the command line and the shell, the name of every call, and the deprecated variables. Co-Authored-By: Claude Opus 5.5 Signed-off-by: Øyvind Harboe --- docs/toc.yml | 2 + docs/user/CommandArguments.md | 142 ++++++++++++++++++++++++++++++++++ docs/user/FlowVariables.md | 3 + 3 files changed, 147 insertions(+) create mode 100644 docs/user/CommandArguments.md diff --git a/docs/toc.yml b/docs/toc.yml index 3aa3ca7279..dcd79e4d82 100644 --- a/docs/toc.yml +++ b/docs/toc.yml @@ -21,6 +21,8 @@ entries: title: Adding New Designs to the ORFS - file: user/FlowVariables.md title: Flow Variables + - file: user/CommandArguments.md + title: Command Arguments - file: user/AutoMemories.md title: Generated Memory Macros (AUTO_MEMORIES) - file: user/LargeDesigns.md diff --git a/docs/user/CommandArguments.md b/docs/user/CommandArguments.md new file mode 100644 index 0000000000..1f99215ef6 --- /dev/null +++ b/docs/user/CommandArguments.md @@ -0,0 +1,142 @@ +# Command arguments + +ORFS runs OpenROAD commands such as `global_placement`, +`clock_tree_synthesis` and `detailed_route`. To change what one of them is +called with, set the variable named after the command, in upper case, with +`_ARGS` after it. It holds only what you want different, written with the +command's own options, as the command's help prints them: + +```make +export CLOCK_TREE_SYNTHESIS_ARGS = -sink_clustering_size 30 ~-repair_clock_nets +export REPAIR_TIMING_ARGS = -setup_margin 0.05 grt:-setup_margin 0.1 floorplan:off +export REPORT_METRICS_ARGS = off cts:on +``` + +The flow's own arguments stay, except where you change them. The log shows +the command as it ran and, for each edit that changed it, the call, the edit +and the variable it came from: + +``` +[cts.main] clock_tree_synthesis: -sink_clustering_size 30 (CLOCK_TREE_SYNTHESIS_ARGS) +[cts.main] clock_tree_synthesis: ~-repair_clock_nets (CLOCK_TREE_SYNTHESIS_ARGS) +clock_tree_synthesis -sink_clustering_enable -sink_clustering_size 30 +``` + +## The grammar + +| Written | Meaning | +|---|---| +| `-option value` | set the value | +| `-flag` | add the flag | +| `~-option` | delete the option, and its value if it has one, where it is passed | +| `on` / `off` | run the command / don't run it | +| `stage:` in front of any of these | only in that stage: `synth`, `floorplan`, `place`, `cts`, `grt`, `route` or `final` | +| `stage.call:` in front | only at that call (see the table below) | +| `{a b}` or `"a b"` | a value with spaces in it, as in Tcl | + +Within one variable, a call edit beats a stage edit, a stage edit beats an +unscoped one, and later beats earlier. A syntax error stops the flow before +the stage runs, with a message that says where it is. + +## Layers + +| From highest to lowest | Where | +|---|---| +| `_ARGS` | a design's `config.mk`, a `FLOW_VARIANT` block, the command line or the shell environment | +| deprecated variables | `CTS_CLUSTER_SIZE` and the others, wherever they are set | +| `PLATFORM_ARGS` | a platform's `config.mk` | +| the flow | ORFS's own arguments, written in the stage scripts | +| nothing passed | OpenROAD's own default | + +For each option, the highest layer that mentions it decides. Make picks each +variable's value first, as for every ORFS variable +([Flow Variables](./FlowVariables.md)): `make REPAIR_TIMING_ARGS=...` on the +command line replaces the design's whole value of that variable, and the +layers below it stay. + +A platform sets its defaults in one variable, each edit starting with the +command it is for: + +```make +export PLATFORM_ARGS = rtl_macro_placer:-min_channel_size {20 20} \ + detailed_route:-disable_via_gen +``` + +## Use cases + +A design changes clock tree synthesis: + +```make +export CLOCK_TREE_SYNTHESIS_ARGS = -sink_clustering_size 30 +``` + +A flow variant skips repair before CTS and reports only at CTS: + +```make +ifeq ($(FLOW_VARIANT),fast) + export REPAIR_TIMING_ARGS = floorplan:off place:off + export REPORT_METRICS_ARGS = off cts:on +endif +``` + +A one-off experiment from the command line, quoted for the shell: + +```sh +make DESIGN_CONFIG=designs/asap7/gcd/config.mk REPAIR_TIMING_ARGS='grt:-setup_margin 0.1' +``` + +The same from the shell environment, used when the design doesn't set the +variable with `=`: + +```sh +export REPORT_METRICS_ARGS='off cts:on' +make DESIGN_CONFIG=designs/asap7/gcd/config.mk +``` + +## Commands and calls + +| Command | Calls | +|---|---| +| `balance_row_usage` | `place.main` | +| `buffer_ports` | `place.main` | +| `clock_tree_synthesis` | `cts.main` | +| `cluster_flops` | `place.main` | +| `detailed_placement` | `place.main`, `cts.main`, `cts.repair_timing`, `grt.repair_design`, `grt.repair_timing` | +| `detailed_route` | `route.main` | +| `global_placement` | `place.skip_io`, `place.main` | +| `global_route` | `grt.main`, the first route; the incremental routes after repair take `-allow_congestion` from it | +| `improve_placement` | `place.main` | +| `place_pins` | `place.main` | +| `repair_antennas` | `grt.main`, `route.main` | +| `repair_design` | `place.main`, `grt.main` | +| `repair_tie_fanout` | `floorplan.tielo`, `floorplan.tiehi` | +| `repair_timing` | `floorplan.main`, `place.main`, `cts.main`, `grt.main`, `grt.wns`, `grt.recover_power` | +| `report_metrics` | named after the report: `cts.cts_final` for the report "cts final", `grt.global_route_post_repair_timing`, ... | +| `rtl_macro_placer` | `floorplan.main` | + +`report_metrics` takes only `on` and `off`. + +## Deprecated variables + +The variables that passed one option to one command, or switched one step on +or off, are deprecated. Each still works, ranks between `PLATFORM_ARGS` and +`_ARGS`, and warns with the line that replaces it: + +``` +[WARNING] CTS_CLUSTER_SIZE=30 is deprecated: write CLOCK_TREE_SYNTHESIS_ARGS = -sink_clustering_size 30 +``` + +[Flow Variables](./FlowVariables.md) lists each one with its replacement. +`CTS_ARGS` and `RTLMP_ARGS` still replace the flow's arguments, and +`DETAILED_ROUTE_ARGS` does too while it holds a plain command line, with no +`~`, `on`, `off` or scope; when that command line differs from the same text +read as edits, the log says which `~-option` deletions keep it. + +## Implementation + +`flow/scripts/args_grammar.bzl` is the grammar, written in the subset of +Python that is also Starlark, so a Bazel build can `load()` it: to stop at +analysis on a syntax error, and to give each stage only its own edits. +`flow/scripts/args.py` runs it for the stage scripts, which call it through +`command_args` and `command_runs` in `flow/scripts/util.tcl`. +`flow/test/test_args.py` tests both. diff --git a/docs/user/FlowVariables.md b/docs/user/FlowVariables.md index 388c1f7d6a..55a679098c 100644 --- a/docs/user/FlowVariables.md +++ b/docs/user/FlowVariables.md @@ -18,6 +18,9 @@ The actual value used is determined by the priority rules set by `make`: 3. **Environment Variables**: Variables exported in the shell environment are used if not overridden by the command line. 4. **Default Values**: Variables defined with the `?=` operator in the `Makefile` are used only if the variable is not already defined elsewhere. +To change the arguments ORFS passes to an OpenROAD command, see +[Command Arguments](./CommandArguments.md). + ## Effects of variables The variables for ORFS are not fully independent and can interact in complex ways. Small changes to a combination of variables can have large consequences, such as on macro placement, which can lead to vastly different quality of results. From 0cd34848509162335fb54121bfceb7bf520c1927 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20Harboe?= Date: Wed, 11 Nov 2026 07:15:47 +0100 Subject: [PATCH 4/5] flow: leave variables.json alone MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit variables.json is unused and #4805 deletes it; editing it here only causes conflicts. variables.yaml carries the change. Signed-off-by: Øyvind Harboe --- flow/scripts/variables.json | 265 +----------------------------------- 1 file changed, 7 insertions(+), 258 deletions(-) diff --git a/flow/scripts/variables.json b/flow/scripts/variables.json index 7e1cfd1b6b..8bebf70c48 100644 --- a/flow/scripts/variables.json +++ b/flow/scripts/variables.json @@ -88,17 +88,7 @@ }, "BALANCE_ROWS": { "default": 0, - "deprecated": 1, "description": "Balance rows during placement.\n", - "replacement": { - "1": "BALANCE_ROW_USAGE_ARGS = on" - }, - "stages": [ - "place" - ] - }, - "BALANCE_ROW_USAGE_ARGS": { - "description": "Edits to the arguments the flow passes to `balance_row_usage`, in the grammar of docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, `on`/`off`, each optionally scoped `stage:` or `stage.call:`.\n", "stages": [ "place" ] @@ -110,7 +100,7 @@ ] }, "BUFFER_PORTS_ARGS": { - "description": "Edits to the arguments the flow passes to `buffer_ports`, in the grammar of docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, `on`/`off`, each optionally scoped `stage:` or `stage.call:`.\n", + "description": "Specify arguments to the buffer_ports call during placement. Only used if DONT_BUFFER_PORTS=0.\n", "stages": [ "place" ] @@ -122,9 +112,7 @@ ] }, "CAP_MARGIN": { - "deprecated": 1, "description": "Specifies a capacitance margin when fixing max capacitance violations. This option allows you to overfix.\n", - "replacement": "REPAIR_DESIGN_ARGS = -cap_margin {value}", "tunable": 1 }, "CDL_FILE": { @@ -164,26 +152,16 @@ "synth" ] }, - "CLOCK_TREE_SYNTHESIS_ARGS": { - "description": "Edits to the arguments the flow passes to `clock_tree_synthesis`, in the grammar of docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, `on`/`off`, each optionally scoped `stage:` or `stage.call:`.\n", - "stages": [ - "cts" - ] - }, "CLUSTER_FLOPS": { "default": 0, - "deprecated": 1, "description": "Enable clustering of flip-flops into multi-bit flip-flops, if the platform PDK includes multi-bit flip-flops\n", - "replacement": { - "1": "CLUSTER_FLOPS_ARGS = on" - }, "stages": [ "place" ] }, "CLUSTER_FLOPS_ARGS": { "default": "", - "description": "Edits to the arguments the flow passes to `cluster_flops`, in the grammar of docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, `on`/`off`, each optionally scoped `stage:` or `stage.call:`.\n", + "description": "Additional arguments passed to the cluster_flops command. Only used when CLUSTER_FLOPS is set.\n", "stages": [ "place" ] @@ -231,17 +209,13 @@ ] }, "CTS_ARGS": { - "deprecated": 1, "description": "Override `clock_tree_synthesis` arguments.\n", - "replacement": "CLOCK_TREE_SYNTHESIS_ARGS, with only what differs from the flow's arguments", "stages": [ "cts" ] }, "CTS_BUF_DISTANCE": { - "deprecated": 1, "description": "Distance (in microns) between buffers.\n", - "replacement": "CLOCK_TREE_SYNTHESIS_ARGS = -distance_between_buffers {value}", "stages": [ "cts" ], @@ -249,17 +223,13 @@ "type": "float" }, "CTS_BUF_LIST": { - "deprecated": 1, "description": "List of cells used to construct the clock tree. Overrides buffer inference.\n", - "replacement": "CLOCK_TREE_SYNTHESIS_ARGS = -buf_list {value}", "stages": [ "cts" ] }, "CTS_CLUSTER_DIAMETER": { - "deprecated": 1, "description": "Maximum diameter (in microns) of sink cluster.\n", - "replacement": "CLOCK_TREE_SYNTHESIS_ARGS = -sink_clustering_max_diameter {value}", "stages": [ "cts" ], @@ -267,9 +237,7 @@ "type": "float" }, "CTS_CLUSTER_SIZE": { - "deprecated": 1, "description": "Maximum number of sinks per cluster.\n", - "replacement": "CLOCK_TREE_SYNTHESIS_ARGS = -sink_clustering_size {value}", "stages": [ "cts" ], @@ -277,9 +245,7 @@ "type": "int" }, "CTS_LIB_NAME": { - "deprecated": 1, "description": "Name of the Liberty library to use in selecting the clock buffers.\n", - "replacement": "CLOCK_TREE_SYNTHESIS_ARGS = -library {value}", "stages": [ "cts" ] @@ -300,43 +266,27 @@ }, "DETAILED_METRICS": { "default": 0, - "deprecated": 1, "description": "If set, then calls report_metrics prior to repair operations in the CTS and global route stages\n", - "replacement": { - "1": "REPORT_METRICS_ARGS = cts:on grt:on" - }, "stages": [ "cts", "grt" ] }, - "DETAILED_PLACEMENT_ARGS": { - "description": "Edits to the arguments the flow passes to `detailed_placement`, in the grammar of docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, `on`/`off`, each optionally scoped `stage:` or `stage.call:`.\n", - "stages": [ - "place", - "cts", - "grt" - ] - }, "DETAILED_ROUTE_ARGS": { - "description": "Edits to the arguments the flow passes to `detailed_route`, in the grammar of docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, `on`/`off`, each optionally scoped `stage:` or `stage.call:`. Until it is removed, a value that is a plain command line, with no `~`, `on`, `off` or scope, replaces the flow's arguments, as it always has.\n", + "description": "Add additional arguments for debugging purposes during detail route.\n", "stages": [ "route" ] }, "DETAILED_ROUTE_END_ITERATION": { "default": 64, - "deprecated": 1, "description": "Maximum number of iterations.\n", - "replacement": "DETAILED_ROUTE_ARGS = -droute_end_iter {value}", "stages": [ "route" ] }, "DETAIL_PLACEMENT_ARGS": { - "deprecated": 1, "description": "Specify arguments to every detailed_placement call: the one in placement and the re-legalizations after clock tree synthesis, after repair in CTS and after the repairs in global route. A legalizer chosen here (-use_diamond_legalizer, -max_displacement) is therefore the one every stage uses.\n", - "replacement": "DETAILED_PLACEMENT_ARGS = {value}", "stages": [ "place", "cts", @@ -363,22 +313,14 @@ "tunable": 1 }, "DISABLE_VIA_GEN": { - "deprecated": 1, "description": "Passed as -disable_via_gen to detailed_route.\n", - "replacement": { - "1": "DETAILED_ROUTE_ARGS = -disable_via_gen" - }, "stages": [ "route" ] }, "DONT_BUFFER_PORTS": { "default": 0, - "deprecated": 1, "description": "Do not buffer input/output ports during floorplanning.\n", - "replacement": { - "1": "BUFFER_PORTS_ARGS = off" - }, "stages": [ "place" ] @@ -388,9 +330,7 @@ }, "DPO_MAX_DISPLACEMENT": { "default": "5 1", - "deprecated": 1, "description": "Specifies how far an instance can be moved when optimizing.\n", - "replacement": "IMPROVE_PLACEMENT_ARGS = -max_displacement {value}", "stages": [ "place" ] @@ -403,32 +343,20 @@ }, "ENABLE_DPO": { "default": 1, - "deprecated": 1, "description": "Enable detail placement with improve_placement feature.\n", - "replacement": { - "0": "IMPROVE_PLACEMENT_ARGS = off" - }, "stages": [ "place" ] }, "ENABLE_PLACE_REPAIR_TIMING": { "default": 0, - "deprecated": 1, "description": "Run repair_timing during the placement resize stage using placement parasitics. Disabled by default; pre-CTS setup/hold repair is skipped unless this is set to 1.\n", - "replacement": { - "1": "REPAIR_TIMING_ARGS = place:on" - }, "stages": [ "place" ] }, "ENABLE_RESISTANCE_AWARE": { - "deprecated": 1, "description": "Passed as -resistance_aware to global_route.\n", - "replacement": { - "1": "GLOBAL_ROUTE_ARGS = -resistance_aware" - }, "stages": [ "grt" ] @@ -484,14 +412,14 @@ ] }, "GLOBAL_PLACEMENT_ARGS": { - "description": "Edits to the arguments the flow passes to `global_placement`, in the grammar of docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, `on`/`off`, each optionally scoped `stage:` or `stage.call:`.\n", + "description": "Use additional tuning parameters during global placement other than default args defined in global_place.tcl.\n", "stages": [ "place" ] }, "GLOBAL_ROUTE_ARGS": { "default": "-congestion_report_iter_step 5 -verbose", - "description": "Edits to the arguments the flow passes to `global_route`, in the grammar of docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, `on`/`off`, each optionally scoped `stage:` or `stage.call:`. Edits the first global_route; the incremental ones after repair take -allow_congestion from it.\n", + "description": "Replaces default arguments for global route. The -congestion_iterations default is set by the flow (30 for FastRoute, 10 for CUGR); add -congestion_iterations here to override it.\n", "stages": [ "grt" ] @@ -523,20 +451,14 @@ ] }, "GPL_RANDOM_SEED": { - "deprecated": 1, "description": "Specifies a random seed for global placement. Useful for perturbation studies.\n", - "replacement": "GLOBAL_PLACEMENT_ARGS = -random_seed {value}", "stages": [ "place" ] }, "GPL_ROUTABILITY_DRIVEN": { "default": 1, - "deprecated": 1, "description": "Specifies whether the placer should use routability driven placement.\n", - "replacement": { - "0": "GLOBAL_PLACEMENT_ARGS = ~-routability_driven" - }, "stages": [ "place" ] @@ -562,21 +484,13 @@ }, "HOLD_SLACK_MARGIN": { "default": 0, - "deprecated": 1, "description": "Specifies a time margin for the slack when fixing hold violations. This option allows you to overfix or underfix (negative value, terminate retiming before 0 or positive slack). floorplan.tcl uses min of HOLD_SLACK_MARGIN and 0 (default hold slack margin). This avoids overrepair in floorplan for hold by default, but allows skipping hold repair using a negative HOLD_SLACK_MARGIN. Exiting timing repair early is useful in exploration where the .sdc has a fixed clock period at the design's target clock period and where HOLD/SETUP_SLACK_MARGIN is used to avoid overrepair (extremely long running times) when exploring different parameter settings. When an ideal clock is used, that is before CTS, a clock insertion delay of 0 is used in timing paths. This creates a mismatch between macros that have a .lib file from after CTS, when the clock is propagated. To mitigate this, OpenSTA will use subtract the clock insertion delay of macros when calculating timing with ideal clock. Provided that min_clock_tree_path and max_clock_tree_path are in the .lib file, which is the case for macros built with OpenROAD. This is less accurate than if OpenROAD had created a placeholder clock tree for timing estimation purposes prior to CTS. There will inevitably be inaccuracies in the timing calculation prior to CTS. Use a slack margin that is low enough, even negative, to avoid overrepair. Inaccuracies in the timing prior to CTS can also lead to underrepair, but there no obvious and simple way to avoid underrapir in these cases. Overrepair can lead to excessive runtimes in repair or too much buffering being added, which can present itself as congestion of hold cells or buffer cells. Another use of SETUP/HOLD_SLACK_MARGIN is design parameter exploration when trying to find the minimum clock period for a design. The SDC_FILE for a design can be quite complicated and instead of modifying the clock period in the SDC_FILE, which can be non-trivial, the clock period can be fixed at the target frequency and the SETUP/HOLD_SLACK_MARGIN can be swept to find a plausible current minimum clock period.\n", - "replacement": "REPAIR_TIMING_ARGS = -hold_margin {value}", "stages": [ "cts", "floorplan", "grt" ] }, - "IMPROVE_PLACEMENT_ARGS": { - "description": "Edits to the arguments the flow passes to `improve_placement`, in the grammar of docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, `on`/`off`, each optionally scoped `stage:` or `stage.call:`.\n", - "stages": [ - "place" - ] - }, "INFER_CLKGATES": { "default": 0, "description": "Enables Yosys clock gate inference. By default, it uses the Liberty cell definitions to determine clock gating cell. The selection can be overridden using the POS_CLKGATE_AND_PORTS and/or NEG_CLKGATE_AND_PORTS variables.\n", @@ -707,9 +621,7 @@ }, "MAX_REPAIR_ANTENNAS_ITER_GRT": { "default": 5, - "deprecated": 1, "description": "Defines the maximum number of iterations post global routing repair antennas will run.\n", - "replacement": "REPAIR_ANTENNAS_ARGS = grt:-iterations {value}", "stages": [ "grt" ] @@ -780,17 +692,13 @@ ] }, "OR_K": { - "deprecated": 1, "description": "Passed as -or_k to detailed routing.\n", - "replacement": "DETAILED_ROUTE_ARGS = -or_k {value}", "stages": [ "route" ] }, "OR_SEED": { - "deprecated": 1, "description": "Passed as -or_seed to detailed routing.\n", - "replacement": "DETAILED_ROUTE_ARGS = -or_seed {value}", "stages": [ "route" ] @@ -818,7 +726,7 @@ "type": "float" }, "PLACE_PINS_ARGS": { - "description": "Edits to the arguments the flow passes to `place_pins`, in the grammar of docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, `on`/`off`, each optionally scoped `stage:` or `stage.call:`.\n", + "description": "Arguments to place_pins\n", "stages": [ "place" ] @@ -835,12 +743,6 @@ "description": "Specifies process design kit or technology node to be used.\n", "required": true }, - "PLATFORM_ARGS": { - "description": "A platform's defaults for command arguments, in the grammar of docs/user/CommandArguments.md, each edit starting with the command it is for, as in `rtl_macro_placer:-halo_width 5`. They rank above the flow's own arguments and below a design's _ARGS.\n", - "stages": [ - "All stages" - ] - }, "PLATFORM_TCL": { "description": "Specifies a Tcl script with commands to run before loading design.\n" }, @@ -1066,39 +968,8 @@ "description": "String patterns directly passed to write_verilog -remove_cells <> for lec checks.\n", "type": "string" }, - "REPAIR_ANTENNAS_ARGS": { - "description": "Edits to the arguments the flow passes to `repair_antennas`, in the grammar of docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, `on`/`off`, each optionally scoped `stage:` or `stage.call:`.\n", - "stages": [ - "grt", - "route" - ] - }, - "REPAIR_DESIGN_ARGS": { - "description": "Edits to the arguments the flow passes to `repair_design`, in the grammar of docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, `on`/`off`, each optionally scoped `stage:` or `stage.call:`.\n", - "stages": [ - "place", - "grt" - ] - }, "REPAIR_PDN_VIA_LAYER": { - "deprecated": 1, - "description": "Remove power grid vias which generate DRC violations after detailed routing.\n", - "replacement": "DETAILED_ROUTE_ARGS = -repair_pdn_vias {value}" - }, - "REPAIR_TIE_FANOUT_ARGS": { - "description": "Edits to the arguments the flow passes to `repair_tie_fanout`, in the grammar of docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, `on`/`off`, each optionally scoped `stage:` or `stage.call:`.\n", - "stages": [ - "floorplan" - ] - }, - "REPAIR_TIMING_ARGS": { - "description": "Edits to the arguments the flow passes to `repair_timing`, in the grammar of docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, `on`/`off`, each optionally scoped `stage:` or `stage.call:`.\n", - "stages": [ - "floorplan", - "place", - "cts", - "grt" - ] + "description": "Remove power grid vias which generate DRC violations after detailed routing.\n" }, "REPORT_CLOCK_SKEW": { "default": 1, @@ -1123,18 +994,6 @@ "final" ] }, - "REPORT_METRICS_ARGS": { - "description": "Edits to the arguments the flow passes to `report_metrics`, in the grammar of docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, `on`/`off`, each optionally scoped `stage:` or `stage.call:`.\n", - "stages": [ - "synth", - "floorplan", - "place", - "cts", - "grt", - "route", - "final" - ] - }, "ROUTING_LAYER_ADJUSTMENT": { "default": 0.5, "description": "Adjusts routing layer capacities to manage congestion and improve detailed routing. High values ease detailed routing but risk excessive detours and long global routing times, while low values reduce global routing failure but can complicate detailed routing. The global routing running time normally reduces dramatically (entirely design specific, but going from hours to minutes has been observed) when the value is low (such as 0.10). Sometimes, global routing will succeed with lower values and fail with higher values. Exploring results with different values can help shed light on the problem. Start with a too low value, such as 0.10, and bisect to value that works by doing multiple global routing runs. As a last resort, `make global_route_issue` and using the tools/OpenROAD/etc/whittle.py can be useful to debug global routing errors. If there is something specific that is impossible to route, such as a clock line over a macro, global routing will terminate with DRC errors routes that could have been routed were it not for the specific impossible routes. whittle.py should weed out the possible routes and leave a minimal failing case that pinpoints the problem.\n", @@ -1148,183 +1007,133 @@ }, "RTLMP_AREA_WT": { "default": 0.1, - "deprecated": 1, "description": "Weight for the area of the current floorplan.\n", - "replacement": "RTL_MACRO_PLACER_ARGS = -area_weight {value}", "stages": [ "floorplan" ] }, "RTLMP_ARGS": { - "deprecated": 1, "description": "Overrides all other RTL macro placer arguments.\n", - "replacement": "RTL_MACRO_PLACER_ARGS, with only what differs from the flow's arguments", "stages": [ "floorplan" ] }, "RTLMP_BOUNDARY_WT": { "default": 50.0, - "deprecated": 1, "description": "Weight for the boundary or how far the hard macro clusters are from boundaries.\n", - "replacement": "RTL_MACRO_PLACER_ARGS = -boundary_weight {value}", "stages": [ "floorplan" ] }, "RTLMP_FENCE_LX": { "default": 0.0, - "deprecated": 1, "description": "Defines the lower left X coordinate for the global fence bounding box in microns.\n", - "replacement": "RTL_MACRO_PLACER_ARGS = -fence_lx {value}", "stages": [ "floorplan" ] }, "RTLMP_FENCE_LY": { "default": 0.0, - "deprecated": 1, "description": "Defines the lower left Y coordinate for the global fence bounding box in microns.\n", - "replacement": "RTL_MACRO_PLACER_ARGS = -fence_ly {value}", "stages": [ "floorplan" ] }, "RTLMP_FENCE_UX": { "default": 0.0, - "deprecated": 1, "description": "Defines the upper right X coordinate for the global fence bounding box in microns.\n", - "replacement": "RTL_MACRO_PLACER_ARGS = -fence_ux {value}", "stages": [ "floorplan" ] }, "RTLMP_FENCE_UY": { "default": 0.0, - "deprecated": 1, "description": "Defines the upper right Y coordinate for the global fence bounding box in microns.\n", - "replacement": "RTL_MACRO_PLACER_ARGS = -fence_uy {value}", "stages": [ "floorplan" ] }, "RTLMP_KEEP_CLUSTERING": { "default": 0, - "deprecated": 1, "description": "Set to 1 to store the RTL macro placer's clustering hierarchy in the ODB as nested dbGroups.\n", - "replacement": { - "1": "RTL_MACRO_PLACER_ARGS = -keep_clustering_data" - }, "stages": [ "floorplan" ] }, "RTLMP_MAX_INST": { - "deprecated": 1, "description": "Maximum number of standard cells in a cluster. If unset, rtl_macro_placer will calculate a value based on the design attributes.\n", - "replacement": "RTL_MACRO_PLACER_ARGS = -max_num_inst {value}", "stages": [ "floorplan" ] }, "RTLMP_MAX_LEVEL": { "default": 2, - "deprecated": 1, "description": "Maximum depth of the physical hierarchy tree.\n", - "replacement": "RTL_MACRO_PLACER_ARGS = -max_num_level {value}", "stages": [ "floorplan" ] }, "RTLMP_MAX_MACRO": { - "deprecated": 1, "description": "Maximum number of macros in a cluster. If unset, rtl_macro_placer will calculate a value based on the design attributes.\n", - "replacement": "RTL_MACRO_PLACER_ARGS = -max_num_macro {value}", "stages": [ "floorplan" ] }, "RTLMP_MIN_AR": { "default": 0.33, - "deprecated": 1, "description": "Specifies the minimum aspect ratio (height/width).\n", - "replacement": "RTL_MACRO_PLACER_ARGS = -min_ar {value}", "stages": [ "floorplan" ] }, "RTLMP_MIN_CHANNEL_SIZE": { - "deprecated": 1, "description": "Minimum channel width and height between macros (microns), given as one value for both, or two values \"width height\".\n", - "replacement": "RTL_MACRO_PLACER_ARGS = -min_channel_size {value}", "stages": [ "floorplan" ] }, "RTLMP_MIN_INST": { - "deprecated": 1, "description": "Minimum number of standard cells in a cluster. If unset, rtl_macro_placer will calculate a value based on the design attributes.\n", - "replacement": "RTL_MACRO_PLACER_ARGS = -min_num_inst {value}", "stages": [ "floorplan" ] }, "RTLMP_MIN_MACRO": { - "deprecated": 1, "description": "Minimum number of macros in a cluster. If unset, rtl_macro_placer will calculate a value based on the design attributes.\n", - "replacement": "RTL_MACRO_PLACER_ARGS = -min_num_macro {value}", "stages": [ "floorplan" ] }, "RTLMP_NOTCH_WT": { "default": 50.0, - "deprecated": 1, "description": "Weight for the notch, or the existence of dead space that cannot be used for placement and routing.\n", - "replacement": "RTL_MACRO_PLACER_ARGS = -notch_weight {value}", "stages": [ "floorplan" ] }, "RTLMP_OUTLINE_WT": { "default": 100.0, - "deprecated": 1, "description": "Weight for violating the fixed outline constraint, meaning that all clusters should be placed within the shape of their parent cluster.\n", - "replacement": "RTL_MACRO_PLACER_ARGS = -outline_weight {value}", "stages": [ "floorplan" ] }, "RTLMP_PIN_AWARE_CHANNELS": { "default": 1, - "deprecated": 1, "description": "Set to 1 to trim macro channels based on the pin locations of macros, instead of using full channels. Requires RTLMP_MIN_CHANNEL_SIZE to also be set. Defaults to 1 whenever RTLMP_MIN_CHANNEL_SIZE is set and this variable is not explicitly set to 0.\n", - "replacement": { - "0": "RTL_MACRO_PLACER_ARGS = ~-pin_aware_channels" - }, "stages": [ "floorplan" ] }, "RTLMP_RPT_DIR": { - "deprecated": 1, "description": "Path to the directory where reports are saved.\n", - "replacement": "RTL_MACRO_PLACER_ARGS = -report_directory {value}", "stages": [ "floorplan" ] }, "RTLMP_WIRELENGTH_WT": { "default": 100.0, - "deprecated": 1, "description": "Weight for half-perimiter wirelength.\n", - "replacement": "RTL_MACRO_PLACER_ARGS = -wirelength_weight {value}", - "stages": [ - "floorplan" - ] - }, - "RTL_MACRO_PLACER_ARGS": { - "description": "Edits to the arguments the flow passes to `rtl_macro_placer`, in the grammar of docs/user/CommandArguments.md: `-option value`, `-flag`, `~-option`, `on`/`off`, each optionally scoped `stage:` or `stage.call:`.\n", "stages": [ "floorplan" ] @@ -1362,9 +1171,7 @@ ] }, "SETUP_MOVE_SEQUENCE": { - "deprecated": 1, "description": "Passed as -sequence to repair_timing. This should be a string of move keywords separated by commas.\n", - "replacement": "REPAIR_TIMING_ARGS = -sequence {value}", "stages": [ "cts", "floorplan", @@ -1372,9 +1179,7 @@ ] }, "SETUP_REPAIR_PHASES": { - "deprecated": 1, "description": "Passed as -phases to repair_timing. This should be a string of setup repair phase names separated by spaces. Set to PARALLEL_EVAL to repair setup timing with the experimental parallel evaluation policy. When unset, repair_timing runs its default phases.\n", - "replacement": "REPAIR_TIMING_ARGS = -phases {value}", "stages": [ "cts", "floorplan", @@ -1384,9 +1189,7 @@ }, "SETUP_SLACK_MARGIN": { "default": 0, - "deprecated": 1, "description": "Specifies a time margin for the slack when fixing setup violations.\nThis option allows you to overfix or underfix(negative value, terminate\nretiming before 0 or positive slack).\nSee HOLD_SLACK_MARGIN for more details.\n", - "replacement": "REPAIR_TIMING_ARGS = -setup_margin {value}", "stages": [ "cts", "floorplan", @@ -1396,32 +1199,20 @@ }, "SKIP_ANTENNA_REPAIR": { "default": 0, - "deprecated": 1, "description": "Skips antenna repair entirely.\n", - "replacement": { - "1": "REPAIR_ANTENNAS_ARGS = grt:off" - }, "stages": [ "grt" ] }, "SKIP_ANTENNA_REPAIR_POST_DRT": { "default": 0, - "deprecated": 1, "description": "Skips antenna repair post-detailed routing.\n", - "replacement": { - "1": "REPAIR_ANTENNAS_ARGS = route:off" - }, "stages": [ "route" ] }, "SKIP_BUFFER_REMOVAL": { - "deprecated": 1, "description": "Passed as -skip_buffer_removal to repair_timing. Do not remove buffers as a transform to fix timing violations (default: allow buffer removal).\n", - "replacement": { - "1": "REPAIR_TIMING_ARGS = -skip_buffer_removal" - }, "stages": [ "cts", "floorplan", @@ -1429,11 +1220,7 @@ ] }, "SKIP_CRIT_VT_SWAP": { - "deprecated": 1, "description": "Do not perform VT swap on critical cells to improve QoR (default: do critical VT swap). This is an additional VT swap on critical cells that remain near the end of setup fixing. If SKIP_VT_SWAP is set to 1, this also disables critical cell VT swap.\n", - "replacement": { - "1": "REPAIR_TIMING_ARGS = -skip_crit_vt_swap" - }, "stages": [ "cts", "floorplan", @@ -1442,11 +1229,7 @@ }, "SKIP_CTS_REPAIR_TIMING": { "default": 0, - "deprecated": 1, "description": "Skipping CTS repair, which can take a long time, can be useful in architectural exploration or when getting CI up and running.\n", - "replacement": { - "1": "REPAIR_TIMING_ARGS = cts:off" - }, "stages": [ "cts" ] @@ -1462,21 +1245,13 @@ }, "SKIP_FLOORPLAN_REPAIR_TIMING": { "default": 0, - "deprecated": 1, "description": "Skipping floorplan repair which sometimes does too much optimization too early.\n", - "replacement": { - "1": "REPAIR_TIMING_ARGS = floorplan:off" - }, "stages": [ "floorplan" ] }, "SKIP_GATE_CLONING": { - "deprecated": 1, "description": "Do not use gate cloning transform to fix timing violations (default: use gate cloning).\n", - "replacement": { - "1": "REPAIR_TIMING_ARGS = -skip_gate_cloning" - }, "stages": [ "cts", "floorplan", @@ -1491,11 +1266,7 @@ ] }, "SKIP_LAST_GASP": { - "deprecated": 1, "description": "Do not use last gasp optimization to fix timing violations (default: use gate last gasp).\n", - "replacement": { - "1": "REPAIR_TIMING_ARGS = -skip_last_gasp" - }, "stages": [ "cts", "floorplan", @@ -1503,11 +1274,7 @@ ] }, "SKIP_PIN_SWAP": { - "deprecated": 1, "description": "Do not use pin swapping as a transform to fix timing violations (default: use pin swapping).\n", - "replacement": { - "1": "REPAIR_TIMING_ARGS = -skip_pin_swap" - }, "stages": [ "cts", "floorplan", @@ -1516,22 +1283,14 @@ }, "SKIP_REPAIR_TIE_FANOUT": { "default": 0, - "deprecated": 1, "description": "Skip repair_tie_fanout at floorplan step.\n", - "replacement": { - "1": "REPAIR_TIE_FANOUT_ARGS = off" - }, "stages": [ "floorplan" ] }, "SKIP_REPORT_METRICS": { "default": 0, - "deprecated": 1, "description": "If set to 1, then metrics, report_metrics does nothing. Useful to speed up builds.\n", - "replacement": { - "1": "REPORT_METRICS_ARGS = off" - }, "stages": [ "synth", "floorplan", @@ -1543,11 +1302,7 @@ ] }, "SKIP_VT_SWAP": { - "deprecated": 1, "description": "Do not perform VT swap to improve QoR (default: do VT swap).\n", - "replacement": { - "1": "REPAIR_TIMING_ARGS = -skip_vt_swap" - }, "stages": [ "cts", "floorplan", @@ -1555,9 +1310,7 @@ ] }, "SLEW_MARGIN": { - "deprecated": 1, "description": "Specifies a slew margin when fixing max slew violations. This option allows you to overfix.\n", - "replacement": "REPAIR_DESIGN_ARGS = -slew_margin {value}", "tunable": 1 }, "SWAP_ARITH_OPERATORS": { @@ -1781,18 +1534,14 @@ }, "TIE_SEPARATION": { "default": 0, - "deprecated": 1, "description": "Distance separating tie high/low instances from the load.\n", - "replacement": "REPAIR_TIE_FANOUT_ARGS = -separation {value}", "stages": [ "floorplan" ] }, "TNS_END_PERCENT": { "default": 100, - "deprecated": 1, "description": "Default TNS_END_PERCENT value for post CTS timing repair. Try fixing all violating endpoints by default (reduce to 5% for runtime). Specifies how many percent of violating paths to fix [0-100]. Worst path will always be fixed.\n", - "replacement": "REPAIR_TIMING_ARGS = -repair_tns {value}", "stages": [ "place", "cts", From 3a3e39b2e45d0b03ab29b1efc1f85516efba0de0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20Harboe?= Date: Thu, 12 Nov 2026 08:03:26 +0100 Subject: [PATCH 5/5] args.py: read variables.yaml, variables.json is gone MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit args.py looked up the variables' defaults and deprecations in variables.json, and test_args.py checked that file against the grammar. Master has deleted variables.json, and on this branch it no longer carried the new _ARGS entries, which is why testUtilScripts failed with KeyError: 'BALANCE_ROW_USAGE_ARGS'. Both now read variables.yaml through args.load_variables(), as defaults.py and non_stage_variables.py do, so the test checks the file the flow and the docs are generated from. Co-Authored-By: Claude Opus 5.5 Signed-off-by: Øyvind Harboe --- flow/scripts/args.py | 15 ++++++++++----- flow/test/test_args.py | 7 ++----- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/flow/scripts/args.py b/flow/scripts/args.py index 95c20bc95d..289546bd15 100644 --- a/flow/scripts/args.py +++ b/flow/scripts/args.py @@ -24,10 +24,11 @@ the first N words of FLOW. """ -import json import os import sys +import yaml + DIR = os.path.dirname(os.path.realpath(__file__)) @@ -183,11 +184,15 @@ def _counted(argv): return argv[1 : 1 + n], argv[1 + n :] +def load_variables(): + """variables.yaml, the metadata of every variable.""" + with open(os.path.join(DIR, "variables.yaml")) as f: + return yaml.safe_load(f) + + def main(argv, env): - with open(os.path.join(DIR, "variables.json")) as f: - variables = json.load(f) if argv[:1] == ["check"] and len(argv) == 2: - for w in check(env, argv[1], variables): + for w in check(env, argv[1], load_variables()): print("[WARNING] " + w, file=sys.stderr) return 0 if argv[:1] == ["resolve"] and len(argv) >= 6: @@ -197,7 +202,7 @@ def main(argv, env): deprecated, rest = _counted(rest) legacy = rest[0] if rest else None defaults = { - k: str(v["default"]) for k, v in variables.items() if "default" in v + k: str(v["default"]) for k, v in load_variables().items() if "default" in v } run, args, notes = resolve( env, command, stage, call, run == "1", flow, deprecated, legacy, defaults diff --git a/flow/test/test_args.py b/flow/test/test_args.py index 5e0bd7640c..85d4e3a9aa 100644 --- a/flow/test/test_args.py +++ b/flow/test/test_args.py @@ -295,14 +295,11 @@ def test_platform_args_unknown_command(self): class VariablesYaml(unittest.TestCase): - """variables.json, generated from variables.yaml, agrees with the code.""" + """variables.yaml agrees with the code.""" @classmethod def setUpClass(cls): - import json - - with open(os.path.join(args.DIR, "variables.json")) as f: - cls.variables = json.load(f) + cls.variables = args.load_variables() def test_every_command_has_its_variable_and_stages(self): for command, stages in G["COMMANDS"].items():