1CopyRight = ''' 2/* 3 * Copyright 2015-2019 Advanced Micro Devices, Inc. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * on the rights to use, copy, modify, merge, publish, distribute, sub 9 * license, and/or sell copies of the Software, and to permit persons to whom 10 * the Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice (including the next 13 * paragraph) shall be included in all copies or substantial portions of the 14 * Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 20 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 21 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 22 * USE OR OTHER DEALINGS IN THE SOFTWARE. 23 * 24 */ 25''' 26 27from collections import defaultdict 28import functools 29import itertools 30import json 31import os.path 32import re 33import sys 34 35AMD_REGISTERS = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), "../registers")) 36sys.path.append(AMD_REGISTERS) 37 38from regdb import Object, RegisterDatabase 39 40 41def string_to_chars(string): 42 return "'" + "', '".join(string) + "', '\\0'," 43 44 45class StringTable: 46 """ 47 A class for collecting multiple strings in a single larger string that is 48 used by indexing (to avoid relocations in the resulting binary) 49 """ 50 def __init__(self): 51 self.table = [] 52 self.length = 0 53 54 def add(self, string): 55 # We might get lucky with string being a suffix of a previously added string 56 for te in self.table: 57 if te[0].endswith(string): 58 idx = te[1] + len(te[0]) - len(string) 59 te[2].add(idx) 60 return idx 61 62 idx = self.length 63 self.table.append((string, idx, set((idx,)))) 64 self.length += len(string) + 1 65 66 return idx 67 68 def emit(self, filp, name, static=True): 69 """ 70 Write 71 [static] const char name[] = "..."; 72 to filp. 73 """ 74 fragments = [ 75 '%s /* %s (%s) */' % ( 76 string_to_chars(te[0].encode('unicode_escape').decode()), 77 te[0].encode('unicode_escape').decode(), 78 ', '.join(str(idx) for idx in sorted(te[2])) 79 ) 80 for te in self.table 81 ] 82 filp.write('%sconst char %s[] = {\n%s\n};\n' % ( 83 'static ' if static else '', 84 name, 85 '\n'.join('\t' + fragment for fragment in fragments) 86 )) 87 88class IntTable: 89 """ 90 A class for collecting multiple arrays of integers in a single big array 91 that is used by indexing (to avoid relocations in the resulting binary) 92 """ 93 def __init__(self, typename): 94 self.typename = typename 95 self.table = [] 96 self.idxs = set() 97 98 def add(self, array): 99 # We might get lucky and find the array somewhere in the existing data 100 try: 101 idx = 0 102 while True: 103 idx = self.table.index(array[0], idx, len(self.table) - len(array) + 1) 104 105 for i in range(1, len(array)): 106 if array[i] != self.table[idx + i]: 107 break 108 else: 109 self.idxs.add(idx) 110 return idx 111 112 idx += 1 113 except ValueError: 114 pass 115 116 idx = len(self.table) 117 self.table += array 118 self.idxs.add(idx) 119 return idx 120 121 def emit(self, filp, name, static=True): 122 """ 123 Write 124 [static] const typename name[] = { ... }; 125 to filp. 126 """ 127 idxs = sorted(self.idxs) + [len(self.table)] 128 129 fragments = [ 130 ('\t/* %s */ %s' % ( 131 idxs[i], 132 ' '.join((str(elt) + ',') for elt in self.table[idxs[i]:idxs[i+1]]) 133 )) 134 for i in range(len(idxs) - 1) 135 ] 136 137 filp.write('%sconst %s %s[] = {\n%s\n};\n' % ( 138 'static ' if static else '', 139 self.typename, name, 140 '\n'.join(fragments) 141 )) 142 143class Field: 144 def __init__(self, name, bits): 145 self.name = name 146 self.bits = bits # [first, last] 147 self.values = [] # [(name, value), ...] 148 149 def format(self, string_table, idx_table): 150 mask = ((1 << (self.bits[1] - self.bits[0] + 1)) - 1) << self.bits[0] 151 if len(self.values): 152 values_offsets = [] 153 for value in self.values: 154 while value[1] >= len(values_offsets): 155 values_offsets.append(-1) 156 values_offsets[value[1]] = string_table.add(value[0]) 157 return '{{{0}, 0x{mask:X}, {1}, {2}}}'.format( 158 string_table.add(self.name), 159 len(values_offsets), idx_table.add(values_offsets), 160 **locals() 161 ) 162 else: 163 return '{{{0}, 0x{mask:X}}}'.format(string_table.add(self.name), **locals()) 164 165 def __eq__(self, other): 166 return (self.name == other.name and 167 self.bits[0] == other.bits[0] and self.bits[1] == other.bits[1] and 168 len(self.values) == len(other.values) and 169 all(a[0] == b[0] and a[1] == b[1] for a, b, in zip(self.values, other.values))) 170 171 def __ne__(self, other): 172 return not (self == other) 173 174 175class FieldTable: 176 """ 177 A class for collecting multiple arrays of register fields in a single big 178 array that is used by indexing (to avoid relocations in the resulting binary) 179 """ 180 def __init__(self): 181 self.table = [] 182 self.idxs = set() 183 self.name_to_idx = defaultdict(lambda: []) 184 185 def add(self, array): 186 """ 187 Add an array of Field objects, and return the index of where to find 188 the array in the table. 189 """ 190 # Check if we can find the array in the table already 191 for base_idx in self.name_to_idx.get(array[0].name, []): 192 if base_idx + len(array) > len(self.table): 193 continue 194 195 for i, a in enumerate(array): 196 b = self.table[base_idx + i] 197 if a != b: 198 break 199 else: 200 return base_idx 201 202 base_idx = len(self.table) 203 self.idxs.add(base_idx) 204 205 for field in array: 206 self.name_to_idx[field.name].append(len(self.table)) 207 self.table.append(field) 208 209 return base_idx 210 211 def emit(self, filp, string_table, idx_table): 212 """ 213 Write 214 static const struct si_field sid_fields_table[] = { ... }; 215 to filp. 216 """ 217 idxs = sorted(self.idxs) + [len(self.table)] 218 219 filp.write('static const struct si_field sid_fields_table[] = {\n') 220 221 for start, end in zip(idxs, idxs[1:]): 222 filp.write('\t/* %s */\n' % (start)) 223 for field in self.table[start:end]: 224 filp.write('\t%s,\n' % (field.format(string_table, idx_table))) 225 226 filp.write('};\n') 227 228 229def parse_packet3(filp): 230 """ 231 Parse PKT3 commands from the given header file. 232 """ 233 packets = [] 234 for line in filp: 235 if not line.startswith('#define '): 236 continue 237 238 line = line[8:].strip() 239 240 if line.startswith('PKT3_') and line.find('0x') != -1 and line.find('(') == -1: 241 packets.append(line.split()[0]) 242 return packets 243 244 245class TableWriter(object): 246 def __init__(self): 247 self.__strings = StringTable() 248 self.__strings_offsets = IntTable('int') 249 self.__fields = FieldTable() 250 251 def write(self, regdb, packets, file=sys.stdout): 252 def out(*args): 253 print(*args, file=file) 254 255 out('/* This file is autogenerated by sid_tables.py from sid.h. Do not edit directly. */') 256 out() 257 out(CopyRight.strip()) 258 out(''' 259#ifndef SID_TABLES_H 260#define SID_TABLES_H 261 262struct si_field { 263 unsigned name_offset; 264 unsigned mask; 265 unsigned num_values; 266 unsigned values_offset; /* offset into sid_strings_offsets */ 267}; 268 269struct si_reg { 270 unsigned name_offset; 271 unsigned offset; 272 unsigned num_fields; 273 unsigned fields_offset; 274}; 275 276struct si_packet3 { 277 unsigned name_offset; 278 unsigned op; 279}; 280''') 281 282 out('static const struct si_packet3 packet3_table[] = {') 283 for pkt in packets: 284 out('\t{%s, %s},' % (self.__strings.add(pkt[5:]), pkt)) 285 out('};') 286 out() 287 288 regmaps_by_chip = defaultdict(list) 289 290 for regmap in regdb.register_mappings(): 291 for chip in regmap.chips: 292 regmaps_by_chip[chip].append(regmap) 293 294 regtypes = {} 295 296 # Sorted iteration over chips for deterministic builds 297 for chip in sorted(regmaps_by_chip.keys()): 298 regmaps = regmaps_by_chip[chip] 299 regmaps.sort(key=lambda regmap: (regmap.map.to, regmap.map.at)) 300 301 out('static const struct si_reg {chip}_reg_table[] = {{'.format(**locals())) 302 303 for regmap in regmaps: 304 if hasattr(regmap, 'type_ref'): 305 if not regmap.type_ref in regtypes: 306 regtype = regdb.register_type(regmap.type_ref) 307 fields = [] 308 for dbfield in regtype.fields: 309 field = Field(dbfield.name, dbfield.bits) 310 if hasattr(dbfield, 'enum_ref'): 311 enum = regdb.enum(dbfield.enum_ref) 312 for entry in enum.entries: 313 field.values.append((entry.name, entry.value)) 314 fields.append(field) 315 316 num_fields = len(regtype.fields) 317 fields_offset = self.__fields.add(fields) 318 regtypes[regmap.type_ref] = (num_fields, fields_offset) 319 else: 320 num_fields, fields_offset = regtypes[regmap.type_ref] 321 322 print('\t{{{0}, {regmap.map.at}, {num_fields}, {fields_offset}}},' 323 .format(self.__strings.add(regmap.name), **locals())) 324 else: 325 print('\t{{{0}, {regmap.map.at}}},' 326 .format(self.__strings.add(regmap.name), **locals())) 327 328 out('};\n') 329 330 self.__fields.emit(file, self.__strings, self.__strings_offsets) 331 332 out() 333 334 self.__strings.emit(file, "sid_strings") 335 336 out() 337 338 self.__strings_offsets.emit(file, "sid_strings_offsets") 339 340 out() 341 out('#endif') 342 343 344def main(): 345 # Parse PKT3 types 346 with open(sys.argv[1], 'r') as filp: 347 packets = parse_packet3(filp) 348 349 # Register database parse 350 regdb = None 351 for filename in sys.argv[2:]: 352 with open(filename, 'r') as filp: 353 try: 354 db = RegisterDatabase.from_json(json.load(filp)) 355 if regdb is None: 356 regdb = db 357 else: 358 regdb.update(db) 359 except json.JSONDecodeError as e: 360 print('Error reading {}'.format(sys.argv[1]), file=sys.stderr) 361 raise 362 363 # The ac_debug code only distinguishes by gfx_level 364 regdb.merge_chips(['gfx8', 'fiji', 'stoney'], 'gfx8') 365 366 # Write it all out 367 w = TableWriter() 368 w.write(regdb, packets) 369 370if __name__ == '__main__': 371 main() 372 373# kate: space-indent on; indent-width 4; replace-tabs on; 374