Chip mapper: add support for MDP1403 7-resistor network.
[trinary.git] / bb / bb.py
blobf2f5b0d0585aab4d3b7c12813b98f6ff27dffe61
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 = int(os.environ.get("JC_CHIP_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 # If False, use discrete resistors
32 # If True, use the MDP140 resistor network
33 USE_RESISTOR_CHIP = os.environ.get("JC_USE_RESISTOR_CHIP", True)
34 RESISTOR_CHIP = "MDP1403" # Vishay isolated 7-resistor network
36 KNOWN_CHIPS = (
37 "CD4007", # dual complementary MOSFETs + binary inverter
38 "CD4016", # quad transmission gates
39 RESISTOR_CHIP
42 # Pairs of pins
43 RESISTOR_NETWORK_PINS = ((1, 14), (2, 13), (3, 12), (4, 11), (5, 10), (6, 9), (7,8))
45 def combine_dicts(dict1, dict2):
46 """Combine two dictionaries; dict2 takes priority over dict1."""
47 ret = copy.deepcopy(dict1)
48 ret.update(dict2)
49 return ret
51 def read_netlist(filename):
52 """Read a SPICE input deck, returning subcircuit nodes and definitions."""
54 if filename == "-":
55 f = sys.stdin
56 else:
57 f = file(filename, "rt")
58 subckt_nodes = {}
59 subckt_defns = {}
60 toplevel = []
61 name = None
62 while True:
63 line = f.readline()
64 if len(line) == 0:
65 break
67 line = line.strip()
69 if line.startswith(".subckt"):
70 words = line.split()
71 name = words[1]
72 nodes = words[2:]
74 subckt_nodes[name] = nodes
75 elif line.startswith(".ends"):
76 name = None
77 else:
78 if name is not None:
79 if not subckt_defns.has_key(name):
80 subckt_defns[name] = []
81 subckt_defns[name].append(line)
82 else:
83 # Top-level elements, skip blank lines, commands and comments
84 if len(line.strip()) != 0 and line[0] not in ('.', '*'):
85 toplevel.append(line)
87 return subckt_nodes, subckt_defns, toplevel
89 def rewrite_subckt(subckt_defns, s):
90 """Partially rewrite subcircuit 's', using rules from a module of the same name.
92 Removes parts in mod.parts_consumed, keeps parts in mod.parts_kept.
94 Does not generate any new parts."""
96 mod = globals()[s]
97 lines = []
98 for line in subckt_defns[s]:
99 words = line.split()
100 name = words[0]
101 args = words[1:]
103 if name in mod.parts_consumed:
104 # Skip this line
105 pass
106 elif name in mod.parts_kept:
107 lines.append(line)
108 else:
109 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)
111 # Map node positions in arguments list (subckt invocation, X..), to node names
112 pos2node = {}
113 for i in range(0, len(mod.nodes)):
114 pos2node[mod.nodes[i]] = i
116 # Rewrite
117 subckt_defns[s] = lines
119 return mod, subckt_defns, pos2node
121 next_serial = -1
122 def get_serial():
123 """Get a unique, increasing number."""
124 global next_serial
126 next_serial += 1
127 return next_serial
129 def get_floating(n=None):
130 """Return a unique disconnected (floating) node name.
132 If n is given, return a dict of n floating node names. Otherwise returns one in a string."""
133 if n is not None:
134 return get_floating_n(n)
136 return "NC__%s" % (get_serial(), )
138 def get_floating_n(n):
139 """Get n floating nodes, see get_floating()."""
140 fs = {}
141 for x in range(1, n + 1):
142 fs[x] = get_floating()
143 return fs
145 def is_floating(node_name):
146 """Return whether the given node name is probably not connected;
147 generated from get_floating()."""
148 return node_name.startswith("NC_")
150 def chip_has_pins_available(pins_needed, pins):
151 """Return whether 'pins' has not-connected pins, all those required in pins_needed."""
152 for p in pins_needed:
153 if not is_floating(pins[p]):
154 return False
155 return True
157 # This program doesn't thoroughly parse SPICE cards, so you must
158 # give it parameters that are not nodes, to not map at all.
159 # For example, '12k' for the 12k resistors. TODO: better parsing
160 def find_chip(chips, model_needed, pins_needed_options):
161 """Return an index into the chips array, and what pins, with the given model and the pins free.
163 pins_needed_options is a list of lists, of any acceptable set of pins to use.
165 A new chip is added if none are found. """
167 result = find_chip_no_add(chips, model_needed, pins_needed_options)
168 if result is not None:
169 return result
171 # No chips found with model model_needed and with pins free. Need more chips.
172 if model_needed not in KNOWN_CHIPS:
173 raise "Model %s not known, it is not in %s, not recognized!" % (model_needed, KNOWN_CHIPS)
175 # Add a new chip!
176 # Assume all are 14-pin chips
177 chips.append((model_needed, get_floating(14)))
179 result = find_chip_no_add(chips, model_needed, pins_needed_options)
180 if result is not None:
181 return result
183 raise "Tried to find model %s with pins %s free, then added a new chip but couldn't find it!" % (
184 model_needed, pins_needed_options)
186 def find_chip_no_add(chips, model_needed, pins_needed_options):
187 """Find chip to use (see find_chip), but return None if not found instead of adding."""
188 for i, chip in enumerate(chips):
189 model, pins = chip
190 if model != model_needed:
191 continue
193 for option_num, option in enumerate(pins_needed_options):
194 # Note: I do not yet check if the chip has pins that are used, but are assigned to
195 # the same node that is required. The pins must be unused.
196 if chip_has_pins_available(option, pins):
197 #print "* Found model %s with pins %s free: chip #%s" % (model_needed, option, i)
198 return i, option_num
199 return None
201 def find_pins_needed(pins):
202 """From a mod.pins[x] dict, return the pins needed for each SPICE model, for find_chip()"""
203 need = {}
204 for x in pins.values():
205 if type(x) == types.TupleType:
206 model, pin = x
207 if not need.has_key(model):
208 need[model] = []
210 need[model].append(pin)
211 elif type(x) == types.ListType:
212 for mp in x:
213 model, pin = mp
214 if not need.has_key(model):
215 need[model] = []
217 need[model].append(pin)
219 return need
221 def assign_part(chips, subckt_defns, extra, model_name, external_nodes, refdesg):
222 """Assign a given model to a physical chip, using the names of the external nodes.
224 chips: array of existing physical chips that can be assigned from
225 mod: logical model to map to, like 'tinv'
226 external_nodes: dict mapping internal nodes in the model, to external nodes in the world
229 mod = globals()[model_name]
230 subckt_lines = subckt_defns[model_name]
233 # Store new pin assignments
234 assignments = {}
235 for p in mod.parts_generated:
236 assignments[p] = {}
238 need_options = []
239 the_model = None
240 for p in mod.pins:
241 need = find_pins_needed(p)
242 if len(need) > 1:
243 raise "Sorry, more than one model is needed: %s, but only one is supported right now." % (need,)
244 if the_model is None:
245 the_model = need.keys()[0]
246 else:
247 if the_model != need.keys()[0]:
248 raise "Sorry, different models are needed: %s, but already decided on %s earlier. This is not yet supported." % (the_model, need[0])
250 need_options.append(need.values()[0])
252 #print "* Searching for model %s with one of pins: %s" % (the_model, need_options)
253 chip_num, option_num = find_chip(chips, the_model, need_options)
254 #print "* FOUND CHIP:",chip_num
255 #print "* WITH PINS (option #%s):" % (option_num,), mod.pins[option_num]
257 findings = []
258 for node_pin in combine_dicts(mod.global_pins, mod.pins[option_num]).iteritems():
259 node, pin = node_pin
261 if type(pin) == types.TupleType:
262 part, pin = pin
263 findings.append((node, part, pin))
264 elif type(pin) == types.ListType:
265 for pp in pin:
266 part, p = pp
267 findings.append((node, part, p))
268 else:
269 part = None
270 findings.append((node, part, pin))
272 for node, part, pin in findings:
273 #print "* %s -> %s:%s" % (node, part, pin)
275 if part is not None:
276 if node.startswith("$G_") or node == "0":
277 new_node = node # global node (LTspice)
278 elif external_nodes.has_key(node):
279 #sys.stderr.write("Mapping external node %s, map = %s\n" % (node, external_nodes))
280 new_node = external_nodes[node] # map internal to external node
281 else:
282 #sys.stderr.write("Mapping internal-only node %s\n" % (node,))
283 # 'refdesg' here is prefixed with X, for a subcircuit instantation,
284 # but we only need the subcircuit prefix for a node, without the
285 # X prefix.
286 assert refdesg[0:2] == 'X$', "Assumed refdesg %s began with X$, but it didn't" % (refdesg,)
287 refdesg_without_letter = refdesg[2:]
288 new_node = rewrite_node("", refdesg_without_letter, node)
289 #sys.stderr.write("Rewriting to node = %s\n" % (new_node,))
291 #sys.stderr.write("Adding to chips: %s\n" % (new_node,))
292 chips[chip_num][1][pin] = new_node
294 internal_only_nodes = {}
296 # Now place any ++additional parts++ (resistors, etc.) within the subcircuit model
297 # that connect to the chip, but are not part of the chip.
298 for line in subckt_lines:
299 words = line.split()
300 new_words = []
302 if words[0][0] == "M":
303 raise ("This line:\t%s\nIn the subcircuit '%s', has a MOSFET left " +
304 "over that wasn't converted. Probably it was meant to be converted to an IC? " +
305 "Comment out this line in %s if you are sure you want this, otherwise " +
306 "double-check the model definition for '%s', specifically, " +
307 "parts_consumed and parts_kept.\nAlso, check if the model was rewritten!") % (line, model_name, PROGRAM_NAME, model_name)
310 #name = "%s_%s_%s_%s" % (words[0], model_name, chip_num, refdesg)
311 name = "%s%s$%s" % (words[0][0], refdesg, words[0])
313 new_words.append(name)
315 args = words[1:-1]
316 model_name = words[-1]
318 # Replace internal nodes with external nodes.
319 for w in args:
320 if w in external_nodes.keys():
321 new_words.append(external_nodes[w])
322 elif is_floating(w):
323 # TODO ???
324 new_words.append(get_floating())
325 else:
326 if not internal_only_nodes.has_key(w):
327 #internal_only_nodes[w] = "%s$%s$%s" % (w[0], refdesg, w)
328 assert refdesg[0:2] == 'X$', "Reference designator %s expected to begin with X$, but didn't" % (refdesg,)
329 refdesg_without_letter = refdesg[2:]
330 internal_only_nodes[w] = rewrite_node("", refdesg_without_letter, w)
331 new_words.append(internal_only_nodes[w])
333 # TODO: comment this out, if the above works
334 #raise "Could not map argument '%s' in subcircuit line %s, not found in %s" % (w, line, external_nodes)
336 new_words.append(model_name)
338 if words[0][0] == "R" and USE_RESISTOR_CHIP:
339 chip_num, option_num = find_chip(chips, RESISTOR_CHIP, RESISTOR_NETWORK_PINS)
340 pins = RESISTOR_NETWORK_PINS[option_num]
341 chips[chip_num][1][pins[0]] = new_words[1]
342 chips[chip_num][1][pins[1]] = new_words[2]
343 else:
344 extra.append(" ".join(new_words))
346 return chips, extra
348 def any_pins_used(pins):
349 """Return whether any of the pins on a chip are used. If False, chip isn't used."""
350 for p in pins.values():
351 if not is_floating(p):
352 return True
353 return False
355 def dump_chips(chips):
356 """Show the current chips and their pin connections."""
357 for i, c in enumerate(chips):
358 m, p = c
360 if not any_pins_used(p):
361 print "* Chip #%s - %s no pins used, skipping" % (i + CHIP_NO_START, m)
362 continue
364 print "* Chip #%s - %s pinout:" % (i + CHIP_NO_START, m)
365 for k, v in p.iteritems():
366 print "* \t%s: %s" % (k, v)
368 print "IC_%s_%s" % (m, i + CHIP_NO_START),
369 # Assumes all chips are 14-pin, arguments from 1 to 14 positional
370 for k in range(1, 14+1):
371 print p[k],
372 print m
373 print
375 def dump_extra(extra):
376 """Shows the extra, supporting subcircuit parts that support the IC and are part of the subcircuit."""
377 print "* Parts to support subcircuits:"
378 for e in extra:
379 print e
381 def make_node_mapping(internal, external):
382 """Make a node mapping dictionary from internal to external nodes.
383 Keys of the returned dictionary are internal nodes (of subcircuit), values are external."""
384 d = {}
385 d.update(zip(internal, external))
386 return d
388 def rewrite_refdesg(original, prefix):
389 """Prefix a reference designator, preserving the first character."""
390 new_refdesg = "%s%s$%s" % (original[0], prefix, original)
392 #sys.stderr.write("@ rewrite_refdesg = %s\n" % (new_refdesg,))
393 return new_refdesg
395 def rewrite_node(prefix, circuit_inside, original_node_name):
396 """Rewrite a node name inside a subcircuit, prefixing it with
397 prefix and the name of the circuit that it is inside (both
398 are optional)."""
400 # Globals never rewritten
401 if original_node_name.startswith("$G_") or original_node_name == "0":
402 return original_node_name
404 new_name = original_node_name
405 if circuit_inside:
406 new_name = "%s$%s" % (circuit_inside, new_name)
408 if prefix:
409 new_name = "%s$%s" % (prefix, new_name)
411 # Nodes don't need to begin with spurious '$'s (can happen if no prefix)
412 if new_name[0] == '$':
413 new_name = new_name[1:]
415 #sys.stderr.write("@@ rewrite_node = %s\n" % (new_name,))
416 return new_name
418 def is_expandable_subcircuit(refdesg, model):
419 """Return whether the SPICE reference designator and model is
420 a) a subcircuit, b) _and_ it can be hierarchically expanded further."""
421 return refdesg[0] == 'X' and model not in SUBCIRCUITS_TO_MAP
423 def expand(subckt_defns, subckt_nodes, line, prefix, outer_nodes, outer_prefixes):
424 """Recursively expand a subcircuit instantiation if needed."""
425 words = line.split()
426 outer_refdesg = words[0]
427 outer_model = words[-1]
428 outer_args = words[1:-1]
430 #sys.stderr.write("expand(%s,%s,%s,%s)\n" % (line, prefix, outer_nodes, outer_prefixes))
431 if is_expandable_subcircuit(outer_refdesg, outer_model):
432 nodes = make_node_mapping(subckt_nodes[outer_model], outer_args)
433 new_lines = []
434 new_lines.append(("* %s: Instance of subcircuit %s: %s" % (outer_refdesg, outer_model, " ".join(outer_args))))
436 # Notes that are internal to the subcircuit, not exposed in any ports
437 internal_only_nodes = {}
439 for sline in subckt_defns[outer_model]:
440 swords = sline.split()
441 inner_refdesg = swords[0]
442 inner_model = swords[-1]
443 inner_args = swords[1:-1]
445 if is_expandable_subcircuit(inner_refdesg, inner_model):
446 # Recursively expand subcircuits, to transistor-level subcircuits (SUBCIRCUITS_TO_MAP)
447 nodes_to_pass = {}
448 prefixes_to_pass = {}
449 for n in nodes:
450 if outer_nodes.has_key(nodes[n]):
451 nodes_to_pass[n] = outer_nodes[nodes[n]]
452 prefixes_to_pass[nodes_to_pass[n]] = outer_prefixes[nodes_to_pass[n]]
453 else:
454 nodes_to_pass[n] = nodes[n]
455 prefixes_to_pass[nodes_to_pass[n]] = prefix
456 # Only append separator if not empty
457 if prefix:
458 prefixes_to_pass[nodes_to_pass[n]] += "$"
460 # Chop '$' if begins with it
461 if len(prefixes_to_pass[nodes_to_pass[n]]) >= 1 and prefixes_to_pass[nodes_to_pass[n]][0] == '$':
462 prefixes_to_pass[nodes_to_pass[n]] = prefixes_to_pass[nodes_to_pass[n]][1:]
463 #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))
464 #sys.stderr.write("\tPASSING PREFIXES: %s (outer=%s)\n" % (prefixes_to_pass, outer_prefixes))
465 new_lines.extend(expand(subckt_defns, subckt_nodes, sline, prefix +
466 "$" + outer_refdesg, nodes_to_pass, prefixes_to_pass))
467 else:
468 new_words = []
469 # Nest reference designator
470 new_words.append(rewrite_refdesg(inner_refdesg, prefix + "$" + outer_refdesg))
472 # Map internal to external nodes
473 for w in inner_args:
474 #print "****", word
475 if w in nodes.keys():
476 # Follow up the hierarchy. Without doing this, leads to:
477 # incomplete nets. For example, dtflop-ms_test.net maps:
479 # In nodes {'Q': 'Q', 'C': 'CLK', 'D': 'D'}, rewrite C -> CLK, prefix [correct]
480 # In nodes {'Q': 'Q', 'C': 'CLK', 'D': 'D'}, rewrite C -> CLK, prefix [correct]
482 # but because the 'nodes' dict is only for the parent, it
483 # doesn't map this correctly, leading to an unconnected node:
485 # In nodes {'OUT': '_C', 'IN': 'C'}, rewrite IN -> C, prefix Xflipflop [wrong]
487 # It should be CLK, not Xflipflop$C. These problems will occur
488 # with more nesting of subcircuits
489 if nodes[w] in outer_nodes:
490 # This is a port of this subcircuit, ascends hierarchy
491 new_words.append(outer_prefixes[outer_nodes[nodes[w]]] + outer_nodes[nodes[w]])
492 #new_words.append(outer_nodes[nodes[w]])
493 #sys.stderr.write("Node %s -> %s -> %s (outer nodes=%s, prefixes=%s) (prefix=%s, refdesgs=%s,%s)\n" %
494 # (w, nodes[w], outer_nodes[nodes[w]], outer_nodes, outer_prefixes, prefix,
495 # outer_refdesg, inner_refdesg))
496 else:
497 new_words.append(rewrite_node(prefix, "", nodes[w]))
499 elif is_floating(w):
500 # This is a port, but that is not connected on the outside, but
501 # still may be internally-connected so it needs a node name.
502 # Name it what it is called inside, hierarchically nested.
503 inner_node_map = make_node_mapping(inner_args, subckt_nodes[inner_model])
504 new_words.append(rewrite_node(prefix, outer_refdesg, inner_node_map[w]))
505 #print "Floating:",w," now=",new_words,"node map=",inner_node_map
506 else:
507 # A signal only connected within this subcircuit, but not a port.
508 # Make a new node name for it and replace it.
509 if not internal_only_nodes.has_key(w):
510 internal_only_nodes[w] = rewrite_node(prefix, outer_refdesg, w)
511 #print "* sline: %s, Subcircuit %s, mapping internal-only node %s -> %s" % (sline, outer_model, w, internal_only_nodes[w])
513 new_words.append(internal_only_nodes[w])
514 #new_words.append(w)
515 #raise "Expanding subcircuit line '%s' (for line '%s'), couldn't map word %s, nodes=%s" % (sline, line, w, nodes)
517 new_words.append(inner_model)
519 new_lines.append(" ".join(new_words))
520 #new_lines.append("")
521 else:
522 new_lines = [line]
524 return new_lines
526 def test_flatten():
527 """Demonstrate flattening of a hierarchical subcircuit."""
528 if os.access("testcases", os.R_OK | os.X_OK):
529 testdir = "testcases"
530 else:
531 testdir = "."
533 i = 0
534 for case_in in sorted(os.listdir(testdir)):
535 if ".in" not in case_in or ".swp" in case_in:
536 continue
537 case = case_in.replace(".in", "")
539 subckt_nodes, subckt_defns, toplevel = read_netlist("%s/%s.in" % (testdir, case))
541 actual_out = []
542 for line in toplevel:
543 actual_out.extend(expand(subckt_defns, subckt_nodes, line, "", {}, {}))
545 outfile = file("%s/%s.act" % (testdir, case), "wt")
546 for line in actual_out:
547 if line[0] == '*':
548 continue
549 outfile.write("%s\n" % (line,))
550 outfile.close()
552 if os.system("diff -u %s/%s.exp %s/%s.act" % (testdir, case, testdir, case)) != 0:
553 print "%2d. FAILED: %s" % (i, case)
554 raise SystemExit
555 else:
556 print "%2d. Passed: %s" % (i, case)
557 print "-" * 70
558 i += 1
560 def test_assignment():
561 """Demonstrate subcircuit assignment."""
562 subckt_nodes, subckt_defns, toplevel = read_netlist("mux3-1_test.net")
564 mod_tinv, subckt_defns, pos2node_tinv = rewrite_subckt(subckt_defns, "tinv")
565 tg_tinv, subckt_defns, pos2node_tg = rewrite_subckt(subckt_defns, "tg")
568 # Available chips
569 chips = [
570 ("CD4007", get_floating(14) ),
571 ("CD4016", get_floating(14) ),
572 #("CD4007", get_floating(14) )
575 extra = []
576 chips, extra = assign_part(chips, subckt_defns, extra, "tinv",
578 "Vin": "IN_1",
579 "PTI_Out": "PTI_Out_1",
580 "NTI_Out": "NTI_Out_1",
581 "STI_Out": "STI_Out_1",
584 chips, extra = assign_part(chips, subckt_defns, extra, "tinv",
586 "Vin": "IN_2",
587 "PTI_Out": "PTI_Out_2",
588 "NTI_Out": "NTI_Out_2",
589 "STI_Out": "STI_Out_2",
592 chips, extra = assign_part(chips, subckt_defns, extra, "tg",
594 "IN_OUT": "IN_1",
595 "OUT_IN": "OUT_1",
596 "CONTROL": "CTRL_1",
598 chips, extra = assign_part(chips, subckt_defns, extra, "tg",
600 "IN_OUT": "IN_2",
601 "OUT_IN": "OUT_2",
602 "CONTROL": "CTRL_2",
604 chips, extra = assign_part(chips, subckt_defns, extra, "tg",
606 "IN_OUT": "IN_3",
607 "OUT_IN": "OUT_3",
608 "CONTROL": "CTRL_3",
610 chips, extra = assign_part(chips, subckt_defns, extra, "tg",
612 "IN_OUT": "IN_4",
613 "OUT_IN": "OUT_4",
614 "CONTROL": "CTRL_4",
617 dump_chips(chips)
618 dump_extra(extra)
620 def usage():
621 print """usage: %s input-filename [output-filename | -p]
623 input-filename A transistor-level SPICE netlist (.net)
624 output-filename Chip-level SPICE netlist (.net2)
626 If output-filename is omitted, input-filename is used but
627 with '2' appended, so .net becomes .net2 by convention.
629 Either filenames can be "-" for stdin or stdout, respectively.
631 The -p flag, instead of an output filename will also run pads.py
632 so that both .net2 and .pads files will be generated.
633 """ % (PROGRAM_NAME, )
634 raise SystemExit
636 def main():
637 if len(sys.argv) < 2:
638 usage()
639 input_filename = sys.argv[1]
641 generate_pads = len(sys.argv) > 2 and sys.argv[2] == "-p"
643 subckt_nodes, subckt_defns, toplevel = read_netlist(input_filename)
645 # Redirect stdout to output file
646 if len(sys.argv) > 2 and sys.argv[2] != "-p":
647 output_filename = sys.argv[2]
648 else:
649 output_filename = input_filename + "2"
651 if output_filename != "-":
652 sys.stdout = file(output_filename, "wt")
654 print "* Chip-level netlist, converted from %s by %s" % (input_filename, PROGRAM_NAME)
656 # Circuits to rewrite need to be loaded first. Any transistor-level circuits
657 # you want to replace with ICs, are loaded here.
658 modules = pos2node = {}
659 for s in SUBCIRCUITS_CAN_MAP:
660 if subckt_defns.has_key(s):
661 modules[s], subckt_defns, pos2node[s] = rewrite_subckt(subckt_defns, s)
663 # First semi-flatten the circuit
664 flat_toplevel = []
665 for line in toplevel:
666 flat_toplevel.extend((expand(subckt_defns, subckt_nodes, line, "", {}, {})))
668 print "* Flattened top-level, before part assignment:"
669 for f in flat_toplevel:
670 print "** %s" % (f,)
671 print "* Begin converted circuit"
672 print
674 # Available chips
675 chips = []
677 extra = []
678 for line in flat_toplevel:
679 words = line.split()
680 if words[0][0] == 'X':
681 refdesg = words[0]
682 model = words[-1]
683 args = words[1:-1]
685 #print "MODEL=%s, args=%s" % (model, args)
687 #print subckt_defns[model]
688 #print subckt_nodes[model]
690 if model in SUBCIRCUITS_CAN_MAP:
691 nodes = make_node_mapping(subckt_nodes[model], args)
692 #print nodes
693 chips, extra = assign_part(chips, subckt_defns, extra, model, nodes, refdesg)
694 elif model in SUBCIRCUITS_PASS:
695 print line
696 else:
697 raise "Cannot synthesize model: %s, line: %s" % (model, line)
698 else:
699 print line
701 dump_chips(chips)
702 dump_extra(extra)
704 sys.stdout = sys.stderr
706 if generate_pads:
707 import os
708 os.system("python pads.py %s" % (output_filename,))
710 if __name__ == "__main__":
711 if len(sys.argv) > 1 and sys.argv[1] == "-t":
712 #test_assignment()
713 test_flatten()
714 raise SystemExit
715 main()