qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

scripts: Add decodetree.py

To be used to decode ARM SVE, but could be used for any fixed-width ISA.

Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

+1202 -1
+1062
scripts/decodetree.py
··· 1 + #!/usr/bin/env python 2 + # Copyright (c) 2018 Linaro Limited 3 + # 4 + # This library is free software; you can redistribute it and/or 5 + # modify it under the terms of the GNU Lesser General Public 6 + # License as published by the Free Software Foundation; either 7 + # version 2 of the License, or (at your option) any later version. 8 + # 9 + # This library is distributed in the hope that it will be useful, 10 + # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 + # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 + # Lesser General Public License for more details. 13 + # 14 + # You should have received a copy of the GNU Lesser General Public 15 + # License along with this library; if not, see <http://www.gnu.org/licenses/>. 16 + # 17 + 18 + # 19 + # Generate a decoding tree from a specification file. 20 + # 21 + # The tree is built from instruction "patterns". A pattern may represent 22 + # a single architectural instruction or a group of same, depending on what 23 + # is convenient for further processing. 24 + # 25 + # Each pattern has "fixedbits" & "fixedmask", the combination of which 26 + # describes the condition under which the pattern is matched: 27 + # 28 + # (insn & fixedmask) == fixedbits 29 + # 30 + # Each pattern may have "fields", which are extracted from the insn and 31 + # passed along to the translator. Examples of such are registers, 32 + # immediates, and sub-opcodes. 33 + # 34 + # In support of patterns, one may declare fields, argument sets, and 35 + # formats, each of which may be re-used to simplify further definitions. 36 + # 37 + # *** Field syntax: 38 + # 39 + # field_def := '%' identifier ( unnamed_field )+ ( !function=identifier )? 40 + # unnamed_field := number ':' ( 's' ) number 41 + # 42 + # For unnamed_field, the first number is the least-significant bit position of 43 + # the field and the second number is the length of the field. If the 's' is 44 + # present, the field is considered signed. If multiple unnamed_fields are 45 + # present, they are concatenated. In this way one can define disjoint fields. 46 + # 47 + # If !function is specified, the concatenated result is passed through the 48 + # named function, taking and returning an integral value. 49 + # 50 + # FIXME: the fields of the structure into which this result will be stored 51 + # is restricted to "int". Which means that we cannot expand 64-bit items. 52 + # 53 + # Field examples: 54 + # 55 + # %disp 0:s16 -- sextract(i, 0, 16) 56 + # %imm9 16:6 10:3 -- extract(i, 16, 6) << 3 | extract(i, 10, 3) 57 + # %disp12 0:s1 1:1 2:10 -- sextract(i, 0, 1) << 11 58 + # | extract(i, 1, 1) << 10 59 + # | extract(i, 2, 10) 60 + # %shimm8 5:s8 13:1 !function=expand_shimm8 61 + # -- expand_shimm8(sextract(i, 5, 8) << 1 62 + # | extract(i, 13, 1)) 63 + # 64 + # *** Argument set syntax: 65 + # 66 + # args_def := '&' identifier ( args_elt )+ 67 + # args_elt := identifier 68 + # 69 + # Each args_elt defines an argument within the argument set. 70 + # Each argument set will be rendered as a C structure "arg_$name" 71 + # with each of the fields being one of the member arguments. 72 + # 73 + # Argument set examples: 74 + # 75 + # &reg3 ra rb rc 76 + # &loadstore reg base offset 77 + # 78 + # *** Format syntax: 79 + # 80 + # fmt_def := '@' identifier ( fmt_elt )+ 81 + # fmt_elt := fixedbit_elt | field_elt | field_ref | args_ref 82 + # fixedbit_elt := [01.-]+ 83 + # field_elt := identifier ':' 's'? number 84 + # field_ref := '%' identifier | identifier '=' '%' identifier 85 + # args_ref := '&' identifier 86 + # 87 + # Defining a format is a handy way to avoid replicating groups of fields 88 + # across many instruction patterns. 89 + # 90 + # A fixedbit_elt describes a contiguous sequence of bits that must 91 + # be 1, 0, [.-] for don't care. The difference between '.' and '-' 92 + # is that '.' means that the bit will be covered with a field or a 93 + # final [01] from the pattern, and '-' means that the bit is really 94 + # ignored by the cpu and will not be specified. 95 + # 96 + # A field_elt describes a simple field only given a width; the position of 97 + # the field is implied by its position with respect to other fixedbit_elt 98 + # and field_elt. 99 + # 100 + # If any fixedbit_elt or field_elt appear then all bits must be defined. 101 + # Padding with a fixedbit_elt of all '.' is an easy way to accomplish that. 102 + # 103 + # A field_ref incorporates a field by reference. This is the only way to 104 + # add a complex field to a format. A field may be renamed in the process 105 + # via assignment to another identifier. This is intended to allow the 106 + # same argument set be used with disjoint named fields. 107 + # 108 + # A single args_ref may specify an argument set to use for the format. 109 + # The set of fields in the format must be a subset of the arguments in 110 + # the argument set. If an argument set is not specified, one will be 111 + # inferred from the set of fields. 112 + # 113 + # It is recommended, but not required, that all field_ref and args_ref 114 + # appear at the end of the line, not interleaving with fixedbit_elf or 115 + # field_elt. 116 + # 117 + # Format examples: 118 + # 119 + # @opr ...... ra:5 rb:5 ... 0 ....... rc:5 120 + # @opi ...... ra:5 lit:8 1 ....... rc:5 121 + # 122 + # *** Pattern syntax: 123 + # 124 + # pat_def := identifier ( pat_elt )+ 125 + # pat_elt := fixedbit_elt | field_elt | field_ref 126 + # | args_ref | fmt_ref | const_elt 127 + # fmt_ref := '@' identifier 128 + # const_elt := identifier '=' number 129 + # 130 + # The fixedbit_elt and field_elt specifiers are unchanged from formats. 131 + # A pattern that does not specify a named format will have one inferred 132 + # from a referenced argument set (if present) and the set of fields. 133 + # 134 + # A const_elt allows a argument to be set to a constant value. This may 135 + # come in handy when fields overlap between patterns and one has to 136 + # include the values in the fixedbit_elt instead. 137 + # 138 + # The decoder will call a translator function for each pattern matched. 139 + # 140 + # Pattern examples: 141 + # 142 + # addl_r 010000 ..... ..... .... 0000000 ..... @opr 143 + # addl_i 010000 ..... ..... .... 0000000 ..... @opi 144 + # 145 + # which will, in part, invoke 146 + # 147 + # trans_addl_r(ctx, &arg_opr, insn) 148 + # and 149 + # trans_addl_i(ctx, &arg_opi, insn) 150 + # 151 + 152 + import io 153 + import os 154 + import re 155 + import sys 156 + import getopt 157 + import pdb 158 + 159 + insnwidth = 32 160 + insnmask = 0xffffffff 161 + fields = {} 162 + arguments = {} 163 + formats = {} 164 + patterns = [] 165 + 166 + translate_prefix = 'trans' 167 + translate_scope = 'static ' 168 + input_file = '' 169 + output_file = None 170 + output_fd = None 171 + insntype = 'uint32_t' 172 + 173 + re_ident = '[a-zA-Z][a-zA-Z0-9_]*' 174 + 175 + 176 + def error(lineno, *args): 177 + """Print an error message from file:line and args and exit.""" 178 + global output_file 179 + global output_fd 180 + 181 + if lineno: 182 + r = '{0}:{1}: error:'.format(input_file, lineno) 183 + elif input_file: 184 + r = '{0}: error:'.format(input_file) 185 + else: 186 + r = 'error:' 187 + for a in args: 188 + r += ' ' + str(a) 189 + r += '\n' 190 + sys.stderr.write(r) 191 + if output_file and output_fd: 192 + output_fd.close() 193 + os.remove(output_file) 194 + exit(1) 195 + 196 + 197 + def output(*args): 198 + global output_fd 199 + for a in args: 200 + output_fd.write(a) 201 + 202 + 203 + if sys.version_info >= (3, 0): 204 + re_fullmatch = re.fullmatch 205 + else: 206 + def re_fullmatch(pat, str): 207 + return re.match('^' + pat + '$', str) 208 + 209 + 210 + def output_autogen(): 211 + output('/* This file is autogenerated by scripts/decodetree.py. */\n\n') 212 + 213 + 214 + def str_indent(c): 215 + """Return a string with C spaces""" 216 + return ' ' * c 217 + 218 + 219 + def str_fields(fields): 220 + """Return a string uniquely identifing FIELDS""" 221 + r = '' 222 + for n in sorted(fields.keys()): 223 + r += '_' + n 224 + return r[1:] 225 + 226 + 227 + def str_match_bits(bits, mask): 228 + """Return a string pretty-printing BITS/MASK""" 229 + global insnwidth 230 + 231 + i = 1 << (insnwidth - 1) 232 + space = 0x01010100 233 + r = '' 234 + while i != 0: 235 + if i & mask: 236 + if i & bits: 237 + r += '1' 238 + else: 239 + r += '0' 240 + else: 241 + r += '.' 242 + if i & space: 243 + r += ' ' 244 + i >>= 1 245 + return r 246 + 247 + 248 + def is_pow2(x): 249 + """Return true iff X is equal to a power of 2.""" 250 + return (x & (x - 1)) == 0 251 + 252 + 253 + def ctz(x): 254 + """Return the number of times 2 factors into X.""" 255 + r = 0 256 + while ((x >> r) & 1) == 0: 257 + r += 1 258 + return r 259 + 260 + 261 + def is_contiguous(bits): 262 + shift = ctz(bits) 263 + if is_pow2((bits >> shift) + 1): 264 + return shift 265 + else: 266 + return -1 267 + 268 + 269 + def eq_fields_for_args(flds_a, flds_b): 270 + if len(flds_a) != len(flds_b): 271 + return False 272 + for k, a in flds_a.items(): 273 + if k not in flds_b: 274 + return False 275 + return True 276 + 277 + 278 + def eq_fields_for_fmts(flds_a, flds_b): 279 + if len(flds_a) != len(flds_b): 280 + return False 281 + for k, a in flds_a.items(): 282 + if k not in flds_b: 283 + return False 284 + b = flds_b[k] 285 + if a.__class__ != b.__class__ or a != b: 286 + return False 287 + return True 288 + 289 + 290 + class Field: 291 + """Class representing a simple instruction field""" 292 + def __init__(self, sign, pos, len): 293 + self.sign = sign 294 + self.pos = pos 295 + self.len = len 296 + self.mask = ((1 << len) - 1) << pos 297 + 298 + def __str__(self): 299 + if self.sign: 300 + s = 's' 301 + else: 302 + s = '' 303 + return str(pos) + ':' + s + str(len) 304 + 305 + def str_extract(self): 306 + if self.sign: 307 + extr = 'sextract32' 308 + else: 309 + extr = 'extract32' 310 + return '{0}(insn, {1}, {2})'.format(extr, self.pos, self.len) 311 + 312 + def __eq__(self, other): 313 + return self.sign == other.sign and self.sign == other.sign 314 + 315 + def __ne__(self, other): 316 + return not self.__eq__(other) 317 + # end Field 318 + 319 + 320 + class MultiField: 321 + """Class representing a compound instruction field""" 322 + def __init__(self, subs, mask): 323 + self.subs = subs 324 + self.sign = subs[0].sign 325 + self.mask = mask 326 + 327 + def __str__(self): 328 + return str(self.subs) 329 + 330 + def str_extract(self): 331 + ret = '0' 332 + pos = 0 333 + for f in reversed(self.subs): 334 + if pos == 0: 335 + ret = f.str_extract() 336 + else: 337 + ret = 'deposit32({0}, {1}, {2}, {3})' \ 338 + .format(ret, pos, 32 - pos, f.str_extract()) 339 + pos += f.len 340 + return ret 341 + 342 + def __ne__(self, other): 343 + if len(self.subs) != len(other.subs): 344 + return True 345 + for a, b in zip(self.subs, other.subs): 346 + if a.__class__ != b.__class__ or a != b: 347 + return True 348 + return False 349 + 350 + def __eq__(self, other): 351 + return not self.__ne__(other) 352 + # end MultiField 353 + 354 + 355 + class ConstField: 356 + """Class representing an argument field with constant value""" 357 + def __init__(self, value): 358 + self.value = value 359 + self.mask = 0 360 + self.sign = value < 0 361 + 362 + def __str__(self): 363 + return str(self.value) 364 + 365 + def str_extract(self): 366 + return str(self.value) 367 + 368 + def __cmp__(self, other): 369 + return self.value - other.value 370 + # end ConstField 371 + 372 + 373 + class FunctionField: 374 + """Class representing a field passed through an expander""" 375 + def __init__(self, func, base): 376 + self.mask = base.mask 377 + self.sign = base.sign 378 + self.base = base 379 + self.func = func 380 + 381 + def __str__(self): 382 + return self.func + '(' + str(self.base) + ')' 383 + 384 + def str_extract(self): 385 + return self.func + '(' + self.base.str_extract() + ')' 386 + 387 + def __eq__(self, other): 388 + return self.func == other.func and self.base == other.base 389 + 390 + def __ne__(self, other): 391 + return not self.__eq__(other) 392 + # end FunctionField 393 + 394 + 395 + class Arguments: 396 + """Class representing the extracted fields of a format""" 397 + def __init__(self, nm, flds): 398 + self.name = nm 399 + self.fields = sorted(flds) 400 + 401 + def __str__(self): 402 + return self.name + ' ' + str(self.fields) 403 + 404 + def struct_name(self): 405 + return 'arg_' + self.name 406 + 407 + def output_def(self): 408 + output('typedef struct {\n') 409 + for n in self.fields: 410 + output(' int ', n, ';\n') 411 + output('} ', self.struct_name(), ';\n\n') 412 + # end Arguments 413 + 414 + 415 + class General: 416 + """Common code between instruction formats and instruction patterns""" 417 + def __init__(self, name, lineno, base, fixb, fixm, udfm, fldm, flds): 418 + self.name = name 419 + self.lineno = lineno 420 + self.base = base 421 + self.fixedbits = fixb 422 + self.fixedmask = fixm 423 + self.undefmask = udfm 424 + self.fieldmask = fldm 425 + self.fields = flds 426 + 427 + def __str__(self): 428 + r = self.name 429 + if self.base: 430 + r = r + ' ' + self.base.name 431 + else: 432 + r = r + ' ' + str(self.fields) 433 + r = r + ' ' + str_match_bits(self.fixedbits, self.fixedmask) 434 + return r 435 + 436 + def str1(self, i): 437 + return str_indent(i) + self.__str__() 438 + # end General 439 + 440 + 441 + class Format(General): 442 + """Class representing an instruction format""" 443 + 444 + def extract_name(self): 445 + return 'extract_' + self.name 446 + 447 + def output_extract(self): 448 + output('static void ', self.extract_name(), '(', 449 + self.base.struct_name(), ' *a, ', insntype, ' insn)\n{\n') 450 + for n, f in self.fields.items(): 451 + output(' a->', n, ' = ', f.str_extract(), ';\n') 452 + output('}\n\n') 453 + # end Format 454 + 455 + 456 + class Pattern(General): 457 + """Class representing an instruction pattern""" 458 + 459 + def output_decl(self): 460 + global translate_scope 461 + global translate_prefix 462 + output('typedef ', self.base.base.struct_name(), 463 + ' arg_', self.name, ';\n') 464 + output(translate_scope, 'void ', translate_prefix, '_', self.name, 465 + '(DisasContext *ctx, arg_', self.name, 466 + ' *a, ', insntype, ' insn);\n') 467 + 468 + def output_code(self, i, extracted, outerbits, outermask): 469 + global translate_prefix 470 + ind = str_indent(i) 471 + arg = self.base.base.name 472 + output(ind, '/* line ', str(self.lineno), ' */\n') 473 + if not extracted: 474 + output(ind, self.base.extract_name(), '(&u.f_', arg, ', insn);\n') 475 + for n, f in self.fields.items(): 476 + output(ind, 'u.f_', arg, '.', n, ' = ', f.str_extract(), ';\n') 477 + output(ind, translate_prefix, '_', self.name, 478 + '(ctx, &u.f_', arg, ', insn);\n') 479 + output(ind, 'return true;\n') 480 + # end Pattern 481 + 482 + 483 + def parse_field(lineno, name, toks): 484 + """Parse one instruction field from TOKS at LINENO""" 485 + global fields 486 + global re_ident 487 + global insnwidth 488 + 489 + # A "simple" field will have only one entry; 490 + # a "multifield" will have several. 491 + subs = [] 492 + width = 0 493 + func = None 494 + for t in toks: 495 + if re_fullmatch('!function=' + re_ident, t): 496 + if func: 497 + error(lineno, 'duplicate function') 498 + func = t.split('=') 499 + func = func[1] 500 + continue 501 + 502 + if re_fullmatch('[0-9]+:s[0-9]+', t): 503 + # Signed field extract 504 + subtoks = t.split(':s') 505 + sign = True 506 + elif re_fullmatch('[0-9]+:[0-9]+', t): 507 + # Unsigned field extract 508 + subtoks = t.split(':') 509 + sign = False 510 + else: 511 + error(lineno, 'invalid field token "{0}"'.format(t)) 512 + po = int(subtoks[0]) 513 + le = int(subtoks[1]) 514 + if po + le > insnwidth: 515 + error(lineno, 'field {0} too large'.format(t)) 516 + f = Field(sign, po, le) 517 + subs.append(f) 518 + width += le 519 + 520 + if width > insnwidth: 521 + error(lineno, 'field too large') 522 + if len(subs) == 1: 523 + f = subs[0] 524 + else: 525 + mask = 0 526 + for s in subs: 527 + if mask & s.mask: 528 + error(lineno, 'field components overlap') 529 + mask |= s.mask 530 + f = MultiField(subs, mask) 531 + if func: 532 + f = FunctionField(func, f) 533 + 534 + if name in fields: 535 + error(lineno, 'duplicate field', name) 536 + fields[name] = f 537 + # end parse_field 538 + 539 + 540 + def parse_arguments(lineno, name, toks): 541 + """Parse one argument set from TOKS at LINENO""" 542 + global arguments 543 + global re_ident 544 + 545 + flds = [] 546 + for t in toks: 547 + if not re_fullmatch(re_ident, t): 548 + error(lineno, 'invalid argument set token "{0}"'.format(t)) 549 + if t in flds: 550 + error(lineno, 'duplicate argument "{0}"'.format(t)) 551 + flds.append(t) 552 + 553 + if name in arguments: 554 + error(lineno, 'duplicate argument set', name) 555 + arguments[name] = Arguments(name, flds) 556 + # end parse_arguments 557 + 558 + 559 + def lookup_field(lineno, name): 560 + global fields 561 + if name in fields: 562 + return fields[name] 563 + error(lineno, 'undefined field', name) 564 + 565 + 566 + def add_field(lineno, flds, new_name, f): 567 + if new_name in flds: 568 + error(lineno, 'duplicate field', new_name) 569 + flds[new_name] = f 570 + return flds 571 + 572 + 573 + def add_field_byname(lineno, flds, new_name, old_name): 574 + return add_field(lineno, flds, new_name, lookup_field(lineno, old_name)) 575 + 576 + 577 + def infer_argument_set(flds): 578 + global arguments 579 + 580 + for arg in arguments.values(): 581 + if eq_fields_for_args(flds, arg.fields): 582 + return arg 583 + 584 + name = str(len(arguments)) 585 + arg = Arguments(name, flds.keys()) 586 + arguments[name] = arg 587 + return arg 588 + 589 + 590 + def infer_format(arg, fieldmask, flds): 591 + global arguments 592 + global formats 593 + 594 + const_flds = {} 595 + var_flds = {} 596 + for n, c in flds.items(): 597 + if c is ConstField: 598 + const_flds[n] = c 599 + else: 600 + var_flds[n] = c 601 + 602 + # Look for an existing format with the same argument set and fields 603 + for fmt in formats.values(): 604 + if arg and fmt.base != arg: 605 + continue 606 + if fieldmask != fmt.fieldmask: 607 + continue 608 + if not eq_fields_for_fmts(flds, fmt.fields): 609 + continue 610 + return (fmt, const_flds) 611 + 612 + name = 'Fmt_' + str(len(formats)) 613 + if not arg: 614 + arg = infer_argument_set(flds) 615 + 616 + fmt = Format(name, 0, arg, 0, 0, 0, fieldmask, var_flds) 617 + formats[name] = fmt 618 + 619 + return (fmt, const_flds) 620 + # end infer_format 621 + 622 + 623 + def parse_generic(lineno, is_format, name, toks): 624 + """Parse one instruction format from TOKS at LINENO""" 625 + global fields 626 + global arguments 627 + global formats 628 + global patterns 629 + global re_ident 630 + global insnwidth 631 + global insnmask 632 + 633 + fixedmask = 0 634 + fixedbits = 0 635 + undefmask = 0 636 + width = 0 637 + flds = {} 638 + arg = None 639 + fmt = None 640 + for t in toks: 641 + # '&Foo' gives a format an explcit argument set. 642 + if t[0] == '&': 643 + tt = t[1:] 644 + if arg: 645 + error(lineno, 'multiple argument sets') 646 + if tt in arguments: 647 + arg = arguments[tt] 648 + else: 649 + error(lineno, 'undefined argument set', t) 650 + continue 651 + 652 + # '@Foo' gives a pattern an explicit format. 653 + if t[0] == '@': 654 + tt = t[1:] 655 + if fmt: 656 + error(lineno, 'multiple formats') 657 + if tt in formats: 658 + fmt = formats[tt] 659 + else: 660 + error(lineno, 'undefined format', t) 661 + continue 662 + 663 + # '%Foo' imports a field. 664 + if t[0] == '%': 665 + tt = t[1:] 666 + flds = add_field_byname(lineno, flds, tt, tt) 667 + continue 668 + 669 + # 'Foo=%Bar' imports a field with a different name. 670 + if re_fullmatch(re_ident + '=%' + re_ident, t): 671 + (fname, iname) = t.split('=%') 672 + flds = add_field_byname(lineno, flds, fname, iname) 673 + continue 674 + 675 + # 'Foo=number' sets an argument field to a constant value 676 + if re_fullmatch(re_ident + '=[0-9]+', t): 677 + (fname, value) = t.split('=') 678 + value = int(value) 679 + flds = add_field(lineno, flds, fname, ConstField(value)) 680 + continue 681 + 682 + # Pattern of 0s, 1s, dots and dashes indicate required zeros, 683 + # required ones, or dont-cares. 684 + if re_fullmatch('[01.-]+', t): 685 + shift = len(t) 686 + fms = t.replace('0', '1') 687 + fms = fms.replace('.', '0') 688 + fms = fms.replace('-', '0') 689 + fbs = t.replace('.', '0') 690 + fbs = fbs.replace('-', '0') 691 + ubm = t.replace('1', '0') 692 + ubm = ubm.replace('.', '0') 693 + ubm = ubm.replace('-', '1') 694 + fms = int(fms, 2) 695 + fbs = int(fbs, 2) 696 + ubm = int(ubm, 2) 697 + fixedbits = (fixedbits << shift) | fbs 698 + fixedmask = (fixedmask << shift) | fms 699 + undefmask = (undefmask << shift) | ubm 700 + # Otherwise, fieldname:fieldwidth 701 + elif re_fullmatch(re_ident + ':s?[0-9]+', t): 702 + (fname, flen) = t.split(':') 703 + sign = False 704 + if flen[0] == 's': 705 + sign = True 706 + flen = flen[1:] 707 + shift = int(flen, 10) 708 + f = Field(sign, insnwidth - width - shift, shift) 709 + flds = add_field(lineno, flds, fname, f) 710 + fixedbits <<= shift 711 + fixedmask <<= shift 712 + undefmask <<= shift 713 + else: 714 + error(lineno, 'invalid token "{0}"'.format(t)) 715 + width += shift 716 + 717 + # We should have filled in all of the bits of the instruction. 718 + if not (is_format and width == 0) and width != insnwidth: 719 + error(lineno, 'definition has {0} bits'.format(width)) 720 + 721 + # Do not check for fields overlaping fields; one valid usage 722 + # is to be able to duplicate fields via import. 723 + fieldmask = 0 724 + for f in flds.values(): 725 + fieldmask |= f.mask 726 + 727 + # Fix up what we've parsed to match either a format or a pattern. 728 + if is_format: 729 + # Formats cannot reference formats. 730 + if fmt: 731 + error(lineno, 'format referencing format') 732 + # If an argument set is given, then there should be no fields 733 + # without a place to store it. 734 + if arg: 735 + for f in flds.keys(): 736 + if f not in arg.fields: 737 + error(lineno, 'field {0} not in argument set {1}' 738 + .format(f, arg.name)) 739 + else: 740 + arg = infer_argument_set(flds) 741 + if name in formats: 742 + error(lineno, 'duplicate format name', name) 743 + fmt = Format(name, lineno, arg, fixedbits, fixedmask, 744 + undefmask, fieldmask, flds) 745 + formats[name] = fmt 746 + else: 747 + # Patterns can reference a format ... 748 + if fmt: 749 + # ... but not an argument simultaneously 750 + if arg: 751 + error(lineno, 'pattern specifies both format and argument set') 752 + if fixedmask & fmt.fixedmask: 753 + error(lineno, 'pattern fixed bits overlap format fixed bits') 754 + fieldmask |= fmt.fieldmask 755 + fixedbits |= fmt.fixedbits 756 + fixedmask |= fmt.fixedmask 757 + undefmask |= fmt.undefmask 758 + else: 759 + (fmt, flds) = infer_format(arg, fieldmask, flds) 760 + arg = fmt.base 761 + for f in flds.keys(): 762 + if f not in arg.fields: 763 + error(lineno, 'field {0} not in argument set {1}' 764 + .format(f, arg.name)) 765 + if f in fmt.fields.keys(): 766 + error(lineno, 'field {0} set by format and pattern'.format(f)) 767 + for f in arg.fields: 768 + if f not in flds.keys() and f not in fmt.fields.keys(): 769 + error(lineno, 'field {0} not initialized'.format(f)) 770 + pat = Pattern(name, lineno, fmt, fixedbits, fixedmask, 771 + undefmask, fieldmask, flds) 772 + patterns.append(pat) 773 + 774 + # Validate the masks that we have assembled. 775 + if fieldmask & fixedmask: 776 + error(lineno, 'fieldmask overlaps fixedmask (0x{0:08x} & 0x{1:08x})' 777 + .format(fieldmask, fixedmask)) 778 + if fieldmask & undefmask: 779 + error(lineno, 'fieldmask overlaps undefmask (0x{0:08x} & 0x{1:08x})' 780 + .format(fieldmask, undefmask)) 781 + if fixedmask & undefmask: 782 + error(lineno, 'fixedmask overlaps undefmask (0x{0:08x} & 0x{1:08x})' 783 + .format(fixedmask, undefmask)) 784 + if not is_format: 785 + allbits = fieldmask | fixedmask | undefmask 786 + if allbits != insnmask: 787 + error(lineno, 'bits left unspecified (0x{0:08x})' 788 + .format(allbits ^ insnmask)) 789 + # end parse_general 790 + 791 + 792 + def parse_file(f): 793 + """Parse all of the patterns within a file""" 794 + 795 + # Read all of the lines of the file. Concatenate lines 796 + # ending in backslash; discard empty lines and comments. 797 + toks = [] 798 + lineno = 0 799 + for line in f: 800 + lineno += 1 801 + 802 + # Discard comments 803 + end = line.find('#') 804 + if end >= 0: 805 + line = line[:end] 806 + 807 + t = line.split() 808 + if len(toks) != 0: 809 + # Next line after continuation 810 + toks.extend(t) 811 + elif len(t) == 0: 812 + # Empty line 813 + continue 814 + else: 815 + toks = t 816 + 817 + # Continuation? 818 + if toks[-1] == '\\': 819 + toks.pop() 820 + continue 821 + 822 + if len(toks) < 2: 823 + error(lineno, 'short line') 824 + 825 + name = toks[0] 826 + del toks[0] 827 + 828 + # Determine the type of object needing to be parsed. 829 + if name[0] == '%': 830 + parse_field(lineno, name[1:], toks) 831 + elif name[0] == '&': 832 + parse_arguments(lineno, name[1:], toks) 833 + elif name[0] == '@': 834 + parse_generic(lineno, True, name[1:], toks) 835 + else: 836 + parse_generic(lineno, False, name, toks) 837 + toks = [] 838 + # end parse_file 839 + 840 + 841 + class Tree: 842 + """Class representing a node in a decode tree""" 843 + 844 + def __init__(self, fm, tm): 845 + self.fixedmask = fm 846 + self.thismask = tm 847 + self.subs = [] 848 + self.base = None 849 + 850 + def str1(self, i): 851 + ind = str_indent(i) 852 + r = '{0}{1:08x}'.format(ind, self.fixedmask) 853 + if self.format: 854 + r += ' ' + self.format.name 855 + r += ' [\n' 856 + for (b, s) in self.subs: 857 + r += '{0} {1:08x}:\n'.format(ind, b) 858 + r += s.str1(i + 4) + '\n' 859 + r += ind + ']' 860 + return r 861 + 862 + def __str__(self): 863 + return self.str1(0) 864 + 865 + def output_code(self, i, extracted, outerbits, outermask): 866 + ind = str_indent(i) 867 + 868 + # If we identified all nodes below have the same format, 869 + # extract the fields now. 870 + if not extracted and self.base: 871 + output(ind, self.base.extract_name(), 872 + '(&u.f_', self.base.base.name, ', insn);\n') 873 + extracted = True 874 + 875 + # Attempt to aid the compiler in producing compact switch statements. 876 + # If the bits in the mask are contiguous, extract them. 877 + sh = is_contiguous(self.thismask) 878 + if sh > 0: 879 + # Propagate SH down into the local functions. 880 + def str_switch(b, sh=sh): 881 + return '(insn >> {0}) & 0x{1:x}'.format(sh, b >> sh) 882 + 883 + def str_case(b, sh=sh): 884 + return '0x{0:x}'.format(b >> sh) 885 + else: 886 + def str_switch(b): 887 + return 'insn & 0x{0:08x}'.format(b) 888 + 889 + def str_case(b): 890 + return '0x{0:08x}'.format(b) 891 + 892 + output(ind, 'switch (', str_switch(self.thismask), ') {\n') 893 + for b, s in sorted(self.subs): 894 + assert (self.thismask & ~s.fixedmask) == 0 895 + innermask = outermask | self.thismask 896 + innerbits = outerbits | b 897 + output(ind, 'case ', str_case(b), ':\n') 898 + output(ind, ' /* ', 899 + str_match_bits(innerbits, innermask), ' */\n') 900 + s.output_code(i + 4, extracted, innerbits, innermask) 901 + output(ind, '}\n') 902 + output(ind, 'return false;\n') 903 + # end Tree 904 + 905 + 906 + def build_tree(pats, outerbits, outermask): 907 + # Find the intersection of all remaining fixedmask. 908 + innermask = ~outermask 909 + for i in pats: 910 + innermask &= i.fixedmask 911 + 912 + if innermask == 0: 913 + pnames = [] 914 + for p in pats: 915 + pnames.append(p.name + ':' + str(p.lineno)) 916 + error(pats[0].lineno, 'overlapping patterns:', pnames) 917 + 918 + fullmask = outermask | innermask 919 + 920 + # Sort each element of pats into the bin selected by the mask. 921 + bins = {} 922 + for i in pats: 923 + fb = i.fixedbits & innermask 924 + if fb in bins: 925 + bins[fb].append(i) 926 + else: 927 + bins[fb] = [i] 928 + 929 + # We must recurse if any bin has more than one element or if 930 + # the single element in the bin has not been fully matched. 931 + t = Tree(fullmask, innermask) 932 + 933 + for b, l in bins.items(): 934 + s = l[0] 935 + if len(l) > 1 or s.fixedmask & ~fullmask != 0: 936 + s = build_tree(l, b | outerbits, fullmask) 937 + t.subs.append((b, s)) 938 + 939 + return t 940 + # end build_tree 941 + 942 + 943 + def prop_format(tree): 944 + """Propagate Format objects into the decode tree""" 945 + 946 + # Depth first search. 947 + for (b, s) in tree.subs: 948 + if isinstance(s, Tree): 949 + prop_format(s) 950 + 951 + # If all entries in SUBS have the same format, then 952 + # propagate that into the tree. 953 + f = None 954 + for (b, s) in tree.subs: 955 + if f is None: 956 + f = s.base 957 + if f is None: 958 + return 959 + if f is not s.base: 960 + return 961 + tree.base = f 962 + # end prop_format 963 + 964 + 965 + def main(): 966 + global arguments 967 + global formats 968 + global patterns 969 + global translate_scope 970 + global translate_prefix 971 + global output_fd 972 + global output_file 973 + global input_file 974 + global insnwidth 975 + global insntype 976 + 977 + decode_function = 'decode' 978 + decode_scope = 'static ' 979 + 980 + long_opts = ['decode=', 'translate=', 'output=', 'insnwidth='] 981 + try: 982 + (opts, args) = getopt.getopt(sys.argv[1:], 'o:w:', long_opts) 983 + except getopt.GetoptError as err: 984 + error(0, err) 985 + for o, a in opts: 986 + if o in ('-o', '--output'): 987 + output_file = a 988 + elif o == '--decode': 989 + decode_function = a 990 + decode_scope = '' 991 + elif o == '--translate': 992 + translate_prefix = a 993 + translate_scope = '' 994 + elif o in ('-w', '--insnwidth'): 995 + insnwidth = int(a) 996 + if insnwidth == 16: 997 + insntype = 'uint16_t' 998 + insnmask = 0xffff 999 + elif insnwidth != 32: 1000 + error(0, 'cannot handle insns of width', insnwidth) 1001 + else: 1002 + assert False, 'unhandled option' 1003 + 1004 + if len(args) < 1: 1005 + error(0, 'missing input file') 1006 + input_file = args[0] 1007 + f = open(input_file, 'r') 1008 + parse_file(f) 1009 + f.close() 1010 + 1011 + t = build_tree(patterns, 0, 0) 1012 + prop_format(t) 1013 + 1014 + if output_file: 1015 + output_fd = open(output_file, 'w') 1016 + else: 1017 + output_fd = sys.stdout 1018 + 1019 + output_autogen() 1020 + for n in sorted(arguments.keys()): 1021 + f = arguments[n] 1022 + f.output_def() 1023 + 1024 + # A single translate function can be invoked for different patterns. 1025 + # Make sure that the argument sets are the same, and declare the 1026 + # function only once. 1027 + out_pats = {} 1028 + for i in patterns: 1029 + if i.name in out_pats: 1030 + p = out_pats[i.name] 1031 + if i.base.base != p.base.base: 1032 + error(0, i.name, ' has conflicting argument sets') 1033 + else: 1034 + i.output_decl() 1035 + out_pats[i.name] = i 1036 + output('\n') 1037 + 1038 + for n in sorted(formats.keys()): 1039 + f = formats[n] 1040 + f.output_extract() 1041 + 1042 + output(decode_scope, 'bool ', decode_function, 1043 + '(DisasContext *ctx, ', insntype, ' insn)\n{\n') 1044 + 1045 + i4 = str_indent(4) 1046 + output(i4, 'union {\n') 1047 + for n in sorted(arguments.keys()): 1048 + f = arguments[n] 1049 + output(i4, i4, f.struct_name(), ' f_', f.name, ';\n') 1050 + output(i4, '} u;\n\n') 1051 + 1052 + t.output_code(4, False, 0, 0) 1053 + 1054 + output('}\n') 1055 + 1056 + if output_file: 1057 + output_fd.close() 1058 + # end main 1059 + 1060 + 1061 + if __name__ == '__main__': 1062 + main()
+8 -1
tests/Makefile.include
··· 932 932 check-tests/qapi-schema/doc-good.texi: tests/qapi-schema/doc-good.test.texi 933 933 @diff -q $(SRC_PATH)/tests/qapi-schema/doc-good.texi $< 934 934 935 + .PHONY: check-decodetree 936 + check-decodetree: 937 + $(call quiet-command, \ 938 + cd $(SRC_PATH)/tests/decode && \ 939 + ./check.sh "$(PYTHON)" "$(SRC_PATH)/scripts/decodetree.py", \ 940 + TEST, decodetree.py) 941 + 935 942 # Consolidated targets 936 943 937 944 .PHONY: check-qapi-schema check-qtest check-unit check check-clean ··· 940 947 check-unit: $(patsubst %,check-%, $(check-unit-y)) 941 948 check-speed: $(patsubst %,check-%, $(check-speed-y)) 942 949 check-block: $(patsubst %,check-%, $(check-block-y)) 943 - check: check-qapi-schema check-unit check-qtest 950 + check: check-qapi-schema check-unit check-qtest check-decodetree 944 951 check-clean: 945 952 $(MAKE) -C tests/tcg clean 946 953 rm -rf $(check-unit-y) tests/*.o $(QEMU_IOTESTS_HELPERS-y)
+18
tests/decode/check.sh
··· 1 + #!/bin/sh 2 + # This work is licensed under the terms of the GNU LGPL, version 2 or later. 3 + # See the COPYING.LIB file in the top-level directory. 4 + 5 + PYTHON=$1 6 + DECODETREE=$2 7 + E=0 8 + 9 + # All of these tests should produce errors 10 + for i in err_*.decode; do 11 + if $PYTHON $DECODETREE $i > /dev/null 2> /dev/null; then 12 + # Pass, aka failed to fail. 13 + echo FAIL: $i 1>&2 14 + E=1 15 + fi 16 + done 17 + 18 + exit $E
+5
tests/decode/err_argset1.decode
··· 1 + # This work is licensed under the terms of the GNU LGPL, version 2 or later. 2 + # See the COPYING.LIB file in the top-level directory. 3 + 4 + # Diagnose duplicate member names 5 + &args a a
+5
tests/decode/err_argset2.decode
··· 1 + # This work is licensed under the terms of the GNU LGPL, version 2 or later. 2 + # See the COPYING.LIB file in the top-level directory. 3 + 4 + # Diagnose invalid member names 5 + &args a b c d0 0e
+5
tests/decode/err_field1.decode
··· 1 + # This work is licensed under the terms of the GNU LGPL, version 2 or later. 2 + # See the COPYING.LIB file in the top-level directory. 3 + 4 + # Diagnose invalid field syntax 5 + %field asdf
+5
tests/decode/err_field2.decode
··· 1 + # This work is licensed under the terms of the GNU LGPL, version 2 or later. 2 + # See the COPYING.LIB file in the top-level directory. 3 + 4 + # Diagnose invalid field width. 5 + %field 0:33
+5
tests/decode/err_field3.decode
··· 1 + # This work is licensed under the terms of the GNU LGPL, version 2 or later. 2 + # See the COPYING.LIB file in the top-level directory. 3 + 4 + # Diagnose invalid field position. 5 + %field 31:2
+6
tests/decode/err_field4.decode
··· 1 + # This work is licensed under the terms of the GNU LGPL, version 2 or later. 2 + # See the COPYING.LIB file in the top-level directory. 3 + 4 + # Diagnose duplicate field name. 5 + %field 0:1 6 + %field 0:1
+5
tests/decode/err_field5.decode
··· 1 + # This work is licensed under the terms of the GNU LGPL, version 2 or later. 2 + # See the COPYING.LIB file in the top-level directory. 3 + 4 + # Diagnose duplicate function specifier. 5 + %field 0:1 !function=a !function=a
+6
tests/decode/err_init1.decode
··· 1 + # This work is licensed under the terms of the GNU LGPL, version 2 or later. 2 + # See the COPYING.LIB file in the top-level directory. 3 + 4 + # Diagnose uninitialized member in pattern. 5 + &args a b 6 + insn 00000000 00000000 00000000 b:8 &args
+6
tests/decode/err_init2.decode
··· 1 + # This work is licensed under the terms of the GNU LGPL, version 2 or later. 2 + # See the COPYING.LIB file in the top-level directory. 3 + 4 + # Diagnose member initialized twice in pattern. 5 + &args a b 6 + insn 00000000 00000000 a:8 b:8 &args a=1
+7
tests/decode/err_init3.decode
··· 1 + # This work is licensed under the terms of the GNU LGPL, version 2 or later. 2 + # See the COPYING.LIB file in the top-level directory. 3 + 4 + # Diagnose member initialized twice in pattern + format. 5 + &args a 6 + @format ........ ........ a:16 &args 7 + insn 00000000 00000000 a:16 @format
+7
tests/decode/err_init4.decode
··· 1 + # This work is licensed under the terms of the GNU LGPL, version 2 or later. 2 + # See the COPYING.LIB file in the top-level directory. 3 + 4 + # Diagnose uninitialized member in pattern + format. 5 + &args a b 6 + @format ........ ........ a:16 &args 7 + insn 00000000 00000000 ........ ........ @format
+6
tests/decode/err_overlap1.decode
··· 1 + # This work is licensed under the terms of the GNU LGPL, version 2 or later. 2 + # See the COPYING.LIB file in the top-level directory. 3 + 4 + # Diagnose field overlapping fixedbits. 5 + %field 0:1 6 + insn 00000000 00000000 00000000 00000000 %field
+6
tests/decode/err_overlap2.decode
··· 1 + # This work is licensed under the terms of the GNU LGPL, version 2 or later. 2 + # See the COPYING.LIB file in the top-level directory. 3 + 4 + # Diagnose field overlapping fixedbits w/format. 5 + @format ........ ........ ........ ....... fld:1 6 + insn 00000000 00000000 00000000 00000000 @format
+6
tests/decode/err_overlap3.decode
··· 1 + # This work is licensed under the terms of the GNU LGPL, version 2 or later. 2 + # See the COPYING.LIB file in the top-level directory. 3 + 4 + # Diagnose field overlapping unspecified bits. 5 + %field 0:1 6 + insn 00000000 00000000 00000000 -------- %field
+6
tests/decode/err_overlap4.decode
··· 1 + # This work is licensed under the terms of the GNU LGPL, version 2 or later. 2 + # See the COPYING.LIB file in the top-level directory. 3 + 4 + # Diagnose fixed bits overlapping unspecified bits. 5 + @format ........ ........ ........ .......- 6 + insn 00000000 00000000 00000000 00000000 @format
+5
tests/decode/err_overlap5.decode
··· 1 + # This work is licensed under the terms of the GNU LGPL, version 2 or later. 2 + # See the COPYING.LIB file in the top-level directory. 3 + 4 + # Diagnose overlapping sub-fields. 5 + %field 3:5 0:5
+6
tests/decode/err_overlap6.decode
··· 1 + # This work is licensed under the terms of the GNU LGPL, version 2 or later. 2 + # See the COPYING.LIB file in the top-level directory. 3 + 4 + # Diagnose overlapping fixed bits w/format. 5 + @format ........ ........ ........ .......1 6 + insn 00000000 00000000 00000000 00000000 @format
+6
tests/decode/err_overlap7.decode
··· 1 + # This work is licensed under the terms of the GNU LGPL, version 2 or later. 2 + # See the COPYING.LIB file in the top-level directory. 3 + 4 + # Diagnose overlapping patterns. 5 + insn1 00000000 00000000 00000000 00000000 6 + insn2 00000000 00000000 00000000 00000000
+5
tests/decode/err_overlap8.decode
··· 1 + # This work is licensed under the terms of the GNU LGPL, version 2 or later. 2 + # See the COPYING.LIB file in the top-level directory. 3 + 4 + # Diagnose not specified bit (. vs -). 5 + insn 00000000 00000000 00000000 0000000.
+6
tests/decode/err_overlap9.decode
··· 1 + # This work is licensed under the terms of the GNU LGPL, version 2 or later. 2 + # See the COPYING.LIB file in the top-level directory. 3 + 4 + # Diagnose not specified bit (. vs -) w/format. 5 + @format ........ a:8 ........ b:7 . 6 + insn 00000000 ........ 00000000 ........ @format