198 lines
6.5 KiB
Python
198 lines
6.5 KiB
Python
#
|
|
# Copyright 2017-2019 Advanced Micro Devices, Inc.
|
|
#
|
|
# Permission is hereby granted, free of charge, to any person obtaining a
|
|
# copy of this software and associated documentation files (the "Software"),
|
|
# to deal in the Software without restriction, including without limitation
|
|
# on the rights to use, copy, modify, merge, publish, distribute, sub
|
|
# license, and/or sell copies of the Software, and to permit persons to whom
|
|
# the Software is furnished to do so, subject to the following conditions:
|
|
#
|
|
# The above copyright notice and this permission notice (including the next
|
|
# paragraph) shall be included in all copies or substantial portions of the
|
|
# Software.
|
|
#
|
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
|
|
# THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
|
|
# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
|
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
|
# USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
#
|
|
"""
|
|
Helper script that parses a register header and produces a register database
|
|
as output. Use as:
|
|
|
|
python3 parseheader.py ADDRESS_SPACE < header.h
|
|
|
|
This script is included for reference -- we should be able to remove this in
|
|
the future.
|
|
"""
|
|
|
|
import json
|
|
import math
|
|
import re
|
|
import sys
|
|
|
|
from regdb import Object, RegisterDatabase, deduplicate_enums, deduplicate_register_types
|
|
|
|
|
|
RE_comment = re.compile(r'(/\*(.*)\*/)$|(//(.*))$')
|
|
RE_prefix = re.compile(r'([RSV])_([0-9a-fA-F]+)_')
|
|
RE_set_value = re.compile(r'\(\(\(unsigned\)\(x\) & ([0-9a-fA-Fx]+)\) << ([0-9]+)\)')
|
|
RE_set_value_no_shift = re.compile(r'\((\(unsigned\))?\(x\) & ([0-9a-fA-Fx]+)\)')
|
|
|
|
class HeaderParser(object):
|
|
def __init__(self, address_space):
|
|
self.regdb = RegisterDatabase()
|
|
self.chips = ['gfx6', 'gfx7', 'gfx8', 'fiji', 'stoney', 'gfx9']
|
|
self.address_space = address_space
|
|
|
|
def __fini_field(self):
|
|
if self.__field is None:
|
|
return
|
|
|
|
if self.__enumentries:
|
|
self.__field.enum_ref = self.__regmap.name + '__' + self.__field.name
|
|
self.regdb.add_enum(self.__field.enum_ref, Object(
|
|
entries=self.__enumentries
|
|
))
|
|
self.__fields.append(self.__field)
|
|
|
|
self.__enumentries = None
|
|
self.__field = None
|
|
|
|
def __fini_register(self):
|
|
if self.__regmap is None:
|
|
return
|
|
|
|
if self.__fields:
|
|
self.regdb.add_register_type(self.__regmap.name, Object(
|
|
fields=self.__fields
|
|
))
|
|
self.__regmap.type_ref = self.__regmap.name
|
|
self.regdb.add_register_mapping(self.__regmap)
|
|
|
|
self.__regmap = None
|
|
self.__fields = None
|
|
|
|
def parse_header(self, filp):
|
|
regdb = RegisterDatabase()
|
|
chips = ['gfx6', 'gfx7', 'gfx8', 'fiji', 'stoney', 'gfx9']
|
|
|
|
self.__regmap = None
|
|
self.__fields = None
|
|
self.__field = None
|
|
self.__enumentries = None
|
|
|
|
for line in filp:
|
|
if not line.startswith('#define '):
|
|
continue
|
|
|
|
line = line[8:].strip()
|
|
|
|
comment = None
|
|
m = RE_comment.search(line)
|
|
if m is not None:
|
|
comment = m.group(2) or m.group(4)
|
|
comment = comment.strip()
|
|
line = line[:m.span()[0]].strip()
|
|
|
|
split = line.split(None, 1)
|
|
name = split[0]
|
|
|
|
m = RE_prefix.match(name)
|
|
if m is None:
|
|
continue
|
|
|
|
prefix = m.group(1)
|
|
prefix_address = int(m.group(2), 16)
|
|
name = name[m.span()[1]:]
|
|
|
|
if prefix == 'V':
|
|
value = int(split[1], 0)
|
|
|
|
for entry in self.__enumentries:
|
|
if name == entry.name:
|
|
sys.exit('Duplicate value define: name = {0}'.format(name))
|
|
|
|
entry = Object(name=name, value=value)
|
|
if comment is not None:
|
|
entry.comment = comment
|
|
self.__enumentries.append(entry)
|
|
continue
|
|
|
|
if prefix == 'S':
|
|
self.__fini_field()
|
|
|
|
if not name.endswith('(x)'):
|
|
sys.exit('Missing (x) in S line: {0}'.line)
|
|
name = name[:-3]
|
|
|
|
for field in self.__fields:
|
|
if name == field.name:
|
|
sys.exit('Duplicate field define: {0}'.format(name))
|
|
|
|
m = RE_set_value.match(split[1])
|
|
if m is not None:
|
|
unshifted_mask = int(m.group(1), 0)
|
|
shift = int(m.group(2), 0)
|
|
else:
|
|
m = RE_set_value_no_shift.match(split[1])
|
|
if m is not None:
|
|
unshifted_mask = int(m.group(2), 0)
|
|
shift = 0
|
|
else:
|
|
sys.exit('Bad S_xxx_xxx define: {0}'.format(line))
|
|
|
|
num_bits = int(math.log2(unshifted_mask + 1))
|
|
if unshifted_mask != (1 << num_bits) - 1:
|
|
sys.exit('Bad unshifted mask in {0}'.format(line))
|
|
|
|
self.__field = Object(
|
|
name=name,
|
|
bits=[shift, shift + num_bits - 1],
|
|
)
|
|
if comment is not None:
|
|
self.__field.comment = comment
|
|
self.__enumentries = []
|
|
|
|
if prefix == 'R':
|
|
self.__fini_field()
|
|
self.__fini_register()
|
|
|
|
if regdb.register_mappings_by_name(name):
|
|
sys.exit('Duplicate register define: {0}'.format(name))
|
|
|
|
address = int(split[1], 0)
|
|
if address != prefix_address:
|
|
sys.exit('Inconsistent register address: {0}'.format(line))
|
|
|
|
self.__regmap = Object(
|
|
name=name,
|
|
chips=self.chips,
|
|
map=Object(to=self.address_space, at=address),
|
|
)
|
|
self.__fields = []
|
|
|
|
self.__fini_field()
|
|
self.__fini_register()
|
|
|
|
def main():
|
|
map_to = sys.argv[1]
|
|
|
|
parser = HeaderParser(map_to)
|
|
parser.parse_header(sys.stdin)
|
|
|
|
deduplicate_enums(parser.regdb)
|
|
deduplicate_register_types(parser.regdb)
|
|
|
|
print(parser.regdb.encode_json_pretty())
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|
|
|
|
# kate: space-indent on; indent-width 4; replace-tabs on;
|