xref: /aosp_15_r20/external/mesa3d/src/amd/registers/parseheader.py (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1#
2# Copyright 2017-2019 Advanced Micro Devices, Inc.
3#
4# SPDX-License-Identifier: MIT
5#
6"""
7Helper script that parses a register header and produces a register database
8as output. Use as:
9
10  python3 parseheader.py ADDRESS_SPACE < header.h
11
12This script is included for reference -- we should be able to remove this in
13the future.
14"""
15
16import json
17import math
18import re
19import sys
20
21from regdb import Object, RegisterDatabase, deduplicate_enums, deduplicate_register_types
22
23
24RE_comment = re.compile(r'(/\*(.*)\*/)$|(//(.*))$')
25RE_prefix = re.compile(r'([RSV])_([0-9a-fA-F]+)_')
26RE_set_value = re.compile(r'\(\(\(unsigned\)\(x\) & ([0-9a-fA-Fx]+)\) << ([0-9]+)\)')
27RE_set_value_no_shift = re.compile(r'\((\(unsigned\))?\(x\) & ([0-9a-fA-Fx]+)\)')
28
29class HeaderParser(object):
30    def __init__(self, address_space):
31        self.regdb = RegisterDatabase()
32        self.chips = ['gfx6', 'gfx7', 'gfx8', 'fiji', 'stoney', 'gfx9']
33        self.address_space = address_space
34
35    def __fini_field(self):
36        if self.__field is None:
37            return
38
39        if self.__enumentries:
40            self.__field.enum_ref = self.__regmap.name + '__' + self.__field.name
41            self.regdb.add_enum(self.__field.enum_ref, Object(
42                entries=self.__enumentries
43            ))
44        self.__fields.append(self.__field)
45
46        self.__enumentries = None
47        self.__field = None
48
49    def __fini_register(self):
50        if self.__regmap is None:
51            return
52
53        if self.__fields:
54            self.regdb.add_register_type(self.__regmap.name, Object(
55                fields=self.__fields
56            ))
57            self.__regmap.type_ref = self.__regmap.name
58        self.regdb.add_register_mapping(self.__regmap)
59
60        self.__regmap = None
61        self.__fields = None
62
63    def parse_header(self, filp):
64        regdb = RegisterDatabase()
65        chips = ['gfx6', 'gfx7', 'gfx8', 'fiji', 'stoney', 'gfx9']
66
67        self.__regmap = None
68        self.__fields = None
69        self.__field = None
70        self.__enumentries = None
71
72        for line in filp:
73            if not line.startswith('#define '):
74                continue
75
76            line = line[8:].strip()
77
78            comment = None
79            m = RE_comment.search(line)
80            if m is not None:
81                comment = m.group(2) or m.group(4)
82                comment = comment.strip()
83                line = line[:m.span()[0]].strip()
84
85            split = line.split(None, 1)
86            name = split[0]
87
88            m = RE_prefix.match(name)
89            if m is None:
90                continue
91
92            prefix = m.group(1)
93            prefix_address = int(m.group(2), 16)
94            name = name[m.span()[1]:]
95
96            if prefix == 'V':
97                value = int(split[1], 0)
98
99                for entry in self.__enumentries:
100                    if name == entry.name:
101                        sys.exit('Duplicate value define: name = {0}'.format(name))
102
103                entry = Object(name=name, value=value)
104                if comment is not None:
105                    entry.comment = comment
106                self.__enumentries.append(entry)
107                continue
108
109            if prefix == 'S':
110                self.__fini_field()
111
112                if not name.endswith('(x)'):
113                    sys.exit('Missing (x) in S line: {0}'.line)
114                name = name[:-3]
115
116                for field in self.__fields:
117                    if name == field.name:
118                        sys.exit('Duplicate field define: {0}'.format(name))
119
120                m = RE_set_value.match(split[1])
121                if m is not None:
122                    unshifted_mask = int(m.group(1), 0)
123                    shift = int(m.group(2), 0)
124                else:
125                    m = RE_set_value_no_shift.match(split[1])
126                    if m is not None:
127                        unshifted_mask = int(m.group(2), 0)
128                        shift = 0
129                    else:
130                        sys.exit('Bad S_xxx_xxx define: {0}'.format(line))
131
132                num_bits = int(math.log2(unshifted_mask + 1))
133                if unshifted_mask != (1 << num_bits) - 1:
134                    sys.exit('Bad unshifted mask in {0}'.format(line))
135
136                self.__field = Object(
137                    name=name,
138                    bits=[shift, shift + num_bits - 1],
139                )
140                if comment is not None:
141                    self.__field.comment = comment
142                self.__enumentries = []
143
144            if prefix == 'R':
145                self.__fini_field()
146                self.__fini_register()
147
148                if regdb.register_mappings_by_name(name):
149                    sys.exit('Duplicate register define: {0}'.format(name))
150
151                address = int(split[1], 0)
152                if address != prefix_address:
153                    sys.exit('Inconsistent register address: {0}'.format(line))
154
155                self.__regmap = Object(
156                    name=name,
157                    chips=self.chips,
158                    map=Object(to=self.address_space, at=address),
159                )
160                self.__fields = []
161
162        self.__fini_field()
163        self.__fini_register()
164
165def main():
166    map_to = sys.argv[1]
167
168    parser = HeaderParser(map_to)
169    parser.parse_header(sys.stdin)
170
171    deduplicate_enums(parser.regdb)
172    deduplicate_register_types(parser.regdb)
173
174    print(parser.regdb.encode_json_pretty())
175
176
177if __name__ == '__main__':
178    main()
179
180# kate: space-indent on; indent-width 4; replace-tabs on;
181