summaryrefslogtreecommitdiff
path: root/arch/isa_parser.py
diff options
context:
space:
mode:
Diffstat (limited to 'arch/isa_parser.py')
-rwxr-xr-xarch/isa_parser.py603
1 files changed, 345 insertions, 258 deletions
diff --git a/arch/isa_parser.py b/arch/isa_parser.py
index fffcc33e5..030bb5a7c 100755
--- a/arch/isa_parser.py
+++ b/arch/isa_parser.py
@@ -82,10 +82,9 @@ tokens = reserved + (
# ( ) [ ] { } < > , ; : :: *
'LPAREN', 'RPAREN',
-# not used any more... commented out to suppress PLY warning
-# 'LBRACKET', 'RBRACKET',
+ 'LBRACKET', 'RBRACKET',
'LBRACE', 'RBRACE',
- 'LESS', 'GREATER',
+ 'LESS', 'GREATER', 'EQUALS',
'COMMA', 'SEMI', 'COLON', 'DBLCOLON',
'ASTERISK',
@@ -104,13 +103,13 @@ tokens = reserved + (
# Regular expressions for token matching
t_LPAREN = r'\('
t_RPAREN = r'\)'
-# not used any more... commented out to suppress PLY warning
-# t_LBRACKET = r'\['
-# t_RBRACKET = r'\]'
+t_LBRACKET = r'\['
+t_RBRACKET = r'\]'
t_LBRACE = r'\{'
t_RBRACE = r'\}'
t_LESS = r'\<'
t_GREATER = r'\>'
+t_EQUALS = r'='
t_COMMA = r','
t_SEMI = r';'
t_COLON = r':'
@@ -321,25 +320,27 @@ def p_global_let(t):
# widths (stored in operandTypeMap).
def p_def_operand_types(t):
'def_operand_types : DEF OPERAND_TYPES CODELIT SEMI'
- s = 'global operandTypeMap; operandTypeMap = {' + t[3] + '}'
try:
- exec s
+ userDict = eval('{' + t[3] + '}')
except Exception, exc:
error(t.lineno(1),
'error: %s in def operand_types block "%s".' % (exc, t[3]))
+ buildOperandTypeMap(userDict, t.lineno(1))
t[0] = GenCode() # contributes nothing to the output C++ file
# Define the mapping from operand names to operand classes and other
-# traits. Stored in operandTraitsMap.
+# traits. Stored in operandNameMap.
def p_def_operands(t):
'def_operands : DEF OPERANDS CODELIT SEMI'
- s = 'global operandTraitsMap; operandTraitsMap = {' + t[3] + '}'
+ if not globals().has_key('operandTypeMap'):
+ error(t.lineno(1),
+ 'error: operand types must be defined before operands')
try:
- exec s
+ userDict = eval('{' + t[3] + '}')
except Exception, exc:
error(t.lineno(1),
'error: %s in def operands block "%s".' % (exc, t[3]))
- defineDerivedOperandVars()
+ buildOperandNameMap(userDict, t.lineno(1))
t[0] = GenCode() # contributes nothing to the output C++ file
# A bitfield definition looks like:
@@ -387,32 +388,66 @@ def p_def_format(t):
t[0] = GenCode()
# The formal parameter list for an instruction format is a possibly
-# empty list of comma-separated parameters.
+# empty list of comma-separated parameters. Positional (standard,
+# non-keyword) parameters must come first, followed by keyword
+# parameters, followed by a '*foo' parameter that gets excess
+# positional arguments (as in Python). Each of these three parameter
+# categories is optional.
+#
+# Note that we do not support the '**foo' parameter for collecting
+# otherwise undefined keyword args. Otherwise the parameter list is
+# (I believe) identical to what is supported in Python.
+#
+# The param list generates a tuple, where the first element is a list of
+# the positional params and the second element is a dict containing the
+# keyword params.
def p_param_list_0(t):
- 'param_list : empty'
- t[0] = [ ]
+ 'param_list : positional_param_list COMMA nonpositional_param_list'
+ t[0] = t[1] + t[3]
def p_param_list_1(t):
- 'param_list : param'
+ '''param_list : positional_param_list
+ | nonpositional_param_list'''
+ t[0] = t[1]
+
+def p_positional_param_list_0(t):
+ 'positional_param_list : empty'
+ t[0] = []
+
+def p_positional_param_list_1(t):
+ 'positional_param_list : ID'
t[0] = [t[1]]
-def p_param_list_2(t):
- 'param_list : param_list COMMA param'
- t[0] = t[1]
- t[0].append(t[3])
+def p_positional_param_list_2(t):
+ 'positional_param_list : positional_param_list COMMA ID'
+ t[0] = t[1] + [t[3]]
-# Each formal parameter is either an identifier or an identifier
-# preceded by an asterisk. As in Python, the latter (if present) gets
-# a tuple containing all the excess positional arguments, allowing
-# varargs functions.
-def p_param_0(t):
- 'param : ID'
+def p_nonpositional_param_list_0(t):
+ 'nonpositional_param_list : keyword_param_list COMMA excess_args_param'
+ t[0] = t[1] + t[3]
+
+def p_nonpositional_param_list_1(t):
+ '''nonpositional_param_list : keyword_param_list
+ | excess_args_param'''
t[0] = t[1]
-def p_param_1(t):
- 'param : ASTERISK ID'
- # just concatenate them: '*ID'
- t[0] = t[1] + t[2]
+def p_keyword_param_list_0(t):
+ 'keyword_param_list : keyword_param'
+ t[0] = [t[1]]
+
+def p_keyword_param_list_1(t):
+ 'keyword_param_list : keyword_param_list COMMA keyword_param'
+ t[0] = t[1] + [t[3]]
+
+def p_keyword_param(t):
+ 'keyword_param : ID EQUALS expr'
+ t[0] = t[1] + ' = ' + t[3].__repr__()
+
+def p_excess_args_param(t):
+ 'excess_args_param : ASTERISK ID'
+ # Just concatenate them: '*ID'. Wrap in list to be consistent
+ # with positional_param_list and keyword_param_list.
+ t[0] = [t[1] + t[2]]
# End of format definition-related rules.
##############
@@ -577,25 +612,78 @@ def p_inst_1(t):
codeObj.prepend_all(comment)
t[0] = codeObj
+# The arg list generates a tuple, where the first element is a list of
+# the positional args and the second element is a dict containing the
+# keyword args.
def p_arg_list_0(t):
- 'arg_list : empty'
- t[0] = [ ]
+ 'arg_list : positional_arg_list COMMA keyword_arg_list'
+ t[0] = ( t[1], t[3] )
def p_arg_list_1(t):
- 'arg_list : arg'
- t[0] = [t[1]]
+ 'arg_list : positional_arg_list'
+ t[0] = ( t[1], {} )
def p_arg_list_2(t):
- 'arg_list : arg_list COMMA arg'
+ 'arg_list : keyword_arg_list'
+ t[0] = ( [], t[1] )
+
+def p_positional_arg_list_0(t):
+ 'positional_arg_list : empty'
+ t[0] = []
+
+def p_positional_arg_list_1(t):
+ 'positional_arg_list : expr'
+ t[0] = [t[1]]
+
+def p_positional_arg_list_2(t):
+ 'positional_arg_list : positional_arg_list COMMA expr'
+ t[0] = t[1] + [t[3]]
+
+def p_keyword_arg_list_0(t):
+ 'keyword_arg_list : keyword_arg'
t[0] = t[1]
- t[0].append(t[3])
-def p_arg(t):
- '''arg : ID
- | INTLIT
- | STRLIT
- | CODELIT'''
+def p_keyword_arg_list_1(t):
+ 'keyword_arg_list : keyword_arg_list COMMA keyword_arg'
t[0] = t[1]
+ t[0].update(t[3])
+
+def p_keyword_arg(t):
+ 'keyword_arg : ID EQUALS expr'
+ t[0] = { t[1] : t[3] }
+
+#
+# Basic expressions. These constitute the argument values of
+# "function calls" (i.e. instruction definitions in the decode block)
+# and default values for formal parameters of format functions.
+#
+# Right now, these are either strings, integers, or (recursively)
+# lists of exprs (using Python square-bracket list syntax). Note that
+# bare identifiers are trated as string constants here (since there
+# isn't really a variable namespace to refer to).
+#
+def p_expr_0(t):
+ '''expr : ID
+ | INTLIT
+ | STRLIT
+ | CODELIT'''
+ t[0] = t[1]
+
+def p_expr_1(t):
+ '''expr : LBRACKET list_expr RBRACKET'''
+ t[0] = t[2]
+
+def p_list_expr_0(t):
+ 'list_expr : expr'
+ t[0] = [t[1]]
+
+def p_list_expr_1(t):
+ 'list_expr : list_expr COMMA expr'
+ t[0] = t[1] + [t[3]]
+
+def p_list_expr_2(t):
+ 'list_expr : empty'
+ t[0] = []
#
# Empty production... use in other rules for readability.
@@ -757,6 +845,19 @@ class GenCode:
# a defineInst() method that generates the code for an instruction
# definition.
+exportContextSymbols = ('InstObjParams', 'CodeBlock',
+ 'makeList', 're', 'string')
+
+exportContext = {}
+
+def updateExportContext():
+ exportContext.update(exportDict(*exportContextSymbols))
+ exportContext.update(templateMap)
+
+def exportDict(*symNames):
+ return dict([(s, eval(s)) for s in symNames])
+
+
class Format:
def __init__(self, id, params, code):
# constructor: just save away arguments
@@ -779,7 +880,7 @@ class Format:
context.update(exportContext)
context.update({ 'name': name, 'Name': string.capitalize(name) })
try:
- vars = self.func(self.user_code, context, *args)
+ vars = self.func(self.user_code, context, *args[0], **args[1])
except Exception, exc:
error(lineno, 'error defining "%s": %s.' % (name, exc))
for k in vars.keys():
@@ -974,74 +1075,88 @@ class Template:
#
#####################################################################
-# Force the argument to be a list
-def makeList(list_or_item):
- if not list_or_item:
+# Force the argument to be a list. Useful for flags, where a caller
+# can specify a singleton flag or a list of flags. Also usful for
+# converting tuples to lists so they can be modified.
+def makeList(arg):
+ if isinstance(arg, list):
+ return arg
+ elif isinstance(arg, tuple):
+ return list(arg)
+ elif not arg:
return []
- elif type(list_or_item) == ListType:
- return list_or_item
else:
- return [ list_or_item ]
-
-# generate operandSizeMap based on provided operandTypeMap:
-# basically generate equiv. C++ type and make is_signed flag
-def buildOperandSizeMap():
- global operandSizeMap
- operandSizeMap = {}
- for ext in operandTypeMap.keys():
- (desc, size) = operandTypeMap[ext]
+ return [ arg ]
+
+# Generate operandTypeMap from the user's 'def operand_types'
+# statement.
+def buildOperandTypeMap(userDict, lineno):
+ global operandTypeMap
+ operandTypeMap = {}
+ for (ext, (desc, size)) in userDict.iteritems():
if desc == 'signed int':
- type = 'int%d_t' % size
+ ctype = 'int%d_t' % size
is_signed = 1
elif desc == 'unsigned int':
- type = 'uint%d_t' % size
+ ctype = 'uint%d_t' % size
is_signed = 0
elif desc == 'float':
is_signed = 1 # shouldn't really matter
if size == 32:
- type = 'float'
+ ctype = 'float'
elif size == 64:
- type = 'double'
- if type == '':
- error(0, 'Unrecognized type description "%s" in operandTypeMap')
- operandSizeMap[ext] = (size, type, is_signed)
+ ctype = 'double'
+ if ctype == '':
+ error(0, 'Unrecognized type description "%s" in userDict')
+ operandTypeMap[ext] = (size, ctype, is_signed)
#
-# Base class for operand traits. An instance of this class (or actually
-# a class derived from this one) encapsulates the traits of a particular
-# operand type (e.g., "32-bit integer register").
#
-class OperandTraits:
- def __init__(self, dflt_ext, reg_spec, flags, sort_pri):
- # Force construction of operandSizeMap from operandTypeMap
- # if it hasn't happened yet
- if not globals().has_key('operandSizeMap'):
- buildOperandSizeMap()
- self.dflt_ext = dflt_ext
- (self.dflt_size, self.dflt_type, self.dflt_is_signed) = \
- operandSizeMap[dflt_ext]
- self.reg_spec = reg_spec
- # Canonical flag structure is a triple of lists, where each list
- # indicates the set of flags implied by this operand always, when
- # used as a source, and when used as a dest, respectively.
- # For simplicity this can be initialized using a variety of fairly
- # obvious shortcuts; we convert these to canonical form here.
- if not flags:
- # no flags specified (e.g., 'None')
- self.flags = ( [], [], [] )
- elif type(flags) == StringType:
- # a single flag: assumed to be unconditional
- self.flags = ( [ flags ], [], [] )
- elif type(flags) == ListType:
- # a list of flags: also assumed to be unconditional
- self.flags = ( flags, [], [] )
- elif type(flags) == TupleType:
- # it's a tuple: it should be a triple,
- # but each item could be a single string or a list
- (uncond_flags, src_flags, dest_flags) = flags
- self.flags = (makeList(uncond_flags),
- makeList(src_flags), makeList(dest_flags))
- self.sort_pri = sort_pri
+#
+# Base class for operand descriptors. An instance of this class (or
+# actually a class derived from this one) represents a specific
+# operand for a code block (e.g, "Rc.sq" as a dest). Intermediate
+# derived classes encapsulates the traits of a particular operand type
+# (e.g., "32-bit integer register").
+#
+class Operand(object):
+ def __init__(self, full_name, ext, is_src, is_dest):
+ self.full_name = full_name
+ self.ext = ext
+ self.is_src = is_src
+ self.is_dest = is_dest
+ # The 'effective extension' (eff_ext) is either the actual
+ # extension, if one was explicitly provided, or the default.
+ if ext:
+ self.eff_ext = ext
+ else:
+ self.eff_ext = self.dflt_ext
+
+ (self.size, self.ctype, self.is_signed) = operandTypeMap[self.eff_ext]
+
+ # note that mem_acc_size is undefined for non-mem operands...
+ # template must be careful not to use it if it doesn't apply.
+ if self.isMem():
+ self.mem_acc_size = self.makeAccSize()
+
+ # Finalize additional fields (primarily code fields). This step
+ # is done separately since some of these fields may depend on the
+ # register index enumeration that hasn't been performed yet at the
+ # time of __init__().
+ def finalize(self):
+ self.flags = self.getFlags()
+ self.constructor = self.makeConstructor()
+ self.op_decl = self.makeDecl()
+
+ if self.is_src:
+ self.op_rd = self.makeRead()
+ else:
+ self.op_rd = ''
+
+ if self.is_dest:
+ self.op_wb = self.makeWrite()
+ else:
+ self.op_wb = ''
def isMem(self):
return 0
@@ -1058,223 +1173,239 @@ class OperandTraits:
def isControlReg(self):
return 0
- def getFlags(self, op_desc):
+ def getFlags(self):
# note the empty slice '[:]' gives us a copy of self.flags[0]
# instead of a reference to it
my_flags = self.flags[0][:]
- if op_desc.is_src:
+ if self.is_src:
my_flags += self.flags[1]
- if op_desc.is_dest:
+ if self.is_dest:
my_flags += self.flags[2]
return my_flags
- def makeDecl(self, op_desc):
- (size, type, is_signed) = operandSizeMap[op_desc.eff_ext]
+ def makeDecl(self):
# Note that initializations in the declarations are solely
# to avoid 'uninitialized variable' errors from the compiler.
- return type + ' ' + op_desc.base_name + ' = 0;\n';
+ return self.ctype + ' ' + self.base_name + ' = 0;\n';
-class IntRegOperandTraits(OperandTraits):
+class IntRegOperand(Operand):
def isReg(self):
return 1
def isIntReg(self):
return 1
- def makeConstructor(self, op_desc):
+ def makeConstructor(self):
c = ''
- if op_desc.is_src:
+ if self.is_src:
c += '\n\t_srcRegIdx[%d] = %s;' % \
- (op_desc.src_reg_idx, self.reg_spec)
- if op_desc.is_dest:
+ (self.src_reg_idx, self.reg_spec)
+ if self.is_dest:
c += '\n\t_destRegIdx[%d] = %s;' % \
- (op_desc.dest_reg_idx, self.reg_spec)
+ (self.dest_reg_idx, self.reg_spec)
return c
- def makeRead(self, op_desc):
- (size, type, is_signed) = operandSizeMap[op_desc.eff_ext]
- if (type == 'float' or type == 'double'):
+ def makeRead(self):
+ if (self.ctype == 'float' or self.ctype == 'double'):
error(0, 'Attempt to read integer register as FP')
- if (size == self.dflt_size):
+ if (self.size == self.dflt_size):
return '%s = xc->readIntReg(this, %d);\n' % \
- (op_desc.base_name, op_desc.src_reg_idx)
+ (self.base_name, self.src_reg_idx)
else:
return '%s = bits(xc->readIntReg(this, %d), %d, 0);\n' % \
- (op_desc.base_name, op_desc.src_reg_idx, size-1)
+ (self.base_name, self.src_reg_idx, self.size-1)
- def makeWrite(self, op_desc):
- (size, type, is_signed) = operandSizeMap[op_desc.eff_ext]
- if (type == 'float' or type == 'double'):
+ def makeWrite(self):
+ if (self.ctype == 'float' or self.ctype == 'double'):
error(0, 'Attempt to write integer register as FP')
- if (size != self.dflt_size and is_signed):
- final_val = 'sext<%d>(%s)' % (size, op_desc.base_name)
+ if (self.size != self.dflt_size and self.is_signed):
+ final_val = 'sext<%d>(%s)' % (self.size, self.base_name)
else:
- final_val = op_desc.base_name
+ final_val = self.base_name
wb = '''
{
%s final_val = %s;
xc->setIntReg(this, %d, final_val);\n
if (traceData) { traceData->setData(final_val); }
- }''' % (self.dflt_type, final_val, op_desc.dest_reg_idx)
+ }''' % (self.dflt_ctype, final_val, self.dest_reg_idx)
return wb
-class FloatRegOperandTraits(OperandTraits):
+class FloatRegOperand(Operand):
def isReg(self):
return 1
def isFloatReg(self):
return 1
- def makeConstructor(self, op_desc):
+ def makeConstructor(self):
c = ''
- if op_desc.is_src:
+ if self.is_src:
c += '\n\t_srcRegIdx[%d] = %s + FP_Base_DepTag;' % \
- (op_desc.src_reg_idx, self.reg_spec)
- if op_desc.is_dest:
+ (self.src_reg_idx, self.reg_spec)
+ if self.is_dest:
c += '\n\t_destRegIdx[%d] = %s + FP_Base_DepTag;' % \
- (op_desc.dest_reg_idx, self.reg_spec)
+ (self.dest_reg_idx, self.reg_spec)
return c
- def makeRead(self, op_desc):
- (size, type, is_signed) = operandSizeMap[op_desc.eff_ext]
+ def makeRead(self):
bit_select = 0
- if (type == 'float'):
+ if (self.ctype == 'float'):
func = 'readFloatRegSingle'
- elif (type == 'double'):
+ elif (self.ctype == 'double'):
func = 'readFloatRegDouble'
else:
func = 'readFloatRegInt'
- if (size != self.dflt_size):
+ if (self.size != self.dflt_size):
bit_select = 1
base = 'xc->%s(this, %d)' % \
- (func, op_desc.src_reg_idx)
+ (func, self.src_reg_idx)
if bit_select:
return '%s = bits(%s, %d, 0);\n' % \
- (op_desc.base_name, base, size-1)
+ (self.base_name, base, self.size-1)
else:
- return '%s = %s;\n' % (op_desc.base_name, base)
+ return '%s = %s;\n' % (self.base_name, base)
- def makeWrite(self, op_desc):
- (size, type, is_signed) = operandSizeMap[op_desc.eff_ext]
- final_val = op_desc.base_name
- if (type == 'float'):
+ def makeWrite(self):
+ final_val = self.base_name
+ final_ctype = self.ctype
+ if (self.ctype == 'float'):
func = 'setFloatRegSingle'
- elif (type == 'double'):
+ elif (self.ctype == 'double'):
func = 'setFloatRegDouble'
else:
func = 'setFloatRegInt'
- type = 'uint%d_t' % self.dflt_size
- if (size != self.dflt_size and is_signed):
- final_val = 'sext<%d>(%s)' % (size, op_desc.base_name)
+ final_ctype = 'uint%d_t' % self.dflt_size
+ if (self.size != self.dflt_size and self.is_signed):
+ final_val = 'sext<%d>(%s)' % (self.size, self.base_name)
wb = '''
{
%s final_val = %s;
xc->%s(this, %d, final_val);\n
if (traceData) { traceData->setData(final_val); }
- }''' % (type, final_val, func, op_desc.dest_reg_idx)
+ }''' % (final_ctype, final_val, func, self.dest_reg_idx)
return wb
-class ControlRegOperandTraits(OperandTraits):
+class ControlRegOperand(Operand):
def isReg(self):
return 1
def isControlReg(self):
return 1
- def makeConstructor(self, op_desc):
+ def makeConstructor(self):
c = ''
- if op_desc.is_src:
+ if self.is_src:
c += '\n\t_srcRegIdx[%d] = %s_DepTag;' % \
- (op_desc.src_reg_idx, self.reg_spec)
- if op_desc.is_dest:
+ (self.src_reg_idx, self.reg_spec)
+ if self.is_dest:
c += '\n\t_destRegIdx[%d] = %s_DepTag;' % \
- (op_desc.dest_reg_idx, self.reg_spec)
+ (self.dest_reg_idx, self.reg_spec)
return c
- def makeRead(self, op_desc):
- (size, type, is_signed) = operandSizeMap[op_desc.eff_ext]
+ def makeRead(self):
bit_select = 0
- if (type == 'float' or type == 'double'):
+ if (self.ctype == 'float' or self.ctype == 'double'):
error(0, 'Attempt to read control register as FP')
base = 'xc->read%s()' % self.reg_spec
- if size == self.dflt_size:
- return '%s = %s;\n' % (op_desc.base_name, base)
+ if self.size == self.dflt_size:
+ return '%s = %s;\n' % (self.base_name, base)
else:
return '%s = bits(%s, %d, 0);\n' % \
- (op_desc.base_name, base, size-1)
+ (self.base_name, base, self.size-1)
- def makeWrite(self, op_desc):
- (size, type, is_signed) = operandSizeMap[op_desc.eff_ext]
- if (type == 'float' or type == 'double'):
+ def makeWrite(self):
+ if (self.ctype == 'float' or self.ctype == 'double'):
error(0, 'Attempt to write control register as FP')
- wb = 'xc->set%s(%s);\n' % (self.reg_spec, op_desc.base_name)
+ wb = 'xc->set%s(%s);\n' % (self.reg_spec, self.base_name)
wb += 'if (traceData) { traceData->setData(%s); }' % \
- op_desc.base_name
+ self.base_name
return wb
-class MemOperandTraits(OperandTraits):
+class MemOperand(Operand):
def isMem(self):
return 1
- def makeConstructor(self, op_desc):
+ def makeConstructor(self):
return ''
- def makeDecl(self, op_desc):
- (size, type, is_signed) = operandSizeMap[op_desc.eff_ext]
+ def makeDecl(self):
# Note that initializations in the declarations are solely
# to avoid 'uninitialized variable' errors from the compiler.
# Declare memory data variable.
- c = '%s %s = 0;\n' % (type, op_desc.base_name)
+ c = '%s %s = 0;\n' % (self.ctype, self.base_name)
return c
- def makeRead(self, op_desc):
+ def makeRead(self):
return ''
- def makeWrite(self, op_desc):
+ def makeWrite(self):
return ''
# Return the memory access size *in bits*, suitable for
# forming a type via "uint%d_t". Divide by 8 if you want bytes.
- def makeAccSize(self, op_desc):
- (size, type, is_signed) = operandSizeMap[op_desc.eff_ext]
- return size
+ def makeAccSize(self):
+ return self.size
-class NPCOperandTraits(OperandTraits):
- def makeConstructor(self, op_desc):
+class NPCOperand(Operand):
+ def makeConstructor(self):
return ''
- def makeRead(self, op_desc):
- return '%s = xc->readPC() + 4;\n' % op_desc.base_name
-
- def makeWrite(self, op_desc):
- return 'xc->setNextPC(%s);\n' % op_desc.base_name
+ def makeRead(self):
+ return '%s = xc->readPC() + 4;\n' % self.base_name
+ def makeWrite(self):
+ return 'xc->setNextPC(%s);\n' % self.base_name
-exportContextSymbols = ('IntRegOperandTraits', 'FloatRegOperandTraits',
- 'ControlRegOperandTraits', 'MemOperandTraits',
- 'NPCOperandTraits', 'InstObjParams', 'CodeBlock',
- 're', 'string')
-exportContext = {}
-
-def updateExportContext():
- exportContext.update(exportDict(*exportContextSymbols))
- exportContext.update(templateMap)
-
-
-def exportDict(*symNames):
- return dict([(s, eval(s)) for s in symNames])
-
-
-#
-# Define operand variables that get derived from the basic declaration
-# of ISA-specific operands in operandTraitsMap. This function must be
-# called by the ISA description file explicitly after defining
-# operandTraitsMap (in a 'let' block).
-#
-def defineDerivedOperandVars():
- global operands
- operands = operandTraitsMap.keys()
+def buildOperandNameMap(userDict, lineno):
+ global operandNameMap
+ operandNameMap = {}
+ for (op_name, val) in userDict.iteritems():
+ (base_cls_name, dflt_ext, reg_spec, flags, sort_pri) = val
+ (dflt_size, dflt_ctype, dflt_is_signed) = operandTypeMap[dflt_ext]
+ # Canonical flag structure is a triple of lists, where each list
+ # indicates the set of flags implied by this operand always, when
+ # used as a source, and when used as a dest, respectively.
+ # For simplicity this can be initialized using a variety of fairly
+ # obvious shortcuts; we convert these to canonical form here.
+ if not flags:
+ # no flags specified (e.g., 'None')
+ flags = ( [], [], [] )
+ elif isinstance(flags, str):
+ # a single flag: assumed to be unconditional
+ flags = ( [ flags ], [], [] )
+ elif isinstance(flags, list):
+ # a list of flags: also assumed to be unconditional
+ flags = ( flags, [], [] )
+ elif isinstance(flags, tuple):
+ # it's a tuple: it should be a triple,
+ # but each item could be a single string or a list
+ (uncond_flags, src_flags, dest_flags) = flags
+ flags = (makeList(uncond_flags),
+ makeList(src_flags), makeList(dest_flags))
+ # Accumulate attributes of new operand class in tmp_dict
+ tmp_dict = {}
+ for attr in ('dflt_ext', 'reg_spec', 'flags', 'sort_pri',
+ 'dflt_size', 'dflt_ctype', 'dflt_is_signed'):
+ tmp_dict[attr] = eval(attr)
+ tmp_dict['base_name'] = op_name
+ # New class name will be e.g. "IntReg_Ra"
+ cls_name = base_cls_name + '_' + op_name
+ # Evaluate string arg to get class object. Note that the
+ # actual base class for "IntReg" is "IntRegOperand", i.e. we
+ # have to append "Operand".
+ try:
+ base_cls = eval(base_cls_name + 'Operand')
+ except NameError:
+ error(lineno,
+ 'error: unknown operand base class "%s"' % base_cls_name)
+ # The following statement creates a new class called
+ # <cls_name> as a subclass of <base_cls> with the attributes
+ # in tmp_dict, just as if we evaluated a class declaration.
+ operandNameMap[op_name] = type(cls_name, (base_cls,), tmp_dict)
+
+ # Define operand variables.
+ operands = userDict.keys()
operandsREString = (r'''
(?<![\w\.]) # neg. lookbehind assertion: prevent partial matches
@@ -1296,54 +1427,10 @@ def defineDerivedOperandVars():
operandsWithExtRE = re.compile(operandsWithExtREString, re.MULTILINE)
-#
-# Operand descriptor class. An instance of this class represents
-# a specific operand for a code block.
-#
-class OperandDescriptor:
- def __init__(self, full_name, base_name, ext, is_src, is_dest):
- self.full_name = full_name
- self.base_name = base_name
- self.ext = ext
- self.is_src = is_src
- self.is_dest = is_dest
- self.traits = operandTraitsMap[base_name]
- # The 'effective extension' (eff_ext) is either the actual
- # extension, if one was explicitly provided, or the default.
- if ext:
- self.eff_ext = ext
- else:
- self.eff_ext = self.traits.dflt_ext
-
- # note that mem_acc_size is undefined for non-mem operands...
- # template must be careful not to use it if it doesn't apply.
- if self.traits.isMem():
- self.mem_acc_size = self.traits.makeAccSize(self)
-
- # Finalize additional fields (primarily code fields). This step
- # is done separately since some of these fields may depend on the
- # register index enumeration that hasn't been performed yet at the
- # time of __init__().
- def finalize(self):
- self.flags = self.traits.getFlags(self)
- self.constructor = self.traits.makeConstructor(self)
- self.op_decl = self.traits.makeDecl(self)
-
- if self.is_src:
- self.op_rd = self.traits.makeRead(self)
- else:
- self.op_rd = ''
-
- if self.is_dest:
- self.op_wb = self.traits.makeWrite(self)
- else:
- self.op_wb = ''
-
-
-class OperandDescriptorList:
+class OperandList:
# Find all the operands in the given code block. Returns an operand
- # descriptor list (instance of class OperandDescriptorList).
+ # descriptor list (instance of class OperandList).
def __init__(self, code):
self.items = []
self.bases = {}
@@ -1373,8 +1460,8 @@ class OperandDescriptorList:
op_desc.is_dest = op_desc.is_dest or is_dest
else:
# new operand: create new descriptor
- op_desc = OperandDescriptor(op_full, op_base, op_ext,
- is_src, is_dest)
+ op_desc = operandNameMap[op_base](op_full, op_ext,
+ is_src, is_dest)
self.append(op_desc)
# start next search after end of current match
next_pos = match.end()
@@ -1387,18 +1474,18 @@ class OperandDescriptorList:
self.numIntDestRegs = 0
self.memOperand = None
for op_desc in self.items:
- if op_desc.traits.isReg():
+ if op_desc.isReg():
if op_desc.is_src:
op_desc.src_reg_idx = self.numSrcRegs
self.numSrcRegs += 1
if op_desc.is_dest:
op_desc.dest_reg_idx = self.numDestRegs
self.numDestRegs += 1
- if op_desc.traits.isFloatReg():
+ if op_desc.isFloatReg():
self.numFPDestRegs += 1
- elif op_desc.traits.isIntReg():
+ elif op_desc.isIntReg():
self.numIntDestRegs += 1
- elif op_desc.traits.isMem():
+ elif op_desc.isMem():
if self.memOperand:
error(0, "Code block has more than one memory operand.")
self.memOperand = op_desc
@@ -1450,7 +1537,7 @@ class OperandDescriptorList:
return self.__internalConcatAttrs(attr_name, filter, [])
def sort(self):
- self.items.sort(lambda a, b: a.traits.sort_pri - b.traits.sort_pri)
+ self.items.sort(lambda a, b: a.sort_pri - b.sort_pri)
# Regular expression object to match C++ comments
# (used in findOperands())
@@ -1462,7 +1549,7 @@ assignRE = re.compile(r'\s*=(?!=)', re.MULTILINE)
# Munge operand names in code string to make legal C++ variable names.
# This means getting rid of the type extension if any.
-# (Will match base_name attribute of OperandDescriptor object.)
+# (Will match base_name attribute of Operand object.)
def substMungedOpNames(code):
return operandsWithExtRE.sub(r'\1', code)
@@ -1488,7 +1575,7 @@ def makeFlagConstructor(flag_list):
class CodeBlock:
def __init__(self, code):
self.orig_code = code
- self.operands = OperandDescriptorList(code)
+ self.operands = OperandList(code)
self.code = substMungedOpNames(substBitOps(code))
self.constructor = self.operands.concatAttrStrings('constructor')
self.constructor += \