diff options
author | Steve Reinhardt <stever@eecs.umich.edu> | 2004-05-17 11:49:46 -0700 |
---|---|---|
committer | Steve Reinhardt <stever@eecs.umich.edu> | 2004-05-17 11:49:46 -0700 |
commit | 1d545281b96a6df358201c7b0e610bfaf9e8f213 (patch) | |
tree | 56f869110d789a8efd02a6470b0b74ce718cab68 /arch/alpha | |
parent | 32a8827b3ea49fe2c9cd25aa88d7bae2adc6d4e6 (diff) | |
download | gem5-1d545281b96a6df358201c7b0e610bfaf9e8f213.tar.xz |
Significant changes to ISA description to completely factor
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
Diffstat (limited to 'arch/alpha')
-rw-r--r-- | arch/alpha/isa_desc | 1392 |
1 files changed, 776 insertions, 616 deletions
diff --git a/arch/alpha/isa_desc b/arch/alpha/isa_desc index 9bbdac9b4..f964101df 100644 --- a/arch/alpha/isa_desc +++ b/arch/alpha/isa_desc @@ -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; - } + MemAcc(MachInst machInst); }; - /// 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; - } + %(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; - } + Addr branchTarget(Addr branchPC) const; - 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; - - 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 { |