/* * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2016 Jean-Pierre Charras, jp.charras at wanadoo.fr * Copyright (C) 2013 Wayne Stambaugh * Copyright (C) 1992-2016 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 * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, you may find one here: * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * or you may search the http://www.gnu.org website for the version 2 license, * or you may write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ /** * @file netlist_object.cpp * @brief Class NETLIST_OBJECT to handle 1 item connected (in netlist and erc calculations) */ #include #include #include #include #include #include #include #if defined(DEBUG) #include const char* ShowType( NETLIST_ITEM aType ) { const char* ret; switch( aType ) { case NETLIST_ITEM::SEGMENT: ret = "segment"; break; case NETLIST_ITEM::BUS: ret = "bus"; break; case NETLIST_ITEM::JUNCTION: ret = "junction"; break; case NETLIST_ITEM::LABEL: ret = "label"; break; case NETLIST_ITEM::HIERLABEL: ret = "hierlabel"; break; case NETLIST_ITEM::GLOBLABEL: ret = "glabel"; break; case NETLIST_ITEM::BUSLABELMEMBER: ret = "buslblmember"; break; case NETLIST_ITEM::HIERBUSLABELMEMBER: ret = "hierbuslblmember"; break; case NETLIST_ITEM::GLOBBUSLABELMEMBER: ret = "gbuslblmember"; break; case NETLIST_ITEM::SHEETBUSLABELMEMBER: ret = "sbuslblmember"; break; case NETLIST_ITEM::SHEETLABEL: ret = "sheetlabel"; break; case NETLIST_ITEM::PINLABEL: ret = "pinlabel"; break; case NETLIST_ITEM::PIN: ret = "pin"; break; case NETLIST_ITEM::NOCONNECT: ret = "noconnect"; break; default: ret = "??"; break; } return ret; } void NETLIST_OBJECT::Show( std::ostream& out, int ndx ) const { wxString path = m_SheetPath.PathHumanReadable(); out << "\n"; out << " \n"; if( !m_Label.IsEmpty() ) out << " \n"; out << " " << m_SheetPath.PathHumanReadable().mb_str() << "\n"; switch( m_Type ) { case NETLIST_ITEM::PIN: /* GetRef() needs to be const out << " " << GetComponentParent()->GetRef(&m_SheetPath).mb_str() << "\n"; */ if( m_Comp ) m_Comp->Show( 1, out ); break; default: // not all the m_Comp classes have working Show functions. ; } /* was segfault-ing if( m_Comp ) m_Comp->Show( 1, out ); // labels may not have good Show() funcs? else out << " m_Comp==NULL\n"; */ out << "\n"; } #endif NETLIST_OBJECT::NETLIST_OBJECT() { m_Type = NETLIST_ITEM::ITEM_UNSPECIFIED; /* Type of this item (see NETLIST_ITEM_T enum) */ m_Comp = NULL; /* Pointer on the library item that created this net object * (the parent)*/ m_Link = NULL; /* For SCH_SHEET_PIN: * Pointer to the hierarchy sheet that contains this * SCH_SHEET_PIN For Pins: pointer to the component that * contains this pin */ m_Flag = 0; /* flag used in calculations */ m_netCode = 0; /* net code for all items except BUS labels because a BUS * label has as many net codes as bus members */ m_BusNetCode = 0; /* Used for BUS connections */ m_Member = 0; /* for labels type NETLIST_ITEM::BUSLABELMEMBER ( bus member created * from the BUS label ) member number */ m_ConnectionType = NET_CONNECTION::UNCONNECTED; m_ElectricalPinType = ELECTRICAL_PINTYPE::PT_INPUT; /* Has meaning only for Pins: electrical type of the pin * used to detect conflicts between pins in ERC */ m_netNameCandidate = NULL; /* a pointer to a NETLIST_OBJECT type label connected to this * object used to give a name to the net */ } // Copy constructor NETLIST_OBJECT::NETLIST_OBJECT( NETLIST_OBJECT& aSource ) { *this = aSource; } NETLIST_OBJECT::~NETLIST_OBJECT() { } // return true if the object is a label of any type bool NETLIST_OBJECT::IsLabelType() const { return m_Type == NETLIST_ITEM::LABEL || m_Type == NETLIST_ITEM::GLOBLABEL || m_Type == NETLIST_ITEM::HIERLABEL || m_Type == NETLIST_ITEM::BUSLABELMEMBER || m_Type == NETLIST_ITEM::GLOBBUSLABELMEMBER || m_Type == NETLIST_ITEM::HIERBUSLABELMEMBER || m_Type == NETLIST_ITEM::PINLABEL; } bool NETLIST_OBJECT::IsLabelConnected( NETLIST_OBJECT* aNetItem ) { if( aNetItem == this ) // Don't compare the same net list object. return false; NETLIST_ITEM at = m_Type; NETLIST_ITEM bt = aNetItem->m_Type; if( ( at == NETLIST_ITEM::HIERLABEL || at == NETLIST_ITEM::HIERBUSLABELMEMBER ) && ( bt == NETLIST_ITEM::SHEETLABEL || bt == NETLIST_ITEM::SHEETBUSLABELMEMBER ) ) { if( m_SheetPath == aNetItem->m_SheetPathInclude ) { return true; //connected! } } else if( ( at == NETLIST_ITEM::GLOBLABEL ) && ( bt == NETLIST_ITEM::GLOBLABEL ) ) { if( m_Label == aNetItem->m_Label ) return true; //connected! } return false; //these two are unconnected } void NETLIST_OBJECT::ConvertBusToNetListItems( NETLIST_OBJECT_LIST& aNetListItems ) { SCH_CONNECTION conn; wxCHECK_RET( conn.IsBusLabel( m_Label ), wxT( "<" ) + m_Label + wxT( "> is not a valid bus label." ) ); if( m_Type == NETLIST_ITEM::HIERLABEL ) m_Type = NETLIST_ITEM::HIERBUSLABELMEMBER; else if( m_Type == NETLIST_ITEM::GLOBLABEL ) m_Type = NETLIST_ITEM::GLOBBUSLABELMEMBER; else if( m_Type == NETLIST_ITEM::SHEETLABEL ) m_Type = NETLIST_ITEM::SHEETBUSLABELMEMBER; else if( m_Type == NETLIST_ITEM::LABEL ) m_Type = NETLIST_ITEM::BUSLABELMEMBER; else wxCHECK_RET( false, wxT( "Net list object type is not valid." ) ); // NOTE: all netlist objects generated from a single bus definition need to have different // member codes set. For bus vectors, the member code matches the vector index, but for // bus groups (including with nested vectors) the code is something arbitrary. long member_offset = 0; auto alias = SCH_SCREEN::GetBusAlias( m_Label ); if( alias || conn.IsBusGroupLabel( m_Label ) ) { wxString group_name; bool self_set = false; std::vector bus_contents_vec; if( alias ) { for( const auto& member : alias->Members() ) bus_contents_vec.emplace_back( member ); } else { wxCHECK_RET( conn.ParseBusGroup( m_Label, &group_name, bus_contents_vec ), wxString::Format( _( "Failed to parse bus group %s" ), m_Label ) ); } // For named bus groups, like "USB{DP DM}" auto group_prefix = ( group_name != "" ) ? ( group_name + "." ) : ""; std::list bus_contents( bus_contents_vec.begin(), bus_contents_vec.end() ); for( const auto& bus_member : bus_contents ) { // Nested bus vector inside a bus group if( conn.IsBusVectorLabel( bus_member ) ) { wxString prefix; std::vector members; long begin, end; conn.ParseBusVector( bus_member, &prefix, members ); prefix = group_prefix + prefix; begin = conn.VectorStart(); end = conn.VectorEnd(); if( !self_set ) { m_Label = members[0]; m_Member = ( begin++ ) + ( member_offset++ ); self_set = true; begin++; } fillBusVector( aNetListItems, prefix, begin, end, member_offset ); member_offset += std::abs( end - begin ); } else if( auto nested_alias = SCH_SCREEN::GetBusAlias( bus_member ) ) { // Nested alias inside a group for( const auto& alias_member : nested_alias->Members() ) { bus_contents.push_back( alias_member ); } } else { if( !self_set ) { m_Label = group_prefix + bus_member; m_Member = member_offset++; self_set = true; } else { auto item = new NETLIST_OBJECT( *this ); item->m_Label = group_prefix + bus_member; item->m_Member = member_offset++; aNetListItems.push_back( item ); } } } } else { // Plain bus vector wxString prefix; std::vector members; long begin, end; conn.ParseBusVector( m_Label, &prefix, members ); begin = conn.VectorStart(); end = conn.VectorEnd(); m_Label = members[0]; m_Member = begin; fillBusVector( aNetListItems, prefix, begin + 1, end, 0 ); } } void NETLIST_OBJECT::fillBusVector( NETLIST_OBJECT_LIST& aNetListItems, wxString aName, long aBegin, long aEnd, long aOffset ) { for( long member = aBegin; member <= aEnd; member++ ) { auto item = new NETLIST_OBJECT( *this ); item->m_Label = aName; item->m_Label << member; item->m_Member = member; aNetListItems.push_back( item ); } } bool NETLIST_OBJECT::IsLabelGlobal() const { // return true if the object is a global label // * a actual global label // * a pin label coming from a invisible power pin return ( m_Type == NETLIST_ITEM::PINLABEL ) || ( m_Type == NETLIST_ITEM::GLOBLABEL ) || ( m_Type == NETLIST_ITEM::GLOBBUSLABELMEMBER ); } bool NETLIST_OBJECT::IsLabelBusMemberType() const { // return true if the object is a bus label member build from a // schematic bus label (like label[xx..yy) // They are labels with very specific properties, especially for connection // between them: 2 bus label members can be connected only // if they have the same member value. return ( m_Type == NETLIST_ITEM::SHEETBUSLABELMEMBER ) || ( m_Type == NETLIST_ITEM::BUSLABELMEMBER ) || ( m_Type == NETLIST_ITEM::HIERBUSLABELMEMBER ) || ( m_Type == NETLIST_ITEM::GLOBBUSLABELMEMBER ); } /* * return the net name of the item */ wxString NETLIST_OBJECT::GetNetName( bool adoptTimestamp ) const { if( m_netNameCandidate == NULL ) return wxEmptyString; wxString netName; if( m_netNameCandidate->m_Type == NETLIST_ITEM::PIN ) return GetShortNetName( adoptTimestamp ); if( !m_netNameCandidate->IsLabelGlobal() ) { // usual net name, prefix it by the sheet path netName = m_netNameCandidate->m_SheetPath.PathHumanReadable(); } netName += m_netNameCandidate->m_Label; return netName; } /** * return the short net name of the item i.e. the net name * from the "best" label without any prefix. * 2 different nets can have the same short name */ wxString NETLIST_OBJECT::GetShortNetName( bool adoptTimestamp ) const { if( m_netNameCandidate == NULL ) return wxEmptyString; wxString netName; if( m_netNameCandidate->m_Type == NETLIST_ITEM::PIN ) { SCH_COMPONENT* link = m_netNameCandidate->GetComponentParent(); if( link ) // Should be always true { netName = wxT("Net-("); netName << link->GetRef( &m_netNameCandidate->m_SheetPath ); if( adoptTimestamp && netName.Last() == '?' ) netName << link->GetTimeStamp(); netName << wxT("-Pad") << m_netNameCandidate->m_PinNum << wxT(")"); } } else netName = m_netNameCandidate->m_Label; return netName; } /** * Set m_netNameCandidate to a connected item which will * be used to calcule the net name of the item * Obviously the candidate can be only a label * If there is no label on the net, a pad name will be * used to build a net name (something like Cmp_Pad * @param aCandidate = the connected item candidate */ void NETLIST_OBJECT::SetNetNameCandidate( NETLIST_OBJECT* aCandidate ) { switch( aCandidate->m_Type ) { case NETLIST_ITEM::HIERLABEL: case NETLIST_ITEM::LABEL: case NETLIST_ITEM::PINLABEL: case NETLIST_ITEM::GLOBLABEL: case NETLIST_ITEM::GLOBBUSLABELMEMBER: case NETLIST_ITEM::SHEETBUSLABELMEMBER: case NETLIST_ITEM::PIN: m_netNameCandidate = aCandidate; break; default: break; } } const wxString NETLIST_OBJECT::GetPinNameText() const { wxString name; // returns the pin name, for NETLIST_ITEM::PIN (usual pin) item. if( m_Type == NETLIST_ITEM::PIN ) { name = static_cast( m_Comp )->GetName(); if( name == "~" ) //empty name name = wxEmptyString; } return name; }