fix(iomux): Fix port signal length (given mux size non-power of 2)
[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 c4m_drawing = cwd + "/c4mlogo.png"
13 ls180_drawing = cwd + "/ls180-img.png"
14
15 def bond_int_to_ext(pin, bank):
16 """ note that internal numbering is 0-31 whereas the DISPLAY internal
17 numbering is 1-32. this uses the INTERNAL numbering.
18
19 side: N S E W
20
21 outer ring numbers: the python list order of the outer pads
22 middle numbers: the package number wires (plus side they are on)
23 inner numbers: the IO pad *python internal (0-31)* numbers plus side
24
25 0 1 2 3 N 34 35 36 37
26 N102 N101 N100 99 N 68 N67 N66 N65
27 W29 W30 W31 N0 N N31 E29 E30 E31
28
29 25 103 W28 E28 64 25
30 W W W E E E
31 0 128 W3 E3 39 0
32
33 W2 W1 W0 S0 S S31 E0 E1 E2
34 S1 S2 S3 4 S 35 S36 S37 S38
35 0 1 2 3 S 34 35 36 37
36
37 """
38 # returns side, order-on-the-side, pin number
39 if bank == 'N':
40 return 'N', pin+3, 99-pin
41 if bank == 'S':
42 return 'S', pin+3, 4+pin
43 if bank == 'W':
44 if pin >= 29: # 29, 30, 31
45 return 'N', pin-29, 100+(31-pin)
46 if pin <= 2: # 0, 1, 2
47 return 'S', 2-pin, 3-pin
48 return 'W', 28-pin, 103+(28-pin)
49 if bank == 'E':
50 if pin >= 29:
51 return 'N', 35+(31-pin), 67-(31-pin)
52 if pin <= 2:
53 return 'S', pin+35, 36+pin
54 return 'E', 28-pin, 39+(pin-3)
55
56
57 def create_sv(fname, pins):
58 """unsophisticated drawer of an SVG
59 """
60
61 try:
62 import svgwrite
63 except ImportError:
64 print ("WARNING, no SVG image, not producing image %s" % fname)
65 return
66
67 # create internal to external map
68 bondmap = {'N': {}, 'S': {}, 'E': {}, 'W': {} }
69 padside = {'pads.north': 'N', 'pads.east': 'E', 'pads.south': 'S',
70 'pads.west': 'W'}
71 sidepad = {}
72 for pinpad, bank in padside.items():
73 sidepad[bank] = pinpad
74 for ipin in range(len(pins[pinpad])):
75 eside, enum, epinnum = bond_int_to_ext(ipin, bank)
76 bondmap[eside][enum] = (epinnum, ipin, bank)
77 with open("/tmp/bondmap.txt", "w") as f:
78 for k,v in bondmap.items():
79 f.write("%s\n" % k)
80 for enum, (epinnum, ipin, bank) in v.items():
81 f.write(" %d %d -> %s %d\n" % (enum, epinnum, bank, ipin))
82
83 scale = 15
84 outerscale = scale * 2.0
85
86 width = len(pins['pads.north']) * scale
87 height = len(pins['pads.east']) * scale
88 woffs = scale*40#-width/2
89 hoffs = scale*40#-height/2
90
91 nepads = list(bondmap['N'].keys())
92 nepads.sort()
93 wepads = list(bondmap['W'].keys())
94 wepads.sort()
95 eepads = list(bondmap['E'].keys())
96 eepads.sort()
97 sepads = list(bondmap['S'].keys())
98 sepads.sort()
99
100 owoffs = woffs + (width/2) - len(nepads)/2 * outerscale
101 ohoffs = hoffs + (height/2) - len(wepads)/2 * outerscale
102
103 dwg = svgwrite.Drawing(fname, profile='full',
104 size=(width+scale*85, height+scale*80))
105
106 # outer QFP rect
107 dwg.add(dwg.rect((owoffs-scale*2.5, ohoffs-scale*4.5),
108 (len(nepads)*outerscale+scale*9,
109 len(wepads)*outerscale+scale*13),
110 fill='white',
111 stroke=svgwrite.rgb(0, 128, 0, '%'),
112 stroke_width=scale/5.0))
113
114 # inner lead rect
115 dwg.add(dwg.rect((woffs-scale*2, hoffs-scale*2),
116 (width+scale*6, height+scale*6),
117 stroke=svgwrite.rgb(16, 255, 16, '%'),
118 stroke_width=scale/10.0))
119
120 # record the inner line (iopad) position so that the outer one can
121 # match with it
122 innerpos = {'N': {}, 'S': {}, 'E': {}, 'W': {} }
123
124 # create the inner diagram
125 for i, pin in enumerate(pins['pads.west']):
126 ht = hoffs + height - (i * scale) + scale*0.5
127 endline = (woffs-scale*4.5, ht-scale*0.5)
128 innerpos['W'][i] = endline
129 dwg.add(dwg.line((woffs-scale*2, ht-scale*0.5),
130 endline,
131 stroke=svgwrite.rgb(16, 255, 16, '%'),
132 stroke_width=scale/10.0))
133 dwg.add(dwg.text(pin.upper(), insert=(woffs-scale*12, ht),
134 fill='black'))
135 dwg.add(dwg.text("W%d" % (i+1), insert=(woffs-scale*1.5, ht),
136 fill='white'))
137
138 for i, pin in enumerate(pins['pads.east']):
139 ht = hoffs + height - (i * scale) + scale*0.5
140 wd = width + woffs + scale*2
141 endline = (wd+scale*4.5, ht-scale*0.5)
142 innerpos['E'][i] = endline
143 dwg.add(dwg.line((wd+scale*2, ht-scale*0.5),
144 endline,
145 stroke=svgwrite.rgb(16, 255, 16, '%'),
146 stroke_width=scale/10.0))
147 dwg.add(dwg.text(pin.upper(), insert=(wd+scale*5, ht-scale*0.25),
148 fill='black'))
149 dwg.add(dwg.text("E%d" % (i+1), insert=(wd, ht-scale*0.25),
150 fill='white'))
151
152 for i, pin in enumerate(pins['pads.north']):
153 wd = woffs + i * scale + scale*1.5
154 endline = (wd, hoffs-scale*4.5)
155 innerpos['N'][i] = endline
156 dwg.add(dwg.line((wd, hoffs-scale*2),
157 endline,
158 stroke=svgwrite.rgb(16, 255, 16, '%'),
159 stroke_width=scale/10.0))
160 pos=(wd, hoffs-scale*5.0)
161 txt = dwg.text(pin.upper(), insert=pos, fill='black')
162 txt.rotate(-90, pos)
163 dwg.add(txt)
164 pos=(wd+scale*0.25, hoffs-scale*0.25)
165 txt = dwg.text("N%d" % (i+1), insert=pos, fill='white')
166 txt.rotate(-90, pos)
167 dwg.add(txt)
168
169 for i, pin in enumerate(pins['pads.south']):
170 wd = woffs + i * scale + scale*1.5
171 ht = hoffs + height + scale*2
172 endline = (wd, ht+scale*4.5)
173 innerpos['S'][i] = endline
174 dwg.add(dwg.line((wd, ht+scale*2),
175 endline,
176 stroke=svgwrite.rgb(16, 255, 16, '%'),
177 stroke_width=scale/10.0))
178 pos=(wd-scale*0.25, ht+scale*5.0)
179 txt = dwg.text(pin.upper(), insert=pos, fill='black')
180 txt.rotate(90, pos)
181 dwg.add(txt)
182 pos=(wd-scale*0.25, ht+scale*0.25)
183 txt = dwg.text("S%d" % (i+1), insert=pos, fill='white')
184 txt.rotate(90, pos)
185 dwg.add(txt)
186
187 # north outer pads
188 for i in nepads:
189 (epinnum, ipin, bank) = pad = bondmap['N'][i]
190 wd = owoffs + i * outerscale + outerscale*1.5
191 endline = (wd, ohoffs-outerscale*2)
192 startline = innerpos[bank][ipin]
193 dwg.add(dwg.line(startline,
194 endline,
195 stroke=svgwrite.rgb(255, 16, 16, '%'),
196 stroke_width=scale/10.0))
197 pin = pins[sidepad[bank]][ipin]
198 pos=(wd, ohoffs-outerscale*4.0)
199 txt = dwg.text("%s (%s%d)" % (pin.upper(), bank, ipin+1),
200 insert=pos, fill='black')
201 txt.rotate(-90, pos)
202 dwg.add(txt)
203 pos=(wd, ohoffs-outerscale*2.5)
204 txt = dwg.text("%d N" % epinnum, insert=pos, fill='blue')
205 txt.rotate(-90, pos)
206 dwg.add(txt)
207
208 # west outer pads
209 for i in wepads:
210 (epinnum, ipin, bank) = pad = bondmap['W'][i]
211 ht = ohoffs + (i * outerscale) + outerscale*1.5
212 endline = (owoffs+outerscale*0.5, ht)
213 startline = innerpos[bank][ipin]
214 dwg.add(dwg.line(startline,
215 endline,
216 stroke=svgwrite.rgb(255, 16, 16, '%'),
217 stroke_width=scale/10.0))
218 pin = pins[sidepad[bank]][ipin]
219 pos = (owoffs-outerscale*6.0, ht)
220 dwg.add(dwg.text("%s (%s%d)" % (pin.upper(), bank, ipin+1),
221 pos,
222 fill='black'))
223 pos = (owoffs-outerscale*1.0, ht)
224 dwg.add(dwg.text("%d W" % epinnum, insert=pos,
225 fill='blue'))
226
227 # south outer pads
228 for i in sepads:
229 (epinnum, ipin, bank) = pad = bondmap['S'][i]
230 wd = owoffs + i * outerscale + outerscale*1.5
231 ht = ohoffs + len(wepads)*outerscale + outerscale*4
232 endline = (wd, ht)
233 startline = innerpos[bank][ipin]
234 dwg.add(dwg.line(startline,
235 endline,
236 stroke=svgwrite.rgb(255, 16, 16, '%'),
237 stroke_width=scale/10.0))
238 pin = pins[sidepad[bank]][ipin]
239 pos=(wd-outerscale*0.25, ht+outerscale*1.5)
240 txt = dwg.text("%s (%s%d)" % (pin.upper(), bank, ipin+1),
241 insert=pos, fill='black')
242 txt.rotate(90, pos)
243 dwg.add(txt)
244 pos=(wd-outerscale*0.25, ht+outerscale*0.5)
245 txt = dwg.text("%d S" % epinnum, insert=pos, fill='blue')
246 txt.rotate(90, pos)
247 dwg.add(txt)
248
249 # east outer pads
250 for i in eepads:
251 (epinnum, ipin, bank) = pad = bondmap['E'][i]
252 ht = ohoffs + (i * outerscale) + outerscale*1.5
253 wd = owoffs+len(nepads)*outerscale + outerscale*1
254 endline = (wd+outerscale*0.5, ht)
255 startline = innerpos[bank][ipin]
256 dwg.add(dwg.line(startline,
257 endline,
258 stroke=svgwrite.rgb(255, 16, 16, '%'),
259 stroke_width=scale/10.0))
260 pin = pins[sidepad[bank]][ipin]
261 pos = (wd+outerscale*2.5, ht)
262 dwg.add(dwg.text("%s (%s%d)" % (pin.upper(), bank, ipin+1),
263 pos,
264 fill='black'))
265 pos = (wd+outerscale*1.0, ht)
266 dwg.add(dwg.text("%d E" % epinnum, insert=pos,
267 fill='blue'))
268
269 # add ls180 image
270 image_data = open(ls180_drawing, "rb").read()
271 encoded = base64.b64encode(image_data).decode()
272 data = 'data:image/png;base64,{}'.format(encoded)
273 pos=(width/2+woffs-225, height/2+hoffs-225)
274 leads = svgwrite.image.Image(data, pos,
275 size=(480,480))
276 dwg.add(leads)
277
278 # add QFP pack image in top-right
279 image_data = open(pack_drawing, "rb").read()
280 encoded = base64.b64encode(image_data).decode()
281 data = 'data:image/png;base64,{}'.format(encoded)
282 pos=(0, 0)
283 leads = svgwrite.image.Image(data, pos,
284 size=(327,300))
285 dwg.add(leads)
286 dwg.add(dwg.text("GREATEK QFP128L",
287 insert=(50,150),
288 font_size=20,
289 fill='black'))
290 dwg.add(dwg.text("D/W J1-03128-001",
291 insert=(50,180),
292 font_size=20,
293 fill='black'))
294
295
296 # add QFP lead image in centre
297 sz=320
298 image_data = open(lead_drawing, "rb").read()
299 encoded = base64.b64encode(image_data).decode()
300 data = 'data:image/png;base64,{}'.format(encoded)
301 pos=(woffs+width+scale*23.5, 0)
302 leads = svgwrite.image.Image(data, pos,
303 size=(sz,sz))
304 leads.rotate(-90, (pos[0]+sz/2, pos[1]+sz/2))
305 dwg.add(leads)
306
307 dwg.add(dwg.text("GREATEK ELECTRONICS INC.",
308 insert=(woffs+width+scale*29, scale*8),
309 fill='black'))
310 dwg.add(dwg.text("INNER LEAD DRAWING",
311 insert=(woffs+width+scale*29, scale*9),
312 fill='black'))
313 dwg.add(dwg.text("QFP 128L OPEN STAMPING",
314 insert=(woffs+width+scale*29, scale*10),
315 fill='black'))
316 dwg.add(dwg.text("BODY 14x20x2.75mm",
317 insert=(woffs+width+scale*29, scale*11),
318 fill='black'))
319 dwg.add(dwg.text("L/F PAD SIZE 236x236mil^2",
320 insert=(woffs+width+scale*29, scale*12),
321 fill='black'))
322
323 # add C4M Logo
324 image_data = open(c4m_drawing, "rb").read()
325 encoded = base64.b64encode(image_data).decode()
326 data = 'data:image/png;base64,{}'.format(encoded)
327 pos=(woffs+scale*5.0, hoffs+height-scale*5.0)
328 leads = svgwrite.image.Image(data, pos,
329 size=(50,50))
330 dwg.add(leads)
331
332 if False:
333 # add SRAMs
334 for i in range(4):
335 dwg.add(dwg.rect((woffs+scale+75*i, hoffs+scale),
336 (70,50),
337 fill='white',
338 stroke=svgwrite.rgb(16, 255, 16, '%'),
339 stroke_width=scale/10.0))
340 # add PLL
341 dwg.add(dwg.rect((woffs+width-scale, hoffs+scale),
342 (25,20),
343 fill='white',
344 stroke=svgwrite.rgb(16, 255, 16, '%'),
345 stroke_width=scale/10.0))
346
347 # add attribution
348 dwg.add(dwg.text("Libre-SOC ls180 QFP-128",
349 insert=(woffs+width/2-scale*5, scale*4),
350 fill='black'))
351 dwg.add(dwg.text("In collaboration with LIP6.fr",
352 insert=(woffs+width/2-scale*5, scale*5),
353 fill='black'))
354 dwg.add(dwg.text("Cell Libraries by Chips4Makers",
355 insert=(woffs+width/2-scale*5, scale*6),
356 fill='black'))
357 dwg.add(dwg.text("IMEC TSMC 180nm",
358 insert=(woffs+width/2-scale*5, scale*7),
359 fill='black'))
360 dwg.add(dwg.text("RED Semiconductor",
361 insert=(woffs+width/2-scale*5, scale*8),
362 fill='black'))
363
364 # add package marking circles
365 pos = (owoffs-outerscale*0, ohoffs+len(wepads)*outerscale+outerscale*2.5)
366 dwg.add(dwg.circle(pos, scale*2,
367 fill='white',
368 stroke=svgwrite.rgb(16, 16, 16, '%'),
369 stroke_width=scale/5.0))
370 dwg.add(dwg.circle(pos, scale*1,
371 fill='black',
372 stroke=svgwrite.rgb(255, 16, 16, '%'),
373 stroke_width=scale/5.0))
374 pos = (owoffs+len(nepads)*outerscale+outerscale*2, ohoffs-outerscale*0.5)
375 dwg.add(dwg.circle(pos, scale*2,
376 fill='white',
377 stroke=svgwrite.rgb(16, 16, 16, '%'),
378 stroke_width=scale/5.0))
379
380
381 dwg.save()
382
383 def temp_create_sv(fname, pins):
384 """unsophisticated drawer of an SVG
385 """
386
387 try:
388 import svgwrite
389 except ImportError:
390 print ("WARNING, no SVG image, not producing image %s" % fname)
391 return
392
393 # create internal to external map
394 bondmap = {'N': {}, 'S': {}, 'E': {}, 'W': {} }
395 padside = {'pads.north': 'N', 'pads.east': 'E', 'pads.south': 'S',
396 'pads.west': 'W'}
397 sidepad = {}
398 for pinpad, bank in padside.items():
399 sidepad[bank] = pinpad
400 for ipin in range(len(pins[pinpad])):
401 eside, enum, epinnum = bond_int_to_ext(ipin, bank)
402 bondmap[eside][enum] = (epinnum, ipin, bank)
403 with open("/tmp/bondmap.txt", "w") as f:
404 for k,v in bondmap.items():
405 f.write("%s\n" % k)
406 for enum, (epinnum, ipin, bank) in v.items():
407 f.write(" %d %d -> %s %d\n" % (enum, epinnum, bank, ipin))
408
409 scale = 15
410 outerscale = scale * 2.0
411
412 width = len(pins['pads.north']) * scale
413 height = len(pins['pads.east']) * scale
414 woffs = scale*40#-width/2
415 hoffs = scale*40#-height/2
416
417 nepads = list(bondmap['N'].keys())
418 nepads.sort()
419 wepads = list(bondmap['W'].keys())
420 wepads.sort()
421 eepads = list(bondmap['E'].keys())
422 eepads.sort()
423 sepads = list(bondmap['S'].keys())
424 sepads.sort()
425
426 owoffs = woffs + (width/2) - len(nepads)/2 * outerscale
427 ohoffs = hoffs + (height/2) - len(wepads)/2 * outerscale
428
429 dwg = svgwrite.Drawing(fname, profile='full',
430 size=(width+scale*85, height+scale*80))
431
432 # outer QFP rect
433 # dwg.add(dwg.rect((owoffs-scale*2.5, ohoffs-scale*4.5),
434 dwg.add(dwg.rect((owoffs-scale*2.5, ohoffs-scale*4.5),
435 (len(nepads)*outerscale+scale*9,
436 len(wepads)*outerscale+scale*13),
437 fill='white',
438 stroke=svgwrite.rgb(0, 128, 0, '%'),
439 stroke_width=scale/5.0))
440
441 # inner lead rect
442 dwg.add(dwg.rect((woffs-scale*2, hoffs-scale*2),
443 (width+scale*6, height+scale*6),
444 stroke=svgwrite.rgb(16, 255, 16, '%'),
445 stroke_width=scale/10.0))
446
447 # record the inner line (iopad) position so that the outer one can
448 # match with it
449 innerpos = {'N': {}, 'S': {}, 'E': {}, 'W': {} }
450
451 # create the inner diagram
452 for i, pin in enumerate(pins['pads.west']):
453 ht = hoffs + height - (i * scale) + scale*0.5
454 endline = (woffs-scale*4.5, ht-scale*0.5)
455 innerpos['W'][i] = endline
456 dwg.add(dwg.line((woffs-scale*2, ht-scale*0.5),
457 endline,
458 stroke=svgwrite.rgb(16, 255, 16, '%'),
459 stroke_width=scale/10.0))
460 dwg.add(dwg.text(pin.upper(), insert=(woffs-scale*12, ht),
461 fill='black'))
462 dwg.add(dwg.text("W%d" % (i+1), insert=(woffs-scale*1.5, ht),
463 fill='white'))
464
465 for i, pin in enumerate(pins['pads.east']):
466 ht = hoffs + height - (i * scale) + scale*0.5
467 wd = width + woffs + scale*2
468 endline = (wd+scale*4.5, ht-scale*0.5)
469 innerpos['E'][i] = endline
470 dwg.add(dwg.line((wd+scale*2, ht-scale*0.5),
471 endline,
472 stroke=svgwrite.rgb(16, 255, 16, '%'),
473 stroke_width=scale/10.0))
474 dwg.add(dwg.text(pin.upper(), insert=(wd+scale*5, ht-scale*0.25),
475 fill='black'))
476 dwg.add(dwg.text("E%d" % (i+1), insert=(wd, ht-scale*0.25),
477 fill='white'))
478
479 for i, pin in enumerate(pins['pads.north']):
480 wd = woffs + i * scale + scale*1.5
481 endline = (wd, hoffs-scale*4.5)
482 innerpos['N'][i] = endline
483 dwg.add(dwg.line((wd, hoffs-scale*2),
484 endline,
485 stroke=svgwrite.rgb(16, 255, 16, '%'),
486 stroke_width=scale/10.0))
487 pos=(wd, hoffs-scale*5.0)
488 txt = dwg.text(pin.upper(), insert=pos, fill='black')
489 txt.rotate(-90, pos)
490 dwg.add(txt)
491 pos=(wd+scale*0.25, hoffs-scale*0.25)
492 txt = dwg.text("N%d" % (i+1), insert=pos, fill='white')
493 txt.rotate(-90, pos)
494 dwg.add(txt)
495
496 for i, pin in enumerate(pins['pads.south']):
497 wd = woffs + i * scale + scale*1.5
498 ht = hoffs + height + scale*2
499 endline = (wd, ht+scale*4.5)
500 innerpos['S'][i] = endline
501 dwg.add(dwg.line((wd, ht+scale*2),
502 endline,
503 stroke=svgwrite.rgb(16, 255, 16, '%'),
504 stroke_width=scale/10.0))
505 pos=(wd-scale*0.25, ht+scale*5.0)
506 txt = dwg.text(pin.upper(), insert=pos, fill='black')
507 txt.rotate(90, pos)
508 dwg.add(txt)
509 pos=(wd-scale*0.25, ht+scale*0.25)
510 txt = dwg.text("S%d" % (i+1), insert=pos, fill='white')
511 txt.rotate(90, pos)
512 dwg.add(txt)
513
514 # north outer pads
515 for i in nepads:
516 (epinnum, ipin, bank) = pad = bondmap['N'][i]
517 wd = owoffs + i * outerscale + outerscale*1.5
518 endline = (wd, ohoffs-outerscale*2)
519 startline = innerpos[bank][ipin]
520 dwg.add(dwg.line(startline,
521 endline,
522 stroke=svgwrite.rgb(255, 16, 16, '%'),
523 stroke_width=scale/10.0))
524 pin = pins[sidepad[bank]][ipin]
525 pos=(wd, ohoffs-outerscale*4.0)
526 txt = dwg.text("%s (%s%d)" % (pin.upper(), bank, ipin+1),
527 insert=pos, fill='black')
528 txt.rotate(-90, pos)
529 dwg.add(txt)
530 pos=(wd, ohoffs-outerscale*2.5)
531 txt = dwg.text("%d N" % epinnum, insert=pos, fill='blue')
532 txt.rotate(-90, pos)
533 dwg.add(txt)
534
535 # west outer pads
536 for i in wepads:
537 (epinnum, ipin, bank) = pad = bondmap['W'][i]
538 ht = ohoffs + (i * outerscale) + outerscale*1.5
539 endline = (owoffs+outerscale*0.5, ht)
540 startline = innerpos[bank][ipin]
541 dwg.add(dwg.line(startline,
542 endline,
543 stroke=svgwrite.rgb(255, 16, 16, '%'),
544 stroke_width=scale/10.0))
545 pin = pins[sidepad[bank]][ipin]
546 pos = (owoffs-outerscale*6.0, ht)
547 dwg.add(dwg.text("%s (%s%d)" % (pin.upper(), bank, ipin+1),
548 pos,
549 fill='black'))
550 pos = (owoffs-outerscale*1.0, ht)
551 dwg.add(dwg.text("%d W" % epinnum, insert=pos,
552 fill='blue'))
553
554 # south outer pads
555 for i in sepads:
556 (epinnum, ipin, bank) = pad = bondmap['S'][i]
557 wd = owoffs + i * outerscale + outerscale*1.5
558 ht = ohoffs + len(wepads)*outerscale + outerscale*4
559 endline = (wd, ht)
560 startline = innerpos[bank][ipin]
561 dwg.add(dwg.line(startline,
562 endline,
563 stroke=svgwrite.rgb(255, 16, 16, '%'),
564 stroke_width=scale/10.0))
565 pin = pins[sidepad[bank]][ipin]
566 pos=(wd-outerscale*0.25, ht+outerscale*1.5)
567 txt = dwg.text("%s (%s%d)" % (pin.upper(), bank, ipin+1),
568 insert=pos, fill='black')
569 txt.rotate(90, pos)
570 dwg.add(txt)
571 pos=(wd-outerscale*0.25, ht+outerscale*0.5)
572 txt = dwg.text("%d S" % epinnum, insert=pos, fill='blue')
573 txt.rotate(90, pos)
574 dwg.add(txt)
575
576 # east outer pads
577 for i in eepads:
578 (epinnum, ipin, bank) = pad = bondmap['E'][i]
579 ht = ohoffs + (i * outerscale) + outerscale*1.5
580 wd = owoffs+len(nepads)*outerscale + outerscale*1
581 endline = (wd+outerscale*0.5, ht)
582 startline = innerpos[bank][ipin]
583 dwg.add(dwg.line(startline,
584 endline,
585 stroke=svgwrite.rgb(255, 16, 16, '%'),
586 stroke_width=scale/10.0))
587 pin = pins[sidepad[bank]][ipin]
588 pos = (wd+outerscale*2.5, ht)
589 dwg.add(dwg.text("%s (%s%d)" % (pin.upper(), bank, ipin+1),
590 pos,
591 fill='black'))
592 pos = (wd+outerscale*1.0, ht)
593 dwg.add(dwg.text("%d E" % epinnum, insert=pos,
594 fill='blue'))
595
596 # add ls180 image
597 image_data = open(ls180_drawing, "rb").read()
598 encoded = base64.b64encode(image_data).decode()
599 data = 'data:image/png;base64,{}'.format(encoded)
600 pos=(width/2+woffs-225, height/2+hoffs-225)
601 leads = svgwrite.image.Image(data, pos,
602 size=(480,480))
603 dwg.add(leads)
604
605 # add QFP pack image in top-right
606 image_data = open(pack_drawing, "rb").read()
607 encoded = base64.b64encode(image_data).decode()
608 data = 'data:image/png;base64,{}'.format(encoded)
609 pos=(0, 0)
610 leads = svgwrite.image.Image(data, pos,
611 size=(327,300))
612 dwg.add(leads)
613 dwg.add(dwg.text("GREATEK QFP128L",
614 insert=(50,150),
615 font_size=20,
616 fill='black'))
617 dwg.add(dwg.text("D/W J1-03128-001",
618 insert=(50,180),
619 font_size=20,
620 fill='black'))
621
622
623 # add QFP lead image in centre
624 sz=320
625 image_data = open(lead_drawing, "rb").read()
626 encoded = base64.b64encode(image_data).decode()
627 data = 'data:image/png;base64,{}'.format(encoded)
628 pos=(woffs+width+scale*23.5, 0)
629 leads = svgwrite.image.Image(data, pos,
630 size=(sz,sz))
631 leads.rotate(-90, (pos[0]+sz/2, pos[1]+sz/2))
632 dwg.add(leads)
633
634 dwg.add(dwg.text("GREATEK ELECTRONICS INC.",
635 insert=(woffs+width+scale*29, scale*8),
636 fill='black'))
637 dwg.add(dwg.text("INNER LEAD DRAWING",
638 insert=(woffs+width+scale*29, scale*9),
639 fill='black'))
640 dwg.add(dwg.text("QFP 128L OPEN STAMPING",
641 insert=(woffs+width+scale*29, scale*10),
642 fill='black'))
643 dwg.add(dwg.text("BODY 14x20x2.75mm",
644 insert=(woffs+width+scale*29, scale*11),
645 fill='black'))
646 dwg.add(dwg.text("L/F PAD SIZE 236x236mil^2",
647 insert=(woffs+width+scale*29, scale*12),
648 fill='black'))
649
650 # add C4M Logo
651 image_data = open(c4m_drawing, "rb").read()
652 encoded = base64.b64encode(image_data).decode()
653 data = 'data:image/png;base64,{}'.format(encoded)
654 pos=(woffs+scale*5.0, hoffs+height-scale*5.0)
655 leads = svgwrite.image.Image(data, pos,
656 size=(50,50))
657 dwg.add(leads)
658
659 if False:
660 # add SRAMs
661 for i in range(4):
662 dwg.add(dwg.rect((woffs+scale+75*i, hoffs+scale),
663 (70,50),
664 fill='white',
665 stroke=svgwrite.rgb(16, 255, 16, '%'),
666 stroke_width=scale/10.0))
667 # add PLL
668 dwg.add(dwg.rect((woffs+width-scale, hoffs+scale),
669 (25,20),
670 fill='white',
671 stroke=svgwrite.rgb(16, 255, 16, '%'),
672 stroke_width=scale/10.0))
673
674 # add attribution
675 dwg.add(dwg.text("Libre-SOC ls180 QFP-128",
676 insert=(woffs+width/2-scale*5, scale*4),
677 fill='black'))
678 dwg.add(dwg.text("In collaboration with LIP6.fr",
679 insert=(woffs+width/2-scale*5, scale*5),
680 fill='black'))
681 dwg.add(dwg.text("Cell Libraries by Chips4Makers",
682 insert=(woffs+width/2-scale*5, scale*6),
683 fill='black'))
684 dwg.add(dwg.text("IMEC TSMC 180nm",
685 insert=(woffs+width/2-scale*5, scale*7),
686 fill='black'))
687 dwg.add(dwg.text("RED Semiconductor",
688 insert=(woffs+width/2-scale*5, scale*8),
689 fill='black'))
690
691 # add package marking circles
692 pos = (owoffs-outerscale*0, ohoffs+len(wepads)*outerscale+outerscale*2.5)
693 dwg.add(dwg.circle(pos, scale*2,
694 fill='white',
695 stroke=svgwrite.rgb(16, 16, 16, '%'),
696 stroke_width=scale/5.0))
697 dwg.add(dwg.circle(pos, scale*1,
698 fill='black',
699 stroke=svgwrite.rgb(255, 16, 16, '%'),
700 stroke_width=scale/5.0))
701 pos = (owoffs+len(nepads)*outerscale+outerscale*2, ohoffs-outerscale*0.5)
702 dwg.add(dwg.circle(pos, scale*2,
703 fill='white',
704 stroke=svgwrite.rgb(16, 16, 16, '%'),
705 stroke_width=scale/5.0))
706
707
708 dwg.save()
709
710
711 def display(of, pins, banksel=None, muxwidth=4):
712 of.write("""\
713 | Pin | Mux0 | Mux1 | Mux2 | Mux3 |
714 | --- | ----------- | ----------- | ----------- | ----------- |
715 """)
716 pinidx = sorted(pins.keys())
717 for pin in pinidx:
718 pdata = pins.get(pin)
719 if banksel:
720 skip = False
721 for mux in range(muxwidth):
722 if mux not in pdata:
723 continue
724 name, bank = pdata[mux]
725 if banksel != bank:
726 skip = True
727 if skip:
728 continue
729 res = '| %3d |' % pin
730 for mux in range(muxwidth):
731 if mux not in pdata:
732 res += " |"
733 continue
734 name, bank = pdata[mux]
735 res += " %s %-9s |" % (bank, name)
736 of.write("%s\n" % res)
737
738
739 def fnsplit(f):
740 a = ''
741 n = 0
742 if not f.startswith('FB_'):
743 f2 = f.split('_')
744 if len(f2) == 2:
745 if f2[1].isdigit():
746 return f2[0], int(f2[1])
747 return f2[0], f2[1]
748 #print f
749 while f and not f[0].isdigit():
750 a += f[0]
751 f = f[1:]
752 return a, int(f) if f else None
753
754
755 def fnsort(f1, f2):
756 a1, n1 = fnsplit(f1)
757 a2, n2 = fnsplit(f2)
758 x = cmp(a1, a2)
759 if x != 0:
760 return x
761 return cmp(n1, n2)
762
763
764 def find_fn(fname, names):
765 for n in names:
766 if fname.startswith(n):
767 return n
768
769 def map_name(pinmap, fn, fblower, pin, rename):
770 if not rename:
771 if pin[:-1].isdigit():
772 print ("map name digit", pin, fn, fblower)
773 if fn in ['PWM', 'EINT', 'VDD', 'VSS']:
774 return fn.lower() + pin.lower()
775 if fn == 'GPIO':
776 return 'gpio' + pin[1:].lower()
777 return pin.lower()
778 pin = pin.lower()
779 if fn == 'GPIO':
780 pk = '%s%s_%s' % (fblower, pin[0], pin[:-1])
781 elif pin[:-1].isdigit() and fn != 'EINT':
782 pk = '%s%s_out' % (fblower, pin[:-1])
783 else:
784 pk = '%s_%s' % (fblower, pin[:-1])
785 print ("map name", pk, fblower, pk in pinmap)
786 if not pk in pinmap:
787 return pin.lower()
788 remapped = pinmap[pk]
789 uscore = remapped.find('_')
790 if uscore == -1:
791 return pin.lower()
792 fn, pin = remapped[:uscore], remapped[uscore+1:] + pin[-1]
793 return pin.lower()
794
795 def python_pindict(of, pinmap, pins, function_names, dname, remap):
796
797 res = OrderedDict()
798 of.write("\n%s = OrderedDict()\n" % dname)
799
800 for k, pingroup in pins.byspec.items():
801 (a, n) = k.split(":")
802 if n.isdigit():
803 a = "%s%s" % (a, n)
804 fblower = a.lower()
805 of.write("%s['%s'] = [ " % (dname, fblower))
806 res[fblower] = []
807 count = 0
808 for i, p in enumerate(pingroup):
809 name = map_name(pinmap, k[0], fblower, p, remap)
810 res[fblower].append(name)
811 of.write("'%s', " % name)
812 count += 1
813 if count == 4 and i != len(pingroup)-1:
814 of.write("\n ")
815 count = 0
816 of.write("]\n")
817 print (" dict %s" % dname, a, n, pingroup)
818 of.write("\n\n")
819 return res
820
821 def python_dict_fns(of, pinmap, pins, function_names):
822 of.write("# auto-generated by Libre-SOC pinmux program: do not edit\n")
823 of.write("# python src/pinmux_generator.py -v -s {spec} -o {output}\n")
824 of.write("# use OrderedDict to fix stable order for JTAG Boundary Scan\n")
825 of.write("from collections import OrderedDict\n")
826
827 fn_names = function_names.keys()
828 fns = {}
829
830 fnidx = list(fns.keys())
831 fnidx.sort(key=fnsplit)
832
833 print ("python fnames", function_names)
834 print ("python speckeys", pins.byspec.keys())
835 print ("python dict fns", dir(pins.gpio))
836 print (pins.gpio.pinfn('', ''))
837 print (pins.pwm.pinfn('', ''))
838 print (pins.sdmmc.pinfn('', ''))
839 print ("by spec", pins.byspec)
840 print (pinmap)
841
842 pd = python_pindict(of, {}, pins, function_names, 'pindict', False)
843 ld = python_pindict(of, pinmap, pins, function_names, 'fabricdict', True)
844
845 print ("pd", pd)
846 print ("ld", ld)
847 # process results and create name map
848 fabricmap = OrderedDict()
849 for k in pd.keys():
850 pl = pd[k]
851 ll = ld[k]
852 for pname, lname in zip(pl, ll):
853 pname = "%s_%s" % (k, pname[:-1]) # strip direction +/-/*
854 lname = lname[:-1] # strip direction +/-/*
855 if k in ['eint', 'pwm', 'gpio', 'vdd', 'vss']: # sigh
856 lname = "%s_%s" % (k, lname)
857 fabricmap[pname] = lname
858 print ("fabricmap", fabricmap)
859 of.write("fabricmap = {\n")
860 for k, v in fabricmap.items():
861 of.write("\t'%s': '%s',\n" % (k, v))
862 of.write("}\n")
863 return fabricmap
864
865
866 def display_fns(of, bankspec, pins, function_names):
867 fn_names = function_names.keys()
868 fns = {}
869 for (pin, pdata) in pins.items():
870 for mux in range(0, 4): # skip GPIO for now
871 if mux not in pdata:
872 continue
873 name, bank = pdata[mux]
874 assert name is not None, str(bank)
875 if name not in fns:
876 fns[name] = []
877 fns[name].append((pin - bankspec[bank], mux, bank))
878
879 fnidx = list(fns.keys())
880 fnidx.sort(key=fnsplit)
881 current_fn = None
882 for fname in fnidx:
883 fnbase = find_fn(fname, fn_names)
884 #fblower = fnbase.lower()
885 if fnbase not in function_names:
886 print ("fn %s not in descriptions %s" % \
887 (fname, str(function_names.keys())))
888 continue
889 #print "name", fname, fnbase
890 if fnbase != current_fn:
891 if current_fn is not None:
892 of.write('\n')
893 of.write("## %s\n\n%s\n\n" % (fnbase, function_names[fnbase]))
894 current_fn = fnbase
895 of.write("* %-9s :" % fname)
896 for (pin, mux, bank) in fns[fname]:
897 of.write(" %s%d/%d" % (bank, pin, mux))
898 of.write('\n')
899
900 return fns
901
902
903 def check_functions(of, title, bankspec, fns, pins, required, eint, pwm,
904 descriptions=None):
905 fns = deepcopy(fns)
906 pins = deepcopy(pins)
907 if descriptions is None:
908 descriptions = {}
909 fnidx = fns.keys()
910
911 #print dir(fns)
912 #print dir(pins)
913
914 of.write("# Pinmap for %s\n\n" % title)
915
916 print ("fn_idx", fnidx)
917 print ("fns", fns)
918 print ("fnspec", pins.fnspec.keys())
919 print ("required", required)
920 for name in required:
921 of.write("## %s\n\n" % name)
922 if descriptions and name in descriptions:
923 of.write("%s\n\n" % descriptions[name])
924
925 name = name.split(':')
926 if len(name) == 2:
927 findbank = name[0][0]
928 findmux = int(name[0][1:])
929 name = name[1]
930 else:
931 name = name[0]
932 findbank = None
933 findmux = None
934 name = name.split('/')
935 if len(name) == 2:
936 count = int(name[1])
937 else:
938 count = 100000
939 name = name[0]
940 #print name
941 found = set()
942 pinfound = {}
943 located = set()
944 for fname in fnidx:
945 if not fname.startswith(name):
946 continue
947 for k in pins.fnspec.keys():
948 if fname.startswith(k):
949 fk = list(pins.fnspec[k].keys())
950 fn = pins.fnspec[k]
951 fn = fn[fk[0]]
952 #print fname, fn, dir(fn)
953 if count == 100000:
954 count = len(fn.pingroup)
955 for pin, mux, bank in fns[fname]:
956 if findbank is not None:
957 if findbank != bank:
958 continue
959 if findmux != mux:
960 continue
961 pin_ = pin + bankspec[bank]
962 if pin_ in pins:
963 pinfound[pin_] = (fname, pin_, bank, pin, mux)
964
965 pinidx = sorted(pinfound.keys())
966
967 fname = None
968 removedcount = 0
969 print ("pinidx", pinidx)
970 for pin_ in pinidx:
971 fname, pin_, bank, pin, mux = pinfound[pin_]
972 if fname in found:
973 continue
974 found.add(fname)
975 if len(found) > count:
976 continue
977 del pins[pin_]
978 removedcount += 1
979 of.write("* %s %d %s%d/%d\n" % (fname, pin_, bank, pin, mux))
980
981 print (fns)
982 if removedcount != count:
983 if fname is None:
984 print ("no match between required and available pins")
985 else:
986 print ("not all found", name, removedcount, count, title, found,
987 fns[fname])
988 print ("pins found", pinfound)
989
990 # fnidx.sort(fnsort)
991 of.write('\n')
992
993 # gpios
994 gpios = []
995 for name in descriptions.keys():
996 if not name.startswith('GPIO'):
997 continue
998 if name == 'GPIO':
999 continue
1000 gpios.append(name)
1001 gpios.sort()
1002
1003 if gpios:
1004 of.write("## GPIO\n\n")
1005
1006 for fname in gpios:
1007 if fname in found:
1008 continue
1009 desc = ''
1010 if descriptions and fname in descriptions:
1011 desc = ': %s' % descriptions[fname]
1012 bank = fname[4]
1013 pin = int(fname[7:])
1014 pin_ = pin + bankspec[bank]
1015 if pin_ not in pins:
1016 continue
1017 del pins[pin_]
1018 found.add(fname)
1019 of.write("* %-8s %d %s%-2d %s\n" % (fname, pin_, bank, pin, desc))
1020 of.write('\n')
1021
1022 if eint:
1023 display_group(of, bankspec, "EINT", eint, fns, pins, descriptions)
1024 if pwm:
1025 display_group(of, bankspec, "PWM", pwm, fns, pins, descriptions)
1026
1027 of.write("## Unused Pinouts (spare as GPIO) for '%s'\n\n" % title)
1028 if descriptions and 'GPIO' in descriptions:
1029 of.write("%s\n\n" % descriptions['GPIO'])
1030 display(of, pins)
1031 of.write('\n')
1032
1033 return pins # unused
1034
1035
1036 def display_group(of, bankspec, title, todisplay, fns, pins, descriptions):
1037 of.write("## %s\n\n" % title)
1038
1039 found = set()
1040 for fname in todisplay:
1041 desc = ''
1042 if descriptions and fname in descriptions:
1043 desc = ': %s' % descriptions[fname]
1044 fname = fname.split(':')
1045 if len(fname) == 2:
1046 findbank = fname[0][0]
1047 findmux = int(fname[0][1:])
1048 fname = fname[1]
1049 else:
1050 fname = fname[0]
1051 findbank = None
1052 findmux = None
1053 for (pin, mux, bank) in fns[fname]:
1054 if findbank is not None:
1055 if findbank != bank:
1056 continue
1057 if findmux != mux:
1058 continue
1059 if fname in found:
1060 continue
1061 pin_ = pin + bankspec[bank]
1062 if pin_ not in pins:
1063 continue
1064 del pins[pin_]
1065 found.add(fname)
1066 of.write("* %s %d %s%d/%d %s\n" %
1067 (fname, pin_, bank, pin, mux, desc))
1068 of.write('\n')
1069
1070
1071 def display_fixed(of, fixed, offs):
1072
1073 fkeys = sorted(fixed.keys())
1074 pin_ = offs
1075 res = []
1076 for pin, k in enumerate(fkeys):
1077 of.write("## %s\n\n" % k)
1078 prevname = ''
1079 linecount = 0
1080 for name in fixed[k]:
1081 if linecount == 4:
1082 linecount = 0
1083 of.write('\n')
1084 if prevname[:2] == name[:2] and linecount != 0:
1085 of.write(" %s" % name)
1086 linecount += 1
1087 else:
1088 if linecount != 0:
1089 of.write('\n')
1090 of.write("* %d: %d %s" % (pin_, pin, name))
1091 linecount = 1
1092 res.append((pin_, name))
1093
1094 prevname = name
1095 pin_ += 1
1096 if linecount != 0:
1097 of.write('\n')
1098 of.write('\n')
1099
1100 return res