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