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