Chip mapper: include resistor value in resistor network name.
[trinary.git] / bb / pads.py
blob2d229a53f2152e689a57a06725ec24a289b89b31
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, os
10 PROGRAM_NAME = "pads.py"
12 footprint_map = {
13 "CD4007": "14DIP300",
14 "CD4016": "14DIP300",
15 "R": "RC07", # 1/4 W resistor
16 "MDP1403-12K": "14DIP300", # 7 x resistor network, all 12k
17 "V": "1X2HDR-100-40", # header, **with 40 mil holes**
18 "sp3t-1": "SS14MDP2", # NKK switch, in position 1
19 "sp3t-2": "SS14MDP2", # NKK switch, in position 2
20 "sp3t-3": "SS14MDP2", # NKK switch, in position 3
21 #"1N4148": "DO-35", # Diode
22 "D": "DO-35", # All diodes (note: should really be specific!)
25 # TODO: Add bypass capacitor? Might be better done
26 # manually, on back of board, directly between 7 and 14.
28 # TODO: Connect not-connected pins? Probably a good idea but
29 # be careful about shorting something. Could also be done
30 # manually, with copious amounts of solder.
32 # Append/prepend this to all part and net names (note, prefix may
33 # cause problems with footprint mapping, if can't be recognized.)
34 UNIVERSAL_SUFFIX = ""
35 UNIVERSAL_PREFIX = ""
37 # Append/prepend to all net names
38 NETNAME_SUFFIX = os.environ.get("JC_NETNAME_SUFFIX", "")
39 NETNAME_PREFIX = ""
41 # If enabled, name resistors numerically R1, R2, ... instead of hierarchically.
42 SERIAL_RESISTORS = True
43 RESISTOR_SERIAL_START = int(os.environ.get("JC_RESISTOR_SERIAL_START", 0))
45 # If enabled, anything containing Vdd or Vss will be named Vdd or Vss--
46 # effectively disabling hierarchy for these power sources. **Note that if
47 # there are multiple Vdd and Vss, this will cause duplicate parts!**
48 SHORT_VDD_VSS = True
50 # If enabled, RX$Xflipflop$XX<n>$Xinv$R{P,N} will be mapped to ${P,N}<n>.
51 # Useful for laying out a single dtflop-ms_test, but may cause serious
52 # errors otherwise!
53 SHORT_DTFLOP_RP_RN = False
55 # TODO: remove these limitations on FreePCB, so that
56 # USE_SHORT_NAMES and BREAK_LONG_LINES can be turned off!
58 # If true, reference designators and node names will be assigned
59 # sequentially if needed, instead of using their hierarchical name
60 # from the net2 file. Some PCB programs have length limits
61 # on reference designators (FreePCB).
62 USE_SHORT_NAMES = True
64 # Split long nets over multiple lines.
65 BREAK_LONG_LINES = True
67 # If not false, nodes with only one connection will have a
68 # testpoint attached, using the given footprint.
69 #NAKED_NODE_FOOTPRINT = "HOLE_100_RND_200"
70 NAKED_NODE_FOOTPRINT = None
73 def usage():
74 print """usage: %s input-filename [output-filename]
76 input-filename A chip-level SPICE netlist (.net2)
77 output-filename PADS-PCB layout netlist (.pads)
79 If output-filename is omitted, input-filename is used but
80 with a .pads extension instead of .net2, or .pads appended.
82 Either filenames can be "-" for stdin or stdout, respectively.
83 """ % (PROGRAM_NAME, )
84 raise SystemExit
86 # MAX_NET_NAME_SIZE and FMAX_PIN_NAME_SIZE from
87 # svn://svn.berlios.de/freepcb/trunk/Shape.h and Netlist.h
88 # (TODO: remove these arbitrary limits in FreePCB)
89 MAX_SIZE = 39
91 long2short = {
92 # Names to preserve, if USE_SHORT_NAMES is True.
93 # Would be nice to preserve all/more net names, but
94 # some are just too long and hierarchical.
95 "$G_Vss": "$G_Vss",
96 "$G_Vdd": "$G_Vdd",
97 "0": "0",
99 next_serial = {
100 "R": 1,
101 "NX": 1,
102 "X": 1,
105 resistor_serial = RESISTOR_SERIAL_START
107 def shorten(long, is_netname):
108 short = UNIVERSAL_PREFIX + shorten_2(long, is_netname) + UNIVERSAL_SUFFIX
109 if is_netname:
110 short = NETNAME_PREFIX + short + NETNAME_SUFFIX
112 return short
114 def shorten_2(long, is_netname):
115 global resistor_serial
117 if SHORT_VDD_VSS:
118 if "Vdd" in long:
119 return "Vdd"
120 if "Vss" in long:
121 return "Vss"
123 if long.startswith("R") and SERIAL_RESISTORS:
124 resistor_serial += 1
125 return "R%d" % (resistor_serial,)
127 if not USE_SHORT_NAMES:
128 return long
130 if SHORT_DTFLOP_RP_RN and long.startswith("RX$Xflipflop$XX"):
131 short = long[len("RX$Xflipflop$XX"):][0]
132 if long.endswith("RP"):
133 short = "RP" + short
134 elif long.endswith("RN"):
135 short = "RN" + short
136 else:
137 sys.stderr.write("dtflop RP/RN mapping enabled, but not RP/RN!")
138 raise SystemExit
139 return short
141 if len(long) <= MAX_SIZE:
142 # We got away with it this time.
143 return long
145 # Resistors are what you have to watch our for
146 if long2short.has_key(long):
147 short = long2short[long]
148 else:
149 # id = first letter, 'R', etc.
150 # Net names get a prefix of "NX" (for node extended;
151 # the name was too long so it was shortened)
152 if is_netname:
153 id = "NX"
154 else:
155 id = long[0]
158 #sys.stderr.write("%s\n" % (long,))
159 short = "%s%d" % (id, next_serial[id])
160 long2short[long] = short
161 next_serial[id] += 1
163 return short
165 if len(sys.argv) < 2:
166 usage()
167 filename = sys.argv[1]
169 # Redirect stdout to output file
170 if len(sys.argv) > 2:
171 output_filename = sys.argv[2]
172 else:
173 output_filename = filename.replace(".net2", ".pads")
174 if output_filename == filename:
175 output_filename = filename + ".pads"
176 if output_filename != "-":
177 sys.stdout = file(output_filename, "wt")
179 print "*PADS-PCB*"
180 print "*%s*" % (filename, )
182 parts = []
183 nets = {}
184 if filename == "-":
185 infile = sys.stdin
186 else:
187 infile = file(filename, "rt")
188 for line in infile.readlines():
189 if line[0] == '*':
190 continue
192 line = line.strip()
193 if len(line) == 0:
194 continue
196 words = line.split()
197 long_refdesg = words[0]
199 refdesg = shorten(long_refdesg, is_netname=False)
201 args = words[1:-1]
202 if refdesg[0] == 'V':
203 # Voltage sources only have two pins, other arguments
204 # may be PWL or other values (really one argument, but
205 # separated by spaces, so we'll see it as more than one).
206 args = [args[0], args[1]]
208 # Make nets list
209 for i, long_arg in enumerate(args):
210 if long_arg.startswith("NC_"):
211 continue
213 #if arg == "0":
214 # arg = "GND"
216 #sys.stderr.write("-> %s" % (line,))
217 arg = shorten(long_arg, is_netname=True)
219 if arg not in nets.keys():
220 nets[arg] = []
222 nets[arg].append("%s.%s" % (refdesg, i + 1))
224 model = words[-1]
226 # Make parts list
227 parts.append((refdesg, model))
230 # Map models to footprints
231 print "*PART*"
232 for part in parts:
233 refdesg, model = part
234 if footprint_map.has_key(model):
235 package = footprint_map[model]
236 elif footprint_map.has_key(refdesg[0]):
237 package = footprint_map[refdesg[0]]
238 else:
239 raise "Part name %s, model %s unknown, couldn't find in map: %s" % (refdesg, model, footprint_map)
240 print "%s %s" % (refdesg, package)
242 # Nets with only one node get testpoints for free (also appends to parts list)
243 if NAKED_NODE_FOOTPRINT:
244 for signal_name, nodes in nets.iteritems():
245 if len(nodes) == 1:
246 testpoint = "%s_tp" % (signal_name,)
247 print "%s %s" % (testpoint, NAKED_NODE_FOOTPRINT)
248 nets[signal_name].append(testpoint)
251 # Dump all nets
252 print "*NET*"
253 for signal, pins in nets.iteritems():
254 print "*SIGNAL* %s" % (signal,)
255 if BREAK_LONG_LINES:
256 i = 0
257 for p in pins:
258 print p,
259 # Break lines every so many pins
260 # (would be nice if didn't have to do this)
261 if i % 5 == 0:
262 print
263 i += 1
264 print
265 else:
266 print " ".join(pins)
268 # Print a newline at the end for picky layout programs (ExpressPCB)
269 print