From e987cc96b8c17b6f0b1c3f7155b5f4ad396c0f7e Mon Sep 17 00:00:00 2001 From: Akash Levy Date: Sun, 26 Apr 2026 16:20:54 -0700 Subject: [PATCH] set_disable_clock_gating_check --- include/sta/Sdc.hh | 10 ++++ include/sta/Sta.hh | 2 + sdc/Sdc.cc | 24 +++++++- sdc/Sdc.i | 12 ++++ sdc/WriteSdc.cc | 42 +++++++++++++ sdc/WriteSdcPvt.hh | 1 + search/Search.tcl | 64 ++++++++++++++++---- search/Sta.cc | 14 +++++ test/disable_clock_gating_check.lib | 92 +++++++++++++++++++++++++++++ test/disable_clock_gating_check.ok | 17 ++++++ test/disable_clock_gating_check.tcl | 47 +++++++++++++++ test/disable_clock_gating_check.v | 10 ++++ test/regression_vars.tcl | 1 + 13 files changed, 325 insertions(+), 11 deletions(-) create mode 100644 test/disable_clock_gating_check.lib create mode 100644 test/disable_clock_gating_check.ok create mode 100644 test/disable_clock_gating_check.tcl create mode 100644 test/disable_clock_gating_check.v diff --git a/include/sta/Sdc.hh b/include/sta/Sdc.hh index 6a69d6ac2..e4f32afec 100644 --- a/include/sta/Sdc.hh +++ b/include/sta/Sdc.hh @@ -705,10 +705,19 @@ public: const EdgeSet *disabledEdges() const { return &disabled_edges_; } 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); bool isDisableClockGatingCheck(const Instance *inst); + bool isDisableClockGatingCheck(const LibertyCell *cell); + 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); @@ -1360,6 +1369,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_; // Unique ID for exceptions. diff --git a/include/sta/Sta.hh b/include/sta/Sta.hh index ebd4ed275..4adc0ddc6 100644 --- a/include/sta/Sta.hh +++ b/include/sta/Sta.hh @@ -458,8 +458,10 @@ public: EdgeSeq disabledEdgesSorted(); void disableClockGatingCheck(Instance *inst); void disableClockGatingCheck(Pin *pin); + void disableClockGatingCheck(LibertyCell *cell); void removeDisableClockGatingCheck(Instance *inst); void removeDisableClockGatingCheck(Pin *pin); + void removeDisableClockGatingCheck(LibertyCell *cell); void setLogicValue(Pin *pin, LogicValue value); void setCaseAnalysis(Pin *pin, diff --git a/sdc/Sdc.cc b/sdc/Sdc.cc index 9ea6f00fd..e105e3c9c 100644 --- a/sdc/Sdc.cc +++ b/sdc/Sdc.cc @@ -213,6 +213,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(); @@ -3860,6 +3861,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) { @@ -3872,10 +3879,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) { - return disabled_clk_gating_checks_inst_.hasKey(inst); + if (disabled_clk_gating_checks_inst_.hasKey(inst)) + return true; + LibertyCell *cell = network_->libertyCell(inst); + return cell && disabled_clk_gating_checks_lib_cell_.hasKey(cell); } bool @@ -3884,6 +3900,12 @@ Sdc::isDisableClockGatingCheck(const Pin *pin) return disabled_clk_gating_checks_pin_.hasKey(pin); } +bool +Sdc::isDisableClockGatingCheck(const LibertyCell *cell) +{ + return disabled_clk_gating_checks_lib_cell_.hasKey(const_cast(cell)); +} + //////////////////////////////////////////////////////////////// void diff --git a/sdc/Sdc.i b/sdc/Sdc.i index 51d6894b6..a1ee1e5a4 100644 --- a/sdc/Sdc.i +++ b/sdc/Sdc.i @@ -644,6 +644,12 @@ disable_clock_gating_check_pin(Pin *pin) Sta::sta()->disableClockGatingCheck(pin); } +void +disable_clock_gating_check_lib_cell(LibertyCell *cell) +{ + Sta::sta()->disableClockGatingCheck(cell); +} + void unset_disable_clock_gating_check_inst(Instance *inst) { @@ -656,6 +662,12 @@ unset_disable_clock_gating_check_pin(Pin *pin) Sta::sta()->removeDisableClockGatingCheck(pin); } +void +unset_disable_clock_gating_check_lib_cell(LibertyCell *cell) +{ + Sta::sta()->removeDisableClockGatingCheck(cell); +} + EdgeSeq disabled_edges_sorted() { diff --git a/sdc/WriteSdc.cc b/sdc/WriteSdc.cc index 2edc79150..b3095d915 100644 --- a/sdc/WriteSdc.cc +++ b/sdc/WriteSdc.cc @@ -996,6 +996,7 @@ WriteSdc::writeDisables() const writeDisabledInstances(); writeDisabledPins(); writeDisabledEdges(); + writeDisabledClockGatingChecks(); } void @@ -1127,6 +1128,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 strcmp(a->name(), b->name()) < 0; + }); + for (const LibertyCell *cell : sorted) { + gzprintf(stream_, "set_disable_clock_gating_check "); + writeGetLibCell(cell); + gzprintf(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) { + gzprintf(stream_, "set_disable_clock_gating_check "); + writeGetInstance(inst); + gzprintf(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) { + gzprintf(stream_, "set_disable_clock_gating_check "); + writeGetPin(pin, false); + gzprintf(stream_, "\n"); + } + } +} + void WriteSdc::writeDisabledEdges() const { diff --git a/sdc/WriteSdcPvt.hh b/sdc/WriteSdcPvt.hh index 0ce672e2c..2518bea49 100644 --- a/sdc/WriteSdcPvt.hh +++ b/sdc/WriteSdcPvt.hh @@ -59,6 +59,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 85ebc60ff..1b8fd0bed 100644 --- a/search/Search.tcl +++ b/search/Search.tcl @@ -1158,17 +1158,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 } @@ -1176,17 +1186,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 } @@ -1194,6 +1214,30 @@ 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 +} + +proc set_disable_inferred_clock_gating_cmd { 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 +} + +proc unset_disable_inferred_clock_gating_cmd { objects } { + unset_disable_clock_gating_check_cmd $objects +} + +################################################################ + # max slew slack / limit proc max_slew_check_slack_limit {} { return [expr "[sta::max_slew_check_slack] / [sta::max_slew_check_limit]"] diff --git a/search/Sta.cc b/search/Sta.cc index cd93f297c..56995b8be 100644 --- a/search/Sta.cc +++ b/search/Sta.cc @@ -1824,6 +1824,13 @@ Sta::disableClockGatingCheck(Pin *pin) search_->endpointsInvalid(); } +void +Sta::disableClockGatingCheck(LibertyCell *cell) +{ + sdc_->disableClockGatingCheck(cell); + search_->endpointsInvalid(); +} + void Sta::removeDisableClockGatingCheck(Instance *inst) { @@ -1838,6 +1845,13 @@ Sta::removeDisableClockGatingCheck(Pin *pin) search_->endpointsInvalid(); } +void +Sta::removeDisableClockGatingCheck(LibertyCell *cell) +{ + 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 000000000..6e336f752 --- /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 000000000..e0ac2e4e5 --- /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 000000000..ba5139066 --- /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 000000000..24295cd0d --- /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 4b37ccb8c..a045fd66e 100644 --- a/test/regression_vars.tcl +++ b/test/regression_vars.tcl @@ -146,6 +146,7 @@ record_example_tests { record_public_tests { collections delay_calc_no_inv + disable_clock_gating_check disconnect_mcp_pin extras filter_expr_defined