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/* 109 * enum tables, these don't have any link back to other tables so just 110 * dump them up front before the bitset tables 111 */ 112 113%for name, enum in isa.enums.items(): 114static const struct isa_enum ${enum.get_c_name()} = { 115 .num_values = ${len(enum.values)}, 116 .values = { 117% for val, display in enum.values.items(): 118 { .val = ${val}, .display = "${display}" }, 119% endfor 120 }, 121}; 122%endfor 123 124/* 125 * generated expression functions, can be linked from bitset tables, so 126 * also dump them up front 127 */ 128 129%for name, expr in isa.expressions.items(): 130static uint64_t 131${expr.get_c_name()}(struct decode_scope *scope) 132{ 133% for fieldname in sorted(expr.fieldnames): 134 int64_t ${fieldname} = isa_decode_field(scope, "${fieldname}"); 135% endfor 136 return ${expr.expr}; 137} 138%endfor 139 140/* forward-declarations of bitset decode functions */ 141%for name, bitset in isa.all_bitsets(): 142% for df in s.decode_fields(bitset): 143static void decode_${bitset.get_c_name()}_gen_${bitset.gen_min}_${df.get_c_name()}(void *out, struct decode_scope *scope, uint64_t val); 144% endfor 145static const struct isa_field_decode decode_${bitset.get_c_name()}_gen_${bitset.gen_min}_fields[] = { 146% for df in s.decode_fields(bitset): 147 { 148 .name = "${df.name}", 149 .decode = decode_${bitset.get_c_name()}_gen_${bitset.gen_min}_${df.get_c_name()}, 150 }, 151% endfor 152}; 153static void decode_${bitset.get_c_name()}_gen_${bitset.gen_min}(void *out, struct decode_scope *scope); 154%endfor 155 156/* 157 * Forward-declarations (so we don't have to figure out which order to 158 * emit various tables when they have pointers to each other) 159 */ 160 161%for name, bitset in isa.all_bitsets(): 162static const struct isa_bitset bitset_${bitset.get_c_name()}_gen_${bitset.gen_min}; 163%endfor 164 165%for root_name, root in isa.roots.items(): 166const struct isa_bitset *${root.get_c_name()}[]; 167%endfor 168 169/* 170 * bitset tables: 171 */ 172 173%for name, bitset in isa.all_bitsets(): 174% for case in bitset.cases: 175% for field_name, field in case.fields.items(): 176% if field.get_c_typename() == 'TYPE_BITSET': 177% if len(field.params) > 0: 178static const struct isa_field_params ${case.get_c_name()}_gen_${bitset.gen_min}_${field.get_c_name()} = { 179 .num_params = ${len(field.params)}, 180 .params = { 181% for param in field.params: 182 { .name= "${param[0]}", .as = "${param[1]}" }, 183% endfor 184 185 }, 186}; 187% endif 188% endif 189% endfor 190static const struct isa_case ${case.get_c_name()}_gen_${bitset.gen_min} = { 191% if case.expr is not None: 192 .expr = &${isa.expressions[case.expr].get_c_name()}, 193% endif 194% if case.display is not None: 195 .display = "${case.display}", 196% endif 197 .num_fields = ${len(case.fields)}, 198 .fields = { 199% for field_name, field in case.fields.items(): 200 { .name = "${field_name}", .low = ${field.low}, .high = ${field.high}, 201% if field.expr is not None: 202 .expr = &${isa.expressions[field.expr].get_c_name()}, 203% endif 204% if field.display is not None: 205 .display = "${field.display}", 206% endif 207 .type = ${field.get_c_typename()}, 208% if field.get_c_typename() == 'TYPE_BITSET': 209 .bitsets = ${isa.roots[field.type].get_c_name()}, 210% if len(field.params) > 0: 211 .params = &${case.get_c_name()}_gen_${bitset.gen_min}_${field.get_c_name()}, 212% endif 213% endif 214% if field.get_c_typename() == 'TYPE_ENUM': 215 .enums = &${isa.enums[field.type].get_c_name()}, 216% endif 217% if field.get_c_typename() == 'TYPE_ASSERT': 218 .val.bitset = { ${', '.join(isa.split_bits(field.val, 32))} }, 219% endif 220% if field.get_c_typename() == 'TYPE_BRANCH' or field.get_c_typename() == 'TYPE_ABSBRANCH': 221 .call = ${str(field.call).lower()}, 222% endif 223 }, 224% endfor 225 }, 226}; 227% endfor 228static const struct isa_bitset bitset_${bitset.get_c_name()}_gen_${bitset.gen_min} = { 229<% pattern = bitset.get_pattern() %> 230% if bitset.extends is not None: 231 .parent = &bitset_${isa.bitsets[bitset.extends].get_c_name()}_gen_${isa.bitsets[bitset.extends].gen_min}, 232% endif 233 .name = "${bitset.display_name}", 234 .gen = { 235 .min = ${bitset.get_gen_min()}, 236 .max = ${bitset.get_gen_max()}, 237 }, 238 .match.bitset = { ${', '.join(isa.split_bits(pattern.match, 32))} }, 239 .dontcare.bitset = { ${', '.join(isa.split_bits(pattern.dontcare, 32))} }, 240 .mask.bitset = { ${', '.join(isa.split_bits(pattern.mask, 32))} }, 241 .decode = decode_${bitset.get_c_name()}_gen_${bitset.gen_min}, 242 .num_decode_fields = ARRAY_SIZE(decode_${bitset.get_c_name()}_gen_${bitset.gen_min}_fields), 243 .decode_fields = decode_${bitset.get_c_name()}_gen_${bitset.gen_min}_fields, 244 .num_cases = ${len(bitset.cases)}, 245 .cases = { 246% for case in bitset.cases: 247 &${case.get_c_name()}_gen_${bitset.gen_min}, 248% endfor 249 }, 250}; 251%endfor 252 253/* 254 * bitset hierarchy root tables (where decoding starts from): 255 */ 256 257%for root_name, root in isa.roots.items(): 258const struct isa_bitset *${root.get_c_name()}[] = { 259% for leaf_name, leafs in isa.leafs.items(): 260% for leaf in leafs: 261% if leaf.get_root() == root: 262 &bitset_${leaf.get_c_name()}_gen_${leaf.gen_min}, 263% endif 264% endfor 265% endfor 266 (void *)0 267}; 268%endfor 269 270#include "isaspec_decode_impl.c" 271 272%for name, bitset in isa.all_bitsets(): 273% for df in s.decode_fields(bitset): 274<% field = s.resolve_simple_field(bitset, df.name) %> 275static void decode_${bitset.get_c_name()}_gen_${bitset.gen_min}_${df.get_c_name()}(void *out, struct decode_scope *scope, uint64_t val) 276{ 277% if bitset.get_root().decode is not None and field is not None: 278 ${bitset.get_root().encode.type} src = *(${bitset.get_root().encode.type} *)out; 279% if field.get_c_typename() == 'TYPE_BITSET': 280 isa_decode_bitset(&${df.map_expr}, ${isa.roots[field.type].get_c_name()}, scope, uint64_t_to_bitmask(val)); 281% elif field.get_c_typename() in ['TYPE_BRANCH', 'TYPE_INT', 'TYPE_OFFSET']: 282 ${df.map_expr} = util_sign_extend(val, ${field.get_size()}); 283% else: 284 ${df.map_expr} = val; 285% endif 286 *(${bitset.get_root().encode.type} *)out = src; 287% endif 288} 289 290% endfor 291static void decode_${bitset.get_c_name()}_gen_${bitset.gen_min}(void *out, struct decode_scope *scope) 292{ 293% if bitset.get_root().decode is not None: 294 UNUSED ${bitset.get_root().encode.type} src; 295% if bitset.get_root().encode.type.endswith('*') and name in isa.leafs and bitset.get_root().encode.case_prefix is not None: 296 src = ${bitset.get_root().get_c_name()}_create(${s.case_name(bitset.get_root(), bitset.name)}); 297 *(${bitset.get_root().encode.type} *)out = src; 298% endif 299% endif 300} 301%endfor 302 303""" 304 305header = """\ 306/* Copyright (C) 2020 Google, Inc. 307 * 308 * Permission is hereby granted, free of charge, to any person obtaining a 309 * copy of this software and associated documentation files (the "Software"), 310 * to deal in the Software without restriction, including without limitation 311 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 312 * and/or sell copies of the Software, and to permit persons to whom the 313 * Software is furnished to do so, subject to the following conditions: 314 * 315 * The above copyright notice and this permission notice (including the next 316 * paragraph) shall be included in all copies or substantial portions of the 317 * Software. 318 * 319 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 320 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 321 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 322 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 323 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 324 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 325 * IN THE SOFTWARE. 326 */ 327 328#ifndef _${guard}_ 329#define _${guard}_ 330 331#include <stdint.h> 332#include <util/bitset.h> 333 334#define BITMASK_WORDS BITSET_WORDS(${isa.bitsize}) 335 336typedef struct { 337 BITSET_WORD bitset[BITMASK_WORDS]; 338} bitmask_t; 339 340 341#define BITSET_FORMAT ${isa.format()} 342#define BITSET_VALUE(v) ${isa.value()} 343 344static inline void 345next_instruction(bitmask_t *instr, BITSET_WORD *start) 346{ 347 %for i in range(0, int(isa.bitsize / 32)): 348 instr->bitset[${i}] = *(start + ${i}); 349 %endfor 350} 351 352static inline uint64_t 353bitmask_to_uint64_t(bitmask_t mask) 354{ 355% if isa.bitsize <= 32: 356 return mask.bitset[0]; 357% else: 358 return ((uint64_t)mask.bitset[1] << 32) | mask.bitset[0]; 359% endif 360} 361 362static inline bitmask_t 363uint64_t_to_bitmask(uint64_t val) 364{ 365 bitmask_t mask = { 366 .bitset[0] = val & 0xffffffff, 367% if isa.bitsize > 32: 368 .bitset[1] = (val >> 32) & 0xffffffff, 369% endif 370 }; 371 372 return mask; 373} 374 375#include "isaspec_decode_decl.h" 376 377#endif /* _${guard}_ */ 378 379""" 380 381def guard(p): 382 return os.path.basename(p).upper().replace("-", "_").replace(".", "_") 383 384def main(): 385 parser = argparse.ArgumentParser() 386 parser.add_argument('--xml', required=True, help='isaspec XML file.') 387 parser.add_argument('--out-c', required=True, help='Output C file.') 388 parser.add_argument('--out-h', required=True, help='Output H file.') 389 args = parser.parse_args() 390 391 isa = ISA(args.xml) 392 s = State(isa) 393 394 try: 395 with open(args.out_c, 'w', encoding='utf-8') as f: 396 out_h_basename = os.path.basename(args.out_h) 397 f.write(Template(template).render(isa=isa, s=s, header=out_h_basename)) 398 399 with open(args.out_h, 'w', encoding='utf-8') as f: 400 f.write(Template(header).render(isa=isa, guard=guard(args.out_h))) 401 402 except Exception: 403 # In the event there's an error, this imports some helpers from mako 404 # to print a useful stack trace and prints it, then exits with 405 # status 1, if python is run with debug; otherwise it just raises 406 # the exception 407 import sys 408 from mako import exceptions 409 print(exceptions.text_error_template().render(), file=sys.stderr) 410 sys.exit(1) 411 412if __name__ == '__main__': 413 main() 414