@ -5,7 +5,7 @@ A node is an instance of class :class:`Node`,
@@ -5,7 +5,7 @@ A node is an instance of class :class:`Node`,
and a line is an instance of class : class : ` Line ` .
"""
from collections import deque
from collections import deque , defaultdict
import re
@ -203,7 +203,7 @@ class Circuit:
@@ -203,7 +203,7 @@ class Circuit:
to enforce consecutiveness .
A subset of nodes can be designated as primary input - or output - ports of the circuit .
This is done by adding them to the : py : attr : ` interface ` list .
This is done by adding them to the : py : attr : ` io_nodes ` list .
"""
def __init__ ( self , name = None ) :
self . name = name
@ -219,13 +219,13 @@ class Circuit:
@@ -219,13 +219,13 @@ class Circuit:
The position of a line in this list equals its index : code : ` self . lines [ 42 ] . index == 42 ` .
"""
self . interface = GrowingList ( )
self . io_nodes = GrowingList ( )
""" A list of nodes that are designated as primary input- or output-ports.
Port - nodes are contained in : py : attr : ` nodes ` as well as : py : attr : ` interface ` .
The position of a node in the interface list corresponds to positions of logic values in test vectors .
Port - nodes are contained in : py : attr : ` nodes ` as well as : py : attr : ` io_nodes ` .
The position of a node in the io_nodes list corresponds to positions of logic values in test vectors .
The port direction is not stored explicitly .
Usually , nodes in the interface list without any lines in their : py : attr : ` Node . ins ` list are primary inputs ,
Usually , nodes in the io_nodes list without any lines in their : py : attr : ` Node . ins ` list are primary inputs ,
and nodes without any lines in their : py : attr : ` Node . outs ` list are regarded as primary outputs .
"""
self . cells = { }
@ -248,50 +248,57 @@ class Circuit:
@@ -248,50 +248,57 @@ class Circuit:
d = c . forks [ line . driver . name ] if line . driver . kind == ' __fork__ ' else c . cells [ line . driver . name ]
r = c . forks [ line . reader . name ] if line . reader . kind == ' __fork__ ' else c . cells [ line . reader . name ]
Line ( c , ( d , line . driver_pin ) , ( r , line . reader_pin ) )
for node in self . interface :
for node in self . io_nodes :
if node . kind == ' __fork__ ' :
n = c . forks [ node . name ]
else :
n = c . cells [ node . name ]
c . interface . append ( n )
c . io_nodes . append ( n )
return c
def __getstate__ ( self ) :
nodes = [ ( node . name , node . kind ) for node in self . nodes ]
lines = [ ( line . driver . index , line . driver_pin , line . reader . index , line . reader_pin ) for line in self . lines ]
interface = [ n . index for n in self . interface ]
io_nodes = [ n . index for n in self . io_nodes ]
return { ' name ' : self . name ,
' nodes ' : nodes ,
' lines ' : lines ,
' interface ' : interface }
' io_nodes ' : io_nodes }
def __setstate__ ( self , state ) :
self . name = state [ ' name ' ]
self . nodes = IndexList ( )
self . lines = IndexList ( )
self . interface = GrowingList ( )
self . io_nodes = GrowingList ( )
self . cells = { }
self . forks = { }
for s in state [ ' nodes ' ] :
Node ( self , * s )
for driver , driver_pin , reader , reader_pin in state [ ' lines ' ] :
Line ( self , ( self . nodes [ driver ] , driver_pin ) , ( self . nodes [ reader ] , reader_pin ) )
for n in state [ ' interface ' ] :
self . interface . append ( self . nodes [ n ] )
for n in state [ ' io_nodes ' ] :
self . io_nodes . append ( self . nodes [ n ] )
def __eq__ ( self , other ) :
return self . nodes == other . nodes and self . lines == other . lines and self . interface == other . interface
return self . nodes == other . nodes and self . lines == other . lines and self . io_nodes == other . io_nodes
def dump ( self ) :
""" Returns a string representation of the circuit and all its nodes.
"""
header = f ' { self . name } ( { " , " . join ( [ str ( n . index ) for n in self . interface ] ) } ) \n '
header = f ' { self . name } ( { " , " . join ( [ str ( n . index ) for n in self . io_nodes ] ) } ) \n '
return header + ' \n ' . join ( [ str ( n ) for n in self . nodes ] )
def __repr__ ( self ) :
name = f ' { self . name } ' if self . name else ' '
return f ' <Circuit { name } cells= { len ( self . cells ) } forks= { len ( self . forks ) } ' + \
f ' lines= { len ( self . lines ) } ports= { len ( self . interface ) } > '
f ' lines= { len ( self . lines ) } ports= { len ( self . io_nodes ) } > '
@property
def cell_counts ( self ) :
counts = defaultdict ( int )
for n in self . cells . values ( ) :
counts [ n . kind ] + = 1
return counts
def topological_order ( self ) :
""" Generator function to iterate over all nodes in topological order.
@ -375,8 +382,8 @@ class Circuit:
@@ -375,8 +382,8 @@ class Circuit:
def io_loc ( self , prefix ) :
d_top = dict ( )
for i , n in enumerate ( list ( self . interface ) + [ n for n in self . nodes if ' dff ' in n . kind . lower ( ) ] ) :
if m := re . match ( fr ' ( { prefix } .*?)((?:[_ \ [ \ ]] \ d+)* [_ \ [ \ ]]*$) ' , n . name ) :
for i , n in enumerate ( list ( self . io_nodes ) + [ n for n in self . nodes if ' dff ' in n . kind . lower ( ) ] ) :
if m := re . match ( fr ' ( { prefix } .*?)((?: \ d+[_ \ [ \ ]]) *$) ' , n . name ) :
path = [ m [ 1 ] ] + [ int ( v ) for v in re . split ( r ' [_ \ [ \ ]]+ ' , m [ 2 ] ) if len ( v ) > 0 ]
d = d_top
for j in path [ : - 1 ] :