interrupts.cc revision 6046
17008Snate@binkert.org/* 27008Snate@binkert.org * Copyright (c) 2006 The Regents of The University of Michigan 37008Snate@binkert.org * Copyright (c) 2007 MIPS Technologies, Inc. 47008Snate@binkert.org * All rights reserved. 57008Snate@binkert.org * 67008Snate@binkert.org * Redistribution and use in source and binary forms, with or without 77008Snate@binkert.org * modification, are permitted provided that the following conditions are 87008Snate@binkert.org * met: redistributions of source code must retain the above copyright 97008Snate@binkert.org * notice, this list of conditions and the following disclaimer; 107008Snate@binkert.org * redistributions in binary form must reproduce the above copyright 117008Snate@binkert.org * notice, this list of conditions and the following disclaimer in the 127008Snate@binkert.org * documentation and/or other materials provided with the distribution; 137008Snate@binkert.org * neither the name of the copyright holders nor the names of its 147008Snate@binkert.org * contributors may be used to endorse or promote products derived from 157008Snate@binkert.org * this software without specific prior written permission. 167008Snate@binkert.org * 177008Snate@binkert.org * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 187008Snate@binkert.org * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 197008Snate@binkert.org * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 207008Snate@binkert.org * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 217008Snate@binkert.org * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 227008Snate@binkert.org * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 237008Snate@binkert.org * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 247008Snate@binkert.org * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 257008Snate@binkert.org * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 267008Snate@binkert.org * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 277008Snate@binkert.org * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 286285Snate@binkert.org * 2910472Sandreas.hansson@arm.com * Authors: Steve Reinhardt 3010472Sandreas.hansson@arm.com * Kevin Lim 3110518Snilay@cs.wisc.edu * Korey Sewell 3210518Snilay@cs.wisc.edu */ 338232Snate@binkert.org 349104Shestness@cs.utexas.edu#include "arch/mips/pra_constants.hh" 357039Snate@binkert.org#include "arch/mips/isa_traits.hh" 367039Snate@binkert.org#include "cpu/thread_context.hh" 376285Snate@binkert.org#include "arch/mips/interrupts.hh" 3810518Snilay@cs.wisc.edu 396285Snate@binkert.orgnamespace MipsISA 406876Ssteve.reinhardt@amd.com{ 4110518Snilay@cs.wisc.edustatic inline uint8_t getCauseIP_(ThreadContext *tc) { 4210518Snilay@cs.wisc.edu MiscReg cause = tc->readMiscRegNoEffect(MipsISA::Cause); 4310519Snilay@cs.wisc.edu uint8_t IP_ = bits(cause,Cause_IP7, Cause_IP0); 4410519Snilay@cs.wisc.edu return IP_; 456285Snate@binkert.org} 4610518Snilay@cs.wisc.edu 476285Snate@binkert.orgstatic inline void setCauseIP_(ThreadContext *tc, uint8_t val) { 486285Snate@binkert.org MiscReg cause = tc->readMiscRegNoEffect(MipsISA::Cause); 497039Snate@binkert.org replaceBits(cause,Cause_IP7,Cause_IP0,val); 507039Snate@binkert.org tc->setMiscRegNoEffect(MipsISA::Cause,cause); 516285Snate@binkert.org} 5210518Snilay@cs.wisc.edu 5310518Snilay@cs.wisc.edu/* 5410518Snilay@cs.wisc.edu void Interrupts::post(int int_num, int index) 5510518Snilay@cs.wisc.edu { 567039Snate@binkert.org DPRINTF(Interrupt, "Interrupt %d posted\n", int_num); 577039Snate@binkert.org 5810519Snilay@cs.wisc.edu //index should not be used 5910519Snilay@cs.wisc.edu assert(index == 0); 606285Snate@binkert.org 616285Snate@binkert.org if (int_num < 0 || int_num >= NumInterruptLevels) 6210518Snilay@cs.wisc.edu panic("int_num out of bounds\n"); 6310518Snilay@cs.wisc.edu intstatus |= 1 << int_num; 6410518Snilay@cs.wisc.edu } 6510518Snilay@cs.wisc.edu 6610518Snilay@cs.wisc.edu void Interrupts::clear(int int_num, int index) 6710518Snilay@cs.wisc.edu { 6810518Snilay@cs.wisc.edu DPRINTF(Interrupt, "Interrupt %d cleared\n", int_num); 6910518Snilay@cs.wisc.edu 7010518Snilay@cs.wisc.edu //index should not be used 7110518Snilay@cs.wisc.edu assert(index == 0); 7210518Snilay@cs.wisc.edu 7310518Snilay@cs.wisc.edu if (int_num < 0 || int_num >= NumInterruptLevels) 7410518Snilay@cs.wisc.edu panic("int_num out of bounds\n"); 7510518Snilay@cs.wisc.edu 7610519Snilay@cs.wisc.edu intstatus &= ~(1 << int_num); 7710519Snilay@cs.wisc.edu } 7810518Snilay@cs.wisc.edu 7910518Snilay@cs.wisc.edu void Interrupts::clearAll() 8010518Snilay@cs.wisc.edu { 8110518Snilay@cs.wisc.edu DPRINTF(Interrupt, "Interrupts all cleared\n"); 8210518Snilay@cs.wisc.edu intstatus = 0; 8310518Snilay@cs.wisc.edu } 8410518Snilay@cs.wisc.edu 8510518Snilay@cs.wisc.edu 8610518Snilay@cs.wisc.edu 8710518Snilay@cs.wisc.edu Fault Interrupts::getInterrupt(ThreadContext * tc) 8810518Snilay@cs.wisc.edu { 8910518Snilay@cs.wisc.edu DPRINTF(Interrupt, "Interrupts getInterrupt\n"); 9010518Snilay@cs.wisc.edu // If a timer interrupt has occured, check to see if a 9110518Snilay@cs.wisc.edu // mtc0 to Compare register caused this interrupt to 9210518Snilay@cs.wisc.edu // be cleared. If this is the case, clear intstatus 9310518Snilay@cs.wisc.edu // bit for timer interrupt 9410518Snilay@cs.wisc.edu if (oncputimerintr){ 9510518Snilay@cs.wisc.edu DPRINTF(Interrupt, "Interrupts oncputimerintr==true\n"); 9610518Snilay@cs.wisc.edu MiscReg cause = tc->readMiscRegNoEffect(MipsISA::Cause); 9710518Snilay@cs.wisc.edu uint8_t IP_ = bits(cause,Cause_IP7, Cause_IP0); 9810518Snilay@cs.wisc.edu MiscReg intctl = tc->readMiscRegNoEffect(MipsISA::IntCtl); 9910518Snilay@cs.wisc.edu uint8_t IPTI = bits(intctl, IntCtl_IPTI_HI, IntCtl_IPTI_LO); 10010518Snilay@cs.wisc.edu //mtc0 to compare must have cleared bit in IP 10110518Snilay@cs.wisc.edu if ( ((1 << IPTI) & IP_) == 0){ 10210518Snilay@cs.wisc.edu clear(IPTI, 0); 10310518Snilay@cs.wisc.edu oncputimerintr=false; 10410518Snilay@cs.wisc.edu } 10510518Snilay@cs.wisc.edu } 10610518Snilay@cs.wisc.edu //if there is a on cpu timer interrupt (i.e. Compare == Count) 10710518Snilay@cs.wisc.edu //update intstatus before proceeding to interrupt 10810518Snilay@cs.wisc.edu if (onCpuTimerInterrupt(tc)){ 10910518Snilay@cs.wisc.edu DPRINTF(Interrupt, "Interrupts OnCpuTimerINterrupt(tc)==true\n"); 11010518Snilay@cs.wisc.edu //determine timer interrupt IP # 11110518Snilay@cs.wisc.edu MiscReg intctl = tc->readMiscRegNoEffect(MipsISA::IntCtl); 11210518Snilay@cs.wisc.edu uint8_t IPTI = bits(intctl, IntCtl_IPTI_HI, IntCtl_IPTI_LO); 11310518Snilay@cs.wisc.edu //set intstatus to correspond 11410518Snilay@cs.wisc.edu post(IPTI, 0); 11510518Snilay@cs.wisc.edu oncputimerintr=true; 11610518Snilay@cs.wisc.edu } 11710518Snilay@cs.wisc.edu 11810518Snilay@cs.wisc.edu //Check if there are any outstanding interrupts 11910518Snilay@cs.wisc.edu MiscReg status = tc->readMiscRegNoEffect(MipsISA::Status); 12010518Snilay@cs.wisc.edu if (bits(status, Status_IE_LO) == 1 && //interrupts must be enabled 12110518Snilay@cs.wisc.edu bits(status, Status_ERL) == 0 && //error level must be 0 or interrupts inhibited 12210518Snilay@cs.wisc.edu bits(status, Status_EXL) == 0 ) //exception level must be 0 or interrupts inhibited 12310518Snilay@cs.wisc.edu { 12410518Snilay@cs.wisc.edu // Software interrupts & hardware interrupts are handled in software. 12510518Snilay@cs.wisc.edu // So if any interrupt that isn't masked is detected, jump to interrupt 12610518Snilay@cs.wisc.edu // handler 12710518Snilay@cs.wisc.edu uint8_t IM, IP; //IM=interrupt mask, IP=interrupt pending 12810518Snilay@cs.wisc.edu IM = bits(status,Status_IM7,Status_IM0); 12910518Snilay@cs.wisc.edu IP = intstatus; 13010518Snilay@cs.wisc.edu //IM and IP are already correctly aligned 13110518Snilay@cs.wisc.edu if (IM & IP){ 13210518Snilay@cs.wisc.edu DPRINTF(Flow, "Interrupt! IM[7:0]=%d IP[7:0]=%d \n", 13310518Snilay@cs.wisc.edu IM, IP); 13410518Snilay@cs.wisc.edu return new InterruptFault; 13510518Snilay@cs.wisc.edu } 13610518Snilay@cs.wisc.edu } 13710518Snilay@cs.wisc.edu 13810518Snilay@cs.wisc.edu return NoFault; 13910518Snilay@cs.wisc.edu 14010518Snilay@cs.wisc.edu } 14110518Snilay@cs.wisc.edu 14210518Snilay@cs.wisc.edu void Interrupts::updateIntrInfo(ThreadContext *tc) const 14310518Snilay@cs.wisc.edu { 14410518Snilay@cs.wisc.edu //Merge Interrupts.intstatus with mips MipISA::Status 14510518Snilay@cs.wisc.edu MiscReg cause = tc->readMiscRegNoEffect(MipsISA::Cause); 14610518Snilay@cs.wisc.edu replaceBits(cause,Cause_IP7,Cause_IP0,intstatus); 14710518Snilay@cs.wisc.edu tc->setMiscRegNoEffect(MipsISA::Cause,cause); 14810518Snilay@cs.wisc.edu } 14910518Snilay@cs.wisc.edu 15010518Snilay@cs.wisc.edu bool Interrupts::onCpuTimerInterrupt(ThreadContext * tc) const 15110518Snilay@cs.wisc.edu { 15210518Snilay@cs.wisc.edu MiscReg compare = tc->readMiscRegNoEffect(MipsISA::Compare); 15310518Snilay@cs.wisc.edu MiscReg count = tc->readMiscRegNoEffect(MipsISA::Count); 15410518Snilay@cs.wisc.edu if (compare == count) 15510518Snilay@cs.wisc.edu return true; 15610518Snilay@cs.wisc.edu return false; 15710518Snilay@cs.wisc.edu } 15810518Snilay@cs.wisc.edu 15910518Snilay@cs.wisc.edu*/ 16010518Snilay@cs.wisc.eduvoid Interrupts::post(int int_num, ThreadContext* tc) 16110518Snilay@cs.wisc.edu{ 16210518Snilay@cs.wisc.edu DPRINTF(Interrupt, "Interrupt %d posted\n", int_num); 16310518Snilay@cs.wisc.edu if (int_num < 0 || int_num >= NumInterruptLevels) 16410518Snilay@cs.wisc.edu panic("int_num out of bounds\n"); 16510518Snilay@cs.wisc.edu 16610518Snilay@cs.wisc.edu uint8_t intstatus= getCauseIP_(tc); 16710518Snilay@cs.wisc.edu intstatus |= 1 << int_num; 16810518Snilay@cs.wisc.edu setCauseIP_(tc, intstatus); 16910518Snilay@cs.wisc.edu} 17010518Snilay@cs.wisc.edu 17110518Snilay@cs.wisc.eduvoid Interrupts::post(int int_num, int index) 17210518Snilay@cs.wisc.edu{ 17310518Snilay@cs.wisc.edu fatal("Must use Thread COntext when posting MIPS Interrupts in M5"); 17410518Snilay@cs.wisc.edu} 17510518Snilay@cs.wisc.edu 17610518Snilay@cs.wisc.eduvoid Interrupts::clear(int int_num, ThreadContext* tc) 17710518Snilay@cs.wisc.edu{ 17810518Snilay@cs.wisc.edu DPRINTF(Interrupt, "Interrupt %d cleared\n", int_num); 17910518Snilay@cs.wisc.edu if (int_num < 0 || int_num >= NumInterruptLevels) 18010518Snilay@cs.wisc.edu panic("int_num out of bounds\n"); 18110518Snilay@cs.wisc.edu 18210518Snilay@cs.wisc.edu uint8_t intstatus = getCauseIP_(tc); 18310518Snilay@cs.wisc.edu intstatus &= ~(1 << int_num); 18410518Snilay@cs.wisc.edu setCauseIP_(tc, intstatus); 18510518Snilay@cs.wisc.edu} 18610518Snilay@cs.wisc.edu 18710518Snilay@cs.wisc.eduvoid Interrupts::clear(int int_num, int index) 18810518Snilay@cs.wisc.edu{ 18910518Snilay@cs.wisc.edu fatal("Must use Thread COntext when clearing MIPS Interrupts in M5"); 19010518Snilay@cs.wisc.edu} 19110518Snilay@cs.wisc.edu 19210518Snilay@cs.wisc.eduvoid Interrupts::clearAll(ThreadContext *tc) 19310518Snilay@cs.wisc.edu{ 19410518Snilay@cs.wisc.edu DPRINTF(Interrupt, "Interrupts all cleared\n"); 19510518Snilay@cs.wisc.edu uint8_t intstatus = 0; 19610518Snilay@cs.wisc.edu setCauseIP_(tc, intstatus); 19710518Snilay@cs.wisc.edu} 19810518Snilay@cs.wisc.edu 19910518Snilay@cs.wisc.eduvoid Interrupts::clearAll() 20010518Snilay@cs.wisc.edu{ 20110518Snilay@cs.wisc.edu fatal("Must use Thread COntext when clearing MIPS Interrupts in M5"); 20210518Snilay@cs.wisc.edu} 20310518Snilay@cs.wisc.edu 20410518Snilay@cs.wisc.edu 20510518Snilay@cs.wisc.edu 20610518Snilay@cs.wisc.eduFault Interrupts::getInterrupt(ThreadContext * tc) 20710518Snilay@cs.wisc.edu{ 20810518Snilay@cs.wisc.edu DPRINTF(Interrupt, "Interrupts getInterrupt\n"); 20910518Snilay@cs.wisc.edu 21010518Snilay@cs.wisc.edu 21110518Snilay@cs.wisc.edu 21210519Snilay@cs.wisc.edu //Check if there are any outstanding interrupts 21310518Snilay@cs.wisc.edu MiscReg status = tc->readMiscRegNoEffect(MipsISA::Status); 21410518Snilay@cs.wisc.edu if (bits(status, Status_IE_LO) == 1 && //interrupts must be enabled 21510518Snilay@cs.wisc.edu bits(status, Status_ERL_HI,Status_ERL_LO) == 0 && //error level must be 0 or interrupts inhibited 21610518Snilay@cs.wisc.edu bits(status, Status_EXL_HI,Status_EXL_LO) == 0 ) //exception level must be 0 or interrupts inhibited 21710518Snilay@cs.wisc.edu { 21810518Snilay@cs.wisc.edu // Software interrupts & hardware interrupts are handled in software. 21910519Snilay@cs.wisc.edu // So if any interrupt that isn't masked is detected, jump to interrupt 22010518Snilay@cs.wisc.edu // handler 22110518Snilay@cs.wisc.edu uint8_t IM, IP; //IM=interrupt mask, IP=interrupt pending 22210518Snilay@cs.wisc.edu IM = bits(status,Status_IM7,Status_IM0); 22310518Snilay@cs.wisc.edu IP = getCauseIP_(tc); 22410518Snilay@cs.wisc.edu //IM and IP are already correctly aligned 22510518Snilay@cs.wisc.edu if (IM & IP){ 22610518Snilay@cs.wisc.edu DPRINTF(Interrupt, "Interrupt! IM[7:0]=%d IP[7:0]=%d \n", 22710518Snilay@cs.wisc.edu IM, IP); 22810518Snilay@cs.wisc.edu return new InterruptFault; 22910518Snilay@cs.wisc.edu } 2307039Snate@binkert.org } 2318615Snilay@cs.wisc.edu 2326285Snate@binkert.org return NoFault; 2337544SBrad.Beckmann@amd.com 2347544SBrad.Beckmann@amd.com} 2357544SBrad.Beckmann@amd.combool Interrupts::onCpuTimerInterrupt(ThreadContext * tc) const 2367544SBrad.Beckmann@amd.com{ 2378615Snilay@cs.wisc.edu MiscReg compare = tc->readMiscRegNoEffect(MipsISA::Compare); 2388615Snilay@cs.wisc.edu MiscReg count = tc->readMiscRegNoEffect(MipsISA::Count); 2398615Snilay@cs.wisc.edu if (compare == count && count != 0) 2408615Snilay@cs.wisc.edu return true; 2416285Snate@binkert.org return false; 2427039Snate@binkert.org} 2437039Snate@binkert.orgvoid Interrupts::updateIntrInfo(ThreadContext *tc) const 2446285Snate@binkert.org{ 2457039Snate@binkert.org //Nothing needs to be done. 2467039Snate@binkert.org ; 2477039Snate@binkert.org} 2487039Snate@binkert.org 2497039Snate@binkert.orgbool Interrupts::interruptsPending(ThreadContext *tc) const 2507039Snate@binkert.org{ 2518615Snilay@cs.wisc.edu //if there is a on cpu timer interrupt (i.e. Compare == Count) 2526285Snate@binkert.org //update CauseIP before proceeding to interrupt 25310472Sandreas.hansson@arm.com if (onCpuTimerInterrupt(tc)){ 25410472Sandreas.hansson@arm.com DPRINTF(Interrupt, "Interrupts OnCpuTimerINterrupt(tc)==true\n"); 2557453Snate@binkert.org //determine timer interrupt IP # 2567453Snate@binkert.org MiscReg intctl = tc->readMiscRegNoEffect(MipsISA::IntCtl); 2577453Snate@binkert.org uint8_t IPTI = bits(intctl, IntCtl_IPTI_HI, IntCtl_IPTI_LO); 2587039Snate@binkert.org //set intstatus to correspond 2596888SBrad.Beckmann@amd.com //post(IPTI, tc); 2607453Snate@binkert.org uint8_t intstatus= getCauseIP_(tc); 2617039Snate@binkert.org intstatus |= 1 << IPTI; 2626888SBrad.Beckmann@amd.com setCauseIP_(tc, intstatus); 2637915SBrad.Beckmann@amd.com } 2647915SBrad.Beckmann@amd.com 2657915SBrad.Beckmann@amd.com return (getCauseIP_(tc) != 0); 2667915SBrad.Beckmann@amd.com 2677039Snate@binkert.org} 2686888SBrad.Beckmann@amd.com 2697039Snate@binkert.org 2707039Snate@binkert.org 2717453Snate@binkert.org 2726285Snate@binkert.org 2737039Snate@binkert.org} 2746285Snate@binkert.org