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