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.

568 lines
20 KiB

18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
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) 2009 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com
  5. * Copyright (C) 2011 Wayne Stambaugh <stambaughw@verizon.net>
  6. * Copyright (C) 1992-2011 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 erc.cpp
  27. * @brief Electrical Rules Check implementation.
  28. */
  29. #include <fctsys.h>
  30. #include <class_drawpanel.h>
  31. #include <kicad_string.h>
  32. #include <wxEeschemaStruct.h>
  33. #include <netlist.h>
  34. #include <class_netlist_object.h>
  35. #include <lib_pin.h>
  36. #include <erc.h>
  37. #include <sch_marker.h>
  38. #include <sch_component.h>
  39. #include <sch_sheet.h>
  40. /* ERC tests :
  41. * 1 - conflicts between connected pins ( example: 2 connected outputs )
  42. * 2 - minimal connections requirements ( 1 input *must* be connected to an
  43. * output, or a passive pin )
  44. */
  45. /*
  46. * Electrical type of pins:
  47. * PIN_INPUT = usual pin input: must be connected
  48. * PIN_OUTPUT = usual output
  49. * PIN_BIDI = input or output (like port for a microprocessor)
  50. * PIN_TRISTATE = tris state bus pin
  51. * PIN_PASSIVE = pin for passive components: must be connected, and can be
  52. * connected to any pin
  53. * PIN_UNSPECIFIED = unknown electrical properties: creates always a warning
  54. * when connected
  55. * PIN_POWER_IN = power input (GND, VCC for ICs). Must be connected to a power
  56. * output.
  57. * PIN_POWER_OUT = output of a regulator: intended to be connected to power
  58. * input pins
  59. * PIN_OPENCOLLECTOR = pin type open collector
  60. * PIN_OPENEMITTER = pin type open emitter
  61. * PIN_NC = not connected (must be left open)
  62. *
  63. * Minimal requirements:
  64. * All pins *must* be connected (except PIN_NC).
  65. * When a pin is not connected in schematic, the user must place a "non
  66. * connected" symbol to this pin.
  67. * This ensures a forgotten connection will be detected.
  68. */
  69. /* Messages for conflicts :
  70. * PIN_INPUT, PIN_OUTPUT, PIN_BIDI, PIN_TRISTATE, PIN_PASSIVE,
  71. * PIN_UNSPECIFIED, PIN_POWER_IN, PIN_POWER_OUT, PIN_OPENCOLLECTOR,
  72. * PIN_OPENEMITTER, PIN_NC
  73. * These messages are used to show the ERC matrix in ERC dialog
  74. */
  75. // Messages for matrix rows:
  76. const wxString CommentERC_H[] =
  77. {
  78. _( "Input Pin.........." ),
  79. _( "Output Pin........." ),
  80. _( "Bidirectional Pin.." ),
  81. _( "Tri-State Pin......" ),
  82. _( "Passive Pin........" ),
  83. _( "Unspecified Pin...." ),
  84. _( "Power Input Pin...." ),
  85. _( "Power Output Pin..." ),
  86. _( "Open Collector....." ),
  87. _( "Open Emitter......." ),
  88. _( "No Connection......" )
  89. };
  90. // Messages for matrix columns
  91. const wxString CommentERC_V[] =
  92. {
  93. _( "Input Pin" ),
  94. _( "Output Pin" ),
  95. _( "Bidirectional Pin" ),
  96. _( "Tri-State Pin" ),
  97. _( "Passive Pin" ),
  98. _( "Unspecified Pin" ),
  99. _( "Power Input Pin" ),
  100. _( "Power Output Pin" ),
  101. _( "Open Collector" ),
  102. _( "Open Emitter" ),
  103. _( "No Connection" )
  104. };
  105. /* Look up table which gives the diag for a pair of connected pins
  106. * Can be modified by ERC options.
  107. * at start up: must be loaded by DefaultDiagErc
  108. */
  109. int DiagErc[PIN_NMAX][PIN_NMAX];
  110. bool DiagErcTableInit; // go to true after DiagErc init
  111. /**
  112. * Default Look up table which gives the ERC error level for a pair of connected pins
  113. * Same as DiagErc, but cannot be modified.
  114. * Used to init or reset DiagErc
  115. * note also, to avoid inconsistancy:
  116. * DefaultDiagErc[i][j] = DefaultDiagErc[j][i]
  117. */
  118. int DefaultDiagErc[PIN_NMAX][PIN_NMAX] =
  119. {
  120. /* I, O, Bi, 3S, Pas, UnS, PwrI, PwrO, OC, OE, NC */
  121. /* I */ { OK, OK, OK, OK, OK, WAR, OK, OK, OK, OK, ERR },
  122. /* O */ { OK, ERR, OK, WAR, OK, WAR, OK, ERR, ERR, ERR, ERR },
  123. /* Bi*/ { OK, OK, OK, OK, OK, WAR, OK, WAR, OK, WAR, ERR },
  124. /* 3S*/ { OK, WAR, OK, OK, OK, WAR, WAR, ERR, WAR, WAR, ERR },
  125. /*Pas*/ { OK, OK, OK, OK, OK, WAR, OK, OK, OK, OK, ERR },
  126. /*UnS */ { WAR, WAR, WAR, WAR, WAR, WAR, WAR, WAR, WAR, WAR, ERR },
  127. /*PwrI*/ { OK, OK, OK, WAR, OK, WAR, OK, OK, OK, OK, ERR },
  128. /*PwrO*/ { OK, ERR, WAR, ERR, OK, WAR, OK, ERR, ERR, ERR, ERR },
  129. /* OC */ { OK, ERR, OK, WAR, OK, WAR, OK, ERR, OK, OK, ERR },
  130. /* OE */ { OK, ERR, WAR, WAR, OK, WAR, OK, ERR, OK, OK, ERR },
  131. /* NC */ { ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR }
  132. };
  133. /**
  134. * Look up table which gives the minimal drive for a pair of connected pins on
  135. * a net.
  136. * <p>
  137. * The initial state of a net is NOC (Net with No Connection). It can be updated to
  138. * NPI (Pin Isolated), NET_NC (Net with a no connect symbol), NOD (Not Driven) or DRV
  139. * (DRIven). It can be updated to NET_NC with no error only if there is only one pin
  140. * in net. Nets are OK when their final state is NET_NC or DRV. Nets with the state
  141. * NOD have no valid source signal.
  142. */
  143. static int MinimalReq[PIN_NMAX][PIN_NMAX] =
  144. {
  145. /* In Out, Bi, 3S, Pas, UnS, PwrI,PwrO,OC, OE, NC */
  146. /* In*/ { NOD, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NPI },
  147. /*Out*/ { DRV, DRV, DRV, DRV, DRV, DRV, DRV, DRV, DRV, DRV, NPI },
  148. /* Bi*/ { DRV, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NPI },
  149. /* 3S*/ { DRV, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NPI },
  150. /*Pas*/ { DRV, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NPI },
  151. /*UnS*/ { DRV, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NPI },
  152. /*PwrI*/ { NOD, DRV, NOD, NOD, NOD, NOD, NOD, DRV, NOD, NOD, NPI },
  153. /*PwrO*/ { DRV, DRV, DRV, DRV, DRV, DRV, DRV, DRV, DRV, DRV, NPI },
  154. /* OC*/ { DRV, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NPI },
  155. /* OE*/ { DRV, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NPI },
  156. /* NC*/ { NPI, NPI, NPI, NPI, NPI, NPI, NPI, NPI, NPI, NPI, NPI }
  157. };
  158. int TestDuplicateSheetNames( bool aCreateMarker )
  159. {
  160. SCH_SCREEN* screen;
  161. SCH_ITEM* item;
  162. SCH_ITEM* test_item;
  163. int err_count = 0;
  164. SCH_SCREENS screenList; // Created the list of screen
  165. for( screen = screenList.GetFirst(); screen != NULL; screen = screenList.GetNext() )
  166. {
  167. for( item = screen->GetDrawItems(); item != NULL; item = item->Next() )
  168. {
  169. // search for a sheet;
  170. if( item->Type() != SCH_SHEET_T )
  171. continue;
  172. for( test_item = item->Next(); test_item != NULL; test_item = test_item->Next() )
  173. {
  174. if( test_item->Type() != SCH_SHEET_T )
  175. continue;
  176. // We have found a second sheet: compare names
  177. if( ( (SCH_SHEET*) item )->GetName().CmpNoCase(
  178. ( ( SCH_SHEET* ) test_item )->GetName() ) == 0 )
  179. {
  180. if( aCreateMarker )
  181. {
  182. /* Create a new marker type ERC error*/
  183. SCH_MARKER* marker = new SCH_MARKER();
  184. marker->SetTimeStamp( GetNewTimeStamp() );
  185. marker->SetData( ERCE_DUPLICATE_SHEET_NAME,
  186. ( (SCH_SHEET*) test_item )->GetPosition(),
  187. _( "Duplicate sheet name" ),
  188. ( (SCH_SHEET*) test_item )->GetPosition() );
  189. marker->SetMarkerType( MARK_ERC );
  190. marker->SetErrorLevel( ERR );
  191. screen->Append( marker );
  192. }
  193. err_count++;
  194. }
  195. }
  196. }
  197. }
  198. return err_count;
  199. }
  200. void Diagnose( NETLIST_OBJECT* aNetItemRef, NETLIST_OBJECT* aNetItemTst,
  201. int aMinConn, int aDiag )
  202. {
  203. SCH_MARKER* marker = NULL;
  204. SCH_SCREEN* screen;
  205. int ii, jj;
  206. if( aDiag == OK )
  207. return;
  208. /* Create new marker for ERC error. */
  209. marker = new SCH_MARKER();
  210. marker->SetTimeStamp( GetNewTimeStamp() );
  211. marker->SetMarkerType( MARK_ERC );
  212. marker->SetErrorLevel( WAR );
  213. screen = aNetItemRef->m_SheetPath.LastScreen();
  214. screen->Append( marker );
  215. wxString msg;
  216. if( aMinConn < 0 )
  217. {
  218. if( (aNetItemRef->m_Type == NET_HIERLABEL)
  219. || (aNetItemRef->m_Type == NET_HIERBUSLABELMEMBER) )
  220. {
  221. msg.Printf( _( "Hierarchical label %s is not connected to a sheet label." ),
  222. GetChars( aNetItemRef->m_Label ) );
  223. }
  224. else
  225. {
  226. msg.Printf( _( "Sheet label %s is not connected to a hierarchical label." ),
  227. GetChars( aNetItemRef->m_Label ) );
  228. }
  229. marker->SetData( ERCE_HIERACHICAL_LABEL,
  230. aNetItemRef->m_Start,
  231. msg,
  232. aNetItemRef->m_Start );
  233. return;
  234. }
  235. ii = aNetItemRef->m_ElectricalType;
  236. wxString string_pinnum, cmp_ref;
  237. char ascii_buf[5];
  238. ascii_buf[4] = 0;
  239. memcpy( ascii_buf, &aNetItemRef->m_PinNum, 4 );
  240. string_pinnum = FROM_UTF8( ascii_buf );
  241. cmp_ref = wxT( "?" );
  242. if( aNetItemRef->m_Type == NET_PIN && aNetItemRef->m_Link )
  243. cmp_ref = aNetItemRef->GetComponentParent()->GetRef( &aNetItemRef->m_SheetPath );
  244. if( aNetItemTst == NULL )
  245. {
  246. if( aMinConn == NOC ) /* Only 1 element in the net. */
  247. {
  248. msg.Printf( _( "Pin %s (%s) of component %s is unconnected." ),
  249. GetChars( string_pinnum ), MsgPinElectricType[ii], GetChars( cmp_ref ) );
  250. marker->SetData( ERCE_PIN_NOT_CONNECTED,
  251. aNetItemRef->m_Start,
  252. msg,
  253. aNetItemRef->m_Start );
  254. return;
  255. }
  256. if( aMinConn == NOD ) /* Nothing driving the net. */
  257. {
  258. if( aNetItemRef->m_Type == NET_PIN && aNetItemRef->m_Link )
  259. cmp_ref = aNetItemRef->GetComponentParent()->GetRef(
  260. &aNetItemRef->m_SheetPath );
  261. msg.Printf( _( "Pin %s (%s) of component %s is not driven (Net %d)." ),
  262. GetChars( string_pinnum ), MsgPinElectricType[ii], GetChars( cmp_ref ),
  263. aNetItemRef->GetNet() );
  264. marker->SetData( ERCE_PIN_NOT_DRIVEN,
  265. aNetItemRef->m_Start,
  266. msg,
  267. aNetItemRef->m_Start );
  268. return;
  269. }
  270. if( aDiag == UNC )
  271. {
  272. msg.Printf( _( "More than 1 pin connected to an UnConnect symbol." ) );
  273. marker->SetData( ERCE_NOCONNECT_CONNECTED,
  274. aNetItemRef->m_Start,
  275. msg,
  276. aNetItemRef->m_Start );
  277. return;
  278. }
  279. }
  280. if( aNetItemTst ) /* Error between 2 pins */
  281. {
  282. jj = aNetItemTst->m_ElectricalType;
  283. int errortype = ERCE_PIN_TO_PIN_WARNING;
  284. if( aDiag == ERR )
  285. {
  286. marker->SetErrorLevel( ERR );
  287. errortype = ERCE_PIN_TO_PIN_ERROR;
  288. }
  289. wxString alt_string_pinnum, alt_cmp;
  290. memcpy( ascii_buf, &aNetItemTst->m_PinNum, 4 );
  291. alt_string_pinnum = FROM_UTF8( ascii_buf );
  292. alt_cmp = wxT( "?" );
  293. if( aNetItemTst->m_Type == NET_PIN && aNetItemTst->m_Link )
  294. alt_cmp = aNetItemTst->GetComponentParent()->GetRef( &aNetItemTst->m_SheetPath );
  295. msg.Printf( _( "Pin %s (%s) of component %s is connected to " ),
  296. GetChars( string_pinnum ), MsgPinElectricType[ii], GetChars( cmp_ref ) );
  297. marker->SetData( errortype, aNetItemRef->m_Start, msg, aNetItemRef->m_Start );
  298. msg.Printf( _( "pin %s (%s) of component %s (net %d)." ),
  299. GetChars( alt_string_pinnum ), MsgPinElectricType[jj], GetChars( alt_cmp ),
  300. aNetItemRef->GetNet() );
  301. marker->SetAuxiliaryData( msg, aNetItemTst->m_Start );
  302. }
  303. }
  304. void TestOthersItems( NETLIST_OBJECT_LIST* aList,
  305. unsigned aNetItemRef, unsigned aNetStart,
  306. int* aNetNbItems, int* aMinConnexion )
  307. {
  308. unsigned netItemTst = aNetStart;
  309. int jj;
  310. int erc = OK;
  311. /* Analysis of the table of connections. */
  312. int ref_elect_type = aList->GetItem( aNetItemRef )->m_ElectricalType;
  313. int local_minconn = NOC;
  314. if( ref_elect_type == PIN_NC )
  315. local_minconn = NPI;
  316. /* Test pins connected to NetItemRef */
  317. for( ; ; netItemTst++ )
  318. {
  319. if( aNetItemRef == netItemTst )
  320. continue;
  321. // We examine only a given net. We stop the search if the net changes
  322. if( ( netItemTst >= aList->size() ) // End of list
  323. || ( aList->GetItemNet( aNetItemRef ) !=
  324. aList->GetItemNet( netItemTst ) ) ) // End of net
  325. {
  326. /* End net code found: minimum connection test. */
  327. if( ( *aMinConnexion < NET_NC ) && ( local_minconn < NET_NC ) )
  328. {
  329. /* Not connected or not driven pin. */
  330. bool seterr = true;
  331. if( local_minconn == NOC &&
  332. aList->GetItemType( aNetItemRef ) == NET_PIN )
  333. {
  334. /* This pin is not connected: for multiple part per
  335. * package, and duplicated pin,
  336. * search for an other instance of this pin
  337. * this will be flagged only if all instances of this pin
  338. * are not connected
  339. * TODO test also if instances connected are connected to
  340. * the same net
  341. */
  342. for( unsigned duplicate = 0; duplicate < aList->size(); duplicate++ )
  343. {
  344. if( aList->GetItemType( duplicate ) != NET_PIN )
  345. continue;
  346. if( duplicate == aNetItemRef )
  347. continue;
  348. if( aList->GetItem( aNetItemRef )->m_PinNum !=
  349. aList->GetItem( duplicate )->m_PinNum )
  350. continue;
  351. if( ( (SCH_COMPONENT*) aList->GetItem( aNetItemRef )->
  352. m_Link )->GetRef( &aList->GetItem( aNetItemRef )-> m_SheetPath ) !=
  353. ( (SCH_COMPONENT*) aList->GetItem( duplicate )->m_Link )
  354. ->GetRef( &aList->GetItem( duplicate )->m_SheetPath ) )
  355. continue;
  356. // Same component and same pin. Do dot create error for this pin
  357. // if the other pin is connected (i.e. if duplicate net has an other
  358. // item)
  359. if( (duplicate > 0)
  360. && ( aList->GetItemNet( duplicate ) ==
  361. aList->GetItemNet( duplicate - 1 ) ) )
  362. seterr = false;
  363. if( (duplicate < aList->size() - 1)
  364. && ( aList->GetItemNet( duplicate ) ==
  365. aList->GetItemNet( duplicate + 1 ) ) )
  366. seterr = false;
  367. }
  368. }
  369. if( seterr )
  370. Diagnose( aList->GetItem( aNetItemRef ), NULL, local_minconn, WAR );
  371. *aMinConnexion = DRV; // inhibiting other messages of this
  372. // type for the net.
  373. }
  374. return;
  375. }
  376. switch( aList->GetItemType( netItemTst ) )
  377. {
  378. case NET_ITEM_UNSPECIFIED:
  379. case NET_SEGMENT:
  380. case NET_BUS:
  381. case NET_JUNCTION:
  382. case NET_LABEL:
  383. case NET_HIERLABEL:
  384. case NET_BUSLABELMEMBER:
  385. case NET_HIERBUSLABELMEMBER:
  386. case NET_SHEETBUSLABELMEMBER:
  387. case NET_SHEETLABEL:
  388. case NET_GLOBLABEL:
  389. case NET_GLOBBUSLABELMEMBER:
  390. case NET_PINLABEL:
  391. break;
  392. case NET_NOCONNECT:
  393. local_minconn = std::max( NET_NC, local_minconn );
  394. break;
  395. case NET_PIN:
  396. jj = aList->GetItem( netItemTst )->m_ElectricalType;
  397. local_minconn = std::max( MinimalReq[ref_elect_type][jj], local_minconn );
  398. if( netItemTst <= aNetItemRef )
  399. break;
  400. *aNetNbItems += 1;
  401. if( erc == OK )
  402. {
  403. erc = DiagErc[ref_elect_type][jj];
  404. if( erc != OK )
  405. {
  406. if( aList->GetConnectionType( netItemTst ) == UNCONNECTED )
  407. {
  408. Diagnose( aList->GetItem( aNetItemRef ),
  409. aList->GetItem( netItemTst ),
  410. 0, erc );
  411. aList->SetConnectionType( netItemTst, NOCONNECT_SYMBOL_PRESENT );
  412. }
  413. }
  414. }
  415. break;
  416. }
  417. }
  418. }
  419. bool WriteDiagnosticERC( const wxString& aFullFileName )
  420. {
  421. SCH_ITEM* item;
  422. SCH_MARKER* marker;
  423. static FILE* file;
  424. SCH_SHEET_PATH* sheet;
  425. wxString msg;
  426. int count = 0;
  427. if( ( file = wxFopen( aFullFileName, wxT( "wt" ) ) ) == NULL )
  428. return false;
  429. msg = _( "ERC report" );
  430. fprintf( file, "%s (%s)\n", TO_UTF8( msg ), TO_UTF8( DateAndTime() ) );
  431. SCH_SHEET_LIST sheetList;
  432. for( sheet = sheetList.GetFirst(); sheet != NULL; sheet = sheetList.GetNext() )
  433. {
  434. msg.Printf( _( "\n***** Sheet %s\n" ), GetChars( sheet->PathHumanReadable() ) );
  435. fprintf( file, "%s", TO_UTF8( msg ) );
  436. for( item = sheet->LastDrawList(); item != NULL; item = item->Next() )
  437. {
  438. if( item->Type() != SCH_MARKER_T )
  439. continue;
  440. marker = (SCH_MARKER*) item;
  441. if( marker->GetMarkerType() != MARK_ERC )
  442. continue;
  443. if( marker->GetMarkerType() == ERR )
  444. count++;
  445. msg = marker->GetReporter().ShowReport();
  446. fprintf( file, "%s", TO_UTF8( msg ) );
  447. }
  448. }
  449. msg.Printf( _( "\n >> Errors ERC: %d\n" ), count );
  450. fprintf( file, "%s", TO_UTF8( msg ) );
  451. fclose( file );
  452. return true;
  453. }
  454. void TestLabel( NETLIST_OBJECT_LIST* aList, unsigned aNetItemRef, unsigned aStartNet )
  455. {
  456. unsigned netItemTst = aStartNet;
  457. int erc = 1;
  458. /* Review the list of labels connected to NetItemRef. */
  459. for( ; ; netItemTst++ )
  460. {
  461. if( netItemTst == aNetItemRef )
  462. continue;
  463. /* Is always in the same net? */
  464. if( ( netItemTst == aList->size() )
  465. || ( aList->GetItemNet( aNetItemRef ) != aList->GetItemNet( netItemTst ) ) )
  466. {
  467. /* End Netcode found. */
  468. if( erc )
  469. {
  470. /* Glabel or SheetLabel orphaned. */
  471. Diagnose( aList->GetItem( aNetItemRef ), NULL, -1, WAR );
  472. }
  473. return;
  474. }
  475. if( aList->GetItem( aNetItemRef )->IsLabelConnected( aList->GetItem( netItemTst ) ) )
  476. erc = 0;
  477. //same thing, different order.
  478. if( aList->GetItem( netItemTst )->IsLabelConnected( aList->GetItem( aNetItemRef ) ) )
  479. erc = 0;
  480. }
  481. }