Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/amd/registers/makeregheader.py
7097 views
1
from __future__ import absolute_import, division, print_function, unicode_literals
2
3
COPYRIGHT = '''
4
/*
5
* Copyright 2015-2019 Advanced Micro Devices, Inc.
6
*
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:
13
*
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
16
* Software.
17
*
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.
25
*
26
*/
27
'''
28
"""
29
Create the (combined) register header from register JSON. Use --help for usage.
30
"""
31
32
import argparse
33
from collections import defaultdict
34
import itertools
35
import json
36
import re
37
import sys
38
39
from regdb import Object, RegisterDatabase, deduplicate_enums, deduplicate_register_types
40
41
42
######### BEGIN HARDCODED CONFIGURATION
43
44
# Chips are sorted chronologically
45
CHIPS = [
46
Object(name='gfx6', disambiguation='GFX6'),
47
Object(name='gfx7', disambiguation='GFX7'),
48
Object(name='gfx8', disambiguation='GFX8'),
49
Object(name='gfx81', disambiguation='GFX81'),
50
Object(name='gfx9', disambiguation='GFX9'),
51
Object(name='gfx10', disambiguation='GFX10'),
52
Object(name='gfx103', disambiguation='GFX103'),
53
]
54
55
######### END HARDCODED CONFIGURATION
56
57
def get_chip_index(chip):
58
"""
59
Given a chip name, return its index in the global CHIPS list.
60
"""
61
return next(idx for idx, obj in enumerate(CHIPS) if obj.name == chip)
62
63
def get_disambiguation_suffix(chips):
64
"""
65
Disambiguation suffix to be used for an enum entry or field name that
66
is supported in the given set of chips.
67
"""
68
oldest_chip_index = min([get_chip_index(chip) for chip in chips])
69
return CHIPS[oldest_chip_index].disambiguation
70
71
def get_chips_comment(chips, parent=None):
72
"""
73
Generate a user-friendly comment describing the given set of chips.
74
75
The return value may be None, if such a comment is deemed unnecessary.
76
77
parent is an optional set of chips supporting a parent structure, e.g.
78
where chips may be the set of chips supporting a specific enum value,
79
parent would be the set of chips supporting the field containing the enum,
80
the idea being that no comment is necessary if all chips that support the
81
parent also support the child.
82
"""
83
chipflags = [chip.name in chips for chip in CHIPS]
84
if all(chipflags):
85
return None
86
87
if parent is not None:
88
parentflags = [chip.name in parent for chip in CHIPS]
89
if all(childflag or not parentflag for childflag, parentflag in zip(chipflags, parentflags)):
90
return None
91
92
prefix = 0
93
for idx, chip, flag in zip(itertools.count(), CHIPS, chipflags):
94
if not flag:
95
break
96
prefix = idx + 1
97
98
suffix = len(CHIPS)
99
for idx, chip, flag in zip(itertools.count(), reversed(CHIPS), reversed(chipflags)):
100
if not flag:
101
break
102
suffix = len(CHIPS) - idx - 1
103
104
comment = []
105
if prefix > 0:
106
comment.append('<= {0}'.format(CHIPS[prefix - 1].name))
107
for chip, flag in zip(CHIPS[prefix:suffix], chipflags[prefix:suffix]):
108
if flag:
109
comment.append(chip.name)
110
if suffix < len(CHIPS):
111
comment.append('>= {0}'.format(CHIPS[suffix].name))
112
113
return ', '.join(comment)
114
115
def detect_conflict(regdb, field_in_type1, field_in_type2):
116
"""
117
Returns False if field_in_type1 and field_in_type2 can be merged
118
into a single field = if writing to field_in_type1 bits won't
119
overwrite adjacent fields in type2, and the other way around.
120
"""
121
for idx, type_refs in enumerate([field_in_type1.type_refs, field_in_type2.type_refs]):
122
ref = field_in_type2 if idx == 0 else field_in_type1
123
for type_ref in type_refs:
124
for field in regdb.register_type(type_ref).fields:
125
# If a different field in the other type starts in
126
# the tested field's bits[0, 1] interval
127
if (field.bits[0] > ref.bits[0] and
128
field.bits[0] <= ref.bits[1]):
129
return True
130
131
return False
132
133
class HeaderWriter(object):
134
def __init__(self, regdb, guard=None):
135
self.guard = guard
136
137
# The following contain: Object(address, chips, name, regmap/field/enumentry)
138
self.register_lines = []
139
self.field_lines = []
140
self.value_lines = []
141
142
regtype_emit = defaultdict(set)
143
enum_emit = defaultdict(set)
144
145
for regmap in regdb.register_mappings():
146
type_ref = getattr(regmap, 'type_ref', None)
147
self.register_lines.append(Object(
148
address=regmap.map.at,
149
chips=set(regmap.chips),
150
name=regmap.name,
151
regmap=regmap,
152
type_refs=set([type_ref]) if type_ref else set(),
153
))
154
155
basename = re.sub(r'[0-9]+', '', regmap.name)
156
key = '{type_ref}::{basename}'.format(**locals())
157
if type_ref is not None and regtype_emit[key].isdisjoint(regmap.chips):
158
regtype_emit[key].update(regmap.chips)
159
160
regtype = regdb.register_type(type_ref)
161
for field in regtype.fields:
162
if field.name == 'RESERVED':
163
continue
164
165
enum_ref = getattr(field, 'enum_ref', None)
166
self.field_lines.append(Object(
167
address=regmap.map.at,
168
chips=set(regmap.chips),
169
name=field.name,
170
field=field,
171
bits=field.bits[:],
172
type_refs=set([type_ref]) if type_ref else set(),
173
enum_refs=set([enum_ref]) if enum_ref else set(),
174
))
175
176
key = '{type_ref}::{basename}::{enum_ref}'.format(**locals())
177
if enum_ref is not None and enum_emit[key].isdisjoint(regmap.chips):
178
enum_emit[key].update(regmap.chips)
179
180
enum = regdb.enum(enum_ref)
181
for entry in enum.entries:
182
self.value_lines.append(Object(
183
address=regmap.map.at,
184
chips=set(regmap.chips),
185
name=entry.name,
186
enumentry=entry,
187
enum_refs=set([enum_ref]) if enum_ref else set(),
188
))
189
190
# Merge register lines
191
lines = self.register_lines
192
lines.sort(key=lambda line: (line.address, line.name))
193
194
self.register_lines = []
195
for line in lines:
196
prev = self.register_lines[-1] if self.register_lines else None
197
if prev and prev.address == line.address and prev.name == line.name:
198
prev.chips.update(line.chips)
199
prev.type_refs.update(line.type_refs)
200
continue
201
self.register_lines.append(line)
202
203
# Merge field lines
204
lines = self.field_lines
205
lines.sort(key=lambda line: (line.address, line.name))
206
207
self.field_lines = []
208
for line in lines:
209
merged = False
210
for prev in reversed(self.field_lines):
211
if prev.address != line.address or prev.name != line.name:
212
break
213
214
# Can merge fields if they have the same starting bit and the
215
# range of the field as intended by the current line does not
216
# conflict with any of the regtypes covered by prev.
217
if prev.bits[0] != line.bits[0]:
218
continue
219
220
if prev.bits[1] != line.bits[1]:
221
# Current line's field extends beyond the range of prev.
222
# Need to check for conflicts
223
if detect_conflict(regdb, prev, line):
224
continue
225
226
prev.bits[1] = max(prev.bits[1], line.bits[1])
227
prev.chips.update(line.chips)
228
prev.type_refs.update(line.type_refs)
229
prev.enum_refs.update(line.enum_refs)
230
merged = True
231
break
232
if not merged:
233
self.field_lines.append(line)
234
235
# Merge value lines
236
lines = self.value_lines
237
lines.sort(key=lambda line: (line.address, line.name))
238
239
self.value_lines = []
240
for line in lines:
241
for prev in reversed(self.value_lines):
242
if prev.address == line.address and prev.name == line.name and\
243
prev.enumentry.value == line.enumentry.value:
244
prev.chips.update(line.chips)
245
prev.enum_refs.update(line.enum_refs)
246
break
247
else:
248
self.value_lines.append(line)
249
250
# Disambiguate field and value lines
251
for idx, line in enumerate(self.field_lines):
252
prev = self.field_lines[idx - 1] if idx > 0 else None
253
next = self.field_lines[idx + 1] if idx + 1 < len(self.field_lines) else None
254
if (prev and prev.address == line.address and prev.field.name == line.field.name) or\
255
(next and next.address == line.address and next.field.name == line.field.name):
256
line.name += '_' + get_disambiguation_suffix(line.chips)
257
258
for idx, line in enumerate(self.value_lines):
259
prev = self.value_lines[idx - 1] if idx > 0 else None
260
next = self.value_lines[idx + 1] if idx + 1 < len(self.value_lines) else None
261
if (prev and prev.address == line.address and prev.enumentry.name == line.enumentry.name) or\
262
(next and next.address == line.address and next.enumentry.name == line.enumentry.name):
263
line.name += '_' + get_disambiguation_suffix(line.chips)
264
265
def print(self, filp, sort='address'):
266
"""
267
Print out the entire register header.
268
"""
269
if sort == 'address':
270
self.register_lines.sort(key=lambda line: (line.address, line.name))
271
else:
272
assert sort == 'name'
273
self.register_lines.sort(key=lambda line: (line.name, line.address))
274
275
# Collect and sort field lines by address
276
field_lines_by_address = defaultdict(list)
277
for line in self.field_lines:
278
field_lines_by_address[line.address].append(line)
279
for field_lines in field_lines_by_address.values():
280
if sort == 'address':
281
field_lines.sort(key=lambda line: (line.bits[0], line.name))
282
else:
283
field_lines.sort(key=lambda line: (line.name, line.bits[0]))
284
285
# Collect and sort value lines by address
286
value_lines_by_address = defaultdict(list)
287
for line in self.value_lines:
288
value_lines_by_address[line.address].append(line)
289
for value_lines in value_lines_by_address.values():
290
if sort == 'address':
291
value_lines.sort(key=lambda line: (line.enumentry.value, line.name))
292
else:
293
value_lines.sort(key=lambda line: (line.name, line.enumentry.value))
294
295
print('/* Automatically generated by amd/registers/makeregheader.py */\n', file=filp)
296
print(file=filp)
297
print(COPYRIGHT.strip(), file=filp)
298
print(file=filp)
299
300
if self.guard:
301
print('#ifndef {self.guard}'.format(**locals()), file=filp)
302
print('#define {self.guard}\n'.format(**locals()), file=filp)
303
304
for register_line in self.register_lines:
305
comment = get_chips_comment(register_line.chips)
306
307
address = '{0:X}'.format(register_line.address)
308
address = address.rjust(3 if register_line.regmap.map.to == 'pkt3' else 6, '0')
309
310
define_name = 'R_{address}_{register_line.name}'.format(**locals()).ljust(63)
311
comment = ' /* {0} */'.format(comment) if comment else ''
312
print('#define {define_name} 0x{address}{comment}'.format(**locals()), file=filp)
313
314
field_lines = field_lines_by_address[register_line.address]
315
field_idx = 0
316
while field_idx < len(field_lines):
317
field_line = field_lines[field_idx]
318
319
if field_line.type_refs.isdisjoint(register_line.type_refs):
320
field_idx += 1
321
continue
322
del field_lines[field_idx]
323
324
comment = get_chips_comment(field_line.chips, register_line.chips)
325
326
mask = (1 << (field_line.bits[1] - field_line.bits[0] + 1)) - 1
327
define_name = '_{address}_{field_line.name}(x)'.format(**locals()).ljust(58)
328
comment = ' /* {0} */'.format(comment) if comment else ''
329
print(
330
'#define S{define_name} (((unsigned)(x) & 0x{mask:X}) << {field_line.bits[0]}){comment}'
331
.format(**locals()), file=filp)
332
print('#define G{define_name} (((x) >> {field_line.bits[0]}) & 0x{mask:X})'
333
.format(**locals()), file=filp)
334
335
complement = ((1 << 32) - 1) ^ (mask << field_line.bits[0])
336
define_name = '_{address}_{field_line.name}'.format(**locals()).ljust(58)
337
print('#define C{define_name} 0x{complement:08X}'
338
.format(**locals()), file=filp)
339
340
value_lines = value_lines_by_address[register_line.address]
341
value_idx = 0
342
while value_idx < len(value_lines):
343
value_line = value_lines[value_idx]
344
345
if value_line.enum_refs.isdisjoint(field_line.enum_refs):
346
value_idx += 1
347
continue
348
del value_lines[value_idx]
349
350
comment = get_chips_comment(value_line.chips, field_line.chips)
351
352
define_name = 'V_{address}_{value_line.name}'.format(**locals()).ljust(55)
353
comment = ' /* {0} */'.format(comment) if comment else ''
354
print('#define {define_name} {value_line.enumentry.value}{comment}'
355
.format(**locals()), file=filp)
356
357
if self.guard:
358
print('\n#endif // {self.guard}'.format(**locals()), file=filp)
359
360
361
def main():
362
parser = argparse.ArgumentParser()
363
parser.add_argument('--chip', dest='chips', type=str, nargs='*',
364
help='Chip for which to generate the header (all chips if unspecified)')
365
parser.add_argument('--sort', choices=['name', 'address'], default='address',
366
help='Sort key for registers, fields, and enum values')
367
parser.add_argument('--guard', type=str, help='Name of the #include guard')
368
parser.add_argument('files', metavar='FILE', type=str, nargs='+',
369
help='Register database file')
370
args = parser.parse_args()
371
372
regdb = None
373
for filename in args.files:
374
with open(filename, 'r') as filp:
375
db = RegisterDatabase.from_json(json.load(filp))
376
if regdb is None:
377
regdb = db
378
else:
379
regdb.update(db)
380
381
deduplicate_enums(regdb)
382
deduplicate_register_types(regdb)
383
384
w = HeaderWriter(regdb, guard=args.guard)
385
w.print(sys.stdout, sort=args.sort)
386
387
388
if __name__ == '__main__':
389
main()
390
391
# kate: space-indent on; indent-width 4; replace-tabs on;
392
393