diff --git a/include/ord/InitOpenRoad.hh b/include/ord/InitOpenRoad.hh index 9d6a17cbe74..95323a1a61f 100644 --- a/include/ord/InitOpenRoad.hh +++ b/include/ord/InitOpenRoad.hh @@ -37,8 +37,12 @@ #include +#include + namespace ord { // Call this inside of Tcl_Main. -void initOpenRoad(Tcl_Interp* interp); +void initOpenRoad(Tcl_Interp* interp, + const char* log_filename, + const char* metrics_filename); } // namespace ord diff --git a/include/ord/OpenRoad.hh b/include/ord/OpenRoad.hh index 05f9b4f20f6..4c220270274 100644 --- a/include/ord/OpenRoad.hh +++ b/include/ord/OpenRoad.hh @@ -166,7 +166,9 @@ class OpenRoad // OpenRoad object and/or any other tools they need to reference. static OpenRoad* openRoad(); static void setOpenRoad(OpenRoad* app, bool reinit_ok = false); - void init(Tcl_Interp* tcl_interp); + void init(Tcl_Interp* tcl_interp, + const char* log_filename, + const char* metrics_filename); Tcl_Interp* tclInterp() { return tcl_interp_; } utl::Logger* getLogger() { return logger_; } diff --git a/include/ord/Tech.h b/include/ord/Tech.h index 29d8399b166..40c28e98bf5 100644 --- a/include/ord/Tech.h +++ b/include/ord/Tech.h @@ -60,7 +60,9 @@ class Tech public: // interp is only passed by standalone OR as it gets its // interpreter from Tcl_Main. - Tech(Tcl_Interp* interp = nullptr); + Tech(Tcl_Interp* interp = nullptr, + const char* log_filename = nullptr, + const char* metrics_filename = nullptr); ~Tech(); void readLef(const std::string& file_name); diff --git a/src/Main.cc b/src/Main.cc index 322f297cecc..1e2fd61a3be 100644 --- a/src/Main.cc +++ b/src/Main.cc @@ -117,10 +117,10 @@ FOREACH_TOOL(X) int cmd_argc; char** cmd_argv; -const char* log_filename = nullptr; -const char* metrics_filename = nullptr; -bool no_settings = false; -bool minimize = false; +static const char* log_filename = nullptr; +static const char* metrics_filename = nullptr; +static bool no_settings = false; +static bool minimize = false; static const char* init_filename = ".openroad"; @@ -281,7 +281,7 @@ int main(int argc, char* argv[]) the_tech = std::make_unique(interp); the_design = std::make_unique(the_tech.get()); ord::OpenRoad::setOpenRoad(the_design->getOpenRoad()); - ord::initOpenRoad(interp); + ord::initOpenRoad(interp, log_filename, metrics_filename); if (!findCmdLineFlag(cmd_argc, cmd_argv, "-no_splash")) { showSplash(); } @@ -448,7 +448,7 @@ static int tclAppInit(int& argc, } #endif - ord::initOpenRoad(interp); + ord::initOpenRoad(interp, log_filename, metrics_filename); bool no_splash = findCmdLineFlag(argc, argv, "-no_splash"); if (!no_splash) { diff --git a/src/OpenRoad.cc b/src/OpenRoad.cc index fc46d46587f..a89c5515ff9 100644 --- a/src/OpenRoad.cc +++ b/src/OpenRoad.cc @@ -98,10 +98,6 @@ extern int Odbtcl_Init(Tcl_Interp* interp); extern int Upf_Init(Tcl_Interp* interp); } -// Main.cc set by main() -extern const char* log_filename; -extern const char* metrics_filename; - namespace ord { using odb::dbBlock; @@ -176,12 +172,16 @@ void OpenRoad::setOpenRoad(OpenRoad* app, bool reinit_ok) //////////////////////////////////////////////////////////////// -void initOpenRoad(Tcl_Interp* interp) +void initOpenRoad(Tcl_Interp* interp, + const char* log_filename, + const char* metrics_filename) { - OpenRoad::openRoad()->init(interp); + OpenRoad::openRoad()->init(interp, log_filename, metrics_filename); } -void OpenRoad::init(Tcl_Interp* tcl_interp) +void OpenRoad::init(Tcl_Interp* tcl_interp, + const char* log_filename, + const char* metrics_filename) { tcl_interp_ = tcl_interp; diff --git a/src/Tech.cc b/src/Tech.cc index 65d9380caaa..1540b1e859e 100644 --- a/src/Tech.cc +++ b/src/Tech.cc @@ -44,12 +44,15 @@ namespace ord { -Tech::Tech(Tcl_Interp* interp) : app_(new OpenRoad()) +Tech::Tech(Tcl_Interp* interp, + const char* log_filename, + const char* metrics_filename) + : app_(new OpenRoad()) { if (!interp) { interp = Tcl_CreateInterp(); Tcl_Init(interp); - app_->init(interp); + app_->init(interp, log_filename, metrics_filename); } } diff --git a/src/cts/src/HTreeBuilder.cpp b/src/cts/src/HTreeBuilder.cpp index efb8081f2ad..665b7151971 100644 --- a/src/cts/src/HTreeBuilder.cpp +++ b/src/cts/src/HTreeBuilder.cpp @@ -1954,8 +1954,7 @@ void HTreeBuilder::createSingleBufferClockNet() void HTreeBuilder::plotSolution() { - static int cnt = 0; - auto name = std::string("plot") + std::to_string(cnt++) + ".py"; + auto name = std::string("plot_") + clock_.getName() + ".py"; std::ofstream file(name); file << "import numpy as np\n"; file << "import matplotlib.pyplot as plt\n"; diff --git a/src/dbSta/src/PathRenderer.cc b/src/dbSta/src/PathRenderer.cc index 4c8c14f8a6e..edfb2f2b7e1 100644 --- a/src/dbSta/src/PathRenderer.cc +++ b/src/dbSta/src/PathRenderer.cc @@ -12,8 +12,8 @@ namespace sta { -gui::Painter::Color PathRenderer::signal_color = gui::Painter::red; -gui::Painter::Color PathRenderer::clock_color = gui::Painter::yellow; +const gui::Painter::Color PathRenderer::signal_color = gui::Painter::red; +const gui::Painter::Color PathRenderer::clock_color = gui::Painter::yellow; PathRenderer::PathRenderer(dbSta* sta) : sta_(sta) { @@ -41,9 +41,9 @@ void PathRenderer::drawObjects(gui::Painter& painter) const PathRef* prev_path = path_->path(i - 1); const Pin* pin = path->pin(sta_); const Pin* prev_pin = prev_path->pin(sta_); - odb::Point pt1 = network->location(pin); - odb::Point pt2 = network->location(prev_pin); - gui::Painter::Color wire_color + const odb::Point pt1 = network->location(pin); + const odb::Point pt2 = network->location(prev_pin); + const gui::Painter::Color wire_color = sta_->isClock(pin) ? clock_color : signal_color; painter.setPen(wire_color, true); painter.drawLine(pt1, pt2); @@ -66,8 +66,8 @@ void PathRenderer::highlightInst(const Pin* pin, gui::Painter& painter) network->staToDb(inst, db_inst, mod_inst); if (db_inst != nullptr) { odb::dbBox* bbox = db_inst->getBBox(); - odb::Rect rect = bbox->getBox(); - gui::Painter::Color inst_color + const odb::Rect rect = bbox->getBox(); + const gui::Painter::Color inst_color = sta_->isClock(pin) ? clock_color : signal_color; painter.setBrush(inst_color); painter.drawRect(rect); diff --git a/src/dbSta/src/PathRenderer.h b/src/dbSta/src/PathRenderer.h index d32614668e2..3f9ac571357 100644 --- a/src/dbSta/src/PathRenderer.h +++ b/src/dbSta/src/PathRenderer.h @@ -30,8 +30,8 @@ class PathRenderer : public gui::Renderer, public AbstractPathRenderer dbSta* sta_; // Expanded path is owned by PathRenderer. std::unique_ptr path_; - static gui::Painter::Color signal_color; - static gui::Painter::Color clock_color; + static const gui::Painter::Color signal_color; + static const gui::Painter::Color clock_color; }; } // namespace sta diff --git a/src/drt/src/gc/FlexGC_init.cpp b/src/drt/src/gc/FlexGC_init.cpp index 1a98afeb86f..e70aaaee9fd 100644 --- a/src/drt/src/gc/FlexGC_init.cpp +++ b/src/drt/src/gc/FlexGC_init.cpp @@ -718,7 +718,31 @@ void FlexGCWorker::Impl::initNet_pins_polygonEdges(gcNet* net) } } } - +namespace { +bool isPolygonCorner(const frCoord x, + const frCoord y, + const gtl::polygon_90_set_data& poly_set) +{ + std::vector> polygons; + poly_set.get(polygons); + for (const auto& polygon : polygons) { + for (const auto& pt : polygon) { + if (pt.x() == x && pt.y() == y) { + return true; + } + } + for (auto hole_itr = polygon.begin_holes(); hole_itr != polygon.end_holes(); + ++hole_itr) { + for (const auto& pt : (*hole_itr)) { + if (pt.x() == x && pt.y() == y) { + return true; + } + } + } + } + return false; +} +} // namespace void FlexGCWorker::Impl::initNet_pins_polygonCorners_helper(gcNet* net, gcPin* pin) { @@ -769,26 +793,32 @@ void FlexGCWorker::Impl::initNet_pins_polygonCorners_helper(gcNet* net, && nextEdge->getDir() == frDirEnum::E)) { currCorner->setDir(frCornerDirEnum::SE); } - - // set fixed / route status - if (currCorner->getType() == frCornerTypeEnum::CONVEX) { - currCorner->setFixed(false); - for (auto& rect : net->getRectangles(true)[layerNum]) { - if (isCornerOverlap(currCorner, rect)) { - currCorner->setFixed(true); - break; + if (getTech()->getLayer(layerNum)->getType() + == odb::dbTechLayerType::CUT) { + if (currCorner->getType() == frCornerTypeEnum::CONVEX) { + currCorner->setFixed(false); + for (auto& rect : net->getRectangles(true)[layerNum]) { + if (isCornerOverlap(currCorner, rect)) { + currCorner->setFixed(true); + break; + } } - } - } else if (currCorner->getType() == frCornerTypeEnum::CONCAVE) { - currCorner->setFixed(true); - auto cornerPt = currCorner->getNextEdge()->low(); - for (auto& rect : net->getRectangles(false)[layerNum]) { - if (gtl::contains(rect, cornerPt, true) - && !gtl::contains(rect, cornerPt, false)) { - currCorner->setFixed(false); - break; + } else if (currCorner->getType() == frCornerTypeEnum::CONCAVE) { + currCorner->setFixed(true); + auto cornerPt = currCorner->getNextEdge()->low(); + for (auto& rect : net->getRectangles(false)[layerNum]) { + if (gtl::contains(rect, cornerPt, true) + && !gtl::contains(rect, cornerPt, false)) { + currCorner->setFixed(false); + break; + } } } + + } else { + currCorner->setFixed(isPolygonCorner(currCorner->x(), + currCorner->y(), + net->getPolygons(true)[layerNum])); } // currCorner->setFixed(prevEdge->isFixed() && nextEdge->isFixed()); diff --git a/src/drt/src/gc/FlexGC_main.cpp b/src/drt/src/gc/FlexGC_main.cpp index 566dab8ef9a..76d9d0fb385 100644 --- a/src/drt/src/gc/FlexGC_main.cpp +++ b/src/drt/src/gc/FlexGC_main.cpp @@ -3006,9 +3006,6 @@ void FlexGCWorker::Impl::checkLef58CutSpacing_spc_layer( const gtl::rectangle_data& markerRect, frLef58CutSpacingConstraint* con) { - if (rect1->isFixed() && rect2->isFixed()) { - return; - } auto layerNum = rect1->getLayerNum(); auto secondLayerNum = rect2->getLayerNum(); auto net1 = rect1->getNet(); diff --git a/src/drt/src/io/io.cpp b/src/drt/src/io/io.cpp index ce4abafcd1c..484eda0acff 100644 --- a/src/drt/src/io/io.cpp +++ b/src/drt/src/io/io.cpp @@ -1573,6 +1573,7 @@ void io::Parser::setRoutingLayerProperties(odb::dbTechLayer* layer, tmpLayer->setLef58RightWayOnGridOnlyConstraint( rightWayOnGridOnlyConstraint.get()); getTech()->addUConstraint(std::move(rightWayOnGridOnlyConstraint)); + ALLOW_PIN_AS_FEEDTHROUGH = false; } for (auto rule : layer->getTechLayerMinStepRules()) { if (rule->getMaxEdges() > 1) { diff --git a/src/gui/resources/icon.png b/src/gui/resources/icon.png index 7b74d1ecb01..3132708e9ea 100644 Binary files a/src/gui/resources/icon.png and b/src/gui/resources/icon.png differ diff --git a/src/mpl2/src/graphics.cpp b/src/mpl2/src/graphics.cpp index f0c8af53b82..f1ae532e682 100644 --- a/src/mpl2/src/graphics.cpp +++ b/src/mpl2/src/graphics.cpp @@ -71,7 +71,7 @@ void Graphics::startSA() return; } - if (only_final_result_ || skip_steps_) { + if (skip_steps_) { return; } @@ -90,7 +90,7 @@ void Graphics::endSA(const float norm_cost) return; } - if (only_final_result_ || skip_steps_) { + if (skip_steps_) { return; } @@ -113,10 +113,6 @@ bool Graphics::isTargetCluster() void Graphics::saStep(const std::vector& macros) { - if (only_final_result_) { - return; - } - resetPenalties(); soft_macros_ = macros; hard_macros_.clear(); @@ -124,10 +120,6 @@ void Graphics::saStep(const std::vector& macros) void Graphics::saStep(const std::vector& macros) { - if (only_final_result_) { - return; - } - resetPenalties(); hard_macros_ = macros; soft_macros_.clear(); @@ -162,10 +154,6 @@ void Graphics::report(const float norm_cost) void Graphics::drawResult() { - if (!only_final_result_) { - return; - } - if (max_level_) { std::vector> outlines(max_level_.value() + 1); int level = 0; @@ -221,10 +209,6 @@ void Graphics::penaltyCalculated(float norm_cost) return; } - if (only_final_result_) { - return; - } - if (is_skipping_) { return; } @@ -591,10 +575,6 @@ void Graphics::setTargetClusterId(const int target_cluster_id) void Graphics::setOutline(const odb::Rect& outline) { - if (only_final_result_) { - return; - } - outline_ = outline; } diff --git a/src/mpl2/src/hier_rtlmp.cpp b/src/mpl2/src/hier_rtlmp.cpp index e08582e23c5..9afe4030ed8 100644 --- a/src/mpl2/src/hier_rtlmp.cpp +++ b/src/mpl2/src/hier_rtlmp.cpp @@ -249,9 +249,20 @@ void HierRTLMP::run() resetSAParameters(); } + std::unique_ptr save_graphics; + if (is_debug_only_final_result_) { + save_graphics = std::move(graphics_); + } + runCoarseShaping(); runHierarchicalMacroPlacement(); + if (save_graphics) { + graphics_ = std::move(save_graphics); + graphics_->setMaxLevel(tree_->max_level); + graphics_->drawResult(); + } + Pusher pusher(logger_, tree_->root.get(), block_, boundary_to_io_blockage_); pusher.pushMacrosToCoreBoundaries(); @@ -314,11 +325,6 @@ void HierRTLMP::runHierarchicalMacroPlacement() } else { runHierarchicalMacroPlacementWithoutBusPlanning(tree_->root.get()); } - - if (graphics_) { - graphics_->setMaxLevel(tree_->max_level); - graphics_->drawResult(); - } } void HierRTLMP::resetSAParameters() @@ -4122,6 +4128,7 @@ void HierRTLMP::setDebugSkipSteps(bool skip_steps) void HierRTLMP::setDebugOnlyFinalResult(bool only_final_result) { graphics_->setOnlyFinalResult(only_final_result); + is_debug_only_final_result_ = only_final_result; } void HierRTLMP::setDebugTargetClusterId(const int target_cluster_id) diff --git a/src/mpl2/src/hier_rtlmp.h b/src/mpl2/src/hier_rtlmp.h index b8c4c1be438..350338b7d29 100644 --- a/src/mpl2/src/hier_rtlmp.h +++ b/src/mpl2/src/hier_rtlmp.h @@ -345,6 +345,7 @@ class HierRTLMP bool skip_macro_placement_ = false; std::unique_ptr graphics_; + bool is_debug_only_final_result_{false}; }; class Pusher diff --git a/src/odb/include/odb/wOrder.h b/src/odb/include/odb/wOrder.h index cc7eb491301..b60a4a674c7 100644 --- a/src/odb/include/odb/wOrder.h +++ b/src/odb/include/odb/wOrder.h @@ -39,9 +39,7 @@ class Logger; namespace odb { class dbBlock; -class dbNet; void orderWires(utl::Logger* logger, dbBlock* b); -void orderWires(utl::Logger* logger, dbNet* net); } // namespace odb diff --git a/src/odb/src/db/dbDatabase.cpp b/src/odb/src/db/dbDatabase.cpp index b4de42bd9ba..a9e58feeb82 100644 --- a/src/odb/src/db/dbDatabase.cpp +++ b/src/odb/src/db/dbDatabase.cpp @@ -73,7 +73,9 @@ constexpr int DB_MAGIC2 = 0x4E414442; // NADB template class dbTable<_dbDatabase>; static dbTable<_dbDatabase>* db_tbl = nullptr; -static uint db_unique_id = 0; +// Must be held to access db_tbl +static std::mutex db_tbl_mutex; +static std::atomic db_unique_id = 0; bool _dbDatabase::operator==(const _dbDatabase& rhs) const { @@ -151,9 +153,6 @@ void _dbDatabase::out(dbDiff& diff, char side, const char* field) const dbObjectTable* _dbDatabase::getObjectTable(dbObjectType type) { switch (type) { - case dbDatabaseObj: - return db_tbl; - case dbTechObj: return _tech_tbl; @@ -671,6 +670,7 @@ void dbDatabase::setLogger(utl::Logger* logger) dbDatabase* dbDatabase::create() { + std::lock_guard lock(db_tbl_mutex); if (db_tbl == nullptr) { db_tbl = new dbTable<_dbDatabase>( nullptr, nullptr, (GetObjTbl_t) nullptr, dbDatabaseObj); @@ -690,12 +690,14 @@ void dbDatabase::clear() void dbDatabase::destroy(dbDatabase* db_) { + std::lock_guard lock(db_tbl_mutex); _dbDatabase* db = (_dbDatabase*) db_; db_tbl->destroy(db); } dbDatabase* dbDatabase::duplicate(dbDatabase* db_) { + std::lock_guard lock(db_tbl_mutex); _dbDatabase* db = (_dbDatabase*) db_; _dbDatabase* d = db_tbl->duplicate(db); return (dbDatabase*) d; @@ -703,6 +705,7 @@ dbDatabase* dbDatabase::duplicate(dbDatabase* db_) dbDatabase* dbDatabase::getDatabase(uint dbid) { + std::lock_guard lock(db_tbl_mutex); return (dbDatabase*) db_tbl->getPtr(dbid); } diff --git a/src/odb/src/db/dbNet.cpp b/src/odb/src/db/dbNet.cpp index d2682f8091a..f6663f68ba1 100644 --- a/src/odb/src/db/dbNet.cpp +++ b/src/odb/src/db/dbNet.cpp @@ -2054,7 +2054,6 @@ dbRSeg* dbNet::findRSeg(uint srcn, uint tgtn) return nullptr; } -int ttttsv = 0; void dbNet::createZeroRc(bool foreign) { dbCapNode* cap1 = dbCapNode::create(this, 1, foreign); @@ -2063,10 +2062,6 @@ void dbNet::createZeroRc(bool foreign) cap1->setNode(iterm->getId()); dbCapNode* cap2 = dbCapNode::create(this, 2, foreign); cap2->setInternalFlag(); - if (ttttsv) { - cap1->setCapacitance(0.0001, 0); - cap2->setCapacitance(0.0001, 0); - } dbRSeg* rseg1 = dbRSeg::create( this, 0 /*x*/, 0 /*y*/, 0 /*path_dir*/, !foreign /*allocate_cap*/); dbRSeg* rseg0 = dbRSeg::create( @@ -2075,10 +2070,6 @@ void dbNet::createZeroRc(bool foreign) rseg0->setTargetNode(cap1->getId()); rseg1->setSourceNode(cap1->getId()); rseg1->setTargetNode(cap2->getId()); - if (ttttsv) { - rseg1->setResistance(1.0, 0); - } - // rseg1->setCapacitance(0.0001, 0); } void dbNet::set1stRSegId(uint rid) diff --git a/src/odb/src/db/tmg_conn.cpp b/src/odb/src/db/tmg_conn.cpp index 33f29f9aa11..62a9161db99 100644 --- a/src/odb/src/db/tmg_conn.cpp +++ b/src/odb/src/db/tmg_conn.cpp @@ -38,6 +38,7 @@ #include "odb/db.h" #include "odb/dbShape.h" #include "odb/dbWireCodec.h" +#include "tmg_conn_g.h" #include "utl/Logger.h" namespace odb { @@ -117,6 +118,17 @@ tmg_conn::tmg_conn(utl::Logger* logger) : logger_(logger) _swireNetCnt = 0; } +tmg_conn::~tmg_conn() +{ + free(_termV); + free(_tstackV); + free(_csNV); + free(_shortV); + + delete _search; + delete _graph; +} + int tmg_conn::ptDist(const int fr, const int to) const { return abs(_ptV[fr]._x - _ptV[to]._x) + abs(_ptV[fr]._y - _ptV[to]._y); diff --git a/src/odb/src/db/tmg_conn.h b/src/odb/src/db/tmg_conn.h index 9794d836bf8..bd50c3f3bd2 100644 --- a/src/odb/src/db/tmg_conn.h +++ b/src/odb/src/db/tmg_conn.h @@ -125,49 +125,9 @@ struct tmg_connect_shape class tmg_conn { - public: - int _slicedTilePinCnt; - int _stbtx1[200]; - int _stbty1[200]; - int _stbtx2[200]; - int _stbty2[200]; - dbBTerm* _slicedTileBTerm[200]; - tmg_conn_search* _search; - tmg_conn_graph* _graph; - std::vector _rcV; - std::vector _ptV; - tmg_rcterm* _termV; - tmg_rcterm** _tstackV; - int _termN; - tmg_rcshort* _shortV; - int _shortN; - dbNet* _net; - bool _hasSWire; - bool _preserveSWire; - int _swireNetCnt; - bool _connected; - dbWireEncoder _encoder; - dbWire* _newWire; - dbTechNonDefaultRule* _net_rule; - dbTechNonDefaultRule* _path_rule; - int _misc_cnt; - int _cut_end_extMin; - int _need_short_wire_id; - std::vector> _csVV; - std::array* _csV; - int* _csNV; - int _csN; - tmg_rcpt* _first_for_clear; - - private: - int _termNmax; - int _shortNmax; - int _last_id; - int _firstSegmentAfterVia; - utl::Logger* logger_; - public: tmg_conn(utl::Logger* logger); + ~tmg_conn(); void analyzeNet(dbNet* net); void loadNet(dbNet* net); void loadWire(dbWire* wire); @@ -226,6 +186,46 @@ class tmg_conn tmg_rc* addRcPatch(int ifr, int ito); int getDisconnectedStart(); void copyWireIdToVisitedShorts(int j); + + int _slicedTilePinCnt; + int _stbtx1[200]; + int _stbty1[200]; + int _stbtx2[200]; + int _stbty2[200]; + dbBTerm* _slicedTileBTerm[200]; + tmg_conn_search* _search; + tmg_conn_graph* _graph; + std::vector _rcV; + std::vector _ptV; + tmg_rcterm* _termV; + tmg_rcterm** _tstackV; + int _termN; + tmg_rcshort* _shortV; + int _shortN; + dbNet* _net; + bool _hasSWire; + bool _preserveSWire; + int _swireNetCnt; + bool _connected; + dbWireEncoder _encoder; + dbWire* _newWire; + dbTechNonDefaultRule* _net_rule; + dbTechNonDefaultRule* _path_rule; + int _misc_cnt; + int _cut_end_extMin; + int _need_short_wire_id; + std::vector> _csVV; + std::array* _csV; + int* _csNV; + int _csN; + tmg_rcpt* _first_for_clear; + + int _termNmax; + int _shortNmax; + int _last_id; + int _firstSegmentAfterVia; + utl::Logger* logger_; + friend class tmg_conn_graph; }; class tmg_conn_search diff --git a/src/odb/src/db/tmg_conn_g.cpp b/src/odb/src/db/tmg_conn_g.cpp index 8944e65a983..909273bb76b 100644 --- a/src/odb/src/db/tmg_conn_g.cpp +++ b/src/odb/src/db/tmg_conn_g.cpp @@ -30,6 +30,8 @@ // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. +#include "tmg_conn_g.h" + #include #include @@ -41,59 +43,6 @@ namespace odb { -struct tcg_edge -{ - tcg_edge* next; - tcg_edge* reverse; - tmg_rcshort* s; - int fr; - int to; - int k; // index to _rcV - bool visited; - bool skip; -}; - -struct tcg_pt -{ - tcg_edge* edges; - int ipath; - int visited; // 1= from another descent, 2+k= _stackV[k]->fr -}; - -class tmg_conn_graph -{ - public: - tmg_conn_graph(); - void init(int ptN, int shortN); - tcg_edge* newEdge(const tmg_conn* conn, int fr, int to); - tcg_edge* newShortEdge(const tmg_conn* conn, int fr, int to); - tcg_edge* getNextEdge(bool ok_to_descend); - tcg_edge* getFirstEdge(int jstart); - tcg_edge* getFirstNonShortEdge(int& jstart); - void addEdges(const tmg_conn* conn, int i0, int i1, int k); - void clearVisited(); - void relocateShorts(tmg_conn* conn); - void getEdgeRefCoord(tmg_conn* conn, tcg_edge* pe, int& rx, int& ry); - bool isBadShort(tcg_edge* pe, tmg_conn* conn); - bool dfsStart(int& j); - bool dfsNext(int* from, int* to, int* k, bool* is_short, bool* is_loop); - - public: - tcg_pt* _ptV; - int _ptN; - int* _path_vis; - tcg_edge** _stackV; - int _stackN; - - private: - tcg_edge* _e; - int _ptNmax; - int _shortNmax; - int _eNmax; - tcg_edge* _eV; - int _eN; -}; - tmg_conn_graph::tmg_conn_graph() { _ptNmax = 1024; @@ -105,6 +54,14 @@ tmg_conn_graph::tmg_conn_graph() _stackV = (tcg_edge**) malloc(_shortNmax * sizeof(tcg_edge*)); } +tmg_conn_graph::~tmg_conn_graph() +{ + free(_ptV); + free(_path_vis); + free(_eV); + free(_stackV); +} + void tmg_conn_graph::init(const int ptN, const int shortN) { if (ptN > _ptNmax) { diff --git a/src/odb/src/db/tmg_conn_g.h b/src/odb/src/db/tmg_conn_g.h new file mode 100644 index 00000000000..7c22d232514 --- /dev/null +++ b/src/odb/src/db/tmg_conn_g.h @@ -0,0 +1,94 @@ +/////////////////////////////////////////////////////////////////////////////// +// BSD 3-Clause License +// +// Copyright (c) 2019, Nefelus Inc +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#pragma once + +namespace odb { + +class tmg_conn; +struct tmg_rcshort; + +struct tcg_edge +{ + tcg_edge* next; + tcg_edge* reverse; + tmg_rcshort* s; + int fr; + int to; + int k; // index to _rcV + bool visited; + bool skip; +}; + +struct tcg_pt +{ + tcg_edge* edges; + int ipath; + int visited; // 1= from another descent, 2+k= _stackV[k]->fr +}; + +class tmg_conn_graph +{ + public: + tmg_conn_graph(); + ~tmg_conn_graph(); + void init(int ptN, int shortN); + tcg_edge* newEdge(const tmg_conn* conn, int fr, int to); + tcg_edge* newShortEdge(const tmg_conn* conn, int fr, int to); + tcg_edge* getNextEdge(bool ok_to_descend); + tcg_edge* getFirstEdge(int jstart); + tcg_edge* getFirstNonShortEdge(int& jstart); + void addEdges(const tmg_conn* conn, int i0, int i1, int k); + void clearVisited(); + void relocateShorts(tmg_conn* conn); + void getEdgeRefCoord(tmg_conn* conn, tcg_edge* pe, int& rx, int& ry); + bool isBadShort(tcg_edge* pe, tmg_conn* conn); + bool dfsStart(int& j); + bool dfsNext(int* from, int* to, int* k, bool* is_short, bool* is_loop); + + public: + tcg_pt* _ptV; + int _ptN; + int* _path_vis; + tcg_edge** _stackV; + int _stackN; + + private: + tcg_edge* _e; + int _ptNmax; + int _shortNmax; + int _eNmax; + tcg_edge* _eV; + int _eN; +}; + +} // namespace odb diff --git a/src/odb/src/db/wOrder.cpp b/src/odb/src/db/wOrder.cpp index 6fcf0bba91d..9e468efd58b 100644 --- a/src/odb/src/db/wOrder.cpp +++ b/src/odb/src/db/wOrder.cpp @@ -37,30 +37,16 @@ namespace odb { -static tmg_conn* conn = nullptr; - void orderWires(utl::Logger* logger, dbBlock* block) { - if (conn == nullptr) { - conn = new tmg_conn(logger); - } + tmg_conn conn(logger); + for (auto net : block->getNets()) { if (net->getSigType().isSupply() || net->isWireOrdered()) { continue; } - conn->analyzeNet(net); - } -} - -void orderWires(utl::Logger* logger, dbNet* net) -{ - if (conn == nullptr) { - conn = new tmg_conn(logger); - } - if (net->getSigType().isSupply()) { - return; + conn.analyzeNet(net); } - conn->analyzeNet(net); } } // namespace odb diff --git a/src/rmp/src/logic_cut.cpp b/src/rmp/src/logic_cut.cpp index 88a54254357..32f21972f3b 100644 --- a/src/rmp/src/logic_cut.cpp +++ b/src/rmp/src/logic_cut.cpp @@ -14,6 +14,7 @@ #include "db_sta/dbNetwork.hh" #include "map/mio/mio.h" #include "sta/Liberty.hh" +#include "unique_name.h" #include "utl/Logger.h" #include "utl/deleter.h" @@ -28,9 +29,9 @@ std::unordered_map CreateAbcPrimaryInputs( for (sta::Net* input_pin : primary_inputs) { abc::Abc_Obj_t* primary_input_abc = abc::Abc_NtkCreatePi(&abc_network); abc::Abc_Obj_t* primary_input_net = abc::Abc_NtkCreateNet(&abc_network); - std::string net_name(network->name(input_pin)); + std::string net_name(network->pathName(input_pin)); abc::Abc_ObjAssignName( - primary_input_abc, net_name.data(), /*pSuffix=*/nullptr); + primary_input_net, net_name.data(), /*pSuffix=*/nullptr); abc::Abc_ObjAddFanin(primary_input_net, primary_input_abc); name_pin_map[input_pin] = primary_input_net; @@ -48,7 +49,7 @@ std::unordered_map CreateAbcPrimaryOutputs( for (sta::Net* output_pin : primary_outputs) { abc::Abc_Obj_t* primary_output_abc = abc::Abc_NtkCreatePo(&abc_network); abc::Abc_Obj_t* primary_output_net = abc::Abc_NtkCreateNet(&abc_network); - std::string net_name(network->name(output_pin)); + std::string net_name(network->pathName(output_pin)); abc::Abc_ObjAssignName( primary_output_net, net_name.data(), /*pSuffix=*/nullptr); abc::Abc_ObjAddFanin(primary_output_abc, primary_output_net); @@ -219,6 +220,7 @@ void CreateNets( abc::Abc_Obj_t* abc_driver_instance = abc_instances.at(instance); abc::Abc_Obj_t* primary_output = abc_primary_output_nets.at(output_net); abc::Abc_ObjAddFanin(primary_output, abc_driver_instance); + abc_net_map[output_net] = primary_output; } // ABC expects the inputs to particular gates to happen in a certain implict @@ -265,9 +267,9 @@ utl::deleted_unique_ptr LogicCut::BuildMappedAbcNetwork( /*fUseMemMan=*/1), &abc::Abc_NtkDelete); - std::unordered_map abc_input_pins + std::unordered_map abc_input_nets = CreateAbcPrimaryInputs(primary_inputs_, *abc_network, network); - std::unordered_map abc_output_pins + std::unordered_map abc_output_nets = CreateAbcPrimaryOutputs(primary_outputs_, *abc_network, network); // Create MIO standard cell library @@ -282,8 +284,8 @@ utl::deleted_unique_ptr LogicCut::BuildMappedAbcNetwork( cut_instances_, *abc_network, network, mio_library, logger); CreateNets(primary_outputs_, - abc_input_pins, - abc_output_pins, + abc_input_nets, + abc_output_nets, standard_cells, *abc_network, network, @@ -293,4 +295,320 @@ utl::deleted_unique_ptr LogicCut::BuildMappedAbcNetwork( return abc_network; } +sta::Instance* GetLogicalParentInstance( + const std::unordered_set& cut_instances_, + sta::dbNetwork* network, + utl::Logger* logger) +{ + // In physical designs with hierarchy we need to figure out + // the parent module in which instances should be placed. + // For now lets just grab the first Instance* we see. RMP + // shouldn't be doing anything across modules right now, but + // if that changes I assume things will break. + if (cut_instances_.empty()) { + logger->error(utl::RMP, 1011, "Empty logic cuts are not allowed"); + } + + sta::Instance* instance = nullptr; + for (sta::Instance* cut_instance : cut_instances_) { + if (instance == nullptr) { + instance = network->parent(cut_instance); + } + + if (instance != network->parent(cut_instance)) { + logger->error(utl::RMP, + 1012, + "LogiCuts with multiple parent modules are not allowed."); + } + } + + return instance; +} + +std::unordered_map CreateInstances( + abc::Abc_Ntk_t* abc_network, + sta::dbNetwork* network, + sta::Instance* parent_instance, + UniqueName& unique_name, + utl::Logger* logger) +{ + std::unordered_map result; + + for (int i = 0; i < abc::Abc_NtkObjNumMax(abc_network); i++) { + // ABC stores all objects as a list of objs we need to filter + // to the ones that represent nodes/standard cells. + abc::Abc_Obj_t* node_obj = abc::Abc_NtkObj(abc_network, i); + if (node_obj == nullptr || !abc::Abc_ObjIsNode(node_obj)) { + continue; + } + + auto std_cell = static_cast(abc::Abc_ObjData(node_obj)); + std::string std_cell_name = abc::Mio_GateReadName(std_cell); + sta::LibertyCell* liberty_cell + = network->findLibertyCell(std_cell_name.c_str()); + + if (liberty_cell == nullptr) { + logger->error( + utl::RMP, + 1010, + "Could not find cell name {}, please report this internal error", + std_cell_name); + } + + sta::Instance* new_instance = network->makeInstance( + liberty_cell, unique_name.GetUniqueName().c_str(), parent_instance); + + result[node_obj] = new_instance; + } + return result; +} + +std::unordered_map CreateNets( + abc::Abc_Ntk_t* abc_network, + sta::dbNetwork* network, + sta::Instance* parent_instance, + UniqueName& unique_name, + utl::Logger* logger) +{ + std::unordered_map result; + + // Get primary input and output nets + for (int i = 0; i < abc::Abc_NtkObjNumMax(abc_network); i++) { + abc::Abc_Obj_t* node_obj = abc::Abc_NtkObj(abc_network, i); + if (node_obj == nullptr) { + continue; + } + + abc::Abc_Obj_t* net_obj = nullptr; + if (abc::Abc_ObjIsPo(node_obj)) { + net_obj = abc::Abc_ObjFanin0(node_obj); + } else if (abc::Abc_ObjIsPi(node_obj)) { + net_obj = abc::Abc_ObjFanout0(node_obj); + } else { + continue; + } + + if (!abc::Abc_ObjIsNet(net_obj)) { + logger->error(utl::RMP, + 1013, + "Primary input or output is not connected to an AIG PI/PO, " + "please report this internal error"); + } + + std::string net_name = abc::Abc_ObjName(net_obj); + sta::Net* net = network->findNet(net_name.c_str()); + if (!net) { + logger->error(utl::RMP, 1024, "Cannot find primary net {}", net_name); + } + result[net_obj] = net; + } + + for (int i = 0; i < abc::Abc_NtkObjNumMax(abc_network); i++) { + // ABC stores all objects as a list of objs we need to filter + // to the ones that represent nodes/standard cells. + abc::Abc_Obj_t* node_obj = abc::Abc_NtkObj(abc_network, i); + if (node_obj == nullptr || !abc::Abc_ObjIsNet(node_obj)) { + continue; + } + + if (result.find(node_obj) != result.end()) { + continue; + } + + sta::Net* sta_net = network->makeNet(unique_name.GetUniqueName().c_str(), + parent_instance); + result[node_obj] = sta_net; + } + + return result; +} + +void DeleteExistingLogicCut(sta::dbNetwork* network, + std::vector& primary_inputs, + std::vector& primary_outputs, + std::unordered_set& cut_instances, + utl::Logger* logger) +{ + // Delete nets that only belong to the cut set. + std::unordered_set nets_to_be_deleted; + std::unordered_set primary_input_or_output_nets; + + for (sta::Net* net : primary_inputs) { + primary_input_or_output_nets.insert(net); + } + for (sta::Net* net : primary_outputs) { + primary_input_or_output_nets.insert(net); + } + + for (sta::Instance* instance : cut_instances) { + auto pin_iterator = std::unique_ptr( + network->pinIterator(instance)); + while (pin_iterator->hasNext()) { + sta::Pin* pin = pin_iterator->next(); + sta::Net* connected_net = network->net(pin); + // If pin isn't a primary input or output add to deleted list. The only + // way this can happen is if a net is only used within the cutset, and + // in that case we want to delete it. + if (primary_input_or_output_nets.find(connected_net) + == primary_input_or_output_nets.end()) { + nets_to_be_deleted.insert(connected_net); + } + } + } + + for (sta::Instance* instance : cut_instances) { + network->deleteInstance(instance); + } + + for (sta::Net* net : nets_to_be_deleted) { + network->deleteNet(net); + } +} + +void ConnectInstances( + abc::Abc_Ntk_t* abc_network, + sta::dbNetwork* network, + const std::unordered_map& new_instances, + const std::unordered_map& new_nets, + utl::Logger* logger) +{ + abc::Mio_Library_t* library + = static_cast(abc_network->pManFunc); + std::unordered_map> + gate_to_port_order = MioGateToPortOrder(library); + for (auto& [abc_obj, sta_instance] : new_instances) { + auto std_cell = static_cast(abc::Abc_ObjData(abc_obj)); + if (gate_to_port_order.find(std_cell) == gate_to_port_order.end()) { + logger->error(utl::RMP, + 1021, + "Cannot find abc gate port order {}, please report this " + "internal error", + abc::Mio_GateReadName(std_cell)); + } + + // Connect fan-ins for instance + + std::string gate_name = abc::Mio_GateReadName(std_cell); + sta::LibertyCell* cell = network->findLibertyCell(gate_name.c_str()); + if (!cell) { + logger->error(utl::RMP, 1014, "Cannot find cell {}", gate_name); + } + + int i = 0; + // ABC doesn't really have a concept of port names and liberty ports + // rather there is an implict order between fan-ins and its standard cell, + // loop through in that order, and connect the ports correctly based + // on the abc fan-in. + for (const std::string& port_name : gate_to_port_order.at(std_cell)) { + sta::LibertyPort* port = cell->findLibertyPort(port_name.c_str()); + if (!port) { + logger->error( + utl::RMP, 1015, "Cannot find port {}/{}", gate_name, port_name); + } + + abc::Abc_Obj_t* net = abc::Abc_ObjFanin(abc_obj, i); + if (!abc::Abc_ObjIsNet(net)) { + logger->error(utl::RMP, + 1016, + "Object is not a net in ABC netlist {}", + abc::Abc_ObjName(net)); + } + + if (new_nets.find(net) == new_nets.end()) { + logger->error(utl::RMP, + 1022, + "Could not find corresponding sta net for abc net: {}", + abc::Abc_ObjName(net)); + } + + sta::Net* sta_net = new_nets.at(net); + + network->connect(sta_instance, port, sta_net); + i++; + } + + // Connect the fan-out, in this case the only fan-out since ABC only + // deals with single output gates. + std::string output_port_name = abc::Mio_GateReadOutName(std_cell); + sta::LibertyPort* output_port + = cell->findLibertyPort(output_port_name.c_str()); + + if (!output_port) { + logger->error(utl::RMP, + 1017, + "Cannot find port {}/{}", + gate_name, + output_port_name); + } + abc::Abc_Obj_t* net = abc::Abc_ObjFanout0(abc_obj); + if (!abc::Abc_ObjIsNet(net)) { + logger->error(utl::RMP, + 1019, + "Object is not a net in ABC netlist {}", + abc::Abc_ObjName(net)); + } + + if (new_nets.find(net) == new_nets.end()) { + logger->error(utl::RMP, + 1020, + "Could not find corresponding sta net for abc net: {}", + abc::Abc_ObjName(net)); + } + + sta::Net* sta_net = new_nets.at(net); + + network->connect(sta_instance, output_port, sta_net); + } +} + +void LogicCut::InsertMappedAbcNetwork(abc::Abc_Ntk_t* abc_network, + sta::dbNetwork* network, + UniqueName& unique_name, + utl::Logger* logger) +{ + if (!abc::Abc_NtkHasMapping(abc_network)) { + logger->error( + utl::RMP, + 1008, + "abc_network has no mapping, please report this internal error."); + } + + if (!abc::Abc_NtkIsNetlist(abc_network)) { + logger->error( + utl::RMP, + 1009, + "abc_network is not a netlist, please report this internal error."); + } + + sta::Instance* parent_instance + = GetLogicalParentInstance(cut_instances_, network, logger); + std::unordered_map abc_objs_to_instances + = CreateInstances( + abc_network, network, parent_instance, unique_name, logger); + std::unordered_map abc_nets_to_sta_nets + = CreateNets(abc_network, network, parent_instance, unique_name, logger); + + // Get rid of the old cut in preparation to connect the new ones. + DeleteExistingLogicCut( + network, primary_inputs_, primary_outputs_, cut_instances_, logger); + + // Connects the new instances to each other and to their primary inputs + // and outputs. + ConnectInstances(abc_network, + network, + abc_objs_to_instances, + abc_nets_to_sta_nets, + logger); + + // Final clean up to make this cut valid again. Replace the old cut instances + // with the new ones. This should result in an equally valid LogicCut since + // the PI/POs haven't changed just the junk inside. + cut_instances_.clear(); + cut_instances_.reserve(abc_objs_to_instances.size()); + + for (const auto& kv : abc_objs_to_instances) { + cut_instances_.insert(kv.second); + } +} + } // namespace rmp \ No newline at end of file diff --git a/src/rmp/src/logic_cut.h b/src/rmp/src/logic_cut.h index 05559114037..245300dc2c9 100644 --- a/src/rmp/src/logic_cut.h +++ b/src/rmp/src/logic_cut.h @@ -15,6 +15,7 @@ #include "db_sta/dbNetwork.hh" #include "sta/GraphClass.hh" #include "sta/NetworkClass.hh" +#include "unique_name.h" #include "utl/Logger.h" #include "utl/deleter.h" @@ -22,7 +23,6 @@ namespace rmp { class LogicCut { public: - LogicCut() = default; LogicCut(std::vector& primary_inputs, std::vector& primary_outputs, std::unordered_set& cut_instances) @@ -57,6 +57,11 @@ class LogicCut sta::dbNetwork* network, utl::Logger* logger); + void InsertMappedAbcNetwork(abc::Abc_Ntk_t* abc_network, + sta::dbNetwork* network, + UniqueName& unique_name, + utl::Logger* logger); + private: std::vector primary_inputs_; std::vector primary_outputs_; diff --git a/src/rmp/src/unique_name.h b/src/rmp/src/unique_name.h new file mode 100644 index 00000000000..d84e1c1f73d --- /dev/null +++ b/src/rmp/src/unique_name.h @@ -0,0 +1,24 @@ +// Copyright 2024 Google LLC +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +#pragma once + +#include + +namespace rmp { +class UniqueName +{ + public: + std::string GetUniqueName(const std::string& prefix = "rmp_") + { + int64_t id = counter++; + return prefix + std::to_string(id); + } + + private: + int64_t counter = 0; +}; +} // namespace rmp diff --git a/src/rmp/test/cpp/TestAbc.cc b/src/rmp/test/cpp/TestAbc.cc index 1ffe64d086a..f97a74e6333 100644 --- a/src/rmp/test/cpp/TestAbc.cc +++ b/src/rmp/test/cpp/TestAbc.cc @@ -60,6 +60,7 @@ class AbcTest : public ::testing::Test sta::initSta(); abc::Abc_Start(); }); + db_->setLogger(&logger_); sta_ = std::unique_ptr(ord::makeDbSta()); sta_->initVars(Tcl_CreateInterp(), db_.get(), &logger_); auto path = std::filesystem::canonical("./Nangate45/Nangate45_fast.lib"); @@ -123,6 +124,18 @@ class AbcTest : public ::testing::Test sta_->ensureGraph(); sta_->ensureLevelized(); } + std::map AbcLogicNetworkNameToPrimaryOutputIds( + abc::Abc_Ntk_t* network) + { + std::map primary_output_name_to_index; + for (int i = 0; i < abc::Abc_NtkPoNum(network); i++) { + abc::Abc_Obj_t* po = abc::Abc_NtkPo(network, i); + std::string po_name = abc::Abc_ObjName(po); + primary_output_name_to_index[po_name] = i; + } + + return primary_output_name_to_index; + } utl::deleted_unique_ptr db_; sta::Unit* power_unit_; @@ -393,12 +406,8 @@ TEST_F(AbcTest, BuildAbcMappedNetworkFromLogicCut) abc::Abc_NtkToLogic(abc_network.get()), &abc::Abc_NtkDelete); // Build map of primary output names to primary output indicies in ABC - std::map primary_output_name_to_index; - for (int i = 0; i < abc::Abc_NtkPoNum(logic_network.get()); i++) { - abc::Abc_Obj_t* po = abc::Abc_NtkPo(logic_network.get(), i); - std::string po_name = abc::Abc_ObjName(po); - primary_output_name_to_index[po_name] = i; - } + std::map primary_output_name_to_index + = AbcLogicNetworkNameToPrimaryOutputIds(logic_network.get()); std::array input_vector = {1, 1}; utl::deleted_unique_ptr output_vector( @@ -436,4 +445,97 @@ TEST_F(AbcTest, BuildComplexLogicCone) EXPECT_NO_THROW(cut.BuildMappedAbcNetwork(abc_library, network, &logger_)); } + +TEST_F(AbcTest, InsertingMappedLogicCutDoesNotThrow) +{ + AbcLibraryFactory factory(&logger_); + factory.AddDbSta(sta_.get()); + AbcLibrary abc_library = factory.Build(); + + LoadVerilog("aes_nangate45.v", /*top=*/"aes_cipher_top"); + + sta::dbNetwork* network = sta_->getDbNetwork(); + sta::Vertex* flop_input_vertex = nullptr; + for (sta::Vertex* vertex : *sta_->endpoints()) { + if (std::string(vertex->name(network)) == "_32989_/D") { + flop_input_vertex = vertex; + } + } + EXPECT_NE(flop_input_vertex, nullptr); + + LogicExtractorFactory logic_extractor(sta_.get(), &logger_); + logic_extractor.AppendEndpoint(flop_input_vertex); + LogicCut cut = logic_extractor.BuildLogicCut(abc_library); + + utl::deleted_unique_ptr mapped_abc_network + = cut.BuildMappedAbcNetwork(abc_library, network, &logger_); + + rmp::UniqueName unique_name; + EXPECT_NO_THROW(cut.InsertMappedAbcNetwork( + mapped_abc_network.get(), network, unique_name, &logger_)); +} + +TEST_F(AbcTest, + AfterExtractingAndReinsertingCuttingAgainResultsInCorrectSimulation) +{ + AbcLibraryFactory factory(&logger_); + factory.AddDbSta(sta_.get()); + AbcLibrary abc_library = factory.Build(); + + LoadVerilog("side_outputs_extract_logic_depth.v"); + + sta::dbNetwork* network = sta_->getDbNetwork(); + sta::Vertex* flop_input_vertex = nullptr; + for (sta::Vertex* vertex : *sta_->endpoints()) { + if (std::string(vertex->name(network)) == "output_flop/D") { + flop_input_vertex = vertex; + } + } + EXPECT_NE(flop_input_vertex, nullptr); + + LogicExtractorFactory logic_extractor(sta_.get(), &logger_); + logic_extractor.AppendEndpoint(flop_input_vertex); + LogicCut cut = logic_extractor.BuildLogicCut(abc_library); + + utl::deleted_unique_ptr mapped_abc_network + = cut.BuildMappedAbcNetwork(abc_library, network, &logger_); + + rmp::UniqueName unique_name; + cut.InsertMappedAbcNetwork( + mapped_abc_network.get(), network, unique_name, &logger_); + + // Re-extract the same cone, and try to simulate it to make sure everything + // still simulates correctly + LogicExtractorFactory logic_extractor_post_insert(sta_.get(), &logger_); + logic_extractor_post_insert.AppendEndpoint(flop_input_vertex); + LogicCut cut_post_insert + = logic_extractor_post_insert.BuildLogicCut(abc_library); + + utl::deleted_unique_ptr mapped_abc_network_post_insert + = cut.BuildMappedAbcNetwork(abc_library, network, &logger_); + + abc::Abc_NtkSetName(mapped_abc_network_post_insert.get(), + strdup("temp_network_name")); + + utl::deleted_unique_ptr logic_network( + abc::Abc_NtkToLogic(mapped_abc_network_post_insert.get()), + &abc::Abc_NtkDelete); + + // Build map of primary output names to primary output indicies in ABC + std::map primary_output_name_to_index + = AbcLogicNetworkNameToPrimaryOutputIds(logic_network.get()); + + std::array input_vector = {1, 1}; + utl::deleted_unique_ptr output_vector( + abc::Abc_NtkVerifySimulatePattern(logic_network.get(), + input_vector.data()), + &free); + + // Both outputs are just the and gate. + EXPECT_EQ(output_vector.get()[primary_output_name_to_index.at("flop_net")], + 0); // Expect that !(1 & 1) == 0 + EXPECT_EQ(output_vector.get()[primary_output_name_to_index.at("and_output")], + 1); // Expect that (1 & 1) == 1 +} + } // namespace rmp