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