interrupts.cc revision 5704:98224505352a
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::clearAll()
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*/
160void Interrupts::post(int int_num, ThreadContext* tc)
161{
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");
165
166    uint8_t intstatus= getCauseIP_(tc);
167    intstatus |= 1 << int_num;
168    setCauseIP_(tc, intstatus);
169}
170
171void Interrupts::post(int int_num, int index)
172{
173    fatal("Must use Thread COntext when posting MIPS Interrupts in M5");
174}
175
176void Interrupts::clear(int int_num, ThreadContext* tc)
177{
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");
181
182    uint8_t intstatus = getCauseIP_(tc);
183    intstatus &= ~(1 << int_num);
184    setCauseIP_(tc, intstatus);
185}
186
187void Interrupts::clear(int int_num, int index)
188{
189    fatal("Must use Thread COntext when clearing MIPS Interrupts in M5");
190}
191
192void Interrupts::clearAll(ThreadContext *tc)
193{
194    DPRINTF(Interrupt, "Interrupts all cleared\n");
195    uint8_t intstatus = 0;
196    setCauseIP_(tc, intstatus);
197}
198
199void Interrupts::clearAll()
200{
201    fatal("Must use Thread COntext when clearing MIPS Interrupts in M5");
202}
203
204
205
206Fault Interrupts::getInterrupt(ThreadContext * tc)
207{
208    DPRINTF(Interrupt, "Interrupts getInterrupt\n");
209
210
211
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
217    {
218        // Software interrupts & hardware interrupts are handled in software.
219        // So if any interrupt that isn't masked is detected, jump to interrupt
220        // handler
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
225        if (IM & IP){
226            DPRINTF(Interrupt, "Interrupt! IM[7:0]=%d IP[7:0]=%d \n",
227                    IM, IP);
228            return new InterruptFault;
229        }
230    }
231
232    return NoFault;
233
234}
235bool Interrupts::onCpuTimerInterrupt(ThreadContext * tc) const
236{
237    MiscReg compare = tc->readMiscRegNoEffect(MipsISA::Compare);
238    MiscReg count = tc->readMiscRegNoEffect(MipsISA::Count);
239    if (compare == count && count != 0)
240        return true;
241    return false;
242}
243void Interrupts::updateIntrInfo(ThreadContext *tc) const
244{
245    //Nothing needs to be done.
246    ;
247}
248
249bool Interrupts::interruptsPending(ThreadContext *tc) const
250{
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
259        //post(IPTI, tc);
260        uint8_t intstatus= getCauseIP_(tc);
261        intstatus |= 1 << IPTI;
262        setCauseIP_(tc, intstatus);
263    }
264
265    return (getCauseIP_(tc) != 0);
266
267}
268
269
270
271
272
273}
274