interrupts.cc revision 5646:0a488a147fb8
1/* 2 * Copyright (c) 2006 The Regents of The University of Michigan 3 * Copyright (c) 2007 MIPS Technologies, Inc. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are 8 * met: redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer; 10 * redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution; 13 * neither the name of the copyright holders nor the names of its 14 * contributors may be used to endorse or promote products derived from 15 * this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 * 29 * Authors: Steve Reinhardt 30 * Kevin Lim 31 * Korey Sewell 32 */ 33 34#include "arch/mips/pra_constants.hh" 35#include "arch/mips/isa_traits.hh" 36#include "cpu/thread_context.hh" 37#include "arch/mips/interrupts.hh" 38 39namespace MipsISA 40{ 41static inline uint8_t getCauseIP_(ThreadContext *tc) { 42 MiscReg cause = tc->readMiscRegNoEffect(MipsISA::Cause); 43 uint8_t IP_ = bits(cause,Cause_IP7, Cause_IP0); 44 return IP_; 45} 46 47static inline void setCauseIP_(ThreadContext *tc, uint8_t val) { 48 MiscReg cause = tc->readMiscRegNoEffect(MipsISA::Cause); 49 replaceBits(cause,Cause_IP7,Cause_IP0,val); 50 tc->setMiscRegNoEffect(MipsISA::Cause,cause); 51} 52 53/* 54 void Interrupts::post(int int_num, int index) 55 { 56 DPRINTF(Interrupt, "Interrupt %d posted\n", int_num); 57 58 //index should not be used 59 assert(index == 0); 60 61 if (int_num < 0 || int_num >= NumInterruptLevels) 62 panic("int_num out of bounds\n"); 63 intstatus |= 1 << int_num; 64 } 65 66 void Interrupts::clear(int int_num, int index) 67 { 68 DPRINTF(Interrupt, "Interrupt %d cleared\n", int_num); 69 70 //index should not be used 71 assert(index == 0); 72 73 if (int_num < 0 || int_num >= NumInterruptLevels) 74 panic("int_num out of bounds\n"); 75 76 intstatus &= ~(1 << int_num); 77 } 78 79 void Interrupts::clear_all() 80 { 81 DPRINTF(Interrupt, "Interrupts all cleared\n"); 82 intstatus = 0; 83 } 84 85 86 87 Fault Interrupts::getInterrupt(ThreadContext * tc) 88 { 89 DPRINTF(Interrupt, "Interrupts getInterrupt\n"); 90 // If a timer interrupt has occured, check to see if a 91 // mtc0 to Compare register caused this interrupt to 92 // be cleared. If this is the case, clear intstatus 93 // bit for timer interrupt 94 if (oncputimerintr){ 95 DPRINTF(Interrupt, "Interrupts oncputimerintr==true\n"); 96 MiscReg cause = tc->readMiscRegNoEffect(MipsISA::Cause); 97 uint8_t IP_ = bits(cause,Cause_IP7, Cause_IP0); 98 MiscReg intctl = tc->readMiscRegNoEffect(MipsISA::IntCtl); 99 uint8_t IPTI = bits(intctl, IntCtl_IPTI_HI, IntCtl_IPTI_LO); 100 //mtc0 to compare must have cleared bit in IP 101 if ( ((1 << IPTI) & IP_) == 0){ 102 clear(IPTI, 0); 103 oncputimerintr=false; 104 } 105 } 106 //if there is a on cpu timer interrupt (i.e. Compare == Count) 107 //update intstatus before proceeding to interrupt 108 if (onCpuTimerInterrupt(tc)){ 109 DPRINTF(Interrupt, "Interrupts OnCpuTimerINterrupt(tc)==true\n"); 110 //determine timer interrupt IP # 111 MiscReg intctl = tc->readMiscRegNoEffect(MipsISA::IntCtl); 112 uint8_t IPTI = bits(intctl, IntCtl_IPTI_HI, IntCtl_IPTI_LO); 113 //set intstatus to correspond 114 post(IPTI, 0); 115 oncputimerintr=true; 116 } 117 118 //Check if there are any outstanding interrupts 119 MiscReg status = tc->readMiscRegNoEffect(MipsISA::Status); 120 if (bits(status, Status_IE_LO) == 1 && //interrupts must be enabled 121 bits(status, Status_ERL) == 0 && //error level must be 0 or interrupts inhibited 122 bits(status, Status_EXL) == 0 ) //exception level must be 0 or interrupts inhibited 123 { 124 // Software interrupts & hardware interrupts are handled in software. 125 // So if any interrupt that isn't masked is detected, jump to interrupt 126 // handler 127 uint8_t IM, IP; //IM=interrupt mask, IP=interrupt pending 128 IM = bits(status,Status_IM7,Status_IM0); 129 IP = intstatus; 130 //IM and IP are already correctly aligned 131 if (IM & IP){ 132 DPRINTF(Flow, "Interrupt! IM[7:0]=%d IP[7:0]=%d \n", 133 IM, IP); 134 return new InterruptFault; 135 } 136 } 137 138 return NoFault; 139 140 } 141 142 void Interrupts::updateIntrInfo(ThreadContext *tc) const 143 { 144 //Merge Interrupts.intstatus with mips MipISA::Status 145 MiscReg cause = tc->readMiscRegNoEffect(MipsISA::Cause); 146 replaceBits(cause,Cause_IP7,Cause_IP0,intstatus); 147 tc->setMiscRegNoEffect(MipsISA::Cause,cause); 148 } 149 150 bool Interrupts::onCpuTimerInterrupt(ThreadContext * tc) const 151 { 152 MiscReg compare = tc->readMiscRegNoEffect(MipsISA::Compare); 153 MiscReg count = tc->readMiscRegNoEffect(MipsISA::Count); 154 if (compare == count) 155 return true; 156 return false; 157 } 158 159*/ 160void Interrupts::post(int int_num, ThreadContext* tc) 161{ 162 DPRINTF(Interrupt, "Interrupt %d posted\n", int_num); 163 if (int_num < 0 || int_num >= NumInterruptLevels) 164 panic("int_num out of bounds\n"); 165 166 uint8_t intstatus= getCauseIP_(tc); 167 intstatus |= 1 << int_num; 168 setCauseIP_(tc, intstatus); 169} 170 171void Interrupts::post(int int_num, int index) 172{ 173 fatal("Must use Thread COntext when posting MIPS Interrupts in M5"); 174} 175 176void Interrupts::clear(int int_num, ThreadContext* tc) 177{ 178 DPRINTF(Interrupt, "Interrupt %d cleared\n", int_num); 179 if (int_num < 0 || int_num >= NumInterruptLevels) 180 panic("int_num out of bounds\n"); 181 182 uint8_t intstatus = getCauseIP_(tc); 183 intstatus &= ~(1 << int_num); 184 setCauseIP_(tc, intstatus); 185} 186 187void Interrupts::clear(int int_num, int index) 188{ 189 fatal("Must use Thread COntext when clearing MIPS Interrupts in M5"); 190} 191 192void Interrupts::clear_all(ThreadContext *tc) 193{ 194 DPRINTF(Interrupt, "Interrupts all cleared\n"); 195 uint8_t intstatus = 0; 196 setCauseIP_(tc, intstatus); 197} 198 199void Interrupts::clear_all() 200{ 201 fatal("Must use Thread COntext when clearing MIPS Interrupts in M5"); 202} 203 204 205 206Fault Interrupts::getInterrupt(ThreadContext * tc) 207{ 208 DPRINTF(Interrupt, "Interrupts getInterrupt\n"); 209 210 211 212 //Check if there are any outstanding interrupts 213 MiscReg status = tc->readMiscRegNoEffect(MipsISA::Status); 214 if (bits(status, Status_IE_LO) == 1 && //interrupts must be enabled 215 bits(status, Status_ERL_HI,Status_ERL_LO) == 0 && //error level must be 0 or interrupts inhibited 216 bits(status, Status_EXL_HI,Status_EXL_LO) == 0 ) //exception level must be 0 or interrupts inhibited 217 { 218 // Software interrupts & hardware interrupts are handled in software. 219 // So if any interrupt that isn't masked is detected, jump to interrupt 220 // handler 221 uint8_t IM, IP; //IM=interrupt mask, IP=interrupt pending 222 IM = bits(status,Status_IM7,Status_IM0); 223 IP = getCauseIP_(tc); 224 //IM and IP are already correctly aligned 225 if (IM & IP){ 226 DPRINTF(Interrupt, "Interrupt! IM[7:0]=%d IP[7:0]=%d \n", 227 IM, IP); 228 return new InterruptFault; 229 } 230 } 231 232 return NoFault; 233 234} 235bool Interrupts::onCpuTimerInterrupt(ThreadContext * tc) const 236{ 237 MiscReg compare = tc->readMiscRegNoEffect(MipsISA::Compare); 238 MiscReg count = tc->readMiscRegNoEffect(MipsISA::Count); 239 if (compare == count && count != 0) 240 return true; 241 return false; 242} 243void Interrupts::updateIntrInfo(ThreadContext *tc) const 244{ 245 //Nothing needs to be done. 246 ; 247} 248 249bool Interrupts::interruptsPending(ThreadContext *tc) const 250{ 251 //if there is a on cpu timer interrupt (i.e. Compare == Count) 252 //update CauseIP before proceeding to interrupt 253 if (onCpuTimerInterrupt(tc)){ 254 DPRINTF(Interrupt, "Interrupts OnCpuTimerINterrupt(tc)==true\n"); 255 //determine timer interrupt IP # 256 MiscReg intctl = tc->readMiscRegNoEffect(MipsISA::IntCtl); 257 uint8_t IPTI = bits(intctl, IntCtl_IPTI_HI, IntCtl_IPTI_LO); 258 //set intstatus to correspond 259 //post(IPTI, tc); 260 uint8_t intstatus= getCauseIP_(tc); 261 intstatus |= 1 << IPTI; 262 setCauseIP_(tc, intstatus); 263 } 264 265 return (getCauseIP_(tc) != 0); 266 267} 268 269 270 271 272 273} 274