Changed targetarch to arch
[gem5.git] / arch / isa_parser.py
index 18e4b0a4509fade75a2222492098d6fda679c217..5185ed573e79a075feeee232fd01c2aaab5494f1 100755 (executable)
@@ -1,8 +1,6 @@
 #! /usr/bin/env python
 
-# $Id$
-
-# Copyright (c) 2003 The Regents of The University of Michigan
+# Copyright (c) 2003-2005 The Regents of The University of Michigan
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -84,27 +82,34 @@ 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',
 
     # C preprocessor directives
     'CPPDIRECTIVE'
+
+# The following are matched but never returned. commented out to
+# suppress PLY warning
+    # newfile directive
+#    'NEWFILE',
+
+    # endfile directive
+#    'ENDFILE'
 )
 
 # 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':'
@@ -151,10 +156,20 @@ def t_CODELIT(t):
     return t
 
 def t_CPPDIRECTIVE(t):
-    r'^\#.*\n'
+    r'^\#[^\#].*\n'
     t.lineno += t.value.count('\n')
     return t
 
+def t_NEWFILE(t):
+    r'^\#\#newfile\s+"[\w/.-]*"'
+    global fileNameStack
+    fileNameStack.append((t.value[11:-1], t.lineno))
+    t.lineno = 0
+
+def t_ENDFILE(t):
+    r'^\#\#endfile'
+    (filename, t.lineno) = fileNameStack.pop()
+
 #
 # The functions t_NEWLINE, t_ignore, and t_error are
 # special for the lex module.
@@ -209,7 +224,7 @@ def p_specification(t):
     namespace = isa_name + "Inst"
     # wrap the decode block as a function definition
     t[4].wrap_decode_block('''
-StaticInstPtr<%(isa_name)s>
+StaticInstPtr
 %(isa_name)s::decodeInst(%(isa_name)s::MachInst machInst)
 {
     using namespace %(namespace)s;
@@ -258,14 +273,19 @@ def p_def_or_output(t):
 # Output blocks 'output <foo> {{...}}' (C++ code blocks) are copied
 # directly to the appropriate output section.
 
+
+# Protect any non-dict-substitution '%'s in a format string
+# (i.e. those not followed by '(')
+def protect_non_subst_percents(s):
+    return re.sub(r'%(?!\()', '%%', s)
+
 # Massage output block by substituting in template definitions and bit
 # operators.  We handle '%'s embedded in the string that don't
 # indicate template substitutions (or CPU-specific symbols, which get
 # handled in GenCode) by doubling them first so that the format
 # operation will reduce them back to single '%'s.
 def process_output(s):
-    # protect any non-substitution '%'s (not followed by '(')
-    s = re.sub(r'%(?!\()', '%%', s)
+    s = protect_non_subst_percents(s)
     # protects cpu-specific symbols too
     s = protect_cpu_symbols(s)
     return substBitOps(s % templateMap)
@@ -300,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:
@@ -366,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.
 ##############
@@ -556,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.
@@ -603,43 +712,6 @@ yacc.yacc()
 #
 #####################################################################
 
-################
-# CpuModel class
-#
-# The CpuModel class encapsulates everything we need to know about a
-# particular CPU model.
-
-class CpuModel:
-    # List of all CPU models.  Accessible as CpuModel.list.
-    list = []
-
-    # Constructor.  Automatically adds models to CpuModel.list.
-    def __init__(self, name, filename, includes, strings):
-        self.name = name
-        self.filename = filename   # filename for output exec code
-        self.includes = includes   # include files needed in exec file
-        # The 'strings' dict holds all the per-CPU symbols we can
-        # substitute into templates etc.
-        self.strings = strings
-        # Add self to list.
-        CpuModel.list.append(self)
-
-# Define CPU models.  The following lines should contain the only
-# CPU-model-specific information in this file.  Note that the ISA
-# description itself should have *no* CPU-model-specific content.
-CpuModel('InorderCPU', 'inorder_cpu_exec.cc',
-         '#include "cpu/inorder_cpu/inorder_cpu.hh"',
-         { 'CPU_exec_context': 'InorderCPU' })
-CpuModel('SimpleCPU', 'simple_cpu_exec.cc',
-         '#include "cpu/simple_cpu/simple_cpu.hh"',
-         { 'CPU_exec_context': 'SimpleCPU' })
-CpuModel('FastCPU', 'fast_cpu_exec.cc',
-         '#include "cpu/fast_cpu/fast_cpu.hh"',
-         { 'CPU_exec_context': 'FastCPU' })
-CpuModel('FullCPU', 'full_cpu_exec.cc',
-         '#include "cpu/full_cpu/dyn_inst.hh"',
-         { 'CPU_exec_context': 'DynInst' })
-
 # Expand template with CPU-specific references into a dictionary with
 # an entry for each CPU model name.  The entry key is the model name
 # and the corresponding value is the template with the CPU-specific
@@ -648,7 +720,7 @@ def expand_cpu_symbols_to_dict(template):
     # Protect '%'s that don't go with CPU-specific terms
     t = re.sub(r'%(?!\(CPU_)', '%%', template)
     result = {}
-    for cpu in CpuModel.list:
+    for cpu in cpu_models:
         result[cpu.name] = t % cpu.strings
     return result
 
@@ -707,7 +779,7 @@ class GenCode:
     # concatenates all the individual strings in the operands.
     def __add__(self, other):
         exec_output = {}
-        for cpu in CpuModel.list:
+        for cpu in cpu_models:
             n = cpu.name
             exec_output[n] = self.exec_output[n] + other.exec_output[n]
         return GenCode(self.header_output + other.header_output,
@@ -721,7 +793,7 @@ class GenCode:
         self.header_output = pre + self.header_output
         self.decoder_output  = pre + self.decoder_output
         self.decode_block = pre + self.decode_block
-        for cpu in CpuModel.list:
+        for cpu in cpu_models:
             self.exec_output[cpu.name] = pre + self.exec_output[cpu.name]
 
     # Wrap the decode block in a pair of strings (e.g., 'case foo:'
@@ -736,6 +808,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
@@ -758,7 +843,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():
@@ -791,20 +876,19 @@ def defFormat(id, params, code, lineno):
 
 ##############
 # Stack: a simple stack object.  Used for both formats (formatStack)
-# and default cases (defaultStack).
+# and default cases (defaultStack).  Simply wraps a list to give more
+# stack-like syntax and enable initialization with an argument list
+# (as opposed to an argument that's a list).
 
-class Stack:
-    def __init__(self, initItem):
-        self.stack = [ initItem ]
+class Stack(list):
+    def __init__(self, *items):
+        list.__init__(self, items)
 
     def push(self, item):
-        self.stack.append(item);
-
-    def pop(self):
-        return self.stack.pop()
+        self.append(item);
 
     def top(self):
-        return self.stack[-1]
+        return self[-1]
 
 # The global format stack.
 formatStack = Stack(NoFormat())
@@ -821,7 +905,7 @@ defaultStack = Stack( None )
 # Used to make nested code blocks look pretty.
 #
 def indent(s):
-    return re.sub(r'(?m)^(?!\#)', '  ', s)
+    return re.sub(r'(?m)^(?!#)', '  ', s)
 
 #
 # Munge a somewhat arbitrarily formatted piece of Python code
@@ -848,12 +932,21 @@ def fixPythonIndentation(s):
     return s
 
 # Error handler.  Just call exit.  Output formatted to work under
-# Emacs compile-mode.
+# Emacs compile-mode.  This function should be called when errors due
+# to user input are detected (as opposed to parser bugs).
 def error(lineno, string):
-    sys.exit("%s:%d: %s" % (input_filename, lineno, string))
+    spaces = ""
+    for (filename, line) in fileNameStack[0:-1]:
+        print spaces + "In file included from " + filename
+        spaces += "  "
+    # Uncomment the following line to get a Python stack backtrace for
+    # these errors too.  Can be handy when trying to debug the parser.
+    # traceback.print_exc()
+    sys.exit(spaces + "%s:%d: %s" % (fileNameStack[-1][0], lineno, string))
 
 # Like error(), but include a Python stack backtrace (for processing
-# Python exceptions).
+# Python exceptions).  This function should be called for errors that
+# appear to be bugs in the parser itself.
 def error_bt(lineno, string):
     traceback.print_exc()
     print >> sys.stderr, "%s:%d: %s" % (input_filename, lineno, string)
@@ -923,8 +1016,12 @@ class Template:
             myDict.update(d.__dict__)
         else:
             raise TypeError, "Template.subst() arg must be or have dictionary"
+        # Protect non-Python-dict substitutions (e.g. if there's a printf
+        # in the templated C++ code)
+        template = protect_non_subst_percents(self.template)
         # CPU-model-specific substitutions are handled later (in GenCode).
-        return protect_cpu_symbols(self.template) % myDict
+        template = protect_cpu_symbols(template)
+        return template % myDict
 
     # Convert to string.  This handles the case when a template with a
     # CPU-specific term gets interpolated into another template or into
@@ -941,74 +1038,93 @@ 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()
+            self.mem_acc_type = self.ctype
+
+    # 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()
+            self.op_src_decl = self.makeDecl()
+        else:
+            self.op_rd = ''
+            self.op_src_decl = ''
+
+        if self.is_dest:
+            self.op_wb = self.makeWrite()
+            self.op_dest_decl = self.makeDecl()
+        else:
+            self.op_wb = ''
+            self.op_dest_decl = ''
 
     def isMem(self):
         return 0
@@ -1025,234 +1141,249 @@ 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.munged_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.munged_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.munged_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.munged_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.munged_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.munged_name, base, size-1)
+                   (self.base_name, base, self.size-1)
         else:
-            return '%s = %s;\n' % (op_desc.munged_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.munged_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.munged_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:
-            c += '\n\t_srcRegIdx[%d] = %s_DepTag;' % \
-                 (op_desc.src_reg_idx, self.reg_spec)
-        if op_desc.is_dest:
-            c += '\n\t_destRegIdx[%d] = %s_DepTag;' % \
-                 (op_desc.dest_reg_idx, self.reg_spec)
+        if self.is_src:
+            c += '\n\t_srcRegIdx[%d] = %s;' % \
+                 (self.src_reg_idx, self.reg_spec)
+        if self.is_dest:
+            c += '\n\t_destRegIdx[%d] = %s;' % \
+                 (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.munged_name, base)
+        base = 'xc->readMiscReg(%s)' % self.reg_spec
+        if self.size == self.dflt_size:
+            return '%s = %s;\n' % (self.base_name, base)
         else:
             return '%s = bits(%s, %d, 0);\n' % \
-                   (op_desc.munged_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.munged_name)
+        wb = 'xc->setMiscReg(%s, %s);\n' % (self.reg_spec, self.base_name)
         wb += 'if (traceData) { traceData->setData(%s); }' % \
-              op_desc.munged_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.munged_name)
-        # Declare var to hold memory access flags.
-        c += 'unsigned %s_flags = memAccessFlags;\n' % op_desc.base_name
-        # If this operand is a dest (i.e., it's a store operation),
-        # then we need to declare a variable for the write result code
-        # as well.
-        if op_desc.is_dest:
-            c += 'uint64_t %s_write_result = 0;\n' % op_desc.base_name
+        c = '%s %s = 0;\n' % (self.ctype, self.base_name)
         return c
 
-    def makeRead(self, op_desc):
-        (size, type, is_signed) = operandSizeMap[op_desc.eff_ext]
-        eff_type = 'uint%d_t' % size
-        return 'fault = xc->read(EA, (%s&)%s, %s_flags);\n' \
-               % (eff_type, op_desc.munged_name, op_desc.base_name)
-
-    def makeWrite(self, op_desc):
-        (size, type, is_signed) = operandSizeMap[op_desc.eff_ext]
-        eff_type = 'uint%d_t' % size
-        wb = 'fault = xc->write((%s&)%s, EA, %s_flags, &%s_write_result);\n' \
-               % (eff_type, op_desc.munged_name, op_desc.base_name,
-                  op_desc.base_name)
-        wb += 'if (traceData) { traceData->setData(%s); }' % \
-              op_desc.munged_name
-        return wb
+    def makeRead(self):
+        return ''
 
-class NPCOperandTraits(OperandTraits):
-    def makeConstructor(self, op_desc):
+    def makeWrite(self):
         return ''
 
-    def makeRead(self, op_desc):
-        return '%s = xc->readPC() + 4;\n' % op_desc.munged_name
+    # 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):
+        return self.size
 
-    def makeWrite(self, op_desc):
-        return 'xc->setNextPC(%s);\n' % op_desc.munged_name
 
+class NPCOperand(Operand):
+    def makeConstructor(self):
+        return ''
 
-exportContextSymbols = ('IntRegOperandTraits', 'FloatRegOperandTraits',
-                        'ControlRegOperandTraits', 'MemOperandTraits',
-                        'NPCOperandTraits', 'InstObjParams', 'CodeBlock',
-                        're', 'string')
+    def makeRead(self):
+        return '%s = xc->readPC() + 4;\n' % self.base_name
 
-exportContext = {}
-
-def updateExportContext():
-    exportContext.update(exportDict(*exportContextSymbols))
-    exportContext.update(templateMap)
+    def makeWrite(self):
+        return 'xc->setNextPC(%s);\n' % self.base_name
 
+class NNPCOperand(Operand):
+    def makeConstructor(self):
+        return ''
 
-def exportDict(*symNames):
-    return dict([(s, eval(s)) for s in symNames])
+    def makeRead(self):
+        return '%s = xc->readPC() + 8;\n' % self.base_name
 
+    def makeWrite(self):
+        return 'xc->setNextNPC(%s);\n' % self.base_name
 
-#
-# 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
@@ -1274,52 +1405,72 @@ 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.
-        # The 'munged name' replaces the '.' between the base and
-        # extension (if any) with a '_' to make a legal C++ variable name.
-        if ext:
-            self.eff_ext = ext
-            self.munged_name = base_name + '_' + ext
-        else:
-            self.eff_ext = self.traits.dflt_ext
-            self.munged_name = base_name
-
-    # 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)
+class OperandList:
 
-        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:
-    def __init__(self):
+    # Find all the operands in the given code block.  Returns an operand
+    # descriptor list (instance of class OperandList).
+    def __init__(self, code):
         self.items = []
         self.bases = {}
+        # delete comments so we don't match on reg specifiers inside
+        code = commentRE.sub('', code)
+        # search for operands
+        next_pos = 0
+        while 1:
+            match = operandsRE.search(code, next_pos)
+            if not match:
+                # no more matches: we're done
+                break
+            op = match.groups()
+            # regexp groups are operand full name, base, and extension
+            (op_full, op_base, op_ext) = op
+            # if the token following the operand is an assignment, this is
+            # a destination (LHS), else it's a source (RHS)
+            is_dest = (assignRE.match(code, match.end()) != None)
+            is_src = not is_dest
+            # see if we've already seen this one
+            op_desc = self.find_base(op_base)
+            if op_desc:
+                if op_desc.ext != op_ext:
+                    error(0, 'Inconsistent extensions for operand %s' % \
+                          op_base)
+                op_desc.is_src = op_desc.is_src or is_src
+                op_desc.is_dest = op_desc.is_dest or is_dest
+            else:
+                # new operand: create new descriptor
+                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()
+        self.sort()
+        # enumerate source & dest register operands... used in building
+        # constructor later
+        self.numSrcRegs = 0
+        self.numDestRegs = 0
+        self.numFPDestRegs = 0
+        self.numIntDestRegs = 0
+        self.memOperand = None
+        for op_desc in self.items:
+            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.isFloatReg():
+                        self.numFPDestRegs += 1
+                    elif op_desc.isIntReg():
+                        self.numIntDestRegs += 1
+            elif op_desc.isMem():
+                if self.memOperand:
+                    error(0, "Code block has more than one memory operand.")
+                self.memOperand = op_desc
+        # now make a final pass to finalize op_desc fields that may depend
+        # on the register enumeration
+        for op_desc in self.items:
+            op_desc.finalize()
 
     def __len__(self):
         return len(self.items)
@@ -1364,7 +1515,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())
@@ -1374,73 +1525,11 @@ commentRE = re.compile(r'//.*\n')
 # (used in findOperands())
 assignRE = re.compile(r'\s*=(?!=)', re.MULTILINE)
 
-#
-# Find all the operands in the given code block.  Returns an operand
-# descriptor list (instance of class OperandDescriptorList).
-#
-def findOperands(code):
-    operands = OperandDescriptorList()
-    # delete comments so we don't accidentally match on reg specifiers inside
-    code = commentRE.sub('', code)
-    # search for operands
-    next_pos = 0
-    while 1:
-        match = operandsRE.search(code, next_pos)
-        if not match:
-            # no more matches: we're done
-            break
-        op = match.groups()
-        # regexp groups are operand full name, base, and extension
-        (op_full, op_base, op_ext) = op
-        # if the token following the operand is an assignment, this is
-        # a destination (LHS), else it's a source (RHS)
-        is_dest = (assignRE.match(code, match.end()) != None)
-        is_src = not is_dest
-        # see if we've already seen this one
-        op_desc = operands.find_base(op_base)
-        if op_desc:
-            if op_desc.ext != op_ext:
-                error(0, 'Inconsistent extensions for operand %s' % op_base)
-            op_desc.is_src = op_desc.is_src or is_src
-            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)
-            operands.append(op_desc)
-        # start next search after end of current match
-        next_pos = match.end()
-    operands.sort()
-    # enumerate source & dest register operands... used in building
-    # constructor later
-    srcRegs = 0
-    destRegs = 0
-    operands.numFPDestRegs = 0
-    operands.numIntDestRegs = 0
-    for op_desc in operands:
-        if op_desc.traits.isReg():
-            if op_desc.is_src:
-                op_desc.src_reg_idx = srcRegs
-                srcRegs += 1
-            if op_desc.is_dest:
-                op_desc.dest_reg_idx = destRegs
-                destRegs += 1
-                if op_desc.traits.isFloatReg():
-                    operands.numFPDestRegs += 1
-                elif op_desc.traits.isIntReg():
-                    operands.numIntDestRegs += 1
-    operands.numSrcRegs = srcRegs
-    operands.numDestRegs = destRegs
-    # now make a final pass to finalize op_desc fields that may depend
-    # on the register enumeration
-    for op_desc in operands:
-        op_desc.finalize()
-    return operands
-
 # Munge operand names in code string to make legal C++ variable names.
-# (Will match munged_name attribute of OperandDescriptor object.)
+# This means getting rid of the type extension if any.
+# (Will match base_name attribute of Operand object.)
 def substMungedOpNames(code):
-    return operandsWithExtRE.sub(r'\1_\2', code)
+    return operandsWithExtRE.sub(r'\1', code)
 
 def joinLists(t):
     return map(string.join, t)
@@ -1464,7 +1553,7 @@ def makeFlagConstructor(flag_list):
 class CodeBlock:
     def __init__(self, code):
         self.orig_code = code
-        self.operands = findOperands(code)
+        self.operands = OperandList(code)
         self.code = substMungedOpNames(substBitOps(code))
         self.constructor = self.operands.concatAttrStrings('constructor')
         self.constructor += \
@@ -1478,22 +1567,23 @@ class CodeBlock:
 
         self.op_decl = self.operands.concatAttrStrings('op_decl')
 
-        is_mem = lambda op: op.traits.isMem()
-        not_mem = lambda op: not op.traits.isMem()
+        is_src = lambda op: op.is_src
+        is_dest = lambda op: op.is_dest
+
+        self.op_src_decl = \
+                  self.operands.concatSomeAttrStrings(is_src, 'op_src_decl')
+        self.op_dest_decl = \
+                  self.operands.concatSomeAttrStrings(is_dest, 'op_dest_decl')
 
         self.op_rd = self.operands.concatAttrStrings('op_rd')
         self.op_wb = self.operands.concatAttrStrings('op_wb')
-        self.op_mem_rd = \
-                 self.operands.concatSomeAttrStrings(is_mem, 'op_rd')
-        self.op_mem_wb = \
-                 self.operands.concatSomeAttrStrings(is_mem, 'op_wb')
-        self.op_nonmem_rd = \
-                 self.operands.concatSomeAttrStrings(not_mem, 'op_rd')
-        self.op_nonmem_wb = \
-                 self.operands.concatSomeAttrStrings(not_mem, 'op_wb')
 
         self.flags = self.operands.concatAttrLists('flags')
 
+        if self.operands.memOperand:
+            self.mem_acc_size = self.operands.memOperand.mem_acc_size
+            self.mem_acc_type = self.operands.memOperand.mem_acc_type
+
         # Make a basic guess on the operand class (function unit type).
         # These are good enough for most cases, and will be overridden
         # later otherwise.
@@ -1554,36 +1644,6 @@ class InstObjParams:
 #
 
 file_template = '''
-/*
- * Copyright (c) 2003
- * The Regents of The University of Michigan
- * All Rights Reserved
- *
- * This code is part of the M5 simulator, developed by Nathan Binkert,
- * Erik Hallnor, Steve Raasch, and Steve Reinhardt, with contributions
- * from Ron Dreslinski, Dave Greene, and Lisa Hsu.
- *
- * Permission is granted to use, copy, create derivative works and
- * redistribute this software and such derivative works for any
- * purpose, so long as the copyright notice above, this grant of
- * permission, and the disclaimer below appear in all copies made; and
- * so long as the name of The University of Michigan is not used in
- * any advertising or publicity pertaining to the use or distribution
- * of this software without specific, written prior authorization.
- *
- * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE
- * UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY PURPOSE, AND
- * WITHOUT WARRANTY BY THE UNIVERSITY OF MICHIGAN OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE. THE REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE
- * LIABLE FOR ANY DAMAGES, INCLUDING DIRECT, SPECIAL, INDIRECT,
- * INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM
- * ARISING OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
- * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGES.
- */
-
 /*
  * DO NOT EDIT THIS FILE!!!
  *
@@ -1599,6 +1659,8 @@ namespace %(namespace)s {
 %(namespace_output)s
 
 } // namespace %(namespace)s
+
+%(decode_function)s
 '''
 
 
@@ -1625,19 +1687,48 @@ def update_if_needed(file, contents):
         f.write(contents)
         f.close()
 
+# This regular expression matches include directives
+includeRE = re.compile(r'^\s*##include\s+"(?P<filename>[\w/.-]*)".*$',
+                       re.MULTILINE)
+
+def preprocess_isa_desc(isa_desc):
+    # Find any includes and include them
+    pos = 0
+    while 1:
+        m = includeRE.search(isa_desc, pos)
+        if not m:
+            break
+        filename = m.group('filename')
+        print 'Including file "%s"' % filename
+        try:
+            isa_desc = isa_desc[:m.start()] + \
+                       '##newfile "' + filename + '"\n' + \
+                       open(filename).read() + \
+                       '##endfile\n' + \
+                       isa_desc[m.end():]
+        except IOError:
+            error(0, 'Error including file "%s"' % (filename))
+        pos = m.start()
+    return isa_desc
+
 #
 # Read in and parse the ISA description.
 #
-def parse_isa_desc(isa_desc_file, output_dir, include_path):
+def parse_isa_desc(isa_desc_file, output_dir):
     # set a global var for the input filename... used in error messages
     global input_filename
     input_filename = isa_desc_file
+    global fileNameStack
+    fileNameStack = [(input_filename, 1)]
 
     # Suck the ISA description file in.
     input = open(isa_desc_file)
     isa_desc = input.read()
     input.close()
 
+    # Perform Preprocessing
+    isa_desc = preprocess_isa_desc(isa_desc)
+
     # Parse it.
     (isa_name, namespace, global_code, namespace_code) = yacc.parse(isa_desc)
 
@@ -1649,24 +1740,33 @@ def parse_isa_desc(isa_desc_file, output_dir, include_path):
     includes = '#include "base/bitfield.hh" // for bitfield support'
     global_output = global_code.header_output
     namespace_output = namespace_code.header_output
+    decode_function = ''
     update_if_needed(output_dir + '/decoder.hh', file_template % vars())
 
     # generate decoder.cc
-    includes = '#include "%s/decoder.hh"' % include_path
+    includes = '#include "decoder.hh"'
     global_output = global_code.decoder_output
     namespace_output = namespace_code.decoder_output
-    namespace_output += namespace_code.decode_block
+    # namespace_output += namespace_code.decode_block
+    decode_function = namespace_code.decode_block
     update_if_needed(output_dir + '/decoder.cc', file_template % vars())
 
     # generate per-cpu exec files
-    for cpu in CpuModel.list:
-        includes = '#include "%s/decoder.hh"\n' % include_path
+    for cpu in cpu_models:
+        includes = '#include "decoder.hh"\n'
         includes += cpu.includes
         global_output = global_code.exec_output[cpu.name]
         namespace_output = namespace_code.exec_output[cpu.name]
+        decode_function = ''
         update_if_needed(output_dir + '/' + cpu.filename,
                           file_template % vars())
 
+# global list of CpuModel objects (see cpu_models.py)
+cpu_models = []
+
 # Called as script: get args from command line.
+# Args are: <path to cpu_models.py> <isa desc file> <output dir> <cpu models>
 if __name__ == '__main__':
-    parse_isa_desc(sys.argv[1], sys.argv[2], sys.argv[3])
+    execfile(sys.argv[1])  # read in CpuModel definitions
+    cpu_models = [CpuModel.dict[cpu] for cpu in sys.argv[4:]]
+    parse_isa_desc(sys.argv[2], sys.argv[3])