interrupts.cc revision 5254:c555f8b07345
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 160 uint64_t Interrupts::get_vec(int int_num) 161 { 162 panic("MipsISA::Interrupts::get_vec() is not implemented. \n"); 163 M5_DUMMY_RETURN 164 } 165*/ 166void Interrupts::post(int int_num, ThreadContext* tc) 167{ 168 DPRINTF(Interrupt, "Interrupt %d posted\n", int_num); 169 if (int_num < 0 || int_num >= NumInterruptLevels) 170 panic("int_num out of bounds\n"); 171 172 uint8_t intstatus= getCauseIP_(tc); 173 intstatus |= 1 << int_num; 174 setCauseIP_(tc, intstatus); 175} 176 177void Interrupts::post(int int_num, int index) 178{ 179 fatal("Must use Thread COntext when posting MIPS Interrupts in M5"); 180} 181 182void Interrupts::clear(int int_num, ThreadContext* tc) 183{ 184 DPRINTF(Interrupt, "Interrupt %d cleared\n", int_num); 185 if (int_num < 0 || int_num >= NumInterruptLevels) 186 panic("int_num out of bounds\n"); 187 188 uint8_t intstatus = getCauseIP_(tc); 189 intstatus &= ~(1 << int_num); 190 setCauseIP_(tc, intstatus); 191} 192 193void Interrupts::clear(int int_num, int index) 194{ 195 fatal("Must use Thread COntext when clearing MIPS Interrupts in M5"); 196} 197 198void Interrupts::clear_all(ThreadContext *tc) 199{ 200 DPRINTF(Interrupt, "Interrupts all cleared\n"); 201 uint8_t intstatus = 0; 202 setCauseIP_(tc, intstatus); 203} 204 205void Interrupts::clear_all() 206{ 207 fatal("Must use Thread COntext when clearing MIPS Interrupts in M5"); 208} 209 210 211 212Fault Interrupts::getInterrupt(ThreadContext * tc) 213{ 214 DPRINTF(Interrupt, "Interrupts getInterrupt\n"); 215 216 217 218 //Check if there are any outstanding interrupts 219 MiscReg status = tc->readMiscRegNoEffect(MipsISA::Status); 220 if (bits(status, Status_IE_LO) == 1 && //interrupts must be enabled 221 bits(status, Status_ERL_HI,Status_ERL_LO) == 0 && //error level must be 0 or interrupts inhibited 222 bits(status, Status_EXL_HI,Status_EXL_LO) == 0 ) //exception level must be 0 or interrupts inhibited 223 { 224 // Software interrupts & hardware interrupts are handled in software. 225 // So if any interrupt that isn't masked is detected, jump to interrupt 226 // handler 227 uint8_t IM, IP; //IM=interrupt mask, IP=interrupt pending 228 IM = bits(status,Status_IM7,Status_IM0); 229 IP = getCauseIP_(tc); 230 //IM and IP are already correctly aligned 231 if (IM & IP){ 232 DPRINTF(Interrupt, "Interrupt! IM[7:0]=%d IP[7:0]=%d \n", 233 IM, IP); 234 return new InterruptFault; 235 } 236 } 237 238 return NoFault; 239 240} 241bool Interrupts::onCpuTimerInterrupt(ThreadContext * tc) const 242{ 243 MiscReg compare = tc->readMiscRegNoEffect(MipsISA::Compare); 244 MiscReg count = tc->readMiscRegNoEffect(MipsISA::Count); 245 if (compare == count && count != 0) 246 return true; 247 return false; 248} 249void Interrupts::updateIntrInfo(ThreadContext *tc) const 250{ 251 //Nothing needs to be done. 252 ; 253} 254 255uint64_t Interrupts::get_vec(int int_num) 256{ 257 panic("MipsISA::Interrupts::get_vec() is not implemented. \n"); 258 M5_DUMMY_RETURN 259 } 260 261bool Interrupts::interruptsPending(ThreadContext *tc) const 262{ 263 //if there is a on cpu timer interrupt (i.e. Compare == Count) 264 //update CauseIP before proceeding to interrupt 265 if (onCpuTimerInterrupt(tc)){ 266 DPRINTF(Interrupt, "Interrupts OnCpuTimerINterrupt(tc)==true\n"); 267 //determine timer interrupt IP # 268 MiscReg intctl = tc->readMiscRegNoEffect(MipsISA::IntCtl); 269 uint8_t IPTI = bits(intctl, IntCtl_IPTI_HI, IntCtl_IPTI_LO); 270 //set intstatus to correspond 271 //post(IPTI, tc); 272 uint8_t intstatus= getCauseIP_(tc); 273 intstatus |= 1 << IPTI; 274 setCauseIP_(tc, intstatus); 275 } 276 277 return (getCauseIP_(tc) != 0); 278 279} 280 281 282 283 284 285} 286