summaryrefslogtreecommitdiff
path: root/src/arch/sparc
diff options
context:
space:
mode:
Diffstat (limited to 'src/arch/sparc')
-rw-r--r--src/arch/sparc/asi.cc3
-rw-r--r--src/arch/sparc/faults.cc4
-rw-r--r--src/arch/sparc/faults.hh2
-rw-r--r--src/arch/sparc/interrupts.hh163
-rw-r--r--src/arch/sparc/isa_traits.hh12
-rw-r--r--src/arch/sparc/linux/process.cc2
-rw-r--r--src/arch/sparc/miscregfile.cc17
-rw-r--r--src/arch/sparc/miscregfile.hh3
-rw-r--r--src/arch/sparc/process.cc48
-rw-r--r--src/arch/sparc/regfile.cc13
-rw-r--r--src/arch/sparc/regfile.hh2
-rw-r--r--src/arch/sparc/tlb.cc46
-rw-r--r--src/arch/sparc/ua2005.cc80
13 files changed, 237 insertions, 158 deletions
diff --git a/src/arch/sparc/asi.cc b/src/arch/sparc/asi.cc
index 3d553955f..d8cd84af5 100644
--- a/src/arch/sparc/asi.cc
+++ b/src/arch/sparc/asi.cc
@@ -294,7 +294,8 @@ namespace SparcISA
bool AsiIsReg(ASI asi)
{
- return AsiIsMmu(asi) || AsiIsScratchPad(asi) | AsiIsSparcError(asi);
+ return AsiIsMmu(asi) || AsiIsScratchPad(asi) ||
+ AsiIsSparcError(asi) || AsiIsInterrupt(asi);
}
bool AsiIsSparcError(ASI asi)
diff --git a/src/arch/sparc/faults.cc b/src/arch/sparc/faults.cc
index 391dd7134..b1a6ae919 100644
--- a/src/arch/sparc/faults.cc
+++ b/src/arch/sparc/faults.cc
@@ -208,6 +208,10 @@ template<> SparcFaultBase::FaultVals
{"trap_level_zero", 0x05F, 202, {H, H, SH}};
template<> SparcFaultBase::FaultVals
+ SparcFault<InterruptVector>::vals =
+ {"interrupt_vector", 0x060, 2630, {H, H, H}};
+
+template<> SparcFaultBase::FaultVals
SparcFault<PAWatchpoint>::vals =
{"PA_watchpoint", 0x061, 1209, {H, H, H}};
diff --git a/src/arch/sparc/faults.hh b/src/arch/sparc/faults.hh
index 5facc081d..0ba897e67 100644
--- a/src/arch/sparc/faults.hh
+++ b/src/arch/sparc/faults.hh
@@ -193,6 +193,8 @@ class HstickMatch : public SparcFault<HstickMatch> {};
class TrapLevelZero : public SparcFault<TrapLevelZero> {};
+class InterruptVector : public SparcFault<InterruptVector> {};
+
class PAWatchpoint : public SparcFault<PAWatchpoint> {};
class VAWatchpoint : public SparcFault<VAWatchpoint> {};
diff --git a/src/arch/sparc/interrupts.hh b/src/arch/sparc/interrupts.hh
index dc3b235fe..3234002c5 100644
--- a/src/arch/sparc/interrupts.hh
+++ b/src/arch/sparc/interrupts.hh
@@ -24,76 +24,80 @@
* 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
+ * Lisa Hsu
*/
#ifndef __ARCH_SPARC_INTERRUPT_HH__
#define __ARCH_SPARC_INTERRUPT_HH__
#include "arch/sparc/faults.hh"
+#include "arch/sparc/isa_traits.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
{
private:
- bool interrupts[num_interrupt_types];
- int numPosted;
+ uint64_t interrupts[NumInterruptTypes];
+ uint64_t intStatus;
public:
Interrupts()
{
- for (int i = 0; i < num_interrupt_types; ++i) {
- interrupts[i] = false;
- }
- numPosted = 0;
+ clear_all();
}
- void post(int int_type)
+ int InterruptLevel(uint64_t softint)
{
- if (int_type < 0 || int_type >= num_interrupt_types)
- panic("posting unknown interrupt!\n");
- if (interrupts[int_type] == false) {
- interrupts[int_type] = true;
- ++numPosted;
- }
+ if (softint & 0x10000 || softint & 0x1)
+ return 14;
+
+ int level = 15;
+ while (level > 0 && !(1 << level & softint))
+ level--;
+ if (1 << level & softint)
+ return level;
+ return 0;
}
void post(int int_num, int index)
{
+ DPRINTF(Interrupt, "Interrupt %d:%d posted\n", int_num, index);
+ assert(int_num >= 0 && int_num < NumInterruptTypes);
+ assert(index >= 0 && index < 64);
+ interrupts[int_num] |= ULL(1) << index;
+ intStatus |= ULL(1) << int_num;
}
void clear(int int_num, int index)
{
+ DPRINTF(Interrupt, "Interrupt %d:%d cleared\n", int_num, index);
+ assert(int_num >= 0 && int_num < NumInterruptTypes);
+ assert(index >= 0 && index < 64);
+ interrupts[int_num] &= ~(ULL(1) << index);
+ if (!interrupts[int_num])
+ intStatus &= ~(ULL(1) << int_num);
}
void clear_all()
{
-
+ for (int i = 0; i < NumInterruptTypes; ++i) {
+ interrupts[i] = 0;
+ }
+ intStatus = 0;
}
bool check_interrupts(ThreadContext * tc) const
{
- if (numPosted)
- return true;
- else
- return false;
+ return intStatus;
}
Fault getInterrupt(ThreadContext * tc)
@@ -109,84 +113,45 @@ class Interrupts
// 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;
+ if (interrupts[IT_HINTP]) {
+ // This will be cleaned by a HINTP write
+ return new HstickMatch;
}
- } else {
- if (interrupts[hstick_match]) {
- return NoFault;
+ if (interrupts[IT_INT_VEC]) {
+ // this will be cleared by an ASI read (or write)
+ return new InterruptVector;
}
-
}
} else {
- if (interrupts[trap_level_zero]) {
- if ((pstate & HPSTATE::tlz) && (tc->readMiscReg(MISCREG_TL) == 0)) {
- interrupts[trap_level_zero] = false;
- --numPosted;
+ if (interrupts[IT_TRAP_LEVEL_ZERO]) {
+ // this is cleared by deasserting HPSTATE::tlz
return new TrapLevelZero;
- }
}
- if (interrupts[hstick_match]) {
- if (tc->readMiscReg(MISCREG_HINTP) & 1) {
- interrupts[hstick_match] = false;
- --numPosted;
- return new HstickMatch;
- }
+ // HStick matches always happen in priv mode (ie doesn't matter)
+ if (interrupts[IT_HINTP]) {
+ return new HstickMatch;
+ }
+ if (interrupts[IT_INT_VEC]) {
+ // this will be cleared by an ASI read (or write)
+ return new InterruptVector;
}
if (ie) {
- if (interrupts[cpu_mondo]) {
- interrupts[cpu_mondo] = false;
- --numPosted;
+ if (interrupts[IT_CPU_MONDO]) {
return new CpuMondo;
}
- if (interrupts[dev_mondo]) {
- interrupts[dev_mondo] = false;
- --numPosted;
+ if (interrupts[IT_DEV_MONDO]) {
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[IT_SOFT_INT]) {
+ return new
+ InterruptLevelN(InterruptLevel(interrupts[IT_SOFT_INT]));
}
- if (interrupts[resumable_error]) {
- interrupts[resumable_error] = false;
- --numPosted;
+
+ if (interrupts[IT_RES_ERROR]) {
return new ResumableError;
}
- }
- }
+ } // !hpriv && ie
+ } // !hpriv
return NoFault;
}
@@ -195,16 +160,22 @@ class Interrupts
}
+ uint64_t get_vec(int int_num)
+ {
+ assert(int_num >= 0 && int_num < NumInterruptTypes);
+ return interrupts[int_num];
+ }
+
void serialize(std::ostream &os)
{
- SERIALIZE_ARRAY(interrupts,num_interrupt_types);
- SERIALIZE_SCALAR(numPosted);
+ SERIALIZE_ARRAY(interrupts,NumInterruptTypes);
+ SERIALIZE_SCALAR(intStatus);
}
void unserialize(Checkpoint *cp, const std::string &section)
{
- UNSERIALIZE_ARRAY(interrupts,num_interrupt_types);
- UNSERIALIZE_SCALAR(numPosted);
+ UNSERIALIZE_ARRAY(interrupts,NumInterruptTypes);
+ UNSERIALIZE_SCALAR(intStatus);
}
};
} // namespace SPARC_ISA
diff --git a/src/arch/sparc/isa_traits.hh b/src/arch/sparc/isa_traits.hh
index 1fbdd160d..d0b8827f3 100644
--- a/src/arch/sparc/isa_traits.hh
+++ b/src/arch/sparc/isa_traits.hh
@@ -113,6 +113,18 @@ namespace SparcISA
const Addr PAddrImplMask = ULL(0x000000FFFFFFFFFF);
const Addr BytesInPageMask = ULL(0x1FFF);
+ enum InterruptTypes
+ {
+ IT_TRAP_LEVEL_ZERO,
+ IT_HINTP,
+ IT_INT_VEC,
+ IT_CPU_MONDO,
+ IT_DEV_MONDO,
+ IT_RES_ERROR,
+ IT_SOFT_INT,
+ NumInterruptTypes
+ };
+
#endif
}
diff --git a/src/arch/sparc/linux/process.cc b/src/arch/sparc/linux/process.cc
index 9c7c0e643..10cde3af8 100644
--- a/src/arch/sparc/linux/process.cc
+++ b/src/arch/sparc/linux/process.cc
@@ -333,7 +333,7 @@ SyscallDesc SparcLinuxProcess::syscallDescs[] = {
/* 233 */ SyscallDesc("stime", unimplementedFunc),
/* 234 */ SyscallDesc("statfs64", unimplementedFunc),
/* 235 */ SyscallDesc("fstatfs64", unimplementedFunc),
- /* 236 */ SyscallDesc("_llseek", unimplementedFunc),
+ /* 236 */ SyscallDesc("_llseek", _llseekFunc),
/* 237 */ SyscallDesc("mlock", unimplementedFunc),
/* 238 */ SyscallDesc("munlock", unimplementedFunc),
/* 239 */ SyscallDesc("mlockall", unimplementedFunc),
diff --git a/src/arch/sparc/miscregfile.cc b/src/arch/sparc/miscregfile.cc
index 9a69d3374..849eed1cc 100644
--- a/src/arch/sparc/miscregfile.cc
+++ b/src/arch/sparc/miscregfile.cc
@@ -54,7 +54,15 @@ string SparcISA::getMiscRegName(RegIndex index)
"wstate",*/ "gl",
"hpstate", "htstate", "hintp", "htba", "hver", "strand_sts_reg",
"hstick_cmpr",
- "fsr"};
+ "fsr", "prictx", "secctx", "partId", "lsuCtrlReg", "itbTsbC0Ps0",
+ "itbTsbC0Ps1", "iTlbC0Cnfg", "itbTsbCXPs0", "itbTsbCXPs1",
+ "iTlbCXCnfg","iTlbSfsr", "iTlbTagAcs", "dtbTsbC0Ps0",
+ "dtbTsbC0Ps1", "dTlbC0Cnfg", "dtbTsbCXPs0", "dtbTsbCXPs1",
+ "dTlbCXCnfg","dTlbSfsr", "dTlbSfar", "dTlbTagAcs",
+ "scratch0", "scratch1", "scratch2", "scratch3", "scratch4",
+ "scratch5", "scratch6", "scratch7", "cpuMondoHead", "cpuMondoTail",
+ "devMondoHead", "devMondoTail", "resErrorHead", "resErrorTail",
+ "nresErrorHead", "nresErrorTail", "TlbData" };
return miscRegName[index];
}
@@ -608,7 +616,6 @@ void MiscRegFile::setReg(int miscReg, const MiscReg &val)
case MISCREG_QUEUE_NRES_ERROR_TAIL:
nres_error_tail = val;
break;
-
default:
panic("Miscellaneous register %d not implemented\n", miscReg);
}
@@ -639,6 +646,12 @@ void MiscRegFile::setRegWithEffect(int miscReg,
return;
case MISCREG_TL:
tl = val;
+#if FULL_SYSTEM
+ if (hpstate & HPSTATE::tlz && tl == 0 && !(hpstate & HPSTATE::hpriv))
+ tc->getCpuPtr()->post_interrupt(IT_TRAP_LEVEL_ZERO,0);
+ else
+ tc->getCpuPtr()->clear_interrupt(IT_TRAP_LEVEL_ZERO,0);
+#endif
return;
case MISCREG_CWP:
new_val = val > NWindows ? NWindows - 1 : val;
diff --git a/src/arch/sparc/miscregfile.hh b/src/arch/sparc/miscregfile.hh
index 66c9f17df..4207de823 100644
--- a/src/arch/sparc/miscregfile.hh
+++ b/src/arch/sparc/miscregfile.hh
@@ -259,6 +259,9 @@ namespace SparcISA
ThreadContext *tc);
MiscReg readFSRegWithEffect(int miscReg, ThreadContext * tc);
+ // Update interrupt state on softint or pil change
+ void checkSoftInt(ThreadContext *tc);
+
/** Process a tick compare event and generate an interrupt on the cpu if
* appropriate. */
void processTickCompare(ThreadContext *tc);
diff --git a/src/arch/sparc/process.cc b/src/arch/sparc/process.cc
index d5a95e0c0..c3b833562 100644
--- a/src/arch/sparc/process.cc
+++ b/src/arch/sparc/process.cc
@@ -425,7 +425,9 @@ Sparc32LiveProcess::argsInit(int intSize, int pageSize)
else
filename = argv[0];
- Addr alignmentMask = ~(intSize - 1);
+ //Even though this is a 32 bit process, the ABI says we still need to
+ //maintain double word alignment of the stack pointer.
+ Addr alignmentMask = ~(8 - 1);
// load object file into target memory
objFile->loadSections(initVirtMem);
@@ -525,21 +527,11 @@ Sparc32LiveProcess::argsInit(int intSize, int pageSize)
arg_data_size += argv[i].size() + 1;
}
- //The info_block needs to be padded so it's size is a multiple of the
- //alignment mask. Also, it appears that there needs to be at least some
- //padding, so if the size is already a multiple, we need to increase it
- //anyway.
+ //The info_block
int info_block_size =
(file_name_size +
env_data_size +
- arg_data_size +
- intSize) & alignmentMask;
-
- int info_block_padding =
- info_block_size -
- file_name_size -
- env_data_size -
- arg_data_size;
+ arg_data_size);
//Each auxilliary vector is two 8 byte words
int aux_array_size = intSize * 2 * (auxv.size() + 1);
@@ -552,7 +544,6 @@ Sparc32LiveProcess::argsInit(int intSize, int pageSize)
int space_needed =
mysterious_size +
- info_block_size +
aux_array_size +
envp_array_size +
argv_array_size +
@@ -568,18 +559,17 @@ Sparc32LiveProcess::argsInit(int intSize, int pageSize)
roundUp(stack_size, pageSize));
// map out initial stack contents
- Addr mysterious_base = stack_base - mysterious_size;
- Addr file_name_base = mysterious_base - file_name_size;
- Addr env_data_base = file_name_base - env_data_size;
- Addr arg_data_base = env_data_base - arg_data_size;
- Addr auxv_array_base = arg_data_base - aux_array_size - info_block_padding;
- Addr envp_array_base = auxv_array_base - envp_array_size;
- Addr argv_array_base = envp_array_base - argv_array_size;
- Addr argc_base = argv_array_base - argc_size;
-#ifndef NDEBUG
- // only used in DPRINTF
- Addr window_save_base = argc_base - window_save_size;
-#endif
+ uint32_t window_save_base = stack_min;
+ uint32_t argc_base = window_save_base + window_save_size;
+ uint32_t argv_array_base = argc_base + argc_size;
+ uint32_t envp_array_base = argv_array_base + argv_array_size;
+ uint32_t auxv_array_base = envp_array_base + envp_array_size;
+ //The info block is pushed up against the top of the stack, while
+ //the rest of the initial stack frame is aligned to an 8 byte boudary.
+ uint32_t arg_data_base = stack_base - info_block_size;
+ uint32_t env_data_base = arg_data_base + arg_data_size;
+ uint32_t file_name_base = env_data_base + env_data_size;
+ uint32_t mysterious_base = file_name_base + file_name_size;
DPRINTF(Sparc, "The addresses of items on the initial stack:\n");
DPRINTF(Sparc, "0x%x - file name\n", file_name_base);
@@ -619,8 +609,8 @@ Sparc32LiveProcess::argsInit(int intSize, int pageSize)
initVirtMem->writeBlob(auxv_array_base + 2 * intSize * auxv.size(),
(uint8_t*)&zero, 2 * intSize);
- copyStringArray(envp, envp_array_base, env_data_base, initVirtMem, intSize);
- copyStringArray(argv, argv_array_base, arg_data_base, initVirtMem, intSize);
+ copyStringArray(envp, envp_array_base, env_data_base, initVirtMem);
+ copyStringArray(argv, argv_array_base, arg_data_base, initVirtMem);
initVirtMem->writeBlob(argc_base, (uint8_t*)&guestArgc, intSize);
@@ -639,7 +629,7 @@ Sparc32LiveProcess::argsInit(int intSize, int pageSize)
threadContexts[0]->setIntReg(ArgumentReg1, argv_array_base);
threadContexts[0]->setIntReg(StackPointerReg, stack_min);
- Addr prog_entry = objFile->entryPoint();
+ uint32_t prog_entry = objFile->entryPoint();
threadContexts[0]->setPC(prog_entry);
threadContexts[0]->setNextPC(prog_entry + sizeof(MachInst));
threadContexts[0]->setNextNPC(prog_entry + (2 * sizeof(MachInst)));
diff --git a/src/arch/sparc/regfile.cc b/src/arch/sparc/regfile.cc
index 827e22c31..944b1f401 100644
--- a/src/arch/sparc/regfile.cc
+++ b/src/arch/sparc/regfile.cc
@@ -254,19 +254,6 @@ void RegFile::changeContext(RegContextParam param, RegContextVal val)
}
}
-int SparcISA::InterruptLevel(uint64_t softint)
-{
- if (softint & 0x10000 || softint & 0x1)
- return 14;
-
- int level = 15;
- while (level > 0 && !(1 << level & softint))
- level--;
- if (1 << level & softint)
- return level;
- return 0;
-}
-
void SparcISA::copyMiscRegs(ThreadContext *src, ThreadContext *dest)
{
diff --git a/src/arch/sparc/regfile.hh b/src/arch/sparc/regfile.hh
index d9af0757c..9e0b3beb3 100644
--- a/src/arch/sparc/regfile.hh
+++ b/src/arch/sparc/regfile.hh
@@ -126,8 +126,6 @@ namespace SparcISA
void copyMiscRegs(ThreadContext *src, ThreadContext *dest);
- int InterruptLevel(uint64_t softint);
-
} // namespace SparcISA
#endif
diff --git a/src/arch/sparc/tlb.cc b/src/arch/sparc/tlb.cc
index 2dca6d5e7..41d55158e 100644
--- a/src/arch/sparc/tlb.cc
+++ b/src/arch/sparc/tlb.cc
@@ -40,6 +40,7 @@
#include "mem/packet_access.hh"
#include "mem/request.hh"
#include "sim/builder.hh"
+#include "sim/system.hh"
/* @todo remove some of the magic constants. -- ali
* */
@@ -691,9 +692,9 @@ DTB::translate(RequestPtr &req, ThreadContext *tc, bool write)
if (AsiIsPartialStore(asi))
panic("Partial Store ASIs not supported\n");
- if (AsiIsInterrupt(asi))
- panic("Interrupt ASIs not supported\n");
+ if (AsiIsInterrupt(asi))
+ goto handleIntRegAccess;
if (AsiIsMmu(asi))
goto handleMmuRegAccess;
if (AsiIsScratchPad(asi))
@@ -793,7 +794,25 @@ DTB::translate(RequestPtr &req, ThreadContext *tc, bool write)
vaddr & e->pte.size()-1);
DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr());
return NoFault;
+
/** Normal flow ends here. */
+handleIntRegAccess:
+ if (!hpriv) {
+ writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi);
+ if (priv)
+ return new DataAccessException;
+ else
+ return new PrivilegedAction;
+ }
+
+ if (asi == ASI_SWVR_UDB_INTR_W && !write ||
+ asi == ASI_SWVR_UDB_INTR_R && write) {
+ writeSfr(tc, vaddr, write, Primary, true, IllegalAsi, asi);
+ return new DataAccessException;
+ }
+
+ goto regAccessOk;
+
handleScratchRegAccess:
if (vaddr > 0x38 || (vaddr >= 0x20 && vaddr < 0x30 && !hpriv)) {
@@ -988,7 +1007,14 @@ DTB::doMmuRegRead(ThreadContext *tc, Packet *pkt)
tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_TSB_PS1),
tc->readMiscRegWithEffect(MISCREG_MMU_ITLB_CX_CONFIG)));
break;
-
+ case ASI_SWVR_INTR_RECEIVE:
+ pkt->set(tc->getCpuPtr()->get_interrupts(IT_INT_VEC));
+ break;
+ case ASI_SWVR_UDB_INTR_R:
+ temp = findMsbSet(tc->getCpuPtr()->get_interrupts(IT_INT_VEC));
+ tc->getCpuPtr()->clear_interrupt(IT_INT_VEC, temp);
+ pkt->set(temp);
+ break;
default:
doMmuReadError:
panic("need to impl DTB::doMmuRegRead() got asi=%#x, va=%#x\n",
@@ -1222,7 +1248,19 @@ DTB::doMmuRegWrite(ThreadContext *tc, Packet *pkt)
panic("Invalid type for IMMU demap\n");
}
break;
- default:
+ case ASI_SWVR_INTR_RECEIVE:
+ int msb;
+ // clear all the interrupts that aren't set in the write
+ while(tc->getCpuPtr()->get_interrupts(IT_INT_VEC) & data) {
+ msb = findMsbSet(tc->getCpuPtr()->get_interrupts(IT_INT_VEC) & data);
+ tc->getCpuPtr()->clear_interrupt(IT_INT_VEC, msb);
+ }
+ break;
+ case ASI_SWVR_UDB_INTR_W:
+ tc->getSystemPtr()->threadContexts[bits(data,12,8)]->getCpuPtr()->
+ post_interrupt(bits(data,5,0),0);
+ break;
+ default:
doMmuWriteError:
panic("need to impl DTB::doMmuRegWrite() got asi=%#x, va=%#x d=%#x\n",
(uint32_t)pkt->req->getAsi(), pkt->getAddr(), data);
diff --git a/src/arch/sparc/ua2005.cc b/src/arch/sparc/ua2005.cc
index ecb63bb9a..5b13cd041 100644
--- a/src/arch/sparc/ua2005.cc
+++ b/src/arch/sparc/ua2005.cc
@@ -34,6 +34,30 @@
using namespace SparcISA;
+
+void
+MiscRegFile::checkSoftInt(ThreadContext *tc)
+{
+ // If PIL < 14, copy over the tm and sm bits
+ if (pil < 14 && softint & 0x10000)
+ tc->getCpuPtr()->post_interrupt(IT_SOFT_INT,16);
+ else
+ tc->getCpuPtr()->clear_interrupt(IT_SOFT_INT,16);
+ if (pil < 14 && softint & 0x1)
+ tc->getCpuPtr()->post_interrupt(IT_SOFT_INT,0);
+ else
+ tc->getCpuPtr()->clear_interrupt(IT_SOFT_INT,0);
+
+ // Copy over any of the other bits that are set
+ for (int bit = 15; bit > 0; --bit) {
+ if (1 << bit & softint && bit > pil)
+ tc->getCpuPtr()->post_interrupt(IT_SOFT_INT,bit);
+ else
+ tc->getCpuPtr()->clear_interrupt(IT_SOFT_INT,bit);
+ }
+}
+
+
void
MiscRegFile::setFSRegWithEffect(int miscReg, const MiscReg &val,
ThreadContext *tc)
@@ -43,23 +67,25 @@ MiscRegFile::setFSRegWithEffect(int miscReg, const MiscReg &val,
/* Full system only ASRs */
case MISCREG_SOFTINT:
setReg(miscReg, val);;
+ checkSoftInt(tc);
break;
-
case MISCREG_SOFTINT_CLR:
return setRegWithEffect(MISCREG_SOFTINT, ~val & softint, tc);
case MISCREG_SOFTINT_SET:
- 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())
+ if ((tick_cmpr & ~mask(63)) && tickCompare->scheduled())
tickCompare->deschedule();
time = (tick_cmpr & mask(63)) - (tick & mask(63));
- if (!(tick_cmpr & ~mask(63)) && time > 0)
+ if (!(tick_cmpr & ~mask(63)) && time > 0) {
+ if (tickCompare->scheduled())
+ tickCompare->deschedule();
tickCompare->schedule(time * tc->getCpuPtr()->cycles(1));
+ }
panic("writing to TICK compare register %#X\n", val);
break;
@@ -71,8 +97,11 @@ MiscRegFile::setFSRegWithEffect(int miscReg, const MiscReg &val,
sTickCompare->deschedule();
time = ((int64_t)(stick_cmpr & mask(63)) - (int64_t)stick) -
tc->getCpuPtr()->instCount();
- if (!(stick_cmpr & ~mask(63)) && time > 0)
+ if (!(stick_cmpr & ~mask(63)) && time > 0) {
+ if (sTickCompare->scheduled())
+ sTickCompare->deschedule();
sTickCompare->schedule(time * tc->getCpuPtr()->cycles(1) + curTick);
+ }
DPRINTF(Timer, "writing to sTICK compare register value %#X\n", val);
break;
@@ -81,6 +110,7 @@ MiscRegFile::setFSRegWithEffect(int miscReg, const MiscReg &val,
case MISCREG_PIL:
setReg(miscReg, val);
+ checkSoftInt(tc);
break;
case MISCREG_HVER:
@@ -88,6 +118,11 @@ MiscRegFile::setFSRegWithEffect(int miscReg, const MiscReg &val,
case MISCREG_HINTP:
setReg(miscReg, val);
+ if (hintp)
+ tc->getCpuPtr()->post_interrupt(IT_HINTP,0);
+ else
+ tc->getCpuPtr()->clear_interrupt(IT_HINTP,0);
+ break;
case MISCREG_HTBA:
// clear lower 7 bits on writes.
@@ -96,14 +131,32 @@ MiscRegFile::setFSRegWithEffect(int miscReg, const MiscReg &val,
case MISCREG_QUEUE_CPU_MONDO_HEAD:
case MISCREG_QUEUE_CPU_MONDO_TAIL:
+ setReg(miscReg, val);
+ if (cpu_mondo_head != cpu_mondo_tail)
+ tc->getCpuPtr()->post_interrupt(IT_CPU_MONDO,0);
+ else
+ tc->getCpuPtr()->clear_interrupt(IT_CPU_MONDO,0);
+ break;
case MISCREG_QUEUE_DEV_MONDO_HEAD:
case MISCREG_QUEUE_DEV_MONDO_TAIL:
+ setReg(miscReg, val);
+ if (dev_mondo_head != dev_mondo_tail)
+ tc->getCpuPtr()->post_interrupt(IT_DEV_MONDO,0);
+ else
+ tc->getCpuPtr()->clear_interrupt(IT_DEV_MONDO,0);
+ break;
case MISCREG_QUEUE_RES_ERROR_HEAD:
case MISCREG_QUEUE_RES_ERROR_TAIL:
+ setReg(miscReg, val);
+ if (res_error_head != res_error_tail)
+ tc->getCpuPtr()->post_interrupt(IT_RES_ERROR,0);
+ else
+ tc->getCpuPtr()->clear_interrupt(IT_RES_ERROR,0);
+ break;
case MISCREG_QUEUE_NRES_ERROR_HEAD:
case MISCREG_QUEUE_NRES_ERROR_TAIL:
setReg(miscReg, val);
- //do something to post mondo interrupt
+ // This one doesn't have an interrupt to report to the guest OS
break;
case MISCREG_HSTICK_CMPR:
@@ -114,14 +167,23 @@ MiscRegFile::setFSRegWithEffect(int miscReg, const MiscReg &val,
hSTickCompare->deschedule();
time = ((int64_t)(hstick_cmpr & mask(63)) - (int64_t)stick) -
tc->getCpuPtr()->instCount();
- if (!(hstick_cmpr & ~mask(63)) && time > 0)
+ if (!(hstick_cmpr & ~mask(63)) && time > 0) {
+ if (hSTickCompare->scheduled())
+ hSTickCompare->deschedule();
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);
+#if FULL_SYSTEM
+ if (hpstate & HPSTATE::tlz && tl == 0 && !(hpstate & HPSTATE::hpriv))
+ tc->getCpuPtr()->post_interrupt(IT_TRAP_LEVEL_ZERO,0);
+ else
+ tc->getCpuPtr()->clear_interrupt(IT_TRAP_LEVEL_ZERO,0);
+#endif
break;
case MISCREG_HTSTATE:
case MISCREG_STRAND_STS_REG:
@@ -198,7 +260,6 @@ MiscRegFile::processSTickCompare(ThreadContext *tc)
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);
setRegWithEffect(MISCREG_SOFTINT, softint | (ULL(1) << 16), tc);
}
} else
@@ -221,10 +282,9 @@ MiscRegFile::processHSTickCompare(ThreadContext *tc)
(stick_cmpr & mask(63)));
if (!(tc->readMiscReg(MISCREG_HSTICK_CMPR) & (ULL(1) << 63))) {
setRegWithEffect(MISCREG_HINTP, 1, tc);
- tc->getCpuPtr()->post_interrupt(hstick_match);
}
// Need to do something to cause interrupt to happen here !!! @todo
} else
- sTickCompare->schedule(ticks * tc->getCpuPtr()->cycles(1) + curTick);
+ hSTickCompare->schedule(ticks * tc->getCpuPtr()->cycles(1) + curTick);
}