diff --git a/CMakeLists.txt b/CMakeLists.txt index 159ee195..2d855785 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -92,6 +92,7 @@ set(STA_SOURCE liberty/LibertyExprPvt.hh liberty/LibertyParser.cc liberty/LibertyReader.cc + liberty/LibertyWriter.cc liberty/LinearModel.cc liberty/Sequential.cc liberty/TableModel.cc diff --git a/include/sta/LibertyWriter.hh b/include/sta/LibertyWriter.hh new file mode 100644 index 00000000..68c4390d --- /dev/null +++ b/include/sta/LibertyWriter.hh @@ -0,0 +1,29 @@ +// OpenSTA, Static Timing Analyzer +// Copyright (c) 2022, Parallax Software, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include "LibertyClass.hh" + +namespace sta { + +void +writeLiberty(LibertyLibrary *lib, + const char *filename); + +} // namespace + + diff --git a/liberty/LibertyWriter.cc b/liberty/LibertyWriter.cc new file mode 100644 index 00000000..2ddfe2ea --- /dev/null +++ b/liberty/LibertyWriter.cc @@ -0,0 +1,143 @@ +// OpenSTA, Static Timing Analyzer +// Copyright (c) 2022, Parallax Software, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "LibertyWriter.hh" + +#include + +#include "Liberty.hh" +#include "Units.hh" + +namespace sta { + +class LibertyWriter +{ +public: + LibertyWriter(LibertyLibrary *lib, + const char *filename, + FILE *stream); + void writeLibrary(); + +protected: + void writeHeader(); + void writeFooter(); + + LibertyLibrary *library_; + const char *filename_; + FILE *stream_; +}; + +void +writeLiberty(LibertyLibrary *lib, + const char *filename) +{ + FILE *stream = fopen(filename, "w"); + if (stream) { + LibertyWriter writer(lib, filename, stream); + writer.writeLibrary(); + fclose(stream); + } + else + throw FileNotWritable(filename); +} + +LibertyWriter::LibertyWriter(LibertyLibrary *lib, + const char *filename, + FILE *stream) : + library_(lib), + filename_(filename), + stream_(stream) +{ +} + +void +LibertyWriter::writeLibrary() +{ + writeHeader(); + writeFooter(); +} + +void +LibertyWriter::writeHeader() +{ + fprintf(stream_, "library (%s) {\n", library_->name()); + fprintf(stream_, " comment : \"\";\n"); + fprintf(stream_, " delay_model : table_lookup;\n"); + fprintf(stream_, " simulation : false;\n"); + Unit *cap_unit = library_->units()->capacitanceUnit(); + fprintf(stream_, " capacitive_load_unit (1,%s%s);\n", + cap_unit->scaleAbreviation(), + cap_unit->suffix()); + fprintf(stream_, " leakage_power_unit : 1pW;\n"); + Unit *current_unit = library_->units()->currentUnit(); + fprintf(stream_, " current_unit : \"1%s%s\";\n", + current_unit->scaleAbreviation(), + current_unit->suffix()); + Unit *res_unit = library_->units()->resistanceUnit(); + fprintf(stream_, " pulling_resistance_unit : \"1%s%s\";\n", + res_unit->scaleAbreviation(), + res_unit->suffix()); + Unit *time_unit = library_->units()->timeUnit(); + fprintf(stream_, " time_unit : \"1%s%s\";\n", + time_unit->scaleAbreviation(), + time_unit->suffix()); + Unit *volt_unit = library_->units()->voltageUnit(); + fprintf(stream_, " voltage_unit : \"1%s%s\";\n", + volt_unit->scaleAbreviation(), + volt_unit->suffix()); + fprintf(stream_, " library_features(report_delay_calculation);\n"); + fprintf(stream_, "\n"); + + fprintf(stream_, " input_threshold_pct_rise : %.0f;\n", + library_->inputThreshold(RiseFall::rise()) * 100); + fprintf(stream_, " input_threshold_pct_fall : %.0f;\n", + library_->inputThreshold(RiseFall::fall()) * 100); + fprintf(stream_, " output_threshold_pct_rise : %.0f;\n", + library_->inputThreshold(RiseFall::rise()) * 100); + fprintf(stream_, " output_threshold_pct_fall : %.0f;\n", + library_->inputThreshold(RiseFall::fall()) * 100); + fprintf(stream_, " slew_lower_threshold_pct_rise : %.0f;\n", + library_->slewLowerThreshold(RiseFall::rise()) * 100); + fprintf(stream_, " slew_lower_threshold_pct_fall : %.0f;\n", + library_->slewLowerThreshold(RiseFall::fall()) * 100); + fprintf(stream_, " slew_upper_threshold_pct_rise : %.0f;\n", + library_->slewUpperThreshold(RiseFall::rise()) * 100); + fprintf(stream_, " slew_upper_threshold_pct_fall : %.0f;\n", + library_->slewUpperThreshold(RiseFall::rise()) * 100); + fprintf(stream_, " slew_derate_from_library : %.1f;\n", + library_->slewDerateFromLibrary()); + fprintf(stream_, "\n"); + + fprintf(stream_, " default_max_fanout : 40;\n"); + fprintf(stream_, " default_max_transition : 2.00;\n"); + fprintf(stream_, " default_cell_leakage_power : 100;\n"); + fprintf(stream_, " default_fanout_load : 1.0;\n"); + fprintf(stream_, " default_inout_pin_cap : 0.0;\n"); + fprintf(stream_, " default_input_pin_cap : 0.0;\n"); + fprintf(stream_, " default_output_pin_cap : 0.0;\n"); + fprintf(stream_, "\n"); + fprintf(stream_, " nom_process : 1.0;\n"); + fprintf(stream_, " nom_temperature : 125.00;\n"); + fprintf(stream_, " nom_voltage : 1.62;\n"); +} + +void +LibertyWriter::writeFooter() +{ + fprintf(stream_, "}\n"); +} + +} // namespace diff --git a/tcl/Liberty.tcl b/tcl/Liberty.tcl index 6a806172..13c48076 100644 --- a/tcl/Liberty.tcl +++ b/tcl/Liberty.tcl @@ -33,5 +33,15 @@ proc_redirect read_liberty { read_liberty_cmd $filename $corner $min_max $infer_latches } +define_cmd_args "write_liberty" {library filename} + +proc write_liberty { args } { + check_argc_eq2 "write_liberty" $args + + set library [get_liberty_error "library" [lindex $args 0]] + set filename [file nativename [lindex $args 1]] + write_liberty_cmd $library $filename +} + # sta namespace end } diff --git a/tcl/StaTcl.i b/tcl/StaTcl.i index 706f82bd..0fac248b 100644 --- a/tcl/StaTcl.i +++ b/tcl/StaTcl.i @@ -50,6 +50,7 @@ #include "TimingRole.hh" #include "TimingArc.hh" #include "Liberty.hh" +#include "LibertyWriter.hh" #include "EquivCells.hh" #include "Wireload.hh" #include "PortDirection.hh" @@ -2174,6 +2175,13 @@ set_min_library_cmd(char *min_filename, return Sta::sta()->setMinLibrary(min_filename, max_filename); } +void +write_liberty_cmd(LibertyLibrary *library, + char *filename) +{ + writeLiberty(library, filename); +} + Library * find_library(const char *name) {