X86: Fix the expected size of the immediate offset in MOV_MI.
[gem5.git] / src / arch / isa_parser.py
index a96622d4a25287ca91ef067cf4a09b167af8dfa2..d5b5bbe4f9c56586082475689918e2ffc335da2c 100755 (executable)
@@ -25,7 +25,6 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #
 # Authors: Steve Reinhardt
-#          Korey Sewell
 
 import os
 import sys
@@ -40,8 +39,8 @@ from types import *
 # of 'build' in the current tree.
 sys.path[0:0] = [os.environ['M5_PLY']]
 
-import lex
-import yacc
+from ply import lex
+from ply import yacc
 
 #####################################################################
 #
@@ -81,12 +80,12 @@ tokens = reserved + (
     # code literal
     'CODELIT',
 
-    # ( ) [ ] { } < > , ; : :: *
+    # ( ) [ ] { } < > , ; : :: *
     'LPAREN', 'RPAREN',
     'LBRACKET', 'RBRACKET',
     'LBRACE', 'RBRACE',
     'LESS', 'GREATER', 'EQUALS',
-    'COMMA', 'SEMI', 'COLON', 'DBLCOLON',
+    'COMMA', 'SEMI', 'DOT', 'COLON', 'DBLCOLON',
     'ASTERISK',
 
     # C preprocessor directives
@@ -113,9 +112,10 @@ t_GREATER          = r'\>'
 t_EQUALS           = r'='
 t_COMMA            = r','
 t_SEMI             = r';'
+t_DOT              = r'\.'
 t_COLON            = r':'
 t_DBLCOLON         = r'::'
-t_ASTERISK        = r'\*'
+t_ASTERISK         = r'\*'
 
 # Identifiers and reserved words
 reserved_map = { }
@@ -133,7 +133,7 @@ def t_INTLIT(t):
     try:
         t.value = int(t.value,0)
     except ValueError:
-        error(t.lineno, 'Integer value "%s" too large' % t.value)
+        error(t.lexer.lineno, 'Integer value "%s" too large' % t.value)
         t.value = 0
     return t
 
@@ -143,7 +143,7 @@ def t_STRLIT(t):
     r"(?m)'([^'])+'"
     # strip off quotes
     t.value = t.value[1:-1]
-    t.lineno += t.value.count('\n')
+    t.lexer.lineno += t.value.count('\n')
     return t
 
 
@@ -153,22 +153,22 @@ def t_CODELIT(t):
     r"(?m)\{\{([^\}]|}(?!\}))+\}\}"
     # strip off {{ & }}
     t.value = t.value[2:-2]
-    t.lineno += t.value.count('\n')
+    t.lexer.lineno += t.value.count('\n')
     return t
 
 def t_CPPDIRECTIVE(t):
     r'^\#[^\#].*\n'
-    t.lineno += t.value.count('\n')
+    t.lexer.lineno += t.value.count('\n')
     return t
 
 def t_NEWFILE(t):
     r'^\#\#newfile\s+"[\w/.-]*"'
-    fileNameStack.push((t.value[11:-1], t.lineno))
-    t.lineno = 0
+    fileNameStack.push((t.value[11:-1], t.lexer.lineno))
+    t.lexer.lineno = 0
 
 def t_ENDFILE(t):
     r'^\#\#endfile'
-    (old_filename, t.lineno) = fileNameStack.pop()
+    (old_filename, t.lexer.lineno) = fileNameStack.pop()
 
 #
 # The functions t_NEWLINE, t_ignore, and t_error are
@@ -178,7 +178,7 @@ def t_ENDFILE(t):
 # Newlines
 def t_NEWLINE(t):
     r'\n+'
-    t.lineno += t.value.count('\n')
+    t.lexer.lineno += t.value.count('\n')
 
 # Comments
 def t_comment(t):
@@ -189,11 +189,11 @@ t_ignore           = ' \t\x0c'
 
 # Error handler
 def t_error(t):
-    error(t.lineno, "illegal character '%s'" % t.value[0])
+    error(t.lexer.lineno, "illegal character '%s'" % t.value[0])
     t.skip(1)
 
 # Build the lexer
-lex.lex()
+lexer = lex.lex()
 
 #####################################################################
 #
@@ -261,6 +261,7 @@ def p_defs_and_outputs_1(t):
 def p_def_or_output(t):
     '''def_or_output : def_format
                      | def_bitfield
+                     | def_bitfield_struct
                      | def_template
                      | def_operand_types
                      | def_operands
@@ -309,12 +310,19 @@ def p_output_exec(t):
 def p_global_let(t):
     'global_let : LET CODELIT SEMI'
     updateExportContext()
+    exportContext["header_output"] = ''
+    exportContext["decoder_output"] = ''
+    exportContext["exec_output"] = ''
+    exportContext["decode_block"] = ''
     try:
         exec fixPythonIndentation(t[2]) in exportContext
     except Exception, exc:
-        error(t.lineno(1),
+        error(t.lexer.lineno,
               'error: %s in global let block "%s".' % (exc, t[2]))
-    t[0] = GenCode() # contributes nothing to the output C++ file
+    t[0] = GenCode(header_output = exportContext["header_output"],
+                   decoder_output = exportContext["decoder_output"],
+                   exec_output = exportContext["exec_output"],
+                   decode_block = exportContext["decode_block"])
 
 # Define the mapping from operand type extensions to C++ types and bit
 # widths (stored in operandTypeMap).
@@ -323,9 +331,9 @@ def p_def_operand_types(t):
     try:
         userDict = eval('{' + t[3] + '}')
     except Exception, exc:
-        error(t.lineno(1),
+        error(t.lexer.lineno,
               'error: %s in def operand_types block "%s".' % (exc, t[3]))
-    buildOperandTypeMap(userDict, t.lineno(1))
+    buildOperandTypeMap(userDict, t.lexer.lineno)
     t[0] = GenCode() # contributes nothing to the output C++ file
 
 # Define the mapping from operand names to operand classes and other
@@ -333,14 +341,14 @@ def p_def_operand_types(t):
 def p_def_operands(t):
     'def_operands : DEF OPERANDS CODELIT SEMI'
     if not globals().has_key('operandTypeMap'):
-        error(t.lineno(1),
+        error(t.lexer.lineno,
               'error: operand types must be defined before operands')
     try:
-        userDict = eval('{' + t[3] + '}')
+        userDict = eval('{' + t[3] + '}', exportContext)
     except Exception, exc:
-        error(t.lineno(1),
+        error(t.lexer.lineno,
               'error: %s in def operands block "%s".' % (exc, t[3]))
-    buildOperandNameMap(userDict, t.lineno(1))
+    buildOperandNameMap(userDict, t.lexer.lineno)
     t[0] = GenCode() # contributes nothing to the output C++ file
 
 # A bitfield definition looks like:
@@ -363,6 +371,23 @@ def p_def_bitfield_1(t):
     hash_define = '#undef %s\n#define %s\t%s\n' % (t[4], t[4], expr)
     t[0] = GenCode(header_output = hash_define)
 
+# alternate form for structure member: 'def bitfield <ID> <ID>'
+def p_def_bitfield_struct(t):
+    'def_bitfield_struct : DEF opt_signed BITFIELD ID id_with_dot SEMI'
+    if (t[2] != ''):
+        error(t.lexer.lineno, 'error: structure bitfields are always unsigned.')
+    expr = 'machInst.%s' % t[5]
+    hash_define = '#undef %s\n#define %s\t%s\n' % (t[4], t[4], expr)
+    t[0] = GenCode(header_output = hash_define)
+
+def p_id_with_dot_0(t):
+    'id_with_dot : ID'
+    t[0] = t[1]
+
+def p_id_with_dot_1(t):
+    'id_with_dot : ID DOT id_with_dot'
+    t[0] = t[1] + t[2] + t[3]
+
 def p_opt_signed_0(t):
     'opt_signed : SIGNED'
     t[0] = t[1]
@@ -384,7 +409,7 @@ def p_def_template(t):
 def p_def_format(t):
     'def_format : DEF FORMAT ID LPAREN param_list RPAREN CODELIT SEMI'
     (id, params, code) = (t[3], t[5], t[7])
-    defFormat(id, params, code, t.lineno(1))
+    defFormat(id, params, code, t.lexer.lineno)
     t[0] = GenCode()
 
 # The formal parameter list for an instruction format is a possibly
@@ -454,7 +479,7 @@ def p_excess_args_param(t):
 
 #
 # A decode block looks like:
-#      decode <field1> [, <field2>]* [default <inst>] { ... }
+#       decode <field1> [, <field2>]* [default <inst>] { ... }
 #
 def p_decode_block(t):
     'decode_block : DECODE ID opt_default LBRACE decode_stmt_list RBRACE'
@@ -494,7 +519,7 @@ def p_decode_stmt_list_0(t):
 def p_decode_stmt_list_1(t):
     'decode_stmt_list : decode_stmt decode_stmt_list'
     if (t[1].has_decode_default and t[2].has_decode_default):
-        error(t.lineno(1), 'Two default cases in decode block')
+        error(t.lexer.lineno, 'Two default cases in decode block')
     t[0] = t[1] + t[2]
 
 #
@@ -539,7 +564,7 @@ def p_push_format_id(t):
         formatStack.push(formatMap[t[1]])
         t[0] = ('', '// format %s' % t[1])
     except KeyError:
-        error(t.lineno(1), 'instruction format "%s" not defined.' % t[1])
+        error(t.lexer.lineno, 'instruction format "%s" not defined.' % t[1])
 
 # Nested decode block: if the value of the current field matches the
 # specified constant, do a nested decode on some other field.
@@ -591,7 +616,7 @@ def p_inst_0(t):
     'inst : ID LPAREN arg_list RPAREN'
     # Pass the ID and arg list to the current format class to deal with.
     currentFormat = formatStack.top()
-    codeObj = currentFormat.defineInst(t[1], t[3], t.lineno(1))
+    codeObj = currentFormat.defineInst(t[1], t[3], t.lexer.lineno)
     args = ','.join(map(str, t[3]))
     args = re.sub('(?m)^', '//', args)
     args = re.sub('^//', '', args)
@@ -606,8 +631,8 @@ def p_inst_1(t):
     try:
         format = formatMap[t[1]]
     except KeyError:
-        error(t.lineno(1), 'instruction format "%s" not defined.' % t[1])
-    codeObj = format.defineInst(t[3], t[5], t.lineno(1))
+        error(t.lexer.lineno, 'instruction format "%s" not defined.' % t[1])
+    codeObj = format.defineInst(t[3], t[5], t.lexer.lineno)
     comment = '\n// %s::%s(%s)\n' % (t[1], t[3], t[5])
     codeObj.prepend_all(comment)
     t[0] = codeObj
@@ -696,14 +721,14 @@ def p_empty(t):
 # *token*, not a grammar symbol (hence the need to use t.value)
 def p_error(t):
     if t:
-        error(t.lineno, "syntax error at '%s'" % t.value)
+        error(t.lexer.lineno, "syntax error at '%s'" % t.value)
     else:
         error(0, "unknown syntax error", True)
 
 # END OF GRAMMAR RULES
 #
 # Now build the parser.
-yacc.yacc()
+parser = yacc.yacc()
 
 
 #####################################################################
@@ -808,8 +833,7 @@ class GenCode:
 # a defineInst() method that generates the code for an instruction
 # definition.
 
-exportContextSymbols = ('InstObjParams', 'CodeBlock',
-                        'makeList', 're', 'string')
+exportContextSymbols = ('InstObjParams', 'makeList', 're', 'string')
 
 exportContext = {}
 
@@ -841,7 +865,11 @@ class Format:
         context = {}
         updateExportContext()
         context.update(exportContext)
-        context.update({ 'name': name, 'Name': string.capitalize(name) })
+        if len(name):
+            Name = name[0].upper()
+            if len(name) > 1:
+                Name += name[1:]
+        context.update({ 'name': name, 'Name': Name })
         try:
             vars = self.func(self.user_code, context, *args[0], **args[1])
         except Exception, exc:
@@ -1003,27 +1031,80 @@ def substBitOps(code):
 # Template objects are format strings that allow substitution from
 # the attribute spaces of other objects (e.g. InstObjParams instances).
 
+labelRE = re.compile(r'(?<!%)%\(([^\)]+)\)[sd]')
+
 class Template:
     def __init__(self, t):
         self.template = t
 
     def subst(self, d):
+        myDict = None
+
+        # 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).
+        template = protect_cpu_symbols(template)
+
+        # Build a dict ('myDict') to use for the template substitution.
         # Start with the template namespace.  Make a copy since we're
         # going to modify it.
         myDict = templateMap.copy()
-        # if the argument is a dictionary, we just use it.
-        if isinstance(d, dict):
+
+        if isinstance(d, InstObjParams):
+            # If we're dealing with an InstObjParams object, we need
+            # to be a little more sophisticated.  The instruction-wide
+            # parameters are already formed, but the parameters which
+            # are only function wide still need to be generated.
+            compositeCode = ''
+
+            myDict.update(d.__dict__)
+            # The "operands" and "snippets" attributes of the InstObjParams
+            # objects are for internal use and not substitution.
+            del myDict['operands']
+            del myDict['snippets']
+
+            snippetLabels = [l for l in labelRE.findall(template)
+                             if d.snippets.has_key(l)]
+
+            snippets = dict([(s, mungeSnippet(d.snippets[s]))
+                             for s in snippetLabels])
+
+            myDict.update(snippets)
+
+            compositeCode = ' '.join(map(str, snippets.values()))
+
+            # Add in template itself in case it references any
+            # operands explicitly (like Mem)
+            compositeCode += ' ' + template
+
+            operands = SubOperandList(compositeCode, d.operands)
+
+            myDict['op_decl'] = operands.concatAttrStrings('op_decl')
+
+            is_src = lambda op: op.is_src
+            is_dest = lambda op: op.is_dest
+
+            myDict['op_src_decl'] = \
+                      operands.concatSomeAttrStrings(is_src, 'op_src_decl')
+            myDict['op_dest_decl'] = \
+                      operands.concatSomeAttrStrings(is_dest, 'op_dest_decl')
+
+            myDict['op_rd'] = operands.concatAttrStrings('op_rd')
+            myDict['op_wb'] = operands.concatAttrStrings('op_wb')
+
+            if d.operands.memOperand:
+                myDict['mem_acc_size'] = d.operands.memOperand.mem_acc_size
+                myDict['mem_acc_type'] = d.operands.memOperand.mem_acc_type
+
+        elif isinstance(d, dict):
+            # if the argument is a dictionary, we just use it.
             myDict.update(d)
-        # if the argument is an object, we use its attribute map.
         elif hasattr(d, '__dict__'):
+            # if the argument is an object, we use its attribute map.
             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).
-        template = protect_cpu_symbols(template)
         return template % myDict
 
     # Convert to string.  This handles the case when a template with a
@@ -1067,11 +1148,17 @@ def buildOperandTypeMap(userDict, lineno):
             ctype = 'uint%d_t' % size
             is_signed = 0
         elif desc == 'float':
-            is_signed = 1      # shouldn't really matter
+            is_signed = 1       # shouldn't really matter
             if size == 32:
                 ctype = 'float'
             elif size == 64:
                 ctype = 'double'
+        elif desc == 'twin64 int':
+            is_signed = 0
+            ctype = 'Twin64_t'
+        elif desc == 'twin32 int':
+            is_signed = 0
+            ctype = 'Twin32_t'
         if ctype == '':
             error(lineno, 'Unrecognized type description "%s" in userDict')
         operandTypeMap[ext] = (size, ctype, is_signed)
@@ -1086,6 +1173,39 @@ def buildOperandTypeMap(userDict, lineno):
 # (e.g., "32-bit integer register").
 #
 class Operand(object):
+    def buildReadCode(self, func = None):
+        code = self.read_code % {"name": self.base_name,
+                                 "func": func,
+                                 "op_idx": self.src_reg_idx,
+                                 "reg_idx": self.reg_spec,
+                                 "size": self.size,
+                                 "ctype": self.ctype}
+        if self.size != self.dflt_size:
+            return '%s = bits(%s, %d, 0);\n' % \
+                   (self.base_name, code, self.size-1)
+        else:
+            return '%s = %s;\n' % \
+                   (self.base_name, code)
+
+    def buildWriteCode(self, func = None):
+        if (self.size != self.dflt_size and self.is_signed):
+            final_val = 'sext<%d>(%s)' % (self.size, self.base_name)
+        else:
+            final_val = self.base_name
+        code = self.write_code % {"name": self.base_name,
+                                  "func": func,
+                                  "op_idx": self.dest_reg_idx,
+                                  "reg_idx": self.reg_spec,
+                                  "size": self.size,
+                                  "ctype": self.ctype,
+                                  "final_val": final_val}
+        return '''
+        {
+            %s final_val = %s;
+            %s;
+            if (traceData) { traceData->setData(final_val); }
+        }''' % (self.dflt_ctype, final_val, code)
+
     def __init__(self, full_name, ext, is_src, is_dest):
         self.full_name = full_name
         self.ext = ext
@@ -1104,7 +1224,10 @@ class Operand(object):
         # 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
+            if self.ctype in ['Twin32_t', 'Twin64_t']:
+                self.mem_acc_type = 'Twin'
+            else:
+                self.mem_acc_type = 'uint'
 
     # Finalize additional fields (primarily code fields).  This step
     # is done separately since some of these fields may depend on the
@@ -1179,6 +1302,8 @@ class IntRegOperand(Operand):
     def makeRead(self):
         if (self.ctype == 'float' or self.ctype == 'double'):
             error(0, 'Attempt to read integer register as FP')
+        if self.read_code != None:
+            return self.buildReadCode('readIntRegOperand')
         if (self.size == self.dflt_size):
             return '%s = xc->readIntRegOperand(this, %d);\n' % \
                    (self.base_name, self.src_reg_idx)
@@ -1195,6 +1320,8 @@ class IntRegOperand(Operand):
     def makeWrite(self):
         if (self.ctype == 'float' or self.ctype == 'double'):
             error(0, 'Attempt to write integer register as FP')
+        if self.write_code != None:
+            return self.buildWriteCode('setIntRegOperand')
         if (self.size != self.dflt_size and self.is_signed):
             final_val = 'sext<%d>(%s)' % (self.size, self.base_name)
         else:
@@ -1226,27 +1353,15 @@ class FloatRegOperand(Operand):
 
     def makeRead(self):
         bit_select = 0
-        width = 0;
-        if (self.ctype == 'float'):
-            func = 'readFloatRegOperand'
-            width = 32;
-        elif (self.ctype == 'double'):
+        if (self.ctype == 'float' or self.ctype == 'double'):
             func = 'readFloatRegOperand'
-            width = 64;
         else:
             func = 'readFloatRegOperandBits'
-            if (self.ctype == 'uint32_t'):
-                width = 32;
-            elif (self.ctype == 'uint64_t'):
-                width = 64;
             if (self.size != self.dflt_size):
                 bit_select = 1
-        if width:
-            base = 'xc->%s(this, %d, %d)' % \
-                   (func, self.src_reg_idx, width)
-        else:
-            base = 'xc->%s(this, %d)' % \
-                   (func, self.src_reg_idx)
+        base = 'xc->%s(this, %d)' % (func, self.src_reg_idx)
+        if self.read_code != None:
+            return self.buildReadCode(func)
         if bit_select:
             return '%s = bits(%s, %d, 0);\n' % \
                    (self.base_name, base, self.size-1)
@@ -1256,34 +1371,23 @@ class FloatRegOperand(Operand):
     def makeWrite(self):
         final_val = self.base_name
         final_ctype = self.ctype
-        widthSpecifier = ''
-        width = 0
-        if (self.ctype == 'float'):
-            width = 32
-            func = 'setFloatRegOperand'
-        elif (self.ctype == 'double'):
-            width = 64
+        if (self.ctype == 'float' or self.ctype == 'double'):
             func = 'setFloatRegOperand'
-        elif (self.ctype == 'uint32_t'):
+        elif (self.ctype == 'uint32_t' or self.ctype == 'uint64_t'):
             func = 'setFloatRegOperandBits'
-            width = 32
-        elif (self.ctype == 'uint64_t'):
-            func = 'setFloatRegOperandBits'
-            width = 64
         else:
             func = 'setFloatRegOperandBits'
             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)
-        if width:
-            widthSpecifier = ', %d' % width
+        if self.write_code != None:
+            return self.buildWriteCode(func)
         wb = '''
         {
             %s final_val = %s;
-            xc->%s(this, %d, final_val%s);\n
+            xc->%s(this, %d, final_val);\n
             if (traceData) { traceData->setData(final_val); }
-        }''' % (final_ctype, final_val, func, self.dest_reg_idx,
-                widthSpecifier)
+        }''' % (final_ctype, final_val, func, self.dest_reg_idx)
         return wb
 
 class ControlRegOperand(Operand):
@@ -1296,10 +1400,10 @@ class ControlRegOperand(Operand):
     def makeConstructor(self):
         c = ''
         if self.is_src:
-            c += '\n\t_srcRegIdx[%d] = %s;' % \
+            c += '\n\t_srcRegIdx[%d] = %s + Ctrl_Base_DepTag;' % \
                  (self.src_reg_idx, self.reg_spec)
         if self.is_dest:
-            c += '\n\t_destRegIdx[%d] = %s;' % \
+            c += '\n\t_destRegIdx[%d] = %s + Ctrl_Base_DepTag;' % \
                  (self.dest_reg_idx, self.reg_spec)
         return c
 
@@ -1307,7 +1411,9 @@ class ControlRegOperand(Operand):
         bit_select = 0
         if (self.ctype == 'float' or self.ctype == 'double'):
             error(0, 'Attempt to read control register as FP')
-        base = 'xc->readMiscReg(%s)' % self.reg_spec
+        if self.read_code != None:
+            return self.buildReadCode('readMiscRegOperand')
+        base = 'xc->readMiscRegOperand(this, %s)' % self.src_reg_idx
         if self.size == self.dflt_size:
             return '%s = %s;\n' % (self.base_name, base)
         else:
@@ -1317,7 +1423,10 @@ class ControlRegOperand(Operand):
     def makeWrite(self):
         if (self.ctype == 'float' or self.ctype == 'double'):
             error(0, 'Attempt to write control register as FP')
-        wb = 'xc->setMiscRegWithEffect(%s, %s);\n' % (self.reg_spec, self.base_name)
+        if self.write_code != None:
+            return self.buildWriteCode('setMiscRegOperand')
+        wb = 'xc->setMiscRegOperand(this, %s, %s);\n' % \
+             (self.dest_reg_idx, self.base_name)
         wb += 'if (traceData) { traceData->setData(%s); }' % \
               self.base_name
         return wb
@@ -1333,13 +1442,20 @@ class MemOperand(Operand):
         # Note that initializations in the declarations are solely
         # to avoid 'uninitialized variable' errors from the compiler.
         # Declare memory data variable.
+        if self.ctype in ['Twin32_t','Twin64_t']:
+            return "%s %s; %s.a = 0; %s.b = 0;\n" % (self.ctype, self.base_name,
+                    self.base_name, self.base_name)
         c = '%s %s = 0;\n' % (self.ctype, self.base_name)
         return c
 
     def makeRead(self):
+        if self.read_code != None:
+            return self.buildReadCode()
         return ''
 
     def makeWrite(self):
+        if self.write_code != None:
+            return self.buildWriteCode()
         return ''
 
     # Return the memory access size *in bits*, suitable for
@@ -1347,15 +1463,46 @@ class MemOperand(Operand):
     def makeAccSize(self):
         return self.size
 
+class UPCOperand(Operand):
+    def makeConstructor(self):
+        return ''
+
+    def makeRead(self):
+        if self.read_code != None:
+            return self.buildReadCode('readMicroPC')
+        return '%s = xc->readMicroPC();\n' % self.base_name
+
+    def makeWrite(self):
+        if self.write_code != None:
+            return self.buildWriteCode('setMicroPC')
+        return 'xc->setMicroPC(%s);\n' % self.base_name
+
+class NUPCOperand(Operand):
+    def makeConstructor(self):
+        return ''
+
+    def makeRead(self):
+        if self.read_code != None:
+            return self.buildReadCode('readNextMicroPC')
+        return '%s = xc->readNextMicroPC();\n' % self.base_name
+
+    def makeWrite(self):
+        if self.write_code != None:
+            return self.buildWriteCode('setNextMicroPC')
+        return 'xc->setNextMicroPC(%s);\n' % self.base_name
 
 class NPCOperand(Operand):
     def makeConstructor(self):
         return ''
 
     def makeRead(self):
+        if self.read_code != None:
+            return self.buildReadCode('readNextPC')
         return '%s = xc->readNextPC();\n' % self.base_name
 
     def makeWrite(self):
+        if self.write_code != None:
+            return self.buildWriteCode('setNextPC')
         return 'xc->setNextPC(%s);\n' % self.base_name
 
 class NNPCOperand(Operand):
@@ -1363,16 +1510,33 @@ class NNPCOperand(Operand):
         return ''
 
     def makeRead(self):
+        if self.read_code != None:
+            return self.buildReadCode('readNextNPC')
         return '%s = xc->readNextNPC();\n' % self.base_name
 
     def makeWrite(self):
+        if self.write_code != None:
+            return self.buildWriteCode('setNextNPC')
         return 'xc->setNextNPC(%s);\n' % self.base_name
 
 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
+        (base_cls_name, dflt_ext, reg_spec, flags, sort_pri) = val[:5]
+        if len(val) > 5:
+            read_code = val[5]
+        else:
+            read_code = None
+        if len(val) > 6:
+            write_code = val[6]
+        else:
+            write_code = None
+        if len(val) > 7:
+            error(lineno,
+                  'error: too many attributes for operand "%s"' %
+                  base_cls_name)
+            
         (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
@@ -1397,7 +1561,8 @@ def buildOperandNameMap(userDict, lineno):
         # 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'):
+                     'dflt_size', 'dflt_ctype', 'dflt_is_signed',
+                     'read_code', 'write_code'):
             tmp_dict[attr] = eval(attr)
         tmp_dict['base_name'] = op_name
         # New class name will be e.g. "IntReg_Ra"
@@ -1419,9 +1584,9 @@ def buildOperandNameMap(userDict, lineno):
     operands = userDict.keys()
 
     operandsREString = (r'''
-    (?<![\w\.])             # neg. lookbehind assertion: prevent partial matches
+    (?<![\w\.])      # neg. lookbehind assertion: prevent partial matches
     ((%s)(?:\.(\w+))?)   # match: operand with optional '.' then suffix
-    (?![\w\.])      # neg. lookahead assertion: prevent partial matches
+    (?![\w\.])       # neg. lookahead assertion: prevent partial matches
     '''
                         % string.join(operands, '|'))
 
@@ -1437,6 +1602,8 @@ def buildOperandNameMap(userDict, lineno):
     global operandsWithExtRE
     operandsWithExtRE = re.compile(operandsWithExtREString, re.MULTILINE)
 
+maxInstSrcRegs = 0
+maxInstDestRegs = 0
 
 class OperandList:
 
@@ -1500,6 +1667,12 @@ class OperandList:
                 if self.memOperand:
                     error(0, "Code block has more than one memory operand.")
                 self.memOperand = op_desc
+        global maxInstSrcRegs
+        global maxInstDestRegs
+        if maxInstSrcRegs < self.numSrcRegs:
+            maxInstSrcRegs = self.numSrcRegs
+        if maxInstDestRegs < self.numDestRegs:
+            maxInstDestRegs = self.numDestRegs
         # now make a final pass to finalize op_desc fields that may depend
         # on the register enumeration
         for op_desc in self.items:
@@ -1550,6 +1723,48 @@ class OperandList:
     def sort(self):
         self.items.sort(lambda a, b: a.sort_pri - b.sort_pri)
 
+class SubOperandList(OperandList):
+
+    # Find all the operands in the given code block.  Returns an operand
+    # descriptor list (instance of class OperandList).
+    def __init__(self, code, master_list):
+        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
+            # find this op in the master list
+            op_desc = master_list.find_base(op_base)
+            if not op_desc:
+                error(0, 'Found operand %s which is not in the master list!' \
+                        ' This is an internal error' % \
+                          op_base)
+            else:
+                # See if we've already found this operand
+                op_desc = self.find_base(op_base)
+                if not op_desc:
+                    # if not, add a reference to it to this sub list
+                    self.append(master_list.bases[op_base])
+
+            # start next search after end of current match
+            next_pos = match.end()
+        self.sort()
+        self.memOperand = None
+        for op_desc in self.items:
+            if op_desc.isMem():
+                if self.memOperand:
+                    error(0, "Code block has more than one memory operand.")
+                self.memOperand = op_desc
+
 # Regular expression object to match C++ comments
 # (used in findOperands())
 commentRE = re.compile(r'//.*\n')
@@ -1564,8 +1779,12 @@ assignRE = re.compile(r'\s*=(?!=)', re.MULTILINE)
 def substMungedOpNames(code):
     return operandsWithExtRE.sub(r'\1', code)
 
-def joinLists(t):
-    return map(string.join, t)
+# Fix up code snippets for final substitution in templates.
+def mungeSnippet(s):
+    if isinstance(s, str):
+        return substMungedOpNames(substBitOps(s))
+    else:
+        return s
 
 def makeFlagConstructor(flag_list):
     if len(flag_list) == 0:
@@ -1583,11 +1802,24 @@ def makeFlagConstructor(flag_list):
     code = pre + string.join(flag_list, post + pre) + post
     return code
 
-class CodeBlock:
-    def __init__(self, code):
-        self.orig_code = code
-        self.operands = OperandList(code)
-        self.code = substMungedOpNames(substBitOps(code))
+# Assume all instruction flags are of the form 'IsFoo'
+instFlagRE = re.compile(r'Is.*')
+
+# OpClass constants end in 'Op' except No_OpClass
+opClassRE = re.compile(r'.*Op|No_OpClass')
+
+class InstObjParams:
+    def __init__(self, mnem, class_name, base_class = '',
+                 snippets = {}, opt_args = []):
+        self.mnemonic = mnem
+        self.class_name = class_name
+        self.base_class = base_class
+        if not isinstance(snippets, dict):
+            snippets = {'code' : snippets}
+        compositeCode = ' '.join(map(str, snippets.values()))
+        self.snippets = snippets
+
+        self.operands = OperandList(compositeCode)
         self.constructor = self.operands.concatAttrStrings('constructor')
         self.constructor += \
                  '\n\t_numSrcRegs = %d;' % self.operands.numSrcRegs
@@ -1597,28 +1829,10 @@ class CodeBlock:
                  '\n\t_numFPDestRegs = %d;' % self.operands.numFPDestRegs
         self.constructor += \
                  '\n\t_numIntDestRegs = %d;' % self.operands.numIntDestRegs
-
-        self.op_decl = self.operands.concatAttrStrings('op_decl')
-
-        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.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
+        # These are good enough for most cases, and can be overridden
         # later otherwise.
         if 'IsStore' in self.flags:
             self.op_class = 'MemWriteOp'
@@ -1629,48 +1843,6 @@ class CodeBlock:
         else:
             self.op_class = 'IntAluOp'
 
-# Assume all instruction flags are of the form 'IsFoo'
-instFlagRE = re.compile(r'Is.*')
-
-# OpClass constants end in 'Op' except No_OpClass
-opClassRE = re.compile(r'.*Op|No_OpClass')
-
-class InstObjParams:
-    def __init__(self, mnem, class_name, base_class = '',
-                 code = None, opt_args = [], extras = {}):
-        self.mnemonic = mnem
-        self.class_name = class_name
-        self.base_class = base_class
-        if code:
-            #If the user already made a CodeBlock, pick the parts from it
-            if isinstance(code, CodeBlock):
-                origCode = code.orig_code
-                codeBlock = code
-            else:
-                origCode = code
-                codeBlock = CodeBlock(code)
-            stringExtras = {}
-            otherExtras = {}
-            for (k, v) in extras.items():
-                if type(v) == str:
-                    stringExtras[k] = v
-                else:
-                    otherExtras[k] = v
-            compositeCode = "\n".join([origCode] + stringExtras.values())
-            # compositeCode = '\n'.join([origCode] +
-            #      [pair[1] for pair in extras])
-            compositeBlock = CodeBlock(compositeCode)
-            for code_attr in compositeBlock.__dict__.keys():
-                setattr(self, code_attr, getattr(compositeBlock, code_attr))
-            for (key, snippet) in stringExtras.items():
-                setattr(self, key, CodeBlock(snippet).code)
-            for (key, item) in otherExtras.items():
-                setattr(self, key, item)
-            self.code = codeBlock.code
-            self.orig_code = origCode
-        else:
-            self.constructor = ''
-            self.flags = []
         # Optional arguments are assumed to be either StaticInst flags
         # or an OpClass value.  To avoid having to import a complete
         # list of these values to match against, we do it ad-hoc
@@ -1720,6 +1892,22 @@ namespace %(namespace)s {
 %(decode_function)s
 '''
 
+max_inst_regs_template = '''
+/*
+ * DO NOT EDIT THIS FILE!!!
+ *
+ * It was automatically generated from the ISA description in %(filename)s
+ */
+
+namespace %(namespace)s {
+
+    const int MaxInstSrcRegs = %(MaxInstSrcRegs)d;
+    const int MaxInstDestRegs = %(MaxInstDestRegs)d;
+
+} // namespace %(namespace)s
+
+'''
+
 
 # Update the output file only if the new contents are different from
 # the current contents.  Minimizes the files that need to be rebuilt
@@ -1787,7 +1975,8 @@ def parse_isa_desc(isa_desc_file, output_dir):
     fileNameStack.push((isa_desc_file, 0))
 
     # Parse it.
-    (isa_name, namespace, global_code, namespace_code) = yacc.parse(isa_desc)
+    (isa_name, namespace, global_code, namespace_code) = \
+        parser.parse(isa_desc, lexer=lexer)
 
     # grab the last three path components of isa_desc_file to put in
     # the output
@@ -1818,6 +2007,16 @@ def parse_isa_desc(isa_desc_file, output_dir):
         update_if_needed(output_dir + '/' + cpu.filename,
                           file_template % vars())
 
+    # The variable names here are hacky, but this will creat local variables
+    # which will be referenced in vars() which have the value of the globals.
+    global maxInstSrcRegs
+    MaxInstSrcRegs = maxInstSrcRegs
+    global maxInstDestRegs
+    MaxInstDestRegs = maxInstDestRegs
+    # max_inst_regs.hh
+    update_if_needed(output_dir + '/max_inst_regs.hh', \
+            max_inst_regs_template % vars())
+
 # global list of CpuModel objects (see cpu_models.py)
 cpu_models = []