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
= list(bondmap
['N'].keys())
93 wepads
= list(bondmap
['W'].keys())
95 eepads
= list(bondmap
['E'].keys())
97 sepads
= list(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
, pk
in pinmap
)
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
))