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