add naming and pin-order reverse option
[pinmux.git] / src / spec / ifaceprint.py
1 #!/usr/bin/env python
2
3 from copy import deepcopy
4 from collections import OrderedDict
5 import svgwrite
6 from math import pi
7
8
9 def create_sv(fname, pins):
10 """unsophisticated drawer of an SVG
11 """
12
13 scale = 15
14 width = len(pins['pads.north']) * scale
15 height = len(pins['pads.east']) * scale
16 woffs = scale*18#-width/2
17 hoffs = scale*18#-height/2
18
19 dwg = svgwrite.Drawing(fname, profile='full',
20 size=(width+scale*40, height+scale*40))
21 dwg.add(dwg.rect((woffs-scale*2, hoffs-scale*2),
22 (woffs+width-scale*12, hoffs+height-scale*12),
23 stroke=svgwrite.rgb(255, 255, 16, '%'),
24 stroke_width=scale/10.0))
25
26 dwg.add(dwg.text("Libre-SOC ls180",
27 insert=(woffs+width/2-scale*5, woffs+height/2),
28 fill='white'))
29 dwg.add(dwg.text("In collaboration with LIP6.fr",
30 insert=(woffs+width/2-scale*5, woffs+height/2+scale),
31 fill='white'))
32 dwg.add(dwg.text("Cell Libraries by Chips4Makers",
33 insert=(woffs+width/2-scale*5, woffs+height/2+scale*2),
34 fill='white'))
35
36 for i, pin in enumerate(pins['pads.west']):
37 ht = hoffs + height - (i * scale) + scale*0.5
38 dwg.add(dwg.line((woffs-scale*2, ht-scale*0.5),
39 (woffs-scale*4.5, ht-scale*0.5),
40 stroke=svgwrite.rgb(255, 255, 16, '%'),
41 stroke_width=scale/10.0))
42 dwg.add(dwg.text(pin.upper(), insert=(woffs-scale*12, ht),
43 fill='white'))
44 dwg.add(dwg.text("W%d" % (i+1), insert=(woffs-scale*1.5, ht),
45 fill='white'))
46
47 for i, pin in enumerate(pins['pads.east']):
48 ht = hoffs + height - (i * scale) + scale*0.5
49 wd = width + woffs + scale*2
50 dwg.add(dwg.line((wd+scale*2, ht-scale*0.5),
51 (wd+scale*4.5, ht-scale*0.5),
52 stroke=svgwrite.rgb(255, 255, 16, '%'),
53 stroke_width=scale/10.0))
54 dwg.add(dwg.text(pin.upper(), insert=(wd+scale*5, ht-scale*0.25),
55 fill='white'))
56 dwg.add(dwg.text("E%d" % (i+1), insert=(wd, ht-scale*0.25),
57 fill='white'))
58
59 for i, pin in enumerate(pins['pads.north']):
60 wd = woffs + i * scale + scale*1.5
61 dwg.add(dwg.line((wd, hoffs-scale*2),
62 (wd, hoffs-scale*4.5),
63 stroke=svgwrite.rgb(255, 255, 16, '%'),
64 stroke_width=scale/10.0))
65 pos=(wd, hoffs-scale*5.0)
66 txt = dwg.text(pin.upper(), insert=pos, fill='white')
67 txt.rotate(-90, pos)
68 dwg.add(txt)
69 pos=(wd+scale*0.25, hoffs-scale*0.25)
70 txt = dwg.text("N%d" % (i+1), insert=pos, fill='white')
71 txt.rotate(-90, pos)
72 dwg.add(txt)
73
74 for i, pin in enumerate(pins['pads.south']):
75 wd = woffs + i * scale + scale*1.5
76 ht = hoffs + height + scale*2
77 dwg.add(dwg.line((wd, ht+scale*2),
78 (wd, ht+scale*4.5),
79 stroke=svgwrite.rgb(255, 255, 16, '%'),
80 stroke_width=scale/10.0))
81 pos=(wd-scale*0.25, ht+scale*5.0)
82 txt = dwg.text(pin.upper(), insert=pos, fill='white')
83 txt.rotate(90, pos)
84 dwg.add(txt)
85 pos=(wd-scale*0.25, ht+scale*0.25)
86 txt = dwg.text("S%d" % (i+1), insert=pos, fill='white')
87 txt.rotate(90, pos)
88 dwg.add(txt)
89
90 dwg.save()
91
92
93 def display(of, pins, banksel=None, muxwidth=4):
94 of.write("""\
95 | Pin | Mux0 | Mux1 | Mux2 | Mux3 |
96 | --- | ----------- | ----------- | ----------- | ----------- |
97 """)
98 pinidx = sorted(pins.keys())
99 for pin in pinidx:
100 pdata = pins.get(pin)
101 if banksel:
102 skip = False
103 for mux in range(muxwidth):
104 if mux not in pdata:
105 continue
106 name, bank = pdata[mux]
107 if banksel != bank:
108 skip = True
109 if skip:
110 continue
111 res = '| %3d |' % pin
112 for mux in range(muxwidth):
113 if mux not in pdata:
114 res += " |"
115 continue
116 name, bank = pdata[mux]
117 res += " %s %-9s |" % (bank, name)
118 of.write("%s\n" % res)
119
120
121 def fnsplit(f):
122 a = ''
123 n = 0
124 if not f.startswith('FB_'):
125 f2 = f.split('_')
126 if len(f2) == 2:
127 if f2[1].isdigit():
128 return f2[0], int(f2[1])
129 return f2[0], f2[1]
130 #print f
131 while f and not f[0].isdigit():
132 a += f[0]
133 f = f[1:]
134 return a, int(f) if f else None
135
136
137 def fnsort(f1, f2):
138 a1, n1 = fnsplit(f1)
139 a2, n2 = fnsplit(f2)
140 x = cmp(a1, a2)
141 if x != 0:
142 return x
143 return cmp(n1, n2)
144
145
146 def find_fn(fname, names):
147 for n in names:
148 if fname.startswith(n):
149 return n
150
151 def map_name(pinmap, fn, fblower, pin, rename):
152 if not rename:
153 if pin[:-1].isdigit():
154 print "map name digit", pin, fn, fblower
155 if fn in ['PWM', 'EINT', 'VDD', 'VSS']:
156 return fn.lower() + pin.lower()
157 if fn == 'GPIO':
158 return 'gpio' + pin[1:].lower()
159 return pin.lower()
160 pin = pin.lower()
161 if fn == 'GPIO':
162 pk = '%s%s_%s' % (fblower, pin[0], pin[:-1])
163 elif pin[:-1].isdigit() and fn != 'EINT':
164 pk = '%s%s_out' % (fblower, pin[:-1])
165 else:
166 pk = '%s_%s' % (fblower, pin[:-1])
167 print "map name", pk, fblower, pinmap.has_key(pk)
168 if not pinmap.has_key(pk):
169 return pin.lower()
170 remapped = pinmap[pk]
171 uscore = remapped.find('_')
172 if uscore == -1:
173 return pin.lower()
174 fn, pin = remapped[:uscore], remapped[uscore+1:] + pin[-1]
175 return pin.lower()
176
177 def python_pindict(of, pinmap, pins, function_names, dname, remap):
178
179 res = OrderedDict()
180 of.write("\n%s = OrderedDict()\n" % dname)
181
182 for k, pingroup in pins.byspec.items():
183 (a, n) = k.split(":")
184 if n.isdigit():
185 a = "%s%s" % (a, n)
186 fblower = a.lower()
187 of.write("%s['%s'] = [ " % (dname, fblower))
188 res[fblower] = []
189 count = 0
190 for i, p in enumerate(pingroup):
191 name = map_name(pinmap, k[0], fblower, p, remap)
192 res[fblower].append(name)
193 of.write("'%s', " % name)
194 count += 1
195 if count == 4 and i != len(pingroup)-1:
196 of.write("\n ")
197 count = 0
198 of.write("]\n")
199 print " dict %s" % dname, a, n, pingroup
200 of.write("\n\n")
201 return res
202
203 def python_dict_fns(of, pinmap, pins, function_names):
204 of.write("# auto-generated by Libre-SOC pinmux program: do not edit\n")
205 of.write("# python src/pinmux_generator.py -v -s {spec} -o {output}\n")
206 of.write("# use OrderedDict to fix stable order for JTAG Boundary Scan\n")
207 of.write("from collections import OrderedDict\n")
208
209 fn_names = function_names.keys()
210 fns = {}
211
212 fnidx = list(fns.keys())
213 fnidx.sort(key=fnsplit)
214
215 print "python fnames", function_names
216 print "python speckeys", pins.byspec.keys()
217 print "python dict fns", dir(pins.gpio)
218 print pins.gpio.pinfn('', '')
219 print pins.pwm.pinfn('', '')
220 print pins.sdmmc.pinfn('', '')
221 print "by spec", pins.byspec
222 print pinmap
223
224 pd = python_pindict(of, {}, pins, function_names, 'pindict', False)
225 ld = python_pindict(of, pinmap, pins, function_names, 'litexdict', True)
226
227 print "pd", pd
228 print "ld", ld
229 # process results and create name map
230 litexmap = OrderedDict()
231 for k in pd.keys():
232 pl = pd[k]
233 ll = ld[k]
234 for pname, lname in zip(pl, ll):
235 pname = "%s_%s" % (k, pname[:-1]) # strip direction +/-/*
236 lname = lname[:-1] # strip direction +/-/*
237 if k in ['eint', 'pwm', 'gpio', 'vdd', 'vss']: # sigh
238 lname = "%s_%s" % (k, lname)
239 litexmap[pname] = lname
240 print "litexmap", litexmap
241 of.write("litexmap = {\n")
242 for k, v in litexmap.items():
243 of.write("\t'%s': '%s',\n" % (k, v))
244 of.write("}\n")
245 return litexmap
246
247
248 def display_fns(of, bankspec, pins, function_names):
249 fn_names = function_names.keys()
250 fns = {}
251 for (pin, pdata) in pins.items():
252 for mux in range(0, 4): # skip GPIO for now
253 if mux not in pdata:
254 continue
255 name, bank = pdata[mux]
256 assert name is not None, str(bank)
257 if name not in fns:
258 fns[name] = []
259 fns[name].append((pin - bankspec[bank], mux, bank))
260
261 fnidx = list(fns.keys())
262 fnidx.sort(key=fnsplit)
263 current_fn = None
264 for fname in fnidx:
265 fnbase = find_fn(fname, fn_names)
266 #fblower = fnbase.lower()
267 assert fnbase in function_names, "fn %s not in descriptions %s" % \
268 (fname, str(function_names.keys()))
269 #print "name", fname, fnbase
270 if fnbase != current_fn:
271 if current_fn is not None:
272 of.write('\n')
273 of.write("## %s\n\n%s\n\n" % (fnbase, function_names[fnbase]))
274 current_fn = fnbase
275 of.write("* %-9s :" % fname)
276 for (pin, mux, bank) in fns[fname]:
277 of.write(" %s%d/%d" % (bank, pin, mux))
278 of.write('\n')
279
280 return fns
281
282
283 def check_functions(of, title, bankspec, fns, pins, required, eint, pwm,
284 descriptions=None):
285 fns = deepcopy(fns)
286 pins = deepcopy(pins)
287 if descriptions is None:
288 descriptions = {}
289 fnidx = fns.keys()
290
291 #print dir(fns)
292 #print dir(pins)
293
294 of.write("# Pinmap for %s\n\n" % title)
295
296 print "fn_idx", fnidx
297 print "fns", fns
298 print "fnspec", pins.fnspec.keys()
299 print "required", required
300 for name in required:
301 of.write("## %s\n\n" % name)
302 if descriptions and name in descriptions:
303 of.write("%s\n\n" % descriptions[name])
304
305 name = name.split(':')
306 if len(name) == 2:
307 findbank = name[0][0]
308 findmux = int(name[0][1:])
309 name = name[1]
310 else:
311 name = name[0]
312 findbank = None
313 findmux = None
314 name = name.split('/')
315 if len(name) == 2:
316 count = int(name[1])
317 else:
318 count = 100000
319 name = name[0]
320 #print name
321 found = set()
322 pinfound = {}
323 located = set()
324 for fname in fnidx:
325 if not fname.startswith(name):
326 continue
327 for k in pins.fnspec.keys():
328 if fname.startswith(k):
329 fk = list(pins.fnspec[k].keys())
330 fn = pins.fnspec[k]
331 fn = fn[fk[0]]
332 #print fname, fn, dir(fn)
333 if count == 100000:
334 count = len(fn.pingroup)
335 for pin, mux, bank in fns[fname]:
336 if findbank is not None:
337 if findbank != bank:
338 continue
339 if findmux != mux:
340 continue
341 pin_ = pin + bankspec[bank]
342 if pin_ in pins:
343 pinfound[pin_] = (fname, pin_, bank, pin, mux)
344
345 pinidx = sorted(pinfound.keys())
346
347 fname = None
348 removedcount = 0
349 print ("pinidx", pinidx)
350 for pin_ in pinidx:
351 fname, pin_, bank, pin, mux = pinfound[pin_]
352 if fname in found:
353 continue
354 found.add(fname)
355 if len(found) > count:
356 continue
357 del pins[pin_]
358 removedcount += 1
359 of.write("* %s %d %s%d/%d\n" % (fname, pin_, bank, pin, mux))
360
361 print fns
362 if removedcount != count:
363 if fname is None:
364 print "no match between required and available pins"
365 else:
366 print ("not all found", name, removedcount, count, title, found,
367 fns[fname])
368 print ("pins found", pinfound)
369
370 # fnidx.sort(fnsort)
371 of.write('\n')
372
373 # gpios
374 gpios = []
375 for name in descriptions.keys():
376 if not name.startswith('GPIO'):
377 continue
378 if name == 'GPIO':
379 continue
380 gpios.append(name)
381 gpios.sort()
382
383 if gpios:
384 of.write("## GPIO\n\n")
385
386 for fname in gpios:
387 if fname in found:
388 continue
389 desc = ''
390 if descriptions and fname in descriptions:
391 desc = ': %s' % descriptions[fname]
392 bank = fname[4]
393 pin = int(fname[7:])
394 pin_ = pin + bankspec[bank]
395 if pin_ not in pins:
396 continue
397 del pins[pin_]
398 found.add(fname)
399 of.write("* %-8s %d %s%-2d %s\n" % (fname, pin_, bank, pin, desc))
400 of.write('\n')
401
402 if eint:
403 display_group(of, bankspec, "EINT", eint, fns, pins, descriptions)
404 if pwm:
405 display_group(of, bankspec, "PWM", pwm, fns, pins, descriptions)
406
407 of.write("## Unused Pinouts (spare as GPIO) for '%s'\n\n" % title)
408 if descriptions and 'GPIO' in descriptions:
409 of.write("%s\n\n" % descriptions['GPIO'])
410 display(of, pins)
411 of.write('\n')
412
413 return pins # unused
414
415
416 def display_group(of, bankspec, title, todisplay, fns, pins, descriptions):
417 of.write("## %s\n\n" % title)
418
419 found = set()
420 for fname in todisplay:
421 desc = ''
422 if descriptions and fname in descriptions:
423 desc = ': %s' % descriptions[fname]
424 fname = fname.split(':')
425 if len(fname) == 2:
426 findbank = fname[0][0]
427 findmux = int(fname[0][1:])
428 fname = fname[1]
429 else:
430 fname = fname[0]
431 findbank = None
432 findmux = None
433 for (pin, mux, bank) in fns[fname]:
434 if findbank is not None:
435 if findbank != bank:
436 continue
437 if findmux != mux:
438 continue
439 if fname in found:
440 continue
441 pin_ = pin + bankspec[bank]
442 if pin_ not in pins:
443 continue
444 del pins[pin_]
445 found.add(fname)
446 of.write("* %s %d %s%d/%d %s\n" %
447 (fname, pin_, bank, pin, mux, desc))
448 of.write('\n')
449
450
451 def display_fixed(of, fixed, offs):
452
453 fkeys = sorted(fixed.keys())
454 pin_ = offs
455 res = []
456 for pin, k in enumerate(fkeys):
457 of.write("## %s\n\n" % k)
458 prevname = ''
459 linecount = 0
460 for name in fixed[k]:
461 if linecount == 4:
462 linecount = 0
463 of.write('\n')
464 if prevname[:2] == name[:2] and linecount != 0:
465 of.write(" %s" % name)
466 linecount += 1
467 else:
468 if linecount != 0:
469 of.write('\n')
470 of.write("* %d: %d %s" % (pin_, pin, name))
471 linecount = 1
472 res.append((pin_, name))
473
474 prevname = name
475 pin_ += 1
476 if linecount != 0:
477 of.write('\n')
478 of.write('\n')
479
480 return res