// -*- 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"
-#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_exit.hh"
+output exec {{
+#include <math.h>
+#if defined(linux)
+#include <fenv.h>
+#endif
#ifdef FULL_SYSTEM
-#include "arch/alpha/ev5.hh"
#include "arch/alpha/pseudo_inst.hh"
#endif
+#include "cpu/base_cpu.hh"
+#include "cpu/exetrace.hh"
+#include "sim/sim_exit.hh"
+}};
+
+////////////////////////////////////////////////////////////////////
+//
+// 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>;
// 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.
/// 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) const;
- std::string generateDisassembly(Addr pc, const SymbolTable *symtab)
- {
- std::stringstream ss;
+ std::string
+ generateDisassembly(Addr pc, const SymbolTable *symtab) const;
+ };
+}};
+
+output decoder {{
+ void
+ AlphaStaticInst::printReg(std::ostream &os, int reg) const
+ {
+ if (reg < FP_Base_DepTag) {
+ ccprintf(os, "r%d", reg);
+ }
+ else {
+ ccprintf(os, "f%d", reg - FP_Base_DepTag);
+ }
+ }
- ccprintf(ss, "%-10s ", mnemonic);
+ std::string
+ AlphaStaticInst::generateDisassembly(Addr pc,
+ const SymbolTable *symtab) const
+ {
+ std::stringstream ss;
- // 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]);
- }
+ ccprintf(ss, "%-10s ", mnemonic);
- // 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]);
- }
+ // 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]);
+ }
- return ss.str();
+ // 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 *) const;
+}};
+// Basic instruction class declaration template.
def template BasicDeclare {{
/**
* Static instruction class for "%(mnemonic)s".
{
public:
/// Constructor.
- %(class_name)s(MachInst machInst)
- : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s)
- {
- %(constructor)s;
- }
-
- 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;
+ %(class_name)s(MachInst machInst);
- 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) const
+ {
+ 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);
}};
// 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.
*/
~Nop() { }
- Fault execute(SimpleCPU *cpu, ExecContext *xc,
- Trace::InstRecord *traceData)
- {
- return No_Fault;
- }
+ std::string
+ generateDisassembly(Addr pc, const SymbolTable *symtab) const;
- 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) const
+ {
#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).
}
}};
-def format Nop() {{
- return ('', 'return new Nop("%s", machInst);\n' % name)
+output exec {{
+ Fault
+ Nop::execute(%(CPU_exec_context)s *, Trace::InstRecord *) const
+ {
+ 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;
}
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)
}};
// Integer operate instructions
//
-declare {{
+output header {{
/**
* Base class for integer immediate instructions.
*/
{
}
- std::string generateDisassembly(Addr pc, const SymbolTable *symtab)
- {
- std::stringstream ss;
+ std::string
+ generateDisassembly(Addr pc, const SymbolTable *symtab) const;
+ };
+}};
- ccprintf(ss, "%-10s ", mnemonic);
+output decoder {{
+ std::string
+ IntegerImm::generateDisassembly(Addr pc, const SymbolTable *symtab) const
+ {
+ 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;
}
# 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)
}};
// 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 (!EV5::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
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) const;
#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) const;
+ };
-#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) const
+ {
+ 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) const
+ {
+ 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];
- // 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 (suffix != "") {
+ mnem_str = csprintf("%s/%s", mnemonic, suffix);
+ }
+#endif
- // 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]);
- }
+ std::stringstream ss;
+ ccprintf(ss, "%-10s ", mnem_str.c_str());
- 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();
+ }
#if defined(linux)
const int AlphaFP::alphaToC99RoundingMode[] = {
{ "", "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)
}};
// Memory-format instructions: LoadAddress, Load, Store
//
-declare {{
+output header {{
/**
* Base class for general Alpha memory-format instructions.
*/
{
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)
- {
- return csprintf("%-10s %c%d,%d(r%d)", mnemonic,
- flags[IsFloating] ? 'f' : 'r', RA, MEMDISP, RB);
- }
+ std::string
+ generateDisassembly(Addr pc, const SymbolTable *symtab) const;
+
+ public:
+
+ const StaticInstPtr<AlphaISA> &eaCompInst() const { return eaCompPtr; }
+ const StaticInstPtr<AlphaISA> &memAccInst() const { return memAccPtr; }
};
/**
- * 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.
+ * Base class for memory-format instructions using a 32-bit
+ * displacement (i.e. most of them).
*/
- class MemoryNoDisp : public AlphaStaticInst
+ class MemoryDisp32 : 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)
- {
- }
+ /// Displacement for EA calculation (signed).
+ int32_t disp;
- std::string generateDisassembly(Addr pc, const SymbolTable *symtab)
+ /// 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 (r%d)", mnemonic, RB);
}
};
+
/**
- * Base class for "fake" effective-address computation
- * instructions returnded by eaCompInst().
+ * 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 EACompBase : public AlphaStaticInst
+ class MemoryNoDisp : public Memory
{
- public:
+ protected:
/// Constructor
- EACompBase(MachInst machInst)
- : AlphaStaticInst("(eacomp)", machInst, IntALU)
+ MemoryNoDisp(const char *mnem, MachInst _machInst, OpClass __opClass,
+ StaticInstPtr<AlphaISA> _eaCompPtr = nullStaticInstPtr,
+ StaticInstPtr<AlphaISA> _memAccPtr = nullStaticInstPtr)
+ : Memory(mnem, _machInst, __opClass, _eaCompPtr, _memAccPtr)
{
}
- 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"); }
+ std::string
+ generateDisassembly(Addr pc, const SymbolTable *symtab) const;
};
+}};
- /**
- * Base class for "fake" memory-access instructions returnded by
- * memAccInst().
- */
- class MemAccBase : public AlphaStaticInst
- {
- public:
- /// Constructor
- MemAccBase(MachInst machInst, OpClass __opClass)
- : AlphaStaticInst("(memacc)", machInst, __opClass)
- {
- }
-
- 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"); }
- };
+output decoder {{
+ std::string
+ Memory::generateDisassembly(Addr pc, const SymbolTable *symtab) const
+ {
+ 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) const
+ {
+ return csprintf("%-10s (r%d)", mnemonic, RB);
+ }
}};
-
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)
}};
/**
* "Fake" effective address computation class for "%(mnemonic)s".
*/
- class EAComp : public EACompBase
+ class EAComp : public %(base_class)s
{
public:
/// Constructor
- EAComp(MachInst machInst)
- : EACompBase(machInst)
- {
- %(ea_constructor)s;
- }
+ EAComp(MachInst machInst);
+
+ %(BasicExecDeclare)s
};
/**
* "Fake" memory access instruction class for "%(mnemonic)s".
*/
- class MemAcc : public MemAccBase
+ class MemAcc : public %(base_class)s
{
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;
+ %(BasicExecDeclare)s
+ };
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);
- 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;
- }
+ %(BasicExecDeclare)s
+ };
+}};
- if (fault == No_Fault) {
- %(simple_mem_wb)s;
- }
+def template LoadStoreConstructor {{
+ /** TODO: change op_class to AddrGenOp or something (requires
+ * creating new member of OpClass enum in op_class.hh, updating
+ * config files, etc.). */
+ inline %(class_name)s::EAComp::EAComp(MachInst machInst)
+ : %(base_class)s("%(mnemonic)s (EAComp)", machInst, IntAluOp)
+ {
+ %(ea_constructor)s;
+ }
- if (fault == No_Fault) {
- %(postacc_code)s;
- }
+ inline %(class_name)s::MemAcc::MemAcc(MachInst machInst)
+ : %(base_class)s("%(mnemonic)s (MemAcc)", 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 EACompExecute {{
+ Fault
+ %(class_name)s::EAComp::execute(%(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
+ {
+ Addr EA;
+ Fault fault = No_Fault;
- if (fault == No_Fault) {
- %(simple_nonmem_wb)s;
- }
+ %(fp_enable_check)s;
+ %(op_decl)s;
+ %(op_rd)s;
+ %(code)s;
- return fault;
+ if (fault == No_Fault) {
+ %(op_wb)s;
+ xc->setEA(EA);
}
- 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;
- }
+ return fault;
+ }
+}};
- if (fault == No_Fault) {
- %(dtld_mem_wb)s;
- }
+def template MemAccExecute {{
+ Fault
+ %(class_name)s::MemAcc::execute(%(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
+ {
+ Addr EA;
+ Fault fault = No_Fault;
+
+ %(fp_enable_check)s;
+ %(op_decl)s;
+ %(op_nonmem_rd)s;
+ EA = xc->getEA();
+
+ if (fault == No_Fault) {
+ %(op_mem_rd)s;
+ %(code)s;
+ }
- if (fault == No_Fault) {
- %(postacc_code)s;
- }
+ if (fault == No_Fault) {
+ %(op_mem_wb)s;
+ }
- if (fault == No_Fault) {
- %(dtld_nonmem_wb)s;
- }
+ if (fault == No_Fault) {
+ %(postacc_code)s;
+ }
- return fault;
+ if (fault == No_Fault) {
+ %(op_nonmem_wb)s;
}
- };
+
+ return fault;
+ }
}};
-def template PrefetchDeclare {{
- /**
- * Static instruction class for "%(mnemonic)s".
- */
- class %(class_name)s : public %(base_class)s
+def template LoadStoreExecute {{
+ Fault %(class_name)s::execute(%(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
{
- 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;
+ }
- %(fp_enable_check)s;
- %(exec_decl)s;
- %(dtld_nonmem_rd)s;
- %(ea_code)s;
+ return fault;
+ }
+}};
- if (fault == No_Fault) {
- dynInst->prefetch(EA, memAccessFlags);
- }
- return No_Fault;
+def template PrefetchExecute {{
+ Fault %(class_name)s::execute(%(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
+ {
+ Addr EA;
+ Fault fault = No_Fault;
+
+ %(fp_enable_check)s;
+ %(op_decl)s;
+ %(op_nonmem_rd)s;
+ %(ea_code)s;
+
+ 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
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).
# Would be nice to autogenerate this list, but oh well.
- valid_mem_flags = ['LOCKED', 'EVICT_NEXT', 'PF_EXCLUSIVE']
- inst_flags = []
- mem_flags = []
- for f in flags:
- if f in valid_mem_flags:
- mem_flags.append(f)
- else:
- inst_flags.append(f)
+ valid_mem_flags = ['LOCKED', 'NO_FAULT', 'EVICT_NEXT', 'PF_EXCLUSIVE']
+ mem_flags = [f for f in flags if f in valid_mem_flags]
+ inst_flags = [f for f in flags if f not in valid_mem_flags]
+ # add hook to get effective addresses into execution trace output.
+ ea_code += '\nif (traceData) { traceData->setAddr(EA); }\n'
+
+ # generate code block objects
ea_cblk = CodeBlock(ea_code)
memacc_cblk = CodeBlock(memacc_code)
postacc_cblk = CodeBlock(postacc_code)
+ # Some CPU models execute the memory operation as an atomic unit,
+ # while others want to separate them into an effective address
+ # computation and a memory access operation. As a result, we need
+ # to generate three StaticInst objects. Note that the latter two
+ # are nested inside the larger "atomic" one.
+
+ # generate InstObjParams for EAComp object
+ ea_iop = InstObjParams(name, Name, base_class, ea_cblk, inst_flags)
+
+ # generate InstObjParams for MemAcc object
+ memacc_iop = InstObjParams(name, Name, base_class, memacc_cblk, inst_flags)
+ # in the split execution model, the MemAcc portion is responsible
+ # for the post-access code.
+ memacc_iop.postacc_code = postacc_cblk.code
+
+ # generate InstObjParams for unified execution
cblk = CodeBlock(ea_code + memacc_code + postacc_code)
iop = InstObjParams(name, Name, base_class, cblk, inst_flags)
iop.memacc_code = memacc_cblk.code
iop.postacc_code = postacc_cblk.code
- mem_flags = string.join(mem_flags, '|')
- if mem_flags != '':
- iop.constructor += '\n\tmemAccessFlags = ' + mem_flags + ';'
-
- return iop.subst(declare_template, decode_template)
+ if mem_flags:
+ s = '\n\tmemAccessFlags = ' + string.join(mem_flags, '|') + ';'
+ iop.constructor += s
+ memacc_iop.constructor += s
+
+ # (header_output, decoder_output, decode_block, exec_output)
+ return (LoadStoreDeclare.subst(iop), LoadStoreConstructor.subst(iop),
+ decode_template.subst(iop),
+ EACompExecute.subst(ea_iop)
+ + MemAccExecute.subst(memacc_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']
+ pf_flags = list(pf_flags) + ['IsMemRef', 'IsLoad', 'IsDataPrefetch', 'MemReadOp', 'NO_FAULT']
- (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
{
protected:
/// Cached program counter from last disassembly
- Addr cachedPC;
+ mutable Addr cachedPC;
/// Cached symbol table pointer from last disassembly
- const SymbolTable *cachedSymtab;
+ mutable const SymbolTable *cachedSymtab;
/// Constructor
PCDependentDisassembly(const char *mnem, MachInst _machInst,
{
}
- 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) const;
};
/**
{
}
- 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 branchTarget(Addr branchPC) const;
- 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) const;
};
/**
{
}
- std::string generateDisassembly(Addr pc, const SymbolTable *symtab)
+ Addr branchTarget(ExecContext *xc) const;
+
+ std::string
+ generateDisassembly(Addr pc, const SymbolTable *symtab) const;
+ };
+}};
+
+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) const
+ {
+ 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) const
+ {
+ std::stringstream ss;
- ccprintf(ss, "%-10s ", mnemonic);
+ ccprintf(ss, "%-10s ", mnemonic);
+
+ // There's only one register arg (RA), but it could be
+ // either a source (the condition for conditional
+ // branches) or a destination (the link reg for
+ // unconditional branches)
+ if (_numSrcRegs > 0) {
+ printReg(ss, _srcRegIdx[0]);
+ ss << ",";
+ }
+ else if (_numDestRegs > 0) {
+ printReg(ss, _destRegIdx[0]);
+ ss << ",";
+ }
#ifdef SS_COMPATIBLE_DISASSEMBLY
- if (_numDestRegs == 0) {
- printReg(ss, 31);
- ss << ",";
- }
+ if (_numSrcRegs == 0 && _numDestRegs == 0) {
+ printReg(ss, 31);
+ ss << ",";
+ }
#endif
- if (_numDestRegs > 0) {
- printReg(ss, _destRegIdx[0]);
- ss << ",";
- }
+ Addr target = pc + 4 + disp;
- ccprintf(ss, "(r%d)", RB);
+ std::string str;
+ if (symtab && symtab->findSymbol(target, str))
+ ss << str;
+ else
+ ccprintf(ss, "0x%x", target);
- return ss.str();
+ return ss.str();
+ }
+
+ std::string
+ Jump::generateDisassembly(Addr pc, const SymbolTable *symtab) const
+ {
+ std::stringstream ss;
+
+ ccprintf(ss, "%-10s ", mnemonic);
+
+#ifdef SS_COMPATIBLE_DISASSEMBLY
+ if (_numDestRegs == 0) {
+ printReg(ss, 31);
+ ss << ",";
}
- };
+#endif
+
+ if (_numDestRegs > 0) {
+ printReg(ss, _destRegIdx[0]);
+ ss << ",";
+ }
+
+ ccprintf(ss, "(r%d)", RB);
+
+ return ss.str();
+ }
}};
def template JumpOrBranchDecode {{
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).
{
}
- std::string generateDisassembly(Addr pc, const SymbolTable *symtab)
- {
+ std::string
+ generateDisassembly(Addr pc, const SymbolTable *symtab) const;
+ };
+}};
+
+output decoder {{
+ std::string
+ EmulatedCallPal::generateDisassembly(Addr pc,
+ const SymbolTable *symtab) const
+ {
#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')
+def format EmulatedCallPal(code, *flags) {{
+ iop = InstObjParams(name, Name, 'EmulatedCallPal', CodeBlock(code), flags)
+ 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
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) const;
};
}};
+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) const
+ {
+ return csprintf("%-10s %#x", "call_pal", palFunc);
+ }
+}};
-def format CallPal(code) {{
- iop = InstObjParams(name, Name, 'CallPalBase', CodeBlock(code))
- return iop.subst('BasicDeclare', 'BasicDecode')
+def format CallPal(code, *flags) {{
+ iop = InstObjParams(name, Name, 'CallPalBase', CodeBlock(code), flags)
+ 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 = nullStaticInstPtr,
+ StaticInstPtr<AlphaISA> _memAccPtr = nullStaticInstPtr);
- std::string generateDisassembly(Addr pc, const SymbolTable *symtab)
- {
+ std::string
+ generateDisassembly(Addr pc, const SymbolTable *symtab) const;
+ };
+}};
+
+
+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) const
+ {
#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.
*/
{
}
- 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) const;
};
}};
+output decoder {{
+ std::string
+ HwMoveIPR::generateDisassembly(Addr pc, const SymbolTable *symtab) const
+ {
+ 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')
+ iop = InstObjParams(name, Name, 'HwMoveIPR', CodeBlock(code),
+ ['IprAccessOp'])
+ 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
FailUnimplemented(const char *_mnemonic, MachInst _machInst)
: AlphaStaticInst(_mnemonic, _machInst, No_OpClass)
{
+ // don't call execute() (which panics) if we're on a
+ // speculative path
+ flags[IsNonSpeculative] = true;
}
- 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) const;
};
/**
{
private:
/// Have we warned on this instruction yet?
- bool warned;
+ mutable bool warned;
public:
/// Constructor
WarnUnimplemented(const char *_mnemonic, MachInst _machInst)
: AlphaStaticInst(_mnemonic, _machInst, No_OpClass), warned(false)
{
+ // don't call execute() (which panics) if we're on a
+ // speculative path
+ flags[IsNonSpeculative] = true;
}
- 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) const;
+ };
+}};
- return No_Fault;
- }
+output decoder {{
+ std::string
+ FailUnimplemented::generateDisassembly(Addr pc,
+ const SymbolTable *symtab) const
+ {
+ return csprintf("%-10s (unimplemented)", mnemonic);
+ }
- std::string generateDisassembly(Addr pc, const SymbolTable *symtab)
- {
+ std::string
+ WarnUnimplemented::generateDisassembly(Addr pc,
+ const SymbolTable *symtab) const
+ {
#ifdef SS_COMPATIBLE_DISASSEMBLY
- return csprintf("%-10s", mnemonic);
+ return csprintf("%-10s", mnemonic);
#else
- return csprintf("%-10s (unimplemented)", mnemonic);
+ return csprintf("%-10s (unimplemented)", mnemonic);
#endif
- }
- };
+ }
}};
-def template WarnUnimplDeclare {{
- /**
- * Static instruction class for "%(mnemonic)s".
- */
- class %(class_name)s : public %(base_class)s
+output exec {{
+ Fault
+ FailUnimplemented::execute(%(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
{
- public:
- /// Constructor
- %(class_name)s(MachInst machInst)
- : %(base_class)s("%(mnemonic)s", machInst)
- {
+ 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) const
+ {
+ if (!warned) {
+ warn("instruction '%s' unimplemented\n", mnemonic);
+ warned = true;
}
- };
+
+ return No_Fault;
+ }
}};
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')
+ iop = InstObjParams(name, 'WarnUnimplemented')
+ decode_block = BasicDecodeWithMnemonic.subst(iop)
}};
-declare {{
+output header {{
/**
* Static instruction class for unknown (illegal) instructions.
* These cause simulator termination if they are executed in a
Unknown(MachInst _machInst)
: AlphaStaticInst("unknown", _machInst, No_OpClass)
{
+ // don't call execute() (which panics) if we're on a
+ // speculative path
+ flags[IsNonSpeculative] = true;
}
- 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;
- }
-
- 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;
- }
+ %(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) const;
};
}};
+////////////////////////////////////////////////////////////////////
+//
+// Unknown instructions
+//
+
+output decoder {{
+ std::string
+ Unknown::generateDisassembly(Addr pc, const SymbolTable *symtab) const
+ {
+ 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) const
+ {
+ 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
/// 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
}
}};
+////////////////////////////////////////////////////////////////////
+//
+// The actual decoder specification
+//
+
decode OPCODE default Unknown::unknown() {
format LoadAddress {
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 {
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 {
}
0x13: decode INTFUNC { // integer multiplies
- 0x00: mull({{ Rc.sl = Ra.sl * Rb_or_imm.sl; }}, IntMULT);
- 0x20: mulq({{ Rc = Ra * Rb_or_imm; }}, IntMULT);
+ 0x00: mull({{ Rc.sl = Ra.sl * Rb_or_imm.sl; }}, IntMultOp);
+ 0x20: mulq({{ Rc = Ra * Rb_or_imm; }}, IntMultOp);
0x30: umulh({{
uint64_t hi, lo;
mul128(Ra, Rb_or_imm, hi, lo);
Rc = hi;
- }}, IntMULT);
+ }}, IntMultOp);
0x40: mullv({{
// 32-bit multiply with trap on overflow
int64_t Rax = Ra.sl; // sign extended version of Ra.sl
if (sign_bits != 0 && sign_bits != mask(33))
fault = Integer_Overflow_Fault;
Rc.sl = tmp<31:0>;
- }}, IntMULT);
+ }}, IntMultOp);
0x60: mulqv({{
// 64-bit multiply with trap on overflow
uint64_t hi, lo;
(hi == mask(64) && lo<63:> == 1)))
fault = Integer_Overflow_Fault;
Rc = lo;
- }}, IntMULT);
+ }}, IntMultOp);
}
0x1c: decode INTFUNC {
0x00: decode RA { 31: sextb({{ Rc.sb = Rb_or_imm< 7:0>; }}); }
0x01: decode RA { 31: sextw({{ Rc.sw = Rb_or_imm<15:0>; }}); }
+ 0x32: ctlz({{
+ uint64_t count = 0;
+ uint64_t temp = Rb;
+ if (temp<63:32>) temp >>= 32; else count += 32;
+ if (temp<31:16>) temp >>= 16; else count += 16;
+ if (temp<15:8>) temp >>= 8; else count += 8;
+ if (temp<7:4>) temp >>= 4; else count += 4;
+ if (temp<3:2>) temp >>= 2; else count += 2;
+ if (temp<1:1>) temp >>= 1; else count += 1;
+ if ((temp<0:0>) != 0x1) count += 1;
+ Rc = count;
+ }}, IntAluOp);
+
+ 0x33: cttz({{
+ uint64_t count = 0;
+ uint64_t temp = Rb;
+ if (!(temp<31:0>)) { temp >>= 32; count += 32; }
+ if (!(temp<15:0>)) { temp >>= 16; count += 16; }
+ if (!(temp<7:0>)) { temp >>= 8; count += 8; }
+ if (!(temp<3:0>)) { temp >>= 4; count += 4; }
+ if (!(temp<1:0>)) { temp >>= 2; count += 2; }
+ if (!(temp<0:0> & ULL(0x1))) count += 1;
+ Rc = count;
+ }}, IntAluOp);
format FailUnimpl {
0x30: ctpop();
0x31: perr();
- 0x32: ctlz();
- 0x33: cttz();
0x34: unpkbw();
0x35: unpkbl();
0x36: pkwb();
format BasicOperateWithNopCheck {
0x70: decode RB {
- 31: ftoit({{ Rc = Fa.uq; }}, FloatCVT);
+ 31: ftoit({{ Rc = Fa.uq; }}, FloatCvtOp);
}
0x78: decode RB {
31: ftois({{ Rc.sl = t_to_s(Fa.uq); }},
- FloatCVT);
+ FloatCvtOp);
}
}
}
0x4: decode RB {
31: decode FP_FULLFUNC {
format BasicOperateWithNopCheck {
- 0x004: itofs({{ Fc.uq = s_to_t(Ra.ul); }}, FloatCVT);
- 0x024: itoft({{ Fc.uq = Ra.uq; }}, FloatCVT);
+ 0x004: itofs({{ Fc.uq = s_to_t(Ra.ul); }}, FloatCvtOp);
+ 0x024: itoft({{ Fc.uq = Ra.uq; }}, FloatCvtOp);
0x014: FailUnimpl::itoff(); // VAX-format conversion
}
}
if (Fb < 0.0)
fault = Arithmetic_Fault;
Fc = sqrt(Fb);
- }}, FloatSQRT);
+ }}, FloatSqrtOp);
#else
0x0b: sqrts({{
if (Fb.sf < 0.0)
fault = Arithmetic_Fault;
Fc.sf = sqrt(Fb.sf);
- }}, FloatSQRT);
+ }}, FloatSqrtOp);
#endif
0x2b: sqrtt({{
if (Fb < 0.0)
fault = Arithmetic_Fault;
Fc = sqrt(Fb);
- }}, FloatSQRT);
+ }}, FloatSqrtOp);
}
}
}
#ifdef SS_COMPATIBLE_FP
0x00: adds({{ Fc = Fa + Fb; }});
0x01: subs({{ Fc = Fa - Fb; }});
- 0x02: muls({{ Fc = Fa * Fb; }}, FloatMULT);
- 0x03: divs({{ Fc = Fa / Fb; }}, FloatDIV);
+ 0x02: muls({{ Fc = Fa * Fb; }}, FloatMultOp);
+ 0x03: divs({{ Fc = Fa / Fb; }}, FloatDivOp);
#else
0x00: adds({{ Fc.sf = Fa.sf + Fb.sf; }});
0x01: subs({{ Fc.sf = Fa.sf - Fb.sf; }});
- 0x02: muls({{ Fc.sf = Fa.sf * Fb.sf; }}, FloatMULT);
- 0x03: divs({{ Fc.sf = Fa.sf / Fb.sf; }}, FloatDIV);
+ 0x02: muls({{ Fc.sf = Fa.sf * Fb.sf; }}, FloatMultOp);
+ 0x03: divs({{ Fc.sf = Fa.sf / Fb.sf; }}, FloatDivOp);
#endif
0x20: addt({{ Fc = Fa + Fb; }});
0x21: subt({{ Fc = Fa - Fb; }});
- 0x22: mult({{ Fc = Fa * Fb; }}, FloatMULT);
- 0x23: divt({{ Fc = Fa / Fb; }}, FloatDIV);
+ 0x22: mult({{ Fc = Fa * Fb; }}, FloatMultOp);
+ 0x23: divt({{ Fc = Fa / Fb; }}, FloatDivOp);
}
}
1: decode FP_FULLFUNC {
format BasicOperateWithNopCheck {
0x0a5, 0x5a5: cmpteq({{ Fc = (Fa == Fb) ? 2.0 : 0.0; }},
- FloatCMP);
+ FloatCmpOp);
0x0a7, 0x5a7: cmptle({{ Fc = (Fa <= Fb) ? 2.0 : 0.0; }},
- FloatCMP);
+ FloatCmpOp);
0x0a6, 0x5a6: cmptlt({{ Fc = (Fa < Fb) ? 2.0 : 0.0; }},
- FloatCMP);
+ FloatCmpOp);
0x0a4, 0x5a4: cmptun({{ // unordered
Fc = (!(Fa < Fb) && !(Fa == Fb) && !(Fa > Fb)) ? 2.0 : 0.0;
- }}, FloatCMP);
+ }}, FloatCmpOp);
}
}
// miscellaneous mem-format ops
0x18: decode MEMFUNC {
format WarnUnimpl {
- 0x0000: trapb();
- 0x0400: excb();
- 0x4000: mb();
- 0x4400: wmb();
0x8000: fetch();
0xa000: fetch_m();
0xe800: ecb();
}
format MiscPrefetch {
- 0xf800: wh64({{ EA = Rb; }},
- {{ memAccessObj->writeHint(EA, 64); }},
- IsMemRef, IsStore, WrPort);
+ 0xf800: wh64({{ EA = Rb & ~ULL(63); }},
+ {{ xc->writeHint(EA, 64, memAccessFlags); }},
+ IsMemRef, IsDataPrefetch, IsStore, MemWriteOp,
+ NO_FAULT);
}
format BasicOperate {
- 0xc000: rpcc({{ Ra = curTick; }});
+ 0xc000: rpcc({{
+#ifdef FULL_SYSTEM
+ /* Rb is a fake dependency so here is a fun way to get
+ * the parser to understand that.
+ */
+ Ra = xc->readIpr(AlphaISA::IPR_CC, fault) + (Rb & 0);
+
+#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, MemReadOp);
+ 0x4400: wmb({{ }}, IsWriteBarrier, MemWriteOp);
}
#ifdef FULL_SYSTEM
format BasicOperate {
0xe000: rc({{
- Ra = xc->regs.intrflag;
- if (!xc->misspeculating()) {
- xc->regs.intrflag = 0;
- }
- }}, No_OpClass);
+ Ra = xc->readIntrFlag();
+ xc->setIntrFlag(0);
+ }}, IsNonSpeculative);
0xf000: rs({{
- Ra = xc->regs.intrflag;
- if (!xc->misspeculating()) {
- xc->regs.intrflag = 1;
- }
- }}, No_OpClass);
+ Ra = xc->readIntrFlag();
+ xc->setIntrFlag(1);
+ }}, IsNonSpeculative);
}
#else
format FailUnimpl {
#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;
}
-
- if (dopal) {
- if (!xc->misspeculating()) {
- AlphaISA::swap_palshadow(&xc->regs, true);
+ else {
+ // check to see if simulator wants to do something special
+ // on this PAL call (including maybe suppress it)
+ bool dopal = xc->simPalCheck(palFunc);
+
+ if (dopal) {
+ AlphaISA::swap_palshadow(&xc->xcBase()->regs, true);
+ xc->setIpr(AlphaISA::IPR_EXC_ADDR, NPC);
+ 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;
}
- }});
+ }}, IsNonSpeculative);
#else
0x00: decode PALFUNC {
format EmulatedCallPal {
0x00: halt ({{
- if (!xc->misspeculating())
- SimExit(curTick, "halt instruction encountered");
- }});
+ SimExit(curTick, "halt instruction encountered");
+ }}, IsNonSpeculative);
0x83: callsys({{
- if (!xc->misspeculating())
- xc->syscall();
- }});
+ xc->syscall();
+ }}, IsNonSpeculative);
// Read uniq reg into ABI return value register (r0)
0x9e: rduniq({{ R0 = Runiq; }});
// Write uniq reg with value from ABI arg register (r16)
}
format BasicOperate {
- 0x1e: hw_rei({{ xc->hwrei(); }});
+ 0x1e: hw_rei({{ xc->hwrei(); }}, IsSerializing);
// M5 special opcodes use the reserved 0x01 opcode space
0x01: decode M5FUNC {
0x00: arm({{
- if (!xc->misspeculating()) {
- Annotate::ARM(xc);
- xc->kernelStats.arm();
- }
- }});
+ AlphaPseudo::arm(xc->xcBase());
+ }}, IsNonSpeculative);
0x01: quiesce({{
- if (!xc->misspeculating())
- AlphaPseudo::quiesce(xc);
- }});
+ AlphaPseudo::quiesce(xc->xcBase());
+ }}, IsNonSpeculative);
0x10: ivlb({{
- if (!xc->misspeculating()) {
- Annotate::BeginInterval(xc);
- xc->kernelStats.ivlb();
- }
- }}, No_OpClass);
+ AlphaPseudo::ivlb(xc->xcBase());
+ }}, No_OpClass, IsNonSpeculative);
0x11: ivle({{
- if (!xc->misspeculating())
- Annotate::EndInterval(xc);
- }}, No_OpClass);
+ AlphaPseudo::ivle(xc->xcBase());
+ }}, No_OpClass, IsNonSpeculative);
0x20: m5exit_old({{
- if (!xc->misspeculating())
- AlphaPseudo::m5exit_old(xc);
- }}, No_OpClass);
+ AlphaPseudo::m5exit_old(xc->xcBase());
+ }}, No_OpClass, IsNonSpeculative);
0x21: m5exit({{
- if (!xc->misspeculating())
- AlphaPseudo::m5exit(xc);
- }}, No_OpClass);
- 0x30: initparam({{ Ra = xc->cpu->system->init_param; }});
+ AlphaPseudo::m5exit(xc->xcBase());
+ }}, No_OpClass, IsNonSpeculative);
+ 0x30: initparam({{ Ra = xc->xcBase()->cpu->system->init_param; }});
0x40: resetstats({{
- if (!xc->misspeculating())
- AlphaPseudo::resetstats(xc);
- }});
+ AlphaPseudo::resetstats(xc->xcBase());
+ }}, IsNonSpeculative);
0x41: dumpstats({{
- if (!xc->misspeculating())
- AlphaPseudo::dumpstats(xc);
- }});
+ AlphaPseudo::dumpstats(xc->xcBase());
+ }}, IsNonSpeculative);
0x42: dumpresetstats({{
- if (!xc->misspeculating())
- AlphaPseudo::dumpresetstats(xc);
- }});
+ AlphaPseudo::dumpresetstats(xc->xcBase());
+ }}, IsNonSpeculative);
0x43: m5checkpoint({{
- if (!xc->misspeculating())
- AlphaPseudo::m5checkpoint(xc);
- }});
+ AlphaPseudo::m5checkpoint(xc->xcBase());
+ }}, IsNonSpeculative);
+ 0x50: m5readfile({{
+ AlphaPseudo::readfile(xc->xcBase());
+ }}, IsNonSpeculative);
+ 0x51: m5break({{
+ AlphaPseudo::debugbreak(xc->xcBase());
+ }}, IsNonSpeculative);
+ 0x52: m5switchcpu({{
+ AlphaPseudo::switchcpu(xc->xcBase());
+ }}, IsNonSpeculative);
+
}
}
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 {
}});
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 {