drc_proto: initial version of legacy rule import (without overrides yet)

This commit is contained in:
Tomasz Wlostowski 2020-08-27 00:07:31 +02:00
parent 05b88acf16
commit 8a5297180e
2 changed files with 323 additions and 15 deletions

View File

@ -123,19 +123,300 @@ bool test::DRC_ENGINE::LoadRules( wxFileName aPath )
}
test::DRC_TEST_PROVIDER *drcCreateClearanceTestProvider( test::DRC_ENGINE *engine );
void test::DRC_ENGINE::inferImplicitRules()
test::DRC_RULE* test::DRC_ENGINE::createInferredRule( const wxString& name, std::set<BOARD_ITEM*> items, int priority )
{
DRC_RULE *rule = new DRC_RULE;
rule->SetName( name );
if (! items.empty() )
rule->FillSpecificItemSet( items );
rule->SetPriority( priority );
addRule( rule );
return rule;
}
#if 0
int BOARD_CONNECTED_ITEM::GetClearance( PCB_LAYER_ID aLayer, BOARD_ITEM* aItem,
wxString* aSource ) const
{
BOARD* board = GetBoard();
int clearance = 0;
wxString source;
wxString* localSource = aSource ? &source : nullptr;
BOARD_CONNECTED_ITEM* second = dynamic_cast<BOARD_CONNECTED_ITEM*>( aItem );
// No clearance if "this" is not (yet) linked to a board therefore no available netclass
if( !board )
return clearance;
// LEVEL 1: local overrides (pad, footprint, etc.)
//
if( GetLocalClearanceOverrides() > clearance )
clearance = GetLocalClearanceOverrides( localSource );
if( second && second->GetLocalClearanceOverrides() > clearance )
clearance = second->GetLocalClearanceOverrides( localSource );
if( clearance )
{
if( aSource )
*aSource = *localSource;
return clearance;
}
// LEVEL 2: Rules
//
if( GetRuleClearance( aItem, aLayer, &clearance, aSource ) )
return clearance;
// LEVEL 3: Accumulated local settings, netclass settings, & board design settings
//
BOARD_DESIGN_SETTINGS& bds = board->GetDesignSettings();
NETCLASS* netclass = GetEffectiveNetclass();
NETCLASS* secondNetclass = second ? second->GetEffectiveNetclass() : nullptr;
if( bds.m_MinClearance > clearance )
{
if( aSource )
*aSource = _( "board minimum" );
clearance = bds.m_MinClearance;
}
if( netclass && netclass->GetClearance() > clearance )
clearance = netclass->GetClearance( aSource );
if( secondNetclass && secondNetclass->GetClearance() > clearance )
clearance = secondNetclass->GetClearance( aSource );
if( aItem && aItem->GetLayer() == Edge_Cuts && bds.m_CopperEdgeClearance > clearance )
{
if( aSource )
*aSource = _( "board edge" );
clearance = bds.m_CopperEdgeClearance;
}
if( GetLocalClearance() > clearance )
clearance = GetLocalClearance( aSource );
if( second && second->GetLocalClearance() > clearance )
clearance = second->GetLocalClearance( aSource );
return clearance;
}
#endif
void test::DRC_ENGINE::inferLegacyRules()
{
int priorityRangeMin = INT_MIN + 10000;
int priorityRangeMax = INT_MAX - 10000;
ReportAux( wxString::Format( "Inferring implicit rules (per-item/class overrides, etc...)" ) );
// 1) global defaults
test::DRC_RULE* rule = createInferredRule( "inferred-defaults", {}, priorityRangeMin );
BOARD_DESIGN_SETTINGS& bds = m_board->GetDesignSettings();
DRC_CONSTRAINT clearanceConstraint( test::DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_CLEARANCE );
clearanceConstraint.Value().SetMin( bds.m_MinClearance );
rule->AddConstraint( clearanceConstraint );
DRC_CONSTRAINT widthConstraint( test::DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_TRACK_WIDTH );
widthConstraint.Value().SetMin( bds.m_TrackMinWidth );
rule->AddConstraint( widthConstraint );
DRC_CONSTRAINT drillConstraint( test::DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_HOLE_SIZE );
drillConstraint.Value().SetMin( bds.m_MinThroughDrill );
rule->AddConstraint( drillConstraint );
DRC_CONSTRAINT annulusConstraint( test::DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_ANNULUS_WIDTH );
annulusConstraint.Value().SetMin( bds.m_ViasMinAnnulus );
rule->AddConstraint( annulusConstraint );
DRC_CONSTRAINT diameterConstraint( test::DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_VIA_DIAMETER );
diameterConstraint.Value().SetMin( bds.m_ViasMinSize );
rule->AddConstraint( diameterConstraint );
DRC_CONSTRAINT edgeClearanceConstraint( test::DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_EDGE_CLEARANCE );
edgeClearanceConstraint.Value().SetMin( bds.m_CopperEdgeClearance );
rule->AddConstraint( edgeClearanceConstraint );
DRC_CONSTRAINT holeClearanceConstraint( test::DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_HOLE_CLEARANCE );
holeClearanceConstraint.Value().SetMin( bds.m_HoleToHoleMin );
rule->AddConstraint( holeClearanceConstraint );
// 2) micro-via specific defaults (new DRC doesn't treat microvias in any special way)
priorityRangeMin++;
auto isMicroViaCondition = new DRC_RULE_CONDITION ( "A.type == 'Via' && A.isMicroVia()" );
test::DRC_RULE* uViaRule = createInferredRule( "inferred-microvia-defaults", {}, priorityRangeMin );
uViaRule->SetCondition( isMicroViaCondition );
DRC_CONSTRAINT uViaDrillConstraint( test::DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_HOLE_SIZE );
uViaDrillConstraint.Value().SetMin( bds.m_MicroViasMinDrill );
uViaRule->AddConstraint( uViaDrillConstraint );
DRC_CONSTRAINT uViaDiameterConstraint( test::DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_VIA_DIAMETER );
uViaDiameterConstraint.Value().SetMin( bds.m_MicroViasMinSize );
uViaRule->AddConstraint( uViaDiameterConstraint );
auto isBlindBuriedViaCondition = new DRC_RULE_CONDITION ( "A.type == 'Via' && A.isBlindBuriedVia()" );
test::DRC_RULE* blindBuriedViaRule = createInferredRule( "inferred-blind-buried-via-defaults", {}, priorityRangeMin );
DRC_CONSTRAINT disallowConstraint( test::DRC_CONSTRAINT_TYPE_T::DRC_CONSTRAINT_TYPE_DISALLOW );
blindBuriedViaRule->SetCondition ( isBlindBuriedViaCondition );
if( !bds.m_MicroViasAllowed )
{
uViaRule->AddConstraint( disallowConstraint );
}
if( !bds.m_BlindBuriedViaAllowed )
{
blindBuriedViaRule->AddConstraint( disallowConstraint );
}
// 3) per-netclass rules
struct NETCLASS_ENTRY
{
wxString name;
int clearance;
int width;
};
std::vector<NETCLASS_ENTRY> netclassesByClearance, netclassesByWidth;
for( auto netclass : bds.GetNetClasses() )
{
auto className = netclass.second->GetName();
NETCLASS_ENTRY ent;
ent.name = className;
ent.clearance = netclass.second->GetClearance();
ent.width = netclass.second->GetTrackWidth();
netclassesByClearance.push_back( ent );
netclassesByWidth.push_back( ent );
}
// create clearance rules
std::sort( netclassesByClearance.begin(), netclassesByClearance.end(), [] ( const NETCLASS_ENTRY& a, const NETCLASS_ENTRY& b ) -> bool
{
return a.clearance < b.clearance;
} );
std::sort( netclassesByWidth.begin(), netclassesByWidth.end(), [] ( const NETCLASS_ENTRY& a, const NETCLASS_ENTRY& b ) -> bool
{
return a.width > b.width;
} );
for( int i = 0; i < netclassesByClearance.size(); i++ )
{
wxString className = netclassesByClearance[i].name;
const auto expr = wxString::Format( "A.NetClass == '%s' || B.NetClass == '%s'", className, className );
auto inNetclassCondition = new DRC_RULE_CONDITION ( expr );
test::DRC_RULE* netclassRule = createInferredRule( wxString::Format( "inferred-netclass-clearance-%s", className ),
{}, priorityRangeMin + i );
netclassRule->SetCondition( inNetclassCondition );
DRC_CONSTRAINT ncClearanceConstraint ( DRC_CONSTRAINT_TYPE_CLEARANCE );
ncClearanceConstraint.Value().SetMin( netclassesByClearance[i].clearance );
netclassRule->AddConstraint( ncClearanceConstraint );
className = netclassesByWidth[i].name;
netclassRule = createInferredRule( wxString::Format( "inferred-netclass-width-%s", className ),
{}, priorityRangeMin + i );
netclassRule->SetCondition( inNetclassCondition );
DRC_CONSTRAINT ncWidthConstraint ( DRC_CONSTRAINT_TYPE_TRACK_WIDTH );
ncWidthConstraint.Value().SetMin( netclassesByWidth[i].width );
netclassRule->AddConstraint( ncWidthConstraint );
// TODO: should we import diff pair gaps/widths here?
}
//clearanceConstraint.SetMin( )
//rule->AddConstraint( )
}
static wxString formatConstraint( const test::DRC_CONSTRAINT& constraint )
{
struct Formatter
{
test::DRC_CONSTRAINT_TYPE_T type;
wxString name;
std::function<wxString(const test::DRC_CONSTRAINT&)> formatter;
};
auto formatMinMax = []( const test::DRC_CONSTRAINT& c ) -> wxString {
wxString str;
const auto value = c.GetValue();
if ( value.HasMin() )
str += wxString::Format(" min: %d", value.Min() );
if ( value.HasOpt() )
str += wxString::Format(" opt: %d", value.Opt() );
if ( value.HasMax() )
str += wxString::Format(" max: %d", value.Max() );
return str;
};
std::vector<Formatter> formats = {
{ test::DRC_CONSTRAINT_TYPE_UNKNOWN, "unknown", nullptr },
{ test::DRC_CONSTRAINT_TYPE_CLEARANCE, "clearance", formatMinMax },
{ test::DRC_CONSTRAINT_TYPE_HOLE_CLEARANCE, "hole_clearance", formatMinMax },
{ test::DRC_CONSTRAINT_TYPE_EDGE_CLEARANCE, "edge_clearance", formatMinMax },
{ test::DRC_CONSTRAINT_TYPE_HOLE_SIZE, "hole_size", formatMinMax },
{ test::DRC_CONSTRAINT_TYPE_COURTYARD_CLEARANCE, "courtyard_clearance", formatMinMax },
{ test::DRC_CONSTRAINT_TYPE_SILK_TO_PAD, "silk_to_pad", formatMinMax },
{ test::DRC_CONSTRAINT_TYPE_SILK_TO_SILK, "silk_to_silk", formatMinMax },
{ test::DRC_CONSTRAINT_TYPE_TRACK_WIDTH, "track_width", formatMinMax },
{ test::DRC_CONSTRAINT_TYPE_ANNULUS_WIDTH, "annulus_with", formatMinMax },
{ test::DRC_CONSTRAINT_TYPE_DISALLOW, "disallow", nullptr }, // fixme
{ test::DRC_CONSTRAINT_TYPE_VIA_DIAMETER, "via_diameter", formatMinMax }
};
for( auto& fmt : formats)
{
if( fmt.type == constraint.GetType() )
{
wxString rv = fmt.name + " ";
if( fmt.formatter )
rv += fmt.formatter( constraint );
return rv;
}
}
return "?";
}
bool test::DRC_ENGINE::CompileRules()
{
ReportAux( wxString::Format( "Compiling Rules (%d rules, %d conditions): ", m_rules.size(), m_ruleConditions.size() ) );
ReportAux( wxString::Format( "Compiling Rules (%d rules, %d conditions): ", (int)m_rules.size(), (int)m_ruleConditions.size() ) );
for( auto provider : m_testProviders )
{
@ -152,36 +433,56 @@ bool test::DRC_ENGINE::CompileRules()
for( auto rule : m_rules )
{
test::DRC_RULE_CONDITION* condition = nullptr;
bool compileOk = false;
std::vector<test::DRC_CONSTRAINT> matchingConstraints;
drc_dbg(7, "Scan provider %s, rule %s", provider->GetName(), rule->GetName() );
if( ! rule->IsEnabled() )
continue;
if( rule->IsConditional() )
{
condition = rule->Condition();
compileOk = condition->Compile( nullptr, 0, 0 ); // fixme
}
for( auto& constraint : rule->Constraints() )
{
drc_dbg(7, "scan constraint id %d\n", constraint.GetType() );
if( constraint.GetType() != id )
continue;
ReportAux( wxString::Format( " |- Rule: '%s' ", rule->GetName() ) );
auto rcons = new CONSTRAINT_WITH_CONDITIONS;
if( rule->IsConditional() )
if( condition )
{
test::DRC_RULE_CONDITION* condition = rule->Condition();
rcons->conditions.push_back( condition );
bool compileOk = condition->Compile( nullptr, 0, 0 ); // fixme
ReportAux( wxString::Format( " |- condition: '%s' compile: %s", condition->GetExpression(), compileOk ? "OK" : "ERROR") );
}
matchingConstraints.push_back( constraint );
rcons->constraint = constraint;
rcons->parentRule = rule;
m_constraintMap[ id ]->sortedConstraints.push_back( rcons );
}
if( !matchingConstraints.empty() )
{
ReportAux( wxString::Format( " |- Rule: '%s' ", rule->GetName() ) );
if( condition )
ReportAux( wxString::Format( " |- condition: '%s' compile: %s", condition->GetExpression(), compileOk ? "OK" : "ERROR") );
for (const auto& constraint : matchingConstraints )
{
ReportAux( wxString::Format( " |- constraint: %s", formatConstraint( constraint ) ) );
}
}
}
}
}
@ -202,7 +503,7 @@ void test::DRC_ENGINE::RunTests( )
}
inferImplicitRules();
inferLegacyRules();
CompileRules();
for( auto provider : m_testProviders )
@ -319,7 +620,9 @@ void test::DRC_ENGINE::ReportStage ( const wxString& aStageName, int index, int
if( !m_progressReporter )
return;
m_progressReporter->SetNumPhases( total );
m_progressReporter->BeginPhase( index ); // fixme: coalesce all stages/test providers
m_progressReporter->Report( aStageName );
}

View File

@ -240,6 +240,10 @@ public:
private:
void addRule( test::DRC_RULE* rule )
{
m_rules.push_back(rule);
}
void freeCompiledRules();
@ -259,8 +263,9 @@ private:
typedef std::unordered_map<test::DRC_CONSTRAINT_TYPE_T, CONSTRAINT_SET*> CONSTRAINT_MAP;
void inferImplicitRules();
void inferLegacyRules();
void loadTestProviders();
test::DRC_RULE* createInferredRule( const wxString& name, std::set<BOARD_ITEM*> items, int priority );
BOARD_DESIGN_SETTINGS* m_designSettings;
BOARD* m_board;