diff options
70 files changed, 3177 insertions, 672 deletions
diff --git a/configs/common/FSConfig.py b/configs/common/FSConfig.py index 546569f30..1c0a56362 100644 --- a/configs/common/FSConfig.py +++ b/configs/common/FSConfig.py @@ -84,10 +84,19 @@ def makeSparcSystem(mem_mode, mdesc = None): # generic system mdesc = SysConfig() self.readfile = mdesc.script() + self.iobus = Bus(bus_id=0) self.membus = Bus(bus_id=1) - self.physmem = PhysicalMemory(range = AddrRange(mdesc.mem())) + self.bridge = Bridge() + self.t1000 = T1000() + self.t1000.attachIO(self.iobus) + self.physmem = PhysicalMemory(range = AddrRange(mdesc.mem()), zero = True) + self.bridge.side_a = self.iobus.port + self.bridge.side_b = self.membus.port self.physmem.port = self.membus.port self.rom.port = self.membus.port + self.nvram.port = self.membus.port + self.hypervisor_desc.port = self.membus.port + self.partition_desc.port = self.membus.port self.intrctrl = IntrControl() self.mem_mode = mem_mode self.kernel = binary('vmlinux') @@ -95,6 +104,9 @@ def makeSparcSystem(mem_mode, mdesc = None): self.reset_bin = binary('reset.bin') self.hypervisor_bin = binary('q.bin') self.openboot_bin = binary('openboot.bin') + self.nvram_bin = binary('nvram1') + self.hypervisor_desc_bin = binary('1up-hv.bin') + self.partition_desc_bin = binary('1up-md.bin') return self diff --git a/src/arch/alpha/regfile.hh b/src/arch/alpha/regfile.hh index ff5830822..c73c32bad 100644 --- a/src/arch/alpha/regfile.hh +++ b/src/arch/alpha/regfile.hh @@ -189,6 +189,11 @@ namespace AlphaISA } }; + static inline int flattenIntIndex(ThreadContext * tc, int reg) + { + return reg; + } + void copyRegs(ThreadContext *src, ThreadContext *dest); void copyMiscRegs(ThreadContext *src, ThreadContext *dest); diff --git a/src/arch/alpha/syscallreturn.hh b/src/arch/alpha/syscallreturn.hh index 803c3b7da..47b4ac8c7 100644 --- a/src/arch/alpha/syscallreturn.hh +++ b/src/arch/alpha/syscallreturn.hh @@ -32,54 +32,25 @@ #ifndef __ARCH_ALPHA_SYSCALLRETURN_HH__ #define __ARCH_ALPHA_SYSCALLRETURN_HH__ -class SyscallReturn { - public: - template <class T> - SyscallReturn(T v, bool s) - { - retval = (uint64_t)v; - success = s; - } - - template <class T> - SyscallReturn(T v) - { - success = (v >= 0); - retval = (uint64_t)v; - } - - ~SyscallReturn() {} - - SyscallReturn& operator=(const SyscallReturn& s) { - retval = s.retval; - success = s.success; - return *this; - } - - bool successful() { return success; } - uint64_t value() { return retval; } - - - private: - uint64_t retval; - bool success; -}; +#include "cpu/thread_context.hh" +#include "sim/syscallreturn.hh" namespace AlphaISA { - static inline void setSyscallReturn(SyscallReturn return_value, RegFile *regs) + static inline void setSyscallReturn(SyscallReturn return_value, + ThreadContext * tc) { // check for error condition. Alpha syscall convention is to // indicate success/failure in reg a3 (r19) and put the // return value itself in the standard return value reg (v0). if (return_value.successful()) { // no error - regs->setIntReg(SyscallSuccessReg, 0); - regs->setIntReg(ReturnValueReg, return_value.value()); + tc->setIntReg(SyscallSuccessReg, 0); + tc->setIntReg(ReturnValueReg, return_value.value()); } else { // got an error, return details - regs->setIntReg(SyscallSuccessReg, (IntReg)-1); - regs->setIntReg(ReturnValueReg, -return_value.value()); + tc->setIntReg(SyscallSuccessReg, (IntReg)-1); + tc->setIntReg(ReturnValueReg, -return_value.value()); } } } diff --git a/src/arch/mips/regfile/regfile.hh b/src/arch/mips/regfile/regfile.hh index dee883c4a..7b57b31f5 100644 --- a/src/arch/mips/regfile/regfile.hh +++ b/src/arch/mips/regfile/regfile.hh @@ -173,6 +173,11 @@ namespace MipsISA } }; + static inline int flattenIntIndex(ThreadContext * tc, int reg) + { + return reg; + } + void copyRegs(ThreadContext *src, ThreadContext *dest); void copyMiscRegs(ThreadContext *src, ThreadContext *dest); diff --git a/src/arch/mips/syscallreturn.hh b/src/arch/mips/syscallreturn.hh index ef1093caf..47290b634 100644 --- a/src/arch/mips/syscallreturn.hh +++ b/src/arch/mips/syscallreturn.hh @@ -32,51 +32,22 @@ #ifndef __ARCH_MIPS_SYSCALLRETURN_HH__ #define __ARCH_MIPS_SYSCALLRETURN_HH__ -class SyscallReturn { - public: - template <class T> - SyscallReturn(T v, bool s) - { - retval = (uint32_t)v; - success = s; - } - - template <class T> - SyscallReturn(T v) - { - success = (v >= 0); - retval = (uint32_t)v; - } - - ~SyscallReturn() {} - - SyscallReturn& operator=(const SyscallReturn& s) { - retval = s.retval; - success = s.success; - return *this; - } - - bool successful() { return success; } - uint64_t value() { return retval; } - - - private: - uint64_t retval; - bool success; -}; +#include "sim/syscallreturn.hh" +#include "cpu/thread_context.hh" namespace MipsISA { - static inline void setSyscallReturn(SyscallReturn return_value, RegFile *regs) + static inline void setSyscallReturn(SyscallReturn return_value, + ThreadContext *tc) { if (return_value.successful()) { // no error - regs->setIntReg(SyscallSuccessReg, 0); - regs->setIntReg(ReturnValueReg1, return_value.value()); + tc->setIntReg(SyscallSuccessReg, 0); + tc->setIntReg(ReturnValueReg1, return_value.value()); } else { // got an error, return details - regs->setIntReg(SyscallSuccessReg, (IntReg) -1); - regs->setIntReg(ReturnValueReg1, -return_value.value()); + tc->setIntReg(SyscallSuccessReg, (IntReg) -1); + tc->setIntReg(ReturnValueReg1, -return_value.value()); } } } diff --git a/src/arch/sparc/faults.cc b/src/arch/sparc/faults.cc index 4cf411d3b..4326e8b67 100644 --- a/src/arch/sparc/faults.cc +++ b/src/arch/sparc/faults.cc @@ -284,6 +284,11 @@ void enterREDState(ThreadContext *tc) //HPSTATE.hpriv = 1 HPSTATE |= (1 << 2); tc->setMiscRegWithEffect(MISCREG_HPSTATE, HPSTATE); + //PSTATE.priv is set to 1 here. The manual says it should be 0, but + //Legion sets it to 1. + MiscReg PSTATE = tc->readMiscReg(MISCREG_PSTATE); + PSTATE |= (1 << 2); + tc->setMiscRegWithEffect(MISCREG_PSTATE, PSTATE); } /** @@ -297,10 +302,12 @@ void doREDFault(ThreadContext *tc, TrapType tt) MiscReg TSTATE = tc->readMiscReg(MISCREG_TSTATE); MiscReg PSTATE = tc->readMiscReg(MISCREG_PSTATE); MiscReg HPSTATE = tc->readMiscReg(MISCREG_HPSTATE); - MiscReg CCR = tc->readMiscReg(MISCREG_CCR); + //MiscReg CCR = tc->readMiscReg(MISCREG_CCR); + MiscReg CCR = tc->readIntReg(NumIntArchRegs + 2); MiscReg ASI = tc->readMiscReg(MISCREG_ASI); MiscReg CWP = tc->readMiscReg(MISCREG_CWP); - MiscReg CANSAVE = tc->readMiscReg(MISCREG_CANSAVE); + //MiscReg CANSAVE = tc->readMiscReg(MISCREG_CANSAVE); + MiscReg CANSAVE = tc->readMiscReg(NumIntArchRegs + 3); MiscReg GL = tc->readMiscReg(MISCREG_GL); MiscReg PC = tc->readPC(); MiscReg NPC = tc->readNextPC(); @@ -340,10 +347,12 @@ void doREDFault(ThreadContext *tc, TrapType tt) PSTATE |= (1 << 4); //set PSTATE.am to 0 PSTATE &= ~(1 << 3); - //set PSTATE.priv to 0 - PSTATE &= ~(1 << 2); +/* //set PSTATE.priv to 0 + PSTATE &= ~(1 << 2);*/ //set PSTATE.ie to 0 - PSTATE &= ~(1 << 1); + //PSTATE.priv is set to 1 here. The manual says it should be 0, but + //Legion sets it to 1. + PSTATE |= (1 << 2); //set PSTATE.cle to 0 PSTATE &= ~(1 << 9); //PSTATE.tle is unchanged @@ -389,10 +398,12 @@ void doNormalFault(ThreadContext *tc, TrapType tt, bool gotoHpriv) MiscReg TSTATE = tc->readMiscReg(MISCREG_TSTATE); MiscReg PSTATE = tc->readMiscReg(MISCREG_PSTATE); MiscReg HPSTATE = tc->readMiscReg(MISCREG_HPSTATE); - MiscReg CCR = tc->readMiscReg(MISCREG_CCR); + //MiscReg CCR = tc->readMiscReg(MISCREG_CCR); + MiscReg CCR = tc->readIntReg(NumIntArchRegs + 2); MiscReg ASI = tc->readMiscReg(MISCREG_ASI); MiscReg CWP = tc->readMiscReg(MISCREG_CWP); - MiscReg CANSAVE = tc->readMiscReg(MISCREG_CANSAVE); + //MiscReg CANSAVE = tc->readMiscReg(MISCREG_CANSAVE); + MiscReg CANSAVE = tc->readIntReg(NumIntArchRegs + 3); MiscReg GL = tc->readMiscReg(MISCREG_GL); MiscReg PC = tc->readPC(); MiscReg NPC = tc->readNextPC(); @@ -451,7 +462,9 @@ void doNormalFault(ThreadContext *tc, TrapType tt, bool gotoHpriv) else { //PSTATE.priv = 0 - PSTATE &= ~(1 << 2); + //PSTATE.priv is set to 1 here. The manual says it should be 0, but + //Legion sets it to 1. + PSTATE |= (1 << 2); //PSTATE.cle = 0 PSTATE &= ~(1 << 9); } @@ -533,20 +546,22 @@ void SparcFaultBase::invoke(ThreadContext * tc) Addr PC, NPC; PrivilegeLevel current; - if(!(PSTATE & (1 << 2))) - current = User; - else if(!(HPSTATE & (1 << 2))) + if(HPSTATE & (1 << 2)) + current = Hyperprivileged; + else if(PSTATE & (1 << 2)) current = Privileged; else - current = Hyperprivileged; + current = User; PrivilegeLevel level = getNextLevel(current); if(HPSTATE & (1 << 5) || TL == MaxTL - 1) { getREDVector(5, PC, NPC); - enterREDState(tc); doREDFault(tc, TT); + //This changes the hpstate and pstate, so we need to make sure we + //save the old version on the trap stack in doREDFault. + enterREDState(tc); } else if(TL == MaxTL) { @@ -578,9 +593,6 @@ void SparcFaultBase::invoke(ThreadContext * tc) void PowerOnReset::invoke(ThreadContext * tc) { - //First, enter RED state. - enterREDState(tc); - //For SPARC, when a system is first started, there is a power //on reset Trap which sets the processor into the following state. //Bits that aren't set aren't defined on startup. @@ -589,15 +601,28 @@ void PowerOnReset::invoke(ThreadContext * tc) tc->setMiscReg(MISCREG_TT, trapType()); tc->setMiscRegWithEffect(MISCREG_GL, MaxGL); - //Turn on pef, set everything else to 0 - tc->setMiscReg(MISCREG_PSTATE, 1 << 4); + //Turn on pef and priv, set everything else to 0 + tc->setMiscReg(MISCREG_PSTATE, (1 << 4) | (1 << 2)); //Turn on red and hpriv, set everything else to 0 - tc->setMiscReg(MISCREG_HPSTATE, (1 << 5) | (1 << 2)); + MiscReg HPSTATE = tc->readMiscReg(MISCREG_HPSTATE); + //HPSTATE.red = 1 + HPSTATE |= (1 << 5); + //HPSTATE.hpriv = 1 + HPSTATE |= (1 << 2); + //HPSTATE.ibe = 0 + HPSTATE &= ~(1 << 10); + //HPSTATE.tlz = 0 + HPSTATE &= ~(1 << 0); + tc->setMiscReg(MISCREG_HPSTATE, HPSTATE); //The tick register is unreadable by nonprivileged software tc->setMiscReg(MISCREG_TICK, 1ULL << 63); + //Enter RED state. We do this last so that the actual state preserved in + //the trap stack is the state from before this fault. + enterREDState(tc); + Addr PC, NPC; getREDVector(trapType(), PC, NPC); tc->setPC(PC); @@ -665,19 +690,21 @@ void PageTableFault::invoke(ThreadContext *tc) { Process *p = tc->getProcessPtr(); - // address is higher than the stack region or in the current stack region - if (vaddr > p->stack_base || vaddr > p->stack_min) - FaultBase::invoke(tc); - - // We've accessed the next page - if (vaddr > p->stack_min - PageBytes) { + // We've accessed the next page of the stack, so extend the stack + // to cover it. + if(vaddr < p->stack_min && vaddr >= p->stack_min - PageBytes) + { p->stack_min -= PageBytes; - if (p->stack_base - p->stack_min > 8*1024*1024) + if(p->stack_base - p->stack_min > 8*1024*1024) fatal("Over max stack size for one thread\n"); p->pTable->allocate(p->stack_min, PageBytes); warn("Increasing stack size by one page."); - } else { - FaultBase::invoke(tc); + } + // Otherwise, we have an unexpected page fault. Report that fact, + // and what address was accessed to cause the fault. + else + { + panic("Page table fault when accessing virtual address %#x\n", vaddr); } } diff --git a/src/arch/sparc/floatregfile.hh b/src/arch/sparc/floatregfile.hh index 9d760c9ff..72803a5e0 100644 --- a/src/arch/sparc/floatregfile.hh +++ b/src/arch/sparc/floatregfile.hh @@ -38,10 +38,15 @@ #include <string> +class Checkpoint; + namespace SparcISA { std::string getFloatRegName(RegIndex); + const int NumFloatArchRegs = 64; + const int NumFloatRegs = 64; + typedef float float32_t; typedef double float64_t; //FIXME long double refers to a 10 byte float, rather than a diff --git a/src/arch/sparc/intregfile.cc b/src/arch/sparc/intregfile.cc index 358368e5f..594fe4bea 100644 --- a/src/arch/sparc/intregfile.cc +++ b/src/arch/sparc/intregfile.cc @@ -31,6 +31,7 @@ #include "arch/sparc/intregfile.hh" #include "base/trace.hh" +#include "base/misc.hh" #include "sim/serialize.hh" #include <string.h> @@ -42,7 +43,7 @@ class Checkpoint; string SparcISA::getIntRegName(RegIndex index) { - static std::string intRegName[NumIntRegs] = + static std::string intRegName[NumIntArchRegs] = {"g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7", "o0", "o1", "o2", "o3", "o4", "o5", "o6", "o7", "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7", @@ -65,6 +66,7 @@ void IntRegFile::clear() memset(regGlobals[x], 0, sizeof(IntReg) * RegsPerFrame); for(int x = 0; x < 2 * NWindows; x++) memset(regSegments[x], 0, sizeof(IntReg) * RegsPerFrame); + memset(regs, 0, sizeof(IntReg) * NumIntRegs); } IntRegFile::IntRegFile() @@ -77,31 +79,39 @@ IntRegFile::IntRegFile() IntReg IntRegFile::readReg(int intReg) { + DPRINTF(Sparc, "Read register %d = 0x%x\n", intReg, regs[intReg]); + return regs[intReg]; IntReg val; - if(intReg < NumRegularIntRegs) + if(intReg < NumIntArchRegs) val = regView[intReg >> FrameOffsetBits][intReg & FrameOffsetMask]; - else if((intReg -= NumRegularIntRegs) < NumMicroIntRegs) + else if((intReg -= NumIntArchRegs) < NumMicroIntRegs) val = microRegs[intReg]; else - panic("Tried to read non-existant integer register %d, %d\n", NumRegularIntRegs + NumMicroIntRegs + intReg, intReg); + panic("Tried to read non-existant integer register %d, %d\n", + NumIntArchRegs + NumMicroIntRegs + intReg, intReg); DPRINTF(Sparc, "Read register %d = 0x%x\n", intReg, val); return val; } -Fault IntRegFile::setReg(int intReg, const IntReg &val) +void IntRegFile::setReg(int intReg, const IntReg &val) { if(intReg) { DPRINTF(Sparc, "Wrote register %d = 0x%x\n", intReg, val); - if(intReg < NumRegularIntRegs) + regs[intReg] = val; + } + return; + if(intReg) + { + DPRINTF(Sparc, "Wrote register %d = 0x%x\n", intReg, val); + if(intReg < NumIntArchRegs) regView[intReg >> FrameOffsetBits][intReg & FrameOffsetMask] = val; - else if((intReg -= NumRegularIntRegs) < NumMicroIntRegs) + else if((intReg -= NumIntArchRegs) < NumMicroIntRegs) microRegs[intReg] = val; else panic("Tried to set non-existant integer register\n"); } - return NoFault; } //This doesn't effect the actual CWP register. diff --git a/src/arch/sparc/intregfile.hh b/src/arch/sparc/intregfile.hh index 223e3b34c..503f3c453 100644 --- a/src/arch/sparc/intregfile.hh +++ b/src/arch/sparc/intregfile.hh @@ -32,12 +32,14 @@ #ifndef __ARCH_SPARC_INTREGFILE_HH__ #define __ARCH_SPARC_INTREGFILE_HH__ -#include "arch/sparc/faults.hh" #include "arch/sparc/isa_traits.hh" #include "arch/sparc/types.hh" +#include "base/bitfield.hh" #include <string> +class Checkpoint; + namespace SparcISA { class RegFile; @@ -45,20 +47,27 @@ namespace SparcISA //This function translates integer register file indices into names std::string getIntRegName(RegIndex); + const int NumIntArchRegs = 32; + const int NumIntRegs = MaxGL * 8 + NWindows * 16 + NumMicroIntRegs; + class IntRegFile { private: friend class RegFile; protected: + //The number of bits needed to index into each 8 register frame static const int FrameOffsetBits = 3; + //The number of bits to choose between the 4 sets of 8 registers static const int FrameNumBits = 2; + //The number of registers per "frame" (8) static const int RegsPerFrame = 1 << FrameOffsetBits; - static const int FrameNumMask = + //A mask to get the frame number + static const uint64_t FrameNumMask = (FrameNumBits == sizeof(int)) ? (unsigned int)(-1) : (1 << FrameNumBits) - 1; - static const int FrameOffsetMask = + static const uint64_t FrameOffsetMask = (FrameOffsetBits == sizeof(int)) ? (unsigned int)(-1) : (1 << FrameOffsetBits) - 1; @@ -66,6 +75,7 @@ namespace SparcISA IntReg regGlobals[MaxGL][RegsPerFrame]; IntReg regSegments[2 * NWindows][RegsPerFrame]; IntReg microRegs[NumMicroIntRegs]; + IntReg regs[NumIntRegs]; enum regFrame {Globals, Outputs, Locals, Inputs, NumFrames}; @@ -85,7 +95,7 @@ namespace SparcISA IntReg readReg(int intReg); - Fault setReg(int intReg, const IntReg &val); + void setReg(int intReg, const IntReg &val); void serialize(std::ostream &os); diff --git a/src/arch/sparc/isa/base.isa b/src/arch/sparc/isa/base.isa index aa24c75be..4a806bfd0 100644 --- a/src/arch/sparc/isa/base.isa +++ b/src/arch/sparc/isa/base.isa @@ -205,7 +205,7 @@ output decoder {{ else if(reg < MaxMicroReg) ccprintf(os, "%%u%d", reg - MaxInput); else { - ccprintf(os, "%%f%d", reg - FP_Base_DepTag); + ccprintf(os, "%%f%d", reg - MaxMicroReg); } } diff --git a/src/arch/sparc/isa/decoder.isa b/src/arch/sparc/isa/decoder.isa index 2c8e59a1d..c3cff42ee 100644 --- a/src/arch/sparc/isa/decoder.isa +++ b/src/arch/sparc/isa/decoder.isa @@ -76,9 +76,15 @@ decode OP default Unknown::unknown() }}); 0x2: bpccx(19, {{ if(passesCondition(Ccr<7:4>, COND2)) + { + //warn("Took branch!\n"); NNPC = xc->readPC() + disp; + } else + { + //warn("Didn't take branch!\n"); handle_annul + } }}); } } @@ -247,16 +253,14 @@ decode OP default Unknown::unknown() ((Rs1 & val2) | (carryin & (Rs1 | val2)))<0:>)<63:>}}, {{Rs1<63:> == val2<63:> && val2<63:> != resTemp<63:>}} ); - 0x1A: umulcc({{ + 0x1A: IntOpCcRes::umulcc({{ uint64_t resTemp; Rd = resTemp = Rs1.udw<31:0> * Rs2_or_imm13.udw<31:0>; - Y = resTemp<63:32>;}}, - {{0}},{{0}},{{0}},{{0}}); - 0x1B: smulcc({{ + Y = resTemp<63:32>;}}); + 0x1B: IntOpCcRes::smulcc({{ int64_t resTemp; Rd = resTemp = Rs1.sdw<31:0> * Rs2_or_imm13.sdw<31:0>; - Y = resTemp<63:32>;}}, - {{0}},{{0}},{{0}},{{0}}); + Y = resTemp<63:32>;}}); 0x1C: subccc({{ int64_t resTemp, val2 = Rs2_or_imm13; int64_t carryin = Ccr<0:0>; @@ -266,10 +270,9 @@ decode OP default Unknown::unknown() {{(~((Rs1<63:1> + (~(val2 + carryin))<63:1>) + (Rs1<0:> + (~(val2+carryin))<0:> + 1)<63:1>))<63:>}}, {{Rs1<63:> != val2<63:> && Rs1<63:> != resTemp<63:>}} ); - 0x1D: udivxcc({{ + 0x1D: IntOpCcRes::udivxcc({{ if(Rs2_or_imm13.udw == 0) fault = new DivisionByZero; - else Rd = Rs1.udw / Rs2_or_imm13.udw;}} - ,{{0}},{{0}},{{0}},{{0}}); + else Rd = Rs1.udw / Rs2_or_imm13.udw;}}); 0x1E: udivcc({{ uint32_t resTemp, val2 = Rs2_or_imm13.udw; int32_t overflow = 0; @@ -307,7 +310,7 @@ decode OP default Unknown::unknown() int64_t resTemp, val2 = Rs2_or_imm13; Rd = resTemp = Rs1 + val2; int32_t overflow = Rs1<1:0> || val2<1:0> || (Rs1<31:> == val2<31:> && val2<31:> != resTemp<31:>);}}, - {{((Rs1 & 0xFFFFFFFF + val2 & 0xFFFFFFFF) >> 31)}}, + {{((Rs1<31:0> + val2<31:0>)<32:0>)}}, {{overflow}}, {{((Rs1 >> 1) + (val2 >> 1) + (Rs1 & val2 & 0x1))<63:>}}, {{Rs1<63:> == val2<63:> && val2<63:> != resTemp<63:>}} @@ -316,7 +319,7 @@ decode OP default Unknown::unknown() int64_t resTemp, val2 = Rs2_or_imm13; Rd = resTemp = Rs1 + val2; int32_t overflow = Rs1<1:0> || val2<1:0> || (Rs1<31:> == val2<31:> && val2<31:> != resTemp<31:>);}}, - {{(Rs1 & 0xFFFFFFFF + val2 & 0xFFFFFFFF) >> 31}}, + {{(Rs1<31:0> + val2<31:0>)<32:0>}}, {{overflow}}, {{((Rs1 >> 1) + (val2 >> 1) + (Rs1 & val2 & 0x1))<63:>}}, {{Rs1<63:> == val2<63:> && val2<63:> != resTemp<63:>}} @@ -327,7 +330,7 @@ decode OP default Unknown::unknown() int32_t overflow = Rs1<1:0> || val2<1:0> || (Rs1<31:> == val2<31:> && val2<31:> != Rd<31:>); if(overflow) fault = new TagOverflow;}}, - {{((Rs1 & 0xFFFFFFFF + val2 & 0xFFFFFFFF) >> 31)}}, + {{((Rs1<31:0> + val2<31:0>)<32:0>)}}, {{overflow}}, {{((Rs1 >> 1) + (val2 >> 1) + (Rs1 & val2 & 0x1))<63:>}}, {{Rs1<63:> == val2<63:> && val2<63:> != Rd<63:>}} @@ -337,7 +340,7 @@ decode OP default Unknown::unknown() Rd = resTemp = Rs1 + val2; int32_t overflow = Rs1<1:0> || val2<1:0> || (Rs1<31:> == val2<31:> && val2<31:> != resTemp<31:>); if(overflow) fault = new TagOverflow;}}, - {{((Rs1 & 0xFFFFFFFF + val2 & 0xFFFFFFFF) >> 31)}}, + {{((Rs1<31:0> + val2<31:0>)<32:0>)}}, {{overflow}}, {{((Rs1 >> 1) + (val2 >> 1) + (Rs1 & val2 & 0x1))<63:>}}, {{Rs1<63:> == val2<63:> && val2<63:> != resTemp<63:>}} @@ -347,13 +350,12 @@ decode OP default Unknown::unknown() int32_t multiplier = Rs1<31:0>; int32_t savedLSB = Rs1<0:>; multiplier = multiplier<31:1> | - ((Ccr<3:3> - ^ Ccr<1:1>) << 32); + ((Ccr<3:3> ^ Ccr<1:1>) << 32); if(!Y<0:>) multiplicand = 0; Rd = resTemp = multiplicand + multiplier; Y = Y<31:1> | (savedLSB << 31);}}, - {{((multiplicand & 0xFFFFFFFF + multiplier & 0xFFFFFFFF) >> 31)}}, + {{((multiplicand<31:0> + multiplier<31:0>)<32:0>)}}, {{multiplicand<31:> == multiplier<31:> && multiplier<31:> != resTemp<31:>}}, {{((multiplicand >> 1) + (multiplier >> 1) + (multiplicand & multiplier & 0x1))<63:>}}, {{multiplicand<63:> == multiplier<63:> && multiplier<63:> != resTemp<63:>}} @@ -881,16 +883,11 @@ decode OP default Unknown::unknown() } }}); 0x39: Branch::return({{ - //If both MemAddressNotAligned and - //a fill trap happen, it's not clear - //which one should be returned. Addr target = Rs1 + Rs2_or_imm13; - if(target & 0x3) - fault = new MemAddressNotAligned; - else - NNPC = target; if(fault == NoFault) { + //Check for fills which are higher priority than alignment + //faults. if(Canrestore == 0) { if(Otherwin) @@ -898,18 +895,15 @@ decode OP default Unknown::unknown() else fault = new FillNNormal(Wstate<2:0>); } + //Check for alignment faults + else if(target & 0x3) + fault = new MemAddressNotAligned; else { - //CWP should be set directly so that it always happens - //Also, this will allow writing to the new window and - //reading from the old one + NNPC = target; Cwp = (Cwp - 1 + NWindows) % NWindows; Cansave = Cansave + 1; Canrestore = Canrestore - 1; - //This is here to make sure the CWP is written - //no matter what. This ensures that the results - //are written in the new window as well. - xc->setMiscRegWithEffect(MISCREG_CWP, Cwp); } } }}); @@ -927,7 +921,7 @@ decode OP default Unknown::unknown() xc->syscall(R1); #endif } - }}); + }}, IsSerializeAfter, IsNonSpeculative); 0x2: Trap::tccx({{ if(passesCondition(Ccr<7:4>, COND2)) { @@ -940,36 +934,27 @@ decode OP default Unknown::unknown() xc->syscall(R1); #endif } - }}); + }}, IsSerializeAfter, IsNonSpeculative); } 0x3B: Nop::flush({{/*Instruction memory flush*/}}); 0x3C: save({{ - //CWP should be set directly so that it always happens - //Also, this will allow writing to the new window and - //reading from the old one if(Cansave == 0) { if(Otherwin) fault = new SpillNOther(Wstate<5:3>); else fault = new SpillNNormal(Wstate<2:0>); - //Cwp = (Cwp + 2) % NWindows; } else if(Cleanwin - Canrestore == 0) { - //Cwp = (Cwp + 1) % NWindows; fault = new CleanWindow; } else { Cwp = (Cwp + 1) % NWindows; - Rd = Rs1 + Rs2_or_imm13; + Rd_next = Rs1 + Rs2_or_imm13; Cansave = Cansave - 1; Canrestore = Canrestore + 1; - //This is here to make sure the CWP is written - //no matter what. This ensures that the results - //are written in the new window as well. - xc->setMiscRegWithEffect(MISCREG_CWP, Cwp); } }}); 0x3D: restore({{ @@ -982,17 +967,10 @@ decode OP default Unknown::unknown() } else { - //CWP should be set directly so that it always happens - //Also, this will allow writing to the new window and - //reading from the old one Cwp = (Cwp - 1 + NWindows) % NWindows; - Rd = Rs1 + Rs2_or_imm13; + Rd_prev = Rs1 + Rs2_or_imm13; Cansave = Cansave + 1; Canrestore = Canrestore - 1; - //This is here to make sure the CWP is written - //no matter what. This ensures that the results - //are written in the new window as well. - xc->setMiscRegWithEffect(MISCREG_CWP, Cwp); } }}); 0x3E: decode FCN { diff --git a/src/arch/sparc/isa/formats/branch.isa b/src/arch/sparc/isa/formats/branch.isa index 5fb7ade2d..3062f38b2 100644 --- a/src/arch/sparc/isa/formats/branch.isa +++ b/src/arch/sparc/isa/formats/branch.isa @@ -170,7 +170,7 @@ output decoder {{ printMnemonic(response, mnemonic); ccprintf(response, "0x%x", target); - if(symtab->findNearestSymbol(target, symbol, symbolAddr)) + if(symtab && symtab->findNearestSymbol(target, symbol, symbolAddr)) { ccprintf(response, " <%s", symbol); if(symbolAddr != target) @@ -178,6 +178,10 @@ output decoder {{ else ccprintf(response, ">"); } + else + { + ccprintf(response, "<%d>", target); + } return response.str(); } diff --git a/src/arch/sparc/isa/formats/mem/util.isa b/src/arch/sparc/isa/formats/mem/util.isa index b9f7fde2d..f3adbe19f 100644 --- a/src/arch/sparc/isa/formats/mem/util.isa +++ b/src/arch/sparc/isa/formats/mem/util.isa @@ -76,19 +76,22 @@ output decoder {{ { std::stringstream response; bool load = flags[IsLoad]; - bool save = flags[IsStore]; + bool store = flags[IsStore]; printMnemonic(response, mnemonic); - if(save) + if(store) { printReg(response, _srcRegIdx[0]); ccprintf(response, ", "); } - ccprintf(response, "[ "); - printReg(response, _srcRegIdx[!save ? 0 : 1]); - ccprintf(response, " + "); - printReg(response, _srcRegIdx[!save ? 1 : 2]); - ccprintf(response, " ]"); + ccprintf(response, "["); + if(_srcRegIdx[!store ? 0 : 1] != 0) + { + printSrcReg(response, !store ? 0 : 1); + ccprintf(response, " + "); + } + printSrcReg(response, !store ? 1 : 2); + ccprintf(response, "]"); if(load) { ccprintf(response, ", "); @@ -111,12 +114,16 @@ output decoder {{ printReg(response, _srcRegIdx[0]); ccprintf(response, ", "); } - ccprintf(response, "[ "); - printReg(response, _srcRegIdx[!save ? 0 : 1]); + ccprintf(response, "["); + if(_srcRegIdx[!save ? 0 : 1] != 0) + { + printReg(response, _srcRegIdx[!save ? 0 : 1]); + ccprintf(response, " + "); + } if(imm >= 0) - ccprintf(response, " + 0x%x ]", imm); + ccprintf(response, "0x%x]", imm); else - ccprintf(response, " + -0x%x ]", -imm); + ccprintf(response, "-0x%x]", -imm); if(load) { ccprintf(response, ", "); @@ -137,7 +144,7 @@ def template LoadExecute {{ %(op_decl)s; %(op_rd)s; %(ea_code)s; - DPRINTF(Sparc, "The address is 0x%x\n", EA); + DPRINTF(Sparc, "%s: The address is 0x%x\n", mnemonic, EA); %(fault_check)s; if(fault == NoFault) { @@ -149,8 +156,8 @@ def template LoadExecute {{ } if(fault == NoFault) { - //Write the resulting state to the execution context - %(op_wb)s; + //Write the resulting state to the execution context + %(op_wb)s; } return fault; @@ -165,6 +172,7 @@ def template LoadExecute {{ %(ea_decl)s; %(ea_rd)s; %(ea_code)s; + DPRINTF(Sparc, "%s: The address is 0x%x\n", mnemonic, EA); %(fault_check)s; if(fault == NoFault) { @@ -195,7 +203,6 @@ def template StoreExecute {{ Trace::InstRecord *traceData) const { Fault fault = NoFault; - uint64_t write_result = 0; //This is to support the conditional store in cas instructions. //It should be optomized out in all the others bool storeCond = true; @@ -203,7 +210,7 @@ def template StoreExecute {{ %(op_decl)s; %(op_rd)s; %(ea_code)s; - DPRINTF(Sparc, "The address is 0x%x\n", EA); + DPRINTF(Sparc, "%s: The address is 0x%x\n", mnemonic, EA); %(fault_check)s; if(fault == NoFault) { @@ -211,12 +218,12 @@ def template StoreExecute {{ } if(storeCond && fault == NoFault) { - fault = xc->write((uint%(mem_acc_size)s_t)Mem, EA, 0, &write_result); + fault = xc->write((uint%(mem_acc_size)s_t)Mem, EA, 0, 0); } if(fault == NoFault) { - //Write the resulting state to the execution context - %(op_wb)s; + //Write the resulting state to the execution context + %(op_wb)s; } return fault; @@ -226,13 +233,12 @@ def template StoreExecute {{ Trace::InstRecord * traceData) const { Fault fault = NoFault; - uint64_t write_result = 0; bool storeCond = true; Addr EA; %(op_decl)s; %(op_rd)s; %(ea_code)s; - DPRINTF(Sparc, "The address is 0x%x\n", EA); + DPRINTF(Sparc, "%s: The address is 0x%x\n", mnemonic, EA); %(fault_check)s; if(fault == NoFault) { @@ -240,11 +246,11 @@ def template StoreExecute {{ } if(storeCond && fault == NoFault) { - fault = xc->write((uint%(mem_acc_size)s_t)Mem, EA, 0, &write_result); + fault = xc->write((uint%(mem_acc_size)s_t)Mem, EA, 0, 0); } if(fault == NoFault) { - //Write the resulting state to the execution context + //Write the resulting state to the execution context %(op_wb)s; } return fault; @@ -293,7 +299,7 @@ let {{ //instruction at a certain micropc let {{ def makeMicroName(name, microPc): - return name + "::" + name + "_" + str(microPc) + return name + "::" + name + "_" + str(microPc) }}; //This function properly generates the execute functions for one of the @@ -302,13 +308,13 @@ let {{ //and in the other they're distributed across two. Also note that for //execute functions, the name of the base class doesn't matter. let {{ - def doSplitExecute(code, eaCode, execute, - faultCode, name, Name, opt_flags): - codeIop = InstObjParams(name, Name, '', code, opt_flags) - eaIop = InstObjParams(name, Name, '', eaCode, - opt_flags, {"fault_check": faultCode}) - iop = InstObjParams(name, Name, '', code, opt_flags, - {"fault_check": faultCode, "ea_code" : eaCode}) + def doSplitExecute(code, execute, name, Name, opt_flags, microParam): + codeParam = microParam.copy() + codeParam["ea_code"] = '' + codeIop = InstObjParams(name, Name, '', code, opt_flags, codeParam) + eaIop = InstObjParams(name, Name, '', microParam["ea_code"], + opt_flags, microParam) + iop = InstObjParams(name, Name, '', code, opt_flags, microParam) (iop.ea_decl, iop.ea_rd, iop.ea_wb) = (eaIop.op_decl, eaIop.op_rd, eaIop.op_wb) @@ -324,7 +330,8 @@ let {{ for (eaCode, name, Name) in ( (eaRegCode, nameReg, NameReg), (eaImmCode, nameImm, NameImm)): - executeCode += doSplitExecute(code, eaCode, - execute, faultCode, name, Name, opt_flags) + microParams = {"ea_code" : eaCode, "fault_check": faultCode} + executeCode += doSplitExecute(code, execute, name, Name, + opt_flags, microParams) return executeCode }}; diff --git a/src/arch/sparc/isa/formats/priv.isa b/src/arch/sparc/isa/formats/priv.isa index 94a68aebe..3d47ca02f 100644 --- a/src/arch/sparc/isa/formats/priv.isa +++ b/src/arch/sparc/isa/formats/priv.isa @@ -153,8 +153,13 @@ output decoder {{ printMnemonic(response, mnemonic); ccprintf(response, " "); - printSrcReg(response, 0); - ccprintf(response, ", "); + //If the first reg is %g0, don't print it. + //This improves readability + if(_srcRegIdx[0] != 0) + { + printSrcReg(response, 0); + ccprintf(response, ", "); + } printSrcReg(response, 1); ccprintf(response, ", %%%s", regName); @@ -169,8 +174,14 @@ output decoder {{ printMnemonic(response, mnemonic); ccprintf(response, " "); - printSrcReg(response, 0); - ccprintf(response, ", 0x%x, %%%s", imm, regName); + //If the first reg is %g0, don't print it. + //This improves readability + if(_srcRegIdx[0] != 0) + { + printSrcReg(response, 0); + ccprintf(response, ", "); + } + ccprintf(response, "0x%x, %%%s", imm, regName); return response.str(); } diff --git a/src/arch/sparc/isa/includes.isa b/src/arch/sparc/isa/includes.isa index 624afb693..2e7b16f20 100644 --- a/src/arch/sparc/isa/includes.isa +++ b/src/arch/sparc/isa/includes.isa @@ -37,12 +37,13 @@ output header {{ #include <sstream> #include <iostream> -#include "cpu/static_inst.hh" #include "arch/sparc/faults.hh" -#include "mem/request.hh" // some constructors use MemReq flags -#include "mem/packet.hh" #include "arch/sparc/isa_traits.hh" #include "arch/sparc/regfile.hh" +#include "base/misc.hh" +#include "cpu/static_inst.hh" +#include "mem/packet.hh" +#include "mem/request.hh" // some constructors use MemReq flags }}; output decoder {{ diff --git a/src/arch/sparc/isa/operands.isa b/src/arch/sparc/isa/operands.isa index 2d200f568..9a5fda6ff 100644 --- a/src/arch/sparc/isa/operands.isa +++ b/src/arch/sparc/isa/operands.isa @@ -56,12 +56,23 @@ 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'. + 'Rd': ('IntReg', 'udw', 'RD', 'IsInteger', 1), - 'RdLow': ('IntReg', 'udw', 'RD & (~1)', 'IsInteger', 2), - 'RdHigh': ('IntReg', 'udw', 'RD | 1', 'IsInteger', 3), - 'Rs1': ('IntReg', 'udw', 'RS1', 'IsInteger', 4), - 'Rs2': ('IntReg', 'udw', 'RS2', 'IsInteger', 5), - 'uReg0': ('IntReg', 'udw', 'NumRegularIntRegs+0', 'IsInteger', 6), + # The Rd from the previous window + 'Rd_prev': ('IntReg', 'udw', 'RD + NumIntArchRegs + NumMicroIntRegs', 'IsInteger', 2), + # The Rd from the next window + 'Rd_next': ('IntReg', 'udw', 'RD + 2 * NumIntArchRegs + NumMicroIntRegs', 'IsInteger', 3), + # The low (even) register of a two register pair + 'RdLow': ('IntReg', 'udw', 'RD & (~1)', 'IsInteger', 4), + # The high (odd) register of a two register pair + 'RdHigh': ('IntReg', 'udw', 'RD | 1', 'IsInteger', 5), + 'Rs1': ('IntReg', 'udw', 'RS1', 'IsInteger', 6), + 'Rs2': ('IntReg', 'udw', 'RS2', 'IsInteger', 7), + # A microcode register. Right now, this is the only one. + 'uReg0': ('IntReg', 'udw', 'NumIntArchRegs', 'IsInteger', 8), + # Because double and quad precision register numbers are decoded + # differently, they get different operands. The single precision versions + # have an s post pended to their name. 'Frds': ('FloatReg', 'sf', 'RD', 'IsFloating', 10), 'Frd': ('FloatReg', 'df', 'dfpr(RD)', 'IsFloating', 10), # Each Frd_N refers to the Nth double precision register from Frd. @@ -80,14 +91,17 @@ def operands {{ 'Frs2': ('FloatReg', 'df', 'dfpr(RS2)', 'IsFloating', 12), 'NPC': ('NPC', 'udw', None, ( None, None, 'IsControl' ), 31), 'NNPC': ('NNPC', 'udw', None, (None, None, 'IsControl' ), 32), + # Registers which are used explicitly in instructions 'R0': ('IntReg', 'udw', '0', None, 6), 'R1': ('IntReg', 'udw', '1', None, 7), 'R15': ('IntReg', 'udw', '15', 'IsInteger', 8), 'R16': ('IntReg', 'udw', '16', None, 9), # Control registers - 'Y': ('ControlReg', 'udw', 'MISCREG_Y', None, 40), - 'Ccr': ('ControlReg', 'udw', 'MISCREG_CCR', None, 41), +# 'Y': ('ControlReg', 'udw', 'MISCREG_Y', None, 40), +# 'Ccr': ('ControlReg', 'udw', 'MISCREG_CCR', None, 41), + 'Y': ('IntReg', 'udw', 'NumIntArchRegs + 1', None, 40), + 'Ccr': ('IntReg', 'udw', 'NumIntArchRegs + 2', None, 41), 'Asi': ('ControlReg', 'udw', 'MISCREG_ASI', None, 42), 'Fprs': ('ControlReg', 'udw', 'MISCREG_FPRS', None, 43), 'Pcr': ('ControlReg', 'udw', 'MISCREG_PCR', None, 44), @@ -109,12 +123,17 @@ def operands {{ 'Pstate': ('ControlReg', 'udw', 'MISCREG_PSTATE', None, 59), 'Tl': ('ControlReg', 'udw', 'MISCREG_TL', None, 60), 'Pil': ('ControlReg', 'udw', 'MISCREG_PIL', None, 61), - 'Cwp': ('ControlReg', 'udw', 'MISCREG_CWP', None, 62), - 'Cansave': ('ControlReg', 'udw', 'MISCREG_CANSAVE', None, 63), - 'Canrestore': ('ControlReg', 'udw', 'MISCREG_CANRESTORE', None, 64), - 'Cleanwin': ('ControlReg', 'udw', 'MISCREG_CLEANWIN', None, 65), - 'Otherwin': ('ControlReg', 'udw', 'MISCREG_OTHERWIN', None, 66), - 'Wstate': ('ControlReg', 'udw', 'MISCREG_WSTATE', None, 67), + 'Cwp': ('ControlReg', 'udw', 'MISCREG_CWP', (None, None, ['IsSerializeAfter','IsSerializing']), 62), +# 'Cansave': ('ControlReg', 'udw', 'MISCREG_CANSAVE', None, 63), +# 'Canrestore': ('ControlReg', 'udw', 'MISCREG_CANRESTORE', None, 64), +# 'Cleanwin': ('ControlReg', 'udw', 'MISCREG_CLEANWIN', None, 65), +# 'Otherwin': ('ControlReg', 'udw', 'MISCREG_OTHERWIN', None, 66), +# 'Wstate': ('ControlReg', 'udw', 'MISCREG_WSTATE', None, 67), + 'Cansave': ('IntReg', 'udw', 'NumIntArchRegs + 3', None, 63), + 'Canrestore': ('IntReg', 'udw', 'NumIntArchRegs + 4', None, 64), + 'Cleanwin': ('IntReg', 'udw', 'NumIntArchRegs + 5', None, 65), + 'Otherwin': ('IntReg', 'udw', 'NumIntArchRegs + 6', None, 66), + 'Wstate': ('IntReg', 'udw', 'NumIntArchRegs + 7', None, 67), 'Gl': ('ControlReg', 'udw', 'MISCREG_GL', None, 68), 'Hpstate': ('ControlReg', 'udw', 'MISCREG_HPSTATE', None, 69), diff --git a/src/arch/sparc/isa_traits.hh b/src/arch/sparc/isa_traits.hh index 1433ba3f8..7d786dc3b 100644 --- a/src/arch/sparc/isa_traits.hh +++ b/src/arch/sparc/isa_traits.hh @@ -32,16 +32,9 @@ #define __ARCH_SPARC_ISA_TRAITS_HH__ #include "arch/sparc/types.hh" -#include "base/misc.hh" +#include "arch/sparc/sparc_traits.hh" #include "config/full_system.hh" -#include "sim/host.hh" -class ThreadContext; -class FastCPU; -//class FullCPU; -class Checkpoint; - -class StaticInst; class StaticInstPtr; namespace BigEndianGuest {} @@ -63,32 +56,12 @@ namespace SparcISA // SPARC NOP (sethi %(hi(0), g0) const MachInst NoopMachInst = 0x01000000; - const int NumRegularIntRegs = 32; - const int NumMicroIntRegs = 1; - const int NumIntRegs = - NumRegularIntRegs + - NumMicroIntRegs; - const int NumFloatRegs = 64; - const int NumMiscRegs = 40; - // These enumerate all the registers for dependence tracking. enum DependenceTags { - // 0..31 are the integer regs 0..31 - // 32..95 are the FP regs 0..31, i.e. use (reg + FP_Base_DepTag) - FP_Base_DepTag = NumIntRegs, - Ctrl_Base_DepTag = NumIntRegs + NumMicroIntRegs + NumFloatRegs, + FP_Base_DepTag = 32*3+8, + Ctrl_Base_DepTag = FP_Base_DepTag + 64, }; - - // MAXTL - maximum trap level - const int MaxPTL = 2; - const int MaxTL = 6; - const int MaxGL = 3; - const int MaxPGL = 2; - - // NWINDOWS - number of register windows, can be 3 to 32 - const int NWindows = 8; - // semantically meaningful register indices const int ZeroReg = 0; // architecturally meaningful // the rest of these depend on the ABI @@ -116,23 +89,11 @@ namespace SparcISA //Why does both the previous set of constants and this one exist? const int PageShift = 13; - const int PageBytes = ULL(1) << PageShift; + const int PageBytes = 1ULL << PageShift; const int BranchPredAddrShiftAmt = 2; - const int MachineBytes = 8; - const int WordBytes = 4; - const int HalfwordBytes = 2; - const int ByteBytes = 1; - - void serialize(std::ostream & os); - - void unserialize(Checkpoint *cp, const std::string §ion); - StaticInstPtr decodeInst(ExtMachInst); - - // return a no-op instruction... used for instruction fetch faults - extern const MachInst NoopMachInst; } #endif // __ARCH_SPARC_ISA_TRAITS_HH__ diff --git a/src/arch/sparc/miscregfile.cc b/src/arch/sparc/miscregfile.cc index d52e3983f..50a4f4871 100644 --- a/src/arch/sparc/miscregfile.cc +++ b/src/arch/sparc/miscregfile.cc @@ -50,19 +50,24 @@ class Checkpoint; string SparcISA::getMiscRegName(RegIndex index) { static::string miscRegName[NumMiscRegs] = - {"y", "ccr", "asi", "tick", "pc", "fprs", "pcr", "pic", + {/*"y", "ccr",*/ "asi", "tick", "fprs", "pcr", "pic", "gsr", "softint_set", "softint_clr", "softint", "tick_cmpr", "stick", "stick_cmpr", "tpc", "tnpc", "tstate", "tt", "privtick", "tba", "pstate", "tl", - "pil", "cwp", "cansave", "canrestore", "cleanwin", "otherwin", - "wstate", "gl", + "pil", "cwp", /*"cansave", "canrestore", "cleanwin", "otherwin", + "wstate",*/ "gl", "hpstate", "htstate", "hintp", "htba", "hver", "strand_sts_reg", "hstick_cmpr", "fsr"}; return miscRegName[index]; } -void MiscRegFile::reset() +enum RegMask +{ + PSTATE_MASK = (((1 << 4) - 1) << 1) | (((1 << 4) - 1) << 6) | (1 << 12) +}; + +void MiscRegFile::clear() { y = 0; ccr = 0; @@ -88,12 +93,14 @@ void MiscRegFile::reset() otherwin = 0; wstate = 0; gl = 0; - hpstate = 0; + //In a T1, bit 11 is apparently always 1 + hpstate = (1 << 11); memset(htstate, 0, sizeof(htstate)); hintp = 0; htba = 0; hstick_cmpr = 0; - strandStatusReg = 0; + //This is set this way in Legion for some reason + strandStatusReg = 0x50000; fsr = 0; implicitInstAsi = ASI_PRIMARY; implicitDataAsi = ASI_PRIMARY; @@ -102,10 +109,10 @@ void MiscRegFile::reset() MiscReg MiscRegFile::readReg(int miscReg) { switch (miscReg) { - case MISCREG_Y: - return y; - case MISCREG_CCR: - return ccr; +// case MISCREG_Y: +// return y; +// case MISCREG_CCR: +// return ccr; case MISCREG_ASI: return asi; case MISCREG_FPRS: @@ -148,16 +155,16 @@ MiscReg MiscRegFile::readReg(int miscReg) return pil; case MISCREG_CWP: return cwp; - case MISCREG_CANSAVE: - return cansave; - case MISCREG_CANRESTORE: - return canrestore; - case MISCREG_CLEANWIN: - return cleanwin; - case MISCREG_OTHERWIN: - return otherwin; - case MISCREG_WSTATE: - return wstate; +// case MISCREG_CANSAVE: +// return cansave; +// case MISCREG_CANRESTORE: +// return canrestore; +// case MISCREG_CLEANWIN: +// return cleanwin; +// case MISCREG_OTHERWIN: +// return otherwin; +// case MISCREG_WSTATE: +// return wstate; case MISCREG_GL: return gl; @@ -218,12 +225,12 @@ MiscReg MiscRegFile::readRegWithEffect(int miscReg, ThreadContext * tc) void MiscRegFile::setReg(int miscReg, const MiscReg &val) { switch (miscReg) { - case MISCREG_Y: - y = val; - break; - case MISCREG_CCR: - ccr = val; - break; +// case MISCREG_Y: +// y = val; +// break; +// case MISCREG_CCR: +// ccr = val; +// break; case MISCREG_ASI: asi = val; break; @@ -273,7 +280,7 @@ void MiscRegFile::setReg(int miscReg, const MiscReg &val) tba = val & ULL(~0x7FFF); break; case MISCREG_PSTATE: - pstate = val; + pstate = (val & PSTATE_MASK); break; case MISCREG_TL: tl = val; @@ -284,21 +291,21 @@ void MiscRegFile::setReg(int miscReg, const MiscReg &val) case MISCREG_CWP: cwp = val; break; - case MISCREG_CANSAVE: - cansave = val; - break; - case MISCREG_CANRESTORE: - canrestore = val; - break; - case MISCREG_CLEANWIN: - cleanwin = val; - break; - case MISCREG_OTHERWIN: - otherwin = val; - break; - case MISCREG_WSTATE: - wstate = val; - break; +// case MISCREG_CANSAVE: +// cansave = val; +// break; +// case MISCREG_CANRESTORE: +// canrestore = val; +// break; +// case MISCREG_CLEANWIN: +// cleanwin = val; +// break; +// case MISCREG_OTHERWIN: +// otherwin = val; +// break; +// case MISCREG_WSTATE: +// wstate = val; +// break; case MISCREG_GL: gl = val; break; @@ -375,7 +382,7 @@ void MiscRegFile::setRegWithEffect(int miscReg, //Set up performance counting based on pcr value break; case MISCREG_PSTATE: - pstate = val; + pstate = val & PSTATE_MASK; setImplicitAsis(); return; case MISCREG_TL: diff --git a/src/arch/sparc/miscregfile.hh b/src/arch/sparc/miscregfile.hh index f74943256..cf0405ac4 100644 --- a/src/arch/sparc/miscregfile.hh +++ b/src/arch/sparc/miscregfile.hh @@ -42,15 +42,14 @@ namespace SparcISA { - //These functions map register indices to names std::string getMiscRegName(RegIndex); enum MiscRegIndex { /** Ancillary State Registers */ - MISCREG_Y, - MISCREG_CCR, +// MISCREG_Y, +// MISCREG_CCR, MISCREG_ASI, MISCREG_TICK, MISCREG_FPRS, @@ -75,11 +74,11 @@ namespace SparcISA MISCREG_TL, MISCREG_PIL, MISCREG_CWP, - MISCREG_CANSAVE, - MISCREG_CANRESTORE, - MISCREG_CLEANWIN, - MISCREG_OTHERWIN, - MISCREG_WSTATE, +// MISCREG_CANSAVE, +// MISCREG_CANRESTORE, +// MISCREG_CLEANWIN, +// MISCREG_OTHERWIN, +// MISCREG_WSTATE, MISCREG_GL, /** Hyper privileged registers */ @@ -92,9 +91,14 @@ namespace SparcISA MISCREG_HSTICK_CMPR, /** Floating Point Status Register */ - MISCREG_FSR + MISCREG_FSR, + + MISCREG_NUMMISCREGS }; + const int NumMiscArchRegs = MISCREG_NUMMISCREGS; + const int NumMiscRegs = MISCREG_NUMMISCREGS; + // The control registers, broken out into fields class MiscRegFile { @@ -172,11 +176,11 @@ namespace SparcISA #endif public: - void reset(); + void clear(); MiscRegFile() { - reset(); + clear(); } MiscReg readReg(int miscReg); diff --git a/src/arch/sparc/process.cc b/src/arch/sparc/process.cc index 3efe4fc08..073117a84 100644 --- a/src/arch/sparc/process.cc +++ b/src/arch/sparc/process.cc @@ -32,6 +32,7 @@ #include "arch/sparc/asi.hh" #include "arch/sparc/isa_traits.hh" #include "arch/sparc/process.hh" +#include "arch/sparc/types.hh" #include "base/loader/object_file.hh" #include "base/loader/elf_object.hh" #include "base/misc.hh" @@ -77,7 +78,7 @@ SparcLiveProcess::SparcLiveProcess(const std::string &nm, ObjectFile *objFile, void SparcLiveProcess::startup() { - argsInit(MachineBytes, VMPageSize); + argsInit(sizeof(IntReg), VMPageSize); //From the SPARC ABI @@ -94,17 +95,22 @@ SparcLiveProcess::startup() */ //No windows contain info from other programs - threadContexts[0]->setMiscReg(MISCREG_OTHERWIN, 0); + //threadContexts[0]->setMiscReg(MISCREG_OTHERWIN, 0); + threadContexts[0]->setIntReg(NumIntArchRegs + 6, 0); //There are no windows to pop - threadContexts[0]->setMiscReg(MISCREG_CANRESTORE, 0); + //threadContexts[0]->setMiscReg(MISCREG_CANRESTORE, 0); + threadContexts[0]->setIntReg(NumIntArchRegs + 4, 0); //All windows are available to save into - threadContexts[0]->setMiscReg(MISCREG_CANSAVE, NWindows - 2); + //threadContexts[0]->setMiscReg(MISCREG_CANSAVE, NWindows - 2); + threadContexts[0]->setIntReg(NumIntArchRegs + 3, NWindows - 2); //All windows are "clean" - threadContexts[0]->setMiscReg(MISCREG_CLEANWIN, NWindows); + //threadContexts[0]->setMiscReg(MISCREG_CLEANWIN, NWindows); + threadContexts[0]->setIntReg(NumIntArchRegs + 5, NWindows); //Start with register window 0 threadContexts[0]->setMiscReg(MISCREG_CWP, 0); //Always use spill and fill traps 0 - threadContexts[0]->setMiscReg(MISCREG_WSTATE, 0); + //threadContexts[0]->setMiscReg(MISCREG_WSTATE, 0); + threadContexts[0]->setIntReg(NumIntArchRegs + 7, 0); //Set the trap level to 0 threadContexts[0]->setMiscReg(MISCREG_TL, 0); //Set the ASI register to something fixed diff --git a/src/arch/sparc/regfile.cc b/src/arch/sparc/regfile.cc index 65e6017da..29aca50c6 100644 --- a/src/arch/sparc/regfile.cc +++ b/src/arch/sparc/regfile.cc @@ -70,8 +70,9 @@ void RegFile::setNextNPC(Addr val) void RegFile::clear() { - intRegFile.clear(); floatRegFile.clear(); + intRegFile.clear(); + miscRegFile.clear(); } MiscReg RegFile::readMiscReg(int miscReg) @@ -150,6 +151,72 @@ void RegFile::setIntReg(int intReg, const IntReg &val) intRegFile.setReg(intReg, val); } +int SparcISA::flattenIntIndex(ThreadContext * tc, int reg) +{ + int gl = tc->readMiscReg(MISCREG_GL); + int cwp = tc->readMiscReg(MISCREG_CWP); + //DPRINTF(Sparc, "Global Level = %d, Current Window Pointer = %d\n", gl, cwp); + int newReg; + if(reg < 8) + { + //Global register + //Put it in the appropriate set of globals + newReg = reg + gl * 8; + } + else if(reg < NumIntArchRegs) + { + //Regular windowed register + //Put it in the window pointed to by cwp + newReg = MaxGL * 8 + + ((reg - 8 - cwp * 16 + NWindows * 16) % (NWindows * 16)); + } + else if(reg < NumIntArchRegs + NumMicroIntRegs) + { + //Microcode register + //Displace from the end of the regular registers + newReg = reg - NumIntArchRegs + MaxGL * 8 + NWindows * 16; + } + else if(reg < 2 * NumIntArchRegs + NumMicroIntRegs) + { + reg -= (NumIntArchRegs + NumMicroIntRegs); + if(reg < 8) + { + //Global register from the next window + //Put it in the appropriate set of globals + newReg = reg + gl * 8; + } + else + { + //Windowed register from the previous window + //Put it in the window before the one pointed to by cwp + newReg = MaxGL * 8 + + ((reg - 8 - (cwp - 1) * 16 + NWindows * 16) % (NWindows * 16)); + } + } + else if(reg < 3 * NumIntArchRegs + NumMicroIntRegs) + { + reg -= (2 * NumIntArchRegs + NumMicroIntRegs); + if(reg < 8) + { + //Global register from the previous window + //Put it in the appropriate set of globals + newReg = reg + gl * 8; + } + else + { + //Windowed register from the next window + //Put it in the window after the one pointed to by cwp + newReg = MaxGL * 8 + + ((reg - 8 - (cwp + 1) * 16 + NWindows * 16) % (NWindows * 16)); + } + } + else + panic("Tried to flatten invalid register index %d!\n", reg); + DPRINTF(Sparc, "Flattened register %d to %d.\n", reg, newReg); + return newReg; + //return intRegFile.flattenIndex(reg); +} + void RegFile::serialize(std::ostream &os) { intRegFile.serialize(os); @@ -219,8 +286,8 @@ void SparcISA::copyMiscRegs(ThreadContext *src, ThreadContext *dest) // ASRs - dest->setMiscReg(MISCREG_Y, src->readMiscReg(MISCREG_Y)); - dest->setMiscReg(MISCREG_CCR, src->readMiscReg(MISCREG_CCR)); +// dest->setMiscReg(MISCREG_Y, src->readMiscReg(MISCREG_Y)); +// dest->setMiscReg(MISCREG_CCR, src->readMiscReg(MISCREG_CCR)); dest->setMiscReg(MISCREG_ASI, src->readMiscReg(MISCREG_ASI)); dest->setMiscReg(MISCREG_TICK, src->readMiscReg(MISCREG_TICK)); dest->setMiscReg(MISCREG_FPRS, src->readMiscReg(MISCREG_FPRS)); @@ -235,11 +302,11 @@ void SparcISA::copyMiscRegs(ThreadContext *src, ThreadContext *dest) dest->setMiscReg(MISCREG_PSTATE, src->readMiscReg(MISCREG_PSTATE)); dest->setMiscReg(MISCREG_PIL, src->readMiscReg(MISCREG_PIL)); dest->setMiscReg(MISCREG_CWP, src->readMiscReg(MISCREG_CWP)); - dest->setMiscReg(MISCREG_CANSAVE, src->readMiscReg(MISCREG_CANSAVE)); - dest->setMiscReg(MISCREG_CANRESTORE, src->readMiscReg(MISCREG_CANRESTORE)); - dest->setMiscReg(MISCREG_OTHERWIN, src->readMiscReg(MISCREG_OTHERWIN)); - dest->setMiscReg(MISCREG_CLEANWIN, src->readMiscReg(MISCREG_CLEANWIN)); - dest->setMiscReg(MISCREG_WSTATE, src->readMiscReg(MISCREG_WSTATE)); +// dest->setMiscReg(MISCREG_CANSAVE, src->readMiscReg(MISCREG_CANSAVE)); +// dest->setMiscReg(MISCREG_CANRESTORE, src->readMiscReg(MISCREG_CANRESTORE)); +// dest->setMiscReg(MISCREG_OTHERWIN, src->readMiscReg(MISCREG_OTHERWIN)); +// dest->setMiscReg(MISCREG_CLEANWIN, src->readMiscReg(MISCREG_CLEANWIN)); +// dest->setMiscReg(MISCREG_WSTATE, src->readMiscReg(MISCREG_WSTATE)); dest->setMiscReg(MISCREG_GL, src->readMiscReg(MISCREG_GL)); // Hyperprivilged registers diff --git a/src/arch/sparc/regfile.hh b/src/arch/sparc/regfile.hh index 9f33435f6..51f1b5fef 100644 --- a/src/arch/sparc/regfile.hh +++ b/src/arch/sparc/regfile.hh @@ -120,6 +120,8 @@ namespace SparcISA void changeContext(RegContextParam param, RegContextVal val); }; + int flattenIntIndex(ThreadContext * tc, int reg); + void copyRegs(ThreadContext *src, ThreadContext *dest); void copyMiscRegs(ThreadContext *src, ThreadContext *dest); diff --git a/src/arch/sparc/sparc_traits.hh b/src/arch/sparc/sparc_traits.hh new file mode 100644 index 000000000..d89ec1119 --- /dev/null +++ b/src/arch/sparc/sparc_traits.hh @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#ifndef __ARCH_SPARC_SPARC_TRAITS_HH__ +#define __ARCH_SPARC_SPARC_TRAITS_HH__ + +namespace SparcISA +{ + // Max trap levels + const int MaxPTL = 2; + const int MaxTL = 6; + const int MaxGL = 3; + const int MaxPGL = 2; + + // Number of register windows, can legally be 3 to 32 + const int NWindows = 8; + //const int NumMicroIntRegs = 1; + const int NumMicroIntRegs = 8; + +// const int NumRegularIntRegs = MaxGL * 8 + NWindows * 16; +// const int NumMicroIntRegs = 1; +// const int NumIntRegs = +// NumRegularIntRegs + +// NumMicroIntRegs; +// const int NumFloatRegs = 64; +// const int NumMiscRegs = 40; +} + +#endif // __ARCH_SPARC_ISA_TRAITS_HH__ diff --git a/src/arch/sparc/syscallreturn.hh b/src/arch/sparc/syscallreturn.hh index 75a063da1..d92b12790 100644 --- a/src/arch/sparc/syscallreturn.hh +++ b/src/arch/sparc/syscallreturn.hh @@ -33,58 +33,30 @@ #include <inttypes.h> +#include "sim/syscallreturn.hh" #include "arch/sparc/regfile.hh" - -class SyscallReturn -{ - public: - template <class T> - SyscallReturn(T v, bool s) - { - retval = (uint64_t)v; - success = s; - } - - template <class T> - SyscallReturn(T v) - { - success = (v >= 0); - retval = (uint64_t)v; - } - - ~SyscallReturn() {} - - SyscallReturn& operator=(const SyscallReturn& s) - { - retval = s.retval; - success = s.success; - return *this; - } - - bool successful() { return success; } - uint64_t value() { return retval; } - - private: - uint64_t retval; - bool success; -}; +#include "cpu/thread_context.hh" namespace SparcISA { static inline void setSyscallReturn(SyscallReturn return_value, - RegFile *regs) + ThreadContext * tc) { // check for error condition. SPARC syscall convention is to // indicate success/failure in reg the carry bit of the ccr // and put the return value itself in the standard return value reg (). if (return_value.successful()) { // no error, clear XCC.C - regs->setMiscReg(MISCREG_CCR, regs->readMiscReg(MISCREG_CCR) & 0xEE); - regs->setIntReg(ReturnValueReg, return_value.value()); + tc->setIntReg(NumIntArchRegs + 2, + tc->readIntReg(NumIntArchRegs + 2) & 0xEE); + //tc->setMiscReg(MISCREG_CCR, tc->readMiscReg(MISCREG_CCR) & 0xEE); + tc->setIntReg(ReturnValueReg, return_value.value()); } else { // got an error, set XCC.C - regs->setMiscReg(MISCREG_CCR, regs->readMiscReg(MISCREG_CCR) | 0x11); - regs->setIntReg(ReturnValueReg, return_value.value()); + tc->setIntReg(NumIntArchRegs + 2, + tc->readIntReg(NumIntArchRegs + 2) | 0x11); + //tc->setMiscReg(MISCREG_CCR, tc->readMiscReg(MISCREG_CCR) | 0x11); + tc->setIntReg(ReturnValueReg, -return_value.value()); } } }; diff --git a/src/arch/sparc/system.cc b/src/arch/sparc/system.cc index 4e907f002..72c87f0ad 100644 --- a/src/arch/sparc/system.cc +++ b/src/arch/sparc/system.cc @@ -42,18 +42,35 @@ using namespace BigEndianGuest; SparcSystem::SparcSystem(Params *p) - : System(p), sysTick(0),funcRomPort(p->name + "-fport") - + : System(p), sysTick(0),funcRomPort(p->name + "-fromport"), + funcNvramPort(p->name + "-fnvramport"), + funcHypDescPort(p->name + "-fhypdescport"), + funcPartDescPort(p->name + "-fpartdescport") { resetSymtab = new SymbolTable; hypervisorSymtab = new SymbolTable; openbootSymtab = new SymbolTable; + nvramSymtab = new SymbolTable; + hypervisorDescSymtab = new SymbolTable; + partitionDescSymtab = new SymbolTable; Port *rom_port; rom_port = params()->rom->getPort("functional"); funcRomPort.setPeer(rom_port); rom_port->setPeer(&funcRomPort); + rom_port = params()->nvram->getPort("functional"); + funcNvramPort.setPeer(rom_port); + rom_port->setPeer(&funcNvramPort); + + rom_port = params()->hypervisor_desc->getPort("functional"); + funcHypDescPort.setPeer(rom_port); + rom_port->setPeer(&funcHypDescPort); + + rom_port = params()->partition_desc->getPort("functional"); + funcPartDescPort.setPeer(rom_port); + rom_port->setPeer(&funcPartDescPort); + /** * Load the boot code, and hypervisor into memory. */ @@ -72,6 +89,23 @@ SparcSystem::SparcSystem(Params *p) if (hypervisor == NULL) fatal("Could not load hypervisor binary %s", params()->hypervisor_bin); + // Read the nvram image + nvram = createObjectFile(params()->nvram_bin, true); + if (nvram == NULL) + fatal("Could not load nvram image %s", params()->nvram_bin); + + // Read the hypervisor description image + hypervisor_desc = createObjectFile(params()->hypervisor_desc_bin, true); + if (hypervisor_desc == NULL) + fatal("Could not load hypervisor description image %s", + params()->hypervisor_desc_bin); + + // Read the partition description image + partition_desc = createObjectFile(params()->partition_desc_bin, true); + if (partition_desc == NULL) + fatal("Could not load partition description image %s", + params()->partition_desc_bin); + // Load reset binary into memory reset->setTextBase(params()->reset_addr); @@ -82,6 +116,15 @@ SparcSystem::SparcSystem(Params *p) // Load the hypervisor binary hypervisor->setTextBase(params()->hypervisor_addr); hypervisor->loadSections(&funcRomPort); + // Load the nvram image + nvram->setTextBase(params()->nvram_addr); + nvram->loadSections(&funcNvramPort); + // Load the hypervisor description image + hypervisor_desc->setTextBase(params()->hypervisor_desc_addr); + hypervisor_desc->loadSections(&funcHypDescPort); + // Load the partition description image + partition_desc->setTextBase(params()->partition_desc_addr); + partition_desc->loadSections(&funcPartDescPort); // load symbols if (!reset->loadGlobalSymbols(resetSymtab)) @@ -93,6 +136,15 @@ SparcSystem::SparcSystem(Params *p) if (!hypervisor->loadLocalSymbols(hypervisorSymtab)) panic("could not load hypervisor symbols\n"); + if (!nvram->loadLocalSymbols(nvramSymtab)) + panic("could not load nvram symbols\n"); + + if (!hypervisor_desc->loadLocalSymbols(hypervisorDescSymtab)) + panic("could not load hypervisor description symbols\n"); + + if (!partition_desc->loadLocalSymbols(partitionDescSymtab)) + panic("could not load partition description symbols\n"); + // load symbols into debug table if (!reset->loadGlobalSymbols(debugSymbolTable)) panic("could not load reset symbols\n"); @@ -103,6 +155,15 @@ SparcSystem::SparcSystem(Params *p) if (!hypervisor->loadLocalSymbols(debugSymbolTable)) panic("could not load hypervisor symbols\n"); + if (!nvram->loadGlobalSymbols(debugSymbolTable)) + panic("could not load reset symbols\n"); + + if (!hypervisor_desc->loadGlobalSymbols(debugSymbolTable)) + panic("could not load hypervisor description symbols\n"); + + if (!partition_desc->loadLocalSymbols(debugSymbolTable)) + panic("could not load partition description symbols\n"); + // @todo any fixup code over writing data in binaries on setting break // events on functions should happen here. @@ -114,9 +175,15 @@ SparcSystem::~SparcSystem() delete resetSymtab; delete hypervisorSymtab; delete openbootSymtab; + delete nvramSymtab; + delete hypervisorDescSymtab; + delete partitionDescSymtab; delete reset; delete openboot; delete hypervisor; + delete nvram; + delete hypervisor_desc; + delete partition_desc; } bool @@ -132,6 +199,9 @@ SparcSystem::serialize(std::ostream &os) resetSymtab->serialize("reset_symtab", os); hypervisorSymtab->serialize("hypervisor_symtab", os); openbootSymtab->serialize("openboot_symtab", os); + nvramSymtab->serialize("nvram_symtab", os); + hypervisorDescSymtab->serialize("hypervisor_desc_symtab", os); + partitionDescSymtab->serialize("partition_desc_symtab", os); } @@ -142,6 +212,9 @@ SparcSystem::unserialize(Checkpoint *cp, const std::string §ion) resetSymtab->unserialize("reset_symtab", cp, section); hypervisorSymtab->unserialize("hypervisor_symtab", cp, section); openbootSymtab->unserialize("openboot_symtab", cp, section); + nvramSymtab->unserialize("nvram_symtab", cp, section); + hypervisorDescSymtab->unserialize("hypervisor_desc_symtab", cp, section); + partitionDescSymtab->unserialize("partition_desc_symtab", cp, section); } @@ -149,16 +222,25 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(SparcSystem) SimObjectParam<PhysicalMemory *> physmem; SimObjectParam<PhysicalMemory *> rom; + SimObjectParam<PhysicalMemory *> nvram; + SimObjectParam<PhysicalMemory *> hypervisor_desc; + SimObjectParam<PhysicalMemory *> partition_desc; SimpleEnumParam<System::MemoryMode> mem_mode; Param<Addr> reset_addr; Param<Addr> hypervisor_addr; Param<Addr> openboot_addr; + Param<Addr> nvram_addr; + Param<Addr> hypervisor_desc_addr; + Param<Addr> partition_desc_addr; Param<std::string> kernel; Param<std::string> reset_bin; Param<std::string> hypervisor_bin; Param<std::string> openboot_bin; + Param<std::string> nvram_bin; + Param<std::string> hypervisor_desc_bin; + Param<std::string> partition_desc_bin; Param<Tick> boot_cpu_frequency; Param<std::string> boot_osflags; @@ -171,17 +253,30 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(SparcSystem) INIT_PARAM(physmem, "phsyical memory"), INIT_PARAM(rom, "ROM for boot code"), + INIT_PARAM(nvram, "Non-volatile RAM for the nvram"), + INIT_PARAM(hypervisor_desc, "ROM for the hypervisor description"), + INIT_PARAM(partition_desc, "ROM for the partition description"), INIT_ENUM_PARAM(mem_mode, "Memory Mode, (1=atomic, 2=timing)", System::MemoryModeStrings), INIT_PARAM(reset_addr, "Address that reset should be loaded at"), INIT_PARAM(hypervisor_addr, "Address that hypervisor should be loaded at"), INIT_PARAM(openboot_addr, "Address that openboot should be loaded at"), + INIT_PARAM(nvram_addr, "Address that nvram should be loaded at"), + INIT_PARAM(hypervisor_desc_addr, + "Address that hypervisor description should be loaded at"), + INIT_PARAM(partition_desc_addr, + "Address that partition description should be loaded at"), INIT_PARAM(kernel, "file that contains the kernel code"), INIT_PARAM(reset_bin, "file that contains the reset code"), INIT_PARAM(hypervisor_bin, "file that contains the hypervisor code"), INIT_PARAM(openboot_bin, "file that contains the openboot code"), + INIT_PARAM(nvram_bin, "file that contains the nvram image"), + INIT_PARAM(hypervisor_desc_bin, + "file that contains the hypervisor description image"), + INIT_PARAM(partition_desc_bin, + "file that contains the partition description image"), INIT_PARAM(boot_cpu_frequency, "Frequency of the boot CPU"), INIT_PARAM_DFLT(boot_osflags, "flags to pass to the kernel during boot", "a"), @@ -197,14 +292,23 @@ CREATE_SIM_OBJECT(SparcSystem) p->boot_cpu_frequency = boot_cpu_frequency; p->physmem = physmem; p->rom = rom; + p->nvram = nvram; + p->hypervisor_desc = hypervisor_desc; + p->partition_desc = partition_desc; p->mem_mode = mem_mode; p->kernel_path = kernel; p->reset_addr = reset_addr; p->hypervisor_addr = hypervisor_addr; p->openboot_addr = openboot_addr; + p->nvram_addr = nvram_addr; + p->hypervisor_desc_addr = hypervisor_desc_addr; + p->partition_desc_addr = partition_desc_addr; p->reset_bin = reset_bin; p->hypervisor_bin = hypervisor_bin; p->openboot_bin = openboot_bin; + p->nvram_bin = nvram_bin; + p->hypervisor_desc_bin = hypervisor_desc_bin; + p->partition_desc_bin = partition_desc_bin; p->boot_osflags = boot_osflags; p->init_param = init_param; p->readfile = readfile; diff --git a/src/arch/sparc/system.hh b/src/arch/sparc/system.hh index 9cf3bb568..5d50ea067 100644 --- a/src/arch/sparc/system.hh +++ b/src/arch/sparc/system.hh @@ -46,12 +46,21 @@ class SparcSystem : public System struct Params : public System::Params { PhysicalMemory *rom; + PhysicalMemory *nvram; + PhysicalMemory *hypervisor_desc; + PhysicalMemory *partition_desc; Addr reset_addr; Addr hypervisor_addr; Addr openboot_addr; + Addr nvram_addr; + Addr hypervisor_desc_addr; + Addr partition_desc_addr; std::string reset_bin; std::string hypervisor_bin; std::string openboot_bin; + std::string nvram_bin; + std::string hypervisor_desc_bin; + std::string partition_desc_bin; std::string boot_osflags; }; @@ -77,6 +86,15 @@ class SparcSystem : public System /** openboot symbol table */ SymbolTable *openbootSymtab; + /** nvram symbol table? */ + SymbolTable *nvramSymtab; + + /** hypervisor desc symbol table? */ + SymbolTable *hypervisorDescSymtab; + + /** partition desc symbol table? */ + SymbolTable *partitionDescSymtab; + /** Object pointer for the reset binary */ ObjectFile *reset; @@ -86,12 +104,30 @@ class SparcSystem : public System /** Object pointer for the openboot code */ ObjectFile *openboot; + /** Object pointer for the nvram image */ + ObjectFile *nvram; + + /** Object pointer for the hypervisor description image */ + ObjectFile *hypervisor_desc; + + /** Object pointer for the partition description image */ + ObjectFile *partition_desc; + /** System Tick for syncronized tick across all cpus. */ Tick sysTick; /** functional port to ROM */ FunctionalPort funcRomPort; + /** functional port to nvram */ + FunctionalPort funcNvramPort; + + /** functional port to hypervisor description */ + FunctionalPort funcHypDescPort; + + /** functional port to partition description */ + FunctionalPort funcPartDescPort; + protected: const Params *params() const { return (const Params *)_params; } diff --git a/src/cpu/base_dyn_inst.hh b/src/cpu/base_dyn_inst.hh index 9037c96df..17e121dbf 100644 --- a/src/cpu/base_dyn_inst.hh +++ b/src/cpu/base_dyn_inst.hh @@ -39,6 +39,7 @@ #include "base/fast_alloc.hh" #include "base/trace.hh" #include "config/full_system.hh" +#include "cpu/o3/comm.hh" #include "cpu/exetrace.hh" #include "cpu/inst_seq.hh" #include "cpu/op_class.hh" @@ -62,10 +63,6 @@ class BaseDynInst : public FastAlloc, public RefCounted typedef typename Impl::CPUType ImplCPU; typedef typename ImplCPU::ImplState ImplState; - // Binary machine instruction type. - typedef TheISA::MachInst MachInst; - // Extended machine instruction type - typedef TheISA::ExtMachInst ExtMachInst; // Logical register index type. typedef TheISA::RegIndex RegIndex; // Integer register type. @@ -236,7 +233,105 @@ class BaseDynInst : public FastAlloc, public RefCounted */ bool _readySrcRegIdx[MaxInstSrcRegs]; + protected: + /** Flattened register index of the destination registers of this + * instruction. + */ + TheISA::RegIndex _flatDestRegIdx[TheISA::MaxInstDestRegs]; + + /** Flattened register index of the source registers of this + * instruction. + */ + TheISA::RegIndex _flatSrcRegIdx[TheISA::MaxInstSrcRegs]; + + /** Physical register index of the destination registers of this + * instruction. + */ + PhysRegIndex _destRegIdx[TheISA::MaxInstDestRegs]; + + /** Physical register index of the source registers of this + * instruction. + */ + PhysRegIndex _srcRegIdx[TheISA::MaxInstSrcRegs]; + + /** Physical register index of the previous producers of the + * architected destinations. + */ + PhysRegIndex _prevDestRegIdx[TheISA::MaxInstDestRegs]; + public: + + /** Returns the physical register index of the i'th destination + * register. + */ + PhysRegIndex renamedDestRegIdx(int idx) const + { + return _destRegIdx[idx]; + } + + /** Returns the physical register index of the i'th source register. */ + PhysRegIndex renamedSrcRegIdx(int idx) const + { + return _srcRegIdx[idx]; + } + + /** Returns the flattened register index of the i'th destination + * register. + */ + TheISA::RegIndex flattenedDestRegIdx(int idx) const + { + return _flatDestRegIdx[idx]; + } + + /** Returns the flattened register index of the i'th source register */ + TheISA::RegIndex flattenedSrcRegIdx(int idx) const + { + return _flatSrcRegIdx[idx]; + } + + /** Returns the physical register index of the previous physical register + * that remapped to the same logical register index. + */ + PhysRegIndex prevDestRegIdx(int idx) const + { + return _prevDestRegIdx[idx]; + } + + /** Renames a destination register to a physical register. Also records + * the previous physical register that the logical register mapped to. + */ + void renameDestReg(int idx, + PhysRegIndex renamed_dest, + PhysRegIndex previous_rename) + { + _destRegIdx[idx] = renamed_dest; + _prevDestRegIdx[idx] = previous_rename; + } + + /** Renames a source logical register to the physical register which + * has/will produce that logical register's result. + * @todo: add in whether or not the source register is ready. + */ + void renameSrcReg(int idx, PhysRegIndex renamed_src) + { + _srcRegIdx[idx] = renamed_src; + } + + /** Flattens a source architectural register index into a logical index. + */ + void flattenSrcReg(int idx, TheISA::RegIndex flattened_src) + { + _flatSrcRegIdx[idx] = flattened_src; + } + + /** Flattens a destination architectural register index into a logical + * index. + */ + void flattenDestReg(int idx, TheISA::RegIndex flattened_dest) + { + _flatDestRegIdx[idx] = flattened_dest; + } + /** BaseDynInst constructor given a binary instruction. * @param inst The binary instruction. * @param PC The PC of the instruction. @@ -244,8 +339,8 @@ class BaseDynInst : public FastAlloc, public RefCounted * @param seq_num The sequence number of the instruction. * @param cpu Pointer to the instruction's CPU. */ - BaseDynInst(ExtMachInst inst, Addr PC, Addr pred_PC, InstSeqNum seq_num, - ImplCPU *cpu); + BaseDynInst(TheISA::ExtMachInst inst, Addr PC, Addr pred_PC, + InstSeqNum seq_num, ImplCPU *cpu); /** BaseDynInst constructor given a StaticInst pointer. * @param _staticInst The StaticInst for this BaseDynInst. @@ -298,9 +393,9 @@ class BaseDynInst : public FastAlloc, public RefCounted /** Returns whether the instruction was predicted taken or not. */ bool predTaken() #if ISA_HAS_DELAY_SLOT - { return predPC != (nextPC + sizeof(MachInst)); } + { return predPC != (nextPC + sizeof(TheISA::MachInst)); } #else - { return predPC != (PC + sizeof(MachInst)); } + { return predPC != (PC + sizeof(TheISA::MachInst)); } #endif /** Returns whether the instruction mispredicted. */ diff --git a/src/cpu/exetrace.cc b/src/cpu/exetrace.cc index 113f0fe74..780a0c4f7 100644 --- a/src/cpu/exetrace.cc +++ b/src/cpu/exetrace.cc @@ -66,6 +66,56 @@ SharedData *shared_data = NULL; // Methods for the InstRecord object // +#if THE_ISA == SPARC_ISA + +inline char * genCenteredLabel(int length, char * buffer, char * label) +{ + int labelLength = strlen(label); + assert(labelLength <= length); + int leftPad = (length - labelLength) / 2; + int rightPad = length - leftPad - labelLength; + char format[64]; + sprintf(format, "%%%ds%%s%%%ds", leftPad, rightPad); + sprintf(buffer, format, "", label, ""); + return buffer; +} + +inline void printRegPair(ostream & os, char const * title, uint64_t a, uint64_t b) +{ + ccprintf(os, " %16s | %#018x %s %#-018x \n", + title, a, (a == b) ? "|" : "X", b); +} + +inline void printColumnLabels(ostream & os) +{ + static char * regLabel = genCenteredLabel(16, new char[17], "Register"); + static char * m5Label = genCenteredLabel(18, new char[18], "M5"); + static char * legionLabel = genCenteredLabel(18, new char[18], "Legion"); + ccprintf(os, " %s | %s | %s \n", regLabel, m5Label, legionLabel); + ccprintf(os, "--------------------+-----------------------+-----------------------\n"); +} + +inline void printSectionHeader(ostream & os, char * name) +{ + char sectionString[70]; + genCenteredLabel(69, sectionString, name); + ccprintf(os, "====================================================================\n"); + ccprintf(os, "%69s\n", sectionString); + ccprintf(os, "====================================================================\n"); +} + +inline void printLevelHeader(ostream & os, int level) +{ + char sectionString[70]; + char levelName[70]; + sprintf(levelName, "Trap stack level %d", level); + genCenteredLabel(69, sectionString, levelName); + ccprintf(os, "====================================================================\n"); + ccprintf(os, "%69s\n", sectionString); + ccprintf(os, "====================================================================\n"); +} + +#endif void Trace::InstRecord::dump(ostream &outs) @@ -91,13 +141,15 @@ Trace::InstRecord::dump(ostream &outs) outs << hex; outs << "PC = " << thread->readNextPC(); outs << " NPC = " << thread->readNextNPC(); - newVal = thread->readMiscReg(SparcISA::MISCREG_CCR); + newVal = thread->readIntReg(SparcISA::NumIntArchRegs + 2); + //newVal = thread->readMiscReg(SparcISA::MISCREG_CCR); if(newVal != ccr) { outs << " CCR = " << newVal; ccr = newVal; } - newVal = thread->readMiscReg(SparcISA::MISCREG_Y); + newVal = thread->readIntReg(SparcISA::NumIntArchRegs + 1); + //newVal = thread->readMiscReg(SparcISA::MISCREG_Y); if(newVal != y) { outs << " Y = " << newVal; @@ -237,25 +289,122 @@ Trace::InstRecord::dump(ostream &outs) bool diffPC = false; bool diffInst = false; bool diffRegs = false; + bool diffTpc = false; + bool diffTnpc = false; + bool diffTstate = false; + bool diffTt = false; + bool diffTba = false; + bool diffHpstate = false; + bool diffHtstate = false; + bool diffHtba = false; + bool diffPstate = false; + bool diffY = false; + bool diffCcr = false; + bool diffTl = false; + bool diffGl = false; + bool diffAsi = false; + bool diffPil = false; + bool diffCwp = false; + bool diffCansave = false; + bool diffCanrestore = false; + bool diffOtherwin = false; + bool diffCleanwin = false; Addr m5Pc, lgnPc; if(!staticInst->isMicroOp() || staticInst->isLastMicroOp()) { while (!compared) { - m5Pc = PC & TheISA::PAddrImplMask; - lgnPc = shared_data->pc & TheISA::PAddrImplMask; if (shared_data->flags == OWN_M5) { + m5Pc = PC & TheISA::PAddrImplMask; + lgnPc = shared_data->pc & TheISA::PAddrImplMask; if (lgnPc != m5Pc) diffPC = true; - if (shared_data->instruction != staticInst->machInst) + if (shared_data->instruction != + (SparcISA::MachInst)staticInst->machInst) { diffInst = true; - for (int i = 0; i < TheISA::NumRegularIntRegs; i++) { + } + for (int i = 0; i < TheISA::NumIntArchRegs; i++) { if (thread->readIntReg(i) != shared_data->intregs[i]) { diffRegs = true; } } - - if (diffPC || diffInst || diffRegs ) { + uint64_t oldTl = thread->readMiscReg(MISCREG_TL); + if (oldTl != shared_data->tl) + diffTl = true; + for (int i = 1; i <= MaxTL; i++) { + thread->setMiscReg(MISCREG_TL, i); + if (thread->readMiscReg(MISCREG_TPC) != + shared_data->tpc[i]) + diffTpc = true; + if (thread->readMiscReg(MISCREG_TNPC) != + shared_data->tnpc[i]) + diffTnpc = true; + if (thread->readMiscReg(MISCREG_TSTATE) != + shared_data->tstate[i]) + diffTstate = true; + if (thread->readMiscReg(MISCREG_TT) != + shared_data->tt[i]) + diffTt = true; + if (thread->readMiscReg(MISCREG_HTSTATE) != + shared_data->htstate[i]) + diffHtstate = true; + } + thread->setMiscReg(MISCREG_TL, oldTl); + + if(shared_data->tba != thread->readMiscReg(MISCREG_TBA)) + diffTba = true; + //When the hpstate register is read by an instruction, + //legion has bit 11 set. When it's in storage, it doesn't. + //Since we don't directly support seperate interpretations + //of the registers like that, the bit is always set to 1 and + //we just don't compare it. It's not supposed to matter + //anyway. + if((shared_data->hpstate | (1 << 11)) != thread->readMiscReg(MISCREG_HPSTATE)) + diffHpstate = true; + if(shared_data->htba != thread->readMiscReg(MISCREG_HTBA)) + diffHtba = true; + if(shared_data->pstate != thread->readMiscReg(MISCREG_PSTATE)) + diffPstate = true; + //if(shared_data->y != thread->readMiscReg(MISCREG_Y)) + if(shared_data->y != + thread->readIntReg(NumIntArchRegs + 1)) + diffY = true; + //if(shared_data->ccr != thread->readMiscReg(MISCREG_CCR)) + if(shared_data->ccr != + thread->readIntReg(NumIntArchRegs + 2)) + diffCcr = true; + if(shared_data->gl != thread->readMiscReg(MISCREG_GL)) + diffGl = true; + if(shared_data->asi != thread->readMiscReg(MISCREG_ASI)) + diffAsi = true; + if(shared_data->pil != thread->readMiscReg(MISCREG_PIL)) + diffPil = true; + if(shared_data->cwp != thread->readMiscReg(MISCREG_CWP)) + diffCwp = true; + //if(shared_data->cansave != thread->readMiscReg(MISCREG_CANSAVE)) + if(shared_data->cansave != + thread->readIntReg(NumIntArchRegs + 3)) + diffCansave = true; + //if(shared_data->canrestore != + // thread->readMiscReg(MISCREG_CANRESTORE)) + if(shared_data->canrestore != + thread->readMiscReg(NumIntArchRegs + 4)) + diffCanrestore = true; + //if(shared_data->otherwin != thread->readMiscReg(MISCREG_OTHERWIN)) + if(shared_data->otherwin != + thread->readIntReg(NumIntArchRegs + 5)) + diffOtherwin = true; + //if(shared_data->cleanwin != thread->readMiscReg(MISCREG_CLEANWIN)) + if(shared_data->cleanwin != + thread->readMiscReg(NumIntArchRegs + 6)) + diffCleanwin = true; + + if (diffPC || diffInst || diffRegs || diffTpc || diffTnpc || + diffTstate || diffTt || diffHpstate || + diffHtstate || diffHtba || diffPstate || diffY || + diffCcr || diffTl || diffGl || diffAsi || diffPil || + diffCwp || diffCansave || diffCanrestore || + diffOtherwin || diffCleanwin) { outs << "Differences found between M5 and Legion:"; if (diffPC) outs << " [PC]"; @@ -263,6 +412,44 @@ Trace::InstRecord::dump(ostream &outs) outs << " [Instruction]"; if (diffRegs) outs << " [IntRegs]"; + if (diffTpc) + outs << " [Tpc]"; + if (diffTnpc) + outs << " [Tnpc]"; + if (diffTstate) + outs << " [Tstate]"; + if (diffTt) + outs << " [Tt]"; + if (diffHpstate) + outs << " [Hpstate]"; + if (diffHtstate) + outs << " [Htstate]"; + if (diffHtba) + outs << " [Htba]"; + if (diffPstate) + outs << " [Pstate]"; + if (diffY) + outs << " [Y]"; + if (diffCcr) + outs << " [Ccr]"; + if (diffTl) + outs << " [Tl]"; + if (diffGl) + outs << " [Gl]"; + if (diffAsi) + outs << " [Asi]"; + if (diffPil) + outs << " [Pil]"; + if (diffCwp) + outs << " [Cwp]"; + if (diffCansave) + outs << " [Cansave]"; + if (diffCanrestore) + outs << " [Canrestore]"; + if (diffOtherwin) + outs << " [Otherwin]"; + if (diffCleanwin) + outs << " [Cleanwin]"; outs << endl << endl; outs << right << setfill(' ') << setw(15) @@ -278,29 +465,112 @@ Trace::InstRecord::dump(ostream &outs) << staticInst->disassemble(m5Pc, debugSymbolTable) << endl; - StaticInstPtr legionInst = StaticInst::decode(makeExtMI(shared_data->instruction, thread)); + StaticInstPtr legionInst = + StaticInst::decode(makeExtMI(shared_data->instruction, + thread)); outs << setfill(' ') << setw(15) << " Legion Inst: " << "0x" << setw(8) << setfill('0') << hex << shared_data->instruction << legionInst->disassemble(lgnPc, debugSymbolTable) - << endl; - + << endl << endl; + + printSectionHeader(outs, "General State"); + printColumnLabels(outs); + printRegPair(outs, "HPstate", + thread->readMiscReg(MISCREG_HPSTATE), + shared_data->hpstate | (1 << 11)); + printRegPair(outs, "Htba", + thread->readMiscReg(MISCREG_HTBA), + shared_data->htba); + printRegPair(outs, "Pstate", + thread->readMiscReg(MISCREG_PSTATE), + shared_data->pstate); + printRegPair(outs, "Y", + //thread->readMiscReg(MISCREG_Y), + thread->readMiscReg(NumIntArchRegs + 1), + shared_data->y); + printRegPair(outs, "Ccr", + //thread->readMiscReg(MISCREG_CCR), + thread->readMiscReg(NumIntArchRegs + 2), + shared_data->ccr); + printRegPair(outs, "Tl", + thread->readMiscReg(MISCREG_TL), + shared_data->tl); + printRegPair(outs, "Gl", + thread->readMiscReg(MISCREG_GL), + shared_data->gl); + printRegPair(outs, "Asi", + thread->readMiscReg(MISCREG_ASI), + shared_data->asi); + printRegPair(outs, "Pil", + thread->readMiscReg(MISCREG_PIL), + shared_data->pil); + printRegPair(outs, "Cwp", + thread->readMiscReg(MISCREG_CWP), + shared_data->cwp); + printRegPair(outs, "Cansave", + //thread->readMiscReg(MISCREG_CANSAVE), + thread->readIntReg(NumIntArchRegs + 3), + shared_data->cansave); + printRegPair(outs, "Canrestore", + //thread->readMiscReg(MISCREG_CANRESTORE), + thread->readIntReg(NumIntArchRegs + 4), + shared_data->canrestore); + printRegPair(outs, "Otherwin", + //thread->readMiscReg(MISCREG_OTHERWIN), + thread->readIntReg(NumIntArchRegs + 5), + shared_data->otherwin); + printRegPair(outs, "Cleanwin", + //thread->readMiscReg(MISCREG_CLEANWIN), + thread->readIntReg(NumIntArchRegs + 6), + shared_data->cleanwin); + outs << endl; + for (int i = 1; i <= MaxTL; i++) { + printLevelHeader(outs, i); + printColumnLabels(outs); + thread->setMiscReg(MISCREG_TL, i); + printRegPair(outs, "Tpc", + thread->readMiscReg(MISCREG_TPC), + shared_data->tpc[i]); + printRegPair(outs, "Tnpc", + thread->readMiscReg(MISCREG_TNPC), + shared_data->tnpc[i]); + printRegPair(outs, "Tstate", + thread->readMiscReg(MISCREG_TSTATE), + shared_data->tstate[i]); + printRegPair(outs, "Tt", + thread->readMiscReg(MISCREG_TT), + shared_data->tt[i]); + printRegPair(outs, "Htstate", + thread->readMiscReg(MISCREG_HTSTATE), + shared_data->htstate[i]); + } + thread->setMiscReg(MISCREG_TL, oldTl); outs << endl; + printSectionHeader(outs, "General Purpose Registers"); static const char * regtypes[4] = {"%g", "%o", "%l", "%i"}; for(int y = 0; y < 4; y++) { for(int x = 0; x < 8; x++) { - outs << regtypes[y] << x << " " ; - outs << "0x" << hex << setw(16) << thread->readIntReg(y*8+x); - if (thread->readIntReg(y*8 + x) != shared_data->intregs[y*8+x]) + char label[8]; + sprintf(label, "%s%d", regtypes[y], x); + printRegPair(outs, label, + thread->readIntReg(y*8+x), + shared_data->intregs[y*8+x]); + /*outs << regtypes[y] << x << " " ; + outs << "0x" << hex << setw(16) + << thread->readIntReg(y*8+x); + if (thread->readIntReg(y*8 + x) + != shared_data->intregs[y*8+x]) outs << " X "; else outs << " | "; - outs << "0x" << setw(16) << hex << shared_data->intregs[y*8+x] - << endl; + outs << "0x" << setw(16) << hex + << shared_data->intregs[y*8+x] + << endl;*/ } } fatal("Differences found between Legion and M5\n"); diff --git a/src/cpu/o3/alpha/cpu.hh b/src/cpu/o3/alpha/cpu.hh index 0078db69f..4a2086296 100644 --- a/src/cpu/o3/alpha/cpu.hh +++ b/src/cpu/o3/alpha/cpu.hh @@ -37,12 +37,6 @@ #include "cpu/o3/cpu.hh" #include "sim/byteswap.hh" -namespace TheISA -{ - class ITB; - class DTB; -} - class EndQuiesceEvent; namespace Kernel { class Statistics; @@ -61,14 +55,6 @@ class TranslatingPort; template <class Impl> class AlphaO3CPU : public FullO3CPU<Impl> { - protected: - typedef TheISA::IntReg IntReg; - typedef TheISA::FloatReg FloatReg; - typedef TheISA::FloatRegBits FloatRegBits; - typedef TheISA::MiscReg MiscReg; - typedef TheISA::RegFile RegFile; - typedef TheISA::MiscRegFile MiscRegFile; - public: typedef O3ThreadState<Impl> ImplState; typedef O3ThreadState<Impl> Thread; @@ -77,13 +63,6 @@ class AlphaO3CPU : public FullO3CPU<Impl> /** Constructs an AlphaO3CPU with the given parameters. */ AlphaO3CPU(Params *params); -#if FULL_SYSTEM - /** ITB pointer. */ - AlphaISA::ITB *itb; - /** DTB pointer. */ - AlphaISA::DTB *dtb; -#endif - /** Registers statistics. */ void regStats(); @@ -91,19 +70,19 @@ class AlphaO3CPU : public FullO3CPU<Impl> /** Translates instruction requestion. */ Fault translateInstReq(RequestPtr &req, Thread *thread) { - return itb->translate(req, thread->getTC()); + return this->itb->translate(req, thread->getTC()); } /** Translates data read request. */ Fault translateDataReadReq(RequestPtr &req, Thread *thread) { - return dtb->translate(req, thread->getTC(), false); + return this->dtb->translate(req, thread->getTC(), false); } /** Translates data write request. */ Fault translateDataWriteReq(RequestPtr &req, Thread *thread) { - return dtb->translate(req, thread->getTC(), true); + return this->dtb->translate(req, thread->getTC(), true); } #else @@ -127,20 +106,22 @@ class AlphaO3CPU : public FullO3CPU<Impl> #endif /** Reads a miscellaneous register. */ - MiscReg readMiscReg(int misc_reg, unsigned tid); + TheISA::MiscReg readMiscReg(int misc_reg, unsigned tid); /** Reads a misc. register, including any side effects the read * might have as defined by the architecture. */ - MiscReg readMiscRegWithEffect(int misc_reg, unsigned tid); + TheISA::MiscReg readMiscRegWithEffect(int misc_reg, unsigned tid); /** Sets a miscellaneous register. */ - void setMiscReg(int misc_reg, const MiscReg &val, unsigned tid); + void setMiscReg(int misc_reg, const TheISA::MiscReg &val, + unsigned tid); /** Sets a misc. register, including any side effects the write * might have as defined by the architecture. */ - void setMiscRegWithEffect(int misc_reg, const MiscReg &val, unsigned tid); + void setMiscRegWithEffect(int misc_reg, const TheISA::MiscReg &val, + unsigned tid); /** Initiates a squash of all in-flight instructions for a given * thread. The source of the squash is an external update of @@ -175,10 +156,10 @@ class AlphaO3CPU : public FullO3CPU<Impl> */ void syscall(int64_t callnum, int tid); /** Gets a syscall argument. */ - IntReg getSyscallArg(int i, int tid); + TheISA::IntReg getSyscallArg(int i, int tid); /** Used to shift args for indirect syscall. */ - void setSyscallArg(int i, IntReg val, int tid); + void setSyscallArg(int i, TheISA::IntReg val, int tid); /** Sets the return value of a syscall. */ void setSyscallReturn(SyscallReturn return_value, int tid); diff --git a/src/cpu/o3/alpha/cpu_impl.hh b/src/cpu/o3/alpha/cpu_impl.hh index 98fd0699a..fb0962056 100644 --- a/src/cpu/o3/alpha/cpu_impl.hh +++ b/src/cpu/o3/alpha/cpu_impl.hh @@ -55,12 +55,7 @@ #endif template <class Impl> -AlphaO3CPU<Impl>::AlphaO3CPU(Params *params) -#if FULL_SYSTEM - : FullO3CPU<Impl>(params), itb(params->itb), dtb(params->dtb) -#else - : FullO3CPU<Impl>(params) -#endif +AlphaO3CPU<Impl>::AlphaO3CPU(Params *params) : FullO3CPU<Impl>(params) { DPRINTF(O3CPU, "Creating AlphaO3CPU object.\n"); @@ -173,15 +168,16 @@ AlphaO3CPU<Impl>::readMiscRegWithEffect(int misc_reg, unsigned tid) template <class Impl> void -AlphaO3CPU<Impl>::setMiscReg(int misc_reg, const MiscReg &val, unsigned tid) +AlphaO3CPU<Impl>::setMiscReg(int misc_reg, const TheISA::MiscReg &val, + unsigned tid) { this->regFile.setMiscReg(misc_reg, val, tid); } template <class Impl> void -AlphaO3CPU<Impl>::setMiscRegWithEffect(int misc_reg, const MiscReg &val, - unsigned tid) +AlphaO3CPU<Impl>::setMiscRegWithEffect(int misc_reg, + const TheISA::MiscReg &val, unsigned tid) { this->regFile.setMiscRegWithEffect(misc_reg, val, tid); } @@ -315,7 +311,7 @@ AlphaO3CPU<Impl>::getSyscallArg(int i, int tid) template <class Impl> void -AlphaO3CPU<Impl>::setSyscallArg(int i, IntReg val, int tid) +AlphaO3CPU<Impl>::setSyscallArg(int i, TheISA::IntReg val, int tid) { this->setArchIntReg(AlphaISA::ArgumentReg0 + i, val, tid); } @@ -324,17 +320,6 @@ template <class Impl> void AlphaO3CPU<Impl>::setSyscallReturn(SyscallReturn return_value, int tid) { - // check for error condition. Alpha syscall convention is to - // indicate success/failure in reg a3 (r19) and put the - // return value itself in the standard return value reg (v0). - if (return_value.successful()) { - // no error - this->setArchIntReg(TheISA::SyscallSuccessReg, 0, tid); - this->setArchIntReg(TheISA::ReturnValueReg, return_value.value(), tid); - } else { - // got an error, return details - this->setArchIntReg(TheISA::SyscallSuccessReg, (IntReg) -1, tid); - this->setArchIntReg(TheISA::ReturnValueReg, -return_value.value(), tid); - } + TheISA::setSyscallReturn(return_value, this->tcBase(tid)); } #endif diff --git a/src/cpu/o3/alpha/dyn_inst.hh b/src/cpu/o3/alpha/dyn_inst.hh index 49cc5a201..c340a806a 100644 --- a/src/cpu/o3/alpha/dyn_inst.hh +++ b/src/cpu/o3/alpha/dyn_inst.hh @@ -134,22 +134,6 @@ class AlphaDynInst : public BaseDynInst<Impl> void syscall(int64_t callnum); #endif - private: - /** Physical register index of the destination registers of this - * instruction. - */ - PhysRegIndex _destRegIdx[MaxInstDestRegs]; - - /** Physical register index of the source registers of this - * instruction. - */ - PhysRegIndex _srcRegIdx[MaxInstSrcRegs]; - - /** Physical register index of the previous producers of the - * architected destinations. - */ - PhysRegIndex _prevDestRegIdx[MaxInstDestRegs]; - public: // The register accessor methods provide the index of the @@ -165,28 +149,28 @@ class AlphaDynInst : public BaseDynInst<Impl> uint64_t readIntRegOperand(const StaticInst *si, int idx) { - return this->cpu->readIntReg(_srcRegIdx[idx]); + return this->cpu->readIntReg(this->_srcRegIdx[idx]); } FloatReg readFloatRegOperand(const StaticInst *si, int idx, int width) { - return this->cpu->readFloatReg(_srcRegIdx[idx], width); + return this->cpu->readFloatReg(this->_srcRegIdx[idx], width); } FloatReg readFloatRegOperand(const StaticInst *si, int idx) { - return this->cpu->readFloatReg(_srcRegIdx[idx]); + return this->cpu->readFloatReg(this->_srcRegIdx[idx]); } FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx, int width) { - return this->cpu->readFloatRegBits(_srcRegIdx[idx], width); + return this->cpu->readFloatRegBits(this->_srcRegIdx[idx], width); } FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx) { - return this->cpu->readFloatRegBits(_srcRegIdx[idx]); + return this->cpu->readFloatRegBits(this->_srcRegIdx[idx]); } /** @todo: Make results into arrays so they can handle multiple dest @@ -194,79 +178,37 @@ class AlphaDynInst : public BaseDynInst<Impl> */ void setIntRegOperand(const StaticInst *si, int idx, uint64_t val) { - this->cpu->setIntReg(_destRegIdx[idx], val); + this->cpu->setIntReg(this->_destRegIdx[idx], val); BaseDynInst<Impl>::setIntRegOperand(si, idx, val); } void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val, int width) { - this->cpu->setFloatReg(_destRegIdx[idx], val, width); + this->cpu->setFloatReg(this->_destRegIdx[idx], val, width); BaseDynInst<Impl>::setFloatRegOperand(si, idx, val, width); } void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val) { - this->cpu->setFloatReg(_destRegIdx[idx], val); + this->cpu->setFloatReg(this->_destRegIdx[idx], val); BaseDynInst<Impl>::setFloatRegOperand(si, idx, val); } void setFloatRegOperandBits(const StaticInst *si, int idx, FloatRegBits val, int width) { - this->cpu->setFloatRegBits(_destRegIdx[idx], val, width); + this->cpu->setFloatRegBits(this->_destRegIdx[idx], val, width); BaseDynInst<Impl>::setFloatRegOperandBits(si, idx, val); } void setFloatRegOperandBits(const StaticInst *si, int idx, FloatRegBits val) { - this->cpu->setFloatRegBits(_destRegIdx[idx], val); + this->cpu->setFloatRegBits(this->_destRegIdx[idx], val); BaseDynInst<Impl>::setFloatRegOperandBits(si, idx, val); } - /** Returns the physical register index of the i'th destination - * register. - */ - PhysRegIndex renamedDestRegIdx(int idx) const - { - return _destRegIdx[idx]; - } - - /** Returns the physical register index of the i'th source register. */ - PhysRegIndex renamedSrcRegIdx(int idx) const - { - return _srcRegIdx[idx]; - } - - /** Returns the physical register index of the previous physical register - * that remapped to the same logical register index. - */ - PhysRegIndex prevDestRegIdx(int idx) const - { - return _prevDestRegIdx[idx]; - } - - /** Renames a destination register to a physical register. Also records - * the previous physical register that the logical register mapped to. - */ - void renameDestReg(int idx, - PhysRegIndex renamed_dest, - PhysRegIndex previous_rename) - { - _destRegIdx[idx] = renamed_dest; - _prevDestRegIdx[idx] = previous_rename; - } - - /** Renames a source logical register to the physical register which - * has/will produce that logical register's result. - * @todo: add in whether or not the source register is ready. - */ - void renameSrcReg(int idx, PhysRegIndex renamed_src) - { - _srcRegIdx[idx] = renamed_src; - } - public: /** Calculates EA part of a memory instruction. Currently unused, * though it may be useful in the future if we want to split diff --git a/src/cpu/o3/alpha/dyn_inst_impl.hh b/src/cpu/o3/alpha/dyn_inst_impl.hh index 6fc548a85..02432f721 100644 --- a/src/cpu/o3/alpha/dyn_inst_impl.hh +++ b/src/cpu/o3/alpha/dyn_inst_impl.hh @@ -53,11 +53,11 @@ AlphaDynInst<Impl>::initVars() // as the normal register entries. It will allow the IQ to work // without any modifications. for (int i = 0; i < this->staticInst->numDestRegs(); i++) { - _destRegIdx[i] = this->staticInst->destRegIdx(i); + this->_destRegIdx[i] = this->staticInst->destRegIdx(i); } for (int i = 0; i < this->staticInst->numSrcRegs(); i++) { - _srcRegIdx[i] = this->staticInst->srcRegIdx(i); + this->_srcRegIdx[i] = this->staticInst->srcRegIdx(i); this->_readySrcRegIdx[i] = 0; } } diff --git a/src/cpu/o3/alpha/thread_context.hh b/src/cpu/o3/alpha/thread_context.hh index bcecb7087..e4a6735c2 100644 --- a/src/cpu/o3/alpha/thread_context.hh +++ b/src/cpu/o3/alpha/thread_context.hh @@ -36,12 +36,6 @@ class AlphaTC : public O3ThreadContext<Impl> { public: #if FULL_SYSTEM - /** Returns a pointer to the ITB. */ - virtual AlphaISA::ITB *getITBPtr() { return this->cpu->itb; } - - /** Returns a pointer to the DTB. */ - virtual AlphaISA::DTB *getDTBPtr() { return this->cpu->dtb; } - /** Returns pointer to the quiesce event. */ virtual EndQuiesceEvent *getQuiesceEvent() { diff --git a/src/cpu/o3/comm.hh b/src/cpu/o3/comm.hh index aa58fc20e..4683c77af 100644 --- a/src/cpu/o3/comm.hh +++ b/src/cpu/o3/comm.hh @@ -87,7 +87,7 @@ struct DefaultIEWDefaultCommit { bool squash[Impl::MaxThreads]; bool branchMispredict[Impl::MaxThreads]; bool branchTaken[Impl::MaxThreads]; - bool condDelaySlotBranch[Impl::MaxThreads]; + bool squashDelaySlot[Impl::MaxThreads]; uint64_t mispredPC[Impl::MaxThreads]; uint64_t nextPC[Impl::MaxThreads]; InstSeqNum squashedSeqNum[Impl::MaxThreads]; diff --git a/src/cpu/o3/commit_impl.hh b/src/cpu/o3/commit_impl.hh index f400d757b..3178410a8 100644 --- a/src/cpu/o3/commit_impl.hh +++ b/src/cpu/o3/commit_impl.hh @@ -728,28 +728,11 @@ DefaultCommit<Impl>::commit() InstSeqNum squashed_inst = fromIEW->squashedSeqNum[tid]; #if ISA_HAS_DELAY_SLOT - InstSeqNum bdelay_done_seq_num; - bool squash_bdelay_slot; - - if (fromIEW->branchMispredict[tid]) { - if (fromIEW->branchTaken[tid] && - fromIEW->condDelaySlotBranch[tid]) { - DPRINTF(Commit, "[tid:%i]: Cond. delay slot branch" - "mispredicted as taken. Squashing after previous " - "inst, [sn:%i]\n", - tid, squashed_inst); - bdelay_done_seq_num = squashed_inst; - squash_bdelay_slot = true; - } else { - DPRINTF(Commit, "[tid:%i]: Branch Mispredict. Squashing " - "after delay slot [sn:%i]\n", tid, squashed_inst+1); - bdelay_done_seq_num = squashed_inst + 1; - squash_bdelay_slot = false; - } - } else { - bdelay_done_seq_num = squashed_inst; - squash_bdelay_slot = true; - } + InstSeqNum bdelay_done_seq_num = squashed_inst; + bool squash_bdelay_slot = fromIEW->squashDelaySlot[tid]; + + if (!squash_bdelay_slot) + bdelay_done_seq_num++; #endif if (fromIEW->includeSquashInst[tid] == true) { @@ -1117,7 +1100,7 @@ DefaultCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num) // Update the commit rename map for (int i = 0; i < head_inst->numDestRegs(); i++) { - renameMap[tid]->setEntry(head_inst->destRegIdx(i), + renameMap[tid]->setEntry(head_inst->flattenedDestRegIdx(i), head_inst->renamedDestRegIdx(i)); } diff --git a/src/cpu/o3/cpu.cc b/src/cpu/o3/cpu.cc index a5a00015f..4056d876f 100644 --- a/src/cpu/o3/cpu.cc +++ b/src/cpu/o3/cpu.cc @@ -149,6 +149,10 @@ FullO3CPU<Impl>::DeallocateContextEvent::description() template <class Impl> FullO3CPU<Impl>::FullO3CPU(Params *params) : BaseO3CPU(params), +#if FULL_SYSTEM + itb(params->itb), + dtb(params->dtb), +#endif tickEvent(this), removeInstsThisCycle(false), fetch(params), diff --git a/src/cpu/o3/cpu.hh b/src/cpu/o3/cpu.hh index 2bf9cb23b..d217a3e85 100644 --- a/src/cpu/o3/cpu.hh +++ b/src/cpu/o3/cpu.hh @@ -91,9 +91,6 @@ template <class Impl> class FullO3CPU : public BaseO3CPU { public: - typedef TheISA::FloatReg FloatReg; - typedef TheISA::FloatRegBits FloatRegBits; - // Typedefs from the Impl here. typedef typename Impl::CPUPol CPUPolicy; typedef typename Impl::Params Params; @@ -114,6 +111,11 @@ class FullO3CPU : public BaseO3CPU SwitchedOut }; +#if FULL_SYSTEM + TheISA::ITB * itb; + TheISA::DTB * dtb; +#endif + /** Overall CPU status. */ Status _status; @@ -382,23 +384,23 @@ class FullO3CPU : public BaseO3CPU /** Register accessors. Index refers to the physical register index. */ uint64_t readIntReg(int reg_idx); - FloatReg readFloatReg(int reg_idx); + TheISA::FloatReg readFloatReg(int reg_idx); - FloatReg readFloatReg(int reg_idx, int width); + TheISA::FloatReg readFloatReg(int reg_idx, int width); - FloatRegBits readFloatRegBits(int reg_idx); + TheISA::FloatRegBits readFloatRegBits(int reg_idx); - FloatRegBits readFloatRegBits(int reg_idx, int width); + TheISA::FloatRegBits readFloatRegBits(int reg_idx, int width); void setIntReg(int reg_idx, uint64_t val); - void setFloatReg(int reg_idx, FloatReg val); + void setFloatReg(int reg_idx, TheISA::FloatReg val); - void setFloatReg(int reg_idx, FloatReg val, int width); + void setFloatReg(int reg_idx, TheISA::FloatReg val, int width); - void setFloatRegBits(int reg_idx, FloatRegBits val); + void setFloatRegBits(int reg_idx, TheISA::FloatRegBits val); - void setFloatRegBits(int reg_idx, FloatRegBits val, int width); + void setFloatRegBits(int reg_idx, TheISA::FloatRegBits val, int width); uint64_t readArchIntReg(int reg_idx, unsigned tid); diff --git a/src/cpu/o3/fetch_impl.hh b/src/cpu/o3/fetch_impl.hh index 622259495..6cff52429 100644 --- a/src/cpu/o3/fetch_impl.hh +++ b/src/cpu/o3/fetch_impl.hh @@ -1157,6 +1157,8 @@ DefaultFetch<Impl>::fetch(bool &status_change) "[sn:%lli]\n", tid, instruction->readPC(), inst_seq); + DPRINTF(Fetch, "[tid:%i]: MachInst is %#x\n", tid, ext_inst); + DPRINTF(Fetch, "[tid:%i]: Instruction is: %s\n", tid, instruction->staticInst->disassemble(fetch_PC)); diff --git a/src/cpu/o3/iew_impl.hh b/src/cpu/o3/iew_impl.hh index ba5260fe2..85db68576 100644 --- a/src/cpu/o3/iew_impl.hh +++ b/src/cpu/o3/iew_impl.hh @@ -481,18 +481,26 @@ DefaultIEW<Impl>::squashDueToBranch(DynInstPtr &inst, unsigned tid) toCommit->branchMispredict[tid] = true; #if ISA_HAS_DELAY_SLOT - bool branch_taken = inst->readNextNPC() != - (inst->readNextPC() + sizeof(TheISA::MachInst)); + bool branch_taken = + (inst->readNextNPC() != (inst->readPC() + 2 * sizeof(TheISA::MachInst)) && + inst->readNextNPC() != (inst->readPC() + 3 * sizeof(TheISA::MachInst))); + DPRINTF(Sparc, "Branch taken = %s [sn:%i]\n", + branch_taken ? "true": "false", inst->seqNum); toCommit->branchTaken[tid] = branch_taken; - toCommit->condDelaySlotBranch[tid] = inst->isCondDelaySlot(); - - if (inst->isCondDelaySlot() && branch_taken) { + bool squashDelaySlot = + (inst->readNextPC() != inst->readPC() + sizeof(TheISA::MachInst)); + DPRINTF(Sparc, "Squash delay slot = %s [sn:%i]\n", + squashDelaySlot ? "true": "false", inst->seqNum); + toCommit->squashDelaySlot[tid] = squashDelaySlot; + //If we're squashing the delay slot, we need to pick back up at NextPC. + //Otherwise, NextPC isn't being squashed, so we should pick back up at + //NextNPC. + if (squashDelaySlot) toCommit->nextPC[tid] = inst->readNextPC(); - } else { + else toCommit->nextPC[tid] = inst->readNextNPC(); - } #else toCommit->branchTaken[tid] = inst->readNextPC() != (inst->readPC() + sizeof(TheISA::MachInst)); diff --git a/src/cpu/o3/isa_specific.hh b/src/cpu/o3/isa_specific.hh index 4937589e3..72a8d4021 100755 --- a/src/cpu/o3/isa_specific.hh +++ b/src/cpu/o3/isa_specific.hh @@ -40,6 +40,11 @@ #include "cpu/o3/mips/impl.hh" #include "cpu/o3/mips/params.hh" #include "cpu/o3/mips/dyn_inst.hh" +#elif THE_ISA == SPARC_ISA + #include "cpu/o3/sparc/cpu.hh" + #include "cpu/o3/sparc/impl.hh" + #include "cpu/o3/sparc/params.hh" + #include "cpu/o3/sparc/dyn_inst.hh" #else #error "ISA-specific header files O3CPU not defined ISA" #endif diff --git a/src/cpu/o3/lsq_unit_impl.hh b/src/cpu/o3/lsq_unit_impl.hh index 3b84d3411..7ce3dc9cb 100644 --- a/src/cpu/o3/lsq_unit_impl.hh +++ b/src/cpu/o3/lsq_unit_impl.hh @@ -597,7 +597,11 @@ LSQUnit<Impl>::writebackStores() assert(!inst->memData); inst->memData = new uint8_t[64]; - memcpy(inst->memData, (uint8_t *)&storeQueue[storeWBIdx].data, + + TheISA::IntReg convertedData = + TheISA::htog(storeQueue[storeWBIdx].data); + + memcpy(inst->memData, (uint8_t *)&convertedData, req->getSize()); PacketPtr data_pkt = new Packet(req, Packet::WriteReq, Packet::Broadcast); diff --git a/src/cpu/o3/mips/cpu_impl.hh b/src/cpu/o3/mips/cpu_impl.hh index 08e9ba483..e7dbd3aba 100644 --- a/src/cpu/o3/mips/cpu_impl.hh +++ b/src/cpu/o3/mips/cpu_impl.hh @@ -220,16 +220,6 @@ template <class Impl> void MipsO3CPU<Impl>::setSyscallReturn(SyscallReturn return_value, int tid) { - // check for error condition. - if (return_value.successful()) { - // no error - this->setArchIntReg(TheISA::SyscallSuccessReg, 0, tid); - this->setArchIntReg(TheISA::ReturnValueReg, return_value.value(), tid); - } else { - // got an error, return details - this->setArchIntReg(TheISA::SyscallSuccessReg, - (TheISA::IntReg) -1, tid); - this->setArchIntReg(TheISA::ReturnValueReg, -return_value.value(), tid); - } + TheISA::setSyscallReturn(return_value, this->tcBase(tid)); } #endif diff --git a/src/cpu/o3/mips/dyn_inst.hh b/src/cpu/o3/mips/dyn_inst.hh index 833371e00..009a08012 100755 --- a/src/cpu/o3/mips/dyn_inst.hh +++ b/src/cpu/o3/mips/dyn_inst.hh @@ -54,10 +54,6 @@ class MipsDynInst : public BaseDynInst<Impl> /** Typedef for the CPU. */ typedef typename Impl::O3CPU O3CPU; - /** Binary machine instruction type. */ - typedef TheISA::MachInst MachInst; - /** Extended machine instruction type. */ - typedef TheISA::ExtMachInst ExtMachInst; /** Logical register index type. */ typedef TheISA::RegIndex RegIndex; /** Integer register index type. */ @@ -127,22 +123,6 @@ class MipsDynInst : public BaseDynInst<Impl> /** Calls a syscall. */ void syscall(int64_t callnum); - private: - /** Physical register index of the destination registers of this - * instruction. - */ - PhysRegIndex _destRegIdx[MaxInstDestRegs]; - - /** Physical register index of the source registers of this - * instruction. - */ - PhysRegIndex _srcRegIdx[MaxInstSrcRegs]; - - /** Physical register index of the previous producers of the - * architected destinations. - */ - PhysRegIndex _prevDestRegIdx[MaxInstDestRegs]; - public: // The register accessor methods provide the index of the @@ -158,28 +138,28 @@ class MipsDynInst : public BaseDynInst<Impl> uint64_t readIntRegOperand(const StaticInst *si, int idx) { - return this->cpu->readIntReg(_srcRegIdx[idx]); + return this->cpu->readIntReg(this->_srcRegIdx[idx]); } FloatReg readFloatRegOperand(const StaticInst *si, int idx, int width) { - return this->cpu->readFloatReg(_srcRegIdx[idx], width); + return this->cpu->readFloatReg(this->_srcRegIdx[idx], width); } FloatReg readFloatRegOperand(const StaticInst *si, int idx) { - return this->cpu->readFloatReg(_srcRegIdx[idx]); + return this->cpu->readFloatReg(this->_srcRegIdx[idx]); } FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx, int width) { - return this->cpu->readFloatRegBits(_srcRegIdx[idx], width); + return this->cpu->readFloatRegBits(this->_srcRegIdx[idx], width); } FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx) { - return this->cpu->readFloatRegBits(_srcRegIdx[idx]); + return this->cpu->readFloatRegBits(this->_srcRegIdx[idx]); } /** @todo: Make results into arrays so they can handle multiple dest @@ -187,79 +167,37 @@ class MipsDynInst : public BaseDynInst<Impl> */ void setIntRegOperand(const StaticInst *si, int idx, uint64_t val) { - this->cpu->setIntReg(_destRegIdx[idx], val); + this->cpu->setIntReg(this->_destRegIdx[idx], val); BaseDynInst<Impl>::setIntRegOperand(si, idx, val); } void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val, int width) { - this->cpu->setFloatReg(_destRegIdx[idx], val, width); + this->cpu->setFloatReg(this->_destRegIdx[idx], val, width); BaseDynInst<Impl>::setFloatRegOperand(si, idx, val, width); } void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val) { - this->cpu->setFloatReg(_destRegIdx[idx], val); + this->cpu->setFloatReg(this->_destRegIdx[idx], val); BaseDynInst<Impl>::setFloatRegOperand(si, idx, val); } void setFloatRegOperandBits(const StaticInst *si, int idx, FloatRegBits val, int width) { - this->cpu->setFloatRegBits(_destRegIdx[idx], val, width); + this->cpu->setFloatRegBits(this->_destRegIdx[idx], val, width); BaseDynInst<Impl>::setFloatRegOperandBits(si, idx, val); } void setFloatRegOperandBits(const StaticInst *si, int idx, FloatRegBits val) { - this->cpu->setFloatRegBits(_destRegIdx[idx], val); + this->cpu->setFloatRegBits(this->_destRegIdx[idx], val); BaseDynInst<Impl>::setFloatRegOperandBits(si, idx, val); } - /** Returns the physical register index of the i'th destination - * register. - */ - PhysRegIndex renamedDestRegIdx(int idx) const - { - return _destRegIdx[idx]; - } - - /** Returns the physical register index of the i'th source register. */ - PhysRegIndex renamedSrcRegIdx(int idx) const - { - return _srcRegIdx[idx]; - } - - /** Returns the physical register index of the previous physical register - * that remapped to the same logical register index. - */ - PhysRegIndex prevDestRegIdx(int idx) const - { - return _prevDestRegIdx[idx]; - } - - /** Renames a destination register to a physical register. Also records - * the previous physical register that the logical register mapped to. - */ - void renameDestReg(int idx, - PhysRegIndex renamed_dest, - PhysRegIndex previous_rename) - { - _destRegIdx[idx] = renamed_dest; - _prevDestRegIdx[idx] = previous_rename; - } - - /** Renames a source logical register to the physical register which - * has/will produce that logical register's result. - * @todo: add in whether or not the source register is ready. - */ - void renameSrcReg(int idx, PhysRegIndex renamed_src) - { - _srcRegIdx[idx] = renamed_src; - } - public: /** Calculates EA part of a memory instruction. Currently unused, * though it may be useful in the future if we want to split diff --git a/src/cpu/o3/mips/dyn_inst_impl.hh b/src/cpu/o3/mips/dyn_inst_impl.hh index 5bc01b9b3..fa8cf6cb4 100755 --- a/src/cpu/o3/mips/dyn_inst_impl.hh +++ b/src/cpu/o3/mips/dyn_inst_impl.hh @@ -53,11 +53,11 @@ MipsDynInst<Impl>::initVars() // as the normal register entries. It will allow the IQ to work // without any modifications. for (int i = 0; i < this->staticInst->numDestRegs(); i++) { - _destRegIdx[i] = this->staticInst->destRegIdx(i); + this->_destRegIdx[i] = this->staticInst->destRegIdx(i); } for (int i = 0; i < this->staticInst->numSrcRegs(); i++) { - _srcRegIdx[i] = this->staticInst->srcRegIdx(i); + this->_srcRegIdx[i] = this->staticInst->srcRegIdx(i); this->_readySrcRegIdx[i] = 0; } } diff --git a/src/cpu/o3/rename.hh b/src/cpu/o3/rename.hh index 177b9cb87..1ede6f355 100644 --- a/src/cpu/o3/rename.hh +++ b/src/cpu/o3/rename.hh @@ -411,6 +411,10 @@ class DefaultRename /** Whether or not rename needs to block this cycle. */ bool blockThisCycle; + /** Whether or not rename needs to resume a serialize instruction + * after squashing. */ + bool resumeSerialize; + /** The number of threads active in rename. */ unsigned numThreads; diff --git a/src/cpu/o3/rename_impl.hh b/src/cpu/o3/rename_impl.hh index 248d7deb6..0c211b183 100644 --- a/src/cpu/o3/rename_impl.hh +++ b/src/cpu/o3/rename_impl.hh @@ -31,6 +31,8 @@ #include <list> +#include "arch/isa_traits.hh" +#include "arch/regfile.hh" #include "config/full_system.hh" #include "cpu/o3/rename.hh" @@ -41,6 +43,7 @@ DefaultRename<Impl>::DefaultRename(Params *params) commitToRenameDelay(params->commitToRenameDelay), renameWidth(params->renameWidth), commitWidth(params->commitWidth), + resumeSerialize(false), numThreads(params->numberOfThreads), maxPhysicalRegs(params->numPhysIntRegs + params->numPhysFloatRegs) { @@ -332,12 +335,22 @@ DefaultRename<Impl>::squash(const InstSeqNum &squash_seq_num, unsigned tid) // If it still needs to block, the blocking should happen the next // cycle and there should be space to hold everything due to the squash. if (renameStatus[tid] == Blocked || - renameStatus[tid] == Unblocking || - renameStatus[tid] == SerializeStall) { - + renameStatus[tid] == Unblocking) { toDecode->renameUnblock[tid] = 1; + resumeSerialize = false; serializeInst[tid] = NULL; + } else if (renameStatus[tid] == SerializeStall) { + if (serializeInst[tid]->seqNum <= squash_seq_num) { + DPRINTF(Rename, "Rename will resume serializing after squash\n"); + resumeSerialize = true; + assert(serializeInst[tid]); + } else { + resumeSerialize = false; + toDecode->renameUnblock[tid] = 1; + + serializeInst[tid] = NULL; + } } // Set the status to Squashing. @@ -475,6 +488,14 @@ DefaultRename<Impl>::rename(bool &status_change, unsigned tid) ++renameSquashCycles; } else if (renameStatus[tid] == SerializeStall) { ++renameSerializeStallCycles; + // If we are currently in SerializeStall and resumeSerialize + // was set, then that means that we are resuming serializing + // this cycle. Tell the previous stages to block. + if (resumeSerialize) { + resumeSerialize = false; + block(tid); + toDecode->renameUnblock[tid] = false; + } } if (renameStatus[tid] == Running || @@ -960,13 +981,19 @@ DefaultRename<Impl>::renameSrcRegs(DynInstPtr &inst,unsigned tid) // Will need to mark dependencies though. for (int src_idx = 0; src_idx < num_src_regs; src_idx++) { RegIndex src_reg = inst->srcRegIdx(src_idx); + RegIndex flat_src_reg = src_reg; + if (src_reg < TheISA::FP_Base_DepTag) { + flat_src_reg = TheISA::flattenIntIndex(inst->tcBase(), src_reg); + DPRINTF(Rename, "Flattening index %d to %d.\n", (int)src_reg, (int)flat_src_reg); + } + inst->flattenSrcReg(src_idx, flat_src_reg); // Look up the source registers to get the phys. register they've // been renamed to, and set the sources to those registers. - PhysRegIndex renamed_reg = renameMap[tid]->lookup(src_reg); + PhysRegIndex renamed_reg = renameMap[tid]->lookup(flat_src_reg); DPRINTF(Rename, "[tid:%u]: Looking up arch reg %i, got " - "physical reg %i.\n", tid, (int)src_reg, + "physical reg %i.\n", tid, (int)flat_src_reg, (int)renamed_reg); inst->renameSrcReg(src_idx, renamed_reg); @@ -993,20 +1020,27 @@ DefaultRename<Impl>::renameDestRegs(DynInstPtr &inst,unsigned tid) // Rename the destination registers. for (int dest_idx = 0; dest_idx < num_dest_regs; dest_idx++) { RegIndex dest_reg = inst->destRegIdx(dest_idx); + RegIndex flat_dest_reg = dest_reg; + if (dest_reg < TheISA::FP_Base_DepTag) { + flat_dest_reg = TheISA::flattenIntIndex(inst->tcBase(), dest_reg); + DPRINTF(Rename, "Flattening index %d to %d.\n", (int)dest_reg, (int)flat_dest_reg); + } + + inst->flattenDestReg(dest_idx, flat_dest_reg); // Get the physical register that the destination will be // renamed to. - rename_result = renameMap[tid]->rename(dest_reg); + rename_result = renameMap[tid]->rename(flat_dest_reg); //Mark Scoreboard entry as not ready scoreboard->unsetReg(rename_result.first); DPRINTF(Rename, "[tid:%u]: Renaming arch reg %i to physical " - "reg %i.\n", tid, (int)dest_reg, + "reg %i.\n", tid, (int)flat_dest_reg, (int)rename_result.first); // Record the rename information so that a history can be kept. - RenameHistory hb_entry(inst->seqNum, dest_reg, + RenameHistory hb_entry(inst->seqNum, flat_dest_reg, rename_result.first, rename_result.second); @@ -1230,12 +1264,19 @@ DefaultRename<Impl>::checkSignalsAndUpdate(unsigned tid) if (renameStatus[tid] == Squashing) { // Switch status to running if rename isn't being told to block or // squash this cycle. - DPRINTF(Rename, "[tid:%u]: Done squashing, switching to running.\n", - tid); + if (!resumeSerialize) { + DPRINTF(Rename, "[tid:%u]: Done squashing, switching to running.\n", + tid); - renameStatus[tid] = Running; + renameStatus[tid] = Running; + return false; + } else { + DPRINTF(Rename, "[tid:%u]: Done squashing, switching to serialize.\n", + tid); - return false; + renameStatus[tid] = SerializeStall; + return true; + } } if (renameStatus[tid] == SerializeStall) { diff --git a/src/cpu/o3/sparc/cpu.cc b/src/cpu/o3/sparc/cpu.cc new file mode 100644 index 000000000..1546a2b88 --- /dev/null +++ b/src/cpu/o3/sparc/cpu.cc @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#include "cpu/o3/sparc/impl.hh" +#include "cpu/o3/sparc/cpu_impl.hh" +#include "cpu/o3/sparc/dyn_inst.hh" + +// Force instantiation of SparcO3CPU for all the implementations that are +// needed. Consider merging this and sparc_dyn_inst.cc, and maybe all +// classes that depend on a certain impl, into one file (sparc_impl.cc?). +template class SparcO3CPU<SparcSimpleImpl>; diff --git a/src/cpu/o3/sparc/cpu.hh b/src/cpu/o3/sparc/cpu.hh new file mode 100644 index 000000000..08ebd2710 --- /dev/null +++ b/src/cpu/o3/sparc/cpu.hh @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2004-2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Kevin Lim + */ + +#ifndef __CPU_O3_SPARC_CPU_HH__ +#define __CPU_O3_SPARC_CPU_HH__ + +#include "arch/sparc/regfile.hh" +#include "arch/sparc/types.hh" +#include "cpu/thread_context.hh" +#include "cpu/o3/cpu.hh" +#include "sim/byteswap.hh" + +class EndQuiesceEvent; +namespace Kernel { + class Statistics; +}; + +class TranslatingPort; + +/** + * SparcO3CPU class. Derives from the FullO3CPU class, and + * implements all ISA and implementation specific functions of the + * CPU. This is the CPU class that is used for the SimObjects, and is + * what is given to the DynInsts. Most of its state exists in the + * FullO3CPU; the state is has is mainly for ISA specific + * functionality. + */ +template <class Impl> +class SparcO3CPU : public FullO3CPU<Impl> +{ + public: + typedef O3ThreadState<Impl> ImplState; + typedef O3ThreadState<Impl> Thread; + typedef typename Impl::Params Params; + + /** Constructs an AlphaO3CPU with the given parameters. */ + SparcO3CPU(Params *params); + + /** Registers statistics. */ + void regStats(); + +#if FULL_SYSTEM + /** Translates instruction requestion. */ + Fault translateInstReq(RequestPtr &req, Thread *thread) + { + return this->itb->translate(req, thread->getTC()); + } + + /** Translates data read request. */ + Fault translateDataReadReq(RequestPtr &req, Thread *thread) + { + return this->dtb->translate(req, thread->getTC(), false); + } + + /** Translates data write request. */ + Fault translateDataWriteReq(RequestPtr &req, Thread *thread) + { + return this->dtb->translate(req, thread->getTC(), true); + } + +#else + /** Translates instruction requestion in syscall emulation mode. */ + Fault translateInstReq(RequestPtr &req, Thread *thread) + { + return thread->getProcessPtr()->pTable->translate(req); + } + + /** Translates data read request in syscall emulation mode. */ + Fault translateDataReadReq(RequestPtr &req, Thread *thread) + { + return thread->getProcessPtr()->pTable->translate(req); + } + + /** Translates data write request in syscall emulation mode. */ + Fault translateDataWriteReq(RequestPtr &req, Thread *thread) + { + return thread->getProcessPtr()->pTable->translate(req); + } + +#endif + /** Reads a miscellaneous register. */ + TheISA::MiscReg readMiscReg(int misc_reg, unsigned tid); + + /** Reads a misc. register, including any side effects the read + * might have as defined by the architecture. + */ + TheISA::MiscReg readMiscRegWithEffect(int misc_reg, unsigned tid); + + /** Sets a miscellaneous register. */ + void setMiscReg(int misc_reg, const TheISA::MiscReg &val, unsigned tid); + + /** Sets a misc. register, including any side effects the write + * might have as defined by the architecture. + */ + void setMiscRegWithEffect(int misc_reg, const TheISA::MiscReg &val, + unsigned tid); + + /** Initiates a squash of all in-flight instructions for a given + * thread. The source of the squash is an external update of + * state through the TC. + */ + void squashFromTC(unsigned tid); + +#if FULL_SYSTEM + /** Posts an interrupt. */ + void post_interrupt(int int_num, int index); + /** HW return from error interrupt. */ + Fault hwrei(unsigned tid); + + bool simPalCheck(int palFunc, unsigned tid); + + /** Returns the Fault for any valid interrupt. */ + Fault getInterrupts(); + + /** Processes any an interrupt fault. */ + void processInterrupts(Fault interrupt); + + /** Halts the CPU. */ + void halt() { panic("Halt not implemented!\n"); } +#endif + + /** Traps to handle given fault. */ + void trap(Fault fault, unsigned tid); + +#if !FULL_SYSTEM + /** Executes a syscall. + * @todo: Determine if this needs to be virtual. + */ + void syscall(int64_t callnum, int tid); + /** Gets a syscall argument. */ + TheISA::IntReg getSyscallArg(int i, int tid); + + /** Used to shift args for indirect syscall. */ + void setSyscallArg(int i, TheISA::IntReg val, int tid); + + /** Sets the return value of a syscall. */ + void setSyscallReturn(SyscallReturn return_value, int tid); +#endif + + /** CPU read function, forwards read to LSQ. */ + template <class T> + Fault read(RequestPtr &req, T &data, int load_idx) + { + return this->iew.ldstQueue.read(req, data, load_idx); + } + + /** CPU write function, forwards write to LSQ. */ + template <class T> + Fault write(RequestPtr &req, T &data, int store_idx) + { + return this->iew.ldstQueue.write(req, data, store_idx); + } + + Addr lockAddr; + + /** Temporary fix for the lock flag, works in the UP case. */ + bool lockFlag; +}; + +#endif // __CPU_O3_SPARC_CPU_HH__ diff --git a/src/cpu/o3/sparc/cpu_builder.cc b/src/cpu/o3/sparc/cpu_builder.cc new file mode 100644 index 000000000..3cac89bad --- /dev/null +++ b/src/cpu/o3/sparc/cpu_builder.cc @@ -0,0 +1,433 @@ +/* + * Copyright (c) 2004-2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#include <string> + +#include "cpu/base.hh" +#include "cpu/o3/sparc/cpu.hh" +#include "cpu/o3/sparc/impl.hh" +#include "cpu/o3/sparc/params.hh" +#include "cpu/o3/fu_pool.hh" +#include "sim/builder.hh" + +class DerivO3CPU : public SparcO3CPU<SparcSimpleImpl> +{ + public: + DerivO3CPU(SparcSimpleParams *p) + : SparcO3CPU<SparcSimpleImpl>(p) + { } +}; + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(DerivO3CPU) + + Param<int> clock; + Param<int> phase; + Param<int> numThreads; + Param<int> activity; + +#if FULL_SYSTEM + SimObjectParam<System *> system; + Param<int> cpu_id; + SimObjectParam<SparcISA::ITB *> itb; + SimObjectParam<SparcISA::DTB *> dtb; + Param<Tick> profile; + + Param<bool> do_quiesce; + Param<bool> do_checkpoint_insts; + Param<bool> do_statistics_insts; +#else + SimObjectVectorParam<Process *> workload; +#endif // FULL_SYSTEM + + SimObjectParam<BaseCPU *> checker; + + Param<Counter> max_insts_any_thread; + Param<Counter> max_insts_all_threads; + Param<Counter> max_loads_any_thread; + Param<Counter> max_loads_all_threads; + Param<Tick> progress_interval; + + Param<unsigned> cachePorts; + + Param<unsigned> decodeToFetchDelay; + Param<unsigned> renameToFetchDelay; + Param<unsigned> iewToFetchDelay; + Param<unsigned> commitToFetchDelay; + Param<unsigned> fetchWidth; + + Param<unsigned> renameToDecodeDelay; + Param<unsigned> iewToDecodeDelay; + Param<unsigned> commitToDecodeDelay; + Param<unsigned> fetchToDecodeDelay; + Param<unsigned> decodeWidth; + + Param<unsigned> iewToRenameDelay; + Param<unsigned> commitToRenameDelay; + Param<unsigned> decodeToRenameDelay; + Param<unsigned> renameWidth; + + Param<unsigned> commitToIEWDelay; + Param<unsigned> renameToIEWDelay; + Param<unsigned> issueToExecuteDelay; + Param<unsigned> dispatchWidth; + Param<unsigned> issueWidth; + Param<unsigned> wbWidth; + Param<unsigned> wbDepth; + SimObjectParam<FUPool *> fuPool; + + Param<unsigned> iewToCommitDelay; + Param<unsigned> renameToROBDelay; + Param<unsigned> commitWidth; + Param<unsigned> squashWidth; + Param<Tick> trapLatency; + + Param<unsigned> backComSize; + Param<unsigned> forwardComSize; + + Param<std::string> predType; + Param<unsigned> localPredictorSize; + Param<unsigned> localCtrBits; + Param<unsigned> localHistoryTableSize; + Param<unsigned> localHistoryBits; + Param<unsigned> globalPredictorSize; + Param<unsigned> globalCtrBits; + Param<unsigned> globalHistoryBits; + Param<unsigned> choicePredictorSize; + Param<unsigned> choiceCtrBits; + + Param<unsigned> BTBEntries; + Param<unsigned> BTBTagSize; + + Param<unsigned> RASSize; + + Param<unsigned> LQEntries; + Param<unsigned> SQEntries; + Param<unsigned> LFSTSize; + Param<unsigned> SSITSize; + + Param<unsigned> numPhysIntRegs; + Param<unsigned> numPhysFloatRegs; + Param<unsigned> numIQEntries; + Param<unsigned> numROBEntries; + + Param<unsigned> smtNumFetchingThreads; + Param<std::string> smtFetchPolicy; + Param<std::string> smtLSQPolicy; + Param<unsigned> smtLSQThreshold; + Param<std::string> smtIQPolicy; + Param<unsigned> smtIQThreshold; + Param<std::string> smtROBPolicy; + Param<unsigned> smtROBThreshold; + Param<std::string> smtCommitPolicy; + + Param<unsigned> instShiftAmt; + + Param<bool> defer_registration; + + Param<bool> function_trace; + Param<Tick> function_trace_start; + +END_DECLARE_SIM_OBJECT_PARAMS(DerivO3CPU) + +BEGIN_INIT_SIM_OBJECT_PARAMS(DerivO3CPU) + + INIT_PARAM(clock, "clock speed"), + INIT_PARAM_DFLT(phase, "clock phase", 0), + INIT_PARAM(numThreads, "number of HW thread contexts"), + INIT_PARAM_DFLT(activity, "Initial activity count", 0), + +#if FULL_SYSTEM + INIT_PARAM(system, "System object"), + INIT_PARAM(cpu_id, "processor ID"), + INIT_PARAM(itb, "Instruction translation buffer"), + INIT_PARAM(dtb, "Data translation buffer"), + INIT_PARAM(profile, ""), + + INIT_PARAM(do_quiesce, ""), + INIT_PARAM(do_checkpoint_insts, ""), + INIT_PARAM(do_statistics_insts, ""), +#else + INIT_PARAM(workload, "Processes to run"), +#endif // FULL_SYSTEM + + INIT_PARAM_DFLT(checker, "Checker CPU", NULL), + + INIT_PARAM_DFLT(max_insts_any_thread, + "Terminate when any thread reaches this inst count", + 0), + INIT_PARAM_DFLT(max_insts_all_threads, + "Terminate when all threads have reached" + "this inst count", + 0), + INIT_PARAM_DFLT(max_loads_any_thread, + "Terminate when any thread reaches this load count", + 0), + INIT_PARAM_DFLT(max_loads_all_threads, + "Terminate when all threads have reached this load" + "count", + 0), + INIT_PARAM_DFLT(progress_interval, "Progress interval", 0), + + INIT_PARAM_DFLT(cachePorts, "Cache Ports", 200), + + INIT_PARAM(decodeToFetchDelay, "Decode to fetch delay"), + INIT_PARAM(renameToFetchDelay, "Rename to fetch delay"), + INIT_PARAM(iewToFetchDelay, "Issue/Execute/Writeback to fetch" + "delay"), + INIT_PARAM(commitToFetchDelay, "Commit to fetch delay"), + INIT_PARAM(fetchWidth, "Fetch width"), + INIT_PARAM(renameToDecodeDelay, "Rename to decode delay"), + INIT_PARAM(iewToDecodeDelay, "Issue/Execute/Writeback to decode" + "delay"), + INIT_PARAM(commitToDecodeDelay, "Commit to decode delay"), + INIT_PARAM(fetchToDecodeDelay, "Fetch to decode delay"), + INIT_PARAM(decodeWidth, "Decode width"), + + INIT_PARAM(iewToRenameDelay, "Issue/Execute/Writeback to rename" + "delay"), + INIT_PARAM(commitToRenameDelay, "Commit to rename delay"), + INIT_PARAM(decodeToRenameDelay, "Decode to rename delay"), + INIT_PARAM(renameWidth, "Rename width"), + + INIT_PARAM(commitToIEWDelay, "Commit to " + "Issue/Execute/Writeback delay"), + INIT_PARAM(renameToIEWDelay, "Rename to " + "Issue/Execute/Writeback delay"), + INIT_PARAM(issueToExecuteDelay, "Issue to execute delay (internal" + "to the IEW stage)"), + INIT_PARAM(dispatchWidth, "Dispatch width"), + INIT_PARAM(issueWidth, "Issue width"), + INIT_PARAM(wbWidth, "Writeback width"), + INIT_PARAM(wbDepth, "Writeback depth (number of cycles it can buffer)"), + INIT_PARAM_DFLT(fuPool, "Functional unit pool", NULL), + + INIT_PARAM(iewToCommitDelay, "Issue/Execute/Writeback to commit " + "delay"), + INIT_PARAM(renameToROBDelay, "Rename to reorder buffer delay"), + INIT_PARAM(commitWidth, "Commit width"), + INIT_PARAM(squashWidth, "Squash width"), + INIT_PARAM_DFLT(trapLatency, "Number of cycles before the trap is handled", 6), + + INIT_PARAM(backComSize, "Time buffer size for backwards communication"), + INIT_PARAM(forwardComSize, "Time buffer size for forward communication"), + + INIT_PARAM(predType, "Type of branch predictor ('local', 'tournament')"), + INIT_PARAM(localPredictorSize, "Size of local predictor"), + INIT_PARAM(localCtrBits, "Bits per counter"), + INIT_PARAM(localHistoryTableSize, "Size of local history table"), + INIT_PARAM(localHistoryBits, "Bits for the local history"), + INIT_PARAM(globalPredictorSize, "Size of global predictor"), + INIT_PARAM(globalCtrBits, "Bits per counter"), + INIT_PARAM(globalHistoryBits, "Bits of history"), + INIT_PARAM(choicePredictorSize, "Size of choice predictor"), + INIT_PARAM(choiceCtrBits, "Bits of choice counters"), + + INIT_PARAM(BTBEntries, "Number of BTB entries"), + INIT_PARAM(BTBTagSize, "Size of the BTB tags, in bits"), + + INIT_PARAM(RASSize, "RAS size"), + + INIT_PARAM(LQEntries, "Number of load queue entries"), + INIT_PARAM(SQEntries, "Number of store queue entries"), + INIT_PARAM(LFSTSize, "Last fetched store table size"), + INIT_PARAM(SSITSize, "Store set ID table size"), + + INIT_PARAM(numPhysIntRegs, "Number of physical integer registers"), + INIT_PARAM(numPhysFloatRegs, "Number of physical floating point " + "registers"), + INIT_PARAM(numIQEntries, "Number of instruction queue entries"), + INIT_PARAM(numROBEntries, "Number of reorder buffer entries"), + + INIT_PARAM_DFLT(smtNumFetchingThreads, "SMT Number of Fetching Threads", 1), + INIT_PARAM_DFLT(smtFetchPolicy, "SMT Fetch Policy", "SingleThread"), + INIT_PARAM_DFLT(smtLSQPolicy, "SMT LSQ Sharing Policy", "Partitioned"), + INIT_PARAM_DFLT(smtLSQThreshold,"SMT LSQ Threshold", 100), + INIT_PARAM_DFLT(smtIQPolicy, "SMT IQ Policy", "Partitioned"), + INIT_PARAM_DFLT(smtIQThreshold, "SMT IQ Threshold", 100), + INIT_PARAM_DFLT(smtROBPolicy, "SMT ROB Sharing Policy", "Partitioned"), + INIT_PARAM_DFLT(smtROBThreshold,"SMT ROB Threshold", 100), + INIT_PARAM_DFLT(smtCommitPolicy,"SMT Commit Fetch Policy", "RoundRobin"), + + INIT_PARAM(instShiftAmt, "Number of bits to shift instructions by"), + INIT_PARAM(defer_registration, "defer system registration (for sampling)"), + + INIT_PARAM(function_trace, "Enable function trace"), + INIT_PARAM(function_trace_start, "Cycle to start function trace") + +END_INIT_SIM_OBJECT_PARAMS(DerivO3CPU) + +CREATE_SIM_OBJECT(DerivO3CPU) +{ + DerivO3CPU *cpu; + +#if FULL_SYSTEM + // Full-system only supports a single thread for the moment. + int actual_num_threads = 1; +#else + // In non-full-system mode, we infer the number of threads from + // the workload if it's not explicitly specified. + int actual_num_threads = + (numThreads.isValid() && numThreads >= workload.size()) ? + numThreads : workload.size(); + + if (workload.size() == 0) { + fatal("Must specify at least one workload!"); + } +#endif + + SparcSimpleParams *params = new SparcSimpleParams; + + params->clock = clock; + + params->name = getInstanceName(); + params->numberOfThreads = actual_num_threads; + params->activity = activity; + +#if FULL_SYSTEM + params->system = system; + params->cpu_id = cpu_id; + params->itb = itb; + params->dtb = dtb; + params->profile = profile; + + params->do_quiesce = do_quiesce; + params->do_checkpoint_insts = do_checkpoint_insts; + params->do_statistics_insts = do_statistics_insts; +#else + params->workload = workload; +#endif // FULL_SYSTEM + + params->checker = checker; + + params->max_insts_any_thread = max_insts_any_thread; + params->max_insts_all_threads = max_insts_all_threads; + params->max_loads_any_thread = max_loads_any_thread; + params->max_loads_all_threads = max_loads_all_threads; + params->progress_interval = progress_interval; + + // + // Caches + // + params->cachePorts = cachePorts; + + params->decodeToFetchDelay = decodeToFetchDelay; + params->renameToFetchDelay = renameToFetchDelay; + params->iewToFetchDelay = iewToFetchDelay; + params->commitToFetchDelay = commitToFetchDelay; + params->fetchWidth = fetchWidth; + + params->renameToDecodeDelay = renameToDecodeDelay; + params->iewToDecodeDelay = iewToDecodeDelay; + params->commitToDecodeDelay = commitToDecodeDelay; + params->fetchToDecodeDelay = fetchToDecodeDelay; + params->decodeWidth = decodeWidth; + + params->iewToRenameDelay = iewToRenameDelay; + params->commitToRenameDelay = commitToRenameDelay; + params->decodeToRenameDelay = decodeToRenameDelay; + params->renameWidth = renameWidth; + + params->commitToIEWDelay = commitToIEWDelay; + params->renameToIEWDelay = renameToIEWDelay; + params->issueToExecuteDelay = issueToExecuteDelay; + params->dispatchWidth = dispatchWidth; + params->issueWidth = issueWidth; + params->wbWidth = wbWidth; + params->wbDepth = wbDepth; + params->fuPool = fuPool; + + params->iewToCommitDelay = iewToCommitDelay; + params->renameToROBDelay = renameToROBDelay; + params->commitWidth = commitWidth; + params->squashWidth = squashWidth; + params->trapLatency = trapLatency; + + params->backComSize = backComSize; + params->forwardComSize = forwardComSize; + + params->predType = predType; + params->localPredictorSize = localPredictorSize; + params->localCtrBits = localCtrBits; + params->localHistoryTableSize = localHistoryTableSize; + params->localHistoryBits = localHistoryBits; + params->globalPredictorSize = globalPredictorSize; + params->globalCtrBits = globalCtrBits; + params->globalHistoryBits = globalHistoryBits; + params->choicePredictorSize = choicePredictorSize; + params->choiceCtrBits = choiceCtrBits; + + params->BTBEntries = BTBEntries; + params->BTBTagSize = BTBTagSize; + + params->RASSize = RASSize; + + params->LQEntries = LQEntries; + params->SQEntries = SQEntries; + + params->SSITSize = SSITSize; + params->LFSTSize = LFSTSize; + + params->numPhysIntRegs = numPhysIntRegs; + params->numPhysFloatRegs = numPhysFloatRegs; + params->numIQEntries = numIQEntries; + params->numROBEntries = numROBEntries; + + params->smtNumFetchingThreads = smtNumFetchingThreads; + + // Default smtFetchPolicy to "RoundRobin", if necessary. + std::string round_robin_policy = "RoundRobin"; + std::string single_thread = "SingleThread"; + + if (actual_num_threads > 1 && single_thread.compare(smtFetchPolicy) == 0) + params->smtFetchPolicy = round_robin_policy; + else + params->smtFetchPolicy = smtFetchPolicy; + + params->smtIQPolicy = smtIQPolicy; + params->smtLSQPolicy = smtLSQPolicy; + params->smtLSQThreshold = smtLSQThreshold; + params->smtROBPolicy = smtROBPolicy; + params->smtROBThreshold = smtROBThreshold; + params->smtCommitPolicy = smtCommitPolicy; + + params->instShiftAmt = 2; + + params->deferRegistration = defer_registration; + + params->functionTrace = function_trace; + params->functionTraceStart = function_trace_start; + + cpu = new DerivO3CPU(params); + + return cpu; +} + +REGISTER_SIM_OBJECT("DerivO3CPU", DerivO3CPU) + diff --git a/src/cpu/o3/sparc/cpu_impl.hh b/src/cpu/o3/sparc/cpu_impl.hh new file mode 100644 index 000000000..4a194cbda --- /dev/null +++ b/src/cpu/o3/sparc/cpu_impl.hh @@ -0,0 +1,304 @@ +/* + * Copyright (c) 2004-2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#include "config/use_checker.hh" + +#include "arch/sparc/faults.hh" +#include "arch/sparc/isa_traits.hh" +#include "arch/sparc/miscregfile.hh" +#include "base/cprintf.hh" +#include "base/statistics.hh" +#include "base/timebuf.hh" +#include "cpu/checker/thread_context.hh" +#include "sim/sim_events.hh" +#include "sim/stats.hh" + +#include "cpu/o3/sparc/cpu.hh" +#include "cpu/o3/sparc/params.hh" +#include "cpu/o3/sparc/thread_context.hh" +#include "cpu/o3/comm.hh" +#include "cpu/o3/thread_state.hh" + +#if FULL_SYSTEM +#include "arch/sparc/isa_traits.hh" +#include "arch/sparc/kernel_stats.hh" +#include "cpu/quiesce_event.hh" +#include "sim/sim_exit.hh" +#include "sim/system.hh" +#endif + +template <class Impl> +SparcO3CPU<Impl>::SparcO3CPU(Params *params) : FullO3CPU<Impl>(params) +{ + DPRINTF(O3CPU, "Creating SparcO3CPU object.\n"); + + // Setup any thread state. + this->thread.resize(this->numThreads); + + for (int i = 0; i < this->numThreads; ++i) { +#if FULL_SYSTEM + // SMT is not supported in FS mode yet. + assert(this->numThreads == 1); + this->thread[i] = new Thread(this, 0); + this->thread[i]->setStatus(ThreadContext::Suspended); +#else + if (i < params->workload.size()) { + DPRINTF(O3CPU, "Workload[%i] process is %#x", + i, this->thread[i]); + this->thread[i] = new Thread(this, i, params->workload[i], i); + + this->thread[i]->setStatus(ThreadContext::Suspended); + + //usedTids[i] = true; + //threadMap[i] = i; + } else { + //Allocate Empty thread so M5 can use later + //when scheduling threads to CPU + Process* dummy_proc = NULL; + + this->thread[i] = new Thread(this, i, dummy_proc, i); + //usedTids[i] = false; + } +#endif // !FULL_SYSTEM + + ThreadContext *tc; + + // Setup the TC that will serve as the interface to the threads/CPU. + SparcTC<Impl> *sparc_tc = new SparcTC<Impl>; + + tc = sparc_tc; + + // If we're using a checker, then the TC should be the + // CheckerThreadContext. +#if USE_CHECKER + if (params->checker) { + tc = new CheckerThreadContext<SparcTC<Impl> >( + sparc_tc, this->checker); + } +#endif + + sparc_tc->cpu = this; + sparc_tc->thread = this->thread[i]; + +#if FULL_SYSTEM + // Setup quiesce event. + this->thread[i]->quiesceEvent = new EndQuiesceEvent(tc); +#endif + // Give the thread the TC. + this->thread[i]->tc = tc; + + // Add the TC to the CPU's list of TC's. + this->threadContexts.push_back(tc); + } + + for (int i=0; i < this->numThreads; i++) { + this->thread[i]->setFuncExeInst(0); + } + + // Sets CPU pointers. These must be set at this level because the CPU + // pointers are defined to be the highest level of CPU class. + this->fetch.setCPU(this); + this->decode.setCPU(this); + this->rename.setCPU(this); + this->iew.setCPU(this); + this->commit.setCPU(this); + + this->rob.setCPU(this); + this->regFile.setCPU(this); + + lockAddr = 0; + lockFlag = false; +} + +template <class Impl> +void +SparcO3CPU<Impl>::regStats() +{ + // Register stats for everything that has stats. + this->fullCPURegStats(); + this->fetch.regStats(); + this->decode.regStats(); + this->rename.regStats(); + this->iew.regStats(); + this->commit.regStats(); +} + + +template <class Impl> +TheISA::MiscReg +SparcO3CPU<Impl>::readMiscReg(int misc_reg, unsigned tid) +{ + return this->regFile.readMiscReg(misc_reg, tid); +} + +template <class Impl> +TheISA::MiscReg +SparcO3CPU<Impl>::readMiscRegWithEffect(int misc_reg, unsigned tid) +{ + return this->regFile.readMiscRegWithEffect(misc_reg, tid); +} + +template <class Impl> +void +SparcO3CPU<Impl>::setMiscReg(int misc_reg, + const SparcISA::MiscReg &val, unsigned tid) +{ + this->regFile.setMiscReg(misc_reg, val, tid); +} + +template <class Impl> +void +SparcO3CPU<Impl>::setMiscRegWithEffect(int misc_reg, + const SparcISA::MiscReg &val, unsigned tid) +{ + this->regFile.setMiscRegWithEffect(misc_reg, val, tid); +} + +template <class Impl> +void +SparcO3CPU<Impl>::squashFromTC(unsigned tid) +{ + this->thread[tid]->inSyscall = true; + this->commit.generateTCEvent(tid); +} + +#if FULL_SYSTEM + +template <class Impl> +void +SparcO3CPU<Impl>::post_interrupt(int int_num, int index) +{ + BaseCPU::post_interrupt(int_num, index); + + if (this->thread[0]->status() == ThreadContext::Suspended) { + DPRINTF(IPI,"Suspended Processor awoke\n"); + this->threadContexts[0]->activate(); + } +} + +template <class Impl> +Fault +SparcO3CPU<Impl>::hwrei(unsigned tid) +{ + panic("This doesn't make sense for SPARC\n"); + return NoFault; +} + +template <class Impl> +bool +SparcO3CPU<Impl>::simPalCheck(int palFunc, unsigned tid) +{ + panic("This doesn't make sense for SPARC\n"); + return true; +} + +template <class Impl> +Fault +SparcO3CPU<Impl>::getInterrupts() +{ + // Check if there are any outstanding interrupts + return this->interrupts.getInterrupt(this->threadContexts[0]); +} + +template <class Impl> +void +SparcO3CPU<Impl>::processInterrupts(Fault interrupt) +{ + // Check for interrupts here. For now can copy the code that + // exists within isa_fullsys_traits.hh. Also assume that thread 0 + // is the one that handles the interrupts. + // @todo: Possibly consolidate the interrupt checking code. + // @todo: Allow other threads to handle interrupts. + + assert(interrupt != NoFault); + this->interrupts.updateIntrInfo(this->threadContexts[0]); + + DPRINTF(O3CPU, "Interrupt %s being handled\n", interrupt->name()); + this->checkInterrupts = false; + this->trap(interrupt, 0); +} + +#endif // FULL_SYSTEM + +template <class Impl> +void +SparcO3CPU<Impl>::trap(Fault fault, unsigned tid) +{ + // Pass the thread's TC into the invoke method. + fault->invoke(this->threadContexts[tid]); +} + +#if !FULL_SYSTEM + +template <class Impl> +void +SparcO3CPU<Impl>::syscall(int64_t callnum, int tid) +{ + DPRINTF(O3CPU, "[tid:%i] Executing syscall().\n\n", tid); + + DPRINTF(Activity,"Activity: syscall() called.\n"); + + // Temporarily increase this by one to account for the syscall + // instruction. + ++(this->thread[tid]->funcExeInst); + + // Execute the actual syscall. + this->thread[tid]->syscall(callnum); + + // Decrease funcExeInst by one as the normal commit will handle + // incrementing it. + --(this->thread[tid]->funcExeInst); +} + +template <class Impl> +TheISA::IntReg +SparcO3CPU<Impl>::getSyscallArg(int i, int tid) +{ + TheISA::IntReg idx = TheISA::flattenIntIndex(this->tcBase(tid), + SparcISA::ArgumentReg0 + i); + return this->readArchIntReg(idx, tid); +} + +template <class Impl> +void +SparcO3CPU<Impl>::setSyscallArg(int i, TheISA::IntReg val, int tid) +{ + TheISA::IntReg idx = TheISA::flattenIntIndex(this->tcBase(tid), + SparcISA::ArgumentReg0 + i); + this->setArchIntReg(idx, val, tid); +} + +template <class Impl> +void +SparcO3CPU<Impl>::setSyscallReturn(SyscallReturn return_value, int tid) +{ + TheISA::setSyscallReturn(return_value, this->tcBase(tid)); +} +#endif diff --git a/src/cpu/o3/sparc/dyn_inst.cc b/src/cpu/o3/sparc/dyn_inst.cc new file mode 100644 index 000000000..984b58f4b --- /dev/null +++ b/src/cpu/o3/sparc/dyn_inst.cc @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#include "cpu/o3/sparc/dyn_inst_impl.hh" +#include "cpu/o3/sparc/impl.hh" + +// Force instantiation of SparcDynInst for all the implementations that +// are needed. +template class SparcDynInst<SparcSimpleImpl>; diff --git a/src/cpu/o3/sparc/dyn_inst.hh b/src/cpu/o3/sparc/dyn_inst.hh new file mode 100644 index 000000000..2d73ca8d1 --- /dev/null +++ b/src/cpu/o3/sparc/dyn_inst.hh @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2004-2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#ifndef __CPU_O3_SPARC_DYN_INST_HH__ +#define __CPU_O3_SPARC_DYN_INST_HH__ + +#include "arch/sparc/isa_traits.hh" +#include "arch/sparc/types.hh" +#include "cpu/base_dyn_inst.hh" +#include "cpu/inst_seq.hh" +#include "cpu/o3/sparc/cpu.hh" +#include "cpu/o3/sparc/impl.hh" + +class Packet; + +/** + * Mostly implementation & ISA specific SparcDynInst. As with most + * other classes in the new CPU model, it is templated on the Impl to + * allow for passing in of all types, such as the CPU type and the ISA + * type. The SparcDynInst serves as the primary interface to the CPU + * for instructions that are executing. + */ +template <class Impl> +class SparcDynInst : public BaseDynInst<Impl> +{ + public: + /** Typedef for the CPU. */ + typedef typename Impl::O3CPU O3CPU; + + public: + /** BaseDynInst constructor given a binary instruction. */ + SparcDynInst(TheISA::ExtMachInst inst, Addr PC, + Addr Pred_PC, InstSeqNum seq_num, O3CPU *cpu); + + /** BaseDynInst constructor given a static inst pointer. */ + SparcDynInst(StaticInstPtr &_staticInst); + + /** Executes the instruction.*/ + Fault execute(); + + /** Initiates the access. Only valid for memory operations. */ + Fault initiateAcc(); + + /** Completes the access. Only valid for memory operations. */ + Fault completeAcc(PacketPtr pkt); + + private: + /** Initializes variables. */ + void initVars(); + + public: + /** Reads a miscellaneous register. */ + TheISA::MiscReg readMiscReg(int misc_reg) + { + return this->cpu->readMiscReg(misc_reg, this->threadNumber); + } + + /** Reads a misc. register, including any side-effects the read + * might have as defined by the architecture. + */ + TheISA::MiscReg readMiscRegWithEffect(int misc_reg) + { + return this->cpu->readMiscRegWithEffect(misc_reg, this->threadNumber); + } + + /** Sets a misc. register. */ + void setMiscReg(int misc_reg, const TheISA::MiscReg &val) + { + this->instResult.integer = val; + return this->cpu->setMiscReg(misc_reg, val, this->threadNumber); + } + + /** Sets a misc. register, including any side-effects the write + * might have as defined by the architecture. + */ + void setMiscRegWithEffect(int misc_reg, const TheISA::MiscReg &val) + { + return this->cpu->setMiscRegWithEffect(misc_reg, val, + this->threadNumber); + } + +#if FULL_SYSTEM + /** Calls hardware return from error interrupt. */ + Fault hwrei(); + /** Traps to handle specified fault. */ + void trap(Fault fault); + bool simPalCheck(int palFunc); +#else + /** Calls a syscall. */ + void syscall(int64_t callnum); +#endif + + public: + + // The register accessor methods provide the index of the + // instruction's operand (e.g., 0 or 1), not the architectural + // register index, to simplify the implementation of register + // renaming. We find the architectural register index by indexing + // into the instruction's own operand index table. Note that a + // raw pointer to the StaticInst is provided instead of a + // ref-counted StaticInstPtr to redice overhead. This is fine as + // long as these methods don't copy the pointer into any long-term + // storage (which is pretty hard to imagine they would have reason + // to do). + + uint64_t readIntReg(const StaticInst *si, int idx) + { + uint64_t val = this->cpu->readIntReg(this->_srcRegIdx[idx]); + DPRINTF(Sparc, "Reading int reg %d (%d, %d) as %x\n", (int)this->_flatSrcRegIdx[idx], (int)this->_srcRegIdx[idx], idx, val); + return this->cpu->readIntReg(this->_srcRegIdx[idx]); + } + + TheISA::FloatReg readFloatReg(const StaticInst *si, int idx, int width) + { + return this->cpu->readFloatReg(this->_srcRegIdx[idx], width); + } + + TheISA::FloatReg readFloatReg(const StaticInst *si, int idx) + { + return this->cpu->readFloatReg(this->_srcRegIdx[idx]); + } + + TheISA::FloatRegBits readFloatRegBits(const StaticInst *si, + int idx, int width) + { + return this->cpu->readFloatRegBits(this->_srcRegIdx[idx], width); + } + + TheISA::FloatRegBits readFloatRegBits(const StaticInst *si, int idx) + { + return this->cpu->readFloatRegBits(this->_srcRegIdx[idx]); + } + + /** @todo: Make results into arrays so they can handle multiple dest + * registers. + */ + void setIntReg(const StaticInst *si, int idx, uint64_t val) + { + DPRINTF(Sparc, "Setting int reg %d (%d, %d) to %x\n", (int)this->_flatDestRegIdx[idx], (int)this->_destRegIdx[idx], idx, val); + this->cpu->setIntReg(this->_destRegIdx[idx], val); + BaseDynInst<Impl>::setIntReg(si, idx, val); + } + + void setFloatReg(const StaticInst *si, int idx, + TheISA::FloatReg val, int width) + { + this->cpu->setFloatReg(this->_destRegIdx[idx], val, width); + BaseDynInst<Impl>::setFloatReg(si, idx, val, width); + } + + void setFloatReg(const StaticInst *si, int idx, TheISA::FloatReg val) + { + this->cpu->setFloatReg(this->_destRegIdx[idx], val); + BaseDynInst<Impl>::setFloatReg(si, idx, val); + } + + void setFloatRegBits(const StaticInst *si, int idx, + TheISA::FloatRegBits val, int width) + { + this->cpu->setFloatRegBits(this->_destRegIdx[idx], val, width); + BaseDynInst<Impl>::setFloatRegBits(si, idx, val); + } + + void setFloatRegBits(const StaticInst *si, + int idx, TheISA::FloatRegBits val) + { + this->cpu->setFloatRegBits(this->_destRegIdx[idx], val); + BaseDynInst<Impl>::setFloatRegBits(si, idx, val); + } + + public: + /** Calculates EA part of a memory instruction. Currently unused, + * though it may be useful in the future if we want to split + * memory operations into EA calculation and memory access parts. + */ + Fault calcEA() + { + return this->staticInst->eaCompInst()->execute(this, this->traceData); + } + + /** Does the memory access part of a memory instruction. Currently unused, + * though it may be useful in the future if we want to split + * memory operations into EA calculation and memory access parts. + */ + Fault memAccess() + { + return this->staticInst->memAccInst()->execute(this, this->traceData); + } +}; + +#endif // __CPU_O3_SPARC_DYN_INST_HH__ + diff --git a/src/cpu/o3/sparc/dyn_inst_impl.hh b/src/cpu/o3/sparc/dyn_inst_impl.hh new file mode 100644 index 000000000..b830ee7bd --- /dev/null +++ b/src/cpu/o3/sparc/dyn_inst_impl.hh @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2004-2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#include "cpu/o3/sparc/dyn_inst.hh" + +template <class Impl> +SparcDynInst<Impl>::SparcDynInst(TheISA::ExtMachInst inst, Addr PC, + Addr Pred_PC, InstSeqNum seq_num, O3CPU *cpu) + : BaseDynInst<Impl>(inst, PC, Pred_PC, seq_num, cpu) +{ + initVars(); +} + +template <class Impl> +SparcDynInst<Impl>::SparcDynInst(StaticInstPtr &_staticInst) + : BaseDynInst<Impl>(_staticInst) +{ + initVars(); +} + +template <class Impl> +void +SparcDynInst<Impl>::initVars() +{ + // Make sure to have the renamed register entries set to the same + // as the normal register entries. It will allow the IQ to work + // without any modifications. + for (int i = 0; i < this->staticInst->numDestRegs(); i++) { + this->_destRegIdx[i] = this->staticInst->destRegIdx(i); + } + + for (int i = 0; i < this->staticInst->numSrcRegs(); i++) { + this->_srcRegIdx[i] = this->staticInst->srcRegIdx(i); + this->_readySrcRegIdx[i] = 0; + } +} + +template <class Impl> +Fault +SparcDynInst<Impl>::execute() +{ + // @todo: Pretty convoluted way to avoid squashing from happening + // when using the TC during an instruction's execution + // (specifically for instructions that have side-effects that use + // the TC). Fix this. + bool in_syscall = this->thread->inSyscall; + this->thread->inSyscall = true; + + this->fault = this->staticInst->execute(this, this->traceData); + + this->thread->inSyscall = in_syscall; + + return this->fault; +} + +template <class Impl> +Fault +SparcDynInst<Impl>::initiateAcc() +{ + // @todo: Pretty convoluted way to avoid squashing from happening + // when using the TC during an instruction's execution + // (specifically for instructions that have side-effects that use + // the TC). Fix this. + bool in_syscall = this->thread->inSyscall; + this->thread->inSyscall = true; + + this->fault = this->staticInst->initiateAcc(this, this->traceData); + + this->thread->inSyscall = in_syscall; + + return this->fault; +} + +template <class Impl> +Fault +SparcDynInst<Impl>::completeAcc(PacketPtr pkt) +{ + this->fault = this->staticInst->completeAcc(pkt, this, this->traceData); + + return this->fault; +} + +#if FULL_SYSTEM +template <class Impl> +Fault +SparcDynInst<Impl>::hwrei() +{ + return NoFault; +} + +template <class Impl> +void +SparcDynInst<Impl>::trap(Fault fault) +{ + this->cpu->trap(fault, this->threadNumber); +} + +template <class Impl> +bool +SparcDynInst<Impl>::simPalCheck(int palFunc) +{ + panic("simPalCheck called, but there's no PAL in SPARC!\n"); + return false; +} +#else +template <class Impl> +void +SparcDynInst<Impl>::syscall(int64_t callnum) +{ + this->cpu->syscall(callnum, this->threadNumber); +} +#endif + diff --git a/src/cpu/o3/sparc/impl.hh b/src/cpu/o3/sparc/impl.hh new file mode 100644 index 000000000..0a970c2f0 --- /dev/null +++ b/src/cpu/o3/sparc/impl.hh @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#ifndef __CPU_O3_SPARC_IMPL_HH__ +#define __CPU_O3_SPARC_IMPL_HH__ + +#include "arch/sparc/isa_traits.hh" + +#include "cpu/o3/sparc/params.hh" +#include "cpu/o3/cpu_policy.hh" + + +// Forward declarations. +template <class Impl> +class SparcDynInst; + +template <class Impl> +class SparcO3CPU; + +/** Implementation specific struct that defines several key types to the + * CPU, the stages within the CPU, the time buffers, and the DynInst. + * The struct defines the ISA, the CPU policy, the specific DynInst, the + * specific O3CPU, and all of the structs from the time buffers to do + * communication. + * This is one of the key things that must be defined for each hardware + * specific CPU implementation. + */ +struct SparcSimpleImpl +{ + /** The type of MachInst. */ + typedef TheISA::MachInst MachInst; + + /** The CPU policy to be used, which defines all of the CPU stages. */ + typedef SimpleCPUPolicy<SparcSimpleImpl> CPUPol; + + /** The DynInst type to be used. */ + typedef SparcDynInst<SparcSimpleImpl> DynInst; + + /** The refcounted DynInst pointer to be used. In most cases this is + * what should be used, and not DynInst *. + */ + typedef RefCountingPtr<DynInst> DynInstPtr; + + /** The O3CPU type to be used. */ + typedef SparcO3CPU<SparcSimpleImpl> O3CPU; + + /** Same typedef, but for CPUType. BaseDynInst may not always use + * an O3 CPU, so it's clearer to call it CPUType instead in that + * case. + */ + typedef O3CPU CPUType; + + /** The Params to be passed to each stage. */ + typedef SparcSimpleParams Params; + + enum { + MaxWidth = 8, + MaxThreads = 4 + }; +}; + +/** The O3Impl to be used. */ +typedef SparcSimpleImpl O3CPUImpl; + +#endif // __CPU_O3_SPARC_IMPL_HH__ diff --git a/src/cpu/o3/sparc/params.hh b/src/cpu/o3/sparc/params.hh new file mode 100644 index 000000000..d399d64c4 --- /dev/null +++ b/src/cpu/o3/sparc/params.hh @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2004-2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#ifndef __CPU_O3_SPARC_PARAMS_HH__ +#define __CPU_O3_SPARC_PARAMS_HH__ + +#include "cpu/o3/cpu.hh" +#include "cpu/o3/params.hh" + +//Forward declarations +namespace SparcISA +{ + class DTB; + class ITB; +} +class MemObject; +class Process; +class System; + +/** + * This file defines the parameters that will be used for the AlphaO3CPU. + * This must be defined externally so that the Impl can have a params class + * defined that it can pass to all of the individual stages. + */ + +class SparcSimpleParams : public O3Params +{ + public: + +#if FULL_SYSTEM + SparcISA::ITB *itb; + SparcISA::DTB *dtb; +#endif +}; + +#endif // __CPU_O3_SPARC_PARAMS_HH__ diff --git a/src/cpu/o3/sparc/thread_context.cc b/src/cpu/o3/sparc/thread_context.cc new file mode 100755 index 000000000..d85aff502 --- /dev/null +++ b/src/cpu/o3/sparc/thread_context.cc @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2004-2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#include "cpu/o3/thread_context.hh" +#include "cpu/o3/thread_context_impl.hh" + +template class O3ThreadContext<SparcSimpleImpl>; + diff --git a/src/cpu/o3/sparc/thread_context.hh b/src/cpu/o3/sparc/thread_context.hh new file mode 100644 index 000000000..7497959e4 --- /dev/null +++ b/src/cpu/o3/sparc/thread_context.hh @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2004-2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#include "arch/sparc/types.hh" +#include "cpu/o3/thread_context.hh" + +template <class Impl> +class SparcTC : public O3ThreadContext<Impl> +{ + public: +#if FULL_SYSTEM + /** Returns pointer to the quiesce event. */ + virtual EndQuiesceEvent *getQuiesceEvent() + { + return this->thread->quiesceEvent; + } +#endif + + virtual uint64_t readNextNPC() + { + return this->cpu->readNextNPC(this->thread->readTid()); + } + + virtual void setNextNPC(uint64_t val) + { + this->cpu->setNextNPC(val, this->thread->readTid()); + } + + virtual void changeRegFileContext(TheISA::RegContextParam param, + TheISA::RegContextVal val) + { + //XXX Ignore this for now. This -really- needs to get fixed. + } + + + /** This function exits the thread context in the CPU and returns + * 1 if the CPU has no more active threads (meaning it's OK to exit); + * Used in syscall-emulation mode when a thread executes the 'exit' + * syscall. + */ + virtual int exit() + { + this->deallocate(); + + // If there are still threads executing in the system + if (this->cpu->numActiveThreads()) + return 0; // don't exit simulation + else + return 1; // exit simulation + } +}; diff --git a/src/cpu/o3/thread_context.hh b/src/cpu/o3/thread_context.hh index 390569c3d..4987d6eb4 100755 --- a/src/cpu/o3/thread_context.hh +++ b/src/cpu/o3/thread_context.hh @@ -66,6 +66,14 @@ class O3ThreadContext : public ThreadContext /** Pointer to the thread state that this TC corrseponds to. */ O3ThreadState<Impl> *thread; +#if FULL_SYSTEM + /** Returns a pointer to the ITB. */ + TheISA::ITB *getITBPtr() { return cpu->itb; } + + /** Returns a pointer to the DTB. */ + TheISA::DTB *getDTBPtr() { return cpu->dtb; } +#endif + /** Returns a pointer to this CPU. */ virtual BaseCPU *getCpuPtr() { return cpu; } diff --git a/src/cpu/o3/thread_context_impl.hh b/src/cpu/o3/thread_context_impl.hh index afebf294f..af98fa1f5 100755 --- a/src/cpu/o3/thread_context_impl.hh +++ b/src/cpu/o3/thread_context_impl.hh @@ -29,6 +29,7 @@ * Korey Sewell */ +#include "arch/regfile.hh" #include "cpu/o3/thread_context.hh" #include "cpu/quiesce_event.hh" @@ -305,6 +306,7 @@ template <class Impl> uint64_t O3ThreadContext<Impl>::readIntReg(int reg_idx) { + reg_idx = TheISA::flattenIntIndex(this, reg_idx); return cpu->readArchIntReg(reg_idx, thread->readTid()); } @@ -349,6 +351,7 @@ template <class Impl> void O3ThreadContext<Impl>::setIntReg(int reg_idx, uint64_t val) { + reg_idx = TheISA::flattenIntIndex(this, reg_idx); cpu->setArchIntReg(reg_idx, val, thread->readTid()); // Squash if we're not already in a state update mode. diff --git a/src/cpu/simple_thread.hh b/src/cpu/simple_thread.hh index 10bbe292c..f2f79c070 100644 --- a/src/cpu/simple_thread.hh +++ b/src/cpu/simple_thread.hh @@ -33,6 +33,8 @@ #define __CPU_SIMPLE_THREAD_HH__ #include "arch/isa_traits.hh" +#include "arch/regfile.hh" +#include "arch/syscallreturn.hh" #include "config/full_system.hh" #include "cpu/thread_context.hh" #include "cpu/thread_state.hh" @@ -250,7 +252,7 @@ class SimpleThread : public ThreadState // uint64_t readIntReg(int reg_idx) { - return regs.readIntReg(reg_idx); + return regs.readIntReg(TheISA::flattenIntIndex(getTC(), reg_idx)); } FloatReg readFloatReg(int reg_idx, int width) @@ -275,7 +277,7 @@ class SimpleThread : public ThreadState void setIntReg(int reg_idx, uint64_t val) { - regs.setIntReg(reg_idx, val); + regs.setIntReg(TheISA::flattenIntIndex(getTC(), reg_idx), val); } void setFloatReg(int reg_idx, FloatReg val, int width) @@ -376,18 +378,20 @@ class SimpleThread : public ThreadState #if !FULL_SYSTEM TheISA::IntReg getSyscallArg(int i) { - return regs.readIntReg(TheISA::ArgumentReg0 + i); + return regs.readIntReg(TheISA::flattenIntIndex(getTC(), + TheISA::ArgumentReg0 + i)); } // used to shift args for indirect syscall void setSyscallArg(int i, TheISA::IntReg val) { - regs.setIntReg(TheISA::ArgumentReg0 + i, val); + regs.setIntReg(TheISA::flattenIntIndex(getTC(), + TheISA::ArgumentReg0 + i), val); } void setSyscallReturn(SyscallReturn return_value) { - TheISA::setSyscallReturn(return_value, ®s); + TheISA::setSyscallReturn(return_value, getTC()); } void syscall(int64_t callnum) diff --git a/src/cpu/thread_context.hh b/src/cpu/thread_context.hh index bb9cc9e16..16e491fd3 100644 --- a/src/cpu/thread_context.hh +++ b/src/cpu/thread_context.hh @@ -32,13 +32,13 @@ #define __CPU_THREAD_CONTEXT_HH__ #include "arch/regfile.hh" -#include "arch/syscallreturn.hh" #include "arch/types.hh" #include "config/full_system.hh" #include "mem/request.hh" #include "sim/faults.hh" #include "sim/host.hh" #include "sim/serialize.hh" +#include "sim/syscallreturn.hh" #include "sim/byteswap.hh" // @todo: Figure out a more architecture independent way to obtain the ITB and diff --git a/src/dev/sparc/SConscript b/src/dev/sparc/SConscript index 701e533a8..c37294f0c 100644 --- a/src/dev/sparc/SConscript +++ b/src/dev/sparc/SConscript @@ -37,6 +37,7 @@ Import('env') sources = [] sources += Split(''' + t1000.cc ''') # Convert file names to SCons File objects. This takes care of the diff --git a/src/dev/sparc/t1000.cc b/src/dev/sparc/t1000.cc new file mode 100644 index 000000000..1df6bf15f --- /dev/null +++ b/src/dev/sparc/t1000.cc @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Ali Saidi + */ + +/** @file + * Implementation of T1000 platform. + */ + +#include <deque> +#include <string> +#include <vector> + +#include "cpu/intr_control.hh" +#include "dev/simconsole.hh" +#include "dev/sparc/t1000.hh" +#include "sim/builder.hh" +#include "sim/system.hh" + +using namespace std; +//Should this be AlphaISA? +using namespace TheISA; + +T1000::T1000(const string &name, System *s, IntrControl *ic) + : Platform(name, ic), system(s) +{ + // set the back pointer from the system to myself + system->platform = this; +} + +Tick +T1000::intrFrequency() +{ + return (Tick)0; +} + +void +T1000::postConsoleInt() +{ +} + +void +T1000::clearConsoleInt() +{ +} + +void +T1000::postPciInt(int line) +{ +} + +void +T1000::clearPciInt(int line) +{ +} + +Addr +T1000::pciToDma(Addr pciAddr) const +{ + return (Addr)0; +} + + +Addr +T1000::calcConfigAddr(int bus, int dev, int func) +{ + return (Addr)0; +} + +void +T1000::serialize(std::ostream &os) +{ +} + +void +T1000::unserialize(Checkpoint *cp, const std::string §ion) +{ +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(T1000) + + SimObjectParam<System *> system; + SimObjectParam<IntrControl *> intrctrl; + +END_DECLARE_SIM_OBJECT_PARAMS(T1000) + +BEGIN_INIT_SIM_OBJECT_PARAMS(T1000) + + INIT_PARAM(system, "system"), + INIT_PARAM(intrctrl, "interrupt controller") + +END_INIT_SIM_OBJECT_PARAMS(T1000) + +CREATE_SIM_OBJECT(T1000) +{ + return new T1000(getInstanceName(), system, intrctrl); +} + +REGISTER_SIM_OBJECT("T1000", T1000) diff --git a/src/dev/sparc/t1000.hh b/src/dev/sparc/t1000.hh new file mode 100644 index 000000000..fb82dff11 --- /dev/null +++ b/src/dev/sparc/t1000.hh @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2004-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Ali Saidi + */ + +/** + * @file + * Declaration of top level class for the Tsunami chipset. This class just + * retains pointers to all its children so the children can communicate. + */ + +#ifndef __DEV_T1000_HH__ +#define __DEV_T1000_HH__ + +#include "dev/platform.hh" + +class IdeController; +class System; + +class T1000 : public Platform +{ + public: + /** Pointer to the system */ + System *system; + + public: + /** + * Constructor for the Tsunami Class. + * @param name name of the object + * @param s system the object belongs to + * @param intctrl pointer to the interrupt controller + */ + T1000(const std::string &name, System *s, IntrControl *intctrl); + + /** + * Return the interrupting frequency to AlphaAccess + * @return frequency of RTC interrupts + */ + virtual Tick intrFrequency(); + + /** + * Cause the cpu to post a serial interrupt to the CPU. + */ + virtual void postConsoleInt(); + + /** + * Clear a posted CPU interrupt (id=55) + */ + virtual void clearConsoleInt(); + + /** + * Cause the chipset to post a cpi interrupt to the CPU. + */ + virtual void postPciInt(int line); + + /** + * Clear a posted PCI->CPU interrupt + */ + virtual void clearPciInt(int line); + + + virtual Addr pciToDma(Addr pciAddr) const; + + /** + * Calculate the configuration address given a bus/dev/func. + */ + virtual Addr calcConfigAddr(int bus, int dev, int func); + + /** + * Serialize this object to the given output stream. + * @param os The stream to serialize to. + */ + virtual void serialize(std::ostream &os); + + /** + * Reconstruct the state of this object from a checkpoint. + * @param cp The checkpoint use. + * @param section The section name of this object + */ + virtual void unserialize(Checkpoint *cp, const std::string §ion); +}; + +#endif // __DEV_T1000_HH__ diff --git a/src/mem/physical.cc b/src/mem/physical.cc index 94f60ad80..6610e547d 100644 --- a/src/mem/physical.cc +++ b/src/mem/physical.cc @@ -65,6 +65,10 @@ PhysicalMemory::PhysicalMemory(Params *p) fatal("Could not mmap!\n"); } + //If requested, initialize all the memory to 0 + if(params()->zero) + memset(pmemAddr, 0, params()->addrRange.size()); + pagePtr = 0; } @@ -191,7 +195,7 @@ PhysicalMemory::checkLockedAddrList(Request *req) void PhysicalMemory::doFunctionalAccess(PacketPtr pkt) { - assert(pkt->getAddr() + pkt->getSize() > params()->addrRange.start && + assert(pkt->getAddr() >= params()->addrRange.start && pkt->getAddr() + pkt->getSize() <= params()->addrRange.start + params()->addrRange.size()); @@ -432,6 +436,7 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory) Param<string> file; Param<Range<Addr> > range; Param<Tick> latency; + Param<bool> zero; END_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory) @@ -439,7 +444,8 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(PhysicalMemory) INIT_PARAM_DFLT(file, "memory mapped file", ""), INIT_PARAM(range, "Device Address Range"), - INIT_PARAM(latency, "Memory access latency") + INIT_PARAM(latency, "Memory access latency"), + INIT_PARAM(zero, "Zero initialize memory") END_INIT_SIM_OBJECT_PARAMS(PhysicalMemory) @@ -449,6 +455,7 @@ CREATE_SIM_OBJECT(PhysicalMemory) p->name = getInstanceName(); p->addrRange = range; p->latency = latency; + p->zero = zero; return new PhysicalMemory(p); } diff --git a/src/mem/physical.hh b/src/mem/physical.hh index 045e61612..af88bcaa0 100644 --- a/src/mem/physical.hh +++ b/src/mem/physical.hh @@ -154,6 +154,7 @@ class PhysicalMemory : public MemObject std::string name; Range<Addr> addrRange; Tick latency; + bool zero; }; protected: diff --git a/src/python/m5/objects/PhysicalMemory.py b/src/python/m5/objects/PhysicalMemory.py index 4e097543d..b8df6229e 100644 --- a/src/python/m5/objects/PhysicalMemory.py +++ b/src/python/m5/objects/PhysicalMemory.py @@ -9,6 +9,7 @@ class PhysicalMemory(MemObject): range = Param.AddrRange(AddrRange('128MB'), "Device Address") file = Param.String('', "memory mapped file") latency = Param.Latency(Parent.clock, "latency of an access") + zero = Param.Bool(False, "zero initialize memory") class DRAMMemory(PhysicalMemory): type = 'DRAMMemory' diff --git a/src/python/m5/objects/System.py b/src/python/m5/objects/System.py index 908c3d4ad..7ac4dd701 100644 --- a/src/python/m5/objects/System.py +++ b/src/python/m5/objects/System.py @@ -29,17 +29,40 @@ class AlphaSystem(System): class SparcSystem(System): type = 'SparcSystem' _rom_base = 0xfff0000000 + _nvram_base = 0x1f11000000 + _hypervisor_desc_base = 0x1f12080000 + _partition_desc_base = 0x1f12000000 # ROM for OBP/Reset/Hypervisor rom = Param.PhysicalMemory(PhysicalMemory(range = AddrRange(_rom_base, size = '8MB')), "Memory to hold the ROM data") + # nvram + nvram = Param.PhysicalMemory( + PhysicalMemory(range = AddrRange(_nvram_base, size = '8kB')), + "Memory to hold the nvram data") + # hypervisor description + hypervisor_desc = Param.PhysicalMemory( + PhysicalMemory(range = AddrRange(_hypervisor_desc_base, size = '8kB')), + "Memory to hold the hypervisor description") + # partition description + partition_desc = Param.PhysicalMemory( + PhysicalMemory(range = AddrRange(_partition_desc_base, size = '8kB')), + "Memory to hold the partition description") reset_addr = Param.Addr(_rom_base, "Address to load ROM at") hypervisor_addr = Param.Addr(Addr('64kB') + _rom_base, "Address to load hypervisor at") openboot_addr = Param.Addr(Addr('512kB') + _rom_base, "Address to load openboot at") + nvram_addr = Param.Addr(_nvram_base, "Address to put the nvram") + hypervisor_desc_addr = Param.Addr(_hypervisor_desc_base, + "Address for the hypervisor description") + partition_desc_addr = Param.Addr(_partition_desc_base, + "Address for the partition description") reset_bin = Param.String("file that contains the reset code") hypervisor_bin = Param.String("file that contains the hypervisor code") openboot_bin = Param.String("file that contains the openboot code") + nvram_bin = Param.String("file that contains the contents of nvram") + hypervisor_desc_bin = Param.String("file that contains the hypervisor description") + partition_desc_bin = Param.String("file that contains the partition description") diff --git a/src/python/m5/objects/T1000.py b/src/python/m5/objects/T1000.py new file mode 100644 index 000000000..bb0d37bf8 --- /dev/null +++ b/src/python/m5/objects/T1000.py @@ -0,0 +1,31 @@ +from m5.params import * +from m5.proxy import * +from Device import BasicPioDevice +from Uart import Uart8250 +from Platform import Platform +from SimConsole import SimConsole, ConsoleListener + +class IsaFake(BasicPioDevice): + type = 'IsaFake' + pio_size = Param.Addr(0x8, "Size of address range") + ret_data = Param.UInt8(0xFF, "Default data to return") + ret_bad_addr = Param.Bool(False, "Return pkt status bad address on access") + +class BadAddr(IsaFake): + ret_bad_addr = Param.Bool(True, "Return pkt status bad address on access") + +class T1000(Platform): + type = 'T1000' + system = Param.System(Parent.any, "system") + + fake_iob = IsaFake(pio_addr=0x8000000000, pio_size=0x7F00000000) + + uart = Uart8250(pio_addr=0xfff0c2c000) + console = SimConsole(listener = ConsoleListener()) + + # Attach I/O devices to specified bus object. Can't do this + # earlier, since the bus object itself is typically defined at the + # System level. + def attachIO(self, bus): + self.fake_iob.pio = bus.port + self.uart.pio = bus.port diff --git a/src/sim/syscallreturn.hh b/src/sim/syscallreturn.hh new file mode 100644 index 000000000..d1c43f584 --- /dev/null +++ b/src/sim/syscallreturn.hh @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Gabe Black + */ + +#ifndef __SIM_SYSCALLRETURN_HH__ +#define __SIM_SYSCALLRETURN_HH__ + +#include <inttypes.h> + +class SyscallReturn +{ + public: + template <class T> + SyscallReturn(T v, bool s) + { + retval = (uint64_t)v; + success = s; + } + + template <class T> + SyscallReturn(T v) + { + success = (v >= 0); + retval = (uint64_t)v; + } + + ~SyscallReturn() {} + + SyscallReturn& operator=(const SyscallReturn& s) + { + retval = s.retval; + success = s.success; + return *this; + } + + bool successful() { return success; } + uint64_t value() { return retval; } + + private: + uint64_t retval; + bool success; +}; + +#endif |