1# 2# Copyright 2017-2019 Advanced Micro Devices, Inc. 3# 4# SPDX-License-Identifier: MIT 5# 6""" 7Helper script that parses a register header and produces a register database 8as output. Use as: 9 10 python3 parseheader.py ADDRESS_SPACE < header.h 11 12This script is included for reference -- we should be able to remove this in 13the future. 14""" 15 16import json 17import math 18import re 19import sys 20 21from regdb import Object, RegisterDatabase, deduplicate_enums, deduplicate_register_types 22 23 24RE_comment = re.compile(r'(/\*(.*)\*/)$|(//(.*))$') 25RE_prefix = re.compile(r'([RSV])_([0-9a-fA-F]+)_') 26RE_set_value = re.compile(r'\(\(\(unsigned\)\(x\) & ([0-9a-fA-Fx]+)\) << ([0-9]+)\)') 27RE_set_value_no_shift = re.compile(r'\((\(unsigned\))?\(x\) & ([0-9a-fA-Fx]+)\)') 28 29class HeaderParser(object): 30 def __init__(self, address_space): 31 self.regdb = RegisterDatabase() 32 self.chips = ['gfx6', 'gfx7', 'gfx8', 'fiji', 'stoney', 'gfx9'] 33 self.address_space = address_space 34 35 def __fini_field(self): 36 if self.__field is None: 37 return 38 39 if self.__enumentries: 40 self.__field.enum_ref = self.__regmap.name + '__' + self.__field.name 41 self.regdb.add_enum(self.__field.enum_ref, Object( 42 entries=self.__enumentries 43 )) 44 self.__fields.append(self.__field) 45 46 self.__enumentries = None 47 self.__field = None 48 49 def __fini_register(self): 50 if self.__regmap is None: 51 return 52 53 if self.__fields: 54 self.regdb.add_register_type(self.__regmap.name, Object( 55 fields=self.__fields 56 )) 57 self.__regmap.type_ref = self.__regmap.name 58 self.regdb.add_register_mapping(self.__regmap) 59 60 self.__regmap = None 61 self.__fields = None 62 63 def parse_header(self, filp): 64 regdb = RegisterDatabase() 65 chips = ['gfx6', 'gfx7', 'gfx8', 'fiji', 'stoney', 'gfx9'] 66 67 self.__regmap = None 68 self.__fields = None 69 self.__field = None 70 self.__enumentries = None 71 72 for line in filp: 73 if not line.startswith('#define '): 74 continue 75 76 line = line[8:].strip() 77 78 comment = None 79 m = RE_comment.search(line) 80 if m is not None: 81 comment = m.group(2) or m.group(4) 82 comment = comment.strip() 83 line = line[:m.span()[0]].strip() 84 85 split = line.split(None, 1) 86 name = split[0] 87 88 m = RE_prefix.match(name) 89 if m is None: 90 continue 91 92 prefix = m.group(1) 93 prefix_address = int(m.group(2), 16) 94 name = name[m.span()[1]:] 95 96 if prefix == 'V': 97 value = int(split[1], 0) 98 99 for entry in self.__enumentries: 100 if name == entry.name: 101 sys.exit('Duplicate value define: name = {0}'.format(name)) 102 103 entry = Object(name=name, value=value) 104 if comment is not None: 105 entry.comment = comment 106 self.__enumentries.append(entry) 107 continue 108 109 if prefix == 'S': 110 self.__fini_field() 111 112 if not name.endswith('(x)'): 113 sys.exit('Missing (x) in S line: {0}'.line) 114 name = name[:-3] 115 116 for field in self.__fields: 117 if name == field.name: 118 sys.exit('Duplicate field define: {0}'.format(name)) 119 120 m = RE_set_value.match(split[1]) 121 if m is not None: 122 unshifted_mask = int(m.group(1), 0) 123 shift = int(m.group(2), 0) 124 else: 125 m = RE_set_value_no_shift.match(split[1]) 126 if m is not None: 127 unshifted_mask = int(m.group(2), 0) 128 shift = 0 129 else: 130 sys.exit('Bad S_xxx_xxx define: {0}'.format(line)) 131 132 num_bits = int(math.log2(unshifted_mask + 1)) 133 if unshifted_mask != (1 << num_bits) - 1: 134 sys.exit('Bad unshifted mask in {0}'.format(line)) 135 136 self.__field = Object( 137 name=name, 138 bits=[shift, shift + num_bits - 1], 139 ) 140 if comment is not None: 141 self.__field.comment = comment 142 self.__enumentries = [] 143 144 if prefix == 'R': 145 self.__fini_field() 146 self.__fini_register() 147 148 if regdb.register_mappings_by_name(name): 149 sys.exit('Duplicate register define: {0}'.format(name)) 150 151 address = int(split[1], 0) 152 if address != prefix_address: 153 sys.exit('Inconsistent register address: {0}'.format(line)) 154 155 self.__regmap = Object( 156 name=name, 157 chips=self.chips, 158 map=Object(to=self.address_space, at=address), 159 ) 160 self.__fields = [] 161 162 self.__fini_field() 163 self.__fini_register() 164 165def main(): 166 map_to = sys.argv[1] 167 168 parser = HeaderParser(map_to) 169 parser.parse_header(sys.stdin) 170 171 deduplicate_enums(parser.regdb) 172 deduplicate_register_types(parser.regdb) 173 174 print(parser.regdb.encode_json_pretty()) 175 176 177if __name__ == '__main__': 178 main() 179 180# kate: space-indent on; indent-width 4; replace-tabs on; 181