diff --git a/openlane/flows/classic.py b/openlane/flows/classic.py index 2da9d037a..aa8c504e0 100644 --- a/openlane/flows/classic.py +++ b/openlane/flows/classic.py @@ -54,6 +54,8 @@ class Classic(SequentialFlow): OpenROAD.CheckMacroInstances, OpenROAD.STAPrePNR, OpenROAD.Floorplan, + OpenROAD.RMP, + OpenROAD.STAPrePNR, 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..d46522920 --- /dev/null +++ b/openlane/scripts/openroad/restructure.tcl @@ -0,0 +1,30 @@ +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 +} +write_views +report_design_area_metrics diff --git a/openlane/steps/openroad.py b/openlane/steps/openroad.py index 0e44f8790..518211a09 100644 --- a/openlane/steps/openroad.py +++ b/openlane/steps/openroad.py @@ -1982,6 +1982,60 @@ 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="area", + ), + 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") + ) + + excluded_cells: Set[str] = set(self.config["EXTRA_EXCLUDED_CELLS"] or []) + excluded_cells.update( + process_list_file(self.config["SYNTH_EXCLUDED_CELL_FILE"]) + ) + excluded_cells.update(process_list_file(self.config["PNR_EXCLUDED_CELL_FILE"])) + trimmed_lib = self.toolbox.remove_cells_from_lib( + frozenset([str(lib) for lib in lib_list]), + excluded_cells=frozenset(excluded_cells), + ) + env["_RMP_LIB"] = TclStep.value_to_tcl(trimmed_lib) + env["_RMP_ABC_LOG"] = TclStep.value_to_tcl( + os.path.join(self.step_dir, "abc.log") + ) + return super().run(state_in, env=env, **kwargs) + + @Step.factory.register() class CTS(ResizerStep): """