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.

583 lines
15 KiB

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