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