diff --git a/dcalc/GraphDelayCalc.cc b/dcalc/GraphDelayCalc.cc index 5b7af80b..b2d43242 100644 --- a/dcalc/GraphDelayCalc.cc +++ b/dcalc/GraphDelayCalc.cc @@ -47,6 +47,7 @@ #include "Sdc.hh" #include "Scene.hh" #include "SearchPred.hh" +#include "search/Sim.hh" #include "Stats.hh" #include "TimingArc.hh" #include "TimingRole.hh" @@ -88,8 +89,10 @@ DcalcPred::searchFrom(const Vertex *from_vertex, const Pin *from_pin = from_vertex->pin(); const Sdc *sdc = mode->sdc(); const Network *network = sta_->network(); + const Sim *sim = mode->sim(); Net *net = network->net(from_pin); return !(sdc->isDisabledConstraint(from_pin) + || sim->isConstant(from_vertex) || (net && (network->isPower(net) || network->isGround(net)))); } diff --git a/dcalc/test/CMakeLists.txt b/dcalc/test/CMakeLists.txt index 6caa2a23..b572e07c 100644 --- a/dcalc/test/CMakeLists.txt +++ b/dcalc/test/CMakeLists.txt @@ -1,5 +1,6 @@ sta_module_tests("dcalc" TESTS + case_analysis_leak prima_report ) diff --git a/dcalc/test/dcalc_case_analysis_leak.ok b/dcalc/test/dcalc_case_analysis_leak.ok new file mode 100644 index 00000000..2cc2edc9 --- /dev/null +++ b/dcalc/test/dcalc_case_analysis_leak.ok @@ -0,0 +1,10 @@ + +load on constant net cn (ff) arrival at z (ps) +0 158.79 +50 158.79 +200 158.79 +500 158.79 +1000 158.79 + +arrival spread across the sweep: 0.00 ps (expected 0.00) + diff --git a/dcalc/test/dcalc_case_analysis_leak.tcl b/dcalc/test/dcalc_case_analysis_leak.tcl new file mode 100644 index 00000000..ac814f6b --- /dev/null +++ b/dcalc/test/dcalc_case_analysis_leak.tcl @@ -0,0 +1,61 @@ +# Delay calculation must not merge slew from set_case_analysis constants. +# +# Regression guard for "dcalc no slew merge for constant disabled arcs". +# +# GraphDelayCalc uses DcalcPred (dcalc/GraphDelayCalc.cc). Its searchFrom +# used to stop only at power/ground nets: +# +# return !(sdc->isDisabledConstraint(from_pin) +# || (net && (network->isPower(net) || network->isGround(net)))); +# +# SearchPred0::searchFrom (search/SearchPred.cc) stops at +# sim->isConstant(from_vertex); DcalcPred did not, so in +# findDriverEdgeDelays an arc whose source pin is an SDC constant still +# passed searchFrom/searchThru and had its delay and slew merged into the +# driver vertex -- including when that driver is a live, non-constant pin. +# +# The fix adds sim->isConstant(from_vertex) to DcalcPred::searchFrom, and +# makes Sta::delayCalcPreamble propagate constants before delay calculation +# so the predicate sees them. +# +# Circuit (dcalc_case_analysis_leak.v): +# +# c --BUF u0--> cn ---A2\ +# AND2 u1 --> n1 --BUF u2--> z +# a -------------------A1/ +# +# set_case_analysis 1 c makes net cn constant. 1 is non-controlling for an +# AND, so n1 and z stay live and the A2->ZN arc is dead. The reported path is +# a -> u1 -> u2 -> z, which never traverses cn. +# +# Sweeping the wire load on cn must not change anything on that path. Before +# the fix it did: cn's slew rode the dead A2->ZN arc into n1, and n1's slew +# set u2's delay, so the arrival spread was 46.38 ps. The arrival column +# below must now be flat. + +read_liberty ../../examples/nangate45_slow.lib.gz +read_verilog dcalc_case_analysis_leak.v +link_design top + +create_clock -name clk -period 10 +set_input_delay 0 -clock clk [get_ports {a c}] +set_output_delay 0 -clock clk [get_ports z] +set_input_transition 0.010 [get_ports {a c}] + +set_case_analysis 1 [get_ports c] + +puts "" +puts "load on constant net cn (ff) arrival at z (ps)" +set arrivals {} +foreach load {0 50 200 500 1000} { + set_load $load [get_nets cn] + set path [lindex [find_timing_paths -path_delay max] 0] + set arrival [format %.2f [expr [$path data_arrival_time] * 1e12]] + lappend arrivals $arrival + puts [format "%-32s%s" $load $arrival] +} + +set delta [expr [lindex $arrivals end] - [lindex $arrivals 0]] +puts "" +puts "arrival spread across the sweep: [format %.2f $delta] ps (expected 0.00)" +puts "" diff --git a/dcalc/test/dcalc_case_analysis_leak.v b/dcalc/test/dcalc_case_analysis_leak.v new file mode 100644 index 00000000..a55c2dc2 --- /dev/null +++ b/dcalc/test/dcalc_case_analysis_leak.v @@ -0,0 +1,12 @@ +module top (a, c, z); + input a, c; + output z; + wire cn, n1; + + // set_case_analysis 1 on port c makes net cn constant. + BUF_X1 u0 (.A(c), .Z(cn)); + // 1 is non-controlling for AND2, so n1 is NOT constant. + AND2_X1 u1 (.A1(a), .A2(cn), .ZN(n1)); + // Consumes n1's slew, so slew corruption becomes a delay change. + BUF_X1 u2 (.A(n1), .Z(z)); +endmodule diff --git a/graph/test/graph_modify.ok b/graph/test/graph_modify.ok index d1d2c152..72bdbb69 100644 --- a/graph/test/graph_modify.ok +++ b/graph/test/graph_modify.ok @@ -2415,7 +2415,7 @@ Corner: slow 0.14 1.14 v buf1/Z (BUF_X1) 0.09 1.23 v and1/ZN (AND2_X1) 0.09 1.32 ^ nand1/ZN (NAND2_X1) - 0.07 1.38 ^ buf4/Z (BUF_X4) + 0.06 1.38 ^ buf4/Z (BUF_X4) 0.00 1.38 ^ q3 (out) 1.38 data arrival time diff --git a/sdc/test/sdc_port_delay_advanced.ok b/sdc/test/sdc_port_delay_advanced.ok index 32e0b4a4..8ee4dbd5 100644 --- a/sdc/test/sdc_port_delay_advanced.ok +++ b/sdc/test/sdc_port_delay_advanced.ok @@ -111,7 +111,7 @@ max slew Pin Limit Slew Slack ------------------------------------------------------------ -nor1/ZN 0.20 0.01 0.18 (MET) +reg1/QN 0.20 0.01 0.19 (MET) max fanout diff --git a/search/Sta.cc b/search/Sta.cc index 8288a76a..1a207f75 100644 --- a/search/Sta.cc +++ b/search/Sta.cc @@ -191,6 +191,7 @@ StaSimObserver::StaSimObserver(StaState *sta) : void StaSimObserver::valueChangeAfter(const Pin *pin) { + graph_delay_calc_->delayInvalid(pin); Vertex *vertex = graph_->pinDrvrVertex(pin); if (vertex) { search_->arrivalInvalid(vertex); @@ -3655,8 +3656,10 @@ void Sta::delayCalcPreamble() { ensureLevelized(); - for (Mode *mode : modes_) + for (Mode *mode : modes_) { + mode->sim()->ensureConstantsPropagated(); mode->clkNetwork()->ensureClkNetwork(); + } } void