4eac66fac50b30fa4d6408cc9d6ef922d9f79a1a
3 from copy
import deepcopy
4 from collections
import OrderedDict
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"
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.
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
26 N102 N101 N100 99 N 68 N67 N66 N65
27 W29 W30 W31 N0 N N31 E29 E30 E31
33 W2 W1 W0 S0 S S31 E0 E1 E2
34 S1 S2 S3 4 S 35 S36 S37 S38
38 # returns side, order-on-the-side, pin number
40 return 'N', pin
+3, 99-pin
42 return 'S', pin
+3, 4+pin
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
)
51 return 'N', 35+(31-pin
), 67-(31-pin
)
53 return 'S', pin
+35, 36+pin
54 return 'E', 28-pin
, 39+(pin
-3)
57 def create_sv(fname
, pins
):
58 """unsophisticated drawer of an SVG
64 print ("WARNING, no SVG image, not producing image %s" % fname
)
67 # create internal to external map
68 bondmap
= {'N': {}, 'S': {}, 'E': {}, 'W': {} }
69 padside
= {'pads.north': 'N', 'pads.east': 'E', 'pads.south': 'S',
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():
80 for enum
, (epinnum
, ipin
, bank
) in v
.items():
81 f
.write(" %d %d -> %s %d\n" % (enum
, epinnum
, bank
, ipin
))
84 outerscale
= scale
* 2.0
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
91 nepads
= bondmap
['N'].keys()
93 wepads
= bondmap
['W'].keys()
95 eepads
= bondmap
['E'].keys()
97 sepads
= bondmap
['S'].keys()
100 owoffs
= woffs
+ (width
/2) - len(nepads
)/2 * outerscale
101 ohoffs
= hoffs
+ (height
/2) - len(wepads
)/2 * outerscale
103 dwg
= svgwrite
.Drawing(fname
, profile
='full',
104 size
=(width
+scale
*85, height
+scale
*80))
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),
111 stroke
=svgwrite
.rgb(0, 128, 0, '%'),
112 stroke_width
=scale
/5.0))
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))
120 # record the inner line (iopad) position so that the outer one can
122 innerpos
= {'N': {}, 'S': {}, 'E': {}, 'W': {} }
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),
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
),
135 dwg
.add(dwg
.text("W%d" % (i
+1), insert
=(woffs
-scale
*1.5, ht
),
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),
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),
149 dwg
.add(dwg
.text("E%d" % (i
+1), insert
=(wd
, ht
-scale
*0.25),
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),
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')
164 pos
=(wd
+scale
*0.25, hoffs
-scale
*0.25)
165 txt
= dwg
.text("N%d" % (i
+1), insert
=pos
, fill
='white')
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),
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')
182 pos
=(wd
-scale
*0.25, ht
+scale
*0.25)
183 txt
= dwg
.text("S%d" % (i
+1), insert
=pos
, fill
='white')
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
,
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')
203 pos
=(wd
, ohoffs
-outerscale
*2.5)
204 txt
= dwg
.text("%d N" % epinnum
, insert
=pos
, fill
='blue')
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
,
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),
223 pos
= (owoffs
-outerscale
*1.0, ht
)
224 dwg
.add(dwg
.text("%d W" % epinnum
, insert
=pos
,
229 (epinnum
, ipin
, bank
) = pad
= bondmap
['S'][i
]
230 wd
= owoffs
+ i
* outerscale
+ outerscale
*1.5
231 ht
= ohoffs
+ len(wepads
)*outerscale
+ outerscale
*4
233 startline
= innerpos
[bank
][ipin
]
234 dwg
.add(dwg
.line(startline
,
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')
244 pos
=(wd
-outerscale
*0.25, ht
+outerscale
*0.5)
245 txt
= dwg
.text("%d S" % epinnum
, insert
=pos
, fill
='blue')
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
,
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),
265 pos
= (wd
+outerscale
*1.0, ht
)
266 dwg
.add(dwg
.text("%d E" % epinnum
, insert
=pos
,
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
,
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
)
283 leads
= svgwrite
.image
.Image(data
, pos
,
286 dwg
.add(dwg
.text("GREATEK QFP128L",
290 dwg
.add(dwg
.text("D/W J1-03128-001",
296 # add QFP lead image in centre
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
,
304 leads
.rotate(-90, (pos
[0]+sz
/2, pos
[1]+sz
/2))
307 dwg
.add(dwg
.text("GREATEK ELECTRONICS INC.",
308 insert
=(woffs
+width
+scale
*29, scale
*8),
310 dwg
.add(dwg
.text("INNER LEAD DRAWING",
311 insert
=(woffs
+width
+scale
*29, scale
*9),
313 dwg
.add(dwg
.text("QFP 128L OPEN STAMPING",
314 insert
=(woffs
+width
+scale
*29, scale
*10),
316 dwg
.add(dwg
.text("BODY 14x20x2.75mm",
317 insert
=(woffs
+width
+scale
*29, scale
*11),
319 dwg
.add(dwg
.text("L/F PAD SIZE 236x236mil^2",
320 insert
=(woffs
+width
+scale
*29, scale
*12),
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
,
335 dwg
.add(dwg
.rect((woffs
+scale
+75*i
, hoffs
+scale
),
338 stroke
=svgwrite
.rgb(16, 255, 16, '%'),
339 stroke_width
=scale
/10.0))
341 dwg
.add(dwg
.rect((woffs
+width
-scale
, hoffs
+scale
),
344 stroke
=svgwrite
.rgb(16, 255, 16, '%'),
345 stroke_width
=scale
/10.0))
348 dwg
.add(dwg
.text("Libre-SOC ls180 QFP-128",
349 insert
=(woffs
+width
/2-scale
*5, scale
*4),
351 dwg
.add(dwg
.text("In collaboration with LIP6.fr",
352 insert
=(woffs
+width
/2-scale
*5, scale
*5),
354 dwg
.add(dwg
.text("Cell Libraries by Chips4Makers",
355 insert
=(woffs
+width
/2-scale
*5, scale
*6),
357 dwg
.add(dwg
.text("IMEC TSMC 180nm",
358 insert
=(woffs
+width
/2-scale
*5, scale
*7),
360 dwg
.add(dwg
.text("RED Semiconductor",
361 insert
=(woffs
+width
/2-scale
*5, scale
*8),
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,
368 stroke
=svgwrite
.rgb(16, 16, 16, '%'),
369 stroke_width
=scale
/5.0))
370 dwg
.add(dwg
.circle(pos
, scale
*1,
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,
377 stroke
=svgwrite
.rgb(16, 16, 16, '%'),
378 stroke_width
=scale
/5.0))
384 def display(of
, pins
, banksel
=None, muxwidth
=4):
386 | Pin | Mux0 | Mux1 | Mux2 | Mux3 |
387 | --- | ----------- | ----------- | ----------- | ----------- |
389 pinidx
= sorted(pins
.keys())
391 pdata
= pins
.get(pin
)
394 for mux
in range(muxwidth
):
397 name
, bank
= pdata
[mux
]
402 res
= '| %3d |' % pin
403 for mux
in range(muxwidth
):
407 name
, bank
= pdata
[mux
]
408 res
+= " %s %-9s |" % (bank
, name
)
409 of
.write("%s\n" % res
)
415 if not f
.startswith('FB_'):
419 return f2
[0], int(f2
[1])
422 while f
and not f
[0].isdigit():
425 return a
, int(f
) if f
else None
437 def find_fn(fname
, names
):
439 if fname
.startswith(n
):
442 def map_name(pinmap
, fn
, fblower
, pin
, rename
):
444 if pin
[:-1].isdigit():
445 print "map name digit", pin
, fn
, fblower
446 if fn
in ['PWM', 'EINT', 'VDD', 'VSS']:
447 return fn
.lower() + pin
.lower()
449 return 'gpio' + pin
[1:].lower()
453 pk
= '%s%s_%s' % (fblower
, pin
[0], pin
[:-1])
454 elif pin
[:-1].isdigit() and fn
!= 'EINT':
455 pk
= '%s%s_out' % (fblower
, pin
[:-1])
457 pk
= '%s_%s' % (fblower
, pin
[:-1])
458 print "map name", pk
, fblower
, pinmap
.has_key(pk
)
459 if not pinmap
.has_key(pk
):
461 remapped
= pinmap
[pk
]
462 uscore
= remapped
.find('_')
465 fn
, pin
= remapped
[:uscore
], remapped
[uscore
+1:] + pin
[-1]
468 def python_pindict(of
, pinmap
, pins
, function_names
, dname
, remap
):
471 of
.write("\n%s = OrderedDict()\n" % dname
)
473 for k
, pingroup
in pins
.byspec
.items():
474 (a
, n
) = k
.split(":")
478 of
.write("%s['%s'] = [ " % (dname
, fblower
))
481 for i
, p
in enumerate(pingroup
):
482 name
= map_name(pinmap
, k
[0], fblower
, p
, remap
)
483 res
[fblower
].append(name
)
484 of
.write("'%s', " % name
)
486 if count
== 4 and i
!= len(pingroup
)-1:
490 print " dict %s" % dname
, a
, n
, pingroup
494 def python_dict_fns(of
, pinmap
, pins
, function_names
):
495 of
.write("# auto-generated by Libre-SOC pinmux program: do not edit\n")
496 of
.write("# python src/pinmux_generator.py -v -s {spec} -o {output}\n")
497 of
.write("# use OrderedDict to fix stable order for JTAG Boundary Scan\n")
498 of
.write("from collections import OrderedDict\n")
500 fn_names
= function_names
.keys()
503 fnidx
= list(fns
.keys())
504 fnidx
.sort(key
=fnsplit
)
506 print "python fnames", function_names
507 print "python speckeys", pins
.byspec
.keys()
508 print "python dict fns", dir(pins
.gpio
)
509 print pins
.gpio
.pinfn('', '')
510 print pins
.pwm
.pinfn('', '')
511 print pins
.sdmmc
.pinfn('', '')
512 print "by spec", pins
.byspec
515 pd
= python_pindict(of
, {}, pins
, function_names
, 'pindict', False)
516 ld
= python_pindict(of
, pinmap
, pins
, function_names
, 'litexdict', True)
520 # process results and create name map
521 litexmap
= OrderedDict()
525 for pname
, lname
in zip(pl
, ll
):
526 pname
= "%s_%s" % (k
, pname
[:-1]) # strip direction +/-/*
527 lname
= lname
[:-1] # strip direction +/-/*
528 if k
in ['eint', 'pwm', 'gpio', 'vdd', 'vss']: # sigh
529 lname
= "%s_%s" % (k
, lname
)
530 litexmap
[pname
] = lname
531 print "litexmap", litexmap
532 of
.write("litexmap = {\n")
533 for k
, v
in litexmap
.items():
534 of
.write("\t'%s': '%s',\n" % (k
, v
))
539 def display_fns(of
, bankspec
, pins
, function_names
):
540 fn_names
= function_names
.keys()
542 for (pin
, pdata
) in pins
.items():
543 for mux
in range(0, 4): # skip GPIO for now
546 name
, bank
= pdata
[mux
]
547 assert name
is not None, str(bank
)
550 fns
[name
].append((pin
- bankspec
[bank
], mux
, bank
))
552 fnidx
= list(fns
.keys())
553 fnidx
.sort(key
=fnsplit
)
556 fnbase
= find_fn(fname
, fn_names
)
557 #fblower = fnbase.lower()
558 assert fnbase
in function_names
, "fn %s not in descriptions %s" % \
559 (fname
, str(function_names
.keys()))
560 #print "name", fname, fnbase
561 if fnbase
!= current_fn
:
562 if current_fn
is not None:
564 of
.write("## %s\n\n%s\n\n" % (fnbase
, function_names
[fnbase
]))
566 of
.write("* %-9s :" % fname
)
567 for (pin
, mux
, bank
) in fns
[fname
]:
568 of
.write(" %s%d/%d" % (bank
, pin
, mux
))
574 def check_functions(of
, title
, bankspec
, fns
, pins
, required
, eint
, pwm
,
577 pins
= deepcopy(pins
)
578 if descriptions
is None:
585 of
.write("# Pinmap for %s\n\n" % title
)
587 print "fn_idx", fnidx
589 print "fnspec", pins
.fnspec
.keys()
590 print "required", required
591 for name
in required
:
592 of
.write("## %s\n\n" % name
)
593 if descriptions
and name
in descriptions
:
594 of
.write("%s\n\n" % descriptions
[name
])
596 name
= name
.split(':')
598 findbank
= name
[0][0]
599 findmux
= int(name
[0][1:])
605 name
= name
.split('/')
616 if not fname
.startswith(name
):
618 for k
in pins
.fnspec
.keys():
619 if fname
.startswith(k
):
620 fk
= list(pins
.fnspec
[k
].keys())
623 #print fname, fn, dir(fn)
625 count
= len(fn
.pingroup
)
626 for pin
, mux
, bank
in fns
[fname
]:
627 if findbank
is not None:
632 pin_
= pin
+ bankspec
[bank
]
634 pinfound
[pin_
] = (fname
, pin_
, bank
, pin
, mux
)
636 pinidx
= sorted(pinfound
.keys())
640 print ("pinidx", pinidx
)
642 fname
, pin_
, bank
, pin
, mux
= pinfound
[pin_
]
646 if len(found
) > count
:
650 of
.write("* %s %d %s%d/%d\n" % (fname
, pin_
, bank
, pin
, mux
))
653 if removedcount
!= count
:
655 print "no match between required and available pins"
657 print ("not all found", name
, removedcount
, count
, title
, found
,
659 print ("pins found", pinfound
)
666 for name
in descriptions
.keys():
667 if not name
.startswith('GPIO'):
675 of
.write("## GPIO\n\n")
681 if descriptions
and fname
in descriptions
:
682 desc
= ': %s' % descriptions
[fname
]
685 pin_
= pin
+ bankspec
[bank
]
690 of
.write("* %-8s %d %s%-2d %s\n" % (fname
, pin_
, bank
, pin
, desc
))
694 display_group(of
, bankspec
, "EINT", eint
, fns
, pins
, descriptions
)
696 display_group(of
, bankspec
, "PWM", pwm
, fns
, pins
, descriptions
)
698 of
.write("## Unused Pinouts (spare as GPIO) for '%s'\n\n" % title
)
699 if descriptions
and 'GPIO' in descriptions
:
700 of
.write("%s\n\n" % descriptions
['GPIO'])
707 def display_group(of
, bankspec
, title
, todisplay
, fns
, pins
, descriptions
):
708 of
.write("## %s\n\n" % title
)
711 for fname
in todisplay
:
713 if descriptions
and fname
in descriptions
:
714 desc
= ': %s' % descriptions
[fname
]
715 fname
= fname
.split(':')
717 findbank
= fname
[0][0]
718 findmux
= int(fname
[0][1:])
724 for (pin
, mux
, bank
) in fns
[fname
]:
725 if findbank
is not None:
732 pin_
= pin
+ bankspec
[bank
]
737 of
.write("* %s %d %s%d/%d %s\n" %
738 (fname
, pin_
, bank
, pin
, mux
, desc
))
742 def display_fixed(of
, fixed
, offs
):
744 fkeys
= sorted(fixed
.keys())
747 for pin
, k
in enumerate(fkeys
):
748 of
.write("## %s\n\n" % k
)
751 for name
in fixed
[k
]:
755 if prevname
[:2] == name
[:2] and linecount
!= 0:
756 of
.write(" %s" % name
)
761 of
.write("* %d: %d %s" % (pin_
, pin
, name
))
763 res
.append((pin_
, name
))