• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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"""
24Helper script that parses a register header and produces a register database
25as output. Use as:
26
27  python3 parseheader.py ADDRESS_SPACE < header.h
28
29This script is included for reference -- we should be able to remove this in
30the future.
31"""
32
33from __future__ import absolute_import, division, print_function, unicode_literals
34
35import json
36import math
37import re
38import sys
39
40from regdb import Object, RegisterDatabase, deduplicate_enums, deduplicate_register_types
41
42
43RE_comment = re.compile(r'(/\*(.*)\*/)$|(//(.*))$')
44RE_prefix = re.compile(r'([RSV])_([0-9a-fA-F]+)_')
45RE_set_value = re.compile(r'\(\(\(unsigned\)\(x\) & ([0-9a-fA-Fx]+)\) << ([0-9]+)\)')
46RE_set_value_no_shift = re.compile(r'\((\(unsigned\))?\(x\) & ([0-9a-fA-Fx]+)\)')
47
48class 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
184def 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
196if __name__ == '__main__':
197    main()
198
199# kate: space-indent on; indent-width 4; replace-tabs on;
200