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 33import json 34import math 35import re 36import sys 37 38from regdb import Object, RegisterDatabase, deduplicate_enums, deduplicate_register_types 39 40 41RE_comment = re.compile(r'(/\*(.*)\*/)$|(//(.*))$') 42RE_prefix = re.compile(r'([RSV])_([0-9a-fA-F]+)_') 43RE_set_value = re.compile(r'\(\(\(unsigned\)\(x\) & ([0-9a-fA-Fx]+)\) << ([0-9]+)\)') 44RE_set_value_no_shift = re.compile(r'\((\(unsigned\))?\(x\) & ([0-9a-fA-Fx]+)\)') 45 46class HeaderParser(object): 47 def __init__(self, address_space): 48 self.regdb = RegisterDatabase() 49 self.chips = ['gfx6', 'gfx7', 'gfx8', 'fiji', 'stoney', 'gfx9'] 50 self.address_space = address_space 51 52 def __fini_field(self): 53 if self.__field is None: 54 return 55 56 if self.__enumentries: 57 self.__field.enum_ref = self.__regmap.name + '__' + self.__field.name 58 self.regdb.add_enum(self.__field.enum_ref, Object( 59 entries=self.__enumentries 60 )) 61 self.__fields.append(self.__field) 62 63 self.__enumentries = None 64 self.__field = None 65 66 def __fini_register(self): 67 if self.__regmap is None: 68 return 69 70 if self.__fields: 71 self.regdb.add_register_type(self.__regmap.name, Object( 72 fields=self.__fields 73 )) 74 self.__regmap.type_ref = self.__regmap.name 75 self.regdb.add_register_mapping(self.__regmap) 76 77 self.__regmap = None 78 self.__fields = None 79 80 def parse_header(self, filp): 81 regdb = RegisterDatabase() 82 chips = ['gfx6', 'gfx7', 'gfx8', 'fiji', 'stoney', 'gfx9'] 83 84 self.__regmap = None 85 self.__fields = None 86 self.__field = None 87 self.__enumentries = None 88 89 for line in filp: 90 if not line.startswith('#define '): 91 continue 92 93 line = line[8:].strip() 94 95 comment = None 96 m = RE_comment.search(line) 97 if m is not None: 98 comment = m.group(2) or m.group(4) 99 comment = comment.strip() 100 line = line[:m.span()[0]].strip() 101 102 split = line.split(None, 1) 103 name = split[0] 104 105 m = RE_prefix.match(name) 106 if m is None: 107 continue 108 109 prefix = m.group(1) 110 prefix_address = int(m.group(2), 16) 111 name = name[m.span()[1]:] 112 113 if prefix == 'V': 114 value = int(split[1], 0) 115 116 for entry in self.__enumentries: 117 if name == entry.name: 118 sys.exit('Duplicate value define: name = {0}'.format(name)) 119 120 entry = Object(name=name, value=value) 121 if comment is not None: 122 entry.comment = comment 123 self.__enumentries.append(entry) 124 continue 125 126 if prefix == 'S': 127 self.__fini_field() 128 129 if not name.endswith('(x)'): 130 sys.exit('Missing (x) in S line: {0}'.line) 131 name = name[:-3] 132 133 for field in self.__fields: 134 if name == field.name: 135 sys.exit('Duplicate field define: {0}'.format(name)) 136 137 m = RE_set_value.match(split[1]) 138 if m is not None: 139 unshifted_mask = int(m.group(1), 0) 140 shift = int(m.group(2), 0) 141 else: 142 m = RE_set_value_no_shift.match(split[1]) 143 if m is not None: 144 unshifted_mask = int(m.group(2), 0) 145 shift = 0 146 else: 147 sys.exit('Bad S_xxx_xxx define: {0}'.format(line)) 148 149 num_bits = int(math.log2(unshifted_mask + 1)) 150 if unshifted_mask != (1 << num_bits) - 1: 151 sys.exit('Bad unshifted mask in {0}'.format(line)) 152 153 self.__field = Object( 154 name=name, 155 bits=[shift, shift + num_bits - 1], 156 ) 157 if comment is not None: 158 self.__field.comment = comment 159 self.__enumentries = [] 160 161 if prefix == 'R': 162 self.__fini_field() 163 self.__fini_register() 164 165 if regdb.register_mappings_by_name(name): 166 sys.exit('Duplicate register define: {0}'.format(name)) 167 168 address = int(split[1], 0) 169 if address != prefix_address: 170 sys.exit('Inconsistent register address: {0}'.format(line)) 171 172 self.__regmap = Object( 173 name=name, 174 chips=self.chips, 175 map=Object(to=self.address_space, at=address), 176 ) 177 self.__fields = [] 178 179 self.__fini_field() 180 self.__fini_register() 181 182def main(): 183 map_to = sys.argv[1] 184 185 parser = HeaderParser(map_to) 186 parser.parse_header(sys.stdin) 187 188 deduplicate_enums(parser.regdb) 189 deduplicate_register_types(parser.regdb) 190 191 print(parser.regdb.encode_json_pretty()) 192 193 194if __name__ == '__main__': 195 main() 196 197# kate: space-indent on; indent-width 4; replace-tabs on; 198