interrupts.cc revision 5222:bb733a878f85
112855Sgabeblack@google.com/*
212855Sgabeblack@google.com * Copyright .AN) 2007 MIPS Technologies, Inc.  All Rights Reserved
312855Sgabeblack@google.com *
412855Sgabeblack@google.com * This software is part of the M5 simulator.
512855Sgabeblack@google.com *
612855Sgabeblack@google.com * THIS IS A LEGAL AGREEMENT.  BY DOWNLOADING, USING, COPYING, CREATING
712855Sgabeblack@google.com * DERIVATIVE WORKS, AND/OR DISTRIBUTING THIS SOFTWARE YOU ARE AGREEING
812855Sgabeblack@google.com * TO THESE TERMS AND CONDITIONS.
912855Sgabeblack@google.com *
1012855Sgabeblack@google.com * Permission is granted to use, copy, create derivative works and
1112855Sgabeblack@google.com * distribute this software and such derivative works for any purpose,
1212855Sgabeblack@google.com * so long as (1) the copyright notice above, this grant of permission,
1312855Sgabeblack@google.com * and the disclaimer below appear in all copies and derivative works
1412855Sgabeblack@google.com * made, (2) the copyright notice above is augmented as appropriate to
1512855Sgabeblack@google.com * reflect the addition of any new copyrightable work in a derivative
1612855Sgabeblack@google.com * work (e.g., Copyright .AN) <Publication Year> Copyright Owner), and (3)
1712855Sgabeblack@google.com * the name of MIPS Technologies, Inc. ($B!H(BMIPS$B!I(B) is not used in any
1812855Sgabeblack@google.com * advertising or publicity pertaining to the use or distribution of
1912855Sgabeblack@google.com * this software without specific, written prior authorization.
2012855Sgabeblack@google.com *
2112855Sgabeblack@google.com * THIS SOFTWARE IS PROVIDED $B!H(BAS IS.$B!I(B  MIPS MAKES NO WARRANTIES AND
2212855Sgabeblack@google.com * DISCLAIMS ALL WARRANTIES, WHETHER EXPRESS, STATUTORY, IMPLIED OR
2312855Sgabeblack@google.com * OTHERWISE, INCLUDING BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
2412855Sgabeblack@google.com * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
2512855Sgabeblack@google.com * NON-INFRINGEMENT OF THIRD PARTY RIGHTS, REGARDING THIS SOFTWARE.
2612855Sgabeblack@google.com * IN NO EVENT SHALL MIPS BE LIABLE FOR ANY DAMAGES, INCLUDING DIRECT,
2712855Sgabeblack@google.com * INDIRECT, INCIDENTAL, CONSEQUENTIAL, SPECIAL, OR PUNITIVE DAMAGES OF
2812855Sgabeblack@google.com * ANY KIND OR NATURE, ARISING OUT OF OR IN CONNECTION WITH THIS AGREEMENT,
2912855Sgabeblack@google.com * THIS SOFTWARE AND/OR THE USE OF THIS SOFTWARE, WHETHER SUCH LIABILITY
3012855Sgabeblack@google.com * IS ASSERTED ON THE BASIS OF CONTRACT, TORT (INCLUDING NEGLIGENCE OR
3112855Sgabeblack@google.com * STRICT LIABILITY), OR OTHERWISE, EVEN IF MIPS HAS BEEN WARNED OF THE
3212855Sgabeblack@google.com * POSSIBILITY OF ANY SUCH LOSS OR DAMAGE IN ADVANCE.
3312855Sgabeblack@google.com *
3412855Sgabeblack@google.com * Authors: Richard Strong
3512855Sgabeblack@google.com */
3612855Sgabeblack@google.com
3712855Sgabeblack@google.com
3812855Sgabeblack@google.com#include "arch/mips/pra_constants.hh"
3912855Sgabeblack@google.com#include "arch/mips/isa_traits.hh"
4012855Sgabeblack@google.com#include "cpu/thread_context.hh"
4112855Sgabeblack@google.com#include "arch/mips/interrupts.hh"
4212855Sgabeblack@google.com
4312855Sgabeblack@google.comnamespace MipsISA
4412855Sgabeblack@google.com{
4512855Sgabeblack@google.comstatic inline uint8_t getCauseIP_(ThreadContext *tc) {
4612855Sgabeblack@google.com    MiscReg cause = tc->readMiscRegNoEffect(MipsISA::Cause);
4712855Sgabeblack@google.com    uint8_t IP_ = bits(cause,Cause_IP7, Cause_IP0);
4812855Sgabeblack@google.com    return IP_;
4912855Sgabeblack@google.com}
5012855Sgabeblack@google.com
5112855Sgabeblack@google.comstatic inline void setCauseIP_(ThreadContext *tc, uint8_t val) {
5212855Sgabeblack@google.com    MiscReg cause = tc->readMiscRegNoEffect(MipsISA::Cause);
5312855Sgabeblack@google.com    replaceBits(cause,Cause_IP7,Cause_IP0,val);
5412855Sgabeblack@google.com    tc->setMiscRegNoEffect(MipsISA::Cause,cause);
5512855Sgabeblack@google.com}
5612855Sgabeblack@google.com
5712855Sgabeblack@google.com/*
5812855Sgabeblack@google.com  void Interrupts::post(int int_num, int index)
5912855Sgabeblack@google.com  {
6012855Sgabeblack@google.com  DPRINTF(Interrupt, "Interrupt %d posted\n", int_num);
6112855Sgabeblack@google.com
6212855Sgabeblack@google.com  //index should not be used
6312855Sgabeblack@google.com  assert(index == 0);
6412855Sgabeblack@google.com
6512855Sgabeblack@google.com  if (int_num < 0 || int_num >= NumInterruptLevels)
6612855Sgabeblack@google.com  panic("int_num out of bounds\n");
6712855Sgabeblack@google.com  intstatus |= 1 << int_num;
6812855Sgabeblack@google.com  }
6912855Sgabeblack@google.com
7012855Sgabeblack@google.com  void Interrupts::clear(int int_num, int index)
7112855Sgabeblack@google.com  {
7212855Sgabeblack@google.com  DPRINTF(Interrupt, "Interrupt %d cleared\n", int_num);
7312855Sgabeblack@google.com
7412855Sgabeblack@google.com  //index should not be used
7512855Sgabeblack@google.com  assert(index == 0);
7612855Sgabeblack@google.com
7712855Sgabeblack@google.com  if (int_num < 0 || int_num >= NumInterruptLevels)
7812855Sgabeblack@google.com  panic("int_num out of bounds\n");
7912855Sgabeblack@google.com
8012855Sgabeblack@google.com  intstatus &= ~(1 << int_num);
8112855Sgabeblack@google.com  }
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