mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-15 06:01:58 -06:00
Add non-overlapping groups
-----BEGIN PGP SIGNATURE----- iQFRBAABCgA7FiEEekgeeIaLTbaoWgXAZN846K9+IV8FAl7ftzkdHHJpY2hhcmQu aGVuZGVyc29uQGxpbmFyby5vcmcACgkQZN846K9+IV+N5Af9H2MaCN9Eka7VmHAd duob3PBkGsQ8jOCOtOQMVukkptkOk2cMycXlW77DJsVrjX3nzpJ6yZ52MH4WO0vn ddFeutkK4iaw+3mBQkEFaJC1H8GavuHz0dMK5NR3WtOvAnZ1eQyEbqFTkbMHJgFI TVyNUz3jfsqCLBDxEx8JU3v5dycMET3WKlvFP6aO2FnQNKBSZXnxTcd7eCN67KOs e+XmBvcsLuGp6fxrIrNFwakjy48jExytfMRdWVSDulC0ErUw9bV4fI9Z8kHV5ETd bL+q5ADFKvogEQeGW74+44zebtmgosO1GWDMfbSTjIdnUQrdAff+Y7huHateaXWs +FHszA== =Z5Ta -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/rth/tags/pull-dt-20200609' into staging Add non-overlapping groups # gpg: Signature made Tue 09 Jun 2020 17:22:17 BST # gpg: using RSA key 7A481E78868B4DB6A85A05C064DF38E8AF7E215F # gpg: issuer "richard.henderson@linaro.org" # gpg: Good signature from "Richard Henderson <richard.henderson@linaro.org>" [full] # Primary key fingerprint: 7A48 1E78 868B 4DB6 A85A 05C0 64DF 38E8 AF7E 215F * remotes/rth/tags/pull-dt-20200609: target/arm: Use a non-overlapping group for misc control decodetree: Drop check for less than 2 patterns in a group tests/decode: Test non-overlapping groups decodetree: Implement non-overlapping groups decodetree: Move semantic propagation into classes decodetree: Allow group covering the entire insn space decodetree: Split out MultiPattern from IncMultiPattern decodetree: Rename MultiPattern to IncMultiPattern decodetree: Tidy error_with_file Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
c291aca63d
8 changed files with 360 additions and 225 deletions
|
@ -31,7 +31,6 @@ variablewidth = False
|
||||||
fields = {}
|
fields = {}
|
||||||
arguments = {}
|
arguments = {}
|
||||||
formats = {}
|
formats = {}
|
||||||
patterns = []
|
|
||||||
allpatterns = []
|
allpatterns = []
|
||||||
anyextern = False
|
anyextern = False
|
||||||
|
|
||||||
|
@ -51,23 +50,27 @@ def error_with_file(file, lineno, *args):
|
||||||
global output_file
|
global output_file
|
||||||
global output_fd
|
global output_fd
|
||||||
|
|
||||||
|
prefix = ''
|
||||||
|
if file:
|
||||||
|
prefix += '{0}:'.format(file)
|
||||||
if lineno:
|
if lineno:
|
||||||
r = '{0}:{1}: error:'.format(file, lineno)
|
prefix += '{0}:'.format(lineno)
|
||||||
elif input_file:
|
if prefix:
|
||||||
r = '{0}: error:'.format(file)
|
prefix += ' '
|
||||||
else:
|
print(prefix, end='error: ', file=sys.stderr)
|
||||||
r = 'error:'
|
print(*args, file=sys.stderr)
|
||||||
for a in args:
|
|
||||||
r += ' ' + str(a)
|
|
||||||
r += '\n'
|
|
||||||
sys.stderr.write(r)
|
|
||||||
if output_file and output_fd:
|
if output_file and output_fd:
|
||||||
output_fd.close()
|
output_fd.close()
|
||||||
os.remove(output_file)
|
os.remove(output_file)
|
||||||
exit(1)
|
exit(1)
|
||||||
|
# end error_with_file
|
||||||
|
|
||||||
|
|
||||||
def error(lineno, *args):
|
def error(lineno, *args):
|
||||||
error_with_file(input_file, lineno, args)
|
error_with_file(input_file, lineno, *args)
|
||||||
|
# end error
|
||||||
|
|
||||||
|
|
||||||
def output(*args):
|
def output(*args):
|
||||||
global output_fd
|
global output_fd
|
||||||
|
@ -120,6 +123,7 @@ def is_pow2(x):
|
||||||
|
|
||||||
def ctz(x):
|
def ctz(x):
|
||||||
"""Return the number of times 2 factors into X."""
|
"""Return the number of times 2 factors into X."""
|
||||||
|
assert x != 0
|
||||||
r = 0
|
r = 0
|
||||||
while ((x >> r) & 1) == 0:
|
while ((x >> r) & 1) == 0:
|
||||||
r += 1
|
r += 1
|
||||||
|
@ -127,6 +131,8 @@ def ctz(x):
|
||||||
|
|
||||||
|
|
||||||
def is_contiguous(bits):
|
def is_contiguous(bits):
|
||||||
|
if bits == 0:
|
||||||
|
return -1
|
||||||
shift = ctz(bits)
|
shift = ctz(bits)
|
||||||
if is_pow2((bits >> shift) + 1):
|
if is_pow2((bits >> shift) + 1):
|
||||||
return shift
|
return shift
|
||||||
|
@ -364,32 +370,99 @@ class Pattern(General):
|
||||||
output(ind, 'u.f_', arg, '.', n, ' = ', f.str_extract(), ';\n')
|
output(ind, 'u.f_', arg, '.', n, ' = ', f.str_extract(), ';\n')
|
||||||
output(ind, 'if (', translate_prefix, '_', self.name,
|
output(ind, 'if (', translate_prefix, '_', self.name,
|
||||||
'(ctx, &u.f_', arg, ')) return true;\n')
|
'(ctx, &u.f_', arg, ')) return true;\n')
|
||||||
|
|
||||||
|
# Normal patterns do not have children.
|
||||||
|
def build_tree(self):
|
||||||
|
return
|
||||||
|
def prop_masks(self):
|
||||||
|
return
|
||||||
|
def prop_format(self):
|
||||||
|
return
|
||||||
|
def prop_width(self):
|
||||||
|
return
|
||||||
|
|
||||||
# end Pattern
|
# end Pattern
|
||||||
|
|
||||||
|
|
||||||
class MultiPattern(General):
|
class MultiPattern(General):
|
||||||
"""Class representing an overlapping set of instruction patterns"""
|
"""Class representing a set of instruction patterns"""
|
||||||
|
|
||||||
def __init__(self, lineno, pats, fixb, fixm, udfm, w):
|
def __init__(self, lineno):
|
||||||
self.file = input_file
|
self.file = input_file
|
||||||
self.lineno = lineno
|
self.lineno = lineno
|
||||||
self.pats = pats
|
self.pats = []
|
||||||
self.base = None
|
self.base = None
|
||||||
self.fixedbits = fixb
|
self.fixedbits = 0
|
||||||
self.fixedmask = fixm
|
self.fixedmask = 0
|
||||||
self.undefmask = udfm
|
self.undefmask = 0
|
||||||
self.width = w
|
self.width = None
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
r = "{"
|
r = 'group'
|
||||||
for p in self.pats:
|
if self.fixedbits is not None:
|
||||||
r = r + ' ' + str(p)
|
r += ' ' + str_match_bits(self.fixedbits, self.fixedmask)
|
||||||
return r + "}"
|
return r
|
||||||
|
|
||||||
def output_decl(self):
|
def output_decl(self):
|
||||||
for p in self.pats:
|
for p in self.pats:
|
||||||
p.output_decl()
|
p.output_decl()
|
||||||
|
|
||||||
|
def prop_masks(self):
|
||||||
|
global insnmask
|
||||||
|
|
||||||
|
fixedmask = insnmask
|
||||||
|
undefmask = insnmask
|
||||||
|
|
||||||
|
# Collect fixedmask/undefmask for all of the children.
|
||||||
|
for p in self.pats:
|
||||||
|
p.prop_masks()
|
||||||
|
fixedmask &= p.fixedmask
|
||||||
|
undefmask &= p.undefmask
|
||||||
|
|
||||||
|
# Widen fixedmask until all fixedbits match
|
||||||
|
repeat = True
|
||||||
|
fixedbits = 0
|
||||||
|
while repeat and fixedmask != 0:
|
||||||
|
fixedbits = None
|
||||||
|
for p in self.pats:
|
||||||
|
thisbits = p.fixedbits & fixedmask
|
||||||
|
if fixedbits is None:
|
||||||
|
fixedbits = thisbits
|
||||||
|
elif fixedbits != thisbits:
|
||||||
|
fixedmask &= ~(fixedbits ^ thisbits)
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
repeat = False
|
||||||
|
|
||||||
|
self.fixedbits = fixedbits
|
||||||
|
self.fixedmask = fixedmask
|
||||||
|
self.undefmask = undefmask
|
||||||
|
|
||||||
|
def build_tree(self):
|
||||||
|
for p in self.pats:
|
||||||
|
p.build_tree()
|
||||||
|
|
||||||
|
def prop_format(self):
|
||||||
|
for p in self.pats:
|
||||||
|
p.build_tree()
|
||||||
|
|
||||||
|
def prop_width(self):
|
||||||
|
width = None
|
||||||
|
for p in self.pats:
|
||||||
|
p.prop_width()
|
||||||
|
if width is None:
|
||||||
|
width = p.width
|
||||||
|
elif width != p.width:
|
||||||
|
error_with_file(self.file, self.lineno,
|
||||||
|
'width mismatch in patterns within braces')
|
||||||
|
self.width = width
|
||||||
|
|
||||||
|
# end MultiPattern
|
||||||
|
|
||||||
|
|
||||||
|
class IncMultiPattern(MultiPattern):
|
||||||
|
"""Class representing an overlapping set of instruction patterns"""
|
||||||
|
|
||||||
def output_code(self, i, extracted, outerbits, outermask):
|
def output_code(self, i, extracted, outerbits, outermask):
|
||||||
global translate_prefix
|
global translate_prefix
|
||||||
ind = str_indent(i)
|
ind = str_indent(i)
|
||||||
|
@ -406,7 +479,154 @@ class MultiPattern(General):
|
||||||
output(ind, '}\n')
|
output(ind, '}\n')
|
||||||
else:
|
else:
|
||||||
p.output_code(i, extracted, p.fixedbits, p.fixedmask)
|
p.output_code(i, extracted, p.fixedbits, p.fixedmask)
|
||||||
#end MultiPattern
|
#end IncMultiPattern
|
||||||
|
|
||||||
|
|
||||||
|
class Tree:
|
||||||
|
"""Class representing a node in a decode tree"""
|
||||||
|
|
||||||
|
def __init__(self, fm, tm):
|
||||||
|
self.fixedmask = fm
|
||||||
|
self.thismask = tm
|
||||||
|
self.subs = []
|
||||||
|
self.base = None
|
||||||
|
|
||||||
|
def str1(self, i):
|
||||||
|
ind = str_indent(i)
|
||||||
|
r = '{0}{1:08x}'.format(ind, self.fixedmask)
|
||||||
|
if self.format:
|
||||||
|
r += ' ' + self.format.name
|
||||||
|
r += ' [\n'
|
||||||
|
for (b, s) in self.subs:
|
||||||
|
r += '{0} {1:08x}:\n'.format(ind, b)
|
||||||
|
r += s.str1(i + 4) + '\n'
|
||||||
|
r += ind + ']'
|
||||||
|
return r
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.str1(0)
|
||||||
|
|
||||||
|
def output_code(self, i, extracted, outerbits, outermask):
|
||||||
|
ind = str_indent(i)
|
||||||
|
|
||||||
|
# If we identified all nodes below have the same format,
|
||||||
|
# extract the fields now.
|
||||||
|
if not extracted and self.base:
|
||||||
|
output(ind, self.base.extract_name(),
|
||||||
|
'(ctx, &u.f_', self.base.base.name, ', insn);\n')
|
||||||
|
extracted = True
|
||||||
|
|
||||||
|
# Attempt to aid the compiler in producing compact switch statements.
|
||||||
|
# If the bits in the mask are contiguous, extract them.
|
||||||
|
sh = is_contiguous(self.thismask)
|
||||||
|
if sh > 0:
|
||||||
|
# Propagate SH down into the local functions.
|
||||||
|
def str_switch(b, sh=sh):
|
||||||
|
return '(insn >> {0}) & 0x{1:x}'.format(sh, b >> sh)
|
||||||
|
|
||||||
|
def str_case(b, sh=sh):
|
||||||
|
return '0x{0:x}'.format(b >> sh)
|
||||||
|
else:
|
||||||
|
def str_switch(b):
|
||||||
|
return 'insn & 0x{0:08x}'.format(b)
|
||||||
|
|
||||||
|
def str_case(b):
|
||||||
|
return '0x{0:08x}'.format(b)
|
||||||
|
|
||||||
|
output(ind, 'switch (', str_switch(self.thismask), ') {\n')
|
||||||
|
for b, s in sorted(self.subs):
|
||||||
|
assert (self.thismask & ~s.fixedmask) == 0
|
||||||
|
innermask = outermask | self.thismask
|
||||||
|
innerbits = outerbits | b
|
||||||
|
output(ind, 'case ', str_case(b), ':\n')
|
||||||
|
output(ind, ' /* ',
|
||||||
|
str_match_bits(innerbits, innermask), ' */\n')
|
||||||
|
s.output_code(i + 4, extracted, innerbits, innermask)
|
||||||
|
output(ind, ' return false;\n')
|
||||||
|
output(ind, '}\n')
|
||||||
|
# end Tree
|
||||||
|
|
||||||
|
|
||||||
|
class ExcMultiPattern(MultiPattern):
|
||||||
|
"""Class representing a non-overlapping set of instruction patterns"""
|
||||||
|
|
||||||
|
def output_code(self, i, extracted, outerbits, outermask):
|
||||||
|
# Defer everything to our decomposed Tree node
|
||||||
|
self.tree.output_code(i, extracted, outerbits, outermask)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def __build_tree(pats, outerbits, outermask):
|
||||||
|
# Find the intersection of all remaining fixedmask.
|
||||||
|
innermask = ~outermask & insnmask
|
||||||
|
for i in pats:
|
||||||
|
innermask &= i.fixedmask
|
||||||
|
|
||||||
|
if innermask == 0:
|
||||||
|
# Edge condition: One pattern covers the entire insnmask
|
||||||
|
if len(pats) == 1:
|
||||||
|
t = Tree(outermask, innermask)
|
||||||
|
t.subs.append((0, pats[0]))
|
||||||
|
return t
|
||||||
|
|
||||||
|
text = 'overlapping patterns:'
|
||||||
|
for p in pats:
|
||||||
|
text += '\n' + p.file + ':' + str(p.lineno) + ': ' + str(p)
|
||||||
|
error_with_file(pats[0].file, pats[0].lineno, text)
|
||||||
|
|
||||||
|
fullmask = outermask | innermask
|
||||||
|
|
||||||
|
# Sort each element of pats into the bin selected by the mask.
|
||||||
|
bins = {}
|
||||||
|
for i in pats:
|
||||||
|
fb = i.fixedbits & innermask
|
||||||
|
if fb in bins:
|
||||||
|
bins[fb].append(i)
|
||||||
|
else:
|
||||||
|
bins[fb] = [i]
|
||||||
|
|
||||||
|
# We must recurse if any bin has more than one element or if
|
||||||
|
# the single element in the bin has not been fully matched.
|
||||||
|
t = Tree(fullmask, innermask)
|
||||||
|
|
||||||
|
for b, l in bins.items():
|
||||||
|
s = l[0]
|
||||||
|
if len(l) > 1 or s.fixedmask & ~fullmask != 0:
|
||||||
|
s = ExcMultiPattern.__build_tree(l, b | outerbits, fullmask)
|
||||||
|
t.subs.append((b, s))
|
||||||
|
|
||||||
|
return t
|
||||||
|
|
||||||
|
def build_tree(self):
|
||||||
|
super().prop_format()
|
||||||
|
self.tree = self.__build_tree(self.pats, self.fixedbits,
|
||||||
|
self.fixedmask)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def __prop_format(tree):
|
||||||
|
"""Propagate Format objects into the decode tree"""
|
||||||
|
|
||||||
|
# Depth first search.
|
||||||
|
for (b, s) in tree.subs:
|
||||||
|
if isinstance(s, Tree):
|
||||||
|
ExcMultiPattern.__prop_format(s)
|
||||||
|
|
||||||
|
# If all entries in SUBS have the same format, then
|
||||||
|
# propagate that into the tree.
|
||||||
|
f = None
|
||||||
|
for (b, s) in tree.subs:
|
||||||
|
if f is None:
|
||||||
|
f = s.base
|
||||||
|
if f is None:
|
||||||
|
return
|
||||||
|
if f is not s.base:
|
||||||
|
return
|
||||||
|
tree.base = f
|
||||||
|
|
||||||
|
def prop_format(self):
|
||||||
|
super().prop_format()
|
||||||
|
self.__prop_format(self.tree)
|
||||||
|
|
||||||
|
# end ExcMultiPattern
|
||||||
|
|
||||||
|
|
||||||
def parse_field(lineno, name, toks):
|
def parse_field(lineno, name, toks):
|
||||||
|
@ -565,18 +785,19 @@ def infer_format(arg, fieldmask, flds, width):
|
||||||
# end infer_format
|
# end infer_format
|
||||||
|
|
||||||
|
|
||||||
def parse_generic(lineno, is_format, name, toks):
|
def parse_generic(lineno, parent_pat, name, toks):
|
||||||
"""Parse one instruction format from TOKS at LINENO"""
|
"""Parse one instruction format from TOKS at LINENO"""
|
||||||
global fields
|
global fields
|
||||||
global arguments
|
global arguments
|
||||||
global formats
|
global formats
|
||||||
global patterns
|
|
||||||
global allpatterns
|
global allpatterns
|
||||||
global re_ident
|
global re_ident
|
||||||
global insnwidth
|
global insnwidth
|
||||||
global insnmask
|
global insnmask
|
||||||
global variablewidth
|
global variablewidth
|
||||||
|
|
||||||
|
is_format = parent_pat is None
|
||||||
|
|
||||||
fixedmask = 0
|
fixedmask = 0
|
||||||
fixedbits = 0
|
fixedbits = 0
|
||||||
undefmask = 0
|
undefmask = 0
|
||||||
|
@ -727,7 +948,7 @@ def parse_generic(lineno, is_format, name, toks):
|
||||||
error(lineno, 'field {0} not initialized'.format(f))
|
error(lineno, 'field {0} not initialized'.format(f))
|
||||||
pat = Pattern(name, lineno, fmt, fixedbits, fixedmask,
|
pat = Pattern(name, lineno, fmt, fixedbits, fixedmask,
|
||||||
undefmask, fieldmask, flds, width)
|
undefmask, fieldmask, flds, width)
|
||||||
patterns.append(pat)
|
parent_pat.pats.append(pat)
|
||||||
allpatterns.append(pat)
|
allpatterns.append(pat)
|
||||||
|
|
||||||
# Validate the masks that we have assembled.
|
# Validate the masks that we have assembled.
|
||||||
|
@ -747,62 +968,16 @@ def parse_generic(lineno, is_format, name, toks):
|
||||||
.format(allbits ^ insnmask))
|
.format(allbits ^ insnmask))
|
||||||
# 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:
|
def parse_file(f, parent_pat):
|
||||||
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
|
|
||||||
|
|
||||||
width = None
|
|
||||||
for p in pats:
|
|
||||||
if width is None:
|
|
||||||
width = p.width
|
|
||||||
elif width != p.width:
|
|
||||||
error(lineno, 'width mismatch in patterns within braces')
|
|
||||||
|
|
||||||
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, width)
|
|
||||||
patterns.append(mp)
|
|
||||||
# end build_multi_pattern
|
|
||||||
|
|
||||||
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
|
nesting = 0
|
||||||
saved_pats = []
|
nesting_pats = []
|
||||||
|
|
||||||
for line in f:
|
for line in f:
|
||||||
lineno += 1
|
lineno += 1
|
||||||
|
@ -846,17 +1021,23 @@ def parse_file(f):
|
||||||
del toks[0]
|
del toks[0]
|
||||||
|
|
||||||
# End nesting?
|
# End nesting?
|
||||||
if name == '}':
|
if name == '}' or name == ']':
|
||||||
if nesting == 0:
|
|
||||||
error(start_lineno, 'mismatched close brace')
|
|
||||||
if len(toks) != 0:
|
if len(toks) != 0:
|
||||||
error(start_lineno, 'extra tokens after close brace')
|
error(start_lineno, 'extra tokens after close brace')
|
||||||
|
|
||||||
|
# Make sure { } and [ ] nest properly.
|
||||||
|
if (name == '}') != isinstance(parent_pat, IncMultiPattern):
|
||||||
|
error(lineno, 'mismatched close brace')
|
||||||
|
|
||||||
|
try:
|
||||||
|
parent_pat = nesting_pats.pop()
|
||||||
|
except:
|
||||||
|
error(lineno, 'extra close brace')
|
||||||
|
|
||||||
nesting -= 2
|
nesting -= 2
|
||||||
if indent != nesting:
|
if indent != nesting:
|
||||||
error(start_lineno, 'indentation ', indent, ' != ', nesting)
|
error(lineno, 'indentation ', indent, ' != ', nesting)
|
||||||
pats = patterns
|
|
||||||
patterns = saved_pats.pop()
|
|
||||||
build_multi_pattern(lineno, pats)
|
|
||||||
toks = []
|
toks = []
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
@ -865,11 +1046,18 @@ def parse_file(f):
|
||||||
error(start_lineno, 'indentation ', indent, ' != ', nesting)
|
error(start_lineno, 'indentation ', indent, ' != ', nesting)
|
||||||
|
|
||||||
# Start nesting?
|
# Start nesting?
|
||||||
if name == '{':
|
if name == '{' or name == '[':
|
||||||
if len(toks) != 0:
|
if len(toks) != 0:
|
||||||
error(start_lineno, 'extra tokens after open brace')
|
error(start_lineno, 'extra tokens after open brace')
|
||||||
saved_pats.append(patterns)
|
|
||||||
patterns = []
|
if name == '{':
|
||||||
|
nested_pat = IncMultiPattern(start_lineno)
|
||||||
|
else:
|
||||||
|
nested_pat = ExcMultiPattern(start_lineno)
|
||||||
|
parent_pat.pats.append(nested_pat)
|
||||||
|
nesting_pats.append(parent_pat)
|
||||||
|
parent_pat = nested_pat
|
||||||
|
|
||||||
nesting += 2
|
nesting += 2
|
||||||
toks = []
|
toks = []
|
||||||
continue
|
continue
|
||||||
|
@ -880,115 +1068,16 @@ def parse_file(f):
|
||||||
elif name[0] == '&':
|
elif name[0] == '&':
|
||||||
parse_arguments(start_lineno, name[1:], toks)
|
parse_arguments(start_lineno, name[1:], toks)
|
||||||
elif name[0] == '@':
|
elif name[0] == '@':
|
||||||
parse_generic(start_lineno, True, name[1:], toks)
|
parse_generic(start_lineno, None, name[1:], toks)
|
||||||
else:
|
else:
|
||||||
parse_generic(start_lineno, False, name, toks)
|
parse_generic(start_lineno, parent_pat, name, toks)
|
||||||
toks = []
|
toks = []
|
||||||
|
|
||||||
|
if nesting != 0:
|
||||||
|
error(lineno, 'missing close brace')
|
||||||
# end parse_file
|
# end parse_file
|
||||||
|
|
||||||
|
|
||||||
class Tree:
|
|
||||||
"""Class representing a node in a decode tree"""
|
|
||||||
|
|
||||||
def __init__(self, fm, tm):
|
|
||||||
self.fixedmask = fm
|
|
||||||
self.thismask = tm
|
|
||||||
self.subs = []
|
|
||||||
self.base = None
|
|
||||||
|
|
||||||
def str1(self, i):
|
|
||||||
ind = str_indent(i)
|
|
||||||
r = '{0}{1:08x}'.format(ind, self.fixedmask)
|
|
||||||
if self.format:
|
|
||||||
r += ' ' + self.format.name
|
|
||||||
r += ' [\n'
|
|
||||||
for (b, s) in self.subs:
|
|
||||||
r += '{0} {1:08x}:\n'.format(ind, b)
|
|
||||||
r += s.str1(i + 4) + '\n'
|
|
||||||
r += ind + ']'
|
|
||||||
return r
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.str1(0)
|
|
||||||
|
|
||||||
def output_code(self, i, extracted, outerbits, outermask):
|
|
||||||
ind = str_indent(i)
|
|
||||||
|
|
||||||
# If we identified all nodes below have the same format,
|
|
||||||
# extract the fields now.
|
|
||||||
if not extracted and self.base:
|
|
||||||
output(ind, self.base.extract_name(),
|
|
||||||
'(ctx, &u.f_', self.base.base.name, ', insn);\n')
|
|
||||||
extracted = True
|
|
||||||
|
|
||||||
# Attempt to aid the compiler in producing compact switch statements.
|
|
||||||
# If the bits in the mask are contiguous, extract them.
|
|
||||||
sh = is_contiguous(self.thismask)
|
|
||||||
if sh > 0:
|
|
||||||
# Propagate SH down into the local functions.
|
|
||||||
def str_switch(b, sh=sh):
|
|
||||||
return '(insn >> {0}) & 0x{1:x}'.format(sh, b >> sh)
|
|
||||||
|
|
||||||
def str_case(b, sh=sh):
|
|
||||||
return '0x{0:x}'.format(b >> sh)
|
|
||||||
else:
|
|
||||||
def str_switch(b):
|
|
||||||
return 'insn & 0x{0:08x}'.format(b)
|
|
||||||
|
|
||||||
def str_case(b):
|
|
||||||
return '0x{0:08x}'.format(b)
|
|
||||||
|
|
||||||
output(ind, 'switch (', str_switch(self.thismask), ') {\n')
|
|
||||||
for b, s in sorted(self.subs):
|
|
||||||
assert (self.thismask & ~s.fixedmask) == 0
|
|
||||||
innermask = outermask | self.thismask
|
|
||||||
innerbits = outerbits | b
|
|
||||||
output(ind, 'case ', str_case(b), ':\n')
|
|
||||||
output(ind, ' /* ',
|
|
||||||
str_match_bits(innerbits, innermask), ' */\n')
|
|
||||||
s.output_code(i + 4, extracted, innerbits, innermask)
|
|
||||||
output(ind, ' return false;\n')
|
|
||||||
output(ind, '}\n')
|
|
||||||
# end Tree
|
|
||||||
|
|
||||||
|
|
||||||
def build_tree(pats, outerbits, outermask):
|
|
||||||
# Find the intersection of all remaining fixedmask.
|
|
||||||
innermask = ~outermask & insnmask
|
|
||||||
for i in pats:
|
|
||||||
innermask &= i.fixedmask
|
|
||||||
|
|
||||||
if innermask == 0:
|
|
||||||
text = 'overlapping patterns:'
|
|
||||||
for p in pats:
|
|
||||||
text += '\n' + p.file + ':' + str(p.lineno) + ': ' + str(p)
|
|
||||||
error_with_file(pats[0].file, pats[0].lineno, text)
|
|
||||||
|
|
||||||
fullmask = outermask | innermask
|
|
||||||
|
|
||||||
# Sort each element of pats into the bin selected by the mask.
|
|
||||||
bins = {}
|
|
||||||
for i in pats:
|
|
||||||
fb = i.fixedbits & innermask
|
|
||||||
if fb in bins:
|
|
||||||
bins[fb].append(i)
|
|
||||||
else:
|
|
||||||
bins[fb] = [i]
|
|
||||||
|
|
||||||
# We must recurse if any bin has more than one element or if
|
|
||||||
# the single element in the bin has not been fully matched.
|
|
||||||
t = Tree(fullmask, innermask)
|
|
||||||
|
|
||||||
for b, l in bins.items():
|
|
||||||
s = l[0]
|
|
||||||
if len(l) > 1 or s.fixedmask & ~fullmask != 0:
|
|
||||||
s = build_tree(l, b | outerbits, fullmask)
|
|
||||||
t.subs.append((b, s))
|
|
||||||
|
|
||||||
return t
|
|
||||||
# end build_tree
|
|
||||||
|
|
||||||
|
|
||||||
class SizeTree:
|
class SizeTree:
|
||||||
"""Class representing a node in a size decode tree"""
|
"""Class representing a node in a size decode tree"""
|
||||||
|
|
||||||
|
@ -1130,28 +1219,6 @@ def build_size_tree(pats, width, outerbits, outermask):
|
||||||
# end build_size_tree
|
# end build_size_tree
|
||||||
|
|
||||||
|
|
||||||
def prop_format(tree):
|
|
||||||
"""Propagate Format objects into the decode tree"""
|
|
||||||
|
|
||||||
# Depth first search.
|
|
||||||
for (b, s) in tree.subs:
|
|
||||||
if isinstance(s, Tree):
|
|
||||||
prop_format(s)
|
|
||||||
|
|
||||||
# If all entries in SUBS have the same format, then
|
|
||||||
# propagate that into the tree.
|
|
||||||
f = None
|
|
||||||
for (b, s) in tree.subs:
|
|
||||||
if f is None:
|
|
||||||
f = s.base
|
|
||||||
if f is None:
|
|
||||||
return
|
|
||||||
if f is not s.base:
|
|
||||||
return
|
|
||||||
tree.base = f
|
|
||||||
# end prop_format
|
|
||||||
|
|
||||||
|
|
||||||
def prop_size(tree):
|
def prop_size(tree):
|
||||||
"""Propagate minimum widths up the decode size tree"""
|
"""Propagate minimum widths up the decode size tree"""
|
||||||
|
|
||||||
|
@ -1172,7 +1239,6 @@ def prop_size(tree):
|
||||||
def main():
|
def main():
|
||||||
global arguments
|
global arguments
|
||||||
global formats
|
global formats
|
||||||
global patterns
|
|
||||||
global allpatterns
|
global allpatterns
|
||||||
global translate_scope
|
global translate_scope
|
||||||
global translate_prefix
|
global translate_prefix
|
||||||
|
@ -1219,18 +1285,29 @@ def main():
|
||||||
|
|
||||||
if len(args) < 1:
|
if len(args) < 1:
|
||||||
error(0, 'missing input file')
|
error(0, 'missing input file')
|
||||||
|
|
||||||
|
toppat = ExcMultiPattern(0)
|
||||||
|
|
||||||
for filename in args:
|
for filename in args:
|
||||||
input_file = filename
|
input_file = filename
|
||||||
f = open(filename, 'r')
|
f = open(filename, 'r')
|
||||||
parse_file(f)
|
parse_file(f, toppat)
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
if variablewidth:
|
# We do not want to compute masks for toppat, because those masks
|
||||||
stree = build_size_tree(patterns, 8, 0, 0)
|
# are used as a starting point for build_tree. For toppat, we must
|
||||||
prop_size(stree)
|
# insist that decode begins from naught.
|
||||||
|
for i in toppat.pats:
|
||||||
|
i.prop_masks()
|
||||||
|
|
||||||
dtree = build_tree(patterns, 0, 0)
|
toppat.build_tree()
|
||||||
prop_format(dtree)
|
toppat.prop_format()
|
||||||
|
|
||||||
|
if variablewidth:
|
||||||
|
for i in toppat.pats:
|
||||||
|
i.prop_width()
|
||||||
|
stree = build_size_tree(toppat.pats, 8, 0, 0)
|
||||||
|
prop_size(stree)
|
||||||
|
|
||||||
if output_file:
|
if output_file:
|
||||||
output_fd = open(output_file, 'w')
|
output_fd = open(output_file, 'w')
|
||||||
|
@ -1289,7 +1366,7 @@ def main():
|
||||||
f = arguments[n]
|
f = arguments[n]
|
||||||
output(i4, i4, f.struct_name(), ' f_', f.name, ';\n')
|
output(i4, i4, f.struct_name(), ' f_', f.name, ';\n')
|
||||||
output(i4, '} u;\n\n')
|
output(i4, '} u;\n\n')
|
||||||
dtree.output_code(4, False, 0, 0)
|
toppat.output_code(4, False, 0, 0)
|
||||||
|
|
||||||
output(i4, 'return false;\n')
|
output(i4, 'return false;\n')
|
||||||
output('}\n')
|
output('}\n')
|
||||||
|
|
|
@ -312,13 +312,13 @@ CLZ 1111 1010 1011 ---- 1111 .... 1000 .... @rdm
|
||||||
&cps
|
&cps
|
||||||
|
|
||||||
# Miscellaneous control
|
# Miscellaneous control
|
||||||
{
|
[
|
||||||
CLREX 1111 0011 1011 1111 1000 1111 0010 1111
|
CLREX 1111 0011 1011 1111 1000 1111 0010 1111
|
||||||
DSB 1111 0011 1011 1111 1000 1111 0100 ----
|
DSB 1111 0011 1011 1111 1000 1111 0100 ----
|
||||||
DMB 1111 0011 1011 1111 1000 1111 0101 ----
|
DMB 1111 0011 1011 1111 1000 1111 0101 ----
|
||||||
ISB 1111 0011 1011 1111 1000 1111 0110 ----
|
ISB 1111 0011 1011 1111 1000 1111 0110 ----
|
||||||
SB 1111 0011 1011 1111 1000 1111 0111 0000
|
SB 1111 0011 1011 1111 1000 1111 0111 0000
|
||||||
}
|
]
|
||||||
|
|
||||||
# Note that the v7m insn overlaps both the normal and banked insn.
|
# Note that the v7m insn overlaps both the normal and banked insn.
|
||||||
{
|
{
|
||||||
|
|
|
@ -3,11 +3,12 @@
|
||||||
|
|
||||||
%sub1 0:8
|
%sub1 0:8
|
||||||
%sub2 8:8
|
%sub2 8:8
|
||||||
%sub3 16:8
|
|
||||||
%sub4 24:8
|
|
||||||
|
|
||||||
# Groups with no overlap are supposed to fail
|
# Make sure braces are matched
|
||||||
{
|
{
|
||||||
top 00000000 00000000 00000000 00000000
|
top 00000000 00000000 00000000 00000000
|
||||||
sub4 ........ ........ ........ ........ %sub1 %sub2 %sub3 %sub4
|
[
|
||||||
|
sub1 00000000 00000000 00000000 ........ %sub1
|
||||||
|
sub2 00000000 00000000 ........ ........ %sub1 %sub2
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
6
tests/decode/err_pattern_group_nest2.decode
Normal file
6
tests/decode/err_pattern_group_nest2.decode
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
# This work is licensed under the terms of the GNU LGPL, version 2 or later.
|
||||||
|
# See the COPYING.LIB file in the top-level directory.
|
||||||
|
|
||||||
|
# Make sure braces are matched
|
||||||
|
{
|
||||||
|
[
|
14
tests/decode/err_pattern_group_nest3.decode
Normal file
14
tests/decode/err_pattern_group_nest3.decode
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
# This work is licensed under the terms of the GNU LGPL, version 2 or later.
|
||||||
|
# See the COPYING.LIB file in the top-level directory.
|
||||||
|
|
||||||
|
%sub1 0:8
|
||||||
|
%sub2 8:8
|
||||||
|
|
||||||
|
# The exclusive group should error for overlap.
|
||||||
|
{
|
||||||
|
top 00000000 00000000 00000000 00000000
|
||||||
|
[
|
||||||
|
sub1 00000000 00000000 00000000 ........ %sub1
|
||||||
|
sub2 00000000 00000000 ........ ........ %sub1 %sub2
|
||||||
|
]
|
||||||
|
}
|
13
tests/decode/succ_pattern_group_nest2.decode
Normal file
13
tests/decode/succ_pattern_group_nest2.decode
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
# This work is licensed under the terms of the GNU LGPL, version 2 or later.
|
||||||
|
# See the COPYING.LIB file in the top-level directory.
|
||||||
|
|
||||||
|
%sub1 0:8
|
||||||
|
%sub2 8:8
|
||||||
|
%sub3 16:8
|
||||||
|
%sub4 24:8
|
||||||
|
|
||||||
|
# Group with complete overlap of the two patterns
|
||||||
|
{
|
||||||
|
top 00000000 00000000 00000000 00000000
|
||||||
|
sub4 ........ ........ ........ ........ %sub1 %sub2 %sub3 %sub4
|
||||||
|
}
|
11
tests/decode/succ_pattern_group_nest3.decode
Normal file
11
tests/decode/succ_pattern_group_nest3.decode
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
# This work is licensed under the terms of the GNU LGPL, version 2 or later.
|
||||||
|
# See the COPYING.LIB file in the top-level directory.
|
||||||
|
|
||||||
|
{
|
||||||
|
[
|
||||||
|
sub1 00000000 a:8 b:8 c:8
|
||||||
|
sub2 00000001 a:8 b:8 c:8
|
||||||
|
sub3 00000010 a:8 b:8 c:8
|
||||||
|
]
|
||||||
|
sub4 000000 d:2 a:8 b:8 c:8
|
||||||
|
}
|
13
tests/decode/succ_pattern_group_nest4.decode
Normal file
13
tests/decode/succ_pattern_group_nest4.decode
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
# This work is licensed under the terms of the GNU LGPL, version 2 or later.
|
||||||
|
# See the COPYING.LIB file in the top-level directory.
|
||||||
|
|
||||||
|
# Verify deeper nesting, and a single element in the groups.
|
||||||
|
{
|
||||||
|
[
|
||||||
|
{
|
||||||
|
[
|
||||||
|
sub1 00000000 a:8 b:8 c:8
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue