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