Move diff-pair netname resolution to BOARD.

Also adds reporting of dp gap constaints and max uncoupled to track
selections, and max uncoupled during routing.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/13748
This commit is contained in:
Jeff Young 2023-10-15 22:45:18 +01:00
parent 2c02c26af4
commit d51e058e24
12 changed files with 161 additions and 97 deletions

View File

@ -1640,6 +1640,71 @@ NETINFO_ITEM* BOARD::FindNet( const wxString& aNetname ) const
}
int BOARD::MatchDpSuffix( const wxString& aNetName, wxString& aComplementNet )
{
int rv = 0;
int count = 0;
for( auto it = aNetName.rbegin(); it != aNetName.rend() && rv == 0; ++it, ++count )
{
int ch = *it;
if( ( ch >= '0' && ch <= '9' ) || ch == '_' )
{
continue;
}
else if( ch == '+' )
{
aComplementNet = wxT( "-" );
rv = 1;
}
else if( ch == '-' )
{
aComplementNet = wxT( "+" );
rv = -1;
}
else if( ch == 'N' )
{
aComplementNet = wxT( "P" );
rv = -1;
}
else if ( ch == 'P' )
{
aComplementNet = wxT( "N" );
rv = 1;
}
else
{
break;
}
}
if( rv != 0 && count >= 1 )
{
aComplementNet = aNetName.Left( aNetName.length() - count )
+ aComplementNet
+ aNetName.Right( count - 1 );
}
return rv;
}
NETINFO_ITEM* BOARD::DpCoupledNet( const NETINFO_ITEM* aNet )
{
if( aNet )
{
wxString refName = aNet->GetNetname();
wxString coupledNetName;
if( MatchDpSuffix( refName, coupledNetName ) )
return FindNet( coupledNetName );
}
return nullptr;
}
FOOTPRINT* BOARD::FindFootprintByReference( const wxString& aReference ) const
{
for( FOOTPRINT* footprint : m_footprints )

View File

@ -804,6 +804,22 @@ public:
*/
NETINFO_ITEM* FindNet( const wxString& aNetname ) const;
/**
* Fetch the coupled netname for a given net.
*
* This accepts netnames suffixed by 'P', 'N', '+', '-', as well as additional numbers and
* underscores following the suffix. So NET_P_123 is a valid positive net name matched to
* NET_N_123.
*
* @return the polarity of the given net (or 0 if it is not a diffpair net).
*/
int MatchDpSuffix( const wxString& aNetName, wxString& aComplementNet );
/**
* @return the coupled net for a given net. If not a diffpair, nullptr is returned.
*/
NETINFO_ITEM* DpCoupledNet( const NETINFO_ITEM* aNet );
const NETINFO_LIST& GetNetInfo() const
{
return m_NetInfo;

View File

@ -907,7 +907,7 @@ DRC_CONSTRAINT DRC_ENGINE::EvalRules( DRC_CONSTRAINT_T aConstraintType, const BO
MessageTextFromValue( c->constraint.m_Value.Min() ) ) )
break;
case DIFF_PAIR_MAX_UNCOUPLED_CONSTRAINT:
case MAX_UNCOUPLED_CONSTRAINT:
REPORT( wxString::Format( _( "Checking %s max uncoupled length: %s." ),
EscapeHTML( c->constraint.GetName() ),
MessageTextFromValue( c->constraint.m_Value.Max() ) ) )

View File

@ -64,7 +64,7 @@ enum DRC_CONSTRAINT_T
LENGTH_CONSTRAINT,
SKEW_CONSTRAINT,
DIFF_PAIR_GAP_CONSTRAINT,
DIFF_PAIR_MAX_UNCOUPLED_CONSTRAINT,
MAX_UNCOUPLED_CONSTRAINT,
DIFF_PAIR_INTRA_SKEW_CONSTRAINT,
VIA_COUNT_CONSTRAINT,
PHYSICAL_CLEARANCE_CONSTRAINT,

View File

@ -325,7 +325,7 @@ void DRC_RULES_PARSER::parseConstraint( DRC_RULE* aRule )
case T_skew: c.m_Type = SKEW_CONSTRAINT; break;
case T_via_count: c.m_Type = VIA_COUNT_CONSTRAINT; break;
case T_diff_pair_gap: c.m_Type = DIFF_PAIR_GAP_CONSTRAINT; break;
case T_diff_pair_uncoupled: c.m_Type = DIFF_PAIR_MAX_UNCOUPLED_CONSTRAINT; break;
case T_diff_pair_uncoupled: c.m_Type = MAX_UNCOUPLED_CONSTRAINT; break;
case T_physical_clearance: c.m_Type = PHYSICAL_CLEARANCE_CONSTRAINT; break;
case T_physical_hole_clearance: c.m_Type = PHYSICAL_HOLE_CLEARANCE_CONSTRAINT; break;
default:

View File

@ -297,7 +297,7 @@ bool test::DRC_TEST_PROVIDER_DIFF_PAIR_COUPLING::Run()
const DRC_CONSTRAINT_T constraintsToCheck[] = {
DIFF_PAIR_GAP_CONSTRAINT,
DIFF_PAIR_MAX_UNCOUPLED_CONSTRAINT
MAX_UNCOUPLED_CONSTRAINT
};
for( int i = 0; i < 2; i++ )
@ -322,7 +322,7 @@ bool test::DRC_TEST_PROVIDER_DIFF_PAIR_COUPLING::Run()
key.gapRuleName = ruleName;
break;
case DIFF_PAIR_MAX_UNCOUPLED_CONSTRAINT:
case MAX_UNCOUPLED_CONSTRAINT:
key.uncoupledConstraint = constraint.GetValue();
key.uncoupledRule = parentRule;
key.uncoupledRuleName = ruleName;

View File

@ -363,14 +363,6 @@ static std::string sideToString( const PNS::MEANDER_SIDE aValue )
}
static NETINFO_ITEM* getCoupledNet( PNS::ROUTER* aRouter, NETINFO_ITEM* aNet )
{
PNS::RULE_RESOLVER* resolver = aRouter->GetRuleResolver();
return static_cast<NETINFO_ITEM*>( resolver->DpCoupledNet( aNet ) );
}
PCB_GENERATOR_MEANDERS::PCB_GENERATOR_MEANDERS( BOARD_ITEM* aParent, PCB_LAYER_ID aLayer,
LENGTH_TUNING_MODE aMode ) :
PCB_GENERATOR( aParent, aLayer ),
@ -452,7 +444,7 @@ PCB_GENERATOR_MEANDERS* PCB_GENERATOR_MEANDERS::CreateNew( GENERATOR_TOOL* aTool
DRC_CONSTRAINT constraint;
PCB_LAYER_ID layer = aStartItem->GetLayer();
if( aMode == SINGLE && getCoupledNet( aTool->Router(), aStartItem->GetNet() ) )
if( aMode == SINGLE && board->DpCoupledNet( aStartItem->GetNet() ) )
aMode = DIFF_PAIR;
PCB_GENERATOR_MEANDERS* meander = new PCB_GENERATOR_MEANDERS( board, layer, aMode );
@ -543,7 +535,7 @@ void PCB_GENERATOR_MEANDERS::EditStart( GENERATOR_TOOL* aTool, BOARD* aBoard,
}
else
{
NETINFO_ITEM* coupledNet = static_cast<NETINFO_ITEM*>( resolver->DpCoupledNet( net ) );
NETINFO_ITEM* coupledNet = aBoard->DpCoupledNet( net );
PNS::SEGMENT coupledItem( m_baseLineCoupled->CSegment( 0 ), coupledNet );
if( m_tuningMode == DIFF_PAIR )
@ -749,7 +741,7 @@ bool PCB_GENERATOR_MEANDERS::initBaseLines( PNS::ROUTER* aRouter, int aLayer, BO
// DRC rules against.
if( m_tuningMode == DIFF_PAIR || m_tuningMode == DIFF_PAIR_SKEW )
{
if( NETINFO_ITEM* coupledNet = getCoupledNet( aRouter, net ) )
if( NETINFO_ITEM* coupledNet = aBoard->DpCoupledNet( net ) )
{
VECTOR2I coupledStart = m_origin;
VECTOR2I coupledEnd = m_end;

View File

@ -130,18 +130,6 @@ public:
void ClearCacheForItems( std::vector<const PNS::ITEM*>& aItems ) override;
void ClearCaches() override;
private:
/**
* Checks for netnamed differential pairs.
* This accepts nets named suffixed by 'P', 'N', '+', '-', as well as additional
* numbers and underscores following the suffix. So NET_P_123 is a valid positive net
* name matched to NET_N_123.
* @param aNetName Input net name to check for DP naming
* @param aComplementNet Generated net name for the pair
* @return -1 if found the negative pair, +1 if found the positive pair, 0 otherwise
*/
int matchDpSuffix( const wxString& aNetName, wxString& aComplementNet );
private:
PNS::ROUTER_IFACE* m_routerIface;
BOARD* m_board;
@ -341,6 +329,7 @@ bool PNS_PCBNEW_RULE_RESOLVER::QueryConstraint( PNS::CONSTRAINT_TYPE aType,
case PNS::CONSTRAINT_TYPE::CT_DIFF_PAIR_GAP: hostType = DIFF_PAIR_GAP_CONSTRAINT; break;
case PNS::CONSTRAINT_TYPE::CT_LENGTH: hostType = LENGTH_CONSTRAINT; break;
case PNS::CONSTRAINT_TYPE::CT_DIFF_PAIR_SKEW: hostType = SKEW_CONSTRAINT; break;
case PNS::CONSTRAINT_TYPE::CT_MAX_UNCOUPLED: hostType = MAX_UNCOUPLED_CONSTRAINT; break;
case PNS::CONSTRAINT_TYPE::CT_VIA_DIAMETER: hostType = VIA_DIAMETER_CONSTRAINT; break;
case PNS::CONSTRAINT_TYPE::CT_VIA_HOLE: hostType = HOLE_SIZE_CONSTRAINT; break;
case PNS::CONSTRAINT_TYPE::CT_HOLE_CLEARANCE: hostType = HOLE_CLEARANCE_CONSTRAINT; break;
@ -448,6 +437,7 @@ bool PNS_PCBNEW_RULE_RESOLVER::QueryConstraint( PNS::CONSTRAINT_TYPE aType,
case PNS::CONSTRAINT_TYPE::CT_HOLE_TO_HOLE:
case PNS::CONSTRAINT_TYPE::CT_LENGTH:
case PNS::CONSTRAINT_TYPE::CT_DIFF_PAIR_SKEW:
case PNS::CONSTRAINT_TYPE::CT_MAX_UNCOUPLED:
aConstraint->m_Value = hostConstraint.GetValue();
aConstraint->m_RuleName = hostConstraint.GetName();
aConstraint->m_Type = aType;
@ -807,68 +797,9 @@ int PNS_KICAD_IFACE_BASE::StackupHeight( int aFirstLayer, int aSecondLayer ) con
}
int PNS_PCBNEW_RULE_RESOLVER::matchDpSuffix( const wxString& aNetName, wxString& aComplementNet )
{
int rv = 0;
int count = 0;
for( auto it = aNetName.rbegin(); it != aNetName.rend() && rv == 0; ++it, ++count )
{
int ch = *it;
if( ( ch >= '0' && ch <= '9' ) || ch == '_' )
{
continue;
}
else if( ch == '+' )
{
aComplementNet = wxT( "-" );
rv = 1;
}
else if( ch == '-' )
{
aComplementNet = wxT( "+" );
rv = -1;
}
else if( ch == 'N' )
{
aComplementNet = wxT( "P" );
rv = -1;
}
else if ( ch == 'P' )
{
aComplementNet = wxT( "N" );
rv = 1;
}
else
{
break;
}
}
if( rv != 0 && count >= 1 )
{
aComplementNet = aNetName.Left( aNetName.length() - count )
+ aComplementNet
+ aNetName.Right( count - 1 );
}
return rv;
}
PNS::NET_HANDLE PNS_PCBNEW_RULE_RESOLVER::DpCoupledNet( PNS::NET_HANDLE aNet )
{
if( NETINFO_ITEM* net = static_cast<NETINFO_ITEM*>( aNet ) )
{
wxString refName = net->GetNetname();
wxString coupledNetName;
if( matchDpSuffix( refName, coupledNetName ) )
return m_board->FindNet( coupledNetName );
}
return nullptr;
return m_board->DpCoupledNet( static_cast<NETINFO_ITEM*>( aNet ) );
}
@ -893,7 +824,7 @@ int PNS_PCBNEW_RULE_RESOLVER::DpNetPolarity( PNS::NET_HANDLE aNet )
wxString dummy1;
return matchDpSuffix( refName, dummy1 );
return m_board->MatchDpSuffix( refName, dummy1 );
}
@ -906,7 +837,7 @@ bool PNS_PCBNEW_RULE_RESOLVER::DpNetPair( const PNS::ITEM* aItem, PNS::NET_HANDL
wxString netNameP = static_cast<NETINFO_ITEM*>( aItem->Net() )->GetNetname();
wxString netNameN, netNameCoupled;
int r = matchDpSuffix( netNameP, netNameCoupled );
int r = m_board->MatchDpSuffix( netNameP, netNameCoupled );
if( r == 0 )
{

View File

@ -59,7 +59,8 @@ enum class CONSTRAINT_TYPE
CT_HOLE_CLEARANCE = 7,
CT_EDGE_CLEARANCE = 8,
CT_HOLE_TO_HOLE = 9,
CT_DIFF_PAIR_SKEW = 10
CT_DIFF_PAIR_SKEW = 10,
CT_MAX_UNCOUPLED = 11
};
/**

View File

@ -2535,7 +2535,8 @@ void ROUTER_TOOL::UpdateMessagePanel()
if( m_router->GetState() == PNS::ROUTER::ROUTE_TRACK )
{
PNS::SIZES_SETTINGS sizes( m_router->Sizes() );
PNS::RULE_RESOLVER* resolver = m_iface->GetRuleResolver();
PNS::RULE_RESOLVER* resolver = m_iface->GetRuleResolver();
PNS::CONSTRAINT constraint;
std::vector<PNS::NET_HANDLE> nets = m_router->GetCurrentNets();
wxString description;
wxString secondary;
@ -2620,6 +2621,18 @@ void ROUTER_TOOL::UpdateMessagePanel()
FORMAT_VALUE( sizes.DiffPairGap() ) ),
wxString::Format( _( "(from %s)" ),
sizes.GetDiffPairGapSource() ) );
const PNS::ITEM_SET& traces = m_router->Placer()->Traces();
wxASSERT( traces.Count() == 2 );
if( resolver->QueryConstraint( PNS::CONSTRAINT_TYPE::CT_MAX_UNCOUPLED, traces[0],
traces[1], m_router->GetCurrentLayer(), &constraint ) )
{
items.emplace_back( wxString::Format( _( "DP Max Uncoupled-length: %s" ),
FORMAT_VALUE( constraint.m_Value.Max() ) ),
wxString::Format( _( "(from %s)" ),
constraint.m_RuleName ) );
}
}
else
{

View File

@ -315,7 +315,7 @@ void BOARD_INSPECTION_TOOL::InspectDRCError( const std::shared_ptr<RC_ITEM>& aDR
if( compileError )
reportCompileError( r );
constraint = drcEngine.EvalRules( DIFF_PAIR_MAX_UNCOUPLED_CONSTRAINT, a, b, layer, r );
constraint = drcEngine.EvalRules( MAX_UNCOUPLED_CONSTRAINT, a, b, layer, r );
r->Report( "" );
r->Report( wxString::Format( _( "Resolved max uncoupled length: %s." ),
@ -908,15 +908,14 @@ int BOARD_INSPECTION_TOOL::InspectClearance( const TOOL_EVENT& aEvent )
reportHeader( _( "Diff-pair max uncoupled length resolution for:" ), ac, bc,
active, r );
if( !drcEngine.HasRulesForConstraintType( DIFF_PAIR_MAX_UNCOUPLED_CONSTRAINT ) )
if( !drcEngine.HasRulesForConstraintType( MAX_UNCOUPLED_CONSTRAINT ) )
{
r->Report( "" );
r->Report( _( "No 'diff_pair_uncoupled' constraints defined." ) );
}
else
{
constraint = drcEngine.EvalRules( DIFF_PAIR_MAX_UNCOUPLED_CONSTRAINT, ac, bc,
active, r );
constraint = drcEngine.EvalRules( MAX_UNCOUPLED_CONSTRAINT, ac, bc, active, r );
r->Report( "" );
r->Report( wxString::Format( _( "Resolved max uncoupled length: %s." ),

View File

@ -1429,9 +1429,56 @@ int PCB_CONTROL::UpdateMessagePanel( const TOOL_EVENT& aEvent )
}
else if( selection.GetSize() == 1 )
{
EDA_ITEM* item = selection.Front();
EDA_ITEM* item = selection.Front();
item->GetMsgPanelInfo( m_frame, msgItems );
PCB_TRACK* track = dynamic_cast<PCB_TRACK*>( item );
NETINFO_ITEM* net = track ? track->GetNet() : nullptr;
NETINFO_ITEM* coupledNet = net ? m_frame->GetBoard()->DpCoupledNet( net ) : nullptr;
if( coupledNet )
{
SEG trackSeg( track->GetStart(), track->GetEnd() );
PCB_TRACK* coupledItem = nullptr;
SEG::ecoord closestDist_sq;
for( PCB_TRACK* candidate : m_frame->GetBoard()->Tracks() )
{
if( candidate->GetNet() != coupledNet )
continue;
SEG::ecoord dist_sq = trackSeg.SquaredDistance( SEG( candidate->GetStart(),
candidate->GetEnd() ) );
if( !coupledItem || dist_sq < closestDist_sq )
{
coupledItem = candidate;
closestDist_sq = dist_sq;
}
}
constraint = drcEngine->EvalRules( DIFF_PAIR_GAP_CONSTRAINT, track, coupledItem,
track->GetLayer() );
wxString msg = m_frame->MessageTextFromMinOptMax( constraint.Value() );
if( !msg.IsEmpty() )
{
msgItems.emplace_back( wxString::Format( _( "DP Gap Constraints: %s" ), msg ),
wxString::Format( _( "(from %s)" ), constraint.GetName() ) );
}
constraint = drcEngine->EvalRules( MAX_UNCOUPLED_CONSTRAINT, track,
coupledItem, track->GetLayer() );
if( constraint.Value().HasMax() )
{
msg = m_frame->MessageTextFromValue( constraint.Value().Max() );
msgItems.emplace_back( wxString::Format( _( "DP Max Uncoupled-length: %s" ), msg ),
wxString::Format( _( "(from %s)" ), constraint.GetName() ) );
}
}
}
else if( pcbFrame && selection.GetSize() == 2 )
{