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:
parent
2c02c26af4
commit
d51e058e24
|
@ -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 )
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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() ) ) )
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 )
|
||||
{
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -2536,6 +2536,7 @@ void ROUTER_TOOL::UpdateMessagePanel()
|
|||
{
|
||||
PNS::SIZES_SETTINGS sizes( m_router->Sizes() );
|
||||
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
|
||||
{
|
||||
|
|
|
@ -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." ),
|
||||
|
|
|
@ -1432,6 +1432,53 @@ int PCB_CONTROL::UpdateMessagePanel( const TOOL_EVENT& aEvent )
|
|||
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 )
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue