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