1/*
2 * Copyright (c) 2006 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Authors: Ali Saidi
29 *          Lisa Hsu
30 */
31
32#ifndef __ARCH_SPARC_INTERRUPT_HH__
33#define __ARCH_SPARC_INTERRUPT_HH__
34
35#include "arch/sparc/faults.hh"
36#include "arch/sparc/isa_traits.hh"
37#include "arch/sparc/registers.hh"
38#include "cpu/thread_context.hh"
39#include "debug/Interrupt.hh"
40#include "params/SparcInterrupts.hh"
41#include "sim/sim_object.hh"
42
43namespace SparcISA
44{
45
46enum InterruptTypes
47{
48    IT_TRAP_LEVEL_ZERO,
49    IT_HINTP,
50    IT_INT_VEC,
51    IT_CPU_MONDO,
52    IT_DEV_MONDO,
53    IT_RES_ERROR,
54    IT_SOFT_INT,
55    NumInterruptTypes
56};
57
58class Interrupts : public SimObject
59{
60  private:
61    BaseCPU * cpu;
62
63    uint64_t interrupts[NumInterruptTypes];
64    uint64_t intStatus;
65
66  public:
67
68    void
69    setCPU(BaseCPU * _cpu)
70    {
71        cpu = _cpu;
72    }
73
74    typedef SparcInterruptsParams Params;
75
76    const Params *
77    params() const
78    {
79        return dynamic_cast<const Params *>(_params);
80    }
81
82    Interrupts(Params * p) : SimObject(p), cpu(NULL)
83    {
84        clearAll();
85    }
86
87    int
88    InterruptLevel(uint64_t softint)
89    {
90        if (softint & 0x10000 || softint & 0x1)
91            return 14;
92
93        int level = 15;
94        while (level > 0 && !(1 << level & softint))
95            level--;
96        if (1 << level & softint)
97            return level;
98        return 0;
99    }
100
101    void
102    post(int int_num, int index)
103    {
104        DPRINTF(Interrupt, "Interrupt %d:%d posted\n", int_num, index);
105        assert(int_num >= 0 && int_num < NumInterruptTypes);
106        assert(index >= 0 && index < 64);
107
108        interrupts[int_num] |= ULL(1) << index;
109        intStatus |= ULL(1) << int_num;
110    }
111
112    void
113    clear(int int_num, int index)
114    {
115        DPRINTF(Interrupt, "Interrupt %d:%d cleared\n", int_num, index);
116        assert(int_num >= 0 && int_num < NumInterruptTypes);
117        assert(index >= 0 && index < 64);
118
119        interrupts[int_num] &= ~(ULL(1) << index);
120        if (!interrupts[int_num])
121            intStatus &= ~(ULL(1) << int_num);
122    }
123
124    void
125    clearAll()
126    {
127        for (int i = 0; i < NumInterruptTypes; ++i) {
128            interrupts[i] = 0;
129        }
130        intStatus = 0;
131    }
132
133    bool
134    checkInterrupts(ThreadContext *tc) const
135    {
136        if (!intStatus)
137            return false;
138
139        HPSTATE hpstate = tc->readMiscRegNoEffect(MISCREG_HPSTATE);
140        PSTATE pstate = tc->readMiscRegNoEffect(MISCREG_PSTATE);
141
142        // THESE ARE IN ORDER OF PRIORITY
143        // since there are early returns, and the highest
144        // priority interrupts should get serviced,
145        // it is v. important that new interrupts are inserted
146        // in the right order of processing
147        if (hpstate.hpriv) {
148            if (pstate.ie) {
149                if (interrupts[IT_HINTP]) {
150                    // This will be cleaned by a HINTP write
151                    return true;
152                }
153                if (interrupts[IT_INT_VEC]) {
154                    // this will be cleared by an ASI read (or write)
155                    return true;
156                }
157            }
158        } else {
159            if (interrupts[IT_TRAP_LEVEL_ZERO]) {
160                    // this is cleared by deasserting HPSTATE::tlz
161                return true;
162            }
163            // HStick matches always happen in priv mode (ie doesn't matter)
164            if (interrupts[IT_HINTP]) {
165                return true;
166            }
167            if (interrupts[IT_INT_VEC]) {
168                // this will be cleared by an ASI read (or write)
169                return true;
170            }
171            if (pstate.ie) {
172                if (interrupts[IT_CPU_MONDO]) {
173                    return true;
174                }
175                if (interrupts[IT_DEV_MONDO]) {
176                    return true;
177                }
178                if (interrupts[IT_SOFT_INT]) {
179                    return true;
180                }
181
182                if (interrupts[IT_RES_ERROR]) {
183                    return true;
184                }
185            } // !hpriv && pstate.ie
186        }  // !hpriv
187
188        return false;
189    }
190
191    Fault
192    getInterrupt(ThreadContext *tc)
193    {
194        assert(checkInterrupts(tc));
195
196        HPSTATE hpstate = tc->readMiscRegNoEffect(MISCREG_HPSTATE);
197        PSTATE pstate = tc->readMiscRegNoEffect(MISCREG_PSTATE);
198
199        // THESE ARE IN ORDER OF PRIORITY
200        // since there are early returns, and the highest
201        // priority interrupts should get serviced,
202        // it is v. important that new interrupts are inserted
203        // in the right order of processing
204        if (hpstate.hpriv) {
205            if (pstate.ie) {
206                if (interrupts[IT_HINTP]) {
207                    // This will be cleaned by a HINTP write
208                    return std::make_shared<HstickMatch>();
209                }
210                if (interrupts[IT_INT_VEC]) {
211                    // this will be cleared by an ASI read (or write)
212                    return std::make_shared<InterruptVector>();
213                }
214            }
215        } else {
216            if (interrupts[IT_TRAP_LEVEL_ZERO]) {
217                    // this is cleared by deasserting HPSTATE::tlz
218                return std::make_shared<TrapLevelZero>();
219            }
220            // HStick matches always happen in priv mode (ie doesn't matter)
221            if (interrupts[IT_HINTP]) {
222                return std::make_shared<HstickMatch>();
223            }
224            if (interrupts[IT_INT_VEC]) {
225                // this will be cleared by an ASI read (or write)
226                return std::make_shared<InterruptVector>();
227            }
228            if (pstate.ie) {
229                if (interrupts[IT_CPU_MONDO]) {
230                    return std::make_shared<CpuMondo>();
231                }
232                if (interrupts[IT_DEV_MONDO]) {
233                    return std::make_shared<DevMondo>();
234                }
235                if (interrupts[IT_SOFT_INT]) {
236                    int level = InterruptLevel(interrupts[IT_SOFT_INT]);
237                    return std::make_shared<InterruptLevelN>(level);
238                }
239
240                if (interrupts[IT_RES_ERROR]) {
241                    return std::make_shared<ResumableError>();
242                }
243            } // !hpriv && pstate.ie
244        }  // !hpriv
245        return NoFault;
246    }
247
248    void
249    updateIntrInfo(ThreadContext *tc)
250    {}
251
252    uint64_t
253    get_vec(int int_num)
254    {
255        assert(int_num >= 0 && int_num < NumInterruptTypes);
256        return interrupts[int_num];
257    }
258
259    void
260    serialize(CheckpointOut &cp) const override
261    {
262        SERIALIZE_ARRAY(interrupts,NumInterruptTypes);
263        SERIALIZE_SCALAR(intStatus);
264    }
265
266    void
267    unserialize(CheckpointIn &cp) override
268    {
269        UNSERIALIZE_ARRAY(interrupts,NumInterruptTypes);
270        UNSERIALIZE_SCALAR(intStatus);
271    }
272};
273} // namespace SPARC_ISA
274
275#endif // __ARCH_SPARC_INTERRUPT_HH__
276