#include "cpu/simple_cpu/simple_cpu.hh"
#include "cpu/static_inst.hh"
#include "sim/annotation.hh"
-#include "sim/serialize.hh"
-#include "sim/sim_events.hh"
-#include "sim/sim_stats.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 AlphaISA;
trappingMode((enum TrappingMode)FP_TRAPMODE)
{
if (trappingMode != Imprecise) {
- warn("Warning: precise FP traps unimplemented\n");
+ warn("precise FP traps unimplemented\n");
}
}
{
std::string mnem_str(mnemonic);
- mnem_str += ((_destRegIdx[0] >= FP_Base_DepTag)
- ? fpTrappingModeSuffix[trappingMode]
- : intTrappingModeSuffix[trappingMode]);
- mnem_str += roundingModeSuffix[roundingMode];
+#ifndef SS_COMPATIBLE_DISASSEMBLY
+ std::string suffix("");
+ suffix += ((_destRegIdx[0] >= FP_Base_DepTag)
+ ? fpTrappingModeSuffix[trappingMode]
+ : intTrappingModeSuffix[trappingMode]);
+ suffix += roundingModeSuffix[roundingMode];
- std::stringstream ss;
+ 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
*/
class %(class_name)s : public %(base_class)s
{
+ protected:
+
+ /**
+ * "Fake" effective address computation class for "%(mnemonic)s".
+ */
+ class EAComp : public EACompBase
+ {
+ public:
+ /// Constructor
+ EAComp(MachInst machInst)
+ : EACompBase(machInst)
+ {
+ %(ea_constructor)s;
+ }
+ };
+
+ /**
+ * "Fake" memory access instruction class for "%(mnemonic)s".
+ */
+ class MemAcc : public MemAccBase
+ {
+ public:
+ /// Constructor
+ MemAcc(MachInst machInst)
+ : MemAccBase(machInst, %(op_class)s)
+ {
+ %(memacc_constructor)s;
+ }
+ };
+
+ /// Pointer to EAComp object.
+ StaticInstPtr<AlphaISA> eaCompPtr;
+ /// Pointer to MemAcc object.
+ StaticInstPtr<AlphaISA> memAccPtr;
+
public:
+
+ StaticInstPtr<AlphaISA> eaCompInst() { return eaCompPtr; }
+ StaticInstPtr<AlphaISA> memAccInst() { return memAccPtr; }
+
/// Constructor
%(class_name)s(MachInst machInst)
- : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s)
+ : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s),
+ eaCompPtr(new EAComp(machInst)), memAccPtr(new MemAcc(machInst))
{
%(constructor)s;
}
{
}
- Addr branchTarget(Addr branchPC)
+ Addr branchTarget(Addr branchPC) const
{
return branchPC + 4 + disp;
}
{
}
+ Addr branchTarget(ExecContext *xc) const
+ {
+ Addr NPC = xc->readPC() + 4;
+ uint64_t Rb = xc->readIntReg(_srcRegIdx[0]);
+ return (Rb & ~3) | (NPC & 1);
+ }
+
std::string generateDisassembly(Addr pc, const SymbolTable *symtab)
{
std::stringstream ss;
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,
: AlphaStaticInst(mnem, _machInst, __opClass),
palFunc(PALFUNC)
{
- int palPriv = ((machInst & 0x80) != 0);
- int shortPalFunc = (machInst & 0x3f);
- palOffset = 0x2001 + (palPriv << 12) + (shortPalFunc << 6);
+ // From the 21164 HRM (paraphrased):
+ // Bit 7 of the function code (mask 0x80) indicates
+ // whether the call is privileged (bit 7 == 0) or
+ // unprivileged (bit 7 == 1). The privileged call table
+ // starts at 0x2000, the unprivielged call table starts at
+ // 0x3000. Bits 5-0 (mask 0x3f) are used to calculate the
+ // offset.
+ const int palPrivMask = 0x80;
+ const int palOffsetMask = 0x3f;
+
+ // Pal call is invalid unless all other bits are 0
+ palValid = ((machInst & ~(palPrivMask | palOffsetMask)) == 0);
+ palPriv = ((machInst & palPrivMask) == 0);
+ int shortPalFunc = (machInst & palOffsetMask);
+ // Add 1 to base to set pal-mode bit
+ palOffset = (palPriv ? 0x2001 : 0x3001) + (shortPalFunc << 6);
}
std::string generateDisassembly(Addr pc, const SymbolTable *symtab)
Trace::InstRecord *traceData)
{
if (!warned) {
- warn("Warning: instruction '%s' unimplemented\n", mnemonic);
+ warn("instruction '%s' unimplemented\n", mnemonic);
warned = true;
}
Trace::InstRecord *traceData)
{
if (!xc->spec_mode && !warned) {
- warn("Warning: instruction '%s' unimplemented\n", mnemonic);
+ warn("instruction '%s' unimplemented\n", mnemonic);
warned = true;
}
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 = memAccessObj->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 {
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 =memAccessObj->copy(EA);}},
+ IsMemRef, IsStore, IsCopy);
}
format StoreCond {
// 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 BasicOperate {
0xc000: rpcc({{ Ra = curTick; }});
+
+ // 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
if (!xc->misspeculating()) {
xc->regs.intrflag = 0;
}
- }}, No_OpClass);
+ }});
0xf000: rs({{
Ra = xc->regs.intrflag;
if (!xc->misspeculating()) {
xc->regs.intrflag = 1;
}
- }}, No_OpClass);
+ }});
}
#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;
}
+ 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);
+
+ Annotate::Callpal(xc, palFunc);
+
+ if (dopal) {
+ AlphaISA::swap_palshadow(&xc->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
}
}});
0x01: quiesce({{
- if (!xc->misspeculating()) {
- Annotate::QUIESCE(xc);
- xc->setStatus(ExecContext::Suspended);
- xc->kernelStats.quiesce();
- }
+ if (!xc->misspeculating())
+ AlphaPseudo::quiesce(xc);
}});
0x10: ivlb({{
if (!xc->misspeculating()) {
}}, No_OpClass);
0x20: m5exit_old({{
if (!xc->misspeculating())
- SimExit(curTick, "m5_exit_old instruction encountered");
+ AlphaPseudo::m5exit_old(xc);
}}, No_OpClass);
0x21: m5exit({{
- if (!xc->misspeculating()) {
- Tick delay = xc->regs.intRegFile[16];
- Tick when = curTick + NS2Ticks(delay);
- SimExit(when, "m5_exit instruction encountered");
- }
+ if (!xc->misspeculating())
+ AlphaPseudo::m5exit(xc);
}}, No_OpClass);
- 0x30: initparam({{ Ra = xc->cpu->system->init_param; }});
+ 0x30: initparam({{ Ra = cpu->system->init_param; }});
0x40: resetstats({{
- if (!xc->misspeculating()) {
- using namespace Statistics;
- Tick delay = xc->regs.intRegFile[16];
- Tick period = xc->regs.intRegFile[17];
-
- Tick when = curTick + NS2Ticks(delay);
- Tick repeat = NS2Ticks(period);
-
- SetupEvent(Reset, when, repeat);
- }
+ if (!xc->misspeculating())
+ AlphaPseudo::resetstats(xc);
}});
0x41: dumpstats({{
- if (!xc->misspeculating()) {
- using namespace Statistics;
- Tick delay = xc->regs.intRegFile[16];
- Tick period = xc->regs.intRegFile[17];
-
- Tick when = curTick + NS2Ticks(delay);
- Tick repeat = NS2Ticks(period);
-
- SetupEvent(Dump, when, repeat);
- }
+ if (!xc->misspeculating())
+ AlphaPseudo::dumpstats(xc);
}});
0x42: dumpresetstats({{
- if (!xc->misspeculating()) {
- using namespace Statistics;
- Tick delay = xc->regs.intRegFile[16];
- Tick period = xc->regs.intRegFile[17];
-
- Tick when = curTick + NS2Ticks(delay);
- Tick repeat = NS2Ticks(period);
-
- SetupEvent(Dump|Reset, when, repeat);
- }
+ if (!xc->misspeculating())
+ AlphaPseudo::dumpresetstats(xc);
}});
0x43: m5checkpoint({{
- if (!xc->misspeculating()) {
- Tick delay = xc->regs.intRegFile[16];
- Tick period = xc->regs.intRegFile[17];
-
- Tick when = curTick + NS2Ticks(delay);
- Tick repeat = NS2Ticks(period);
-
- SetupCheckpoint(when, repeat);
- }
+ if (!xc->misspeculating())
+ AlphaPseudo::m5checkpoint(xc);
}});
}
}