diff --git a/src/database/data/design/IdbEnum.h b/src/database/data/design/IdbEnum.h index 3d3746112..0e252c79c 100644 --- a/src/database/data/design/IdbEnum.h +++ b/src/database/data/design/IdbEnum.h @@ -388,6 +388,7 @@ enum class IdbLayerSpacingType : uint8_t kSpacingDefault, kSpacingRange, kSpacingRangeLenThreshold, + kSpacingEndOfLine, //!-----tbd------------- kMax }; diff --git a/src/database/data/design/db_layout/IdbLayer.h b/src/database/data/design/db_layout/IdbLayer.h index 00239857a..ef6e84713 100644 --- a/src/database/data/design/db_layout/IdbLayer.h +++ b/src/database/data/design/db_layout/IdbLayer.h @@ -110,12 +110,24 @@ class IdbLayerSpacing const int32_t get_min_spacing() const { return _min_spacing; } const int32_t get_min_width() const { return _min_width; } const int32_t get_max_width() const { return _max_width; } + const int32_t get_eol_width() const { return _eol_width; } + const int32_t get_eol_within() const { return _eol_within; } + const bool get_has_parallel_edge() const { return _has_parallel_edge; } + const int32_t get_par_space() const { return _par_space; } + const int32_t get_par_within() const { return _par_within; } + const bool get_has_two_edges() const { return _has_two_edges; } // setter void set_spacing_type(IdbLayerSpacingType spacing_type) { _spacing_type = spacing_type; } void set_min_spacing(int32_t min_spacing) { _min_spacing = min_spacing; } void set_min_width(int32_t min_width) { _min_width = min_width; } void set_max_width(int32_t max_width) { _max_width = max_width; } + void set_eol_width(int32_t eol_width) { _eol_width = eol_width; } + void set_eol_within(int32_t eol_within) { _eol_within = eol_within; } + void set_has_parallel_edge(bool has_parallel_edge) { _has_parallel_edge = has_parallel_edge; } + void set_par_space(int32_t par_space) { _par_space = par_space; } + void set_par_within(int32_t par_within) { _par_within = par_within; } + void set_has_two_edges(bool has_two_edges) { _has_two_edges = has_two_edges; } // operator bool isDefault() { return _spacing_type == IdbLayerSpacingType::kSpacingDefault ? true : false; } @@ -126,6 +138,14 @@ class IdbLayerSpacing int32_t _min_spacing; int32_t _min_width; int32_t _max_width; + + // end of line + int32_t _eol_width; + int32_t _eol_within; + bool _has_parallel_edge; + int32_t _par_space; + int32_t _par_within; + bool _has_two_edges; }; class IdbLayerSpacingList @@ -343,6 +363,7 @@ class IdbLayerRouting : public IdbLayer std::vector>& get_lef58_spacing_eol_list() { return _lef58_spacing_eol_list; }; std::vector>& get_lef58_area() { return _lef58_area; } std::shared_ptr get_lef58_corner_fill_spacing() { return _lef58_corner_fill_spacing; } + std::vector>& get_lef58_corner_spacing_list() { return _lef58_corner_spacing_list; } std::vector>& get_lef58_minimum_cut() { return _lef58_minimum_cut; } std::vector>& get_lef58_min_step() { return _lef58_min_steps; } std::shared_ptr get_lef58_spacing_notchlength() { return _lef58_spacing_notchlength; } @@ -392,6 +413,10 @@ class IdbLayerRouting : public IdbLayer { _lef58_corner_fill_spacing = std::move(cornerfill_spacing); } + void add_lef58_corner_spacing(std::shared_ptr corner_spacing) + { + _lef58_corner_spacing_list.emplace_back(std::move(corner_spacing)); + } void add_lef58_minimum_cut(std::shared_ptr minimum_cut) { _lef58_minimum_cut.push_back(std::move(minimum_cut)); @@ -443,6 +468,7 @@ class IdbLayerRouting : public IdbLayer std::vector> _lef58_spacing_eol_list; std::vector> _lef58_area; std::shared_ptr _lef58_corner_fill_spacing; + std::vector> _lef58_corner_spacing_list; std::vector> _lef58_minimum_cut; std::vector> _lef58_min_steps; std::shared_ptr _lef58_spacing_notchlength; @@ -556,9 +582,13 @@ class IdbLayerCutSpacing void set_adjacent_cuts(std::optional adj) { _adjacnet_cuts = adj; } [[nodiscard]] std::optional get_adjacent_cuts() const { return _adjacnet_cuts; } + void set_has_same_net(bool has_same_net) { _has_same_net = has_same_net; }; + [[nodiscard]] bool get_has_same_net() const { return _has_same_net; } + private: int32_t _spacing; std::optional _adjacnet_cuts; + bool _has_same_net; }; class IdbLayerCut : public IdbLayer diff --git a/src/database/data/design/db_layout/IdbLayer_routing.cpp b/src/database/data/design/db_layout/IdbLayer_routing.cpp index 9df2d52f0..509922512 100644 --- a/src/database/data/design/db_layout/IdbLayer_routing.cpp +++ b/src/database/data/design/db_layout/IdbLayer_routing.cpp @@ -72,6 +72,12 @@ IdbLayerSpacing::IdbLayerSpacing() _min_spacing = -1; _min_width = -1; _max_width = -1; + _eol_width = -1; + _eol_within = -1; + _has_parallel_edge = false; + _par_space = -1; + _par_within = -1; + _has_two_edges = false; } IdbLayerSpacing::~IdbLayerSpacing() { diff --git a/src/database/data/design/db_property/IdbRoutingLayerLef58Property.h b/src/database/data/design/db_property/IdbRoutingLayerLef58Property.h index 1ad9496e3..35868043d 100644 --- a/src/database/data/design/db_property/IdbRoutingLayerLef58Property.h +++ b/src/database/data/design/db_property/IdbRoutingLayerLef58Property.h @@ -101,6 +101,51 @@ class Lef58CornerFillSpacing int32_t _eol_width; }; +// LEF58_CORNERSPACING +class Lef58CornerSpacing +{ + public: + enum class CornerType + { + kNone, + kConvexCorner, + kConcaveCorner + }; + + class WidthSpacing + { + public: + WidthSpacing() = default; + WidthSpacing(int32_t width, int32_t spacing) : _width(width), _spacing(spacing) {} + + [[nodiscard]] int32_t get_width() const { return _width; } + [[nodiscard]] int32_t get_spacing() const { return _spacing; } + void set_width(int32_t width) { _width = width; } + void set_spacing(int32_t spacing) { _spacing = spacing; } + + private: + int32_t _width; + int32_t _spacing; + }; + + [[nodiscard]] CornerType get_corner_type() const { return _corner_type; } + [[nodiscard]] std::optional get_except_eol() const { return _except_eol; } + [[nodiscard]] const std::vector& get_width_spacing_list() const { return _width_spacing_list; } + + void set_corner_type(CornerType corner_type) { _corner_type = corner_type; } + void set_except_eol(int32_t except_eol) { _except_eol = except_eol; } + template + void add_width_spacing(Args&&... args) + { + _width_spacing_list.emplace_back(std::forward(args)...); + } + + private: + CornerType _corner_type = CornerType::kNone; + std::optional _except_eol; + std::vector _width_spacing_list; +}; + // LEF58_MINIMUMCUT class Lef58MinimumCut { diff --git a/src/database/manager/builder/lef_builder/lef_read.cpp b/src/database/manager/builder/lef_builder/lef_read.cpp index fb7365a05..fc6cf70d6 100644 --- a/src/database/manager/builder/lef_builder/lef_read.cpp +++ b/src/database/manager/builder/lef_builder/lef_read.cpp @@ -495,6 +495,7 @@ int LefRead::parse_layer_cut(lefiLayer* lef_layer, IdbLayerCut* layer_cut) double cut_within = lef_layer->spacingAdjacentWithin(i); spacing->set_adjacent_cuts(IdbLayerCutSpacing::AdjacentCuts(adj_cuts, transUnitDB(cut_within))); } + spacing->set_has_same_net(lef_layer->hasSpacingSamenet(i)); layer_cut->add_spacing(spacing); } @@ -670,6 +671,19 @@ int LefRead::parse_layer_routing(lefiLayer* lef_layer, IdbLayerRouting* layer_ro auto& spacing_notch = layer_routing->get_spacing_notchlength(); spacing_notch.set_notch_length(transUnitDB(lef_layer->spacingNotchLength(i))); spacing_notch.set_min_spacing(transUnitDB(lef_layer->spacing(i))); + // 如果有notchLength关键字,不能再算作Spacing规则 + continue; + } + if (lef_layer->hasSpacingEndOfLine(i)) { + layer_spacing->set_spacing_type(IdbLayerSpacingType::kSpacingEndOfLine); + layer_spacing->set_eol_width(transUnitDB(lef_layer->spacingEolWidth(i))); + layer_spacing->set_eol_within(transUnitDB(lef_layer->spacingEolWithin(i))); + layer_spacing->set_has_parallel_edge(lef_layer->hasSpacingParellelEdge(i)); + if (layer_spacing->get_has_parallel_edge()) { + layer_spacing->set_par_space(transUnitDB(lef_layer->spacingParSpace(i))); + layer_spacing->set_par_within(transUnitDB(lef_layer->spacingParWithin(i))); + layer_spacing->set_has_two_edges(lef_layer->hasSpacingTwoEdges(i)); + } } spacing_list->add_spacing(layer_spacing); } diff --git a/src/database/manager/builder/lef_builder/property_parser/lef58_property/routinglayer_property.h b/src/database/manager/builder/lef_builder/property_parser/lef58_property/routinglayer_property.h index 2a07c489d..50201b80f 100644 --- a/src/database/manager/builder/lef_builder/property_parser/lef58_property/routinglayer_property.h +++ b/src/database/manager/builder/lef_builder/property_parser/lef58_property/routinglayer_property.h @@ -233,6 +233,25 @@ struct lef58_spacingtable_jogtojog std::vector _width; }; +////////////////////////////////// +// LEF58_CORNERSPACING // +////////////////////////////////// + +struct lef58_cornerspacing_width +{ + double _width; + double _spacing; +}; + +struct lef58_cornerspacing +{ + std::string _corner_type; + std::optional _except_eol; + std::vector _width_spacings; +}; + + + } // namespace idb::routinglayer_property BOOST_FUSION_ADAPT_STRUCT(idb::routinglayer_property::double_pair, (double, first)(double, second)) @@ -322,4 +341,8 @@ BOOST_FUSION_ADAPT_STRUCT(idb::routinglayer_property::lef58_spacingtable_jogtojo _width_short_jog_spacing)) BOOST_FUSION_ADAPT_STRUCT(idb::routinglayer_property::lef58_spacingtable_jogtojog, (double, _jog2jog_spacing)(double, _jog_width)(double, _short_jog_spacing)( - std::vector, _width)) \ No newline at end of file + std::vector, _width)) +BOOST_FUSION_ADAPT_STRUCT(idb::routinglayer_property::lef58_cornerspacing_width, (double, _width)(double, _spacing)) +BOOST_FUSION_ADAPT_STRUCT(idb::routinglayer_property::lef58_cornerspacing, + (std::string, _corner_type)(std::optional, _except_eol)( + std::vector, _width_spacings)) diff --git a/src/database/manager/builder/lef_builder/property_parser/lef58_property/routinglayer_property_parser.h b/src/database/manager/builder/lef_builder/property_parser/lef58_property/routinglayer_property_parser.h index cc38715a9..e3725f6e6 100644 --- a/src/database/manager/builder/lef_builder/property_parser/lef58_property/routinglayer_property_parser.h +++ b/src/database/manager/builder/lef_builder/property_parser/lef58_property/routinglayer_property_parser.h @@ -26,6 +26,9 @@ namespace idb::routinglayer_property { template bool parse_lef58_conerfillspacing(Iterator beg, Iterator end, lef58_cornerfillspacing& spacing); + template + bool parse_lef58_cornerspacing(Iterator beg, Iterator end, std::vector& spacings); + template bool parse_lef58_minimumcut(Iterator beg, Iterator end, std::vector& cuts); @@ -72,6 +75,25 @@ namespace idb::routinglayer_property { return true; } + template + bool parse_lef58_cornerspacing(Iterator beg, Iterator end, std::vector& spacings) { + const static qi::rule width_spacing_rule = + lit("WIDTH") >> double_ >> lit("SPACING") >> double_; + const static qi::rule corner_spacing_rule = + lit("CORNERSPACING") + >> (qi::string("CONVEXCORNER") | qi::string("CONCAVECORNER")) + >> -(lit("EXCEPTEOL") >> double_) + >> +width_spacing_rule + >> lit(";"); + + bool ok = qi::phrase_parse(beg, end, +corner_spacing_rule, space, spacings); + if (!ok || beg != end) { + std::cout << "Parse \"" << std::string(beg, end) << "\" failed" << std::endl; + return false; + } + return true; + } + template bool parse_lef58_minimumcut(Iterator beg, Iterator end, std::vector& cuts){ const static qi::rule value_string = lexeme[+(char_ - char_(" ;\n"))]; @@ -221,4 +243,4 @@ namespace idb::routinglayer_property { } return true; } -} // namespace idb::routinglayer_property \ No newline at end of file +} // namespace idb::routinglayer_property diff --git a/src/database/manager/builder/lef_builder/property_parser/lef58_property/test/test_routinglayer.cc b/src/database/manager/builder/lef_builder/property_parser/lef58_property/test/test_routinglayer.cc index 5e9ddbf3c..730808141 100644 --- a/src/database/manager/builder/lef_builder/property_parser/lef58_property/test/test_routinglayer.cc +++ b/src/database/manager/builder/lef_builder/property_parser/lef58_property/test/test_routinglayer.cc @@ -90,6 +90,43 @@ TEST(RoutingLayerTest, LEF58CORNERFILLSPACING) { EXPECT_EQ(spacing._eol_width, 0.06); } +TEST(RoutingLayerTest, LEF58CORNERSPACINGMultipleRules) { + std::vector spacings; + const std::string str = R"( + CORNERSPACING CONVEXCORNER EXCEPTEOL 0.08 + WIDTH 0.00 SPACING 0.10 + WIDTH 0.20 SPACING 0.20 + WIDTH 0.50 SPACING 0.30 ; + CORNERSPACING CONCAVECORNER + WIDTH 0.00 SPACING 0.12 + WIDTH 0.18 SPACING 0.22 ;)"; + + bool ok = parse_lef58_cornerspacing(str.begin(), str.end(), spacings); + EXPECT_TRUE(ok); + ASSERT_EQ(spacings.size(), 2); + + const auto& convex_spacing = spacings[0]; + EXPECT_EQ(convex_spacing._corner_type, "CONVEXCORNER"); + EXPECT_TRUE(convex_spacing._except_eol.has_value()); + EXPECT_EQ(convex_spacing._except_eol.value(), 0.08); + EXPECT_EQ(convex_spacing._width_spacings.size(), 3); + EXPECT_EQ(convex_spacing._width_spacings[0]._width, 0.00); + EXPECT_EQ(convex_spacing._width_spacings[0]._spacing, 0.10); + EXPECT_EQ(convex_spacing._width_spacings[1]._width, 0.20); + EXPECT_EQ(convex_spacing._width_spacings[1]._spacing, 0.20); + EXPECT_EQ(convex_spacing._width_spacings[2]._width, 0.50); + EXPECT_EQ(convex_spacing._width_spacings[2]._spacing, 0.30); + + const auto& concave_spacing = spacings[1]; + EXPECT_EQ(concave_spacing._corner_type, "CONCAVECORNER"); + EXPECT_FALSE(concave_spacing._except_eol.has_value()); + EXPECT_EQ(concave_spacing._width_spacings.size(), 2); + EXPECT_EQ(concave_spacing._width_spacings[0]._width, 0.00); + EXPECT_EQ(concave_spacing._width_spacings[0]._spacing, 0.12); + EXPECT_EQ(concave_spacing._width_spacings[1]._width, 0.18); + EXPECT_EQ(concave_spacing._width_spacings[1]._spacing, 0.22); +} + TEST(RoutingLayerTest, LEF58MINIMUNCUT) { std::vector cuts; const std::string str = R"( diff --git a/src/database/manager/builder/lef_builder/property_parser/routinglayer_parser.cpp b/src/database/manager/builder/lef_builder/property_parser/routinglayer_parser.cpp index 98a9dd359..7f6829d6d 100644 --- a/src/database/manager/builder/lef_builder/property_parser/routinglayer_parser.cpp +++ b/src/database/manager/builder/lef_builder/property_parser/routinglayer_parser.cpp @@ -32,6 +32,9 @@ bool RoutingLayerParser::parse(const std::string& name, const std::string& value if (name == "LEF58_CORNERFILLSPACING") { return parse_lef58_conerfillspacing(value, data); } + if (name == "LEF58_CORNERSPACING") { + return parse_lef58_cornerspacing(value, data); + } if (name == "LEF58_MINIMUMCUT") { return parse_lef58_minimuncut(value, data); } @@ -95,6 +98,34 @@ bool RoutingLayerParser::parse_lef58_conerfillspacing(const std::string& value, cornerfill_spacing->set_eol_width(transUnitDB(cornerspacing._eol_width)); return true; } +bool RoutingLayerParser::parse_lef58_cornerspacing(const std::string& value, IdbLayerRouting* data) +{ + std::vector cornerspacings; + bool parse_ok = routinglayer_property::parse_lef58_cornerspacing(value.begin(), value.end(), cornerspacings); + if (not parse_ok) { + return false; + } + + for (const auto& cornerspacing : cornerspacings) { + auto corner_spacing = std::make_shared(); + data->add_lef58_corner_spacing(corner_spacing); + + if (cornerspacing._corner_type == "CONVEXCORNER") { + corner_spacing->set_corner_type(routinglayer::Lef58CornerSpacing::CornerType::kConvexCorner); + } else if (cornerspacing._corner_type == "CONCAVECORNER") { + corner_spacing->set_corner_type(routinglayer::Lef58CornerSpacing::CornerType::kConcaveCorner); + } + + if (cornerspacing._except_eol.has_value()) { + corner_spacing->set_except_eol(transUnitDB(cornerspacing._except_eol.value())); + } + + for (const auto& width_spacing : cornerspacing._width_spacings) { + corner_spacing->add_width_spacing(transUnitDB(width_spacing._width), transUnitDB(width_spacing._spacing)); + } + } + return true; +} bool RoutingLayerParser::parse_lef58_minimuncut(const std::string& value, IdbLayerRouting* data) { std::vector minimuncuts; @@ -303,4 +334,4 @@ bool RoutingLayerParser::parse_lef58_spacingtable(const std::string& value, IdbL return false; } -} // namespace idb \ No newline at end of file +} // namespace idb diff --git a/src/database/manager/builder/lef_builder/property_parser/routinglayer_parser.h b/src/database/manager/builder/lef_builder/property_parser/routinglayer_parser.h index 892fa72ba..27d3dc0e9 100644 --- a/src/database/manager/builder/lef_builder/property_parser/routinglayer_parser.h +++ b/src/database/manager/builder/lef_builder/property_parser/routinglayer_parser.h @@ -29,6 +29,7 @@ class RoutingLayerParser : public PropertyBaseParser private: bool parse_lef58_area(const std::string& value, IdbLayerRouting* data); bool parse_lef58_conerfillspacing(const std::string& value, IdbLayerRouting* data); + bool parse_lef58_cornerspacing(const std::string& value, IdbLayerRouting* data); bool parse_lef58_minimuncut(const std::string& value, IdbLayerRouting* data); bool parse_lef58_minstep(const std::string& value, IdbLayerRouting* data); bool parse_lef58_spacing(const std::string& value, IdbLayerRouting* data); diff --git a/src/operation/iDRC/interface/DRCInterface.cpp b/src/operation/iDRC/interface/DRCInterface.cpp index e82d3d7f7..3132eac75 100644 --- a/src/operation/iDRC/interface/DRCInterface.cpp +++ b/src/operation/iDRC/interface/DRCInterface.cpp @@ -17,10 +17,14 @@ #include "DRCInterface.hpp" +#include "AdjacentCutSpacingRule.hpp" #include "DataManager.hpp" #include "GDSPlotter.hpp" +#include "IdbEnum.h" #include "Monitor.hpp" +#include "ParallelRunLengthSpacingRule.hpp" #include "RuleValidator.hpp" +#include "SameLayerCutSpacingRule.hpp" #include "feature_manager.h" #include "idm.h" @@ -87,7 +91,7 @@ void DRCInterface::checkDef() } printSummary(type_violation_map); outputViolationJson(type_violation_map); - // outputViolationFile(type_violation_map); + outputViolationFile(type_violation_map); outputTofeature(type_violation_map); } @@ -451,6 +455,26 @@ void DRCInterface::wrapRoutingDesignRule(RoutingLayer& routing_layer, idb::IdbLa exist_rule_set.insert(ViolationType::kCornerFillSpacing); } } + // CornerSpacingRule + { + std::vector& corner_spacing_rule_list = routing_layer.get_corner_spacing_rule_list(); + if (!idb_layer->get_lef58_corner_spacing_list().empty()) { + for (const std::shared_ptr& idb_corner_spacing : idb_layer->get_lef58_corner_spacing_list()) { + CornerSpacingRule corner_spacing_rule; + corner_spacing_rule.has_convex_corner = idb_corner_spacing->get_corner_type() == idb::routinglayer::Lef58CornerSpacing::CornerType::kConvexCorner; + corner_spacing_rule.has_concave_corner = idb_corner_spacing->get_corner_type() == idb::routinglayer::Lef58CornerSpacing::CornerType::kConcaveCorner; + corner_spacing_rule.has_except_eol = idb_corner_spacing->get_except_eol().has_value(); + if (idb_corner_spacing->get_except_eol().has_value()) { + corner_spacing_rule.except_eol = idb_corner_spacing->get_except_eol().value(); + } + for (const auto& width_spacing : idb_corner_spacing->get_width_spacing_list()) { + corner_spacing_rule.width_spacing_list.emplace_back(width_spacing.get_width(), width_spacing.get_spacing()); + } + corner_spacing_rule_list.push_back(std::move(corner_spacing_rule)); + } + exist_rule_set.insert(ViolationType::kCornerSpacing); + } + } // EndOfLineSpacingRule { std::vector& end_of_line_spacing_rule_list = routing_layer.get_end_of_line_spacing_rule_list(); @@ -494,6 +518,23 @@ void DRCInterface::wrapRoutingDesignRule(RoutingLayer& routing_layer, idb::IdbLa } exist_rule_set.insert(ViolationType::kEndOfLineSpacing); } + + if (idb_layer->get_spacing_list() != nullptr) { + for (auto& spacing_rule : idb_layer->get_spacing_list()->get_spacing_list()) { + EndOfLineSpacingRule end_of_line_spacing_rule; + if (spacing_rule->get_spacing_type() == idb::IdbLayerSpacingType::kSpacingEndOfLine) { + end_of_line_spacing_rule.eol_spacing = spacing_rule->get_min_spacing(); + end_of_line_spacing_rule.eol_width = spacing_rule->get_eol_width(); + end_of_line_spacing_rule.eol_within = spacing_rule->get_eol_within(); + end_of_line_spacing_rule.has_par = spacing_rule->get_has_parallel_edge(); + end_of_line_spacing_rule.par_spacing = spacing_rule->get_par_space(); + end_of_line_spacing_rule.par_within = spacing_rule->get_par_within(); + end_of_line_spacing_rule.has_two_edges = spacing_rule->get_has_parallel_edge() && spacing_rule->get_has_two_edges(); + end_of_line_spacing_rule_list.push_back(end_of_line_spacing_rule); + exist_rule_set.insert(ViolationType::kEndOfLineSpacing); + } + } + } } // MaximumWidthRule { @@ -601,15 +642,8 @@ void DRCInterface::wrapRoutingDesignRule(RoutingLayer& routing_layer, idb::IdbLa { ParallelRunLengthSpacingRule& parallel_run_length_spacing_rule = routing_layer.get_parallel_run_length_spacing_rule(); std::shared_ptr idb_spacing_table; - bool exist_spacing_table = false; if (idb_layer->get_spacing_table().get()->get_parallel().get() != nullptr && idb_layer->get_spacing_table().get()->is_parallel()) { idb_spacing_table = idb_layer->get_spacing_table()->get_parallel(); - exist_spacing_table = true; - } else if (idb_layer->get_spacing_list() != nullptr && !idb_layer->get_spacing_table().get()->is_parallel()) { - idb_spacing_table = idb_layer->get_spacing_table_from_spacing_list()->get_parallel(); - exist_spacing_table = true; - } - if (exist_spacing_table) { std::vector& width_list = parallel_run_length_spacing_rule.width_list; std::vector& parallel_length_list = parallel_run_length_spacing_rule.parallel_length_list; GridMap& width_parallel_length_map = parallel_run_length_spacing_rule.width_parallel_length_map; @@ -622,6 +656,28 @@ void DRCInterface::wrapRoutingDesignRule(RoutingLayer& routing_layer, idb::IdbLa width_parallel_length_map[x][y] = idb_spacing_table->get_spacing_table()[x][y]; } } + parallel_run_length_spacing_rule.has_spacing_table = true; + exist_rule_set.insert(ViolationType::kParallelRunLengthSpacing); + } + + if (idb_layer->get_spacing_list() != nullptr) { + auto& spacing_list = parallel_run_length_spacing_rule.spacing_list; + for (auto& spacing_rule : idb_layer->get_spacing_list()->get_spacing_list()) { + LayerSpacingType spacing_type; + if (spacing_rule->get_spacing_type() == idb::IdbLayerSpacingType::kSpacingDefault) { + spacing_type = LayerSpacingType::kSpacingDefault; + } else if (spacing_rule->get_spacing_type() == idb::IdbLayerSpacingType::kSpacingRange) { + spacing_type = LayerSpacingType::kSpacingRange; + } else if (spacing_rule->get_spacing_type() == idb::IdbLayerSpacingType::kSpacingEndOfLine) { + continue; + } else { + spacing_type = LayerSpacingType::kNone; + } + LayerSpacing spacing{spacing_type, spacing_rule->get_min_spacing(), spacing_rule->get_min_width(), spacing_rule->get_max_width()}; + spacing_list.push_back(spacing); + } + + parallel_run_length_spacing_rule.has_spacing_list = true; exist_rule_set.insert(ViolationType::kParallelRunLengthSpacing); } } @@ -635,6 +691,22 @@ void DRCInterface::wrapCutDesignRule(CutLayer& cut_layer, idb::IdbLayerCut* idb_ { exist_rule_set.insert(ViolationType::kCutShort); } + // AdjacentCutSpacingRule + { + AdjacentCutSpacingRule& adj_cut_spacing_rule = cut_layer.get_adjacent_cut_rule(); + if (!idb_layer->get_spacings().empty()) { + for (auto& cut_spacing : idb_layer->get_spacings()) { + if (cut_spacing->get_adjacent_cuts().has_value()) { + adj_cut_spacing_rule.cut_spacing = cut_spacing->get_spacing(); + adj_cut_spacing_rule.adjacnet_cuts = cut_spacing->get_adjacent_cuts()->get_adjacent_cuts(); + adj_cut_spacing_rule.cut_within = cut_spacing->get_adjacent_cuts()->get_cut_within(); + exist_rule_set.insert(ViolationType::kAdjacentCutSpacing); + // only one ADJACENTCUTS statement per cut layer + continue; + } + } + } + } // CutEOLSpacingRule { CutEOLSpacingRule& cut_eol_spacing_rule = cut_layer.get_cut_eol_spacing_rule(); @@ -734,9 +806,17 @@ void DRCInterface::wrapCutDesignRule(CutLayer& cut_layer, idb::IdbLayerCut* idb_ { SameLayerCutSpacingRule& same_layer_cut_spacing_rule = cut_layer.get_same_layer_cut_spacing_rule(); if (!idb_layer->get_spacings().empty()) { - same_layer_cut_spacing_rule.curr_spacing = idb_layer->get_spacings().front()->get_spacing(); - same_layer_cut_spacing_rule.curr_prl = 0; - same_layer_cut_spacing_rule.curr_prl_spacing = idb_layer->get_spacings().front()->get_spacing(); + for (auto& cut_spacing : idb_layer->get_spacings()) { + if (cut_spacing->get_adjacent_cuts().has_value()) { + continue; + } + SameLayerCutSpacing same_layer_cut_spacing; + same_layer_cut_spacing.curr_spacing = cut_spacing->get_spacing(); + same_layer_cut_spacing.curr_prl = -1; + same_layer_cut_spacing.curr_prl_spacing = -1; + same_layer_cut_spacing.has_same_net = cut_spacing->get_has_same_net(); + same_layer_cut_spacing_rule.spacings.push_back(same_layer_cut_spacing); + } exist_rule_set.insert(ViolationType::kSameLayerCutSpacing); } else if (!idb_layer->get_lef58_spacing_table().empty()) { idb::cutlayer::Lef58SpacingTable* spacing_table = nullptr; @@ -747,14 +827,13 @@ void DRCInterface::wrapCutDesignRule(CutLayer& cut_layer, idb::IdbLayerCut* idb_ spacing_table = spacing_table_ptr.get(); } if (spacing_table != nullptr) { + // NEXT 是否需要支持全部的规则,而不是第一条? idb::cutlayer::Lef58SpacingTable::CutSpacing cut_spacing = spacing_table->get_cutclass().get_cut_spacing(0, 0); int32_t curr_spacing = cut_spacing.get_cut_spacing1().value(); int32_t curr_prl = spacing_table->get_prl().value().get_prl(); int32_t curr_prl_spacing = cut_spacing.get_cut_spacing2().value(); - same_layer_cut_spacing_rule.curr_spacing = curr_spacing; - same_layer_cut_spacing_rule.curr_prl = curr_prl; - same_layer_cut_spacing_rule.curr_prl_spacing = curr_prl_spacing; + same_layer_cut_spacing_rule.spacings.push_back({curr_spacing, curr_prl, curr_prl_spacing, false}); exist_rule_set.insert(ViolationType::kSameLayerCutSpacing); } } @@ -862,6 +941,10 @@ std::vector DRCInterface::buildEnvShapeList() // instance obs for (idb::IdbLayerShape* obs_box : idb_instance->get_obs_box_list()) { for (idb::IdbRect* rect : obs_box->get_rect_list()) { + if (obs_box->get_layer() == nullptr) { + // DRCLOG.warn(Loc::current(), "The obs box layer is empty for instance ", idb_instance->get_name()); + continue; + } ids::Shape ids_shape; ids_shape.net_idx = -1; ids_shape.ll_x = rect->get_low_x(); diff --git a/src/operation/iDRC/source/data_manager/advance/CutLayer.hpp b/src/operation/iDRC/source/data_manager/advance/CutLayer.hpp index 81579493e..dd390b5ae 100644 --- a/src/operation/iDRC/source/data_manager/advance/CutLayer.hpp +++ b/src/operation/iDRC/source/data_manager/advance/CutLayer.hpp @@ -16,6 +16,7 @@ // *************************************************************************************** #pragma once +#include "AdjacentCutSpacingRule.hpp" #include "CutEOLSpacingRule.hpp" #include "DRCHeader.hpp" #include "DifferentLayerCutSpacingRule.hpp" @@ -35,6 +36,7 @@ class CutLayer int32_t get_layer_idx() const { return _layer_idx; } int32_t get_layer_order() const { return _layer_order; } std::string& get_layer_name() { return _layer_name; } + AdjacentCutSpacingRule& get_adjacent_cut_rule() { return _adjacent_cut_rule; } CutEOLSpacingRule& get_cut_eol_spacing_rule() { return _cut_eol_spacing_rule; } DifferentLayerCutSpacingRule& get_different_layer_cut_spacing_rule() { return _different_layer_cut_spacing_rule; } std::vector& get_enclosure_edge_rule_list() { return _enclosure_edge_rule_list; } @@ -49,6 +51,7 @@ class CutLayer int32_t _layer_idx = -1; int32_t _layer_order = -1; std::string _layer_name; + AdjacentCutSpacingRule _adjacent_cut_rule; CutEOLSpacingRule _cut_eol_spacing_rule; DifferentLayerCutSpacingRule _different_layer_cut_spacing_rule; std::vector _enclosure_edge_rule_list; diff --git a/src/operation/iDRC/source/data_manager/advance/RoutingLayer.hpp b/src/operation/iDRC/source/data_manager/advance/RoutingLayer.hpp index 977af3242..7b749abba 100644 --- a/src/operation/iDRC/source/data_manager/advance/RoutingLayer.hpp +++ b/src/operation/iDRC/source/data_manager/advance/RoutingLayer.hpp @@ -17,6 +17,7 @@ #pragma once #include "CornerFillSpacingRule.hpp" +#include "CornerSpacingRule.hpp" #include "DRCHeader.hpp" #include "EndOfLineSpacingRule.hpp" #include "Logger.hpp" @@ -45,6 +46,7 @@ class RoutingLayer Direction& get_prefer_direction() { return _prefer_direction; } int32_t get_pitch() const { return _pitch; } CornerFillSpacingRule& get_corner_fill_spacing_rule() { return _corner_fill_spacing_rule; } + std::vector& get_corner_spacing_rule_list() { return _corner_spacing_rule_list; } std::vector& get_end_of_line_spacing_rule_list() { return _end_of_line_spacing_rule_list; } MaximumWidthRule& get_maximum_width_rule() { return _maximum_width_rule; } MinHoleRule& get_min_hole_rule() { return _min_hole_rule; } @@ -71,6 +73,7 @@ class RoutingLayer Direction _prefer_direction = Direction::kNone; int32_t _pitch = -1; CornerFillSpacingRule _corner_fill_spacing_rule; + std::vector _corner_spacing_rule_list; std::vector _end_of_line_spacing_rule_list; MaximumWidthRule _maximum_width_rule; MinHoleRule _min_hole_rule; diff --git a/src/operation/iDRC/source/data_manager/design_rule/AdjacentCutSpacingRule.hpp b/src/operation/iDRC/source/data_manager/design_rule/AdjacentCutSpacingRule.hpp index e50c60dee..3c1da825e 100644 --- a/src/operation/iDRC/source/data_manager/design_rule/AdjacentCutSpacingRule.hpp +++ b/src/operation/iDRC/source/data_manager/design_rule/AdjacentCutSpacingRule.hpp @@ -25,6 +25,10 @@ class AdjacentCutSpacingRule public: AdjacentCutSpacingRule() = default; ~AdjacentCutSpacingRule() = default; + + int32_t cut_spacing; + int32_t adjacnet_cuts; + int32_t cut_within; }; } // namespace idrc diff --git a/src/operation/iDRC/source/data_manager/design_rule/CornerSpacingRule.hpp b/src/operation/iDRC/source/data_manager/design_rule/CornerSpacingRule.hpp new file mode 100644 index 000000000..c17f399da --- /dev/null +++ b/src/operation/iDRC/source/data_manager/design_rule/CornerSpacingRule.hpp @@ -0,0 +1,45 @@ +// *************************************************************************************** +// Copyright (c) 2023-2025 Peng Cheng Laboratory +// Copyright (c) 2023-2025 Institute of Computing Technology, Chinese Academy of Sciences +// Copyright (c) 2023-2025 Beijing Institute of Open Source Chip +// +// iEDA is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// +// See the Mulan PSL v2 for more details. +// *************************************************************************************** +#pragma once + +#include "DRCHeader.hpp" + +namespace idrc { + +class CornerSpacingRule +{ + public: + CornerSpacingRule() = default; + ~CornerSpacingRule() = default; + int32_t get_width_spacing(int32_t width) + { + for (int32_t i = width_spacing_list.size() - 1; i >= 0; i--) { + if (width > width_spacing_list[i].first) { + return width_spacing_list[i].second; + } + } + return width_spacing_list[0].second; + } + + bool has_convex_corner = false; + bool has_concave_corner = false; + bool has_except_eol = false; + int32_t except_eol = -1; + std::vector> width_spacing_list; +}; + +} // namespace idrc diff --git a/src/operation/iDRC/source/data_manager/design_rule/ParallelRunLengthSpacingRule.hpp b/src/operation/iDRC/source/data_manager/design_rule/ParallelRunLengthSpacingRule.hpp index 34113a3ae..23dddbeac 100644 --- a/src/operation/iDRC/source/data_manager/design_rule/ParallelRunLengthSpacingRule.hpp +++ b/src/operation/iDRC/source/data_manager/design_rule/ParallelRunLengthSpacingRule.hpp @@ -21,6 +21,24 @@ namespace idrc { +enum class LayerSpacingType : uint8_t +{ + kNone, + kSpacingDefault, + kSpacingRange, + //!-----tbd------------- + kSpacingRangeLenThreshold, + kSpacingEOL, + kMax +}; +struct LayerSpacing +{ + LayerSpacingType spacing_type; + int32_t min_spacing; + int32_t min_width; + int32_t max_width; +}; + class ParallelRunLengthSpacingRule { public: @@ -48,6 +66,35 @@ class ParallelRunLengthSpacingRule std::vector width_list; std::vector parallel_length_list; GridMap width_parallel_length_map; + bool has_spacing_table = false; + + std::vector spacing_list; + bool has_spacing_list = false; + + int32_t getSpacingWithWidth(int32_t width) + { + int32_t spacing = -1; + int32_t default_spacing = -1; + for (auto& layerSpacing : spacing_list) { + if (layerSpacing.spacing_type == LayerSpacingType::kSpacingRange) { + if (layerSpacing.min_width <= width && width <= layerSpacing.max_width) { + spacing = layerSpacing.min_spacing; + } + } else { + default_spacing = layerSpacing.min_spacing; + } + } + return spacing == -1 ? default_spacing : spacing; + } + + int32_t getSpacingMaxWidth() + { + int32_t spacing = -1; + for (auto& layerSpacing : spacing_list) { + spacing = std::max(spacing, layerSpacing.min_spacing); + } + return spacing; + } }; } // namespace idrc diff --git a/src/operation/iDRC/source/data_manager/design_rule/SameLayerCutSpacingRule.hpp b/src/operation/iDRC/source/data_manager/design_rule/SameLayerCutSpacingRule.hpp index 0dd4e62f9..4c2bbc13c 100644 --- a/src/operation/iDRC/source/data_manager/design_rule/SameLayerCutSpacingRule.hpp +++ b/src/operation/iDRC/source/data_manager/design_rule/SameLayerCutSpacingRule.hpp @@ -19,15 +19,20 @@ #include "DRCHeader.hpp" namespace idrc { +struct SameLayerCutSpacing +{ + int32_t curr_spacing = -1; + int32_t curr_prl = -1; + int32_t curr_prl_spacing = -1; + bool has_same_net = false; +}; class SameLayerCutSpacingRule { public: SameLayerCutSpacingRule() = default; ~SameLayerCutSpacingRule() = default; - int32_t curr_spacing = -1; - int32_t curr_prl = -1; - int32_t curr_prl_spacing = -1; + std::vector spacings; }; } // namespace idrc diff --git a/src/operation/iDRC/source/module/rule_validator/RuleValidator.cpp b/src/operation/iDRC/source/module/rule_validator/RuleValidator.cpp index 9d14b94ef..7d83271ae 100644 --- a/src/operation/iDRC/source/module/rule_validator/RuleValidator.cpp +++ b/src/operation/iDRC/source/module/rule_validator/RuleValidator.cpp @@ -19,7 +19,9 @@ #include "DRCHeader.hpp" #include "GDSPlotter.hpp" #include "Monitor.hpp" +#include "PlanarRect.hpp" #include "RVCluster.hpp" +#include "Utility.hpp" namespace idrc { @@ -545,7 +547,15 @@ void RuleValidator::prepareRVCluster(RVCluster& rv_cluster) } else { std::vector delta_overlap_list; delta_rect_rtree.query(bgi::intersects(gtl_rect), std::back_inserter(delta_overlap_list)); - max_rect_data.isEnv = delta_overlap_list.empty(); + max_rect_data.isEnv = true; + for (auto& delta_rect : delta_overlap_list) { + PlanarRect delta_planar_rect = DRCUTIL.convertToPlanarRect(delta_rect); + PlanarRect max_rect = DRCUTIL.convertToPlanarRect(max_rect_data.rect); + if (DRCUTIL.isOpenOverlap(delta_planar_rect, max_rect)) { + max_rect_data.isEnv = false; + break; + } + } } } is_polygon_env = is_polygon_env && max_rect_data.isEnv; diff --git a/src/operation/iDRC/source/module/rule_validator/rv_design_rule/AdjacentCutSpacing.cpp b/src/operation/iDRC/source/module/rule_validator/rv_design_rule/AdjacentCutSpacing.cpp index 6c4ddd6e1..d96604e0f 100644 --- a/src/operation/iDRC/source/module/rule_validator/rv_design_rule/AdjacentCutSpacing.cpp +++ b/src/operation/iDRC/source/module/rule_validator/rv_design_rule/AdjacentCutSpacing.cpp @@ -20,117 +20,78 @@ namespace idrc { void RuleValidator::verifyAdjacentCutSpacing(RVCluster& rv_cluster) { -#if 0 - /* - 规则: SPACING 0.155 ADJACENTCUTS 3 WITHIN 0.200 ; - */ - struct AdjacentCutSpacingRule // 这是cut spacing的子规则 - { - int32_t cut_spacing = -1; - int32_t adjacent_cuts = -1; - int32_t within = -1; - }; - std::map layer_adjacent_cut_spacing_rule; - for (int32_t i = 1; i <= 4; i++) { - AdjacentCutSpacingRule rule = {310, 3, 400}; - layer_adjacent_cut_spacing_rule[i] = rule; // via2-via5 - } std::vector& cut_layer_list = DRCDM.getDatabase().get_cut_layer_list(); std::map>& cut_to_adjacent_routing_map = DRCDM.getDatabase().get_cut_to_adjacent_routing_map(); + const auto& layer_data = rv_cluster.get_layer_data(); - std::map>> cut_net_rect_map; - std::map, bgi::quadratic<16>>> cut_bg_rtree_map; - for (DRCShape* drc_shape : rv_cluster.get_drc_env_shape_list()) { - if (drc_shape->get_is_routing()) { - continue; - } - cut_net_rect_map[drc_shape->get_layer_idx()][drc_shape->get_net_idx()].push_back(drc_shape->get_rect()); - cut_bg_rtree_map[drc_shape->get_layer_idx()].insert(std::make_pair(DRCUTIL.convertToBGRectInt(drc_shape->get_rect()), drc_shape->get_net_idx())); - } - for (DRCShape* drc_shape : rv_cluster.get_drc_result_shape_list()) { - if (drc_shape->get_is_routing()) { + for (const auto& [cut_layer_idx, cut_layer_data] : layer_data) { + if (cut_layer_data.cut_pool.empty()) { continue; } - cut_net_rect_map[drc_shape->get_layer_idx()][drc_shape->get_net_idx()].push_back(drc_shape->get_rect()); - cut_bg_rtree_map[drc_shape->get_layer_idx()].insert(std::make_pair(DRCUTIL.convertToBGRectInt(drc_shape->get_rect()), drc_shape->get_net_idx())); - } - for (auto& [cut_layer_idx, net_rect_map] : cut_net_rect_map) { + int32_t routing_layer_idx = -1; { std::vector& routing_layer_idx_list = cut_to_adjacent_routing_map[cut_layer_idx]; routing_layer_idx = *std::min_element(routing_layer_idx_list.begin(), routing_layer_idx_list.end()); } - if (!DRCUTIL.exist(layer_adjacent_cut_spacing_rule, cut_layer_idx)) { - continue; - } - AdjacentCutSpacingRule& curr_rule = layer_adjacent_cut_spacing_rule[cut_layer_idx]; - int32_t cut_spacing = curr_rule.cut_spacing; - int32_t adjacent_cuts = curr_rule.adjacent_cuts; - int32_t within = curr_rule.within; - for (auto& [net_idx, rect_list] : net_rect_map) { - for (PlanarRect& rect : rect_list) { - std::vector> bg_rect_net_pair_list; - { - PlanarRect check_rect = DRCUTIL.getEnlargedRect(rect, within); - cut_bg_rtree_map[cut_layer_idx].query(bgi::intersects(DRCUTIL.convertToBGRectInt(check_rect)), std::back_inserter(bg_rect_net_pair_list)); + CutLayer& cut_layer = cut_layer_list[cut_layer_idx]; + + AdjacentCutSpacingRule& adj_cut_rule = cut_layer.get_adjacent_cut_rule(); + for (const CutData& cut_data : cut_layer_data.getCuts()) { + GTLRectInt cut_gtl_rect = cut_data.rect; + PlanarRect cut_rect = DRCUTIL.convertToPlanarRect(cut_gtl_rect); + int32_t net_idx = cut_data.net_idx; + + std::vector neighbor_cut_list; + { + PlanarRect check_rect = DRCUTIL.getEnlargedRect(cut_rect, adj_cut_rule.cut_within); + cut_layer_data.queryCuts(DRCUTIL.convertToGTLRectInt(check_rect), std::back_inserter(neighbor_cut_list)); + } + + int32_t adjacent_cut_count = 0; + bool has_violation = false; + int32_t cur_remote_spacing = -1; + int32_t cur_remote_env_net = -1; + std::set> seen_neighboor_rects; + + for (const CutData& neighbor_cut_data : neighbor_cut_list) { + int32_t env_net_idx = neighbor_cut_data.net_idx; + PlanarRect env_rect = DRCUTIL.convertToPlanarRect(neighbor_cut_data.rect); + if (cut_rect == env_rect) { + continue; } - int32_t adjacent_cut_count = 0; - bool is_inside_spacing = false; - std::vector> env_cut_rect_list; - for (auto& [bg_env_rect, env_net_idx] : bg_rect_net_pair_list) { - PlanarRect env_rect = DRCUTIL.convertToPlanarRect(bg_env_rect); - if (env_rect == rect) { - continue; // 忽略自己 - } - if (DRCUTIL.getEuclideanDistance(rect, env_rect) >= within) { - continue; // 忽略不在within范围内的 - } - if (DRCUTIL.getEuclideanDistance(rect, env_rect) < cut_spacing) { - is_inside_spacing = true; // 在spacing范围内 + + int32_t distance = DRCUTIL.getEuclideanDistance(cut_rect, env_rect); + if (distance < adj_cut_rule.cut_within) { + auto nb_rect_key = std::make_tuple(env_rect.get_ll_x(), env_rect.get_ll_y(), env_rect.get_ur_x(), env_rect.get_ur_y()); + if (!seen_neighboor_rects.insert(nb_rect_key).second) { + continue; } - env_cut_rect_list.push_back(std::make_pair(env_net_idx, env_rect)); adjacent_cut_count++; + if (distance > cur_remote_spacing && env_net_idx != -1) { + cur_remote_spacing = distance; + cur_remote_env_net = env_net_idx; + } } - if (adjacent_cut_count < adjacent_cuts) { - continue; // 忽略不满足adjacent_cuts的 - } - if (is_inside_spacing == false) { - continue; + if (distance < adj_cut_rule.cut_spacing) { + has_violation = true; } - sort(env_cut_rect_list.begin(), env_cut_rect_list.end(), [&](const std::pair& a, const std::pair& b) { - SortStatus sort_status = SortStatus::kEqual; - double a_dis = DRCUTIL.getEuclideanDistance(rect, a.second); - double b_dis = DRCUTIL.getEuclideanDistance(rect, b.second); - // EuclideanDistance大的优先 - if (sort_status == SortStatus::kEqual) { - if (a_dis > b_dis) { - sort_status = SortStatus::kTrue; - } else if (a_dis < b_dis) { - sort_status = SortStatus::kFalse; - } else { - sort_status = SortStatus::kEqual; - } - } - if (sort_status == SortStatus::kTrue) { - return true; - } else if (sort_status == SortStatus::kFalse) { - return false; - } - return false; - }); - int32_t env_idx = env_cut_rect_list.front().first; + } + if (net_idx == -1 && cur_remote_env_net == -1) { + continue; + } + if (has_violation && (adjacent_cut_count >= adj_cut_rule.adjacnet_cuts)) { Violation violation; violation.set_violation_type(ViolationType::kAdjacentCutSpacing); violation.set_is_routing(true); - violation.set_violation_net_set({net_idx, env_idx}); + violation.set_violation_net_set({net_idx, cur_remote_env_net}); violation.set_layer_idx(routing_layer_idx); - violation.set_rect(rect); - violation.set_required_size(cut_spacing); + violation.set_rect(cut_rect); + violation.set_required_size(adj_cut_rule.cut_spacing); rv_cluster.get_violation_list().push_back(violation); } } } -#endif } } // namespace idrc diff --git a/src/operation/iDRC/source/module/rule_validator/rv_design_rule/CornerSpacing.cpp b/src/operation/iDRC/source/module/rule_validator/rv_design_rule/CornerSpacing.cpp index 863fde034..996682caf 100644 --- a/src/operation/iDRC/source/module/rule_validator/rv_design_rule/CornerSpacing.cpp +++ b/src/operation/iDRC/source/module/rule_validator/rv_design_rule/CornerSpacing.cpp @@ -17,224 +17,511 @@ #include "RuleValidator.hpp" namespace idrc { +struct Corner +{ + PlanarCoord point; + int32_t width; + Orientation orient1; + Orientation orient2; + int32_t net_idx; + int32_t polygon_id; + int32_t boundary_id; + int32_t next_boundary_id; +}; void RuleValidator::verifyCornerSpacing(RVCluster& rv_cluster) { -#if 0 - /* - PROPERTY LEF58_CORNERSPACING "CORNERSPACING CONVEXCORNER EXCEPTEOL 0.08 - WIDTH 0.00 SPACING 0.10 - WIDTH 0.20 SPACING 0.20 - WIDTH 0.50 SPACING 0.30 ;" ; - */ - // corner to corner rule - struct CornerSpacingRule - { - bool has_convex_corner = false; - bool has_except_eol = false; - int32_t eolwidth = 0; - std::vector> width_spacing_list; - }; - std::map layer_corner_spacing_rule; // M2-M7 - for (int32_t i = 1; i <= 6; i++) { - CornerSpacingRule rule = {true, true, 160, {{0, 200}, {400, 400}, {1000, 600}}}; - layer_corner_spacing_rule[i] = rule; // M2-M7 - } -/////////// -#if 1 // 数据结构定义 - struct PolyInfo - { - int32_t coord_size = -1; - std::vector coord_list; - std::vector convex_corner_list; - std::vector> edge_list; - std::vector edge_length_list; - std::set eol_edge_idx_set; - GTLHolePolyInt gtl_hole_poly; - int32_t poly_info_idx = -1; - }; -#endif std::vector& routing_layer_list = DRCDM.getDatabase().get_routing_layer_list(); - std::map>& routing_to_adjacent_cut_map = DRCDM.getDatabase().get_routing_to_adjacent_cut_map(); - - std::map>> routing_net_poly_info_map; - { - std::map> routing_net_gtl_poly_set_map; - for (DRCShape* drc_shape : rv_cluster.get_drc_env_shape_list()) { - if (drc_shape->get_is_routing()) { - routing_net_gtl_poly_set_map[drc_shape->get_layer_idx()][drc_shape->get_net_idx()] += DRCUTIL.convertToGTLRectInt(drc_shape->get_rect()); - } - } - for (DRCShape* drc_shape : rv_cluster.get_drc_result_shape_list()) { - if (drc_shape->get_is_routing()) { - routing_net_gtl_poly_set_map[drc_shape->get_layer_idx()][drc_shape->get_net_idx()] += DRCUTIL.convertToGTLRectInt(drc_shape->get_rect()); - } - } - for (auto& [routing_layer_idx, net_gtl_poly_set_map] : routing_net_gtl_poly_set_map) { - for (auto& [net_idx, gtl_poly_set] : net_gtl_poly_set_map) { - std::vector gtl_hole_poly_list; - gtl_poly_set.get(gtl_hole_poly_list); - for (GTLHolePolyInt& gtl_hole_poly : gtl_hole_poly_list) { - int32_t coord_size = static_cast(gtl_hole_poly.size()); - if (coord_size < 4) { + const auto& layer_data = rv_cluster.get_layer_data(); + + auto collect_exempted_eol_edges = [&](const auto& curr_layer_data, int32_t eol_width, std::set& exempted_eol_boundary_ids) { + for (const auto& net_entry : curr_layer_data.nets) { + const RVRoutingNet& routing_net = net_entry.second; + for (const PolygonData& polygon_data : curr_layer_data.getPolygons(routing_net)) { + std::vector visited_ring_boundary(static_cast(polygon_data.boundary_count), false); + for (const BoundaryData& seed_boundary : curr_layer_data.getBoundaries(polygon_data)) { + int32_t seed_boundary_id = curr_layer_data.getBoundaryId(seed_boundary); + int32_t seed_local_idx = seed_boundary_id - polygon_data.boundary_begin; + if (visited_ring_boundary[seed_local_idx]) { continue; } - std::vector coord_list; - for (auto iter = gtl_hole_poly.begin(); iter != gtl_hole_poly.end(); iter++) { - coord_list.push_back(DRCUTIL.convertToPlanarCoord(*iter)); - } - std::vector convex_corner_list; - std::vector> edge_list; - std::vector edge_length_list; - for (int32_t i = 0; i < coord_size; i++) { - PlanarCoord& pre_coord = coord_list[getIdx(i - 1, coord_size)]; - PlanarCoord& curr_coord = coord_list[i]; - PlanarCoord& post_coord = coord_list[getIdx(i + 1, coord_size)]; - convex_corner_list.push_back(DRCUTIL.isConvexCorner(DRCUTIL.getRotation(gtl_hole_poly), pre_coord, curr_coord, post_coord)); - edge_list.push_back(Segment(pre_coord, curr_coord)); - edge_length_list.push_back(DRCUTIL.getManhattanDistance(pre_coord, curr_coord)); - } - std::set eol_edge_idx_set; - for (int32_t i = 0; i < coord_size; i++) { - if (convex_corner_list[getIdx(i - 1, coord_size)] && convex_corner_list[i]) { - eol_edge_idx_set.insert(i); + + int32_t curr_boundary_id = seed_boundary_id; + do { + int32_t local_idx = curr_boundary_id - polygon_data.boundary_begin; + if (local_idx < 0 || polygon_data.boundary_count <= local_idx || visited_ring_boundary[local_idx]) { + break; } - } - routing_net_poly_info_map[routing_layer_idx][net_idx].emplace_back(coord_size, coord_list, convex_corner_list, edge_list, edge_length_list, - eol_edge_idx_set, gtl_hole_poly); + visited_ring_boundary[local_idx] = true; + + const BoundaryData& curr_boundary = curr_layer_data.getBoundary(curr_boundary_id); + const BoundaryData& prev_boundary = curr_layer_data.getPrevBoundary(curr_boundary_id); + bool is_curr_eol_boundary = prev_boundary.isConvex && curr_boundary.isConvex; + bool is_exempted = curr_boundary.edge_length < eol_width && is_curr_eol_boundary; + if (is_exempted) { + exempted_eol_boundary_ids.insert(curr_boundary_id); + } + curr_boundary_id = curr_boundary.next_boundary_id; + } while (curr_boundary_id != seed_boundary_id); } } } + }; + + auto build_outside_query_rect = [](const Corner& corner, int32_t spacing) { + Orientation outer_orient1 = DRCUTIL.getOppositeOrientation(corner.orient1); + Orientation outer_orient2 = DRCUTIL.getOppositeOrientation(corner.orient2); + + int32_t ll_x_minus_offset = 0; + int32_t ll_y_minus_offset = 0; + int32_t ur_x_add_offset = 0; + int32_t ur_y_add_offset = 0; + for (Orientation orient : {outer_orient1, outer_orient2}) { + if (orient == Orientation::kWest) { + ll_x_minus_offset = spacing; + } else if (orient == Orientation::kSouth) { + ll_y_minus_offset = spacing; + } else if (orient == Orientation::kEast) { + ur_x_add_offset = spacing; + } else if (orient == Orientation::kNorth) { + ur_y_add_offset = spacing; + } + } + return DRCUTIL.getEnlargedRect(corner.point, ll_x_minus_offset, ll_y_minus_offset, ur_x_add_offset, ur_y_add_offset); + }; + + auto queryNetIdxByRect = [](const RVLayerData& rv_layer_data, const PlanarRect& query_rect) -> int32_t { + std::vector> rect_max_rect_pair_list; + rv_layer_data.queryMaxRects(DRCUTIL.convertToGTLRectInt(query_rect), std::back_inserter(rect_max_rect_pair_list)); + return rect_max_rect_pair_list.empty() ? -1 : rv_layer_data.getNetIdxByMaxRectId(rect_max_rect_pair_list.front().second); + }; + + std::map layer_merged_polyset_map; + for (const auto& [routing_layer_idx, rv_layer_data] : layer_data) { + for (const auto& net_entry : rv_layer_data.nets) { + const RVRoutingNet& routing_net = net_entry.second; + layer_merged_polyset_map[routing_layer_idx] += routing_net.polyset; + } } - std::map>, bgi::quadratic<16>>> routing_bg_rtree_map; - { - for (auto& [routing_layer_idx, net_poly_info_map] : routing_net_poly_info_map) { - for (auto& [net_idx, poly_info_list] : net_poly_info_map) { - for (int32_t i = 0; i < static_cast(poly_info_list.size()); i++) { - std::vector gtl_rect_list; - gtl::get_max_rectangles(gtl_rect_list, poly_info_list[i].gtl_hole_poly); - for (GTLRectInt& gtl_rect : gtl_rect_list) { - routing_bg_rtree_map[routing_layer_idx].insert(std::make_pair(DRCUTIL.convertToBGRectInt(gtl_rect), std::make_pair(net_idx, i))); - } - poly_info_list[i].poly_info_idx = i; + + std::map merged_layer_data_map; + auto append_boundary_edges = [this](RVLayerData& rv_layer_data, GTLHolePolyInt& check_hole_poly, bool is_hole, int32_t polygon_id, + std::vector>& boundary_rtree_inputs) { + int32_t coord_size = static_cast(check_hole_poly.size()); + std::vector coord_list; + coord_list.reserve(coord_size); + for (auto iter = check_hole_poly.begin(); iter != check_hole_poly.end(); ++iter) { + coord_list.push_back(DRCUTIL.convertToPlanarCoord(*iter)); + } + while (coord_list.size() > 1 && coord_list.front() == coord_list.back()) { + coord_list.pop_back(); + } + coord_size = static_cast(coord_list.size()); + if (coord_size < 2) { + return; + } + + Rotation rotation = DRCUTIL.getRotation(check_hole_poly); + auto get_boundary_orient = [is_hole, rotation](const PlanarCoord& begin_coord, const PlanarCoord& end_coord) { + auto rotate_left = [](Orientation orient) { + switch (orient) { + case Orientation::kEast: + return Orientation::kNorth; + case Orientation::kNorth: + return Orientation::kWest; + case Orientation::kWest: + return Orientation::kSouth; + case Orientation::kSouth: + return Orientation::kEast; + default: + return Orientation::kNone; + } + }; + auto rotate_right = [](Orientation orient) { + switch (orient) { + case Orientation::kEast: + return Orientation::kSouth; + case Orientation::kSouth: + return Orientation::kWest; + case Orientation::kWest: + return Orientation::kNorth; + case Orientation::kNorth: + return Orientation::kEast; + default: + return Orientation::kNone; } + }; + + Orientation travel_orient = DRCUTIL.getOrientation(begin_coord, end_coord); + bool metal_on_left = (rotation == Rotation::kCounterclockwise); + if (is_hole) { + metal_on_left = !metal_on_left; + } + return metal_on_left ? rotate_right(travel_orient) : rotate_left(travel_orient); + }; + + std::vector convex_corner_list(coord_size, false); + if (coord_size >= 3) { + for (int32_t i = 0; i < coord_size; i++) { + PlanarCoord& pre_coord = coord_list[getIdx(i - 1, coord_size)]; + PlanarCoord& curr_coord = coord_list[i]; + PlanarCoord& post_coord = coord_list[getIdx(i + 1, coord_size)]; + convex_corner_list[i] = is_hole ? DRCUTIL.isConcaveCorner(rotation, pre_coord, curr_coord, post_coord) + : DRCUTIL.isConvexCorner(rotation, pre_coord, curr_coord, post_coord); + } + } + + std::vector ring_boundary_ids; + ring_boundary_ids.reserve(coord_size); + for (int32_t i = 0; i < coord_size; i++) { + PlanarCoord& pre_coord = coord_list[getIdx(i - 1, coord_size)]; + PlanarCoord& curr_coord = coord_list[i]; + if (pre_coord == curr_coord) { + continue; + } + + BoundaryData boundary_data; + boundary_data.edge = DRCUTIL.convertToGTLRectInt(DRCUTIL.getRect(pre_coord, curr_coord)); + boundary_data.begin_coord = pre_coord; + boundary_data.end_coord = curr_coord; + boundary_data.orient = get_boundary_orient(pre_coord, curr_coord); + boundary_data.polygon_id = polygon_id; + boundary_data.edge_length = DRCUTIL.getManhattanDistance(pre_coord, curr_coord); + boundary_data.isConvex = convex_corner_list[i]; + boundary_data.isHole = is_hole; + + rv_layer_data.boundary_pool.push_back(boundary_data); + int32_t boundary_id = static_cast(rv_layer_data.boundary_pool.size()) - 1; + ring_boundary_ids.push_back(boundary_id); + boundary_rtree_inputs.push_back({boundary_data.edge, boundary_id}); + } + + int32_t ring_size = static_cast(ring_boundary_ids.size()); + if (ring_size < 2) { + return; + } + for (int32_t i = 0; i < ring_size; i++) { + BoundaryData& boundary_data = rv_layer_data.boundary_pool[ring_boundary_ids[i]]; + boundary_data.prev_boundary_id = ring_boundary_ids[getIdx(i - 1, ring_size)]; + boundary_data.next_boundary_id = ring_boundary_ids[getIdx(i + 1, ring_size)]; + } + }; + + auto build_layer_component_data = [&](RVLayerData& merged_layer_data, const GTLPolySetInt& merged_layer_polyset) { + merged_layer_data.nets.clear(); + merged_layer_data.polygon_pool.clear(); + merged_layer_data.max_rect_pool.clear(); + merged_layer_data.boundary_pool.clear(); + + std::vector> rect_rtree_inputs; + std::vector> boundary_rtree_inputs; + std::vector gtl_hole_poly_list; + merged_layer_polyset.get(gtl_hole_poly_list); + merged_layer_data.polygon_pool.reserve(gtl_hole_poly_list.size()); + + for (int32_t component_idx = 0; component_idx < static_cast(gtl_hole_poly_list.size()); ++component_idx) { + GTLHolePolyInt& gtl_hole_poly = gtl_hole_poly_list[component_idx]; + GTLPolySetInt component_polyset; + component_polyset += gtl_hole_poly; + + RVRoutingNet& routing_net = merged_layer_data.nets[component_idx]; + routing_net.polyset = component_polyset; + routing_net.polygon_begin = static_cast(merged_layer_data.polygon_pool.size()); + routing_net.max_rect_begin = static_cast(merged_layer_data.max_rect_pool.size()); + routing_net.boundary_begin = static_cast(merged_layer_data.boundary_pool.size()); + + int32_t polygon_id = static_cast(merged_layer_data.polygon_pool.size()); + merged_layer_data.polygon_pool.push_back( + {component_idx, static_cast(merged_layer_data.max_rect_pool.size()), 0, static_cast(merged_layer_data.boundary_pool.size()), 0}); + PolygonData& polygon_data = merged_layer_data.polygon_pool.back(); + + std::vector gtl_rect_list; + gtl::get_max_rectangles(gtl_rect_list, gtl_hole_poly); + merged_layer_data.max_rect_pool.reserve(merged_layer_data.max_rect_pool.size() + gtl_rect_list.size()); + for (GTLRectInt& gtl_rect : gtl_rect_list) { + MaxRectData max_rect_data; + max_rect_data.rect = gtl_rect; + max_rect_data.polygon_id = polygon_id; + + merged_layer_data.max_rect_pool.push_back(max_rect_data); + int32_t max_rect_id = static_cast(merged_layer_data.max_rect_pool.size()) - 1; + rect_rtree_inputs.push_back({gtl_rect, max_rect_id}); + } + polygon_data.max_rect_count = static_cast(merged_layer_data.max_rect_pool.size()) - polygon_data.max_rect_begin; + + append_boundary_edges(merged_layer_data, gtl_hole_poly, false, polygon_id, boundary_rtree_inputs); + for (auto iter = gtl_hole_poly.begin_holes(); iter != gtl_hole_poly.end_holes(); ++iter) { + GTLPolyInt gtl_poly = *iter; + GTLHolePolyInt hole_poly; + hole_poly.set(gtl_poly.begin(), gtl_poly.end()); + append_boundary_edges(merged_layer_data, hole_poly, true, polygon_id, boundary_rtree_inputs); } + polygon_data.boundary_count = static_cast(merged_layer_data.boundary_pool.size()) - polygon_data.boundary_begin; + + routing_net.polygon_count = static_cast(merged_layer_data.polygon_pool.size()) - routing_net.polygon_begin; + routing_net.max_rect_count = static_cast(merged_layer_data.max_rect_pool.size()) - routing_net.max_rect_begin; + routing_net.boundary_count = static_cast(merged_layer_data.boundary_pool.size()) - routing_net.boundary_begin; } + + merged_layer_data.rect_rtrees = decltype(merged_layer_data.rect_rtrees)(rect_rtree_inputs); + merged_layer_data.boundary_rtrees = decltype(merged_layer_data.boundary_rtrees)(boundary_rtree_inputs); + }; + + for (const auto& [routing_layer_idx, merged_layer_polyset] : layer_merged_polyset_map) { + build_layer_component_data(merged_layer_data_map[routing_layer_idx], merged_layer_polyset); } - for (auto& [routing_layer_idx, net_poly_info_map] : routing_net_poly_info_map) { - if (DRCUTIL.exist(layer_corner_spacing_rule, routing_layer_idx) == false) { - continue; // skip layer without corner spacing rule + for (auto& [routing_layer_idx, rv_layer_data] : layer_data) { + auto merged_layer_it = merged_layer_data_map.find(routing_layer_idx); + if (merged_layer_it == merged_layer_data_map.end()) { + continue; } - CornerSpacingRule& curr_rule = layer_corner_spacing_rule[routing_layer_idx]; - for (auto& [net_idx, poly_info_list] : net_poly_info_map) { - for (PolyInfo& poly_info : poly_info_list) { - int32_t& coord_size = poly_info.coord_size; - std::vector& coord_list = poly_info.coord_list; - std::vector gtl_rect_list; - gtl::get_max_rectangles(gtl_rect_list, poly_info.gtl_hole_poly); - std::vector rect_list; - std::set eol_edge_idx_set = poly_info.eol_edge_idx_set; - for (GTLRectInt& gtl_rect : gtl_rect_list) { - rect_list.push_back(DRCUTIL.convertToPlanarRect(gtl_rect)); + RVLayerData& merged_layer_data = merged_layer_it->second; + RoutingLayer& routing_layer = routing_layer_list[routing_layer_idx]; + std::vector& corner_spacing_rule_list = routing_layer.get_corner_spacing_rule_list(); + std::vector violations; + std::vector check_corners; + + for (auto& corner_spacing_rule : corner_spacing_rule_list) { + if (corner_spacing_rule.has_convex_corner) { + // build exempted eol + std::set exempted_eol_boundary_ids; + if (corner_spacing_rule.has_except_eol) { + collect_exempted_eol_edges(rv_layer_data, corner_spacing_rule.except_eol, exempted_eol_boundary_ids); } - for (int32_t eol_idx = 0; eol_idx < poly_info.convex_corner_list.size(); eol_idx++) { - if (!poly_info.convex_corner_list[eol_idx]) { - continue; // skip non-convex corner - } - if(curr_rule.has_except_eol){ - int32_t eol_width = curr_rule.eolwidth; - int32_t post_eol_idx = getIdx(eol_idx + 1, coord_size); - if((DRCUTIL.exist(eol_edge_idx_set, eol_idx) && poly_info.edge_length_list[eol_idx] < eol_width) || - (DRCUTIL.exist(eol_edge_idx_set, post_eol_idx) && poly_info.edge_length_list[post_eol_idx] < eol_width)) { - continue; // skip if the adjacent edges are shorter than the eol width - } - } - PlanarCoord eol_coord = coord_list[eol_idx]; - PlanarCoord pre_coord = coord_list[getIdx(eol_idx - 1, coord_size)]; - PlanarCoord post_coord = coord_list[getIdx(eol_idx + 1, coord_size)]; - PlanarRect corner_rect = DRCUTIL.getBoundingBox({pre_coord, eol_coord, post_coord}); - Orientation pre_orientation = DRCUTIL.getOrientation(pre_coord, eol_coord); - Orientation post_orientation = DRCUTIL.getOrientation(eol_coord, post_coord); - int32_t max_width = 0; - for (PlanarRect& rect : rect_list) { - if (DRCUTIL.isInside(rect, eol_coord)) { - max_width = std::max(max_width, rect.getWidth()); - } - } - int32_t required_spacing = 0; - for (auto& [width, spacing] : curr_rule.width_spacing_list) { - if (max_width > width) { - required_spacing = spacing; + + // build dubious corner + check_corners.clear(); + std::set> seen_corner_keys; + for (const auto& [net_idx, routing_net] : rv_layer_data.nets) { + for (const PolygonData& polygon_data : rv_layer_data.getPolygons(routing_net)) { + int32_t polygon_id = rv_layer_data.getPolygonId(polygon_data); + std::vector visited_ring_boundary(static_cast(polygon_data.boundary_count), false); + for (const BoundaryData& seed_boundary : rv_layer_data.getBoundaries(polygon_data)) { + if (seed_boundary.isHole) { + continue; + } + int32_t seed_boundary_id = rv_layer_data.getBoundaryId(seed_boundary); + int32_t seed_local_idx = seed_boundary_id - polygon_data.boundary_begin; + if (visited_ring_boundary[seed_local_idx]) { + continue; + } + + std::vector ring_boundary_ids; + int32_t curr_boundary_id = seed_boundary_id; + do { + int32_t local_idx = curr_boundary_id - polygon_data.boundary_begin; + if (local_idx < 0 || polygon_data.boundary_count <= local_idx || visited_ring_boundary[local_idx]) { + break; + } + visited_ring_boundary[local_idx] = true; + ring_boundary_ids.push_back(curr_boundary_id); + curr_boundary_id = rv_layer_data.getBoundary(curr_boundary_id).next_boundary_id; + } while (curr_boundary_id != seed_boundary_id); + + int32_t coord_size = static_cast(ring_boundary_ids.size()); + if (coord_size < 3) { + continue; + } + + std::vector convex_corner_list; + convex_corner_list.reserve(coord_size); + for (int32_t ring_boundary_id : ring_boundary_ids) { + convex_corner_list.push_back(rv_layer_data.getBoundary(ring_boundary_id).isConvex); + } + + for (int32_t i = 0; i < coord_size; i++) { + if (!convex_corner_list[i]) { + continue; + } + + int32_t boundary_id = ring_boundary_ids[i]; + int32_t next_boundary_id = ring_boundary_ids[(i + 1) % coord_size]; + const BoundaryData& curr_boundary = rv_layer_data.getBoundary(boundary_id); + const BoundaryData& next_boundary = rv_layer_data.getBoundary(next_boundary_id); + + PlanarCoord corner_point = curr_boundary.end_coord; + Orientation orient1 = DRCUTIL.getOrientation(corner_point, curr_boundary.begin_coord); + Orientation orient2 = DRCUTIL.getOrientation(corner_point, next_boundary.end_coord); + + std::vector> rect_hits; + rv_layer_data.queryMaxRects(DRCUTIL.convertToGTLRectInt(PlanarRect(corner_point, corner_point)), std::back_inserter(rect_hits)); + for (const auto& [gtl_rect, max_rect_id] : rect_hits) { + const MaxRectData& max_rect_data = rv_layer_data.getMaxRect(max_rect_id); + if (max_rect_data.polygon_id != polygon_id) { + continue; + } + + PlanarRect max_rect = DRCUTIL.convertToPlanarRect(gtl_rect); + Orientation rect_orient1 = Orientation::kNone; + Orientation rect_orient2 = Orientation::kNone; + if (!DRCUTIL.getCornerOrientsInRect(max_rect, corner_point, rect_orient1, rect_orient2)) { + continue; + } + if (!((orient1 == rect_orient1 && orient2 == rect_orient2) || (orient1 == rect_orient2 && orient2 == rect_orient1))) { + continue; + } + + int32_t width = max_rect.getWidth(); + auto corner_key = std::make_tuple(corner_point.get_x(), corner_point.get_y(), width, static_cast(orient1), + static_cast(orient2), polygon_id); + if (!seen_corner_keys.insert(corner_key).second) { + continue; + } + check_corners.push_back({corner_point, width, orient1, orient2, net_idx, polygon_id, boundary_id, next_boundary_id}); + } + } } } - PlanarRect check_rect; - if (pre_orientation == Orientation::kNorth && post_orientation == Orientation::kWest) { - check_rect = DRCUTIL.getEnlargedRect(eol_coord, 0, 0, required_spacing, required_spacing); - } else if (pre_orientation == Orientation::kWest && post_orientation == Orientation::kSouth) { - check_rect = DRCUTIL.getEnlargedRect(eol_coord, required_spacing, 0, 0, required_spacing); - } else if (pre_orientation == Orientation::kSouth && post_orientation == Orientation::kEast) { - check_rect = DRCUTIL.getEnlargedRect(eol_coord, required_spacing, required_spacing, 0, 0); - } else if (pre_orientation == Orientation::kEast && post_orientation == Orientation::kNorth) { - check_rect = DRCUTIL.getEnlargedRect(eol_coord, 0, required_spacing, required_spacing, 0); - } else { - DRCLOG.error(Loc::current(), "Unrecognized orientation!"); + } + + // exempt eol boundary edge corner + if (!exempted_eol_boundary_ids.empty()) { + check_corners.erase(std::remove_if(check_corners.begin(), check_corners.end(), + [&](const Corner& corner) { + return DRCUTIL.exist(exempted_eol_boundary_ids, corner.boundary_id) + || DRCUTIL.exist(exempted_eol_boundary_ids, corner.next_boundary_id); + }), + check_corners.end()); + } + + // query corner rect towards outside + for (auto& check_corner : check_corners) { + int32_t spacing = corner_spacing_rule.get_width_spacing(check_corner.width); + if (spacing <= 0) { + continue; } + const BoundaryData& curr_boundary = rv_layer_data.getBoundary(check_corner.boundary_id); + const BoundaryData& next_boundary = rv_layer_data.getBoundary(check_corner.next_boundary_id); + PlanarRect corner_rect = DRCUTIL.getRect(curr_boundary.begin_coord, next_boundary.end_coord); + PlanarRect check_rect = build_outside_query_rect(check_corner, spacing); - std::map> env_net_poly_info_idx_map; - { - std::vector>> bg_rect_net_pair_list; - routing_bg_rtree_map[routing_layer_idx].query(bgi::intersects(DRCUTIL.convertToBGRectInt(check_rect)), std::back_inserter(bg_rect_net_pair_list)); - for (auto& [bg_env_rect, net_poly_info_idx_pair] : bg_rect_net_pair_list) { - env_net_poly_info_idx_map[net_poly_info_idx_pair.first].insert(net_poly_info_idx_pair.second); + std::vector> boundary_hits; + merged_layer_data.queryBoundaries(DRCUTIL.convertToGTLRectInt(check_rect), std::back_inserter(boundary_hits)); + + for (const auto& [gtl_rect, boundary_id] : boundary_hits) { + const BoundaryData& env_boundary = merged_layer_data.getBoundary(boundary_id); + if (env_boundary.orient != check_corner.orient1 && env_boundary.orient != check_corner.orient2) { + continue; } - } - std::map orientation_map = {{Orientation::kEast, Orientation::kWest}, - {Orientation::kWest, Orientation::kEast}, - {Orientation::kSouth, Orientation::kNorth}, - {Orientation::kNorth, Orientation::kSouth}}; - for (auto& [env_net_idx, env_poly_info_idx_set] : env_net_poly_info_idx_map) { - for (int32_t env_poly_info_idx : env_poly_info_idx_set) { - PolyInfo& env_poly_info = net_poly_info_map[env_net_idx][env_poly_info_idx]; - - for (int32_t env_eol_idx = 0; env_eol_idx < env_poly_info.convex_corner_list.size(); env_eol_idx++) { - if (!env_poly_info.convex_corner_list[env_eol_idx]) { - continue; // skip non-convex corner + PlanarRect env_edge_rect = DRCUTIL.convertToPlanarRect(gtl_rect); + PlanarRect env_prl_rect = env_edge_rect; + bool has_positive_prl = false; + { + const PolygonData& env_polygon = merged_layer_data.getPolygon(env_boundary.polygon_id); + Segment env_boundary_seg(env_boundary.begin_coord, env_boundary.end_coord); + std::vector env_prl_rect_list; + for (const MaxRectData& env_max_rect : merged_layer_data.getMaxRects(env_polygon)) { + PlanarRect candidate_rect = DRCUTIL.convertToPlanarRect(env_max_rect.rect); + if (DRCUTIL.getTouchedEdgeOrient(candidate_rect, env_boundary_seg) != env_boundary.orient) { + continue; } - PlanarCoord env_eol_coord = env_poly_info.coord_list[env_eol_idx]; - PlanarCoord env_pre_coord = env_poly_info.coord_list[getIdx(env_eol_idx - 1, env_poly_info.coord_size)]; - PlanarCoord env_post_coord = env_poly_info.coord_list[getIdx(env_eol_idx + 1, env_poly_info.coord_size)]; - if(DRCUTIL.isInside(check_rect, env_eol_coord) == false ) { - continue; + env_prl_rect_list.push_back(candidate_rect); + if (DRCUTIL.getParallelLength(corner_rect, candidate_rect) > 0) { + has_positive_prl = true; } - if (!(orientation_map[pre_orientation] == DRCUTIL.getOrientation(env_pre_coord, env_eol_coord) - && orientation_map[post_orientation] == DRCUTIL.getOrientation(env_eol_coord, env_post_coord))) { - continue; // skip if the orientation is not matched - } - int32_t x_spacing = std::abs(env_eol_coord.get_x() - eol_coord.get_x()); - int32_t y_spacing = std::abs(env_eol_coord.get_y() - eol_coord.get_y()); - int32_t MAXXY_spacing = std::max(x_spacing, y_spacing); - if (MAXXY_spacing >= required_spacing || MAXXY_spacing == 0) { - continue; // skip if the spacing is not satisfied + } + if (!env_prl_rect_list.empty()) { + env_prl_rect = env_prl_rect_list.front(); + } else if (DRCUTIL.getParallelLength(corner_rect, env_edge_rect) > 0) { + has_positive_prl = true; + } + } + + if (!DRCUTIL.isOpenOverlap(check_rect, env_edge_rect) || has_positive_prl) { + continue; + } + PlanarRect violation_rect = DRCUTIL.getSpacingRect(corner_rect, env_edge_rect); + if (violation_rect.getArea() != 0) { + std::vector> overlap_rect_hits; + merged_layer_data.queryMaxRects(DRCUTIL.convertToGTLRectInt(violation_rect), std::back_inserter(overlap_rect_hits)); + GTLPolySetInt violation_ps; + violation_ps += DRCUTIL.convertToGTLRectInt(violation_rect); + for (const auto& [overlap_gtl_rect, overlap_max_rect_id] : overlap_rect_hits) { + (void) overlap_max_rect_id; + PlanarRect overlap_rect = DRCUTIL.convertToPlanarRect(overlap_gtl_rect); + if (DRCUTIL.isOpenOverlap(violation_rect, overlap_rect)) { + violation_ps -= overlap_gtl_rect; } + } + + if (gtl::empty(violation_ps)) { + continue; + } - PlanarRect violation_rect = DRCUTIL.getBoundingBox({eol_coord, env_eol_coord}); - Violation violation; - violation.set_violation_type(ViolationType::kCornerSpacing); - violation.set_required_size(required_spacing); - violation.set_is_routing(true); - violation.set_violation_net_set({net_idx, env_net_idx}); - violation.set_layer_idx(routing_layer_idx); - violation.set_rect(violation_rect); - rv_cluster.get_violation_list().push_back(violation); + std::vector remain_violation_poly_list; + violation_ps.get(remain_violation_poly_list); + if (remain_violation_poly_list.size() != 1) { + continue; + } + + GTLRectInt remain_violation_bbox; + violation_ps.extents(remain_violation_bbox); + if (!(DRCUTIL.convertToPlanarRect(remain_violation_bbox) == violation_rect)) { + continue; } } + int32_t env_net_idx = queryNetIdxByRect(rv_layer_data, env_edge_rect); + + Violation violation; + violation.set_violation_type(ViolationType::kCornerSpacing); + violation.set_required_size(spacing); + violation.set_is_routing(true); + violation.set_violation_net_set({check_corner.net_idx, env_net_idx}); + violation.set_layer_idx(routing_layer_idx); + violation.set_rect(violation_rect); + violations.push_back(std::move(violation)); } } } } + + // postprocess, build final violations + { + if (violations.size() > 1) { + std::sort(violations.begin(), violations.end(), [](const Violation& a, const Violation& b) { + const auto& ra = a.get_rect(); + const auto& rb = b.get_rect(); + if (ra.get_ll_x() != rb.get_ll_x()) + return ra.get_ll_x() < rb.get_ll_x(); + if (ra.get_ur_x() != rb.get_ur_x()) + return ra.get_ur_x() > rb.get_ur_x(); + if (ra.get_ll_y() != rb.get_ll_y()) + return ra.get_ll_y() < rb.get_ll_y(); + return ra.get_ur_y() > rb.get_ur_y(); + }); + + std::vector results; + results.reserve(violations.size()); + + std::vector active_set; + + for (const auto& v : violations) { + bool is_redundant = false; + const auto& cur_r = v.get_rect(); + + active_set.erase( + std::remove_if(active_set.begin(), active_set.end(), [&](const Violation* p) { return p->get_rect().get_ur_x() < cur_r.get_ll_x(); }), + active_set.end()); + + for (const auto* p_active : active_set) { + if (DRCUTIL.isInside(p_active->get_rect(), cur_r)) { + is_redundant = true; + break; + } + } + + if (!is_redundant) { + results.push_back(v); + active_set.push_back(&results.back()); + } + } + violations = std::move(results); + } + + rv_cluster.get_violation_list().insert(rv_cluster.get_violation_list().end(), std::make_move_iterator(violations.begin()), + std::make_move_iterator(violations.end())); + } } -#endif } - } // namespace idrc diff --git a/src/operation/iDRC/source/module/rule_validator/rv_design_rule/EndOfLineSpacing.cpp b/src/operation/iDRC/source/module/rule_validator/rv_design_rule/EndOfLineSpacing.cpp index 5e25d0908..a1922b121 100644 --- a/src/operation/iDRC/source/module/rule_validator/rv_design_rule/EndOfLineSpacing.cpp +++ b/src/operation/iDRC/source/module/rule_validator/rv_design_rule/EndOfLineSpacing.cpp @@ -523,7 +523,7 @@ void RuleValidator::verifyEndOfLineSpacing(RVCluster& rv_cluster) if (boundary_idx >= 0) { const BoundaryData& env_boundary = merged_layer_data.getBoundary(boundary_idx); if (boundary_idx >= 0 && boundary_idx < static_cast(is_eol_boundary.size()) && is_eol_boundary[boundary_idx]) { - if (env_boundary.edge_length < eol_rule.eol_width) { + if (env_boundary.edge_length < eol_rule.eol_width && eol_rule.has_ete) { is_ete = true; } } diff --git a/src/operation/iDRC/source/module/rule_validator/rv_design_rule/ParallelRunLengthSpacing.cpp b/src/operation/iDRC/source/module/rule_validator/rv_design_rule/ParallelRunLengthSpacing.cpp index ec787ecce..ba43c73d9 100644 --- a/src/operation/iDRC/source/module/rule_validator/rv_design_rule/ParallelRunLengthSpacing.cpp +++ b/src/operation/iDRC/source/module/rule_validator/rv_design_rule/ParallelRunLengthSpacing.cpp @@ -27,122 +27,165 @@ void RuleValidator::verifyParallelRunLengthSpacing(RVCluster& rv_cluster) RoutingLayer& routing_layer = routing_layer_list[routing_layer_idx]; ParallelRunLengthSpacingRule& parallel_run_length_spacing_rule = routing_layer.get_parallel_run_length_spacing_rule(); std::map, std::map>> net_required_violation_rect_map; - std::vector> gtl_rect_id_pair_list; - std::vector violation_env_rect_list; + std::map, std::map>> env_net_required_violation_rect_map; for (auto& [net_idx, routing_net] : rv_layer_data.nets) { - if (net_idx == -1) { - continue; - } for (const MaxRectData& max_rect_data : rv_layer_data.getMaxRects(routing_net)) { PlanarRect rect = DRCUTIL.convertToPlanarRect(max_rect_data.rect); - if (max_rect_data.isEnv) { + if (net_idx == -1) { continue; } + bool has_spacing_table = parallel_run_length_spacing_rule.has_spacing_table; + bool has_spacing_list = parallel_run_length_spacing_rule.has_spacing_list; - gtl_rect_id_pair_list.clear(); - violation_env_rect_list.clear(); + std::vector> neighbor_rect_id_list; { - int32_t width_max_spacing = parallel_run_length_spacing_rule.getSpacing(rect.getWidth(), rect.getLength()); - PlanarRect check_rect = DRCUTIL.getEnlargedRect(rect, width_max_spacing); - rv_layer_data.queryMaxRects(DRCUTIL.convertToGTLRectInt(check_rect), std::back_inserter(gtl_rect_id_pair_list)); - for (const auto& [gtl_rect, max_rect_id] : gtl_rect_id_pair_list) { - (void) max_rect_id; - violation_env_rect_list.push_back(DRCUTIL.convertToPlanarRect(gtl_rect)); - } + int32_t spacing_table_check = has_spacing_table ? parallel_run_length_spacing_rule.getMaxSpacing() : 0; + int32_t spacing_list_check = has_spacing_list ? parallel_run_length_spacing_rule.getSpacingMaxWidth() : 0; + int32_t check_spacing = std::max(spacing_table_check, spacing_list_check); + + PlanarRect check_rect = DRCUTIL.getEnlargedRect(rect, check_spacing); + rv_layer_data.queryMaxRects(DRCUTIL.convertToGTLRectInt(check_rect), std::back_inserter(neighbor_rect_id_list)); } - for (const auto& [env_gtl_rect, env_max_rect_id] : gtl_rect_id_pair_list) { + + for (const auto& [gtl_rect, env_max_rect_id] : neighbor_rect_id_list) { + PlanarRect env_rect = DRCUTIL.convertToPlanarRect(gtl_rect); int32_t env_net_idx = rv_layer_data.getNetIdxByMaxRectId(env_max_rect_id); - PlanarRect env_rect = DRCUTIL.convertToPlanarRect(env_gtl_rect); if (DRCUTIL.isClosedOverlap(rect, env_rect)) { continue; } - // prl with overlaped shapes - int32_t prl = DRCUTIL.getParallelLength(rect, env_rect); - int32_t required_size = parallel_run_length_spacing_rule.getSpacing(std::max(rect.getWidth(), env_rect.getWidth()), prl); - int32_t spacing = DRCUTIL.getEuclideanDistance(env_rect, rect); - if (required_size <= spacing) { + + PlanarRect violation_rect = DRCUTIL.getSpacingRect(rect, env_rect); + bool is_prl_violation = false, is_spacing_violation = false; + int32_t real_prl_spacing = 0, real_spacing = 0; + // prl rules + if (has_spacing_table) { + int32_t prl = DRCUTIL.getParallelLength(rect, env_rect); + real_prl_spacing = parallel_run_length_spacing_rule.getSpacing(std::max(rect.getWidth(), env_rect.getWidth()), prl); + is_prl_violation = DRCUTIL.getEuclideanDistance(rect, env_rect) < real_prl_spacing; + } + + // spacing rules + if (has_spacing_list) { + real_spacing = parallel_run_length_spacing_rule.getSpacingWithWidth(std::max(rect.getWidth(), env_rect.getWidth())); + is_spacing_violation = DRCUTIL.getEuclideanDistance(rect, env_rect) < real_spacing; + } + + if (!is_prl_violation && !is_spacing_violation) { continue; } - PlanarRect violation_rect = DRCUTIL.getSpacingRect(rect, env_rect); + // sameNet + if (net_idx == env_net_idx) { + std::set orient_inside; + bool total_inside = false; + // for violation area = 0 + bool zero_area_inside = false; + GTLPolySetInt violation_ps; + violation_ps += DRCUTIL.convertToGTLRectInt(violation_rect); + for (const auto& [gtl_rect, max_rect_id] : neighbor_rect_id_list) { + PlanarRect violation_env_rect = DRCUTIL.convertToPlanarRect(gtl_rect); + int32_t violation_env_net_idx = rv_layer_data.getNetIdxByMaxRectId(max_rect_id); + if (violation_env_net_idx == net_idx) { + if (DRCUTIL.isOpenOverlap(violation_env_rect, violation_rect)) { + violation_ps -= gtl_rect; + } + if (gtl::empty(violation_ps)) { + total_inside = true; + } + if (DRCUTIL.isInside(violation_env_rect, violation_rect)) { + zero_area_inside = true; + } - if (prl > 0 || (prl < 0 && env_net_idx == net_idx)) { - GTLPolySetInt vioaltion_around_set; - for (const auto& [around_gtl_rect, around_max_rect_id] : gtl_rect_id_pair_list) { - (void) around_max_rect_id; - PlanarRect violation_env_rect = DRCUTIL.convertToPlanarRect(around_gtl_rect); - if (DRCUTIL.isOpenOverlap(violation_rect, violation_env_rect)) { - vioaltion_around_set += DRCUTIL.convertToGTLRectInt(violation_env_rect); + for (auto orient : {Orientation::kEast, Orientation::kWest, Orientation::kNorth, Orientation::kSouth}) { + if (!DRCUTIL.exist(orient_inside, orient) && DRCUTIL.isInside(violation_env_rect, violation_rect.getOrientEdge(orient))) { + orient_inside.insert(orient); + } + } } } - if (!gtl::empty(vioaltion_around_set)) { - GTLRectInt min_violation; - gtl::extents(min_violation, DRCUTIL.convertToGTLRectInt(violation_rect) - vioaltion_around_set); - violation_rect = DRCUTIL.convertToPlanarRect(min_violation); - } + bool hor = DRCUTIL.exist(orient_inside, Orientation::kWest) && DRCUTIL.exist(orient_inside, Orientation::kEast); + bool ver = DRCUTIL.exist(orient_inside, Orientation::kNorth) && DRCUTIL.exist(orient_inside, Orientation::kSouth); + if (violation_rect.getArea() == 0) { + if (zero_area_inside) { + continue; + } + } else if ((orient_inside.size() != 0 && !hor && !ver) || total_inside) { continue; + } else { + GTLRectInt violation_bbox; + violation_ps.extents(violation_bbox); + violation_rect = DRCUTIL.convertToPlanarRect(violation_bbox); } } - // exact prl - if (prl > 0) { - prl = DRCUTIL.getParallelLength(violation_rect, rect); - required_size = parallel_run_length_spacing_rule.getSpacing(std::max(rect.getWidth(), env_rect.getWidth()), prl); - if (required_size <= spacing) { - continue; + // diffNet + if (net_idx != env_net_idx && DRCUTIL.getParallelLength(rect, env_rect) > 0) { + bool total_inside = false; + GTLPolySetInt violation_ps; + violation_ps += DRCUTIL.convertToGTLRectInt(violation_rect); + for (const auto& [gtl_rect, max_rect_id] : neighbor_rect_id_list) { + PlanarRect violation_env_rect = DRCUTIL.convertToPlanarRect(gtl_rect); + if (DRCUTIL.isOpenOverlap(violation_env_rect, violation_rect)) { + violation_ps -= gtl_rect; + } + } + if (gtl::empty(violation_ps)) { + total_inside = true; + } + GTLRectInt violation_bbox; + violation_ps.extents(violation_bbox); + PlanarRect new_violation_rect = DRCUTIL.convertToPlanarRect(violation_bbox); + if (!DRCUTIL.isClosedOverlap(new_violation_rect, rect) || !DRCUTIL.isClosedOverlap(new_violation_rect, env_rect)) { + total_inside = true; } - } - bool is_zero_area = (violation_rect.getArea() == 0); - bool is_horizontal_inside = false, is_vertical_inside = false; - bool valid_violation = true; - if (DRCUTIL.isInside(rect, violation_rect)) { - continue; + if (total_inside) { + continue; + } } - for (PlanarRect& violation_env_rect : violation_env_rect_list) { - if (!DRCUTIL.isClosedOverlap(violation_env_rect, violation_rect)) { - continue; + if (max_rect_data.isEnv && rv_layer_data.getMaxRect(env_max_rect_id).isEnv) { + if (is_prl_violation) { + env_net_required_violation_rect_map[{net_idx, env_net_idx}][real_prl_spacing].push_back(violation_rect); } - if (violation_env_rect == env_rect || violation_env_rect == rect) { - continue; + if (is_spacing_violation) { + env_net_required_violation_rect_map[{net_idx, env_net_idx}][real_spacing].push_back(violation_rect); } - - if (is_zero_area) { - if (DRCUTIL.isInside(violation_env_rect, violation_rect) && DRCUTIL.isInside(violation_env_rect, violation_rect.getMidPoint(), false)) { - valid_violation = false; - break; - } - if (net_idx == env_net_idx && (DRCUTIL.isInside(violation_env_rect, violation_rect))) { - valid_violation = false; - break; - } - } else if (prl < 0 && env_net_idx == net_idx) { - if (!is_horizontal_inside - && (DRCUTIL.isInside(violation_env_rect, DRCUTIL.getRect(violation_rect.getOrientEdge(Orientation::kWest))) - || DRCUTIL.isInside(violation_env_rect, DRCUTIL.getRect(violation_rect.getOrientEdge(Orientation::kEast))))) { - is_horizontal_inside = true; - } - if (!is_vertical_inside - && (DRCUTIL.isInside(violation_env_rect, DRCUTIL.getRect(violation_rect.getOrientEdge(Orientation::kSouth))) - || DRCUTIL.isInside(violation_env_rect, DRCUTIL.getRect(violation_rect.getOrientEdge(Orientation::kNorth))))) { - is_vertical_inside = true; - } + } else { + if (is_prl_violation) { + net_required_violation_rect_map[{net_idx, env_net_idx}][real_prl_spacing].push_back(violation_rect); + } + if (is_spacing_violation) { + net_required_violation_rect_map[{net_idx, env_net_idx}][real_spacing].push_back(violation_rect); } } - if (!valid_violation) { - continue; + } + } + } + + std::map, std::map>> exclude_env; + for (auto& [violation_net_set, required_violation_rect_map] : net_required_violation_rect_map) { + for (auto& [required_size, violation_rect_list] : required_violation_rect_map) { + for (PlanarRect& violation_rect : violation_rect_list) { + auto& env_violations = env_net_required_violation_rect_map[violation_net_set][required_size]; + bool is_env_inside = false; + for (auto& env_violation : env_violations) { + bool closed_inside = (violation_rect.getXSpan() == env_violation.getXSpan()) || (violation_rect.getYSpan() == env_violation.getYSpan()); + if (DRCUTIL.isInside(env_violation, violation_rect) && closed_inside) { + is_env_inside = true; + break; + } } - if (!is_zero_area && is_horizontal_inside && is_vertical_inside) { + if (is_env_inside) { continue; } - net_required_violation_rect_map[{net_idx, env_net_idx}][required_size].push_back(violation_rect); + exclude_env[violation_net_set][required_size].push_back(violation_rect); } } } - std::map rect_computed; - for (auto& [violation_net_set, required_violation_rect_map] : net_required_violation_rect_map) { + + for (auto& [violation_net_set, required_violation_rect_map] : exclude_env) { for (auto& [required_size, violation_rect_list] : required_violation_rect_map) { for (PlanarRect& violation_rect : violation_rect_list) { bool is_inside = false; diff --git a/src/operation/iDRC/source/module/rule_validator/rv_design_rule/SameLayerCutSpacing.cpp b/src/operation/iDRC/source/module/rule_validator/rv_design_rule/SameLayerCutSpacing.cpp index ef6453c4e..756f298e6 100644 --- a/src/operation/iDRC/source/module/rule_validator/rv_design_rule/SameLayerCutSpacing.cpp +++ b/src/operation/iDRC/source/module/rule_validator/rv_design_rule/SameLayerCutSpacing.cpp @@ -14,6 +14,7 @@ // // See the Mulan PSL v2 for more details. // *************************************************************************************** +#include "PlanarRect.hpp" #include "RuleValidator.hpp" namespace idrc { @@ -36,9 +37,21 @@ void RuleValidator::verifySameLayerCutSpacing(RVCluster& rv_cluster) } CutLayer& cut_layer = cut_layer_list[cut_layer_idx]; SameLayerCutSpacingRule& same_layer_cut_spacing_rule = cut_layer.get_same_layer_cut_spacing_rule(); - int32_t curr_spacing = same_layer_cut_spacing_rule.curr_spacing; - int32_t curr_prl_spacing = same_layer_cut_spacing_rule.curr_prl_spacing; - int32_t curr_prl = -1 * same_layer_cut_spacing_rule.curr_prl; + bool has_same_net = false; + int32_t curr_same_net_spacing = -1; + int32_t curr_spacing = -1; + int32_t curr_prl_spacing = -1; + int32_t curr_prl = -1; + for (auto& spacing_rule : same_layer_cut_spacing_rule.spacings) { + if (spacing_rule.has_same_net) { + has_same_net = true; + curr_same_net_spacing = spacing_rule.curr_spacing; + } else { + curr_spacing = spacing_rule.curr_spacing; + } + curr_prl = -1 * spacing_rule.curr_prl; + curr_prl_spacing = spacing_rule.curr_prl_spacing; + } for (const CutData& cut_data : cut_layer_data.getCuts()) { GTLRectInt cut_gtl_rect = cut_data.rect; @@ -56,14 +69,20 @@ void RuleValidator::verifySameLayerCutSpacing(RVCluster& rv_cluster) } for (const CutData& overlap_cut_data : overlap_cut_list) { int32_t env_net_idx = overlap_cut_data.net_idx; + int32_t net_spacing = curr_spacing; PlanarRect env_rect = DRCUTIL.convertToPlanarRect(overlap_cut_data.rect); + PlanarRect violation_rect = DRCUTIL.getSpacingRect(cut_rect, env_rect); + if ((env_net_idx == net_idx) && has_same_net) { + net_spacing = curr_same_net_spacing; + } // ignore cutShort if (DRCUTIL.isClosedOverlap(cut_rect, env_rect)) { continue; } bool use_prl_spacing = false, use_spaing = false; use_prl_spacing = DRCUTIL.isOpenOverlap(checking_region_horizontal, env_rect) || DRCUTIL.isOpenOverlap(checking_region_vertical, env_rect); - use_spaing = DRCUTIL.getEuclideanDistance(cut_rect, env_rect) < curr_spacing; + use_prl_spacing &= (curr_prl_spacing != -1); + use_spaing = DRCUTIL.getEuclideanDistance(cut_rect, env_rect) < net_spacing; if (!use_prl_spacing && !use_spaing) { continue; } @@ -72,8 +91,8 @@ void RuleValidator::verifySameLayerCutSpacing(RVCluster& rv_cluster) violation.set_is_routing(true); violation.set_violation_net_set({net_idx, env_net_idx}); violation.set_layer_idx(routing_layer_idx); - violation.set_rect(DRCUTIL.getSpacingRect(cut_rect, env_rect)); - violation.set_required_size(use_prl_spacing ? curr_prl_spacing : curr_spacing); + violation.set_rect(violation_rect); + violation.set_required_size(use_prl_spacing ? curr_prl_spacing : net_spacing); layer_violations.push_back(std::move(violation)); } } diff --git a/src/operation/iDRC/source/toolkit/utility/Utility.hpp b/src/operation/iDRC/source/toolkit/utility/Utility.hpp index e247e71b5..af3fd6804 100644 --- a/src/operation/iDRC/source/toolkit/utility/Utility.hpp +++ b/src/operation/iDRC/source/toolkit/utility/Utility.hpp @@ -190,6 +190,34 @@ class Utility return orientation_list; } + // 获取 rect 某个角点向内部的两个方向 + static bool getCornerOrientsInRect(const PlanarRect& rect, const PlanarCoord& corner_point, Orientation& orient1, Orientation& orient2) + { + int32_t x = corner_point.get_x(); + int32_t y = corner_point.get_y(); + if (x == rect.get_ll_x() && y == rect.get_ll_y()) { + orient1 = Orientation::kEast; + orient2 = Orientation::kNorth; + return true; + } + if (x == rect.get_ur_x() && y == rect.get_ur_y()) { + orient1 = Orientation::kWest; + orient2 = Orientation::kSouth; + return true; + } + if (x == rect.get_ll_x() && y == rect.get_ur_y()) { + orient1 = Orientation::kEast; + orient2 = Orientation::kSouth; + return true; + } + if (x == rect.get_ur_x() && y == rect.get_ll_y()) { + orient1 = Orientation::kWest; + orient2 = Orientation::kNorth; + return true; + } + return false; + } + static Direction getOppositeDirection(Direction direction) { if (direction == Direction::kHorizontal) { @@ -886,15 +914,17 @@ class Utility static PlanarRect getRect(Segment segment) { return getRect(segment.get_first(), segment.get_second()); } // 三个点的叉乘 - static int32_t crossProduct(Rotation rotation, PlanarCoord& first_coord, PlanarCoord& second_coord, PlanarCoord& third_coord) + static int64_t crossProduct(Rotation rotation, PlanarCoord& first_coord, PlanarCoord& second_coord, PlanarCoord& third_coord) { - int32_t cross_product = 0; + // Use 64-bit arithmetic here because large layout coordinates can make the + // area term exceed int32_t and flip the sign, which breaks convex/concave checks. + int64_t cross_product = 0; if (rotation == Rotation::kClockwise) { - cross_product = ((second_coord.get_x() - first_coord.get_x()) * (third_coord.get_y() - first_coord.get_y()) - - (second_coord.get_y() - first_coord.get_y()) * (third_coord.get_x() - first_coord.get_x())); + cross_product = (static_cast(second_coord.get_x()) - first_coord.get_x()) * (static_cast(third_coord.get_y()) - first_coord.get_y()) + - (static_cast(second_coord.get_y()) - first_coord.get_y()) * (static_cast(third_coord.get_x()) - first_coord.get_x()); } else if (rotation == Rotation::kCounterclockwise) { - cross_product = ((second_coord.get_x() - third_coord.get_x()) * (first_coord.get_y() - third_coord.get_y()) - - (second_coord.get_y() - third_coord.get_y()) * (first_coord.get_x() - third_coord.get_x())); + cross_product = (static_cast(second_coord.get_x()) - third_coord.get_x()) * (static_cast(first_coord.get_y()) - third_coord.get_y()) + - (static_cast(second_coord.get_y()) - third_coord.get_y()) * (static_cast(first_coord.get_x()) - third_coord.get_x()); } else { DRCLOG.error(Loc::current(), "The rotation is error!"); } @@ -1543,6 +1573,24 @@ class Utility return string; } + static std::string getBooleanName(bool value) { return value ? "true" : "false"; } + + template + static std::string getStringList(const std::vector& value_list, const std::string& delimiter = ", ", const std::string& prefix = "[", + const std::string& suffix = "]") + { + std::stringstream oss; + oss << prefix; + for (size_t i = 0; i < value_list.size(); ++i) { + if (i > 0) { + oss << delimiter; + } + oss << value_list[i]; + } + oss << suffix; + return oss.str(); + } + template static void pushStream(Stream* stream, T t, Args... args) {