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.

971 lines
29 KiB

18 years ago
18 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
  5. * Copyright (C) 2013-2016 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 eeschema/netlist.cpp
  27. */
  28. #include <fctsys.h>
  29. #include <schframe.h>
  30. #include <confirm.h>
  31. #include <netlist_exporter_kicad.h>
  32. #include <kiway.h>
  33. #include <netlist.h>
  34. #include <class_netlist_object.h>
  35. #include <class_library.h>
  36. #include <lib_pin.h>
  37. #include <sch_junction.h>
  38. #include <sch_component.h>
  39. #include <sch_line.h>
  40. #include <sch_no_connect.h>
  41. #include <sch_text.h>
  42. #include <sch_sheet.h>
  43. #include <algorithm>
  44. #include <invoke_sch_dialog.h>
  45. #define IS_WIRE false
  46. #define IS_BUS true
  47. //Imported function:
  48. int TestDuplicateSheetNames( bool aCreateMarker );
  49. bool SCH_EDIT_FRAME::prepareForNetlist()
  50. {
  51. SCH_SHEET_LIST sheets( g_RootSheet );
  52. sheets.AnnotatePowerSymbols( Prj().SchLibs() );
  53. // Performs some controls:
  54. if( CheckAnnotate( NULL, 0 ) )
  55. {
  56. // Schematic must be annotated: call Annotate dialog and tell
  57. // the user why that is.
  58. InvokeDialogAnnotate( this, _( "Exporting the netlist requires a "
  59. "completely\nannotated schematic." ) );
  60. if( CheckAnnotate( NULL, 0 ) )
  61. return false;
  62. }
  63. // Test duplicate sheet names:
  64. if( TestDuplicateSheetNames( false ) > 0 )
  65. {
  66. if( !IsOK( NULL, _( "Error: duplicate sheet names. Continue?" ) ) )
  67. return false;
  68. }
  69. // Cleanup the entire hierarchy
  70. SCH_SCREENS screens;
  71. screens.SchematicCleanUp();
  72. return true;
  73. }
  74. void SCH_EDIT_FRAME::sendNetlist()
  75. {
  76. NETLIST_OBJECT_LIST* net_atoms = BuildNetListBase();
  77. NETLIST_EXPORTER_KICAD exporter( net_atoms, Prj().SchLibs() );
  78. STRING_FORMATTER formatter;
  79. // @todo : trim GNL_ALL down to minimum for CVPCB
  80. exporter.Format( &formatter, GNL_ALL );
  81. Kiway().ExpressMail( FRAME_CVPCB,
  82. MAIL_EESCHEMA_NETLIST,
  83. formatter.GetString(), // an abbreviated "kicad" (s-expr) netlist
  84. this
  85. );
  86. }
  87. bool SCH_EDIT_FRAME::CreateNetlist( int aFormat, const wxString& aFullFileName,
  88. unsigned aNetlistOptions, REPORTER* aReporter )
  89. {
  90. if( !prepareForNetlist() )
  91. return false;
  92. std::unique_ptr<NETLIST_OBJECT_LIST> connectedItemsList( BuildNetListBase() );
  93. bool success = WriteNetListFile( connectedItemsList.release(), aFormat,
  94. aFullFileName, aNetlistOptions, aReporter );
  95. return success;
  96. }
  97. //#define NETLIST_DEBUG
  98. NETLIST_OBJECT_LIST::~NETLIST_OBJECT_LIST()
  99. {
  100. Clear();
  101. }
  102. void NETLIST_OBJECT_LIST::Clear()
  103. {
  104. NETLIST_OBJECTS::iterator iter;
  105. for( iter = begin(); iter != end(); iter++ )
  106. {
  107. NETLIST_OBJECT* item = *iter;
  108. delete item;
  109. }
  110. clear();
  111. }
  112. void NETLIST_OBJECT_LIST::SortListbyNetcode()
  113. {
  114. sort( this->begin(), this->end(), NETLIST_OBJECT_LIST::sortItemsbyNetcode );
  115. }
  116. void NETLIST_OBJECT_LIST::SortListbySheet()
  117. {
  118. sort( this->begin(), this->end(), NETLIST_OBJECT_LIST::sortItemsBySheet );
  119. }
  120. NETLIST_OBJECT_LIST* SCH_EDIT_FRAME::BuildNetListBase()
  121. {
  122. // I own this list until I return it to the new owner.
  123. std::unique_ptr<NETLIST_OBJECT_LIST> ret( new NETLIST_OBJECT_LIST() );
  124. // Creates the flattened sheet list:
  125. SCH_SHEET_LIST aSheets( g_RootSheet );
  126. // Build netlist info
  127. bool success = ret->BuildNetListInfo( aSheets );
  128. if( !success )
  129. {
  130. SetStatusText( _( "No Objects" ) );
  131. return ret.release();
  132. }
  133. wxString msg = wxString::Format( _( "Net count = %d" ), int( ret->size() ) );
  134. SetStatusText( msg );
  135. return ret.release();
  136. }
  137. bool NETLIST_OBJECT_LIST::BuildNetListInfo( SCH_SHEET_LIST& aSheets )
  138. {
  139. SCH_SHEET_PATH* sheet;
  140. // Fill list with connected items from the flattened sheet list
  141. for( unsigned i = 0; i < aSheets.size(); i++ )
  142. {
  143. sheet = &aSheets[i];
  144. for( SCH_ITEM* item = sheet->LastScreen()->GetDrawItems(); item; item = item->Next() )
  145. {
  146. item->GetNetListItem( *this, sheet );
  147. }
  148. }
  149. if( size() == 0 )
  150. return false;
  151. // Sort objects by Sheet
  152. SortListbySheet();
  153. sheet = &(GetItem( 0 )->m_SheetPath);
  154. m_lastNetCode = m_lastBusNetCode = 1;
  155. for( unsigned ii = 0, istart = 0; ii < size(); ii++ )
  156. {
  157. NETLIST_OBJECT* net_item = GetItem( ii );
  158. if( net_item->m_SheetPath != *sheet ) // Sheet change
  159. {
  160. sheet = &(net_item->m_SheetPath);
  161. istart = ii;
  162. }
  163. switch( net_item->m_Type )
  164. {
  165. case NET_ITEM_UNSPECIFIED:
  166. wxMessageBox( wxT( "BuildNetListInfo() error" ) );
  167. break;
  168. case NET_PIN:
  169. case NET_PINLABEL:
  170. case NET_SHEETLABEL:
  171. case NET_NOCONNECT:
  172. if( net_item->GetNet() != 0 )
  173. break;
  174. case NET_SEGMENT:
  175. // Test connections point to point type without bus.
  176. if( net_item->GetNet() == 0 )
  177. {
  178. net_item->SetNet( m_lastNetCode );
  179. m_lastNetCode++;
  180. }
  181. pointToPointConnect( net_item, IS_WIRE, istart );
  182. break;
  183. case NET_JUNCTION:
  184. // Control of the junction outside BUS.
  185. if( net_item->GetNet() == 0 )
  186. {
  187. net_item->SetNet( m_lastNetCode );
  188. m_lastNetCode++;
  189. }
  190. segmentToPointConnect( net_item, IS_WIRE, istart );
  191. // Control of the junction, on BUS.
  192. if( net_item->m_BusNetCode == 0 )
  193. {
  194. net_item->m_BusNetCode = m_lastBusNetCode;
  195. m_lastBusNetCode++;
  196. }
  197. segmentToPointConnect( net_item, IS_BUS, istart );
  198. break;
  199. case NET_LABEL:
  200. case NET_HIERLABEL:
  201. case NET_GLOBLABEL:
  202. // Test connections type junction without bus.
  203. if( net_item->GetNet() == 0 )
  204. {
  205. net_item->SetNet( m_lastNetCode );
  206. m_lastNetCode++;
  207. }
  208. segmentToPointConnect( net_item, IS_WIRE, istart );
  209. break;
  210. case NET_SHEETBUSLABELMEMBER:
  211. if( net_item->m_BusNetCode != 0 )
  212. break;
  213. case NET_BUS:
  214. // Control type connections point to point mode bus
  215. if( net_item->m_BusNetCode == 0 )
  216. {
  217. net_item->m_BusNetCode = m_lastBusNetCode;
  218. m_lastBusNetCode++;
  219. }
  220. pointToPointConnect( net_item, IS_BUS, istart );
  221. break;
  222. case NET_BUSLABELMEMBER:
  223. case NET_HIERBUSLABELMEMBER:
  224. case NET_GLOBBUSLABELMEMBER:
  225. // Control connections similar has on BUS
  226. if( net_item->GetNet() == 0 )
  227. {
  228. net_item->m_BusNetCode = m_lastBusNetCode;
  229. m_lastBusNetCode++;
  230. }
  231. segmentToPointConnect( net_item, IS_BUS, istart );
  232. break;
  233. }
  234. }
  235. #if defined(NETLIST_DEBUG) && defined(DEBUG)
  236. std::cout << "\n\nafter sheet local\n\n";
  237. DumpNetTable();
  238. #endif
  239. // Updating the Bus Labels Netcode connected by Bus
  240. connectBusLabels();
  241. // Group objects by label.
  242. for( unsigned ii = 0; ii < size(); ii++ )
  243. {
  244. switch( GetItem( ii )->m_Type )
  245. {
  246. case NET_PIN:
  247. case NET_SHEETLABEL:
  248. case NET_SEGMENT:
  249. case NET_JUNCTION:
  250. case NET_BUS:
  251. case NET_NOCONNECT:
  252. break;
  253. case NET_LABEL:
  254. case NET_GLOBLABEL:
  255. case NET_PINLABEL:
  256. case NET_BUSLABELMEMBER:
  257. case NET_GLOBBUSLABELMEMBER:
  258. labelConnect( GetItem( ii ) );
  259. break;
  260. case NET_SHEETBUSLABELMEMBER:
  261. case NET_HIERLABEL:
  262. case NET_HIERBUSLABELMEMBER:
  263. break;
  264. case NET_ITEM_UNSPECIFIED:
  265. break;
  266. }
  267. }
  268. #if defined(NETLIST_DEBUG) && defined(DEBUG)
  269. std::cout << "\n\nafter sheet global\n\n";
  270. DumpNetTable();
  271. #endif
  272. // Connection between hierarchy sheets
  273. for( unsigned ii = 0; ii < size(); ii++ )
  274. {
  275. if( GetItem( ii )->m_Type == NET_SHEETLABEL
  276. || GetItem( ii )->m_Type == NET_SHEETBUSLABELMEMBER )
  277. sheetLabelConnect( GetItem( ii ) );
  278. }
  279. // Sort objects by NetCode
  280. SortListbyNetcode();
  281. #if defined(NETLIST_DEBUG) && defined(DEBUG)
  282. std::cout << "\n\nafter qsort()\n";
  283. DumpNetTable();
  284. #endif
  285. // Compress numbers of Netcode having consecutive values.
  286. int NetCode = 0;
  287. m_lastNetCode = 0;
  288. for( unsigned ii = 0; ii < size(); ii++ )
  289. {
  290. if( GetItem( ii )->GetNet() != m_lastNetCode )
  291. {
  292. NetCode++;
  293. m_lastNetCode = GetItem( ii )->GetNet();
  294. }
  295. GetItem( ii )->SetNet( NetCode );
  296. }
  297. // Set the minimal connection info:
  298. setUnconnectedFlag();
  299. // find the best label object to give the best net name to each net
  300. findBestNetNameForEachNet();
  301. return true;
  302. }
  303. // Helper function to give a priority to sort labels:
  304. // NET_PINLABEL, NET_GLOBBUSLABELMEMBER and NET_GLOBLABEL are global labels
  305. // and the priority is high
  306. static int getPriority( const NETLIST_OBJECT* Objet )
  307. {
  308. switch( Objet->m_Type )
  309. {
  310. case NET_PIN: return 1;
  311. case NET_LABEL: return 2;
  312. case NET_HIERLABEL: return 3;
  313. case NET_PINLABEL: return 4;
  314. case NET_GLOBBUSLABELMEMBER: return 5;
  315. case NET_GLOBLABEL: return 6;
  316. default: break;
  317. }
  318. return 0;
  319. }
  320. /* function evalLabelsPriority used by findBestNetNameForEachNet()
  321. * evalLabelsPriority calculates the priority of alabel1 and aLabel2
  322. * return true if alabel1 has a higher priority than aLabel2
  323. */
  324. static bool evalLabelsPriority( const NETLIST_OBJECT* aLabel1, const NETLIST_OBJECT* aLabel2 )
  325. {
  326. // Global labels have the highest prioriy.
  327. // For local labels: names are prefixed by their sheetpath
  328. // use name defined in the more top level hierarchical sheet
  329. // (i.e. shorter timestamp path because paths are /<timestamp1>/<timestamp2>/...
  330. // and timestamp = 8 letters.
  331. // Note: the final net name uses human sheetpath name, not timestamp sheetpath name
  332. // They are equivalent, but not for human readers.
  333. if( ! aLabel1->IsLabelGlobal() && ! aLabel2->IsLabelGlobal() )
  334. {
  335. if( aLabel1->m_SheetPath.Path().Length() != aLabel2->m_SheetPath.Path().Length() )
  336. return aLabel1->m_SheetPath.Path().Length() < aLabel2->m_SheetPath.Path().Length();
  337. }
  338. int priority1 = getPriority( aLabel1 );
  339. int priority2 = getPriority( aLabel2 );
  340. if( priority1 != priority2 )
  341. return priority1 > priority2;
  342. // Objects have here the same priority, therefore they have the same type.
  343. // for global labels, we select the best candidate by alphabetic order
  344. // because they have no sheetpath as prefix name
  345. // for other labels, we select them before by sheet deep order
  346. // because the actual name is /sheetpath/label
  347. // and for a given path length, by alphabetic order
  348. if( aLabel1->IsLabelGlobal() )
  349. return aLabel1->m_Label.Cmp( aLabel2->m_Label ) < 0;
  350. // Sheet paths have here the same length: use alphabetic label name order
  351. // For labels on sheets having an equivalent deep in hierarchy, use
  352. // alphabetic label name order:
  353. if( aLabel1->m_Label.Cmp( aLabel2->m_Label ) != 0 )
  354. return aLabel1->m_Label.Cmp( aLabel2->m_Label ) < 0;
  355. // For identical labels having the same priority: choose the
  356. // alphabetic label full name order
  357. return aLabel1->m_SheetPath.PathHumanReadable().Cmp(
  358. aLabel2->m_SheetPath.PathHumanReadable() ) < 0;
  359. }
  360. void NETLIST_OBJECT_LIST::findBestNetNameForEachNet()
  361. {
  362. // Important note: NET_SHEETLABEL items of sheet items should *NOT* be considered,
  363. // because they live in a sheet but their names are actually used in the subsheet.
  364. // Moreover, in the parent sheet, the name of NET_SHEETLABEL can be not unique,
  365. // ( for instance when 2 different sheets share the same schematic in complex hierarchies
  366. // and 2 identical NET_SHEETLABEL labels can be connected to 2 different nets
  367. int netcode = 0; // current netcode for tested items
  368. unsigned idxstart = 0; // index of the first item of this net
  369. NETLIST_OBJECT* item;
  370. NETLIST_OBJECT* candidate;
  371. // Pass 1: find the best name for labelled nets:
  372. candidate = NULL;
  373. for( unsigned ii = 0; ii <= size(); ii++ )
  374. {
  375. if( ii == size() ) // last item already tested
  376. item = NULL;
  377. else
  378. item = GetItem( ii );
  379. if( !item || netcode != item->GetNet() ) // End of net found
  380. {
  381. if( candidate ) // One or more labels exists, find the best
  382. {
  383. for (unsigned jj = idxstart; jj < ii; jj++ )
  384. GetItem( jj )->SetNetNameCandidate( candidate );
  385. }
  386. if( item == NULL ) // End of list
  387. break;
  388. // Prepare next net analysis:
  389. netcode = item->GetNet();
  390. candidate = NULL;
  391. idxstart = ii;
  392. }
  393. switch( item->m_Type )
  394. {
  395. case NET_HIERLABEL:
  396. case NET_LABEL:
  397. case NET_PINLABEL:
  398. case NET_GLOBLABEL:
  399. case NET_GLOBBUSLABELMEMBER:
  400. // A candidate is found: select the better between the previous
  401. // and this one
  402. if( candidate == NULL )
  403. candidate = item;
  404. else
  405. {
  406. if( evalLabelsPriority( item, candidate ) )
  407. // item has a highter priority than candidate
  408. // so update the best candidate
  409. candidate = item;
  410. }
  411. break;
  412. default:
  413. break;
  414. }
  415. }
  416. // Pass 2: find the best name for not labelled nets:
  417. // The "default" net name is Net-<<Ref cmp>_Pad<num pad>>
  418. // (see NETLIST_OBJECT::GetShortNetName())
  419. // therefore the "best" is the short net name alphabetically classed first
  420. // (to avoid net names changes when the net is not modified,
  421. // even if components are moved or deleted and undelete or replaced, as long
  422. // the reference is kept)
  423. // Build a list of items with no net names
  424. NETLIST_OBJECTS list; // no ownership of elements being pointed at
  425. for( unsigned ii = 0; ii < size(); ii++ )
  426. {
  427. item = GetItem( ii );
  428. if( !item->HasNetNameCandidate() )
  429. list.push_back( item );
  430. }
  431. if( list.size() == 0 )
  432. return;
  433. idxstart = 0;
  434. candidate = NULL;
  435. netcode = list[0]->GetNet();
  436. for( unsigned ii = 0; ii <= list.size(); ii++ )
  437. {
  438. if( ii < list.size() )
  439. item = list[ii];
  440. else
  441. item = NULL;
  442. if( !item || netcode != item->GetNet() ) // End of net found
  443. {
  444. if( candidate )
  445. {
  446. for (unsigned jj = idxstart; jj < ii; jj++ )
  447. {
  448. NETLIST_OBJECT* obj = list[jj];
  449. obj->SetNetNameCandidate( candidate );
  450. }
  451. }
  452. if( !item )
  453. break;
  454. netcode = item->GetNet();
  455. candidate = NULL;
  456. idxstart = ii;
  457. }
  458. // Examine all pins of the net to find the best candidate,
  459. // i.e. the first net name candidate, by alphabetic order
  460. // the net names are built by GetShortNetName
  461. // (Net-<{reference}-Pad{pad number}> like Net-<U3-Pad5>
  462. // Not named nets do not have usually a lot of members.
  463. // Many have only 2 members(a pad and a non connection symbol)
  464. if( item->m_Type == NET_PIN )
  465. {
  466. // A candidate is found, however components which are not in
  467. // netlist are not candidate because some have their reference
  468. // changed each time the netlist is built (power components)
  469. // and anyway obviously they are not a good candidate
  470. SCH_COMPONENT* link = item->GetComponentParent();
  471. if( link && link->IsInNetlist() )
  472. {
  473. // select the better between the previous and this one
  474. item->SetNetNameCandidate( item ); // Needed to calculate GetShortNetName
  475. if( candidate == NULL )
  476. candidate = item;
  477. else
  478. {
  479. if( item->GetShortNetName().Cmp( candidate->GetShortNetName() ) < 0 )
  480. candidate = item;
  481. }
  482. }
  483. }
  484. }
  485. }
  486. void NETLIST_OBJECT_LIST::sheetLabelConnect( NETLIST_OBJECT* SheetLabel )
  487. {
  488. if( SheetLabel->GetNet() == 0 )
  489. return;
  490. for( unsigned ii = 0; ii < size(); ii++ )
  491. {
  492. NETLIST_OBJECT* ObjetNet = GetItem( ii );
  493. if( ObjetNet->m_SheetPath != SheetLabel->m_SheetPathInclude )
  494. continue; //use SheetInclude, not the sheet!!
  495. if( (ObjetNet->m_Type != NET_HIERLABEL ) && (ObjetNet->m_Type != NET_HIERBUSLABELMEMBER ) )
  496. continue;
  497. if( ObjetNet->GetNet() == SheetLabel->GetNet() )
  498. continue; //already connected.
  499. if( ObjetNet->m_Label != SheetLabel->m_Label )
  500. continue; //different names.
  501. // Propagate Netcode having all the objects of the same Netcode.
  502. if( ObjetNet->GetNet() )
  503. propagateNetCode( ObjetNet->GetNet(), SheetLabel->GetNet(), IS_WIRE );
  504. else
  505. ObjetNet->SetNet( SheetLabel->GetNet() );
  506. }
  507. }
  508. void NETLIST_OBJECT_LIST::connectBusLabels()
  509. {
  510. // Propagate the net code between all bus label member objects connected by they name.
  511. // If the net code is not yet existing, a new one is created
  512. // Search is done in the entire list
  513. for( unsigned ii = 0; ii < size(); ii++ )
  514. {
  515. NETLIST_OBJECT* Label = GetItem( ii );
  516. if( Label->IsLabelBusMemberType() )
  517. {
  518. if( Label->GetNet() == 0 )
  519. {
  520. // Not yet existiing net code: create a new one.
  521. Label->SetNet( m_lastNetCode );
  522. m_lastNetCode++;
  523. }
  524. for( unsigned jj = ii + 1; jj < size(); jj++ )
  525. {
  526. NETLIST_OBJECT* LabelInTst = GetItem( jj );
  527. if( LabelInTst->IsLabelBusMemberType() )
  528. {
  529. if( LabelInTst->m_BusNetCode != Label->m_BusNetCode )
  530. continue;
  531. if( LabelInTst->m_Member != Label->m_Member )
  532. continue;
  533. if( LabelInTst->GetNet() == 0 )
  534. // Append this object to the current net
  535. LabelInTst->SetNet( Label->GetNet() );
  536. else
  537. // Merge the 2 net codes, they are connected.
  538. propagateNetCode( LabelInTst->GetNet(), Label->GetNet(), IS_WIRE );
  539. }
  540. }
  541. }
  542. }
  543. }
  544. void NETLIST_OBJECT_LIST::propagateNetCode( int aOldNetCode, int aNewNetCode, bool aIsBus )
  545. {
  546. if( aOldNetCode == aNewNetCode )
  547. return;
  548. if( aIsBus == false ) // Propagate NetCode
  549. {
  550. for( unsigned jj = 0; jj < size(); jj++ )
  551. {
  552. NETLIST_OBJECT* object = GetItem( jj );
  553. if( object->GetNet() == aOldNetCode )
  554. object->SetNet( aNewNetCode );
  555. }
  556. }
  557. else // Propagate BusNetCode
  558. {
  559. for( unsigned jj = 0; jj < size(); jj++ )
  560. {
  561. NETLIST_OBJECT* object = GetItem( jj );
  562. if( object->m_BusNetCode == aOldNetCode )
  563. object->m_BusNetCode = aNewNetCode;
  564. }
  565. }
  566. }
  567. void NETLIST_OBJECT_LIST::pointToPointConnect( NETLIST_OBJECT* aRef, bool aIsBus, int start )
  568. {
  569. int netCode;
  570. if( aIsBus == false ) // Objects other than BUS and BUSLABELS
  571. {
  572. netCode = aRef->GetNet();
  573. for( unsigned i = start; i < size(); i++ )
  574. {
  575. NETLIST_OBJECT* item = GetItem( i );
  576. if( item->m_SheetPath != aRef->m_SheetPath ) //used to be > (why?)
  577. continue;
  578. switch( item->m_Type )
  579. {
  580. case NET_SEGMENT:
  581. case NET_PIN:
  582. case NET_LABEL:
  583. case NET_HIERLABEL:
  584. case NET_GLOBLABEL:
  585. case NET_SHEETLABEL:
  586. case NET_PINLABEL:
  587. case NET_JUNCTION:
  588. case NET_NOCONNECT:
  589. if( aRef->m_Start == item->m_Start
  590. || aRef->m_Start == item->m_End
  591. || aRef->m_End == item->m_Start
  592. || aRef->m_End == item->m_End )
  593. {
  594. if( item->GetNet() == 0 )
  595. item->SetNet( netCode );
  596. else
  597. propagateNetCode( item->GetNet(), netCode, IS_WIRE );
  598. }
  599. break;
  600. case NET_BUS:
  601. case NET_BUSLABELMEMBER:
  602. case NET_SHEETBUSLABELMEMBER:
  603. case NET_HIERBUSLABELMEMBER:
  604. case NET_GLOBBUSLABELMEMBER:
  605. case NET_ITEM_UNSPECIFIED:
  606. break;
  607. }
  608. }
  609. }
  610. else // Object type BUS, BUSLABELS, and junctions.
  611. {
  612. netCode = aRef->m_BusNetCode;
  613. for( unsigned i = start; i < size(); i++ )
  614. {
  615. NETLIST_OBJECT* item = GetItem( i );
  616. if( item->m_SheetPath != aRef->m_SheetPath )
  617. continue;
  618. switch( item->m_Type )
  619. {
  620. case NET_ITEM_UNSPECIFIED:
  621. case NET_SEGMENT:
  622. case NET_PIN:
  623. case NET_LABEL:
  624. case NET_HIERLABEL:
  625. case NET_GLOBLABEL:
  626. case NET_SHEETLABEL:
  627. case NET_PINLABEL:
  628. case NET_NOCONNECT:
  629. break;
  630. case NET_BUS:
  631. case NET_BUSLABELMEMBER:
  632. case NET_SHEETBUSLABELMEMBER:
  633. case NET_HIERBUSLABELMEMBER:
  634. case NET_GLOBBUSLABELMEMBER:
  635. case NET_JUNCTION:
  636. if( aRef->m_Start == item->m_Start
  637. || aRef->m_Start == item->m_End
  638. || aRef->m_End == item->m_Start
  639. || aRef->m_End == item->m_End )
  640. {
  641. if( item->m_BusNetCode == 0 )
  642. item->m_BusNetCode = netCode;
  643. else
  644. propagateNetCode( item->m_BusNetCode, netCode, IS_BUS );
  645. }
  646. break;
  647. }
  648. }
  649. }
  650. }
  651. void NETLIST_OBJECT_LIST::segmentToPointConnect( NETLIST_OBJECT* aJonction,
  652. bool aIsBus, int aIdxStart )
  653. {
  654. for( unsigned i = aIdxStart; i < size(); i++ )
  655. {
  656. NETLIST_OBJECT* segment = GetItem( i );
  657. // if different sheets, obviously no physical connection between elements.
  658. if( segment->m_SheetPath != aJonction->m_SheetPath )
  659. continue;
  660. if( aIsBus == IS_WIRE )
  661. {
  662. if( segment->m_Type != NET_SEGMENT )
  663. continue;
  664. }
  665. else
  666. {
  667. if( segment->m_Type != NET_BUS )
  668. continue;
  669. }
  670. if( IsPointOnSegment( segment->m_Start, segment->m_End, aJonction->m_Start ) )
  671. {
  672. // Propagation Netcode has all the objects of the same Netcode.
  673. if( aIsBus == IS_WIRE )
  674. {
  675. if( segment->GetNet() )
  676. propagateNetCode( segment->GetNet(), aJonction->GetNet(), aIsBus );
  677. else
  678. segment->SetNet( aJonction->GetNet() );
  679. }
  680. else
  681. {
  682. if( segment->m_BusNetCode )
  683. propagateNetCode( segment->m_BusNetCode, aJonction->m_BusNetCode, aIsBus );
  684. else
  685. segment->m_BusNetCode = aJonction->m_BusNetCode;
  686. }
  687. }
  688. }
  689. }
  690. void NETLIST_OBJECT_LIST::labelConnect( NETLIST_OBJECT* aLabelRef )
  691. {
  692. if( aLabelRef->GetNet() == 0 )
  693. return;
  694. for( unsigned i = 0; i < size(); i++ )
  695. {
  696. NETLIST_OBJECT* item = GetItem( i );
  697. if( item->GetNet() == aLabelRef->GetNet() )
  698. continue;
  699. if( item->m_SheetPath != aLabelRef->m_SheetPath )
  700. {
  701. if( item->m_Type != NET_PINLABEL && item->m_Type != NET_GLOBLABEL
  702. && item->m_Type != NET_GLOBBUSLABELMEMBER )
  703. continue;
  704. if( (item->m_Type == NET_GLOBLABEL
  705. || item->m_Type == NET_GLOBBUSLABELMEMBER)
  706. && item->m_Type != aLabelRef->m_Type )
  707. //global labels only connect other global labels.
  708. continue;
  709. }
  710. // NET_HIERLABEL are used to connect sheets.
  711. // NET_LABEL are local to a sheet
  712. // NET_GLOBLABEL are global.
  713. // NET_PINLABEL is a kind of global label (generated by a power pin invisible)
  714. if( item->IsLabelType() )
  715. {
  716. if( item->m_Label != aLabelRef->m_Label )
  717. continue;
  718. if( item->GetNet() )
  719. propagateNetCode( item->GetNet(), aLabelRef->GetNet(), IS_WIRE );
  720. else
  721. item->SetNet( aLabelRef->GetNet() );
  722. }
  723. }
  724. }
  725. void NETLIST_OBJECT_LIST::setUnconnectedFlag()
  726. {
  727. NETLIST_OBJECT* NetItemRef;
  728. unsigned NetStart, NetEnd;
  729. NET_CONNECTION_T StateFlag;
  730. NetStart = NetEnd = 0;
  731. StateFlag = UNCONNECTED;
  732. for( unsigned ii = 0; ii < size(); ii++ )
  733. {
  734. NetItemRef = GetItem( ii );
  735. if( NetItemRef->m_Type == NET_NOCONNECT && StateFlag != PAD_CONNECT )
  736. StateFlag = NOCONNECT_SYMBOL_PRESENT;
  737. // Analysis of current net.
  738. unsigned idxtoTest = ii + 1;
  739. if( ( idxtoTest >= size() )
  740. || ( NetItemRef->GetNet() != GetItem( idxtoTest )->GetNet() ) )
  741. {
  742. // Net analysis to update m_ConnectionType
  743. NetEnd = idxtoTest;
  744. /* set m_ConnectionType member to StateFlag for all items of
  745. * this net: */
  746. for( unsigned kk = NetStart; kk < NetEnd; kk++ )
  747. GetItem( kk )->m_ConnectionType = StateFlag;
  748. if( idxtoTest >= size() )
  749. return;
  750. // Start Analysis next Net
  751. StateFlag = UNCONNECTED;
  752. NetStart = idxtoTest;
  753. continue;
  754. }
  755. /* test the current item: if this is a pin and if the reference item
  756. * is also a pin, then 2 pins are connected, so set StateFlag to
  757. * PAD_CONNECT (can be already done) Of course, if the current
  758. * item is a no connect symbol, set StateFlag to
  759. * NOCONNECT_SYMBOL_PRESENT to inhibit error diags. However if
  760. * StateFlag is already set to PAD_CONNECT this state is kept (the
  761. * no connect symbol was surely an error and an ERC will report this)
  762. */
  763. for( ; ; idxtoTest++ )
  764. {
  765. if( ( idxtoTest >= size() )
  766. || ( NetItemRef->GetNet() != GetItem( idxtoTest )->GetNet() ) )
  767. break;
  768. switch( GetItem( idxtoTest )->m_Type )
  769. {
  770. case NET_ITEM_UNSPECIFIED:
  771. wxMessageBox( wxT( "BuildNetListBase() error" ) );
  772. break;
  773. case NET_SEGMENT:
  774. case NET_LABEL:
  775. case NET_HIERLABEL:
  776. case NET_GLOBLABEL:
  777. case NET_SHEETLABEL:
  778. case NET_PINLABEL:
  779. case NET_BUS:
  780. case NET_BUSLABELMEMBER:
  781. case NET_SHEETBUSLABELMEMBER:
  782. case NET_HIERBUSLABELMEMBER:
  783. case NET_GLOBBUSLABELMEMBER:
  784. case NET_JUNCTION:
  785. break;
  786. case NET_PIN:
  787. if( NetItemRef->m_Type == NET_PIN )
  788. StateFlag = PAD_CONNECT;
  789. break;
  790. case NET_NOCONNECT:
  791. if( StateFlag != PAD_CONNECT )
  792. StateFlag = NOCONNECT_SYMBOL_PRESENT;
  793. break;
  794. }
  795. }
  796. }
  797. }