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.

610 lines
16 KiB

5 years ago
5 years ago
5 years ago
5 years ago
3 years ago
3 years ago
3 years ago
2 years ago
2 years ago
2 years ago
3 years ago
3 years ago
3 years ago
3 years ago
8 months ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2018 CERN
  5. * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
  6. *
  7. * @author Jon Evans <jon@craftyjon.com>
  8. *
  9. * This program is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU General Public License
  11. * as published by the Free Software Foundation; either version 2
  12. * of the License, or (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License along
  20. * with this program. If not, see <http://www.gnu.org/licenses/>.
  21. */
  22. #include <regex>
  23. #include <wx/tokenzr.h>
  24. #include <connection_graph.h>
  25. #include <sch_symbol.h>
  26. #include <sch_pin.h>
  27. #include <sch_screen.h>
  28. #include <project/net_settings.h>
  29. #include <advanced_config.h>
  30. #include <string_utils.h>
  31. #include <sch_connection.h>
  32. #include <boost/algorithm/string/join.hpp>
  33. /**
  34. *
  35. * Buses can be defined in multiple ways. A bus vector consists of a prefix and
  36. * a numeric range of suffixes:
  37. *
  38. * BUS_NAME[M..N]
  39. *
  40. * For example, the bus A[3..0] will contain nets A3, A2, A1, and A0.
  41. * The BUS_NAME is required. M and N must be integers but do not need to be in
  42. * any particular order -- A[0..3] produces the same result.
  43. *
  44. * Like net names, bus names cannot contain whitespace.
  45. *
  46. * A bus group is just a grouping of signals, separated by spaces, some
  47. * of which may be bus vectors. Bus groups can have names, but do not need to.
  48. *
  49. * MEMORY{A[15..0] D[7..0] RW CE OE}
  50. *
  51. * In named bus groups, the net names are expanded as <BUS_NAME>.<NET_NAME>
  52. * In the above example, the nets would be named like MEMORY.A15, MEMORY.D0, etc.
  53. *
  54. * {USB_DP USB_DN}
  55. *
  56. * In the above example, the bus is unnamed and so the underlying net names are
  57. * just USB_DP and USB_DN.
  58. *
  59. */
  60. SCH_CONNECTION::SCH_CONNECTION( SCH_ITEM* aParent, const SCH_SHEET_PATH& aPath ) :
  61. m_sheet( aPath ),
  62. m_local_sheet( aPath ),
  63. m_parent( aParent ),
  64. m_driver( nullptr ),
  65. m_graph( nullptr )
  66. {
  67. Reset();
  68. }
  69. SCH_CONNECTION::SCH_CONNECTION( CONNECTION_GRAPH* aGraph ) :
  70. m_sheet( SCH_SHEET_PATH() ),
  71. m_local_sheet( SCH_SHEET_PATH() ),
  72. m_parent( nullptr ),
  73. m_driver( nullptr ),
  74. m_graph( aGraph )
  75. {
  76. Reset();
  77. }
  78. SCH_CONNECTION::SCH_CONNECTION( SCH_CONNECTION& aOther ) :
  79. m_parent( nullptr ),
  80. m_driver( nullptr )
  81. {
  82. Reset();
  83. Clone( aOther );
  84. }
  85. bool SCH_CONNECTION::operator==( const SCH_CONNECTION& aOther ) const
  86. {
  87. // NOTE: Not comparing m_dirty or net/bus/subgraph codes
  88. if( ( aOther.m_driver == m_driver ) &&
  89. ( aOther.m_type == m_type ) &&
  90. ( aOther.m_name == m_name ) &&
  91. ( aOther.m_sheet == m_sheet ) )
  92. {
  93. return true;
  94. }
  95. return false;
  96. }
  97. void SCH_CONNECTION::SetDriver( SCH_ITEM* aItem )
  98. {
  99. m_driver = aItem;
  100. recacheName();
  101. for( const std::shared_ptr<SCH_CONNECTION>& member : m_members )
  102. member->SetDriver( aItem );
  103. }
  104. void SCH_CONNECTION::SetSheet( const SCH_SHEET_PATH& aSheet )
  105. {
  106. m_sheet = aSheet;
  107. m_local_sheet = aSheet;
  108. recacheName();
  109. for( const std::shared_ptr<SCH_CONNECTION>& member : m_members )
  110. member->SetSheet( aSheet );
  111. }
  112. bool SCH_CONNECTION::operator!=( const SCH_CONNECTION& aOther ) const
  113. {
  114. return !( aOther == *this );
  115. }
  116. void SCH_CONNECTION::ConfigureFromLabel( const wxString& aLabel )
  117. {
  118. m_members.clear();
  119. m_name = aLabel;
  120. m_local_name = aLabel;
  121. m_local_prefix = m_prefix;
  122. wxString prefix;
  123. std::vector<wxString> members;
  124. wxString unescaped = UnescapeString( aLabel );
  125. if( NET_SETTINGS::ParseBusVector( unescaped, &prefix, &members ) )
  126. {
  127. m_type = CONNECTION_TYPE::BUS;
  128. m_vector_prefix = std::move( prefix );
  129. long i = 0;
  130. for( const wxString& vector_member : members )
  131. {
  132. std::shared_ptr<SCH_CONNECTION> member = std::make_shared<SCH_CONNECTION>( m_parent, m_sheet );
  133. member->m_type = CONNECTION_TYPE::NET;
  134. member->m_prefix = m_prefix;
  135. member->m_local_name = vector_member;
  136. member->m_local_prefix = m_prefix;
  137. member->m_vector_index = i++;
  138. member->SetName( vector_member );
  139. member->SetGraph( m_graph );
  140. m_members.push_back( std::move( member ) );
  141. }
  142. }
  143. else if( NET_SETTINGS::ParseBusGroup( unescaped, &prefix, &members ) )
  144. {
  145. m_type = CONNECTION_TYPE::BUS_GROUP;
  146. m_bus_prefix = prefix;
  147. // Named bus groups generate a net prefix, unnamed ones don't
  148. if( !prefix.IsEmpty() )
  149. prefix += wxT( "." );
  150. for( const wxString& group_member : members )
  151. {
  152. // Handle alias inside bus group member list
  153. if( auto alias = m_graph->GetBusAlias( group_member ) )
  154. {
  155. for( const wxString& alias_member : alias->Members() )
  156. {
  157. std::shared_ptr<SCH_CONNECTION> member = std::make_shared<SCH_CONNECTION>( m_parent, m_sheet );
  158. member->SetPrefix( prefix );
  159. member->SetGraph( m_graph );
  160. member->ConfigureFromLabel( EscapeString( alias_member, CTX_NETNAME ) );
  161. m_members.push_back( std::move( member ) );
  162. }
  163. }
  164. else
  165. {
  166. std::shared_ptr<SCH_CONNECTION> member = std::make_shared<SCH_CONNECTION>( m_parent, m_sheet );
  167. member->SetPrefix( prefix );
  168. member->SetGraph( m_graph );
  169. member->ConfigureFromLabel( group_member );
  170. m_members.push_back( std::move( member ) );
  171. }
  172. }
  173. }
  174. else
  175. {
  176. m_type = CONNECTION_TYPE::NET;
  177. }
  178. recacheName();
  179. }
  180. void SCH_CONNECTION::Reset()
  181. {
  182. m_type = CONNECTION_TYPE::NONE;
  183. m_name.Empty();
  184. m_local_name.Empty();
  185. m_local_prefix.Empty();
  186. m_cached_name.Empty();
  187. m_cached_name_with_path.Empty();
  188. m_prefix.Empty();
  189. m_bus_prefix.Empty();
  190. m_suffix .Empty();
  191. m_lastDriver = m_driver;
  192. m_driver = nullptr;
  193. m_members.clear();
  194. m_dirty = true;
  195. m_net_code = 0;
  196. m_bus_code = 0;
  197. m_subgraph_code = 0;
  198. m_vector_start = 0;
  199. m_vector_end = 0;
  200. m_vector_index = 0;
  201. m_vector_prefix.Empty();
  202. }
  203. void SCH_CONNECTION::Clone( const SCH_CONNECTION& aOther )
  204. {
  205. m_graph = aOther.m_graph;
  206. // Note: m_lastDriver is not cloned as it needs to be the last driver of *this* connection
  207. m_driver = aOther.Driver();
  208. m_sheet = aOther.Sheet();
  209. // Note: m_local_sheet is not cloned
  210. m_name = aOther.m_name;
  211. m_type = aOther.m_type;
  212. // Note: m_local_name is not cloned if not set yet
  213. if( m_local_name.IsEmpty() )
  214. {
  215. m_local_name = aOther.LocalName();
  216. m_local_prefix = aOther.Prefix();
  217. }
  218. m_prefix = aOther.Prefix();
  219. // m_bus_prefix is not cloned; only used for local names
  220. m_suffix = aOther.Suffix();
  221. m_net_code = aOther.NetCode();
  222. m_bus_code = aOther.BusCode();
  223. m_vector_start = aOther.VectorStart();
  224. m_vector_end = aOther.VectorEnd();
  225. // Note: m_vector_index is not cloned
  226. m_vector_prefix = aOther.VectorPrefix();
  227. // Note: subgraph code isn't cloned, it should remain with the original object
  228. // Handle vector bus members: make sure local names are preserved where possible
  229. const std::vector<std::shared_ptr<SCH_CONNECTION>>& otherMembers = aOther.Members();
  230. if( m_type == CONNECTION_TYPE::BUS && aOther.Type() == CONNECTION_TYPE::BUS )
  231. {
  232. if( m_members.empty() )
  233. {
  234. m_members = otherMembers;
  235. }
  236. else
  237. {
  238. size_t cloneLimit = std::min( m_members.size(), otherMembers.size() );
  239. for( size_t i = 0; i < cloneLimit; ++i )
  240. m_members[i]->Clone( *otherMembers[i] );
  241. }
  242. }
  243. else if( m_type == CONNECTION_TYPE::BUS_GROUP && aOther.Type() == CONNECTION_TYPE::BUS_GROUP )
  244. {
  245. if( m_members.empty() )
  246. {
  247. m_members = otherMembers;
  248. }
  249. else
  250. {
  251. // TODO: refactor this once we support deep nesting
  252. for( std::shared_ptr<SCH_CONNECTION>& member : m_members )
  253. {
  254. auto it = std::find_if( otherMembers.begin(), otherMembers.end(),
  255. [&]( const std::shared_ptr<SCH_CONNECTION>& aTest )
  256. {
  257. return aTest->LocalName() == member->LocalName();
  258. } );
  259. if( it != otherMembers.end() )
  260. member->Clone( **it );
  261. }
  262. }
  263. }
  264. m_type = aOther.Type();
  265. recacheName();
  266. }
  267. bool SCH_CONNECTION::IsDriver() const
  268. {
  269. wxASSERT( Parent() );
  270. switch( Parent()->Type() )
  271. {
  272. case SCH_LABEL_T:
  273. case SCH_GLOBAL_LABEL_T:
  274. case SCH_HIER_LABEL_T:
  275. case SCH_SHEET_PIN_T:
  276. case SCH_SHEET_T:
  277. return true;
  278. case SCH_PIN_T:
  279. {
  280. const SCH_PIN* pin = static_cast<const SCH_PIN*>( Parent() );
  281. if( const SCH_SYMBOL* symbol = dynamic_cast<const SCH_SYMBOL*>( pin->GetParentSymbol() ) )
  282. {
  283. // Only annotated symbols should drive nets.
  284. return pin->IsPower() || symbol->IsAnnotated( &m_sheet );
  285. }
  286. return true;
  287. }
  288. default:
  289. return false;
  290. }
  291. }
  292. bool SCH_CONNECTION::HasDriverChanged() const
  293. {
  294. return m_driver != m_lastDriver;
  295. }
  296. void SCH_CONNECTION::ClearDriverChanged()
  297. {
  298. m_lastDriver = m_driver;
  299. }
  300. wxString SCH_CONNECTION::Name( bool aIgnoreSheet ) const
  301. {
  302. wxASSERT( !m_cached_name.IsEmpty() );
  303. return aIgnoreSheet ? m_cached_name : m_cached_name_with_path;
  304. }
  305. wxString SCH_CONNECTION::GetNetName() const
  306. {
  307. wxString retv;
  308. if( m_graph )
  309. {
  310. CONNECTION_SUBGRAPH* subgraph = m_graph->GetSubgraphForItem( m_parent );
  311. if( subgraph )
  312. retv = subgraph->GetNetName();
  313. }
  314. return retv;
  315. }
  316. void SCH_CONNECTION::recacheName()
  317. {
  318. m_cached_name = m_name.IsEmpty() ? wxString( wxT( "<NO NET>" ) )
  319. : wxString( m_prefix ) << m_name << m_suffix;
  320. bool prepend_path = true;
  321. if( !Parent() || m_type == CONNECTION_TYPE::NONE )
  322. prepend_path = false;
  323. if( m_driver )
  324. {
  325. switch( m_driver->Type() )
  326. {
  327. case SCH_GLOBAL_LABEL_T:
  328. prepend_path = false;
  329. break;
  330. case SCH_PIN_T:
  331. { // Normal pins and global power pins do not need a path. But local power pins do
  332. SCH_PIN* pin = static_cast<SCH_PIN*>( m_driver );
  333. prepend_path = pin->IsLocalPower();
  334. break;
  335. }
  336. default:
  337. break;
  338. }
  339. }
  340. m_cached_name_with_path = prepend_path ? m_sheet.PathHumanReadable() << m_cached_name
  341. : m_cached_name;
  342. }
  343. void SCH_CONNECTION::SetPrefix( const wxString& aPrefix )
  344. {
  345. m_prefix = aPrefix;
  346. recacheName();
  347. for( const std::shared_ptr<SCH_CONNECTION>& m : Members() )
  348. m->SetPrefix( aPrefix );
  349. }
  350. void SCH_CONNECTION::SetSuffix( const wxString& aSuffix )
  351. {
  352. m_suffix = aSuffix;
  353. recacheName();
  354. for( const std::shared_ptr<SCH_CONNECTION>& m : Members() )
  355. m->SetSuffix( aSuffix );
  356. }
  357. void SCH_CONNECTION::AppendInfoToMsgPanel( std::vector<MSG_PANEL_ITEM>& aList ) const
  358. {
  359. wxString msg, group_name;
  360. std::vector<wxString> group_members;
  361. aList.emplace_back( _( "Connection Name" ), UnescapeString( Name() ) );
  362. if( std::shared_ptr<BUS_ALIAS> alias = m_graph->GetBusAlias( m_name ) )
  363. {
  364. msg.Printf( _( "Bus Alias %s Members" ), m_name );
  365. aList.emplace_back( msg, boost::algorithm::join( alias->Members(), " " ) );
  366. }
  367. else if( NET_SETTINGS::ParseBusGroup( m_name, &group_name, &group_members ) )
  368. {
  369. for( const wxString& group_member : group_members )
  370. {
  371. if( std::shared_ptr<BUS_ALIAS> group_alias = m_graph->GetBusAlias( group_member ) )
  372. {
  373. msg.Printf( _( "Bus Alias %s Members" ), group_alias->GetName() );
  374. aList.emplace_back( msg, boost::algorithm::join( group_alias->Members(), " " ) );
  375. }
  376. }
  377. }
  378. #if defined(DEBUG)
  379. // These messages are not flagged as translatable, because they are only debug messages
  380. if( IsBus() )
  381. aList.emplace_back( wxT( "Bus Code" ), wxString::Format( "%d", m_bus_code ) );
  382. aList.emplace_back( wxT( "Subgraph Code" ), wxString::Format( "%d", m_subgraph_code ) );
  383. if( SCH_ITEM* driver = Driver() )
  384. {
  385. UNITS_PROVIDER unitsProvider( schIUScale, EDA_UNITS::MM );
  386. msg.Printf( wxS( "%s at %p" ),
  387. driver->GetItemDescription( &unitsProvider, false ),
  388. driver );
  389. aList.emplace_back( wxT( "Connection Source" ), msg );
  390. }
  391. #endif
  392. }
  393. bool SCH_CONNECTION::IsBusLabel( const wxString& aLabel )
  394. {
  395. const wxString& unescaped = UnescapeString( aLabel );
  396. return NET_SETTINGS::ParseBusVector( unescaped, nullptr, nullptr )
  397. || NET_SETTINGS::ParseBusGroup( unescaped, nullptr, nullptr );
  398. }
  399. bool SCH_CONNECTION::MightBeBusLabel( const wxString& aLabel )
  400. {
  401. // Weak heuristic for performance reasons. Stronger test will be used for connectivity
  402. wxString label = UnescapeString( aLabel );
  403. return label.Contains( wxT( "[" ) ) || label.Contains( wxT( "{" ) );
  404. }
  405. const std::vector< std::shared_ptr< SCH_CONNECTION > > SCH_CONNECTION::AllMembers() const
  406. {
  407. std::vector< std::shared_ptr< SCH_CONNECTION > > ret( m_members );
  408. for( const std::shared_ptr<SCH_CONNECTION>& member : m_members )
  409. {
  410. if( member->IsBus() )
  411. ret.insert( ret.end(), member->Members().begin(), member->Members().end() );
  412. }
  413. return ret;
  414. }
  415. static bool isSuperSubOverbar( wxChar c )
  416. {
  417. return c == '_' || c == '^' || c == '~';
  418. };
  419. wxString SCH_CONNECTION::PrintBusForUI( const wxString& aGroup )
  420. {
  421. size_t groupLen = aGroup.length();
  422. size_t i = 0;
  423. wxString ret;
  424. // Parse prefix
  425. //
  426. for( ; i < groupLen; ++i )
  427. {
  428. if( isSuperSubOverbar( aGroup[i] ) && i + 1 < groupLen && aGroup[i+1] == '{' )
  429. {
  430. i++;
  431. continue;
  432. }
  433. else if( aGroup[i] == '}' )
  434. {
  435. continue;
  436. }
  437. ret += aGroup[i];
  438. if( aGroup[i] == '{' )
  439. break;
  440. }
  441. // Parse members
  442. //
  443. i++; // '{' character
  444. for( ; i < groupLen; ++i )
  445. {
  446. if( isSuperSubOverbar( aGroup[i] ) && i + 1 < groupLen && aGroup[i+1] == '{' )
  447. {
  448. i++;
  449. continue;
  450. }
  451. else if( aGroup[i] == '}' )
  452. {
  453. continue;
  454. }
  455. ret += aGroup[i];
  456. if( aGroup[i] == '}' )
  457. break;
  458. }
  459. return ret;
  460. }
  461. bool SCH_CONNECTION::IsSubsetOf( SCH_CONNECTION* aOther ) const
  462. {
  463. if( !aOther->IsBus() )
  464. return false;
  465. for( const std::shared_ptr<SCH_CONNECTION>& member : aOther->Members() )
  466. {
  467. if( member->FullLocalName() == FullLocalName() )
  468. return true;
  469. }
  470. return false;
  471. }
  472. bool SCH_CONNECTION::IsMemberOfBus( SCH_CONNECTION* aOther ) const
  473. {
  474. if( !aOther->IsBus() )
  475. return false;
  476. wxString me = Name( true );
  477. for( const std::shared_ptr<SCH_CONNECTION>& m : aOther->Members() )
  478. {
  479. if( m->Name( true ) == me )
  480. return true;
  481. }
  482. return false;
  483. }