add copying jtag files
[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 pingroup, gangedgroup = self.pinfn(suffix, bank)
70 if isinstance(pingroup, tuple):
71 prefix, pingroup = pingroup
72 else:
73 prefix = self.fname
74 if start and limit: # limit turns into an offset from start
75 limit = start + limit
76 pingroup = pingroup[start:limit] # see comment in spec.pinfunctions
77 pins = Pins(prefix, pingroup, self.bankspec,
78 suffix, offs, bank, mux,
79 spec, origsuffix=suffix, gangedgrp=gangedgroup)
80 fname = self.pinouts.pinmerge(pins)
81 self.pinouts.setganged(fname, gangedgroup)
82
83 # pinouts class
84
85
86 class Pinouts(object):
87 def __init__(self, bankspec):
88 self.bankspec = bankspec
89 self.pins = {}
90 self.fnspec = {}
91 self.ganged = {}
92 for fname, pinfn in pinspec:
93 if isinstance(pinfn, tuple):
94 name, pinfn = pinfn
95 else:
96 name = pinfn.__name__
97 setattr(self, name, PinGen(self, fname, pinfn, self.bankspec))
98
99 def setganged(self, fname, grp):
100 self.ganged[fname] = map(lambda x: x[:-1], grp)
101
102 def __contains__(self, k):
103 return k in self.pins
104
105 def has_key(self, k):
106 return k in self.pins
107
108 def add_spec(self, k, v):
109 self.fnspec[k] = v
110
111 def update(self, pinidx, v):
112 if pinidx not in self.pins:
113 self.pins[pinidx] = v
114 else:
115 for k in v:
116 assert k not in self.pins[pinidx], \
117 "pin %d position %d already taken\n%s\n%s" % \
118 (pinidx, k, str(v), self.pins[pinidx])
119 self.pins[pinidx].update(v)
120
121 def keys(self):
122 return self.pins.keys()
123
124 def items(self):
125 return self.pins.items()
126
127 def get(self, k):
128 return self.pins[k]
129
130 def __len__(self):
131 return len(self.pins)
132
133 def __delitem__(self, k):
134 del self.pins[k]
135
136 def __getitem__(self, k):
137 return self.pins[k]
138
139 def pinmerge(self, fn):
140 # hack, store the function specs in the pins dict
141 fname = fn.fname
142 suffix = fn.origsuffix
143 bank = fn.bank
144
145 if not hasattr(self, 'fnspec'):
146 self.fnspec = pins
147 if fname == 'GPIO':
148 fname = fname + bank
149 assert 'EINT' not in self
150 if fname not in self.fnspec:
151 self.add_spec(fname, {})
152 if suffix or fname == 'EINT' or fname == 'PWM':
153 specname = fname + suffix
154 else:
155 specname = fname
156 # print "fname bank specname suffix ", fname, bank, specname, repr(
157 # suffix)
158 if specname in self.fnspec[fname]:
159 # ok so some declarations may bring in different
160 # names at different stages (EINT, PWM, flexbus1/2)
161 # so we have to merge the names in. main thing is
162 # the pingroup
163 tomerge = self.fnspec[fname][specname]
164 for p in fn.pingroup:
165 if p not in tomerge.pingroup:
166 tomerge.pingroup.append(p)
167 tomerge.pins.update(fn.pins)
168 tomerge.fntype.update(fn.fntype)
169 else:
170 self.fnspec[fname][specname] = deepcopy(fn)
171
172 # merge actual pins
173 for (pinidx, v) in fn.pins.items():
174 self.update(pinidx, v)
175
176 return fname
177
178
179 class Pins(object):
180
181 def __init__(self, fname, pingroup, bankspec, suffix, offs, bank, mux,
182 spec=None, limit=None, origsuffix=None, gangedgrp=None):
183
184 # function type can be in, out or inout, represented by - + *
185 # strip function type out of each pin name
186 self.fntype = {}
187 for i in range(len(pingroup)):
188 pname = pingroup[i]
189 if not pname:
190 continue
191 fntype = pname[-1]
192 if fntype not in '+-*':
193 continue
194 pname = pname[:-1]
195 fntype = {'-': 'in', '+': 'out', '*': 'inout'}[fntype]
196 self.fntype[pname] = fntype
197 pingroup[i] = pname
198
199 self.fname = fname
200 self.pingroup = pingroup
201 self.gangedgroup = gangedgrp
202 self.bankspec = bankspec
203 self.suffix = suffix
204 self.origsuffix = origsuffix or suffix
205 self.bank = bank
206 self.mux = mux
207
208 # create consistent name suffixes
209 pingroup = namesuffix(fname, suffix, pingroup)
210 suffix = '' # hack
211
212 res = {}
213 names = {}
214 idx = 0
215 for name in pingroup[:limit]:
216 if suffix and name:
217 name_ = "%s_%s" % (name, suffix)
218 else:
219 name_ = name
220 if spec and name in spec:
221 continue
222 pin = {mux: (name_, bank)}
223 offs_bank, offs_ = offs
224 idx_ = offs_ + idx
225 idx += 1
226 idx_ += bankspec[bank]
227 res[idx_] = pin
228 names[name] = idx_
229 for name in pingroup:
230 if suffix and name:
231 name_ = "%s_%s" % (name, suffix)
232 else:
233 name_ = name
234 if not spec:
235 continue
236 if name not in spec:
237 continue
238 idx_, mux_ = spec[name]
239 idx_ = names[idx_]
240 pin = {mux_: (name_, bank)}
241 if idx_ in res:
242 res[idx_].update(pin)
243 else:
244 res[idx_] = pin
245
246 self.pins = res