diff --git a/include/sta/Sdc.hh b/include/sta/Sdc.hh index a93569fe..2d0e9742 100644 --- a/include/sta/Sdc.hh +++ b/include/sta/Sdc.hh @@ -704,10 +704,19 @@ public: void disableClockGatingCheck(Instance *inst); void disableClockGatingCheck(Pin *pin); + void disableClockGatingCheck(LibertyCell *cell); void removeDisableClockGatingCheck(Instance *inst); void removeDisableClockGatingCheck(Pin *pin); + void removeDisableClockGatingCheck(LibertyCell *cell); bool isDisableClockGatingCheck(const Pin *pin) const; bool isDisableClockGatingCheck(const Instance *inst) const; + bool isDisableClockGatingCheck(const LibertyCell *cell) const; + const InstanceSet *disabledClockGatingChecksInst() const + { return &disabled_clk_gating_checks_inst_; } + const PinSet *disabledClockGatingChecksPin() const + { return &disabled_clk_gating_checks_pin_; } + const LibertyCellSet *disabledClockGatingChecksLibCell() const + { return &disabled_clk_gating_checks_lib_cell_; } // set_LogicValue::zero, set_LogicValue::one, set_logic_dc void setLogicValue(const Pin *pin, LogicValue value); @@ -1369,6 +1378,7 @@ protected: DisabledInstancePortsMap disabled_inst_ports_; InstanceSet disabled_clk_gating_checks_inst_; PinSet disabled_clk_gating_checks_pin_; + LibertyCellSet disabled_clk_gating_checks_lib_cell_; ExceptionPathSet exceptions_; size_t exception_id_{0}; // Unique ID for exceptions. diff --git a/include/sta/Sta.hh b/include/sta/Sta.hh index bf482f55..0cd0bbf4 100644 --- a/include/sta/Sta.hh +++ b/include/sta/Sta.hh @@ -578,10 +578,14 @@ public: Sdc *sdc); void disableClockGatingCheck(Pin *pin, Sdc *sdc); + void disableClockGatingCheck(LibertyCell *cell, + Sdc *sdc); void removeDisableClockGatingCheck(Instance *inst, Sdc *sdc); void removeDisableClockGatingCheck(Pin *pin, Sdc *sdc); + void removeDisableClockGatingCheck(LibertyCell *cell, + Sdc *sdc); void setLogicValue(Pin *pin, LogicValue value, Mode *mode); diff --git a/sdc/Sdc.cc b/sdc/Sdc.cc index 9b30c470..1909a42f 100644 --- a/sdc/Sdc.cc +++ b/sdc/Sdc.cc @@ -217,6 +217,7 @@ Sdc::clear() disabled_clk_gating_checks_inst_.clear(); disabled_clk_gating_checks_pin_.clear(); + disabled_clk_gating_checks_lib_cell_.clear(); input_drive_map_.clear(); logic_value_map_.clear(); @@ -3720,6 +3721,12 @@ Sdc::disableClockGatingCheck(Pin *pin) disabled_clk_gating_checks_pin_.insert(pin); } +void +Sdc::disableClockGatingCheck(LibertyCell *cell) +{ + disabled_clk_gating_checks_lib_cell_.insert(cell); +} + void Sdc::removeDisableClockGatingCheck(Instance *inst) { @@ -3732,10 +3739,19 @@ Sdc::removeDisableClockGatingCheck(Pin *pin) disabled_clk_gating_checks_pin_.erase(pin); } +void +Sdc::removeDisableClockGatingCheck(LibertyCell *cell) +{ + disabled_clk_gating_checks_lib_cell_.erase(cell); +} + bool Sdc::isDisableClockGatingCheck(const Instance *inst) const { - return disabled_clk_gating_checks_inst_.contains(inst); + if (disabled_clk_gating_checks_inst_.contains(inst)) + return true; + LibertyCell *cell = network_->libertyCell(inst); + return cell && disabled_clk_gating_checks_lib_cell_.contains(cell); } bool @@ -3744,6 +3760,12 @@ Sdc::isDisableClockGatingCheck(const Pin *pin) const return disabled_clk_gating_checks_pin_.contains(pin); } +bool +Sdc::isDisableClockGatingCheck(const LibertyCell *cell) const +{ + return disabled_clk_gating_checks_lib_cell_.contains(const_cast(cell)); +} + //////////////////////////////////////////////////////////////// void diff --git a/sdc/Sdc.i b/sdc/Sdc.i index 3ac13d81..5d8da684 100644 --- a/sdc/Sdc.i +++ b/sdc/Sdc.i @@ -761,6 +761,14 @@ disable_clock_gating_check_pin(Pin *pin) sta->disableClockGatingCheck(pin, sdc); } +void +disable_clock_gating_check_lib_cell(LibertyCell *cell) +{ + Sta *sta = Sta::sta(); + Sdc *sdc = sta->cmdSdc(); + sta->disableClockGatingCheck(cell, sdc); +} + void unset_disable_clock_gating_check_inst(Instance *inst) { @@ -777,6 +785,14 @@ unset_disable_clock_gating_check_pin(Pin *pin) sta->removeDisableClockGatingCheck(pin, sdc); } +void +unset_disable_clock_gating_check_lib_cell(LibertyCell *cell) +{ + Sta *sta = Sta::sta(); + Sdc *sdc = sta->cmdSdc(); + sta->removeDisableClockGatingCheck(cell, sdc); +} + EdgeSeq disabled_edges_sorted() { diff --git a/sdc/WriteSdc.cc b/sdc/WriteSdc.cc index 1733a050..364ae3cc 100644 --- a/sdc/WriteSdc.cc +++ b/sdc/WriteSdc.cc @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -976,6 +977,7 @@ WriteSdc::writeDisables() const writeDisabledInstances(); writeDisabledPins(); writeDisabledEdges(); + writeDisabledClockGatingChecks(); } void @@ -1107,6 +1109,47 @@ WriteSdc::writeDisabledPins() const } } +void +WriteSdc::writeDisabledClockGatingChecks() const +{ + const LibertyCellSet *lib_cells = sdc_->disabledClockGatingChecksLibCell(); + if (!lib_cells->empty()) { + LibertyCellSeq sorted; + for (LibertyCell *cell : *lib_cells) + sorted.push_back(cell); + std::sort(sorted.begin(), sorted.end(), + [] (const LibertyCell *a, const LibertyCell *b) { + return a->name() < b->name(); + }); + for (const LibertyCell *cell : sorted) { + sta::print(stream_, "set_disable_clock_gating_check "); + writeGetLibCell(cell); + sta::print(stream_, "\n"); + } + } + const InstanceSet *insts = sdc_->disabledClockGatingChecksInst(); + if (!insts->empty()) { + InstanceSeq sorted_insts; + for (const Instance *inst : *insts) + sorted_insts.push_back(inst); + sort(sorted_insts, InstancePathNameLess(sdc_network_)); + for (const Instance *inst : sorted_insts) { + sta::print(stream_, "set_disable_clock_gating_check "); + writeGetInstance(inst); + sta::print(stream_, "\n"); + } + } + const PinSet *pins_set = sdc_->disabledClockGatingChecksPin(); + if (!pins_set->empty()) { + PinSeq sorted_pins = sortByPathName(pins_set, sdc_network_); + for (const Pin *pin : sorted_pins) { + sta::print(stream_, "set_disable_clock_gating_check "); + writeGetPin(pin, false); + sta::print(stream_, "\n"); + } + } +} + void WriteSdc::writeDisabledEdges() const { diff --git a/sdc/WriteSdcPvt.hh b/sdc/WriteSdcPvt.hh index b7bc9338..7f257597 100644 --- a/sdc/WriteSdcPvt.hh +++ b/sdc/WriteSdcPvt.hh @@ -62,6 +62,7 @@ public: void writeDisabledInstances() const; void writeDisabledPins() const; void writeDisabledEdges() const; + void writeDisabledClockGatingChecks() const; void writeDisabledEdge(Edge *edge) const; void findMatchingEdges(Edge *edge, EdgeSet &matches) const; diff --git a/search/Search.tcl b/search/Search.tcl index a57b109b..19a45865 100644 --- a/search/Search.tcl +++ b/search/Search.tcl @@ -978,17 +978,27 @@ proc_redirect report_clock_min_period { ################################################################ -define_cmd_args "set_disable_inferred_clock_gating" { objects } +define_cmd_args "set_disable_clock_gating_check" { objects } -proc set_disable_inferred_clock_gating { objects } { - set_disable_inferred_clock_gating_cmd $objects +proc set_disable_clock_gating_check { objects } { + set_disable_clock_gating_check_cmd $objects } -proc set_disable_inferred_clock_gating_cmd { objects } { - parse_inst_port_pin_arg $objects insts pins +proc set_disable_clock_gating_check_cmd { objects } { + set libcells {} + set insts {} + set ports {} + set pins {} + get_object_args $objects {} libcells {} {} insts ports pins {} {} {} + foreach lc $libcells { + disable_clock_gating_check_lib_cell $lc + } foreach inst $insts { disable_clock_gating_check_inst $inst } + foreach port $ports { + disable_clock_gating_check_pin [get_port_pin $port] + } foreach pin $pins { disable_clock_gating_check_pin $pin } @@ -996,17 +1006,27 @@ proc set_disable_inferred_clock_gating_cmd { objects } { ################################################################ -define_cmd_args "unset_disable_inferred_clock_gating" { objects } +define_cmd_args "unset_disable_clock_gating_check" { objects } -proc unset_disable_inferred_clock_gating { objects } { - unset_disable_inferred_clock_gating_cmd $objects +proc unset_disable_clock_gating_check { objects } { + unset_disable_clock_gating_check_cmd $objects } -proc unset_disable_inferred_clock_gating_cmd { objects } { - parse_inst_port_pin_arg $objects insts pins +proc unset_disable_clock_gating_check_cmd { objects } { + set libcells {} + set insts {} + set ports {} + set pins {} + get_object_args $objects {} libcells {} {} insts ports pins {} {} {} + foreach lc $libcells { + unset_disable_clock_gating_check_lib_cell $lc + } foreach inst $insts { unset_disable_clock_gating_check_inst $inst } + foreach port $ports { + unset_disable_clock_gating_check_pin [get_port_pin $port] + } foreach pin $pins { unset_disable_clock_gating_check_pin $pin } @@ -1014,6 +1034,22 @@ proc unset_disable_inferred_clock_gating_cmd { objects } { ################################################################ +define_cmd_args "set_disable_inferred_clock_gating" { objects } + +proc set_disable_inferred_clock_gating { objects } { + set_disable_clock_gating_check_cmd $objects +} + +################################################################ + +define_cmd_args "unset_disable_inferred_clock_gating" { objects } + +proc unset_disable_inferred_clock_gating { objects } { + unset_disable_clock_gating_check_cmd $objects +} + +################################################################ + # max slew slack / limit proc max_slew_check_slack_limit {} { return [expr "[max_slew_check_slack] / [max_slew_check_limit]"] diff --git a/search/Sta.cc b/search/Sta.cc index 843061df..75de7236 100644 --- a/search/Sta.cc +++ b/search/Sta.cc @@ -1868,6 +1868,14 @@ Sta::disableClockGatingCheck(Pin *pin, search_->endpointsInvalid(); } +void +Sta::disableClockGatingCheck(LibertyCell *cell, + Sdc *sdc) +{ + sdc->disableClockGatingCheck(cell); + search_->endpointsInvalid(); +} + void Sta::removeDisableClockGatingCheck(Instance *inst, Sdc *sdc) @@ -1884,6 +1892,14 @@ Sta::removeDisableClockGatingCheck(Pin *pin, search_->endpointsInvalid(); } +void +Sta::removeDisableClockGatingCheck(LibertyCell *cell, + Sdc *sdc) +{ + sdc->removeDisableClockGatingCheck(cell); + search_->endpointsInvalid(); +} + void Sta::setLogicValue(Pin *pin, LogicValue value, diff --git a/test/disable_clock_gating_check.lib b/test/disable_clock_gating_check.lib new file mode 100644 index 00000000..6e336f75 --- /dev/null +++ b/test/disable_clock_gating_check.lib @@ -0,0 +1,92 @@ +library (disable_clock_gating_check) { + delay_model : "table_lookup"; + time_unit : "1ns"; + voltage_unit : "1v"; + capacitive_load_unit (1,pF); + current_unit : "1mA"; + pulling_resistance_unit : "1kohm"; + leakage_power_unit : "1pW"; + input_threshold_pct_rise : 50; + input_threshold_pct_fall : 50; + output_threshold_pct_rise : 50; + output_threshold_pct_fall : 50; + slew_lower_threshold_pct_rise : 30; + slew_lower_threshold_pct_fall : 30; + slew_upper_threshold_pct_rise : 70; + slew_upper_threshold_pct_fall : 70; + slew_derate_from_library : 1.0; + nom_process : 1.0; + nom_temperature : 25.0; + nom_voltage : 1.0; + + cell (DFF) { + area : 10.0; + ff (IQ, IQN) { + next_state : "D"; + clocked_on : "CK"; + } + pin (D) { + direction : input; + capacitance : 0.001; + timing () { + related_pin : "CK"; + timing_type : setup_rising; + rise_constraint (scalar) { values ("0.1"); } + fall_constraint (scalar) { values ("0.1"); } + } + timing () { + related_pin : "CK"; + timing_type : hold_rising; + rise_constraint (scalar) { values ("0.05"); } + fall_constraint (scalar) { values ("0.05"); } + } + } + pin (CK) { + direction : input; + capacitance : 0.001; + clock : true; + } + pin (Q) { + direction : output; + function : "IQ"; + timing () { + related_pin : "CK"; + timing_type : rising_edge; + cell_rise (scalar) { values ("0.2"); } + cell_fall (scalar) { values ("0.2"); } + rise_transition (scalar) { values ("0.1"); } + fall_transition (scalar) { values ("0.1"); } + } + } + } + + cell (AND2) { + area : 4.0; + pin (A) { + direction : input; + capacitance : 0.001; + } + pin (B) { + direction : input; + capacitance : 0.001; + } + pin (Z) { + direction : output; + function : "(A * B)"; + timing () { + related_pin : "A"; + cell_rise (scalar) { values ("0.05"); } + cell_fall (scalar) { values ("0.05"); } + rise_transition (scalar) { values ("0.02"); } + fall_transition (scalar) { values ("0.02"); } + } + timing () { + related_pin : "B"; + cell_rise (scalar) { values ("0.05"); } + cell_fall (scalar) { values ("0.05"); } + rise_transition (scalar) { values ("0.02"); } + fall_transition (scalar) { values ("0.02"); } + } + } + } +} diff --git a/test/disable_clock_gating_check.ok b/test/disable_clock_gating_check.ok new file mode 100644 index 00000000..e0ac2e4e --- /dev/null +++ b/test/disable_clock_gating_check.ok @@ -0,0 +1,17 @@ +-- libcell -- +ok +-- inst -- +ok +-- pin -- +ok +-- port -- +ok +-- mixed -- +ok +-- back-compat alias -- +ok +-- write_sdc -- +set_disable_clock_gating_check [get_lib_cells {disable_clock_gating_check/AND2}] +set_disable_clock_gating_check [get_cells {cg}] +set_disable_clock_gating_check [get_pins {cg/B}] +ok diff --git a/test/disable_clock_gating_check.tcl b/test/disable_clock_gating_check.tcl new file mode 100644 index 00000000..ba513906 --- /dev/null +++ b/test/disable_clock_gating_check.tcl @@ -0,0 +1,47 @@ +read_liberty disable_clock_gating_check.lib +read_verilog disable_clock_gating_check.v +link_design top +create_clock -name clk -period 1.0 [get_ports clk] +set_input_delay -clock clk 0 [get_ports {en d}] + +puts "-- libcell --" +set_disable_clock_gating_check [get_lib_cells AND2] +unset_disable_clock_gating_check [get_lib_cells AND2] +puts "ok" + +puts "-- inst --" +set_disable_clock_gating_check [get_cells cg] +unset_disable_clock_gating_check [get_cells cg] +puts "ok" + +puts "-- pin --" +set_disable_clock_gating_check [get_pins cg/B] +unset_disable_clock_gating_check [get_pins cg/B] +puts "ok" + +puts "-- port --" +set_disable_clock_gating_check [get_ports en] +unset_disable_clock_gating_check [get_ports en] +puts "ok" + +puts "-- mixed --" +set_disable_clock_gating_check [list [get_lib_cells AND2] [get_cells cg] [get_pins cg/B]] +unset_disable_clock_gating_check [list [get_lib_cells AND2] [get_cells cg] [get_pins cg/B]] +puts "ok" + +puts "-- back-compat alias --" +set_disable_inferred_clock_gating [get_cells cg] +unset_disable_inferred_clock_gating [get_cells cg] +puts "ok" + +puts "-- write_sdc --" +set_disable_clock_gating_check [list [get_lib_cells AND2] [get_cells cg] [get_pins cg/B]] +write_sdc results/disable_clock_gating_check.sdc +set fp [open results/disable_clock_gating_check.sdc r] +foreach line [split [read $fp] "\n"] { + if { [string match "*disable_clock_gating_check*" $line] } { + puts $line + } +} +close $fp +puts "ok" diff --git a/test/disable_clock_gating_check.v b/test/disable_clock_gating_check.v new file mode 100644 index 00000000..24295cd0 --- /dev/null +++ b/test/disable_clock_gating_check.v @@ -0,0 +1,10 @@ +module top (clk, en, d, q); + input clk; + input en; + input d; + output q; + wire gclk; + + AND2 cg (.A(clk), .B(en), .Z(gclk)); + DFF ff (.CK(gclk), .D(d), .Q(q)); +endmodule diff --git a/test/regression_vars.tcl b/test/regression_vars.tcl index fcb2c291..2fc44761 100644 --- a/test/regression_vars.tcl +++ b/test/regression_vars.tcl @@ -141,6 +141,7 @@ record_example_tests { } record_public_tests { + disable_clock_gating_check disconnect_mcp_pin get_filter get_is_buffer