X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=arch%2Falpha%2Fisa_desc;h=f964101df774294099f32ebc2017782084fd1d89;hb=1d545281b96a6df358201c7b0e610bfaf9e8f213;hp=75f765029258681e23e2418ac3f83f370536b0de;hpb=e12e64a0718f6805c1203e1d11a39abaf0d9483b;p=gem5.git diff --git a/arch/alpha/isa_desc b/arch/alpha/isa_desc index 75f765029..f964101df 100644 --- a/arch/alpha/isa_desc +++ b/arch/alpha/isa_desc @@ -1,41 +1,67 @@ // -*- mode:c++ -*- + +//////////////////////////////////////////////////////////////////// // // Alpha ISA description file. // +//////////////////////////////////////////////////////////////////// -let {{ - global rcs_id - rcs_id = "$Id$" -}}; +//////////////////////////////////////////////////////////////////// +// +// Output include file directives. +// +output header {{ #include #include #include +#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 #if defined(linux) #include #endif +}}; -#include "base/cprintf.hh" -#include "base/misc.hh" -#include "cpu/exec_context.hh" +output exec {{ +#include +#if defined(linux) +#include +#endif + +#include "cpu/base_cpu.hh" #include "cpu/exetrace.hh" -#include "cpu/full_cpu/full_cpu.hh" -#include "cpu/full_cpu/op_class.hh" -#include "cpu/full_cpu/spec_state.hh" -#include "cpu/simple_cpu/simple_cpu.hh" -#include "cpu/static_inst.hh" -#include "sim/annotation.hh" -#include "sim/sim_events.hh" +#include "sim/sim_exit.hh" #ifdef FULL_SYSTEM -#include "targetarch/ev5.hh" +#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>; @@ -94,68 +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 - inline Fault checkFpEnableFault(ExecContext *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(ExecContext *xc) - { - return No_Fault; - } -#endif +output header {{ +// uncomment the following to get SimpleScalar-compatible disassembly +// (useful for diffing output traces). +// #define SS_COMPATIBLE_DISASSEMBLY /** * Base class for all Alpha static instructions. @@ -183,47 +189,60 @@ declare {{ /// Print a register name for disassembly given the unique /// dependence tag number (FP or int). - void printReg(std::ostream &os, int reg) - { - if (reg < FP_Base_DepTag) { - ccprintf(os, "r%d", reg); - } - else { - ccprintf(os, "f%d", reg - FP_Base_DepTag); - } - } + void printReg(std::ostream &os, int reg); - std::string generateDisassembly(Addr pc, const SymbolTable *symtab) - { - std::stringstream ss; + std::string generateDisassembly(Addr pc, const SymbolTable *symtab); + }; +}}; - ccprintf(ss, "%-10s ", mnemonic); +output decoder {{ + void + AlphaStaticInst::printReg(std::ostream &os, int reg) + { + if (reg < FP_Base_DepTag) { + ccprintf(os, "r%d", reg); + } + else { + ccprintf(os, "f%d", reg - FP_Base_DepTag); + } + } - // just print the first two source regs... if there's - // a third one, it's a read-modify-write dest (Rc), - // e.g. for CMOVxx - if (_numSrcRegs > 0) { - printReg(ss, _srcRegIdx[0]); - } - if (_numSrcRegs > 1) { - ss << ","; - printReg(ss, _srcRegIdx[1]); - } + std::string + AlphaStaticInst::generateDisassembly(Addr pc, const SymbolTable *symtab) + { + std::stringstream ss; - // just print the first dest... if there's a second one, - // it's generally implicit - if (_numDestRegs > 0) { - if (_numSrcRegs > 0) - ss << ","; - printReg(ss, _destRegIdx[0]); - } + ccprintf(ss, "%-10s ", mnemonic); - return ss.str(); + // just print the first two source regs... if there's + // a third one, it's a read-modify-write dest (Rc), + // e.g. for CMOVxx + if (_numSrcRegs > 0) { + printReg(ss, _srcRegIdx[0]); } - }; + if (_numSrcRegs > 1) { + ss << ","; + printReg(ss, _srcRegIdx[1]); + } + + // just print the first dest... if there's a second one, + // it's generally implicit + if (_numDestRegs > 0) { + if (_numSrcRegs > 0) + ss << ","; + printReg(ss, _destRegIdx[0]); + } + + return ss.str(); + } }}; +// Declarations for execute() methods. +def template BasicExecDeclare {{ + Fault execute(%(CPU_exec_context)s *, Trace::InstRecord *); +}}; +// Basic instruction class declaration template. def template BasicDeclare {{ /** * Static instruction class for "%(mnemonic)s". @@ -232,54 +251,47 @@ 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); - Fault execute(SimpleCPU *cpu, ExecContext *xc, - Trace::InstRecord *traceData) - { - SimpleCPU *memAccessObj __attribute__((unused)) = cpu; - Fault fault = No_Fault; - - %(fp_enable_check)s; - %(exec_decl)s; - %(simple_rd)s; - %(code)s; - - if (fault == No_Fault) { - %(simple_wb)s; - } - - return fault; - } + %(BasicExecDeclare)s + }; +}}; - Fault execute(FullCPU *cpu, SpecExecContext *xc, DynInst *dynInst, - Trace::InstRecord *traceData) - { - DynInst *memAccessObj __attribute__((unused)) = dynInst; - Fault fault = No_Fault; +// 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; + } +}}; - %(fp_enable_check)s; - %(exec_decl)s; - %(dtld_rd)s; - %(code)s; +// Basic instruction class execute method template. +def template BasicExecute {{ + Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) + { + Fault fault = No_Fault; - if (fault == No_Fault) { - %(dtld_wb)s; - } + %(fp_enable_check)s; + %(op_decl)s; + %(op_rd)s; + %(code)s; - return fault; + if (fault == No_Fault) { + %(op_wb)s; } - }; + + return fault; + } }}; +// 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); }}; @@ -287,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') + 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. */ @@ -314,27 +332,21 @@ declare {{ ~Nop() { } - Fault execute(SimpleCPU *cpu, ExecContext *xc, - Trace::InstRecord *traceData) - { - return No_Fault; - } + std::string generateDisassembly(Addr pc, const SymbolTable *symtab); - Fault execute(FullCPU *cpu, SpecExecContext *xc, DynInst *dynInst, - Trace::InstRecord *traceData) - { - return No_Fault; - } + %(BasicExecDeclare)s + }; +}}; - std::string generateDisassembly(Addr pc, const SymbolTable *symtab) - { +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 - } - }; + } /// Helper function for decoding nops. Substitute Nop object /// for original inst passed in as arg (and delete latter). @@ -348,18 +360,21 @@ declare {{ } }}; -def format Nop() {{ - return ('', 'return new Nop("%s", machInst);\n' % name) +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; } @@ -369,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') + header_output = BasicDeclare.subst(iop) + decoder_output = BasicConstructor.subst(iop) + decode_block = OperateNopCheckDecode.subst(iop) + exec_output = BasicExecute.subst(iop) }}; @@ -378,7 +396,7 @@ def format BasicOperateWithNopCheck(code, *opt_args) {{ // Integer operate instructions // -declare {{ +output header {{ /** * Base class for integer immediate instructions. */ @@ -394,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; } @@ -453,21 +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 = iop.subst('BasicDeclare') + 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) - decls += imm_iop.subst('BasicDeclare') + 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) + decode_block = OperateNopCheckDecode.subst(iop) }}; @@ -480,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 @@ -537,60 +585,93 @@ declare {{ trappingMode((enum TrappingMode)FP_TRAPMODE) { if (trappingMode != Imprecise) { - warn("Warning: precise FP traps unimplemented\n"); + warn("precise FP traps unimplemented\n"); } } #if defined(linux) - int - getC99RoundingMode(ExecContext *xc) - { - if (roundingMode == Dynamic) { - return alphaToC99RoundingMode[bits(xc->readFpcr(), 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); + }; - mnem_str += ((_destRegIdx[0] >= FP_Base_DepTag) - ? fpTrappingModeSuffix[trappingMode] - : intTrappingModeSuffix[trappingMode]); - mnem_str += roundingModeSuffix[roundingMode]; +}}; - std::stringstream ss; - ccprintf(ss, "%-10s ", mnem_str.c_str()); +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); - // 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]); - } + if (FC == 31) { + i = makeNop(i); + } - // 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 i; + } +}}; - return ss.str(); +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::string + AlphaFP::generateDisassembly(Addr pc, const SymbolTable *symtab) + { + std::string mnem_str(mnemonic); + +#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); + } +#endif + + 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[] = { @@ -610,150 +691,36 @@ declare {{ { "", "v", "INVTM2", "INVTM3", "INVTM4", "sv", "INVTM6", "svi" }; }}; +// 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_block = FloatingPointDecode.subst(iop) -def template FloatingPointDeclare {{ - /** - * "Fast" static instruction class for "%(mnemonic)s" (imprecise - * trapping mode, normal rounding mode). - */ - class %(class_name)sFast : public %(base_class)s - { - public: - /// Constructor. - %(class_name)sFast(MachInst machInst) - : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s) - { - %(constructor)s; - } - - Fault execute(SimpleCPU *cpu, ExecContext *xc, - Trace::InstRecord *traceData) - { - Fault fault = No_Fault; - - %(fp_enable_check)s; - %(exec_decl)s; - %(simple_rd)s; - %(code)s; - - if (fault == No_Fault) { - %(simple_wb)s; - } - - return fault; - } - - Fault execute(FullCPU *cpu, SpecExecContext *xc, DynInst *dynInst, - Trace::InstRecord *traceData) - { - Fault fault = No_Fault; - - %(fp_enable_check)s; - %(exec_decl)s; - %(dtld_rd)s; - %(code)s; - - if (fault == No_Fault) { - %(dtld_wb)s; - } - - return fault; - } - }; - - /** - * General static instruction class for "%(mnemonic)s". Supports - * all the various rounding and trapping modes. - */ - class %(class_name)sGeneral : public %(base_class)s - { - public: - /// Constructor. - %(class_name)sGeneral(MachInst machInst) - : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s) - { - %(constructor)s; - } - - Fault execute(SimpleCPU *cpu, ExecContext *xc, - Trace::InstRecord *traceData) - { - Fault fault = No_Fault; - - %(fp_enable_check)s; - %(exec_decl)s; - %(simple_rd)s; - -#if defined(linux) - fesetround(getC99RoundingMode(xc)); -#endif - - %(code)s; - -#if defined(linux) - fesetround(FE_TONEAREST); -#endif - - if (fault == No_Fault) { - %(simple_wb)s; - } - - return fault; - } - - Fault execute(FullCPU *cpu, SpecExecContext *xc, DynInst *dynInst, - Trace::InstRecord *traceData) - { - Fault fault = No_Fault; - - %(fp_enable_check)s; - %(exec_decl)s; - %(dtld_rd)s; + fast_iop = InstObjParams(name, Name + 'Fast', 'AlphaFP', + 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) - fesetround(getC99RoundingMode(xc)); + fesetround(getC99RoundingMode(xc->readFpcr())); #endif - - %(code)s; - +''' + gen_code_suffix = r''' #if defined(linux) - fesetround(FE_TONEAREST); + fesetround(FE_TONEAREST); #endif +''' - if (fault == No_Fault) { - %(dtld_wb)s; - } - - return fault; - } - }; -}}; - -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) - return iop.subst('FloatingPointDeclare', 'FloatingPointDecode') + gen_iop = InstObjParams(name, Name + 'General', 'AlphaFP', + CodeBlock(gen_code_prefix + code + gen_code_suffix), opt_args) + header_output += BasicDeclare.subst(gen_iop) + decoder_output += BasicConstructor.subst(gen_iop) + exec_output += BasicExecute.subst(gen_iop) }}; @@ -762,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. */ @@ -770,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 eaCompPtr; + /// Pointer to MemAcc object. + const StaticInstPtr memAccPtr; /// Constructor - Memory(const char *mnem, MachInst _machInst, OpClass __opClass) + Memory(const char *mnem, MachInst _machInst, OpClass __opClass, + StaticInstPtr _eaCompPtr = nullStaticInstPtr, + StaticInstPtr _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 &eaCompInst() const { return eaCompPtr; } + const StaticInstPtr &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 _eaCompPtr = nullStaticInstPtr, + StaticInstPtr _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 _eaCompPtr, + StaticInstPtr _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(). @@ -826,13 +815,7 @@ declare {{ { } - Fault execute(SimpleCPU *cpu, ExecContext *xc, - Trace::InstRecord *traceData) - { panic("attempt to execute eacomp"); } - - Fault execute(FullCPU *cpu, SpecExecContext *xc, DynInst *dynInst, - Trace::InstRecord *traceData) - { panic("attempt to execute eacomp"); } + %(BasicExecDeclare)s }; /** @@ -848,21 +831,48 @@ declare {{ { } - Fault execute(SimpleCPU *cpu, ExecContext *xc, - Trace::InstRecord *traceData) - { panic("attempt to execute memacc"); } - - Fault execute(FullCPU *cpu, SpecExecContext *xc, DynInst *dynInst, - Trace::InstRecord *traceData) - { 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') + 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) }}; @@ -881,11 +891,7 @@ def template LoadStoreDeclare {{ { public: /// Constructor - EAComp(MachInst machInst) - : EACompBase(machInst) - { - %(ea_constructor)s; - } + EAComp(MachInst machInst); }; /** @@ -895,150 +901,92 @@ def template LoadStoreDeclare {{ { public: /// Constructor - MemAcc(MachInst machInst) - : MemAccBase(machInst, %(op_class)s) - { - %(memacc_constructor)s; - } + MemAcc(MachInst machInst); }; - /// Pointer to EAComp object. - StaticInstPtr eaCompPtr; - /// Pointer to MemAcc object. - StaticInstPtr memAccPtr; - public: - StaticInstPtr eaCompInst() { return eaCompPtr; } - StaticInstPtr 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; - } - - Fault execute(SimpleCPU *cpu, ExecContext *xc, - Trace::InstRecord *traceData) - { - SimpleCPU *memAccessObj = cpu; - Addr EA; - Fault fault = No_Fault; - - %(fp_enable_check)s; - %(exec_decl)s; - %(simple_nonmem_rd)s; - %(ea_code)s; - - if (fault == No_Fault) { - %(simple_mem_rd)s; - %(memacc_code)s; - } - - if (fault == No_Fault) { - %(simple_mem_wb)s; - } - - if (fault == No_Fault) { - %(postacc_code)s; - } - - if (fault == No_Fault) { - %(simple_nonmem_wb)s; - } + %(class_name)s(MachInst machInst); - return fault; - } - - Fault execute(FullCPU *cpu, SpecExecContext *xc, DynInst *dynInst, - Trace::InstRecord *traceData) - { - DynInst *memAccessObj = dynInst; - Addr EA; - Fault fault = No_Fault; - - %(fp_enable_check)s; - %(exec_decl)s; - %(dtld_nonmem_rd)s; - %(ea_code)s; - - if (fault == No_Fault) { - %(dtld_mem_rd)s; - %(memacc_code)s; - } - - if (fault == No_Fault) { - %(dtld_mem_wb)s; - } - - if (fault == No_Fault) { - %(postacc_code)s; - } - - if (fault == No_Fault) { - %(dtld_nonmem_wb)s; - } - - return fault; - } + %(BasicExecDeclare)s }; }}; +def template LoadStoreConstructor {{ + inline %(class_name)s::EAComp::EAComp(MachInst machInst) + : EACompBase(machInst) + { + %(ea_constructor)s; + } -def template PrefetchDeclare {{ - /** - * Static instruction class for "%(mnemonic)s". - */ - class %(class_name)s : public %(base_class)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_exec_context)s *xc, + Trace::InstRecord *traceData) { - public: - /// Constructor - %(class_name)s(MachInst machInst) - : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s) - { - %(constructor)s; - } + Addr EA; + Fault fault = No_Fault; - Fault execute(SimpleCPU *cpu, ExecContext *xc, - Trace::InstRecord *traceData) - { - Addr EA; - Fault fault = No_Fault; + %(fp_enable_check)s; + %(op_decl)s; + %(op_nonmem_rd)s; + %(ea_code)s; - %(fp_enable_check)s; - %(exec_decl)s; - %(simple_nonmem_rd)s; - %(ea_code)s; + if (fault == No_Fault) { + %(op_mem_rd)s; + %(memacc_code)s; + } - if (fault == No_Fault) { - cpu->prefetch(EA, memAccessFlags); - } + if (fault == No_Fault) { + %(op_mem_wb)s; + } - return No_Fault; + if (fault == No_Fault) { + %(postacc_code)s; } - Fault execute(FullCPU *cpu, SpecExecContext *xc, DynInst *dynInst, - Trace::InstRecord *traceData) - { - Addr EA; - Fault fault = No_Fault; + if (fault == No_Fault) { + %(op_nonmem_wb)s; + } + + return fault; + } +}}; - %(fp_enable_check)s; - %(exec_decl)s; - %(dtld_nonmem_rd)s; - %(ea_code)s; - if (fault == No_Fault) { - dynInst->prefetch(EA, memAccessFlags); - } +def template PrefetchExecute {{ + Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, + Trace::InstRecord *traceData) + { + Addr EA; + Fault fault = No_Fault; + + %(fp_enable_check)s; + %(op_decl)s; + %(op_nonmem_rd)s; + %(ea_code)s; - return No_Fault; + if (fault == No_Fault) { + xc->prefetch(EA, memAccessFlags); } - }; -}}; + return No_Fault; + } +}}; // load instructions use Ra as dest, so check for // Ra == 31 to detect nops @@ -1067,11 +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'): + base_class = 'MemoryDisp32', flags = [], + decode_template = BasicDecode, + exec_template = LoadStoreExecute): # Segregate flags into instruction flags (handled by InstObjParams) # and memory access flags (handled here). @@ -1102,61 +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) + # (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) = \ + (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) = \ + (pf_header_output, pf_decoder_output, _, pf_exec_output) = \ LoadStoreBase(name, Name + 'Prefetch', ea_code, '', - flags = pf_flags, - declare_template = 'PrefetchDeclare') + flags = pf_flags, exec_template = PrefetchExecute) - return (decls + pfdecls, decode) + 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 @@ -1183,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); }; /** @@ -1218,47 +1157,9 @@ declare {{ { } - Addr branchTarget(Addr branchPC) - { - return branchPC + 4 + disp; - } - - std::string generateDisassembly(Addr pc, const SymbolTable *symtab) - { - std::stringstream ss; - - ccprintf(ss, "%-10s ", mnemonic); - - // There's only one register arg (RA), but it could be - // either a source (the condition for conditional - // branches) or a destination (the link reg for - // unconditional branches) - if (_numSrcRegs > 0) { - printReg(ss, _srcRegIdx[0]); - ss << ","; - } - else if (_numDestRegs > 0) { - printReg(ss, _destRegIdx[0]); - ss << ","; - } - -#ifdef SS_COMPATIBLE_DISASSEMBLY - if (_numSrcRegs == 0 && _numDestRegs == 0) { - printReg(ss, 31); - ss << ","; - } -#endif - - Addr target = pc + 4 + disp; + Addr branchTarget(Addr branchPC) const; - std::string str; - if (symtab && symtab->findSymbol(target, str)) - ss << str; - else - ccprintf(ss, "0x%x", target); - - return ss.str(); - } + std::string generateDisassembly(Addr pc, const SymbolTable *symtab); }; /** @@ -1280,29 +1181,106 @@ declare {{ { } - std::string generateDisassembly(Addr pc, const SymbolTable *symtab) + 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) { - std::stringstream ss; + if (cachedDisassembly) + delete cachedDisassembly; + + cachedDisassembly = + new std::string(generateDisassembly(pc, symtab)); + cachedPC = pc; + cachedSymtab = symtab; + } + + 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 {{ @@ -1315,41 +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') + 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 = nolink_iop.subst('BasicDeclare') + 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) - decls += link_iop.subst('BasicDeclare') + 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')) + + 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). @@ -1365,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') + 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 @@ -1392,96 +1393,135 @@ declare {{ protected: int palFunc; ///< Function code part of instruction int palOffset; ///< Target PC, offset from IPR_PAL_BASE + bool palValid; ///< is the function code valid? + bool palPriv; ///< is this call privileged? /// Constructor. CallPalBase(const char *mnem, MachInst _machInst, - OpClass __opClass) - : AlphaStaticInst(mnem, _machInst, __opClass), - palFunc(PALFUNC) - { - int palPriv = ((machInst & 0x80) != 0); - int shortPalFunc = (machInst & 0x3f); - palOffset = 0x2001 + (palPriv << 12) + (shortPalFunc << 6); - } + OpClass __opClass); - std::string generateDisassembly(Addr pc, const SymbolTable *symtab) - { - return csprintf("%-10s %#x", "call_pal", palFunc); - } + 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') + 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 _eaCompPtr, + StaticInstPtr _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 _eaCompPtr, + StaticInstPtr _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. */ @@ -1498,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') + 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 @@ -1536,29 +1590,9 @@ declare {{ { } - Fault execute(SimpleCPU *cpu, ExecContext *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(FullCPU *cpu, SpecExecContext *xc, DynInst *dynInst, - Trace::InstRecord *traceData) - { - // don't panic if this is a misspeculated instruction - if (!xc->spec_mode) - 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); }; /** @@ -1583,39 +1617,56 @@ declare {{ { } - Fault execute(SimpleCPU *cpu, ExecContext *xc, - Trace::InstRecord *traceData) - { - if (!warned) { - warn("Warning: instruction '%s' unimplemented\n", mnemonic); - warned = true; - } - - return No_Fault; - } + %(BasicExecDeclare)s - Fault execute(FullCPU *cpu, SpecExecContext *xc, DynInst *dynInst, - Trace::InstRecord *traceData) - { - if (!xc->spec_mode && !warned) { - warn("Warning: 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". @@ -1634,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 @@ -1657,37 +1709,47 @@ declare {{ { } - Fault execute(SimpleCPU *cpu, ExecContext *xc, - Trace::InstRecord *traceData) - { - panic("attempt to execute unknown instruction " - "(inst 0x%08x, opcode 0x%x)", machInst, OPCODE); - return Unimplemented_Opcode_Fault; - } + %(BasicExecDeclare)s - Fault execute(FullCPU *cpu, SpecExecContext *xc, DynInst *dynInst, - Trace::InstRecord *traceData) - { - // don't panic if this is a misspeculated instruction - if (!xc->spec_mode) - panic("attempt to execute unknown instruction " - "(inst 0x%08x, opcode 0x%x)", machInst, OPCODE); - return Unimplemented_Opcode_Fault; - } - - std::string generateDisassembly(Addr pc, const SymbolTable *symtab) - { - return csprintf("%-10s (inst 0x%x, opcode 0x%x)", - "unknown", machInst, OPCODE); - } + std::string generateDisassembly(Addr pc, const SymbolTable *symtab); }; }}; +//////////////////////////////////////////////////////////////////// +// +// Unknown instructions +// + +output decoder {{ + std::string + Unknown::generateDisassembly(Addr pc, const SymbolTable *symtab) + { + return csprintf("%-10s (inst 0x%x, opcode 0x%x)", + "unknown", machInst, OPCODE); + } +}}; + +output exec {{ + Fault + Unknown::execute(%(CPU_exec_context)s *xc, Trace::InstRecord *traceData) + { + if (!xc->misspeculating()) + panic("attempt to execute unknown instruction " + "(inst 0x%08x, opcode 0x%x)", machInst, OPCODE); + return Unimplemented_Opcode_Fault; + } +}}; + def format Unknown() {{ - return ('', 'return new Unknown(machInst);\n') + decode_block = 'return new Unknown(machInst);\n' }}; -declare {{ +//////////////////////////////////////////////////////////////////// +// +// Utility functions for execute methods +// + +output exec {{ /// Return opa + opb, summing carry into third arg. inline uint64_t @@ -1701,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 @@ -1771,6 +1833,11 @@ declare {{ } }}; +//////////////////////////////////////////////////////////////////// +// +// The actual decoder specification +// + decode OPCODE default Unknown::unknown() { format LoadAddress { @@ -1785,13 +1852,18 @@ decode OPCODE default Unknown::unknown() { 0x23: ldt({{ EA = Rb + disp; }}, {{ Fa = Mem.df; }}); 0x2a: ldl_l({{ EA = Rb + disp; }}, {{ Ra.sl = Mem.sl; }}, LOCKED); 0x2b: ldq_l({{ EA = Rb + disp; }}, {{ Ra.uq = Mem.uq; }}, LOCKED); + 0x20: copy_load({{EA = Ra;}}, + {{ fault = xc->copySrcTranslate(EA);}}, + IsMemRef, IsLoad, IsCopy); } format LoadOrPrefetch { 0x28: ldl({{ EA = Rb + disp; }}, {{ Ra.sl = Mem.sl; }}); 0x29: ldq({{ EA = Rb + disp; }}, {{ Ra.uq = Mem.uq; }}, EVICT_NEXT); + // IsFloating flag on lds gets the prefetch to disassemble + // using f31 instead of r31... funcitonally it's unnecessary 0x22: lds({{ EA = Rb + disp; }}, {{ Fa.uq = s_to_t(Mem.ul); }}, - PF_EXCLUSIVE); + PF_EXCLUSIVE, IsFloating); } format Store { @@ -1802,6 +1874,9 @@ decode OPCODE default Unknown::unknown() { 0x0f: stq_u({{ EA = (Rb + disp) & ~7; }}, {{ Mem.uq = Ra.uq; }}); 0x26: sts({{ EA = Rb + disp; }}, {{ Mem.ul = t_to_s(Fa.uq); }}); 0x27: stt({{ EA = Rb + disp; }}, {{ Mem.df = Fa; }}); + 0x24: copy_store({{EA = Rb;}}, + {{ fault = xc->copy(EA);}}, + IsMemRef, IsStore, IsCopy); } format StoreCond { @@ -2299,10 +2374,6 @@ decode OPCODE default Unknown::unknown() { // miscellaneous mem-format ops 0x18: decode MEMFUNC { format WarnUnimpl { - 0x0000: trapb(); - 0x0400: excb(); - 0x4000: mb(); - 0x4400: wmb(); 0x8000: fetch(); 0xa000: fetch_m(); 0xe800: ecb(); @@ -2310,28 +2381,55 @@ decode OPCODE default Unknown::unknown() { format MiscPrefetch { 0xf800: wh64({{ EA = Rb; }}, - {{ memAccessObj->writeHint(EA, 64); }}, + {{ xc->writeHint(EA, 64); }}, IsMemRef, IsStore, WrPort); } format BasicOperate { - 0xc000: rpcc({{ Ra = curTick; }}); + 0xc000: rpcc({{ +#ifdef FULL_SYSTEM + Ra = xc->readIpr(AlphaISA::IPR_CC, fault); +#else + Ra = curTick; +#endif + }}); + + // All of the barrier instructions below do nothing in + // their execute() methods (hence the empty code blocks). + // All of their functionality is hard-coded in the + // pipeline based on the flags IsSerializing, + // IsMemBarrier, and IsWriteBarrier. In the current + // detailed CPU model, the execute() function only gets + // called at fetch, so there's no way to generate pipeline + // behavior at any other stage. Once we go to an + // exec-in-exec CPU model we should be able to get rid of + // these flags and implement this behavior via the + // execute() methods. + + // trapb is just a barrier on integer traps, where excb is + // a barrier on integer and FP traps. "EXCB is thus a + // superset of TRAPB." (Alpha ARM, Sec 4.11.4) We treat + // them the same though. + 0x0000: trapb({{ }}, IsSerializing, No_OpClass); + 0x0400: excb({{ }}, IsSerializing, No_OpClass); + 0x4000: mb({{ }}, IsMemBarrier, RdPort); + 0x4400: wmb({{ }}, IsWriteBarrier, WrPort); } #ifdef FULL_SYSTEM format BasicOperate { 0xe000: rc({{ - Ra = xc->regs.intrflag; + Ra = xc->readIntrFlag(); if (!xc->misspeculating()) { - xc->regs.intrflag = 0; + xc->setIntrFlag(0); } - }}, No_OpClass); + }}); 0xf000: rs({{ - Ra = xc->regs.intrflag; + Ra = xc->readIntrFlag(); if (!xc->misspeculating()) { - xc->regs.intrflag = 1; + xc->setIntrFlag(1); } - }}, No_OpClass); + }}); } #else format FailUnimpl { @@ -2343,20 +2441,33 @@ decode OPCODE default Unknown::unknown() { #ifdef FULL_SYSTEM 0x00: CallPal::call_pal({{ - // check to see if simulator wants to do something special - // on this PAL call (including maybe suppress it) - bool dopal = xc->simPalCheck(palFunc); - - if (!xc->misspeculating()) { - Annotate::Callpal(xc, palFunc); + if (!palValid || + (palPriv + && xc->readIpr(AlphaISA::IPR_ICM, fault) != AlphaISA::mode_kernel)) { + // invalid pal function code, or attempt to do privileged + // PAL call in non-kernel mode + fault = Unimplemented_Opcode_Fault; } + else { + bool dopal = true; - if (dopal) { if (!xc->misspeculating()) { - AlphaISA::swap_palshadow(&xc->regs, true); + // check to see if simulator wants to do something special + // on this PAL call (including maybe suppress it) + dopal = xc->simPalCheck(palFunc); + + if (dopal) { + AlphaISA::swap_palshadow(&xc->xcBase()->regs, true); + xc->setIpr(AlphaISA::IPR_EXC_ADDR, NPC); + } + } + + // if we're misspeculating, it's still safe (if + // unrealistic) to set NPC, as the control-flow change + // won't get committed. + if (dopal) { + NPC = xc->readIpr(AlphaISA::IPR_PAL_BASE, fault) + palOffset; } - xc->setIpr(AlphaISA::IPR_EXC_ADDR, NPC); - NPC = xc->readIpr(AlphaISA::IPR_PAL_BASE, fault) + palOffset; } }}); #else @@ -2364,7 +2475,7 @@ decode OPCODE default Unknown::unknown() { format EmulatedCallPal { 0x00: halt ({{ if (!xc->misspeculating()) - SimExit("halt instruction encountered"); + SimExit(curTick, "halt instruction encountered"); }}); 0x83: callsys({{ if (!xc->misspeculating()) @@ -2403,36 +2514,45 @@ 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); - xc->kernelStats.arm(); - } + if (!xc->misspeculating()) + AlphaPseudo::arm(xc->xcBase()); }}); 0x01: quiesce({{ - if (!xc->misspeculating()) { - Annotate::QUIESCE(xc); - xc->setStatus(ExecContext::Suspended); - xc->kernelStats.quiesce(); - } + if (!xc->misspeculating()) + AlphaPseudo::quiesce(xc->xcBase()); }}); 0x10: ivlb({{ - if (!xc->misspeculating()) { - Annotate::BeginInterval(xc); - xc->kernelStats.ivlb(); - } + if (!xc->misspeculating()) + AlphaPseudo::ivlb(xc->xcBase()); }}, No_OpClass); 0x11: ivle({{ if (!xc->misspeculating()) - Annotate::EndInterval(xc); + AlphaPseudo::ivle(xc->xcBase()); }}, No_OpClass); - 0x20: m5exit({{ + 0x20: m5exit_old({{ if (!xc->misspeculating()) - SimExit("m5_exit instruction encountered"); + AlphaPseudo::m5exit_old(xc->xcBase()); }}, No_OpClass); - 0x30: initparam({{ Ra = xc->cpu->system->init_param; }}); + 0x21: m5exit({{ + if (!xc->misspeculating()) + AlphaPseudo::m5exit(xc->xcBase()); + }}, No_OpClass); + 0x30: initparam({{ Ra = xc->xcBase()->cpu->system->init_param; }}); 0x40: resetstats({{ if (!xc->misspeculating()) - Statistics::reset(); + AlphaPseudo::resetstats(xc->xcBase()); + }}); + 0x41: dumpstats({{ + if (!xc->misspeculating()) + AlphaPseudo::dumpstats(xc->xcBase()); + }}); + 0x42: dumpresetstats({{ + if (!xc->misspeculating()) + AlphaPseudo::dumpresetstats(xc->xcBase()); + }}); + 0x43: m5checkpoint({{ + if (!xc->misspeculating()) + AlphaPseudo::m5checkpoint(xc->xcBase()); }}); } } @@ -2440,7 +2560,7 @@ decode OPCODE default Unknown::unknown() { format HwMoveIPR { 0x19: hw_mfpr({{ // this instruction is only valid in PAL mode - if (!PC_PAL(xc->regs.pc)) { + if (!xc->inPalMode()) { fault = Unimplemented_Opcode_Fault; } else { @@ -2449,7 +2569,7 @@ decode OPCODE default Unknown::unknown() { }}); 0x1d: hw_mtpr({{ // this instruction is only valid in PAL mode - if (!PC_PAL(xc->regs.pc)) { + if (!xc->inPalMode()) { fault = Unimplemented_Opcode_Fault; } else {