diff --git a/src/OpenRoad.cc b/src/OpenRoad.cc index 3570a30e7bc..16e674258fd 100644 --- a/src/OpenRoad.cc +++ b/src/OpenRoad.cc @@ -566,8 +566,27 @@ void OpenRoad::readDb(const char* filename, bool hierarchy) void OpenRoad::readDb(std::istream& stream) { if (db_->getChip() && db_->getChip()->getBlock()) { - logger_->error( - ORD, 47, "You can't load a new db file as the db is already populated"); + // Notify observers (STA, GUI) to clean up before clearing + db_->triggerPreDbClear(); + + // Clear tool-specific cached state to ensure reproducibility + global_router_->clearForReload(); + opendp_->clearForReload(); + detailed_router_->clearForReload(); + replace_->reset(); + tritonCts_->clear(); + macro_placer_->clear(); + tapcell_->reset(); + ioPlacer_->clear(); + pdngen_->reset(); + pdnsim_->clearSolvers(); + antenna_checker_->clear(); + resizer_->clear(); + extractor_->clear(); + estimate_parasitics_->clear(); + verilog_network_->clear(); + + db_->clear(); } stream.exceptions(std::ifstream::failbit | std::ifstream::badbit diff --git a/src/ant/include/ant/AntennaChecker.hh b/src/ant/include/ant/AntennaChecker.hh index 2f242144b74..2a15c279b07 100644 --- a/src/ant/include/ant/AntennaChecker.hh +++ b/src/ant/include/ant/AntennaChecker.hh @@ -39,6 +39,7 @@ class AntennaChecker odb::dbMTerm* diode_mterm, float ratio_margin); void setReportFileName(const char* file_name); + void clear(); // Used in repair void initAntennaRules(); diff --git a/src/ant/src/AntennaChecker.cc b/src/ant/src/AntennaChecker.cc index 723e18936ad..132efdcc0c1 100644 --- a/src/ant/src/AntennaChecker.cc +++ b/src/ant/src/AntennaChecker.cc @@ -92,6 +92,11 @@ void AntennaChecker::setReportFileName(const char* file_name) impl_->setReportFileName(file_name); } +void AntennaChecker::clear() +{ + impl_->clear(); +} + void AntennaChecker::makeNetWiresFromGuides( const std::vector& nets) { @@ -1304,6 +1309,15 @@ void AntennaChecker::Impl::setReportFileName(const char* file_name) report_file_name_ = file_name; } +void AntennaChecker::Impl::clear() +{ + block_ = nullptr; + layer_info_.clear(); + net_violation_count_ = 0; + nets_.clear(); + net_to_report_.clear(); +} + void AntennaChecker::Impl::makeNetWiresFromGuides( const std::vector& nets) { diff --git a/src/ant/src/AntennaCheckerImpl.hh b/src/ant/src/AntennaCheckerImpl.hh index a3c684abdbe..147f43ac4c5 100644 --- a/src/ant/src/AntennaCheckerImpl.hh +++ b/src/ant/src/AntennaCheckerImpl.hh @@ -92,6 +92,7 @@ class AntennaChecker::Impl float ratio_margin); void initAntennaRules(); void setReportFileName(const char* file_name); + void clear(); void makeNetWiresFromGuides(const std::vector& nets); private: diff --git a/src/cts/include/cts/TritonCTS.h b/src/cts/include/cts/TritonCTS.h index 49b52cbb092..3b527045b8d 100644 --- a/src/cts/include/cts/TritonCTS.h +++ b/src/cts/include/cts/TritonCTS.h @@ -75,6 +75,8 @@ class TritonCTS void resetRootBuffer() { rootBuffers_.clear(); } void setSinkBuffer(const char* buffers); + void clear(); + private: std::string selectRootBuffer(std::vector& buffers); std::string selectSinkBuffer(std::vector& buffers); @@ -219,6 +221,7 @@ class TritonCTS sta::dbSta* openSta_ = nullptr; sta::dbNetwork* network_ = nullptr; utl::Logger* logger_ = nullptr; + stt::SteinerTreeBuilder* st_builder_ = nullptr; CtsOptions* options_ = nullptr; std::unique_ptr techChar_; rsz::Resizer* resizer_ = nullptr; diff --git a/src/cts/src/TritonCTS.cpp b/src/cts/src/TritonCTS.cpp index 24fab44ba4d..c2b5e345153 100644 --- a/src/cts/src/TritonCTS.cpp +++ b/src/cts/src/TritonCTS.cpp @@ -71,10 +71,11 @@ TritonCTS::TritonCTS(utl::Logger* logger, db_ = db; network_ = network; openSta_ = sta; + st_builder_ = st_builder; resizer_ = resizer; estimate_parasitics_ = estimate_parasitics; - options_ = new CtsOptions(logger_, st_builder); + options_ = new CtsOptions(logger_, st_builder_); } TritonCTS::~TritonCTS() @@ -82,6 +83,30 @@ TritonCTS::~TritonCTS() delete options_; } +void TritonCTS::clear() +{ + techChar_.reset(); + builders_.clear(); + staClockNets_.clear(); + visitedClockNets_.clear(); + inst2clkbuf_.clear(); + driver2subnet_.clear(); + net2builder_.clear(); + rootBuffers_.clear(); + sinkBuffers_.clear(); + // Recreate options to reset all Tcl-settable CTS configuration + // (buffer list, cap/slew ranges, clustering, etc.) + delete options_; + options_ = new CtsOptions(logger_, st_builder_); + block_ = nullptr; + numberOfClocks_ = 0; + numClkNets_ = 0; + numFixedNets_ = 0; + dummyLoadIndex_ = 0; + regTreeRootBufIndex_ = 0; + delayBufIndex_ = 0; +} + void TritonCTS::runTritonCts() { odb::dbChip* chip = db_->getChip(); diff --git a/src/dbSta/include/db_sta/dbSta.hh b/src/dbSta/include/db_sta/dbSta.hh index 2c66a95a89c..43ef6b9502f 100644 --- a/src/dbSta/include/db_sta/dbSta.hh +++ b/src/dbSta/include/db_sta/dbSta.hh @@ -163,6 +163,7 @@ class dbSta : public Sta, public odb::dbDatabaseObserver void postReadDef(odb::dbBlock* block) override; void postReadDb(odb::dbDatabase* db) override; void postRead3Dbx(odb::dbChip* chip) override; + void preDbClear(odb::dbDatabase* db) override; // Find clock nets connected by combinational gates from the clock roots. std::set findClkNets(); diff --git a/src/dbSta/src/dbNetwork.cc b/src/dbSta/src/dbNetwork.cc index 763b4f1a956..b09b74189d0 100644 --- a/src/dbSta/src/dbNetwork.cc +++ b/src/dbSta/src/dbNetwork.cc @@ -704,6 +704,8 @@ void dbNetwork::clear() { ConcreteNetwork::clear(); db_ = nullptr; + block_ = nullptr; + top_cell_ = nullptr; } Instance* dbNetwork::topInstance() const diff --git a/src/dbSta/src/dbSta.cc b/src/dbSta/src/dbSta.cc index 6577b50111e..edfdbe0bf53 100644 --- a/src/dbSta/src/dbSta.cc +++ b/src/dbSta/src/dbSta.cc @@ -323,6 +323,27 @@ void dbSta::postReadDb(odb::dbDatabase* db) } } +void dbSta::preDbClear(odb::dbDatabase* db) +{ + db_cbk_->removeOwner(); + // Clear staCell pointers on all masters before freeing the network. + // The GUI render thread may still be accessing these concurrently. + for (odb::dbLib* lib : db->getLibs()) { + for (odb::dbMaster* master : lib->getMasters()) { + master->staSetCell(nullptr); + } + } + // Delete scenes before clearing the network, since scenes hold + // LibertyLibrary pointers that ConcreteNetwork::clear() will free. + // Recreate the default scene so cmd_scene_ remains valid. + deleteScenes(); + makeDefaultScene(); + clear(); + db_network_->clear(); + // Restore db_ since dbNetwork::clear() nulls it, but we need it for reload + db_network_->init(db_, logger_); +} + float dbSta::slack(const odb::dbNet* db_net, const MinMax* min_max) { const Net* net = db_network_->dbToSta(db_net); diff --git a/src/dpl/include/dpl/Opendp.h b/src/dpl/include/dpl/Opendp.h index 14d2a41111a..3e962ac070d 100644 --- a/src/dpl/include/dpl/Opendp.h +++ b/src/dpl/include/dpl/Opendp.h @@ -95,6 +95,7 @@ class Opendp public: Opendp(odb::dbDatabase* db, utl::Logger* logger); ~Opendp(); + void clearForReload(); Opendp(const Opendp&) = delete; Opendp& operator=(const Opendp&) = delete; diff --git a/src/dpl/src/Opendp.cpp b/src/dpl/src/Opendp.cpp index 49ab13088d6..a4ddca2df70 100644 --- a/src/dpl/src/Opendp.cpp +++ b/src/dpl/src/Opendp.cpp @@ -65,6 +65,16 @@ Opendp::Opendp(odb::dbDatabase* db, utl::Logger* logger) Opendp::~Opendp() = default; +void Opendp::clearForReload() +{ + importClear(); + padding_ = std::make_shared(); + decap_masters_.clear(); + disallow_one_site_gaps_ = false; + extra_dpl_enabled_ = false; + global_swap_params_ = GlobalSwapParams(); +} + void Opendp::setPaddingGlobal(const int left, const int right) { padding_->setPaddingGlobal(GridX{left}, GridX{right}); diff --git a/src/drt/include/drt/TritonRoute.h b/src/drt/include/drt/TritonRoute.h index 574ffe08346..7b14d1890a0 100644 --- a/src/drt/include/drt/TritonRoute.h +++ b/src/drt/include/drt/TritonRoute.h @@ -157,6 +157,7 @@ class TritonRoute : public PinAccessService void updateGlobals(const char* file_name); void resetDb(const char* file_name); void clearDesign(); + void clearForReload(); void updateDesign(const std::vector& updates, int num_threads); void updateDesign(const std::string& path, int num_threads); void addWorkerResults( diff --git a/src/drt/src/TritonRoute.cpp b/src/drt/src/TritonRoute.cpp index 1645872026c..b651b723610 100644 --- a/src/drt/src/TritonRoute.cpp +++ b/src/drt/src/TritonRoute.cpp @@ -371,6 +371,25 @@ void TritonRoute::clearDesign() design_ = std::make_unique(logger_, router_cfg_.get()); } +void TritonRoute::clearForReload() +{ + router_cfg_ = std::make_unique(); + design_ = std::make_unique(logger_, router_cfg_.get()); + dr_.reset(); + pa_.reset(); + // Block destructor will remove this callback; just detach so it can + // re-register on the new block via initDesign(). + db_callback_->removeOwner(); + num_drvs_ = -1; + distributed_ = false; + dist_ip_.clear(); + dist_port_ = 0; + shared_volume_.clear(); + workers_results_.clear(); + results_sz_ = 0; + cloud_sz_ = 0; +} + static void deserializeUpdate(frDesign* design, const std::string& updateStr, std::vector& updates) diff --git a/src/est/include/est/EstimateParasitics.h b/src/est/include/est/EstimateParasitics.h index db0b337d764..6424b55d51e 100644 --- a/src/est/include/est/EstimateParasitics.h +++ b/src/est/include/est/EstimateParasitics.h @@ -80,6 +80,7 @@ class EstimateParasitics : public sta::dbStaState, public ParasiticsService stt::SteinerTreeBuilder* stt_builder, grt::GlobalRouter* global_router); ~EstimateParasitics() override; + void clear(); void estimateAllGlobalRouteParasitics() override; void initSteinerRenderer( diff --git a/src/est/src/EstimateParasitics.cpp b/src/est/src/EstimateParasitics.cpp index 1b2a9ea54f8..7ae4f64f35d 100644 --- a/src/est/src/EstimateParasitics.cpp +++ b/src/est/src/EstimateParasitics.cpp @@ -90,6 +90,23 @@ EstimateParasitics::~EstimateParasitics() service_registry_->withdraw(this); } +void EstimateParasitics::clear() +{ + block_ = nullptr; + signal_layers_.clear(); + clk_layers_.clear(); + layer_res_.clear(); + layer_cap_.clear(); + wire_signal_res_.clear(); + wire_signal_cap_.clear(); + wire_clk_res_.clear(); + wire_clk_cap_.clear(); + parasitics_src_ = ParasiticsSrc::kNone; + parasitics_invalid_.clear(); + dbu_ = 0; + incremental_parasitics_enabled_ = false; +} + void EstimateParasitics::estimateAllGlobalRouteParasitics() { clearParasitics(); diff --git a/src/gpl/src/replace.cpp b/src/gpl/src/replace.cpp index da456ada541..3130ae50fdf 100644 --- a/src/gpl/src/replace.cpp +++ b/src/gpl/src/replace.cpp @@ -62,6 +62,8 @@ void Replace::reset() tb_.reset(); rb_.reset(); + + clusters_.clear(); } void Replace::addPlacementCluster(const Cluster& cluster) diff --git a/src/grt/include/grt/GlobalRouter.h b/src/grt/include/grt/GlobalRouter.h index 1475619cb74..160b476bc65 100644 --- a/src/grt/include/grt/GlobalRouter.h +++ b/src/grt/include/grt/GlobalRouter.h @@ -130,6 +130,7 @@ class GlobalRouter gui::HeatMapSourceHandle routing_congestion_data_source_rudy); void clear(); + void clearForReload(); void setAdjustment(float adjustment); void setMinRoutingLayer(int min_layer); @@ -333,6 +334,7 @@ class GlobalRouter odb::dbDatabase* db() const { return db_; } FastRouteCore* fastroute() const { return fastroute_; } Rudy* getRudy(); + void clearRudy(); void writePinLocations(const char* file_name); diff --git a/src/grt/src/GlobalRouter.cpp b/src/grt/src/GlobalRouter.cpp index 812f79e819f..9166ab56cd5 100644 --- a/src/grt/src/GlobalRouter.cpp +++ b/src/grt/src/GlobalRouter.cpp @@ -121,6 +121,7 @@ void GlobalRouter::initGui( void GlobalRouter::clear() { routes_.clear(); + partial_routes_.clear(); for (auto [ignored, net] : db_net_map_) { delete net; } @@ -131,7 +132,49 @@ void GlobalRouter::clear() fastroute_->clear(); vertical_capacities_.clear(); horizontal_capacities_.clear(); + + pad_pins_connections_.clear(); + h_nets_in_pos_.clear(); + v_nets_in_pos_.clear(); + + block_ = nullptr; + delete repair_antennas_; + repair_antennas_ = nullptr; + delete grouter_cbk_; + grouter_cbk_ = nullptr; + initialized_ = false; + is_incremental_ = false; + total_diodes_count_ = 0; +} + +void GlobalRouter::clearForReload() +{ + clear(); + clearRudy(); + region_adjustments_.clear(); + dirty_nets_.clear(); + nets_to_route_.clear(); + + // Reset Tcl-settable configuration to constructor defaults + adjustment_ = 0.0; + congestion_iterations_ = 50; + congestion_report_iter_step_ = 0; + allow_congestion_ = false; + resistance_aware_ = false; + macro_extension_ = 0; + infinite_capacity_ = false; + grid_origin_ = odb::Point(0, 0); + verbose_ = false; + seed_ = 0; + caps_perturbation_percentage_ = 0; + perturbation_amount_ = 1; + use_cugr_ = false; + skip_large_fanout_ = std::numeric_limits::max(); + congestion_file_name_ = nullptr; + is_congested_ = false; + has_macros_or_pads_ = false; + check_pin_placement_ = true; } GlobalRouter::~GlobalRouter() @@ -1139,6 +1182,12 @@ Rudy* GlobalRouter::getRudy() return rudy_; } +void GlobalRouter::clearRudy() +{ + delete rudy_; + rudy_ = nullptr; +} + bool GlobalRouter::findPinAccessPointPositions( const Pin& pin, std::map>& ap_positions, diff --git a/src/grt/src/GrouteRenderer.cpp b/src/grt/src/GrouteRenderer.cpp index 28b84700248..5cb15a85c58 100644 --- a/src/grt/src/GrouteRenderer.cpp +++ b/src/grt/src/GrouteRenderer.cpp @@ -27,6 +27,15 @@ void GrouteRenderer::highlightRoute(odb::dbNet* net, bool show_pin_locations) void GrouteRenderer::drawLayer(odb::dbTechLayer* layer, gui::Painter& painter) { + // After a database reload, cached net pointers are stale. + // Detect the reload by checking if the tech changed. + if (layer->getTech() != tech_) { + tech_ = layer->getTech(); + nets_.clear(); + show_segments_.clear(); + show_pin_locations_.clear(); + } + painter.setPen(layer); painter.setBrush(layer); diff --git a/src/grt/src/heatMap.h b/src/grt/src/heatMap.h index 49bd81a7db2..3a0301e2f83 100644 --- a/src/grt/src/heatMap.h +++ b/src/grt/src/heatMap.h @@ -15,6 +15,12 @@ class RoutingCongestionDataSource : public gui::GlobalRoutingDataSource public: RoutingCongestionDataSource(utl::Logger* logger, odb::dbDatabase* db); + void setChip(odb::dbChip* chip) override + { + layer_ = nullptr; + HeatMapDataSource::setChip(chip); + } + protected: bool populateMap() override; void combineMapData(bool base_has_value, diff --git a/src/grt/src/heatMapRudy.cpp b/src/grt/src/heatMapRudy.cpp index 0902e272bdd..fac11300db7 100644 --- a/src/grt/src/heatMapRudy.cpp +++ b/src/grt/src/heatMapRudy.cpp @@ -156,6 +156,17 @@ bool RUDYDataSource::populateMap() return true; } +void RUDYDataSource::setChip(odb::dbChip* chip) +{ + grouter_->clearRudy(); + rudy_ = nullptr; + removeOwner(); + HeatMapDataSource::setChip(chip); + if (chip && chip->getBlock()) { + addOwner(chip->getBlock()); + } +} + void RUDYDataSource::onShow() { HeatMapDataSource::onShow(); diff --git a/src/grt/src/heatMapRudy.h b/src/grt/src/heatMapRudy.h index 3527d4a7aae..ca631a39fec 100644 --- a/src/grt/src/heatMapRudy.h +++ b/src/grt/src/heatMapRudy.h @@ -23,6 +23,7 @@ class RUDYDataSource : public gui::GlobalRoutingDataSource, grt::GlobalRouter* grouter, odb::dbDatabase* db); + void setChip(odb::dbChip* chip) override; void onShow() override; void onHide() override; diff --git a/src/gui/include/gui/heatMap.h b/src/gui/include/gui/heatMap.h index df182b01570..07c342964ad 100644 --- a/src/gui/include/gui/heatMap.h +++ b/src/gui/include/gui/heatMap.h @@ -53,7 +53,7 @@ class HeatMapDataSource std::string name; std::string label; std::function()> choices; - std::function getter; + std::function getter; std::function setter; }; @@ -92,7 +92,13 @@ class HeatMapDataSource void registerHeatMap(); - virtual void setChip(odb::dbChip* chip) { chip_ = chip; } + virtual void setChip(odb::dbChip* chip) + { + if (chip_ != chip) { + destroyMap(); + } + chip_ = chip; + } void setUseDBU(bool use_dbu) { use_dbu_ = use_dbu; } bool getUseDBU() const { return use_dbu_; } diff --git a/src/gui/src/displayControls.cpp b/src/gui/src/displayControls.cpp index b6931490935..10b4ee1ecbf 100644 --- a/src/gui/src/displayControls.cpp +++ b/src/gui/src/displayControls.cpp @@ -2163,6 +2163,36 @@ void DisplayControls::techInit(odb::dbTech* tech) techs_.insert(tech); } +void DisplayControls::clearTechData() +{ + // Remove layer leaf rows but preserve sub-group items (implant, other) + // by clearing children of each sub-group first, then removing only + // direct layer rows from the layers group. + layers_.implant.name->removeRows(0, layers_.implant.name->rowCount()); + layers_.other.name->removeRows(0, layers_.other.name->rowCount()); + + // Remove direct children (routing/cut layers) from layers_group_, but + // keep the implant and other sub-group rows. Walk in reverse to avoid + // index shifting. + for (int i = layers_group_.name->rowCount() - 1; i >= 0; --i) { + QStandardItem* child = layers_group_.name->child(i); + if (child != layers_.implant.name && child != layers_.other.name) { + layers_group_.name->removeRow(i); + } + } + + site_group_.name->removeRows(0, site_group_.name->rowCount()); + + // Clear ODB-keyed maps + layer_controls_.clear(); + site_controls_.clear(); + layer_color_.clear(); + layer_pattern_.clear(); + site_color_.clear(); + techs_.clear(); + layers_menu_layer_ = nullptr; +} + void DisplayControls::blockLoaded(odb::dbBlock* block) { addTech(block->getTech()); diff --git a/src/gui/src/displayControls.h b/src/gui/src/displayControls.h index 6f6f0bf6667..fe12e21ebac 100644 --- a/src/gui/src/displayControls.h +++ b/src/gui/src/displayControls.h @@ -272,6 +272,9 @@ class DisplayControls : public QDockWidget, // options displayed need to match void blockLoaded(odb::dbBlock* block); + // Clears all ODB-derived display state (layers, sites) for DB reload + void clearTechData(); + void setCurrentChip(odb::dbChip* chip); // This is called by the check boxes to update the state diff --git a/src/gui/src/heatMapCore.cpp b/src/gui/src/heatMapCore.cpp index 4cebbc04c7d..8ed9eb150d3 100644 --- a/src/gui/src/heatMapCore.cpp +++ b/src/gui/src/heatMapCore.cpp @@ -397,7 +397,6 @@ Renderer::Settings HeatMapDataSource::getSettings() const settings[set.name] = set.getter(); } } - return settings; } diff --git a/src/gui/src/layoutTabs.cpp b/src/gui/src/layoutTabs.cpp index d7649ef05e2..5e1513f8e13 100644 --- a/src/gui/src/layoutTabs.cpp +++ b/src/gui/src/layoutTabs.cpp @@ -130,8 +130,30 @@ void LayoutTabs::chipLoaded(odb::dbChip* chip) emit newViewer(viewer); } +void LayoutTabs::clearViewers() +{ + // Stop render threads before destroying viewers to avoid + // deleting a running QThread. + for (LayoutViewer* viewer : viewers_) { + viewer->exit(); + } + // QTabWidget::clear() removes all tabs and deletes the page widgets + // (LayoutScroll), which are parents of the LayoutViewer widgets. + QTabWidget::clear(); + viewers_.clear(); + current_viewer_ = nullptr; + modules_.clear(); + focus_nets_.clear(); + route_guides_.clear(); + net_tracks_.clear(); +} + void LayoutTabs::tabChange(int index) { + if (index < 0 || index >= static_cast(viewers_.size())) { + current_viewer_ = nullptr; + return; + } current_viewer_ = viewers_[index]; emit setCurrentChip(current_viewer_->getChip()); diff --git a/src/gui/src/layoutTabs.h b/src/gui/src/layoutTabs.h index a0422f29227..4db63e8f78d 100644 --- a/src/gui/src/layoutTabs.h +++ b/src/gui/src/layoutTabs.h @@ -91,6 +91,7 @@ class LayoutTabs : public QTabWidget void tabChange(int index); void updateBackgroundColors(); void updateBackgroundColor(LayoutViewer* viewer); + void clearViewers(); // These are just forwarding to the current LayoutViewer void zoomIn(); diff --git a/src/gui/src/mainWindow.cpp b/src/gui/src/mainWindow.cpp index fd93eadb6fc..62a7afc6b7a 100644 --- a/src/gui/src/mainWindow.cpp +++ b/src/gui/src/mainWindow.cpp @@ -1629,6 +1629,10 @@ void MainWindow::selectHighlightConnectedBufferTrees(bool select_flag, void MainWindow::saveSettings() { + // Stop render threads before saving settings to avoid races + // between the render thread and the main thread. + viewers_->exit(); + QSettings settings("OpenRoad Project", "openroad"); settings.beginGroup("main"); settings.setValue("geometry", saveGeometry()); @@ -1662,6 +1666,18 @@ void MainWindow::postRead3Dbx(odb::dbChip* chip) emit chipLoaded(chip); } +void MainWindow::preDbClear(odb::dbDatabase* db) +{ + selected_.clear(); + for (auto& highlighted_set : highlighted_) { + highlighted_set.clear(); + } + inspector_->inspect(Selected()); + viewers_->clearViewers(); + controls_->clearTechData(); + setBlock(nullptr); +} + void MainWindow::postReadDb(odb::dbDatabase* db) { auto chip = db->getChip(); diff --git a/src/gui/src/mainWindow.h b/src/gui/src/mainWindow.h index 9df989b3dd3..ce122b09f54 100644 --- a/src/gui/src/mainWindow.h +++ b/src/gui/src/mainWindow.h @@ -79,6 +79,7 @@ class MainWindow : public QMainWindow, public odb::dbDatabaseObserver void postReadDef(odb::dbBlock* block) override; void postReadDb(odb::dbDatabase* db) override; void postRead3Dbx(odb::dbChip* chip) override; + void preDbClear(odb::dbDatabase* db) override; // Capture logger messages into the script widget output void setLogger(utl::Logger* logger); diff --git a/src/mpl/include/mpl/rtl_mp.h b/src/mpl/include/mpl/rtl_mp.h index 43e0567b633..2814fb20251 100644 --- a/src/mpl/include/mpl/rtl_mp.h +++ b/src/mpl/include/mpl/rtl_mp.h @@ -81,6 +81,7 @@ class MacroPlacer int right, int top); + void clear(); void setDebug(std::unique_ptr& graphics); void setDebugShowBundledNets(bool show_bundled_nets); void setDebugShowClustersIds(bool show_clusters_ids); diff --git a/src/mpl/src/hier_rtlmp.cpp b/src/mpl/src/hier_rtlmp.cpp index 4d591bd4b82..baa178b90ec 100644 --- a/src/mpl/src/hier_rtlmp.cpp +++ b/src/mpl/src/hier_rtlmp.cpp @@ -2467,7 +2467,13 @@ void HierRTLMP::writeMacroPlacement(const std::string& file_name) void HierRTLMP::clear() { - tree_.reset(); + tree_ = std::make_unique(); + clustering_engine_.reset(); + fences_.clear(); + guides_.clear(); + macro_to_halo_.clear(); + placement_blockages_.clear(); + io_blockages_.clear(); if (graphics_) { graphics_->eraseDrawing(); diff --git a/src/mpl/src/hier_rtlmp.h b/src/mpl/src/hier_rtlmp.h index 8faf0380cb7..2a2cbeee17a 100644 --- a/src/mpl/src/hier_rtlmp.h +++ b/src/mpl/src/hier_rtlmp.h @@ -118,6 +118,7 @@ class HierRTLMP void setNumThreads(int threads) { num_threads_ = threads; } void setMacroPlacementFile(const std::string& file_name); void writeMacroPlacement(const std::string& file_name); + void clear(); private: struct PinAccessDepthLimits @@ -140,7 +141,6 @@ class HierRTLMP void commitClusteringDataToDb() const; void createGroupForCluster(Cluster* cluster, odb::dbGroup* parent_group) const; - void clear(); void computeWireLength() const; // Coarse Shaping diff --git a/src/mpl/src/rtl_mp.cpp b/src/mpl/src/rtl_mp.cpp index 376cc1bced0..0790b568cce 100644 --- a/src/mpl/src/rtl_mp.cpp +++ b/src/mpl/src/rtl_mp.cpp @@ -33,6 +33,12 @@ MacroPlacer::MacroPlacer(odb::dbDatabase* db, MacroPlacer::~MacroPlacer() = default; +void MacroPlacer::clear() +{ + hier_rtlmp_->clear(); + guidance_regions_.clear(); +} + bool MacroPlacer::place(const int num_threads, const int max_num_macro, const int min_num_macro, diff --git a/src/odb/include/odb/db.h b/src/odb/include/odb/db.h index 943cd973647..fe93468bd31 100644 --- a/src/odb/include/odb/db.h +++ b/src/odb/include/odb/db.h @@ -7717,6 +7717,7 @@ class dbDatabase : public dbObject void triggerPostReadDef(dbBlock* block, bool floorplan); void triggerPostReadDb(); void triggerPostRead3Dbx(dbChip* chip); + void triggerPreDbClear(); /// /// Create an instance of a database diff --git a/src/odb/include/odb/dbDatabaseObserver.h b/src/odb/include/odb/dbDatabaseObserver.h index 05ff66327ec..99a9f69a409 100644 --- a/src/odb/include/odb/dbDatabaseObserver.h +++ b/src/odb/include/odb/dbDatabaseObserver.h @@ -31,6 +31,9 @@ class dbDatabaseObserver virtual void postReadDb(odb::dbDatabase* db) = 0; virtual void postRead3Dbx(odb::dbChip* chip) = 0; + // Called before the database is cleared for a reload + virtual void preDbClear(odb::dbDatabase* /*db*/) {} + void setUnregisterObserver(std::function unregister_observer) { unregister_observer_ = std::move(unregister_observer); diff --git a/src/odb/src/db/dbDatabase.cpp b/src/odb/src/db/dbDatabase.cpp index 83a5fec5d6e..f115f6ebca5 100644 --- a/src/odb/src/db/dbDatabase.cpp +++ b/src/odb/src/db/dbDatabase.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include "absl/synchronization/mutex.h" @@ -478,6 +479,24 @@ _dbDatabase::_dbDatabase(_dbDatabase* /* unused: db */, int id) chip_tbl_ = new dbTable<_dbChip, 2>( this, this, (GetObjTbl_t) &_dbDatabase::getObjectTable, dbChipObj); + chip_hash_.setTable(chip_tbl_); + + chip_inst_tbl_ = new dbTable<_dbChipInst>( + this, this, (GetObjTbl_t) &_dbDatabase::getObjectTable, dbChipInstObj); + chip_region_inst_tbl_ = new dbTable<_dbChipRegionInst>( + this, + this, + (GetObjTbl_t) &_dbDatabase::getObjectTable, + dbChipRegionInstObj); + chip_conn_tbl_ = new dbTable<_dbChipConn>( + this, this, (GetObjTbl_t) &_dbDatabase::getObjectTable, dbChipConnObj); + chip_bump_inst_tbl_ + = new dbTable<_dbChipBumpInst>(this, + this, + (GetObjTbl_t) &_dbDatabase::getObjectTable, + dbChipBumpInstObj); + chip_net_tbl_ = new dbTable<_dbChipNet>( + this, this, (GetObjTbl_t) &_dbDatabase::getObjectTable, dbChipNetObj); gds_lib_tbl_ = new dbTable<_dbGDSLib, 2>( this, this, (GetObjTbl_t) &_dbDatabase::getObjectTable, dbGdsLibObj); @@ -925,8 +944,14 @@ void dbDatabase::clear() { _dbDatabase* db = (_dbDatabase*) this; int id = db->unique_id_; + // Save session-level state that was set up during init and is not + // part of the database content being cleared. + auto observers = std::move(db->observers_); + utl::Logger* logger = db->logger_; db->~_dbDatabase(); new (db) _dbDatabase(db, id); + db->observers_ = std::move(observers); + db->logger_ = logger; } void dbDatabase::destroy(dbDatabase* db_) @@ -1029,6 +1054,14 @@ void dbDatabase::triggerPostReadDb() } } +void dbDatabase::triggerPreDbClear() +{ + _dbDatabase* db = (_dbDatabase*) this; + for (dbDatabaseObserver* observer : db->observers_) { + observer->preDbClear(this); + } +} + // User Code End dbDatabasePublicMethods } // namespace odb // Generator Code End Cpp diff --git a/src/pdn/src/PdnGen.cc b/src/pdn/src/PdnGen.cc index f2610a80242..54dce9c4e9d 100644 --- a/src/pdn/src/PdnGen.cc +++ b/src/pdn/src/PdnGen.cc @@ -50,6 +50,8 @@ void PdnGen::reset() { core_domain_ = nullptr; domains_.clear(); + switched_power_cells_.clear(); + sroute_.reset(); updateRenderer(true); } diff --git a/src/psm/src/heatMap.cpp b/src/psm/src/heatMap.cpp index 347ceac0bb1..faed2592e03 100644 --- a/src/psm/src/heatMap.cpp +++ b/src/psm/src/heatMap.cpp @@ -96,6 +96,9 @@ IRDropDataSource::IRDropDataSource(PDNSim* psm, void IRDropDataSource::setChip(odb::dbChip* chip) { + layer_ = nullptr; + net_ = nullptr; + corner_ = nullptr; gui::HeatMapDataSource::setChip(chip); if (chip != nullptr) { odb::dbBlock* block = chip->getBlock(); diff --git a/src/rcx/include/rcx/ext.h b/src/rcx/include/rcx/ext.h index 90dee2632ab..f4e7118d9b7 100644 --- a/src/rcx/include/rcx/ext.h +++ b/src/rcx/include/rcx/ext.h @@ -23,6 +23,7 @@ class Ext public: Ext(odb::dbDatabase* db, utl::Logger* logger, const char* spef_version); ~Ext(); + void clear(); void setLogger(utl::Logger* logger); diff --git a/src/rcx/src/ext.cpp b/src/rcx/src/ext.cpp index ef9f8583a84..46dc33f4e2c 100644 --- a/src/rcx/src/ext.cpp +++ b/src/rcx/src/ext.cpp @@ -34,6 +34,13 @@ Ext::~Ext() delete _ext; } +void Ext::clear() +{ + delete _ext; + _ext = new extMain(); + _ext->init(_db, logger_); +} + void Ext::setLogger(Logger* logger) { if (!logger_) { diff --git a/src/rsz/include/rsz/Resizer.hh b/src/rsz/include/rsz/Resizer.hh index 2eee80bdb13..352a34ce4c2 100644 --- a/src/rsz/include/rsz/Resizer.hh +++ b/src/rsz/include/rsz/Resizer.hh @@ -191,6 +191,7 @@ class Resizer : public sta::dbStaState, public sta::dbNetworkObserver dpl::Opendp* opendp, est::EstimateParasitics* estimate_parasitics); ~Resizer() override; + void clear(); // Core area (meters). double coreArea() const; diff --git a/src/rsz/src/Resizer.cc b/src/rsz/src/Resizer.cc index 099c1b321fc..1a7e5d5571d 100644 --- a/src/rsz/src/Resizer.cc +++ b/src/rsz/src/Resizer.cc @@ -157,6 +157,48 @@ Resizer::Resizer(utl::Logger* logger, Resizer::~Resizer() = default; +void Resizer::clear() +{ + db_cbk_->removeOwner(); + + block_ = nullptr; + debug_pin_ = nullptr; + core_exists_ = false; + core_ = odb::Rect(); + design_area_ = 0.0; + dbu_ = 0; + max_area_ = 0.0; + + dont_use_.clear(); + buffer_cells_.clear(); + buffer_lowest_drive_ = nullptr; + buffer_fast_sizes_.clear(); + clk_buffers_.clear(); + swappable_cells_cache_.clear(); + vt_equiv_cells_cache_.clear(); + target_load_map_.reset(); + tgt_slews_ = {}; + tgt_slew_corner_ = nullptr; + resized_multi_output_insts_.clear(); + net_slack_map_.clear(); + cell_leakage_cache_.clear(); + inserted_buffer_set_.clear(); + all_inserted_buffer_set_.clear(); + removed_buffer_set_.clear(); + input_slew_map_.clear(); + vt_map_.clear(); + vt_hash_map_.clear(); + equiv_cells_made_ = false; + + inserted_buffer_count_ = 0; + cloned_gate_count_ = 0; + swap_pin_count_ = 0; + removed_buffer_count_ = 0; + accepted_move_count_ = 0; + max_wire_length_ = 0; + buffer_moved_into_core_ = false; +} + //////////////////////////////////////////////////////////////// double Resizer::coreArea() const diff --git a/src/tap/src/tapcell.cpp b/src/tap/src/tapcell.cpp index c41f0a208ed..79c251599c2 100644 --- a/src/tap/src/tapcell.cpp +++ b/src/tap/src/tapcell.cpp @@ -38,6 +38,7 @@ void Tapcell::reset() phy_idx_ = 0; tap_prefix_ = "TAP_"; endcap_prefix_ = "PHY_"; + filled_edges_.clear(); } //--------------------------------------------------------------- diff --git a/src/web/src/search.cpp b/src/web/src/search.cpp index c9f7aa59aaf..d273232bfbb 100644 --- a/src/web/src/search.cpp +++ b/src/web/src/search.cpp @@ -203,10 +203,13 @@ void Search::setTopChip(odb::dbChip* chip) return; } odb::dbBlock* block = chip->getBlock(); - if (top_chip_ != chip) { + // Re-initialize when the chip changed or when the previous block was + // destroyed (e.g. after a database reload via read_db). The block + // destructor calls removeOwner() which clears hasOwner(). + if (top_chip_ != chip || !hasOwner()) { clear(); - if (top_chip_ != nullptr) { + if (hasOwner()) { removeOwner(); }