1CopyRight = ''' 2/* 3 * Copyright 2015 Advanced Micro Devices, Inc. 4 * SPDX-License-Identifier: MIT 5 */ 6''' 7 8import sys 9import re 10 11 12class StringTable: 13 """ 14 A class for collecting multiple strings in a single larger string that is 15 used by indexing (to avoid relocations in the resulting binary) 16 """ 17 def __init__(self): 18 self.table = [] 19 self.length = 0 20 21 def add(self, string): 22 # We might get lucky with string being a suffix of a previously added string 23 for te in self.table: 24 if te[0].endswith(string): 25 idx = te[1] + len(te[0]) - len(string) 26 te[2].add(idx) 27 return idx 28 29 idx = self.length 30 self.table.append((string, idx, set((idx,)))) 31 self.length += len(string) + 1 32 33 return idx 34 35 def emit(self, filp, name, static=True): 36 """ 37 Write 38 [static] const char name[] = "..."; 39 to filp. 40 """ 41 fragments = [ 42 '"%s\\0" /* %s */' % ( 43 te[0].encode('unicode_escape').decode(), 44 ', '.join(str(idx) for idx in te[2]) 45 ) 46 for te in self.table 47 ] 48 filp.write('%sconst char %s[] =\n%s;\n' % ( 49 'static ' if static else '', 50 name, 51 '\n'.join('\t' + fragment for fragment in fragments) 52 )) 53 54class IntTable: 55 """ 56 A class for collecting multiple arrays of integers in a single big array 57 that is used by indexing (to avoid relocations in the resulting binary) 58 """ 59 def __init__(self, typename): 60 self.typename = typename 61 self.table = [] 62 self.idxs = set() 63 64 def add(self, array): 65 # We might get lucky and find the array somewhere in the existing data 66 try: 67 idx = 0 68 while True: 69 idx = self.table.index(array[0], idx, len(self.table) - len(array) + 1) 70 71 for i in range(1, len(array)): 72 if array[i] != self.table[idx + i]: 73 break 74 else: 75 self.idxs.add(idx) 76 return idx 77 78 idx += 1 79 except ValueError: 80 pass 81 82 idx = len(self.table) 83 self.table += array 84 self.idxs.add(idx) 85 return idx 86 87 def emit(self, filp, name, static=True): 88 """ 89 Write 90 [static] const typename name[] = { ... }; 91 to filp. 92 """ 93 idxs = sorted(self.idxs) + [len(self.table)] 94 95 fragments = [ 96 ('\t/* %s */ %s' % ( 97 idxs[i], 98 ' '.join((str(elt) + ',') for elt in self.table[idxs[i]:idxs[i+1]]) 99 )) 100 for i in range(len(idxs) - 1) 101 ] 102 103 filp.write('%sconst %s %s[] = {\n%s\n};\n' % ( 104 'static ' if static else '', 105 self.typename, name, 106 '\n'.join(fragments) 107 )) 108 109class Field: 110 def __init__(self, reg, s_name): 111 self.s_name = s_name 112 self.name = strip_prefix(s_name) 113 self.values = [] 114 self.varname_values = '%s__%s__values' % (reg.r_name.lower(), self.name.lower()) 115 116class Reg: 117 def __init__(self, r_name): 118 self.r_name = r_name 119 self.name = strip_prefix(r_name) 120 self.fields = [] 121 self.own_fields = True 122 123 124def strip_prefix(s): 125 '''Strip prefix in the form ._.*_, e.g. R_001234_''' 126 return s[s[2:].find('_')+3:] 127 128def parse(filename, regs, packets): 129 stream = open(filename) 130 131 for line in stream: 132 if not line.startswith('#define '): 133 continue 134 135 line = line[8:].strip() 136 137 if line.startswith('R_'): 138 name = line.split()[0] 139 140 for it in regs: 141 if it.r_name == name: 142 reg = it 143 break 144 else: 145 reg = Reg(name) 146 regs.append(reg) 147 148 elif line.startswith('S_'): 149 name = line[:line.find('(')] 150 151 for it in reg.fields: 152 if it.s_name == name: 153 field = it 154 break 155 else: 156 field = Field(reg, name) 157 reg.fields.append(field) 158 159 elif line.startswith('V_'): 160 split = line.split() 161 name = split[0] 162 value = int(split[1], 0) 163 164 for (n,v) in field.values: 165 if n == name: 166 if v != value: 167 sys.exit('Value mismatch: name = ' + name) 168 169 field.values.append((name, value)) 170 171 elif line.startswith('PKT3_') and line.find('0x') != -1 and line.find('(') == -1: 172 packets.append(line.split()[0]) 173 174 # Copy fields to indexed registers which have their fields only defined 175 # at register index 0. 176 # For example, copy fields from CB_COLOR0_INFO to CB_COLORn_INFO, n > 0. 177 match_number = re.compile('[0-9]+') 178 reg_dict = dict() 179 180 # Create a dict of registers with fields and '0' in their name 181 for reg in regs: 182 if len(reg.fields) and reg.name.find('0') != -1: 183 reg_dict[reg.name] = reg 184 185 # Assign fields 186 for reg in regs: 187 if not len(reg.fields): 188 reg0 = reg_dict.get(match_number.sub('0', reg.name)) 189 if reg0 != None: 190 reg.fields = reg0.fields 191 reg.fields_owner = reg0 192 reg.own_fields = False 193 194 195def write_tables(regs, packets): 196 197 strings = StringTable() 198 strings_offsets = IntTable("int") 199 200 print('/* This file is autogenerated by egd_tables.py from evergreend.h. Do not edit directly. */') 201 print() 202 print(CopyRight.strip()) 203 print(''' 204#ifndef EG_TABLES_H 205#define EG_TABLES_H 206 207struct eg_field { 208 unsigned name_offset; 209 unsigned mask; 210 unsigned num_values; 211 unsigned values_offset; /* offset into eg_strings_offsets */ 212}; 213 214struct eg_reg { 215 unsigned name_offset; 216 unsigned offset; 217 unsigned num_fields; 218 unsigned fields_offset; 219}; 220 221struct eg_packet3 { 222 unsigned name_offset; 223 unsigned op; 224}; 225''') 226 227 print('static const struct eg_packet3 packet3_table[] = {') 228 for pkt in packets: 229 print('\t{%s, %s},' % (strings.add(pkt[5:]), pkt)) 230 print('};') 231 print() 232 233 print('static const struct eg_field egd_fields_table[] = {') 234 235 fields_idx = 0 236 for reg in regs: 237 if len(reg.fields) and reg.own_fields: 238 print('\t/* %s */' % (fields_idx)) 239 240 reg.fields_idx = fields_idx 241 242 for field in reg.fields: 243 if len(field.values): 244 values_offsets = [] 245 for value in field.values: 246 while value[1] >= len(values_offsets): 247 values_offsets.append(-1) 248 values_offsets[value[1]] = strings.add(strip_prefix(value[0])) 249 print('\t{%s, %s(~0u), %s, %s},' % ( 250 strings.add(field.name), field.s_name, 251 len(values_offsets), strings_offsets.add(values_offsets))) 252 else: 253 print('\t{%s, %s(~0u)},' % (strings.add(field.name), field.s_name)) 254 fields_idx += 1 255 256 print('};') 257 print() 258 259 print('static const struct eg_reg egd_reg_table[] = {') 260 for reg in regs: 261 if len(reg.fields): 262 print('\t{%s, %s, %s, %s},' % (strings.add(reg.name), reg.r_name, 263 len(reg.fields), reg.fields_idx if reg.own_fields else reg.fields_owner.fields_idx)) 264 else: 265 print('\t{%s, %s},' % (strings.add(reg.name), reg.r_name)) 266 print('};') 267 print() 268 269 strings.emit(sys.stdout, "egd_strings") 270 271 print() 272 273 strings_offsets.emit(sys.stdout, "egd_strings_offsets") 274 275 print() 276 print('#endif') 277 278 279def main(): 280 regs = [] 281 packets = [] 282 for arg in sys.argv[1:]: 283 parse(arg, regs, packets) 284 write_tables(regs, packets) 285 286 287if __name__ == '__main__': 288 main() 289 290# kate: space-indent on; indent-width 4; replace-tabs on; 291