use OrderedDict in pinmap so that JTAG boundary scan is ordered
[pinmux.git] / src / spec / ifaceprint.py
1 #!/usr/bin/env python
2
3 from copy import deepcopy
4
5
6 def display(of, pins, banksel=None, muxwidth=4):
7 of.write("""\
8 | Pin | Mux0 | Mux1 | Mux2 | Mux3 |
9 | --- | ----------- | ----------- | ----------- | ----------- |
10 """)
11 pinidx = sorted(pins.keys())
12 for pin in pinidx:
13 pdata = pins.get(pin)
14 if banksel:
15 skip = False
16 for mux in range(muxwidth):
17 if mux not in pdata:
18 continue
19 name, bank = pdata[mux]
20 if banksel != bank:
21 skip = True
22 if skip:
23 continue
24 res = '| %3d |' % pin
25 for mux in range(muxwidth):
26 if mux not in pdata:
27 res += " |"
28 continue
29 name, bank = pdata[mux]
30 res += " %s %-9s |" % (bank, name)
31 of.write("%s\n" % res)
32
33
34 def fnsplit(f):
35 a = ''
36 n = 0
37 if not f.startswith('FB_'):
38 f2 = f.split('_')
39 if len(f2) == 2:
40 if f2[1].isdigit():
41 return f2[0], int(f2[1])
42 return f2[0], f2[1]
43 #print f
44 while f and not f[0].isdigit():
45 a += f[0]
46 f = f[1:]
47 return a, int(f) if f else None
48
49
50 def fnsort(f1, f2):
51 a1, n1 = fnsplit(f1)
52 a2, n2 = fnsplit(f2)
53 x = cmp(a1, a2)
54 if x != 0:
55 return x
56 return cmp(n1, n2)
57
58
59 def find_fn(fname, names):
60 for n in names:
61 if fname.startswith(n):
62 return n
63
64 def map_name(pinmap, fn, fblower, pin, rename):
65 if not rename:
66 if pin[:-1].isdigit():
67 print "map name digit", pin, fn, fblower
68 if fn in ['PWM', 'EINT', 'VDD', 'VSS']:
69 return fn.lower() + pin.lower()
70 if fn == 'GPIO':
71 return 'gpio' + pin[1:].lower()
72 return pin.lower()
73 pin = pin.lower()
74 if fn == 'GPIO':
75 pk = '%s%s_%s' % (fblower, pin[0], pin[:-1])
76 elif pin[:-1].isdigit() and fn != 'EINT':
77 pk = '%s%s_out' % (fblower, pin[:-1])
78 else:
79 pk = '%s_%s' % (fblower, pin[:-1])
80 print "map name", pk, fblower, pinmap.has_key(pk)
81 if not pinmap.has_key(pk):
82 return pin.lower()
83 remapped = pinmap[pk]
84 uscore = remapped.find('_')
85 if uscore == -1:
86 return pin.lower()
87 fn, pin = remapped[:uscore], remapped[uscore+1:] + pin[-1]
88 return pin.lower()
89
90 def python_pindict(of, pinmap, pins, function_names, dname, remap):
91
92 of.write("\n%s = OrderedDict()\n" % dname)
93
94 for k, pingroup in pins.byspec.items():
95 (a, n) = k.split(":")
96 if n.isdigit():
97 a = "%s%s" % (a, n)
98 fblower = a.lower()
99 of.write("%s['%s'] = [ " % (dname, fblower))
100 count = 0
101 for i, p in enumerate(pingroup):
102 of.write("'%s', " % map_name(pinmap, k[0], fblower, p, remap))
103 count += 1
104 if count == 4 and i != len(pingroup)-1:
105 of.write("\n ")
106 count = 0
107 of.write("]\n")
108 print " dict %s" % dname, a, n, pingroup
109 of.write("\n\n")
110
111 def python_dict_fns(of, pinmap, pins, function_names):
112 of.write("# auto-generated by Libre-SOC pinmux program: do not edit\n")
113 of.write("# python src/pinmux_generator.py -v -s {spec} -o {output}\n")
114 of.write("# use OrderedDict to fix stable order for JTAG Boundary Scan\n")
115 of.write("from collections import OrderedDict\n")
116
117 fn_names = function_names.keys()
118 fns = {}
119
120 fnidx = list(fns.keys())
121 fnidx.sort(key=fnsplit)
122
123 print "python fnames", function_names
124 print "python speckeys", pins.byspec.keys()
125 print "python dict fns", dir(pins.gpio)
126 print pins.gpio.pinfn('', '')
127 print pins.pwm.pinfn('', '')
128 print pins.sdmmc.pinfn('', '')
129 print "by spec", pins.byspec
130 print pinmap
131
132 python_pindict(of, {}, pins, function_names, 'pindict', False)
133 python_pindict(of, pinmap, pins, function_names, 'litexdict', True)
134
135
136 def display_fns(of, bankspec, pins, function_names):
137 fn_names = function_names.keys()
138 fns = {}
139 for (pin, pdata) in pins.items():
140 for mux in range(0, 4): # skip GPIO for now
141 if mux not in pdata:
142 continue
143 name, bank = pdata[mux]
144 assert name is not None, str(bank)
145 if name not in fns:
146 fns[name] = []
147 fns[name].append((pin - bankspec[bank], mux, bank))
148
149 fnidx = list(fns.keys())
150 fnidx.sort(key=fnsplit)
151 current_fn = None
152 for fname in fnidx:
153 fnbase = find_fn(fname, fn_names)
154 #fblower = fnbase.lower()
155 assert fnbase in function_names, "fn %s not in descriptions %s" % \
156 (fname, str(function_names.keys()))
157 #print "name", fname, fnbase
158 if fnbase != current_fn:
159 if current_fn is not None:
160 of.write('\n')
161 of.write("## %s\n\n%s\n\n" % (fnbase, function_names[fnbase]))
162 current_fn = fnbase
163 of.write("* %-9s :" % fname)
164 for (pin, mux, bank) in fns[fname]:
165 of.write(" %s%d/%d" % (bank, pin, mux))
166 of.write('\n')
167
168 return fns
169
170
171 def check_functions(of, title, bankspec, fns, pins, required, eint, pwm,
172 descriptions=None):
173 fns = deepcopy(fns)
174 pins = deepcopy(pins)
175 if descriptions is None:
176 descriptions = {}
177 fnidx = fns.keys()
178
179 #print dir(fns)
180 #print dir(pins)
181
182 of.write("# Pinmap for %s\n\n" % title)
183
184 print "fn_idx", fnidx
185 print "fns", fns
186 print "fnspec", pins.fnspec.keys()
187 print "required", required
188 for name in required:
189 of.write("## %s\n\n" % name)
190 if descriptions and name in descriptions:
191 of.write("%s\n\n" % descriptions[name])
192
193 name = name.split(':')
194 if len(name) == 2:
195 findbank = name[0][0]
196 findmux = int(name[0][1:])
197 name = name[1]
198 else:
199 name = name[0]
200 findbank = None
201 findmux = None
202 name = name.split('/')
203 if len(name) == 2:
204 count = int(name[1])
205 else:
206 count = 100000
207 name = name[0]
208 #print name
209 found = set()
210 pinfound = {}
211 located = set()
212 for fname in fnidx:
213 if not fname.startswith(name):
214 continue
215 for k in pins.fnspec.keys():
216 if fname.startswith(k):
217 fk = list(pins.fnspec[k].keys())
218 fn = pins.fnspec[k]
219 fn = fn[fk[0]]
220 #print fname, fn, dir(fn)
221 if count == 100000:
222 count = len(fn.pingroup)
223 for pin, mux, bank in fns[fname]:
224 if findbank is not None:
225 if findbank != bank:
226 continue
227 if findmux != mux:
228 continue
229 pin_ = pin + bankspec[bank]
230 if pin_ in pins:
231 pinfound[pin_] = (fname, pin_, bank, pin, mux)
232
233 pinidx = sorted(pinfound.keys())
234
235 fname = None
236 removedcount = 0
237 print ("pinidx", pinidx)
238 for pin_ in pinidx:
239 fname, pin_, bank, pin, mux = pinfound[pin_]
240 if fname in found:
241 continue
242 found.add(fname)
243 if len(found) > count:
244 continue
245 del pins[pin_]
246 removedcount += 1
247 of.write("* %s %d %s%d/%d\n" % (fname, pin_, bank, pin, mux))
248
249 print fns
250 if removedcount != count:
251 if fname is None:
252 print "no match between required and available pins"
253 else:
254 print ("not all found", name, removedcount, count, title, found,
255 fns[fname])
256 print ("pins found", pinfound)
257
258 # fnidx.sort(fnsort)
259 of.write('\n')
260
261 # gpios
262 gpios = []
263 for name in descriptions.keys():
264 if not name.startswith('GPIO'):
265 continue
266 if name == 'GPIO':
267 continue
268 gpios.append(name)
269 gpios.sort()
270
271 if gpios:
272 of.write("## GPIO\n\n")
273
274 for fname in gpios:
275 if fname in found:
276 continue
277 desc = ''
278 if descriptions and fname in descriptions:
279 desc = ': %s' % descriptions[fname]
280 bank = fname[4]
281 pin = int(fname[7:])
282 pin_ = pin + bankspec[bank]
283 if pin_ not in pins:
284 continue
285 del pins[pin_]
286 found.add(fname)
287 of.write("* %-8s %d %s%-2d %s\n" % (fname, pin_, bank, pin, desc))
288 of.write('\n')
289
290 if eint:
291 display_group(of, bankspec, "EINT", eint, fns, pins, descriptions)
292 if pwm:
293 display_group(of, bankspec, "PWM", pwm, fns, pins, descriptions)
294
295 of.write("## Unused Pinouts (spare as GPIO) for '%s'\n\n" % title)
296 if descriptions and 'GPIO' in descriptions:
297 of.write("%s\n\n" % descriptions['GPIO'])
298 display(of, pins)
299 of.write('\n')
300
301 return pins # unused
302
303
304 def display_group(of, bankspec, title, todisplay, fns, pins, descriptions):
305 of.write("## %s\n\n" % title)
306
307 found = set()
308 for fname in todisplay:
309 desc = ''
310 if descriptions and fname in descriptions:
311 desc = ': %s' % descriptions[fname]
312 fname = fname.split(':')
313 if len(fname) == 2:
314 findbank = fname[0][0]
315 findmux = int(fname[0][1:])
316 fname = fname[1]
317 else:
318 fname = fname[0]
319 findbank = None
320 findmux = None
321 for (pin, mux, bank) in fns[fname]:
322 if findbank is not None:
323 if findbank != bank:
324 continue
325 if findmux != mux:
326 continue
327 if fname in found:
328 continue
329 pin_ = pin + bankspec[bank]
330 if pin_ not in pins:
331 continue
332 del pins[pin_]
333 found.add(fname)
334 of.write("* %s %d %s%d/%d %s\n" %
335 (fname, pin_, bank, pin, mux, desc))
336 of.write('\n')
337
338
339 def display_fixed(of, fixed, offs):
340
341 fkeys = sorted(fixed.keys())
342 pin_ = offs
343 res = []
344 for pin, k in enumerate(fkeys):
345 of.write("## %s\n\n" % k)
346 prevname = ''
347 linecount = 0
348 for name in fixed[k]:
349 if linecount == 4:
350 linecount = 0
351 of.write('\n')
352 if prevname[:2] == name[:2] and linecount != 0:
353 of.write(" %s" % name)
354 linecount += 1
355 else:
356 if linecount != 0:
357 of.write('\n')
358 of.write("* %d: %d %s" % (pin_, pin, name))
359 linecount = 1
360 res.append((pin_, name))
361
362 prevname = name
363 pin_ += 1
364 if linecount != 0:
365 of.write('\n')
366 of.write('\n')
367
368 return res