2018-12-19 23:41:39 +01:00
/*
KLayout Layout Viewer
2021-01-05 22:57:48 +01:00
Copyright ( C ) 2006 - 2021 Matthias Koefferlein
2018-12-19 23:41:39 +01:00
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
*/
# include "dbNetlist.h"
2018-12-24 16:55:22 +01:00
# include <set>
2018-12-19 23:41:39 +01:00
namespace db
{
// --------------------------------------------------------------------------------
// Netlist class implementation
2019-07-26 19:07:19 +02:00
Netlist : : Netlist ( NetlistManipulationCallbacks * callbacks )
2021-03-24 22:11:15 +01:00
: m_case_sensitive ( true ) , mp_callbacks ( callbacks ) ,
2019-07-26 19:07:19 +02:00
m_valid_topology ( false ) , m_lock_count ( 0 ) ,
2018-12-30 13:00:03 +01:00
m_circuit_by_name ( this , & Netlist : : begin_circuits , & Netlist : : end_circuits ) ,
2019-01-19 23:00:19 +01:00
m_circuit_by_cell_index ( this , & Netlist : : begin_circuits , & Netlist : : end_circuits ) ,
2019-01-21 22:37:13 +01:00
m_device_abstract_by_name ( this , & Netlist : : begin_device_abstracts , & Netlist : : end_device_abstracts ) ,
m_device_abstract_by_cell_index ( this , & Netlist : : begin_device_abstracts , & Netlist : : end_device_abstracts )
2018-12-19 23:41:39 +01:00
{
2018-12-29 00:48:28 +01:00
m_circuits . changed ( ) . add ( this , & Netlist : : invalidate_topology ) ;
2018-12-30 22:37:31 +01:00
m_circuits . changed ( ) . add ( this , & Netlist : : circuits_changed ) ;
2019-01-21 22:37:13 +01:00
m_device_abstracts . changed ( ) . add ( this , & Netlist : : device_abstracts_changed ) ;
2018-12-19 23:41:39 +01:00
}
Netlist : : Netlist ( const Netlist & other )
2021-03-24 22:11:15 +01:00
: gsi : : ObjectBase ( other ) , tl : : Object ( other ) , m_case_sensitive ( true ) ,
m_valid_topology ( false ) , m_lock_count ( 0 ) ,
2018-12-30 13:00:03 +01:00
m_circuit_by_name ( this , & Netlist : : begin_circuits , & Netlist : : end_circuits ) ,
2019-01-19 23:00:19 +01:00
m_circuit_by_cell_index ( this , & Netlist : : begin_circuits , & Netlist : : end_circuits ) ,
2019-01-21 22:37:13 +01:00
m_device_abstract_by_name ( this , & Netlist : : begin_device_abstracts , & Netlist : : end_device_abstracts ) ,
m_device_abstract_by_cell_index ( this , & Netlist : : begin_device_abstracts , & Netlist : : end_device_abstracts )
2018-12-19 23:41:39 +01:00
{
operator = ( other ) ;
2018-12-29 00:48:28 +01:00
m_circuits . changed ( ) . add ( this , & Netlist : : invalidate_topology ) ;
2018-12-30 22:37:31 +01:00
m_circuits . changed ( ) . add ( this , & Netlist : : circuits_changed ) ;
2019-01-21 22:37:13 +01:00
m_device_abstracts . changed ( ) . add ( this , & Netlist : : device_abstracts_changed ) ;
2018-12-19 23:41:39 +01:00
}
2018-12-31 17:33:14 +01:00
Netlist : : ~ Netlist ( )
{
m_circuits . changed ( ) . remove ( this , & Netlist : : invalidate_topology ) ;
m_circuits . changed ( ) . remove ( this , & Netlist : : circuits_changed ) ;
2019-01-21 22:37:13 +01:00
m_device_abstracts . changed ( ) . remove ( this , & Netlist : : device_abstracts_changed ) ;
2018-12-31 17:33:14 +01:00
}
2018-12-19 23:41:39 +01:00
Netlist & Netlist : : operator = ( const Netlist & other )
{
if ( this ! = & other ) {
2018-12-29 00:48:28 +01:00
clear ( ) ;
2021-03-24 22:11:15 +01:00
set_case_sensitive ( other . is_case_sensitive ( ) ) ;
2018-12-20 22:11:20 +01:00
std : : map < const DeviceClass * , DeviceClass * > dct ;
2018-12-19 23:41:39 +01:00
for ( const_device_class_iterator dc = other . begin_device_classes ( ) ; dc ! = other . end_device_classes ( ) ; + + dc ) {
2018-12-20 22:11:20 +01:00
DeviceClass * dc_new = dc - > clone ( ) ;
dct [ dc . operator - > ( ) ] = dc_new ;
m_device_classes . push_back ( dc_new ) ;
2018-12-19 23:41:39 +01:00
}
2019-01-21 22:37:13 +01:00
std : : map < const DeviceAbstract * , DeviceAbstract * > dmt ;
for ( const_abstract_model_iterator dm = other . begin_device_abstracts ( ) ; dm ! = other . end_device_abstracts ( ) ; + + dm ) {
DeviceAbstract * dm_new = new DeviceAbstract ( * dm ) ;
2019-01-15 23:03:25 +01:00
dmt [ dm . operator - > ( ) ] = dm_new ;
2019-01-21 22:37:13 +01:00
m_device_abstracts . push_back ( dm_new ) ;
2019-01-15 23:03:25 +01:00
}
2018-12-20 22:11:20 +01:00
std : : map < const Circuit * , Circuit * > ct ;
for ( const_circuit_iterator i = other . begin_circuits ( ) ; i ! = other . end_circuits ( ) ; + + i ) {
Circuit * ct_new = new Circuit ( * i ) ;
ct_new - > translate_device_classes ( dct ) ;
2019-01-21 22:37:13 +01:00
ct_new - > translate_device_abstracts ( dmt ) ;
2018-12-20 22:11:20 +01:00
ct [ i . operator - > ( ) ] = ct_new ;
add_circuit ( ct_new ) ;
}
for ( circuit_iterator i = begin_circuits ( ) ; i ! = end_circuits ( ) ; + + i ) {
i - > translate_circuits ( ct ) ;
}
}
2018-12-19 23:41:39 +01:00
return * this ;
}
2021-04-26 22:26:31 +02:00
void Netlist : : mem_stat ( MemStatistics * stat , MemStatistics : : purpose_t purpose , int cat , bool no_self , void * parent ) const
{
if ( ! no_self ) {
stat - > add ( typeid ( * this ) , ( void * ) this , sizeof ( * this ) , sizeof ( * this ) , parent , purpose , cat ) ;
}
db : : mem_stat ( stat , purpose , cat , m_circuits , true , ( void * ) this ) ;
db : : mem_stat ( stat , purpose , cat , m_device_classes , true , ( void * ) this ) ;
db : : mem_stat ( stat , purpose , cat , m_device_abstracts , true , ( void * ) this ) ;
db : : mem_stat ( stat , purpose , cat , m_top_down_circuits , true , ( void * ) this ) ;
db : : mem_stat ( stat , purpose , cat , m_child_circuits , true , ( void * ) this ) ;
db : : mem_stat ( stat , purpose , cat , m_parent_circuits , true , ( void * ) this ) ;
db : : mem_stat ( stat , purpose , cat , m_circuit_by_name , true , ( void * ) this ) ;
db : : mem_stat ( stat , purpose , cat , m_circuit_by_cell_index , true , ( void * ) this ) ;
db : : mem_stat ( stat , purpose , cat , m_device_abstract_by_name , true , ( void * ) this ) ;
db : : mem_stat ( stat , purpose , cat , m_device_abstract_by_cell_index , true , ( void * ) this ) ;
}
2021-03-24 22:11:15 +01:00
void Netlist : : set_case_sensitive ( bool f )
{
m_case_sensitive = f ;
}
int Netlist : : name_compare ( bool case_sensitive , const std : : string & n1 , const std : : string & n2 )
{
// TODO: unicode support?
if ( case_sensitive ) {
return strcmp ( n1 . c_str ( ) , n2 . c_str ( ) ) ;
} else {
# if defined(_WIN32)
return _stricmp ( n1 . c_str ( ) , n2 . c_str ( ) ) ;
# else
return strcasecmp ( n1 . c_str ( ) , n2 . c_str ( ) ) ;
# endif
}
}
std : : string Netlist : : normalize_name ( bool case_sensitive , const std : : string & n )
{
if ( case_sensitive ) {
return n ;
} else {
return tl : : to_upper_case ( n ) ;
}
}
2018-12-30 22:37:31 +01:00
void Netlist : : circuits_changed ( )
{
m_circuit_by_cell_index . invalidate ( ) ;
m_circuit_by_name . invalidate ( ) ;
}
2019-01-21 22:37:13 +01:00
void Netlist : : device_abstracts_changed ( )
2019-01-19 23:00:19 +01:00
{
2019-01-21 22:37:13 +01:00
m_device_abstract_by_cell_index . invalidate ( ) ;
m_device_abstract_by_name . invalidate ( ) ;
2019-01-19 23:00:19 +01:00
}
2018-12-29 00:48:28 +01:00
void Netlist : : invalidate_topology ( )
{
if ( m_valid_topology ) {
2018-12-29 01:04:48 +01:00
2018-12-29 00:48:28 +01:00
m_valid_topology = false ;
2018-12-29 01:04:48 +01:00
if ( m_lock_count = = 0 ) {
m_top_circuits = 0 ;
m_top_down_circuits . clear ( ) ;
m_child_circuits . clear ( ) ;
m_parent_circuits . clear ( ) ;
}
2018-12-29 00:48:28 +01:00
}
}
namespace {
struct sort_by_index
{
bool operator ( ) ( const Circuit * a , const Circuit * b ) const
{
return a - > index ( ) < b - > index ( ) ;
}
} ;
}
void Netlist : : validate_topology ( )
{
if ( m_valid_topology ) {
return ;
2018-12-29 01:04:48 +01:00
} else if ( m_lock_count > 0 ) {
return ;
2018-12-29 00:48:28 +01:00
}
m_child_circuits . clear ( ) ;
m_parent_circuits . clear ( ) ;
size_t max_index = 0 ;
for ( circuit_iterator c = begin_circuits ( ) ; c ! = end_circuits ( ) ; + + c ) {
c - > set_index ( max_index ) ;
+ + max_index ;
}
// build the child circuit list ... needed for the topology sorting
m_child_circuits . reserve ( max_index ) ;
m_parent_circuits . reserve ( max_index ) ;
for ( circuit_iterator c = begin_circuits ( ) ; c ! = end_circuits ( ) ; + + c ) {
std : : set < Circuit * > children ;
for ( Circuit : : subcircuit_iterator sc = c - > begin_subcircuits ( ) ; sc ! = c - > end_subcircuits ( ) ; + + sc ) {
if ( sc - > circuit_ref ( ) ) {
children . insert ( sc - > circuit_ref ( ) ) ;
}
}
m_child_circuits . push_back ( tl : : vector < Circuit * > ( ) ) ;
tl : : vector < Circuit * > & cc = m_child_circuits . back ( ) ;
cc . reserve ( children . size ( ) ) ;
cc . insert ( cc . end ( ) , children . begin ( ) , children . end ( ) ) ;
// sort by index for better reproducibility
std : : sort ( cc . begin ( ) , cc . end ( ) , sort_by_index ( ) ) ;
std : : set < Circuit * > parents ;
for ( Circuit : : refs_iterator sc = c - > begin_refs ( ) ; sc ! = c - > end_refs ( ) ; + + sc ) {
if ( sc - > circuit ( ) ) {
parents . insert ( sc - > circuit ( ) ) ;
}
}
m_parent_circuits . push_back ( tl : : vector < Circuit * > ( ) ) ;
tl : : vector < Circuit * > & pc = m_parent_circuits . back ( ) ;
pc . reserve ( parents . size ( ) ) ;
pc . insert ( pc . end ( ) , parents . begin ( ) , parents . end ( ) ) ;
// sort by index for better reproducibility
std : : sort ( pc . begin ( ) , pc . end ( ) , sort_by_index ( ) ) ;
}
// do topology sorting
m_top_circuits = 0 ;
m_top_down_circuits . clear ( ) ;
m_top_down_circuits . reserve ( max_index ) ;
std : : vector < size_t > num_parents ( max_index , 0 ) ;
// while there are cells to treat ..
while ( m_top_down_circuits . size ( ) ! = max_index ) {
size_t n_top_down_circuits = m_top_down_circuits . size ( ) ;
// Treat all circuits that do not have all parents reported.
// For all such a circuits, disable the parent counting,
// add the circuits's index to the top-down sorted list and
// increment the reported parent count in all the
// child circuits.
for ( circuit_iterator c = begin_circuits ( ) ; c ! = end_circuits ( ) ; + + c ) {
if ( m_parent_circuits [ c - > index ( ) ] . size ( ) = = num_parents [ c - > index ( ) ] ) {
m_top_down_circuits . push_back ( c . operator - > ( ) ) ;
num_parents [ c - > index ( ) ] = std : : numeric_limits < cell_index_type > : : max ( ) ;
}
}
// For all these a circuits, increment the reported parent instance
// count in all the child circuits.
for ( tl : : vector < Circuit * > : : const_iterator ii = m_top_down_circuits . begin ( ) + n_top_down_circuits ; ii ! = m_top_down_circuits . end ( ) ; + + ii ) {
const tl : : vector < Circuit * > & cc = m_child_circuits [ ( * ii ) - > index ( ) ] ;
for ( tl : : vector < Circuit * > : : const_iterator icc = cc . begin ( ) ; icc ! = cc . end ( ) ; + + icc ) {
tl_assert ( num_parents [ ( * icc ) - > index ( ) ] ! = std : : numeric_limits < cell_index_type > : : max ( ) ) ;
num_parents [ ( * icc ) - > index ( ) ] + = 1 ;
}
}
// If no new cells have been reported this is basically a
// sign of recursion in the graph.
if ( n_top_down_circuits = = m_top_down_circuits . size ( ) ) {
throw tl : : Exception ( tl : : to_string ( tr ( " Recursive hierarchy detected in netlist " ) ) ) ;
}
2019-05-10 00:15:51 +02:00
// doing this reverse will mean we preserve bottom-up order. This is useful for
// netlists where subcircuits have to be defined before they are used.
std : : reverse ( m_top_down_circuits . begin ( ) + n_top_down_circuits , m_top_down_circuits . end ( ) ) ;
2018-12-29 00:48:28 +01:00
}
// Determine the number of top cells
for ( tl : : vector < Circuit * > : : const_iterator e = m_top_down_circuits . begin ( ) ; e ! = m_top_down_circuits . end ( ) & & m_parent_circuits [ ( * e ) - > index ( ) ] . empty ( ) ; + + e ) {
+ + m_top_circuits ;
}
m_valid_topology = true ;
}
2018-12-29 01:04:48 +01:00
void Netlist : : lock ( )
{
if ( m_lock_count = = 0 ) {
validate_topology ( ) ;
}
+ + m_lock_count ;
}
void Netlist : : unlock ( )
{
if ( m_lock_count > 0 ) {
- - m_lock_count ;
}
}
2018-12-29 00:48:28 +01:00
const tl : : vector < Circuit * > & Netlist : : child_circuits ( Circuit * circuit )
{
2020-07-05 19:02:43 +02:00
if ( circuit - > netlist ( ) ! = this ) {
throw tl : : Exception ( tl : : to_string ( tr ( " Circuit not within given netlist " ) ) ) ;
}
2018-12-29 00:48:28 +01:00
if ( ! m_valid_topology ) {
validate_topology ( ) ;
}
tl_assert ( circuit - > index ( ) < m_child_circuits . size ( ) ) ;
return m_child_circuits [ circuit - > index ( ) ] ;
}
const tl : : vector < Circuit * > & Netlist : : parent_circuits ( Circuit * circuit )
{
2020-07-05 19:02:43 +02:00
if ( circuit - > netlist ( ) ! = this ) {
throw tl : : Exception ( tl : : to_string ( tr ( " Circuit not within given netlist " ) ) ) ;
}
2018-12-29 00:48:28 +01:00
if ( ! m_valid_topology ) {
validate_topology ( ) ;
}
tl_assert ( circuit - > index ( ) < m_parent_circuits . size ( ) ) ;
return m_parent_circuits [ circuit - > index ( ) ] ;
}
Netlist : : top_down_circuit_iterator Netlist : : begin_top_down ( )
{
if ( ! m_valid_topology ) {
validate_topology ( ) ;
}
return m_top_down_circuits . begin ( ) ;
}
Netlist : : top_down_circuit_iterator Netlist : : end_top_down ( )
{
if ( ! m_valid_topology ) {
validate_topology ( ) ;
}
return m_top_down_circuits . end ( ) ;
}
Netlist : : const_top_down_circuit_iterator Netlist : : begin_top_down ( ) const
{
if ( ! m_valid_topology ) {
const_cast < Netlist * > ( this ) - > validate_topology ( ) ;
}
return reinterpret_cast < const tl : : vector < const Circuit * > & > ( m_top_down_circuits ) . begin ( ) ;
}
Netlist : : const_top_down_circuit_iterator Netlist : : end_top_down ( ) const
{
if ( ! m_valid_topology ) {
const_cast < Netlist * > ( this ) - > validate_topology ( ) ;
}
return reinterpret_cast < const tl : : vector < const Circuit * > & > ( m_top_down_circuits ) . end ( ) ;
}
size_t Netlist : : top_circuit_count ( ) const
{
if ( ! m_valid_topology ) {
const_cast < Netlist * > ( this ) - > validate_topology ( ) ;
}
return m_top_circuits ;
}
Netlist : : bottom_up_circuit_iterator Netlist : : begin_bottom_up ( )
{
if ( ! m_valid_topology ) {
validate_topology ( ) ;
}
return m_top_down_circuits . rbegin ( ) ;
}
Netlist : : bottom_up_circuit_iterator Netlist : : end_bottom_up ( )
{
if ( ! m_valid_topology ) {
validate_topology ( ) ;
}
return m_top_down_circuits . rend ( ) ;
}
Netlist : : const_bottom_up_circuit_iterator Netlist : : begin_bottom_up ( ) const
{
if ( ! m_valid_topology ) {
const_cast < Netlist * > ( this ) - > validate_topology ( ) ;
}
return reinterpret_cast < const tl : : vector < const Circuit * > & > ( m_top_down_circuits ) . rbegin ( ) ;
}
Netlist : : const_bottom_up_circuit_iterator Netlist : : end_bottom_up ( ) const
{
if ( ! m_valid_topology ) {
const_cast < Netlist * > ( this ) - > validate_topology ( ) ;
}
return reinterpret_cast < const tl : : vector < const Circuit * > & > ( m_top_down_circuits ) . rend ( ) ;
}
2018-12-19 23:41:39 +01:00
void Netlist : : clear ( )
{
m_device_classes . clear ( ) ;
2019-01-21 22:37:13 +01:00
m_device_abstracts . clear ( ) ;
2018-12-19 23:41:39 +01:00
m_circuits . clear ( ) ;
}
void Netlist : : add_circuit ( Circuit * circuit )
{
2020-07-05 19:02:43 +02:00
if ( ! circuit ) {
return ;
}
if ( circuit - > netlist ( ) ) {
throw tl : : Exception ( tl : : to_string ( tr ( " Circuit already contained in a netlist " ) ) ) ;
}
2018-12-19 23:41:39 +01:00
m_circuits . push_back ( circuit ) ;
2018-12-21 22:13:37 +01:00
circuit - > set_netlist ( this ) ;
2018-12-19 23:41:39 +01:00
}
void Netlist : : remove_circuit ( Circuit * circuit )
{
2020-07-05 19:02:43 +02:00
if ( ! circuit ) {
return ;
}
if ( circuit - > netlist ( ) ! = this ) {
throw tl : : Exception ( tl : : to_string ( tr ( " Circuit not within given netlist " ) ) ) ;
}
2018-12-24 13:52:17 +01:00
circuit - > set_netlist ( 0 ) ;
2018-12-19 23:41:39 +01:00
m_circuits . erase ( circuit ) ;
}
2019-07-06 19:50:20 +02:00
void Netlist : : purge_circuit ( Circuit * circuit )
{
2020-07-05 19:02:43 +02:00
if ( ! circuit ) {
return ;
}
if ( circuit - > netlist ( ) ! = this ) {
throw tl : : Exception ( tl : : to_string ( tr ( " Circuit not within given netlist " ) ) ) ;
}
2019-07-06 19:50:20 +02:00
circuit - > blank ( ) ;
remove_circuit ( circuit ) ;
}
2019-10-21 22:14:36 +02:00
void Netlist : : flatten_circuits ( const std : : vector < Circuit * > & circuits )
{
if ( circuits . empty ( ) ) {
return ;
}
std : : set < Circuit * > circuits_set ( circuits . begin ( ) , circuits . end ( ) ) ;
std : : vector < Circuit * > to_flatten ;
to_flatten . reserve ( circuits . size ( ) ) ;
// Before flatten, we sort top-down. This optimizes for the case of flattening away
// some hierarchy above a certain circuit.
for ( top_down_circuit_iterator c = begin_top_down ( ) ; c ! = end_top_down ( ) ; + + c ) {
if ( circuits_set . find ( c . operator - > ( ) ) ! = circuits_set . end ( ) ) {
to_flatten . push_back ( c . operator - > ( ) ) ;
}
}
for ( std : : vector < Circuit * > : : const_iterator c = to_flatten . begin ( ) ; c ! = to_flatten . end ( ) ; + + c ) {
flatten_circuit ( * c ) ;
}
}
2019-04-06 23:36:08 +02:00
void Netlist : : flatten_circuit ( Circuit * circuit )
{
2020-07-05 19:02:43 +02:00
if ( ! circuit ) {
return ;
}
if ( circuit - > netlist ( ) ! = this ) {
throw tl : : Exception ( tl : : to_string ( tr ( " Circuit not within given netlist " ) ) ) ;
}
2019-04-07 10:15:57 +02:00
2019-04-06 23:36:08 +02:00
std : : vector < db : : SubCircuit * > refs ;
for ( db : : Circuit : : refs_iterator sc = circuit - > begin_refs ( ) ; sc ! = circuit - > end_refs ( ) ; + + sc ) {
refs . push_back ( sc . operator - > ( ) ) ;
}
for ( std : : vector < db : : SubCircuit * > : : const_iterator r = refs . begin ( ) ; r ! = refs . end ( ) ; + + r ) {
( * r ) - > circuit ( ) - > flatten_subcircuit ( * r ) ;
}
2019-04-07 10:15:57 +02:00
delete circuit ;
2019-04-06 23:36:08 +02:00
}
2019-09-06 23:13:21 +02:00
void Netlist : : flatten ( )
{
std : : set < db : : Circuit * > top_circuits ;
size_t ntop = top_circuit_count ( ) ;
for ( db : : Netlist : : top_down_circuit_iterator tc = begin_top_down ( ) ; tc ! = end_top_down ( ) & & ntop > 0 ; + + tc ) {
top_circuits . insert ( tc . operator - > ( ) ) ;
- - ntop ;
}
for ( db : : Netlist : : bottom_up_circuit_iterator c = begin_bottom_up ( ) ; c ! = end_bottom_up ( ) ; + + c ) {
if ( top_circuits . find ( c . operator - > ( ) ) = = top_circuits . end ( ) ) {
flatten_circuit ( c . operator - > ( ) ) ;
}
}
}
2019-03-28 18:01:22 +01:00
DeviceClass * Netlist : : device_class_by_name ( const std : : string & name )
{
2021-03-24 22:11:15 +01:00
std : : string nn = m_case_sensitive ? name : normalize_name ( name ) ;
2019-03-28 18:01:22 +01:00
for ( device_class_iterator d = begin_device_classes ( ) ; d ! = end_device_classes ( ) ; + + d ) {
2021-03-24 22:11:15 +01:00
if ( d - > name ( ) = = nn ) {
2019-03-28 18:01:22 +01:00
return d . operator - > ( ) ;
}
}
return 0 ;
}
2018-12-19 23:41:39 +01:00
void Netlist : : add_device_class ( DeviceClass * device_class )
{
2020-07-05 19:02:43 +02:00
if ( ! device_class ) {
return ;
}
if ( device_class - > netlist ( ) ) {
throw tl : : Exception ( tl : : to_string ( tr ( " Device class already contained in a netlist " ) ) ) ;
}
2018-12-19 23:41:39 +01:00
m_device_classes . push_back ( device_class ) ;
2018-12-24 13:52:17 +01:00
device_class - > set_netlist ( this ) ;
2018-12-19 23:41:39 +01:00
}
void Netlist : : remove_device_class ( DeviceClass * device_class )
{
2020-07-05 19:02:43 +02:00
if ( ! device_class ) {
return ;
}
if ( device_class - > netlist ( ) ! = this ) {
throw tl : : Exception ( tl : : to_string ( tr ( " Device class not within given netlist " ) ) ) ;
}
2018-12-24 13:52:17 +01:00
device_class - > set_netlist ( 0 ) ;
2018-12-19 23:41:39 +01:00
m_device_classes . erase ( device_class ) ;
}
2019-01-21 22:37:13 +01:00
void Netlist : : add_device_abstract ( DeviceAbstract * device_abstract )
2019-01-15 23:03:25 +01:00
{
2020-07-05 19:02:43 +02:00
if ( ! device_abstract ) {
return ;
}
if ( device_abstract - > netlist ( ) ) {
throw tl : : Exception ( tl : : to_string ( tr ( " Device abstract already contained in a netlist " ) ) ) ;
}
2019-01-21 22:37:13 +01:00
m_device_abstracts . push_back ( device_abstract ) ;
device_abstract - > set_netlist ( this ) ;
2019-01-15 23:03:25 +01:00
}
2019-01-21 22:37:13 +01:00
void Netlist : : remove_device_abstract ( DeviceAbstract * device_abstract )
2019-01-15 23:03:25 +01:00
{
2020-07-05 19:02:43 +02:00
if ( ! device_abstract ) {
return ;
}
if ( device_abstract - > netlist ( ) ! = this ) {
throw tl : : Exception ( tl : : to_string ( tr ( " Device abstract not within given netlist " ) ) ) ;
}
2019-01-21 22:37:13 +01:00
device_abstract - > set_netlist ( 0 ) ;
m_device_abstracts . erase ( device_abstract ) ;
2019-01-15 23:03:25 +01:00
}
2018-12-25 00:25:07 +01:00
void Netlist : : purge_nets ( )
{
2019-11-23 01:20:22 +01:00
for ( bottom_up_circuit_iterator c = begin_bottom_up ( ) ; c ! = end_bottom_up ( ) ; + + c ) {
2018-12-25 00:25:07 +01:00
c - > purge_nets ( ) ;
}
}
2018-12-29 20:50:35 +01:00
void Netlist : : make_top_level_pins ( )
{
size_t ntop = top_circuit_count ( ) ;
for ( top_down_circuit_iterator c = begin_top_down ( ) ; c ! = end_top_down ( ) & & ntop > 0 ; + + c , - - ntop ) {
2019-06-06 01:36:07 +02:00
Circuit * circuit = c . operator - > ( ) ;
2018-12-29 20:50:35 +01:00
if ( circuit - > pin_count ( ) = = 0 ) {
// create pins for the named nets and connect them
for ( Circuit : : net_iterator n = circuit - > begin_nets ( ) ; n ! = circuit - > end_nets ( ) ; + + n ) {
2019-01-06 12:53:22 +01:00
if ( ! n - > name ( ) . empty ( ) & & n - > terminal_count ( ) + n - > subcircuit_pin_count ( ) > 0 ) {
2018-12-30 13:37:52 +01:00
Pin pin = circuit - > add_pin ( n - > name ( ) ) ;
2018-12-29 20:50:35 +01:00
circuit - > connect_pin ( pin . id ( ) , n . operator - > ( ) ) ;
}
}
}
}
}
void Netlist : : purge ( )
{
// This locking is very important as we do not want to recompute the bottom-up list
// while iterating.
NetlistLocker locker ( this ) ;
for ( bottom_up_circuit_iterator c = begin_bottom_up ( ) ; c ! = end_bottom_up ( ) ; + + c ) {
2019-06-06 01:36:07 +02:00
Circuit * circuit = c . operator - > ( ) ;
2018-12-29 20:50:35 +01:00
2019-09-30 20:58:55 +02:00
// purge floating, disconnected nets
2018-12-29 20:50:35 +01:00
circuit - > purge_nets ( ) ;
2019-09-30 20:58:55 +02:00
2019-09-30 21:58:13 +02:00
// if only passive nets are left, consider this circuit for purging
2019-09-30 20:58:55 +02:00
bool purge_candidate = ! circuit - > dont_purge ( ) ;
for ( db : : Circuit : : net_iterator n = circuit - > begin_nets ( ) ; n ! = circuit - > end_nets ( ) & & purge_candidate ; + + n ) {
2019-09-30 21:58:13 +02:00
purge_candidate = n - > is_passive ( ) ;
2019-09-30 20:58:55 +02:00
}
if ( purge_candidate ) {
2018-12-29 20:50:35 +01:00
// No nets left: delete the subcircuits that refer to us and finally delete the circuit
while ( circuit - > begin_refs ( ) ! = circuit - > end_refs ( ) ) {
delete circuit - > begin_refs ( ) . operator - > ( ) ;
}
delete circuit ;
}
}
}
2018-12-25 00:25:07 +01:00
void Netlist : : combine_devices ( )
{
for ( circuit_iterator c = begin_circuits ( ) ; c ! = end_circuits ( ) ; + + c ) {
c - > combine_devices ( ) ;
}
}
2019-06-22 22:18:55 +02:00
void Netlist : : simplify ( )
{
make_top_level_pins ( ) ;
purge ( ) ;
combine_devices ( ) ;
purge_nets ( ) ;
}
2018-12-29 22:18:58 +01:00
static std : : string net2string ( const db : : Net * net )
{
return net ? tl : : to_word_or_quoted_string ( net - > expanded_name ( ) ) : " (null) " ;
}
static std : : string device2string ( const db : : Device & device )
{
if ( device . name ( ) . empty ( ) ) {
return " $ " + tl : : to_string ( device . id ( ) ) ;
} else {
return tl : : to_word_or_quoted_string ( device . name ( ) ) ;
}
}
static std : : string subcircuit2string ( const db : : SubCircuit & subcircuit )
{
if ( subcircuit . name ( ) . empty ( ) ) {
return " $ " + tl : : to_string ( subcircuit . id ( ) ) ;
} else {
return tl : : to_word_or_quoted_string ( subcircuit . name ( ) ) ;
}
}
static std : : string pin2string ( const db : : Pin & pin )
{
if ( pin . name ( ) . empty ( ) ) {
// the pin ID is zero-based and essentially the index, so we add 1 to make it compliant with the other IDs
return " $ " + tl : : to_string ( pin . id ( ) + 1 ) ;
} else {
return tl : : to_word_or_quoted_string ( pin . name ( ) ) ;
}
}
2019-03-19 00:08:47 +01:00
std : : string Netlist : : to_string ( ) const
2019-03-18 02:00:33 +01:00
{
std : : string res ;
for ( db : : Netlist : : const_circuit_iterator c = begin_circuits ( ) ; c ! = end_circuits ( ) ; + + c ) {
std : : string ps ;
for ( db : : Circuit : : const_pin_iterator p = c - > begin_pins ( ) ; p ! = c - > end_pins ( ) ; + + p ) {
if ( ! ps . empty ( ) ) {
ps + = " , " ;
}
ps + = pin2string ( * p ) + " = " + net2string ( c - > net_for_pin ( p - > id ( ) ) ) ;
}
2019-03-18 19:28:20 +01:00
res + = std : : string ( " circuit " ) + tl : : to_word_or_quoted_string ( c - > name ( ) ) + " ( " + ps + " ); \n " ;
2019-03-18 02:00:33 +01:00
for ( db : : Circuit : : const_device_iterator d = c - > begin_devices ( ) ; d ! = c - > end_devices ( ) ; + + d ) {
std : : string ts ;
const std : : vector < db : : DeviceTerminalDefinition > & td = d - > device_class ( ) - > terminal_definitions ( ) ;
for ( std : : vector < db : : DeviceTerminalDefinition > : : const_iterator t = td . begin ( ) ; t ! = td . end ( ) ; + + t ) {
if ( t ! = td . begin ( ) ) {
2019-03-18 19:28:20 +01:00
ts + = " , " ;
2019-03-18 02:00:33 +01:00
}
ts + = t - > name ( ) + " = " + net2string ( d - > net_for_terminal ( t - > id ( ) ) ) ;
}
std : : string ps ;
const std : : vector < db : : DeviceParameterDefinition > & pd = d - > device_class ( ) - > parameter_definitions ( ) ;
for ( std : : vector < db : : DeviceParameterDefinition > : : const_iterator p = pd . begin ( ) ; p ! = pd . end ( ) ; + + p ) {
if ( p ! = pd . begin ( ) ) {
ps + = " , " ;
}
2019-05-29 21:35:02 +02:00
ps + = p - > name ( ) + " = " + tl : : sprintf ( " %.12g " , d - > parameter_value ( p - > id ( ) ) ) ;
2019-03-18 02:00:33 +01:00
}
res + = std : : string ( " device " ) + tl : : to_word_or_quoted_string ( d - > device_class ( ) - > name ( ) ) + " " + device2string ( * d ) + " ( " + ts + " ) ( " + ps + " ); \n " ;
}
for ( db : : Circuit : : const_subcircuit_iterator sc = c - > begin_subcircuits ( ) ; sc ! = c - > end_subcircuits ( ) ; + + sc ) {
std : : string ps ;
const db : : SubCircuit & subcircuit = * sc ;
const db : : Circuit * circuit = sc - > circuit_ref ( ) ;
2019-07-06 19:50:20 +02:00
if ( circuit ) {
for ( db : : Circuit : : const_pin_iterator p = circuit - > begin_pins ( ) ; p ! = circuit - > end_pins ( ) ; + + p ) {
if ( p ! = circuit - > begin_pins ( ) ) {
ps + = " , " ;
}
ps + = pin2string ( * p ) + " = " + net2string ( subcircuit . net_for_pin ( p - > id ( ) ) ) ;
2019-03-18 02:00:33 +01:00
}
2019-07-06 19:50:20 +02:00
res + = std : : string ( " subcircuit " ) + tl : : to_word_or_quoted_string ( circuit - > name ( ) ) + " " + subcircuit2string ( * sc ) + " ( " + ps + " ); \n " ;
} else {
res + = std : : string ( " subcircuit (null); \n " ) ;
2019-03-18 02:00:33 +01:00
}
}
res + = std : : string ( " end; \n " ) ;
}
return res ;
}
static db : : Net * read_net ( tl : : Extractor & ex , db : : Circuit * circuit , std : : map < std : : string , db : : Net * > & n2n )
{
std : : string nn ;
bool has_name = false ;
size_t cluster_id = 0 ;
if ( ex . test ( " ( " ) ) {
ex . expect ( " null " ) ;
ex . expect ( " ) " ) ;
return 0 ;
} else if ( ex . test ( " $ " ) ) {
bool has_i = ex . test ( " I " ) ;
ex . read ( cluster_id ) ;
nn = ( has_i ? " $I " : " $ " ) + tl : : to_string ( cluster_id ) ;
if ( has_i ) {
cluster_id = ( std : : numeric_limits < size_t > : : max ( ) - cluster_id ) + 1 ;
}
} else {
ex . read_word_or_quoted ( nn ) ;
has_name = true ;
}
std : : map < std : : string , db : : Net * > : : const_iterator i = n2n . find ( nn ) ;
if ( i = = n2n . end ( ) ) {
db : : Net * net = new db : : Net ( ) ;
circuit - > add_net ( net ) ;
if ( has_name ) {
net - > set_name ( nn ) ;
} else {
net - > set_cluster_id ( cluster_id ) ;
}
n2n . insert ( std : : make_pair ( nn , net ) ) ;
return net ;
} else {
return i - > second ;
}
}
static void read_pins ( tl : : Extractor & ex , db : : Circuit * circuit , std : : map < std : : string , db : : Net * > & n2n )
{
2019-03-31 09:53:51 +02:00
std : : vector < std : : string > org_pins ;
for ( db : : Circuit : : const_pin_iterator p = circuit - > begin_pins ( ) ; p ! = circuit - > end_pins ( ) ; + + p ) {
org_pins . push_back ( p - > name ( ) ) ;
}
2019-03-18 02:00:33 +01:00
circuit - > clear_pins ( ) ;
ex . expect ( " ( " ) ;
while ( ! ex . test ( " ) " ) ) {
ex . expect_more ( ) ;
std : : string pn ;
if ( ex . test ( " $ " ) ) {
size_t i ;
ex . read ( i ) ;
} else {
ex . read_word_or_quoted ( pn ) ;
}
ex . expect ( " = " ) ;
db : : Net * net = read_net ( ex , circuit , n2n ) ;
2019-03-31 09:53:51 +02:00
if ( circuit - > pin_count ( ) < org_pins . size ( ) & & pn ! = org_pins [ circuit - > pin_count ( ) ] ) {
ex . error ( tl : : sprintf ( tl : : to_string ( tr ( " Circuit defines different name for pin than subcircuit: %s (circuit) vs. %s (subcircuit) " ) ) , pn , org_pins [ circuit - > pin_count ( ) ] ) ) ;
}
2019-03-18 02:00:33 +01:00
const db : : Pin & pin = circuit - > add_pin ( pn ) ;
if ( net ) {
net - > add_pin ( db : : NetPinRef ( pin . id ( ) ) ) ;
}
ex . test ( " , " ) ;
}
2019-03-31 09:53:51 +02:00
if ( circuit - > pin_count ( ) < org_pins . size ( ) ) {
2019-03-18 02:00:33 +01:00
ex . error ( tl : : to_string ( tr ( " Circuit defines less pins that subcircuit " ) ) ) ;
2019-03-31 09:53:51 +02:00
} else if ( org_pins . size ( ) > 0 & & circuit - > pin_count ( ) > org_pins . size ( ) ) {
ex . error ( tl : : to_string ( tr ( " Circuit defines more pins that subcircuit " ) ) ) ;
2019-03-18 02:00:33 +01:00
}
}
static void read_device_terminals ( tl : : Extractor & ex , db : : Device * device , std : : map < std : : string , db : : Net * > & n2n )
{
ex . expect ( " ( " ) ;
while ( ! ex . test ( " ) " ) ) {
ex . expect_more ( ) ;
std : : string tn ;
ex . read_word_or_quoted ( tn ) ;
size_t tid = std : : numeric_limits < size_t > : : max ( ) ;
const std : : vector < DeviceTerminalDefinition > & td = device - > device_class ( ) - > terminal_definitions ( ) ;
for ( std : : vector < DeviceTerminalDefinition > : : const_iterator i = td . begin ( ) ; i ! = td . end ( ) ; + + i ) {
if ( i - > name ( ) = = tn ) {
tid = i - > id ( ) ;
break ;
}
}
if ( tid = = std : : numeric_limits < size_t > : : max ( ) ) {
ex . error ( tl : : to_string ( tr ( " Not a valid terminal name: " ) ) + tn ) ;
}
ex . expect ( " = " ) ;
db : : Net * net = read_net ( ex , device - > circuit ( ) , n2n ) ;
if ( net ) {
device - > connect_terminal ( tid , net ) ;
}
ex . test ( " , " ) ;
}
}
static void read_device_parameters ( tl : : Extractor & ex , db : : Device * device )
{
2019-03-26 22:05:08 +01:00
if ( ! ex . test ( " ( " ) ) {
return ;
}
2019-03-18 02:00:33 +01:00
while ( ! ex . test ( " ) " ) ) {
ex . expect_more ( ) ;
std : : string pn ;
ex . read_word_or_quoted ( pn ) ;
size_t pid = std : : numeric_limits < size_t > : : max ( ) ;
const std : : vector < DeviceParameterDefinition > & pd = device - > device_class ( ) - > parameter_definitions ( ) ;
for ( std : : vector < DeviceParameterDefinition > : : const_iterator i = pd . begin ( ) ; i ! = pd . end ( ) ; + + i ) {
if ( i - > name ( ) = = pn ) {
pid = i - > id ( ) ;
break ;
}
}
if ( pid = = std : : numeric_limits < size_t > : : max ( ) ) {
ex . error ( tl : : to_string ( tr ( " Not a valid parameter name: " ) ) + pn ) ;
}
ex . expect ( " = " ) ;
double value = 0 ;
ex . read ( value ) ;
device - > set_parameter_value ( pid , value ) ;
ex . test ( " , " ) ;
}
}
static void read_device ( tl : : Extractor & ex , db : : Circuit * circuit , std : : map < std : : string , db : : Net * > & n2n )
{
db : : Netlist * netlist = circuit - > netlist ( ) ;
std : : string dcn ;
ex . read_word_or_quoted ( dcn ) ;
db : : DeviceClass * dc = 0 ;
for ( db : : Netlist : : device_class_iterator i = netlist - > begin_device_classes ( ) ; i ! = netlist - > end_device_classes ( ) ; + + i ) {
if ( i - > name ( ) = = dcn ) {
dc = i . operator - > ( ) ;
}
}
if ( ! dc ) {
ex . error ( tl : : to_string ( tr ( " Not a valid device class name: " ) ) + dcn ) ;
}
std : : string dn ;
if ( ex . test ( " $ " ) ) {
size_t i ;
ex . read ( i ) ;
} else {
ex . read_word_or_quoted ( dn ) ;
}
db : : Device * device = new db : : Device ( dc , dn ) ;
circuit - > add_device ( device ) ;
read_device_terminals ( ex , device , n2n ) ;
read_device_parameters ( ex , device ) ;
}
2019-03-25 22:14:16 +01:00
static void read_subcircuit_pins ( tl : : Extractor & ex , db : : Circuit * circuit , db : : SubCircuit * subcircuit , std : : map < std : : string , db : : Net * > & n2n )
2019-03-18 02:00:33 +01:00
{
2019-03-25 22:14:16 +01:00
db : : Circuit * circuit_ref = subcircuit - > circuit_ref ( ) ;
db : : Circuit : : pin_iterator pi = circuit_ref - > begin_pins ( ) ;
2019-03-18 02:00:33 +01:00
ex . expect ( " ( " ) ;
while ( ! ex . test ( " ) " ) ) {
2019-03-18 19:28:20 +01:00
std : : string pn ;
2019-03-31 09:53:51 +02:00
if ( ex . test ( " $ " ) ) {
size_t i ;
ex . read ( i ) ;
} else {
ex . read_word_or_quoted ( pn ) ;
}
2019-03-18 19:28:20 +01:00
ex . expect ( " = " ) ;
2019-03-25 22:14:16 +01:00
if ( pi = = circuit_ref - > end_pins ( ) ) {
2019-03-18 02:00:33 +01:00
// add a dummy pin
2019-03-25 22:14:16 +01:00
circuit_ref - > add_pin ( pn ) ;
pi = circuit_ref - > end_pins ( ) ;
2019-03-18 02:00:33 +01:00
- - pi ;
2019-03-25 22:14:16 +01:00
} else if ( ! pi - > name ( ) . empty ( ) & & pi - > name ( ) ! = pn ) {
2019-03-18 19:28:20 +01:00
ex . error ( tl : : to_string ( tr ( " Expected pin with name: " ) ) + pi - > name ( ) ) ;
2019-03-18 02:00:33 +01:00
}
ex . expect_more ( ) ;
db : : Net * net = read_net ( ex , circuit , n2n ) ;
if ( net ) {
subcircuit - > connect_pin ( pi - > id ( ) , net ) ;
}
ex . test ( " , " ) ;
+ + pi ;
}
2019-03-25 22:14:16 +01:00
if ( pi ! = circuit_ref - > end_pins ( ) ) {
2019-03-18 19:28:20 +01:00
ex . error ( tl : : to_string ( tr ( " Too few pins in subcircuit call " ) ) ) ;
2019-03-18 02:00:33 +01:00
}
}
static void read_subcircuit ( tl : : Extractor & ex , db : : Circuit * circuit , std : : map < std : : string , db : : Net * > & n2n , std : : map < std : : string , db : : Circuit * > & c2n )
{
std : : string cn ;
ex . read_word_or_quoted ( cn ) ;
db : : Circuit * cc = 0 ;
std : : map < std : : string , db : : Circuit * > : : const_iterator ic = c2n . find ( cn ) ;
if ( ic = = c2n . end ( ) ) {
cc = new db : : Circuit ( ) ;
circuit - > netlist ( ) - > add_circuit ( cc ) ;
cc - > set_name ( cn ) ;
c2n . insert ( std : : make_pair ( cn , cc ) ) ;
} else {
cc = ic - > second ;
}
std : : string scn ;
if ( ex . test ( " $ " ) ) {
size_t i ;
ex . read ( i ) ;
} else {
ex . read_word_or_quoted ( scn ) ;
}
db : : SubCircuit * subcircuit = new db : : SubCircuit ( cc , scn ) ;
circuit - > add_subcircuit ( subcircuit ) ;
2019-03-25 22:14:16 +01:00
read_subcircuit_pins ( ex , circuit , subcircuit , n2n ) ;
2019-03-18 02:00:33 +01:00
}
void Netlist : : from_string ( const std : : string & s )
{
tl : : Extractor ex ( s . c_str ( ) ) ;
std : : map < std : : string , db : : Circuit * > c2n ;
while ( ex . test ( " circuit " ) ) {
std : : string n ;
ex . read_word_or_quoted ( n ) ;
db : : Circuit * circuit = 0 ;
std : : map < std : : string , db : : Circuit * > : : const_iterator ic = c2n . find ( n ) ;
if ( ic = = c2n . end ( ) ) {
circuit = new db : : Circuit ( ) ;
add_circuit ( circuit ) ;
circuit - > set_name ( n ) ;
c2n . insert ( std : : make_pair ( n , circuit ) ) ;
} else {
circuit = ic - > second ;
}
std : : map < std : : string , db : : Net * > n2n ;
read_pins ( ex , circuit , n2n ) ;
ex . expect ( " ; " ) ;
while ( ! ex . test ( " end " ) ) {
ex . expect_more ( ) ;
if ( ex . test ( " device " ) ) {
read_device ( ex , circuit , n2n ) ;
ex . expect ( " ; " ) ;
} else if ( ex . test ( " subcircuit " ) ) {
read_subcircuit ( ex , circuit , n2n , c2n ) ;
ex . expect ( " ; " ) ;
} else {
ex . error ( tl : : to_string ( tr ( " device or subcircuit expected " ) ) ) ;
}
}
ex . expect ( " ; " ) ;
}
ex . expect_end ( ) ;
}
2018-12-19 23:41:39 +01:00
}