Redo DRC rules to get ready for new system.

This commit is contained in:
Jeff Young 2020-05-23 22:48:24 +01:00
parent 2164501b06
commit 416d82727f
20 changed files with 385 additions and 369 deletions

View File

@ -1,8 +1,10 @@
allow
annulus_width
blind_via
board_edge
clearance
condition
constraint
disallow
track_width
graphic
hole
@ -10,10 +12,12 @@ match_area
match_layer
match_netclass
match_type
max
micro_via
min
npth
opt
pad
priority
pth
relaxed
rule

View File

@ -397,10 +397,6 @@ public:
*/
int GetSmallestClearanceValue();
int GetRuleClearance( const BOARD_ITEM* aItem, const NETCLASS* aItemNetclass,
const BOARD_ITEM* bItem, const NETCLASS* bItemNetclass,
wxString* aSource );
/**
* Function GetCurrentMicroViaSize
* @return the current micro via size,

View File

@ -3,7 +3,7 @@
*
* Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 1992-2020 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -23,11 +23,6 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file board_connected_item.cpp
* @brief BOARD_CONNECTED_ITEM class functions.
*/
#include <fctsys.h>
#include <pcbnew.h>
@ -37,9 +32,6 @@
#include <connectivity/connectivity_data.h>
const wxChar* const traceMask = wxT( "BOARD_CONNECTED_ITEM" );
BOARD_CONNECTED_ITEM::BOARD_CONNECTED_ITEM( BOARD_ITEM* aParent, KICAD_T idtype ) :
BOARD_ITEM( aParent, idtype ), m_netinfo( NETINFO_LIST::OrphanedItem() )
{
@ -79,6 +71,27 @@ bool BOARD_CONNECTED_ITEM::SetNetCode( int aNetCode, bool aNoAssert )
}
// This method returns the Default netclass for nets which don't have their own.
NETCLASS* BOARD_CONNECTED_ITEM::GetEffectiveNetclass() const
{
// NB: we must check the net first, as when it is 0 GetNetClass() will return the
// orphaned net netclass, not the default netclass.
if( m_netinfo->GetNet() == 0 )
return GetBoard()->GetDesignSettings().GetDefault();
else
return GetNetClass();
}
/*
* Clearances exist in a hiearchy:
* 1) accumulated board & netclass constraints
* 2) last rule whose condition evaluates to true
* 4) footprint override
* 5) pad override
*
* The base class handles (1) and (2).
*/
int BOARD_CONNECTED_ITEM::GetClearance( BOARD_ITEM* aItem, wxString* aSource ) const
{
BOARD* board = GetBoard();
@ -87,64 +100,51 @@ int BOARD_CONNECTED_ITEM::GetClearance( BOARD_ITEM* aItem, wxString* aSource ) c
if( !board )
return 0;
BOARD_DESIGN_SETTINGS& bds = board->GetDesignSettings();
NETCLASS* myNetclass = nullptr;
NETCLASS* itemNetclass = nullptr;
DRC_RULE* rule = GetRule( this, aItem, CLEARANCE_CONSTRAINT );
// NB: we must check the net first, as when it is 0 GetNetClass() will return the
// orphaned net netclass, not the default netclass.
if( m_netinfo->GetNet() == 0 )
myNetclass = bds.GetDefault();
else
myNetclass = GetNetClass();
if( rule )
{
if( aSource )
*aSource = wxString::Format( _( "'%s' rule clearance" ), rule->m_Name );
return rule->m_Clearance.Min;
}
BOARD_DESIGN_SETTINGS& bds = board->GetDesignSettings();
int clearance = bds.m_MinClearance;
if( aSource )
*aSource = _( "board minimum" );
NETCLASS* netclass = GetEffectiveNetclass();
if( netclass && netclass->GetClearance() > clearance )
{
clearance = netclass->GetClearance();
if( aSource )
*aSource = wxString::Format( _( "'%s' netclass" ), netclass->GetName() );
}
if( aItem && aItem->IsConnected() )
{
if( static_cast<BOARD_CONNECTED_ITEM*>( aItem )->GetNet()->GetNet() == 0 )
itemNetclass = bds.GetDefault();
else
itemNetclass = static_cast<BOARD_CONNECTED_ITEM*>( aItem )->GetNetClass();
}
netclass = static_cast<BOARD_CONNECTED_ITEM*>( aItem )->GetEffectiveNetclass();
int clearance = bds.GetRuleClearance( this, myNetclass, aItem, itemNetclass, aSource );
if( myNetclass )
{
int myClearance = myNetclass->GetClearance();
if( myClearance > clearance )
if( netclass && netclass->GetClearance() > clearance )
{
clearance = myClearance;
clearance = netclass->GetClearance();
if( aSource )
*aSource = wxString::Format( _( "'%s' netclass" ), myNetclass->GetName() );
*aSource = wxString::Format( _( "'%s' netclass" ), netclass->GetName() );
}
}
if( itemNetclass )
if( aItem && aItem->GetLayer() == Edge_Cuts && bds.m_CopperEdgeClearance > clearance )
{
int itemClearance = myNetclass->GetClearance();
clearance = bds.m_CopperEdgeClearance;
if( itemClearance > clearance )
{
clearance = itemClearance;
if( aSource )
*aSource = wxString::Format( _( "'%s' netclass" ), itemNetclass->GetName() );
}
}
if( aItem && aItem->GetLayer() == Edge_Cuts )
{
int edgeClearance = bds.m_CopperEdgeClearance;
if( edgeClearance > clearance )
{
clearance = edgeClearance;
if( aSource )
*aSource = _( "board edge" );
}
if( aSource )
*aSource = _( "board edge" );
}
return clearance;

View File

@ -172,6 +172,15 @@ public:
*/
NETCLASS* GetNetClass() const;
/**
* Function GetEffectiveNetclass
* returns the NETCLASS for this item, or the default netclass if none is defined.
*
* Note: do NOT return a std::shared_ptr from this. It is used heavily in DRC, and the
* std::shared_ptr stuff shows up large in performance profiling.
*/
NETCLASS* GetEffectiveNetclass() const;
/**
* Function GetNetClassName
* returns a pointer to the netclass of the zone.

View File

@ -21,11 +21,6 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file board_design_settings.cpp
* BOARD_DESIGN_SETTINGS class functions.
*/
#include <fctsys.h>
#include <common.h>
#include <class_board.h>
@ -967,7 +962,7 @@ int BOARD_DESIGN_SETTINGS::GetBiggestClearanceValue()
clearance = std::max( clearance, netclass.second->GetClearance() );
for( const DRC_RULE* rule : m_DRCRules )
clearance = std::max( clearance, rule->m_Clearance );
clearance = std::max( clearance, rule->m_Clearance.Min );
return clearance;
}
@ -984,58 +979,6 @@ int BOARD_DESIGN_SETTINGS::GetSmallestClearanceValue()
}
int BOARD_DESIGN_SETTINGS::GetRuleClearance( const BOARD_ITEM* aItem, const NETCLASS* aNetclass,
const BOARD_ITEM* bItem, const NETCLASS* bNetclass,
wxString* aSource )
{
if( !m_matched.empty() )
m_matched.clear(); // yes, the difference can be seen in profiles
if( m_DRCRuleSelectors.size() == 0 )
return 0;
MatchSelectors( m_DRCRuleSelectors, aItem, aNetclass, bItem, bNetclass, &m_matched );
if( m_matched.size() == 0 )
return 0;
std::sort( m_matched.begin(), m_matched.end(),
[]( DRC_SELECTOR* a, DRC_SELECTOR* b ) -> bool
{
return a->m_Priority < b->m_Priority;
});
int clearance = 0;
for( DRC_SELECTOR* selector : m_matched )
{
// ignore hole rules; we're just interested in copper here
for( KICAD_T matchType : selector->m_MatchTypes )
{
if( BaseType( matchType ) == PCB_LOCATE_HOLE_T )
continue;
}
if( selector->m_Rule->m_Clearance > 0 )
{
clearance = std::max( clearance, selector->m_Rule->m_Clearance );
if( aSource )
*aSource = wxString::Format( _( "'%s' rule clearance" ), selector->m_Rule->m_Name );
}
else if( selector->m_Rule->m_Clearance < 0 )
{
clearance = std::min( clearance, abs( selector->m_Rule->m_Clearance ) );
if( aSource )
*aSource = wxString::Format( _( "'%s' rule clearance" ), selector->m_Rule->m_Name );
}
}
return clearance;
}
int BOARD_DESIGN_SETTINGS::GetCurrentMicroViaSize()
{
NETCLASSPTR netclass = m_NetClasses.Find( m_currentNetClassName );
@ -1122,26 +1065,11 @@ void BOARD_DESIGN_SETTINGS::SetElementVisibility( GAL_LAYER_ID aElementCategory,
void BOARD_DESIGN_SETTINGS::SetCopperLayerCount( int aNewLayerCount )
{
// if( aNewLayerCount < 2 ) aNewLayerCount = 2;
m_copperLayerCount = aNewLayerCount;
// ensure consistency with the m_EnabledLayers member
#if 0
// was:
m_enabledLayers &= ~ALL_CU_LAYERS;
m_enabledLayers |= LAYER_BACK;
if( m_copperLayerCount > 1 )
m_enabledLayers |= LAYER_FRONT;
for( LAYER_NUM ii = LAYER_N_2; ii < aNewLayerCount - 1; ++ii )
m_enabledLayers |= GetLayerSet( ii );
#else
// Update only enabled copper layers mask
m_enabledLayers &= ~LSET::AllCuMask();
m_enabledLayers |= LSET::AllCuMask( aNewLayerCount );
#endif
}

View File

@ -615,33 +615,25 @@ wxPoint D_PAD::ShapePos() const
int D_PAD::GetClearance( BOARD_ITEM* aItem, wxString* aSource ) const
{
int clearance;
// A pad can have specific clearance that overrides its NETCLASS clearance value
if( m_LocalClearance )
{
clearance = m_LocalClearance;
if( aSource )
*aSource = wxString::Format( _( "pad %s" ), GetName() );
return m_LocalClearance;
}
// A footprint can have a specific clearance value
else if( GetParent() && GetParent()->GetLocalClearance() )
if( GetParent() && GetParent()->GetLocalClearance() )
{
clearance = GetParent()->GetLocalClearance();
if( aSource )
*aSource = wxString::Format( _( "%s footprint" ), GetParent()->GetReference() );
return GetParent()->GetLocalClearance();
}
// Otherwise use the baseclass method to fetch the netclass and/or rule setting
else
{
clearance = BOARD_CONNECTED_ITEM::GetClearance( aItem, aSource );
}
return clearance;
return BOARD_CONNECTED_ITEM::GetClearance( aItem, aSource );
}

View File

@ -125,75 +125,52 @@ int TRACK::GetClearance( BOARD_ITEM* aItem, wxString* aSource ) const
}
int TRACK::GetMinWidth( wxString* aSource ) const
/*
* Width constraints exist in a hiearchy:
* 1) accumulated board & netclass constraints
* 2) last rule whose condition evaluates to true
*/
void TRACK::GetWidthConstraints( int* aMin, int* aMax, wxString* aSource ) const
{
BOARD_DESIGN_SETTINGS& bds = GetBoard()->GetDesignSettings();
NETCLASS* netclass = nullptr;
std::vector<DRC_SELECTOR*> matched;
DRC_RULE* rule = GetRule( this, nullptr, TRACK_CONSTRAINT );
// NB: we must check the net first, as when it is 0 GetNetClass() will return the
// orphaned net netclass, not the default netclass.
if( m_netinfo->GetNet() == 0 )
netclass = bds.GetDefault();
else
netclass = GetNetClass();
MatchSelectors( bds.m_DRCRuleSelectors, this, netclass, nullptr, nullptr, &matched );
int minWidth = bds.m_TrackMinWidth;
if( aSource )
*aSource = _( "board minumum" );
for( DRC_SELECTOR* selector : matched )
if( rule )
{
if( selector->m_Rule->m_TrackWidth > minWidth )
{
minWidth = selector->m_Rule->m_TrackWidth;
*aMin = rule->m_TrackConstraint.Min;
*aMax = rule->m_TrackConstraint.Max;
if( aSource )
*aSource = wxString::Format( _( "'%s' rule" ), selector->m_Rule->m_Name );
}
if( aSource )
*aSource = wxString::Format( _( "'%s' rule" ), rule->m_Name );
}
else
{
*aMin = GetBoard()->GetDesignSettings().m_TrackMinWidth;
*aMax = INT_MAX / 2;
return minWidth;
if( aSource )
*aSource = _( "board minumum" );
}
}
int VIA::GetMinAnnulus( wxString* aSource ) const
{
BOARD_DESIGN_SETTINGS& bds = GetBoard()->GetDesignSettings();
NETCLASS* netclass = nullptr;
std::vector<DRC_SELECTOR*> matched;
DRC_RULE* rule = GetRule( this, nullptr, ANNULUS_CONSTRAINT );
// NB: we must check the net first, as when it is 0 GetNetClass() will return the
// orphaned net netclass, not the default netclass.
if( m_netinfo->GetNet() == 0 )
netclass = bds.GetDefault();
else
netclass = GetNetClass();
MatchSelectors( bds.m_DRCRuleSelectors, this, netclass, nullptr, nullptr, &matched );
int minAnnulus = bds.m_ViasMinAnnulus;
if( aSource )
*aSource = _( "board minumum" );
MatchSelectors( bds.m_DRCRuleSelectors, this, netclass, nullptr, nullptr, &matched );
for( DRC_SELECTOR* selector : matched )
if( rule )
{
if( selector->m_Rule->m_AnnulusWidth > minAnnulus )
{
minAnnulus = selector->m_Rule->m_AnnulusWidth;
if( aSource )
*aSource = wxString::Format( _( "'%s' rule" ), rule->m_Name );
if( aSource )
*aSource = wxString::Format( _( "'%s' rule" ), selector->m_Rule->m_Name );
}
return rule->m_MinAnnulusWidth;
}
else
{
if( aSource )
*aSource = _( "board minumum" );
return minAnnulus;
return GetBoard()->GetDesignSettings().m_ViasMinAnnulus;
}
}
@ -634,7 +611,8 @@ void TRACK::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>
msg2.Printf( _( "(from %s)" ), source );
aList.emplace_back( msg, msg2, BLACK );
int minWidth = GetMinWidth( &source );
int minWidth, maxWidth;
GetWidthConstraints( &minWidth, &maxWidth, &source );
msg.Printf( _( "Min Width: %s" ), MessageTextFromValue( units, minWidth, true ) );
msg2.Printf( _( "(from %s)" ), source );

View File

@ -212,7 +212,7 @@ public:
*/
int GetClearance( BOARD_ITEM* aItem = nullptr, wxString* aSource = nullptr ) const override;
int GetMinWidth( wxString* aSource ) const;
void GetWidthConstraints( int* aMin, int* aMax, wxString* aSource ) const;
wxString GetSelectMenuText( EDA_UNITS aUnits ) const override;

View File

@ -463,7 +463,58 @@ int ZONE_CONTAINER::GetClearance( BOARD_ITEM* aItem, wxString* aSource ) const
if( m_isKeepout )
return 0;
int clearance = BOARD_CONNECTED_ITEM::GetClearance( aItem, aSource );
BOARD* board = GetBoard();
// No clearance if "this" is not (yet) linked to a board
if( !board )
return 0;
DRC_RULE* rule = GetRule( this, aItem, CLEARANCE_CONSTRAINT );
if( rule )
{
if( aSource )
*aSource = wxString::Format( _( "'%s' rule clearance" ), rule->m_Name );
return rule->m_Clearance.Min;
}
BOARD_DESIGN_SETTINGS& bds = board->GetDesignSettings();
int clearance = bds.m_MinClearance;
if( aSource )
*aSource = _( "board minimum" );
NETCLASS* netclass = GetEffectiveNetclass();
if( netclass && netclass->GetClearance() > clearance )
{
clearance = netclass->GetClearance();
if( aSource )
*aSource = wxString::Format( _( "'%s' netclass" ), netclass->GetName() );
}
if( aItem && aItem->IsConnected() )
{
netclass = static_cast<BOARD_CONNECTED_ITEM*>( aItem )->GetEffectiveNetclass();
if( netclass && netclass->GetClearance() > clearance )
{
clearance = netclass->GetClearance();
if( aSource )
*aSource = wxString::Format( _( "'%s' netclass" ), netclass->GetName() );
}
}
if( aItem && aItem->GetLayer() == Edge_Cuts && bds.m_CopperEdgeClearance > clearance )
{
clearance = bds.m_CopperEdgeClearance;
if( aSource )
*aSource = _( "board edge" );
}
if( m_ZoneClearance > clearance )
{

View File

@ -27,7 +27,7 @@ PANEL_SETUP_NETCLASSES_BASE::PANEL_SETUP_NETCLASSES_BASE( wxWindow* parent, wxWi
m_netclassGrid = new WX_GRID( m_netclassesPane, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBORDER_DEFAULT|wxHSCROLL|wxTAB_TRAVERSAL|wxVSCROLL );
// Grid
m_netclassGrid->CreateGrid( 1, 9 );
m_netclassGrid->CreateGrid( 1, 10 );
m_netclassGrid->EnableEditing( true );
m_netclassGrid->EnableGridLines( true );
m_netclassGrid->EnableDragGridSize( false );
@ -41,8 +41,9 @@ PANEL_SETUP_NETCLASSES_BASE::PANEL_SETUP_NETCLASSES_BASE( wxWindow* parent, wxWi
m_netclassGrid->SetColSize( 4, 96 );
m_netclassGrid->SetColSize( 5, 96 );
m_netclassGrid->SetColSize( 6, 96 );
m_netclassGrid->SetColSize( 7, 96 );
m_netclassGrid->SetColSize( 8, 96 );
m_netclassGrid->SetColSize( 7, 60 );
m_netclassGrid->SetColSize( 8, 60 );
m_netclassGrid->SetColSize( 9, 60 );
m_netclassGrid->EnableDragColMove( false );
m_netclassGrid->EnableDragColSize( true );
m_netclassGrid->SetColLabelSize( 24 );
@ -53,8 +54,9 @@ PANEL_SETUP_NETCLASSES_BASE::PANEL_SETUP_NETCLASSES_BASE( wxWindow* parent, wxWi
m_netclassGrid->SetColLabelValue( 4, _("Via Drill") );
m_netclassGrid->SetColLabelValue( 5, _("uVia Size") );
m_netclassGrid->SetColLabelValue( 6, _("uVia Drill") );
m_netclassGrid->SetColLabelValue( 7, _("dPair Width") );
m_netclassGrid->SetColLabelValue( 8, _("dPair Gap") );
m_netclassGrid->SetColLabelValue( 7, _("DP Width") );
m_netclassGrid->SetColLabelValue( 8, _("DP Gap") );
m_netclassGrid->SetColLabelValue( 9, _("DP Via Gap") );
m_netclassGrid->SetColLabelAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
// Rows

View File

@ -155,10 +155,10 @@
<property name="close_button">1</property>
<property name="col_label_horiz_alignment">wxALIGN_CENTER</property>
<property name="col_label_size">24</property>
<property name="col_label_values">&quot;Name&quot; &quot;Clearance&quot; &quot;Track Width&quot; &quot;Via Size&quot; &quot;Via Drill&quot; &quot;uVia Size&quot; &quot;uVia Drill&quot; &quot;dPair Width&quot; &quot;dPair Gap&quot;</property>
<property name="col_label_values">&quot;Name&quot; &quot;Clearance&quot; &quot;Track Width&quot; &quot;Via Size&quot; &quot;Via Drill&quot; &quot;uVia Size&quot; &quot;uVia Drill&quot; &quot;DP Width&quot; &quot;DP Gap&quot; &quot;DP Via Gap&quot;</property>
<property name="col_label_vert_alignment">wxALIGN_CENTER</property>
<property name="cols">9</property>
<property name="column_sizes">130,96,96,96,96,96,96,96,96</property>
<property name="cols">10</property>
<property name="column_sizes">130,96,96,96,96,96,96,60,60,60</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>

View File

@ -383,6 +383,8 @@ void DRC::LoadRules()
}
}
std::reverse( std::begin( m_ruleSelectors ), std::end( m_ruleSelectors ) );
BOARD_DESIGN_SETTINGS& bds = m_pcb->GetDesignSettings();
bds.m_DRCRuleSelectors = m_ruleSelectors;
bds.m_DRCRules = m_rules;

View File

@ -65,6 +65,7 @@ enum PCB_DRC_CODE {
DRCE_HOLE_NEAR_TRACK, ///< hole too close to track
DRCE_DRILLED_HOLES_TOO_CLOSE, ///< overlapping drilled holes break drill bits
DRCE_TOO_SMALL_TRACK_WIDTH, ///< Too small track width
DRCE_TOO_LARGE_TRACK_WIDTH, ///< Too small track width
DRCE_TOO_SMALL_VIA, ///< Too small via size
DRCE_TOO_SMALL_VIA_ANNULUS, ///< Via size and drill leave annulus too small
DRCE_TOO_SMALL_VIA_DRILL, ///< Too small via drill

View File

@ -315,17 +315,32 @@ void DRC::doTrackDrc( BOARD_COMMIT& aCommit, TRACK* aRefSeg, TRACKS::iterator aS
}
else // This is a track segment
{
int minWidth = aRefSeg->GetMinWidth( &m_clearanceSource );
int minWidth, maxWidth;
aRefSeg->GetWidthConstraints( &minWidth, &maxWidth, &m_clearanceSource );
int errorCode = 0;
int constraintWidth;
if( refSegWidth < minWidth )
{
errorCode = DRCE_TOO_SMALL_TRACK_WIDTH;
constraintWidth = minWidth;
}
else if( refSegWidth > maxWidth )
{
errorCode = DRCE_TOO_LARGE_TRACK_WIDTH;
constraintWidth = maxWidth;
}
if( errorCode )
{
wxPoint refsegMiddle = ( aRefSeg->GetStart() + aRefSeg->GetEnd() ) / 2;
DRC_ITEM* drcItem = new DRC_ITEM( DRCE_TOO_SMALL_TRACK_WIDTH );
DRC_ITEM* drcItem = new DRC_ITEM( errorCode );
m_msg.Printf( drcItem->GetErrorText() + _( " (%s %s; actual %s)" ),
m_clearanceSource,
MessageTextFromValue( userUnits(), minWidth, true ),
MessageTextFromValue( userUnits(), constraintWidth, true ),
MessageTextFromValue( userUnits(), refSegWidth, true ) );
drcItem->SetErrorMessage( m_msg );

View File

@ -91,21 +91,14 @@ bool DRC_DRILLED_HOLE_TESTER::checkPad( D_PAD* aPad )
if( !bds.Ignore( DRCE_TOO_SMALL_PAD_DRILL ) )
{
NETCLASS* netclass = aPad->GetNet()->GetNet() == 0 ? bds.GetDefault()
: aPad->GetNetClass();
int minHole = bds.m_MinThroughDrill;
wxString minHoleSource = _( "board minimum" );
DRC_RULE* rule = GetRule( aPad, nullptr, HOLE_CONSTRAINT );
std::vector<DRC_SELECTOR*> matched;
MatchSelectors( bds.m_DRCRuleSelectors, aPad, netclass, nullptr, nullptr, &matched );
for( DRC_SELECTOR* selector : matched )
if( rule )
{
if( selector->m_Rule->m_Hole > minHole )
{
minHole = selector->m_Rule->m_Hole;
minHoleSource = wxString::Format( _( "'%s' rule" ), selector->m_Rule->m_Name );
}
minHole = rule->m_MinHole;
minHoleSource = wxString::Format( _( "'%s' rule" ), rule->m_Name );
}
if( holeSize < minHole )
@ -141,21 +134,14 @@ bool DRC_DRILLED_HOLE_TESTER::checkVia( VIA* via )
if( !bds.Ignore( DRCE_TOO_SMALL_VIA_DRILL ) )
{
NETCLASS* netclass = via->GetNet()->GetNet() == 0 ? bds.GetDefault()
: via->GetNetClass();
int minHole = bds.m_MinThroughDrill;
wxString minHoleSource = _( "board minimum" );
DRC_RULE* rule = GetRule( via, nullptr, HOLE_CONSTRAINT );
std::vector<DRC_SELECTOR*> matched;
MatchSelectors( bds.m_DRCRuleSelectors, via, netclass, nullptr, nullptr, &matched );
for( DRC_SELECTOR* selector : matched )
if( rule )
{
if( selector->m_Rule->m_Hole > minHole )
{
minHole = selector->m_Rule->m_Hole;
minHoleSource = wxString::Format( _( "'%s' rule" ), selector->m_Rule->m_Name );
}
minHole = rule->m_MinHole;
minHoleSource = wxString::Format( _( "'%s' rule" ), rule->m_Name );
}
if( via->GetDrillValue() < minHole )
@ -191,21 +177,14 @@ bool DRC_DRILLED_HOLE_TESTER::checkMicroVia( VIA* via )
if( !bds.Ignore( DRCE_TOO_SMALL_MICROVIA_DRILL ) )
{
NETCLASS* netclass = via->GetNet()->GetNet() == 0 ? bds.GetDefault()
: via->GetNetClass();
int minHole = bds.m_MicroViasMinDrill;
wxString minHoleSource = _( "board minimum" );
DRC_RULE* rule = GetRule( via, nullptr, HOLE_CONSTRAINT );
std::vector<DRC_SELECTOR*> matched;
MatchSelectors( bds.m_DRCRuleSelectors, via, netclass, nullptr, nullptr, &matched );
for( DRC_SELECTOR* selector : matched )
if( rule )
{
if( selector->m_Rule->m_Hole > minHole )
{
minHole = selector->m_Rule->m_Hole;
minHoleSource = wxString::Format( _( "'%s' rule" ), selector->m_Rule->m_Name );
}
minHole = rule->m_MinHole;
minHoleSource = wxString::Format( _( "'%s' rule" ), rule->m_Name );
}
if( via->GetDrillValue() < minHole )

View File

@ -84,6 +84,7 @@ wxString DRC_ITEM::GetErrorText( int aCode, bool aTranslate ) const
case DRCE_HOLE_NEAR_PAD: msg = _HKI( "Hole too close to pad" ); break;
case DRCE_HOLE_NEAR_TRACK: msg = _HKI( "Hole too close to track" ); break;
case DRCE_TOO_SMALL_TRACK_WIDTH: msg = _HKI( "Track width too small" ); break;
case DRCE_TOO_LARGE_TRACK_WIDTH: msg = _HKI( "Track width too large" ); break;
case DRCE_TOO_SMALL_VIA: msg = _HKI( "Via size too small" ); break;
case DRCE_TOO_SMALL_VIA_ANNULUS: msg = _HKI( "Via annulus too small" ); break;
case DRCE_TOO_SMALL_MICROVIA: msg = _HKI( "Micro via size too small" ); break;

View File

@ -29,31 +29,12 @@
#include <class_board_item.h>
/*
* Match tokens:
* match_netclass
* match_type
* match_layer
* match_all
* match_area
* Rule tokens:
* disallow
* constraint
* condition
*
* (selector (match_area "$board") (rule "OSHParkClass3") (priority 100))
*
* (selector (match_netclass "HV") (rule "HV_internal"))
* (selector (match_netclass "HV") (match_layer "F_Cu") (rule "HV_external"))
* (selector (match_netclass "HV") (match_layer "B_Cu") (rule "HV_external"))
*
* (selector (match_netclass "HV") (match_netclass "HV") (rule "HV2HV"))
* (selector (match_netclass "HV") (match_netclass "HV") (match_layer "F_Cu") (rule "HV2HV_external"))
* (selector (match_netclass "HV") (match_netclass "HV") (match_layer "B_Cu") (rule "HV2HV_external"))
*
* TODO: pads for connector pins or wire pads have even larger clearances. How to encode?
* User attributes on parent footprint?
*
* (selector (match_netclass "HV") (match_type "pad") (match_netclass "HV") (match_type "pad") (rule "pad2PadHV"))
*
* (selector (match_netclass "signal") (match_area "BGA") (rule "neckdown"))
*
* Type tokens:
* Disallow types:
* track
* via
* micro_via
@ -62,40 +43,46 @@
* zone
* text
* graphic
* board_edge
* hole
* npth
* pth
*
* Rule tokens:
* allow
* Constraint types:
* clearance
* annulus_width
* track_width
* hole
*
* Rule modifiers:
* relaxed
*
* (rule "HV" (clearance 200) (priority 200))
* (rule "HV_external" (clearance 400) (priority 200))
* (rule "HV2HV" (clearance 200) (priority 200))
* (rule "HV2HV_external" (clearance 500) (priority 200))
* (rule "pad2padHV" (clearance 500) (priority 200))
* (rule "HV" (constraint clearance (min 200)))
* (rule "HV_external" (constraint clearance (min 400)))
* (rule "HV2HV" (constraint clearance (min 200)))
* (rule "HV2HV_external" (constraint clearance (min 500)))
* (rule "pad2padHV" (constraint clearance (min 500)))
*
* (rule "signal" (clearance 20)) // implied priority of 1
* (rule "neckdown" (clearance relaxed 15) (priority 2))
* (rule "signal" (constraint clearance (min 20)))
* (rule "neckdown" (constraint clearance (min 15)))
*
* (rule "allowMicrovias" (allow microvia))
* (rule "disallowMicrovias" (disallow micro_via))
*/
void MatchSelectors( const std::vector<DRC_SELECTOR*>& aSelectors,
const BOARD_ITEM* aItem, const NETCLASS* aNetclass,
const BOARD_ITEM* bItem, const NETCLASS* bNetclass,
std::vector<DRC_SELECTOR*>* aSelected )
DRC_RULE* GetRule( const BOARD_ITEM* aItem, const BOARD_ITEM* bItem, int aConstraint )
{
for( DRC_SELECTOR* candidate : aSelectors )
// JEY TODO: the bulk of this will be replaced by Tom's expression evaluator
BOARD* board = aItem->GetBoard();
if( !board )
return nullptr;
NETCLASS* aNetclass = nullptr;
NETCLASS* bNetclass = nullptr;
if( aItem->IsConnected() )
aNetclass = static_cast<const BOARD_CONNECTED_ITEM*>( aItem )->GetEffectiveNetclass();
if( bItem && bItem->IsConnected() )
bNetclass = static_cast<const BOARD_CONNECTED_ITEM*>( bItem )->GetEffectiveNetclass();
for( DRC_SELECTOR* candidate : board->GetDesignSettings().m_DRCRuleSelectors )
{
if( candidate->m_MatchNetclasses.size() == 2 )
{
@ -145,11 +132,8 @@ void MatchSelectors( const std::vector<DRC_SELECTOR*>& aSelectors,
{
PCB_LAYER_ID matchLayer = candidate->m_MatchLayers[0];
if( !aItem->GetLayerSet().test( matchLayer )
|| ( bItem && !bItem->GetLayerSet().test( matchLayer ) ) )
{
if( !aItem->GetLayerSet().test( matchLayer ) )
continue;
}
}
if( candidate->m_MatchAreas.size() )
@ -165,8 +149,12 @@ void MatchSelectors( const std::vector<DRC_SELECTOR*>& aSelectors,
}
// All tests done; if we're still here then it matches
aSelected->push_back( candidate );
if( ( candidate->m_Rule->m_ConstraintFlags & aConstraint ) > 0 )
return candidate->m_Rule;
}
return nullptr;
}

View File

@ -32,26 +32,55 @@
class BOARD_ITEM;
#define CLEARANCE_CONSTRAINT (1 << 0)
#define ANNULUS_CONSTRAINT (1 << 1)
#define TRACK_CONSTRAINT (1 << 2)
#define HOLE_CONSTRAINT (1 << 3)
#define DISALLOW_VIAS (1 << 0)
#define DISALLOW_MICRO_VIAS (1 << 1)
#define DISALLOW_BB_VIAS (1 << 2)
#define DISALLOW_TRACKS (1 << 3)
#define DISALLOW_PADS (1 << 4)
#define DISALLOW_ZONES (1 << 5)
#define DISALLOW_TEXTS (1 << 6)
#define DISALLOW_GRAPHICS (1 << 7)
#define DISALLOW_HOLES (1 << 8)
#define DISALLOW_FOOTPRINTS (1 << 9)
class DRC_RULE
{
public:
DRC_RULE() :
m_Clearance( 0 ),
m_AnnulusWidth( 0 ),
m_TrackWidth( 0 ),
m_Hole( 0 )
m_ConstraintFlags( 0 ),
m_DisallowFlags( 0 ),
m_Clearance( { 0, 0, INT_MAX / 2 } ),
m_MinAnnulusWidth( 0 ),
m_TrackConstraint( { 0, 0, INT_MAX / 2 } ),
m_MinHole( 0 )
{ }
struct MINOPTMAX
{
int Min;
int Opt;
int Max;
};
public:
wxString m_Name;
wxString m_Name;
int m_ConstraintFlags;
int m_DisallowFlags;
// A 0 value means the property is not modified by this rule.
// A positive value is a minimum. A negative value is a relaxed constraint: the minimum
// is reduced to the absolute value of the constraint.
int m_Clearance;
int m_AnnulusWidth;
int m_TrackWidth;
int m_Hole;
// A positive value is a minimum.
MINOPTMAX m_Clearance;
int m_MinAnnulusWidth;
MINOPTMAX m_TrackConstraint;
int m_MinHole;
wxString m_Condition;
};
@ -74,10 +103,7 @@ public:
};
void MatchSelectors( const std::vector<DRC_SELECTOR*>& aSelectors,
const BOARD_ITEM* aItem, const NETCLASS* aNetclass,
const BOARD_ITEM* bItem, const NETCLASS* bNetclass,
std::vector<DRC_SELECTOR*>* aSelected );
DRC_RULE* GetRule( const BOARD_ITEM* aItem, const BOARD_ITEM* bItem, int aConstraint );

View File

@ -183,14 +183,8 @@ DRC_SELECTOR* DRC_RULES_PARSER::parseDRC_SELECTOR( wxString* aRuleName )
NeedRIGHT();
break;
case T_priority:
NeedNUMBER( "priority" );
selector->m_Priority = (int)strtol( CurText(), NULL, 10 );
NeedRIGHT();
break;
default:
Expecting( "match_netclass, match_type, match_layer, match_area, rule, or priority" );
Expecting( "match_netclass, match_type, match_layer, match_area, or rule" );
}
}
@ -211,61 +205,40 @@ DRC_RULE* DRC_RULES_PARSER::parseDRC_RULE()
if( token != T_LEFT )
Expecting( T_LEFT );
int sign = 1;
token = NextTok();
switch( token )
{
case T_allow:
// TODO
break;
case T_clearance:
if( NextTok() == T_relaxed )
case T_disallow:
switch( NextTok() )
{
sign = -1;
NextTok();
case T_track: rule->m_DisallowFlags |= DISALLOW_TRACKS; break;
case T_via: rule->m_DisallowFlags |= DISALLOW_VIAS; break;
case T_micro_via: rule->m_DisallowFlags |= DISALLOW_MICRO_VIAS; break;
case T_blind_via: rule->m_DisallowFlags |= DISALLOW_BB_VIAS; break;
case T_pad: rule->m_DisallowFlags |= DISALLOW_PADS; break;
case T_zone: rule->m_DisallowFlags |= DISALLOW_ZONES; break;
case T_text: rule->m_DisallowFlags |= DISALLOW_TEXTS; break;
case T_graphic: rule->m_DisallowFlags |= DISALLOW_GRAPHICS; break;
case T_hole: rule->m_DisallowFlags |= DISALLOW_HOLES; break;
default: Expecting( "track, via, micro_via, blind_via, pad, zone, text, "
"graphic, or hole" );
}
rule->m_Clearance = parseValue( T_clearance ) * sign;
NeedRIGHT();
break;
case T_track_width:
if( NextTok() == T_relaxed )
{
sign = -1;
NextTok();
}
rule->m_TrackWidth = parseValue( T_track_width ) * sign;
NeedRIGHT();
case T_constraint:
parseConstraint( rule );
break;
case T_annulus_width:
if( NextTok() == T_relaxed )
{
sign = -1;
NextTok();
}
rule->m_AnnulusWidth = parseValue( T_annulus_width ) * sign;
NeedRIGHT();
break;
case T_hole:
if( NextTok() == T_relaxed )
{
sign = -1;
NextTok();
}
rule->m_Hole = parseValue( T_hole ) * sign;
case T_condition:
NeedSYMBOL();
rule->m_Condition = FromUTF8();
NeedRIGHT();
break;
default:
Expecting( "allow, clearance, track_width, annulus_width, or hole" );
Expecting( "disallow, constraint or condition" );
}
}
@ -273,6 +246,82 @@ DRC_RULE* DRC_RULES_PARSER::parseDRC_RULE()
}
void DRC_RULES_PARSER::parseConstraint( DRC_RULE* aRule )
{
T token;
int constraintType;
int value;
switch( NextTok() )
{
case T_clearance: constraintType = CLEARANCE_CONSTRAINT; break;
case T_track_width: constraintType = TRACK_CONSTRAINT; break;
case T_annulus_width: constraintType = ANNULUS_CONSTRAINT; break;
case T_hole: constraintType = HOLE_CONSTRAINT; break;
default: Expecting( "clearance, track_width, annulus_width, or hole" ); return;
}
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( token != T_LEFT )
Expecting( T_LEFT );
token = NextTok();
switch( token )
{
case T_min:
NextTok();
value = parseValue( token );
switch( constraintType )
{
case CLEARANCE_CONSTRAINT: aRule->m_Clearance.Min = value; break;
case TRACK_CONSTRAINT: aRule->m_TrackConstraint.Min = value; break;
case ANNULUS_CONSTRAINT: aRule->m_MinAnnulusWidth = value; break;
case HOLE_CONSTRAINT: aRule->m_MinHole = value; break;
}
NeedRIGHT();
break;
case T_max:
NextTok();
value = parseValue( token );
switch( constraintType )
{
case CLEARANCE_CONSTRAINT: aRule->m_Clearance.Max = value; break;
case TRACK_CONSTRAINT: aRule->m_TrackConstraint.Max = value; break;
default: Expecting( "min" );
}
NeedRIGHT();
break;
case T_opt:
NextTok();
value = parseValue( token );
switch( constraintType )
{
case CLEARANCE_CONSTRAINT: aRule->m_Clearance.Opt = value; break;
case TRACK_CONSTRAINT: aRule->m_TrackConstraint.Opt = value; break;
default: Expecting( "min" );
}
NeedRIGHT();
break;
default:
Expecting( "allow or constraint" );
}
}
aRule->m_ConstraintFlags |= constraintType;
}
int DRC_RULES_PARSER::parseValue( DRCRULE_T::T aToken )
{
char* tmp;
@ -283,20 +332,14 @@ int DRC_RULES_PARSER::parseValue( DRCRULE_T::T aToken )
if( errno )
{
wxString error;
error.Printf( _( "Invalid floating point number in\nfile: \"%s\"\nline: %d\noffset: %d" ),
GetChars( CurSource() ), CurLineNumber(), CurOffset() );
THROW_IO_ERROR( error );
THROW_PARSE_ERROR( _( "Invalid floating point number" ), CurSource(), CurLine(),
CurLineNumber(), CurOffset() );
}
if( CurText() == tmp )
{
wxString error;
error.Printf( _( "Missing floating point number in\nfile: \"%s\"\nline: %d\noffset: %d" ),
GetChars( CurSource() ), CurLineNumber(), CurOffset() );
THROW_IO_ERROR( error );
THROW_PARSE_ERROR( _( "Missing floating point number" ), CurSource(), CurLine(),
CurLineNumber(), CurOffset() );
}
return KiROUND( fval * IU_PER_MM );

View File

@ -49,6 +49,7 @@ private:
DRC_RULE* parseDRC_RULE();
void parseConstraint( DRC_RULE* aRule );
int parseValue( DRCRULE_T::T aToken );
private: