remove pullup and other pad characteristics as theyre handled by the GPIO mod
[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):
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, fmtinfn, fmtdecfn):
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, fmtinfn, fmtdecfn):
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, ganged=None, single=False):
91 self.ifacename = ifacename
92 self.ganged = ganged or {}
93 self.pins = []
94 self.pinspecs = pinspecs
95 self.single = single
96 for p in pinspecs:
97 _p = {}
98 _p.update(p)
99 if p.get('outen') is True: # special case, generate 3 pins
100 del _p['outen']
101 for psuffix in ['out', 'outen', 'in']:
102 _p['name'] = "%s_%s" % (self.pname(p['name']), psuffix)
103 _p['action'] = psuffix != 'in'
104 self.pins.append(Pin(**_p))
105 else:
106 _p['name'] = self.pname(p['name'])
107 self.pins.append(Pin(**_p))
108
109 def getifacetype(self, name):
110 for p in self.pinspecs:
111 fname = "%s_%s" % (self.ifacename, p['name'])
112 #print "search", self.ifacename, name, fname
113 if fname == name:
114 if p.get('action'):
115 return 'out'
116 elif p.get('outen'):
117 return 'inout'
118 return 'input'
119 return None
120
121 def pname(self, name):
122 """ generates the interface spec e.g. flexbus_ale
123 if there is only one flexbus interface, or
124 sd{0}_cmd if there are several. string format
125 function turns this into sd0_cmd, sd1_cmd as
126 appropriate. single mode stops the numerical extension.
127 """
128 if self.single:
129 return '%s_%s' % (self.ifacename, name)
130 return '%s{0}_%s' % (self.ifacename, name)
131
132 def busfmt(self, *args):
133 """ this function creates a bus "ganging" system based
134 on input from the {interfacename}.txt file.
135 only inout pins that are under the control of the
136 interface may be "ganged" together.
137 """
138 if not self.ganged:
139 return ''
140 #print self.ganged
141 res = []
142 for (k, pnames) in self.ganged.items():
143 name = self.pname('%senable' % k).format(*args)
144 decl = 'Bit#(1) %s = 0;' % name
145 res.append(decl)
146 ganged = []
147 for p in self.pinspecs:
148 if p['name'] not in pnames:
149 continue
150 pname = self.pname(p['name']).format(*args)
151 if p.get('outen') is True:
152 outname = self.ifacefmtoutfn(pname)
153 ganged.append("%s_outen" % outname) # match wirefmt
154
155 gangedfmt = '{%s} = duplicate(%s);'
156 res.append(gangedfmt % (',\n '.join(ganged), name))
157 return '\n'.join(res) + '\n\n'
158
159 def wirefmt(self, *args):
160 res = '\n'.join(map(self.wirefmtpin, self.pins)).format(*args)
161 res += '\n'
162 for p in self.pinspecs:
163 name = self.pname(p['name'])
164 typ = self.getifacetype(name.format(""))
165 name = name.format(*args)
166 res += " # declare %s_io, set up as type '%s'\n" % (name, typ)
167 res += " GenericIOType %s_io = GenericIOType{\n" % name
168 params = []
169 if typ == 'inout':
170 outname = self.ifacefmtoutfn(name)
171 params.append('outputval:%s_out,' % outname)
172 params.append('output_en:%s_outen,' % outname) # match busfmt
173 params.append('input_en:~%s_outen,' % outname)
174 elif typ == 'out':
175 outname = self.ifacefmtoutfn(name)
176 params.append('outputval:%s,' % outname)
177 params.append('output_en:1,')
178 params.append('input_en:0,')
179 else: # input
180 params.append('outputval:0,')
181 params.append('output_en:0,')
182 params.append('input_en:1,')
183 res += ' };\n'
184 return '\n' + res
185
186 def ifacefmt(self, *args):
187 res = '\n'.join(map(self.ifacefmtdecpin, self.pins)).format(*args)
188 return '\n' + res
189
190 def ifacefmtdecfn(self, name):
191 return name
192
193 def ifacefmtdecfn2(self, name):
194 return name
195
196 def ifacefmtoutfn(self, name):
197 return "wr%s" % name
198
199 def ifacefmtinfn(self, name):
200 return "wr%s" % name
201
202 def wirefmtpin(self, pin):
203 return pin.wirefmt(self.ifacefmtoutfn, self.ifacefmtinfn,
204 self.ifacefmtdecfn2)
205
206 def ifacefmtdecpin(self, pin):
207 return pin.ifacefmt(self.ifacefmtdecfn)
208
209 def ifacefmtpin(self, pin):
210 return pin.ifacedef(self.ifacefmtoutfn, self.ifacefmtinfn,
211 self.ifacefmtdecfn2)
212
213 def ifacedef(self, *args):
214 res = '\n'.join(map(self.ifacefmtpin, self.pins))
215 res = res.format(*args)
216 return '\n' + res + '\n'
217
218
219 class MuxInterface(Interface):
220
221 def wirefmt(self, *args):
222 return muxwire.format(*args)
223
224
225 class IOInterface(Interface):
226
227 def ifacefmtoutfn(self, name):
228 """ for now strip off io{0}_ part """
229 return "cell{0}_mux_out"
230
231 def ifacefmtinfn(self, name):
232 return "cell{0}_mux_in"
233
234 def wirefmt(self, *args):
235 return generic_io.format(*args)
236
237
238 class Interfaces(UserDict):
239 """ contains a list of interface definitions
240 """
241
242 def __init__(self, pth):
243 self.pth = pth
244 self.ifacecount = []
245 UserDict.__init__(self, {})
246 ift = 'interfaces.txt'
247 if pth:
248 ift = os.path.join(pth, ift)
249 with open(ift, 'r') as ifile:
250 for ln in ifile.readlines():
251 ln = ln.strip()
252 ln = ln.split("\t")
253 name = ln[0]
254 count = int(ln[1])
255 spec, ganged = self.read_spec(pth, name)
256 iface = Interface(name, spec, ganged, count == 1)
257 self.ifaceadd(name, count, iface)
258
259 def getifacetype(self, fname):
260 # finds the interface type, e.g sd_d0 returns "inout"
261 for iface in self.values():
262 typ = iface.getifacetype(fname)
263 if typ:
264 return typ
265 return None
266
267 def ifaceadd(self, name, count, iface, at=None):
268 if at is None:
269 at = len(self.ifacecount)
270 self.ifacecount.insert(at, (name, count))
271 self[name] = iface
272
273 def read_spec(self, pth, name):
274 spec = []
275 ganged = {}
276 fname = '%s.txt' % name
277 if pth:
278 ift = os.path.join(pth, fname)
279 with open(ift, 'r') as sfile:
280 for ln in sfile.readlines():
281 ln = ln.strip()
282 ln = ln.split("\t")
283 name = ln[0]
284 d = {'name': name}
285 if ln[1] == 'out':
286 d['action'] = True
287 elif ln[1] == 'inout':
288 d['outen'] = True
289 if len(ln) == 3:
290 bus = ln[2]
291 if bus not in ganged:
292 ganged[bus] = []
293 ganged[bus].append(name)
294 spec.append(d)
295 return spec, ganged
296
297 def ifacedef(self, f, *args):
298 for (name, count) in self.ifacecount:
299 for i in range(count):
300 f.write(self.data[name].ifacedef(i))
301
302 def busfmt(self, f, *args):
303 f.write("import BUtils::*;\n\n")
304 for (name, count) in self.ifacecount:
305 for i in range(count):
306 bf = self.data[name].busfmt(i)
307 f.write(bf)
308
309 def ifacefmt(self, f, *args):
310 comment = '''
311 // interface declaration between %s-{0} and pinmux'''
312 for (name, count) in self.ifacecount:
313 for i in range(count):
314 c = comment % name.upper()
315 f.write(c.format(i))
316 f.write(self.data[name].ifacefmt(i))
317
318 def wirefmt(self, f, *args):
319 comment = '\n // following wires capture signals ' \
320 'to IO CELL if %s-{0} is\n' \
321 ' // allotted to it'
322 for (name, count) in self.ifacecount:
323 for i in range(count):
324 c = comment % name
325 f.write(c.format(i))
326 f.write(self.data[name].wirefmt(i))
327
328
329 # ========= Interface declarations ================ #
330
331 mux_interface = MuxInterface('cell', [{'name': 'mux', 'ready': False,
332 'enabled': False,
333 'bitspec': '{1}', 'action': True}])
334
335 io_interface = IOInterface(
336 'io',
337 [{'name': 'cell', 'enabled': False, 'bitspec': 'GenericIOType'},
338 {'name': 'inputval', 'action': True, 'io': True}, ])
339
340 # == Peripheral Interface definitions == #
341 # these are the interface of the peripherals to the pin mux
342 # Outputs from the peripherals will be inputs to the pinmux
343 # module. Hence the change in direction for most pins
344
345 # ======================================= #
346
347 # basic test
348 if __name__ == '__main__':
349
350 uartinterface_decl = Interface('uart',
351 [{'name': 'rx'},
352 {'name': 'tx', 'action': True},
353 ])
354
355 twiinterface_decl = Interface('twi',
356 [{'name': 'sda', 'outen': True},
357 {'name': 'scl', 'outen': True},
358 ])
359
360 def _pinmunge(p, sep, repl, dedupe=True):
361 """ munges the text so it's easier to compare.
362 splits by separator, strips out blanks, re-joins.
363 """
364 p = p.strip()
365 p = p.split(sep)
366 if dedupe:
367 p = filter(lambda x: x, p) # filter out blanks
368 return repl.join(p)
369
370 def pinmunge(p):
371 """ munges the text so it's easier to compare.
372 """
373 # first join lines by semicolons, strip out returns
374 p = p.split(";")
375 p = map(lambda x: x.replace('\n', ''), p)
376 p = '\n'.join(p)
377 # now split first by brackets, then spaces (deduping on spaces)
378 p = _pinmunge(p, "(", " ( ", False)
379 p = _pinmunge(p, ")", " ) ", False)
380 p = _pinmunge(p, " ", " ")
381 return p
382
383 def zipcmp(l1, l2):
384 l1 = l1.split("\n")
385 l2 = l2.split("\n")
386 for p1, p2 in zip(l1, l2):
387 print (repr(p1))
388 print (repr(p2))
389 print ()
390 assert p1 == p2
391
392 ifaces = Interfaces()
393
394 ifaceuart = ifaces['uart']
395 print (ifaceuart.ifacedef(0))
396 print (uartinterface_decl.ifacedef(0))
397 assert ifaceuart.ifacedef(0) == uartinterface_decl.ifacedef(0)
398
399 ifacetwi = ifaces['twi']
400 print (ifacetwi.ifacedef(0))
401 print (twiinterface_decl.ifacedef(0))
402 assert ifacetwi.ifacedef(0) == twiinterface_decl.ifacedef(0)