interrupts.cc revision 5222:bb733a878f85
1/* 2 * Copyright .AN) 2007 MIPS Technologies, Inc. All Rights Reserved 3 * 4 * This software is part of the M5 simulator. 5 * 6 * THIS IS A LEGAL AGREEMENT. BY DOWNLOADING, USING, COPYING, CREATING 7 * DERIVATIVE WORKS, AND/OR DISTRIBUTING THIS SOFTWARE YOU ARE AGREEING 8 * TO THESE TERMS AND CONDITIONS. 9 * 10 * Permission is granted to use, copy, create derivative works and 11 * distribute this software and such derivative works for any purpose, 12 * so long as (1) the copyright notice above, this grant of permission, 13 * and the disclaimer below appear in all copies and derivative works 14 * made, (2) the copyright notice above is augmented as appropriate to 15 * reflect the addition of any new copyrightable work in a derivative 16 * work (e.g., Copyright .AN) <Publication Year> Copyright Owner), and (3) 17 * the name of MIPS Technologies, Inc. ($B!H(BMIPS$B!I(B) is not used in any 18 * advertising or publicity pertaining to the use or distribution of 19 * this software without specific, written prior authorization. 20 * 21 * THIS SOFTWARE IS PROVIDED $B!H(BAS IS.$B!I(B MIPS MAKES NO WARRANTIES AND 22 * DISCLAIMS ALL WARRANTIES, WHETHER EXPRESS, STATUTORY, IMPLIED OR 23 * OTHERWISE, INCLUDING BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 24 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND 25 * NON-INFRINGEMENT OF THIRD PARTY RIGHTS, REGARDING THIS SOFTWARE. 26 * IN NO EVENT SHALL MIPS BE LIABLE FOR ANY DAMAGES, INCLUDING DIRECT, 27 * INDIRECT, INCIDENTAL, CONSEQUENTIAL, SPECIAL, OR PUNITIVE DAMAGES OF 28 * ANY KIND OR NATURE, ARISING OUT OF OR IN CONNECTION WITH THIS AGREEMENT, 29 * THIS SOFTWARE AND/OR THE USE OF THIS SOFTWARE, WHETHER SUCH LIABILITY 30 * IS ASSERTED ON THE BASIS OF CONTRACT, TORT (INCLUDING NEGLIGENCE OR 31 * STRICT LIABILITY), OR OTHERWISE, EVEN IF MIPS HAS BEEN WARNED OF THE 32 * POSSIBILITY OF ANY SUCH LOSS OR DAMAGE IN ADVANCE. 33 * 34 * Authors: Richard Strong 35 */ 36 37 38#include "arch/mips/pra_constants.hh" 39#include "arch/mips/isa_traits.hh" 40#include "cpu/thread_context.hh" 41#include "arch/mips/interrupts.hh" 42 43namespace MipsISA 44{ 45static inline uint8_t getCauseIP_(ThreadContext *tc) { 46 MiscReg cause = tc->readMiscRegNoEffect(MipsISA::Cause); 47 uint8_t IP_ = bits(cause,Cause_IP7, Cause_IP0); 48 return IP_; 49} 50 51static inline void setCauseIP_(ThreadContext *tc, uint8_t val) { 52 MiscReg cause = tc->readMiscRegNoEffect(MipsISA::Cause); 53 replaceBits(cause,Cause_IP7,Cause_IP0,val); 54 tc->setMiscRegNoEffect(MipsISA::Cause,cause); 55} 56 57/* 58 void Interrupts::post(int int_num, int index) 59 { 60 DPRINTF(Interrupt, "Interrupt %d posted\n", int_num); 61 62 //index should not be used 63 assert(index == 0); 64 65 if (int_num < 0 || int_num >= NumInterruptLevels) 66 panic("int_num out of bounds\n"); 67 intstatus |= 1 << int_num; 68 } 69 70 void Interrupts::clear(int int_num, int index) 71 { 72 DPRINTF(Interrupt, "Interrupt %d cleared\n", int_num); 73 74 //index should not be used 75 assert(index == 0); 76 77 if (int_num < 0 || int_num >= NumInterruptLevels) 78 panic("int_num out of bounds\n"); 79 80 intstatus &= ~(1 << int_num); 81 } 82 83 void Interrupts::clear_all() 84 { 85 DPRINTF(Interrupt, "Interrupts all cleared\n"); 86 intstatus = 0; 87 } 88 89 90 91 Fault Interrupts::getInterrupt(ThreadContext * tc) 92 { 93 DPRINTF(Interrupt, "Interrupts getInterrupt\n"); 94 // If a timer interrupt has occured, check to see if a 95 // mtc0 to Compare register caused this interrupt to 96 // be cleared. If this is the case, clear intstatus 97 // bit for timer interrupt 98 if (oncputimerintr){ 99 DPRINTF(Interrupt, "Interrupts oncputimerintr==true\n"); 100 MiscReg cause = tc->readMiscRegNoEffect(MipsISA::Cause); 101 uint8_t IP_ = bits(cause,Cause_IP7, Cause_IP0); 102 MiscReg intctl = tc->readMiscRegNoEffect(MipsISA::IntCtl); 103 uint8_t IPTI = bits(intctl, IntCtl_IPTI_HI, IntCtl_IPTI_LO); 104 //mtc0 to compare must have cleared bit in IP 105 if ( ((1 << IPTI) & IP_) == 0){ 106 clear(IPTI, 0); 107 oncputimerintr=false; 108 } 109 } 110 //if there is a on cpu timer interrupt (i.e. Compare == Count) 111 //update intstatus before proceeding to interrupt 112 if (onCpuTimerInterrupt(tc)){ 113 DPRINTF(Interrupt, "Interrupts OnCpuTimerINterrupt(tc)==true\n"); 114 //determine timer interrupt IP # 115 MiscReg intctl = tc->readMiscRegNoEffect(MipsISA::IntCtl); 116 uint8_t IPTI = bits(intctl, IntCtl_IPTI_HI, IntCtl_IPTI_LO); 117 //set intstatus to correspond 118 post(IPTI, 0); 119 oncputimerintr=true; 120 } 121 122 //Check if there are any outstanding interrupts 123 MiscReg status = tc->readMiscRegNoEffect(MipsISA::Status); 124 if (bits(status, Status_IE_LO) == 1 && //interrupts must be enabled 125 bits(status, Status_ERL) == 0 && //error level must be 0 or interrupts inhibited 126 bits(status, Status_EXL) == 0 ) //exception level must be 0 or interrupts inhibited 127 { 128 // Software interrupts & hardware interrupts are handled in software. 129 // So if any interrupt that isn't masked is detected, jump to interrupt 130 // handler 131 uint8_t IM, IP; //IM=interrupt mask, IP=interrupt pending 132 IM = bits(status,Status_IM7,Status_IM0); 133 IP = intstatus; 134 //IM and IP are already correctly aligned 135 if (IM & IP){ 136 DPRINTF(Flow, "Interrupt! IM[7:0]=%d IP[7:0]=%d \n", 137 IM, IP); 138 return new InterruptFault; 139 } 140 } 141 142 return NoFault; 143 144 } 145 146 void Interrupts::updateIntrInfo(ThreadContext *tc) const 147 { 148 //Merge Interrupts.intstatus with mips MipISA::Status 149 MiscReg cause = tc->readMiscRegNoEffect(MipsISA::Cause); 150 replaceBits(cause,Cause_IP7,Cause_IP0,intstatus); 151 tc->setMiscRegNoEffect(MipsISA::Cause,cause); 152 } 153 154 bool Interrupts::onCpuTimerInterrupt(ThreadContext * tc) const 155 { 156 MiscReg compare = tc->readMiscRegNoEffect(MipsISA::Compare); 157 MiscReg count = tc->readMiscRegNoEffect(MipsISA::Count); 158 if (compare == count) 159 return true; 160 return false; 161 } 162 163 164 uint64_t Interrupts::get_vec(int int_num) 165 { 166 panic("MipsISA::Interrupts::get_vec() is not implemented. \n"); 167 M5_DUMMY_RETURN 168 } 169*/ 170void Interrupts::post(int int_num, ThreadContext* tc) 171{ 172 DPRINTF(Interrupt, "Interrupt %d posted\n", int_num); 173 if (int_num < 0 || int_num >= NumInterruptLevels) 174 panic("int_num out of bounds\n"); 175 176 uint8_t intstatus= getCauseIP_(tc); 177 intstatus |= 1 << int_num; 178 setCauseIP_(tc, intstatus); 179} 180 181void Interrupts::post(int int_num, int index) 182{ 183 fatal("Must use Thread COntext when posting MIPS Interrupts in M5"); 184} 185 186void Interrupts::clear(int int_num, ThreadContext* tc) 187{ 188 DPRINTF(Interrupt, "Interrupt %d cleared\n", int_num); 189 if (int_num < 0 || int_num >= NumInterruptLevels) 190 panic("int_num out of bounds\n"); 191 192 uint8_t intstatus = getCauseIP_(tc); 193 intstatus &= ~(1 << int_num); 194 setCauseIP_(tc, intstatus); 195} 196 197void Interrupts::clear(int int_num, int index) 198{ 199 fatal("Must use Thread COntext when clearing MIPS Interrupts in M5"); 200} 201 202void Interrupts::clear_all(ThreadContext *tc) 203{ 204 DPRINTF(Interrupt, "Interrupts all cleared\n"); 205 uint8_t intstatus = 0; 206 setCauseIP_(tc, intstatus); 207} 208 209void Interrupts::clear_all() 210{ 211 fatal("Must use Thread COntext when clearing MIPS Interrupts in M5"); 212} 213 214 215 216Fault Interrupts::getInterrupt(ThreadContext * tc) 217{ 218 DPRINTF(Interrupt, "Interrupts getInterrupt\n"); 219 220 221 222 //Check if there are any outstanding interrupts 223 MiscReg status = tc->readMiscRegNoEffect(MipsISA::Status); 224 if (bits(status, Status_IE_LO) == 1 && //interrupts must be enabled 225 bits(status, Status_ERL_HI,Status_ERL_LO) == 0 && //error level must be 0 or interrupts inhibited 226 bits(status, Status_EXL_HI,Status_EXL_LO) == 0 ) //exception level must be 0 or interrupts inhibited 227 { 228 // Software interrupts & hardware interrupts are handled in software. 229 // So if any interrupt that isn't masked is detected, jump to interrupt 230 // handler 231 uint8_t IM, IP; //IM=interrupt mask, IP=interrupt pending 232 IM = bits(status,Status_IM7,Status_IM0); 233 IP = getCauseIP_(tc); 234 //IM and IP are already correctly aligned 235 if (IM & IP){ 236 DPRINTF(Interrupt, "Interrupt! IM[7:0]=%d IP[7:0]=%d \n", 237 IM, IP); 238 return new InterruptFault; 239 } 240 } 241 242 return NoFault; 243 244} 245bool Interrupts::onCpuTimerInterrupt(ThreadContext * tc) const 246{ 247 MiscReg compare = tc->readMiscRegNoEffect(MipsISA::Compare); 248 MiscReg count = tc->readMiscRegNoEffect(MipsISA::Count); 249 if (compare == count && count != 0) 250 return true; 251 return false; 252} 253void Interrupts::updateIntrInfo(ThreadContext *tc) const 254{ 255 //Nothing needs to be done. 256 ; 257} 258 259uint64_t Interrupts::get_vec(int int_num) 260{ 261 panic("MipsISA::Interrupts::get_vec() is not implemented. \n"); 262 M5_DUMMY_RETURN 263 } 264 265bool Interrupts::interruptsPending(ThreadContext *tc) const 266{ 267 //if there is a on cpu timer interrupt (i.e. Compare == Count) 268 //update CauseIP before proceeding to interrupt 269 if (onCpuTimerInterrupt(tc)){ 270 DPRINTF(Interrupt, "Interrupts OnCpuTimerINterrupt(tc)==true\n"); 271 //determine timer interrupt IP # 272 MiscReg intctl = tc->readMiscRegNoEffect(MipsISA::IntCtl); 273 uint8_t IPTI = bits(intctl, IntCtl_IPTI_HI, IntCtl_IPTI_LO); 274 //set intstatus to correspond 275 //post(IPTI, tc); 276 uint8_t intstatus= getCauseIP_(tc); 277 intstatus |= 1 << IPTI; 278 setCauseIP_(tc, intstatus); 279 } 280 281 return (getCauseIP_(tc) != 0); 282 283} 284 285 286 287 288 289} 290