17ec681f3Smrg#
27ec681f3Smrg# Copyright 2017-2019 Advanced Micro Devices, Inc.
37ec681f3Smrg#
47ec681f3Smrg# Permission is hereby granted, free of charge, to any person obtaining a
57ec681f3Smrg# copy of this software and associated documentation files (the "Software"),
67ec681f3Smrg# to deal in the Software without restriction, including without limitation
77ec681f3Smrg# on the rights to use, copy, modify, merge, publish, distribute, sub
87ec681f3Smrg# license, and/or sell copies of the Software, and to permit persons to whom
97ec681f3Smrg# the Software is furnished to do so, subject to the following conditions:
107ec681f3Smrg#
117ec681f3Smrg# The above copyright notice and this permission notice (including the next
127ec681f3Smrg# paragraph) shall be included in all copies or substantial portions of the
137ec681f3Smrg# Software.
147ec681f3Smrg#
157ec681f3Smrg# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
167ec681f3Smrg# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
177ec681f3Smrg# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
187ec681f3Smrg# THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
197ec681f3Smrg# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
207ec681f3Smrg# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
217ec681f3Smrg# USE OR OTHER DEALINGS IN THE SOFTWARE.
227ec681f3Smrg#
237ec681f3Smrg"""
247ec681f3SmrgHelper script that parses a register header and produces a register database
257ec681f3Smrgas output. Use as:
267ec681f3Smrg
277ec681f3Smrg  python3 parseheader.py ADDRESS_SPACE < header.h
287ec681f3Smrg
297ec681f3SmrgThis script is included for reference -- we should be able to remove this in
307ec681f3Smrgthe future.
317ec681f3Smrg"""
327ec681f3Smrg
337ec681f3Smrgimport json
347ec681f3Smrgimport math
357ec681f3Smrgimport re
367ec681f3Smrgimport sys
377ec681f3Smrg
387ec681f3Smrgfrom regdb import Object, RegisterDatabase, deduplicate_enums, deduplicate_register_types
397ec681f3Smrg
407ec681f3Smrg
417ec681f3SmrgRE_comment = re.compile(r'(/\*(.*)\*/)$|(//(.*))$')
427ec681f3SmrgRE_prefix = re.compile(r'([RSV])_([0-9a-fA-F]+)_')
437ec681f3SmrgRE_set_value = re.compile(r'\(\(\(unsigned\)\(x\) & ([0-9a-fA-Fx]+)\) << ([0-9]+)\)')
447ec681f3SmrgRE_set_value_no_shift = re.compile(r'\((\(unsigned\))?\(x\) & ([0-9a-fA-Fx]+)\)')
457ec681f3Smrg
467ec681f3Smrgclass HeaderParser(object):
477ec681f3Smrg    def __init__(self, address_space):
487ec681f3Smrg        self.regdb = RegisterDatabase()
497ec681f3Smrg        self.chips = ['gfx6', 'gfx7', 'gfx8', 'fiji', 'stoney', 'gfx9']
507ec681f3Smrg        self.address_space = address_space
517ec681f3Smrg
527ec681f3Smrg    def __fini_field(self):
537ec681f3Smrg        if self.__field is None:
547ec681f3Smrg            return
557ec681f3Smrg
567ec681f3Smrg        if self.__enumentries:
577ec681f3Smrg            self.__field.enum_ref = self.__regmap.name + '__' + self.__field.name
587ec681f3Smrg            self.regdb.add_enum(self.__field.enum_ref, Object(
597ec681f3Smrg                entries=self.__enumentries
607ec681f3Smrg            ))
617ec681f3Smrg        self.__fields.append(self.__field)
627ec681f3Smrg
637ec681f3Smrg        self.__enumentries = None
647ec681f3Smrg        self.__field = None
657ec681f3Smrg
667ec681f3Smrg    def __fini_register(self):
677ec681f3Smrg        if self.__regmap is None:
687ec681f3Smrg            return
697ec681f3Smrg
707ec681f3Smrg        if self.__fields:
717ec681f3Smrg            self.regdb.add_register_type(self.__regmap.name, Object(
727ec681f3Smrg                fields=self.__fields
737ec681f3Smrg            ))
747ec681f3Smrg            self.__regmap.type_ref = self.__regmap.name
757ec681f3Smrg        self.regdb.add_register_mapping(self.__regmap)
767ec681f3Smrg
777ec681f3Smrg        self.__regmap = None
787ec681f3Smrg        self.__fields = None
797ec681f3Smrg
807ec681f3Smrg    def parse_header(self, filp):
817ec681f3Smrg        regdb = RegisterDatabase()
827ec681f3Smrg        chips = ['gfx6', 'gfx7', 'gfx8', 'fiji', 'stoney', 'gfx9']
837ec681f3Smrg
847ec681f3Smrg        self.__regmap = None
857ec681f3Smrg        self.__fields = None
867ec681f3Smrg        self.__field = None
877ec681f3Smrg        self.__enumentries = None
887ec681f3Smrg
897ec681f3Smrg        for line in filp:
907ec681f3Smrg            if not line.startswith('#define '):
917ec681f3Smrg                continue
927ec681f3Smrg
937ec681f3Smrg            line = line[8:].strip()
947ec681f3Smrg
957ec681f3Smrg            comment = None
967ec681f3Smrg            m = RE_comment.search(line)
977ec681f3Smrg            if m is not None:
987ec681f3Smrg                comment = m.group(2) or m.group(4)
997ec681f3Smrg                comment = comment.strip()
1007ec681f3Smrg                line = line[:m.span()[0]].strip()
1017ec681f3Smrg
1027ec681f3Smrg            split = line.split(None, 1)
1037ec681f3Smrg            name = split[0]
1047ec681f3Smrg
1057ec681f3Smrg            m = RE_prefix.match(name)
1067ec681f3Smrg            if m is None:
1077ec681f3Smrg                continue
1087ec681f3Smrg
1097ec681f3Smrg            prefix = m.group(1)
1107ec681f3Smrg            prefix_address = int(m.group(2), 16)
1117ec681f3Smrg            name = name[m.span()[1]:]
1127ec681f3Smrg
1137ec681f3Smrg            if prefix == 'V':
1147ec681f3Smrg                value = int(split[1], 0)
1157ec681f3Smrg
1167ec681f3Smrg                for entry in self.__enumentries:
1177ec681f3Smrg                    if name == entry.name:
1187ec681f3Smrg                        sys.exit('Duplicate value define: name = {0}'.format(name))
1197ec681f3Smrg
1207ec681f3Smrg                entry = Object(name=name, value=value)
1217ec681f3Smrg                if comment is not None:
1227ec681f3Smrg                    entry.comment = comment
1237ec681f3Smrg                self.__enumentries.append(entry)
1247ec681f3Smrg                continue
1257ec681f3Smrg
1267ec681f3Smrg            if prefix == 'S':
1277ec681f3Smrg                self.__fini_field()
1287ec681f3Smrg
1297ec681f3Smrg                if not name.endswith('(x)'):
1307ec681f3Smrg                    sys.exit('Missing (x) in S line: {0}'.line)
1317ec681f3Smrg                name = name[:-3]
1327ec681f3Smrg
1337ec681f3Smrg                for field in self.__fields:
1347ec681f3Smrg                    if name == field.name:
1357ec681f3Smrg                        sys.exit('Duplicate field define: {0}'.format(name))
1367ec681f3Smrg
1377ec681f3Smrg                m = RE_set_value.match(split[1])
1387ec681f3Smrg                if m is not None:
1397ec681f3Smrg                    unshifted_mask = int(m.group(1), 0)
1407ec681f3Smrg                    shift = int(m.group(2), 0)
1417ec681f3Smrg                else:
1427ec681f3Smrg                    m = RE_set_value_no_shift.match(split[1])
1437ec681f3Smrg                    if m is not None:
1447ec681f3Smrg                        unshifted_mask = int(m.group(2), 0)
1457ec681f3Smrg                        shift = 0
1467ec681f3Smrg                    else:
1477ec681f3Smrg                        sys.exit('Bad S_xxx_xxx define: {0}'.format(line))
1487ec681f3Smrg
1497ec681f3Smrg                num_bits = int(math.log2(unshifted_mask + 1))
1507ec681f3Smrg                if unshifted_mask != (1 << num_bits) - 1:
1517ec681f3Smrg                    sys.exit('Bad unshifted mask in {0}'.format(line))
1527ec681f3Smrg
1537ec681f3Smrg                self.__field = Object(
1547ec681f3Smrg                    name=name,
1557ec681f3Smrg                    bits=[shift, shift + num_bits - 1],
1567ec681f3Smrg                )
1577ec681f3Smrg                if comment is not None:
1587ec681f3Smrg                    self.__field.comment = comment
1597ec681f3Smrg                self.__enumentries = []
1607ec681f3Smrg
1617ec681f3Smrg            if prefix == 'R':
1627ec681f3Smrg                self.__fini_field()
1637ec681f3Smrg                self.__fini_register()
1647ec681f3Smrg
1657ec681f3Smrg                if regdb.register_mappings_by_name(name):
1667ec681f3Smrg                    sys.exit('Duplicate register define: {0}'.format(name))
1677ec681f3Smrg
1687ec681f3Smrg                address = int(split[1], 0)
1697ec681f3Smrg                if address != prefix_address:
1707ec681f3Smrg                    sys.exit('Inconsistent register address: {0}'.format(line))
1717ec681f3Smrg
1727ec681f3Smrg                self.__regmap = Object(
1737ec681f3Smrg                    name=name,
1747ec681f3Smrg                    chips=self.chips,
1757ec681f3Smrg                    map=Object(to=self.address_space, at=address),
1767ec681f3Smrg                )
1777ec681f3Smrg                self.__fields = []
1787ec681f3Smrg
1797ec681f3Smrg        self.__fini_field()
1807ec681f3Smrg        self.__fini_register()
1817ec681f3Smrg
1827ec681f3Smrgdef main():
1837ec681f3Smrg    map_to = sys.argv[1]
1847ec681f3Smrg
1857ec681f3Smrg    parser = HeaderParser(map_to)
1867ec681f3Smrg    parser.parse_header(sys.stdin)
1877ec681f3Smrg
1887ec681f3Smrg    deduplicate_enums(parser.regdb)
1897ec681f3Smrg    deduplicate_register_types(parser.regdb)
1907ec681f3Smrg
1917ec681f3Smrg    print(parser.regdb.encode_json_pretty())
1927ec681f3Smrg
1937ec681f3Smrg
1947ec681f3Smrgif __name__ == '__main__':
1957ec681f3Smrg    main()
1967ec681f3Smrg
1977ec681f3Smrg# kate: space-indent on; indent-width 4; replace-tabs on;
198