diff --git a/CMakeLists.txt b/CMakeLists.txt index 0d84e9b5..6a4c4a50 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -200,6 +200,7 @@ set(STA_SOURCE util/Debug.cc util/Error.cc util/Fuzzy.cc + util/Hash.cc util/Machine.cc util/MinMax.cc util/PatternMatch.cc diff --git a/doc/OpenSTA.odt b/doc/OpenSTA.odt index cb48d45f..80786bdd 100644 Binary files a/doc/OpenSTA.odt and b/doc/OpenSTA.odt differ diff --git a/liberty/EquivCells.cc b/liberty/EquivCells.cc index 43f9730c..f0ef2726 100644 --- a/liberty/EquivCells.cc +++ b/liberty/EquivCells.cc @@ -15,6 +15,7 @@ // along with this program. If not, see . #include "Machine.hh" +#include "Hash.hh" #include "PortDirection.hh" #include "Transition.hh" #include "MinMax.hh" @@ -40,8 +41,6 @@ static unsigned hashFuncExpr(const FuncExpr *expr); static unsigned hashPort(const LibertyPort *port); -static unsigned -hashString(const char *str); static float cellDriveResistance(const LibertyCell *cell) @@ -228,17 +227,6 @@ hashFuncExpr(const FuncExpr *expr) } } -static unsigned -hashString(const char *str) -{ - unsigned hash = 0; - size_t length = strlen(str); - for (size_t i = 0; i < length; i++) { - hash = str[i] + (hash << 2); - } - return hash; -} - bool equivCells(const LibertyCell *cell1, const LibertyCell *cell2) diff --git a/liberty/LibertyReader.cc b/liberty/LibertyReader.cc index 7ae3c6ae..289dd39e 100644 --- a/liberty/LibertyReader.cc +++ b/liberty/LibertyReader.cc @@ -172,6 +172,7 @@ LibertyReader::defineVisitors() defineAttrVisitor("voltage_unit", &LibertyReader::visitVoltageUnit); defineAttrVisitor("current_unit", &LibertyReader::visitCurrentUnit); defineAttrVisitor("leakage_power_unit", &LibertyReader::visitPowerUnit); + defineAttrVisitor("distance_unit", &LibertyReader::visitDistanceUnit); defineAttrVisitor("delay_model", &LibertyReader::visitDelayModel); defineAttrVisitor("bus_naming_style", &LibertyReader::visitBusStyle); defineAttrVisitor("voltage_map", &LibertyReader::visitVoltageMap); @@ -547,17 +548,20 @@ LibertyReader::beginLibrary(LibertyGroup *group) // 1v default volt_scale_ = 1; // Default is 1mA. - curr_scale_ = 1E-3F; + current_scale_ = 1E-3F; // Default is 1; power_scale_ = 1; // Default is fJ. setEnergyScale(); + // Default is 1 micron. + distance_scale_ = 1e-6; library_->units()->timeUnit()->setScale(time_scale_); library_->units()->capacitanceUnit()->setScale(cap_scale_); library_->units()->resistanceUnit()->setScale(res_scale_); library_->units()->voltageUnit()->setScale(volt_scale_); - library_->units()->currentUnit()->setScale(curr_scale_); + library_->units()->currentUnit()->setScale(current_scale_); + library_->units()->distanceUnit()->setScale(distance_scale_); library_->setDelayModelType(DelayModelType::cmos_linear); @@ -667,7 +671,7 @@ void LibertyReader::visitCurrentUnit(LibertyAttr *attr) { if (library_) - parseUnits(attr, "A", curr_scale_, library_->units()->currentUnit()); + parseUnits(attr, "A", current_scale_, library_->units()->currentUnit()); } void @@ -685,6 +689,13 @@ LibertyReader::visitPowerUnit(LibertyAttr *attr) parseUnits(attr, "W", power_scale_, library_->units()->powerUnit()); } +void +LibertyReader::visitDistanceUnit(LibertyAttr *attr) +{ + if (library_) + parseUnits(attr, "m", distance_scale_, library_->units()->distanceUnit()); +} + void LibertyReader::parseUnits(LibertyAttr *attr, const char *unit_suffix, diff --git a/liberty/LibertyReaderPvt.hh b/liberty/LibertyReaderPvt.hh index ecdc42ac..cb273492 100644 --- a/liberty/LibertyReaderPvt.hh +++ b/liberty/LibertyReaderPvt.hh @@ -81,6 +81,7 @@ public: virtual void visitVoltageUnit(LibertyAttr *attr); virtual void visitCurrentUnit(LibertyAttr *attr); virtual void visitPowerUnit(LibertyAttr *attr); + virtual void visitDistanceUnit(LibertyAttr *attr); virtual void parseUnits(LibertyAttr *attr, const char *suffix, float &scale_var, @@ -562,9 +563,10 @@ protected: float cap_scale_; float res_scale_; float volt_scale_; - float curr_scale_; + float current_scale_; float power_scale_; float energy_scale_; + float distance_scale_; bool have_resistance_unit_; private: diff --git a/tcl/Sdc.tcl b/tcl/Sdc.tcl index c9ac24c0..ad0312f6 100644 --- a/tcl/Sdc.tcl +++ b/tcl/Sdc.tcl @@ -191,22 +191,23 @@ proc check_path_divider { divider } { define_cmd_args "set_units" \ {[-capacitance cap_unit] [-resistance res_unit] [-time time_unit]\ - [-voltage voltage_unit] [-current current_unit] [-power power_unit]} + [-voltage voltage_unit] [-current current_unit] [-power power_unit]\ + [-distance distance_unit]} -# Note that this does NOT actually set the units. -# It merely checks that the library units are the same as the -# units in the set_units command. +# Note that the set_units command does NOT actually set the units. +# It merely checks that the current units are the same as the +# units in the set_units command. Blame SNPS for this brain damage. proc set_units { args } { parse_key_args "set_units" args \ - keys {-capacitance -resistance -time -voltage -current -power} flags {} - if { [llength $args] != 0 } { - cmd_usage_error "set_units" - } + keys {-capacitance -resistance -time -voltage -current -power -distance} \ + flags {} + check_argc_eq0 "set_units" $args check_unit "capacitance" -capacitance "f" keys check_unit "time" -time "s" keys check_unit "voltage" -voltage "v" keys check_unit "current" -current "A" keys check_unit "resistance" -resistance "ohm" keys + check_unit "distance" -distance "m" keys } proc check_unit { unit key unit_name key_var } { @@ -219,23 +220,8 @@ proc check_unit { unit key unit_name key_var } { set prefix [string index $value 0] set suffix [string range $value 1 end] if { [string equal -nocase $suffix $unit_name] } { - if { [string equal $prefix "M"] } { - check_unit_scale $unit 1E+6 - } elseif { [string equal $prefix "k"] } { - check_unit_scale $unit 1E+3 - } elseif { [string equal $prefix "m"] } { - check_unit_scale $unit 1E-3 - } elseif { [string equal $prefix "u"] } { - check_unit_scale $unit 1E-6 - } elseif { [string equal $prefix "n"] } { - check_unit_scale $unit 1E-9 - } elseif { [string equal $prefix "p"] } { - check_unit_scale $unit 1E-12 - } elseif { [string equal $prefix "f"] } { - check_unit_scale $unit 1E-15 - } else { - sta_error "unknown $unit prefix '$prefix'." - } + set scale [unit_prefix_scale $unit $prefix] + check_unit_scale $unit 1.0 $scale } else { sta_error "unknown unit $unit '$suffix'." } @@ -243,6 +229,26 @@ proc check_unit { unit key unit_name key_var } { } } +proc unit_prefix_scale { unit prefix } { + if { [string equal $prefix "M"] } { + return 1E+6 + } elseif { [string equal $prefix "k"] } { + return 1E+3 + } elseif { [string equal $prefix "m"] } { + return 1E-3 + } elseif { [string equal $prefix "u"] } { + return 1E-6 + } elseif { [string equal $prefix "n"] } { + return 1E-9 + } elseif { [string equal $prefix "p"] } { + return 1E-12 + } elseif { [string equal $prefix "f"] } { + return 1E-15 + } else { + sta_error "unknown $unit prefix '$prefix'." + } +} + proc check_unit_scale { unit scale } { set unit_scale [unit_scale $unit] if { ![fuzzy_equal $scale $unit_scale] } { @@ -250,6 +256,53 @@ proc check_unit_scale { unit scale } { } } +################################################################ + +define_cmd_args "set_cmd_units" \ + {[-capacitance cap_unit] [-resistance res_unit] [-time time_unit]\ + [-voltage voltage_unit] [-current current_unit] [-power power_unit]\ + [-distance distance_unit]} + +proc set_cmd_units { args } { + parse_key_args "set_cmd_units" args \ + keys {-capacitance -resistance -time -voltage -current -power \ + -distance -digits -suffix} \ + flags {} + + check_argc_eq0 "set_cmd_units" $args + set_unit_values "capacitance" -capacitance "f" keys + set_unit_values "time" -time "s" keys + set_unit_values "voltage" -voltage "v" keys + set_unit_values "current" -current "A" keys + set_unit_values "resistance" -resistance "ohm" keys + set_unit_values "distance" -distance "m" keys +} + +proc set_unit_values { unit key unit_name key_var } { + upvar 1 $key_var keys + if { [info exists keys($key)] } { + set value $keys($key) + if { [string equal -nocase $value $unit_name] } { + set_cmd_unit_scale $unit 1.0 + } else { + set prefix [string index $value 0] + set suffix [string range $value 1 end] + if { [string equal -nocase $suffix $unit_name] } { + set scale [unit_prefix_scale $unit $prefix] + set_cmd_unit_scale $unit $scale + } else { + sta_error "unknown $unit unit '$suffix'." + } + } + if [info exists keys(-digits)] { + set_cmd_unit_digits $unit $keys(-digits) + } + if [info exists keys(-suffix)] { + set_cmd_unit_suffix $unit $keys(-suffix) + } + } +} + ################################################################ # # Object Access Commands diff --git a/tcl/StaTcl.i b/tcl/StaTcl.i index 37085132..d4f9a29c 100644 --- a/tcl/StaTcl.i +++ b/tcl/StaTcl.i @@ -3808,6 +3808,8 @@ format_power(const char *value, return Sta::sta()->units()->powerUnit()->asString(value1, digits); } +//////////////////////////////////////////////////////////////// + // Unit converstion from sta unit to user interface and visa versa. double time_ui_sta(double value) @@ -3881,6 +3883,50 @@ power_sta_ui(double value) return value / Sta::sta()->units()->powerUnit()->scale(); } +double +distance_ui_sta(double value) +{ + return value * Sta::sta()->units()->distanceUnit()->scale(); +} + +double +distance_sta_ui(double value) +{ + return value / Sta::sta()->units()->distanceUnit()->scale(); +} + +//////////////////////////////////////////////////////////////// + +void +set_cmd_unit_scale(const char *unit_name, + float scale) +{ + Unit *unit = Sta::sta()->units()->find(unit_name); + if (unit) + unit->setScale(scale); +} + +void +set_cmd_unit_digits(const char *unit_name, + int digits) +{ + Unit *unit = Sta::sta()->units()->find(unit_name); + if (unit) + unit->setDigits(digits); +} + +void +set_cmd_unit_suffix(const char *unit_name, + const char *suffix) +{ + Unit *unit = Sta::sta()->units()->find(unit_name); + if (unit) { + unit->setSuffix(suffix); + } +} + +//////////////////////////////////////////////////////////////// + VertexIterator * vertex_iterator() { diff --git a/util/Hash.cc b/util/Hash.cc new file mode 100644 index 00000000..78b54013 --- /dev/null +++ b/util/Hash.cc @@ -0,0 +1,33 @@ +// OpenSTA, Static Timing Analyzer +// Copyright (c) 2019, 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 +#include "Machine.hh" +#include "Hash.hh" + +namespace sta { + +Hash +hashString(const char *str) +{ + unsigned hash = hash_init_value; + size_t length = strlen(str); + for (size_t i = 0; i < length; i++) + hash = ((hash << 5) + hash) ^ str[i]; + return hash; +} + +} // namespace diff --git a/util/Hash.hh b/util/Hash.hh index ffb13b7e..f1c702fd 100644 --- a/util/Hash.hh +++ b/util/Hash.hh @@ -48,5 +48,9 @@ nextMersenne(size_t n) return (n + 1) * 2 - 1; } +// Sadly necessary until c++ std::hash works for char *. +Hash +hashString(const char *str); + } // namespace #endif