1313from openram import debug
1414from openram import tech
1515from openram import OPTS
16-
17- from compiler .base .net_spice import net_spice
16+ from collections import OrderedDict
1817from .delay_data import delay_data
1918from .wire_spice_model import wire_spice_model
2019from .power_data import power_data
2120from .logical_effort import convert_relative_c_to_farad , convert_farad_to_relative_c
2221from .pin_spice import pin_spice
22+ from .net_spice import net_spice
2323
2424
2525class spice ():
@@ -55,14 +55,15 @@ def __init__(self, name, cell_name):
5555 # Holds subckts/mods for this module
5656 self .mods = set ()
5757 # Holds the pins for this module (in order)
58- self .pins = []
58+ # on Python3.7+ regular dictionaries guarantee order too, but we allow use of v3.5+
59+ self .pins = OrderedDict ()
5960 # An (optional) list of indices to reorder the pins to match the spice.
6061 self .pin_indices = []
6162 # THE CONNECTIONS MUST MATCH THE ORDER OF THE PINS (restriction imposed by the
6263 # Spice format)
6364 # internal nets, which may or may not be connected to pins of the same name
64- self .nets = []
65- # If this is set, it will out output subckt or isntances of this (for row/col caps etc.)
65+ self .nets = {}
66+ # If this is set, it will not output subckt or instances of this (for row/col caps etc.)
6667 self .no_instances = False
6768 # If we are doing a trimmed netlist, these are the instance that will be filtered
6869 self .trim_insts = set ()
@@ -90,9 +91,8 @@ def add_comment(self, comment):
9091
9192 def add_pin (self , name , pin_type = "INOUT" ):
9293 """ Adds a pin to the pins list. Default type is INOUT signal. """
93- new_pin = pin_spice (name , pin_type )
94- debug .check (new_pin not in self .pins , "cannot add duplicate spice pin" )
95- self .pins .append (new_pin )
94+ debug .check (name not in self .pins , "cannot add duplicate spice pin {}" .format (name ))
95+ self .pins [name ] = pin_spice (name , pin_type )
9696
9797 def add_pin_list (self , pin_list , pin_type = "INOUT" ):
9898 """ Adds a pin_list to the pins list """
@@ -122,20 +122,17 @@ def get_ordered_inputs(self, input_list):
122122
123123 def update_pin_types (self , type_list ):
124124 """ Change pin types for all the cell's pins. """
125- if len (type_list ) != len (self .pins ):
126- debug .error ("{} spice subcircuit number of port types does not match number of pins\
127- \n SPICE names={}\
128- \n Module names={}\
129- " .format (self .name , self .pins , type_list ), 1 )
130- for pin , type in zip (self .pins , type_list ):
125+ debug .check (len (type_list ) == len (self .pins ),
126+ "{} spice subcircuit number of port types does not match number of pins\
127+ \n pin names={}\n port types={}" .format (self .name , list (self .pins ), type_list ))
128+ for pin , type in zip (self .pins .values (), type_list ):
131129 pin .set_pin_type (type )
132130
133131 def get_pin_type (self , name ):
134132 """ Returns the type of the signal pin. """
135- for pin in self .pins :
136- if pin .name == name :
137- return pin .type
138- debug .error ("Spice pin {} not found" .format (name ))
133+ pin = self .pins .get (name )
134+ debug .check (pin is not None , "Spice pin {} not found" .format (name ))
135+ return pin .type
139136
140137 def get_pin_dir (self , name ):
141138 """ Returns the direction of the pin. (Supply/ground are INOUT). """
@@ -148,45 +145,47 @@ def get_pin_dir(self, name):
148145 def get_inputs (self ):
149146 """
150147 These use pin types to determine pin lists.
151- Returns names only to maintain historical interface.
148+ Returns names only, to maintain historical interface.
152149 """
153150 input_list = []
154- for pin in self .pins :
151+ for pin in self .pins . values () :
155152 if pin .type == "INPUT" :
156153 input_list .append (pin .name )
157154 return input_list
158155
159156 def get_outputs (self ):
160157 """
161158 These use pin types to determine pin lists.
162- Returns names only to maintain historical interface.
159+ Returns names only, to maintain historical interface.
163160 """
164161 output_list = []
165- for pin in self .pins :
162+ for pin in self .pins . values () :
166163 if pin .type == "OUTPUT" :
167164 output_list .append (pin .name )
168165 return output_list
169166
170167 def get_inouts (self ):
171- """ These use pin types to determine pin lists. These
172- may be over-ridden by submodules that didn't use pin directions yet."""
168+ """
169+ These use pin types to determine pin lists.
170+ Returns names only, to maintain historical interface.
171+ """
173172 inout_list = []
174- for pin in self .pins :
173+ for pin in self .pins . values () :
175174 if pin .type == "INOUT" :
176175 inout_list .append (pin .name )
177176 return inout_list
178177
179178 def copy_pins (self , other_module , suffix = "" ):
180179 """ This will copy all of the pins from the other module and add an optional suffix."""
181- for pin in other_module .pins :
180+ for pin in other_module .pins . values () :
182181 self .add_pin (pin .name + suffix , pin .type )
183182
184183 def connect_inst (self , args ):
185184 """
186185 Connects the pins of the last instance added
187186 """
188187
189- spice_pins = self .insts [- 1 ].spice_pins
188+ spice_pins = list ( self .insts [- 1 ].spice_pins )
190189 num_pins = len (spice_pins )
191190 num_args = len (args )
192191
@@ -241,8 +240,7 @@ def sp_read(self):
241240 subckt = re .compile ("^.subckt {}" .format (self .cell_name ), re .IGNORECASE )
242241 subckt_line = list (filter (subckt .search , self .spice ))[0 ]
243242 # parses line into ports and remove subckt
244- # FIXME: needs to use new pins interface
245- self .pins = subckt_line .split (" " )[2 :]
243+ self .add_pin_list (subckt_line .split (" " )[2 :])
246244 else :
247245 debug .info (4 , "no spfile {0}" .format (self .sp_file ))
248246 self .spice = []
@@ -263,10 +261,10 @@ def sp_read(self):
263261 subckt_line = list (filter (subckt .search , self .lvs ))[0 ]
264262 # parses line into ports and remove subckt
265263 lvs_pins = subckt_line .split (" " )[2 :]
266- debug .check (lvs_pins == self .pins ,
264+ debug .check (lvs_pins == list ( self .pins ) ,
267265 "Spice netlists for LVS and simulation have port mismatches:\n {0} (LVS {1})\n vs\n {2} (sim {3})" .format (lvs_pins ,
268266 self .lvs_file ,
269- self .pins ,
267+ list ( self .pins ) ,
270268 self .sp_file ))
271269
272270 def check_net_in_spice (self , net_name ):
@@ -299,6 +297,8 @@ def contains(self, mod, modlist):
299297 return False
300298
301299 def sp_write_file (self , sp , usedMODS , lvs = False , trim = False ):
300+ # FIXME: this function refers to conns for connections but that no longer exists.
301+ # it should be possible to just query the instances themselves for their connections.
302302 """
303303 Recursive spice subcircuit write;
304304 Writes the spice subcircuit from the library or the dynamically generated one.
@@ -319,29 +319,17 @@ def sp_write_file(self, sp, usedMODS, lvs=False, trim=False):
319319
320320 if len (self .insts ) == 0 :
321321 return
322- if self .pins == [] :
322+ if len ( self .pins ) == 0 :
323323 return
324324
325325 # write out the first spice line (the subcircuit)
326- wrapped_pins = "\n + " .join (tr .wrap (" " .join (self .pins )))
326+ wrapped_pins = "\n + " .join (tr .wrap (" " .join (list ( self .pins ) )))
327327 sp .write ("\n .SUBCKT {0}\n + {1}\n " .format (self .cell_name ,
328328 wrapped_pins ))
329329
330- # write a PININFO line
331- if False :
332- pin_info = "*.PININFO"
333- for pin in self .pins :
334- if self .pin_type [pin ] == "INPUT" :
335- pin_info += " {0}:I" .format (pin )
336- elif self .pin_type [pin ] == "OUTPUT" :
337- pin_info += " {0}:O" .format (pin )
338- else :
339- pin_info += " {0}:B" .format (pin )
340- sp .write (pin_info + "\n " )
341-
342330 # Also write pins as comments
343- for pin in self .pins :
344- sp .write ("* {1:6}: {0} \n " .format (pin , pin .type ))
331+ for pin in self .pins . values () :
332+ sp .write ("* {1:6}: {0} \n " .format (pin . name , pin .type ))
345333
346334 for line in self .comments :
347335 sp .write ("* {}\n " .format (line ))
0 commit comments