| # |
| # Copyright 2017-2019 Advanced Micro Devices, Inc. |
| # |
| # Permission is hereby granted, free of charge, to any person obtaining a |
| # copy of this software and associated documentation files (the "Software"), |
| # to deal in the Software without restriction, including without limitation |
| # on the rights to use, copy, modify, merge, publish, distribute, sub |
| # license, and/or sell copies of the Software, and to permit persons to whom |
| # the Software is furnished to do so, subject to the following conditions: |
| # |
| # The above copyright notice and this permission notice (including the next |
| # paragraph) shall be included in all copies or substantial portions of the |
| # Software. |
| # |
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| # FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL |
| # THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, |
| # DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
| # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE |
| # USE OR OTHER DEALINGS IN THE SOFTWARE. |
| # |
| """ |
| Helper script that parses a register header and produces a register database |
| as output. Use as: |
| |
| python3 parseheader.py ADDRESS_SPACE < header.h |
| |
| This script is included for reference -- we should be able to remove this in |
| the future. |
| """ |
| |
| import json |
| import math |
| import re |
| import sys |
| |
| from regdb import Object, RegisterDatabase, deduplicate_enums, deduplicate_register_types |
| |
| |
| RE_comment = re.compile(r'(/\*(.*)\*/)$|(//(.*))$') |
| RE_prefix = re.compile(r'([RSV])_([0-9a-fA-F]+)_') |
| RE_set_value = re.compile(r'\(\(\(unsigned\)\(x\) & ([0-9a-fA-Fx]+)\) << ([0-9]+)\)') |
| RE_set_value_no_shift = re.compile(r'\((\(unsigned\))?\(x\) & ([0-9a-fA-Fx]+)\)') |
| |
| class HeaderParser(object): |
| def __init__(self, address_space): |
| self.regdb = RegisterDatabase() |
| self.chips = ['gfx6', 'gfx7', 'gfx8', 'fiji', 'stoney', 'gfx9'] |
| self.address_space = address_space |
| |
| def __fini_field(self): |
| if self.__field is None: |
| return |
| |
| if self.__enumentries: |
| self.__field.enum_ref = self.__regmap.name + '__' + self.__field.name |
| self.regdb.add_enum(self.__field.enum_ref, Object( |
| entries=self.__enumentries |
| )) |
| self.__fields.append(self.__field) |
| |
| self.__enumentries = None |
| self.__field = None |
| |
| def __fini_register(self): |
| if self.__regmap is None: |
| return |
| |
| if self.__fields: |
| self.regdb.add_register_type(self.__regmap.name, Object( |
| fields=self.__fields |
| )) |
| self.__regmap.type_ref = self.__regmap.name |
| self.regdb.add_register_mapping(self.__regmap) |
| |
| self.__regmap = None |
| self.__fields = None |
| |
| def parse_header(self, filp): |
| regdb = RegisterDatabase() |
| chips = ['gfx6', 'gfx7', 'gfx8', 'fiji', 'stoney', 'gfx9'] |
| |
| self.__regmap = None |
| self.__fields = None |
| self.__field = None |
| self.__enumentries = None |
| |
| for line in filp: |
| if not line.startswith('#define '): |
| continue |
| |
| line = line[8:].strip() |
| |
| comment = None |
| m = RE_comment.search(line) |
| if m is not None: |
| comment = m.group(2) or m.group(4) |
| comment = comment.strip() |
| line = line[:m.span()[0]].strip() |
| |
| split = line.split(None, 1) |
| name = split[0] |
| |
| m = RE_prefix.match(name) |
| if m is None: |
| continue |
| |
| prefix = m.group(1) |
| prefix_address = int(m.group(2), 16) |
| name = name[m.span()[1]:] |
| |
| if prefix == 'V': |
| value = int(split[1], 0) |
| |
| for entry in self.__enumentries: |
| if name == entry.name: |
| sys.exit('Duplicate value define: name = {0}'.format(name)) |
| |
| entry = Object(name=name, value=value) |
| if comment is not None: |
| entry.comment = comment |
| self.__enumentries.append(entry) |
| continue |
| |
| if prefix == 'S': |
| self.__fini_field() |
| |
| if not name.endswith('(x)'): |
| sys.exit('Missing (x) in S line: {0}'.line) |
| name = name[:-3] |
| |
| for field in self.__fields: |
| if name == field.name: |
| sys.exit('Duplicate field define: {0}'.format(name)) |
| |
| m = RE_set_value.match(split[1]) |
| if m is not None: |
| unshifted_mask = int(m.group(1), 0) |
| shift = int(m.group(2), 0) |
| else: |
| m = RE_set_value_no_shift.match(split[1]) |
| if m is not None: |
| unshifted_mask = int(m.group(2), 0) |
| shift = 0 |
| else: |
| sys.exit('Bad S_xxx_xxx define: {0}'.format(line)) |
| |
| num_bits = int(math.log2(unshifted_mask + 1)) |
| if unshifted_mask != (1 << num_bits) - 1: |
| sys.exit('Bad unshifted mask in {0}'.format(line)) |
| |
| self.__field = Object( |
| name=name, |
| bits=[shift, shift + num_bits - 1], |
| ) |
| if comment is not None: |
| self.__field.comment = comment |
| self.__enumentries = [] |
| |
| if prefix == 'R': |
| self.__fini_field() |
| self.__fini_register() |
| |
| if regdb.register_mappings_by_name(name): |
| sys.exit('Duplicate register define: {0}'.format(name)) |
| |
| address = int(split[1], 0) |
| if address != prefix_address: |
| sys.exit('Inconsistent register address: {0}'.format(line)) |
| |
| self.__regmap = Object( |
| name=name, |
| chips=self.chips, |
| map=Object(to=self.address_space, at=address), |
| ) |
| self.__fields = [] |
| |
| self.__fini_field() |
| self.__fini_register() |
| |
| def main(): |
| map_to = sys.argv[1] |
| |
| parser = HeaderParser(map_to) |
| parser.parse_header(sys.stdin) |
| |
| deduplicate_enums(parser.regdb) |
| deduplicate_register_types(parser.regdb) |
| |
| print(parser.regdb.encode_json_pretty()) |
| |
| |
| if __name__ == '__main__': |
| main() |
| |
| # kate: space-indent on; indent-width 4; replace-tabs on; |