diff options
Diffstat (limited to 'src/arch/sparc')
-rw-r--r-- | src/arch/sparc/asi.cc | 27 | ||||
-rw-r--r-- | src/arch/sparc/faults.cc | 103 | ||||
-rw-r--r-- | src/arch/sparc/faults.hh | 8 | ||||
-rw-r--r-- | src/arch/sparc/interrupts.hh | 134 | ||||
-rw-r--r-- | src/arch/sparc/intregfile.cc | 7 | ||||
-rw-r--r-- | src/arch/sparc/isa/decoder.isa | 32 | ||||
-rw-r--r-- | src/arch/sparc/isa/formats/mem/blockmem.isa | 4 | ||||
-rw-r--r-- | src/arch/sparc/isa_traits.hh | 9 | ||||
-rw-r--r-- | src/arch/sparc/miscregfile.cc | 26 | ||||
-rw-r--r-- | src/arch/sparc/miscregfile.hh | 30 | ||||
-rw-r--r-- | src/arch/sparc/regfile.cc | 6 | ||||
-rw-r--r-- | src/arch/sparc/tlb.cc | 150 | ||||
-rw-r--r-- | src/arch/sparc/ua2005.cc | 245 |
13 files changed, 483 insertions, 298 deletions
diff --git a/src/arch/sparc/asi.cc b/src/arch/sparc/asi.cc index a9a778ff6..3d553955f 100644 --- a/src/arch/sparc/asi.cc +++ b/src/arch/sparc/asi.cc @@ -179,26 +179,23 @@ namespace SparcISA (asi == ASI_LDTX_PL) || (asi == ASI_LDTX_SL) || (asi == ASI_BLK_PL) || - (asi == ASI_BLK_SL); + (asi == ASI_BLK_SL) || + (asi == ASI_LTX_L); } bool AsiIsTwin(ASI asi) { return - (asi == ASI_QUAD_LDD) || - (asi == ASI_LDTX_AIUP) || - (asi == ASI_LDTX_AIUS) || - (asi == ASI_LDTX_REAL) || - (asi == ASI_LDTX_N) || - (asi == ASI_LDTX_AIUP_L) || - (asi == ASI_LDTX_AIUS_L) || - (asi == ASI_LDTX_REAL_L) || - (asi == ASI_LDTX_NL) || - (asi == ASI_LDTX_P) || - (asi == ASI_LDTX_S) || - (asi == ASI_LDTX_PL) || - (asi == ASI_LDTX_SL) || - (asi == ASI_LTX_L); + (asi >= ASI_LDTX_AIUP && + asi <= ASI_LDTX_N && + asi != ASI_QUEUE) || + (asi >= ASI_LDTX_AIUP_L && + asi <= ASI_LDTX_NL && + asi != 0x2D) || + asi == ASI_LDTX_P || + asi == ASI_LDTX_S || + asi == ASI_LDTX_PL || + asi == ASI_LDTX_SL; } bool AsiIsPartialStore(ASI asi) diff --git a/src/arch/sparc/faults.cc b/src/arch/sparc/faults.cc index 92fdbfdbb..d94c05a0f 100644 --- a/src/arch/sparc/faults.cc +++ b/src/arch/sparc/faults.cc @@ -197,7 +197,7 @@ template<> SparcFaultBase::FaultVals template<> SparcFaultBase::FaultVals SparcFault<InterruptLevelN>::vals = - {"interrupt_level_n", 0x041, 0, {P, P, SH}}; + {"interrupt_level_n", 0x040, 0, {P, P, SH}}; template<> SparcFaultBase::FaultVals SparcFault<HstickMatch>::vals = @@ -240,7 +240,7 @@ template<> SparcFaultBase::FaultVals {"dev_mondo", 0x07D, 1611, {P, P, SH}}; template<> SparcFaultBase::FaultVals - SparcFault<ResumeableError>::vals = + SparcFault<ResumableError>::vals = {"resume_error", 0x07E, 3330, {P, P, SH}}; template<> SparcFaultBase::FaultVals @@ -342,22 +342,8 @@ void doREDFault(ThreadContext *tc, TrapType tt) //Update GL tc->setMiscRegWithEffect(MISCREG_GL, min<int>(GL+1, MaxGL)); - //set PSTATE.mm to 00 - //set PSTATE.pef to 1 - PSTATE |= (1 << 4); - //set PSTATE.am to 0 - PSTATE &= ~(1 << 3); -/* //set PSTATE.priv to 0 - PSTATE &= ~(1 << 2);*/ - //set PSTATE.ie to 0 - //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 - //XXX Where is the tct bit? - //set PSTATE.tct to 0 + PSTATE = mbits(PSTATE, 2, 2); // just save the priv bit + PSTATE |= (1 << 4); //set PSTATE.pef to 1 tc->setMiscReg(MISCREG_PSTATE, PSTATE); //set HPSTATE.red to 1 @@ -440,64 +426,45 @@ void doNormalFault(ThreadContext *tc, TrapType tt, bool gotoHpriv) tc->setMiscReg(MISCREG_TT, tt); //Update the global register level - if(!gotoHpriv) + if (!gotoHpriv) tc->setMiscRegWithEffect(MISCREG_GL, min<int>(GL+1, MaxPGL)); else tc->setMiscRegWithEffect(MISCREG_GL, min<int>(GL+1, MaxGL)); //PSTATE.mm is unchanged - //PSTATE.pef = whether or not an fpu is present - //XXX We'll say there's one present, even though there aren't - //implementations for a decent number of the instructions - PSTATE |= (1 << 4); - //PSTATE.am = 0 - PSTATE &= ~(1 << 3); - if(!gotoHpriv) - { - //PSTATE.priv = 1 - PSTATE |= (1 << 2); - //PSTATE.cle = PSTATE.tle - replaceBits(PSTATE, 9, 9, PSTATE >> 8); - } - else - { - //PSTATE.priv = 0 - //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); - } - //PSTATE.ie = 0 - PSTATE &= ~(1 << 1); + PSTATE |= (1 << 4); //PSTATE.pef = whether or not an fpu is present + PSTATE &= ~(1 << 3); //PSTATE.am = 0 + PSTATE &= ~(1 << 1); //PSTATE.ie = 0 //PSTATE.tle is unchanged //PSTATE.tct = 0 - //XXX Where exactly is this field? - tc->setMiscReg(MISCREG_PSTATE, PSTATE); - if(gotoHpriv) + if (gotoHpriv) { - //HPSTATE.red = 0 - HPSTATE &= ~(1 << 5); - //HPSTATE.hpriv = 1 - HPSTATE |= (1 << 2); - //HPSTATE.ibe = 0 - HPSTATE &= ~(1 << 10); + PSTATE &= ~(1 << 9); // PSTATE.cle = 0 + //The manual says PSTATE.priv should be 0, but Legion leaves it alone + HPSTATE &= ~(1 << 5); //HPSTATE.red = 0 + HPSTATE |= (1 << 2); //HPSTATE.hpriv = 1 + HPSTATE &= ~(1 << 10); //HPSTATE.ibe = 0 //HPSTATE.tlz is unchanged tc->setMiscReg(MISCREG_HPSTATE, HPSTATE); + } else { // we are going to priv + PSTATE |= (1 << 2); //PSTATE.priv = 1 + replaceBits(PSTATE, 9, 9, PSTATE >> 8); //PSTATE.cle = PSTATE.tle } + tc->setMiscReg(MISCREG_PSTATE, PSTATE); + bool changedCWP = true; - if(tt == 0x24) + if (tt == 0x24) CWP++; - else if(0x80 <= tt && tt <= 0xbf) + else if (0x80 <= tt && tt <= 0xbf) CWP += (CANSAVE + 2); - else if(0xc0 <= tt && tt <= 0xff) + else if (0xc0 <= tt && tt <= 0xff) CWP--; else changedCWP = false; - if(changedCWP) + if (changedCWP) { CWP = (CWP + NWindows) % NWindows; tc->setMiscRegWithEffect(MISCREG_CWP, CWP); @@ -538,45 +505,45 @@ void SparcFaultBase::invoke(ThreadContext * tc) //We can refer to this to see what the trap level -was-, but something //in the middle could change it in the regfile out from under us. - MiscReg TL = tc->readMiscReg(MISCREG_TL); - MiscReg TT = tc->readMiscReg(MISCREG_TT); - MiscReg PSTATE = tc->readMiscReg(MISCREG_PSTATE); - MiscReg HPSTATE = tc->readMiscReg(MISCREG_HPSTATE); + MiscReg tl = tc->readMiscReg(MISCREG_TL); + MiscReg tt = tc->readMiscReg(MISCREG_TT); + MiscReg pstate = tc->readMiscReg(MISCREG_PSTATE); + MiscReg hpstate = tc->readMiscReg(MISCREG_HPSTATE); Addr PC, NPC; PrivilegeLevel current; - if(HPSTATE & (1 << 2)) + if (hpstate & HPSTATE::hpriv) current = Hyperprivileged; - else if(PSTATE & (1 << 2)) + else if (pstate & PSTATE::priv) current = Privileged; else current = User; PrivilegeLevel level = getNextLevel(current); - if(HPSTATE & (1 << 5) || TL == MaxTL - 1) { + if ((hpstate & HPSTATE::red) || (tl == MaxTL - 1)) { getREDVector(5, PC, NPC); - doREDFault(tc, TT); + 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) { + } else if (tl == MaxTL) { panic("Should go to error state here.. crap\n"); //Do error_state somehow? //Probably inject a WDR fault using the interrupt mechanism. //What should the PC and NPC be set to? - } else if(TL > MaxPTL && level == Privileged) { + } else if (tl > MaxPTL && level == Privileged) { //guest_watchdog fault doNormalFault(tc, trapType(), true); getHyperVector(tc, PC, NPC, 2); - } else if(level == Hyperprivileged || + } else if (level == Hyperprivileged || level == Privileged && trapType() >= 384) { doNormalFault(tc, trapType(), true); getHyperVector(tc, PC, NPC, trapType()); } else { doNormalFault(tc, trapType(), false); - getPrivVector(tc, PC, NPC, trapType(), TL+1); + getPrivVector(tc, PC, NPC, trapType(), tl+1); } tc->setPC(PC); diff --git a/src/arch/sparc/faults.hh b/src/arch/sparc/faults.hh index e632502aa..3c0d9674f 100644 --- a/src/arch/sparc/faults.hh +++ b/src/arch/sparc/faults.hh @@ -29,8 +29,8 @@ * Kevin Lim */ -#ifndef __ALPHA_FAULTS_HH__ -#define __ALPHA_FAULTS_HH__ +#ifndef __SPARC_FAULTS_HH__ +#define __SPARC_FAULTS_HH__ #include "sim/faults.hh" @@ -210,7 +210,7 @@ class CpuMondo : public SparcFault<CpuMondo> {}; class DevMondo : public SparcFault<DevMondo> {}; -class ResumeableError : public SparcFault<ResumeableError> {}; +class ResumableError : public SparcFault<ResumableError> {}; class SpillNNormal : public EnumeratedFault<SpillNNormal> { @@ -280,4 +280,4 @@ static inline Fault genAlignmentFault() } // SparcISA namespace -#endif // __FAULTS_HH__ +#endif // __SPARC_FAULTS_HH__ diff --git a/src/arch/sparc/interrupts.hh b/src/arch/sparc/interrupts.hh index 452164e46..99ddb4919 100644 --- a/src/arch/sparc/interrupts.hh +++ b/src/arch/sparc/interrupts.hh @@ -24,8 +24,6 @@ * 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_INTERRUPT_HH__ @@ -34,19 +32,45 @@ #include "arch/sparc/faults.hh" #include "cpu/thread_context.hh" - namespace SparcISA { + +enum interrupts_t { + trap_level_zero, + hstick_match, + interrupt_vector, + cpu_mondo, + dev_mondo, + resumable_error, + soft_interrupt, + num_interrupt_types +}; + class Interrupts { - protected: + private: + + bool interrupts[num_interrupt_types]; + int numPosted; public: Interrupts() { + for (int i = 0; i < num_interrupt_types; ++i) { + interrupts[i] = false; + } + numPosted = 0; + } + void post(int int_type) + { + if (int_type < 0 || int_type >= num_interrupt_types) + panic("posting unknown interrupt!\n"); + interrupts[int_type] = true; + ++numPosted; } + void post(int int_num, int index) { @@ -64,9 +88,7 @@ namespace SparcISA bool check_interrupts(ThreadContext * tc) const { - // so far only handle softint interrupts - int int_level = InterruptLevel(tc->readMiscReg(MISCREG_SOFTINT)); - if (int_level) + if (numPosted) return true; else return false; @@ -74,20 +96,96 @@ namespace SparcISA Fault getInterrupt(ThreadContext * tc) { - // conditioning the softint interrups - if (tc->readMiscReg(MISCREG_HPSTATE) & hpriv) { - // if running in privileged mode, then pend the interrupt - return NoFault; - } else { - int int_level = InterruptLevel(tc->readMiscReg(MISCREG_SOFTINT)); - if ((int_level <= tc->readMiscReg(MISCREG_PIL)) || - !(tc->readMiscReg(MISCREG_PSTATE) & ie)) { - // if PIL or no interrupt enabled, then pend the interrupt - return NoFault; + int hpstate = tc->readMiscReg(MISCREG_HPSTATE); + int pstate = tc->readMiscReg(MISCREG_PSTATE); + bool ie = pstate & PSTATE::ie; + + // THESE ARE IN ORDER OF PRIORITY + // since there are early returns, and the highest + // priority interrupts should get serviced, + // it is v. important that new interrupts are inserted + // in the right order of processing + if (hpstate & HPSTATE::hpriv) { + if (ie) { + if (interrupts[hstick_match]) { + if (tc->readMiscReg(MISCREG_HINTP) & 1) { + interrupts[hstick_match] = false; + --numPosted; + return new HstickMatch; + } + } + if (interrupts[interrupt_vector]) { + interrupts[interrupt_vector] = false; + --numPosted; + //HAVEN'T IMPLed THIS YET + return NoFault; + } } else { - return new InterruptLevelN(int_level); + if (interrupts[hstick_match]) { + return NoFault; + } + + } + } else { + if (interrupts[trap_level_zero]) { + if ((pstate & HPSTATE::tlz) && (tc->readMiscReg(MISCREG_TL) == 0)) { + interrupts[trap_level_zero] = false; + --numPosted; + return new TrapLevelZero; + } + } + if (interrupts[hstick_match]) { + if (tc->readMiscReg(MISCREG_HINTP) & 1) { + interrupts[hstick_match] = false; + --numPosted; + return new HstickMatch; + } + } + if (ie) { + if (interrupts[cpu_mondo]) { + interrupts[cpu_mondo] = false; + --numPosted; + return new CpuMondo; + } + if (interrupts[dev_mondo]) { + interrupts[dev_mondo] = false; + --numPosted; + return new DevMondo; + } + if (interrupts[soft_interrupt]) { + int il = InterruptLevel(tc->readMiscReg(MISCREG_SOFTINT)); + // it seems that interrupt vectors are right in + // the middle of interrupt levels with regard to + // priority, so have to check + if ((il < 6) && + interrupts[interrupt_vector]) { + // may require more details here since there + // may be lots of interrupts embedded in an + // platform interrupt vector + interrupts[interrupt_vector] = false; + --numPosted; + //HAVEN'T IMPLed YET + return NoFault; + } else { + if (il > tc->readMiscReg(MISCREG_PIL)) { + uint64_t si = tc->readMiscReg(MISCREG_SOFTINT); + uint64_t more = si & ~(1 << (il + 1)); + if (!InterruptLevel(more)) { + interrupts[soft_interrupt] = false; + --numPosted; + } + return new InterruptLevelN(il); + } + } + } + if (interrupts[resumable_error]) { + interrupts[resumable_error] = false; + --numPosted; + return new ResumableError; + } } } + return NoFault; } void updateIntrInfo(ThreadContext * tc) diff --git a/src/arch/sparc/intregfile.cc b/src/arch/sparc/intregfile.cc index 594fe4bea..2c9d9b162 100644 --- a/src/arch/sparc/intregfile.cc +++ b/src/arch/sparc/intregfile.cc @@ -120,6 +120,8 @@ void IntRegFile::setReg(int intReg, const IntReg &val) void IntRegFile::setCWP(int cwp) { int index = ((NWindows - cwp) % NWindows) * 2; + if (index < 0) + panic("Index less than 0. cwp=%d nwin=%d\n", cwp, NWindows); offset[Outputs] = FrameOffset + (index * RegsPerFrame); offset[Locals] = FrameOffset + ((index+1) * RegsPerFrame); offset[Inputs] = FrameOffset + @@ -137,6 +139,11 @@ void IntRegFile::setGlobals(int gl) regView[Globals] = regGlobals[gl]; offset[Globals] = RegGlobalOffset + gl * RegsPerFrame; + + if (regView[Globals] == regView[Inputs] || + regView[Globals] == regView[Locals] || + regView[Globals] == regView[Outputs] ) + panic("Two register arrays set to the same thing!\n"); } void IntRegFile::serialize(std::ostream &os) diff --git a/src/arch/sparc/isa/decoder.isa b/src/arch/sparc/isa/decoder.isa index 8abaf1007..e59ce9d11 100644 --- a/src/arch/sparc/isa/decoder.isa +++ b/src/arch/sparc/isa/decoder.isa @@ -190,7 +190,7 @@ decode OP default Unknown::unknown() }}); 0x0B: smul({{ Rd.sdw = Rs1.sdw<31:0> * Rs2_or_imm13<31:0>; - Y = Rd.sdw; + Y = Rd.sdw<63:32>; }}); 0x0C: subc({{Rd.sdw = Rs1.sdw + (~Rs2_or_imm13) + 1 - Ccr<0:0>}}); 0x0D: udivx({{ @@ -471,12 +471,12 @@ decode OP default Unknown::unknown() //0x11-0x1F should cause an illegal instruction exception } 0x2B: BasicOperate::flushw({{ - if(NWindows - 2 - Cansave == 0) + if(NWindows - 2 - Cansave != 0) { if(Otherwin) - fault = new SpillNOther(Wstate<5:3>); + fault = new SpillNOther(4*Wstate<5:3>); else - fault = new SpillNNormal(Wstate<2:0>); + fault = new SpillNNormal(4*Wstate<2:0>); } }}); 0x2C: decode MOVCC3 @@ -891,9 +891,9 @@ decode OP default Unknown::unknown() if(Canrestore == 0) { if(Otherwin) - fault = new FillNOther(Wstate<5:3>); + fault = new FillNOther(4*Wstate<5:3>); else - fault = new FillNNormal(Wstate<2:0>); + fault = new FillNNormal(4*Wstate<2:0>); } //Check for alignment faults else if(target & 0x3) @@ -941,9 +941,9 @@ decode OP default Unknown::unknown() if(Cansave == 0) { if(Otherwin) - fault = new SpillNOther(Wstate<5:3>); + fault = new SpillNOther(4*Wstate<5:3>); else - fault = new SpillNNormal(Wstate<2:0>); + fault = new SpillNNormal(4*Wstate<2:0>); } else if(Cleanwin - Canrestore == 0) { @@ -961,9 +961,9 @@ decode OP default Unknown::unknown() if(Canrestore == 0) { if(Otherwin) - fault = new FillNOther(Wstate<5:3>); + fault = new FillNOther(4*Wstate<5:3>); else - fault = new FillNNormal(Wstate<2:0>); + fault = new FillNNormal(4*Wstate<2:0>); } else { @@ -1040,6 +1040,12 @@ decode OP default Unknown::unknown() 0x11: lduba({{Rd = Mem.ub;}}, {{EXT_ASI}}); 0x12: lduha({{Rd = Mem.uhw;}}, {{EXT_ASI}}); 0x13: decode EXT_ASI { + //ASI_LDTD_AIUP + 0x22: TwinLoad::ldtx_aiup( + {{RdTwin.udw = Mem.udw}}, {{EXT_ASI}}); + //ASI_LDTD_AIUS + 0x23: TwinLoad::ldtx_aius( + {{RdTwin.udw = Mem.udw}}, {{EXT_ASI}}); //ASI_QUAD_LDD 0x24: TwinLoad::ldtx_quad_ldd( {{RdTwin.udw = Mem.udw}}, {{EXT_ASI}}); @@ -1058,6 +1064,12 @@ decode OP default Unknown::unknown() //ASI_LDTX_N_L 0x2F: TwinLoad::ldtx_n_l( {{RdTwin.udw = Mem.udw}}, {{EXT_ASI}}); + //ASI_LDTX_P + 0xE2: TwinLoad::ldtx_p( + {{RdTwin.udw = Mem.udw}}, {{EXT_ASI}}); + //ASI_LDTX_S + 0xE3: TwinLoad::ldtx_s( + {{RdTwin.udw = Mem.udw}}, {{EXT_ASI}}); default: ldtwa({{ uint64_t val = Mem.udw; RdLow = val<31:0>; diff --git a/src/arch/sparc/isa/formats/mem/blockmem.isa b/src/arch/sparc/isa/formats/mem/blockmem.isa index 62ac4b43a..352e963b3 100644 --- a/src/arch/sparc/isa/formats/mem/blockmem.isa +++ b/src/arch/sparc/isa/formats/mem/blockmem.isa @@ -451,6 +451,8 @@ let {{ flag_code = '' if (microPc == 7): flag_code = "flags[IsLastMicroOp] = true;" + elif (microPc == 0): + flag_code = "flags[IsDelayedCommit] = true; flags[IsFirstMicroOp] = true;" else: flag_code = "flags[IsDelayedCommit] = true;" pcedCode = matcher.sub("Frd_%d" % microPc, code) @@ -492,7 +494,7 @@ let {{ flag_code = "flags[IsLastMicroOp] = true;" pcedCode = matcher.sub("RdHigh", code) else: - flag_code = "flags[IsDelayedCommit] = true;" + flag_code = "flags[IsDelayedCommit] = true; flags[IsFirstMicroOp] = true;" pcedCode = matcher.sub("RdLow", code) iop = InstObjParams(name, Name, 'TwinMem', {"code": pcedCode, "ea_code": addrCalcReg, diff --git a/src/arch/sparc/isa_traits.hh b/src/arch/sparc/isa_traits.hh index 2b136856a..8a26334a7 100644 --- a/src/arch/sparc/isa_traits.hh +++ b/src/arch/sparc/isa_traits.hh @@ -96,15 +96,6 @@ namespace SparcISA StaticInstPtr decodeInst(ExtMachInst); #if FULL_SYSTEM - ////////// Interrupt Stuff /////////// - enum InterruptLevels - { - INTLEVEL_MIN = 1, - INTLEVEL_MAX = 15, - - NumInterruptLevels = INTLEVEL_MAX - INTLEVEL_MIN - }; - // I don't know what it's for, so I don't // know what SPARC's value should be // For loading... XXX This maybe could be USegEnd?? --ali diff --git a/src/arch/sparc/miscregfile.cc b/src/arch/sparc/miscregfile.cc index 9c703d917..422bc2fbe 100644 --- a/src/arch/sparc/miscregfile.cc +++ b/src/arch/sparc/miscregfile.cc @@ -215,7 +215,7 @@ MiscReg MiscRegFile::readReg(int miscReg) case MISCREG_HTSTATE: return htstate[tl-1]; case MISCREG_HINTP: - panic("HINTP not implemented\n"); + return hintp; case MISCREG_HTBA: return htba; case MISCREG_HVER: @@ -322,13 +322,13 @@ MiscReg MiscRegFile::readRegWithEffect(int miscReg, ThreadContext * tc) // I'm not sure why legion ignores the lowest two bits, but we'll go // with it // change from curCycle() to instCount() until we're done with legion - DPRINTFN("Instruction Count when TICK read: %#X stick=%#X\n", + DPRINTF(Timer, "Instruction Count when TICK read: %#X stick=%#X\n", tc->getCpuPtr()->instCount(), stick); - return mbits(tc->getCpuPtr()->instCount() + (int32_t)stick,62,2) | + return mbits(tc->getCpuPtr()->instCount() + (int64_t)stick,62,2) | mbits(tick,63,63); case MISCREG_FPRS: - warn("FPRS register read and FPU stuff not really implemented\n"); - return fprs; + // in legion if fp is enabled du and dl are set + return fprs | 0x3; case MISCREG_PCR: case MISCREG_PIC: panic("Performance Instrumentation not impl\n"); @@ -386,7 +386,6 @@ void MiscRegFile::setReg(int miscReg, const MiscReg &val) asi = val; break; case MISCREG_FPRS: - warn("FPU not really implemented writing %#X to FPRS\n", val); fprs = val; break; case MISCREG_TICK: @@ -400,7 +399,7 @@ void MiscRegFile::setReg(int miscReg, const MiscReg &val) gsr = val; break; case MISCREG_SOFTINT: - softint |= val; + softint = val; break; case MISCREG_TICK_CMPR: tick_cmpr = val; @@ -470,7 +469,7 @@ void MiscRegFile::setReg(int miscReg, const MiscReg &val) htstate[tl-1] = val; break; case MISCREG_HINTP: - panic("HINTP not implemented\n"); + hintp = val; case MISCREG_HTBA: htba = val; break; @@ -609,6 +608,8 @@ void MiscRegFile::setReg(int miscReg, const MiscReg &val) void MiscRegFile::setRegWithEffect(int miscReg, const MiscReg &val, ThreadContext * tc) { + MiscReg new_val = val; + switch (miscReg) { case MISCREG_STICK: case MISCREG_TICK: @@ -616,7 +617,7 @@ void MiscRegFile::setRegWithEffect(int miscReg, // use stick for offset and tick for holding intrrupt bit stick = mbits(val,62,0) - tc->getCpuPtr()->instCount(); tick = mbits(val,63,63); - DPRINTFN("Writing TICK=%#X\n", val); + DPRINTF(Timer, "Writing TICK=%#X\n", val); break; case MISCREG_FPRS: //Configure the fpu based on the fprs @@ -631,13 +632,16 @@ void MiscRegFile::setRegWithEffect(int miscReg, tl = val; return; case MISCREG_CWP: - tc->changeRegFileContext(CONTEXT_CWP, val); + new_val = val > NWindows ? NWindows - 1 : val; + tc->changeRegFileContext(CONTEXT_CWP, new_val); break; case MISCREG_GL: tc->changeRegFileContext(CONTEXT_GLOBALS, val); break; case MISCREG_PIL: case MISCREG_SOFTINT: + case MISCREG_SOFTINT_SET: + case MISCREG_SOFTINT_CLR: case MISCREG_TICK_CMPR: case MISCREG_STICK_CMPR: case MISCREG_HINTP: @@ -666,7 +670,7 @@ void MiscRegFile::setRegWithEffect(int miscReg, panic("Accessing Fullsystem register %s to %#x in SE mode\n", getMiscRegName(miscReg), val); #endif } - setReg(miscReg, val); + setReg(miscReg, new_val); } void MiscRegFile::serialize(std::ostream & os) diff --git a/src/arch/sparc/miscregfile.hh b/src/arch/sparc/miscregfile.hh index 8ede2421a..66c9f17df 100644 --- a/src/arch/sparc/miscregfile.hh +++ b/src/arch/sparc/miscregfile.hh @@ -142,24 +142,26 @@ namespace SparcISA MISCREG_NUMMISCREGS }; - enum HPStateFields { - id = 0x800, // this impl. dependent (id) field must always be '1' for T1000 - ibe = 0x400, - red = 0x20, - hpriv = 0x4, - tlz = 0x1 + struct HPSTATE { + const static uint64_t id = 0x800; // this impl. dependent (id) field m + const static uint64_t ibe = 0x400; + const static uint64_t red = 0x20; + const static uint64_t hpriv = 0x4; + const static uint64_t tlz = 0x1; }; - enum PStateFields { - cle = 0x200, - tle = 0x100, - mm = 0xC0, - pef = 0x10, - am = 0x8, - priv = 0x4, - ie = 0x2 + + struct PSTATE { + const static int cle = 0x200; + const static int tle = 0x100; + const static int mm = 0xC0; + const static int pef = 0x10; + const static int am = 0x8; + const static int priv = 0x4; + const static int ie = 0x2; }; + const int NumMiscArchRegs = MISCREG_NUMMISCREGS; const int NumMiscRegs = MISCREG_NUMMISCREGS; diff --git a/src/arch/sparc/regfile.cc b/src/arch/sparc/regfile.cc index 691d0a0f1..4be411d17 100644 --- a/src/arch/sparc/regfile.cc +++ b/src/arch/sparc/regfile.cc @@ -255,10 +255,10 @@ int SparcISA::InterruptLevel(uint64_t softint) if (softint & 0x10000 || softint & 0x1) return 14; - int level = 14; - while (level >= 0 && !(1 << (level + 1) & softint)) + int level = 15; + while (level > 0 && !(1 << level & softint)) level--; - if (1 << (level + 1) & softint) + if (1 << level & softint) return level; return 0; } diff --git a/src/arch/sparc/tlb.cc b/src/arch/sparc/tlb.cc index 40542a9a6..1a2ec6eac 100644 --- a/src/arch/sparc/tlb.cc +++ b/src/arch/sparc/tlb.cc @@ -81,21 +81,45 @@ TLB::insert(Addr va, int partition_id, int context_id, bool real, MapIter i; TlbEntry *new_entry = NULL; - TlbRange tr; +// TlbRange tr; int x; cacheValid = false; - tr.va = va; + va &= ~(PTE.size()-1); + /* tr.va = va; tr.size = PTE.size() - 1; tr.contextId = context_id; tr.partitionId = partition_id; tr.real = real; - +*/ DPRINTF(TLB, "TLB: Inserting TLB Entry; va=%#x pa=%#x pid=%d cid=%d r=%d entryid=%d\n", va, PTE.paddr(), partition_id, context_id, (int)real, entry); // Demap any entry that conflicts + for (x = 0; x < size; x++) { + if (tlb[x].range.real == real && + tlb[x].range.partitionId == partition_id && + tlb[x].range.va < va + PTE.size() - 1 && + tlb[x].range.va + tlb[x].range.size >= va && + (real || tlb[x].range.contextId == context_id )) + { + if (tlb[x].valid) { + freeList.push_front(&tlb[x]); + DPRINTF(TLB, "TLB: Conflicting entry %#X , deleting it\n", x); + + tlb[x].valid = false; + if (tlb[x].used) { + tlb[x].used = false; + usedEntries--; + } + lookupTable.erase(tlb[x].range); + } + } + } + + +/* i = lookupTable.find(tr); if (i != lookupTable.end()) { i->second->valid = false; @@ -108,7 +132,7 @@ TLB::insert(Addr va, int partition_id, int context_id, bool real, i->second); lookupTable.erase(i); } - +*/ if (entry != -1) { assert(entry < size && entry >= 0); @@ -127,7 +151,6 @@ TLB::insert(Addr va, int partition_id, int context_id, bool real, } while (tlb[x].pte.locked()); lastReplaced = x; new_entry = &tlb[x]; - lookupTable.erase(new_entry->range); } /* for (x = 0; x < size; x++) { @@ -142,10 +165,15 @@ insertAllLocked: // Update the last ently if their all locked if (!new_entry) { new_entry = &tlb[size-1]; - lookupTable.erase(new_entry->range); } freeList.remove(new_entry); + if (new_entry->valid && new_entry->used) + usedEntries--; + + lookupTable.erase(new_entry->range); + + DPRINTF(TLB, "Using entry: %#X\n", new_entry); assert(PTE.valid()); @@ -315,10 +343,12 @@ TLB::invalidateAll() cacheValid = false; freeList.clear(); + lookupTable.clear(); for (x = 0; x < size; x++) { if (tlb[x].valid == true) freeList.push_back(&tlb[x]); tlb[x].valid = false; + tlb[x].used = false; } usedEntries = 0; } @@ -385,6 +415,9 @@ TLB::writeSfsr(ThreadContext *tc, int reg, bool write, ContextType ct, void TLB::writeTagAccess(ThreadContext *tc, int reg, Addr va, int context) { + DPRINTF(TLB, "TLB: Writing Tag Access: va: %#X ctx: %#X value: %#X\n", + va, context, mbits(va, 63,13) | mbits(context,12,0)); + tc->setMiscRegWithEffect(reg, mbits(va, 63,13) | mbits(context,12,0)); } @@ -507,8 +540,7 @@ ITB::translate(RequestPtr &req, ThreadContext *tc) } if (e == NULL || !e->valid) { - tc->setMiscReg(MISCREG_MMU_ITLB_TAG_ACCESS, - vaddr & ~BytesInPageMask | context); + writeTagAccess(tc, vaddr, context); if (real) return new InstructionRealTranslationMiss; else @@ -581,7 +613,7 @@ DTB::translate(RequestPtr &req, ThreadContext *tc, bool write) int part_id = bits(tlbdata,15,8); int tl = bits(tlbdata,18,16); int pri_context = bits(tlbdata,47,32); - int sec_context = bits(tlbdata,47,32); + int sec_context = bits(tlbdata,63,48); bool real = false; ContextType ct = Primary; @@ -602,52 +634,42 @@ DTB::translate(RequestPtr &req, ThreadContext *tc, bool write) ct = Primary; context = pri_context; } - } else if (!hpriv && !red) { - if (tl > 0 || AsiIsNucleus(asi)) { - ct = Nucleus; - context = 0; - } else if (AsiIsSecondary(asi)) { - ct = Secondary; - context = sec_context; - } else { - context = pri_context; - ct = Primary; //??? - } - + } else { // We need to check for priv level/asi priv - if (!priv && !AsiIsUnPriv(asi)) { + if (!priv && !hpriv && !AsiIsUnPriv(asi)) { // It appears that context should be Nucleus in these cases? writeSfr(tc, vaddr, write, Nucleus, false, IllegalAsi, asi); return new PrivilegedAction; } - if (priv && AsiIsHPriv(asi)) { + + if (!hpriv && AsiIsHPriv(asi)) { writeSfr(tc, vaddr, write, Nucleus, false, IllegalAsi, asi); return new DataAccessException; } - } else if (hpriv) { - if (asi == ASI_P) { + if (AsiIsPrimary(asi)) { + context = pri_context; + ct = Primary; + } else if (AsiIsSecondary(asi)) { + context = sec_context; + ct = Secondary; + } else if (AsiIsNucleus(asi)) { + ct = Nucleus; + context = 0; + } else { // ???? ct = Primary; context = pri_context; - goto continueDtbFlow; } } - if (!implicit) { + if (!implicit && asi != ASI_P && asi != ASI_S) { if (AsiIsLittle(asi)) panic("Little Endian ASIs not supported\n"); if (AsiIsBlock(asi)) panic("Block ASIs not supported\n"); if (AsiIsNoFault(asi)) panic("No Fault ASIs not supported\n"); - if (write && asi == ASI_LDTX_P) - // block init store (like write hint64) - goto continueDtbFlow; - if (!write && asi == ASI_QUAD_LDD) - goto continueDtbFlow; - - if (AsiIsTwin(asi)) - panic("Twin ASIs not supported\n"); + if (AsiIsPartialStore(asi)) panic("Partial Store ASIs not supported\n"); if (AsiIsInterrupt(asi)) @@ -662,11 +684,11 @@ DTB::translate(RequestPtr &req, ThreadContext *tc, bool write) if (AsiIsSparcError(asi)) goto handleSparcErrorRegAccess; - if (!AsiIsReal(asi) && !AsiIsNucleus(asi)) + if (!AsiIsReal(asi) && !AsiIsNucleus(asi) && !AsiIsAsIfUser(asi) && + !AsiIsTwin(asi)) panic("Accessing ASI %#X. Should we?\n", asi); } -continueDtbFlow: // If the asi is unaligned trap if (vaddr & size-1) { writeSfr(tc, vaddr, false, ct, false, OtherFault, asi); @@ -682,7 +704,7 @@ continueDtbFlow: } - if ((!lsu_dm && !hpriv) || AsiIsReal(asi)) { + if ((!lsu_dm && !hpriv && !red) || AsiIsReal(asi)) { real = true; context = 0; }; @@ -695,8 +717,7 @@ continueDtbFlow: e = lookup(vaddr, part_id, real, context); if (e == NULL || !e->valid) { - tc->setMiscReg(MISCREG_MMU_DTLB_TAG_ACCESS, - vaddr & ~BytesInPageMask | context); + writeTagAccess(tc, vaddr, context); DPRINTF(TLB, "TLB: DTB Failed to find matching TLB entry\n"); if (real) return new DataRealTranslationMiss; @@ -868,7 +889,7 @@ DTB::doMmuRegRead(ThreadContext *tc, Packet *pkt) break; case ASI_SPARC_ERROR_STATUS_REG: warn("returning 0 for SPARC ERROR regsiter read\n"); - pkt->set(0); + pkt->set((uint64_t)0); break; case ASI_HYP_SCRATCHPAD: case ASI_SCRATCHPAD: @@ -880,6 +901,9 @@ DTB::doMmuRegRead(ThreadContext *tc, Packet *pkt) temp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS); pkt->set(bits(temp,63,22) | bits(temp,12,0) << 48); break; + case 0x18: + pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_SFSR)); + break; case 0x30: pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS)); break; @@ -893,6 +917,12 @@ DTB::doMmuRegRead(ThreadContext *tc, Packet *pkt) temp = tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS); pkt->set(bits(temp,63,22) | bits(temp,12,0) << 48); break; + case 0x18: + pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_SFSR)); + break; + case 0x20: + pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_SFAR)); + break; case 0x30: pkt->set(tc->readMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS)); break; @@ -929,10 +959,40 @@ DTB::doMmuRegRead(ThreadContext *tc, Packet *pkt) data = mbits(tsbtemp,63,13); if (bits(tsbtemp,12,12)) data |= ULL(1) << (13+bits(tsbtemp,3,0)); + data |= temp >> (9 + bits(cnftemp,10,8) * 3) & + mbits((uint64_t)-1ll,12+bits(tsbtemp,3,0), 4); + pkt->set(data); + break; + case ASI_IMMU_TSB_PS0_PTR_REG: + temp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS); + if (bits(temp,12,0) == 0) { + tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS0); + cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_CONFIG); + } else { + tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS0); + cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_CONFIG); + } + data = mbits(tsbtemp,63,13); data |= temp >> (9 + bits(cnftemp,2,0) * 3) & mbits((uint64_t)-1ll,12+bits(tsbtemp,3,0), 4); pkt->set(data); break; + case ASI_IMMU_TSB_PS1_PTR_REG: + temp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS); + if (bits(temp,12,0) == 0) { + tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_TSB_PS1); + cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_C0_CONFIG); + } else { + tsbtemp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS1); + cnftemp = tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_CONFIG); + } + data = mbits(tsbtemp,63,13); + if (bits(tsbtemp,12,12)) + data |= ULL(1) << (13+bits(tsbtemp,3,0)); + data |= temp >> (9 + bits(cnftemp,10,8) * 3) & + mbits((uint64_t)-1ll,12+bits(tsbtemp,3,0), 4); + pkt->set(data); + break; default: doMmuReadError: @@ -1044,7 +1104,11 @@ DTB::doMmuRegWrite(ThreadContext *tc, Packet *pkt) break; case ASI_IMMU: switch (va) { + case 0x18: + tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_SFSR, data); + break; case 0x30: + sext<59>(bits(data, 59,0)); tc->setMiscRegWithEffect(MISCREG_MMU_ITLB_TAG_ACCESS, data); break; default: @@ -1115,7 +1179,11 @@ DTB::doMmuRegWrite(ThreadContext *tc, Packet *pkt) break; case ASI_DMMU: switch (va) { + case 0x18: + tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_SFSR, data); + break; case 0x30: + sext<59>(bits(data, 59,0)); tc->setMiscRegWithEffect(MISCREG_MMU_DTLB_TAG_ACCESS, data); break; case 0x80: diff --git a/src/arch/sparc/ua2005.cc b/src/arch/sparc/ua2005.cc index 0db5f6acc..00a44275c 100644 --- a/src/arch/sparc/ua2005.cc +++ b/src/arch/sparc/ua2005.cc @@ -24,8 +24,6 @@ * 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 */ #include "arch/sparc/miscregfile.hh" @@ -38,103 +36,107 @@ using namespace SparcISA; void MiscRegFile::setFSRegWithEffect(int miscReg, const MiscReg &val, - ThreadContext *tc) + ThreadContext *tc) { int64_t time; switch (miscReg) { /* Full system only ASRs */ - case MISCREG_SOFTINT: - // Check if we are going to interrupt because of something - setReg(miscReg, val); - tc->getCpuPtr()->checkInterrupts = true; - warn("Writing to softint not really supported, writing: %#x\n", val); - break; - - case MISCREG_SOFTINT_CLR: - return setRegWithEffect(miscReg, ~val & softint, tc); - case MISCREG_SOFTINT_SET: - return setRegWithEffect(miscReg, val | softint, tc); - - case MISCREG_TICK_CMPR: - if (tickCompare == NULL) - tickCompare = new TickCompareEvent(this, tc); - setReg(miscReg, val); - if ((tick_cmpr & mask(63)) && tickCompare->scheduled()) - tickCompare->deschedule(); - time = (tick_cmpr & mask(63)) - (tick & mask(63)); - if (!(tick_cmpr & ~mask(63)) && time > 0) - tickCompare->schedule(time * tc->getCpuPtr()->cycles(1)); - warn ("writing to TICK compare register %#X\n", val); - break; - - case MISCREG_STICK_CMPR: - if (sTickCompare == NULL) - sTickCompare = new STickCompareEvent(this, tc); - setReg(miscReg, val); - if ((stick_cmpr & mask(63)) && sTickCompare->scheduled()) - sTickCompare->deschedule(); - time = (stick_cmpr & mask(63)) - (stick & mask(63)); - if (!(stick_cmpr & ~mask(63)) && time > 0) - sTickCompare->schedule(time * tc->getCpuPtr()->cycles(1)); - warn ("writing to sTICK compare register value %#X\n", val); - break; - - case MISCREG_PSTATE: - if (val & ie && !(pstate & ie)) { - tc->getCpuPtr()->checkInterrupts = true; - } - setReg(miscReg, val); - - case MISCREG_PIL: - if (val < pil) { - tc->getCpuPtr()->checkInterrupts = true; - } - setReg(miscReg, val); - break; - - case MISCREG_HVER: - panic("Shouldn't be writing HVER\n"); - - case MISCREG_HTBA: - // clear lower 7 bits on writes. - setReg(miscReg, val & ULL(~0x7FFF)); - break; - - case MISCREG_QUEUE_CPU_MONDO_HEAD: - case MISCREG_QUEUE_CPU_MONDO_TAIL: - case MISCREG_QUEUE_DEV_MONDO_HEAD: - case MISCREG_QUEUE_DEV_MONDO_TAIL: - case MISCREG_QUEUE_RES_ERROR_HEAD: - case MISCREG_QUEUE_RES_ERROR_TAIL: - case MISCREG_QUEUE_NRES_ERROR_HEAD: - case MISCREG_QUEUE_NRES_ERROR_TAIL: - setReg(miscReg, val); - tc->getCpuPtr()->checkInterrupts = true; - break; - - case MISCREG_HSTICK_CMPR: - if (hSTickCompare == NULL) - hSTickCompare = new HSTickCompareEvent(this, tc); - setReg(miscReg, val); - if ((hstick_cmpr & mask(63)) && hSTickCompare->scheduled()) - hSTickCompare->deschedule(); - time = (hstick_cmpr & mask(63)) - (stick & mask(63)); - if (!(hstick_cmpr & ~mask(63)) && time > 0) - hSTickCompare->schedule(time * tc->getCpuPtr()->cycles(1)); - warn ("writing to hsTICK compare register value %#X\n", val); - break; - - case MISCREG_HPSTATE: - // T1000 spec says impl. dependent val must always be 1 - setReg(miscReg, val | id); - break; - case MISCREG_HTSTATE: - case MISCREG_STRAND_STS_REG: - setReg(miscReg, val); - break; - - default: - panic("Invalid write to FS misc register %s\n", getMiscRegName(miscReg)); + case MISCREG_SOFTINT: + setReg(miscReg, val);; + break; + + case MISCREG_SOFTINT_CLR: + return setRegWithEffect(MISCREG_SOFTINT, ~val & softint, tc); + case MISCREG_SOFTINT_SET: + tc->getCpuPtr()->checkInterrupts = true; + tc->getCpuPtr()->post_interrupt(soft_interrupt); + return setRegWithEffect(MISCREG_SOFTINT, val | softint, tc); + + case MISCREG_TICK_CMPR: + if (tickCompare == NULL) + tickCompare = new TickCompareEvent(this, tc); + setReg(miscReg, val); + if ((tick_cmpr & mask(63)) && tickCompare->scheduled()) + tickCompare->deschedule(); + time = (tick_cmpr & mask(63)) - (tick & mask(63)); + if (!(tick_cmpr & ~mask(63)) && time > 0) + tickCompare->schedule(time * tc->getCpuPtr()->cycles(1)); + panic("writing to TICK compare register %#X\n", val); + break; + + case MISCREG_STICK_CMPR: + if (sTickCompare == NULL) + sTickCompare = new STickCompareEvent(this, tc); + setReg(miscReg, val); + if ((stick_cmpr & ~mask(63)) && sTickCompare->scheduled()) + sTickCompare->deschedule(); + time = ((int64_t)(stick_cmpr & mask(63)) - (int64_t)stick) - + tc->getCpuPtr()->instCount(); + if (!(stick_cmpr & ~mask(63)) && time > 0) + sTickCompare->schedule(time * tc->getCpuPtr()->cycles(1) + curTick); + DPRINTF(Timer, "writing to sTICK compare register value %#X\n", val); + break; + + case MISCREG_PSTATE: + if (val & PSTATE::ie && !(pstate & PSTATE::ie)) { + tc->getCpuPtr()->checkInterrupts = true; + } + setReg(miscReg, val); + + case MISCREG_PIL: + if (val < pil) { + tc->getCpuPtr()->checkInterrupts = true; + } + setReg(miscReg, val); + break; + + case MISCREG_HVER: + panic("Shouldn't be writing HVER\n"); + + case MISCREG_HINTP: + setReg(miscReg, val); + + case MISCREG_HTBA: + // clear lower 7 bits on writes. + setReg(miscReg, val & ULL(~0x7FFF)); + break; + + case MISCREG_QUEUE_CPU_MONDO_HEAD: + case MISCREG_QUEUE_CPU_MONDO_TAIL: + case MISCREG_QUEUE_DEV_MONDO_HEAD: + case MISCREG_QUEUE_DEV_MONDO_TAIL: + case MISCREG_QUEUE_RES_ERROR_HEAD: + case MISCREG_QUEUE_RES_ERROR_TAIL: + case MISCREG_QUEUE_NRES_ERROR_HEAD: + case MISCREG_QUEUE_NRES_ERROR_TAIL: + setReg(miscReg, val); + tc->getCpuPtr()->checkInterrupts = true; + break; + + case MISCREG_HSTICK_CMPR: + if (hSTickCompare == NULL) + hSTickCompare = new HSTickCompareEvent(this, tc); + setReg(miscReg, val); + if ((hstick_cmpr & ~mask(63)) && hSTickCompare->scheduled()) + hSTickCompare->deschedule(); + time = ((int64_t)(hstick_cmpr & mask(63)) - (int64_t)stick) - + tc->getCpuPtr()->instCount(); + if (!(hstick_cmpr & ~mask(63)) && time > 0) + hSTickCompare->schedule(curTick + time * tc->getCpuPtr()->cycles(1)); + DPRINTF(Timer, "writing to hsTICK compare register value %#X\n", val); + break; + + case MISCREG_HPSTATE: + // T1000 spec says impl. dependent val must always be 1 + setReg(miscReg, val | HPSTATE::id); + break; + case MISCREG_HTSTATE: + case MISCREG_STRAND_STS_REG: + setReg(miscReg, val); + break; + + default: + panic("Invalid write to FS misc register %s\n", getMiscRegName(miscReg)); } } @@ -142,7 +144,7 @@ MiscReg MiscRegFile::readFSRegWithEffect(int miscReg, ThreadContext * tc) { switch (miscReg) { - /* Privileged registers. */ + /* Privileged registers. */ case MISCREG_QUEUE_CPU_MONDO_HEAD: case MISCREG_QUEUE_CPU_MONDO_TAIL: case MISCREG_QUEUE_DEV_MONDO_HEAD: @@ -172,12 +174,12 @@ MiscRegFile::readFSRegWithEffect(int miscReg, ThreadContext * tc) } } /* - In Niagra STICK==TICK so this isn't needed - case MISCREG_STICK: - SparcSystem *sys; - sys = dynamic_cast<SparcSystem*>(tc->getSystemPtr()); - assert(sys != NULL); - return curTick/Clock::Int::ns - sys->sysTick | (stick & ~(mask(63))); + In Niagra STICK==TICK so this isn't needed + case MISCREG_STICK: + SparcSystem *sys; + sys = dynamic_cast<SparcSystem*>(tc->getSystemPtr()); + assert(sys != NULL); + return curTick/Clock::Int::ns - sys->sysTick | (stick & ~(mask(63))); */ @@ -191,12 +193,47 @@ MiscRegFile::processTickCompare(ThreadContext *tc) void MiscRegFile::processSTickCompare(ThreadContext *tc) { - panic("tick compare not implemented\n"); + // since our microcode instructions take two cycles we need to check if + // we're actually at the correct cycle or we need to wait a little while + // more + int ticks; + ticks = ((int64_t)(stick_cmpr & mask(63)) - (int64_t)stick) - + tc->getCpuPtr()->instCount(); + assert(ticks >= 0 && "stick compare missed interrupt cycle"); + + if (ticks == 0) { + DPRINTF(Timer, "STick compare cycle reached at %#x\n", + (stick_cmpr & mask(63))); + if (!(tc->readMiscReg(MISCREG_STICK_CMPR) & (ULL(1) << 63))) { + tc->getCpuPtr()->post_interrupt(soft_interrupt); + tc->getCpuPtr()->checkInterrupts = true; + setRegWithEffect(MISCREG_SOFTINT, softint | (ULL(1) << 16), tc); + } + } else + sTickCompare->schedule(ticks * tc->getCpuPtr()->cycles(1) + curTick); } void MiscRegFile::processHSTickCompare(ThreadContext *tc) { - panic("tick compare not implemented\n"); + // since our microcode instructions take two cycles we need to check if + // we're actually at the correct cycle or we need to wait a little while + // more + int ticks; + ticks = ((int64_t)(hstick_cmpr & mask(63)) - (int64_t)stick) - + tc->getCpuPtr()->instCount(); + assert(ticks >= 0 && "hstick compare missed interrupt cycle"); + + if (ticks == 0) { + DPRINTF(Timer, "HSTick compare cycle reached at %#x\n", + (stick_cmpr & mask(63))); + if (!(tc->readMiscReg(MISCREG_HSTICK_CMPR) & (ULL(1) << 63))) { + setRegWithEffect(MISCREG_HINTP, 1, tc); + tc->getCpuPtr()->post_interrupt(hstick_match); + tc->getCpuPtr()->checkInterrupts = true; + } + // Need to do something to cause interrupt to happen here !!! @todo + } else + sTickCompare->schedule(ticks * tc->getCpuPtr()->cycles(1) + curTick); } |