diff options
41 files changed, 1086 insertions, 348 deletions
diff --git a/configs/common/FSConfig.py b/configs/common/FSConfig.py index 72742775f..c341b762a 100644 --- a/configs/common/FSConfig.py +++ b/configs/common/FSConfig.py @@ -1,4 +1,4 @@ -# Copyright (c) 2006 The Regents of The University of Michigan +# Copyright (c) 2006-2007 The Regents of The University of Michigan # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -38,6 +38,14 @@ class CowIdeDisk(IdeDisk): def childImage(self, ci): self.image.child.image_file = ci +class CowMmDisk(MmDisk): + image = CowDiskImage(child=RawDiskImage(read_only=True), + read_only=False) + + def childImage(self, ci): + self.image.child.image_file = ci + + class BaseTsunami(Tsunami): ethernet = NSGigE(configdata=NSGigEPciData(), pci_bus=0, pci_dev=1, pci_func=0) @@ -100,8 +108,9 @@ def makeSparcSystem(mem_mode, mdesc = None): self.hypervisor_desc.port = self.membus.port self.partition_desc.port = self.membus.port self.intrctrl = IntrControl() - self.mem_mode = mem_mode - + self.disk0 = CowMmDisk() + self.disk0.childImage(disk('disk.s10hw2')) + self.disk0.pio = self.iobus.port self.reset_bin = binary('reset.bin') self.hypervisor_bin = binary('q.bin') self.openboot_bin = binary('openboot.bin') diff --git a/src/arch/alpha/interrupts.hh b/src/arch/alpha/interrupts.hh index 388ccacde..a522dec6c 100644 --- a/src/arch/alpha/interrupts.hh +++ b/src/arch/alpha/interrupts.hh @@ -52,6 +52,11 @@ namespace AlphaISA newInfoSet = false; } + void post(int int_type) + { + // sparc only + } + void post(int int_num, int index) { DPRINTF(Interrupt, "Interrupt %d:%d posted\n", int_num, index); diff --git a/src/arch/alpha/pagetable.hh b/src/arch/alpha/pagetable.hh index 7ec4a6a75..c7e1c8923 100644 --- a/src/arch/alpha/pagetable.hh +++ b/src/arch/alpha/pagetable.hh @@ -80,7 +80,7 @@ namespace AlphaISA { bool _kre() const { return (entry >> 8) & 0x1; } bool _nomb() const { return (entry >> 7) & 0x1; } int _gh() const { return (entry >> 5) & 0x3; } - bool _asm() const { return (entry >> 4) & 0x1; } + bool _asm_() const { return (entry >> 4) & 0x1; } bool _foe() const { return (entry >> 3) & 0x1; } bool _fow() const { return (entry >> 2) & 0x1; } bool _for() const { return (entry >> 1) & 0x1; } 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); } diff --git a/src/base/loader/elf_object.cc b/src/base/loader/elf_object.cc index 7339507f6..d59affe85 100644 --- a/src/base/loader/elf_object.cc +++ b/src/base/loader/elf_object.cc @@ -340,3 +340,41 @@ ElfObject::loadLocalSymbols(SymbolTable *symtab, Addr addrMask) { return loadSomeSymbols(symtab, STB_LOCAL); } + +bool +ElfObject::isDynamic() +{ + Elf *elf; + int sec_idx = 1; // there is a 0 but it is nothing, go figure + Elf_Scn *section; + GElf_Shdr shdr; + + GElf_Ehdr ehdr; + + // check that header matches library version + if (elf_version(EV_CURRENT) == EV_NONE) + panic("wrong elf version number!"); + + // get a pointer to elf structure + elf = elf_memory((char*)fileData,len); + assert(elf != NULL); + + // Check that we actually have a elf file + if (gelf_getehdr(elf, &ehdr) ==0) { + panic("Not ELF, shouldn't be here"); + } + + // Get the first section + section = elf_getscn(elf, sec_idx); + + // While there are no more sections + while (section != NULL) { + gelf_getshdr(section, &shdr); + if (!strcmp(".interp", elf_strptr(elf, ehdr.e_shstrndx, shdr.sh_name))) + return true; + section = elf_getscn(elf, ++sec_idx); + } // while sections + return false; +} + + diff --git a/src/base/loader/elf_object.hh b/src/base/loader/elf_object.hh index fb728b3c5..d909140f3 100644 --- a/src/base/loader/elf_object.hh +++ b/src/base/loader/elf_object.hh @@ -58,6 +58,8 @@ class ElfObject : public ObjectFile virtual bool loadLocalSymbols(SymbolTable *symtab, Addr addrMask = std::numeric_limits<Addr>::max()); + virtual bool isDynamic(); + static ObjectFile *tryFile(const std::string &fname, int fd, size_t len, uint8_t *data); Addr programHeaderTable() {return _programHeaderTable;} diff --git a/src/base/loader/object_file.cc b/src/base/loader/object_file.cc index ad2cd34ba..da5aa9552 100644 --- a/src/base/loader/object_file.cc +++ b/src/base/loader/object_file.cc @@ -150,3 +150,9 @@ createObjectFile(const string &fname, bool raw) munmap(fileData, len); return NULL; } + +bool +ObjectFile::isDynamic() +{ + return false; +} diff --git a/src/base/loader/object_file.hh b/src/base/loader/object_file.hh index 6e98332c5..18e6482be 100644 --- a/src/base/loader/object_file.hh +++ b/src/base/loader/object_file.hh @@ -83,6 +83,8 @@ class ObjectFile virtual bool loadLocalSymbols(SymbolTable *symtab, Addr addrMask = std::numeric_limits<Addr>::max()) = 0; + virtual bool isDynamic(); + Arch getArch() const { return arch; } OpSys getOpSys() const { return opSys; } diff --git a/src/base/loader/raw_object.cc b/src/base/loader/raw_object.cc index 2a52b0d6e..d002d9005 100644 --- a/src/base/loader/raw_object.cc +++ b/src/base/loader/raw_object.cc @@ -63,19 +63,19 @@ RawObject::RawObject(const std::string &_filename, int _fd, size_t _len, bool RawObject::loadGlobalSymbols(SymbolTable *symtab, Addr addrMask) { - int fnameStart = filename.rfind('/',filename.size()) + 1; +/* int fnameStart = filename.rfind('/',filename.size()) + 1; int extStart = filename.rfind('.',filename.size()); symtab->insert(text.baseAddr & addrMask, filename.substr(fnameStart, - extStart-fnameStart) + "_start"); + extStart-fnameStart) + "_start");*/ return true; } bool RawObject::loadLocalSymbols(SymbolTable *symtab, Addr addrMask) { - int fnameStart = filename.rfind('/',filename.size()) + 1; +/* int fnameStart = filename.rfind('/',filename.size()) + 1; int extStart = filename.rfind('.',filename.size()); symtab->insert(text.baseAddr & addrMask, filename.substr(fnameStart, - extStart-fnameStart) + "_start"); + extStart-fnameStart) + "_start");*/ return true; } diff --git a/src/cpu/base.cc b/src/cpu/base.cc index 31604ad58..b03bc19a5 100644 --- a/src/cpu/base.cc +++ b/src/cpu/base.cc @@ -363,6 +363,12 @@ BaseCPU::ProfileEvent::process() } void +BaseCPU::post_interrupt(int int_type) +{ + interrupts.post(int_type); +} + +void BaseCPU::post_interrupt(int int_num, int index) { checkInterrupts = true; diff --git a/src/cpu/base.hh b/src/cpu/base.hh index 8c6b079da..89c7d9dda 100644 --- a/src/cpu/base.hh +++ b/src/cpu/base.hh @@ -102,6 +102,7 @@ class BaseCPU : public MemObject TheISA::Interrupts interrupts; public: + virtual void post_interrupt(int int_type); virtual void post_interrupt(int int_num, int index); virtual void clear_interrupt(int int_num, int index); virtual void clear_interrupts(); diff --git a/src/cpu/cpuevent.hh b/src/cpu/cpuevent.hh index 3339f8252..c973621c0 100644 --- a/src/cpu/cpuevent.hh +++ b/src/cpu/cpuevent.hh @@ -36,12 +36,14 @@ class ThreadContext; -/** This class creates a global list of events that need a pointer to a - * thread context. When a switchover takes place the events can be migrated - * to the new thread context, otherwise you could have a wake timer interrupt - * go off on a switched out cpu or other unfortunate events. This object MUST be - * dynamically allocated to avoid it being deleted after a cpu switch happens. - * */ +/** + * This class creates a global list of events that need a pointer to a + * thread context. When a switchover takes place the events can be + * migrated to the new thread context, otherwise you could have a wake + * timer interrupt go off on a switched out cpu or other unfortunate + * events. This object MUST be dynamically allocated to avoid it being + * deleted after a cpu switch happens. + */ class CpuEvent : public Event { protected: @@ -78,8 +80,8 @@ class CpuEventWrapper : public CpuEvent T *object; public: - CpuEventWrapper(T *obj, ThreadContext *_tc, EventQueue *q = &mainEventQueue, - Priority p = Default_Pri) + CpuEventWrapper(T *obj, ThreadContext *_tc, + EventQueue *q = &mainEventQueue, Priority p = Default_Pri) : CpuEvent(q, _tc, p), object(obj) { } void process() { (object->*F)(tc); } diff --git a/src/cpu/exetrace.cc b/src/cpu/exetrace.cc index 378fcd09b..7ebbf455a 100644 --- a/src/cpu/exetrace.cc +++ b/src/cpu/exetrace.cc @@ -59,6 +59,7 @@ using namespace TheISA; #if THE_ISA == SPARC_ISA && FULL_SYSTEM static int diffcount = 0; +static bool wasMicro = false; #endif namespace Trace { @@ -124,6 +125,7 @@ inline void printLevelHeader(ostream & os, int level) void Trace::InstRecord::dump(ostream &outs) { + DPRINTF(Sparc, "Instruction: %#X\n", staticInst->machInst); if (flags[PRINT_REG_DELTA]) { #if THE_ISA == SPARC_ISA @@ -317,6 +319,24 @@ Trace::InstRecord::dump(ostream &outs) bool diffTlb = false; Addr m5Pc, lgnPc; + // We took a trap on a micro-op... + if (wasMicro && !staticInst->isMicroOp()) + { + // let's skip comparing this cycle + while (!compared) + if (shared_data->flags == OWN_M5) { + shared_data->flags = OWN_LEGION; + compared = true; + } + compared = false; + wasMicro = false; + } + + if (staticInst->isLastMicroOp()) + wasMicro = false; + else if (staticInst->isMicroOp()) + wasMicro = true; + if(!staticInst->isMicroOp() || staticInst->isLastMicroOp()) { while (!compared) { @@ -607,29 +627,34 @@ Trace::InstRecord::dump(ostream &outs) << endl;*/ } } - printColumnLabels(outs); - char label[8]; - for (int x = 0; x < 64; x++) { - if (shared_data->itb[x] != ULL(0xFFFFFFFFFFFFFFFF) || - thread->getITBPtr()->TteRead(x) != ULL(0xFFFFFFFFFFFFFFFF)) { - sprintf(label, "I-TLB:%02d", x); - printRegPair(outs, label, thread->getITBPtr()->TteRead(x), shared_data->itb[x]); + if (diffTlb) { + printColumnLabels(outs); + char label[8]; + for (int x = 0; x < 64; x++) { + if (shared_data->itb[x] != ULL(0xFFFFFFFFFFFFFFFF) || + thread->getITBPtr()->TteRead(x) != ULL(0xFFFFFFFFFFFFFFFF)) { + sprintf(label, "I-TLB:%02d", x); + printRegPair(outs, label, thread->getITBPtr()->TteRead(x), + shared_data->itb[x]); + } } - } - for (int x = 0; x < 64; x++) { - if (shared_data->dtb[x] != ULL(0xFFFFFFFFFFFFFFFF) || - thread->getDTBPtr()->TteRead(x) != ULL(0xFFFFFFFFFFFFFFFF)) { - sprintf(label, "D-TLB:%02d", x); - printRegPair(outs, label, thread->getDTBPtr()->TteRead(x), shared_data->dtb[x]); + for (int x = 0; x < 64; x++) { + if (shared_data->dtb[x] != ULL(0xFFFFFFFFFFFFFFFF) || + thread->getDTBPtr()->TteRead(x) != ULL(0xFFFFFFFFFFFFFFFF)) { + sprintf(label, "D-TLB:%02d", x); + printRegPair(outs, label, thread->getDTBPtr()->TteRead(x), + shared_data->dtb[x]); + } } + thread->getITBPtr()->dumpAll(); + thread->getDTBPtr()->dumpAll(); } - thread->getITBPtr()->dumpAll(); - thread->getDTBPtr()->dumpAll(); diffcount++; if (diffcount > 2) fatal("Differences found between Legion and M5\n"); - } + } else + diffcount = 0; compared = true; shared_data->flags = OWN_LEGION; diff --git a/src/cpu/simple/atomic.cc b/src/cpu/simple/atomic.cc index 8db864153..3b3536e44 100644 --- a/src/cpu/simple/atomic.cc +++ b/src/cpu/simple/atomic.cc @@ -497,7 +497,7 @@ AtomicSimpleCPU::tick() // @todo remove me after debugging with legion done if (curStaticInst && (!curStaticInst->isMicroOp() || - curStaticInst->isLastMicroOp())) + curStaticInst->isFirstMicroOp())) instCnt++; if (simulate_stalls) { diff --git a/src/cpu/simple/base.cc b/src/cpu/simple/base.cc index 4e5754bbb..ddccc5a9b 100644 --- a/src/cpu/simple/base.cc +++ b/src/cpu/simple/base.cc @@ -437,6 +437,7 @@ void BaseSimpleCPU::advancePC(Fault fault) { if (fault != NoFault) { + curMacroStaticInst = StaticInst::nullStaticInstPtr; fault->invoke(tc); } else { //If we're at the last micro op for this instruction diff --git a/src/cpu/static_inst.hh b/src/cpu/static_inst.hh index 523cfae40..5928eea76 100644 --- a/src/cpu/static_inst.hh +++ b/src/cpu/static_inst.hh @@ -146,6 +146,7 @@ class StaticInstBase : public RefCounted IsMicroOp, ///< Is a microop IsDelayedCommit, ///< This microop doesn't commit right away IsLastMicroOp, ///< This microop ends a microop sequence + IsFirstMicroOp, ///< This microop begins a microop sequence //This flag doesn't do anything yet IsMicroBranch, ///< This microop branches within the microcode for a macroop @@ -244,6 +245,7 @@ class StaticInstBase : public RefCounted bool isMicroOp() const { return flags[IsMicroOp]; } bool isDelayedCommit() const { return flags[IsDelayedCommit]; } bool isLastMicroOp() const { return flags[IsLastMicroOp]; } + bool isFirstMicroOp() const { return flags[IsFirstMicroOp]; } //This flag doesn't do anything yet bool isMicroBranch() const { return flags[IsMicroBranch]; } //@} diff --git a/src/dev/alpha/tsunami_io.cc b/src/dev/alpha/tsunami_io.cc index 8430856ef..38986b77e 100644 --- a/src/dev/alpha/tsunami_io.cc +++ b/src/dev/alpha/tsunami_io.cc @@ -57,17 +57,13 @@ using namespace std; //Should this be AlphaISA? using namespace TheISA; -TsunamiIO::RTC::RTC(const string &name, Tsunami* t, Tick i) - : _name(name), event(t, i), addr(0) +TsunamiIO::RTC::RTC(const string &n, Tsunami* tsunami, time_t t, Tick i) + : _name(n), event(tsunami, i), addr(0) { memset(clock_data, 0, sizeof(clock_data)); stat_regA = RTCA_32768HZ | RTCA_1024HZ; stat_regB = RTCB_PRDC_IE |RTCB_BIN | RTCB_24HR; -} -void -TsunamiIO::RTC::set_time(time_t t) -{ struct tm tm; gmtime_r(&t, &tm); @@ -428,7 +424,7 @@ TsunamiIO::PITimer::Counter::CounterEvent::description() TsunamiIO::TsunamiIO(Params *p) : BasicPioDevice(p), tsunami(p->tsunami), pitimer(p->name + "pitimer"), - rtc(p->name + ".rtc", p->tsunami, p->frequency) + rtc(p->name + ".rtc", p->tsunami, p->init_time, p->frequency) { pioSize = 0x100; @@ -436,7 +432,6 @@ TsunamiIO::TsunamiIO(Params *p) tsunami->io = this; timerData = 0; - rtc.set_time(p->init_time == 0 ? time(NULL) : p->init_time); picr = 0; picInterrupting = false; } diff --git a/src/dev/alpha/tsunami_io.hh b/src/dev/alpha/tsunami_io.hh index 54acefc25..b0c368eb8 100644 --- a/src/dev/alpha/tsunami_io.hh +++ b/src/dev/alpha/tsunami_io.hh @@ -110,10 +110,7 @@ class TsunamiIO : public BasicPioDevice uint8_t stat_regB; public: - RTC(const std::string &name, Tsunami* t, Tick i); - - /** Set the initial RTC time/date */ - void set_time(time_t t); + RTC(const std::string &name, Tsunami* tsunami, time_t t, Tick i); /** RTC address port: write address of RTC RAM data to access */ void writeAddr(const uint8_t data); diff --git a/src/dev/sparc/SConscript b/src/dev/sparc/SConscript index c37294f0c..44b082b68 100644 --- a/src/dev/sparc/SConscript +++ b/src/dev/sparc/SConscript @@ -37,7 +37,9 @@ Import('env') sources = [] sources += Split(''' + dtod.cc t1000.cc + mm_disk.cc ''') # Convert file names to SCons File objects. This takes care of the diff --git a/src/dev/sparc/dtod.cc b/src/dev/sparc/dtod.cc new file mode 100644 index 000000000..30c7baaf5 --- /dev/null +++ b/src/dev/sparc/dtod.cc @@ -0,0 +1,115 @@ +/* + * 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: Ali Saidi + */ + +/** @file + * Time of date device implementation + */ +#include <sys/time.h> + +#include <deque> +#include <string> +#include <vector> + +#include "base/trace.hh" +#include "dev/sparc/dtod.hh" +#include "dev/platform.hh" +#include "mem/packet_access.hh" +#include "mem/port.hh" +#include "sim/builder.hh" +#include "sim/system.hh" + +using namespace std; +using namespace TheISA; + +DumbTOD::DumbTOD(Params *p) + : BasicPioDevice(p), todTime(p->init_time) +{ + pioSize = 0x08; + + struct tm tm; + gmtime_r((time_t*)&todTime, &tm); + DPRINTFN("Real-time clock set to %s\n", asctime(&tm)); + DPRINTFN("Real-time clock set to %d\n", todTime); +} + +Tick +DumbTOD::read(PacketPtr pkt) +{ + assert(pkt->result == Packet::Unknown); + assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); + assert(pkt->getSize() == 8); + + pkt->allocate(); + pkt->set(todTime); + todTime += 1000; + + pkt->result = Packet::Success; + return pioDelay; +} + +Tick +DumbTOD::write(PacketPtr pkt) +{ + panic("Dumb tod device doesn't support writes\n"); +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(DumbTOD) + + Param<Addr> pio_addr; + Param<Tick> pio_latency; + SimObjectParam<Platform *> platform; + SimObjectParam<System *> system; + Param<time_t> time; + +END_DECLARE_SIM_OBJECT_PARAMS(DumbTOD) + +BEGIN_INIT_SIM_OBJECT_PARAMS(DumbTOD) + + INIT_PARAM(pio_addr, "Device Address"), + INIT_PARAM(pio_latency, "Programmed IO latency"), + INIT_PARAM(platform, "platform"), + INIT_PARAM(system, "system object"), + INIT_PARAM(time, "System time to use (0 for actual time") + +END_INIT_SIM_OBJECT_PARAMS(DumbTOD) + +CREATE_SIM_OBJECT(DumbTOD) +{ + DumbTOD::Params *p = new DumbTOD::Params; + p->name =getInstanceName(); + p->pio_addr = pio_addr; + p->pio_delay = pio_latency; + p->platform = platform; + p->system = system; + p->init_time = time; + return new DumbTOD(p); +} + +REGISTER_SIM_OBJECT("DumbTOD", DumbTOD) diff --git a/src/dev/sparc/dtod.hh b/src/dev/sparc/dtod.hh new file mode 100644 index 000000000..7d3a9f628 --- /dev/null +++ b/src/dev/sparc/dtod.hh @@ -0,0 +1,67 @@ +/* + * Copyright (c) 206, 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 + * This device acts as a simple time of date device. It's implemented as a + * simple device register read. + */ + +#ifndef __DEV_SPARC_DTOD_HH__ +#define __DEV_SPARC_DTOD_HH__ + +#include "base/range.hh" +#include "dev/io_device.hh" + + +/** + * DumbTOD simply returns some idea of time when read. Until we finish with + * legion it starts with the start time and increments itself by 1000 each time. + */ +class DumbTOD : public BasicPioDevice +{ + private: + uint64_t todTime; + + public: + struct Params : public BasicPioDevice::Params + { + time_t init_time; + }; + protected: + const Params *params() const { return (const Params *)_params; } + + public: + DumbTOD(Params *p); + + virtual Tick read(PacketPtr pkt); + virtual Tick write(PacketPtr pkt); +}; + +#endif // __DEV_BADDEV_HH__ diff --git a/src/dev/sparc/mm_disk.cc b/src/dev/sparc/mm_disk.cc new file mode 100644 index 000000000..9057c28be --- /dev/null +++ b/src/dev/sparc/mm_disk.cc @@ -0,0 +1,137 @@ +/* + * Copyright (c) 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: Ali Saidi + */ + +/** @file + * This device acts as a disk similar to the memory mapped disk device + * in legion. Any access is translated to an offset in the disk image. + */ + +#include "base/trace.hh" +#include "dev/sparc/mm_disk.hh" +#include "dev/platform.hh" +#include "mem/port.hh" +#include "mem/packet_access.hh" +#include "sim/builder.hh" +#include "sim/byteswap.hh" +#include "sim/system.hh" + +MmDisk::MmDisk(Params *p) + : BasicPioDevice(p), image(p->image), curSector((uint64_t)-1), dirty(false) +{ + memset(&bytes, 0, SectorSize); + pioSize = image->size() * SectorSize; +} + +Tick +MmDisk::read(PacketPtr pkt) +{ + Addr accessAddr; + off_t sector; + off_t bytes_read; + uint16_t *d16; + uint32_t *d32; + uint64_t *d64; + + assert(pkt->result == Packet::Unknown); + assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize); + accessAddr = pkt->getAddr() - pioAddr; + + sector = accessAddr / SectorSize; + + if (sector != curSector) { + if (dirty) + bytes_read = image->write(bytes, curSector); + bytes_read = image->read(bytes, sector); + curSector = sector; + } + switch (pkt->getSize()) { + case sizeof(uint8_t): + pkt->set(bytes[accessAddr % SectorSize]); + break; + case sizeof(uint16_t): + d16 = (uint16_t*)bytes + (accessAddr % SectorSize)/2; + pkt->set(htobe(*d16)); + break; + case sizeof(uint32_t): + d32 = (uint32_t*)bytes + (accessAddr % SectorSize)/4; + pkt->set(htobe(*d32)); + break; + case sizeof(uint64_t): + d64 = (uint64_t*)bytes + (accessAddr % SectorSize)/8; + pkt->set(htobe(*d64)); + break; + default: + panic("Invalid access size\n"); + } + + pkt->result = Packet::Success; + return pioDelay; +} + +Tick +MmDisk::write(PacketPtr pkt) +{ + panic("need to implement\n"); +} + + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(MmDisk) + Param<Addr> pio_addr; + Param<Tick> pio_latency; + Param<Addr> pio_size; + SimObjectParam<Platform *> platform; + SimObjectParam<System *> system; + SimObjectParam<DiskImage *> image; +END_DECLARE_SIM_OBJECT_PARAMS(MmDisk) + +BEGIN_INIT_SIM_OBJECT_PARAMS(MmDisk) + + INIT_PARAM(pio_addr, "Device Address"), + INIT_PARAM(pio_latency, "Programmed IO latency"), + INIT_PARAM(pio_size, "Size of address range"), + INIT_PARAM(platform, "platform"), + INIT_PARAM(system, "system object"), + INIT_PARAM(image, "disk image") + +END_INIT_SIM_OBJECT_PARAMS(MmDisk) + +CREATE_SIM_OBJECT(MmDisk) +{ + MmDisk::Params *p = new MmDisk::Params; + p->name = getInstanceName(); + p->pio_addr = pio_addr; + p->pio_delay = pio_latency; + p->platform = platform; + p->system = system; + p->image = image; + return new MmDisk(p); +} + +REGISTER_SIM_OBJECT("MmDisk", MmDisk) diff --git a/src/dev/sparc/mm_disk.hh b/src/dev/sparc/mm_disk.hh new file mode 100644 index 000000000..0a4626067 --- /dev/null +++ b/src/dev/sparc/mm_disk.hh @@ -0,0 +1,70 @@ +/* + * Copyright (c) 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: Ali Saidi + */ + +/** @file + * This device acts as a disk similar to the memory mapped disk device + * in legion. Any access is translated to an offset in the disk image. + */ + +#ifndef __DEV_SPARC_MM_DISK_HH__ +#define __DEV_SPARC_MM_DISK_HH__ + +#include "base/range.hh" +#include "dev/io_device.hh" +#include "dev/disk_image.hh" + +class MmDisk : public BasicPioDevice +{ + private: + DiskImage *image; + off_t curSector; + bool dirty; + union { + uint8_t bytes[SectorSize]; + uint32_t words[SectorSize/4]; + }; + + public: + struct Params : public BasicPioDevice::Params + { + DiskImage *image; + }; + protected: + const Params *params() const { return (const Params*)_params; } + + public: + MmDisk(Params *p); + + virtual Tick read(PacketPtr pkt); + virtual Tick write(PacketPtr pkt); +}; + +#endif //__DEV_SPARC_MM_DISK_HH__ + diff --git a/src/python/m5/main.py b/src/python/m5/main.py index 114c668a6..5df6d03cf 100644 --- a/src/python/m5/main.py +++ b/src/python/m5/main.py @@ -304,7 +304,8 @@ def main(): sys.argv = arguments sys.path = [ os.path.dirname(sys.argv[0]) ] + sys.path - scope = { '__file__' : sys.argv[0] } + scope = { '__file__' : sys.argv[0], + '__name__' : '__m5_main__' } # we want readline if we're doing anything interactive if options.interactive or options.pdb: diff --git a/src/python/m5/objects/T1000.py b/src/python/m5/objects/T1000.py index 79195d976..7b93268ac 100644 --- a/src/python/m5/objects/T1000.py +++ b/src/python/m5/objects/T1000.py @@ -5,6 +5,18 @@ from Uart import Uart8250 from Platform import Platform from SimConsole import SimConsole, ConsoleListener + +class MmDisk(BasicPioDevice): + type = 'MmDisk' + image = Param.DiskImage("Disk Image") + pio_addr = 0x1F40000000 + +class DumbTOD(BasicPioDevice): + type = 'DumbTOD' + time = Param.Time('01/01/2009', "System time to use ('Now' for real time)") + pio_addr = 0xfff0c1fff8 + + class T1000(Platform): type = 'T1000' system = Param.System(Parent.any, "system") @@ -58,6 +70,8 @@ class T1000(Platform): warn_access="Accessing SSI -- Unimplemented!") hvuart = Uart8250(pio_addr=0xfff0c2c000) + htod = DumbTOD() + puart0 = Uart8250(pio_addr=0x1f10000000) console = SimConsole(listener = ConsoleListener()) @@ -80,3 +94,4 @@ class T1000(Platform): self.fake_ssi.pio = bus.port self.puart0.pio = bus.port self.hvuart.pio = bus.port + self.htod.pio = bus.port diff --git a/src/python/m5/objects/Tsunami.py b/src/python/m5/objects/Tsunami.py index ac9020b47..18a776a7f 100644 --- a/src/python/m5/objects/Tsunami.py +++ b/src/python/m5/objects/Tsunami.py @@ -13,8 +13,8 @@ class TsunamiCChip(BasicPioDevice): class TsunamiIO(BasicPioDevice): type = 'TsunamiIO' - time = Param.UInt64(1136073600, - "System time to use (0 for actual time, default is 1/1/06)") + time = Param.Time('01/01/2009', + "System time to use ('Now' for actual time)") tsunami = Param.Tsunami(Parent.any, "Tsunami") frequency = Param.Frequency('1024Hz', "frequency of interrupts") diff --git a/src/python/m5/params.py b/src/python/m5/params.py index d83d5f73f..d570804d8 100644 --- a/src/python/m5/params.py +++ b/src/python/m5/params.py @@ -44,7 +44,12 @@ # ##################################################################### -import sys, inspect, copy +import copy +import datetime +import inspect +import sys +import time + import convert from util import * @@ -513,6 +518,50 @@ class EthernetAddr(ParamValue): else: return self.value +def parse_time(value): + strings = [ "%a %b %d %H:%M:%S %Z %Y", + "%a %b %d %H:%M:%S %Z %Y", + "%Y/%m/%d %H:%M:%S", + "%Y/%m/%d %H:%M", + "%Y/%m/%d", + "%m/%d/%Y %H:%M:%S", + "%m/%d/%Y %H:%M", + "%m/%d/%Y", + "%m/%d/%y %H:%M:%S", + "%m/%d/%y %H:%M", + "%m/%d/%y"] + + for string in strings: + try: + return time.strptime(value, string) + except ValueError: + pass + + raise ValueError, "Could not parse '%s' as a time" % value + +class Time(ParamValue): + cxx_type = 'time_t' + def __init__(self, value): + if isinstance(value, time.struct_time): + self.value = time.mktime(value) + elif isinstance(value, int): + self.value = value + elif isinstance(value, str): + if value in ('Now', 'Today'): + self.value = time.time() + else: + self.value = time.mktime(parse_time(value)) + elif isinstance(value, (datetime.datetime, datetime.date)): + self.value = time.mktime(value.timetuple()) + else: + raise ValueError, "Could not parse '%s' as a time" % value + + def __str__(self): + return str(int(self.value)) + + def ini_str(self): + return str(int(self.value)) + # Enumerated types are a little more complex. The user specifies the # type as Enum(foo) where foo is either a list or dictionary of # alternatives (typically strings, but not necessarily so). (In the @@ -973,6 +1022,7 @@ __all__ = ['Param', 'VectorParam', 'NetworkBandwidth', 'MemoryBandwidth', 'Range', 'AddrRange', 'TickRange', 'MaxAddr', 'MaxTick', 'AllMemory', + 'Time', 'NextEthernetAddr', 'NULL', 'Port', 'VectorPort'] diff --git a/src/sim/byteswap.hh b/src/sim/byteswap.hh index 7b63cf6e0..9e7390977 100644 --- a/src/sim/byteswap.hh +++ b/src/sim/byteswap.hh @@ -132,7 +132,7 @@ template <typename T> static inline T letobe(T value) {return swap_byte(value);} //For conversions not involving the guest system, we can define the functions //conditionally based on the BYTE_ORDER macro and outside of the namespaces -#if defined(_BIG_ENDIAN) || BYTE_ORDER == BIG_ENDIAN +#if defined(_BIG_ENDIAN) || !defined(_LITTLE_ENDIAN) && BYTE_ORDER == BIG_ENDIAN const ByteOrder HostByteOrder = BigEndianByteOrder; template <typename T> static inline T htole(T value) {return swap_byte(value);} template <typename T> static inline T letoh(T value) {return swap_byte(value);} diff --git a/src/sim/process.cc b/src/sim/process.cc index 1a0f54842..e5d868115 100644 --- a/src/sim/process.cc +++ b/src/sim/process.cc @@ -448,6 +448,11 @@ LiveProcess::create(const std::string &nm, System *system, int stdin_fd, fatal("Can't load object file %s", executable); } + if (objFile->isDynamic()) + fatal("Object file is a dynamic executable however only static " + "executables are supported!\n Please recompile your " + "executable as a static binary and try again.\n"); + #if THE_ISA == ALPHA_ISA if (objFile->getArch() != ObjectFile::Alpha) fatal("Object file architecture does not match compiled ISA (Alpha)."); |