diff options
author | Ali Saidi <saidi@eecs.umich.edu> | 2007-03-03 19:03:22 -0500 |
---|---|---|
committer | Ali Saidi <saidi@eecs.umich.edu> | 2007-03-03 19:03:22 -0500 |
commit | 82874eefca231fa960fbd39a90ed98929915c414 (patch) | |
tree | 8646c2358edec660d123e45d20885a366d0815de /src | |
parent | 61178c8de20d334e9c5cf0454d453880a5fff928 (diff) | |
parent | 1694c65ba169a555bd642d3352c65be41a36ce4d (diff) | |
download | gem5-82874eefca231fa960fbd39a90ed98929915c414.tar.xz |
Merge zizzer:/bk/newmem
into zeep.pool:/z/saidi/work/m5.newmem
--HG--
extra : convert_revision : fd6464c9883783c7c2cbefba317f4a0f20dd24cb
Diffstat (limited to 'src')
-rw-r--r-- | src/arch/alpha/interrupts.hh | 12 | ||||
-rw-r--r-- | src/arch/sparc/asi.cc | 3 | ||||
-rw-r--r-- | src/arch/sparc/faults.cc | 4 | ||||
-rw-r--r-- | src/arch/sparc/faults.hh | 2 | ||||
-rw-r--r-- | src/arch/sparc/interrupts.hh | 163 | ||||
-rw-r--r-- | src/arch/sparc/isa_traits.hh | 12 | ||||
-rw-r--r-- | src/arch/sparc/miscregfile.cc | 17 | ||||
-rw-r--r-- | src/arch/sparc/miscregfile.hh | 3 | ||||
-rw-r--r-- | src/arch/sparc/regfile.cc | 13 | ||||
-rw-r--r-- | src/arch/sparc/regfile.hh | 2 | ||||
-rw-r--r-- | src/arch/sparc/tlb.cc | 46 | ||||
-rw-r--r-- | src/arch/sparc/ua2005.cc | 80 | ||||
-rw-r--r-- | src/base/bitfield.hh | 25 | ||||
-rw-r--r-- | src/cpu/base.cc | 11 | ||||
-rw-r--r-- | src/cpu/base.hh | 2 | ||||
-rw-r--r-- | src/cpu/intr_control.cc | 22 | ||||
-rw-r--r-- | src/cpu/intr_control.hh | 4 | ||||
-rw-r--r-- | src/dev/alpha/tsunami_cchip.cc | 12 | ||||
-rw-r--r-- | src/dev/sparc/SConscript | 1 | ||||
-rw-r--r-- | src/dev/sparc/iob.cc | 366 | ||||
-rw-r--r-- | src/dev/sparc/iob.hh | 153 | ||||
-rw-r--r-- | src/python/m5/objects/IntrControl.py | 2 | ||||
-rw-r--r-- | src/python/m5/objects/T1000.py | 20 |
23 files changed, 806 insertions, 169 deletions
diff --git a/src/arch/alpha/interrupts.hh b/src/arch/alpha/interrupts.hh index a522dec6c..0500714ad 100644 --- a/src/arch/alpha/interrupts.hh +++ b/src/arch/alpha/interrupts.hh @@ -34,6 +34,7 @@ #include "arch/alpha/faults.hh" #include "arch/alpha/isa_traits.hh" +#include "base/compiler.hh" #include "cpu/thread_context.hh" namespace AlphaISA @@ -52,11 +53,6 @@ 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); @@ -163,6 +159,12 @@ namespace AlphaISA newInfoSet = false; } + uint64_t get_vec(int int_num) + { + panic("Shouldn't be called for Alpha\n"); + M5_DUMMY_RETURN + } + private: bool newInfoSet; int newIpl; 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 §ion) { - 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/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/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); } diff --git a/src/base/bitfield.hh b/src/base/bitfield.hh index 0f1233677..83b9138b4 100644 --- a/src/base/bitfield.hh +++ b/src/base/bitfield.hh @@ -112,4 +112,29 @@ replaceBits(T& val, int first, int last, B bit_val) val = insertBits(val, first, last, bit_val); } +/** + * Returns the bit position of the MSB that is set in the input + */ +inline +int +findMsbSet(uint64_t val) { + int msb = 0; + if (!val) + return 0; + if (bits(val, 63,32)) msb += 32; + val >>= 32; + if (bits(val, 31,16)) msb += 16; + val >>= 16; + if (bits(val, 15,8)) msb += 8; + val >>= 8; + if (bits(val, 7,4)) msb += 4; + val >>= 4; + if (bits(val, 3,2)) msb += 2; + val >>= 2; + if (bits(val, 1,1)) msb += 1; + return msb; +} + + + #endif // __BASE_BITFIELD_HH__ diff --git a/src/cpu/base.cc b/src/cpu/base.cc index d5a023c59..104b3b6bb 100644 --- a/src/cpu/base.cc +++ b/src/cpu/base.cc @@ -372,12 +372,6 @@ BaseCPU::ProfileEvent::process() } void -BaseCPU::post_interrupt(int int_type) -{ - interrupts.post(int_type); -} - -void BaseCPU::post_interrupt(int int_num, int index) { interrupts.post(int_num, index); @@ -395,6 +389,11 @@ BaseCPU::clear_interrupts() interrupts.clear_all(); } +uint64_t +BaseCPU::get_interrupts(int int_num) +{ + return interrupts.get_vec(int_num); +} void BaseCPU::serialize(std::ostream &os) diff --git a/src/cpu/base.hh b/src/cpu/base.hh index a1265b748..d4213887d 100644 --- a/src/cpu/base.hh +++ b/src/cpu/base.hh @@ -102,10 +102,10 @@ 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(); + virtual uint64_t get_interrupts(int int_num); bool check_interrupts(ThreadContext * tc) const { return interrupts.check_interrupts(tc); } diff --git a/src/cpu/intr_control.cc b/src/cpu/intr_control.cc index 4cbc86891..be0f6599b 100644 --- a/src/cpu/intr_control.cc +++ b/src/cpu/intr_control.cc @@ -40,18 +40,14 @@ using namespace std; -IntrControl::IntrControl(const string &name, BaseCPU *c) - : SimObject(name), cpu(c) +IntrControl::IntrControl(const string &name, System *s) + : SimObject(name), sys(s) {} -/* @todo - *Fix the cpu sim object parameter to be a system pointer - *instead, to avoid some extra dereferencing - */ void IntrControl::post(int int_num, int index) { - std::vector<ThreadContext *> &tcvec = cpu->system->threadContexts; + std::vector<ThreadContext *> &tcvec = sys->threadContexts; BaseCPU *temp = tcvec[0]->getCpuPtr(); temp->post_interrupt(int_num, index); } @@ -59,7 +55,7 @@ IntrControl::post(int int_num, int index) void IntrControl::post(int cpu_id, int int_num, int index) { - std::vector<ThreadContext *> &tcvec = cpu->system->threadContexts; + std::vector<ThreadContext *> &tcvec = sys->threadContexts; BaseCPU *temp = tcvec[cpu_id]->getCpuPtr(); temp->post_interrupt(int_num, index); } @@ -67,7 +63,7 @@ IntrControl::post(int cpu_id, int int_num, int index) void IntrControl::clear(int int_num, int index) { - std::vector<ThreadContext *> &tcvec = cpu->system->threadContexts; + std::vector<ThreadContext *> &tcvec = sys->threadContexts; BaseCPU *temp = tcvec[0]->getCpuPtr(); temp->clear_interrupt(int_num, index); } @@ -75,26 +71,26 @@ IntrControl::clear(int int_num, int index) void IntrControl::clear(int cpu_id, int int_num, int index) { - std::vector<ThreadContext *> &tcvec = cpu->system->threadContexts; + std::vector<ThreadContext *> &tcvec = sys->threadContexts; BaseCPU *temp = tcvec[cpu_id]->getCpuPtr(); temp->clear_interrupt(int_num, index); } BEGIN_DECLARE_SIM_OBJECT_PARAMS(IntrControl) - SimObjectParam<BaseCPU *> cpu; + SimObjectParam<System *> sys; END_DECLARE_SIM_OBJECT_PARAMS(IntrControl) BEGIN_INIT_SIM_OBJECT_PARAMS(IntrControl) - INIT_PARAM(cpu, "the cpu") + INIT_PARAM(sys, "the system we are part of") END_INIT_SIM_OBJECT_PARAMS(IntrControl) CREATE_SIM_OBJECT(IntrControl) { - return new IntrControl(getInstanceName(), cpu); + return new IntrControl(getInstanceName(), sys); } REGISTER_SIM_OBJECT("IntrControl", IntrControl) diff --git a/src/cpu/intr_control.hh b/src/cpu/intr_control.hh index 2e3f9e038..c6f75abf0 100644 --- a/src/cpu/intr_control.hh +++ b/src/cpu/intr_control.hh @@ -42,8 +42,8 @@ class IntrControl : public SimObject { public: - BaseCPU *cpu; - IntrControl(const std::string &name, BaseCPU *c); + System *sys; + IntrControl(const std::string &name, System *s); void clear(int int_num, int index = 0); void post(int int_num, int index = 0); diff --git a/src/dev/alpha/tsunami_cchip.cc b/src/dev/alpha/tsunami_cchip.cc index 15c47984b..118160adf 100644 --- a/src/dev/alpha/tsunami_cchip.cc +++ b/src/dev/alpha/tsunami_cchip.cc @@ -372,7 +372,7 @@ TsunamiCChip::write(PacketPtr pkt) void TsunamiCChip::clearIPI(uint64_t ipintr) { - int numcpus = tsunami->intrctrl->cpu->system->threadContexts.size(); + int numcpus = sys->threadContexts.size(); assert(numcpus <= Tsunami::Max_CPUs); if (ipintr) { @@ -398,7 +398,7 @@ TsunamiCChip::clearIPI(uint64_t ipintr) void TsunamiCChip::clearITI(uint64_t itintr) { - int numcpus = tsunami->intrctrl->cpu->system->threadContexts.size(); + int numcpus = sys->threadContexts.size(); assert(numcpus <= Tsunami::Max_CPUs); if (itintr) { @@ -418,7 +418,7 @@ TsunamiCChip::clearITI(uint64_t itintr) void TsunamiCChip::reqIPI(uint64_t ipreq) { - int numcpus = tsunami->intrctrl->cpu->system->threadContexts.size(); + int numcpus = sys->threadContexts.size(); assert(numcpus <= Tsunami::Max_CPUs); if (ipreq) { @@ -445,7 +445,7 @@ TsunamiCChip::reqIPI(uint64_t ipreq) void TsunamiCChip::postRTC() { - int size = tsunami->intrctrl->cpu->system->threadContexts.size(); + int size = sys->threadContexts.size(); assert(size <= Tsunami::Max_CPUs); for (int i = 0; i < size; i++) { @@ -463,7 +463,7 @@ void TsunamiCChip::postDRIR(uint32_t interrupt) { uint64_t bitvector = ULL(1) << interrupt; - uint64_t size = tsunami->intrctrl->cpu->system->threadContexts.size(); + uint64_t size = sys->threadContexts.size(); assert(size <= Tsunami::Max_CPUs); drir |= bitvector; @@ -481,7 +481,7 @@ void TsunamiCChip::clearDRIR(uint32_t interrupt) { uint64_t bitvector = ULL(1) << interrupt; - uint64_t size = tsunami->intrctrl->cpu->system->threadContexts.size(); + uint64_t size = sys->threadContexts.size(); assert(size <= Tsunami::Max_CPUs); if (drir & bitvector) diff --git a/src/dev/sparc/SConscript b/src/dev/sparc/SConscript index 44b082b68..4d63690c2 100644 --- a/src/dev/sparc/SConscript +++ b/src/dev/sparc/SConscript @@ -38,6 +38,7 @@ sources = [] sources += Split(''' dtod.cc + iob.cc t1000.cc mm_disk.cc ''') diff --git a/src/dev/sparc/iob.cc b/src/dev/sparc/iob.cc new file mode 100644 index 000000000..b8caff7e9 --- /dev/null +++ b/src/dev/sparc/iob.cc @@ -0,0 +1,366 @@ +/* + * 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 implemetns the niagara I/O bridge chip. It manages incomming + * interrupts and posts them to the CPU when needed. It holds mask registers and + * various status registers for CPUs to check what interrupts are pending as + * well as facilities to send IPIs to other cpus. + */ + +#include <cstring> + +#include "arch/sparc/isa_traits.hh" +#include "base/trace.hh" +#include "cpu/intr_control.hh" +#include "dev/sparc/iob.hh" +#include "dev/platform.hh" +#include "mem/port.hh" +#include "mem/packet_access.hh" +#include "sim/builder.hh" +#include "sim/system.hh" + +Iob::Iob(Params *p) + : PioDevice(p), ic(p->platform->intrctrl) +{ + iobManAddr = ULL(0x9800000000); + iobManSize = ULL(0x0100000000); + iobJBusAddr = ULL(0x9F00000000); + iobJBusSize = ULL(0x0100000000); + assert (params()->system->threadContexts.size() <= MaxNiagaraProcs); + // Get the interrupt controller from the platform + ic = platform->intrctrl; + + for (int x = 0; x < NumDeviceIds; ++x) { + intMan[x].cpu = 0; + intMan[x].vector = 0; + intCtl[x].mask = true; + intCtl[x].pend = false; + } + +} + +Tick +Iob::read(PacketPtr pkt) +{ + assert(pkt->result == Packet::Unknown); + + if (pkt->getAddr() >= iobManAddr && pkt->getAddr() < iobManAddr + iobManSize) + readIob(pkt); + else if (pkt->getAddr() >= iobJBusAddr && pkt->getAddr() < iobJBusAddr+iobJBusSize) + readJBus(pkt); + else + panic("Invalid address reached Iob\n"); + + pkt->result = Packet::Success; + return pioDelay; +} + +void +Iob::readIob(PacketPtr pkt) +{ + Addr accessAddr = pkt->getAddr() - iobManAddr; + int index; + uint64_t data; + + if (accessAddr >= IntManAddr && accessAddr < IntManAddr + IntManSize) { + index = (accessAddr - IntManAddr) >> 3; + data = intMan[index].cpu << 8 | intMan[index].vector << 0; + pkt->set(data); + return; + } + + if (accessAddr >= IntCtlAddr && accessAddr < IntCtlAddr + IntCtlSize) { + index = (accessAddr - IntManAddr) >> 3; + data = intCtl[index].mask ? 1 << 2 : 0 | + intCtl[index].pend ? 1 << 0 : 0; + pkt->set(data); + return; + } + + if (accessAddr == JIntVecAddr) { + pkt->set(jIntVec); + return; + } + + panic("Read to unknown IOB offset 0x%x\n", accessAddr); +} + +void +Iob::readJBus(PacketPtr pkt) +{ + Addr accessAddr = pkt->getAddr() - iobJBusAddr; + int cpuid = pkt->req->getCpuNum(); + int index; + uint64_t data; + + + + + if (accessAddr >= JIntData0Addr && accessAddr < JIntData1Addr) { + index = (accessAddr - JIntData0Addr) >> 3; + pkt->set(jBusData0[index]); + return; + } + + if (accessAddr >= JIntData1Addr && accessAddr < JIntDataA0Addr) { + index = (accessAddr - JIntData1Addr) >> 3; + pkt->set(jBusData1[index]); + return; + } + + if (accessAddr == JIntDataA0Addr) { + pkt->set(jBusData0[cpuid]); + return; + } + + if (accessAddr == JIntDataA1Addr) { + pkt->set(jBusData1[cpuid]); + return; + } + + if (accessAddr >= JIntBusyAddr && accessAddr < JIntBusyAddr + JIntBusySize) { + index = (accessAddr - JIntBusyAddr) >> 3; + data = jIntBusy[index].busy ? 1 << 5 : 0 | + jIntBusy[index].source; + pkt->set(data); + return; + } + if (accessAddr == JIntABusyAddr) { + data = jIntBusy[cpuid].busy ? 1 << 5 : 0 | + jIntBusy[cpuid].source; + pkt->set(data); + return; + }; + + panic("Read to unknown JBus offset 0x%x\n", accessAddr); +} + +Tick +Iob::write(PacketPtr pkt) +{ + if (pkt->getAddr() >= iobManAddr && pkt->getAddr() < iobManAddr + iobManSize) + writeIob(pkt); + else if (pkt->getAddr() >= iobJBusAddr && pkt->getAddr() < iobJBusAddr+iobJBusSize) + writeJBus(pkt); + else + panic("Invalid address reached Iob\n"); + + + pkt->result = Packet::Success; + return pioDelay; +} + +void +Iob::writeIob(PacketPtr pkt) +{ + Addr accessAddr = pkt->getAddr() - iobManAddr; + int index; + uint64_t data; + + if (accessAddr >= IntManAddr && accessAddr < IntManAddr + IntManSize) { + index = (accessAddr - IntManAddr) >> 3; + data = pkt->get<uint64_t>(); + intMan[index].cpu = bits(data,12,8); + intMan[index].vector = bits(data,5,0); + return; + } + + if (accessAddr >= IntCtlAddr && accessAddr < IntCtlAddr + IntCtlSize) { + index = (accessAddr - IntManAddr) >> 3; + data = pkt->get<uint64_t>(); + intCtl[index].mask = bits(data,2,2); + if (bits(data,1,1)) + intCtl[index].pend = false; + return; + } + + if (accessAddr == JIntVecAddr) { + jIntVec = bits(pkt->get<uint64_t>(), 5,0); + return; + } + + if (accessAddr >= IntVecDisAddr && accessAddr < IntVecDisAddr + IntVecDisSize) { + Type type; + int cpu_id; + int vector; + index = (accessAddr - IntManAddr) >> 3; + data = pkt->get<uint64_t>(); + type = (Type)bits(data,17,16); + cpu_id = bits(data, 12,8); + vector = bits(data,5,0); + generateIpi(type,cpu_id, vector); + return; + } + + panic("Write to unknown IOB offset 0x%x\n", accessAddr); +} + +void +Iob::writeJBus(PacketPtr pkt) +{ + Addr accessAddr = pkt->getAddr() - iobJBusAddr; + int cpuid = pkt->req->getCpuNum(); + int index; + uint64_t data; + + if (accessAddr >= JIntBusyAddr && accessAddr < JIntBusyAddr + JIntBusySize) { + index = (accessAddr - JIntBusyAddr) >> 3; + data = pkt->get<uint64_t>(); + jIntBusy[index].busy = bits(data,5,5); + return; + } + if (accessAddr == JIntABusyAddr) { + data = pkt->get<uint64_t>(); + jIntBusy[cpuid].busy = bits(data,5,5); + return; + }; + + panic("Write to unknown JBus offset 0x%x\n", accessAddr); +} + +void +Iob::receiveDeviceInterrupt(DeviceId devid) +{ + assert(devid < NumDeviceIds); + if (intCtl[devid].mask) + return; + intCtl[devid].mask = true; + intCtl[devid].pend = true; + ic->post(intMan[devid].cpu, SparcISA::IT_INT_VEC, intMan[devid].vector); +} + + +void +Iob::generateIpi(Type type, int cpu_id, int vector) +{ + // Only handle interrupts for the moment... Cpu Idle/reset/resume will be + // later + if (type != 0) { + warn("Ignoring IntVecDis write\n"); + return; + } + assert(type == 0); + ic->post(cpu_id, SparcISA::IT_INT_VEC, vector); +} + +bool +Iob::receiveJBusInterrupt(int cpu_id, int source, uint64_t d0, uint64_t d1) +{ + // If we are already dealing with an interrupt for that cpu we can't deal + // with another one right now... come back later + if (jIntBusy[cpu_id].busy) + return false; + + jIntBusy[cpu_id].busy = true; + jIntBusy[cpu_id].source = source; + jBusData0[cpu_id] = d0; + jBusData1[cpu_id] = d1; + + ic->post(cpu_id, SparcISA::IT_INT_VEC, jIntVec); + return true; +} + +void +Iob::addressRanges(AddrRangeList &range_list) +{ + range_list.clear(); + range_list.push_back(RangeSize(iobManAddr, iobManSize)); + range_list.push_back(RangeSize(iobJBusAddr, iobJBusSize)); +} + + +void +Iob::serialize(std::ostream &os) +{ + + SERIALIZE_SCALAR(jIntVec); + SERIALIZE_ARRAY(jBusData0, MaxNiagaraProcs); + SERIALIZE_ARRAY(jBusData1, MaxNiagaraProcs); + for (int x = 0; x < NumDeviceIds; x++) { + nameOut(os, csprintf("%s.Int%d", name(), x)); + paramOut(os, "cpu", intMan[x].cpu); + paramOut(os, "vector", intMan[x].vector); + paramOut(os, "mask", intCtl[x].mask); + paramOut(os, "pend", intCtl[x].pend); + }; + for (int x = 0; x < MaxNiagaraProcs; x++) { + nameOut(os, csprintf("%s.jIntBusy%d", name(), x)); + paramOut(os, "busy", jIntBusy[x].busy); + paramOut(os, "source", jIntBusy[x].source); + }; +} + +void +Iob::unserialize(Checkpoint *cp, const std::string §ion) +{ + UNSERIALIZE_SCALAR(jIntVec); + UNSERIALIZE_ARRAY(jBusData0, MaxNiagaraProcs); + UNSERIALIZE_ARRAY(jBusData1, MaxNiagaraProcs); + for (int x = 0; x < NumDeviceIds; x++) { + paramIn(cp, csprintf("%s.Int%d", name(), x), "cpu", intMan[x].cpu); + paramIn(cp, csprintf("%s.Int%d", name(), x), "vector", intMan[x].vector); + paramIn(cp, csprintf("%s.Int%d", name(), x), "mask", intCtl[x].mask); + paramIn(cp, csprintf("%s.Int%d", name(), x), "pend", intCtl[x].pend); + }; + for (int x = 0; x < MaxNiagaraProcs; x++) { + paramIn(cp, csprintf("%s.jIntBusy%d", name(), x), "busy", jIntBusy[x].busy); + paramIn(cp, csprintf("%s.jIntBusy%d", name(), x), "source", jIntBusy[x].source); + }; +} + + + + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(Iob) + Param<Tick> pio_latency; + SimObjectParam<Platform *> platform; + SimObjectParam<System *> system; +END_DECLARE_SIM_OBJECT_PARAMS(Iob) + +BEGIN_INIT_SIM_OBJECT_PARAMS(Iob) + + INIT_PARAM(pio_latency, "Programmed IO latency"), + INIT_PARAM(platform, "platform"), + INIT_PARAM(system, "system object") + +END_INIT_SIM_OBJECT_PARAMS(Iob) + +CREATE_SIM_OBJECT(Iob) +{ + Iob::Params *p = new Iob::Params; + p->name = getInstanceName(); + p->pio_delay = pio_latency; + p->platform = platform; + p->system = system; + return new Iob(p); +} + +REGISTER_SIM_OBJECT("Iob", Iob) diff --git a/src/dev/sparc/iob.hh b/src/dev/sparc/iob.hh new file mode 100644 index 000000000..c05c4f2ef --- /dev/null +++ b/src/dev/sparc/iob.hh @@ -0,0 +1,153 @@ +/* + * 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 implements the niagara I/O Bridge chip. The device manages + * internal (ipi) and external (serial, pci via jbus). + */ + +#ifndef __DEV_SPARC_IOB_HH__ +#define __DEV_SPARC_IOB_HH__ + +#include "base/range.hh" +#include "dev/io_device.hh" +#include "dev/disk_image.hh" + +class IntrControl; + +const int MaxNiagaraProcs = 32; +// IOB Managment Addresses +const Addr IntManAddr = 0x0000; +const Addr IntManSize = 0x0020; +const Addr IntCtlAddr = 0x0400; +const Addr IntCtlSize = 0x0020; +const Addr JIntVecAddr = 0x0A00; +const Addr IntVecDisAddr = 0x0800; +const Addr IntVecDisSize = 0x0100; + + +// IOB Control Addresses +const Addr JIntData0Addr = 0x0400; +const Addr JIntData1Addr = 0x0500; +const Addr JIntDataA0Addr = 0x0600; +const Addr JIntDataA1Addr = 0x0700; +const Addr JIntBusyAddr = 0x0900; +const Addr JIntBusySize = 0x0100; +const Addr JIntABusyAddr = 0x0B00; + + +// IOB Masks +const uint64_t IntManMask = 0x01F3F; +const uint64_t IntCtlMask = 0x00006; +const uint64_t JIntVecMask = 0x0003F; +const uint64_t IntVecDis = 0x31F3F; +const uint64_t JIntBusyMask = 0x0003F; + + +class Iob : public PioDevice +{ + private: + IntrControl *ic; + Addr iobManAddr; + Addr iobManSize; + Addr iobJBusAddr; + Addr iobJBusSize; + Tick pioDelay; + + enum DeviceId { + Interal = 0, + Error = 1, + SSI = 2, + Reserved = 3, + NumDeviceIds + }; + + struct IntMan { + int cpu; + int vector; + }; + + struct IntCtl { + bool mask; + bool pend; + }; + + struct IntBusy { + bool busy; + int source; + }; + + enum Type { + Interrupt, + Reset, + Idle, + Resume + }; + + IntMan intMan[NumDeviceIds]; + IntCtl intCtl[NumDeviceIds]; + uint64_t jIntVec; + uint64_t jBusData0[MaxNiagaraProcs]; + uint64_t jBusData1[MaxNiagaraProcs]; + IntBusy jIntBusy[MaxNiagaraProcs]; + + void writeIob(PacketPtr pkt); + void writeJBus(PacketPtr pkt); + void readIob(PacketPtr pkt); + void readJBus(PacketPtr pkt); + + + public: + struct Params : public PioDevice::Params + { + Tick pio_delay; + }; + protected: + const Params *params() const { return (const Params*)_params; } + + public: + Iob(Params *p); + + virtual Tick read(PacketPtr pkt); + virtual Tick write(PacketPtr pkt); + void generateIpi(Type type, int cpu_id, int vector); + void receiveDeviceInterrupt(DeviceId devid); + bool receiveJBusInterrupt(int cpu_id, int source, uint64_t d0, uint64_t d1); + + + void addressRanges(AddrRangeList &range_list); + + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); + +}; + +#endif //__DEV_SPARC_IOB_HH__ + diff --git a/src/python/m5/objects/IntrControl.py b/src/python/m5/objects/IntrControl.py index a7cf5cc84..398ba47f9 100644 --- a/src/python/m5/objects/IntrControl.py +++ b/src/python/m5/objects/IntrControl.py @@ -3,4 +3,4 @@ from m5.params import * from m5.proxy import * class IntrControl(SimObject): type = 'IntrControl' - cpu = Param.BaseCPU(Parent.cpu[0], "the cpu") + sys = Param.System(Parent.any, "the system we are part of") diff --git a/src/python/m5/objects/T1000.py b/src/python/m5/objects/T1000.py index aeca491c4..0acfa0920 100644 --- a/src/python/m5/objects/T1000.py +++ b/src/python/m5/objects/T1000.py @@ -1,6 +1,6 @@ from m5.params import * from m5.proxy import * -from Device import BasicPioDevice, IsaFake, BadAddr +from Device import BasicPioDevice, PioDevice, IsaFake, BadAddr from Uart import Uart8250 from Platform import Platform from SimConsole import SimConsole @@ -16,6 +16,10 @@ class DumbTOD(BasicPioDevice): time = Param.Time('01/01/2009', "System time to use ('Now' for real time)") pio_addr = 0xfff0c1fff8 +class Iob(PioDevice): + type = 'Iob' + pio_latency = Param.Latency('1ns', "Programed IO latency in simticks") + class T1000(Platform): type = 'T1000' @@ -28,9 +32,6 @@ class T1000(Platform): ret_data64=0x0000000000000000, update_data=False) #warn_access="Accessing Memory Banks -- Unimplemented!") - fake_iob = IsaFake(pio_addr=0x9800000000, pio_size=0x100000000) - #warn_access="Accessing IOB -- Unimplemented!") - fake_jbi = IsaFake(pio_addr=0x8000000000, pio_size=0x100000000) #warn_access="Accessing JBI -- Unimplemented!") @@ -76,6 +77,13 @@ class T1000(Platform): pconsole = SimConsole() puart0 = Uart8250(pio_addr=0x1f10000000) + iob = Iob() + # Attach I/O devices that are on chip + def attachOnChipIO(self, bus): + self.iob.pio = bus.port + self.htod.pio = bus.port + + # Attach I/O devices to specified bus object. Can't do this # earlier, since the bus object itself is typically defined at the # System level. @@ -84,8 +92,6 @@ class T1000(Platform): self.puart0.sim_console = self.pconsole self.fake_clk.pio = bus.port self.fake_membnks.pio = bus.port - self.fake_iob.pio = bus.port - self.fake_jbi.pio = bus.port self.fake_l2_1.pio = bus.port self.fake_l2_2.pio = bus.port self.fake_l2_3.pio = bus.port @@ -95,6 +101,6 @@ class T1000(Platform): self.fake_l2esr_3.pio = bus.port self.fake_l2esr_4.pio = bus.port self.fake_ssi.pio = bus.port + self.fake_jbi.pio = bus.port self.puart0.pio = bus.port self.hvuart.pio = bus.port - self.htod.pio = bus.port |