Path: blob/21.2-virgl/src/amd/common/sid_tables.py
7132 views
from __future__ import print_function, division, unicode_literals12CopyRight = '''3/*4* Copyright 2015-2019 Advanced Micro Devices, Inc.5*6* Permission is hereby granted, free of charge, to any person obtaining a7* copy of this software and associated documentation files (the "Software"),8* to deal in the Software without restriction, including without limitation9* on the rights to use, copy, modify, merge, publish, distribute, sub10* license, and/or sell copies of the Software, and to permit persons to whom11* the Software is furnished to do so, subject to the following conditions:12*13* The above copyright notice and this permission notice (including the next14* paragraph) shall be included in all copies or substantial portions of the15* Software.16*17* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR18* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,19* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL20* THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,21* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR22* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE23* USE OR OTHER DEALINGS IN THE SOFTWARE.24*25*/26'''2728from collections import defaultdict29import functools30import itertools31import json32import os.path33import re34import sys3536AMD_REGISTERS = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), "../registers"))37sys.path.append(AMD_REGISTERS)3839from regdb import Object, RegisterDatabase404142def string_to_chars(string):43return "'" + "', '".join(string) + "', '\\0',"444546class StringTable:47"""48A class for collecting multiple strings in a single larger string that is49used by indexing (to avoid relocations in the resulting binary)50"""51def __init__(self):52self.table = []53self.length = 05455def add(self, string):56# We might get lucky with string being a suffix of a previously added string57for te in self.table:58if te[0].endswith(string):59idx = te[1] + len(te[0]) - len(string)60te[2].add(idx)61return idx6263idx = self.length64self.table.append((string, idx, set((idx,))))65self.length += len(string) + 16667return idx6869def emit(self, filp, name, static=True):70"""71Write72[static] const char name[] = "...";73to filp.74"""75fragments = [76'%s /* %s (%s) */' % (77string_to_chars(te[0].encode('unicode_escape').decode()),78te[0].encode('unicode_escape').decode(),79', '.join(str(idx) for idx in sorted(te[2]))80)81for te in self.table82]83filp.write('%sconst char %s[] = {\n%s\n};\n' % (84'static ' if static else '',85name,86'\n'.join('\t' + fragment for fragment in fragments)87))8889class IntTable:90"""91A class for collecting multiple arrays of integers in a single big array92that is used by indexing (to avoid relocations in the resulting binary)93"""94def __init__(self, typename):95self.typename = typename96self.table = []97self.idxs = set()9899def add(self, array):100# We might get lucky and find the array somewhere in the existing data101try:102idx = 0103while True:104idx = self.table.index(array[0], idx, len(self.table) - len(array) + 1)105106for i in range(1, len(array)):107if array[i] != self.table[idx + i]:108break109else:110self.idxs.add(idx)111return idx112113idx += 1114except ValueError:115pass116117idx = len(self.table)118self.table += array119self.idxs.add(idx)120return idx121122def emit(self, filp, name, static=True):123"""124Write125[static] const typename name[] = { ... };126to filp.127"""128idxs = sorted(self.idxs) + [len(self.table)]129130fragments = [131('\t/* %s */ %s' % (132idxs[i],133' '.join((str(elt) + ',') for elt in self.table[idxs[i]:idxs[i+1]])134))135for i in range(len(idxs) - 1)136]137138filp.write('%sconst %s %s[] = {\n%s\n};\n' % (139'static ' if static else '',140self.typename, name,141'\n'.join(fragments)142))143144class Field:145def __init__(self, name, bits):146self.name = name147self.bits = bits # [first, last]148self.values = [] # [(name, value), ...]149150def format(self, string_table, idx_table):151mask = ((1 << (self.bits[1] - self.bits[0] + 1)) - 1) << self.bits[0]152if len(self.values):153values_offsets = []154for value in self.values:155while value[1] >= len(values_offsets):156values_offsets.append(-1)157values_offsets[value[1]] = string_table.add(value[0])158return '{{{0}, 0x{mask:X}, {1}, {2}}}'.format(159string_table.add(self.name),160len(values_offsets), idx_table.add(values_offsets),161**locals()162)163else:164return '{{{0}, 0x{mask:X}}}'.format(string_table.add(self.name), **locals())165166def __eq__(self, other):167return (self.name == other.name and168self.bits[0] == other.bits[0] and self.bits[1] == other.bits[1] and169len(self.values) == len(other.values) and170all(a[0] == b[0] and a[1] == b[1] for a, b, in zip(self.values, other.values)))171172def __ne__(self, other):173return not (self == other)174175176class FieldTable:177"""178A class for collecting multiple arrays of register fields in a single big179array that is used by indexing (to avoid relocations in the resulting binary)180"""181def __init__(self):182self.table = []183self.idxs = set()184self.name_to_idx = defaultdict(lambda: [])185186def add(self, array):187"""188Add an array of Field objects, and return the index of where to find189the array in the table.190"""191# Check if we can find the array in the table already192for base_idx in self.name_to_idx.get(array[0].name, []):193if base_idx + len(array) > len(self.table):194continue195196for i, a in enumerate(array):197b = self.table[base_idx + i]198if a != b:199break200else:201return base_idx202203base_idx = len(self.table)204self.idxs.add(base_idx)205206for field in array:207self.name_to_idx[field.name].append(len(self.table))208self.table.append(field)209210return base_idx211212def emit(self, filp, string_table, idx_table):213"""214Write215static const struct si_field sid_fields_table[] = { ... };216to filp.217"""218idxs = sorted(self.idxs) + [len(self.table)]219220filp.write('static const struct si_field sid_fields_table[] = {\n')221222for start, end in zip(idxs, idxs[1:]):223filp.write('\t/* %s */\n' % (start))224for field in self.table[start:end]:225filp.write('\t%s,\n' % (field.format(string_table, idx_table)))226227filp.write('};\n')228229230def parse_packet3(filp):231"""232Parse PKT3 commands from the given header file.233"""234packets = []235for line in filp:236if not line.startswith('#define '):237continue238239line = line[8:].strip()240241if line.startswith('PKT3_') and line.find('0x') != -1 and line.find('(') == -1:242packets.append(line.split()[0])243return packets244245246class TableWriter(object):247def __init__(self):248self.__strings = StringTable()249self.__strings_offsets = IntTable('int')250self.__fields = FieldTable()251252def write(self, regdb, packets, file=sys.stdout):253def out(*args):254print(*args, file=file)255256out('/* This file is autogenerated by sid_tables.py from sid.h. Do not edit directly. */')257out()258out(CopyRight.strip())259out('''260#ifndef SID_TABLES_H261#define SID_TABLES_H262263struct si_field {264unsigned name_offset;265unsigned mask;266unsigned num_values;267unsigned values_offset; /* offset into sid_strings_offsets */268};269270struct si_reg {271unsigned name_offset;272unsigned offset;273unsigned num_fields;274unsigned fields_offset;275};276277struct si_packet3 {278unsigned name_offset;279unsigned op;280};281''')282283out('static const struct si_packet3 packet3_table[] = {')284for pkt in packets:285out('\t{%s, %s},' % (self.__strings.add(pkt[5:]), pkt))286out('};')287out()288289regmaps_by_chip = defaultdict(list)290291for regmap in regdb.register_mappings():292for chip in regmap.chips:293regmaps_by_chip[chip].append(regmap)294295regtypes = {}296297# Sorted iteration over chips for deterministic builds298for chip in sorted(regmaps_by_chip.keys()):299regmaps = regmaps_by_chip[chip]300regmaps.sort(key=lambda regmap: (regmap.map.to, regmap.map.at))301302out('static const struct si_reg {chip}_reg_table[] = {{'.format(**locals()))303304for regmap in regmaps:305if hasattr(regmap, 'type_ref'):306if not regmap.type_ref in regtypes:307regtype = regdb.register_type(regmap.type_ref)308fields = []309for dbfield in regtype.fields:310field = Field(dbfield.name, dbfield.bits)311if hasattr(dbfield, 'enum_ref'):312enum = regdb.enum(dbfield.enum_ref)313for entry in enum.entries:314field.values.append((entry.name, entry.value))315fields.append(field)316317num_fields = len(regtype.fields)318fields_offset = self.__fields.add(fields)319regtypes[regmap.type_ref] = (num_fields, fields_offset)320else:321num_fields, fields_offset = regtypes[regmap.type_ref]322323print('\t{{{0}, {regmap.map.at}, {num_fields}, {fields_offset}}},'324.format(self.__strings.add(regmap.name), **locals()))325else:326print('\t{{{0}, {regmap.map.at}}},'327.format(self.__strings.add(regmap.name), **locals()))328329out('};\n')330331self.__fields.emit(file, self.__strings, self.__strings_offsets)332333out()334335self.__strings.emit(file, "sid_strings")336337out()338339self.__strings_offsets.emit(file, "sid_strings_offsets")340341out()342out('#endif')343344345def main():346# Parse PKT3 types347with open(sys.argv[1], 'r') as filp:348packets = parse_packet3(filp)349350# Register database parse351regdb = None352for filename in sys.argv[2:]:353with open(filename, 'r') as filp:354try:355db = RegisterDatabase.from_json(json.load(filp))356if regdb is None:357regdb = db358else:359regdb.update(db)360except json.JSONDecodeError as e:361print('Error reading {}'.format(sys.argv[1]), file=sys.stderr)362raise363364# The ac_debug code only distinguishes by chip_class365regdb.merge_chips(['gfx8', 'fiji', 'stoney'], 'gfx8')366367# Write it all out368w = TableWriter()369w.write(regdb, packets)370371if __name__ == '__main__':372main()373374# kate: space-indent on; indent-width 4; replace-tabs on;375376377