From bcebb1966594eddbe7b2ca352d7fe4552a420fb7 Mon Sep 17 00:00:00 2001 From: Jeff Young Date: Sun, 11 Oct 2020 11:19:07 +0100 Subject: [PATCH] Add implied diffpair netclass rules. --- pcbnew/drc/drc_engine.cpp | 193 ++++++++++++++++++------------ pcbnew/router/pns_kicad_iface.cpp | 94 +++++++-------- 2 files changed, 156 insertions(+), 131 deletions(-) diff --git a/pcbnew/drc/drc_engine.cpp b/pcbnew/drc/drc_engine.cpp index 62daf8537a..e37ec20e58 100644 --- a/pcbnew/drc/drc_engine.cpp +++ b/pcbnew/drc/drc_engine.cpp @@ -179,118 +179,155 @@ void DRC_ENGINE::loadImplicitRules() // 3) per-netclass rules - std::vector netclassRules; + std::vector netclassClearanceRules; + std::vector netclassItemSpecificRules; - auto makeNetclassRule = - [&]( const NETCLASSPTR& netclass, bool isDefault ) + auto makeNetclassRules = + [&]( const NETCLASSPTR& nc, bool isDefault ) { - // Only add constraints for netclass values which are larger than board minimums. - // That way board minimums will still enforce a global minimum. + // Note: only add constraints for netclass values which are larger than board + // minimums. (This ensures that the board minimums will still enforce a global + // lower bound.) - DRC_RULE* rule = new DRC_RULE; - wxString name = netclass->GetName(); + wxString ncName = nc->GetName(); - rule->m_Name = wxString::Format( _( "netclass '%s'" ), name ); - rule->m_Implicit = true; + DRC_RULE* rule; + wxString expr; - wxString expr = wxString::Format( "A.NetClass == '%s'", name ); - DRC_RULE_CONDITION* condition = new DRC_RULE_CONDITION( expr ); - - rule->m_Condition = condition; - netclassRules.push_back( rule ); - - if( netclass->GetClearance() > bds.m_MinClearance ) + if( nc->GetClearance() > bds.m_MinClearance + || nc->GetTrackWidth() > bds.m_TrackMinWidth ) { - DRC_CONSTRAINT ncClearanceConstraint( DRC_CONSTRAINT_TYPE_CLEARANCE ); - ncClearanceConstraint.Value().SetMin( netclass->GetClearance() ); - rule->AddConstraint( ncClearanceConstraint ); + rule = new DRC_RULE; + rule->m_Name = wxString::Format( _( "netclass '%s'" ), ncName ); + rule->m_Implicit = true; + + expr = wxString::Format( "A.NetClass == '%s'", + ncName ); + rule->m_Condition = new DRC_RULE_CONDITION( expr ); + netclassClearanceRules.push_back( rule ); + + if( nc->GetClearance() > bds.m_MinClearance ) + { + DRC_CONSTRAINT ncClearanceConstraint( DRC_CONSTRAINT_TYPE_CLEARANCE ); + ncClearanceConstraint.Value().SetMin( nc->GetClearance() ); + rule->AddConstraint( ncClearanceConstraint ); + } + + if( nc->GetTrackWidth() > bds.m_TrackMinWidth ) + { + DRC_CONSTRAINT ncWidthConstraint( DRC_CONSTRAINT_TYPE_TRACK_WIDTH ); + ncWidthConstraint.Value().SetMin( nc->GetTrackWidth() ); + rule->AddConstraint( ncWidthConstraint ); + } } - if( netclass->GetTrackWidth() > bds.m_TrackMinWidth ) + if( nc->GetDiffPairWidth() || nc->GetDiffPairGap() ) { - DRC_CONSTRAINT ncWidthConstraint( DRC_CONSTRAINT_TYPE_TRACK_WIDTH ); - ncWidthConstraint.Value().SetMin( netclass->GetTrackWidth() ); - rule->AddConstraint( ncWidthConstraint ); + rule = new DRC_RULE; + rule->m_Name = wxString::Format( _( "netclass '%s'" ), ncName ); + rule->m_Implicit = true; + + expr = wxString::Format( "A.NetClass == '%s' && A.isDiffPair()", + ncName ); + rule->m_Condition = new DRC_RULE_CONDITION( expr ); + netclassItemSpecificRules.push_back( rule ); + + if( nc->GetDiffPairWidth() ) + { + DRC_CONSTRAINT constraint( DRC_CONSTRAINT_TYPE_TRACK_WIDTH ); + constraint.Value().SetMin( nc->GetDiffPairWidth() ); + rule->AddConstraint( constraint ); + } + + if( nc->GetDiffPairGap() ) + { + DRC_CONSTRAINT constraint( DRC_CONSTRAINT_TYPE_DIFF_PAIR_GAP ); + constraint.Value().SetMin( nc->GetDiffPairGap() ); + rule->AddConstraint( constraint ); + } } - // We need separate rules for micro-vias and other vias because they use the - // same constraints. - // - // Note that since these are unary rules they don't need to be sorted, so we - // add them directly to the current rule set. - - rule = new DRC_RULE; - - rule->m_Name = wxString::Format( _( "netclass '%s'" ), name ); - rule->m_Implicit = true; - - expr = wxString::Format( "A.NetClass == '%s' && A.Via_Type != 'micro_via'", name ); - condition = new DRC_RULE_CONDITION( expr ); - - rule->m_Condition = condition; - addRule( rule ); - - if( netclass->GetViaDiameter() > bds.m_ViasMinSize ) + if( nc->GetViaDiameter() > bds.m_ViasMinSize + || nc->GetViaDrill() > bds.m_MinThroughDrill ) { - DRC_CONSTRAINT ncViaDiaConstraint( DRC_CONSTRAINT_TYPE_VIA_DIAMETER ); - ncViaDiaConstraint.Value().SetMin( netclass->GetViaDiameter() ); - rule->AddConstraint( ncViaDiaConstraint ); + rule = new DRC_RULE; + rule->m_Name = wxString::Format( _( "netclass '%s'" ), ncName ); + rule->m_Implicit = true; + + expr = wxString::Format( "A.NetClass == '%s' && A.Via_Type != 'micro_via'", + ncName ); + rule->m_Condition = new DRC_RULE_CONDITION( expr ); + netclassItemSpecificRules.push_back( rule ); + + if( nc->GetViaDiameter() > bds.m_ViasMinSize ) + { + DRC_CONSTRAINT constraint( DRC_CONSTRAINT_TYPE_VIA_DIAMETER ); + constraint.Value().SetMin( nc->GetViaDiameter() ); + rule->AddConstraint( constraint ); + } + + if( nc->GetViaDrill() > bds.m_MinThroughDrill ) + { + DRC_CONSTRAINT constraint( DRC_CONSTRAINT_TYPE_HOLE_SIZE ); + constraint.Value().SetMin( nc->GetViaDrill() ); + rule->AddConstraint( constraint ); + } } - if( netclass->GetViaDrill() > bds.m_MinThroughDrill ) + if( nc->GetuViaDiameter() > bds.m_MicroViasMinSize + || nc->GetuViaDrill() > bds.m_MicroViasMinDrill ) { - DRC_CONSTRAINT ncViaDrillConstraint( DRC_CONSTRAINT_TYPE_HOLE_SIZE ); - ncViaDrillConstraint.Value().SetMin( netclass->GetViaDrill() ); - rule->AddConstraint( ncViaDrillConstraint ); - } + rule = new DRC_RULE; + rule->m_Name = wxString::Format( _( "netclass '%s'" ), ncName ); + rule->m_Implicit = true; - rule = new DRC_RULE; + expr = wxString::Format( "A.NetClass == '%s' && A.Via_Type == 'micro_via'", + ncName ); + rule->m_Condition = new DRC_RULE_CONDITION( expr ); + netclassItemSpecificRules.push_back( rule ); - rule->m_Name = wxString::Format( _( "netclass '%s'" ), name ); - rule->m_Implicit = true; + if( nc->GetuViaDiameter() > bds.m_MicroViasMinSize ) + { + DRC_CONSTRAINT constraint( DRC_CONSTRAINT_TYPE_VIA_DIAMETER ); + constraint.Value().SetMin( nc->GetuViaDiameter() ); + rule->AddConstraint( constraint ); + } - expr = wxString::Format( "A.NetClass == '%s' && A.Via_Type == 'micro_via'", name ); - condition = new DRC_RULE_CONDITION( expr ); - - rule->m_Condition = condition; - addRule( rule ); - - if( netclass->GetuViaDiameter() > bds.m_MicroViasMinSize ) - { - DRC_CONSTRAINT ncuViaDiaConstraint( DRC_CONSTRAINT_TYPE_VIA_DIAMETER ); - ncuViaDiaConstraint.Value().SetMin( netclass->GetuViaDiameter() ); - rule->AddConstraint( ncuViaDiaConstraint ); - } - - if( netclass->GetuViaDrill() > bds.m_MicroViasMinDrill ) - { - DRC_CONSTRAINT ncuViaDrillConstraint( DRC_CONSTRAINT_TYPE_HOLE_SIZE ); - ncuViaDrillConstraint.Value().SetMin( netclass->GetuViaDrill() ); - rule->AddConstraint( ncuViaDrillConstraint ); + if( nc->GetuViaDrill() > bds.m_MicroViasMinDrill ) + { + DRC_CONSTRAINT constraint( DRC_CONSTRAINT_TYPE_HOLE_SIZE ); + constraint.Value().SetMin( nc->GetuViaDrill() ); + rule->AddConstraint( constraint ); + } } }; m_board->SynchronizeNetsAndNetClasses(); - makeNetclassRule( bds.GetNetClasses().GetDefault(), true ); + makeNetclassRules( bds.GetNetClasses().GetDefault(), true ); for( const std::pair& netclass : bds.GetNetClasses() ) - makeNetclassRule( netclass.second, false ); + makeNetclassRules( netclass.second, false ); - // These have to be sorted by min clearance so the right one fires if 'A' and 'B' belong - // to two different netclasses. + // The netclass clearance rules have to be sorted by min clearance so the right one fires + // if 'A' and 'B' belong to two different netclasses. + // + // The item-specific netclass rules are all unary, so there's no 'A' vs 'B' issue. - std::sort( netclassRules.begin(), netclassRules.end(), + std::sort( netclassClearanceRules.begin(), netclassClearanceRules.end(), []( DRC_RULE* lhs, DRC_RULE* rhs ) { return lhs->m_Constraints[0].m_Value.Min() < rhs->m_Constraints[0].m_Value.Min(); } ); - for( DRC_RULE* netclassRule : netclassRules ) - addRule( netclassRule ); + for( DRC_RULE* ncRule : netclassClearanceRules ) + addRule( ncRule ); + + for( DRC_RULE* ncRule : netclassItemSpecificRules ) + addRule( ncRule ); ReportAux( wxString::Format( "Building %d implicit netclass rules", - (int) netclassRules.size() ) ); + (int) netclassClearanceRules.size() ) ); } static wxString formatConstraint( const DRC_CONSTRAINT& constraint ) diff --git a/pcbnew/router/pns_kicad_iface.cpp b/pcbnew/router/pns_kicad_iface.cpp index 245cfe469b..31cc6c457d 100644 --- a/pcbnew/router/pns_kicad_iface.cpp +++ b/pcbnew/router/pns_kicad_iface.cpp @@ -246,9 +246,10 @@ bool PNS_PCBNEW_RULE_RESOLVER::QueryConstraint( PNS::CONSTRAINT_TYPE aType, aConstraint->m_RuleName = hostConstraint.GetName(); aConstraint->m_Type = aType; return true; - } - return false; + default: + return false; + } } @@ -256,22 +257,24 @@ int PNS_PCBNEW_RULE_RESOLVER::Clearance( const PNS::ITEM* aA, const PNS::ITEM* a { PNS::CONSTRAINT constraint; bool ok = false; - int rv; + int rv = 0; if( IsDiffPair( aA, aB ) ) { // for diff pairs, we use the gap value for shoving/dragging - ok = QueryConstraint( PNS::CONSTRAINT_TYPE::CT_DIFF_PAIR_GAP, aA, aB, aA->Layer(), &constraint ); + ok = QueryConstraint( PNS::CONSTRAINT_TYPE::CT_DIFF_PAIR_GAP, aA, aB, aA->Layer(), + &constraint ); rv = constraint.m_Value.Opt(); - printf("QueryDPCL %d\n", rv); + printf( "QueryDPCL %d\n", rv ); } if( !ok ) { - ok = QueryConstraint( PNS::CONSTRAINT_TYPE::CT_CLEARANCE, aA, aB, aA->Layer(), &constraint ); + ok = QueryConstraint( PNS::CONSTRAINT_TYPE::CT_CLEARANCE, aA, aB, aA->Layer(), + &constraint ); assert( ok ); rv = constraint.m_Value.Min(); - printf("QueryCL %d\n", rv); + printf( "QueryCL %d\n", rv ); } assert( ok ); @@ -325,59 +328,45 @@ int PNS_KICAD_IFACE_BASE::inheritTrackWidth( PNS::ITEM* aItem ) bool PNS_KICAD_IFACE_BASE::ImportSizes( PNS::SIZES_SETTINGS& aSizes, PNS::ITEM* aStartItem, int aNet ) { - BOARD_DESIGN_SETTINGS &bds = m_board->GetDesignSettings(); + BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings(); + PNS::CONSTRAINT constraint; - int trackWidth = 0; + int trackWidth = bds.m_TrackMinWidth; if( bds.m_UseConnectedTrackWidth && aStartItem != nullptr ) { trackWidth = inheritTrackWidth( aStartItem ); } - - if( !trackWidth && bds.UseNetClassTrack() && aStartItem ) // netclass value + else if( bds.UseNetClassTrack() && aStartItem ) // netclass value { - PNS::CONSTRAINT constraint; - bool ok = m_ruleResolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_WIDTH, - aStartItem, nullptr, aStartItem->Layer(), - &constraint ); - - if( ok ) + if( m_ruleResolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_WIDTH, aStartItem, nullptr, + aStartItem->Layer(), &constraint ) ) { - trackWidth = constraint.m_Value.HasOpt() ? constraint.m_Value.Opt() - : constraint.m_Value.Min(); + trackWidth = constraint.m_Value.OptThenMin(); } } - - if( !trackWidth ) + else { trackWidth = bds.GetCurrentTrackWidth(); } aSizes.SetTrackWidth( trackWidth ); - int viaDiameter = 0; - int viaDrill = 0; + int viaDiameter = bds.m_ViasMinSize; + int viaDrill = bds.m_MinThroughDrill; if( bds.UseNetClassVia() && aStartItem ) // netclass value { - PNS::CONSTRAINT diaConstraint, drillConstraint; - bool okDia = m_ruleResolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_VIA_DIAMETER, - aStartItem, nullptr, aStartItem->Layer(), - &diaConstraint ); - bool okDrill = m_ruleResolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_VIA_HOLE, - aStartItem, nullptr, aStartItem->Layer(), - &drillConstraint ); - - if( okDia ) + if( m_ruleResolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_VIA_DIAMETER, aStartItem, + nullptr, aStartItem->Layer(), &constraint ) ) { - viaDiameter = diaConstraint.m_Value.HasOpt() ? diaConstraint.m_Value.Opt() - : diaConstraint.m_Value.Min(); + viaDiameter = constraint.m_Value.OptThenMin(); } - if( okDrill ) + if( m_ruleResolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_VIA_HOLE, aStartItem, + nullptr, aStartItem->Layer(), &constraint ) ) { - viaDrill = drillConstraint.m_Value.HasOpt() ? drillConstraint.m_Value.Opt() - : drillConstraint.m_Value.Min(); + viaDrill = constraint.m_Value.OptThenMin(); } } else @@ -389,25 +378,24 @@ bool PNS_KICAD_IFACE_BASE::ImportSizes( PNS::SIZES_SETTINGS& aSizes, PNS::ITEM* aSizes.SetViaDiameter( viaDiameter ); aSizes.SetViaDrill( viaDrill ); - int diffPairWidth = 0; - int diffPairGap = 0; - int diffPairViaGap = 0; + int diffPairWidth = bds.m_TrackMinWidth; + int diffPairGap = bds.m_MinClearance; + int diffPairViaGap = bds.m_MinClearance; if( bds.UseNetClassDiffPair() && aStartItem ) { - PNS::CONSTRAINT widthConstraint, gapConstraint; - bool okWidth = m_ruleResolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_WIDTH, - aStartItem, nullptr, aStartItem->Layer(), - &widthConstraint ); - bool okGap = m_ruleResolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_DIFF_PAIR_GAP, - aStartItem, nullptr, aStartItem->Layer(), - &gapConstraint ); + if( m_ruleResolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_WIDTH, aStartItem, + nullptr, aStartItem->Layer(), &constraint ) ) + { + diffPairWidth = constraint.m_Value.OptThenMin(); + } - if( okWidth ) - diffPairWidth = widthConstraint.m_Value.OptThenMin(); - - if( okGap ) - diffPairViaGap = diffPairGap = gapConstraint.m_Value.OptThenMin(); + if( m_ruleResolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_DIFF_PAIR_GAP, aStartItem, + nullptr, aStartItem->Layer(), &constraint ) ) + { + diffPairGap = constraint.m_Value.OptThenMin(); + diffPairViaGap = constraint.m_Value.OptThenMin(); + } } else if( bds.UseCustomDiffPairDimensions() ) { @@ -416,7 +404,7 @@ bool PNS_KICAD_IFACE_BASE::ImportSizes( PNS::SIZES_SETTINGS& aSizes, PNS::ITEM* diffPairViaGap = bds.GetCustomDiffPairViaGap(); } - //printf("DPWidth: %d gap %d\n", diffPairWidth, diffPairGap ); + //printf( "DPWidth: %d gap %d\n", diffPairWidth, diffPairGap ); aSizes.SetDiffPairWidth( diffPairWidth ); aSizes.SetDiffPairGap( diffPairGap );