2 * Copyright (c) 2006 The Regents of The University of Michigan
3 * Copyright (c) 2007 MIPS Technologies, Inc.
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.
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.
29 * Authors: Steve Reinhardt
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"
41 static inline uint8_t getCauseIP_(ThreadContext
*tc
) {
42 MiscReg cause
= tc
->readMiscRegNoEffect(MipsISA::Cause
);
43 uint8_t IP_
= bits(cause
,Cause_IP7
, Cause_IP0
);
47 static 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
);
54 void Interrupts::post(int int_num, int index)
56 DPRINTF(Interrupt, "Interrupt %d posted\n", int_num);
58 //index should not be used
61 if (int_num < 0 || int_num >= NumInterruptLevels)
62 panic("int_num out of bounds\n");
63 intstatus |= 1 << int_num;
66 void Interrupts::clear(int int_num, int index)
68 DPRINTF(Interrupt, "Interrupt %d cleared\n", int_num);
70 //index should not be used
73 if (int_num < 0 || int_num >= NumInterruptLevels)
74 panic("int_num out of bounds\n");
76 intstatus &= ~(1 << int_num);
79 void Interrupts::clear_all()
81 DPRINTF(Interrupt, "Interrupts all cleared\n");
87 Fault Interrupts::getInterrupt(ThreadContext * tc)
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
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){
103 oncputimerintr=false;
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
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
124 // Software interrupts & hardware interrupts are handled in software.
125 // So if any interrupt that isn't masked is detected, jump to interrupt
127 uint8_t IM, IP; //IM=interrupt mask, IP=interrupt pending
128 IM = bits(status,Status_IM7,Status_IM0);
130 //IM and IP are already correctly aligned
132 DPRINTF(Flow, "Interrupt! IM[7:0]=%d IP[7:0]=%d \n",
134 return new InterruptFault;
142 void Interrupts::updateIntrInfo(ThreadContext *tc) const
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);
150 bool Interrupts::onCpuTimerInterrupt(ThreadContext * tc) const
152 MiscReg compare = tc->readMiscRegNoEffect(MipsISA::Compare);
153 MiscReg count = tc->readMiscRegNoEffect(MipsISA::Count);
154 if (compare == count)
160 uint64_t Interrupts::get_vec(int int_num)
162 panic("MipsISA::Interrupts::get_vec() is not implemented. \n");
166 void Interrupts::post(int int_num
, ThreadContext
* tc
)
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");
172 uint8_t intstatus
= getCauseIP_(tc
);
173 intstatus
|= 1 << int_num
;
174 setCauseIP_(tc
, intstatus
);
177 void Interrupts::post(int int_num
, int index
)
179 fatal("Must use Thread COntext when posting MIPS Interrupts in M5");
182 void Interrupts::clear(int int_num
, ThreadContext
* tc
)
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");
188 uint8_t intstatus
= getCauseIP_(tc
);
189 intstatus
&= ~(1 << int_num
);
190 setCauseIP_(tc
, intstatus
);
193 void Interrupts::clear(int int_num
, int index
)
195 fatal("Must use Thread COntext when clearing MIPS Interrupts in M5");
198 void Interrupts::clear_all(ThreadContext
*tc
)
200 DPRINTF(Interrupt
, "Interrupts all cleared\n");
201 uint8_t intstatus
= 0;
202 setCauseIP_(tc
, intstatus
);
205 void Interrupts::clear_all()
207 fatal("Must use Thread COntext when clearing MIPS Interrupts in M5");
212 Fault
Interrupts::getInterrupt(ThreadContext
* tc
)
214 DPRINTF(Interrupt
, "Interrupts getInterrupt\n");
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
224 // Software interrupts & hardware interrupts are handled in software.
225 // So if any interrupt that isn't masked is detected, jump to interrupt
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
232 DPRINTF(Interrupt
, "Interrupt! IM[7:0]=%d IP[7:0]=%d \n",
234 return new InterruptFault
;
241 bool Interrupts::onCpuTimerInterrupt(ThreadContext
* tc
) const
243 MiscReg compare
= tc
->readMiscRegNoEffect(MipsISA::Compare
);
244 MiscReg count
= tc
->readMiscRegNoEffect(MipsISA::Count
);
245 if (compare
== count
&& count
!= 0)
249 void Interrupts::updateIntrInfo(ThreadContext
*tc
) const
251 //Nothing needs to be done.
255 uint64_t Interrupts::get_vec(int int_num
)
257 panic("MipsISA::Interrupts::get_vec() is not implemented. \n");
261 bool Interrupts::interruptsPending(ThreadContext
*tc
) const
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
272 uint8_t intstatus
= getCauseIP_(tc
);
273 intstatus
|= 1 << IPTI
;
274 setCauseIP_(tc
, intstatus
);
277 return (getCauseIP_(tc
) != 0);