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