4 * Copyright 2015 Advanced Micro Devices, Inc.
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * on the rights to use, copy, modify, merge, publish, distribute, sub
10 * license, and/or sell copies of the Software, and to permit persons to whom
11 * the Software is furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice (including the next
14 * paragraph) shall be included in all copies or substantial portions of the
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
21 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
22 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
23 * USE OR OTHER DEALINGS IN THE SOFTWARE.
38 A class for collecting multiple strings in a single larger string that is
39 used by indexing (to avoid relocations in the resulting binary)
45 def add(self
, string
):
46 # We might get lucky with string being a suffix of a previously added string
48 if te
[0].endswith(string
):
49 idx
= te
[1] + len(te
[0]) - len(string
)
54 self
.table
.append((string
, idx
, set((idx
,))))
55 self
.length
+= len(string
) + 1
59 def emit(self
, filp
, name
, static
=True):
62 [static] const char name[] = "...";
66 '"%s\\0" /* %s */' % (
67 te
[0].encode('string_escape'),
68 ', '.join(str(idx
) for idx
in te
[2])
72 filp
.write('%sconst char %s[] =\n%s;\n' % (
73 'static ' if static
else '',
75 '\n'.join('\t' + fragment
for fragment
in fragments
)
80 A class for collecting multiple arrays of integers in a single big array
81 that is used by indexing (to avoid relocations in the resulting binary)
83 def __init__(self
, typename
):
84 self
.typename
= typename
89 # We might get lucky and find the array somewhere in the existing data
93 idx
= self
.table
.index(array
[0], idx
, len(self
.table
) - len(array
) + 1)
95 for i
in range(1, len(array
)):
96 if array
[i
] != self
.table
[idx
+ i
]:
106 idx
= len(self
.table
)
111 def emit(self
, filp
, name
, static
=True):
114 [static] const typename name[] = { ... };
117 idxs
= sorted(self
.idxs
) + [len(self
.table
)]
122 ' '.join((str(elt
) + ',') for elt
in self
.table
[idxs
[i
]:idxs
[i
+1]])
124 for i
in range(len(idxs
) - 1)
127 filp
.write('%sconst %s %s[] = {\n%s\n};\n' % (
128 'static ' if static
else '',
134 def __init__(self
, reg
, s_name
):
136 self
.name
= strip_prefix(s_name
)
139 def format(self
, string_table
, idx_table
):
142 for value
in self
.values
:
143 while value
[1] >= len(values_offsets
):
144 values_offsets
.append(-1)
145 values_offsets
[value
[1]] = string_table
.add(strip_prefix(value
[0]))
146 return '{%s, %s(~0u), %s, %s}' % (
147 string_table
.add(self
.name
), self
.s_name
,
148 len(values_offsets
), idx_table
.add(values_offsets
))
150 return '{%s, %s(~0u)}' % (string_table
.add(self
.name
), self
.s_name
)
152 def __eq__(self
, other
):
153 return (self
.s_name
== other
.s_name
and
154 self
.name
== other
.name
and
155 len(self
.values
) == len(other
.values
) and
156 all(a
[0] == b
[0] and a
[1] == b
[1] for a
, b
, in zip(self
.values
, other
.values
)))
158 def __ne__(self
, other
):
159 return not (self
== other
)
164 A class for collecting multiple arrays of register fields in a single big
165 array that is used by indexing (to avoid relocations in the resulting binary)
170 self
.name_to_idx
= collections
.defaultdict(lambda: [])
172 def add(self
, array
):
174 Add an array of Field objects, and return the index of where to find
175 the array in the table.
177 # Check if we can find the array in the table already
178 for base_idx
in self
.name_to_idx
.get(array
[0].name
, []):
179 if base_idx
+ len(array
) > len(self
.table
):
182 for i
, a
in enumerate(array
):
183 b
= self
.table
[base_idx
+ i
]
189 base_idx
= len(self
.table
)
190 self
.idxs
.add(base_idx
)
193 self
.name_to_idx
[field
.name
].append(len(self
.table
))
194 self
.table
.append(field
)
198 def emit(self
, filp
, string_table
, idx_table
):
201 static const struct si_field sid_fields_table[] = { ... };
204 idxs
= sorted(self
.idxs
) + [len(self
.table
)]
206 filp
.write('static const struct si_field sid_fields_table[] = {\n')
208 for start
, end
in zip(idxs
, idxs
[1:]):
209 filp
.write('\t/* %s */\n' % (start
))
210 for field
in self
.table
[start
:end
]:
211 filp
.write('\t%s,\n' % (field
.format(string_table
, idx_table
)))
217 def __init__(self
, r_name
):
219 self
.name
= strip_prefix(r_name
)
222 def __eq__(self
, other
):
223 if not isinstance(other
, Reg
):
225 return (self
.r_name
== other
.r_name
and
226 self
.name
== other
.name
and
227 len(self
.fields
) == len(other
.fields
) and
228 all(a
== b
for a
, b
in zip(self
.fields
, other
.fields
)))
230 def __ne__(self
, other
):
231 return not (self
== other
)
235 '''Strip prefix in the form ._.*_, e.g. R_001234_'''
236 return s
[s
[2:].find('_')+3:]
241 Store the registers of one ASIC class / group of classes.
243 def __init__(self
, name
):
247 def parse(self
, filp
, packets
, older_asics
):
249 Parse registers from the given header file. Packets are separately
250 stored in the packets array.
253 if not line
.startswith('#define '):
256 line
= line
[8:].strip()
258 if line
.startswith('R_'):
259 name
= line
.split()[0]
261 for it
in self
.registers
:
262 if it
.r_name
== name
:
263 sys
.exit('Duplicate register define: %s' % (name
))
266 self
.registers
.append(reg
)
268 elif line
.startswith('S_'):
269 name
= line
[:line
.find('(')]
271 for it
in reg
.fields
:
272 if it
.s_name
== name
:
273 sys
.exit('Duplicate field define: %s' % (name
))
275 field
= Field(reg
, name
)
276 reg
.fields
.append(field
)
278 elif line
.startswith('V_'):
281 value
= int(split
[1], 0)
283 for (n
,v
) in field
.values
:
285 sys
.exit('Duplicate value define: name = ' + name
)
287 field
.values
.append((name
, value
))
289 elif line
.startswith('PKT3_') and line
.find('0x') != -1 and line
.find('(') == -1:
290 packets
.append(line
.split()[0])
292 # Copy values for corresponding fields from older ASICs if they were
294 for reg
in self
.registers
:
296 for field
in reg
.fields
:
297 if len(field
.values
) > 0:
300 for old_reg
in itertools
.chain(
301 *(asic
.registers
for asic
in reversed(older_asics
))):
302 if old_reg
.name
== reg
.name
:
306 if old_reg
is not None:
307 for old_field
in old_reg
.fields
:
308 if old_field
.name
== field
.name
:
309 field
.values
= old_field
.values
312 # Copy fields to indexed registers which have their fields only defined
313 # at register index 0.
314 # For example, copy fields from CB_COLOR0_INFO to CB_COLORn_INFO, n > 0.
315 match_number
= re
.compile('[0-9]+')
318 # Create a dict of registers with fields and '0' in their name
319 for reg
in self
.registers
:
320 if len(reg
.fields
) and reg
.name
.find('0') != -1:
321 reg_dict
[reg
.name
] = reg
324 for reg
in self
.registers
:
325 if not len(reg
.fields
):
326 reg0
= reg_dict
.get(match_number
.sub('0', reg
.name
))
328 reg
.fields
= reg0
.fields
331 def write_tables(asics
, packets
):
332 strings
= StringTable()
333 strings_offsets
= IntTable("int")
334 fields
= FieldTable()
336 print '/* This file is autogenerated by sid_tables.py from sid.h. Do not edit directly. */'
338 print CopyRight
.strip()
344 unsigned name_offset;
347 unsigned values_offset; /* offset into sid_strings_offsets */
351 unsigned name_offset;
354 unsigned fields_offset;
358 unsigned name_offset;
363 print 'static const struct si_packet3 packet3_table[] = {'
365 print '\t{%s, %s},' % (strings
.add(pkt
[5:]), pkt
)
371 print 'static const struct si_reg %s_reg_table[] = {' % (asic
.name
)
372 for reg
in asic
.registers
:
373 # Only output a register that was changed or added relative to
374 # the previous generation
375 previous
= regs
.get(reg
.r_name
, None)
380 print '\t{%s, %s, %s, %s},' % (strings
.add(reg
.name
), reg
.r_name
,
381 len(reg
.fields
), fields
.add(reg
.fields
))
383 print '\t{%s, %s},' % (strings
.add(reg
.name
), reg
.r_name
)
385 regs
[reg
.r_name
] = reg
389 fields
.emit(sys
.stdout
, strings
, strings_offsets
)
393 strings
.emit(sys
.stdout
, "sid_strings")
397 strings_offsets
.emit(sys
.stdout
, "sid_strings_offsets")
406 for arg
in sys
.argv
[1:]:
407 basename
= os
.path
.basename(arg
)
408 m
= re
.match(r
'(.*)\.h', basename
)
409 asic
= Asic(m
.group(1))
410 with
open(arg
) as filp
:
411 asic
.parse(filp
, packets
, asics
)
413 write_tables(asics
, packets
)
416 if __name__
== '__main__':
419 # kate: space-indent on; indent-width 4; replace-tabs on;