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