diff options
author | Lisa Hsu <hsul@eecs.umich.edu> | 2004-05-18 01:40:03 -0400 |
---|---|---|
committer | Lisa Hsu <hsul@eecs.umich.edu> | 2004-05-18 01:40:03 -0400 |
commit | a0ccdf8aba8f71c8d66c03f5c6907d0a3c2e091f (patch) | |
tree | 71de26a0139e7db042c79989ae745377d98c3d23 | |
parent | 4d98ab1ca92c2d88d3ee13a7518acc36a6d5bf84 (diff) | |
parent | 02af86f7e813db27b12214ea377948f07f891b69 (diff) | |
download | gem5-a0ccdf8aba8f71c8d66c03f5c6907d0a3c2e091f.tar.xz |
merge m5 with linux for the event and binning lifting
--HG--
extra : convert_revision : 09d3678746c2e9a93a9982dc75d5e1ac309cb2fa
-rw-r--r-- | arch/alpha/ev5.cc | 10 | ||||
-rw-r--r-- | arch/alpha/isa_desc | 1409 | ||||
-rw-r--r-- | arch/alpha/pseudo_inst.cc | 19 | ||||
-rw-r--r-- | arch/alpha/pseudo_inst.hh | 3 | ||||
-rw-r--r-- | arch/alpha/vptr.hh | 113 | ||||
-rwxr-xr-x | arch/isa_parser.py | 678 | ||||
-rw-r--r-- | base/statistics.hh | 218 | ||||
-rw-r--r-- | base/stats/text.cc | 2 | ||||
-rw-r--r-- | cpu/base_cpu.cc | 7 | ||||
-rw-r--r-- | cpu/base_cpu.hh | 20 | ||||
-rw-r--r-- | cpu/simple_cpu/simple_cpu.cc | 7 | ||||
-rw-r--r-- | cpu/simple_cpu/simple_cpu.hh | 16 | ||||
-rw-r--r-- | cpu/static_inst.hh | 14 | ||||
-rw-r--r-- | kern/system_events.cc | 109 | ||||
-rw-r--r-- | kern/system_events.hh | 56 | ||||
-rw-r--r-- | kern/tru64/mbuf.hh | 4 | ||||
-rw-r--r-- | kern/tru64/tru64_events.cc | 82 | ||||
-rw-r--r-- | kern/tru64/tru64_events.hh | 22 | ||||
-rw-r--r-- | kern/tru64/tru64_system.cc | 69 | ||||
-rw-r--r-- | kern/tru64/tru64_system.hh | 13 | ||||
-rw-r--r-- | sim/debug.cc | 2 | ||||
-rw-r--r-- | sim/debug.hh | 4 | ||||
-rw-r--r-- | sim/stat_control.cc | 26 | ||||
-rw-r--r-- | sim/stats.hh | 6 | ||||
-rw-r--r-- | sim/system.cc | 79 | ||||
-rw-r--r-- | sim/system.hh | 22 | ||||
-rw-r--r-- | test/Makefile | 12 | ||||
-rw-r--r-- | test/stattest.cc | 10 |
28 files changed, 1826 insertions, 1206 deletions
diff --git a/arch/alpha/ev5.cc b/arch/alpha/ev5.cc index 9b3ac5fff..f037a34ac 100644 --- a/arch/alpha/ev5.cc +++ b/arch/alpha/ev5.cc @@ -1,7 +1,6 @@ /* $Id$ */ #include "targetarch/alpha_memory.hh" -#include "sim/annotation.hh" #ifdef DEBUG #include "sim/debug.hh" #endif @@ -126,8 +125,6 @@ ExecContext::ev5_trap(Fault fault) regs.pc = ipr[AlphaISA::IPR_PAL_BASE] + AlphaISA::fault_addr[fault]; regs.npc = regs.pc + sizeof(MachInst); - - Annotate::Ev5Trap(this, fault); } @@ -303,6 +300,7 @@ Fault ExecContext::setIpr(int idx, uint64_t val) { uint64_t *ipr = regs.ipr; + uint64_t old; if (misspeculating()) return No_Fault; @@ -355,9 +353,9 @@ ExecContext::setIpr(int idx, uint64_t val) case AlphaISA::IPR_PALtemp23: // write entire quad w/ no side-effect + old = ipr[idx]; ipr[idx] = val; - kernelStats.context(ipr[idx]); - Annotate::Context(this); + kernelStats.context(old, val); break; case AlphaISA::IPR_DTB_PTE: @@ -385,11 +383,9 @@ ExecContext::setIpr(int idx, uint64_t val) // only write least significant five bits - interrupt level ipr[idx] = val & 0x1f; kernelStats.swpipl(ipr[idx]); - Annotate::IPL(this, val & 0x1f); break; case AlphaISA::IPR_DTB_CM: - Annotate::ChangeMode(this, (val & 0x18) != 0); kernelStats.mode((val & 0x18) != 0); case AlphaISA::IPR_ICM: diff --git a/arch/alpha/isa_desc b/arch/alpha/isa_desc index 0d1e7138f..f964101df 100644 --- a/arch/alpha/isa_desc +++ b/arch/alpha/isa_desc @@ -1,40 +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/annotation.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>; @@ -93,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. @@ -184,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". @@ -233,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; @@ -262,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); }}; @@ -273,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. */ @@ -300,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). @@ -328,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; } @@ -349,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) }}; @@ -358,7 +396,7 @@ def format BasicOperateWithNopCheck(code, *opt_args) {{ // Integer operate instructions // -declare {{ +output header {{ /** * Base class for integer immediate instructions. */ @@ -374,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; } @@ -433,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) }}; @@ -463,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 @@ -525,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[] = { @@ -599,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) @@ -641,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) }}; @@ -652,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. */ @@ -660,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(). @@ -716,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 }; /** @@ -736,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) }}; @@ -767,11 +891,7 @@ def template LoadStoreDeclare {{ { public: /// Constructor - EAComp(MachInst machInst) - : EACompBase(machInst) - { - %(ea_constructor)s; - } + EAComp(MachInst machInst); }; /** @@ -781,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; @@ -843,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; @@ -948,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). @@ -984,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 @@ -1066,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); }; /** @@ -1101,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); + Addr branchTarget(Addr branchPC) const; - // 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); }; /** @@ -1163,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; + + std::string str; + if (symtab && symtab->findSymbol(target, str)) + ss << str; + else + ccprintf(ss, "0x%x", target); + + return ss.str(); + } + + std::string + Jump::generateDisassembly(Addr pc, const SymbolTable *symtab) + { + std::stringstream ss; - ccprintf(ss, "(r%d)", RB); + ccprintf(ss, "%-10s ", mnemonic); - return ss.str(); +#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 {{ @@ -1205,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). @@ -1258,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 @@ -1290,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. */ @@ -1406,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 @@ -1444,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); }; /** @@ -1491,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". @@ -1542,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 @@ -1565,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; - } - - 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; - } + %(BasicExecDeclare)s - 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 @@ -1609,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 @@ -1679,6 +1833,11 @@ declare {{ } }}; +//////////////////////////////////////////////////////////////////// +// +// The actual decoder specification +// + decode OPCODE default Unknown::unknown() { format LoadAddress { @@ -2297,8 +2456,6 @@ decode OPCODE default Unknown::unknown() { // on this PAL call (including maybe suppress it) dopal = xc->simPalCheck(palFunc); - Annotate::Callpal(xc->xcBase(), palFunc); - if (dopal) { AlphaISA::swap_palshadow(&xc->xcBase()->regs, true); xc->setIpr(AlphaISA::IPR_EXC_ADDR, NPC); @@ -2357,24 +2514,20 @@ decode OPCODE default Unknown::unknown() { // M5 special opcodes use the reserved 0x01 opcode space 0x01: decode M5FUNC { 0x00: arm({{ - if (!xc->misspeculating()) { - Annotate::ARM(xc->xcBase()); - xc->xcBase()->kernelStats.arm(); - } + if (!xc->misspeculating()) + AlphaPseudo::arm(xc->xcBase()); }}); 0x01: quiesce({{ if (!xc->misspeculating()) AlphaPseudo::quiesce(xc->xcBase()); }}); 0x10: ivlb({{ - if (!xc->misspeculating()) { - Annotate::BeginInterval(xc->xcBase()); - xc->xcBase()->kernelStats.ivlb(); - } + if (!xc->misspeculating()) + AlphaPseudo::ivlb(xc->xcBase()); }}, No_OpClass); 0x11: ivle({{ if (!xc->misspeculating()) - Annotate::EndInterval(xc->xcBase()); + AlphaPseudo::ivle(xc->xcBase()); }}, No_OpClass); 0x20: m5exit_old({{ if (!xc->misspeculating()) diff --git a/arch/alpha/pseudo_inst.cc b/arch/alpha/pseudo_inst.cc index 194dc6400..0a5c5b006 100644 --- a/arch/alpha/pseudo_inst.cc +++ b/arch/alpha/pseudo_inst.cc @@ -30,7 +30,6 @@ #include "arch/alpha/pseudo_inst.hh" #include "cpu/exec_context.hh" -#include "sim/annotation.hh" #include "sim/param.hh" #include "sim/serialize.hh" #include "sim/sim_exit.hh" @@ -47,17 +46,33 @@ namespace AlphaPseudo bool doQuiesce; void + arm(ExecContext *xc) + { + xc->kernelStats.arm(); + } + + void quiesce(ExecContext *xc) { if (!doQuiesce) return; - Annotate::QUIESCE(xc); xc->suspend(); xc->kernelStats.quiesce(); } void + ivlb(ExecContext *xc) + { + xc->kernelStats.ivlb(); + } + + void + ivle(ExecContext *xc) + { + } + + void m5exit_old(ExecContext *xc) { SimExit(curTick, "m5_exit_old instruction encountered"); diff --git a/arch/alpha/pseudo_inst.hh b/arch/alpha/pseudo_inst.hh index 85f432504..e5551a44b 100644 --- a/arch/alpha/pseudo_inst.hh +++ b/arch/alpha/pseudo_inst.hh @@ -37,7 +37,10 @@ namespace AlphaPseudo extern bool doCheckpointInsts; extern bool doQuiesce; + void arm(ExecContext *xc); void quiesce(ExecContext *xc); + void ivlb(ExecContext *xc); + void ivle(ExecContext *xc); void m5exit(ExecContext *xc); void m5exit_old(ExecContext *xc); void resetstats(ExecContext *xc); diff --git a/arch/alpha/vptr.hh b/arch/alpha/vptr.hh new file mode 100644 index 000000000..7f0b036a3 --- /dev/null +++ b/arch/alpha/vptr.hh @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __VPTR_HH__ +#define __VPTR_HH__ + +#include "arch/alpha/vtophys.hh" + +class ExecContext; + +template <class T> +class VPtr +{ + public: + typedef T Type; + + private: + ExecContext *xc; + Addr ptr; + + public: + ExecContext *GetXC() const { return xc; } + Addr GetPointer() const { return ptr; } + + public: + explicit VPtr(ExecContext *_xc, Addr p = 0) : xc(_xc), ptr(p) { } + template <class U> + VPtr(const VPtr<U> &vp) : xc(vp.GetXC()), ptr(vp.GetPointer()) {} + ~VPtr() {} + + bool operator!() const + { + return ptr == 0; + } + + VPtr<T> operator+(int offset) + { + VPtr<T> ptr(*this); + ptr += offset; + + return ptr; + } + + const VPtr<T> &operator+=(int offset) + { + ptr += offset; + assert((ptr & (ALPHA_PGBYTES - 1)) + sizeof(T) < ALPHA_PGBYTES); + + return *this; + } + + const VPtr<T> &operator=(Addr p) + { + assert((p & (ALPHA_PGBYTES - 1)) + sizeof(T) < ALPHA_PGBYTES); + ptr = p; + + return *this; + } + + template <class U> + const VPtr<T> &operator=(const VPtr<U> &vp) + { + xc = vp.GetXC(); + ptr = vp.GetPointer(); + + return *this; + } + + operator T *() + { + void *addr = vtomem(xc, ptr, sizeof(T)); + return (T *)addr; + } + + T *operator->() + { + void *addr = vtomem(xc, ptr, sizeof(T)); + return (T *)addr; + } + + T &operator*() + { + void *addr = vtomem(xc, ptr, sizeof(T)); + return *(T *)addr; + } +}; + +#endif // __VPTR_HH__ diff --git a/arch/isa_parser.py b/arch/isa_parser.py index 0ee9e2e2d..621720709 100755 --- a/arch/isa_parser.py +++ b/arch/isa_parser.py @@ -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]) diff --git a/base/statistics.hh b/base/statistics.hh index e7fc18d74..ee09cc622 100644 --- a/base/statistics.hh +++ b/base/statistics.hh @@ -139,11 +139,13 @@ struct StatData static bool less(StatData *stat1, StatData *stat2); }; -struct ScalarData : public StatData +class ScalarData : public StatData { + public: virtual Counter value() const = 0; virtual Result result() const = 0; virtual Result total() const = 0; + virtual void visit(Visit &visitor) { visitor.visit(*this); } }; template <class Stat> @@ -162,8 +164,6 @@ class ScalarStatData : public ScalarData virtual Result total() const { return s.total(); } virtual void reset() { s.reset(); } virtual bool zero() const { return s.zero(); } - - virtual void visit(Visit &visitor) { visitor.visit(*this); } }; struct VectorData : public StatData @@ -394,6 +394,16 @@ class Wrap : public Child return ptr; } + protected: + /** + * Copy constructor, copies are not allowed. + */ + Wrap(const Wrap &stat); + /** + * Can't copy stats. + */ + void operator=(const Wrap &); + public: Wrap() { @@ -726,16 +736,6 @@ class ScalarBase : public DataAccess return _bin->data(*_params); } - protected: - /** - * Copy constructor, copies are not allowed. - */ - ScalarBase(const ScalarBase &stat); - /** - * Can't copy stats. - */ - const ScalarBase &operator=(const ScalarBase &); - public: /** * Return the current value of this stat as its base type. @@ -822,6 +822,79 @@ class ScalarBase : public DataAccess }; +class ProxyData : public ScalarData +{ + public: + virtual void visit(Visit &visitor) { visitor.visit(*this); } + virtual bool binned() const { return false; } + virtual std::string str() const { return to_string(value()); } + virtual size_t size() const { return 1; } + virtual bool zero() const { return value() == 0; } + virtual bool check() const { return true; } + virtual void reset() { } +}; + +template <class T> +class ValueProxy : public ProxyData +{ + private: + T *scalar; + + public: + ValueProxy(T &val) : scalar(&val) {} + virtual Counter value() const { return *scalar; } + virtual Result result() const { return *scalar; } + virtual Result total() const { return *scalar; } +}; + +template <class T> +class FunctorProxy : public ProxyData +{ + private: + T *functor; + + public: + FunctorProxy(T &func) : functor(&func) {} + virtual Counter value() const { return (*functor)(); } + virtual Result result() const { return (*functor)(); } + virtual Result total() const { return (*functor)(); } +}; + +class ValueBase : public DataAccess +{ + private: + ProxyData *proxy; + + public: + ValueBase() : proxy(NULL) { } + ~ValueBase() { if (proxy) delete proxy; } + + template <class T> + void scalar(T &value) + { + proxy = new ValueProxy<T>(value); + setInit(); + } + + template <class T> + void functor(T &func) + { + proxy = new FunctorProxy<T>(func); + setInit(); + } + + Counter value() { return proxy->value(); } + Result result() const { return proxy->result(); } + Result total() const { return proxy->total(); }; + size_t size() const { return proxy->size(); } + + bool binned() const { return proxy->binned(); } + std::string str() const { return proxy->str(); } + bool zero() const { return proxy->zero(); } + bool check() const { return proxy != NULL; } + void reset() { } +}; + ////////////////////////////////////////////////////////////////////// // // Vector Statistics @@ -869,13 +942,6 @@ class VectorBase : public DataAccess return _bin->data(index, *_params); } - protected: - // Copying stats is not allowed - /** Copying stats isn't allowed. */ - VectorBase(const VectorBase &stat); - /** Copying stats isn't allowed. */ - const VectorBase &operator=(const VectorBase &); - public: void value(VCounter &vec) const { @@ -1127,11 +1193,6 @@ class Vector2dBase : public DataAccess return _bin->data(index, *_params); } - protected: - // Copying stats is not allowed - Vector2dBase(const Vector2dBase &stat); - const Vector2dBase &operator=(const Vector2dBase &); - public: Vector2dBase() {} @@ -1586,13 +1647,6 @@ class DistBase : public DataAccess return _bin->data(*_params); } - protected: - // Copying stats is not allowed - /** Copies are not allowed. */ - DistBase(const DistBase &stat); - /** Copies are not allowed. */ - const DistBase &operator=(const DistBase &); - public: DistBase() { } @@ -1659,11 +1713,6 @@ class VectorDistBase : public DataAccess return _bin->data(index, *_params); } - protected: - // Copying stats is not allowed - VectorDistBase(const VectorDistBase &stat); - const VectorDistBase &operator=(const VectorDistBase &); - public: VectorDistBase() {} @@ -1910,56 +1959,6 @@ class ConstNode : public Node virtual std::string str() const { return to_string(vresult[0]); } }; -template <class T> -class FunctorNode : public Node -{ - private: - T &functor; - mutable VResult vresult; - - public: - FunctorNode(T &f) : functor(f) { vresult.resize(1); } - const VResult &result() const - { - vresult[0] = (Result)functor(); - return vresult; - } - virtual Result total() const { return (Result)functor(); }; - - virtual size_t size() const { return 1; } - /** - * Return true if stat is binned. - *@return False since Functors aren't binned - */ - virtual bool binned() const { return false; } - virtual std::string str() const { return to_string(functor()); } -}; - -template <class T> -class ScalarNode : public Node -{ - private: - T &scalar; - mutable VResult vresult; - - public: - ScalarNode(T &s) : scalar(s) { vresult.resize(1); } - const VResult &result() const - { - vresult[0] = (Result)scalar; - return vresult; - } - virtual Result total() const { return (Result)scalar; }; - - virtual size_t size() const { return 1; } - /** - * Return true if stat is binned. - *@return False since Scalar's aren't binned - */ - virtual bool binned() const { return false; } - virtual std::string str() const { return to_string(scalar); } -}; - template <class Op> struct OpString; @@ -2219,6 +2218,30 @@ class Scalar void operator=(const U &v) { Base::operator=(v); } }; +class Value + : public Wrap<Value, + ValueBase, + ScalarStatData> +{ + public: + /** The base implementation. */ + typedef ValueBase Base; + + template <class T> + Value &scalar(T &value) + { + Base::scalar(value); + return *this; + } + + template <class T> + Value &functor(T &func) + { + Base::functor(func); + return *this; + } +}; + /** * A stat that calculates the per cycle average of a value. * @sa Stat, ScalarBase, AvgStor @@ -2698,6 +2721,13 @@ class Temp * Create a new ScalarStatNode. * @param s The ScalarStat to place in a node. */ + Temp(const Value &s) + : node(new ScalarStatNode(s.statData())) { } + + /** + * Create a new ScalarStatNode. + * @param s The ScalarStat to place in a node. + */ template <class Bin> Temp(const Average<Bin> &s) : node(new ScalarStatNode(s.statData())) { } @@ -2861,20 +2891,6 @@ constant(T val) return NodePtr(new ConstNode<T>(val)); } -template <typename T> -inline Temp -functor(T &val) -{ - return NodePtr(new FunctorNode<T>(val)); -} - -template <typename T> -inline Temp -scalar(T &val) -{ - return NodePtr(new ScalarNode<T>(val)); -} - inline Temp sum(Temp val) { diff --git a/base/stats/text.cc b/base/stats/text.cc index 0f43a1772..79a91e661 100644 --- a/base/stats/text.cc +++ b/base/stats/text.cc @@ -132,7 +132,7 @@ Text::output() for (i = bins().begin(); i != end; ++i) { MainBin *bin = *i; bin->activate(); - ccprintf(*stream,"---%s Bin------------\n", bin); + ccprintf(*stream,"---%s Bin------------\n", bin->name()); stat_list_t::const_iterator i, end = stats().end(); for (i = stats().begin(); i != end; ++i) (*i)->visit(*this); diff --git a/cpu/base_cpu.cc b/cpu/base_cpu.cc index c6cff814d..fe88891d6 100644 --- a/cpu/base_cpu.cc +++ b/cpu/base_cpu.cc @@ -130,6 +130,13 @@ BaseCPU::BaseCPU(const string &_name, int _number_of_threads, void BaseCPU::regStats() { + using namespace Statistics; + + numCycles + .name(name() + ".numCycles") + .desc("number of cpu cycles simulated") + ; + int size = execContexts.size(); if (size > 1) { for (int i = 0; i < size; ++i) { diff --git a/cpu/base_cpu.hh b/cpu/base_cpu.hh index 0041ecc99..0b4a38b0e 100644 --- a/cpu/base_cpu.hh +++ b/cpu/base_cpu.hh @@ -31,10 +31,10 @@ #include <vector> +#include "base/statistics.hh" #include "sim/eventq.hh" #include "sim/sim_object.hh" - -#include "targetarch/isa_traits.hh" // for Addr +#include "targetarch/isa_traits.hh" #ifdef FULL_SYSTEM class System; @@ -147,11 +147,27 @@ class BaseCPU : public SimObject */ virtual BranchPred *getBranchPred() { return NULL; }; + virtual Counter totalInstructions() const { return 0; } + private: static std::vector<BaseCPU *> cpuList; //!< Static global cpu list public: static int numSimulatedCPUs() { return cpuList.size(); } + static Counter numSimulatedInstructions() + { + Counter total = 0; + + int size = cpuList.size(); + for (int i = 0; i < size; ++i) + total += cpuList[i]->totalInstructions(); + + return total; + } + + public: + // Number of CPU cycles simulated + Statistics::Scalar<> numCycles; }; #endif // __BASE_CPU_HH__ diff --git a/cpu/simple_cpu/simple_cpu.cc b/cpu/simple_cpu/simple_cpu.cc index 065140883..617c91e68 100644 --- a/cpu/simple_cpu/simple_cpu.cc +++ b/cpu/simple_cpu/simple_cpu.cc @@ -50,7 +50,6 @@ #include "cpu/static_inst.hh" #include "mem/base_mem.hh" #include "mem/mem_interface.hh" -#include "sim/annotation.hh" #include "sim/builder.hh" #include "sim/debug.hh" #include "sim/host.hh" @@ -287,8 +286,6 @@ SimpleCPU::regStats() ; idleFraction = constant(1.0) - notIdleFraction; - numInsts = Statistics::scalar(numInst) - Statistics::scalar(startNumInst); - simInsts += numInsts; } void @@ -581,7 +578,6 @@ SimpleCPU::post_interrupt(int int_num, int index) if (xc->status() == ExecContext::Suspended) { DPRINTF(IPI,"Suspended Processor awoke\n"); xc->activate(); - Annotate::Resume(xc); } } #endif // FULL_SYSTEM @@ -590,6 +586,8 @@ SimpleCPU::post_interrupt(int int_num, int index) void SimpleCPU::tick() { + numCycles++; + traceData = NULL; Fault fault = No_Fault; @@ -697,6 +695,7 @@ SimpleCPU::tick() // keep an instruction count numInst++; + numInsts++; // check for instruction-count-based events comInstEventQueue[0]->serviceEvents(numInst); diff --git a/cpu/simple_cpu/simple_cpu.hh b/cpu/simple_cpu/simple_cpu.hh index 4977e6992..a04dcd057 100644 --- a/cpu/simple_cpu/simple_cpu.hh +++ b/cpu/simple_cpu/simple_cpu.hh @@ -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; @@ -204,7 +209,12 @@ class SimpleCPU : public BaseCPU // number of simulated instructions Counter numInst; Counter startNumInst; - Statistics::Formula numInsts; + Statistics::Scalar<> numInsts; + + virtual Counter totalInstructions() const + { + return numInst - startNumInst; + } // number of simulated memory references Statistics::Scalar<> numMemRefs; @@ -300,6 +310,4 @@ class SimpleCPU : public BaseCPU ExecContext *xcBase() { return xc; } }; -typedef SimpleCPU SimpleCPUExecContext; - #endif // __SIMPLE_CPU_HH__ diff --git a/cpu/static_inst.hh b/cpu/static_inst.hh index 57208f8e6..1065fa3d4 100644 --- a/cpu/static_inst.hh +++ b/cpu/static_inst.hh @@ -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. diff --git a/kern/system_events.cc b/kern/system_events.cc new file mode 100644 index 000000000..011dbce5f --- /dev/null +++ b/kern/system_events.cc @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "cpu/exec_context.hh" +#include "cpu/base_cpu.hh" +#include "cpu/full_cpu/bpred.hh" +#include "cpu/full_cpu/full_cpu.hh" +#include "kern/system_events.hh" +#include "sim/system.hh" +#include "sim/sw_context.hh" + +void +SkipFuncEvent::process(ExecContext *xc) +{ + Addr newpc = xc->regs.intRegFile[ReturnAddressReg]; + + DPRINTF(PCEvent, "skipping %s: pc=%x, newpc=%x\n", description, + xc->regs.pc, newpc); + + xc->regs.pc = newpc; + xc->regs.npc = xc->regs.pc + sizeof(MachInst); + + BranchPred *bp = xc->cpu->getBranchPred(); + if (bp != NULL) { + bp->popRAS(xc->thread_num); + } +} + + +FnEvent::FnEvent(PCEventQueue *q, const std::string & desc, System *system) + : PCEvent(q, desc), _name(desc) +{ + myBin = system->getBin(desc); + assert(myBin); +} + +void +FnEvent::process(ExecContext *xc) +{ + if (xc->misspeculating()) + return; + assert(xc->system->bin && "FnEvent must be in a binned system"); + SWContext *ctx = xc->swCtx; + DPRINTF(TCPIP, "%s: %s Event!!!\n", xc->system->name(), description); + + if (ctx && !ctx->callStack.empty()) { + DPRINTF(TCPIP, "already a callstack!\n"); + fnCall *last = ctx->callStack.top(); + + if (last->name == "idle_thread") + ctx->calls++; + + if (!xc->system->findCaller(myname(), "" ) && + !xc->system->findCaller(myname(), last->name)) { + + DPRINTF(TCPIP, "but can't find parent %s\n", last->name); + return; + } + ctx->calls--; + + //assert(!ctx->calls && "on a binned fn, calls should == 0 (but can happen in boot)"); + } else { + DPRINTF(TCPIP, "no callstack yet\n"); + if (!xc->system->findCaller(myname(), "")) { + DPRINTF(TCPIP, "not the right function, returning\n"); + return; + } + if (!ctx) { + DPRINTF(TCPIP, "creating new context for %s\n", myname()); + ctx = new SWContext; + xc->swCtx = ctx; + } + } + DPRINTF(TCPIP, "adding fn %s to context\n", myname()); + fnCall *call = new fnCall; + call->myBin = myBin; + call->name = myname(); + ctx->callStack.push(call); + myBin->activate(); + xc->system->fnCalls++; + DPRINTF(TCPIP, "fnCalls for %s is %d\n", description, + xc->system->fnCalls.value()); + xc->system->dumpState(xc); +} diff --git a/kern/system_events.hh b/kern/system_events.hh new file mode 100644 index 000000000..fdf2a06c9 --- /dev/null +++ b/kern/system_events.hh @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2003 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __SYSTEM_EVENTS_HH__ +#define __SYSTEM_EVENTS_HH__ + +#include "cpu/pc_event.hh" + +class System; + +class SkipFuncEvent : public PCEvent +{ + public: + SkipFuncEvent(PCEventQueue *q, const std::string &desc) + : PCEvent(q, desc) {} + virtual void process(ExecContext *xc); +}; + +class FnEvent : public PCEvent +{ + public: + FnEvent(PCEventQueue *q, const std::string &desc, System *system); + virtual void process(ExecContext *xc); + std::string myname() const { return _name; } + + private: + std::string _name; + Statistics::MainBin *myBin; +}; + +#endif // __SYSTEM_EVENTS_HH__ diff --git a/kern/tru64/mbuf.hh b/kern/tru64/mbuf.hh index bfee0b3fa..a386fa611 100644 --- a/kern/tru64/mbuf.hh +++ b/kern/tru64/mbuf.hh @@ -32,6 +32,8 @@ #include "sim/host.hh" #include "targetarch/isa_traits.hh" +namespace tru64 { + struct m_hdr { Addr mh_next; // 0x00 Addr mh_nextpkt; // 0x08 @@ -91,4 +93,6 @@ struct mbuf { #define m_pktdat M_dat.MH.MH_dat.MH_databuf #define m_dat M_dat.M_databuf +} + #endif // __MBUF_HH__ diff --git a/kern/tru64/tru64_events.cc b/kern/tru64/tru64_events.cc index 17a5e406a..89b808653 100644 --- a/kern/tru64/tru64_events.cc +++ b/kern/tru64/tru64_events.cc @@ -28,32 +28,14 @@ #include "cpu/exec_context.hh" #include "cpu/base_cpu.hh" -#include "cpu/full_cpu/bpred.hh" -#include "cpu/full_cpu/full_cpu.hh" +#include "kern/system_events.hh" +#include "kern/tru64/tru64_events.hh" #include "kern/tru64/dump_mbuf.hh" #include "kern/tru64/printf.hh" -#include "kern/tru64/tru64_events.hh" -#include "mem/functional_mem/memory_control.hh" #include "targetarch/arguments.hh" -#include "sim/system.hh" -#include "sim/sw_context.hh" - -void -SkipFuncEvent::process(ExecContext *xc) -{ - Addr newpc = xc->regs.intRegFile[ReturnAddressReg]; - - DPRINTF(PCEvent, "skipping %s: pc=%x, newpc=%x\n", description, - xc->regs.pc, newpc); - - xc->regs.pc = newpc; - xc->regs.npc = xc->regs.pc + sizeof(MachInst); +#include "mem/functional_mem/memory_control.hh" - BranchPred *bp = xc->cpu->getBranchPred(); - if (bp != NULL) { - bp->popRAS(xc->thread_num); - } -} +//void SkipFuncEvent::process(ExecContext *xc); void BadAddrEvent::process(ExecContext *xc) @@ -106,59 +88,3 @@ DumpMbufEvent::process(ExecContext *xc) tru64::DumpMbuf(args); } } - -FnEvent::FnEvent(PCEventQueue *q, const std::string & desc, System *system) - : PCEvent(q, desc), _name(desc) -{ - myBin = system->getBin(desc); - assert(myBin); -} - -void -FnEvent::process(ExecContext *xc) -{ - if (xc->misspeculating()) - return; - assert(xc->system->bin && "FnEvent must be in a binned system"); - SWContext *ctx = xc->swCtx; - DPRINTF(TCPIP, "%s: %s Event!!!\n", xc->system->name(), description); - - if (ctx && !ctx->callStack.empty()) { - DPRINTF(TCPIP, "already a callstack!\n"); - fnCall *last = ctx->callStack.top(); - - if (last->name == "idle_thread") - ctx->calls++; - - if (!xc->system->findCaller(myname(), "" ) && - !xc->system->findCaller(myname(), last->name)) { - - DPRINTF(TCPIP, "but can't find parent %s\n", last->name); - return; - } - ctx->calls--; - - //assert(!ctx->calls && "on a binned fn, calls should == 0 (but can happen in boot)"); - } else { - DPRINTF(TCPIP, "no callstack yet\n"); - if (!xc->system->findCaller(myname(), "")) { - DPRINTF(TCPIP, "not the right function, returning\n"); - return; - } - if (!ctx) { - DPRINTF(TCPIP, "creating new context for %s\n", myname()); - ctx = new SWContext; - xc->swCtx = ctx; - } - } - DPRINTF(TCPIP, "adding fn %s to context\n", myname()); - fnCall *call = new fnCall; - call->myBin = myBin; - call->name = myname(); - ctx->callStack.push(call); - myBin->activate(); - xc->system->fnCalls++; - DPRINTF(TCPIP, "fnCalls for %s is %d\n", description, - xc->system->fnCalls.value()); - xc->system->dumpState(xc); -} diff --git a/kern/tru64/tru64_events.hh b/kern/tru64/tru64_events.hh index 96e6a8b26..bcf33d686 100644 --- a/kern/tru64/tru64_events.hh +++ b/kern/tru64/tru64_events.hh @@ -32,19 +32,10 @@ #include <string> #include "cpu/pc_event.hh" +#include "kern/system_events.hh" class ExecContext; -class System; - -class SkipFuncEvent : public PCEvent -{ - public: - SkipFuncEvent(PCEventQueue *q, const std::string &desc) - : PCEvent(q, desc) {} - virtual void process(ExecContext *xc); -}; - class BadAddrEvent : public SkipFuncEvent { public: @@ -80,15 +71,4 @@ class DumpMbufEvent : public PCEvent virtual void process(ExecContext *xc); }; -class FnEvent : public PCEvent -{ - public: - FnEvent(PCEventQueue *q, const std::string &desc, System *system); - virtual void process(ExecContext *xc); - std::string myname() const { return _name; } - - private: - std::string _name; - Statistics::MainBin *myBin; -}; #endif // __TRU64_EVENTS_HH__ diff --git a/kern/tru64/tru64_system.cc b/kern/tru64/tru64_system.cc index 905ff5df6..ebd78c58b 100644 --- a/kern/tru64/tru64_system.cc +++ b/kern/tru64/tru64_system.cc @@ -35,6 +35,7 @@ #include "cpu/exec_context.hh" #include "kern/tru64/tru64_events.hh" #include "kern/tru64/tru64_system.hh" +#include "kern/system_events.hh" #include "mem/functional_mem/memory_control.hh" #include "mem/functional_mem/physical_memory.hh" #include "sim/builder.hh" @@ -48,7 +49,7 @@ Tru64System::Tru64System(const string _name, const uint64_t _init_param, const string &kernel_path, const string &console_path, const string &palcode, const string &boot_osflags, const bool _bin, const vector<string> &binned_fns) - : System(_name, _init_param, _memCtrl, _physmem, _bin), + : System(_name, _init_param, _memCtrl, _physmem, _bin, binned_fns), bin(_bin), binned_fns(binned_fns) { kernelSymtab = new SymbolTable; @@ -176,33 +177,14 @@ Tru64System::Tru64System(const string _name, const uint64_t _init_param, // BINNING STUFF if (bin == true) { int end = binned_fns.size(); - assert(!(end & 1)); - - Statistics::MainBin *Bin; Addr address = 0; - fnEvents.resize(end>>1); - for (int i = 0; i < end; i +=2) { - Bin = new Statistics::MainBin(binned_fns[i]); - fnBins.insert(make_pair(binned_fns[i], Bin)); - - fnEvents[(i>>1)] = new FnEvent(&pcEventQueue, binned_fns[i], this); if (kernelSymtab->findAddress(binned_fns[i], address)) fnEvents[(i>>1)]->schedule(address); else panic("could not find kernel symbol %s\n", binned_fns[i]); - - if (binned_fns[i+1] == "null") - populateMap(binned_fns[i], ""); - else - populateMap(binned_fns[i], binned_fns[i+1]); } - - fnCalls - .name(name() + ":fnCalls") - .desc("all fn calls being tracked") - ; } // } @@ -226,14 +208,6 @@ Tru64System::~Tru64System() delete debugPrintfEvent; delete debugPrintfrEvent; delete dumpMbufEvent; - - if (bin == true) { - int end = fnEvents.size(); - for (int i = 0; i < end; ++i) { - delete fnEvents[i]; - } - fnEvents.clear(); - } } int @@ -274,45 +248,6 @@ Tru64System::breakpoint() return remoteGDB[0]->trap(ALPHA_KENTRY_INT); } -void -Tru64System::populateMap(std::string callee, std::string caller) -{ - multimap<const string, string>::const_iterator i; - i = callerMap.insert(make_pair(callee, caller)); - assert(i != callerMap.end() && "should not fail populating callerMap"); -} - -bool -Tru64System::findCaller(std::string callee, std::string caller) const -{ - typedef multimap<const std::string, std::string>::const_iterator iter; - pair<iter, iter> range; - - range = callerMap.equal_range(callee); - for (iter i = range.first; i != range.second; ++i) { - if ((*i).second == caller) - return true; - } - return false; -} - -void -Tru64System::dumpState(ExecContext *xc) const -{ - if (xc->swCtx) { - stack<fnCall *> copy(xc->swCtx->callStack); - if (copy.empty()) - return; - DPRINTF(TCPIP, "xc->swCtx, size: %d:\n", copy.size()); - fnCall *top; - DPRINTF(TCPIP, "|| call : %d\n",xc->swCtx->calls); - for (top = copy.top(); !copy.empty(); copy.pop() ) { - top = copy.top(); - DPRINTF(TCPIP, "|| %13s : %s \n", top->name, top->myBin->name()); - } - } -} - BEGIN_DECLARE_SIM_OBJECT_PARAMS(Tru64System) Param<bool> bin; diff --git a/kern/tru64/tru64_system.hh b/kern/tru64/tru64_system.hh index 34569664d..144febbf9 100644 --- a/kern/tru64/tru64_system.hh +++ b/kern/tru64/tru64_system.hh @@ -67,8 +67,6 @@ class Tru64System : public System DebugPrintfEvent *debugPrintfrEvent; DumpMbufEvent *dumpMbufEvent; - std::vector<FnEvent *> fnEvents; - private: Addr kernelStart; @@ -104,17 +102,6 @@ class Tru64System : public System static void Printf(AlphaArguments args); static void DumpMbuf(AlphaArguments args); - - - // Lisa's binning stuff - private: - std::multimap<const std::string, std::string> callerMap; - void populateMap(std::string caller, std::string callee); - - public: - bool findCaller(std::string callee, std::string caller) const; - void dumpState(ExecContext *xc) const; - // }; #endif // __TRU64_SYSTEM_HH__ diff --git a/sim/debug.cc b/sim/debug.cc index 09c604a95..b73ab4245 100644 --- a/sim/debug.cc +++ b/sim/debug.cc @@ -40,11 +40,13 @@ using namespace std; +#ifdef DEBUG void debug_break() { kill(getpid(), SIGTRAP); } +#endif // // Debug event: place a breakpoint on the process function and diff --git a/sim/debug.hh b/sim/debug.hh index eb0be772e..a4f8b8702 100644 --- a/sim/debug.hh +++ b/sim/debug.hh @@ -29,6 +29,10 @@ #ifndef __DEBUG_HH__ #define __DEBUG_HH__ +#ifdef DEBUG void debug_break(); +#else +inline void debug_break() { } +#endif #endif // __DEBUG_HH__ diff --git a/sim/stat_control.cc b/sim/stat_control.cc index d6d7e2c91..c7d2fdd5b 100644 --- a/sim/stat_control.cc +++ b/sim/stat_control.cc @@ -39,6 +39,7 @@ #include "base/str.hh" #include "base/time.hh" #include "base/stats/output.hh" +#include "cpu/base_cpu.hh" #include "sim/eventq.hh" #include "sim/sim_object.hh" #include "sim/stat_control.hh" @@ -47,13 +48,14 @@ using namespace std; Statistics::Formula hostInstRate; -Statistics::Formula hostMemory; -Statistics::Formula hostSeconds; Statistics::Formula hostTickRate; +Statistics::Value hostMemory; +Statistics::Value hostSeconds; -Statistics::Formula simInsts; +Statistics::Value simTicks; +Statistics::Value simInsts; +Statistics::Value simFreq; Statistics::Formula simSeconds; -Statistics::Formula simTicks; namespace Statistics { @@ -84,6 +86,7 @@ void InitSimStats() { simInsts + .functor(BaseCPU::numSimulatedInstructions) .name("sim_insts") .desc("Number of instructions simulated") .precision(0) @@ -95,7 +98,14 @@ InitSimStats() .desc("Number of seconds simulated") ; + simFreq + .scalar(ticksPerSecond) + .name("sim_freq") + .desc("Frequency of simulated ticks") + ; + simTicks + .scalar(curTick) .name("sim_ticks") .desc("Number of ticks simulated") ; @@ -108,12 +118,14 @@ InitSimStats() ; hostMemory + .functor(memUsage) .name("host_mem_usage") .desc("Number of bytes of host memory used") .prereq(hostMemory) ; hostSeconds + .functor(statElapsedTime) .name("host_seconds") .desc("Real time elapsed on the host") .precision(2) @@ -125,11 +137,7 @@ InitSimStats() .precision(0) ; - simInsts = constant(0); - simTicks = scalar(curTick) - scalar(startTick); - simSeconds = simTicks / scalar(ticksPerSecond); - hostMemory = functor(memUsage); - hostSeconds = functor(statElapsedTime); + simSeconds = simTicks / simFreq; hostInstRate = simInsts / hostSeconds; hostTickRate = simTicks / hostSeconds; diff --git a/sim/stats.hh b/sim/stats.hh index b736850e7..c5e791cfb 100644 --- a/sim/stats.hh +++ b/sim/stats.hh @@ -31,11 +31,7 @@ #include "base/statistics.hh" -extern Statistics::Formula simTicks; extern Statistics::Formula simSeconds; -extern Statistics::Formula simInsts; -extern Statistics::Formula hostSeconds; -extern Statistics::Formula hostTickRate; -extern Statistics::Formula hostInstRate; +extern Statistics::Value simTicks; #endif // __SIM_SIM_STATS_HH__ diff --git a/sim/system.cc b/sim/system.cc index 43f43baec..791a092ac 100644 --- a/sim/system.cc +++ b/sim/system.cc @@ -30,6 +30,7 @@ #include "targetarch/vtophys.hh" #include "sim/param.hh" #include "sim/system.hh" +#include "base/trace.hh" using namespace std; @@ -41,12 +42,15 @@ System::System(const std::string _name, const uint64_t _init_param, MemoryController *_memCtrl, PhysicalMemory *_physmem, - const bool _bin) + const bool _bin, + const std::vector<string> &binned_fns) + : SimObject(_name), init_param(_init_param), memCtrl(_memCtrl), physmem(_physmem), - bin(_bin) + bin(_bin), + binned_fns(binned_fns) { // add self to global system list systemList.push_back(this); @@ -54,6 +58,31 @@ System::System(const std::string _name, Kernel = new Statistics::MainBin("non TCPIP Kernel stats"); Kernel->activate(); User = new Statistics::MainBin("User stats"); + + int end = binned_fns.size(); + assert(!(end & 1)); + + Statistics::MainBin *Bin; + + fnEvents.resize(end>>1); + + for (int i = 0; i < end; i +=2) { + Bin = new Statistics::MainBin(binned_fns[i]); + fnBins.insert(make_pair(binned_fns[i], Bin)); + + fnEvents[(i>>1)] = new FnEvent(&pcEventQueue, binned_fns[i], this); + + if (binned_fns[i+1] == "null") + populateMap(binned_fns[i], ""); + else + populateMap(binned_fns[i], binned_fns[i+1]); + } + + fnCalls + .name(name() + ":fnCalls") + .desc("all fn calls being tracked") + ; + } else Kernel = NULL; } @@ -61,6 +90,13 @@ System::System(const std::string _name, System::~System() { + if (bin == true) { + int end = fnEvents.size(); + for (int i = 0; i < end; ++i) { + delete fnEvents[i]; + } + fnEvents.clear(); + } } @@ -103,6 +139,45 @@ printSystems() System::printSystems(); } +void +System::populateMap(std::string callee, std::string caller) +{ + multimap<const string, string>::const_iterator i; + i = callerMap.insert(make_pair(callee, caller)); + assert(i != callerMap.end() && "should not fail populating callerMap"); +} + +bool +System::findCaller(std::string callee, std::string caller) const +{ + typedef multimap<const std::string, std::string>::const_iterator iter; + pair<iter, iter> range; + + range = callerMap.equal_range(callee); + for (iter i = range.first; i != range.second; ++i) { + if ((*i).second == caller) + return true; + } + return false; +} + +void +System::dumpState(ExecContext *xc) const +{ + if (xc->swCtx) { + stack<fnCall *> copy(xc->swCtx->callStack); + if (copy.empty()) + return; + DPRINTF(TCPIP, "xc->swCtx, size: %d:\n", copy.size()); + fnCall *top; + DPRINTF(TCPIP, "|| call : %d\n",xc->swCtx->calls); + for (top = copy.top(); !copy.empty(); copy.pop() ) { + top = copy.top(); + DPRINTF(TCPIP, "|| %13s : %s \n", top->name, top->myBin->name()); + } + } +} + Statistics::MainBin * System::getBin(const std::string &name) { diff --git a/sim/system.hh b/sim/system.hh index 0fcdd77cc..08fcfb784 100644 --- a/sim/system.hh +++ b/sim/system.hh @@ -35,6 +35,7 @@ #include "base/loader/symtab.hh" #include "base/statistics.hh" #include "cpu/pc_event.hh" +#include "kern/system_events.hh" #include "sim/sim_object.hh" #include "sim/sw_context.hh" @@ -49,17 +50,20 @@ class ExecContext; class System : public SimObject { // lisa's binning stuff - protected: + private: std::map<const std::string, Statistics::MainBin *> fnBins; std::map<const Addr, SWContext *> swCtxMap; + protected: + std::vector<FnEvent *> fnEvents; + public: Statistics::Scalar<> fnCalls; Statistics::MainBin *Kernel; Statistics::MainBin *User; Statistics::MainBin * getBin(const std::string &name); - virtual bool findCaller(std::string, std::string) const = 0; + bool findCaller(std::string, std::string) const; SWContext *findContext(Addr pcb); bool addContext(Addr pcb, SWContext *ctx) { @@ -69,12 +73,16 @@ class System : public SimObject swCtxMap.erase(pcb); return; } - - virtual void dumpState(ExecContext *xc) const = 0; + void dumpState(ExecContext *xc) const; virtual void serialize(std::ostream &os); virtual void unserialize(Checkpoint *cp, const std::string §ion); - // + + + private: + std::multimap<const std::string, std::string> callerMap; + void populateMap(std::string caller, std::string callee); +// public: const uint64_t init_param; @@ -82,6 +90,7 @@ class System : public SimObject PhysicalMemory *physmem; Platform *platform; bool bin; + std::vector<string> binned_fns; PCEventQueue pcEventQueue; @@ -92,7 +101,8 @@ class System : public SimObject public: System(const std::string _name, const uint64_t _init_param, - MemoryController *, PhysicalMemory *, const bool); + MemoryController *, PhysicalMemory *, const bool, + const std::vector<string> &binned_fns); ~System(); virtual Addr getKernelStart() const = 0; diff --git a/test/Makefile b/test/Makefile index bf4200ba3..15019a1f5 100644 --- a/test/Makefile +++ b/test/Makefile @@ -2,18 +2,24 @@ CC?= gcc CXX?= g++ +PYTHON?=/usr/bin/env python CURDIR?= $(shell /bin/pwd) -SRCDIR?= .. +SRCDIR?= $(CURDIR)/.. CCFLAGS= -g -O0 -MMD -I. -I$(SRCDIR) -I- -DTRACING_ON=0 MYSQL= -I/usr/include/mysql -L/usr/lib/mysql -lmysqlclient -VPATH=$(SRCDIR) +VPATH=$(SRCDIR):$(CURDIR) default: @echo "You must specify a target" +base/traceflags.cc base/traceflags.hh: $(SRCDIR)/base/traceflags.py + mkdir -p base; \ + cd base; \ + $(PYTHON) $< + bitvectest: test/bitvectest.cc $(CXX) $(CCFLAGS) -o $@ $^ @@ -61,5 +67,5 @@ tracetest: $(TRACE) $(CXX) $(CCFLAGS) -o $@ $^ clean: - @rm -f *test *~ .#* *.core core + @rm -rf *test *~ .#* *.core core base .PHONY: clean diff --git a/test/stattest.cc b/test/stattest.cc index 7bf355c0e..9b7ba9857 100644 --- a/test/stattest.cc +++ b/test/stattest.cc @@ -66,8 +66,8 @@ Vector2d<> s16; Formula f1; Formula f2; Formula f3; -Formula f4; -Formula f5; +Value f4; +Value f5; Formula f6; Formula f7; @@ -279,11 +279,14 @@ main(int argc, char *argv[]) ; f4 + .functor(testfunc) .name("Formula4") .desc("this is formula 4") ; + TestClass testclass; f5 + .functor(testclass) .name("Formula5") .desc("this is formula 5") ; @@ -296,9 +299,6 @@ main(int argc, char *argv[]) f1 = s1 + s2; f2 = (-s1) / (-s2) * (-s3 + ULL(100) + s4); f3 = sum(s5) * s7; - f4 = functor(testfunc); - TestClass testclass; - f5 = functor(testclass); f6 += constant(10.0); f6 += s5[3]; f7 = constant(1); |