diff --git a/src/drt/src/db/gcObj/gcShape.h b/src/drt/src/db/gcObj/gcShape.h index 2166a1fc6cc..0d2c5c99508 100644 --- a/src/drt/src/db/gcObj/gcShape.h +++ b/src/drt/src/db/gcObj/gcShape.h @@ -76,6 +76,9 @@ class gcCorner : public gtl::point_data frCornerTypeEnum getType() const { return cornerType_; } frCornerDirEnum getDir() const { return cornerDir_; } bool isFixed() const { return fixed_; } + bool hasPin() const { return pin_; } + gcPin* getPin() const { return pin_; } + frLayerNum getLayerNum() const { return layer_num_; } // setters void setPrevCorner(gcCorner* in) { prevCorner_ = in; } @@ -85,8 +88,12 @@ class gcCorner : public gtl::point_data void setType(frCornerTypeEnum in) { cornerType_ = in; } void setDir(frCornerDirEnum in) { cornerDir_ = in; } void setFixed(bool in) { fixed_ = in; } + void addToPin(gcPin* in) { pin_ = in; } + void removeFromPin() { pin_ = nullptr; } + void setLayerNum(const frLayerNum in) { layer_num_ = in; } private: + gcPin* pin_{nullptr}; gcCorner* prevCorner_{nullptr}; gcCorner* nextCorner_{nullptr}; gcSegment* prevEdge_{nullptr}; @@ -95,6 +102,7 @@ class gcCorner : public gtl::point_data // points away from poly for convex and concave frCornerDirEnum cornerDir_{frCornerDirEnum::UNKNOWN}; bool fixed_{false}; + frLayerNum layer_num_{-1}; }; class gcSegment : public gtl::segment_data, public gcShape diff --git a/src/drt/src/db/tech/frConstraint.cc b/src/drt/src/db/tech/frConstraint.cc index d082c0eca84..9e99c7782ba 100644 --- a/src/drt/src/db/tech/frConstraint.cc +++ b/src/drt/src/db/tech/frConstraint.cc @@ -164,6 +164,8 @@ std::string frConstraint::getViolName() const return "Lef58MaxSpacing"; case frConstraintTypeEnum::frcSpacingTableOrth: return "SpacingTableOrth"; + case frConstraintTypeEnum::frcLef58WidthTableOrth: + return "WidthTableOrth"; } return ""; } diff --git a/src/drt/src/db/tech/frConstraint.h b/src/drt/src/db/tech/frConstraint.h index 193bb1d3d8f..aa57a3de212 100644 --- a/src/drt/src/db/tech/frConstraint.h +++ b/src/drt/src/db/tech/frConstraint.h @@ -2323,6 +2323,31 @@ class frLef58MaxSpacingConstraint : public frConstraint int cut_class_idx_{-1}; }; +class frLef58WidthTableOrthConstraint : public frConstraint +{ + public: + frLef58WidthTableOrthConstraint(const frCoord horz_spc, + const frCoord vert_spc) + : horz_spc_(horz_spc), vert_spc_(vert_spc) + { + } + frCoord getHorzSpc() const { return horz_spc_; } + frCoord getVertSpc() const { return vert_spc_; } + void report(utl::Logger* logger) const override + { + logger->report("LEF58_WIDTHTABLE ORTH"); + } + // typeId + frConstraintTypeEnum typeId() const override + { + return frConstraintTypeEnum::frcLef58WidthTableOrth; + } + + private: + frCoord horz_spc_; + frCoord vert_spc_; +}; + class frNonDefaultRule { public: diff --git a/src/drt/src/db/tech/frLayer.h b/src/drt/src/db/tech/frLayer.h index 14fa1041ac9..e0631e4dd69 100644 --- a/src/drt/src/db/tech/frLayer.h +++ b/src/drt/src/db/tech/frLayer.h @@ -836,6 +836,15 @@ class frLayer void printAllConstraints(utl::Logger* logger); + void setWidthTblOrthCon(frLef58WidthTableOrthConstraint* con) + { + width_tbl_orth_con_ = con; + } + frLef58WidthTableOrthConstraint* getWidthTblOrthCon() const + { + return width_tbl_orth_con_; + } + protected: odb::dbTechLayer* db_layer_{nullptr}; bool fakeCut_{false}; @@ -929,6 +938,7 @@ class frLayer frOrthSpacingTableConstraint* spc_tbl_orth_con_{nullptr}; drEolSpacingConstraint drEolCon_; + frLef58WidthTableOrthConstraint* width_tbl_orth_con_{nullptr}; friend class io::Parser; }; diff --git a/src/drt/src/frBaseTypes.cpp b/src/drt/src/frBaseTypes.cpp index c71a8254f0c..f8d585f0b1a 100644 --- a/src/drt/src/frBaseTypes.cpp +++ b/src/drt/src/frBaseTypes.cpp @@ -303,6 +303,8 @@ std::ostream& operator<<(std::ostream& os, frConstraintTypeEnum type) return os << "frcLef58MaxSpacingConstraint"; case frConstraintTypeEnum::frcSpacingTableOrth: return os << "frcSpacingTableOrth"; + case frConstraintTypeEnum::frcLef58WidthTableOrth: + return os << "frcLef58WidthTableOrth"; } return os << "Bad frConstraintTypeEnum"; } diff --git a/src/drt/src/frBaseTypes.h b/src/drt/src/frBaseTypes.h index 01d58d71581..4043826c521 100644 --- a/src/drt/src/frBaseTypes.h +++ b/src/drt/src/frBaseTypes.h @@ -210,7 +210,8 @@ enum class frConstraintTypeEnum frcLef58EnclosureConstraint, frcSpacingRangeConstraint, frcLef58MaxSpacingConstraint, - frcSpacingTableOrth + frcSpacingTableOrth, + frcLef58WidthTableOrth }; std::ostream& operator<<(std::ostream& os, frConstraintTypeEnum type); diff --git a/src/drt/src/gc/FlexGC_impl.h b/src/drt/src/gc/FlexGC_impl.h index 40e638c7cd8..973f1cd48f8 100644 --- a/src/drt/src/gc/FlexGC_impl.h +++ b/src/drt/src/gc/FlexGC_impl.h @@ -295,8 +295,8 @@ class FlexGCWorker::Impl gcRect* rect, frLef58TwoWiresForbiddenSpcConstraint* con); box_t checkMetalCornerSpacing_getQueryBox(gcCorner* corner, - frCoord& maxSpcValX, - frCoord& maxSpcValY); + frCoord maxSpcValX, + frCoord maxSpcValY); void checkMetalCornerSpacing(); void checkMetalCornerSpacing_getMaxSpcVal(frLayerNum layerNum, frCoord& maxSpcValX, @@ -307,6 +307,8 @@ class FlexGCWorker::Impl gcRect* rect, frLef58CornerSpacingConstraint* con); + void checkWidthTableOrth(gcCorner* corner); + void checkWidthTableOrth_main(gcCorner* corner1, gcCorner* corner2); void checkMetalShape(bool allow_patching = false); void checkMetalShape_main(gcPin* pin, bool allow_patching); void checkMetalShape_minWidth(const gtl::rectangle_data& rect, diff --git a/src/drt/src/gc/FlexGC_init.cpp b/src/drt/src/gc/FlexGC_init.cpp index d2a7007c76a..4575e6a5962 100644 --- a/src/drt/src/gc/FlexGC_init.cpp +++ b/src/drt/src/gc/FlexGC_init.cpp @@ -759,8 +759,10 @@ void FlexGCWorker::Impl::initNet_pins_polygonCorners_helper(gcNet* net, prevEdge->setHighCorner(currCorner); nextEdge->setLowCorner(currCorner); // set currCorner attributes + currCorner->addToPin(pin); currCorner->setPrevEdge(prevEdge); currCorner->setNextEdge(nextEdge.get()); + currCorner->setLayerNum(layerNum); currCorner->x(prevEdge->high().x()); currCorner->y(prevEdge->high().y()); int orient = gtl::orientation(*prevEdge, *nextEdge); diff --git a/src/drt/src/gc/FlexGC_main.cpp b/src/drt/src/gc/FlexGC_main.cpp index 2375798e449..b29d23866d0 100644 --- a/src/drt/src/gc/FlexGC_main.cpp +++ b/src/drt/src/gc/FlexGC_main.cpp @@ -194,12 +194,12 @@ bool FlexGCWorker::Impl::isOppositeDir(gcCorner* corner, gcSegment* seg) box_t FlexGCWorker::Impl::checkMetalCornerSpacing_getQueryBox( gcCorner* corner, - frCoord& maxSpcValX, - frCoord& maxSpcValY) + const frCoord maxSpcValX, + const frCoord maxSpcValY) { box_t queryBox; - frCoord baseX = corner->getNextEdge()->low().x(); - frCoord baseY = corner->getNextEdge()->low().y(); + frCoord baseX = corner->x(); + frCoord baseY = corner->y(); frCoord llx = baseX; frCoord lly = baseY; frCoord urx = baseX; @@ -1384,14 +1384,20 @@ void FlexGCWorker::Impl::checkMetalCornerSpacing() i++) { auto currLayer = getTech()->getLayer(i); if (currLayer->getType() != dbTechLayerType::ROUTING - || !currLayer->hasLef58CornerSpacingConstraint()) { + || (!currLayer->hasLef58CornerSpacingConstraint() + && currLayer->getWidthTblOrthCon() == nullptr)) { continue; } for (auto& pin : targetNet_->getPins(i)) { for (auto& corners : pin->getPolygonCorners()) { for (auto& corner : corners) { // LEF58 corner spacing - checkMetalCornerSpacing_main(corner.get()); + if (currLayer->hasLef58CornerSpacingConstraint()) { + checkMetalCornerSpacing_main(corner.get()); + } + if (currLayer->getWidthTblOrthCon()) { + checkWidthTableOrth(corner.get()); + } } } } @@ -1405,7 +1411,8 @@ void FlexGCWorker::Impl::checkMetalCornerSpacing() i++) { auto currLayer = getTech()->getLayer(i); if (currLayer->getType() != dbTechLayerType::ROUTING - || !currLayer->hasLef58CornerSpacingConstraint()) { + || (!currLayer->hasLef58CornerSpacingConstraint() + && currLayer->getWidthTblOrthCon() == nullptr)) { continue; } for (auto& net : getNets()) { @@ -1413,7 +1420,12 @@ void FlexGCWorker::Impl::checkMetalCornerSpacing() for (auto& corners : pin->getPolygonCorners()) { for (auto& corner : corners) { // LEF58 corner spacing - checkMetalCornerSpacing_main(corner.get()); + if (currLayer->hasLef58CornerSpacingConstraint()) { + checkMetalCornerSpacing_main(corner.get()); + } + if (currLayer->getWidthTblOrthCon()) { + checkWidthTableOrth(corner.get()); + } } } } @@ -1422,6 +1434,78 @@ void FlexGCWorker::Impl::checkMetalCornerSpacing() } } +void FlexGCWorker::Impl::checkWidthTableOrth_main(gcCorner* corner1, + gcCorner* corner2) +{ + if (corner2 == nullptr) { + return; + } + if (corner1 == corner2) { + return; + } + if (corner2->getType() != frCornerTypeEnum::CONCAVE) { + return; + } + if (corner1->isFixed() && corner2->isFixed()) { + return; + } + const auto layer_num = corner1->getLayerNum(); + const auto layer = getTech()->getLayer(layer_num); + const auto con = layer->getWidthTblOrthCon(); + const frCoord horz_spc = con->getHorzSpc(); + const frCoord vert_spc = con->getVertSpc(); + + Rect marker_rect(corner1->x(), corner1->y(), corner2->x(), corner2->y()); + if (marker_rect.dx() >= horz_spc || marker_rect.dy() >= vert_spc) { + return; + } + const auto owner = corner1->getPin()->getNet()->getOwner(); + auto marker = std::make_unique(); + marker->setBBox(marker_rect); + marker->setLayerNum(layer_num); + marker->setConstraint(con); + marker->addSrc(owner); + marker->addVictim( + owner, + std::make_tuple( + layer_num, + Rect(corner1->x(), corner1->y(), corner1->x(), corner1->y()), + corner1->isFixed())); + marker->addAggressor( + owner, + std::make_tuple( + layer_num, + Rect(corner2->x(), corner2->y(), corner2->x(), corner2->y()), + corner2->isFixed())); + addMarker(std::move(marker)); +} + +void FlexGCWorker::Impl::checkWidthTableOrth(gcCorner* corner) +{ + // applied only to inside corners (CONCAVE) + if (corner->getType() != frCornerTypeEnum::CONCAVE) { + return; + } + auto layer_num = corner->getLayerNum(); + auto layer = getTech()->getLayer(layer_num); + auto con = layer->getWidthTblOrthCon(); + const frCoord horz_spc = con->getHorzSpc(); + const frCoord vert_spc = con->getVertSpc(); + Rect query_rect(corner->x() - horz_spc, + corner->y() - vert_spc, + corner->x() + horz_spc, + corner->y() + vert_spc); + std::vector> result; + getWorkerRegionQuery().queryPolygonEdge(query_rect, layer_num, result); + for (auto [_, edge] : result) { + if (edge->getPin() != corner->getPin()) { + continue; + } + checkWidthTableOrth_main(corner, edge->getLowCorner()); + checkWidthTableOrth_main(corner, edge->getHighCorner()); + } +} + void FlexGCWorker::Impl::checkMetalShape_minWidth( const gtl::rectangle_data& rect, frLayerNum layerNum, @@ -4128,7 +4212,7 @@ int FlexGCWorker::Impl::main() } // clear existing markers clearMarkers(); - // check LEF58CornerSpacing + // check LEF58CornerSpacing and LEF58WidthTable ORTH checkMetalCornerSpacing(); // check Short, NSMet, MetSpc based on max rectangles checkMetalSpacing(); diff --git a/src/drt/src/io/io.cpp b/src/drt/src/io/io.cpp index baad602d750..699fb32001d 100644 --- a/src/drt/src/io/io.cpp +++ b/src/drt/src/io/io.cpp @@ -1665,6 +1665,32 @@ void io::Parser::setRoutingLayerProperties(odb::dbTechLayer* layer, tmpLayer->addForbiddenSpacingConstraint(con.get()); getTech()->addUConstraint(std::move(con)); } + if (!layer->getTechLayerWidthTableRules().empty()) { + frUInt4 width = 0; + frUInt4 wrongway_width = 0; + for (auto rule : layer->getTechLayerWidthTableRules()) { + if (!rule->isOrthogonal()) { + continue; + } + if (rule->isWrongDirection()) { + wrongway_width = rule->getWidthTable().at(0); + } else { + width = rule->getWidthTable().at(0); + } + } + if (wrongway_width == 0) { + wrongway_width = width; + } + if (width != 0 || wrongway_width != 0) { + const bool is_horz = tmpLayer->isHorizontal(); + const frCoord horz_spc = is_horz ? wrongway_width : width; + const frCoord vert_spc = is_horz ? width : wrongway_width; + auto ucon = std::make_unique(horz_spc, + vert_spc); + tmpLayer->setWidthTblOrthCon(ucon.get()); + getTech()->addUConstraint(std::move(ucon)); + } + } } void io::Parser::setCutLayerProperties(odb::dbTechLayer* layer, diff --git a/src/drt/test/fixture.cpp b/src/drt/test/fixture.cpp index 80aa7e6a672..96cfe2b7aba 100644 --- a/src/drt/test/fixture.cpp +++ b/src/drt/test/fixture.cpp @@ -396,6 +396,21 @@ frSpacingTableTwConstraint* Fixture::makeSpacingTableTwConstraint( return rptr; } +frLef58WidthTableOrthConstraint* Fixture::makeWidthTblOrthConstraint( + frLayerNum layer_num, + frCoord horz_spc, + frCoord vert_spc) +{ + frTechObject* tech = design->getTech(); + frLayer* layer = tech->getLayer(layer_num); + std::unique_ptr uCon + = std::make_unique(horz_spc, vert_spc); + auto rptr = static_cast(uCon.get()); + tech->addUConstraint(std::move(uCon)); + layer->setWidthTblOrthCon(rptr); + return rptr; +} + void Fixture::makeLef58EolKeepOutConstraint(frLayerNum layer_num, bool cornerOnly, bool exceptWithin, diff --git a/src/drt/test/fixture.h b/src/drt/test/fixture.h index 951d03461e3..be794dcea54 100644 --- a/src/drt/test/fixture.h +++ b/src/drt/test/fixture.h @@ -219,6 +219,11 @@ class Fixture std::vector widthTbl, std::vector prlTbl, std::vector> spacingTbl); + + frLef58WidthTableOrthConstraint* makeWidthTblOrthConstraint( + frLayerNum layer_num, + frCoord horz_spc, + frCoord vert_spc); void initRegionQuery(); frLef58CutSpacingConstraint* makeLef58CutSpacingConstraint_parallelOverlap( frLayerNum layer_num, diff --git a/src/drt/test/gcTest.cpp b/src/drt/test/gcTest.cpp index d0713af8919..021fd017453 100644 --- a/src/drt/test/gcTest.cpp +++ b/src/drt/test/gcTest.cpp @@ -1496,6 +1496,29 @@ BOOST_DATA_TEST_CASE(cut_spc_tbl_orth, } } +BOOST_DATA_TEST_CASE(width_tbl_orth, + (bdata::make({40, 50, 60}) * bdata::make({40, 50, 60})), + horz_spc, + vert_spc) +{ + makeWidthTblOrthConstraint(2, horz_spc, vert_spc); + design->getTech()->getLayer(2)->setMinWidth( + 10); // to ignore NSMetal violations + frNet* n1 = makeNet("n1"); + makePathseg(n1, 2, {0, 100}, {200, 100}, 100); + makePathseg(n1, 2, {150, 50}, {350, 50}, 100); + const frCoord dx = 50; + const frCoord dy = 50; + const bool violating = dx < horz_spc && dy < vert_spc; + runGC(); + auto& markers = worker.getMarkers(); + if (violating) { + BOOST_TEST(markers.size() == 1); + } else { + BOOST_TEST(markers.size() == 0); + } +} + BOOST_AUTO_TEST_SUITE_END(); } // namespace drt