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:
parent
a6ae23831b
commit
17560e9349
@ -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'
|
||||||
|
Loading…
Reference in New Issue
Block a user