Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/amd/common/sid_tables.py
7132 views
1
from __future__ import print_function, division, 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
from collections import defaultdict
30
import functools
31
import itertools
32
import json
33
import os.path
34
import re
35
import sys
36
37
AMD_REGISTERS = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), "../registers"))
38
sys.path.append(AMD_REGISTERS)
39
40
from regdb import Object, RegisterDatabase
41
42
43
def string_to_chars(string):
44
return "'" + "', '".join(string) + "', '\\0',"
45
46
47
class StringTable:
48
"""
49
A class for collecting multiple strings in a single larger string that is
50
used by indexing (to avoid relocations in the resulting binary)
51
"""
52
def __init__(self):
53
self.table = []
54
self.length = 0
55
56
def add(self, string):
57
# We might get lucky with string being a suffix of a previously added string
58
for te in self.table:
59
if te[0].endswith(string):
60
idx = te[1] + len(te[0]) - len(string)
61
te[2].add(idx)
62
return idx
63
64
idx = self.length
65
self.table.append((string, idx, set((idx,))))
66
self.length += len(string) + 1
67
68
return idx
69
70
def emit(self, filp, name, static=True):
71
"""
72
Write
73
[static] const char name[] = "...";
74
to filp.
75
"""
76
fragments = [
77
'%s /* %s (%s) */' % (
78
string_to_chars(te[0].encode('unicode_escape').decode()),
79
te[0].encode('unicode_escape').decode(),
80
', '.join(str(idx) for idx in sorted(te[2]))
81
)
82
for te in self.table
83
]
84
filp.write('%sconst char %s[] = {\n%s\n};\n' % (
85
'static ' if static else '',
86
name,
87
'\n'.join('\t' + fragment for fragment in fragments)
88
))
89
90
class IntTable:
91
"""
92
A class for collecting multiple arrays of integers in a single big array
93
that is used by indexing (to avoid relocations in the resulting binary)
94
"""
95
def __init__(self, typename):
96
self.typename = typename
97
self.table = []
98
self.idxs = set()
99
100
def add(self, array):
101
# We might get lucky and find the array somewhere in the existing data
102
try:
103
idx = 0
104
while True:
105
idx = self.table.index(array[0], idx, len(self.table) - len(array) + 1)
106
107
for i in range(1, len(array)):
108
if array[i] != self.table[idx + i]:
109
break
110
else:
111
self.idxs.add(idx)
112
return idx
113
114
idx += 1
115
except ValueError:
116
pass
117
118
idx = len(self.table)
119
self.table += array
120
self.idxs.add(idx)
121
return idx
122
123
def emit(self, filp, name, static=True):
124
"""
125
Write
126
[static] const typename name[] = { ... };
127
to filp.
128
"""
129
idxs = sorted(self.idxs) + [len(self.table)]
130
131
fragments = [
132
('\t/* %s */ %s' % (
133
idxs[i],
134
' '.join((str(elt) + ',') for elt in self.table[idxs[i]:idxs[i+1]])
135
))
136
for i in range(len(idxs) - 1)
137
]
138
139
filp.write('%sconst %s %s[] = {\n%s\n};\n' % (
140
'static ' if static else '',
141
self.typename, name,
142
'\n'.join(fragments)
143
))
144
145
class Field:
146
def __init__(self, name, bits):
147
self.name = name
148
self.bits = bits # [first, last]
149
self.values = [] # [(name, value), ...]
150
151
def format(self, string_table, idx_table):
152
mask = ((1 << (self.bits[1] - self.bits[0] + 1)) - 1) << self.bits[0]
153
if len(self.values):
154
values_offsets = []
155
for value in self.values:
156
while value[1] >= len(values_offsets):
157
values_offsets.append(-1)
158
values_offsets[value[1]] = string_table.add(value[0])
159
return '{{{0}, 0x{mask:X}, {1}, {2}}}'.format(
160
string_table.add(self.name),
161
len(values_offsets), idx_table.add(values_offsets),
162
**locals()
163
)
164
else:
165
return '{{{0}, 0x{mask:X}}}'.format(string_table.add(self.name), **locals())
166
167
def __eq__(self, other):
168
return (self.name == other.name and
169
self.bits[0] == other.bits[0] and self.bits[1] == other.bits[1] and
170
len(self.values) == len(other.values) and
171
all(a[0] == b[0] and a[1] == b[1] for a, b, in zip(self.values, other.values)))
172
173
def __ne__(self, other):
174
return not (self == other)
175
176
177
class FieldTable:
178
"""
179
A class for collecting multiple arrays of register fields in a single big
180
array that is used by indexing (to avoid relocations in the resulting binary)
181
"""
182
def __init__(self):
183
self.table = []
184
self.idxs = set()
185
self.name_to_idx = defaultdict(lambda: [])
186
187
def add(self, array):
188
"""
189
Add an array of Field objects, and return the index of where to find
190
the array in the table.
191
"""
192
# Check if we can find the array in the table already
193
for base_idx in self.name_to_idx.get(array[0].name, []):
194
if base_idx + len(array) > len(self.table):
195
continue
196
197
for i, a in enumerate(array):
198
b = self.table[base_idx + i]
199
if a != b:
200
break
201
else:
202
return base_idx
203
204
base_idx = len(self.table)
205
self.idxs.add(base_idx)
206
207
for field in array:
208
self.name_to_idx[field.name].append(len(self.table))
209
self.table.append(field)
210
211
return base_idx
212
213
def emit(self, filp, string_table, idx_table):
214
"""
215
Write
216
static const struct si_field sid_fields_table[] = { ... };
217
to filp.
218
"""
219
idxs = sorted(self.idxs) + [len(self.table)]
220
221
filp.write('static const struct si_field sid_fields_table[] = {\n')
222
223
for start, end in zip(idxs, idxs[1:]):
224
filp.write('\t/* %s */\n' % (start))
225
for field in self.table[start:end]:
226
filp.write('\t%s,\n' % (field.format(string_table, idx_table)))
227
228
filp.write('};\n')
229
230
231
def parse_packet3(filp):
232
"""
233
Parse PKT3 commands from the given header file.
234
"""
235
packets = []
236
for line in filp:
237
if not line.startswith('#define '):
238
continue
239
240
line = line[8:].strip()
241
242
if line.startswith('PKT3_') and line.find('0x') != -1 and line.find('(') == -1:
243
packets.append(line.split()[0])
244
return packets
245
246
247
class TableWriter(object):
248
def __init__(self):
249
self.__strings = StringTable()
250
self.__strings_offsets = IntTable('int')
251
self.__fields = FieldTable()
252
253
def write(self, regdb, packets, file=sys.stdout):
254
def out(*args):
255
print(*args, file=file)
256
257
out('/* This file is autogenerated by sid_tables.py from sid.h. Do not edit directly. */')
258
out()
259
out(CopyRight.strip())
260
out('''
261
#ifndef SID_TABLES_H
262
#define SID_TABLES_H
263
264
struct si_field {
265
unsigned name_offset;
266
unsigned mask;
267
unsigned num_values;
268
unsigned values_offset; /* offset into sid_strings_offsets */
269
};
270
271
struct si_reg {
272
unsigned name_offset;
273
unsigned offset;
274
unsigned num_fields;
275
unsigned fields_offset;
276
};
277
278
struct si_packet3 {
279
unsigned name_offset;
280
unsigned op;
281
};
282
''')
283
284
out('static const struct si_packet3 packet3_table[] = {')
285
for pkt in packets:
286
out('\t{%s, %s},' % (self.__strings.add(pkt[5:]), pkt))
287
out('};')
288
out()
289
290
regmaps_by_chip = defaultdict(list)
291
292
for regmap in regdb.register_mappings():
293
for chip in regmap.chips:
294
regmaps_by_chip[chip].append(regmap)
295
296
regtypes = {}
297
298
# Sorted iteration over chips for deterministic builds
299
for chip in sorted(regmaps_by_chip.keys()):
300
regmaps = regmaps_by_chip[chip]
301
regmaps.sort(key=lambda regmap: (regmap.map.to, regmap.map.at))
302
303
out('static const struct si_reg {chip}_reg_table[] = {{'.format(**locals()))
304
305
for regmap in regmaps:
306
if hasattr(regmap, 'type_ref'):
307
if not regmap.type_ref in regtypes:
308
regtype = regdb.register_type(regmap.type_ref)
309
fields = []
310
for dbfield in regtype.fields:
311
field = Field(dbfield.name, dbfield.bits)
312
if hasattr(dbfield, 'enum_ref'):
313
enum = regdb.enum(dbfield.enum_ref)
314
for entry in enum.entries:
315
field.values.append((entry.name, entry.value))
316
fields.append(field)
317
318
num_fields = len(regtype.fields)
319
fields_offset = self.__fields.add(fields)
320
regtypes[regmap.type_ref] = (num_fields, fields_offset)
321
else:
322
num_fields, fields_offset = regtypes[regmap.type_ref]
323
324
print('\t{{{0}, {regmap.map.at}, {num_fields}, {fields_offset}}},'
325
.format(self.__strings.add(regmap.name), **locals()))
326
else:
327
print('\t{{{0}, {regmap.map.at}}},'
328
.format(self.__strings.add(regmap.name), **locals()))
329
330
out('};\n')
331
332
self.__fields.emit(file, self.__strings, self.__strings_offsets)
333
334
out()
335
336
self.__strings.emit(file, "sid_strings")
337
338
out()
339
340
self.__strings_offsets.emit(file, "sid_strings_offsets")
341
342
out()
343
out('#endif')
344
345
346
def main():
347
# Parse PKT3 types
348
with open(sys.argv[1], 'r') as filp:
349
packets = parse_packet3(filp)
350
351
# Register database parse
352
regdb = None
353
for filename in sys.argv[2:]:
354
with open(filename, 'r') as filp:
355
try:
356
db = RegisterDatabase.from_json(json.load(filp))
357
if regdb is None:
358
regdb = db
359
else:
360
regdb.update(db)
361
except json.JSONDecodeError as e:
362
print('Error reading {}'.format(sys.argv[1]), file=sys.stderr)
363
raise
364
365
# The ac_debug code only distinguishes by chip_class
366
regdb.merge_chips(['gfx8', 'fiji', 'stoney'], 'gfx8')
367
368
# Write it all out
369
w = TableWriter()
370
w.write(regdb, packets)
371
372
if __name__ == '__main__':
373
main()
374
375
# kate: space-indent on; indent-width 4; replace-tabs on;
376
377