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