cb012660c3bc1ac9f8cacd58a59413f8682a221f
[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 import os
7 import base64
8
9 cwd = os.path.split(os.path.abspath(__file__))[0]
10 lead_drawing = cwd + "/greatek_qfp_128L.png"
11 pack_drawing = cwd + "/greatek_qfp_128_fp.png"
12
13 def bond_int_to_ext(pin, bank):
14 """ note that internal numbering is 0-31 whereas the DISPLAY internal
15 numbering is 1-32. this uses the INTERNAL numbering.
16
17 side: N S E W
18
19 outer ring numbers: the python list order of the outer pads
20 middle numbers: the package number wires (plus side they are on)
21 inner numbers: the IO pad *python internal (0-31)* numbers plus side
22
23 0 1 2 3 N 34 35 36 37
24 N102 N101 N100 99 N 68 N67 N66 N65
25 W29 W30 W31 N0 N N31 E29 E30 E31
26
27 25 103 W28 E28 64 25
28 W W W E E E
29 0 128 W3 E3 39 0
30
31 W2 W1 W0 S0 S S31 E0 E1 E2
32 S1 S2 S3 4 S 35 S36 S37 S38
33 0 1 2 3 S 34 35 36 37
34
35 """
36 # returns side, order-on-the-side, pin number
37 if bank == 'N':
38 return 'N', pin+3, 99-pin
39 if bank == 'S':
40 return 'S', pin+3, 4+pin
41 if bank == 'W':
42 if pin >= 29: # 29, 30, 31
43 return 'N', pin-29, 100+(31-pin)
44 if pin <= 2:
45 return 'S', 2-pin, 3-pin
46 return 'W', 28-pin, 103+(28-pin)
47 if bank == 'E':
48 if pin >= 29:
49 return 'N', 35+(31-pin), 67-(31-pin)
50 if pin <= 2:
51 return 'S', pin+35, 36+pin
52 return 'E', 28-pin, 39+(28-pin)
53
54
55 def create_sv(fname, pins):
56 """unsophisticated drawer of an SVG
57 """
58
59 try:
60 import svgwrite
61 except ImportError:
62 print ("WARNING, no SVG image, not producing image %s" % fname)
63 return
64
65 # create internal to external map
66 bondmap = {'N': {}, 'S': {}, 'E': {}, 'W': {} }
67 padside = {'pads.north': 'N', 'pads.east': 'E', 'pads.south': 'S',
68 'pads.west': 'W'}
69 sidepad = {}
70 for pinpad, bank in padside.items():
71 sidepad[bank] = pinpad
72 for ipin in range(len(pins[pinpad])):
73 eside, enum, epinnum = bond_int_to_ext(ipin, bank)
74 bondmap[eside][enum] = (epinnum, ipin, bank)
75 with open("/tmp/bondmap.txt", "w") as f:
76 for k,v in bondmap.items():
77 f.write("%s\n" % k)
78 for enum, (epinnum, ipin, bank) in v.items():
79 f.write(" %d %d -> %s %d\n" % (enum, epinnum, bank, ipin))
80
81 scale = 15
82 outerscale = scale * 2.0
83
84 width = len(pins['pads.north']) * scale
85 height = len(pins['pads.east']) * scale
86 woffs = scale*40#-width/2
87 hoffs = scale*40#-height/2
88
89 dwg = svgwrite.Drawing(fname, profile='full',
90 size=(width+scale*80, height+scale*80))
91 dwg.add(dwg.rect((woffs-scale*2, hoffs-scale*2),
92 (woffs+width-scale*34, hoffs+height-scale*34),
93 stroke=svgwrite.rgb(16, 255, 16, '%'),
94 stroke_width=scale/10.0))
95
96 # record the inner line (iopad) position so that the outer one can
97 # match with it
98 innerpos = {'N': {}, 'S': {}, 'E': {}, 'W': {} }
99
100 # create the inner diagram
101 for i, pin in enumerate(pins['pads.west']):
102 ht = hoffs + height - (i * scale) + scale*0.5
103 endline = (woffs-scale*4.5, ht-scale*0.5)
104 innerpos['W'][i] = endline
105 dwg.add(dwg.line((woffs-scale*2, ht-scale*0.5),
106 endline,
107 stroke=svgwrite.rgb(16, 255, 16, '%'),
108 stroke_width=scale/10.0))
109 dwg.add(dwg.text(pin.upper(), insert=(woffs-scale*14, ht),
110 fill='black'))
111 dwg.add(dwg.text("W%d" % (i+1), insert=(woffs-scale*1.5, ht),
112 fill='white'))
113
114 for i, pin in enumerate(pins['pads.east']):
115 ht = hoffs + height - (i * scale) + scale*0.5
116 wd = width + woffs + scale*2
117 endline = (wd+scale*4.5, ht-scale*0.5)
118 innerpos['E'][i] = endline
119 dwg.add(dwg.line((wd+scale*2, ht-scale*0.5),
120 endline,
121 stroke=svgwrite.rgb(16, 255, 16, '%'),
122 stroke_width=scale/10.0))
123 dwg.add(dwg.text(pin.upper(), insert=(wd+scale*5, ht-scale*0.25),
124 fill='black'))
125 dwg.add(dwg.text("E%d" % (i+1), insert=(wd, ht-scale*0.25),
126 fill='white'))
127
128 for i, pin in enumerate(pins['pads.north']):
129 wd = woffs + i * scale + scale*1.5
130 endline = (wd, hoffs-scale*4.5)
131 innerpos['N'][i] = endline
132 dwg.add(dwg.line((wd, hoffs-scale*2),
133 endline,
134 stroke=svgwrite.rgb(16, 255, 16, '%'),
135 stroke_width=scale/10.0))
136 pos=(wd, hoffs-scale*5.0)
137 txt = dwg.text(pin.upper(), insert=pos, fill='black')
138 txt.rotate(-90, pos)
139 dwg.add(txt)
140 pos=(wd+scale*0.25, hoffs-scale*0.25)
141 txt = dwg.text("N%d" % (i+1), insert=pos, fill='white')
142 txt.rotate(-90, pos)
143 dwg.add(txt)
144
145 for i, pin in enumerate(pins['pads.south']):
146 wd = woffs + i * scale + scale*1.5
147 ht = hoffs + height + scale*2
148 endline = (wd, ht+scale*4.5)
149 innerpos['S'][i] = endline
150 dwg.add(dwg.line((wd, ht+scale*2),
151 endline,
152 stroke=svgwrite.rgb(16, 255, 16, '%'),
153 stroke_width=scale/10.0))
154 pos=(wd-scale*0.25, ht+scale*5.0)
155 txt = dwg.text(pin.upper(), insert=pos, fill='black')
156 txt.rotate(90, pos)
157 dwg.add(txt)
158 pos=(wd-scale*0.25, ht+scale*0.25)
159 txt = dwg.text("S%d" % (i+1), insert=pos, fill='white')
160 txt.rotate(90, pos)
161 dwg.add(txt)
162
163 nepads = bondmap['N'].keys()
164 nepads.sort()
165 wepads = bondmap['W'].keys()
166 wepads.sort()
167 eepads = bondmap['E'].keys()
168 eepads.sort()
169 sepads = bondmap['S'].keys()
170 sepads.sort()
171
172 owoffs = woffs + (width/2) - len(nepads)/2 * outerscale
173 ohoffs = hoffs + (height/2) - len(wepads)/2 * outerscale
174
175 # north outer pads
176 for i in nepads:
177 (epinnum, ipin, bank) = pad = bondmap['N'][i]
178 wd = owoffs + i * outerscale + outerscale*1.5
179 endline = (wd, ohoffs-outerscale*2)
180 startline = innerpos[bank][ipin]
181 dwg.add(dwg.line(startline,
182 endline,
183 stroke=svgwrite.rgb(255, 16, 16, '%'),
184 stroke_width=scale/10.0))
185 pin = pins[sidepad[bank]][ipin]
186 pos=(wd, ohoffs-outerscale*4.0)
187 txt = dwg.text("%s (%s%d)" % (pin.upper(), bank, ipin+1),
188 insert=pos, fill='black')
189 txt.rotate(-90, pos)
190 dwg.add(txt)
191 pos=(wd, ohoffs-outerscale*2.5)
192 txt = dwg.text("%d N" % epinnum, insert=pos, fill='blue')
193 txt.rotate(-90, pos)
194 dwg.add(txt)
195
196 # west outer pads
197 for i in wepads:
198 (epinnum, ipin, bank) = pad = bondmap['W'][i]
199 ht = ohoffs + (i * outerscale) + outerscale*1.5
200 endline = (owoffs+outerscale*0.5, ht)
201 startline = innerpos[bank][ipin]
202 dwg.add(dwg.line(startline,
203 endline,
204 stroke=svgwrite.rgb(255, 16, 16, '%'),
205 stroke_width=scale/10.0))
206 pin = pins[sidepad[bank]][ipin]
207 pos = (owoffs-outerscale*6.0, ht)
208 dwg.add(dwg.text("%s (%s%d)" % (pin.upper(), bank, ipin+1),
209 pos,
210 fill='black'))
211 pos = (owoffs-outerscale*1.0, ht)
212 dwg.add(dwg.text("%d W" % epinnum, insert=pos,
213 fill='blue'))
214
215 # south outer pads
216 for i in sepads:
217 (epinnum, ipin, bank) = pad = bondmap['S'][i]
218 wd = owoffs + i * outerscale + outerscale*1.5
219 ht = ohoffs + len(wepads)*outerscale + outerscale*4
220 endline = (wd, ht)
221 startline = innerpos[bank][ipin]
222 dwg.add(dwg.line(startline,
223 endline,
224 stroke=svgwrite.rgb(255, 16, 16, '%'),
225 stroke_width=scale/10.0))
226 pin = pins[sidepad[bank]][ipin]
227 pos=(wd-outerscale*0.25, ht+outerscale*1.5)
228 txt = dwg.text("%s (%s%d)" % (pin.upper(), bank, ipin+1),
229 insert=pos, fill='black')
230 txt.rotate(90, pos)
231 dwg.add(txt)
232 pos=(wd-outerscale*0.25, ht+outerscale*0.5)
233 txt = dwg.text("%d S" % epinnum, insert=pos, fill='blue')
234 txt.rotate(90, pos)
235 dwg.add(txt)
236
237 # east outer pads
238 for i in eepads:
239 (epinnum, ipin, bank) = pad = bondmap['E'][i]
240 ht = ohoffs + (i * outerscale) + outerscale*1.5
241 wd = owoffs+len(nepads)*outerscale
242 endline = (wd+outerscale*0.5, ht)
243 startline = innerpos[bank][ipin]
244 dwg.add(dwg.line(startline,
245 endline,
246 stroke=svgwrite.rgb(255, 16, 16, '%'),
247 stroke_width=scale/10.0))
248 pin = pins[sidepad[bank]][ipin]
249 pos = (wd+outerscale*2.5, ht)
250 dwg.add(dwg.text("%s (%s%d)" % (pin.upper(), bank, ipin+1),
251 pos,
252 fill='black'))
253 pos = (wd+outerscale*1.0, ht)
254 dwg.add(dwg.text("%d E" % epinnum, insert=pos,
255 fill='blue'))
256
257 # add QFP pack image in top-right
258 image_data = open(pack_drawing, "rb").read()
259 encoded = base64.b64encode(image_data).decode()
260 data = 'data:image/png;base64,{}'.format(encoded)
261 pos=(0, 0)
262 leads = svgwrite.image.Image(data, pos,
263 size=(327,300))
264 dwg.add(leads)
265
266 # add QFP lead image in centre
267 image_data = open(lead_drawing, "rb").read()
268 encoded = base64.b64encode(image_data).decode()
269 data = 'data:image/png;base64,{}'.format(encoded)
270 pos=(woffs+scale*3.5, hoffs+scale*3.5)
271 leads = svgwrite.image.Image(data, pos,
272 size=(400,400))
273 leads.rotate(-90, (pos[0]+200, pos[1]+200))
274 dwg.add(leads)
275
276 dwg.add(dwg.text("GREATEK ELECTRONICS INC.",
277 insert=(woffs+width/2-scale*5, woffs+height/2-scale*6),
278 fill='black'))
279 dwg.add(dwg.text("INNER LEAD DRAWING",
280 insert=(woffs+width/2-scale*5, woffs+height/2-scale*5),
281 fill='black'))
282 dwg.add(dwg.text("QFP 128L OPEN STAMPING",
283 insert=(woffs+width/2-scale*5, woffs+height/2-scale*4),
284 fill='black'))
285 dwg.add(dwg.text("BODY 14x20x2.75mm",
286 insert=(woffs+width/2-scale*5, woffs+height/2-scale*3),
287 fill='black'))
288 dwg.add(dwg.text("L/F PAD SIZE 236x236mil^2",
289 insert=(woffs+width/2-scale*5, woffs+height/2-scale*2),
290 fill='black'))
291
292 # add attribution
293 dwg.add(dwg.text("Libre-SOC ls180 QFP-128",
294 insert=(woffs+width/2-scale*5, woffs+height/2),
295 fill='black'))
296 dwg.add(dwg.text("In collaboration with LIP6.fr",
297 insert=(woffs+width/2-scale*5, woffs+height/2+scale),
298 fill='black'))
299 dwg.add(dwg.text("Cell Libraries by Chips4Makers",
300 insert=(woffs+width/2-scale*5, woffs+height/2+scale*2),
301 fill='black'))
302 dwg.add(dwg.text("IMEC TSMC 180nm",
303 insert=(woffs+width/2-scale*5, woffs+height/2+scale*3),
304 fill='black'))
305
306 dwg.save()
307
308
309 def display(of, pins, banksel=None, muxwidth=4):
310 of.write("""\
311 | Pin | Mux0 | Mux1 | Mux2 | Mux3 |
312 | --- | ----------- | ----------- | ----------- | ----------- |
313 """)
314 pinidx = sorted(pins.keys())
315 for pin in pinidx:
316 pdata = pins.get(pin)
317 if banksel:
318 skip = False
319 for mux in range(muxwidth):
320 if mux not in pdata:
321 continue
322 name, bank = pdata[mux]
323 if banksel != bank:
324 skip = True
325 if skip:
326 continue
327 res = '| %3d |' % pin
328 for mux in range(muxwidth):
329 if mux not in pdata:
330 res += " |"
331 continue
332 name, bank = pdata[mux]
333 res += " %s %-9s |" % (bank, name)
334 of.write("%s\n" % res)
335
336
337 def fnsplit(f):
338 a = ''
339 n = 0
340 if not f.startswith('FB_'):
341 f2 = f.split('_')
342 if len(f2) == 2:
343 if f2[1].isdigit():
344 return f2[0], int(f2[1])
345 return f2[0], f2[1]
346 #print f
347 while f and not f[0].isdigit():
348 a += f[0]
349 f = f[1:]
350 return a, int(f) if f else None
351
352
353 def fnsort(f1, f2):
354 a1, n1 = fnsplit(f1)
355 a2, n2 = fnsplit(f2)
356 x = cmp(a1, a2)
357 if x != 0:
358 return x
359 return cmp(n1, n2)
360
361
362 def find_fn(fname, names):
363 for n in names:
364 if fname.startswith(n):
365 return n
366
367 def map_name(pinmap, fn, fblower, pin, rename):
368 if not rename:
369 if pin[:-1].isdigit():
370 print "map name digit", pin, fn, fblower
371 if fn in ['PWM', 'EINT', 'VDD', 'VSS']:
372 return fn.lower() + pin.lower()
373 if fn == 'GPIO':
374 return 'gpio' + pin[1:].lower()
375 return pin.lower()
376 pin = pin.lower()
377 if fn == 'GPIO':
378 pk = '%s%s_%s' % (fblower, pin[0], pin[:-1])
379 elif pin[:-1].isdigit() and fn != 'EINT':
380 pk = '%s%s_out' % (fblower, pin[:-1])
381 else:
382 pk = '%s_%s' % (fblower, pin[:-1])
383 print "map name", pk, fblower, pinmap.has_key(pk)
384 if not pinmap.has_key(pk):
385 return pin.lower()
386 remapped = pinmap[pk]
387 uscore = remapped.find('_')
388 if uscore == -1:
389 return pin.lower()
390 fn, pin = remapped[:uscore], remapped[uscore+1:] + pin[-1]
391 return pin.lower()
392
393 def python_pindict(of, pinmap, pins, function_names, dname, remap):
394
395 res = OrderedDict()
396 of.write("\n%s = OrderedDict()\n" % dname)
397
398 for k, pingroup in pins.byspec.items():
399 (a, n) = k.split(":")
400 if n.isdigit():
401 a = "%s%s" % (a, n)
402 fblower = a.lower()
403 of.write("%s['%s'] = [ " % (dname, fblower))
404 res[fblower] = []
405 count = 0
406 for i, p in enumerate(pingroup):
407 name = map_name(pinmap, k[0], fblower, p, remap)
408 res[fblower].append(name)
409 of.write("'%s', " % name)
410 count += 1
411 if count == 4 and i != len(pingroup)-1:
412 of.write("\n ")
413 count = 0
414 of.write("]\n")
415 print " dict %s" % dname, a, n, pingroup
416 of.write("\n\n")
417 return res
418
419 def python_dict_fns(of, pinmap, pins, function_names):
420 of.write("# auto-generated by Libre-SOC pinmux program: do not edit\n")
421 of.write("# python src/pinmux_generator.py -v -s {spec} -o {output}\n")
422 of.write("# use OrderedDict to fix stable order for JTAG Boundary Scan\n")
423 of.write("from collections import OrderedDict\n")
424
425 fn_names = function_names.keys()
426 fns = {}
427
428 fnidx = list(fns.keys())
429 fnidx.sort(key=fnsplit)
430
431 print "python fnames", function_names
432 print "python speckeys", pins.byspec.keys()
433 print "python dict fns", dir(pins.gpio)
434 print pins.gpio.pinfn('', '')
435 print pins.pwm.pinfn('', '')
436 print pins.sdmmc.pinfn('', '')
437 print "by spec", pins.byspec
438 print pinmap
439
440 pd = python_pindict(of, {}, pins, function_names, 'pindict', False)
441 ld = python_pindict(of, pinmap, pins, function_names, 'litexdict', True)
442
443 print "pd", pd
444 print "ld", ld
445 # process results and create name map
446 litexmap = OrderedDict()
447 for k in pd.keys():
448 pl = pd[k]
449 ll = ld[k]
450 for pname, lname in zip(pl, ll):
451 pname = "%s_%s" % (k, pname[:-1]) # strip direction +/-/*
452 lname = lname[:-1] # strip direction +/-/*
453 if k in ['eint', 'pwm', 'gpio', 'vdd', 'vss']: # sigh
454 lname = "%s_%s" % (k, lname)
455 litexmap[pname] = lname
456 print "litexmap", litexmap
457 of.write("litexmap = {\n")
458 for k, v in litexmap.items():
459 of.write("\t'%s': '%s',\n" % (k, v))
460 of.write("}\n")
461 return litexmap
462
463
464 def display_fns(of, bankspec, pins, function_names):
465 fn_names = function_names.keys()
466 fns = {}
467 for (pin, pdata) in pins.items():
468 for mux in range(0, 4): # skip GPIO for now
469 if mux not in pdata:
470 continue
471 name, bank = pdata[mux]
472 assert name is not None, str(bank)
473 if name not in fns:
474 fns[name] = []
475 fns[name].append((pin - bankspec[bank], mux, bank))
476
477 fnidx = list(fns.keys())
478 fnidx.sort(key=fnsplit)
479 current_fn = None
480 for fname in fnidx:
481 fnbase = find_fn(fname, fn_names)
482 #fblower = fnbase.lower()
483 assert fnbase in function_names, "fn %s not in descriptions %s" % \
484 (fname, str(function_names.keys()))
485 #print "name", fname, fnbase
486 if fnbase != current_fn:
487 if current_fn is not None:
488 of.write('\n')
489 of.write("## %s\n\n%s\n\n" % (fnbase, function_names[fnbase]))
490 current_fn = fnbase
491 of.write("* %-9s :" % fname)
492 for (pin, mux, bank) in fns[fname]:
493 of.write(" %s%d/%d" % (bank, pin, mux))
494 of.write('\n')
495
496 return fns
497
498
499 def check_functions(of, title, bankspec, fns, pins, required, eint, pwm,
500 descriptions=None):
501 fns = deepcopy(fns)
502 pins = deepcopy(pins)
503 if descriptions is None:
504 descriptions = {}
505 fnidx = fns.keys()
506
507 #print dir(fns)
508 #print dir(pins)
509
510 of.write("# Pinmap for %s\n\n" % title)
511
512 print "fn_idx", fnidx
513 print "fns", fns
514 print "fnspec", pins.fnspec.keys()
515 print "required", required
516 for name in required:
517 of.write("## %s\n\n" % name)
518 if descriptions and name in descriptions:
519 of.write("%s\n\n" % descriptions[name])
520
521 name = name.split(':')
522 if len(name) == 2:
523 findbank = name[0][0]
524 findmux = int(name[0][1:])
525 name = name[1]
526 else:
527 name = name[0]
528 findbank = None
529 findmux = None
530 name = name.split('/')
531 if len(name) == 2:
532 count = int(name[1])
533 else:
534 count = 100000
535 name = name[0]
536 #print name
537 found = set()
538 pinfound = {}
539 located = set()
540 for fname in fnidx:
541 if not fname.startswith(name):
542 continue
543 for k in pins.fnspec.keys():
544 if fname.startswith(k):
545 fk = list(pins.fnspec[k].keys())
546 fn = pins.fnspec[k]
547 fn = fn[fk[0]]
548 #print fname, fn, dir(fn)
549 if count == 100000:
550 count = len(fn.pingroup)
551 for pin, mux, bank in fns[fname]:
552 if findbank is not None:
553 if findbank != bank:
554 continue
555 if findmux != mux:
556 continue
557 pin_ = pin + bankspec[bank]
558 if pin_ in pins:
559 pinfound[pin_] = (fname, pin_, bank, pin, mux)
560
561 pinidx = sorted(pinfound.keys())
562
563 fname = None
564 removedcount = 0
565 print ("pinidx", pinidx)
566 for pin_ in pinidx:
567 fname, pin_, bank, pin, mux = pinfound[pin_]
568 if fname in found:
569 continue
570 found.add(fname)
571 if len(found) > count:
572 continue
573 del pins[pin_]
574 removedcount += 1
575 of.write("* %s %d %s%d/%d\n" % (fname, pin_, bank, pin, mux))
576
577 print fns
578 if removedcount != count:
579 if fname is None:
580 print "no match between required and available pins"
581 else:
582 print ("not all found", name, removedcount, count, title, found,
583 fns[fname])
584 print ("pins found", pinfound)
585
586 # fnidx.sort(fnsort)
587 of.write('\n')
588
589 # gpios
590 gpios = []
591 for name in descriptions.keys():
592 if not name.startswith('GPIO'):
593 continue
594 if name == 'GPIO':
595 continue
596 gpios.append(name)
597 gpios.sort()
598
599 if gpios:
600 of.write("## GPIO\n\n")
601
602 for fname in gpios:
603 if fname in found:
604 continue
605 desc = ''
606 if descriptions and fname in descriptions:
607 desc = ': %s' % descriptions[fname]
608 bank = fname[4]
609 pin = int(fname[7:])
610 pin_ = pin + bankspec[bank]
611 if pin_ not in pins:
612 continue
613 del pins[pin_]
614 found.add(fname)
615 of.write("* %-8s %d %s%-2d %s\n" % (fname, pin_, bank, pin, desc))
616 of.write('\n')
617
618 if eint:
619 display_group(of, bankspec, "EINT", eint, fns, pins, descriptions)
620 if pwm:
621 display_group(of, bankspec, "PWM", pwm, fns, pins, descriptions)
622
623 of.write("## Unused Pinouts (spare as GPIO) for '%s'\n\n" % title)
624 if descriptions and 'GPIO' in descriptions:
625 of.write("%s\n\n" % descriptions['GPIO'])
626 display(of, pins)
627 of.write('\n')
628
629 return pins # unused
630
631
632 def display_group(of, bankspec, title, todisplay, fns, pins, descriptions):
633 of.write("## %s\n\n" % title)
634
635 found = set()
636 for fname in todisplay:
637 desc = ''
638 if descriptions and fname in descriptions:
639 desc = ': %s' % descriptions[fname]
640 fname = fname.split(':')
641 if len(fname) == 2:
642 findbank = fname[0][0]
643 findmux = int(fname[0][1:])
644 fname = fname[1]
645 else:
646 fname = fname[0]
647 findbank = None
648 findmux = None
649 for (pin, mux, bank) in fns[fname]:
650 if findbank is not None:
651 if findbank != bank:
652 continue
653 if findmux != mux:
654 continue
655 if fname in found:
656 continue
657 pin_ = pin + bankspec[bank]
658 if pin_ not in pins:
659 continue
660 del pins[pin_]
661 found.add(fname)
662 of.write("* %s %d %s%d/%d %s\n" %
663 (fname, pin_, bank, pin, mux, desc))
664 of.write('\n')
665
666
667 def display_fixed(of, fixed, offs):
668
669 fkeys = sorted(fixed.keys())
670 pin_ = offs
671 res = []
672 for pin, k in enumerate(fkeys):
673 of.write("## %s\n\n" % k)
674 prevname = ''
675 linecount = 0
676 for name in fixed[k]:
677 if linecount == 4:
678 linecount = 0
679 of.write('\n')
680 if prevname[:2] == name[:2] and linecount != 0:
681 of.write(" %s" % name)
682 linecount += 1
683 else:
684 if linecount != 0:
685 of.write('\n')
686 of.write("* %d: %d %s" % (pin_, pin, name))
687 linecount = 1
688 res.append((pin_, name))
689
690 prevname = name
691 pin_ += 1
692 if linecount != 0:
693 of.write('\n')
694 of.write('\n')
695
696 return res