mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2024-12-23 06:45:35 +00:00
decodetree: Allow grouping of overlapping patterns
Backports commit 0eff2df4a2ce677230119440f7eb057acffad5eb from qemu
This commit is contained in:
parent
0c1b2a5d5a
commit
c8514cc538
|
@ -163,6 +163,7 @@ fields = {}
|
||||||
arguments = {}
|
arguments = {}
|
||||||
formats = {}
|
formats = {}
|
||||||
patterns = []
|
patterns = []
|
||||||
|
allpatterns = []
|
||||||
|
|
||||||
translate_prefix = 'trans'
|
translate_prefix = 'trans'
|
||||||
translate_scope = 'static '
|
translate_scope = 'static '
|
||||||
|
@ -434,13 +435,7 @@ class General:
|
||||||
self.fields = flds
|
self.fields = flds
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
r = self.name
|
return self.name + ' ' + str_match_bits(self.fixedbits, self.fixedmask)
|
||||||
if self.base:
|
|
||||||
r = r + ' ' + self.base.name
|
|
||||||
else:
|
|
||||||
r = r + ' ' + str(self.fields)
|
|
||||||
r = r + ' ' + str_match_bits(self.fixedbits, self.fixedmask)
|
|
||||||
return r
|
|
||||||
|
|
||||||
def str1(self, i):
|
def str1(self, i):
|
||||||
return str_indent(i) + self.__str__()
|
return str_indent(i) + self.__str__()
|
||||||
|
@ -487,6 +482,47 @@ class Pattern(General):
|
||||||
# end Pattern
|
# end Pattern
|
||||||
|
|
||||||
|
|
||||||
|
class MultiPattern(General):
|
||||||
|
"""Class representing an overlapping set of instruction patterns"""
|
||||||
|
|
||||||
|
def __init__(self, lineno, pats, fixb, fixm, udfm):
|
||||||
|
self.file = input_file
|
||||||
|
self.lineno = lineno
|
||||||
|
self.pats = pats
|
||||||
|
self.base = None
|
||||||
|
self.fixedbits = fixb
|
||||||
|
self.fixedmask = fixm
|
||||||
|
self.undefmask = udfm
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
r = "{"
|
||||||
|
for p in self.pats:
|
||||||
|
r = r + ' ' + str(p)
|
||||||
|
return r + "}"
|
||||||
|
|
||||||
|
def output_decl(self):
|
||||||
|
for p in self.pats:
|
||||||
|
p.output_decl()
|
||||||
|
|
||||||
|
def output_code(self, i, extracted, outerbits, outermask):
|
||||||
|
global translate_prefix
|
||||||
|
ind = str_indent(i)
|
||||||
|
for p in self.pats:
|
||||||
|
if outermask != p.fixedmask:
|
||||||
|
innermask = p.fixedmask & ~outermask
|
||||||
|
innerbits = p.fixedbits & ~outermask
|
||||||
|
output(ind, 'if ((insn & ',
|
||||||
|
'0x{0:08x}) == 0x{1:08x}'.format(innermask, innerbits),
|
||||||
|
') {\n')
|
||||||
|
output(ind, ' /* ',
|
||||||
|
str_match_bits(p.fixedbits, p.fixedmask), ' */\n')
|
||||||
|
p.output_code(i + 4, extracted, p.fixedbits, p.fixedmask)
|
||||||
|
output(ind, '}\n')
|
||||||
|
else:
|
||||||
|
p.output_code(i, extracted, p.fixedbits, p.fixedmask)
|
||||||
|
#end MultiPattern
|
||||||
|
|
||||||
|
|
||||||
def parse_field(lineno, name, toks):
|
def parse_field(lineno, name, toks):
|
||||||
"""Parse one instruction field from TOKS at LINENO"""
|
"""Parse one instruction field from TOKS at LINENO"""
|
||||||
global fields
|
global fields
|
||||||
|
@ -639,6 +675,7 @@ def parse_generic(lineno, is_format, name, toks):
|
||||||
global arguments
|
global arguments
|
||||||
global formats
|
global formats
|
||||||
global patterns
|
global patterns
|
||||||
|
global allpatterns
|
||||||
global re_ident
|
global re_ident
|
||||||
global insnwidth
|
global insnwidth
|
||||||
global insnmask
|
global insnmask
|
||||||
|
@ -783,6 +820,7 @@ def parse_generic(lineno, is_format, name, toks):
|
||||||
pat = Pattern(name, lineno, fmt, fixedbits, fixedmask,
|
pat = Pattern(name, lineno, fmt, fixedbits, fixedmask,
|
||||||
undefmask, fieldmask, flds)
|
undefmask, fieldmask, flds)
|
||||||
patterns.append(pat)
|
patterns.append(pat)
|
||||||
|
allpatterns.append(pat)
|
||||||
|
|
||||||
# Validate the masks that we have assembled.
|
# Validate the masks that we have assembled.
|
||||||
if fieldmask & fixedmask:
|
if fieldmask & fixedmask:
|
||||||
|
@ -802,16 +840,67 @@ def parse_generic(lineno, is_format, name, toks):
|
||||||
# end parse_general
|
# end parse_general
|
||||||
|
|
||||||
|
|
||||||
|
def build_multi_pattern(lineno, pats):
|
||||||
|
"""Validate the Patterns going into a MultiPattern."""
|
||||||
|
global patterns
|
||||||
|
global insnmask
|
||||||
|
|
||||||
|
if len(pats) < 2:
|
||||||
|
error(lineno, 'less than two patterns within braces')
|
||||||
|
|
||||||
|
fixedmask = insnmask
|
||||||
|
undefmask = insnmask
|
||||||
|
|
||||||
|
# Collect fixed/undefmask for all of the children.
|
||||||
|
# Move the defining lineno back to that of the first child.
|
||||||
|
for p in pats:
|
||||||
|
fixedmask &= p.fixedmask
|
||||||
|
undefmask &= p.undefmask
|
||||||
|
if p.lineno < lineno:
|
||||||
|
lineno = p.lineno
|
||||||
|
|
||||||
|
repeat = True
|
||||||
|
while repeat:
|
||||||
|
if fixedmask == 0:
|
||||||
|
error(lineno, 'no overlap in patterns within braces')
|
||||||
|
fixedbits = None
|
||||||
|
for p in pats:
|
||||||
|
thisbits = p.fixedbits & fixedmask
|
||||||
|
if fixedbits is None:
|
||||||
|
fixedbits = thisbits
|
||||||
|
elif fixedbits != thisbits:
|
||||||
|
fixedmask &= ~(fixedbits ^ thisbits)
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
repeat = False
|
||||||
|
|
||||||
|
mp = MultiPattern(lineno, pats, fixedbits, fixedmask, undefmask)
|
||||||
|
patterns.append(mp)
|
||||||
|
# end build_multi_pattern
|
||||||
|
|
||||||
|
|
||||||
def parse_file(f):
|
def parse_file(f):
|
||||||
"""Parse all of the patterns within a file"""
|
"""Parse all of the patterns within a file"""
|
||||||
|
|
||||||
|
global patterns
|
||||||
|
|
||||||
# Read all of the lines of the file. Concatenate lines
|
# Read all of the lines of the file. Concatenate lines
|
||||||
# ending in backslash; discard empty lines and comments.
|
# ending in backslash; discard empty lines and comments.
|
||||||
toks = []
|
toks = []
|
||||||
lineno = 0
|
lineno = 0
|
||||||
|
nesting = 0
|
||||||
|
saved_pats = []
|
||||||
|
|
||||||
for line in f:
|
for line in f:
|
||||||
lineno += 1
|
lineno += 1
|
||||||
|
|
||||||
|
# Expand and strip spaces, to find indent.
|
||||||
|
line = line.rstrip()
|
||||||
|
line = line.expandtabs()
|
||||||
|
len1 = len(line)
|
||||||
|
line = line.lstrip()
|
||||||
|
len2 = len(line)
|
||||||
|
|
||||||
# Discard comments
|
# Discard comments
|
||||||
end = line.find('#')
|
end = line.find('#')
|
||||||
if end >= 0:
|
if end >= 0:
|
||||||
|
@ -821,10 +910,18 @@ def parse_file(f):
|
||||||
if len(toks) != 0:
|
if len(toks) != 0:
|
||||||
# Next line after continuation
|
# Next line after continuation
|
||||||
toks.extend(t)
|
toks.extend(t)
|
||||||
elif len(t) == 0:
|
|
||||||
# Empty line
|
|
||||||
continue
|
|
||||||
else:
|
else:
|
||||||
|
# Allow completely blank lines.
|
||||||
|
if len1 == 0:
|
||||||
|
continue
|
||||||
|
indent = len1 - len2
|
||||||
|
# Empty line due to comment.
|
||||||
|
if len(t) == 0:
|
||||||
|
# Indentation must be correct, even for comment lines.
|
||||||
|
if indent != nesting:
|
||||||
|
error(lineno, 'indentation ', indent, ' != ', nesting)
|
||||||
|
continue
|
||||||
|
start_lineno = lineno
|
||||||
toks = t
|
toks = t
|
||||||
|
|
||||||
# Continuation?
|
# Continuation?
|
||||||
|
@ -832,21 +929,47 @@ def parse_file(f):
|
||||||
toks.pop()
|
toks.pop()
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if len(toks) < 2:
|
|
||||||
error(lineno, 'short line')
|
|
||||||
|
|
||||||
name = toks[0]
|
name = toks[0]
|
||||||
del toks[0]
|
del toks[0]
|
||||||
|
|
||||||
|
# End nesting?
|
||||||
|
if name == '}':
|
||||||
|
if nesting == 0:
|
||||||
|
error(start_lineno, 'mismatched close brace')
|
||||||
|
if len(toks) != 0:
|
||||||
|
error(start_lineno, 'extra tokens after close brace')
|
||||||
|
nesting -= 2
|
||||||
|
if indent != nesting:
|
||||||
|
error(start_lineno, 'indentation ', indent, ' != ', nesting)
|
||||||
|
pats = patterns
|
||||||
|
patterns = saved_pats.pop()
|
||||||
|
build_multi_pattern(lineno, pats)
|
||||||
|
toks = []
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Everything else should have current indentation.
|
||||||
|
if indent != nesting:
|
||||||
|
error(start_lineno, 'indentation ', indent, ' != ', nesting)
|
||||||
|
|
||||||
|
# Start nesting?
|
||||||
|
if name == '{':
|
||||||
|
if len(toks) != 0:
|
||||||
|
error(start_lineno, 'extra tokens after open brace')
|
||||||
|
saved_pats.append(patterns)
|
||||||
|
patterns = []
|
||||||
|
nesting += 2
|
||||||
|
toks = []
|
||||||
|
continue
|
||||||
|
|
||||||
# Determine the type of object needing to be parsed.
|
# Determine the type of object needing to be parsed.
|
||||||
if name[0] == '%':
|
if name[0] == '%':
|
||||||
parse_field(lineno, name[1:], toks)
|
parse_field(start_lineno, name[1:], toks)
|
||||||
elif name[0] == '&':
|
elif name[0] == '&':
|
||||||
parse_arguments(lineno, name[1:], toks)
|
parse_arguments(start_lineno, name[1:], toks)
|
||||||
elif name[0] == '@':
|
elif name[0] == '@':
|
||||||
parse_generic(lineno, True, name[1:], toks)
|
parse_generic(start_lineno, True, name[1:], toks)
|
||||||
else:
|
else:
|
||||||
parse_generic(lineno, False, name, toks)
|
parse_generic(start_lineno, False, name, toks)
|
||||||
toks = []
|
toks = []
|
||||||
# end parse_file
|
# end parse_file
|
||||||
|
|
||||||
|
@ -923,11 +1046,10 @@ def build_tree(pats, outerbits, outermask):
|
||||||
innermask &= i.fixedmask
|
innermask &= i.fixedmask
|
||||||
|
|
||||||
if innermask == 0:
|
if innermask == 0:
|
||||||
pnames = []
|
text = 'overlapping patterns:'
|
||||||
for p in pats:
|
for p in pats:
|
||||||
pnames.append(p.name + ':' + p.file + ':' + str(p.lineno))
|
text += '\n' + p.file + ':' + str(p.lineno) + ': ' + str(p)
|
||||||
error_with_file(pats[0].file, pats[0].lineno,
|
error_with_file(pats[0].file, pats[0].lineno, text)
|
||||||
'overlapping patterns:', pnames)
|
|
||||||
|
|
||||||
fullmask = outermask | innermask
|
fullmask = outermask | innermask
|
||||||
|
|
||||||
|
@ -980,6 +1102,7 @@ def main():
|
||||||
global arguments
|
global arguments
|
||||||
global formats
|
global formats
|
||||||
global patterns
|
global patterns
|
||||||
|
global allpatterns
|
||||||
global translate_scope
|
global translate_scope
|
||||||
global translate_prefix
|
global translate_prefix
|
||||||
global output_fd
|
global output_fd
|
||||||
|
@ -1041,7 +1164,7 @@ def main():
|
||||||
# Make sure that the argument sets are the same, and declare the
|
# Make sure that the argument sets are the same, and declare the
|
||||||
# function only once.
|
# function only once.
|
||||||
out_pats = {}
|
out_pats = {}
|
||||||
for i in patterns:
|
for i in allpatterns:
|
||||||
if i.name in out_pats:
|
if i.name in out_pats:
|
||||||
p = out_pats[i.name]
|
p = out_pats[i.name]
|
||||||
if i.base.base != p.base.base:
|
if i.base.base != p.base.base:
|
||||||
|
|
Loading…
Reference in a new issue