You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

456 lines
14 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2016 Jean-Pierre Charras, jp.charras at wanadoo.fr
  5. * Copyright (C) 2013 Wayne Stambaugh <stambaughw@verizon.net>
  6. * Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License
  10. * as published by the Free Software Foundation; either version 2
  11. * of the License, or (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, you may find one here:
  20. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  21. * or you may search the http://www.gnu.org website for the version 2 license,
  22. * or you may write to the Free Software Foundation, Inc.,
  23. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  24. */
  25. /**
  26. * @file netlist_object.cpp
  27. * @brief Class NETLIST_OBJECT to handle 1 item connected (in netlist and erc calculations)
  28. */
  29. #include <fctsys.h>
  30. #include <macros.h>
  31. #include <list>
  32. #include <sch_component.h>
  33. #include <sch_connection.h>
  34. #include <netlist_object.h>
  35. #include <sch_edit_frame.h>
  36. #if defined(DEBUG)
  37. #include <iostream>
  38. const char* ShowType( NETLIST_ITEM_T aType )
  39. {
  40. const char* ret;
  41. switch( aType )
  42. {
  43. case NET_SEGMENT:
  44. ret = "segment"; break;
  45. case NET_BUS:
  46. ret = "bus"; break;
  47. case NET_JUNCTION:
  48. ret = "junction"; break;
  49. case NET_LABEL:
  50. ret = "label"; break;
  51. case NET_HIERLABEL:
  52. ret = "hierlabel"; break;
  53. case NET_GLOBLABEL:
  54. ret = "glabel"; break;
  55. case NET_BUSLABELMEMBER:
  56. ret = "buslblmember"; break;
  57. case NET_HIERBUSLABELMEMBER:
  58. ret = "hierbuslblmember"; break;
  59. case NET_GLOBBUSLABELMEMBER:
  60. ret = "gbuslblmember"; break;
  61. case NET_SHEETBUSLABELMEMBER:
  62. ret = "sbuslblmember"; break;
  63. case NET_SHEETLABEL:
  64. ret = "sheetlabel"; break;
  65. case NET_PINLABEL:
  66. ret = "pinlabel"; break;
  67. case NET_PIN:
  68. ret = "pin"; break;
  69. case NET_NOCONNECT:
  70. ret = "noconnect"; break;
  71. default:
  72. ret = "??"; break;
  73. }
  74. return ret;
  75. }
  76. void NETLIST_OBJECT::Show( std::ostream& out, int ndx ) const
  77. {
  78. wxString path = m_SheetPath.PathHumanReadable();
  79. out << "<netItem ndx=\"" << ndx << '"' <<
  80. " type=\"" << ShowType( m_Type ) << '"' <<
  81. " netCode=\"" << GetNet() << '"' <<
  82. " sheet=\"" << TO_UTF8( path ) << '"' <<
  83. ">\n";
  84. out << " <start " << m_Start << "/> <end " << m_End << "/>\n";
  85. if( !m_Label.IsEmpty() )
  86. out << " <label>" << m_Label.mb_str() << "</label>\n";
  87. out << " <sheetpath>" << m_SheetPath.PathHumanReadable().mb_str() << "</sheetpath>\n";
  88. switch( m_Type )
  89. {
  90. case NET_PIN:
  91. /* GetRef() needs to be const
  92. out << " <refOfComp>" << GetComponentParent()->GetRef(&m_SheetPath).mb_str()
  93. << "</refOfComp>\n";
  94. */
  95. if( m_Comp )
  96. m_Comp->Show( 1, out );
  97. break;
  98. default:
  99. // not all the m_Comp classes have working Show functions.
  100. ;
  101. }
  102. /* was segfault-ing
  103. if( m_Comp )
  104. m_Comp->Show( 1, out ); // labels may not have good Show() funcs?
  105. else
  106. out << " m_Comp==NULL\n";
  107. */
  108. out << "</netItem>\n";
  109. }
  110. #endif
  111. NETLIST_OBJECT::NETLIST_OBJECT()
  112. {
  113. m_Type = NET_ITEM_UNSPECIFIED; /* Type of this item (see NETLIST_ITEM_T enum) */
  114. m_Comp = NULL; /* Pointer on the library item that created this net object
  115. * (the parent)*/
  116. m_Link = NULL; /* For SCH_SHEET_PIN:
  117. * Pointer to the hierarchy sheet that contains this
  118. * SCH_SHEET_PIN For Pins: pointer to the component that
  119. * contains this pin
  120. */
  121. m_Flag = 0; /* flag used in calculations */
  122. m_ElectricalPinType = PIN_INPUT; /* Has meaning only for Pins: electrical type of the pin
  123. * used to detect conflicts between pins in ERC
  124. */
  125. m_netCode = 0; /* net code for all items except BUS labels because a BUS
  126. * label has as many net codes as bus members
  127. */
  128. m_BusNetCode = 0; /* Used for BUS connections */
  129. m_Member = 0; /* for labels type NET_BUSLABELMEMBER ( bus member created
  130. * from the BUS label ) member number
  131. */
  132. m_ConnectionType = UNCONNECTED;
  133. m_netNameCandidate = NULL; /* a pointer to a NETLIST_OBJECT type label connected to this
  134. * object used to give a name to the net
  135. */
  136. }
  137. // Copy constructor
  138. NETLIST_OBJECT::NETLIST_OBJECT( NETLIST_OBJECT& aSource )
  139. {
  140. *this = aSource;
  141. }
  142. NETLIST_OBJECT::~NETLIST_OBJECT()
  143. {
  144. }
  145. // return true if the object is a label of any type
  146. bool NETLIST_OBJECT::IsLabelType() const
  147. {
  148. return m_Type == NET_LABEL
  149. || m_Type == NET_GLOBLABEL || m_Type == NET_HIERLABEL
  150. || m_Type == NET_BUSLABELMEMBER || m_Type == NET_GLOBBUSLABELMEMBER
  151. || m_Type == NET_HIERBUSLABELMEMBER
  152. || m_Type == NET_PINLABEL;
  153. }
  154. bool NETLIST_OBJECT::IsLabelConnected( NETLIST_OBJECT* aNetItem )
  155. {
  156. if( aNetItem == this ) // Don't compare the same net list object.
  157. return false;
  158. int at = m_Type;
  159. int bt = aNetItem->m_Type;
  160. if( ( at == NET_HIERLABEL || at == NET_HIERBUSLABELMEMBER )
  161. && ( bt == NET_SHEETLABEL || bt == NET_SHEETBUSLABELMEMBER ) )
  162. {
  163. if( m_SheetPath == aNetItem->m_SheetPathInclude )
  164. {
  165. return true; //connected!
  166. }
  167. }
  168. else if( ( at == NET_GLOBLABEL ) && ( bt == NET_GLOBLABEL ) )
  169. {
  170. if( m_Label == aNetItem->m_Label )
  171. return true; //connected!
  172. }
  173. return false; //these two are unconnected
  174. }
  175. void NETLIST_OBJECT::ConvertBusToNetListItems( NETLIST_OBJECT_LIST& aNetListItems )
  176. {
  177. SCH_CONNECTION conn;
  178. wxCHECK_RET( conn.IsBusLabel( m_Label ),
  179. wxT( "<" ) + m_Label + wxT( "> is not a valid bus label." ) );
  180. if( m_Type == NET_HIERLABEL )
  181. m_Type = NET_HIERBUSLABELMEMBER;
  182. else if( m_Type == NET_GLOBLABEL )
  183. m_Type = NET_GLOBBUSLABELMEMBER;
  184. else if( m_Type == NET_SHEETLABEL )
  185. m_Type = NET_SHEETBUSLABELMEMBER;
  186. else if( m_Type == NET_LABEL )
  187. m_Type = NET_BUSLABELMEMBER;
  188. else
  189. wxCHECK_RET( false, wxT( "Net list object type is not valid." ) );
  190. // NOTE: all netlist objects generated from a single bus definition need to have different
  191. // member codes set. For bus vectors, the member code matches the vector index, but for
  192. // bus groups (including with nested vectors) the code is something arbitrary.
  193. long member_offset = 0;
  194. auto alias = SCH_SCREEN::GetBusAlias( m_Label );
  195. if( alias || conn.IsBusGroupLabel( m_Label ) )
  196. {
  197. wxString group_name;
  198. bool self_set = false;
  199. std::vector<wxString> bus_contents_vec;
  200. if( alias )
  201. {
  202. bus_contents_vec = alias->Members();
  203. }
  204. else
  205. {
  206. wxCHECK_RET( conn.ParseBusGroup( m_Label, &group_name, bus_contents_vec ),
  207. _( "Failed to parse bus group " ) + m_Label );
  208. }
  209. // For named bus groups, like "USB{DP DM}"
  210. auto group_prefix = ( group_name != "" ) ? ( group_name + "." ) : "";
  211. std::list<wxString> bus_contents( bus_contents_vec.begin(),
  212. bus_contents_vec.end() );
  213. for( auto bus_member : bus_contents )
  214. {
  215. // Nested bus vector inside a bus group
  216. if( conn.IsBusVectorLabel( bus_member ) )
  217. {
  218. wxString prefix;
  219. long begin, end;
  220. conn.ParseBusVector( bus_member, &prefix, &begin, &end );
  221. prefix = group_prefix + prefix;
  222. if( !self_set )
  223. {
  224. m_Label = prefix;
  225. m_Label << begin;
  226. m_Member = ( begin++ ) + ( member_offset++ );
  227. self_set = true;
  228. begin++;
  229. }
  230. fillBusVector( aNetListItems, prefix, begin, end, member_offset );
  231. member_offset += std::abs( end - begin );
  232. }
  233. else if( auto nested_alias = SCH_SCREEN::GetBusAlias( bus_member ) )
  234. {
  235. // Nested alias inside a group
  236. for( auto alias_member : nested_alias->Members() )
  237. {
  238. bus_contents.push_back( alias_member );
  239. }
  240. }
  241. else
  242. {
  243. if( !self_set )
  244. {
  245. m_Label = group_prefix + bus_member;
  246. m_Member = member_offset++;
  247. self_set = true;
  248. }
  249. else
  250. {
  251. auto item = new NETLIST_OBJECT( *this );
  252. item->m_Label = group_prefix + bus_member;
  253. item->m_Member = member_offset++;
  254. aNetListItems.push_back( item );
  255. }
  256. }
  257. }
  258. }
  259. else
  260. {
  261. // Plain bus vector
  262. wxString prefix;
  263. long begin, end;
  264. conn.ParseBusVector( m_Label, &prefix, &begin, &end );
  265. m_Label = prefix;
  266. m_Label << begin;
  267. m_Member = begin;
  268. fillBusVector( aNetListItems, prefix, begin + 1, end, 0 );
  269. }
  270. }
  271. void NETLIST_OBJECT::fillBusVector( NETLIST_OBJECT_LIST& aNetListItems,
  272. wxString aName, long aBegin, long aEnd, long aOffset )
  273. {
  274. for( long member = aBegin; member <= aEnd; member++ )
  275. {
  276. auto item = new NETLIST_OBJECT( *this );
  277. item->m_Label = aName;
  278. item->m_Label << member;
  279. item->m_Member = member;
  280. aNetListItems.push_back( item );
  281. }
  282. }
  283. bool NETLIST_OBJECT::IsLabelGlobal() const
  284. {
  285. // return true if the object is a global label
  286. // * a actual global label
  287. // * a pin label coming from a invisible power pin
  288. return ( m_Type == NET_PINLABEL ) ||
  289. ( m_Type == NET_GLOBLABEL ) ||
  290. ( m_Type == NET_GLOBBUSLABELMEMBER );
  291. }
  292. bool NETLIST_OBJECT::IsLabelBusMemberType() const
  293. {
  294. // return true if the object is a bus label member build from a
  295. // schematic bus label (like label[xx..yy)
  296. // They are labels with very specific properties, especially for connection
  297. // between them: 2 bus label members can be connected only
  298. // if they have the same member value.
  299. return ( m_Type == NET_SHEETBUSLABELMEMBER ) ||
  300. ( m_Type == NET_BUSLABELMEMBER ) ||
  301. ( m_Type == NET_HIERBUSLABELMEMBER ) ||
  302. ( m_Type == NET_GLOBBUSLABELMEMBER );
  303. }
  304. /*
  305. * return the net name of the item
  306. */
  307. wxString NETLIST_OBJECT::GetNetName( bool adoptTimestamp ) const
  308. {
  309. if( m_netNameCandidate == NULL )
  310. return wxEmptyString;
  311. wxString netName;
  312. if( m_netNameCandidate->m_Type == NET_PIN )
  313. return GetShortNetName( adoptTimestamp );
  314. if( !m_netNameCandidate->IsLabelGlobal() )
  315. {
  316. // usual net name, prefix it by the sheet path
  317. netName = m_netNameCandidate->m_SheetPath.PathHumanReadable();
  318. }
  319. netName += m_netNameCandidate->m_Label;
  320. return netName;
  321. }
  322. /**
  323. * return the short net name of the item i.e. the net name
  324. * from the "best" label without any prefix.
  325. * 2 different nets can have the same short name
  326. */
  327. wxString NETLIST_OBJECT::GetShortNetName( bool adoptTimestamp ) const
  328. {
  329. if( m_netNameCandidate == NULL )
  330. return wxEmptyString;
  331. wxString netName;
  332. if( m_netNameCandidate->m_Type == NET_PIN )
  333. {
  334. SCH_COMPONENT* link = m_netNameCandidate->GetComponentParent();
  335. if( link ) // Should be always true
  336. {
  337. netName = wxT("Net-(");
  338. netName << link->GetRef( &m_netNameCandidate->m_SheetPath );
  339. if( adoptTimestamp && netName.Last() == '?' )
  340. netName << link->GetTimeStamp();
  341. netName << wxT("-Pad") << m_netNameCandidate->m_PinNum << wxT(")");
  342. }
  343. }
  344. else
  345. netName = m_netNameCandidate->m_Label;
  346. return netName;
  347. }
  348. /**
  349. * Set m_netNameCandidate to a connected item which will
  350. * be used to calcule the net name of the item
  351. * Obviously the candidate can be only a label
  352. * If there is no label on the net, a pad name will be
  353. * used to build a net name (something like Cmp<REF>_Pad<PAD_NAME>
  354. * @param aCandidate = the connected item candidate
  355. */
  356. void NETLIST_OBJECT::SetNetNameCandidate( NETLIST_OBJECT* aCandidate )
  357. {
  358. switch( aCandidate->m_Type )
  359. {
  360. case NET_HIERLABEL:
  361. case NET_LABEL:
  362. case NET_PINLABEL:
  363. case NET_GLOBLABEL:
  364. case NET_GLOBBUSLABELMEMBER:
  365. case NET_SHEETBUSLABELMEMBER:
  366. case NET_PIN:
  367. m_netNameCandidate = aCandidate;
  368. break;
  369. default:
  370. break;
  371. }
  372. }