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::clearAll()
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 void Interrupts::post(int int_num
, ThreadContext
* tc
)
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");
166 uint8_t intstatus
= getCauseIP_(tc
);
167 intstatus
|= 1 << int_num
;
168 setCauseIP_(tc
, intstatus
);
171 void Interrupts::post(int int_num
, int index
)
173 fatal("Must use Thread COntext when posting MIPS Interrupts in M5");
176 void Interrupts::clear(int int_num
, ThreadContext
* tc
)
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");
182 uint8_t intstatus
= getCauseIP_(tc
);
183 intstatus
&= ~(1 << int_num
);
184 setCauseIP_(tc
, intstatus
);
187 void Interrupts::clear(int int_num
, int index
)
189 fatal("Must use Thread COntext when clearing MIPS Interrupts in M5");
192 void Interrupts::clearAll(ThreadContext
*tc
)
194 DPRINTF(Interrupt
, "Interrupts all cleared\n");
195 uint8_t intstatus
= 0;
196 setCauseIP_(tc
, intstatus
);
199 void Interrupts::clearAll()
201 fatal("Must use Thread COntext when clearing MIPS Interrupts in M5");
206 Fault
Interrupts::getInterrupt(ThreadContext
* tc
)
208 DPRINTF(Interrupt
, "Interrupts getInterrupt\n");
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
218 // Software interrupts & hardware interrupts are handled in software.
219 // So if any interrupt that isn't masked is detected, jump to interrupt
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
226 DPRINTF(Interrupt
, "Interrupt! IM[7:0]=%d IP[7:0]=%d \n",
228 return new InterruptFault
;
235 bool Interrupts::onCpuTimerInterrupt(ThreadContext
* tc
) const
237 MiscReg compare
= tc
->readMiscRegNoEffect(MipsISA::Compare
);
238 MiscReg count
= tc
->readMiscRegNoEffect(MipsISA::Count
);
239 if (compare
== count
&& count
!= 0)
243 void Interrupts::updateIntrInfo(ThreadContext
*tc
) const
245 //Nothing needs to be done.
249 bool Interrupts::interruptsPending(ThreadContext
*tc
) const
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
260 uint8_t intstatus
= getCauseIP_(tc
);
261 intstatus
|= 1 << IPTI
;
262 setCauseIP_(tc
, intstatus
);
265 return (getCauseIP_(tc
) != 0);