add vectorised gpio interface
[pinmux.git] / src / bsv / interface_decl.py
1 import os.path
2
3 try:
4 from UserDict import UserDict
5 except ImportError:
6 from collections import UserDict
7
8 from bsv.wire_def import generic_io # special case
9 from bsv.wire_def import muxwire # special case
10 from ifacebase import InterfacesBase
11 from bsv.peripheral_gen import PeripheralIface
12 from bsv.peripheral_gen import PeripheralInterfaces
13
14
15 class Pin(object):
16 """ pin interface declaration.
17 * name is the name of the pin
18 * ready, enabled and io all create a (* .... *) prefix
19 * action changes it to an "in" if true
20 """
21
22 def __init__(self, name,
23 name_ = None,
24 idx=None,
25 ready=True,
26 enabled=True,
27 io=False,
28 action=False,
29 bitspec=None,
30 outenmode=False):
31 self.name = name
32 self.name_ = name_
33 self.idx = idx
34 self.ready = ready
35 self.enabled = enabled
36 self.io = io
37 self.action = action
38 self.bitspec = bitspec if bitspec else 'Bit#(1)'
39 self.outenmode = outenmode
40
41 # bsv will look like this (method declaration):
42 """
43 (*always_ready,always_enabled*) method Bit#(1) io0_cell_outen;
44 (*always_ready,always_enabled,result="io"*) method
45 Action io0_inputval (Bit#(1) in);
46 """
47
48 def ifacepfmt(self, fmtfn):
49 res = ' '
50 status = []
51 res += "interface "
52 name = fmtfn(self.name_)
53 if self.action:
54 res += "Put"
55 else:
56 res += "Get"
57 res += "#(%s) %s;" % (self.bitspec, name)
58 return res
59
60 def ifacefmt(self, fmtfn):
61 res = ' '
62 status = []
63 if self.ready:
64 status.append('always_ready')
65 if self.enabled:
66 status.append('always_enabled')
67 if self.io:
68 status.append('result="io"')
69 if status:
70 res += '(*'
71 res += ','.join(status)
72 res += '*)'
73 res += " method "
74 if self.io:
75 res += "\n "
76 name = fmtfn(self.name)
77 if self.action:
78 res += " Action "
79 res += name
80 res += ' (%s in)' % self.bitspec
81 else:
82 res += " %s " % self.bitspec
83 res += name
84 res += ";"
85 return res
86
87 def ifacedef(self, fmtoutfn, fmtinfn, fmtdecfn):
88 res = ' method '
89 if self.action:
90 fmtname = fmtinfn(self.name)
91 res += "Action "
92 res += fmtdecfn(self.name)
93 res += '(%s in);\n' % self.bitspec
94 res += ' %s<=in;\n' % fmtname
95 res += ' endmethod'
96 else:
97 fmtname = fmtoutfn(self.name)
98 res += "%s=%s;" % (self.name, fmtname)
99 return res
100 # sample bsv method definition :
101 """
102 method Action cell0_mux(Bit#(2) in);
103 wrcell0_mux<=in;
104 endmethod
105 """
106
107 # sample bsv wire (wire definiton):
108 """
109 Wire#(Bit#(2)) wrcell0_mux<-mkDWire(0);
110 """
111
112 def wirefmt(self, fmtoutfn, fmtinfn, fmtdecfn):
113 res = ' Wire#(%s) ' % self.bitspec
114 if self.action:
115 res += '%s' % fmtinfn(self.name)
116 else:
117 res += '%s' % fmtoutfn(self.name)
118 res += "<-mkDWire(0);"
119 return res
120
121 def ifacedef2(self, fmtoutfn, fmtinfn, fmtdecfn):
122 if self.action:
123 fmtname = fmtinfn(self.name)
124 res = " interface %s = interface Put\n" % self.name_
125 res += ' method '
126 res += "Action put"
127 #res += fmtdecfn(self.name)
128 res += '(%s in);\n' % self.bitspec
129 res += ' %s<=in;\n' % fmtname
130 res += ' endmethod\n'
131 res += ' endinterface;'
132 else:
133 fmtname = fmtoutfn(self.name)
134 res = " interface %s = interface Get\n" % self.name_
135 res += ' method ActionValue#'
136 res += '(%s) get;\n' % self.bitspec
137 res += " return %s;\n" % (fmtname)
138 res += ' endmethod\n'
139 res += ' endinterface;'
140 return res
141
142 def ifacedef3(self, fmtoutfn, fmtinfn, fmtdecfn):
143 if self.action:
144 fmtname = fmtinfn(self.name)
145 if self.name.endswith('outen'):
146 name = "tputen"
147 else:
148 name = "tput"
149 res = " %s <= in[%d];" % (fmtname, self.idx)
150 else:
151 fmtname = fmtoutfn(self.name)
152 res = " tget[%d] <= %s;" % (self.idx, fmtname)
153 name = 'tget'
154 return (name, res)
155
156 class Interface(PeripheralIface):
157 """ create an interface from a list of pinspecs.
158 each pinspec is a dictionary, see Pin class arguments
159 single indicates that there is only one of these, and
160 so the name must *not* be extended numerically (see pname)
161 """
162 # sample interface object:
163 """
164 twiinterface_decl = Interface('twi',
165 [{'name': 'sda', 'outen': True},
166 {'name': 'scl', 'outen': True},
167 ])
168 """
169
170 def __init__(self, ifacename, pinspecs, ganged=None, single=False):
171 PeripheralIface.__init__(self, ifacename)
172 self.ifacename = ifacename
173 self.ganged = ganged or {}
174 self.pins = [] # a list of instances of class Pin
175 self.pinspecs = pinspecs # a list of dictionary
176 self.single = single
177
178 for idx, p in enumerate(pinspecs):
179 _p = {}
180 _p.update(p)
181 if 'type' in _p:
182 del _p['type']
183 if p.get('outen') is True: # special case, generate 3 pins
184 del _p['outen']
185 for psuffix in ['out', 'outen', 'in']:
186 # changing the name (like sda) to (twi_sda_out)
187 _p['name_'] = "%s_%s" % (p['name'], psuffix)
188 _p['name'] = "%s_%s" % (self.pname(p['name']), psuffix)
189 _p['action'] = psuffix != 'in'
190 _p['idx'] = idx
191 self.pins.append(Pin(**_p))
192 # will look like {'name': 'twi_sda_out', 'action': True}
193 # {'name': 'twi_sda_outen', 'action': True}
194 #{'name': 'twi_sda_in', 'action': False}
195 # NOTice - outen key is removed
196 else:
197 name = p['name']
198 if name.isdigit(): # HACK! deals with EINT case
199 name = self.pname(name)
200 _p['name_'] = name
201 _p['idx'] = idx
202 _p['name'] = self.pname(p['name'])
203 self.pins.append(Pin(**_p))
204
205 # sample interface object:
206 """
207 uartinterface_decl = Interface('uart',
208 [{'name': 'rx'},
209 {'name': 'tx', 'action': True},
210 ])
211 """
212 """
213 getifacetype is called multiple times in actual_pinmux.py
214 x = ifaces.getifacetype(temp), where temp is uart_rx, spi_mosi
215 Purpose is to identify is function : input/output/inout
216 """
217
218 def getifacetype(self, name):
219 for p in self.pinspecs:
220 fname = "%s_%s" % (self.ifacename, p['name'])
221 # print "search", self.ifacename, name, fname
222 if fname == name:
223 if p.get('action'):
224 return 'out'
225 elif p.get('outen'):
226 return 'inout'
227 return 'input'
228 return None
229
230 def iname(self):
231 """ generates the interface spec e.g. flexbus_ale
232 if there is only one flexbus interface, or
233 sd{0}_cmd if there are several. string format
234 function turns this into sd0_cmd, sd1_cmd as
235 appropriate. single mode stops the numerical extension.
236 """
237 if self.single:
238 return self.ifacename
239 return '%s{0}' % self.ifacename
240
241 def pname(self, name):
242 """ generates the interface spec e.g. flexbus_ale
243 if there is only one flexbus interface, or
244 sd{0}_cmd if there are several. string format
245 function turns this into sd0_cmd, sd1_cmd as
246 appropriate. single mode stops the numerical extension.
247 """
248 return "%s_%s" % (self.iname(), name)
249
250 def busfmt(self, *args):
251 """ this function creates a bus "ganging" system based
252 on input from the {interfacename}.txt file.
253 only inout pins that are under the control of the
254 interface may be "ganged" together.
255 """
256 if not self.ganged:
257 return '' # when self.ganged is None
258 # print self.ganged
259 res = []
260 for (k, pnames) in self.ganged.items():
261 name = self.pname('%senable' % k).format(*args)
262 decl = 'Bit#(1) %s = 0;' % name
263 res.append(decl)
264 ganged = []
265 for p in self.pinspecs:
266 if p['name'] not in pnames:
267 continue
268 pname = self.pname(p['name']).format(*args)
269 if p.get('outen') is True:
270 outname = self.ifacefmtoutfn(pname)
271 ganged.append("%s_outen" % outname) # match wirefmt
272
273 gangedfmt = '{%s} = duplicate(%s);'
274 res.append(gangedfmt % (',\n '.join(ganged), name))
275 return '\n'.join(res) + '\n\n'
276
277 def wirefmt(self, *args):
278 res = '\n'.join(map(self.wirefmtpin, self.pins)).format(*args)
279 res += '\n'
280 return '\n' + res
281
282 def ifacepfmt(self, *args):
283 res = '\n'.join(map(self.ifacepfmtdecpin, self.pins)).format(*args)
284 return '\n' + res # pins is a list
285
286 def ifacefmt(self, *args):
287 res = '\n'.join(map(self.ifacefmtdecpin, self.pins)).format(*args)
288 return '\n' + res # pins is a list
289
290 def ifacepfmtdecfn(self, name):
291 return name
292
293 def ifacefmtdecfn(self, name):
294 return name # like: uart
295
296 def ifacefmtdecfn2(self, name):
297 return name # like: uart
298
299 def ifacefmtdecfn3(self, name):
300 """ HACK! """
301 return "%s_outen" % name # like uart_outen
302
303 def ifacefmtoutfn(self, name):
304 return "wr%s" % name # like wruart
305
306 def ifacefmtinfn(self, name):
307 return "wr%s" % name
308
309 def wirefmtpin(self, pin):
310 return pin.wirefmt(self.ifacefmtoutfn, self.ifacefmtinfn,
311 self.ifacefmtdecfn2)
312
313 def ifacepfmtdecpin(self, pin):
314 return pin.ifacepfmt(self.ifacepfmtdecfn)
315
316 def ifacefmtdecpin(self, pin):
317 return pin.ifacefmt(self.ifacefmtdecfn)
318
319 def ifacefmtpin(self, pin):
320 decfn = self.ifacefmtdecfn2
321 outfn = self.ifacefmtoutfn
322 # print pin, pin.outenmode
323 if pin.outenmode:
324 decfn = self.ifacefmtdecfn3
325 outfn = self.ifacefmtoutenfn
326 return pin.ifacedef(outfn, self.ifacefmtinfn,
327 decfn)
328
329 def ifacedef2pin(self, pin):
330 decfn = self.ifacefmtdecfn2
331 outfn = self.ifacefmtoutfn
332 # print pin, pin.outenmode
333 if pin.outenmode:
334 decfn = self.ifacefmtdecfn3
335 outfn = self.ifacefmtoutenfn
336 return pin.ifacedef2(outfn, self.ifacefmtinfn,
337 decfn)
338
339 def ifacedef(self, *args):
340 res = '\n'.join(map(self.ifacefmtpin, self.pins))
341 res = res.format(*args)
342 return '\n' + res + '\n'
343
344 def ifacedef2(self, *args):
345 res = '\n'.join(map(self.ifacedef2pin, self.pins))
346 res = res.format(*args)
347 return '\n' + res + '\n'
348
349
350 class MuxInterface(Interface):
351
352 def wirefmt(self, *args):
353 return muxwire.format(*args)
354
355
356 class IOInterface(Interface):
357
358 def ifacefmtoutenfn(self, name):
359 return "cell{0}_mux_outen"
360
361 def ifacefmtoutfn(self, name):
362 """ for now strip off io{0}_ part """
363 return "cell{0}_mux_out"
364
365 def ifacefmtinfn(self, name):
366 return "cell{0}_mux_in"
367
368 def wirefmt(self, *args):
369 return generic_io.format(*args)
370
371 class InterfaceGPIO(Interface):
372
373 def ifacedef2(self, *args):
374 tput = []
375 tget = []
376 tputen = []
377 for (typ, txt) in map(self.ifacedef2pin, self.pins):
378 if typ == 'tput':
379 tput.append(txt)
380 elif typ == 'tget':
381 tget.append(txt)
382 elif typ == 'tputen':
383 tputen.append(txt)
384 tput = '\n'.join(tput).format(*args)
385 tget = '\n'.join(tget).format(*args)
386 tputen = '\n'.join(tputen).format(*args)
387
388 template = """\
389 interface gpio_out = interface Put#({0})
390 method Action put(Vector#({0},Bit#(1)) in);
391 {1}
392 endmethod
393 endinterface;
394 interface gpio_outen = interface Put#({0})
395 method Action put(Vector#({0},Bit#(1)) in);
396 {2}
397 endmethod
398 endinterface;
399 interface gpio_in = interface Get#({0})
400 method ActionValue#(Vector#({0},Bit#(1))) get;
401 Vector#({0},Bit#(1)) tputen;
402 {3}
403 return tget;
404 endmethod
405 endinterface;
406 """.format(len(self.pinspecs), tput, tputen, tget)
407 return '\n' + template + '\n'
408
409 def ifacedef2pin(self, pin):
410 decfn = self.ifacefmtdecfn2
411 outfn = self.ifacefmtoutfn
412 # print pin, pin.outenmode
413 if pin.outenmode:
414 decfn = self.ifacefmtdecfn3
415 outfn = self.ifacefmtoutenfn
416 return pin.ifacedef3(outfn, self.ifacefmtinfn,
417 decfn)
418
419
420 class Interfaces(InterfacesBase, PeripheralInterfaces):
421 """ contains a list of interface definitions
422 """
423
424 def __init__(self, pth=None):
425 InterfacesBase.__init__(self, Interface, pth,
426 {'gpio': InterfaceGPIO })
427 PeripheralInterfaces.__init__(self)
428
429 def ifacedef(self, f, *args):
430 for (name, count) in self.ifacecount:
431 for i in range(count):
432 f.write(self.data[name].ifacedef(i))
433
434 def ifacedef2(self, f, *args):
435 c = " interface {0} = interface PeripheralSide{1}"
436 for (name, count) in self.ifacecount:
437 for i in range(count):
438 iname = self.data[name].iname().format(i)
439 f.write(c.format(iname, name.upper()))
440 f.write(self.data[name].ifacedef2(i))
441 f.write(" endinterface;\n\n")
442
443 def busfmt(self, f, *args):
444 f.write("import BUtils::*;\n\n")
445 for (name, count) in self.ifacecount:
446 for i in range(count):
447 bf = self.data[name].busfmt(i)
448 f.write(bf)
449
450 def ifacepfmt(self, f, *args):
451 comment = '''
452 // interface declaration between {0} and pinmux
453 (*always_ready,always_enabled*)
454 interface PeripheralSide{0};'''
455 for (name, count) in self.ifacecount:
456 f.write(comment.format(name.upper()))
457 f.write(self.data[name].ifacepfmt(0))
458 f.write("\n endinterface\n")
459
460 def ifacefmt(self, f, *args):
461 comment = '''
462 // interface declaration between %s-{0} and pinmux'''
463 for (name, count) in self.ifacecount:
464 for i in range(count):
465 c = comment % name.upper()
466 f.write(c.format(i))
467 f.write(self.data[name].ifacefmt(i))
468
469 def ifacefmt2(self, f, *args):
470 comment = '''
471 interface PeripheralSide{0} {1};'''
472 for (name, count) in self.ifacecount:
473 for i in range(count):
474 iname = self.data[name].iname().format(i)
475 f.write(comment.format(name.upper(), iname))
476
477 def wirefmt(self, f, *args):
478 comment = '\n // following wires capture signals ' \
479 'to IO CELL if %s-{0} is\n' \
480 ' // allotted to it'
481 for (name, count) in self.ifacecount:
482 for i in range(count):
483 c = comment % name
484 f.write(c.format(i))
485 f.write(self.data[name].wirefmt(i))
486
487
488 # ========= Interface declarations ================ #
489
490 mux_interface = MuxInterface('cell',
491 [{'name': 'mux', 'ready': False, 'enabled': False,
492 'bitspec': '{1}', 'action': True}])
493
494 io_interface = IOInterface(
495 'io',
496 [{'name': 'cell_out', 'enabled': True, },
497 {'name': 'cell_outen', 'enabled': True, 'outenmode': True, },
498 {'name': 'cell_in', 'action': True, 'io': True}, ])
499
500 # == Peripheral Interface definitions == #
501 # these are the interface of the peripherals to the pin mux
502 # Outputs from the peripherals will be inputs to the pinmux
503 # module. Hence the change in direction for most pins
504
505 # ======================================= #
506
507 # basic test
508 if __name__ == '__main__':
509
510 uartinterface_decl = Interface('uart',
511 [{'name': 'rx'},
512 {'name': 'tx', 'action': True},
513 ])
514
515 twiinterface_decl = Interface('twi',
516 [{'name': 'sda', 'outen': True},
517 {'name': 'scl', 'outen': True},
518 ])
519
520 def _pinmunge(p, sep, repl, dedupe=True):
521 """ munges the text so it's easier to compare.
522 splits by separator, strips out blanks, re-joins.
523 """
524 p = p.strip()
525 p = p.split(sep)
526 if dedupe:
527 p = filter(lambda x: x, p) # filter out blanks
528 return repl.join(p)
529
530 def pinmunge(p):
531 """ munges the text so it's easier to compare.
532 """
533 # first join lines by semicolons, strip out returns
534 p = p.split(";")
535 p = map(lambda x: x.replace('\n', ''), p)
536 p = '\n'.join(p)
537 # now split first by brackets, then spaces (deduping on spaces)
538 p = _pinmunge(p, "(", " ( ", False)
539 p = _pinmunge(p, ")", " ) ", False)
540 p = _pinmunge(p, " ", " ")
541 return p
542
543 def zipcmp(l1, l2):
544 l1 = l1.split("\n")
545 l2 = l2.split("\n")
546 for p1, p2 in zip(l1, l2):
547 print (repr(p1))
548 print (repr(p2))
549 print ()
550 assert p1 == p2
551
552 ifaces = Interfaces()
553
554 ifaceuart = ifaces['uart']
555 print (ifaceuart.ifacedef(0))
556 print (uartinterface_decl.ifacedef(0))
557 assert ifaceuart.ifacedef(0) == uartinterface_decl.ifacedef(0)
558
559 ifacetwi = ifaces['twi']
560 print (ifacetwi.ifacedef(0))
561 print (twiinterface_decl.ifacedef(0))
562 assert ifacetwi.ifacedef(0) == twiinterface_decl.ifacedef(0)