diff --git a/openlane/flows/classic.py b/openlane/flows/classic.py index 2da9d037a..81e112d07 100644 --- a/openlane/flows/classic.py +++ b/openlane/flows/classic.py @@ -54,6 +54,7 @@ class Classic(SequentialFlow): OpenROAD.CheckMacroInstances, OpenROAD.STAPrePNR, OpenROAD.Floorplan, + OpenROAD.RMP, Odb.CheckMacroAntennaProperties, Odb.SetPowerConnections, Odb.ManualMacroPlacement, diff --git a/openlane/scripts/openroad/restructure.tcl b/openlane/scripts/openroad/restructure.tcl new file mode 100644 index 000000000..fec792893 --- /dev/null +++ b/openlane/scripts/openroad/restructure.tcl @@ -0,0 +1,28 @@ +source $::env(SCRIPTS_DIR)/openroad/common/io.tcl + +read_current_odb + +if { $::env(RMP_TARGET) == "timing" } { + repair_design + repair_timing +} +set arg_list [list] +lappend arg_list -tiehi_port $::env(SYNTH_TIEHI_CELL) +lappend arg_list -tielo_port $::env(SYNTH_TIELO_CELL) +lappend arg_list -work_dir $::env(STEP_DIR) +lappend arg_list -abc_logfile $::env(_RMP_ABC_LOG) +lappend arg_list -liberty_file $::env(_RMP_LIB) +lappend arg_list -target $::env(RMP_TARGET) +if { [info exists ::env(RMP_DEPTH_THRESHOLD)] } { + lappend arg_list -depth_threshold $::env(RMP_DEPTH_THRESHOLD) +} +if { [info exists ::env(RMP_SLACK_THRESHOLD)] } { + lappend arg_list -slack_threshold $::env(RMP_SLACK_THRESHOLD) +} +restructure {*}$arg_list +remove_buffers +if { $::env(RMP_TARGET) == "timing" } { + repair_design + repair_timing + remove_buffers +} diff --git a/openlane/steps/openroad.py b/openlane/steps/openroad.py index 0e44f8790..a6eabb282 100644 --- a/openlane/steps/openroad.py +++ b/openlane/steps/openroad.py @@ -1982,6 +1982,51 @@ def run( return super().run(state_in, env=env, **kwargs) +@Step.factory.register() +class RMP(OpenROADStep): + id = "OpenROAD.RMP" + name = "Restructure RMP" + + config_vars = OpenROADStep.config_vars + [ + Variable( + "RMP_CORNER", + Optional[str], + description="IPVT corner to use during restructure. If unspecified, the value for `DEFAULT_CORNER` from the PDK will be used.", + ), + Variable( + "RMP_TARGET", + Literal["timing", "area"], + description="In area mode, the focus is area reduction, and timing may degrade. In delay mode, delay is likely reduced, but the area may increase", + default="timing", + ), + Variable( + "RMP_SLACK_THRESHOLD", + Optional[Decimal], + description="Specifies a (setup) timing slack value below which timing paths need to be analyzed for restructuring", + ), + Variable( + "RMP_DEPTH_THRESHOLD", + Optional[int], + description="Specifies the path depth above which a timing path would be considered for restructuring", + ), + ] + + def get_script_path(self): + return os.path.join(get_script_dir(), "openroad", "restructure.tcl") + + def run(self, state_in: State, **kwargs) -> Tuple[ViewsUpdate, MetricsUpdate]: + kwargs, env = self.extract_env(kwargs) + lib_list = self.toolbox.filter_views( + self.config, self.config["LIB"], timing_corner=self.config.get("RMP_CORNER") + ) + env["_RMP_LIB"] = TclStep.value_to_tcl(lib_list) + env["_RMP_ABC_LOG"] = TclStep.value_to_tcl( + os.path.join(self.step_dir, "abc.log") + ) + mkdirp(env["_RMP_WORK_DIR"]) + return super().run(state_in, env=env, **kwargs) + + @Step.factory.register() class CTS(ResizerStep): """