1 from __future__
import print_function
, division
, unicode_literals
5 * Copyright 2015 Advanced Micro Devices, Inc.
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * on the rights to use, copy, modify, merge, publish, distribute, sub
11 * license, and/or sell copies of the Software, and to permit persons to whom
12 * the Software is furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice (including the next
15 * paragraph) shall be included in all copies or substantial portions of the
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
22 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24 * USE OR OTHER DEALINGS IN THE SOFTWARE.
39 A class for collecting multiple strings in a single larger string that is
40 used by indexing (to avoid relocations in the resulting binary)
46 def add(self
, string
):
47 # We might get lucky with string being a suffix of a previously added string
49 if te
[0].endswith(string
):
50 idx
= te
[1] + len(te
[0]) - len(string
)
55 self
.table
.append((string
, idx
, set((idx
,))))
56 self
.length
+= len(string
) + 1
60 def emit(self
, filp
, name
, static
=True):
63 [static] const char name[] = "...";
67 '"%s\\0" /* %s */' % (
68 te
[0].encode('unicode_escape').decode(),
69 ', '.join(str(idx
) for idx
in sorted(te
[2]))
73 filp
.write('%sconst char %s[] =\n%s;\n' % (
74 'static ' if static
else '',
76 '\n'.join('\t' + fragment
for fragment
in fragments
)
81 A class for collecting multiple arrays of integers in a single big array
82 that is used by indexing (to avoid relocations in the resulting binary)
84 def __init__(self
, typename
):
85 self
.typename
= typename
90 # We might get lucky and find the array somewhere in the existing data
94 idx
= self
.table
.index(array
[0], idx
, len(self
.table
) - len(array
) + 1)
96 for i
in range(1, len(array
)):
97 if array
[i
] != self
.table
[idx
+ i
]:
107 idx
= len(self
.table
)
112 def emit(self
, filp
, name
, static
=True):
115 [static] const typename name[] = { ... };
118 idxs
= sorted(self
.idxs
) + [len(self
.table
)]
123 ' '.join((str(elt
) + ',') for elt
in self
.table
[idxs
[i
]:idxs
[i
+1]])
125 for i
in range(len(idxs
) - 1)
128 filp
.write('%sconst %s %s[] = {\n%s\n};\n' % (
129 'static ' if static
else '',
135 def __init__(self
, reg
, s_name
):
137 self
.name
= strip_prefix(s_name
)
140 def format(self
, string_table
, idx_table
):
143 for value
in self
.values
:
144 while value
[1] >= len(values_offsets
):
145 values_offsets
.append(-1)
146 values_offsets
[value
[1]] = string_table
.add(strip_prefix(value
[0]))
147 return '{%s, %s(~0u), %s, %s}' % (
148 string_table
.add(self
.name
), self
.s_name
,
149 len(values_offsets
), idx_table
.add(values_offsets
))
151 return '{%s, %s(~0u)}' % (string_table
.add(self
.name
), self
.s_name
)
153 def __eq__(self
, other
):
154 return (self
.s_name
== other
.s_name
and
155 self
.name
== other
.name
and
156 len(self
.values
) == len(other
.values
) and
157 all(a
[0] == b
[0] and a
[1] == b
[1] for a
, b
, in zip(self
.values
, other
.values
)))
159 def __ne__(self
, other
):
160 return not (self
== other
)
165 A class for collecting multiple arrays of register fields in a single big
166 array that is used by indexing (to avoid relocations in the resulting binary)
171 self
.name_to_idx
= collections
.defaultdict(lambda: [])
173 def add(self
, array
):
175 Add an array of Field objects, and return the index of where to find
176 the array in the table.
178 # Check if we can find the array in the table already
179 for base_idx
in self
.name_to_idx
.get(array
[0].name
, []):
180 if base_idx
+ len(array
) > len(self
.table
):
183 for i
, a
in enumerate(array
):
184 b
= self
.table
[base_idx
+ i
]
190 base_idx
= len(self
.table
)
191 self
.idxs
.add(base_idx
)
194 self
.name_to_idx
[field
.name
].append(len(self
.table
))
195 self
.table
.append(field
)
199 def emit(self
, filp
, string_table
, idx_table
):
202 static const struct si_field sid_fields_table[] = { ... };
205 idxs
= sorted(self
.idxs
) + [len(self
.table
)]
207 filp
.write('static const struct si_field sid_fields_table[] = {\n')
209 for start
, end
in zip(idxs
, idxs
[1:]):
210 filp
.write('\t/* %s */\n' % (start
))
211 for field
in self
.table
[start
:end
]:
212 filp
.write('\t%s,\n' % (field
.format(string_table
, idx_table
)))
218 def __init__(self
, r_name
):
220 self
.name
= strip_prefix(r_name
)
223 def __eq__(self
, other
):
224 if not isinstance(other
, Reg
):
226 return (self
.r_name
== other
.r_name
and
227 self
.name
== other
.name
and
228 len(self
.fields
) == len(other
.fields
) and
229 all(a
== b
for a
, b
in zip(self
.fields
, other
.fields
)))
231 def __ne__(self
, other
):
232 return not (self
== other
)
236 '''Strip prefix in the form ._.*_, e.g. R_001234_'''
237 return s
[s
[2:].find('_')+3:]
242 Store the registers of one ASIC class / group of classes.
244 def __init__(self
, name
):
248 def parse(self
, filp
, packets
, older_asics
):
250 Parse registers from the given header file. Packets are separately
251 stored in the packets array.
254 if not line
.startswith('#define '):
257 line
= line
[8:].strip()
259 if line
.startswith('R_'):
260 name
= line
.split()[0]
262 for it
in self
.registers
:
263 if it
.r_name
== name
:
264 sys
.exit('Duplicate register define: %s' % (name
))
267 self
.registers
.append(reg
)
269 elif line
.startswith('S_'):
270 name
= line
[:line
.find('(')]
272 for it
in reg
.fields
:
273 if it
.s_name
== name
:
274 sys
.exit('Duplicate field define: %s' % (name
))
276 field
= Field(reg
, name
)
277 reg
.fields
.append(field
)
279 elif line
.startswith('V_'):
282 value
= int(split
[1], 0)
284 for (n
,v
) in field
.values
:
286 sys
.exit('Duplicate value define: name = ' + name
)
288 field
.values
.append((name
, value
))
290 elif line
.startswith('PKT3_') and line
.find('0x') != -1 and line
.find('(') == -1:
291 packets
.append(line
.split()[0])
293 # Copy values for corresponding fields from older ASICs if they were
295 for reg
in self
.registers
:
297 for field
in reg
.fields
:
298 if len(field
.values
) > 0:
301 for old_reg
in itertools
.chain(
302 *(asic
.registers
for asic
in reversed(older_asics
))):
303 if old_reg
.name
== reg
.name
:
307 if old_reg
is not None:
308 for old_field
in old_reg
.fields
:
309 if old_field
.name
== field
.name
:
310 field
.values
= old_field
.values
313 # Copy fields to indexed registers which have their fields only defined
314 # at register index 0.
315 # For example, copy fields from CB_COLOR0_INFO to CB_COLORn_INFO, n > 0.
316 match_number
= re
.compile('[0-9]+')
319 # Create a dict of registers with fields and '0' in their name
320 for reg
in self
.registers
:
321 if len(reg
.fields
) and reg
.name
.find('0') != -1:
322 reg_dict
[reg
.name
] = reg
325 for reg
in self
.registers
:
326 if not len(reg
.fields
):
327 reg0
= reg_dict
.get(match_number
.sub('0', reg
.name
))
329 reg
.fields
= reg0
.fields
332 def write_tables(asics
, packets
):
333 strings
= StringTable()
334 strings_offsets
= IntTable("int")
335 fields
= FieldTable()
337 print('/* This file is autogenerated by sid_tables.py from sid.h. Do not edit directly. */')
339 print(CopyRight
.strip())
345 unsigned name_offset;
348 unsigned values_offset; /* offset into sid_strings_offsets */
352 unsigned name_offset;
355 unsigned fields_offset;
359 unsigned name_offset;
364 print('static const struct si_packet3 packet3_table[] = {')
366 print('\t{%s, %s},' % (strings
.add(pkt
[5:]), pkt
))
372 print('static const struct si_reg %s_reg_table[] = {' % (asic
.name
))
373 for reg
in asic
.registers
:
374 # Only output a register that was changed or added relative to
375 # the previous generation
376 previous
= regs
.get(reg
.r_name
, None)
381 print('\t{%s, %s, %s, %s},' % (strings
.add(reg
.name
), reg
.r_name
,
382 len(reg
.fields
), fields
.add(reg
.fields
)))
384 print('\t{%s, %s},' % (strings
.add(reg
.name
), reg
.r_name
))
386 regs
[reg
.r_name
] = reg
390 fields
.emit(sys
.stdout
, strings
, strings_offsets
)
394 strings
.emit(sys
.stdout
, "sid_strings")
398 strings_offsets
.emit(sys
.stdout
, "sid_strings_offsets")
407 for arg
in sys
.argv
[1:]:
408 basename
= os
.path
.basename(arg
)
409 m
= re
.match(r
'(.*)\.h', basename
)
410 asic
= Asic(m
.group(1))
411 with
open(arg
) as filp
:
412 asic
.parse(filp
, packets
, asics
)
414 write_tables(asics
, packets
)
417 if __name__
== '__main__':
420 # kate: space-indent on; indent-width 4; replace-tabs on;