add axi fn_address_mapping
[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 def axi_addr_map(self, count):
283 if not self.slow:
284 return ''
285 return self.slow.axi_addr_map(self.ifacename, count)
286
287
288 class MuxInterface(Interface):
289
290 def wirefmt(self, *args):
291 return muxwire.format(*args)
292
293
294 class IOInterface(Interface):
295
296 def ifacefmtoutenfn(self, name):
297 return "cell{0}_mux_outen"
298
299 def ifacefmtoutfn(self, name):
300 """ for now strip off io{0}_ part """
301 return "cell{0}_mux_out"
302
303 def ifacefmtinfn(self, name):
304 return "cell{0}_mux_in"
305
306 def wirefmt(self, *args):
307 return generic_io.format(*args)
308
309
310 class Interfaces(InterfacesBase):
311 """ contains a list of interface definitions
312 """
313
314 def __init__(self, pth=None):
315 InterfacesBase.__init__(self, Interface, pth)
316
317 def ifacedef(self, f, *args):
318 for (name, count) in self.ifacecount:
319 for i in range(count):
320 f.write(self.data[name].ifacedef(i))
321
322 def busfmt(self, f, *args):
323 f.write("import BUtils::*;\n\n")
324 for (name, count) in self.ifacecount:
325 for i in range(count):
326 bf = self.data[name].busfmt(i)
327 f.write(bf)
328
329 def ifacefmt(self, f, *args):
330 comment = '''
331 // interface declaration between %s-{0} and pinmux'''
332 for (name, count) in self.ifacecount:
333 for i in range(count):
334 c = comment % name.upper()
335 f.write(c.format(i))
336 f.write(self.data[name].ifacefmt(i))
337
338 def wirefmt(self, f, *args):
339 comment = '\n // following wires capture signals ' \
340 'to IO CELL if %s-{0} is\n' \
341 ' // allotted to it'
342 for (name, count) in self.ifacecount:
343 for i in range(count):
344 c = comment % name
345 f.write(c.format(i))
346 f.write(self.data[name].wirefmt(i))
347
348 def slowimport(self, *args):
349 ret = []
350 for (name, count) in self.ifacecount:
351 ret.append(self.data[name].slowimport())
352 return '\n'.join(list(filter(None, ret)))
353
354 def slowifdecl(self, *args):
355 ret = []
356 for (name, count) in self.ifacecount:
357 for i in range(count):
358 ret.append(self.data[name].slowifdecl(i))
359 return '\n'.join(list(filter(None, ret)))
360
361 def axi_reg_def(self, *args):
362 ret = []
363 start = 0x00011100 # start of AXI peripherals address
364 for (name, count) in self.ifacecount:
365 for i in range(count):
366 x = self.data[name].axi_reg_def(start, i)
367 print ("ifc", name, x)
368 (rdef, offs) = x
369 ret.append(rdef)
370 start += offs
371 return '\n'.join(list(filter(None, ret)))
372
373 def axi_slave_idx(self, *args):
374 ret = []
375 start = 0
376 for (name, count) in self.ifacecount:
377 for i in range(count):
378 (rdef, offs) = self.data[name].axi_slave_idx(start, i)
379 print ("ifc", name, rdef, offs)
380 ret.append(rdef)
381 start += offs
382 ret.append("typedef %d LastGen_slave_num" % (start - 1))
383 decls = '\n'.join(list(filter(None, ret)))
384 return axi_slave_declarations.format(decls)
385
386 def axi_addr_map(self, *args):
387 ret = []
388 for (name, count) in self.ifacecount:
389 for i in range(count):
390 ret.append(self.data[name].axi_addr_map(i))
391 return '\n'.join(list(filter(None, ret)))
392
393
394 # ========= Interface declarations ================ #
395
396 mux_interface = MuxInterface('cell',
397 [{'name': 'mux', 'ready': False, 'enabled': False,
398 'bitspec': '{1}', 'action': True}])
399
400 io_interface = IOInterface(
401 'io',
402 [{'name': 'cell_out', 'enabled': True, },
403 {'name': 'cell_outen', 'enabled': True, 'outenmode': True, },
404 {'name': 'cell_in', 'action': True, 'io': True}, ])
405
406 # == Peripheral Interface definitions == #
407 # these are the interface of the peripherals to the pin mux
408 # Outputs from the peripherals will be inputs to the pinmux
409 # module. Hence the change in direction for most pins
410
411 # ======================================= #
412
413 # basic test
414 if __name__ == '__main__':
415
416 uartinterface_decl = Interface('uart',
417 [{'name': 'rx'},
418 {'name': 'tx', 'action': True},
419 ])
420
421 twiinterface_decl = Interface('twi',
422 [{'name': 'sda', 'outen': True},
423 {'name': 'scl', 'outen': True},
424 ])
425
426 def _pinmunge(p, sep, repl, dedupe=True):
427 """ munges the text so it's easier to compare.
428 splits by separator, strips out blanks, re-joins.
429 """
430 p = p.strip()
431 p = p.split(sep)
432 if dedupe:
433 p = filter(lambda x: x, p) # filter out blanks
434 return repl.join(p)
435
436 def pinmunge(p):
437 """ munges the text so it's easier to compare.
438 """
439 # first join lines by semicolons, strip out returns
440 p = p.split(";")
441 p = map(lambda x: x.replace('\n', ''), p)
442 p = '\n'.join(p)
443 # now split first by brackets, then spaces (deduping on spaces)
444 p = _pinmunge(p, "(", " ( ", False)
445 p = _pinmunge(p, ")", " ) ", False)
446 p = _pinmunge(p, " ", " ")
447 return p
448
449 def zipcmp(l1, l2):
450 l1 = l1.split("\n")
451 l2 = l2.split("\n")
452 for p1, p2 in zip(l1, l2):
453 print (repr(p1))
454 print (repr(p2))
455 print ()
456 assert p1 == p2
457
458 ifaces = Interfaces()
459
460 ifaceuart = ifaces['uart']
461 print (ifaceuart.ifacedef(0))
462 print (uartinterface_decl.ifacedef(0))
463 assert ifaceuart.ifacedef(0) == uartinterface_decl.ifacedef(0)
464
465 ifacetwi = ifaces['twi']
466 print (ifacetwi.ifacedef(0))
467 print (twiinterface_decl.ifacedef(0))
468 assert ifacetwi.ifacedef(0) == twiinterface_decl.ifacedef(0)