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