1#!/usr/bin/env python3 2# 3# Copyright © 2020 Google, 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# the rights to use, copy, modify, merge, publish, distribute, sublicense, 9# and/or sell copies of the Software, and to permit persons to whom the 10# 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 NONINFRINGEMENT. IN NO EVENT SHALL 19# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22# IN THE SOFTWARE. 23 24from mako.template import Template 25from isa import ISA 26import argparse 27import os 28import sys 29 30class FieldDecode(object): 31 def __init__(self, name, map_expr): 32 self.name = name 33 self.map_expr = map_expr 34 35 def get_c_name(self): 36 return self.name.lower().replace('-', '_') 37 38# State and helpers used by the template: 39class State(object): 40 def __init__(self, isa): 41 self.isa = isa 42 43 def case_name(self, bitset, name): 44 return bitset.encode.case_prefix + name.upper().replace('.', '_').replace('-', '_').replace('#', '') 45 46 # Return a list of all <map> entries for a leaf bitset, with the child 47 # bitset overriding the parent bitset's entries. Because we can't resolve 48 # which <map>s are used until we resolve which overload is used, we 49 # generate code for encoding all of these and then at runtime select which 50 # one to call based on the display. 51 def decode_fields(self, bitset): 52 if bitset.get_root().decode is None: 53 return 54 55 seen_fields = set() 56 if bitset.encode is not None: 57 for name, expr in bitset.encode.maps.items(): 58 seen_fields.add(name) 59 yield FieldDecode(name, expr) 60 61 if bitset.extends is not None: 62 for field in self.decode_fields(self.isa.bitsets[bitset.extends]): 63 if field.name not in seen_fields: 64 yield field 65 66 # A limited resolver for field type which doesn't properly account for 67 # overrides. In particular, if a field is defined differently in multiple 68 # different cases, this just blindly picks the last one. 69 # 70 # TODO to do this properly, I don't think there is an alternative than 71 # to emit code which evaluates the case.expr 72 def resolve_simple_field(self, bitset, name): 73 field = None 74 for case in bitset.cases: 75 if name in case.fields: 76 field = case.fields[name] 77 if field is not None: 78 return field 79 if bitset.extends is not None: 80 return self.resolve_simple_field(bitset.isa.bitsets[bitset.extends], name) 81 return None 82 83template = """\ 84/* Copyright (C) 2020 Google, Inc. 85 * 86 * Permission is hereby granted, free of charge, to any person obtaining a 87 * copy of this software and associated documentation files (the "Software"), 88 * to deal in the Software without restriction, including without limitation 89 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 90 * and/or sell copies of the Software, and to permit persons to whom the 91 * Software is furnished to do so, subject to the following conditions: 92 * 93 * The above copyright notice and this permission notice (including the next 94 * paragraph) shall be included in all copies or substantial portions of the 95 * Software. 96 * 97 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 98 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 99 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 100 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 101 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 102 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 103 * IN THE SOFTWARE. 104 */ 105 106#include "${header}" 107 108#include <stdint.h> 109#include <util/bitset.h> 110 111#define BITMASK_WORDS BITSET_WORDS(${isa.bitsize}) 112 113typedef struct { 114 BITSET_WORD bitset[BITMASK_WORDS]; 115} bitmask_t; 116 117 118#define BITSET_FORMAT ${isa.format()} 119#define BITSET_VALUE(v) ${isa.value()} 120 121static inline void 122next_instruction(bitmask_t *instr, BITSET_WORD *start) 123{ 124 %for i in range(0, int(isa.bitsize / 32)): 125 instr->bitset[${i}] = *(start + ${i}); 126 %endfor 127} 128 129static inline uint64_t 130bitmask_to_uint64_t(bitmask_t mask) 131{ 132% if isa.bitsize <= 32: 133 return mask.bitset[0]; 134% else: 135 return ((uint64_t)mask.bitset[1] << 32) | mask.bitset[0]; 136% endif 137} 138 139static inline bitmask_t 140uint64_t_to_bitmask(uint64_t val) 141{ 142 bitmask_t mask = { 143 .bitset[0] = val & 0xffffffff, 144% if isa.bitsize > 32: 145 .bitset[1] = (val >> 32) & 0xffffffff, 146% endif 147 }; 148 149 return mask; 150} 151 152#include "isaspec_decode_decl.h" 153 154static uint64_t 155isa_decode_field(struct decode_scope *scope, const char *field_name); 156 157/* 158 * enum tables, these don't have any link back to other tables so just 159 * dump them up front before the bitset tables 160 */ 161 162%for name, enum in isa.enums.items(): 163static const struct isa_enum ${enum.get_c_name()} = { 164 .num_values = ${len(enum.values)}, 165 .values = { 166% for val, display in enum.values.items(): 167 { .val = ${val}, .display = "${display}" }, 168% endfor 169 }, 170}; 171%endfor 172 173/* 174 * generated expression functions, can be linked from bitset tables, so 175 * also dump them up front 176 */ 177 178%for name, expr in isa.expressions.items(): 179static uint64_t 180${expr.get_c_name()}(struct decode_scope *scope) 181{ 182% for fieldname in sorted(expr.fieldnames): 183 int64_t ${fieldname} = isa_decode_field(scope, "${fieldname}"); 184% endfor 185 return ${expr.expr}; 186} 187%endfor 188 189/* forward-declarations of bitset decode functions */ 190%for name, bitset in isa.all_bitsets(): 191% for df in s.decode_fields(bitset): 192static void decode_${bitset.get_c_name()}_gen_${bitset.gen_min}_${df.get_c_name()}(void *out, struct decode_scope *scope, uint64_t val); 193% endfor 194static const struct isa_field_decode decode_${bitset.get_c_name()}_gen_${bitset.gen_min}_fields[] = { 195% for df in s.decode_fields(bitset): 196 { 197 .name = "${df.name}", 198 .decode = decode_${bitset.get_c_name()}_gen_${bitset.gen_min}_${df.get_c_name()}, 199 }, 200% endfor 201}; 202static void decode_${bitset.get_c_name()}_gen_${bitset.gen_min}(void *out, struct decode_scope *scope); 203%endfor 204 205/* 206 * Forward-declarations (so we don't have to figure out which order to 207 * emit various tables when they have pointers to each other) 208 */ 209 210%for name, bitset in isa.all_bitsets(): 211static const struct isa_bitset bitset_${bitset.get_c_name()}_gen_${bitset.gen_min}; 212%endfor 213 214%for root_name, root in isa.roots.items(): 215static const struct isa_bitset *${root.get_c_name()}[]; 216%endfor 217 218/* 219 * bitset tables: 220 */ 221 222%for name, bitset in isa.all_bitsets(): 223% for case in bitset.cases: 224% for field_name, field in case.fields.items(): 225% if field.get_c_typename() == 'TYPE_BITSET': 226% if len(field.params) > 0: 227static const struct isa_field_params ${case.get_c_name()}_gen_${bitset.gen_min}_${field.get_c_name()} = { 228 .num_params = ${len(field.params)}, 229 .params = { 230% for param in field.params: 231 { .name= "${param[0]}", .as = "${param[1]}" }, 232% endfor 233 234 }, 235}; 236% endif 237% endif 238% endfor 239static const struct isa_case ${case.get_c_name()}_gen_${bitset.gen_min} = { 240% if case.expr is not None: 241 .expr = &${isa.expressions[case.expr].get_c_name()}, 242% endif 243% if case.display is not None: 244 .display = "${case.display}", 245% endif 246 .num_fields = ${len(case.fields)}, 247 .fields = { 248% for field_name, field in case.fields.items(): 249 { .name = "${field_name}", .low = ${field.low}, .high = ${field.high}, 250% if field.expr is not None: 251 .expr = &${isa.expressions[field.expr].get_c_name()}, 252% endif 253% if field.display is not None: 254 .display = "${field.display}", 255% endif 256 .type = ${field.get_c_typename()}, 257% if field.get_c_typename() == 'TYPE_BITSET': 258 .bitsets = ${isa.roots[field.type].get_c_name()}, 259% if len(field.params) > 0: 260 .params = &${case.get_c_name()}_gen_${bitset.gen_min}_${field.get_c_name()}, 261% endif 262% endif 263% if field.get_c_typename() == 'TYPE_ENUM': 264 .enums = &${isa.enums[field.type].get_c_name()}, 265% endif 266% if field.get_c_typename() == 'TYPE_ASSERT': 267 .val.bitset = { ${', '.join(isa.split_bits(field.val, 32))} }, 268% endif 269% if field.get_c_typename() == 'TYPE_BRANCH' or field.get_c_typename() == 'TYPE_ABSBRANCH': 270 .call = ${str(field.call).lower()}, 271% endif 272 }, 273% endfor 274 }, 275}; 276% endfor 277static const struct isa_bitset bitset_${bitset.get_c_name()}_gen_${bitset.gen_min} = { 278<% pattern = bitset.get_pattern() %> 279% if bitset.extends is not None: 280 .parent = &bitset_${isa.bitsets[bitset.extends].get_c_name()}_gen_${isa.bitsets[bitset.extends].gen_min}, 281% endif 282 .name = "${bitset.display_name}", 283 .gen = { 284 .min = ${bitset.get_gen_min()}, 285 .max = ${bitset.get_gen_max()}, 286 }, 287 .match.bitset = { ${', '.join(isa.split_bits(pattern.match, 32))} }, 288 .dontcare.bitset = { ${', '.join(isa.split_bits(pattern.dontcare, 32))} }, 289 .mask.bitset = { ${', '.join(isa.split_bits(pattern.mask, 32))} }, 290 .decode = decode_${bitset.get_c_name()}_gen_${bitset.gen_min}, 291 .num_decode_fields = ARRAY_SIZE(decode_${bitset.get_c_name()}_gen_${bitset.gen_min}_fields), 292 .decode_fields = decode_${bitset.get_c_name()}_gen_${bitset.gen_min}_fields, 293 .num_cases = ${len(bitset.cases)}, 294 .cases = { 295% for case in bitset.cases: 296 &${case.get_c_name()}_gen_${bitset.gen_min}, 297% endfor 298 }, 299}; 300%endfor 301 302/* 303 * bitset hierarchy root tables (where decoding starts from): 304 */ 305 306%for root_name, root in isa.roots.items(): 307static const struct isa_bitset *${root.get_c_name()}[] = { 308% for leaf_name, leafs in isa.leafs.items(): 309% for leaf in leafs: 310% if leaf.get_root() == root: 311 &bitset_${leaf.get_c_name()}_gen_${leaf.gen_min}, 312% endif 313% endfor 314% endfor 315 (void *)0 316}; 317%endfor 318 319#include "isaspec_decode_impl.c" 320 321%for name, bitset in isa.all_bitsets(): 322% for df in s.decode_fields(bitset): 323<% field = s.resolve_simple_field(bitset, df.name) %> 324static void decode_${bitset.get_c_name()}_gen_${bitset.gen_min}_${df.get_c_name()}(void *out, struct decode_scope *scope, uint64_t val) 325{ 326% if bitset.get_root().decode is not None and field is not None: 327 ${bitset.get_root().encode.type} src = *(${bitset.get_root().encode.type} *)out; 328% if field.get_c_typename() == 'TYPE_BITSET': 329 isa_decode_bitset(&${df.map_expr}, ${isa.roots[field.type].get_c_name()}, scope, uint64_t_to_bitmask(val)); 330% elif field.get_c_typename() in ['TYPE_BRANCH', 'TYPE_INT', 'TYPE_OFFSET']: 331 ${df.map_expr} = util_sign_extend(val, ${field.get_size()}); 332% else: 333 ${df.map_expr} = val; 334% endif 335 *(${bitset.get_root().encode.type} *)out = src; 336% endif 337} 338 339% endfor 340static void decode_${bitset.get_c_name()}_gen_${bitset.gen_min}(void *out, struct decode_scope *scope) 341{ 342% if bitset.get_root().decode is not None: 343 UNUSED ${bitset.get_root().encode.type} src; 344% if bitset.get_root().encode.type.endswith('*') and name in isa.leafs and bitset.get_root().encode.case_prefix is not None: 345 src = ${bitset.get_root().get_c_name()}_create(${s.case_name(bitset.get_root(), bitset.name)}); 346 *(${bitset.get_root().encode.type} *)out = src; 347% endif 348% endif 349} 350%endfor 351 352void ${prefix}_isa_disasm(void *bin, int sz, FILE *out, const struct isa_decode_options *options) 353{ 354 isa_disasm(bin, sz, out, options); 355} 356 357bool ${prefix}_isa_decode(void *out, void *bin, const struct isa_decode_options *options) 358{ 359 return isa_decode(out, bin, options); 360} 361 362uint32_t ${prefix}_isa_get_gpu_id(struct decode_scope *scope) 363{ 364 return isa_get_gpu_id(scope); 365} 366""" 367 368header = """\ 369/* Copyright (C) 2020 Google, Inc. 370 * 371 * Permission is hereby granted, free of charge, to any person obtaining a 372 * copy of this software and associated documentation files (the "Software"), 373 * to deal in the Software without restriction, including without limitation 374 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 375 * and/or sell copies of the Software, and to permit persons to whom the 376 * Software is furnished to do so, subject to the following conditions: 377 * 378 * The above copyright notice and this permission notice (including the next 379 * paragraph) shall be included in all copies or substantial portions of the 380 * Software. 381 * 382 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 383 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 384 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 385 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 386 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 387 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 388 * IN THE SOFTWARE. 389 */ 390 391#ifndef _${guard}_ 392#define _${guard}_ 393 394#include "compiler/isaspec/isaspec.h" 395 396#ifdef __cplusplus 397extern "C" { 398#endif 399 400void ${prefix}_isa_disasm(void *bin, int sz, FILE *out, const struct isa_decode_options *options); 401bool ${prefix}_isa_decode(void *out, void *bin, const struct isa_decode_options *options); 402 403struct decode_scope; 404 405uint32_t ${prefix}_isa_get_gpu_id(struct decode_scope *scope); 406 407/** 408 * Allows to use gpu_id in expr functions 409 */ 410#define ISA_GPU_ID() ${prefix}_isa_get_gpu_id(scope) 411 412#ifdef __cplusplus 413} 414#endif 415 416#endif /* _${guard}_ */ 417 418""" 419 420def guard(p): 421 return os.path.basename(p).upper().replace("-", "_").replace(".", "_") 422 423def prefix(p): 424 return os.path.basename(p).lower().replace("-", "_").replace(".", "_").split('_')[0] 425 426def main(): 427 parser = argparse.ArgumentParser() 428 parser.add_argument('--xml', required=True, help='isaspec XML file.') 429 parser.add_argument('--out-c', required=True, help='Output C file.') 430 parser.add_argument('--out-h', required=True, help='Output H file.') 431 args = parser.parse_args() 432 433 isa = ISA(args.xml) 434 s = State(isa) 435 436 try: 437 with open(args.out_c, 'w', encoding='utf-8') as f: 438 out_h_basename = os.path.basename(args.out_h) 439 f.write(Template(template).render(isa=isa, s=s, header=out_h_basename, prefix=prefix(args.out_h))) 440 441 with open(args.out_h, 'w', encoding='utf-8') as f: 442 f.write(Template(header).render(isa=isa, guard=guard(args.out_h), prefix=prefix(args.out_h))) 443 444 except Exception: 445 # In the event there's an error, this imports some helpers from mako 446 # to print a useful stack trace and prints it, then exits with 447 # status 1, if python is run with debug; otherwise it just raises 448 # the exception 449 import sys 450 from mako import exceptions 451 print(exceptions.text_error_template().render(), file=sys.stderr) 452 sys.exit(1) 453 454if __name__ == '__main__': 455 main() 456