Chip mapper: allow chip numbering to start at a given value, instead of 0.
[trinary.git] / bb / bb.py
blob37ce2a8b331fb597ac777aa712d564a60ff13cdd
1 #!/usr/bin/env python
2 # Created:20080411
3 # By Jeff Connelly
5 # Circuit pin layout program, for mapping sub-chip (or partially sub-chip)
6 # subcircuits to actual integrated circuit chips plus optional extra components,
7 # outside the chip. For example, the 'tinv' subcircuit has a complementary pair
8 # of MOSFETs, which this program maps to part of CD4007, assigning the pins,
9 # and mapping the other pair inside the CD4007 if another 'tinv' comes along.
11 import copy
12 import types
13 import sys
15 import tg
16 import tinv
17 import tnor
18 import tnand
19 import os
21 PROGRAM_NAME = "bb.py"
23 # Start chip numbering at this value.
24 CHIP_NO_START = 10
26 # Subcircuits to map that should be mapped physical ICs
27 SUBCIRCUITS_TO_MAP = ('tg', 'tinv', 'tnor', 'tnor3', 'tnand', 'tnand3', 'sp3t-1', 'sp3t-2', 'sp3t-3')
28 SUBCIRCUITS_CAN_MAP = ('tg', 'tinv', 'tnor', 'tnand') # subcircuits we actually can map to ICs, as of yet
29 SUBCIRCUITS_PASS = ('sp3t-1', 'sp3t-2', 'sp3t-3') # pass unchanged to pads.py
31 def combine_dicts(dict1, dict2):
32 """Combine two dictionaries; dict2 takes priority over dict1."""
33 ret = copy.deepcopy(dict1)
34 ret.update(dict2)
35 return ret
37 def read_netlist(filename):
38 """Read a SPICE input deck, returning subcircuit nodes and definitions."""
40 if filename == "-":
41 f = sys.stdin
42 else:
43 f = file(filename, "rt")
44 subckt_nodes = {}
45 subckt_defns = {}
46 toplevel = []
47 name = None
48 while True:
49 line = f.readline()
50 if len(line) == 0:
51 break
53 line = line.strip()
55 if line.startswith(".subckt"):
56 words = line.split()
57 name = words[1]
58 nodes = words[2:]
60 subckt_nodes[name] = nodes
61 elif line.startswith(".ends"):
62 name = None
63 else:
64 if name is not None:
65 if not subckt_defns.has_key(name):
66 subckt_defns[name] = []
67 subckt_defns[name].append(line)
68 else:
69 # Top-level elements, skip blank lines, commands and comments
70 if len(line.strip()) != 0 and line[0] not in ('.', '*'):
71 toplevel.append(line)
73 return subckt_nodes, subckt_defns, toplevel
75 def rewrite_subckt(subckt_defns, s):
76 """Partially rewrite subcircuit 's', using rules from a module of the same name.
78 Removes parts in mod.parts_consumed, keeps parts in mod.parts_kept.
80 Does not generate any new parts."""
82 mod = globals()[s]
83 lines = []
84 for line in subckt_defns[s]:
85 words = line.split()
86 name = words[0]
87 args = words[1:]
89 if name in mod.parts_consumed:
90 # Skip this line
91 pass
92 elif name in mod.parts_kept:
93 lines.append(line)
94 else:
95 raise "Subcircuit %s defined in module %s has parts consumed list: %s and parts kept list: %s, but the name '%s' is in neither. Add it to either." % (s, name, mod.parts_consumed, mod.parts_kept, name)
97 # Map node positions in arguments list (subckt invocation, X..), to node names
98 pos2node = {}
99 for i in range(0, len(mod.nodes)):
100 pos2node[mod.nodes[i]] = i
102 # Rewrite
103 subckt_defns[s] = lines
105 return mod, subckt_defns, pos2node
107 next_serial = -1
108 def get_serial():
109 """Get a unique, increasing number."""
110 global next_serial
112 next_serial += 1
113 return next_serial
115 def get_floating(n=None):
116 """Return a unique disconnected (floating) node name.
118 If n is given, return a dict of n floating node names. Otherwise returns one in a string."""
119 if n is not None:
120 return get_floating_n(n)
122 return "NC__%s" % (get_serial(), )
124 def get_floating_n(n):
125 """Get n floating nodes, see get_floating()."""
126 fs = {}
127 for x in range(1, n + 1):
128 fs[x] = get_floating()
129 return fs
131 def is_floating(node_name):
132 """Return whether the given node name is probably not connected;
133 generated from get_floating()."""
134 return node_name.startswith("NC_")
136 def chip_has_pins_available(pins_needed, pins):
137 """Return whether 'pins' has not-connected pins, all those required in pins_needed."""
138 for p in pins_needed:
139 if not is_floating(pins[p]):
140 return False
141 return True
143 # This program doesn't thoroughly parse SPICE cards, so you must
144 # give it parameters that are not nodes, to not map at all.
145 # For example, '12k' for the 12k resistors. TODO: better parsing
146 def find_chip(chips, model_needed, pins_needed_options):
147 """Return an index into the chips array, and what pins, with the given model and the pins free.
149 pins_needed_options is a list of lists, of any acceptable set of pins to use.
151 A new chip is added if none are found. """
153 result = find_chip_no_add(chips, model_needed, pins_needed_options)
154 if result is not None:
155 return result
157 # No chips found with model model_needed and with pins free. Need more chips.
158 if model_needed not in ("CD4016", "CD4007"):
159 raise "Model %s not known, it is not CD4016 nor CD4007, not recognized!" % (model_needed,)
161 # Add a new chip!
162 # Assume all are 14-pin chips
163 chips.append((model_needed, get_floating(14)))
165 result = find_chip_no_add(chips, model_needed, pins_needed_options)
166 if result is not None:
167 return result
169 raise "Tried to find model %s with pins %s free, then added a new chip but couldn't find it!" % (
170 model_needed, pins_needed_options)
172 def find_chip_no_add(chips, model_needed, pins_needed_options):
173 """Find chip to use (see find_chip), but return None if not found instead of adding."""
174 for i, chip in enumerate(chips):
175 model, pins = chip
176 if model != model_needed:
177 continue
179 for option_num, option in enumerate(pins_needed_options):
180 # Note: I do not yet check if the chip has pins that are used, but are assigned to
181 # the same node that is required. The pins must be unused.
182 if chip_has_pins_available(option, pins):
183 #print "* Found model %s with pins %s free: chip #%s" % (model_needed, option, i)
184 return i, option_num
185 return None
187 def find_pins_needed(pins):
188 """From a mod.pins[x] dict, return the pins needed for each model, for find_chip()"""
189 need = {}
190 for x in pins.values():
191 if type(x) == types.TupleType:
192 model, pin = x
193 if not need.has_key(model):
194 need[model] = []
196 need[model].append(pin)
197 elif type(x) == types.ListType:
198 for mp in x:
199 model, pin = mp
200 if not need.has_key(model):
201 need[model] = []
203 need[model].append(pin)
205 return need
207 def assign_part(chips, subckt_defns, extra, model_name, external_nodes, refdesg):
208 """Assign a given model to a physical chip, using the names of the external nodes.
210 chips: array of existing physical chips that can be assigned from
211 mod: logical model to map to, like 'tinv'
212 external_nodes: dict mapping internal nodes in the model, to external nodes in the world
215 mod = globals()[model_name]
216 subckt_lines = subckt_defns[model_name]
219 # Store new pin assignments
220 assignments = {}
221 for p in mod.parts_generated:
222 assignments[p] = {}
224 need_options = []
225 the_model = None
226 for p in mod.pins:
227 need = find_pins_needed(p)
228 if len(need) > 1:
229 raise "Sorry, more than one model is needed: %s, but only one is supported right now." % (need,)
230 if the_model is None:
231 the_model = need.keys()[0]
232 else:
233 if the_model != need.keys()[0]:
234 raise "Sorry, different models are needed: %s, but already decided on %s earlier. This is not yet supported." % (the_model, need[0])
236 need_options.append(need.values()[0])
238 #print "* Searching for model %s with one of pins: %s" % (the_model, need_options)
239 chip_num, option_num = find_chip(chips, the_model, need_options)
240 #print "* FOUND CHIP:",chip_num
241 #print "* WITH PINS (option #%s):" % (option_num,), mod.pins[option_num]
243 findings = []
244 for node_pin in combine_dicts(mod.global_pins, mod.pins[option_num]).iteritems():
245 node, pin = node_pin
247 if type(pin) == types.TupleType:
248 part, pin = pin
249 findings.append((node, part, pin))
250 elif type(pin) == types.ListType:
251 for pp in pin:
252 part, p = pp
253 findings.append((node, part, p))
254 else:
255 part = None
256 findings.append((node, part, pin))
258 for node, part, pin in findings:
259 #print "* %s -> %s:%s" % (node, part, pin)
261 if part is not None:
262 if node.startswith("$G_") or node == "0":
263 new_node = node # global node (LTspice)
264 elif external_nodes.has_key(node):
265 #sys.stderr.write("Mapping external node %s, map = %s\n" % (node, external_nodes))
266 new_node = external_nodes[node] # map internal to external node
267 else:
268 #sys.stderr.write("Mapping internal-only node %s\n" % (node,))
269 # 'refdesg' here is prefixed with X, for a subcircuit instantation,
270 # but we only need the subcircuit prefix for a node, without the
271 # X prefix.
272 assert refdesg[0:2] == 'X$', "Assumed refdesg %s began with X$, but it didn't" % (refdesg,)
273 refdesg_without_letter = refdesg[2:]
274 new_node = rewrite_node("", refdesg_without_letter, node)
275 sys.stderr.write("Rewriting to node = %s\n" % (new_node,))
277 sys.stderr.write("Adding to chips: %s\n" % (new_node,))
278 chips[chip_num][1][pin] = new_node
280 internal_only_nodes = {}
282 # Now place any ++additional parts++ (resistors, etc.) within the subcircuit model
283 # that connect to the chip, but are not part of the chip.
284 for line in subckt_lines:
285 words = line.split()
286 new_words = []
288 if words[0][0] == "M":
289 raise ("This line:\t%s\nIn the subcircuit '%s', has a MOSFET left " +
290 "over that wasn't converted. Probably it was meant to be converted to an IC? " +
291 "Comment out this line in %s if you are sure you want this, otherwise " +
292 "double-check the model definition for '%s', specifically, " +
293 "parts_consumed and parts_kept.\nAlso, check if the model was rewritten!") % (line, model_name, PROGRAM_NAME, model_name)
295 #name = "%s_%s_%s_%s" % (words[0], model_name, chip_num, refdesg)
296 name = "%s%s$%s" % (words[0][0], refdesg, words[0])
298 new_words.append(name)
300 args = words[1:-1]
301 model_name = words[-1]
303 # Replace internal nodes with external nodes.
304 for w in args:
305 if w in external_nodes.keys():
306 new_words.append(external_nodes[w])
307 elif is_floating(w):
308 # TODO ???
309 new_words.append(get_floating())
310 else:
311 if not internal_only_nodes.has_key(w):
312 #internal_only_nodes[w] = "%s$%s$%s" % (w[0], refdesg, w)
313 assert refdesg[0:2] == 'X$', "Reference designator %s expected to begin with X$, but didn't" % (refdesg,)
314 refdesg_without_letter = refdesg[2:]
315 internal_only_nodes[w] = rewrite_node("", refdesg_without_letter, w)
316 new_words.append(internal_only_nodes[w])
318 # TODO: comment this out, if the above works
319 #raise "Could not map argument '%s' in subcircuit line %s, not found in %s" % (w, line, external_nodes)
321 new_words.append(model_name)
323 extra.append(" ".join(new_words))
325 return chips, extra
327 def any_pins_used(pins):
328 """Return whether any of the pins on a chip are used. If False, chip isn't used."""
329 for p in pins.values():
330 if not is_floating(p):
331 return True
332 return False
334 def dump_chips(chips):
335 """Show the current chips and their pin connections."""
336 for i, c in enumerate(chips):
337 m, p = c
339 if not any_pins_used(p):
340 print "* Chip #%s - %s no pins used, skipping" % (i + CHIP_NO_START, m)
341 continue
343 print "* Chip #%s - %s pinout:" % (i + CHIP_NO_START, m)
344 for k, v in p.iteritems():
345 print "* \t%s: %s" % (k, v)
347 print "IC_%s_%s" % (m, i + CHIP_NO_START),
348 # Assumes all chips are 14-pin, arguments from 1 to 14 positional
349 for k in range(1, 14+1):
350 print p[k],
351 print m
352 print
354 def dump_extra(extra):
355 """Shows the extra, supporting subcircuit parts that support the IC and are part of the subcircuit."""
356 print "* Parts to support subcircuits:"
357 for e in extra:
358 print e
360 def make_node_mapping(internal, external):
361 """Make a node mapping dictionary from internal to external nodes.
362 Keys of the returned dictionary are internal nodes (of subcircuit), values are external."""
363 d = {}
364 d.update(zip(internal, external))
365 return d
367 def rewrite_refdesg(original, prefix):
368 """Prefix a reference designator, preserving the first character."""
369 new_refdesg = "%s%s$%s" % (original[0], prefix, original)
371 #sys.stderr.write("@ rewrite_refdesg = %s\n" % (new_refdesg,))
372 return new_refdesg
374 def rewrite_node(prefix, circuit_inside, original_node_name):
375 """Rewrite a node name inside a subcircuit, prefixing it with
376 prefix and the name of the circuit that it is inside (both
377 are optional)."""
379 # Globals never rewritten
380 if original_node_name.startswith("$G_") or original_node_name == "0":
381 return original_node_name
383 new_name = original_node_name
384 if circuit_inside:
385 new_name = "%s$%s" % (circuit_inside, new_name)
387 if prefix:
388 new_name = "%s$%s" % (prefix, new_name)
390 # Nodes don't need to begin with spurious '$'s (can happen if no prefix)
391 if new_name[0] == '$':
392 new_name = new_name[1:]
394 #sys.stderr.write("@@ rewrite_node = %s\n" % (new_name,))
395 return new_name
397 def is_expandable_subcircuit(refdesg, model):
398 """Return whether the SPICE reference designator and model is
399 a) a subcircuit, b) _and_ it can be hierarchically expanded further."""
400 return refdesg[0] == 'X' and model not in SUBCIRCUITS_TO_MAP
402 def expand(subckt_defns, subckt_nodes, line, prefix, outer_nodes, outer_prefixes):
403 """Recursively expand a subcircuit instantiation if needed."""
404 words = line.split()
405 outer_refdesg = words[0]
406 outer_model = words[-1]
407 outer_args = words[1:-1]
409 sys.stderr.write("expand(%s,%s,%s,%s)\n" % (line, prefix, outer_nodes, outer_prefixes))
410 if is_expandable_subcircuit(outer_refdesg, outer_model):
411 nodes = make_node_mapping(subckt_nodes[outer_model], outer_args)
412 new_lines = []
413 new_lines.append(("* %s: Instance of subcircuit %s: %s" % (outer_refdesg, outer_model, " ".join(outer_args))))
415 # Notes that are internal to the subcircuit, not exposed in any ports
416 internal_only_nodes = {}
418 for sline in subckt_defns[outer_model]:
419 swords = sline.split()
420 inner_refdesg = swords[0]
421 inner_model = swords[-1]
422 inner_args = swords[1:-1]
424 if is_expandable_subcircuit(inner_refdesg, inner_model):
425 # Recursively expand subcircuits, to transistor-level subcircuits (SUBCIRCUITS_TO_MAP)
426 nodes_to_pass = {}
427 prefixes_to_pass = {}
428 for n in nodes:
429 if outer_nodes.has_key(nodes[n]):
430 nodes_to_pass[n] = outer_nodes[nodes[n]]
431 prefixes_to_pass[nodes_to_pass[n]] = outer_prefixes[nodes_to_pass[n]]
432 else:
433 nodes_to_pass[n] = nodes[n]
434 prefixes_to_pass[nodes_to_pass[n]] = prefix
435 # Only append separator if not empty
436 if prefix:
437 prefixes_to_pass[nodes_to_pass[n]] += "$"
439 # Chop '$' if begins with it
440 if len(prefixes_to_pass[nodes_to_pass[n]]) >= 1 and prefixes_to_pass[nodes_to_pass[n]][0] == '$':
441 prefixes_to_pass[nodes_to_pass[n]] = prefixes_to_pass[nodes_to_pass[n]][1:]
442 # TODO: get the prefixes right!
443 sys.stderr.write("PASSING NODES: %s (outer=%s, inner=%s), outer_refdesg=%s, prefix=%s\n" % (nodes_to_pass, outer_nodes, nodes, outer_refdesg, prefix))
444 sys.stderr.write("\tPASSING PREFIXES: %s (outer=%s)\n" % (prefixes_to_pass, outer_prefixes))
445 new_lines.extend(expand(subckt_defns, subckt_nodes, sline, prefix +
446 "$" + outer_refdesg, nodes_to_pass, prefixes_to_pass))
447 else:
448 new_words = []
449 # Nest reference designator
450 new_words.append(rewrite_refdesg(inner_refdesg, prefix + "$" + outer_refdesg))
452 # Map internal to external nodes
453 for w in inner_args:
454 #print "****", word
455 if w in nodes.keys():
456 # XXX TODO: Need to follow up hierarchy! This leads to
457 # incomplete nets. For example, dtflop-ms_test.net maps:
459 # In nodes {'Q': 'Q', 'C': 'CLK', 'D': 'D'}, rewrite C -> CLK, prefix [correct]
460 # In nodes {'Q': 'Q', 'C': 'CLK', 'D': 'D'}, rewrite C -> CLK, prefix [correct]
462 # but because the 'nodes' dict is only for the parent, it
463 # doesn't map this correctly, leading to an unconnected node:
465 # In nodes {'OUT': '_C', 'IN': 'C'}, rewrite IN -> C, prefix Xflipflop [wrong]
467 # It should be CLK, not Xflipflop$C. These problems will occur
468 # with more nesting of subcircuits
469 if nodes[w] in outer_nodes:
470 # This is a port of this subcircuit, ascends hierarchy
471 new_words.append(outer_prefixes[outer_nodes[nodes[w]]] + outer_nodes[nodes[w]])
472 # TODO XXX: get the prefixes right! what if it isn't top-level?
473 #new_words.append(outer_nodes[nodes[w]])
474 sys.stderr.write("Node %s -> %s -> %s (outer nodes=%s, prefixes=%s) (prefix=%s, refdesgs=%s,%s)\n" %
475 (w, nodes[w], outer_nodes[nodes[w]], outer_nodes, outer_prefixes, prefix,
476 outer_refdesg, inner_refdesg))
477 else:
478 new_words.append(rewrite_node(prefix, "", nodes[w]))
480 elif is_floating(w):
481 # This is a port, but that is not connected on the outside, but
482 # still may be internally-connected so it needs a node name.
483 # Name it what it is called inside, hierarchically nested.
484 inner_node_map = make_node_mapping(inner_args, subckt_nodes[inner_model])
485 new_words.append(rewrite_node(prefix, outer_refdesg, inner_node_map[w]))
486 #print "Floating:",w," now=",new_words,"node map=",inner_node_map
487 else:
488 # A signal only connected within this subcircuit, but not a port.
489 # Make a new node name for it and replace it.
490 if not internal_only_nodes.has_key(w):
491 internal_only_nodes[w] = rewrite_node(prefix, outer_refdesg, w)
492 #print "* sline: %s, Subcircuit %s, mapping internal-only node %s -> %s" % (sline, outer_model, w, internal_only_nodes[w])
494 new_words.append(internal_only_nodes[w])
495 #new_words.append(w)
496 #raise "Expanding subcircuit line '%s' (for line '%s'), couldn't map word %s, nodes=%s" % (sline, line, w, nodes)
498 new_words.append(inner_model)
500 new_lines.append(" ".join(new_words))
501 #new_lines.append("")
502 else:
503 new_lines = [line]
505 return new_lines
507 def test_flatten():
508 """Demonstrate flattening of a hierarchical subcircuit."""
509 if os.access("testcases", os.R_OK | os.X_OK):
510 testdir = "testcases"
511 else:
512 testdir = "."
514 i = 0
515 for case_in in sorted(os.listdir(testdir)):
516 if ".in" not in case_in or ".swp" in case_in:
517 continue
518 case = case_in.replace(".in", "")
520 subckt_nodes, subckt_defns, toplevel = read_netlist("%s/%s.in" % (testdir, case))
522 actual_out = []
523 for line in toplevel:
524 actual_out.extend(expand(subckt_defns, subckt_nodes, line, "", {}, {}))
526 outfile = file("%s/%s.act" % (testdir, case), "wt")
527 for line in actual_out:
528 if line[0] == '*':
529 continue
530 outfile.write("%s\n" % (line,))
531 outfile.close()
533 if os.system("diff -u %s/%s.exp %s/%s.act" % (testdir, case, testdir, case)) != 0:
534 print "%2d. FAILED: %s" % (i, case)
535 raise SystemExit
536 else:
537 print "%2d. Passed: %s" % (i, case)
538 print "-" * 70
539 i += 1
541 def test_assignment():
542 """Demonstrate subcircuit assignment."""
543 subckt_nodes, subckt_defns, toplevel = read_netlist("mux3-1_test.net")
545 mod_tinv, subckt_defns, pos2node_tinv = rewrite_subckt(subckt_defns, "tinv")
546 tg_tinv, subckt_defns, pos2node_tg = rewrite_subckt(subckt_defns, "tg")
549 # Available chips
550 chips = [
551 ("CD4007", get_floating(14) ),
552 ("CD4016", get_floating(14) ),
553 #("CD4007", get_floating(14) )
556 extra = []
557 chips, extra = assign_part(chips, subckt_defns, extra, "tinv",
559 "Vin": "IN_1",
560 "PTI_Out": "PTI_Out_1",
561 "NTI_Out": "NTI_Out_1",
562 "STI_Out": "STI_Out_1",
565 chips, extra = assign_part(chips, subckt_defns, extra, "tinv",
567 "Vin": "IN_2",
568 "PTI_Out": "PTI_Out_2",
569 "NTI_Out": "NTI_Out_2",
570 "STI_Out": "STI_Out_2",
573 chips, extra = assign_part(chips, subckt_defns, extra, "tg",
575 "IN_OUT": "IN_1",
576 "OUT_IN": "OUT_1",
577 "CONTROL": "CTRL_1",
579 chips, extra = assign_part(chips, subckt_defns, extra, "tg",
581 "IN_OUT": "IN_2",
582 "OUT_IN": "OUT_2",
583 "CONTROL": "CTRL_2",
585 chips, extra = assign_part(chips, subckt_defns, extra, "tg",
587 "IN_OUT": "IN_3",
588 "OUT_IN": "OUT_3",
589 "CONTROL": "CTRL_3",
591 chips, extra = assign_part(chips, subckt_defns, extra, "tg",
593 "IN_OUT": "IN_4",
594 "OUT_IN": "OUT_4",
595 "CONTROL": "CTRL_4",
598 dump_chips(chips)
599 dump_extra(extra)
601 def usage():
602 print """usage: %s input-filename [output-filename | -p]
604 input-filename A transistor-level SPICE netlist (.net)
605 output-filename Chip-level SPICE netlist (.net2)
607 If output-filename is omitted, input-filename is used but
608 with '2' appended, so .net becomes .net2 by convention.
610 Either filenames can be "-" for stdin or stdout, respectively.
612 The -p flag, instead of an output filename will also run pads.py
613 so that both .net2 and .pads files will be generated.
614 """ % (PROGRAM_NAME, )
615 raise SystemExit
617 def main():
618 if len(sys.argv) < 2:
619 usage()
620 input_filename = sys.argv[1]
622 generate_pads = len(sys.argv) > 2 and sys.argv[2] == "-p"
624 subckt_nodes, subckt_defns, toplevel = read_netlist(input_filename)
626 # Redirect stdout to output file
627 if len(sys.argv) > 2 and sys.argv[2] != "-p":
628 output_filename = sys.argv[2]
629 else:
630 output_filename = input_filename + "2"
632 if output_filename != "-":
633 sys.stdout = file(output_filename, "wt")
635 print "* Chip-level netlist, converted from %s by %s" % (input_filename, PROGRAM_NAME)
637 # Circuits to rewrite need to be loaded first. Any transistor-level circuits
638 # you want to replace with ICs, are loaded here.
639 modules = pos2node = {}
640 for s in SUBCIRCUITS_CAN_MAP:
641 if subckt_defns.has_key(s):
642 modules[s], subckt_defns, pos2node[s] = rewrite_subckt(subckt_defns, s)
644 # First semi-flatten the circuit
645 flat_toplevel = []
646 for line in toplevel:
647 flat_toplevel.extend((expand(subckt_defns, subckt_nodes, line, "", {}, {})))
649 print "* Flattened top-level, before part assignment:"
650 for f in flat_toplevel:
651 print "** %s" % (f,)
652 print "* Begin converted circuit"
653 print
655 # Available chips
656 chips = []
658 extra = []
659 for line in flat_toplevel:
660 words = line.split()
661 if words[0][0] == 'X':
662 refdesg = words[0]
663 model = words[-1]
664 args = words[1:-1]
666 #print "MODEL=%s, args=%s" % (model, args)
668 #print subckt_defns[model]
669 #print subckt_nodes[model]
671 if model in SUBCIRCUITS_CAN_MAP:
672 nodes = make_node_mapping(subckt_nodes[model], args)
673 #print nodes
674 chips, extra = assign_part(chips, subckt_defns, extra, model, nodes, refdesg)
675 elif model in SUBCIRCUITS_PASS:
676 print line
677 else:
678 raise "Cannot synthesize model: %s, line: %s" % (model, line)
679 else:
680 print line
682 dump_chips(chips)
683 dump_extra(extra)
685 sys.stdout = sys.stderr
687 if generate_pads:
688 import os
689 os.system("python pads.py %s" % (output_filename,))
691 if __name__ == "__main__":
692 if len(sys.argv) > 1 and sys.argv[1] == "-t":
693 test_flatten()
694 raise SystemExit
695 #test_assignment()
696 main()