ac: update register and packet definitions for preemption
[mesa.git] / src / amd / registers / parseheader.py
1 #
2 # Copyright 2017-2019 Advanced Micro Devices, Inc.
3 #
4 # Permission is hereby granted, free of charge, to any person obtaining a
5 # copy of this software and associated documentation files (the "Software"),
6 # to deal in the Software without restriction, including without limitation
7 # on the rights to use, copy, modify, merge, publish, distribute, sub
8 # license, and/or sell copies of the Software, and to permit persons to whom
9 # the Software is furnished to do so, subject to the following conditions:
10 #
11 # The above copyright notice and this permission notice (including the next
12 # paragraph) shall be included in all copies or substantial portions of the
13 # Software.
14 #
15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 # FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18 # THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19 # DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 # USE OR OTHER DEALINGS IN THE SOFTWARE.
22 #
23 """
24 Helper script that parses a register header and produces a register database
25 as output. Use as:
26
27 python3 parseheader.py ADDRESS_SPACE < header.h
28
29 This script is included for reference -- we should be able to remove this in
30 the future.
31 """
32
33 from __future__ import absolute_import, division, print_function, unicode_literals
34
35 import json
36 import math
37 import re
38 import sys
39
40 from regdb import Object, RegisterDatabase, deduplicate_enums, deduplicate_register_types
41
42
43 RE_comment = re.compile(r'(/\*(.*)\*/)$|(//(.*))$')
44 RE_prefix = re.compile(r'([RSV])_([0-9a-fA-F]+)_')
45 RE_set_value = re.compile(r'\(\(\(unsigned\)\(x\) & ([0-9a-fA-Fx]+)\) << ([0-9]+)\)')
46 RE_set_value_no_shift = re.compile(r'\((\(unsigned\))?\(x\) & ([0-9a-fA-Fx]+)\)')
47
48 class HeaderParser(object):
49 def __init__(self, address_space):
50 self.regdb = RegisterDatabase()
51 self.chips = ['gfx6', 'gfx7', 'gfx8', 'fiji', 'stoney', 'gfx9']
52 self.address_space = address_space
53
54 def __fini_field(self):
55 if self.__field is None:
56 return
57
58 if self.__enumentries:
59 self.__field.enum_ref = self.__regmap.name + '__' + self.__field.name
60 self.regdb.add_enum(self.__field.enum_ref, Object(
61 entries=self.__enumentries
62 ))
63 self.__fields.append(self.__field)
64
65 self.__enumentries = None
66 self.__field = None
67
68 def __fini_register(self):
69 if self.__regmap is None:
70 return
71
72 if self.__fields:
73 self.regdb.add_register_type(self.__regmap.name, Object(
74 fields=self.__fields
75 ))
76 self.__regmap.type_ref = self.__regmap.name
77 self.regdb.add_register_mapping(self.__regmap)
78
79 self.__regmap = None
80 self.__fields = None
81
82 def parse_header(self, filp):
83 regdb = RegisterDatabase()
84 chips = ['gfx6', 'gfx7', 'gfx8', 'fiji', 'stoney', 'gfx9']
85
86 self.__regmap = None
87 self.__fields = None
88 self.__field = None
89 self.__enumentries = None
90
91 for line in filp:
92 if not line.startswith('#define '):
93 continue
94
95 line = line[8:].strip()
96
97 comment = None
98 m = RE_comment.search(line)
99 if m is not None:
100 comment = m.group(2) or m.group(4)
101 comment = comment.strip()
102 line = line[:m.span()[0]].strip()
103
104 split = line.split(None, 1)
105 name = split[0]
106
107 m = RE_prefix.match(name)
108 if m is None:
109 continue
110
111 prefix = m.group(1)
112 prefix_address = int(m.group(2), 16)
113 name = name[m.span()[1]:]
114
115 if prefix == 'V':
116 value = int(split[1], 0)
117
118 for entry in self.__enumentries:
119 if name == entry.name:
120 sys.exit('Duplicate value define: name = {0}'.format(name))
121
122 entry = Object(name=name, value=value)
123 if comment is not None:
124 entry.comment = comment
125 self.__enumentries.append(entry)
126 continue
127
128 if prefix == 'S':
129 self.__fini_field()
130
131 if not name.endswith('(x)'):
132 sys.exit('Missing (x) in S line: {0}'.line)
133 name = name[:-3]
134
135 for field in self.__fields:
136 if name == field.name:
137 sys.exit('Duplicate field define: {0}'.format(name))
138
139 m = RE_set_value.match(split[1])
140 if m is not None:
141 unshifted_mask = int(m.group(1), 0)
142 shift = int(m.group(2), 0)
143 else:
144 m = RE_set_value_no_shift.match(split[1])
145 if m is not None:
146 unshifted_mask = int(m.group(2), 0)
147 shift = 0
148 else:
149 sys.exit('Bad S_xxx_xxx define: {0}'.format(line))
150
151 num_bits = int(math.log2(unshifted_mask + 1))
152 if unshifted_mask != (1 << num_bits) - 1:
153 sys.exit('Bad unshifted mask in {0}'.format(line))
154
155 self.__field = Object(
156 name=name,
157 bits=[shift, shift + num_bits - 1],
158 )
159 if comment is not None:
160 self.__field.comment = comment
161 self.__enumentries = []
162
163 if prefix == 'R':
164 self.__fini_field()
165 self.__fini_register()
166
167 if regdb.register_mappings_by_name(name):
168 sys.exit('Duplicate register define: {0}'.format(name))
169
170 address = int(split[1], 0)
171 if address != prefix_address:
172 sys.exit('Inconsistent register address: {0}'.format(line))
173
174 self.__regmap = Object(
175 name=name,
176 chips=self.chips,
177 map=Object(to=self.address_space, at=address),
178 )
179 self.__fields = []
180
181 self.__fini_field()
182 self.__fini_register()
183
184 def main():
185 map_to = sys.argv[1]
186
187 parser = HeaderParser(map_to)
188 parser.parse_header(sys.stdin)
189
190 deduplicate_enums(parser.regdb)
191 deduplicate_register_types(parser.regdb)
192
193 print(parser.regdb.encode_json_pretty())
194
195
196 if __name__ == '__main__':
197 main()
198
199 # kate: space-indent on; indent-width 4; replace-tabs on;