@@ -2345,13 +2345,6 @@ void TritonCTS::printClockNetwork(const Clock& clockNet) const
23452345
23462346void TritonCTS::setAllClocksPropagated ()
23472347{
2348- // Compute ideal buffer delay to use in delay insertion
2349- if (options_->insertionDelayEnabled ()) {
2350- for (auto & iter : builders_) {
2351- TreeBuilder* builder = iter.get ();
2352- computeTopBufferDelay (builder);
2353- }
2354- }
23552348 sta::Sdc* sdc = openSta_->sdc ();
23562349 for (sta::Clock* clk : *sdc->clocks ()) {
23572350 openSta_->setPropagatedClock (clk);
@@ -2406,351 +2399,4 @@ void TritonCTS::balanceMacroRegisterLatencies()
24062399 }
24072400}
24082401
2409- float TritonCTS::getVertexClkArrival (sta::Vertex* sinkVertex,
2410- odb::dbNet* topNet,
2411- odb::dbITerm* iterm)
2412- {
2413- sta::VertexPathIterator pathIter (sinkVertex, openSta_);
2414- float clkPathArrival = 0.0 ;
2415- while (pathIter.hasNext ()) {
2416- sta::Path* path = pathIter.next ();
2417- const sta::ClockEdge* clock_edge = path->clkEdge (openSta_);
2418- if (clock_edge == nullptr ) {
2419- continue ;
2420- }
2421-
2422- if (clock_edge->transition () != sta::RiseFall::rise ()) {
2423- // only populate with rising edges
2424- continue ;
2425- }
2426-
2427- if (path->dcalcAnalysisPt (openSta_)->delayMinMax () != sta::MinMax::max ()) {
2428- continue ;
2429- // only populate with max delay
2430- }
2431-
2432- const sta::Clock* clock = path->clock (openSta_);
2433- if (clock) {
2434- sta::PathExpanded expand (path, openSta_);
2435- const sta::Path* start = expand.startPath ();
2436-
2437- odb::dbNet* pathStartNet = nullptr ;
2438-
2439- odb::dbITerm* term;
2440- odb::dbBTerm* port;
2441- odb::dbModITerm* modIterm;
2442- network_->staToDb (start->pin (openSta_), term, port, modIterm);
2443- if (term) {
2444- pathStartNet = term->getNet ();
2445- }
2446- if (port) {
2447- pathStartNet = port->getNet ();
2448- }
2449- if (pathStartNet == topNet) {
2450- clkPathArrival = path->arrival ();
2451- return clkPathArrival;
2452- }
2453- }
2454- }
2455- logger_->warn (CTS, 2 , " No paths found for pin {}." , iterm->getName ());
2456- return clkPathArrival;
2457- }
2458-
2459- void TritonCTS::computeAveSinkArrivals (TreeBuilder* builder, sta::Graph* graph)
2460- {
2461- Clock clock = builder->getClock ();
2462- odb::dbNet* topInputClockNet = clock.getNetObj ();
2463- if (builder->getTopInputNet () != nullptr ) {
2464- topInputClockNet = builder->getTopInputNet ();
2465- }
2466- // compute average input arrival at all sinks
2467- float sumArrivals = 0.0 ;
2468- unsigned numSinks = 0 ;
2469- clock.forEachSink ([&](const ClockInst& sink) {
2470- odb::dbITerm* iterm = sink.getDbInputPin ();
2471- computeSinkArrivalRecur (
2472- topInputClockNet, iterm, sumArrivals, numSinks, graph);
2473- });
2474- float aveArrival = sumArrivals / (float ) numSinks;
2475- builder->setAveSinkArrival (aveArrival);
2476- debugPrint (logger_,
2477- CTS,
2478- " insertion delay" ,
2479- 1 ,
2480- " {} {}: average sink arrival is {:0.3e}" ,
2481- (builder->getTreeType () == TreeType::MacroTree) ? " macro tree"
2482- : " register tree" ,
2483- clock.getName (),
2484- builder->getAveSinkArrival ());
2485- }
2486-
2487- void TritonCTS::computeSinkArrivalRecur (odb::dbNet* topClokcNet,
2488- odb::dbITerm* iterm,
2489- float & sumArrivals,
2490- unsigned & numSinks,
2491- sta::Graph* graph)
2492- {
2493- if (iterm) {
2494- odb::dbInst* inst = iterm->getInst ();
2495- if (inst) {
2496- if (isSink (iterm)) {
2497- // either register or macro input pin
2498- sta::Pin* pin = network_->dbToSta (iterm);
2499- if (pin) {
2500- sta::Vertex* sinkVertex = graph->pinDrvrVertex (pin);
2501- float arrival = getVertexClkArrival (sinkVertex, topClokcNet, iterm);
2502- // add insertion delay
2503- float insDelay = 0.0 ;
2504- sta::LibertyCell* libCell
2505- = network_->libertyCell (network_->dbToSta (inst));
2506- odb::dbMTerm* mterm = iterm->getMTerm ();
2507- if (libCell && mterm) {
2508- sta::LibertyPort* libPort
2509- = libCell->findLibertyPort (mterm->getConstName ());
2510- if (libPort) {
2511- const float rise = libPort->clkTreeDelay (
2512- 0.0 , sta::RiseFall::rise (), sta::MinMax::max ());
2513- const float fall = libPort->clkTreeDelay (
2514- 0.0 , sta::RiseFall::fall (), sta::MinMax::max ());
2515-
2516- if (rise != 0 || fall != 0 ) {
2517- insDelay = (rise + fall) / 2.0 ;
2518- }
2519- }
2520- }
2521- sumArrivals += (arrival + insDelay);
2522- numSinks++;
2523- }
2524- } else {
2525- // not a sink, but a clock gater
2526- odb::dbITerm* outTerm = inst->getFirstOutput ();
2527- if (outTerm) {
2528- odb::dbNet* outNet = outTerm->getNet ();
2529- bool propagate = propagateClock (iterm);
2530- if (outNet && propagate) {
2531- odb::dbSet<odb::dbITerm> iterms = outNet->getITerms ();
2532- odb::dbSet<odb::dbITerm>::iterator iter;
2533- for (iter = iterms.begin (); iter != iterms.end (); ++iter) {
2534- odb::dbITerm* inTerm = *iter;
2535- if (inTerm->getIoType () == odb::dbIoType::INPUT) {
2536- computeSinkArrivalRecur (
2537- topClokcNet, inTerm, sumArrivals, numSinks, graph);
2538- }
2539- }
2540- }
2541- }
2542- }
2543- }
2544- }
2545- }
2546-
2547- bool TritonCTS::propagateClock (odb::dbITerm* input)
2548- {
2549- odb::dbInst* inst = input->getInst ();
2550- sta::Cell* masterCell = network_->dbToSta (inst->getMaster ());
2551- sta::LibertyCell* libertyCell = network_->libertyCell (masterCell);
2552-
2553- if (!libertyCell) {
2554- return false ;
2555- }
2556- // Clock tree buffers
2557- if (libertyCell->isInverter () || libertyCell->isBuffer ()) {
2558- return true ;
2559- }
2560- // Combinational components
2561- if (!libertyCell->hasSequentials ()) {
2562- return true ;
2563- }
2564- sta::LibertyPort* inputPort
2565- = libertyCell->findLibertyPort (input->getMTerm ()->getConstName ());
2566-
2567- // Clock Gater / Latch improvised as clock gater
2568- if (inputPort) {
2569- return inputPort->isClockGateClock () || inputPort->isLatchData ();
2570- }
2571-
2572- return false ;
2573- }
2574-
2575- // Balance latencies between macro tree and register tree
2576- // by adding delay buffers to one tree
2577- void TritonCTS::adjustLatencies (TreeBuilder* macroBuilder,
2578- TreeBuilder* registerBuilder)
2579- {
2580- float latencyDiff = macroBuilder->getAveSinkArrival ()
2581- - registerBuilder->getAveSinkArrival ();
2582- int numBuffers = 0 ;
2583- TreeBuilder* builder = nullptr ;
2584- if (latencyDiff > 0 ) {
2585- // add buffers to register tree
2586- numBuffers = (int ) (latencyDiff / registerBuilder->getTopBufferDelay ());
2587- builder = registerBuilder;
2588- } else {
2589- // add buffers to macro tree (not common but why not?)
2590- numBuffers
2591- = (int ) (std::abs (latencyDiff) / macroBuilder->getTopBufferDelay ());
2592- builder = macroBuilder;
2593- }
2594-
2595- // We don't want to add more delay buffers than needed because
2596- // wire delays are not considered. The fewer the delay buffers, the better.
2597- numBuffers = numBuffers * options_->getDelayBufferDerate ();
2598- if (numBuffers == 0 ) {
2599- // clang-format off
2600- debugPrint (logger_, CTS, " insertion delay" , 1 , " no delay buffers are needed"
2601- " to adjust latencies" );
2602- // clang-format on
2603- return ;
2604- }
2605- // clang-format off
2606- debugPrint (logger_, CTS, " insertion delay" , 1 , " {} delay buffers are needed"
2607- " to adjust latencies at {} tree" , numBuffers,
2608- (builder->getTreeType () == TreeType::MacroTree)? " macro" : " register" );
2609- // clang-format on
2610-
2611- // disconnect driver output
2612- odb::dbInst* driver = builder->getTopBuffer ();
2613- odb::dbITerm* driverOutputTerm = driver->getFirstOutput ();
2614- odb::dbNet* outputNet = driverOutputTerm->getNet ();
2615-
2616- // hierarchy support:
2617- // Get the hierarchical net if any and propagate to end of chain
2618- sta::Pin* op_pin = network_->dbToSta (driverOutputTerm);
2619- odb::dbModNet* candidate_hier_net = network_->hasHierarchicalElements ()
2620- ? network_->hierNet (op_pin)
2621- : nullptr ;
2622- odb::dbNet* orig_flat_net = network_->flatNet (op_pin);
2623-
2624- // get bbox of current load pins without driver output pin
2625- driverOutputTerm->disconnect ();
2626- odb::Rect bbox = outputNet->getTermBBox ();
2627- int destX = bbox.xCenter ();
2628- int destY = bbox.yCenter ();
2629- int sourceX, sourceY;
2630- driver->getLocation (sourceX, sourceY);
2631- float offsetX = (float ) (destX - sourceX) / (numBuffers + 1 );
2632- float offsetY = (float ) (destY - sourceY) / (numBuffers + 1 );
2633-
2634- double scalingFactor = techChar_->getLengthUnit ();
2635- for (int i = 0 ; i < numBuffers; i++) {
2636- double locX = (double ) (sourceX + offsetX * (i + 1 )) / scalingFactor;
2637- double locY = (double ) (sourceY + offsetY * (i + 1 )) / scalingFactor;
2638- Point<double > bufferLoc (locX, locY);
2639- Point<double > legalBufferLoc
2640- = builder->legalizeOneBuffer (bufferLoc, options_->getRootBuffer ());
2641- odb::dbInst* buffer
2642- = insertDelayBuffer (driver,
2643- builder->getClock ().getSdcName (),
2644- legalBufferLoc.getX () * scalingFactor,
2645- legalBufferLoc.getY () * scalingFactor);
2646- driver = buffer;
2647- }
2648- // take care of output pin connections
2649- // driver is now the last delay buffer
2650- driverOutputTerm = driver->getFirstOutput ();
2651- driverOutputTerm->disconnect ();
2652- // hierarchical fix. guarded by network has hierarchy
2653- if (candidate_hier_net && network_->hasHierarchy ()) {
2654- network_->connectPin ((sta::Pin*) driverOutputTerm,
2655- (sta::Net*) orig_flat_net,
2656- (sta::Net*) candidate_hier_net);
2657- } else {
2658- driverOutputTerm->connect (outputNet);
2659- }
2660- }
2661-
2662- void TritonCTS::computeTopBufferDelay (TreeBuilder* builder)
2663- {
2664- Clock clock = builder->getClock ();
2665- odb::dbInst* topBuffer
2666- = block_->findInst (builder->getTopBufferName ().c_str ());
2667- if (topBuffer) {
2668- builder->setTopBuffer (topBuffer);
2669- odb::dbITerm* inputTerm = getFirstInput (topBuffer);
2670- odb::dbITerm* outputTerm = topBuffer->getFirstOutput ();
2671- sta::Pin* inputPin = network_->dbToSta (inputTerm);
2672- sta::Pin* outputPin = network_->dbToSta (outputTerm);
2673-
2674- float inputArrival = openSta_->pinArrival (
2675- inputPin, sta::RiseFall::rise (), sta::MinMax::max ());
2676- float outputArrival = openSta_->pinArrival (
2677- outputPin, sta::RiseFall::rise (), sta::MinMax::max ());
2678- float bufferDelay = outputArrival - inputArrival;
2679- // add a 10% increase on the buffer delay as this is an ideal model
2680- // TODO: compute the exact delay adding a buffer adds,
2681- // removing the need for the derate
2682- builder->setTopBufferDelay (bufferDelay * 1.1 );
2683- debugPrint (logger_,
2684- CTS,
2685- " insertion delay" ,
2686- 1 ,
2687- " top buffer delay for {} {} is {:0.3e}" ,
2688- (builder->getTreeType () == TreeType::MacroTree)
2689- ? " macro tree"
2690- : " register tree" ,
2691- topBuffer->getName (),
2692- builder->getTopBufferDelay ());
2693- }
2694- }
2695-
2696- // Create a new delay buffer and connect output pin of driver to input pin of
2697- // new buffer. Output pin of new buffer will be connected later.
2698- odb::dbInst* TritonCTS::insertDelayBuffer (odb::dbInst* driver,
2699- const std::string& clockName,
2700- int locX,
2701- int locY)
2702-
2703- {
2704- // creat a new input net
2705- std::string newNetName
2706- = " delaynet_" + std::to_string (delayBufIndex_) + " _" + clockName;
2707-
2708- // hierarchy fix, make the net in the right scope
2709- odb::dbModule* module = driver->getModule ();
2710- if (module == nullptr ) {
2711- // if none put in top level
2712- module = block_->getTopModule ();
2713- }
2714- sta::Instance* scope
2715- = (module == nullptr || (module == block_->getTopModule ()))
2716- ? network_->topInstance ()
2717- : (sta::Instance*) (module ->getModInst ());
2718- odb::dbNet* newNet = network_->staToDb (network_->makeNet (
2719- newNetName.c_str (), scope, odb::dbNameUniquifyType::IF_NEEDED));
2720-
2721- newNet->setSigType (odb::dbSigType::CLOCK);
2722-
2723- // create a new delay buffer
2724- std::string newBufName
2725- = " delaybuf_" + std::to_string (delayBufIndex_++) + " _" + clockName;
2726- odb::dbMaster* master = db_->findMaster (options_->getRootBuffer ().c_str ());
2727-
2728- // fix: make buffer in same hierarchical module as driver
2729-
2730- odb::dbInst* newBuf
2731- = odb::dbInst::create (block_, master, newBufName.c_str (), false , module );
2732-
2733- newBuf->setSourceType (odb::dbSourceType::TIMING);
2734- newBuf->setLocation (locX, locY);
2735- newBuf->setPlacementStatus (odb::dbPlacementStatus::PLACED);
2736-
2737- // connect driver output with new buffer input
2738- odb::dbITerm* driverOutTerm = driver->getFirstOutput ();
2739- odb::dbITerm* newBufInTerm = getFirstInput (newBuf);
2740-
2741- driverOutTerm->disconnect ();
2742- driverOutTerm->connect (newNet);
2743- newBufInTerm->connect (newNet);
2744-
2745- debugPrint (logger_,
2746- CTS,
2747- " insertion delay" ,
2748- 1 ,
2749- " new delay buffer {} is inserted at ({} {})" ,
2750- newBuf->getName (),
2751- locX,
2752- locY);
2753-
2754- return newBuf;
2755- }
27562402} // namespace cts
0 commit comments