Re-add credits and title to memory board, but leave the per-trit headers.
[trinary.git] / bb / pads.py
blob98b9aeab3f228ac8a470fcaece132e2b892ba32c
1 #!/usr/bin/env python
2 # Created:20080412
3 # By Jeff Connelly
5 # Created PADS-PCB netlist file, for FreePCB at http://www.freepcb.com/ ,
6 # or any other PCB layout program that supports the PADS-PCB format.
8 import sys
10 PROGRAM_NAME = "pads.py"
12 footprint_map = {
13 "CD4007": "14DIP300",
14 "CD4016": "14DIP300",
15 "R": "RC07", # 1/4 resistor
16 "V": "1X2HDR-100",
17 "sp3t": "SS14MDP2", # NKK switch
18 #"1N4148": "DO-35", # Diode
19 "D": "DO-35", # All diodes (note: should really be specific!)
22 # If enabled, RX$Xflipflop$XX<n>$Xinv$R{P,N} will be mapped to ${P,N}<n>.
23 # Useful for laying out a single dtflop-ms_test, but may cause serious
24 # errors otherwise!
25 SHORT_DTFLOP_RP_RN = False
27 # TODO: remove these limitations on FreePCB, so that
28 # USE_SHORT_NAMES and BREAK_LONG_LINES can be turned off!
30 # If true, reference designators and node names will be assigned
31 # sequentially, instead of using their hierarchical name
32 # from the net2 file. Some PCB programs have length limits
33 # on reference designators (FreePCB).
34 USE_SHORT_NAMES = True
36 # Split long nets over multiple lines.
37 BREAK_LONG_LINES = True
39 # If not false, nodes with only one connection will have a
40 # testpoint attached, using the given footprint.
41 #NAKED_NODE_FOOTPRINT = "HOLE_100_RND_200"
42 NAKED_NODE_FOOTPRINT = None
45 def usage():
46 print """usage: %s input-filename [output-filename]
48 input-filename A chip-level SPICE netlist (.net2)
49 output-filename PADS-PCB layout netlist (.pads)
51 If output-filename is omitted, input-filename is used but
52 with a .pads extension instead of .net2, or .pads appended.
54 Either filenames can be "-" for stdin or stdout, respectively.
55 """ % (PROGRAM_NAME, )
56 raise SystemExit
58 # MAX_NET_NAME_SIZE and FMAX_PIN_NAME_SIZE from
59 # svn://svn.berlios.de/freepcb/trunk/Shape.h and Netlist.h
60 # (TODO: remove these arbitrary limits in FreePCB)
61 MAX_SIZE = 39
63 long2short = {
64 # Names to preserve, if USE_SHORT_NAMES is True.
65 # Would be nice to preserve all/more net names, but
66 # some are just too long and hierarchical.
67 "$G_Vss": "$G_Vss",
68 "$G_Vdd": "$G_Vdd",
69 "0": "0",
71 next_serial = {
72 "R": 1,
73 "NX": 1,
74 "X": 1,
76 def shorten(long, is_netname):
77 if not USE_SHORT_NAMES:
78 return long
80 if SHORT_DTFLOP_RP_RN and long.startswith("RX$Xflipflop$XX"):
81 short = long[len("RX$Xflipflop$XX"):][0]
82 if long.endswith("RP"):
83 short = "RP" + short
84 elif long.endswith("RN"):
85 short = "RN" + short
86 else:
87 sys.stderr.write("dtflop RP/RN mapping enabled, but not RP/RN!")
88 raise SystemExit
89 return short
91 if len(long) <= MAX_SIZE:
92 # We got away with it this time.
93 return long
95 # Resistors are what you have to watch our for
96 if long2short.has_key(long):
97 short = long2short[long]
98 else:
99 # id = first letter, 'R', etc.
100 # Net names get a prefix of "NX" (for node extended;
101 # the name was too long so it was shortened)
102 if is_netname:
103 id = "NX"
104 else:
105 id = long[0]
108 #sys.stderr.write("%s\n" % (long,))
109 short = "%s%d" % (id, next_serial[id])
110 long2short[long] = short
111 next_serial[id] += 1
113 return short
115 if len(sys.argv) < 2:
116 usage()
117 filename = sys.argv[1]
119 # Redirect stdout to output file
120 if len(sys.argv) > 2:
121 output_filename = sys.argv[2]
122 else:
123 output_filename = filename.replace(".net2", ".pads")
124 if output_filename == filename:
125 output_filename = filename + ".pads"
126 if output_filename != "-":
127 sys.stdout = file(output_filename, "wt")
129 print "*PADS-PCB*"
130 print "*%s*" % (filename, )
132 parts = []
133 nets = {}
134 if filename == "-":
135 infile = sys.stdin
136 else:
137 infile = file(filename, "rt")
138 for line in infile.readlines():
139 if line[0] == '*':
140 continue
142 line = line.strip()
143 if len(line) == 0:
144 continue
146 words = line.split()
147 long_refdesg = words[0]
149 refdesg = shorten(long_refdesg, is_netname=False)
151 args = words[1:-1]
152 if refdesg[0] == 'V':
153 # Voltage sources only have two pins, other arguments
154 # may be PWL or other values (really one argument, but
155 # separated by spaces, so we'll see it as more than one).
156 args = [args[0], args[1]]
158 # Make nets list
159 for i, long_arg in enumerate(args):
160 if long_arg.startswith("NC_"):
161 continue
163 #if arg == "0":
164 # arg = "GND"
166 #sys.stderr.write("-> %s" % (line,))
167 arg = shorten(long_arg, is_netname=True)
169 if arg not in nets.keys():
170 nets[arg] = []
172 nets[arg].append("%s.%s" % (refdesg, i + 1))
174 model = words[-1]
176 # Make parts list
177 parts.append((refdesg, model))
179 # Map models to footprints
180 print "*PART*"
181 for part in parts:
182 refdesg, model = part
183 if footprint_map.has_key(model):
184 package = footprint_map[model]
185 elif footprint_map.has_key(refdesg[0]):
186 package = footprint_map[refdesg[0]]
187 else:
188 raise "Part name %s, model %s unknown, couldn't find in map: %s" % (refdesg, model, footprint_map)
189 print "%s %s" % (refdesg, package)
191 # Nets with only one node get testpoints for free (also appends to parts list)
192 if NAKED_NODE_FOOTPRINT:
193 for signal_name, nodes in nets.iteritems():
194 if len(nodes) == 1:
195 testpoint = "%s_tp" % (signal_name,)
196 print "%s %s" % (testpoint, NAKED_NODE_FOOTPRINT)
197 nets[signal_name].append(testpoint)
200 # Dump all nets
201 print "*NET*"
202 for signal, pins in nets.iteritems():
203 print "*SIGNAL* %s" % (signal,)
204 if BREAK_LONG_LINES:
205 i = 0
206 for p in pins:
207 print p,
208 # Break lines every so many pins
209 # (would be nice if didn't have to do this)
210 if i % 5 == 0:
211 print
212 i += 1
213 print
214 else:
215 print " ".join(pins)
217 # Print a newline at the end for picky layout programs (ExpressPCB)
218 print