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