create new get/put interface pinmux declaration
[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 # sample bsv method definition :
86 """
87 method Action cell0_mux(Bit#(2) in);
88 wrcell0_mux<=in;
89 endmethod
90 """
91
92 def ifacedef(self, fmtoutfn, fmtinfn, fmtdecfn):
93 res = ' method '
94 if self.action:
95 fmtname = fmtinfn(self.name)
96 res += "Action "
97 res += fmtdecfn(self.name)
98 res += '(%s in);\n' % self.bitspec
99 res += ' %s<=in;\n' % fmtname
100 res += ' endmethod'
101 else:
102 fmtname = fmtoutfn(self.name)
103 res += "%s=%s;" % (self.name, fmtname)
104 return res
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
120 class Interface(PeripheralIface):
121 """ create an interface from a list of pinspecs.
122 each pinspec is a dictionary, see Pin class arguments
123 single indicates that there is only one of these, and
124 so the name must *not* be extended numerically (see pname)
125 """
126 # sample interface object:
127 """
128 twiinterface_decl = Interface('twi',
129 [{'name': 'sda', 'outen': True},
130 {'name': 'scl', 'outen': True},
131 ])
132 """
133
134 def __init__(self, ifacename, pinspecs, ganged=None, single=False):
135 PeripheralIface.__init__(self, ifacename)
136 self.ifacename = ifacename
137 self.ganged = ganged or {}
138 self.pins = [] # a list of instances of class Pin
139 self.pinspecs = pinspecs # a list of dictionary
140 self.single = single
141
142 for p in pinspecs:
143 _p = {}
144 _p.update(p)
145 if 'type' in _p:
146 del _p['type']
147 if p.get('outen') is True: # special case, generate 3 pins
148 del _p['outen']
149 for psuffix in ['out', 'outen', 'in']:
150 # changing the name (like sda) to (twi_sda_out)
151 _p['name_'] = "%s_%s" % (p['name'], psuffix)
152 _p['name'] = "%s_%s" % (self.pname(p['name']), psuffix)
153 _p['action'] = psuffix != 'in'
154 self.pins.append(Pin(**_p))
155 # will look like {'name': 'twi_sda_out', 'action': True}
156 # {'name': 'twi_sda_outen', 'action': True}
157 #{'name': 'twi_sda_in', 'action': False}
158 # NOTice - outen key is removed
159 else:
160 _p['name_'] = p['name']
161 _p['name'] = self.pname(p['name'])
162 self.pins.append(Pin(**_p))
163
164 # sample interface object:
165 """
166 uartinterface_decl = Interface('uart',
167 [{'name': 'rx'},
168 {'name': 'tx', 'action': True},
169 ])
170 """
171 """
172 getifacetype is called multiple times in actual_pinmux.py
173 x = ifaces.getifacetype(temp), where temp is uart_rx, spi_mosi
174 Purpose is to identify is function : input/output/inout
175 """
176
177 def getifacetype(self, name):
178 for p in self.pinspecs:
179 fname = "%s_%s" % (self.ifacename, p['name'])
180 # print "search", self.ifacename, name, fname
181 if fname == name:
182 if p.get('action'):
183 return 'out'
184 elif p.get('outen'):
185 return 'inout'
186 return 'input'
187 return None
188
189 def pname(self, name):
190 """ generates the interface spec e.g. flexbus_ale
191 if there is only one flexbus interface, or
192 sd{0}_cmd if there are several. string format
193 function turns this into sd0_cmd, sd1_cmd as
194 appropriate. single mode stops the numerical extension.
195 """
196 if self.single:
197 return '%s_%s' % (self.ifacename, name)
198 return '%s{0}_%s' % (self.ifacename, name)
199
200 def busfmt(self, *args):
201 """ this function creates a bus "ganging" system based
202 on input from the {interfacename}.txt file.
203 only inout pins that are under the control of the
204 interface may be "ganged" together.
205 """
206 if not self.ganged:
207 return '' # when self.ganged is None
208 # print self.ganged
209 res = []
210 for (k, pnames) in self.ganged.items():
211 name = self.pname('%senable' % k).format(*args)
212 decl = 'Bit#(1) %s = 0;' % name
213 res.append(decl)
214 ganged = []
215 for p in self.pinspecs:
216 if p['name'] not in pnames:
217 continue
218 pname = self.pname(p['name']).format(*args)
219 if p.get('outen') is True:
220 outname = self.ifacefmtoutfn(pname)
221 ganged.append("%s_outen" % outname) # match wirefmt
222
223 gangedfmt = '{%s} = duplicate(%s);'
224 res.append(gangedfmt % (',\n '.join(ganged), name))
225 return '\n'.join(res) + '\n\n'
226
227 def wirefmt(self, *args):
228 res = '\n'.join(map(self.wirefmtpin, self.pins)).format(*args)
229 res += '\n'
230 return '\n' + res
231
232 def ifacepfmt(self, *args):
233 res = '\n'.join(map(self.ifacepfmtdecpin, self.pins)).format(*args)
234 return '\n' + res # pins is a list
235
236 def ifacefmt(self, *args):
237 res = '\n'.join(map(self.ifacefmtdecpin, self.pins)).format(*args)
238 return '\n' + res # pins is a list
239
240 def ifacepfmtdecfn(self, name):
241 return name
242
243 def ifacefmtdecfn(self, name):
244 return name # like: uart
245
246 def ifacefmtdecfn2(self, name):
247 return name # like: uart
248
249 def ifacefmtdecfn3(self, name):
250 """ HACK! """
251 return "%s_outen" % name # like uart_outen
252
253 def ifacefmtoutfn(self, name):
254 return "wr%s" % name # like wruart
255
256 def ifacefmtinfn(self, name):
257 return "wr%s" % name
258
259 def wirefmtpin(self, pin):
260 return pin.wirefmt(self.ifacefmtoutfn, self.ifacefmtinfn,
261 self.ifacefmtdecfn2)
262
263 def ifacepfmtdecpin(self, pin):
264 return pin.ifacepfmt(self.ifacepfmtdecfn)
265
266 def ifacefmtdecpin(self, pin):
267 return pin.ifacefmt(self.ifacefmtdecfn)
268
269 def ifacefmtpin(self, pin):
270 decfn = self.ifacefmtdecfn2
271 outfn = self.ifacefmtoutfn
272 # print pin, pin.outenmode
273 if pin.outenmode:
274 decfn = self.ifacefmtdecfn3
275 outfn = self.ifacefmtoutenfn
276 return pin.ifacedef(outfn, self.ifacefmtinfn,
277 decfn)
278
279 def ifacedef(self, *args):
280 res = '\n'.join(map(self.ifacefmtpin, self.pins))
281 res = res.format(*args)
282 return '\n' + res + '\n'
283
284
285 class MuxInterface(Interface):
286
287 def wirefmt(self, *args):
288 return muxwire.format(*args)
289
290
291 class IOInterface(Interface):
292
293 def ifacefmtoutenfn(self, name):
294 return "cell{0}_mux_outen"
295
296 def ifacefmtoutfn(self, name):
297 """ for now strip off io{0}_ part """
298 return "cell{0}_mux_out"
299
300 def ifacefmtinfn(self, name):
301 return "cell{0}_mux_in"
302
303 def wirefmt(self, *args):
304 return generic_io.format(*args)
305
306
307 class Interfaces(InterfacesBase, PeripheralInterfaces):
308 """ contains a list of interface definitions
309 """
310
311 def __init__(self, pth=None):
312 InterfacesBase.__init__(self, Interface, pth)
313 PeripheralInterfaces.__init__(self)
314
315 def ifacedef(self, f, *args):
316 for (name, count) in self.ifacecount:
317 for i in range(count):
318 f.write(self.data[name].ifacedef(i))
319
320 def busfmt(self, f, *args):
321 f.write("import BUtils::*;\n\n")
322 for (name, count) in self.ifacecount:
323 for i in range(count):
324 bf = self.data[name].busfmt(i)
325 f.write(bf)
326
327 def ifacepfmt(self, f, *args):
328 comment = '''
329 // interface declaration between {0} and pinmux
330 (*always_ready,always_enabled*)
331 interface PeripheralSide{0};'''
332 for (name, count) in self.ifacecount:
333 f.write(comment.format(name.upper()))
334 f.write(self.data[name].ifacepfmt(0))
335 f.write("\n endinterface\n")
336
337 def ifacefmt(self, f, *args):
338 comment = '''
339 // interface declaration between %s-{0} and pinmux'''
340 for (name, count) in self.ifacecount:
341 for i in range(count):
342 c = comment % name.upper()
343 f.write(c.format(i))
344 f.write(self.data[name].ifacefmt(i))
345
346 def wirefmt(self, f, *args):
347 comment = '\n // following wires capture signals ' \
348 'to IO CELL if %s-{0} is\n' \
349 ' // allotted to it'
350 for (name, count) in self.ifacecount:
351 for i in range(count):
352 c = comment % name
353 f.write(c.format(i))
354 f.write(self.data[name].wirefmt(i))
355
356
357 # ========= Interface declarations ================ #
358
359 mux_interface = MuxInterface('cell',
360 [{'name': 'mux', 'ready': False, 'enabled': False,
361 'bitspec': '{1}', 'action': True}])
362
363 io_interface = IOInterface(
364 'io',
365 [{'name': 'cell_out', 'enabled': True, },
366 {'name': 'cell_outen', 'enabled': True, 'outenmode': True, },
367 {'name': 'cell_in', 'action': True, 'io': True}, ])
368
369 # == Peripheral Interface definitions == #
370 # these are the interface of the peripherals to the pin mux
371 # Outputs from the peripherals will be inputs to the pinmux
372 # module. Hence the change in direction for most pins
373
374 # ======================================= #
375
376 # basic test
377 if __name__ == '__main__':
378
379 uartinterface_decl = Interface('uart',
380 [{'name': 'rx'},
381 {'name': 'tx', 'action': True},
382 ])
383
384 twiinterface_decl = Interface('twi',
385 [{'name': 'sda', 'outen': True},
386 {'name': 'scl', 'outen': True},
387 ])
388
389 def _pinmunge(p, sep, repl, dedupe=True):
390 """ munges the text so it's easier to compare.
391 splits by separator, strips out blanks, re-joins.
392 """
393 p = p.strip()
394 p = p.split(sep)
395 if dedupe:
396 p = filter(lambda x: x, p) # filter out blanks
397 return repl.join(p)
398
399 def pinmunge(p):
400 """ munges the text so it's easier to compare.
401 """
402 # first join lines by semicolons, strip out returns
403 p = p.split(";")
404 p = map(lambda x: x.replace('\n', ''), p)
405 p = '\n'.join(p)
406 # now split first by brackets, then spaces (deduping on spaces)
407 p = _pinmunge(p, "(", " ( ", False)
408 p = _pinmunge(p, ")", " ) ", False)
409 p = _pinmunge(p, " ", " ")
410 return p
411
412 def zipcmp(l1, l2):
413 l1 = l1.split("\n")
414 l2 = l2.split("\n")
415 for p1, p2 in zip(l1, l2):
416 print (repr(p1))
417 print (repr(p2))
418 print ()
419 assert p1 == p2
420
421 ifaces = Interfaces()
422
423 ifaceuart = ifaces['uart']
424 print (ifaceuart.ifacedef(0))
425 print (uartinterface_decl.ifacedef(0))
426 assert ifaceuart.ifacedef(0) == uartinterface_decl.ifacedef(0)
427
428 ifacetwi = ifaces['twi']
429 print (ifacetwi.ifacedef(0))
430 print (twiinterface_decl.ifacedef(0))
431 assert ifacetwi.ifacedef(0) == twiinterface_decl.ifacedef(0)