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