summaryrefslogtreecommitdiff
path: root/src/arch/sparc
diff options
context:
space:
mode:
Diffstat (limited to 'src/arch/sparc')
-rw-r--r--src/arch/sparc/asi.cc27
-rw-r--r--src/arch/sparc/faults.cc103
-rw-r--r--src/arch/sparc/faults.hh8
-rw-r--r--src/arch/sparc/interrupts.hh134
-rw-r--r--src/arch/sparc/intregfile.cc7
-rw-r--r--src/arch/sparc/isa/decoder.isa32
-rw-r--r--src/arch/sparc/isa/formats/mem/blockmem.isa4
-rw-r--r--src/arch/sparc/isa_traits.hh9
-rw-r--r--src/arch/sparc/miscregfile.cc26
-rw-r--r--src/arch/sparc/miscregfile.hh30
-rw-r--r--src/arch/sparc/regfile.cc6
-rw-r--r--src/arch/sparc/tlb.cc150
-rw-r--r--src/arch/sparc/ua2005.cc245
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);
}