establish clocks of each function in a pinspec clocks dictionary
[pinmux.git] / src / spec / interfaces.py
1 #!/usr/bin/env python
2
3 from spec.pinfunctions import pinspec
4 from copy import deepcopy
5
6
7 def namesuffix(name, suffix, namelist):
8 names = []
9 for n in namelist:
10 if n:
11 names.append("%s%s_%s" % (name, suffix, n))
12 else:
13 names.append("%s_%s" % (name, suffix))
14 return names
15
16
17 class PinGen(object):
18 """ a meta-helper which creates pins from the pinspec
19 and adds them to the pinouts.
20
21 __call__ is used to effectively create a lambda function, which
22 in combination with setattr (below) gives the function a name
23 in the Pinouts class, according to the pinspec.
24
25 arguments to __call__ (which ends up as Pinouts.i2s, Pinouts.sdmmc
26 and so on, according to spec.pinfunctions.pinspec) are:
27
28 suffix: e.g. GPIO or SD or SPI
29 offs : a tuple of (Bank, Bank offset) as a string, integer
30 mux : which column in the multiplexer
31 start : the start of a subset of pins to be inserted
32 limit : the end of the subset (or the number if start also given)
33 spec : *EXTRA* pins to be inserted (at different implicit positions)
34
35 the pins are inserted with the suffix, starting from the
36 offset position using offs as the row and mux as the column,
37 and working in a constant increment down the rows.
38
39 spec is slightly complicated, basically there's extra
40 functions that we want to be on the same pin (but a different mux)
41 because their use is mutually-exclusive. without this spec
42 argument the extra pins would need to be MANUALLY moved about
43 during the development of the pinmux, if the "main" pins
44 were also moved about. this would be a pain.
45
46 so instead, extra pins are given of the form:
47 { 'EXTRA1' : ('PREEXISTING_NAME', MUX_COLUMN),
48 ...
49 }
50
51 where the function EXTRA1 will always be placed on the SAME ROW
52 as PREEXISTING_NAME, just in MUX_COLUMN. this may be done
53 several times i.e. multiple new EXTRA functions can be added
54 on the same row as PRE_EXISTING_NAME, just with different
55 MUX_COLUMN values.
56
57 Note: spec must implicitly be in the same Bank.
58 """
59
60 def __init__(self, pinouts, fname, pinfn, bankspec):
61 self.pinouts = pinouts
62 self.bankspec = bankspec
63 self.pinfn = pinfn
64 self.fname = fname
65
66 def __call__(self, suffix, offs, mux,
67 start=None, limit=None, spec=None, origsuffix=None):
68 bank = offs[0]
69 pf = self.pinfn(suffix, bank)
70 print "pf", suffix, bank, pf
71 pingroup, gangedgroup, clock = pf
72 if clock:
73 self.pinouts.clocks[self.fname] = clock
74 if isinstance(pingroup, tuple):
75 prefix, pingroup = pingroup
76 else:
77 prefix = self.fname
78 if start and limit: # limit turns into an offset from start
79 limit = start + limit
80 pingroup = pingroup[start:limit] # see comment in spec.pinfunctions
81 pins = Pins(prefix, pingroup, self.bankspec,
82 suffix, offs, bank, mux,
83 spec, origsuffix=suffix, gangedgrp=gangedgroup)
84 fname = self.pinouts.pinmerge(pins)
85 self.pinouts.setganged(fname, gangedgroup)
86
87 # pinouts class
88
89
90 class Pinouts(object):
91 def __init__(self, bankspec):
92 self.bankspec = bankspec
93 self.pins = {}
94 self.fnspec = {}
95 self.ganged = {}
96 self.clocks = {}
97 for fname, pinfn in pinspec:
98 if isinstance(pinfn, tuple):
99 name, pinfn = pinfn
100 else:
101 name = pinfn.__name__
102 pin = PinGen(self, fname, pinfn, self.bankspec)
103 setattr(self, name, pin)
104
105 def setganged(self, fname, grp):
106 grp = map(lambda x: x[:-1], grp)
107 if fname not in self.ganged:
108 self.ganged[fname] = []
109 self.ganged[fname] += grp
110
111 def __contains__(self, k):
112 return k in self.pins
113
114 def has_key(self, k):
115 return k in self.pins
116
117 def add_spec(self, k, v):
118 self.fnspec[k] = v
119
120 def update(self, pinidx, v):
121 if pinidx not in self.pins:
122 self.pins[pinidx] = v
123 else:
124 for k in v:
125 assert k not in self.pins[pinidx], \
126 "pin %d position %d already taken\n%s\n%s" % \
127 (pinidx, k, str(v), self.pins[pinidx])
128 self.pins[pinidx].update(v)
129
130 def keys(self):
131 return self.pins.keys()
132
133 def items(self):
134 return self.pins.items()
135
136 def get(self, k):
137 return self.pins[k]
138
139 def __len__(self):
140 return len(self.pins)
141
142 def __delitem__(self, k):
143 del self.pins[k]
144
145 def __getitem__(self, k):
146 return self.pins[k]
147
148 def pinmerge(self, fn):
149 # hack, store the function specs in the pins dict
150 fname = fn.fname
151 suffix = fn.origsuffix
152 bank = fn.bank
153
154 if not hasattr(self, 'fnspec'):
155 self.fnspec = pins
156 if fname == 'GPIO':
157 fname = fname + bank
158 assert 'EINT' not in self
159 if fname not in self.fnspec:
160 self.add_spec(fname, {})
161 if suffix or fname == 'EINT' or fname == 'PWM':
162 specname = fname + suffix
163 else:
164 specname = fname
165 # print "fname bank specname suffix ", fname, bank, specname, repr(
166 # suffix)
167 if specname in self.fnspec[fname]:
168 # ok so some declarations may bring in different
169 # names at different stages (EINT, PWM, flexbus1/2)
170 # so we have to merge the names in. main thing is
171 # the pingroup
172 tomerge = self.fnspec[fname][specname]
173 for p in fn.pingroup:
174 if p not in tomerge.pingroup:
175 tomerge.pingroup.append(p)
176 tomerge.pins.update(fn.pins)
177 tomerge.fntype.update(fn.fntype)
178 else:
179 self.fnspec[fname][specname] = deepcopy(fn)
180
181 # merge actual pins
182 for (pinidx, v) in fn.pins.items():
183 self.update(pinidx, v)
184
185 return fname
186
187
188 class Pins(object):
189
190 def __init__(self, fname, pingroup, bankspec, suffix, offs, bank, mux,
191 spec=None, limit=None, origsuffix=None, gangedgrp=None):
192
193 # function type can be in, out or inout, represented by - + *
194 # strip function type out of each pin name
195 self.fntype = {}
196 for i in range(len(pingroup)):
197 pname = pingroup[i]
198 if not pname:
199 continue
200 fntype = pname[-1]
201 if fntype not in '+-*':
202 continue
203 pname = pname[:-1]
204 fntype = {'-': 'in', '+': 'out', '*': 'inout'}[fntype]
205 self.fntype[pname] = fntype
206 pingroup[i] = pname
207
208 self.fname = fname
209 self.pingroup = pingroup
210 self.gangedgroup = gangedgrp
211 self.bankspec = bankspec
212 self.suffix = suffix
213 self.origsuffix = origsuffix or suffix
214 self.bank = bank
215 self.mux = mux
216
217 # create consistent name suffixes
218 pingroup = namesuffix(fname, suffix, pingroup)
219 suffix = '' # hack
220
221 res = {}
222 names = {}
223 idx = 0
224 for name in pingroup[:limit]:
225 if suffix and name:
226 name_ = "%s_%s" % (name, suffix)
227 else:
228 name_ = name
229 if spec and name in spec:
230 continue
231 pin = {mux: (name_, bank)}
232 offs_bank, offs_ = offs
233 idx_ = offs_ + idx
234 idx += 1
235 idx_ += bankspec[bank]
236 res[idx_] = pin
237 names[name] = idx_
238 for name in pingroup:
239 if suffix and name:
240 name_ = "%s_%s" % (name, suffix)
241 else:
242 name_ = name
243 if not spec:
244 continue
245 if name not in spec:
246 continue
247 idx_, mux_ = spec[name]
248 idx_ = names[idx_]
249 pin = {mux_: (name_, bank)}
250 if idx_ in res:
251 res[idx_].update(pin)
252 else:
253 res[idx_] = pin
254
255 self.pins = res