split out iocells to separate interface, just makes more sense
[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
166 def ifacefmt(self, *args):
167 res = '\n'.join(map(self.ifacefmtdecpin, self.pins)).format(*args)
168 return '\n' + res
169
170 def ifacefmtdecfn(self, name):
171 return name
172
173 def ifacefmtdecfn2(self, name):
174 return name
175
176 def ifacefmtdecfn3(self, name):
177 """ HACK! """
178 return "%s_outenX" % name
179
180 def ifacefmtoutfn(self, name):
181 return "wr%s" % name
182
183 def ifacefmtinfn(self, name):
184 return "wr%s" % name
185
186 def wirefmtpin(self, pin):
187 return pin.wirefmt(self.ifacefmtoutfn, self.ifacefmtinfn,
188 self.ifacefmtdecfn2)
189
190 def ifacefmtdecpin(self, pin):
191 return pin.ifacefmt(self.ifacefmtdecfn)
192
193 def ifacefmtpin(self, pin):
194 decfn = self.ifacefmtdecfn2
195 outfn = self.ifacefmtoutfn
196 print pin, pin.outenmode
197 if pin.outenmode:
198 decfn = self.ifacefmtdecfn3
199 outfn = self.ifacefmtoutenfn
200 return pin.ifacedef(outfn, self.ifacefmtinfn,
201 decfn)
202
203 def ifacedef(self, *args):
204 res = '\n'.join(map(self.ifacefmtpin, self.pins))
205 res = res.format(*args)
206 return '\n' + res + '\n'
207
208
209 class MuxInterface(Interface):
210
211 def wirefmt(self, *args):
212 return muxwire.format(*args)
213
214
215 class IOInterface(Interface):
216
217 def ifacefmtoutenfn(self, name):
218 return "cell{0}_mux_outen"
219
220 def ifacefmtoutfn(self, name):
221 """ for now strip off io{0}_ part """
222 return "cell{0}_mux_out"
223
224 def ifacefmtinfn(self, name):
225 return "cell{0}_mux_in"
226
227 def wirefmt(self, *args):
228 return generic_io.format(*args)
229
230
231 class Interfaces(UserDict):
232 """ contains a list of interface definitions
233 """
234
235 def __init__(self, pth=None):
236 self.pth = pth
237 self.ifacecount = []
238 UserDict.__init__(self, {})
239 if not pth:
240 return
241 ift = 'interfaces.txt'
242 if pth:
243 ift = os.path.join(pth, ift)
244 with open(ift, 'r') as ifile:
245 for ln in ifile.readlines():
246 ln = ln.strip()
247 ln = ln.split("\t")
248 name = ln[0]
249 count = int(ln[1])
250 spec, ganged = self.read_spec(pth, name)
251 iface = Interface(name, spec, ganged, count == 1)
252 self.ifaceadd(name, count, iface)
253
254 def getifacetype(self, fname):
255 # finds the interface type, e.g sd_d0 returns "inout"
256 for iface in self.values():
257 typ = iface.getifacetype(fname)
258 if typ:
259 return typ
260 return None
261
262 def ifaceadd(self, name, count, iface, at=None):
263 if at is None:
264 at = len(self.ifacecount)
265 self.ifacecount.insert(at, (name, count))
266 self[name] = iface
267
268 def read_spec(self, pth, name):
269 spec = []
270 ganged = {}
271 fname = '%s.txt' % name
272 if pth:
273 ift = os.path.join(pth, fname)
274 with open(ift, 'r') as sfile:
275 for ln in sfile.readlines():
276 ln = ln.strip()
277 ln = ln.split("\t")
278 name = ln[0]
279 d = {'name': name}
280 if ln[1] == 'out':
281 d['action'] = True
282 elif ln[1] == 'inout':
283 d['outen'] = True
284 if len(ln) == 3:
285 bus = ln[2]
286 if bus not in ganged:
287 ganged[bus] = []
288 ganged[bus].append(name)
289 spec.append(d)
290 return spec, ganged
291
292 def ifacedef(self, f, *args):
293 for (name, count) in self.ifacecount:
294 for i in range(count):
295 f.write(self.data[name].ifacedef(i))
296
297 def busfmt(self, f, *args):
298 f.write("import BUtils::*;\n\n")
299 for (name, count) in self.ifacecount:
300 for i in range(count):
301 bf = self.data[name].busfmt(i)
302 f.write(bf)
303
304 def ifacefmt(self, f, *args):
305 comment = '''
306 // interface declaration between %s-{0} and pinmux'''
307 for (name, count) in self.ifacecount:
308 for i in range(count):
309 c = comment % name.upper()
310 f.write(c.format(i))
311 f.write(self.data[name].ifacefmt(i))
312
313 def wirefmt(self, f, *args):
314 comment = '\n // following wires capture signals ' \
315 'to IO CELL if %s-{0} is\n' \
316 ' // allotted to it'
317 for (name, count) in self.ifacecount:
318 for i in range(count):
319 c = comment % name
320 f.write(c.format(i))
321 f.write(self.data[name].wirefmt(i))
322
323
324 # ========= Interface declarations ================ #
325
326 mux_interface = MuxInterface('cell', [{'name': 'mux', 'ready': False,
327 'enabled': False,
328 'bitspec': '{1}', 'action': True}])
329
330 io_interface = IOInterface(
331 'io',
332 [{'name': 'cell_out', 'enabled': True, },
333 {'name': 'cell_outen', 'enabled': True, 'outenmode': True, },
334 {'name': 'cell_in', 'action': True, 'io': True}, ])
335
336 # == Peripheral Interface definitions == #
337 # these are the interface of the peripherals to the pin mux
338 # Outputs from the peripherals will be inputs to the pinmux
339 # module. Hence the change in direction for most pins
340
341 # ======================================= #
342
343 # basic test
344 if __name__ == '__main__':
345
346 uartinterface_decl = Interface('uart',
347 [{'name': 'rx'},
348 {'name': 'tx', 'action': True},
349 ])
350
351 twiinterface_decl = Interface('twi',
352 [{'name': 'sda', 'outen': True},
353 {'name': 'scl', 'outen': True},
354 ])
355
356 def _pinmunge(p, sep, repl, dedupe=True):
357 """ munges the text so it's easier to compare.
358 splits by separator, strips out blanks, re-joins.
359 """
360 p = p.strip()
361 p = p.split(sep)
362 if dedupe:
363 p = filter(lambda x: x, p) # filter out blanks
364 return repl.join(p)
365
366 def pinmunge(p):
367 """ munges the text so it's easier to compare.
368 """
369 # first join lines by semicolons, strip out returns
370 p = p.split(";")
371 p = map(lambda x: x.replace('\n', ''), p)
372 p = '\n'.join(p)
373 # now split first by brackets, then spaces (deduping on spaces)
374 p = _pinmunge(p, "(", " ( ", False)
375 p = _pinmunge(p, ")", " ) ", False)
376 p = _pinmunge(p, " ", " ")
377 return p
378
379 def zipcmp(l1, l2):
380 l1 = l1.split("\n")
381 l2 = l2.split("\n")
382 for p1, p2 in zip(l1, l2):
383 print (repr(p1))
384 print (repr(p2))
385 print ()
386 assert p1 == p2
387
388 ifaces = Interfaces()
389
390 ifaceuart = ifaces['uart']
391 print (ifaceuart.ifacedef(0))
392 print (uartinterface_decl.ifacedef(0))
393 assert ifaceuart.ifacedef(0) == uartinterface_decl.ifacedef(0)
394
395 ifacetwi = ifaces['twi']
396 print (ifacetwi.ifacedef(0))
397 print (twiinterface_decl.ifacedef(0))
398 assert ifacetwi.ifacedef(0) == twiinterface_decl.ifacedef(0)