|
|
|
@ -26,7 +26,6 @@ |
|
|
|
#include <unordered_map>
|
|
|
|
#include <profile.h>
|
|
|
|
|
|
|
|
#include <advanced_config.h>
|
|
|
|
#include <common.h>
|
|
|
|
#include <erc.h>
|
|
|
|
#include <sch_edit_frame.h>
|
|
|
|
@ -309,56 +308,23 @@ void CONNECTION_GRAPH::Recalculate( SCH_SHEET_LIST aSheetList, bool aUncondition |
|
|
|
if( aUnconditional ) |
|
|
|
Reset(); |
|
|
|
|
|
|
|
std::map<SCH_ITEM*, std::vector<SCH_SHEET_PATH>> sheets; |
|
|
|
|
|
|
|
for( auto sheet : aSheetList ) |
|
|
|
for( const auto& sheet : aSheetList ) |
|
|
|
{ |
|
|
|
if( auto list = sheet.LastDrawList() ) |
|
|
|
sheets[list].push_back( sheet ); |
|
|
|
} |
|
|
|
|
|
|
|
size_t parallelThreadCount = std::min<size_t>( std::thread::hardware_concurrency(), |
|
|
|
( sheets.size() + 1 ) / 2 ); |
|
|
|
std::atomic<size_t> nextSheet( 0 ); |
|
|
|
std::vector<std::future<size_t>> returns( parallelThreadCount ); |
|
|
|
|
|
|
|
auto update_connectivity = [&]() -> size_t |
|
|
|
{ |
|
|
|
for( size_t sheetId = nextSheet++; sheetId < sheets.size(); sheetId = nextSheet++ ) |
|
|
|
{ |
|
|
|
auto sheet = sheets.begin(); |
|
|
|
std::advance( sheet, sheetId ); |
|
|
|
std::vector<SCH_ITEM*> items; |
|
|
|
|
|
|
|
for( auto item = sheet->first; item; item = item->Next() ) |
|
|
|
for( auto item = sheet.LastScreen()->GetDrawItems(); |
|
|
|
item; item = item->Next() ) |
|
|
|
{ |
|
|
|
if( item->IsConnectable() && |
|
|
|
( aUnconditional || item->IsConnectivityDirty() ) ) |
|
|
|
{ |
|
|
|
if( item->IsConnectable() && ( aUnconditional || item->IsConnectivityDirty() ) ) |
|
|
|
items.push_back( item ); |
|
|
|
} |
|
|
|
|
|
|
|
auto it = sheet->second.begin(); |
|
|
|
updateItemConnectivity( *it, items ); |
|
|
|
|
|
|
|
for( ++it; it != sheet->second.end(); ++it ) |
|
|
|
initializeSheetConnections( *it, items ); |
|
|
|
} |
|
|
|
|
|
|
|
return 1; |
|
|
|
}; |
|
|
|
|
|
|
|
if( parallelThreadCount == 1 ) |
|
|
|
update_connectivity(); |
|
|
|
else |
|
|
|
{ |
|
|
|
for( size_t ii = 0; ii < parallelThreadCount; ++ii ) |
|
|
|
returns[ii] = std::async( std::launch::async, update_connectivity ); |
|
|
|
|
|
|
|
// Finalize the threads
|
|
|
|
for( size_t ii = 0; ii < parallelThreadCount; ++ii ) |
|
|
|
returns[ii].wait(); |
|
|
|
updateItemConnectivity( sheet, items ); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
phase1.Stop(); |
|
|
|
wxLogTrace( "CONN_PROFILE", "UpdateItemConnectivity() %0.4f ms", phase1.msecs() ); |
|
|
|
|
|
|
|
@ -375,50 +341,10 @@ void CONNECTION_GRAPH::Recalculate( SCH_SHEET_LIST aSheetList, bool aUncondition |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void CONNECTION_GRAPH::initializeSheetConnections( SCH_SHEET_PATH aSheet, |
|
|
|
std::vector<SCH_ITEM*>& aItemList ) |
|
|
|
{ |
|
|
|
for( auto item : aItemList ) |
|
|
|
{ |
|
|
|
if( item->Type() == SCH_SHEET_T ) |
|
|
|
{ |
|
|
|
for( auto& pin : static_cast<SCH_SHEET*>( item )->GetPins() ) |
|
|
|
pin.InitializeConnection( aSheet ); |
|
|
|
} |
|
|
|
else if( item->Type() != SCH_COMPONENT_T ) |
|
|
|
{ |
|
|
|
auto conn = item->InitializeConnection( aSheet ); |
|
|
|
|
|
|
|
// Set bus/net property here so that the propagation code uses it
|
|
|
|
switch( item->Type() ) |
|
|
|
{ |
|
|
|
case SCH_LINE_T: |
|
|
|
conn->SetType( ( item->GetLayer() == LAYER_BUS ) ? |
|
|
|
CONNECTION_BUS : CONNECTION_NET ); |
|
|
|
break; |
|
|
|
|
|
|
|
case SCH_BUS_BUS_ENTRY_T: |
|
|
|
conn->SetType( CONNECTION_BUS ); |
|
|
|
break; |
|
|
|
|
|
|
|
case SCH_PIN_T: |
|
|
|
case SCH_BUS_WIRE_ENTRY_T: |
|
|
|
conn->SetType( CONNECTION_NET ); |
|
|
|
break; |
|
|
|
|
|
|
|
default: |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void CONNECTION_GRAPH::updateItemConnectivity( SCH_SHEET_PATH aSheet, |
|
|
|
std::vector<SCH_ITEM*>& aItemList ) |
|
|
|
std::vector<SCH_ITEM*> aItemList ) |
|
|
|
{ |
|
|
|
std::unordered_multimap< wxPoint, SCH_ITEM* > connection_map; |
|
|
|
std::unordered_map< wxPoint, std::vector<SCH_ITEM*> > connection_map; |
|
|
|
|
|
|
|
for( auto item : aItemList ) |
|
|
|
{ |
|
|
|
@ -429,18 +355,25 @@ void CONNECTION_GRAPH::updateItemConnectivity( SCH_SHEET_PATH aSheet, |
|
|
|
if( item->Type() == SCH_SHEET_T ) |
|
|
|
{ |
|
|
|
for( auto& pin : static_cast<SCH_SHEET*>( item )->GetPins() ) |
|
|
|
{ |
|
|
|
if( !pin.Connection( aSheet ) ) |
|
|
|
{ |
|
|
|
pin.InitializeConnection( aSheet ); |
|
|
|
} |
|
|
|
|
|
|
|
pin.ConnectedItems().clear(); |
|
|
|
pin.Connection( aSheet )->Reset(); |
|
|
|
|
|
|
|
connection_map.emplace( pin.GetTextPos(), &pin ); |
|
|
|
InsertItem( &pin ); |
|
|
|
connection_map[ pin.GetTextPos() ].push_back( &pin ); |
|
|
|
m_items.insert( &pin ); |
|
|
|
} |
|
|
|
} |
|
|
|
else if( item->Type() == SCH_COMPONENT_T ) |
|
|
|
{ |
|
|
|
auto component = static_cast<SCH_COMPONENT*>( item ); |
|
|
|
|
|
|
|
component->UpdatePins( &aSheet ); |
|
|
|
|
|
|
|
for( auto& it : component->GetPinMap() ) |
|
|
|
{ |
|
|
|
SCH_PIN* pin = &it.second; |
|
|
|
@ -455,15 +388,15 @@ void CONNECTION_GRAPH::updateItemConnectivity( SCH_SHEET_PATH aSheet, |
|
|
|
// Invisible power pins need to be post-processed later
|
|
|
|
|
|
|
|
if( pin->IsPowerConnection() && !pin->IsVisible() ) |
|
|
|
InsertPin( pin ); |
|
|
|
m_invisible_power_pins.push_back( pin ); |
|
|
|
|
|
|
|
connection_map.emplace( pos, pin ); |
|
|
|
InsertItem( pin ); |
|
|
|
connection_map[ pos ].push_back( pin ); |
|
|
|
m_items.insert( pin ); |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
InsertItem( item ); |
|
|
|
m_items.insert( item ); |
|
|
|
auto conn = item->InitializeConnection( aSheet ); |
|
|
|
|
|
|
|
// Set bus/net property here so that the propagation code uses it
|
|
|
|
@ -488,23 +421,22 @@ void CONNECTION_GRAPH::updateItemConnectivity( SCH_SHEET_PATH aSheet, |
|
|
|
} |
|
|
|
|
|
|
|
for( auto point : points ) |
|
|
|
connection_map.emplace( point, item ); |
|
|
|
{ |
|
|
|
connection_map[ point ].push_back( item ); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
item->SetConnectivityDirty( false ); |
|
|
|
} |
|
|
|
|
|
|
|
auto primary_it = connection_map.begin(); |
|
|
|
for( auto it = connection_map.begin(); it != connection_map.end(); it = primary_it ) |
|
|
|
for( const auto& it : connection_map ) |
|
|
|
{ |
|
|
|
auto range = connection_map.equal_range( it->first ); |
|
|
|
auto count = std::distance( range.first, range.second ); |
|
|
|
primary_it = range.second; |
|
|
|
auto connection_vec = it.second; |
|
|
|
SCH_ITEM* junction = nullptr; |
|
|
|
|
|
|
|
for( primary_it = range.first; primary_it != range.second; ++primary_it ) |
|
|
|
for( auto primary_it = connection_vec.begin(); primary_it != connection_vec.end(); primary_it++ ) |
|
|
|
{ |
|
|
|
auto connected_item = primary_it->second; |
|
|
|
auto connected_item = *primary_it; |
|
|
|
|
|
|
|
// Look for junctions. For points that have a junction, we want all
|
|
|
|
// items to connect to the junction but not to each other.
|
|
|
|
@ -526,10 +458,10 @@ void CONNECTION_GRAPH::updateItemConnectivity( SCH_SHEET_PATH aSheet, |
|
|
|
// entry itself, this means that either the bus entry is not
|
|
|
|
// connected to anything graphically, or that it is connected to
|
|
|
|
// a segment at some point other than at one of the endpoints.
|
|
|
|
if( count == 1 ) |
|
|
|
if( connection_vec.size() == 1 ) |
|
|
|
{ |
|
|
|
auto screen = aSheet.LastScreen(); |
|
|
|
auto bus = screen->GetBus( primary_it->first ); |
|
|
|
auto bus = screen->GetBus( it.first ); |
|
|
|
|
|
|
|
if( bus ) |
|
|
|
{ |
|
|
|
@ -542,41 +474,42 @@ void CONNECTION_GRAPH::updateItemConnectivity( SCH_SHEET_PATH aSheet, |
|
|
|
// Bus-to-bus entries are treated just like bus wires
|
|
|
|
if( connected_item->Type() == SCH_BUS_BUS_ENTRY_T ) |
|
|
|
{ |
|
|
|
if( count < 2 ) |
|
|
|
if( connection_vec.size() < 2 ) |
|
|
|
{ |
|
|
|
auto screen = aSheet.LastScreen(); |
|
|
|
auto bus = screen->GetBus( primary_it->first ); |
|
|
|
auto bus = screen->GetBus( it.first ); |
|
|
|
|
|
|
|
if( bus ) |
|
|
|
{ |
|
|
|
auto bus_entry = static_cast<SCH_BUS_BUS_ENTRY*>( connected_item ); |
|
|
|
|
|
|
|
if( primary_it->first == bus_entry->GetPosition() ) |
|
|
|
if( it.first == bus_entry->GetPosition() ) |
|
|
|
bus_entry->m_connected_bus_items[0] = bus; |
|
|
|
else |
|
|
|
bus_entry->m_connected_bus_items[1] = bus; |
|
|
|
|
|
|
|
bus_entry->AddConnectionTo( bus ); |
|
|
|
bus->AddConnectionTo( bus_entry ); |
|
|
|
bus_entry->ConnectedItems().insert( bus ); |
|
|
|
bus->ConnectedItems().insert( bus_entry ); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
for( auto test_it = std::next( primary_it ); test_it != range.second; ++test_it ) |
|
|
|
for( auto test_it = primary_it + 1; test_it != connection_vec.end(); test_it++ ) |
|
|
|
{ |
|
|
|
auto test_item = test_it->second; |
|
|
|
auto test_item = *test_it; |
|
|
|
|
|
|
|
if( !junction && test_item->Type() == SCH_JUNCTION_T ) |
|
|
|
{ |
|
|
|
junction = test_item; |
|
|
|
} |
|
|
|
|
|
|
|
if( connected_item != junction && |
|
|
|
if( connected_item != test_item && |
|
|
|
connected_item != junction && |
|
|
|
connected_item->ConnectionPropagatesTo( test_item ) && |
|
|
|
test_item->ConnectionPropagatesTo( connected_item ) ) |
|
|
|
{ |
|
|
|
connected_item->AddConnectionTo( test_item ); |
|
|
|
test_item->AddConnectionTo( connected_item ); |
|
|
|
connected_item->ConnectedItems().insert( test_item ); |
|
|
|
test_item->ConnectedItems().insert( connected_item ); |
|
|
|
} |
|
|
|
|
|
|
|
// Set up the link between the bus entry net and the bus
|
|
|
|
@ -713,7 +646,7 @@ void CONNECTION_GRAPH::buildConnectionGraph() |
|
|
|
|
|
|
|
// Resolve drivers for subgraphs and propagate connectivity info
|
|
|
|
|
|
|
|
// We don't want to spin up a new thread for fewer than 4 nets (overhead costs)
|
|
|
|
// We don't want to spin up a new thread for fewer than 8 nets (overhead costs)
|
|
|
|
size_t parallelThreadCount = std::min<size_t>( std::thread::hardware_concurrency(), |
|
|
|
( m_subgraphs.size() + 3 ) / 4 ); |
|
|
|
|
|
|
|
|