Finish porting netlisters to use CONNECTION_GRAPH

This commit is contained in:
Jon Evans 2020-05-20 23:40:31 -04:00
parent d61b6f965e
commit de9520d65e
20 changed files with 274 additions and 600 deletions

View File

@ -1416,6 +1416,7 @@ void CONNECTION_GRAPH::buildConnectionGraph()
}
m_net_code_to_subgraphs_map.clear();
m_net_name_to_subgraphs_map.clear();
for( CONNECTION_SUBGRAPH* subgraph : m_driver_subgraphs )
{
@ -1433,6 +1434,8 @@ void CONNECTION_GRAPH::buildConnectionGraph()
auto key = std::make_pair( subgraph->GetNetName(),
subgraph->m_driver_connection->NetCode() );
m_net_code_to_subgraphs_map[ key ].push_back( subgraph );
m_net_name_to_subgraphs_map[subgraph->m_driver_connection->Name()].push_back( subgraph );
}
// Clean up and deallocate stale subgraphs
@ -1929,6 +1932,25 @@ std::vector<const CONNECTION_SUBGRAPH*> CONNECTION_GRAPH::GetBusesNeedingMigrati
}
CONNECTION_SUBGRAPH* CONNECTION_GRAPH::FindSubgraphByName(
const wxString& aNetName, const SCH_SHEET_PATH& aPath )
{
if( !m_net_name_to_subgraphs_map.count( aNetName ) )
return nullptr;
for( auto sg : m_net_name_to_subgraphs_map.at( aNetName ) )
{
// Cache is supposed to be valid by now
wxASSERT( sg && !sg->m_absorbed && sg->m_driver_connection );
if( sg->m_sheet == aPath && sg->m_driver_connection->Name() == aNetName )
return sg;
}
return nullptr;
}
int CONNECTION_GRAPH::RunERC()
{
int error_count = 0;

View File

@ -275,6 +275,15 @@ public:
const NET_MAP& GetNetMap() const { return m_net_code_to_subgraphs_map; }
/**
* Returns the subgraph for a given net name on a given sheet
* @param aNetName is the local net name to look for
* @param aPath is a sheet path to look on
* @return the subgraph matching the query, or nullptr if none is found
*/
CONNECTION_SUBGRAPH* FindSubgraphByName( const wxString& aNetName,
const SCH_SHEET_PATH& aPath );
// TODO(JE) Remove this when pressure valve is removed
static bool m_allowRealTime;

View File

@ -404,9 +404,7 @@ void SCH_EDIT_FRAME::KiwayMailIn( KIWAY_EXPRESS& mail )
}
{
NETLIST_OBJECT_LIST* net_atoms = BuildNetListBase();
NETLIST_EXPORTER_KICAD exporter(
this, net_atoms, &Schematic(), Schematic().ConnectionGraph() );
NETLIST_EXPORTER_KICAD exporter( &Schematic() );
STRING_FORMATTER formatter;
exporter.Format( &formatter, GNL_ALL );

View File

@ -32,9 +32,10 @@
#include <refdes_utils.h>
#include <class_library.h>
#include <netlist.h>
#include <connection_graph.h>
#include <sch_reference_list.h>
#include <sch_screen.h>
#include <schematic.h>
wxString NETLIST_EXPORTER::MakeCommandLine( const wxString& aFormatString,
@ -71,34 +72,6 @@ wxString NETLIST_EXPORTER::MakeCommandLine( const wxString& aFormatString,
}
void NETLIST_EXPORTER::sprintPinNetName( wxString& aResult,
const wxString& aNetNameFormat, NETLIST_OBJECT* aPin,
bool aUseNetcodeAsNetName )
{
int netcode = aPin->GetNet();
// Not wxString::Clear(), which would free memory. We want the worst
// case wxString memory to grow to avoid reallocation from within the
// caller's loop.
aResult.Empty();
if( netcode != 0 && aPin->GetConnectionType() == NET_CONNECTION::PAD_CONNECT )
{
if( aUseNetcodeAsNetName )
{
aResult.Printf( "%d", netcode );
}
else
{
aResult = aPin->GetNetName();
if( aResult.IsEmpty() ) // No net name: give a name from net code
aResult.Printf( aNetNameFormat.GetData(), netcode );
}
}
}
SCH_COMPONENT* NETLIST_EXPORTER::findNextComponent( EDA_ITEM* aItem, SCH_SHEET_PATH* aSheetPath )
{
wxString ref;
@ -138,202 +111,3 @@ SCH_COMPONENT* NETLIST_EXPORTER::findNextComponent( EDA_ITEM* aItem, SCH_SHEET_P
return comp;
}
/// Comparison routine for sorting by pin numbers.
static bool sortPinsByNum( NETLIST_OBJECT* aPin1, NETLIST_OBJECT* aPin2 )
{
// return "lhs < rhs"
return UTIL::RefDesStringCompare( aPin1->GetPinNumText(), aPin2->GetPinNumText() ) < 0;
}
void NETLIST_EXPORTER::CreatePinList( SCH_COMPONENT* comp, SCH_SHEET_PATH* aSheetPath )
{
wxString ref( comp->GetRef( aSheetPath ) );
// Power symbols and other components which have the reference starting
// with "#" are not included in netlist (pseudo or virtual components)
if( ref[0] == wxChar( '#' ) )
return;
// if( Component->m_FlagControlMulti == 1 )
// continue; /* yes */
// removed because with multiple instances of one schematic
// (several sheets pointing to 1 screen), this will be erroneously be
// toggled.
if( !comp->GetPartRef() )
return;
m_SortedComponentPinList.clear();
// If component is a "multi parts per package" type
if( comp->GetPartRef()->GetUnitCount() > 1 )
{
// test if this reference has already been processed, and if so skip
if( m_ReferencesAlreadyFound.Lookup( ref ) )
return;
// Collect all pins for this reference designator by searching
// the entire design for other parts with the same reference designator.
// This is only done once, it would be too expensive otherwise.
findAllUnitsOfComponent( comp, comp->GetPartRef().get(), aSheetPath );
}
else // entry->GetUnitCount() <= 1 means one part per package
{
LIB_PINS pins; // constructed once here
comp->GetPartRef()->GetPins(
pins, comp->GetUnitSelection( aSheetPath ), comp->GetConvert() );
for( size_t i = 0; i < pins.size(); i++ )
{
LIB_PIN* pin = pins[i];
wxASSERT( pin->Type() == LIB_PIN_T );
addPinToComponentPinList( comp, aSheetPath, pin );
}
}
// Sort pins in m_SortedComponentPinList by pin number
sort( m_SortedComponentPinList.begin(), m_SortedComponentPinList.end(), sortPinsByNum );
// Remove duplicate Pins in m_SortedComponentPinList
eraseDuplicatePins();
// record the usage of this library component entry.
m_LibParts.insert( comp->GetPartRef().get() ); // rejects non-unique pointers
}
bool NETLIST_EXPORTER::addPinToComponentPinList( SCH_COMPONENT* aComponent,
SCH_SHEET_PATH* aSheetPath, LIB_PIN* aPin )
{
// Search the PIN description for Pin in g_NetObjectslist
for( unsigned ii = 0; ii < m_masterList->size(); ii++ )
{
NETLIST_OBJECT* pin = m_masterList->GetItem( ii );
if( pin->m_Type != NETLIST_ITEM::PIN )
continue;
if( pin->m_Link != aComponent )
continue;
if( pin->m_PinNum != aPin->GetNumber() )
continue;
// most expensive test at the end.
if( pin->m_SheetPath != *aSheetPath )
continue;
m_SortedComponentPinList.push_back( pin );
if( m_SortedComponentPinList.size() >= MAXPIN )
{
// Log message for Internal error
DisplayError( NULL, wxT( "addPinToComponentPinList err: MAXPIN reached" ) );
}
return true; // we're done, we appended.
}
return false;
}
void NETLIST_EXPORTER::eraseDuplicatePins()
{
for( unsigned ii = 0; ii < m_SortedComponentPinList.size(); ii++ )
{
if( m_SortedComponentPinList[ii] == NULL ) /* already deleted */
continue;
/* Search for duplicated pins
* If found, remove duplicates. The priority is to keep connected pins
* and remove unconnected
* - So this allows (for instance when using multi op amps per package
* - to connect only one op amp to power
* Because the pin list is sorted by m_PinNum value, duplicated pins
* are necessary successive in list
*/
int idxref = ii;
for( unsigned jj = ii + 1; jj < m_SortedComponentPinList.size(); jj++ )
{
if( m_SortedComponentPinList[jj] == NULL ) // Already removed
continue;
// if other pin num, stop search,
// because all pins having the same number are consecutive in list.
if( m_SortedComponentPinList[idxref]->m_PinNum != m_SortedComponentPinList[jj]->m_PinNum )
break;
if( m_SortedComponentPinList[idxref]->GetConnectionType()
== NET_CONNECTION::PAD_CONNECT )
{
m_SortedComponentPinList[jj]->m_Flag = 1;
m_SortedComponentPinList[jj] = NULL;
}
else /* the reference pin is not connected: remove this pin if the
* other pin is connected */
{
if( m_SortedComponentPinList[jj]->GetConnectionType()
== NET_CONNECTION::PAD_CONNECT )
{
m_SortedComponentPinList[idxref]->m_Flag = 1;
m_SortedComponentPinList[idxref] = NULL;
idxref = jj;
}
else // the 2 pins are not connected: remove the tested pin,
{ // and continue ...
m_SortedComponentPinList[jj]->m_Flag = 1;
m_SortedComponentPinList[jj] = NULL;
}
}
}
}
}
void NETLIST_EXPORTER::findAllUnitsOfComponent( SCH_COMPONENT* aComponent,
LIB_PART* aEntry, SCH_SHEET_PATH* aSheetPath )
{
wxString ref = aComponent->GetRef( aSheetPath );
wxString ref2;
SCH_SHEET_LIST sheetList = m_schematic->GetSheets();
for( unsigned i = 0; i < sheetList.size(); i++ )
{
for( auto item : sheetList[i].LastScreen()->Items().OfType( SCH_COMPONENT_T ) )
{
SCH_COMPONENT* comp2 = static_cast<SCH_COMPONENT*>( item );
ref2 = comp2->GetRef( &sheetList[i] );
if( ref2.CmpNoCase( ref ) != 0 )
continue;
int unit2 = comp2->GetUnitSelection( &sheetList[i] ); // slow
for( LIB_PIN* pin = aEntry->GetNextPin(); pin; pin = aEntry->GetNextPin( pin ) )
{
wxASSERT( pin->Type() == LIB_PIN_T );
if( pin->GetUnit() && pin->GetUnit() != unit2 )
continue;
if( pin->GetConvert() && pin->GetConvert() != comp2->GetConvert() )
continue;
// A suitable pin is found: add it to the current list
addPinToComponentPinList( comp2, &sheetList[i], pin );
}
}
}
}

View File

@ -88,13 +88,14 @@ struct LIB_PART_LESS_THAN
class NETLIST_EXPORTER
{
protected:
NETLIST_OBJECT_LIST* m_masterList; /// yes ownership, connected items flat list
// TODO(JE) NETLISTING
#if 0
/// Used to temporarily store and filter the list of pins of a schematic component
/// when generating schematic component data in netlist (comp section). No ownership
/// of members.
/// TODO(snh): Descope this object
NETLIST_OBJECTS m_SortedComponentPinList;
#endif
/// Used for "multi parts per package" components,
/// avoids processing a lib component more than once.
@ -106,68 +107,10 @@ protected:
/// The schematic we're generating a netlist for
SCHEMATIC* m_schematic;
/**
* Function sprintPinNetName
* formats the net name for \a aPin using \a aNetNameFormat into \a aResult.
* <p>
* Net name is:
* <ul>
* <li> "?" if pin not connected
* <li> "netname" for global net (like gnd, vcc ..
* <li> "/path/netname" for the usual nets
* </ul>
* if aUseNetcodeAsNetName is true, the net name is just the net code (SPICE only)
*/
static void sprintPinNetName( wxString& aResult, const wxString& aNetNameFormat,
NETLIST_OBJECT* aPin, bool aUseNetcodeAsNetName = false );
/**
* Function findNextComponentAndCreatePinList
* finds a component from the DrawList and builds
* its pin list in m_SortedComponentPinList. This list is sorted by pin num.
* the component is the next actual component after aItem
* (power symbols and virtual components that have their reference starting by '#'are skipped).
*/
void CreatePinList( SCH_COMPONENT* aItem, SCH_SHEET_PATH* aSheetPath );
SCH_COMPONENT* findNextComponent( EDA_ITEM* aItem, SCH_SHEET_PATH* aSheetPath );
/**
* Function eraseDuplicatePins
* erase duplicate Pins from m_SortedComponentPinList (i.e. set pointer in this list to NULL).
* (This is a list of pins found in the whole schematic, for a single
* component.) These duplicate pins were put in list because some pins (powers... )
* are found more than one time when we have a multiple parts per package
* component. For instance, a 74ls00 has 4 parts, and therefore the VCC pin
* and GND pin appears 4 times in the list.
* Note: this list *MUST* be sorted by pin number (.m_PinNum member value)
* Also set the m_Flag member of "removed" NETLIST_OBJECT pin item to 1
*/
void eraseDuplicatePins();
/**
* Function addPinToComponentPinList
* adds a new pin description to the pin list m_SortedComponentPinList.
* A pin description is a pointer to the corresponding structure
* created by BuildNetList() in the table g_NetObjectslist.
*/
bool addPinToComponentPinList( SCH_COMPONENT* Component,
SCH_SHEET_PATH* sheet,
LIB_PIN* PinEntry );
/**
* Function findAllUnitsOfComponent
* is used for "multiple parts per package" components.
* <p>
* Search the entire design for all units of \a aComponent based on
* matching reference designator, and for each unit, add all its pins
* to the temporary sorted pin list, m_SortedComponentPinList.
*/
void findAllUnitsOfComponent( SCH_COMPONENT* aComponent,
LIB_PART* aEntry,
SCH_SHEET_PATH* aSheetPath );
public:
/**
@ -175,16 +118,14 @@ public:
* @param aMasterList we take ownership of this here.
* @param aLibTable is the symbol library table of the project.
*/
NETLIST_EXPORTER( NETLIST_OBJECT_LIST* aMasterList, SCHEMATIC* aSchematic ) :
m_masterList( aMasterList ),
NETLIST_EXPORTER( SCHEMATIC* aSchematic ) :
m_schematic( aSchematic )
{
wxASSERT( aMasterList );
wxASSERT( aSchematic );
}
virtual ~NETLIST_EXPORTER()
{
delete m_masterList; // I own the list itself in this instance.
}
/**

View File

@ -27,6 +27,7 @@
#include <build_version.h>
#include <confirm.h>
#include <connection_graph.h>
#include <sch_edit_frame.h>
#include <sch_reference_list.h>
@ -62,10 +63,6 @@ bool NETLIST_EXPORTER_CADSTAR::WriteNetlist( const wxString& aOutFileName, unsig
ret |= fprintf( f, "\"%s\"\n", TO_UTF8( title ) );
ret |= fprintf( f, ".TYP FULL\n\n" );
// Prepare list of nets generation
for( unsigned ii = 0; ii < m_masterList->size(); ii++ )
m_masterList->GetItem( ii )->m_Flag = 0;
// Create netlist module section
m_ReferencesAlreadyFound.Clear();
@ -82,8 +79,6 @@ bool NETLIST_EXPORTER_CADSTAR::WriteNetlist( const wxString& aOutFileName, unsig
if( !component )
continue;
CreatePinList( component, &sheetList[i] );
if( !component->GetField( FOOTPRINT )->IsVoid() )
footprint = component->GetField( FOOTPRINT )->GetText();
else
@ -103,8 +98,6 @@ bool NETLIST_EXPORTER_CADSTAR::WriteNetlist( const wxString& aOutFileName, unsig
ret |= fprintf( f, "\n" );
m_SortedComponentPinList.clear();
if( ! writeListOfNets( f ) )
ret = -1; // set error
@ -118,78 +111,99 @@ bool NETLIST_EXPORTER_CADSTAR::WriteNetlist( const wxString& aOutFileName, unsig
bool NETLIST_EXPORTER_CADSTAR::writeListOfNets( FILE* f )
{
int ret = 0;
int ret = 0;
int print_ter = 0;
wxString InitNetDesc = StartLine + wxT( "ADD_TER" );
wxString StartNetDesc = StartLine + wxT( "TER" );
wxString netcodeName, InitNetDescLine;
unsigned ii;
int print_ter = 0;
int NetCode, lastNetCode = -1;
SCH_COMPONENT* Cmp;
wxString InitNetDescLine;
wxString netName;
for( ii = 0; ii < m_masterList->size(); ii++ )
for( const auto& it : m_schematic->ConnectionGraph()->GetNetMap() )
{
NETLIST_OBJECT* nitem = m_masterList->GetItem( ii );
auto subgraphs = it.second;
// Get the NetName of the current net :
if( ( NetCode = nitem->GetNet() ) != lastNetCode )
netName.Printf( wxT( "\"%s\"" ), it.first.first );
std::vector<std::pair<SCH_PIN*, SCH_SHEET_PATH>> sorted_items;
for( auto subgraph : subgraphs )
{
netName = nitem->GetNetName();
netcodeName = wxT( "\"" );
auto sheet = subgraph->m_sheet;
if( !netName.IsEmpty() )
netcodeName << netName;
else // this net has no name: create a default name $<net number>
netcodeName << wxT( "$" ) << NetCode;
netcodeName += wxT( "\"" );
lastNetCode = NetCode;
print_ter = 0;
for( auto item : subgraph->m_items )
if( item->Type() == SCH_PIN_T )
sorted_items.emplace_back(
std::make_pair( static_cast<SCH_PIN*>( item ), sheet ) );
}
// Netlist ordering: Net name, then ref des, then pin name
std::sort( sorted_items.begin(), sorted_items.end(),
[]( auto a, auto b )
{
wxString ref_a = a.first->GetParentComponent()->GetRef( &a.second );
wxString ref_b = b.first->GetParentComponent()->GetRef( &b.second );
if( nitem->m_Type != NETLIST_ITEM::PIN )
continue;
if( ref_a == ref_b )
return a.first->GetNumber() < b.first->GetNumber();
if( nitem->m_Flag != 0 )
continue;
return ref_a < ref_b;
} );
Cmp = nitem->GetComponentParent();
wxString refstr = Cmp->GetRef( &nitem->m_SheetPath );
if( refstr[0] == '#' )
continue; // Power supply symbols.
// Some duplicates can exist, for example on multi-unit parts with duplicated
// pins across units. If the user connects the pins on each unit, they will
// appear on separate subgraphs. Remove those here:
sorted_items.erase( std::unique( sorted_items.begin(), sorted_items.end(),
[]( auto a, auto b )
{
auto ref_a = a.first->GetParentComponent()->GetRef( &a.second );
auto ref_b = b.first->GetParentComponent()->GetRef( &b.second );
switch( print_ter )
return ref_a == ref_b && a.first->GetNumber() == b.first->GetNumber();
} ),
sorted_items.end() );
for( const auto& pair : sorted_items )
{
case 0:
SCH_PIN* pin = pair.first;
SCH_SHEET_PATH sheet = pair.second;
wxString refText = pin->GetParentComponent()->GetRef( &sheet );
wxString pinText = pin->GetNumber();
// Skip power symbols and virtual components
if( refText[0] == wxChar( '#' ) )
continue;
switch( print_ter )
{
InitNetDescLine.Printf( wxT( "\n%s %s %.4s %s" ),
GetChars( InitNetDesc ),
GetChars( refstr ),
GetChars( nitem->m_PinNum ),
GetChars( netcodeName ) );
case 0:
{
InitNetDescLine.Printf( wxT( "\n%s %s %.4s %s" ),
GetChars( InitNetDesc ),
GetChars( refText ),
GetChars( pinText ),
GetChars( netName ) );
}
print_ter++;
break;
case 1:
ret |= fprintf( f, "%s\n", TO_UTF8( InitNetDescLine ) );
ret |= fprintf( f, "%s %s %.4s\n",
TO_UTF8( StartNetDesc ),
TO_UTF8( refText ),
TO_UTF8( pinText ) );
print_ter++;
break;
default:
ret |= fprintf( f, " %s %.4s\n",
TO_UTF8( refText ),
TO_UTF8( pinText ) );
break;
}
print_ter++;
break;
case 1:
ret |= fprintf( f, "%s\n", TO_UTF8( InitNetDescLine ) );
ret |= fprintf( f, "%s %s %.4s\n",
TO_UTF8( StartNetDesc ),
TO_UTF8( refstr ),
TO_UTF8( nitem->m_PinNum ) );
print_ter++;
break;
default:
ret |= fprintf( f, " %s %.4s\n",
TO_UTF8( refstr ),
TO_UTF8( nitem->m_PinNum ) );
break;
}
nitem->m_Flag = 1;
}
return ret >= 0;

View File

@ -48,8 +48,8 @@ class NETLIST_EXPORTER_CADSTAR : public NETLIST_EXPORTER
bool writeListOfNets( FILE* f );
public:
NETLIST_EXPORTER_CADSTAR( NETLIST_OBJECT_LIST* aMasterList, SCHEMATIC* aSchematic ) :
NETLIST_EXPORTER( aMasterList, aSchematic )
NETLIST_EXPORTER_CADSTAR( SCHEMATIC* aSchematic ) :
NETLIST_EXPORTER( aSchematic )
{
}

View File

@ -40,10 +40,6 @@ static bool sortPinsByNumber( LIB_PIN* aPin1, LIB_PIN* aPin2 );
bool NETLIST_EXPORTER_GENERIC::WriteNetlist( const wxString& aOutFileName, unsigned aNetlistOptions )
{
// Prepare list of nets generation
for( unsigned ii = 0; ii < m_masterList->size(); ii++ )
m_masterList->GetItem( ii )->m_Flag = 0;
// output the XML format netlist.
wxXmlDocument xdoc;
@ -201,6 +197,7 @@ XNODE* NETLIST_EXPORTER_GENERIC::makeComponents()
XNODE* xcomps = node( "components" );
m_ReferencesAlreadyFound.Clear();
m_LibParts.clear();
SCH_SHEET_LIST sheetList = m_schematic->GetSheets();
@ -379,11 +376,12 @@ XNODE* NETLIST_EXPORTER_GENERIC::makeLibraries()
wxString libNickname = *it;
XNODE* xlibrary;
if( m_libTable->HasLibrary( libNickname ) )
if( m_schematic->Prj().SchSymbolLibTable()->HasLibrary( libNickname ) )
{
xlibs->AddChild( xlibrary = node( "library" ) );
xlibrary->AddAttribute( "logical", libNickname );
xlibrary->AddChild( node( "uri", m_libTable->GetFullURI( libNickname ) ) );
xlibrary->AddChild( node(
"uri", m_schematic->Prj().SchSymbolLibTable()->GetFullURI( libNickname ) ) );
}
// @todo: add more fun stuff here
@ -496,7 +494,7 @@ XNODE* NETLIST_EXPORTER_GENERIC::makeLibParts()
}
XNODE* NETLIST_EXPORTER_GENERIC::makeListOfNets( bool aUseGraph )
XNODE* NETLIST_EXPORTER_GENERIC::makeListOfNets()
{
XNODE* xnets = node( "nets" ); // auto_ptr if exceptions ever get used.
wxString netCodeTxt;
@ -504,10 +502,6 @@ XNODE* NETLIST_EXPORTER_GENERIC::makeListOfNets( bool aUseGraph )
wxString ref;
XNODE* xnet = 0;
int netCode;
int lastNetCode = -1;
int sameNetcodeCount = 0;
/* output:
<net code="123" name="/cfcard.sch/WAIT#">
@ -516,137 +510,85 @@ XNODE* NETLIST_EXPORTER_GENERIC::makeListOfNets( bool aUseGraph )
</net>
*/
m_LibParts.clear(); // must call this function before using m_LibParts.
int code = 0;
if( aUseGraph )
for( const auto& it : m_schematic->ConnectionGraph()->GetNetMap() )
{
wxASSERT( m_graph );
int code = 0;
bool added = false;
wxString net_name = it.first.first;
auto subgraphs = it.second;
for( const auto& it : m_graph->GetNetMap() )
// Code starts at 1
code++;
XNODE* xnode;
std::vector<std::pair<SCH_PIN*, SCH_SHEET_PATH>> sorted_items;
for( auto subgraph : subgraphs )
{
bool added = false;
wxString net_name = it.first.first;
auto subgraphs = it.second;
auto sheet = subgraph->m_sheet;
// Code starts at 1
code++;
XNODE* xnode;
std::vector<std::pair<SCH_PIN*, SCH_SHEET_PATH>> sorted_items;
for( auto subgraph : subgraphs )
{
auto sheet = subgraph->m_sheet;
for( auto item : subgraph->m_items )
if( item->Type() == SCH_PIN_T )
sorted_items.emplace_back(
std::make_pair( static_cast<SCH_PIN*>( item ), sheet ) );
}
// Netlist ordering: Net name, then ref des, then pin name
std::sort( sorted_items.begin(), sorted_items.end(), [] ( auto a, auto b ) {
auto ref_a = a.first->GetParentComponent()->GetRef( &a.second );
auto ref_b = b.first->GetParentComponent()->GetRef( &b.second );
if( ref_a == ref_b )
return a.first->GetNumber() < b.first->GetNumber();
return ref_a < ref_b;
} );
// Some duplicates can exist, for example on multi-unit parts with duplicated
// pins across units. If the user connects the pins on each unit, they will
// appear on separate subgraphs. Remove those here:
sorted_items.erase( std::unique( sorted_items.begin(), sorted_items.end(),
[] ( auto a, auto b ) {
auto ref_a = a.first->GetParentComponent()->GetRef( &a.second );
auto ref_b = b.first->GetParentComponent()->GetRef( &b.second );
return ref_a == ref_b && a.first->GetNumber() == b.first->GetNumber();
} ), sorted_items.end() );
for( const auto& pair : sorted_items )
{
SCH_PIN* pin = pair.first;
SCH_SHEET_PATH sheet = pair.second;
auto refText = pin->GetParentComponent()->GetRef( &sheet );
const auto& pinText = pin->GetNumber();
// Skip power symbols and virtual components
if( refText[0] == wxChar( '#' ) )
continue;
if( !added )
{
xnets->AddChild( xnet = node( "net" ) );
netCodeTxt.Printf( "%d", code );
xnet->AddAttribute( "code", netCodeTxt );
xnet->AddAttribute( "name", net_name );
added = true;
}
xnet->AddChild( xnode = node( "node" ) );
xnode->AddAttribute( "ref", refText );
xnode->AddAttribute( "pin", pinText );
wxString pinName;
if( pin->GetName() != "~" ) // ~ is a char used to code empty strings in libs.
pinName = pin->GetName();
if( !pinName.IsEmpty() )
xnode->AddAttribute( "pinfunction", pinName );
}
for( auto item : subgraph->m_items )
if( item->Type() == SCH_PIN_T )
sorted_items.emplace_back(
std::make_pair( static_cast<SCH_PIN*>( item ), sheet ) );
}
}
else
{
for( unsigned ii = 0; ii < m_masterList->size(); ii++ )
// Netlist ordering: Net name, then ref des, then pin name
std::sort( sorted_items.begin(), sorted_items.end(), [] ( auto a, auto b ) {
auto ref_a = a.first->GetParentComponent()->GetRef( &a.second );
auto ref_b = b.first->GetParentComponent()->GetRef( &b.second );
if( ref_a == ref_b )
return a.first->GetNumber() < b.first->GetNumber();
return ref_a < ref_b;
} );
// Some duplicates can exist, for example on multi-unit parts with duplicated
// pins across units. If the user connects the pins on each unit, they will
// appear on separate subgraphs. Remove those here:
sorted_items.erase( std::unique( sorted_items.begin(), sorted_items.end(),
[] ( auto a, auto b ) {
auto ref_a = a.first->GetParentComponent()->GetRef( &a.second );
auto ref_b = b.first->GetParentComponent()->GetRef( &b.second );
return ref_a == ref_b && a.first->GetNumber() == b.first->GetNumber();
} ), sorted_items.end() );
for( const auto& pair : sorted_items )
{
NETLIST_OBJECT* nitem = m_masterList->GetItem( ii );
SCH_COMPONENT* comp;
SCH_PIN* pin = pair.first;
SCH_SHEET_PATH sheet = pair.second;
// New net found, write net id;
if( ( netCode = nitem->GetNet() ) != lastNetCode )
{
sameNetcodeCount = 0; // item count for this net
netName = nitem->GetNetName();
lastNetCode = netCode;
}
auto refText = pin->GetParentComponent()->GetRef( &sheet );
const auto& pinText = pin->GetNumber();
if( nitem->m_Type != NETLIST_ITEM::PIN )
// Skip power symbols and virtual components
if( refText[0] == wxChar( '#' ) )
continue;
if( nitem->m_Flag != 0 ) // Redundant pin, skip it
continue;
comp = nitem->GetComponentParent();
// Get the reference for the net name and the main parent component
ref = comp->GetRef( &nitem->m_SheetPath );
if( ref[0] == wxChar( '#' ) )
continue;
if( ++sameNetcodeCount == 1 )
if( !added )
{
xnets->AddChild( xnet = node( "net" ) );
netCodeTxt.Printf( "%d", netCode );
netCodeTxt.Printf( "%d", code );
xnet->AddAttribute( "code", netCodeTxt );
xnet->AddAttribute( "name", netName );
xnet->AddAttribute( "name", net_name );
added = true;
}
XNODE* xnode;
xnet->AddChild( xnode = node( "node" ) );
xnode->AddAttribute( "ref", ref );
xnode->AddAttribute( "pin", nitem->GetPinNumText() );
xnode->AddAttribute( "ref", refText );
xnode->AddAttribute( "pin", pinText );
if( !nitem->GetPinNameText().IsEmpty() )
xnode->AddAttribute( "pinfunction", nitem->GetPinNameText() );
wxString pinName;
if( pin->GetName() != "~" ) // ~ is a char used to code empty strings in libs.
pinName = pin->GetName();
if( !pinName.IsEmpty() )
xnode->AddAttribute( "pinfunction", pinName );
}
}

View File

@ -62,19 +62,9 @@ class NETLIST_EXPORTER_GENERIC : public NETLIST_EXPORTER
private:
std::set< wxString > m_libraries; ///< Set of library nicknames.
SYMBOL_LIB_TABLE* m_libTable;
protected:
CONNECTION_GRAPH* m_graph;
public:
NETLIST_EXPORTER_GENERIC( SCH_EDIT_FRAME* aFrame,
NETLIST_OBJECT_LIST* aMasterList,
SCHEMATIC* aSchematic,
CONNECTION_GRAPH* aGraph = nullptr ) :
NETLIST_EXPORTER( aMasterList, aSchematic ),
m_libTable( aFrame->Prj().SchSymbolLibTable() ),
m_graph( aGraph )
NETLIST_EXPORTER_GENERIC( SCHEMATIC* aSchematic ) :
NETLIST_EXPORTER( aSchematic )
{}
/**
@ -132,7 +122,7 @@ protected:
* fills out an XML node with a list of nets and returns it.
* @return XNODE* - the list of nets nodes
*/
XNODE* makeListOfNets( bool aUseGraph = true );
XNODE* makeListOfNets();
/**
* Function makeLibraries

View File

@ -36,8 +36,6 @@
bool NETLIST_EXPORTER_KICAD::WriteNetlist( const wxString& aOutFileName, unsigned aNetlistOptions )
{
wxASSERT( m_graph );
try
{
FILE_OUTPUTFORMATTER formatter( aOutFileName );
@ -56,10 +54,6 @@ bool NETLIST_EXPORTER_KICAD::WriteNetlist( const wxString& aOutFileName, unsigne
void NETLIST_EXPORTER_KICAD::Format( OUTPUTFORMATTER* aOut, int aCtl )
{
// Prepare list of nets generation
for( unsigned ii = 0; ii < m_masterList->size(); ii++ )
m_masterList->GetItem( ii )->m_Flag = 0;
std::unique_ptr<XNODE> xroot( makeRoot( aCtl ) );
xroot->Format( aOut, 0 );

View File

@ -38,11 +38,8 @@ class OUTPUTFORMATTER;
class NETLIST_EXPORTER_KICAD : public NETLIST_EXPORTER_GENERIC
{
public:
NETLIST_EXPORTER_KICAD( SCH_EDIT_FRAME* aFrame,
NETLIST_OBJECT_LIST* aMasterList,
SCHEMATIC* aSchematic,
CONNECTION_GRAPH* aGraph = nullptr ) :
NETLIST_EXPORTER_GENERIC( aFrame, aMasterList, aSchematic, aGraph )
NETLIST_EXPORTER_KICAD( SCHEMATIC* aSchematic ) :
NETLIST_EXPORTER_GENERIC( aSchematic )
{}
/**

View File

@ -24,8 +24,8 @@
*/
#include <fctsys.h>
#include <build_version.h>
#include <confirm.h>
#include <refdes_utils.h>
#include <sch_edit_frame.h>
#include <sch_reference_list.h>
@ -61,10 +61,6 @@ bool NETLIST_EXPORTER_ORCADPCB2::WriteNetlist( const wxString& aOutFileName,
ret |= fprintf( f, "( { %s created %s }\n",
NETLIST_HEAD_STRING, TO_UTF8( DateAndTime() ) );
// Prepare list of nets generation
for( unsigned ii = 0; ii < m_masterList->size(); ii++ )
m_masterList->GetItem( ii )->m_Flag = 0;
// Create netlist module section
m_ReferencesAlreadyFound.Clear();
@ -72,24 +68,18 @@ bool NETLIST_EXPORTER_ORCADPCB2::WriteNetlist( const wxString& aOutFileName,
for( unsigned i = 0; i < sheetList.size(); i++ )
{
SCH_SHEET_PATH sheet = sheetList[i];
// Process component attributes
for( auto item : sheetList[i].LastScreen()->Items().OfType( SCH_COMPONENT_T ) )
for( auto item : sheet.LastScreen()->Items().OfType( SCH_COMPONENT_T ) )
{
SCH_COMPONENT* comp = findNextComponent( item, &sheetList[i] );
SCH_COMPONENT* comp = findNextComponent( item, &sheet );
if( !comp )
continue;
CreatePinList( comp, &sheetList[i] );
if( comp->GetPartRef() )
{
if( comp->GetPartRef()->GetFootprints().GetCount() != 0 ) // Put in list
{
cmpList.push_back( SCH_REFERENCE( comp, comp->GetPartRef().get(),
sheetList[i] ) );
}
}
if( comp->GetPartRef() && comp->GetPartRef()->GetFootprints().GetCount() != 0 )
cmpList.push_back( SCH_REFERENCE( comp, comp->GetPartRef().get(), sheet ) );
if( !comp->GetField( FOOTPRINT )->IsVoid() )
{
@ -97,7 +87,9 @@ bool NETLIST_EXPORTER_ORCADPCB2::WriteNetlist( const wxString& aOutFileName,
footprint.Replace( wxT( " " ), wxT( "_" ) );
}
else
{
footprint = wxT( "$noname" );
}
field = comp->GetRef( &sheetList[i] );
@ -114,21 +106,27 @@ bool NETLIST_EXPORTER_ORCADPCB2::WriteNetlist( const wxString& aOutFileName,
ret |= fprintf( f, "\n" );
// Write pin list:
for( unsigned ii = 0; ii < m_SortedComponentPinList.size(); ii++ )
std::vector<SCH_PIN*> pins;
for( const auto& pin : comp->GetSchPins( &sheet ) )
pins.emplace_back( pin );
std::sort( pins.begin(), pins.end(),
[]( const SCH_PIN* a, const SCH_PIN* b )
{
return UTIL::RefDesStringCompare( a->GetNumber(), b->GetNumber() ) < 0;
} );
for( const auto* pin : pins )
{
NETLIST_OBJECT* pin = m_SortedComponentPinList[ii];
if( !pin )
continue;
sprintPinNetName( netName, wxT( "N-%.6d" ), pin );
if( netName.IsEmpty() )
if( auto conn = pin->Connection( sheet ) )
netName = conn->Name();
else
netName = wxT( "?" );
netName.Replace( wxT( " " ), wxT( "_" ) );
ret |= fprintf( f, " ( %4.4s %s )\n", TO_UTF8( pin->m_PinNum ),
ret |= fprintf( f, " ( %4.4s %s )\n", TO_UTF8( pin->GetNumber() ),
TO_UTF8( netName ) );
}
@ -140,6 +138,5 @@ bool NETLIST_EXPORTER_ORCADPCB2::WriteNetlist( const wxString& aOutFileName,
fclose( f );
m_SortedComponentPinList.clear();
return ret >= 0;
}

View File

@ -35,8 +35,8 @@
class NETLIST_EXPORTER_ORCADPCB2 : public NETLIST_EXPORTER
{
public:
NETLIST_EXPORTER_ORCADPCB2( NETLIST_OBJECT_LIST* aMasterList, SCHEMATIC* aSchematic ) :
NETLIST_EXPORTER( aMasterList, aSchematic )
NETLIST_EXPORTER_ORCADPCB2( SCHEMATIC* aSchematic ) :
NETLIST_EXPORTER( aSchematic )
{
}

View File

@ -31,8 +31,8 @@
#include <map>
#include <search_stack.h>
#include <connection_graph.h>
#include <sch_edit_frame.h>
#include <netlist.h>
#include <sch_reference_list.h>
#include <env_paths.h>
@ -97,7 +97,7 @@ bool NETLIST_EXPORTER_PSPICE::Format( OUTPUTFORMATTER* aFormatter, unsigned aCtl
if( ( aCtl & NET_ADJUST_INCLUDE_PATHS ) )
{
// Look for the library in known search locations
full_path = ResolveFile( lib, &Pgm().GetLocalEnvVariables(), m_project );
full_path = ResolveFile( lib, &Pgm().GetLocalEnvVariables(), &m_schematic->Prj() );
if( full_path.IsEmpty() )
{
@ -135,19 +135,16 @@ bool NETLIST_EXPORTER_PSPICE::Format( OUTPUTFORMATTER* aFormatter, unsigned aCtl
continue;
}
NETLIST_OBJECT* pin = item.m_pins[activePinIndex];
assert( pin );
wxString netName = pin->GetNetName();
wxString netName = item.m_pins[activePinIndex];
wxASSERT( m_netMap.count( netName ) );
if( useNetcodeAsNetName )
{
assert( m_netMap.count( netName ) );
aFormatter->Print( 0, "%d ", m_netMap[netName] );
}
else
{
sprintPinNetName( netName , wxT( "N-%.6d" ), pin, useNetcodeAsNetName );
// Replace parenthesis with underscore to prevent parse issues with simulators
ReplaceForbiddenChars( netName );
@ -272,30 +269,28 @@ bool NETLIST_EXPORTER_PSPICE::ProcessNetlist( unsigned aCtl )
// Set of reference names, to check for duplications
std::set<wxString> refNames;
// Prepare list of nets generation (not used here, but...
for( unsigned ii = 0; ii < m_masterList->size(); ii++ )
m_masterList->GetItem( ii )->m_Flag = 0;
m_netMap.clear();
m_netMap["GND"] = 0; // 0 is reserved for "GND"
int netIdx = 1;
m_libraries.clear();
m_ReferencesAlreadyFound.Clear();
m_LibParts.clear();
UpdateDirectives( aCtl );
for( unsigned sheet_idx = 0; sheet_idx < sheetList.size(); sheet_idx++ )
{
SCH_SHEET_PATH sheet = sheetList[sheet_idx];
// Process component attributes to find Spice directives
for( auto item : sheetList[sheet_idx].LastScreen()->Items().OfType( SCH_COMPONENT_T ) )
for( auto item : sheet.LastScreen()->Items().OfType( SCH_COMPONENT_T ) )
{
SCH_COMPONENT* comp = findNextComponent( item, &sheetList[sheet_idx] );
SCH_COMPONENT* comp = findNextComponent( item, &sheet );
if( !comp )
continue;
CreatePinList( comp, &sheetList[sheet_idx] );
SPICE_ITEM spiceItem;
spiceItem.m_parent = comp;
@ -305,7 +300,7 @@ bool NETLIST_EXPORTER_PSPICE::ProcessNetlist( unsigned aCtl )
spiceItem.m_primitive = GetSpiceField( SF_PRIMITIVE, comp, aCtl )[0];
spiceItem.m_model = GetSpiceField( SF_MODEL, comp, aCtl );
spiceItem.m_refName = comp->GetRef( &sheetList[sheet_idx] );
spiceItem.m_refName = comp->GetRef( &sheet );
// Duplicate references will result in simulation errors
if( refNames.count( spiceItem.m_refName ) )
@ -326,21 +321,26 @@ bool NETLIST_EXPORTER_PSPICE::ProcessNetlist( unsigned aCtl )
wxArrayString pinNames;
// Store pin information
for( unsigned ii = 0; ii < m_SortedComponentPinList.size(); ii++ )
for( const auto& pin : comp->GetSchPins( &sheet ) )
{
NETLIST_OBJECT* pin = m_SortedComponentPinList[ii];
if( auto conn = pin->Connection( sheet ) )
{
const wxString& netName = conn->Name();
// NETLIST_EXPORTER marks removed pins by setting them to NULL
if( !pin )
continue;
// Skip unconnected pins
CONNECTION_SUBGRAPH* sg =
m_schematic->ConnectionGraph()->FindSubgraphByName( netName, sheet );
spiceItem.m_pins.push_back( pin );
pinNames.Add( pin->GetPinNumText() );
if( !sg || sg->m_no_connect || sg->m_items.size() < 2 )
continue;
// Create net mapping
const wxString& netName = pin->GetNetName();
if( m_netMap.count( netName ) == 0 )
m_netMap[netName] = netIdx++;
// Create net mapping
spiceItem.m_pins.push_back( netName );
pinNames.Add( pin->GetName() );
if( m_netMap.count( netName ) == 0 )
m_netMap[netName] = netIdx++;
}
}
// Check if an alternative pin sequence is available:

View File

@ -87,7 +87,7 @@ struct SPICE_ITEM
bool m_enabled;
///> Array containing Standard Pin Name
std::vector<NETLIST_OBJECT*> m_pins;
std::vector<wxString> m_pins;
///> Numeric indices into m_SortedComponentPinList
std::vector<int> m_pinSequence;
@ -101,10 +101,8 @@ struct SPICE_ITEM
class NETLIST_EXPORTER_PSPICE : public NETLIST_EXPORTER
{
public:
NETLIST_EXPORTER_PSPICE( NETLIST_OBJECT_LIST* aMasterList, SCHEMATIC* aSchematic,
PROJECT* aProject = nullptr ) :
NETLIST_EXPORTER( aMasterList, aSchematic ),
m_project( aProject )
NETLIST_EXPORTER_PSPICE( SCHEMATIC* aSchematic ) :
NETLIST_EXPORTER( aSchematic )
{
}
@ -245,9 +243,6 @@ private:
///> List of items representing schematic components in the Spice world
SPICE_ITEM_LIST m_spiceItems;
///> Project object to fetch its settings (e.g. paths)
PROJECT* m_project;
// Component fields that are processed during netlist export & simulation
static const std::vector<wxString> m_spiceFields;
};

View File

@ -67,20 +67,19 @@ bool SCH_EDIT_FRAME::WriteNetListFile( NETLIST_OBJECT_LIST* aConnectedItemsList,
switch( aFormat )
{
case NET_TYPE_PCBNEW:
helper = new NETLIST_EXPORTER_KICAD(
this, aConnectedItemsList, sch, sch->ConnectionGraph() );
helper = new NETLIST_EXPORTER_KICAD( sch );
break;
case NET_TYPE_ORCADPCB2:
helper = new NETLIST_EXPORTER_ORCADPCB2( aConnectedItemsList, sch );
helper = new NETLIST_EXPORTER_ORCADPCB2( sch );
break;
case NET_TYPE_CADSTAR:
helper = new NETLIST_EXPORTER_CADSTAR( aConnectedItemsList, sch );
helper = new NETLIST_EXPORTER_CADSTAR( sch );
break;
case NET_TYPE_SPICE:
helper = new NETLIST_EXPORTER_PSPICE( aConnectedItemsList, sch );
helper = new NETLIST_EXPORTER_PSPICE( sch );
break;
default:
@ -89,8 +88,7 @@ bool SCH_EDIT_FRAME::WriteNetListFile( NETLIST_OBJECT_LIST* aConnectedItemsList,
tmpFile.SetExt( GENERIC_INTERMEDIATE_NETLIST_EXT );
fileName = tmpFile.GetFullPath();
helper = new NETLIST_EXPORTER_GENERIC( this, aConnectedItemsList, sch,
sch->ConnectionGraph() );
helper = new NETLIST_EXPORTER_GENERIC( sch );
executeCommandLine = true;
}
break;
@ -193,8 +191,7 @@ bool SCH_EDIT_FRAME::prepareForNetlist()
void SCH_EDIT_FRAME::sendNetlistToCvpcb()
{
NETLIST_OBJECT_LIST* net_atoms = BuildNetListBase();
NETLIST_EXPORTER_KICAD exporter( this, net_atoms, &Schematic(), Schematic().ConnectionGraph() );
NETLIST_EXPORTER_KICAD exporter( &Schematic() );
STRING_FORMATTER formatter;
// @todo : trim GNL_ALL down to minimum for CVPCB

View File

@ -46,9 +46,8 @@ struct SPICE_DC_PARAMS
class NETLIST_EXPORTER_PSPICE_SIM : public NETLIST_EXPORTER_PSPICE
{
public:
NETLIST_EXPORTER_PSPICE_SIM( NETLIST_OBJECT_LIST* aMasterList, SCHEMATIC* aSchematic,
PROJECT* aProject = nullptr ) :
NETLIST_EXPORTER_PSPICE( aMasterList, aSchematic, aProject )
NETLIST_EXPORTER_PSPICE_SIM( SCHEMATIC* aSchematic ) :
NETLIST_EXPORTER_PSPICE( aSchematic )
{
}

View File

@ -672,8 +672,7 @@ void SIM_PLOT_FRAME::removePlot( const wxString& aPlotName, bool aErase )
void SIM_PLOT_FRAME::updateNetlistExporter()
{
m_exporter.reset( new NETLIST_EXPORTER_PSPICE_SIM(
m_schematicFrame->BuildNetListBase(), &m_schematicFrame->Schematic(), &Prj() ) );
m_exporter.reset( new NETLIST_EXPORTER_PSPICE_SIM( &m_schematicFrame->Schematic() ) );
}

View File

@ -21,7 +21,7 @@ uViaDrill=0.127
dPairWidth=0.2
dPairGap=0.25
dPairViaGap=0.25
update=Wed 20 May 2020 18:03:51 EDT
update=Thu 21 May 2020 16:15:39 EDT
last_client=eeschema
[pcbnew/Netclasses/1]
Name=pwr
@ -34,6 +34,15 @@ uViaDrill=0.127
dPairWidth=0.2
dPairGap=0.25
dPairViaGap=0.25
[sheetnames]
1=84d4d60f-6656-461e-b8d6-5d42ccee0251:
2=00000000-0000-0000-0000-00004bf03687:buspci.sch
3=00000000-0000-0000-0000-00004bf03683:graphic
4=00000000-0000-0000-0000-00004bf03689:ESVIDEO-RVB
5=00000000-0000-0000-0000-00004bf03681:pal-ntsc.sch
6=00000000-0000-0000-0000-00004bf03685:RAMS
7=00000000-0000-0000-0000-00004bf0367d:muxdata
8=00000000-0000-0000-0000-00004bf0367f:modul
[schematic_editor]
version=1
PageLayoutDescrFile=
@ -56,12 +65,3 @@ ERC_CheckBusDriverConflicts=1
ERC_CheckBusEntryConflicts=1
ERC_CheckBusToBusConflicts=1
ERC_CheckBusToNetConflicts=1
[sheetnames]
1=84d4d60f-6656-461e-b8d6-5d42ccee0251:
2=00000000-0000-0000-0000-00004bf03687:buspci.sch
3=00000000-0000-0000-0000-00004bf03683:graphic
4=00000000-0000-0000-0000-00004bf03689:ESVIDEO-RVB
5=00000000-0000-0000-0000-00004bf03681:pal-ntsc.sch
6=00000000-0000-0000-0000-00004bf03685:RAMS
7=00000000-0000-0000-0000-00004bf0367d:muxdata
8=00000000-0000-0000-0000-00004bf0367f:modul

View File

@ -33,18 +33,24 @@
#include <wx/string.h>
// Code under test
#include <project.h>
#include <schematic.h>
#include <sim/netlist_exporter_pspice_sim.h>
class TEST_NETLIST_EXPORTER_PSPICE_SIM
{
public:
TEST_NETLIST_EXPORTER_PSPICE_SIM()
: m_netlist( new NETLIST_OBJECT_LIST ),
m_exporter( m_netlist, nullptr )
TEST_NETLIST_EXPORTER_PSPICE_SIM() :
m_project(),
m_schematic( &m_project ),
m_exporter( &m_schematic )
{
}
NETLIST_OBJECT_LIST* m_netlist;
PROJECT m_project;
SCHEMATIC m_schematic;
NETLIST_EXPORTER_PSPICE_SIM m_exporter;
};