decodetree: Initial support for variable-length ISAs

Assuming that the ISA clearly describes how to determine
the length of the instruction, and the ISA has a reasonable
maximum instruction length, the input to the decoder can be
right-justified in an appropriate insn word.

This is not 100% convenient, as out-of-line %fields are
numbered relative to the maximum instruction length, but
this appears to still be usable.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson 2019-01-30 18:01:29 -08:00
parent a6ae23831b
commit 17560e9349

View File

@ -27,6 +27,7 @@ import getopt
insnwidth = 32 insnwidth = 32
insnmask = 0xffffffff insnmask = 0xffffffff
variablewidth = False
fields = {} fields = {}
arguments = {} arguments = {}
formats = {} formats = {}
@ -289,7 +290,7 @@ class Arguments:
class General: class General:
"""Common code between instruction formats and instruction patterns""" """Common code between instruction formats and instruction patterns"""
def __init__(self, name, lineno, base, fixb, fixm, udfm, fldm, flds): def __init__(self, name, lineno, base, fixb, fixm, udfm, fldm, flds, w):
self.name = name self.name = name
self.file = input_file self.file = input_file
self.lineno = lineno self.lineno = lineno
@ -299,6 +300,7 @@ class General:
self.undefmask = udfm self.undefmask = udfm
self.fieldmask = fldm self.fieldmask = fldm
self.fields = flds self.fields = flds
self.width = w
def __str__(self): def __str__(self):
return self.name + ' ' + str_match_bits(self.fixedbits, self.fixedmask) return self.name + ' ' + str_match_bits(self.fixedbits, self.fixedmask)
@ -352,7 +354,7 @@ class Pattern(General):
class MultiPattern(General): class MultiPattern(General):
"""Class representing an overlapping set of instruction patterns""" """Class representing an overlapping set of instruction patterns"""
def __init__(self, lineno, pats, fixb, fixm, udfm): def __init__(self, lineno, pats, fixb, fixm, udfm, w):
self.file = input_file self.file = input_file
self.lineno = lineno self.lineno = lineno
self.pats = pats self.pats = pats
@ -360,6 +362,7 @@ class MultiPattern(General):
self.fixedbits = fixb self.fixedbits = fixb
self.fixedmask = fixm self.fixedmask = fixm
self.undefmask = udfm self.undefmask = udfm
self.width = w
def __str__(self): def __str__(self):
r = "{" r = "{"
@ -502,7 +505,7 @@ def infer_argument_set(flds):
return arg return arg
def infer_format(arg, fieldmask, flds): def infer_format(arg, fieldmask, flds, width):
global arguments global arguments
global formats global formats
global decode_function global decode_function
@ -521,6 +524,8 @@ def infer_format(arg, fieldmask, flds):
continue continue
if fieldmask != fmt.fieldmask: if fieldmask != fmt.fieldmask:
continue continue
if width != fmt.width:
continue
if not eq_fields_for_fmts(flds, fmt.fields): if not eq_fields_for_fmts(flds, fmt.fields):
continue continue
return (fmt, const_flds) return (fmt, const_flds)
@ -529,7 +534,7 @@ def infer_format(arg, fieldmask, flds):
if not arg: if not arg:
arg = infer_argument_set(flds) arg = infer_argument_set(flds)
fmt = Format(name, 0, arg, 0, 0, 0, fieldmask, var_flds) fmt = Format(name, 0, arg, 0, 0, 0, fieldmask, var_flds, width)
formats[name] = fmt formats[name] = fmt
return (fmt, const_flds) return (fmt, const_flds)
@ -546,6 +551,7 @@ def parse_generic(lineno, is_format, name, toks):
global re_ident global re_ident
global insnwidth global insnwidth
global insnmask global insnmask
global variablewidth
fixedmask = 0 fixedmask = 0
fixedbits = 0 fixedbits = 0
@ -633,8 +639,15 @@ def parse_generic(lineno, is_format, name, toks):
error(lineno, 'invalid token "{0}"'.format(t)) error(lineno, 'invalid token "{0}"'.format(t))
width += shift width += shift
if variablewidth and width < insnwidth and width % 8 == 0:
shift = insnwidth - width
fixedbits <<= shift
fixedmask <<= shift
undefmask <<= shift
undefmask |= (1 << shift) - 1
# We should have filled in all of the bits of the instruction. # We should have filled in all of the bits of the instruction.
if not (is_format and width == 0) and width != insnwidth: elif not (is_format and width == 0) and width != insnwidth:
error(lineno, 'definition has {0} bits'.format(width)) error(lineno, 'definition has {0} bits'.format(width))
# Do not check for fields overlaping fields; one valid usage # Do not check for fields overlaping fields; one valid usage
@ -660,7 +673,7 @@ def parse_generic(lineno, is_format, name, toks):
if name in formats: if name in formats:
error(lineno, 'duplicate format name', name) error(lineno, 'duplicate format name', name)
fmt = Format(name, lineno, arg, fixedbits, fixedmask, fmt = Format(name, lineno, arg, fixedbits, fixedmask,
undefmask, fieldmask, flds) undefmask, fieldmask, flds, width)
formats[name] = fmt formats[name] = fmt
else: else:
# Patterns can reference a format ... # Patterns can reference a format ...
@ -670,12 +683,14 @@ def parse_generic(lineno, is_format, name, toks):
error(lineno, 'pattern specifies both format and argument set') error(lineno, 'pattern specifies both format and argument set')
if fixedmask & fmt.fixedmask: if fixedmask & fmt.fixedmask:
error(lineno, 'pattern fixed bits overlap format fixed bits') error(lineno, 'pattern fixed bits overlap format fixed bits')
if width != fmt.width:
error(lineno, 'pattern uses format of different width')
fieldmask |= fmt.fieldmask fieldmask |= fmt.fieldmask
fixedbits |= fmt.fixedbits fixedbits |= fmt.fixedbits
fixedmask |= fmt.fixedmask fixedmask |= fmt.fixedmask
undefmask |= fmt.undefmask undefmask |= fmt.undefmask
else: else:
(fmt, flds) = infer_format(arg, fieldmask, flds) (fmt, flds) = infer_format(arg, fieldmask, flds, width)
arg = fmt.base arg = fmt.base
for f in flds.keys(): for f in flds.keys():
if f not in arg.fields: if f not in arg.fields:
@ -687,7 +702,7 @@ def parse_generic(lineno, is_format, name, toks):
if f not in flds.keys() and f not in fmt.fields.keys(): if f not in flds.keys() and f not in fmt.fields.keys():
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) undefmask, fieldmask, flds, width)
patterns.append(pat) patterns.append(pat)
allpatterns.append(pat) allpatterns.append(pat)
@ -727,6 +742,13 @@ def build_multi_pattern(lineno, pats):
if p.lineno < lineno: if p.lineno < lineno:
lineno = p.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 repeat = True
while repeat: while repeat:
if fixedmask == 0: if fixedmask == 0:
@ -742,7 +764,7 @@ def build_multi_pattern(lineno, pats):
else: else:
repeat = False repeat = False
mp = MultiPattern(lineno, pats, fixedbits, fixedmask, undefmask) mp = MultiPattern(lineno, pats, fixedbits, fixedmask, undefmask, width)
patterns.append(mp) patterns.append(mp)
# end build_multi_pattern # end build_multi_pattern
@ -979,13 +1001,14 @@ def main():
global insntype global insntype
global insnmask global insnmask
global decode_function global decode_function
global variablewidth
decode_scope = 'static ' decode_scope = 'static '
long_opts = ['decode=', 'translate=', 'output=', 'insnwidth=', long_opts = ['decode=', 'translate=', 'output=', 'insnwidth=',
'static-decode='] 'static-decode=', 'varinsnwidth=']
try: try:
(opts, args) = getopt.getopt(sys.argv[1:], 'o:w:', long_opts) (opts, args) = getopt.getopt(sys.argv[1:], 'o:vw:', long_opts)
except getopt.GetoptError as err: except getopt.GetoptError as err:
error(0, err) error(0, err)
for o, a in opts: for o, a in opts:
@ -999,7 +1022,9 @@ def main():
elif o == '--translate': elif o == '--translate':
translate_prefix = a translate_prefix = a
translate_scope = '' translate_scope = ''
elif o in ('-w', '--insnwidth'): elif o in ('-w', '--insnwidth', '--varinsnwidth'):
if o == '--varinsnwidth':
variablewidth = True
insnwidth = int(a) insnwidth = int(a)
if insnwidth == 16: if insnwidth == 16:
insntype = 'uint16_t' insntype = 'uint16_t'