Add in files from merge-bare-iron, get them compiling in FS and SE mode
[gem5.git] / src / arch / mips / interrupts.cc
1 /*
2 * Copyright \e.A\eN) 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 \e.A\eN) <Publication Year> Copyright Owner), and (3)
17 * the name of MIPS Technologies, Inc. (\e$B!H\e(BMIPS\e$B!I\e(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 \e$B!H\e(BAS IS.\e$B!I\e(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
43 namespace MipsISA
44 {
45 static 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
51 static 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 */
170 void 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
181 void Interrupts::post(int int_num, int index)
182 {
183 fatal("Must use Thread COntext when posting MIPS Interrupts in M5");
184 }
185
186 void 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
197 void Interrupts::clear(int int_num, int index)
198 {
199 fatal("Must use Thread COntext when clearing MIPS Interrupts in M5");
200 }
201
202 void Interrupts::clear_all(ThreadContext *tc)
203 {
204 DPRINTF(Interrupt, "Interrupts all cleared\n");
205 uint8_t intstatus = 0;
206 setCauseIP_(tc, intstatus);
207 }
208
209 void Interrupts::clear_all()
210 {
211 fatal("Must use Thread COntext when clearing MIPS Interrupts in M5");
212 }
213
214
215
216 Fault 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 }
245 bool 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 }
253 void Interrupts::updateIntrInfo(ThreadContext *tc) const
254 {
255 //Nothing needs to be done.
256 ;
257 }
258
259 uint64_t Interrupts::get_vec(int int_num)
260 {
261 panic("MipsISA::Interrupts::get_vec() is not implemented. \n");
262 M5_DUMMY_RETURN
263 }
264
265 bool 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 }