Implemented the SPARC fill and spill handlers.
authorGabe Black <gblack@eecs.umich.edu>
Wed, 25 Oct 2006 21:49:41 +0000 (17:49 -0400)
committerGabe Black <gblack@eecs.umich.edu>
Wed, 25 Oct 2006 21:49:41 +0000 (17:49 -0400)
src/arch/sparc/faults.cc:
src/arch/sparc/faults.hh:
    Added a function to do normal SPARC trap processing, and implemented the spill and fill faults for SE
src/arch/sparc/process.cc:
src/arch/sparc/process.hh:
    Added fill and spill handlers which are stuffed into the processes address space. The location of these handlers are stored in fillStart and spillStart.

--HG--
extra : convert_revision : 59adb96570cce86f373fbc2c3e4c05abe1742d3b

src/arch/sparc/faults.cc
src/arch/sparc/faults.hh
src/arch/sparc/process.cc
src/arch/sparc/process.hh

index 7b7765935a27a5705ff153672d191929ebd3be2e..fd91ccf0f037740a1e0329a75ab05b68b9234908 100644 (file)
  *          Kevin Lim
  */
 
+#include <algorithm>
+
 #include "arch/sparc/faults.hh"
-#include "cpu/thread_context.hh"
-#include "cpu/base.hh"
+#include "arch/sparc/isa_traits.hh"
+#include "arch/sparc/process.hh"
+#include "base/bitfield.hh"
 #include "base/trace.hh"
+#include "cpu/base.hh"
+#include "cpu/thread_context.hh"
 #if !FULL_SYSTEM
-#include "sim/process.hh"
 #include "mem/page_table.hh"
+#include "sim/process.hh"
 #endif
 
+using namespace std;
+
 namespace SparcISA
 {
 
@@ -229,6 +236,129 @@ FaultPriority PageTableFault::_priority = 0;
 FaultStat PageTableFault::_count;
 #endif
 
+/**
+ * This sets everything up for a normal trap except for actually jumping to
+ * the handler. It will need to be expanded to include the state machine in
+ * the manual. Right now it assumes that traps will always be to the
+ * privileged level.
+ */
+
+void doNormalFault(ThreadContext *tc, TrapType tt)
+{
+    uint64_t TL = tc->readMiscReg(MISCREG_TL);
+    uint64_t TSTATE = tc->readMiscReg(MISCREG_TSTATE);
+    uint64_t PSTATE = tc->readMiscReg(MISCREG_PSTATE);
+    uint64_t HPSTATE = tc->readMiscReg(MISCREG_HPSTATE);
+    uint64_t CCR = tc->readMiscReg(MISCREG_CCR);
+    uint64_t ASI = tc->readMiscReg(MISCREG_ASI);
+    uint64_t CWP = tc->readMiscReg(MISCREG_CWP);
+    uint64_t CANSAVE = tc->readMiscReg(MISCREG_CANSAVE);
+    uint64_t GL = tc->readMiscReg(MISCREG_GL);
+    uint64_t PC = tc->readPC();
+    uint64_t NPC = tc->readNextPC();
+
+    //Increment the trap level
+    TL++;
+    tc->setMiscReg(MISCREG_TL, TL);
+
+    //Save off state
+
+    //set TSTATE.gl to gl
+    replaceBits(TSTATE, 42, 40, GL);
+    //set TSTATE.ccr to ccr
+    replaceBits(TSTATE, 39, 32, CCR);
+    //set TSTATE.asi to asi
+    replaceBits(TSTATE, 31, 24, ASI);
+    //set TSTATE.pstate to pstate
+    replaceBits(TSTATE, 20, 8, PSTATE);
+    //set TSTATE.cwp to cwp
+    replaceBits(TSTATE, 4, 0, CWP);
+
+    //Write back TSTATE
+    tc->setMiscReg(MISCREG_TSTATE, TSTATE);
+
+    //set TPC to PC
+    tc->setMiscReg(MISCREG_TPC, PC);
+    //set TNPC to NPC
+    tc->setMiscReg(MISCREG_TNPC, NPC);
+
+    //set HTSTATE.hpstate to hpstate
+    tc->setMiscReg(MISCREG_HTSTATE, HPSTATE);
+
+    //TT = trap type;
+    tc->setMiscReg(MISCREG_TT, tt);
+
+    //Update the global register level
+    if(1/*We're delivering the trap in priveleged mode*/)
+        tc->setMiscReg(MISCREG_GL, max<int>(GL+1, MaxGL));
+    else
+        tc->setMiscReg(MISCREG_GL, max<int>(GL+1, MaxPGL));
+
+    //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(1/*We're delivering the trap in priveleged mode*/)
+    {
+        //PSTATE.priv = 1
+        PSTATE |= (1 << 2);
+        //PSTATE.cle = PSTATE.tle
+        replaceBits(PSTATE, 9, 9, PSTATE >> 8);
+    }
+    else
+    {
+        //PSTATE.priv = 0
+        PSTATE &= ~(1 << 2);
+        //PSTATE.cle = 0
+        PSTATE &= ~(1 << 9);
+    }
+    //PSTATE.ie = 0
+    PSTATE &= ~(1 << 1);
+    //PSTATE.tle is unchanged
+    //PSTATE.tct = 0
+    //XXX Where exactly is this field?
+    tc->setMiscReg(MISCREG_PSTATE, PSTATE);
+
+    if(0/*We're delivering the trap in hyperprivileged mode*/)
+    {
+        //HPSTATE.red = 0
+        HPSTATE &= ~(1 << 5);
+        //HPSTATE.hpriv = 1
+        HPSTATE |= (1 << 2);
+        //HPSTATE.ibe = 0
+        HPSTATE &= ~(1 << 10);
+        //HPSTATE.tlz is unchanged
+        tc->setMiscReg(MISCREG_HPSTATE, HPSTATE);
+    }
+
+    bool changedCWP = true;
+    if(tt == 0x24)
+    {
+        warn("Incrementing the CWP by 1\n");
+        CWP++;
+    }
+    else if(0x80 <= tt && tt <= 0xbf)
+    {
+        warn("Incrementing the CWP by %d\n", CANSAVE + 2);
+        CWP += (CANSAVE + 2);
+    }
+    else if(0xc0 <= tt && tt <= 0xff)
+    {
+        warn("Decrementing the CWP by 1\n");
+        CWP--;
+    }
+    else
+        changedCWP = false;
+    if(changedCWP)
+    {
+        CWP = (CWP + NWindows) % NWindows;
+        tc->setMiscRegWithEffect(MISCREG_CWP, CWP);
+    }
+}
+
 #if FULL_SYSTEM
 
 void SparcFault::invoke(ThreadContext * tc)
@@ -263,6 +393,42 @@ void TrapInstruction::invoke(ThreadContext * tc)
     // Should be handled in ISA.
 }
 
+void SpillNNormal::invoke(ThreadContext *tc)
+{
+    warn("I'm in a spill trap\n");
+    doNormalFault(tc, trapType());
+
+    Process *p = tc->getProcessPtr();
+
+    //This will only work in faults from a SparcLiveProcess
+    SparcLiveProcess *lp = dynamic_cast<SparcLiveProcess *>(p);
+    assert(lp);
+
+    //Then adjust the PC and NPC
+    Addr spillStart = lp->readSpillStart();
+    tc->setPC(spillStart);
+    tc->setNextPC(spillStart + sizeof(MachInst));
+    tc->setNextNPC(spillStart + 2*sizeof(MachInst));
+}
+
+void FillNNormal::invoke(ThreadContext *tc)
+{
+    warn("I'm in a fill trap\n");
+    doNormalFault(tc, trapType());
+
+    Process * p = tc->getProcessPtr();
+
+    //This will only work in faults from a SparcLiveProcess
+    SparcLiveProcess *lp = dynamic_cast<SparcLiveProcess *>(p);
+    assert(lp);
+
+    //The adjust the PC and NPC
+    Addr fillStart = lp->readFillStart();
+    tc->setPC(fillStart);
+    tc->setNextPC(fillStart + sizeof(MachInst));
+    tc->setNextNPC(fillStart + 2*sizeof(MachInst));
+}
+
 void PageTableFault::invoke(ThreadContext *tc)
 {
     Process *p = tc->getProcessPtr();
@@ -282,6 +448,7 @@ void PageTableFault::invoke(ThreadContext *tc)
         FaultBase::invoke(tc);
     }
 }
+
 #endif
 
 } // namespace SparcISA
index b279f4911bf2a090ce8f85368771067178470c5f..394a06294c80c6ece26e00124d774957749df8b5 100644 (file)
@@ -39,8 +39,8 @@
 namespace SparcISA
 {
 
-typedef const uint32_t TrapType;
-typedef const uint32_t FaultPriority;
+typedef uint32_t TrapType;
+typedef uint32_t FaultPriority;
 
 class SparcFault : public FaultBase
 {
@@ -547,6 +547,7 @@ class SpillNNormal : public EnumeratedFault
     FaultName name() {return _name;}
     FaultPriority priority() {return _priority;}
     FaultStat & countStat() {return _count;}
+    void invoke(ThreadContext * tc);
 };
 
 class SpillNOther : public EnumeratedFault
@@ -577,6 +578,7 @@ class FillNNormal : public EnumeratedFault
     FaultName name() {return _name;}
     FaultPriority priority() {return _priority;}
     FaultStat & countStat() {return _count;}
+    void invoke(ThreadContext * tc);
 };
 
 class FillNOther : public EnumeratedFault
index 3323ba7a072162e1ab8ac24901ca1ec0364b68b8..a3b7dde7c425a6656af4ff218760d6c29291774f 100644 (file)
@@ -66,6 +66,10 @@ SparcLiveProcess::SparcLiveProcess(const std::string &nm, ObjectFile *objFile,
 
     // Set pointer for next thread stack.  Reserve 8M for main stack.
     next_thread_stack_base = stack_base - (8 * 1024 * 1024);
+
+    //Initialize these to 0s
+    fillStart = 0;
+    spillStart = 0;
 }
 
 void
@@ -88,15 +92,19 @@ SparcLiveProcess::startup()
      */
 
     //No windows contain info from other programs
-    threadContexts[0]->setMiscRegWithEffect(MISCREG_OTHERWIN, 0);
+    threadContexts[0]->setMiscReg(MISCREG_OTHERWIN, 0);
     //There are no windows to pop
-    threadContexts[0]->setMiscRegWithEffect(MISCREG_CANRESTORE, 0);
+    threadContexts[0]->setMiscReg(MISCREG_CANRESTORE, 0);
     //All windows are available to save into
-    threadContexts[0]->setMiscRegWithEffect(MISCREG_CANSAVE, NWindows - 2);
+    threadContexts[0]->setMiscReg(MISCREG_CANSAVE, NWindows - 2);
     //All windows are "clean"
-    threadContexts[0]->setMiscRegWithEffect(MISCREG_CLEANWIN, NWindows);
+    threadContexts[0]->setMiscReg(MISCREG_CLEANWIN, NWindows);
     //Start with register window 0
-    threadContexts[0]->setMiscRegWithEffect(MISCREG_CWP, 0);
+    threadContexts[0]->setMiscReg(MISCREG_CWP, 0);
+    //Always use spill and fill traps 0
+    threadContexts[0]->setMiscReg(MISCREG_WSTATE, 0);
+    //Set the trap level to 0
+    threadContexts[0]->setMiscReg(MISCREG_TL, 0);
 }
 
 m5_auxv_t buildAuxVect(int64_t type, int64_t val)
@@ -107,6 +115,83 @@ m5_auxv_t buildAuxVect(int64_t type, int64_t val)
     return result;
 }
 
+//We only use 19 instructions for the trap handlers, but there would be
+//space for 32 in a real SPARC trap table.
+const int numFillInsts = 32;
+const int numSpillInsts = 32;
+
+MachInst fillHandler[numFillInsts] =
+{
+    htog(0x87802018), //wr %g0, ASI_AIUP, %asi
+    htog(0xe0dba7ff), //ldxa [%sp + BIAS + (0*8)] %asi, %l0
+    htog(0xe2dba807), //ldxa [%sp + BIAS + (1*8)] %asi, %l1
+    htog(0xe4dba80f), //ldxa [%sp + BIAS + (2*8)] %asi, %l2
+    htog(0xe6dba817), //ldxa [%sp + BIAS + (3*8)] %asi, %l3
+    htog(0xe8dba81f), //ldxa [%sp + BIAS + (4*8)] %asi, %l4
+    htog(0xeadba827), //ldxa [%sp + BIAS + (5*8)] %asi, %l5
+    htog(0xecdba82f), //ldxa [%sp + BIAS + (6*8)] %asi, %l6
+    htog(0xeedba837), //ldxa [%sp + BIAS + (7*8)] %asi, %l7
+    htog(0xf0dba83f), //ldxa [%sp + BIAS + (8*8)] %asi, %i0
+    htog(0xf2dba847), //ldxa [%sp + BIAS + (9*8)] %asi, %i1
+    htog(0xf4dba84f), //ldxa [%sp + BIAS + (10*8)] %asi, %i2
+    htog(0xf6dba857), //ldxa [%sp + BIAS + (11*8)] %asi, %i3
+    htog(0xf8dba85f), //ldxa [%sp + BIAS + (12*8)] %asi, %i4
+    htog(0xfadba867), //ldxa [%sp + BIAS + (13*8)] %asi, %i5
+    htog(0xfcdba86f), //ldxa [%sp + BIAS + (14*8)] %asi, %i6
+    htog(0xfedba877), //ldxa [%sp + BIAS + (15*8)] %asi, %i7
+    htog(0x83880000), //restored
+    htog(0x83F00000), //retry
+    htog(0x00000000), //illtrap
+    htog(0x00000000), //illtrap
+    htog(0x00000000), //illtrap
+    htog(0x00000000), //illtrap
+    htog(0x00000000), //illtrap
+    htog(0x00000000), //illtrap
+    htog(0x00000000), //illtrap
+    htog(0x00000000), //illtrap
+    htog(0x00000000), //illtrap
+    htog(0x00000000), //illtrap
+    htog(0x00000000), //illtrap
+    htog(0x00000000), //illtrap
+    htog(0x00000000)  //illtrap
+};
+
+MachInst spillHandler[numSpillInsts] =
+{
+    htog(0x87802018), //wr %g0, ASI_AIUP, %asi
+    htog(0xe0f3a7ff), //stxa %l0, [%sp + BIAS + (0*8)] %asi
+    htog(0xe2f3a807), //stxa %l1, [%sp + BIAS + (1*8)] %asi
+    htog(0xe4f3a80f), //stxa %l2, [%sp + BIAS + (2*8)] %asi
+    htog(0xe6f3a817), //stxa %l3, [%sp + BIAS + (3*8)] %asi
+    htog(0xe8f3a81f), //stxa %l4, [%sp + BIAS + (4*8)] %asi
+    htog(0xeaf3a827), //stxa %l5, [%sp + BIAS + (5*8)] %asi
+    htog(0xecf3a82f), //stxa %l6, [%sp + BIAS + (6*8)] %asi
+    htog(0xeef3a837), //stxa %l7, [%sp + BIAS + (7*8)] %asi
+    htog(0xf0f3a83f), //stxa %i0, [%sp + BIAS + (8*8)] %asi
+    htog(0xf2f3a847), //stxa %i1, [%sp + BIAS + (9*8)] %asi
+    htog(0xf4f3a84f), //stxa %i2, [%sp + BIAS + (10*8)] %asi
+    htog(0xf6f3a857), //stxa %i3, [%sp + BIAS + (11*8)] %asi
+    htog(0xf8f3a85f), //stxa %i4, [%sp + BIAS + (12*8)] %asi
+    htog(0xfaf3a867), //stxa %i5, [%sp + BIAS + (13*8)] %asi
+    htog(0xfcf3a86f), //stxa %i6, [%sp + BIAS + (14*8)] %asi
+    htog(0xfef3a877), //stxa %i7, [%sp + BIAS + (15*8)] %asi
+    htog(0x81880000), //saved
+    htog(0x83F00000), //retry
+    htog(0x00000000), //illtrap
+    htog(0x00000000), //illtrap
+    htog(0x00000000), //illtrap
+    htog(0x00000000), //illtrap
+    htog(0x00000000), //illtrap
+    htog(0x00000000), //illtrap
+    htog(0x00000000), //illtrap
+    htog(0x00000000), //illtrap
+    htog(0x00000000), //illtrap
+    htog(0x00000000), //illtrap
+    htog(0x00000000), //illtrap
+    htog(0x00000000), //illtrap
+    htog(0x00000000)  //illtrap
+};
+
 void
 SparcLiveProcess::argsInit(int intSize, int pageSize)
 {
@@ -317,6 +402,17 @@ SparcLiveProcess::argsInit(int intSize, int pageSize)
 
     initVirtMem->writeBlob(argc_base, (uint8_t*)&guestArgc, intSize);
 
+    //Stuff the trap handlers into the processes address space.
+    //Since the stack grows down and is the highest area in the processes
+    //address space, we can put stuff above it and stay out of the way.
+    int fillSize = sizeof(MachInst) * numFillInsts;
+    int spillSize = sizeof(MachInst) * numSpillInsts;
+    fillStart = stack_base;
+    spillStart = fillStart + fillSize;
+    initVirtMem->writeBlob(fillStart, (uint8_t*)fillHandler, fillSize);
+    initVirtMem->writeBlob(spillStart, (uint8_t*)spillHandler, spillSize);
+
+    //Set up the thread context to start running the process
     threadContexts[0]->setIntReg(ArgumentReg0, argc);
     threadContexts[0]->setIntReg(ArgumentReg1, argv_array_base);
     threadContexts[0]->setIntReg(StackPointerReg, stack_min - StackBias);
index 7cc52e241459b99c15024f5a97b64bbad06e00f2..2320810c7b6267d68e42c35a34db1d7ec6974354 100644 (file)
@@ -55,6 +55,9 @@ class SparcLiveProcess : public LiveProcess
 
     static const Addr StackBias = 2047;
 
+    //The locations of the fill and spill handlers
+    Addr fillStart, spillStart;
+
     std::vector<m5_auxv_t> auxv;
 
     SparcLiveProcess(const std::string &nm, ObjectFile *objFile,
@@ -71,6 +74,12 @@ class SparcLiveProcess : public LiveProcess
 
     void argsInit(int intSize, int pageSize);
 
+    Addr readFillStart()
+    { return fillStart; }
+
+    Addr readSpillStart()
+    { return spillStart; }
+
 };
 
 #endif // __SPARC_PROCESS_HH__