1#!/usr/bin/env python3 2# Copyright © 2019 Intel Corporation 3# SPDX-License-Identifier: MIT 4 5from collections import OrderedDict 6import os 7import pathlib 8import re 9import xml.etree.ElementTree as et 10 11def get_filename(element): 12 return element.attrib['filename'] 13 14def get_name(element): 15 return element.attrib['name'] 16 17def get_value(element): 18 return int(element.attrib['value'], 0) 19 20def get_start(element): 21 return int(element.attrib['start'], 0) 22 23 24base_types = [ 25 'address', 26 'offset', 27 'int', 28 'uint', 29 'bool', 30 'float', 31] 32 33ufixed_pattern = re.compile(r"u(\d+)\.(\d+)") 34sfixed_pattern = re.compile(r"s(\d+)\.(\d+)") 35 36def is_base_type(name): 37 return name in base_types or sfixed_pattern.match(name) or ufixed_pattern.match(name) 38 39def add_struct_refs(items, node): 40 if node.tag == 'field': 41 if 'type' in node.attrib and not is_base_type(node.attrib['type']): 42 t = node.attrib['type'] 43 items[t] = True 44 return 45 if node.tag != 'struct' and node.tag != 'group': 46 return 47 for c in node: 48 add_struct_refs(items, c) 49 50 51class Struct(object): 52 def __init__(self, xml): 53 self.xml = xml 54 self.name = xml.attrib['name'] 55 self.deps = OrderedDict() 56 57 def find_deps(self, struct_dict, enum_dict): 58 deps = OrderedDict() 59 add_struct_refs(deps, self.xml) 60 for d in deps.keys(): 61 if d in struct_dict: 62 self.deps[d] = struct_dict[d] 63 else: 64 assert(d in enum_dict) 65 66 def add_xml(self, items): 67 for d in self.deps.values(): 68 d.add_xml(items) 69 items[self.name] = self.xml 70 71 72# ordering of the various tag attributes 73genxml_desc = { 74 'genxml' : [ 'name', 'gen', ], 75 'enum' : [ 'name', 'value', 'prefix', ], 76 'struct' : [ 'name', 'length', ], 77 'field' : [ 'name', 'start', 'end', 'type', 'default', 'prefix', ], 78 'instruction' : [ 'name', 'bias', 'length', 'engine', ], 79 'value' : [ 'name', 'value', ], 80 'group' : [ 'count', 'start', 'size', ], 81 'register' : [ 'name', 'length', 'num', ], 82} 83 84space_delta = 2 85 86def print_node(f, offset, node): 87 if node.tag in [ 'enum', 'struct', 'instruction', 'register' ]: 88 f.write('\n') 89 spaces = ''.rjust(offset * space_delta) 90 f.write('{0}<{1}'.format(spaces, node.tag)) 91 attribs = genxml_desc[node.tag] 92 for a in node.attrib: 93 assert(a in attribs) 94 for a in attribs: 95 if a in node.attrib: 96 f.write(' {0}="{1}"'.format(a, node.attrib[a])) 97 children = list(node) 98 if len(children) > 0: 99 f.write('>\n') 100 for c in children: 101 print_node(f, offset + 1, c) 102 f.write('{0}</{1}>\n'.format(spaces, node.tag)) 103 else: 104 f.write('/>\n') 105 106 107def process(filename): 108 xml = et.parse(filename) 109 genxml = xml.getroot() 110 111 enums = sorted(genxml.findall('enum'), key=get_name) 112 enum_dict = {} 113 for e in enums: 114 values = e.findall('./value') 115 e[:] = sorted(e, key=get_value) 116 enum_dict[e.attrib['name']] = e 117 118 # Structs are a bit annoying because they can refer to each other. We sort 119 # them alphabetically and then build a graph of depedencies. Finally we go 120 # through the alphabetically sorted list and print out dependencies first. 121 structs = sorted(xml.findall('./struct'), key=get_name) 122 wrapped_struct_dict = {} 123 for s in structs: 124 s[:] = sorted(s, key=get_start) 125 ws = Struct(s) 126 wrapped_struct_dict[ws.name] = ws 127 128 for s in wrapped_struct_dict: 129 wrapped_struct_dict[s].find_deps(wrapped_struct_dict, enum_dict) 130 131 sorted_structs = OrderedDict() 132 for _s in structs: 133 s = wrapped_struct_dict[_s.attrib['name']] 134 s.add_xml(sorted_structs) 135 136 instructions = sorted(xml.findall('./instruction'), key=get_name) 137 for i in instructions: 138 i[:] = sorted(i, key=get_start) 139 140 registers = sorted(xml.findall('./register'), key=get_name) 141 for r in registers: 142 r[:] = sorted(r, key=get_start) 143 144 genxml[:] = enums + list(sorted_structs.values()) + instructions + registers 145 146 with open(filename, 'w') as f: 147 f.write('<?xml version="1.0" ?>\n') 148 print_node(f, 0, genxml) 149 150 151if __name__ == '__main__': 152 folder = pathlib.Path('.') 153 for f in folder.glob('*.xml'): 154 print('Processing {}... '.format(f), end='', flush=True) 155 process(f) 156 print('done.') 157