Significant changes to ISA description to completely factor
authorSteve Reinhardt <stever@eecs.umich.edu>
Mon, 17 May 2004 18:49:46 +0000 (11:49 -0700)
committerSteve Reinhardt <stever@eecs.umich.edu>
Mon, 17 May 2004 18:49:46 +0000 (11:49 -0700)
out CPU model.  ISA description now generates multiple
output source files to (in theory) reduce compilation time.

arch/alpha/isa_desc:
    Update for parser changes.  Move most constructors
    out of class declarations (which are now in decoder.hh)
    and into decoder.cc.  Move all execute() methods into
    exec output.
arch/isa_parser.py:
    Significant changes to make ISA description completely
    independent of CPU model, and isolate model-dependent parts
    of parser into one little class (CpuModel).  Also split up code
    output into multiple files (a header, a main source file, and
    per-cpu execute() method files).

    Noticeable changes to language as a result.  See updated Doxygen
    documentation.
cpu/simple_cpu/simple_cpu.hh:
    SimpleCPUExecContext typedef no longer needed.
    Add forward declaration of Process.
cpu/static_inst.hh:
    SimpleCPUExecContext and FullCPUExecContext typedefs no longer needed.
    Make eaCompInst() and memAccInst() return const refs.

--HG--
extra : convert_revision : 71471f267804fafd0a881bac7445677e76334daf

arch/alpha/isa_desc
arch/isa_parser.py
cpu/simple_cpu/simple_cpu.hh
cpu/static_inst.hh

index 9bbdac9b45e6706fb607d8f3a6f13f3b03893326..f964101df774294099f32ebc2017782084fd1d89 100644 (file)
@@ -1,39 +1,67 @@
 // -*- mode:c++ -*-
+
+////////////////////////////////////////////////////////////////////
 //
 // Alpha ISA description file.
 //
+////////////////////////////////////////////////////////////////////
 
-let {{
-    global rcs_id
-    rcs_id = "$Id$"
-}};
 
+////////////////////////////////////////////////////////////////////
+//
+// Output include file directives.
+//
 
+output header {{
 #include <sstream>
 #include <iostream>
 #include <iomanip>
 
+#include "cpu/static_inst.hh"
+#include "mem/mem_req.hh"  // some constructors use MemReq flags
+}};
+
+output decoder {{
+#include "base/cprintf.hh"
+#include "base/loader/symtab.hh"
+#include "cpu/exec_context.hh"  // for Jump::branchTarget()
+
 #include <math.h>
 #if defined(linux)
 #include <fenv.h>
 #endif
+}};
 
-#include "base/cprintf.hh"
-#include "base/misc.hh"
-#include "cpu/exec_context.hh"
+output exec {{
+#include <math.h>
+#if defined(linux)
+#include <fenv.h>
+#endif
+
+#include "cpu/base_cpu.hh"
 #include "cpu/exetrace.hh"
-#include "cpu/full_cpu/dyn_inst.hh"
-#include "cpu/simple_cpu/simple_cpu.hh"
-#include "cpu/static_inst.hh"
 #include "sim/sim_exit.hh"
 
 #ifdef FULL_SYSTEM
 #include "arch/alpha/ev5.hh"
 #include "arch/alpha/pseudo_inst.hh"
 #endif
+}};
+
+////////////////////////////////////////////////////////////////////
+//
+// Namespace statement.  Everything below this line will be in the
+// AlphaISAInst namespace.
+//
+
 
 namespace AlphaISA;
 
+////////////////////////////////////////////////////////////////////
+//
+// Bitfield definitions.
+//
+
 // Universal (format-independent) fields
 def bitfield OPCODE    <31:26>;
 def bitfield RA                <25:21>;
@@ -92,70 +120,48 @@ def bitfield HW_IPR_IDX <15:0>;     // IPR index
 // M5 instructions
 def bitfield M5FUNC <7:0>;
 
-let {{
-    global operandTypeMap
-    operandTypeMap = {
-       'sb' : ('signed int', 8),
-       'ub' : ('unsigned int', 8),
-       'sw' : ('signed int', 16),
-       'uw' : ('unsigned int', 16),
-       'sl' : ('signed int', 32),
-       'ul' : ('unsigned int', 32),
-       'sq' : ('signed int', 64),
-       'uq' : ('unsigned int', 64),
-       'sf' : ('float', 32),
-       'df' : ('float', 64)
-    }
-
-    global operandTraitsMap
-    operandTraitsMap = {
-       # Int regs default to unsigned, but code should not count on this.
-       # For clarity, descriptions that depend on unsigned behavior should
-       # explicitly specify '.uq'.
-       'Ra': IntRegOperandTraits('uq', 'RA', 'IsInteger', 1),
-       'Rb': IntRegOperandTraits('uq', 'RB', 'IsInteger', 2),
-       'Rc': IntRegOperandTraits('uq', 'RC', 'IsInteger', 3),
-       'Fa': FloatRegOperandTraits('df', 'FA', 'IsFloating', 1),
-       'Fb': FloatRegOperandTraits('df', 'FB', 'IsFloating', 2),
-       'Fc': FloatRegOperandTraits('df', 'FC', 'IsFloating', 3),
-       'Mem': MemOperandTraits('uq', None,
-                               ('IsMemRef', 'IsLoad', 'IsStore'), 4),
-       'NPC': NPCOperandTraits('uq', None, ( None, None, 'IsControl' ), 4),
-       'Runiq': ControlRegOperandTraits('uq', 'Uniq', None, 1),
-       'FPCR':  ControlRegOperandTraits('uq', 'Fpcr', None, 1),
-       # The next two are hacks for non-full-system call-pal emulation
-       'R0':  IntRegOperandTraits('uq', '0', None, 1),
-       'R16': IntRegOperandTraits('uq', '16', None, 1),
-    }
+def operand_types {{
+    'sb' : ('signed int', 8),
+    'ub' : ('unsigned int', 8),
+    'sw' : ('signed int', 16),
+    'uw' : ('unsigned int', 16),
+    'sl' : ('signed int', 32),
+    'ul' : ('unsigned int', 32),
+    'sq' : ('signed int', 64),
+    'uq' : ('unsigned int', 64),
+    'sf' : ('float', 32),
+    'df' : ('float', 64)
+}};
 
-    defineDerivedOperandVars()
+def operands {{
+    # Int regs default to unsigned, but code should not count on this.
+    # For clarity, descriptions that depend on unsigned behavior should
+    # explicitly specify '.uq'.
+    'Ra': IntRegOperandTraits('uq', 'RA', 'IsInteger', 1),
+    'Rb': IntRegOperandTraits('uq', 'RB', 'IsInteger', 2),
+    'Rc': IntRegOperandTraits('uq', 'RC', 'IsInteger', 3),
+    'Fa': FloatRegOperandTraits('df', 'FA', 'IsFloating', 1),
+    'Fb': FloatRegOperandTraits('df', 'FB', 'IsFloating', 2),
+    'Fc': FloatRegOperandTraits('df', 'FC', 'IsFloating', 3),
+    'Mem': MemOperandTraits('uq', None,
+                            ('IsMemRef', 'IsLoad', 'IsStore'), 4),
+    'NPC': NPCOperandTraits('uq', None, ( None, None, 'IsControl' ), 4),
+    'Runiq': ControlRegOperandTraits('uq', 'Uniq', None, 1),
+    'FPCR':  ControlRegOperandTraits('uq', 'Fpcr', None, 1),
+    # The next two are hacks for non-full-system call-pal emulation
+    'R0':  IntRegOperandTraits('uq', '0', None, 1),
+    'R16': IntRegOperandTraits('uq', '16', None, 1)
 }};
 
-declare {{
-// just temporary, while comparing with old code for debugging
-// #define SS_COMPATIBLE_DISASSEMBLY
+////////////////////////////////////////////////////////////////////
+//
+// Basic instruction classes/templates/formats etc.
+//
 
-    /// Check "FP enabled" machine status bit.  Called when executing any FP
-    /// instruction in full-system mode.
-    /// @retval Full-system mode: No_Fault if FP is enabled, Fen_Fault
-    /// if not.  Non-full-system mode: always returns No_Fault.
-#ifdef FULL_SYSTEM
-    template <class XC>
-    inline Fault checkFpEnableFault(XC *xc)
-    {
-       Fault fault = No_Fault; // dummy... this ipr access should not fault
-       if (!ICSR_FPE(xc->readIpr(AlphaISA::IPR_ICSR, fault))) {
-           fault = Fen_Fault;
-       }
-       return fault;
-    }
-#else
-    template <class XC>
-    inline Fault checkFpEnableFault(XC *xc)
-    {
-       return No_Fault;
-    }
-#endif
+output header {{
+// uncomment the following to get SimpleScalar-compatible disassembly
+// (useful for diffing output traces).
+// #define SS_COMPATIBLE_DISASSEMBLY
 
     /**
      * Base class for all Alpha static instructions.
@@ -183,47 +189,60 @@ declare {{
 
        /// Print a register name for disassembly given the unique
        /// dependence tag number (FP or int).
-       void printReg(std::ostream &os, int reg)
-       {
-           if (reg < FP_Base_DepTag) {
-               ccprintf(os, "r%d", reg);
-           }
-           else {
-               ccprintf(os, "f%d", reg - FP_Base_DepTag);
-           }
-       }
+       void printReg(std::ostream &os, int reg);
 
-       std::string generateDisassembly(Addr pc, const SymbolTable *symtab)
-       {
-           std::stringstream ss;
+       std::string generateDisassembly(Addr pc, const SymbolTable *symtab);
+    };
+}};
 
-           ccprintf(ss, "%-10s ", mnemonic);
+output decoder {{
+    void
+    AlphaStaticInst::printReg(std::ostream &os, int reg)
+    {
+       if (reg < FP_Base_DepTag) {
+           ccprintf(os, "r%d", reg);
+       }
+       else {
+           ccprintf(os, "f%d", reg - FP_Base_DepTag);
+       }
+    }
 
-           // just print the first two source regs... if there's
-           // a third one, it's a read-modify-write dest (Rc),
-           // e.g. for CMOVxx
-           if (_numSrcRegs > 0) {
-               printReg(ss, _srcRegIdx[0]);
-           }
-           if (_numSrcRegs > 1) {
-               ss << ",";
-               printReg(ss, _srcRegIdx[1]);
-           }
+    std::string
+    AlphaStaticInst::generateDisassembly(Addr pc, const SymbolTable *symtab)
+    {
+       std::stringstream ss;
 
-           // just print the first dest... if there's a second one,
-           // it's generally implicit
-           if (_numDestRegs > 0) {
-               if (_numSrcRegs > 0)
-                   ss << ",";
-               printReg(ss, _destRegIdx[0]);
-           }
+       ccprintf(ss, "%-10s ", mnemonic);
 
-           return ss.str();
+       // just print the first two source regs... if there's
+       // a third one, it's a read-modify-write dest (Rc),
+       // e.g. for CMOVxx
+       if (_numSrcRegs > 0) {
+           printReg(ss, _srcRegIdx[0]);
        }
-    };
+       if (_numSrcRegs > 1) {
+           ss << ",";
+           printReg(ss, _srcRegIdx[1]);
+       }
+
+       // just print the first dest... if there's a second one,
+       // it's generally implicit
+       if (_numDestRegs > 0) {
+           if (_numSrcRegs > 0)
+               ss << ",";
+           printReg(ss, _destRegIdx[0]);
+       }
+
+       return ss.str();
+    }
 }};
 
+// Declarations for execute() methods.
+def template BasicExecDeclare {{
+    Fault execute(%(CPU_exec_context)s *, Trace::InstRecord *);
+}};
 
+// Basic instruction class declaration template.
 def template BasicDeclare {{
     /**
      * Static instruction class for "%(mnemonic)s".
@@ -232,18 +251,24 @@ def template BasicDeclare {{
     {
       public:
        /// Constructor.
-       %(class_name)s(MachInst machInst)
-            : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s)
-       {
-           %(constructor)s;
-       }
+       %(class_name)s(MachInst machInst);
 
-       %(exec_func_declarations)s
+       %(BasicExecDeclare)s
     };
 }};
 
+// Basic instruction class constructor template.
+def template BasicConstructor {{
+    inline %(class_name)s::%(class_name)s(MachInst machInst)
+        : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s)
+    {
+       %(constructor)s;
+    }
+}};
+
+// Basic instruction class execute method template.
 def template BasicExecute {{
-    Fault %(class_name)s::execute(%(cpu_model)s *xc,
+    Fault %(class_name)s::execute(%(CPU_exec_context)s *xc,
                                  Trace::InstRecord *traceData)
     {
        Fault fault = No_Fault;
@@ -261,10 +286,12 @@ def template BasicExecute {{
     }
 }};
 
+// Basic decode template.
 def template BasicDecode {{
     return new %(class_name)s(machInst);
 }};
 
+// Basic decode template, passing mnemonic in as string arg to constructor.
 def template BasicDecodeWithMnemonic {{
     return new %(class_name)s("%(mnemonic)s", machInst);
 }};
@@ -272,14 +299,20 @@ def template BasicDecodeWithMnemonic {{
 // The most basic instruction format... used only for a few misc. insts
 def format BasicOperate(code, *flags) {{
     iop = InstObjParams(name, Name, 'AlphaStaticInst', CodeBlock(code), flags)
-    return iop.subst('BasicDeclare', 'BasicDecode', 'BasicExecute')
+    header_output = BasicDeclare.subst(iop)
+    decoder_output = BasicConstructor.subst(iop)
+    decode_block = BasicDecode.subst(iop)
+    exec_output = BasicExecute.subst(iop)
 }};
 
 
 
 ////////////////////////////////////////////////////////////////////
+//
+// Nop
+//
 
-declare {{
+output header {{
     /**
      * Static instruction class for no-ops.  This is a leaf class.
      */
@@ -299,21 +332,21 @@ declare {{
 
        ~Nop() { }
 
-       std::string generateDisassembly(Addr pc, const SymbolTable *symtab)
-       {
+       std::string generateDisassembly(Addr pc, const SymbolTable *symtab);
+
+       %(BasicExecDeclare)s
+    };
+}};
+
+output decoder {{
+    std::string Nop::generateDisassembly(Addr pc, const SymbolTable *symtab)
+    {
 #ifdef SS_COMPATIBLE_DISASSEMBLY
-           return originalDisassembly;
+       return originalDisassembly;
 #else
-           return csprintf("%-10s (%s)", "nop", originalDisassembly);
+       return csprintf("%-10s (%s)", "nop", originalDisassembly);
 #endif
-       }
-
-       Fault execute(SimpleCPUExecContext *, Trace::InstRecord *)
-        { return No_Fault; }
-
-       Fault execute(FullCPUExecContext *, Trace::InstRecord *)
-        { return No_Fault; }
-    };
+    }
 
     /// Helper function for decoding nops.  Substitute Nop object
     /// for original inst passed in as arg (and delete latter).
@@ -327,18 +360,21 @@ declare {{
     }
 }};
 
-def format Nop() {{
-    return ('', 'return new Nop("%s", machInst);\n' % name, 'return No_Fault;')
+output exec {{
+    Fault
+    Nop::execute(%(CPU_exec_context)s *, Trace::InstRecord *)
+    {
+       return No_Fault;
+    }
 }};
 
-
 // integer & FP operate instructions use Rc as dest, so check for
 // Rc == 31 to detect nops
 def template OperateNopCheckDecode {{
  {
      AlphaStaticInst *i = new %(class_name)s(machInst);
      if (RC == 31) {
-        i = makeNop(i);
+         i = makeNop(i);
      }
      return i;
  }
@@ -348,7 +384,10 @@ def template OperateNopCheckDecode {{
 def format BasicOperateWithNopCheck(code, *opt_args) {{
     iop = InstObjParams(name, Name, 'AlphaStaticInst', CodeBlock(code),
                        opt_args)
-    return iop.subst('BasicDeclare', 'OperateNopCheckDecode', 'BasicExecute')
+    header_output = BasicDeclare.subst(iop)
+    decoder_output = BasicConstructor.subst(iop)
+    decode_block = OperateNopCheckDecode.subst(iop)
+    exec_output = BasicExecute.subst(iop)
 }};
 
 
@@ -357,7 +396,7 @@ def format BasicOperateWithNopCheck(code, *opt_args) {{
 // Integer operate instructions
 //
 
-declare {{
+output header {{
     /**
      * Base class for integer immediate instructions.
      */
@@ -373,39 +412,45 @@ declare {{
        {
        }
 
-       std::string generateDisassembly(Addr pc, const SymbolTable *symtab)
-       {
-           std::stringstream ss;
+       std::string generateDisassembly(Addr pc, const SymbolTable *symtab);
+    };
+}};
 
-           ccprintf(ss, "%-10s ", mnemonic);
+output decoder {{
+    std::string
+    IntegerImm::generateDisassembly(Addr pc, const SymbolTable *symtab)
+    {
+       std::stringstream ss;
 
-           // just print the first source reg... if there's
-           // a second one, it's a read-modify-write dest (Rc),
-           // e.g. for CMOVxx
-           if (_numSrcRegs > 0) {
-               printReg(ss, _srcRegIdx[0]);
-               ss << ",";
-           }
+       ccprintf(ss, "%-10s ", mnemonic);
 
-           ss << (int)imm;
-           if (_numDestRegs > 0) {
-               ss << ",";
-               printReg(ss, _destRegIdx[0]);
-           }
+       // just print the first source reg... if there's
+       // a second one, it's a read-modify-write dest (Rc),
+       // e.g. for CMOVxx
+       if (_numSrcRegs > 0) {
+           printReg(ss, _srcRegIdx[0]);
+           ss << ",";
+       }
 
-           return ss.str();
+       ss << (int)imm;
+       if (_numDestRegs > 0) {
+           ss << ",";
+           printReg(ss, _destRegIdx[0]);
        }
-    };
+
+       return ss.str();
+    }
 }};
 
+
 def template RegOrImmDecode {{
  {
      AlphaStaticInst *i =
-        (IMM) ? (AlphaStaticInst *)new %(class_name)sImm(machInst)
-        : (AlphaStaticInst *)new %(class_name)s(machInst);
+         (IMM) ? (AlphaStaticInst *)new %(class_name)sImm(machInst)
+               : (AlphaStaticInst *)new %(class_name)s(machInst);
      if (RC == 31) {
-        i = makeNop(i);
+         i = makeNop(i);
      }
      return i;
  }
@@ -432,24 +477,23 @@ def format IntegerOperate(code, *opt_flags) {{
     # generate declaration for register version
     cblk = CodeBlock(code)
     iop = InstObjParams(name, Name, 'AlphaStaticInst', cblk, opt_flags)
-    (decls, exec_code) = iop.subst('BasicDeclare', 'BasicExecute')
+    header_output = BasicDeclare.subst(iop)
+    decoder_output = BasicConstructor.subst(iop)
+    exec_output = BasicExecute.subst(iop)
 
     if uses_imm:
         # append declaration for imm version
         imm_cblk = CodeBlock(imm_code)
         imm_iop = InstObjParams(name, Name + 'Imm', 'IntegerImm', imm_cblk,
                                opt_flags)
-        (imm_decls, imm_exec_code) = \
-                  imm_iop.subst('BasicDeclare', 'BasicExecute')
-       decls += imm_decls
-        exec_code += imm_exec_code
+       header_output += BasicDeclare.subst(imm_iop)
+        decoder_output += BasicConstructor.subst(imm_iop)
+        exec_output += BasicExecute.subst(imm_iop)
         # decode checks IMM bit to pick correct version
-       decode = iop.subst('RegOrImmDecode')
+       decode_block = RegOrImmDecode.subst(iop)
     else:
         # no imm version: just check for nop
-        decode = iop.subst('OperateNopCheckDecode')
-
-    return (decls, decode, exec_code)
+        decode_block = OperateNopCheckDecode.subst(iop)
 }};
 
 
@@ -462,7 +506,29 @@ def format IntegerOperate(code, *opt_flags) {{
 //     BasicOperateWithNopCheck.
 //
 
-declare {{
+output exec {{
+    /// Check "FP enabled" machine status bit.  Called when executing any FP
+    /// instruction in full-system mode.
+    /// @retval Full-system mode: No_Fault if FP is enabled, Fen_Fault
+    /// if not.  Non-full-system mode: always returns No_Fault.
+#ifdef FULL_SYSTEM
+    inline Fault checkFpEnableFault(%(CPU_exec_context)s *xc)
+    {
+       Fault fault = No_Fault; // dummy... this ipr access should not fault
+       if (!ICSR_FPE(xc->readIpr(AlphaISA::IPR_ICSR, fault))) {
+           fault = Fen_Fault;
+       }
+       return fault;
+    }
+#else
+    inline Fault checkFpEnableFault(%(CPU_exec_context)s *xc)
+    {
+       return No_Fault;
+    }
+#endif
+}};
+
+output header {{
     /**
      * Base class for general floating-point instructions.  Includes
      * support for various Alpha rounding and trapping modes.  Only FP
@@ -524,61 +590,88 @@ declare {{
        }
 
 #if defined(linux)
-       int
-       getC99RoundingMode(uint64_t fpcr_val)
-       {
-           if (roundingMode == Dynamic) {
-               return alphaToC99RoundingMode[bits(fpcr_val, 59, 58)];
-           }
-           else {
-               return alphaToC99RoundingMode[roundingMode];
-           }
-       }
+       int getC99RoundingMode(uint64_t fpcr_val);
 #endif
 
        // This differs from the AlphaStaticInst version only in
        // printing suffixes for non-default rounding & trapping modes.
-       std::string generateDisassembly(Addr pc, const SymbolTable *symtab)
-       {
-           std::string mnem_str(mnemonic);
+       std::string generateDisassembly(Addr pc, const SymbolTable *symtab);
+    };
 
-#ifndef SS_COMPATIBLE_DISASSEMBLY
-           std::string suffix("");
-           suffix += ((_destRegIdx[0] >= FP_Base_DepTag)
-                      ? fpTrappingModeSuffix[trappingMode]
-                      : intTrappingModeSuffix[trappingMode]);
-           suffix += roundingModeSuffix[roundingMode];
-
-           if (suffix != "") {
-               mnem_str = csprintf("%s/%s", mnemonic, suffix);
-           }
+}};
+
+
+def template FloatingPointDecode {{
+ {
+     bool fast = (FP_TRAPMODE == AlphaFP::Imprecise
+                 && FP_ROUNDMODE == AlphaFP::Normal);
+     AlphaStaticInst *i =
+        fast ? (AlphaStaticInst *)new %(class_name)sFast(machInst) :
+               (AlphaStaticInst *)new %(class_name)sGeneral(machInst);
+
+     if (FC == 31) {
+        i = makeNop(i);
+     }
+
+     return i;
+ }
+}};
+
+output decoder {{
+#if defined(linux)
+    int
+    AlphaFP::getC99RoundingMode(uint64_t fpcr_val)
+    {
+       if (roundingMode == Dynamic) {
+           return alphaToC99RoundingMode[bits(fpcr_val, 59, 58)];
+       }
+       else {
+           return alphaToC99RoundingMode[roundingMode];
+       }
+    }
 #endif
 
-           std::stringstream ss;
-           ccprintf(ss, "%-10s ", mnem_str.c_str());
+    std::string
+    AlphaFP::generateDisassembly(Addr pc, const SymbolTable *symtab)
+    {
+       std::string mnem_str(mnemonic);
 
-           // just print the first two source regs... if there's
-           // a third one, it's a read-modify-write dest (Rc),
-           // e.g. for CMOVxx
-           if (_numSrcRegs > 0) {
-               printReg(ss, _srcRegIdx[0]);
-           }
-           if (_numSrcRegs > 1) {
-               ss << ",";
-               printReg(ss, _srcRegIdx[1]);
-           }
+#ifndef SS_COMPATIBLE_DISASSEMBLY
+       std::string suffix("");
+       suffix += ((_destRegIdx[0] >= FP_Base_DepTag)
+                  ? fpTrappingModeSuffix[trappingMode]
+                  : intTrappingModeSuffix[trappingMode]);
+       suffix += roundingModeSuffix[roundingMode];
 
-           // just print the first dest... if there's a second one,
-           // it's generally implicit
-           if (_numDestRegs > 0) {
-               if (_numSrcRegs > 0)
-                   ss << ",";
-               printReg(ss, _destRegIdx[0]);
-           }
+       if (suffix != "") {
+           mnem_str = csprintf("%s/%s", mnemonic, suffix);
+       }
+#endif
 
-           return ss.str();
+       std::stringstream ss;
+       ccprintf(ss, "%-10s ", mnem_str.c_str());
+
+       // just print the first two source regs... if there's
+       // a third one, it's a read-modify-write dest (Rc),
+       // e.g. for CMOVxx
+       if (_numSrcRegs > 0) {
+           printReg(ss, _srcRegIdx[0]);
        }
-    };
+       if (_numSrcRegs > 1) {
+           ss << ",";
+           printReg(ss, _srcRegIdx[1]);
+       }
+
+       // just print the first dest... if there's a second one,
+       // it's generally implicit
+       if (_numDestRegs > 0) {
+           if (_numSrcRegs > 0)
+               ss << ",";
+           printReg(ss, _destRegIdx[0]);
+       }
+
+       return ss.str();
+    }
 
 #if defined(linux)
     const int AlphaFP::alphaToC99RoundingMode[] = {
@@ -598,34 +691,19 @@ declare {{
        { "", "v", "INVTM2", "INVTM3", "INVTM4", "sv", "INVTM6", "svi" };
 }};
 
-
-def template FloatingPointDecode {{
- {
-     bool fast = (FP_TRAPMODE == AlphaFP::Imprecise
-                 && FP_ROUNDMODE == AlphaFP::Normal);
-     AlphaStaticInst *i =
-        fast ? (AlphaStaticInst *)new %(class_name)sFast(machInst) :
-               (AlphaStaticInst *)new %(class_name)sGeneral(machInst);
-
-     if (FC == 31) {
-        i = makeNop(i);
-     }
-
-     return i;
- }
-}};
-
 // General format for floating-point operate instructions:
 // - Checks trapping and rounding mode flags.  Trapping modes
 //   currently unimplemented (will fail).
 // - Generates NOP if FC == 31.
 def format FloatingPointOperate(code, *opt_args) {{
     iop = InstObjParams(name, Name, 'AlphaFP', CodeBlock(code), opt_args)
-    decode = iop.subst('FloatingPointDecode')
+    decode_block = FloatingPointDecode.subst(iop)
 
     fast_iop = InstObjParams(name, Name + 'Fast', 'AlphaFP',
-    CodeBlock(code), opt_args)
-    (fast_declare, fast_exec) = fast_iop.subst('BasicDeclare', 'BasicExecute')
+                            CodeBlock(code), opt_args)
+    header_output = BasicDeclare.subst(fast_iop)
+    decoder_output = BasicConstructor.subst(fast_iop)
+    exec_output = BasicExecute.subst(fast_iop)
 
     gen_code_prefix = r'''
 #if defined(linux)
@@ -640,9 +718,9 @@ def format FloatingPointOperate(code, *opt_args) {{
 
     gen_iop = InstObjParams(name, Name + 'General', 'AlphaFP',
     CodeBlock(gen_code_prefix + code + gen_code_suffix), opt_args)
-    (gen_declare, gen_exec) = gen_iop.subst('BasicDeclare', 'BasicExecute')
-    
-    return (fast_declare + gen_declare, decode, fast_exec + gen_exec)
+    header_output += BasicDeclare.subst(gen_iop)
+    decoder_output += BasicConstructor.subst(gen_iop)
+    exec_output += BasicExecute.subst(gen_iop)
 }};
 
 
@@ -651,7 +729,7 @@ def format FloatingPointOperate(code, *opt_args) {{
 // Memory-format instructions: LoadAddress, Load, Store
 //
 
-declare {{
+output header {{
     /**
      * Base class for general Alpha memory-format instructions.
      */
@@ -659,49 +737,71 @@ declare {{
     {
       protected:
 
-       /// Displacement for EA calculation (signed).
-       int32_t disp;
        /// Memory request flags.  See mem_req_base.hh.
         unsigned memAccessFlags;
+       /// Pointer to EAComp object.
+       const StaticInstPtr<AlphaISA> eaCompPtr;
+       /// Pointer to MemAcc object.
+       const StaticInstPtr<AlphaISA> memAccPtr;
 
        /// Constructor
-       Memory(const char *mnem, MachInst _machInst, OpClass __opClass)
+       Memory(const char *mnem, MachInst _machInst, OpClass __opClass,
+              StaticInstPtr<AlphaISA> _eaCompPtr = nullStaticInstPtr,
+              StaticInstPtr<AlphaISA> _memAccPtr = nullStaticInstPtr)
            : AlphaStaticInst(mnem, _machInst, __opClass),
-             disp(MEMDISP), memAccessFlags(0)
+             memAccessFlags(0), eaCompPtr(_eaCompPtr), memAccPtr(_memAccPtr)
        {
        }
 
-       std::string generateDisassembly(Addr pc, const SymbolTable *symtab)
+       std::string generateDisassembly(Addr pc, const SymbolTable *symtab);
+
+      public:
+
+       const StaticInstPtr<AlphaISA> &eaCompInst() const { return eaCompPtr; }
+       const StaticInstPtr<AlphaISA> &memAccInst() const { return memAccPtr; }
+    };
+
+    /**
+     * Base class for memory-format instructions using a 32-bit
+     * displacement (i.e. most of them).
+     */
+    class MemoryDisp32 : public Memory
+    {
+      protected:
+       /// Displacement for EA calculation (signed).
+       int32_t disp;
+
+       /// Constructor.
+       MemoryDisp32(const char *mnem, MachInst _machInst, OpClass __opClass,
+                    StaticInstPtr<AlphaISA> _eaCompPtr = nullStaticInstPtr,
+                    StaticInstPtr<AlphaISA> _memAccPtr = nullStaticInstPtr)
+           : Memory(mnem, _machInst, __opClass, _eaCompPtr, _memAccPtr),
+             disp(MEMDISP)
        {
-           return csprintf("%-10s %c%d,%d(r%d)", mnemonic,
-                           flags[IsFloating] ? 'f' : 'r', RA, MEMDISP, RB);
        }
     };
 
+
     /**
      * Base class for a few miscellaneous memory-format insts
      * that don't interpret the disp field: wh64, fetch, fetch_m, ecb.
      * None of these instructions has a destination register either.
      */
-    class MemoryNoDisp : public AlphaStaticInst
+    class MemoryNoDisp : public Memory
     {
       protected:
-       /// Memory request flags.  See mem_req_base.hh.
-        unsigned memAccessFlags;
-
        /// Constructor
-       MemoryNoDisp(const char *mnem, MachInst _machInst, OpClass __opClass)
-           : AlphaStaticInst(mnem, _machInst, __opClass),
-             memAccessFlags(0)
+       MemoryNoDisp(const char *mnem, MachInst _machInst, OpClass __opClass,
+                    StaticInstPtr<AlphaISA> _eaCompPtr,
+                    StaticInstPtr<AlphaISA> _memAccPtr)
+           : Memory(mnem, _machInst, __opClass, _eaCompPtr, _memAccPtr)
        {
        }
 
-       std::string generateDisassembly(Addr pc, const SymbolTable *symtab)
-       {
-           return csprintf("%-10s (r%d)", mnemonic, RB);
-       }
+       std::string generateDisassembly(Addr pc, const SymbolTable *symtab);
     };
 
+
     /**
      * Base class for "fake" effective-address computation
      * instructions returnded by eaCompInst().
@@ -715,11 +815,7 @@ declare {{
        {
        }
 
-       Fault execute(SimpleCPUExecContext *, Trace::InstRecord *)
-        { panic("attempt to execute eacomp"); }
-
-       Fault execute(FullCPUExecContext *, Trace::InstRecord *)
-        { panic("attempt to execute eacomp"); }
+       %(BasicExecDeclare)s
     };
 
     /**
@@ -735,19 +831,48 @@ declare {{
        {
        }
 
-       Fault execute(SimpleCPUExecContext *, Trace::InstRecord *)
-        { panic("attempt to execute memacc"); }
-
-       Fault execute(FullCPUExecContext *, Trace::InstRecord *)
-        { panic("attempt to execute memacc"); }
+       %(BasicExecDeclare)s
     };
 
 }};
 
 
+output decoder {{
+    std::string
+    Memory::generateDisassembly(Addr pc, const SymbolTable *symtab)
+    {
+       return csprintf("%-10s %c%d,%d(r%d)", mnemonic,
+                       flags[IsFloating] ? 'f' : 'r', RA, MEMDISP, RB);
+    }
+
+    std::string
+    MemoryNoDisp::generateDisassembly(Addr pc, const SymbolTable *symtab)
+    {
+       return csprintf("%-10s (r%d)", mnemonic, RB);
+    }
+}};
+
+output exec {{
+    Fault
+    EACompBase::execute(%(CPU_exec_context)s *, Trace::InstRecord *)
+    {
+       panic("attempt to execute eacomp");
+    }
+
+    Fault
+    MemAccBase::execute(%(CPU_exec_context)s *, Trace::InstRecord *)
+    {
+       panic("attempt to execute memacc");
+    }
+}};
+
+
 def format LoadAddress(code) {{
-    iop = InstObjParams(name, Name, 'Memory', CodeBlock(code))
-    return iop.subst('BasicDeclare', 'BasicDecode', 'BasicExecute')
+    iop = InstObjParams(name, Name, 'MemoryDisp32', CodeBlock(code))
+    header_output = BasicDeclare.subst(iop)
+    decoder_output = BasicConstructor.subst(iop)
+    decode_block = BasicDecode.subst(iop)
+    exec_output = BasicExecute.subst(iop)
 }};
 
 
@@ -766,11 +891,7 @@ def template LoadStoreDeclare {{
        {
          public:
            /// Constructor
-           EAComp(MachInst machInst)
-               : EACompBase(machInst)
-           {
-               %(ea_constructor)s;
-           }
+           EAComp(MachInst machInst);
        };
 
        /**
@@ -780,37 +901,41 @@ def template LoadStoreDeclare {{
        {
          public:
            /// Constructor
-           MemAcc(MachInst machInst)
-               : MemAccBase(machInst, %(op_class)s)
-           {
-               %(memacc_constructor)s;
-           }
-       };
-
-       /// Pointer to EAComp object.
-       StaticInstPtr<AlphaISA> eaCompPtr;
-       /// Pointer to MemAcc object.
-       StaticInstPtr<AlphaISA> memAccPtr;
+           MemAcc(MachInst machInst);
+       };
 
       public:
 
-       StaticInstPtr<AlphaISA> eaCompInst() { return eaCompPtr; }
-       StaticInstPtr<AlphaISA> memAccInst() { return memAccPtr; }
-
        /// Constructor.
-       %(class_name)s(MachInst machInst)
-            : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s),
-              eaCompPtr(new EAComp(machInst)), memAccPtr(new MemAcc(machInst))
-       {
-           %(constructor)s;
-       }
+       %(class_name)s(MachInst machInst);
 
-       %(exec_func_declarations)s
+       %(BasicExecDeclare)s
     };
 }};
 
+def template LoadStoreConstructor {{
+    inline %(class_name)s::EAComp::EAComp(MachInst machInst)
+       : EACompBase(machInst)
+    {
+       %(ea_constructor)s;
+    }
+
+    inline %(class_name)s::MemAcc::MemAcc(MachInst machInst)
+       : MemAccBase(machInst, %(op_class)s)
+    {
+       %(memacc_constructor)s;
+    }
+
+    inline %(class_name)s::%(class_name)s(MachInst machInst)
+        : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s,
+                         new EAComp(machInst), new MemAcc(machInst))
+    {
+       %(constructor)s;
+    }
+}};
+
 def template LoadStoreExecute {{
-    Fault %(class_name)s::execute(%(cpu_model)s *xc,
+    Fault %(class_name)s::execute(%(CPU_exec_context)s *xc,
                                  Trace::InstRecord *traceData)
     {
        Addr EA;
@@ -842,66 +967,9 @@ def template LoadStoreExecute {{
     }
 }};
 
-def template PrefetchDeclare {{
-    /**
-     * Static instruction class for "%(mnemonic)s".
-     */
-    class %(class_name)s : public %(base_class)s
-    {
-      protected:
-
-       /**
-        * "Fake" effective address computation class for "%(mnemonic)s".
-        */
-       class EAComp : public EACompBase
-       {
-         public:
-           /// Constructor
-           EAComp(MachInst machInst)
-               : EACompBase(machInst)
-           {
-               %(ea_constructor)s;
-           }
-       };
-
-       /**
-        * "Fake" memory access instruction class for "%(mnemonic)s".
-        */
-       class MemAcc : public MemAccBase
-       {
-         public:
-           /// Constructor
-           MemAcc(MachInst machInst)
-               : MemAccBase(machInst, %(op_class)s)
-           {
-               %(memacc_constructor)s;
-           }
-       };
-
-       /// Pointer to EAComp object.
-       StaticInstPtr<AlphaISA> eaCompPtr;
-       /// Pointer to MemAcc object.
-       StaticInstPtr<AlphaISA> memAccPtr;
-
-      public:
-
-       StaticInstPtr<AlphaISA> eaCompInst() { return eaCompPtr; }
-       StaticInstPtr<AlphaISA> memAccInst() { return memAccPtr; }
-
-       /// Constructor
-       %(class_name)s(MachInst machInst)
-            : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s),
-              eaCompPtr(new EAComp(machInst)), memAccPtr(new MemAcc(machInst))
-       {
-           %(constructor)s;
-       }
-
-       %(exec_func_declarations)s
-    };
-}};
 
 def template PrefetchExecute {{
-    Fault %(class_name)s::execute(%(cpu_model)s *xc,
+    Fault %(class_name)s::execute(%(CPU_exec_context)s *xc,
                                  Trace::InstRecord *traceData)
     {
        Addr EA;
@@ -947,12 +1015,10 @@ def template LoadPrefetchCheckDecode {{
 
 
 let {{
-global LoadStoreBase
 def LoadStoreBase(name, Name, ea_code, memacc_code, postacc_code = '',
-                 base_class = 'Memory', flags = [],
-                 declare_template = 'LoadStoreDeclare',
-                 decode_template = 'BasicDecode',
-                 exec_template = 'LoadStoreExecute'):
+                 base_class = 'MemoryDisp32', flags = [],
+                 decode_template = BasicDecode,
+                 exec_template = LoadStoreExecute):
     # Segregate flags into instruction flags (handled by InstObjParams)
     # and memory access flags (handled here).
 
@@ -983,62 +1049,68 @@ def LoadStoreBase(name, Name, ea_code, memacc_code, postacc_code = '',
     if mem_flags != '':
         iop.constructor += '\n\tmemAccessFlags = ' + mem_flags + ';'
 
-    return iop.subst(declare_template, decode_template, exec_template)
+    # (header_output, decoder_output, decode_block, exec_output)
+    return (LoadStoreDeclare.subst(iop), LoadStoreConstructor.subst(iop),
+           decode_template.subst(iop), exec_template.subst(iop))
 }};
 
 
 def format LoadOrNop(ea_code, memacc_code, *flags) {{
-    return LoadStoreBase(name, Name, ea_code, memacc_code,
-                        flags = flags,
-                        decode_template = 'LoadNopCheckDecode')
+    (header_output, decoder_output, decode_block, exec_output) = \
+        LoadStoreBase(name, Name, ea_code, memacc_code, flags = flags,
+                      decode_template = LoadNopCheckDecode)
 }};
 
 
 // Note that the flags passed in apply only to the prefetch version
 def format LoadOrPrefetch(ea_code, memacc_code, *pf_flags) {{
     # declare the load instruction object and generate the decode block
-    (decls, decode, exec_code) = \
+    (header_output, decoder_output, decode_block, exec_output) = \
        LoadStoreBase(name, Name, ea_code, memacc_code,
-                     decode_template = 'LoadPrefetchCheckDecode')
+                     decode_template = LoadPrefetchCheckDecode)
 
     # Declare the prefetch instruction object.
 
     # convert flags from tuple to list to make them mutable
     pf_flags = list(pf_flags) + ['IsMemRef', 'IsLoad', 'IsDataPrefetch', 'RdPort']
 
-    (pfdecls, pfdecode, pfexec) = \
+    (pf_header_output, pf_decoder_output, _, pf_exec_output) = \
        LoadStoreBase(name, Name + 'Prefetch', ea_code, '',
-                     flags = pf_flags,
-                     declare_template = 'PrefetchDeclare',
-                     exec_template = 'PrefetchExecute')
+                     flags = pf_flags, exec_template = PrefetchExecute)
 
-    return (decls + pfdecls, decode, exec_code + pfexec)
+    header_output += pf_header_output
+    decoder_output += pf_decoder_output
+    exec_output += pf_exec_output
 }};
 
 
 def format Store(ea_code, memacc_code, *flags) {{
-    return LoadStoreBase(name, Name, ea_code, memacc_code,
-                        flags = flags)
+    (header_output, decoder_output, decode_block, exec_output) = \
+        LoadStoreBase(name, Name, ea_code, memacc_code, flags = flags)
 }};
 
 
 def format StoreCond(ea_code, memacc_code, postacc_code, *flags) {{
-    return LoadStoreBase(name, Name, ea_code, memacc_code, postacc_code,
-                        flags = flags)
+    (header_output, decoder_output, decode_block, exec_output) = \
+        LoadStoreBase(name, Name, ea_code, memacc_code, postacc_code,
+                      flags = flags)
 }};
 
 
 // Use 'MemoryNoDisp' as base: for wh64, fetch, ecb
 def format MiscPrefetch(ea_code, memacc_code, *flags) {{
-    return LoadStoreBase(name, Name, ea_code, memacc_code,
-                        flags = flags, base_class = 'MemoryNoDisp')
+    (header_output, decoder_output, decode_block, exec_output) = \
+        LoadStoreBase(name, Name, ea_code, memacc_code, flags = flags,
+                      base_class = 'MemoryNoDisp')
 }};
 
 
 ////////////////////////////////////////////////////////////////////
+//
+// Control transfer instructions
+//
 
-
-declare {{
+output header {{
 
     /**
      * Base class for instructions whose disassembly is not purely a
@@ -1065,22 +1137,7 @@ declare {{
        {
        }
 
-       const std::string &disassemble(Addr pc, const SymbolTable *symtab)
-       {
-           if (!cachedDisassembly ||
-               pc != cachedPC || symtab != cachedSymtab)
-           {
-               if (cachedDisassembly)
-                   delete cachedDisassembly;
-
-               cachedDisassembly =
-                   new std::string(generateDisassembly(pc, symtab));
-               cachedPC = pc;
-               cachedSymtab = symtab;
-           }
-
-           return *cachedDisassembly;
-       }
+       const std::string &disassemble(Addr pc, const SymbolTable *symtab);
     };
 
     /**
@@ -1100,47 +1157,9 @@ declare {{
        {
        }
 
-       Addr branchTarget(Addr branchPC) const
-       {
-           return branchPC + 4 + disp;
-       }
-
-       std::string generateDisassembly(Addr pc, const SymbolTable *symtab)
-       {
-           std::stringstream ss;
-
-           ccprintf(ss, "%-10s ", mnemonic);
-
-           // There's only one register arg (RA), but it could be
-           // either a source (the condition for conditional
-           // branches) or a destination (the link reg for
-           // unconditional branches)
-           if (_numSrcRegs > 0) {
-               printReg(ss, _srcRegIdx[0]);
-               ss << ",";
-           }
-           else if (_numDestRegs > 0) {
-               printReg(ss, _destRegIdx[0]);
-               ss << ",";
-           }
-
-#ifdef SS_COMPATIBLE_DISASSEMBLY
-           if (_numSrcRegs == 0 && _numDestRegs == 0) {
-               printReg(ss, 31);
-               ss << ",";
-           }
-#endif
-
-           Addr target = pc + 4 + disp;
+       Addr branchTarget(Addr branchPC) const;
 
-           std::string str;
-           if (symtab && symtab->findSymbol(target, str))
-               ss << str;
-           else 
-               ccprintf(ss, "0x%x", target);
-
-           return ss.str();
-       }
+       std::string generateDisassembly(Addr pc, const SymbolTable *symtab);
     };
 
     /**
@@ -1162,36 +1181,106 @@ declare {{
        {
        }
 
-       Addr branchTarget(ExecContext *xc) const
+       Addr branchTarget(ExecContext *xc) const;
+
+       std::string generateDisassembly(Addr pc, const SymbolTable *symtab);
+    };
+}};
+
+output decoder {{
+    Addr
+    Branch::branchTarget(Addr branchPC) const
+    {
+       return branchPC + 4 + disp;
+    }
+
+    Addr
+    Jump::branchTarget(ExecContext *xc) const
+    {
+       Addr NPC = xc->readPC() + 4;
+       uint64_t Rb = xc->readIntReg(_srcRegIdx[0]);
+       return (Rb & ~3) | (NPC & 1);
+    }
+
+    const std::string &
+    PCDependentDisassembly::disassemble(Addr pc, const SymbolTable *symtab)
+    {
+       if (!cachedDisassembly ||
+           pc != cachedPC || symtab != cachedSymtab)
        {
-           Addr NPC = xc->readPC() + 4;
-           uint64_t Rb = xc->readIntReg(_srcRegIdx[0]);
-           return (Rb & ~3) | (NPC & 1);
+           if (cachedDisassembly)
+               delete cachedDisassembly;
+
+           cachedDisassembly =
+               new std::string(generateDisassembly(pc, symtab));
+           cachedPC = pc;
+           cachedSymtab = symtab;
        }
 
-       std::string generateDisassembly(Addr pc, const SymbolTable *symtab)
-       {
-           std::stringstream ss;
+       return *cachedDisassembly;
+    }
+
+    std::string
+    Branch::generateDisassembly(Addr pc, const SymbolTable *symtab)
+    {
+       std::stringstream ss;
 
-           ccprintf(ss, "%-10s ", mnemonic);
+       ccprintf(ss, "%-10s ", mnemonic);
+
+       // There's only one register arg (RA), but it could be
+       // either a source (the condition for conditional
+       // branches) or a destination (the link reg for
+       // unconditional branches)
+       if (_numSrcRegs > 0) {
+           printReg(ss, _srcRegIdx[0]);
+           ss << ",";
+       }
+       else if (_numDestRegs > 0) {
+           printReg(ss, _destRegIdx[0]);
+           ss << ",";
+       }
 
 #ifdef SS_COMPATIBLE_DISASSEMBLY
-           if (_numDestRegs == 0) {
-               printReg(ss, 31);
-               ss << ",";
-           }
+       if (_numSrcRegs == 0 && _numDestRegs == 0) {
+           printReg(ss, 31);
+           ss << ",";
+       }
 #endif
 
-           if (_numDestRegs > 0) {
-               printReg(ss, _destRegIdx[0]);
-               ss << ",";
-           }
+       Addr target = pc + 4 + disp;
 
-           ccprintf(ss, "(r%d)", RB);
+       std::string str;
+       if (symtab && symtab->findSymbol(target, str))
+           ss << str;
+       else 
+           ccprintf(ss, "0x%x", target);
 
-           return ss.str();
+       return ss.str();
+    }
+
+    std::string
+    Jump::generateDisassembly(Addr pc, const SymbolTable *symtab)
+    {
+       std::stringstream ss;
+
+       ccprintf(ss, "%-10s ", mnemonic);
+
+#ifdef SS_COMPATIBLE_DISASSEMBLY
+       if (_numDestRegs == 0) {
+           printReg(ss, 31);
+           ss << ",";
        }
-    };
+#endif
+
+       if (_numDestRegs > 0) {
+           printReg(ss, _destRegIdx[0]);
+           ss << ",";
+       }
+
+       ccprintf(ss, "(r%d)", RB);
+
+       return ss.str();
+    }
 }};
 
 def template JumpOrBranchDecode {{
@@ -1204,44 +1293,56 @@ def format CondBranch(code) {{
     code = 'bool cond;\n' + code + '\nif (cond) NPC = NPC + disp;\n';
     iop = InstObjParams(name, Name, 'Branch', CodeBlock(code),
                        ('IsDirectControl', 'IsCondControl'))
-    return iop.subst('BasicDeclare', 'BasicDecode', 'BasicExecute')
+    header_output = BasicDeclare.subst(iop)
+    decoder_output = BasicConstructor.subst(iop)
+    decode_block = BasicDecode.subst(iop)
+    exec_output = BasicExecute.subst(iop)
 }};
 
 let {{
-global UncondCtrlBase
 def UncondCtrlBase(name, Name, base_class, npc_expr, flags):
     # Declare basic control transfer w/o link (i.e. link reg is R31)
     nolink_code = 'NPC = %s;\n' % npc_expr
     nolink_iop = InstObjParams(name, Name, base_class,
                                CodeBlock(nolink_code), flags)
-    (decls, exec_code) = nolink_iop.subst('BasicDeclare', 'BasicExecute')
+    header_output = BasicDeclare.subst(nolink_iop)
+    decoder_output = BasicConstructor.subst(nolink_iop)
+    exec_output = BasicExecute.subst(nolink_iop)
 
     # Generate declaration of '*AndLink' version, append to decls
     link_code = 'Ra = NPC & ~3;\n' + nolink_code
     link_iop = InstObjParams(name, Name + 'AndLink', base_class,
                              CodeBlock(link_code), flags)
-    (link_decls, link_exec_code) = \
-       link_iop.subst('BasicDeclare', 'BasicExecute')
-    decls += link_decls
-    exec_code += link_exec_code
+    header_output += BasicDeclare.subst(link_iop)
+    decoder_output += BasicConstructor.subst(link_iop)
+    exec_output += BasicExecute.subst(link_iop)
 
     # need to use link_iop for the decode template since it is expecting
     # the shorter version of class_name (w/o "AndLink")
-    return (decls, nolink_iop.subst('JumpOrBranchDecode'), exec_code)
+
+    return (header_output, decoder_output,
+            JumpOrBranchDecode.subst(nolink_iop), exec_output)
 }};
 
 def format UncondBranch(*flags) {{
     flags += ('IsUncondControl', 'IsDirectControl')
-    return UncondCtrlBase(name, Name, 'Branch', 'NPC + disp', flags) 
+    (header_output, decoder_output, decode_block, exec_output) = \
+        UncondCtrlBase(name, Name, 'Branch', 'NPC + disp', flags)
 }};
 
 def format Jump(*flags) {{
     flags += ('IsUncondControl', 'IsIndirectControl')
-    return UncondCtrlBase(name, Name, 'Jump', '(Rb & ~3) | (NPC & 1)', flags) 
+    (header_output, decoder_output, decode_block, exec_output) = \
+        UncondCtrlBase(name, Name, 'Jump', '(Rb & ~3) | (NPC & 1)', flags)
 }};
 
 
-declare {{
+////////////////////////////////////////////////////////////////////
+//
+// PAL calls
+//
+
+output header {{
     /**
      * Base class for emulated call_pal calls (used only in
      * non-full-system mode).
@@ -1257,23 +1358,31 @@ declare {{
        {
        }
 
-       std::string generateDisassembly(Addr pc, const SymbolTable *symtab)
-       {
+       std::string generateDisassembly(Addr pc, const SymbolTable *symtab);
+    };
+}};
+
+output decoder {{
+    std::string
+    EmulatedCallPal::generateDisassembly(Addr pc, const SymbolTable *symtab)
+    {
 #ifdef SS_COMPATIBLE_DISASSEMBLY
-           return csprintf("%s %s", "call_pal", mnemonic);
+       return csprintf("%s %s", "call_pal", mnemonic);
 #else
-           return csprintf("%-10s %s", "call_pal", mnemonic);
+       return csprintf("%-10s %s", "call_pal", mnemonic);
 #endif
-       }
-    };
+    }
 }};
 
 def format EmulatedCallPal(code) {{
     iop = InstObjParams(name, Name, 'EmulatedCallPal', CodeBlock(code))
-    return iop.subst('BasicDeclare', 'BasicDecode', 'BasicExecute')
+    header_output = BasicDeclare.subst(iop)
+    decoder_output = BasicConstructor.subst(iop)
+    decode_block = BasicDecode.subst(iop)
+    exec_output = BasicExecute.subst(iop)
 }};
 
-declare {{
+output header {{
     /**
      * Base class for full-system-mode call_pal instructions.
      * Probably could turn this into a leaf class and get rid of the
@@ -1289,106 +1398,130 @@ declare {{
 
        /// Constructor.
        CallPalBase(const char *mnem, MachInst _machInst,
-                   OpClass __opClass)
-           : AlphaStaticInst(mnem, _machInst, __opClass),
-             palFunc(PALFUNC)
-       {
-           // From the 21164 HRM (paraphrased):
-           // Bit 7 of the function code (mask 0x80) indicates
-           // whether the call is privileged (bit 7 == 0) or
-           // unprivileged (bit 7 == 1).  The privileged call table
-           // starts at 0x2000, the unprivielged call table starts at
-           // 0x3000.  Bits 5-0 (mask 0x3f) are used to calculate the
-           // offset.
-           const int palPrivMask = 0x80;
-           const int palOffsetMask = 0x3f;
-
-           // Pal call is invalid unless all other bits are 0
-           palValid = ((machInst & ~(palPrivMask | palOffsetMask)) == 0);
-           palPriv = ((machInst & palPrivMask) == 0);
-           int shortPalFunc = (machInst & palOffsetMask);
-           // Add 1 to base to set pal-mode bit
-           palOffset = (palPriv ? 0x2001 : 0x3001) + (shortPalFunc << 6);
-       }
-
-       std::string generateDisassembly(Addr pc, const SymbolTable *symtab)
-       {
-           return csprintf("%-10s %#x", "call_pal", palFunc);
-       }
+                   OpClass __opClass);
+
+       std::string generateDisassembly(Addr pc, const SymbolTable *symtab);
     };
 }};
 
+output decoder {{
+    inline
+    CallPalBase::CallPalBase(const char *mnem, MachInst _machInst,
+                            OpClass __opClass)
+       : AlphaStaticInst(mnem, _machInst, __opClass),
+       palFunc(PALFUNC)
+    {
+       // From the 21164 HRM (paraphrased):
+       // Bit 7 of the function code (mask 0x80) indicates
+       // whether the call is privileged (bit 7 == 0) or
+       // unprivileged (bit 7 == 1).  The privileged call table
+       // starts at 0x2000, the unprivielged call table starts at
+       // 0x3000.  Bits 5-0 (mask 0x3f) are used to calculate the
+       // offset.
+       const int palPrivMask = 0x80;
+       const int palOffsetMask = 0x3f;
+
+       // Pal call is invalid unless all other bits are 0
+       palValid = ((machInst & ~(palPrivMask | palOffsetMask)) == 0);
+       palPriv = ((machInst & palPrivMask) == 0);
+       int shortPalFunc = (machInst & palOffsetMask);
+       // Add 1 to base to set pal-mode bit
+       palOffset = (palPriv ? 0x2001 : 0x3001) + (shortPalFunc << 6);
+    }
+
+    std::string
+    CallPalBase::generateDisassembly(Addr pc, const SymbolTable *symtab)
+    {
+       return csprintf("%-10s %#x", "call_pal", palFunc);
+    }
+}};
 
 def format CallPal(code) {{
     iop = InstObjParams(name, Name, 'CallPalBase', CodeBlock(code))
-    return iop.subst('BasicDeclare', 'BasicDecode', 'BasicExecute')
+    header_output = BasicDeclare.subst(iop)
+    decoder_output = BasicConstructor.subst(iop)
+    decode_block = BasicDecode.subst(iop)
+    exec_output = BasicExecute.subst(iop)
 }};
 
+////////////////////////////////////////////////////////////////////
 //
 // hw_ld, hw_st
 //
-declare {{
+
+output header {{
     /**
      * Base class for hw_ld and hw_st.
      */
-    class HwLoadStore : public AlphaStaticInst
+    class HwLoadStore : public Memory
     {
       protected:
 
        /// Displacement for EA calculation (signed).
        int16_t disp;
-       /// Memory request flags.  See mem_req_base.hh.
-       unsigned memAccessFlags;
 
        /// Constructor
-       HwLoadStore(const char *mnem, MachInst _machInst, OpClass __opClass)
-           : AlphaStaticInst(mnem, _machInst, __opClass), disp(HW_LDST_DISP)
-       {
-           memAccessFlags = 0;
-           if (HW_LDST_PHYS) memAccessFlags |= PHYSICAL;
-           if (HW_LDST_ALT)  memAccessFlags |= ALTMODE;
-           if (HW_LDST_VPTE) memAccessFlags |= VPTE;
-           if (HW_LDST_LOCK) memAccessFlags |= LOCKED;
-       }
+       HwLoadStore(const char *mnem, MachInst _machInst, OpClass __opClass,
+                   StaticInstPtr<AlphaISA> _eaCompPtr,
+                   StaticInstPtr<AlphaISA> _memAccPtr);
 
-       std::string generateDisassembly(Addr pc, const SymbolTable *symtab)
-       {
+       std::string generateDisassembly(Addr pc, const SymbolTable *symtab);
+    };
+}};
+
+
+output decoder {{
+    inline
+    HwLoadStore::HwLoadStore(const char *mnem, MachInst _machInst,
+                            OpClass __opClass,
+                            StaticInstPtr<AlphaISA> _eaCompPtr,
+                            StaticInstPtr<AlphaISA> _memAccPtr)
+       : Memory(mnem, _machInst, __opClass, _eaCompPtr, _memAccPtr),
+       disp(HW_LDST_DISP)
+    {
+       memAccessFlags = 0;
+       if (HW_LDST_PHYS) memAccessFlags |= PHYSICAL;
+       if (HW_LDST_ALT)  memAccessFlags |= ALTMODE;
+       if (HW_LDST_VPTE) memAccessFlags |= VPTE;
+       if (HW_LDST_LOCK) memAccessFlags |= LOCKED;
+    }
+
+    std::string
+    HwLoadStore::generateDisassembly(Addr pc, const SymbolTable *symtab)
+    {
 #ifdef SS_COMPATIBLE_DISASSEMBLY
-           return csprintf("%-10s r%d,%d(r%d)", mnemonic, RA, disp, RB);
+       return csprintf("%-10s r%d,%d(r%d)", mnemonic, RA, disp, RB);
 #else
-           // HW_LDST_LOCK and HW_LDST_COND are the same bit.
-           const char *lock_str =
-               (HW_LDST_LOCK) ? (flags[IsLoad] ? ",LOCK" : ",COND") : "";
-
-           return csprintf("%-10s r%d,%d(r%d)%s%s%s%s%s",
-                           mnemonic, RA, disp, RB,
-                           HW_LDST_PHYS ? ",PHYS" : "",
-                           HW_LDST_ALT ? ",ALT" : "",
-                           HW_LDST_QUAD ? ",QUAD" : "",
-                           HW_LDST_VPTE ? ",VPTE" : "",
-                           lock_str);
+       // HW_LDST_LOCK and HW_LDST_COND are the same bit.
+       const char *lock_str =
+           (HW_LDST_LOCK) ? (flags[IsLoad] ? ",LOCK" : ",COND") : "";
+
+       return csprintf("%-10s r%d,%d(r%d)%s%s%s%s%s",
+                       mnemonic, RA, disp, RB,
+                       HW_LDST_PHYS ? ",PHYS" : "",
+                       HW_LDST_ALT ? ",ALT" : "",
+                       HW_LDST_QUAD ? ",QUAD" : "",
+                       HW_LDST_VPTE ? ",VPTE" : "",
+                       lock_str);
 #endif
-       }
-    };
+    }
 }};
 
-
 def format HwLoadStore(ea_code, memacc_code, class_ext, *flags) {{
-    return LoadStoreBase(name, Name + class_ext, ea_code, memacc_code,
-                         flags = flags,
-                        base_class = 'HwLoadStore')
+    (header_output, decoder_output, decode_block, exec_output) = \
+        LoadStoreBase(name, Name + class_ext, ea_code, memacc_code,
+                     flags = flags, base_class = 'HwLoadStore')
 }};
 
 
 def format HwStoreCond(ea_code, memacc_code, postacc_code, class_ext, *flags) {{
-    return LoadStoreBase(name, Name + class_ext,
-                        ea_code, memacc_code, postacc_code,
-                         flags = flags,
-                        base_class = 'HwLoadStore')
+    (header_output, decoder_output, decode_block, exec_output) = \
+        LoadStoreBase(name, Name + class_ext, ea_code, memacc_code,
+                     postacc_code, flags = flags, base_class = 'HwLoadStore')
 }};
 
 
-declare {{
+output header {{
     /**
      * Base class for hw_mfpr and hw_mtpr.
      */
@@ -1405,28 +1538,42 @@ declare {{
        {
        }
 
-       std::string generateDisassembly(Addr pc, const SymbolTable *symtab)
-       {
-           if (_numSrcRegs > 0) {
-               // must be mtpr
-               return csprintf("%-10s r%d,IPR(%#x)",
-                               mnemonic, RA, ipr_index);
-           }
-           else {
-               // must be mfpr
-               return csprintf("%-10s IPR(%#x),r%d",
-                               mnemonic, ipr_index, RA);
-           }
-       }
+       std::string generateDisassembly(Addr pc, const SymbolTable *symtab);
     };
 }};
 
+output decoder {{
+    std::string
+    HwMoveIPR::generateDisassembly(Addr pc, const SymbolTable *symtab)
+    {
+       if (_numSrcRegs > 0) {
+           // must be mtpr
+           return csprintf("%-10s r%d,IPR(%#x)",
+                           mnemonic, RA, ipr_index);
+       }
+       else {
+           // must be mfpr
+           return csprintf("%-10s IPR(%#x),r%d",
+                           mnemonic, ipr_index, RA);
+       }
+    }
+}};
+
 def format HwMoveIPR(code) {{
     iop = InstObjParams(name, Name, 'HwMoveIPR', CodeBlock(code))
-    return iop.subst('BasicDeclare', 'BasicDecode', 'BasicExecute')
+    header_output = BasicDeclare.subst(iop)
+    decoder_output = BasicConstructor.subst(iop)
+    decode_block = BasicDecode.subst(iop)
+    exec_output = BasicExecute.subst(iop)
 }};
 
-declare {{
+
+////////////////////////////////////////////////////////////////////
+//
+// Unimplemented instructions
+//
+
+output header {{
     /**
      * Static instruction class for unimplemented instructions that
      * cause simulator termination.  Note that these are recognized
@@ -1443,29 +1590,9 @@ declare {{
        {
        }
 
-       Fault execute(SimpleCPUExecContext *xc,
-                     Trace::InstRecord *traceData)
-       {
-           panic("attempt to execute unimplemented instruction '%s' "
-                 "(inst 0x%08x, opcode 0x%x)", mnemonic, machInst, OPCODE);
-           return Unimplemented_Opcode_Fault;
-       }
-
-       Fault execute(FullCPUExecContext *xc,
-                     Trace::InstRecord *traceData)
-       {
-           // don't panic if this is a misspeculated instruction
-           if (!xc->misspeculating())
-               panic("attempt to execute unimplemented instruction '%s' "
-                     "(inst 0x%08x, opcode 0x%x)",
-                     mnemonic, machInst, OPCODE);
-           return Unimplemented_Opcode_Fault;
-       }
+       %(BasicExecDeclare)s
 
-       std::string generateDisassembly(Addr pc, const SymbolTable *symtab)
-       {
-           return csprintf("%-10s (unimplemented)", mnemonic);
-       }
+       std::string generateDisassembly(Addr pc, const SymbolTable *symtab);
     };
 
     /**
@@ -1490,39 +1617,56 @@ declare {{
        {
        }
 
-       Fault execute(SimpleCPUExecContext *xc,
-                     Trace::InstRecord *traceData)
-       {
-           if (!warned) {
-               warn("instruction '%s' unimplemented\n", mnemonic);
-               warned = true;
-           }
-
-           return No_Fault;
-       }
+       %(BasicExecDeclare)s
 
-       Fault execute(FullCPUExecContext *xc,
-                     Trace::InstRecord *traceData)
-       {
-           if (!xc->misspeculating() && !warned) {
-               warn("instruction '%s' unimplemented\n", mnemonic);
-               warned = true;
-           }
+       std::string generateDisassembly(Addr pc, const SymbolTable *symtab);
+    };
+}};
 
-           return No_Fault;
-       }
+output decoder {{
+    std::string
+    FailUnimplemented::generateDisassembly(Addr pc, const SymbolTable *symtab)
+    {
+       return csprintf("%-10s (unimplemented)", mnemonic);
+    }
 
-       std::string generateDisassembly(Addr pc, const SymbolTable *symtab)
-       {
+    std::string
+    WarnUnimplemented::generateDisassembly(Addr pc, const SymbolTable *symtab)
+    {
 #ifdef SS_COMPATIBLE_DISASSEMBLY
-           return csprintf("%-10s", mnemonic);
+       return csprintf("%-10s", mnemonic);
 #else
-           return csprintf("%-10s (unimplemented)", mnemonic);
+       return csprintf("%-10s (unimplemented)", mnemonic);
 #endif
-       }
-    };
+    }
 }};
 
+output exec {{
+    Fault
+    FailUnimplemented::execute(%(CPU_exec_context)s *xc,
+                              Trace::InstRecord *traceData)
+    {
+       if (!xc->misspeculating())
+           panic("attempt to execute unimplemented instruction '%s' "
+                 "(inst 0x%08x, opcode 0x%x)", mnemonic, machInst, OPCODE);
+       return Unimplemented_Opcode_Fault;
+    }
+
+    Fault
+    WarnUnimplemented::execute(%(CPU_exec_context)s *xc,
+                              Trace::InstRecord *traceData)
+    {
+       if (!xc->misspeculating())
+           if (!warned) {
+               warn("instruction '%s' unimplemented\n", mnemonic);
+               warned = true;
+           }
+
+       return No_Fault;
+    }
+}};
+
+
 def template WarnUnimplDeclare {{
     /**
      * Static instruction class for "%(mnemonic)s".
@@ -1541,15 +1685,16 @@ def template WarnUnimplDeclare {{
 
 def format FailUnimpl() {{
     iop = InstObjParams(name, 'FailUnimplemented')
-    return ('', iop.subst('BasicDecodeWithMnemonic'), '')
+    decode_block = BasicDecodeWithMnemonic.subst(iop)
 }};
 
 def format WarnUnimpl() {{
     iop = InstObjParams(name, Name, 'WarnUnimplemented')
-    return iop.subst('WarnUnimplDeclare', 'BasicDecode') + ['']
+    header_output = WarnUnimplDeclare.subst(iop)
+    decode_block = BasicDecode.subst(iop)
 }};
 
-declare {{
+output header {{
     /**
      * Static instruction class for unknown (illegal) instructions.
      * These cause simulator termination if they are executed in a
@@ -1564,37 +1709,47 @@ declare {{
        {
        }
 
-       Fault execute(SimpleCPUExecContext *xc,
-                     Trace::InstRecord *traceData)
-       {
-           panic("attempt to execute unknown instruction "
-                 "(inst 0x%08x, opcode 0x%x)", machInst, OPCODE);
-           return Unimplemented_Opcode_Fault;
-       }
+       %(BasicExecDeclare)s
 
-       Fault execute(FullCPUExecContext *xc,
-                     Trace::InstRecord *traceData)
-       {
-           // don't panic if this is a misspeculated instruction
-           if (!xc->misspeculating())
-               panic("attempt to execute unknown instruction "
-                     "(inst 0x%08x, opcode 0x%x)", machInst, OPCODE);
-           return Unimplemented_Opcode_Fault;
-       }
-
-       std::string generateDisassembly(Addr pc, const SymbolTable *symtab)
-       {
-           return csprintf("%-10s (inst 0x%x, opcode 0x%x)",
-                           "unknown", machInst, OPCODE);
-       }
+       std::string generateDisassembly(Addr pc, const SymbolTable *symtab);
     };
 }};
 
+////////////////////////////////////////////////////////////////////
+//
+// Unknown instructions
+//
+
+output decoder {{
+    std::string
+    Unknown::generateDisassembly(Addr pc, const SymbolTable *symtab)
+    {
+       return csprintf("%-10s (inst 0x%x, opcode 0x%x)",
+                       "unknown", machInst, OPCODE);
+    }
+}};
+
+output exec {{
+    Fault
+    Unknown::execute(%(CPU_exec_context)s *xc, Trace::InstRecord *traceData)
+    {
+       if (!xc->misspeculating())
+           panic("attempt to execute unknown instruction "
+                 "(inst 0x%08x, opcode 0x%x)", machInst, OPCODE);
+       return Unimplemented_Opcode_Fault;
+    }
+}};
+
 def format Unknown() {{
-    return ('', 'return new Unknown(machInst);\n', '')
+    decode_block = 'return new Unknown(machInst);\n'
 }};
 
-declare {{
+////////////////////////////////////////////////////////////////////
+//
+// Utility functions for execute methods
+//
+
+output exec {{
 
     /// Return opa + opb, summing carry into third arg.
     inline uint64_t
@@ -1608,7 +1763,7 @@ declare {{
 
     /// Multiply two 64-bit values (opa * opb), returning the 128-bit
     /// product in res_hi and res_lo.
-    void
+    inline void
     mul128(uint64_t opa, uint64_t opb, uint64_t &res_hi, uint64_t &res_lo)
     {
        // do a 64x64 --> 128 multiply using four 32x32 --> 64 multiplies
@@ -1678,6 +1833,11 @@ declare {{
     }
 }};
 
+////////////////////////////////////////////////////////////////////
+//
+// The actual decoder specification
+//
+
 decode OPCODE default Unknown::unknown() {
 
     format LoadAddress {
index 0ee9e2e2d9577006295131e692e0206d7a21bd88..621720709623246e2f6cece3d8d9026ae33c99d9 100755 (executable)
@@ -63,8 +63,9 @@ import yacc
 # using the same regexp as generic IDs, but distinguished in the
 # t_ID() function.  The PLY documentation suggests this approach.
 reserved = (
-    'BITFIELD', 'DECLARE', 'DECODE', 'DEFAULT', 'DEF', 'FORMAT',
-    'LET', 'NAMESPACE', 'SIGNED', 'TEMPLATE'
+    'BITFIELD', 'DECODE', 'DECODER', 'DEFAULT', 'DEF', 'EXEC', 'FORMAT',
+    'HEADER', 'LET', 'NAMESPACE', 'OPERAND_TYPES', 'OPERANDS',
+    'OUTPUT', 'SIGNED', 'TEMPLATE'
     )
 
 # List of tokens.  The lex module requires this.
@@ -195,14 +196,6 @@ lex.lex()
 # (by assigning to t[0]).
 #####################################################################
 
-# Not sure why, but we get a handful of shift/reduce conflicts on DECLARE.
-# By default these get resolved as shifts, which is correct, but
-# warnings are printed.  Explicitly marking DECLARE as right-associative
-# suppresses the warnings.
-precedence = (
-    ('right', 'DECLARE'),
-    )
-
 # The LHS of the first grammar rule is used as the start symbol
 # (in this case, 'specification').  Note that this rule enforces
 # that there will be exactly one namespace declaration, with 0 or more
@@ -210,163 +203,123 @@ precedence = (
 # the namespace decl will be outside the namespace; those after
 # will be inside.  The decoder function is always inside the namespace.
 def p_specification(t):
-    'specification : opt_defs_and_declares name_decl opt_defs_and_declares decode_block'
-    global_decls1 = t[1]
+    'specification : opt_defs_and_outputs name_decl opt_defs_and_outputs decode_block'
+    global_code = t[1]
     isa_name = t[2]
     namespace = isa_name + "Inst"
-    global_decls2 = t[3]
-    (inst_decls, decode_code, exec_code) = t[4]
-    decode_code = indent(decode_code)
-    # grab the last three path components of isa_desc_filename
-    filename = '/'.join(isa_desc_filename.split('/')[-3:])
-    # if the isa_desc file defines a 'rcs_id' string,
-    # echo that into the output too
-    try:
-        local_rcs_id = rcs_id
-        # strip $s out of ID so it doesn't get re-substituted
-        local_rcs_id = re.sub(r'\$', '', local_rcs_id)
-    except NameError:
-        local_rcs_id = 'Id: no RCS id found'
-    output = open(decoder_filename, 'w')
-    # split string to keep rcs from substituting this file's RCS id in
-    print >> output, '/* $Id' + '''$ */
-
-/*
- * 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!!!
- *
- * It was automatically generated from this ISA description:
- *  Filename: %(filename)s
- *    RCS %(local_rcs_id)s
- */
-
-#include "base/bitfield.hh"    // required for bitfield support
-
-
-/////////////////////////////////////
-// Global defs (outside namespace) //
-/////////////////////////////////////
-
-%(global_decls1)s
-
-/**
- * Namespace for %(isa_name)s static instruction objects.
- */
-namespace %(namespace)s
-{
-
-/////////////////////////////////////
-// Global defs  (within namespace) //
-/////////////////////////////////////
-
-%(global_decls2)s
-
-////////////////////////////////////
-// Declares from inst definitions //
-////////////////////////////////////
-
-%(inst_decls)s
-
-%(exec_code)s
-
-} // namespace %(namespace)s
-
-//////////////////////
-// Decoder function //
-//////////////////////
-
+    # wrap the decode block as a function definition
+    t[4].wrap_decode_block('''
 StaticInstPtr<%(isa_name)s>
 %(isa_name)s::decodeInst(%(isa_name)s::MachInst machInst)
 {
     using namespace %(namespace)s;
-%(decode_code)s
-} // decodeInst
-''' % vars()
-    output.close()
+''' % vars(), '}')
+    # both the latter output blocks and the decode block are in the namespace
+    namespace_code = t[3] + t[4]
+    # pass it all back to the caller of yacc.parse()
+    t[0] = (isa_name, namespace, global_code, namespace_code)
 
 # ISA name declaration looks like "namespace <foo>;"
 def p_name_decl(t):
     'name_decl : NAMESPACE ID SEMI'
     t[0] = t[2]
 
-# 'opt_defs_and_declares' is a possibly empty sequence of
-# defs and/or declares.
-def p_opt_defs_and_declares_0(t):
-    'opt_defs_and_declares : empty'
-    t[0] = ''
+# 'opt_defs_and_outputs' is a possibly empty sequence of
+# def and/or output statements.
+def p_opt_defs_and_outputs_0(t):
+    'opt_defs_and_outputs : empty'
+    t[0] = GenCode()
 
-def p_opt_defs_and_declares_1(t):
-    'opt_defs_and_declares : defs_and_declares'
+def p_opt_defs_and_outputs_1(t):
+    'opt_defs_and_outputs : defs_and_outputs'
     t[0] = t[1]
 
-def p_defs_and_declares_0(t):
-    'defs_and_declares : def_or_declare'
+def p_defs_and_outputs_0(t):
+    'defs_and_outputs : def_or_output'
     t[0] = t[1]
 
-def p_defs_and_declares_1(t):
-    'defs_and_declares : defs_and_declares def_or_declare'
+def p_defs_and_outputs_1(t):
+    'defs_and_outputs : defs_and_outputs def_or_output'
     t[0] = t[1] + t[2]
 
-# The list of possible definition/declaration statements.
-def p_def_or_declare(t):
-    '''def_or_declare : def_format
-                      | def_bitfield
-                      | def_template
-                      | global_declare
-                      | global_let
-                      | cpp_directive'''
+# The list of possible definition/output statements.
+def p_def_or_output(t):
+    '''def_or_output : def_format
+                     | def_bitfield
+                     | def_template
+                     | def_operand_types
+                     | def_operands
+                     | output_header
+                     | output_decoder
+                     | output_exec
+                     | global_let'''
     t[0] = t[1]
 
-# preprocessor directives are copied directly to the output.
-def p_cpp_directive(t):
-    '''cpp_directive : CPPDIRECTIVE'''
-    t[0] = t[1]
-
-# Global declares 'declare {{...}}' (C++ code blocks) are copied
-# directly to the output.
-def p_global_declare(t):
-    'global_declare : DECLARE CODELIT SEMI'
-    t[0] = substBitOps(t[2])
+# Output blocks 'output <foo> {{...}}' (C++ code blocks) are copied
+# directly to the appropriate output section.
+
+# 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)
+    # protects cpu-specific symbols too
+    s = protect_cpu_symbols(s)
+    return substBitOps(s % templateMap)
+
+def p_output_header(t):
+    'output_header : OUTPUT HEADER CODELIT SEMI'
+    t[0] = GenCode(header_output = process_output(t[3]))
+
+def p_output_decoder(t):
+    'output_decoder : OUTPUT DECODER CODELIT SEMI'
+    t[0] = GenCode(decoder_output = process_output(t[3]))
+
+def p_output_exec(t):
+    'output_exec : OUTPUT EXEC CODELIT SEMI'
+    t[0] = GenCode(exec_output = process_output(t[3]))
 
 # global let blocks 'let {{...}}' (Python code blocks) are executed
-# directly when seen.  These are typically used to initialize global
-# Python variables used in later format definitions.
+# directly when seen.  Note that these execute in a special variable
+# context 'exportContext' to prevent the code from polluting this
+# script's namespace.
 def p_global_let(t):
     'global_let : LET CODELIT SEMI'
+    updateExportContext()
+    try:
+        exec fixPythonIndentation(t[2]) in exportContext
+    except Exception, exc:
+        error(t.lineno(1),
+              'error: %s in global let block "%s".' % (exc, t[2]))
+    t[0] = GenCode() # contributes nothing to the output C++ file
+
+# Define the mapping from operand type extensions to C++ types and bit
+# 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(fixPythonIndentation(t[2]))
-    except:
-        error_bt(t.lineno(1), 'error in global let block "%s".' % t[2])
-    t[0] = '' # contributes nothing to the output C++ file
+        exec s
+    except Exception, exc:
+        error(t.lineno(1),
+              'error: %s in def operand_types block "%s".' % (exc, t[3]))
+    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.
+def p_def_operands(t):
+    'def_operands : DEF OPERANDS CODELIT SEMI'
+    s = 'global operandTraitsMap; operandTraitsMap = {' + t[3] + '}'
+    try:
+        exec s
+    except Exception, exc:
+        error(t.lineno(1),
+              'error: %s in def operands block "%s".' % (exc, t[3]))
+    defineDerivedOperandVars()
+    t[0] = GenCode() # contributes nothing to the output C++ file
 
 # A bitfield definition looks like:
 # 'def [signed] bitfield <ID> [<first>:<last>]'
@@ -376,7 +329,8 @@ def p_def_bitfield_0(t):
     expr = 'bits(machInst, %2d, %2d)' % (t[6], t[8])
     if (t[2] == 'signed'):
         expr = 'sext<%d>(%s)' % (t[6] - t[8] + 1, expr)
-    t[0] = '#undef %s\n#define %s\t%s\n' % (t[4], t[4], expr)
+    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 single bit: 'def [signed] bitfield <ID> [<bit>]'
 def p_def_bitfield_1(t):
@@ -384,7 +338,8 @@ def p_def_bitfield_1(t):
     expr = 'bits(machInst, %2d, %2d)' % (t[6], t[6])
     if (t[2] == 'signed'):
         expr = 'sext<%d>(%s)' % (1, expr)
-    t[0] = '#undef %s\n#define %s\t%s\n' % (t[4], t[4], expr)
+    hash_define = '#undef %s\n#define %s\t%s\n' % (t[4], t[4], expr)
+    t[0] = GenCode(header_output = hash_define)
 
 def p_opt_signed_0(t):
     'opt_signed : SIGNED'
@@ -399,8 +354,8 @@ templateMap = {}
 
 def p_def_template(t):
     'def_template : DEF TEMPLATE ID CODELIT SEMI'
-    templateMap[t[3]] = t[4]
-    t[0] = ''
+    templateMap[t[3]] = Template(t[4])
+    t[0] = GenCode()
 
 # An instruction format definition looks like
 # "def format <fmt>(<params>) {{...}};"
@@ -408,12 +363,7 @@ 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))
-    # insert a comment into the output to note that the def was processed
-    t[0] = '''
-//
-// parser: format %s defined
-//
-''' % id
+    t[0] = GenCode()
 
 # The formal parameter list for an instruction format is a possibly
 # empty list of comma-separated parameters.
@@ -453,19 +403,13 @@ def p_param_1(t):
 def p_decode_block(t):
     'decode_block : DECODE ID opt_default LBRACE decode_stmt_list RBRACE'
     default_defaults = defaultStack.pop()
-    (decls, decode_code, exec_code, has_default) = t[5]
+    codeObj = t[5]
     # use the "default defaults" only if there was no explicit
     # default statement in decode_stmt_list
-    if not has_default:
-        (default_decls, default_decode, default_exec) = default_defaults
-        decls += default_decls
-        decode_code += default_decode
-        exec_code += default_exec
-    t[0] = (decls,  '''
-switch (%s) {
-%s
-}
-''' % (t[2], indent(decode_code)), exec_code)
+    if not codeObj.has_decode_default:
+        codeObj += default_defaults
+    codeObj.wrap_decode_block('switch (%s) {\n' % t[2], '}\n')
+    t[0] = codeObj
 
 # The opt_default statement serves only to push the "default defaults"
 # onto defaultStack.  This value will be used by nested decode blocks,
@@ -481,8 +425,9 @@ def p_opt_default_0(t):
 def p_opt_default_1(t):
     'opt_default : DEFAULT inst'
     # push the new default
-    (decls, decode_code, exec_code) = t[2]
-    defaultStack.push((decls, '\ndefault:\n%sbreak;' % decode_code, exec_code))
+    codeObj = t[2]
+    codeObj.wrap_decode_block('\ndefault:\n', 'break;\n')
+    defaultStack.push(codeObj)
     # no meaningful value returned
     t[0] = None
 
@@ -492,12 +437,9 @@ def p_decode_stmt_list_0(t):
 
 def p_decode_stmt_list_1(t):
     'decode_stmt_list : decode_stmt decode_stmt_list'
-    (decls1, decode_code1, exec_code1, has_default1) = t[1]
-    (decls2, decode_code2, exec_code2, has_default2) = t[2]
-    if (has_default1 and has_default2):
+    if (t[1].has_decode_default and t[2].has_decode_default):
         error(t.lineno(1), 'Two default cases in decode block')
-    t[0] = (decls1 + '\n' + decls2, decode_code1 + '\n' + decode_code2,
-            exec_code1 + '\n' + exec_code2, has_default1 or has_default2)
+    t[0] = t[1] + t[2]
 
 #
 # Decode statement rules
@@ -510,7 +452,7 @@ def p_decode_stmt_list_1(t):
 
 
 # Preprocessor directives found in a decode statement list are passed
-# through to the output, replicated to both the declaration and decode
+# through to the output, replicated to all of the output code
 # streams.  This works well for ifdefs, so we can ifdef out both the
 # declarations and the decode cases generated by an instruction
 # definition.  Handling them as part of the grammar makes it easy to
@@ -518,7 +460,7 @@ def p_decode_stmt_list_1(t):
 # the other statements.
 def p_decode_stmt_cpp(t):
     'decode_stmt : CPPDIRECTIVE'
-    t[0] = (t[1], t[1], t[1], 0)
+    t[0] = GenCode(t[1], t[1], t[1], t[1])
 
 # A format block 'format <foo> { ... }' sets the default instruction
 # format used to handle instruction definitions inside the block.
@@ -547,29 +489,31 @@ def p_push_format_id(t):
 # specified constant, do a nested decode on some other field.
 def p_decode_stmt_decode(t):
     'decode_stmt : case_label COLON decode_block'
-    (label, is_default) = t[1]
-    (decls, decode_code, exec_code) = t[3]
+    label = t[1]
+    codeObj = t[3]
     # just wrap the decoding code from the block as a case in the
     # outer switch statement.
-    t[0] = (decls, '\n%s:\n%s' % (label, indent(decode_code)),
-            exec_code, is_default)
+    codeObj.wrap_decode_block('\n%s:\n' % label)
+    codeObj.has_decode_default = (label == 'default')
+    t[0] = codeObj
 
 # Instruction definition (finally!).
 def p_decode_stmt_inst(t):
     'decode_stmt : case_label COLON inst SEMI'
-    (label, is_default) = t[1]
-    (decls, decode_code, exec_code) = t[3]
-    t[0] = (decls, '\n%s:%sbreak;' % (label, indent(decode_code)),
-            exec_code, is_default)
+    label = t[1]
+    codeObj = t[3]
+    codeObj.wrap_decode_block('\n%s:' % label, 'break;\n')
+    codeObj.has_decode_default = (label == 'default')
+    t[0] = codeObj
 
 # The case label is either a list of one or more constants or 'default'
 def p_case_label_0(t):
     'case_label : intlit_list'
-    t[0] = (': '.join(map(lambda a: 'case %#x' % a, t[1])), 0)
+    t[0] = ': '.join(map(lambda a: 'case %#x' % a, t[1]))
 
 def p_case_label_1(t):
     'case_label : DEFAULT'
-    t[0] = ('default', 1)
+    t[0] = 'default'
 
 #
 # The constant list for a decode case label must be non-empty, but may have
@@ -591,13 +535,13 @@ 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()
-    (decls, decode_code, exec_code) = \
-            currentFormat.defineInst(t[1], t[3], t.lineno(1))
+    codeObj = currentFormat.defineInst(t[1], t[3], t.lineno(1))
     args = ','.join(map(str, t[3]))
     args = re.sub('(?m)^', '//', args)
     args = re.sub('^//', '', args)
-    comment = '// %s::%s(%s)\n' % (currentFormat.id, t[1], args)
-    t[0] = (comment + decls, comment + decode_code, comment + exec_code)
+    comment = '\n// %s::%s(%s)\n' % (currentFormat.id, t[1], args)
+    codeObj.prepend_all(comment)
+    t[0] = codeObj
 
 # Define an instruction using an explicitly specified format:
 # "<fmt>::<mnemonic>(<args>)"
@@ -607,10 +551,10 @@ def p_inst_1(t):
         format = formatMap[t[1]]
     except KeyError:
         error(t.lineno(1), 'instruction format "%s" not defined.' % t[1])
-    (decls, decode_code, exec_code) = \
-            format.defineInst(t[3], t[5], t.lineno(1))
-    comment = '// %s::%s(%s)\n' % (t[1], t[3], t[5])
-    t[0] = (comment + decls, comment + decode_code, comment + exec_code)
+    codeObj = format.defineInst(t[3], t[5], t.lineno(1))
+    comment = '\n// %s::%s(%s)\n' % (t[1], t[3], t[5])
+    codeObj.prepend_all(comment)
+    t[0] = codeObj
 
 def p_arg_list_0(t):
     'arg_list : empty'
@@ -652,6 +596,133 @@ def p_error(t):
 # Now build the parser.
 yacc.yacc()
 
+
+#####################################################################
+#
+#                           Support Classes
+#
+#####################################################################
+
+################
+# 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('SimpleCPU', 'simple_cpu_exec.cc',
+         '#include "cpu/simple_cpu/simple_cpu.hh"',
+         { 'CPU_exec_context': 'SimpleCPU' })
+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
+# refs substituted for that model.
+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:
+        result[cpu.name] = t % cpu.strings
+    return result
+
+# *If* the template has CPU-specific references, return a single
+# string containing a copy of the template for each CPU model with the
+# corresponding values substituted in.  If the template has no
+# CPU-specific references, it is returned unmodified.
+def expand_cpu_symbols_to_string(template):
+    if template.find('%(CPU_') != -1:
+        return reduce(lambda x,y: x+y,
+                      expand_cpu_symbols_to_dict(template).values())
+    else:
+        return template
+
+# Protect CPU-specific references by doubling the corresponding '%'s
+# (in preparation for substituting a different set of references into
+# the template).
+def protect_cpu_symbols(template):
+    return re.sub(r'%(?=\(CPU_)', '%%', template)
+
+###############
+# GenCode class
+#
+# The GenCode class encapsulates generated code destined for various
+# output files.  The header_output and decoder_output attributes are
+# strings containing code destined for decoder.hh and decoder.cc
+# respectively.  The decode_block attribute contains code to be
+# incorporated in the decode function itself (that will also end up in
+# decoder.cc).  The exec_output attribute is a dictionary with a key
+# for each CPU model name; the value associated with a particular key
+# is the string of code for that CPU model's exec.cc file.  The
+# has_decode_default attribute is used in the decode block to allow
+# explicit default clauses to override default default clauses.
+
+class GenCode:
+    # Constructor.  At this point we substitute out all CPU-specific
+    # symbols.  For the exec output, these go into the per-model
+    # dictionary.  For all other output types they get collapsed into
+    # a single string.
+    def __init__(self,
+                 header_output = '', decoder_output = '', exec_output = '',
+                 decode_block = '', has_decode_default = False):
+        self.header_output = expand_cpu_symbols_to_string(header_output)
+        self.decoder_output = expand_cpu_symbols_to_string(decoder_output)
+        if isinstance(exec_output, dict):
+            self.exec_output = exec_output
+        elif isinstance(exec_output, str):
+            # If the exec_output arg is a single string, we replicate
+            # it for each of the CPU models, substituting and
+            # %(CPU_foo)s params appropriately.
+            self.exec_output = expand_cpu_symbols_to_dict(exec_output)
+        self.decode_block = expand_cpu_symbols_to_string(decode_block)
+        self.has_decode_default = has_decode_default
+
+    # Override '+' operator: generate a new GenCode object that
+    # concatenates all the individual strings in the operands.
+    def __add__(self, other):
+        exec_output = {}
+        for cpu in CpuModel.list:
+            n = cpu.name
+            exec_output[n] = self.exec_output[n] + other.exec_output[n]
+        return GenCode(self.header_output + other.header_output,
+                       self.decoder_output + other.decoder_output,
+                       exec_output,
+                       self.decode_block + other.decode_block,
+                       self.has_decode_default or other.has_decode_default)
+
+    # Prepend a string (typically a comment) to all the strings.
+    def prepend_all(self, pre):
+        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:
+            self.exec_output[cpu.name] = pre + self.exec_output[cpu.name]
+
+    # Wrap the decode block in a pair of strings (e.g., 'case foo:'
+    # and 'break;').  Used to build the big nested switch statement.
+    def wrap_decode_block(self, pre, post = ''):
+        self.decode_block = pre + indent(self.decode_block) + post
+
 ################
 # Format object.
 #
@@ -664,24 +735,31 @@ class Format:
         # constructor: just save away arguments
         self.id = id
         self.params = params
-        # strip blank lines from code (ones at the end are troublesome)
-        code = re.sub(r'(?m)^\s*$', '', code);
-        if code == '':
-            code = '    pass\n'
+        label = 'def format ' + id
+        self.user_code = compile(fixPythonIndentation(code), label, 'exec')
         param_list = string.join(params, ", ")
-        f = 'def defInst(name, Name, ' + param_list + '):\n' + code
-        c = compile(f, 'def format ' + id, 'exec')
-        exec(c)
+        f = '''def defInst(_code, _context, %s):
+                my_locals = vars().copy()
+                exec _code in _context, my_locals
+                return my_locals\n''' % param_list
+        c = compile(f, label + ' wrapper', 'exec')
+        exec c
         self.func = defInst
 
     def defineInst(self, name, args, lineno):
-        # automatically provide a capitalized version of mnemonic
-        Name = string.capitalize(name)
+        context = {}
+        updateExportContext()
+        context.update(exportContext)
+        context.update({ 'name': name, 'Name': string.capitalize(name) })
         try:
-            retval = self.func(name, Name, *args)
-        except:
-            error_bt(lineno, 'error defining "%s".' % name)
-        return retval
+            vars = self.func(self.user_code, context, *args)
+        except Exception, exc:
+            error(lineno, 'error defining "%s": %s.' % (name, exc))
+        for k in vars.keys():
+            if k not in ('header_output', 'decoder_output',
+                         'exec_output', 'decode_block'):
+                del vars[k]
+        return GenCode(**vars)
 
 # Special null format to catch an implicit-format instruction
 # definition outside of any format block.
@@ -766,13 +844,13 @@ def fixPythonIndentation(s):
 # Error handler.  Just call exit.  Output formatted to work under
 # Emacs compile-mode.
 def error(lineno, string):
-    sys.exit("%s:%d: %s" % (isa_desc_filename, lineno, string))
+    sys.exit("%s:%d: %s" % (input_filename, lineno, string))
 
 # Like error(), but include a Python stack backtrace (for processing
 # Python exceptions).
 def error_bt(lineno, string):
     traceback.print_exc()
-    print >> sys.stderr, "%s:%d: %s" % (isa_desc_filename, lineno, string)
+    print >> sys.stderr, "%s:%d: %s" % (input_filename, lineno, string)
     sys.exit(1)
 
 
@@ -817,6 +895,37 @@ def substBitOps(code):
     return code
 
 
+####################
+# Template objects.
+#
+# Template objects are format strings that allow substitution from
+# the attribute spaces of other objects (e.g. InstObjParams instances).
+
+class Template:
+    def __init__(self, t):
+        self.template = t
+
+    def subst(self, d):
+        # 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):
+            myDict.update(d)
+        # if the argument is an object, we use its attribute map.
+        elif hasattr(d, '__dict__'):
+            myDict.update(d.__dict__)
+        else:
+            raise TypeError, "Template.subst() arg must be or have dictionary"
+        # CPU-model-specific substitutions are handled later (in GenCode).
+        return protect_cpu_symbols(self.template) % myDict
+
+    # Convert to string.  This handles the case when a template with a
+    # CPU-specific term gets interpolated into another template or into
+    # an output block.
+    def __str__(self):
+        return expand_cpu_symbols_to_string(self.template)
+
 #####################################################################
 #
 #                             Code Parser
@@ -1111,6 +1220,22 @@ class NPCOperandTraits(OperandTraits):
         return 'xc->setNextPC(%s);\n' % op_desc.munged_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
@@ -1385,10 +1510,6 @@ class InstObjParams:
         self.mnemonic = mnem
         self.class_name = class_name
         self.base_class = base_class
-        self.exec_func_declarations = '''
-    Fault execute(SimpleCPUExecContext *, Trace::InstRecord *);
-    Fault execute(FullCPUExecContext *, Trace::InstRecord *);
-'''
         if code_block:
             for code_attr in code_block.__dict__.keys():
                 setattr(self, code_attr, getattr(code_block, code_attr))
@@ -1419,48 +1540,125 @@ class InstObjParams:
         else:
             self.fp_enable_check = ''
 
-    def _subst(self, template):
-        try:
-            return template % self.__dict__
-        except KeyError, key:
-            raise KeyError, 'InstObjParams.subst: no definition for %s' % key
-
-    def subst(self, *args):
-        result = []
-        for t in args:
-            try: template = templateMap[t]
-            except KeyError:
-                error(0, 'InstObjParams::subst: undefined template "%s"' % t)
-            if template.find('%(cpu_model)') != -1:
-                tmp = ''
-                for cpu_model in ('SimpleCPUExecContext', 'FullCPUExecContext'):
-                    self.cpu_model = cpu_model
-                    tmp += self._subst(template)
-                result.append(tmp)
-            else:
-                result.append(self._subst(template))
-        if len(args) == 1:
-            result = result[0]
-        return result
+#######################
+#
+# Output file template
+#
+
+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!!!
+ *
+ * It was automatically generated from the ISA description in %(filename)s
+ */
+
+%(includes)s
+
+%(global_output)s
+
+namespace %(namespace)s {
+
+%(namespace_output)s
+
+} // 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
+# after minor changes.
+def update_if_needed(file, contents):
+    update = False
+    if os.access(file, os.R_OK):
+        f = open(file, 'r')
+        old_contents = f.read()
+        f.close()
+        if contents != old_contents:
+            print 'Updating', file
+            os.remove(file) # in case it's write-protected
+            update = True
+        else:
+            print 'File', file, 'is unchanged'
+    else:
+        print 'Generating', file
+        update = True
+    if update:
+        f = open(file, 'w')
+        f.write(contents)
+        f.close()
 
 #
 # Read in and parse the ISA description.
 #
-def parse_isa_desc(isa_desc_file, decoder_file):
-    # Arguments are the name of the ISA description (input) file and
-    # the name of the C++ decoder (output) file.
-    global isa_desc_filename, decoder_filename
-    isa_desc_filename = isa_desc_file
-    decoder_filename = decoder_file
+def parse_isa_desc(isa_desc_file, output_dir, include_path):
+    # set a global var for the input filename... used in error messages
+    global input_filename
+    input_filename = isa_desc_file
 
     # Suck the ISA description file in.
-    input = open(isa_desc_filename)
+    input = open(isa_desc_file)
     isa_desc = input.read()
     input.close()
 
     # Parse it.
-    yacc.parse(isa_desc)
+    (isa_name, namespace, global_code, namespace_code) = yacc.parse(isa_desc)
+
+    # grab the last three path components of isa_desc_file to put in
+    # the output
+    filename = '/'.join(isa_desc_file.split('/')[-3:])
+
+    # generate decoder.hh
+    includes = '#include "base/bitfield.hh" // for bitfield support'
+    global_output = global_code.header_output
+    namespace_output = namespace_code.header_output
+    update_if_needed(output_dir + '/decoder.hh', file_template % vars())
+
+    # generate decoder.cc
+    includes = '#include "%s/decoder.hh"' % include_path
+    global_output = global_code.decoder_output
+    namespace_output = namespace_code.decoder_output
+    namespace_output += 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
+        includes += cpu.includes
+        global_output = global_code.exec_output[cpu.name]
+        namespace_output = namespace_code.exec_output[cpu.name]
+        update_if_needed(output_dir + '/' + cpu.filename,
+                          file_template % vars())
 
 # Called as script: get args from command line.
 if __name__ == '__main__':
-    parse_isa_desc(sys.argv[1], sys.argv[2])
+    parse_isa_desc(sys.argv[1], sys.argv[2], sys.argv[3])
index 07d6cb0c961a840f904ba7e1d94305701f69ad97..a04dcd057a69468946c7c9d0623e796ac332bad9 100644 (file)
@@ -34,7 +34,7 @@
 #include "base/loader/symtab.hh"
 #include "cpu/pc_event.hh"
 #include "base/statistics.hh"
-
+#include "cpu/exec_context.hh"
 
 // forward declarations
 #ifdef FULL_SYSTEM
@@ -46,6 +46,11 @@ class PhysicalMemory;
 
 class RemoteGDB;
 class GDBListener;
+
+#else
+
+class Process;
+
 #endif // FULL_SYSTEM
 
 class MemInterface;
@@ -305,6 +310,4 @@ class SimpleCPU : public BaseCPU
     ExecContext *xcBase() { return xc; }
 };
 
-typedef SimpleCPU SimpleCPUExecContext;
-
 #endif // __SIMPLE_CPU_HH__
index 57208f8e6f1c0d0b99b93a2b6570ab70ed92c862..1065fa3d487c2cfc747a5f6d3e86612f734ef238 100644 (file)
@@ -42,9 +42,7 @@
 // forward declarations
 class ExecContext;
 class DynInst;
-typedef DynInst FullCPUExecContext;
 class SimpleCPU;
-typedef SimpleCPU SimpleCPUExecContext;
 class SymbolTable;
 
 namespace Trace {
@@ -249,7 +247,8 @@ class StaticInst : public StaticInstBase
      * obtain the dependence info (numSrcRegs and srcRegIdx[]) for
      * just the EA computation.
      */
-    virtual StaticInstPtr<ISA> eaCompInst() { return nullStaticInstPtr; }
+    virtual const
+    StaticInstPtr<ISA> &eaCompInst() const { return nullStaticInstPtr; }
 
     /**
      * Memory references only: returns "fake" instruction representing
@@ -257,7 +256,8 @@ class StaticInst : public StaticInstBase
      * obtain the dependence info (numSrcRegs and srcRegIdx[]) for
      * just the memory access (not the EA computation).
      */
-    virtual StaticInstPtr<ISA> memAccInst() { return nullStaticInstPtr; }
+    virtual const
+    StaticInstPtr<ISA> &memAccInst() const { return nullStaticInstPtr; }
 
     /// The binary machine instruction.
     const MachInst machInst;
@@ -307,14 +307,12 @@ class StaticInst : public StaticInstBase
     /**
      * Execute this instruction under SimpleCPU model.
      */
-    virtual Fault execute(SimpleCPUExecContext *xc,
-                          Trace::InstRecord *traceData) = 0;
+    virtual Fault execute(SimpleCPU *xc, Trace::InstRecord *traceData) = 0;
 
     /**
      * Execute this instruction under detailed FullCPU model.
      */
-    virtual Fault execute(FullCPUExecContext *xc,
-                          Trace::InstRecord *traceData) = 0;
+    virtual Fault execute(DynInst *xc, Trace::InstRecord *traceData) = 0;
 
     /**
      * Return the target address for a PC-relative branch.